(defn analyze-let
[[op bindings & body :as form] {:keys [context loop-id] :as env}]
(validate-bindings form env)
(let [loop? (= 'loop* op)]
(loop [bindings bindings
env (ctx env :ctx/expr)
binds []]
(if-let [[name init & bindings] (seq bindings)]
(if (not (valid-binding-symbol? name))
(throw (ex-info (str "Bad binding form: " name)
(merge {:form form
:sym name}
(-source-info form env))))
(let [init-expr (analyze-form init env)
bind-expr {:op :binding
:env env
:name name
:init init-expr
:form name
:local (if loop? :loop :let)
:children [:init]}]
(recur bindings
(assoc-in env [:locals name] (dissoc-env bind-expr))
(conj binds bind-expr))))
(let [body-env (assoc env :context (if loop? :ctx/return context))
body (analyze-body body (merge body-env
(when loop?
{:loop-id loop-id
:loop-locals (count binds)})))]
{:body body
:bindings binds
:children [:bindings :body]})))))