From 2cd17f3b569326b4a2829ae5b27c5f6c78e2fe07 Mon Sep 17 00:00:00 2001 From: Petar Dambovaliev Date: Wed, 12 Jun 2024 14:59:29 +0200 Subject: [PATCH] save --- gnovm/pkg/gnolang/preprocess.go | 74 +++++++++++++++++++++--------- gnovm/pkg/gnolang/symbols_table.go | 46 +++++++++++++++++++ gnovm/tests/files/var21.gno | 9 ++++ 3 files changed, 107 insertions(+), 22 deletions(-) create mode 100644 gnovm/pkg/gnolang/symbols_table.go diff --git a/gnovm/pkg/gnolang/preprocess.go b/gnovm/pkg/gnolang/preprocess.go index 38931e91f6e3..652449b09967 100644 --- a/gnovm/pkg/gnolang/preprocess.go +++ b/gnovm/pkg/gnolang/preprocess.go @@ -2726,7 +2726,7 @@ func findUndefined(store Store, last BlockNode, x Expr) (un Name) { } // finds the next undefined identifier and returns it if it is global -func findUndefined2SkipLocals(store Store, last BlockNode, x Expr, t Type) Name { +func findUndefined2SkipLocals(store Store, last BlockNode, x Expr, t Type, st *SymbolTable) Name { name := findUndefined2(store, last, x, t) if name != "" { @@ -2736,61 +2736,87 @@ func findUndefined2SkipLocals(store Store, last BlockNode, x Expr, t Type) Name // skip it if it's a local identifier return "" } + + isLocal := st.IdentifierExists(string(name)) + + if isLocal { + return "" + } } return name } -func findUndefinedStmt(store Store, last BlockNode, stmt Stmt, t Type) Name { +func findUndefinedStmt(store Store, last BlockNode, stmt Stmt, t Type, st *SymbolTable) Name { switch s := stmt.(type) { + case *ValueDecl: + for _, rh := range s.Values { + un := findUndefined2SkipLocals(store, last, rh, t, st) + + if un != "" { + return un + } + } + + for _, rh := range s.NameExprs { + st.AddIdentifier(string(rh.Name)) + } + case *DeclStmt: + for _, rh := range s.Body { + un := findUndefinedStmt(store, last, rh, t, st) + + if un != "" { + return un + } + } case *IncDecStmt: - un := findUndefined2SkipLocals(store, last, s.X, t) + un := findUndefined2SkipLocals(store, last, s.X, t, st) if un != "" { return un } case *PanicStmt: - un := findUndefined2SkipLocals(store, last, s.Exception, t) + un := findUndefined2SkipLocals(store, last, s.Exception, t, st) if un != "" { return un } case *BlockStmt: for _, rh := range s.Body { - un := findUndefinedStmt(store, last, rh, t) + un := findUndefinedStmt(store, last, rh, t, st) if un != "" { return un } } case *DeferStmt: - un := findUndefined2SkipLocals(store, last, s.Call.Func, t) + un := findUndefined2SkipLocals(store, last, s.Call.Func, t, st) if un != "" { return un } for _, rh := range s.Call.Args { - un = findUndefined2SkipLocals(store, last, rh, t) + un = findUndefined2SkipLocals(store, last, rh, t, st) if un != "" { return un } } case *SwitchStmt: - un := findUndefined2SkipLocals(store, last, s.X, t) + un := findUndefined2SkipLocals(store, last, s.X, t, st) if un != "" { return un } - un = findUndefinedStmt(store, last, s.Init, t) + un = findUndefinedStmt(store, last, s.Init, t, st) if un != "" { return un } for _, b := range s.Clauses { b := b - un = findUndefinedStmt(store, last, &b, t) + un = findUndefinedStmt(store, last, &b, t, st) if un != "" { return un @@ -2798,40 +2824,43 @@ func findUndefinedStmt(store Store, last BlockNode, stmt Stmt, t Type) Name { } case *SwitchClauseStmt: for _, rh := range s.Cases { - un := findUndefined2SkipLocals(store, last, rh, t) + un := findUndefined2SkipLocals(store, last, rh, t, st) if un != "" { return un } } case *ExprStmt: - return findUndefined2SkipLocals(store, last, s.X, t) + return findUndefined2SkipLocals(store, last, s.X, t, st) case *AssignStmt: - for _, rh := range s.Rhs { - un := findUndefined2SkipLocals(store, last, rh, t) + for i, rh := range s.Rhs { + if s.Op == DEFINE { + st.AddIdentifier(string(s.Lhs[i].(*NameExpr).Name)) + } + un := findUndefined2SkipLocals(store, last, rh, t, st) if un != "" { return un } } case *IfStmt: - un := findUndefined2SkipLocals(store, last, s.Cond, t) + un := findUndefined2SkipLocals(store, last, s.Cond, t, st) if un != "" { return un } - un = findUndefinedStmt(store, last, &s.Else, t) + un = findUndefinedStmt(store, last, &s.Else, t, st) if un != "" { return un } - un = findUndefinedStmt(store, last, &s.Then, t) + un = findUndefinedStmt(store, last, &s.Then, t, st) if un != "" { return un } case *IfCaseStmt: for _, b := range s.Body { - un := findUndefinedStmt(store, last, b, t) + un := findUndefinedStmt(store, last, b, t, st) if un != "" { return un @@ -2839,19 +2868,19 @@ func findUndefinedStmt(store Store, last BlockNode, stmt Stmt, t Type) Name { } case *ReturnStmt: for _, b := range s.Results { - un := findUndefined2SkipLocals(store, last, b, t) + un := findUndefined2SkipLocals(store, last, b, t, st) if un != "" { return un } } case *RangeStmt: - un := findUndefined2SkipLocals(store, last, s.X, t) + un := findUndefined2SkipLocals(store, last, s.X, t, st) if un != "" { return un } for _, b := range s.Body { - un := findUndefinedStmt(store, last, b, t) + un := findUndefinedStmt(store, last, b, t, st) if un != "" { return un } @@ -2976,8 +3005,9 @@ func findUndefined2(store Store, last BlockNode, x Expr, t Type) (un Name) { ct.String())) } case *FuncLitExpr: + st := NewSymbolTable() for _, stmt := range cx.Body { - un = findUndefinedStmt(store, last, stmt, t) + un = findUndefinedStmt(store, last, stmt, t, st) if un != "" { return diff --git a/gnovm/pkg/gnolang/symbols_table.go b/gnovm/pkg/gnolang/symbols_table.go new file mode 100644 index 000000000000..24417bea0e98 --- /dev/null +++ b/gnovm/pkg/gnolang/symbols_table.go @@ -0,0 +1,46 @@ +package gnolang + +type SymbolTable struct { + scopes []*Scope +} + +type Scope struct { + symbols map[string]struct{} +} + +func NewSymbolTable() *SymbolTable { + return &SymbolTable{ + scopes: []*Scope{newScope()}, + } +} + +func newScope() *Scope { + return &Scope{ + symbols: make(map[string]struct{}), + } +} + +func (st *SymbolTable) EnterScope() { + st.scopes = append(st.scopes, newScope()) +} + +func (st *SymbolTable) ExitScope() { + if len(st.scopes) > 1 { + st.scopes = st.scopes[:len(st.scopes)-1] + } +} + +func (st *SymbolTable) AddIdentifier(name string) { + if len(st.scopes) > 0 { + st.scopes[len(st.scopes)-1].symbols[name] = struct{}{} + } +} + +func (st *SymbolTable) IdentifierExists(name string) bool { + for i := len(st.scopes) - 1; i >= 0; i-- { + if _, exists := st.scopes[i].symbols[name]; exists { + return true + } + } + return false +} diff --git a/gnovm/tests/files/var21.gno b/gnovm/tests/files/var21.gno index 858e2b35f6cb..3aec47ab6e74 100644 --- a/gnovm/tests/files/var21.gno +++ b/gnovm/tests/files/var21.gno @@ -30,3 +30,12 @@ var myVar3 = func() { } var myDep3 string + +var v1 = func() int { + v2 := 11 + return v2 +}() + +var v2 = func() int { + return v1 +}()