From afb7d173529df1ba03f04960326b8556a17053a5 Mon Sep 17 00:00:00 2001 From: Dmitri Sotnikov Date: Wed, 10 Jun 2026 11:41:42 +0800 Subject: [PATCH] =?UTF-8?q?core:=20fix=20jolt-265=20=E2=80=94=20syntax-quo?= =?UTF-8?q?te=20fully-qualifies=20core=20syms=20to=20clojure.core/=20(#18)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Re-attempt of the deferred gap, now unblocked. The earlier uberscript break wasn't qualification itself but an aliased-ref resolution bug it exposed: resolve-var looked up ns-aliases (e.g. g/foo) against the analyzer's REBOUND ctx-current-ns (jolt.analyzer, since the analyzer runs interpreted in its own ns) instead of the namespace being compiled. A user's aliased refs failed mid-compile (g/hello -> nil in the bundled standalone). - resolve-var resolves aliases against :compile-ns when set (same ns h-current-ns uses), falling back to ctx-current-ns — correct for both modes. - sq-symbol qualifies a resolved clojure.core name to clojure.core/ (Clojure hygiene); special forms stay bare; unresolved syms -> current ns. Tests updated to the qualified behavior (features-test, reader-forms-spec). Co-authored-by: Yogthos --- src/jolt/evaluator.janet | 13 +++++++++---- test/integration/features-test.janet | 3 ++- test/spec/reader-forms-spec.janet | 10 +++++----- 3 files changed, 16 insertions(+), 10 deletions(-) diff --git a/src/jolt/evaluator.janet b/src/jolt/evaluator.janet index 099ced6..72c672b 100644 --- a/src/jolt/evaluator.janet +++ b/src/jolt/evaluator.janet @@ -149,7 +149,8 @@ :name (string (string/slice nm 0 -2) "__" (string (gensym)) "__auto")}] (put gsmap nm g) g)) (special-symbol? nm) form - (ns-find (ctx-find-ns ctx "clojure.core") nm) form + (ns-find (ctx-find-ns ctx "clojure.core") nm) + {:jolt/type :symbol :ns "clojure.core" :name nm} {:jolt/type :symbol :ns (ctx-current-ns ctx) :name nm})) form)) @@ -266,9 +267,13 @@ [ctx bindings sym-s] (let [name (sym-s :name) ns (sym-s :ns)] (if (not (nil? ns)) - # Resolve ns aliases (e.g. `p/thrown?` where `p` is a require :as alias) - # so that aliased macros are recognized as macros, matching resolve-sym. - (let [current-ns (ctx-find-ns ctx (ctx-current-ns ctx)) + # Resolve ns aliases (e.g. `p/thrown?` where `p` is a require :as alias) so + # aliased refs/macros resolve. During compilation the analyzer (interpreted, + # in jolt.analyzer) rebinds ctx-current-ns to its own ns, so look up the alias + # against the COMPILE ns (:compile-ns, the user's ns) when set — otherwise an + # 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) target-ns (ctx-find-ns ctx (or aliased-ns ns))] (ns-find target-ns name)) diff --git a/test/integration/features-test.janet b/test/integration/features-test.janet index 7785451..2548956 100644 --- a/test/integration/features-test.janet +++ b/test/integration/features-test.janet @@ -82,7 +82,8 @@ ["macroexpand-1" "true" "(do (defmacro mm [x] (list 'inc x)) (= '(inc 5) (macroexpand-1 '(mm 5))))"] ["gensym distinct" "false" "(= (gensym) (gensym))"] ["syntax-quote splice" "[1 2 3]" "(let [xs [1 2 3]] `[~@xs])"] - ["syntax-quote unquote" "(quote (+ 1 5))" "(let [x 5] `(+ 1 ~x))"] + # syntax-quote fully-qualifies resolved core symbols to clojure.core/ (jolt-265). + ["syntax-quote unquote" "(quote (clojure.core/+ 1 5))" "(let [x 5] `(+ 1 ~x))"] ### 8. Recursion ["recursion fact" "120" "(do (defn fact [n] (if (<= n 1) 1 (* n (fact (dec n))))) (fact 5))"] diff --git a/test/spec/reader-forms-spec.janet b/test/spec/reader-forms-spec.janet index 3022c59..aa4bf19 100644 --- a/test/spec/reader-forms-spec.janet +++ b/test/spec/reader-forms-spec.janet @@ -38,12 +38,12 @@ ["gensym distinct" "true" "(not= `meow# `meow#)"] ["gensym stable" "true" "(let [s `[meow# meow#]] (= (first s) (second s)))"] ["qualifies unresolved" "(quote user/foo)" "`foo"] + # jolt-265 (fixed): resolved core symbols fully-qualify to clojure.core/. + ["qualifies core sym" "(quote clojure.core/str)" "`str"] ["unquote value" "[1 2 3]" "(let [a [1 2 3]] `~a)"] - # functional: the syntax-quoted call evaluates correctly. (jolt-265: core syms are - # left bare rather than qualified to clojure.core/ — full qualification breaks the - # standalone uberscript's ns macro, so it's deferred; they still resolve at eval.) - ["unquote call evals" "6" "(let [a 5] (eval `(+ ~a 1)))"] - ["splice call evals" "6" "(let [a [1 2 3]] (eval `(+ ~@a)))"] + ["unquote in call" "(quote (clojure.core/str [1 2 3]))" "(let [a [1 2 3]] `(str ~a))"] + ["splice empty" "(quote (clojure.core/str))" "(let [e []] `(str ~@e))"] + ["splice values" "(quote (clojure.core/str 1 2 3))" "(let [a [1 2 3]] `(str ~@a))"] ["splice in vector" "[1 2 3 0 1 2 3]" "(let [b [0] a [1 2 3] e []] `[~@e ~@a ~@b ~@a ~@e])"] # jolt-edb (fixed): ~/~@ inside set literals. ["splice in set" "#{0 1 2 3}" "(let [b [0] a [1 2 3] e []] `#{~@e ~@a ~@b})"]