refactor: clean up context and stack data
This commit is contained in:
parent
926b9c17d8
commit
517e3e6657
@ -7,7 +7,7 @@ import java.io.InputStreamReader;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
|
||||
import me.topchetoeu.jscript.engine.Message;
|
||||
import me.topchetoeu.jscript.engine.Context;
|
||||
import me.topchetoeu.jscript.engine.Engine;
|
||||
import me.topchetoeu.jscript.engine.Environment;
|
||||
import me.topchetoeu.jscript.engine.values.NativeFunction;
|
||||
@ -65,7 +65,7 @@ public class Main {
|
||||
env = new Environment(null, null, null);
|
||||
var exited = new boolean[1];
|
||||
|
||||
engine.pushMsg(false, new Message(engine), new NativeFunction((ctx, thisArg, _a) -> {
|
||||
engine.pushMsg(false, null, new NativeFunction((ctx, thisArg, _a) -> {
|
||||
new Internals().apply(env);
|
||||
|
||||
env.global.define("exit", _ctx -> {
|
||||
@ -94,7 +94,7 @@ public class Main {
|
||||
var raw = in.readLine();
|
||||
|
||||
if (raw == null) break;
|
||||
engine.pushMsg(false, env.context(new Message(engine)), "<stdio>", raw, null).toObservable().once(valuePrinter);
|
||||
engine.pushMsg(false, new Context(engine).pushEnv(env), "<stdio>", raw, null).toObservable().once(valuePrinter);
|
||||
}
|
||||
catch (EngineException e) {
|
||||
try {
|
||||
|
@ -1,27 +1,39 @@
|
||||
package me.topchetoeu.jscript.engine;
|
||||
|
||||
import java.util.Stack;
|
||||
|
||||
import me.topchetoeu.jscript.engine.values.FunctionValue;
|
||||
import me.topchetoeu.jscript.engine.values.Values;
|
||||
import me.topchetoeu.jscript.parsing.Parsing;
|
||||
|
||||
public class Context {
|
||||
public final Environment env;
|
||||
public final Message message;
|
||||
private final Stack<Environment> env = new Stack<>();
|
||||
public final Data data;
|
||||
public final Engine engine;
|
||||
|
||||
public Environment environment() {
|
||||
return env.empty() ? null : env.peek();
|
||||
}
|
||||
|
||||
public Context pushEnv(Environment env) {
|
||||
this.env.push(env);
|
||||
return this;
|
||||
}
|
||||
public void popEnv() {
|
||||
if (!env.empty()) this.env.pop();
|
||||
}
|
||||
|
||||
public FunctionValue compile(String filename, String raw) throws InterruptedException {
|
||||
var res = Values.toString(this, env.compile.call(this, null, raw, filename));
|
||||
return Parsing.compile(message.engine.functions, env, filename, res);
|
||||
var res = Values.toString(this, environment().compile.call(this, null, raw, filename));
|
||||
return Parsing.compile(engine.functions, environment(), filename, res);
|
||||
}
|
||||
|
||||
public Context setEnv(Environment env) {
|
||||
return new Context(env, message);
|
||||
public Context(Engine engine, Data data) {
|
||||
this.data = new Data(engine.data);
|
||||
if (data != null) this.data.addAll(data);
|
||||
this.engine = engine;
|
||||
}
|
||||
public Context setMsg(Message msg) {
|
||||
return new Context(env, msg);
|
||||
}
|
||||
|
||||
public Context(Environment env, Message msg) {
|
||||
this.env = env;
|
||||
this.message = msg;
|
||||
public Context(Engine engine) {
|
||||
this(engine, null);
|
||||
}
|
||||
}
|
||||
|
@ -1,43 +1,53 @@
|
||||
package me.topchetoeu.jscript.engine;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Map;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public class Data implements Iterable<Entry<DataKey<?>, ?>> {
|
||||
public class Data {
|
||||
public final Data parent;
|
||||
private HashMap<DataKey<Object>, Object> data = new HashMap<>();
|
||||
|
||||
public Data copy() {
|
||||
return new Data().addAll(this);
|
||||
}
|
||||
|
||||
public Data addAll(Iterable<Entry<DataKey<?>, ?>> data) {
|
||||
for (var el : data) {
|
||||
add((DataKey<Object>)el.getKey(), (Object)el.getValue());
|
||||
public Data addAll(Map<DataKey<?>, ?> data) {
|
||||
for (var el : data.entrySet()) {
|
||||
get((DataKey<Object>)el.getKey(), (Object)el.getValue());
|
||||
}
|
||||
return this;
|
||||
}
|
||||
public Data addAll(Data data) {
|
||||
for (var el : data.data.entrySet()) {
|
||||
get((DataKey<Object>)el.getKey(), (Object)el.getValue());
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public <T> T remove(DataKey<T> key) {
|
||||
return (T)data.remove(key);
|
||||
}
|
||||
public <T> Data set(DataKey<T> key, T val) {
|
||||
if (val == null) data.remove(key);
|
||||
else data.put((DataKey<Object>)key, (Object)val);
|
||||
data.put((DataKey<Object>)key, (Object)val);
|
||||
return this;
|
||||
}
|
||||
public <T> T add(DataKey<T> key, T val) {
|
||||
if (data.containsKey(key)) return (T)data.get(key);
|
||||
else {
|
||||
if (val == null) data.remove(key);
|
||||
else data.put((DataKey<Object>)key, (Object)val);
|
||||
return val;
|
||||
public <T> T get(DataKey<T> key, T val) {
|
||||
for (var it = this; it != null; it = it.parent) {
|
||||
if (it.data.containsKey(key)) {
|
||||
this.set(key, val);
|
||||
return (T)data.get((DataKey<Object>)key);
|
||||
}
|
||||
}
|
||||
|
||||
set(key, val);
|
||||
return val;
|
||||
}
|
||||
public <T> T get(DataKey<T> key) {
|
||||
return get(key, null);
|
||||
}
|
||||
public <T> T get(DataKey<T> key, T defaultVal) {
|
||||
if (!has(key)) return defaultVal;
|
||||
else return (T)data.get(key);
|
||||
for (var it = this; it != null; it = it.parent) {
|
||||
if (it.data.containsKey(key)) return (T)data.get((DataKey<Object>)key);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
public boolean has(DataKey<?> key) { return data.containsKey(key); }
|
||||
|
||||
@ -53,8 +63,10 @@ public class Data implements Iterable<Entry<DataKey<?>, ?>> {
|
||||
return increase(key, 1, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<Entry<DataKey<?>, ?>> iterator() {
|
||||
return (Iterator<Entry<DataKey<?>, ?>>)data.entrySet();
|
||||
public Data() {
|
||||
this.parent = null;
|
||||
}
|
||||
public Data(Data parent) {
|
||||
this.parent = parent;
|
||||
}
|
||||
}
|
||||
|
@ -13,19 +13,18 @@ public class Engine {
|
||||
private class UncompiledFunction extends FunctionValue {
|
||||
public final String filename;
|
||||
public final String raw;
|
||||
public final Environment env;
|
||||
private FunctionValue compiled = null;
|
||||
|
||||
@Override
|
||||
public Object call(Context ctx, Object thisArg, Object ...args) throws InterruptedException {
|
||||
ctx = ctx.setEnv(env);
|
||||
return ctx.compile(filename, raw).call(ctx, thisArg, args);
|
||||
if (compiled == null) compiled = ctx.compile(filename, raw);
|
||||
return compiled.call(ctx, thisArg, args);
|
||||
}
|
||||
|
||||
public UncompiledFunction(Environment env, String filename, String raw) {
|
||||
public UncompiledFunction(String filename, String raw) {
|
||||
super(filename, 0);
|
||||
this.filename = filename;
|
||||
this.raw = raw;
|
||||
this.env = env;
|
||||
}
|
||||
}
|
||||
|
||||
@ -34,10 +33,10 @@ public class Engine {
|
||||
public final Object thisArg;
|
||||
public final Object[] args;
|
||||
public final DataNotifier<Object> notifier = new DataNotifier<>();
|
||||
public final Message msg;
|
||||
public final Context ctx;
|
||||
|
||||
public Task(Message ctx, FunctionValue func, Object thisArg, Object[] args) {
|
||||
this.msg = ctx;
|
||||
public Task(Context ctx, FunctionValue func, Object thisArg, Object[] args) {
|
||||
this.ctx = ctx;
|
||||
this.func = func;
|
||||
this.thisArg = thisArg;
|
||||
this.args = args;
|
||||
@ -52,10 +51,11 @@ public class Engine {
|
||||
|
||||
public final int id = ++nextId;
|
||||
public final HashMap<Long, Instruction[]> functions = new HashMap<>();
|
||||
public final Data data = new Data().set(StackData.MAX_FRAMES, 10000);
|
||||
|
||||
private void runTask(Task task) throws InterruptedException {
|
||||
try {
|
||||
task.notifier.next(task.func.call(task.msg.context(null), task.thisArg, task.args));
|
||||
task.notifier.next(task.func.call(task.ctx, task.thisArg, task.args));
|
||||
}
|
||||
catch (InterruptedException e) {
|
||||
task.notifier.error(new RuntimeException(e));
|
||||
@ -105,17 +105,13 @@ public class Engine {
|
||||
return this.thread != null;
|
||||
}
|
||||
|
||||
public Awaitable<Object> pushMsg(boolean micro, Message ctx, FunctionValue func, Object thisArg, Object ...args) {
|
||||
var msg = new Task(ctx, func, thisArg, args);
|
||||
public Awaitable<Object> pushMsg(boolean micro, Context ctx, FunctionValue func, Object thisArg, Object ...args) {
|
||||
var msg = new Task(ctx == null ? new Context(this) : ctx, func, thisArg, args);
|
||||
if (micro) microTasks.addLast(msg);
|
||||
else macroTasks.addLast(msg);
|
||||
return msg.notifier;
|
||||
}
|
||||
public Awaitable<Object> pushMsg(boolean micro, Context ctx, String filename, String raw, Object thisArg, Object ...args) {
|
||||
return pushMsg(micro, ctx.message, new UncompiledFunction(ctx.env, filename, raw), thisArg, args);
|
||||
return pushMsg(micro, ctx, new UncompiledFunction(filename, raw), thisArg, args);
|
||||
}
|
||||
|
||||
// public Engine() {
|
||||
// this.typeRegister = new NativeTypeRegister();
|
||||
// }
|
||||
}
|
||||
|
@ -20,7 +20,7 @@ public class Environment {
|
||||
public final HashMap<String, Symbol> symbols = new HashMap<>();
|
||||
|
||||
public GlobalScope global;
|
||||
public WrappersProvider wrappersProvider;
|
||||
public WrappersProvider wrappers;
|
||||
|
||||
@Native public FunctionValue compile;
|
||||
@Native public FunctionValue regexConstructor = new NativeFunction("RegExp", (ctx, thisArg, args) -> {
|
||||
@ -57,7 +57,7 @@ public class Environment {
|
||||
}
|
||||
|
||||
@Native public Environment fork() {
|
||||
var res = new Environment(compile, wrappersProvider, global);
|
||||
var res = new Environment(compile, wrappers, global);
|
||||
res.regexConstructor = regexConstructor;
|
||||
res.prototypes = new HashMap<>(prototypes);
|
||||
return res;
|
||||
@ -68,8 +68,11 @@ public class Environment {
|
||||
return res;
|
||||
}
|
||||
|
||||
public Context context(Message msg) {
|
||||
return new Context(this, msg);
|
||||
public Context context(Engine engine, Data data) {
|
||||
return new Context(engine, data).pushEnv(this);
|
||||
}
|
||||
public Context context(Engine engine) {
|
||||
return new Context(engine).pushEnv(this);
|
||||
}
|
||||
|
||||
public Environment(FunctionValue compile, WrappersProvider nativeConverter, GlobalScope global) {
|
||||
@ -77,7 +80,7 @@ public class Environment {
|
||||
if (nativeConverter == null) nativeConverter = new NativeWrapperProvider(this);
|
||||
if (global == null) global = new GlobalScope();
|
||||
|
||||
this.wrappersProvider = nativeConverter;
|
||||
this.wrappers = nativeConverter;
|
||||
this.compile = compile;
|
||||
this.global = global;
|
||||
}
|
||||
|
@ -1,63 +0,0 @@
|
||||
package me.topchetoeu.jscript.engine;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import me.topchetoeu.jscript.engine.frame.CodeFrame;
|
||||
import me.topchetoeu.jscript.exceptions.EngineException;
|
||||
|
||||
public class Message {
|
||||
public final Engine engine;
|
||||
|
||||
private final ArrayList<CodeFrame> frames = new ArrayList<>();
|
||||
public int maxStackFrames = 1000;
|
||||
|
||||
public final Data data = new Data();
|
||||
|
||||
public List<CodeFrame> frames() { return Collections.unmodifiableList(frames); }
|
||||
|
||||
public Message addData(Data data) {
|
||||
this.data.addAll(data);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Message pushFrame(Context ctx, CodeFrame frame) throws InterruptedException {
|
||||
this.frames.add(frame);
|
||||
if (this.frames.size() > maxStackFrames) throw EngineException.ofRange("Stack overflow!");
|
||||
return this;
|
||||
}
|
||||
public boolean popFrame(CodeFrame frame) {
|
||||
if (this.frames.size() == 0) return false;
|
||||
if (this.frames.get(this.frames.size() - 1) != frame) return false;
|
||||
this.frames.remove(this.frames.size() - 1);
|
||||
return true;
|
||||
}
|
||||
|
||||
public List<String> stackTrace() {
|
||||
var res = new ArrayList<String>();
|
||||
|
||||
for (var el : frames) {
|
||||
var name = el.function.name;
|
||||
var loc = el.function.loc();
|
||||
var trace = "";
|
||||
|
||||
if (loc != null) trace += "at " + loc.toString() + " ";
|
||||
if (name != null && !name.equals("")) trace += "in " + name + " ";
|
||||
|
||||
trace = trace.trim();
|
||||
|
||||
if (!res.equals("")) res.add(trace);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
public Context context(Environment env) {
|
||||
return new Context(env, this);
|
||||
}
|
||||
|
||||
public Message(Engine engine) {
|
||||
this.engine = engine;
|
||||
}
|
||||
}
|
52
src/me/topchetoeu/jscript/engine/StackData.java
Normal file
52
src/me/topchetoeu/jscript/engine/StackData.java
Normal file
@ -0,0 +1,52 @@
|
||||
package me.topchetoeu.jscript.engine;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import me.topchetoeu.jscript.engine.debug.DebugServer;
|
||||
import me.topchetoeu.jscript.engine.frame.CodeFrame;
|
||||
import me.topchetoeu.jscript.exceptions.EngineException;
|
||||
|
||||
public class StackData {
|
||||
public static final DataKey<ArrayList<CodeFrame>> FRAMES = new DataKey<>();
|
||||
public static final DataKey<Integer> MAX_FRAMES = new DataKey<>();
|
||||
public static final DataKey<DebugServer> DEBUGGER = new DataKey<>();
|
||||
|
||||
public static void pushFrame(Context ctx, CodeFrame frame) throws InterruptedException {
|
||||
var frames = ctx.data.get(FRAMES, new ArrayList<>());
|
||||
frames.add(frame);
|
||||
if (frames.size() > ctx.data.get(MAX_FRAMES, 10000)) throw EngineException.ofRange("Stack overflow!");
|
||||
ctx.pushEnv(frame.function.environment);
|
||||
}
|
||||
public static boolean popFrame(Context ctx, CodeFrame frame) {
|
||||
var frames = ctx.data.get(FRAMES, new ArrayList<>());
|
||||
if (frames.size() == 0) return false;
|
||||
if (frames.get(frames.size() - 1) != frame) return false;
|
||||
frames.remove(frames.size() - 1);
|
||||
ctx.popEnv();
|
||||
return true;
|
||||
}
|
||||
|
||||
public static List<CodeFrame> frames(Context ctx) {
|
||||
return Collections.unmodifiableList(ctx.data.get(FRAMES, new ArrayList<>()));
|
||||
}
|
||||
public static List<String> stackTrace(Context ctx) {
|
||||
var res = new ArrayList<String>();
|
||||
|
||||
for (var el : frames(ctx)) {
|
||||
var name = el.function.name;
|
||||
var loc = el.function.loc();
|
||||
var trace = "";
|
||||
|
||||
if (loc != null) trace += "at " + loc.toString() + " ";
|
||||
if (name != null && !name.equals("")) trace += "in " + name + " ";
|
||||
|
||||
trace = trace.trim();
|
||||
|
||||
if (!trace.equals("")) res.add(trace);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
}
|
@ -95,7 +95,7 @@ public class CodeFrame {
|
||||
|
||||
private void setCause(Context ctx, EngineException err, EngineException cause) throws InterruptedException {
|
||||
if (err.value instanceof ObjectValue) {
|
||||
Values.setMember(ctx, err, ctx.env.symbol("Symbol.cause"), cause);
|
||||
Values.setMember(ctx, err, ctx.environment().symbol("Symbol.cause"), cause);
|
||||
}
|
||||
err.cause = cause;
|
||||
}
|
||||
@ -227,19 +227,6 @@ public class CodeFrame {
|
||||
return Runners.NO_RETURN;
|
||||
}
|
||||
|
||||
public Object run(Context ctx) throws InterruptedException {
|
||||
try {
|
||||
ctx.message.pushFrame(ctx, this);
|
||||
while (true) {
|
||||
var res = next(ctx, Runners.NO_RETURN, Runners.NO_RETURN, null);
|
||||
if (res != Runners.NO_RETURN) return res;
|
||||
}
|
||||
}
|
||||
finally {
|
||||
ctx.message.popFrame(this);
|
||||
}
|
||||
}
|
||||
|
||||
public CodeFrame(Context ctx, Object thisArg, Object[] args, CodeFunction func) {
|
||||
this.args = args.clone();
|
||||
this.scope = new LocalScope(func.localsN, func.captures);
|
||||
|
@ -63,7 +63,7 @@ public class Runners {
|
||||
|
||||
public static Object execMakeVar(Context ctx, Instruction instr, CodeFrame frame) throws InterruptedException {
|
||||
var name = (String)instr.get(0);
|
||||
ctx.env.global.define(name);
|
||||
ctx.environment().global.define(name);
|
||||
frame.codePtr++;
|
||||
return NO_RETURN;
|
||||
}
|
||||
@ -158,7 +158,7 @@ public class Runners {
|
||||
public static Object execLoadVar(Context ctx, Instruction instr, CodeFrame frame) throws InterruptedException {
|
||||
var i = instr.get(0);
|
||||
|
||||
if (i instanceof String) frame.push(ctx, ctx.env.global.get(ctx, (String)i));
|
||||
if (i instanceof String) frame.push(ctx, ctx.environment().global.get(ctx, (String)i));
|
||||
else frame.push(ctx, frame.scope.get((int)i).get(ctx));
|
||||
|
||||
frame.codePtr++;
|
||||
@ -170,7 +170,7 @@ public class Runners {
|
||||
return NO_RETURN;
|
||||
}
|
||||
public static Object execLoadGlob(Context ctx, Instruction instr, CodeFrame frame) {
|
||||
frame.push(ctx, ctx.env.global.obj);
|
||||
frame.push(ctx, ctx.environment().global.obj);
|
||||
frame.codePtr++;
|
||||
return NO_RETURN;
|
||||
}
|
||||
@ -191,8 +191,8 @@ public class Runners {
|
||||
captures[i - 3] = frame.scope.get(instr.get(i));
|
||||
}
|
||||
|
||||
var body = ctx.message.engine.functions.get(id);
|
||||
var func = new CodeFunction(ctx.env, "", localsN, len, captures, body);
|
||||
var body = ctx.engine.functions.get(id);
|
||||
var func = new CodeFunction(ctx.environment(), "", localsN, len, captures, body);
|
||||
|
||||
frame.push(ctx, func);
|
||||
|
||||
@ -217,7 +217,7 @@ public class Runners {
|
||||
return execLoadMember(ctx, instr, frame);
|
||||
}
|
||||
public static Object execLoadRegEx(Context ctx, Instruction instr, CodeFrame frame) throws InterruptedException {
|
||||
frame.push(ctx, ctx.env.regexConstructor.call(ctx, null, instr.get(0), instr.get(1)));
|
||||
frame.push(ctx, ctx.environment().regexConstructor.call(ctx, null, instr.get(0), instr.get(1)));
|
||||
frame.codePtr++;
|
||||
return NO_RETURN;
|
||||
}
|
||||
@ -241,7 +241,7 @@ public class Runners {
|
||||
var val = (boolean)instr.get(1) ? frame.peek() : frame.pop();
|
||||
var i = instr.get(0);
|
||||
|
||||
if (i instanceof String) ctx.env.global.set(ctx, (String)i, val);
|
||||
if (i instanceof String) ctx.environment().global.set(ctx, (String)i, val);
|
||||
else frame.scope.get((int)i).set(ctx, val);
|
||||
|
||||
frame.codePtr++;
|
||||
@ -288,8 +288,8 @@ public class Runners {
|
||||
Object obj;
|
||||
|
||||
if (name != null) {
|
||||
if (ctx.env.global.has(ctx, name)) {
|
||||
obj = ctx.env.global.get(ctx, name);
|
||||
if (ctx.environment().global.has(ctx, name)) {
|
||||
obj = ctx.environment().global.get(ctx, name);
|
||||
}
|
||||
else obj = null;
|
||||
}
|
||||
|
@ -4,7 +4,9 @@ import me.topchetoeu.jscript.Location;
|
||||
import me.topchetoeu.jscript.compilation.Instruction;
|
||||
import me.topchetoeu.jscript.engine.Context;
|
||||
import me.topchetoeu.jscript.engine.Environment;
|
||||
import me.topchetoeu.jscript.engine.StackData;
|
||||
import me.topchetoeu.jscript.engine.frame.CodeFrame;
|
||||
import me.topchetoeu.jscript.engine.frame.Runners;
|
||||
import me.topchetoeu.jscript.engine.scope.ValueVariable;
|
||||
|
||||
public class CodeFunction extends FunctionValue {
|
||||
@ -29,7 +31,18 @@ public class CodeFunction extends FunctionValue {
|
||||
|
||||
@Override
|
||||
public Object call(Context ctx, Object thisArg, Object ...args) throws InterruptedException {
|
||||
return new CodeFrame(ctx, thisArg, args, this).run(ctx.setEnv(environment));
|
||||
var frame = new CodeFrame(ctx, thisArg, args, this);
|
||||
try {
|
||||
StackData.pushFrame(ctx, frame);
|
||||
|
||||
while (true) {
|
||||
var res = frame.next(ctx, Runners.NO_RETURN, Runners.NO_RETURN, null);
|
||||
if (res != Runners.NO_RETURN) return res;
|
||||
}
|
||||
}
|
||||
finally {
|
||||
StackData.popFrame(ctx, frame);
|
||||
}
|
||||
}
|
||||
|
||||
public CodeFunction(Environment environment, String name, int localsN, int length, ValueVariable[] captures, Instruction[] body) {
|
||||
|
@ -8,8 +8,7 @@ public class NativeWrapper extends ObjectValue {
|
||||
|
||||
@Override
|
||||
public ObjectValue getPrototype(Context ctx) throws InterruptedException {
|
||||
if (prototype == NATIVE_PROTO)
|
||||
return ctx.env.wrappersProvider.getProto(wrapped.getClass());
|
||||
if (prototype == NATIVE_PROTO) return ctx.environment().wrappers.getProto(wrapped.getClass());
|
||||
else return super.getPrototype(ctx);
|
||||
}
|
||||
|
||||
|
@ -147,13 +147,13 @@ public class ObjectValue {
|
||||
|
||||
public ObjectValue getPrototype(Context ctx) throws InterruptedException {
|
||||
try {
|
||||
if (prototype == OBJ_PROTO) return ctx.env.proto("object");
|
||||
if (prototype == ARR_PROTO) return ctx.env.proto("array");
|
||||
if (prototype == FUNC_PROTO) return ctx.env.proto("function");
|
||||
if (prototype == ERR_PROTO) return ctx.env.proto("error");
|
||||
if (prototype == RANGE_ERR_PROTO) return ctx.env.proto("rangeErr");
|
||||
if (prototype == SYNTAX_ERR_PROTO) return ctx.env.proto("syntaxErr");
|
||||
if (prototype == TYPE_ERR_PROTO) return ctx.env.proto("typeErr");
|
||||
if (prototype == OBJ_PROTO) return ctx.environment().proto("object");
|
||||
if (prototype == ARR_PROTO) return ctx.environment().proto("array");
|
||||
if (prototype == FUNC_PROTO) return ctx.environment().proto("function");
|
||||
if (prototype == ERR_PROTO) return ctx.environment().proto("error");
|
||||
if (prototype == RANGE_ERR_PROTO) return ctx.environment().proto("rangeErr");
|
||||
if (prototype == SYNTAX_ERR_PROTO) return ctx.environment().proto("syntaxErr");
|
||||
if (prototype == TYPE_ERR_PROTO) return ctx.environment().proto("typeErr");
|
||||
}
|
||||
catch (NullPointerException e) {
|
||||
return null;
|
||||
@ -172,14 +172,14 @@ public class ObjectValue {
|
||||
else if (Values.isObject(val)) {
|
||||
var obj = Values.object(val);
|
||||
|
||||
if (ctx != null && ctx.env != null) {
|
||||
if (obj == ctx.env.proto("object")) prototype = OBJ_PROTO;
|
||||
else if (obj == ctx.env.proto("array")) prototype = ARR_PROTO;
|
||||
else if (obj == ctx.env.proto("function")) prototype = FUNC_PROTO;
|
||||
else if (obj == ctx.env.proto("error")) prototype = ERR_PROTO;
|
||||
else if (obj == ctx.env.proto("syntaxErr")) prototype = SYNTAX_ERR_PROTO;
|
||||
else if (obj == ctx.env.proto("typeErr")) prototype = TYPE_ERR_PROTO;
|
||||
else if (obj == ctx.env.proto("rangeErr")) prototype = RANGE_ERR_PROTO;
|
||||
if (ctx != null && ctx.environment() != null) {
|
||||
if (obj == ctx.environment().proto("object")) prototype = OBJ_PROTO;
|
||||
else if (obj == ctx.environment().proto("array")) prototype = ARR_PROTO;
|
||||
else if (obj == ctx.environment().proto("function")) prototype = FUNC_PROTO;
|
||||
else if (obj == ctx.environment().proto("error")) prototype = ERR_PROTO;
|
||||
else if (obj == ctx.environment().proto("syntaxErr")) prototype = SYNTAX_ERR_PROTO;
|
||||
else if (obj == ctx.environment().proto("typeErr")) prototype = TYPE_ERR_PROTO;
|
||||
else if (obj == ctx.environment().proto("rangeErr")) prototype = RANGE_ERR_PROTO;
|
||||
else prototype = obj;
|
||||
}
|
||||
else prototype = obj;
|
||||
|
@ -321,10 +321,10 @@ public class Values {
|
||||
if (isObject(obj)) return object(obj).getPrototype(ctx);
|
||||
if (ctx == null) return null;
|
||||
|
||||
if (obj instanceof String) return ctx.env.proto("string");
|
||||
else if (obj instanceof Number) return ctx.env.proto("number");
|
||||
else if (obj instanceof Boolean) return ctx.env.proto("bool");
|
||||
else if (obj instanceof Symbol) return ctx.env.proto("symbol");
|
||||
if (obj instanceof String) return ctx.environment().proto("string");
|
||||
else if (obj instanceof Number) return ctx.environment().proto("number");
|
||||
else if (obj instanceof Boolean) return ctx.environment().proto("bool");
|
||||
else if (obj instanceof Symbol) return ctx.environment().proto("symbol");
|
||||
|
||||
return null;
|
||||
}
|
||||
@ -446,7 +446,7 @@ public class Values {
|
||||
|
||||
if (val instanceof Class) {
|
||||
if (ctx == null) return null;
|
||||
else return ctx.env.wrappersProvider.getConstr((Class<?>)val);
|
||||
else return ctx.environment().wrappers.getConstr((Class<?>)val);
|
||||
}
|
||||
|
||||
return new NativeWrapper(val);
|
||||
@ -520,7 +520,7 @@ public class Values {
|
||||
public static Iterable<Object> toJavaIterable(Context ctx, Object obj) {
|
||||
return () -> {
|
||||
try {
|
||||
var symbol = ctx.env.symbol("Symbol.iterator");
|
||||
var symbol = ctx.environment().symbol("Symbol.iterator");
|
||||
|
||||
var iteratorFunc = getMember(ctx, obj, symbol);
|
||||
if (!isFunction(iteratorFunc)) return Collections.emptyIterator();
|
||||
@ -590,7 +590,7 @@ public class Values {
|
||||
var res = new ObjectValue();
|
||||
|
||||
try {
|
||||
var key = getMember(ctx, getMember(ctx, ctx.env.proto("symbol"), "constructor"), "iterator");
|
||||
var key = getMember(ctx, getMember(ctx, ctx.environment().proto("symbol"), "constructor"), "iterator");
|
||||
res.defineProperty(ctx, key, new NativeFunction("", (_ctx, thisArg, args) -> thisArg));
|
||||
}
|
||||
catch (IllegalArgumentException | NullPointerException e) { }
|
||||
|
@ -1,6 +1,7 @@
|
||||
package me.topchetoeu.jscript.lib;
|
||||
|
||||
import me.topchetoeu.jscript.engine.Context;
|
||||
import me.topchetoeu.jscript.engine.StackData;
|
||||
import me.topchetoeu.jscript.engine.frame.CodeFrame;
|
||||
import me.topchetoeu.jscript.engine.frame.Runners;
|
||||
import me.topchetoeu.jscript.engine.values.CodeFunction;
|
||||
@ -19,7 +20,8 @@ public class AsyncFunctionLib extends FunctionValue {
|
||||
|
||||
private void next(Context ctx, Object inducedValue, Object inducedError) throws InterruptedException {
|
||||
Object res = null;
|
||||
ctx.message.pushFrame(ctx, frame);
|
||||
StackData.pushFrame(ctx, frame);
|
||||
ctx.pushEnv(frame.function.environment);
|
||||
|
||||
awaiting = false;
|
||||
while (!awaiting) {
|
||||
@ -37,7 +39,7 @@ public class AsyncFunctionLib extends FunctionValue {
|
||||
}
|
||||
}
|
||||
|
||||
ctx.message.popFrame(frame);
|
||||
StackData.popFrame(ctx, frame);
|
||||
|
||||
if (awaiting) {
|
||||
PromiseLib.then(ctx, frame.pop(), new NativeFunction(this::fulfill), new NativeFunction(this::reject));
|
||||
|
@ -3,6 +3,7 @@ package me.topchetoeu.jscript.lib;
|
||||
import java.util.Map;
|
||||
|
||||
import me.topchetoeu.jscript.engine.Context;
|
||||
import me.topchetoeu.jscript.engine.StackData;
|
||||
import me.topchetoeu.jscript.engine.frame.CodeFrame;
|
||||
import me.topchetoeu.jscript.engine.frame.Runners;
|
||||
import me.topchetoeu.jscript.engine.values.CodeFunction;
|
||||
@ -34,7 +35,7 @@ public class AsyncGeneratorLib extends FunctionValue {
|
||||
}
|
||||
|
||||
Object res = null;
|
||||
ctx.message.pushFrame(ctx, frame);
|
||||
StackData.pushFrame(ctx, frame);
|
||||
state = 0;
|
||||
|
||||
while (state == 0) {
|
||||
@ -55,7 +56,7 @@ public class AsyncGeneratorLib extends FunctionValue {
|
||||
}
|
||||
}
|
||||
|
||||
ctx.message.popFrame(frame);
|
||||
StackData.popFrame(ctx, frame);
|
||||
|
||||
if (state == 1) {
|
||||
PromiseLib.then(ctx, frame.pop(), new NativeFunction(this::fulfill), new NativeFunction(this::reject));
|
||||
|
@ -2,6 +2,7 @@ package me.topchetoeu.jscript.lib;
|
||||
|
||||
import me.topchetoeu.jscript.engine.Context;
|
||||
import me.topchetoeu.jscript.engine.Environment;
|
||||
import me.topchetoeu.jscript.engine.StackData;
|
||||
import me.topchetoeu.jscript.engine.values.ArrayValue;
|
||||
import me.topchetoeu.jscript.engine.values.ObjectValue;
|
||||
import me.topchetoeu.jscript.engine.values.Values;
|
||||
@ -52,7 +53,7 @@ public class ErrorLib {
|
||||
var target = new ObjectValue();
|
||||
if (thisArg instanceof ObjectValue) target = (ObjectValue)thisArg;
|
||||
|
||||
target.defineProperty(ctx, "stack", new ArrayValue(ctx, ctx.message.stackTrace().toArray()));
|
||||
target.defineProperty(ctx, "stack", new ArrayValue(ctx, StackData.stackTrace(ctx)));
|
||||
target.defineProperty(ctx, "name", "Error");
|
||||
if (message == null) target.defineProperty(ctx, "message", "");
|
||||
else target.defineProperty(ctx, "message", Values.toString(ctx, message));
|
||||
|
@ -1,6 +1,7 @@
|
||||
package me.topchetoeu.jscript.lib;
|
||||
|
||||
import me.topchetoeu.jscript.engine.Context;
|
||||
import me.topchetoeu.jscript.engine.StackData;
|
||||
import me.topchetoeu.jscript.engine.frame.CodeFrame;
|
||||
import me.topchetoeu.jscript.engine.frame.Runners;
|
||||
import me.topchetoeu.jscript.engine.values.CodeFunction;
|
||||
@ -30,7 +31,7 @@ public class GeneratorLib extends FunctionValue {
|
||||
}
|
||||
|
||||
Object res = null;
|
||||
ctx.message.pushFrame(ctx, frame);
|
||||
StackData.pushFrame(ctx, frame);
|
||||
yielding = false;
|
||||
|
||||
while (!yielding) {
|
||||
@ -48,7 +49,7 @@ public class GeneratorLib extends FunctionValue {
|
||||
}
|
||||
}
|
||||
|
||||
ctx.message.popFrame(frame);
|
||||
StackData.popFrame(ctx, frame);
|
||||
if (done) frame = null;
|
||||
else res = frame.pop();
|
||||
|
||||
|
@ -31,12 +31,12 @@ public class Internals {
|
||||
}
|
||||
catch (InterruptedException e) { return; }
|
||||
|
||||
ctx.message.engine.pushMsg(false, ctx.message, func, null, args);
|
||||
ctx.engine.pushMsg(false, ctx, func, null, args);
|
||||
});
|
||||
thread.start();
|
||||
|
||||
int i = ctx.env.data.increase(I, 1, 0);
|
||||
var threads = ctx.env.data.add(THREADS, new HashMap<>());
|
||||
int i = ctx.environment().data.increase(I, 1, 0);
|
||||
var threads = ctx.environment().data.get(THREADS, new HashMap<>());
|
||||
threads.put(++i, thread);
|
||||
return i;
|
||||
}
|
||||
@ -51,19 +51,19 @@ public class Internals {
|
||||
}
|
||||
catch (InterruptedException e) { return; }
|
||||
|
||||
ctx.message.engine.pushMsg(false, ctx.message, func, null, args);
|
||||
ctx.engine.pushMsg(false, ctx, func, null, args);
|
||||
}
|
||||
});
|
||||
thread.start();
|
||||
|
||||
int i = ctx.env.data.increase(I, 1, 0);
|
||||
var threads = ctx.env.data.add(THREADS, new HashMap<>());
|
||||
int i = ctx.environment().data.increase(I, 1, 0);
|
||||
var threads = ctx.environment().data.get(THREADS, new HashMap<>());
|
||||
threads.put(++i, thread);
|
||||
return i;
|
||||
}
|
||||
|
||||
@Native public static void clearTimeout(Context ctx, int i) {
|
||||
var threads = ctx.env.data.add(THREADS, new HashMap<>());
|
||||
var threads = ctx.environment().data.get(THREADS, new HashMap<>());
|
||||
|
||||
var thread = threads.remove(i);
|
||||
if (thread != null) thread.interrupt();
|
||||
@ -80,7 +80,7 @@ public class Internals {
|
||||
}
|
||||
|
||||
public void apply(Environment env) {
|
||||
var wp = env.wrappersProvider;
|
||||
var wp = env.wrappers;
|
||||
var glob = env.global = new GlobalScope(wp.getNamespace(Internals.class));
|
||||
|
||||
glob.define(null, "Math", false, wp.getNamespace(MathLib.class));
|
||||
|
@ -194,7 +194,7 @@ public class ObjectLib {
|
||||
return thisArg;
|
||||
}
|
||||
@Native(thisArg = true) public static String toString(Context ctx, Object thisArg) throws InterruptedException {
|
||||
var name = Values.getMember(ctx, thisArg, ctx.env.symbol("Symbol.typeName"));
|
||||
var name = Values.getMember(ctx, thisArg, ctx.environment().symbol("Symbol.typeName"));
|
||||
if (name == null) name = "Unknown";
|
||||
else name = Values.toString(ctx, name);
|
||||
|
||||
|
@ -6,7 +6,6 @@ import java.util.Map;
|
||||
|
||||
import me.topchetoeu.jscript.engine.Context;
|
||||
import me.topchetoeu.jscript.engine.Environment;
|
||||
import me.topchetoeu.jscript.engine.Message;
|
||||
import me.topchetoeu.jscript.engine.values.ArrayValue;
|
||||
import me.topchetoeu.jscript.engine.values.FunctionValue;
|
||||
import me.topchetoeu.jscript.engine.values.NativeFunction;
|
||||
@ -263,7 +262,7 @@ public class PromiseLib {
|
||||
else if (state == STATE_REJECTED) {
|
||||
for (var handle : handles) handle.rejected.call(handle.ctx, null, val);
|
||||
if (handles.size() == 0) {
|
||||
ctx.message.engine.pushMsg(true, ctx.message, new NativeFunction((_ctx, _thisArg, _args) -> {
|
||||
ctx.engine.pushMsg(true, ctx, new NativeFunction((_ctx, _thisArg, _args) -> {
|
||||
if (!handled) {
|
||||
try { Values.printError(new EngineException(val).setContext(ctx), "(in promise)"); }
|
||||
catch (InterruptedException ex) { }
|
||||
@ -297,9 +296,9 @@ public class PromiseLib {
|
||||
}
|
||||
|
||||
private void handle(Context ctx, FunctionValue fulfill, FunctionValue reject) {
|
||||
if (state == STATE_FULFILLED) ctx.message.engine.pushMsg(true, new Message(ctx.message.engine), fulfill, null, val);
|
||||
if (state == STATE_FULFILLED) ctx.engine.pushMsg(true, ctx, fulfill, null, val);
|
||||
else if (state == STATE_REJECTED) {
|
||||
ctx.message.engine.pushMsg(true, new Message(ctx.message.engine), reject, null, val);
|
||||
ctx.engine.pushMsg(true, ctx, reject, null, val);
|
||||
handled = true;
|
||||
}
|
||||
else handles.add(new Handle(ctx, fulfill, reject));
|
||||
|
@ -76,7 +76,7 @@ public class StringLib {
|
||||
var val = passThis(ctx, "indexOf", thisArg);
|
||||
|
||||
if (term != null && term != Values.NULL && !(term instanceof String)) {
|
||||
var search = Values.getMember(ctx, term, ctx.env.symbol("Symbol.search"));
|
||||
var search = Values.getMember(ctx, term, ctx.environment().symbol("Symbol.search"));
|
||||
if (search instanceof FunctionValue) {
|
||||
return (int)Values.toNumber(ctx, ((FunctionValue)search).call(ctx, term, val, false, start));
|
||||
}
|
||||
@ -88,7 +88,7 @@ public class StringLib {
|
||||
var val = passThis(ctx, "lastIndexOf", thisArg);
|
||||
|
||||
if (term != null && term != Values.NULL && !(term instanceof String)) {
|
||||
var search = Values.getMember(ctx, term, ctx.env.symbol("Symbol.search"));
|
||||
var search = Values.getMember(ctx, term, ctx.environment().symbol("Symbol.search"));
|
||||
if (search instanceof FunctionValue) {
|
||||
return (int)Values.toNumber(ctx, ((FunctionValue)search).call(ctx, term, val, true, pos));
|
||||
}
|
||||
@ -105,7 +105,7 @@ public class StringLib {
|
||||
var val = passThis(ctx, "replace", thisArg);
|
||||
|
||||
if (term != null && term != Values.NULL && !(term instanceof String)) {
|
||||
var replace = Values.getMember(ctx, term, ctx.env.symbol("Symbol.replace"));
|
||||
var replace = Values.getMember(ctx, term, ctx.environment().symbol("Symbol.replace"));
|
||||
if (replace instanceof FunctionValue) {
|
||||
return Values.toString(ctx, ((FunctionValue)replace).call(ctx, term, val, replacement));
|
||||
}
|
||||
@ -117,7 +117,7 @@ public class StringLib {
|
||||
var val = passThis(ctx, "replaceAll", thisArg);
|
||||
|
||||
if (term != null && term != Values.NULL && !(term instanceof String)) {
|
||||
var replace = Values.getMember(ctx, term, ctx.env.symbol("Symbol.replace"));
|
||||
var replace = Values.getMember(ctx, term, ctx.environment().symbol("Symbol.replace"));
|
||||
if (replace instanceof FunctionValue) {
|
||||
return Values.toString(ctx, ((FunctionValue)replace).call(ctx, term, val, replacement));
|
||||
}
|
||||
@ -132,11 +132,11 @@ public class StringLib {
|
||||
FunctionValue match;
|
||||
|
||||
try {
|
||||
var _match = Values.getMember(ctx, term, ctx.env.symbol("Symbol.match"));
|
||||
var _match = Values.getMember(ctx, term, ctx.environment().symbol("Symbol.match"));
|
||||
if (_match instanceof FunctionValue) match = (FunctionValue)_match;
|
||||
else if (ctx.env.regexConstructor != null) {
|
||||
var regex = Values.callNew(ctx, ctx.env.regexConstructor, Values.toString(ctx, term), "");
|
||||
_match = Values.getMember(ctx, regex, ctx.env.symbol("Symbol.match"));
|
||||
else if (ctx.environment().regexConstructor != null) {
|
||||
var regex = Values.callNew(ctx, ctx.environment().regexConstructor, Values.toString(ctx, term), "");
|
||||
_match = Values.getMember(ctx, regex, ctx.environment().symbol("Symbol.match"));
|
||||
if (_match instanceof FunctionValue) match = (FunctionValue)_match;
|
||||
else throw EngineException.ofError("Regular expressions don't support matching.");
|
||||
}
|
||||
@ -154,14 +154,14 @@ public class StringLib {
|
||||
FunctionValue match = null;
|
||||
|
||||
try {
|
||||
var _match = Values.getMember(ctx, term, ctx.env.symbol("Symbol.matchAll"));
|
||||
var _match = Values.getMember(ctx, term, ctx.environment().symbol("Symbol.matchAll"));
|
||||
if (_match instanceof FunctionValue) match = (FunctionValue)_match;
|
||||
}
|
||||
catch (IllegalArgumentException e) { }
|
||||
|
||||
if (match == null && ctx.env.regexConstructor != null) {
|
||||
var regex = Values.callNew(ctx, ctx.env.regexConstructor, Values.toString(ctx, term), "g");
|
||||
var _match = Values.getMember(ctx, regex, ctx.env.symbol("Symbol.matchAll"));
|
||||
if (match == null && ctx.environment().regexConstructor != null) {
|
||||
var regex = Values.callNew(ctx, ctx.environment().regexConstructor, Values.toString(ctx, term), "g");
|
||||
var _match = Values.getMember(ctx, regex, ctx.environment().symbol("Symbol.matchAll"));
|
||||
if (_match instanceof FunctionValue) match = (FunctionValue)_match;
|
||||
else throw EngineException.ofError("Regular expressions don't support matching.");
|
||||
}
|
||||
@ -176,7 +176,7 @@ public class StringLib {
|
||||
if (lim != null) lim = Values.toNumber(ctx, lim);
|
||||
|
||||
if (term != null && term != Values.NULL && !(term instanceof String)) {
|
||||
var replace = Values.getMember(ctx, term, ctx.env.symbol("Symbol.replace"));
|
||||
var replace = Values.getMember(ctx, term, ctx.environment().symbol("Symbol.replace"));
|
||||
if (replace instanceof FunctionValue) {
|
||||
var tmp = ((FunctionValue)replace).call(ctx, term, val, lim, sensible);
|
||||
|
||||
|
@ -18,14 +18,14 @@ import me.topchetoeu.jscript.interop.NativeInit;
|
||||
public class SymbolLib {
|
||||
private static final Map<String, Symbol> symbols = new HashMap<>();
|
||||
|
||||
@NativeGetter public static Symbol typeName(Context ctx) { return ctx.env.symbol("Symbol.typeName"); }
|
||||
@NativeGetter public static Symbol replace(Context ctx) { return ctx.env.symbol("Symbol.replace"); }
|
||||
@NativeGetter public static Symbol match(Context ctx) { return ctx.env.symbol("Symbol.match"); }
|
||||
@NativeGetter public static Symbol matchAll(Context ctx) { return ctx.env.symbol("Symbol.matchAll"); }
|
||||
@NativeGetter public static Symbol split(Context ctx) { return ctx.env.symbol("Symbol.split"); }
|
||||
@NativeGetter public static Symbol search(Context ctx) { return ctx.env.symbol("Symbol.search"); }
|
||||
@NativeGetter public static Symbol iterator(Context ctx) { return ctx.env.symbol("Symbol.iterator"); }
|
||||
@NativeGetter public static Symbol asyncIterator(Context ctx) { return ctx.env.symbol("Symbol.asyncIterator"); }
|
||||
@NativeGetter public static Symbol typeName(Context ctx) { return ctx.environment().symbol("Symbol.typeName"); }
|
||||
@NativeGetter public static Symbol replace(Context ctx) { return ctx.environment().symbol("Symbol.replace"); }
|
||||
@NativeGetter public static Symbol match(Context ctx) { return ctx.environment().symbol("Symbol.match"); }
|
||||
@NativeGetter public static Symbol matchAll(Context ctx) { return ctx.environment().symbol("Symbol.matchAll"); }
|
||||
@NativeGetter public static Symbol split(Context ctx) { return ctx.environment().symbol("Symbol.split"); }
|
||||
@NativeGetter public static Symbol search(Context ctx) { return ctx.environment().symbol("Symbol.search"); }
|
||||
@NativeGetter public static Symbol iterator(Context ctx) { return ctx.environment().symbol("Symbol.iterator"); }
|
||||
@NativeGetter public static Symbol asyncIterator(Context ctx) { return ctx.environment().symbol("Symbol.asyncIterator"); }
|
||||
|
||||
public final Symbol value;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user