Compare commits
8 Commits
0.9.33-bet
...
0.9.40-bet
| Author | SHA1 | Date | |
|---|---|---|---|
|
fc6ddf7d3c
|
|||
|
7f275095a2
|
|||
|
90d019f92a
|
|||
|
6fb31be12c
|
|||
|
d6ede0b404
|
|||
|
71b40240c0
|
|||
|
a8775d212f
|
|||
|
71872a8d64
|
@@ -1,4 +1,4 @@
|
||||
project_group = me.topchetoeu
|
||||
project_name = jscript
|
||||
project_version = 0.9.27-beta
|
||||
project_version = 0.9.40-beta
|
||||
main_class = me.topchetoeu.jscript.utils.JScriptRepl
|
||||
|
||||
@@ -10,7 +10,7 @@ public class ContinueStatement extends Statement {
|
||||
|
||||
@Override
|
||||
public void compile(CompileResult target, boolean pollute) {
|
||||
target.add(Instruction.nop(loc(), "cont", label));
|
||||
target.add(Instruction.nop("cont", label));
|
||||
if (pollute) target.add(Instruction.pushUndefined());
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package me.topchetoeu.jscript.lib;
|
||||
|
||||
import java.text.NumberFormat;
|
||||
|
||||
import me.topchetoeu.jscript.runtime.values.ObjectValue;
|
||||
import me.topchetoeu.jscript.runtime.values.Values;
|
||||
import me.topchetoeu.jscript.utils.interop.Arguments;
|
||||
@@ -85,6 +87,15 @@ public class NumberLib {
|
||||
@Expose public static String __toString(Arguments args) {
|
||||
return Values.toString(args.ctx, args.self);
|
||||
}
|
||||
@Expose public static String __toFixed(Arguments args) {
|
||||
var digits = args.getInt(0, 0);
|
||||
|
||||
var nf = NumberFormat.getNumberInstance();
|
||||
nf.setMinimumFractionDigits(digits);
|
||||
nf.setMaximumFractionDigits(digits);
|
||||
|
||||
return nf.format(args.getDouble(-1));
|
||||
}
|
||||
@Expose public static double __valueOf(Arguments args) {
|
||||
if (Values.isWrapper(args.self, NumberLib.class)) return Values.wrapper(args.self, NumberLib.class).value;
|
||||
else return Values.toNumber(args.ctx, args.self);
|
||||
|
||||
@@ -14,43 +14,26 @@ public class Context implements Extensions {
|
||||
public final Context parent;
|
||||
public final Extensions extensions;
|
||||
public final Frame frame;
|
||||
// public final Engine engine;
|
||||
public final int stackSize;
|
||||
|
||||
@Override public <T> void add(Key<T> key, T obj) {
|
||||
if (extensions != null) extensions.add(key, obj);
|
||||
// else if (engine != null) engine.add(key, obj);
|
||||
}
|
||||
@Override public <T> T get(Key<T> key) {
|
||||
if (extensions != null && extensions.has(key)) return extensions.get(key);
|
||||
// else if (engine != null && engine.has(key)) return engine.get(key);
|
||||
return null;
|
||||
}
|
||||
@Override public boolean has(Key<?> key) {
|
||||
return
|
||||
extensions != null && extensions.has(key);
|
||||
// engine != null && engine.has(key);
|
||||
return extensions != null && extensions.has(key);
|
||||
}
|
||||
@Override public boolean remove(Key<?> key) {
|
||||
var res = false;
|
||||
|
||||
if (extensions != null) res |= extensions.remove(key);
|
||||
// else if (engine != null) res |= engine.remove(key);
|
||||
|
||||
return res;
|
||||
}
|
||||
@Override public Iterable<Key<?>> keys() {
|
||||
if (extensions == null) return List.of();
|
||||
else return extensions.keys();
|
||||
|
||||
// if (engine == null && environment == null) return List.of();
|
||||
// if (engine == null) return environment.keys();
|
||||
// if (environment == null) return engine.keys();
|
||||
|
||||
// return () -> Stream.concat(
|
||||
// StreamSupport.stream(engine.keys().spliterator(), false),
|
||||
// StreamSupport.stream(environment.keys().spliterator(), false)
|
||||
// ).distinct().iterator();
|
||||
}
|
||||
|
||||
public FunctionValue compile(Filename filename, String raw) {
|
||||
@@ -101,7 +84,7 @@ public class Context implements Extensions {
|
||||
this(null, null, null, 0);
|
||||
}
|
||||
public Context(Extensions ext) {
|
||||
this(null, ext, null, 0);
|
||||
this(null, clean(ext), null, 0);
|
||||
}
|
||||
|
||||
public static Context of(Extensions ext) {
|
||||
|
||||
@@ -44,7 +44,7 @@ public class CodeFunction extends FunctionValue {
|
||||
public CodeFunction(Extensions extensions, String name, FunctionBody body, ValueVariable[] captures) {
|
||||
super(name, body.argsN);
|
||||
this.captures = captures;
|
||||
this.extensions = extensions;
|
||||
this.extensions = Context.clean(extensions);
|
||||
this.body = body;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ import me.topchetoeu.jscript.runtime.debug.DebugContext;
|
||||
import me.topchetoeu.jscript.runtime.exceptions.EngineException;
|
||||
import me.topchetoeu.jscript.runtime.exceptions.InterruptException;
|
||||
import me.topchetoeu.jscript.runtime.exceptions.SyntaxException;
|
||||
import me.topchetoeu.jscript.runtime.scope.GlobalScope;
|
||||
import me.topchetoeu.jscript.runtime.values.NativeFunction;
|
||||
import me.topchetoeu.jscript.runtime.values.Values;
|
||||
import me.topchetoeu.jscript.utils.debug.DebugServer;
|
||||
@@ -28,6 +29,7 @@ import me.topchetoeu.jscript.utils.filesystem.Mode;
|
||||
import me.topchetoeu.jscript.utils.filesystem.PhysicalFilesystem;
|
||||
import me.topchetoeu.jscript.utils.filesystem.RootFilesystem;
|
||||
import me.topchetoeu.jscript.utils.filesystem.STDFilesystem;
|
||||
import me.topchetoeu.jscript.utils.interop.NativeWrapperProvider;
|
||||
import me.topchetoeu.jscript.utils.modules.ModuleRepo;
|
||||
import me.topchetoeu.jscript.utils.permissions.PermissionsManager;
|
||||
import me.topchetoeu.jscript.utils.permissions.PermissionsProvider;
|
||||
@@ -87,10 +89,13 @@ public class JScriptRepl {
|
||||
private static void initEnv() {
|
||||
environment = Internals.apply(environment);
|
||||
|
||||
environment.global.define(null, false, new NativeFunction("exit", args -> {
|
||||
var wp = NativeWrapperProvider.get(environment);
|
||||
var glob = GlobalScope.get(environment);
|
||||
|
||||
glob.define(null, false, new NativeFunction("exit", args -> {
|
||||
throw new InterruptException();
|
||||
}));
|
||||
environment.global.define(null, false, new NativeFunction("go", args -> {
|
||||
glob.define(null, false, new NativeFunction("go", args -> {
|
||||
try {
|
||||
var f = Path.of("do.js");
|
||||
var func = args.ctx.compile(new Filename("do", "do/" + j++ + ".js"), new String(Files.readAllBytes(f)));
|
||||
@@ -100,7 +105,7 @@ public class JScriptRepl {
|
||||
throw new EngineException("Couldn't open do.js");
|
||||
}
|
||||
}));
|
||||
environment.global.define(null, false, new NativeFunction("log", args -> {
|
||||
glob.define(null, false, new NativeFunction("log", args -> {
|
||||
for (var el : args.args) {
|
||||
Values.printValue(args.ctx, el);
|
||||
}
|
||||
|
||||
@@ -397,7 +397,7 @@ public class SimpleDebugger implements Debugger {
|
||||
catch (Exception e) { }
|
||||
|
||||
try { res.set("description", className + (defaultToString ? "" : " { " + Values.toString(ctx, obj) + " }")); }
|
||||
catch (EngineException e) { }
|
||||
catch (Exception e) { }
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -4,10 +4,12 @@ import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Member;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import me.topchetoeu.jscript.common.Location;
|
||||
import me.topchetoeu.jscript.runtime.Context;
|
||||
@@ -30,6 +32,7 @@ public class NativeWrapperProvider implements Copyable {
|
||||
private final HashMap<Class<?>, ObjectValue> namespaces = new HashMap<>();
|
||||
private final HashMap<Class<?>, Class<?>> classToProxy = new HashMap<>();
|
||||
private final HashMap<Class<?>, Class<?>> proxyToClass = new HashMap<>();
|
||||
private final HashMap<Class<?>, Class<?>> interfaceToProxy = new HashMap<>();
|
||||
private final HashSet<Class<?>> ignore = new HashSet<>();
|
||||
|
||||
private static Object call(Context ctx, String name, Method method, Object thisArg, Object... args) {
|
||||
@@ -83,10 +86,16 @@ public class NativeWrapperProvider implements Copyable {
|
||||
String.join(", ", Arrays.stream(actual).map(v -> v.getName()).collect(Collectors.toList()))
|
||||
));
|
||||
}
|
||||
private static String getName(Class<?> clazz) {
|
||||
var classNat = clazz.getAnnotation(WrapperName.class);
|
||||
if (classNat != null && !classNat.value().trim().equals("")) return classNat.value().trim();
|
||||
else return clazz.getSimpleName();
|
||||
private static String getName(Class<?> ...classes) {
|
||||
String last = null;
|
||||
|
||||
for (var clazz : classes) {
|
||||
var classNat = clazz.getAnnotation(WrapperName.class);
|
||||
if (classNat != null && !classNat.value().trim().equals("")) return classNat.value().trim();
|
||||
else if (last != null) last = clazz.getSimpleName();
|
||||
}
|
||||
|
||||
return last;
|
||||
}
|
||||
|
||||
private static void checkUnderscore(Member member) {
|
||||
@@ -120,13 +129,13 @@ public class NativeWrapperProvider implements Copyable {
|
||||
|
||||
for (var method : clazz.getDeclaredMethods()) {
|
||||
for (var annotation : method.getAnnotationsByType(Expose.class)) {
|
||||
any = true;
|
||||
if (!annotation.target().shouldApply(target)) continue;
|
||||
|
||||
checkUnderscore(method);
|
||||
var name = getName(method, annotation.value());
|
||||
var key = getKey(name);
|
||||
var repeat = false;
|
||||
any = true;
|
||||
|
||||
switch (annotation.type()) {
|
||||
case METHOD:
|
||||
@@ -162,13 +171,13 @@ public class NativeWrapperProvider implements Copyable {
|
||||
));
|
||||
}
|
||||
for (var annotation : method.getAnnotationsByType(ExposeField.class)) {
|
||||
any = true;
|
||||
if (!annotation.target().shouldApply(target)) continue;
|
||||
|
||||
checkUnderscore(method);
|
||||
var name = getName(method, annotation.value());
|
||||
var key = getKey(name);
|
||||
var repeat = false;
|
||||
any = true;
|
||||
|
||||
if (props.contains(key) || nonProps.contains(key)) repeat = true;
|
||||
else {
|
||||
@@ -191,13 +200,13 @@ public class NativeWrapperProvider implements Copyable {
|
||||
}
|
||||
for (var field : clazz.getDeclaredFields()) {
|
||||
for (var annotation : field.getAnnotationsByType(ExposeField.class)) {
|
||||
any = true;
|
||||
if (!annotation.target().shouldApply(target)) continue;
|
||||
|
||||
checkUnderscore(field);
|
||||
var name = getName(field, annotation.value());
|
||||
var key = getKey(name);
|
||||
var repeat = false;
|
||||
any = true;
|
||||
|
||||
if (props.contains(key) || nonProps.contains(key)) repeat = true;
|
||||
else {
|
||||
@@ -237,12 +246,23 @@ public class NativeWrapperProvider implements Copyable {
|
||||
|
||||
return any;
|
||||
}
|
||||
private static boolean apply(ObjectValue obj, ExposeTarget target, Class<?> ...appliers) {
|
||||
var res = false;
|
||||
|
||||
private static Method getConstructor(Class<?> clazz) {
|
||||
for (var method : clazz.getDeclaredMethods()) {
|
||||
if (!method.isAnnotationPresent(ExposeConstructor.class)) continue;
|
||||
checkSignature(method, true, Arguments.class);
|
||||
return method;
|
||||
for (var i = appliers.length - 1; i >= 0; i--) {
|
||||
res |= apply(obj, target, appliers[i]);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
private static Method getConstructor(Class<?> ...appliers) {
|
||||
for (var clazz : appliers) {
|
||||
for (var method : clazz.getDeclaredMethods()) {
|
||||
if (!method.isAnnotationPresent(ExposeConstructor.class)) continue;
|
||||
checkSignature(method, true, Arguments.class);
|
||||
return method;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
@@ -254,10 +274,10 @@ public class NativeWrapperProvider implements Copyable {
|
||||
* 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) {
|
||||
public static ObjectValue makeProto(Class<?> ...appliers) {
|
||||
var res = new ObjectValue();
|
||||
res.defineProperty(null, Symbol.get("Symbol.typeName"), getName(clazz));
|
||||
if (!apply(res, ExposeTarget.PROTOTYPE, clazz)) return null;
|
||||
res.defineProperty(null, Symbol.get("Symbol.typeName"), getName(appliers));
|
||||
if (!apply(res, ExposeTarget.PROTOTYPE, appliers)) return null;
|
||||
return res;
|
||||
}
|
||||
/**
|
||||
@@ -266,14 +286,14 @@ public class NativeWrapperProvider implements Copyable {
|
||||
* 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) {
|
||||
var constr = getConstructor(clazz);
|
||||
public static FunctionValue makeConstructor(Class<?> ...appliers) {
|
||||
var constr = getConstructor(appliers);
|
||||
|
||||
FunctionValue res = constr == null ?
|
||||
new NativeFunction(getName(clazz), args -> { throw EngineException.ofError("This constructor is not invokable."); }) :
|
||||
create(getName(clazz), constr);
|
||||
new NativeFunction(getName(appliers), args -> { throw EngineException.ofError("This constructor is not invokable."); }) :
|
||||
create(getName(appliers), constr);
|
||||
|
||||
apply(res, ExposeTarget.CONSTRUCTOR, clazz);
|
||||
if (constr == null && !apply(res, ExposeTarget.CONSTRUCTOR, appliers)) return null;
|
||||
|
||||
return res;
|
||||
}
|
||||
@@ -283,13 +303,27 @@ public class NativeWrapperProvider implements Copyable {
|
||||
* This method behaves almost like {@link NativeWrapperProvider#makeConstructor}, but will return an object instead.
|
||||
* @param clazz The class for which a constructor should be generated
|
||||
*/
|
||||
public static ObjectValue makeNamespace(Class<?> clazz) {
|
||||
public static ObjectValue makeNamespace(Class<?> ...appliers) {
|
||||
var res = new ObjectValue();
|
||||
res.defineProperty(null, Symbol.get("Symbol.typeName"), getName(clazz));
|
||||
if (!apply(res, ExposeTarget.NAMESPACE, clazz)) return null;
|
||||
|
||||
if (!apply(res, ExposeTarget.NAMESPACE, appliers)) return null;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
private Class<?>[] getAppliers(Class<?> clazz) {
|
||||
var res = new ArrayList<Class<?>>();
|
||||
|
||||
res.add(clazz);
|
||||
|
||||
if (classToProxy.containsKey(clazz)) res.add(classToProxy.get(clazz));
|
||||
for (var intf : interfaceToProxy.keySet()) {
|
||||
if (intf.isAssignableFrom(clazz)) res.add(interfaceToProxy.get(intf));
|
||||
}
|
||||
|
||||
return res.toArray(Class<?>[]::new);
|
||||
}
|
||||
|
||||
private void updateProtoChain(Class<?> clazz, ObjectValue proto, FunctionValue constr) {
|
||||
var parent = clazz;
|
||||
|
||||
@@ -326,8 +360,10 @@ public class NativeWrapperProvider implements Copyable {
|
||||
clazz.isSynthetic()
|
||||
) return;
|
||||
|
||||
if (constr == null) constr = makeConstructor(clazz);
|
||||
if (proto == null) proto = makeProto(clazz);
|
||||
var appliers = getAppliers(clazz);
|
||||
|
||||
if (constr == null) constr = makeConstructor(appliers);
|
||||
if (proto == null) proto = makeProto(appliers);
|
||||
|
||||
if (constr == null || proto == null) return;
|
||||
|
||||
@@ -386,30 +422,29 @@ public class NativeWrapperProvider implements Copyable {
|
||||
|
||||
public void set(Class<?> clazz, Class<?> wrapper) {
|
||||
if (clazz == null) return;
|
||||
if (wrapper == null) wrapper = clazz;
|
||||
if (classToProxy.get(clazz) == wrapper) return;
|
||||
|
||||
classToProxy.remove(wrapper);
|
||||
proxyToClass.remove(clazz);
|
||||
if (clazz.isInterface()) {
|
||||
if (wrapper == null || wrapper == clazz) interfaceToProxy.remove(clazz);
|
||||
else interfaceToProxy.put(clazz, wrapper);
|
||||
}
|
||||
else {
|
||||
if (wrapper == null || wrapper == clazz) classToProxy.remove(clazz);
|
||||
else classToProxy.put(clazz, wrapper);
|
||||
}
|
||||
|
||||
classToProxy.put(clazz, wrapper);
|
||||
proxyToClass.put(wrapper, clazz);
|
||||
var classes = Stream.concat(
|
||||
Stream.of(clazz),
|
||||
prototypes.keySet().stream().filter(clazz::isAssignableFrom)
|
||||
).toArray(Class<?>[]::new);
|
||||
|
||||
ignore.remove(clazz);
|
||||
for (var el : classes) {
|
||||
prototypes.remove(el);
|
||||
constructors.remove(el);
|
||||
namespaces.remove(el);
|
||||
}
|
||||
|
||||
var proto = makeProto(wrapper);
|
||||
var constr = makeConstructor(wrapper);
|
||||
|
||||
prototypes.put(clazz, proto);
|
||||
constructors.put(clazz, constr);
|
||||
|
||||
proto.defineProperty(null, "constructor", constr, true, false, false);
|
||||
constr.defineProperty(null, "prototype", proto, true, false, false);
|
||||
|
||||
for (var el : prototypes.keySet()) {
|
||||
if (clazz.isAssignableFrom(el)) {
|
||||
updateProtoChain(el, getProto(el), getConstr(el));
|
||||
}
|
||||
for (var el : classes) {
|
||||
initType(el, null, null);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user