-
Notifications
You must be signed in to change notification settings - Fork 33
/
dot.go
76 lines (67 loc) · 1.6 KB
/
dot.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
package main
import (
"bufio"
"encoding/base64"
"fmt"
"html"
"os"
"strings"
"github.com/nokia/ntt/ttcn3/syntax"
)
func dot(n syntax.Node) {
w := bufio.NewWriter(os.Stdout)
defer w.Flush()
w.WriteString(`digraph {
rankdir=LR
`)
q := []syntax.Node{n}
toks := []syntax.Token{}
for len(q) > 0 {
n := q[0]
q = q[1:]
if syntax.IsNil(n) {
continue
}
if tok, ok := n.(syntax.Token); ok {
toks = append(toks, tok)
continue
}
fmt.Fprintf(w, "\t%s %s;\n", nodeID(n), nodeProps(n))
for _, child := range n.Children() {
if !syntax.IsNil(child) {
fmt.Fprintf(w, "\t%s -> %s;\n", nodeID(n), nodeID(child))
q = append(q, child)
}
}
}
w.WriteString(" { \n")
for _, tok := range toks {
fmt.Fprintf(w, "\t%s %s;\n", nodeID(tok), nodeProps(tok))
}
w.WriteString(" }")
w.WriteString("}")
}
func nodeID(n syntax.Node) string {
if tok, ok := n.(syntax.Token); ok {
return fmt.Sprintf("t%d", tok.Pos())
}
return fmt.Sprintf("n%p%s", n, base64.RawStdEncoding.EncodeToString([]byte(fmt.Sprintf("%T", n))))
}
func nodeProps(n syntax.Node) string {
if tok, ok := n.(syntax.Token); ok {
label := fmt.Sprintf("%v", tok.Kind())
if tok.Kind().IsLiteral() {
label = tok.String()
}
return fmt.Sprintf("[label=<<B>%s</B>>; shape=box; style=filled; fillcolor=lightgrey]", escape(label))
}
label := strings.TrimPrefix(fmt.Sprintf("%T", n), "*syntax.")
return fmt.Sprintf("[label=\"%s\"]", label)
}
func escape(s string) string {
s = html.EscapeString(s)
s = strings.Replace(s, "[", " [", -1)
s = strings.Replace(s, "|", " |", -1)
s = strings.Replace(s, "]", " ]", -1)
return s
}