feat: use new wrapper API in libs

This commit is contained in:
TopchetoEU 2024-01-04 10:02:14 +02:00
parent a61c6a494e
commit 4fa5f5a815
Signed by: topchetoeu
GPG Key ID: 6531B8583E5F6ED4
29 changed files with 1867 additions and 1427 deletions

View File

@ -76,9 +76,11 @@ async function downloadTypescript(outFile) {
console.log('Minifying typescript...');
const minified = minify((await fs.readFile('tmp/typescript-es5.js')).toString());
// const minified = minify((await fs.readFile('tmp/typescript-es5.js')).toString());
const minified = { code: (await fs.readFile('tmp/typescript-es5.js')).toString() };
if (minified.error) throw minified.error;
// Patch unsupported regex syntax
minified.code = minified.code.replaceAll('[-/\\\\^$*+?.()|[\\]{}]', '[-/\\\\^$*+?.()|\\[\\]{}]');

View File

@ -3,107 +3,20 @@ package me.topchetoeu.jscript.lib;
import java.util.Iterator;
import java.util.Stack;
import me.topchetoeu.jscript.engine.Context;
import me.topchetoeu.jscript.engine.values.ArrayValue;
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.Values;
import me.topchetoeu.jscript.interop.Native;
import me.topchetoeu.jscript.interop.NativeConstructor;
import me.topchetoeu.jscript.interop.NativeGetter;
import me.topchetoeu.jscript.interop.NativeSetter;
@Native("Array") public class ArrayLib {
@NativeGetter(thisArg = true) public static int length(Context ctx, ArrayValue thisArg) {
return thisArg.size();
}
@NativeSetter(thisArg = true) public static void length(Context ctx, ArrayValue thisArg, int len) {
thisArg.setSize(len);
}
@Native(thisArg = true) public static ObjectValue values(Context ctx, ArrayValue thisArg) {
return Values.toJSIterator(ctx, thisArg);
}
@Native(thisArg = true) public static ObjectValue keys(Context ctx, ArrayValue thisArg) {
return Values.toJSIterator(ctx, () -> new Iterator<Object>() {
private int i = 0;
@Override
public boolean hasNext() {
return i < thisArg.size();
}
@Override
public Object next() {
if (!hasNext()) return null;
return i++;
}
});
}
@Native(thisArg = true) public static ObjectValue entries(Context ctx, ArrayValue thisArg) {
return Values.toJSIterator(ctx, () -> new Iterator<Object>() {
private int i = 0;
@Override
public boolean hasNext() {
return i < thisArg.size();
}
@Override
public Object next() {
if (!hasNext()) return null;
return new ArrayValue(ctx, i, thisArg.get(i++));
}
});
}
@Native(value = "@@Symbol.iterator", thisArg = true)
public static ObjectValue iterator(Context ctx, ArrayValue thisArg) {
return values(ctx, thisArg);
}
@Native(value = "@@Symbol.asyncIterator", thisArg = true)
public static ObjectValue asyncIterator(Context ctx, ArrayValue thisArg) {
return values(ctx, thisArg);
}
@Native(thisArg = true) public static ArrayValue concat(Context ctx, ArrayValue thisArg, Object ...others) {
// TODO: Fully implement with non-array spreadable objects
var size = thisArg.size();
for (int i = 0; i < others.length; i++) {
if (others[i] instanceof ArrayValue) size += ((ArrayValue)others[i]).size();
else i++;
}
var res = new ArrayValue(size);
thisArg.copyTo(ctx, res, 0, 0, thisArg.size());
for (int i = 0, j = thisArg.size(); i < others.length; i++) {
if (others[i] instanceof ArrayValue) {
int n = ((ArrayValue)others[i]).size();
((ArrayValue)others[i]).copyTo(ctx, res, 0, j, n);
j += n;
}
else {
res.set(ctx, j++, others[i]);
}
}
return res;
}
@Native(thisArg = true) public static ArrayValue sort(Context ctx, ArrayValue arr, FunctionValue cmp) {
var defaultCmp = new NativeFunction("", (_ctx, thisArg, args) -> {
return Values.toString(ctx, args[0]).compareTo(Values.toString(ctx, args[1]));
});
arr.sort((a, b) -> {
var res = Values.toNumber(ctx, (cmp == null ? defaultCmp : cmp).call(ctx, null, a, b));
if (res < 0) return -1;
if (res > 0) return 1;
return 0;
});
return arr;
}
import me.topchetoeu.jscript.interop.Arguments;
import me.topchetoeu.jscript.interop.Expose;
import me.topchetoeu.jscript.interop.ExposeConstructor;
import me.topchetoeu.jscript.interop.ExposeTarget;
import me.topchetoeu.jscript.interop.ExposeType;
import me.topchetoeu.jscript.interop.WrapperName;
@WrapperName("Array")
public class ArrayLib {
private static int normalizeI(int len, int i, boolean clamp) {
if (i < 0) i += len;
if (clamp) {
@ -113,91 +26,202 @@ import me.topchetoeu.jscript.interop.NativeSetter;
return i;
}
@Native(thisArg = true) public static ArrayValue fill(Context ctx, ArrayValue arr, Object val, int start, int end) {
start = normalizeI(arr.size(), start, true);
end = normalizeI(arr.size(), end, true);
for (; start < end; start++) {
arr.set(ctx, start, val);
@Expose(value = "length", type = ExposeType.GETTER)
public static int __getLength(Arguments args) {
return args.self(ArrayValue.class).size();
}
@Expose(value = "length", type = ExposeType.SETTER)
public static void __setLength(Arguments args) {
args.self(ArrayValue.class).setSize(args.getInt(0));
}
@Expose public static ObjectValue __values(Arguments args) {
return __iterator(args);
}
@Expose public static ObjectValue __keys(Arguments args) {
return Values.toJSIterator(args.ctx, () -> new Iterator<Object>() {
private int i = 0;
@Override
public boolean hasNext() {
return i < args.self(ArrayValue.class).size();
}
@Override
public Object next() {
if (!hasNext()) return null;
return i++;
}
});
}
@Expose public static ObjectValue __entries(Arguments args) {
return Values.toJSIterator(args.ctx, () -> new Iterator<Object>() {
private int i = 0;
@Override
public boolean hasNext() {
return i < args.self(ArrayValue.class).size();
}
@Override
public Object next() {
if (!hasNext()) return null;
return new ArrayValue(args.ctx, 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));
}
@Expose(value = "@@Symbol.asyncIterator")
public static ObjectValue __asyncIterator(Arguments args) {
return Values.toJSAsyncIterator(args.ctx, args.self(ArrayValue.class).iterator());
}
@Expose public static ArrayValue __concat(Arguments args) {
// TODO: Fully implement with non-array spreadable objects
var arrs = args.slice(-1);
var size = 0;
for (int i = 0; i < arrs.n(); i++) {
if (arrs.get(i) instanceof ArrayValue) size += arrs.convert(i, ArrayValue.class).size();
else i++;
}
var res = new ArrayValue(size);
for (int i = 0, j = 0; i < arrs.n(); i++) {
if (arrs.get(i) instanceof ArrayValue) {
var arrEl = arrs.convert(i, ArrayValue.class);
int n = arrEl.size();
arrEl.copyTo(args.ctx, res, 0, j, n);
j += n;
}
else {
res.set(args.ctx, j++, arrs.get(i));
}
}
return res;
}
@Expose public static ArrayValue __sort(Arguments args) {
var arr = args.self(ArrayValue.class);
var cmp = args.convert(0, FunctionValue.class);
var defaultCmp = new NativeFunction("", _args -> {
return _args.getString(0).compareTo(_args.getString(1));
});
arr.sort((a, b) -> {
var res = Values.toNumber(args.ctx, (cmp == null ? defaultCmp : cmp).call(args.ctx, null, a, b));
if (res < 0) return -1;
if (res > 0) return 1;
return 0;
});
return arr;
}
@Expose public static ArrayValue __fill(Arguments args) {
var arr = args.self(ArrayValue.class);
var val = args.get(0);
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);
return arr;
}
@Native(thisArg = true) public static ArrayValue fill(Context ctx, ArrayValue arr, Object val, int start) {
return fill(ctx, arr, val, start, arr.size());
}
@Native(thisArg = true) public static ArrayValue fill(Context ctx, ArrayValue arr, Object val) {
return fill(ctx, arr, val, 0, arr.size());
}
@Expose public static boolean __every(Arguments args) {
var arr = args.self(ArrayValue.class);
var func = args.convert(0, FunctionValue.class);
var thisArg = args.get(1);
@Native(thisArg = true) public static boolean every(Context ctx, ArrayValue arr, FunctionValue func, Object thisArg) {
for (var i = 0; i < arr.size(); i++) {
if (!Values.toBoolean(func.call(ctx, thisArg, arr.get(i), i, arr))) return false;
if (!Values.toBoolean(func.call(args.ctx, thisArg, arr.get(i), i, arr))) return false;
}
return true;
}
@Native(thisArg = true) public static boolean some(Context ctx, ArrayValue arr, FunctionValue func, Object thisArg) {
@Expose public static boolean __some(Arguments args) {
var arr = args.self(ArrayValue.class);
var func = args.convert(0, FunctionValue.class);
var thisArg = args.get(1);
for (var i = 0; i < arr.size(); i++) {
if (Values.toBoolean(func.call(ctx, thisArg, arr.get(i), i, arr))) return true;
if (Values.toBoolean(func.call(args.ctx, thisArg, arr.get(i), i, arr))) return true;
}
return false;
}
@Native(thisArg = true) public static ArrayValue filter(Context ctx, ArrayValue arr, FunctionValue func, Object thisArg) {
@Expose public static ArrayValue __filter(Arguments args) {
var arr = args.self(ArrayValue.class);
var func = args.convert(0, FunctionValue.class);
var thisArg = args.get(1);
var res = new ArrayValue(arr.size());
for (int i = 0, j = 0; i < arr.size(); i++) {
if (arr.has(i) && Values.toBoolean(func.call(ctx, thisArg, arr.get(i), i, arr))) res.set(ctx, j++, arr.get(i));
if (arr.has(i) && Values.toBoolean(func.call(args.ctx, thisArg, arr.get(i), i, arr))) res.set(args.ctx, j++, arr.get(i));
}
return res;
}
@Native(thisArg = true) public static ArrayValue map(Context ctx, ArrayValue arr, FunctionValue func, Object thisArg) {
@Expose public static ArrayValue __map(Arguments args) {
var arr = args.self(ArrayValue.class);
var func = args.convert(0, FunctionValue.class);
var thisArg = args.get(1);
var res = new ArrayValue(arr.size());
res.setSize(arr.size());
for (int i = 0, j = 0; i < arr.size(); i++) {
if (arr.has(i)) res.set(ctx, j++, func.call(ctx, thisArg, arr.get(i), i, arr));
if (arr.has(i)) res.set(args.ctx, j++, func.call(args.ctx, thisArg, arr.get(i), i, arr));
}
return res;
}
@Native(thisArg = true) public static void forEach(Context ctx, ArrayValue arr, FunctionValue func, Object thisArg) {
@Expose public static void __forEach(Arguments args) {
var arr = args.self(ArrayValue.class);
var func = args.convert(0, FunctionValue.class);
var thisArg = args.get(1);
for (int i = 0; i < arr.size(); i++) {
if (arr.has(i)) func.call(ctx, thisArg, arr.get(i), i, arr);
if (arr.has(i)) func.call(args.ctx, thisArg, arr.get(i), i, arr);
}
}
@Native(thisArg = true) public static Object reduce(Context ctx, ArrayValue arr, FunctionValue func, Object... args) {
@Expose public static Object __reduce(Arguments args) {
var arr = args.self(ArrayValue.class);
var func = args.convert(0, FunctionValue.class);
var res = args.get(1);
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);
if (args.n() < 2) 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);
res = func.call(args.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) {
@Expose public static Object __reduceRight(Arguments args) {
var arr = args.self(ArrayValue.class);
var func = args.convert(0, FunctionValue.class);
var res = args.get(1);
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);
if (args.n() < 1) 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);
res = func.call(args.ctx, null, res, arr.get(i), i, arr);
}
}
return res;
}
@Native(thisArg = true) public static ArrayValue flat(Context ctx, ArrayValue arr, int depth) {
@Expose public static ArrayValue __flat(Arguments args) {
var arr = args.self(ArrayValue.class);
var depth = args.getInt(0, 1);
var res = new ArrayValue(arr.size());
var stack = new Stack<Object>();
var depths = new Stack<Integer>();
@ -209,127 +233,165 @@ import me.topchetoeu.jscript.interop.NativeSetter;
var el = stack.pop();
int d = depths.pop();
if (d <= depth && el instanceof ArrayValue) {
for (int i = ((ArrayValue)el).size() - 1; i >= 0; i--) {
stack.push(((ArrayValue)el).get(i));
if ((d == -1 || d < depth) && el instanceof ArrayValue) {
var arrEl = (ArrayValue)el;
for (int i = arrEl.size() - 1; i >= 0; i--) {
if (!arrEl.has(i)) continue;
stack.push(arrEl.get(i));
depths.push(d + 1);
}
}
else res.set(ctx, depth, arr);
else res.set(args.ctx, res.size(), el);
}
return res;
}
@Native(thisArg = true) public static ArrayValue flatMap(Context ctx, ArrayValue arr, FunctionValue cmp, Object thisArg) {
return flat(ctx, map(ctx, arr, cmp, thisArg), 1);
@Expose public static ArrayValue __flatMap(Arguments args) {
return __flat(new Arguments(args.ctx, __map(args), 1));
}
@Native(thisArg = true) public static Object find(Context ctx, ArrayValue arr, FunctionValue cmp, Object thisArg) {
@Expose public static Object __find(Arguments args) {
var arr = args.self(ArrayValue.class);
var cmp = args.convert(0, FunctionValue.class);
var thisArg = args.get(1);
for (int i = 0; i < arr.size(); i++) {
if (arr.has(i) && Values.toBoolean(cmp.call(ctx, thisArg, arr.get(i), i, arr))) return arr.get(i);
if (arr.has(i) && Values.toBoolean(cmp.call(args.ctx, thisArg, arr.get(i), i, arr))) return arr.get(i);
}
return null;
}
@Native(thisArg = true) public static Object findLast(Context ctx, ArrayValue arr, FunctionValue cmp, Object thisArg) {
@Expose public static Object __findLast(Arguments args) {
var arr = args.self(ArrayValue.class);
var cmp = args.convert(0, FunctionValue.class);
var thisArg = args.get(1);
for (var i = arr.size() - 1; i >= 0; i--) {
if (arr.has(i) && Values.toBoolean(cmp.call(ctx, thisArg, arr.get(i), i, arr))) return arr.get(i);
if (arr.has(i) && Values.toBoolean(cmp.call(args.ctx, thisArg, arr.get(i), i, arr))) return arr.get(i);
}
return null;
}
@Native(thisArg = true) public static int findIndex(Context ctx, ArrayValue arr, FunctionValue cmp, Object thisArg) {
@Expose public static int __findIndex(Arguments args) {
var arr = args.self(ArrayValue.class);
var cmp = args.convert(0, FunctionValue.class);
var thisArg = args.get(1);
for (int i = 0; i < arr.size(); i++) {
if (arr.has(i) && Values.toBoolean(cmp.call(ctx, thisArg, arr.get(i), i, arr))) return i;
if (arr.has(i) && Values.toBoolean(cmp.call(args.ctx, thisArg, arr.get(i), i, arr))) return i;
}
return -1;
}
@Native(thisArg = true) public static int findLastIndex(Context ctx, ArrayValue arr, FunctionValue cmp, Object thisArg) {
@Expose public static int __findLastIndex(Arguments args) {
var arr = args.self(ArrayValue.class);
var cmp = args.convert(0, FunctionValue.class);
var thisArg = args.get(1);
for (var i = arr.size() - 1; i >= 0; i--) {
if (arr.has(i) && Values.toBoolean(cmp.call(ctx, thisArg, arr.get(i), i, arr))) return i;
if (arr.has(i) && Values.toBoolean(cmp.call(args.ctx, thisArg, arr.get(i), i, arr))) return i;
}
return -1;
}
@Native(thisArg = true) public static int indexOf(Context ctx, ArrayValue arr, Object val, int start) {
start = normalizeI(arr.size(), start, true);
@Expose public static int __indexOf(Arguments args) {
var arr = args.self(ArrayValue.class);
var val = args.get(0);
var start = normalizeI(arr.size(), args.getInt(1), true);
for (int i = start; i < arr.size(); i++) {
if (Values.strictEquals(ctx, arr.get(i), val)) return i;
if (Values.strictEquals(args.ctx, arr.get(i), val)) return i;
}
return -1;
}
@Native(thisArg = true) public static int lastIndexOf(Context ctx, ArrayValue arr, Object val, int start) {
start = normalizeI(arr.size(), start, true);
@Expose public static int __lastIndexOf(Arguments args) {
var arr = args.self(ArrayValue.class);
var val = args.get(0);
var start = normalizeI(arr.size(), args.getInt(1), true);
for (int i = arr.size(); i >= start; i--) {
if (Values.strictEquals(ctx, arr.get(i), val)) return i;
if (Values.strictEquals(args.ctx, arr.get(i), val)) return i;
}
return -1;
}
@Native(thisArg = true) public static boolean includes(Context ctx, ArrayValue arr, Object el, int start) {
return indexOf(ctx, arr, el, start) >= 0;
@Expose public static boolean __includes(Arguments args) {
return __indexOf(args) >= 0;
}
@Native(thisArg = true) public static Object pop(Context ctx, ArrayValue arr) {
@Expose public static Object __pop(Arguments args) {
var arr = args.self(ArrayValue.class);
if (arr.size() == 0) return null;
var val = arr.get(arr.size() - 1);
arr.shrink(1);
return val;
}
@Native(thisArg = true) public static int push(Context ctx, ArrayValue arr, Object ...values) {
arr.copyFrom(ctx, values, 0, arr.size(), values.length);
@Expose public static int __push(Arguments args) {
var arr = args.self(ArrayValue.class);
var values = args.args;
arr.copyFrom(args.ctx, values, 0, arr.size(), values.length);
return arr.size();
}
@Native(thisArg = true) public static Object shift(Context ctx, ArrayValue arr) {
@Expose public static Object __shift(Arguments args) {
var arr = args.self(ArrayValue.class);
if (arr.size() == 0) return null;
var val = arr.get(0);
arr.move(1, 0, arr.size());
arr.shrink(1);
return val;
}
@Native(thisArg = true) public static int unshift(Context ctx, ArrayValue arr, Object ...values) {
@Expose public static int __unshift(Arguments args) {
var arr = args.self(ArrayValue.class);
var values = args.slice(0).args;
arr.move(0, values.length, arr.size());
arr.copyFrom(ctx, values, 0, 0, values.length);
arr.copyFrom(args.ctx, values, 0, 0, values.length);
return arr.size();
}
@Native(thisArg = true) public static ArrayValue slice(Context ctx, ArrayValue arr, int start, Object _end) {
start = normalizeI(arr.size(), start, true);
int end = normalizeI(arr.size(), (int)(_end == null ? arr.size() : Values.toNumber(ctx, _end)), true);
@Expose public static ArrayValue __slice(Arguments args) {
var arr = args.self(ArrayValue.class);
var start = normalizeI(arr.size(), args.getInt(0), true);
var end = normalizeI(arr.size(), args.getInt(1, arr.size()), true);
var res = new ArrayValue(end - start);
arr.copyTo(ctx, res, start, 0, end - start);
arr.copyTo(args.ctx, res, start, 0, end - start);
return res;
}
@Native(thisArg = true) public static ArrayValue splice(Context ctx, ArrayValue arr, int start, Object _deleteCount, Object ...items) {
start = normalizeI(arr.size(), start, true);
int deleteCount = _deleteCount == null ? arr.size() - 1 : (int)Values.toNumber(ctx, _deleteCount);
deleteCount = normalizeI(arr.size(), deleteCount, true);
@Expose public static ArrayValue __splice(Arguments args) {
var arr = args.self(ArrayValue.class);
var start = normalizeI(arr.size(), args.getInt(0), true);
var deleteCount = normalizeI(arr.size(), args.getInt(1, arr.size()), true);
var items = args.slice(2).args;
if (start + deleteCount >= arr.size()) deleteCount = arr.size() - start;
var size = arr.size() - deleteCount + items.length;
var res = new ArrayValue(deleteCount);
arr.copyTo(ctx, res, start, 0, deleteCount);
arr.copyTo(args.ctx, res, start, 0, deleteCount);
arr.move(start + deleteCount, start + items.length, arr.size() - start - deleteCount);
arr.copyFrom(ctx, items, 0, start, items.length);
arr.copyFrom(args.ctx, items, 0, start, items.length);
arr.setSize(size);
return res;
}
@Native(thisArg = true) public static String toString(Context ctx, ArrayValue arr) {
return join(ctx, arr, ",");
@Expose public static String __toString(Arguments args) {
return __join(new Arguments(args.ctx, args.self, ","));
}
@Native(thisArg = true) public static String join(Context ctx, ArrayValue arr, String sep) {
@Expose public static String __join(Arguments args) {
var arr = args.self(ArrayValue.class);
var sep = args.getString(0);
var res = new StringBuilder();
var comma = false;
@ -342,30 +404,33 @@ import me.topchetoeu.jscript.interop.NativeSetter;
var el = arr.get(i);
if (el == null || el == Values.NULL) continue;
res.append(Values.toString(ctx, el));
res.append(Values.toString(args.ctx, el));
}
return res.toString();
}
@Native public static boolean isArray(Context ctx, Object val) { return val instanceof ArrayValue; }
@Native public static ArrayValue of(Context ctx, Object... args) {
var res = new ArrayValue(args.length);
res.copyFrom(ctx, args, 0, 0, args.length);
return res;
@Expose(target = ExposeTarget.STATIC)
public static boolean __isArray(Arguments args) {
return args.get(0) instanceof ArrayValue;
}
@Expose(target = ExposeTarget.STATIC)
public static ArrayValue __of(Arguments args) {
return new ArrayValue(args.ctx, args.slice(0).args);
}
@NativeConstructor public static ArrayValue constructor(Context ctx, Object... args) {
@ExposeConstructor public static ArrayValue __constructor(Arguments args) {
ArrayValue res;
if (args.length == 1 && args[0] instanceof Number) {
int len = ((Number)args[0]).intValue();
if (args.n() == 1 && args.get(0) instanceof Number) {
var len = args.getInt(0);
res = new ArrayValue(len);
res.setSize(len);
}
else {
res = new ArrayValue(args.length);
res.copyFrom(ctx, args, 0, 0, args.length);
var val = args.slice(0).args;
res = new ArrayValue(val.length);
res.copyFrom(args.ctx, val, 0, 0, val.length);
}
return res;

View File

@ -7,55 +7,60 @@ 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;
import me.topchetoeu.jscript.interop.Arguments;
import me.topchetoeu.jscript.interop.WrapperName;
import me.topchetoeu.jscript.lib.PromiseLib.Handle;
@Native("AsyncFunction") public class AsyncFunctionLib extends FunctionValue {
@WrapperName("AsyncFunction")
public class AsyncFunctionLib extends FunctionValue {
public final FunctionValue factory;
public static class AsyncHelper {
private static class AsyncHelper {
public PromiseLib promise = new PromiseLib();
public CodeFrame frame;
private boolean awaiting = false;
private void next(Context ctx, Object inducedValue, Object inducedError) {
private void next(Context ctx, Object inducedValue, EngineException inducedError) {
Object res = null;
frame.onPush();
awaiting = false;
while (!awaiting) {
try {
res = frame.next(inducedValue, Runners.NO_RETURN, inducedError == Runners.NO_RETURN ? null : new EngineException(inducedError));
inducedValue = inducedError = Runners.NO_RETURN;
res = frame.next(inducedValue, Runners.NO_RETURN, inducedError);
inducedValue = Runners.NO_RETURN;
inducedError = null;
if (res != Runners.NO_RETURN) {
promise.fulfill(ctx, res);
break;
}
}
catch (EngineException e) {
promise.reject(ctx, e.value);
promise.reject(ctx, e);
break;
}
}
frame.onPop();
if (awaiting) {
PromiseLib.then(ctx, frame.pop(), new NativeFunction(this::fulfill), new NativeFunction(this::reject));
PromiseLib.handle(ctx, frame.pop(), new Handle() {
@Override
public void onFulfil(Object val) {
next(ctx, val, null);
}
@Override
public void onReject(EngineException err) {
next(ctx, Runners.NO_RETURN, err);
}
});
}
}
public Object fulfill(Context ctx, Object thisArg, Object ...args) {
next(ctx, args.length > 0 ? args[0] : null, 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);
return null;
}
public Object await(Context ctx, Object thisArg, Object[] args) {
public Object await(Arguments args) {
this.awaiting = true;
return args.length > 0 ? args[0] : null;
return args.get(0);
}
}
@ -65,7 +70,7 @@ import me.topchetoeu.jscript.interop.Native;
var func = factory.call(ctx, thisArg, new NativeFunction("await", handler::await));
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);
handler.next(ctx, Runners.NO_RETURN, Runners.NO_RETURN);
handler.next(ctx, Runners.NO_RETURN, null);
return handler.promise;
}

View File

@ -6,9 +6,10 @@ 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;
import me.topchetoeu.jscript.interop.WrapperName;
@Native("AsyncGeneratorFunction") public class AsyncGeneratorFunctionLib extends FunctionValue {
@WrapperName("AsyncGeneratorFunction")
public class AsyncGeneratorFunctionLib extends FunctionValue {
public final FunctionValue factory;
@Override

View File

@ -5,21 +5,23 @@ import java.util.Map;
import me.topchetoeu.jscript.engine.Context;
import me.topchetoeu.jscript.engine.frame.CodeFrame;
import me.topchetoeu.jscript.engine.frame.Runners;
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;
import me.topchetoeu.jscript.interop.Arguments;
import me.topchetoeu.jscript.interop.Expose;
import me.topchetoeu.jscript.interop.WrapperName;
import me.topchetoeu.jscript.lib.PromiseLib.Handle;
@Native("AsyncGenerator") public class AsyncGeneratorLib {
@Native("@@Symbol.typeName") public final String name = "AsyncGenerator";
@WrapperName("AsyncGenerator")
public class AsyncGeneratorLib {
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) {
private void next(Context ctx, Object inducedValue, Object inducedReturn, EngineException inducedError) {
if (done) {
if (inducedError != Runners.NO_RETURN) throw new EngineException(inducedError);
if (inducedError != null) throw inducedError;
currPromise.fulfill(ctx, new ObjectValue(ctx, Map.of(
"done", true,
"value", inducedReturn == Runners.NO_RETURN ? null : inducedReturn
@ -33,8 +35,10 @@ import me.topchetoeu.jscript.interop.Native;
frame.onPush();
while (state == 0) {
try {
res = frame.next(inducedValue, inducedReturn, inducedError == Runners.NO_RETURN ? null : new EngineException(inducedError));
inducedValue = inducedReturn = inducedError = Runners.NO_RETURN;
res = frame.next(inducedValue, inducedReturn, inducedError);
inducedValue = inducedReturn = Runners.NO_RETURN;
inducedError = null;
if (res != Runners.NO_RETURN) {
var obj = new ObjectValue();
obj.defineProperty(ctx, "done", true);
@ -44,14 +48,21 @@ import me.topchetoeu.jscript.interop.Native;
}
}
catch (EngineException e) {
currPromise.reject(ctx, e.value);
currPromise.reject(ctx, e);
break;
}
}
frame.onPop();
if (state == 1) {
PromiseLib.then(ctx, frame.pop(), new NativeFunction(this::fulfill), new NativeFunction(this::reject));
PromiseLib.handle(ctx, frame.pop(), new Handle() {
@Override public void onFulfil(Object val) {
next(ctx, val, Runners.NO_RETURN, null);
}
@Override public void onReject(EngineException err) {
next(ctx, Runners.NO_RETURN, Runners.NO_RETURN, err);
}
});
}
else if (state == 2) {
var obj = new ObjectValue();
@ -68,42 +79,29 @@ import me.topchetoeu.jscript.interop.Native;
return "Generator [running]";
}
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) {
public Object await(Arguments args) {
this.state = 1;
return args.length > 0 ? args[0] : null;
return args.get(0);
}
public Object yield(Context ctx, Object thisArg, Object[] args) {
public Object yield(Arguments args) {
this.state = 2;
return args.length > 0 ? args[0] : null;
return args.get(0);
}
@Expose public PromiseLib __next(Arguments args) {
this.currPromise = new PromiseLib();
if (args.has(0)) next(args.ctx, args.get(0), Runners.NO_RETURN, null);
else next(args.ctx, Runners.NO_RETURN, Runners.NO_RETURN, null);
return this.currPromise;
}
@Expose public PromiseLib __return(Arguments args) {
this.currPromise = new PromiseLib();
next(args.ctx, Runners.NO_RETURN, args.get(0), null);
return this.currPromise;
}
@Expose public PromiseLib __throw(Arguments args) {
this.currPromise = new PromiseLib();
next(args.ctx, Runners.NO_RETURN, Runners.NO_RETURN, new EngineException(args.get(0)).setCtx(args.ctx));
return this.currPromise;
}
}

View File

@ -1,30 +1,31 @@
package me.topchetoeu.jscript.lib;
import me.topchetoeu.jscript.engine.Context;
import me.topchetoeu.jscript.engine.values.ObjectValue;
import me.topchetoeu.jscript.engine.values.Values;
import me.topchetoeu.jscript.interop.Native;
import me.topchetoeu.jscript.interop.NativeConstructor;
import me.topchetoeu.jscript.interop.Arguments;
import me.topchetoeu.jscript.interop.Expose;
import me.topchetoeu.jscript.interop.ExposeConstructor;
import me.topchetoeu.jscript.interop.WrapperName;
@Native("Boolean") public class BooleanLib {
@WrapperName("Boolean")
public class BooleanLib {
public static final BooleanLib TRUE = new BooleanLib(true);
public static final BooleanLib FALSE = new BooleanLib(false);
public final boolean value;
@NativeConstructor(thisArg = true) public static Object constructor(Context ctx, Object thisArg, Object val) {
val = Values.toBoolean(val);
if (thisArg instanceof ObjectValue) return (boolean)val ? TRUE : FALSE;
else return val;
}
@Native(thisArg = true) public static String toString(Context ctx, Object thisArg) {
return Values.toBoolean(thisArg) ? "true" : "false";
}
@Native(thisArg = true) public static boolean valueOf(Context ctx, Object thisArg) {
return Values.toBoolean(thisArg);
}
public BooleanLib(boolean val) {
this.value = val;
}
@ExposeConstructor public static Object __constructor(Arguments args) {
var val = args.getBoolean(0);
if (args.self instanceof ObjectValue) return val ? TRUE : FALSE;
else return val;
}
@Expose public static String __toString(Arguments args) {
return args.self(Boolean.class) ? "true" : "false";
}
@Expose public static boolean __valueOf(Arguments args) {
return args.self(Boolean.class);
}
}

View File

@ -1,12 +1,17 @@
package me.topchetoeu.jscript.lib;
import java.util.Calendar;
import java.util.Date;
import java.util.TimeZone;
import me.topchetoeu.jscript.engine.Context;
import me.topchetoeu.jscript.interop.Native;
import me.topchetoeu.jscript.interop.Arguments;
import me.topchetoeu.jscript.interop.Expose;
import me.topchetoeu.jscript.interop.ExposeConstructor;
import me.topchetoeu.jscript.interop.ExposeTarget;
import me.topchetoeu.jscript.interop.WrapperName;
@Native("Date") public class DateLib {
@WrapperName("Date")
public class DateLib {
private Calendar normal;
private Calendar utc;
@ -22,244 +27,217 @@ import me.topchetoeu.jscript.interop.Native;
normal = utc = null;
}
@Native
public static double now() {
return new DateLib().getTime();
}
@Native
public double getYear() {
@Expose public double __getYear() {
if (normal == null) return Double.NaN;
return normal.get(Calendar.YEAR) - 1900;
}
@Native
public double setYear(Context ctx, double real) {
@Expose public double __setYeard(Arguments args) {
var real = args.getDouble(0);
if (real >= 0 && real <= 99) real = real + 1900;
if (Double.isNaN(real)) invalidate();
else normal.set(Calendar.YEAR, (int)real);
updateUTC();
return getTime();
return __getTime();
}
@Native
public double getFullYear() {
@Expose public double __getFullYear() {
if (normal == null) return Double.NaN;
return normal.get(Calendar.YEAR);
}
@Native
public double getMonth() {
@Expose public double __getMonth() {
if (normal == null) return Double.NaN;
return normal.get(Calendar.MONTH);
}
@Native
public double getDate() {
@Expose public double __getDate() {
if (normal == null) return Double.NaN;
return normal.get(Calendar.DAY_OF_MONTH);
}
@Native
public double getDay() {
@Expose public double __getDay() {
if (normal == null) return Double.NaN;
return normal.get(Calendar.DAY_OF_WEEK);
}
@Native
public double getHours() {
@Expose public double __getHours() {
if (normal == null) return Double.NaN;
return normal.get(Calendar.HOUR_OF_DAY);
}
@Native
public double getMinutes() {
@Expose public double __getMinutes() {
if (normal == null) return Double.NaN;
return normal.get(Calendar.MINUTE);
}
@Native
public double getSeconds() {
@Expose public double __getSeconds() {
if (normal == null) return Double.NaN;
return normal.get(Calendar.SECOND);
}
@Native
public double getMilliseconds() {
@Expose public double __getMilliseconds() {
if (normal == null) return Double.NaN;
return normal.get(Calendar.MILLISECOND);
}
@Native
public double getUTCFullYear() {
@Expose public double __getUTCFullYear() {
if (utc == null) return Double.NaN;
return utc.get(Calendar.YEAR);
}
@Native
public double getUTCMonth() {
@Expose public double __getUTCMonth() {
if (utc == null) return Double.NaN;
return utc.get(Calendar.MONTH);
}
@Native
public double getUTCDate() {
@Expose public double __getUTCDate() {
if (utc == null) return Double.NaN;
return utc.get(Calendar.DAY_OF_MONTH);
}
@Native
public double getUTCDay() {
@Expose public double __getUTCDay() {
if (utc == null) return Double.NaN;
return utc.get(Calendar.DAY_OF_WEEK);
}
@Native
public double getUTCHours() {
@Expose public double __getUTCHours() {
if (utc == null) return Double.NaN;
return utc.get(Calendar.HOUR_OF_DAY);
}
@Native
public double getUTCMinutes() {
@Expose public double __getUTCMinutes() {
if (utc == null) return Double.NaN;
return utc.get(Calendar.MINUTE);
}
@Native
public double getUTCSeconds() {
@Expose public double __getUTCSeconds() {
if (utc == null) return Double.NaN;
return utc.get(Calendar.SECOND);
}
@Native
public double getUTCMilliseconds() {
@Expose public double __getUTCMilliseconds() {
if (utc == null) return Double.NaN;
return utc.get(Calendar.MILLISECOND);
}
@Native
public double setFullYear(Context ctx, double real) {
@Expose public double __setFullYear(Arguments args) {
var real = args.getDouble(0);
if (Double.isNaN(real)) invalidate();
else normal.set(Calendar.YEAR, (int)real);
updateUTC();
return getTime();
return __getTime();
}
@Native
public double setMonth(Context ctx, double real) {
@Expose public double __setMonthd(Arguments args) {
var real = args.getDouble(0);
if (Double.isNaN(real)) invalidate();
else normal.set(Calendar.MONTH, (int)real);
updateUTC();
return getTime();
return __getTime();
}
@Native
public double setDate(Context ctx, double real) {
@Expose public double __setDated(Arguments args) {
var real = args.getDouble(0);
if (Double.isNaN(real)) invalidate();
else normal.set(Calendar.DAY_OF_MONTH, (int)real);
updateUTC();
return getTime();
return __getTime();
}
@Native
public double setDay(Context ctx, double real) {
@Expose public double __setDayd(Arguments args) {
var real = args.getDouble(0);
if (Double.isNaN(real)) invalidate();
else normal.set(Calendar.DAY_OF_WEEK, (int)real);
updateUTC();
return getTime();
return __getTime();
}
@Native
public double setHours(Context ctx, double real) {
@Expose public double __setHoursd(Arguments args) {
var real = args.getDouble(0);
if (Double.isNaN(real)) invalidate();
else normal.set(Calendar.HOUR_OF_DAY, (int)real);
updateUTC();
return getTime();
return __getTime();
}
@Native
public double setMinutes(Context ctx, double real) {
@Expose public double __setMinutesd(Arguments args) {
var real = args.getDouble(0);
if (Double.isNaN(real)) invalidate();
else normal.set(Calendar.MINUTE, (int)real);
updateUTC();
return getTime();
return __getTime();
}
@Native
public double setSeconds(Context ctx, double real) {
@Expose public double __setSecondsd(Arguments args) {
var real = args.getDouble(0);
if (Double.isNaN(real)) invalidate();
else normal.set(Calendar.SECOND, (int)real);
updateUTC();
return getTime();
return __getTime();
}
@Native
public double setMilliseconds(Context ctx, double real) {
@Expose public double __setMillisecondsd(Arguments args) {
var real = args.getDouble(0);
if (Double.isNaN(real)) invalidate();
else normal.set(Calendar.MILLISECOND, (int)real);
updateUTC();
return getTime();
return __getTime();
}
@Native
public double setUTCFullYear(Context ctx, double real) {
@Expose public double __setUTCFullYeard(Arguments args) {
var real = args.getDouble(0);
if (Double.isNaN(real)) invalidate();
else utc.set(Calendar.YEAR, (int)real);
updateNormal();
return getTime();
return __getTime();
}
@Native
public double setUTCMonth(Context ctx, double real) {
@Expose public double __setUTCMonthd(Arguments args) {
var real = args.getDouble(0);
if (Double.isNaN(real)) invalidate();
else utc.set(Calendar.MONTH, (int)real);
updateNormal();
return getTime();
return __getTime();
}
@Native
public double setUTCDate(Context ctx, double real) {
@Expose public double __setUTCDated(Arguments args) {
var real = args.getDouble(0);
if (Double.isNaN(real)) invalidate();
else utc.set(Calendar.DAY_OF_MONTH, (int)real);
updateNormal();
return getTime();
return __getTime();
}
@Native
public double setUTCDay(Context ctx, double real) {
@Expose public double __setUTCDayd(Arguments args) {
var real = args.getDouble(0);
if (Double.isNaN(real)) invalidate();
else utc.set(Calendar.DAY_OF_WEEK, (int)real);
updateNormal();
return getTime();
return __getTime();
}
@Native
public double setUTCHours(Context ctx, double real) {
@Expose public double __setUTCHoursd(Arguments args) {
var real = args.getDouble(0);
if (Double.isNaN(real)) invalidate();
else utc.set(Calendar.HOUR_OF_DAY, (int)real);
updateNormal();
return getTime();
return __getTime();
}
@Native
public double setUTCMinutes(Context ctx, double real) {
@Expose public double __setUTCMinutesd(Arguments args) {
var real = args.getDouble(0);
if (Double.isNaN(real)) invalidate();
else utc.set(Calendar.MINUTE, (int)real);
updateNormal();
return getTime();
return __getTime();
}
@Native
public double setUTCSeconds(Context ctx, double real) {
@Expose public double __setUTCSecondsd(Arguments args) {
var real = args.getDouble(0);
if (Double.isNaN(real)) invalidate();
else utc.set(Calendar.SECOND, (int)real);
updateNormal();
return getTime();
return __getTime();
}
@Native
public double setUTCMilliseconds(Context ctx, double real) {
@Expose public double __setUTCMillisecondsd(Arguments args) {
var real = args.getDouble(0);
if (Double.isNaN(real)) invalidate();
else utc.set(Calendar.MILLISECOND, (int)real);
updateNormal();
return getTime();
return __getTime();
}
@Native
public double getTime() {
@Expose public double __getTime() {
if (utc == null) return Double.NaN;
return utc.getTimeInMillis();
}
@Native
public double getTimezoneOffset() {
@Expose public double __getTimezoneOffset() {
if (normal == null) return Double.NaN;
return normal.getTimeZone().getRawOffset() / 60000;
}
@Native
public double valueOf() {
@Expose public double __valueOf() {
if (normal == null) return Double.NaN;
else return normal.getTimeInMillis();
}
@Native
public String toString() {
@Expose public String __toString() {
return normal.getTime().toString();
}
@Native
public DateLib(long timestamp) {
normal = Calendar.getInstance();
utc = Calendar.getInstance();
@ -268,8 +246,17 @@ import me.topchetoeu.jscript.interop.Native;
utc.setTimeInMillis(timestamp);
}
@Native
public DateLib() {
this(new java.util.Date().getTime());
this(new Date().getTime());
}
@ExposeConstructor public static DateLib init(Arguments args) {
if (args.has(0)) return new DateLib(args.getLong(0));
else return new DateLib();
}
@Expose(target = ExposeTarget.STATIC)
public static double __now() {
return new DateLib().__getTime();
}
}

View File

@ -1,20 +1,89 @@
package me.topchetoeu.jscript.lib;
import me.topchetoeu.jscript.engine.Context;
import java.util.ArrayList;
import me.topchetoeu.jscript.Buffer;
import me.topchetoeu.jscript.engine.values.ArrayValue;
import me.topchetoeu.jscript.engine.values.Values;
import me.topchetoeu.jscript.interop.Native;
import me.topchetoeu.jscript.exceptions.EngineException;
import me.topchetoeu.jscript.interop.Arguments;
import me.topchetoeu.jscript.interop.Expose;
import me.topchetoeu.jscript.interop.ExposeTarget;
import me.topchetoeu.jscript.interop.WrapperName;
import me.topchetoeu.jscript.parsing.Parsing;
@Native("Encoding")
@WrapperName("Encoding")
public class EncodingLib {
@Native public static ArrayValue encode(String value) {
private static final String HEX = "0123456789ABCDEF";
public static String encodeUriAny(String str, String keepAlphabet) {
if (str == null) str = "undefined";
var bytes = str.getBytes();
var sb = new StringBuilder(bytes.length);
for (byte c : bytes) {
if (Parsing.isAlphanumeric((char)c) || Parsing.isAny((char)c, keepAlphabet)) sb.append((char)c);
else {
sb.append('%');
sb.append(HEX.charAt(c / 16));
sb.append(HEX.charAt(c % 16));
}
}
return sb.toString();
}
public static String decodeUriAny(String str, String keepAlphabet) {
if (str == null) str = "undefined";
var res = new Buffer();
var bytes = str.getBytes();
for (var i = 0; i < bytes.length; i++) {
var c = bytes[i];
if (c == '%') {
if (i >= bytes.length - 2) throw EngineException.ofError("URIError", "URI malformed.");
var b = Parsing.fromHex((char)bytes[i + 1]) * 16 | Parsing.fromHex((char)bytes[i + 2]);
if (!Parsing.isAny((char)b, keepAlphabet)) {
i += 2;
res.append((byte)b);
continue;
}
}
res.append(c);
}
return new String(res.data());
}
@Expose(target = ExposeTarget.STATIC)
public static ArrayValue __encode(Arguments args) {
var res = new ArrayValue();
for (var el : value.getBytes()) res.set(null, res.size(), (int)el);
for (var el : args.getString(0).getBytes()) res.set(null, res.size(), (int)el);
return res;
}
@Native public static String decode(Context ctx, ArrayValue raw) {
@Expose(target = ExposeTarget.STATIC)
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(ctx, raw.get(i));
for (var i = 0; i < raw.size(); i++) res[i] = (byte)Values.toNumber(args.ctx, raw.get(i));
return new String(res);
}
@Expose(target = ExposeTarget.STATIC)
public static String __encodeURIComponent(Arguments args) {
return EncodingLib.encodeUriAny(args.getString(0), ".-_!~*'()");
}
@Expose(target = ExposeTarget.STATIC)
public static String __decodeURIComponent(Arguments args) {
return decodeUriAny(args.getString(0), "");
}
@Expose(target = ExposeTarget.STATIC)
public static String __encodeURI(Arguments args) {
return encodeUriAny(args.getString(0), ";,/?:@&=+$#.-_!~*'()");
}
@Expose(target = ExposeTarget.STATIC)
public static String __decodeURI(Arguments args) {
return decodeUriAny(args.getString(0), ",/?:@&=+$#.");
}
}

View File

@ -3,28 +3,34 @@ package me.topchetoeu.jscript.lib;
import me.topchetoeu.jscript.engine.Environment;
import me.topchetoeu.jscript.engine.values.FunctionValue;
import me.topchetoeu.jscript.engine.values.ObjectValue;
import me.topchetoeu.jscript.interop.Native;
import me.topchetoeu.jscript.interop.NativeGetter;
import me.topchetoeu.jscript.interop.NativeSetter;
import me.topchetoeu.jscript.interop.Arguments;
import me.topchetoeu.jscript.interop.Expose;
import me.topchetoeu.jscript.interop.ExposeType;
import me.topchetoeu.jscript.interop.WrapperName;
@Native("Environment")
@WrapperName("Environment")
public class EnvironmentLib {
private Environment env;
@NativeGetter("@@env") public Environment env() { return env; }
@Expose(value = "@@env", type = ExposeType.GETTER)
public Environment __env() { return env; }
@NativeGetter public int id() {
@Expose(type = ExposeType.GETTER)
public int __id(Arguments args) {
return env.hashCode();
}
@NativeGetter public ObjectValue global() {
@Expose(type = ExposeType.GETTER)
public ObjectValue __global(Arguments args) {
return env.global.obj;
}
@NativeGetter public FunctionValue compile() {
@Expose(type = ExposeType.GETTER)
public FunctionValue __compile() {
return Environment.compileFunc(env);
}
@NativeSetter public void compile(FunctionValue func) {
env.add(Environment.COMPILE_FUNC, func);
@Expose(type = ExposeType.SETTER)
public void __compile(Arguments args) {
env.add(Environment.COMPILE_FUNC, args.convert(0, FunctionValue.class));
}
public EnvironmentLib(Environment env) {

View File

@ -1,19 +1,18 @@
package me.topchetoeu.jscript.lib;
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.ObjectValue;
import me.topchetoeu.jscript.engine.values.Symbol;
import me.topchetoeu.jscript.engine.values.Values;
import me.topchetoeu.jscript.engine.values.ObjectValue.PlaceholderProto;
import me.topchetoeu.jscript.interop.InitType;
import me.topchetoeu.jscript.interop.Native;
import me.topchetoeu.jscript.interop.NativeConstructor;
import me.topchetoeu.jscript.interop.NativeInit;
import me.topchetoeu.jscript.exceptions.ConvertException;
import me.topchetoeu.jscript.interop.WrapperName;
import me.topchetoeu.jscript.interop.Arguments;
import me.topchetoeu.jscript.interop.Expose;
import me.topchetoeu.jscript.interop.ExposeField;
@Native("Error") public class ErrorLib {
private static String toString(Context ctx, boolean rethrown, Object cause, Object name, Object message, ArrayValue stack) {
@WrapperName("Error")
public class ErrorLib {
private static String toString(Context ctx, Object name, Object message) {
if (name == null) name = "";
else name = Values.toString(ctx, name).trim();
if (message == null) message = "";
@ -24,43 +23,31 @@ import me.topchetoeu.jscript.interop.NativeInit;
if (!message.equals("") && !name.equals("")) res.append(": ");
if (!message.equals("")) res.append(message);
if (cause instanceof ObjectValue) {
if (rethrown) res.append("\n (rethrown)");
else res.append("\nCaused by ").append(toString(ctx, cause));
}
return res.toString();
}
@Native(thisArg = true) public static String toString(Context ctx, Object thisArg) {
if (thisArg instanceof ObjectValue) {
var stack = Values.getMember(ctx, thisArg, "stack");
if (!(stack instanceof ArrayValue)) stack = null;
var cause = Values.getMember(ctx, thisArg, Symbol.get("Symbol.cause"));
return toString(ctx,
thisArg == cause,
cause,
Values.getMember(ctx, thisArg, "name"),
Values.getMember(ctx, thisArg, "message"),
(ArrayValue)stack
@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")
);
}
else return "[Invalid error]";
}
@NativeConstructor(thisArg = true) public static ObjectValue constructor(Context ctx, Object thisArg, Object message) {
@Expose public static ObjectValue __constructor(Arguments args) {
var target = new ObjectValue();
if (thisArg instanceof ObjectValue) target = (ObjectValue)thisArg;
var message = args.getString(0, "");
try {
target = args.self(ObjectValue.class);
}
catch (ConvertException e) {}
target.setPrototype(PlaceholderProto.ERROR);
target.defineProperty(ctx, "stack", ArrayValue.of(ctx, ctx.stackTrace()));
if (message == null) target.defineProperty(ctx, "message", "");
else target.defineProperty(ctx, "message", Values.toString(ctx, message));
target.defineProperty(args.ctx, "message", Values.toString(args.ctx, message));
return target;
}
@NativeInit(InitType.PROTOTYPE) public static void init(Environment env, ObjectValue target) {
target.defineProperty(null, "name", "Error");
}
}

View File

@ -1,27 +1,27 @@
package me.topchetoeu.jscript.lib;
import me.topchetoeu.jscript.engine.Context;
import me.topchetoeu.jscript.engine.values.ArrayValue;
import me.topchetoeu.jscript.engine.values.Values;
import me.topchetoeu.jscript.filesystem.File;
import me.topchetoeu.jscript.filesystem.FilesystemException;
import me.topchetoeu.jscript.interop.Native;
import me.topchetoeu.jscript.interop.NativeGetter;
import me.topchetoeu.jscript.interop.Arguments;
import me.topchetoeu.jscript.interop.Expose;
import me.topchetoeu.jscript.interop.WrapperName;
@Native("File")
@WrapperName("File")
public class FileLib {
public final File file;
@NativeGetter public PromiseLib pointer(Context ctx) {
return PromiseLib.await(ctx, () -> {
@Expose public PromiseLib __pointer(Arguments args) {
return PromiseLib.await(args.ctx, () -> {
try {
return file.seek(0, 1);
}
catch (FilesystemException e) { throw e.toEngineException(); }
});
}
@NativeGetter public PromiseLib length(Context ctx) {
return PromiseLib.await(ctx, () -> {
@Expose public PromiseLib __length(Arguments args) {
return PromiseLib.await(args.ctx, () -> {
try {
long curr = file.seek(0, 1);
long res = file.seek(0, 2);
@ -32,25 +32,27 @@ public class FileLib {
});
}
@Native public PromiseLib read(Context ctx, int n) {
return PromiseLib.await(ctx, () -> {
@Expose public PromiseLib __read(Arguments args) {
return PromiseLib.await(args.ctx, () -> {
var n = args.getInt(0);
try {
var buff = new byte[n];
var res = new ArrayValue();
int resI = file.read(buff);
for (var i = resI - 1; i >= 0; i--) res.set(ctx, i, (int)buff[i]);
for (var i = resI - 1; i >= 0; i--) res.set(args.ctx, i, (int)buff[i]);
return res;
}
catch (FilesystemException e) { throw e.toEngineException(); }
});
}
@Native public PromiseLib write(Context ctx, ArrayValue val) {
return PromiseLib.await(ctx, () -> {
@Expose public PromiseLib __write(Arguments args) {
return PromiseLib.await(args.ctx, () -> {
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(ctx, val.get(i));
for (var i = 0; i < val.size(); i++) res[i] = (byte)Values.toNumber(args.ctx, val.get(i));
file.write(res);
return null;
@ -58,14 +60,17 @@ public class FileLib {
catch (FilesystemException e) { throw e.toEngineException(); }
});
}
@Native public PromiseLib close(Context ctx) {
return PromiseLib.await(ctx, () -> {
@Expose public PromiseLib __close(Arguments args) {
return PromiseLib.await(args.ctx, () -> {
file.close();
return null;
});
}
@Native public PromiseLib seek(Context ctx, long ptr, int whence) {
return PromiseLib.await(ctx, () -> {
@Expose public PromiseLib __seek(Arguments args) {
return PromiseLib.await(args.ctx, () -> {
var ptr = args.getLong(0);
var whence = args.getInt(1);
try {
return file.seek(ptr, whence);
}

View File

@ -4,7 +4,6 @@ import java.io.IOException;
import java.util.Iterator;
import java.util.Stack;
import me.topchetoeu.jscript.Filename;
import me.topchetoeu.jscript.engine.Context;
import me.topchetoeu.jscript.engine.values.ObjectValue;
import me.topchetoeu.jscript.engine.values.Values;
@ -16,13 +15,16 @@ import me.topchetoeu.jscript.filesystem.Filesystem;
import me.topchetoeu.jscript.filesystem.FilesystemException;
import me.topchetoeu.jscript.filesystem.Mode;
import me.topchetoeu.jscript.filesystem.FilesystemException.FSCode;
import me.topchetoeu.jscript.interop.Native;
import me.topchetoeu.jscript.interop.Arguments;
import me.topchetoeu.jscript.interop.Expose;
import me.topchetoeu.jscript.interop.ExposeField;
import me.topchetoeu.jscript.interop.WrapperName;
@Native("Filesystem")
@WrapperName("Filesystem")
public class FilesystemLib {
@Native public static final int SEEK_SET = 0;
@Native public static final int SEEK_CUR = 1;
@Native public static final int SEEK_END = 2;
@ExposeField public static final int __SEEK_SET = 0;
@ExposeField public static final int __SEEK_CUR = 1;
@ExposeField public static final int __SEEK_END = 2;
private static Filesystem fs(Context ctx) {
var fs = Filesystem.get(ctx);
@ -30,30 +32,30 @@ public class FilesystemLib {
throw EngineException.ofError("Current environment doesn't have a file system.");
}
@Native public static String normalize(Context ctx, String... paths) {
return fs(ctx).normalize(paths);
@Expose public static String __normalize(Arguments args) {
return fs(args.ctx).normalize(args.convert(String.class));
}
@Native public static PromiseLib open(Context ctx, String _path, String mode) {
var path = fs(ctx).normalize(_path);
var _mode = Mode.parse(mode);
@Expose public static PromiseLib __open(Arguments args) {
return PromiseLib.await(args.ctx, () -> {
var fs = fs(args.ctx);
var path = fs.normalize(args.getString(0));
var _mode = Mode.parse(args.getString(1));
return PromiseLib.await(ctx, () -> {
try {
if (fs(ctx).stat(path).type != EntryType.FILE) {
if (fs.stat(path).type != EntryType.FILE) {
throw new FilesystemException(path, FSCode.NOT_FILE);
}
var file = fs(ctx).open(path, _mode);
var file = fs.open(path, _mode);
return new FileLib(file);
}
catch (FilesystemException e) { throw e.toEngineException(); }
});
}
@Native public static ObjectValue ls(Context ctx, String _path) throws IOException {
var path = fs(ctx).normalize(_path);
@Expose public static ObjectValue __ls(Arguments args) {
return Values.toJSAsyncIterator(ctx, new Iterator<>() {
return Values.toJSAsyncIterator(args.ctx, new Iterator<>() {
private boolean failed, done;
private File file;
private String nextLine;
@ -62,11 +64,14 @@ public class FilesystemLib {
if (done) return;
if (!failed) {
if (file == null) {
if (fs(ctx).stat(path).type != EntryType.FOLDER) {
var fs = fs(args.ctx);
var path = fs.normalize(args.getString(0));
if (fs.stat(path).type != EntryType.FOLDER) {
throw new FilesystemException(path, FSCode.NOT_FOLDER);
}
file = fs(ctx).open(path, Mode.READ);
file = fs.open(path, Mode.READ);
}
if (nextLine == null) {
@ -103,29 +108,33 @@ public class FilesystemLib {
}
});
}
@Native public static PromiseLib mkdir(Context ctx, String _path) throws IOException {
return PromiseLib.await(ctx, () -> {
@Expose public static PromiseLib __mkdir(Arguments args) throws IOException {
return PromiseLib.await(args.ctx, () -> {
try {
fs(ctx).create(Filename.parse(_path).toString(), EntryType.FOLDER);
fs(args.ctx).create(args.getString(0), EntryType.FOLDER);
return null;
}
catch (FilesystemException e) { throw e.toEngineException(); }
});
}
@Native public static PromiseLib mkfile(Context ctx, String path) throws IOException {
return PromiseLib.await(ctx, () -> {
@Expose public static PromiseLib __mkfile(Arguments args) throws IOException {
return PromiseLib.await(args.ctx, () -> {
try {
fs(ctx).create(path, EntryType.FILE);
fs(args.ctx).create(args.getString(0), EntryType.FILE);
return null;
}
catch (FilesystemException e) { throw e.toEngineException(); }
});
}
@Native public static PromiseLib rm(Context ctx, String path, boolean recursive) throws IOException {
return PromiseLib.await(ctx, () -> {
@Expose public static PromiseLib __rm(Arguments args) throws IOException {
return PromiseLib.await(args.ctx, () -> {
try {
if (!recursive) fs(ctx).create(path, EntryType.NONE);
var fs = fs(args.ctx);
var path = fs.normalize(args.getString(0));
var recursive = args.getBoolean(1);
if (!recursive) fs.create(path, EntryType.NONE);
else {
var stack = new Stack<String>();
stack.push(path);
@ -134,13 +143,13 @@ public class FilesystemLib {
var currPath = stack.pop();
FileStat stat;
try { stat = fs(ctx).stat(currPath); }
try { stat = fs.stat(currPath); }
catch (FilesystemException e) { continue; }
if (stat.type == EntryType.FOLDER) {
for (var el : fs(ctx).open(currPath, Mode.READ).readToString().split("\n")) stack.push(el);
for (var el : fs.open(currPath, Mode.READ).readToString().split("\n")) stack.push(el);
}
else fs(ctx).create(currPath, EntryType.NONE);
else fs.create(currPath, EntryType.NONE);
}
}
return null;
@ -148,22 +157,24 @@ public class FilesystemLib {
catch (FilesystemException e) { throw e.toEngineException(); }
});
}
@Native public static PromiseLib stat(Context ctx, String path) throws IOException {
return PromiseLib.await(ctx, () -> {
@Expose public static PromiseLib __stat(Arguments args) throws IOException {
return PromiseLib.await(args.ctx, () -> {
try {
var stat = fs(ctx).stat(path);
var fs = fs(args.ctx);
var path = fs.normalize(args.getString(0));
var stat = fs.stat(path);
var res = new ObjectValue();
res.defineProperty(ctx, "type", stat.type.name);
res.defineProperty(ctx, "mode", stat.mode.name);
res.defineProperty(args.ctx, "type", stat.type.name);
res.defineProperty(args.ctx, "mode", stat.mode.name);
return res;
}
catch (FilesystemException e) { throw e.toEngineException(); }
});
}
@Native public static PromiseLib exists(Context ctx, String _path) throws IOException {
return PromiseLib.await(ctx, () -> {
try { fs(ctx).stat(_path); return true; }
@Expose public static PromiseLib __exists(Arguments args) throws IOException {
return PromiseLib.await(args.ctx, () -> {
try { fs(args.ctx).stat(args.getString(0)); return true; }
catch (FilesystemException e) { return false; }
});
}

View File

@ -1,54 +1,56 @@
package me.topchetoeu.jscript.lib;
import me.topchetoeu.jscript.Location;
import me.topchetoeu.jscript.engine.Context;
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.exceptions.EngineException;
import me.topchetoeu.jscript.interop.Native;
import me.topchetoeu.jscript.interop.Arguments;
import me.topchetoeu.jscript.interop.Expose;
import me.topchetoeu.jscript.interop.ExposeTarget;
import me.topchetoeu.jscript.interop.WrapperName;
@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();
@WrapperName("Function")
public class FunctionLib {
@Expose public static Object __location(Arguments args) {
if (args.self instanceof CodeFunction) return ((CodeFunction)args.self).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());
@Expose public static Object __apply(Arguments args) {
return args.self(FunctionValue.class).call(args.ctx, args.get(0), args.convert(1, ArrayValue.class).toArray());
}
@Native(thisArg = true) public static Object call(Context ctx, FunctionValue func, Object thisArg, Object... args) {
if (!(func instanceof FunctionValue)) throw EngineException.ofError("Expected this to be a function.");
return func.call(ctx, thisArg, args);
@Expose public static Object __call(Arguments args) {
return args.self(FunctionValue.class).call(args.ctx, args.get(0), args.slice(1).args);
}
@Native(thisArg = true) public static FunctionValue bind(FunctionValue func, Object thisArg, Object... args) {
if (!(func instanceof FunctionValue)) throw EngineException.ofError("Expected this to be a function.");
return new NativeFunction(func.name + " (bound)", (callCtx, _0, callArgs) -> {
@Expose public static FunctionValue __bind(Arguments args) {
var self = args.self(FunctionValue.class);
return new NativeFunction(self.name + " (bound)", callArgs -> {
Object[] resArgs;
if (args.length == 0) resArgs = callArgs;
if (args.n() == 0) resArgs = callArgs.args;
else {
resArgs = new Object[args.length + callArgs.length];
System.arraycopy(args, 0, resArgs, 0, args.length);
System.arraycopy(callArgs, 0, resArgs, args.length, callArgs.length);
resArgs = new Object[args.n() + callArgs.n()];
System.arraycopy(args.args, 0, resArgs, 0, args.n());
System.arraycopy(callArgs.args, 0, resArgs, args.n(), callArgs.n());
}
return func.call(callCtx, thisArg, resArgs);
return self.call(callArgs.ctx, self, resArgs);
});
}
@Native(thisArg = true) public static String toString(Context ctx, Object func) {
return func.toString();
@Expose public static String __toString(Arguments args) {
return args.self.toString();
}
@Native public static FunctionValue async(FunctionValue func) {
return new AsyncFunctionLib(func);
@Expose(target = ExposeTarget.STATIC)
public static FunctionValue __async(Arguments args) {
return new AsyncFunctionLib(args.convert(0, FunctionValue.class));
}
@Native public static FunctionValue asyncGenerator(FunctionValue func) {
return new AsyncGeneratorFunctionLib(func);
@Expose(target = ExposeTarget.STATIC)
public static FunctionValue __asyncGenerator(Arguments args) {
return new AsyncGeneratorFunctionLib(args.convert(0, FunctionValue.class));
}
@Native public static FunctionValue generator(FunctionValue func) {
return new GeneratorFunctionLib(func);
@Expose(target = ExposeTarget.STATIC)
public static FunctionValue __generator(Arguments args) {
return new GeneratorFunctionLib(args.convert(0, FunctionValue.class));
}
}

View File

@ -6,13 +6,13 @@ 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;
import me.topchetoeu.jscript.interop.WrapperName;
@Native("GeneratorFunction") public class GeneratorFunctionLib extends FunctionValue {
@WrapperName("GeneratorFunction")
public class GeneratorFunctionLib extends FunctionValue {
public final FunctionValue factory;
@Override
public Object call(Context ctx, Object thisArg, Object ...args) {
@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.");

View File

@ -5,18 +5,19 @@ import me.topchetoeu.jscript.engine.frame.CodeFrame;
import me.topchetoeu.jscript.engine.frame.Runners;
import me.topchetoeu.jscript.engine.values.ObjectValue;
import me.topchetoeu.jscript.exceptions.EngineException;
import me.topchetoeu.jscript.interop.Native;
import me.topchetoeu.jscript.interop.Arguments;
import me.topchetoeu.jscript.interop.Expose;
import me.topchetoeu.jscript.interop.WrapperName;
@Native("Generator") public class GeneratorLib {
@WrapperName("Generator")
public class GeneratorLib {
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) {
private ObjectValue next(Context ctx, Object inducedValue, Object inducedReturn, EngineException inducedError) {
if (done) {
if (inducedError != Runners.NO_RETURN) throw new EngineException(inducedError);
if (inducedError != Runners.NO_RETURN) throw inducedError;
var res = new ObjectValue();
res.defineProperty(ctx, "done", true);
res.defineProperty(ctx, "value", inducedReturn == Runners.NO_RETURN ? null : inducedReturn);
@ -29,8 +30,9 @@ import me.topchetoeu.jscript.interop.Native;
frame.onPush();
while (!yielding) {
try {
res = frame.next(inducedValue, inducedReturn, inducedError == Runners.NO_RETURN ? null : new EngineException(inducedError));
inducedReturn = inducedError = Runners.NO_RETURN;
res = frame.next(inducedValue, inducedReturn, inducedError);
inducedReturn = Runners.NO_RETURN;
inducedError = null;
if (res != Runners.NO_RETURN) {
done = true;
break;
@ -52,29 +54,25 @@ import me.topchetoeu.jscript.interop.Native;
return obj;
}
@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);
@Expose public ObjectValue __next(Arguments args) {
if (args.n() == 0) return next(args.ctx, Runners.NO_RETURN, Runners.NO_RETURN, null);
else return next(args.ctx, args.get(0), Runners.NO_RETURN, null);
}
@Native("throw")
public ObjectValue _throw(Context ctx, Object error) {
return next(ctx, Runners.NO_RETURN, Runners.NO_RETURN, error);
@Expose public ObjectValue __throw(Arguments args) {
return next(args.ctx, Runners.NO_RETURN, Runners.NO_RETURN, new EngineException(args.get(0)).setCtx(args.ctx));
}
@Native("return")
public ObjectValue _return(Context ctx, Object value) {
return next(ctx, Runners.NO_RETURN, value, Runners.NO_RETURN);
@Expose public ObjectValue __return(Arguments args) {
return next(args.ctx, Runners.NO_RETURN, args.get(0), null);
}
@Override
public String toString() {
@Override public String toString() {
if (done) return "Generator [closed]";
if (yielding) return "Generator [suspended]";
return "Generator [running]";
}
public Object yield(Context ctx, Object thisArg, Object[] args) {
public Object yield(Arguments args) {
this.yielding = true;
return args.length > 0 ? args[0] : null;
return args.get(0);
}
}

View File

@ -1,44 +1,50 @@
package me.topchetoeu.jscript.lib;
import java.io.IOException;
import java.util.HashMap;
import me.topchetoeu.jscript.Buffer;
import me.topchetoeu.jscript.Reading;
import me.topchetoeu.jscript.engine.Context;
import me.topchetoeu.jscript.engine.Environment;
import me.topchetoeu.jscript.engine.scope.GlobalScope;
import me.topchetoeu.jscript.engine.values.FunctionValue;
import me.topchetoeu.jscript.engine.values.Symbol;
import me.topchetoeu.jscript.engine.values.Values;
import me.topchetoeu.jscript.exceptions.EngineException;
import me.topchetoeu.jscript.interop.Native;
import me.topchetoeu.jscript.interop.NativeGetter;
import me.topchetoeu.jscript.interop.Arguments;
import me.topchetoeu.jscript.interop.Expose;
import me.topchetoeu.jscript.interop.ExposeField;
import me.topchetoeu.jscript.interop.ExposeTarget;
import me.topchetoeu.jscript.modules.ModuleRepo;
import me.topchetoeu.jscript.parsing.Parsing;
public class Internals {
@Native public static Object require(Context ctx, String name) {
var repo = ModuleRepo.get(ctx);
private static final Symbol THREADS = new Symbol("Internals.threads");
private static final Symbol I = new Symbol("Internals.i");
@Expose(target = ExposeTarget.STATIC)
public static Object __require(Arguments args) {
var repo = ModuleRepo.get(args.ctx);
if (repo != null) {
var res = repo.getModule(ctx, ModuleRepo.cwd(ctx), name);
res.load(ctx);
var res = repo.getModule(args.ctx, ModuleRepo.cwd(args.ctx), args.getString(0));
res.load(args.ctx);
return res.value();
}
else throw EngineException.ofError("Modules are not supported.");
}
@Native public static Object log(Context ctx, Object ...args) {
for (var arg : args) {
Values.printValue(ctx, arg);
@Expose(target = ExposeTarget.STATIC)
public static Object __log(Arguments args) {
for (var arg : args.args) {
Values.printValue(args.ctx, arg);
System.out.print(" ");
}
System.out.println();
if (args.length == 0) return null;
else return args[0];
return args.get(0);
}
@Native public static String readline(Context ctx) {
@Expose(target = ExposeTarget.STATIC)
public static String __readline() {
try {
return Reading.readline();
}
@ -48,23 +54,35 @@ public class Internals {
}
}
@Native public static Thread setTimeout(Context ctx, FunctionValue func, int delay, Object ...args) {
@Expose(target = ExposeTarget.STATIC)
public static Thread __setTimeout(Arguments args) {
var func = args.convert(0, FunctionValue.class);
var delay = args.getDouble(1);
var arguments = args.slice(2).args;
var thread = new Thread(() -> {
var ms = (long)delay;
var ns = (int)((delay - ms) * 10000000);
try {
Thread.sleep(ms, ns);
}
try { Thread.sleep(ms, ns); }
catch (InterruptedException e) { return; }
ctx.engine.pushMsg(false, ctx.environment, func, null, args);
args.ctx.engine.pushMsg(false, args.ctx.environment, func, null, arguments);
});
thread.start();
var i = args.ctx.init(I, 1);
args.ctx.add(I, i + 1);
args.ctx.init(THREADS, new HashMap<Integer, Thread>()).put(i, thread);
return thread;
}
@Native public static Thread setInterval(Context ctx, FunctionValue func, int delay, Object ...args) {
@Expose(target = ExposeTarget.STATIC)
public static Thread __setInterval(Arguments args) {
var func = args.convert(0, FunctionValue.class);
var delay = args.getDouble(1);
var arguments = args.slice(2).args;
var thread = new Thread(() -> {
var ms = (long)delay;
var ns = (int)((delay - ms) * 10000000);
@ -75,96 +93,76 @@ public class Internals {
}
catch (InterruptedException e) { return; }
ctx.engine.pushMsg(false, ctx.environment, func, null, args);
args.ctx.engine.pushMsg(false, args.ctx.environment, func, null, arguments);
}
});
thread.start();
var i = args.ctx.init(I, 1);
args.ctx.add(I, i + 1);
args.ctx.init(THREADS, new HashMap<Integer, Thread>()).put(i, thread);
return thread;
}
@Native public static void clearTimeout(Context ctx, Thread t) {
t.interrupt();
@Expose(target = ExposeTarget.STATIC)
public static void __clearTimeout(Arguments args) {
var i = args.getInt(0);
HashMap<Integer, Thread> map = args.ctx.get(THREADS);
if (map == null) return;
var thread = map.get(i);
if (thread == null) return;
thread.interrupt();
map.remove(i);
}
@Native public static void clearInterval(Context ctx, Thread t) {
t.interrupt();
@Expose(target = ExposeTarget.STATIC)
public static void __clearInterval(Arguments args) {
__clearTimeout(args);
}
@Native public static double parseInt(Context ctx, String val) {
return NumberLib.parseInt(ctx, val);
@Expose(target = ExposeTarget.STATIC)
public static double __parseInt(Arguments args) {
return NumberLib.__parseInt(args);
}
@Native public static double parseFloat(Context ctx, String val) {
return NumberLib.parseFloat(ctx, val);
@Expose(target = ExposeTarget.STATIC)
public static double __parseFloat(Arguments args) {
return NumberLib.__parseFloat(args);
}
@Native public static boolean isNaN(Context ctx, double val) {
return NumberLib.isNaN(ctx, val);
@Expose(target = ExposeTarget.STATIC)
public static boolean __isNaN(Arguments args) {
return NumberLib.__isNaN(args);
}
@Native public static boolean isFinite(Context ctx, double val) {
return NumberLib.isFinite(ctx, val);
@Expose(target = ExposeTarget.STATIC)
public static boolean __isFinite(Arguments args) {
return NumberLib.__isFinite(args);
}
@Native public static boolean isInfinite(Context ctx, double val) {
return NumberLib.isInfinite(ctx, val);
@Expose(target = ExposeTarget.STATIC)
public static boolean __isInfinite(Arguments args) {
return NumberLib.__isInfinite(args);
}
@NativeGetter public static double NaN(Context ctx) {
return Double.NaN;
}
@NativeGetter public static double Infinity(Context ctx) {
return Double.POSITIVE_INFINITY;
}
private static final String HEX = "0123456789ABCDEF";
@ExposeField(target = ExposeTarget.STATIC)
public static double __NaN = Double.NaN;
@ExposeField(target = ExposeTarget.STATIC)
public static double __Infinity = Double.POSITIVE_INFINITY;
private static String encodeUriAny(String str, String keepAlphabet) {
if (str == null) str = "undefined";
var bytes = str.getBytes();
var sb = new StringBuilder(bytes.length);
for (byte c : bytes) {
if (Parsing.isAlphanumeric((char)c) || Parsing.isAny((char)c, keepAlphabet)) sb.append((char)c);
else {
sb.append('%');
sb.append(HEX.charAt(c / 16));
sb.append(HEX.charAt(c % 16));
@Expose(target = ExposeTarget.STATIC)
public static String __encodeURIComponent(Arguments args) {
return EncodingLib.__encodeURIComponent(args);
}
@Expose(target = ExposeTarget.STATIC)
public static String __decodeURIComponent(Arguments args) {
return EncodingLib.__decodeURIComponent(args);
}
return sb.toString();
@Expose(target = ExposeTarget.STATIC)
public static String __encodeURI(Arguments args) {
return EncodingLib.__encodeURI(args);
}
private static String decodeUriAny(String str, String keepAlphabet) {
if (str == null) str = "undefined";
var res = new Buffer();
var bytes = str.getBytes();
for (var i = 0; i < bytes.length; i++) {
var c = bytes[i];
if (c == '%') {
if (i >= bytes.length - 2) throw EngineException.ofError("URIError", "URI malformed.");
var b = Parsing.fromHex((char)bytes[i + 1]) * 16 | Parsing.fromHex((char)bytes[i + 2]);
if (!Parsing.isAny((char)b, keepAlphabet)) {
i += 2;
res.append((byte)b);
continue;
}
}
res.append(c);
}
return new String(res.data());
}
@Native public static String encodeURIComponent(String str) {
return encodeUriAny(str, ".-_!~*'()");
}
@Native public static String decodeURIComponent(String str) {
return decodeUriAny(str, "");
}
@Native public static String encodeURI(String str) {
return encodeUriAny(str, ";,/?:@&=+$#.-_!~*'()");
}
@Native public static String decodeURI(String str) {
return decodeUriAny(str, ",/?:@&=+$#.");
@Expose(target = ExposeTarget.STATIC)
public static String __decodeURI(Arguments args) {
return EncodingLib.__decodeURI(args);
}
public static Environment apply(Environment env) {

View File

@ -1,21 +1,24 @@
package me.topchetoeu.jscript.lib;
import me.topchetoeu.jscript.engine.Context;
import me.topchetoeu.jscript.exceptions.EngineException;
import me.topchetoeu.jscript.exceptions.SyntaxException;
import me.topchetoeu.jscript.interop.Native;
import me.topchetoeu.jscript.interop.Arguments;
import me.topchetoeu.jscript.interop.Expose;
import me.topchetoeu.jscript.interop.ExposeTarget;
import me.topchetoeu.jscript.interop.WrapperName;
import me.topchetoeu.jscript.json.JSON;
@Native("JSON") public class JSONLib {
@Native
public static Object parse(Context ctx, String val) {
@WrapperName("JSON")
public class JSONLib {
@Expose(target = ExposeTarget.STATIC)
public static Object __parse(Arguments args) {
try {
return JSON.toJs(JSON.parse(null, val));
return JSON.toJs(JSON.parse(null, args.getString(0)));
}
catch (SyntaxException e) { throw EngineException.ofSyntax(e.msg); }
}
@Native
public static String stringify(Context ctx, Object val) {
return me.topchetoeu.jscript.json.JSON.stringify(JSON.fromJs(ctx, val));
@Expose(target = ExposeTarget.STATIC)
public static String __stringify(Arguments args) {
return me.topchetoeu.jscript.json.JSON.stringify(JSON.fromJs(args.ctx, args.get(0)));
}
}

View File

@ -9,21 +9,26 @@ import me.topchetoeu.jscript.engine.values.ArrayValue;
import me.topchetoeu.jscript.engine.values.FunctionValue;
import me.topchetoeu.jscript.engine.values.ObjectValue;
import me.topchetoeu.jscript.engine.values.Values;
import me.topchetoeu.jscript.interop.Native;
import me.topchetoeu.jscript.interop.NativeGetter;
import me.topchetoeu.jscript.interop.Arguments;
import me.topchetoeu.jscript.interop.Expose;
import me.topchetoeu.jscript.interop.ExposeConstructor;
import me.topchetoeu.jscript.interop.ExposeType;
import me.topchetoeu.jscript.interop.WrapperName;
@Native("Map") public class MapLib {
@WrapperName("Map")
public class MapLib {
private LinkedHashMap<Object, Object> map = new LinkedHashMap<>();
@Native("@@Symbol.typeName") public final String name = "Map";
@Native("@@Symbol.iterator") public ObjectValue iterator(Context ctx) {
return this.entries(ctx);
@Expose("@@Symbol.iterator")
public ObjectValue __iterator(Arguments args) {
return this.__entries(args);
}
@Native public void clear() {
@Expose public void __clear() {
map.clear();
}
@Native public boolean delete(Object key) {
@Expose public boolean __delete(Arguments args) {
var key = args.get(0);
if (map.containsKey(key)) {
map.remove(key);
return true;
@ -31,48 +36,56 @@ import me.topchetoeu.jscript.interop.NativeGetter;
return false;
}
@Native public ObjectValue entries(Context ctx) {
return ArrayValue.of(ctx, map
@Expose public ObjectValue __entries(Arguments args) {
return ArrayValue.of(args.ctx, map
.entrySet()
.stream()
.map(v -> new ArrayValue(ctx, v.getKey(), v.getValue()))
.map(v -> new ArrayValue(args.ctx, v.getKey(), v.getValue()))
.collect(Collectors.toList())
);
}
@Native public ObjectValue keys(Context ctx) {
return ArrayValue.of(ctx, map.keySet());
@Expose public ObjectValue __keys(Arguments args) {
return ArrayValue.of(args.ctx, map.keySet());
}
@Native public ObjectValue values(Context ctx) {
return ArrayValue.of(ctx, map.values());
@Expose public ObjectValue __values(Arguments args) {
return ArrayValue.of(args.ctx, map.values());
}
@Native public Object get(Object key) {
return map.get(key);
@Expose public Object __get(Arguments args) {
return map.get(args.get(0));
}
@Native public MapLib set(Object key, Object val) {
map.put(key, val);
@Expose public MapLib __set(Arguments args) {
map.put(args.get(0), args.get(1));
return this;
}
@Native public boolean has(Object key) {
return map.containsKey(key);
@Expose public boolean __has(Arguments args) {
return map.containsKey(args.get(0));
}
@NativeGetter public int size() {
@Expose(type = ExposeType.GETTER)
public int __size() {
return map.size();
}
@Native public void forEach(Context ctx, FunctionValue func, Object thisArg) {
@Expose public void __forEach(Arguments args) {
var func = args.convert(0, FunctionValue.class);
var thisArg = args.get(1);
var keys = new ArrayList<>(map.keySet());
for (var el : keys) func.call(ctx, thisArg, map.get(el), el,this);
for (var el : keys) func.call(args.ctx, thisArg, map.get(el), el,this);
}
@Native public MapLib(Context ctx, Object iterable) {
public MapLib(Context ctx, Object iterable) {
for (var el : Values.fromJSIterator(ctx, iterable)) {
try {
set(Values.getMember(ctx, el, 0), Values.getMember(ctx, el, 1));
map.put(Values.getMember(ctx, el, 0), Values.getMember(ctx, el, 1));
}
catch (IllegalArgumentException e) { }
}
}
@ExposeConstructor public static MapLib __constructor(Arguments args) {
return new MapLib(args.ctx, args.get(0));
}
}

View File

@ -1,21 +1,47 @@
package me.topchetoeu.jscript.lib;
import me.topchetoeu.jscript.interop.Native;
import me.topchetoeu.jscript.interop.Arguments;
import me.topchetoeu.jscript.interop.Expose;
import me.topchetoeu.jscript.interop.ExposeField;
import me.topchetoeu.jscript.interop.ExposeTarget;
import me.topchetoeu.jscript.interop.WrapperName;
@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);
@Native public static final double SQRT1_2 = Math.sqrt(.5);
@Native public static final double LN2 = Math.log(2);
@Native public static final double LN10 = Math.log(10);
@Native public static final double LOG2E = Math.log(Math.E) / LN2;
@Native public static final double LOG10E = Math.log10(Math.E);
@WrapperName("Math")
public class MathLib {
@ExposeField(target = ExposeTarget.STATIC)
public static final double __E = Math.E;
@ExposeField(target = ExposeTarget.STATIC)
public static final double __PI = Math.PI;
@ExposeField(target = ExposeTarget.STATIC)
public static final double __SQRT2 = Math.sqrt(2);
@ExposeField(target = ExposeTarget.STATIC)
public static final double __SQRT1_2 = Math.sqrt(.5);
@ExposeField(target = ExposeTarget.STATIC)
public static final double __LN2 = Math.log(2);
@ExposeField(target = ExposeTarget.STATIC)
public static final double __LN10 = Math.log(10);
@ExposeField(target = ExposeTarget.STATIC)
public static final double __LOG2E = Math.log(Math.E) / __LN2;
@ExposeField(target = ExposeTarget.STATIC)
public static final double __LOG10E = Math.log10(Math.E);
@Expose(target = ExposeTarget.STATIC)
public static double __asin(Arguments args) {
return Math.asin(args.getDouble(0));
}
@Expose(target = ExposeTarget.STATIC)
public static double __acos(Arguments args) {
return Math.acos(args.getDouble(0));
}
@Expose(target = ExposeTarget.STATIC)
public static double __atan(Arguments args) {
return Math.atan(args.getDouble(0));
}
@Expose(target = ExposeTarget.STATIC)
public static double __atan2(Arguments args) {
var x = args.getDouble(1);
var y = args.getDouble(0);
@Native public static double asin(double x) { return Math.asin(x); }
@Native public static double acos(double x) { return Math.acos(x); }
@Native public static double atan(double x) { return Math.atan(x); }
@Native public static double atan2(double y, double x) {
if (x == 0) {
if (y == 0) return Double.NaN;
return Math.signum(y) * Math.PI / 2;
@ -29,71 +55,157 @@ import me.topchetoeu.jscript.interop.Native;
}
@Native public static double asinh(double x) { return Math.log(x + Math.sqrt(x * x + 1)); }
@Native public static double acosh(double x) { return Math.log(x + Math.sqrt(x * x - 1)); }
@Native public static double atanh(double x) {
@Expose(target = ExposeTarget.STATIC)
public static double __asinh(Arguments args) {
var x = args.getDouble(0);
return Math.log(x + Math.sqrt(x * x + 1));
}
@Expose(target = ExposeTarget.STATIC)
public static double __acosh(Arguments args) {
var x = args.getDouble(0);
return Math.log(x + Math.sqrt(x * x - 1));
}
@Expose(target = ExposeTarget.STATIC)
public static double __atanh(Arguments args) {
var x = args.getDouble(0);
if (x <= -1 || x >= 1) return Double.NaN;
return .5 * Math.log((1 + x) / (1 - x));
}
@Native public static double sin(double x) { return Math.sin(x); }
@Native public static double cos(double x) { return Math.cos(x); }
@Native public static double tan(double x) { return Math.tan(x); }
@Expose(target = ExposeTarget.STATIC)
public static double __sin(Arguments args) {
return Math.sin(args.getDouble(0));
}
@Expose(target = ExposeTarget.STATIC)
public static double __cos(Arguments args) {
return Math.cos(args.getDouble(0));
}
@Expose(target = ExposeTarget.STATIC)
public static double __tan(Arguments args) {
return Math.tan(args.getDouble(0));
}
@Native public static double sinh(double x) { return Math.sinh(x); }
@Native public static double cosh(double x) { return Math.cosh(x); }
@Native public static double tanh(double x) { return Math.tanh(x); }
@Expose(target = ExposeTarget.STATIC)
public static double __sinh(Arguments args) {
return Math.sinh(args.getDouble(0));
}
@Expose(target = ExposeTarget.STATIC)
public static double __cosh(Arguments args) {
return Math.cosh(args.getDouble(0));
}
@Expose(target = ExposeTarget.STATIC)
public static double __tanh(Arguments args) {
return Math.tanh(args.getDouble(0));
}
@Native public static double sqrt(double x) { return Math.sqrt(x); }
@Native public static double cbrt(double x) { return Math.cbrt(x); }
@Expose(target = ExposeTarget.STATIC)
public static double __sqrt(Arguments args) {
return Math.sqrt(args.getDouble(0));
}
@Expose(target = ExposeTarget.STATIC)
public static double __cbrt(Arguments args) {
return Math.cbrt(args.getDouble(0));
}
@Native public static double hypot(double ...vals) {
@Expose(target = ExposeTarget.STATIC)
public static double __hypot(Arguments args) {
var res = 0.;
for (var el : vals) {
var val = el;
for (var i = 0; i < args.n(); i++) {
var val = args.getDouble(i);
res += val * val;
}
return Math.sqrt(res);
}
@Native public static int imul(double a, double b) { return (int)a * (int)b; }
@Expose(target = ExposeTarget.STATIC)
public static int __imul(Arguments args) { return args.getInt(0) * args.getInt(1); }
@Native public static double exp(double x) { return Math.exp(x); }
@Native public static double expm1(double x) { return Math.expm1(x); }
@Native public static double pow(double x, double y) { return Math.pow(x, y); }
@Expose(target = ExposeTarget.STATIC)
public static double __exp(Arguments args) {
return Math.exp(args.getDouble(0));
}
@Expose(target = ExposeTarget.STATIC)
public static double __expm1(Arguments args) {
return Math.expm1(args.getDouble(0));
}
@Expose(target = ExposeTarget.STATIC)
public static double __pow(Arguments args) { return Math.pow(args.getDouble(0), args.getDouble(1)); }
@Native public static double log(double x) { return Math.log(x); }
@Native public static double log10(double x) { return Math.log10(x); }
@Native public static double log1p(double x) { return Math.log1p(x); }
@Native public static double log2(double x) { return Math.log(x) / LN2; }
@Expose(target = ExposeTarget.STATIC)
public static double __log(Arguments args) {
return Math.log(args.getDouble(0));
}
@Expose(target = ExposeTarget.STATIC)
public static double __log10(Arguments args) {
return Math.log10(args.getDouble(0));
}
@Expose(target = ExposeTarget.STATIC)
public static double __log1p(Arguments args) {
return Math.log1p(args.getDouble(0));
}
@Expose(target = ExposeTarget.STATIC)
public static double __log2(Arguments args) {
return Math.log(args.getDouble(0)) / __LN2;
}
@Native public static double ceil(double x) { return Math.ceil(x); }
@Native public static double floor(double x) { return Math.floor(x); }
@Native public static double round(double x) { return Math.round(x); }
@Native public static float fround(double x) { return (float)x; }
@Native public static double trunc(double x) { return Math.floor(Math.abs(x)) * Math.signum(x); }
@Native public static double abs(double x) { return Math.abs(x); }
@Expose(target = ExposeTarget.STATIC)
public static double __ceil(Arguments args) {
return Math.ceil(args.getDouble(0));
}
@Expose(target = ExposeTarget.STATIC)
public static double __floor(Arguments args) {
return Math.floor(args.getDouble(0));
}
@Expose(target = ExposeTarget.STATIC)
public static double __round(Arguments args) {
return Math.round(args.getDouble(0));
}
@Expose(target = ExposeTarget.STATIC)
public static float __fround(Arguments args) {
return (float)args.getDouble(0);
}
@Expose(target = ExposeTarget.STATIC)
public static double __trunc(Arguments args) {
var x = args.getDouble(0);
return Math.floor(Math.abs(x)) * Math.signum(x);
}
@Expose(target = ExposeTarget.STATIC)
public static double __abs(Arguments args) {
return Math.abs(args.getDouble(0));
}
@Native public static double max(double ...vals) {
@Expose(target = ExposeTarget.STATIC)
public static double __max(Arguments args) {
var res = Double.NEGATIVE_INFINITY;
for (var el : vals) {
for (var i = 0; i < args.n(); i++) {
var el = args.getDouble(i);
if (el > res) res = el;
}
return res;
}
@Native public static double min(double ...vals) {
@Expose(target = ExposeTarget.STATIC)
public static double __min(Arguments args) {
var res = Double.POSITIVE_INFINITY;
for (var el : vals) {
for (var i = 0; i < args.n(); i++) {
var el = args.getDouble(i);
if (el < res) res = el;
}
return res;
}
@Native public static double sign(double x) { return Math.signum(x); }
@Native public static double random() { return Math.random(); }
@Native public static int clz32(double x) { return Integer.numberOfLeadingZeros((int)x); }
@Expose(target = ExposeTarget.STATIC)
public static double __sign(Arguments args) {
return Math.signum(args.getDouble(0));
}
@Expose(target = ExposeTarget.STATIC)
public static double __random() { return Math.random(); }
@Expose(target = ExposeTarget.STATIC)
public static int __clz32(Arguments args) {
return Integer.numberOfLeadingZeros(args.getInt(0));
}
}

View File

@ -1,49 +1,66 @@
package me.topchetoeu.jscript.lib;
import me.topchetoeu.jscript.engine.Context;
import me.topchetoeu.jscript.engine.values.ObjectValue;
import me.topchetoeu.jscript.engine.values.Values;
import me.topchetoeu.jscript.interop.Native;
import me.topchetoeu.jscript.interop.NativeConstructor;
import me.topchetoeu.jscript.interop.Arguments;
import me.topchetoeu.jscript.interop.Expose;
import me.topchetoeu.jscript.interop.ExposeConstructor;
import me.topchetoeu.jscript.interop.ExposeField;
import me.topchetoeu.jscript.interop.ExposeTarget;
import me.topchetoeu.jscript.interop.WrapperName;
@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;
@WrapperName("Number")
public class NumberLib {
@ExposeField(target = ExposeTarget.STATIC)
public static final double __EPSILON = Math.ulp(1.0);
@ExposeField(target = ExposeTarget.STATIC)
public static final double __MAX_SAFE_INTEGER = 9007199254740991.;
@ExposeField(target = ExposeTarget.STATIC)
public static final double __MIN_SAFE_INTEGER = -__MAX_SAFE_INTEGER;
// lmao big number go brrr
@Native public static final double MAX_VALUE = 179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168738177180919299881250404026184124858368.;
@Native public static final double MIN_VALUE = -MAX_VALUE;
@Native public static final double NaN = 0. / 0;
@Native public static final double NEGATIVE_INFINITY = -1. / 0;
@Native public static final double POSITIVE_INFINITY = 1. / 0;
@ExposeField(target = ExposeTarget.STATIC)
public static final double __MAX_VALUE = 179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168738177180919299881250404026184124858368.;
@ExposeField(target = ExposeTarget.STATIC)
public static final double __MIN_VALUE = -__MAX_VALUE;
@ExposeField(target = ExposeTarget.STATIC)
public static final double __NaN = 0. / 0;
@ExposeField(target = ExposeTarget.STATIC)
public static final double __NEGATIVE_INFINITY = -1. / 0;
@ExposeField(target = ExposeTarget.STATIC)
public static final double __POSITIVE_INFINITY = 1. / 0;
public final double value;
@Native public static boolean isFinite(Context ctx, double val) { return Double.isFinite(val); }
@Native public static boolean isInfinite(Context ctx, double val) { return Double.isInfinite(val); }
@Native public static boolean isNaN(Context ctx, double val) { return Double.isNaN(val); }
@Native public static boolean isSafeInteger(Context ctx, double val) {
return val > MIN_SAFE_INTEGER && val < MAX_SAFE_INTEGER;
@Expose(target = ExposeTarget.STATIC)
public static boolean __isFinite(Arguments args) { return Double.isFinite(args.getDouble(0)); }
@Expose(target = ExposeTarget.STATIC)
public static boolean __isInfinite(Arguments args) { return Double.isInfinite(args.getDouble(0)); }
@Expose(target = ExposeTarget.STATIC)
public static boolean __isNaN(Arguments args) { return Double.isNaN(args.getDouble(0)); }
@Expose(target = ExposeTarget.STATIC)
public static boolean __isSafeInteger(Arguments args) {
return args.getDouble(0) > __MIN_SAFE_INTEGER && args.getDouble(0) < __MAX_SAFE_INTEGER;
}
@Native public static double parseFloat(Context ctx, String val) {
return Values.toNumber(ctx, val);
@Expose(target = ExposeTarget.STATIC)
public static double __parseFloat(Arguments args) {
return args.getDouble(0);
}
@Native public static double parseInt(Context ctx, String val) {
return (long)Values.toNumber(ctx, val);
@Expose(target = ExposeTarget.STATIC)
public static double __parseInt(Arguments args) {
return args.getLong(0);
}
@NativeConstructor(thisArg = true) public static Object constructor(Context ctx, Object thisArg, Object val) {
val = Values.toNumber(ctx, val);
if (thisArg instanceof ObjectValue) return new NumberLib((double)val);
else return val;
@ExposeConstructor public static Object __constructor(Arguments args) {
if (args.self instanceof ObjectValue) return new NumberLib(args.getDouble(0));
else return args.getDouble(0);
}
@Native(thisArg = true) public static String toString(Context ctx, Object thisArg) {
return Values.toString(ctx, Values.toNumber(ctx, thisArg));
@Expose public static String __toString(Arguments args) {
return Values.toString(args.ctx, args.getDouble(0));
}
@Native(thisArg = true) public static double valueOf(Context ctx, Object thisArg) {
if (thisArg instanceof NumberLib) return ((NumberLib)thisArg).value;
else return Values.toNumber(ctx, thisArg);
@Expose public static double __valueOf(Arguments args) {
if (args.self instanceof NumberLib) return args.self(NumberLib.class).value;
else return Values.toNumber(args.ctx, args.self);
}
public NumberLib(double val) {

View File

@ -1,171 +1,219 @@
package me.topchetoeu.jscript.lib;
import me.topchetoeu.jscript.engine.Context;
import me.topchetoeu.jscript.engine.values.ArrayValue;
import me.topchetoeu.jscript.engine.values.FunctionValue;
import me.topchetoeu.jscript.engine.values.ObjectValue;
import me.topchetoeu.jscript.engine.values.Symbol;
import me.topchetoeu.jscript.engine.values.Values;
import me.topchetoeu.jscript.exceptions.EngineException;
import me.topchetoeu.jscript.interop.Native;
import me.topchetoeu.jscript.interop.NativeConstructor;
import me.topchetoeu.jscript.interop.Arguments;
import me.topchetoeu.jscript.interop.Expose;
import me.topchetoeu.jscript.interop.ExposeConstructor;
import me.topchetoeu.jscript.interop.ExposeTarget;
import me.topchetoeu.jscript.interop.WrapperName;
@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)) {
Values.setMember(ctx, dst, key, Values.getMember(ctx, obj, key));
@WrapperName("Object")
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));
}
}
return dst;
return args.get(0);
}
@Native public static ObjectValue create(Context ctx, ObjectValue proto, ObjectValue props) {
@Expose(target = ExposeTarget.STATIC)
public static ObjectValue __create(Arguments args) {
var obj = new ObjectValue();
obj.setPrototype(ctx, proto);
return defineProperties(ctx, obj, props);
obj.setPrototype(args.ctx, 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));
}
@Native public static ObjectValue defineProperty(Context ctx, ObjectValue obj, Object key, ObjectValue attrib) {
var hasVal = attrib.hasMember(ctx, "value", false);
var hasGet = attrib.hasMember(ctx, "get", false);
var hasSet = attrib.hasMember(ctx, "set", false);
return obj;
}
@Expose(target = ExposeTarget.STATIC)
public static ObjectValue __defineProperty(Arguments args) {
var obj = args.convert(0, ObjectValue.class);
var key = args.get(1);
var attrib = args.convert(2, ObjectValue.class);
var hasVal = attrib.hasMember(args.ctx, "value", false);
var hasGet = attrib.hasMember(args.ctx, "get", false);
var hasSet = attrib.hasMember(args.ctx, "set", false);
if (hasVal) {
if (hasGet || hasSet) throw EngineException.ofType("Cannot specify a value and accessors for a property.");
if (!obj.defineProperty(
ctx, key,
attrib.getMember(ctx, "value"),
Values.toBoolean(attrib.getMember(ctx, "writable")),
Values.toBoolean(attrib.getMember(ctx, "configurable")),
Values.toBoolean(attrib.getMember(ctx, "enumerable"))
args.ctx, key,
attrib.getMember(args.ctx, "value"),
Values.toBoolean(attrib.getMember(args.ctx, "writable")),
Values.toBoolean(attrib.getMember(args.ctx, "configurable")),
Values.toBoolean(attrib.getMember(args.ctx, "enumerable"))
)) throw EngineException.ofType("Can't define property '" + key + "'.");
}
else {
var get = attrib.getMember(ctx, "get");
var set = attrib.getMember(ctx, "set");
var get = attrib.getMember(args.ctx, "get");
var set = attrib.getMember(args.ctx, "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(
ctx, key,
args.ctx, key,
(FunctionValue)get, (FunctionValue)set,
Values.toBoolean(attrib.getMember(ctx, "configurable")),
Values.toBoolean(attrib.getMember(ctx, "enumerable"))
Values.toBoolean(attrib.getMember(args.ctx, "configurable")),
Values.toBoolean(attrib.getMember(args.ctx, "enumerable"))
)) throw EngineException.ofType("Can't define property '" + key + "'.");
}
return obj;
}
@Native public static ObjectValue defineProperties(Context ctx, ObjectValue obj, ObjectValue attrib) {
@Expose(target = ExposeTarget.STATIC)
public static ObjectValue __defineProperties(Arguments args) {
var obj = args.convert(0, ObjectValue.class);
var attrib = args.convert(1, ObjectValue.class);
for (var key : Values.getMembers(null, obj, false, false)) {
obj.defineProperty(ctx, key, attrib.getMember(ctx, key));
obj.defineProperty(args.ctx, key, attrib.getMember(args.ctx, key));
}
return obj;
}
@Native public static ArrayValue keys(Context ctx, Object obj, Object all) {
@Expose(target = ExposeTarget.STATIC)
public static ArrayValue __keys(Arguments args) {
var obj = args.convert(0, ObjectValue.class);
var all = args.getBoolean(1);
var res = new ArrayValue();
var _all = Values.toBoolean(all);
for (var key : Values.getMembers(ctx, obj, true, false)) {
if (_all || !(key instanceof Symbol)) res.set(ctx, res.size(), key);
for (var key : Values.getMembers(args.ctx, obj, true, false)) {
if (all || !(key instanceof Symbol)) res.set(args.ctx, res.size(), key);
}
return res;
}
@Native public static ArrayValue entries(Context ctx, Object obj, Object all) {
@Expose(target = ExposeTarget.STATIC)
public static ArrayValue __entries(Arguments args) {
var res = new ArrayValue();
var _all = Values.toBoolean(all);
var obj = args.convert(0, ObjectValue.class);
var all = args.getBoolean(1);
for (var key : Values.getMembers(ctx, obj, true, false)) {
if (_all || !(key instanceof Symbol)) res.set(ctx, res.size(), new ArrayValue(ctx, key, Values.getMember(ctx, obj, key)));
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)));
}
return res;
}
@Native public static ArrayValue values(Context ctx, Object obj, Object all) {
@Expose(target = ExposeTarget.STATIC)
public static ArrayValue __values(Arguments args) {
var res = new ArrayValue();
var _all = Values.toBoolean(all);
var obj = args.convert(0, ObjectValue.class);
var all = args.getBoolean(1);
for (var key : Values.getMembers(ctx, obj, true, false)) {
if (_all || key instanceof String) res.set(ctx, res.size(), Values.getMember(ctx, obj, key));
for (var key : Values.getMembers(args.ctx, obj, true, false)) {
if (all || key instanceof String) res.set(args.ctx, res.size(), Values.getMember(args.ctx, obj, key));
}
return res;
}
@Native public static ObjectValue getOwnPropertyDescriptor(Context ctx, Object obj, Object key) {
return Values.getMemberDescriptor(ctx, obj, key);
@Expose(target = ExposeTarget.STATIC)
public static ObjectValue __getOwnPropertyDescriptor(Arguments args) {
return Values.getMemberDescriptor(args.ctx, args.get(0), args.get(1));
}
@Native public static ObjectValue getOwnPropertyDescriptors(Context ctx, Object obj) {
@Expose(target = ExposeTarget.STATIC)
public static ObjectValue __getOwnPropertyDescriptors(Arguments args) {
var res = new ObjectValue();
for (var key : Values.getMembers(ctx, obj, true, true)) {
res.defineProperty(ctx, key, getOwnPropertyDescriptor(ctx, obj, key));
var obj = args.get(0);
for (var key : Values.getMembers(args.ctx, obj, true, true)) {
res.defineProperty(args.ctx, key, __getOwnPropertyDescriptor(new Arguments(args.ctx, null, obj, key)));
}
return res;
}
@Native public static ArrayValue getOwnPropertyNames(Context ctx, Object obj, Object all) {
@Expose(target = ExposeTarget.STATIC)
public static ArrayValue __getOwnPropertyNames(Arguments args) {
var res = new ArrayValue();
var _all = Values.toBoolean(all);
var obj = args.convert(0, ObjectValue.class);
var all = args.getBoolean(1);
for (var key : Values.getMembers(ctx, obj, true, true)) {
if (_all || !(key instanceof Symbol)) res.set(ctx, res.size(), key);
for (var key : Values.getMembers(args.ctx, obj, true, true)) {
if (all || !(key instanceof Symbol)) res.set(args.ctx, res.size(), key);
}
return res;
}
@Native public static ArrayValue getOwnPropertySymbols(Context ctx, Object obj) {
@Expose(target = ExposeTarget.STATIC)
public static ArrayValue __getOwnPropertySymbols(Arguments args) {
var obj = args.convert(0, ObjectValue.class);
var res = new ArrayValue();
for (var key : Values.getMembers(ctx, obj, true, true)) {
if (key instanceof Symbol) res.set(ctx, res.size(), key);
for (var key : Values.getMembers(args.ctx, obj, true, true)) {
if (key instanceof Symbol) res.set(args.ctx, res.size(), key);
}
return res;
}
@Native public static boolean hasOwn(Context ctx, Object obj, Object key) {
return Values.hasMember(ctx, obj, key, true);
@Expose(target = ExposeTarget.STATIC)
public static boolean __hasOwn(Arguments args) {
return Values.hasMember(args.ctx, args.get(0), args.get(1), true);
}
@Native public static ObjectValue getPrototypeOf(Context ctx, Object obj) {
return Values.getPrototype(ctx, obj);
@Expose(target = ExposeTarget.STATIC)
public static ObjectValue __getPrototypeOf(Arguments args) {
return Values.getPrototype(args.ctx, args.get(0));
}
@Native public static Object setPrototypeOf(Context ctx, Object obj, Object proto) {
Values.setPrototype(ctx, obj, proto);
return obj;
@Expose(target = ExposeTarget.STATIC)
public static Object __setPrototypeOf(Arguments args) {
Values.setPrototype(args.ctx, args.get(0), args.get(1));
return args.get(0);
}
@Native public static ObjectValue fromEntries(Context ctx, Object iterable) {
@Expose(target = ExposeTarget.STATIC)
public static ObjectValue __fromEntries(Arguments args) {
var res = new ObjectValue();
for (var el : Values.fromJSIterator(ctx, iterable)) {
for (var el : Values.fromJSIterator(args.ctx, args.get(0))) {
if (el instanceof ArrayValue) {
res.defineProperty(ctx, ((ArrayValue)el).get(0), ((ArrayValue)el).get(1));
res.defineProperty(args.ctx, ((ArrayValue)el).get(0), ((ArrayValue)el).get(1));
}
}
return res;
}
@Native public static Object preventExtensions(Context ctx, Object obj) {
if (obj instanceof ObjectValue) ((ObjectValue)obj).preventExtensions();
return obj;
@Expose(target = ExposeTarget.STATIC)
public static Object __preventExtensions(Arguments args) {
if (args.get(0) instanceof ObjectValue) args.convert(0, ObjectValue.class).preventExtensions();
return args.get(0);
}
@Native public static Object seal(Context ctx, Object obj) {
if (obj instanceof ObjectValue) ((ObjectValue)obj).seal();
return obj;
@Expose(target = ExposeTarget.STATIC)
public static Object __seal(Arguments args) {
if (args.get(0) instanceof ObjectValue) args.convert(0, ObjectValue.class).seal();
return args.get(0);
}
@Native public static Object freeze(Context ctx, Object obj) {
if (obj instanceof ObjectValue) ((ObjectValue)obj).freeze();
return obj;
@Expose(target = ExposeTarget.STATIC)
public static Object __freeze(Arguments args) {
if (args.get(0) instanceof ObjectValue) args.convert(0, ObjectValue.class).freeze();
return args.get(0);
}
@Native public static boolean isExtensible(Context ctx, Object obj) {
@Expose(target = ExposeTarget.STATIC)
public static boolean __isExtensible(Arguments args) {
var obj = args.get(0);
return obj instanceof ObjectValue && ((ObjectValue)obj).extensible();
}
@Native public static boolean isSealed(Context ctx, Object obj) {
@Expose(target = ExposeTarget.STATIC)
public static boolean __isSealed(Arguments args) {
var obj = args.get(0);
if (obj instanceof ObjectValue && ((ObjectValue)obj).extensible()) {
var _obj = (ObjectValue)obj;
for (var key : _obj.keys(true)) {
@ -175,7 +223,10 @@ import me.topchetoeu.jscript.interop.NativeConstructor;
return true;
}
@Native public static boolean isFrozen(Context ctx, Object obj) {
@Expose(target = ExposeTarget.STATIC)
public static boolean __isFrozen(Arguments args) {
var obj = args.get(0);
if (obj instanceof ObjectValue && ((ObjectValue)obj).extensible()) {
var _obj = (ObjectValue)obj;
for (var key : _obj.keys(true)) {
@ -187,26 +238,31 @@ import me.topchetoeu.jscript.interop.NativeConstructor;
return true;
}
@Native(thisArg = true) public static Object valueOf(Context ctx, Object thisArg) {
return thisArg;
@Expose
public static Object __valueOf(Arguments args) {
return args.self;
}
@Native(thisArg = true) public static String toString(Context ctx, Object thisArg) {
var name = Values.getMember(ctx, thisArg, Symbol.get("Symbol.typeName"));
@Expose
public static String __toString(Arguments args) {
var name = Values.getMember(args.ctx, args.self, Symbol.get("Symbol.typeName"));
if (name == null) name = "Unknown";
else name = Values.toString(ctx, name);
else name = Values.toString(args.ctx, name);
return "[object " + name + "]";
}
@Native(thisArg = true) public static boolean hasOwnProperty(Context ctx, Object thisArg, Object key) {
return ObjectLib.hasOwn(ctx, thisArg, Values.convert(ctx, key, String.class));
@Expose
public static boolean __hasOwnProperty(Arguments args) {
return Values.hasMember(args.ctx, args.self, args.get(0), true);
}
@NativeConstructor(thisArg = true) public static Object constructor(Context ctx, Object thisArg, Object arg) {
@ExposeConstructor
public static Object __constructor(Arguments args) {
var arg = args.get(0);
if (arg == null || arg == Values.NULL) return new ObjectValue();
else if (arg instanceof Boolean) return BooleanLib.constructor(ctx, thisArg, arg);
else if (arg instanceof Number) return NumberLib.constructor(ctx, thisArg, arg);
else if (arg instanceof String) return StringLib.constructor(ctx, thisArg, arg);
// else if (arg instanceof Symbol) return SymbolPolyfill.constructor(ctx, thisArg, arg);
else if (arg instanceof Boolean) return new BooleanLib((boolean)arg);
else if (arg instanceof Number) return new NumberLib(((Number)arg).doubleValue());
else if (arg instanceof String) return new StringLib((String)arg);
else if (arg instanceof Symbol) return new SymbolLib((Symbol)arg);
else return arg;
}
}

View File

@ -2,355 +2,314 @@ package me.topchetoeu.jscript.lib;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import me.topchetoeu.jscript.engine.Context;
import me.topchetoeu.jscript.engine.EventLoop;
import me.topchetoeu.jscript.engine.values.ArrayValue;
import me.topchetoeu.jscript.engine.values.FunctionValue;
import me.topchetoeu.jscript.engine.values.NativeFunction;
import me.topchetoeu.jscript.engine.values.NativeWrapper;
import me.topchetoeu.jscript.engine.values.ObjectValue;
import me.topchetoeu.jscript.engine.values.Values;
import me.topchetoeu.jscript.exceptions.EngineException;
import me.topchetoeu.jscript.interop.Native;
import me.topchetoeu.jscript.interop.Arguments;
import me.topchetoeu.jscript.interop.Expose;
import me.topchetoeu.jscript.interop.ExposeConstructor;
import me.topchetoeu.jscript.interop.ExposeTarget;
import me.topchetoeu.jscript.interop.WrapperName;
import me.topchetoeu.jscript.ResultRunnable;
@Native("Promise") public class PromiseLib {
public static interface PromiseRunner {
Object run();
@WrapperName("Promise")
public class PromiseLib {
public static interface Handle {
void onFulfil(Object val);
void onReject(EngineException err);
default Handle defer(EventLoop loop) {
var self = this;
return new Handle() {
@Override public void onFulfil(Object val) {
loop.pushMsg(() -> self.onFulfil(val), true);
}
private static class Handle {
public final Context ctx;
public final FunctionValue fulfilled;
public final FunctionValue rejected;
public Handle(Context ctx, FunctionValue fulfilled, FunctionValue rejected) {
this.ctx = ctx;
this.fulfilled = fulfilled;
this.rejected = rejected;
@Override public void onReject(EngineException val) {
loop.pushMsg(() -> self.onReject(val), true);
}
};
}
}
@Native("resolve")
public static PromiseLib ofResolved(Context ctx, Object val) {
var res = new PromiseLib();
res.fulfill(ctx, val);
return res;
}
@Native("reject")
public static PromiseLib ofRejected(Context ctx, Object val) {
var res = new PromiseLib();
res.reject(ctx, val);
return res;
}
@Native public static PromiseLib any(Context ctx, Object _promises) {
if (!Values.isArray(_promises)) throw EngineException.ofType("Expected argument for any to be an array.");
var promises = Values.array(_promises);
if (promises.size() == 0) return ofResolved(ctx, new ArrayValue());
var n = new int[] { promises.size() };
var res = new PromiseLib();
var errors = new ArrayValue();
for (var i = 0; i < promises.size(); i++) {
var index = i;
var val = promises.get(i);
then(ctx, val,
new NativeFunction(null, (e, th, args) -> { res.fulfill(e, args[0]); return null; }),
new NativeFunction(null, (e, th, args) -> {
errors.set(ctx, index, args[0]);
n[0]--;
if (n[0] <= 0) res.reject(e, errors);
return null;
})
);
}
return res;
}
@Native public static PromiseLib race(Context ctx, Object _promises) {
if (!Values.isArray(_promises)) throw EngineException.ofType("Expected argument for any to be an array.");
var promises = Values.array(_promises);
if (promises.size() == 0) return ofResolved(ctx, new ArrayValue());
var res = new PromiseLib();
for (var i = 0; i < promises.size(); i++) {
var val = promises.get(i);
then(ctx, val,
new NativeFunction(null, (e, th, args) -> { res.fulfill(e, args[0]); return null; }),
new NativeFunction(null, (e, th, args) -> { res.reject(e, args[0]); return null; })
);
}
return res;
}
@Native public static PromiseLib all(Context ctx, Object _promises) {
if (!Values.isArray(_promises)) throw EngineException.ofType("Expected argument for any to be an array.");
var promises = Values.array(_promises);
if (promises.size() == 0) return ofResolved(ctx, new ArrayValue());
var n = new int[] { promises.size() };
var res = new PromiseLib();
var result = new ArrayValue();
for (var i = 0; i < promises.size(); i++) {
var index = i;
var val = promises.get(i);
then(ctx, val,
new NativeFunction(null, (e, th, args) -> {
result.set(ctx, index, args[0]);
n[0]--;
if (n[0] <= 0) res.fulfill(e, result);
return null;
}),
new NativeFunction(null, (e, th, args) -> { res.reject(e, args[0]); return null; })
);
}
if (n[0] <= 0) res.fulfill(ctx, result);
return res;
}
@Native public static PromiseLib allSettled(Context ctx, Object _promises) {
if (!Values.isArray(_promises)) throw EngineException.ofType("Expected argument for any to be an array.");
var promises = Values.array(_promises);
if (promises.size() == 0) return ofResolved(ctx, new ArrayValue());
var n = new int[] { promises.size() };
var res = new PromiseLib();
var result = new ArrayValue();
for (var i = 0; i < promises.size(); i++) {
var index = i;
var val = promises.get(i);
then(ctx, val,
new NativeFunction(null, (e, th, args) -> {
result.set(ctx, index, new ObjectValue(ctx, Map.of(
"status", "fulfilled",
"value", args[0]
)));
n[0]--;
if (n[0] <= 0) res.fulfill(e, result);
return null;
}),
new NativeFunction(null, (e, th, args) -> {
result.set(ctx, index, new ObjectValue(ctx, Map.of(
"status", "rejected",
"reason", args[0]
)));
n[0]--;
if (n[0] <= 0) res.fulfill(e, result);
return null;
})
);
}
if (n[0] <= 0) res.fulfill(ctx, result);
return res;
}
/**
* Thread safe - you can call this from anywhere
* HOWEVER, it's strongly recommended to use this only in javascript
*/
@Native(thisArg=true) public static Object then(Context ctx, Object _thisArg, Object _onFulfill, Object _onReject) {
var onFulfill = _onFulfill instanceof FunctionValue ? ((FunctionValue)_onFulfill) : null;
var onReject = _onReject instanceof FunctionValue ? ((FunctionValue)_onReject) : null;
var res = new PromiseLib();
var fulfill = onFulfill == null ? new NativeFunction((_ctx, _0, _args) -> _args.length > 0 ? _args[0] : null) : (FunctionValue)onFulfill;
var reject = onReject == null ? new NativeFunction((_ctx, _0, _args) -> {
throw new EngineException(_args.length > 0 ? _args[0] : null);
}) : (FunctionValue)onReject;
var thisArg = _thisArg instanceof NativeWrapper && ((NativeWrapper)_thisArg).wrapped instanceof PromiseLib ?
((NativeWrapper)_thisArg).wrapped :
_thisArg;
var fulfillHandle = new NativeFunction(null, (_ctx, th, a) -> {
try { res.fulfill(ctx, Values.convert(ctx, fulfill.call(ctx, null, a[0]), Object.class)); }
catch (EngineException err) { res.reject(ctx, err.value); }
return null;
});
var rejectHandle = new NativeFunction(null, (_ctx, th, a) -> {
try { res.fulfill(ctx, reject.call(ctx, null, a[0])); }
catch (EngineException err) { res.reject(ctx, err.value); }
if (thisArg instanceof PromiseLib) ((PromiseLib)thisArg).handled = true;
return null;
});
if (thisArg instanceof PromiseLib) ((PromiseLib)thisArg).handle(ctx, fulfillHandle, rejectHandle);
else {
Object next;
try { next = Values.getMember(ctx, thisArg, "then"); }
catch (IllegalArgumentException e) { next = null; }
try {
if (next instanceof FunctionValue) ((FunctionValue)next).call(ctx, thisArg, fulfillHandle, rejectHandle);
else res.fulfill(ctx, fulfill.call(ctx, null, thisArg));
}
catch (EngineException err) {
res.reject(ctx, fulfill.call(ctx, null, err.value));
}
}
return res;
}
/**
* Thread safe - you can call this from anywhere
* HOWEVER, it's strongly recommended to use this only in javascript
*/
@Native(value="catch", thisArg=true) public static Object _catch(Context ctx, Object thisArg, Object _onReject) {
return then(ctx, thisArg, null, _onReject);
}
/**
* Thread safe - you can call this from anywhere
* HOWEVER, it's strongly recommended to use this only in javascript
*/
@Native(value="finally", thisArg=true) public static Object _finally(Context ctx, Object thisArg, Object _handle) {
return then(ctx, thisArg,
new NativeFunction(null, (e, th, _args) -> {
if (_handle instanceof FunctionValue) ((FunctionValue)_handle).call(ctx);
return _args.length > 0 ? _args[0] : null;
}),
new NativeFunction(null, (e, th, _args) -> {
if (_handle instanceof FunctionValue) ((FunctionValue)_handle).call(ctx);
throw new EngineException(_args.length > 0 ? _args[0] : null);
})
);
}
private List<Handle> handles = new ArrayList<>();
private static final int STATE_PENDING = 0;
private static final int STATE_FULFILLED = 1;
private static final int STATE_REJECTED = 2;
private int state = STATE_PENDING;
private boolean handled = false;
private Object val;
@Expose(value = "resolve", target = ExposeTarget.STATIC)
public static PromiseLib __ofResolved(Arguments args) {
return ofResolved(args.ctx, args.get(0));
}
@Expose(value = "reject", target = ExposeTarget.STATIC)
public static PromiseLib __ofRejected(Arguments args) {
return ofRejected(args.ctx, new EngineException(args.get(0)).setCtx(args.ctx));
}
public synchronized void fulfill(Context ctx, Object val) {
if (this.state != STATE_PENDING) return;
@Expose(target = ExposeTarget.STATIC)
private static PromiseLib __any(Arguments args) {
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 (val instanceof PromiseLib) ((PromiseLib)val).handle(ctx,
new NativeFunction(null, (e, th, a) -> { this.fulfill(ctx, a[0]); return null; }),
new NativeFunction(null, (e, th, a) -> { this.reject(ctx, a[0]); return null; })
);
else {
Object then;
try { then = Values.getMember(ctx, val, "then"); }
catch (IllegalArgumentException e) { then = null; }
if (promises.size() == 0) return ofRejected(args.ctx, EngineException.ofError("No promises passed to 'Promise.any'.").setCtx(args.ctx));
var n = new int[] { promises.size() };
var res = new PromiseLib();
var errors = new ArrayValue();
for (var i = 0; i < promises.size(); i++) {
var index = i;
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); }
public void onReject(EngineException err) {
errors.set(args.ctx, index, err.value);
n[0]--;
if (n[0] <= 0) res.reject(args.ctx, new EngineException(errors).setCtx(args.ctx));
}
});
}
return res;
}
@Expose(target = ExposeTarget.STATIC)
private static PromiseLib __race(Arguments args) {
if (!(args.get(0) instanceof ArrayValue)) throw EngineException.ofType("Expected argument for any to be an array.");
var promises = args.convert(0, ArrayValue.class);
var res = new PromiseLib();
for (var i = 0; i < promises.size(); i++) {
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); }
});
}
return res;
}
@Expose(target = ExposeTarget.STATIC)
private static PromiseLib __all(Arguments args) {
if (!(args.get(0) instanceof ArrayValue)) throw EngineException.ofType("Expected argument for any to be an array.");
var promises = args.convert(0, ArrayValue.class);
var n = new int[] { promises.size() };
var res = new PromiseLib();
var result = new ArrayValue();
for (var i = 0; i < promises.size(); i++) {
if (res.state != STATE_PENDING) break;
var index = i;
var val = promises.get(i);
handle(args.ctx, val, new Handle() {
@Override public void onFulfil(Object val) {
result.set(args.ctx, index, val);
n[0]--;
if (n[0] <= 0) res.fulfill(args.ctx, result);
}
@Override public void onReject(EngineException err) {
res.reject(args.ctx, err);
}
});
}
if (n[0] <= 0) res.fulfill(args.ctx, result);
return res;
}
@Expose(target = ExposeTarget.STATIC)
private static PromiseLib __allSettled(Arguments args) {
if (!(args.get(0) instanceof ArrayValue)) throw EngineException.ofType("Expected argument for any to be an array.");
var promises = args.convert(0, ArrayValue.class);
var n = new int[] { promises.size() };
var res = new PromiseLib();
var result = new ArrayValue();
for (var i = 0; i < promises.size(); i++) {
if (res.state != STATE_PENDING) break;
var index = i;
handle(args.ctx, 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);
result.set(args.ctx, index, desc);
n[0]--;
if (n[0] <= 0) res.fulfill(args.ctx, res);
}
@Override public void onReject(EngineException err) {
var desc = new ObjectValue();
desc.defineProperty(args.ctx, "status", "reject");
desc.defineProperty(args.ctx, "value", err.value);
result.set(args.ctx, index, desc);
n[0]--;
if (n[0] <= 0) res.fulfill(args.ctx, res);
}
});
}
if (n[0] <= 0) res.fulfill(args.ctx, result);
return res;
}
@Expose
private static Object __then(Arguments args) {
var onFulfill = args.get(0) instanceof FunctionValue ? args.convert(0, FunctionValue.class) : null;
var onReject = args.get(1) instanceof FunctionValue ? args.convert(1, FunctionValue.class) : null;
var res = new PromiseLib();
handle(args.ctx, 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); }
}
@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); }
}
}.defer(args.ctx.engine));
return res;
}
@Expose
private static Object __catch(Arguments args) {
return __then(new Arguments(args.ctx, args.self, null, args.get(0)));
}
@Expose
private static Object __finally(Arguments args) {
var func = args.get(0) instanceof FunctionValue ? args.convert(0, FunctionValue.class) : null;
var res = new PromiseLib();
handle(args.ctx, args.self, new Handle() {
@Override public void onFulfil(Object val) {
try {
if (then instanceof FunctionValue) ((FunctionValue)then).call(ctx, val,
new NativeFunction((e, _thisArg, a) -> { this.fulfill(ctx, a.length > 0 ? a[0] : null); return null; }),
new NativeFunction((e, _thisArg, a) -> { this.reject(ctx, a.length > 0 ? a[0] : null); return null; })
);
else {
this.val = val;
this.state = STATE_FULFILLED;
ctx.engine.pushMsg(true, ctx.environment, new NativeFunction((_ctx, _thisArg, _args) -> {
for (var handle : handles) {
handle.fulfilled.call(handle.ctx, null, val);
func.call(args.ctx);
res.fulfill(args.ctx, val);
}
handles = null;
return null;
}), null);
catch (EngineException e) { res.reject(args.ctx, e); }
}
}
catch (EngineException err) {
this.reject(ctx, err.value);
}
}
}
public synchronized void reject(Context ctx, Object val) {
if (this.state != STATE_PENDING) return;
if (val instanceof PromiseLib) ((PromiseLib)val).handle(ctx,
new NativeFunction(null, (e, th, a) -> { this.reject(ctx, a[0]); return null; }),
new NativeFunction(null, (e, th, a) -> { this.reject(ctx, a[0]); return null; })
);
else {
Object then;
try { then = Values.getMember(ctx, val, "then"); }
catch (IllegalArgumentException e) { then = null; }
@Override public void onReject(EngineException err) {
try {
if (then instanceof FunctionValue) ((FunctionValue)then).call(ctx, val,
new NativeFunction((e, _thisArg, a) -> { this.reject(ctx, a.length > 0 ? a[0] : null); return null; }),
new NativeFunction((e, _thisArg, a) -> { this.reject(ctx, a.length > 0 ? a[0] : null); return null; })
);
else {
this.val = val;
this.state = STATE_REJECTED;
func.call(args.ctx);
res.reject(args.ctx, err);
}
catch (EngineException e) { res.reject(args.ctx, e); }
}
}.defer(args.ctx.engine));
ctx.engine.pushMsg(true, ctx.environment, new NativeFunction((_ctx, _thisArg, _args) -> {
for (var handle : handles) handle.rejected.call(handle.ctx, null, val);
if (!handled) {
Values.printError(new EngineException(val).setCtx(ctx.environment, ctx.engine), "(in promise)");
}
handles = null;
return null;
}), null);
}
}
catch (EngineException err) {
this.reject(ctx, err.value);
}
}
return res;
}
private void handle(Context ctx, FunctionValue fulfill, FunctionValue reject) {
if (state == STATE_FULFILLED) ctx.engine.pushMsg(true, ctx.environment, fulfill, null, val);
else if (state == STATE_REJECTED) {
ctx.engine.pushMsg(true, ctx.environment, reject, null, val);
handled = true;
}
else handles.add(new Handle(ctx, fulfill, reject));
}
@ExposeConstructor
private static PromiseLib __constructor(Arguments args) {
var func = args.convert(0, FunctionValue.class);
var res = new PromiseLib();
@Override @Native public String toString() {
if (state == STATE_PENDING) return "Promise (pending)";
else if (state == STATE_FULFILLED) return "Promise (fulfilled)";
else return "Promise (rejected)";
}
/**
* NOT THREAD SAFE - must be called from the engine executor thread
*/
@Native public PromiseLib(Context ctx, FunctionValue func) {
if (!(func instanceof FunctionValue)) throw EngineException.ofType("A function must be passed to the promise constructor.");
try {
func.call(
ctx, null,
new NativeFunction(null, (e, th, args) -> {
fulfill(e, args.length > 0 ? args[0] : null);
args.ctx, null,
new NativeFunction(null, _args -> {
res.fulfill(_args.ctx, _args.get(0));
return null;
}),
new NativeFunction(null, (e, th, args) -> {
reject(e, args.length > 0 ? args[0] : null);
new NativeFunction(null, _args -> {
res.reject(_args.ctx, new EngineException(_args.get(0)).setCtx(_args.ctx));
return null;
})
);
}
catch (EngineException e) {
reject(ctx, e.value);
}
res.reject(args.ctx, e);
}
private PromiseLib(int state, Object val) {
this.state = state;
return res;
}
private List<Handle> handles = new ArrayList<>();
private int state = STATE_PENDING;
private boolean handled = false;
private Object val;
private void resolveSynchronized(Context ctx, Object val, int newState) {
ctx.engine.pushMsg(() -> {
this.val = val;
this.state = newState;
for (var handle : handles) {
if (newState == STATE_FULFILLED) handle.onFulfil(val);
if (newState == STATE_REJECTED) {
handle.onReject((EngineException)val);
handled = true;
}
public PromiseLib() {
this(STATE_PENDING, null);
}
public static PromiseLib await(Context ctx, PromiseRunner runner) {
if (state == STATE_REJECTED && !handled) {
Values.printError(new EngineException(val).setCtx(ctx.environment, ctx.engine), "(in promise)");
}
handles = null;
}, true);
}
private synchronized void resolve(Context ctx, Object val, int newState) {
if (this.state != STATE_PENDING || newState == STATE_PENDING) return;
handle(ctx, val, new Handle() {
@Override public void onFulfil(Object val) {
resolveSynchronized(ctx, val, newState);
}
@Override public void onReject(EngineException err) {
resolveSynchronized(ctx, val, STATE_REJECTED);
}
});
}
public synchronized void fulfill(Context ctx, Object val) {
resolve(ctx, val, STATE_FULFILLED);
}
public synchronized void reject(Context ctx, EngineException val) {
resolve(ctx, val, STATE_REJECTED);
}
private void handle(Handle handle) {
if (state == STATE_FULFILLED) handle.onFulfil(val);
else if (state == STATE_REJECTED) {
handle.onReject((EngineException)val);
handled = true;
}
else handles.add(handle);
}
@Override public String toString() {
if (state == STATE_PENDING) return "Promise (pending)";
else if (state == STATE_FULFILLED) return "Promise (fulfilled)";
else return "Promise (rejected)";
}
public PromiseLib() {
this.state = STATE_PENDING;
this.val = null;
}
public static PromiseLib await(Context ctx, ResultRunnable<Object> runner) {
var res = new PromiseLib();
new Thread(() -> {
@ -358,10 +317,70 @@ import me.topchetoeu.jscript.interop.Native;
res.fulfill(ctx, runner.run());
}
catch (EngineException e) {
res.reject(ctx, e.value);
res.reject(ctx, e);
}
}, "Promisifier").start();
return res;
}
public static PromiseLib await(Context ctx, Runnable runner) {
return await(ctx, () -> {
runner.run();
return null;
});
}
public static void handle(Context ctx, Object obj, Handle handle) {
if (Values.isWrapper(obj, PromiseLib.class)) {
var promise = Values.wrapper(obj, PromiseLib.class);
handle(ctx, promise, handle);
return;
}
if (obj instanceof PromiseLib) {
((PromiseLib)obj).handle(handle);
return;
}
var rethrow = new boolean[1];
try {
var then = Values.getMember(ctx, obj, "then");
Values.call(ctx, then, obj,
new NativeFunction(args -> {
try { handle.onFulfil(args.get(0)); }
catch (Exception e) {
rethrow[0] = true;
throw e;
}
return null;
}),
new NativeFunction(args -> {
try { handle.onReject(new EngineException(args.get(0))); }
catch (Exception e) {
rethrow[0] = true;
throw e;
}
return null;
})
);
return;
}
catch (Exception e) {
if (rethrow[0]) throw e;
}
handle.onFulfil(obj);
}
public static PromiseLib ofResolved(Context ctx, Object value) {
var res = new PromiseLib();
res.fulfill(ctx, value);
return res;
}
public static PromiseLib ofRejected(Context ctx, EngineException value) {
var res = new PromiseLib();
res.reject(ctx, value);
return res;
}
}

View File

@ -1,22 +1,22 @@
package me.topchetoeu.jscript.lib;
import me.topchetoeu.jscript.engine.Context;
import me.topchetoeu.jscript.engine.Environment;
import me.topchetoeu.jscript.engine.values.ObjectValue;
import me.topchetoeu.jscript.engine.values.ObjectValue.PlaceholderProto;
import me.topchetoeu.jscript.interop.InitType;
import me.topchetoeu.jscript.interop.Native;
import me.topchetoeu.jscript.interop.NativeConstructor;
import me.topchetoeu.jscript.interop.NativeInit;
import me.topchetoeu.jscript.interop.WrapperName;
import me.topchetoeu.jscript.interop.Arguments;
import me.topchetoeu.jscript.interop.ExposeConstructor;
import me.topchetoeu.jscript.interop.ExposeField;
import me.topchetoeu.jscript.interop.ExposeTarget;
@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.setPrototype(PlaceholderProto.SYNTAX_ERROR);
target.defineProperty(ctx, "name", "RangeError");
@WrapperName("RangeError")
public class RangeErrorLib extends ErrorLib {
@ExposeField(target = ExposeTarget.STATIC)
public static final String __name = "RangeError";
@ExposeConstructor
public static ObjectValue constructor(Arguments args) {
var target = ErrorLib.__constructor(args);
target.setPrototype(PlaceholderProto.RANGE_ERROR);
return target;
}
@NativeInit(InitType.PROTOTYPE) public static void init(Environment env, ObjectValue target) {
target.defineProperty(null, "name", "RangeError");
}
}

View File

@ -10,79 +10,63 @@ import me.topchetoeu.jscript.engine.values.FunctionValue;
import me.topchetoeu.jscript.engine.values.NativeWrapper;
import me.topchetoeu.jscript.engine.values.ObjectValue;
import me.topchetoeu.jscript.engine.values.Values;
import me.topchetoeu.jscript.interop.Native;
import me.topchetoeu.jscript.interop.NativeGetter;
import me.topchetoeu.jscript.interop.Arguments;
import me.topchetoeu.jscript.interop.Expose;
import me.topchetoeu.jscript.interop.ExposeConstructor;
import me.topchetoeu.jscript.interop.ExposeTarget;
import me.topchetoeu.jscript.interop.ExposeType;
import me.topchetoeu.jscript.interop.WrapperName;
@Native("RegExp") public class RegExpLib {
@WrapperName("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("[/\\-\\\\^$*+?.()|\\[\\]{}]");
private static String cleanupPattern(Context ctx, 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);
if (res.equals("")) return "(?:)";
return res;
}
private static String cleanupFlags(Context ctx, Object val) {
if (val == null) return "";
return Values.toString(ctx, val);
}
private static boolean checkEscaped(String s, int pos) {
int n = 0;
while (true) {
if (pos <= 0) break;
if (s.charAt(pos) != '\\') break;
n++;
pos--;
}
return (n % 2) != 0;
}
@Native
public static RegExpLib escape(Context ctx, Object raw, Object flags) {
return escape(Values.toString(ctx, raw), cleanupFlags(ctx, flags));
}
public static RegExpLib escape(String raw, String flags) {
return new RegExpLib(ESCAPE_PATTERN.matcher(raw).replaceAll("\\\\$0"), flags);
}
private Pattern pattern;
private String[] namedGroups;
private int flags;
@Native public int lastI = 0;
@Native public final String source;
@Native public final boolean hasIndices;
@Native public final boolean global;
@Native public final boolean sticky;
@Native("@@Symbol.typeName") public final String name = "RegExp";
public int lastI = 0;
public final String source;
public final boolean hasIndices;
public final boolean global;
public final boolean sticky;
@NativeGetter public boolean ignoreCase() { return (flags & Pattern.CASE_INSENSITIVE) != 0; }
@NativeGetter public boolean multiline() { return (flags & Pattern.MULTILINE) != 0; }
@NativeGetter public boolean unicode() { return (flags & Pattern.UNICODE_CHARACTER_CLASS) != 0; }
@NativeGetter public boolean dotAll() { return (flags & Pattern.DOTALL) != 0; }
@Expose(type = ExposeType.GETTER)
public int __lastIndex() { return lastI; }
@Expose(type = ExposeType.SETTER)
public void __setLastIndex(Arguments args) { lastI = args.getInt(0); }
@Expose(type = ExposeType.GETTER)
public String __source() { return source; }
@NativeGetter("flags") public final String flags() {
@Expose(type = ExposeType.GETTER)
public boolean __ignoreCase() { return (flags & Pattern.CASE_INSENSITIVE) != 0; }
@Expose(type = ExposeType.GETTER)
public boolean __multiline() { return (flags & Pattern.MULTILINE) != 0; }
@Expose(type = ExposeType.GETTER)
public boolean __unicode() { return (flags & Pattern.UNICODE_CHARACTER_CLASS) != 0; }
@Expose(type = ExposeType.GETTER)
public boolean __dotAll() { return (flags & Pattern.DOTALL) != 0; }
@Expose(type = ExposeType.GETTER)
public boolean __global() { return global; }
@Expose(type = ExposeType.GETTER)
public boolean __sticky() { return sticky; }
@Expose(type = ExposeType.GETTER)
public final String __flags() {
String res = "";
if (hasIndices) res += 'd';
if (global) res += 'g';
if (ignoreCase()) res += 'i';
if (multiline()) res += 'm';
if (dotAll()) res += 's';
if (unicode()) res += 'u';
if (__ignoreCase()) res += 'i';
if (__multiline()) res += 'm';
if (__dotAll()) res += 's';
if (__unicode()) res += 'u';
if (sticky) res += 'y';
return res;
}
@Native public Object exec(String str) {
@Expose public Object __exec(Arguments args) {
var str = args.getString(0);
var matcher = pattern.matcher(str);
if (lastI > str.length() || !matcher.find(lastI) || sticky && matcher.start() != lastI) {
lastI = 0;
@ -126,39 +110,36 @@ import me.topchetoeu.jscript.interop.NativeGetter;
return obj;
}
@Native public boolean test(String str) {
return this.exec(str) != Values.NULL;
}
@Native public String toString() {
return "/" + source + "/" + flags();
@Expose public boolean __test(Arguments args) {
return this.__exec(args) != Values.NULL;
}
@Native("@@Symbol.match") public Object match(Context ctx, String target) {
@Expose("@@Symbol.match") public Object __match(Arguments args) {
if (this.global) {
var res = new ArrayValue();
Object val;
while ((val = this.exec(target)) != Values.NULL) {
res.set(ctx, res.size(), Values.getMember(ctx, val, 0));
while ((val = this.__exec(args)) != Values.NULL) {
res.set(args.ctx, res.size(), Values.getMember(args.ctx, val, 0));
}
lastI = 0;
return res;
}
else {
var res = this.exec(target);
var res = this.__exec(args);
if (!this.sticky) this.lastI = 0;
return res;
}
}
@Native("@@Symbol.matchAll") public Object matchAll(Context ctx, String target) {
var pattern = new RegExpLib(this.source, this.flags() + "g");
@Expose("@@Symbol.matchAll") public Object __matchAll(Arguments args) {
var pattern = this.toGlobal();
return Values.toJSIterator(ctx, new Iterator<Object>() {
return Values.toJSIterator(args.ctx, new Iterator<Object>() {
private Object val = null;
private boolean updated = false;
private void update() {
if (!updated) val = pattern.exec(target);
if (!updated) val = pattern.__exec(args);
}
@Override public boolean hasNext() {
update();
@ -172,17 +153,21 @@ import me.topchetoeu.jscript.interop.NativeGetter;
});
}
@Native("@@Symbol.split") public ArrayValue split(Context ctx, String target, Object limit, boolean sensible) {
var pattern = new RegExpLib(this.source, this.flags() + "g");
@Expose("@@Symbol.split") public ArrayValue __split(Arguments args) {
var pattern = this.toGlobal();
var target = args.getString(0);
var hasLimit = args.get(1) != null;
var lim = args.getInt(1);
var sensible = args.getBoolean(2);
Object match;
int lastEnd = 0;
var res = new ArrayValue();
var lim = limit == null ? 0 : Values.toNumber(ctx, limit);
while ((match = pattern.exec(target)) != Values.NULL) {
while ((match = pattern.__exec(args)) != Values.NULL) {
var added = new ArrayList<String>();
var arrMatch = (ArrayValue)match;
int index = (int)Values.toNumber(ctx, Values.getMember(ctx, match, "index"));
int index = (int)Values.toNumber(args.ctx, Values.getMember(args.ctx, match, "index"));
var matchVal = (String)arrMatch.get(0);
if (index >= target.length()) break;
@ -198,31 +183,33 @@ import me.topchetoeu.jscript.interop.NativeGetter;
}
if (sensible) {
if (limit != null && res.size() + added.size() >= lim) break;
else for (var i = 0; i < added.size(); i++) res.set(ctx, res.size(), added.get(i));
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++) {
if (limit != null && res.size() >= lim) return res;
else res.set(ctx, res.size(), added.get(i));
if (hasLimit && res.size() >= lim) return res;
else res.set(args.ctx, res.size(), added.get(i));
}
}
lastEnd = pattern.lastI;
}
if (lastEnd < target.length()) {
res.set(ctx, res.size(), target.substring(lastEnd));
res.set(args.ctx, res.size(), target.substring(lastEnd));
}
return res;
}
@Native("@@Symbol.replace") public String replace(Context ctx, String target, Object replacement) {
var pattern = new RegExpLib(this.source, this.flags() + "d");
@Expose("@@Symbol.replace") public String __replace(Arguments args) {
var pattern = this.toIndexed();
var target = args.getString(0);
var replacement = args.get(1);
Object match;
var lastEnd = 0;
var res = new StringBuilder();
while ((match = pattern.exec(target)) != Values.NULL) {
var indices = (ArrayValue)((ArrayValue)Values.getMember(ctx, match, "indices")).get(0);
while ((match = pattern.__exec(args)) != Values.NULL) {
var indices = (ArrayValue)((ArrayValue)Values.getMember(args.ctx, match, "indices")).get(0);
var arrMatch = (ArrayValue)match;
var start = ((Number)indices.get(0)).intValue();
@ -230,15 +217,15 @@ import me.topchetoeu.jscript.interop.NativeGetter;
res.append(target.substring(lastEnd, start));
if (replacement instanceof FunctionValue) {
var args = new Object[arrMatch.size() + 2];
args[0] = target.substring(start, end);
arrMatch.copyTo(args, 1, 1, arrMatch.size() - 1);
args[args.length - 2] = start;
args[args.length - 1] = target;
res.append(Values.toString(ctx, ((FunctionValue)replacement).call(ctx, null, args)));
var callArgs = new Object[arrMatch.size() + 2];
callArgs[0] = target.substring(start, end);
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)));
}
else {
res.append(Values.toString(ctx, replacement));
res.append(Values.toString(args.ctx, replacement));
}
lastEnd = end;
if (!pattern.global) break;
@ -271,9 +258,17 @@ import me.topchetoeu.jscript.interop.NativeGetter;
// }
// },
@Native public RegExpLib(Context ctx, Object pattern, Object flags) {
this(cleanupPattern(ctx, pattern), cleanupFlags(ctx, flags));
public RegExpLib toGlobal() {
return new RegExpLib(pattern, namedGroups, flags, source, hasIndices, true, sticky);
}
public RegExpLib toIndexed() {
return new RegExpLib(pattern, namedGroups, flags, source, true, global, sticky);
}
public String toString() {
return "/" + source + "/" + __flags();
}
public RegExpLib(String pattern, String flags) {
if (pattern == null || pattern.equals("")) pattern = "(?:)";
if (flags == null || flags.equals("")) flags = "";
@ -304,6 +299,56 @@ import me.topchetoeu.jscript.interop.NativeGetter;
namedGroups = groups.toArray(String[]::new);
}
private RegExpLib(Pattern pattern, String[] namedGroups, int flags, String source, boolean hasIndices, boolean global, boolean sticky) {
this.pattern = pattern;
this.namedGroups = namedGroups;
this.flags = flags;
this.source = source;
this.hasIndices = hasIndices;
this.global = global;
this.sticky = sticky;
}
public RegExpLib(String pattern) { this(pattern, null); }
public RegExpLib() { this(null, null); }
@ExposeConstructor
public static RegExpLib __constructor(Arguments args) {
return new RegExpLib(cleanupPattern(args.ctx, args.get(0)), cleanupFlags(args.ctx, 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)));
}
private static String cleanupPattern(Context ctx, 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);
if (res.equals("")) return "(?:)";
return res;
}
private static String cleanupFlags(Context ctx, Object val) {
if (val == null) return "";
return Values.toString(ctx, val);
}
private static boolean checkEscaped(String s, int pos) {
int n = 0;
while (true) {
if (pos <= 0) break;
if (s.charAt(pos) != '\\') break;
n++;
pos--;
}
return (n % 2) != 0;
}
public static RegExpLib escape(String raw, String flags) {
return new RegExpLib(ESCAPE_PATTERN.matcher(raw).replaceAll("\\\\$0"), flags);
}
}

View File

@ -6,55 +6,64 @@ import java.util.stream.Collectors;
import me.topchetoeu.jscript.engine.Context;
import me.topchetoeu.jscript.engine.values.ArrayValue;
import me.topchetoeu.jscript.engine.values.FunctionValue;
import me.topchetoeu.jscript.engine.values.ObjectValue;
import me.topchetoeu.jscript.engine.values.Values;
import me.topchetoeu.jscript.interop.Native;
import me.topchetoeu.jscript.interop.NativeGetter;
import me.topchetoeu.jscript.interop.Arguments;
import me.topchetoeu.jscript.interop.Expose;
import me.topchetoeu.jscript.interop.ExposeConstructor;
import me.topchetoeu.jscript.interop.ExposeType;
import me.topchetoeu.jscript.interop.WrapperName;
@Native("Set") public class SetLib {
@WrapperName("Set")
public class SetLib {
private LinkedHashSet<Object> set = new LinkedHashSet<>();
@Native("@@Symbol.typeName") public final String name = "Set";
@Native("@@Symbol.iterator") public ObjectValue iterator(Context ctx) {
return this.values(ctx);
@Expose("@@Symbol.iterator")
public ObjectValue __iterator(Arguments args) {
return this.__values(args);
}
@Native public ObjectValue entries(Context ctx) {
return ArrayValue.of(ctx, set.stream().map(v -> new ArrayValue(ctx, v, v)).collect(Collectors.toList()));
@Expose public ObjectValue __entries(Arguments args) {
return ArrayValue.of(args.ctx, set.stream().map(v -> new ArrayValue(args.ctx, v, v)).collect(Collectors.toList()));
}
@Native public ObjectValue keys(Context ctx) {
return ArrayValue.of(ctx, set);
@Expose public ObjectValue __keys(Arguments args) {
return ArrayValue.of(args.ctx, set);
}
@Native public ObjectValue values(Context ctx) {
return ArrayValue.of(ctx, set);
@Expose public ObjectValue __values(Arguments args) {
return ArrayValue.of(args.ctx, set);
}
@Native public Object add(Object key) {
return set.add(key);
@Expose public Object __add(Arguments args) {
return set.add(args.get(0));
}
@Native public boolean delete(Object key) {
return set.remove(key);
@Expose public boolean __delete(Arguments args) {
return set.remove(args.get(0));
}
@Native public boolean has(Object key) {
return set.contains(key);
@Expose public boolean __has(Arguments args) {
return set.contains(args.get(0));
}
@Native public void clear() {
@Expose public void __clear() {
set.clear();
}
@NativeGetter public int size() {
@Expose(type = ExposeType.GETTER)
public int __size() {
return set.size();
}
@Native public void forEach(Context ctx, FunctionValue func, Object thisArg) {
@Expose public void __forEach(Arguments args) {
var keys = new ArrayList<>(set);
for (var el : keys) func.call(ctx, thisArg, el, el, this);
for (var el : keys) Values.call(args.ctx, args.get(0), args.get(1), el, el, this);
}
@Native public SetLib(Context ctx, Object iterable) {
for (var el : Values.fromJSIterator(ctx, iterable)) add(el);
public SetLib(Context ctx, Object iterable) {
for (var el : Values.fromJSIterator(ctx, iterable)) set.add(el);
}
@ExposeConstructor
public static SetLib __constructor(Arguments args) {
return new SetLib(args.ctx, args.get(0));
}
}

View File

@ -2,7 +2,6 @@ package me.topchetoeu.jscript.lib;
import java.util.regex.Pattern;
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.FunctionValue;
@ -10,15 +9,20 @@ import me.topchetoeu.jscript.engine.values.ObjectValue;
import me.topchetoeu.jscript.engine.values.Symbol;
import me.topchetoeu.jscript.engine.values.Values;
import me.topchetoeu.jscript.exceptions.EngineException;
import me.topchetoeu.jscript.interop.Native;
import me.topchetoeu.jscript.interop.NativeConstructor;
import me.topchetoeu.jscript.interop.NativeGetter;
import me.topchetoeu.jscript.interop.Arguments;
import me.topchetoeu.jscript.interop.Expose;
import me.topchetoeu.jscript.interop.ExposeConstructor;
import me.topchetoeu.jscript.interop.ExposeTarget;
import me.topchetoeu.jscript.interop.ExposeType;
import me.topchetoeu.jscript.interop.WrapperName;
// TODO: implement index wrapping properly
@Native("String") public class StringLib {
@WrapperName("String")
public class StringLib {
public final String value;
private static String passThis(Context ctx, String funcName, Object val) {
private static String passThis(Arguments args, String funcName) {
var val = args.self;
if (val instanceof StringLib) return ((StringLib)val).value;
else if (val instanceof String) return (String)val;
else throw EngineException.ofType(String.format("'%s' may only be called upon object and primitve strings.", funcName));
@ -32,170 +36,174 @@ import me.topchetoeu.jscript.interop.NativeGetter;
return i;
}
@NativeGetter(thisArg = true) public static int length(Context ctx, Object thisArg) {
return passThis(ctx, "substring", thisArg).length();
@Expose(type = ExposeType.GETTER)
public static int __length(Arguments args) {
return passThis(args, "substring").length();
}
@Native(thisArg = true) public static String substring(Context ctx, Object thisArg, int start, Object _end) {
var val = passThis(ctx, "substring", thisArg);
start = normalizeI(start, val.length(), true);
int end = normalizeI(_end == null ? val.length() : (int)Values.toNumber(ctx, _end), val.length(), true);
@Expose public static String __substring(Arguments args) {
var val = passThis(args, "substring");
var start = normalizeI(args.getInt(0), val.length(), true);
var end = normalizeI(args.getInt(1, val.length()), val.length(), true);
return val.substring(start, end);
}
@Native(thisArg = true) public static String substr(Context ctx, Object thisArg, int start, Object _len) {
var val = passThis(ctx, "substr", thisArg);
int len = _len == null ? val.length() - start : (int)Values.toNumber(ctx, _len);
return substring(ctx, val, start, start + len);
@Expose public static String __substr(Arguments args) {
var val = passThis(args, "substr");
var start = normalizeI(args.getInt(0), val.length(), true);
int len = normalizeI(args.getInt(0), val.length() - start, true);
return val.substring(start, start + len);
}
@Native(thisArg = true) public static String toLowerCase(Context ctx, Object thisArg) {
return passThis(ctx, "toLowerCase", thisArg).toLowerCase();
@Expose public static String __toLowerCase(Arguments args) {
return passThis(args, "toLowerCase").toLowerCase();
}
@Native(thisArg = true) public static String toUpperCase(Context ctx, Object thisArg) {
return passThis(ctx, "toUpperCase", thisArg).toUpperCase();
@Expose public static String __toUpperCase(Arguments args) {
return passThis(args, "toUpperCase").toUpperCase();
}
@Native(thisArg = true) public static String charAt(Context ctx, Object thisArg, int i) {
return passThis(ctx, "charAt", thisArg).charAt(i) + "";
@Expose public static String __charAt(Arguments args) {
return passThis(args, "charAt").charAt(args.getInt(0)) + "";
}
@Native(thisArg = true) public static double charCodeAt(Context ctx, Object thisArg, int i) {
var str = passThis(ctx, "charCodeAt", thisArg);
@Expose public static double __charCodeAt(Arguments args) {
var str = passThis(args, "charCodeAt");
var i = args.getInt(0);
if (i < 0 || i >= str.length()) return Double.NaN;
else return str.charAt(i);
}
@Native(thisArg = true) public static double codePointAt(Context ctx, Object thisArg, int i) {
var str = passThis(ctx, "codePointAt", thisArg);
@Expose public static double __codePointAt(Arguments args) {
var str = passThis(args, "codePointAt");
var i = args.getInt(0);
if (i < 0 || i >= str.length()) return Double.NaN;
else return str.codePointAt(i);
}
@Native(thisArg = true) public static boolean startsWith(Context ctx, Object thisArg, String term, int pos) {
return passThis(ctx, "startsWith", thisArg).startsWith(term, pos);
@Expose public static boolean __startsWith(Arguments args) {
return passThis(args, "startsWith").startsWith(args.getString(0), args.getInt(1));
}
@Native(thisArg = true) public static boolean endsWith(Context ctx, Object thisArg, String term, int pos) {
var val = passThis(ctx, "endsWith", thisArg);
return val.lastIndexOf(term, pos) >= 0;
@Expose public static boolean __endsWith(Arguments args) {
return passThis(args, "endsWith").lastIndexOf(args.getString(0), args.getInt(1)) >= 0;
}
@Native(thisArg = true) public static int indexOf(Context ctx, Object thisArg, Object term, int start) {
var val = passThis(ctx, "indexOf", thisArg);
@Expose public static int __indexOf(Arguments args) {
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"));
if (term != null && term != Values.NULL && !(term instanceof String)) {
var search = Values.getMember(ctx, term, Symbol.get("Symbol.search"));
if (search instanceof FunctionValue) {
return (int)Values.toNumber(ctx, ((FunctionValue)search).call(ctx, term, val, false, start));
return (int)Values.toNumber(args.ctx, Values.call(args.ctx, search, term, val, false, start));
}
else return val.indexOf(Values.toString(args.ctx, 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"));
return val.indexOf(Values.toString(ctx, term), start);
}
@Native(thisArg = true) public static int lastIndexOf(Context ctx, Object thisArg, Object term, int pos) {
var val = passThis(ctx, "lastIndexOf", thisArg);
if (term != null && term != Values.NULL && !(term instanceof String)) {
var search = Values.getMember(ctx, term, Symbol.get("Symbol.search"));
if (search instanceof FunctionValue) {
return (int)Values.toNumber(ctx, ((FunctionValue)search).call(ctx, term, val, true, pos));
return (int)Values.toNumber(args.ctx, Values.call(args.ctx, search, term, val, true, start));
}
else return val.lastIndexOf(Values.toString(args.ctx, term), start);
}
return val.lastIndexOf(Values.toString(ctx, term), pos);
@Expose public static boolean __includes(Arguments args) {
return __indexOf(args) >= 0;
}
@Native(thisArg = true) public static boolean includes(Context ctx, Object thisArg, Object term, int pos) {
return indexOf(ctx, passThis(ctx, "includes", thisArg), term, pos) >= 0;
}
@Expose public static String __replace(Arguments args) {
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"));
@Native(thisArg = true) public static String replace(Context ctx, Object thisArg, Object term, Object replacement) {
var val = passThis(ctx, "replace", thisArg);
if (term != null && term != Values.NULL && !(term instanceof String)) {
var replace = Values.getMember(ctx, term, Symbol.get("Symbol.replace"));
if (replace instanceof FunctionValue) {
return Values.toString(ctx, ((FunctionValue)replace).call(ctx, term, val, replacement));
return Values.toString(args.ctx, Values.call(args.ctx, replace, term, val, replacement));
}
else return val.replaceFirst(Pattern.quote(Values.toString(args.ctx, term)), Values.toString(args.ctx, 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"));
return val.replaceFirst(Pattern.quote(Values.toString(ctx, term)), Values.toString(ctx, replacement));
}
@Native(thisArg = true) public static String replaceAll(Context ctx, Object thisArg, Object term, Object replacement) {
var val = passThis(ctx, "replaceAll", thisArg);
if (term != null && term != Values.NULL && !(term instanceof String)) {
var replace = Values.getMember(ctx, term, Symbol.get("Symbol.replace"));
if (replace instanceof FunctionValue) {
return Values.toString(ctx, ((FunctionValue)replace).call(ctx, term, val, replacement));
return Values.toString(args.ctx, Values.call(args.ctx, replace, term, val, replacement));
}
else return val.replace(Values.toString(args.ctx, term), Values.toString(args.ctx, replacement));
}
return val.replaceFirst(Pattern.quote(Values.toString(ctx, term)), Values.toString(ctx, replacement));
}
@Native(thisArg = true) public static ArrayValue match(Context ctx, Object thisArg, Object term, String replacement) {
var val = passThis(ctx, "match", thisArg);
@Expose public static ArrayValue __match(Arguments args) {
var val = passThis(args, "match");
var term = args.get(0);
FunctionValue match;
try {
var _match = Values.getMember(ctx, term, Symbol.get("Symbol.match"));
var _match = Values.getMember(args.ctx, term, Symbol.get("Symbol.match"));
if (_match instanceof FunctionValue) match = (FunctionValue)_match;
else if (ctx.has(Environment.REGEX_CONSTR)) {
var regex = Values.callNew(ctx, ctx.get(Environment.REGEX_CONSTR), Values.toString(ctx, term), "");
_match = Values.getMember(ctx, regex, Symbol.get("Symbol.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"));
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(ctx, ""); }
catch (IllegalArgumentException e) { return new ArrayValue(args.ctx, ""); }
var res = match.call(ctx, term, val);
var res = match.call(args.ctx, term, val);
if (res instanceof ArrayValue) return (ArrayValue)res;
else return new ArrayValue(ctx, "");
else return new ArrayValue(args.ctx, "");
}
@Native(thisArg = true) public static Object matchAll(Context ctx, Object thisArg, Object term, String replacement) {
var val = passThis(ctx, "matchAll", thisArg);
@Expose public static Object __matchAll(Arguments args) {
var val = passThis(args, "matchAll");
var term = args.get(0);
FunctionValue match = null;
try {
var _match = Values.getMember(ctx, term, Symbol.get("Symbol.matchAll"));
var _match = Values.getMember(args.ctx, term, Symbol.get("Symbol.matchAll"));
if (_match instanceof FunctionValue) match = (FunctionValue)_match;
}
catch (IllegalArgumentException e) { }
if (match == null && ctx.has(Environment.REGEX_CONSTR)) {
var regex = Values.callNew(ctx, ctx.get(Environment.REGEX_CONSTR), Values.toString(ctx, term), "g");
var _match = Values.getMember(ctx, regex, Symbol.get("Symbol.matchAll"));
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 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(ctx, term, val);
return match.call(args.ctx, term, val);
}
@Native(thisArg = true) public static ArrayValue split(Context ctx, Object thisArg, Object term, Object lim, boolean sensible) {
var val = passThis(ctx, "split", thisArg);
@Expose public static ArrayValue __split(Arguments args) {
var val = passThis(args, "split");
var term = args.get(0);
var lim = args.get(1);
var sensible = args.getBoolean(2);
if (lim != null) lim = Values.toNumber(ctx, lim);
if (lim != null) lim = Values.toNumber(args.ctx, lim);
if (term != null && term != Values.NULL && !(term instanceof String)) {
var replace = Values.getMember(ctx, term, Symbol.get("Symbol.replace"));
var replace = Values.getMember(args.ctx, term, Symbol.get("Symbol.replace"));
if (replace instanceof FunctionValue) {
var tmp = ((FunctionValue)replace).call(ctx, term, val, lim, sensible);
var tmp = ((FunctionValue)replace).call(args.ctx, 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(ctx, i, Values.toString(ctx, ((ArrayValue)tmp).get(i)));
for (int i = 0; i < parts.size(); i++) parts.set(args.ctx, i, Values.toString(args.ctx, ((ArrayValue)tmp).get(i)));
return parts;
}
}
}
String[] parts;
var pattern = Pattern.quote(Values.toString(ctx, term));
var pattern = Pattern.quote(Values.toString(args.ctx, term));
if (lim == null) parts = val.split(pattern);
else if (sensible) parts = val.split(pattern, (int)(double)lim);
@ -207,7 +215,7 @@ import me.topchetoeu.jscript.interop.NativeGetter;
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(ctx, i, parts[i]);
for (var i = 0; i < parts.length && i < limit; i++) res.set(args.ctx, i, parts[i]);
return res;
}
@ -217,46 +225,49 @@ import me.topchetoeu.jscript.interop.NativeGetter;
for (; i < parts.length; i++) {
if (lim != null && (double)lim <= i) break;
res.set(ctx, i, parts[i]);
res.set(args.ctx, i, parts[i]);
}
return res;
}
@Native(thisArg = true) public static String slice(Context ctx, Object thisArg, int start, Object _end) {
return substring(ctx, passThis(ctx, "slice", thisArg), start, _end);
@Expose public static String __slice(Arguments args) {
passThis(args, "slice");
return __substring(args);
}
@Native(thisArg = true) public static String concat(Context ctx, Object thisArg, Object... args) {
var res = new StringBuilder(passThis(ctx, "concat", thisArg));
@Expose public static String __concat(Arguments args) {
var res = new StringBuilder(passThis(args, "concat"));
for (var el : args) res.append(Values.toString(ctx, el));
for (var el : args.convert(String.class)) res.append(el);
return res.toString();
}
@Native(thisArg = true) public static String trim(Context ctx, Object thisArg) {
return passThis(ctx, "trim", thisArg).trim();
@Expose public static String __trim(Arguments args) {
return passThis(args, "trim").trim();
}
@Native(thisArg = true) public static String trimStart(Context ctx, Object thisArg) {
return passThis(ctx, "trimStart", thisArg).replaceAll("^\\s+", "");
@Expose public static String __trimStart(Arguments args) {
return passThis(args, "trimStart").replaceAll("^\\s+", "");
}
@Native(thisArg = true) public static String trimEnd(Context ctx, Object thisArg) {
return passThis(ctx, "trimEnd", thisArg).replaceAll("\\s+$", "");
@Expose public static String __trimEnd(Arguments args) {
return passThis(args, "trimEnd").replaceAll("\\s+$", "");
}
@NativeConstructor(thisArg = true) public static Object constructor(Context ctx, Object thisArg, Object val) {
val = Values.toString(ctx, val);
if (thisArg instanceof ObjectValue) return new StringLib((String)val);
@ExposeConstructor public static Object __constructor(Arguments args) {
var val = args.getString(0);
if (args.self instanceof ObjectValue) return new StringLib(val);
else return val;
}
@Native(thisArg = true) public static String toString(Context ctx, Object thisArg) {
return passThis(ctx, "toString", thisArg);
@Expose public static String __toString(Arguments args) {
return passThis(args, "toString");
}
@Native(thisArg = true) public static String valueOf(Context ctx, Object thisArg) {
return passThis(ctx, "valueOf", thisArg);
@Expose public static String __valueOf(Arguments args) {
return passThis(args, "valueOf");
}
@Native public static String fromCharCode(int ...val) {
@Expose(target = ExposeTarget.STATIC)
public static String __fromCharCode(Arguments args) {
var val = args.convertInt();
char[] arr = new char[val.length];
for (var i = 0; i < val.length; i++) arr[i] = (char)val[i];
return new String(arr);

View File

@ -3,48 +3,69 @@ package me.topchetoeu.jscript.lib;
import java.util.HashMap;
import java.util.Map;
import me.topchetoeu.jscript.engine.Context;
import me.topchetoeu.jscript.engine.values.ObjectValue;
import me.topchetoeu.jscript.engine.values.Symbol;
import me.topchetoeu.jscript.engine.values.Values;
import me.topchetoeu.jscript.exceptions.EngineException;
import me.topchetoeu.jscript.interop.Native;
import me.topchetoeu.jscript.interop.NativeConstructor;
import me.topchetoeu.jscript.interop.Arguments;
import me.topchetoeu.jscript.interop.Expose;
import me.topchetoeu.jscript.interop.ExposeConstructor;
import me.topchetoeu.jscript.interop.ExposeField;
import me.topchetoeu.jscript.interop.ExposeTarget;
import me.topchetoeu.jscript.interop.WrapperName;
@Native("Symbol") public class SymbolLib {
@WrapperName("Symbol")
public class SymbolLib {
private static final Map<String, Symbol> symbols = new HashMap<>();
@Native public static final Symbol typeName = Symbol.get("Symbol.typeName");
@Native public static final Symbol replace = Symbol.get("Symbol.replace");
@Native public static final Symbol match = Symbol.get("Symbol.match");
@Native public static final Symbol matchAll = Symbol.get("Symbol.matchAll");
@Native public static final Symbol split = Symbol.get("Symbol.split");
@Native public static final Symbol search = Symbol.get("Symbol.search");
@Native public static final Symbol iterator = Symbol.get("Symbol.iterator");
@Native public static final Symbol asyncIterator = Symbol.get("Symbol.asyncIterator");
@Native public static final Symbol cause = Symbol.get("Symbol.cause");
@ExposeField(target = ExposeTarget.STATIC)
public static final Symbol __typeName = Symbol.get("Symbol.typeName");
@ExposeField(target = ExposeTarget.STATIC)
public static final Symbol __replace = Symbol.get("Symbol.replace");
@ExposeField(target = ExposeTarget.STATIC)
public static final Symbol __match = Symbol.get("Symbol.match");
@ExposeField(target = ExposeTarget.STATIC)
public static final Symbol __matchAll = Symbol.get("Symbol.matchAll");
@ExposeField(target = ExposeTarget.STATIC)
public static final Symbol __split = Symbol.get("Symbol.split");
@ExposeField(target = ExposeTarget.STATIC)
public static final Symbol __search = Symbol.get("Symbol.search");
@ExposeField(target = ExposeTarget.STATIC)
public static final Symbol __iterator = Symbol.get("Symbol.iterator");
@ExposeField(target = ExposeTarget.STATIC)
public static final Symbol __asyncIterator = Symbol.get("Symbol.asyncIterator");
@ExposeField(target = ExposeTarget.STATIC)
public static final Symbol __cause = Symbol.get("Symbol.cause");
public final Symbol value;
private static Symbol passThis(Context ctx, String funcName, Object val) {
private static Symbol passThis(Arguments args, String funcName) {
var val = args.self;
if (val instanceof SymbolLib) return ((SymbolLib)val).value;
else if (val instanceof Symbol) return (Symbol)val;
else throw EngineException.ofType(String.format("'%s' may only be called upon object and primitve symbols.", funcName));
}
@NativeConstructor(thisArg = true) public static Object constructor(Context ctx, Object thisArg, Object val) {
if (thisArg instanceof ObjectValue) throw EngineException.ofType("Symbol constructor may not be called with new.");
if (val == null) return new Symbol("");
else return new Symbol(Values.toString(ctx, val));
}
@Native(thisArg = true) public static String toString(Context ctx, Object thisArg) {
return passThis(ctx, "toString", thisArg).value;
}
@Native(thisArg = true) public static Symbol valueOf(Context ctx, Object thisArg) {
return passThis(ctx, "valueOf", thisArg);
public SymbolLib(Symbol val) {
this.value = val;
}
@Native("for") public static Symbol _for(String key) {
@Expose public static String __toString(Arguments args) {
return passThis(args, "toString").value;
}
@Expose public static Symbol __valueOf(Arguments args) {
return passThis(args, "valueOf");
}
@ExposeConstructor
public static Object __constructor(Arguments args) {
if (args.self instanceof ObjectValue) throw EngineException.ofType("Symbol constructor may not be called with new.");
if (args.get(0) == null) return new Symbol("");
else return new Symbol(args.getString(0));
}
@Expose(target = ExposeTarget.STATIC)
public static Symbol __for(Arguments args) {
var key = args.getString(0);
if (symbols.containsKey(key)) return symbols.get(key);
else {
var sym = new Symbol(key);
@ -52,11 +73,8 @@ import me.topchetoeu.jscript.interop.NativeConstructor;
return sym;
}
}
@Native public static String keyFor(Symbol sym) {
return sym.value;
}
public SymbolLib(Symbol val) {
this.value = val;
@Expose(target = ExposeTarget.STATIC)
public static String __keyFor(Arguments args) {
return passThis(args.slice(-1), "keyFor").value;
}
}

View File

@ -1,21 +1,22 @@
package me.topchetoeu.jscript.lib;
import me.topchetoeu.jscript.engine.Context;
import me.topchetoeu.jscript.engine.Environment;
import me.topchetoeu.jscript.engine.values.ObjectValue;
import me.topchetoeu.jscript.engine.values.ObjectValue.PlaceholderProto;
import me.topchetoeu.jscript.interop.InitType;
import me.topchetoeu.jscript.interop.Native;
import me.topchetoeu.jscript.interop.NativeConstructor;
import me.topchetoeu.jscript.interop.NativeInit;
import me.topchetoeu.jscript.interop.WrapperName;
import me.topchetoeu.jscript.interop.Arguments;
import me.topchetoeu.jscript.interop.ExposeConstructor;
import me.topchetoeu.jscript.interop.ExposeField;
import me.topchetoeu.jscript.interop.ExposeTarget;
@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);
@WrapperName("SyntaxError")
public class SyntaxErrorLib extends ErrorLib {
@ExposeField(target = ExposeTarget.STATIC)
public static final String __name = "SyntaxError";
@ExposeConstructor
public static ObjectValue __constructor(Arguments args) {
var target = ErrorLib.__constructor(args);
target.setPrototype(PlaceholderProto.SYNTAX_ERROR);
return target;
}
@NativeInit(InitType.PROTOTYPE) public static void init(Environment env, ObjectValue target) {
target.defineProperty(null, "name", "SyntaxError");
}
}

View File

@ -1,21 +1,22 @@
package me.topchetoeu.jscript.lib;
import me.topchetoeu.jscript.engine.Context;
import me.topchetoeu.jscript.engine.Environment;
import me.topchetoeu.jscript.engine.values.ObjectValue;
import me.topchetoeu.jscript.engine.values.ObjectValue.PlaceholderProto;
import me.topchetoeu.jscript.interop.InitType;
import me.topchetoeu.jscript.interop.Native;
import me.topchetoeu.jscript.interop.NativeConstructor;
import me.topchetoeu.jscript.interop.NativeInit;
import me.topchetoeu.jscript.interop.WrapperName;
import me.topchetoeu.jscript.interop.Arguments;
import me.topchetoeu.jscript.interop.ExposeConstructor;
import me.topchetoeu.jscript.interop.ExposeField;
import me.topchetoeu.jscript.interop.ExposeTarget;
@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.setPrototype(PlaceholderProto.SYNTAX_ERROR);
@WrapperName("TypeError")
public class TypeErrorLib extends ErrorLib {
@ExposeField(target = ExposeTarget.STATIC)
public static final String __name = "TypeError";
@ExposeConstructor
public static ObjectValue __constructor(Arguments args) {
var target = ErrorLib.__constructor(args);
target.setPrototype(PlaceholderProto.TYPE_ERROR);
return target;
}
@NativeInit(InitType.PROTOTYPE) public static void init(Environment env, ObjectValue target) {
target.defineProperty(null, "name", "TypeError");
}
}