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:
parent
4f872fce94
commit
817495dd51
5 changed files with 46 additions and 9 deletions
|
|
@ -3,16 +3,16 @@
|
|||
Generated 2026-06-10 by `tools/spec_coverage.py` — do not edit by hand.
|
||||
|
||||
Surface: **694** clojure.core vars (ClojureDocs export; 648 with
|
||||
community examples). jolt interns 552 of them.
|
||||
community examples). jolt interns 553 of them.
|
||||
|
||||
| Status | Count | Meaning |
|
||||
|---|---|---|
|
||||
| implemented+tested | 415 | in jolt and exercised by spec/conformance |
|
||||
| implemented-untested | 137 | in jolt, no direct test — spec entries will add them |
|
||||
| implemented-untested | 138 | in jolt, no direct test — spec entries will add them |
|
||||
| resolvable-not-interned | 2 | works in code but invisible to ns introspection (conformance finding) |
|
||||
| missing-portable | 10 | portable semantics, jolt lacks it — implementation gap |
|
||||
| special-form | 15 | specified in §3, not a library var |
|
||||
| dynamic-var | 31 | classification needed: portable default vs host-dependent |
|
||||
| dynamic-var | 30 | classification needed: portable default vs host-dependent |
|
||||
| agents-taps | 22 | out of scope pending concurrency design note |
|
||||
| stm-refs | 11 | out of scope pending concurrency design note |
|
||||
| jvm-specific | 53 | catalogued, not specified |
|
||||
|
|
@ -47,7 +47,7 @@ UNVERIFIED field; that column will be added as entries land.
|
|||
| `*fn-loader*` | dynamic-var | |
|
||||
| `*in*` | dynamic-var | |
|
||||
| `*math-context*` | dynamic-var | |
|
||||
| `*ns*` | dynamic-var | ✓ |
|
||||
| `*ns*` | implemented-untested | ✓ |
|
||||
| `*out*` | dynamic-var | ✓ |
|
||||
| `*print-dup*` | dynamic-var | ✓ |
|
||||
| `*print-length*` | dynamic-var | ✓ |
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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)))))
|
||||
|
|
|
|||
|
|
@ -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."
|
||||
|
|
|
|||
16
test/spec/ns-var-spec.janet
Normal file
16
test/spec/ns-var-spec.janet
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
# Specification: *ns* — the current-namespace dynamic var (stage 3).
|
||||
# *ns* holds the current NAMESPACE OBJECT; (str *ns*) is its name; it tracks
|
||||
# in-ns at the top level and works with the ns-introspection fns.
|
||||
(use ../support/harness)
|
||||
|
||||
(defspec "*ns* / identity & printing"
|
||||
["str of *ns*" "\"user\"" "(str *ns*)"]
|
||||
["ns-name of *ns*" "(quote user)" "(ns-name *ns*)"]
|
||||
["*ns* is find-ns" "true" "(= (ns-name *ns*) (ns-name (find-ns (quote user))))"]
|
||||
["*ns* not a map" "false" "(map? *ns*)"]
|
||||
["tracks in-ns" "\"jolt.test-ns-a\"" "(do (in-ns (quote jolt.test-ns-a)) (str *ns*))"]
|
||||
["in-ns returns ns" "\"jolt.test-ns-b\"" "(str (in-ns (quote jolt.test-ns-b)))"]
|
||||
["usable with ns fns" "true"
|
||||
"(do (require (quote clojure.string)) (alias (quote nsv) (quote clojure.string)) (some? (get (ns-aliases *ns*) (quote nsv))))"]
|
||||
["ns-unalias via *ns*" "true"
|
||||
"(do (require (quote clojure.string)) (alias (quote nsw) (quote clojure.string)) (ns-unalias *ns* (quote nsw)) (nil? (get (ns-aliases *ns*) (quote nsw))))"])
|
||||
Loading…
Add table
Add a link
Reference in a new issue