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 suppport for ASTs.
18 // A FieldFilter may be provided to Fprint to control the output.
19 type FieldFilter
func(name
string, value reflect
.Value
) bool
22 // NotNilFilter returns true for field values that are not nil;
23 // it returns false otherwise.
24 func NotNilFilter(_
string, value reflect
.Value
) bool {
25 v
, ok
:= value
.(interface {
28 return !ok ||
!v
.IsNil()
32 // Fprint prints the (sub-)tree starting at AST node x to w.
34 // A non-nil FieldFilter f may be provided to control the output:
35 // struct fields for which f(fieldname, fieldvalue) is true are
36 // are printed; all others are filtered from the output.
38 func Fprint(w io
.Writer
, x
interface{}, f FieldFilter
) (n
int, err os
.Error
) {
43 ptrmap
: make(map[interface{}]int),
44 last
: '\n', // force printing of line number on first line
47 // install error handler
50 if e
:= recover(); e
!= nil {
51 err
= e
.(localError
).err
// re-panics if it's not a localError
60 p
.print(reflect
.NewValue(x
))
67 // Print prints x to standard output, skipping nil fields.
68 // Print(x) is the same as Fprint(os.Stdout, x, NotNilFilter).
69 func Print(x
interface{}) (int, os
.Error
) {
70 return Fprint(os
.Stdout
, x
, NotNilFilter
)
77 ptrmap
map[interface{}]int // *reflect.PtrValue -> line number
78 written
int // number of bytes written to output
79 indent
int // current indentation level
80 last
byte // the last byte processed by Write
81 line
int // current line number
85 var indent
= []byte(". ")
87 func (p
*printer
) Write(data
[]byte) (n
int, err os
.Error
) {
89 for i
, b
:= range data
{
90 // invariant: data[0:n] has been written
92 m
, err
= p
.output
.Write(data
[n
: i
+1])
98 } else if p
.last
== '\n' {
99 _
, err
= fmt
.Fprintf(p
.output
, "%6d ", p
.line
)
103 for j
:= p
.indent
; j
> 0; j
-- {
104 _
, err
= p
.output
.Write(indent
)
112 m
, err
= p
.output
.Write(data
[n
:])
118 // localError wraps locally caught os.Errors so we can distinguish
119 // them from genuine panics which we don't want to return as errors.
120 type localError
struct {
125 // printf is a convenience wrapper that takes care of print errors.
126 func (p
*printer
) printf(format
string, args
...interface{}) {
127 n
, err
:= fmt
.Fprintf(p
, format
, args
...)
130 panic(localError
{err
})
135 // Implementation note: Print is written for AST nodes but could be
136 // used to print arbitrary data structures; such a version should
137 // probably be in a different package.
139 func (p
*printer
) print(x reflect
.Value
) {
140 // Note: This test is only needed because AST nodes
141 // embed a token.Position, and thus all of them
142 // understand the String() method (but it only
143 // applies to the Position field).
144 // TODO: Should reconsider this AST design decision.
145 if pos
, ok
:= x
.Interface().(token
.Position
); ok
{
150 if !NotNilFilter("", x
) {
155 switch v
:= x
.(type) {
156 case *reflect
.InterfaceValue
:
159 case *reflect
.MapValue
:
160 p
.printf("%s (len = %d) {\n", x
.Type().String(), v
.Len())
162 for _
, key
:= range v
.Keys() {
170 case *reflect
.PtrValue
:
172 // type-checked ASTs may contain cycles - use ptrmap
173 // to keep track of objects that have been printed
174 // already and print the respective line number instead
176 if line
, exists
:= p
.ptrmap
[ptr
]; exists
{
177 p
.printf("(obj @ %d)", line
)
179 p
.ptrmap
[ptr
] = p
.line
183 case *reflect
.SliceValue
:
184 if s
, ok
:= v
.Interface().([]byte); ok
{
188 p
.printf("%s (len = %d) {\n", x
.Type().String(), v
.Len())
190 for i
, n
:= 0, v
.Len(); i
< n
; i
++ {
198 case *reflect
.StructValue
:
199 p
.printf("%s {\n", x
.Type().String())
201 t
:= v
.Type().(*reflect
.StructType
)
202 for i
, n
:= 0, t
.NumField(); i
< n
; i
++ {
203 name
:= t
.Field(i
).Name
205 if p
.filter
== nil || p
.filter(name
, value
) {
206 p
.printf("%s: ", name
)
215 p
.printf("%v", x
.Interface())