From 2e28577cecad1d615d5d8b3772b5b70e881760d1 Mon Sep 17 00:00:00 2001 From: Noah Bogart Date: Tue, 28 Nov 2023 09:04:00 -0500 Subject: [PATCH 1/3] Add Actions build and deps.edn --- .github/workflows/build.yml | 26 +++++++++++++++++++++++++ .gitignore | 11 +++++++++++ deps.edn | 38 +++++++++++++++++++++++++++++++++++++ 3 files changed, 75 insertions(+) create mode 100644 .github/workflows/build.yml create mode 100644 deps.edn diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000000..2fa83e6c72 --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,26 @@ +name: Java CI + +on: [push] + +jobs: + build: + timeout-minutes: 5 + strategy: + matrix: + jdk: ['8', '11', '17', '19'] + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + - name: Set up JDK ${{ matrix.jdk }} + uses: actions/setup-java@v2 + with: + java-version: ${{ matrix.jdk }} + distribution: 'temurin' + cache: maven + - name: Build with Maven + run: mvn test + - name: Configure settings.xml + run: | + mkdir -p ~/.m2 + echo "clojars${{ secrets.CLOJARS_USER }}-clojars${{ secrets.CLOJARS_PASSWORD }}" > ~/.m2/settings.xml diff --git a/.gitignore b/.gitignore index 18cf4cc05c..2d4ad6a834 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,14 @@ maven-classpath maven-classpath.properties .idea/ *.iml +.clj-kondo +.cpcache +.lsp +.nrepl-port +.project +.settings/ +.vim +deps.edn +.nrepl-* +*.patch +*.diff diff --git a/deps.edn b/deps.edn new file mode 100644 index 0000000000..1b5a7ea601 --- /dev/null +++ b/deps.edn @@ -0,0 +1,38 @@ +;; https://clojure.org/dev/developing_patches#_run_an_individual_test +{:paths ["test" + "target/test-classes"] + :deps + {org.clojure/clojure {:local/root "." + :deps/manifest :pom} #_{:mvn/version "RELEASE"} + org.clojure/test.check {:mvn/version "1.1.1"} + org.clojure/test.generative {:mvn/version "1.0.0"}} + :aliases + {:dbg {:classpath-overrides {org.clojure/clojure "target/classes"} + :extra-deps {criterium/criterium {:mvn/version "0.4.4"}}} + :cognitest {:extra-deps {io.github.cognitect-labs/test-runner + {:git/tag "v0.5.0" :git/sha "b3fd0d2"}} + :main-opts ["-m" "cognitect.test-runner"] + :exec-fn cognitect.test-runner.api/test + :exec-args {:dirs ["test"] + :patterns [;; FIXME clojure.test-clojure.ns-libs has a test that is sensitive to loading order + ;; FIXME clojure.test-clojure.java-interop doesn't seem to work on JDK 17 (untested on others) + ;; regex ref: https://stackoverflow.com/a/2387072 + "^((?!(clojure.test-clojure.ns-libs|clojure.test-clojure.java-interop)).)*$" + ]}} + :test-example-script {:jvm-opts [;; from build.xml + "-Dclojure.test-clojure.exclude-namespaces=#{clojure.test-clojure.compilation.load-ns clojure.test-clojure.ns-libs-load-later}" + "-Dclojure.compiler.direct-linking=true"] + :main-opts ["-e" "(load-file,\"src/script/run_test.clj\")"]} + :test-generative-script {:jvm-opts [;; from build.xml + "-Dclojure.compiler.direct-linking=true"] + :main-opts ["-e" "(load-file,\"src/script/run_test_generative.clj\")"]} + + :kaocha {:extra-deps {lambdaisland/kaocha {:mvn/version "1.60.977"}} + :exec-fn kaocha.runner/exec-fn + :exec-args {;:watch? true + :tests [{:id :unit + :test-paths ["test"] + :ns-patterns [".*"]}] + :reporter kaocha.report/dots + ;; :plugins [:kaocha.plugin/profiling :kaocha.plugin/notifier] + }}}} From 6f0c9447bc340d90a847ca4a567322e476b4e9bd Mon Sep 17 00:00:00 2001 From: Noah Bogart Date: Tue, 28 Nov 2023 20:22:51 -0500 Subject: [PATCH 2/3] Expose syntax-quote macro --- src/clj/clojure/core.clj | 21 +++++++++++++++++++++ src/jvm/clojure/lang/LispReader.java | 7 +++++-- src/jvm/clojure/lang/RT.java | 3 +++ 3 files changed, 29 insertions(+), 2 deletions(-) diff --git a/src/clj/clojure/core.clj b/src/clj/clojure/core.clj index b8d9ff9f54..e371873012 100644 --- a/src/clj/clojure/core.clj +++ b/src/clj/clojure/core.clj @@ -745,6 +745,27 @@ (cat (concat x y) zs)))) ;;;;;;;;;;;;;;;;at this point all the support for syntax-quote exists;;;;;;;;;;;;;;;;;;;;;; +(defmacro syntax-quote + "Return the given form as if wrapped in quote ('), with handling for + unqoute (~) and unquote-splicing (~@). + + Recursively walks the form: For all forms other than symbols, lists, vectors, + sets and maps, `x is the same as 'x. For symbols, syntax-quote resolves the + symbol in the current context, yielding a fully-qualified symbol. + Non-qualified symbols ending in # are resolved to a generated symbol and all + references to that symbol within the form will use that generated symbol. + + For lists, vectors, sets, and maps, syntax-quote establishes a template of the + corresponding data structure. Within the template, unqualified forms behave as + if recursively syntax-quoted, but forms can be exempted from such recursive + quoting by qualifying them with unquote or unquote-splicing, in which case + they will be treated as expressions and be replaced in the template by their + value, or sequence of values, respectively." + {:added "1.13"} + ([] ()) + ([form] + (. clojure.lang.RT syntaxQuote form))) + (defmacro delay "Takes a body of expressions and yields a Delay object that will invoke the body only the first time it is forced (with force or deref/@), and diff --git a/src/jvm/clojure/lang/LispReader.java b/src/jvm/clojure/lang/LispReader.java index 9fcb7b5aa9..94c22d8957 100644 --- a/src/jvm/clojure/lang/LispReader.java +++ b/src/jvm/clojure/lang/LispReader.java @@ -988,12 +988,15 @@ else if(!(meta instanceof IPersistentMap)) public static class SyntaxQuoteReader extends AFn{ public Object invoke(Object reader, Object backquote, Object opts, Object pendingForms) { PushbackReader r = (PushbackReader) reader; + Object form = read(r, true, null, true, opts, ensurePending(pendingForms)); + return parseSyntaxQuote(form); + } + + public static Object parseSyntaxQuote(Object form) { try { Var.pushThreadBindings( RT.map(GENSYM_ENV, PersistentHashMap.EMPTY)); - - Object form = read(r, true, null, true, opts, ensurePending(pendingForms)); return syntaxQuote(form); } finally diff --git a/src/jvm/clojure/lang/RT.java b/src/jvm/clojure/lang/RT.java index 5d20ef4964..01794dd4ea 100644 --- a/src/jvm/clojure/lang/RT.java +++ b/src/jvm/clojure/lang/RT.java @@ -509,6 +509,9 @@ public static void loadLibrary(String libname){ System.loadLibrary(libname); } +public static Object syntaxQuote(Object form){ + return LispReader.SyntaxQuoteReader.parseSyntaxQuote(form); +} ////////////// Collections support ///////////////////////////////// From e357305e0ecacfdd6f79fbd6d9016d1c4dee16f3 Mon Sep 17 00:00:00 2001 From: Noah Bogart Date: Tue, 28 Nov 2023 21:54:09 -0500 Subject: [PATCH 3/3] Add simple test --- test/clojure/test_clojure/reader.cljc | 32 ++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/test/clojure/test_clojure/reader.cljc b/test/clojure/test_clojure/reader.cljc index 522a27928a..0832c8b2dd 100644 --- a/test/clojure/test_clojure/reader.cljc +++ b/test/clojure/test_clojure/reader.cljc @@ -458,10 +458,40 @@ ;; Syntax-quote (`, note, the "backquote" character), Unquote (~) and ;; Unquote-splicing (~@) +(defmacro sq-or + ([] nil) + ([x] x) + ([x & next] + (syntax-quote + (let [or# ~x] + (if or# or# (sq-or ~@next)))))) + (deftest t-Syntax-quote (are [x y] (= x y) `() () ; was NPE before SVN r1337 - )) + (syntax-quote ()) () + (syntax-quote) ()) + (let [literal '`(clj-880/example 1 2) + macro '(syntax-quote (clj-880/example 1 2))] + (is (not= literal macro) "Reader templates literal immediately") + (is (= literal (macroexpand-1 macro))) "Macro expands to same form as literal") + (let [foo :foo] + (is (= `(example 1 [2] #{~foo}) + (syntax-quote (example 1 [2] #{~foo})) + '(clojure.test-clojure.reader/example 1 [2] #{:foo})))) + (is (= `[1 2 ~@[3 4 5] 6] + (syntax-quote [1 2 ~@[3 4 5] 6]) + [1 2 3 4 5 6]) + "unquote-splicing works correctly") + (testing "auto-gensym works within forms but not across forms" + (let [[l1 l2 l3] `[a# a# b#] + [v1 v2 v3] (syntax-quote [a# a# b#])] + (is (= l1 l2)) + (is (not= l1 l3)) + (is (= v1 v2)) + (is (not= v1 v3)) + (is (not= l1 v1)))) + (is (= 5 (sq-or false nil 5)))) ;; (read) ;; (read stream)