fix: use Extensions instead of Environment
This commit is contained in:
parent
0d629a6e82
commit
c707f880f7
@ -9,7 +9,7 @@ import me.topchetoeu.jscript.compilation.parsing.Operator;
|
|||||||
import me.topchetoeu.jscript.compilation.parsing.ParseRes;
|
import me.topchetoeu.jscript.compilation.parsing.ParseRes;
|
||||||
import me.topchetoeu.jscript.compilation.parsing.Parsing;
|
import me.topchetoeu.jscript.compilation.parsing.Parsing;
|
||||||
import me.topchetoeu.jscript.compilation.parsing.Token;
|
import me.topchetoeu.jscript.compilation.parsing.Token;
|
||||||
import me.topchetoeu.jscript.runtime.Context;
|
import me.topchetoeu.jscript.runtime.Extensions;
|
||||||
import me.topchetoeu.jscript.runtime.exceptions.EngineException;
|
import me.topchetoeu.jscript.runtime.exceptions.EngineException;
|
||||||
import me.topchetoeu.jscript.runtime.exceptions.SyntaxException;
|
import me.topchetoeu.jscript.runtime.exceptions.SyntaxException;
|
||||||
import me.topchetoeu.jscript.runtime.values.ArrayValue;
|
import me.topchetoeu.jscript.runtime.values.ArrayValue;
|
||||||
@ -32,7 +32,7 @@ public class JSON {
|
|||||||
if (val.isNull()) return Values.NULL;
|
if (val.isNull()) return Values.NULL;
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
private static JSONElement fromJs(Context ctx, Object val, HashSet<Object> prev) {
|
private static JSONElement fromJs(Extensions ext, Object val, HashSet<Object> prev) {
|
||||||
if (val instanceof Boolean) return JSONElement.bool((boolean)val);
|
if (val instanceof Boolean) return JSONElement.bool((boolean)val);
|
||||||
if (val instanceof Number) return JSONElement.number(((Number)val).doubleValue());
|
if (val instanceof Number) return JSONElement.number(((Number)val).doubleValue());
|
||||||
if (val instanceof String) return JSONElement.string((String)val);
|
if (val instanceof String) return JSONElement.string((String)val);
|
||||||
@ -44,7 +44,7 @@ public class JSON {
|
|||||||
var res = new JSONList();
|
var res = new JSONList();
|
||||||
|
|
||||||
for (var el : ((ArrayValue)val).toArray()) {
|
for (var el : ((ArrayValue)val).toArray()) {
|
||||||
var jsonEl = fromJs(ctx, el, prev);
|
var jsonEl = fromJs(ext, el, prev);
|
||||||
if (jsonEl == null) jsonEl = JSONElement.NULL;
|
if (jsonEl == null) jsonEl = JSONElement.NULL;
|
||||||
res.add(jsonEl);
|
res.add(jsonEl);
|
||||||
}
|
}
|
||||||
@ -58,8 +58,8 @@ public class JSON {
|
|||||||
|
|
||||||
var res = new JSONMap();
|
var res = new JSONMap();
|
||||||
|
|
||||||
for (var el : Values.getMembers(ctx, val, false, false)) {
|
for (var el : Values.getMembers(ext, val, false, false)) {
|
||||||
var jsonEl = fromJs(ctx, Values.getMember(ctx, val, el), prev);
|
var jsonEl = fromJs(ext, Values.getMember(ext, val, el), prev);
|
||||||
if (jsonEl == null) continue;
|
if (jsonEl == null) continue;
|
||||||
if (el instanceof String || el instanceof Number) res.put(el.toString(), jsonEl);
|
if (el instanceof String || el instanceof Number) res.put(el.toString(), jsonEl);
|
||||||
}
|
}
|
||||||
@ -70,8 +70,8 @@ public class JSON {
|
|||||||
if (val == null) return null;
|
if (val == null) return null;
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
public static JSONElement fromJs(Context ctx, Object val) {
|
public static JSONElement fromJs(Extensions ext, Object val) {
|
||||||
return fromJs(ctx, val, new HashSet<>());
|
return fromJs(ext, val, new HashSet<>());
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ParseRes<String> parseIdentifier(List<Token> tokens, int i) {
|
public static ParseRes<String> parseIdentifier(List<Token> tokens, int i) {
|
||||||
|
@ -2,6 +2,7 @@ package me.topchetoeu.jscript.lib;
|
|||||||
|
|
||||||
import me.topchetoeu.jscript.lib.PromiseLib.Handle;
|
import me.topchetoeu.jscript.lib.PromiseLib.Handle;
|
||||||
import me.topchetoeu.jscript.runtime.Context;
|
import me.topchetoeu.jscript.runtime.Context;
|
||||||
|
import me.topchetoeu.jscript.runtime.Extensions;
|
||||||
import me.topchetoeu.jscript.runtime.Frame;
|
import me.topchetoeu.jscript.runtime.Frame;
|
||||||
import me.topchetoeu.jscript.runtime.exceptions.EngineException;
|
import me.topchetoeu.jscript.runtime.exceptions.EngineException;
|
||||||
import me.topchetoeu.jscript.runtime.values.CodeFunction;
|
import me.topchetoeu.jscript.runtime.values.CodeFunction;
|
||||||
@ -65,8 +66,9 @@ public class AsyncFunctionLib extends FunctionValue {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object call(Context ctx, Object thisArg, Object ...args) {
|
public Object call(Extensions ext, Object thisArg, Object ...args) {
|
||||||
var handler = new AsyncHelper();
|
var handler = new AsyncHelper();
|
||||||
|
var ctx = Context.of(ext);
|
||||||
|
|
||||||
var newArgs = new Object[args.length + 1];
|
var newArgs = new Object[args.length + 1];
|
||||||
newArgs[0] = new NativeFunction("await", handler::await);
|
newArgs[0] = new NativeFunction("await", handler::await);
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package me.topchetoeu.jscript.lib;
|
package me.topchetoeu.jscript.lib;
|
||||||
|
|
||||||
import me.topchetoeu.jscript.runtime.Context;
|
import me.topchetoeu.jscript.runtime.Context;
|
||||||
|
import me.topchetoeu.jscript.runtime.Extensions;
|
||||||
import me.topchetoeu.jscript.runtime.Frame;
|
import me.topchetoeu.jscript.runtime.Frame;
|
||||||
import me.topchetoeu.jscript.runtime.exceptions.EngineException;
|
import me.topchetoeu.jscript.runtime.exceptions.EngineException;
|
||||||
import me.topchetoeu.jscript.runtime.values.CodeFunction;
|
import me.topchetoeu.jscript.runtime.values.CodeFunction;
|
||||||
@ -13,7 +14,7 @@ public class AsyncGeneratorFunctionLib extends FunctionValue {
|
|||||||
public final CodeFunction func;
|
public final CodeFunction func;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object call(Context ctx, Object thisArg, Object ...args) {
|
public Object call(Extensions ext, Object thisArg, Object ...args) {
|
||||||
var handler = new AsyncGeneratorLib();
|
var handler = new AsyncGeneratorLib();
|
||||||
|
|
||||||
var newArgs = new Object[args.length + 2];
|
var newArgs = new Object[args.length + 2];
|
||||||
@ -21,7 +22,7 @@ public class AsyncGeneratorFunctionLib extends FunctionValue {
|
|||||||
newArgs[1] = new NativeFunction("yield", handler::yield);
|
newArgs[1] = new NativeFunction("yield", handler::yield);
|
||||||
System.arraycopy(args, 0, newArgs, 2, args.length);
|
System.arraycopy(args, 0, newArgs, 2, args.length);
|
||||||
|
|
||||||
handler.frame = new Frame(ctx, thisArg, newArgs, func);
|
handler.frame = new Frame(Context.of(ext), thisArg, newArgs, func);
|
||||||
return handler;
|
return handler;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -101,7 +101,7 @@ public class AsyncGeneratorLib {
|
|||||||
}
|
}
|
||||||
@Expose public PromiseLib __throw(Arguments args) {
|
@Expose public PromiseLib __throw(Arguments args) {
|
||||||
this.currPromise = new PromiseLib();
|
this.currPromise = new PromiseLib();
|
||||||
next(args.ctx, Values.NO_RETURN, Values.NO_RETURN, new EngineException(args.get(0)).setCtx(args.ctx));
|
next(args.ctx, Values.NO_RETURN, Values.NO_RETURN, new EngineException(args.get(0)).setExtensions(args.ctx));
|
||||||
return this.currPromise;
|
return this.currPromise;
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,6 +1,7 @@
|
|||||||
package me.topchetoeu.jscript.lib;
|
package me.topchetoeu.jscript.lib;
|
||||||
|
|
||||||
import me.topchetoeu.jscript.runtime.Context;
|
import me.topchetoeu.jscript.runtime.Context;
|
||||||
|
import me.topchetoeu.jscript.runtime.Extensions;
|
||||||
import me.topchetoeu.jscript.runtime.Frame;
|
import me.topchetoeu.jscript.runtime.Frame;
|
||||||
import me.topchetoeu.jscript.runtime.exceptions.EngineException;
|
import me.topchetoeu.jscript.runtime.exceptions.EngineException;
|
||||||
import me.topchetoeu.jscript.runtime.values.CodeFunction;
|
import me.topchetoeu.jscript.runtime.values.CodeFunction;
|
||||||
@ -12,14 +13,14 @@ import me.topchetoeu.jscript.utils.interop.WrapperName;
|
|||||||
public class GeneratorFunctionLib extends FunctionValue {
|
public class GeneratorFunctionLib extends FunctionValue {
|
||||||
public final CodeFunction func;
|
public final CodeFunction func;
|
||||||
|
|
||||||
@Override public Object call(Context ctx, Object thisArg, Object ...args) {
|
@Override public Object call(Extensions ext, Object thisArg, Object ...args) {
|
||||||
var handler = new GeneratorLib();
|
var handler = new GeneratorLib();
|
||||||
|
|
||||||
var newArgs = new Object[args.length + 1];
|
var newArgs = new Object[args.length + 1];
|
||||||
newArgs[0] = new NativeFunction("yield", handler::yield);
|
newArgs[0] = new NativeFunction("yield", handler::yield);
|
||||||
System.arraycopy(args, 0, newArgs, 1, args.length);
|
System.arraycopy(args, 0, newArgs, 1, args.length);
|
||||||
|
|
||||||
handler.frame = new Frame(ctx, thisArg, newArgs, func);
|
handler.frame = new Frame(Context.of(ext), thisArg, newArgs, func);
|
||||||
return handler;
|
return handler;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -59,7 +59,7 @@ public class GeneratorLib {
|
|||||||
else return next(args.ctx, args.get(0), Values.NO_RETURN, null);
|
else return next(args.ctx, args.get(0), Values.NO_RETURN, null);
|
||||||
}
|
}
|
||||||
@Expose public ObjectValue __throw(Arguments args) {
|
@Expose public ObjectValue __throw(Arguments args) {
|
||||||
return next(args.ctx, Values.NO_RETURN, Values.NO_RETURN, new EngineException(args.get(0)).setCtx(args.ctx));
|
return next(args.ctx, Values.NO_RETURN, Values.NO_RETURN, new EngineException(args.get(0)).setExtensions(args.ctx));
|
||||||
}
|
}
|
||||||
@Expose public ObjectValue __return(Arguments args) {
|
@Expose public ObjectValue __return(Arguments args) {
|
||||||
return next(args.ctx, Values.NO_RETURN, args.get(0), null);
|
return next(args.ctx, Values.NO_RETURN, args.get(0), null);
|
||||||
|
@ -17,6 +17,7 @@ import me.topchetoeu.jscript.utils.interop.Expose;
|
|||||||
import me.topchetoeu.jscript.utils.interop.ExposeField;
|
import me.topchetoeu.jscript.utils.interop.ExposeField;
|
||||||
import me.topchetoeu.jscript.utils.interop.ExposeTarget;
|
import me.topchetoeu.jscript.utils.interop.ExposeTarget;
|
||||||
import me.topchetoeu.jscript.utils.interop.ExposeType;
|
import me.topchetoeu.jscript.utils.interop.ExposeType;
|
||||||
|
import me.topchetoeu.jscript.utils.interop.NativeWrapperProvider;
|
||||||
import me.topchetoeu.jscript.utils.modules.ModuleRepo;
|
import me.topchetoeu.jscript.utils.modules.ModuleRepo;
|
||||||
|
|
||||||
public class Internals {
|
public class Internals {
|
||||||
@ -51,7 +52,7 @@ public class Internals {
|
|||||||
try { Thread.sleep(ms, ns); }
|
try { Thread.sleep(ms, ns); }
|
||||||
catch (InterruptedException e) { return; }
|
catch (InterruptedException e) { return; }
|
||||||
|
|
||||||
args.ctx.get(EventLoop.KEY).pushMsg(() -> func.call(new Context(args.ctx.environment), null, arguments), false);
|
args.ctx.get(EventLoop.KEY).pushMsg(() -> func.call(new Context(args.ctx.extensions), null, arguments), false);
|
||||||
});
|
});
|
||||||
|
|
||||||
thread.start();
|
thread.start();
|
||||||
@ -79,7 +80,7 @@ public class Internals {
|
|||||||
}
|
}
|
||||||
catch (InterruptedException e) { return; }
|
catch (InterruptedException e) { return; }
|
||||||
|
|
||||||
args.ctx.get(EventLoop.KEY).pushMsg(() -> func.call(new Context(args.ctx.environment), null, arguments), false);
|
args.ctx.get(EventLoop.KEY).pushMsg(() -> func.call(new Context(args.ctx.extensions), null, arguments), false);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
thread.start();
|
thread.start();
|
||||||
@ -165,8 +166,8 @@ public class Internals {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static Environment apply(Environment env) {
|
public static Environment apply(Environment env) {
|
||||||
var wp = env.wrappers;
|
var wp = new NativeWrapperProvider();
|
||||||
var glob = env.global = new GlobalScope(wp.getNamespace(Internals.class));
|
var glob = new GlobalScope(wp.getNamespace(Internals.class));
|
||||||
|
|
||||||
glob.define(null, "Math", false, wp.getNamespace(MathLib.class));
|
glob.define(null, "Math", false, wp.getNamespace(MathLib.class));
|
||||||
glob.define(null, "JSON", false, wp.getNamespace(JSONLib.class));
|
glob.define(null, "JSON", false, wp.getNamespace(JSONLib.class));
|
||||||
@ -209,8 +210,12 @@ public class Internals {
|
|||||||
env.add(Environment.TYPE_ERR_PROTO, wp.getProto(TypeErrorLib.class));
|
env.add(Environment.TYPE_ERR_PROTO, wp.getProto(TypeErrorLib.class));
|
||||||
env.add(Environment.RANGE_ERR_PROTO, wp.getProto(RangeErrorLib.class));
|
env.add(Environment.RANGE_ERR_PROTO, wp.getProto(RangeErrorLib.class));
|
||||||
|
|
||||||
Values.setPrototype(Context.NULL, wp.getProto(ObjectLib.class), null);
|
|
||||||
env.add(Environment.REGEX_CONSTR, wp.getConstr(RegExpLib.class));
|
env.add(Environment.REGEX_CONSTR, wp.getConstr(RegExpLib.class));
|
||||||
|
Values.setPrototype(new Context(), wp.getProto(ObjectLib.class), null);
|
||||||
|
|
||||||
|
env.add(NativeWrapperProvider.KEY, wp);
|
||||||
|
env.add(GlobalScope.KEY, glob);
|
||||||
|
|
||||||
|
|
||||||
return env;
|
return env;
|
||||||
}
|
}
|
||||||
|
@ -65,7 +65,7 @@ public class PromiseLib {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (state == STATE_REJECTED && !handled) {
|
if (state == STATE_REJECTED && !handled) {
|
||||||
Values.printError(((EngineException)val).setCtx(ctx), "(in promise)");
|
Values.printError(((EngineException)val).setExtensions(ctx), "(in promise)");
|
||||||
}
|
}
|
||||||
|
|
||||||
handles = null;
|
handles = null;
|
||||||
@ -207,7 +207,7 @@ public class PromiseLib {
|
|||||||
}
|
}
|
||||||
@Expose(value = "reject", target = ExposeTarget.STATIC)
|
@Expose(value = "reject", target = ExposeTarget.STATIC)
|
||||||
public static PromiseLib __ofRejected(Arguments args) {
|
public static PromiseLib __ofRejected(Arguments args) {
|
||||||
return ofRejected(args.ctx, new EngineException(args.get(0)).setCtx(args.ctx));
|
return ofRejected(args.ctx, new EngineException(args.get(0)).setExtensions(args.ctx));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Expose(target = ExposeTarget.STATIC)
|
@Expose(target = ExposeTarget.STATIC)
|
||||||
@ -215,7 +215,7 @@ public class PromiseLib {
|
|||||||
if (!(args.get(0) instanceof ArrayValue)) throw EngineException.ofType("Expected argument for any to be an array.");
|
if (!(args.get(0) instanceof ArrayValue)) throw EngineException.ofType("Expected argument for any to be an array.");
|
||||||
var promises = args.convert(0, ArrayValue.class);
|
var promises = args.convert(0, ArrayValue.class);
|
||||||
|
|
||||||
if (promises.size() == 0) return ofRejected(args.ctx, EngineException.ofError("No promises passed to 'Promise.any'.").setCtx(args.ctx));
|
if (promises.size() == 0) return ofRejected(args.ctx, EngineException.ofError("No promises passed to 'Promise.any'.").setExtensions(args.ctx));
|
||||||
var n = new int[] { promises.size() };
|
var n = new int[] { promises.size() };
|
||||||
var res = new PromiseLib();
|
var res = new PromiseLib();
|
||||||
var errors = new ArrayValue();
|
var errors = new ArrayValue();
|
||||||
@ -230,7 +230,7 @@ public class PromiseLib {
|
|||||||
public void onReject(EngineException err) {
|
public void onReject(EngineException err) {
|
||||||
errors.set(args.ctx, index, err.value);
|
errors.set(args.ctx, index, err.value);
|
||||||
n[0]--;
|
n[0]--;
|
||||||
if (n[0] <= 0) res.reject(args.ctx, new EngineException(errors).setCtx(args.ctx));
|
if (n[0] <= 0) res.reject(args.ctx, new EngineException(errors).setExtensions(args.ctx));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -390,7 +390,7 @@ public class PromiseLib {
|
|||||||
return null;
|
return null;
|
||||||
}),
|
}),
|
||||||
new NativeFunction(null, _args -> {
|
new NativeFunction(null, _args -> {
|
||||||
res.reject(_args.ctx, new EngineException(_args.get(0)).setCtx(_args.ctx));
|
res.reject(_args.ctx, new EngineException(_args.get(0)).setExtensions(_args.ctx));
|
||||||
return null;
|
return null;
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
5
src/java/me/topchetoeu/jscript/runtime/Childable.java
Normal file
5
src/java/me/topchetoeu/jscript/runtime/Childable.java
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
package me.topchetoeu.jscript.runtime;
|
||||||
|
|
||||||
|
public interface Childable {
|
||||||
|
Object child();
|
||||||
|
}
|
@ -11,39 +11,37 @@ import me.topchetoeu.jscript.runtime.values.CodeFunction;
|
|||||||
import me.topchetoeu.jscript.runtime.values.FunctionValue;
|
import me.topchetoeu.jscript.runtime.values.FunctionValue;
|
||||||
|
|
||||||
public class Context implements Extensions {
|
public class Context implements Extensions {
|
||||||
public static final Context NULL = new Context();
|
|
||||||
|
|
||||||
public final Context parent;
|
public final Context parent;
|
||||||
public final Environment environment;
|
public final Extensions extensions;
|
||||||
public final Frame frame;
|
public final Frame frame;
|
||||||
// public final Engine engine;
|
// public final Engine engine;
|
||||||
public final int stackSize;
|
public final int stackSize;
|
||||||
|
|
||||||
@Override public <T> void add(Key<T> key, T obj) {
|
@Override public <T> void add(Key<T> key, T obj) {
|
||||||
if (environment != null) environment.add(key, obj);
|
if (extensions != null) extensions.add(key, obj);
|
||||||
// else if (engine != null) engine.add(key, obj);
|
// else if (engine != null) engine.add(key, obj);
|
||||||
}
|
}
|
||||||
@Override public <T> T get(Key<T> key) {
|
@Override public <T> T get(Key<T> key) {
|
||||||
if (environment != null && environment.has(key)) return environment.get(key);
|
if (extensions != null && extensions.has(key)) return extensions.get(key);
|
||||||
// else if (engine != null && engine.has(key)) return engine.get(key);
|
// else if (engine != null && engine.has(key)) return engine.get(key);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@Override public boolean has(Key<?> key) {
|
@Override public boolean has(Key<?> key) {
|
||||||
return
|
return
|
||||||
environment != null && environment.has(key);
|
extensions != null && extensions.has(key);
|
||||||
// engine != null && engine.has(key);
|
// engine != null && engine.has(key);
|
||||||
}
|
}
|
||||||
@Override public boolean remove(Key<?> key) {
|
@Override public boolean remove(Key<?> key) {
|
||||||
var res = false;
|
var res = false;
|
||||||
|
|
||||||
if (environment != null) res |= environment.remove(key);
|
if (extensions != null) res |= extensions.remove(key);
|
||||||
// else if (engine != null) res |= engine.remove(key);
|
// else if (engine != null) res |= engine.remove(key);
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
@Override public Iterable<Key<?>> keys() {
|
@Override public Iterable<Key<?>> keys() {
|
||||||
if (environment == null) return List.of();
|
if (extensions == null) return List.of();
|
||||||
else return environment.keys();
|
else return extensions.keys();
|
||||||
|
|
||||||
// if (engine == null && environment == null) return List.of();
|
// if (engine == null && environment == null) return List.of();
|
||||||
// if (engine == null) return environment.keys();
|
// if (engine == null) return environment.keys();
|
||||||
@ -57,12 +55,12 @@ public class Context implements Extensions {
|
|||||||
|
|
||||||
public FunctionValue compile(Filename filename, String raw) {
|
public FunctionValue compile(Filename filename, String raw) {
|
||||||
DebugContext.get(this).onSource(filename, raw);
|
DebugContext.get(this).onSource(filename, raw);
|
||||||
var result = new CodeFunction(environment, filename.toString(), Compiler.get(this).compile(filename, raw), new ValueVariable[0]);
|
var result = new CodeFunction(extensions, filename.toString(), Compiler.get(this).compile(filename, raw), new ValueVariable[0]);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Context pushFrame(Frame frame) {
|
public Context pushFrame(Frame frame) {
|
||||||
var res = new Context(this, frame.function.environment, frame, stackSize + 1);
|
var res = new Context(this, frame.function.extensions, frame, stackSize + 1);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -88,10 +86,9 @@ public class Context implements Extensions {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Context(Context parent, Extensions ext, Frame frame, int stackSize) {
|
||||||
private Context(Context parent, Environment environment, Frame frame, int stackSize) {
|
|
||||||
this.parent = parent;
|
this.parent = parent;
|
||||||
this.environment = environment;
|
this.extensions = ext;
|
||||||
this.frame = frame;
|
this.frame = frame;
|
||||||
this.stackSize = stackSize;
|
this.stackSize = stackSize;
|
||||||
|
|
||||||
@ -103,7 +100,16 @@ public class Context implements Extensions {
|
|||||||
public Context() {
|
public Context() {
|
||||||
this(null, null, null, 0);
|
this(null, null, null, 0);
|
||||||
}
|
}
|
||||||
public Context(Environment env) {
|
public Context(Extensions ext) {
|
||||||
this(null, env, null, 0);
|
this(null, ext, null, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Context of(Extensions ext) {
|
||||||
|
if (ext instanceof Context) return (Context)ext;
|
||||||
|
return new Context(ext);
|
||||||
|
}
|
||||||
|
public static Extensions clean(Extensions ext) {
|
||||||
|
if (ext instanceof Context) return ((Context)ext).extensions;
|
||||||
|
else return ext;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
5
src/java/me/topchetoeu/jscript/runtime/Copyable.java
Normal file
5
src/java/me/topchetoeu/jscript/runtime/Copyable.java
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
package me.topchetoeu.jscript.runtime;
|
||||||
|
|
||||||
|
public interface Copyable {
|
||||||
|
Object copy();
|
||||||
|
}
|
@ -3,11 +3,9 @@ package me.topchetoeu.jscript.runtime;
|
|||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
|
||||||
import me.topchetoeu.jscript.runtime.exceptions.EngineException;
|
import me.topchetoeu.jscript.runtime.exceptions.EngineException;
|
||||||
import me.topchetoeu.jscript.runtime.scope.GlobalScope;
|
|
||||||
import me.topchetoeu.jscript.runtime.values.FunctionValue;
|
import me.topchetoeu.jscript.runtime.values.FunctionValue;
|
||||||
import me.topchetoeu.jscript.runtime.values.NativeFunction;
|
import me.topchetoeu.jscript.runtime.values.NativeFunction;
|
||||||
import me.topchetoeu.jscript.runtime.values.ObjectValue;
|
import me.topchetoeu.jscript.runtime.values.ObjectValue;
|
||||||
import me.topchetoeu.jscript.utils.interop.NativeWrapperProvider;
|
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public class Environment implements Extensions {
|
public class Environment implements Extensions {
|
||||||
@ -31,9 +29,6 @@ public class Environment implements Extensions {
|
|||||||
|
|
||||||
private HashMap<Key<?>, Object> data = new HashMap<>();
|
private HashMap<Key<?>, Object> data = new HashMap<>();
|
||||||
|
|
||||||
public GlobalScope global;
|
|
||||||
public WrapperProvider wrappers;
|
|
||||||
|
|
||||||
@Override public <T> void add(Key<T> key, T obj) {
|
@Override public <T> void add(Key<T> key, T obj) {
|
||||||
data.put(key, obj);
|
data.put(key, obj);
|
||||||
}
|
}
|
||||||
@ -56,37 +51,11 @@ public class Environment implements Extensions {
|
|||||||
|
|
||||||
public static FunctionValue regexConstructor(Extensions ext) {
|
public static FunctionValue regexConstructor(Extensions ext) {
|
||||||
return ext.init(REGEX_CONSTR, new NativeFunction("RegExp", args -> {
|
return ext.init(REGEX_CONSTR, new NativeFunction("RegExp", args -> {
|
||||||
throw EngineException.ofError("Regular expressions not supported.").setCtx(args.ctx);
|
throw EngineException.ofError("Regular expressions not supported.").setExtensions(args.ctx);
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
public Environment copy() {
|
|
||||||
var res = new Environment();
|
|
||||||
|
|
||||||
res.wrappers = wrappers.fork(res);
|
|
||||||
res.global = global;
|
|
||||||
res.data.putAll(data);
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
public Environment child() {
|
|
||||||
var res = copy();
|
|
||||||
res.global = res.global.globalChild();
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Context context() {
|
public Context context() {
|
||||||
return new Context(this);
|
return new Context(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Environment(WrapperProvider nativeConverter, GlobalScope global) {
|
|
||||||
if (nativeConverter == null) nativeConverter = new NativeWrapperProvider();
|
|
||||||
if (global == null) global = new GlobalScope();
|
|
||||||
|
|
||||||
this.wrappers = nativeConverter;
|
|
||||||
this.global = global;
|
|
||||||
}
|
|
||||||
public Environment() {
|
|
||||||
this(null, null);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -23,15 +23,15 @@ public interface EventLoop {
|
|||||||
return pushMsg(() -> { runnable.run(); return null; }, micro);
|
return pushMsg(() -> { runnable.run(); return null; }, micro);
|
||||||
}
|
}
|
||||||
|
|
||||||
public default DataNotifier<Object> pushMsg(boolean micro, Environment env, FunctionValue func, Object thisArg, Object ...args) {
|
public default DataNotifier<Object> pushMsg(boolean micro, Extensions ext, FunctionValue func, Object thisArg, Object ...args) {
|
||||||
return pushMsg(() -> {
|
return pushMsg(() -> {
|
||||||
return func.call(new Context(env), thisArg, args);
|
return func.call(Context.of(ext), thisArg, args);
|
||||||
}, micro);
|
}, micro);
|
||||||
}
|
}
|
||||||
public default DataNotifier<Object> pushMsg(boolean micro, Environment env, Filename filename, String raw, Object thisArg, Object ...args) {
|
public default DataNotifier<Object> pushMsg(boolean micro, Extensions ext, Filename filename, String raw, Object thisArg, Object ...args) {
|
||||||
return pushMsg(() -> {
|
return pushMsg(() -> {
|
||||||
var ctx = new Context(env);
|
var ctx = Context.of(ext);
|
||||||
return ctx.compile(filename, raw).call(new Context(env), thisArg, args);
|
return ctx.compile(filename, raw).call(Context.of(ext), thisArg, args);
|
||||||
}, micro);
|
}, micro);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@ package me.topchetoeu.jscript.runtime;
|
|||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public interface Extensions {
|
public interface Extensions extends Childable, Copyable {
|
||||||
public static Extensions EMPTY = new Extensions() {
|
public static Extensions EMPTY = new Extensions() {
|
||||||
@Override public <T> void add(Key<T> key, T obj) { }
|
@Override public <T> void add(Key<T> key, T obj) { }
|
||||||
@Override public boolean remove(Key<?> key) { return false; }
|
@Override public boolean remove(Key<?> key) { return false; }
|
||||||
@ -47,6 +47,29 @@ public interface Extensions {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
default Extensions copy() {
|
||||||
|
var res = new Environment();
|
||||||
|
for (var key : keys()) {
|
||||||
|
var val = get(key);
|
||||||
|
if (val instanceof Copyable) val = ((Copyable)val).copy();
|
||||||
|
res.add((Key<Object>)key, val);
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
default Extensions child() {
|
||||||
|
var res = new Environment();
|
||||||
|
for (var key : keys()) {
|
||||||
|
var val = get(key);
|
||||||
|
if (val instanceof Childable) val = ((Childable)val).child();
|
||||||
|
res.add((Key<Object>)key, val);
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
public static Extensions wrap(Extensions ext) {
|
public static Extensions wrap(Extensions ext) {
|
||||||
if (ext == null) return EMPTY;
|
if (ext == null) return EMPTY;
|
||||||
else return ext;
|
else return ext;
|
||||||
|
@ -294,13 +294,13 @@ public class Frame {
|
|||||||
public ObjectValue getValStackScope() {
|
public ObjectValue getValStackScope() {
|
||||||
return new ObjectValue() {
|
return new ObjectValue() {
|
||||||
@Override
|
@Override
|
||||||
protected Object getField(Context ctx, Object key) {
|
protected Object getField(Extensions ext, Object key) {
|
||||||
var i = (int)Values.toNumber(ctx, key);
|
var i = (int)Values.toNumber(ext, key);
|
||||||
if (i < 0 || i >= stackPtr) return null;
|
if (i < 0 || i >= stackPtr) return null;
|
||||||
else return stack[i];
|
else return stack[i];
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
protected boolean hasField(Context ctx, Object key) {
|
protected boolean hasField(Extensions ext, Object key) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
|
@ -5,6 +5,7 @@ import java.util.Collections;
|
|||||||
import me.topchetoeu.jscript.common.Instruction;
|
import me.topchetoeu.jscript.common.Instruction;
|
||||||
import me.topchetoeu.jscript.common.Operation;
|
import me.topchetoeu.jscript.common.Operation;
|
||||||
import me.topchetoeu.jscript.runtime.exceptions.EngineException;
|
import me.topchetoeu.jscript.runtime.exceptions.EngineException;
|
||||||
|
import me.topchetoeu.jscript.runtime.scope.GlobalScope;
|
||||||
import me.topchetoeu.jscript.runtime.scope.ValueVariable;
|
import me.topchetoeu.jscript.runtime.scope.ValueVariable;
|
||||||
import me.topchetoeu.jscript.runtime.values.ArrayValue;
|
import me.topchetoeu.jscript.runtime.values.ArrayValue;
|
||||||
import me.topchetoeu.jscript.runtime.values.CodeFunction;
|
import me.topchetoeu.jscript.runtime.values.CodeFunction;
|
||||||
@ -14,43 +15,43 @@ import me.topchetoeu.jscript.runtime.values.Symbol;
|
|||||||
import me.topchetoeu.jscript.runtime.values.Values;
|
import me.topchetoeu.jscript.runtime.values.Values;
|
||||||
|
|
||||||
public class InstructionRunner {
|
public class InstructionRunner {
|
||||||
private static Object execReturn(Context ctx, Instruction instr, Frame frame) {
|
private static Object execReturn(Extensions ext, Instruction instr, Frame frame) {
|
||||||
return frame.pop();
|
return frame.pop();
|
||||||
}
|
}
|
||||||
private static Object execThrow(Context ctx, Instruction instr, Frame frame) {
|
private static Object execThrow(Extensions ext, Instruction instr, Frame frame) {
|
||||||
throw new EngineException(frame.pop());
|
throw new EngineException(frame.pop());
|
||||||
}
|
}
|
||||||
private static Object execThrowSyntax(Context ctx, Instruction instr, Frame frame) {
|
private static Object execThrowSyntax(Extensions ext, Instruction instr, Frame frame) {
|
||||||
throw EngineException.ofSyntax((String)instr.get(0));
|
throw EngineException.ofSyntax((String)instr.get(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Object execCall(Context ctx, Instruction instr, Frame frame) {
|
private static Object execCall(Extensions ext, Instruction instr, Frame frame) {
|
||||||
var callArgs = frame.take(instr.get(0));
|
var callArgs = frame.take(instr.get(0));
|
||||||
var func = frame.pop();
|
var func = frame.pop();
|
||||||
var thisArg = frame.pop();
|
var thisArg = frame.pop();
|
||||||
|
|
||||||
frame.push(Values.call(ctx, func, thisArg, callArgs));
|
frame.push(Values.call(ext, func, thisArg, callArgs));
|
||||||
|
|
||||||
frame.codePtr++;
|
frame.codePtr++;
|
||||||
return Values.NO_RETURN;
|
return Values.NO_RETURN;
|
||||||
}
|
}
|
||||||
private static Object execCallNew(Context ctx, Instruction instr, Frame frame) {
|
private static Object execCallNew(Extensions ext, Instruction instr, Frame frame) {
|
||||||
var callArgs = frame.take(instr.get(0));
|
var callArgs = frame.take(instr.get(0));
|
||||||
var funcObj = frame.pop();
|
var funcObj = frame.pop();
|
||||||
|
|
||||||
frame.push(Values.callNew(ctx, funcObj, callArgs));
|
frame.push(Values.callNew(ext, funcObj, callArgs));
|
||||||
|
|
||||||
frame.codePtr++;
|
frame.codePtr++;
|
||||||
return Values.NO_RETURN;
|
return Values.NO_RETURN;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Object execMakeVar(Context ctx, Instruction instr, Frame frame) {
|
private static Object execMakeVar(Extensions ext, Instruction instr, Frame frame) {
|
||||||
var name = (String)instr.get(0);
|
var name = (String)instr.get(0);
|
||||||
ctx.environment.global.define(ctx, name);
|
GlobalScope.get(ext).define(ext, name);
|
||||||
frame.codePtr++;
|
frame.codePtr++;
|
||||||
return Values.NO_RETURN;
|
return Values.NO_RETURN;
|
||||||
}
|
}
|
||||||
private static Object execDefProp(Context ctx, Instruction instr, Frame frame) {
|
private static Object execDefProp(Extensions ext, Instruction instr, Frame frame) {
|
||||||
var setter = frame.pop();
|
var setter = frame.pop();
|
||||||
var getter = frame.pop();
|
var getter = frame.pop();
|
||||||
var name = frame.pop();
|
var name = frame.pop();
|
||||||
@ -59,16 +60,16 @@ public class InstructionRunner {
|
|||||||
if (getter != null && !(getter instanceof FunctionValue)) throw EngineException.ofType("Getter must be a function or undefined.");
|
if (getter != null && !(getter instanceof FunctionValue)) throw EngineException.ofType("Getter must be a function or undefined.");
|
||||||
if (setter != null && !(setter instanceof FunctionValue)) throw EngineException.ofType("Setter must be a function or undefined.");
|
if (setter != null && !(setter instanceof FunctionValue)) throw EngineException.ofType("Setter must be a function or undefined.");
|
||||||
if (!(obj instanceof ObjectValue)) throw EngineException.ofType("Property apply target must be an object.");
|
if (!(obj instanceof ObjectValue)) throw EngineException.ofType("Property apply target must be an object.");
|
||||||
((ObjectValue)obj).defineProperty(ctx, name, (FunctionValue)getter, (FunctionValue)setter, false, false);
|
((ObjectValue)obj).defineProperty(ext, name, (FunctionValue)getter, (FunctionValue)setter, false, false);
|
||||||
|
|
||||||
frame.push(obj);
|
frame.push(obj);
|
||||||
frame.codePtr++;
|
frame.codePtr++;
|
||||||
return Values.NO_RETURN;
|
return Values.NO_RETURN;
|
||||||
}
|
}
|
||||||
private static Object execKeys(Context ctx, Instruction instr, Frame frame) {
|
private static Object execKeys(Extensions ext, Instruction instr, Frame frame) {
|
||||||
var val = frame.pop();
|
var val = frame.pop();
|
||||||
|
|
||||||
var members = Values.getMembers(ctx, val, false, false);
|
var members = Values.getMembers(ext, val, false, false);
|
||||||
Collections.reverse(members);
|
Collections.reverse(members);
|
||||||
|
|
||||||
frame.push(null);
|
frame.push(null);
|
||||||
@ -76,7 +77,7 @@ public class InstructionRunner {
|
|||||||
for (var el : members) {
|
for (var el : members) {
|
||||||
if (el instanceof Symbol) continue;
|
if (el instanceof Symbol) continue;
|
||||||
var obj = new ObjectValue();
|
var obj = new ObjectValue();
|
||||||
obj.defineProperty(ctx, "value", el);
|
obj.defineProperty(ext, "value", el);
|
||||||
frame.push(obj);
|
frame.push(obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -84,7 +85,7 @@ public class InstructionRunner {
|
|||||||
return Values.NO_RETURN;
|
return Values.NO_RETURN;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Object execTryStart(Context ctx, Instruction instr, Frame frame) {
|
private static Object execTryStart(Extensions ext, Instruction instr, Frame frame) {
|
||||||
int start = frame.codePtr + 1;
|
int start = frame.codePtr + 1;
|
||||||
int catchStart = (int)instr.get(0);
|
int catchStart = (int)instr.get(0);
|
||||||
int finallyStart = (int)instr.get(1);
|
int finallyStart = (int)instr.get(1);
|
||||||
@ -95,12 +96,12 @@ public class InstructionRunner {
|
|||||||
frame.codePtr++;
|
frame.codePtr++;
|
||||||
return Values.NO_RETURN;
|
return Values.NO_RETURN;
|
||||||
}
|
}
|
||||||
private static Object execTryEnd(Context ctx, Instruction instr, Frame frame) {
|
private static Object execTryEnd(Extensions ext, Instruction instr, Frame frame) {
|
||||||
frame.popTryFlag = true;
|
frame.popTryFlag = true;
|
||||||
return Values.NO_RETURN;
|
return Values.NO_RETURN;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Object execDup(Context ctx, Instruction instr, Frame frame) {
|
private static Object execDup(Extensions ext, Instruction instr, Frame frame) {
|
||||||
int count = instr.get(0);
|
int count = instr.get(0);
|
||||||
|
|
||||||
for (var i = 0; i < count; i++) {
|
for (var i = 0; i < count; i++) {
|
||||||
@ -110,7 +111,7 @@ public class InstructionRunner {
|
|||||||
frame.codePtr++;
|
frame.codePtr++;
|
||||||
return Values.NO_RETURN;
|
return Values.NO_RETURN;
|
||||||
}
|
}
|
||||||
private static Object execLoadValue(Context ctx, Instruction instr, Frame frame) {
|
private static Object execLoadValue(Extensions ext, Instruction instr, Frame frame) {
|
||||||
switch (instr.type) {
|
switch (instr.type) {
|
||||||
case PUSH_UNDEFINED: frame.push(null); break;
|
case PUSH_UNDEFINED: frame.push(null); break;
|
||||||
case PUSH_NULL: frame.push(Values.NULL); break;
|
case PUSH_NULL: frame.push(Values.NULL); break;
|
||||||
@ -120,33 +121,33 @@ public class InstructionRunner {
|
|||||||
frame.codePtr++;
|
frame.codePtr++;
|
||||||
return Values.NO_RETURN;
|
return Values.NO_RETURN;
|
||||||
}
|
}
|
||||||
private static Object execLoadVar(Context ctx, Instruction instr, Frame frame) {
|
private static Object execLoadVar(Extensions ext, Instruction instr, Frame frame) {
|
||||||
var i = instr.get(0);
|
var i = instr.get(0);
|
||||||
|
|
||||||
if (i instanceof String) frame.push(ctx.environment.global.get(ctx, (String)i));
|
if (i instanceof String) frame.push(GlobalScope.get(ext).get(ext, (String)i));
|
||||||
else frame.push(frame.scope.get((int)i).get(ctx));
|
else frame.push(frame.scope.get((int)i).get(ext));
|
||||||
|
|
||||||
frame.codePtr++;
|
frame.codePtr++;
|
||||||
return Values.NO_RETURN;
|
return Values.NO_RETURN;
|
||||||
}
|
}
|
||||||
private static Object execLoadObj(Context ctx, Instruction instr, Frame frame) {
|
private static Object execLoadObj(Extensions ext, Instruction instr, Frame frame) {
|
||||||
frame.push(new ObjectValue());
|
frame.push(new ObjectValue());
|
||||||
frame.codePtr++;
|
frame.codePtr++;
|
||||||
return Values.NO_RETURN;
|
return Values.NO_RETURN;
|
||||||
}
|
}
|
||||||
private static Object execLoadGlob(Context ctx, Instruction instr, Frame frame) {
|
private static Object execLoadGlob(Extensions ext, Instruction instr, Frame frame) {
|
||||||
frame.push(ctx.environment.global.obj);
|
frame.push(GlobalScope.get(ext).obj);
|
||||||
frame.codePtr++;
|
frame.codePtr++;
|
||||||
return Values.NO_RETURN;
|
return Values.NO_RETURN;
|
||||||
}
|
}
|
||||||
private static Object execLoadArr(Context ctx, Instruction instr, Frame frame) {
|
private static Object execLoadArr(Extensions ext, Instruction instr, Frame frame) {
|
||||||
var res = new ArrayValue();
|
var res = new ArrayValue();
|
||||||
res.setSize(instr.get(0));
|
res.setSize(instr.get(0));
|
||||||
frame.push(res);
|
frame.push(res);
|
||||||
frame.codePtr++;
|
frame.codePtr++;
|
||||||
return Values.NO_RETURN;
|
return Values.NO_RETURN;
|
||||||
}
|
}
|
||||||
private static Object execLoadFunc(Context ctx, Instruction instr, Frame frame) {
|
private static Object execLoadFunc(Extensions ext, Instruction instr, Frame frame) {
|
||||||
int id = instr.get(0);
|
int id = instr.get(0);
|
||||||
var captures = new ValueVariable[instr.params.length - 1];
|
var captures = new ValueVariable[instr.params.length - 1];
|
||||||
|
|
||||||
@ -154,19 +155,19 @@ public class InstructionRunner {
|
|||||||
captures[i - 1] = frame.scope.get(instr.get(i));
|
captures[i - 1] = frame.scope.get(instr.get(i));
|
||||||
}
|
}
|
||||||
|
|
||||||
var func = new CodeFunction(ctx.environment, "", frame.function.body.children[id], captures);
|
var func = new CodeFunction(ext, "", frame.function.body.children[id], captures);
|
||||||
|
|
||||||
frame.push(func);
|
frame.push(func);
|
||||||
|
|
||||||
frame.codePtr++;
|
frame.codePtr++;
|
||||||
return Values.NO_RETURN;
|
return Values.NO_RETURN;
|
||||||
}
|
}
|
||||||
private static Object execLoadMember(Context ctx, Instruction instr, Frame frame) {
|
private static Object execLoadMember(Extensions ext, Instruction instr, Frame frame) {
|
||||||
var key = frame.pop();
|
var key = frame.pop();
|
||||||
var obj = frame.pop();
|
var obj = frame.pop();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
frame.push(Values.getMember(ctx, obj, key));
|
frame.push(Values.getMember(ext, obj, key));
|
||||||
}
|
}
|
||||||
catch (IllegalArgumentException e) {
|
catch (IllegalArgumentException e) {
|
||||||
throw EngineException.ofType(e.getMessage());
|
throw EngineException.ofType(e.getMessage());
|
||||||
@ -174,9 +175,9 @@ public class InstructionRunner {
|
|||||||
frame.codePtr++;
|
frame.codePtr++;
|
||||||
return Values.NO_RETURN;
|
return Values.NO_RETURN;
|
||||||
}
|
}
|
||||||
private static Object execLoadRegEx(Context ctx, Instruction instr, Frame frame) {
|
private static Object execLoadRegEx(Extensions ext, Instruction instr, Frame frame) {
|
||||||
if (ctx.hasNotNull(Environment.REGEX_CONSTR)) {
|
if (ext.hasNotNull(Environment.REGEX_CONSTR)) {
|
||||||
frame.push(Values.callNew(ctx, ctx.get(Environment.REGEX_CONSTR), instr.get(0), instr.get(1)));
|
frame.push(Values.callNew(ext, ext.get(Environment.REGEX_CONSTR), instr.get(0), instr.get(1)));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
throw EngineException.ofSyntax("Regex is not supported.");
|
throw EngineException.ofSyntax("Regex is not supported.");
|
||||||
@ -185,43 +186,43 @@ public class InstructionRunner {
|
|||||||
return Values.NO_RETURN;
|
return Values.NO_RETURN;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Object execDiscard(Context ctx, Instruction instr, Frame frame) {
|
private static Object execDiscard(Extensions ext, Instruction instr, Frame frame) {
|
||||||
frame.pop();
|
frame.pop();
|
||||||
frame.codePtr++;
|
frame.codePtr++;
|
||||||
return Values.NO_RETURN;
|
return Values.NO_RETURN;
|
||||||
}
|
}
|
||||||
private static Object execStoreMember(Context ctx, Instruction instr, Frame frame) {
|
private static Object execStoreMember(Extensions ext, Instruction instr, Frame frame) {
|
||||||
var val = frame.pop();
|
var val = frame.pop();
|
||||||
var key = frame.pop();
|
var key = frame.pop();
|
||||||
var obj = frame.pop();
|
var obj = frame.pop();
|
||||||
|
|
||||||
if (!Values.setMember(ctx, obj, key, val)) throw EngineException.ofSyntax("Can't set member '" + key + "'.");
|
if (!Values.setMember(ext, obj, key, val)) throw EngineException.ofSyntax("Can't set member '" + key + "'.");
|
||||||
if ((boolean)instr.get(0)) frame.push(val);
|
if ((boolean)instr.get(0)) frame.push(val);
|
||||||
frame.codePtr++;
|
frame.codePtr++;
|
||||||
return Values.NO_RETURN;
|
return Values.NO_RETURN;
|
||||||
}
|
}
|
||||||
private static Object execStoreVar(Context ctx, Instruction instr, Frame frame) {
|
private static Object execStoreVar(Extensions ext, Instruction instr, Frame frame) {
|
||||||
var val = (boolean)instr.get(1) ? frame.peek() : frame.pop();
|
var val = (boolean)instr.get(1) ? frame.peek() : frame.pop();
|
||||||
var i = instr.get(0);
|
var i = instr.get(0);
|
||||||
|
|
||||||
if (i instanceof String) ctx.environment.global.set(ctx, (String)i, val);
|
if (i instanceof String) GlobalScope.get(ext).set(ext, (String)i, val);
|
||||||
else frame.scope.get((int)i).set(ctx, val);
|
else frame.scope.get((int)i).set(ext, val);
|
||||||
|
|
||||||
frame.codePtr++;
|
frame.codePtr++;
|
||||||
return Values.NO_RETURN;
|
return Values.NO_RETURN;
|
||||||
}
|
}
|
||||||
private static Object execStoreSelfFunc(Context ctx, Instruction instr, Frame frame) {
|
private static Object execStoreSelfFunc(Extensions ext, Instruction instr, Frame frame) {
|
||||||
frame.scope.locals[(int)instr.get(0)].set(ctx, frame.function);
|
frame.scope.locals[(int)instr.get(0)].set(ext, frame.function);
|
||||||
frame.codePtr++;
|
frame.codePtr++;
|
||||||
return Values.NO_RETURN;
|
return Values.NO_RETURN;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Object execJmp(Context ctx, Instruction instr, Frame frame) {
|
private static Object execJmp(Extensions ext, Instruction instr, Frame frame) {
|
||||||
frame.codePtr += (int)instr.get(0);
|
frame.codePtr += (int)instr.get(0);
|
||||||
frame.jumpFlag = true;
|
frame.jumpFlag = true;
|
||||||
return Values.NO_RETURN;
|
return Values.NO_RETURN;
|
||||||
}
|
}
|
||||||
private static Object execJmpIf(Context ctx, Instruction instr, Frame frame) {
|
private static Object execJmpIf(Extensions ext, Instruction instr, Frame frame) {
|
||||||
if (Values.toBoolean(frame.pop())) {
|
if (Values.toBoolean(frame.pop())) {
|
||||||
frame.codePtr += (int)instr.get(0);
|
frame.codePtr += (int)instr.get(0);
|
||||||
frame.jumpFlag = true;
|
frame.jumpFlag = true;
|
||||||
@ -229,7 +230,7 @@ public class InstructionRunner {
|
|||||||
else frame.codePtr ++;
|
else frame.codePtr ++;
|
||||||
return Values.NO_RETURN;
|
return Values.NO_RETURN;
|
||||||
}
|
}
|
||||||
private static Object execJmpIfNot(Context ctx, Instruction instr, Frame frame) {
|
private static Object execJmpIfNot(Extensions ext, Instruction instr, Frame frame) {
|
||||||
if (Values.not(frame.pop())) {
|
if (Values.not(frame.pop())) {
|
||||||
frame.codePtr += (int)instr.get(0);
|
frame.codePtr += (int)instr.get(0);
|
||||||
frame.jumpFlag = true;
|
frame.jumpFlag = true;
|
||||||
@ -238,13 +239,13 @@ public class InstructionRunner {
|
|||||||
return Values.NO_RETURN;
|
return Values.NO_RETURN;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Object execTypeof(Context ctx, Instruction instr, Frame frame) {
|
private static Object execTypeof(Extensions ext, Instruction instr, Frame frame) {
|
||||||
String name = instr.get(0);
|
String name = instr.get(0);
|
||||||
Object obj;
|
Object obj;
|
||||||
|
|
||||||
if (name != null) {
|
if (name != null) {
|
||||||
if (ctx.environment.global.has(ctx, name)) {
|
if (GlobalScope.get(ext).has(ext, name)) {
|
||||||
obj = ctx.environment.global.get(ctx, name);
|
obj = GlobalScope.get(ext).get(ext, name);
|
||||||
}
|
}
|
||||||
else obj = null;
|
else obj = null;
|
||||||
}
|
}
|
||||||
@ -255,73 +256,73 @@ public class InstructionRunner {
|
|||||||
frame.codePtr++;
|
frame.codePtr++;
|
||||||
return Values.NO_RETURN;
|
return Values.NO_RETURN;
|
||||||
}
|
}
|
||||||
private static Object execNop(Context ctx, Instruction instr, Frame frame) {
|
private static Object execNop(Extensions ext, Instruction instr, Frame frame) {
|
||||||
frame.codePtr++;
|
frame.codePtr++;
|
||||||
return Values.NO_RETURN;
|
return Values.NO_RETURN;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Object execDelete(Context ctx, Instruction instr, Frame frame) {
|
private static Object execDelete(Extensions ext, Instruction instr, Frame frame) {
|
||||||
var key = frame.pop();
|
var key = frame.pop();
|
||||||
var val = frame.pop();
|
var val = frame.pop();
|
||||||
|
|
||||||
if (!Values.deleteMember(ctx, val, key)) throw EngineException.ofSyntax("Can't delete member '" + key + "'.");
|
if (!Values.deleteMember(ext, val, key)) throw EngineException.ofSyntax("Can't delete member '" + key + "'.");
|
||||||
frame.codePtr++;
|
frame.codePtr++;
|
||||||
return Values.NO_RETURN;
|
return Values.NO_RETURN;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Object execOperation(Context ctx, Instruction instr, Frame frame) {
|
private static Object execOperation(Extensions ext, Instruction instr, Frame frame) {
|
||||||
Operation op = instr.get(0);
|
Operation op = instr.get(0);
|
||||||
var args = new Object[op.operands];
|
var args = new Object[op.operands];
|
||||||
|
|
||||||
for (var i = op.operands - 1; i >= 0; i--) args[i] = frame.pop();
|
for (var i = op.operands - 1; i >= 0; i--) args[i] = frame.pop();
|
||||||
|
|
||||||
frame.push(Values.operation(ctx, op, args));
|
frame.push(Values.operation(ext, op, args));
|
||||||
frame.codePtr++;
|
frame.codePtr++;
|
||||||
return Values.NO_RETURN;
|
return Values.NO_RETURN;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Object exec(Context ctx, Instruction instr, Frame frame) {
|
public static Object exec(Extensions ext, Instruction instr, Frame frame) {
|
||||||
switch (instr.type) {
|
switch (instr.type) {
|
||||||
case NOP: return execNop(ctx, instr, frame);
|
case NOP: return execNop(ext, instr, frame);
|
||||||
case RETURN: return execReturn(ctx, instr, frame);
|
case RETURN: return execReturn(ext, instr, frame);
|
||||||
case THROW: return execThrow(ctx, instr, frame);
|
case THROW: return execThrow(ext, instr, frame);
|
||||||
case THROW_SYNTAX: return execThrowSyntax(ctx, instr, frame);
|
case THROW_SYNTAX: return execThrowSyntax(ext, instr, frame);
|
||||||
case CALL: return execCall(ctx, instr, frame);
|
case CALL: return execCall(ext, instr, frame);
|
||||||
case CALL_NEW: return execCallNew(ctx, instr, frame);
|
case CALL_NEW: return execCallNew(ext, instr, frame);
|
||||||
case TRY_START: return execTryStart(ctx, instr, frame);
|
case TRY_START: return execTryStart(ext, instr, frame);
|
||||||
case TRY_END: return execTryEnd(ctx, instr, frame);
|
case TRY_END: return execTryEnd(ext, instr, frame);
|
||||||
|
|
||||||
case DUP: return execDup(ctx, instr, frame);
|
case DUP: return execDup(ext, instr, frame);
|
||||||
case PUSH_UNDEFINED:
|
case PUSH_UNDEFINED:
|
||||||
case PUSH_NULL:
|
case PUSH_NULL:
|
||||||
case PUSH_STRING:
|
case PUSH_STRING:
|
||||||
case PUSH_NUMBER:
|
case PUSH_NUMBER:
|
||||||
case PUSH_BOOL:
|
case PUSH_BOOL:
|
||||||
return execLoadValue(ctx, instr, frame);
|
return execLoadValue(ext, instr, frame);
|
||||||
case LOAD_VAR: return execLoadVar(ctx, instr, frame);
|
case LOAD_VAR: return execLoadVar(ext, instr, frame);
|
||||||
case LOAD_OBJ: return execLoadObj(ctx, instr, frame);
|
case LOAD_OBJ: return execLoadObj(ext, instr, frame);
|
||||||
case LOAD_ARR: return execLoadArr(ctx, instr, frame);
|
case LOAD_ARR: return execLoadArr(ext, instr, frame);
|
||||||
case LOAD_FUNC: return execLoadFunc(ctx, instr, frame);
|
case LOAD_FUNC: return execLoadFunc(ext, instr, frame);
|
||||||
case LOAD_MEMBER: return execLoadMember(ctx, instr, frame);
|
case LOAD_MEMBER: return execLoadMember(ext, instr, frame);
|
||||||
case LOAD_REGEX: return execLoadRegEx(ctx, instr, frame);
|
case LOAD_REGEX: return execLoadRegEx(ext, instr, frame);
|
||||||
case LOAD_GLOB: return execLoadGlob(ctx, instr, frame);
|
case LOAD_GLOB: return execLoadGlob(ext, instr, frame);
|
||||||
|
|
||||||
case DISCARD: return execDiscard(ctx, instr, frame);
|
case DISCARD: return execDiscard(ext, instr, frame);
|
||||||
case STORE_MEMBER: return execStoreMember(ctx, instr, frame);
|
case STORE_MEMBER: return execStoreMember(ext, instr, frame);
|
||||||
case STORE_VAR: return execStoreVar(ctx, instr, frame);
|
case STORE_VAR: return execStoreVar(ext, instr, frame);
|
||||||
case STORE_SELF_FUNC: return execStoreSelfFunc(ctx, instr, frame);
|
case STORE_SELF_FUNC: return execStoreSelfFunc(ext, instr, frame);
|
||||||
case MAKE_VAR: return execMakeVar(ctx, instr, frame);
|
case MAKE_VAR: return execMakeVar(ext, instr, frame);
|
||||||
|
|
||||||
case KEYS: return execKeys(ctx, instr, frame);
|
case KEYS: return execKeys(ext, instr, frame);
|
||||||
case DEF_PROP: return execDefProp(ctx, instr, frame);
|
case DEF_PROP: return execDefProp(ext, instr, frame);
|
||||||
case TYPEOF: return execTypeof(ctx, instr, frame);
|
case TYPEOF: return execTypeof(ext, instr, frame);
|
||||||
case DELETE: return execDelete(ctx, instr, frame);
|
case DELETE: return execDelete(ext, instr, frame);
|
||||||
|
|
||||||
case JMP: return execJmp(ctx, instr, frame);
|
case JMP: return execJmp(ext, instr, frame);
|
||||||
case JMP_IF: return execJmpIf(ctx, instr, frame);
|
case JMP_IF: return execJmpIf(ext, instr, frame);
|
||||||
case JMP_IFN: return execJmpIfNot(ctx, instr, frame);
|
case JMP_IFN: return execJmpIfNot(ext, instr, frame);
|
||||||
|
|
||||||
case OPERATION: return execOperation(ctx, instr, frame);
|
case OPERATION: return execOperation(ext, instr, frame);
|
||||||
|
|
||||||
default: throw EngineException.ofSyntax("Invalid instruction " + instr.type.name() + ".");
|
default: throw EngineException.ofSyntax("Invalid instruction " + instr.type.name() + ".");
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,7 @@ import java.util.List;
|
|||||||
import me.topchetoeu.jscript.common.Location;
|
import me.topchetoeu.jscript.common.Location;
|
||||||
import me.topchetoeu.jscript.runtime.Context;
|
import me.topchetoeu.jscript.runtime.Context;
|
||||||
import me.topchetoeu.jscript.runtime.Environment;
|
import me.topchetoeu.jscript.runtime.Environment;
|
||||||
|
import me.topchetoeu.jscript.runtime.Extensions;
|
||||||
import me.topchetoeu.jscript.runtime.values.ObjectValue;
|
import me.topchetoeu.jscript.runtime.values.ObjectValue;
|
||||||
import me.topchetoeu.jscript.runtime.values.Values;
|
import me.topchetoeu.jscript.runtime.values.Values;
|
||||||
import me.topchetoeu.jscript.runtime.values.ObjectValue.PlaceholderProto;
|
import me.topchetoeu.jscript.runtime.values.ObjectValue.PlaceholderProto;
|
||||||
@ -14,10 +15,10 @@ public class EngineException extends RuntimeException {
|
|||||||
public static class StackElement {
|
public static class StackElement {
|
||||||
public final Location location;
|
public final Location location;
|
||||||
public final String name;
|
public final String name;
|
||||||
public final Context ctx;
|
public final Extensions ext;
|
||||||
|
|
||||||
public boolean visible() {
|
public boolean visible() {
|
||||||
return ctx == null || !ctx.get(Environment.HIDE_STACK, false);
|
return ext == null || !ext.get(Environment.HIDE_STACK, false);
|
||||||
}
|
}
|
||||||
public String toString() {
|
public String toString() {
|
||||||
var res = "";
|
var res = "";
|
||||||
@ -29,12 +30,13 @@ public class EngineException extends RuntimeException {
|
|||||||
return res.trim();
|
return res.trim();
|
||||||
}
|
}
|
||||||
|
|
||||||
public StackElement(Context ctx, Location location, String name) {
|
public StackElement(Extensions ext, Location location, String name) {
|
||||||
if (name != null) name = name.trim();
|
if (name != null) name = name.trim();
|
||||||
if (name.equals("")) name = null;
|
if (name.equals("")) name = null;
|
||||||
|
|
||||||
if (ctx == null) this.ctx = null;
|
if (ext == null) this.ext = null;
|
||||||
else this.ctx = new Context(ctx.environment);
|
else this.ext = Context.clean(ext);
|
||||||
|
|
||||||
this.location = location;
|
this.location = location;
|
||||||
this.name = name;
|
this.name = name;
|
||||||
}
|
}
|
||||||
@ -42,13 +44,13 @@ public class EngineException extends RuntimeException {
|
|||||||
|
|
||||||
public final Object value;
|
public final Object value;
|
||||||
public EngineException cause;
|
public EngineException cause;
|
||||||
public Environment env = null;
|
public Extensions ext = null;
|
||||||
public final List<StackElement> stackTrace = new ArrayList<>();
|
public final List<StackElement> stackTrace = new ArrayList<>();
|
||||||
|
|
||||||
public EngineException add(Context ctx, String name, Location location) {
|
public EngineException add(Extensions ext, String name, Location location) {
|
||||||
var el = new StackElement(ctx, location, name);
|
var el = new StackElement(ext, location, name);
|
||||||
if (el.name == null && el.location == null) return this;
|
if (el.name == null && el.location == null) return this;
|
||||||
setCtx(ctx);
|
setExtensions(ext);
|
||||||
stackTrace.add(el);
|
stackTrace.add(el);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
@ -56,15 +58,15 @@ public class EngineException extends RuntimeException {
|
|||||||
this.cause = cause;
|
this.cause = cause;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
public EngineException setCtx(Context ctx) {
|
public EngineException setExtensions(Extensions ext) {
|
||||||
if (this.env == null) this.env = ctx.environment;
|
if (this.ext == null) this.ext = Context.clean(ext);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String toString(Context ctx) {
|
public String toString(Extensions ext) {
|
||||||
var ss = new StringBuilder();
|
var ss = new StringBuilder();
|
||||||
try {
|
try {
|
||||||
ss.append(Values.toString(ctx, value)).append('\n');
|
ss.append(Values.toString(ext, value)).append('\n');
|
||||||
}
|
}
|
||||||
catch (EngineException e) {
|
catch (EngineException e) {
|
||||||
ss.append("[Error while stringifying]\n");
|
ss.append("[Error while stringifying]\n");
|
||||||
@ -72,7 +74,7 @@ public class EngineException extends RuntimeException {
|
|||||||
for (var line : stackTrace) {
|
for (var line : stackTrace) {
|
||||||
if (line.visible()) ss.append(" ").append(line.toString()).append("\n");
|
if (line.visible()) ss.append(" ").append(line.toString()).append("\n");
|
||||||
}
|
}
|
||||||
if (cause != null) ss.append("Caused by ").append(cause.toString(ctx)).append('\n');
|
if (cause != null) ss.append("Caused by ").append(cause.toString(ext)).append('\n');
|
||||||
ss.deleteCharAt(ss.length() - 1);
|
ss.deleteCharAt(ss.length() - 1);
|
||||||
return ss.toString();
|
return ss.toString();
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,8 @@ package me.topchetoeu.jscript.runtime.scope;
|
|||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import me.topchetoeu.jscript.runtime.Context;
|
import me.topchetoeu.jscript.runtime.Extensions;
|
||||||
|
import me.topchetoeu.jscript.runtime.Key;
|
||||||
import me.topchetoeu.jscript.runtime.exceptions.EngineException;
|
import me.topchetoeu.jscript.runtime.exceptions.EngineException;
|
||||||
import me.topchetoeu.jscript.runtime.values.FunctionValue;
|
import me.topchetoeu.jscript.runtime.values.FunctionValue;
|
||||||
import me.topchetoeu.jscript.runtime.values.NativeFunction;
|
import me.topchetoeu.jscript.runtime.values.NativeFunction;
|
||||||
@ -11,10 +12,12 @@ import me.topchetoeu.jscript.runtime.values.ObjectValue;
|
|||||||
import me.topchetoeu.jscript.runtime.values.Values;
|
import me.topchetoeu.jscript.runtime.values.Values;
|
||||||
|
|
||||||
public class GlobalScope {
|
public class GlobalScope {
|
||||||
|
public static final Key<GlobalScope> KEY = new Key<>();
|
||||||
|
|
||||||
public final ObjectValue obj;
|
public final ObjectValue obj;
|
||||||
|
|
||||||
public boolean has(Context ctx, String name) {
|
public boolean has(Extensions ext, String name) {
|
||||||
return Values.hasMember(null, obj, name, false);
|
return Values.hasMember(ext, obj, name, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public GlobalScope globalChild() {
|
public GlobalScope globalChild() {
|
||||||
@ -23,35 +26,35 @@ public class GlobalScope {
|
|||||||
return new GlobalScope(obj);
|
return new GlobalScope(obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Object define(Context ctx, String name) {
|
public Object define(Extensions ext, String name) {
|
||||||
if (Values.hasMember(ctx, obj, name, false)) return name;
|
if (Values.hasMember(ext, obj, name, false)) return name;
|
||||||
obj.defineProperty(ctx, name, null);
|
obj.defineProperty(ext, name, null);
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
public void define(Context ctx, String name, Variable val) {
|
public void define(Extensions ext, String name, Variable val) {
|
||||||
obj.defineProperty(ctx, name,
|
obj.defineProperty(ext, name,
|
||||||
new NativeFunction("get " + name, args -> val.get(args.ctx)),
|
new NativeFunction("get " + name, args -> val.get(args.ctx)),
|
||||||
new NativeFunction("set " + name, args -> { val.set(args.ctx, args.get(0)); return null; }),
|
new NativeFunction("set " + name, args -> { val.set(args.ctx, args.get(0)); return null; }),
|
||||||
true, true
|
true, true
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
public void define(Context ctx, String name, boolean readonly, Object val) {
|
public void define(Extensions ext, String name, boolean readonly, Object val) {
|
||||||
obj.defineProperty(ctx, name, val, readonly, true, true);
|
obj.defineProperty(ext, name, val, readonly, true, true);
|
||||||
}
|
}
|
||||||
public void define(Context ctx, String ...names) {
|
public void define(Extensions ext, String ...names) {
|
||||||
for (var n : names) define(ctx, n);
|
for (var n : names) define(ext, n);
|
||||||
}
|
}
|
||||||
public void define(Context ctx, boolean readonly, FunctionValue val) {
|
public void define(Extensions ext, boolean readonly, FunctionValue val) {
|
||||||
define(ctx, val.name, readonly, val);
|
define(ext, val.name, readonly, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Object get(Context ctx, String name) {
|
public Object get(Extensions ext, String name) {
|
||||||
if (!Values.hasMember(ctx, obj, name, false)) throw EngineException.ofSyntax("The variable '" + name + "' doesn't exist.");
|
if (!Values.hasMember(ext, obj, name, false)) throw EngineException.ofSyntax("The variable '" + name + "' doesn't exist.");
|
||||||
else return Values.getMember(ctx, obj, name);
|
else return Values.getMember(ext, obj, name);
|
||||||
}
|
}
|
||||||
public void set(Context ctx, String name, Object val) {
|
public void set(Extensions ext, String name, Object val) {
|
||||||
if (!Values.hasMember(ctx, obj, name, false)) throw EngineException.ofSyntax("The variable '" + name + "' doesn't exist.");
|
if (!Values.hasMember(ext, obj, name, false)) throw EngineException.ofSyntax("The variable '" + name + "' doesn't exist.");
|
||||||
if (!Values.setMember(ctx, obj, name, val)) throw EngineException.ofSyntax("The global '" + name + "' is readonly.");
|
if (!Values.setMember(ext, obj, name, val)) throw EngineException.ofSyntax("The global '" + name + "' is readonly.");
|
||||||
}
|
}
|
||||||
|
|
||||||
public Set<String> keys() {
|
public Set<String> keys() {
|
||||||
@ -70,4 +73,9 @@ public class GlobalScope {
|
|||||||
public GlobalScope(ObjectValue val) {
|
public GlobalScope(ObjectValue val) {
|
||||||
this.obj = val;
|
this.obj = val;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static GlobalScope get(Extensions ext) {
|
||||||
|
if (ext.has(KEY)) return ext.get(KEY);
|
||||||
|
else return new GlobalScope();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
package me.topchetoeu.jscript.runtime.scope;
|
package me.topchetoeu.jscript.runtime.scope;
|
||||||
|
|
||||||
import me.topchetoeu.jscript.runtime.Context;
|
import me.topchetoeu.jscript.runtime.Extensions;
|
||||||
import me.topchetoeu.jscript.runtime.values.Values;
|
import me.topchetoeu.jscript.runtime.values.Values;
|
||||||
|
|
||||||
public class ValueVariable implements Variable {
|
public class ValueVariable implements Variable {
|
||||||
@ -11,14 +11,14 @@ public class ValueVariable implements Variable {
|
|||||||
public boolean readonly() { return readonly; }
|
public boolean readonly() { return readonly; }
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object get(Context ctx) {
|
public Object get(Extensions ext) {
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void set(Context ctx, Object val) {
|
public void set(Extensions ext, Object val) {
|
||||||
if (readonly) return;
|
if (readonly) return;
|
||||||
this.value = Values.normalize(ctx, val);
|
this.value = Values.normalize(ext, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ValueVariable(boolean readonly, Object val) {
|
public ValueVariable(boolean readonly, Object val) {
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
package me.topchetoeu.jscript.runtime.scope;
|
package me.topchetoeu.jscript.runtime.scope;
|
||||||
|
|
||||||
import me.topchetoeu.jscript.runtime.Context;
|
import me.topchetoeu.jscript.runtime.Extensions;
|
||||||
|
|
||||||
public interface Variable {
|
public interface Variable {
|
||||||
Object get(Context ctx);
|
Object get(Extensions ext);
|
||||||
default boolean readonly() { return true; }
|
default boolean readonly() { return true; }
|
||||||
default void set(Context ctx, Object val) { }
|
default void set(Extensions ext, Object val) { }
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,7 @@ import java.util.Comparator;
|
|||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import me.topchetoeu.jscript.runtime.Context;
|
import me.topchetoeu.jscript.runtime.Extensions;
|
||||||
|
|
||||||
// TODO: Make methods generic
|
// TODO: Make methods generic
|
||||||
public class ArrayValue extends ObjectValue implements Iterable<Object> {
|
public class ArrayValue extends ObjectValue implements Iterable<Object> {
|
||||||
@ -41,12 +41,12 @@ public class ArrayValue extends ObjectValue implements Iterable<Object> {
|
|||||||
if (res == UNDEFINED) return null;
|
if (res == UNDEFINED) return null;
|
||||||
else return res;
|
else return res;
|
||||||
}
|
}
|
||||||
public void set(Context ctx, int i, Object val) {
|
public void set(Extensions ext, int i, Object val) {
|
||||||
if (i < 0) return;
|
if (i < 0) return;
|
||||||
|
|
||||||
values = alloc(i);
|
values = alloc(i);
|
||||||
|
|
||||||
val = Values.normalize(ctx, val);
|
val = Values.normalize(ext, val);
|
||||||
if (val == null) val = UNDEFINED;
|
if (val == null) val = UNDEFINED;
|
||||||
values[i] = val;
|
values[i] = val;
|
||||||
if (i >= size) size = i + 1;
|
if (i >= size) size = i + 1;
|
||||||
@ -99,9 +99,9 @@ public class ArrayValue extends ObjectValue implements Iterable<Object> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void copyFrom(Context ctx, Object[] arr, int sourceStart, int destStart, int count) {
|
public void copyFrom(Extensions ext, Object[] arr, int sourceStart, int destStart, int count) {
|
||||||
for (var i = 0; i < count; i++) {
|
for (var i = 0; i < count; i++) {
|
||||||
set(ctx, i + destStart, arr[i + sourceStart]);
|
set(ext, i + destStart, arr[i + sourceStart]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -131,7 +131,7 @@ public class ArrayValue extends ObjectValue implements Iterable<Object> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Object getField(Context ctx, Object key) {
|
protected Object getField(Extensions ext, Object key) {
|
||||||
if (key instanceof Number) {
|
if (key instanceof Number) {
|
||||||
var i = ((Number)key).doubleValue();
|
var i = ((Number)key).doubleValue();
|
||||||
if (i >= 0 && i - Math.floor(i) == 0) {
|
if (i >= 0 && i - Math.floor(i) == 0) {
|
||||||
@ -139,22 +139,22 @@ public class ArrayValue extends ObjectValue implements Iterable<Object> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return super.getField(ctx, key);
|
return super.getField(ext, key);
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
protected boolean setField(Context ctx, Object key, Object val) {
|
protected boolean setField(Extensions ext, Object key, Object val) {
|
||||||
if (key instanceof Number) {
|
if (key instanceof Number) {
|
||||||
var i = Values.number(key);
|
var i = Values.number(key);
|
||||||
if (i >= 0 && i - Math.floor(i) == 0) {
|
if (i >= 0 && i - Math.floor(i) == 0) {
|
||||||
set(ctx, (int)i, val);
|
set(ext, (int)i, val);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return super.setField(ctx, key, val);
|
return super.setField(ext, key, val);
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
protected boolean hasField(Context ctx, Object key) {
|
protected boolean hasField(Extensions ext, Object key) {
|
||||||
if (key instanceof Number) {
|
if (key instanceof Number) {
|
||||||
var i = Values.number(key);
|
var i = Values.number(key);
|
||||||
if (i >= 0 && i - Math.floor(i) == 0) {
|
if (i >= 0 && i - Math.floor(i) == 0) {
|
||||||
@ -162,10 +162,10 @@ public class ArrayValue extends ObjectValue implements Iterable<Object> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return super.hasField(ctx, key);
|
return super.hasField(ext, key);
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
protected void deleteField(Context ctx, Object key) {
|
protected void deleteField(Extensions ext, Object key) {
|
||||||
if (key instanceof Number) {
|
if (key instanceof Number) {
|
||||||
var i = Values.number(key);
|
var i = Values.number(key);
|
||||||
if (i >= 0 && i - Math.floor(i) == 0) {
|
if (i >= 0 && i - Math.floor(i) == 0) {
|
||||||
@ -174,7 +174,7 @@ public class ArrayValue extends ObjectValue implements Iterable<Object> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
super.deleteField(ctx, key);
|
super.deleteField(ext, key);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -213,15 +213,15 @@ public class ArrayValue extends ObjectValue implements Iterable<Object> {
|
|||||||
values = new Object[cap];
|
values = new Object[cap];
|
||||||
size = 0;
|
size = 0;
|
||||||
}
|
}
|
||||||
public ArrayValue(Context ctx, Object ...values) {
|
public ArrayValue(Extensions ext, Object ...values) {
|
||||||
this();
|
this();
|
||||||
this.values = new Object[values.length];
|
this.values = new Object[values.length];
|
||||||
size = values.length;
|
size = values.length;
|
||||||
|
|
||||||
for (var i = 0; i < size; i++) this.values[i] = Values.normalize(ctx, values[i]);
|
for (var i = 0; i < size; i++) this.values[i] = Values.normalize(ext, values[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ArrayValue of(Context ctx, Collection<?> values) {
|
public static ArrayValue of(Extensions ext, Collection<?> values) {
|
||||||
return new ArrayValue(ctx, values.toArray(Object[]::new));
|
return new ArrayValue(ext, values.toArray(Object[]::new));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,14 +2,14 @@ package me.topchetoeu.jscript.runtime.values;
|
|||||||
|
|
||||||
import me.topchetoeu.jscript.common.FunctionBody;
|
import me.topchetoeu.jscript.common.FunctionBody;
|
||||||
import me.topchetoeu.jscript.runtime.Context;
|
import me.topchetoeu.jscript.runtime.Context;
|
||||||
import me.topchetoeu.jscript.runtime.Environment;
|
import me.topchetoeu.jscript.runtime.Extensions;
|
||||||
import me.topchetoeu.jscript.runtime.Frame;
|
import me.topchetoeu.jscript.runtime.Frame;
|
||||||
import me.topchetoeu.jscript.runtime.scope.ValueVariable;
|
import me.topchetoeu.jscript.runtime.scope.ValueVariable;
|
||||||
|
|
||||||
public class CodeFunction extends FunctionValue {
|
public class CodeFunction extends FunctionValue {
|
||||||
public final FunctionBody body;
|
public final FunctionBody body;
|
||||||
public final ValueVariable[] captures;
|
public final ValueVariable[] captures;
|
||||||
public Environment environment;
|
public Extensions extensions;
|
||||||
|
|
||||||
// public Location loc() {
|
// public Location loc() {
|
||||||
// for (var instr : body.instructions) {
|
// for (var instr : body.instructions) {
|
||||||
@ -25,8 +25,8 @@ public class CodeFunction extends FunctionValue {
|
|||||||
// }
|
// }
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object call(Context ctx, Object thisArg, Object ...args) {
|
public Object call(Extensions ext, Object thisArg, Object ...args) {
|
||||||
var frame = new Frame(ctx, thisArg, args, this);
|
var frame = new Frame(Context.of(ext), thisArg, args, this);
|
||||||
|
|
||||||
frame.onPush();
|
frame.onPush();
|
||||||
|
|
||||||
@ -41,10 +41,10 @@ public class CodeFunction extends FunctionValue {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public CodeFunction(Environment environment, String name, FunctionBody body, ValueVariable[] captures) {
|
public CodeFunction(Extensions extensions, String name, FunctionBody body, ValueVariable[] captures) {
|
||||||
super(name, body.argsN);
|
super(name, body.argsN);
|
||||||
this.captures = captures;
|
this.captures = captures;
|
||||||
this.environment = environment;
|
this.extensions = extensions;
|
||||||
this.body = body;
|
this.body = body;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@ package me.topchetoeu.jscript.runtime.values;
|
|||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import me.topchetoeu.jscript.runtime.Context;
|
import me.topchetoeu.jscript.runtime.Extensions;
|
||||||
|
|
||||||
public abstract class FunctionValue extends ObjectValue {
|
public abstract class FunctionValue extends ObjectValue {
|
||||||
public String name = "";
|
public String name = "";
|
||||||
@ -13,29 +13,29 @@ public abstract class FunctionValue extends ObjectValue {
|
|||||||
return String.format("function %s(...)", name);
|
return String.format("function %s(...)", name);
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract Object call(Context ctx, Object thisArg, Object ...args);
|
public abstract Object call(Extensions ext, Object thisArg, Object ...args);
|
||||||
public Object call(Context ctx) {
|
public Object call(Extensions ext) {
|
||||||
return call(ctx, null);
|
return call(ext, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Object getField(Context ctx, Object key) {
|
protected Object getField(Extensions ext, Object key) {
|
||||||
if ("name".equals(key)) return name;
|
if ("name".equals(key)) return name;
|
||||||
if ("length".equals(key)) return length;
|
if ("length".equals(key)) return length;
|
||||||
return super.getField(ctx, key);
|
return super.getField(ext, key);
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
protected boolean setField(Context ctx, Object key, Object val) {
|
protected boolean setField(Extensions ext, Object key, Object val) {
|
||||||
if ("name".equals(key)) name = Values.toString(ctx, val);
|
if ("name".equals(key)) name = Values.toString(ext, val);
|
||||||
else if ("length".equals(key)) length = (int)Values.toNumber(ctx, val);
|
else if ("length".equals(key)) length = (int)Values.toNumber(ext, val);
|
||||||
else return super.setField(ctx, key, val);
|
else return super.setField(ext, key, val);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
protected boolean hasField(Context ctx, Object key) {
|
protected boolean hasField(Extensions ext, Object key) {
|
||||||
if ("name".equals(key)) return true;
|
if ("name".equals(key)) return true;
|
||||||
if ("length".equals(key)) return true;
|
if ("length".equals(key)) return true;
|
||||||
return super.hasField(ctx, key);
|
return super.hasField(ext, key);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package me.topchetoeu.jscript.runtime.values;
|
package me.topchetoeu.jscript.runtime.values;
|
||||||
|
|
||||||
import me.topchetoeu.jscript.runtime.Context;
|
import me.topchetoeu.jscript.runtime.Context;
|
||||||
|
import me.topchetoeu.jscript.runtime.Extensions;
|
||||||
import me.topchetoeu.jscript.utils.interop.Arguments;
|
import me.topchetoeu.jscript.utils.interop.Arguments;
|
||||||
|
|
||||||
public class NativeFunction extends FunctionValue {
|
public class NativeFunction extends FunctionValue {
|
||||||
@ -11,8 +12,8 @@ public class NativeFunction extends FunctionValue {
|
|||||||
public final NativeFunctionRunner action;
|
public final NativeFunctionRunner action;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object call(Context ctx, Object thisArg, Object ...args) {
|
public Object call(Extensions ext, Object thisArg, Object ...args) {
|
||||||
return action.run(new Arguments(ctx, thisArg, args));
|
return action.run(new Arguments(Context.of(ext), thisArg, args));
|
||||||
}
|
}
|
||||||
|
|
||||||
public NativeFunction(String name, NativeFunctionRunner action) {
|
public NativeFunction(String name, NativeFunctionRunner action) {
|
||||||
|
@ -2,9 +2,9 @@ package me.topchetoeu.jscript.runtime.values;
|
|||||||
|
|
||||||
import java.util.WeakHashMap;
|
import java.util.WeakHashMap;
|
||||||
|
|
||||||
import me.topchetoeu.jscript.runtime.Context;
|
|
||||||
import me.topchetoeu.jscript.runtime.Extensions;
|
import me.topchetoeu.jscript.runtime.Extensions;
|
||||||
import me.topchetoeu.jscript.runtime.Key;
|
import me.topchetoeu.jscript.runtime.Key;
|
||||||
|
import me.topchetoeu.jscript.utils.interop.NativeWrapperProvider;
|
||||||
|
|
||||||
public class NativeWrapper extends ObjectValue {
|
public class NativeWrapper extends ObjectValue {
|
||||||
private static final Key<WeakHashMap<Object, NativeWrapper>> WRAPPERS = new Key<>();
|
private static final Key<WeakHashMap<Object, NativeWrapper>> WRAPPERS = new Key<>();
|
||||||
@ -12,13 +12,13 @@ public class NativeWrapper extends ObjectValue {
|
|||||||
public final Object wrapped;
|
public final Object wrapped;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ObjectValue getPrototype(Context ctx) {
|
public ObjectValue getPrototype(Extensions ext) {
|
||||||
if (ctx.environment != null && prototype == NATIVE_PROTO) {
|
if (ext != null && prototype == NATIVE_PROTO) {
|
||||||
var clazz = wrapped.getClass();
|
var clazz = wrapped.getClass();
|
||||||
var res = ctx.environment.wrappers.getProto(clazz);
|
var res = NativeWrapperProvider.get(ext).getProto(clazz);
|
||||||
if (res != null) return res;
|
if (res != null) return res;
|
||||||
}
|
}
|
||||||
return super.getPrototype(ctx);
|
return super.getPrototype(ext);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -40,9 +40,14 @@ public class NativeWrapper extends ObjectValue {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static NativeWrapper of(Extensions exts, Object wrapped) {
|
public static NativeWrapper of(Extensions exts, Object wrapped) {
|
||||||
var wrappers = exts == null ? null : exts.get(WRAPPERS);
|
if (exts == null) return new NativeWrapper(wrapped);
|
||||||
|
var wrappers = exts.get(WRAPPERS);
|
||||||
|
|
||||||
|
if (wrappers == null) {
|
||||||
|
wrappers = new WeakHashMap<>();
|
||||||
|
exts.add(WRAPPERS, wrappers);
|
||||||
|
}
|
||||||
|
|
||||||
if (wrappers == null) return new NativeWrapper(wrapped);
|
|
||||||
if (wrappers.containsKey(wrapped)) return wrappers.get(wrapped);
|
if (wrappers.containsKey(wrapped)) return wrappers.get(wrapped);
|
||||||
|
|
||||||
var res = new NativeWrapper(wrapped);
|
var res = new NativeWrapper(wrapped);
|
||||||
|
@ -6,8 +6,8 @@ import java.util.LinkedHashSet;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import me.topchetoeu.jscript.runtime.Context;
|
|
||||||
import me.topchetoeu.jscript.runtime.Environment;
|
import me.topchetoeu.jscript.runtime.Environment;
|
||||||
|
import me.topchetoeu.jscript.runtime.Extensions;
|
||||||
|
|
||||||
public class ObjectValue {
|
public class ObjectValue {
|
||||||
public static enum PlaceholderProto {
|
public static enum PlaceholderProto {
|
||||||
@ -54,10 +54,10 @@ public class ObjectValue {
|
|||||||
public LinkedHashSet<Object> nonConfigurableSet = new LinkedHashSet<>();
|
public LinkedHashSet<Object> nonConfigurableSet = new LinkedHashSet<>();
|
||||||
public LinkedHashSet<Object> nonEnumerableSet = new LinkedHashSet<>();
|
public LinkedHashSet<Object> nonEnumerableSet = new LinkedHashSet<>();
|
||||||
|
|
||||||
private Property getProperty(Context ctx, Object key) {
|
private Property getProperty(Extensions ext, Object key) {
|
||||||
if (properties.containsKey(key)) return properties.get(key);
|
if (properties.containsKey(key)) return properties.get(key);
|
||||||
var proto = getPrototype(ctx);
|
var proto = getPrototype(ext);
|
||||||
if (proto != null) return proto.getProperty(ctx, key);
|
if (proto != null) return proto.getProperty(ext, key);
|
||||||
else return null;
|
else return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -86,8 +86,8 @@ public class ObjectValue {
|
|||||||
state = State.FROZEN;
|
state = State.FROZEN;
|
||||||
}
|
}
|
||||||
|
|
||||||
public final boolean defineProperty(Context ctx, Object key, Object val, boolean writable, boolean configurable, boolean enumerable) {
|
public final boolean defineProperty(Extensions ext, Object key, Object val, boolean writable, boolean configurable, boolean enumerable) {
|
||||||
key = Values.normalize(ctx, key); val = Values.normalize(ctx, val);
|
key = Values.normalize(ext, key); val = Values.normalize(ext, val);
|
||||||
boolean reconfigured =
|
boolean reconfigured =
|
||||||
writable != memberWritable(key) ||
|
writable != memberWritable(key) ||
|
||||||
configurable != memberConfigurable(key) ||
|
configurable != memberConfigurable(key) ||
|
||||||
@ -125,11 +125,11 @@ public class ObjectValue {
|
|||||||
values.put(key, val);
|
values.put(key, val);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
public final boolean defineProperty(Context ctx, Object key, Object val) {
|
public final boolean defineProperty(Extensions ext, Object key, Object val) {
|
||||||
return defineProperty(ctx, key, val, true, true, true);
|
return defineProperty(ext, key, val, true, true, true);
|
||||||
}
|
}
|
||||||
public final boolean defineProperty(Context ctx, Object key, FunctionValue getter, FunctionValue setter, boolean configurable, boolean enumerable) {
|
public final boolean defineProperty(Extensions ext, Object key, FunctionValue getter, FunctionValue setter, boolean configurable, boolean enumerable) {
|
||||||
key = Values.normalize(ctx, key);
|
key = Values.normalize(ext, key);
|
||||||
if (
|
if (
|
||||||
properties.containsKey(key) &&
|
properties.containsKey(key) &&
|
||||||
properties.get(key).getter == getter &&
|
properties.get(key).getter == getter &&
|
||||||
@ -152,17 +152,17 @@ public class ObjectValue {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ObjectValue getPrototype(Context ctx) {
|
public ObjectValue getPrototype(Extensions ext) {
|
||||||
if (prototype instanceof ObjectValue || prototype == null) return (ObjectValue)prototype;
|
if (prototype instanceof ObjectValue || prototype == null) return (ObjectValue)prototype;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (prototype == ARR_PROTO) return ctx.get(Environment.ARRAY_PROTO);
|
if (prototype == ARR_PROTO) return ext.get(Environment.ARRAY_PROTO);
|
||||||
if (prototype == FUNC_PROTO) return ctx.get(Environment.FUNCTION_PROTO);
|
if (prototype == FUNC_PROTO) return ext.get(Environment.FUNCTION_PROTO);
|
||||||
if (prototype == ERR_PROTO) return ctx.get(Environment.ERROR_PROTO);
|
if (prototype == ERR_PROTO) return ext.get(Environment.ERROR_PROTO);
|
||||||
if (prototype == RANGE_ERR_PROTO) return ctx.get(Environment.RANGE_ERR_PROTO);
|
if (prototype == RANGE_ERR_PROTO) return ext.get(Environment.RANGE_ERR_PROTO);
|
||||||
if (prototype == SYNTAX_ERR_PROTO) return ctx.get(Environment.SYNTAX_ERR_PROTO);
|
if (prototype == SYNTAX_ERR_PROTO) return ext.get(Environment.SYNTAX_ERR_PROTO);
|
||||||
if (prototype == TYPE_ERR_PROTO) return ctx.get(Environment.TYPE_ERR_PROTO);
|
if (prototype == TYPE_ERR_PROTO) return ext.get(Environment.TYPE_ERR_PROTO);
|
||||||
return ctx.get(Environment.OBJECT_PROTO);
|
return ext.get(Environment.OBJECT_PROTO);
|
||||||
}
|
}
|
||||||
catch (NullPointerException e) { return null; }
|
catch (NullPointerException e) { return null; }
|
||||||
}
|
}
|
||||||
@ -185,10 +185,10 @@ public class ObjectValue {
|
|||||||
* A method, used to get the value of a field. If a property is bound to
|
* A method, used to get the value of a field. If a property is bound to
|
||||||
* this key, but not a field, this method should return null.
|
* this key, but not a field, this method should return null.
|
||||||
*/
|
*/
|
||||||
protected Object getField(Context ctx, Object key) {
|
protected Object getField(Extensions ext, Object key) {
|
||||||
if (values.containsKey(key)) return values.get(key);
|
if (values.containsKey(key)) return values.get(key);
|
||||||
var proto = getPrototype(ctx);
|
var proto = getPrototype(ext);
|
||||||
if (proto != null) return proto.getField(ctx, key);
|
if (proto != null) return proto.getField(ext, key);
|
||||||
else return null;
|
else return null;
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
@ -196,9 +196,9 @@ public class ObjectValue {
|
|||||||
* bound to this key, a new field should be created with the given value
|
* bound to this key, a new field should be created with the given value
|
||||||
* @return Whether or not the operation was successful
|
* @return Whether or not the operation was successful
|
||||||
*/
|
*/
|
||||||
protected boolean setField(Context ctx, Object key, Object val) {
|
protected boolean setField(Extensions ext, Object key, Object val) {
|
||||||
if (val instanceof FunctionValue && ((FunctionValue)val).name.equals("")) {
|
if (val instanceof FunctionValue && ((FunctionValue)val).name.equals("")) {
|
||||||
((FunctionValue)val).name = Values.toString(ctx, key);
|
((FunctionValue)val).name = Values.toString(ext, key);
|
||||||
}
|
}
|
||||||
|
|
||||||
values.put(key, val);
|
values.put(key, val);
|
||||||
@ -207,40 +207,40 @@ public class ObjectValue {
|
|||||||
/**
|
/**
|
||||||
* Deletes the field bound to the given key.
|
* Deletes the field bound to the given key.
|
||||||
*/
|
*/
|
||||||
protected void deleteField(Context ctx, Object key) {
|
protected void deleteField(Extensions ext, Object key) {
|
||||||
values.remove(key);
|
values.remove(key);
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Returns whether or not there is a field bound to the given key.
|
* Returns whether or not there is a field bound to the given key.
|
||||||
* This must ignore properties
|
* This must ignore properties
|
||||||
*/
|
*/
|
||||||
protected boolean hasField(Context ctx, Object key) {
|
protected boolean hasField(Extensions ext, Object key) {
|
||||||
return values.containsKey(key);
|
return values.containsKey(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
public final Object getMember(Context ctx, Object key, Object thisArg) {
|
public final Object getMember(Extensions ext, Object key, Object thisArg) {
|
||||||
key = Values.normalize(ctx, key);
|
key = Values.normalize(ext, key);
|
||||||
|
|
||||||
if ("__proto__".equals(key)) {
|
if ("__proto__".equals(key)) {
|
||||||
var res = getPrototype(ctx);
|
var res = getPrototype(ext);
|
||||||
return res == null ? Values.NULL : res;
|
return res == null ? Values.NULL : res;
|
||||||
}
|
}
|
||||||
|
|
||||||
var prop = getProperty(ctx, key);
|
var prop = getProperty(ext, key);
|
||||||
|
|
||||||
if (prop != null) {
|
if (prop != null) {
|
||||||
if (prop.getter == null) return null;
|
if (prop.getter == null) return null;
|
||||||
else return prop.getter.call(ctx, Values.normalize(ctx, thisArg));
|
else return prop.getter.call(ext, Values.normalize(ext, thisArg));
|
||||||
}
|
}
|
||||||
else return getField(ctx, key);
|
else return getField(ext, key);
|
||||||
}
|
}
|
||||||
public final boolean setMember(Context ctx, Object key, Object val, Object thisArg, boolean onlyProps) {
|
public final boolean setMember(Extensions ext, Object key, Object val, Object thisArg, boolean onlyProps) {
|
||||||
key = Values.normalize(ctx, key); val = Values.normalize(ctx, val);
|
key = Values.normalize(ext, key); val = Values.normalize(ext, val);
|
||||||
|
|
||||||
var prop = getProperty(ctx, key);
|
var prop = getProperty(ext, key);
|
||||||
if (prop != null) {
|
if (prop != null) {
|
||||||
if (prop.setter == null) return false;
|
if (prop.setter == null) return false;
|
||||||
prop.setter.call(ctx, Values.normalize(ctx, thisArg), val);
|
prop.setter.call(ext, Values.normalize(ext, thisArg), val);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else if (onlyProps) return false;
|
else if (onlyProps) return false;
|
||||||
@ -249,32 +249,32 @@ public class ObjectValue {
|
|||||||
values.put(key, val);
|
values.put(key, val);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else if ("__proto__".equals(key)) return setPrototype(ctx, val);
|
else if ("__proto__".equals(key)) return setPrototype(ext, val);
|
||||||
else if (nonWritableSet.contains(key)) return false;
|
else if (nonWritableSet.contains(key)) return false;
|
||||||
else return setField(ctx, key, val);
|
else return setField(ext, key, val);
|
||||||
}
|
}
|
||||||
public final boolean hasMember(Context ctx, Object key, boolean own) {
|
public final boolean hasMember(Extensions ext, Object key, boolean own) {
|
||||||
key = Values.normalize(ctx, key);
|
key = Values.normalize(ext, key);
|
||||||
|
|
||||||
if (key != null && "__proto__".equals(key)) return true;
|
if (key != null && "__proto__".equals(key)) return true;
|
||||||
if (hasField(ctx, key)) return true;
|
if (hasField(ext, key)) return true;
|
||||||
if (properties.containsKey(key)) return true;
|
if (properties.containsKey(key)) return true;
|
||||||
if (own) return false;
|
if (own) return false;
|
||||||
var proto = getPrototype(ctx);
|
var proto = getPrototype(ext);
|
||||||
return proto != null && proto.hasMember(ctx, key, own);
|
return proto != null && proto.hasMember(ext, key, own);
|
||||||
}
|
}
|
||||||
public final boolean deleteMember(Context ctx, Object key) {
|
public final boolean deleteMember(Extensions ext, Object key) {
|
||||||
key = Values.normalize(ctx, key);
|
key = Values.normalize(ext, key);
|
||||||
|
|
||||||
if (!memberConfigurable(key)) return false;
|
if (!memberConfigurable(key)) return false;
|
||||||
properties.remove(key);
|
properties.remove(key);
|
||||||
nonWritableSet.remove(key);
|
nonWritableSet.remove(key);
|
||||||
nonEnumerableSet.remove(key);
|
nonEnumerableSet.remove(key);
|
||||||
deleteField(ctx, key);
|
deleteField(ext, key);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
public final boolean setPrototype(Context ctx, Object val) {
|
public final boolean setPrototype(Extensions ext, Object val) {
|
||||||
val = Values.normalize(ctx, val);
|
val = Values.normalize(ext, val);
|
||||||
|
|
||||||
if (!extensible()) return false;
|
if (!extensible()) return false;
|
||||||
if (val == null || val == Values.NULL) {
|
if (val == null || val == Values.NULL) {
|
||||||
@ -284,14 +284,14 @@ public class ObjectValue {
|
|||||||
else if (val instanceof ObjectValue) {
|
else if (val instanceof ObjectValue) {
|
||||||
var obj = (ObjectValue)val;
|
var obj = (ObjectValue)val;
|
||||||
|
|
||||||
if (ctx != null) {
|
if (ext != null) {
|
||||||
if (obj == ctx.get(Environment.OBJECT_PROTO)) prototype = OBJ_PROTO;
|
if (obj == ext.get(Environment.OBJECT_PROTO)) prototype = OBJ_PROTO;
|
||||||
else if (obj == ctx.get(Environment.ARRAY_PROTO)) prototype = ARR_PROTO;
|
else if (obj == ext.get(Environment.ARRAY_PROTO)) prototype = ARR_PROTO;
|
||||||
else if (obj == ctx.get(Environment.FUNCTION_PROTO)) prototype = FUNC_PROTO;
|
else if (obj == ext.get(Environment.FUNCTION_PROTO)) prototype = FUNC_PROTO;
|
||||||
else if (obj == ctx.get(Environment.ERROR_PROTO)) prototype = ERR_PROTO;
|
else if (obj == ext.get(Environment.ERROR_PROTO)) prototype = ERR_PROTO;
|
||||||
else if (obj == ctx.get(Environment.SYNTAX_ERR_PROTO)) prototype = SYNTAX_ERR_PROTO;
|
else if (obj == ext.get(Environment.SYNTAX_ERR_PROTO)) prototype = SYNTAX_ERR_PROTO;
|
||||||
else if (obj == ctx.get(Environment.TYPE_ERR_PROTO)) prototype = TYPE_ERR_PROTO;
|
else if (obj == ext.get(Environment.TYPE_ERR_PROTO)) prototype = TYPE_ERR_PROTO;
|
||||||
else if (obj == ctx.get(Environment.RANGE_ERR_PROTO)) prototype = RANGE_ERR_PROTO;
|
else if (obj == ext.get(Environment.RANGE_ERR_PROTO)) prototype = RANGE_ERR_PROTO;
|
||||||
else prototype = obj;
|
else prototype = obj;
|
||||||
}
|
}
|
||||||
else prototype = obj;
|
else prototype = obj;
|
||||||
@ -301,22 +301,22 @@ public class ObjectValue {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public final ObjectValue getMemberDescriptor(Context ctx, Object key) {
|
public final ObjectValue getMemberDescriptor(Extensions ext, Object key) {
|
||||||
key = Values.normalize(ctx, key);
|
key = Values.normalize(ext, key);
|
||||||
|
|
||||||
var prop = properties.get(key);
|
var prop = properties.get(key);
|
||||||
var res = new ObjectValue();
|
var res = new ObjectValue();
|
||||||
|
|
||||||
res.defineProperty(ctx, "configurable", memberConfigurable(key));
|
res.defineProperty(ext, "configurable", memberConfigurable(key));
|
||||||
res.defineProperty(ctx, "enumerable", memberEnumerable(key));
|
res.defineProperty(ext, "enumerable", memberEnumerable(key));
|
||||||
|
|
||||||
if (prop != null) {
|
if (prop != null) {
|
||||||
res.defineProperty(ctx, "get", prop.getter);
|
res.defineProperty(ext, "get", prop.getter);
|
||||||
res.defineProperty(ctx, "set", prop.setter);
|
res.defineProperty(ext, "set", prop.setter);
|
||||||
}
|
}
|
||||||
else if (hasField(ctx, key)) {
|
else if (hasField(ext, key)) {
|
||||||
res.defineProperty(ctx, "value", values.get(key));
|
res.defineProperty(ext, "value", values.get(key));
|
||||||
res.defineProperty(ctx, "writable", memberWritable(key));
|
res.defineProperty(ext, "writable", memberWritable(key));
|
||||||
}
|
}
|
||||||
else return null;
|
else return null;
|
||||||
return res;
|
return res;
|
||||||
@ -337,10 +337,10 @@ public class ObjectValue {
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ObjectValue(Context ctx, Map<?, ?> values) {
|
public ObjectValue(Extensions ext, Map<?, ?> values) {
|
||||||
this(PlaceholderProto.OBJECT);
|
this(PlaceholderProto.OBJECT);
|
||||||
for (var el : values.entrySet()) {
|
for (var el : values.entrySet()) {
|
||||||
defineProperty(ctx, el.getKey(), el.getValue());
|
defineProperty(ext, el.getKey(), el.getValue());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public ObjectValue(PlaceholderProto proto) {
|
public ObjectValue(PlaceholderProto proto) {
|
||||||
|
@ -3,7 +3,7 @@ package me.topchetoeu.jscript.runtime.values;
|
|||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import me.topchetoeu.jscript.runtime.Context;
|
import me.topchetoeu.jscript.runtime.Extensions;
|
||||||
import me.topchetoeu.jscript.runtime.scope.ValueVariable;
|
import me.topchetoeu.jscript.runtime.scope.ValueVariable;
|
||||||
|
|
||||||
public class ScopeValue extends ObjectValue {
|
public class ScopeValue extends ObjectValue {
|
||||||
@ -11,31 +11,31 @@ public class ScopeValue extends ObjectValue {
|
|||||||
public final HashMap<String, Integer> names = new HashMap<>();
|
public final HashMap<String, Integer> names = new HashMap<>();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Object getField(Context ctx, Object key) {
|
protected Object getField(Extensions ext, Object key) {
|
||||||
if (names.containsKey(key)) return variables[names.get(key)].get(ctx);
|
if (names.containsKey(key)) return variables[names.get(key)].get(ext);
|
||||||
return super.getField(ctx, key);
|
return super.getField(ext, key);
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
protected boolean setField(Context ctx, Object key, Object val) {
|
protected boolean setField(Extensions ext, Object key, Object val) {
|
||||||
if (names.containsKey(key)) {
|
if (names.containsKey(key)) {
|
||||||
variables[names.get(key)].set(ctx, val);
|
variables[names.get(key)].set(ext, val);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
var proto = getPrototype(ctx);
|
var proto = getPrototype(ext);
|
||||||
if (proto != null && proto.hasMember(ctx, key, false) && proto.setField(ctx, key, val)) return true;
|
if (proto != null && proto.hasMember(ext, key, false) && proto.setField(ext, key, val)) return true;
|
||||||
|
|
||||||
return super.setField(ctx, key, val);
|
return super.setField(ext, key, val);
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
protected void deleteField(Context ctx, Object key) {
|
protected void deleteField(Extensions ext, Object key) {
|
||||||
if (names.containsKey(key)) return;
|
if (names.containsKey(key)) return;
|
||||||
super.deleteField(ctx, key);
|
super.deleteField(ext, key);
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
protected boolean hasField(Context ctx, Object key) {
|
protected boolean hasField(Extensions ext, Object key) {
|
||||||
if (names.containsKey(key)) return true;
|
if (names.containsKey(key)) return true;
|
||||||
return super.hasField(ctx, key);
|
return super.hasField(ext, key);
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
public List<Object> keys(boolean includeNonEnumerable) {
|
public List<Object> keys(boolean includeNonEnumerable) {
|
||||||
|
@ -14,12 +14,13 @@ import java.util.Map;
|
|||||||
|
|
||||||
import me.topchetoeu.jscript.common.Operation;
|
import me.topchetoeu.jscript.common.Operation;
|
||||||
import me.topchetoeu.jscript.lib.PromiseLib;
|
import me.topchetoeu.jscript.lib.PromiseLib;
|
||||||
import me.topchetoeu.jscript.runtime.Context;
|
|
||||||
import me.topchetoeu.jscript.runtime.Environment;
|
import me.topchetoeu.jscript.runtime.Environment;
|
||||||
|
import me.topchetoeu.jscript.runtime.Extensions;
|
||||||
import me.topchetoeu.jscript.runtime.debug.DebugContext;
|
import me.topchetoeu.jscript.runtime.debug.DebugContext;
|
||||||
import me.topchetoeu.jscript.runtime.exceptions.ConvertException;
|
import me.topchetoeu.jscript.runtime.exceptions.ConvertException;
|
||||||
import me.topchetoeu.jscript.runtime.exceptions.EngineException;
|
import me.topchetoeu.jscript.runtime.exceptions.EngineException;
|
||||||
import me.topchetoeu.jscript.runtime.exceptions.SyntaxException;
|
import me.topchetoeu.jscript.runtime.exceptions.SyntaxException;
|
||||||
|
import me.topchetoeu.jscript.utils.interop.NativeWrapperProvider;
|
||||||
|
|
||||||
public class Values {
|
public class Values {
|
||||||
public static enum CompareResult {
|
public static enum CompareResult {
|
||||||
@ -73,11 +74,11 @@ public class Values {
|
|||||||
return "object";
|
return "object";
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Object tryCallConvertFunc(Context ctx, Object obj, String name) {
|
private static Object tryCallConvertFunc(Extensions ext, Object obj, String name) {
|
||||||
var func = getMember(ctx, obj, name);
|
var func = getMember(ext, obj, name);
|
||||||
|
|
||||||
if (func instanceof FunctionValue) {
|
if (func instanceof FunctionValue) {
|
||||||
var res = Values.call(ctx, func, obj);
|
var res = Values.call(ext, func, obj);
|
||||||
if (isPrimitive(res)) return res;
|
if (isPrimitive(res)) return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -94,16 +95,16 @@ public class Values {
|
|||||||
obj == NULL;
|
obj == NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Object toPrimitive(Context ctx, Object obj, ConvertHint hint) {
|
public static Object toPrimitive(Extensions ext, Object obj, ConvertHint hint) {
|
||||||
obj = normalize(ctx, obj);
|
obj = normalize(ext, obj);
|
||||||
if (isPrimitive(obj)) return obj;
|
if (isPrimitive(obj)) return obj;
|
||||||
|
|
||||||
var first = hint == ConvertHint.VALUEOF ? "valueOf" : "toString";
|
var first = hint == ConvertHint.VALUEOF ? "valueOf" : "toString";
|
||||||
var second = hint == ConvertHint.VALUEOF ? "toString" : "valueOf";
|
var second = hint == ConvertHint.VALUEOF ? "toString" : "valueOf";
|
||||||
|
|
||||||
if (ctx != null) {
|
if (ext != null) {
|
||||||
try { return tryCallConvertFunc(ctx, obj, first); }
|
try { return tryCallConvertFunc(ext, obj, first); }
|
||||||
catch (EngineException unused) { return tryCallConvertFunc(ctx, obj, second); }
|
catch (EngineException unused) { return tryCallConvertFunc(ext, obj, second); }
|
||||||
}
|
}
|
||||||
|
|
||||||
throw EngineException.ofType("Value couldn't be converted to a primitive.");
|
throw EngineException.ofType("Value couldn't be converted to a primitive.");
|
||||||
@ -115,8 +116,8 @@ public class Values {
|
|||||||
if (obj instanceof Boolean) return (Boolean)obj;
|
if (obj instanceof Boolean) return (Boolean)obj;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
public static double toNumber(Context ctx, Object obj) {
|
public static double toNumber(Extensions ext, Object obj) {
|
||||||
var val = toPrimitive(ctx, obj, ConvertHint.VALUEOF);
|
var val = toPrimitive(ext, obj, ConvertHint.VALUEOF);
|
||||||
|
|
||||||
if (val instanceof Number) return number(val);
|
if (val instanceof Number) return number(val);
|
||||||
if (val instanceof Boolean) return ((Boolean)val) ? 1 : 0;
|
if (val instanceof Boolean) return ((Boolean)val) ? 1 : 0;
|
||||||
@ -126,8 +127,8 @@ public class Values {
|
|||||||
}
|
}
|
||||||
return Double.NaN;
|
return Double.NaN;
|
||||||
}
|
}
|
||||||
public static String toString(Context ctx, Object obj) {
|
public static String toString(Extensions ext, Object obj) {
|
||||||
var val = toPrimitive(ctx, obj, ConvertHint.VALUEOF);
|
var val = toPrimitive(ext, obj, ConvertHint.VALUEOF);
|
||||||
|
|
||||||
if (val == null) return "undefined";
|
if (val == null) return "undefined";
|
||||||
if (val == NULL) return "null";
|
if (val == NULL) return "null";
|
||||||
@ -146,63 +147,63 @@ public class Values {
|
|||||||
return "Unknown value";
|
return "Unknown value";
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Object add(Context ctx, Object a, Object b) {
|
public static Object add(Extensions ext, Object a, Object b) {
|
||||||
if (a instanceof String || b instanceof String) return toString(ctx, a) + toString(ctx, b);
|
if (a instanceof String || b instanceof String) return toString(ext, a) + toString(ext, b);
|
||||||
else return toNumber(ctx, a) + toNumber(ctx, b);
|
else return toNumber(ext, a) + toNumber(ext, b);
|
||||||
}
|
}
|
||||||
public static double subtract(Context ctx, Object a, Object b) {
|
public static double subtract(Extensions ext, Object a, Object b) {
|
||||||
return toNumber(ctx, a) - toNumber(ctx, b);
|
return toNumber(ext, a) - toNumber(ext, b);
|
||||||
}
|
}
|
||||||
public static double multiply(Context ctx, Object a, Object b) {
|
public static double multiply(Extensions ext, Object a, Object b) {
|
||||||
return toNumber(ctx, a) * toNumber(ctx, b);
|
return toNumber(ext, a) * toNumber(ext, b);
|
||||||
}
|
}
|
||||||
public static double divide(Context ctx, Object a, Object b) {
|
public static double divide(Extensions ext, Object a, Object b) {
|
||||||
return toNumber(ctx, a) / toNumber(ctx, b);
|
return toNumber(ext, a) / toNumber(ext, b);
|
||||||
}
|
}
|
||||||
public static double modulo(Context ctx, Object a, Object b) {
|
public static double modulo(Extensions ext, Object a, Object b) {
|
||||||
return toNumber(ctx, a) % toNumber(ctx, b);
|
return toNumber(ext, a) % toNumber(ext, b);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static double negative(Context ctx, Object obj) {
|
public static double negative(Extensions ext, Object obj) {
|
||||||
return -toNumber(ctx, obj);
|
return -toNumber(ext, obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int and(Context ctx, Object a, Object b) {
|
public static int and(Extensions ext, Object a, Object b) {
|
||||||
return (int)toNumber(ctx, a) & (int)toNumber(ctx, b);
|
return (int)toNumber(ext, a) & (int)toNumber(ext, b);
|
||||||
}
|
}
|
||||||
public static int or(Context ctx, Object a, Object b) {
|
public static int or(Extensions ext, Object a, Object b) {
|
||||||
return (int)toNumber(ctx, a) | (int)toNumber(ctx, b);
|
return (int)toNumber(ext, a) | (int)toNumber(ext, b);
|
||||||
}
|
}
|
||||||
public static int xor(Context ctx, Object a, Object b) {
|
public static int xor(Extensions ext, Object a, Object b) {
|
||||||
return (int)toNumber(ctx, a) ^ (int)toNumber(ctx, b);
|
return (int)toNumber(ext, a) ^ (int)toNumber(ext, b);
|
||||||
}
|
}
|
||||||
public static int bitwiseNot(Context ctx, Object obj) {
|
public static int bitwiseNot(Extensions ext, Object obj) {
|
||||||
return ~(int)toNumber(ctx, obj);
|
return ~(int)toNumber(ext, obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int shiftLeft(Context ctx, Object a, Object b) {
|
public static int shiftLeft(Extensions ext, Object a, Object b) {
|
||||||
return (int)toNumber(ctx, a) << (int)toNumber(ctx, b);
|
return (int)toNumber(ext, a) << (int)toNumber(ext, b);
|
||||||
}
|
}
|
||||||
public static int shiftRight(Context ctx, Object a, Object b) {
|
public static int shiftRight(Extensions ext, Object a, Object b) {
|
||||||
return (int)toNumber(ctx, a) >> (int)toNumber(ctx, b);
|
return (int)toNumber(ext, a) >> (int)toNumber(ext, b);
|
||||||
}
|
}
|
||||||
public static long unsignedShiftRight(Context ctx, Object a, Object b) {
|
public static long unsignedShiftRight(Extensions ext, Object a, Object b) {
|
||||||
long _a = (long)toNumber(ctx, a);
|
long _a = (long)toNumber(ext, a);
|
||||||
long _b = (long)toNumber(ctx, b);
|
long _b = (long)toNumber(ext, b);
|
||||||
|
|
||||||
if (_a < 0) _a += 0x100000000l;
|
if (_a < 0) _a += 0x100000000l;
|
||||||
if (_b < 0) _b += 0x100000000l;
|
if (_b < 0) _b += 0x100000000l;
|
||||||
return _a >>> _b;
|
return _a >>> _b;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static CompareResult compare(Context ctx, Object a, Object b) {
|
public static CompareResult compare(Extensions ext, Object a, Object b) {
|
||||||
a = toPrimitive(ctx, a, ConvertHint.VALUEOF);
|
a = toPrimitive(ext, a, ConvertHint.VALUEOF);
|
||||||
b = toPrimitive(ctx, b, ConvertHint.VALUEOF);
|
b = toPrimitive(ext, b, ConvertHint.VALUEOF);
|
||||||
|
|
||||||
if (a instanceof String && b instanceof String) CompareResult.from(((String)a).compareTo((String)b));
|
if (a instanceof String && b instanceof String) CompareResult.from(((String)a).compareTo((String)b));
|
||||||
|
|
||||||
var _a = toNumber(ctx, a);
|
var _a = toNumber(ext, a);
|
||||||
var _b = toNumber(ctx, b);
|
var _b = toNumber(ext, b);
|
||||||
|
|
||||||
if (Double.isNaN(_a) || Double.isNaN(_b)) return CompareResult.NOT_EQUAL;
|
if (Double.isNaN(_a) || Double.isNaN(_b)) return CompareResult.NOT_EQUAL;
|
||||||
|
|
||||||
@ -213,60 +214,60 @@ public class Values {
|
|||||||
return !toBoolean(obj);
|
return !toBoolean(obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isInstanceOf(Context ctx, Object obj, Object proto) {
|
public static boolean isInstanceOf(Extensions ext, Object obj, Object proto) {
|
||||||
if (obj == null || obj == NULL || proto == null || proto == NULL) return false;
|
if (obj == null || obj == NULL || proto == null || proto == NULL) return false;
|
||||||
var val = getPrototype(ctx, obj);
|
var val = getPrototype(ext, obj);
|
||||||
|
|
||||||
while (val != null) {
|
while (val != null) {
|
||||||
if (val.equals(proto)) return true;
|
if (val.equals(proto)) return true;
|
||||||
val = val.getPrototype(ctx);
|
val = val.getPrototype(ext);
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Object operation(Context ctx, Operation op, Object ...args) {
|
public static Object operation(Extensions ext, Operation op, Object ...args) {
|
||||||
switch (op) {
|
switch (op) {
|
||||||
case ADD: return add(ctx, args[0], args[1]);
|
case ADD: return add(ext, args[0], args[1]);
|
||||||
case SUBTRACT: return subtract(ctx, args[0], args[1]);
|
case SUBTRACT: return subtract(ext, args[0], args[1]);
|
||||||
case DIVIDE: return divide(ctx, args[0], args[1]);
|
case DIVIDE: return divide(ext, args[0], args[1]);
|
||||||
case MULTIPLY: return multiply(ctx, args[0], args[1]);
|
case MULTIPLY: return multiply(ext, args[0], args[1]);
|
||||||
case MODULO: return modulo(ctx, args[0], args[1]);
|
case MODULO: return modulo(ext, args[0], args[1]);
|
||||||
|
|
||||||
case AND: return and(ctx, args[0], args[1]);
|
case AND: return and(ext, args[0], args[1]);
|
||||||
case OR: return or(ctx, args[0], args[1]);
|
case OR: return or(ext, args[0], args[1]);
|
||||||
case XOR: return xor(ctx, args[0], args[1]);
|
case XOR: return xor(ext, args[0], args[1]);
|
||||||
|
|
||||||
case EQUALS: return strictEquals(ctx, args[0], args[1]);
|
case EQUALS: return strictEquals(ext, args[0], args[1]);
|
||||||
case NOT_EQUALS: return !strictEquals(ctx, args[0], args[1]);
|
case NOT_EQUALS: return !strictEquals(ext, args[0], args[1]);
|
||||||
case LOOSE_EQUALS: return looseEqual(ctx, args[0], args[1]);
|
case LOOSE_EQUALS: return looseEqual(ext, args[0], args[1]);
|
||||||
case LOOSE_NOT_EQUALS: return !looseEqual(ctx, args[0], args[1]);
|
case LOOSE_NOT_EQUALS: return !looseEqual(ext, args[0], args[1]);
|
||||||
|
|
||||||
case GREATER: return compare(ctx, args[0], args[1]).greater();
|
case GREATER: return compare(ext, args[0], args[1]).greater();
|
||||||
case GREATER_EQUALS: return compare(ctx, args[0], args[1]).greaterOrEqual();
|
case GREATER_EQUALS: return compare(ext, args[0], args[1]).greaterOrEqual();
|
||||||
case LESS: return compare(ctx, args[0], args[1]).less();
|
case LESS: return compare(ext, args[0], args[1]).less();
|
||||||
case LESS_EQUALS: return compare(ctx, args[0], args[1]).lessOrEqual();
|
case LESS_EQUALS: return compare(ext, args[0], args[1]).lessOrEqual();
|
||||||
|
|
||||||
case INVERSE: return bitwiseNot(ctx, args[0]);
|
case INVERSE: return bitwiseNot(ext, args[0]);
|
||||||
case NOT: return not(args[0]);
|
case NOT: return not(args[0]);
|
||||||
case POS: return toNumber(ctx, args[0]);
|
case POS: return toNumber(ext, args[0]);
|
||||||
case NEG: return negative(ctx, args[0]);
|
case NEG: return negative(ext, args[0]);
|
||||||
|
|
||||||
case SHIFT_LEFT: return shiftLeft(ctx, args[0], args[1]);
|
case SHIFT_LEFT: return shiftLeft(ext, args[0], args[1]);
|
||||||
case SHIFT_RIGHT: return shiftRight(ctx, args[0], args[1]);
|
case SHIFT_RIGHT: return shiftRight(ext, args[0], args[1]);
|
||||||
case USHIFT_RIGHT: return unsignedShiftRight(ctx, args[0], args[1]);
|
case USHIFT_RIGHT: return unsignedShiftRight(ext, args[0], args[1]);
|
||||||
|
|
||||||
case IN: return hasMember(ctx, args[1], args[0], false);
|
case IN: return hasMember(ext, args[1], args[0], false);
|
||||||
case INSTANCEOF: {
|
case INSTANCEOF: {
|
||||||
var proto = getMember(ctx, args[1], "prototype");
|
var proto = getMember(ext, args[1], "prototype");
|
||||||
return isInstanceOf(ctx, args[0], proto);
|
return isInstanceOf(ext, args[0], proto);
|
||||||
}
|
}
|
||||||
|
|
||||||
default: return null;
|
default: return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Object getMember(Context ctx, Object obj, Object key) {
|
public static Object getMember(Extensions ctx, Object obj, Object key) {
|
||||||
obj = normalize(ctx, obj); key = normalize(ctx, key);
|
obj = normalize(ctx, obj); key = normalize(ctx, key);
|
||||||
if (obj == null) throw new IllegalArgumentException("Tried to access member of undefined.");
|
if (obj == null) throw new IllegalArgumentException("Tried to access member of undefined.");
|
||||||
if (obj == NULL) throw new IllegalArgumentException("Tried to access member of null.");
|
if (obj == NULL) throw new IllegalArgumentException("Tried to access member of null.");
|
||||||
@ -286,12 +287,12 @@ public class Values {
|
|||||||
else if (key != null && "__proto__".equals(key)) return proto;
|
else if (key != null && "__proto__".equals(key)) return proto;
|
||||||
else return proto.getMember(ctx, key, obj);
|
else return proto.getMember(ctx, key, obj);
|
||||||
}
|
}
|
||||||
public static Object getMemberPath(Context ctx, Object obj, Object ...path) {
|
public static Object getMemberPath(Extensions ctx, Object obj, Object ...path) {
|
||||||
var res = obj;
|
var res = obj;
|
||||||
for (var key : path) res = getMember(ctx, res, key);
|
for (var key : path) res = getMember(ctx, res, key);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
public static boolean setMember(Context ctx, Object obj, Object key, Object val) {
|
public static boolean setMember(Extensions ctx, Object obj, Object key, Object val) {
|
||||||
obj = normalize(ctx, obj); key = normalize(ctx, key); val = normalize(ctx, val);
|
obj = normalize(ctx, obj); key = normalize(ctx, key); val = normalize(ctx, val);
|
||||||
if (obj == null) throw EngineException.ofType("Tried to access member of undefined.");
|
if (obj == null) throw EngineException.ofType("Tried to access member of undefined.");
|
||||||
if (obj == NULL) throw EngineException.ofType("Tried to access member of null.");
|
if (obj == NULL) throw EngineException.ofType("Tried to access member of null.");
|
||||||
@ -301,7 +302,7 @@ public class Values {
|
|||||||
var proto = getPrototype(ctx, obj);
|
var proto = getPrototype(ctx, obj);
|
||||||
return proto.setMember(ctx, key, val, obj, true);
|
return proto.setMember(ctx, key, val, obj, true);
|
||||||
}
|
}
|
||||||
public static boolean hasMember(Context ctx, Object obj, Object key, boolean own) {
|
public static boolean hasMember(Extensions ctx, Object obj, Object key, boolean own) {
|
||||||
if (obj == null || obj == NULL) return false;
|
if (obj == null || obj == NULL) return false;
|
||||||
obj = normalize(ctx, obj); key = normalize(ctx, key);
|
obj = normalize(ctx, obj); key = normalize(ctx, key);
|
||||||
|
|
||||||
@ -319,36 +320,36 @@ public class Values {
|
|||||||
var proto = getPrototype(ctx, obj);
|
var proto = getPrototype(ctx, obj);
|
||||||
return proto != null && proto.hasMember(ctx, key, own);
|
return proto != null && proto.hasMember(ctx, key, own);
|
||||||
}
|
}
|
||||||
public static boolean deleteMember(Context ctx, Object obj, Object key) {
|
public static boolean deleteMember(Extensions ext, Object obj, Object key) {
|
||||||
if (obj == null || obj == NULL) return false;
|
if (obj == null || obj == NULL) return false;
|
||||||
obj = normalize(ctx, obj); key = normalize(ctx, key);
|
obj = normalize(ext, obj); key = normalize(ext, key);
|
||||||
|
|
||||||
if (obj instanceof ObjectValue) return ((ObjectValue)obj).deleteMember(ctx, key);
|
if (obj instanceof ObjectValue) return ((ObjectValue)obj).deleteMember(ext, key);
|
||||||
else return false;
|
else return false;
|
||||||
}
|
}
|
||||||
public static ObjectValue getPrototype(Context ctx, Object obj) {
|
public static ObjectValue getPrototype(Extensions ext, Object obj) {
|
||||||
if (obj == null || obj == NULL) return null;
|
if (obj == null || obj == NULL) return null;
|
||||||
obj = normalize(ctx, obj);
|
obj = normalize(ext, obj);
|
||||||
if (obj instanceof ObjectValue) return ((ObjectValue)obj).getPrototype(ctx);
|
if (obj instanceof ObjectValue) return ((ObjectValue)obj).getPrototype(ext);
|
||||||
if (ctx == null) return null;
|
if (ext == null) return null;
|
||||||
|
|
||||||
if (obj instanceof String) return ctx.get(Environment.STRING_PROTO);
|
if (obj instanceof String) return ext.get(Environment.STRING_PROTO);
|
||||||
else if (obj instanceof Number) return ctx.get(Environment.NUMBER_PROTO);
|
else if (obj instanceof Number) return ext.get(Environment.NUMBER_PROTO);
|
||||||
else if (obj instanceof Boolean) return ctx.get(Environment.BOOL_PROTO);
|
else if (obj instanceof Boolean) return ext.get(Environment.BOOL_PROTO);
|
||||||
else if (obj instanceof Symbol) return ctx.get(Environment.SYMBOL_PROTO);
|
else if (obj instanceof Symbol) return ext.get(Environment.SYMBOL_PROTO);
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
public static boolean setPrototype(Context ctx, Object obj, Object proto) {
|
public static boolean setPrototype(Extensions ext, Object obj, Object proto) {
|
||||||
obj = normalize(ctx, obj);
|
obj = normalize(ext, obj);
|
||||||
return obj instanceof ObjectValue && ((ObjectValue)obj).setPrototype(ctx, proto);
|
return obj instanceof ObjectValue && ((ObjectValue)obj).setPrototype(ext, proto);
|
||||||
}
|
}
|
||||||
public static void makePrototypeChain(Context ctx, Object... chain) {
|
public static void makePrototypeChain(Extensions ext, Object... chain) {
|
||||||
for(var i = 1; i < chain.length; i++) {
|
for(var i = 1; i < chain.length; i++) {
|
||||||
setPrototype(ctx, chain[i], chain[i - 1]);
|
setPrototype(ext, chain[i], chain[i - 1]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public static List<Object> getMembers(Context ctx, Object obj, boolean own, boolean includeNonEnumerable) {
|
public static List<Object> getMembers(Extensions ext, Object obj, boolean own, boolean includeNonEnumerable) {
|
||||||
List<Object> res = new ArrayList<>();
|
List<Object> res = new ArrayList<>();
|
||||||
|
|
||||||
if (obj instanceof ObjectValue) res = ((ObjectValue)obj).keys(includeNonEnumerable);
|
if (obj instanceof ObjectValue) res = ((ObjectValue)obj).keys(includeNonEnumerable);
|
||||||
@ -357,26 +358,26 @@ public class Values {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!own) {
|
if (!own) {
|
||||||
var proto = getPrototype(ctx, obj);
|
var proto = getPrototype(ext, obj);
|
||||||
|
|
||||||
while (proto != null) {
|
while (proto != null) {
|
||||||
res.addAll(proto.keys(includeNonEnumerable));
|
res.addAll(proto.keys(includeNonEnumerable));
|
||||||
proto = getPrototype(ctx, proto);
|
proto = getPrototype(ext, proto);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
public static ObjectValue getMemberDescriptor(Context ctx, Object obj, Object key) {
|
public static ObjectValue getMemberDescriptor(Extensions ext, Object obj, Object key) {
|
||||||
if (obj instanceof ObjectValue) return ((ObjectValue)obj).getMemberDescriptor(ctx, key);
|
if (obj instanceof ObjectValue) return ((ObjectValue)obj).getMemberDescriptor(ext, key);
|
||||||
else if (obj instanceof String && key instanceof Number) {
|
else if (obj instanceof String && key instanceof Number) {
|
||||||
var i = ((Number)key).intValue();
|
var i = ((Number)key).intValue();
|
||||||
var _i = ((Number)key).doubleValue();
|
var _i = ((Number)key).doubleValue();
|
||||||
if (i - _i != 0) return null;
|
if (i - _i != 0) return null;
|
||||||
if (i < 0 || i >= ((String)obj).length()) return null;
|
if (i < 0 || i >= ((String)obj).length()) return null;
|
||||||
|
|
||||||
return new ObjectValue(ctx, Map.of(
|
return new ObjectValue(ext, Map.of(
|
||||||
"value", ((String)obj).charAt(i) + "",
|
"value", ((String)obj).charAt(i) + "",
|
||||||
"writable", false,
|
"writable", false,
|
||||||
"enumerable", true,
|
"enumerable", true,
|
||||||
@ -386,17 +387,17 @@ public class Values {
|
|||||||
else return null;
|
else return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Object call(Context ctx, Object func, Object thisArg, Object ...args) {
|
public static Object call(Extensions ext, Object func, Object thisArg, Object ...args) {
|
||||||
if (!(func instanceof FunctionValue)) throw EngineException.ofType("Tried to call a non-function value.");
|
if (!(func instanceof FunctionValue)) throw EngineException.ofType("Tried to call a non-function value.");
|
||||||
return ((FunctionValue)func).call(ctx, thisArg, args);
|
return ((FunctionValue)func).call(ext, thisArg, args);
|
||||||
}
|
}
|
||||||
public static Object callNew(Context ctx, Object func, Object ...args) {
|
public static Object callNew(Extensions ext, Object func, Object ...args) {
|
||||||
var res = new ObjectValue();
|
var res = new ObjectValue();
|
||||||
try {
|
try {
|
||||||
var proto = Values.getMember(ctx, func, "prototype");
|
var proto = Values.getMember(ext, func, "prototype");
|
||||||
setPrototype(ctx, res, proto);
|
setPrototype(ext, res, proto);
|
||||||
|
|
||||||
var ret = call(ctx, func, res, args);
|
var ret = call(ext, func, res, args);
|
||||||
|
|
||||||
if (!isPrimitive(ret)) return ret;
|
if (!isPrimitive(ret)) return ret;
|
||||||
return res;
|
return res;
|
||||||
@ -406,8 +407,9 @@ public class Values {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean strictEquals(Context ctx, Object a, Object b) {
|
public static boolean strictEquals(Extensions ext, Object a, Object b) {
|
||||||
a = normalize(ctx, a); b = normalize(ctx, b);
|
a = normalize(ext, a);
|
||||||
|
b = normalize(ext, b);
|
||||||
|
|
||||||
if (a == null || b == null) return a == null && b == null;
|
if (a == null || b == null) return a == null && b == null;
|
||||||
if (isNan(a) || isNan(b)) return false;
|
if (isNan(a) || isNan(b)) return false;
|
||||||
@ -416,8 +418,8 @@ public class Values {
|
|||||||
|
|
||||||
return a == b || a.equals(b);
|
return a == b || a.equals(b);
|
||||||
}
|
}
|
||||||
public static boolean looseEqual(Context ctx, Object a, Object b) {
|
public static boolean looseEqual(Extensions ext, Object a, Object b) {
|
||||||
a = normalize(ctx, a); b = normalize(ctx, b);
|
a = normalize(ext, a); b = normalize(ext, b);
|
||||||
|
|
||||||
// In loose equality, null is equivalent to undefined
|
// In loose equality, null is equivalent to undefined
|
||||||
if (a == NULL) a = null;
|
if (a == NULL) a = null;
|
||||||
@ -428,19 +430,19 @@ public class Values {
|
|||||||
if (!isPrimitive(a) && !isPrimitive(b)) return a == b;
|
if (!isPrimitive(a) && !isPrimitive(b)) return a == b;
|
||||||
|
|
||||||
// Convert values to primitives
|
// Convert values to primitives
|
||||||
a = toPrimitive(ctx, a, ConvertHint.VALUEOF);
|
a = toPrimitive(ext, a, ConvertHint.VALUEOF);
|
||||||
b = toPrimitive(ctx, b, ConvertHint.VALUEOF);
|
b = toPrimitive(ext, b, ConvertHint.VALUEOF);
|
||||||
|
|
||||||
// Compare symbols by reference
|
// Compare symbols by reference
|
||||||
if (a instanceof Symbol || b instanceof Symbol) return a == b;
|
if (a instanceof Symbol || b instanceof Symbol) return a == b;
|
||||||
if (a instanceof Boolean || b instanceof Boolean) return toBoolean(a) == toBoolean(b);
|
if (a instanceof Boolean || b instanceof Boolean) return toBoolean(a) == toBoolean(b);
|
||||||
if (a instanceof Number || b instanceof Number) return strictEquals(ctx, toNumber(ctx, a), toNumber(ctx, b));
|
if (a instanceof Number || b instanceof Number) return strictEquals(ext, toNumber(ext, a), toNumber(ext, b));
|
||||||
|
|
||||||
// Default to strings
|
// Default to strings
|
||||||
return toString(ctx, a).equals(toString(ctx, b));
|
return toString(ext, a).equals(toString(ext, b));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Object normalize(Context ctx, Object val) {
|
public static Object normalize(Extensions ext, Object val) {
|
||||||
if (val instanceof Number) return number(val);
|
if (val instanceof Number) return number(val);
|
||||||
if (isPrimitive(val) || val instanceof ObjectValue) return val;
|
if (isPrimitive(val) || val instanceof ObjectValue) return val;
|
||||||
if (val instanceof Character) return val + "";
|
if (val instanceof Character) return val + "";
|
||||||
@ -449,7 +451,7 @@ public class Values {
|
|||||||
var res = new ObjectValue();
|
var res = new ObjectValue();
|
||||||
|
|
||||||
for (var entry : ((Map<?, ?>)val).entrySet()) {
|
for (var entry : ((Map<?, ?>)val).entrySet()) {
|
||||||
res.defineProperty(ctx, entry.getKey(), entry.getValue());
|
res.defineProperty(ext, entry.getKey(), entry.getValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
@ -459,22 +461,22 @@ public class Values {
|
|||||||
var res = new ArrayValue();
|
var res = new ArrayValue();
|
||||||
|
|
||||||
for (var entry : ((Iterable<?>)val)) {
|
for (var entry : ((Iterable<?>)val)) {
|
||||||
res.set(ctx, res.size(), entry);
|
res.set(ext, res.size(), entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (val instanceof Class) {
|
if (val instanceof Class) {
|
||||||
if (ctx == null) return null;
|
if (ext == null) return null;
|
||||||
else return ctx.environment.wrappers.getConstr((Class<?>)val);
|
else return NativeWrapperProvider.get(ext).getConstr((Class<?>)val);
|
||||||
}
|
}
|
||||||
|
|
||||||
return NativeWrapper.of(ctx, val);
|
return NativeWrapper.of(ext, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public static <T> T convert(Context ctx, Object obj, Class<T> clazz) {
|
public static <T> T convert(Extensions ext, Object obj, Class<T> clazz) {
|
||||||
if (clazz == Void.class) return null;
|
if (clazz == Void.class) return null;
|
||||||
|
|
||||||
if (obj instanceof NativeWrapper) {
|
if (obj instanceof NativeWrapper) {
|
||||||
@ -488,19 +490,19 @@ public class Values {
|
|||||||
if (clazz.isAssignableFrom(ArrayList.class)) {
|
if (clazz.isAssignableFrom(ArrayList.class)) {
|
||||||
var raw = ((ArrayValue)obj).toArray();
|
var raw = ((ArrayValue)obj).toArray();
|
||||||
var res = new ArrayList<>();
|
var res = new ArrayList<>();
|
||||||
for (var i = 0; i < raw.length; i++) res.add(convert(ctx, raw[i], Object.class));
|
for (var i = 0; i < raw.length; i++) res.add(convert(ext, raw[i], Object.class));
|
||||||
return (T)new ArrayList<>(res);
|
return (T)new ArrayList<>(res);
|
||||||
}
|
}
|
||||||
if (clazz.isAssignableFrom(HashSet.class)) {
|
if (clazz.isAssignableFrom(HashSet.class)) {
|
||||||
var raw = ((ArrayValue)obj).toArray();
|
var raw = ((ArrayValue)obj).toArray();
|
||||||
var res = new HashSet<>();
|
var res = new HashSet<>();
|
||||||
for (var i = 0; i < raw.length; i++) res.add(convert(ctx, raw[i], Object.class));
|
for (var i = 0; i < raw.length; i++) res.add(convert(ext, raw[i], Object.class));
|
||||||
return (T)new HashSet<>(res);
|
return (T)new HashSet<>(res);
|
||||||
}
|
}
|
||||||
if (clazz.isArray()) {
|
if (clazz.isArray()) {
|
||||||
var raw = ((ArrayValue)obj).toArray();
|
var raw = ((ArrayValue)obj).toArray();
|
||||||
Object res = Array.newInstance(clazz.getComponentType(), raw.length);
|
Object res = Array.newInstance(clazz.getComponentType(), raw.length);
|
||||||
for (var i = 0; i < raw.length; i++) Array.set(res, i, convert(ctx, raw[i], Object.class));
|
for (var i = 0; i < raw.length; i++) Array.set(res, i, convert(ext, raw[i], Object.class));
|
||||||
return (T)res;
|
return (T)res;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -508,25 +510,25 @@ public class Values {
|
|||||||
if (obj instanceof ObjectValue && clazz.isAssignableFrom(HashMap.class)) {
|
if (obj instanceof ObjectValue && clazz.isAssignableFrom(HashMap.class)) {
|
||||||
var res = new HashMap<>();
|
var res = new HashMap<>();
|
||||||
for (var el : ((ObjectValue)obj).values.entrySet()) res.put(
|
for (var el : ((ObjectValue)obj).values.entrySet()) res.put(
|
||||||
convert(ctx, el.getKey(), null),
|
convert(ext, el.getKey(), null),
|
||||||
convert(ctx, el.getValue(), null)
|
convert(ext, el.getValue(), null)
|
||||||
);
|
);
|
||||||
return (T)res;
|
return (T)res;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (clazz == String.class) return (T)toString(ctx, obj);
|
if (clazz == String.class) return (T)toString(ext, obj);
|
||||||
if (clazz == Boolean.class || clazz == Boolean.TYPE) return (T)(Boolean)toBoolean(obj);
|
if (clazz == Boolean.class || clazz == Boolean.TYPE) return (T)(Boolean)toBoolean(obj);
|
||||||
if (clazz == Byte.class || clazz == byte.class) return (T)(Byte)(byte)toNumber(ctx, obj);
|
if (clazz == Byte.class || clazz == byte.class) return (T)(Byte)(byte)toNumber(ext, obj);
|
||||||
if (clazz == Integer.class || clazz == int.class) return (T)(Integer)(int)toNumber(ctx, obj);
|
if (clazz == Integer.class || clazz == int.class) return (T)(Integer)(int)toNumber(ext, obj);
|
||||||
if (clazz == Long.class || clazz == long.class) return (T)(Long)(long)toNumber(ctx, obj);
|
if (clazz == Long.class || clazz == long.class) return (T)(Long)(long)toNumber(ext, obj);
|
||||||
if (clazz == Short.class || clazz == short.class) return (T)(Short)(short)toNumber(ctx, obj);
|
if (clazz == Short.class || clazz == short.class) return (T)(Short)(short)toNumber(ext, obj);
|
||||||
if (clazz == Float.class || clazz == float.class) return (T)(Float)(float)toNumber(ctx, obj);
|
if (clazz == Float.class || clazz == float.class) return (T)(Float)(float)toNumber(ext, obj);
|
||||||
if (clazz == Double.class || clazz == double.class) return (T)(Double)toNumber(ctx, obj);
|
if (clazz == Double.class || clazz == double.class) return (T)(Double)toNumber(ext, obj);
|
||||||
|
|
||||||
if (clazz == Character.class || clazz == char.class) {
|
if (clazz == Character.class || clazz == char.class) {
|
||||||
if (obj instanceof Number) return (T)(Character)(char)number(obj);
|
if (obj instanceof Number) return (T)(Character)(char)number(obj);
|
||||||
else {
|
else {
|
||||||
var res = toString(ctx, obj);
|
var res = toString(ext, obj);
|
||||||
if (res.length() == 0) throw new ConvertException("\"\"", "Character");
|
if (res.length() == 0) throw new ConvertException("\"\"", "Character");
|
||||||
else return (T)(Character)res.charAt(0);
|
else return (T)(Character)res.charAt(0);
|
||||||
}
|
}
|
||||||
@ -535,23 +537,23 @@ public class Values {
|
|||||||
if (obj == null) return null;
|
if (obj == null) return null;
|
||||||
if (clazz.isInstance(obj)) return (T)obj;
|
if (clazz.isInstance(obj)) return (T)obj;
|
||||||
if (clazz.isAssignableFrom(NativeWrapper.class)) {
|
if (clazz.isAssignableFrom(NativeWrapper.class)) {
|
||||||
return (T)NativeWrapper.of(ctx, obj);
|
return (T)NativeWrapper.of(ext, obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new ConvertException(type(obj), clazz.getSimpleName());
|
throw new ConvertException(type(obj), clazz.getSimpleName());
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Iterable<Object> fromJSIterator(Context ctx, Object obj) {
|
public static Iterable<Object> fromJSIterator(Extensions ext, Object obj) {
|
||||||
return () -> {
|
return () -> {
|
||||||
try {
|
try {
|
||||||
var symbol = Symbol.get("Symbol.iterator");
|
var symbol = Symbol.get("Symbol.iterator");
|
||||||
|
|
||||||
var iteratorFunc = getMember(ctx, obj, symbol);
|
var iteratorFunc = getMember(ext, obj, symbol);
|
||||||
if (!(iteratorFunc instanceof FunctionValue)) return Collections.emptyIterator();
|
if (!(iteratorFunc instanceof FunctionValue)) return Collections.emptyIterator();
|
||||||
var iterator = iteratorFunc instanceof FunctionValue ?
|
var iterator = iteratorFunc instanceof FunctionValue ?
|
||||||
((FunctionValue)iteratorFunc).call(ctx, obj, obj) :
|
((FunctionValue)iteratorFunc).call(ext, obj, obj) :
|
||||||
iteratorFunc;
|
iteratorFunc;
|
||||||
var nextFunc = getMember(ctx, call(ctx, iteratorFunc, obj), "next");
|
var nextFunc = getMember(ext, call(ext, iteratorFunc, obj), "next");
|
||||||
|
|
||||||
if (!(nextFunc instanceof FunctionValue)) return Collections.emptyIterator();
|
if (!(nextFunc instanceof FunctionValue)) return Collections.emptyIterator();
|
||||||
|
|
||||||
@ -563,11 +565,11 @@ public class Values {
|
|||||||
private void loadNext() {
|
private void loadNext() {
|
||||||
if (next == null) value = null;
|
if (next == null) value = null;
|
||||||
else if (consumed) {
|
else if (consumed) {
|
||||||
var curr = next.call(ctx, iterator);
|
var curr = next.call(ext, iterator);
|
||||||
if (curr == null) { next = null; value = null; }
|
if (curr == null) { next = null; value = null; }
|
||||||
if (toBoolean(Values.getMember(ctx, curr, "done"))) { next = null; value = null; }
|
if (toBoolean(Values.getMember(ext, curr, "done"))) { next = null; value = null; }
|
||||||
else {
|
else {
|
||||||
this.value = Values.getMember(ctx, curr, "value");
|
this.value = Values.getMember(ext, curr, "value");
|
||||||
consumed = false;
|
consumed = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -594,17 +596,17 @@ public class Values {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ObjectValue toJSIterator(Context ctx, Iterator<?> it) {
|
public static ObjectValue toJSIterator(Extensions ext, Iterator<?> it) {
|
||||||
var res = new ObjectValue();
|
var res = new ObjectValue();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
var key = getMember(ctx, getMember(ctx, ctx.get(Environment.SYMBOL_PROTO), "constructor"), "iterator");
|
var key = getMember(ext, getMember(ext, ext.get(Environment.SYMBOL_PROTO), "constructor"), "iterator");
|
||||||
res.defineProperty(ctx, key, new NativeFunction("", args -> args.self));
|
res.defineProperty(ext, key, new NativeFunction("", args -> args.self));
|
||||||
}
|
}
|
||||||
catch (IllegalArgumentException | NullPointerException e) { }
|
catch (IllegalArgumentException | NullPointerException e) { }
|
||||||
|
|
||||||
res.defineProperty(ctx, "next", new NativeFunction("", args -> {
|
res.defineProperty(ext, "next", new NativeFunction("", args -> {
|
||||||
if (!it.hasNext()) return new ObjectValue(ctx, Map.of("done", true));
|
if (!it.hasNext()) return new ObjectValue(ext, Map.of("done", true));
|
||||||
else {
|
else {
|
||||||
var obj = new ObjectValue();
|
var obj = new ObjectValue();
|
||||||
obj.defineProperty(args.ctx, "value", it.next());
|
obj.defineProperty(args.ctx, "value", it.next());
|
||||||
@ -615,22 +617,22 @@ public class Values {
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ObjectValue toJSIterator(Context ctx, Iterable<?> it) {
|
public static ObjectValue toJSIterator(Extensions ext, Iterable<?> it) {
|
||||||
return toJSIterator(ctx, it.iterator());
|
return toJSIterator(ext, it.iterator());
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ObjectValue toJSAsyncIterator(Context ctx, Iterator<?> it) {
|
public static ObjectValue toJSAsyncIterator(Extensions ext, Iterator<?> it) {
|
||||||
var res = new ObjectValue();
|
var res = new ObjectValue();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
var key = getMemberPath(ctx, ctx.get(Environment.SYMBOL_PROTO), "constructor", "asyncIterator");
|
var key = getMemberPath(ext, ext.get(Environment.SYMBOL_PROTO), "constructor", "asyncIterator");
|
||||||
res.defineProperty(ctx, key, new NativeFunction("", args -> args.self));
|
res.defineProperty(ext, key, new NativeFunction("", args -> args.self));
|
||||||
}
|
}
|
||||||
catch (IllegalArgumentException | NullPointerException e) { }
|
catch (IllegalArgumentException | NullPointerException e) { }
|
||||||
|
|
||||||
res.defineProperty(ctx, "next", new NativeFunction("", args -> {
|
res.defineProperty(ext, "next", new NativeFunction("", args -> {
|
||||||
return PromiseLib.await(args.ctx, () -> {
|
return PromiseLib.await(args.ctx, () -> {
|
||||||
if (!it.hasNext()) return new ObjectValue(ctx, Map.of("done", true));
|
if (!it.hasNext()) return new ObjectValue(ext, Map.of("done", true));
|
||||||
else {
|
else {
|
||||||
var obj = new ObjectValue();
|
var obj = new ObjectValue();
|
||||||
obj.defineProperty(args.ctx, "value", it.next());
|
obj.defineProperty(args.ctx, "value", it.next());
|
||||||
@ -652,14 +654,14 @@ public class Values {
|
|||||||
if (protoObj.values.size() + protoObj.properties.size() != 1) return false;
|
if (protoObj.values.size() + protoObj.properties.size() != 1) return false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
private static String toReadable(Context ctx, Object val, HashSet<Object> passed, int tab) {
|
private static String toReadable(Extensions ext, Object val, HashSet<Object> passed, int tab) {
|
||||||
if (tab == 0 && val instanceof String) return (String)val;
|
if (tab == 0 && val instanceof String) return (String)val;
|
||||||
|
|
||||||
if (passed.contains(val)) return "[circular]";
|
if (passed.contains(val)) return "[circular]";
|
||||||
|
|
||||||
var printed = true;
|
var printed = true;
|
||||||
var res = new StringBuilder();
|
var res = new StringBuilder();
|
||||||
var dbg = DebugContext.get(ctx);
|
var dbg = DebugContext.get(ext);
|
||||||
|
|
||||||
if (val instanceof FunctionValue) {
|
if (val instanceof FunctionValue) {
|
||||||
res.append(val.toString());
|
res.append(val.toString());
|
||||||
@ -673,7 +675,7 @@ public class Values {
|
|||||||
for (int i = 0; i < obj.size(); i++) {
|
for (int i = 0; i < obj.size(); i++) {
|
||||||
if (i != 0) res.append(", ");
|
if (i != 0) res.append(", ");
|
||||||
else res.append(" ");
|
else res.append(" ");
|
||||||
if (obj.has(i)) res.append(toReadable(ctx, obj.get(i), passed, tab));
|
if (obj.has(i)) res.append(toReadable(ext, obj.get(i), passed, tab));
|
||||||
else res.append("<empty>");
|
else res.append("<empty>");
|
||||||
}
|
}
|
||||||
res.append(" ] ");
|
res.append(" ] ");
|
||||||
@ -700,14 +702,14 @@ public class Values {
|
|||||||
|
|
||||||
for (var el : obj.values.entrySet()) {
|
for (var el : obj.values.entrySet()) {
|
||||||
for (int i = 0; i < tab + 1; i++) res.append(" ");
|
for (int i = 0; i < tab + 1; i++) res.append(" ");
|
||||||
res.append(toReadable(ctx, el.getKey(), passed, tab + 1));
|
res.append(toReadable(ext, el.getKey(), passed, tab + 1));
|
||||||
res.append(": ");
|
res.append(": ");
|
||||||
res.append(toReadable(ctx, el.getValue(), passed, tab + 1));
|
res.append(toReadable(ext, el.getValue(), passed, tab + 1));
|
||||||
res.append(",\n");
|
res.append(",\n");
|
||||||
}
|
}
|
||||||
for (var el : obj.properties.entrySet()) {
|
for (var el : obj.properties.entrySet()) {
|
||||||
for (int i = 0; i < tab + 1; i++) res.append(" ");
|
for (int i = 0; i < tab + 1; i++) res.append(" ");
|
||||||
res.append(toReadable(ctx, el.getKey(), passed, tab + 1));
|
res.append(toReadable(ext, el.getKey(), passed, tab + 1));
|
||||||
res.append(": [prop],\n");
|
res.append(": [prop],\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -720,23 +722,23 @@ public class Values {
|
|||||||
else if (val == null) return "undefined";
|
else if (val == null) return "undefined";
|
||||||
else if (val == Values.NULL) return "null";
|
else if (val == Values.NULL) return "null";
|
||||||
else if (val instanceof String) return "'" + val + "'";
|
else if (val instanceof String) return "'" + val + "'";
|
||||||
else return Values.toString(ctx, val);
|
else return Values.toString(ext, val);
|
||||||
|
|
||||||
return res.toString();
|
return res.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String toReadable(Context ctx, Object val) {
|
public static String toReadable(Extensions ext, Object val) {
|
||||||
return toReadable(ctx, val, new HashSet<>(), 0);
|
return toReadable(ext, val, new HashSet<>(), 0);
|
||||||
}
|
}
|
||||||
public static String errorToReadable(RuntimeException err, String prefix) {
|
public static String errorToReadable(RuntimeException err, String prefix) {
|
||||||
prefix = prefix == null ? "Uncaught" : "Uncaught " + prefix;
|
prefix = prefix == null ? "Uncaught" : "Uncaught " + prefix;
|
||||||
if (err instanceof EngineException) {
|
if (err instanceof EngineException) {
|
||||||
var ee = ((EngineException)err);
|
var ee = ((EngineException)err);
|
||||||
try {
|
try {
|
||||||
return prefix + " " + ee.toString(new Context(ee.env));
|
return prefix + " " + ee.toString(ee.ext);
|
||||||
}
|
}
|
||||||
catch (EngineException ex) {
|
catch (EngineException ex) {
|
||||||
return prefix + " " + toReadable(new Context(ee.env), ee.value);
|
return prefix + " " + toReadable(ee.ext, ee.value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (err instanceof SyntaxException) {
|
else if (err instanceof SyntaxException) {
|
||||||
@ -750,8 +752,8 @@ public class Values {
|
|||||||
return prefix + " internal error " + str.toString();
|
return prefix + " internal error " + str.toString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public static void printValue(Context ctx, Object val) {
|
public static void printValue(Extensions ext, Object val) {
|
||||||
System.out.print(toReadable(ctx, val));
|
System.out.print(toReadable(ext, val));
|
||||||
}
|
}
|
||||||
public static void printError(RuntimeException err, String prefix) {
|
public static void printError(RuntimeException err, String prefix) {
|
||||||
System.out.println(errorToReadable(err, prefix));
|
System.out.println(errorToReadable(err, prefix));
|
||||||
|
@ -27,6 +27,7 @@ import me.topchetoeu.jscript.runtime.Context;
|
|||||||
import me.topchetoeu.jscript.runtime.Engine;
|
import me.topchetoeu.jscript.runtime.Engine;
|
||||||
import me.topchetoeu.jscript.runtime.Environment;
|
import me.topchetoeu.jscript.runtime.Environment;
|
||||||
import me.topchetoeu.jscript.runtime.EventLoop;
|
import me.topchetoeu.jscript.runtime.EventLoop;
|
||||||
|
import me.topchetoeu.jscript.runtime.Extensions;
|
||||||
import me.topchetoeu.jscript.runtime.Frame;
|
import me.topchetoeu.jscript.runtime.Frame;
|
||||||
import me.topchetoeu.jscript.runtime.debug.DebugContext;
|
import me.topchetoeu.jscript.runtime.debug.DebugContext;
|
||||||
import me.topchetoeu.jscript.runtime.exceptions.EngineException;
|
import me.topchetoeu.jscript.runtime.exceptions.EngineException;
|
||||||
@ -149,7 +150,7 @@ public class SimpleDebugger implements Debugger {
|
|||||||
this.frame = frame;
|
this.frame = frame;
|
||||||
this.id = id;
|
this.id = id;
|
||||||
|
|
||||||
this.global = frame.function.environment.global.obj;
|
this.global = GlobalScope.get(frame.ctx).obj;
|
||||||
this.local = frame.getLocalScope();
|
this.local = frame.getLocalScope();
|
||||||
this.capture = frame.getCaptureScope();
|
this.capture = frame.getCaptureScope();
|
||||||
Values.makePrototypeChain(frame.ctx, global, capture, local);
|
Values.makePrototypeChain(frame.ctx, global, capture, local);
|
||||||
@ -162,29 +163,29 @@ public class SimpleDebugger implements Debugger {
|
|||||||
.add(new JSONMap()
|
.add(new JSONMap()
|
||||||
.set("type", "local")
|
.set("type", "local")
|
||||||
.set("name", "Local Scope")
|
.set("name", "Local Scope")
|
||||||
.set("object", serializeObj(frame.ctx.environment, local))
|
.set("object", serializeObj(frame.ctx, local))
|
||||||
)
|
)
|
||||||
.add(new JSONMap()
|
.add(new JSONMap()
|
||||||
.set("type", "closure")
|
.set("type", "closure")
|
||||||
.set("name", "Closure")
|
.set("name", "Closure")
|
||||||
.set("object", serializeObj(frame.ctx.environment, capture))
|
.set("object", serializeObj(frame.ctx, capture))
|
||||||
)
|
)
|
||||||
.add(new JSONMap()
|
.add(new JSONMap()
|
||||||
.set("type", "global")
|
.set("type", "global")
|
||||||
.set("name", "Global Scope")
|
.set("name", "Global Scope")
|
||||||
.set("object", serializeObj(frame.ctx.environment, global))
|
.set("object", serializeObj(frame.ctx.extensions, global))
|
||||||
)
|
)
|
||||||
.add(new JSONMap()
|
.add(new JSONMap()
|
||||||
.set("type", "other")
|
.set("type", "other")
|
||||||
.set("name", "Value Stack")
|
.set("name", "Value Stack")
|
||||||
.set("object", serializeObj(frame.ctx.environment, valstack))
|
.set("object", serializeObj(frame.ctx.extensions, valstack))
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private class ObjRef {
|
private class ObjRef {
|
||||||
public final ObjectValue obj;
|
public final ObjectValue obj;
|
||||||
public final Environment env;
|
public final Extensions ext;
|
||||||
public final HashSet<String> heldGroups = new HashSet<>();
|
public final HashSet<String> heldGroups = new HashSet<>();
|
||||||
public boolean held = true;
|
public boolean held = true;
|
||||||
|
|
||||||
@ -192,19 +193,19 @@ public class SimpleDebugger implements Debugger {
|
|||||||
return !held && heldGroups.size() == 0;
|
return !held && heldGroups.size() == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ObjRef(Environment env, ObjectValue obj) {
|
public ObjRef(Extensions ext, ObjectValue obj) {
|
||||||
this.env = env;
|
this.ext = ext;
|
||||||
this.obj = obj;
|
this.obj = obj;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class RunResult {
|
private static class RunResult {
|
||||||
public final Environment ctx;
|
public final Extensions ext;
|
||||||
public final Object result;
|
public final Object result;
|
||||||
public final EngineException error;
|
public final EngineException error;
|
||||||
|
|
||||||
public RunResult(Environment env, Object result, EngineException error) {
|
public RunResult(Extensions ext, Object result, EngineException error) {
|
||||||
this.ctx = env;
|
this.ext = ext;
|
||||||
this.result = result;
|
this.result = result;
|
||||||
this.error = error;
|
this.error = error;
|
||||||
}
|
}
|
||||||
@ -338,10 +339,10 @@ public class SimpleDebugger implements Debugger {
|
|||||||
.set("columnNumber", loc.start() - 1);
|
.set("columnNumber", loc.start() - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
private JSONMap serializeObj(Environment env, Object val, boolean byValue) {
|
private JSONMap serializeObj(Extensions env, Object val, boolean byValue) {
|
||||||
val = Values.normalize(null, val);
|
val = Values.normalize(null, val);
|
||||||
env = sanitizeEnvironment(env);
|
env = sanitizeEnvironment(env);
|
||||||
var ctx = env.context();
|
var ctx = Context.of(env);
|
||||||
|
|
||||||
if (val == Values.NULL) {
|
if (val == Values.NULL) {
|
||||||
return new JSONMap()
|
return new JSONMap()
|
||||||
@ -400,7 +401,7 @@ public class SimpleDebugger implements Debugger {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (byValue) try { res.put("value", JSON.fromJs(env.context(), obj)); }
|
if (byValue) try { res.put("value", JSON.fromJs(env, obj)); }
|
||||||
catch (Exception e) { }
|
catch (Exception e) { }
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
@ -426,8 +427,8 @@ public class SimpleDebugger implements Debugger {
|
|||||||
|
|
||||||
throw new IllegalArgumentException("Unexpected JS object.");
|
throw new IllegalArgumentException("Unexpected JS object.");
|
||||||
}
|
}
|
||||||
private JSONMap serializeObj(Environment env, Object val) {
|
private JSONMap serializeObj(Extensions ext, Object val) {
|
||||||
return serializeObj(env, val, false);
|
return serializeObj(ext, val, false);
|
||||||
}
|
}
|
||||||
private void addObjectGroup(String name, Object val) {
|
private void addObjectGroup(String name, Object val) {
|
||||||
if (val instanceof ObjectValue) {
|
if (val instanceof ObjectValue) {
|
||||||
@ -466,11 +467,11 @@ public class SimpleDebugger implements Debugger {
|
|||||||
else return JSON.toJs(res);
|
else return JSON.toJs(res);
|
||||||
}
|
}
|
||||||
|
|
||||||
private JSONMap serializeException(Environment env, EngineException err) {
|
private JSONMap serializeException(Extensions ext, EngineException err) {
|
||||||
String text = null;
|
String text = null;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
text = Values.toString(env.context(), err.value);
|
text = Values.toString(Context.of(ext), err.value);
|
||||||
}
|
}
|
||||||
catch (EngineException e) {
|
catch (EngineException e) {
|
||||||
text = "[error while stringifying]";
|
text = "[error while stringifying]";
|
||||||
@ -478,7 +479,7 @@ public class SimpleDebugger implements Debugger {
|
|||||||
|
|
||||||
var res = new JSONMap()
|
var res = new JSONMap()
|
||||||
.set("exceptionId", nextId())
|
.set("exceptionId", nextId())
|
||||||
.set("exception", serializeObj(env, err.value))
|
.set("exception", serializeObj(ext, err.value))
|
||||||
.set("text", text);
|
.set("text", text);
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
@ -539,8 +540,8 @@ public class SimpleDebugger implements Debugger {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Environment sanitizeEnvironment(Environment env) {
|
private Extensions sanitizeEnvironment(Extensions ext) {
|
||||||
var res = env.child();
|
var res = ext.child();
|
||||||
|
|
||||||
res.remove(EventLoop.KEY);
|
res.remove(EventLoop.KEY);
|
||||||
res.remove(DebugContext.KEY);
|
res.remove(DebugContext.KEY);
|
||||||
@ -552,12 +553,13 @@ public class SimpleDebugger implements Debugger {
|
|||||||
private RunResult run(DebugFrame codeFrame, String code) {
|
private RunResult run(DebugFrame codeFrame, String code) {
|
||||||
if (codeFrame == null) return new RunResult(null, code, new EngineException("Invalid code frame!"));
|
if (codeFrame == null) return new RunResult(null, code, new EngineException("Invalid code frame!"));
|
||||||
var engine = new Engine();
|
var engine = new Engine();
|
||||||
var env = codeFrame.frame.ctx.environment.copy();
|
var env = codeFrame.frame.ctx.extensions.copy();
|
||||||
|
|
||||||
env.global = new GlobalScope(codeFrame.local);
|
|
||||||
env.remove(EventLoop.KEY);
|
|
||||||
env.remove(DebugContext.KEY);
|
env.remove(DebugContext.KEY);
|
||||||
|
env.remove(EventLoop.KEY);
|
||||||
|
env.remove(GlobalScope.KEY);
|
||||||
env.add(EventLoop.KEY, engine);
|
env.add(EventLoop.KEY, engine);
|
||||||
|
env.add(GlobalScope.KEY, new GlobalScope(codeFrame.local));
|
||||||
|
|
||||||
var awaiter = engine.pushMsg(false, env, new Filename("jscript", "eval"), code, codeFrame.frame.thisArg, codeFrame.frame.args);
|
var awaiter = engine.pushMsg(false, env, new Filename("jscript", "eval"), code, codeFrame.frame.thisArg, codeFrame.frame.args);
|
||||||
|
|
||||||
@ -569,12 +571,12 @@ public class SimpleDebugger implements Debugger {
|
|||||||
catch (SyntaxException e) { return new RunResult(env, null, EngineException.ofSyntax(e.toString())); }
|
catch (SyntaxException e) { return new RunResult(env, null, EngineException.ofSyntax(e.toString())); }
|
||||||
}
|
}
|
||||||
|
|
||||||
private ObjectValue vscodeAutoSuggest(Environment env, Object target, String query, boolean variable) {
|
private ObjectValue vscodeAutoSuggest(Extensions ext, Object target, String query, boolean variable) {
|
||||||
var res = new ArrayValue();
|
var res = new ArrayValue();
|
||||||
var passed = new HashSet<String>();
|
var passed = new HashSet<String>();
|
||||||
var tildas = "~";
|
var tildas = "~";
|
||||||
var ctx = env.context();
|
var ctx = Context.of(ext);
|
||||||
if (target == null) target = env.global;
|
if (target == null) target = GlobalScope.get(ext);
|
||||||
|
|
||||||
for (var proto = target; proto != null && proto != Values.NULL; proto = Values.getPrototype(ctx, proto)) {
|
for (var proto = target; proto != null && proto != Values.NULL; proto = Values.getPrototype(ctx, proto)) {
|
||||||
for (var el : Values.getMembers(ctx, proto, true, true)) {
|
for (var el : Values.getMembers(ctx, proto, true, true)) {
|
||||||
@ -827,8 +829,8 @@ public class SimpleDebugger implements Debugger {
|
|||||||
|
|
||||||
if (group != null) addObjectGroup(group, res.result);
|
if (group != null) addObjectGroup(group, res.result);
|
||||||
|
|
||||||
if (res.error != null) ws.send(msg.respond(new JSONMap().set("exceptionDetails", serializeException(res.ctx, res.error))));
|
if (res.error != null) ws.send(msg.respond(new JSONMap().set("exceptionDetails", serializeException(res.ext, res.error))));
|
||||||
else ws.send(msg.respond(new JSONMap().set("result", serializeObj(res.ctx, res.result))));
|
else ws.send(msg.respond(new JSONMap().set("result", serializeObj(res.ext, res.result))));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override public synchronized void releaseObjectGroup(V8Message msg) throws IOException {
|
@Override public synchronized void releaseObjectGroup(V8Message msg) throws IOException {
|
||||||
@ -851,8 +853,8 @@ public class SimpleDebugger implements Debugger {
|
|||||||
@Override public synchronized void getProperties(V8Message msg) throws IOException {
|
@Override public synchronized void getProperties(V8Message msg) throws IOException {
|
||||||
var ref = idToObject.get(Integer.parseInt(msg.params.string("objectId")));
|
var ref = idToObject.get(Integer.parseInt(msg.params.string("objectId")));
|
||||||
var obj = ref.obj;
|
var obj = ref.obj;
|
||||||
var env = ref.env;
|
var ext = ref.ext;
|
||||||
var ctx = env.context();
|
var ctx = Context.of(ext);
|
||||||
var res = new JSONList();
|
var res = new JSONList();
|
||||||
var own = true;
|
var own = true;
|
||||||
|
|
||||||
@ -865,8 +867,8 @@ public class SimpleDebugger implements Debugger {
|
|||||||
var prop = obj.properties.get(key);
|
var prop = obj.properties.get(key);
|
||||||
|
|
||||||
propDesc.set("name", Values.toString(ctx, key));
|
propDesc.set("name", Values.toString(ctx, key));
|
||||||
if (prop.getter != null) propDesc.set("get", serializeObj(env, prop.getter));
|
if (prop.getter != null) propDesc.set("get", serializeObj(ext, prop.getter));
|
||||||
if (prop.setter != null) propDesc.set("set", serializeObj(env, prop.setter));
|
if (prop.setter != null) propDesc.set("set", serializeObj(ext, prop.setter));
|
||||||
propDesc.set("enumerable", obj.memberEnumerable(key));
|
propDesc.set("enumerable", obj.memberEnumerable(key));
|
||||||
propDesc.set("configurable", obj.memberConfigurable(key));
|
propDesc.set("configurable", obj.memberConfigurable(key));
|
||||||
propDesc.set("isOwn", true);
|
propDesc.set("isOwn", true);
|
||||||
@ -874,7 +876,7 @@ public class SimpleDebugger implements Debugger {
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
propDesc.set("name", Values.toString(ctx, key));
|
propDesc.set("name", Values.toString(ctx, key));
|
||||||
propDesc.set("value", serializeObj(env, Values.getMember(ctx, obj, key)));
|
propDesc.set("value", serializeObj(ext, Values.getMember(ctx, obj, key)));
|
||||||
propDesc.set("writable", obj.memberWritable(key));
|
propDesc.set("writable", obj.memberWritable(key));
|
||||||
propDesc.set("enumerable", obj.memberEnumerable(key));
|
propDesc.set("enumerable", obj.memberEnumerable(key));
|
||||||
propDesc.set("configurable", obj.memberConfigurable(key));
|
propDesc.set("configurable", obj.memberConfigurable(key));
|
||||||
@ -888,7 +890,7 @@ public class SimpleDebugger implements Debugger {
|
|||||||
if (own) {
|
if (own) {
|
||||||
var protoDesc = new JSONMap();
|
var protoDesc = new JSONMap();
|
||||||
protoDesc.set("name", "__proto__");
|
protoDesc.set("name", "__proto__");
|
||||||
protoDesc.set("value", serializeObj(env, proto == null ? Values.NULL : proto));
|
protoDesc.set("value", serializeObj(ext, proto == null ? Values.NULL : proto));
|
||||||
protoDesc.set("writable", true);
|
protoDesc.set("writable", true);
|
||||||
protoDesc.set("enumerable", false);
|
protoDesc.set("enumerable", false);
|
||||||
protoDesc.set("configurable", false);
|
protoDesc.set("configurable", false);
|
||||||
@ -915,8 +917,8 @@ public class SimpleDebugger implements Debugger {
|
|||||||
|
|
||||||
var thisArgRef = idToObject.get(Integer.parseInt(msg.params.string("objectId")));
|
var thisArgRef = idToObject.get(Integer.parseInt(msg.params.string("objectId")));
|
||||||
var thisArg = thisArgRef.obj;
|
var thisArg = thisArgRef.obj;
|
||||||
var env = thisArgRef.env;
|
var ext = thisArgRef.ext;
|
||||||
var ctx = env.context();
|
var ctx = Context.of(ext);
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
var start = src.lastIndexOf("//# sourceURL=");
|
var start = src.lastIndexOf("//# sourceURL=");
|
||||||
@ -939,20 +941,20 @@ public class SimpleDebugger implements Debugger {
|
|||||||
}
|
}
|
||||||
else if (compare(src, VSCODE_CALL)) {
|
else if (compare(src, VSCODE_CALL)) {
|
||||||
var func = (FunctionValue)(args.size() < 1 ? null : args.get(0));
|
var func = (FunctionValue)(args.size() < 1 ? null : args.get(0));
|
||||||
ws.send(msg.respond(new JSONMap().set("result", serializeObj(env, func.call(ctx, thisArg)))));
|
ws.send(msg.respond(new JSONMap().set("result", serializeObj(ext, func.call(ctx, thisArg)))));
|
||||||
}
|
}
|
||||||
else if (compare(src, VSCODE_AUTOCOMPLETE)) {
|
else if (compare(src, VSCODE_AUTOCOMPLETE)) {
|
||||||
var target = args.get(0);
|
var target = args.get(0);
|
||||||
if (target == null) target = thisArg;
|
if (target == null) target = thisArg;
|
||||||
res = vscodeAutoSuggest(env, target, Values.toString(ctx, args.get(1)), Values.toBoolean(args.get(2)));
|
res = vscodeAutoSuggest(ext, target, Values.toString(ctx, args.get(1)), Values.toBoolean(args.get(2)));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
ws.send(new V8Error("Please use well-known functions with callFunctionOn"));
|
ws.send(new V8Error("Please use well-known functions with callFunctionOn"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
ws.send(msg.respond(new JSONMap().set("result", serializeObj(env, res, byValue))));
|
ws.send(msg.respond(new JSONMap().set("result", serializeObj(ext, res, byValue))));
|
||||||
}
|
}
|
||||||
catch (EngineException e) { ws.send(msg.respond(new JSONMap().set("exceptionDetails", serializeException(env, e)))); }
|
catch (EngineException e) { ws.send(msg.respond(new JSONMap().set("exceptionDetails", serializeException(ext, e)))); }
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override public synchronized void runtimeEnable(V8Message msg) throws IOException {
|
@Override public synchronized void runtimeEnable(V8Message msg) throws IOException {
|
||||||
|
@ -3,14 +3,32 @@ package me.topchetoeu.jscript.utils.interop;
|
|||||||
import java.lang.reflect.Array;
|
import java.lang.reflect.Array;
|
||||||
|
|
||||||
import me.topchetoeu.jscript.runtime.Context;
|
import me.topchetoeu.jscript.runtime.Context;
|
||||||
|
import me.topchetoeu.jscript.runtime.Extensions;
|
||||||
|
import me.topchetoeu.jscript.runtime.Key;
|
||||||
import me.topchetoeu.jscript.runtime.values.NativeWrapper;
|
import me.topchetoeu.jscript.runtime.values.NativeWrapper;
|
||||||
import me.topchetoeu.jscript.runtime.values.Values;
|
import me.topchetoeu.jscript.runtime.values.Values;
|
||||||
|
|
||||||
public class Arguments {
|
public class Arguments implements Extensions {
|
||||||
public final Object self;
|
public final Object self;
|
||||||
public final Object[] args;
|
public final Object[] args;
|
||||||
public final Context ctx;
|
public final Context ctx;
|
||||||
|
|
||||||
|
@Override public <T> void add(Key<T> key, T obj) {
|
||||||
|
ctx.add(key, obj);
|
||||||
|
}
|
||||||
|
@Override public <T> T get(Key<T> key) {
|
||||||
|
return ctx.get(key);
|
||||||
|
}
|
||||||
|
@Override public boolean has(Key<?> key) {
|
||||||
|
return ctx.has(key);
|
||||||
|
}
|
||||||
|
@Override public boolean remove(Key<?> key) {
|
||||||
|
return ctx.remove(key);
|
||||||
|
}
|
||||||
|
@Override public Iterable<Key<?>> keys() {
|
||||||
|
return ctx.keys();
|
||||||
|
}
|
||||||
|
|
||||||
public int n() {
|
public int n() {
|
||||||
return args.length;
|
return args.length;
|
||||||
}
|
}
|
||||||
|
@ -11,8 +11,9 @@ import java.util.stream.Collectors;
|
|||||||
|
|
||||||
import me.topchetoeu.jscript.common.Location;
|
import me.topchetoeu.jscript.common.Location;
|
||||||
import me.topchetoeu.jscript.runtime.Context;
|
import me.topchetoeu.jscript.runtime.Context;
|
||||||
import me.topchetoeu.jscript.runtime.Environment;
|
import me.topchetoeu.jscript.runtime.Copyable;
|
||||||
import me.topchetoeu.jscript.runtime.WrapperProvider;
|
import me.topchetoeu.jscript.runtime.Extensions;
|
||||||
|
import me.topchetoeu.jscript.runtime.Key;
|
||||||
import me.topchetoeu.jscript.runtime.exceptions.EngineException;
|
import me.topchetoeu.jscript.runtime.exceptions.EngineException;
|
||||||
import me.topchetoeu.jscript.runtime.exceptions.InterruptException;
|
import me.topchetoeu.jscript.runtime.exceptions.InterruptException;
|
||||||
import me.topchetoeu.jscript.runtime.values.FunctionValue;
|
import me.topchetoeu.jscript.runtime.values.FunctionValue;
|
||||||
@ -21,7 +22,9 @@ import me.topchetoeu.jscript.runtime.values.ObjectValue;
|
|||||||
import me.topchetoeu.jscript.runtime.values.Symbol;
|
import me.topchetoeu.jscript.runtime.values.Symbol;
|
||||||
import me.topchetoeu.jscript.runtime.values.Values;
|
import me.topchetoeu.jscript.runtime.values.Values;
|
||||||
|
|
||||||
public class NativeWrapperProvider implements WrapperProvider {
|
public class NativeWrapperProvider implements Copyable {
|
||||||
|
public static final Key<NativeWrapperProvider> KEY = new Key<>();
|
||||||
|
|
||||||
private final HashMap<Class<?>, FunctionValue> constructors = new HashMap<>();
|
private final HashMap<Class<?>, FunctionValue> constructors = new HashMap<>();
|
||||||
private final HashMap<Class<?>, ObjectValue> prototypes = new HashMap<>();
|
private final HashMap<Class<?>, ObjectValue> prototypes = new HashMap<>();
|
||||||
private final HashMap<Class<?>, ObjectValue> namespaces = new HashMap<>();
|
private final HashMap<Class<?>, ObjectValue> namespaces = new HashMap<>();
|
||||||
@ -298,8 +301,8 @@ public class NativeWrapperProvider implements WrapperProvider {
|
|||||||
var parentConstr = getConstr(parent);
|
var parentConstr = getConstr(parent);
|
||||||
|
|
||||||
if (parentProto != null && parentConstr != null) {
|
if (parentProto != null && parentConstr != null) {
|
||||||
Values.setPrototype(Context.NULL, proto, parentProto);
|
Values.setPrototype(Extensions.EMPTY, proto, parentProto);
|
||||||
Values.setPrototype(Context.NULL, constr, parentConstr);
|
Values.setPrototype(Extensions.EMPTY, constr, parentConstr);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -371,11 +374,13 @@ public class NativeWrapperProvider implements WrapperProvider {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override public WrapperProvider fork(Environment env) {
|
public NativeWrapperProvider copy() {
|
||||||
var res = new NativeWrapperProvider();
|
var res = new NativeWrapperProvider();
|
||||||
|
|
||||||
for (var pair : classToProxy.entrySet()) {
|
for (var pair : classToProxy.entrySet()) {
|
||||||
res.set(pair.getKey(), pair.getValue());
|
res.set(pair.getKey(), pair.getValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -409,4 +414,8 @@ public class NativeWrapperProvider implements WrapperProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public NativeWrapperProvider() { }
|
public NativeWrapperProvider() { }
|
||||||
|
|
||||||
|
public static NativeWrapperProvider get(Extensions ext) {
|
||||||
|
return ext.get(KEY);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,7 +25,7 @@ public interface ModuleRepo {
|
|||||||
|
|
||||||
if (modules.containsKey(name)) return modules.get(name);
|
if (modules.containsKey(name)) return modules.get(name);
|
||||||
|
|
||||||
var env = ctx.environment.child();
|
var env = ctx.extensions.child();
|
||||||
env.add(CWD, fs.normalize(name, ".."));
|
env.add(CWD, fs.normalize(name, ".."));
|
||||||
|
|
||||||
var mod = new SourceModule(filename, src, env);
|
var mod = new SourceModule(filename, src, env);
|
||||||
|
@ -2,22 +2,22 @@ package me.topchetoeu.jscript.utils.modules;
|
|||||||
|
|
||||||
import me.topchetoeu.jscript.common.Filename;
|
import me.topchetoeu.jscript.common.Filename;
|
||||||
import me.topchetoeu.jscript.runtime.Context;
|
import me.topchetoeu.jscript.runtime.Context;
|
||||||
import me.topchetoeu.jscript.runtime.Environment;
|
import me.topchetoeu.jscript.runtime.Extensions;
|
||||||
|
|
||||||
public class SourceModule extends Module {
|
public class SourceModule extends Module {
|
||||||
public final Filename filename;
|
public final Filename filename;
|
||||||
public final String source;
|
public final String source;
|
||||||
public final Environment env;
|
public final Extensions ext;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Object onLoad(Context ctx) {
|
protected Object onLoad(Context ctx) {
|
||||||
var res = new Context(env).compile(filename, source);
|
var res = new Context(ext).compile(filename, source);
|
||||||
return res.call(ctx);
|
return res.call(ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
public SourceModule(Filename filename, String source, Environment env) {
|
public SourceModule(Filename filename, String source, Extensions ext) {
|
||||||
this.filename = filename;
|
this.filename = filename;
|
||||||
this.source = source;
|
this.source = source;
|
||||||
this.env = env;
|
this.ext = ext;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user