diff --git a/NEWS b/NEWS index a4bb456..513ac40 100644 --- a/NEWS +++ b/NEWS @@ -21,6 +21,7 @@ Changes from 0.12.1 * A `yield` inside of a `with` statement will properly suppress implicit returns. * `setv` no longer unnecessarily tries to get attributes + * `loop` no longer replaces string literals equal to "recur" [ Misc. Improvements ] * New contrib module `hy-repr` diff --git a/hy/contrib/loop.hy b/hy/contrib/loop.hy index 40217d6..5d9c9dc 100644 --- a/hy/contrib/loop.hy +++ b/hy/contrib/loop.hy @@ -24,6 +24,8 @@ ;;; The loop/recur macro allows you to construct functions that use tail-call ;;; optimization to allow arbitrary levels of recursion. +(import [hy.contrib.walk [prewalk]]) + (defn --trampoline-- [f] "Wrap f function and make it tail-call optimized." ;; Takes the function "f" and returns a wrapper that may be used for tail- @@ -47,18 +49,11 @@ (assoc active 0 False) result))) -(defn recursive-replace [old-term new-term body] - "Recurses through lists of lists looking for old-term and replacing it with new-term." - ((type body) - (list-comp (cond - [(= term old-term) new-term] - [(instance? hy.HyList term) - (recursive-replace old-term new-term term)] - [True term]) [term body]))) - (defmacro/g! fnr [signature &rest body] - (setv new-body (recursive-replace 'recur g!recur-fn body)) + (setv new-body (prewalk + (fn [x] (if (and (symbol? x) (= x "recur")) g!recur-fn x)) + body)) `(do (import [hy.contrib.loop [--trampoline--]]) (with-decorator diff --git a/tests/native_tests/contrib/loop.hy b/tests/native_tests/contrib/loop.hy index 100b276..3a8ac12 100644 --- a/tests/native_tests/contrib/loop.hy +++ b/tests/native_tests/contrib/loop.hy @@ -44,3 +44,7 @@ (assert True)) (else (assert False)))) + +(defn test-recur-string [] + "test that `loop` doesn't touch a string named `recur`" + (assert (= (loop [] (+ "recur" "1")) "recur1")))