compiler: support exporting method variables in debug info

This commit is contained in:
Evgenii Stratonikov 2020-04-02 16:36:11 +03:00
parent 5bdee683e6
commit 457e7e006a
4 changed files with 31 additions and 0 deletions

View file

@ -286,6 +286,9 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor {
for _, spec := range n.Specs { for _, spec := range n.Specs {
switch t := spec.(type) { switch t := spec.(type) {
case *ast.ValueSpec: case *ast.ValueSpec:
for _, id := range t.Names {
c.registerDebugVariable(id.Name, t.Type)
}
if len(t.Values) != 0 { if len(t.Values) != 0 {
for i, val := range t.Values { for i, val := range t.Values {
ast.Walk(c, val) ast.Walk(c, val)
@ -320,6 +323,11 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor {
c.convertToken(n.Tok) c.convertToken(n.Tok)
l := c.scope.loadLocal(t.Name) l := c.scope.loadLocal(t.Name)
c.emitStoreLocal(l) c.emitStoreLocal(l)
case token.DEFINE:
if !multiRet {
c.registerDebugVariable(t.Name, n.Rhs[i])
}
fallthrough
default: default:
if i == 0 || !multiRet { if i == 0 || !multiRet {
ast.Walk(c, n.Rhs[i]) ast.Walk(c, n.Rhs[i])

View file

@ -104,6 +104,11 @@ func (c *codegen) emitDebugInfo() *DebugInfo {
return d 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 { func (c *codegen) methodInfoFromScope(name string, scope *funcScope) *MethodDebugInfo {
ps := scope.decl.Type.Params ps := scope.decl.Type.Params
params := make([]DebugParam, 0, ps.NumFields()) params := make([]DebugParam, 0, ps.NumFields())
@ -122,6 +127,7 @@ func (c *codegen) methodInfoFromScope(name string, scope *funcScope) *MethodDebu
Parameters: params, Parameters: params,
ReturnType: c.scReturnTypeFromScope(scope), ReturnType: c.scReturnTypeFromScope(scope),
SeqPoints: c.sequencePoints[name], SeqPoints: c.sequencePoints[name],
Variables: scope.variables,
} }
} }

View file

@ -12,6 +12,8 @@ import (
func TestCodeGen_DebugInfo(t *testing.T) { func TestCodeGen_DebugInfo(t *testing.T) {
src := `package foo src := `package foo
func Main(op string) bool { func Main(op string) bool {
var s string
_ = s
res := methodInt(op) res := methodInt(op)
_ = methodString() _ = methodString()
_ = methodByteArray() _ = 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 // basic check that last instruction of every method is indeed RET
for i := range d.Methods { for i := range d.Methods {
index := d.Methods[i].Range.End index := d.Methods[i].Range.End

View file

@ -23,6 +23,8 @@ type funcScope struct {
// Range of opcodes corresponding to the function. // Range of opcodes corresponding to the function.
rng DebugRange rng DebugRange
// Variables together with it's type in neo-vm.
variables []string
// Local variables // Local variables
locals map[string]int locals map[string]int
@ -46,6 +48,7 @@ func newFuncScope(decl *ast.FuncDecl, label uint16) *funcScope {
label: label, label: label,
locals: map[string]int{}, locals: map[string]int{},
voidCalls: map[*ast.CallExpr]bool{}, voidCalls: map[*ast.CallExpr]bool{},
variables: []string{},
i: -1, i: -1,
} }
} }