forked from TrueCloudLab/neoneo-go
compiler: support continue statement in for loops
This commit is contained in:
parent
fa2edc46e0
commit
03dc6f7cbb
2 changed files with 83 additions and 1 deletions
|
@ -55,6 +55,7 @@ type labelOffsetType byte
|
||||||
const (
|
const (
|
||||||
labelStart labelOffsetType = iota // labelStart is a default label type
|
labelStart labelOffsetType = iota // labelStart is a default label type
|
||||||
labelEnd // labelEnd is a type for labels that are targets for break
|
labelEnd // labelEnd is a type for labels that are targets for break
|
||||||
|
labelPost // labelPost is a type for labels that are targets for continue
|
||||||
)
|
)
|
||||||
|
|
||||||
type labelWithType struct {
|
type labelWithType struct {
|
||||||
|
@ -692,7 +693,8 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor {
|
||||||
end := c.getLabelOffset(labelEnd, label)
|
end := c.getLabelOffset(labelEnd, label)
|
||||||
emit.Jmp(c.prog.BinWriter, opcode.JMP, int16(end))
|
emit.Jmp(c.prog.BinWriter, opcode.JMP, int16(end))
|
||||||
case token.CONTINUE:
|
case token.CONTINUE:
|
||||||
c.prog.Err = fmt.Errorf("continue statement is not supported yet")
|
post := c.getLabelOffset(labelPost, label)
|
||||||
|
emit.Jmp(c.prog.BinWriter, opcode.JMP, int16(post))
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
@ -707,6 +709,7 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor {
|
||||||
case *ast.ForStmt:
|
case *ast.ForStmt:
|
||||||
fstart, label := c.generateLabel(labelStart)
|
fstart, label := c.generateLabel(labelStart)
|
||||||
fend := c.newNamedLabel(labelEnd, label)
|
fend := c.newNamedLabel(labelEnd, label)
|
||||||
|
fpost := c.newNamedLabel(labelPost, label)
|
||||||
|
|
||||||
lastLabel := c.currentFor
|
lastLabel := c.currentFor
|
||||||
c.currentFor = label
|
c.currentFor = label
|
||||||
|
@ -725,6 +728,7 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor {
|
||||||
|
|
||||||
// Walk body followed by the iterator (post stmt).
|
// Walk body followed by the iterator (post stmt).
|
||||||
ast.Walk(c, n.Body)
|
ast.Walk(c, n.Body)
|
||||||
|
c.setLabel(fpost)
|
||||||
if n.Post != nil {
|
if n.Post != nil {
|
||||||
ast.Walk(c, n.Post)
|
ast.Walk(c, n.Post)
|
||||||
}
|
}
|
||||||
|
|
|
@ -538,6 +538,84 @@ func TestForLoopNestedBreakLabel(t *testing.T) {
|
||||||
eval(t, src, big.NewInt(5))
|
eval(t, src, big.NewInt(5))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestForLoopContinue(t *testing.T) {
|
||||||
|
src := `
|
||||||
|
package foo
|
||||||
|
func Main() int {
|
||||||
|
var i, j int
|
||||||
|
for i < 10 {
|
||||||
|
i++
|
||||||
|
if i >= 5 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
j++
|
||||||
|
}
|
||||||
|
return j
|
||||||
|
}`
|
||||||
|
|
||||||
|
eval(t, src, big.NewInt(4))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestForLoopContinueLabel(t *testing.T) {
|
||||||
|
src := `
|
||||||
|
package foo
|
||||||
|
func Main() int {
|
||||||
|
var i, j int
|
||||||
|
loop:
|
||||||
|
for i < 10 {
|
||||||
|
i++
|
||||||
|
if i >= 5 {
|
||||||
|
continue loop
|
||||||
|
}
|
||||||
|
j++
|
||||||
|
}
|
||||||
|
return j
|
||||||
|
}`
|
||||||
|
|
||||||
|
eval(t, src, big.NewInt(4))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestForLoopNestedContinue(t *testing.T) {
|
||||||
|
src := `
|
||||||
|
package foo
|
||||||
|
func Main() int {
|
||||||
|
var i, k int
|
||||||
|
for i < 10 {
|
||||||
|
i++
|
||||||
|
for j := 0; j < 3; j++ {
|
||||||
|
if j >= 2 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
k++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return k
|
||||||
|
}`
|
||||||
|
|
||||||
|
eval(t, src, big.NewInt(20))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestForLoopNestedContinueLabel(t *testing.T) {
|
||||||
|
src := `
|
||||||
|
package foo
|
||||||
|
func Main() int {
|
||||||
|
var i int
|
||||||
|
loop:
|
||||||
|
for ; i < 10; i += 10 {
|
||||||
|
i++
|
||||||
|
for j := 0; j < 4; j++ {
|
||||||
|
if i == 5 {
|
||||||
|
continue loop
|
||||||
|
}
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return i
|
||||||
|
}`
|
||||||
|
|
||||||
|
eval(t, src, big.NewInt(15))
|
||||||
|
}
|
||||||
|
|
||||||
func TestForLoopRangeNoVariable(t *testing.T) {
|
func TestForLoopRangeNoVariable(t *testing.T) {
|
||||||
src := `
|
src := `
|
||||||
package foo
|
package foo
|
||||||
|
|
Loading…
Reference in a new issue