Skip to content

Commit

Permalink
CLJ-1121 Reimplement -> and ->> without recursion
Browse files Browse the repository at this point in the history
The recursive definitions can be subtly dependent on the behavior
of macros in the forms passed to them.

Signed-off-by: Stuart Halloway <stu@thinkrelevance.com>
  • Loading branch information
gfredericks authored and stuarthalloway committed Aug 14, 2013
1 parent f3259f4 commit 86bfa99
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 9 deletions.
27 changes: 18 additions & 9 deletions src/clj/clojure/core.clj
Original file line number Diff line number Diff line change
Expand Up @@ -1548,22 +1548,31 @@
list already. If there are more forms, inserts the first form as the
second item in second form, etc."
{:added "1.0"}
([x] x)
([x form] (if (seq? form)
(with-meta `(~(first form) ~x ~@(next form)) (meta form))
(list form x)))
([x form & more] `(-> (-> ~x ~form) ~@more)))
[x & forms]
(loop [x x, forms forms]
(if forms
(let [form (first forms)
threaded (if (seq? form)
(with-meta `(~(first form) ~x ~@(next form)) (meta form))
(list form x))]
(recur threaded (next forms)))
x)))

(defmacro ->>
"Threads the expr through the forms. Inserts x as the
last item in the first form, making a list of it if it is not a
list already. If there are more forms, inserts the first form as the
last item in second form, etc."
{:added "1.1"}
([x form] (if (seq? form)
{:added "1.1"}
[x & forms]
(loop [x x, forms forms]
(if forms
(let [form (first forms)
threaded (if (seq? form)
(with-meta `(~(first form) ~@(next form) ~x) (meta form))
(list form x)))
([x form & more] `(->> (->> ~x ~form) ~@more)))
(list form x))]
(recur threaded (next forms)))
x)))

(def map)

Expand Down
18 changes: 18 additions & 0 deletions test/clojure/test_clojure/macros.clj
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,21 @@
; ->
; defmacro definline macroexpand-1 macroexpand


;; -> and ->> should not be dependent on the meaning of their arguments

(defmacro c
[arg]
(if (= 'b (first arg))
:foo
:bar))

(deftest ->test
(let [a 2, b identity]
(is (= (-> a b c)
(c (b a))))))

(deftest ->>test
(let [a 2, b identity]
(is (= (->> a b c)
(c (b a))))))

0 comments on commit 86bfa99

Please sign in to comment.