Skip to content

Commit

Permalink
adds helpful print commands for tracing and debugging the interp system.
Browse files Browse the repository at this point in the history
I found these basic functions and Stringer methods essential for tracking down issues fixed recently -- probably be of use to others and I couldn't find something else in the code that would provide similar utility, though I never tried the debugger.
  • Loading branch information
rcoreilly committed Jul 19, 2024
1 parent 81a9d11 commit b6315ca
Show file tree
Hide file tree
Showing 3 changed files with 122 additions and 0 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,8 @@ test

Documentation about Yaegi commands and libraries can be found at usual [godoc.org][docs].

Key documentation of the internal design: https://marc.vertes.org/yaegi-internals/ Also see [interp/trace.go](interp/trace.go) for helpful printing commands to see what is happening under the hood during compilation.

## Limitations

Beside the known [bugs] which are supposed to be fixed in the short term, there are some limitations not planned to be addressed soon:
Expand Down
2 changes: 2 additions & 0 deletions interp/cfg.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,8 @@ func (interp *Interpreter) cfg(root *node, sc *scope, importPath, pkgName string
if n.scope == nil {
n.scope = sc
}
tracePrintln(n)

switch n.kind {
case binaryExpr, unaryExpr, parenExpr:
if isBoolAction(n) {
Expand Down
118 changes: 118 additions & 0 deletions interp/trace.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
package interp

import (
"fmt"
"reflect"
"strings"
)

// Set trace to true for debugging the cfg and other processes.
var trace = false

func traceIndent(n *node) string {
return strings.Repeat(" ", n.depth())
}

// tracePrintln works like fmt.Println, with indenting by depth
// and key info on given node.
func tracePrintln(n *node, v ...any) {
if !trace {
return
}
fmt.Println(append([]any{traceIndent(n), n}, v...)...)
}

// tracePrintTree is particularly useful in post-order for seeing the full
// structure of a given code segment of interest.
//
//nolint:unused // debugging facility
func tracePrintTree(n *node, v ...any) {
if !trace {
return
}
tracePrintln(n, v...)
n.Walk(func(n *node) bool {
tracePrintln(n)
return true
}, nil)
}

// nodeAddr returns the pointer address of node, short version.
func ptrAddr(v any) string {
p := fmt.Sprintf("%p", v)
return p[:2] + p[9:] // unique bits
}

// valString returns string rep of given value, showing underlying pointers etc.
//
//nolint:unused // debugging facility
func valString(v reflect.Value) string {
s := v.String()
if v.Kind() == reflect.Func || v.Kind() == reflect.Map || v.Kind() == reflect.Pointer || v.Kind() == reflect.Slice || v.Kind() == reflect.UnsafePointer {
p := fmt.Sprintf("%#x", v.Pointer())
ln := len(p)
s += " " + p[:2] + p[max(2, ln-4):]
}
return s
}

func (n *node) String() string {
s := n.kind.String()
if n.ident != "" {
s += " " + n.ident
}
s += " " + ptrAddr(n)
if n.sym != nil {
s += " sym:" + n.sym.String()
} else if n.typ != nil {
s += " typ:" + n.typ.String()
}
if n.findex >= 0 {
s += fmt.Sprintf(" fidx: %d lev: %d", n.findex, n.level)
}
if n.start != nil && n.start != n {
s += fmt.Sprintf(" ->start: %s %s", n.start.kind.String(), ptrAddr(n.start))
}
if n.tnext != nil {
s += fmt.Sprintf(" ->tnext: %s %s", n.tnext.kind.String(), ptrAddr(n.tnext))
}
if n.fnext != nil {
s += fmt.Sprintf(" ->fnext: %s %s", n.fnext.kind.String(), ptrAddr(n.fnext))
}
return s
}

func (n *node) depth() int {
if n.anc != nil {
return n.anc.depth() + 1
}
return 0
}

func (sy *symbol) String() string {
s := sy.kind.String()
if sy.typ != nil {
s += " (" + sy.typ.String() + ")"
}
if sy.rval.IsValid() {
s += " = " + sy.rval.String()
}
if sy.index >= 0 {
s += fmt.Sprintf(" idx: %d", sy.index)
}
if sy.node != nil {
s += " " + sy.node.String()
}
return s
}

func (t *itype) String() string {
if t.str != "" {
return t.str
}
s := t.cat.String()
if t.name != "" {
s += " (" + t.name + ")"
}
return s
}

0 comments on commit b6315ca

Please sign in to comment.