test(spec): macros, reader, host-interop, namespaces — fix def-doc, resolve, %&

Final spec areas. Bugs caught and fixed:
- (def name docstring value) used the docstring as the value; now the 3-arg
  docstring form binds the value and records :doc meta
- resolve was a nil stub; now a special form resolving a symbol to its var
  (nil if unresolved). Added find-ns (non-creating lookup) and ns-name.
- in-ns didn't evaluate its arg, so (in-ns 'foo) failed; now evaluates it per
  Clojure (the integration test's unquoted form updated to the quoted idiom)
- #(... %& ...) built %& as a positional param instead of a & rest param;
  now emits (fn* [... & gen] ...) so %& captures the rest

Full public-API spec layer now in place. conformance 218/218, jpm test green.
This commit is contained in:
Yogthos 2026-06-05 00:35:48 -04:00
parent e3d2aa8d14
commit ad5539b0de
8 changed files with 140 additions and 12 deletions

View file

@ -2432,7 +2432,11 @@
@[{:jolt/type :symbol :ns nil :name "ex-info"} msg-form {}]]])
# resolve stub — returns nil (symbols not found in Jolt's clojure.core)
(defn core-resolve [sym] nil)
(defn core-resolve [sym] nil) # shadowed by the resolve special form (needs ctx)
(defn core-ns-name [ns]
# ns object -> its name as a symbol (works whether ns is a table/struct/phm)
(let [nm (core-get ns :name)]
(if nm {:jolt/type :symbol :ns nil :name (string nm)} nil)))
# update — works on both structs and tables
(defn core-update [m k f & args]
@ -3532,6 +3536,7 @@
"defrecord" core-defrecord
"comment" core-comment
"resolve" core-resolve
"ns-name" core-ns-name
"update" core-update
"update-in" core-update-in
"assoc-in" core-assoc-in

View file

@ -580,8 +580,12 @@
ns (ctx-find-ns ctx ns-name)
# Create var first (unbound) so self-referencing defs resolve
v (ns-intern ns (name-sym :name))
val (eval-form ctx bindings (in form 2))]
# (def name docstring value): docstring is form 2, value form 3
has-doc (and (> (length form) 3) (string? (in form 2)))
val (eval-form ctx bindings (in form (if has-doc 3 2)))]
(bind-root v val)
(when has-doc
(put v :meta (merge (or (get v :meta) {}) {:doc (in form 2)})))
(when dynamic?
(put v :dynamic true))
# def returns the var (Clojure semantics); REPL prints #'ns/name
@ -695,10 +699,19 @@
"ns-aliases" (let [ns (ctx-find-ns ctx (ctx-current-ns ctx))] (ns :aliases))
"ns-imports" (let [ns (ctx-find-ns ctx (ctx-current-ns ctx))] (ns :imports))
"ns-resolve" (ns-resolve (ctx-find-ns ctx (ctx-current-ns ctx)) (in form 1))
"in-ns" (let [ns-name (sym-name-str (in form 1))]
(ctx-set-current-ns ctx ns-name)
"in-ns" (let [sym (eval-form ctx bindings (in form 1))
ns-name (if (and (struct? sym) (= :symbol (sym :jolt/type))) (sym :name) (string sym))]
(ctx-find-ns ctx ns-name)
(ctx-set-current-ns ctx ns-name)
nil)
"resolve" (let [sym (eval-form ctx bindings (in form 1))]
(if (and (struct? sym) (= :symbol (sym :jolt/type)))
(let [r (protect (resolve-var ctx bindings sym))]
(if (= (r 0) true) (r 1) nil))
nil))
"find-ns" (let [sym (eval-form ctx bindings (in form 1))
nm (if (and (struct? sym) (= :symbol (sym :jolt/type))) (sym :name) (string sym))]
(get (get (ctx :env) :namespaces) nm))
"fn*" (let [# optional name: (fn* name [args] ...) / (fn* name ([args] ...)...)
named? (and (struct? (in form 1)) (= :symbol ((in form 1) :jolt/type)))
fn-name (if named? ((in form 1) :name) nil)

View file

@ -303,14 +303,15 @@
f))
(def replaced (replace-pct form))
(def arg-names @[])
# Sort %1 %2 %3 ..., then %, then %&
(def sorted-keys (sort (keys arg-map)))
(each k sorted-keys
# Positional params %, %1, %2, ... in order; %& becomes a `& rest` param.
(def pos-keys (sort (filter |(not= $ "%&") (keys arg-map))))
(each k pos-keys
(array/push arg-names {:jolt/type :symbol :ns nil :name (get arg-map k)}))
(when (get arg-map "%&")
(array/push arg-names (sym "&"))
(array/push arg-names {:jolt/type :symbol :ns nil :name (get arg-map "%&")}))
(def result @[(sym "fn*")])
(if (> (length arg-names) 0)
(array/push result (tuple ;arg-names))
(array/push result (tuple))) # no args
(array/push result (tuple ;arg-names))
(array/push result replaced)
[result new-pos]))