Source file
src/go/ast/print.go
1
2
3
4
5
6
7 package ast
8
9 import (
10 "fmt"
11 "go/token"
12 "io"
13 "os"
14 "reflect"
15 )
16
17
18 type FieldFilter func(name string, value reflect.Value) bool
19
20
21
22 func NotNilFilter(_ string, v reflect.Value) bool {
23 switch v.Kind() {
24 case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Pointer, reflect.Slice:
25 return !v.IsNil()
26 }
27 return true
28 }
29
30
31
32
33
34
35
36
37
38
39 func Fprint(w io.Writer, fset *token.FileSet, x any, f FieldFilter) error {
40 return fprint(w, fset, x, f)
41 }
42
43 func fprint(w io.Writer, fset *token.FileSet, x any, f FieldFilter) (err error) {
44
45 p := printer{
46 output: w,
47 fset: fset,
48 filter: f,
49 ptrmap: make(map[any]int),
50 last: '\n',
51 }
52
53
54 defer func() {
55 if e := recover(); e != nil {
56 err = e.(localError).err
57 }
58 }()
59
60
61 if x == nil {
62 p.printf("nil\n")
63 return
64 }
65 p.print(reflect.ValueOf(x))
66 p.printf("\n")
67
68 return
69 }
70
71
72
73 func Print(fset *token.FileSet, x any) error {
74 return Fprint(os.Stdout, fset, x, NotNilFilter)
75 }
76
77 type printer struct {
78 output io.Writer
79 fset *token.FileSet
80 filter FieldFilter
81 ptrmap map[any]int
82 indent int
83 last byte
84 line int
85 }
86
87 var indent = []byte(". ")
88
89 func (p *printer) Write(data []byte) (n int, err error) {
90 var m int
91 for i, b := range data {
92
93 if b == '\n' {
94 m, err = p.output.Write(data[n : i+1])
95 n += m
96 if err != nil {
97 return
98 }
99 p.line++
100 } else if p.last == '\n' {
101 _, err = fmt.Fprintf(p.output, "%6d ", p.line)
102 if err != nil {
103 return
104 }
105 for j := p.indent; j > 0; j-- {
106 _, err = p.output.Write(indent)
107 if err != nil {
108 return
109 }
110 }
111 }
112 p.last = b
113 }
114 if len(data) > n {
115 m, err = p.output.Write(data[n:])
116 n += m
117 }
118 return
119 }
120
121
122
123 type localError struct {
124 err error
125 }
126
127
128 func (p *printer) printf(format string, args ...any) {
129 if _, err := fmt.Fprintf(p, format, args...); err != nil {
130 panic(localError{err})
131 }
132 }
133
134
135
136
137
138
139
140
141
142
143 func (p *printer) print(x reflect.Value) {
144 if !NotNilFilter("", x) {
145 p.printf("nil")
146 return
147 }
148
149 switch x.Kind() {
150 case reflect.Interface:
151 p.print(x.Elem())
152
153 case reflect.Map:
154 p.printf("%s (len = %d) {", x.Type(), x.Len())
155 if x.Len() > 0 {
156 p.indent++
157 p.printf("\n")
158 for _, key := range x.MapKeys() {
159 p.print(key)
160 p.printf(": ")
161 p.print(x.MapIndex(key))
162 p.printf("\n")
163 }
164 p.indent--
165 }
166 p.printf("}")
167
168 case reflect.Pointer:
169 p.printf("*")
170
171
172
173 ptr := x.Interface()
174 if line, exists := p.ptrmap[ptr]; exists {
175 p.printf("(obj @ %d)", line)
176 } else {
177 p.ptrmap[ptr] = p.line
178 p.print(x.Elem())
179 }
180
181 case reflect.Array:
182 p.printf("%s {", x.Type())
183 if x.Len() > 0 {
184 p.indent++
185 p.printf("\n")
186 for i, n := 0, x.Len(); i < n; i++ {
187 p.printf("%d: ", i)
188 p.print(x.Index(i))
189 p.printf("\n")
190 }
191 p.indent--
192 }
193 p.printf("}")
194
195 case reflect.Slice:
196 if s, ok := x.Interface().([]byte); ok {
197 p.printf("%#q", s)
198 return
199 }
200 p.printf("%s (len = %d) {", x.Type(), x.Len())
201 if x.Len() > 0 {
202 p.indent++
203 p.printf("\n")
204 for i, n := 0, x.Len(); i < n; i++ {
205 p.printf("%d: ", i)
206 p.print(x.Index(i))
207 p.printf("\n")
208 }
209 p.indent--
210 }
211 p.printf("}")
212
213 case reflect.Struct:
214 t := x.Type()
215 p.printf("%s {", t)
216 p.indent++
217 first := true
218 for i, n := 0, t.NumField(); i < n; i++ {
219
220
221 if name := t.Field(i).Name; IsExported(name) {
222 value := x.Field(i)
223 if p.filter == nil || p.filter(name, value) {
224 if first {
225 p.printf("\n")
226 first = false
227 }
228 p.printf("%s: ", name)
229 p.print(value)
230 p.printf("\n")
231 }
232 }
233 }
234 p.indent--
235 p.printf("}")
236
237 default:
238 v := x.Interface()
239 switch v := v.(type) {
240 case string:
241
242 p.printf("%q", v)
243 return
244 case token.Pos:
245
246 if p.fset != nil {
247 p.printf("%s", p.fset.Position(v))
248 return
249 }
250 }
251
252 p.printf("%v", v)
253 }
254 }
255
View as plain text