summaryrefslogtreecommitdiff
path: root/src/pkg/go/ast/print.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/pkg/go/ast/print.go')
-rw-r--r--src/pkg/go/ast/print.go94
1 files changed, 55 insertions, 39 deletions
diff --git a/src/pkg/go/ast/print.go b/src/pkg/go/ast/print.go
index d71490d4a..e6d4e838d 100644
--- a/src/pkg/go/ast/print.go
+++ b/src/pkg/go/ast/print.go
@@ -21,24 +21,29 @@ type FieldFilter func(name string, value reflect.Value) bool
// NotNilFilter returns true for field values that are not nil;
// it returns false otherwise.
-func NotNilFilter(_ string, value reflect.Value) bool {
- v, ok := value.(interface {
- IsNil() bool
- })
- return !ok || !v.IsNil()
+func NotNilFilter(_ string, v reflect.Value) bool {
+ switch v.Kind() {
+ case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice:
+ return !v.IsNil()
+ }
+ return true
}
// Fprint prints the (sub-)tree starting at AST node x to w.
+// If fset != nil, position information is interpreted relative
+// to that file set. Otherwise positions are printed as integer
+// values (file set specific offsets).
//
// A non-nil FieldFilter f may be provided to control the output:
// struct fields for which f(fieldname, fieldvalue) is true are
// are printed; all others are filtered from the output.
//
-func Fprint(w io.Writer, x interface{}, f FieldFilter) (n int, err os.Error) {
+func Fprint(w io.Writer, fset *token.FileSet, x interface{}, f FieldFilter) (n int, err os.Error) {
// setup printer
p := printer{
output: w,
+ fset: fset,
filter: f,
ptrmap: make(map[interface{}]int),
last: '\n', // force printing of line number on first line
@@ -65,16 +70,17 @@ func Fprint(w io.Writer, x interface{}, f FieldFilter) (n int, err os.Error) {
// Print prints x to standard output, skipping nil fields.
-// Print(x) is the same as Fprint(os.Stdout, x, NotNilFilter).
-func Print(x interface{}) (int, os.Error) {
- return Fprint(os.Stdout, x, NotNilFilter)
+// Print(fset, x) is the same as Fprint(os.Stdout, fset, x, NotNilFilter).
+func Print(fset *token.FileSet, x interface{}) (int, os.Error) {
+ return Fprint(os.Stdout, fset, x, NotNilFilter)
}
type printer struct {
output io.Writer
+ fset *token.FileSet
filter FieldFilter
- ptrmap map[interface{}]int // *reflect.PtrValue -> line number
+ ptrmap map[interface{}]int // *T -> line number
written int // number of bytes written to output
indent int // current indentation level
last byte // the last byte processed by Write
@@ -135,73 +141,69 @@ func (p *printer) printf(format string, args ...interface{}) {
// Implementation note: Print is written for AST nodes but could be
// used to print arbitrary data structures; such a version should
// probably be in a different package.
+//
+// Note: This code detects (some) cycles created via pointers but
+// not cycles that are created via slices or maps containing the
+// same slice or map. Code for general data structures probably
+// should catch those as well.
func (p *printer) print(x reflect.Value) {
- // Note: This test is only needed because AST nodes
- // embed a token.Position, and thus all of them
- // understand the String() method (but it only
- // applies to the Position field).
- // TODO: Should reconsider this AST design decision.
- if pos, ok := x.Interface().(token.Position); ok {
- p.printf("%s", pos)
- return
- }
-
if !NotNilFilter("", x) {
p.printf("nil")
return
}
- switch v := x.(type) {
- case *reflect.InterfaceValue:
- p.print(v.Elem())
+ switch x.Kind() {
+ case reflect.Interface:
+ p.print(x.Elem())
- case *reflect.MapValue:
- p.printf("%s (len = %d) {\n", x.Type().String(), v.Len())
+ case reflect.Map:
+ p.printf("%s (len = %d) {\n", x.Type().String(), x.Len())
p.indent++
- for _, key := range v.Keys() {
+ for _, key := range x.MapKeys() {
p.print(key)
p.printf(": ")
- p.print(v.Elem(key))
+ p.print(x.MapIndex(key))
+ p.printf("\n")
}
p.indent--
p.printf("}")
- case *reflect.PtrValue:
+ case reflect.Ptr:
p.printf("*")
// type-checked ASTs may contain cycles - use ptrmap
// to keep track of objects that have been printed
// already and print the respective line number instead
- ptr := v.Interface()
+ ptr := x.Interface()
if line, exists := p.ptrmap[ptr]; exists {
p.printf("(obj @ %d)", line)
} else {
p.ptrmap[ptr] = p.line
- p.print(v.Elem())
+ p.print(x.Elem())
}
- case *reflect.SliceValue:
- if s, ok := v.Interface().([]byte); ok {
+ case reflect.Slice:
+ if s, ok := x.Interface().([]byte); ok {
p.printf("%#q", s)
return
}
- p.printf("%s (len = %d) {\n", x.Type().String(), v.Len())
+ p.printf("%s (len = %d) {\n", x.Type().String(), x.Len())
p.indent++
- for i, n := 0, v.Len(); i < n; i++ {
+ for i, n := 0, x.Len(); i < n; i++ {
p.printf("%d: ", i)
- p.print(v.Elem(i))
+ p.print(x.Index(i))
p.printf("\n")
}
p.indent--
p.printf("}")
- case *reflect.StructValue:
+ case reflect.Struct:
p.printf("%s {\n", x.Type().String())
p.indent++
- t := v.Type().(*reflect.StructType)
+ t := x.Type()
for i, n := 0, t.NumField(); i < n; i++ {
name := t.Field(i).Name
- value := v.Field(i)
+ value := x.Field(i)
if p.filter == nil || p.filter(name, value) {
p.printf("%s: ", name)
p.print(value)
@@ -212,6 +214,20 @@ func (p *printer) print(x reflect.Value) {
p.printf("}")
default:
- p.printf("%v", x.Interface())
+ v := x.Interface()
+ switch v := v.(type) {
+ case string:
+ // print strings in quotes
+ p.printf("%q", v)
+ return
+ case token.Pos:
+ // position values can be printed nicely if we have a file set
+ if p.fset != nil {
+ p.printf("%s", p.fset.Position(v))
+ return
+ }
+ }
+ // default
+ p.printf("%v", v)
}
}