Skip to content

Commit b9a1de2

Browse files
committed
Merge branch 'nicola/array_class_syntax'
2 parents f4cdf07 + 588bbd6 commit b9a1de2

File tree

7 files changed

+71
-33
lines changed

7 files changed

+71
-33
lines changed

deps.edn

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{:deps {org.clojure/clojure {:mvn/version "1.12.0"}
2+
org.clojure/tools.analyzer {:mvn/version "1.2.0"}
3+
org.clojure/tools.reader {:mvn/version "1.5.0"}
4+
org.clojure/core.memoize {:mvn/version "1.1.266"}
5+
org.ow2.asm/asm {:mvn/version "9.2"}}
6+
:paths ["src/main/clojure"]}

pom.xml

+1-1
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@
4242
<dependency>
4343
<groupId>org.clojure</groupId>
4444
<artifactId>tools.reader</artifactId>
45-
<version>1.4.0</version>
45+
<version>1.5.0</version>
4646
</dependency>
4747
</dependencies>
4848

project.clj

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
:test-paths ["src/test/clojure"]
88
:dependencies [[org.clojure/clojure "1.9.0"]
99
[org.clojure/core.memoize "1.1.266"]
10-
[org.clojure/tools.reader "1.4.0"]
10+
[org.clojure/tools.reader "1.5.0"]
1111
[org.clojure/tools.analyzer "1.2.0"]
1212
[org.ow2.asm/asm "9.2"]]
1313
:repositories [["sonatype" "https://oss.sonatype.org/content/repositories/releases"]

src/main/clojure/clojure/tools/analyzer/jvm.clj

+6-2
Original file line numberDiff line numberDiff line change
@@ -126,8 +126,12 @@
126126
(if-let [target (and sym-ns
127127
(not (resolve-ns (symbol sym-ns) env))
128128
(maybe-class-literal sym-ns))] ;; Class/field
129-
(with-meta (list '. target (symbol (str "-" (name form)))) ;; transform to (. Class -field)
130-
(meta form))
129+
(let [opname (name form)]
130+
(if (and (= (count opname) 1)
131+
(Character/isDigit (first opname)))
132+
form ;; Array/<n>
133+
(with-meta (list '. target (symbol (str "-" opname))) ;; transform to (. Class -field)
134+
(meta form))))
131135
form)))
132136

133137
(defn desugar-host-expr [form env]

src/main/clojure/clojure/tools/analyzer/jvm/utils.clj

+36-21
Original file line numberDiff line numberDiff line change
@@ -67,13 +67,16 @@
6767
"Takes a Symbol, String or Class and tires to resolve to a matching Class"
6868
class)
6969

70-
(defn array-class [element-type]
71-
(RT/classForName
72-
(str "[" (-> element-type
73-
maybe-class
74-
Type/getType
75-
.getDescriptor
76-
(.replace \/ \.)))))
70+
(defn array-class
71+
([element-type] (array-class 1 element-type))
72+
([n element-type]
73+
(RT/classForName
74+
(str (apply str (repeat n"["))
75+
(-> element-type
76+
maybe-class
77+
Type/getType
78+
.getDescriptor
79+
(.replace \/ \.))))))
7780

7881
(defn maybe-class-from-string [^String s]
7982
(or (when-let [maybe-class (and (neg? (.indexOf s "."))
@@ -90,24 +93,36 @@
9093
(defmethod maybe-class String [s]
9194
(maybe-class (symbol s)))
9295

96+
(defn maybe-array-class-sym [x]
97+
(let [sname (name x)]
98+
(if-let [c (and (= (count sname) 1)
99+
(Character/isDigit (first sname))
100+
(namespace x))]
101+
(when-let [c (or (specials c)
102+
(maybe-class-from-string c))]
103+
(array-class (Integer/parseInt sname) c)))))
104+
93105
(defmethod maybe-class Symbol [sym]
94-
(when-not (namespace sym)
95-
(let [sname (name sym)
96-
snamec (count sname)]
97-
(if-let [base-type (and (.endsWith sname "<>")
98-
(maybe-class (subs sname 0 (- snamec 2))))]
99-
(array-class base-type)
100-
(if-let [ret (or (specials sname)
101-
(special-arrays sname))]
102-
ret
103-
(maybe-class-from-string sname))))))
106+
(let [sname (name sym)
107+
snamec (count sname)]
108+
(or (maybe-array-class-sym sym)
109+
(when-not (namespace sym)
110+
(if-let [base-type (and (.endsWith sname "<>")
111+
(maybe-class (subs sname 0 (- snamec 2))))]
112+
;; TODO: we're leaking into the syntax
113+
(array-class base-type)
114+
(if-let [ret (or (specials sname)
115+
(special-arrays sname))]
116+
ret
117+
(maybe-class-from-string sname)))))))
104118

105119
(defn maybe-class-literal [x]
106120
(cond
107-
(class? x) x
108-
(symbol? x) (and (not (namespace x))
109-
(maybe-class-from-string (name x)))
110-
(string? x) (maybe-class-from-string x)))
121+
(class? x) x
122+
(symbol? x) (or (maybe-array-class-sym x)
123+
(and (not (namespace x))
124+
(maybe-class-from-string (name x))))
125+
(string? x) (maybe-class-from-string x)))
111126

112127
(def primitive?
113128
"Returns non-nil if the argument represents a primitive Class other than Void"

src/main/clojure/clojure/tools/analyzer/passes/jvm/analyze_host_expr.clj

+8-2
Original file line numberDiff line numberDiff line change
@@ -142,8 +142,8 @@
142142
(defn analyze-host-expr
143143
"Performing some reflection, transforms :host-interop/:host-call/:host-field
144144
nodes in either: :static-field, :static-call, :instance-call, :instance-field
145-
or :host-interop nodes, and a :var or :maybe-class node in a :const :class node,
146-
if necessary (class literals shadow Vars).
145+
or :host-interop nodes, and a :var/:maybe-class/:maybe-host-form node in a
146+
:const :class node, if necessary (class literals shadow Vars).
147147
148148
A :host-interop node represents either an instance-field or a no-arg instance-method. "
149149
{:pass-info {:walk :post :depends #{}}}
@@ -189,4 +189,10 @@
189189
(assoc (ana/analyze-const the-class env :class) :form form)
190190
ast)
191191

192+
:maybe-host-form
193+
(if-let [the-class (maybe-array-class-sym (symbol (str (:class ast))
194+
(str (:field ast))))]
195+
(assoc (ana/analyze-const the-class env :class) :form form)
196+
ast)
197+
192198
ast))

src/test/clojure/clojure/tools/analyzer/jvm/core_test.clj

+13-6
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
[clojure.tools.analyzer.env :as env]
66
[clojure.tools.analyzer.passes.elide-meta :refer [elides elide-meta]]
77
[clojure.tools.analyzer.ast :refer [postwalk]]
8+
[clojure.tools.reader :as r]
89
[clojure.test :refer [deftest is]]))
910

1011
(defprotocol p (f [_]))
@@ -20,13 +21,16 @@
2021
(env/with-env (ana.jvm/global-env)
2122
(postwalk (ana/analyze '~form e) elide-meta))))
2223

24+
(defn ana [form]
25+
(binding [ana/macroexpand-1 ana.jvm/macroexpand-1
26+
ana/create-var ana.jvm/create-var
27+
ana/parse ana.jvm/parse
28+
ana/var? var?
29+
elides {:all #{:line :column :file}}]
30+
(ana.jvm/analyze form e)))
31+
2332
(defmacro ast1 [form]
24-
`(binding [ana/macroexpand-1 ana.jvm/macroexpand-1
25-
ana/create-var ana.jvm/create-var
26-
ana/parse ana.jvm/parse
27-
ana/var? var?
28-
elides {:all #{:line :column :file}}]
29-
(ana.jvm/analyze '~form e)))
33+
`(ana '~form))
3034

3135
(defmacro mexpand [form]
3236
`(ana.jvm/macroexpand-1 '~form e))
@@ -108,3 +112,6 @@
108112
(deftest analyze+eval-context-test
109113
(let [do-ast (ana.jvm/analyze+eval '(do 1 2 3))]
110114
(is (= :ctx/statement (-> do-ast :statements first :env :context)))))
115+
116+
(deftest array_class
117+
(is (ana (r/read-string "(fn [^{:tag int/2} x] (instance? int/2 x))"))))

0 commit comments

Comments
 (0)