diff --git a/bb/integration_tests.clj b/bb/integration_tests.clj index e12b0e6..f224470 100644 --- a/bb/integration_tests.clj +++ b/bb/integration_tests.clj @@ -38,6 +38,34 @@ "node lib/cli.js run test/cherry/cross_platform_test.cljc"))] (is (str/includes? out "0 failures") "cross-platform test passes on Cherry"))) +(deftest cljc-macro-reads-data-ns-via-require-macros-test + (let [{:keys [out exit]} (sh {:dir "test-resources/test_project" + :out :string :err :inherit} + "npx cherry run macro_data_via_require_macros_test.cljs")] + (is (zero? exit) "compile + run completes without sci error") + (is (str/includes? out ":fn-key :add") "macro expanded — add called") + (is (str/includes? out ":fn-key :mul") "macro expanded — mul called"))) + +(deftest cljc-macro-via-require-expands-at-compile-time-test + (let [dir "test-resources/test_project" + out-mjs (str dir "/macro_data_via_require_test.mjs")] + (shell "rm" "-f" out-mjs) + (sh {:dir dir :err :inherit} + "npx cherry compile src/macro_data.cljc src/macro_data_macros.cljc macro_data_via_require_test.cljc") + (let [emitted (slurp out-mjs)] + (is (str/includes? emitted "var add = function") "macro expanded inline — add defn emitted") + (is (str/includes? emitted "var mul = function") "macro expanded inline — mul defn emitted")))) + +(deftest cljc-macro-via-require-runs-test + (let [dir "test-resources/test_project"] + (sh {:dir dir :err :inherit} + "npx cherry compile src/macro_data.cljc src/macro_data_macros.cljc macro_data_via_require_test.cljc") + (let [{:keys [out exit]} (sh {:dir dir :out :string :err :inherit} + "node macro_data_via_require_test.mjs")] + (is (zero? exit) "consumer runs without ERR_MODULE_NOT_FOUND") + (is (str/includes? out ":fn-key :add") "add prints data-driven body") + (is (str/includes? out ":fn-key :mul") "mul prints data-driven body")))) + (defn run-tests [] (shell {:dir "test-resources/test_project"} "npm install") (let [{:keys [fail error]} (t/run-tests 'integration-tests)] diff --git a/deps.edn b/deps.edn index ebaa7e4..e8b23f0 100644 --- a/deps.edn +++ b/deps.edn @@ -3,7 +3,7 @@ org.babashka/sci {:mvn/version "0.10.49"} io.github.squint-cljs/squint #_{:local/root "/Users/borkdude/dev/squint"} - {:git/sha "9ad6e7b6106c93fd58cd3c1358d5838cce85db28"}} + {:git/sha "5abc27fcb1c47e97aff39ce539f52d0e54dd30a8"}} :aliases {:cljs {:extra-paths ["test"] :extra-deps {thheller/shadow-cljs {:mvn/version "3.3.4"} diff --git a/src/cherry/compiler/node.cljs b/src/cherry/compiler/node.cljs index dbdd2a6..6300f49 100644 --- a/src/cherry/compiler/node.cljs +++ b/src/cherry/compiler/node.cljs @@ -17,6 +17,13 @@ (defn spit [f s] (fs/writeFileSync f s "utf-8")) +(defn- cljc-with-macros? + [[libname & _]] + (when (symbol? libname) + (when-let [path (utils/resolve-file libname)] + (and (str/ends-with? path ".cljc") + (str/includes? (slurp path) "defmacro"))))) + (defn scan-macros [s {:keys [ns-state]}] (let [maybe-ns (e/parse-next (e/reader s) compiler/cherry-parse-opts)] (when (and (seq? maybe-ns) @@ -26,8 +33,15 @@ (when (and (seq? clause) (= :require-macros (first clause))) [(rest clause) reload])) - (partition-all 2 1 clauses))] - (when require-macros + (partition-all 2 1 clauses)) + require-cljc (some->> clauses + (some (fn [clause] + (when (and (seq? clause) + (= :require (first clause))) + (rest clause)))) + (filter cljc-with-macros?)) + all-macro-requires (concat require-macros require-cljc)] + (when (seq all-macro-requires) (.then (esm/dynamic-import "./compiler.sci.js") (fn [_] (let [eval-form (:eval-form @sci)] @@ -65,7 +79,7 @@ merge (zipmap refer (repeat macro-ns)))))))))))) (js/Promise.resolve nil) - require-macros))))))))) + all-macro-requires))))))))) (defn default-ns-state [] (atom {:current 'user})) diff --git a/src/cherry/compiler/sci.cljs b/src/cherry/compiler/sci.cljs index 05ba4f2..7cabf3e 100644 --- a/src/cherry/compiler/sci.cljs +++ b/src/cherry/compiler/sci.cljs @@ -12,7 +12,8 @@ fstr (slurp f)] {:source fstr})) :classes {:allow :all - 'js js/globalThis}})) + 'js js/globalThis} + :features #{:cljs}})) (sci/alter-var-root sci/print-fn (constantly *print-fn*)) (sci/alter-var-root sci/print-err-fn (constantly *print-err-fn*)) diff --git a/test-resources/test_project/macro_data_via_require_macros_test.cljs b/test-resources/test_project/macro_data_via_require_macros_test.cljs new file mode 100644 index 0000000..ddee79b --- /dev/null +++ b/test-resources/test_project/macro_data_via_require_macros_test.cljs @@ -0,0 +1,7 @@ +(ns macro-data-via-require-macros-test + (:require-macros [macro-data-macros :refer [define-fns]])) + +(define-fns) + +(prn (add 1)) +(prn (mul 2)) diff --git a/test-resources/test_project/macro_data_via_require_test.cljc b/test-resources/test_project/macro_data_via_require_test.cljc new file mode 100644 index 0000000..3d8e5ee --- /dev/null +++ b/test-resources/test_project/macro_data_via_require_test.cljc @@ -0,0 +1,9 @@ +#?(:clj (ns macro-data-via-require-test + (:require [macro-data-macros :refer [define-fns]])) + :cljs (ns macro-data-via-require-test + (:require [macro-data-macros :refer [define-fns]]))) + +(define-fns) + +(prn (add 1)) +(prn (mul 2)) diff --git a/test-resources/test_project/src/macro_data.cljc b/test-resources/test_project/src/macro_data.cljc new file mode 100644 index 0000000..19eba24 --- /dev/null +++ b/test-resources/test_project/src/macro_data.cljc @@ -0,0 +1,6 @@ +#?(:clj (ns macro-data) + :cljs (ns macro-data)) + +(def function-table + {:add {:rettype :int} + :mul {:rettype :int}}) diff --git a/test-resources/test_project/src/macro_data_macros.cljc b/test-resources/test_project/src/macro_data_macros.cljc new file mode 100644 index 0000000..fd70319 --- /dev/null +++ b/test-resources/test_project/src/macro_data_macros.cljc @@ -0,0 +1,10 @@ +#?(:clj (ns macro-data-macros (:require [macro-data :as d])) + :cljs (ns macro-data-macros (:require [macro-data :as d]))) + +(defmacro define-fns [] + `(do + ~@(for [[fn-key fn-def] d/function-table] + `(defn ~(symbol (name fn-key)) [~'x] + {:fn-key ~fn-key + :rettype ~(:rettype fn-def) + :input ~'x}))))