Commit 1a667f52 authored by Robert Griesemer's avatar Robert Griesemer

go/ast Fprint: handle cycles in AST

Augmented ASTs may contain cycles. Keep
track of already printed objects and refer
to them with a line number instead of
printing them again.

R=rsc
CC=golang-dev
https://golang.org/cl/1998042
parent 9d3eb29a
......@@ -37,7 +37,12 @@ func NotNilFilter(_ string, value reflect.Value) bool {
//
func Fprint(w io.Writer, x interface{}, f FieldFilter) (n int, err os.Error) {
// setup printer
p := printer{output: w, filter: f}
p := printer{
output: w,
filter: f,
ptrmap: make(map[interface{}]int),
last: '\n', // force printing of line number on first line
}
// install error handler
defer func() {
......@@ -69,9 +74,11 @@ func Print(x interface{}) (int, os.Error) {
type printer struct {
output io.Writer
filter FieldFilter
written int // number of bytes written to output
indent int // current indentation level
last byte // the last byte processed by Write
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
}
......@@ -87,7 +94,12 @@ func (p *printer) Write(data []byte) (n int, err os.Error) {
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 {
......@@ -121,9 +133,8 @@ func (p *printer) printf(format string, args ...interface{}) {
// Implementation note: Print is written for AST nodes but could be
// used to print any acyclic data structure. It would also be easy
// to generalize it to arbitrary data structures; such a version
// should probably be in a different package.
// used to print arbitrary data structures; such a version should
// probably be in a different package.
func (p *printer) print(x reflect.Value) {
// Note: This test is only needed because AST nodes
......@@ -158,7 +169,16 @@ func (p *printer) print(x reflect.Value) {
case *reflect.PtrValue:
p.printf("*")
p.print(v.Elem())
// 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()
if line, exists := p.ptrmap[ptr]; exists {
p.printf("(obj @ %d)", line)
} else {
p.ptrmap[ptr] = p.line
p.print(v.Elem())
}
case *reflect.SliceValue:
if s, ok := v.Interface().([]byte); ok {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment