diff --git a/pkg/compiler/codegen.go b/pkg/compiler/codegen.go index 612ae60de..e5c8b7e32 100644 --- a/pkg/compiler/codegen.go +++ b/pkg/compiler/codegen.go @@ -286,6 +286,9 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor { for _, spec := range n.Specs { switch t := spec.(type) { case *ast.ValueSpec: + for _, id := range t.Names { + c.registerDebugVariable(id.Name, t.Type) + } if len(t.Values) != 0 { for i, val := range t.Values { ast.Walk(c, val) @@ -320,6 +323,11 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor { c.convertToken(n.Tok) l := c.scope.loadLocal(t.Name) c.emitStoreLocal(l) + case token.DEFINE: + if !multiRet { + c.registerDebugVariable(t.Name, n.Rhs[i]) + } + fallthrough default: if i == 0 || !multiRet { ast.Walk(c, n.Rhs[i]) diff --git a/pkg/compiler/debug.go b/pkg/compiler/debug.go index 101da8dbc..be1b96d92 100644 --- a/pkg/compiler/debug.go +++ b/pkg/compiler/debug.go @@ -104,6 +104,11 @@ func (c *codegen) emitDebugInfo() *DebugInfo { return d } +func (c *codegen) registerDebugVariable(name string, expr ast.Expr) { + typ := c.scTypeFromExpr(expr) + c.scope.variables = append(c.scope.variables, name+","+typ) +} + func (c *codegen) methodInfoFromScope(name string, scope *funcScope) *MethodDebugInfo { ps := scope.decl.Type.Params params := make([]DebugParam, 0, ps.NumFields()) @@ -122,6 +127,7 @@ func (c *codegen) methodInfoFromScope(name string, scope *funcScope) *MethodDebu Parameters: params, ReturnType: c.scReturnTypeFromScope(scope), SeqPoints: c.sequencePoints[name], + Variables: scope.variables, } } diff --git a/pkg/compiler/debug_test.go b/pkg/compiler/debug_test.go index 07bd2a517..baecbb09e 100644 --- a/pkg/compiler/debug_test.go +++ b/pkg/compiler/debug_test.go @@ -12,6 +12,8 @@ import ( func TestCodeGen_DebugInfo(t *testing.T) { src := `package foo func Main(op string) bool { + var s string + _ = s res := methodInt(op) _ = methodString() _ = methodByteArray() @@ -56,6 +58,18 @@ func methodStruct() struct{} { return struct{}{} } } }) + t.Run("variables", func(t *testing.T) { + vars := map[string][]string{ + "Main": {"s,String", "res,Integer"}, + } + for i := range d.Methods { + v, ok := vars[d.Methods[i].Name.Name] + if ok { + require.Equal(t, v, d.Methods[i].Variables) + } + } + }) + // basic check that last instruction of every method is indeed RET for i := range d.Methods { index := d.Methods[i].Range.End diff --git a/pkg/compiler/func_scope.go b/pkg/compiler/func_scope.go index a43a0ec20..d4a0ca862 100644 --- a/pkg/compiler/func_scope.go +++ b/pkg/compiler/func_scope.go @@ -23,6 +23,8 @@ type funcScope struct { // Range of opcodes corresponding to the function. rng DebugRange + // Variables together with it's type in neo-vm. + variables []string // Local variables locals map[string]int @@ -46,6 +48,7 @@ func newFuncScope(decl *ast.FuncDecl, label uint16) *funcScope { label: label, locals: map[string]int{}, voidCalls: map[*ast.CallExpr]bool{}, + variables: []string{}, i: -1, } }