recur
(recur exprs*)
Source docstring:
Evaluates the exprs in order, then, in parallel, rebinds
the bindings of the recursion point to the values of the exprs.
Execution then jumps back to the recursion point, a loop or fn method.
(defmethod parse 'recur
[op env [_ & exprs :as form] _ _]
(let [context (:context env)
frame (first *recur-frames*)
add-implicit-target-object? (and (:protocol-impl frame)
(= (count exprs) (dec (count (:params frame)))))
exprs (cond->> exprs add-implicit-target-object? (cons nil))
exprs (disallowing-recur (vec (map #(analyze (assoc env :context :expr) %) exprs)))]
(when-not frame
(throw (error env "Can't recur here")))
(when-not (= (count exprs) (count (:params frame)))
(throw (error env (str "recur argument count mismatch, expected: "
(count (:params frame)) " args, got: " (count exprs)))))
(when (and (:protocol-impl frame)
(not add-implicit-target-object?))
(warning :protocol-impl-recur-with-target env {:form (:form (first exprs))}))
(reset! (:flag frame) true)
(swap! (:tags frame) (fn [tags]
(mapv (fn [tag expr]
(if (= :loop (:local expr))
'any
(add-types tag (:tag expr))))
tags exprs)))
(assoc {:env env :op :recur :form form}
:frame frame
:exprs exprs
:children [:exprs])))
(defmethod emit* :recur
[{:keys [frame exprs env]}]
(let [temps (vec (take (count exprs) (repeatedly gensym)))
params (:params frame)]
(dotimes [i (count exprs)]
(emitln "var " (temps i) " = " (exprs i) ";"))
(dotimes [i (count exprs)]
(emitln (munge (params i)) " = " (temps i) ";"))
(emitln "continue;")))