Skip to content

Commit f03cbb6

Browse files
committed
Улучшенная типизация массивов в модуле java
1 parent 826891a commit f03cbb6

File tree

2 files changed

+77
-7
lines changed

2 files changed

+77
-7
lines changed

src/main/java/com/annimon/ownlang/modules/java/java.java

Lines changed: 76 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import java.lang.reflect.InvocationTargetException;
99
import java.lang.reflect.Method;
1010
import java.util.ArrayList;
11+
import java.util.Arrays;
1112
import java.util.List;
1213

1314
/**
@@ -167,7 +168,7 @@ public Value newInstance(Value[] args) {
167168
return findConstructorAndInstantiate(args, clazz.getConstructors());
168169
}
169170

170-
private Value cast(Value... args) {
171+
private Value cast(Value[] args) {
171172
Arguments.check(1, args.length);
172173
return objectToValue(clazz, clazz.cast(((ObjectValue)args[0]).object));
173174
}
@@ -337,7 +338,15 @@ private static boolean isMatch(Value[] args, Class<?>[] types) {
337338
boolean assignable = unboxed != null;
338339
final Object object = valueToObject(arg);
339340
assignable = assignable && (object != null);
340-
assignable = assignable && (unboxed.isAssignableFrom(object.getClass()));
341+
if (assignable && unboxed.isArray() && object.getClass().isArray()) {
342+
final Class<?> uComponentType = unboxed.getComponentType();
343+
final Class<?> oComponentType = object.getClass().getComponentType();
344+
assignable = assignable && (uComponentType != null);
345+
assignable = assignable && (oComponentType != null);
346+
assignable = assignable && (uComponentType.isAssignableFrom(oComponentType));
347+
} else {
348+
assignable = assignable && (unboxed.isAssignableFrom(object.getClass()));
349+
}
341350
if (assignable) continue;
342351

343352
return false;
@@ -460,7 +469,7 @@ private static Value arrayToValue(Class<?> clazz, Object o) {
460469
}
461470
return result;
462471
}
463-
472+
464473
private static Object[] valuesToObjects(Value[] args) {
465474
Object[] result = new Object[args.length];
466475
for (int i = 0; i < args.length; i++) {
@@ -490,11 +499,72 @@ private static Object valueToObject(Value value) {
490499

491500
private static Object arrayToObject(ArrayValue value) {
492501
final int size = value.size();
493-
final Object[] result = new Object[size];
502+
final Object[] array = new Object[size];
503+
if (size == 0) {
504+
return array;
505+
}
506+
507+
Class<?> elementsType = null;
494508
for (int i = 0; i < size; i++) {
495-
result[i] = valueToObject(value.get(i));
509+
array[i] = valueToObject(value.get(i));
510+
if (i == 0) {
511+
elementsType = array[0].getClass();
512+
} else {
513+
elementsType = mostCommonType(elementsType, array[i].getClass());
514+
}
515+
}
516+
517+
if (elementsType.equals(Object[].class)) {
518+
return array;
519+
}
520+
return typedArray(array, size, elementsType);
521+
}
522+
523+
private static <T, U> T[] typedArray(U[] elements, int newLength, Class<?> elementsType) {
524+
@SuppressWarnings("unchecked")
525+
T[] copy = (T[]) Array.newInstance(elementsType, newLength);
526+
System.arraycopy(elements, 0, copy, 0, Math.min(elements.length, newLength));
527+
return copy;
528+
}
529+
530+
private static Class<?> mostCommonType(Class<?> c1, Class<?> c2) {
531+
if (c1.equals(c2)) {
532+
return c1;
533+
} else if (c1.isAssignableFrom(c2)) {
534+
return c1;
535+
} else if (c2.isAssignableFrom(c1)) {
536+
return c2;
537+
}
538+
final Class<?> s1 = c1.getSuperclass();
539+
final Class<?> s2 = c2.getSuperclass();
540+
if (s1 == null && s2 == null) {
541+
final List<Class<?>> upperTypes = Arrays.asList(
542+
Object.class, void.class, boolean.class, char.class,
543+
byte.class, short.class, int.class, long.class,
544+
float.class, double.class);
545+
for (Class<?> type : upperTypes) {
546+
if (c1.equals(type) && c2.equals(type)) {
547+
return s1;
548+
}
549+
}
550+
return Object.class;
551+
} else if (s1 == null || s2 == null) {
552+
if (c1.equals(c2)) {
553+
return c1;
554+
}
555+
if (c1.isInterface() && c1.isAssignableFrom(c2)) {
556+
return c1;
557+
}
558+
if (c2.isInterface() && c2.isAssignableFrom(c1)) {
559+
return c2;
560+
}
561+
}
562+
563+
if (s1 != null) {
564+
return mostCommonType(s1, c2);
565+
} else {
566+
return mostCommonType(c1, s2);
496567
}
497-
return result;
498568
}
499569
//</editor-fold>
500570
}

src/test/resources/modules/java/classes.own

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ def testInvokeMethodSameName() {
3838

3939
def testNonDefaultConstructor() {
4040
StringBuilder = newClass("java.lang.StringBuilder")
41-
sb = StringBuilder.`new`("text")
41+
sb = new StringBuilder("text")
4242
assertEquals("text", sb.toString())
4343
}
4444

0 commit comments

Comments
 (0)