1 // Copyright 2010 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
5 // This file contains printing support for ASTs.
17 // A FieldFilter may be provided to Fprint to control the output.
18 type FieldFilter func(name string, value reflect.Value) bool
20 // NotNilFilter returns true for field values that are not nil;
21 // it returns false otherwise.
22 func NotNilFilter(_ string, v reflect.Value) bool {
24 case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice:
30 // Fprint prints the (sub-)tree starting at AST node x to w.
31 // If fset != nil, position information is interpreted relative
32 // to that file set. Otherwise positions are printed as integer
33 // values (file set specific offsets).
35 // A non-nil FieldFilter f may be provided to control the output:
36 // struct fields for which f(fieldname, fieldvalue) is true are
37 // are printed; all others are filtered from the output. Unexported
38 // struct fields are never printed.
40 func Fprint(w io.Writer, fset *token.FileSet, x interface{}, f FieldFilter) (err error) {
46 ptrmap: make(map[interface{}]int),
47 last: '\n', // force printing of line number on first line
50 // install error handler
52 if e := recover(); e != nil {
53 err = e.(localError).err // re-panics if it's not a localError
62 p.print(reflect.ValueOf(x))
68 // Print prints x to standard output, skipping nil fields.
69 // Print(fset, x) is the same as Fprint(os.Stdout, fset, x, NotNilFilter).
70 func Print(fset *token.FileSet, x interface{}) error {
71 return Fprint(os.Stdout, fset, x, NotNilFilter)
78 ptrmap map[interface{}]int // *T -> line number
79 indent int // current indentation level
80 last byte // the last byte processed by Write
81 line int // current line number
84 var indent = []byte(". ")
86 func (p *printer) Write(data []byte) (n int, err error) {
88 for i, b := range data {
89 // invariant: data[0:n] has been written
91 m, err = p.output.Write(data[n : i+1])
97 } else if p.last == '\n' {
98 _, err = fmt.Fprintf(p.output, "%6d ", p.line)
102 for j := p.indent; j > 0; j-- {
103 _, err = p.output.Write(indent)
111 m, err = p.output.Write(data[n:])
116 // localError wraps locally caught errors so we can distinguish
117 // them from genuine panics which we don't want to return as errors.
118 type localError struct {
122 // printf is a convenience wrapper that takes care of print errors.
123 func (p *printer) printf(format string, args ...interface{}) {
124 if _, err := fmt.Fprintf(p, format, args...); err != nil {
125 panic(localError{err})
129 // Implementation note: Print is written for AST nodes but could be
130 // used to print arbitrary data structures; such a version should
131 // probably be in a different package.
133 // Note: This code detects (some) cycles created via pointers but
134 // not cycles that are created via slices or maps containing the
135 // same slice or map. Code for general data structures probably
136 // should catch those as well.
138 func (p *printer) print(x reflect.Value) {
139 if !NotNilFilter("", x) {
145 case reflect.Interface:
149 p.printf("%s (len = %d) {", x.Type(), x.Len())
153 for _, key := range x.MapKeys() {
156 p.print(x.MapIndex(key))
165 // type-checked ASTs may contain cycles - use ptrmap
166 // to keep track of objects that have been printed
167 // already and print the respective line number instead
169 if line, exists := p.ptrmap[ptr]; exists {
170 p.printf("(obj @ %d)", line)
172 p.ptrmap[ptr] = p.line
177 p.printf("%s {", x.Type())
181 for i, n := 0, x.Len(); i < n; i++ {
191 if s, ok := x.Interface().([]byte); ok {
195 p.printf("%s (len = %d) {", x.Type(), x.Len())
199 for i, n := 0, x.Len(); i < n; i++ {
213 for i, n := 0, t.NumField(); i < n; i++ {
214 // exclude non-exported fields because their
215 // values cannot be accessed via reflection
216 if name := t.Field(i).Name; IsExported(name) {
218 if p.filter == nil || p.filter(name, value) {
223 p.printf("%s: ", name)
234 switch v := v.(type) {
236 // print strings in quotes
240 // position values can be printed nicely if we have a file set
242 p.printf("%s", p.fset.Position(v))