diff --git a/src/me/topchetoeu/jscript/interop/NativeWrapperProvider.java b/src/me/topchetoeu/jscript/interop/NativeWrapperProvider.java index 0d4db6c..a120171 100644 --- a/src/me/topchetoeu/jscript/interop/NativeWrapperProvider.java +++ b/src/me/topchetoeu/jscript/interop/NativeWrapperProvider.java @@ -137,7 +137,11 @@ public class NativeWrapperProvider implements WrappersProvider { * @param clazz The class for which a constructor should be generated */ public static FunctionValue makeConstructor(Environment ctx, Class clazz) { - FunctionValue func = new OverloadFunction(clazz.getName()); + var name = clazz.getName(); + var classNat = clazz.getAnnotation(Native.class); + if (classNat != null && !classNat.value().trim().equals("")) name = classNat.value().trim(); + + FunctionValue func = new OverloadFunction(name); for (var overload : clazz.getDeclaredConstructors()) { var nat = overload.getAnnotation(Native.class); diff --git a/src/me/topchetoeu/jscript/lib/ArrayLib.java b/src/me/topchetoeu/jscript/lib/ArrayLib.java index 4ccd282..f6108c5 100644 --- a/src/me/topchetoeu/jscript/lib/ArrayLib.java +++ b/src/me/topchetoeu/jscript/lib/ArrayLib.java @@ -16,7 +16,7 @@ import me.topchetoeu.jscript.interop.NativeGetter; import me.topchetoeu.jscript.interop.NativeInit; import me.topchetoeu.jscript.interop.NativeSetter; -public class ArrayLib { +@Native("Array") public class ArrayLib { @NativeGetter(thisArg = true) public static int length(Context ctx, ArrayValue thisArg) { return thisArg.size(); } @@ -164,6 +164,37 @@ public class ArrayLib { } } + @Native(thisArg = true) public static Object reduce(Context ctx, ArrayValue arr, FunctionValue func, Object... args) { + var i = 0; + var res = arr.get(0); + + if (args.length > 0) res = args[0]; + else for (; !arr.has(i) && i < arr.size(); i++) res = arr.get(i); + + for (; i < arr.size(); i++) { + if (arr.has(i)) { + res = func.call(ctx, null, res, arr.get(i), i, arr); + } + } + + return res; + } + @Native(thisArg = true) public static Object reduceRight(Context ctx, ArrayValue arr, FunctionValue func, Object... args) { + var i = arr.size(); + var res = arr.get(0); + + if (args.length > 0) res = args[0]; + else while (!arr.has(i--) && i >= 0) res = arr.get(i); + + for (; i >= 0; i--) { + if (arr.has(i)) { + res = func.call(ctx, null, res, arr.get(i), i, arr); + } + } + + return res; + } + @Native(thisArg = true) public static ArrayValue flat(Context ctx, ArrayValue arr, int depth) { var res = new ArrayValue(arr.size()); var stack = new Stack(); @@ -224,7 +255,7 @@ public class ArrayLib { @Native(thisArg = true) public static int indexOf(Context ctx, ArrayValue arr, Object val, int start) { start = normalizeI(arr.size(), start, true); - for (int i = 0; i < arr.size() && i < start; i++) { + for (int i = start; i < arr.size(); i++) { if (Values.strictEquals(ctx, arr.get(i), val)) return i; } @@ -303,12 +334,14 @@ public class ArrayLib { @Native(thisArg = true) public static String join(Context ctx, ArrayValue arr, String sep) { var res = new StringBuilder(); - var comma = true; + var comma = false; for (int i = 0; i < arr.size(); i++) { if (!arr.has(i)) continue; + if (comma) res.append(sep); - comma = false; + comma = true; + var el = arr.get(i); if (el == null || el == Values.NULL) continue; diff --git a/src/me/topchetoeu/jscript/lib/AsyncFunctionLib.java b/src/me/topchetoeu/jscript/lib/AsyncFunctionLib.java index e372d83..ff248e4 100644 --- a/src/me/topchetoeu/jscript/lib/AsyncFunctionLib.java +++ b/src/me/topchetoeu/jscript/lib/AsyncFunctionLib.java @@ -8,8 +8,9 @@ import me.topchetoeu.jscript.engine.values.CodeFunction; import me.topchetoeu.jscript.engine.values.FunctionValue; import me.topchetoeu.jscript.engine.values.NativeFunction; import me.topchetoeu.jscript.exceptions.EngineException; +import me.topchetoeu.jscript.interop.Native; -public class AsyncFunctionLib extends FunctionValue { +@Native("AsyncFunction") public class AsyncFunctionLib extends FunctionValue { public final FunctionValue factory; public static class AsyncHelper { diff --git a/src/me/topchetoeu/jscript/lib/AsyncGeneratorFunctionLib.java b/src/me/topchetoeu/jscript/lib/AsyncGeneratorFunctionLib.java new file mode 100644 index 0000000..490905c --- /dev/null +++ b/src/me/topchetoeu/jscript/lib/AsyncGeneratorFunctionLib.java @@ -0,0 +1,30 @@ +package me.topchetoeu.jscript.lib; + +import me.topchetoeu.jscript.engine.Context; +import me.topchetoeu.jscript.engine.frame.CodeFrame; +import me.topchetoeu.jscript.engine.values.CodeFunction; +import me.topchetoeu.jscript.engine.values.FunctionValue; +import me.topchetoeu.jscript.engine.values.NativeFunction; +import me.topchetoeu.jscript.exceptions.EngineException; +import me.topchetoeu.jscript.interop.Native; + +@Native("AsyncGeneratorFunction") public class AsyncGeneratorFunctionLib extends FunctionValue { + public final FunctionValue factory; + + @Override + public Object call(Context ctx, Object thisArg, Object ...args) { + var handler = new AsyncGeneratorLib(); + var func = factory.call(ctx, thisArg, + new NativeFunction("await", handler::await), + new NativeFunction("yield", handler::yield) + ); + if (!(func instanceof CodeFunction)) throw EngineException.ofType("Return value of argument must be a js function."); + handler.frame = new CodeFrame(ctx, thisArg, args, (CodeFunction)func); + return handler; + } + + public AsyncGeneratorFunctionLib(FunctionValue factory) { + super(factory.name, factory.length); + this.factory = factory; + } +} diff --git a/src/me/topchetoeu/jscript/lib/AsyncGeneratorLib.java b/src/me/topchetoeu/jscript/lib/AsyncGeneratorLib.java index ef11c5a..7f2e78c 100644 --- a/src/me/topchetoeu/jscript/lib/AsyncGeneratorLib.java +++ b/src/me/topchetoeu/jscript/lib/AsyncGeneratorLib.java @@ -6,130 +6,106 @@ import me.topchetoeu.jscript.engine.Context; import me.topchetoeu.jscript.engine.StackData; import me.topchetoeu.jscript.engine.frame.CodeFrame; import me.topchetoeu.jscript.engine.frame.Runners; -import me.topchetoeu.jscript.engine.values.CodeFunction; -import me.topchetoeu.jscript.engine.values.FunctionValue; import me.topchetoeu.jscript.engine.values.NativeFunction; import me.topchetoeu.jscript.engine.values.ObjectValue; import me.topchetoeu.jscript.exceptions.EngineException; import me.topchetoeu.jscript.interop.Native; -public class AsyncGeneratorLib extends FunctionValue { - public final FunctionValue factory; +@Native("AsyncGenerator") public class AsyncGeneratorLib { + @Native("@@Symbol.typeName") public final String name = "AsyncGenerator"; + private int state = 0; + private boolean done = false; + private PromiseLib currPromise; + public CodeFrame frame; - public static class AsyncGenerator { - @Native("@@Symbol.typeName") public final String name = "AsyncGenerator"; - private int state = 0; - private boolean done = false; - private PromiseLib currPromise; - public CodeFrame frame; + private void next(Context ctx, Object inducedValue, Object inducedReturn, Object inducedError) { + if (done) { + if (inducedError != Runners.NO_RETURN) throw new EngineException(inducedError); + currPromise.fulfill(ctx, new ObjectValue(ctx, Map.of( + "done", true, + "value", inducedReturn == Runners.NO_RETURN ? null : inducedReturn + ))); + return; + } - private void next(Context ctx, Object inducedValue, Object inducedReturn, Object inducedError) { - if (done) { - if (inducedError != Runners.NO_RETURN) - throw new EngineException(inducedError); - currPromise.fulfill(ctx, new ObjectValue(ctx, Map.of( - "done", true, - "value", inducedReturn == Runners.NO_RETURN ? null : inducedReturn - ))); - return; - } + Object res = null; + StackData.pushFrame(ctx, frame); + state = 0; - Object res = null; - StackData.pushFrame(ctx, frame); - state = 0; - - while (state == 0) { - try { - res = frame.next(ctx, inducedValue, inducedReturn, inducedError == Runners.NO_RETURN ? null : new EngineException(inducedError)); - inducedValue = inducedReturn = inducedError = Runners.NO_RETURN; - if (res != Runners.NO_RETURN) { - var obj = new ObjectValue(); - obj.defineProperty(ctx, "done", true); - obj.defineProperty(ctx, "value", res); - currPromise.fulfill(ctx, obj); - break; - } - } - catch (EngineException e) { - currPromise.reject(ctx, e.value); + while (state == 0) { + try { + res = frame.next(ctx, inducedValue, inducedReturn, inducedError == Runners.NO_RETURN ? null : new EngineException(inducedError)); + inducedValue = inducedReturn = inducedError = Runners.NO_RETURN; + if (res != Runners.NO_RETURN) { + var obj = new ObjectValue(); + obj.defineProperty(ctx, "done", true); + obj.defineProperty(ctx, "value", res); + currPromise.fulfill(ctx, obj); break; } } - - StackData.popFrame(ctx, frame); - - if (state == 1) { - PromiseLib.then(ctx, frame.pop(), new NativeFunction(this::fulfill), new NativeFunction(this::reject)); - } - else if (state == 2) { - var obj = new ObjectValue(); - obj.defineProperty(ctx, "done", false); - obj.defineProperty(ctx, "value", frame.pop()); - currPromise.fulfill(ctx, obj); + catch (EngineException e) { + currPromise.reject(ctx, e.value); + break; } } - @Override - public String toString() { - if (done) return "Generator [closed]"; - if (state != 0) return "Generator [suspended]"; - return "Generator [running]"; - } + StackData.popFrame(ctx, frame); - public Object fulfill(Context ctx, Object thisArg, Object ...args) { - next(ctx, args.length > 0 ? args[0] : null, Runners.NO_RETURN, Runners.NO_RETURN); - return null; + if (state == 1) { + PromiseLib.then(ctx, frame.pop(), new NativeFunction(this::fulfill), new NativeFunction(this::reject)); } - public Object reject(Context ctx, Object thisArg, Object ...args) { - next(ctx, Runners.NO_RETURN, args.length > 0 ? args[0] : null, Runners.NO_RETURN); - return null; - } - - @Native - public PromiseLib next(Context ctx, Object ...args) { - this.currPromise = new PromiseLib(); - if (args.length == 0) next(ctx, Runners.NO_RETURN, Runners.NO_RETURN, Runners.NO_RETURN); - else next(ctx, args[0], Runners.NO_RETURN, Runners.NO_RETURN); - return this.currPromise; - } - @Native("throw") - public PromiseLib _throw(Context ctx, Object error) { - this.currPromise = new PromiseLib(); - next(ctx, Runners.NO_RETURN, Runners.NO_RETURN, error); - return this.currPromise; - } - @Native("return") - public PromiseLib _return(Context ctx, Object value) { - this.currPromise = new PromiseLib(); - next(ctx, Runners.NO_RETURN, value, Runners.NO_RETURN); - return this.currPromise; - } - - - public Object await(Context ctx, Object thisArg, Object[] args) { - this.state = 1; - return args.length > 0 ? args[0] : null; - } - public Object yield(Context ctx, Object thisArg, Object[] args) { - this.state = 2; - return args.length > 0 ? args[0] : null; + else if (state == 2) { + var obj = new ObjectValue(); + obj.defineProperty(ctx, "done", false); + obj.defineProperty(ctx, "value", frame.pop()); + currPromise.fulfill(ctx, obj); } } @Override - public Object call(Context ctx, Object thisArg, Object ...args) { - var handler = new AsyncGenerator(); - var func = factory.call(ctx, thisArg, - new NativeFunction("await", handler::await), - new NativeFunction("yield", handler::yield) - ); - if (!(func instanceof CodeFunction)) throw EngineException.ofType("Return value of argument must be a js function."); - handler.frame = new CodeFrame(ctx, thisArg, args, (CodeFunction)func); - return handler; + public String toString() { + if (done) return "Generator [closed]"; + if (state != 0) return "Generator [suspended]"; + return "Generator [running]"; } - public AsyncGeneratorLib(FunctionValue factory) { - super(factory.name, factory.length); - this.factory = factory; + public Object fulfill(Context ctx, Object thisArg, Object ...args) { + next(ctx, args.length > 0 ? args[0] : null, Runners.NO_RETURN, Runners.NO_RETURN); + return null; } -} + public Object reject(Context ctx, Object thisArg, Object ...args) { + next(ctx, Runners.NO_RETURN, args.length > 0 ? args[0] : null, Runners.NO_RETURN); + return null; + } + + @Native + public PromiseLib next(Context ctx, Object ...args) { + this.currPromise = new PromiseLib(); + if (args.length == 0) next(ctx, Runners.NO_RETURN, Runners.NO_RETURN, Runners.NO_RETURN); + else next(ctx, args[0], Runners.NO_RETURN, Runners.NO_RETURN); + return this.currPromise; + } + @Native("throw") + public PromiseLib _throw(Context ctx, Object error) { + this.currPromise = new PromiseLib(); + next(ctx, Runners.NO_RETURN, Runners.NO_RETURN, error); + return this.currPromise; + } + @Native("return") + public PromiseLib _return(Context ctx, Object value) { + this.currPromise = new PromiseLib(); + next(ctx, Runners.NO_RETURN, value, Runners.NO_RETURN); + return this.currPromise; + } + + + public Object await(Context ctx, Object thisArg, Object[] args) { + this.state = 1; + return args.length > 0 ? args[0] : null; + } + public Object yield(Context ctx, Object thisArg, Object[] args) { + this.state = 2; + return args.length > 0 ? args[0] : null; + } +} \ No newline at end of file diff --git a/src/me/topchetoeu/jscript/lib/BooleanLib.java b/src/me/topchetoeu/jscript/lib/BooleanLib.java index 7866668..e9c2a3f 100644 --- a/src/me/topchetoeu/jscript/lib/BooleanLib.java +++ b/src/me/topchetoeu/jscript/lib/BooleanLib.java @@ -9,7 +9,7 @@ import me.topchetoeu.jscript.interop.Native; import me.topchetoeu.jscript.interop.NativeConstructor; import me.topchetoeu.jscript.interop.NativeInit; -public class BooleanLib { +@Native("Boolean") public class BooleanLib { public static final BooleanLib TRUE = new BooleanLib(true); public static final BooleanLib FALSE = new BooleanLib(false); diff --git a/src/me/topchetoeu/jscript/lib/DateLib.java b/src/me/topchetoeu/jscript/lib/DateLib.java index 575d72b..339d961 100644 --- a/src/me/topchetoeu/jscript/lib/DateLib.java +++ b/src/me/topchetoeu/jscript/lib/DateLib.java @@ -6,7 +6,7 @@ import java.util.TimeZone; import me.topchetoeu.jscript.engine.Context; import me.topchetoeu.jscript.interop.Native; -public class DateLib { +@Native("Date") public class DateLib { private Calendar normal; private Calendar utc; diff --git a/src/me/topchetoeu/jscript/lib/ErrorLib.java b/src/me/topchetoeu/jscript/lib/ErrorLib.java index 0991fce..e33cf1a 100644 --- a/src/me/topchetoeu/jscript/lib/ErrorLib.java +++ b/src/me/topchetoeu/jscript/lib/ErrorLib.java @@ -11,7 +11,7 @@ import me.topchetoeu.jscript.interop.Native; import me.topchetoeu.jscript.interop.NativeConstructor; import me.topchetoeu.jscript.interop.NativeInit; -public class ErrorLib { +@Native("Error") public class ErrorLib { private static String toString(Context ctx, boolean rethrown, Object cause, Object name, Object message, ArrayValue stack) { if (name == null) name = ""; else name = Values.toString(ctx, name).trim(); @@ -23,13 +23,6 @@ public class ErrorLib { if (!message.equals("") && !name.equals("")) res.append(": "); if (!message.equals("")) res.append(message); - if (stack != null) { - for (var el : stack) { - var str = Values.toString(ctx, el).trim(); - if (!str.equals("")) res.append("\n ").append(el); - } - } - if (cause instanceof ObjectValue) { if (rethrown) res.append("\n (rethrown)"); else res.append("\nCaused by ").append(toString(ctx, cause)); diff --git a/src/me/topchetoeu/jscript/lib/FunctionLib.java b/src/me/topchetoeu/jscript/lib/FunctionLib.java index 9cdc3ac..51581a0 100644 --- a/src/me/topchetoeu/jscript/lib/FunctionLib.java +++ b/src/me/topchetoeu/jscript/lib/FunctionLib.java @@ -1,8 +1,10 @@ package me.topchetoeu.jscript.lib; +import me.topchetoeu.jscript.Location; import me.topchetoeu.jscript.engine.Context; import me.topchetoeu.jscript.engine.Environment; import me.topchetoeu.jscript.engine.values.ArrayValue; +import me.topchetoeu.jscript.engine.values.CodeFunction; import me.topchetoeu.jscript.engine.values.FunctionValue; import me.topchetoeu.jscript.engine.values.NativeFunction; import me.topchetoeu.jscript.engine.values.ObjectValue; @@ -11,7 +13,11 @@ import me.topchetoeu.jscript.interop.InitType; import me.topchetoeu.jscript.interop.Native; import me.topchetoeu.jscript.interop.NativeInit; -public class FunctionLib { +@Native("Function") public class FunctionLib { + @Native(thisArg = true) public static Object location(Context ctx, FunctionValue func) { + if (func instanceof CodeFunction) return ((CodeFunction)func).loc().toString(); + else return Location.INTERNAL.toString(); + } @Native(thisArg = true) public static Object apply(Context ctx, FunctionValue func, Object thisArg, ArrayValue args) { return func.call(ctx, thisArg, args.toArray()); } @@ -44,10 +50,10 @@ public class FunctionLib { return new AsyncFunctionLib(func); } @Native public static FunctionValue asyncGenerator(FunctionValue func) { - return new AsyncGeneratorLib(func); + return new AsyncGeneratorFunctionLib(func); } @Native public static FunctionValue generator(FunctionValue func) { - return new GeneratorLib(func); + return new GeneratorFunctionLib(func); } @NativeInit(InitType.PROTOTYPE) public static void init(Environment env, ObjectValue target) { diff --git a/src/me/topchetoeu/jscript/lib/GeneratorFunctionLib.java b/src/me/topchetoeu/jscript/lib/GeneratorFunctionLib.java new file mode 100644 index 0000000..f08e1a5 --- /dev/null +++ b/src/me/topchetoeu/jscript/lib/GeneratorFunctionLib.java @@ -0,0 +1,27 @@ +package me.topchetoeu.jscript.lib; + +import me.topchetoeu.jscript.engine.Context; +import me.topchetoeu.jscript.engine.frame.CodeFrame; +import me.topchetoeu.jscript.engine.values.CodeFunction; +import me.topchetoeu.jscript.engine.values.FunctionValue; +import me.topchetoeu.jscript.engine.values.NativeFunction; +import me.topchetoeu.jscript.exceptions.EngineException; +import me.topchetoeu.jscript.interop.Native; + +@Native("GeneratorFunction") public class GeneratorFunctionLib extends FunctionValue { + public final FunctionValue factory; + + @Override + public Object call(Context ctx, Object thisArg, Object ...args) { + var handler = new GeneratorLib(); + var func = factory.call(ctx, thisArg, new NativeFunction("yield", handler::yield)); + if (!(func instanceof CodeFunction)) throw EngineException.ofType("Return value of argument must be a js function."); + handler.frame = new CodeFrame(ctx, thisArg, args, (CodeFunction)func); + return handler; + } + + public GeneratorFunctionLib(FunctionValue factory) { + super(factory.name, factory.length); + this.factory = factory; + } +} diff --git a/src/me/topchetoeu/jscript/lib/GeneratorLib.java b/src/me/topchetoeu/jscript/lib/GeneratorLib.java index e39062b..6f055a7 100644 --- a/src/me/topchetoeu/jscript/lib/GeneratorLib.java +++ b/src/me/topchetoeu/jscript/lib/GeneratorLib.java @@ -4,99 +4,78 @@ import me.topchetoeu.jscript.engine.Context; import me.topchetoeu.jscript.engine.StackData; import me.topchetoeu.jscript.engine.frame.CodeFrame; import me.topchetoeu.jscript.engine.frame.Runners; -import me.topchetoeu.jscript.engine.values.CodeFunction; -import me.topchetoeu.jscript.engine.values.FunctionValue; -import me.topchetoeu.jscript.engine.values.NativeFunction; import me.topchetoeu.jscript.engine.values.ObjectValue; import me.topchetoeu.jscript.exceptions.EngineException; import me.topchetoeu.jscript.interop.Native; -public class GeneratorLib extends FunctionValue { - public final FunctionValue factory; +@Native("Generator") public class GeneratorLib { + private boolean yielding = true; + private boolean done = false; + public CodeFrame frame; - public static class Generator { - private boolean yielding = true; - private boolean done = false; - public CodeFrame frame; + @Native("@@Symbol.typeName") public final String name = "Generator"; - @Native("@@Symbol.typeName") public final String name = "Generator"; + private ObjectValue next(Context ctx, Object inducedValue, Object inducedReturn, Object inducedError) { + if (done) { + if (inducedError != Runners.NO_RETURN) throw new EngineException(inducedError); + var res = new ObjectValue(); + res.defineProperty(ctx, "done", true); + res.defineProperty(ctx, "value", inducedReturn == Runners.NO_RETURN ? null : inducedReturn); + return res; + } - private ObjectValue next(Context ctx, Object inducedValue, Object inducedReturn, Object inducedError) { - if (done) { - if (inducedError != Runners.NO_RETURN) throw new EngineException(inducedError); - var res = new ObjectValue(); - res.defineProperty(ctx, "done", true); - res.defineProperty(ctx, "value", inducedReturn == Runners.NO_RETURN ? null : inducedReturn); - return res; - } + Object res = null; + StackData.pushFrame(ctx, frame); + yielding = false; - Object res = null; - StackData.pushFrame(ctx, frame); - yielding = false; - - while (!yielding) { - try { - res = frame.next(ctx, inducedValue, inducedReturn, inducedError == Runners.NO_RETURN ? null : new EngineException(inducedError)); - inducedReturn = inducedError = Runners.NO_RETURN; - if (res != Runners.NO_RETURN) { - done = true; - break; - } - } - catch (EngineException e) { + while (!yielding) { + try { + res = frame.next(ctx, inducedValue, inducedReturn, inducedError == Runners.NO_RETURN ? null : new EngineException(inducedError)); + inducedReturn = inducedError = Runners.NO_RETURN; + if (res != Runners.NO_RETURN) { done = true; - throw e; + break; } } - - StackData.popFrame(ctx, frame); - if (done) frame = null; - else res = frame.pop(); - - var obj = new ObjectValue(); - obj.defineProperty(ctx, "done", done); - obj.defineProperty(ctx, "value", res); - return obj; + catch (EngineException e) { + done = true; + throw e; + } } - @Native - public ObjectValue next(Context ctx, Object ...args) { - if (args.length == 0) return next(ctx, Runners.NO_RETURN, Runners.NO_RETURN, Runners.NO_RETURN); - else return next(ctx, args[0], Runners.NO_RETURN, Runners.NO_RETURN); - } - @Native("throw") - public ObjectValue _throw(Context ctx, Object error) { - return next(ctx, Runners.NO_RETURN, Runners.NO_RETURN, error); - } - @Native("return") - public ObjectValue _return(Context ctx, Object value) { - return next(ctx, Runners.NO_RETURN, value, Runners.NO_RETURN); - } + StackData.popFrame(ctx, frame); + if (done) frame = null; + else res = frame.pop(); - @Override - public String toString() { - if (done) return "Generator [closed]"; - if (yielding) return "Generator [suspended]"; - return "Generator [running]"; - } + var obj = new ObjectValue(); + obj.defineProperty(ctx, "done", done); + obj.defineProperty(ctx, "value", res); + return obj; + } - public Object yield(Context ctx, Object thisArg, Object[] args) { - this.yielding = true; - return args.length > 0 ? args[0] : null; - } + @Native + public ObjectValue next(Context ctx, Object ...args) { + if (args.length == 0) return next(ctx, Runners.NO_RETURN, Runners.NO_RETURN, Runners.NO_RETURN); + else return next(ctx, args[0], Runners.NO_RETURN, Runners.NO_RETURN); + } + @Native("throw") + public ObjectValue _throw(Context ctx, Object error) { + return next(ctx, Runners.NO_RETURN, Runners.NO_RETURN, error); + } + @Native("return") + public ObjectValue _return(Context ctx, Object value) { + return next(ctx, Runners.NO_RETURN, value, Runners.NO_RETURN); } @Override - public Object call(Context ctx, Object thisArg, Object ...args) { - var handler = new Generator(); - var func = factory.call(ctx, thisArg, new NativeFunction("yield", handler::yield)); - if (!(func instanceof CodeFunction)) throw EngineException.ofType("Return value of argument must be a js function."); - handler.frame = new CodeFrame(ctx, thisArg, args, (CodeFunction)func); - return handler; + public String toString() { + if (done) return "Generator [closed]"; + if (yielding) return "Generator [suspended]"; + return "Generator [running]"; } - public GeneratorLib(FunctionValue factory) { - super(factory.name, factory.length); - this.factory = factory; + public Object yield(Context ctx, Object thisArg, Object[] args) { + this.yielding = true; + return args.length > 0 ? args[0] : null; } -} +} \ No newline at end of file diff --git a/src/me/topchetoeu/jscript/lib/Internals.java b/src/me/topchetoeu/jscript/lib/Internals.java index 3714a1f..c31b762 100644 --- a/src/me/topchetoeu/jscript/lib/Internals.java +++ b/src/me/topchetoeu/jscript/lib/Internals.java @@ -11,6 +11,7 @@ import me.topchetoeu.jscript.engine.scope.GlobalScope; import me.topchetoeu.jscript.engine.values.FunctionValue; import me.topchetoeu.jscript.engine.values.Values; import me.topchetoeu.jscript.interop.Native; +import me.topchetoeu.jscript.interop.NativeGetter; public class Internals { private static final DataKey> THREADS = new DataKey<>(); @@ -20,6 +21,7 @@ public class Internals { @Native public static void log(Context ctx, Object ...args) { for (var arg : args) { Values.printValue(ctx, arg); + System.out.print(" "); } System.out.println(); } @@ -101,6 +103,13 @@ public class Internals { return NumberLib.isInfinite(ctx, val); } + @NativeGetter public static double NaN(Context ctx) { + return Double.NaN; + } + @NativeGetter public static double Infinity(Context ctx) { + return Double.POSITIVE_INFINITY; + } + public void apply(Environment env) { var wp = env.wrappers; var glob = env.global = new GlobalScope(wp.getNamespace(Internals.class)); diff --git a/src/me/topchetoeu/jscript/lib/MapLib.java b/src/me/topchetoeu/jscript/lib/MapLib.java index 5a8a879..53acc2a 100644 --- a/src/me/topchetoeu/jscript/lib/MapLib.java +++ b/src/me/topchetoeu/jscript/lib/MapLib.java @@ -12,7 +12,7 @@ import me.topchetoeu.jscript.engine.values.Values; import me.topchetoeu.jscript.interop.Native; import me.topchetoeu.jscript.interop.NativeGetter; -public class MapLib { +@Native("Map") public class MapLib { private LinkedHashMap map = new LinkedHashMap<>(); @Native("@@Symbol.typeName") public final String name = "Map"; @@ -64,7 +64,7 @@ public class MapLib { @Native public void forEach(Context ctx, FunctionValue func, Object thisArg) { var keys = new ArrayList<>(map.keySet()); - for (var el : keys) func.call(ctx, thisArg, el, map.get(el), this); + for (var el : keys) func.call(ctx, thisArg, map.get(el), el,this); } @Native public MapLib(Context ctx, Object iterable) { diff --git a/src/me/topchetoeu/jscript/lib/MathLib.java b/src/me/topchetoeu/jscript/lib/MathLib.java index 0dbf1cb..381b5ae 100644 --- a/src/me/topchetoeu/jscript/lib/MathLib.java +++ b/src/me/topchetoeu/jscript/lib/MathLib.java @@ -2,7 +2,7 @@ package me.topchetoeu.jscript.lib; import me.topchetoeu.jscript.interop.Native; -public class MathLib { +@Native("Math") public class MathLib { @Native public static final double E = Math.E; @Native public static final double PI = Math.PI; @Native public static final double SQRT2 = Math.sqrt(2); diff --git a/src/me/topchetoeu/jscript/lib/NumberLib.java b/src/me/topchetoeu/jscript/lib/NumberLib.java index 11556e3..29e280a 100644 --- a/src/me/topchetoeu/jscript/lib/NumberLib.java +++ b/src/me/topchetoeu/jscript/lib/NumberLib.java @@ -9,7 +9,7 @@ import me.topchetoeu.jscript.interop.Native; import me.topchetoeu.jscript.interop.NativeConstructor; import me.topchetoeu.jscript.interop.NativeInit; -public class NumberLib { +@Native("Number") public class NumberLib { @Native public static final double EPSILON = java.lang.Math.ulp(1.0); @Native public static final double MAX_SAFE_INTEGER = 9007199254740991.; @Native public static final double MIN_SAFE_INTEGER = -MAX_SAFE_INTEGER; diff --git a/src/me/topchetoeu/jscript/lib/ObjectLib.java b/src/me/topchetoeu/jscript/lib/ObjectLib.java index f7fce62..165bee5 100644 --- a/src/me/topchetoeu/jscript/lib/ObjectLib.java +++ b/src/me/topchetoeu/jscript/lib/ObjectLib.java @@ -13,7 +13,7 @@ import me.topchetoeu.jscript.interop.Native; import me.topchetoeu.jscript.interop.NativeConstructor; import me.topchetoeu.jscript.interop.NativeInit; -public class ObjectLib { +@Native("Object") public class ObjectLib { @Native public static ObjectValue assign(Context ctx, ObjectValue dst, Object... src) { for (var obj : src) { for (var key : Values.getMembers(ctx, obj, true, true)) { diff --git a/src/me/topchetoeu/jscript/lib/PromiseLib.java b/src/me/topchetoeu/jscript/lib/PromiseLib.java index 7c4f7db..769fa80 100644 --- a/src/me/topchetoeu/jscript/lib/PromiseLib.java +++ b/src/me/topchetoeu/jscript/lib/PromiseLib.java @@ -18,7 +18,7 @@ import me.topchetoeu.jscript.interop.InitType; import me.topchetoeu.jscript.interop.Native; import me.topchetoeu.jscript.interop.NativeInit; -public class PromiseLib { +@Native("Promise") public class PromiseLib { private static class Handle { public final Context ctx; public final FunctionValue fulfilled; diff --git a/src/me/topchetoeu/jscript/lib/RangeErrorLib.java b/src/me/topchetoeu/jscript/lib/RangeErrorLib.java index fc21e47..9e24482 100644 --- a/src/me/topchetoeu/jscript/lib/RangeErrorLib.java +++ b/src/me/topchetoeu/jscript/lib/RangeErrorLib.java @@ -4,10 +4,11 @@ import me.topchetoeu.jscript.engine.Context; import me.topchetoeu.jscript.engine.Environment; import me.topchetoeu.jscript.engine.values.ObjectValue; import me.topchetoeu.jscript.interop.InitType; +import me.topchetoeu.jscript.interop.Native; import me.topchetoeu.jscript.interop.NativeConstructor; import me.topchetoeu.jscript.interop.NativeInit; -public class RangeErrorLib extends ErrorLib { +@Native("RangeError") public class RangeErrorLib extends ErrorLib { @NativeConstructor(thisArg = true) public static ObjectValue constructor(Context ctx, Object thisArg, Object message) { var target = ErrorLib.constructor(ctx, thisArg, message); target.defineProperty(ctx, "name", "RangeError"); diff --git a/src/me/topchetoeu/jscript/lib/RegExpLib.java b/src/me/topchetoeu/jscript/lib/RegExpLib.java index 9828577..0c5c0ec 100644 --- a/src/me/topchetoeu/jscript/lib/RegExpLib.java +++ b/src/me/topchetoeu/jscript/lib/RegExpLib.java @@ -12,7 +12,7 @@ import me.topchetoeu.jscript.engine.values.Values; import me.topchetoeu.jscript.interop.Native; import me.topchetoeu.jscript.interop.NativeGetter; -public class RegExpLib { +@Native("RegExp") public class RegExpLib { // I used Regex to analyze Regex private static final Pattern NAMED_PATTERN = Pattern.compile("\\(\\?<([^=!].*?)>", Pattern.DOTALL); private static final Pattern ESCAPE_PATTERN = Pattern.compile("[/\\-\\\\^$*+?.()|\\[\\]{}]"); diff --git a/src/me/topchetoeu/jscript/lib/SetLib.java b/src/me/topchetoeu/jscript/lib/SetLib.java index 1cd8b7f..0afc096 100644 --- a/src/me/topchetoeu/jscript/lib/SetLib.java +++ b/src/me/topchetoeu/jscript/lib/SetLib.java @@ -12,7 +12,7 @@ import me.topchetoeu.jscript.engine.values.Values; import me.topchetoeu.jscript.interop.Native; import me.topchetoeu.jscript.interop.NativeGetter; -public class SetLib { +@Native("Set") public class SetLib { private LinkedHashSet set = new LinkedHashSet<>(); @Native("@@Symbol.typeName") public final String name = "Set"; diff --git a/src/me/topchetoeu/jscript/lib/StringLib.java b/src/me/topchetoeu/jscript/lib/StringLib.java index 707d542..f163c81 100644 --- a/src/me/topchetoeu/jscript/lib/StringLib.java +++ b/src/me/topchetoeu/jscript/lib/StringLib.java @@ -16,7 +16,7 @@ import me.topchetoeu.jscript.interop.NativeGetter; import me.topchetoeu.jscript.interop.NativeInit; // TODO: implement index wrapping properly -public class StringLib { +@Native("String") public class StringLib { public final String value; private static String passThis(Context ctx, String funcName, Object val) { diff --git a/src/me/topchetoeu/jscript/lib/SymbolLib.java b/src/me/topchetoeu/jscript/lib/SymbolLib.java index e7be32a..03fed13 100644 --- a/src/me/topchetoeu/jscript/lib/SymbolLib.java +++ b/src/me/topchetoeu/jscript/lib/SymbolLib.java @@ -15,7 +15,7 @@ import me.topchetoeu.jscript.interop.NativeConstructor; import me.topchetoeu.jscript.interop.NativeGetter; import me.topchetoeu.jscript.interop.NativeInit; -public class SymbolLib { +@Native("Symbol") public class SymbolLib { private static final Map symbols = new HashMap<>(); @NativeGetter public static Symbol typeName(Context ctx) { return ctx.environment().symbol("Symbol.typeName"); } diff --git a/src/me/topchetoeu/jscript/lib/SyntaxErrorLib.java b/src/me/topchetoeu/jscript/lib/SyntaxErrorLib.java index c3b2de5..7c2a1ef 100644 --- a/src/me/topchetoeu/jscript/lib/SyntaxErrorLib.java +++ b/src/me/topchetoeu/jscript/lib/SyntaxErrorLib.java @@ -4,10 +4,11 @@ import me.topchetoeu.jscript.engine.Context; import me.topchetoeu.jscript.engine.Environment; import me.topchetoeu.jscript.engine.values.ObjectValue; import me.topchetoeu.jscript.interop.InitType; +import me.topchetoeu.jscript.interop.Native; import me.topchetoeu.jscript.interop.NativeConstructor; import me.topchetoeu.jscript.interop.NativeInit; -public class SyntaxErrorLib extends ErrorLib { +@Native("SyntaxError") public class SyntaxErrorLib extends ErrorLib { @NativeConstructor(thisArg = true) public static ObjectValue constructor(Context ctx, Object thisArg, Object message) { var target = ErrorLib.constructor(ctx, thisArg, message); target.defineProperty(ctx, "name", "SyntaxError"); diff --git a/src/me/topchetoeu/jscript/lib/TypeErrorLib.java b/src/me/topchetoeu/jscript/lib/TypeErrorLib.java index b15a5b3..27298cd 100644 --- a/src/me/topchetoeu/jscript/lib/TypeErrorLib.java +++ b/src/me/topchetoeu/jscript/lib/TypeErrorLib.java @@ -4,10 +4,11 @@ import me.topchetoeu.jscript.engine.Context; import me.topchetoeu.jscript.engine.Environment; import me.topchetoeu.jscript.engine.values.ObjectValue; import me.topchetoeu.jscript.interop.InitType; +import me.topchetoeu.jscript.interop.Native; import me.topchetoeu.jscript.interop.NativeConstructor; import me.topchetoeu.jscript.interop.NativeInit; -public class TypeErrorLib extends ErrorLib { +@Native("TypeError") public class TypeErrorLib extends ErrorLib { @NativeConstructor(thisArg = true) public static ObjectValue constructor(Context ctx, Object thisArg, Object message) { var target = ErrorLib.constructor(ctx, thisArg, message); target.defineProperty(ctx, "name", "TypeError");