Merge from mainline (167278:168000).
[official-gcc/graphite-test-results.git] / libgo / go / go / ast / print.go
blobd71490d4a9ff440bb2c032987894ab0d0c4d50d9
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.
7 package ast
9 import (
10 "fmt"
11 "go/token"
12 "io"
13 "os"
14 "reflect"
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 {
26 IsNil() bool
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) {
39 // setup printer
40 p := printer{
41 output: w,
42 filter: f,
43 ptrmap: make(map[interface{}]int),
44 last: '\n', // force printing of line number on first line
47 // install error handler
48 defer func() {
49 n = p.written
50 if e := recover(); e != nil {
51 err = e.(localError).err // re-panics if it's not a localError
53 }()
55 // print x
56 if x == nil {
57 p.printf("nil\n")
58 return
60 p.print(reflect.NewValue(x))
61 p.printf("\n")
63 return
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)
74 type printer struct {
75 output io.Writer
76 filter FieldFilter
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) {
88 var m int
89 for i, b := range data {
90 // invariant: data[0:n] has been written
91 if b == '\n' {
92 m, err = p.output.Write(data[n : i+1])
93 n += m
94 if err != nil {
95 return
97 p.line++
98 } else if p.last == '\n' {
99 _, err = fmt.Fprintf(p.output, "%6d ", p.line)
100 if err != nil {
101 return
103 for j := p.indent; j > 0; j-- {
104 _, err = p.output.Write(indent)
105 if err != nil {
106 return
110 p.last = b
112 m, err = p.output.Write(data[n:])
113 n += m
114 return
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 {
121 err os.Error
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...)
128 p.written += n
129 if err != nil {
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 {
146 p.printf("%s", pos)
147 return
150 if !NotNilFilter("", x) {
151 p.printf("nil")
152 return
155 switch v := x.(type) {
156 case *reflect.InterfaceValue:
157 p.print(v.Elem())
159 case *reflect.MapValue:
160 p.printf("%s (len = %d) {\n", x.Type().String(), v.Len())
161 p.indent++
162 for _, key := range v.Keys() {
163 p.print(key)
164 p.printf(": ")
165 p.print(v.Elem(key))
167 p.indent--
168 p.printf("}")
170 case *reflect.PtrValue:
171 p.printf("*")
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
175 ptr := v.Interface()
176 if line, exists := p.ptrmap[ptr]; exists {
177 p.printf("(obj @ %d)", line)
178 } else {
179 p.ptrmap[ptr] = p.line
180 p.print(v.Elem())
183 case *reflect.SliceValue:
184 if s, ok := v.Interface().([]byte); ok {
185 p.printf("%#q", s)
186 return
188 p.printf("%s (len = %d) {\n", x.Type().String(), v.Len())
189 p.indent++
190 for i, n := 0, v.Len(); i < n; i++ {
191 p.printf("%d: ", i)
192 p.print(v.Elem(i))
193 p.printf("\n")
195 p.indent--
196 p.printf("}")
198 case *reflect.StructValue:
199 p.printf("%s {\n", x.Type().String())
200 p.indent++
201 t := v.Type().(*reflect.StructType)
202 for i, n := 0, t.NumField(); i < n; i++ {
203 name := t.Field(i).Name
204 value := v.Field(i)
205 if p.filter == nil || p.filter(name, value) {
206 p.printf("%s: ", name)
207 p.print(value)
208 p.printf("\n")
211 p.indent--
212 p.printf("}")
214 default:
215 p.printf("%v", x.Interface())