Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: switch branch stmts #3043

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 11 additions & 10 deletions gnovm/pkg/gnolang/nodes.go
Original file line number Diff line number Diff line change
Expand Up @@ -149,16 +149,17 @@ func (loc Location) IsZero() bool {
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_LOCATIONE" // XXX DELETE
ATTR_GOTOLOOP_STMT GnoAttribute = "ATTR_GOTOLOOP_STMT" // XXX delete?
ATTR_LOOP_DEFINES GnoAttribute = "ATTR_LOOP_DEFINES" // []Name defined within loops.
ATTR_LOOP_USES GnoAttribute = "ATTR_LOOP_USES" // []Name loop defines actually used.
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_LOCATIONE" // XXX DELETE
ATTR_GOTOLOOP_STMT GnoAttribute = "ATTR_GOTOLOOP_STMT" // XXX delete?
ATTR_LOOP_DEFINES GnoAttribute = "ATTR_LOOP_DEFINES" // []Name defined within loops.
ATTR_LOOP_USES GnoAttribute = "ATTR_LOOP_USES" // []Name loop defines actually used.
ATTR_SHIFT_RHS GnoAttribute = "ATTR_SHIFT_RHS"
ATTR_LAST_BLOCK_STMT GnoAttribute = "ATTR_LAST_BLOCK_STMT"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is there a better name?

)

type Attributes struct {
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
59 changes: 48 additions & 11 deletions gnovm/pkg/gnolang/preprocess.go
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,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)
}

// parent switch statement.
ss := ns[len(ns)-1].(*SwitchStmt)
// anything declared in ss are copied,
Expand Down Expand Up @@ -2125,8 +2130,19 @@ func preprocess1(store Store, ctx BlockNode, n Node) Node {

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

Copy link
Contributor

@ltzmaxwell ltzmaxwell Nov 4, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

delete this line for consistency.

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 @@ -2139,6 +2155,8 @@ func preprocess1(store Store, ctx BlockNode, n Node) Node {
}
}
case CONTINUE:
notAllowedFunc("continue")
Copy link
Contributor

@ltzmaxwell ltzmaxwell Nov 4, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should this logic be merged into findContinuableNode and findBranchLabel, seems what we need to do is to make these two funcs correct.


if n.Label == "" {
if !findContinuableNode(ns) {
panic("cannot continue with no parent loop")
Expand All @@ -2154,17 +2172,36 @@ func preprocess1(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("fallthrough statement out of place")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

any test targeting this?

}

// 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 i == len(swch.Clauses)-1 {
panic("cannot fallthrough final case in switch")
}

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:
// main/files/for21.gno:7:17: 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:
// main/files/for22.gno:7:17: 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:
// main/files/for23.gno:7:17: break statement out of place
2 changes: 1 addition & 1 deletion gnovm/tests/files/switch8.gno
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,4 @@ func main() {
}

// Error:
// fallthrough statement out of place
// main/files/switch8.gno:5:2: fallthrough statement out of place
2 changes: 1 addition & 1 deletion gnovm/tests/files/switch8b.gno
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,4 @@ func main() {
}

// Error:
// cannot fallthrough final case in switch
// main/files/switch8b.gno:10:3: cannot fallthrough final case in switch
2 changes: 1 addition & 1 deletion gnovm/tests/files/switch8c.gno
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,4 @@ func main() {
}

// Error:
// fallthrough statement out of place
// main/files/switch8c.gno:7:3: fallthrough statement out of place
2 changes: 1 addition & 1 deletion gnovm/tests/files/switch9.gno
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,4 @@ func main() {
}

// Error:
// cannot fallthrough in type switch
// main/files/switch9.gno:9:3: cannot fallthrough in type switch
Loading