mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-23 00:24:11 -08:00
Updating JSO implementation
This commit is contained in:
parent
e717adcd84
commit
e1f6bfdaeb
|
@ -265,6 +265,10 @@ public abstract class ValueType {
|
||||||
|
|
||||||
public abstract boolean isObject(String cls);
|
public abstract boolean isObject(String cls);
|
||||||
|
|
||||||
|
public boolean isObject(Class<?> cls) {
|
||||||
|
return isObject(cls.getName());
|
||||||
|
}
|
||||||
|
|
||||||
private static ValueType parseImpl(String string) {
|
private static ValueType parseImpl(String string) {
|
||||||
switch (string.charAt(0)) {
|
switch (string.charAt(0)) {
|
||||||
case 'Z':
|
case 'Z':
|
||||||
|
|
|
@ -17,6 +17,7 @@ package org.teavm.jso.plugin;
|
||||||
|
|
||||||
import java.lang.reflect.Array;
|
import java.lang.reflect.Array;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
|
import java.util.function.Function;
|
||||||
import org.teavm.dependency.PluggableDependency;
|
import org.teavm.dependency.PluggableDependency;
|
||||||
import org.teavm.javascript.spi.GeneratedBy;
|
import org.teavm.javascript.spi.GeneratedBy;
|
||||||
import org.teavm.javascript.spi.InjectedBy;
|
import org.teavm.javascript.spi.InjectedBy;
|
||||||
|
@ -28,30 +29,54 @@ import org.teavm.jso.core.JSBoolean;
|
||||||
import org.teavm.jso.core.JSNumber;
|
import org.teavm.jso.core.JSNumber;
|
||||||
import org.teavm.jso.core.JSString;
|
import org.teavm.jso.core.JSString;
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>Container of static methods to manipulate over {@link JSObject}s.</p>
|
|
||||||
*
|
|
||||||
* @author Alexey Andreev
|
|
||||||
*/
|
|
||||||
final class JS {
|
final class JS {
|
||||||
private JS() {
|
private JS() {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@InjectedBy(JSNativeGenerator.class)
|
||||||
* Gets global JavaScript object, that is similar to the <code>window</code> object in the browser.
|
public static native JSObject wrap(byte value);
|
||||||
* @return global object.
|
|
||||||
*/
|
|
||||||
@JSBody(params = {}, script = "return window;")
|
|
||||||
public static native JSObject getGlobal();
|
|
||||||
|
|
||||||
@InjectedBy(JSNativeGenerator.class)
|
@InjectedBy(JSNativeGenerator.class)
|
||||||
public static native JSObject wrap(String str);
|
public static native JSObject wrap(short value);
|
||||||
|
|
||||||
@InjectedBy(JSNativeGenerator.class)
|
@InjectedBy(JSNativeGenerator.class)
|
||||||
public static native JSObject wrap(char c);
|
public static native JSObject wrap(int value);
|
||||||
|
|
||||||
@InjectedBy(JSNativeGenerator.class)
|
@InjectedBy(JSNativeGenerator.class)
|
||||||
public static native JSObject marshall(Object obj);
|
public static native JSObject wrap(char value);
|
||||||
|
|
||||||
|
@InjectedBy(JSNativeGenerator.class)
|
||||||
|
public static native JSObject wrap(float value);
|
||||||
|
|
||||||
|
@InjectedBy(JSNativeGenerator.class)
|
||||||
|
public static native JSObject wrap(double value);
|
||||||
|
|
||||||
|
@InjectedBy(JSNativeGenerator.class)
|
||||||
|
public static native JSObject wrap(boolean value);
|
||||||
|
|
||||||
|
@InjectedBy(JSNativeGenerator.class)
|
||||||
|
public static native JSObject wrap(String value);
|
||||||
|
|
||||||
|
@InjectedBy(JSNativeGenerator.class)
|
||||||
|
public static native byte unwrapByte(JSObject value);
|
||||||
|
|
||||||
|
@InjectedBy(JSNativeGenerator.class)
|
||||||
|
public static native short unwrapShort(JSObject value);
|
||||||
|
|
||||||
|
@InjectedBy(JSNativeGenerator.class)
|
||||||
|
public static native int unwrapInt(JSObject value);
|
||||||
|
|
||||||
|
@InjectedBy(JSNativeGenerator.class)
|
||||||
|
public static native float unwrapFloat(JSObject value);
|
||||||
|
|
||||||
|
@InjectedBy(JSNativeGenerator.class)
|
||||||
|
public static native double unwrapDouble(JSObject value);
|
||||||
|
|
||||||
|
@InjectedBy(JSNativeGenerator.class)
|
||||||
|
public static native boolean unwrapBoolean(JSObject value);
|
||||||
|
|
||||||
|
@InjectedBy(JSNativeGenerator.class)
|
||||||
|
public static native String unwrapString(JSObject value);
|
||||||
|
|
||||||
public static <T extends JSObject> JSArray<T> wrap(T[] array) {
|
public static <T extends JSObject> JSArray<T> wrap(T[] array) {
|
||||||
JSArray<T> result = JSArray.create(array.length);
|
JSArray<T> result = JSArray.create(array.length);
|
||||||
|
@ -61,20 +86,20 @@ final class JS {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static <T extends JSObject> JSArray<JSArray<T>> wrap(T[][] array) {
|
public static <T extends JSObject> Function<T[], JSArray<T>> arrayWrapper() {
|
||||||
JSArray<JSArray<T>> result = JSArray.create(array.length);
|
return JS::wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T extends JSObject, S> JSArray<T> map(S[] array, Function<S, T> f) {
|
||||||
|
JSArray<T> result = JSArray.create(array.length);
|
||||||
for (int i = 0; i < array.length; ++i) {
|
for (int i = 0; i < array.length; ++i) {
|
||||||
result.set(i, wrap(array[i]));
|
result.set(i, f.apply(array[i]));
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static <T extends JSObject> JSArray<JSArray<JSArray<T>>> wrap(T[][][] array) {
|
public static <T extends JSObject, S> Function<S[], JSArray<T>> arrayMapper(Function<S, T> f) {
|
||||||
JSArray<JSArray<JSArray<T>>> result = JSArray.create(array.length);
|
return array -> map(array, f);
|
||||||
for (int i = 0; i < array.length; ++i) {
|
|
||||||
result.set(i, wrap(array[i]));
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static JSArray<JSBoolean> wrap(boolean[] array) {
|
public static JSArray<JSBoolean> wrap(boolean[] array) {
|
||||||
|
@ -85,20 +110,8 @@ final class JS {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static JSArray<JSArray<JSBoolean>> wrap(boolean[][] array) {
|
public static Function<boolean[], JSArray<JSBoolean>> booleanArrayWrapper() {
|
||||||
JSArray<JSArray<JSBoolean>> result = JSArray.create(array.length);
|
return JS::wrap;
|
||||||
for (int i = 0; i < array.length; ++i) {
|
|
||||||
result.set(i, wrap(array[i]));
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static JSArray<JSArray<JSArray<JSBoolean>>> wrap(boolean[][][] array) {
|
|
||||||
JSArray<JSArray<JSArray<JSBoolean>>> result = JSArray.create(array.length);
|
|
||||||
for (int i = 0; i < array.length; ++i) {
|
|
||||||
result.set(i, wrap(array[i]));
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static JSArray<JSNumber> wrap(byte[] array) {
|
public static JSArray<JSNumber> wrap(byte[] array) {
|
||||||
|
@ -109,20 +122,8 @@ final class JS {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static JSArray<JSArray<JSNumber>> wrap(byte[][] array) {
|
public static Function<byte[], JSArray<JSNumber>> byteArrayWrapper() {
|
||||||
JSArray<JSArray<JSNumber>> result = JSArray.create(array.length);
|
return JS::wrap;
|
||||||
for (int i = 0; i < array.length; ++i) {
|
|
||||||
result.set(i, wrap(array[i]));
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static JSArray<JSArray<JSArray<JSNumber>>> wrap(byte[][][] array) {
|
|
||||||
JSArray<JSArray<JSArray<JSNumber>>> result = JSArray.create(array.length);
|
|
||||||
for (int i = 0; i < array.length; ++i) {
|
|
||||||
result.set(i, wrap(array[i]));
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static JSArray<JSNumber> wrap(short[] array) {
|
public static JSArray<JSNumber> wrap(short[] array) {
|
||||||
|
@ -133,20 +134,8 @@ final class JS {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static JSArray<JSArray<JSNumber>> wrap(short[][] array) {
|
public static Function<short[], JSArray<JSNumber>> shortArrayWrapper() {
|
||||||
JSArray<JSArray<JSNumber>> result = JSArray.create(array.length);
|
return JS::wrap;
|
||||||
for (int i = 0; i < array.length; ++i) {
|
|
||||||
result.set(i, wrap(array[i]));
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static JSArray<JSArray<JSArray<JSNumber>>> wrap(short[][][] array) {
|
|
||||||
JSArray<JSArray<JSArray<JSNumber>>> result = JSArray.create(array.length);
|
|
||||||
for (int i = 0; i < array.length; ++i) {
|
|
||||||
result.set(i, wrap(array[i]));
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static JSArray<JSNumber> wrap(char[] array) {
|
public static JSArray<JSNumber> wrap(char[] array) {
|
||||||
|
@ -157,20 +146,8 @@ final class JS {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static JSArray<JSArray<JSNumber>> wrap(char[][] array) {
|
public static Function<char[], JSArray<JSNumber>> charArrayWrapper() {
|
||||||
JSArray<JSArray<JSNumber>> result = JSArray.create(array.length);
|
return JS::wrap;
|
||||||
for (int i = 0; i < array.length; ++i) {
|
|
||||||
result.set(i, wrap(array[i]));
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static JSArray<JSArray<JSArray<JSNumber>>> wrap(char[][][] array) {
|
|
||||||
JSArray<JSArray<JSArray<JSNumber>>> result = JSArray.create(array.length);
|
|
||||||
for (int i = 0; i < array.length; ++i) {
|
|
||||||
result.set(i, wrap(array[i]));
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static JSArray<JSNumber> wrap(int[] array) {
|
public static JSArray<JSNumber> wrap(int[] array) {
|
||||||
|
@ -181,20 +158,8 @@ final class JS {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static JSArray<JSArray<JSNumber>> wrap(int[][] array) {
|
public static Function<int[], JSArray<JSNumber>> intArrayWrapper() {
|
||||||
JSArray<JSArray<JSNumber>> result = JSArray.create(array.length);
|
return JS::wrap;
|
||||||
for (int i = 0; i < array.length; ++i) {
|
|
||||||
result.set(i, wrap(array[i]));
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static JSArray<JSArray<JSArray<JSNumber>>> wrap(int[][][] array) {
|
|
||||||
JSArray<JSArray<JSArray<JSNumber>>> result = JSArray.create(array.length);
|
|
||||||
for (int i = 0; i < array.length; ++i) {
|
|
||||||
result.set(i, wrap(array[i]));
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static JSArray<JSString> wrap(String[] array) {
|
public static JSArray<JSString> wrap(String[] array) {
|
||||||
|
@ -205,20 +170,8 @@ final class JS {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static JSArray<JSArray<JSString>> wrap(String[][] array) {
|
public static Function<String[], JSArray<JSString>> stringArrayWrapper() {
|
||||||
JSArray<JSArray<JSString>> result = JSArray.create(array.length);
|
return JS::wrap;
|
||||||
for (int i = 0; i < array.length; ++i) {
|
|
||||||
result.set(i, wrap(array[i]));
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static JSArray<JSArray<JSArray<JSString>>> wrap(String[][][] array) {
|
|
||||||
JSArray<JSArray<JSArray<JSString>>> result = JSArray.create(array.length);
|
|
||||||
for (int i = 0; i < array.length; ++i) {
|
|
||||||
result.set(i, wrap(array[i]));
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static JSArray<JSNumber> wrap(float[] array) {
|
public static JSArray<JSNumber> wrap(float[] array) {
|
||||||
|
@ -229,20 +182,8 @@ final class JS {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static JSArray<JSArray<JSNumber>> wrap(float[][] array) {
|
public static Function<float[], JSArray<JSNumber>> floatArrayWrapper() {
|
||||||
JSArray<JSArray<JSNumber>> result = JSArray.create(array.length);
|
return JS::wrap;
|
||||||
for (int i = 0; i < array.length; ++i) {
|
|
||||||
result.set(i, wrap(array[i]));
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static JSArray<JSArray<JSArray<JSNumber>>> wrap(float[][][] array) {
|
|
||||||
JSArray<JSArray<JSArray<JSNumber>>> result = JSArray.create(array.length);
|
|
||||||
for (int i = 0; i < array.length; ++i) {
|
|
||||||
result.set(i, wrap(array[i]));
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static JSArray<JSNumber> wrap(double[] array) {
|
public static JSArray<JSNumber> wrap(double[] array) {
|
||||||
|
@ -253,30 +194,11 @@ final class JS {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static JSArray<JSArray<JSNumber>> wrap(double[][] array) {
|
public static Function<double[], JSArray<JSNumber>> doubleArrayWrapper() {
|
||||||
JSArray<JSArray<JSNumber>> result = JSArray.create(array.length);
|
return JS::wrap;
|
||||||
for (int i = 0; i < array.length; ++i) {
|
|
||||||
result.set(i, wrap(array[i]));
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static JSArray<JSArray<JSArray<JSNumber>>> wrap(double[][][] array) {
|
public static <T extends JSObject> T[] unwrapArray(Class<T> type, JSArrayReader<T> array) {
|
||||||
JSArray<JSArray<JSArray<JSNumber>>> result = JSArray.create(array.length);
|
|
||||||
for (int i = 0; i < array.length; ++i) {
|
|
||||||
result.set(i, wrap(array[i]));
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
@InjectedBy(JSNativeGenerator.class)
|
|
||||||
@PluggableDependency(JSNativeGenerator.class)
|
|
||||||
public static native String unwrapString(JSObject obj);
|
|
||||||
|
|
||||||
@InjectedBy(JSNativeGenerator.class)
|
|
||||||
public static native char unwrapCharacter(JSObject obj);
|
|
||||||
|
|
||||||
public static <T extends JSObject> T[] unwrapArray(Class<T> type, JSArray<T> array) {
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
T[] result = (T[]) Array.newInstance(type, array.getLength());
|
T[] result = (T[]) Array.newInstance(type, array.getLength());
|
||||||
for (int i = 0; i < result.length; ++i) {
|
for (int i = 0; i < result.length; ++i) {
|
||||||
|
@ -285,27 +207,118 @@ final class JS {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static <T extends JSObject> T[][] unwrapArray2(Class<T> type, JSArray<JSArray<T>> array) {
|
public static <T extends JSObject> Function<JSArrayReader<T>, T[]> arrayUnwrapper(Class<T> type) {
|
||||||
|
return array -> unwrapArray(type, array);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <S extends JSObject, T> T[] unmapArray(Class<T> type, JSArrayReader<S> array, Function<S, T> f) {
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
T[][] result = (T[][]) Array.newInstance(Array.newInstance(type, 0).getClass(), array.getLength());
|
T[] result = (T[]) Array.newInstance(type, array.getLength());
|
||||||
for (int i = 0; i < result.length; ++i) {
|
for (int i = 0; i < result.length; ++i) {
|
||||||
result[i] = unwrapArray(type, array.get(i));
|
result[i] = f.apply(array.get(i));
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static <T extends JSObject> T[][][] unwrapArray3(Class<T> type, JSArray<JSArray<JSArray<T>>> array) {
|
public static <T, S extends JSObject> Function<JSArray<S>, T[]> arrayUnmapper(Class<T> type, Function<S, T> f) {
|
||||||
Class<?> baseType = Array.newInstance(type, 0).getClass();
|
return array -> unmapArray(type, array, f);
|
||||||
@SuppressWarnings("unchecked")
|
}
|
||||||
T[][][] result = (T[][][]) Array.newInstance(Array.newInstance(baseType, 0).getClass(), array.getLength());
|
|
||||||
|
public static boolean[] unwrapBooleanArray(JSArrayReader<JSBoolean> array) {
|
||||||
|
boolean[] result = new boolean[array.getLength()];
|
||||||
for (int i = 0; i < result.length; ++i) {
|
for (int i = 0; i < result.length; ++i) {
|
||||||
result[i] = unwrapArray2(type, array.get(i));
|
result[i] = array.get(i).booleanValue();
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@JSBody(params = "obj", script = "return typeof(obj) === 'undefined';")
|
public static Function<JSArrayReader<JSBoolean>, boolean[]> booleanArrayUnwrapper() {
|
||||||
public static native boolean isUndefined(JSObject obj);
|
return JS::unwrapBooleanArray;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static byte[] unwrapByteArray(JSArrayReader<JSNumber> array) {
|
||||||
|
byte[] result = new byte[array.getLength()];
|
||||||
|
for (int i = 0; i < result.length; ++i) {
|
||||||
|
result[i] = array.get(i).byteValue();
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Function<JSArrayReader<JSNumber>, byte[]> byteArrayUnwrapper() {
|
||||||
|
return JS::unwrapByteArray;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static short[] unwrapShortArray(JSArrayReader<JSNumber> array) {
|
||||||
|
short[] result = new short[array.getLength()];
|
||||||
|
for (int i = 0; i < result.length; ++i) {
|
||||||
|
result[i] = array.get(i).shortValue();
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Function<JSArrayReader<JSNumber>, short[]> shortArrayUnwrapper() {
|
||||||
|
return JS::unwrapShortArray;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int[] unwrapIntArray(JSArrayReader<JSNumber> array) {
|
||||||
|
int[] result = new int[array.getLength()];
|
||||||
|
for (int i = 0; i < result.length; ++i) {
|
||||||
|
result[i] = array.get(i).intValue();
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Function<JSArrayReader<JSNumber>, int[]> intArrayUnwrapper() {
|
||||||
|
return JS::unwrapIntArray;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static char[] unwrapCharArray(JSArrayReader<JSNumber> array) {
|
||||||
|
char[] result = new char[array.getLength()];
|
||||||
|
for (int i = 0; i < result.length; ++i) {
|
||||||
|
result[i] = array.get(i).charValue();
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Function<JSArrayReader<JSNumber>, char[]> charArrayUnwrapper() {
|
||||||
|
return JS::unwrapCharArray;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static float[] unwrapFloatArray(JSArrayReader<JSNumber> array) {
|
||||||
|
float[] result = new float[array.getLength()];
|
||||||
|
for (int i = 0; i < result.length; ++i) {
|
||||||
|
result[i] = array.get(i).floatValue();
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Function<JSArrayReader<JSNumber>, float[]> floatArrayUnwrapper() {
|
||||||
|
return JS::unwrapFloatArray;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static double[] unwrapDoubleArray(JSArrayReader<JSNumber> array) {
|
||||||
|
double[] result = new double[array.getLength()];
|
||||||
|
for (int i = 0; i < result.length; ++i) {
|
||||||
|
result[i] = array.get(i).doubleValue();
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Function<JSArrayReader<JSNumber>, double[]> doubleArrayUnwrapper() {
|
||||||
|
return JS::unwrapDoubleArray;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String[] unwrapStringArray(JSArrayReader<JSString> array) {
|
||||||
|
String[] result = new String[array.getLength()];
|
||||||
|
for (int i = 0; i < result.length; ++i) {
|
||||||
|
result[i] = array.get(i).stringValue();
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Function<JSArrayReader<JSString>, String[]> stringArrayUnwrapper() {
|
||||||
|
return JS::unwrapStringArray;
|
||||||
|
}
|
||||||
|
|
||||||
@InjectedBy(JSNativeGenerator.class)
|
@InjectedBy(JSNativeGenerator.class)
|
||||||
@PluggableDependency(JSNativeGenerator.class)
|
@PluggableDependency(JSNativeGenerator.class)
|
||||||
|
@ -333,7 +346,6 @@ final class JS {
|
||||||
public static native JSObject invoke(JSObject instance, JSObject method, JSObject a, JSObject b, JSObject c,
|
public static native JSObject invoke(JSObject instance, JSObject method, JSObject a, JSObject b, JSObject c,
|
||||||
JSObject d, JSObject e);
|
JSObject d, JSObject e);
|
||||||
|
|
||||||
|
|
||||||
@InjectedBy(JSNativeGenerator.class)
|
@InjectedBy(JSNativeGenerator.class)
|
||||||
@PluggableDependency(JSNativeGenerator.class)
|
@PluggableDependency(JSNativeGenerator.class)
|
||||||
public static native JSObject invoke(JSObject instance, JSObject method, JSObject a, JSObject b, JSObject c,
|
public static native JSObject invoke(JSObject instance, JSObject method, JSObject a, JSObject b, JSObject c,
|
||||||
|
|
|
@ -17,7 +17,9 @@ package org.teavm.jso.plugin;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import org.teavm.codegen.SourceWriter;
|
import org.teavm.codegen.SourceWriter;
|
||||||
import org.teavm.dependency.*;
|
import org.teavm.dependency.DependencyAgent;
|
||||||
|
import org.teavm.dependency.DependencyPlugin;
|
||||||
|
import org.teavm.dependency.MethodDependency;
|
||||||
import org.teavm.javascript.Renderer;
|
import org.teavm.javascript.Renderer;
|
||||||
import org.teavm.javascript.ast.ConstantExpr;
|
import org.teavm.javascript.ast.ConstantExpr;
|
||||||
import org.teavm.javascript.ast.Expr;
|
import org.teavm.javascript.ast.Expr;
|
||||||
|
@ -72,19 +74,6 @@ public class JSNativeGenerator implements Injector, DependencyPlugin, Generator
|
||||||
public void generate(InjectorContext context, MethodReference methodRef) throws IOException {
|
public void generate(InjectorContext context, MethodReference methodRef) throws IOException {
|
||||||
SourceWriter writer = context.getWriter();
|
SourceWriter writer = context.getWriter();
|
||||||
switch (methodRef.getName()) {
|
switch (methodRef.getName()) {
|
||||||
case "getGlobal":
|
|
||||||
writer.append("window");
|
|
||||||
break;
|
|
||||||
case "isUndefined":
|
|
||||||
writer.append("(");
|
|
||||||
context.writeExpr(context.getArgument(0));
|
|
||||||
writer.ws().append("===").ws().append("undefined)");
|
|
||||||
break;
|
|
||||||
case "getTypeName":
|
|
||||||
writer.append("(typeof ");
|
|
||||||
context.writeExpr(context.getArgument(0));
|
|
||||||
writer.append(")");
|
|
||||||
break;
|
|
||||||
case "get":
|
case "get":
|
||||||
context.writeExpr(context.getArgument(0));
|
context.writeExpr(context.getArgument(0));
|
||||||
renderProperty(context.getArgument(1), context);
|
renderProperty(context.getArgument(1), context);
|
||||||
|
@ -122,9 +111,6 @@ public class JSNativeGenerator implements Injector, DependencyPlugin, Generator
|
||||||
}
|
}
|
||||||
writer.append("))");
|
writer.append("))");
|
||||||
break;
|
break;
|
||||||
case "marshall":
|
|
||||||
context.writeExpr(context.getArgument(0));
|
|
||||||
break;
|
|
||||||
case "wrap":
|
case "wrap":
|
||||||
if (methodRef.getDescriptor().parameterType(0).isObject("java.lang.String")) {
|
if (methodRef.getDescriptor().parameterType(0).isObject("java.lang.String")) {
|
||||||
if (context.getArgument(0) instanceof ConstantExpr) {
|
if (context.getArgument(0) instanceof ConstantExpr) {
|
||||||
|
|
|
@ -22,6 +22,7 @@ import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.function.Function;
|
||||||
import org.teavm.diagnostics.Diagnostics;
|
import org.teavm.diagnostics.Diagnostics;
|
||||||
import org.teavm.javascript.spi.GeneratedBy;
|
import org.teavm.javascript.spi.GeneratedBy;
|
||||||
import org.teavm.javascript.spi.Sync;
|
import org.teavm.javascript.spi.Sync;
|
||||||
|
@ -33,6 +34,7 @@ import org.teavm.jso.JSMethod;
|
||||||
import org.teavm.jso.JSObject;
|
import org.teavm.jso.JSObject;
|
||||||
import org.teavm.jso.JSProperty;
|
import org.teavm.jso.JSProperty;
|
||||||
import org.teavm.jso.core.JSArray;
|
import org.teavm.jso.core.JSArray;
|
||||||
|
import org.teavm.jso.core.JSArrayReader;
|
||||||
import org.teavm.model.AccessLevel;
|
import org.teavm.model.AccessLevel;
|
||||||
import org.teavm.model.AnnotationHolder;
|
import org.teavm.model.AnnotationHolder;
|
||||||
import org.teavm.model.AnnotationReader;
|
import org.teavm.model.AnnotationReader;
|
||||||
|
@ -667,28 +669,136 @@ class JavascriptNativeProcessor {
|
||||||
++degree;
|
++degree;
|
||||||
itemType = ((ValueType.Array) itemType).getItemType();
|
itemType = ((ValueType.Array) itemType).getItemType();
|
||||||
}
|
}
|
||||||
if (degree > 3) {
|
|
||||||
diagnostics.error(location, "Unsupported type: {{t0}}", type);
|
CastInstruction castInsn = new CastInstruction();
|
||||||
return var;
|
castInsn.setValue(var);
|
||||||
|
castInsn.setTargetType(ValueType.parse(JSArrayReader.class));
|
||||||
|
var = program.createVariable();
|
||||||
|
castInsn.setReceiver(var);
|
||||||
|
castInsn.setLocation(location.getSourceLocation());
|
||||||
|
replacement.add(castInsn);
|
||||||
|
|
||||||
|
var = degree == 1
|
||||||
|
? unwrapSingleDimensionArray(location, var, itemType)
|
||||||
|
: unwrapMultiDimensionArray(location, var, itemType, degree);
|
||||||
|
|
||||||
|
return var;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Variable unwrapSingleDimensionArray(CallLocation location, Variable var, ValueType type) {
|
||||||
|
Variable result = program.createVariable();
|
||||||
|
|
||||||
|
InvokeInstruction insn = new InvokeInstruction();
|
||||||
|
insn.setMethod(singleDimensionArrayUnwrapper(type));
|
||||||
|
insn.setType(InvocationType.SPECIAL);
|
||||||
|
|
||||||
|
if (insn.getMethod().parameterCount() == 2) {
|
||||||
|
Variable cls = program.createVariable();
|
||||||
|
ClassConstantInstruction clsInsn = new ClassConstantInstruction();
|
||||||
|
clsInsn.setConstant(type);
|
||||||
|
clsInsn.setLocation(location.getSourceLocation());
|
||||||
|
clsInsn.setReceiver(cls);
|
||||||
|
replacement.add(clsInsn);
|
||||||
|
insn.getArguments().add(cls);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (itemType instanceof ValueType.Object) {
|
insn.getArguments().add(var);
|
||||||
String className = ((ValueType.Object) itemType).getClassName();
|
insn.setReceiver(result);
|
||||||
if (className.equals("java.lang.String")) {
|
return result;
|
||||||
String methodName = "unwrapStringArray";
|
}
|
||||||
if (degree > 1) {
|
|
||||||
methodName += degree;
|
private Variable unwrapMultiDimensionArray(CallLocation location, Variable var, ValueType type, int degree) {
|
||||||
}
|
Variable function = program.createVariable();
|
||||||
ValueType argType = degree == 1
|
|
||||||
? ValueType.parse(JSStringArray.class)
|
InvokeInstruction insn = new InvokeInstruction();
|
||||||
: ValueType.parse(JSArray.class);
|
insn.setMethod(multipleDimensionArrayUnwrapper(type));
|
||||||
return unwrap(var, methodName, argType, type, location.getSourceLocation());
|
insn.setType(InvocationType.SPECIAL);
|
||||||
} else if (isNative(className)) {
|
|
||||||
return unwrapObjectArray(location, var, degree, itemType, type);
|
if (insn.getMethod().parameterCount() == 1) {
|
||||||
}
|
Variable cls = program.createVariable();
|
||||||
|
ClassConstantInstruction clsInsn = new ClassConstantInstruction();
|
||||||
|
clsInsn.setConstant(type);
|
||||||
|
clsInsn.setLocation(location.getSourceLocation());
|
||||||
|
clsInsn.setReceiver(cls);
|
||||||
|
replacement.add(clsInsn);
|
||||||
|
insn.getArguments().add(cls);
|
||||||
}
|
}
|
||||||
diagnostics.error(location, "Unsupported type: {{t0}}", type);
|
|
||||||
return var;
|
insn.setReceiver(function);
|
||||||
|
|
||||||
|
while (--degree > 1) {
|
||||||
|
type = ValueType.arrayOf(type);
|
||||||
|
Variable cls = program.createVariable();
|
||||||
|
|
||||||
|
ClassConstantInstruction clsInsn = new ClassConstantInstruction();
|
||||||
|
clsInsn.setConstant(type);
|
||||||
|
clsInsn.setLocation(location.getSourceLocation());
|
||||||
|
clsInsn.setReceiver(cls);
|
||||||
|
replacement.add(clsInsn);
|
||||||
|
|
||||||
|
insn = new InvokeInstruction();
|
||||||
|
insn.setMethod(new MethodReference(JS.class, "arrayUnmapper", Class.class, Function.class,
|
||||||
|
Function.class));
|
||||||
|
insn.setType(InvocationType.SPECIAL);
|
||||||
|
insn.getArguments().add(cls);
|
||||||
|
insn.getArguments().add(function);
|
||||||
|
function = program.createVariable();
|
||||||
|
insn.setReceiver(function);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private MethodReference singleDimensionArrayUnwrapper(ValueType itemType) {
|
||||||
|
if (itemType instanceof ValueType.Primitive) {
|
||||||
|
switch (((ValueType.Primitive) itemType).getKind()) {
|
||||||
|
case BOOLEAN:
|
||||||
|
return new MethodReference(JS.class, "unwrapBooleanArray", JSArrayReader.class, boolean[].class);
|
||||||
|
case BYTE:
|
||||||
|
return new MethodReference(JS.class, "unwrapByteArray", JSArrayReader.class, byte[].class);
|
||||||
|
case SHORT:
|
||||||
|
return new MethodReference(JS.class, "unwrapShortArray", JSArrayReader.class, short[].class);
|
||||||
|
case CHARACTER:
|
||||||
|
return new MethodReference(JS.class, "unwrapCharArray", JSArrayReader.class, char[].class);
|
||||||
|
case INTEGER:
|
||||||
|
return new MethodReference(JS.class, "unwrapIntArray", JSArrayReader.class, int[].class);
|
||||||
|
case FLOAT:
|
||||||
|
return new MethodReference(JS.class, "unwrapFloatArray", JSArrayReader.class, float[].class);
|
||||||
|
case DOUBLE:
|
||||||
|
return new MethodReference(JS.class, "unwrapDoubleArray", JSArrayReader.class, double[].class);
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else if (itemType.isObject(String.class)) {
|
||||||
|
return new MethodReference(JS.class, "unwrapStringArray", JSArrayReader.class, String[].class);
|
||||||
|
}
|
||||||
|
return new MethodReference(JS.class, "unwrapArray", Class.class, JSArrayReader.class, byte[].class);
|
||||||
|
}
|
||||||
|
|
||||||
|
private MethodReference multipleDimensionArrayUnwrapper(ValueType itemType) {
|
||||||
|
if (itemType instanceof ValueType.Primitive) {
|
||||||
|
switch (((ValueType.Primitive) itemType).getKind()) {
|
||||||
|
case BOOLEAN:
|
||||||
|
return new MethodReference(JS.class, "booleanArrayUnwrapper", Function.class, Function.class);
|
||||||
|
case BYTE:
|
||||||
|
return new MethodReference(JS.class, "byteArrayUnwrapper", Function.class, Function.class);
|
||||||
|
case SHORT:
|
||||||
|
return new MethodReference(JS.class, "shortArrayUnwrapper", Function.class, Function.class);
|
||||||
|
case CHARACTER:
|
||||||
|
return new MethodReference(JS.class, "charArrayUnwrapper", Function.class, Function.class);
|
||||||
|
case INTEGER:
|
||||||
|
return new MethodReference(JS.class, "intArrayUnwrapper", Function.class, Function.class);
|
||||||
|
case FLOAT:
|
||||||
|
return new MethodReference(JS.class, "floatArrayUnwrapper", Function.class, Function.class);
|
||||||
|
case DOUBLE:
|
||||||
|
return new MethodReference(JS.class, "doubleArrayUnwrapper", Function.class, Function.class);
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else if (itemType.isObject(String.class)) {
|
||||||
|
return new MethodReference(JS.class, "stringArrayUnwrapper", Function.class, Function.class);
|
||||||
|
}
|
||||||
|
return new MethodReference(JS.class, "arrayUnwrapper", Class.class, Function.class, Function.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Variable unwrap(Variable var, String methodName, ValueType argType, ValueType resultType,
|
private Variable unwrap(Variable var, String methodName, ValueType argType, ValueType resultType,
|
||||||
|
@ -714,57 +824,6 @@ class JavascriptNativeProcessor {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Variable unwrapObjectArray(CallLocation location, Variable var, int degree, ValueType itemType,
|
|
||||||
ValueType expectedType) {
|
|
||||||
String methodName = "unwrapArray";
|
|
||||||
if (degree > 1) {
|
|
||||||
methodName += degree;
|
|
||||||
}
|
|
||||||
ValueType resultType = ValueType.parse(JSObject.class);
|
|
||||||
for (int i = 0; i < degree; ++i) {
|
|
||||||
resultType = ValueType.arrayOf(resultType);
|
|
||||||
}
|
|
||||||
|
|
||||||
Variable classVar = program.createVariable();
|
|
||||||
ClassConstantInstruction classInsn = new ClassConstantInstruction();
|
|
||||||
classInsn.setConstant(itemType);
|
|
||||||
classInsn.setReceiver(classVar);
|
|
||||||
classInsn.setLocation(location.getSourceLocation());
|
|
||||||
replacement.add(classInsn);
|
|
||||||
|
|
||||||
Variable castValue = program.createVariable();
|
|
||||||
CastInstruction castInsn = new CastInstruction();
|
|
||||||
castInsn.setValue(var);
|
|
||||||
castInsn.setReceiver(castValue);
|
|
||||||
castInsn.setLocation(location.getSourceLocation());
|
|
||||||
castInsn.setTargetType(ValueType.parse(JSArray.class));
|
|
||||||
replacement.add(castInsn);
|
|
||||||
var = castValue;
|
|
||||||
|
|
||||||
Variable result = program.createVariable();
|
|
||||||
InvokeInstruction insn = new InvokeInstruction();
|
|
||||||
insn.setMethod(new MethodReference(JS.class.getName(), methodName, ValueType.parse(Class.class),
|
|
||||||
ValueType.parse(JSArray.class), resultType));
|
|
||||||
insn.getArguments().add(classVar);
|
|
||||||
insn.getArguments().add(var);
|
|
||||||
insn.setReceiver(result);
|
|
||||||
insn.setType(InvocationType.SPECIAL);
|
|
||||||
insn.setLocation(location.getSourceLocation());
|
|
||||||
replacement.add(insn);
|
|
||||||
var = result;
|
|
||||||
|
|
||||||
Variable castResult = program.createVariable();
|
|
||||||
castInsn = new CastInstruction();
|
|
||||||
castInsn.setValue(var);
|
|
||||||
castInsn.setReceiver(castResult);
|
|
||||||
castInsn.setLocation(location.getSourceLocation());
|
|
||||||
castInsn.setTargetType(expectedType);
|
|
||||||
replacement.add(castInsn);
|
|
||||||
var = castResult;
|
|
||||||
|
|
||||||
return var;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Variable wrapArgument(CallLocation location, Variable var, ValueType type) {
|
private Variable wrapArgument(CallLocation location, Variable var, ValueType type) {
|
||||||
if (type instanceof ValueType.Object) {
|
if (type instanceof ValueType.Object) {
|
||||||
String className = ((ValueType.Object) type).getClassName();
|
String className = ((ValueType.Object) type).getClassName();
|
||||||
|
@ -807,22 +866,89 @@ class JavascriptNativeProcessor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Variable result = program.createVariable();
|
Variable result = program.createVariable();
|
||||||
InvokeInstruction insn = new InvokeInstruction();
|
|
||||||
insn.setMethod(new MethodReference(JS.class.getName(), "wrap", getWrappedType(type), getWrapperType(type)));
|
ValueType itemType = type;
|
||||||
insn.getArguments().add(var);
|
int degree = 0;
|
||||||
insn.setReceiver(result);
|
while (itemType instanceof ValueType.Array) {
|
||||||
insn.setType(InvocationType.SPECIAL);
|
itemType = ((ValueType.Array) itemType).getItemType();
|
||||||
insn.setLocation(location);
|
++degree;
|
||||||
replacement.add(insn);
|
}
|
||||||
|
|
||||||
|
if (degree <= 1) {
|
||||||
|
InvokeInstruction insn = new InvokeInstruction();
|
||||||
|
insn.setMethod(new MethodReference(JS.class.getName(), "wrap", getWrappedType(type),
|
||||||
|
getWrapperType(type)));
|
||||||
|
insn.getArguments().add(var);
|
||||||
|
insn.setReceiver(result);
|
||||||
|
insn.setType(InvocationType.SPECIAL);
|
||||||
|
insn.setLocation(location);
|
||||||
|
replacement.add(insn);
|
||||||
|
} else {
|
||||||
|
Variable function = program.createVariable();
|
||||||
|
|
||||||
|
InvokeInstruction insn = new InvokeInstruction();
|
||||||
|
insn.setMethod(getWrapperFunction(itemType));
|
||||||
|
insn.setReceiver(function);
|
||||||
|
insn.setType(InvocationType.SPECIAL);
|
||||||
|
insn.setLocation(location);
|
||||||
|
replacement.add(insn);
|
||||||
|
|
||||||
|
while (--degree > 1) {
|
||||||
|
insn = new InvokeInstruction();
|
||||||
|
insn.setMethod(new MethodReference(JS.class, "arrayMapper", Function.class, Function.class));
|
||||||
|
insn.getArguments().add(function);
|
||||||
|
function = program.createVariable();
|
||||||
|
insn.setReceiver(function);
|
||||||
|
insn.setType(InvocationType.SPECIAL);
|
||||||
|
insn.setLocation(location);
|
||||||
|
replacement.add(insn);
|
||||||
|
}
|
||||||
|
|
||||||
|
insn = new InvokeInstruction();
|
||||||
|
insn.setMethod(new MethodReference(JS.class.getName(), "map", getWrappedType(type),
|
||||||
|
ValueType.parse(Function.class), getWrapperType(type)));
|
||||||
|
insn.getArguments().add(var);
|
||||||
|
insn.getArguments().add(function);
|
||||||
|
insn.setReceiver(result);
|
||||||
|
insn.setType(InvocationType.SPECIAL);
|
||||||
|
insn.setLocation(location);
|
||||||
|
replacement.add(insn);
|
||||||
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private MethodReference getWrapperFunction(ValueType type) {
|
||||||
|
if (type instanceof ValueType.Primitive) {
|
||||||
|
switch (((ValueType.Primitive) type).getKind()) {
|
||||||
|
case BOOLEAN:
|
||||||
|
return new MethodReference(JS.class, "booleanArrayWrapper", Function.class);
|
||||||
|
case BYTE:
|
||||||
|
return new MethodReference(JS.class, "byteArrayWrapper", Function.class);
|
||||||
|
case SHORT:
|
||||||
|
return new MethodReference(JS.class, "shortArrayWrapper", Function.class);
|
||||||
|
case CHARACTER:
|
||||||
|
return new MethodReference(JS.class, "charArrayWrapper", Function.class);
|
||||||
|
case INTEGER:
|
||||||
|
return new MethodReference(JS.class, "intArrayWrapper", Function.class);
|
||||||
|
case FLOAT:
|
||||||
|
return new MethodReference(JS.class, "floatArrayWrapper", Function.class);
|
||||||
|
case DOUBLE:
|
||||||
|
return new MethodReference(JS.class, "doubleArrayWrapper", Function.class);
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else if (type.isObject(String.class)) {
|
||||||
|
return new MethodReference(JS.class, "stringArrayWrapper", Function.class);
|
||||||
|
}
|
||||||
|
return new MethodReference(JS.class, "arrayWrapper", Function.class);
|
||||||
|
}
|
||||||
|
|
||||||
private ValueType getWrappedType(ValueType type) {
|
private ValueType getWrappedType(ValueType type) {
|
||||||
if (type instanceof ValueType.Array) {
|
if (type instanceof ValueType.Array) {
|
||||||
ValueType itemType = ((ValueType.Array) type).getItemType();
|
ValueType itemType = ((ValueType.Array) type).getItemType();
|
||||||
return ValueType.arrayOf(getWrappedType(itemType));
|
return ValueType.arrayOf(getWrappedType(itemType));
|
||||||
} else if (type instanceof ValueType.Object) {
|
} else if (type instanceof ValueType.Object) {
|
||||||
if (type.isObject("java.lang.String")) {
|
if (type.isObject(String.class)) {
|
||||||
return type;
|
return type;
|
||||||
} else {
|
} else {
|
||||||
return ValueType.parse(JSObject.class);
|
return ValueType.parse(JSObject.class);
|
||||||
|
@ -834,28 +960,7 @@ class JavascriptNativeProcessor {
|
||||||
|
|
||||||
private ValueType getWrapperType(ValueType type) {
|
private ValueType getWrapperType(ValueType type) {
|
||||||
if (type instanceof ValueType.Array) {
|
if (type instanceof ValueType.Array) {
|
||||||
ValueType itemType = ((ValueType.Array) type).getItemType();
|
return ValueType.parse(JSArray.class);
|
||||||
if (itemType instanceof ValueType.Primitive) {
|
|
||||||
switch (((ValueType.Primitive) itemType).getKind()) {
|
|
||||||
case BOOLEAN:
|
|
||||||
return ValueType.parse(JSBooleanArray.class);
|
|
||||||
case BYTE:
|
|
||||||
case SHORT:
|
|
||||||
case INTEGER:
|
|
||||||
case CHARACTER:
|
|
||||||
return ValueType.parse(JSIntArray.class);
|
|
||||||
case FLOAT:
|
|
||||||
case DOUBLE:
|
|
||||||
return ValueType.parse(JSDoubleArray.class);
|
|
||||||
case LONG:
|
|
||||||
default:
|
|
||||||
return ValueType.parse(JSArray.class);
|
|
||||||
}
|
|
||||||
} else if (itemType.isObject("java.lang.String")) {
|
|
||||||
return ValueType.parse(JSStringArray.class);
|
|
||||||
} else {
|
|
||||||
return ValueType.parse(JSArray.class);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
return ValueType.parse(JSObject.class);
|
return ValueType.parse(JSObject.class);
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,6 +24,7 @@ import org.teavm.jso.JSObject;
|
||||||
* @param <T>
|
* @param <T>
|
||||||
*/
|
*/
|
||||||
@JSFunctor
|
@JSFunctor
|
||||||
|
@FunctionalInterface
|
||||||
public interface JSSortFunction<T extends JSObject> {
|
public interface JSSortFunction<T extends JSObject> {
|
||||||
int compare(T a, T b);
|
int compare(T a, T b);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user