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:
Yogthos 2026-06-20 15:46:11 -04:00
parent d7cfafd3a9
commit 1ba19759c8
7 changed files with 168 additions and 9 deletions

View file

@ -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"))