feat: use new wrapper API in libs

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

View File

@ -76,9 +76,11 @@ async function downloadTypescript(outFile) {
console.log('Minifying typescript...'); 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; if (minified.error) throw minified.error;
// Patch unsupported regex syntax // Patch unsupported regex syntax
minified.code = minified.code.replaceAll('[-/\\\\^$*+?.()|[\\]{}]', '[-/\\\\^$*+?.()|\\[\\]{}]'); minified.code = minified.code.replaceAll('[-/\\\\^$*+?.()|[\\]{}]', '[-/\\\\^$*+?.()|\\[\\]{}]');

View File

@ -3,107 +3,20 @@ package me.topchetoeu.jscript.lib;
import java.util.Iterator; import java.util.Iterator;
import java.util.Stack; import java.util.Stack;
import me.topchetoeu.jscript.engine.Context;
import me.topchetoeu.jscript.engine.values.ArrayValue; import me.topchetoeu.jscript.engine.values.ArrayValue;
import me.topchetoeu.jscript.engine.values.FunctionValue; import me.topchetoeu.jscript.engine.values.FunctionValue;
import me.topchetoeu.jscript.engine.values.NativeFunction; import me.topchetoeu.jscript.engine.values.NativeFunction;
import me.topchetoeu.jscript.engine.values.ObjectValue; import me.topchetoeu.jscript.engine.values.ObjectValue;
import me.topchetoeu.jscript.engine.values.Values; import me.topchetoeu.jscript.engine.values.Values;
import me.topchetoeu.jscript.interop.Native; import me.topchetoeu.jscript.interop.Arguments;
import me.topchetoeu.jscript.interop.NativeConstructor; import me.topchetoeu.jscript.interop.Expose;
import me.topchetoeu.jscript.interop.NativeGetter; import me.topchetoeu.jscript.interop.ExposeConstructor;
import me.topchetoeu.jscript.interop.NativeSetter; import me.topchetoeu.jscript.interop.ExposeTarget;
import me.topchetoeu.jscript.interop.ExposeType;
@Native("Array") public class ArrayLib { import me.topchetoeu.jscript.interop.WrapperName;
@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;
}
@WrapperName("Array")
public class ArrayLib {
private static int normalizeI(int len, int i, boolean clamp) { private static int normalizeI(int len, int i, boolean clamp) {
if (i < 0) i += len; if (i < 0) i += len;
if (clamp) { if (clamp) {
@ -113,91 +26,202 @@ import me.topchetoeu.jscript.interop.NativeSetter;
return i; return i;
} }
@Native(thisArg = true) public static ArrayValue fill(Context ctx, ArrayValue arr, Object val, int start, int end) { @Expose(value = "length", type = ExposeType.GETTER)
start = normalizeI(arr.size(), start, true); public static int __getLength(Arguments args) {
end = normalizeI(arr.size(), end, true); 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));
}
for (; start < end; start++) { @Expose public static ObjectValue __values(Arguments args) {
arr.set(ctx, start, val); 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; return arr;
} }
@Native(thisArg = true) public static ArrayValue fill(Context ctx, ArrayValue arr, Object val, int start) { @Expose public static boolean __every(Arguments args) {
return fill(ctx, arr, val, start, arr.size()); var arr = args.self(ArrayValue.class);
} var func = args.convert(0, FunctionValue.class);
@Native(thisArg = true) public static ArrayValue fill(Context ctx, ArrayValue arr, Object val) { var thisArg = args.get(1);
return fill(ctx, arr, val, 0, arr.size());
}
@Native(thisArg = true) public static boolean every(Context ctx, ArrayValue arr, FunctionValue func, Object thisArg) {
for (var i = 0; i < arr.size(); i++) { 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; 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++) { 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; return false;
} }
@Expose public static ArrayValue __filter(Arguments args) {
@Native(thisArg = true) public static ArrayValue filter(Context ctx, ArrayValue arr, FunctionValue func, Object thisArg) { var arr = args.self(ArrayValue.class);
var func = args.convert(0, FunctionValue.class);
var thisArg = args.get(1);
var res = new ArrayValue(arr.size()); var res = new ArrayValue(arr.size());
for (int i = 0, j = 0; i < arr.size(); i++) { 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; 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()); var res = new ArrayValue(arr.size());
res.setSize(arr.size());
for (int i = 0, j = 0; i < arr.size(); i++) { 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; 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++) { 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 i = 0;
var res = arr.get(0);
if (args.length > 0) res = args[0]; if (args.n() < 2) for (; !arr.has(i) && i < arr.size(); i++) res = arr.get(i);
else for (; !arr.has(i) && i < arr.size(); i++) res = arr.get(i);
for (; i < arr.size(); i++) { for (; i < arr.size(); i++) {
if (arr.has(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; 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 i = arr.size();
var res = arr.get(0);
if (args.length > 0) res = args[0]; if (args.n() < 1) while (!arr.has(i--) && i >= 0) res = arr.get(i);
else while (!arr.has(i--) && i >= 0) res = arr.get(i);
for (; i >= 0; i--) { for (; i >= 0; i--) {
if (arr.has(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; 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 res = new ArrayValue(arr.size());
var stack = new Stack<Object>(); var stack = new Stack<Object>();
var depths = new Stack<Integer>(); var depths = new Stack<Integer>();
@ -209,127 +233,165 @@ import me.topchetoeu.jscript.interop.NativeSetter;
var el = stack.pop(); var el = stack.pop();
int d = depths.pop(); int d = depths.pop();
if (d <= depth && el instanceof ArrayValue) { if ((d == -1 || d < depth) && el instanceof ArrayValue) {
for (int i = ((ArrayValue)el).size() - 1; i >= 0; i--) { var arrEl = (ArrayValue)el;
stack.push(((ArrayValue)el).get(i)); for (int i = arrEl.size() - 1; i >= 0; i--) {
if (!arrEl.has(i)) continue;
stack.push(arrEl.get(i));
depths.push(d + 1); depths.push(d + 1);
} }
} }
else res.set(ctx, depth, arr); else res.set(args.ctx, res.size(), el);
} }
return res; return res;
} }
@Native(thisArg = true) public static ArrayValue flatMap(Context ctx, ArrayValue arr, FunctionValue cmp, Object thisArg) { @Expose public static ArrayValue __flatMap(Arguments args) {
return flat(ctx, map(ctx, arr, cmp, thisArg), 1); 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++) { 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; 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--) { 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; 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++) { 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; 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--) { 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; return -1;
} }
@Native(thisArg = true) public static int indexOf(Context ctx, ArrayValue arr, Object val, int start) { @Expose public static int __indexOf(Arguments args) {
start = normalizeI(arr.size(), start, true); 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++) { 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; return -1;
} }
@Native(thisArg = true) public static int lastIndexOf(Context ctx, ArrayValue arr, Object val, int start) { @Expose public static int __lastIndexOf(Arguments args) {
start = normalizeI(arr.size(), start, true); 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--) { 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; return -1;
} }
@Native(thisArg = true) public static boolean includes(Context ctx, ArrayValue arr, Object el, int start) { @Expose public static boolean __includes(Arguments args) {
return indexOf(ctx, arr, el, start) >= 0; 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; if (arr.size() == 0) return null;
var val = arr.get(arr.size() - 1); var val = arr.get(arr.size() - 1);
arr.shrink(1); arr.shrink(1);
return val; return val;
} }
@Native(thisArg = true) public static int push(Context ctx, ArrayValue arr, Object ...values) { @Expose public static int __push(Arguments args) {
arr.copyFrom(ctx, values, 0, arr.size(), values.length); var arr = args.self(ArrayValue.class);
var values = args.args;
arr.copyFrom(args.ctx, values, 0, arr.size(), values.length);
return arr.size(); 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; if (arr.size() == 0) return null;
var val = arr.get(0); var val = arr.get(0);
arr.move(1, 0, arr.size()); arr.move(1, 0, arr.size());
arr.shrink(1); arr.shrink(1);
return val; 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.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(); return arr.size();
} }
@Native(thisArg = true) public static ArrayValue slice(Context ctx, ArrayValue arr, int start, Object _end) { @Expose public static ArrayValue __slice(Arguments args) {
start = normalizeI(arr.size(), start, true); var arr = args.self(ArrayValue.class);
int end = normalizeI(arr.size(), (int)(_end == null ? arr.size() : Values.toNumber(ctx, _end)), true); 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); 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; return res;
} }
@Native(thisArg = true) public static ArrayValue splice(Context ctx, ArrayValue arr, int start, Object _deleteCount, Object ...items) { @Expose public static ArrayValue __splice(Arguments args) {
start = normalizeI(arr.size(), start, true); var arr = args.self(ArrayValue.class);
int deleteCount = _deleteCount == null ? arr.size() - 1 : (int)Values.toNumber(ctx, _deleteCount); var start = normalizeI(arr.size(), args.getInt(0), true);
deleteCount = normalizeI(arr.size(), deleteCount, 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; if (start + deleteCount >= arr.size()) deleteCount = arr.size() - start;
var size = arr.size() - deleteCount + items.length; var size = arr.size() - deleteCount + items.length;
var res = new ArrayValue(deleteCount); 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.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); arr.setSize(size);
return res; return res;
} }
@Native(thisArg = true) public static String toString(Context ctx, ArrayValue arr) { @Expose public static String __toString(Arguments args) {
return join(ctx, arr, ","); 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 res = new StringBuilder();
var comma = false; var comma = false;
@ -342,30 +404,33 @@ import me.topchetoeu.jscript.interop.NativeSetter;
var el = arr.get(i); var el = arr.get(i);
if (el == null || el == Values.NULL) continue; if (el == null || el == Values.NULL) continue;
res.append(Values.toString(ctx, el)); res.append(Values.toString(args.ctx, el));
} }
return res.toString(); return res.toString();
} }
@Native public static boolean isArray(Context ctx, Object val) { return val instanceof ArrayValue; } @Expose(target = ExposeTarget.STATIC)
@Native public static ArrayValue of(Context ctx, Object... args) { public static boolean __isArray(Arguments args) {
var res = new ArrayValue(args.length); return args.get(0) instanceof ArrayValue;
res.copyFrom(ctx, args, 0, 0, args.length); }
return res; @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; ArrayValue res;
if (args.length == 1 && args[0] instanceof Number) { if (args.n() == 1 && args.get(0) instanceof Number) {
int len = ((Number)args[0]).intValue(); var len = args.getInt(0);
res = new ArrayValue(len); res = new ArrayValue(len);
res.setSize(len); res.setSize(len);
} }
else { else {
res = new ArrayValue(args.length); var val = args.slice(0).args;
res.copyFrom(ctx, args, 0, 0, args.length); res = new ArrayValue(val.length);
res.copyFrom(args.ctx, val, 0, 0, val.length);
} }
return res; return res;

View File

@ -7,55 +7,60 @@ import me.topchetoeu.jscript.engine.values.CodeFunction;
import me.topchetoeu.jscript.engine.values.FunctionValue; import me.topchetoeu.jscript.engine.values.FunctionValue;
import me.topchetoeu.jscript.engine.values.NativeFunction; import me.topchetoeu.jscript.engine.values.NativeFunction;
import me.topchetoeu.jscript.exceptions.EngineException; import me.topchetoeu.jscript.exceptions.EngineException;
import me.topchetoeu.jscript.interop.Native; 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 final FunctionValue factory;
public static class AsyncHelper { private static class AsyncHelper {
public PromiseLib promise = new PromiseLib(); public PromiseLib promise = new PromiseLib();
public CodeFrame frame; public CodeFrame frame;
private boolean awaiting = false; 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; Object res = null;
frame.onPush(); frame.onPush();
awaiting = false; awaiting = false;
while (!awaiting) { while (!awaiting) {
try { try {
res = frame.next(inducedValue, Runners.NO_RETURN, inducedError == Runners.NO_RETURN ? null : new EngineException(inducedError)); res = frame.next(inducedValue, Runners.NO_RETURN, inducedError);
inducedValue = inducedError = Runners.NO_RETURN; inducedValue = Runners.NO_RETURN;
inducedError = null;
if (res != Runners.NO_RETURN) { if (res != Runners.NO_RETURN) {
promise.fulfill(ctx, res); promise.fulfill(ctx, res);
break; break;
} }
} }
catch (EngineException e) { catch (EngineException e) {
promise.reject(ctx, e.value); promise.reject(ctx, e);
break; break;
} }
} }
frame.onPop(); frame.onPop();
if (awaiting) { 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) { public Object await(Arguments 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) {
this.awaiting = true; 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)); 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."); 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.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; return handler.promise;
} }

View File

@ -6,9 +6,10 @@ import me.topchetoeu.jscript.engine.values.CodeFunction;
import me.topchetoeu.jscript.engine.values.FunctionValue; import me.topchetoeu.jscript.engine.values.FunctionValue;
import me.topchetoeu.jscript.engine.values.NativeFunction; import me.topchetoeu.jscript.engine.values.NativeFunction;
import me.topchetoeu.jscript.exceptions.EngineException; import me.topchetoeu.jscript.exceptions.EngineException;
import me.topchetoeu.jscript.interop.Native; import me.topchetoeu.jscript.interop.WrapperName;
@Native("AsyncGeneratorFunction") public class AsyncGeneratorFunctionLib extends FunctionValue { @WrapperName("AsyncGeneratorFunction")
public class AsyncGeneratorFunctionLib extends FunctionValue {
public final FunctionValue factory; public final FunctionValue factory;
@Override @Override

View File

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

View File

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

View File

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

View File

@ -1,20 +1,89 @@
package me.topchetoeu.jscript.lib; 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.ArrayValue;
import me.topchetoeu.jscript.engine.values.Values; 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 { 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(); 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; 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()]; 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); return new String(res);
} }
@Expose(target = ExposeTarget.STATIC)
public static String __encodeURIComponent(Arguments args) {
return EncodingLib.encodeUriAny(args.getString(0), ".-_!~*'()");
}
@Expose(target = ExposeTarget.STATIC)
public static String __decodeURIComponent(Arguments args) {
return decodeUriAny(args.getString(0), "");
}
@Expose(target = ExposeTarget.STATIC)
public static String __encodeURI(Arguments args) {
return encodeUriAny(args.getString(0), ";,/?:@&=+$#.-_!~*'()");
}
@Expose(target = ExposeTarget.STATIC)
public static String __decodeURI(Arguments args) {
return decodeUriAny(args.getString(0), ",/?:@&=+$#.");
}
} }

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -6,13 +6,13 @@ import me.topchetoeu.jscript.engine.values.CodeFunction;
import me.topchetoeu.jscript.engine.values.FunctionValue; import me.topchetoeu.jscript.engine.values.FunctionValue;
import me.topchetoeu.jscript.engine.values.NativeFunction; import me.topchetoeu.jscript.engine.values.NativeFunction;
import me.topchetoeu.jscript.exceptions.EngineException; import me.topchetoeu.jscript.exceptions.EngineException;
import me.topchetoeu.jscript.interop.Native; import me.topchetoeu.jscript.interop.WrapperName;
@Native("GeneratorFunction") public class GeneratorFunctionLib extends FunctionValue { @WrapperName("GeneratorFunction")
public class GeneratorFunctionLib extends FunctionValue {
public final FunctionValue factory; public final FunctionValue factory;
@Override @Override public Object call(Context ctx, Object thisArg, Object ...args) {
public Object call(Context ctx, Object thisArg, Object ...args) {
var handler = new GeneratorLib(); var handler = new GeneratorLib();
var func = factory.call(ctx, thisArg, new NativeFunction("yield", handler::yield)); 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."); if (!(func instanceof CodeFunction)) throw EngineException.ofType("Return value of argument must be a js function.");

View File

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

View File

@ -1,44 +1,50 @@
package me.topchetoeu.jscript.lib; package me.topchetoeu.jscript.lib;
import java.io.IOException; import java.io.IOException;
import java.util.HashMap;
import me.topchetoeu.jscript.Buffer;
import me.topchetoeu.jscript.Reading; import me.topchetoeu.jscript.Reading;
import me.topchetoeu.jscript.engine.Context;
import me.topchetoeu.jscript.engine.Environment; import me.topchetoeu.jscript.engine.Environment;
import me.topchetoeu.jscript.engine.scope.GlobalScope; import me.topchetoeu.jscript.engine.scope.GlobalScope;
import me.topchetoeu.jscript.engine.values.FunctionValue; import me.topchetoeu.jscript.engine.values.FunctionValue;
import me.topchetoeu.jscript.engine.values.Symbol;
import me.topchetoeu.jscript.engine.values.Values; import me.topchetoeu.jscript.engine.values.Values;
import me.topchetoeu.jscript.exceptions.EngineException; import me.topchetoeu.jscript.exceptions.EngineException;
import me.topchetoeu.jscript.interop.Native; import me.topchetoeu.jscript.interop.Arguments;
import me.topchetoeu.jscript.interop.NativeGetter; 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.modules.ModuleRepo;
import me.topchetoeu.jscript.parsing.Parsing;
public class Internals { public class Internals {
@Native public static Object require(Context ctx, String name) { private static final Symbol THREADS = new Symbol("Internals.threads");
var repo = ModuleRepo.get(ctx); 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) { if (repo != null) {
var res = repo.getModule(ctx, ModuleRepo.cwd(ctx), name); var res = repo.getModule(args.ctx, ModuleRepo.cwd(args.ctx), args.getString(0));
res.load(ctx); res.load(args.ctx);
return res.value(); return res.value();
} }
else throw EngineException.ofError("Modules are not supported."); else throw EngineException.ofError("Modules are not supported.");
} }
@Native public static Object log(Context ctx, Object ...args) { @Expose(target = ExposeTarget.STATIC)
for (var arg : args) { public static Object __log(Arguments args) {
Values.printValue(ctx, arg); for (var arg : args.args) {
Values.printValue(args.ctx, arg);
System.out.print(" "); System.out.print(" ");
} }
System.out.println(); System.out.println();
if (args.length == 0) return null; return args.get(0);
else return args[0];
} }
@Native public static String readline(Context ctx) { @Expose(target = ExposeTarget.STATIC)
public static String __readline() {
try { try {
return Reading.readline(); 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 thread = new Thread(() -> {
var ms = (long)delay; var ms = (long)delay;
var ns = (int)((delay - ms) * 10000000); var ns = (int)((delay - ms) * 10000000);
try { try { Thread.sleep(ms, ns); }
Thread.sleep(ms, ns);
}
catch (InterruptedException e) { return; } 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(); 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; 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 thread = new Thread(() -> {
var ms = (long)delay; var ms = (long)delay;
var ns = (int)((delay - ms) * 10000000); var ns = (int)((delay - ms) * 10000000);
@ -75,96 +93,76 @@ public class Internals {
} }
catch (InterruptedException e) { return; } 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; return thread;
} }
@Native public static void clearTimeout(Context ctx, Thread t) { @Expose(target = ExposeTarget.STATIC)
t.interrupt(); 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) { @Expose(target = ExposeTarget.STATIC)
t.interrupt(); public static void __clearInterval(Arguments args) {
__clearTimeout(args);
} }
@Native public static double parseInt(Context ctx, String val) { @Expose(target = ExposeTarget.STATIC)
return NumberLib.parseInt(ctx, val); public static double __parseInt(Arguments args) {
return NumberLib.__parseInt(args);
} }
@Native public static double parseFloat(Context ctx, String val) { @Expose(target = ExposeTarget.STATIC)
return NumberLib.parseFloat(ctx, val); public static double __parseFloat(Arguments args) {
return NumberLib.__parseFloat(args);
} }
@Native public static boolean isNaN(Context ctx, double val) { @Expose(target = ExposeTarget.STATIC)
return NumberLib.isNaN(ctx, val); public static boolean __isNaN(Arguments args) {
return NumberLib.__isNaN(args);
} }
@Native public static boolean isFinite(Context ctx, double val) { @Expose(target = ExposeTarget.STATIC)
return NumberLib.isFinite(ctx, val); public static boolean __isFinite(Arguments args) {
return NumberLib.__isFinite(args);
} }
@Native public static boolean isInfinite(Context ctx, double val) { @Expose(target = ExposeTarget.STATIC)
return NumberLib.isInfinite(ctx, val); public static boolean __isInfinite(Arguments args) {
return NumberLib.__isInfinite(args);
} }
@NativeGetter public static double NaN(Context ctx) { @ExposeField(target = ExposeTarget.STATIC)
return Double.NaN; public static double __NaN = Double.NaN;
@ExposeField(target = ExposeTarget.STATIC)
public static double __Infinity = Double.POSITIVE_INFINITY;
@Expose(target = ExposeTarget.STATIC)
public static String __encodeURIComponent(Arguments args) {
return EncodingLib.__encodeURIComponent(args);
} }
@NativeGetter public static double Infinity(Context ctx) { @Expose(target = ExposeTarget.STATIC)
return Double.POSITIVE_INFINITY; public static String __decodeURIComponent(Arguments args) {
return EncodingLib.__decodeURIComponent(args);
} }
private static final String HEX = "0123456789ABCDEF"; @Expose(target = ExposeTarget.STATIC)
public static String __encodeURI(Arguments args) {
private static String encodeUriAny(String str, String keepAlphabet) { return EncodingLib.__encodeURI(args);
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();
} }
private static String decodeUriAny(String str, String keepAlphabet) { @Expose(target = ExposeTarget.STATIC)
if (str == null) str = "undefined"; public static String __decodeURI(Arguments args) {
return EncodingLib.__decodeURI(args);
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, ",/?:@&=+$#.");
} }
public static Environment apply(Environment env) { public static Environment apply(Environment env) {

View File

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

View File

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

View File

@ -1,21 +1,47 @@
package me.topchetoeu.jscript.lib; 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 { @WrapperName("Math")
@Native public static final double E = Math.E; public class MathLib {
@Native public static final double PI = Math.PI; @ExposeField(target = ExposeTarget.STATIC)
@Native public static final double SQRT2 = Math.sqrt(2); public static final double __E = Math.E;
@Native public static final double SQRT1_2 = Math.sqrt(.5); @ExposeField(target = ExposeTarget.STATIC)
@Native public static final double LN2 = Math.log(2); public static final double __PI = Math.PI;
@Native public static final double LN10 = Math.log(10); @ExposeField(target = ExposeTarget.STATIC)
@Native public static final double LOG2E = Math.log(Math.E) / LN2; public static final double __SQRT2 = Math.sqrt(2);
@Native public static final double LOG10E = Math.log10(Math.E); @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 (x == 0) {
if (y == 0) return Double.NaN; if (y == 0) return Double.NaN;
return Math.signum(y) * Math.PI / 2; 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)); } @Expose(target = ExposeTarget.STATIC)
@Native public static double acosh(double x) { return Math.log(x + Math.sqrt(x * x - 1)); } public static double __asinh(Arguments args) {
@Native public static double atanh(double x) { 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; if (x <= -1 || x >= 1) return Double.NaN;
return .5 * Math.log((1 + x) / (1 - x)); return .5 * Math.log((1 + x) / (1 - x));
} }
@Native public static double sin(double x) { return Math.sin(x); } @Expose(target = ExposeTarget.STATIC)
@Native public static double cos(double x) { return Math.cos(x); } public static double __sin(Arguments args) {
@Native public static double tan(double x) { return Math.tan(x); } 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); } @Expose(target = ExposeTarget.STATIC)
@Native public static double cosh(double x) { return Math.cosh(x); } public static double __sinh(Arguments args) {
@Native public static double tanh(double x) { return Math.tanh(x); } 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); } @Expose(target = ExposeTarget.STATIC)
@Native public static double cbrt(double x) { return Math.cbrt(x); } 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.; var res = 0.;
for (var el : vals) { for (var i = 0; i < args.n(); i++) {
var val = el; var val = args.getDouble(i);
res += val * val; res += val * val;
} }
return Math.sqrt(res); 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); } @Expose(target = ExposeTarget.STATIC)
@Native public static double expm1(double x) { return Math.expm1(x); } public static double __exp(Arguments args) {
@Native public static double pow(double x, double y) { return Math.pow(x, y); } 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); } @Expose(target = ExposeTarget.STATIC)
@Native public static double log10(double x) { return Math.log10(x); } public static double __log(Arguments args) {
@Native public static double log1p(double x) { return Math.log1p(x); } return Math.log(args.getDouble(0));
@Native public static double log2(double x) { return Math.log(x) / LN2; } }
@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); } @Expose(target = ExposeTarget.STATIC)
@Native public static double floor(double x) { return Math.floor(x); } public static double __ceil(Arguments args) {
@Native public static double round(double x) { return Math.round(x); } return Math.ceil(args.getDouble(0));
@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); } @Expose(target = ExposeTarget.STATIC)
@Native public static double abs(double x) { return Math.abs(x); } 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; 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; if (el > res) res = el;
} }
return res; return res;
} }
@Native public static double min(double ...vals) { @Expose(target = ExposeTarget.STATIC)
public static double __min(Arguments args) {
var res = Double.POSITIVE_INFINITY; 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; if (el < res) res = el;
} }
return res; 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(); } @Expose(target = ExposeTarget.STATIC)
@Native public static int clz32(double x) { return Integer.numberOfLeadingZeros((int)x); } public static double __random() { return Math.random(); }
@Expose(target = ExposeTarget.STATIC)
public static int __clz32(Arguments args) {
return Integer.numberOfLeadingZeros(args.getInt(0));
}
} }

View File

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

View File

@ -1,171 +1,219 @@
package me.topchetoeu.jscript.lib; package me.topchetoeu.jscript.lib;
import me.topchetoeu.jscript.engine.Context;
import me.topchetoeu.jscript.engine.values.ArrayValue; import me.topchetoeu.jscript.engine.values.ArrayValue;
import me.topchetoeu.jscript.engine.values.FunctionValue; import me.topchetoeu.jscript.engine.values.FunctionValue;
import me.topchetoeu.jscript.engine.values.ObjectValue; import me.topchetoeu.jscript.engine.values.ObjectValue;
import me.topchetoeu.jscript.engine.values.Symbol; import me.topchetoeu.jscript.engine.values.Symbol;
import me.topchetoeu.jscript.engine.values.Values; import me.topchetoeu.jscript.engine.values.Values;
import me.topchetoeu.jscript.exceptions.EngineException; import me.topchetoeu.jscript.exceptions.EngineException;
import me.topchetoeu.jscript.interop.Native; import me.topchetoeu.jscript.interop.Arguments;
import me.topchetoeu.jscript.interop.NativeConstructor; 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 { @WrapperName("Object")
@Native public static ObjectValue assign(Context ctx, ObjectValue dst, Object... src) { public class ObjectLib {
for (var obj : src) { @Expose(target = ExposeTarget.STATIC)
for (var key : Values.getMembers(ctx, obj, true, true)) { public static Object __assign(Arguments args) {
Values.setMember(ctx, dst, key, Values.getMember(ctx, obj, key)); 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(); var obj = new ObjectValue();
obj.setPrototype(ctx, proto); obj.setPrototype(args.ctx, args.get(0));
return defineProperties(ctx, obj, props);
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));
}
return obj;
} }
@Native public static ObjectValue defineProperty(Context ctx, ObjectValue obj, Object key, ObjectValue attrib) { @Expose(target = ExposeTarget.STATIC)
var hasVal = attrib.hasMember(ctx, "value", false); public static ObjectValue __defineProperty(Arguments args) {
var hasGet = attrib.hasMember(ctx, "get", false); var obj = args.convert(0, ObjectValue.class);
var hasSet = attrib.hasMember(ctx, "set", false); 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 (hasVal) {
if (hasGet || hasSet) throw EngineException.ofType("Cannot specify a value and accessors for a property."); if (hasGet || hasSet) throw EngineException.ofType("Cannot specify a value and accessors for a property.");
if (!obj.defineProperty( if (!obj.defineProperty(
ctx, key, args.ctx, key,
attrib.getMember(ctx, "value"), attrib.getMember(args.ctx, "value"),
Values.toBoolean(attrib.getMember(ctx, "writable")), Values.toBoolean(attrib.getMember(args.ctx, "writable")),
Values.toBoolean(attrib.getMember(ctx, "configurable")), Values.toBoolean(attrib.getMember(args.ctx, "configurable")),
Values.toBoolean(attrib.getMember(ctx, "enumerable")) Values.toBoolean(attrib.getMember(args.ctx, "enumerable"))
)) throw EngineException.ofType("Can't define property '" + key + "'."); )) throw EngineException.ofType("Can't define property '" + key + "'.");
} }
else { else {
var get = attrib.getMember(ctx, "get"); var get = attrib.getMember(args.ctx, "get");
var set = attrib.getMember(ctx, "set"); var set = attrib.getMember(args.ctx, "set");
if (get != null && !(get instanceof FunctionValue)) throw EngineException.ofType("Get accessor must be a function."); 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 (set != null && !(set instanceof FunctionValue)) throw EngineException.ofType("Set accessor must be a function.");
if (!obj.defineProperty( if (!obj.defineProperty(
ctx, key, args.ctx, key,
(FunctionValue)get, (FunctionValue)set, (FunctionValue)get, (FunctionValue)set,
Values.toBoolean(attrib.getMember(ctx, "configurable")), Values.toBoolean(attrib.getMember(args.ctx, "configurable")),
Values.toBoolean(attrib.getMember(ctx, "enumerable")) Values.toBoolean(attrib.getMember(args.ctx, "enumerable"))
)) throw EngineException.ofType("Can't define property '" + key + "'."); )) throw EngineException.ofType("Can't define property '" + key + "'.");
} }
return obj; 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)) { 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; 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 res = new ArrayValue();
var _all = Values.toBoolean(all);
for (var key : Values.getMembers(ctx, obj, true, false)) { for (var key : Values.getMembers(args.ctx, obj, true, false)) {
if (_all || !(key instanceof Symbol)) res.set(ctx, res.size(), key); if (all || !(key instanceof Symbol)) res.set(args.ctx, res.size(), key);
} }
return res; 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 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)) { for (var key : Values.getMembers(args.ctx, obj, true, false)) {
if (_all || !(key instanceof Symbol)) res.set(ctx, res.size(), new ArrayValue(ctx, key, Values.getMember(ctx, obj, key))); if (all || !(key instanceof Symbol)) res.set(args.ctx, res.size(), new ArrayValue(args.ctx, key, Values.getMember(args.ctx, obj, key)));
} }
return res; 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 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)) { for (var key : Values.getMembers(args.ctx, obj, true, false)) {
if (_all || key instanceof String) res.set(ctx, res.size(), Values.getMember(ctx, obj, key)); if (all || key instanceof String) res.set(args.ctx, res.size(), Values.getMember(args.ctx, obj, key));
} }
return res; return res;
} }
@Native public static ObjectValue getOwnPropertyDescriptor(Context ctx, Object obj, Object key) { @Expose(target = ExposeTarget.STATIC)
return Values.getMemberDescriptor(ctx, obj, key); 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(); var res = new ObjectValue();
for (var key : Values.getMembers(ctx, obj, true, true)) { var obj = args.get(0);
res.defineProperty(ctx, key, getOwnPropertyDescriptor(ctx, obj, key)); 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; 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 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)) { for (var key : Values.getMembers(args.ctx, obj, true, true)) {
if (_all || !(key instanceof Symbol)) res.set(ctx, res.size(), key); if (all || !(key instanceof Symbol)) res.set(args.ctx, res.size(), key);
} }
return res; 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(); var res = new ArrayValue();
for (var key : Values.getMembers(ctx, obj, true, true)) { for (var key : Values.getMembers(args.ctx, obj, true, true)) {
if (key instanceof Symbol) res.set(ctx, res.size(), key); if (key instanceof Symbol) res.set(args.ctx, res.size(), key);
} }
return res; return res;
} }
@Native public static boolean hasOwn(Context ctx, Object obj, Object key) { @Expose(target = ExposeTarget.STATIC)
return Values.hasMember(ctx, obj, key, true); 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) { @Expose(target = ExposeTarget.STATIC)
return Values.getPrototype(ctx, obj); 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) { @Expose(target = ExposeTarget.STATIC)
Values.setPrototype(ctx, obj, proto); public static Object __setPrototypeOf(Arguments args) {
return obj; 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(); 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) { 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; return res;
} }
@Native public static Object preventExtensions(Context ctx, Object obj) { @Expose(target = ExposeTarget.STATIC)
if (obj instanceof ObjectValue) ((ObjectValue)obj).preventExtensions(); public static Object __preventExtensions(Arguments args) {
return obj; 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) { @Expose(target = ExposeTarget.STATIC)
if (obj instanceof ObjectValue) ((ObjectValue)obj).seal(); public static Object __seal(Arguments args) {
return obj; 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) { @Expose(target = ExposeTarget.STATIC)
if (obj instanceof ObjectValue) ((ObjectValue)obj).freeze(); public static Object __freeze(Arguments args) {
return obj; 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(); 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()) { if (obj instanceof ObjectValue && ((ObjectValue)obj).extensible()) {
var _obj = (ObjectValue)obj; var _obj = (ObjectValue)obj;
for (var key : _obj.keys(true)) { for (var key : _obj.keys(true)) {
@ -175,7 +223,10 @@ import me.topchetoeu.jscript.interop.NativeConstructor;
return true; 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()) { if (obj instanceof ObjectValue && ((ObjectValue)obj).extensible()) {
var _obj = (ObjectValue)obj; var _obj = (ObjectValue)obj;
for (var key : _obj.keys(true)) { for (var key : _obj.keys(true)) {
@ -187,26 +238,31 @@ import me.topchetoeu.jscript.interop.NativeConstructor;
return true; return true;
} }
@Native(thisArg = true) public static Object valueOf(Context ctx, Object thisArg) { @Expose
return thisArg; public static Object __valueOf(Arguments args) {
return args.self;
} }
@Native(thisArg = true) public static String toString(Context ctx, Object thisArg) { @Expose
var name = Values.getMember(ctx, thisArg, Symbol.get("Symbol.typeName")); public static String __toString(Arguments args) {
var name = Values.getMember(args.ctx, args.self, Symbol.get("Symbol.typeName"));
if (name == null) name = "Unknown"; if (name == null) name = "Unknown";
else name = Values.toString(ctx, name); else name = Values.toString(args.ctx, name);
return "[object " + name + "]"; return "[object " + name + "]";
} }
@Native(thisArg = true) public static boolean hasOwnProperty(Context ctx, Object thisArg, Object key) { @Expose
return ObjectLib.hasOwn(ctx, thisArg, Values.convert(ctx, key, String.class)); 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(); if (arg == null || arg == Values.NULL) return new ObjectValue();
else if (arg instanceof Boolean) return BooleanLib.constructor(ctx, thisArg, arg); else if (arg instanceof Boolean) return new BooleanLib((boolean)arg);
else if (arg instanceof Number) return NumberLib.constructor(ctx, thisArg, arg); else if (arg instanceof Number) return new NumberLib(((Number)arg).doubleValue());
else if (arg instanceof String) return StringLib.constructor(ctx, thisArg, arg); else if (arg instanceof String) return new StringLib((String)arg);
// else if (arg instanceof Symbol) return SymbolPolyfill.constructor(ctx, thisArg, arg); else if (arg instanceof Symbol) return new SymbolLib((Symbol)arg);
else return arg; else return arg;
} }
} }

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -3,48 +3,69 @@ package me.topchetoeu.jscript.lib;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import me.topchetoeu.jscript.engine.Context;
import me.topchetoeu.jscript.engine.values.ObjectValue; import me.topchetoeu.jscript.engine.values.ObjectValue;
import me.topchetoeu.jscript.engine.values.Symbol; import me.topchetoeu.jscript.engine.values.Symbol;
import me.topchetoeu.jscript.engine.values.Values;
import me.topchetoeu.jscript.exceptions.EngineException; import me.topchetoeu.jscript.exceptions.EngineException;
import me.topchetoeu.jscript.interop.Native; import me.topchetoeu.jscript.interop.Arguments;
import me.topchetoeu.jscript.interop.NativeConstructor; 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<>(); private static final Map<String, Symbol> symbols = new HashMap<>();
@Native public static final Symbol typeName = Symbol.get("Symbol.typeName"); @ExposeField(target = ExposeTarget.STATIC)
@Native public static final Symbol replace = Symbol.get("Symbol.replace"); public static final Symbol __typeName = Symbol.get("Symbol.typeName");
@Native public static final Symbol match = Symbol.get("Symbol.match"); @ExposeField(target = ExposeTarget.STATIC)
@Native public static final Symbol matchAll = Symbol.get("Symbol.matchAll"); public static final Symbol __replace = Symbol.get("Symbol.replace");
@Native public static final Symbol split = Symbol.get("Symbol.split"); @ExposeField(target = ExposeTarget.STATIC)
@Native public static final Symbol search = Symbol.get("Symbol.search"); public static final Symbol __match = Symbol.get("Symbol.match");
@Native public static final Symbol iterator = Symbol.get("Symbol.iterator"); @ExposeField(target = ExposeTarget.STATIC)
@Native public static final Symbol asyncIterator = Symbol.get("Symbol.asyncIterator"); public static final Symbol __matchAll = Symbol.get("Symbol.matchAll");
@Native public static final Symbol cause = Symbol.get("Symbol.cause"); @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; 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; if (val instanceof SymbolLib) return ((SymbolLib)val).value;
else if (val instanceof Symbol) return (Symbol)val; 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)); 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) { public SymbolLib(Symbol val) {
if (thisArg instanceof ObjectValue) throw EngineException.ofType("Symbol constructor may not be called with new."); this.value = val;
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);
} }
@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); if (symbols.containsKey(key)) return symbols.get(key);
else { else {
var sym = new Symbol(key); var sym = new Symbol(key);
@ -52,11 +73,8 @@ import me.topchetoeu.jscript.interop.NativeConstructor;
return sym; return sym;
} }
} }
@Native public static String keyFor(Symbol sym) { @Expose(target = ExposeTarget.STATIC)
return sym.value; public static String __keyFor(Arguments args) {
} return passThis(args.slice(-1), "keyFor").value;
public SymbolLib(Symbol val) {
this.value = val;
} }
} }

View File

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

View File

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