feat: implement Array.reduce

fix: native functions are now named
This commit is contained in:
TopchetoEU 2023-11-04 11:38:29 +02:00
parent 6508f15bb0
commit ac128d17f4
Signed by: topchetoeu
GPG Key ID: 6531B8583E5F6ED4
24 changed files with 272 additions and 211 deletions

View File

@ -137,7 +137,11 @@ public class NativeWrapperProvider implements WrappersProvider {
* @param clazz The class for which a constructor should be generated * @param clazz The class for which a constructor should be generated
*/ */
public static FunctionValue makeConstructor(Environment ctx, Class<?> clazz) { 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()) { for (var overload : clazz.getDeclaredConstructors()) {
var nat = overload.getAnnotation(Native.class); var nat = overload.getAnnotation(Native.class);

View File

@ -16,7 +16,7 @@ import me.topchetoeu.jscript.interop.NativeGetter;
import me.topchetoeu.jscript.interop.NativeInit; import me.topchetoeu.jscript.interop.NativeInit;
import me.topchetoeu.jscript.interop.NativeSetter; 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) { @NativeGetter(thisArg = true) public static int length(Context ctx, ArrayValue thisArg) {
return thisArg.size(); 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) { @Native(thisArg = true) public static ArrayValue flat(Context ctx, ArrayValue arr, int depth) {
var res = new ArrayValue(arr.size()); var res = new ArrayValue(arr.size());
var stack = new Stack<Object>(); var stack = new Stack<Object>();
@ -224,7 +255,7 @@ public class ArrayLib {
@Native(thisArg = true) public static int indexOf(Context ctx, ArrayValue arr, Object val, int start) { @Native(thisArg = true) public static int indexOf(Context ctx, ArrayValue arr, Object val, int start) {
start = normalizeI(arr.size(), start, true); 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; 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) { @Native(thisArg = true) public static String join(Context ctx, ArrayValue arr, String sep) {
var res = new StringBuilder(); var res = new StringBuilder();
var comma = true; var comma = false;
for (int i = 0; i < arr.size(); i++) { for (int i = 0; i < arr.size(); i++) {
if (!arr.has(i)) continue; if (!arr.has(i)) continue;
if (comma) res.append(sep); if (comma) res.append(sep);
comma = false; comma = true;
var el = arr.get(i); var el = arr.get(i);
if (el == null || el == Values.NULL) continue; if (el == null || el == Values.NULL) continue;

View File

@ -8,8 +8,9 @@ import me.topchetoeu.jscript.engine.values.CodeFunction;
import me.topchetoeu.jscript.engine.values.FunctionValue; import me.topchetoeu.jscript.engine.values.FunctionValue;
import me.topchetoeu.jscript.engine.values.NativeFunction; import me.topchetoeu.jscript.engine.values.NativeFunction;
import me.topchetoeu.jscript.exceptions.EngineException; 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 final FunctionValue factory;
public static class AsyncHelper { public static class AsyncHelper {

View File

@ -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;
}
}

View File

@ -6,130 +6,106 @@ import me.topchetoeu.jscript.engine.Context;
import me.topchetoeu.jscript.engine.StackData; import me.topchetoeu.jscript.engine.StackData;
import me.topchetoeu.jscript.engine.frame.CodeFrame; import me.topchetoeu.jscript.engine.frame.CodeFrame;
import me.topchetoeu.jscript.engine.frame.Runners; 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.NativeFunction;
import me.topchetoeu.jscript.engine.values.ObjectValue; import me.topchetoeu.jscript.engine.values.ObjectValue;
import me.topchetoeu.jscript.exceptions.EngineException; import me.topchetoeu.jscript.exceptions.EngineException;
import me.topchetoeu.jscript.interop.Native; import me.topchetoeu.jscript.interop.Native;
public class AsyncGeneratorLib extends FunctionValue { @Native("AsyncGenerator") public class AsyncGeneratorLib {
public final FunctionValue factory; @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 { private void next(Context ctx, Object inducedValue, Object inducedReturn, Object inducedError) {
@Native("@@Symbol.typeName") public final String name = "AsyncGenerator"; if (done) {
private int state = 0; if (inducedError != Runners.NO_RETURN) throw new EngineException(inducedError);
private boolean done = false; currPromise.fulfill(ctx, new ObjectValue(ctx, Map.of(
private PromiseLib currPromise; "done", true,
public CodeFrame frame; "value", inducedReturn == Runners.NO_RETURN ? null : inducedReturn
)));
return;
}
private void next(Context ctx, Object inducedValue, Object inducedReturn, Object inducedError) { Object res = null;
if (done) { StackData.pushFrame(ctx, frame);
if (inducedError != Runners.NO_RETURN) state = 0;
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; while (state == 0) {
StackData.pushFrame(ctx, frame); try {
state = 0; res = frame.next(ctx, inducedValue, inducedReturn, inducedError == Runners.NO_RETURN ? null : new EngineException(inducedError));
inducedValue = inducedReturn = inducedError = Runners.NO_RETURN;
while (state == 0) { if (res != Runners.NO_RETURN) {
try { var obj = new ObjectValue();
res = frame.next(ctx, inducedValue, inducedReturn, inducedError == Runners.NO_RETURN ? null : new EngineException(inducedError)); obj.defineProperty(ctx, "done", true);
inducedValue = inducedReturn = inducedError = Runners.NO_RETURN; obj.defineProperty(ctx, "value", res);
if (res != Runners.NO_RETURN) { currPromise.fulfill(ctx, obj);
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);
break; break;
} }
} }
catch (EngineException e) {
StackData.popFrame(ctx, frame); currPromise.reject(ctx, e.value);
break;
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);
} }
} }
@Override StackData.popFrame(ctx, frame);
public String toString() {
if (done) return "Generator [closed]";
if (state != 0) return "Generator [suspended]";
return "Generator [running]";
}
public Object fulfill(Context ctx, Object thisArg, Object ...args) { if (state == 1) {
next(ctx, args.length > 0 ? args[0] : null, Runners.NO_RETURN, Runners.NO_RETURN); PromiseLib.then(ctx, frame.pop(), new NativeFunction(this::fulfill), new NativeFunction(this::reject));
return null;
} }
public Object reject(Context ctx, Object thisArg, Object ...args) { else if (state == 2) {
next(ctx, Runners.NO_RETURN, args.length > 0 ? args[0] : null, Runners.NO_RETURN); var obj = new ObjectValue();
return null; obj.defineProperty(ctx, "done", false);
} obj.defineProperty(ctx, "value", frame.pop());
currPromise.fulfill(ctx, obj);
@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;
} }
} }
@Override @Override
public Object call(Context ctx, Object thisArg, Object ...args) { public String toString() {
var handler = new AsyncGenerator(); if (done) return "Generator [closed]";
var func = factory.call(ctx, thisArg, if (state != 0) return "Generator [suspended]";
new NativeFunction("await", handler::await), return "Generator [running]";
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 AsyncGeneratorLib(FunctionValue factory) { public Object fulfill(Context ctx, Object thisArg, Object ...args) {
super(factory.name, factory.length); next(ctx, args.length > 0 ? args[0] : null, Runners.NO_RETURN, Runners.NO_RETURN);
this.factory = factory; 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;
}
}

View File

@ -9,7 +9,7 @@ import me.topchetoeu.jscript.interop.Native;
import me.topchetoeu.jscript.interop.NativeConstructor; import me.topchetoeu.jscript.interop.NativeConstructor;
import me.topchetoeu.jscript.interop.NativeInit; 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 TRUE = new BooleanLib(true);
public static final BooleanLib FALSE = new BooleanLib(false); public static final BooleanLib FALSE = new BooleanLib(false);

View File

@ -6,7 +6,7 @@ import java.util.TimeZone;
import me.topchetoeu.jscript.engine.Context; import me.topchetoeu.jscript.engine.Context;
import me.topchetoeu.jscript.interop.Native; import me.topchetoeu.jscript.interop.Native;
public class DateLib { @Native("Date") public class DateLib {
private Calendar normal; private Calendar normal;
private Calendar utc; private Calendar utc;

View File

@ -11,7 +11,7 @@ import me.topchetoeu.jscript.interop.Native;
import me.topchetoeu.jscript.interop.NativeConstructor; import me.topchetoeu.jscript.interop.NativeConstructor;
import me.topchetoeu.jscript.interop.NativeInit; 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) { private static String toString(Context ctx, boolean rethrown, Object cause, Object name, Object message, ArrayValue stack) {
if (name == null) name = ""; if (name == null) name = "";
else name = Values.toString(ctx, name).trim(); else name = Values.toString(ctx, name).trim();
@ -23,13 +23,6 @@ public class ErrorLib {
if (!message.equals("") && !name.equals("")) res.append(": "); if (!message.equals("") && !name.equals("")) res.append(": ");
if (!message.equals("")) res.append(message); 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 (cause instanceof ObjectValue) {
if (rethrown) res.append("\n (rethrown)"); if (rethrown) res.append("\n (rethrown)");
else res.append("\nCaused by ").append(toString(ctx, cause)); else res.append("\nCaused by ").append(toString(ctx, cause));

View File

@ -1,8 +1,10 @@
package me.topchetoeu.jscript.lib; package me.topchetoeu.jscript.lib;
import me.topchetoeu.jscript.Location;
import me.topchetoeu.jscript.engine.Context; import me.topchetoeu.jscript.engine.Context;
import me.topchetoeu.jscript.engine.Environment; import me.topchetoeu.jscript.engine.Environment;
import me.topchetoeu.jscript.engine.values.ArrayValue; 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.FunctionValue;
import me.topchetoeu.jscript.engine.values.NativeFunction; import me.topchetoeu.jscript.engine.values.NativeFunction;
import me.topchetoeu.jscript.engine.values.ObjectValue; 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.Native;
import me.topchetoeu.jscript.interop.NativeInit; 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) { @Native(thisArg = true) public static Object apply(Context ctx, FunctionValue func, Object thisArg, ArrayValue args) {
return func.call(ctx, thisArg, args.toArray()); return func.call(ctx, thisArg, args.toArray());
} }
@ -44,10 +50,10 @@ public class FunctionLib {
return new AsyncFunctionLib(func); return new AsyncFunctionLib(func);
} }
@Native public static FunctionValue asyncGenerator(FunctionValue func) { @Native public static FunctionValue asyncGenerator(FunctionValue func) {
return new AsyncGeneratorLib(func); return new AsyncGeneratorFunctionLib(func);
} }
@Native public static FunctionValue generator(FunctionValue 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) { @NativeInit(InitType.PROTOTYPE) public static void init(Environment env, ObjectValue target) {

View File

@ -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;
}
}

View File

@ -4,99 +4,78 @@ import me.topchetoeu.jscript.engine.Context;
import me.topchetoeu.jscript.engine.StackData; import me.topchetoeu.jscript.engine.StackData;
import me.topchetoeu.jscript.engine.frame.CodeFrame; import me.topchetoeu.jscript.engine.frame.CodeFrame;
import me.topchetoeu.jscript.engine.frame.Runners; 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.engine.values.ObjectValue;
import me.topchetoeu.jscript.exceptions.EngineException; import me.topchetoeu.jscript.exceptions.EngineException;
import me.topchetoeu.jscript.interop.Native; import me.topchetoeu.jscript.interop.Native;
public class GeneratorLib extends FunctionValue { @Native("Generator") public class GeneratorLib {
public final FunctionValue factory; private boolean yielding = true;
private boolean done = false;
public CodeFrame frame;
public static class Generator { @Native("@@Symbol.typeName") public final String name = "Generator";
private boolean yielding = true;
private boolean done = false;
public CodeFrame frame;
@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) { Object res = null;
if (done) { StackData.pushFrame(ctx, frame);
if (inducedError != Runners.NO_RETURN) throw new EngineException(inducedError); yielding = false;
var res = new ObjectValue();
res.defineProperty(ctx, "done", true);
res.defineProperty(ctx, "value", inducedReturn == Runners.NO_RETURN ? null : inducedReturn);
return res;
}
Object res = null; while (!yielding) {
StackData.pushFrame(ctx, frame); try {
yielding = false; res = frame.next(ctx, inducedValue, inducedReturn, inducedError == Runners.NO_RETURN ? null : new EngineException(inducedError));
inducedReturn = inducedError = Runners.NO_RETURN;
while (!yielding) { if (res != Runners.NO_RETURN) {
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) {
done = true; done = true;
throw e; break;
} }
} }
catch (EngineException e) {
StackData.popFrame(ctx, frame); done = true;
if (done) frame = null; throw e;
else res = frame.pop(); }
var obj = new ObjectValue();
obj.defineProperty(ctx, "done", done);
obj.defineProperty(ctx, "value", res);
return obj;
} }
@Native StackData.popFrame(ctx, frame);
public ObjectValue next(Context ctx, Object ...args) { if (done) frame = null;
if (args.length == 0) return next(ctx, Runners.NO_RETURN, Runners.NO_RETURN, Runners.NO_RETURN); else res = frame.pop();
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 var obj = new ObjectValue();
public String toString() { obj.defineProperty(ctx, "done", done);
if (done) return "Generator [closed]"; obj.defineProperty(ctx, "value", res);
if (yielding) return "Generator [suspended]"; return obj;
return "Generator [running]"; }
}
public Object yield(Context ctx, Object thisArg, Object[] args) { @Native
this.yielding = true; public ObjectValue next(Context ctx, Object ...args) {
return args.length > 0 ? args[0] : null; 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 @Override
public Object call(Context ctx, Object thisArg, Object ...args) { public String toString() {
var handler = new Generator(); if (done) return "Generator [closed]";
var func = factory.call(ctx, thisArg, new NativeFunction("yield", handler::yield)); if (yielding) return "Generator [suspended]";
if (!(func instanceof CodeFunction)) throw EngineException.ofType("Return value of argument must be a js function."); return "Generator [running]";
handler.frame = new CodeFrame(ctx, thisArg, args, (CodeFunction)func);
return handler;
} }
public GeneratorLib(FunctionValue factory) { public Object yield(Context ctx, Object thisArg, Object[] args) {
super(factory.name, factory.length); this.yielding = true;
this.factory = factory; return args.length > 0 ? args[0] : null;
} }
} }

View File

@ -11,6 +11,7 @@ import me.topchetoeu.jscript.engine.scope.GlobalScope;
import me.topchetoeu.jscript.engine.values.FunctionValue; import me.topchetoeu.jscript.engine.values.FunctionValue;
import me.topchetoeu.jscript.engine.values.Values; import me.topchetoeu.jscript.engine.values.Values;
import me.topchetoeu.jscript.interop.Native; import me.topchetoeu.jscript.interop.Native;
import me.topchetoeu.jscript.interop.NativeGetter;
public class Internals { public class Internals {
private static final DataKey<HashMap<Integer, Thread>> THREADS = new DataKey<>(); private static final DataKey<HashMap<Integer, Thread>> THREADS = new DataKey<>();
@ -20,6 +21,7 @@ public class Internals {
@Native public static void log(Context ctx, Object ...args) { @Native public static void log(Context ctx, Object ...args) {
for (var arg : args) { for (var arg : args) {
Values.printValue(ctx, arg); Values.printValue(ctx, arg);
System.out.print(" ");
} }
System.out.println(); System.out.println();
} }
@ -101,6 +103,13 @@ public class Internals {
return NumberLib.isInfinite(ctx, val); 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) { public void apply(Environment env) {
var wp = env.wrappers; var wp = env.wrappers;
var glob = env.global = new GlobalScope(wp.getNamespace(Internals.class)); var glob = env.global = new GlobalScope(wp.getNamespace(Internals.class));

View File

@ -12,7 +12,7 @@ import me.topchetoeu.jscript.engine.values.Values;
import me.topchetoeu.jscript.interop.Native; import me.topchetoeu.jscript.interop.Native;
import me.topchetoeu.jscript.interop.NativeGetter; import me.topchetoeu.jscript.interop.NativeGetter;
public class MapLib { @Native("Map") public class MapLib {
private LinkedHashMap<Object, Object> map = new LinkedHashMap<>(); private LinkedHashMap<Object, Object> map = new LinkedHashMap<>();
@Native("@@Symbol.typeName") public final String name = "Map"; @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) { @Native public void forEach(Context ctx, FunctionValue func, Object thisArg) {
var keys = new ArrayList<>(map.keySet()); 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) { @Native public MapLib(Context ctx, Object iterable) {

View File

@ -2,7 +2,7 @@ package me.topchetoeu.jscript.lib;
import me.topchetoeu.jscript.interop.Native; 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 E = Math.E;
@Native public static final double PI = Math.PI; @Native public static final double PI = Math.PI;
@Native public static final double SQRT2 = Math.sqrt(2); @Native public static final double SQRT2 = Math.sqrt(2);

View File

@ -9,7 +9,7 @@ import me.topchetoeu.jscript.interop.Native;
import me.topchetoeu.jscript.interop.NativeConstructor; import me.topchetoeu.jscript.interop.NativeConstructor;
import me.topchetoeu.jscript.interop.NativeInit; 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 EPSILON = java.lang.Math.ulp(1.0);
@Native public static final double MAX_SAFE_INTEGER = 9007199254740991.; @Native public static final double MAX_SAFE_INTEGER = 9007199254740991.;
@Native public static final double MIN_SAFE_INTEGER = -MAX_SAFE_INTEGER; @Native public static final double MIN_SAFE_INTEGER = -MAX_SAFE_INTEGER;

View File

@ -13,7 +13,7 @@ import me.topchetoeu.jscript.interop.Native;
import me.topchetoeu.jscript.interop.NativeConstructor; import me.topchetoeu.jscript.interop.NativeConstructor;
import me.topchetoeu.jscript.interop.NativeInit; 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) { @Native public static ObjectValue assign(Context ctx, ObjectValue dst, Object... src) {
for (var obj : src) { for (var obj : src) {
for (var key : Values.getMembers(ctx, obj, true, true)) { for (var key : Values.getMembers(ctx, obj, true, true)) {

View File

@ -18,7 +18,7 @@ import me.topchetoeu.jscript.interop.InitType;
import me.topchetoeu.jscript.interop.Native; import me.topchetoeu.jscript.interop.Native;
import me.topchetoeu.jscript.interop.NativeInit; import me.topchetoeu.jscript.interop.NativeInit;
public class PromiseLib { @Native("Promise") public class PromiseLib {
private static class Handle { private static class Handle {
public final Context ctx; public final Context ctx;
public final FunctionValue fulfilled; public final FunctionValue fulfilled;

View File

@ -4,10 +4,11 @@ import me.topchetoeu.jscript.engine.Context;
import me.topchetoeu.jscript.engine.Environment; import me.topchetoeu.jscript.engine.Environment;
import me.topchetoeu.jscript.engine.values.ObjectValue; import me.topchetoeu.jscript.engine.values.ObjectValue;
import me.topchetoeu.jscript.interop.InitType; import me.topchetoeu.jscript.interop.InitType;
import me.topchetoeu.jscript.interop.Native;
import me.topchetoeu.jscript.interop.NativeConstructor; import me.topchetoeu.jscript.interop.NativeConstructor;
import me.topchetoeu.jscript.interop.NativeInit; 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) { @NativeConstructor(thisArg = true) public static ObjectValue constructor(Context ctx, Object thisArg, Object message) {
var target = ErrorLib.constructor(ctx, thisArg, message); var target = ErrorLib.constructor(ctx, thisArg, message);
target.defineProperty(ctx, "name", "RangeError"); target.defineProperty(ctx, "name", "RangeError");

View File

@ -12,7 +12,7 @@ import me.topchetoeu.jscript.engine.values.Values;
import me.topchetoeu.jscript.interop.Native; import me.topchetoeu.jscript.interop.Native;
import me.topchetoeu.jscript.interop.NativeGetter; import me.topchetoeu.jscript.interop.NativeGetter;
public class RegExpLib { @Native("RegExp") public class RegExpLib {
// I used Regex to analyze Regex // I used Regex to analyze Regex
private static final Pattern NAMED_PATTERN = Pattern.compile("\\(\\?<([^=!].*?)>", Pattern.DOTALL); private static final Pattern NAMED_PATTERN = Pattern.compile("\\(\\?<([^=!].*?)>", Pattern.DOTALL);
private static final Pattern ESCAPE_PATTERN = Pattern.compile("[/\\-\\\\^$*+?.()|\\[\\]{}]"); private static final Pattern ESCAPE_PATTERN = Pattern.compile("[/\\-\\\\^$*+?.()|\\[\\]{}]");

View File

@ -12,7 +12,7 @@ import me.topchetoeu.jscript.engine.values.Values;
import me.topchetoeu.jscript.interop.Native; import me.topchetoeu.jscript.interop.Native;
import me.topchetoeu.jscript.interop.NativeGetter; import me.topchetoeu.jscript.interop.NativeGetter;
public class SetLib { @Native("Set") public class SetLib {
private LinkedHashSet<Object> set = new LinkedHashSet<>(); private LinkedHashSet<Object> set = new LinkedHashSet<>();
@Native("@@Symbol.typeName") public final String name = "Set"; @Native("@@Symbol.typeName") public final String name = "Set";

View File

@ -16,7 +16,7 @@ import me.topchetoeu.jscript.interop.NativeGetter;
import me.topchetoeu.jscript.interop.NativeInit; import me.topchetoeu.jscript.interop.NativeInit;
// TODO: implement index wrapping properly // TODO: implement index wrapping properly
public class StringLib { @Native("String") public class StringLib {
public final String value; public final String value;
private static String passThis(Context ctx, String funcName, Object val) { private static String passThis(Context ctx, String funcName, Object val) {

View File

@ -15,7 +15,7 @@ import me.topchetoeu.jscript.interop.NativeConstructor;
import me.topchetoeu.jscript.interop.NativeGetter; import me.topchetoeu.jscript.interop.NativeGetter;
import me.topchetoeu.jscript.interop.NativeInit; import me.topchetoeu.jscript.interop.NativeInit;
public class SymbolLib { @Native("Symbol") public class SymbolLib {
private static final Map<String, Symbol> symbols = new HashMap<>(); private static final Map<String, Symbol> symbols = new HashMap<>();
@NativeGetter public static Symbol typeName(Context ctx) { return ctx.environment().symbol("Symbol.typeName"); } @NativeGetter public static Symbol typeName(Context ctx) { return ctx.environment().symbol("Symbol.typeName"); }

View File

@ -4,10 +4,11 @@ import me.topchetoeu.jscript.engine.Context;
import me.topchetoeu.jscript.engine.Environment; import me.topchetoeu.jscript.engine.Environment;
import me.topchetoeu.jscript.engine.values.ObjectValue; import me.topchetoeu.jscript.engine.values.ObjectValue;
import me.topchetoeu.jscript.interop.InitType; import me.topchetoeu.jscript.interop.InitType;
import me.topchetoeu.jscript.interop.Native;
import me.topchetoeu.jscript.interop.NativeConstructor; import me.topchetoeu.jscript.interop.NativeConstructor;
import me.topchetoeu.jscript.interop.NativeInit; 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) { @NativeConstructor(thisArg = true) public static ObjectValue constructor(Context ctx, Object thisArg, Object message) {
var target = ErrorLib.constructor(ctx, thisArg, message); var target = ErrorLib.constructor(ctx, thisArg, message);
target.defineProperty(ctx, "name", "SyntaxError"); target.defineProperty(ctx, "name", "SyntaxError");

View File

@ -4,10 +4,11 @@ import me.topchetoeu.jscript.engine.Context;
import me.topchetoeu.jscript.engine.Environment; import me.topchetoeu.jscript.engine.Environment;
import me.topchetoeu.jscript.engine.values.ObjectValue; import me.topchetoeu.jscript.engine.values.ObjectValue;
import me.topchetoeu.jscript.interop.InitType; import me.topchetoeu.jscript.interop.InitType;
import me.topchetoeu.jscript.interop.Native;
import me.topchetoeu.jscript.interop.NativeConstructor; import me.topchetoeu.jscript.interop.NativeConstructor;
import me.topchetoeu.jscript.interop.NativeInit; 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) { @NativeConstructor(thisArg = true) public static ObjectValue constructor(Context ctx, Object thisArg, Object message) {
var target = ErrorLib.constructor(ctx, thisArg, message); var target = ErrorLib.constructor(ctx, thisArg, message);
target.defineProperty(ctx, "name", "TypeError"); target.defineProperty(ctx, "name", "TypeError");