Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

adds helpful print commands for tracing and debugging the interp system. #1648

Merged
merged 4 commits into from
Jul 19, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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.
mvertes marked this conversation as resolved.
Show resolved Hide resolved
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.
//
//lint:ignore
mvertes marked this conversation as resolved.
Show resolved Hide resolved
func tracePrintTree(n *node, v ...any) {

Check failure on line 29 in interp/trace.go

View workflow job for this annotation

GitHub Actions / Linting

func `tracePrintTree` is unused (unused)
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.
//
//lint:ignore
mvertes marked this conversation as resolved.
Show resolved Hide resolved
func valString(v reflect.Value) string {

Check failure on line 49 in interp/trace.go

View workflow job for this annotation

GitHub Actions / Linting

func `valString` is unused (unused)
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
}
Loading