OSDN Git Service

libgo: Update to Go 1.0.3.
[pf3gnuchains/gcc-fork.git] / libgo / go / go / ast / print.go
index 82c334e..2de9af2 100644 (file)
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// This file contains printing suppport for ASTs.
+// This file contains printing support for ASTs.
 
 package ast
 
@@ -14,21 +14,19 @@ import (
        "reflect"
 )
 
-
 // A FieldFilter may be provided to Fprint to control the output.
 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
@@ -36,9 +34,10 @@ func NotNilFilter(_ string, value reflect.Value) bool {
 //
 // 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.
+// are printed; all others are filtered from the output. Unexported
+// struct fields are never printed.
 //
-func Fprint(w io.Writer, fset *token.FileSet, x interface{}, f FieldFilter) (n int, err os.Error) {
+func Fprint(w io.Writer, fset *token.FileSet, x interface{}, f FieldFilter) (err error) {
        // setup printer
        p := printer{
                output: w,
@@ -50,7 +49,6 @@ func Fprint(w io.Writer, fset *token.FileSet, x interface{}, f FieldFilter) (n i
 
        // install error handler
        defer func() {
-               n = p.written
                if e := recover(); e != nil {
                        err = e.(localError).err // re-panics if it's not a localError
                }
@@ -61,35 +59,31 @@ func Fprint(w io.Writer, fset *token.FileSet, x interface{}, f FieldFilter) (n i
                p.printf("nil\n")
                return
        }
-       p.print(reflect.NewValue(x))
+       p.print(reflect.ValueOf(x))
        p.printf("\n")
 
        return
 }
 
-
 // Print prints x to standard output, skipping nil fields.
 // Print(fset, x) is the same as Fprint(os.Stdout, fset, x, NotNilFilter).
-func Print(fset *token.FileSet, x interface{}) (int, os.Error) {
+func Print(fset *token.FileSet, x interface{}) 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
-       written int                 // number of bytes written to output
-       indent  int                 // current indentation level
-       last    byte                // the last byte processed by Write
-       line    int                 // current line number
+       output io.Writer
+       fset   *token.FileSet
+       filter FieldFilter
+       ptrmap map[interface{}]int // *T -> line number
+       indent int                 // current indentation level
+       last   byte                // the last byte processed by Write
+       line   int                 // current line number
 }
 
-
 var indent = []byte(".  ")
 
-func (p *printer) Write(data []byte) (n int, err os.Error) {
+func (p *printer) Write(data []byte) (n int, err error) {
        var m int
        for i, b := range data {
                // invariant: data[0:n] has been written
@@ -119,27 +113,27 @@ func (p *printer) Write(data []byte) (n int, err os.Error) {
        return
 }
 
-
-// localError wraps locally caught os.Errors so we can distinguish
+// localError wraps locally caught errors so we can distinguish
 // them from genuine panics which we don't want to return as errors.
 type localError struct {
-       err os.Error
+       err error
 }
 
-
 // printf is a convenience wrapper that takes care of print errors.
 func (p *printer) printf(format string, args ...interface{}) {
-       n, err := fmt.Fprintf(p, format, args...)
-       p.written += n
-       if err != nil {
+       if _, err := fmt.Fprintf(p, format, args...); err != nil {
                panic(localError{err})
        }
 }
 
-
 // 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) {
        if !NotNilFilter("", x) {
@@ -147,72 +141,109 @@ func (p *printer) print(x reflect.Value) {
                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())
-               p.indent++
-               for _, key := range v.Keys() {
-                       p.print(key)
-                       p.printf(": ")
-                       p.print(v.Elem(key))
+       case reflect.Map:
+               p.printf("%s (len = %d) {", x.Type(), x.Len())
+               if x.Len() > 0 {
+                       p.indent++
                        p.printf("\n")
+                       for _, key := range x.MapKeys() {
+                               p.print(key)
+                               p.printf(": ")
+                               p.print(x.MapIndex(key))
+                               p.printf("\n")
+                       }
+                       p.indent--
                }
-               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.Array:
+               p.printf("%s {", x.Type())
+               if x.Len() > 0 {
+                       p.indent++
+                       p.printf("\n")
+                       for i, n := 0, x.Len(); i < n; i++ {
+                               p.printf("%d: ", i)
+                               p.print(x.Index(i))
+                               p.printf("\n")
+                       }
+                       p.indent--
+               }
+               p.printf("}")
+
+       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.indent++
-               for i, n := 0, v.Len(); i < n; i++ {
-                       p.printf("%d: ", i)
-                       p.print(v.Elem(i))
+               p.printf("%s (len = %d) {", x.Type(), x.Len())
+               if x.Len() > 0 {
+                       p.indent++
                        p.printf("\n")
+                       for i, n := 0, x.Len(); i < n; i++ {
+                               p.printf("%d: ", i)
+                               p.print(x.Index(i))
+                               p.printf("\n")
+                       }
+                       p.indent--
                }
-               p.indent--
                p.printf("}")
 
-       case *reflect.StructValue:
-               p.printf("%s {\n", x.Type().String())
+       case reflect.Struct:
+               t := x.Type()
+               p.printf("%s {", t)
                p.indent++
-               t := v.Type().(*reflect.StructType)
+               first := true
                for i, n := 0, t.NumField(); i < n; i++ {
-                       name := t.Field(i).Name
-                       value := v.Field(i)
-                       if p.filter == nil || p.filter(name, value) {
-                               p.printf("%s: ", name)
-                               p.print(value)
-                               p.printf("\n")
+                       // exclude non-exported fields because their
+                       // values cannot be accessed via reflection
+                       if name := t.Field(i).Name; IsExported(name) {
+                               value := x.Field(i)
+                               if p.filter == nil || p.filter(name, value) {
+                                       if first {
+                                               p.printf("\n")
+                                               first = false
+                                       }
+                                       p.printf("%s: ", name)
+                                       p.print(value)
+                                       p.printf("\n")
+                               }
                        }
                }
                p.indent--
                p.printf("}")
 
        default:
-               value := x.Interface()
-               // position values can be printed nicely if we have a file set
-               if pos, ok := value.(token.Pos); ok && p.fset != nil {
-                       value = p.fset.Position(pos)
+               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
+                       }
                }
-               p.printf("%v", value)
+               // default
+               p.printf("%v", v)
        }
 }