Chez Phase 2 (inc M): dynamic var binding (jolt-2o7x)

Add the dynamic-binding cluster on the Chez RT: a per-thread binding stack
(host/chez/dyn-binding.ss) backing binding / with-bindings* / var-set /
thread-bound? / with-local-vars / with-redefs / bound-fn* /
get-thread-bindings / alter-var-root + the __local-var seam.

Frames are stored innermost-first as identity-keyed alists of mutable
(cell . value) pairs, so var-set updates the current binding in place. The
two var-read paths — var-deref (compiled code) and jolt-var-get (var-get /
deref on a cell) — are chained onto the stack so a `binding` frame is seen
by every read, with a fast path when the stack is empty. var-cells now hash
by ns/name so a var works as a map key (with-redefs builds (hash-map (var f)
v); get-thread-bindings returns a var-keyed map).

Fix a latent bug exposed once with-in-str could bind *in*: seq? didn't
recognize a lazy-seq. predicates.ss's jolt-seq? predates the lazyseq record,
and unlike the native-op dispatchers it's reached via var-deref, so the
patch must re-def-var! the var, not just set! the top-level binding.

Note: with-bindings* over a hash-map literal now returns the correct Clojure
value where the seed returns a stale one — the seed's PHM can't find a var
key (which is why its `binding` uses array-map); on Chez frames look up by
cell identity.

Prelude corpus parity 1972 -> 2000, floor raised. Gate: _dynbind 24/24,
prelude corpus 0 divergences, full jpm test, conformance 355x3.
This commit is contained in:
Yogthos 2026-06-18 18:29:55 -04:00
parent 737288bff5
commit fc6551f877
5 changed files with 238 additions and 1 deletions

View file

@ -258,3 +258,10 @@
;; var-cell + var-cell-defined?, jolt-symbol/jolt-hash-map/jolt-assoc, chez-current-ns
;; (multimethods.ss), list->cseq (seq.ss), and the fully-patched printers (vars.ss).
(load "host/chez/ns.ss")
;; dynamic var binding (jolt-2o7x, Phase 2): the per-thread binding stack +
;; push/pop/get-thread-bindings/__thread-bound?/var-set/alter-var-root/__local-var.
;; Chains var-deref (rt.ss) and jolt-var-get (vars.ss) onto the stack, so a `binding`
;; frame is seen by every var read. Loaded LAST: needs the fully-extended var-read
;; paths + jolt-hash-map/pmap-fold/pmap-assoc (collections.ss).
(load "host/chez/dyn-binding.ss")