forked from TrueCloudLab/neoneo-go
compiler: support break in switch statements
This commit is contained in:
parent
03dc6f7cbb
commit
ccb53414f2
2 changed files with 76 additions and 2 deletions
|
@ -43,6 +43,8 @@ type codegen struct {
|
||||||
|
|
||||||
// A label for the for-loop being currently visited.
|
// A label for the for-loop being currently visited.
|
||||||
currentFor string
|
currentFor string
|
||||||
|
// A label for the switch statement being visited.
|
||||||
|
currentSwitch string
|
||||||
// A label to be used in the next statement.
|
// A label to be used in the next statement.
|
||||||
nextLabel string
|
nextLabel string
|
||||||
|
|
||||||
|
@ -403,7 +405,10 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor {
|
||||||
ast.Walk(c, n.Tag)
|
ast.Walk(c, n.Tag)
|
||||||
|
|
||||||
eqOpcode := c.getEqualityOpcode(n.Tag)
|
eqOpcode := c.getEqualityOpcode(n.Tag)
|
||||||
switchEnd := c.newLabel()
|
switchEnd, label := c.generateLabel(labelEnd)
|
||||||
|
|
||||||
|
lastSwitch := c.currentSwitch
|
||||||
|
c.currentSwitch = label
|
||||||
|
|
||||||
for i := range n.Body.List {
|
for i := range n.Body.List {
|
||||||
lEnd := c.newLabel()
|
lEnd := c.newLabel()
|
||||||
|
@ -434,6 +439,8 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor {
|
||||||
c.setLabel(switchEnd)
|
c.setLabel(switchEnd)
|
||||||
emit.Opcode(c.prog.BinWriter, opcode.DROP)
|
emit.Opcode(c.prog.BinWriter, opcode.DROP)
|
||||||
|
|
||||||
|
c.currentSwitch = lastSwitch
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|
||||||
case *ast.BasicLit:
|
case *ast.BasicLit:
|
||||||
|
@ -683,9 +690,13 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor {
|
||||||
return nil
|
return nil
|
||||||
|
|
||||||
case *ast.BranchStmt:
|
case *ast.BranchStmt:
|
||||||
label := c.currentFor
|
var label string
|
||||||
if n.Label != nil {
|
if n.Label != nil {
|
||||||
label = n.Label.Name
|
label = n.Label.Name
|
||||||
|
} else if n.Tok == token.BREAK {
|
||||||
|
label = c.currentSwitch
|
||||||
|
} else if n.Tok == token.CONTINUE {
|
||||||
|
label = c.currentFor
|
||||||
}
|
}
|
||||||
|
|
||||||
switch n.Tok {
|
switch n.Tok {
|
||||||
|
@ -712,7 +723,9 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor {
|
||||||
fpost := c.newNamedLabel(labelPost, label)
|
fpost := c.newNamedLabel(labelPost, label)
|
||||||
|
|
||||||
lastLabel := c.currentFor
|
lastLabel := c.currentFor
|
||||||
|
lastSwitch := c.currentSwitch
|
||||||
c.currentFor = label
|
c.currentFor = label
|
||||||
|
c.currentSwitch = label
|
||||||
|
|
||||||
// Walk the initializer and condition.
|
// Walk the initializer and condition.
|
||||||
if n.Init != nil {
|
if n.Init != nil {
|
||||||
|
@ -738,6 +751,7 @@ func (c *codegen) Visit(node ast.Node) ast.Visitor {
|
||||||
c.setLabel(fend)
|
c.setLabel(fend)
|
||||||
|
|
||||||
c.currentFor = lastLabel
|
c.currentFor = lastLabel
|
||||||
|
c.currentSwitch = lastSwitch
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|
||||||
|
|
|
@ -127,6 +127,66 @@ var switchTestCases = []testCase{
|
||||||
}`,
|
}`,
|
||||||
big.NewInt(4),
|
big.NewInt(4),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"break from switch",
|
||||||
|
`package main
|
||||||
|
func Main() int {
|
||||||
|
i := 3
|
||||||
|
switch i {
|
||||||
|
case 2: return 2
|
||||||
|
case 3:
|
||||||
|
i = 1
|
||||||
|
break
|
||||||
|
return 3
|
||||||
|
case 4: return 4
|
||||||
|
}
|
||||||
|
return i
|
||||||
|
}`,
|
||||||
|
big.NewInt(1),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"break from outer for",
|
||||||
|
`package main
|
||||||
|
func Main() int {
|
||||||
|
i := 3
|
||||||
|
loop:
|
||||||
|
for i < 10 {
|
||||||
|
i++
|
||||||
|
switch i {
|
||||||
|
case 5:
|
||||||
|
i = 7
|
||||||
|
break loop
|
||||||
|
return 3
|
||||||
|
case 6: return 4
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return i
|
||||||
|
}`,
|
||||||
|
big.NewInt(7),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"continue outer for",
|
||||||
|
`package main
|
||||||
|
func Main() int {
|
||||||
|
i := 2
|
||||||
|
for i < 10 {
|
||||||
|
i++
|
||||||
|
switch i {
|
||||||
|
case 3:
|
||||||
|
i = 7
|
||||||
|
continue
|
||||||
|
case 4, 5, 6, 7: return 5
|
||||||
|
case 8: return 2
|
||||||
|
}
|
||||||
|
|
||||||
|
if i == 7 {
|
||||||
|
return 6
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return i
|
||||||
|
}`,
|
||||||
|
big.NewInt(2),
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSwitch(t *testing.T) {
|
func TestSwitch(t *testing.T) {
|
||||||
|
|
Loading…
Reference in a new issue