From 960d8b6e2459820b6db328c276dfc75198b6cc69 Mon Sep 17 00:00:00 2001 From: Yogthos Date: Tue, 23 Jun 2026 23:50:42 -0400 Subject: [PATCH] refactor: consolidate transducers, dissolve natives-parity.ss (jolt-jcs7) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit natives-parity.ss was a grab-bag (its own header called it 'parity'). Dissolve it into homes that say what they hold: - cat -> natives-transduce.ss (was natives-xform.ss, renamed for the whole transducer surface: volatiles + cat + transduce/sequence) - transient? -> transients.ss - rseq -> natives-seq.ss - hash family -> natives-misc.ss (the public hash API over jolt-hash) The remainder — the #?() feature set, the reader-conditional + re-matcher tagged-map ctors, and macroexpand — is a coherent reader/macro runtime-support unit, kept as natives-reader.ss (np- prefix -> nr-). rt.ss loads + two comment refs updated. Runtime .ss, no re-mint. make test green; hash/transient?/rseq/cat/macroexpand and #?() reader features all verified. --- host/chez/natives-misc.ss | 18 ++++ host/chez/natives-parity.ss | 91 ------------------- host/chez/natives-reader.ss | 52 +++++++++++ host/chez/natives-seq.ss | 7 ++ ...{natives-xform.ss => natives-transduce.ss} | 16 +++- host/chez/post-prelude.ss | 2 +- host/chez/rt.ss | 14 +-- host/chez/transients.ss | 1 + host/chez/vars.ss | 2 +- 9 files changed, 102 insertions(+), 101 deletions(-) delete mode 100644 host/chez/natives-parity.ss create mode 100644 host/chez/natives-reader.ss rename host/chez/{natives-xform.ss => natives-transduce.ss} (78%) diff --git a/host/chez/natives-misc.ss b/host/chez/natives-misc.ss index 80bb9a2..f89ba1b 100644 --- a/host/chez/natives-misc.ss +++ b/host/chez/natives-misc.ss @@ -144,3 +144,21 @@ (loop (fx+ j 1) rest)))))) (begin (write-char c out) (loop (fx+ i 1) as)))))))) (def-var! "clojure.core" "format" jolt-format) + +;; --- hash family (24-bit masked so int? holds) ------------------------------- +;; The public hash API over jolt-hash (values.ss). hash-ordered/-unordered-coll +;; fold the element hashes the way Clojure's IHash mixers do. +(define (nm-h24 x) (bitwise-and (jolt-hash x) #xffffff)) +(define (nm-hash x) (nm-h24 x)) +(define (nm-hash-combine a b) + (bitwise-and (bitwise-xor (nm-h24 a) (+ (nm-h24 b) #x9e3779)) #xffffff)) +(define (nm-hash-ordered-coll coll) + (let loop ((xs (seq->list (jolt-seq coll))) (h 1)) + (if (null? xs) h (loop (cdr xs) (bitwise-and (+ (* 31 h) (nm-h24 (car xs))) #xffffff))))) +(define (nm-hash-unordered-coll coll) + (let loop ((xs (seq->list (jolt-seq coll))) (h 0)) + (if (null? xs) h (loop (cdr xs) (bitwise-and (+ h (nm-h24 (car xs))) #xffffff))))) +(def-var! "clojure.core" "hash" nm-hash) +(def-var! "clojure.core" "hash-combine" nm-hash-combine) +(def-var! "clojure.core" "hash-ordered-coll" nm-hash-ordered-coll) +(def-var! "clojure.core" "hash-unordered-coll" nm-hash-unordered-coll) diff --git a/host/chez/natives-parity.ss b/host/chez/natives-parity.ss deleted file mode 100644 index ddd7a13..0000000 --- a/host/chez/natives-parity.ss +++ /dev/null @@ -1,91 +0,0 @@ -;; natives-parity.ss — native Chez shims for clojure.core fns. Pure-Chez, -;; JVM-matching. -;; -;; Loaded after host-table.ss (htable-sorted?), transients.ss (jolt-transient?), -;; values.ss (jolt-hash), seq.ss (jolt-seq/seq->list/list->cseq/jolt-invoke). - -;; --- hash family (24-bit masked so int? holds) ------ -(define (np-h24 x) (bitwise-and (jolt-hash x) #xffffff)) -(define (np-hash x) (np-h24 x)) -(define (np-hash-combine a b) - (bitwise-and (bitwise-xor (np-h24 a) (+ (np-h24 b) #x9e3779)) #xffffff)) -(define (np-hash-ordered-coll coll) - (let loop ((xs (seq->list (jolt-seq coll))) (h 1)) - (if (null? xs) h (loop (cdr xs) (bitwise-and (+ (* 31 h) (np-h24 (car xs))) #xffffff))))) -(define (np-hash-unordered-coll coll) - (let loop ((xs (seq->list (jolt-seq coll))) (h 0)) - (if (null? xs) h (loop (cdr xs) (bitwise-and (+ h (np-h24 (car xs))) #xffffff))))) - -;; --- transient? --------------------------------------------------------------- -(define (np-transient? x) (jolt-transient? x)) - -;; --- rseq: vectors + sorted colls only (Clojure), reverse of the ascending seq. -(define (np-rseq coll) - (if (or (pvec? coll) (htable-sorted? coll)) - (list->cseq (reverse (seq->list (jolt-seq coll)))) - (jolt-throw (jolt-ex-info "rseq requires a vector or sorted collection" (jolt-hash-map))))) - -;; --- cat transducer: each item of the input -;; is itself a collection, concatenated into the downstream reducing fn. -(define (np-cat rf) - (lambda a - (cond - ((null? a) (jolt-invoke rf)) - ((null? (cdr a)) (jolt-invoke rf (car a))) - (else - (let loop ((xs (seq->list (jolt-seq (cadr a)))) (acc (car a))) - (if (null? xs) acc (loop (cdr xs) (jolt-invoke rf acc (car xs))))))))) - -;; --- reader feature set (for #?() conditionals) — mutable list of name strings, -;; default jolt + default. __reader-features returns the strings; -set! replaces. -(define np-reader-features (list "jolt" "default")) -(define (np-reader-features-get) (list->cseq np-reader-features)) -(define (np-reader-features-set! names) - (set! np-reader-features - (map (lambda (n) (cond ((keyword-t? n) (keyword-t-name n)) ((string? n) n) (else (jolt-pr-str n)))) - (seq->list (jolt-seq names)))) - jolt-nil) - -;; --- reader-conditional / re-matcher: tagged maps (reader-conditional? + the -;; matcher consumers are overlay tagged-value predicates that read :jolt/type). -(define np-kw-type (keyword "jolt" "type")) -(define np-kw-rc (keyword "jolt" "reader-conditional")) -(define np-kw-form (keyword #f "form")) -(define np-kw-spl (keyword #f "splicing?")) -(define np-kw-mat (keyword "jolt" "matcher")) -(define np-kw-re (keyword #f "re")) -(define np-kw-s (keyword #f "s")) -(define np-kw-pos (keyword #f "pos")) -(define (np-reader-conditional form splicing?) - (jolt-hash-map np-kw-type np-kw-rc np-kw-form form np-kw-spl splicing?)) -(define (np-re-matcher re s) - (jolt-hash-map np-kw-type np-kw-mat np-kw-re re np-kw-s s np-kw-pos 0.0)) - -;; (delay? / make-delay / force live in concurrency.ss with the real delay type.) - -;; --- macroexpand-1 / macroexpand: expand a (quoted) call form via the runtime -;; macro table (host-contract hc-macro?/hc-expand-1; forward-referenced, resolved -;; at call time after the spine loads). macroexpand loops until the head is no -;; longer a macro (subforms are not expanded, matching Clojure). -(define (np-macroexpand-1 form) - (if (and (cseq? form) (cseq-list? form) (symbol-t? (seq-first form))) - (let ((ctx (make-analyze-ctx (chez-current-ns)))) - (if (hc-macro? ctx (seq-first form)) (hc-expand-1 ctx form) form)) - form)) -(define (np-macroexpand form) - (let loop ((cur form)) - (let ((nxt (np-macroexpand-1 cur))) (if (eq? cur nxt) cur (loop nxt))))) - -(def-var! "clojure.core" "hash" np-hash) -(def-var! "clojure.core" "hash-combine" np-hash-combine) -(def-var! "clojure.core" "hash-ordered-coll" np-hash-ordered-coll) -(def-var! "clojure.core" "hash-unordered-coll" np-hash-unordered-coll) -(def-var! "clojure.core" "transient?" np-transient?) -(def-var! "clojure.core" "rseq" np-rseq) -(def-var! "clojure.core" "cat" np-cat) -(def-var! "clojure.core" "__reader-features" np-reader-features-get) -(def-var! "clojure.core" "__reader-features-set!" np-reader-features-set!) -(def-var! "clojure.core" "reader-conditional" np-reader-conditional) -(def-var! "clojure.core" "re-matcher" np-re-matcher) -(def-var! "clojure.core" "macroexpand-1" np-macroexpand-1) -(def-var! "clojure.core" "macroexpand" np-macroexpand) diff --git a/host/chez/natives-reader.ss b/host/chez/natives-reader.ss new file mode 100644 index 0000000..458ad6a --- /dev/null +++ b/host/chez/natives-reader.ss @@ -0,0 +1,52 @@ +;; natives-reader.ss — reader/macro runtime-support natives: the #?() reader feature +;; set, the reader-conditional + re-matcher tagged-map constructors, and macroexpand. +;; +;; Loaded late (after ns.ss): macroexpand forward-refs the runtime macro table +;; (host-contract hc-macro?/hc-expand-1) + the analyzer ctx, resolved at call time +;; after the spine loads. The hash / transient? / rseq / cat natives that used to +;; live here moved to natives-misc, transients, natives-seq, and natives-transduce. + +;; --- reader feature set (for #?() conditionals) — mutable list of name strings, +;; default jolt + default. __reader-features returns the strings; -set! replaces. +(define nr-reader-features (list "jolt" "default")) +(define (nr-reader-features-get) (list->cseq nr-reader-features)) +(define (nr-reader-features-set! names) + (set! nr-reader-features + (map (lambda (n) (cond ((keyword-t? n) (keyword-t-name n)) ((string? n) n) (else (jolt-pr-str n)))) + (seq->list (jolt-seq names)))) + jolt-nil) + +;; --- reader-conditional / re-matcher: tagged maps (reader-conditional? + the +;; matcher consumers are overlay tagged-value predicates that read :jolt/type). +(define nr-kw-type (keyword "jolt" "type")) +(define nr-kw-rc (keyword "jolt" "reader-conditional")) +(define nr-kw-form (keyword #f "form")) +(define nr-kw-spl (keyword #f "splicing?")) +(define nr-kw-mat (keyword "jolt" "matcher")) +(define nr-kw-re (keyword #f "re")) +(define nr-kw-s (keyword #f "s")) +(define nr-kw-pos (keyword #f "pos")) +(define (nr-reader-conditional form splicing?) + (jolt-hash-map nr-kw-type nr-kw-rc nr-kw-form form nr-kw-spl splicing?)) +(define (nr-re-matcher re s) + (jolt-hash-map nr-kw-type nr-kw-mat nr-kw-re re nr-kw-s s nr-kw-pos 0.0)) + +;; --- macroexpand-1 / macroexpand: expand a (quoted) call form via the runtime +;; macro table (host-contract hc-macro?/hc-expand-1; forward-referenced, resolved +;; at call time after the spine loads). macroexpand loops until the head is no +;; longer a macro (subforms are not expanded, matching Clojure). +(define (nr-macroexpand-1 form) + (if (and (cseq? form) (cseq-list? form) (symbol-t? (seq-first form))) + (let ((ctx (make-analyze-ctx (chez-current-ns)))) + (if (hc-macro? ctx (seq-first form)) (hc-expand-1 ctx form) form)) + form)) +(define (nr-macroexpand form) + (let loop ((cur form)) + (let ((nxt (nr-macroexpand-1 cur))) (if (eq? cur nxt) cur (loop nxt))))) + +(def-var! "clojure.core" "__reader-features" nr-reader-features-get) +(def-var! "clojure.core" "__reader-features-set!" nr-reader-features-set!) +(def-var! "clojure.core" "reader-conditional" nr-reader-conditional) +(def-var! "clojure.core" "re-matcher" nr-re-matcher) +(def-var! "clojure.core" "macroexpand-1" nr-macroexpand-1) +(def-var! "clojure.core" "macroexpand" nr-macroexpand) diff --git a/host/chez/natives-seq.ss b/host/chez/natives-seq.ss index 25a0e91..eef5cb0 100644 --- a/host/chez/natives-seq.ss +++ b/host/chez/natives-seq.ss @@ -213,3 +213,10 @@ (def-var! "clojure.core" "partition" jolt-partition) (def-var! "clojure.core" "sort" jolt-sort) (def-var! "clojure.core" "identical?" jolt-identical?) + +;; rseq: vectors + sorted colls only (Clojure), the reverse of the ascending seq. +(define (jolt-rseq coll) + (if (or (pvec? coll) (htable-sorted? coll)) + (list->cseq (reverse (seq->list (jolt-seq coll)))) + (jolt-throw (jolt-ex-info "rseq requires a vector or sorted collection" (jolt-hash-map))))) +(def-var! "clojure.core" "rseq" jolt-rseq) diff --git a/host/chez/natives-xform.ss b/host/chez/natives-transduce.ss similarity index 78% rename from host/chez/natives-xform.ss rename to host/chez/natives-transduce.ss index 941a5cb..96ae477 100644 --- a/host/chez/natives-xform.ss +++ b/host/chez/natives-transduce.ss @@ -1,4 +1,5 @@ -;; volatiles + sequence / transduce — the transducer application surface. +;; natives-transduce.ss — the transducer surface: volatiles, the `cat` transducer, +;; and sequence / transduce application. ;; ;; `sequence` and `transduce` are seed natives. The stateful transducer arities ;; (take-nth/map-indexed/partition-by/dedupe/distinct, all overlay) use @@ -47,3 +48,16 @@ (def-var! "clojure.core" "transduce" jolt-transduce) (def-var! "clojure.core" "sequence" jolt-sequence) + +;; --- cat --------------------------------------------------------------------- +;; cat transducer: each input item is itself a collection, concatenated into the +;; downstream reducing fn. +(define (jolt-cat rf) + (lambda a + (cond + ((null? a) (jolt-invoke rf)) + ((null? (cdr a)) (jolt-invoke rf (car a))) + (else + (let loop ((xs (seq->list (jolt-seq (cadr a)))) (acc (car a))) + (if (null? xs) acc (loop (cdr xs) (jolt-invoke rf acc (car xs))))))))) +(def-var! "clojure.core" "cat" jolt-cat) diff --git a/host/chez/post-prelude.ss b/host/chez/post-prelude.ss index 0659641..7a47e03 100644 --- a/host/chez/post-prelude.ss +++ b/host/chez/post-prelude.ss @@ -18,7 +18,7 @@ (def-var! "clojure.core" "get-validator" jolt-get-validator) ;; volatiles: a Chez volatile is a jvol record, but the overlay vreset!/vswap!/ ;; volatile? drive it via jolt.host/ref-put!+get / :jolt/type (tagged-table only). -;; Override with the native versions (defined in natives-xform.ss). +;; Override with the native versions (defined in natives-transduce.ss). (def-var! "clojure.core" "vreset!" jolt-vreset!) (def-var! "clojure.core" "vswap!" jolt-vswap!) (def-var! "clojure.core" "volatile?" jolt-volatile-pred?) diff --git a/host/chez/rt.ss b/host/chez/rt.ss index ac184e0..d690ec5 100644 --- a/host/chez/rt.ss +++ b/host/chez/rt.ss @@ -286,13 +286,13 @@ ;; Loaded LAST so %ls-seq captures the fully-extended (sorted-aware) jolt-seq. (load "host/chez/lazy-bridge.ss") -;; volatiles + sequence / transduce: native volatile boxes + +;; transducer surface: native volatile boxes, cat, + ;; the transduce/sequence entry points over into-xform/reduce-seq. After ;; natives-seq.ss (into-xform), seq.ss (reduce-seq) + atoms.ss (deref). -(load "host/chez/natives-xform.ss") +(load "host/chez/natives-transduce.ss") ;; vars as first-class objects: var?/var-get/deref/invoke/=/ -;; pr-str over the rt.ss var-cell. After natives-xform.ss (chains deref) + the +;; pr-str over the rt.ss var-cell. After natives-transduce.ss (chains deref) + the ;; printers. emit lowers :the-var to (jolt-var ns name). (load "host/chez/vars.ss") @@ -356,10 +356,10 @@ ;; clojure.math ns. Self-contained (only def-var! + Chez math), order-independent. (load "host/chez/math.ss") -;; parity shims: native clojure.core fns not covered by the overlay -;; (hash family / rseq / cat / transient?). After host-table.ss (sorted), -;; transients.ss, values.ss (jolt-hash), seq.ss. -(load "host/chez/natives-parity.ss") +;; reader/macro runtime support: #?() feature set, reader-conditional + re-matcher +;; tagged-map ctors, macroexpand. After ns.ss; macroexpand call-time-refs the macro +;; table (host-contract) + analyzer ctx. +(load "host/chez/natives-reader.ss") ;; Java-style arrays: object/typed array constructors + a jolt-array ;; backing; extends count/nth/seq/get/ref-put! so the overlay aget/aset/alength see diff --git a/host/chez/transients.ss b/host/chez/transients.ss index 5c40624..3a595e7 100644 --- a/host/chez/transients.ss +++ b/host/chez/transients.ss @@ -192,6 +192,7 @@ (%prev-jolt-nth coll i d))))) (def-var! "clojure.core" "transient" jolt-transient-new) +(def-var! "clojure.core" "transient?" jolt-transient?) (def-var! "clojure.core" "persistent!" jolt-persistent!) (def-var! "clojure.core" "conj!" jolt-conj!) (def-var! "clojure.core" "assoc!" jolt-assoc!) diff --git a/host/chez/vars.ss b/host/chez/vars.ss index 0876ba2..3472957 100644 --- a/host/chez/vars.ss +++ b/host/chez/vars.ss @@ -9,7 +9,7 @@ ;; with-redefs) lives in dyn-binding.ss, which chains the var-read paths set up ;; here. ;; -;; Loaded LAST (after natives-xform.ss): chains jolt-deref (atom/volatile arms) +;; Loaded LAST (after natives-transduce.ss): chains jolt-deref (atom/volatile arms) ;; and the printers. (define (jolt-var-pred? x) (var-cell? x))