From 517e3e66575188c6069ee8fe60d94ca8c93a1068 Mon Sep 17 00:00:00 2001 From: TopchetoEU <36534413+TopchetoEU@users.noreply.github.com> Date: Sat, 7 Oct 2023 13:07:07 +0300 Subject: [PATCH] refactor: clean up context and stack data --- src/me/topchetoeu/jscript/Main.java | 6 +- src/me/topchetoeu/jscript/engine/Context.java | 38 +++++++---- src/me/topchetoeu/jscript/engine/Data.java | 56 ++++++++++------- src/me/topchetoeu/jscript/engine/Engine.java | 28 ++++----- .../jscript/engine/Environment.java | 13 ++-- src/me/topchetoeu/jscript/engine/Message.java | 63 ------------------- .../topchetoeu/jscript/engine/StackData.java | 52 +++++++++++++++ .../jscript/engine/frame/CodeFrame.java | 15 +---- .../jscript/engine/frame/Runners.java | 18 +++--- .../jscript/engine/values/CodeFunction.java | 15 ++++- .../jscript/engine/values/NativeWrapper.java | 3 +- .../jscript/engine/values/ObjectValue.java | 30 ++++----- .../jscript/engine/values/Values.java | 14 ++--- .../jscript/lib/AsyncFunctionLib.java | 6 +- .../jscript/lib/AsyncGeneratorLib.java | 5 +- src/me/topchetoeu/jscript/lib/ErrorLib.java | 3 +- .../topchetoeu/jscript/lib/GeneratorLib.java | 5 +- src/me/topchetoeu/jscript/lib/Internals.java | 16 ++--- src/me/topchetoeu/jscript/lib/ObjectLib.java | 2 +- src/me/topchetoeu/jscript/lib/PromiseLib.java | 7 +-- src/me/topchetoeu/jscript/lib/StringLib.java | 26 ++++---- src/me/topchetoeu/jscript/lib/SymbolLib.java | 16 ++--- 22 files changed, 226 insertions(+), 211 deletions(-) delete mode 100644 src/me/topchetoeu/jscript/engine/Message.java create mode 100644 src/me/topchetoeu/jscript/engine/StackData.java diff --git a/src/me/topchetoeu/jscript/Main.java b/src/me/topchetoeu/jscript/Main.java index 314f9c6..021ad62 100644 --- a/src/me/topchetoeu/jscript/Main.java +++ b/src/me/topchetoeu/jscript/Main.java @@ -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)), "", raw, null).toObservable().once(valuePrinter); + engine.pushMsg(false, new Context(engine).pushEnv(env), "", raw, null).toObservable().once(valuePrinter); } catch (EngineException e) { try { diff --git a/src/me/topchetoeu/jscript/engine/Context.java b/src/me/topchetoeu/jscript/engine/Context.java index 480453f..92ffb1d 100644 --- a/src/me/topchetoeu/jscript/engine/Context.java +++ b/src/me/topchetoeu/jscript/engine/Context.java @@ -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 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); } } diff --git a/src/me/topchetoeu/jscript/engine/Data.java b/src/me/topchetoeu/jscript/engine/Data.java index 1db4ba8..828c25b 100644 --- a/src/me/topchetoeu/jscript/engine/Data.java +++ b/src/me/topchetoeu/jscript/engine/Data.java @@ -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, ?>> { +public class Data { + public final Data parent; private HashMap, Object> data = new HashMap<>(); public Data copy() { return new Data().addAll(this); } - public Data addAll(Iterable, ?>> data) { - for (var el : data) { - add((DataKey)el.getKey(), (Object)el.getValue()); + public Data addAll(Map, ?> data) { + for (var el : data.entrySet()) { + get((DataKey)el.getKey(), (Object)el.getValue()); + } + return this; + } + public Data addAll(Data data) { + for (var el : data.data.entrySet()) { + get((DataKey)el.getKey(), (Object)el.getValue()); } return this; } + public T remove(DataKey key) { + return (T)data.remove(key); + } public Data set(DataKey key, T val) { - if (val == null) data.remove(key); - else data.put((DataKey)key, (Object)val); + data.put((DataKey)key, (Object)val); return this; } - public T add(DataKey key, T val) { - if (data.containsKey(key)) return (T)data.get(key); - else { - if (val == null) data.remove(key); - else data.put((DataKey)key, (Object)val); - return val; + public T get(DataKey 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)key); + } } + + set(key, val); + return val; } public T get(DataKey key) { - return get(key, null); - } - public T get(DataKey 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)key); + } + return null; } public boolean has(DataKey key) { return data.containsKey(key); } @@ -53,8 +63,10 @@ public class Data implements Iterable, ?>> { return increase(key, 1, 0); } - @Override - public Iterator, ?>> iterator() { - return (Iterator, ?>>)data.entrySet(); + public Data() { + this.parent = null; + } + public Data(Data parent) { + this.parent = parent; } } diff --git a/src/me/topchetoeu/jscript/engine/Engine.java b/src/me/topchetoeu/jscript/engine/Engine.java index ae4b3a7..9c59378 100644 --- a/src/me/topchetoeu/jscript/engine/Engine.java +++ b/src/me/topchetoeu/jscript/engine/Engine.java @@ -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 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 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 pushMsg(boolean micro, Message ctx, FunctionValue func, Object thisArg, Object ...args) { - var msg = new Task(ctx, func, thisArg, args); + public Awaitable 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 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(); - // } } diff --git a/src/me/topchetoeu/jscript/engine/Environment.java b/src/me/topchetoeu/jscript/engine/Environment.java index c8136cf..5afe1c2 100644 --- a/src/me/topchetoeu/jscript/engine/Environment.java +++ b/src/me/topchetoeu/jscript/engine/Environment.java @@ -20,7 +20,7 @@ public class Environment { public final HashMap 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; } diff --git a/src/me/topchetoeu/jscript/engine/Message.java b/src/me/topchetoeu/jscript/engine/Message.java deleted file mode 100644 index b61f522..0000000 --- a/src/me/topchetoeu/jscript/engine/Message.java +++ /dev/null @@ -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 frames = new ArrayList<>(); - public int maxStackFrames = 1000; - - public final Data data = new Data(); - - public List 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 stackTrace() { - var res = new ArrayList(); - - 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; - } -} diff --git a/src/me/topchetoeu/jscript/engine/StackData.java b/src/me/topchetoeu/jscript/engine/StackData.java new file mode 100644 index 0000000..9bb0fab --- /dev/null +++ b/src/me/topchetoeu/jscript/engine/StackData.java @@ -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> FRAMES = new DataKey<>(); + public static final DataKey MAX_FRAMES = new DataKey<>(); + public static final DataKey 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 frames(Context ctx) { + return Collections.unmodifiableList(ctx.data.get(FRAMES, new ArrayList<>())); + } + public static List stackTrace(Context ctx) { + var res = new ArrayList(); + + 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; + } +} diff --git a/src/me/topchetoeu/jscript/engine/frame/CodeFrame.java b/src/me/topchetoeu/jscript/engine/frame/CodeFrame.java index 2ab02a3..84c12b1 100644 --- a/src/me/topchetoeu/jscript/engine/frame/CodeFrame.java +++ b/src/me/topchetoeu/jscript/engine/frame/CodeFrame.java @@ -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); diff --git a/src/me/topchetoeu/jscript/engine/frame/Runners.java b/src/me/topchetoeu/jscript/engine/frame/Runners.java index ba56ad2..f25345a 100644 --- a/src/me/topchetoeu/jscript/engine/frame/Runners.java +++ b/src/me/topchetoeu/jscript/engine/frame/Runners.java @@ -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; } diff --git a/src/me/topchetoeu/jscript/engine/values/CodeFunction.java b/src/me/topchetoeu/jscript/engine/values/CodeFunction.java index c0025b3..1333cf2 100644 --- a/src/me/topchetoeu/jscript/engine/values/CodeFunction.java +++ b/src/me/topchetoeu/jscript/engine/values/CodeFunction.java @@ -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) { diff --git a/src/me/topchetoeu/jscript/engine/values/NativeWrapper.java b/src/me/topchetoeu/jscript/engine/values/NativeWrapper.java index 9005e5f..5501129 100644 --- a/src/me/topchetoeu/jscript/engine/values/NativeWrapper.java +++ b/src/me/topchetoeu/jscript/engine/values/NativeWrapper.java @@ -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); } diff --git a/src/me/topchetoeu/jscript/engine/values/ObjectValue.java b/src/me/topchetoeu/jscript/engine/values/ObjectValue.java index fbd474f..e3de9d2 100644 --- a/src/me/topchetoeu/jscript/engine/values/ObjectValue.java +++ b/src/me/topchetoeu/jscript/engine/values/ObjectValue.java @@ -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; diff --git a/src/me/topchetoeu/jscript/engine/values/Values.java b/src/me/topchetoeu/jscript/engine/values/Values.java index cc27f10..c4381d3 100644 --- a/src/me/topchetoeu/jscript/engine/values/Values.java +++ b/src/me/topchetoeu/jscript/engine/values/Values.java @@ -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 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) { } diff --git a/src/me/topchetoeu/jscript/lib/AsyncFunctionLib.java b/src/me/topchetoeu/jscript/lib/AsyncFunctionLib.java index f14078c..13f0314 100644 --- a/src/me/topchetoeu/jscript/lib/AsyncFunctionLib.java +++ b/src/me/topchetoeu/jscript/lib/AsyncFunctionLib.java @@ -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)); diff --git a/src/me/topchetoeu/jscript/lib/AsyncGeneratorLib.java b/src/me/topchetoeu/jscript/lib/AsyncGeneratorLib.java index 81fcd23..99df988 100644 --- a/src/me/topchetoeu/jscript/lib/AsyncGeneratorLib.java +++ b/src/me/topchetoeu/jscript/lib/AsyncGeneratorLib.java @@ -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)); diff --git a/src/me/topchetoeu/jscript/lib/ErrorLib.java b/src/me/topchetoeu/jscript/lib/ErrorLib.java index ffa5f73..ebe27bd 100644 --- a/src/me/topchetoeu/jscript/lib/ErrorLib.java +++ b/src/me/topchetoeu/jscript/lib/ErrorLib.java @@ -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)); diff --git a/src/me/topchetoeu/jscript/lib/GeneratorLib.java b/src/me/topchetoeu/jscript/lib/GeneratorLib.java index 109491e..35c3e4d 100644 --- a/src/me/topchetoeu/jscript/lib/GeneratorLib.java +++ b/src/me/topchetoeu/jscript/lib/GeneratorLib.java @@ -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(); diff --git a/src/me/topchetoeu/jscript/lib/Internals.java b/src/me/topchetoeu/jscript/lib/Internals.java index e09d58e..631c2e1 100644 --- a/src/me/topchetoeu/jscript/lib/Internals.java +++ b/src/me/topchetoeu/jscript/lib/Internals.java @@ -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)); diff --git a/src/me/topchetoeu/jscript/lib/ObjectLib.java b/src/me/topchetoeu/jscript/lib/ObjectLib.java index 35f9c6b..8b0b264 100644 --- a/src/me/topchetoeu/jscript/lib/ObjectLib.java +++ b/src/me/topchetoeu/jscript/lib/ObjectLib.java @@ -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); diff --git a/src/me/topchetoeu/jscript/lib/PromiseLib.java b/src/me/topchetoeu/jscript/lib/PromiseLib.java index bd393e8..f0a4ed3 100644 --- a/src/me/topchetoeu/jscript/lib/PromiseLib.java +++ b/src/me/topchetoeu/jscript/lib/PromiseLib.java @@ -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)); diff --git a/src/me/topchetoeu/jscript/lib/StringLib.java b/src/me/topchetoeu/jscript/lib/StringLib.java index 9621487..d491045 100644 --- a/src/me/topchetoeu/jscript/lib/StringLib.java +++ b/src/me/topchetoeu/jscript/lib/StringLib.java @@ -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); diff --git a/src/me/topchetoeu/jscript/lib/SymbolLib.java b/src/me/topchetoeu/jscript/lib/SymbolLib.java index 8edb69f..8c76cce 100644 --- a/src/me/topchetoeu/jscript/lib/SymbolLib.java +++ b/src/me/topchetoeu/jscript/lib/SymbolLib.java @@ -18,14 +18,14 @@ import me.topchetoeu.jscript.interop.NativeInit; public class SymbolLib { private static final Map 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;