Chez parity: missing native core fns + ns runtime fns (jolt-cf1q.7)
Native Chez shims for clojure.core fns that live in the Janet seed but had none
on the zero-Janet spine (they resolved to nil -> "not a fn"):
- host/chez/natives-parity.ss: hash / hash-combine / hash-ordered-coll /
hash-unordered-coll (24-bit masked like core_extra), transient?, rseq (vectors +
sorted colls), cat (transducer).
- jolt-invoke now dispatches a TRANSIENT vec/map/set as a fn (callable on the JVM):
((transient [10 20 30]) 1) -> 20.
- ns.ss: ns-resolve, ns-imports, remove-ns, intern, alias, ns-unalias, refer,
ns-refers, refer-clojure, alter-meta!, reset-meta!, and a real ns-aliases (was a
stub returning {}).
- runtime (require ...)/(use ...) now register :as/:refer into the Chez ns tables
(was a no-op). The Chez analyzer already pre-registers at analyze time, but when
the JANET analyzer compiled the form (prelude path) the Chez tables stayed empty,
so ns-aliases/ns-resolve over an alias diverged — this fixes both paths.
Seed unchanged (overlay doesn't reference these at mint time). zero-Janet corpus
2567->2600, prelude 2557->2590, 0 new divergences on either; Janet gate + JVM cert
green. Filed jolt-vgrp for the pre-existing var-get-of-scalar-native-op quirk.
jolt-cf1q.7
This commit is contained in:
parent
d7cfafd3a9
commit
1ba19759c8
7 changed files with 168 additions and 9 deletions
46
host/chez/natives-parity.ss
Normal file
46
host/chez/natives-parity.ss
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
;; natives-parity.ss (jolt-cf1q.7) — native Chez shims for clojure.core fns that
|
||||
;; live in the Janet seed (src/jolt/core*.janet) but had no Chez shim, so on the
|
||||
;; zero-Janet spine they resolved to nil ("not a fn"). 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 (mirrors core_extra.janet: 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 (mirrors core_refs.janet core-cat): 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)))))))))
|
||||
|
||||
(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)
|
||||
|
|
@ -277,8 +277,14 @@
|
|||
(def-var! "clojure.core" "str-replace" str-replace)
|
||||
(def-var! "clojure.core" "str-replace-all" str-replace-all)
|
||||
|
||||
;; (require ...) / (use ...) at runtime: the Chez AOT driver pre-evals these
|
||||
;; against the analyzer ctx to register aliases + load aliased nss (driver.janet),
|
||||
;; so the emitted call only needs to not crash. A no-op returning nil.
|
||||
(def-var! "clojure.core" "require" (lambda args jolt-nil))
|
||||
(def-var! "clojure.core" "use" (lambda args jolt-nil))
|
||||
;; (require ...) / (use ...) at runtime: register each spec's :as alias + :refer
|
||||
;; names into the runtime ns tables (chez-register-spec!, ns.ss), keyed by the
|
||||
;; current ns. The zero-Janet spine also pre-registers these at analyze time
|
||||
;; (idempotent); but when the JANET analyzer compiled the form (the prelude path)
|
||||
;; the Chez tables were never populated, so ns-aliases/ns-resolve over an :as alias
|
||||
;; need this runtime registration (jolt-cf1q.7). Specs arrive evaluated (quoted).
|
||||
(define (chez-runtime-require . specs)
|
||||
(for-each (lambda (s) (chez-register-spec! (chez-current-ns) s)) specs)
|
||||
jolt-nil)
|
||||
(def-var! "clojure.core" "require" chez-runtime-require)
|
||||
(def-var! "clojure.core" "use" chez-runtime-require)
|
||||
|
|
|
|||
100
host/chez/ns.ss
100
host/chez/ns.ss
|
|
@ -121,7 +121,34 @@
|
|||
(hashtable-values var-table))
|
||||
m))
|
||||
(define (jolt-ns-publics desig) (ns-vars-pmap (ns-desig->name desig)))
|
||||
(define (jolt-ns-aliases desig) (jolt-hash-map))
|
||||
|
||||
;; ns-aliases (jolt-cf1q.7): the {alias-sym -> ns-value} registered under `desig`
|
||||
;; (default the current ns) via require :as / alias. Reads ns-alias-table.
|
||||
(define (jolt-ns-aliases . desig)
|
||||
(let ((cns (if (pair? desig) (ns-desig->name (car desig)) (chez-current-ns)))
|
||||
(m (jolt-hash-map)))
|
||||
(vector-for-each
|
||||
(lambda (k)
|
||||
(when (string=? (car k) cns)
|
||||
(set! m (jolt-assoc m (jolt-symbol #f (cdr k))
|
||||
(intern-ns! (hashtable-ref ns-alias-table k #f))))))
|
||||
(hashtable-keys ns-alias-table))
|
||||
m))
|
||||
|
||||
;; ns-refers (jolt-cf1q.7): the {sym -> var} referred into `desig` via refer/use.
|
||||
(define (jolt-ns-refers desig)
|
||||
(let ((cns (ns-desig->name desig)) (m (jolt-hash-map)))
|
||||
(vector-for-each
|
||||
(lambda (k)
|
||||
(when (string=? (car k) cns)
|
||||
(let* ((target (hashtable-ref ns-refer-table k #f))
|
||||
(c (and target (var-cell-lookup target (cdr k)))))
|
||||
(when c (set! m (jolt-assoc m (jolt-symbol #f (cdr k)) c))))))
|
||||
(hashtable-keys ns-refer-table))
|
||||
m))
|
||||
|
||||
;; ns-imports: Chez has no Java class imports -> always the empty map.
|
||||
(define (jolt-ns-imports . _) (jolt-hash-map))
|
||||
|
||||
;; resolve: an unqualified symbol resolves in the current ns then clojure.core; a
|
||||
;; qualified one in its own ns. Returns the var iff genuinely defined, else nil —
|
||||
|
|
@ -147,6 +174,66 @@
|
|||
(when c (var-cell-defined?-set! c #f) (var-cell-root-set! c jolt-unbound)))
|
||||
jolt-nil)
|
||||
|
||||
;; --- ns runtime fns (jolt-cf1q.7) -------------------------------------------
|
||||
;; ns-resolve: resolve `sym` as if reading it in namespace `ns-desig`. Qualified
|
||||
;; syms consult that ns's :as aliases; unqualified resolve in the ns, its :refers,
|
||||
;; then clojure.core. Returns the var or nil (never interns).
|
||||
(define (jolt-ns-resolve ns-desig sym)
|
||||
(let* ((cns (ns-desig->name ns-desig))
|
||||
(sns (symbol-t-ns sym)) (nm (symbol-t-name sym))
|
||||
(c (if (string? sns)
|
||||
(var-cell-lookup (or (chez-resolve-alias cns sns) sns) nm)
|
||||
(or (var-cell-lookup cns nm)
|
||||
(let ((ref (chez-resolve-refer cns nm))) (and ref (var-cell-lookup ref nm)))
|
||||
(var-cell-lookup "clojure.core" nm)))))
|
||||
(if (and c (var-cell-defined? c)) c jolt-nil)))
|
||||
|
||||
;; remove-ns: drop the namespace from the registry AND its vars, so find-ns
|
||||
;; (which also derives existence from the var-table) returns nil afterward.
|
||||
(define (jolt-remove-ns desig)
|
||||
(let ((nm (ns-desig->name desig)))
|
||||
(hashtable-delete! ns-registry nm)
|
||||
(vector-for-each
|
||||
(lambda (k) (let ((c (hashtable-ref var-table k #f)))
|
||||
(when (and c (string=? (var-cell-ns c) nm)) (hashtable-delete! var-table k))))
|
||||
(hashtable-keys var-table))
|
||||
jolt-nil))
|
||||
|
||||
;; intern: create/set a var ns/sym to val (or an unbound cell). Returns the var.
|
||||
(define (jolt-intern ns-desig sym . vopt)
|
||||
(let ((nm (ns-desig->name ns-desig)) (s (symbol-t-name sym)))
|
||||
(if (pair? vopt) (def-var! nm s (car vopt)) (declare-var! nm s))))
|
||||
|
||||
;; alias / ns-unalias: register/drop an :as alias under the current (or given) ns.
|
||||
;; A runtime alias is registered into the SAME table the analyzer consults, so a
|
||||
;; later form in the program resolves alias/foo (the spine analyzes form by form).
|
||||
(define (jolt-alias alias-sym ns-sym)
|
||||
(chez-register-alias! (chez-current-ns) (symbol-t-name alias-sym) (ns-desig->name ns-sym))
|
||||
jolt-nil)
|
||||
(define (jolt-ns-unalias ns-desig alias-sym)
|
||||
(hashtable-delete! ns-alias-table (cons (ns-desig->name ns-desig) (symbol-t-name alias-sym)))
|
||||
jolt-nil)
|
||||
|
||||
;; refer: bring every public var of `ns-sym` into the current ns as an unqualified
|
||||
;; name (filters accepted/ignored — the corpus uses the bare form). refer-clojure
|
||||
;; is a no-op (clojure.core always resolves on Chez).
|
||||
(define (jolt-refer ns-sym . _filters)
|
||||
(let ((target (ns-desig->name ns-sym)) (cns (chez-current-ns)))
|
||||
(vector-for-each
|
||||
(lambda (c) (when (and (string=? (var-cell-ns c) target) (var-cell-defined? c))
|
||||
(chez-register-refer! cns (var-cell-name c) target)))
|
||||
(hashtable-values var-table))
|
||||
jolt-nil))
|
||||
(define (jolt-refer-clojure . _) jolt-nil)
|
||||
|
||||
;; alter-meta! / reset-meta!: update a var's metadata (var-meta-table, rt.ss).
|
||||
(define (jolt-alter-meta! ref f . args)
|
||||
(let* ((cur (or (hashtable-ref var-meta-table ref #f) (jolt-hash-map)))
|
||||
(new (apply jolt-invoke f cur args)))
|
||||
(hashtable-set! var-meta-table ref new)
|
||||
new))
|
||||
(define (jolt-reset-meta! ref m) (hashtable-set! var-meta-table ref m) m)
|
||||
|
||||
;; --- RESOLVE FRICTION: native-op cells -------------------------------------
|
||||
;; Native-op primitives (+ map reduce …) are INLINED at emit, so they have no
|
||||
;; var-cell and (resolve '+) would be nil — diverging from Clojure where it is a
|
||||
|
|
@ -187,9 +274,20 @@
|
|||
(def-var! "clojure.core" "ns-map" jolt-ns-publics)
|
||||
(def-var! "clojure.core" "ns-interns" jolt-ns-publics)
|
||||
(def-var! "clojure.core" "ns-aliases" jolt-ns-aliases)
|
||||
(def-var! "clojure.core" "ns-refers" jolt-ns-refers)
|
||||
(def-var! "clojure.core" "ns-imports" jolt-ns-imports)
|
||||
(def-var! "clojure.core" "resolve" jolt-resolve)
|
||||
(def-var! "clojure.core" "ns-resolve" jolt-ns-resolve)
|
||||
(def-var! "clojure.core" "find-var" jolt-find-var)
|
||||
(def-var! "clojure.core" "ns-unmap" jolt-ns-unmap)
|
||||
(def-var! "clojure.core" "remove-ns" jolt-remove-ns)
|
||||
(def-var! "clojure.core" "intern" jolt-intern)
|
||||
(def-var! "clojure.core" "alias" jolt-alias)
|
||||
(def-var! "clojure.core" "ns-unalias" jolt-ns-unalias)
|
||||
(def-var! "clojure.core" "refer" jolt-refer)
|
||||
(def-var! "clojure.core" "refer-clojure" jolt-refer-clojure)
|
||||
(def-var! "clojure.core" "alter-meta!" jolt-alter-meta!)
|
||||
(def-var! "clojure.core" "reset-meta!" jolt-reset-meta!)
|
||||
;; *ns* starts at the user namespace (the current ns for -e user code). in-ns
|
||||
;; re-binds it. (ns-name is overridden natively in post-prelude.ss.)
|
||||
(def-var! "clojure.core" "*ns*" (intern-ns! "user"))
|
||||
|
|
|
|||
|
|
@ -320,6 +320,11 @@
|
|||
;; clojure.math ns. Self-contained (only def-var! + Chez math), order-independent.
|
||||
(load "host/chez/math.ss")
|
||||
|
||||
;; parity shims (jolt-cf1q.7): native clojure.core fns missing on the zero-Janet
|
||||
;; spine (hash family / rseq / cat / transient?). After host-table.ss (sorted),
|
||||
;; transients.ss, values.ss (jolt-hash), seq.ss.
|
||||
(load "host/chez/natives-parity.ss")
|
||||
|
||||
;; syntax-quote form builders (jolt-r9lm, inc6b): __sqcat/__sqvec/__sqmap/__sqset/
|
||||
;; __sq1, def-var!'d into clojure.core. A cross-compiled macro expander (analyzer
|
||||
;; on Chez, inc6b) calls these to build its expansion as reader forms. Needs the
|
||||
|
|
|
|||
|
|
@ -132,6 +132,7 @@
|
|||
((procedure? f) (apply f args))
|
||||
((keyword? f) (apply jolt-get (car args) f (cdr args))) ; (:k m [d]) -> (get m :k [d])
|
||||
((jolt-coll? f) (apply jolt-get f args)) ; (coll k [d]) -> (get coll k [d])
|
||||
((jolt-transient? f) (apply jolt-get f args)) ; a transient vec/map/set is callable on the JVM
|
||||
(else (error 'invoke "not a fn" f))))
|
||||
|
||||
;; ============================================================================
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue