Merge pull request #60 from jolt-lang/ns-alias-unify
core: one alias store (jolt-ark); '.' classified as a special form
This commit is contained in:
commit
c24c7617b8
6 changed files with 55 additions and 22 deletions
|
|
@ -9,7 +9,7 @@ community examples). jolt interns 564 of them.
|
|||
|---|---|---|
|
||||
| implemented+tested | 564 | in jolt and exercised by spec/conformance |
|
||||
| implemented-untested | 0 | in jolt, no direct test — spec entries will add them |
|
||||
| resolvable-not-interned | 1 | works in code but invisible to ns introspection (conformance finding) |
|
||||
| resolvable-not-interned | 0 | works in code but invisible to ns introspection (conformance finding) |
|
||||
| missing-portable | 0 | portable semantics, jolt lacks it — implementation gap |
|
||||
| special-form | 15 | specified in §3, not a library var |
|
||||
| dynamic-var | 29 | classification needed: portable default vs host-dependent |
|
||||
|
|
|
|||
|
|
@ -286,7 +286,7 @@
|
|||
# aliased ref like g/foo wouldn't resolve mid-compile. Same ns h-current-ns uses.
|
||||
(let [cur-name (or (get (ctx :env) :compile-ns) (ctx-current-ns ctx))
|
||||
current-ns (ctx-find-ns ctx cur-name)
|
||||
aliased-ns (ns-import-lookup current-ns ns)
|
||||
aliased-ns (or (ns-alias-lookup current-ns ns) (ns-import-lookup current-ns ns))
|
||||
target-ns (ctx-find-ns ctx (or aliased-ns ns))]
|
||||
(ns-find target-ns name))
|
||||
(if (get bindings name) nil
|
||||
|
|
@ -374,7 +374,7 @@
|
|||
(maybe-require-ns ctx ns-name)
|
||||
(when alias
|
||||
(let [current-ns (ctx-find-ns ctx (ctx-current-ns ctx))]
|
||||
(ns-import current-ns alias ns-name)))
|
||||
(ns-add-alias current-ns alias ns-name)))
|
||||
(when refer-syms
|
||||
(let [source-ns (ctx-find-ns ctx ns-name)
|
||||
target-ns (ctx-find-ns ctx (ctx-current-ns ctx))]
|
||||
|
|
@ -436,7 +436,7 @@
|
|||
(if (nil? v) (error (string "Unsupported Thread member: Thread/" name)) v))
|
||||
(if (not (nil? ns))
|
||||
(let [current-ns (ctx-find-ns ctx (ctx-current-ns ctx))
|
||||
aliased-ns (ns-import-lookup current-ns ns)
|
||||
aliased-ns (or (ns-alias-lookup current-ns ns) (ns-import-lookup current-ns ns))
|
||||
target-ns (ctx-find-ns ctx (or aliased-ns ns))
|
||||
v (and target-ns (ns-find target-ns name))]
|
||||
(if v (var-get v)
|
||||
|
|
@ -1026,7 +1026,14 @@
|
|||
# interns/imports return a jolt MAP (struct), not the live host table — so
|
||||
# count/seq/keys work on them, and callers can't mutate the ns through them.
|
||||
(ns-intern core "ns-interns" (fn [&opt x] (table/to-struct ((ns-or-current x) :mappings))))
|
||||
(ns-intern core "ns-aliases" (fn [&opt x] ((ns-or-current x) :aliases)))
|
||||
# {alias-symbol -> namespace object}, Clojure's shape, from the string store.
|
||||
(ns-intern core "ns-aliases"
|
||||
(fn [&opt x]
|
||||
(def ns (ns-or-current x))
|
||||
(def out @{})
|
||||
(eachp [a target] (ns :aliases)
|
||||
(put out {:jolt/type :symbol :ns nil :name a} (ctx-find-ns ctx target)))
|
||||
(table/to-struct out)))
|
||||
(ns-intern core "ns-imports" (fn [&opt x] (table/to-struct ((ns-or-current x) :imports))))
|
||||
# (ns-resolve ns sym) -> the var or nil. Unqualified syms look in ns's own
|
||||
# mappings; ns-qualified syms resolve through ns's aliases. (types/ns-resolve
|
||||
|
|
@ -1038,8 +1045,9 @@
|
|||
(def nm (if (struct? sym) (sym :name) (string sym)))
|
||||
(def nsp (if (struct? sym) (sym :ns) nil))
|
||||
(if nsp
|
||||
(let [alias-ns (get (ns :aliases) nsp)]
|
||||
(when alias-ns (ns-find alias-ns nm)))
|
||||
(let [target (or (ns-alias-lookup ns nsp) nsp)
|
||||
target-ns (ctx-find-ns ctx target)]
|
||||
(when target-ns (ns-find target-ns nm)))
|
||||
(ns-find ns nm))))
|
||||
(ns-intern core "resolve"
|
||||
(fn [sym]
|
||||
|
|
@ -1185,20 +1193,18 @@
|
|||
(var nxt (expand-1 cur))
|
||||
(while (not= cur nxt) (set cur nxt) (set nxt (expand-1 cur)))
|
||||
cur))
|
||||
# alias/ns-unalias: alias bookkeeping is currently split (require :as writes
|
||||
# the string-keyed :imports table that resolution reads; :aliases is the
|
||||
# introspection table ns-aliases reads) — write/remove BOTH until unified.
|
||||
# alias bookkeeping is UNIFIED (jolt-ark): :aliases (alias-name string ->
|
||||
# ns-name string) is the one store, read by resolution and ns-aliases;
|
||||
# :imports holds class imports only.
|
||||
(ns-intern core "alias"
|
||||
(fn [alias-sym ns-sym]
|
||||
(def cur (ctx-find-ns ctx (ctx-current-ns ctx)))
|
||||
(ns-import cur (alias-sym :name) (ns-sym :name))
|
||||
(ns-add-alias cur alias-sym (ctx-find-ns ctx (ns-sym :name)))
|
||||
(ns-add-alias cur (alias-sym :name) (ns-sym :name))
|
||||
nil))
|
||||
(ns-intern core "ns-unalias"
|
||||
(fn [ns-d alias-sym]
|
||||
(def ns (ns-or-current ns-d))
|
||||
(put (ns :imports) (alias-sym :name) nil)
|
||||
(put (ns :aliases) alias-sym nil)
|
||||
(put (ns :aliases) (alias-sym :name) nil)
|
||||
nil))
|
||||
# ns-publics: {symbol -> var} (jolt has no private vars, so publics = interns).
|
||||
# Keys are symbol structs (value-hashed), matching Clojure's symbol keys.
|
||||
|
|
|
|||
|
|
@ -279,7 +279,7 @@
|
|||
(or (ns-find ns sym)
|
||||
(let [qualified? (sym? sym)]
|
||||
(when qualified?
|
||||
# qualified symbol: look up via alias
|
||||
# qualified symbol: look up via alias (string-keyed store)
|
||||
(let [alias-ns (get (ns :aliases) (sym :ns))]
|
||||
(when alias-ns
|
||||
(ns-find alias-ns (sym :name))))))))
|
||||
|
|
@ -295,9 +295,16 @@
|
|||
(get (ns :imports) class-name))
|
||||
|
||||
(defn ns-add-alias
|
||||
"Add an alias from alias-sym to target-ns."
|
||||
[ns alias-sym target-ns]
|
||||
(put (ns :aliases) alias-sym target-ns))
|
||||
"Add an alias: alias-name (string) -> target ns NAME (string). The ONE alias
|
||||
store (jolt-ark): resolution and ns-aliases both read it; :imports is class
|
||||
imports only."
|
||||
[ns alias-name target-ns-name]
|
||||
(put (ns :aliases) alias-name target-ns-name))
|
||||
|
||||
(defn ns-alias-lookup
|
||||
"The target ns NAME for alias-name, or nil."
|
||||
[ns alias-name]
|
||||
(get (ns :aliases) alias-name))
|
||||
|
||||
# ============================================================
|
||||
# Context
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@
|
|||
(assert (= "my.app" (ctx-current-ns ctx)) "ns with require sets current namespace")
|
||||
# Alias should be registered
|
||||
(let [ns (ctx-find-ns ctx "my.app")
|
||||
aliased (ns-import-lookup ns "o")]
|
||||
aliased (ns-alias-lookup ns "o")]
|
||||
(assert (= "other.lib" aliased) "alias o -> other.lib registered")))
|
||||
(print " passed")
|
||||
|
||||
|
|
@ -55,7 +55,7 @@
|
|||
(let [ctx (fresh-ctx)]
|
||||
(eval-form ctx @{} (parse-string "(require '[other.lib :as o])"))
|
||||
(let [ns (ctx-find-ns ctx "user")
|
||||
aliased (ns-import-lookup ns "o")]
|
||||
aliased (ns-alias-lookup ns "o")]
|
||||
(assert (= "other.lib" aliased) "standalone require registers alias")))
|
||||
(print " passed")
|
||||
|
||||
|
|
|
|||
|
|
@ -53,3 +53,21 @@
|
|||
"(do (require (quote [clojure.string :as s9])) (try (s9/join nil nil nil) (catch Exception e nil)) (s9/upper-case \"a\"))"]
|
||||
["*ns* restored after throw" "\"user\""
|
||||
"(do (require (quote [clojure.walk :as w9])) (try (w9/postwalk nil nil nil) (catch Exception e nil)) (str *ns*))"])
|
||||
|
||||
# Alias bookkeeping is unified (jolt-ark): one string-keyed :aliases store,
|
||||
# read by resolution AND ns-aliases (which presents Clojure's
|
||||
# {alias-symbol -> namespace} shape); :imports holds class imports only.
|
||||
(defspec "namespaces / unified alias store"
|
||||
["require :as registers the alias" "1"
|
||||
"(do (require (quote [clojure.string :as st1])) (count (filter (fn [[a n]] (= (str a) \"st1\")) (ns-aliases))))"]
|
||||
["aliased call resolves" "\"A\""
|
||||
"(do (require (quote [clojure.string :as st2])) (st2/upper-case \"a\"))"]
|
||||
["alias fn registers + resolves" "\"B\""
|
||||
"(do (require (quote [clojure.string])) (alias (quote st3) (quote clojure.string)) (st3/upper-case \"b\"))"]
|
||||
["alias fn visible to ns-aliases" "true"
|
||||
"(do (require (quote [clojure.string])) (alias (quote st4) (quote clojure.string)) (pos? (count (filter (fn [[a n]] (= (str a) \"st4\")) (ns-aliases)))))"]
|
||||
["ns-unalias removes both views" "[0 false]"
|
||||
"(do (require (quote [clojure.string :as st5])) (ns-unalias (quote user) (quote st5)) [(count (filter (fn [[a n]] (= (str a) \"st5\")) (ns-aliases))) (boolean (resolve (quote st5/upper-case)))])"]
|
||||
["ns-resolve through alias" "true"
|
||||
"(do (require (quote [clojure.string :as st6])) (var? (ns-resolve (quote user) (quote st6/upper-case))))"]
|
||||
["empty ns-aliases is a map" "true" "(map? (ns-aliases (quote clojure.core)))"])
|
||||
|
|
|
|||
|
|
@ -54,7 +54,9 @@ for f in glob.glob('test/spec/*.janet') + ['test/integration/conformance-test.ja
|
|||
|
||||
# --- classification ---------------------------------------------------------
|
||||
SPECIAL = {'catch','finally','do','def','defmacro','fn','if','let','loop','quote',
|
||||
'recur','throw','try','var','new','set!','monitor-enter','monitor-exit'}
|
||||
'recur','throw','try','var','new','set!','monitor-enter','monitor-exit',
|
||||
# '.' is the interop special form — (resolve '.) is nil on the JVM too
|
||||
'.'}
|
||||
AGENTS = {'agent','send','send-off','send-via','await','await-for','await1',
|
||||
'agent-error','agent-errors','clear-agent-errors','error-handler',
|
||||
'error-mode','set-agent-send-executor!','set-agent-send-off-executor!',
|
||||
|
|
@ -105,7 +107,7 @@ community examples). jolt interns {len(jolt & set(core))} of them.
|
|||
|---|---|---|
|
||||
| implemented+tested | {counts['implemented+tested']} | in jolt and exercised by spec/conformance |
|
||||
| implemented-untested | {counts['implemented-untested']} | in jolt, no direct test — spec entries will add them |
|
||||
| resolvable-not-interned | {len((resolvable - interned) & set(core))} | works in code but invisible to ns introspection (conformance finding) |
|
||||
| resolvable-not-interned | {len((resolvable - interned) & set(core) - SPECIAL)} | works in code but invisible to ns introspection (conformance finding) |
|
||||
| missing-portable | {counts['missing-portable']} | portable semantics, jolt lacks it — implementation gap |
|
||||
| special-form | {counts['special-form']} | specified in §3, not a library var |
|
||||
| dynamic-var | {counts['dynamic-var']} | classification needed: portable default vs host-dependent |
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue