interp: fix CFG in case of for loop with empty init and cond
Refactor `for` variants for clarity. Ensure all possible 8 combinations are covered. Fixes #942.
This commit is contained in:
16
_test/for16.go
Normal file
16
_test/for16.go
Normal file
@@ -0,0 +1,16 @@
|
||||
package main
|
||||
|
||||
func main() {
|
||||
max := 1
|
||||
for ; ; max-- {
|
||||
if max == 0 {
|
||||
break
|
||||
}
|
||||
println("in for")
|
||||
}
|
||||
println("bye")
|
||||
}
|
||||
|
||||
// Output:
|
||||
// in for
|
||||
// bye
|
||||
@@ -51,13 +51,14 @@ const (
|
||||
fieldList
|
||||
fileStmt
|
||||
forStmt0 // for {}
|
||||
forStmt0a // for init; ; {}
|
||||
forStmt1 // for cond {}
|
||||
forStmt2 // for init; cond; {}
|
||||
forStmt3 // for ; cond; post {}
|
||||
forStmt3a // for init; ; post {}
|
||||
forStmt4 // for init; cond; post {}
|
||||
forRangeStmt // for range
|
||||
forStmt1 // for init; ; {}
|
||||
forStmt2 // for cond {}
|
||||
forStmt3 // for init; cond; {}
|
||||
forStmt4 // for ; ; post {}
|
||||
forStmt5 // for ; cond; post {}
|
||||
forStmt6 // for init; ; post {}
|
||||
forStmt7 // for init; cond; post {}
|
||||
forRangeStmt // for range {}
|
||||
funcDecl
|
||||
funcLit
|
||||
funcType
|
||||
@@ -132,12 +133,13 @@ var kinds = [...]string{
|
||||
fieldList: "fieldList",
|
||||
fileStmt: "fileStmt",
|
||||
forStmt0: "forStmt0",
|
||||
forStmt0a: "forStmt0a",
|
||||
forStmt1: "forStmt1",
|
||||
forStmt2: "forStmt2",
|
||||
forStmt3: "forStmt3",
|
||||
forStmt3a: "forStmt3a",
|
||||
forStmt4: "forStmt4",
|
||||
forStmt5: "forStmt5",
|
||||
forStmt6: "forStmt6",
|
||||
forStmt7: "forStmt7",
|
||||
forRangeStmt: "forRangeStmt",
|
||||
funcDecl: "funcDecl",
|
||||
funcType: "funcType",
|
||||
@@ -656,27 +658,23 @@ func (interp *Interpreter) ast(src, name string, inc bool) (string, *node, error
|
||||
case *ast.ForStmt:
|
||||
// Disambiguate variants of FOR statements with a node kind per variant
|
||||
var kind nkind
|
||||
if a.Cond == nil {
|
||||
if a.Init != nil {
|
||||
if a.Post != nil {
|
||||
kind = forStmt3a
|
||||
} else {
|
||||
kind = forStmt0a
|
||||
}
|
||||
} else {
|
||||
kind = forStmt0
|
||||
}
|
||||
} else {
|
||||
switch {
|
||||
case a.Init == nil && a.Post == nil:
|
||||
kind = forStmt1
|
||||
case a.Init != nil && a.Post == nil:
|
||||
kind = forStmt2
|
||||
case a.Init == nil && a.Post != nil:
|
||||
kind = forStmt3
|
||||
default:
|
||||
kind = forStmt4
|
||||
}
|
||||
switch {
|
||||
case a.Cond == nil && a.Init == nil && a.Post == nil:
|
||||
kind = forStmt0
|
||||
case a.Cond == nil && a.Init != nil && a.Post == nil:
|
||||
kind = forStmt1
|
||||
case a.Cond != nil && a.Init == nil && a.Post == nil:
|
||||
kind = forStmt2
|
||||
case a.Cond != nil && a.Init != nil && a.Post == nil:
|
||||
kind = forStmt3
|
||||
case a.Cond == nil && a.Init == nil && a.Post != nil:
|
||||
kind = forStmt4
|
||||
case a.Cond != nil && a.Init == nil && a.Post != nil:
|
||||
kind = forStmt5
|
||||
case a.Cond == nil && a.Init != nil && a.Post != nil:
|
||||
kind = forStmt6
|
||||
case a.Cond != nil && a.Init != nil && a.Post != nil:
|
||||
kind = forStmt7
|
||||
}
|
||||
st.push(addChild(&root, anc, pos, kind, aNop), nod)
|
||||
|
||||
|
||||
@@ -320,11 +320,7 @@ func (interp *Interpreter) cfg(root *node, importPath string) ([]*node, error) {
|
||||
}
|
||||
}
|
||||
|
||||
case forStmt0, forRangeStmt:
|
||||
sc = sc.pushBloc()
|
||||
sc.loop, sc.loopRestart = n, n.child[0]
|
||||
|
||||
case forStmt0a, forStmt1, forStmt2, forStmt3, forStmt3a, forStmt4:
|
||||
case forStmt0, forStmt1, forStmt2, forStmt3, forStmt4, forStmt5, forStmt6, forStmt7, forRangeStmt:
|
||||
sc = sc.pushBloc()
|
||||
sc.loop, sc.loopRestart = n, n.lastChild()
|
||||
|
||||
@@ -1050,14 +1046,14 @@ func (interp *Interpreter) cfg(root *node, importPath string) ([]*node, error) {
|
||||
body.tnext = n.start
|
||||
sc = sc.pop()
|
||||
|
||||
case forStmt0a: // for init; ; {}
|
||||
case forStmt1: // for init; ; {}
|
||||
init, body := n.child[0], n.child[1]
|
||||
n.start = init.start
|
||||
init.tnext = body.start
|
||||
body.tnext = n.start
|
||||
sc = sc.pop()
|
||||
|
||||
case forStmt1: // for cond {}
|
||||
case forStmt2: // for cond {}
|
||||
cond, body := n.child[0], n.child[1]
|
||||
if !isBool(cond.typ) {
|
||||
err = cond.cfgErrorf("non-bool used as for condition")
|
||||
@@ -1076,7 +1072,7 @@ func (interp *Interpreter) cfg(root *node, importPath string) ([]*node, error) {
|
||||
setFNext(cond, n)
|
||||
sc = sc.pop()
|
||||
|
||||
case forStmt2: // for init; cond; {}
|
||||
case forStmt3: // for init; cond; {}
|
||||
init, cond, body := n.child[0], n.child[1], n.child[2]
|
||||
if !isBool(cond.typ) {
|
||||
err = cond.cfgErrorf("non-bool used as for condition")
|
||||
@@ -1098,7 +1094,14 @@ func (interp *Interpreter) cfg(root *node, importPath string) ([]*node, error) {
|
||||
setFNext(cond, n)
|
||||
sc = sc.pop()
|
||||
|
||||
case forStmt3: // for ; cond; post {}
|
||||
case forStmt4: // for ; ; post {}
|
||||
post, body := n.child[0], n.child[1]
|
||||
n.start = body.start
|
||||
post.tnext = body.start
|
||||
body.tnext = post.start
|
||||
sc = sc.pop()
|
||||
|
||||
case forStmt5: // for ; cond; post {}
|
||||
cond, post, body := n.child[0], n.child[1], n.child[2]
|
||||
if !isBool(cond.typ) {
|
||||
err = cond.cfgErrorf("non-bool used as for condition")
|
||||
@@ -1118,7 +1121,7 @@ func (interp *Interpreter) cfg(root *node, importPath string) ([]*node, error) {
|
||||
body.tnext = post.start
|
||||
sc = sc.pop()
|
||||
|
||||
case forStmt3a: // for init; ; post {}
|
||||
case forStmt6: // for init; ; post {}
|
||||
init, post, body := n.child[0], n.child[1], n.child[2]
|
||||
n.start = init.start
|
||||
init.tnext = body.start
|
||||
@@ -1126,7 +1129,7 @@ func (interp *Interpreter) cfg(root *node, importPath string) ([]*node, error) {
|
||||
post.tnext = body.start
|
||||
sc = sc.pop()
|
||||
|
||||
case forStmt4: // for init; cond; post {}
|
||||
case forStmt7: // for init; cond; post {}
|
||||
init, cond, post, body := n.child[0], n.child[1], n.child[2], n.child[3]
|
||||
if !isBool(cond.typ) {
|
||||
err = cond.cfgErrorf("non-bool used as for condition")
|
||||
|
||||
Reference in New Issue
Block a user