URL
https://opencores.org/ocsvn/openrisc/openrisc/trunk
Subversion Repositories openrisc
[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [libgo/] [go/] [go/] [ast/] [print.go] - Rev 747
Compare with Previous | Blame | View Log
// Copyright 2010 The Go Authors. All rights reserved.// 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.package astimport ("fmt""go/token""io""os""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, 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, fset *token.FileSet, x interface{}, f FieldFilter) (err error) {// setup printerp := printer{output: w,fset: fset,filter: f,ptrmap: make(map[interface{}]int),last: '\n', // force printing of line number on first line}// install error handlerdefer func() {if e := recover(); e != nil {err = e.(localError).err // re-panics if it's not a localError}}()// print xif x == nil {p.printf("nil\n")return}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{}) error {return Fprint(os.Stdout, fset, x, NotNilFilter)}type printer struct {output io.Writerfset *token.FileSetfilter FieldFilterptrmap map[interface{}]int // *T -> line numberindent int // current indentation levellast byte // the last byte processed by Writeline int // current line number}var indent = []byte(". ")func (p *printer) Write(data []byte) (n int, err error) {var m intfor i, b := range data {// invariant: data[0:n] has been writtenif b == '\n' {m, err = p.output.Write(data[n : i+1])n += mif err != nil {return}p.line++} else if p.last == '\n' {_, err = fmt.Fprintf(p.output, "%6d ", p.line)if err != nil {return}for j := p.indent; j > 0; j-- {_, err = p.output.Write(indent)if err != nil {return}}}p.last = b}m, err = p.output.Write(data[n:])n += mreturn}// 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 error}// printf is a convenience wrapper that takes care of print errors.func (p *printer) printf(format string, args ...interface{}) {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) {p.printf("nil")return}switch x.Kind() {case reflect.Interface:p.print(x.Elem())case reflect.Map:p.printf("%s (len = %d) {\n", x.Type(), x.Len())p.indent++for _, key := range x.MapKeys() {p.print(key)p.printf(": ")p.print(x.MapIndex(key))p.printf("\n")}p.indent--p.printf("}")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 insteadptr := x.Interface()if line, exists := p.ptrmap[ptr]; exists {p.printf("(obj @ %d)", line)} else {p.ptrmap[ptr] = p.linep.print(x.Elem())}case reflect.Slice:if s, ok := x.Interface().([]byte); ok {p.printf("%#q", s)return}p.printf("%s (len = %d) {\n", x.Type(), x.Len())p.indent++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.Struct:p.printf("%s {\n", x.Type())p.indent++t := x.Type()for i, n := 0, t.NumField(); i < n; i++ {name := t.Field(i).Namevalue := x.Field(i)if p.filter == nil || p.filter(name, value) {p.printf("%s: ", name)p.print(value)p.printf("\n")}}p.indent--p.printf("}")default:v := x.Interface()switch v := v.(type) {case string:// print strings in quotesp.printf("%q", v)returncase token.Pos:// position values can be printed nicely if we have a file setif p.fset != nil {p.printf("%s", p.fset.Position(v))return}}// defaultp.printf("%v", v)}}
