1
2
3
4
5
6
7 package syntax
8
9 import (
10 "fmt"
11 "io"
12 "reflect"
13 "unicode"
14 "unicode/utf8"
15 )
16
17
18
19
20 func Fdump(w io.Writer, n Node) (err error) {
21 p := dumper{
22 output: w,
23 ptrmap: make(map[Node]int),
24 last: '\n',
25 }
26
27 defer func() {
28 if e := recover(); e != nil {
29 err = e.(writeError).err
30 }
31 }()
32
33 if n == nil {
34 p.printf("nil\n")
35 return
36 }
37 p.dump(reflect.ValueOf(n), n)
38 p.printf("\n")
39
40 return
41 }
42
43 type dumper struct {
44 output io.Writer
45 ptrmap map[Node]int
46 indent int
47 last byte
48 line int
49 }
50
51 var indentBytes = []byte(". ")
52
53 func (p *dumper) Write(data []byte) (n int, err error) {
54 var m int
55 for i, b := range data {
56
57 if b == '\n' {
58 m, err = p.output.Write(data[n : i+1])
59 n += m
60 if err != nil {
61 return
62 }
63 } else if p.last == '\n' {
64 p.line++
65 _, err = fmt.Fprintf(p.output, "%6d ", p.line)
66 if err != nil {
67 return
68 }
69 for j := p.indent; j > 0; j-- {
70 _, err = p.output.Write(indentBytes)
71 if err != nil {
72 return
73 }
74 }
75 }
76 p.last = b
77 }
78 if len(data) > n {
79 m, err = p.output.Write(data[n:])
80 n += m
81 }
82 return
83 }
84
85
86
87 type writeError struct {
88 err error
89 }
90
91
92 func (p *dumper) printf(format string, args ...interface{}) {
93 if _, err := fmt.Fprintf(p, format, args...); err != nil {
94 panic(writeError{err})
95 }
96 }
97
98
99
100
101
102
103
104
105 func (p *dumper) dump(x reflect.Value, n Node) {
106 switch x.Kind() {
107 case reflect.Interface:
108 if x.IsNil() {
109 p.printf("nil")
110 return
111 }
112 p.dump(x.Elem(), nil)
113
114 case reflect.Ptr:
115 if x.IsNil() {
116 p.printf("nil")
117 return
118 }
119
120
121 if x, ok := x.Interface().(*Name); ok {
122 p.printf("%s @ %v", x.Value, x.Pos())
123 return
124 }
125
126 p.printf("*")
127
128
129
130 if ptr, ok := x.Interface().(Node); ok {
131 if line, exists := p.ptrmap[ptr]; exists {
132 p.printf("(Node @ %d)", line)
133 return
134 }
135 p.ptrmap[ptr] = p.line
136 n = ptr
137 }
138 p.dump(x.Elem(), n)
139
140 case reflect.Slice:
141 if x.IsNil() {
142 p.printf("nil")
143 return
144 }
145 p.printf("%s (%d entries) {", x.Type(), x.Len())
146 if x.Len() > 0 {
147 p.indent++
148 p.printf("\n")
149 for i, n := 0, x.Len(); i < n; i++ {
150 p.printf("%d: ", i)
151 p.dump(x.Index(i), nil)
152 p.printf("\n")
153 }
154 p.indent--
155 }
156 p.printf("}")
157
158 case reflect.Struct:
159 typ := x.Type()
160
161
162
163
164
165
166 p.printf("%s {", typ)
167 p.indent++
168
169 first := true
170 if n != nil {
171 p.printf("\n")
172 first = false
173
174
175
176
177
178
179 }
180
181 for i, n := 0, typ.NumField(); i < n; i++ {
182
183
184 if name := typ.Field(i).Name; isExported(name) {
185 if first {
186 p.printf("\n")
187 first = false
188 }
189 p.printf("%s: ", name)
190 p.dump(x.Field(i), nil)
191 p.printf("\n")
192 }
193 }
194
195 p.indent--
196 p.printf("}")
197
198 default:
199 switch x := x.Interface().(type) {
200 case string:
201
202 p.printf("%q", x)
203 default:
204 p.printf("%v", x)
205 }
206 }
207 }
208
209 func isExported(name string) bool {
210 ch, _ := utf8.DecodeRuneInString(name)
211 return unicode.IsUpper(ch)
212 }
213
View as plain text