(defn parse-letfn*
[[_ bindings & body :as form] env]
(validate-bindings form env)
(let [bindings (apply array-map bindings) ;; pick only one local with the same name, if more are present.
fns (keys bindings)]
(when-let [[sym] (seq (remove valid-binding-symbol? fns))]
(throw (ex-info (str "Bad binding form: " sym)
(merge {:form form
:sym sym}
(-source-info form env)))))
(let [binds (reduce (fn [binds name]
(assoc binds name
{:op :binding
:env env
:name name
:form name
:local :letfn}))
{} fns)
e (update-in env [:locals] merge binds) ;; pre-seed locals
binds (reduce-kv (fn [binds name bind]
(assoc binds name
(merge bind
{:init (analyze-form (bindings name)
(ctx e :ctx/expr))
:children [:init]})))
{} binds)
e (update-in env [:locals] merge (update-vals binds dissoc-env))
body (analyze-body body e)]
{:op :letfn
:env env
:form form
:bindings (vec (vals binds)) ;; order is irrelevant
:body body
:children [:bindings :body]})))