Skip to content

Commit

Permalink
2973: fix switch branch stmts
Browse files Browse the repository at this point in the history
  • Loading branch information
petar-dambovaliev committed Oct 29, 2024
1 parent 4b68712 commit 5f5172c
Show file tree
Hide file tree
Showing 6 changed files with 106 additions and 31 deletions.
15 changes: 8 additions & 7 deletions gnovm/pkg/gnolang/nodes.go
Original file line number Diff line number Diff line change
Expand Up @@ -2118,13 +2118,14 @@ func (x *BasicLitExpr) GetInt() int {
type GnoAttribute string

const (
ATTR_PREPROCESSED GnoAttribute = "ATTR_PREPROCESSED"
ATTR_PREDEFINED GnoAttribute = "ATTR_PREDEFINED"
ATTR_TYPE_VALUE GnoAttribute = "ATTR_TYPE_VALUE"
ATTR_TYPEOF_VALUE GnoAttribute = "ATTR_TYPEOF_VALUE"
ATTR_IOTA GnoAttribute = "ATTR_IOTA"
ATTR_LOCATIONED GnoAttribute = "ATTR_LOCATIONED"
ATTR_SHIFT_RHS GnoAttribute = "ATTR_SHIFT_RHS"
ATTR_PREPROCESSED GnoAttribute = "ATTR_PREPROCESSED"
ATTR_PREDEFINED GnoAttribute = "ATTR_PREDEFINED"
ATTR_TYPE_VALUE GnoAttribute = "ATTR_TYPE_VALUE"
ATTR_TYPEOF_VALUE GnoAttribute = "ATTR_TYPEOF_VALUE"
ATTR_IOTA GnoAttribute = "ATTR_IOTA"
ATTR_LOCATIONED GnoAttribute = "ATTR_LOCATIONED"
ATTR_SHIFT_RHS GnoAttribute = "ATTR_SHIFT_RHS"
ATTR_LAST_BLOCK_STMT GnoAttribute = "ATTR_LAST_BLOCK_STMT"
)

var rePkgName = regexp.MustCompile(`^[a-z][a-z0-9_]+$`)
Expand Down
16 changes: 3 additions & 13 deletions gnovm/pkg/gnolang/op_exec.go
Original file line number Diff line number Diff line change
Expand Up @@ -676,25 +676,15 @@ EXEC_SWITCH:
bs.Active = bs.Body[cs.BodyIndex] // prefill
case FALLTHROUGH:
ss, ok := m.LastFrame().Source.(*SwitchStmt)
// this is handled in the preprocessor
// should never happen
if !ok {
// fallthrough is only allowed in a switch statement
panic("fallthrough statement out of place")
}
if ss.IsTypeSwitch {
// fallthrough is not allowed in type switches
panic("cannot fallthrough in type switch")
}

b := m.LastBlock()
if b.bodyStmt.NextBodyIndex != len(b.bodyStmt.Body) {
// fallthrough is not the final statement
panic("fallthrough statement out of place")
}
// compute next switch clause from BodyIndex (assigned in preprocess)
nextClause := cs.BodyIndex + 1
if nextClause >= len(ss.Clauses) {
// no more clause after the one executed, this is not allowed
panic("cannot fallthrough final case in switch")
}
// expand block size
cl := ss.Clauses[nextClause]
if nn := cl.GetNumNames(); int(nn) > len(b.Values) {
Expand Down
55 changes: 44 additions & 11 deletions gnovm/pkg/gnolang/preprocess.go
Original file line number Diff line number Diff line change
Expand Up @@ -311,6 +311,11 @@ func initStaticBlocks(store Store, ctx BlockNode, bn BlockNode) {
last.Predefine(false, n.VarName)
}
case *SwitchClauseStmt:
blen := len(n.Body)
if blen > 0 {
n.Body[blen-1].SetAttribute(ATTR_LAST_BLOCK_STMT, true)
}

pushInitRealBlock(n, &last, &stack)
// parent switch statement.
ss := ns[len(ns)-1].(*SwitchStmt)
Expand Down Expand Up @@ -2106,8 +2111,19 @@ func Preprocess(store Store, ctx BlockNode, n Node) Node {

// TRANS_LEAVE -----------------------
case *BranchStmt:

notAllowedFunc := func(s string) {
_, isFunc := last.(*FuncLitExpr)

if isFunc {
panic(fmt.Sprintf("%s statement out of place", s))
}
}

switch n.Op {
case BREAK:
notAllowedFunc("break")

if n.Label == "" {
if !findBreakableNode(ns) {
panic("cannot break with no parent loop or switch")
Expand All @@ -2120,6 +2136,8 @@ func Preprocess(store Store, ctx BlockNode, n Node) Node {
}
}
case CONTINUE:
notAllowedFunc("continue")

if n.Label == "" {
if !findContinuableNode(ns) {
panic("cannot continue with no parent loop")
Expand All @@ -2135,17 +2153,32 @@ func Preprocess(store Store, ctx BlockNode, n Node) Node {
n.Depth = depth
n.BodyIndex = index
case FALLTHROUGH:
if swchC, ok := last.(*SwitchClauseStmt); ok {
// last is a switch clause, find its index in the switch and assign
// it to the fallthrough node BodyIndex. This will be used at
// runtime to determine the next switch clause to run.
swch := lastSwitch(ns)
for i := range swch.Clauses {
if &swch.Clauses[i] == swchC {
// switch clause found
n.BodyIndex = i
break
}
swchC, ok := last.(*SwitchClauseStmt)
if !ok {
// fallthrough is only allowed in a switch statement
panic("fallthrough statement out of place")
}

if n.GetAttribute(ATTR_LAST_BLOCK_STMT) != true {
// no more clause after the one executed, this is not allowed
panic("cannot fallthrough final case in switch")
}

// last is a switch clause, find its index in the switch and assign
// it to the fallthrough node BodyIndex. This will be used at
// runtime to determine the next switch clause to run.
swch := lastSwitch(ns)

if swch.IsTypeSwitch {
// fallthrough is not allowed in type switches
panic("cannot fallthrough in type switch")
}

for i := range swch.Clauses {
if &swch.Clauses[i] == swchC {
// switch clause found
n.BodyIndex = i
break
}
}
default:
Expand Down
17 changes: 17 additions & 0 deletions gnovm/tests/files/for21.gno
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package main

func main() {
for i := 0; i < 10; i++ {
if i == 1 {
_ = func() int {
continue
return 11
}()
}
println(i)
}
println("wat???")
}

// Error:
// continue statement out of place
17 changes: 17 additions & 0 deletions gnovm/tests/files/for22.gno
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package main

func main() {
for i := 0; i < 10; i++ {
if i == 1 {
_ = func() int {
fallthrough
return 11
}()
}
println(i)
}
println("wat???")
}

// Error:
// fallthrough statement out of place
17 changes: 17 additions & 0 deletions gnovm/tests/files/for23.gno
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package main

func main() {
for i := 0; i < 10; i++ {
if i == 1 {
_ = func() int {
break
return 11
}()
}
println(i)
}
println("wat???")
}

// Error:
// break statement out of place

0 comments on commit 5f5172c

Please sign in to comment.