feat: use new wrapper API in libs
This commit is contained in:
parent
a61c6a494e
commit
4fa5f5a815
4
build.js
4
build.js
@ -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('[-/\\\\^$*+?.()|[\\]{}]', '[-/\\\\^$*+?.()|\\[\\]{}]');
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
@ -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), ",/?:@&=+$#.");
|
||||
}
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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; }
|
||||
});
|
||||
}
|
||||
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
@ -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.");
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
@ -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) {
|
||||
|
@ -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)));
|
||||
}
|
||||
}
|
||||
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
@ -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); }
|
||||
@Expose(target = ExposeTarget.STATIC)
|
||||
public static double __sign(Arguments args) {
|
||||
return Math.signum(args.getDouble(0));
|
||||
}
|
||||
|
||||
@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 __random() { return Math.random(); }
|
||||
@Expose(target = ExposeTarget.STATIC)
|
||||
public static int __clz32(Arguments args) {
|
||||
return Integer.numberOfLeadingZeros(args.getInt(0));
|
||||
}
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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");
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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");
|
||||
}
|
||||
}
|
@ -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");
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user