core: *ns* — the current-namespace dynamic var

*ns* is interned in clojure.core holding the current NAMESPACE OBJECT, kept
in sync by ctx-set-current-ns through a var table cached on the env (one
table put on the hot path; core-bench A/B neutral). A thread binding
(binding [*ns* ...]) shadows the root through var-get as usual. in-ns now
returns the namespace object (Clojure); str renders a namespace as its name
and pr-str as #namespace[name]. The ns-designator helper accepts namespace
objects (they are tagged STRUCTS — the old table?-based check never matched
them), so (ns-aliases *ns*) / (ns-unalias *ns* 'a) work — SCI and the jank
syntax-quote corpus use exactly that shape.

Known divergence (documented): inside an interpreted fn, *ns* reflects the
fn's defining ns (jolt's resolution model rebinds current-ns per call);
top-level and load-time reads match Clojure.

Gate green (conformance 326x3, suite 4572 >= 4540, all batteries,
specs+unit +8 *ns* rows); bench neutral.
This commit is contained in:
Yogthos 2026-06-10 13:05:15 -04:00
parent 4f872fce94
commit 817495dd51
5 changed files with 46 additions and 9 deletions

View file

@ -1612,6 +1612,12 @@
# Readable rendering of a value (Clojure pr semantics): strings quoted,
# keywords with leading ':', symbols by name, collections with their reader
# syntax. Used by both pr-str (readable) and str (collection elements).
# A namespace's :name may be a string or a symbol struct depending on the
# creation path — normalize for display.
(defn- ns-display-name [ns]
(def n (ns :name))
(if (and (struct? n) (= :symbol (get n :jolt/type))) (n :name) (string n)))
(var pr-render nil)
# Format a number the way Clojure prints it: infinity and NaN have named forms
@ -1686,6 +1692,10 @@
(and (struct? v) (= :jolt/inst (v :jolt/type)))
(do (buffer/push-string buf "#inst \"") (buffer/push-string buf (inst->rfc3339 v))
(buffer/push-string buf "\""))
(= :jolt/namespace (get v :jolt/type))
(do (buffer/push-string buf "#namespace[")
(buffer/push-string buf (ns-display-name v))
(buffer/push-string buf "]"))
(and (table? v) (= :jolt/var (get v :jolt/type))) (buffer/push-string buf (var-display v))
(core-sorted-map? v) (pr-render-pairs buf (sorted-map-entries v))
(core-sorted-set? v) (pr-render-seq buf (v :items) "#{" "}")
@ -1718,6 +1728,7 @@
(if (v :ns) (string (v :ns) "/" (v :name)) (v :name))
(and (struct? v) (= :jolt/uuid (v :jolt/type))) (v :str)
(and (struct? v) (= :jolt/inst (v :jolt/type))) (inst->rfc3339 v)
(= :jolt/namespace (get v :jolt/type)) (ns-display-name v)
(and (table? v) (= :jolt/var (get v :jolt/type))) (var-display v)
(number? v) (fmt-number v)
(= true v) "true"

View file

@ -796,9 +796,9 @@
quoted symbol arrives evaluated."
[ctx sym]
(def ns-name (if (and (struct? sym) (= :symbol (sym :jolt/type))) (sym :name) (string sym)))
(ctx-find-ns ctx ns-name)
(def the-ns-obj (ctx-find-ns ctx ns-name))
(ctx-set-current-ns ctx ns-name)
nil)
the-ns-obj)
(defn use-impl
"(use '[ns ...] ...) — refer ALL public vars of each used ns into the CURRENT ns.
@ -953,6 +953,12 @@
# Var/namespace lookups that need the ctx (the rest of the var fns — var-get/
# var-set/var?/alter-var-root/alter-meta!/reset-meta! — are plain core-bindings).
(ns-intern core "find-var" (fn [sym] (find-var ctx sym)))
# *ns*: the current-namespace dynamic var. Its root is kept in sync by
# ctx-set-current-ns via the cached var table (env :ns-var); a thread
# binding (binding [*ns* ...]) shadows the root through var-get as usual.
(def ns-var (ns-intern core "*ns*" (ctx-find-ns ctx (ctx-current-ns ctx))))
(put ns-var :dynamic true)
(put (ctx :env) :ns-var ns-var)
(ns-intern core "intern"
(fn [ns-name sym-name &opt val]
(def ns (ctx-find-ns ctx (if (struct? ns-name) (ns-name :name) ns-name)))
@ -969,7 +975,7 @@
(keyword? x) (string x)
nil)))
(def ns-of (fn [x]
(if (and (table? x) (not (nil? (x :mappings))))
(if (= :jolt/namespace (get x :jolt/type))
x
(let [nm (ns-name-of x)]
(if nm (get (get (ctx :env) :namespaces) nm) nil)))))

View file

@ -509,9 +509,13 @@
(get (ctx :env) :current-ns))
(defn ctx-set-current-ns
"Set the current namespace symbol."
"Set the current namespace symbol. Also keeps the *ns* dynamic var's root in
sync (the var table is cached on the env by install-stateful-fns! — one table
put on this hot path, no ns lookup chain)."
[ctx ns-sym]
(put (ctx :env) :current-ns ns-sym))
(put (ctx :env) :current-ns ns-sym)
(when-let [v (get (ctx :env) :ns-var)]
(put v :root (ctx-find-ns ctx ns-sym))))
(defn all-ns
"Return a list of all namespaces in the context."