diff options
-rw-r--r-- | src/clj/clojure/core.clj | 49 | ||||
-rw-r--r-- | test/clojure/test_clojure/for.clj | 5 |
2 files changed, 48 insertions, 6 deletions
diff --git a/src/clj/clojure/core.clj b/src/clj/clojure/core.clj index 2a17e788..992989e5 100644 --- a/src/clj/clojure/core.clj +++ b/src/clj/clojure/core.clj @@ -2858,7 +2858,7 @@ binding-forms. Supported modifiers are: :let [binding-form expr ...], :while test, :when test. - (take 100 (for [x (range 100000000) y (range 1000000) :while (< y x)] [x y]))" + (take 100 (for [x (range 100000000) y (range 1000000) :while (< y x)] [x y]))" [seq-exprs body-expr] (assert-args for (vector? seq-exprs) "a vector for its binding" @@ -2890,11 +2890,48 @@ (recur (rest ~gxs)))) :else `(cons ~body-expr (~giter (rest ~gxs)))))] - `(fn ~giter [~gxs] - (lazy-seq - (loop [~gxs ~gxs] - (when-first [~bind ~gxs] - ~(do-mod mod-pairs)))))))] + (if next-groups + #_"not the inner-most loop" + `(fn ~giter [~gxs] + (lazy-seq + (loop [~gxs ~gxs] + (when-first [~bind ~gxs] + ~(do-mod mod-pairs))))) + #_"inner-most loop" + (let [gi (gensym "i__") + gb (gensym "b__") + do-cmod (fn do-cmod [[[k v :as pair] & etc]] + (cond + (= k :let) `(let ~v ~(do-cmod etc)) + (= k :while) `(when ~v ~(do-cmod etc)) + (= k :when) `(if ~v + ~(do-cmod etc) + (recur + (unchecked-inc ~gi))) + (keyword? k) + (err "Invalid 'for' keyword " k) + :else + `(do (chunk-append ~gb ~body-expr) + (recur (unchecked-inc ~gi)))))] + `(fn ~giter [~gxs] + (lazy-seq + (loop [~gxs ~gxs] + (when-let [~gxs (seq ~gxs)] + (if (chunked-seq? ~gxs) + (let [c# (chunk-first ~gxs) + size# (int (count c#)) + ~gb (chunk-buffer size#)] + (if (loop [~gi (int 0)] + (if (< ~gi size#) + (let [~bind (.nth c# ~gi)] + ~(do-cmod mod-pairs)) + true)) + (chunk-cons + (chunk ~gb) + (~giter (chunk-rest ~gxs))) + (chunk-cons (chunk ~gb) nil))) + (let [~bind (first ~gxs)] + ~(do-mod mod-pairs)))))))))))] `(let [iter# ~(emit-bind (to-groups seq-exprs))] (iter# ~(second seq-exprs))))) diff --git a/test/clojure/test_clojure/for.clj b/test/clojure/test_clojure/for.clj index d8ebed26..6d9dc59e 100644 --- a/test/clojure/test_clojure/for.clj +++ b/test/clojure/test_clojure/for.clj @@ -121,3 +121,8 @@ '([0 1 1] [1 0 1] [1 2 3] [2 1 3]))) (is (= (for [x (range 6) :let [y (rem x 2)] :when (even? y) z [8 9]] [x z]) '([0 8] [0 9] [2 8] [2 9] [4 8] [4 9])))) + +; :while must skip all subsequent chunks as well as the remainder of +; the current chunk: +(deftest-both Chunked-While + (is (= (for [x (range 100) :while (even? x)] x) '(0)))) |