Chez Phase 1 (increment 3g): letfn + declare/def-no-init
Closes the last two non-host-interop prelude emit gaps. letfn now analyzes to a :let node flagged :letrec — the binding fns are bound into the env together before any spec is analyzed, so siblings and self resolve. The Chez back end lowers it to letrec*; the Janet back end punts it at emit (its sequential let* can't express the mutual recursion — same interpreter fallback as before, just decided at emit-ir instead of analyze). (def x) with no init (declare) analyzes to a :def with :no-init instead of punting. Chez reserves the var cell via declare-var! (which doesn't clobber an existing root — (do (def x 7) (def x) x) => 7); the Janet back end still punts to the interpreter, which interns a genuinely-unbound var. fallback-zero-test now checks emit-ir too, not just analyze-form, so the real compile-vs-interpret decision is what it asserts (letfn/def-no-init analyze but the Janet back end punts them). letfn stays in must-punt with an updated note. Prelude emit reach 342 -> 348/355 (40-lazy now 13/13); Chez subset 664 -> 672, 0 divergences; emit-test 110 -> 117. Full gate green.
This commit is contained in:
parent
930800f9a6
commit
0f7d2753a8
8 changed files with 119 additions and 31 deletions
|
|
@ -179,6 +179,11 @@
|
|||
(tuple/slice out))
|
||||
|
||||
(defn- emit-let [ctx node]
|
||||
# letfn lowers to a :let flagged :letrec (mutually-recursive bindings). A
|
||||
# compiled sequential Janet let can't forward-ref a sibling, so punt to the
|
||||
# interpreter (the deliberate uncompilable channel) — its shared mutable env
|
||||
# gives the letrec semantics. The Chez back end compiles it directly (letrec*).
|
||||
(when (node :letrec) (error "jolt/uncompilable: letfn"))
|
||||
(def binds @[])
|
||||
(each pair (vview (node :bindings))
|
||||
(def p (vview pair))
|
||||
|
|
@ -740,7 +745,12 @@
|
|||
:recur (emit-recur ctx node)
|
||||
:try (emit-try ctx node)
|
||||
:throw ['error (emit ctx (node :expr))]
|
||||
:def (let [cell (cell-for ctx (node :ns) (node :name))
|
||||
:def (do
|
||||
# (def name) with no init (declare): no compiled value to install —
|
||||
# punt to the interpreter, which interns a genuinely-unbound var
|
||||
# (compiling it to nil would diverge: reading an unbound var throws).
|
||||
(when (node :no-init) (error "jolt/uncompilable: def with no init"))
|
||||
(let [cell (cell-for ctx (node :ns) (node :name))
|
||||
meta (node :meta)
|
||||
setter (if (and meta (not (empty? meta))) (var-setter-meta cell meta) (var-setter cell))
|
||||
_ (cgen-collect! ctx node)
|
||||
|
|
@ -759,7 +769,7 @@
|
|||
# redefined (jolt-wf4).
|
||||
(let [init-form (emit ctx (node :init))]
|
||||
(when-let [ud (get (ctx :env) :unit-defs)] (put ud cell true))
|
||||
(tuple setter init-form)))))
|
||||
(tuple setter init-form))))))
|
||||
:let (emit-let ctx node)
|
||||
:fn (emit-fn ctx node)
|
||||
:invoke (emit-invoke ctx node)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue