compiler: support break and continue in range loops
This commit is contained in:
parent
ccb53414f2
commit
da89f18999
2 changed files with 71 additions and 2 deletions
|
@ -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.
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in a new issue