From 082c814b4798295386317763d767addb3b1396e0 Mon Sep 17 00:00:00 2001 From: Nicola Mometto Date: Fri, 18 Oct 2024 13:37:37 +0100 Subject: [PATCH 1/7] feat: don't desugar array/n into (. array -n) --- src/main/clojure/clojure/tools/analyzer/jvm.clj | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/main/clojure/clojure/tools/analyzer/jvm.clj b/src/main/clojure/clojure/tools/analyzer/jvm.clj index 7cd5678..a1fcf48 100644 --- a/src/main/clojure/clojure/tools/analyzer/jvm.clj +++ b/src/main/clojure/clojure/tools/analyzer/jvm.clj @@ -126,8 +126,12 @@ (if-let [target (and sym-ns (not (resolve-ns (symbol sym-ns) env)) (maybe-class-literal sym-ns))] ;; Class/field - (with-meta (list '. target (symbol (str "-" (name form)))) ;; transform to (. Class -field) - (meta form)) + (let [opname (name form)] + (if (and (= (count opname) 1) + (Character/isDigit (first opname))) + form ;; Array/ + (with-meta (list '. target (symbol (str "-" opname))) ;; transform to (. Class -field) + (meta form)))) form))) (defn desugar-host-expr [form env] From d74645c2acb558c3c7ea12f09216ac7adaf43905 Mon Sep 17 00:00:00 2001 From: Nicola Mometto Date: Fri, 18 Oct 2024 13:59:05 +0100 Subject: [PATCH 2/7] feat: array-class for multi-dimension --- .../clojure/tools/analyzer/jvm/utils.clj | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/src/main/clojure/clojure/tools/analyzer/jvm/utils.clj b/src/main/clojure/clojure/tools/analyzer/jvm/utils.clj index b5782a3..1332add 100644 --- a/src/main/clojure/clojure/tools/analyzer/jvm/utils.clj +++ b/src/main/clojure/clojure/tools/analyzer/jvm/utils.clj @@ -67,13 +67,16 @@ "Takes a Symbol, String or Class and tires to resolve to a matching Class" class) -(defn array-class [element-type] - (RT/classForName - (str "[" (-> element-type - maybe-class - Type/getType - .getDescriptor - (.replace \/ \.))))) +(defn array-class + ([element-type] (array-class 1 element-type)) + ([n element-type] + (RT/classForName + (str (apply str (repeat n"[")) + (-> element-type + maybe-class + Type/getType + .getDescriptor + (.replace \/ \.)))))) (defn maybe-class-from-string [^String s] (or (when-let [maybe-class (and (neg? (.indexOf s ".")) From f2c6747eeeeb3366ad5aee76e9526b10c2034c9a Mon Sep 17 00:00:00 2001 From: Nicola Mometto Date: Fri, 18 Oct 2024 14:02:09 +0100 Subject: [PATCH 3/7] feat: support for understands Class/n --- .../clojure/tools/analyzer/jvm/utils.clj | 40 ++++++++++++------- 1 file changed, 26 insertions(+), 14 deletions(-) diff --git a/src/main/clojure/clojure/tools/analyzer/jvm/utils.clj b/src/main/clojure/clojure/tools/analyzer/jvm/utils.clj index 1332add..678abd4 100644 --- a/src/main/clojure/clojure/tools/analyzer/jvm/utils.clj +++ b/src/main/clojure/clojure/tools/analyzer/jvm/utils.clj @@ -93,24 +93,36 @@ (defmethod maybe-class String [s] (maybe-class (symbol s))) +(defn maybe-array-class-sym [x] + (let [sname (name x)] + (if-let [c (and (= (count sname) 1) + (Character/isDigit (first sname)) + (namespace x))] + (when-let [c (or (specials c) + (maybe-class-from-string c))] + (array-class (Integer/parseInt sname) c))))) + (defmethod maybe-class Symbol [sym] - (when-not (namespace sym) - (let [sname (name sym) - snamec (count sname)] - (if-let [base-type (and (.endsWith sname "<>") - (maybe-class (subs sname 0 (- snamec 2))))] - (array-class base-type) - (if-let [ret (or (specials sname) - (special-arrays sname))] - ret - (maybe-class-from-string sname)))))) + (let [sname (name sym) + snamec (count sname)] + (or (maybe-array-class-sym sym) + (when-not (namespace sym) + (if-let [base-type (and (.endsWith sname "<>") + (maybe-class (subs sname 0 (- snamec 2))))] + ;; TODO: we're leaking into the syntax + (array-class base-type) + (if-let [ret (or (specials sname) + (special-arrays sname))] + ret + (maybe-class-from-string sname))))))) (defn maybe-class-literal [x] (cond - (class? x) x - (symbol? x) (and (not (namespace x)) - (maybe-class-from-string (name x))) - (string? x) (maybe-class-from-string x))) + (class? x) x + (symbol? x) (or (maybe-array-class-sym x) + (and (not (namespace x)) + (maybe-class-from-string (name x)))) + (string? x) (maybe-class-from-string x))) (def primitive? "Returns non-nil if the argument represents a primitive Class other than Void" From 5374a891f0c482afd06a8341eb5d3ed09233ef4f Mon Sep 17 00:00:00 2001 From: Nicola Mometto Date: Fri, 18 Oct 2024 14:25:36 +0100 Subject: [PATCH 4/7] feat: hook into analyze_host_expr --- .../tools/analyzer/passes/jvm/analyze_host_expr.clj | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/main/clojure/clojure/tools/analyzer/passes/jvm/analyze_host_expr.clj b/src/main/clojure/clojure/tools/analyzer/passes/jvm/analyze_host_expr.clj index 5391ae8..edc566a 100644 --- a/src/main/clojure/clojure/tools/analyzer/passes/jvm/analyze_host_expr.clj +++ b/src/main/clojure/clojure/tools/analyzer/passes/jvm/analyze_host_expr.clj @@ -142,8 +142,8 @@ (defn analyze-host-expr "Performing some reflection, transforms :host-interop/:host-call/:host-field nodes in either: :static-field, :static-call, :instance-call, :instance-field - or :host-interop nodes, and a :var or :maybe-class node in a :const :class node, - if necessary (class literals shadow Vars). + or :host-interop nodes, and a :var/:maybe-class/:maybe-host-form node in a + :const :class node, if necessary (class literals shadow Vars). A :host-interop node represents either an instance-field or a no-arg instance-method. " {:pass-info {:walk :post :depends #{}}} @@ -189,4 +189,10 @@ (assoc (ana/analyze-const the-class env :class) :form form) ast) + :maybe-host-form + (if-let [the-class (maybe-array-class-sym (symbol (str (:class ast)) + (str (:field ast))))] + (assoc (ana/analyze-const the-class env :class) :form form) + ast) + ast)) From ba3e7a4e073d7e1fd4e82c904fd13d0a436b9b5b Mon Sep 17 00:00:00 2001 From: Nicola Mometto Date: Fri, 18 Oct 2024 14:32:34 +0100 Subject: [PATCH 5/7] chore: bump t.r --- pom.xml | 2 +- project.clj | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index db44792..9d39ca3 100644 --- a/pom.xml +++ b/pom.xml @@ -42,7 +42,7 @@ org.clojure tools.reader - 1.4.0 + 1.5.0 diff --git a/project.clj b/project.clj index 8ec4fa5..e01257c 100644 --- a/project.clj +++ b/project.clj @@ -7,7 +7,7 @@ :test-paths ["src/test/clojure"] :dependencies [[org.clojure/clojure "1.9.0"] [org.clojure/core.memoize "1.1.266"] - [org.clojure/tools.reader "1.4.0"] + [org.clojure/tools.reader "1.5.0"] [org.clojure/tools.analyzer "1.2.0"] [org.ow2.asm/asm "9.2"]] :repositories [["sonatype" "https://oss.sonatype.org/content/repositories/releases"] From 189a98881fc3d29ce173a019e2a154e4f6b9b7a3 Mon Sep 17 00:00:00 2001 From: Nicola Mometto Date: Fri, 18 Oct 2024 14:39:24 +0100 Subject: [PATCH 6/7] fix: use t.r reader so it works on older clojure versions --- .../clojure/tools/analyzer/jvm/core_test.clj | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/src/test/clojure/clojure/tools/analyzer/jvm/core_test.clj b/src/test/clojure/clojure/tools/analyzer/jvm/core_test.clj index 7828ac0..a0b88da 100644 --- a/src/test/clojure/clojure/tools/analyzer/jvm/core_test.clj +++ b/src/test/clojure/clojure/tools/analyzer/jvm/core_test.clj @@ -5,6 +5,7 @@ [clojure.tools.analyzer.env :as env] [clojure.tools.analyzer.passes.elide-meta :refer [elides elide-meta]] [clojure.tools.analyzer.ast :refer [postwalk]] + [clojure.tools.reader :as r] [clojure.test :refer [deftest is]])) (defprotocol p (f [_])) @@ -20,13 +21,16 @@ (env/with-env (ana.jvm/global-env) (postwalk (ana/analyze '~form e) elide-meta)))) +(defn ana [form] + (binding [ana/macroexpand-1 ana.jvm/macroexpand-1 + ana/create-var ana.jvm/create-var + ana/parse ana.jvm/parse + ana/var? var? + elides {:all #{:line :column :file}}] + (ana.jvm/analyze form e))) + (defmacro ast1 [form] - `(binding [ana/macroexpand-1 ana.jvm/macroexpand-1 - ana/create-var ana.jvm/create-var - ana/parse ana.jvm/parse - ana/var? var? - elides {:all #{:line :column :file}}] - (ana.jvm/analyze '~form e))) + `(ana '~form)) (defmacro mexpand [form] `(ana.jvm/macroexpand-1 '~form e)) @@ -108,3 +112,6 @@ (deftest analyze+eval-context-test (let [do-ast (ana.jvm/analyze+eval '(do 1 2 3))] (is (= :ctx/statement (-> do-ast :statements first :env :context))))) + +(deftest array_class + (is (ana (r/read-string "(fn [^{:tag int/2} x] (instance? int/2 x))")))) From 588bbd603da9367ef03785b9734725b4c36e3c24 Mon Sep 17 00:00:00 2001 From: Nicola Mometto Date: Fri, 18 Oct 2024 14:39:35 +0100 Subject: [PATCH 7/7] chore: deps.edn --- deps.edn | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 deps.edn diff --git a/deps.edn b/deps.edn new file mode 100644 index 0000000..940495d --- /dev/null +++ b/deps.edn @@ -0,0 +1,6 @@ +{:deps {org.clojure/clojure {:mvn/version "1.12.0"} + org.clojure/tools.analyzer {:mvn/version "1.2.0"} + org.clojure/tools.reader {:mvn/version "1.5.0"} + org.clojure/core.memoize {:mvn/version "1.1.266"} + org.ow2.asm/asm {:mvn/version "9.2"}} + :paths ["src/main/clojure"]}