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