From 3475e3a130e8b32d313dabe1f0f0ef08e859d92c Mon Sep 17 00:00:00 2001 From: TopchetoEU <36534413+TopchetoEU@users.noreply.github.com> Date: Sat, 24 Aug 2024 22:18:20 +0300 Subject: [PATCH] refactor: Remove environment-related bloat --- .../topchetoeu/jscript/common/json/JSON.java | 6 +- .../jscript/compilation/parsing/Parsing.java | 2 +- .../me/topchetoeu/jscript/lib/ArrayLib.java | 62 +- .../jscript/lib/AsyncFunctionLib.java | 29 +- .../lib/AsyncGeneratorFunctionLib.java | 9 +- .../jscript/lib/AsyncGeneratorLib.java | 42 +- .../me/topchetoeu/jscript/lib/ConsoleLib.java | 2 +- .../topchetoeu/jscript/lib/EncodingLib.java | 2 +- .../me/topchetoeu/jscript/lib/ErrorLib.java | 12 +- .../me/topchetoeu/jscript/lib/FileLib.java | 16 +- .../topchetoeu/jscript/lib/FilesystemLib.java | 40 +- .../topchetoeu/jscript/lib/FunctionLib.java | 15 +- .../jscript/lib/GeneratorFunctionLib.java | 7 +- .../topchetoeu/jscript/lib/GeneratorLib.java | 26 +- .../me/topchetoeu/jscript/lib/Internals.java | 51 +- .../me/topchetoeu/jscript/lib/JSONLib.java | 2 +- .../me/topchetoeu/jscript/lib/MapLib.java | 20 +- .../me/topchetoeu/jscript/lib/NumberLib.java | 4 +- .../me/topchetoeu/jscript/lib/ObjectLib.java | 78 +- .../me/topchetoeu/jscript/lib/PromiseLib.java | 137 ++-- .../me/topchetoeu/jscript/lib/RegExpLib.java | 32 +- .../me/topchetoeu/jscript/lib/SetLib.java | 16 +- .../me/topchetoeu/jscript/lib/StringLib.java | 66 +- .../me/topchetoeu/jscript/lib/SymbolLib.java | 2 +- .../topchetoeu/jscript/runtime/Childable.java | 5 - .../topchetoeu/jscript/runtime/Compiler.java | 6 +- .../topchetoeu/jscript/runtime/Context.java | 98 --- .../topchetoeu/jscript/runtime/Copyable.java | 5 - .../jscript/runtime/Environment.java | 61 -- .../topchetoeu/jscript/runtime/EventLoop.java | 17 +- .../jscript/runtime/Extensions.java | 77 -- .../me/topchetoeu/jscript/runtime/Frame.java | 99 ++- .../jscript/runtime/InstructionRunner.java | 63 +- .../me/topchetoeu/jscript/runtime/Key.java | 5 - .../jscript/runtime/WrapperProvider.java | 1 + .../jscript/runtime/debug/DebugContext.java | 37 +- .../jscript/runtime/debug/DebugHandler.java | 25 +- .../runtime/environment/Environment.java | 144 ++++ .../jscript/runtime/environment/Key.java | 5 + .../runtime/exceptions/EngineException.java | 24 +- .../jscript/runtime/scope/GlobalScope.java | 26 +- .../jscript/runtime/scope/ValueVariable.java | 6 +- .../jscript/runtime/scope/Variable.java | 6 +- .../jscript/runtime/values/ArrayValue.java | 18 +- .../jscript/runtime/values/CodeFunction.java | 17 +- .../jscript/runtime/values/FunctionValue.java | 12 +- .../runtime/values/NativeFunction.java | 7 +- .../jscript/runtime/values/NativeWrapper.java | 20 +- .../jscript/runtime/values/ObjectValue.java | 133 ++-- .../jscript/runtime/values/ScopeValue.java | 10 +- .../jscript/runtime/values/Value.java | 733 ++++++++++++++++++ .../jscript/runtime/values/Values.java | 101 ++- .../topchetoeu/jscript/utils/JSCompiler.java | 6 +- .../topchetoeu/jscript/utils/JScriptRepl.java | 14 +- .../jscript/utils/debug/ObjectManager.java | 212 +++++ .../jscript/utils/debug/SimpleDebugger.java | 387 +++------ .../jscript/utils/filesystem/Filesystem.java | 6 +- .../jscript/utils/interop/Arguments.java | 46 +- .../utils/interop/NativeWrapperProvider.java | 18 +- .../jscript/utils/modules/Module.java | 6 +- .../jscript/utils/modules/ModuleRepo.java | 25 +- .../jscript/utils/modules/RootModuleRepo.java | 6 +- .../jscript/utils/modules/SourceModule.java | 13 +- .../permissions/PermissionsProvider.java | 6 +- 64 files changed, 1943 insertions(+), 1241 deletions(-) delete mode 100644 src/java/me/topchetoeu/jscript/runtime/Childable.java delete mode 100644 src/java/me/topchetoeu/jscript/runtime/Context.java delete mode 100644 src/java/me/topchetoeu/jscript/runtime/Copyable.java delete mode 100644 src/java/me/topchetoeu/jscript/runtime/Environment.java delete mode 100644 src/java/me/topchetoeu/jscript/runtime/Extensions.java delete mode 100644 src/java/me/topchetoeu/jscript/runtime/Key.java create mode 100644 src/java/me/topchetoeu/jscript/runtime/environment/Environment.java create mode 100644 src/java/me/topchetoeu/jscript/runtime/environment/Key.java create mode 100644 src/java/me/topchetoeu/jscript/runtime/values/Value.java create mode 100644 src/java/me/topchetoeu/jscript/utils/debug/ObjectManager.java diff --git a/src/java/me/topchetoeu/jscript/common/json/JSON.java b/src/java/me/topchetoeu/jscript/common/json/JSON.java index 2aaa8f1..d44270e 100644 --- a/src/java/me/topchetoeu/jscript/common/json/JSON.java +++ b/src/java/me/topchetoeu/jscript/common/json/JSON.java @@ -9,7 +9,7 @@ import me.topchetoeu.jscript.compilation.parsing.Operator; import me.topchetoeu.jscript.compilation.parsing.ParseRes; import me.topchetoeu.jscript.compilation.parsing.Parsing; import me.topchetoeu.jscript.compilation.parsing.Token; -import me.topchetoeu.jscript.runtime.Extensions; +import me.topchetoeu.jscript.runtime.environment.Environment; import me.topchetoeu.jscript.runtime.exceptions.EngineException; import me.topchetoeu.jscript.runtime.exceptions.SyntaxException; import me.topchetoeu.jscript.runtime.values.ArrayValue; @@ -32,7 +32,7 @@ public class JSON { if (val.isNull()) return Values.NULL; return null; } - private static JSONElement fromJs(Extensions ext, Object val, HashSet prev) { + private static JSONElement fromJs(Environment ext, Object val, HashSet prev) { if (val instanceof Boolean) return JSONElement.bool((boolean)val); if (val instanceof Number) return JSONElement.number(((Number)val).doubleValue()); if (val instanceof String) return JSONElement.string((String)val); @@ -70,7 +70,7 @@ public class JSON { if (val == null) return null; return null; } - public static JSONElement fromJs(Extensions ext, Object val) { + public static JSONElement fromJs(Environment ext, Object val) { return fromJs(ext, val, new HashSet<>()); } diff --git a/src/java/me/topchetoeu/jscript/compilation/parsing/Parsing.java b/src/java/me/topchetoeu/jscript/compilation/parsing/Parsing.java index def1449..9ec962a 100644 --- a/src/java/me/topchetoeu/jscript/compilation/parsing/Parsing.java +++ b/src/java/me/topchetoeu/jscript/compilation/parsing/Parsing.java @@ -699,7 +699,7 @@ public class Parsing { var values = new ArrayList(); - // Java allows labels, so me uses labels + // Java allows labels, so labels were used loop: while (true) { if (isOperator(tokens, i + n, Operator.BRACKET_CLOSE)) { n++; diff --git a/src/java/me/topchetoeu/jscript/lib/ArrayLib.java b/src/java/me/topchetoeu/jscript/lib/ArrayLib.java index cfe9708..ce6a5aa 100644 --- a/src/java/me/topchetoeu/jscript/lib/ArrayLib.java +++ b/src/java/me/topchetoeu/jscript/lib/ArrayLib.java @@ -39,7 +39,7 @@ public class ArrayLib { return __iterator(args); } @Expose public static ObjectValue __keys(Arguments args) { - return Values.toJSIterator(args.ctx, () -> new Iterator() { + return Values.toJSIterator(args.env, () -> new Iterator() { private int i = 0; @Override @@ -54,7 +54,7 @@ public class ArrayLib { }); } @Expose public static ObjectValue __entries(Arguments args) { - return Values.toJSIterator(args.ctx, () -> new Iterator() { + return Values.toJSIterator(args.env, () -> new Iterator() { private int i = 0; @Override @@ -64,18 +64,18 @@ public class ArrayLib { @Override public Object next() { if (!hasNext()) return null; - return new ArrayValue(args.ctx, i, args.self(ArrayValue.class).get(i++)); + return new ArrayValue(args.env, i, args.self(ArrayValue.class).get(i++)); } }); } @Expose(value = "@@Symbol.iterator") public static ObjectValue __iterator(Arguments args) { - return Values.toJSIterator(args.ctx, args.self(ArrayValue.class)); + return Values.toJSIterator(args.env, args.self(ArrayValue.class)); } @Expose(value = "@@Symbol.asyncIterator") public static ObjectValue __asyncIterator(Arguments args) { - return Values.toJSAsyncIterator(args.ctx, args.self(ArrayValue.class).iterator()); + return Values.toJSAsyncIterator(args.env, args.self(ArrayValue.class).iterator()); } @Expose public static ArrayValue __concat(Arguments args) { @@ -98,7 +98,7 @@ public class ArrayLib { j += n; } else { - res.set(args.ctx, j++, arrs.get(i)); + res.set(args.env, j++, arrs.get(i)); } } @@ -113,7 +113,7 @@ public class ArrayLib { }); arr.sort((a, b) -> { - var res = Values.toNumber(args.ctx, (cmp == null ? defaultCmp : cmp).call(args.ctx, null, a, b)); + var res = Values.toNumber(args.env, (cmp == null ? defaultCmp : cmp).call(args.env, null, a, b)); if (res < 0) return -1; if (res > 0) return 1; return 0; @@ -127,7 +127,7 @@ public class ArrayLib { var start = normalizeI(arr.size(), args.getInt(1, 0), true); var end = normalizeI(arr.size(), args.getInt(2, arr.size()), true); - for (; start < end; start++) arr.set(args.ctx, start, val); + for (; start < end; start++) arr.set(args.env, start, val); return arr; } @@ -136,7 +136,7 @@ public class ArrayLib { for (var i = 0; i < arr.size(); i++) { if (arr.has(i) && !Values.toBoolean(Values.call( - args.ctx, args.get(0), args.get(1), + args.env, args.get(0), args.get(1), arr.get(i), i, arr ))) return false; } @@ -148,7 +148,7 @@ public class ArrayLib { for (var i = 0; i < arr.size(); i++) { if (arr.has(i) && Values.toBoolean(Values.call( - args.ctx, args.get(0), args.get(1), + args.env, args.get(0), args.get(1), arr.get(i), i, arr ))) return true; } @@ -161,9 +161,9 @@ public class ArrayLib { for (int i = 0, j = 0; i < arr.size(); i++) { if (arr.has(i) && Values.toBoolean(Values.call( - args.ctx, args.get(0), args.get(1), + args.env, args.get(0), args.get(1), arr.get(i), i, arr - ))) res.set(args.ctx, j++, arr.get(i)); + ))) res.set(args.env, j++, arr.get(i)); } return res; @@ -174,7 +174,7 @@ public class ArrayLib { res.setSize(arr.size()); for (int i = 0; i < arr.size(); i++) { - if (arr.has(i)) res.set(args.ctx, i, Values.call(args.ctx, args.get(0), args.get(1), arr.get(i), i, arr)); + if (arr.has(i)) res.set(args.env, i, Values.call(args.env, args.get(0), args.get(1), arr.get(i), i, arr)); } return res; } @@ -184,7 +184,7 @@ public class ArrayLib { var thisArg = args.get(1); for (int i = 0; i < arr.size(); i++) { - if (arr.has(i)) func.call(args.ctx, thisArg, arr.get(i), i, arr); + if (arr.has(i)) func.call(args.env, thisArg, arr.get(i), i, arr); } } @@ -205,7 +205,7 @@ public class ArrayLib { for (; i < arr.size(); i++) { if (arr.has(i)) { - res = func.call(args.ctx, null, res, arr.get(i), i, arr); + res = func.call(args.env, null, res, arr.get(i), i, arr); } } @@ -226,7 +226,7 @@ public class ArrayLib { for (; i >= 0; i--) { if (arr.has(i)) { - res = func.call(args.ctx, null, res, arr.get(i), i, arr); + res = func.call(args.env, null, res, arr.get(i), i, arr); } } @@ -255,13 +255,13 @@ public class ArrayLib { depths.push(d + 1); } } - else res.set(args.ctx, res.size(), el); + else res.set(args.env, res.size(), el); } return res; } @Expose public static ArrayValue __flatMap(Arguments args) { - return __flat(new Arguments(args.ctx, __map(args), 1)); + return __flat(new Arguments(args.env, __map(args), 1)); } @Expose public static Object __find(Arguments args) { @@ -269,7 +269,7 @@ public class ArrayLib { for (int i = 0; i < arr.size(); i++) { if (arr.has(i) && Values.toBoolean(Values.call( - args.ctx, args.get(0), args.get(1), + args.env, args.get(0), args.get(1), arr.get(i), i, args.self ))) return arr.get(i); } @@ -281,7 +281,7 @@ public class ArrayLib { for (var i = arr.size() - 1; i >= 0; i--) { if (arr.has(i) && Values.toBoolean(Values.call( - args.ctx, args.get(0), args.get(1), + args.env, args.get(0), args.get(1), arr.get(i), i, args.self ))) return arr.get(i); } @@ -294,7 +294,7 @@ public class ArrayLib { for (int i = 0; i < arr.size(); i++) { if (arr.has(i) && Values.toBoolean(Values.call( - args.ctx, args.get(0), args.get(1), + args.env, args.get(0), args.get(1), arr.get(i), i, args.self ))) return i; } @@ -306,7 +306,7 @@ public class ArrayLib { for (var i = arr.size() - 1; i >= 0; i--) { if (arr.has(i) && Values.toBoolean(Values.call( - args.ctx, args.get(0), args.get(1), + args.env, args.get(0), args.get(1), arr.get(i), i, args.self ))) return i; } @@ -320,7 +320,7 @@ public class ArrayLib { var start = normalizeI(arr.size(), args.getInt(1), true); for (int i = start; i < arr.size(); i++) { - if (Values.strictEquals(args.ctx, arr.get(i), val)) return i; + if (Values.strictEquals(args.env, arr.get(i), val)) return i; } return -1; @@ -331,7 +331,7 @@ public class ArrayLib { var start = normalizeI(arr.size(), args.getInt(1), true); for (int i = arr.size(); i >= start; i--) { - if (Values.strictEquals(args.ctx, arr.get(i), val)) return i; + if (Values.strictEquals(args.env, arr.get(i), val)) return i; } return -1; @@ -353,7 +353,7 @@ public class ArrayLib { var arr = args.self(ArrayValue.class); var values = args.args; - arr.copyFrom(args.ctx, values, 0, arr.size(), values.length); + arr.copyFrom(args.env, values, 0, arr.size(), values.length); return arr.size(); } @@ -372,7 +372,7 @@ public class ArrayLib { var values = args.slice(0).args; arr.move(0, values.length, arr.size()); - arr.copyFrom(args.ctx, values, 0, 0, values.length); + arr.copyFrom(args.env, values, 0, 0, values.length); return arr.size(); } @@ -398,13 +398,13 @@ public class ArrayLib { var res = new ArrayValue(deleteCount); arr.copyTo(res, start, 0, deleteCount); arr.move(start + deleteCount, start + items.length, arr.size() - start - deleteCount); - arr.copyFrom(args.ctx, items, 0, start, items.length); + arr.copyFrom(args.env, items, 0, start, items.length); arr.setSize(size); return res; } @Expose public static String __toString(Arguments args) { - return __join(new Arguments(args.ctx, args.self, ",")); + return __join(new Arguments(args.env, args.self, ",")); } @Expose public static String __join(Arguments args) { @@ -422,7 +422,7 @@ public class ArrayLib { var el = arr.get(i); if (el == null || el == Values.NULL) continue; - res.append(Values.toString(args.ctx, el)); + res.append(Values.toString(args.env, el)); } return res.toString(); @@ -434,7 +434,7 @@ public class ArrayLib { } @Expose(target = ExposeTarget.STATIC) public static ArrayValue __of(Arguments args) { - return new ArrayValue(args.ctx, args.slice(0).args); + return new ArrayValue(args.env, args.slice(0).args); } @ExposeConstructor public static ArrayValue __constructor(Arguments args) { @@ -448,7 +448,7 @@ public class ArrayLib { else { var val = args.args; res = new ArrayValue(val.length); - res.copyFrom(args.ctx, val, 0, 0, val.length); + res.copyFrom(args.env, val, 0, 0, val.length); } return res; diff --git a/src/java/me/topchetoeu/jscript/lib/AsyncFunctionLib.java b/src/java/me/topchetoeu/jscript/lib/AsyncFunctionLib.java index 2151164..af1f178 100644 --- a/src/java/me/topchetoeu/jscript/lib/AsyncFunctionLib.java +++ b/src/java/me/topchetoeu/jscript/lib/AsyncFunctionLib.java @@ -1,9 +1,8 @@ package me.topchetoeu.jscript.lib; import me.topchetoeu.jscript.lib.PromiseLib.Handle; -import me.topchetoeu.jscript.runtime.Context; -import me.topchetoeu.jscript.runtime.Extensions; import me.topchetoeu.jscript.runtime.Frame; +import me.topchetoeu.jscript.runtime.environment.Environment; import me.topchetoeu.jscript.runtime.exceptions.EngineException; import me.topchetoeu.jscript.runtime.values.CodeFunction; import me.topchetoeu.jscript.runtime.values.FunctionValue; @@ -22,40 +21,43 @@ public class AsyncFunctionLib extends FunctionValue { private boolean awaiting = false; - private void next(Context ctx, Object inducedValue, EngineException inducedError) { + private void next(Environment env, Object inducedValue, EngineException inducedError) { Object res = null; frame.onPush(); awaiting = false; while (!awaiting) { try { - res = frame.next(inducedValue, Values.NO_RETURN, inducedError); + if (inducedValue != Values.NO_RETURN) res = frame.next(inducedValue); + else if (inducedError != null) res = frame.induceError(inducedError); + else res = frame.next(); + inducedValue = Values.NO_RETURN; inducedError = null; if (res != Values.NO_RETURN) { - promise.fulfill(ctx, res); + promise.fulfill(env, res); break; } } catch (EngineException e) { - promise.reject(ctx, e); + promise.reject(env, e); break; } } frame.onPop(); if (awaiting) { - PromiseLib.handle(ctx, frame.pop(), new Handle() { + PromiseLib.handle(env, frame.pop(), new Handle() { @Override public void onFulfil(Object val) { - next(ctx, val, null); + next(env, val, null); } @Override public void onReject(EngineException err) { - next(ctx, Values.NO_RETURN, err); + next(env, Values.NO_RETURN, err); } - }.defer(ctx)); + }.defer(env)); } } @@ -66,16 +68,15 @@ public class AsyncFunctionLib extends FunctionValue { } @Override - public Object call(Extensions ext, Object thisArg, Object ...args) { + public Object call(Environment env, Object thisArg, Object ...args) { var handler = new AsyncHelper(); - var ctx = Context.of(ext); var newArgs = new Object[args.length + 1]; newArgs[0] = new NativeFunction("await", handler::await); System.arraycopy(args, 0, newArgs, 1, args.length); - handler.frame = new Frame(ctx, thisArg, newArgs, (CodeFunction)func); - handler.next(ctx, Values.NO_RETURN, null); + handler.frame = new Frame(env, thisArg, newArgs, (CodeFunction)func); + handler.next(env, Values.NO_RETURN, null); return handler.promise; } diff --git a/src/java/me/topchetoeu/jscript/lib/AsyncGeneratorFunctionLib.java b/src/java/me/topchetoeu/jscript/lib/AsyncGeneratorFunctionLib.java index 43e7689..f6bdbc7 100644 --- a/src/java/me/topchetoeu/jscript/lib/AsyncGeneratorFunctionLib.java +++ b/src/java/me/topchetoeu/jscript/lib/AsyncGeneratorFunctionLib.java @@ -1,8 +1,7 @@ package me.topchetoeu.jscript.lib; -import me.topchetoeu.jscript.runtime.Context; -import me.topchetoeu.jscript.runtime.Extensions; import me.topchetoeu.jscript.runtime.Frame; +import me.topchetoeu.jscript.runtime.environment.Environment; import me.topchetoeu.jscript.runtime.exceptions.EngineException; import me.topchetoeu.jscript.runtime.values.CodeFunction; import me.topchetoeu.jscript.runtime.values.FunctionValue; @@ -14,7 +13,7 @@ public class AsyncGeneratorFunctionLib extends FunctionValue { public final CodeFunction func; @Override - public Object call(Extensions ext, Object thisArg, Object ...args) { + public Object call(Environment ext, Object thisArg, Object ...args) { var handler = new AsyncGeneratorLib(); var newArgs = new Object[args.length + 2]; @@ -22,13 +21,13 @@ public class AsyncGeneratorFunctionLib extends FunctionValue { newArgs[1] = new NativeFunction("yield", handler::yield); System.arraycopy(args, 0, newArgs, 2, args.length); - handler.frame = new Frame(Context.of(ext), thisArg, newArgs, func); + handler.frame = new Frame(ext, thisArg, newArgs, func); return handler; } public AsyncGeneratorFunctionLib(CodeFunction func) { super(func.name, func.length); - if (!(func instanceof CodeFunction)) throw EngineException.ofType("Return value of argument must be a js function."); + if (!(func instanceof CodeFunction)) throw EngineException.ofType("Return value of argument must be a code function."); this.func = func; } } diff --git a/src/java/me/topchetoeu/jscript/lib/AsyncGeneratorLib.java b/src/java/me/topchetoeu/jscript/lib/AsyncGeneratorLib.java index 32778ac..cb1ad6a 100644 --- a/src/java/me/topchetoeu/jscript/lib/AsyncGeneratorLib.java +++ b/src/java/me/topchetoeu/jscript/lib/AsyncGeneratorLib.java @@ -3,8 +3,8 @@ package me.topchetoeu.jscript.lib; import java.util.Map; import me.topchetoeu.jscript.lib.PromiseLib.Handle; -import me.topchetoeu.jscript.runtime.Context; import me.topchetoeu.jscript.runtime.Frame; +import me.topchetoeu.jscript.runtime.environment.Environment; import me.topchetoeu.jscript.runtime.exceptions.EngineException; import me.topchetoeu.jscript.runtime.values.ObjectValue; import me.topchetoeu.jscript.runtime.values.Values; @@ -19,10 +19,10 @@ public class AsyncGeneratorLib { private PromiseLib currPromise; public Frame frame; - private void next(Context ctx, Object inducedValue, Object inducedReturn, EngineException inducedError) { + private void next(Environment env, Object inducedValue, Object inducedReturn, EngineException inducedError) { if (done) { if (inducedError != null) throw inducedError; - currPromise.fulfill(ctx, new ObjectValue(ctx, Map.of( + currPromise.fulfill(env, new ObjectValue(env, Map.of( "done", true, "value", inducedReturn == Values.NO_RETURN ? null : inducedReturn ))); @@ -35,40 +35,44 @@ public class AsyncGeneratorLib { frame.onPush(); while (state == 0) { try { - res = frame.next(inducedValue, inducedReturn, inducedError); + if (inducedValue != Values.NO_RETURN) res = frame.next(inducedValue); + else if (inducedReturn != Values.NO_RETURN) res = frame.induceReturn(inducedValue); + else if (inducedError != null) res = frame.induceError(inducedError); + else res = frame.next(); + inducedValue = inducedReturn = Values.NO_RETURN; inducedError = null; if (res != Values.NO_RETURN) { var obj = new ObjectValue(); - obj.defineProperty(ctx, "done", true); - obj.defineProperty(ctx, "value", res); - currPromise.fulfill(ctx, obj); + obj.defineProperty(env, "done", true); + obj.defineProperty(env, "value", res); + currPromise.fulfill(env, obj); break; } } catch (EngineException e) { - currPromise.reject(ctx, e); + currPromise.reject(env, e); break; } } frame.onPop(); if (state == 1) { - PromiseLib.handle(ctx, frame.pop(), new Handle() { + PromiseLib.handle(env, frame.pop(), new Handle() { @Override public void onFulfil(Object val) { - next(ctx, val, Values.NO_RETURN, null); + next(env, val, Values.NO_RETURN, null); } @Override public void onReject(EngineException err) { - next(ctx, Values.NO_RETURN, Values.NO_RETURN, err); + next(env, Values.NO_RETURN, Values.NO_RETURN, err); } - }.defer(ctx)); + }.defer(env)); } else if (state == 2) { var obj = new ObjectValue(); - obj.defineProperty(ctx, "done", false); - obj.defineProperty(ctx, "value", frame.pop()); - currPromise.fulfill(ctx, obj); + obj.defineProperty(env, "done", false); + obj.defineProperty(env, "value", frame.pop()); + currPromise.fulfill(env, obj); } } @@ -90,18 +94,18 @@ public class AsyncGeneratorLib { @Expose public PromiseLib __next(Arguments args) { this.currPromise = new PromiseLib(); - if (args.has(0)) next(args.ctx, args.get(0), Values.NO_RETURN, null); - else next(args.ctx, Values.NO_RETURN, Values.NO_RETURN, null); + if (args.has(0)) next(args.env, args.get(0), Values.NO_RETURN, null); + else next(args.env, Values.NO_RETURN, Values.NO_RETURN, null); return this.currPromise; } @Expose public PromiseLib __return(Arguments args) { this.currPromise = new PromiseLib(); - next(args.ctx, Values.NO_RETURN, args.get(0), null); + next(args.env, Values.NO_RETURN, args.get(0), null); return this.currPromise; } @Expose public PromiseLib __throw(Arguments args) { this.currPromise = new PromiseLib(); - next(args.ctx, Values.NO_RETURN, Values.NO_RETURN, new EngineException(args.get(0)).setExtensions(args.ctx)); + next(args.env, Values.NO_RETURN, Values.NO_RETURN, new EngineException(args.get(0)).setEnvironment(args.env)); return this.currPromise; } } \ No newline at end of file diff --git a/src/java/me/topchetoeu/jscript/lib/ConsoleLib.java b/src/java/me/topchetoeu/jscript/lib/ConsoleLib.java index 2a7c205..cd08dbf 100644 --- a/src/java/me/topchetoeu/jscript/lib/ConsoleLib.java +++ b/src/java/me/topchetoeu/jscript/lib/ConsoleLib.java @@ -24,7 +24,7 @@ public class ConsoleLib { for (var el : args.args) { if (!first) res.append(" "); first = false; - res.append(Values.toReadable(args.ctx, el).getBytes()); + res.append(Values.toReadable(args.env, el).getBytes()); } for (var line : res.toString().split("\n", -1)) { diff --git a/src/java/me/topchetoeu/jscript/lib/EncodingLib.java b/src/java/me/topchetoeu/jscript/lib/EncodingLib.java index 04ec153..e164ef8 100644 --- a/src/java/me/topchetoeu/jscript/lib/EncodingLib.java +++ b/src/java/me/topchetoeu/jscript/lib/EncodingLib.java @@ -66,7 +66,7 @@ public class EncodingLib { public static String __decode(Arguments args) { var raw = args.convert(0, ArrayList.class); var res = new byte[raw.size()]; - for (var i = 0; i < raw.size(); i++) res[i] = (byte)Values.toNumber(args.ctx, raw.get(i)); + for (var i = 0; i < raw.size(); i++) res[i] = (byte)Values.toNumber(args.env, raw.get(i)); return new String(res); } diff --git a/src/java/me/topchetoeu/jscript/lib/ErrorLib.java b/src/java/me/topchetoeu/jscript/lib/ErrorLib.java index abda9c3..431f6bd 100644 --- a/src/java/me/topchetoeu/jscript/lib/ErrorLib.java +++ b/src/java/me/topchetoeu/jscript/lib/ErrorLib.java @@ -1,6 +1,6 @@ package me.topchetoeu.jscript.lib; -import me.topchetoeu.jscript.runtime.Context; +import me.topchetoeu.jscript.runtime.environment.Environment; import me.topchetoeu.jscript.runtime.exceptions.ConvertException; import me.topchetoeu.jscript.runtime.values.ObjectValue; import me.topchetoeu.jscript.runtime.values.Values; @@ -13,7 +13,7 @@ import me.topchetoeu.jscript.utils.interop.WrapperName; @WrapperName("Error") public class ErrorLib { - private static String toString(Context ctx, Object name, Object message) { + private static String toString(Environment ctx, Object name, Object message) { if (name == null) name = ""; else name = Values.toString(ctx, name).trim(); if (message == null) message = ""; @@ -30,9 +30,9 @@ public class ErrorLib { @ExposeField public static final String __name = "Error"; @Expose public static String __toString(Arguments args) { - if (args.self instanceof ObjectValue) return toString(args.ctx, - Values.getMember(args.ctx, args.self, "name"), - Values.getMember(args.ctx, args.self, "message") + if (args.self instanceof ObjectValue) return toString(args.env, + Values.getMember(args.env, args.self, "name"), + Values.getMember(args.env, args.self, "message") ); else return "[Invalid error]"; } @@ -47,7 +47,7 @@ public class ErrorLib { catch (ConvertException e) {} target.setPrototype(PlaceholderProto.ERROR); - target.defineProperty(args.ctx, "message", Values.toString(args.ctx, message)); + target.defineProperty(args.env, "message", Values.toString(args.env, message)); return target; } diff --git a/src/java/me/topchetoeu/jscript/lib/FileLib.java b/src/java/me/topchetoeu/jscript/lib/FileLib.java index 95b7baa..6a8deb4 100644 --- a/src/java/me/topchetoeu/jscript/lib/FileLib.java +++ b/src/java/me/topchetoeu/jscript/lib/FileLib.java @@ -13,7 +13,7 @@ public class FileLib { public final File fd; @Expose public PromiseLib __pointer(Arguments args) { - return PromiseLib.await(args.ctx, () -> { + return PromiseLib.await(args.env, () -> { try { return fd.seek(0, 1); } @@ -21,7 +21,7 @@ public class FileLib { }); } @Expose public PromiseLib __length(Arguments args) { - return PromiseLib.await(args.ctx, () -> { + return PromiseLib.await(args.env, () -> { try { long curr = fd.seek(0, 1); long res = fd.seek(0, 2); @@ -33,26 +33,26 @@ public class FileLib { } @Expose public PromiseLib __read(Arguments args) { - return PromiseLib.await(args.ctx, () -> { + return PromiseLib.await(args.env, () -> { var n = args.getInt(0); try { var buff = new byte[n]; var res = new ArrayValue(); int resI = fd.read(buff); - for (var i = resI - 1; i >= 0; i--) res.set(args.ctx, i, (int)buff[i]); + for (var i = resI - 1; i >= 0; i--) res.set(args.env, i, (int)buff[i]); return res; } catch (FilesystemException e) { throw e.toEngineException(); } }); } @Expose public PromiseLib __write(Arguments args) { - return PromiseLib.await(args.ctx, () -> { + return PromiseLib.await(args.env, () -> { var val = args.convert(0, ArrayValue.class); try { var res = new byte[val.size()]; - for (var i = 0; i < val.size(); i++) res[i] = (byte)Values.toNumber(args.ctx, val.get(i)); + for (var i = 0; i < val.size(); i++) res[i] = (byte)Values.toNumber(args.env, val.get(i)); fd.write(res); return null; @@ -61,13 +61,13 @@ public class FileLib { }); } @Expose public PromiseLib __close(Arguments args) { - return PromiseLib.await(args.ctx, () -> { + return PromiseLib.await(args.env, () -> { fd.close(); return null; }); } @Expose public PromiseLib __seek(Arguments args) { - return PromiseLib.await(args.ctx, () -> { + return PromiseLib.await(args.env, () -> { var ptr = args.getLong(0); var whence = args.getInt(1); diff --git a/src/java/me/topchetoeu/jscript/lib/FilesystemLib.java b/src/java/me/topchetoeu/jscript/lib/FilesystemLib.java index 6582495..d2f9c3c 100644 --- a/src/java/me/topchetoeu/jscript/lib/FilesystemLib.java +++ b/src/java/me/topchetoeu/jscript/lib/FilesystemLib.java @@ -4,7 +4,7 @@ import java.io.IOException; import java.util.Iterator; import java.util.Stack; -import me.topchetoeu.jscript.runtime.Context; +import me.topchetoeu.jscript.runtime.environment.Environment; import me.topchetoeu.jscript.runtime.exceptions.EngineException; import me.topchetoeu.jscript.runtime.values.ObjectValue; import me.topchetoeu.jscript.runtime.values.Values; @@ -31,21 +31,21 @@ public class FilesystemLib { @ExposeField(target = ExposeTarget.STATIC) public static final int __SEEK_END = 2; - private static Filesystem fs(Context ctx) { - var fs = Filesystem.get(ctx); + private static Filesystem fs(Environment env) { + var fs = Filesystem.get(env); if (fs != null) return fs; throw EngineException.ofError("Current environment doesn't have a file system."); } @Expose(target = ExposeTarget.STATIC) public static String __normalize(Arguments args) { - return fs(args.ctx).normalize(args.convert(String.class)); + return fs(args.env).normalize(args.convert(String.class)); } @Expose(target = ExposeTarget.STATIC) public static PromiseLib __open(Arguments args) { - return PromiseLib.await(args.ctx, () -> { - var fs = fs(args.ctx); + return PromiseLib.await(args.env, () -> { + var fs = fs(args.env); var path = fs.normalize(args.getString(0)); var _mode = Mode.parse(args.getString(1)); @@ -62,7 +62,7 @@ public class FilesystemLib { @Expose(target = ExposeTarget.STATIC) public static ObjectValue __ls(Arguments args) { - return Values.toJSAsyncIterator(args.ctx, new Iterator<>() { + return Values.toJSAsyncIterator(args.env, new Iterator<>() { private boolean failed, done; private File file; private String nextLine; @@ -71,7 +71,7 @@ public class FilesystemLib { if (done) return; if (!failed) { if (file == null) { - var fs = fs(args.ctx); + var fs = fs(args.env); var path = fs.normalize(args.getString(0)); if (fs.stat(path).type != EntryType.FOLDER) { @@ -117,9 +117,9 @@ public class FilesystemLib { } @Expose(target = ExposeTarget.STATIC) public static PromiseLib __mkdir(Arguments args) throws IOException { - return PromiseLib.await(args.ctx, () -> { + return PromiseLib.await(args.env, () -> { try { - fs(args.ctx).create(args.getString(0), EntryType.FOLDER); + fs(args.env).create(args.getString(0), EntryType.FOLDER); return null; } catch (FilesystemException e) { throw e.toEngineException(); } @@ -128,9 +128,9 @@ public class FilesystemLib { } @Expose(target = ExposeTarget.STATIC) public static PromiseLib __mkfile(Arguments args) throws IOException { - return PromiseLib.await(args.ctx, () -> { + return PromiseLib.await(args.env, () -> { try { - fs(args.ctx).create(args.getString(0), EntryType.FILE); + fs(args.env).create(args.getString(0), EntryType.FILE); return null; } catch (FilesystemException e) { throw e.toEngineException(); } @@ -138,9 +138,9 @@ public class FilesystemLib { } @Expose(target = ExposeTarget.STATIC) public static PromiseLib __rm(Arguments args) throws IOException { - return PromiseLib.await(args.ctx, () -> { + return PromiseLib.await(args.env, () -> { try { - var fs = fs(args.ctx); + var fs = fs(args.env); var path = fs.normalize(args.getString(0)); var recursive = args.getBoolean(1); @@ -169,15 +169,15 @@ public class FilesystemLib { } @Expose(target = ExposeTarget.STATIC) public static PromiseLib __stat(Arguments args) throws IOException { - return PromiseLib.await(args.ctx, () -> { + return PromiseLib.await(args.env, () -> { try { - var fs = fs(args.ctx); + var fs = fs(args.env); var path = fs.normalize(args.getString(0)); var stat = fs.stat(path); var res = new ObjectValue(); - res.defineProperty(args.ctx, "type", stat.type.name); - res.defineProperty(args.ctx, "mode", stat.mode.name); + res.defineProperty(args.env, "type", stat.type.name); + res.defineProperty(args.env, "mode", stat.mode.name); return res; } catch (FilesystemException e) { throw e.toEngineException(); } @@ -185,8 +185,8 @@ public class FilesystemLib { } @Expose(target = ExposeTarget.STATIC) public static PromiseLib __exists(Arguments args) throws IOException { - return PromiseLib.await(args.ctx, () -> { - try { fs(args.ctx).stat(args.getString(0)); return true; } + return PromiseLib.await(args.env, () -> { + try { fs(args.env).stat(args.getString(0)); return true; } catch (FilesystemException e) { return false; } }); } diff --git a/src/java/me/topchetoeu/jscript/lib/FunctionLib.java b/src/java/me/topchetoeu/jscript/lib/FunctionLib.java index e50a927..278bac3 100644 --- a/src/java/me/topchetoeu/jscript/lib/FunctionLib.java +++ b/src/java/me/topchetoeu/jscript/lib/FunctionLib.java @@ -2,7 +2,6 @@ package me.topchetoeu.jscript.lib; import me.topchetoeu.jscript.common.Filename; import me.topchetoeu.jscript.runtime.Compiler; -import me.topchetoeu.jscript.runtime.Context; import me.topchetoeu.jscript.runtime.scope.ValueVariable; import me.topchetoeu.jscript.runtime.values.ArrayValue; import me.topchetoeu.jscript.runtime.values.CodeFunction; @@ -20,10 +19,10 @@ public class FunctionLib { private static int i; @Expose public static Object __apply(Arguments args) { - return args.self(FunctionValue.class).call(args.ctx, args.get(0), args.convert(1, ArrayValue.class).toArray()); + return args.self(FunctionValue.class).call(args.env, args.get(0), args.convert(1, ArrayValue.class).toArray()); } @Expose public static Object __call(Arguments args) { - return args.self(FunctionValue.class).call(args.ctx, args.get(0), args.slice(1).args); + return args.self(FunctionValue.class).call(args.env, args.get(0), args.slice(1).args); } @Expose public static FunctionValue __bind(Arguments args) { var self = args.self(FunctionValue.class); @@ -40,7 +39,7 @@ public class FunctionLib { System.arraycopy(callArgs.args, 0, resArgs, bindArgs.length, callArgs.n()); } - return self.call(callArgs.ctx, thisArg, resArgs); + return self.call(callArgs.env, thisArg, resArgs); }); } @Expose public static String __toString(Arguments args) { @@ -62,8 +61,6 @@ public class FunctionLib { @ExposeConstructor public static Object __constructor(Arguments args) { - var compiler = Compiler.get(args); - var parts = args.convert(String.class); if (parts.length == 0) parts = new String[] { "" }; @@ -76,8 +73,8 @@ public class FunctionLib { src += "){" + parts[parts.length - 1] + "}"; - var body = compiler.compile(new Filename("jscript", "func/" + i++), src); - var func = new CodeFunction(Context.clean(args.ctx), "", body, new ValueVariable[0]); - return Values.call(args, func, null); + var body = Compiler.get(args.env).compile(new Filename("jscript", "func/" + i++), src); + var func = new CodeFunction(args.env, "", body, new ValueVariable[0]); + return Values.call(args.env, func, null); } } diff --git a/src/java/me/topchetoeu/jscript/lib/GeneratorFunctionLib.java b/src/java/me/topchetoeu/jscript/lib/GeneratorFunctionLib.java index 7075dae..1316cfb 100644 --- a/src/java/me/topchetoeu/jscript/lib/GeneratorFunctionLib.java +++ b/src/java/me/topchetoeu/jscript/lib/GeneratorFunctionLib.java @@ -1,8 +1,7 @@ package me.topchetoeu.jscript.lib; -import me.topchetoeu.jscript.runtime.Context; -import me.topchetoeu.jscript.runtime.Extensions; import me.topchetoeu.jscript.runtime.Frame; +import me.topchetoeu.jscript.runtime.environment.Environment; import me.topchetoeu.jscript.runtime.exceptions.EngineException; import me.topchetoeu.jscript.runtime.values.CodeFunction; import me.topchetoeu.jscript.runtime.values.FunctionValue; @@ -13,14 +12,14 @@ import me.topchetoeu.jscript.utils.interop.WrapperName; public class GeneratorFunctionLib extends FunctionValue { public final CodeFunction func; - @Override public Object call(Extensions ext, Object thisArg, Object ...args) { + @Override public Object call(Environment env, Object thisArg, Object ...args) { var handler = new GeneratorLib(); var newArgs = new Object[args.length + 1]; newArgs[0] = new NativeFunction("yield", handler::yield); System.arraycopy(args, 0, newArgs, 1, args.length); - handler.frame = new Frame(Context.of(ext), thisArg, newArgs, func); + handler.frame = new Frame(env, thisArg, newArgs, func); return handler; } diff --git a/src/java/me/topchetoeu/jscript/lib/GeneratorLib.java b/src/java/me/topchetoeu/jscript/lib/GeneratorLib.java index 9849c7d..be8b71c 100644 --- a/src/java/me/topchetoeu/jscript/lib/GeneratorLib.java +++ b/src/java/me/topchetoeu/jscript/lib/GeneratorLib.java @@ -1,7 +1,7 @@ package me.topchetoeu.jscript.lib; -import me.topchetoeu.jscript.runtime.Context; import me.topchetoeu.jscript.runtime.Frame; +import me.topchetoeu.jscript.runtime.environment.Environment; import me.topchetoeu.jscript.runtime.exceptions.EngineException; import me.topchetoeu.jscript.runtime.values.ObjectValue; import me.topchetoeu.jscript.runtime.values.Values; @@ -15,12 +15,12 @@ public class GeneratorLib { private boolean done = false; public Frame frame; - private ObjectValue next(Context ctx, Object inducedValue, Object inducedReturn, EngineException inducedError) { + private ObjectValue next(Environment env, Object inducedValue, Object inducedReturn, EngineException inducedError) { if (done) { if (inducedError != Values.NO_RETURN) throw inducedError; var res = new ObjectValue(); - res.defineProperty(ctx, "done", true); - res.defineProperty(ctx, "value", inducedReturn == Values.NO_RETURN ? null : inducedReturn); + res.defineProperty(env, "done", true); + res.defineProperty(env, "value", inducedReturn == Values.NO_RETURN ? null : inducedReturn); return res; } @@ -30,7 +30,11 @@ public class GeneratorLib { frame.onPush(); while (!yielding) { try { - res = frame.next(inducedValue, inducedReturn, inducedError); + if (inducedValue != Values.NO_RETURN) res = frame.next(inducedValue); + else if (inducedReturn != Values.NO_RETURN) res = frame.induceReturn(inducedValue); + else if (inducedError != null) res = frame.induceError(inducedError); + else res = frame.next(); + inducedReturn = Values.NO_RETURN; inducedError = null; if (res != Values.NO_RETURN) { @@ -49,20 +53,20 @@ public class GeneratorLib { else res = frame.pop(); var obj = new ObjectValue(); - obj.defineProperty(ctx, "done", done); - obj.defineProperty(ctx, "value", res); + obj.defineProperty(env, "done", done); + obj.defineProperty(env, "value", res); return obj; } @Expose public ObjectValue __next(Arguments args) { - if (args.n() == 0) return next(args.ctx, Values.NO_RETURN, Values.NO_RETURN, null); - else return next(args.ctx, args.get(0), Values.NO_RETURN, null); + if (args.n() == 0) return next(args.env, Values.NO_RETURN, Values.NO_RETURN, null); + else return next(args.env, args.get(0), Values.NO_RETURN, null); } @Expose public ObjectValue __throw(Arguments args) { - return next(args.ctx, Values.NO_RETURN, Values.NO_RETURN, new EngineException(args.get(0)).setExtensions(args.ctx)); + return next(args.env, Values.NO_RETURN, Values.NO_RETURN, new EngineException(args.get(0)).setEnvironment(args.env)); } @Expose public ObjectValue __return(Arguments args) { - return next(args.ctx, Values.NO_RETURN, args.get(0), null); + return next(args.env, Values.NO_RETURN, args.get(0), null); } @Override public String toString() { diff --git a/src/java/me/topchetoeu/jscript/lib/Internals.java b/src/java/me/topchetoeu/jscript/lib/Internals.java index 67564c6..e2633b6 100644 --- a/src/java/me/topchetoeu/jscript/lib/Internals.java +++ b/src/java/me/topchetoeu/jscript/lib/Internals.java @@ -2,10 +2,9 @@ package me.topchetoeu.jscript.lib; import java.util.HashMap; -import me.topchetoeu.jscript.runtime.Context; -import me.topchetoeu.jscript.runtime.Environment; import me.topchetoeu.jscript.runtime.EventLoop; -import me.topchetoeu.jscript.runtime.Key; +import me.topchetoeu.jscript.runtime.environment.Environment; +import me.topchetoeu.jscript.runtime.environment.Key; import me.topchetoeu.jscript.runtime.exceptions.EngineException; import me.topchetoeu.jscript.runtime.scope.GlobalScope; import me.topchetoeu.jscript.runtime.values.FunctionValue; @@ -26,11 +25,11 @@ public class Internals { @Expose(target = ExposeTarget.STATIC) public static Object __require(Arguments args) { - var repo = ModuleRepo.get(args.ctx); + var repo = ModuleRepo.get(args.env); if (repo != null) { - var res = repo.getModule(args.ctx, ModuleRepo.cwd(args.ctx), args.getString(0)); - res.load(args.ctx); + var res = repo.getModule(args.env, ModuleRepo.cwd(args.env), args.getString(0)); + res.load(args.env); return res.value(); } @@ -43,7 +42,7 @@ public class Internals { var delay = args.getDouble(1); var arguments = args.slice(2).args; - if (!args.ctx.hasNotNull(EventLoop.KEY)) throw EngineException.ofError("No event loop"); + if (!args.env.hasNotNull(EventLoop.KEY)) throw EngineException.ofError("No event loop"); var thread = new Thread(() -> { var ms = (long)delay; @@ -52,13 +51,17 @@ public class Internals { try { Thread.sleep(ms, ns); } catch (InterruptedException e) { return; } - args.ctx.get(EventLoop.KEY).pushMsg(() -> func.call(new Context(args.ctx.extensions), null, arguments), false); + args.env.get(EventLoop.KEY).pushMsg(() -> func.call(args.env, null, arguments), false); }); thread.start(); - var i = args.ctx.init(I, 1); - args.ctx.add(I, i + 1); - args.ctx.init(THREADS, new HashMap()).put(i, thread); + + args.env.init(I, 1); + args.env.init(THREADS, new HashMap<>()); + var i = args.env.get(I); + + args.env.add(I, i + 1); + args.env.get(THREADS).put(i, thread); return thread; } @@ -68,7 +71,7 @@ public class Internals { var delay = args.getDouble(1); var arguments = args.slice(2).args; - if (!args.ctx.hasNotNull(EventLoop.KEY)) throw EngineException.ofError("No event loop"); + if (!args.env.hasNotNull(EventLoop.KEY)) throw EngineException.ofError("No event loop"); var thread = new Thread(() -> { var ms = (long)delay; @@ -80,13 +83,18 @@ public class Internals { } catch (InterruptedException e) { return; } - args.ctx.get(EventLoop.KEY).pushMsg(() -> func.call(new Context(args.ctx.extensions), null, arguments), false); + args.env.get(EventLoop.KEY).pushMsg(() -> func.call(args.env, null, arguments), false); } }); + thread.start(); - var i = args.ctx.init(I, 1); - args.ctx.add(I, i + 1); - args.ctx.init(THREADS, new HashMap()).put(i, thread); + + args.env.init(I, 1); + args.env.init(THREADS, new HashMap<>()); + var i = args.env.get(I); + + args.env.add(I, i + 1); + args.env.get(THREADS).put(i, thread); return thread; } @@ -94,7 +102,7 @@ public class Internals { @Expose(target = ExposeTarget.STATIC) public static void __clearTimeout(Arguments args) { var i = args.getInt(0); - HashMap map = args.ctx.get(THREADS); + HashMap map = args.env.get(THREADS); if (map == null) return; var thread = map.get(i); @@ -132,15 +140,15 @@ public class Internals { @Expose(target = ExposeTarget.STATIC, type = ExposeType.GETTER) public static FileLib __stdin(Arguments args) { - return new FileLib(Filesystem.get(args.ctx).open("std://in", Mode.READ)); + return new FileLib(Filesystem.get(args.env).open("std://in", Mode.READ)); } @Expose(target = ExposeTarget.STATIC, type = ExposeType.GETTER) public static FileLib __stdout(Arguments args) { - return new FileLib(Filesystem.get(args.ctx).open("std://out", Mode.READ)); + return new FileLib(Filesystem.get(args.env).open("std://out", Mode.READ)); } @Expose(target = ExposeTarget.STATIC, type = ExposeType.GETTER) public static FileLib __stderr(Arguments args) { - return new FileLib(Filesystem.get(args.ctx).open("std://err", Mode.READ)); + return new FileLib(Filesystem.get(args.env).open("std://err", Mode.READ)); } @ExposeField(target = ExposeTarget.STATIC) @@ -211,12 +219,11 @@ public class Internals { env.add(Environment.RANGE_ERR_PROTO, wp.getProto(RangeErrorLib.class)); env.add(Environment.REGEX_CONSTR, wp.getConstr(RegExpLib.class)); - Values.setPrototype(new Context(), wp.getProto(ObjectLib.class), null); + Values.setPrototype(Environment.empty(), wp.getProto(ObjectLib.class), null); env.add(NativeWrapperProvider.KEY, wp); env.add(GlobalScope.KEY, glob); - return env; } } diff --git a/src/java/me/topchetoeu/jscript/lib/JSONLib.java b/src/java/me/topchetoeu/jscript/lib/JSONLib.java index 31a1e11..11bbb55 100644 --- a/src/java/me/topchetoeu/jscript/lib/JSONLib.java +++ b/src/java/me/topchetoeu/jscript/lib/JSONLib.java @@ -19,6 +19,6 @@ public class JSONLib { } @Expose(target = ExposeTarget.STATIC) public static String __stringify(Arguments args) { - return JSON.stringify(JSON.fromJs(args.ctx, args.get(0))); + return JSON.stringify(JSON.fromJs(args.env, args.get(0))); } } diff --git a/src/java/me/topchetoeu/jscript/lib/MapLib.java b/src/java/me/topchetoeu/jscript/lib/MapLib.java index 849bf00..bfda4f7 100644 --- a/src/java/me/topchetoeu/jscript/lib/MapLib.java +++ b/src/java/me/topchetoeu/jscript/lib/MapLib.java @@ -4,7 +4,7 @@ import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.stream.Collectors; -import me.topchetoeu.jscript.runtime.Context; +import me.topchetoeu.jscript.runtime.environment.Environment; import me.topchetoeu.jscript.runtime.values.ArrayValue; import me.topchetoeu.jscript.runtime.values.ObjectValue; import me.topchetoeu.jscript.runtime.values.Values; @@ -36,18 +36,18 @@ public class MapLib { } @Expose public ObjectValue __entries(Arguments args) { - return Values.toJSIterator(args.ctx, map + return Values.toJSIterator(args.env, map .entrySet() .stream() - .map(v -> new ArrayValue(args.ctx, v.getKey(), v.getValue())) + .map(v -> new ArrayValue(args.env, v.getKey(), v.getValue())) .collect(Collectors.toList()) ); } @Expose public ObjectValue __keys(Arguments args) { - return Values.toJSIterator(args.ctx, map.keySet()); + return Values.toJSIterator(args.env, map.keySet()); } @Expose public ObjectValue __values(Arguments args) { - return Values.toJSIterator(args.ctx, map.values()); + return Values.toJSIterator(args.env, map.values()); } @Expose public Object __get(Arguments args) { @@ -69,19 +69,19 @@ public class MapLib { @Expose public void __forEach(Arguments args) { var keys = new ArrayList<>(map.keySet()); - for (var el : keys) Values.call(args.ctx, args.get(0), args.get(1), map.get(el), el, args.self); + for (var el : keys) Values.call(args.env, args.get(0), args.get(1), map.get(el), el, args.self); } - public MapLib(Context ctx, Object iterable) { - for (var el : Values.fromJSIterator(ctx, iterable)) { + public MapLib(Environment env, Object iterable) { + for (var el : Values.fromJSIterator(env, iterable)) { try { - map.put(Values.getMember(ctx, el, 0), Values.getMember(ctx, el, 1)); + map.put(Values.getMember(env, el, 0), Values.getMember(env, el, 1)); } catch (IllegalArgumentException e) { } } } @ExposeConstructor public static MapLib __constructor(Arguments args) { - return new MapLib(args.ctx, args.get(0)); + return new MapLib(args.env, args.get(0)); } } diff --git a/src/java/me/topchetoeu/jscript/lib/NumberLib.java b/src/java/me/topchetoeu/jscript/lib/NumberLib.java index 07eb00b..1a7aac1 100644 --- a/src/java/me/topchetoeu/jscript/lib/NumberLib.java +++ b/src/java/me/topchetoeu/jscript/lib/NumberLib.java @@ -85,7 +85,7 @@ public class NumberLib { else return args.getDouble(0); } @Expose public static String __toString(Arguments args) { - return Values.toString(args.ctx, args.self); + return Values.toString(args.env, args.self); } @Expose public static String __toFixed(Arguments args) { var digits = args.getInt(0, 0); @@ -98,6 +98,6 @@ public class NumberLib { } @Expose public static double __valueOf(Arguments args) { if (Values.isWrapper(args.self, NumberLib.class)) return Values.wrapper(args.self, NumberLib.class).value; - else return Values.toNumber(args.ctx, args.self); + else return Values.toNumber(args.env, args.self); } } diff --git a/src/java/me/topchetoeu/jscript/lib/ObjectLib.java b/src/java/me/topchetoeu/jscript/lib/ObjectLib.java index c9b2964..2dfbafa 100644 --- a/src/java/me/topchetoeu/jscript/lib/ObjectLib.java +++ b/src/java/me/topchetoeu/jscript/lib/ObjectLib.java @@ -17,8 +17,8 @@ public class ObjectLib { @Expose(target = ExposeTarget.STATIC) public static Object __assign(Arguments args) { for (var obj : args.slice(1).args) { - for (var key : Values.getMembers(args.ctx, obj, true, true)) { - Values.setMember(args.ctx, args.get(0), key, Values.getMember(args.ctx, obj, key)); + for (var key : Values.getMembers(args.env, obj, true, true)) { + Values.setMember(args.env, args.get(0), key, Values.getMember(args.env, obj, key)); } } return args.get(0); @@ -26,14 +26,14 @@ public class ObjectLib { @Expose(target = ExposeTarget.STATIC) public static ObjectValue __create(Arguments args) { var obj = new ObjectValue(); - Values.setPrototype(args.ctx, obj, args.get(0)); + Values.setPrototype(args.env, obj, args.get(0)); if (args.n() >= 1) { var newArgs = new Object[args.n()]; System.arraycopy(args.args, 1, args, 1, args.n() - 1); newArgs[0] = obj; - __defineProperties(new Arguments(args.ctx, null, newArgs)); + __defineProperties(new Arguments(args.env, null, newArgs)); } return obj; @@ -45,31 +45,31 @@ public class ObjectLib { var key = args.get(1); var attrib = args.convert(2, ObjectValue.class); - var hasVal = Values.hasMember(args.ctx, attrib, "value", false); - var hasGet = Values.hasMember(args.ctx, attrib, "get", false); - var hasSet = Values.hasMember(args.ctx, attrib, "set", false); + var hasVal = Values.hasMember(args.env, attrib, "value", false); + var hasGet = Values.hasMember(args.env, attrib, "get", false); + var hasSet = Values.hasMember(args.env, attrib, "set", false); if (hasVal) { if (hasGet || hasSet) throw EngineException.ofType("Cannot specify a value and accessors for a property."); if (!obj.defineProperty( - args.ctx, key, - Values.getMember(args.ctx, attrib, "value"), - Values.toBoolean(Values.getMember(args.ctx, attrib, "writable")), - Values.toBoolean(Values.getMember(args.ctx, attrib, "configurable")), - Values.toBoolean(Values.getMember(args.ctx, attrib, "enumerable")) + args.env, key, + Values.getMember(args.env, attrib, "value"), + Values.toBoolean(Values.getMember(args.env, attrib, "writable")), + Values.toBoolean(Values.getMember(args.env, attrib, "configurable")), + Values.toBoolean(Values.getMember(args.env, attrib, "enumerable")) )) throw EngineException.ofType("Can't define property '" + key + "'."); } else { - var get = Values.getMember(args.ctx, attrib, "get"); - var set = Values.getMember(args.ctx, attrib, "set"); + var get = Values.getMember(args.env, attrib, "get"); + var set = Values.getMember(args.env, attrib, "set"); if (get != null && !(get instanceof FunctionValue)) throw EngineException.ofType("Get accessor must be a function."); if (set != null && !(set instanceof FunctionValue)) throw EngineException.ofType("Set accessor must be a function."); if (!obj.defineProperty( - args.ctx, key, + args.env, key, (FunctionValue)get, (FunctionValue)set, - Values.toBoolean(Values.getMember(args.ctx, attrib, "configurable")), - Values.toBoolean(Values.getMember(args.ctx, attrib, "enumerable")) + Values.toBoolean(Values.getMember(args.env, attrib, "configurable")), + Values.toBoolean(Values.getMember(args.env, attrib, "enumerable")) )) throw EngineException.ofType("Can't define property '" + key + "'."); } @@ -81,7 +81,7 @@ public class ObjectLib { var attrib = args.get(1); for (var key : Values.getMembers(null, attrib, false, false)) { - __defineProperty(new Arguments(args.ctx, null, obj, key, Values.getMember(args.ctx, attrib, key))); + __defineProperty(new Arguments(args.env, null, obj, key, Values.getMember(args.env, attrib, key))); } return obj; @@ -93,8 +93,8 @@ public class ObjectLib { var all = args.getBoolean(1); var res = new ArrayValue(); - for (var key : Values.getMembers(args.ctx, obj, true, false)) { - if (all || !(key instanceof Symbol)) res.set(args.ctx, res.size(), key); + for (var key : Values.getMembers(args.env, obj, true, false)) { + if (all || !(key instanceof Symbol)) res.set(args.env, res.size(), key); } return res; @@ -105,8 +105,8 @@ public class ObjectLib { var obj = args.get(0); var all = args.getBoolean(1); - for (var key : Values.getMembers(args.ctx, obj, true, false)) { - if (all || !(key instanceof Symbol)) res.set(args.ctx, res.size(), new ArrayValue(args.ctx, key, Values.getMember(args.ctx, obj, key))); + for (var key : Values.getMembers(args.env, obj, true, false)) { + if (all || !(key instanceof Symbol)) res.set(args.env, res.size(), new ArrayValue(args.env, key, Values.getMember(args.env, obj, key))); } return res; @@ -117,8 +117,8 @@ public class ObjectLib { var obj = args.get(0); var all = args.getBoolean(1); - for (var key : Values.getMembers(args.ctx, obj, true, false)) { - if (all || !(key instanceof Symbol)) res.set(args.ctx, res.size(), Values.getMember(args.ctx, obj, key)); + for (var key : Values.getMembers(args.env, obj, true, false)) { + if (all || !(key instanceof Symbol)) res.set(args.env, res.size(), Values.getMember(args.env, obj, key)); } return res; @@ -126,14 +126,14 @@ public class ObjectLib { @Expose(target = ExposeTarget.STATIC) public static ObjectValue __getOwnPropertyDescriptor(Arguments args) { - return Values.getMemberDescriptor(args.ctx, args.get(0), args.get(1)); + return Values.getMemberDescriptor(args.env, args.get(0), args.get(1)); } @Expose(target = ExposeTarget.STATIC) public static ObjectValue __getOwnPropertyDescriptors(Arguments args) { var res = new ObjectValue(); var obj = args.get(0); - for (var key : Values.getMembers(args.ctx, obj, true, true)) { - res.defineProperty(args.ctx, key, Values.getMemberDescriptor(args.ctx, obj, key)); + for (var key : Values.getMembers(args.env, obj, true, true)) { + res.defineProperty(args.env, key, Values.getMemberDescriptor(args.env, obj, key)); } return res; } @@ -144,8 +144,8 @@ public class ObjectLib { var obj = args.get(0); var all = args.getBoolean(1); - for (var key : Values.getMembers(args.ctx, obj, true, true)) { - if (all || !(key instanceof Symbol)) res.set(args.ctx, res.size(), key); + for (var key : Values.getMembers(args.env, obj, true, true)) { + if (all || !(key instanceof Symbol)) res.set(args.env, res.size(), key); } return res; @@ -155,24 +155,24 @@ public class ObjectLib { var obj = args.get(0); var res = new ArrayValue(); - for (var key : Values.getMembers(args.ctx, obj, true, true)) { - if (key instanceof Symbol) res.set(args.ctx, res.size(), key); + for (var key : Values.getMembers(args.env, obj, true, true)) { + if (key instanceof Symbol) res.set(args.env, res.size(), key); } return res; } @Expose(target = ExposeTarget.STATIC) public static boolean __hasOwn(Arguments args) { - return Values.hasMember(args.ctx, args.get(0), args.get(1), true); + return Values.hasMember(args.env, args.get(0), args.get(1), true); } @Expose(target = ExposeTarget.STATIC) public static ObjectValue __getPrototypeOf(Arguments args) { - return Values.getPrototype(args.ctx, args.get(0)); + return Values.getPrototype(args.env, args.get(0)); } @Expose(target = ExposeTarget.STATIC) public static Object __setPrototypeOf(Arguments args) { - Values.setPrototype(args.ctx, args.get(0), args.get(1)); + Values.setPrototype(args.env, args.get(0), args.get(1)); return args.get(0); } @@ -180,9 +180,9 @@ public class ObjectLib { public static ObjectValue __fromEntries(Arguments args) { var res = new ObjectValue(); - for (var el : Values.fromJSIterator(args.ctx, args.get(0))) { + for (var el : Values.fromJSIterator(args.env, args.get(0))) { if (el instanceof ArrayValue) { - res.defineProperty(args.ctx, ((ArrayValue)el).get(0), ((ArrayValue)el).get(1)); + res.defineProperty(args.env, ((ArrayValue)el).get(0), ((ArrayValue)el).get(1)); } } @@ -249,15 +249,15 @@ public class ObjectLib { } @Expose public static String __toString(Arguments args) { - var name = Values.getMember(args.ctx, args.self, Symbol.get("Symbol.typeName")); + var name = Values.getMember(args.env, args.self, Symbol.get("Symbol.typeName")); if (name == null) name = "Unknown"; - else name = Values.toString(args.ctx, name); + else name = Values.toString(args.env, name); return "[object " + name + "]"; } @Expose public static boolean __hasOwnProperty(Arguments args) { - return Values.hasMember(args.ctx, args.self, args.get(0), true); + return Values.hasMember(args.env, args.self, args.get(0), true); } @ExposeConstructor diff --git a/src/java/me/topchetoeu/jscript/lib/PromiseLib.java b/src/java/me/topchetoeu/jscript/lib/PromiseLib.java index 66829de..5bd95cb 100644 --- a/src/java/me/topchetoeu/jscript/lib/PromiseLib.java +++ b/src/java/me/topchetoeu/jscript/lib/PromiseLib.java @@ -4,9 +4,8 @@ import java.util.ArrayList; import java.util.List; import me.topchetoeu.jscript.common.ResultRunnable; -import me.topchetoeu.jscript.runtime.Context; import me.topchetoeu.jscript.runtime.EventLoop; -import me.topchetoeu.jscript.runtime.Extensions; +import me.topchetoeu.jscript.runtime.environment.Environment; import me.topchetoeu.jscript.runtime.exceptions.EngineException; import me.topchetoeu.jscript.runtime.exceptions.InterruptException; import me.topchetoeu.jscript.runtime.values.ArrayValue; @@ -26,7 +25,7 @@ public class PromiseLib { void onFulfil(Object val); void onReject(EngineException err); - default Handle defer(Extensions loop) { + default Handle defer(Environment loop) { var self = this; return new Handle() { @@ -52,7 +51,7 @@ public class PromiseLib { private boolean handled = false; private Object val; - private void resolveSynchronized(Context ctx, Object val, int newState) { + private void resolveSynchronized(Environment env, Object val, int newState) { this.val = val; this.state = newState; @@ -65,7 +64,7 @@ public class PromiseLib { } if (state == STATE_REJECTED && !handled) { - Values.printError(((EngineException)val).setExtensions(ctx), "(in promise)"); + Values.printError(((EngineException)val).setEnvironment(env), "(in promise)"); } handles = null; @@ -78,24 +77,24 @@ public class PromiseLib { // }, true); } - private synchronized void resolve(Context ctx, Object val, int newState) { + private synchronized void resolve(Environment env, Object val, int newState) { if (this.state != STATE_PENDING || newState == STATE_PENDING) return; - handle(ctx, val, new Handle() { + handle(env, val, new Handle() { @Override public void onFulfil(Object val) { - resolveSynchronized(ctx, val, newState); + resolveSynchronized(env, val, newState); } @Override public void onReject(EngineException err) { - resolveSynchronized(ctx, val, STATE_REJECTED); + resolveSynchronized(env, val, STATE_REJECTED); } }); } - public synchronized void fulfill(Context ctx, Object val) { - resolve(ctx, val, STATE_FULFILLED); + public synchronized void fulfill(Environment env, Object val) { + resolve(env, val, STATE_FULFILLED); } - public synchronized void reject(Context ctx, EngineException val) { - resolve(ctx, val, STATE_REJECTED); + public synchronized void reject(Environment env, EngineException val) { + resolve(env, val, STATE_REJECTED); } private void handle(Handle handle) { @@ -118,37 +117,37 @@ public class PromiseLib { this.val = null; } - public static PromiseLib await(Context ctx, ResultRunnable runner) { + public static PromiseLib await(Environment env, ResultRunnable runner) { var res = new PromiseLib(); new Thread(() -> { try { - res.fulfill(ctx, runner.run()); + res.fulfill(env, runner.run()); } catch (EngineException e) { - res.reject(ctx, e); + res.reject(env, e); } catch (Exception e) { if (e instanceof InterruptException) throw e; else { - res.reject(ctx, EngineException.ofError("Native code failed with " + e.getMessage())); + res.reject(env, EngineException.ofError("Native code failed with " + e.getMessage())); } } }, "Promisifier").start(); return res; } - public static PromiseLib await(Context ctx, Runnable runner) { - return await(ctx, () -> { + public static PromiseLib await(Environment env, Runnable runner) { + return await(env, () -> { runner.run(); return null; }); } - public static void handle(Context ctx, Object obj, Handle handle) { + public static void handle(Environment env, Object obj, Handle handle) { if (Values.isWrapper(obj, PromiseLib.class)) { var promise = Values.wrapper(obj, PromiseLib.class); - handle(ctx, promise, handle); + handle(env, promise, handle); return; } if (obj instanceof PromiseLib) { @@ -159,9 +158,9 @@ public class PromiseLib { var rethrow = new boolean[1]; try { - var then = Values.getMember(ctx, obj, "then"); + var then = Values.getMember(env, obj, "then"); - if (then instanceof FunctionValue) Values.call(ctx, then, obj, + if (then instanceof FunctionValue) Values.call(env, then, obj, new NativeFunction(args -> { try { handle.onFulfil(args.get(0)); } catch (Exception e) { @@ -190,12 +189,12 @@ public class PromiseLib { handle.onFulfil(obj); } - public static PromiseLib ofResolved(Context ctx, Object value) { + public static PromiseLib ofResolved(Environment ctx, Object value) { var res = new PromiseLib(); res.fulfill(ctx, value); return res; } - public static PromiseLib ofRejected(Context ctx, EngineException value) { + public static PromiseLib ofRejected(Environment ctx, EngineException value) { var res = new PromiseLib(); res.reject(ctx, value); return res; @@ -203,11 +202,11 @@ public class PromiseLib { @Expose(value = "resolve", target = ExposeTarget.STATIC) public static PromiseLib __ofResolved(Arguments args) { - return ofResolved(args.ctx, args.get(0)); + return ofResolved(args.env, args.get(0)); } @Expose(value = "reject", target = ExposeTarget.STATIC) public static PromiseLib __ofRejected(Arguments args) { - return ofRejected(args.ctx, new EngineException(args.get(0)).setExtensions(args.ctx)); + return ofRejected(args.env, new EngineException(args.get(0)).setEnvironment(args.env)); } @Expose(target = ExposeTarget.STATIC) @@ -215,7 +214,7 @@ public class PromiseLib { if (!(args.get(0) instanceof ArrayValue)) throw EngineException.ofType("Expected argument for any to be an array."); var promises = args.convert(0, ArrayValue.class); - if (promises.size() == 0) return ofRejected(args.ctx, EngineException.ofError("No promises passed to 'Promise.any'.").setExtensions(args.ctx)); + if (promises.size() == 0) return ofRejected(args.env, EngineException.ofError("No promises passed to 'Promise.any'.").setEnvironment(args.env)); var n = new int[] { promises.size() }; var res = new PromiseLib(); var errors = new ArrayValue(); @@ -225,12 +224,12 @@ public class PromiseLib { var val = promises.get(i); if (res.state != STATE_PENDING) break; - handle(args.ctx, val, new Handle() { - public void onFulfil(Object val) { res.fulfill(args.ctx, val); } + handle(args.env, val, new Handle() { + public void onFulfil(Object val) { res.fulfill(args.env, val); } public void onReject(EngineException err) { - errors.set(args.ctx, index, err.value); + errors.set(args.env, index, err.value); n[0]--; - if (n[0] <= 0) res.reject(args.ctx, new EngineException(errors).setExtensions(args.ctx)); + if (n[0] <= 0) res.reject(args.env, new EngineException(errors).setEnvironment(args.env)); } }); } @@ -247,9 +246,9 @@ public class PromiseLib { var val = promises.get(i); if (res.state != STATE_PENDING) break; - handle(args.ctx, val, new Handle() { - @Override public void onFulfil(Object val) { res.fulfill(args.ctx, val); } - @Override public void onReject(EngineException err) { res.reject(args.ctx, err); } + handle(args.env, val, new Handle() { + @Override public void onFulfil(Object val) { res.fulfill(args.env, val); } + @Override public void onReject(EngineException err) { res.reject(args.env, err); } }); } @@ -269,19 +268,19 @@ public class PromiseLib { var index = i; var val = promises.get(i); - handle(args.ctx, val, new Handle() { + handle(args.env, val, new Handle() { @Override public void onFulfil(Object val) { - result.set(args.ctx, index, val); + result.set(args.env, index, val); n[0]--; - if (n[0] <= 0) res.fulfill(args.ctx, result); + if (n[0] <= 0) res.fulfill(args.env, result); } @Override public void onReject(EngineException err) { - res.reject(args.ctx, err); + res.reject(args.env, err); } }); } - if (n[0] <= 0) res.fulfill(args.ctx, result); + if (n[0] <= 0) res.fulfill(args.env, result); return res; } @@ -298,31 +297,31 @@ public class PromiseLib { var index = i; - handle(args.ctx, promises.get(i), new Handle() { + handle(args.env, promises.get(i), new Handle() { @Override public void onFulfil(Object val) { var desc = new ObjectValue(); - desc.defineProperty(args.ctx, "status", "fulfilled"); - desc.defineProperty(args.ctx, "value", val); + desc.defineProperty(args.env, "status", "fulfilled"); + desc.defineProperty(args.env, "value", val); - result.set(args.ctx, index, desc); + result.set(args.env, index, desc); n[0]--; - if (n[0] <= 0) res.fulfill(args.ctx, res); + if (n[0] <= 0) res.fulfill(args.env, res); } @Override public void onReject(EngineException err) { var desc = new ObjectValue(); - desc.defineProperty(args.ctx, "status", "reject"); - desc.defineProperty(args.ctx, "value", err.value); + desc.defineProperty(args.env, "status", "reject"); + desc.defineProperty(args.env, "value", err.value); - result.set(args.ctx, index, desc); + result.set(args.env, index, desc); n[0]--; - if (n[0] <= 0) res.fulfill(args.ctx, res); + if (n[0] <= 0) res.fulfill(args.env, res); } }); } - if (n[0] <= 0) res.fulfill(args.ctx, result); + if (n[0] <= 0) res.fulfill(args.env, result); return res; } @@ -334,22 +333,22 @@ public class PromiseLib { var res = new PromiseLib(); - handle(args.ctx, args.self, new Handle() { + handle(args.env, args.self, new Handle() { @Override public void onFulfil(Object val) { - try { res.fulfill(args.ctx, onFulfill.call(args.ctx, null, val)); } - catch (EngineException e) { res.reject(args.ctx, e); } + try { res.fulfill(args.env, onFulfill.call(args.env, null, val)); } + catch (EngineException e) { res.reject(args.env, e); } } @Override public void onReject(EngineException err) { - try { res.fulfill(args.ctx, onReject.call(args.ctx, null, err.value)); } - catch (EngineException e) { res.reject(args.ctx, e); } + try { res.fulfill(args.env, onReject.call(args.env, null, err.value)); } + catch (EngineException e) { res.reject(args.env, e); } } - }.defer(args.ctx)); + }.defer(args.env)); return res; } @Expose public static Object __catch(Arguments args) { - return __then(new Arguments(args.ctx, args.self, null, args.get(0))); + return __then(new Arguments(args.env, args.self, null, args.get(0))); } @Expose public static Object __finally(Arguments args) { @@ -357,22 +356,22 @@ public class PromiseLib { var res = new PromiseLib(); - handle(args.ctx, args.self, new Handle() { + handle(args.env, args.self, new Handle() { @Override public void onFulfil(Object val) { try { - func.call(args.ctx); - res.fulfill(args.ctx, val); + func.call(args.env); + res.fulfill(args.env, val); } - catch (EngineException e) { res.reject(args.ctx, e); } + catch (EngineException e) { res.reject(args.env, e); } } @Override public void onReject(EngineException err) { try { - func.call(args.ctx); - res.reject(args.ctx, err); + func.call(args.env); + res.reject(args.env, err); } - catch (EngineException e) { res.reject(args.ctx, e); } + catch (EngineException e) { res.reject(args.env, e); } } - }.defer(args.ctx)); + }.defer(args.env)); return res; } @@ -384,19 +383,19 @@ public class PromiseLib { try { func.call( - args.ctx, null, + args.env, null, new NativeFunction(null, _args -> { - res.fulfill(_args.ctx, _args.get(0)); + res.fulfill(_args.env, _args.get(0)); return null; }), new NativeFunction(null, _args -> { - res.reject(_args.ctx, new EngineException(_args.get(0)).setExtensions(_args.ctx)); + res.reject(_args.env, new EngineException(_args.get(0)).setEnvironment(_args.env)); return null; }) ); } catch (EngineException e) { - res.reject(args.ctx, e); + res.reject(args.env, e); } return res; diff --git a/src/java/me/topchetoeu/jscript/lib/RegExpLib.java b/src/java/me/topchetoeu/jscript/lib/RegExpLib.java index 47c8b92..d4cf695 100644 --- a/src/java/me/topchetoeu/jscript/lib/RegExpLib.java +++ b/src/java/me/topchetoeu/jscript/lib/RegExpLib.java @@ -4,7 +4,7 @@ import java.util.ArrayList; import java.util.Iterator; import java.util.regex.Pattern; -import me.topchetoeu.jscript.runtime.Context; +import me.topchetoeu.jscript.runtime.environment.Environment; import me.topchetoeu.jscript.runtime.values.ArrayValue; import me.topchetoeu.jscript.runtime.values.FunctionValue; import me.topchetoeu.jscript.runtime.values.NativeWrapper; @@ -119,7 +119,7 @@ public class RegExpLib { var res = new ArrayValue(); Object val; while ((val = this.__exec(args)) != Values.NULL) { - res.set(args.ctx, res.size(), Values.getMember(args.ctx, val, 0)); + res.set(args.env, res.size(), Values.getMember(args.env, val, 0)); } lastI = 0; return res; @@ -134,7 +134,7 @@ public class RegExpLib { @Expose("@@Symbol.matchAll") public Object __matchAll(Arguments args) { var pattern = this.toGlobal(); - return Values.toJSIterator(args.ctx, new Iterator() { + return Values.toJSIterator(args.env, new Iterator() { private Object val = null; private boolean updated = false; @@ -167,7 +167,7 @@ public class RegExpLib { while ((match = pattern.__exec(args)) != Values.NULL) { var added = new ArrayList(); var arrMatch = (ArrayValue)match; - int index = (int)Values.toNumber(args.ctx, Values.getMember(args.ctx, match, "index")); + int index = (int)Values.toNumber(args.env, Values.getMember(args.env, match, "index")); var matchVal = (String)arrMatch.get(0); if (index >= target.length()) break; @@ -184,18 +184,18 @@ public class RegExpLib { if (sensible) { if (hasLimit && res.size() + added.size() >= lim) break; - else for (var i = 0; i < added.size(); i++) res.set(args.ctx, res.size(), added.get(i)); + else for (var i = 0; i < added.size(); i++) res.set(args.env, res.size(), added.get(i)); } else { for (var i = 0; i < added.size(); i++) { if (hasLimit && res.size() >= lim) return res; - else res.set(args.ctx, res.size(), added.get(i)); + else res.set(args.env, res.size(), added.get(i)); } } lastEnd = pattern.lastI; } if (lastEnd < target.length()) { - res.set(args.ctx, res.size(), target.substring(lastEnd)); + res.set(args.env, res.size(), target.substring(lastEnd)); } return res; } @@ -209,7 +209,7 @@ public class RegExpLib { var res = new StringBuilder(); while ((match = pattern.__exec(args)) != Values.NULL) { - var indices = (ArrayValue)((ArrayValue)Values.getMember(args.ctx, match, "indices")).get(0); + var indices = (ArrayValue)((ArrayValue)Values.getMember(args.env, match, "indices")).get(0); var arrMatch = (ArrayValue)match; var start = ((Number)indices.get(0)).intValue(); @@ -222,10 +222,10 @@ public class RegExpLib { arrMatch.copyTo(callArgs, 1, 1, arrMatch.size() - 1); callArgs[callArgs.length - 2] = start; callArgs[callArgs.length - 1] = target; - res.append(Values.toString(args.ctx, ((FunctionValue)replacement).call(args.ctx, null, callArgs))); + res.append(Values.toString(args.env, ((FunctionValue)replacement).call(args.env, null, callArgs))); } else { - res.append(Values.toString(args.ctx, replacement)); + res.append(Values.toString(args.env, replacement)); } lastEnd = end; if (!pattern.global) break; @@ -313,26 +313,26 @@ public class RegExpLib { @ExposeConstructor public static RegExpLib __constructor(Arguments args) { - return new RegExpLib(cleanupPattern(args.ctx, args.get(0)), cleanupFlags(args.ctx, args.get(1))); + return new RegExpLib(cleanupPattern(args.env, args.get(0)), cleanupFlags(args.env, args.get(1))); } @Expose(target = ExposeTarget.STATIC) public static RegExpLib __escape(Arguments args) { - return escape(Values.toString(args.ctx, args.get(0)), cleanupFlags(args.ctx, args.get(1))); + return escape(Values.toString(args.env, args.get(0)), cleanupFlags(args.env, args.get(1))); } - private static String cleanupPattern(Context ctx, Object val) { + private static String cleanupPattern(Environment env, Object val) { if (val == null) return "(?:)"; if (val instanceof RegExpLib) return ((RegExpLib)val).source; if (val instanceof NativeWrapper && ((NativeWrapper)val).wrapped instanceof RegExpLib) { return ((RegExpLib)((NativeWrapper)val).wrapped).source; } - var res = Values.toString(ctx, val); + var res = Values.toString(env, val); if (res.equals("")) return "(?:)"; return res; } - private static String cleanupFlags(Context ctx, Object val) { + private static String cleanupFlags(Environment env, Object val) { if (val == null) return ""; - return Values.toString(ctx, val); + return Values.toString(env, val); } private static boolean checkEscaped(String s, int pos) { diff --git a/src/java/me/topchetoeu/jscript/lib/SetLib.java b/src/java/me/topchetoeu/jscript/lib/SetLib.java index 273a27c..d76113a 100644 --- a/src/java/me/topchetoeu/jscript/lib/SetLib.java +++ b/src/java/me/topchetoeu/jscript/lib/SetLib.java @@ -4,7 +4,7 @@ import java.util.ArrayList; import java.util.LinkedHashSet; import java.util.stream.Collectors; -import me.topchetoeu.jscript.runtime.Context; +import me.topchetoeu.jscript.runtime.environment.Environment; import me.topchetoeu.jscript.runtime.values.ArrayValue; import me.topchetoeu.jscript.runtime.values.ObjectValue; import me.topchetoeu.jscript.runtime.values.Values; @@ -24,13 +24,13 @@ public class SetLib { } @Expose public ObjectValue __entries(Arguments args) { - return Values.toJSIterator(args.ctx, set.stream().map(v -> new ArrayValue(args.ctx, v, v)).collect(Collectors.toList())); + return Values.toJSIterator(args.env, set.stream().map(v -> new ArrayValue(args.env, v, v)).collect(Collectors.toList())); } @Expose public ObjectValue __keys(Arguments args) { - return Values.toJSIterator(args.ctx, set); + return Values.toJSIterator(args.env, set); } @Expose public ObjectValue __values(Arguments args) { - return Values.toJSIterator(args.ctx, set); + return Values.toJSIterator(args.env, set); } @Expose public Object __add(Arguments args) { @@ -55,15 +55,15 @@ public class SetLib { @Expose public void __forEach(Arguments args) { var keys = new ArrayList<>(set); - for (var el : keys) Values.call(args.ctx, args.get(0), args.get(1), el, el, args.self); + for (var el : keys) Values.call(args.env, args.get(0), args.get(1), el, el, args.self); } - public SetLib(Context ctx, Object iterable) { - for (var el : Values.fromJSIterator(ctx, iterable)) set.add(el); + public SetLib(Environment env, Object iterable) { + for (var el : Values.fromJSIterator(env, iterable)) set.add(el); } @ExposeConstructor public static SetLib __constructor(Arguments args) { - return new SetLib(args.ctx, args.get(0)); + return new SetLib(args.env, args.get(0)); } } diff --git a/src/java/me/topchetoeu/jscript/lib/StringLib.java b/src/java/me/topchetoeu/jscript/lib/StringLib.java index 93317a3..dba6546 100644 --- a/src/java/me/topchetoeu/jscript/lib/StringLib.java +++ b/src/java/me/topchetoeu/jscript/lib/StringLib.java @@ -2,7 +2,7 @@ package me.topchetoeu.jscript.lib; import java.util.regex.Pattern; -import me.topchetoeu.jscript.runtime.Environment; +import me.topchetoeu.jscript.runtime.environment.Environment; import me.topchetoeu.jscript.runtime.exceptions.EngineException; import me.topchetoeu.jscript.runtime.values.ArrayValue; import me.topchetoeu.jscript.runtime.values.FunctionValue; @@ -101,23 +101,23 @@ public class StringLib { var val = passThis(args, "indexOf"); var term = args.get(0); var start = args.getInt(1); - var search = Values.getMember(args.ctx, term, Symbol.get("Symbol.search")); + var search = Values.getMember(args.env, term, Symbol.get("Symbol.search")); if (search instanceof FunctionValue) { - return (int)Values.toNumber(args.ctx, Values.call(args.ctx, search, term, val, false, start)); + return (int)Values.toNumber(args.env, Values.call(args.env, search, term, val, false, start)); } - else return val.indexOf(Values.toString(args.ctx, term), start); + else return val.indexOf(Values.toString(args.env, term), start); } @Expose public static int __lastIndexOf(Arguments args) { var val = passThis(args, "lastIndexOf"); var term = args.get(0); var start = args.getInt(1); - var search = Values.getMember(args.ctx, term, Symbol.get("Symbol.search")); + var search = Values.getMember(args.env, term, Symbol.get("Symbol.search")); if (search instanceof FunctionValue) { - return (int)Values.toNumber(args.ctx, Values.call(args.ctx, search, term, val, true, start)); + return (int)Values.toNumber(args.env, Values.call(args.env, search, term, val, true, start)); } - else return val.lastIndexOf(Values.toString(args.ctx, term), start); + else return val.lastIndexOf(Values.toString(args.env, term), start); } @Expose public static boolean __includes(Arguments args) { @@ -128,23 +128,23 @@ public class StringLib { var val = passThis(args, "replace"); var term = args.get(0); var replacement = args.get(1); - var replace = Values.getMember(args.ctx, term, Symbol.get("Symbol.replace")); + var replace = Values.getMember(args.env, term, Symbol.get("Symbol.replace")); if (replace instanceof FunctionValue) { - return Values.toString(args.ctx, Values.call(args.ctx, replace, term, val, replacement)); + return Values.toString(args.env, Values.call(args.env, replace, term, val, replacement)); } - else return val.replaceFirst(Pattern.quote(Values.toString(args.ctx, term)), Values.toString(args.ctx, replacement)); + else return val.replaceFirst(Pattern.quote(Values.toString(args.env, term)), Values.toString(args.env, replacement)); } @Expose public static String __replaceAll(Arguments args) { var val = passThis(args, "replaceAll"); var term = args.get(0); var replacement = args.get(1); - var replace = Values.getMember(args.ctx, term, Symbol.get("Symbol.replace")); + var replace = Values.getMember(args.env, term, Symbol.get("Symbol.replace")); if (replace instanceof FunctionValue) { - return Values.toString(args.ctx, Values.call(args.ctx, replace, term, val, replacement)); + return Values.toString(args.env, Values.call(args.env, replace, term, val, replacement)); } - else return val.replace(Values.toString(args.ctx, term), Values.toString(args.ctx, replacement)); + else return val.replace(Values.toString(args.env, term), Values.toString(args.env, replacement)); } @Expose public static ArrayValue __match(Arguments args) { @@ -154,21 +154,21 @@ public class StringLib { FunctionValue match; try { - var _match = Values.getMember(args.ctx, term, Symbol.get("Symbol.match")); + var _match = Values.getMember(args.env, term, Symbol.get("Symbol.match")); if (_match instanceof FunctionValue) match = (FunctionValue)_match; - else if (args.ctx.hasNotNull(Environment.REGEX_CONSTR)) { - var regex = Values.callNew(args.ctx, args.ctx.get(Environment.REGEX_CONSTR), Values.toString(args.ctx, term), ""); - _match = Values.getMember(args.ctx, regex, Symbol.get("Symbol.match")); + else if (args.env.hasNotNull(Environment.REGEX_CONSTR)) { + var regex = Values.callNew(args.env, args.env.get(Environment.REGEX_CONSTR), Values.toString(args.env, term), ""); + _match = Values.getMember(args.env, regex, Symbol.get("Symbol.match")); if (_match instanceof FunctionValue) match = (FunctionValue)_match; else throw EngineException.ofError("Regular expressions don't support matching."); } else throw EngineException.ofError("Regular expressions not supported."); } - catch (IllegalArgumentException e) { return new ArrayValue(args.ctx, ""); } + catch (IllegalArgumentException e) { return new ArrayValue(args.env, ""); } - var res = match.call(args.ctx, term, val); + var res = match.call(args.env, term, val); if (res instanceof ArrayValue) return (ArrayValue)res; - else return new ArrayValue(args.ctx, ""); + else return new ArrayValue(args.env, ""); } @Expose public static Object __matchAll(Arguments args) { var val = passThis(args, "matchAll"); @@ -177,20 +177,20 @@ public class StringLib { FunctionValue match = null; try { - var _match = Values.getMember(args.ctx, term, Symbol.get("Symbol.matchAll")); + var _match = Values.getMember(args.env, term, Symbol.get("Symbol.matchAll")); if (_match instanceof FunctionValue) match = (FunctionValue)_match; } catch (IllegalArgumentException e) { } - if (match == null && args.ctx.hasNotNull(Environment.REGEX_CONSTR)) { - var regex = Values.callNew(args.ctx, args.ctx.get(Environment.REGEX_CONSTR), Values.toString(args.ctx, term), "g"); - var _match = Values.getMember(args.ctx, regex, Symbol.get("Symbol.matchAll")); + if (match == null && args.env.hasNotNull(Environment.REGEX_CONSTR)) { + var regex = Values.callNew(args.env, args.env.get(Environment.REGEX_CONSTR), Values.toString(args.env, term), "g"); + var _match = Values.getMember(args.env, regex, Symbol.get("Symbol.matchAll")); if (_match instanceof FunctionValue) match = (FunctionValue)_match; else throw EngineException.ofError("Regular expressions don't support matching."); } else throw EngineException.ofError("Regular expressions not supported."); - return match.call(args.ctx, term, val); + return match.call(args.env, term, val); } @Expose public static ArrayValue __split(Arguments args) { @@ -199,23 +199,23 @@ public class StringLib { var lim = args.get(1); var sensible = args.getBoolean(2); - if (lim != null) lim = Values.toNumber(args.ctx, lim); + if (lim != null) lim = Values.toNumber(args.env, lim); if (term != null && term != Values.NULL && !(term instanceof String)) { - var replace = Values.getMember(args.ctx, term, Symbol.get("Symbol.replace")); + var replace = Values.getMember(args.env, term, Symbol.get("Symbol.replace")); if (replace instanceof FunctionValue) { - var tmp = ((FunctionValue)replace).call(args.ctx, term, val, lim, sensible); + var tmp = ((FunctionValue)replace).call(args.env, term, val, lim, sensible); if (tmp instanceof ArrayValue) { var parts = new ArrayValue(((ArrayValue)tmp).size()); - for (int i = 0; i < parts.size(); i++) parts.set(args.ctx, i, Values.toString(args.ctx, ((ArrayValue)tmp).get(i))); + for (int i = 0; i < parts.size(); i++) parts.set(args.env, i, Values.toString(args.env, ((ArrayValue)tmp).get(i))); return parts; } } } String[] parts; - var pattern = Pattern.quote(Values.toString(args.ctx, term)); + var pattern = Pattern.quote(Values.toString(args.env, term)); if (lim == null) parts = val.split(pattern); else if ((double)lim < 1) return new ArrayValue(); @@ -228,7 +228,7 @@ public class StringLib { if (parts.length > limit) res = new ArrayValue(limit); else res = new ArrayValue(parts.length); - for (var i = 0; i < parts.length && i < limit; i++) res.set(args.ctx, i, parts[i]); + for (var i = 0; i < parts.length && i < limit; i++) res.set(args.env, i, parts[i]); return res; } @@ -238,7 +238,7 @@ public class StringLib { for (; i < parts.length; i++) { if (lim != null && (double)lim <= i) break; - res.set(args.ctx, i, parts[i]); + res.set(args.env, i, parts[i]); } return res; @@ -249,7 +249,7 @@ public class StringLib { var start = normalizeI(args.getInt(0), self.length(), false); var end = normalizeI(args.getInt(1, self.length()), self.length(), false); - return __substring(new Arguments(args.ctx, self, start, end)); + return __substring(new Arguments(args.env, self, start, end)); } @Expose public static String __concat(Arguments args) { diff --git a/src/java/me/topchetoeu/jscript/lib/SymbolLib.java b/src/java/me/topchetoeu/jscript/lib/SymbolLib.java index 9de6a74..e6a553d 100644 --- a/src/java/me/topchetoeu/jscript/lib/SymbolLib.java +++ b/src/java/me/topchetoeu/jscript/lib/SymbolLib.java @@ -76,6 +76,6 @@ public class SymbolLib { } @Expose(target = ExposeTarget.STATIC) public static String __keyFor(Arguments args) { - return passThis(new Arguments(args.ctx, args.get(0)), "keyFor").value; + return passThis(new Arguments(args.env, args.get(0)), "keyFor").value; } } diff --git a/src/java/me/topchetoeu/jscript/runtime/Childable.java b/src/java/me/topchetoeu/jscript/runtime/Childable.java deleted file mode 100644 index f1f358e..0000000 --- a/src/java/me/topchetoeu/jscript/runtime/Childable.java +++ /dev/null @@ -1,5 +0,0 @@ -package me.topchetoeu.jscript.runtime; - -public interface Childable { - Object child(); -} \ No newline at end of file diff --git a/src/java/me/topchetoeu/jscript/runtime/Compiler.java b/src/java/me/topchetoeu/jscript/runtime/Compiler.java index d332da5..ff87201 100644 --- a/src/java/me/topchetoeu/jscript/runtime/Compiler.java +++ b/src/java/me/topchetoeu/jscript/runtime/Compiler.java @@ -2,6 +2,9 @@ package me.topchetoeu.jscript.runtime; import me.topchetoeu.jscript.common.Filename; import me.topchetoeu.jscript.common.FunctionBody; +import me.topchetoeu.jscript.runtime.debug.DebugContext; +import me.topchetoeu.jscript.runtime.environment.Environment; +import me.topchetoeu.jscript.runtime.environment.Key; import me.topchetoeu.jscript.runtime.exceptions.EngineException; import me.topchetoeu.jscript.runtime.scope.ValueVariable; import me.topchetoeu.jscript.runtime.values.CodeFunction; @@ -11,13 +14,14 @@ public interface Compiler { public FunctionBody compile(Filename filename, String source); - public static Compiler get(Extensions ext) { + public static Compiler get(Environment ext) { return ext.get(KEY, (filename, src) -> { throw EngineException.ofError("No compiler attached to engine."); }); } public static CodeFunction compile(Environment env, Filename filename, String raw) { + DebugContext.get(env).onSource(filename, raw); return new CodeFunction(env, filename.toString(), Compiler.get(env).compile(filename, raw), new ValueVariable[0]); } } diff --git a/src/java/me/topchetoeu/jscript/runtime/Context.java b/src/java/me/topchetoeu/jscript/runtime/Context.java deleted file mode 100644 index e20a62b..0000000 --- a/src/java/me/topchetoeu/jscript/runtime/Context.java +++ /dev/null @@ -1,98 +0,0 @@ -package me.topchetoeu.jscript.runtime; - -import java.util.Iterator; -import java.util.List; - -import me.topchetoeu.jscript.common.Filename; -import me.topchetoeu.jscript.runtime.debug.DebugContext; -import me.topchetoeu.jscript.runtime.exceptions.EngineException; -import me.topchetoeu.jscript.runtime.scope.ValueVariable; -import me.topchetoeu.jscript.runtime.values.CodeFunction; -import me.topchetoeu.jscript.runtime.values.FunctionValue; - -public class Context implements Extensions { - public final Context parent; - public final Extensions extensions; - public final Frame frame; - public final int stackSize; - - @Override public void add(Key key, T obj) { - if (extensions != null) extensions.add(key, obj); - } - @Override public T get(Key key) { - if (extensions != null && extensions.has(key)) return extensions.get(key); - return null; - } - @Override public boolean has(Key key) { - return extensions != null && extensions.has(key); - } - @Override public boolean remove(Key key) { - var res = false; - if (extensions != null) res |= extensions.remove(key); - return res; - } - @Override public Iterable> keys() { - if (extensions == null) return List.of(); - else return extensions.keys(); - } - - public FunctionValue compile(Filename filename, String raw) { - DebugContext.get(this).onSource(filename, raw); - var result = new CodeFunction(extensions, filename.toString(), Compiler.get(this).compile(filename, raw), new ValueVariable[0]); - return result; - } - - public Context pushFrame(Frame frame) { - var res = new Context(this, frame.function.extensions, frame, stackSize + 1); - return res; - } - - public Iterable frames() { - var self = this; - return () -> new Iterator() { - private Context curr = self; - - private void update() { - while (curr != null && curr.frame == null) curr = curr.parent; - } - - @Override public boolean hasNext() { - update(); - return curr != null; - } - @Override public Frame next() { - update(); - var res = curr.frame; - curr = curr.parent; - return res; - } - }; - } - - private Context(Context parent, Extensions ext, Frame frame, int stackSize) { - this.parent = parent; - this.extensions = ext; - this.frame = frame; - this.stackSize = stackSize; - - if (hasNotNull(Environment.MAX_STACK_COUNT) && stackSize > (int)get(Environment.MAX_STACK_COUNT)) { - throw EngineException.ofRange("Stack overflow!"); - } - } - - public Context() { - this(null, null, null, 0); - } - public Context(Extensions ext) { - this(null, clean(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 clean(((Context)ext).extensions); - else return ext; - } -} diff --git a/src/java/me/topchetoeu/jscript/runtime/Copyable.java b/src/java/me/topchetoeu/jscript/runtime/Copyable.java deleted file mode 100644 index cb2e75e..0000000 --- a/src/java/me/topchetoeu/jscript/runtime/Copyable.java +++ /dev/null @@ -1,5 +0,0 @@ -package me.topchetoeu.jscript.runtime; - -public interface Copyable { - Object copy(); -} \ No newline at end of file diff --git a/src/java/me/topchetoeu/jscript/runtime/Environment.java b/src/java/me/topchetoeu/jscript/runtime/Environment.java deleted file mode 100644 index 4e232d8..0000000 --- a/src/java/me/topchetoeu/jscript/runtime/Environment.java +++ /dev/null @@ -1,61 +0,0 @@ -package me.topchetoeu.jscript.runtime; - -import java.util.HashMap; - -import me.topchetoeu.jscript.runtime.exceptions.EngineException; -import me.topchetoeu.jscript.runtime.values.FunctionValue; -import me.topchetoeu.jscript.runtime.values.NativeFunction; -import me.topchetoeu.jscript.runtime.values.ObjectValue; - -@SuppressWarnings("unchecked") -public class Environment implements Extensions { - public static final Key COMPILE_FUNC = new Key<>(); - - public static final Key REGEX_CONSTR = new Key<>(); - public static final Key MAX_STACK_COUNT = new Key<>(); - public static final Key HIDE_STACK = new Key<>(); - - public static final Key OBJECT_PROTO = new Key<>(); - public static final Key FUNCTION_PROTO = new Key<>(); - public static final Key ARRAY_PROTO = new Key<>(); - public static final Key BOOL_PROTO = new Key<>(); - public static final Key NUMBER_PROTO = new Key<>(); - public static final Key STRING_PROTO = new Key<>(); - public static final Key SYMBOL_PROTO = new Key<>(); - public static final Key ERROR_PROTO = new Key<>(); - public static final Key SYNTAX_ERR_PROTO = new Key<>(); - public static final Key TYPE_ERR_PROTO = new Key<>(); - public static final Key RANGE_ERR_PROTO = new Key<>(); - - private HashMap, Object> data = new HashMap<>(); - - @Override public void add(Key key, T obj) { - data.put(key, obj); - } - @Override public T get(Key key) { - return (T)data.get(key); - } - @Override public boolean remove(Key key) { - if (data.containsKey(key)) { - data.remove(key); - return true; - } - return false; - } - @Override public boolean has(Key key) { - return data.containsKey(key); - } - @Override public Iterable> keys() { - return data.keySet(); - } - - public static FunctionValue regexConstructor(Extensions ext) { - return ext.init(REGEX_CONSTR, new NativeFunction("RegExp", args -> { - throw EngineException.ofError("Regular expressions not supported.").setExtensions(args.ctx); - })); - } - - public Context context() { - return new Context(this); - } -} diff --git a/src/java/me/topchetoeu/jscript/runtime/EventLoop.java b/src/java/me/topchetoeu/jscript/runtime/EventLoop.java index 6046971..9502c7d 100644 --- a/src/java/me/topchetoeu/jscript/runtime/EventLoop.java +++ b/src/java/me/topchetoeu/jscript/runtime/EventLoop.java @@ -3,13 +3,15 @@ package me.topchetoeu.jscript.runtime; import me.topchetoeu.jscript.common.Filename; import me.topchetoeu.jscript.common.ResultRunnable; import me.topchetoeu.jscript.common.events.DataNotifier; +import me.topchetoeu.jscript.runtime.environment.Environment; +import me.topchetoeu.jscript.runtime.environment.Key; import me.topchetoeu.jscript.runtime.exceptions.EngineException; import me.topchetoeu.jscript.runtime.values.FunctionValue; public interface EventLoop { public static final Key KEY = new Key<>(); - public static EventLoop get(Extensions ext) { + public static EventLoop get(Environment ext) { if (ext.hasNotNull(KEY)) return ext.get(KEY); else return new EventLoop() { @Override public DataNotifier pushMsg(ResultRunnable runnable, boolean micro) { @@ -23,15 +25,10 @@ public interface EventLoop { return pushMsg(() -> { runnable.run(); return null; }, micro); } - public default DataNotifier pushMsg(boolean micro, Extensions ext, FunctionValue func, Object thisArg, Object ...args) { - return pushMsg(() -> { - return func.call(Context.of(ext), thisArg, args); - }, micro); + public default DataNotifier pushMsg(boolean micro, Environment env, FunctionValue func, Object thisArg, Object ...args) { + return pushMsg(() -> func.call(env, thisArg, args), micro); } - public default DataNotifier pushMsg(boolean micro, Extensions ext, Filename filename, String raw, Object thisArg, Object ...args) { - return pushMsg(() -> { - var ctx = Context.of(ext); - return ctx.compile(filename, raw).call(Context.of(ext), thisArg, args); - }, micro); + public default DataNotifier pushMsg(boolean micro, Environment env, Filename filename, String raw, Object thisArg, Object ...args) { + return pushMsg(() -> Compiler.compile(env, filename, raw).call(env, thisArg, args), micro); } } diff --git a/src/java/me/topchetoeu/jscript/runtime/Extensions.java b/src/java/me/topchetoeu/jscript/runtime/Extensions.java deleted file mode 100644 index 3410e3e..0000000 --- a/src/java/me/topchetoeu/jscript/runtime/Extensions.java +++ /dev/null @@ -1,77 +0,0 @@ -package me.topchetoeu.jscript.runtime; - -import java.util.List; - -public interface Extensions extends Childable, Copyable { - public static Extensions EMPTY = new Extensions() { - @Override public void add(Key key, T obj) { } - @Override public boolean remove(Key key) { return false; } - - @Override public T get(Key key) { return null; } - @Override public boolean has(Key key) { return false; } - @Override public Iterable> keys() { return List.of(); } - }; - - T get(Key key); - void add(Key key, T obj); - Iterable> keys(); - - boolean has(Key key); - boolean remove(Key key); - - default void add(Key key) { - add(key, null); - } - - default boolean hasNotNull(Key key) { - return has(key) && get(key) != null; - } - - default T get(Key key, T defaultVal) { - if (has(key)) return get(key); - else return defaultVal; - } - - default T init(Key key, T val) { - if (has(key)) return get(key); - else { - add(key, val); - return val; - } - } - @SuppressWarnings("unchecked") - default void addAll(Extensions source) { - if (source == null) return; - for (var key : source.keys()) { - add((Key)key, (Object)source.get(key)); - } - } - - @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)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)key, val); - } - return res; - } - - public static Extensions wrap(Extensions ext) { - if (ext == null) return EMPTY; - else return ext; - } -} diff --git a/src/java/me/topchetoeu/jscript/runtime/Frame.java b/src/java/me/topchetoeu/jscript/runtime/Frame.java index 7cdb025..69e7c19 100644 --- a/src/java/me/topchetoeu/jscript/runtime/Frame.java +++ b/src/java/me/topchetoeu/jscript/runtime/Frame.java @@ -5,6 +5,8 @@ import java.util.Stack; import me.topchetoeu.jscript.common.Instruction; import me.topchetoeu.jscript.runtime.debug.DebugContext; +import me.topchetoeu.jscript.runtime.environment.Environment; +import me.topchetoeu.jscript.runtime.environment.Key; import me.topchetoeu.jscript.runtime.exceptions.EngineException; import me.topchetoeu.jscript.runtime.exceptions.InterruptException; import me.topchetoeu.jscript.runtime.scope.LocalScope; @@ -16,6 +18,8 @@ import me.topchetoeu.jscript.runtime.values.ScopeValue; import me.topchetoeu.jscript.runtime.values.Values; public class Frame { + public static final Key KEY = new Key<>(); + public static enum TryState { TRY, CATCH, @@ -94,11 +98,13 @@ public class Frame { public final Object[] args; public final Stack tryStack = new Stack<>(); public final CodeFunction function; - public final Context ctx; + public final Environment env; + public Object[] stack = new Object[32]; public int stackPtr = 0; public int codePtr = 0; - public boolean jumpFlag = false, popTryFlag = false; + public boolean jumpFlag = false; + public boolean popTryFlag = false; public void addTry(int start, int end, int catchStart, int finallyStart) { var err = tryStack.empty() ? null : tryStack.peek().error; @@ -137,10 +143,10 @@ public class Frame { System.arraycopy(stack, 0, newStack, 0, stack.length); stack = newStack; } - stack[stackPtr++] = Values.normalize(ctx, val); + stack[stackPtr++] = Values.normalize(env, val); } - public Object next(Object value, Object returnValue, EngineException error) { + private Object next(Object value, Object returnValue, EngineException error) { if (value != Values.NO_RETURN) push(value); Instruction instr = null; @@ -148,18 +154,18 @@ public class Frame { if (returnValue == Values.NO_RETURN && error == null) { try { - if (Thread.currentThread().isInterrupted()) throw new InterruptException(); + if (Thread.interrupted()) throw new InterruptException(); if (instr == null) returnValue = null; else { - DebugContext.get(ctx).onInstruction(ctx, this, instr, Values.NO_RETURN, null, false); + DebugContext.get(env).onInstruction(env, this, instr, Values.NO_RETURN, null, false); try { this.jumpFlag = this.popTryFlag = false; - returnValue = InstructionRunner.exec(ctx, instr, this); + returnValue = InstructionRunner.exec(env, instr, this); } catch (EngineException e) { - error = e.add(ctx, function.name, DebugContext.get(ctx).getMapOrEmpty(function).toLocation(codePtr, true)); + error = e.add(env, function.name, DebugContext.get(env).getMapOrEmpty(function).toLocation(codePtr, true)); } } } @@ -201,6 +207,7 @@ public class Frame { tryStack.pop(); tryStack.push(newCtx); } + error = null; returnValue = Values.NO_RETURN; break; @@ -239,33 +246,75 @@ public class Frame { if (error != null) { var caught = false; - for (var frame : ctx.frames()) { + for (var frame : DebugContext.get(env).getStackFrames()) { for (var tryCtx : frame.tryStack) { if (tryCtx.state == TryState.TRY) caught = true; } } - DebugContext.get(ctx).onInstruction(ctx, this, instr, null, error, caught); + DebugContext.get(env).onInstruction(env, this, instr, null, error, caught); throw error; } if (returnValue != Values.NO_RETURN) { - DebugContext.get(ctx).onInstruction(ctx, this, instr, returnValue, null, false); + DebugContext.get(env).onInstruction(env, this, instr, returnValue, null, false); return returnValue; } return Values.NO_RETURN; } - public void onPush() { - DebugContext.get(ctx).onFramePush(ctx, this); + /** + * Executes the next instruction in the frame + */ + public Object next() { + return next(Values.NO_RETURN, Values.NO_RETURN, null); } - public void onPop() { - DebugContext.get(ctx.parent).onFramePop(ctx.parent, this); + /** + * Induces a value on the stack (as if it were returned by the last function call) + * and executes the next instruction in the frame. + * + * @param value The value to induce + */ + public Object next(Object value) { + return next(value, Values.NO_RETURN, null); + } + /** + * Induces a thrown error and executes the next instruction. + * Note that this is different than just throwing the error outside the + * function, as the function executed could have a try-catch which + * would otherwise handle the error + * + * @param error The error to induce + */ + public Object induceError(EngineException error) { + return next(Values.NO_RETURN, Values.NO_RETURN, error); + } + /** + * Induces a return, as if there was a return statement before + * the currently executed instruction and executes the next instruction. + * Note that this is different than just returning the value outside the + * function, as the function executed could have a try-catch which + * would otherwise handle the error + * + * @param value The retunr value to induce + */ + public Object induceReturn(Object value) { + return next(Values.NO_RETURN, value, null); } + public void onPush() { + DebugContext.get(env).onFramePush(env, this); + } + public void onPop() { + DebugContext.get(env).onFramePop(env, this); + } + + /** + * Gets an object proxy of the local scope + */ public ObjectValue getLocalScope() { var names = new String[scope.locals.length]; - var map = DebugContext.get(ctx).getMapOrEmpty(function); + var map = DebugContext.get(env).getMapOrEmpty(function); for (int i = 0; i < scope.locals.length; i++) { var name = "local_" + (i - 2); @@ -279,9 +328,12 @@ public class Frame { return new ScopeValue(scope.locals, names); } + /** + * Gets an object proxy of the capture scope + */ public ObjectValue getCaptureScope() { var names = new String[scope.captures.length]; - var map = DebugContext.get(ctx).getMapOrEmpty(function); + var map = DebugContext.get(env).getMapOrEmpty(function); for (int i = 0; i < scope.captures.length; i++) { var name = "capture_" + (i - 2); @@ -291,16 +343,19 @@ public class Frame { return new ScopeValue(scope.captures, names); } + /** + * Gets an array proxy of the local scope + */ public ObjectValue getValStackScope() { return new ObjectValue() { @Override - protected Object getField(Extensions ext, Object key) { + protected Object getField(Environment ext, Object key) { var i = (int)Values.toNumber(ext, key); if (i < 0 || i >= stackPtr) return null; else return stack[i]; } @Override - protected boolean hasField(Extensions ext, Object key) { + protected boolean hasField(Environment ext, Object key) { return true; } @Override @@ -312,18 +367,18 @@ public class Frame { }; } - public Frame(Context ctx, Object thisArg, Object[] args, CodeFunction func) { + public Frame(Environment env, Object thisArg, Object[] args, CodeFunction func) { + this.env = env; this.args = args.clone(); this.scope = new LocalScope(func.body.localsN, func.captures); this.scope.get(0).set(null, thisArg); var argsObj = new ArrayValue(); for (var i = 0; i < args.length; i++) { - argsObj.set(ctx, i, args[i]); + argsObj.set(env, i, args[i]); } this.scope.get(1).value = argsObj; this.thisArg = thisArg; this.function = func; - this.ctx = ctx.pushFrame(this); } } diff --git a/src/java/me/topchetoeu/jscript/runtime/InstructionRunner.java b/src/java/me/topchetoeu/jscript/runtime/InstructionRunner.java index 7a31109..c7bcfb8 100644 --- a/src/java/me/topchetoeu/jscript/runtime/InstructionRunner.java +++ b/src/java/me/topchetoeu/jscript/runtime/InstructionRunner.java @@ -4,6 +4,7 @@ import java.util.Collections; import me.topchetoeu.jscript.common.Instruction; import me.topchetoeu.jscript.common.Operation; +import me.topchetoeu.jscript.runtime.environment.Environment; import me.topchetoeu.jscript.runtime.exceptions.EngineException; import me.topchetoeu.jscript.runtime.scope.GlobalScope; import me.topchetoeu.jscript.runtime.scope.ValueVariable; @@ -15,17 +16,17 @@ import me.topchetoeu.jscript.runtime.values.Symbol; import me.topchetoeu.jscript.runtime.values.Values; public class InstructionRunner { - private static Object execReturn(Extensions ext, Instruction instr, Frame frame) { + private static Object execReturn(Environment ext, Instruction instr, Frame frame) { return frame.pop(); } - private static Object execThrow(Extensions ext, Instruction instr, Frame frame) { + private static Object execThrow(Environment ext, Instruction instr, Frame frame) { throw new EngineException(frame.pop()); } - private static Object execThrowSyntax(Extensions ext, Instruction instr, Frame frame) { + private static Object execThrowSyntax(Environment ext, Instruction instr, Frame frame) { throw EngineException.ofSyntax((String)instr.get(0)); } - private static Object execCall(Extensions ext, Instruction instr, Frame frame) { + private static Object execCall(Environment ext, Instruction instr, Frame frame) { var callArgs = frame.take(instr.get(0)); var func = frame.pop(); var thisArg = frame.pop(); @@ -35,7 +36,7 @@ public class InstructionRunner { frame.codePtr++; return Values.NO_RETURN; } - private static Object execCallNew(Extensions ext, Instruction instr, Frame frame) { + private static Object execCallNew(Environment ext, Instruction instr, Frame frame) { var callArgs = frame.take(instr.get(0)); var funcObj = frame.pop(); @@ -45,13 +46,13 @@ public class InstructionRunner { return Values.NO_RETURN; } - private static Object execMakeVar(Extensions ext, Instruction instr, Frame frame) { + private static Object execMakeVar(Environment ext, Instruction instr, Frame frame) { var name = (String)instr.get(0); GlobalScope.get(ext).define(ext, name); frame.codePtr++; return Values.NO_RETURN; } - private static Object execDefProp(Extensions ext, Instruction instr, Frame frame) { + private static Object execDefProp(Environment ext, Instruction instr, Frame frame) { var setter = frame.pop(); var getter = frame.pop(); var name = frame.pop(); @@ -66,7 +67,7 @@ public class InstructionRunner { frame.codePtr++; return Values.NO_RETURN; } - private static Object execKeys(Extensions ext, Instruction instr, Frame frame) { + private static Object execKeys(Environment ext, Instruction instr, Frame frame) { var val = frame.pop(); var members = Values.getMembers(ext, val, false, false); @@ -85,7 +86,7 @@ public class InstructionRunner { return Values.NO_RETURN; } - private static Object execTryStart(Extensions ext, Instruction instr, Frame frame) { + private static Object execTryStart(Environment ext, Instruction instr, Frame frame) { int start = frame.codePtr + 1; int catchStart = (int)instr.get(0); int finallyStart = (int)instr.get(1); @@ -96,12 +97,12 @@ public class InstructionRunner { frame.codePtr++; return Values.NO_RETURN; } - private static Object execTryEnd(Extensions ext, Instruction instr, Frame frame) { + private static Object execTryEnd(Environment ext, Instruction instr, Frame frame) { frame.popTryFlag = true; return Values.NO_RETURN; } - private static Object execDup(Extensions ext, Instruction instr, Frame frame) { + private static Object execDup(Environment ext, Instruction instr, Frame frame) { int count = instr.get(0); for (var i = 0; i < count; i++) { @@ -111,7 +112,7 @@ public class InstructionRunner { frame.codePtr++; return Values.NO_RETURN; } - private static Object execLoadValue(Extensions ext, Instruction instr, Frame frame) { + private static Object execLoadValue(Environment ext, Instruction instr, Frame frame) { switch (instr.type) { case PUSH_UNDEFINED: frame.push(null); break; case PUSH_NULL: frame.push(Values.NULL); break; @@ -121,7 +122,7 @@ public class InstructionRunner { frame.codePtr++; return Values.NO_RETURN; } - private static Object execLoadVar(Extensions ext, Instruction instr, Frame frame) { + private static Object execLoadVar(Environment ext, Instruction instr, Frame frame) { var i = instr.get(0); if (i instanceof String) frame.push(GlobalScope.get(ext).get(ext, (String)i)); @@ -130,24 +131,24 @@ public class InstructionRunner { frame.codePtr++; return Values.NO_RETURN; } - private static Object execLoadObj(Extensions ext, Instruction instr, Frame frame) { + private static Object execLoadObj(Environment ext, Instruction instr, Frame frame) { frame.push(new ObjectValue()); frame.codePtr++; return Values.NO_RETURN; } - private static Object execLoadGlob(Extensions ext, Instruction instr, Frame frame) { + private static Object execLoadGlob(Environment ext, Instruction instr, Frame frame) { frame.push(GlobalScope.get(ext).obj); frame.codePtr++; return Values.NO_RETURN; } - private static Object execLoadArr(Extensions ext, Instruction instr, Frame frame) { + private static Object execLoadArr(Environment ext, Instruction instr, Frame frame) { var res = new ArrayValue(); res.setSize(instr.get(0)); frame.push(res); frame.codePtr++; return Values.NO_RETURN; } - private static Object execLoadFunc(Extensions ext, Instruction instr, Frame frame) { + private static Object execLoadFunc(Environment ext, Instruction instr, Frame frame) { int id = instr.get(0); var captures = new ValueVariable[instr.params.length - 1]; @@ -162,7 +163,7 @@ public class InstructionRunner { frame.codePtr++; return Values.NO_RETURN; } - private static Object execLoadMember(Extensions ext, Instruction instr, Frame frame) { + private static Object execLoadMember(Environment ext, Instruction instr, Frame frame) { var key = frame.pop(); var obj = frame.pop(); @@ -175,7 +176,7 @@ public class InstructionRunner { frame.codePtr++; return Values.NO_RETURN; } - private static Object execLoadRegEx(Extensions ext, Instruction instr, Frame frame) { + private static Object execLoadRegEx(Environment ext, Instruction instr, Frame frame) { if (ext.hasNotNull(Environment.REGEX_CONSTR)) { frame.push(Values.callNew(ext, ext.get(Environment.REGEX_CONSTR), instr.get(0), instr.get(1))); } @@ -186,12 +187,12 @@ public class InstructionRunner { return Values.NO_RETURN; } - private static Object execDiscard(Extensions ext, Instruction instr, Frame frame) { + private static Object execDiscard(Environment ext, Instruction instr, Frame frame) { frame.pop(); frame.codePtr++; return Values.NO_RETURN; } - private static Object execStoreMember(Extensions ext, Instruction instr, Frame frame) { + private static Object execStoreMember(Environment ext, Instruction instr, Frame frame) { var val = frame.pop(); var key = frame.pop(); var obj = frame.pop(); @@ -201,7 +202,7 @@ public class InstructionRunner { frame.codePtr++; return Values.NO_RETURN; } - private static Object execStoreVar(Extensions ext, Instruction instr, Frame frame) { + private static Object execStoreVar(Environment ext, Instruction instr, Frame frame) { var val = (boolean)instr.get(1) ? frame.peek() : frame.pop(); var i = instr.get(0); @@ -211,18 +212,18 @@ public class InstructionRunner { frame.codePtr++; return Values.NO_RETURN; } - private static Object execStoreSelfFunc(Extensions ext, Instruction instr, Frame frame) { + private static Object execStoreSelfFunc(Environment ext, Instruction instr, Frame frame) { frame.scope.locals[(int)instr.get(0)].set(ext, frame.function); frame.codePtr++; return Values.NO_RETURN; } - private static Object execJmp(Extensions ext, Instruction instr, Frame frame) { + private static Object execJmp(Environment ext, Instruction instr, Frame frame) { frame.codePtr += (int)instr.get(0); frame.jumpFlag = true; return Values.NO_RETURN; } - private static Object execJmpIf(Extensions ext, Instruction instr, Frame frame) { + private static Object execJmpIf(Environment ext, Instruction instr, Frame frame) { if (Values.toBoolean(frame.pop())) { frame.codePtr += (int)instr.get(0); frame.jumpFlag = true; @@ -230,7 +231,7 @@ public class InstructionRunner { else frame.codePtr ++; return Values.NO_RETURN; } - private static Object execJmpIfNot(Extensions ext, Instruction instr, Frame frame) { + private static Object execJmpIfNot(Environment ext, Instruction instr, Frame frame) { if (Values.not(frame.pop())) { frame.codePtr += (int)instr.get(0); frame.jumpFlag = true; @@ -239,7 +240,7 @@ public class InstructionRunner { return Values.NO_RETURN; } - private static Object execTypeof(Extensions ext, Instruction instr, Frame frame) { + private static Object execTypeof(Environment ext, Instruction instr, Frame frame) { String name = instr.get(0); Object obj; @@ -256,12 +257,12 @@ public class InstructionRunner { frame.codePtr++; return Values.NO_RETURN; } - private static Object execNop(Extensions ext, Instruction instr, Frame frame) { + private static Object execNop(Environment ext, Instruction instr, Frame frame) { frame.codePtr++; return Values.NO_RETURN; } - private static Object execDelete(Extensions ext, Instruction instr, Frame frame) { + private static Object execDelete(Environment ext, Instruction instr, Frame frame) { var key = frame.pop(); var val = frame.pop(); @@ -270,7 +271,7 @@ public class InstructionRunner { return Values.NO_RETURN; } - private static Object execOperation(Extensions ext, Instruction instr, Frame frame) { + private static Object execOperation(Environment ext, Instruction instr, Frame frame) { Operation op = instr.get(0); var args = new Object[op.operands]; @@ -281,7 +282,7 @@ public class InstructionRunner { return Values.NO_RETURN; } - public static Object exec(Extensions ext, Instruction instr, Frame frame) { + public static Object exec(Environment ext, Instruction instr, Frame frame) { switch (instr.type) { case NOP: return execNop(ext, instr, frame); case RETURN: return execReturn(ext, instr, frame); diff --git a/src/java/me/topchetoeu/jscript/runtime/Key.java b/src/java/me/topchetoeu/jscript/runtime/Key.java deleted file mode 100644 index 656efc8..0000000 --- a/src/java/me/topchetoeu/jscript/runtime/Key.java +++ /dev/null @@ -1,5 +0,0 @@ -package me.topchetoeu.jscript.runtime; - -public class Key { - -} diff --git a/src/java/me/topchetoeu/jscript/runtime/WrapperProvider.java b/src/java/me/topchetoeu/jscript/runtime/WrapperProvider.java index 8665625..ac0555b 100644 --- a/src/java/me/topchetoeu/jscript/runtime/WrapperProvider.java +++ b/src/java/me/topchetoeu/jscript/runtime/WrapperProvider.java @@ -1,5 +1,6 @@ package me.topchetoeu.jscript.runtime; +import me.topchetoeu.jscript.runtime.environment.Environment; import me.topchetoeu.jscript.runtime.values.FunctionValue; import me.topchetoeu.jscript.runtime.values.ObjectValue; diff --git a/src/java/me/topchetoeu/jscript/runtime/debug/DebugContext.java b/src/java/me/topchetoeu/jscript/runtime/debug/DebugContext.java index f43e7bc..bb9be07 100644 --- a/src/java/me/topchetoeu/jscript/runtime/debug/DebugContext.java +++ b/src/java/me/topchetoeu/jscript/runtime/debug/DebugContext.java @@ -10,10 +10,9 @@ import me.topchetoeu.jscript.common.FunctionBody; import me.topchetoeu.jscript.common.Instruction; import me.topchetoeu.jscript.common.Location; import me.topchetoeu.jscript.common.mapping.FunctionMap; -import me.topchetoeu.jscript.runtime.Context; -import me.topchetoeu.jscript.runtime.Extensions; import me.topchetoeu.jscript.runtime.Frame; -import me.topchetoeu.jscript.runtime.Key; +import me.topchetoeu.jscript.runtime.environment.Environment; +import me.topchetoeu.jscript.runtime.environment.Key; import me.topchetoeu.jscript.runtime.exceptions.EngineException; import me.topchetoeu.jscript.runtime.values.CodeFunction; import me.topchetoeu.jscript.runtime.values.FunctionValue; @@ -71,15 +70,19 @@ public class DebugContext { if (maps == null || !(func instanceof CodeFunction)) return FunctionMap.EMPTY; return getMapOrEmpty(((CodeFunction)func).body); } + public List getStackFrames() { + return this.debugger.getStackFrame(); + } - public void onFramePop(Context ctx, Frame frame) { - if (debugger != null) debugger.onFramePop(ctx, frame); + public void onFramePop(Environment env, Frame frame) { + if (debugger != null) debugger.onFramePop(env, frame); } - public void onFramePush(Context ctx, Frame frame) { - if (debugger != null) debugger.onFramePush(ctx, frame); + public void onFramePush(Environment env, Frame frame) { + if (debugger != null) debugger.onFramePush(env, frame); } - public boolean onInstruction(Context ctx, Frame frame, Instruction instruction, Object returnVal, EngineException error, boolean caught) { - if (debugger != null) return debugger.onInstruction(ctx, frame, instruction, returnVal, error, caught); + + public boolean onInstruction(Environment env, Frame frame, Instruction instruction, Object returnVal, EngineException error, boolean caught) { + if (debugger != null) return debugger.onInstruction(env, frame, instruction, returnVal, error, caught); else return false; } public void onSource(Filename filename, String source) { @@ -102,26 +105,26 @@ public class DebugContext { this(true); } - public static boolean enabled(Extensions exts) { + public static boolean enabled(Environment exts) { return exts != null && exts.hasNotNull(KEY) && !exts.has(IGNORE); } - public static DebugContext get(Extensions exts) { + public static DebugContext get(Environment exts) { if (enabled(exts)) return exts.get(KEY); else return new DebugContext(false); } - public static List stackTrace(Context ctx) { + public static List stackTrace(Environment env) { var res = new ArrayList(); - var dbgCtx = get(ctx); + var dbgCtx = get(env); - for (var el : ctx.frames()) { - var name = el.function.name; + for (var frame : dbgCtx.getStackFrames()) { + var name = frame.function.name; - var map = dbgCtx.getMapOrEmpty(el.function); + var map = dbgCtx.getMapOrEmpty(frame.function); Location loc = null; if (map != null) { - loc = map.toLocation(el.codePtr, true); + loc = map.toLocation(frame.codePtr, true); if (loc == null) loc = map.start(); } diff --git a/src/java/me/topchetoeu/jscript/runtime/debug/DebugHandler.java b/src/java/me/topchetoeu/jscript/runtime/debug/DebugHandler.java index cb4b786..aad4c68 100644 --- a/src/java/me/topchetoeu/jscript/runtime/debug/DebugHandler.java +++ b/src/java/me/topchetoeu/jscript/runtime/debug/DebugHandler.java @@ -1,11 +1,13 @@ package me.topchetoeu.jscript.runtime.debug; +import java.util.List; + import me.topchetoeu.jscript.common.Filename; import me.topchetoeu.jscript.common.FunctionBody; import me.topchetoeu.jscript.common.Instruction; import me.topchetoeu.jscript.common.mapping.FunctionMap; -import me.topchetoeu.jscript.runtime.Context; import me.topchetoeu.jscript.runtime.Frame; +import me.topchetoeu.jscript.runtime.environment.Environment; import me.topchetoeu.jscript.runtime.exceptions.EngineException; public interface DebugHandler { @@ -35,7 +37,7 @@ public interface DebugHandler { /** * Called immediatly before an instruction is executed, as well as after an instruction, if it has threw or returned. * This function might pause in order to await debugging commands. - * @param ctx The context of execution + * @param env The context of execution * @param frame The frame in which execution is occuring * @param instruction The instruction which was or will be executed * @param returnVal The return value of the instruction, Values.NO_RETURN if none @@ -43,32 +45,35 @@ public interface DebugHandler { * @param caught Whether or not the error has been caught * @return Whether or not the frame should restart (currently does nothing) */ - boolean onInstruction(Context ctx, Frame frame, Instruction instruction, Object returnVal, EngineException error, boolean caught); + boolean onInstruction(Environment env, Frame frame, Instruction instruction, Object returnVal, EngineException error, boolean caught); /** * Called immediatly before a frame has been pushed on the frame stack. * This function might pause in order to await debugging commands. - * @param ctx The context of execution + * @param env The context of execution * @param frame The code frame which was pushed */ - void onFramePush(Context ctx, Frame frame); + void onFramePush(Environment env, Frame frame); /** * Called immediatly after a frame has been popped out of the frame stack. * This function might pause in order to await debugging commands. - * @param ctx The context of execution + * @param env The context of execution * @param frame The code frame which was popped out */ - void onFramePop(Context ctx, Frame frame); + void onFramePop(Environment env, Frame frame); + + List getStackFrame(); public static DebugHandler empty() { return new DebugHandler () { - @Override public void onFramePop(Context ctx, Frame frame) { } - @Override public void onFramePush(Context ctx, Frame frame) { } - @Override public boolean onInstruction(Context ctx, Frame frame, Instruction instruction, Object returnVal, EngineException error, boolean caught) { + @Override public void onFramePop(Environment env, Frame frame) { } + @Override public void onFramePush(Environment env, Frame frame) { } + @Override public boolean onInstruction(Environment env, Frame frame, Instruction instruction, Object returnVal, EngineException error, boolean caught) { return false; } @Override public void onSourceLoad(Filename filename, String source) { } @Override public void onFunctionLoad(FunctionBody body, FunctionMap map) { } + @Override public List getStackFrame() { return List.of(); } }; } } diff --git a/src/java/me/topchetoeu/jscript/runtime/environment/Environment.java b/src/java/me/topchetoeu/jscript/runtime/environment/Environment.java new file mode 100644 index 0000000..24c246e --- /dev/null +++ b/src/java/me/topchetoeu/jscript/runtime/environment/Environment.java @@ -0,0 +1,144 @@ +package me.topchetoeu.jscript.runtime.environment; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Random; +import java.util.Set; +import java.util.function.Supplier; + +import me.topchetoeu.jscript.runtime.Compiler; +import me.topchetoeu.jscript.runtime.values.FunctionValue; +import me.topchetoeu.jscript.runtime.values.ObjectValue; + +public class Environment { + public static final Key COMPILE_FUNC = new Key<>(); + + public static final Key REGEX_CONSTR = new Key<>(); + public static final Key MAX_STACK_COUNT = new Key<>(); + public static final Key HIDE_STACK = new Key<>(); + + public static final Key OBJECT_PROTO = new Key<>(); + public static final Key FUNCTION_PROTO = new Key<>(); + public static final Key ARRAY_PROTO = new Key<>(); + public static final Key BOOL_PROTO = new Key<>(); + public static final Key NUMBER_PROTO = new Key<>(); + public static final Key STRING_PROTO = new Key<>(); + public static final Key SYMBOL_PROTO = new Key<>(); + public static final Key ERROR_PROTO = new Key<>(); + public static final Key SYNTAX_ERR_PROTO = new Key<>(); + public static final Key TYPE_ERR_PROTO = new Key<>(); + public static final Key RANGE_ERR_PROTO = new Key<>(); + + public final Environment parent; + private final Map, Object> map = new HashMap<>(); + private final Set> hidden = new HashSet<>(); + + @SuppressWarnings("unchecked") + public T get(Key key) { + if (map.containsKey(key)) return (T)map.get(key); + else if (!hidden.contains(key) && parent != null) return parent.get(key); + else return null; + } + public boolean has(Key key) { + if (map.containsKey(key)) return true; + else if (!hidden.contains(key) && parent != null) return parent.has(key); + else return false; + } + + @SuppressWarnings("all") + public Set> keys() { + if (parent != null) { + if (map.size() == 0) return (Set)map.keySet(); + + var res = new HashSet(); + res.addAll(parent.keys()); + res.addAll(map.keySet()); + return res; + } + else return (Set)map.keySet(); + } + + public boolean hasNotNull(Key key) { + return get(key) != null; + } + + public T get(Key key, T defaultVal) { + if (has(key)) return get(key); + else return defaultVal; + } + public T get(Key key, Supplier defaultVal) { + if (has(key)) return get(key); + else return defaultVal.get(); + } + + @SuppressWarnings("unchecked") + public Environment add(Key key, T val) { + map.put((Key)key, val); + hidden.remove(key); + return this; + } + @SuppressWarnings("unchecked") + public Environment add(Key key) { + map.put((Key)(Key)key, null); + hidden.remove(key); + return this; + } + @SuppressWarnings("all") + public Environment addAll(Map, ?> map) { + map.putAll((Map)map); + hidden.removeAll(map.keySet()); + return this; + } + public Environment addAll(Environment env) { + this.map.putAll(env.map); + this.hidden.removeAll(env.map.keySet()); + return this; + } + + @SuppressWarnings("unchecked") + public Environment remove(Key key) { + map.remove((Key)key); + hidden.add((Key)key); + return this; + } + + public Environment init(Key key, T val) { + if (!has(key)) this.add(key, val); + return this; + } + public Environment init(Key key, Supplier val) { + if (!has(key)) this.add(key, val.get()); + return this; + } + + public Environment child() { + return new Environment(this); + } + + public Environment(Environment parent) { + this.parent = parent; + } + public Environment() { + this.parent = null; + } + + public static Environment wrap(Environment ext) { + if (ext == null) return empty(); + else return ext; + } + + // public static Environment chain(int id, Environment ...envs) { + // var res = new Environment(); + // for (var env : envs) res.addAll(env); + // return res; + // } + + public static Environment empty() { + return new Environment(); + } + + public static int nextId() { + return new Random().nextInt(); + } +} diff --git a/src/java/me/topchetoeu/jscript/runtime/environment/Key.java b/src/java/me/topchetoeu/jscript/runtime/environment/Key.java new file mode 100644 index 0000000..67a5156 --- /dev/null +++ b/src/java/me/topchetoeu/jscript/runtime/environment/Key.java @@ -0,0 +1,5 @@ +package me.topchetoeu.jscript.runtime.environment; + +public class Key { + +} diff --git a/src/java/me/topchetoeu/jscript/runtime/exceptions/EngineException.java b/src/java/me/topchetoeu/jscript/runtime/exceptions/EngineException.java index 20d19bc..15f0aed 100644 --- a/src/java/me/topchetoeu/jscript/runtime/exceptions/EngineException.java +++ b/src/java/me/topchetoeu/jscript/runtime/exceptions/EngineException.java @@ -4,9 +4,7 @@ import java.util.ArrayList; import java.util.List; import me.topchetoeu.jscript.common.Location; -import me.topchetoeu.jscript.runtime.Context; -import me.topchetoeu.jscript.runtime.Environment; -import me.topchetoeu.jscript.runtime.Extensions; +import me.topchetoeu.jscript.runtime.environment.Environment; import me.topchetoeu.jscript.runtime.values.ObjectValue; import me.topchetoeu.jscript.runtime.values.Values; import me.topchetoeu.jscript.runtime.values.ObjectValue.PlaceholderProto; @@ -15,7 +13,7 @@ public class EngineException extends RuntimeException { public static class StackElement { public final Location location; public final String name; - public final Extensions ext; + public final Environment ext; public boolean visible() { return ext == null || !ext.get(Environment.HIDE_STACK, false); @@ -30,12 +28,12 @@ public class EngineException extends RuntimeException { return res.trim(); } - public StackElement(Extensions ext, Location location, String name) { + public StackElement(Environment ext, Location location, String name) { if (name != null) name = name.trim(); if (name.equals("")) name = null; if (ext == null) this.ext = null; - else this.ext = Context.clean(ext); + else this.ext = ext; this.location = location; this.name = name; @@ -44,13 +42,13 @@ public class EngineException extends RuntimeException { public final Object value; public EngineException cause; - public Extensions ext = null; + public Environment env = null; public final List stackTrace = new ArrayList<>(); - public EngineException add(Extensions ext, String name, Location location) { - var el = new StackElement(ext, location, name); + public EngineException add(Environment env, String name, Location location) { + var el = new StackElement(env, location, name); if (el.name == null && el.location == null) return this; - setExtensions(ext); + setEnvironment(env); stackTrace.add(el); return this; } @@ -58,12 +56,12 @@ public class EngineException extends RuntimeException { this.cause = cause; return this; } - public EngineException setExtensions(Extensions ext) { - if (this.ext == null) this.ext = Context.clean(ext); + public EngineException setEnvironment(Environment env) { + if (this.env == null) this.env = env; return this; } - public String toString(Extensions ext) { + public String toString(Environment ext) { var ss = new StringBuilder(); try { ss.append(Values.toString(ext, value)).append('\n'); diff --git a/src/java/me/topchetoeu/jscript/runtime/scope/GlobalScope.java b/src/java/me/topchetoeu/jscript/runtime/scope/GlobalScope.java index 63eed8e..eb26e61 100644 --- a/src/java/me/topchetoeu/jscript/runtime/scope/GlobalScope.java +++ b/src/java/me/topchetoeu/jscript/runtime/scope/GlobalScope.java @@ -3,8 +3,8 @@ package me.topchetoeu.jscript.runtime.scope; import java.util.HashSet; import java.util.Set; -import me.topchetoeu.jscript.runtime.Extensions; -import me.topchetoeu.jscript.runtime.Key; +import me.topchetoeu.jscript.runtime.environment.Environment; +import me.topchetoeu.jscript.runtime.environment.Key; import me.topchetoeu.jscript.runtime.exceptions.EngineException; import me.topchetoeu.jscript.runtime.values.FunctionValue; import me.topchetoeu.jscript.runtime.values.NativeFunction; @@ -16,7 +16,7 @@ public class GlobalScope { public final ObjectValue obj; - public boolean has(Extensions ext, String name) { + public boolean has(Environment ext, String name) { return Values.hasMember(ext, obj, name, false); } @@ -26,33 +26,33 @@ public class GlobalScope { return new GlobalScope(obj); } - public Object define(Extensions ext, String name) { + public Object define(Environment ext, String name) { if (Values.hasMember(ext, obj, name, false)) return name; obj.defineProperty(ext, name, null); return name; } - public void define(Extensions ext, String name, Variable val) { + public void define(Environment ext, String name, Variable val) { obj.defineProperty(ext, name, - 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("get " + name, args -> val.get(args.env)), + new NativeFunction("set " + name, args -> { val.set(args.env, args.get(0)); return null; }), true, true ); } - public void define(Extensions ext, String name, boolean readonly, Object val) { + public void define(Environment ext, String name, boolean readonly, Object val) { obj.defineProperty(ext, name, val, readonly, true, true); } - public void define(Extensions ext, String ...names) { + public void define(Environment ext, String ...names) { for (var n : names) define(ext, n); } - public void define(Extensions ext, boolean readonly, FunctionValue val) { + public void define(Environment ext, boolean readonly, FunctionValue val) { define(ext, val.name, readonly, val); } - public Object get(Extensions ext, String name) { + public Object get(Environment ext, String name) { if (!Values.hasMember(ext, obj, name, false)) throw EngineException.ofSyntax("The variable '" + name + "' doesn't exist."); else return Values.getMember(ext, obj, name); } - public void set(Extensions ext, String name, Object val) { + public void set(Environment ext, String name, Object val) { if (!Values.hasMember(ext, obj, name, false)) throw EngineException.ofSyntax("The variable '" + name + "' doesn't exist."); if (!Values.setMember(ext, obj, name, val)) throw EngineException.ofSyntax("The global '" + name + "' is readonly."); } @@ -74,7 +74,7 @@ public class GlobalScope { this.obj = val; } - public static GlobalScope get(Extensions ext) { + public static GlobalScope get(Environment ext) { if (ext.has(KEY)) return ext.get(KEY); else return new GlobalScope(); } diff --git a/src/java/me/topchetoeu/jscript/runtime/scope/ValueVariable.java b/src/java/me/topchetoeu/jscript/runtime/scope/ValueVariable.java index eb988b3..60b30fb 100644 --- a/src/java/me/topchetoeu/jscript/runtime/scope/ValueVariable.java +++ b/src/java/me/topchetoeu/jscript/runtime/scope/ValueVariable.java @@ -1,6 +1,6 @@ package me.topchetoeu.jscript.runtime.scope; -import me.topchetoeu.jscript.runtime.Extensions; +import me.topchetoeu.jscript.runtime.environment.Environment; import me.topchetoeu.jscript.runtime.values.Values; public class ValueVariable implements Variable { @@ -11,12 +11,12 @@ public class ValueVariable implements Variable { public boolean readonly() { return readonly; } @Override - public Object get(Extensions ext) { + public Object get(Environment ext) { return value; } @Override - public void set(Extensions ext, Object val) { + public void set(Environment ext, Object val) { if (readonly) return; this.value = Values.normalize(ext, val); } diff --git a/src/java/me/topchetoeu/jscript/runtime/scope/Variable.java b/src/java/me/topchetoeu/jscript/runtime/scope/Variable.java index 6d00d80..db5fb89 100644 --- a/src/java/me/topchetoeu/jscript/runtime/scope/Variable.java +++ b/src/java/me/topchetoeu/jscript/runtime/scope/Variable.java @@ -1,9 +1,9 @@ package me.topchetoeu.jscript.runtime.scope; -import me.topchetoeu.jscript.runtime.Extensions; +import me.topchetoeu.jscript.runtime.environment.Environment; public interface Variable { - Object get(Extensions ext); + Object get(Environment ext); default boolean readonly() { return true; } - default void set(Extensions ext, Object val) { } + default void set(Environment ext, Object val) { } } diff --git a/src/java/me/topchetoeu/jscript/runtime/values/ArrayValue.java b/src/java/me/topchetoeu/jscript/runtime/values/ArrayValue.java index a13c014..0214505 100644 --- a/src/java/me/topchetoeu/jscript/runtime/values/ArrayValue.java +++ b/src/java/me/topchetoeu/jscript/runtime/values/ArrayValue.java @@ -6,7 +6,7 @@ import java.util.Comparator; import java.util.Iterator; import java.util.List; -import me.topchetoeu.jscript.runtime.Extensions; +import me.topchetoeu.jscript.runtime.environment.Environment; // TODO: Make methods generic public class ArrayValue extends ObjectValue implements Iterable { @@ -41,7 +41,7 @@ public class ArrayValue extends ObjectValue implements Iterable { if (res == UNDEFINED) return null; else return res; } - public void set(Extensions ext, int i, Object val) { + public void set(Environment ext, int i, Object val) { if (i < 0) return; values = alloc(i); @@ -99,7 +99,7 @@ public class ArrayValue extends ObjectValue implements Iterable { } } - public void copyFrom(Extensions ext, Object[] arr, int sourceStart, int destStart, int count) { + public void copyFrom(Environment ext, Object[] arr, int sourceStart, int destStart, int count) { for (var i = 0; i < count; i++) { set(ext, i + destStart, arr[i + sourceStart]); } @@ -131,7 +131,7 @@ public class ArrayValue extends ObjectValue implements Iterable { } @Override - protected Object getField(Extensions ext, Object key) { + protected Object getField(Environment ext, Object key) { if (key instanceof Number) { var i = ((Number)key).doubleValue(); if (i >= 0 && i - Math.floor(i) == 0) { @@ -142,7 +142,7 @@ public class ArrayValue extends ObjectValue implements Iterable { return super.getField(ext, key); } @Override - protected boolean setField(Extensions ext, Object key, Object val) { + protected boolean setField(Environment ext, Object key, Object val) { if (key instanceof Number) { var i = Values.number(key); if (i >= 0 && i - Math.floor(i) == 0) { @@ -154,7 +154,7 @@ public class ArrayValue extends ObjectValue implements Iterable { return super.setField(ext, key, val); } @Override - protected boolean hasField(Extensions ext, Object key) { + protected boolean hasField(Environment ext, Object key) { if (key instanceof Number) { var i = Values.number(key); if (i >= 0 && i - Math.floor(i) == 0) { @@ -165,7 +165,7 @@ public class ArrayValue extends ObjectValue implements Iterable { return super.hasField(ext, key); } @Override - protected void deleteField(Extensions ext, Object key) { + protected void deleteField(Environment ext, Object key) { if (key instanceof Number) { var i = Values.number(key); if (i >= 0 && i - Math.floor(i) == 0) { @@ -213,7 +213,7 @@ public class ArrayValue extends ObjectValue implements Iterable { values = new Object[cap]; size = 0; } - public ArrayValue(Extensions ext, Object ...values) { + public ArrayValue(Environment ext, Object ...values) { this(); this.values = new Object[values.length]; size = values.length; @@ -221,7 +221,7 @@ public class ArrayValue extends ObjectValue implements Iterable { for (var i = 0; i < size; i++) this.values[i] = Values.normalize(ext, values[i]); } - public static ArrayValue of(Extensions ext, Collection values) { + public static ArrayValue of(Environment ext, Collection values) { return new ArrayValue(ext, values.toArray(Object[]::new)); } } diff --git a/src/java/me/topchetoeu/jscript/runtime/values/CodeFunction.java b/src/java/me/topchetoeu/jscript/runtime/values/CodeFunction.java index 2d0df77..ba5a909 100644 --- a/src/java/me/topchetoeu/jscript/runtime/values/CodeFunction.java +++ b/src/java/me/topchetoeu/jscript/runtime/values/CodeFunction.java @@ -1,15 +1,14 @@ package me.topchetoeu.jscript.runtime.values; import me.topchetoeu.jscript.common.FunctionBody; -import me.topchetoeu.jscript.runtime.Context; -import me.topchetoeu.jscript.runtime.Extensions; import me.topchetoeu.jscript.runtime.Frame; +import me.topchetoeu.jscript.runtime.environment.Environment; import me.topchetoeu.jscript.runtime.scope.ValueVariable; public class CodeFunction extends FunctionValue { public final FunctionBody body; public final ValueVariable[] captures; - public Extensions extensions; + public Environment env; // public Location loc() { // for (var instr : body.instructions) { @@ -24,15 +23,13 @@ public class CodeFunction extends FunctionValue { // else return name + "@" + loc; // } - @Override - public Object call(Extensions ext, Object thisArg, Object ...args) { - var frame = new Frame(Context.of(ext), thisArg, args, this); - + @Override public Object call(Environment env, Object thisArg, Object ...args) { + var frame = new Frame(env, thisArg, args, this); frame.onPush(); try { while (true) { - var res = frame.next(Values.NO_RETURN, Values.NO_RETURN, null); + var res = frame.next(); if (res != Values.NO_RETURN) return res; } } @@ -41,10 +38,10 @@ public class CodeFunction extends FunctionValue { } } - public CodeFunction(Extensions extensions, String name, FunctionBody body, ValueVariable[] captures) { + public CodeFunction(Environment env, String name, FunctionBody body, ValueVariable[] captures) { super(name, body.argsN); this.captures = captures; - this.extensions = Context.clean(extensions); + this.env = env; this.body = body; } } diff --git a/src/java/me/topchetoeu/jscript/runtime/values/FunctionValue.java b/src/java/me/topchetoeu/jscript/runtime/values/FunctionValue.java index ced4c9a..115f855 100644 --- a/src/java/me/topchetoeu/jscript/runtime/values/FunctionValue.java +++ b/src/java/me/topchetoeu/jscript/runtime/values/FunctionValue.java @@ -2,7 +2,7 @@ package me.topchetoeu.jscript.runtime.values; import java.util.List; -import me.topchetoeu.jscript.runtime.Extensions; +import me.topchetoeu.jscript.runtime.environment.Environment; public abstract class FunctionValue extends ObjectValue { public String name = ""; @@ -13,26 +13,26 @@ public abstract class FunctionValue extends ObjectValue { return String.format("function %s(...)", name); } - public abstract Object call(Extensions ext, Object thisArg, Object ...args); - public Object call(Extensions ext) { + public abstract Object call(Environment ext, Object thisArg, Object ...args); + public Object call(Environment ext) { return call(ext, null); } @Override - protected Object getField(Extensions ext, Object key) { + protected Object getField(Environment ext, Object key) { if ("name".equals(key)) return name; if ("length".equals(key)) return length; return super.getField(ext, key); } @Override - protected boolean setField(Extensions ext, Object key, Object val) { + protected boolean setField(Environment ext, Object key, Object val) { if ("name".equals(key)) name = Values.toString(ext, val); else if ("length".equals(key)) length = (int)Values.toNumber(ext, val); else return super.setField(ext, key, val); return true; } @Override - protected boolean hasField(Extensions ext, Object key) { + protected boolean hasField(Environment ext, Object key) { if ("name".equals(key)) return true; if ("length".equals(key)) return true; return super.hasField(ext, key); diff --git a/src/java/me/topchetoeu/jscript/runtime/values/NativeFunction.java b/src/java/me/topchetoeu/jscript/runtime/values/NativeFunction.java index e1145f9..3746568 100644 --- a/src/java/me/topchetoeu/jscript/runtime/values/NativeFunction.java +++ b/src/java/me/topchetoeu/jscript/runtime/values/NativeFunction.java @@ -1,7 +1,6 @@ package me.topchetoeu.jscript.runtime.values; -import me.topchetoeu.jscript.runtime.Context; -import me.topchetoeu.jscript.runtime.Extensions; +import me.topchetoeu.jscript.runtime.environment.Environment; import me.topchetoeu.jscript.utils.interop.Arguments; public class NativeFunction extends FunctionValue { @@ -12,8 +11,8 @@ public class NativeFunction extends FunctionValue { public final NativeFunctionRunner action; @Override - public Object call(Extensions ext, Object thisArg, Object ...args) { - return action.run(new Arguments(Context.of(ext), thisArg, args)); + public Object call(Environment env, Object thisArg, Object ...args) { + return action.run(new Arguments(env, thisArg, args)); } public NativeFunction(String name, NativeFunctionRunner action) { diff --git a/src/java/me/topchetoeu/jscript/runtime/values/NativeWrapper.java b/src/java/me/topchetoeu/jscript/runtime/values/NativeWrapper.java index 938bc73..c2fbf55 100644 --- a/src/java/me/topchetoeu/jscript/runtime/values/NativeWrapper.java +++ b/src/java/me/topchetoeu/jscript/runtime/values/NativeWrapper.java @@ -2,8 +2,8 @@ package me.topchetoeu.jscript.runtime.values; import java.util.WeakHashMap; -import me.topchetoeu.jscript.runtime.Extensions; -import me.topchetoeu.jscript.runtime.Key; +import me.topchetoeu.jscript.runtime.environment.Environment; +import me.topchetoeu.jscript.runtime.environment.Key; import me.topchetoeu.jscript.utils.interop.NativeWrapperProvider; public class NativeWrapper extends ObjectValue { @@ -28,12 +28,12 @@ public class NativeWrapper extends ObjectValue { } } - private static final Key> WRAPPERS = new Key<>(); + private static final Key> WRAPPER_MAP = new Key<>(); private static final Object NATIVE_PROTO = new Object(); public final Object wrapped; @Override - public ObjectValue getPrototype(Extensions ext) { + public ObjectValue getPrototype(Environment ext) { if (ext != null && prototype == NATIVE_PROTO) { var clazz = wrapped.getClass(); var res = NativeWrapperProvider.get(ext).getProto(clazz); @@ -60,17 +60,13 @@ public class NativeWrapper extends ObjectValue { prototype = NATIVE_PROTO; } - public static NativeWrapper of(Extensions exts, Object wrapped) { - if (exts == null) return new NativeWrapper(wrapped); - var wrappers = exts.get(WRAPPERS); + public static NativeWrapper of(Environment env, Object wrapped) { + if (env == null) return new NativeWrapper(wrapped); - if (wrappers == null) { - wrappers = new WeakHashMap<>(); - exts.add(WRAPPERS, wrappers); - } + var wrappers = env.get(WRAPPER_MAP); + if (wrappers == null) return new NativeWrapper(wrapped); var key = new MapKey(wrapped); - if (wrappers.containsKey(key)) return wrappers.get(key); var res = new NativeWrapper(wrapped); diff --git a/src/java/me/topchetoeu/jscript/runtime/values/ObjectValue.java b/src/java/me/topchetoeu/jscript/runtime/values/ObjectValue.java index c1e0768..aabb1f1 100644 --- a/src/java/me/topchetoeu/jscript/runtime/values/ObjectValue.java +++ b/src/java/me/topchetoeu/jscript/runtime/values/ObjectValue.java @@ -6,8 +6,7 @@ import java.util.LinkedHashSet; import java.util.List; import java.util.Map; -import me.topchetoeu.jscript.runtime.Environment; -import me.topchetoeu.jscript.runtime.Extensions; +import me.topchetoeu.jscript.runtime.environment.Environment; public class ObjectValue { public static enum PlaceholderProto { @@ -54,10 +53,10 @@ public class ObjectValue { public LinkedHashSet nonConfigurableSet = new LinkedHashSet<>(); public LinkedHashSet nonEnumerableSet = new LinkedHashSet<>(); - private Property getProperty(Extensions ext, Object key) { + private Property getProperty(Environment env, Object key) { if (properties.containsKey(key)) return properties.get(key); - var proto = getPrototype(ext); - if (proto != null) return proto.getProperty(ext, key); + var proto = getPrototype(env); + if (proto != null) return proto.getProperty(env, key); else return null; } @@ -86,8 +85,8 @@ public class ObjectValue { state = State.FROZEN; } - public final boolean defineProperty(Extensions ext, Object key, Object val, boolean writable, boolean configurable, boolean enumerable) { - key = Values.normalize(ext, key); val = Values.normalize(ext, val); + public final boolean defineProperty(Environment env, Object key, Object val, boolean writable, boolean configurable, boolean enumerable) { + key = Values.normalize(env, key); val = Values.normalize(env, val); boolean reconfigured = writable != memberWritable(key) || configurable != memberConfigurable(key) || @@ -125,11 +124,11 @@ public class ObjectValue { values.put(key, val); return true; } - public final boolean defineProperty(Extensions ext, Object key, Object val) { - return defineProperty(ext, key, val, true, true, true); + public final boolean defineProperty(Environment env, Object key, Object val) { + return defineProperty(env, key, val, true, true, true); } - public final boolean defineProperty(Extensions ext, Object key, FunctionValue getter, FunctionValue setter, boolean configurable, boolean enumerable) { - key = Values.normalize(ext, key); + public final boolean defineProperty(Environment env, Object key, FunctionValue getter, FunctionValue setter, boolean configurable, boolean enumerable) { + key = Values.normalize(env, key); if ( properties.containsKey(key) && properties.get(key).getter == getter && @@ -152,17 +151,17 @@ public class ObjectValue { return true; } - public ObjectValue getPrototype(Extensions ext) { + public ObjectValue getPrototype(Environment env) { if (prototype instanceof ObjectValue || prototype == null) return (ObjectValue)prototype; try { - if (prototype == ARR_PROTO) return ext.get(Environment.ARRAY_PROTO); - if (prototype == FUNC_PROTO) return ext.get(Environment.FUNCTION_PROTO); - if (prototype == ERR_PROTO) return ext.get(Environment.ERROR_PROTO); - if (prototype == RANGE_ERR_PROTO) return ext.get(Environment.RANGE_ERR_PROTO); - if (prototype == SYNTAX_ERR_PROTO) return ext.get(Environment.SYNTAX_ERR_PROTO); - if (prototype == TYPE_ERR_PROTO) return ext.get(Environment.TYPE_ERR_PROTO); - return ext.get(Environment.OBJECT_PROTO); + if (prototype == ARR_PROTO) return env.get(Environment.ARRAY_PROTO); + if (prototype == FUNC_PROTO) return env.get(Environment.FUNCTION_PROTO); + if (prototype == ERR_PROTO) return env.get(Environment.ERROR_PROTO); + if (prototype == RANGE_ERR_PROTO) return env.get(Environment.RANGE_ERR_PROTO); + if (prototype == SYNTAX_ERR_PROTO) return env.get(Environment.SYNTAX_ERR_PROTO); + if (prototype == TYPE_ERR_PROTO) return env.get(Environment.TYPE_ERR_PROTO); + return env.get(Environment.OBJECT_PROTO); } catch (NullPointerException e) { return null; } } @@ -185,10 +184,10 @@ public class ObjectValue { * 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. */ - protected Object getField(Extensions ext, Object key) { + protected Object getField(Environment env, Object key) { if (values.containsKey(key)) return values.get(key); - var proto = getPrototype(ext); - if (proto != null) return proto.getField(ext, key); + var proto = getPrototype(env); + if (proto != null) return proto.getField(env, key); else return null; } /** @@ -196,9 +195,9 @@ public class ObjectValue { * bound to this key, a new field should be created with the given value * @return Whether or not the operation was successful */ - protected boolean setField(Extensions ext, Object key, Object val) { + protected boolean setField(Environment env, Object key, Object val) { if (val instanceof FunctionValue && ((FunctionValue)val).name.equals("")) { - ((FunctionValue)val).name = Values.toString(ext, key); + ((FunctionValue)val).name = Values.toString(env, key); } values.put(key, val); @@ -207,40 +206,40 @@ public class ObjectValue { /** * Deletes the field bound to the given key. */ - protected void deleteField(Extensions ext, Object key) { + protected void deleteField(Environment env, Object key) { values.remove(key); } /** * Returns whether or not there is a field bound to the given key. * This must ignore properties */ - protected boolean hasField(Extensions ext, Object key) { + protected boolean hasField(Environment env, Object key) { return values.containsKey(key); } - public final Object getMember(Extensions ext, Object key, Object thisArg) { - key = Values.normalize(ext, key); + public final Object getMember(Environment env, Object key, Object thisArg) { + key = Values.normalize(env, key); if ("__proto__".equals(key)) { - var res = getPrototype(ext); + var res = getPrototype(env); return res == null ? Values.NULL : res; } - var prop = getProperty(ext, key); + var prop = getProperty(env, key); if (prop != null) { if (prop.getter == null) return null; - else return prop.getter.call(ext, Values.normalize(ext, thisArg)); + else return prop.getter.call(env, Values.normalize(env, thisArg)); } - else return getField(ext, key); + else return getField(env, key); } - public final boolean setMember(Extensions ext, Object key, Object val, Object thisArg, boolean onlyProps) { - key = Values.normalize(ext, key); val = Values.normalize(ext, val); + public final boolean setMember(Environment env, Object key, Object val, Object thisArg, boolean onlyProps) { + key = Values.normalize(env, key); val = Values.normalize(env, val); - var prop = getProperty(ext, key); + var prop = getProperty(env, key); if (prop != null) { if (prop.setter == null) return false; - prop.setter.call(ext, Values.normalize(ext, thisArg), val); + prop.setter.call(env, Values.normalize(env, thisArg), val); return true; } else if (onlyProps) return false; @@ -249,32 +248,32 @@ public class ObjectValue { values.put(key, val); return true; } - else if ("__proto__".equals(key)) return setPrototype(ext, val); + else if ("__proto__".equals(key)) return setPrototype(env, val); else if (nonWritableSet.contains(key)) return false; - else return setField(ext, key, val); + else return setField(env, key, val); } - public final boolean hasMember(Extensions ext, Object key, boolean own) { - key = Values.normalize(ext, key); + public final boolean hasMember(Environment env, Object key, boolean own) { + key = Values.normalize(env, key); if (key != null && "__proto__".equals(key)) return true; - if (hasField(ext, key)) return true; + if (hasField(env, key)) return true; if (properties.containsKey(key)) return true; if (own) return false; - var proto = getPrototype(ext); - return proto != null && proto.hasMember(ext, key, own); + var proto = getPrototype(env); + return proto != null && proto.hasMember(env, key, own); } - public final boolean deleteMember(Extensions ext, Object key) { - key = Values.normalize(ext, key); + public final boolean deleteMember(Environment env, Object key) { + key = Values.normalize(env, key); if (!memberConfigurable(key)) return false; properties.remove(key); nonWritableSet.remove(key); nonEnumerableSet.remove(key); - deleteField(ext, key); + deleteField(env, key); return true; } - public final boolean setPrototype(Extensions ext, Object val) { - val = Values.normalize(ext, val); + public final boolean setPrototype(Environment env, Object val) { + val = Values.normalize(env, val); if (!extensible()) return false; if (val == null || val == Values.NULL) { @@ -284,14 +283,14 @@ public class ObjectValue { else if (val instanceof ObjectValue) { var obj = (ObjectValue)val; - if (ext != null) { - if (obj == ext.get(Environment.OBJECT_PROTO)) prototype = OBJ_PROTO; - else if (obj == ext.get(Environment.ARRAY_PROTO)) prototype = ARR_PROTO; - else if (obj == ext.get(Environment.FUNCTION_PROTO)) prototype = FUNC_PROTO; - else if (obj == ext.get(Environment.ERROR_PROTO)) prototype = ERR_PROTO; - else if (obj == ext.get(Environment.SYNTAX_ERR_PROTO)) prototype = SYNTAX_ERR_PROTO; - else if (obj == ext.get(Environment.TYPE_ERR_PROTO)) prototype = TYPE_ERR_PROTO; - else if (obj == ext.get(Environment.RANGE_ERR_PROTO)) prototype = RANGE_ERR_PROTO; + if (env != null) { + if (obj == env.get(Environment.OBJECT_PROTO)) prototype = OBJ_PROTO; + else if (obj == env.get(Environment.ARRAY_PROTO)) prototype = ARR_PROTO; + else if (obj == env.get(Environment.FUNCTION_PROTO)) prototype = FUNC_PROTO; + else if (obj == env.get(Environment.ERROR_PROTO)) prototype = ERR_PROTO; + else if (obj == env.get(Environment.SYNTAX_ERR_PROTO)) prototype = SYNTAX_ERR_PROTO; + else if (obj == env.get(Environment.TYPE_ERR_PROTO)) prototype = TYPE_ERR_PROTO; + else if (obj == env.get(Environment.RANGE_ERR_PROTO)) prototype = RANGE_ERR_PROTO; else prototype = obj; } else prototype = obj; @@ -301,22 +300,22 @@ public class ObjectValue { return false; } - public final ObjectValue getMemberDescriptor(Extensions ext, Object key) { - key = Values.normalize(ext, key); + public final ObjectValue getMemberDescriptor(Environment env, Object key) { + key = Values.normalize(env, key); var prop = properties.get(key); var res = new ObjectValue(); - res.defineProperty(ext, "configurable", memberConfigurable(key)); - res.defineProperty(ext, "enumerable", memberEnumerable(key)); + res.defineProperty(env, "configurable", memberConfigurable(key)); + res.defineProperty(env, "enumerable", memberEnumerable(key)); if (prop != null) { - res.defineProperty(ext, "get", prop.getter); - res.defineProperty(ext, "set", prop.setter); + res.defineProperty(env, "get", prop.getter); + res.defineProperty(env, "set", prop.setter); } - else if (hasField(ext, key)) { - res.defineProperty(ext, "value", values.get(key)); - res.defineProperty(ext, "writable", memberWritable(key)); + else if (hasField(env, key)) { + res.defineProperty(env, "value", values.get(key)); + res.defineProperty(env, "writable", memberWritable(key)); } else return null; return res; @@ -337,10 +336,10 @@ public class ObjectValue { return res; } - public ObjectValue(Extensions ext, Map values) { + public ObjectValue(Environment env, Map values) { this(PlaceholderProto.OBJECT); for (var el : values.entrySet()) { - defineProperty(ext, el.getKey(), el.getValue()); + defineProperty(env, el.getKey(), el.getValue()); } } public ObjectValue(PlaceholderProto proto) { diff --git a/src/java/me/topchetoeu/jscript/runtime/values/ScopeValue.java b/src/java/me/topchetoeu/jscript/runtime/values/ScopeValue.java index a64f4c2..3abf2ee 100644 --- a/src/java/me/topchetoeu/jscript/runtime/values/ScopeValue.java +++ b/src/java/me/topchetoeu/jscript/runtime/values/ScopeValue.java @@ -3,7 +3,7 @@ package me.topchetoeu.jscript.runtime.values; import java.util.HashMap; import java.util.List; -import me.topchetoeu.jscript.runtime.Extensions; +import me.topchetoeu.jscript.runtime.environment.Environment; import me.topchetoeu.jscript.runtime.scope.ValueVariable; public class ScopeValue extends ObjectValue { @@ -11,12 +11,12 @@ public class ScopeValue extends ObjectValue { public final HashMap names = new HashMap<>(); @Override - protected Object getField(Extensions ext, Object key) { + protected Object getField(Environment ext, Object key) { if (names.containsKey(key)) return variables[names.get(key)].get(ext); return super.getField(ext, key); } @Override - protected boolean setField(Extensions ext, Object key, Object val) { + protected boolean setField(Environment ext, Object key, Object val) { if (names.containsKey(key)) { variables[names.get(key)].set(ext, val); return true; @@ -28,12 +28,12 @@ public class ScopeValue extends ObjectValue { return super.setField(ext, key, val); } @Override - protected void deleteField(Extensions ext, Object key) { + protected void deleteField(Environment ext, Object key) { if (names.containsKey(key)) return; super.deleteField(ext, key); } @Override - protected boolean hasField(Extensions ext, Object key) { + protected boolean hasField(Environment ext, Object key) { if (names.containsKey(key)) return true; return super.hasField(ext, key); } diff --git a/src/java/me/topchetoeu/jscript/runtime/values/Value.java b/src/java/me/topchetoeu/jscript/runtime/values/Value.java new file mode 100644 index 0000000..a240ec0 --- /dev/null +++ b/src/java/me/topchetoeu/jscript/runtime/values/Value.java @@ -0,0 +1,733 @@ +package me.topchetoeu.jscript.runtime.values; + +import java.io.ByteArrayOutputStream; +import java.io.PrintStream; +import java.lang.reflect.Array; +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import me.topchetoeu.jscript.common.Operation; +// import me.topchetoeu.jscript.lib.PromiseLib; +import me.topchetoeu.jscript.runtime.debug.DebugContext; +import me.topchetoeu.jscript.runtime.environment.Environment; +import me.topchetoeu.jscript.runtime.exceptions.ConvertException; +import me.topchetoeu.jscript.runtime.exceptions.EngineException; +import me.topchetoeu.jscript.runtime.exceptions.SyntaxException; +import me.topchetoeu.jscript.utils.interop.NativeWrapperProvider; + +public interface Value { + public static enum CompareResult { + NOT_EQUAL, + EQUAL, + LESS, + GREATER; + + public boolean less() { return this == LESS; } + public boolean greater() { return this == GREATER; } + public boolean lessOrEqual() { return this == LESS || this == EQUAL; } + public boolean greaterOrEqual() { return this == GREATER || this == EQUAL; } + + public static CompareResult from(int cmp) { + if (cmp < 0) return LESS; + if (cmp > 0) return GREATER; + return EQUAL; + } + } + + public static final Object NULL = new Object(); + public static final Object NO_RETURN = new Object(); + + public static double number(Object val) { + if (val instanceof Number) return ((Number)val).doubleValue(); + else return Double.NaN; + } + + @SuppressWarnings("unchecked") + public static T wrapper(Object val, Class clazz) { + if (isWrapper(val)) val = ((NativeWrapper)val).wrapped; + if (val != null && clazz.isInstance(val)) return (T)val; + else return null; + } + + public static String type(Object val) { + if (val == null) return "undefined"; + if (val instanceof String) return "string"; + if (val instanceof Number) return "number"; + if (val instanceof Boolean) return "boolean"; + if (val instanceof Symbol) return "symbol"; + if (val instanceof FunctionValue) return "function"; + return "object"; + } + + public boolean isPrimitive(); + public BooleanValue toBoolean(); + + public default Value call(Environment env, Value self, Value ...args) { + throw EngineException.ofType("Tried to call a non-function value."); + } + public default Value callNew(Environment env, Value ...args) { + var res = new ObjectValue(); + + try { + var proto = Values.getMember(env, this, "prototype"); + setPrototype(env, res, proto); + + var ret = this.call(env, res, args); + + if (!ret.isPrimitive()) return ret; + return res; + } + catch (IllegalArgumentException e) { + throw EngineException.ofType("Tried to call new on an invalid constructor."); + } + } + + public default Value toPrimitive(Environment env, Value val) { + if (val.isPrimitive()) return val; + + if (env != null) { + var valueOf = getMember(env, val, "valueOf"); + + if (valueOf instanceof FunctionValue) { + var res = valueOf.call(env, val); + if (res.isPrimitive()) return res; + } + + var toString = getMember(env, val, "toString"); + if (toString instanceof FunctionValue) { + var res = toString.call(env, val); + if (res.isPrimitive()) return res; + } + } + + throw EngineException.ofType("Value couldn't be converted to a primitive."); + } + public default NumberValue toNumber(Environment ext, Object obj) { + var val = this.toPrimitive(ext, obj, ConvertHint.VALUEOF); + + if (val instanceof NumberValue) return number(val); + if (val instanceof Boolean) return ((Boolean)val) ? 1 : 0; + if (val instanceof String) { + try { return Double.parseDouble((String)val); } + catch (NumberFormatException e) { return Double.NaN; } + } + return Double.NaN; + } + public default StringValue toString(Environment ext, Object obj) { + var val = toPrimitive(ext, obj, ConvertHint.VALUEOF); + + if (val == null) return "undefined"; + if (val == NULL) return "null"; + + if (val instanceof Number) { + var d = number(val); + if (d == Double.NEGATIVE_INFINITY) return "-Infinity"; + if (d == Double.POSITIVE_INFINITY) return "Infinity"; + if (Double.isNaN(d)) return "NaN"; + return BigDecimal.valueOf(d).stripTrailingZeros().toPlainString(); + } + if (val instanceof Boolean) return (Boolean)val ? "true" : "false"; + if (val instanceof String) return (String)val; + if (val instanceof Symbol) return val.toString(); + + return "Unknown value"; + } + + public static Object add(Environment ext, Object a, Object b) { + if (a instanceof String || b instanceof String) return toString(ext, a) + toString(ext, b); + else return toNumber(ext, a) + toNumber(ext, b); + } + public static double subtract(Environment ext, Object a, Object b) { + return toNumber(ext, a) - toNumber(ext, b); + } + public static double multiply(Environment ext, Object a, Object b) { + return toNumber(ext, a) * toNumber(ext, b); + } + public static double divide(Environment ext, Object a, Object b) { + return toNumber(ext, a) / toNumber(ext, b); + } + public static double modulo(Environment ext, Object a, Object b) { + return toNumber(ext, a) % toNumber(ext, b); + } + + public static double negative(Environment ext, Object obj) { + return -toNumber(ext, obj); + } + + public static int and(Environment ext, Object a, Object b) { + return (int)toNumber(ext, a) & (int)toNumber(ext, b); + } + public static int or(Environment ext, Object a, Object b) { + return (int)toNumber(ext, a) | (int)toNumber(ext, b); + } + public static int xor(Environment ext, Object a, Object b) { + return (int)toNumber(ext, a) ^ (int)toNumber(ext, b); + } + public static int bitwiseNot(Environment ext, Object obj) { + return ~(int)toNumber(ext, obj); + } + + public static int shiftLeft(Environment ext, Object a, Object b) { + return (int)toNumber(ext, a) << (int)toNumber(ext, b); + } + public static int shiftRight(Environment ext, Object a, Object b) { + return (int)toNumber(ext, a) >> (int)toNumber(ext, b); + } + public static long unsignedShiftRight(Environment ext, Object a, Object b) { + long _a = (long)toNumber(ext, a); + long _b = (long)toNumber(ext, b); + + if (_a < 0) _a += 0x100000000l; + if (_b < 0) _b += 0x100000000l; + return _a >>> _b; + } + + public static CompareResult compare(Environment ext, Object a, Object b) { + a = toPrimitive(ext, a, ConvertHint.VALUEOF); + b = toPrimitive(ext, b, ConvertHint.VALUEOF); + + if (a instanceof String && b instanceof String) CompareResult.from(((String)a).compareTo((String)b)); + + var _a = toNumber(ext, a); + var _b = toNumber(ext, b); + + if (Double.isNaN(_a) || Double.isNaN(_b)) return CompareResult.NOT_EQUAL; + + return CompareResult.from(Double.compare(_a, _b)); + } + + public static boolean not(Object obj) { + return !toBoolean(obj); + } + + public static boolean isInstanceOf(Environment ext, Object obj, Object proto) { + if (obj == null || obj == NULL || proto == null || proto == NULL) return false; + var val = getPrototype(ext, obj); + + while (val != null) { + if (val.equals(proto)) return true; + val = val.getPrototype(ext); + } + + return false; + } + + public static Object operation(Environment ext, Operation op, Object ...args) { + switch (op) { + case ADD: return add(ext, args[0], args[1]); + case SUBTRACT: return subtract(ext, args[0], args[1]); + case DIVIDE: return divide(ext, args[0], args[1]); + case MULTIPLY: return multiply(ext, args[0], args[1]); + case MODULO: return modulo(ext, args[0], args[1]); + + case AND: return and(ext, args[0], args[1]); + case OR: return or(ext, args[0], args[1]); + case XOR: return xor(ext, args[0], args[1]); + + case EQUALS: return strictEquals(ext, args[0], args[1]); + case NOT_EQUALS: return !strictEquals(ext, args[0], args[1]); + case LOOSE_EQUALS: return looseEqual(ext, args[0], args[1]); + case LOOSE_NOT_EQUALS: return !looseEqual(ext, args[0], args[1]); + + case GREATER: return compare(ext, args[0], args[1]).greater(); + case GREATER_EQUALS: return compare(ext, args[0], args[1]).greaterOrEqual(); + case LESS: return compare(ext, args[0], args[1]).less(); + case LESS_EQUALS: return compare(ext, args[0], args[1]).lessOrEqual(); + + case INVERSE: return bitwiseNot(ext, args[0]); + case NOT: return not(args[0]); + case POS: return toNumber(ext, args[0]); + case NEG: return negative(ext, args[0]); + + case SHIFT_LEFT: return shiftLeft(ext, args[0], args[1]); + case SHIFT_RIGHT: return shiftRight(ext, args[0], args[1]); + case USHIFT_RIGHT: return unsignedShiftRight(ext, args[0], args[1]); + + case IN: return hasMember(ext, args[1], args[0], false); + case INSTANCEOF: { + var proto = getMember(ext, args[1], "prototype"); + return isInstanceOf(ext, args[0], proto); + } + + default: return null; + } + } + + public static Object getMember(Environment ctx, Object obj, Object 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 null."); + if (obj instanceof ObjectValue) return ((ObjectValue)obj).getMember(ctx, key, obj); + + if (obj instanceof String && key instanceof Number) { + var i = number(key); + var s = (String)obj; + if (i >= 0 && i < s.length() && i - Math.floor(i) == 0) { + return s.charAt((int)i) + ""; + } + } + + var proto = getPrototype(ctx, obj); + + if (proto == null) return "__proto__".equals(key) ? NULL : null; + else if (key != null && "__proto__".equals(key)) return proto; + else return proto.getMember(ctx, key, obj); + } + public static Object getMemberPath(Environment ctx, Object obj, Object ...path) { + var res = obj; + for (var key : path) res = getMember(ctx, res, key); + return res; + } + public static boolean setMember(Environment ctx, Object obj, Object key, Object 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 null."); + if (key != null && "__proto__".equals(key)) return setPrototype(ctx, obj, val); + if (obj instanceof ObjectValue) return ((ObjectValue)obj).setMember(ctx, key, val, obj, false); + + var proto = getPrototype(ctx, obj); + return proto.setMember(ctx, key, val, obj, true); + } + public static boolean hasMember(Environment ctx, Object obj, Object key, boolean own) { + if (obj == null || obj == NULL) return false; + obj = normalize(ctx, obj); key = normalize(ctx, key); + + if ("__proto__".equals(key)) return true; + if (obj instanceof ObjectValue) return ((ObjectValue)obj).hasMember(ctx, key, own); + + if (obj instanceof String && key instanceof Number) { + var i = number(key); + var s = (String)obj; + if (i >= 0 && i < s.length() && i - Math.floor(i) == 0) return true; + } + + if (own) return false; + + var proto = getPrototype(ctx, obj); + return proto != null && proto.hasMember(ctx, key, own); + } + public static boolean deleteMember(Environment ext, Object obj, Object key) { + if (obj == null || obj == NULL) return false; + obj = normalize(ext, obj); key = normalize(ext, key); + + if (obj instanceof ObjectValue) return ((ObjectValue)obj).deleteMember(ext, key); + else return false; + } + public static ObjectValue getPrototype(Environment ext, Object obj) { + if (obj == null || obj == NULL) return null; + obj = normalize(ext, obj); + if (obj instanceof ObjectValue) return ((ObjectValue)obj).getPrototype(ext); + if (ext == null) return null; + + if (obj instanceof String) return ext.get(Environment.STRING_PROTO); + else if (obj instanceof Number) return ext.get(Environment.NUMBER_PROTO); + else if (obj instanceof Boolean) return ext.get(Environment.BOOL_PROTO); + else if (obj instanceof Symbol) return ext.get(Environment.SYMBOL_PROTO); + + return null; + } + public static boolean setPrototype(Environment ext, Object obj, Object proto) { + obj = normalize(ext, obj); + return obj instanceof ObjectValue && ((ObjectValue)obj).setPrototype(ext, proto); + } + public static void makePrototypeChain(Environment ext, Object... chain) { + for(var i = 1; i < chain.length; i++) { + setPrototype(ext, chain[i], chain[i - 1]); + } + } + public static List getMembers(Environment ext, Object obj, boolean own, boolean includeNonEnumerable) { + List res = new ArrayList<>(); + + if (obj instanceof ObjectValue) res = ((ObjectValue)obj).keys(includeNonEnumerable); + if (obj instanceof String) { + for (var i = 0; i < ((String)obj).length(); i++) res.add((double)i); + } + + if (!own) { + var proto = getPrototype(ext, obj); + + while (proto != null) { + res.addAll(proto.keys(includeNonEnumerable)); + proto = getPrototype(ext, proto); + } + } + + + return res; + } + public static ObjectValue getMemberDescriptor(Environment ext, Object obj, Object key) { + if (obj instanceof ObjectValue) return ((ObjectValue)obj).getMemberDescriptor(ext, key); + else if (obj instanceof String && key instanceof Number) { + var i = ((Number)key).intValue(); + var _i = ((Number)key).doubleValue(); + if (i - _i != 0) return null; + if (i < 0 || i >= ((String)obj).length()) return null; + + return new ObjectValue(ext, Map.of( + "value", ((String)obj).charAt(i) + "", + "writable", false, + "enumerable", true, + "configurable", false + )); + } + else return null; + } + + public static boolean strictEquals(Environment ext, Object a, Object b) { + a = normalize(ext, a); + b = normalize(ext, b); + + if (a == null || b == null) return a == null && b == null; + if (isNan(a) || isNan(b)) return false; + if (a instanceof Number && number(a) == -0.) a = 0.; + if (b instanceof Number && number(b) == -0.) b = 0.; + + return a == b || a.equals(b); + } + public static boolean looseEqual(Environment ext, Object a, Object b) { + a = normalize(ext, a); b = normalize(ext, b); + + // In loose equality, null is equivalent to undefined + if (a == NULL) a = null; + if (b == NULL) b = null; + + if (a == null || b == null) return a == null && b == null; + // If both are objects, just compare their references + if (!isPrimitive(a) && !isPrimitive(b)) return a == b; + + // Convert values to primitives + a = toPrimitive(ext, a, ConvertHint.VALUEOF); + b = toPrimitive(ext, b, ConvertHint.VALUEOF); + + // Compare symbols by reference + 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 Number || b instanceof Number) return strictEquals(ext, toNumber(ext, a), toNumber(ext, b)); + + // Default to strings + return toString(ext, a).equals(toString(ext, b)); + } + + public static Object normalize(Environment ext, Object val) { + if (val instanceof Number) return number(val); + if (isPrimitive(val) || val instanceof ObjectValue) return val; + if (val instanceof Character) return val + ""; + + if (val instanceof Map) { + var res = new ObjectValue(); + + for (var entry : ((Map)val).entrySet()) { + res.defineProperty(ext, entry.getKey(), entry.getValue()); + } + + return res; + } + + if (val instanceof Iterable) { + var res = new ArrayValue(); + + for (var entry : ((Iterable)val)) { + res.set(ext, res.size(), entry); + } + + return res; + } + + if (val instanceof Class) { + if (ext == null) return null; + else return NativeWrapperProvider.get(ext).getConstr((Class)val); + } + + return NativeWrapper.of(ext, val); + } + + @SuppressWarnings("unchecked") + public static T convert(Environment ext, Object obj, Class clazz) { + if (clazz == Void.class) return null; + + if (obj instanceof NativeWrapper) { + var res = ((NativeWrapper)obj).wrapped; + if (clazz.isInstance(res)) return (T)res; + } + + if (clazz == null || clazz == Object.class) return (T)obj; + + if (obj instanceof ArrayValue) { + if (clazz.isAssignableFrom(ArrayList.class)) { + var raw = ((ArrayValue)obj).toArray(); + var res = new ArrayList<>(); + for (var i = 0; i < raw.length; i++) res.add(convert(ext, raw[i], Object.class)); + return (T)new ArrayList<>(res); + } + if (clazz.isAssignableFrom(HashSet.class)) { + var raw = ((ArrayValue)obj).toArray(); + var res = new HashSet<>(); + for (var i = 0; i < raw.length; i++) res.add(convert(ext, raw[i], Object.class)); + return (T)new HashSet<>(res); + } + if (clazz.isArray()) { + var raw = ((ArrayValue)obj).toArray(); + Object res = Array.newInstance(clazz.getComponentType(), raw.length); + for (var i = 0; i < raw.length; i++) Array.set(res, i, convert(ext, raw[i], Object.class)); + return (T)res; + } + } + + if (obj instanceof ObjectValue && clazz.isAssignableFrom(HashMap.class)) { + var res = new HashMap<>(); + for (var el : ((ObjectValue)obj).values.entrySet()) res.put( + convert(ext, el.getKey(), null), + convert(ext, el.getValue(), null) + ); + return (T)res; + } + + if (clazz == String.class) return (T)toString(ext, 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(ext, 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(ext, 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(ext, obj); + if (clazz == Double.class || clazz == double.class) return (T)(Double)toNumber(ext, obj); + + if (clazz == Character.class || clazz == char.class) { + if (obj instanceof Number) return (T)(Character)(char)number(obj); + else { + var res = toString(ext, obj); + if (res.length() == 0) throw new ConvertException("\"\"", "Character"); + else return (T)(Character)res.charAt(0); + } + } + + if (obj == null) return null; + if (clazz.isInstance(obj)) return (T)obj; + if (clazz.isAssignableFrom(NativeWrapper.class)) { + return (T)NativeWrapper.of(ext, obj); + } + + throw new ConvertException(type(obj), clazz.getSimpleName()); + } + + public static Iterable fromJSIterator(Environment ext, Object obj) { + return () -> { + try { + var symbol = Symbol.get("Symbol.iterator"); + + var iteratorFunc = getMember(ext, obj, symbol); + if (!(iteratorFunc instanceof FunctionValue)) return Collections.emptyIterator(); + var iterator = iteratorFunc instanceof FunctionValue ? + ((FunctionValue)iteratorFunc).call(ext, obj, obj) : + iteratorFunc; + var nextFunc = getMember(ext, call(ext, iteratorFunc, obj), "next"); + + if (!(nextFunc instanceof FunctionValue)) return Collections.emptyIterator(); + + return new Iterator() { + private Object value = null; + public boolean consumed = true; + private FunctionValue next = (FunctionValue)nextFunc; + + private void loadNext() { + if (next == null) value = null; + else if (consumed) { + var curr = next.call(ext, iterator); + if (curr == null) { next = null; value = null; } + if (toBoolean(Values.getMember(ext, curr, "done"))) { next = null; value = null; } + else { + this.value = Values.getMember(ext, curr, "value"); + consumed = false; + } + } + } + + @Override + public boolean hasNext() { + loadNext(); + return next != null; + } + @Override + public Object next() { + loadNext(); + var res = value; + value = null; + consumed = true; + return res; + } + }; + } + catch (IllegalArgumentException | NullPointerException e) { + return Collections.emptyIterator(); + } + }; + } + + public static ObjectValue toJSIterator(Environment ext, Iterator it) { + var res = new ObjectValue(); + + try { + var key = getMember(ext, getMember(ext, ext.get(Environment.SYMBOL_PROTO), "constructor"), "iterator"); + res.defineProperty(ext, key, new NativeFunction("", args -> args.self)); + } + catch (IllegalArgumentException | NullPointerException e) { } + + res.defineProperty(ext, "next", new NativeFunction("", args -> { + if (!it.hasNext()) return new ObjectValue(ext, Map.of("done", true)); + else { + var obj = new ObjectValue(); + obj.defineProperty(args.env, "value", it.next()); + return obj; + } + })); + + return res; + } + + public static ObjectValue toJSIterator(Environment ext, Iterable it) { + return toJSIterator(ext, it.iterator()); + } + + public static ObjectValue toJSAsyncIterator(Environment ext, Iterator it) { + var res = new ObjectValue(); + + try { + var key = getMemberPath(ext, ext.get(Environment.SYMBOL_PROTO), "constructor", "asyncIterator"); + res.defineProperty(ext, key, new NativeFunction("", args -> args.self)); + } + catch (IllegalArgumentException | NullPointerException e) { } + + res.defineProperty(ext, "next", new NativeFunction("", args -> { + return PromiseLib.await(args.env, () -> { + if (!it.hasNext()) return new ObjectValue(ext, Map.of("done", true)); + else { + var obj = new ObjectValue(); + obj.defineProperty(args.env, "value", it.next()); + return obj; + } + }); + })); + + return res; + } + + private static boolean isEmptyFunc(ObjectValue val) { + if (!(val instanceof FunctionValue)) return false; + if (!val.values.containsKey("prototype") || val.values.size() + val.properties.size() > 1) return false; + var proto = val.values.get("prototype"); + if (!(proto instanceof ObjectValue)) return false; + var protoObj = (ObjectValue)proto; + if (protoObj.values.get("constructor") != val) return false; + if (protoObj.values.size() + protoObj.properties.size() != 1) return false; + return true; + } + private static String toReadable(Environment ext, Object val, HashSet passed, int tab) { + if (tab == 0 && val instanceof String) return (String)val; + + if (passed.contains(val)) return "[circular]"; + + var printed = true; + var res = new StringBuilder(); + var dbg = DebugContext.get(ext); + + if (val instanceof FunctionValue) { + res.append(val.toString()); + var loc = val instanceof CodeFunction ? dbg.getMapOrEmpty((CodeFunction)val).start() : null; + + if (loc != null) res.append(" @ " + loc); + } + else if (val instanceof ArrayValue) { + res.append("["); + var obj = ((ArrayValue)val); + for (int i = 0; i < obj.size(); i++) { + if (i != 0) res.append(", "); + else res.append(" "); + if (obj.has(i)) res.append(toReadable(ext, obj.get(i), passed, tab)); + else res.append(""); + } + res.append(" ] "); + } + else if (val instanceof NativeWrapper) { + var obj = ((NativeWrapper)val).wrapped; + res.append("Native " + obj.toString() + " "); + } + else printed = false; + + if (val instanceof ObjectValue) { + if (tab > 3) { + return "{...}"; + } + + passed.add(val); + + var obj = (ObjectValue)val; + if (obj.values.size() + obj.properties.size() == 0 || isEmptyFunc(obj)) { + if (!printed) res.append("{}\n"); + } + else { + res.append("{\n"); + + for (var el : obj.values.entrySet()) { + for (int i = 0; i < tab + 1; i++) res.append(" "); + res.append(toReadable(ext, el.getKey(), passed, tab + 1)); + res.append(": "); + res.append(toReadable(ext, el.getValue(), passed, tab + 1)); + res.append(",\n"); + } + for (var el : obj.properties.entrySet()) { + for (int i = 0; i < tab + 1; i++) res.append(" "); + res.append(toReadable(ext, el.getKey(), passed, tab + 1)); + res.append(": [prop],\n"); + } + + for (int i = 0; i < tab; i++) res.append(" "); + res.append("}"); + } + + passed.remove(val); + } + else if (val == null) return "undefined"; + else if (val == Values.NULL) return "null"; + else if (val instanceof String) return "'" + val + "'"; + else return Values.toString(ext, val); + + return res.toString(); + } + + public static String toReadable(Environment ext, Object val) { + return toReadable(ext, val, new HashSet<>(), 0); + } + public static String errorToReadable(RuntimeException err, String prefix) { + prefix = prefix == null ? "Uncaught" : "Uncaught " + prefix; + if (err instanceof EngineException) { + var ee = ((EngineException)err); + try { + return prefix + " " + ee.toString(ee.env); + } + catch (EngineException ex) { + return prefix + " " + toReadable(ee.env, ee.value); + } + } + else if (err instanceof SyntaxException) { + return prefix + " SyntaxError " + ((SyntaxException)err).msg; + } + else if (err.getCause() instanceof InterruptedException) return ""; + else { + var str = new ByteArrayOutputStream(); + err.printStackTrace(new PrintStream(str)); + + return prefix + " internal error " + str.toString(); + } + } + public static void printValue(Environment ext, Object val) { + System.out.print(toReadable(ext, val)); + } + public static void printError(RuntimeException err, String prefix) { + System.out.println(errorToReadable(err, prefix)); + } +} diff --git a/src/java/me/topchetoeu/jscript/runtime/values/Values.java b/src/java/me/topchetoeu/jscript/runtime/values/Values.java index db93cd8..0e527f6 100644 --- a/src/java/me/topchetoeu/jscript/runtime/values/Values.java +++ b/src/java/me/topchetoeu/jscript/runtime/values/Values.java @@ -13,10 +13,9 @@ import java.util.List; import java.util.Map; import me.topchetoeu.jscript.common.Operation; -import me.topchetoeu.jscript.lib.PromiseLib; -import me.topchetoeu.jscript.runtime.Environment; -import me.topchetoeu.jscript.runtime.Extensions; +// import me.topchetoeu.jscript.lib.PromiseLib; import me.topchetoeu.jscript.runtime.debug.DebugContext; +import me.topchetoeu.jscript.runtime.environment.Environment; import me.topchetoeu.jscript.runtime.exceptions.ConvertException; import me.topchetoeu.jscript.runtime.exceptions.EngineException; import me.topchetoeu.jscript.runtime.exceptions.SyntaxException; @@ -74,7 +73,7 @@ public class Values { return "object"; } - private static Object tryCallConvertFunc(Extensions ext, Object obj, String name) { + private static Object tryCallConvertFunc(Environment ext, Object obj, String name) { var func = getMember(ext, obj, name); if (func instanceof FunctionValue) { @@ -95,7 +94,7 @@ public class Values { obj == NULL; } - public static Object toPrimitive(Extensions ext, Object obj, ConvertHint hint) { + public static Object toPrimitive(Environment ext, Object obj, ConvertHint hint) { obj = normalize(ext, obj); if (isPrimitive(obj)) return obj; @@ -116,7 +115,7 @@ public class Values { if (obj instanceof Boolean) return (Boolean)obj; return true; } - public static double toNumber(Extensions ext, Object obj) { + public static double toNumber(Environment ext, Object obj) { var val = toPrimitive(ext, obj, ConvertHint.VALUEOF); if (val instanceof Number) return number(val); @@ -127,7 +126,7 @@ public class Values { } return Double.NaN; } - public static String toString(Extensions ext, Object obj) { + public static String toString(Environment ext, Object obj) { var val = toPrimitive(ext, obj, ConvertHint.VALUEOF); if (val == null) return "undefined"; @@ -147,47 +146,47 @@ public class Values { return "Unknown value"; } - public static Object add(Extensions ext, Object a, Object b) { + public static Object add(Environment ext, Object a, Object b) { if (a instanceof String || b instanceof String) return toString(ext, a) + toString(ext, b); else return toNumber(ext, a) + toNumber(ext, b); } - public static double subtract(Extensions ext, Object a, Object b) { + public static double subtract(Environment ext, Object a, Object b) { return toNumber(ext, a) - toNumber(ext, b); } - public static double multiply(Extensions ext, Object a, Object b) { + public static double multiply(Environment ext, Object a, Object b) { return toNumber(ext, a) * toNumber(ext, b); } - public static double divide(Extensions ext, Object a, Object b) { + public static double divide(Environment ext, Object a, Object b) { return toNumber(ext, a) / toNumber(ext, b); } - public static double modulo(Extensions ext, Object a, Object b) { + public static double modulo(Environment ext, Object a, Object b) { return toNumber(ext, a) % toNumber(ext, b); } - public static double negative(Extensions ext, Object obj) { + public static double negative(Environment ext, Object obj) { return -toNumber(ext, obj); } - public static int and(Extensions ext, Object a, Object b) { + public static int and(Environment ext, Object a, Object b) { return (int)toNumber(ext, a) & (int)toNumber(ext, b); } - public static int or(Extensions ext, Object a, Object b) { + public static int or(Environment ext, Object a, Object b) { return (int)toNumber(ext, a) | (int)toNumber(ext, b); } - public static int xor(Extensions ext, Object a, Object b) { + public static int xor(Environment ext, Object a, Object b) { return (int)toNumber(ext, a) ^ (int)toNumber(ext, b); } - public static int bitwiseNot(Extensions ext, Object obj) { + public static int bitwiseNot(Environment ext, Object obj) { return ~(int)toNumber(ext, obj); } - public static int shiftLeft(Extensions ext, Object a, Object b) { + public static int shiftLeft(Environment ext, Object a, Object b) { return (int)toNumber(ext, a) << (int)toNumber(ext, b); } - public static int shiftRight(Extensions ext, Object a, Object b) { + public static int shiftRight(Environment ext, Object a, Object b) { return (int)toNumber(ext, a) >> (int)toNumber(ext, b); } - public static long unsignedShiftRight(Extensions ext, Object a, Object b) { + public static long unsignedShiftRight(Environment ext, Object a, Object b) { long _a = (long)toNumber(ext, a); long _b = (long)toNumber(ext, b); @@ -196,7 +195,7 @@ public class Values { return _a >>> _b; } - public static CompareResult compare(Extensions ext, Object a, Object b) { + public static CompareResult compare(Environment ext, Object a, Object b) { a = toPrimitive(ext, a, ConvertHint.VALUEOF); b = toPrimitive(ext, b, ConvertHint.VALUEOF); @@ -214,7 +213,7 @@ public class Values { return !toBoolean(obj); } - public static boolean isInstanceOf(Extensions ext, Object obj, Object proto) { + public static boolean isInstanceOf(Environment ext, Object obj, Object proto) { if (obj == null || obj == NULL || proto == null || proto == NULL) return false; var val = getPrototype(ext, obj); @@ -226,7 +225,7 @@ public class Values { return false; } - public static Object operation(Extensions ext, Operation op, Object ...args) { + public static Object operation(Environment ext, Operation op, Object ...args) { switch (op) { case ADD: return add(ext, args[0], args[1]); case SUBTRACT: return subtract(ext, args[0], args[1]); @@ -267,7 +266,7 @@ public class Values { } } - public static Object getMember(Extensions ctx, Object obj, Object key) { + public static Object getMember(Environment ctx, Object obj, Object 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 null."); @@ -287,12 +286,12 @@ public class Values { else if (key != null && "__proto__".equals(key)) return proto; else return proto.getMember(ctx, key, obj); } - public static Object getMemberPath(Extensions ctx, Object obj, Object ...path) { + public static Object getMemberPath(Environment ctx, Object obj, Object ...path) { var res = obj; for (var key : path) res = getMember(ctx, res, key); return res; } - public static boolean setMember(Extensions ctx, Object obj, Object key, Object val) { + public static boolean setMember(Environment ctx, Object obj, Object key, Object 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 null."); @@ -302,7 +301,7 @@ public class Values { var proto = getPrototype(ctx, obj); return proto.setMember(ctx, key, val, obj, true); } - public static boolean hasMember(Extensions ctx, Object obj, Object key, boolean own) { + public static boolean hasMember(Environment ctx, Object obj, Object key, boolean own) { if (obj == null || obj == NULL) return false; obj = normalize(ctx, obj); key = normalize(ctx, key); @@ -320,14 +319,14 @@ public class Values { var proto = getPrototype(ctx, obj); return proto != null && proto.hasMember(ctx, key, own); } - public static boolean deleteMember(Extensions ext, Object obj, Object key) { + public static boolean deleteMember(Environment ext, Object obj, Object key) { if (obj == null || obj == NULL) return false; obj = normalize(ext, obj); key = normalize(ext, key); if (obj instanceof ObjectValue) return ((ObjectValue)obj).deleteMember(ext, key); else return false; } - public static ObjectValue getPrototype(Extensions ext, Object obj) { + public static ObjectValue getPrototype(Environment ext, Object obj) { if (obj == null || obj == NULL) return null; obj = normalize(ext, obj); if (obj instanceof ObjectValue) return ((ObjectValue)obj).getPrototype(ext); @@ -340,16 +339,16 @@ public class Values { return null; } - public static boolean setPrototype(Extensions ext, Object obj, Object proto) { + public static boolean setPrototype(Environment ext, Object obj, Object proto) { obj = normalize(ext, obj); return obj instanceof ObjectValue && ((ObjectValue)obj).setPrototype(ext, proto); } - public static void makePrototypeChain(Extensions ext, Object... chain) { + public static void makePrototypeChain(Environment ext, Object... chain) { for(var i = 1; i < chain.length; i++) { setPrototype(ext, chain[i], chain[i - 1]); } } - public static List getMembers(Extensions ext, Object obj, boolean own, boolean includeNonEnumerable) { + public static List getMembers(Environment ext, Object obj, boolean own, boolean includeNonEnumerable) { List res = new ArrayList<>(); if (obj instanceof ObjectValue) res = ((ObjectValue)obj).keys(includeNonEnumerable); @@ -369,7 +368,7 @@ public class Values { return res; } - public static ObjectValue getMemberDescriptor(Extensions ext, Object obj, Object key) { + public static ObjectValue getMemberDescriptor(Environment ext, Object obj, Object key) { if (obj instanceof ObjectValue) return ((ObjectValue)obj).getMemberDescriptor(ext, key); else if (obj instanceof String && key instanceof Number) { var i = ((Number)key).intValue(); @@ -387,11 +386,11 @@ public class Values { else return null; } - public static Object call(Extensions ext, Object func, Object thisArg, Object ...args) { + public static Object call(Environment ext, Object func, Object thisArg, Object ...args) { if (!(func instanceof FunctionValue)) throw EngineException.ofType("Tried to call a non-function value."); return ((FunctionValue)func).call(ext, thisArg, args); } - public static Object callNew(Extensions ext, Object func, Object ...args) { + public static Object callNew(Environment ext, Object func, Object ...args) { var res = new ObjectValue(); try { var proto = Values.getMember(ext, func, "prototype"); @@ -407,7 +406,7 @@ public class Values { } } - public static boolean strictEquals(Extensions ext, Object a, Object b) { + public static boolean strictEquals(Environment ext, Object a, Object b) { a = normalize(ext, a); b = normalize(ext, b); @@ -418,7 +417,7 @@ public class Values { return a == b || a.equals(b); } - public static boolean looseEqual(Extensions ext, Object a, Object b) { + public static boolean looseEqual(Environment ext, Object a, Object b) { a = normalize(ext, a); b = normalize(ext, b); // In loose equality, null is equivalent to undefined @@ -442,7 +441,7 @@ public class Values { return toString(ext, a).equals(toString(ext, b)); } - public static Object normalize(Extensions ext, Object val) { + public static Object normalize(Environment ext, Object val) { if (val instanceof Number) return number(val); if (isPrimitive(val) || val instanceof ObjectValue) return val; if (val instanceof Character) return val + ""; @@ -476,7 +475,7 @@ public class Values { } @SuppressWarnings("unchecked") - public static T convert(Extensions ext, Object obj, Class clazz) { + public static T convert(Environment ext, Object obj, Class clazz) { if (clazz == Void.class) return null; if (obj instanceof NativeWrapper) { @@ -543,7 +542,7 @@ public class Values { throw new ConvertException(type(obj), clazz.getSimpleName()); } - public static Iterable fromJSIterator(Extensions ext, Object obj) { + public static Iterable fromJSIterator(Environment ext, Object obj) { return () -> { try { var symbol = Symbol.get("Symbol.iterator"); @@ -596,7 +595,7 @@ public class Values { }; } - public static ObjectValue toJSIterator(Extensions ext, Iterator it) { + public static ObjectValue toJSIterator(Environment ext, Iterator it) { var res = new ObjectValue(); try { @@ -609,7 +608,7 @@ public class Values { if (!it.hasNext()) return new ObjectValue(ext, Map.of("done", true)); else { var obj = new ObjectValue(); - obj.defineProperty(args.ctx, "value", it.next()); + obj.defineProperty(args.env, "value", it.next()); return obj; } })); @@ -617,11 +616,11 @@ public class Values { return res; } - public static ObjectValue toJSIterator(Extensions ext, Iterable it) { + public static ObjectValue toJSIterator(Environment ext, Iterable it) { return toJSIterator(ext, it.iterator()); } - public static ObjectValue toJSAsyncIterator(Extensions ext, Iterator it) { + public static ObjectValue toJSAsyncIterator(Environment ext, Iterator it) { var res = new ObjectValue(); try { @@ -631,11 +630,11 @@ public class Values { catch (IllegalArgumentException | NullPointerException e) { } res.defineProperty(ext, "next", new NativeFunction("", args -> { - return PromiseLib.await(args.ctx, () -> { + return PromiseLib.await(args.env, () -> { if (!it.hasNext()) return new ObjectValue(ext, Map.of("done", true)); else { var obj = new ObjectValue(); - obj.defineProperty(args.ctx, "value", it.next()); + obj.defineProperty(args.env, "value", it.next()); return obj; } }); @@ -654,7 +653,7 @@ public class Values { if (protoObj.values.size() + protoObj.properties.size() != 1) return false; return true; } - private static String toReadable(Extensions ext, Object val, HashSet passed, int tab) { + private static String toReadable(Environment ext, Object val, HashSet passed, int tab) { if (tab == 0 && val instanceof String) return (String)val; if (passed.contains(val)) return "[circular]"; @@ -727,7 +726,7 @@ public class Values { return res.toString(); } - public static String toReadable(Extensions ext, Object val) { + public static String toReadable(Environment ext, Object val) { return toReadable(ext, val, new HashSet<>(), 0); } public static String errorToReadable(RuntimeException err, String prefix) { @@ -735,10 +734,10 @@ public class Values { if (err instanceof EngineException) { var ee = ((EngineException)err); try { - return prefix + " " + ee.toString(ee.ext); + return prefix + " " + ee.toString(ee.env); } catch (EngineException ex) { - return prefix + " " + toReadable(ee.ext, ee.value); + return prefix + " " + toReadable(ee.env, ee.value); } } else if (err instanceof SyntaxException) { @@ -752,7 +751,7 @@ public class Values { return prefix + " internal error " + str.toString(); } } - public static void printValue(Extensions ext, Object val) { + public static void printValue(Environment ext, Object val) { System.out.print(toReadable(ext, val)); } public static void printError(RuntimeException err, String prefix) { diff --git a/src/java/me/topchetoeu/jscript/utils/JSCompiler.java b/src/java/me/topchetoeu/jscript/utils/JSCompiler.java index 81e2c5a..78e66af 100644 --- a/src/java/me/topchetoeu/jscript/utils/JSCompiler.java +++ b/src/java/me/topchetoeu/jscript/utils/JSCompiler.java @@ -5,11 +5,11 @@ import me.topchetoeu.jscript.common.FunctionBody; import me.topchetoeu.jscript.compilation.CompileResult; import me.topchetoeu.jscript.compilation.parsing.Parsing; import me.topchetoeu.jscript.runtime.Compiler; -import me.topchetoeu.jscript.runtime.Extensions; import me.topchetoeu.jscript.runtime.debug.DebugContext; +import me.topchetoeu.jscript.runtime.environment.Environment; public class JSCompiler implements Compiler { - public final Extensions ext; + public final Environment ext; private void registerFunc(FunctionBody body, CompileResult res) { var map = res.map(); @@ -30,7 +30,7 @@ public class JSCompiler implements Compiler { return func; } - public JSCompiler(Extensions ext) { + public JSCompiler(Environment ext) { this.ext = ext; } } diff --git a/src/java/me/topchetoeu/jscript/utils/JScriptRepl.java b/src/java/me/topchetoeu/jscript/utils/JScriptRepl.java index 5f55ed5..0fdaf73 100644 --- a/src/java/me/topchetoeu/jscript/utils/JScriptRepl.java +++ b/src/java/me/topchetoeu/jscript/utils/JScriptRepl.java @@ -10,11 +10,10 @@ import me.topchetoeu.jscript.common.Metadata; import me.topchetoeu.jscript.common.Reading; import me.topchetoeu.jscript.lib.Internals; import me.topchetoeu.jscript.runtime.Compiler; -import me.topchetoeu.jscript.runtime.Context; import me.topchetoeu.jscript.runtime.Engine; -import me.topchetoeu.jscript.runtime.Environment; import me.topchetoeu.jscript.runtime.EventLoop; import me.topchetoeu.jscript.runtime.debug.DebugContext; +import me.topchetoeu.jscript.runtime.environment.Environment; import me.topchetoeu.jscript.runtime.exceptions.EngineException; import me.topchetoeu.jscript.runtime.exceptions.InterruptException; import me.topchetoeu.jscript.runtime.exceptions.SyntaxException; @@ -29,7 +28,6 @@ import me.topchetoeu.jscript.utils.filesystem.Mode; import me.topchetoeu.jscript.utils.filesystem.PhysicalFilesystem; import me.topchetoeu.jscript.utils.filesystem.RootFilesystem; import me.topchetoeu.jscript.utils.filesystem.STDFilesystem; -import me.topchetoeu.jscript.utils.interop.NativeWrapperProvider; import me.topchetoeu.jscript.utils.modules.ModuleRepo; import me.topchetoeu.jscript.utils.permissions.PermissionsManager; import me.topchetoeu.jscript.utils.permissions.PermissionsProvider; @@ -38,7 +36,7 @@ public class JScriptRepl { static Thread engineTask, debugTask; static Engine engine = new Engine(); static DebugServer debugServer = new DebugServer(); - static Environment environment = new Environment(); + static Environment environment = Environment.empty(); static int j = 0; static String[] args; @@ -97,8 +95,8 @@ public class JScriptRepl { glob.define(null, false, new NativeFunction("go", args -> { try { var f = Path.of("do.js"); - var func = args.ctx.compile(new Filename("do", "do/" + j++ + ".js"), new String(Files.readAllBytes(f))); - return func.call(args.ctx); + var func = Compiler.compile(args.env, new Filename("do", "do/" + j++ + ".js"), new String(Files.readAllBytes(f))); + return func.call(args.env); } catch (IOException e) { throw new EngineException("Couldn't open do.js"); @@ -106,7 +104,7 @@ public class JScriptRepl { })); glob.define(null, false, new NativeFunction("log", args -> { for (var el : args.args) { - Values.printValue(args.ctx, el); + Values.printValue(args.env, el); } return null; @@ -120,7 +118,7 @@ public class JScriptRepl { environment.add(PermissionsProvider.KEY, PermissionsManager.ALL_PERMS); environment.add(Filesystem.KEY, fs); environment.add(ModuleRepo.KEY, ModuleRepo.ofFilesystem(fs)); - environment.add(Compiler.KEY, new JSCompiler(new Context(environment))); + environment.add(Compiler.KEY, new JSCompiler(environment)); environment.add(EventLoop.KEY, engine); } private static void initEngine() { diff --git a/src/java/me/topchetoeu/jscript/utils/debug/ObjectManager.java b/src/java/me/topchetoeu/jscript/utils/debug/ObjectManager.java new file mode 100644 index 0000000..15fac42 --- /dev/null +++ b/src/java/me/topchetoeu/jscript/utils/debug/ObjectManager.java @@ -0,0 +1,212 @@ +package me.topchetoeu.jscript.utils.debug; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.function.Supplier; + +import me.topchetoeu.jscript.common.json.JSON; +import me.topchetoeu.jscript.common.json.JSONMap; +import me.topchetoeu.jscript.runtime.environment.Environment; +import me.topchetoeu.jscript.runtime.exceptions.EngineException; +import me.topchetoeu.jscript.runtime.values.ArrayValue; +import me.topchetoeu.jscript.runtime.values.FunctionValue; +import me.topchetoeu.jscript.runtime.values.ObjectValue; +import me.topchetoeu.jscript.runtime.values.Symbol; +import me.topchetoeu.jscript.runtime.values.Values; + +class ObjectManager { + public static class ObjRef { + public final ObjectValue obj; + public final Environment ext; + public final HashSet heldGroups = new HashSet<>(); + public boolean held = true; + + public boolean shouldRelease() { + return !held && heldGroups.size() == 0; + } + + public ObjRef(Environment ext, ObjectValue obj) { + this.ext = ext; + this.obj = obj; + } + } + + private Supplier idSupplier; + private HashMap idToObject = new HashMap<>(); + private HashMap objectToId = new HashMap<>(); + private HashMap> objectGroups = new HashMap<>(); + + public JSONMap serialize(Environment env, Object val, boolean byValue) { + val = Values.normalize(null, val); + env = SimpleDebugger.sanitizeEnvironment(env); + + if (val == Values.NULL) { + return new JSONMap() + .set("type", "object") + .set("subtype", "null") + .setNull("value") + .set("description", "null"); + } + + if (val instanceof ObjectValue) { + var obj = (ObjectValue)val; + int id; + + if (objectToId.containsKey(obj)) id = objectToId.get(obj); + else { + id = idSupplier.get(); + var ref = new ObjRef(env, obj); + objectToId.put(obj, id); + idToObject.put(id, ref); + } + + var type = "object"; + String subtype = null; + String className = null; + + if (obj instanceof FunctionValue) type = "function"; + if (obj instanceof ArrayValue) subtype = "array"; + + try { className = Values.toString(env, Values.getMemberPath(env, obj, "constructor", "name")); } + catch (Exception e) { } + + var res = new JSONMap() + .set("type", type) + .set("objectId", id + ""); + + if (subtype != null) res.set("subtype", subtype); + if (className != null) { + res.set("className", className); + res.set("description", className); + } + + if (obj instanceof ArrayValue) res.set("description", "Array(" + ((ArrayValue)obj).size() + ")"); + else if (obj instanceof FunctionValue) res.set("description", obj.toString()); + else { + var defaultToString = false; + + try { + defaultToString = + Values.getMember(env, obj, "toString") == + Values.getMember(env, env.get(Environment.OBJECT_PROTO), "toString"); + } + catch (Exception e) { } + + try { res.set("description", className + (defaultToString ? "" : " { " + Values.toString(env, obj) + " }")); } + catch (Exception e) { } + } + + + if (byValue) try { res.put("value", JSON.fromJs(env, obj)); } + catch (Exception e) { } + + return res; + } + + if (val == null) return new JSONMap().set("type", "undefined"); + if (val instanceof String) return new JSONMap().set("type", "string").set("value", (String)val); + if (val instanceof Boolean) return new JSONMap().set("type", "boolean").set("value", (Boolean)val); + if (val instanceof Symbol) return new JSONMap().set("type", "symbol").set("description", val.toString()); + if (val instanceof Number) { + var num = (double)(Number)val; + var res = new JSONMap().set("type", "number"); + + if (Double.POSITIVE_INFINITY == num) res.set("unserializableValue", "Infinity"); + else if (Double.NEGATIVE_INFINITY == num) res.set("unserializableValue", "-Infinity"); + else if (Double.doubleToRawLongBits(num) == Double.doubleToRawLongBits(-0d)) res.set("unserializableValue", "-0"); + else if (Double.doubleToRawLongBits(num) == Double.doubleToRawLongBits(0d)) res.set("unserializableValue", "0"); + else if (Double.isNaN(num)) res.set("unserializableValue", "NaN"); + else res.set("value", num); + + return res; + } + + throw new IllegalArgumentException("Unexpected JS object."); + } + public JSONMap serialize(Environment ext, Object val) { + return serialize(ext, val, false); + } + + public void addToGroup(String name, Object val) { + if (val instanceof ObjectValue) { + var obj = (ObjectValue)val; + var id = objectToId.getOrDefault(obj, -1); + if (id < 0) return; + + var ref = idToObject.get(id); + + if (objectGroups.containsKey(name)) objectGroups.get(name).add(ref); + else objectGroups.put(name, new ArrayList<>(List.of(ref))); + + ref.heldGroups.add(name); + } + } + public void removeGroup(String name) { + var objs = objectGroups.remove(name); + + if (objs != null) { + for (var obj : objs) { + if (obj.heldGroups.remove(name) && obj.shouldRelease()) { + var id = objectToId.remove(obj.obj); + if (id != null) idToObject.remove(id); + } + } + } + } + + public ObjRef get(int id) { + return idToObject.get(id); + } + public void release(int id) { + var ref = idToObject.get(id); + ref.held = false; + + if (ref.shouldRelease()) { + objectToId.remove(ref.obj); + idToObject.remove(id); + } + } + + public Object deserializeArgument(JSONMap val) { + if (val.isString("objectId")) return get(Integer.parseInt(val.string("objectId"))).obj; + else if (val.isString("unserializableValue")) switch (val.string("unserializableValue")) { + case "NaN": return Double.NaN; + case "-Infinity": return Double.NEGATIVE_INFINITY; + case "Infinity": return Double.POSITIVE_INFINITY; + case "-0": return -0.; + } + + var res = val.get("value"); + + if (res == null) return null; + else return JSON.toJs(res); + } + + public JSONMap serializeException(Environment ext, EngineException err) { + String text = null; + + try { + text = Values.toString(ext, err.value); + } + catch (EngineException e) { + text = "[error while stringifying]"; + } + + return new JSONMap() + .set("exceptionId", idSupplier.get()) + .set("exception", serialize(ext, err.value)) + .set("text", text); + } + + public void clear() { + this.idToObject.clear(); + this.objectToId.clear(); + this.objectGroups.clear(); + } + + public ObjectManager(Supplier idSupplier) { + this.idSupplier = idSupplier; + } +} \ No newline at end of file diff --git a/src/java/me/topchetoeu/jscript/utils/debug/SimpleDebugger.java b/src/java/me/topchetoeu/jscript/utils/debug/SimpleDebugger.java index 9b89386..d248456 100644 --- a/src/java/me/topchetoeu/jscript/utils/debug/SimpleDebugger.java +++ b/src/java/me/topchetoeu/jscript/utils/debug/SimpleDebugger.java @@ -23,20 +23,17 @@ import me.topchetoeu.jscript.common.json.JSONList; import me.topchetoeu.jscript.common.json.JSONMap; import me.topchetoeu.jscript.common.mapping.FunctionMap; import me.topchetoeu.jscript.compilation.parsing.Parsing; -import me.topchetoeu.jscript.runtime.Context; import me.topchetoeu.jscript.runtime.Engine; -import me.topchetoeu.jscript.runtime.Environment; import me.topchetoeu.jscript.runtime.EventLoop; -import me.topchetoeu.jscript.runtime.Extensions; import me.topchetoeu.jscript.runtime.Frame; import me.topchetoeu.jscript.runtime.debug.DebugContext; +import me.topchetoeu.jscript.runtime.environment.Environment; import me.topchetoeu.jscript.runtime.exceptions.EngineException; import me.topchetoeu.jscript.runtime.exceptions.SyntaxException; import me.topchetoeu.jscript.runtime.scope.GlobalScope; import me.topchetoeu.jscript.runtime.values.ArrayValue; import me.topchetoeu.jscript.runtime.values.FunctionValue; import me.topchetoeu.jscript.runtime.values.ObjectValue; -import me.topchetoeu.jscript.runtime.values.Symbol; import me.topchetoeu.jscript.runtime.values.Values; // very simple indeed @@ -150,10 +147,10 @@ public class SimpleDebugger implements Debugger { this.frame = frame; this.id = id; - this.global = GlobalScope.get(frame.ctx).obj; + this.global = GlobalScope.get(frame.env).obj; this.local = frame.getLocalScope(); this.capture = frame.getCaptureScope(); - Values.makePrototypeChain(frame.ctx, global, capture, local); + Values.makePrototypeChain(frame.env, global, capture, local); this.valstack = frame.getValStackScope(); this.serialized = new JSONMap() @@ -163,48 +160,32 @@ public class SimpleDebugger implements Debugger { .add(new JSONMap() .set("type", "local") .set("name", "Local Scope") - .set("object", serializeObj(frame.ctx, local)) + .set("object", objects.serialize(frame.env, local)) ) .add(new JSONMap() .set("type", "closure") .set("name", "Closure") - .set("object", serializeObj(frame.ctx, capture)) + .set("object", objects.serialize(frame.env, capture)) ) .add(new JSONMap() .set("type", "global") .set("name", "Global Scope") - .set("object", serializeObj(frame.ctx.extensions, global)) + .set("object", objects.serialize(frame.env, global)) ) .add(new JSONMap() .set("type", "other") .set("name", "Value Stack") - .set("object", serializeObj(frame.ctx.extensions, valstack)) + .set("object", objects.serialize(frame.env, valstack)) ) ); } } - private class ObjRef { - public final ObjectValue obj; - public final Extensions ext; - public final HashSet heldGroups = new HashSet<>(); - public boolean held = true; - - public boolean shouldRelease() { - return !held && heldGroups.size() == 0; - } - - public ObjRef(Extensions ext, ObjectValue obj) { - this.ext = ext; - this.obj = obj; - } - } - private static class RunResult { - public final Extensions ext; + public final Environment ext; public final Object result; public final EngineException error; - public RunResult(Extensions ext, Object result, EngineException error) { + public RunResult(Environment ext, Object result, EngineException error) { this.ext = ext; this.result = result; this.error = error; @@ -232,15 +213,17 @@ public class SimpleDebugger implements Debugger { private HashMap idToFrame = new HashMap<>(); private HashMap codeFrameToFrame = new HashMap<>(); - private HashMap idToObject = new HashMap<>(); - private HashMap objectToId = new HashMap<>(); - private HashMap> objectGroups = new HashMap<>(); + private ObjectManager objects = new ObjectManager(this::nextId); + // private HashMap idToObject = new HashMap<>(); + // private HashMap objectToId = new HashMap<>(); + // private HashMap> objectGroups = new HashMap<>(); private Notifier updateNotifier = new Notifier(); private boolean pendingPause = false; private int nextId = 0; - private DebugFrame stepOutFrame = null, currFrame = null; + private DebugFrame stepOutFrame = null; + private List frames = new ArrayList<>(); private int stepOutPtr = 0; private boolean compare(String src, String target) { @@ -288,18 +271,14 @@ public class SimpleDebugger implements Debugger { } else return codeFrameToFrame.get(frame); } - private synchronized void updateFrames(Context ctx) { - var frame = ctx.frame; - if (frame == null) return; - currFrame = getFrame(frame); - } - private JSONList serializeFrames(Context ctx) { + private JSONList serializeFrames(Environment env) { var res = new JSONList(); - for (var el : ctx.frames()) { + for (var el : DebugContext.get(env).getStackFrames()) { var frame = getFrame(el); if (frame.location == null) continue; + frame.serialized.set("location", serializeLocation(frame.location)); if (frame.location != null) res.add(frame.serialized); } @@ -339,151 +318,6 @@ public class SimpleDebugger implements Debugger { .set("columnNumber", loc.start() - 1); } - private JSONMap serializeObj(Extensions env, Object val, boolean byValue) { - val = Values.normalize(null, val); - env = sanitizeEnvironment(env); - var ctx = Context.of(env); - - if (val == Values.NULL) { - return new JSONMap() - .set("type", "object") - .set("subtype", "null") - .setNull("value") - .set("description", "null"); - } - - if (val instanceof ObjectValue) { - var obj = (ObjectValue)val; - int id; - - if (objectToId.containsKey(obj)) id = objectToId.get(obj); - else { - id = nextId(); - var ref = new ObjRef(env, obj); - objectToId.put(obj, id); - idToObject.put(id, ref); - } - - var type = "object"; - String subtype = null; - String className = null; - - if (obj instanceof FunctionValue) type = "function"; - if (obj instanceof ArrayValue) subtype = "array"; - - try { className = Values.toString(ctx, Values.getMemberPath(ctx, obj, "constructor", "name")); } - catch (Exception e) { } - - var res = new JSONMap() - .set("type", type) - .set("objectId", id + ""); - - if (subtype != null) res.set("subtype", subtype); - if (className != null) { - res.set("className", className); - res.set("description", className); - } - - if (obj instanceof ArrayValue) res.set("description", "Array(" + ((ArrayValue)obj).size() + ")"); - else if (obj instanceof FunctionValue) res.set("description", obj.toString()); - else { - var defaultToString = false; - - try { - defaultToString = - Values.getMember(ctx, obj, "toString") == - Values.getMember(ctx, env.get(Environment.OBJECT_PROTO), "toString"); - } - catch (Exception e) { } - - try { res.set("description", className + (defaultToString ? "" : " { " + Values.toString(ctx, obj) + " }")); } - catch (Exception e) { } - } - - - if (byValue) try { res.put("value", JSON.fromJs(env, obj)); } - catch (Exception e) { } - - return res; - } - - if (val == null) return new JSONMap().set("type", "undefined"); - if (val instanceof String) return new JSONMap().set("type", "string").set("value", (String)val); - if (val instanceof Boolean) return new JSONMap().set("type", "boolean").set("value", (Boolean)val); - if (val instanceof Symbol) return new JSONMap().set("type", "symbol").set("description", val.toString()); - if (val instanceof Number) { - var num = (double)(Number)val; - var res = new JSONMap().set("type", "number"); - - if (Double.POSITIVE_INFINITY == num) res.set("unserializableValue", "Infinity"); - else if (Double.NEGATIVE_INFINITY == num) res.set("unserializableValue", "-Infinity"); - else if (Double.doubleToRawLongBits(num) == Double.doubleToRawLongBits(-0d)) res.set("unserializableValue", "-0"); - else if (Double.doubleToRawLongBits(num) == Double.doubleToRawLongBits(0d)) res.set("unserializableValue", "0"); - else if (Double.isNaN(num)) res.set("unserializableValue", "NaN"); - else res.set("value", num); - - return res; - } - - throw new IllegalArgumentException("Unexpected JS object."); - } - private JSONMap serializeObj(Extensions ext, Object val) { - return serializeObj(ext, val, false); - } - private void addObjectGroup(String name, Object val) { - if (val instanceof ObjectValue) { - var obj = (ObjectValue)val; - var id = objectToId.getOrDefault(obj, -1); - if (id < 0) return; - - var ref = idToObject.get(id); - - if (objectGroups.containsKey(name)) objectGroups.get(name).add(ref); - else objectGroups.put(name, new ArrayList<>(List.of(ref))); - - ref.heldGroups.add(name); - } - } - private void releaseGroup(String name) { - var objs = objectGroups.remove(name); - - if (objs != null) for (var obj : objs) { - if (obj.heldGroups.remove(name) && obj.shouldRelease()) { - var id = objectToId.remove(obj.obj); - if (id != null) idToObject.remove(id); - } - } - } - private Object deserializeArgument(JSONMap val) { - if (val.isString("objectId")) return idToObject.get(Integer.parseInt(val.string("objectId"))).obj; - else if (val.isString("unserializableValue")) switch (val.string("unserializableValue")) { - case "NaN": return Double.NaN; - case "-Infinity": return Double.NEGATIVE_INFINITY; - case "Infinity": return Double.POSITIVE_INFINITY; - case "-0": return -0.; - } - var res = val.get("value"); - if (res == null) return null; - else return JSON.toJs(res); - } - - private JSONMap serializeException(Extensions ext, EngineException err) { - String text = null; - - try { - text = Values.toString(Context.of(ext), err.value); - } - catch (EngineException e) { - text = "[error while stringifying]"; - } - - var res = new JSONMap() - .set("exceptionId", nextId()) - .set("exception", serializeObj(ext, err.value)) - .set("text", text); - - return res; - } private void resume(State state) { try { @@ -496,11 +330,11 @@ public class SimpleDebugger implements Debugger { close(); } } - private void pauseDebug(Context ctx, Breakpoint bp) { + private void pauseDebug(Environment env, Breakpoint bp) { try { state = State.PAUSED_NORMAL; var map = new JSONMap() - .set("callFrames", serializeFrames(ctx)) + .set("callFrames", serializeFrames(env)) .set("reason", "debugCommand"); if (bp != null) map.set("hitBreakpoints", new JSONList().add(bp.id + "")); @@ -511,11 +345,11 @@ public class SimpleDebugger implements Debugger { close(); } } - private void pauseException(Context ctx) { + private void pauseException(Environment env) { try { state = State.PAUSED_EXCEPTION; var map = new JSONMap() - .set("callFrames", serializeFrames(ctx)) + .set("callFrames", serializeFrames(env)) .set("reason", "exception"); ws.send(new V8Event("Debugger.paused", map)); @@ -540,26 +374,19 @@ public class SimpleDebugger implements Debugger { } } - private Extensions sanitizeEnvironment(Extensions ext) { - var res = ext.child(); - - res.remove(EventLoop.KEY); - res.remove(DebugContext.KEY); - res.add(DebugContext.IGNORE); - - return res; + static Environment sanitizeEnvironment(Environment env) { + return env.child().remove(EventLoop.KEY).remove(DebugContext.KEY).add(DebugContext.IGNORE); } private RunResult run(DebugFrame codeFrame, String code) { if (codeFrame == null) return new RunResult(null, code, new EngineException("Invalid code frame!")); var engine = new Engine(); - var env = codeFrame.frame.ctx.extensions.copy(); - env.remove(DebugContext.KEY); - env.remove(EventLoop.KEY); - env.remove(GlobalScope.KEY); - env.add(EventLoop.KEY, engine); - env.add(GlobalScope.KEY, new GlobalScope(codeFrame.local)); + var env = codeFrame.frame.env.child() + .remove(DebugContext.KEY) + .add(DebugContext.IGNORE) + .add(EventLoop.KEY, engine) + .add(GlobalScope.KEY, new GlobalScope(codeFrame.local)); var awaiter = engine.pushMsg(false, env, new Filename("jscript", "eval"), code, codeFrame.frame.thisArg, codeFrame.frame.args); @@ -571,20 +398,19 @@ public class SimpleDebugger implements Debugger { catch (SyntaxException e) { return new RunResult(env, null, EngineException.ofSyntax(e.toString())); } } - private ObjectValue vscodeAutoSuggest(Extensions ext, Object target, String query, boolean variable) { + private ObjectValue vscodeAutoSuggest(Environment env, Object target, String query, boolean variable) { var res = new ArrayValue(); var passed = new HashSet(); var tildas = "~"; - var ctx = Context.of(ext); - if (target == null) target = GlobalScope.get(ext); + if (target == null) target = GlobalScope.get(env); - for (var proto = target; proto != null && proto != Values.NULL; proto = Values.getPrototype(ctx, proto)) { - for (var el : Values.getMembers(ctx, proto, true, true)) { - var strKey = Values.toString(ctx, el); + for (var proto = target; proto != null && proto != Values.NULL; proto = Values.getPrototype(env, proto)) { + for (var el : Values.getMembers(env, proto, true, true)) { + var strKey = Values.toString(env, el); if (passed.contains(strKey)) continue; passed.add(strKey); - var val = Values.getMember(ctx, Values.getMemberDescriptor(ctx, proto, el), "value"); + var val = Values.getMember(env, Values.getMemberDescriptor(env, proto, el), "value"); var desc = new ObjectValue(); var sortText = ""; if (strKey.startsWith(query)) sortText += "0@"; @@ -594,27 +420,27 @@ public class SimpleDebugger implements Debugger { else sortText += "4@"; sortText += tildas + strKey; - desc.defineProperty(ctx, "label", strKey); - desc.defineProperty(ctx, "sortText", sortText); + desc.defineProperty(env, "label", strKey); + desc.defineProperty(env, "sortText", sortText); if (val instanceof FunctionValue) { - if (strKey.equals("constructor")) desc.defineProperty(ctx, "type", "name"); - else desc.defineProperty(ctx, "type", variable ? "function" : "method"); + if (strKey.equals("constructor")) desc.defineProperty(env, "type", "name"); + else desc.defineProperty(env, "type", variable ? "function" : "method"); } - else desc.defineProperty(ctx, "type", variable ? "variable" : "property"); + else desc.defineProperty(env, "type", variable ? "variable" : "property"); switch (Values.type(val)) { case "number": case "boolean": - desc.defineProperty(ctx, "detail", Values.toString(ctx, val)); + desc.defineProperty(env, "detail", Values.toString(env, val)); break; case "object": - if (val == Values.NULL) desc.defineProperty(ctx, "detail", "null"); + if (val == Values.NULL) desc.defineProperty(env, "detail", "null"); else try { - desc.defineProperty(ctx, "detail", Values.getMemberPath(ctx, target, "constructor", "name")); + desc.defineProperty(env, "detail", Values.getMemberPath(env, target, "constructor", "name")); } catch (IllegalArgumentException e) { - desc.defineProperty(ctx, "detail", "object"); + desc.defineProperty(env, "detail", "object"); } break; case "function": { @@ -624,15 +450,15 @@ public class SimpleDebugger implements Debugger { type += "?"; } type += ")"; - desc.defineProperty(ctx, "detail", type); + desc.defineProperty(env, "detail", type); break; } default: - desc.defineProperty(ctx, "type", Values.type(val)); + desc.defineProperty(env, "type", Values.type(val)); break; } - res.set(ctx, res.size(), desc); + res.set(env, res.size(), desc); } tildas += "~"; @@ -640,8 +466,8 @@ public class SimpleDebugger implements Debugger { } var resObj = new ObjectValue(); - resObj.defineProperty(ctx, "result", res); - resObj.defineProperty(ctx, "isArray", target instanceof ArrayValue); + resObj.defineProperty(env, "result", res); + resObj.defineProperty(env, "isArray", target instanceof ArrayValue); return resObj; } @@ -679,13 +505,12 @@ public class SimpleDebugger implements Debugger { idToFrame.clear(); codeFrameToFrame.clear(); - idToObject.clear(); - objectToId.clear(); - objectGroups.clear(); + objects.clear(); pendingPause = false; - stepOutFrame = currFrame = null; + frames.clear(); + stepOutFrame = null; stepOutPtr = 0; for (var ctx : contexts.keySet()) ctx.detachDebugger(this); @@ -744,7 +569,6 @@ public class SimpleDebugger implements Debugger { var bpt = new Breakpoint(nextId(), regex, line, col, cond); idToBreakpoint.put(bpt.id, bpt); - for (var el : mappings.entrySet()) { bpt.addFunc(el.getKey(), el.getValue()); } @@ -794,8 +618,8 @@ public class SimpleDebugger implements Debugger { @Override public synchronized void stepInto(V8Message msg) throws IOException { if (state == State.RESUMED) ws.send(new V8Error("Debugger is resumed.")); else { - stepOutFrame = currFrame; - stepOutPtr = currFrame.frame.codePtr; + stepOutFrame = frames.get(frames.size() - 1); + stepOutPtr = stepOutFrame.frame.codePtr; resume(State.STEPPING_IN); ws.send(msg.respond()); } @@ -803,8 +627,8 @@ public class SimpleDebugger implements Debugger { @Override public synchronized void stepOut(V8Message msg) throws IOException { if (state == State.RESUMED) ws.send(new V8Error("Debugger is resumed.")); else { - stepOutFrame = currFrame; - stepOutPtr = currFrame.frame.codePtr; + stepOutFrame = frames.get(frames.size() - 1); + stepOutPtr = stepOutFrame.frame.codePtr; resume(State.STEPPING_OUT); ws.send(msg.respond()); } @@ -812,8 +636,8 @@ public class SimpleDebugger implements Debugger { @Override public synchronized void stepOver(V8Message msg) throws IOException { if (state == State.RESUMED) ws.send(new V8Error("Debugger is resumed.")); else { - stepOutFrame = currFrame; - stepOutPtr = currFrame.frame.codePtr; + stepOutFrame = frames.get(frames.size() - 1); + stepOutPtr = stepOutFrame.frame.codePtr; resume(State.STEPPING_OVER); ws.send(msg.respond()); } @@ -827,34 +651,26 @@ public class SimpleDebugger implements Debugger { var cf = idToFrame.get(cfId); var res = run(cf, expr); - if (group != null) addObjectGroup(group, res.result); + if (group != null) objects.addToGroup(group, res.result); - 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.ext, res.result)))); + if (res.error != null) ws.send(msg.respond(new JSONMap().set("exceptionDetails", objects.serializeException(res.ext, res.error)))); + else ws.send(msg.respond(new JSONMap().set("result", objects.serialize(res.ext, res.result)))); } @Override public synchronized void releaseObjectGroup(V8Message msg) throws IOException { var group = msg.params.string("objectGroup"); - releaseGroup(group); + objects.removeGroup(group); ws.send(msg.respond()); } @Override public synchronized void releaseObject(V8Message msg) throws IOException { var id = Integer.parseInt(msg.params.string("objectId")); - var ref = idToObject.get(id); - ref.held = false; - - if (ref.shouldRelease()) { - objectToId.remove(ref.obj); - idToObject.remove(id); - } - + objects.release(id); ws.send(msg.respond()); } @Override public synchronized void getProperties(V8Message msg) throws IOException { - var ref = idToObject.get(Integer.parseInt(msg.params.string("objectId"))); + var ref = objects.get(Integer.parseInt(msg.params.string("objectId"))); var obj = ref.obj; - var ext = ref.ext; - var ctx = Context.of(ext); + var env = ref.ext; var res = new JSONList(); var own = true; @@ -866,17 +682,17 @@ public class SimpleDebugger implements Debugger { if (obj.properties.containsKey(key)) { var prop = obj.properties.get(key); - propDesc.set("name", Values.toString(ctx, key)); - if (prop.getter != null) propDesc.set("get", serializeObj(ext, prop.getter)); - if (prop.setter != null) propDesc.set("set", serializeObj(ext, prop.setter)); + propDesc.set("name", Values.toString(env, key)); + if (prop.getter != null) propDesc.set("get", objects.serialize(env, prop.getter)); + if (prop.setter != null) propDesc.set("set", objects.serialize(env, prop.setter)); propDesc.set("enumerable", obj.memberEnumerable(key)); propDesc.set("configurable", obj.memberConfigurable(key)); propDesc.set("isOwn", true); res.add(propDesc); } else { - propDesc.set("name", Values.toString(ctx, key)); - propDesc.set("value", serializeObj(ext, Values.getMember(ctx, obj, key))); + propDesc.set("name", Values.toString(env, key)); + propDesc.set("value", objects.serialize(env, Values.getMember(env, obj, key))); propDesc.set("writable", obj.memberWritable(key)); propDesc.set("enumerable", obj.memberEnumerable(key)); propDesc.set("configurable", obj.memberConfigurable(key)); @@ -885,12 +701,12 @@ public class SimpleDebugger implements Debugger { } } - var proto = Values.getPrototype(ctx, obj); + var proto = Values.getPrototype(env, obj); if (own) { var protoDesc = new JSONMap(); protoDesc.set("name", "__proto__"); - protoDesc.set("value", serializeObj(ext, proto == null ? Values.NULL : proto)); + protoDesc.set("value", objects.serialize(env, proto == null ? Values.NULL : proto)); protoDesc.set("writable", true); protoDesc.set("enumerable", false); protoDesc.set("configurable", false); @@ -911,14 +727,13 @@ public class SimpleDebugger implements Debugger { .list("arguments", new JSONList()) .stream() .map(v -> v.map()) - .map(this::deserializeArgument) + .map(objects::deserializeArgument) .collect(Collectors.toList()); var byValue = msg.params.bool("returnByValue", false); - var thisArgRef = idToObject.get(Integer.parseInt(msg.params.string("objectId"))); + var thisArgRef = objects.get(Integer.parseInt(msg.params.string("objectId"))); var thisArg = thisArgRef.obj; - var ext = thisArgRef.ext; - var ctx = Context.of(ext); + var env = thisArgRef.ext; while (true) { var start = src.lastIndexOf("//# sourceURL="); @@ -934,27 +749,27 @@ public class SimpleDebugger implements Debugger { else if (compare(src, VSCODE_SELF)) res = thisArg; else if (compare(src, CHROME_GET_PROP_FUNC)) { res = thisArg; - for (var el : JSON.parse(null, (String)args.get(0)).list()) res = Values.getMember(ctx, res, JSON.toJs(el)); + for (var el : JSON.parse(null, (String)args.get(0)).list()) res = Values.getMember(env, res, JSON.toJs(el)); } else if (compare(src, CHROME_GET_PROP_FUNC_2)) { - res = Values.call(ctx, args.get(0), thisArg); + res = Values.call(env, args.get(0), thisArg); } else if (compare(src, VSCODE_CALL)) { var func = (FunctionValue)(args.size() < 1 ? null : args.get(0)); - ws.send(msg.respond(new JSONMap().set("result", serializeObj(ext, func.call(ctx, thisArg))))); + ws.send(msg.respond(new JSONMap().set("result", objects.serialize(env, func.call(env, thisArg))))); } else if (compare(src, VSCODE_AUTOCOMPLETE)) { var target = args.get(0); if (target == null) target = thisArg; - res = vscodeAutoSuggest(ext, target, Values.toString(ctx, args.get(1)), Values.toBoolean(args.get(2))); + res = vscodeAutoSuggest(env, target, Values.toString(env, args.get(1)), Values.toBoolean(args.get(2))); } else { ws.send(new V8Error("Please use well-known functions with callFunctionOn")); return; } - ws.send(msg.respond(new JSONMap().set("result", serializeObj(ext, res, byValue)))); + ws.send(msg.respond(new JSONMap().set("result", objects.serialize(env, res, byValue)))); } - catch (EngineException e) { ws.send(msg.respond(new JSONMap().set("exceptionDetails", serializeException(ext, e)))); } + catch (EngineException e) { ws.send(msg.respond(new JSONMap().set("exceptionDetails", objects.serializeException(env, e)))); } } @Override public synchronized void runtimeEnable(V8Message msg) throws IOException { @@ -977,7 +792,7 @@ public class SimpleDebugger implements Debugger { } mappings.put(body, map); } - @Override public boolean onInstruction(Context ctx, Frame cf, Instruction instruction, Object returnVal, EngineException error, boolean caught) { + @Override public boolean onInstruction(Environment env, Frame cf, Instruction instruction, Object returnVal, EngineException error, boolean caught) { if (!enabled) return false; boolean isBreakpointable; @@ -988,7 +803,7 @@ public class SimpleDebugger implements Debugger { synchronized (this) { frame = getFrame(cf); - var map = DebugContext.get(ctx).getMap(frame.frame.function); + var map = DebugContext.get(env).getMap(frame.frame.function); frame.updateLoc(map.toLocation(frame.frame.codePtr)); loc = frame.location; @@ -996,27 +811,27 @@ public class SimpleDebugger implements Debugger { isBreakpointable = loc != null && (bptType.shouldStepIn()); if (error != null && (execptionType == CatchType.ALL || execptionType == CatchType.UNCAUGHT && !caught)) { - pauseException(ctx); + pauseException(env); } else if ( loc != null && (state == State.STEPPING_IN || state == State.STEPPING_OVER) && returnVal != Values.NO_RETURN && stepOutFrame == frame ) { - pauseDebug(ctx, null); + pauseDebug(env, null); } else if (isBreakpointable && bpLocs.containsKey(loc)) { for (var bp : bpLocs.get(loc)) { - var ok = bp.condition == null ? true : Values.toBoolean(run(currFrame, bp.condition).result); - if (ok) pauseDebug(ctx, bp); + var ok = bp.condition == null ? true : Values.toBoolean(run(frames.get(frames.size() - 1), bp.condition).result); + if (ok) pauseDebug(env, bp); } } // else if (isBreakpointable && tmpBreakpts.remove(loc)) pauseDebug(ctx, null); else if (isBreakpointable && pendingPause) { - pauseDebug(ctx, null); + pauseDebug(env, null); pendingPause = false; } - else if (instruction.type == Type.NOP && instruction.match("debug")) pauseDebug(ctx, null); + else if (instruction.type == Type.NOP && instruction.match("debug")) pauseDebug(env, null); } @@ -1039,11 +854,11 @@ public class SimpleDebugger implements Debugger { else if (stepOutPtr != frame.frame.codePtr) { if (state == State.STEPPING_IN && bptType.shouldStepIn()) { - pauseDebug(ctx, null); + pauseDebug(env, null); break; } else if (state == State.STEPPING_OVER && bptType.shouldStepOver()) { - pauseDebug(ctx, null); + pauseDebug(env, null); break; } } @@ -1056,28 +871,32 @@ public class SimpleDebugger implements Debugger { return false; } - @Override public void onFramePush(Context ctx, Frame frame) { - var prevFrame = currFrame; - updateFrames(ctx); + @Override public void onFramePush(Environment env, Frame frame) { + var prevFrame = frames.get(frames.size() - 1); + var newFrame = getFrame(frame); + frames.add(newFrame); if (stepOutFrame != null && stepOutFrame.frame == prevFrame.frame && state == State.STEPPING_IN) { - stepOutFrame = currFrame; + stepOutFrame = newFrame; } } - @Override public void onFramePop(Context ctx, Frame frame) { - updateFrames(ctx); + @Override public void onFramePop(Environment env, Frame frame) { + frames.remove(frames.size() - 1); try { idToFrame.remove(codeFrameToFrame.remove(frame).id); } catch (NullPointerException e) { } - if (ctx.stackSize == 0) { + if (frames.size() == 0) { if (state == State.PAUSED_EXCEPTION || state == State.PAUSED_NORMAL) resume(State.RESUMED); } else if (stepOutFrame != null && stepOutFrame.frame == frame && state == State.STEPPING_OUT) { state = State.STEPPING_IN; - stepOutFrame = currFrame; + stepOutFrame = frames.get(frames.size() - 1); } } + @Override public List getStackFrame() { + return frames.stream().map(v -> v.frame).collect(Collectors.toList()); + } public SimpleDebugger attach(DebugContext ctx) { ctx.attachDebugger(this); diff --git a/src/java/me/topchetoeu/jscript/utils/filesystem/Filesystem.java b/src/java/me/topchetoeu/jscript/utils/filesystem/Filesystem.java index 6f477cb..283d633 100644 --- a/src/java/me/topchetoeu/jscript/utils/filesystem/Filesystem.java +++ b/src/java/me/topchetoeu/jscript/utils/filesystem/Filesystem.java @@ -1,7 +1,7 @@ package me.topchetoeu.jscript.utils.filesystem; -import me.topchetoeu.jscript.runtime.Extensions; -import me.topchetoeu.jscript.runtime.Key; +import me.topchetoeu.jscript.runtime.environment.Environment; +import me.topchetoeu.jscript.runtime.environment.Key; public interface Filesystem { public static final Key KEY = new Key<>(); @@ -12,7 +12,7 @@ public interface Filesystem { FileStat stat(String path); void close(); - public static Filesystem get(Extensions exts) { + public static Filesystem get(Environment exts) { return exts.get(KEY); } } \ No newline at end of file diff --git a/src/java/me/topchetoeu/jscript/utils/interop/Arguments.java b/src/java/me/topchetoeu/jscript/utils/interop/Arguments.java index 4e8c2ff..2ced1aa 100644 --- a/src/java/me/topchetoeu/jscript/utils/interop/Arguments.java +++ b/src/java/me/topchetoeu/jscript/utils/interop/Arguments.java @@ -2,32 +2,14 @@ package me.topchetoeu.jscript.utils.interop; import java.lang.reflect.Array; -import me.topchetoeu.jscript.runtime.Context; -import me.topchetoeu.jscript.runtime.Extensions; -import me.topchetoeu.jscript.runtime.Key; +import me.topchetoeu.jscript.runtime.environment.Environment; import me.topchetoeu.jscript.runtime.values.NativeWrapper; import me.topchetoeu.jscript.runtime.values.Values; -public class Arguments implements Extensions { +public class Arguments { public final Object self; public final Object[] args; - public final Context ctx; - - @Override public void add(Key key, T obj) { - ctx.add(key, obj); - } - @Override public T get(Key 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> keys() { - return ctx.keys(); - } + public final Environment env; public int n() { return args.length; @@ -41,7 +23,7 @@ public class Arguments implements Extensions { return convert(-1, type); } public T convert(int i, Class type) { - return Values.convert(ctx, get(i), type); + return Values.convert(env, get(i), type); } public Object get(int i, boolean unwrap) { Object res = null; @@ -63,7 +45,7 @@ public class Arguments implements Extensions { public Arguments slice(int start) { var res = new Object[Math.max(0, args.length - start)]; for (int j = start; j < args.length; j++) res[j - start] = get(j); - return new Arguments(ctx, args, res); + return new Arguments(env, args, res); } @SuppressWarnings("unchecked") @@ -113,26 +95,26 @@ public class Arguments implements Extensions { return res; } - public String getString(int i) { return Values.toString(ctx, get(i)); } + public String getString(int i) { return Values.toString(env, get(i)); } public boolean getBoolean(int i) { return Values.toBoolean(get(i)); } - public int getInt(int i) { return (int)Values.toNumber(ctx, get(i)); } - public long getLong(int i) { return (long)Values.toNumber(ctx, get(i)); } - public double getDouble(int i) { return Values.toNumber(ctx, get(i)); } - public float getFloat(int i) { return (float)Values.toNumber(ctx, get(i)); } + public int getInt(int i) { return (int)Values.toNumber(env, get(i)); } + public long getLong(int i) { return (long)Values.toNumber(env, get(i)); } + public double getDouble(int i) { return Values.toNumber(env, get(i)); } + public float getFloat(int i) { return (float)Values.toNumber(env, get(i)); } public int getInt(int i, int def) { var res = get(i); if (res == null) return def; - else return (int)Values.toNumber(ctx, res); + else return (int)Values.toNumber(env, res); } public String getString(int i, String def) { var res = get(i); if (res == null) return def; - else return Values.toString(ctx, res); + else return Values.toString(env, res); } - public Arguments(Context ctx, Object thisArg, Object... args) { - this.ctx = ctx; + public Arguments(Environment env, Object thisArg, Object... args) { + this.env = env; this.args = args; this.self = thisArg; } diff --git a/src/java/me/topchetoeu/jscript/utils/interop/NativeWrapperProvider.java b/src/java/me/topchetoeu/jscript/utils/interop/NativeWrapperProvider.java index 3f7573a..1022ce4 100644 --- a/src/java/me/topchetoeu/jscript/utils/interop/NativeWrapperProvider.java +++ b/src/java/me/topchetoeu/jscript/utils/interop/NativeWrapperProvider.java @@ -12,10 +12,8 @@ import java.util.stream.Collectors; import java.util.stream.Stream; import me.topchetoeu.jscript.common.Location; -import me.topchetoeu.jscript.runtime.Context; -import me.topchetoeu.jscript.runtime.Copyable; -import me.topchetoeu.jscript.runtime.Extensions; -import me.topchetoeu.jscript.runtime.Key; +import me.topchetoeu.jscript.runtime.environment.Environment; +import me.topchetoeu.jscript.runtime.environment.Key; import me.topchetoeu.jscript.runtime.exceptions.EngineException; import me.topchetoeu.jscript.runtime.exceptions.InterruptException; import me.topchetoeu.jscript.runtime.values.FunctionValue; @@ -24,7 +22,7 @@ import me.topchetoeu.jscript.runtime.values.ObjectValue; import me.topchetoeu.jscript.runtime.values.Symbol; import me.topchetoeu.jscript.runtime.values.Values; -public class NativeWrapperProvider implements Copyable { +public class NativeWrapperProvider { public static final Key KEY = new Key<>(); private final HashMap, FunctionValue> constructors = new HashMap<>(); @@ -35,7 +33,7 @@ public class NativeWrapperProvider implements Copyable { private final HashMap, Class> interfaceToProxy = new HashMap<>(); private final HashSet> ignore = new HashSet<>(); - private static Object call(Context ctx, String name, Method method, Object thisArg, Object... args) { + private static Object call(Environment ctx, String name, Method method, Object thisArg, Object... args) { try { var realArgs = new Object[method.getParameterCount()]; System.arraycopy(args, 0, realArgs, 0, realArgs.length); @@ -60,7 +58,7 @@ public class NativeWrapperProvider implements Copyable { } } private static FunctionValue create(String name, Method method) { - return new NativeFunction(name, args -> call(args.ctx, name, method, args.self, args)); + return new NativeFunction(name, args -> call(args.env, name, method, args.self, args)); } private static void checkSignature(Method method, boolean forceStatic, Class ...params) { if (forceStatic && !Modifier.isStatic(method.getModifiers())) throw new IllegalArgumentException(String.format( @@ -335,8 +333,8 @@ public class NativeWrapperProvider implements Copyable { var parentConstr = getConstr(parent); if (parentProto != null && parentConstr != null) { - Values.setPrototype(Extensions.EMPTY, proto, parentProto); - Values.setPrototype(Extensions.EMPTY, constr, parentConstr); + Values.setPrototype(Environment.empty(), proto, parentProto); + Values.setPrototype(Environment.empty(), constr, parentConstr); return; } @@ -450,7 +448,7 @@ public class NativeWrapperProvider implements Copyable { public NativeWrapperProvider() { } - public static NativeWrapperProvider get(Extensions ext) { + public static NativeWrapperProvider get(Environment ext) { return ext.get(KEY); } } diff --git a/src/java/me/topchetoeu/jscript/utils/modules/Module.java b/src/java/me/topchetoeu/jscript/utils/modules/Module.java index ad84d6c..63b1164 100644 --- a/src/java/me/topchetoeu/jscript/utils/modules/Module.java +++ b/src/java/me/topchetoeu/jscript/utils/modules/Module.java @@ -1,6 +1,6 @@ package me.topchetoeu.jscript.utils.modules; -import me.topchetoeu.jscript.runtime.Context; +import me.topchetoeu.jscript.runtime.environment.Environment; public abstract class Module { private Object value; @@ -9,9 +9,9 @@ public abstract class Module { public Object value() { return value; } public boolean loaded() { return loaded; } - protected abstract Object onLoad(Context ctx); + protected abstract Object onLoad(Environment ctx); - public void load(Context ctx) { + public void load(Environment ctx) { if (loaded) return; this.value = onLoad(ctx); this.loaded = true; diff --git a/src/java/me/topchetoeu/jscript/utils/modules/ModuleRepo.java b/src/java/me/topchetoeu/jscript/utils/modules/ModuleRepo.java index 1138485..99cffdc 100644 --- a/src/java/me/topchetoeu/jscript/utils/modules/ModuleRepo.java +++ b/src/java/me/topchetoeu/jscript/utils/modules/ModuleRepo.java @@ -3,9 +3,8 @@ package me.topchetoeu.jscript.utils.modules; import java.util.HashMap; import me.topchetoeu.jscript.common.Filename; -import me.topchetoeu.jscript.runtime.Context; -import me.topchetoeu.jscript.runtime.Extensions; -import me.topchetoeu.jscript.runtime.Key; +import me.topchetoeu.jscript.runtime.environment.Environment; +import me.topchetoeu.jscript.runtime.environment.Key; import me.topchetoeu.jscript.runtime.scope.GlobalScope; import me.topchetoeu.jscript.utils.filesystem.Filesystem; import me.topchetoeu.jscript.utils.filesystem.Mode; @@ -14,34 +13,34 @@ public interface ModuleRepo { public static final Key KEY = new Key<>(); public static final Key CWD = new Key<>(); - public Module getModule(Context ctx, String cwd, String name); + public Module getModule(Environment ctx, String cwd, String name); public static ModuleRepo ofFilesystem(Filesystem fs) { var modules = new HashMap(); - return (ctx, cwd, name) -> { + return (env, cwd, name) -> { name = fs.normalize(cwd, name); var filename = Filename.parse(name); var src = fs.open(name, Mode.READ).readToString(); if (modules.containsKey(name)) return modules.get(name); - var env = Context.clean(ctx.extensions).child(); - env.add(CWD, fs.normalize(name, "..")); - var glob = env.get(GlobalScope.KEY); - env.add(GlobalScope.KEY, glob.child()); + var moduleEnv = env.child() + .add(CWD, fs.normalize(name, "..")) + .add(GlobalScope.KEY, env.hasNotNull(GlobalScope.KEY) ? env.get(GlobalScope.KEY).child() : new GlobalScope()); - var mod = new SourceModule(filename, src, env); + var mod = new SourceModule(filename, src, moduleEnv); modules.put(name, mod); return mod; }; } - public static String cwd(Extensions exts) { - return exts.init(CWD, "/"); + public static String cwd(Environment exts) { + exts.init(CWD, "/"); + return "/"; } - public static ModuleRepo get(Extensions exts) { + public static ModuleRepo get(Environment exts) { return exts.get(KEY); } } diff --git a/src/java/me/topchetoeu/jscript/utils/modules/RootModuleRepo.java b/src/java/me/topchetoeu/jscript/utils/modules/RootModuleRepo.java index 6e9ca40..2644941 100644 --- a/src/java/me/topchetoeu/jscript/utils/modules/RootModuleRepo.java +++ b/src/java/me/topchetoeu/jscript/utils/modules/RootModuleRepo.java @@ -2,14 +2,14 @@ package me.topchetoeu.jscript.utils.modules; import java.util.HashMap; -import me.topchetoeu.jscript.runtime.Context; +import me.topchetoeu.jscript.runtime.environment.Environment; import me.topchetoeu.jscript.runtime.exceptions.EngineException; public class RootModuleRepo implements ModuleRepo { public final HashMap repos = new HashMap<>(); @Override - public Module getModule(Context ctx, String cwd, String name) { + public Module getModule(Environment env, String cwd, String name) { var i = name.indexOf(":"); String repoName, modName; @@ -25,6 +25,6 @@ public class RootModuleRepo implements ModuleRepo { var repo = repos.get(repoName); if (repo == null) throw EngineException.ofError("ModuleError", "Couldn't find module repo '" + repoName + "'."); - return repo.getModule(ctx, cwd, modName); + return repo.getModule(env, cwd, modName); } } diff --git a/src/java/me/topchetoeu/jscript/utils/modules/SourceModule.java b/src/java/me/topchetoeu/jscript/utils/modules/SourceModule.java index 4efd72a..36aeb0d 100644 --- a/src/java/me/topchetoeu/jscript/utils/modules/SourceModule.java +++ b/src/java/me/topchetoeu/jscript/utils/modules/SourceModule.java @@ -1,21 +1,20 @@ package me.topchetoeu.jscript.utils.modules; import me.topchetoeu.jscript.common.Filename; -import me.topchetoeu.jscript.runtime.Context; -import me.topchetoeu.jscript.runtime.Extensions; +import me.topchetoeu.jscript.runtime.Compiler; +import me.topchetoeu.jscript.runtime.environment.Environment; public class SourceModule extends Module { public final Filename filename; public final String source; - public final Extensions ext; + public final Environment ext; @Override - protected Object onLoad(Context ctx) { - var res = new Context(ext).compile(filename, source); - return res.call(ctx); + protected Object onLoad(Environment env) { + return Compiler.compile(env, filename, source).call(env); } - public SourceModule(Filename filename, String source, Extensions ext) { + public SourceModule(Filename filename, String source, Environment ext) { this.filename = filename; this.source = source; this.ext = ext; diff --git a/src/java/me/topchetoeu/jscript/utils/permissions/PermissionsProvider.java b/src/java/me/topchetoeu/jscript/utils/permissions/PermissionsProvider.java index 53112b3..19f474b 100644 --- a/src/java/me/topchetoeu/jscript/utils/permissions/PermissionsProvider.java +++ b/src/java/me/topchetoeu/jscript/utils/permissions/PermissionsProvider.java @@ -1,7 +1,7 @@ package me.topchetoeu.jscript.utils.permissions; -import me.topchetoeu.jscript.runtime.Extensions; -import me.topchetoeu.jscript.runtime.Key; +import me.topchetoeu.jscript.runtime.environment.Environment; +import me.topchetoeu.jscript.runtime.environment.Key; public interface PermissionsProvider { public static final Key KEY = new Key<>(); @@ -20,7 +20,7 @@ public interface PermissionsProvider { return hasPermission(new Permission(perm, matcher)); } - public static PermissionsProvider get(Extensions exts) { + public static PermissionsProvider get(Environment exts) { return (perm, value) -> { if (exts.hasNotNull(KEY)) return exts.get(KEY).hasPermission(perm); else return true;