fix: continue statement was not applied correctly

This commit is contained in:
Marc Vertes
2020-01-10 17:50:05 +01:00
committed by Traefiker Bot
parent f1cde2be0f
commit 5381ee65d1
4 changed files with 59 additions and 21 deletions

18
_test/for8.go Normal file
View File

@@ -0,0 +1,18 @@
package main
func main() {
for i := 0; i < 4; i++ {
for {
break
}
if i == 1 {
continue
}
println(i)
}
}
// Output:
// 0
// 2
// 3

26
_test/primes.go Normal file
View File

@@ -0,0 +1,26 @@
package main
func Primes(n int) int {
var xs []int
for i := 2; len(xs) < n; i++ {
ok := true
for _, x := range xs {
if i%x == 0 {
ok = false
break
}
}
if !ok {
continue
}
xs = append(xs, i)
}
return xs[n-1]
}
func main() {
println(Primes(3))
}
// Output:
// 5

View File

@@ -44,7 +44,6 @@ var identifier = regexp.MustCompile(`([\pL_][\pL_\d]*)$`)
// Following this pass, the CFG is ready to run
func (interp *Interpreter) cfg(root *node) ([]*node, error) {
sc, pkgName := interp.initScopePkg(root)
var loop, loopRestart *node
var initNodes []*node
var iotaValue int
var err error
@@ -236,12 +235,12 @@ func (interp *Interpreter) cfg(root *node) ([]*node, error) {
}
case forStmt0, forRangeStmt:
loop, loopRestart = n, n.child[0]
sc = sc.pushBloc()
sc.loop, sc.loopRestart = n, n.child[0]
case forStmt1, forStmt2, forStmt3, forStmt3a, forStmt4:
loop, loopRestart = n, n.lastChild()
sc = sc.pushBloc()
sc.loop, sc.loopRestart = n, n.lastChild()
case funcLit:
n.typ = nil // to force nodeType to recompute the type
@@ -313,7 +312,7 @@ func (interp *Interpreter) cfg(root *node) ([]*node, error) {
c[i], c[l] = c[l], c[i]
}
sc = sc.pushBloc()
loop = n
sc.loop = n
case importSpec:
var name, ipath string
@@ -698,14 +697,14 @@ func (interp *Interpreter) cfg(root *node) ([]*node, error) {
if len(n.child) > 0 {
gotoLabel(n.sym)
} else {
n.tnext = loop
n.tnext = sc.loop
}
case continueStmt:
if len(n.child) > 0 {
gotoLabel(n.sym)
} else {
n.tnext = loopRestart
n.tnext = sc.loopRestart
}
case gotoStmt:
@@ -829,7 +828,6 @@ func (interp *Interpreter) cfg(root *node) ([]*node, error) {
body := n.child[0]
n.start = body.start
body.tnext = n.start
loop, loopRestart = nil, nil
sc = sc.pop()
case forStmt1: // for cond {}
@@ -841,7 +839,6 @@ func (interp *Interpreter) cfg(root *node) ([]*node, error) {
cond.tnext = body.start
cond.fnext = n
body.tnext = cond.start
loop, loopRestart = nil, nil
sc = sc.pop()
case forStmt2: // for init; cond; {}
@@ -854,7 +851,6 @@ func (interp *Interpreter) cfg(root *node) ([]*node, error) {
cond.tnext = body.start
cond.fnext = n
body.tnext = cond.start
loop, loopRestart = nil, nil
sc = sc.pop()
case forStmt3: // for ; cond; post {}
@@ -867,7 +863,6 @@ func (interp *Interpreter) cfg(root *node) ([]*node, error) {
cond.fnext = n
body.tnext = post.start
post.tnext = cond.start
loop, loopRestart = nil, nil
sc = sc.pop()
case forStmt3a: // for int; ; post {}
@@ -876,7 +871,6 @@ func (interp *Interpreter) cfg(root *node) ([]*node, error) {
init.tnext = body.start
body.tnext = post.start
post.tnext = body.start
loop, loopRestart = nil, nil
sc = sc.pop()
case forStmt4: // for init; cond; post {}
@@ -890,11 +884,9 @@ func (interp *Interpreter) cfg(root *node) ([]*node, error) {
cond.fnext = n
body.tnext = post.start
post.tnext = cond.start
loop, loopRestart = nil, nil
sc = sc.pop()
case forRangeStmt:
loop, loopRestart = nil, nil
n.start = n.child[0].start
n.child[0].fnext = n
sc = sc.pop()
@@ -1320,7 +1312,6 @@ func (interp *Interpreter) cfg(root *node) ([]*node, error) {
n.start = sbn.start
}
sc = sc.pop()
loop = nil
case switchIfStmt: // like an if-else chain
sbn := n.lastChild() // switch block node
@@ -1357,7 +1348,6 @@ func (interp *Interpreter) cfg(root *node) ([]*node, error) {
n.start = sbn.start
}
sc = sc.pop()
loop = nil
case typeAssertExpr:
if len(n.child) > 1 {

View File

@@ -74,12 +74,14 @@ type symbol struct {
// execution to the index in frame, created exactly from the types layout.
//
type scope struct {
anc *scope // Ancestor upper scope
def *node // function definition node this scope belongs to, or nil
types []reflect.Type // Frame layout, may be shared by same level scopes
level int // Frame level: number of frame indirections to access var during execution
sym map[string]*symbol // Map of symbols defined in this current scope
global bool // true if scope refers to global space (single frame for universe and package level scopes)
anc *scope // Ancestor upper scope
def *node // function definition node this scope belongs to, or nil
loop *node // loop exit node for break statement
loopRestart *node // loop restart node for continue statement
types []reflect.Type // Frame layout, may be shared by same level scopes
level int // Frame level: number of frame indirections to access var during execution
sym map[string]*symbol // Map of symbols defined in this current scope
global bool // true if scope refers to global space (single frame for universe and package level scopes)
}
// push creates a new scope and chain it to the current one
@@ -95,6 +97,8 @@ func (s *scope) push(indirect bool) *scope {
sc.global = s.global
sc.level = s.level
}
// inherit loop state from ancestor
sc.loop, sc.loopRestart = s.loop, s.loopRestart
return &sc
}