this repo has no description
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

internal/astinternal: add IncludePointers

This has been very useful for me when debugging ASTs
to tally pointers in log messages with nodes in the
final AST.

Signed-off-by: Roger Peppe <rogpeppe@gmail.com>
Change-Id: Icdc564619069120aa425a16990c99c2faff2906f
Reviewed-on: https://review.gerrithub.io/c/cue-lang/cue/+/1205771
TryBot-Result: CUEcueckoo <cueckoo@cuelang.org>
Reviewed-by: Daniel Martí <mvdan@mvdan.cc>
Unity-Result: CUE porcuepine <cue.porcuepine@gmail.com>

+111 -3
+21 -3
internal/astinternal/debug.go
··· 56 56 // IncludeNodeRefs causes a Node reference in an identifier 57 57 // to indicate which (if any) ast.Node it refers to. 58 58 IncludeNodeRefs bool 59 + 60 + // IncludePointers causes all nodes to be printed with their pointer 61 + // values; setting this also implies [DebugConfig.IncludeNodeRefs] 62 + // and references will be printed as pointers. 63 + IncludePointers bool 59 64 } 60 65 61 66 type debugPrinter struct { ··· 82 87 // Skip over interfaces and pointers, stopping early if nil. 83 88 concreteType := v.Type() 84 89 refName := "" 90 + ptrVal := uintptr(0) 85 91 for { 86 92 k := v.Kind() 87 93 if k != reflect.Interface && k != reflect.Pointer { ··· 95 101 } 96 102 if k == reflect.Pointer { 97 103 if n, ok := v.Interface().(ast.Node); ok { 104 + ptrVal = v.Pointer() 98 105 if id, ok := d.nodeRefs[n]; ok { 99 106 refName = refIDToName(id) 100 107 } ··· 143 150 if concreteType != impliedType { 144 151 d.printf("%s", concreteType) 145 152 } 146 - if refName != "" { 153 + if d.cfg.IncludePointers { 154 + if ptrVal != 0 { 155 + d.printf("@%#x", ptrVal) 156 + } 157 + } else if refName != "" { 147 158 d.printf("@%s", refName) 148 159 } 149 160 d.printf("{") ··· 192 203 } 193 204 if f.Name == "Node" { 194 205 nodeVal := v.Field(i) 195 - if !d.cfg.IncludeNodeRefs || nodeVal.IsNil() { 206 + if (!d.cfg.IncludeNodeRefs && !d.cfg.IncludePointers) || nodeVal.IsNil() { 196 207 continue 197 208 } 198 209 d.newline() 199 - d.printf("Node: @%s (%v)", refIDToName(d.nodeRefs[nodeVal.Interface().(ast.Node)]), nodeVal.Elem().Type()) 210 + if d.cfg.IncludePointers { 211 + if nodeVal.Kind() == reflect.Interface { 212 + nodeVal = nodeVal.Elem() 213 + } 214 + d.printf("Node: @%#v (%v)", nodeVal.Pointer(), nodeVal.Elem().Type()) 215 + } else { 216 + d.printf("Node: @%s (%v)", refIDToName(d.nodeRefs[nodeVal.Interface().(ast.Node)]), nodeVal.Elem().Type()) 217 + } 200 218 continue 201 219 } 202 220 switch f.Name {
+11
internal/astinternal/debug_test.go
··· 17 17 import ( 18 18 "path" 19 19 "reflect" 20 + "regexp" 20 21 "strings" 21 22 "testing" 22 23 ··· 27 28 28 29 "github.com/go-quicktest/qt" 29 30 ) 31 + 32 + var ptrPat = regexp.MustCompile(`0x[0-9a-z]+`) 30 33 31 34 func TestDebugPrint(t *testing.T) { 32 35 test := cuetxtar.TxTarTest{ ··· 35 38 } 36 39 37 40 test.Run(t, func(t *cuetxtar.Test) { 41 + includePointers := t.HasTag("includePointers") 38 42 for _, file := range t.Archive.Files { 39 43 if strings.HasPrefix(file.Name, "out/") { 40 44 continue 41 45 } 46 + 42 47 f, err := parser.ParseFile(file.Name, file.Data, parser.ParseComments) 43 48 qt.Assert(t, qt.IsNil(err)) 44 49 ··· 49 54 // the generated reference names should be deterministic. 50 55 full := astinternal.AppendDebug(nil, f, astinternal.DebugConfig{ 51 56 IncludeNodeRefs: true, 57 + IncludePointers: includePointers, 52 58 }) 59 + if includePointers { 60 + // Pointer values change between runs. Replace with a constant 61 + // string so that we can test stable output. 62 + full = ptrPat.ReplaceAll(full, []byte("XXXX")) 63 + } 53 64 t.Writer(file.Name).Write(full) 54 65 55 66 // A syntax tree which omits any empty values,
+79
internal/astinternal/testdata/debugprint/withpointer.txtar
··· 1 + #includePointers 2 + -- file.cue -- 3 + package p 4 + 5 + a: b 6 + b: 3 7 + -- out/debugprint/file.cue -- 8 + *ast.File@XXXX{ 9 + Filename: "file.cue" 10 + Decls: []ast.Decl{ 11 + *ast.Package@XXXX{ 12 + PackagePos: token.Pos("file.cue:1:1", nospace) 13 + Name: *ast.Ident@XXXX{ 14 + NamePos: token.Pos("file.cue:1:9", blank) 15 + Name: "p" 16 + } 17 + } 18 + *ast.Field@XXXX{ 19 + Label: *ast.Ident@XXXX{ 20 + NamePos: token.Pos("file.cue:3:1", section) 21 + Name: "a" 22 + } 23 + Optional: token.Pos("-") 24 + Constraint: token.Token("ILLEGAL") 25 + TokenPos: token.Pos("file.cue:3:2", nospace) 26 + Token: token.Token(":") 27 + Value: *ast.Ident@XXXX{ 28 + NamePos: token.Pos("file.cue:3:4", blank) 29 + Name: "b" 30 + Node: @XXXX (ast.BasicLit) 31 + } 32 + Attrs: []*ast.Attribute{} 33 + } 34 + *ast.Field@XXXX{ 35 + Label: *ast.Ident@XXXX{ 36 + NamePos: token.Pos("file.cue:4:1", newline) 37 + Name: "b" 38 + } 39 + Optional: token.Pos("-") 40 + Constraint: token.Token("ILLEGAL") 41 + TokenPos: token.Pos("file.cue:4:2", nospace) 42 + Token: token.Token(":") 43 + Value: *ast.BasicLit@XXXX{ 44 + ValuePos: token.Pos("file.cue:4:4", blank) 45 + Kind: token.Token("INT") 46 + Value: "3" 47 + } 48 + Attrs: []*ast.Attribute{} 49 + } 50 + } 51 + Imports: []*ast.ImportSpec{} 52 + } 53 + -- out/debugprint/file.cue/omitempty-strings -- 54 + *ast.File{ 55 + Filename: "file.cue" 56 + Decls: []ast.Decl{ 57 + *ast.Package{ 58 + Name: *ast.Ident{ 59 + Name: "p" 60 + } 61 + } 62 + *ast.Field{ 63 + Label: *ast.Ident{ 64 + Name: "a" 65 + } 66 + Value: *ast.Ident{ 67 + Name: "b" 68 + } 69 + } 70 + *ast.Field{ 71 + Label: *ast.Ident{ 72 + Name: "b" 73 + } 74 + Value: *ast.BasicLit{ 75 + Value: "3" 76 + } 77 + } 78 + } 79 + }