compiler: support variable shadowing

Closes #1131.
This commit is contained in:
Evgenii Stratonikov 2020-06-29 16:57:38 +03:00
parent 1ee4acbdbc
commit 40bacc6775
2 changed files with 40 additions and 0 deletions

View file

@ -499,6 +499,9 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor {
return nil
case *ast.IfStmt:
c.scope.vars.newScope()
defer c.scope.vars.dropScope()
lIf := c.newLabel()
lElse := c.newLabel()
lElseEnd := c.newLabel()
@ -553,6 +556,8 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor {
}
}
c.scope.vars.newScope()
c.setLabel(lStart)
last := len(cc.Body) - 1
for j, stmt := range cc.Body {
@ -564,6 +569,8 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor {
}
emit.Jmp(c.prog.BinWriter, opcode.JMPL, switchEnd)
c.setLabel(lEnd)
c.scope.vars.dropScope()
}
c.setLabel(switchEnd)
@ -884,6 +891,9 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor {
return nil
case *ast.ForStmt:
c.scope.vars.newScope()
defer c.scope.vars.dropScope()
fstart, label := c.generateLabel(labelStart)
fend := c.newNamedLabel(labelEnd, label)
fpost := c.newNamedLabel(labelPost, label)
@ -926,6 +936,9 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor {
return nil
case *ast.RangeStmt:
c.scope.vars.newScope()
defer c.scope.vars.dropScope()
start, label := c.generateLabel(labelStart)
end := c.newNamedLabel(labelEnd, label)
post := c.newNamedLabel(labelPost, label)

View file

@ -1,6 +1,7 @@
package compiler_test
import (
"fmt"
"math/big"
"testing"
)
@ -55,3 +56,29 @@ func TestMultiDeclarationLocalCompound(t *testing.T) {
}`
eval(t, src, big.NewInt(6))
}
func TestShadow(t *testing.T) {
srcTmpl := `package foo
func Main() int {
x := 1
y := 10
%s
x += 1 // increase old local
x := 30 // introduce new local
y += x // make sure is means something
}
return x+y
}`
runCase := func(b string) func(t *testing.T) {
return func(t *testing.T) {
src := fmt.Sprintf(srcTmpl, b)
eval(t, src, big.NewInt(42))
}
}
t.Run("If", runCase("if true {"))
t.Run("For", runCase("for i := 0; i < 1; i++ {"))
t.Run("Range", runCase("for range []int{1} {"))
t.Run("Switch", runCase("switch true {\ncase false: x += 2\ncase true:"))
}