github.com/elves/Elvish@v0.12.0/parse/pprint.go (about) 1 package parse 2 3 import ( 4 "bytes" 5 "fmt" 6 "io" 7 "reflect" 8 "strconv" 9 ) 10 11 const ( 12 maxL int = 10 13 maxR = 10 14 indentInc = 2 15 ) 16 17 // PPrintAST pretty-prints the AST part of a Node. 18 func PPrintAST(n Node) string { 19 var b bytes.Buffer 20 PPrintASTTo(n, &b) 21 return b.String() 22 } 23 24 // PPrintASTTo pretty-prints the AST part of a Node to a Writer. 25 func PPrintASTTo(n Node, wr io.Writer) { 26 pprintAST(n, wr, 0, "") 27 } 28 29 type field struct { 30 name string 31 tag reflect.StructTag 32 value interface{} 33 } 34 35 var zeroValue reflect.Value 36 37 func pprintAST(n Node, wr io.Writer, indent int, leading string) { 38 nodeType := reflect.TypeOf((*Node)(nil)).Elem() 39 40 var childFields, childrenFields, propertyFields []field 41 42 nt := reflect.TypeOf(n).Elem() 43 nv := reflect.ValueOf(n).Elem() 44 45 for i := 0; i < nt.NumField(); i++ { 46 f := nt.Field(i) 47 if f.Anonymous { 48 // embedded node struct, skip 49 continue 50 } 51 ft := f.Type 52 fv := nv.Field(i) 53 if ft.Kind() == reflect.Slice { 54 // list of children 55 if ft.Elem().Implements(nodeType) { 56 childrenFields = append(childrenFields, 57 field{f.Name, f.Tag, fv.Interface()}) 58 continue 59 } 60 } else if child, ok := fv.Interface().(Node); ok { 61 // a child node 62 if reflect.Indirect(fv) != zeroValue { 63 childFields = append(childFields, 64 field{f.Name, f.Tag, child}) 65 } 66 continue 67 } 68 // a property 69 propertyFields = append(propertyFields, 70 field{f.Name, f.Tag, fv.Interface()}) 71 } 72 73 // has only one child and nothing more : coalesce 74 if len(n.Children()) == 1 && 75 n.Children()[0].SourceText() == n.SourceText() { 76 pprintAST(n.Children()[0], wr, indent, leading+nt.Name()+"/") 77 return 78 } 79 // print heading 80 //b := n.n() 81 //fmt.Fprintf(wr, "%*s%s%s %s %d-%d", indent, "", 82 // wr.leading, nt.Name(), compactQuote(b.source(src)), b.begin, b.end) 83 fmt.Fprintf(wr, "%*s%s%s", indent, "", leading, nt.Name()) 84 // print properties 85 for _, pf := range propertyFields { 86 fmtstring := pf.tag.Get("fmt") 87 if len(fmtstring) > 0 { 88 fmt.Fprintf(wr, " %s="+fmtstring, pf.name, pf.value) 89 } else { 90 value := pf.value 91 if s, ok := value.(string); ok { 92 value = compactQuote(s) 93 } 94 fmt.Fprintf(wr, " %s=%v", pf.name, value) 95 } 96 } 97 fmt.Fprint(wr, "\n") 98 // print lone children recursively 99 for _, chf := range childFields { 100 // TODO the name is omitted 101 pprintAST(chf.value.(Node), wr, indent+indentInc, "") 102 } 103 // print children list recursively 104 for _, chf := range childrenFields { 105 children := reflect.ValueOf(chf.value) 106 if children.Len() == 0 { 107 continue 108 } 109 // fmt.Fprintf(wr, "%*s.%s:\n", indent, "", chf.name) 110 for i := 0; i < children.Len(); i++ { 111 n := children.Index(i).Interface().(Node) 112 pprintAST(n, wr, indent+indentInc, "") 113 } 114 } 115 } 116 117 // PPrintParseTree pretty-prints the parse tree part of a Node. 118 func PPrintParseTree(n Node) string { 119 var b bytes.Buffer 120 PPrintParseTreeTo(n, &b) 121 return b.String() 122 } 123 124 // PPrintParseTreeTo pretty-prints the parse tree part of a Node to a Writer. 125 func PPrintParseTreeTo(n Node, wr io.Writer) { 126 pprintParseTree(n, wr, 0) 127 } 128 129 func pprintParseTree(n Node, wr io.Writer, indent int) { 130 leading := "" 131 for len(n.Children()) == 1 { 132 leading += reflect.TypeOf(n).Elem().Name() + "/" 133 n = n.Children()[0] 134 } 135 fmt.Fprintf(wr, "%*s%s%s\n", indent, "", leading, summary(n)) 136 for _, ch := range n.Children() { 137 pprintParseTree(ch, wr, indent+indentInc) 138 } 139 } 140 141 func summary(n Node) string { 142 return fmt.Sprintf("%s %s %d-%d", reflect.TypeOf(n).Elem().Name(), 143 compactQuote(n.SourceText()), n.Begin(), n.End()) 144 } 145 146 func compactQuote(text string) string { 147 if len(text) > maxL+maxR+3 { 148 text = text[0:maxL] + "..." + text[len(text)-maxR:] 149 } 150 return strconv.Quote(text) 151 }