OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [libgo/] [go/] [go/] [ast/] [print.go] - Rev 774

Go to most recent revision | 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 ast

import (
        "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 printer
        p := printer{
                output: w,
                fset:   fset,
                filter: f,
                ptrmap: make(map[interface{}]int),
                last:   '\n', // force printing of line number on first line
        }

        // install error handler
        defer func() {
                if e := recover(); e != nil {
                        err = e.(localError).err // re-panics if it's not a localError
                }
        }()

        // print x
        if 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.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 error) {
        var m int
        for i, b := range data {
                // invariant: data[0:n] has been written
                if b == '\n' {
                        m, err = p.output.Write(data[n : i+1])
                        n += m
                        if 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 += m
        return
}

// 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 instead
                ptr := x.Interface()
                if line, exists := p.ptrmap[ptr]; exists {
                        p.printf("(obj @ %d)", line)
                } else {
                        p.ptrmap[ptr] = p.line
                        p.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).Name
                        value := 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 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)
        }
}

Go to most recent revision | Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.