fix: remove raw native funcs, use this arg passing instead
This commit is contained in:
parent
356a5a5b78
commit
0b7442a3d8
@ -9,5 +9,5 @@ import java.lang.annotation.Target;
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface Native {
|
||||
public String value() default "";
|
||||
public boolean raw() default false;
|
||||
public boolean thisArg() default false;
|
||||
}
|
||||
|
@ -8,6 +8,6 @@ import java.lang.annotation.Target;
|
||||
@Target({ ElementType.METHOD })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface NativeConstructor {
|
||||
public boolean raw() default false;
|
||||
public boolean thisArg() default false;
|
||||
}
|
||||
|
||||
|
@ -9,5 +9,5 @@ import java.lang.annotation.Target;
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface NativeGetter {
|
||||
public String value();
|
||||
public boolean raw() default false;
|
||||
public boolean thisArg() default false;
|
||||
}
|
||||
|
@ -9,5 +9,5 @@ import java.lang.annotation.Target;
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface NativeSetter {
|
||||
public String value();
|
||||
public boolean raw() default false;
|
||||
public boolean thisArg() default false;
|
||||
}
|
||||
|
@ -13,23 +13,15 @@ public class NativeTypeRegister implements WrappersProvider {
|
||||
private final HashMap<Class<?>, FunctionValue> constructors = new HashMap<>();
|
||||
private final HashMap<Class<?>, ObjectValue> prototypes = new HashMap<>();
|
||||
|
||||
private static boolean isMember(Class<?>[] args) {
|
||||
return args.length == 3;
|
||||
}
|
||||
|
||||
private static void applyMethods(boolean member, ObjectValue target, Class<?> clazz) {
|
||||
for (var method : clazz.getDeclaredMethods()) {
|
||||
var nat = method.getAnnotation(Native.class);
|
||||
var get = method.getAnnotation(NativeGetter.class);
|
||||
var set = method.getAnnotation(NativeSetter.class);
|
||||
var params = method.getParameterTypes();
|
||||
var memberMismatch = !Modifier.isStatic(method.getModifiers()) != member;
|
||||
|
||||
if (nat != null) {
|
||||
if (nat.raw()) {
|
||||
if (isMember(params) != member) continue;
|
||||
}
|
||||
else if (memberMismatch) continue;
|
||||
if (nat.thisArg() != member && memberMismatch) continue;
|
||||
|
||||
var name = nat.value();
|
||||
var val = target.values.get(name);
|
||||
@ -37,11 +29,12 @@ public class NativeTypeRegister implements WrappersProvider {
|
||||
if (name.equals("")) name = method.getName();
|
||||
if (!(val instanceof OverloadFunction)) target.defineProperty(null, name, val = new OverloadFunction(name));
|
||||
|
||||
((OverloadFunction)val).overloads.add(Overload.fromMethod(method, nat.raw()));
|
||||
((OverloadFunction)val).overloads.add(Overload.fromMethod(method, nat.thisArg()));
|
||||
}
|
||||
else {
|
||||
if (get != null) {
|
||||
if (get.raw() && isMember(params) != member || memberMismatch) continue;
|
||||
if (get.thisArg() != member && memberMismatch) continue;
|
||||
|
||||
var name = get.value();
|
||||
var prop = target.properties.get(name);
|
||||
OverloadFunction getter = null;
|
||||
@ -50,11 +43,12 @@ public class NativeTypeRegister implements WrappersProvider {
|
||||
if (prop != null && prop.getter instanceof OverloadFunction) getter = (OverloadFunction)prop.getter;
|
||||
else getter = new OverloadFunction("get " + name);
|
||||
|
||||
getter.overloads.add(Overload.fromMethod(method, get.raw()));
|
||||
getter.overloads.add(Overload.fromMethod(method, get.thisArg()));
|
||||
target.defineProperty(null, name, getter, setter, true, true);
|
||||
}
|
||||
if (set != null) {
|
||||
if (set.raw() && isMember(params) != member || memberMismatch) continue;
|
||||
if (set.thisArg() != member && memberMismatch) continue;
|
||||
|
||||
var name = set.value();
|
||||
var prop = target.properties.get(name);
|
||||
var getter = prop == null ? null : prop.getter;
|
||||
@ -63,7 +57,7 @@ public class NativeTypeRegister implements WrappersProvider {
|
||||
if (prop != null && prop.setter instanceof OverloadFunction) setter = (OverloadFunction)prop.setter;
|
||||
else setter = new OverloadFunction("set " + name);
|
||||
|
||||
setter.overloads.add(Overload.fromMethod(method, set.raw()));
|
||||
setter.overloads.add(Overload.fromMethod(method, set.thisArg()));
|
||||
target.defineProperty(null, name, getter, setter, true, true);
|
||||
}
|
||||
}
|
||||
@ -77,8 +71,8 @@ public class NativeTypeRegister implements WrappersProvider {
|
||||
if (nat != null) {
|
||||
var name = nat.value();
|
||||
if (name.equals("")) name = field.getName();
|
||||
var getter = new OverloadFunction("get " + name).add(Overload.getterFromField(field, nat.raw()));
|
||||
var setter = new OverloadFunction("set " + name).add(Overload.setterFromField(field, nat.raw()));
|
||||
var getter = new OverloadFunction("get " + name).add(Overload.getterFromField(field));
|
||||
var setter = new OverloadFunction("set " + name).add(Overload.setterFromField(field));
|
||||
target.defineProperty(null, name, getter, setter, true, false);
|
||||
}
|
||||
}
|
||||
@ -126,12 +120,12 @@ public class NativeTypeRegister implements WrappersProvider {
|
||||
for (var overload : clazz.getConstructors()) {
|
||||
var nat = overload.getAnnotation(Native.class);
|
||||
if (nat == null) continue;
|
||||
((OverloadFunction)func).add(Overload.fromConstructor(overload, nat.raw()));
|
||||
((OverloadFunction)func).add(Overload.fromConstructor(overload, nat.thisArg()));
|
||||
}
|
||||
for (var overload : clazz.getMethods()) {
|
||||
var constr = overload.getAnnotation(NativeConstructor.class);
|
||||
if (constr == null) continue;
|
||||
((OverloadFunction)func).add(Overload.fromMethod(overload, constr.raw()));
|
||||
((OverloadFunction)func).add(Overload.fromMethod(overload, constr.thisArg()));
|
||||
}
|
||||
|
||||
if (((OverloadFunction)func).overloads.size() == 0) {
|
||||
|
@ -17,63 +17,55 @@ public class Overload {
|
||||
|
||||
public final OverloadRunner runner;
|
||||
public final boolean variadic;
|
||||
public final boolean raw;
|
||||
public final boolean passThis;
|
||||
public final Class<?> thisArg;
|
||||
public final Class<?>[] params;
|
||||
|
||||
public static Overload fromMethod(Method method, boolean raw) {
|
||||
public static Overload fromMethod(Method method, boolean passThis) {
|
||||
return new Overload(
|
||||
(ctx, th, args) -> method.invoke(th, args),
|
||||
method.isVarArgs(), raw,
|
||||
method.isVarArgs(), passThis,
|
||||
Modifier.isStatic(method.getModifiers()) ? null : method.getDeclaringClass(),
|
||||
method.getParameterTypes()
|
||||
);
|
||||
}
|
||||
public static Overload fromConstructor(Constructor<?> method, boolean raw) {
|
||||
public static Overload fromConstructor(Constructor<?> method, boolean passThis) {
|
||||
return new Overload(
|
||||
(ctx, th, args) -> method.newInstance(args),
|
||||
method.isVarArgs(), raw,
|
||||
method.isVarArgs(), passThis,
|
||||
Modifier.isStatic(method.getModifiers()) ? null : method.getDeclaringClass(),
|
||||
method.getParameterTypes()
|
||||
);
|
||||
}
|
||||
public static Overload getterFromField(Field field, boolean raw) {
|
||||
public static Overload getterFromField(Field field) {
|
||||
return new Overload(
|
||||
(ctx, th, args) -> field.get(th), false, raw,
|
||||
(ctx, th, args) -> field.get(th), false, false,
|
||||
Modifier.isStatic(field.getModifiers()) ? null : field.getDeclaringClass(),
|
||||
new Class[0]
|
||||
);
|
||||
}
|
||||
public static Overload setterFromField(Field field, boolean raw) {
|
||||
public static Overload setterFromField(Field field) {
|
||||
if (Modifier.isFinal(field.getModifiers())) return null;
|
||||
return new Overload(
|
||||
(ctx, th, args) -> { field.set(th, args[0]); return null; }, false, raw,
|
||||
(ctx, th, args) -> { field.set(th, args[0]); return null; }, false, false,
|
||||
Modifier.isStatic(field.getModifiers()) ? null : field.getDeclaringClass(),
|
||||
new Class[0]
|
||||
);
|
||||
}
|
||||
|
||||
public static Overload getter(Class<?> thisArg, OverloadRunner runner, boolean raw) {
|
||||
public static Overload getter(Class<?> thisArg, OverloadRunner runner, boolean passThis) {
|
||||
return new Overload(
|
||||
(ctx, th, args) -> runner.run(ctx, th, args), false, raw,
|
||||
(ctx, th, args) -> runner.run(ctx, th, args), false, passThis,
|
||||
thisArg,
|
||||
new Class[0]
|
||||
);
|
||||
}
|
||||
|
||||
public Overload(OverloadRunner runner, boolean variadic, boolean raw, Class<?> thisArg, Class<?> args[]) {
|
||||
public Overload(OverloadRunner runner, boolean variadic, boolean passThis, Class<?> thisArg, Class<?> args[]) {
|
||||
this.runner = runner;
|
||||
this.variadic = variadic;
|
||||
this.raw = raw;
|
||||
this.passThis = passThis;
|
||||
this.thisArg = thisArg;
|
||||
this.params = args;
|
||||
|
||||
if (raw) {
|
||||
if (!(
|
||||
thisArg == null && (
|
||||
args.length == 3 && args[0] == Context.class && args[1] == Object.class && args[2] == Object[].class ||
|
||||
args.length == 2 && args[0] == Context.class && args[1] == Object[].class
|
||||
))) throw new IllegalArgumentException("Invalid signature for raw method.");
|
||||
}
|
||||
}
|
||||
}
|
@ -18,14 +18,8 @@ public class OverloadFunction extends FunctionValue {
|
||||
loop: for (var overload : overloads) {
|
||||
Object[] newArgs = new Object[overload.params.length];
|
||||
|
||||
if (overload.raw) {
|
||||
newArgs[0] = ctx;
|
||||
newArgs[1] = thisArg;
|
||||
newArgs[2] = args;
|
||||
}
|
||||
else {
|
||||
boolean consumesEngine = overload.params.length > 0 && overload.params[0] == Context.class;
|
||||
int start = consumesEngine ? 1 : 0;
|
||||
int start = (consumesEngine ? 1 : 0) + (overload.passThis ? 1 : 0);
|
||||
int end = overload.params.length - (overload.variadic ? 1 : 0);
|
||||
|
||||
for (var i = start; i < end; i++) {
|
||||
@ -61,10 +55,11 @@ public class OverloadFunction extends FunctionValue {
|
||||
newArgs[newArgs.length - 1] = varArg;
|
||||
}
|
||||
|
||||
if (consumesEngine) newArgs[0] = ctx;
|
||||
}
|
||||
var thisArgType = overload.passThis ? overload.params[consumesEngine ? 1 : 0] : overload.thisArg;
|
||||
Object _this = thisArgType == null ? null : Values.convert(ctx, thisArg, thisArgType);
|
||||
|
||||
Object _this = overload.thisArg == null ? null : Values.convert(ctx, thisArg, overload.thisArg);
|
||||
if (consumesEngine) newArgs[0] = ctx;
|
||||
if (overload.passThis) newArgs[consumesEngine ? 1 : 0] = _this;
|
||||
|
||||
try {
|
||||
return Values.normalize(ctx, overload.runner.run(ctx, _this, newArgs));
|
||||
|
@ -8,43 +8,26 @@ import me.topchetoeu.jscript.exceptions.EngineException;
|
||||
import me.topchetoeu.jscript.interop.Native;
|
||||
|
||||
public class FunctionPolyfill {
|
||||
@Native(raw=true) public static Object apply(Context ctx, Object func, Object[] args) throws InterruptedException {
|
||||
var thisArg = args.length > 0 ? args[0] : null;
|
||||
var _args = args.length > 1 ? args[1] : null;
|
||||
|
||||
if (!(_args instanceof ArrayValue)) throw EngineException.ofError("Expected arguments to be an array.");
|
||||
if (!(func instanceof FunctionValue)) throw EngineException.ofError("Expected this to be a function.");
|
||||
|
||||
return ((FunctionValue)func).call(ctx, thisArg, ((ArrayValue)_args).toArray());
|
||||
@Native(thisArg = true) public static Object apply(Context ctx, FunctionValue func, Object thisArg, ArrayValue args) throws InterruptedException {
|
||||
return func.call(ctx, thisArg, args.toArray());
|
||||
}
|
||||
@Native(raw=true) public static Object call(Context ctx, Object func, Object[] args) throws InterruptedException {
|
||||
var thisArg = args.length > 0 ? args[0] : null;
|
||||
var _args = new Object[args.length > 1 ? args.length - 1 : 0];
|
||||
|
||||
@Native(thisArg = true) public static Object call(Context ctx, FunctionValue func, Object thisArg, Object... args) throws InterruptedException {
|
||||
if (!(func instanceof FunctionValue)) throw EngineException.ofError("Expected this to be a function.");
|
||||
|
||||
if (_args.length != 0) System.arraycopy(args, 1, _args, 0, _args.length);
|
||||
|
||||
return ((FunctionValue)func).call(ctx, thisArg, _args);
|
||||
return func.call(ctx, thisArg, args);
|
||||
}
|
||||
@Native(raw=true) public static Object bind(Context ctx, Object func, Object[] args) {
|
||||
var thisArg = args.length > 0 ? args[0] : null;
|
||||
var _args = new Object[args.length > 1 ? args.length - 1 : 0];
|
||||
FunctionValue _func = (FunctionValue)func;
|
||||
|
||||
@Native(thisArg = true) public static Object bind(Context ctx, FunctionValue func, Object thisArg, Object... args) {
|
||||
if (!(func instanceof FunctionValue)) throw EngineException.ofError("Expected this to be a function.");
|
||||
|
||||
if (_args.length != 0) System.arraycopy(args, 1, _args, 0, _args.length);
|
||||
return new NativeFunction(func.name + " (bound)", (callCtx, _0, callArgs) -> {
|
||||
var resArgs = new Object[args.length + callArgs.length];
|
||||
System.arraycopy(args, 0, resArgs, 0, args.length);
|
||||
System.arraycopy(callArgs, 0, resArgs, args.length, callArgs.length);
|
||||
|
||||
return new NativeFunction(_func.name + " (bound)", (callCtx, _0, callArgs) -> {
|
||||
var resArgs = new Object[_args.length + callArgs.length];
|
||||
System.arraycopy(_args, 0, resArgs, 0, _args.length);
|
||||
System.arraycopy(callArgs, 0, resArgs, _args.length, resArgs.length - _args.length);
|
||||
|
||||
return _func.call(ctx, thisArg, resArgs);
|
||||
return func.call(ctx, thisArg, resArgs);
|
||||
});
|
||||
}
|
||||
@Native(raw=true) public static String toString(Context ctx, Object func, Object[] args) {
|
||||
@Native(thisArg = true) public static String toString(Context ctx, Object func) {
|
||||
return "function (...) { ... }";
|
||||
}
|
||||
|
||||
|
@ -187,18 +187,18 @@ public class ObjectPolyfill {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Native(raw = true) public static Object valueOf(Context ctx, Object thisArg, Object[] args) {
|
||||
@Native(thisArg = true) public static Object valueOf(Context ctx, Object thisArg) {
|
||||
return thisArg;
|
||||
}
|
||||
@Native(raw = true) public static String toString(Context ctx, Object thisArg, Object[] args) throws InterruptedException {
|
||||
@Native(thisArg = true) public static String toString(Context ctx, Object thisArg) throws InterruptedException {
|
||||
var name = Values.getMember(ctx, thisArg, ctx.env.symbol("Symbol.typeName"));
|
||||
if (name == null) name = "Unknown";
|
||||
else name = Values.toString(ctx, name);
|
||||
|
||||
return "[object " + name + "]";
|
||||
}
|
||||
@Native(raw = true) public static boolean hasOwnProperty(Context ctx, Object thisArg, Object[] args) throws InterruptedException {
|
||||
return ObjectPolyfill.hasOwn(ctx, thisArg, Values.convert(ctx, args.length == 0 ? null : args[0], String.class));
|
||||
@Native(thisArg = true) public static boolean hasOwnProperty(Context ctx, Object thisArg, Object key) throws InterruptedException {
|
||||
return ObjectPolyfill.hasOwn(ctx, thisArg, Values.convert(ctx, key, String.class));
|
||||
}
|
||||
|
||||
@NativeConstructor public static Object constructor(Context ctx, Object arg) throws InterruptedException {
|
||||
|
@ -152,12 +152,9 @@ public class PromisePolyfill {
|
||||
* Thread safe - you can call this from anywhere
|
||||
* HOWEVER, it's strongly recommended to use this only in javascript
|
||||
*/
|
||||
@Native(raw = true) public static Object then(Context ctx, Object thisArg, Object ...args) throws InterruptedException {
|
||||
var onFulfill = args.length > 0 ? args[0] : null;
|
||||
var onReject = args.length > 1 ? args[1]: null;
|
||||
|
||||
if (!(onFulfill instanceof FunctionValue)) onFulfill = null;
|
||||
if (!(onReject instanceof FunctionValue)) onReject = null;
|
||||
@Native(thisArg=true) public static Object then(Context ctx, Object thisArg, Object _onFulfill, Object _onReject) throws InterruptedException {
|
||||
var onFulfill = _onFulfill instanceof FunctionValue ? ((FunctionValue)_onFulfill) : null;
|
||||
var onReject = _onReject instanceof FunctionValue ? ((FunctionValue)_onReject) : null;
|
||||
|
||||
var res = new PromisePolyfill();
|
||||
|
||||
@ -206,24 +203,22 @@ public class PromisePolyfill {
|
||||
* Thread safe - you can call this from anywhere
|
||||
* HOWEVER, it's strongly recommended to use this only in javascript
|
||||
*/
|
||||
@Native(value = "catch", raw = true) public static Object _catch(Context ctx, Object thisArg, Object ...args) throws InterruptedException {
|
||||
return then(ctx, thisArg, null, args.length > 0 ? args[0] : null);
|
||||
@Native(value="catch", thisArg=true) public static Object _catch(Context ctx, Object thisArg, Object _onReject) throws InterruptedException {
|
||||
return then(ctx, thisArg, null, _onReject);
|
||||
}
|
||||
/**
|
||||
* Thread safe - you can call this from anywhere
|
||||
* HOWEVER, it's strongly recommended to use this only in javascript
|
||||
*/
|
||||
@Native(value = "finally", raw = true) public static Object _finally(Context ctx, Object thisArg, Object ...args) throws InterruptedException {
|
||||
var handleFunc = args.length > 0 ? args[0] : null;
|
||||
|
||||
@Native(value="finally", thisArg=true) public static Object _finally(Context ctx, Object thisArg, Object _handle) throws InterruptedException {
|
||||
return then(ctx, thisArg,
|
||||
new NativeFunction(null, (e, th, _args) -> {
|
||||
if (handleFunc instanceof FunctionValue) ((FunctionValue)handleFunc).call(ctx);
|
||||
return args[0];
|
||||
if (_handle instanceof FunctionValue) ((FunctionValue)_handle).call(ctx);
|
||||
return _args.length > 0 ? _args[0] : null;
|
||||
}),
|
||||
new NativeFunction(null, (e, th, _args) -> {
|
||||
if (handleFunc instanceof FunctionValue) ((FunctionValue)handleFunc).call(ctx);
|
||||
throw new EngineException(_args[0]);
|
||||
if (_handle instanceof FunctionValue) ((FunctionValue)_handle).call(ctx);
|
||||
throw new EngineException(_args.length > 0 ? _args[0] : null);
|
||||
})
|
||||
);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user