From 5381ee65d192eee13687e6f31c731ad843327b02 Mon Sep 17 00:00:00 2001 From: Marc Vertes Date: Fri, 10 Jan 2020 17:50:05 +0100 Subject: [PATCH] fix: continue statement was not applied correctly --- _test/for8.go | 18 ++++++++++++++++++ _test/primes.go | 26 ++++++++++++++++++++++++++ interp/cfg.go | 20 +++++--------------- interp/scope.go | 16 ++++++++++------ 4 files changed, 59 insertions(+), 21 deletions(-) create mode 100644 _test/for8.go create mode 100644 _test/primes.go diff --git a/_test/for8.go b/_test/for8.go new file mode 100644 index 000000000..f53c28c24 --- /dev/null +++ b/_test/for8.go @@ -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 diff --git a/_test/primes.go b/_test/primes.go new file mode 100644 index 000000000..6f5ab6af2 --- /dev/null +++ b/_test/primes.go @@ -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 diff --git a/interp/cfg.go b/interp/cfg.go index 79fb3234d..6b239ba86 100644 --- a/interp/cfg.go +++ b/interp/cfg.go @@ -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 { diff --git a/interp/scope.go b/interp/scope.go index 0dda7f425..8b93befb9 100644 --- a/interp/scope.go +++ b/interp/scope.go @@ -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 }