...

Source file src/pkg/cmd/compile/internal/syntax/dumper.go

     1	// Copyright 2016 The Go Authors. All rights reserved.
     2	// Use of this source code is governed by a BSD-style
     3	// license that can be found in the LICENSE file.
     4	
     5	// This file implements printing of syntax tree structures.
     6	
     7	package syntax
     8	
     9	import (
    10		"fmt"
    11		"io"
    12		"reflect"
    13		"unicode"
    14		"unicode/utf8"
    15	)
    16	
    17	// Fdump dumps the structure of the syntax tree rooted at n to w.
    18	// It is intended for debugging purposes; no specific output format
    19	// is guaranteed.
    20	func Fdump(w io.Writer, n Node) (err error) {
    21		p := dumper{
    22			output: w,
    23			ptrmap: make(map[Node]int),
    24			last:   '\n', // force printing of line number on first line
    25		}
    26	
    27		defer func() {
    28			if e := recover(); e != nil {
    29				err = e.(localError).err // re-panics if it's not a localError
    30			}
    31		}()
    32	
    33		if n == nil {
    34			p.printf("nil\n")
    35			return
    36		}
    37		p.dump(reflect.ValueOf(n), n)
    38		p.printf("\n")
    39	
    40		return
    41	}
    42	
    43	type dumper struct {
    44		output io.Writer
    45		ptrmap map[Node]int // node -> dump line number
    46		indent int          // current indentation level
    47		last   byte         // last byte processed by Write
    48		line   int          // current line number
    49	}
    50	
    51	var indentBytes = []byte(".  ")
    52	
    53	func (p *dumper) Write(data []byte) (n int, err error) {
    54		var m int
    55		for i, b := range data {
    56			// invariant: data[0:n] has been written
    57			if b == '\n' {
    58				m, err = p.output.Write(data[n : i+1])
    59				n += m
    60				if err != nil {
    61					return
    62				}
    63			} else if p.last == '\n' {
    64				p.line++
    65				_, err = fmt.Fprintf(p.output, "%6d  ", p.line)
    66				if err != nil {
    67					return
    68				}
    69				for j := p.indent; j > 0; j-- {
    70					_, err = p.output.Write(indentBytes)
    71					if err != nil {
    72						return
    73					}
    74				}
    75			}
    76			p.last = b
    77		}
    78		if len(data) > n {
    79			m, err = p.output.Write(data[n:])
    80			n += m
    81		}
    82		return
    83	}
    84	
    85	// localError wraps locally caught errors so we can distinguish
    86	// them from genuine panics which we don't want to return as errors.
    87	type localError struct {
    88		err error
    89	}
    90	
    91	// printf is a convenience wrapper that takes care of print errors.
    92	func (p *dumper) printf(format string, args ...interface{}) {
    93		if _, err := fmt.Fprintf(p, format, args...); err != nil {
    94			panic(localError{err})
    95		}
    96	}
    97	
    98	// dump prints the contents of x.
    99	// If x is the reflect.Value of a struct s, where &s
   100	// implements Node, then &s should be passed for n -
   101	// this permits printing of the unexported span and
   102	// comments fields of the embedded isNode field by
   103	// calling the Span() and Comment() instead of using
   104	// reflection.
   105	func (p *dumper) dump(x reflect.Value, n Node) {
   106		switch x.Kind() {
   107		case reflect.Interface:
   108			if x.IsNil() {
   109				p.printf("nil")
   110				return
   111			}
   112			p.dump(x.Elem(), nil)
   113	
   114		case reflect.Ptr:
   115			if x.IsNil() {
   116				p.printf("nil")
   117				return
   118			}
   119	
   120			// special cases for identifiers w/o attached comments (common case)
   121			if x, ok := x.Interface().(*Name); ok {
   122				p.printf("%s @ %v", x.Value, x.Pos())
   123				return
   124			}
   125	
   126			p.printf("*")
   127			// Fields may share type expressions, and declarations
   128			// may share the same group - use ptrmap to keep track
   129			// of nodes that have been printed already.
   130			if ptr, ok := x.Interface().(Node); ok {
   131				if line, exists := p.ptrmap[ptr]; exists {
   132					p.printf("(Node @ %d)", line)
   133					return
   134				}
   135				p.ptrmap[ptr] = p.line
   136				n = ptr
   137			}
   138			p.dump(x.Elem(), n)
   139	
   140		case reflect.Slice:
   141			if x.IsNil() {
   142				p.printf("nil")
   143				return
   144			}
   145			p.printf("%s (%d entries) {", x.Type(), x.Len())
   146			if x.Len() > 0 {
   147				p.indent++
   148				p.printf("\n")
   149				for i, n := 0, x.Len(); i < n; i++ {
   150					p.printf("%d: ", i)
   151					p.dump(x.Index(i), nil)
   152					p.printf("\n")
   153				}
   154				p.indent--
   155			}
   156			p.printf("}")
   157	
   158		case reflect.Struct:
   159			typ := x.Type()
   160	
   161			// if span, ok := x.Interface().(lexical.Span); ok {
   162			// 	p.printf("%s", &span)
   163			// 	return
   164			// }
   165	
   166			p.printf("%s {", typ)
   167			p.indent++
   168	
   169			first := true
   170			if n != nil {
   171				p.printf("\n")
   172				first = false
   173				// p.printf("Span: %s\n", n.Span())
   174				// if c := *n.Comments(); c != nil {
   175				// 	p.printf("Comments: ")
   176				// 	p.dump(reflect.ValueOf(c), nil) // a Comment is not a Node
   177				// 	p.printf("\n")
   178				// }
   179			}
   180	
   181			for i, n := 0, typ.NumField(); i < n; i++ {
   182				// Exclude non-exported fields because their
   183				// values cannot be accessed via reflection.
   184				if name := typ.Field(i).Name; isExported(name) {
   185					if first {
   186						p.printf("\n")
   187						first = false
   188					}
   189					p.printf("%s: ", name)
   190					p.dump(x.Field(i), nil)
   191					p.printf("\n")
   192				}
   193			}
   194	
   195			p.indent--
   196			p.printf("}")
   197	
   198		default:
   199			switch x := x.Interface().(type) {
   200			case string:
   201				// print strings in quotes
   202				p.printf("%q", x)
   203			default:
   204				p.printf("%v", x)
   205			}
   206		}
   207	}
   208	
   209	func isExported(name string) bool {
   210		ch, _ := utf8.DecodeRuneInString(name)
   211		return unicode.IsUpper(ch)
   212	}
   213	

View as plain text