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
|
|
@ -43,6 +43,10 @@
|
|||
;; A var is a mutable cell keyed by "ns/name". A `:def` sets the root; a `:var`
|
||||
;; reference reads it at use time (late binding), so a forward/mutually-recursive
|
||||
;; reference resolves to whatever the cell holds when the call actually runs.
|
||||
;; declare / (def name) with no init reserves a cell holding this placeholder
|
||||
;; until the real def overwrites it (a forward reference resolves to the cell, and
|
||||
;; correct code never reads it before the binding def runs).
|
||||
(define jolt-unbound (string->symbol "#<jolt-unbound>"))
|
||||
(define-record-type var-cell (fields ns name (mutable root)) (nongenerative var-cell-v1))
|
||||
(define var-table (make-hashtable string-hash string=?))
|
||||
(define (jolt-var ns name)
|
||||
|
|
@ -53,6 +57,13 @@
|
|||
c))))
|
||||
(define (var-deref ns name) (var-cell-root (jolt-var ns name)))
|
||||
(define (def-var! ns name v) (var-cell-root-set! (jolt-var ns name) v) v)
|
||||
;; declare / (def name) with no init: reserve the cell ONLY if absent. An
|
||||
;; existing root is left intact — Clojure's (def x) with no init does not clobber
|
||||
;; a prior binding (do (def x 7) (def x) x) => 7.
|
||||
(define (declare-var! ns name)
|
||||
(let ((k (string-append ns "/" name)))
|
||||
(unless (hashtable-ref var-table k #f)
|
||||
(hashtable-set! var-table k (make-var-cell ns name jolt-unbound)))))
|
||||
|
||||
;; --- jolt number printing ----------------------------------------------------
|
||||
;; jolt models every number as a Clojure double: integer-valued values print
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue