compiler: support break and continue in range loops

This commit is contained in:
Evgenii Stratonikov 2020-02-19 11:24:31 +03:00
parent ccb53414f2
commit da89f18999
2 changed files with 71 additions and 2 deletions

View file

@ -763,8 +763,14 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor {
return nil return nil
} }
start := c.newLabel() start, label := c.generateLabel(labelStart)
end := c.newLabel() end := c.newNamedLabel(labelEnd, label)
post := c.newNamedLabel(labelPost, label)
lastFor := c.currentFor
lastSwitch := c.currentSwitch
c.currentFor = label
c.currentSwitch = label
ast.Walk(c, n.X) ast.Walk(c, n.X)
@ -787,11 +793,16 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor {
ast.Walk(c, n.Body) ast.Walk(c, n.Body)
c.setLabel(post)
emit.Opcode(c.prog.BinWriter, opcode.INC) emit.Opcode(c.prog.BinWriter, opcode.INC)
emit.Jmp(c.prog.BinWriter, opcode.JMP, int16(start)) emit.Jmp(c.prog.BinWriter, opcode.JMP, int16(start))
c.setLabel(end) c.setLabel(end)
c.currentFor = lastFor
c.currentSwitch = lastSwitch
return nil return nil
// We dont really care about assertions for the core logic. // We dont really care about assertions for the core logic.

View file

@ -616,6 +616,64 @@ func TestForLoopNestedContinueLabel(t *testing.T) {
eval(t, src, big.NewInt(15)) eval(t, src, big.NewInt(15))
} }
func TestForLoopRangeBreak(t *testing.T) {
src := `
package foo
func Main() int {
var i int
arr := []int{1, 2, 3}
for i = range arr {
if arr[i] == 2 {
break
}
}
return i
}`
eval(t, src, big.NewInt(1))
}
func TestForLoopRangeNestedBreak(t *testing.T) {
src := `
package foo
func Main() int {
k := 5
arr := []int{1, 2, 3}
urr := []int{4, 5, 6, 7}
loop:
for range arr {
k++
for j := range urr {
k++
if j == 3 {
break loop
}
}
}
return k
}`
eval(t, src, big.NewInt(10))
}
func TestForLoopRangeContinue(t *testing.T) {
src := `
package foo
func Main() int {
i := 6
arr := []int{1, 2, 3}
for j := range arr {
if arr[j] < 2 {
continue
}
i++
}
return i
}`
eval(t, src, big.NewInt(8))
}
func TestForLoopRangeNoVariable(t *testing.T) { func TestForLoopRangeNoVariable(t *testing.T) {
src := ` src := `
package foo package foo