Skip to content

Commit b2a9143

Browse files
foguspuredanger
authored andcommitted
CLJ-2807: Add support for a symbol comprising the name of the array component type (primitive, full-qualified class, or import aliases accepted) followed by an asterisk for each dimension of the array (1 or more).
1 parent a6937fd commit b2a9143

3 files changed

Lines changed: 119 additions & 5 deletions

File tree

src/jvm/clojure/lang/Compiler.java

Lines changed: 82 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -395,7 +395,12 @@ static Symbol resolveSymbol(Symbol sym){
395395
}
396396
Object o = currentNS().getMapping(sym);
397397
if(o == null)
398+
{
399+
Class ac = HostExpr.maybeArrayClass(sym);
400+
if(ac != null)
401+
return HostExpr.arrayTypeToSymbol(ac);
398402
return Symbol.intern(currentNS().name.name, sym.name);
403+
}
399404
else if(o instanceof Class)
400405
return Symbol.intern(null, ((Class) o).getName());
401406
else if(o instanceof Var)
@@ -1023,8 +1028,12 @@ public static Class maybeClass(Object form, boolean stringOk) {
10231028
{
10241029
if(Util.equals(sym,COMPILE_STUB_SYM.get()))
10251030
return (Class) COMPILE_STUB_CLASS.get();
1026-
if(sym.name.indexOf('.') > 0 || sym.name.charAt(0) == '[')
1027-
c = RT.classForNameNonLoading(sym.name);
1031+
else if(sym.name.indexOf('.') > 0 || sym.name.charAt(0) == '[')
1032+
{
1033+
c = maybeArrayClass(sym);
1034+
if (c == null)
1035+
c = RT.classForNameNonLoading(sym.name);
1036+
}
10281037
else
10291038
{
10301039
Object o = currentNS().getMapping(sym);
@@ -1035,7 +1044,12 @@ else if(LOCAL_ENV.deref() != null && ((java.util.Map)LOCAL_ENV.deref()).contains
10351044
else
10361045
{
10371046
try{
1038-
c = RT.classForNameNonLoading(sym.name);
1047+
if(c == null)
1048+
{
1049+
c = maybeArrayClass(sym);
1050+
if(c == null)
1051+
c = RT.classForNameNonLoading(sym.name);
1052+
}
10391053
}
10401054
catch(Exception e){
10411055
// aargh
@@ -1097,6 +1111,60 @@ else if(sym.name.equals("booleans"))
10971111
return c;
10981112
}
10991113

1114+
static String getArrayComponentClassDescriptor(Class c) {
1115+
if (c.isPrimitive())
1116+
return Type.getType(c).getDescriptor();
1117+
1118+
return "L" + c.getName() + ";";
1119+
}
1120+
1121+
// componentArrayType (maybe qualified or prim) ending in 1+ *'s, e.g. java.lang.String**
1122+
// capture group 1 = componentArrayType, group 2 = dimension *'s
1123+
final static Pattern ARRAY_TYPE_PATTERN = Pattern.compile("([^*]+)(\\*+)");
1124+
1125+
public static Class maybeArrayClass(Symbol sym) {
1126+
if(!sym.name.endsWith("*")) return null;
1127+
1128+
Matcher matcher = ARRAY_TYPE_PATTERN.matcher(sym.name);
1129+
1130+
if(!matcher.matches()) return null;
1131+
1132+
Symbol rootSymbol = Symbol.intern(matcher.group(1));
1133+
String stars = matcher.group(2);
1134+
Class componentClass = maybeClass(rootSymbol, false);
1135+
1136+
if(componentClass == null)
1137+
componentClass = primClass(rootSymbol);
1138+
1139+
if(componentClass == null) return null;
1140+
1141+
String componentDescriptor = getArrayComponentClassDescriptor(componentClass);
1142+
StringBuilder arrayDescriptor = new StringBuilder();
1143+
arrayDescriptor.append(stars.replace('*', '['));
1144+
arrayDescriptor.append(componentDescriptor);
1145+
return maybeClass(arrayDescriptor.toString(), true);
1146+
}
1147+
1148+
public static Symbol arrayTypeToSymbol(Class c) {
1149+
if(!c.isArray()) return null;
1150+
1151+
int dim = 1;
1152+
1153+
Class componentClass = c.getComponentType();
1154+
1155+
while(componentClass.isArray()) {
1156+
dim++;
1157+
componentClass = componentClass.getComponentType();
1158+
}
1159+
1160+
String componentClassName = componentClass.getName();
1161+
StringBuilder repr = new StringBuilder(componentClassName.length() + dim);
1162+
repr.append(componentClassName);
1163+
for(int i=0; i<dim; i++)
1164+
repr.append("*");
1165+
1166+
return Symbol.intern(null, repr.toString());
1167+
}
11001168

11011169
static Class tagToClass(Object tag) {
11021170
Class c = null;
@@ -7719,7 +7787,11 @@ else if(v.ns != currentNS() && !v.isPublic() && !allowPrivate)
77197787
}
77207788
else if(sym.name.indexOf('.') > 0 || sym.name.charAt(0) == '[')
77217789
{
7722-
return RT.classForName(sym.name);
7790+
Class ac = HostExpr.maybeArrayClass(sym);
7791+
if(ac != null)
7792+
return ac;
7793+
else
7794+
return RT.classForName(sym.name);
77237795
}
77247796
else if(sym.equals(NS))
77257797
return RT.NS_VAR;
@@ -7732,7 +7804,12 @@ else if(sym.equals(IN_NS))
77327804
Object o = n.getMapping(sym);
77337805
if(o == null)
77347806
{
7735-
if(RT.booleanCast(RT.ALLOW_UNRESOLVED_VARS.deref()))
7807+
o = HostExpr.maybeArrayClass(sym);
7808+
if(o != null)
7809+
{
7810+
return o;
7811+
}
7812+
else if(RT.booleanCast(RT.ALLOW_UNRESOLVED_VARS.deref()))
77367813
{
77377814
return sym;
77387815
}

test/clojure/test_clojure/java_interop.clj

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -639,3 +639,23 @@
639639
(deftest test-boxing-prevention-when-compiling-statements
640640
(is (= 1 (.get (doto (AtomicInteger. 0) inc-atomic-int))))
641641
(is (= 1 (.get (doto (AtomicLong. 0) inc-atomic-long)))))
642+
643+
(deftest array-type-symbols
644+
(is (= long* (class (make-array Long/TYPE 0))))
645+
(is (= int* (class (make-array Integer/TYPE 0))))
646+
(is (= double* (class (make-array Double/TYPE 0))))
647+
(is (= short* (class (make-array Short/TYPE 0))))
648+
(is (= boolean* (class (make-array Boolean/TYPE 0))))
649+
(is (= byte* (class (make-array Byte/TYPE 0))))
650+
(is (= float* (class (make-array Float/TYPE 0))))
651+
(is (= String* (class (make-array String 0))))
652+
(is (= java.lang.String* (class (make-array String 0))))
653+
(is (= java.util.UUID* (class (make-array java.util.UUID 0))))
654+
(is (= `byte* 'byte*))
655+
(is (= `byte*** 'byte***))
656+
(is (= `java.util.UUID* 'java.util.UUID*))
657+
(is (= `String* 'java.lang.String*))
658+
(is (= `java.lang.String* 'java.lang.String*))
659+
(is (= `[NotAClassThatWasImported*] '[clojure.test-clojure.java-interop/NotAClassThatWasImported*]))
660+
(is (= [long**] `[~long**]))
661+
(is (= [42] (let [long** 42] `[~long**]))))

test/clojure/test_clojure/numbers.clj

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -593,6 +593,23 @@ Math/pow overflows to Infinity."
593593
"[I" (int-array 1) (ints (int-array 1 1))
594594
"[J" (long-array 1) (longs (long-array 1 1))))
595595

596+
(deftest test-array-type-symbols
597+
(are [str-repr klass] (= (Class/forName str-repr) klass)
598+
"[Z" (clojure.lang.Compiler$HostExpr/maybeArrayClass 'boolean*)
599+
"[B" (clojure.lang.Compiler$HostExpr/maybeArrayClass 'byte*)
600+
"[C" (clojure.lang.Compiler$HostExpr/maybeArrayClass 'char*)
601+
"[S" (clojure.lang.Compiler$HostExpr/maybeArrayClass 'short*)
602+
"[F" (clojure.lang.Compiler$HostExpr/maybeArrayClass 'float*)
603+
"[D" (clojure.lang.Compiler$HostExpr/maybeArrayClass 'double*)
604+
"[I" (clojure.lang.Compiler$HostExpr/maybeArrayClass 'int*)
605+
"[J" (clojure.lang.Compiler$HostExpr/maybeArrayClass 'long*)
606+
"[[J" (clojure.lang.Compiler$HostExpr/maybeArrayClass 'long**)
607+
"[Ljava.lang.Object;" (clojure.lang.Compiler$HostExpr/maybeArrayClass 'Object*)
608+
"[Ljava.lang.String;" (clojure.lang.Compiler$HostExpr/maybeArrayClass 'String*)
609+
"[[Ljava.lang.String;" (clojure.lang.Compiler$HostExpr/maybeArrayClass 'String**))
610+
(is (nil? (clojure.lang.Compiler$HostExpr/maybeArrayClass 'Object)))
611+
(is (nil? (clojure.lang.Compiler$HostExpr/maybeArrayClass 'ThisIsNotAClassThatCouldBeFound138)))
612+
(is (nil? (clojure.lang.Compiler$HostExpr/maybeArrayClass 'String-*IJ*))))
596613

597614
(deftest test-ratios
598615
(is (== (denominator 1/2) 2))

0 commit comments

Comments
 (0)