feat: add support for member class wrappers

This commit is contained in:
TopchetoEU 2023-08-21 11:02:06 +03:00
parent 7e6a1e03c8
commit 6da7720c67
No known key found for this signature in database
GPG Key ID: 24E57B2E9C61AD19
4 changed files with 49 additions and 5 deletions

View File

@ -8,7 +8,6 @@ import me.topchetoeu.jscript.engine.CallContext.DataKey;
import me.topchetoeu.jscript.engine.debug.DebugState;
import me.topchetoeu.jscript.engine.modules.ModuleManager;
import me.topchetoeu.jscript.engine.scope.GlobalScope;
import me.topchetoeu.jscript.engine.values.CodeFunction;
import me.topchetoeu.jscript.engine.values.FunctionValue;
import me.topchetoeu.jscript.engine.values.ObjectValue;
import me.topchetoeu.jscript.engine.values.ObjectValue.PlaceholderProto;
@ -181,7 +180,7 @@ public class Engine {
return msg.notifier;
}
public CodeFunction compile(GlobalScope scope, String filename, String raw) throws InterruptedException {
public FunctionValue compile(GlobalScope scope, String filename, String raw) throws InterruptedException {
return Parsing.compile(scope, filename, raw);
}

View File

@ -5,7 +5,7 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ ElementType.METHOD, ElementType.FIELD, ElementType.CONSTRUCTOR })
@Target({ ElementType.METHOD, ElementType.FIELD, ElementType.CONSTRUCTOR, ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
public @interface Native {
public String value() default "";

View File

@ -71,15 +71,45 @@ public class NativeTypeRegister {
}
}
}
private static void applyClasses(boolean member, ObjectValue target, Class<?> clazz) {
for (var cl : clazz.getDeclaredClasses()) {
if (!Modifier.isStatic(cl.getModifiers()) != member) continue;
var nat = cl.getAnnotation(Native.class);
if (nat != null) {
var name = nat.value();
if (name.equals("")) name = cl.getSimpleName();
var getter = new OverloadFunction("get " + name).add(Overload.getter(member ? clazz : null, (ctx, thisArg, args) -> {
return ctx.engine().typeRegister().getConstr(cl);
}));
target.defineProperty(name, getter, null, true, false);
}
}
}
/**
* Generates a prototype for the given class.
* The returned object will have appropriate wrappers for all instance members.
* All accessors and methods will expect the this argument to be a native wrapper of the given class type.
* @param clazz The class for which a prototype should be generated
*/
public static ObjectValue makeProto(Class<?> clazz) {
var res = new ObjectValue();
applyMethods(true, res, clazz);
applyFields(true, res, clazz);
applyClasses(true, res, clazz);
return res;
}
/**
* Generates a constructor for the given class.
* The returned function will have appropriate wrappers for all static members.
* When the function gets called, the underlying constructor will get called, unless the constructor is inaccessible.
* @param clazz The class for which a constructor should be generated
*/
public static FunctionValue makeConstructor(Class<?> clazz) {
FunctionValue func = new OverloadFunction(clazz.getName());
@ -94,16 +124,24 @@ public class NativeTypeRegister {
applyMethods(false, func, clazz);
applyFields(false, func, clazz);
applyClasses(false, func, clazz);
func.special = true;
return func;
}
/**
* Generates a namespace for the given class.
* The returned function will have appropriate wrappers for all static members.
* This method behaves almost like {@link NativeTypeRegister#makeConstructor}, but will return an object instead.
* @param clazz The class for which a constructor should be generated
*/
public static ObjectValue makeNamespace(Class<?> clazz) {
ObjectValue res = new ObjectValue();
applyMethods(false, res, clazz);
applyFields(false, res, clazz);
applyClasses(false, res, clazz);
return res;
}

View File

@ -15,7 +15,7 @@ public class Overload {
IllegalArgumentException;
}
public final Overload.OverloadRunner runner;
public final OverloadRunner runner;
public final boolean variadic;
public final Class<?> thisArg;
public final Class<?>[] params;
@ -52,8 +52,15 @@ public class Overload {
);
}
public static Overload getter(Class<?> thisArg, OverloadRunner runner) {
return new Overload(
(ctx, th, args) -> runner.run(ctx, th, args), false,
thisArg,
new Class[0]
);
}
public Overload(Overload.OverloadRunner runner, boolean variadic, Class<?> thisArg, Class<?> args[]) {
public Overload(OverloadRunner runner, boolean variadic, Class<?> thisArg, Class<?> args[]) {
this.runner = runner;
this.variadic = variadic;
this.thisArg = thisArg;