From 91cdce75b4ff62aab3a6129d593efa7c3006042f Mon Sep 17 00:00:00 2001 From: Mike Nolta Date: Wed, 25 Jun 2014 19:31:30 -0400 Subject: [PATCH 1/3] fix #5154 (nested for loop syntax & break behavior) --- src/julia-parser.scm | 10 ++++++---- src/julia-syntax.scm | 17 ++++++++++++++--- 2 files changed, 20 insertions(+), 7 deletions(-) diff --git a/src/julia-parser.scm b/src/julia-parser.scm index 549b02f035bb7..9917541e9dd57 100644 --- a/src/julia-parser.scm +++ b/src/julia-parser.scm @@ -1016,10 +1016,12 @@ (let* ((ranges (parse-comma-separated-iters s)) (body (parse-block s))) (expect-end s) - (let nest ((r ranges)) - (if (null? r) - body - `(for ,(car r) ,(nest (cdr r))))))) + `(for ,(car ranges) + ,(let nest ((r (cdr ranges))) + (if (null? r) + body + `(inner-for ,(car r) ,(nest (cdr r)))))))) + ((if) (let* ((test (parse-cond s)) (then (if (memq (require-token s) '(else elseif)) diff --git a/src/julia-syntax.scm b/src/julia-syntax.scm index 8c27dab2230a3..0f2418e5a005f 100644 --- a/src/julia-syntax.scm +++ b/src/julia-syntax.scm @@ -1793,6 +1793,13 @@ (break-block loop-cont ,(expand-forms (caddr e))))))) + 'inner-while + (lambda (e) + `(scope-block + (_while ,(expand-forms (cadr e)) + (break-block loop-cont + ,(expand-forms (caddr e)))))) + 'break (lambda (e) (if (pair? (cdr e)) @@ -1801,11 +1808,15 @@ 'continue (lambda (e) '(break loop-cont)) - 'for + 'for (lambda (e) (expand-forms `(_for ,@(cdr e) while))) + 'inner-for (lambda (e) (expand-forms `(_for ,@(cdr e) inner-while))) + + '_for (lambda (e) (let ((X (caddr (cadr e))) (lhs (cadr (cadr e))) - (body (caddr e))) + (body (caddr e)) + (while (cadddr e))) ;; (for (= lhs X) body) (let ((coll (gensy)) (state (gensy))) @@ -1813,7 +1824,7 @@ (block (= ,coll ,(expand-forms X)) (= ,state (call (top start) ,coll)) ,(expand-forms - `(while + `(,while (call (top !) (call (top done) ,coll ,state)) (scope-block (block From fde05726bc2110f2ee090d59585017b21d6f36a8 Mon Sep 17 00:00:00 2001 From: Jeff Bezanson Date: Thu, 3 Jul 2014 09:45:10 -0400 Subject: [PATCH 2/3] simpler parsing of multi-range for --- src/julia-parser.scm | 7 ++---- src/julia-syntax.scm | 53 ++++++++++++++++++++++++-------------------- 2 files changed, 31 insertions(+), 29 deletions(-) diff --git a/src/julia-parser.scm b/src/julia-parser.scm index 9917541e9dd57..06872168082ba 100644 --- a/src/julia-parser.scm +++ b/src/julia-parser.scm @@ -1016,11 +1016,8 @@ (let* ((ranges (parse-comma-separated-iters s)) (body (parse-block s))) (expect-end s) - `(for ,(car ranges) - ,(let nest ((r (cdr ranges))) - (if (null? r) - body - `(inner-for ,(car r) ,(nest (cdr r)))))))) + `(for ,(if (length= ranges 1) (car ranges) (cons 'block ranges)) + ,body))) ((if) (let* ((test (parse-cond s)) diff --git a/src/julia-syntax.scm b/src/julia-syntax.scm index 0f2418e5a005f..b15f2de50067a 100644 --- a/src/julia-syntax.scm +++ b/src/julia-syntax.scm @@ -1494,6 +1494,24 @@ (cadr e) (caddr e)))) +(define (expand-for while lhs X body) + ;; (for (= lhs X) body) + (let ((coll (gensy)) + (state (gensy))) + `(scope-block + (block (= ,coll ,(expand-forms X)) + (= ,state (call (top start) ,coll)) + ,(expand-forms + `(,while + (call (top !) (call (top done) ,coll ,state)) + (scope-block + (block + ;; NOTE: enable this to force loop-local var + #;,@(map (lambda (v) `(local ,v)) (lhs-vars lhs)) + ,(lower-tuple-assignment (list lhs state) + `(call (top next) ,coll ,state)) + ,body)))))))) + (define (map-expand-forms e) (map expand-forms e)) (define (expand-forms e) @@ -1808,31 +1826,18 @@ 'continue (lambda (e) '(break loop-cont)) - 'for (lambda (e) (expand-forms `(_for ,@(cdr e) while))) - 'inner-for (lambda (e) (expand-forms `(_for ,@(cdr e) inner-while))) - - '_for + 'for (lambda (e) - (let ((X (caddr (cadr e))) - (lhs (cadr (cadr e))) - (body (caddr e)) - (while (cadddr e))) - ;; (for (= lhs X) body) - (let ((coll (gensy)) - (state (gensy))) - `(scope-block - (block (= ,coll ,(expand-forms X)) - (= ,state (call (top start) ,coll)) - ,(expand-forms - `(,while - (call (top !) (call (top done) ,coll ,state)) - (scope-block - (block - ;; NOTE: enable this to force loop-local var - #;,@(map (lambda (v) `(local ,v)) (lhs-vars lhs)) - ,(lower-tuple-assignment (list lhs state) - `(call (top next) ,coll ,state)) - ,body))))))))) + (let nest ((ranges (if (eq? (car (cadr e)) 'block) + (cdr (cadr e)) + (list (cadr e)))) + (first #t)) + (expand-for (if first 'while 'inner-while) + (cadr (car ranges)) + (caddr (car ranges)) + (if (null? (cdr ranges)) + (caddr e) ;; body + (nest (cdr ranges) #f))))) '+= lower-update-op '-= lower-update-op From 1dc075b5607e8fec073245f662770f61aef17292 Mon Sep 17 00:00:00 2001 From: Jeff Bezanson Date: Thu, 3 Jul 2014 09:53:07 -0400 Subject: [PATCH 3/3] doc and test updates for `for` loop change --- NEWS.md | 2 ++ doc/manual/control-flow.rst | 3 +++ test/core.jl | 10 ++++++++++ 3 files changed, 15 insertions(+) diff --git a/NEWS.md b/NEWS.md index 2cec3a6092db9..232f7614f2316 100644 --- a/NEWS.md +++ b/NEWS.md @@ -55,6 +55,8 @@ New language features * Improved reporting of syntax errors ([#6179]) + * `break` inside a `for` loop with multiple ranges now exits the entire loop nest ([#5154]) + REPL improvements ----------------- diff --git a/doc/manual/control-flow.rst b/doc/manual/control-flow.rst index b1f1a24d49e66..93b24cab61635 100644 --- a/doc/manual/control-flow.rst +++ b/doc/manual/control-flow.rst @@ -514,6 +514,9 @@ forming the cartesian product of its iterables: (2,3) (2,4) +A ``break`` statement inside such a loop exits the entire nest of loops, +not just the inner one. + .. _man-exception-handling: Exception Handling diff --git a/test/core.jl b/test/core.jl index 716a914834793..531448afd8c10 100644 --- a/test/core.jl +++ b/test/core.jl @@ -1772,3 +1772,13 @@ macro let_with_uninit() end @test @let_with_uninit() == 2 + +# issue #5154 +let + v = {} + for i=1:3, j=1:3 + push!(v, (i, j)) + i == 1 && j == 2 && break + end + @test v == {(1,1), (1,2)} +end