refactor: Remove environment-related bloat
This commit is contained in:
parent
49b52d90a7
commit
3475e3a130
@ -9,7 +9,7 @@ import me.topchetoeu.jscript.compilation.parsing.Operator;
|
|||||||
import me.topchetoeu.jscript.compilation.parsing.ParseRes;
|
import me.topchetoeu.jscript.compilation.parsing.ParseRes;
|
||||||
import me.topchetoeu.jscript.compilation.parsing.Parsing;
|
import me.topchetoeu.jscript.compilation.parsing.Parsing;
|
||||||
import me.topchetoeu.jscript.compilation.parsing.Token;
|
import me.topchetoeu.jscript.compilation.parsing.Token;
|
||||||
import me.topchetoeu.jscript.runtime.Extensions;
|
import me.topchetoeu.jscript.runtime.environment.Environment;
|
||||||
import me.topchetoeu.jscript.runtime.exceptions.EngineException;
|
import me.topchetoeu.jscript.runtime.exceptions.EngineException;
|
||||||
import me.topchetoeu.jscript.runtime.exceptions.SyntaxException;
|
import me.topchetoeu.jscript.runtime.exceptions.SyntaxException;
|
||||||
import me.topchetoeu.jscript.runtime.values.ArrayValue;
|
import me.topchetoeu.jscript.runtime.values.ArrayValue;
|
||||||
@ -32,7 +32,7 @@ public class JSON {
|
|||||||
if (val.isNull()) return Values.NULL;
|
if (val.isNull()) return Values.NULL;
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
private static JSONElement fromJs(Extensions ext, Object val, HashSet<Object> prev) {
|
private static JSONElement fromJs(Environment ext, Object val, HashSet<Object> prev) {
|
||||||
if (val instanceof Boolean) return JSONElement.bool((boolean)val);
|
if (val instanceof Boolean) return JSONElement.bool((boolean)val);
|
||||||
if (val instanceof Number) return JSONElement.number(((Number)val).doubleValue());
|
if (val instanceof Number) return JSONElement.number(((Number)val).doubleValue());
|
||||||
if (val instanceof String) return JSONElement.string((String)val);
|
if (val instanceof String) return JSONElement.string((String)val);
|
||||||
@ -70,7 +70,7 @@ public class JSON {
|
|||||||
if (val == null) return null;
|
if (val == null) return null;
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
public static JSONElement fromJs(Extensions ext, Object val) {
|
public static JSONElement fromJs(Environment ext, Object val) {
|
||||||
return fromJs(ext, val, new HashSet<>());
|
return fromJs(ext, val, new HashSet<>());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -699,7 +699,7 @@ public class Parsing {
|
|||||||
|
|
||||||
var values = new ArrayList<Statement>();
|
var values = new ArrayList<Statement>();
|
||||||
|
|
||||||
// Java allows labels, so me uses labels
|
// Java allows labels, so labels were used
|
||||||
loop: while (true) {
|
loop: while (true) {
|
||||||
if (isOperator(tokens, i + n, Operator.BRACKET_CLOSE)) {
|
if (isOperator(tokens, i + n, Operator.BRACKET_CLOSE)) {
|
||||||
n++;
|
n++;
|
||||||
|
@ -39,7 +39,7 @@ public class ArrayLib {
|
|||||||
return __iterator(args);
|
return __iterator(args);
|
||||||
}
|
}
|
||||||
@Expose public static ObjectValue __keys(Arguments args) {
|
@Expose public static ObjectValue __keys(Arguments args) {
|
||||||
return Values.toJSIterator(args.ctx, () -> new Iterator<Object>() {
|
return Values.toJSIterator(args.env, () -> new Iterator<Object>() {
|
||||||
private int i = 0;
|
private int i = 0;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -54,7 +54,7 @@ public class ArrayLib {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
@Expose public static ObjectValue __entries(Arguments args) {
|
@Expose public static ObjectValue __entries(Arguments args) {
|
||||||
return Values.toJSIterator(args.ctx, () -> new Iterator<Object>() {
|
return Values.toJSIterator(args.env, () -> new Iterator<Object>() {
|
||||||
private int i = 0;
|
private int i = 0;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -64,18 +64,18 @@ public class ArrayLib {
|
|||||||
@Override
|
@Override
|
||||||
public Object next() {
|
public Object next() {
|
||||||
if (!hasNext()) return null;
|
if (!hasNext()) return null;
|
||||||
return new ArrayValue(args.ctx, i, args.self(ArrayValue.class).get(i++));
|
return new ArrayValue(args.env, i, args.self(ArrayValue.class).get(i++));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Expose(value = "@@Symbol.iterator")
|
@Expose(value = "@@Symbol.iterator")
|
||||||
public static ObjectValue __iterator(Arguments args) {
|
public static ObjectValue __iterator(Arguments args) {
|
||||||
return Values.toJSIterator(args.ctx, args.self(ArrayValue.class));
|
return Values.toJSIterator(args.env, args.self(ArrayValue.class));
|
||||||
}
|
}
|
||||||
@Expose(value = "@@Symbol.asyncIterator")
|
@Expose(value = "@@Symbol.asyncIterator")
|
||||||
public static ObjectValue __asyncIterator(Arguments args) {
|
public static ObjectValue __asyncIterator(Arguments args) {
|
||||||
return Values.toJSAsyncIterator(args.ctx, args.self(ArrayValue.class).iterator());
|
return Values.toJSAsyncIterator(args.env, args.self(ArrayValue.class).iterator());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Expose public static ArrayValue __concat(Arguments args) {
|
@Expose public static ArrayValue __concat(Arguments args) {
|
||||||
@ -98,7 +98,7 @@ public class ArrayLib {
|
|||||||
j += n;
|
j += n;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
res.set(args.ctx, j++, arrs.get(i));
|
res.set(args.env, j++, arrs.get(i));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -113,7 +113,7 @@ public class ArrayLib {
|
|||||||
});
|
});
|
||||||
|
|
||||||
arr.sort((a, b) -> {
|
arr.sort((a, b) -> {
|
||||||
var res = Values.toNumber(args.ctx, (cmp == null ? defaultCmp : cmp).call(args.ctx, null, a, b));
|
var res = Values.toNumber(args.env, (cmp == null ? defaultCmp : cmp).call(args.env, null, a, b));
|
||||||
if (res < 0) return -1;
|
if (res < 0) return -1;
|
||||||
if (res > 0) return 1;
|
if (res > 0) return 1;
|
||||||
return 0;
|
return 0;
|
||||||
@ -127,7 +127,7 @@ public class ArrayLib {
|
|||||||
var start = normalizeI(arr.size(), args.getInt(1, 0), true);
|
var start = normalizeI(arr.size(), args.getInt(1, 0), true);
|
||||||
var end = normalizeI(arr.size(), args.getInt(2, arr.size()), true);
|
var end = normalizeI(arr.size(), args.getInt(2, arr.size()), true);
|
||||||
|
|
||||||
for (; start < end; start++) arr.set(args.ctx, start, val);
|
for (; start < end; start++) arr.set(args.env, start, val);
|
||||||
|
|
||||||
return arr;
|
return arr;
|
||||||
}
|
}
|
||||||
@ -136,7 +136,7 @@ public class ArrayLib {
|
|||||||
|
|
||||||
for (var i = 0; i < arr.size(); i++) {
|
for (var i = 0; i < arr.size(); i++) {
|
||||||
if (arr.has(i) && !Values.toBoolean(Values.call(
|
if (arr.has(i) && !Values.toBoolean(Values.call(
|
||||||
args.ctx, args.get(0), args.get(1),
|
args.env, args.get(0), args.get(1),
|
||||||
arr.get(i), i, arr
|
arr.get(i), i, arr
|
||||||
))) return false;
|
))) return false;
|
||||||
}
|
}
|
||||||
@ -148,7 +148,7 @@ public class ArrayLib {
|
|||||||
|
|
||||||
for (var i = 0; i < arr.size(); i++) {
|
for (var i = 0; i < arr.size(); i++) {
|
||||||
if (arr.has(i) && Values.toBoolean(Values.call(
|
if (arr.has(i) && Values.toBoolean(Values.call(
|
||||||
args.ctx, args.get(0), args.get(1),
|
args.env, args.get(0), args.get(1),
|
||||||
arr.get(i), i, arr
|
arr.get(i), i, arr
|
||||||
))) return true;
|
))) return true;
|
||||||
}
|
}
|
||||||
@ -161,9 +161,9 @@ public class ArrayLib {
|
|||||||
|
|
||||||
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(Values.call(
|
if (arr.has(i) && Values.toBoolean(Values.call(
|
||||||
args.ctx, args.get(0), args.get(1),
|
args.env, args.get(0), args.get(1),
|
||||||
arr.get(i), i, arr
|
arr.get(i), i, arr
|
||||||
))) res.set(args.ctx, j++, arr.get(i));
|
))) res.set(args.env, j++, arr.get(i));
|
||||||
}
|
}
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
@ -174,7 +174,7 @@ public class ArrayLib {
|
|||||||
res.setSize(arr.size());
|
res.setSize(arr.size());
|
||||||
|
|
||||||
for (int i = 0; i < arr.size(); i++) {
|
for (int i = 0; i < arr.size(); i++) {
|
||||||
if (arr.has(i)) res.set(args.ctx, i, Values.call(args.ctx, args.get(0), args.get(1), arr.get(i), i, arr));
|
if (arr.has(i)) res.set(args.env, i, Values.call(args.env, args.get(0), args.get(1), arr.get(i), i, arr));
|
||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
@ -184,7 +184,7 @@ public class ArrayLib {
|
|||||||
var thisArg = args.get(1);
|
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(args.ctx, thisArg, arr.get(i), i, arr);
|
if (arr.has(i)) func.call(args.env, thisArg, arr.get(i), i, arr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -205,7 +205,7 @@ public class ArrayLib {
|
|||||||
|
|
||||||
for (; i < arr.size(); i++) {
|
for (; i < arr.size(); i++) {
|
||||||
if (arr.has(i)) {
|
if (arr.has(i)) {
|
||||||
res = func.call(args.ctx, null, res, arr.get(i), i, arr);
|
res = func.call(args.env, null, res, arr.get(i), i, arr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -226,7 +226,7 @@ public class ArrayLib {
|
|||||||
|
|
||||||
for (; i >= 0; i--) {
|
for (; i >= 0; i--) {
|
||||||
if (arr.has(i)) {
|
if (arr.has(i)) {
|
||||||
res = func.call(args.ctx, null, res, arr.get(i), i, arr);
|
res = func.call(args.env, null, res, arr.get(i), i, arr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -255,13 +255,13 @@ public class ArrayLib {
|
|||||||
depths.push(d + 1);
|
depths.push(d + 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else res.set(args.ctx, res.size(), el);
|
else res.set(args.env, res.size(), el);
|
||||||
}
|
}
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
@Expose public static ArrayValue __flatMap(Arguments args) {
|
@Expose public static ArrayValue __flatMap(Arguments args) {
|
||||||
return __flat(new Arguments(args.ctx, __map(args), 1));
|
return __flat(new Arguments(args.env, __map(args), 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Expose public static Object __find(Arguments args) {
|
@Expose public static Object __find(Arguments args) {
|
||||||
@ -269,7 +269,7 @@ public class ArrayLib {
|
|||||||
|
|
||||||
for (int i = 0; i < arr.size(); i++) {
|
for (int i = 0; i < arr.size(); i++) {
|
||||||
if (arr.has(i) && Values.toBoolean(Values.call(
|
if (arr.has(i) && Values.toBoolean(Values.call(
|
||||||
args.ctx, args.get(0), args.get(1),
|
args.env, args.get(0), args.get(1),
|
||||||
arr.get(i), i, args.self
|
arr.get(i), i, args.self
|
||||||
))) return arr.get(i);
|
))) return arr.get(i);
|
||||||
}
|
}
|
||||||
@ -281,7 +281,7 @@ public class ArrayLib {
|
|||||||
|
|
||||||
for (var i = arr.size() - 1; i >= 0; i--) {
|
for (var i = arr.size() - 1; i >= 0; i--) {
|
||||||
if (arr.has(i) && Values.toBoolean(Values.call(
|
if (arr.has(i) && Values.toBoolean(Values.call(
|
||||||
args.ctx, args.get(0), args.get(1),
|
args.env, args.get(0), args.get(1),
|
||||||
arr.get(i), i, args.self
|
arr.get(i), i, args.self
|
||||||
))) return arr.get(i);
|
))) return arr.get(i);
|
||||||
}
|
}
|
||||||
@ -294,7 +294,7 @@ public class ArrayLib {
|
|||||||
|
|
||||||
for (int i = 0; i < arr.size(); i++) {
|
for (int i = 0; i < arr.size(); i++) {
|
||||||
if (arr.has(i) && Values.toBoolean(Values.call(
|
if (arr.has(i) && Values.toBoolean(Values.call(
|
||||||
args.ctx, args.get(0), args.get(1),
|
args.env, args.get(0), args.get(1),
|
||||||
arr.get(i), i, args.self
|
arr.get(i), i, args.self
|
||||||
))) return i;
|
))) return i;
|
||||||
}
|
}
|
||||||
@ -306,7 +306,7 @@ public class ArrayLib {
|
|||||||
|
|
||||||
for (var i = arr.size() - 1; i >= 0; i--) {
|
for (var i = arr.size() - 1; i >= 0; i--) {
|
||||||
if (arr.has(i) && Values.toBoolean(Values.call(
|
if (arr.has(i) && Values.toBoolean(Values.call(
|
||||||
args.ctx, args.get(0), args.get(1),
|
args.env, args.get(0), args.get(1),
|
||||||
arr.get(i), i, args.self
|
arr.get(i), i, args.self
|
||||||
))) return i;
|
))) return i;
|
||||||
}
|
}
|
||||||
@ -320,7 +320,7 @@ public class ArrayLib {
|
|||||||
var start = normalizeI(arr.size(), args.getInt(1), true);
|
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(args.ctx, arr.get(i), val)) return i;
|
if (Values.strictEquals(args.env, arr.get(i), val)) return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
@ -331,7 +331,7 @@ public class ArrayLib {
|
|||||||
var start = normalizeI(arr.size(), args.getInt(1), true);
|
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(args.ctx, arr.get(i), val)) return i;
|
if (Values.strictEquals(args.env, arr.get(i), val)) return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
@ -353,7 +353,7 @@ public class ArrayLib {
|
|||||||
var arr = args.self(ArrayValue.class);
|
var arr = args.self(ArrayValue.class);
|
||||||
var values = args.args;
|
var values = args.args;
|
||||||
|
|
||||||
arr.copyFrom(args.ctx, values, 0, arr.size(), values.length);
|
arr.copyFrom(args.env, values, 0, arr.size(), values.length);
|
||||||
return arr.size();
|
return arr.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -372,7 +372,7 @@ public class ArrayLib {
|
|||||||
var values = args.slice(0).args;
|
var values = args.slice(0).args;
|
||||||
|
|
||||||
arr.move(0, values.length, arr.size());
|
arr.move(0, values.length, arr.size());
|
||||||
arr.copyFrom(args.ctx, values, 0, 0, values.length);
|
arr.copyFrom(args.env, values, 0, 0, values.length);
|
||||||
return arr.size();
|
return arr.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -398,13 +398,13 @@ public class ArrayLib {
|
|||||||
var res = new ArrayValue(deleteCount);
|
var res = new ArrayValue(deleteCount);
|
||||||
arr.copyTo(res, start, 0, deleteCount);
|
arr.copyTo(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(args.ctx, items, 0, start, items.length);
|
arr.copyFrom(args.env, items, 0, start, items.length);
|
||||||
arr.setSize(size);
|
arr.setSize(size);
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
@Expose public static String __toString(Arguments args) {
|
@Expose public static String __toString(Arguments args) {
|
||||||
return __join(new Arguments(args.ctx, args.self, ","));
|
return __join(new Arguments(args.env, args.self, ","));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Expose public static String __join(Arguments args) {
|
@Expose public static String __join(Arguments args) {
|
||||||
@ -422,7 +422,7 @@ public class ArrayLib {
|
|||||||
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(args.ctx, el));
|
res.append(Values.toString(args.env, el));
|
||||||
}
|
}
|
||||||
|
|
||||||
return res.toString();
|
return res.toString();
|
||||||
@ -434,7 +434,7 @@ public class ArrayLib {
|
|||||||
}
|
}
|
||||||
@Expose(target = ExposeTarget.STATIC)
|
@Expose(target = ExposeTarget.STATIC)
|
||||||
public static ArrayValue __of(Arguments args) {
|
public static ArrayValue __of(Arguments args) {
|
||||||
return new ArrayValue(args.ctx, args.slice(0).args);
|
return new ArrayValue(args.env, args.slice(0).args);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ExposeConstructor public static ArrayValue __constructor(Arguments args) {
|
@ExposeConstructor public static ArrayValue __constructor(Arguments args) {
|
||||||
@ -448,7 +448,7 @@ public class ArrayLib {
|
|||||||
else {
|
else {
|
||||||
var val = args.args;
|
var val = args.args;
|
||||||
res = new ArrayValue(val.length);
|
res = new ArrayValue(val.length);
|
||||||
res.copyFrom(args.ctx, val, 0, 0, val.length);
|
res.copyFrom(args.env, val, 0, 0, val.length);
|
||||||
}
|
}
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
|
@ -1,9 +1,8 @@
|
|||||||
package me.topchetoeu.jscript.lib;
|
package me.topchetoeu.jscript.lib;
|
||||||
|
|
||||||
import me.topchetoeu.jscript.lib.PromiseLib.Handle;
|
import me.topchetoeu.jscript.lib.PromiseLib.Handle;
|
||||||
import me.topchetoeu.jscript.runtime.Context;
|
|
||||||
import me.topchetoeu.jscript.runtime.Extensions;
|
|
||||||
import me.topchetoeu.jscript.runtime.Frame;
|
import me.topchetoeu.jscript.runtime.Frame;
|
||||||
|
import me.topchetoeu.jscript.runtime.environment.Environment;
|
||||||
import me.topchetoeu.jscript.runtime.exceptions.EngineException;
|
import me.topchetoeu.jscript.runtime.exceptions.EngineException;
|
||||||
import me.topchetoeu.jscript.runtime.values.CodeFunction;
|
import me.topchetoeu.jscript.runtime.values.CodeFunction;
|
||||||
import me.topchetoeu.jscript.runtime.values.FunctionValue;
|
import me.topchetoeu.jscript.runtime.values.FunctionValue;
|
||||||
@ -22,40 +21,43 @@ public class AsyncFunctionLib extends FunctionValue {
|
|||||||
|
|
||||||
private boolean awaiting = false;
|
private boolean awaiting = false;
|
||||||
|
|
||||||
private void next(Context ctx, Object inducedValue, EngineException inducedError) {
|
private void next(Environment env, 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, Values.NO_RETURN, inducedError);
|
if (inducedValue != Values.NO_RETURN) res = frame.next(inducedValue);
|
||||||
|
else if (inducedError != null) res = frame.induceError(inducedError);
|
||||||
|
else res = frame.next();
|
||||||
|
|
||||||
inducedValue = Values.NO_RETURN;
|
inducedValue = Values.NO_RETURN;
|
||||||
inducedError = null;
|
inducedError = null;
|
||||||
|
|
||||||
if (res != Values.NO_RETURN) {
|
if (res != Values.NO_RETURN) {
|
||||||
promise.fulfill(ctx, res);
|
promise.fulfill(env, res);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (EngineException e) {
|
catch (EngineException e) {
|
||||||
promise.reject(ctx, e);
|
promise.reject(env, e);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
frame.onPop();
|
frame.onPop();
|
||||||
|
|
||||||
if (awaiting) {
|
if (awaiting) {
|
||||||
PromiseLib.handle(ctx, frame.pop(), new Handle() {
|
PromiseLib.handle(env, frame.pop(), new Handle() {
|
||||||
@Override
|
@Override
|
||||||
public void onFulfil(Object val) {
|
public void onFulfil(Object val) {
|
||||||
next(ctx, val, null);
|
next(env, val, null);
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
public void onReject(EngineException err) {
|
public void onReject(EngineException err) {
|
||||||
next(ctx, Values.NO_RETURN, err);
|
next(env, Values.NO_RETURN, err);
|
||||||
}
|
}
|
||||||
}.defer(ctx));
|
}.defer(env));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -66,16 +68,15 @@ public class AsyncFunctionLib extends FunctionValue {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object call(Extensions ext, Object thisArg, Object ...args) {
|
public Object call(Environment env, Object thisArg, Object ...args) {
|
||||||
var handler = new AsyncHelper();
|
var handler = new AsyncHelper();
|
||||||
var ctx = Context.of(ext);
|
|
||||||
|
|
||||||
var newArgs = new Object[args.length + 1];
|
var newArgs = new Object[args.length + 1];
|
||||||
newArgs[0] = new NativeFunction("await", handler::await);
|
newArgs[0] = new NativeFunction("await", handler::await);
|
||||||
System.arraycopy(args, 0, newArgs, 1, args.length);
|
System.arraycopy(args, 0, newArgs, 1, args.length);
|
||||||
|
|
||||||
handler.frame = new Frame(ctx, thisArg, newArgs, (CodeFunction)func);
|
handler.frame = new Frame(env, thisArg, newArgs, (CodeFunction)func);
|
||||||
handler.next(ctx, Values.NO_RETURN, null);
|
handler.next(env, Values.NO_RETURN, null);
|
||||||
return handler.promise;
|
return handler.promise;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
package me.topchetoeu.jscript.lib;
|
package me.topchetoeu.jscript.lib;
|
||||||
|
|
||||||
import me.topchetoeu.jscript.runtime.Context;
|
|
||||||
import me.topchetoeu.jscript.runtime.Extensions;
|
|
||||||
import me.topchetoeu.jscript.runtime.Frame;
|
import me.topchetoeu.jscript.runtime.Frame;
|
||||||
|
import me.topchetoeu.jscript.runtime.environment.Environment;
|
||||||
import me.topchetoeu.jscript.runtime.exceptions.EngineException;
|
import me.topchetoeu.jscript.runtime.exceptions.EngineException;
|
||||||
import me.topchetoeu.jscript.runtime.values.CodeFunction;
|
import me.topchetoeu.jscript.runtime.values.CodeFunction;
|
||||||
import me.topchetoeu.jscript.runtime.values.FunctionValue;
|
import me.topchetoeu.jscript.runtime.values.FunctionValue;
|
||||||
@ -14,7 +13,7 @@ public class AsyncGeneratorFunctionLib extends FunctionValue {
|
|||||||
public final CodeFunction func;
|
public final CodeFunction func;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object call(Extensions ext, Object thisArg, Object ...args) {
|
public Object call(Environment ext, Object thisArg, Object ...args) {
|
||||||
var handler = new AsyncGeneratorLib();
|
var handler = new AsyncGeneratorLib();
|
||||||
|
|
||||||
var newArgs = new Object[args.length + 2];
|
var newArgs = new Object[args.length + 2];
|
||||||
@ -22,13 +21,13 @@ public class AsyncGeneratorFunctionLib extends FunctionValue {
|
|||||||
newArgs[1] = new NativeFunction("yield", handler::yield);
|
newArgs[1] = new NativeFunction("yield", handler::yield);
|
||||||
System.arraycopy(args, 0, newArgs, 2, args.length);
|
System.arraycopy(args, 0, newArgs, 2, args.length);
|
||||||
|
|
||||||
handler.frame = new Frame(Context.of(ext), thisArg, newArgs, func);
|
handler.frame = new Frame(ext, thisArg, newArgs, func);
|
||||||
return handler;
|
return handler;
|
||||||
}
|
}
|
||||||
|
|
||||||
public AsyncGeneratorFunctionLib(CodeFunction func) {
|
public AsyncGeneratorFunctionLib(CodeFunction func) {
|
||||||
super(func.name, func.length);
|
super(func.name, func.length);
|
||||||
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 code function.");
|
||||||
this.func = func;
|
this.func = func;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,8 +3,8 @@ package me.topchetoeu.jscript.lib;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import me.topchetoeu.jscript.lib.PromiseLib.Handle;
|
import me.topchetoeu.jscript.lib.PromiseLib.Handle;
|
||||||
import me.topchetoeu.jscript.runtime.Context;
|
|
||||||
import me.topchetoeu.jscript.runtime.Frame;
|
import me.topchetoeu.jscript.runtime.Frame;
|
||||||
|
import me.topchetoeu.jscript.runtime.environment.Environment;
|
||||||
import me.topchetoeu.jscript.runtime.exceptions.EngineException;
|
import me.topchetoeu.jscript.runtime.exceptions.EngineException;
|
||||||
import me.topchetoeu.jscript.runtime.values.ObjectValue;
|
import me.topchetoeu.jscript.runtime.values.ObjectValue;
|
||||||
import me.topchetoeu.jscript.runtime.values.Values;
|
import me.topchetoeu.jscript.runtime.values.Values;
|
||||||
@ -19,10 +19,10 @@ public class AsyncGeneratorLib {
|
|||||||
private PromiseLib currPromise;
|
private PromiseLib currPromise;
|
||||||
public Frame frame;
|
public Frame frame;
|
||||||
|
|
||||||
private void next(Context ctx, Object inducedValue, Object inducedReturn, EngineException inducedError) {
|
private void next(Environment env, Object inducedValue, Object inducedReturn, EngineException inducedError) {
|
||||||
if (done) {
|
if (done) {
|
||||||
if (inducedError != null) throw inducedError;
|
if (inducedError != null) throw inducedError;
|
||||||
currPromise.fulfill(ctx, new ObjectValue(ctx, Map.of(
|
currPromise.fulfill(env, new ObjectValue(env, Map.of(
|
||||||
"done", true,
|
"done", true,
|
||||||
"value", inducedReturn == Values.NO_RETURN ? null : inducedReturn
|
"value", inducedReturn == Values.NO_RETURN ? null : inducedReturn
|
||||||
)));
|
)));
|
||||||
@ -35,40 +35,44 @@ public class AsyncGeneratorLib {
|
|||||||
frame.onPush();
|
frame.onPush();
|
||||||
while (state == 0) {
|
while (state == 0) {
|
||||||
try {
|
try {
|
||||||
res = frame.next(inducedValue, inducedReturn, inducedError);
|
if (inducedValue != Values.NO_RETURN) res = frame.next(inducedValue);
|
||||||
|
else if (inducedReturn != Values.NO_RETURN) res = frame.induceReturn(inducedValue);
|
||||||
|
else if (inducedError != null) res = frame.induceError(inducedError);
|
||||||
|
else res = frame.next();
|
||||||
|
|
||||||
inducedValue = inducedReturn = Values.NO_RETURN;
|
inducedValue = inducedReturn = Values.NO_RETURN;
|
||||||
inducedError = null;
|
inducedError = null;
|
||||||
|
|
||||||
if (res != Values.NO_RETURN) {
|
if (res != Values.NO_RETURN) {
|
||||||
var obj = new ObjectValue();
|
var obj = new ObjectValue();
|
||||||
obj.defineProperty(ctx, "done", true);
|
obj.defineProperty(env, "done", true);
|
||||||
obj.defineProperty(ctx, "value", res);
|
obj.defineProperty(env, "value", res);
|
||||||
currPromise.fulfill(ctx, obj);
|
currPromise.fulfill(env, obj);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (EngineException e) {
|
catch (EngineException e) {
|
||||||
currPromise.reject(ctx, e);
|
currPromise.reject(env, e);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
frame.onPop();
|
frame.onPop();
|
||||||
|
|
||||||
if (state == 1) {
|
if (state == 1) {
|
||||||
PromiseLib.handle(ctx, frame.pop(), new Handle() {
|
PromiseLib.handle(env, frame.pop(), new Handle() {
|
||||||
@Override public void onFulfil(Object val) {
|
@Override public void onFulfil(Object val) {
|
||||||
next(ctx, val, Values.NO_RETURN, null);
|
next(env, val, Values.NO_RETURN, null);
|
||||||
}
|
}
|
||||||
@Override public void onReject(EngineException err) {
|
@Override public void onReject(EngineException err) {
|
||||||
next(ctx, Values.NO_RETURN, Values.NO_RETURN, err);
|
next(env, Values.NO_RETURN, Values.NO_RETURN, err);
|
||||||
}
|
}
|
||||||
}.defer(ctx));
|
}.defer(env));
|
||||||
}
|
}
|
||||||
else if (state == 2) {
|
else if (state == 2) {
|
||||||
var obj = new ObjectValue();
|
var obj = new ObjectValue();
|
||||||
obj.defineProperty(ctx, "done", false);
|
obj.defineProperty(env, "done", false);
|
||||||
obj.defineProperty(ctx, "value", frame.pop());
|
obj.defineProperty(env, "value", frame.pop());
|
||||||
currPromise.fulfill(ctx, obj);
|
currPromise.fulfill(env, obj);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -90,18 +94,18 @@ public class AsyncGeneratorLib {
|
|||||||
|
|
||||||
@Expose public PromiseLib __next(Arguments args) {
|
@Expose public PromiseLib __next(Arguments args) {
|
||||||
this.currPromise = new PromiseLib();
|
this.currPromise = new PromiseLib();
|
||||||
if (args.has(0)) next(args.ctx, args.get(0), Values.NO_RETURN, null);
|
if (args.has(0)) next(args.env, args.get(0), Values.NO_RETURN, null);
|
||||||
else next(args.ctx, Values.NO_RETURN, Values.NO_RETURN, null);
|
else next(args.env, Values.NO_RETURN, Values.NO_RETURN, null);
|
||||||
return this.currPromise;
|
return this.currPromise;
|
||||||
}
|
}
|
||||||
@Expose public PromiseLib __return(Arguments args) {
|
@Expose public PromiseLib __return(Arguments args) {
|
||||||
this.currPromise = new PromiseLib();
|
this.currPromise = new PromiseLib();
|
||||||
next(args.ctx, Values.NO_RETURN, args.get(0), null);
|
next(args.env, Values.NO_RETURN, args.get(0), null);
|
||||||
return this.currPromise;
|
return this.currPromise;
|
||||||
}
|
}
|
||||||
@Expose public PromiseLib __throw(Arguments args) {
|
@Expose public PromiseLib __throw(Arguments args) {
|
||||||
this.currPromise = new PromiseLib();
|
this.currPromise = new PromiseLib();
|
||||||
next(args.ctx, Values.NO_RETURN, Values.NO_RETURN, new EngineException(args.get(0)).setExtensions(args.ctx));
|
next(args.env, Values.NO_RETURN, Values.NO_RETURN, new EngineException(args.get(0)).setEnvironment(args.env));
|
||||||
return this.currPromise;
|
return this.currPromise;
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -24,7 +24,7 @@ public class ConsoleLib {
|
|||||||
for (var el : args.args) {
|
for (var el : args.args) {
|
||||||
if (!first) res.append(" ");
|
if (!first) res.append(" ");
|
||||||
first = false;
|
first = false;
|
||||||
res.append(Values.toReadable(args.ctx, el).getBytes());
|
res.append(Values.toReadable(args.env, el).getBytes());
|
||||||
}
|
}
|
||||||
|
|
||||||
for (var line : res.toString().split("\n", -1)) {
|
for (var line : res.toString().split("\n", -1)) {
|
||||||
|
@ -66,7 +66,7 @@ public class EncodingLib {
|
|||||||
public static String __decode(Arguments args) {
|
public static String __decode(Arguments args) {
|
||||||
var raw = args.convert(0, ArrayList.class);
|
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(args.ctx, raw.get(i));
|
for (var i = 0; i < raw.size(); i++) res[i] = (byte)Values.toNumber(args.env, raw.get(i));
|
||||||
return new String(res);
|
return new String(res);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
package me.topchetoeu.jscript.lib;
|
package me.topchetoeu.jscript.lib;
|
||||||
|
|
||||||
import me.topchetoeu.jscript.runtime.Context;
|
import me.topchetoeu.jscript.runtime.environment.Environment;
|
||||||
import me.topchetoeu.jscript.runtime.exceptions.ConvertException;
|
import me.topchetoeu.jscript.runtime.exceptions.ConvertException;
|
||||||
import me.topchetoeu.jscript.runtime.values.ObjectValue;
|
import me.topchetoeu.jscript.runtime.values.ObjectValue;
|
||||||
import me.topchetoeu.jscript.runtime.values.Values;
|
import me.topchetoeu.jscript.runtime.values.Values;
|
||||||
@ -13,7 +13,7 @@ import me.topchetoeu.jscript.utils.interop.WrapperName;
|
|||||||
|
|
||||||
@WrapperName("Error")
|
@WrapperName("Error")
|
||||||
public class ErrorLib {
|
public class ErrorLib {
|
||||||
private static String toString(Context ctx, Object name, Object message) {
|
private static String toString(Environment 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 = "";
|
||||||
@ -30,9 +30,9 @@ public class ErrorLib {
|
|||||||
@ExposeField public static final String __name = "Error";
|
@ExposeField public static final String __name = "Error";
|
||||||
|
|
||||||
@Expose public static String __toString(Arguments args) {
|
@Expose public static String __toString(Arguments args) {
|
||||||
if (args.self instanceof ObjectValue) return toString(args.ctx,
|
if (args.self instanceof ObjectValue) return toString(args.env,
|
||||||
Values.getMember(args.ctx, args.self, "name"),
|
Values.getMember(args.env, args.self, "name"),
|
||||||
Values.getMember(args.ctx, args.self, "message")
|
Values.getMember(args.env, args.self, "message")
|
||||||
);
|
);
|
||||||
else return "[Invalid error]";
|
else return "[Invalid error]";
|
||||||
}
|
}
|
||||||
@ -47,7 +47,7 @@ public class ErrorLib {
|
|||||||
catch (ConvertException e) {}
|
catch (ConvertException e) {}
|
||||||
|
|
||||||
target.setPrototype(PlaceholderProto.ERROR);
|
target.setPrototype(PlaceholderProto.ERROR);
|
||||||
target.defineProperty(args.ctx, "message", Values.toString(args.ctx, message));
|
target.defineProperty(args.env, "message", Values.toString(args.env, message));
|
||||||
|
|
||||||
return target;
|
return target;
|
||||||
}
|
}
|
||||||
|
@ -13,7 +13,7 @@ public class FileLib {
|
|||||||
public final File fd;
|
public final File fd;
|
||||||
|
|
||||||
@Expose public PromiseLib __pointer(Arguments args) {
|
@Expose public PromiseLib __pointer(Arguments args) {
|
||||||
return PromiseLib.await(args.ctx, () -> {
|
return PromiseLib.await(args.env, () -> {
|
||||||
try {
|
try {
|
||||||
return fd.seek(0, 1);
|
return fd.seek(0, 1);
|
||||||
}
|
}
|
||||||
@ -21,7 +21,7 @@ public class FileLib {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
@Expose public PromiseLib __length(Arguments args) {
|
@Expose public PromiseLib __length(Arguments args) {
|
||||||
return PromiseLib.await(args.ctx, () -> {
|
return PromiseLib.await(args.env, () -> {
|
||||||
try {
|
try {
|
||||||
long curr = fd.seek(0, 1);
|
long curr = fd.seek(0, 1);
|
||||||
long res = fd.seek(0, 2);
|
long res = fd.seek(0, 2);
|
||||||
@ -33,26 +33,26 @@ public class FileLib {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Expose public PromiseLib __read(Arguments args) {
|
@Expose public PromiseLib __read(Arguments args) {
|
||||||
return PromiseLib.await(args.ctx, () -> {
|
return PromiseLib.await(args.env, () -> {
|
||||||
var n = args.getInt(0);
|
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 = fd.read(buff);
|
int resI = fd.read(buff);
|
||||||
|
|
||||||
for (var i = resI - 1; i >= 0; i--) res.set(args.ctx, i, (int)buff[i]);
|
for (var i = resI - 1; i >= 0; i--) res.set(args.env, i, (int)buff[i]);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
catch (FilesystemException e) { throw e.toEngineException(); }
|
catch (FilesystemException e) { throw e.toEngineException(); }
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@Expose public PromiseLib __write(Arguments args) {
|
@Expose public PromiseLib __write(Arguments args) {
|
||||||
return PromiseLib.await(args.ctx, () -> {
|
return PromiseLib.await(args.env, () -> {
|
||||||
var val = args.convert(0, ArrayValue.class);
|
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(args.ctx, val.get(i));
|
for (var i = 0; i < val.size(); i++) res[i] = (byte)Values.toNumber(args.env, val.get(i));
|
||||||
fd.write(res);
|
fd.write(res);
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
@ -61,13 +61,13 @@ public class FileLib {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
@Expose public PromiseLib __close(Arguments args) {
|
@Expose public PromiseLib __close(Arguments args) {
|
||||||
return PromiseLib.await(args.ctx, () -> {
|
return PromiseLib.await(args.env, () -> {
|
||||||
fd.close();
|
fd.close();
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@Expose public PromiseLib __seek(Arguments args) {
|
@Expose public PromiseLib __seek(Arguments args) {
|
||||||
return PromiseLib.await(args.ctx, () -> {
|
return PromiseLib.await(args.env, () -> {
|
||||||
var ptr = args.getLong(0);
|
var ptr = args.getLong(0);
|
||||||
var whence = args.getInt(1);
|
var whence = args.getInt(1);
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@ import java.io.IOException;
|
|||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.Stack;
|
import java.util.Stack;
|
||||||
|
|
||||||
import me.topchetoeu.jscript.runtime.Context;
|
import me.topchetoeu.jscript.runtime.environment.Environment;
|
||||||
import me.topchetoeu.jscript.runtime.exceptions.EngineException;
|
import me.topchetoeu.jscript.runtime.exceptions.EngineException;
|
||||||
import me.topchetoeu.jscript.runtime.values.ObjectValue;
|
import me.topchetoeu.jscript.runtime.values.ObjectValue;
|
||||||
import me.topchetoeu.jscript.runtime.values.Values;
|
import me.topchetoeu.jscript.runtime.values.Values;
|
||||||
@ -31,21 +31,21 @@ public class FilesystemLib {
|
|||||||
@ExposeField(target = ExposeTarget.STATIC)
|
@ExposeField(target = ExposeTarget.STATIC)
|
||||||
public static final int __SEEK_END = 2;
|
public static final int __SEEK_END = 2;
|
||||||
|
|
||||||
private static Filesystem fs(Context ctx) {
|
private static Filesystem fs(Environment env) {
|
||||||
var fs = Filesystem.get(ctx);
|
var fs = Filesystem.get(env);
|
||||||
if (fs != null) return fs;
|
if (fs != null) return fs;
|
||||||
throw EngineException.ofError("Current environment doesn't have a file system.");
|
throw EngineException.ofError("Current environment doesn't have a file system.");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Expose(target = ExposeTarget.STATIC)
|
@Expose(target = ExposeTarget.STATIC)
|
||||||
public static String __normalize(Arguments args) {
|
public static String __normalize(Arguments args) {
|
||||||
return fs(args.ctx).normalize(args.convert(String.class));
|
return fs(args.env).normalize(args.convert(String.class));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Expose(target = ExposeTarget.STATIC)
|
@Expose(target = ExposeTarget.STATIC)
|
||||||
public static PromiseLib __open(Arguments args) {
|
public static PromiseLib __open(Arguments args) {
|
||||||
return PromiseLib.await(args.ctx, () -> {
|
return PromiseLib.await(args.env, () -> {
|
||||||
var fs = fs(args.ctx);
|
var fs = fs(args.env);
|
||||||
var path = fs.normalize(args.getString(0));
|
var path = fs.normalize(args.getString(0));
|
||||||
var _mode = Mode.parse(args.getString(1));
|
var _mode = Mode.parse(args.getString(1));
|
||||||
|
|
||||||
@ -62,7 +62,7 @@ public class FilesystemLib {
|
|||||||
@Expose(target = ExposeTarget.STATIC)
|
@Expose(target = ExposeTarget.STATIC)
|
||||||
public static ObjectValue __ls(Arguments args) {
|
public static ObjectValue __ls(Arguments args) {
|
||||||
|
|
||||||
return Values.toJSAsyncIterator(args.ctx, new Iterator<>() {
|
return Values.toJSAsyncIterator(args.env, new Iterator<>() {
|
||||||
private boolean failed, done;
|
private boolean failed, done;
|
||||||
private File file;
|
private File file;
|
||||||
private String nextLine;
|
private String nextLine;
|
||||||
@ -71,7 +71,7 @@ public class FilesystemLib {
|
|||||||
if (done) return;
|
if (done) return;
|
||||||
if (!failed) {
|
if (!failed) {
|
||||||
if (file == null) {
|
if (file == null) {
|
||||||
var fs = fs(args.ctx);
|
var fs = fs(args.env);
|
||||||
var path = fs.normalize(args.getString(0));
|
var path = fs.normalize(args.getString(0));
|
||||||
|
|
||||||
if (fs.stat(path).type != EntryType.FOLDER) {
|
if (fs.stat(path).type != EntryType.FOLDER) {
|
||||||
@ -117,9 +117,9 @@ public class FilesystemLib {
|
|||||||
}
|
}
|
||||||
@Expose(target = ExposeTarget.STATIC)
|
@Expose(target = ExposeTarget.STATIC)
|
||||||
public static PromiseLib __mkdir(Arguments args) throws IOException {
|
public static PromiseLib __mkdir(Arguments args) throws IOException {
|
||||||
return PromiseLib.await(args.ctx, () -> {
|
return PromiseLib.await(args.env, () -> {
|
||||||
try {
|
try {
|
||||||
fs(args.ctx).create(args.getString(0), EntryType.FOLDER);
|
fs(args.env).create(args.getString(0), EntryType.FOLDER);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
catch (FilesystemException e) { throw e.toEngineException(); }
|
catch (FilesystemException e) { throw e.toEngineException(); }
|
||||||
@ -128,9 +128,9 @@ public class FilesystemLib {
|
|||||||
}
|
}
|
||||||
@Expose(target = ExposeTarget.STATIC)
|
@Expose(target = ExposeTarget.STATIC)
|
||||||
public static PromiseLib __mkfile(Arguments args) throws IOException {
|
public static PromiseLib __mkfile(Arguments args) throws IOException {
|
||||||
return PromiseLib.await(args.ctx, () -> {
|
return PromiseLib.await(args.env, () -> {
|
||||||
try {
|
try {
|
||||||
fs(args.ctx).create(args.getString(0), EntryType.FILE);
|
fs(args.env).create(args.getString(0), EntryType.FILE);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
catch (FilesystemException e) { throw e.toEngineException(); }
|
catch (FilesystemException e) { throw e.toEngineException(); }
|
||||||
@ -138,9 +138,9 @@ public class FilesystemLib {
|
|||||||
}
|
}
|
||||||
@Expose(target = ExposeTarget.STATIC)
|
@Expose(target = ExposeTarget.STATIC)
|
||||||
public static PromiseLib __rm(Arguments args) throws IOException {
|
public static PromiseLib __rm(Arguments args) throws IOException {
|
||||||
return PromiseLib.await(args.ctx, () -> {
|
return PromiseLib.await(args.env, () -> {
|
||||||
try {
|
try {
|
||||||
var fs = fs(args.ctx);
|
var fs = fs(args.env);
|
||||||
var path = fs.normalize(args.getString(0));
|
var path = fs.normalize(args.getString(0));
|
||||||
var recursive = args.getBoolean(1);
|
var recursive = args.getBoolean(1);
|
||||||
|
|
||||||
@ -169,15 +169,15 @@ public class FilesystemLib {
|
|||||||
}
|
}
|
||||||
@Expose(target = ExposeTarget.STATIC)
|
@Expose(target = ExposeTarget.STATIC)
|
||||||
public static PromiseLib __stat(Arguments args) throws IOException {
|
public static PromiseLib __stat(Arguments args) throws IOException {
|
||||||
return PromiseLib.await(args.ctx, () -> {
|
return PromiseLib.await(args.env, () -> {
|
||||||
try {
|
try {
|
||||||
var fs = fs(args.ctx);
|
var fs = fs(args.env);
|
||||||
var path = fs.normalize(args.getString(0));
|
var path = fs.normalize(args.getString(0));
|
||||||
var stat = fs.stat(path);
|
var stat = fs.stat(path);
|
||||||
var res = new ObjectValue();
|
var res = new ObjectValue();
|
||||||
|
|
||||||
res.defineProperty(args.ctx, "type", stat.type.name);
|
res.defineProperty(args.env, "type", stat.type.name);
|
||||||
res.defineProperty(args.ctx, "mode", stat.mode.name);
|
res.defineProperty(args.env, "mode", stat.mode.name);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
catch (FilesystemException e) { throw e.toEngineException(); }
|
catch (FilesystemException e) { throw e.toEngineException(); }
|
||||||
@ -185,8 +185,8 @@ public class FilesystemLib {
|
|||||||
}
|
}
|
||||||
@Expose(target = ExposeTarget.STATIC)
|
@Expose(target = ExposeTarget.STATIC)
|
||||||
public static PromiseLib __exists(Arguments args) throws IOException {
|
public static PromiseLib __exists(Arguments args) throws IOException {
|
||||||
return PromiseLib.await(args.ctx, () -> {
|
return PromiseLib.await(args.env, () -> {
|
||||||
try { fs(args.ctx).stat(args.getString(0)); return true; }
|
try { fs(args.env).stat(args.getString(0)); return true; }
|
||||||
catch (FilesystemException e) { return false; }
|
catch (FilesystemException e) { return false; }
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,6 @@ package me.topchetoeu.jscript.lib;
|
|||||||
|
|
||||||
import me.topchetoeu.jscript.common.Filename;
|
import me.topchetoeu.jscript.common.Filename;
|
||||||
import me.topchetoeu.jscript.runtime.Compiler;
|
import me.topchetoeu.jscript.runtime.Compiler;
|
||||||
import me.topchetoeu.jscript.runtime.Context;
|
|
||||||
import me.topchetoeu.jscript.runtime.scope.ValueVariable;
|
import me.topchetoeu.jscript.runtime.scope.ValueVariable;
|
||||||
import me.topchetoeu.jscript.runtime.values.ArrayValue;
|
import me.topchetoeu.jscript.runtime.values.ArrayValue;
|
||||||
import me.topchetoeu.jscript.runtime.values.CodeFunction;
|
import me.topchetoeu.jscript.runtime.values.CodeFunction;
|
||||||
@ -20,10 +19,10 @@ public class FunctionLib {
|
|||||||
private static int i;
|
private static int i;
|
||||||
|
|
||||||
@Expose public static Object __apply(Arguments args) {
|
@Expose public static Object __apply(Arguments args) {
|
||||||
return args.self(FunctionValue.class).call(args.ctx, args.get(0), args.convert(1, ArrayValue.class).toArray());
|
return args.self(FunctionValue.class).call(args.env, args.get(0), args.convert(1, ArrayValue.class).toArray());
|
||||||
}
|
}
|
||||||
@Expose public static Object __call(Arguments args) {
|
@Expose public static Object __call(Arguments args) {
|
||||||
return args.self(FunctionValue.class).call(args.ctx, args.get(0), args.slice(1).args);
|
return args.self(FunctionValue.class).call(args.env, args.get(0), args.slice(1).args);
|
||||||
}
|
}
|
||||||
@Expose public static FunctionValue __bind(Arguments args) {
|
@Expose public static FunctionValue __bind(Arguments args) {
|
||||||
var self = args.self(FunctionValue.class);
|
var self = args.self(FunctionValue.class);
|
||||||
@ -40,7 +39,7 @@ public class FunctionLib {
|
|||||||
System.arraycopy(callArgs.args, 0, resArgs, bindArgs.length, callArgs.n());
|
System.arraycopy(callArgs.args, 0, resArgs, bindArgs.length, callArgs.n());
|
||||||
}
|
}
|
||||||
|
|
||||||
return self.call(callArgs.ctx, thisArg, resArgs);
|
return self.call(callArgs.env, thisArg, resArgs);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@Expose public static String __toString(Arguments args) {
|
@Expose public static String __toString(Arguments args) {
|
||||||
@ -62,8 +61,6 @@ public class FunctionLib {
|
|||||||
|
|
||||||
@ExposeConstructor
|
@ExposeConstructor
|
||||||
public static Object __constructor(Arguments args) {
|
public static Object __constructor(Arguments args) {
|
||||||
var compiler = Compiler.get(args);
|
|
||||||
|
|
||||||
var parts = args.convert(String.class);
|
var parts = args.convert(String.class);
|
||||||
if (parts.length == 0) parts = new String[] { "" };
|
if (parts.length == 0) parts = new String[] { "" };
|
||||||
|
|
||||||
@ -76,8 +73,8 @@ public class FunctionLib {
|
|||||||
|
|
||||||
src += "){" + parts[parts.length - 1] + "}";
|
src += "){" + parts[parts.length - 1] + "}";
|
||||||
|
|
||||||
var body = compiler.compile(new Filename("jscript", "func/" + i++), src);
|
var body = Compiler.get(args.env).compile(new Filename("jscript", "func/" + i++), src);
|
||||||
var func = new CodeFunction(Context.clean(args.ctx), "", body, new ValueVariable[0]);
|
var func = new CodeFunction(args.env, "", body, new ValueVariable[0]);
|
||||||
return Values.call(args, func, null);
|
return Values.call(args.env, func, null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
package me.topchetoeu.jscript.lib;
|
package me.topchetoeu.jscript.lib;
|
||||||
|
|
||||||
import me.topchetoeu.jscript.runtime.Context;
|
|
||||||
import me.topchetoeu.jscript.runtime.Extensions;
|
|
||||||
import me.topchetoeu.jscript.runtime.Frame;
|
import me.topchetoeu.jscript.runtime.Frame;
|
||||||
|
import me.topchetoeu.jscript.runtime.environment.Environment;
|
||||||
import me.topchetoeu.jscript.runtime.exceptions.EngineException;
|
import me.topchetoeu.jscript.runtime.exceptions.EngineException;
|
||||||
import me.topchetoeu.jscript.runtime.values.CodeFunction;
|
import me.topchetoeu.jscript.runtime.values.CodeFunction;
|
||||||
import me.topchetoeu.jscript.runtime.values.FunctionValue;
|
import me.topchetoeu.jscript.runtime.values.FunctionValue;
|
||||||
@ -13,14 +12,14 @@ import me.topchetoeu.jscript.utils.interop.WrapperName;
|
|||||||
public class GeneratorFunctionLib extends FunctionValue {
|
public class GeneratorFunctionLib extends FunctionValue {
|
||||||
public final CodeFunction func;
|
public final CodeFunction func;
|
||||||
|
|
||||||
@Override public Object call(Extensions ext, Object thisArg, Object ...args) {
|
@Override public Object call(Environment env, Object thisArg, Object ...args) {
|
||||||
var handler = new GeneratorLib();
|
var handler = new GeneratorLib();
|
||||||
|
|
||||||
var newArgs = new Object[args.length + 1];
|
var newArgs = new Object[args.length + 1];
|
||||||
newArgs[0] = new NativeFunction("yield", handler::yield);
|
newArgs[0] = new NativeFunction("yield", handler::yield);
|
||||||
System.arraycopy(args, 0, newArgs, 1, args.length);
|
System.arraycopy(args, 0, newArgs, 1, args.length);
|
||||||
|
|
||||||
handler.frame = new Frame(Context.of(ext), thisArg, newArgs, func);
|
handler.frame = new Frame(env, thisArg, newArgs, func);
|
||||||
return handler;
|
return handler;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
package me.topchetoeu.jscript.lib;
|
package me.topchetoeu.jscript.lib;
|
||||||
|
|
||||||
import me.topchetoeu.jscript.runtime.Context;
|
|
||||||
import me.topchetoeu.jscript.runtime.Frame;
|
import me.topchetoeu.jscript.runtime.Frame;
|
||||||
|
import me.topchetoeu.jscript.runtime.environment.Environment;
|
||||||
import me.topchetoeu.jscript.runtime.exceptions.EngineException;
|
import me.topchetoeu.jscript.runtime.exceptions.EngineException;
|
||||||
import me.topchetoeu.jscript.runtime.values.ObjectValue;
|
import me.topchetoeu.jscript.runtime.values.ObjectValue;
|
||||||
import me.topchetoeu.jscript.runtime.values.Values;
|
import me.topchetoeu.jscript.runtime.values.Values;
|
||||||
@ -15,12 +15,12 @@ public class GeneratorLib {
|
|||||||
private boolean done = false;
|
private boolean done = false;
|
||||||
public Frame frame;
|
public Frame frame;
|
||||||
|
|
||||||
private ObjectValue next(Context ctx, Object inducedValue, Object inducedReturn, EngineException inducedError) {
|
private ObjectValue next(Environment env, Object inducedValue, Object inducedReturn, EngineException inducedError) {
|
||||||
if (done) {
|
if (done) {
|
||||||
if (inducedError != Values.NO_RETURN) throw inducedError;
|
if (inducedError != Values.NO_RETURN) throw inducedError;
|
||||||
var res = new ObjectValue();
|
var res = new ObjectValue();
|
||||||
res.defineProperty(ctx, "done", true);
|
res.defineProperty(env, "done", true);
|
||||||
res.defineProperty(ctx, "value", inducedReturn == Values.NO_RETURN ? null : inducedReturn);
|
res.defineProperty(env, "value", inducedReturn == Values.NO_RETURN ? null : inducedReturn);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -30,7 +30,11 @@ public class GeneratorLib {
|
|||||||
frame.onPush();
|
frame.onPush();
|
||||||
while (!yielding) {
|
while (!yielding) {
|
||||||
try {
|
try {
|
||||||
res = frame.next(inducedValue, inducedReturn, inducedError);
|
if (inducedValue != Values.NO_RETURN) res = frame.next(inducedValue);
|
||||||
|
else if (inducedReturn != Values.NO_RETURN) res = frame.induceReturn(inducedValue);
|
||||||
|
else if (inducedError != null) res = frame.induceError(inducedError);
|
||||||
|
else res = frame.next();
|
||||||
|
|
||||||
inducedReturn = Values.NO_RETURN;
|
inducedReturn = Values.NO_RETURN;
|
||||||
inducedError = null;
|
inducedError = null;
|
||||||
if (res != Values.NO_RETURN) {
|
if (res != Values.NO_RETURN) {
|
||||||
@ -49,20 +53,20 @@ public class GeneratorLib {
|
|||||||
else res = frame.pop();
|
else res = frame.pop();
|
||||||
|
|
||||||
var obj = new ObjectValue();
|
var obj = new ObjectValue();
|
||||||
obj.defineProperty(ctx, "done", done);
|
obj.defineProperty(env, "done", done);
|
||||||
obj.defineProperty(ctx, "value", res);
|
obj.defineProperty(env, "value", res);
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Expose public ObjectValue __next(Arguments args) {
|
@Expose public ObjectValue __next(Arguments args) {
|
||||||
if (args.n() == 0) return next(args.ctx, Values.NO_RETURN, Values.NO_RETURN, null);
|
if (args.n() == 0) return next(args.env, Values.NO_RETURN, Values.NO_RETURN, null);
|
||||||
else return next(args.ctx, args.get(0), Values.NO_RETURN, null);
|
else return next(args.env, args.get(0), Values.NO_RETURN, null);
|
||||||
}
|
}
|
||||||
@Expose public ObjectValue __throw(Arguments args) {
|
@Expose public ObjectValue __throw(Arguments args) {
|
||||||
return next(args.ctx, Values.NO_RETURN, Values.NO_RETURN, new EngineException(args.get(0)).setExtensions(args.ctx));
|
return next(args.env, Values.NO_RETURN, Values.NO_RETURN, new EngineException(args.get(0)).setEnvironment(args.env));
|
||||||
}
|
}
|
||||||
@Expose public ObjectValue __return(Arguments args) {
|
@Expose public ObjectValue __return(Arguments args) {
|
||||||
return next(args.ctx, Values.NO_RETURN, args.get(0), null);
|
return next(args.env, Values.NO_RETURN, args.get(0), null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override public String toString() {
|
@Override public String toString() {
|
||||||
|
@ -2,10 +2,9 @@ package me.topchetoeu.jscript.lib;
|
|||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
|
||||||
import me.topchetoeu.jscript.runtime.Context;
|
|
||||||
import me.topchetoeu.jscript.runtime.Environment;
|
|
||||||
import me.topchetoeu.jscript.runtime.EventLoop;
|
import me.topchetoeu.jscript.runtime.EventLoop;
|
||||||
import me.topchetoeu.jscript.runtime.Key;
|
import me.topchetoeu.jscript.runtime.environment.Environment;
|
||||||
|
import me.topchetoeu.jscript.runtime.environment.Key;
|
||||||
import me.topchetoeu.jscript.runtime.exceptions.EngineException;
|
import me.topchetoeu.jscript.runtime.exceptions.EngineException;
|
||||||
import me.topchetoeu.jscript.runtime.scope.GlobalScope;
|
import me.topchetoeu.jscript.runtime.scope.GlobalScope;
|
||||||
import me.topchetoeu.jscript.runtime.values.FunctionValue;
|
import me.topchetoeu.jscript.runtime.values.FunctionValue;
|
||||||
@ -26,11 +25,11 @@ public class Internals {
|
|||||||
|
|
||||||
@Expose(target = ExposeTarget.STATIC)
|
@Expose(target = ExposeTarget.STATIC)
|
||||||
public static Object __require(Arguments args) {
|
public static Object __require(Arguments args) {
|
||||||
var repo = ModuleRepo.get(args.ctx);
|
var repo = ModuleRepo.get(args.env);
|
||||||
|
|
||||||
if (repo != null) {
|
if (repo != null) {
|
||||||
var res = repo.getModule(args.ctx, ModuleRepo.cwd(args.ctx), args.getString(0));
|
var res = repo.getModule(args.env, ModuleRepo.cwd(args.env), args.getString(0));
|
||||||
res.load(args.ctx);
|
res.load(args.env);
|
||||||
return res.value();
|
return res.value();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -43,7 +42,7 @@ public class Internals {
|
|||||||
var delay = args.getDouble(1);
|
var delay = args.getDouble(1);
|
||||||
var arguments = args.slice(2).args;
|
var arguments = args.slice(2).args;
|
||||||
|
|
||||||
if (!args.ctx.hasNotNull(EventLoop.KEY)) throw EngineException.ofError("No event loop");
|
if (!args.env.hasNotNull(EventLoop.KEY)) throw EngineException.ofError("No event loop");
|
||||||
|
|
||||||
var thread = new Thread(() -> {
|
var thread = new Thread(() -> {
|
||||||
var ms = (long)delay;
|
var ms = (long)delay;
|
||||||
@ -52,13 +51,17 @@ public class Internals {
|
|||||||
try { Thread.sleep(ms, ns); }
|
try { Thread.sleep(ms, ns); }
|
||||||
catch (InterruptedException e) { return; }
|
catch (InterruptedException e) { return; }
|
||||||
|
|
||||||
args.ctx.get(EventLoop.KEY).pushMsg(() -> func.call(new Context(args.ctx.extensions), null, arguments), false);
|
args.env.get(EventLoop.KEY).pushMsg(() -> func.call(args.env, null, arguments), false);
|
||||||
});
|
});
|
||||||
|
|
||||||
thread.start();
|
thread.start();
|
||||||
var i = args.ctx.init(I, 1);
|
|
||||||
args.ctx.add(I, i + 1);
|
args.env.init(I, 1);
|
||||||
args.ctx.init(THREADS, new HashMap<Integer, Thread>()).put(i, thread);
|
args.env.init(THREADS, new HashMap<>());
|
||||||
|
var i = args.env.get(I);
|
||||||
|
|
||||||
|
args.env.add(I, i + 1);
|
||||||
|
args.env.get(THREADS).put(i, thread);
|
||||||
|
|
||||||
return thread;
|
return thread;
|
||||||
}
|
}
|
||||||
@ -68,7 +71,7 @@ public class Internals {
|
|||||||
var delay = args.getDouble(1);
|
var delay = args.getDouble(1);
|
||||||
var arguments = args.slice(2).args;
|
var arguments = args.slice(2).args;
|
||||||
|
|
||||||
if (!args.ctx.hasNotNull(EventLoop.KEY)) throw EngineException.ofError("No event loop");
|
if (!args.env.hasNotNull(EventLoop.KEY)) throw EngineException.ofError("No event loop");
|
||||||
|
|
||||||
var thread = new Thread(() -> {
|
var thread = new Thread(() -> {
|
||||||
var ms = (long)delay;
|
var ms = (long)delay;
|
||||||
@ -80,13 +83,18 @@ public class Internals {
|
|||||||
}
|
}
|
||||||
catch (InterruptedException e) { return; }
|
catch (InterruptedException e) { return; }
|
||||||
|
|
||||||
args.ctx.get(EventLoop.KEY).pushMsg(() -> func.call(new Context(args.ctx.extensions), null, arguments), false);
|
args.env.get(EventLoop.KEY).pushMsg(() -> func.call(args.env, null, arguments), false);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
thread.start();
|
thread.start();
|
||||||
var i = args.ctx.init(I, 1);
|
|
||||||
args.ctx.add(I, i + 1);
|
args.env.init(I, 1);
|
||||||
args.ctx.init(THREADS, new HashMap<Integer, Thread>()).put(i, thread);
|
args.env.init(THREADS, new HashMap<>());
|
||||||
|
var i = args.env.get(I);
|
||||||
|
|
||||||
|
args.env.add(I, i + 1);
|
||||||
|
args.env.get(THREADS).put(i, thread);
|
||||||
|
|
||||||
return thread;
|
return thread;
|
||||||
}
|
}
|
||||||
@ -94,7 +102,7 @@ public class Internals {
|
|||||||
@Expose(target = ExposeTarget.STATIC)
|
@Expose(target = ExposeTarget.STATIC)
|
||||||
public static void __clearTimeout(Arguments args) {
|
public static void __clearTimeout(Arguments args) {
|
||||||
var i = args.getInt(0);
|
var i = args.getInt(0);
|
||||||
HashMap<Integer, Thread> map = args.ctx.get(THREADS);
|
HashMap<Integer, Thread> map = args.env.get(THREADS);
|
||||||
if (map == null) return;
|
if (map == null) return;
|
||||||
|
|
||||||
var thread = map.get(i);
|
var thread = map.get(i);
|
||||||
@ -132,15 +140,15 @@ public class Internals {
|
|||||||
|
|
||||||
@Expose(target = ExposeTarget.STATIC, type = ExposeType.GETTER)
|
@Expose(target = ExposeTarget.STATIC, type = ExposeType.GETTER)
|
||||||
public static FileLib __stdin(Arguments args) {
|
public static FileLib __stdin(Arguments args) {
|
||||||
return new FileLib(Filesystem.get(args.ctx).open("std://in", Mode.READ));
|
return new FileLib(Filesystem.get(args.env).open("std://in", Mode.READ));
|
||||||
}
|
}
|
||||||
@Expose(target = ExposeTarget.STATIC, type = ExposeType.GETTER)
|
@Expose(target = ExposeTarget.STATIC, type = ExposeType.GETTER)
|
||||||
public static FileLib __stdout(Arguments args) {
|
public static FileLib __stdout(Arguments args) {
|
||||||
return new FileLib(Filesystem.get(args.ctx).open("std://out", Mode.READ));
|
return new FileLib(Filesystem.get(args.env).open("std://out", Mode.READ));
|
||||||
}
|
}
|
||||||
@Expose(target = ExposeTarget.STATIC, type = ExposeType.GETTER)
|
@Expose(target = ExposeTarget.STATIC, type = ExposeType.GETTER)
|
||||||
public static FileLib __stderr(Arguments args) {
|
public static FileLib __stderr(Arguments args) {
|
||||||
return new FileLib(Filesystem.get(args.ctx).open("std://err", Mode.READ));
|
return new FileLib(Filesystem.get(args.env).open("std://err", Mode.READ));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ExposeField(target = ExposeTarget.STATIC)
|
@ExposeField(target = ExposeTarget.STATIC)
|
||||||
@ -211,12 +219,11 @@ public class Internals {
|
|||||||
env.add(Environment.RANGE_ERR_PROTO, wp.getProto(RangeErrorLib.class));
|
env.add(Environment.RANGE_ERR_PROTO, wp.getProto(RangeErrorLib.class));
|
||||||
|
|
||||||
env.add(Environment.REGEX_CONSTR, wp.getConstr(RegExpLib.class));
|
env.add(Environment.REGEX_CONSTR, wp.getConstr(RegExpLib.class));
|
||||||
Values.setPrototype(new Context(), wp.getProto(ObjectLib.class), null);
|
Values.setPrototype(Environment.empty(), wp.getProto(ObjectLib.class), null);
|
||||||
|
|
||||||
env.add(NativeWrapperProvider.KEY, wp);
|
env.add(NativeWrapperProvider.KEY, wp);
|
||||||
env.add(GlobalScope.KEY, glob);
|
env.add(GlobalScope.KEY, glob);
|
||||||
|
|
||||||
|
|
||||||
return env;
|
return env;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,6 +19,6 @@ public class JSONLib {
|
|||||||
}
|
}
|
||||||
@Expose(target = ExposeTarget.STATIC)
|
@Expose(target = ExposeTarget.STATIC)
|
||||||
public static String __stringify(Arguments args) {
|
public static String __stringify(Arguments args) {
|
||||||
return JSON.stringify(JSON.fromJs(args.ctx, args.get(0)));
|
return JSON.stringify(JSON.fromJs(args.env, args.get(0)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,7 @@ import java.util.ArrayList;
|
|||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import me.topchetoeu.jscript.runtime.Context;
|
import me.topchetoeu.jscript.runtime.environment.Environment;
|
||||||
import me.topchetoeu.jscript.runtime.values.ArrayValue;
|
import me.topchetoeu.jscript.runtime.values.ArrayValue;
|
||||||
import me.topchetoeu.jscript.runtime.values.ObjectValue;
|
import me.topchetoeu.jscript.runtime.values.ObjectValue;
|
||||||
import me.topchetoeu.jscript.runtime.values.Values;
|
import me.topchetoeu.jscript.runtime.values.Values;
|
||||||
@ -36,18 +36,18 @@ public class MapLib {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Expose public ObjectValue __entries(Arguments args) {
|
@Expose public ObjectValue __entries(Arguments args) {
|
||||||
return Values.toJSIterator(args.ctx, map
|
return Values.toJSIterator(args.env, map
|
||||||
.entrySet()
|
.entrySet()
|
||||||
.stream()
|
.stream()
|
||||||
.map(v -> new ArrayValue(args.ctx, v.getKey(), v.getValue()))
|
.map(v -> new ArrayValue(args.env, v.getKey(), v.getValue()))
|
||||||
.collect(Collectors.toList())
|
.collect(Collectors.toList())
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@Expose public ObjectValue __keys(Arguments args) {
|
@Expose public ObjectValue __keys(Arguments args) {
|
||||||
return Values.toJSIterator(args.ctx, map.keySet());
|
return Values.toJSIterator(args.env, map.keySet());
|
||||||
}
|
}
|
||||||
@Expose public ObjectValue __values(Arguments args) {
|
@Expose public ObjectValue __values(Arguments args) {
|
||||||
return Values.toJSIterator(args.ctx, map.values());
|
return Values.toJSIterator(args.env, map.values());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Expose public Object __get(Arguments args) {
|
@Expose public Object __get(Arguments args) {
|
||||||
@ -69,19 +69,19 @@ public class MapLib {
|
|||||||
@Expose public void __forEach(Arguments args) {
|
@Expose public void __forEach(Arguments args) {
|
||||||
var keys = new ArrayList<>(map.keySet());
|
var keys = new ArrayList<>(map.keySet());
|
||||||
|
|
||||||
for (var el : keys) Values.call(args.ctx, args.get(0), args.get(1), map.get(el), el, args.self);
|
for (var el : keys) Values.call(args.env, args.get(0), args.get(1), map.get(el), el, args.self);
|
||||||
}
|
}
|
||||||
|
|
||||||
public MapLib(Context ctx, Object iterable) {
|
public MapLib(Environment env, Object iterable) {
|
||||||
for (var el : Values.fromJSIterator(ctx, iterable)) {
|
for (var el : Values.fromJSIterator(env, iterable)) {
|
||||||
try {
|
try {
|
||||||
map.put(Values.getMember(ctx, el, 0), Values.getMember(ctx, el, 1));
|
map.put(Values.getMember(env, el, 0), Values.getMember(env, el, 1));
|
||||||
}
|
}
|
||||||
catch (IllegalArgumentException e) { }
|
catch (IllegalArgumentException e) { }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ExposeConstructor public static MapLib __constructor(Arguments args) {
|
@ExposeConstructor public static MapLib __constructor(Arguments args) {
|
||||||
return new MapLib(args.ctx, args.get(0));
|
return new MapLib(args.env, args.get(0));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -85,7 +85,7 @@ public class NumberLib {
|
|||||||
else return args.getDouble(0);
|
else return args.getDouble(0);
|
||||||
}
|
}
|
||||||
@Expose public static String __toString(Arguments args) {
|
@Expose public static String __toString(Arguments args) {
|
||||||
return Values.toString(args.ctx, args.self);
|
return Values.toString(args.env, args.self);
|
||||||
}
|
}
|
||||||
@Expose public static String __toFixed(Arguments args) {
|
@Expose public static String __toFixed(Arguments args) {
|
||||||
var digits = args.getInt(0, 0);
|
var digits = args.getInt(0, 0);
|
||||||
@ -98,6 +98,6 @@ public class NumberLib {
|
|||||||
}
|
}
|
||||||
@Expose public static double __valueOf(Arguments args) {
|
@Expose public static double __valueOf(Arguments args) {
|
||||||
if (Values.isWrapper(args.self, NumberLib.class)) return Values.wrapper(args.self, NumberLib.class).value;
|
if (Values.isWrapper(args.self, NumberLib.class)) return Values.wrapper(args.self, NumberLib.class).value;
|
||||||
else return Values.toNumber(args.ctx, args.self);
|
else return Values.toNumber(args.env, args.self);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,8 +17,8 @@ public class ObjectLib {
|
|||||||
@Expose(target = ExposeTarget.STATIC)
|
@Expose(target = ExposeTarget.STATIC)
|
||||||
public static Object __assign(Arguments args) {
|
public static Object __assign(Arguments args) {
|
||||||
for (var obj : args.slice(1).args) {
|
for (var obj : args.slice(1).args) {
|
||||||
for (var key : Values.getMembers(args.ctx, obj, true, true)) {
|
for (var key : Values.getMembers(args.env, obj, true, true)) {
|
||||||
Values.setMember(args.ctx, args.get(0), key, Values.getMember(args.ctx, obj, key));
|
Values.setMember(args.env, args.get(0), key, Values.getMember(args.env, obj, key));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return args.get(0);
|
return args.get(0);
|
||||||
@ -26,14 +26,14 @@ public class ObjectLib {
|
|||||||
@Expose(target = ExposeTarget.STATIC)
|
@Expose(target = ExposeTarget.STATIC)
|
||||||
public static ObjectValue __create(Arguments args) {
|
public static ObjectValue __create(Arguments args) {
|
||||||
var obj = new ObjectValue();
|
var obj = new ObjectValue();
|
||||||
Values.setPrototype(args.ctx, obj, args.get(0));
|
Values.setPrototype(args.env, obj, args.get(0));
|
||||||
|
|
||||||
if (args.n() >= 1) {
|
if (args.n() >= 1) {
|
||||||
var newArgs = new Object[args.n()];
|
var newArgs = new Object[args.n()];
|
||||||
System.arraycopy(args.args, 1, args, 1, args.n() - 1);
|
System.arraycopy(args.args, 1, args, 1, args.n() - 1);
|
||||||
newArgs[0] = obj;
|
newArgs[0] = obj;
|
||||||
|
|
||||||
__defineProperties(new Arguments(args.ctx, null, newArgs));
|
__defineProperties(new Arguments(args.env, null, newArgs));
|
||||||
}
|
}
|
||||||
|
|
||||||
return obj;
|
return obj;
|
||||||
@ -45,31 +45,31 @@ public class ObjectLib {
|
|||||||
var key = args.get(1);
|
var key = args.get(1);
|
||||||
var attrib = args.convert(2, ObjectValue.class);
|
var attrib = args.convert(2, ObjectValue.class);
|
||||||
|
|
||||||
var hasVal = Values.hasMember(args.ctx, attrib, "value", false);
|
var hasVal = Values.hasMember(args.env, attrib, "value", false);
|
||||||
var hasGet = Values.hasMember(args.ctx, attrib, "get", false);
|
var hasGet = Values.hasMember(args.env, attrib, "get", false);
|
||||||
var hasSet = Values.hasMember(args.ctx, attrib, "set", false);
|
var hasSet = Values.hasMember(args.env, attrib, "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(
|
||||||
args.ctx, key,
|
args.env, key,
|
||||||
Values.getMember(args.ctx, attrib, "value"),
|
Values.getMember(args.env, attrib, "value"),
|
||||||
Values.toBoolean(Values.getMember(args.ctx, attrib, "writable")),
|
Values.toBoolean(Values.getMember(args.env, attrib, "writable")),
|
||||||
Values.toBoolean(Values.getMember(args.ctx, attrib, "configurable")),
|
Values.toBoolean(Values.getMember(args.env, attrib, "configurable")),
|
||||||
Values.toBoolean(Values.getMember(args.ctx, attrib, "enumerable"))
|
Values.toBoolean(Values.getMember(args.env, attrib, "enumerable"))
|
||||||
)) throw EngineException.ofType("Can't define property '" + key + "'.");
|
)) throw EngineException.ofType("Can't define property '" + key + "'.");
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
var get = Values.getMember(args.ctx, attrib, "get");
|
var get = Values.getMember(args.env, attrib, "get");
|
||||||
var set = Values.getMember(args.ctx, attrib, "set");
|
var set = Values.getMember(args.env, attrib, "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(
|
||||||
args.ctx, key,
|
args.env, key,
|
||||||
(FunctionValue)get, (FunctionValue)set,
|
(FunctionValue)get, (FunctionValue)set,
|
||||||
Values.toBoolean(Values.getMember(args.ctx, attrib, "configurable")),
|
Values.toBoolean(Values.getMember(args.env, attrib, "configurable")),
|
||||||
Values.toBoolean(Values.getMember(args.ctx, attrib, "enumerable"))
|
Values.toBoolean(Values.getMember(args.env, attrib, "enumerable"))
|
||||||
)) throw EngineException.ofType("Can't define property '" + key + "'.");
|
)) throw EngineException.ofType("Can't define property '" + key + "'.");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -81,7 +81,7 @@ public class ObjectLib {
|
|||||||
var attrib = args.get(1);
|
var attrib = args.get(1);
|
||||||
|
|
||||||
for (var key : Values.getMembers(null, attrib, false, false)) {
|
for (var key : Values.getMembers(null, attrib, false, false)) {
|
||||||
__defineProperty(new Arguments(args.ctx, null, obj, key, Values.getMember(args.ctx, attrib, key)));
|
__defineProperty(new Arguments(args.env, null, obj, key, Values.getMember(args.env, attrib, key)));
|
||||||
}
|
}
|
||||||
|
|
||||||
return obj;
|
return obj;
|
||||||
@ -93,8 +93,8 @@ public class ObjectLib {
|
|||||||
var all = args.getBoolean(1);
|
var all = args.getBoolean(1);
|
||||||
var res = new ArrayValue();
|
var res = new ArrayValue();
|
||||||
|
|
||||||
for (var key : Values.getMembers(args.ctx, obj, true, false)) {
|
for (var key : Values.getMembers(args.env, obj, true, false)) {
|
||||||
if (all || !(key instanceof Symbol)) res.set(args.ctx, res.size(), key);
|
if (all || !(key instanceof Symbol)) res.set(args.env, res.size(), key);
|
||||||
}
|
}
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
@ -105,8 +105,8 @@ public class ObjectLib {
|
|||||||
var obj = args.get(0);
|
var obj = args.get(0);
|
||||||
var all = args.getBoolean(1);
|
var all = args.getBoolean(1);
|
||||||
|
|
||||||
for (var key : Values.getMembers(args.ctx, obj, true, false)) {
|
for (var key : Values.getMembers(args.env, obj, true, false)) {
|
||||||
if (all || !(key instanceof Symbol)) res.set(args.ctx, res.size(), new ArrayValue(args.ctx, key, Values.getMember(args.ctx, obj, key)));
|
if (all || !(key instanceof Symbol)) res.set(args.env, res.size(), new ArrayValue(args.env, key, Values.getMember(args.env, obj, key)));
|
||||||
}
|
}
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
@ -117,8 +117,8 @@ public class ObjectLib {
|
|||||||
var obj = args.get(0);
|
var obj = args.get(0);
|
||||||
var all = args.getBoolean(1);
|
var all = args.getBoolean(1);
|
||||||
|
|
||||||
for (var key : Values.getMembers(args.ctx, obj, true, false)) {
|
for (var key : Values.getMembers(args.env, obj, true, false)) {
|
||||||
if (all || !(key instanceof Symbol)) res.set(args.ctx, res.size(), Values.getMember(args.ctx, obj, key));
|
if (all || !(key instanceof Symbol)) res.set(args.env, res.size(), Values.getMember(args.env, obj, key));
|
||||||
}
|
}
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
@ -126,14 +126,14 @@ public class ObjectLib {
|
|||||||
|
|
||||||
@Expose(target = ExposeTarget.STATIC)
|
@Expose(target = ExposeTarget.STATIC)
|
||||||
public static ObjectValue __getOwnPropertyDescriptor(Arguments args) {
|
public static ObjectValue __getOwnPropertyDescriptor(Arguments args) {
|
||||||
return Values.getMemberDescriptor(args.ctx, args.get(0), args.get(1));
|
return Values.getMemberDescriptor(args.env, args.get(0), args.get(1));
|
||||||
}
|
}
|
||||||
@Expose(target = ExposeTarget.STATIC)
|
@Expose(target = ExposeTarget.STATIC)
|
||||||
public static ObjectValue __getOwnPropertyDescriptors(Arguments args) {
|
public static ObjectValue __getOwnPropertyDescriptors(Arguments args) {
|
||||||
var res = new ObjectValue();
|
var res = new ObjectValue();
|
||||||
var obj = args.get(0);
|
var obj = args.get(0);
|
||||||
for (var key : Values.getMembers(args.ctx, obj, true, true)) {
|
for (var key : Values.getMembers(args.env, obj, true, true)) {
|
||||||
res.defineProperty(args.ctx, key, Values.getMemberDescriptor(args.ctx, obj, key));
|
res.defineProperty(args.env, key, Values.getMemberDescriptor(args.env, obj, key));
|
||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
@ -144,8 +144,8 @@ public class ObjectLib {
|
|||||||
var obj = args.get(0);
|
var obj = args.get(0);
|
||||||
var all = args.getBoolean(1);
|
var all = args.getBoolean(1);
|
||||||
|
|
||||||
for (var key : Values.getMembers(args.ctx, obj, true, true)) {
|
for (var key : Values.getMembers(args.env, obj, true, true)) {
|
||||||
if (all || !(key instanceof Symbol)) res.set(args.ctx, res.size(), key);
|
if (all || !(key instanceof Symbol)) res.set(args.env, res.size(), key);
|
||||||
}
|
}
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
@ -155,24 +155,24 @@ public class ObjectLib {
|
|||||||
var obj = args.get(0);
|
var obj = args.get(0);
|
||||||
var res = new ArrayValue();
|
var res = new ArrayValue();
|
||||||
|
|
||||||
for (var key : Values.getMembers(args.ctx, obj, true, true)) {
|
for (var key : Values.getMembers(args.env, obj, true, true)) {
|
||||||
if (key instanceof Symbol) res.set(args.ctx, res.size(), key);
|
if (key instanceof Symbol) res.set(args.env, res.size(), key);
|
||||||
}
|
}
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
@Expose(target = ExposeTarget.STATIC)
|
@Expose(target = ExposeTarget.STATIC)
|
||||||
public static boolean __hasOwn(Arguments args) {
|
public static boolean __hasOwn(Arguments args) {
|
||||||
return Values.hasMember(args.ctx, args.get(0), args.get(1), true);
|
return Values.hasMember(args.env, args.get(0), args.get(1), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Expose(target = ExposeTarget.STATIC)
|
@Expose(target = ExposeTarget.STATIC)
|
||||||
public static ObjectValue __getPrototypeOf(Arguments args) {
|
public static ObjectValue __getPrototypeOf(Arguments args) {
|
||||||
return Values.getPrototype(args.ctx, args.get(0));
|
return Values.getPrototype(args.env, args.get(0));
|
||||||
}
|
}
|
||||||
@Expose(target = ExposeTarget.STATIC)
|
@Expose(target = ExposeTarget.STATIC)
|
||||||
public static Object __setPrototypeOf(Arguments args) {
|
public static Object __setPrototypeOf(Arguments args) {
|
||||||
Values.setPrototype(args.ctx, args.get(0), args.get(1));
|
Values.setPrototype(args.env, args.get(0), args.get(1));
|
||||||
return args.get(0);
|
return args.get(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -180,9 +180,9 @@ public class ObjectLib {
|
|||||||
public static ObjectValue __fromEntries(Arguments args) {
|
public static ObjectValue __fromEntries(Arguments args) {
|
||||||
var res = new ObjectValue();
|
var res = new ObjectValue();
|
||||||
|
|
||||||
for (var el : Values.fromJSIterator(args.ctx, args.get(0))) {
|
for (var el : Values.fromJSIterator(args.env, args.get(0))) {
|
||||||
if (el instanceof ArrayValue) {
|
if (el instanceof ArrayValue) {
|
||||||
res.defineProperty(args.ctx, ((ArrayValue)el).get(0), ((ArrayValue)el).get(1));
|
res.defineProperty(args.env, ((ArrayValue)el).get(0), ((ArrayValue)el).get(1));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -249,15 +249,15 @@ public class ObjectLib {
|
|||||||
}
|
}
|
||||||
@Expose
|
@Expose
|
||||||
public static String __toString(Arguments args) {
|
public static String __toString(Arguments args) {
|
||||||
var name = Values.getMember(args.ctx, args.self, Symbol.get("Symbol.typeName"));
|
var name = Values.getMember(args.env, args.self, Symbol.get("Symbol.typeName"));
|
||||||
if (name == null) name = "Unknown";
|
if (name == null) name = "Unknown";
|
||||||
else name = Values.toString(args.ctx, name);
|
else name = Values.toString(args.env, name);
|
||||||
|
|
||||||
return "[object " + name + "]";
|
return "[object " + name + "]";
|
||||||
}
|
}
|
||||||
@Expose
|
@Expose
|
||||||
public static boolean __hasOwnProperty(Arguments args) {
|
public static boolean __hasOwnProperty(Arguments args) {
|
||||||
return Values.hasMember(args.ctx, args.self, args.get(0), true);
|
return Values.hasMember(args.env, args.self, args.get(0), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ExposeConstructor
|
@ExposeConstructor
|
||||||
|
@ -4,9 +4,8 @@ import java.util.ArrayList;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import me.topchetoeu.jscript.common.ResultRunnable;
|
import me.topchetoeu.jscript.common.ResultRunnable;
|
||||||
import me.topchetoeu.jscript.runtime.Context;
|
|
||||||
import me.topchetoeu.jscript.runtime.EventLoop;
|
import me.topchetoeu.jscript.runtime.EventLoop;
|
||||||
import me.topchetoeu.jscript.runtime.Extensions;
|
import me.topchetoeu.jscript.runtime.environment.Environment;
|
||||||
import me.topchetoeu.jscript.runtime.exceptions.EngineException;
|
import me.topchetoeu.jscript.runtime.exceptions.EngineException;
|
||||||
import me.topchetoeu.jscript.runtime.exceptions.InterruptException;
|
import me.topchetoeu.jscript.runtime.exceptions.InterruptException;
|
||||||
import me.topchetoeu.jscript.runtime.values.ArrayValue;
|
import me.topchetoeu.jscript.runtime.values.ArrayValue;
|
||||||
@ -26,7 +25,7 @@ public class PromiseLib {
|
|||||||
void onFulfil(Object val);
|
void onFulfil(Object val);
|
||||||
void onReject(EngineException err);
|
void onReject(EngineException err);
|
||||||
|
|
||||||
default Handle defer(Extensions loop) {
|
default Handle defer(Environment loop) {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
return new Handle() {
|
return new Handle() {
|
||||||
@ -52,7 +51,7 @@ public class PromiseLib {
|
|||||||
private boolean handled = false;
|
private boolean handled = false;
|
||||||
private Object val;
|
private Object val;
|
||||||
|
|
||||||
private void resolveSynchronized(Context ctx, Object val, int newState) {
|
private void resolveSynchronized(Environment env, Object val, int newState) {
|
||||||
this.val = val;
|
this.val = val;
|
||||||
this.state = newState;
|
this.state = newState;
|
||||||
|
|
||||||
@ -65,7 +64,7 @@ public class PromiseLib {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (state == STATE_REJECTED && !handled) {
|
if (state == STATE_REJECTED && !handled) {
|
||||||
Values.printError(((EngineException)val).setExtensions(ctx), "(in promise)");
|
Values.printError(((EngineException)val).setEnvironment(env), "(in promise)");
|
||||||
}
|
}
|
||||||
|
|
||||||
handles = null;
|
handles = null;
|
||||||
@ -78,24 +77,24 @@ public class PromiseLib {
|
|||||||
// }, true);
|
// }, true);
|
||||||
|
|
||||||
}
|
}
|
||||||
private synchronized void resolve(Context ctx, Object val, int newState) {
|
private synchronized void resolve(Environment env, Object val, int newState) {
|
||||||
if (this.state != STATE_PENDING || newState == STATE_PENDING) return;
|
if (this.state != STATE_PENDING || newState == STATE_PENDING) return;
|
||||||
|
|
||||||
handle(ctx, val, new Handle() {
|
handle(env, val, new Handle() {
|
||||||
@Override public void onFulfil(Object val) {
|
@Override public void onFulfil(Object val) {
|
||||||
resolveSynchronized(ctx, val, newState);
|
resolveSynchronized(env, val, newState);
|
||||||
}
|
}
|
||||||
@Override public void onReject(EngineException err) {
|
@Override public void onReject(EngineException err) {
|
||||||
resolveSynchronized(ctx, val, STATE_REJECTED);
|
resolveSynchronized(env, val, STATE_REJECTED);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized void fulfill(Context ctx, Object val) {
|
public synchronized void fulfill(Environment env, Object val) {
|
||||||
resolve(ctx, val, STATE_FULFILLED);
|
resolve(env, val, STATE_FULFILLED);
|
||||||
}
|
}
|
||||||
public synchronized void reject(Context ctx, EngineException val) {
|
public synchronized void reject(Environment env, EngineException val) {
|
||||||
resolve(ctx, val, STATE_REJECTED);
|
resolve(env, val, STATE_REJECTED);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handle(Handle handle) {
|
private void handle(Handle handle) {
|
||||||
@ -118,37 +117,37 @@ public class PromiseLib {
|
|||||||
this.val = null;
|
this.val = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static PromiseLib await(Context ctx, ResultRunnable<Object> runner) {
|
public static PromiseLib await(Environment env, ResultRunnable<Object> runner) {
|
||||||
var res = new PromiseLib();
|
var res = new PromiseLib();
|
||||||
|
|
||||||
new Thread(() -> {
|
new Thread(() -> {
|
||||||
try {
|
try {
|
||||||
res.fulfill(ctx, runner.run());
|
res.fulfill(env, runner.run());
|
||||||
}
|
}
|
||||||
catch (EngineException e) {
|
catch (EngineException e) {
|
||||||
res.reject(ctx, e);
|
res.reject(env, e);
|
||||||
}
|
}
|
||||||
catch (Exception e) {
|
catch (Exception e) {
|
||||||
if (e instanceof InterruptException) throw e;
|
if (e instanceof InterruptException) throw e;
|
||||||
else {
|
else {
|
||||||
res.reject(ctx, EngineException.ofError("Native code failed with " + e.getMessage()));
|
res.reject(env, EngineException.ofError("Native code failed with " + e.getMessage()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, "Promisifier").start();
|
}, "Promisifier").start();
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
public static PromiseLib await(Context ctx, Runnable runner) {
|
public static PromiseLib await(Environment env, Runnable runner) {
|
||||||
return await(ctx, () -> {
|
return await(env, () -> {
|
||||||
runner.run();
|
runner.run();
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void handle(Context ctx, Object obj, Handle handle) {
|
public static void handle(Environment env, Object obj, Handle handle) {
|
||||||
if (Values.isWrapper(obj, PromiseLib.class)) {
|
if (Values.isWrapper(obj, PromiseLib.class)) {
|
||||||
var promise = Values.wrapper(obj, PromiseLib.class);
|
var promise = Values.wrapper(obj, PromiseLib.class);
|
||||||
handle(ctx, promise, handle);
|
handle(env, promise, handle);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (obj instanceof PromiseLib) {
|
if (obj instanceof PromiseLib) {
|
||||||
@ -159,9 +158,9 @@ public class PromiseLib {
|
|||||||
var rethrow = new boolean[1];
|
var rethrow = new boolean[1];
|
||||||
|
|
||||||
try {
|
try {
|
||||||
var then = Values.getMember(ctx, obj, "then");
|
var then = Values.getMember(env, obj, "then");
|
||||||
|
|
||||||
if (then instanceof FunctionValue) Values.call(ctx, then, obj,
|
if (then instanceof FunctionValue) Values.call(env, then, obj,
|
||||||
new NativeFunction(args -> {
|
new NativeFunction(args -> {
|
||||||
try { handle.onFulfil(args.get(0)); }
|
try { handle.onFulfil(args.get(0)); }
|
||||||
catch (Exception e) {
|
catch (Exception e) {
|
||||||
@ -190,12 +189,12 @@ public class PromiseLib {
|
|||||||
handle.onFulfil(obj);
|
handle.onFulfil(obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static PromiseLib ofResolved(Context ctx, Object value) {
|
public static PromiseLib ofResolved(Environment ctx, Object value) {
|
||||||
var res = new PromiseLib();
|
var res = new PromiseLib();
|
||||||
res.fulfill(ctx, value);
|
res.fulfill(ctx, value);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
public static PromiseLib ofRejected(Context ctx, EngineException value) {
|
public static PromiseLib ofRejected(Environment ctx, EngineException value) {
|
||||||
var res = new PromiseLib();
|
var res = new PromiseLib();
|
||||||
res.reject(ctx, value);
|
res.reject(ctx, value);
|
||||||
return res;
|
return res;
|
||||||
@ -203,11 +202,11 @@ public class PromiseLib {
|
|||||||
|
|
||||||
@Expose(value = "resolve", target = ExposeTarget.STATIC)
|
@Expose(value = "resolve", target = ExposeTarget.STATIC)
|
||||||
public static PromiseLib __ofResolved(Arguments args) {
|
public static PromiseLib __ofResolved(Arguments args) {
|
||||||
return ofResolved(args.ctx, args.get(0));
|
return ofResolved(args.env, args.get(0));
|
||||||
}
|
}
|
||||||
@Expose(value = "reject", target = ExposeTarget.STATIC)
|
@Expose(value = "reject", target = ExposeTarget.STATIC)
|
||||||
public static PromiseLib __ofRejected(Arguments args) {
|
public static PromiseLib __ofRejected(Arguments args) {
|
||||||
return ofRejected(args.ctx, new EngineException(args.get(0)).setExtensions(args.ctx));
|
return ofRejected(args.env, new EngineException(args.get(0)).setEnvironment(args.env));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Expose(target = ExposeTarget.STATIC)
|
@Expose(target = ExposeTarget.STATIC)
|
||||||
@ -215,7 +214,7 @@ public class PromiseLib {
|
|||||||
if (!(args.get(0) instanceof ArrayValue)) throw EngineException.ofType("Expected argument for any to be an array.");
|
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 promises = args.convert(0, ArrayValue.class);
|
||||||
|
|
||||||
if (promises.size() == 0) return ofRejected(args.ctx, EngineException.ofError("No promises passed to 'Promise.any'.").setExtensions(args.ctx));
|
if (promises.size() == 0) return ofRejected(args.env, EngineException.ofError("No promises passed to 'Promise.any'.").setEnvironment(args.env));
|
||||||
var n = new int[] { promises.size() };
|
var n = new int[] { promises.size() };
|
||||||
var res = new PromiseLib();
|
var res = new PromiseLib();
|
||||||
var errors = new ArrayValue();
|
var errors = new ArrayValue();
|
||||||
@ -225,12 +224,12 @@ public class PromiseLib {
|
|||||||
var val = promises.get(i);
|
var val = promises.get(i);
|
||||||
if (res.state != STATE_PENDING) break;
|
if (res.state != STATE_PENDING) break;
|
||||||
|
|
||||||
handle(args.ctx, val, new Handle() {
|
handle(args.env, val, new Handle() {
|
||||||
public void onFulfil(Object val) { res.fulfill(args.ctx, val); }
|
public void onFulfil(Object val) { res.fulfill(args.env, val); }
|
||||||
public void onReject(EngineException err) {
|
public void onReject(EngineException err) {
|
||||||
errors.set(args.ctx, index, err.value);
|
errors.set(args.env, index, err.value);
|
||||||
n[0]--;
|
n[0]--;
|
||||||
if (n[0] <= 0) res.reject(args.ctx, new EngineException(errors).setExtensions(args.ctx));
|
if (n[0] <= 0) res.reject(args.env, new EngineException(errors).setEnvironment(args.env));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -247,9 +246,9 @@ public class PromiseLib {
|
|||||||
var val = promises.get(i);
|
var val = promises.get(i);
|
||||||
if (res.state != STATE_PENDING) break;
|
if (res.state != STATE_PENDING) break;
|
||||||
|
|
||||||
handle(args.ctx, val, new Handle() {
|
handle(args.env, val, new Handle() {
|
||||||
@Override public void onFulfil(Object val) { res.fulfill(args.ctx, val); }
|
@Override public void onFulfil(Object val) { res.fulfill(args.env, val); }
|
||||||
@Override public void onReject(EngineException err) { res.reject(args.ctx, err); }
|
@Override public void onReject(EngineException err) { res.reject(args.env, err); }
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -269,19 +268,19 @@ public class PromiseLib {
|
|||||||
var index = i;
|
var index = i;
|
||||||
var val = promises.get(i);
|
var val = promises.get(i);
|
||||||
|
|
||||||
handle(args.ctx, val, new Handle() {
|
handle(args.env, val, new Handle() {
|
||||||
@Override public void onFulfil(Object val) {
|
@Override public void onFulfil(Object val) {
|
||||||
result.set(args.ctx, index, val);
|
result.set(args.env, index, val);
|
||||||
n[0]--;
|
n[0]--;
|
||||||
if (n[0] <= 0) res.fulfill(args.ctx, result);
|
if (n[0] <= 0) res.fulfill(args.env, result);
|
||||||
}
|
}
|
||||||
@Override public void onReject(EngineException err) {
|
@Override public void onReject(EngineException err) {
|
||||||
res.reject(args.ctx, err);
|
res.reject(args.env, err);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (n[0] <= 0) res.fulfill(args.ctx, result);
|
if (n[0] <= 0) res.fulfill(args.env, result);
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
@ -298,31 +297,31 @@ public class PromiseLib {
|
|||||||
|
|
||||||
var index = i;
|
var index = i;
|
||||||
|
|
||||||
handle(args.ctx, promises.get(i), new Handle() {
|
handle(args.env, promises.get(i), new Handle() {
|
||||||
@Override public void onFulfil(Object val) {
|
@Override public void onFulfil(Object val) {
|
||||||
var desc = new ObjectValue();
|
var desc = new ObjectValue();
|
||||||
desc.defineProperty(args.ctx, "status", "fulfilled");
|
desc.defineProperty(args.env, "status", "fulfilled");
|
||||||
desc.defineProperty(args.ctx, "value", val);
|
desc.defineProperty(args.env, "value", val);
|
||||||
|
|
||||||
result.set(args.ctx, index, desc);
|
result.set(args.env, index, desc);
|
||||||
|
|
||||||
n[0]--;
|
n[0]--;
|
||||||
if (n[0] <= 0) res.fulfill(args.ctx, res);
|
if (n[0] <= 0) res.fulfill(args.env, res);
|
||||||
}
|
}
|
||||||
@Override public void onReject(EngineException err) {
|
@Override public void onReject(EngineException err) {
|
||||||
var desc = new ObjectValue();
|
var desc = new ObjectValue();
|
||||||
desc.defineProperty(args.ctx, "status", "reject");
|
desc.defineProperty(args.env, "status", "reject");
|
||||||
desc.defineProperty(args.ctx, "value", err.value);
|
desc.defineProperty(args.env, "value", err.value);
|
||||||
|
|
||||||
result.set(args.ctx, index, desc);
|
result.set(args.env, index, desc);
|
||||||
|
|
||||||
n[0]--;
|
n[0]--;
|
||||||
if (n[0] <= 0) res.fulfill(args.ctx, res);
|
if (n[0] <= 0) res.fulfill(args.env, res);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (n[0] <= 0) res.fulfill(args.ctx, result);
|
if (n[0] <= 0) res.fulfill(args.env, result);
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
@ -334,22 +333,22 @@ public class PromiseLib {
|
|||||||
|
|
||||||
var res = new PromiseLib();
|
var res = new PromiseLib();
|
||||||
|
|
||||||
handle(args.ctx, args.self, new Handle() {
|
handle(args.env, args.self, new Handle() {
|
||||||
@Override public void onFulfil(Object val) {
|
@Override public void onFulfil(Object val) {
|
||||||
try { res.fulfill(args.ctx, onFulfill.call(args.ctx, null, val)); }
|
try { res.fulfill(args.env, onFulfill.call(args.env, null, val)); }
|
||||||
catch (EngineException e) { res.reject(args.ctx, e); }
|
catch (EngineException e) { res.reject(args.env, e); }
|
||||||
}
|
}
|
||||||
@Override public void onReject(EngineException err) {
|
@Override public void onReject(EngineException err) {
|
||||||
try { res.fulfill(args.ctx, onReject.call(args.ctx, null, err.value)); }
|
try { res.fulfill(args.env, onReject.call(args.env, null, err.value)); }
|
||||||
catch (EngineException e) { res.reject(args.ctx, e); }
|
catch (EngineException e) { res.reject(args.env, e); }
|
||||||
}
|
}
|
||||||
}.defer(args.ctx));
|
}.defer(args.env));
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
@Expose
|
@Expose
|
||||||
public static Object __catch(Arguments args) {
|
public static Object __catch(Arguments args) {
|
||||||
return __then(new Arguments(args.ctx, args.self, null, args.get(0)));
|
return __then(new Arguments(args.env, args.self, null, args.get(0)));
|
||||||
}
|
}
|
||||||
@Expose
|
@Expose
|
||||||
public static Object __finally(Arguments args) {
|
public static Object __finally(Arguments args) {
|
||||||
@ -357,22 +356,22 @@ public class PromiseLib {
|
|||||||
|
|
||||||
var res = new PromiseLib();
|
var res = new PromiseLib();
|
||||||
|
|
||||||
handle(args.ctx, args.self, new Handle() {
|
handle(args.env, args.self, new Handle() {
|
||||||
@Override public void onFulfil(Object val) {
|
@Override public void onFulfil(Object val) {
|
||||||
try {
|
try {
|
||||||
func.call(args.ctx);
|
func.call(args.env);
|
||||||
res.fulfill(args.ctx, val);
|
res.fulfill(args.env, val);
|
||||||
}
|
}
|
||||||
catch (EngineException e) { res.reject(args.ctx, e); }
|
catch (EngineException e) { res.reject(args.env, e); }
|
||||||
}
|
}
|
||||||
@Override public void onReject(EngineException err) {
|
@Override public void onReject(EngineException err) {
|
||||||
try {
|
try {
|
||||||
func.call(args.ctx);
|
func.call(args.env);
|
||||||
res.reject(args.ctx, err);
|
res.reject(args.env, err);
|
||||||
}
|
}
|
||||||
catch (EngineException e) { res.reject(args.ctx, e); }
|
catch (EngineException e) { res.reject(args.env, e); }
|
||||||
}
|
}
|
||||||
}.defer(args.ctx));
|
}.defer(args.env));
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
@ -384,19 +383,19 @@ public class PromiseLib {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
func.call(
|
func.call(
|
||||||
args.ctx, null,
|
args.env, null,
|
||||||
new NativeFunction(null, _args -> {
|
new NativeFunction(null, _args -> {
|
||||||
res.fulfill(_args.ctx, _args.get(0));
|
res.fulfill(_args.env, _args.get(0));
|
||||||
return null;
|
return null;
|
||||||
}),
|
}),
|
||||||
new NativeFunction(null, _args -> {
|
new NativeFunction(null, _args -> {
|
||||||
res.reject(_args.ctx, new EngineException(_args.get(0)).setExtensions(_args.ctx));
|
res.reject(_args.env, new EngineException(_args.get(0)).setEnvironment(_args.env));
|
||||||
return null;
|
return null;
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
catch (EngineException e) {
|
catch (EngineException e) {
|
||||||
res.reject(args.ctx, e);
|
res.reject(args.env, e);
|
||||||
}
|
}
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
|
@ -4,7 +4,7 @@ import java.util.ArrayList;
|
|||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
import me.topchetoeu.jscript.runtime.Context;
|
import me.topchetoeu.jscript.runtime.environment.Environment;
|
||||||
import me.topchetoeu.jscript.runtime.values.ArrayValue;
|
import me.topchetoeu.jscript.runtime.values.ArrayValue;
|
||||||
import me.topchetoeu.jscript.runtime.values.FunctionValue;
|
import me.topchetoeu.jscript.runtime.values.FunctionValue;
|
||||||
import me.topchetoeu.jscript.runtime.values.NativeWrapper;
|
import me.topchetoeu.jscript.runtime.values.NativeWrapper;
|
||||||
@ -119,7 +119,7 @@ public class RegExpLib {
|
|||||||
var res = new ArrayValue();
|
var res = new ArrayValue();
|
||||||
Object val;
|
Object val;
|
||||||
while ((val = this.__exec(args)) != Values.NULL) {
|
while ((val = this.__exec(args)) != Values.NULL) {
|
||||||
res.set(args.ctx, res.size(), Values.getMember(args.ctx, val, 0));
|
res.set(args.env, res.size(), Values.getMember(args.env, val, 0));
|
||||||
}
|
}
|
||||||
lastI = 0;
|
lastI = 0;
|
||||||
return res;
|
return res;
|
||||||
@ -134,7 +134,7 @@ public class RegExpLib {
|
|||||||
@Expose("@@Symbol.matchAll") public Object __matchAll(Arguments args) {
|
@Expose("@@Symbol.matchAll") public Object __matchAll(Arguments args) {
|
||||||
var pattern = this.toGlobal();
|
var pattern = this.toGlobal();
|
||||||
|
|
||||||
return Values.toJSIterator(args.ctx, new Iterator<Object>() {
|
return Values.toJSIterator(args.env, new Iterator<Object>() {
|
||||||
private Object val = null;
|
private Object val = null;
|
||||||
private boolean updated = false;
|
private boolean updated = false;
|
||||||
|
|
||||||
@ -167,7 +167,7 @@ public class RegExpLib {
|
|||||||
while ((match = pattern.__exec(args)) != 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(args.ctx, Values.getMember(args.ctx, match, "index"));
|
int index = (int)Values.toNumber(args.env, Values.getMember(args.env, match, "index"));
|
||||||
var matchVal = (String)arrMatch.get(0);
|
var matchVal = (String)arrMatch.get(0);
|
||||||
|
|
||||||
if (index >= target.length()) break;
|
if (index >= target.length()) break;
|
||||||
@ -184,18 +184,18 @@ public class RegExpLib {
|
|||||||
|
|
||||||
if (sensible) {
|
if (sensible) {
|
||||||
if (hasLimit && 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(args.ctx, res.size(), added.get(i));
|
else for (var i = 0; i < added.size(); i++) res.set(args.env, res.size(), added.get(i));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
for (var i = 0; i < added.size(); i++) {
|
for (var i = 0; i < added.size(); i++) {
|
||||||
if (hasLimit && res.size() >= lim) return res;
|
if (hasLimit && res.size() >= lim) return res;
|
||||||
else res.set(args.ctx, res.size(), added.get(i));
|
else res.set(args.env, res.size(), added.get(i));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
lastEnd = pattern.lastI;
|
lastEnd = pattern.lastI;
|
||||||
}
|
}
|
||||||
if (lastEnd < target.length()) {
|
if (lastEnd < target.length()) {
|
||||||
res.set(args.ctx, res.size(), target.substring(lastEnd));
|
res.set(args.env, res.size(), target.substring(lastEnd));
|
||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
@ -209,7 +209,7 @@ public class RegExpLib {
|
|||||||
var res = new StringBuilder();
|
var res = new StringBuilder();
|
||||||
|
|
||||||
while ((match = pattern.__exec(args)) != Values.NULL) {
|
while ((match = pattern.__exec(args)) != Values.NULL) {
|
||||||
var indices = (ArrayValue)((ArrayValue)Values.getMember(args.ctx, match, "indices")).get(0);
|
var indices = (ArrayValue)((ArrayValue)Values.getMember(args.env, 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();
|
||||||
@ -222,10 +222,10 @@ public class RegExpLib {
|
|||||||
arrMatch.copyTo(callArgs, 1, 1, arrMatch.size() - 1);
|
arrMatch.copyTo(callArgs, 1, 1, arrMatch.size() - 1);
|
||||||
callArgs[callArgs.length - 2] = start;
|
callArgs[callArgs.length - 2] = start;
|
||||||
callArgs[callArgs.length - 1] = target;
|
callArgs[callArgs.length - 1] = target;
|
||||||
res.append(Values.toString(args.ctx, ((FunctionValue)replacement).call(args.ctx, null, callArgs)));
|
res.append(Values.toString(args.env, ((FunctionValue)replacement).call(args.env, null, callArgs)));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
res.append(Values.toString(args.ctx, replacement));
|
res.append(Values.toString(args.env, replacement));
|
||||||
}
|
}
|
||||||
lastEnd = end;
|
lastEnd = end;
|
||||||
if (!pattern.global) break;
|
if (!pattern.global) break;
|
||||||
@ -313,26 +313,26 @@ public class RegExpLib {
|
|||||||
|
|
||||||
@ExposeConstructor
|
@ExposeConstructor
|
||||||
public static RegExpLib __constructor(Arguments args) {
|
public static RegExpLib __constructor(Arguments args) {
|
||||||
return new RegExpLib(cleanupPattern(args.ctx, args.get(0)), cleanupFlags(args.ctx, args.get(1)));
|
return new RegExpLib(cleanupPattern(args.env, args.get(0)), cleanupFlags(args.env, args.get(1)));
|
||||||
}
|
}
|
||||||
@Expose(target = ExposeTarget.STATIC)
|
@Expose(target = ExposeTarget.STATIC)
|
||||||
public static RegExpLib __escape(Arguments args) {
|
public static RegExpLib __escape(Arguments args) {
|
||||||
return escape(Values.toString(args.ctx, args.get(0)), cleanupFlags(args.ctx, args.get(1)));
|
return escape(Values.toString(args.env, args.get(0)), cleanupFlags(args.env, args.get(1)));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String cleanupPattern(Context ctx, Object val) {
|
private static String cleanupPattern(Environment env, Object val) {
|
||||||
if (val == null) return "(?:)";
|
if (val == null) return "(?:)";
|
||||||
if (val instanceof RegExpLib) return ((RegExpLib)val).source;
|
if (val instanceof RegExpLib) return ((RegExpLib)val).source;
|
||||||
if (val instanceof NativeWrapper && ((NativeWrapper)val).wrapped instanceof RegExpLib) {
|
if (val instanceof NativeWrapper && ((NativeWrapper)val).wrapped instanceof RegExpLib) {
|
||||||
return ((RegExpLib)((NativeWrapper)val).wrapped).source;
|
return ((RegExpLib)((NativeWrapper)val).wrapped).source;
|
||||||
}
|
}
|
||||||
var res = Values.toString(ctx, val);
|
var res = Values.toString(env, val);
|
||||||
if (res.equals("")) return "(?:)";
|
if (res.equals("")) return "(?:)";
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
private static String cleanupFlags(Context ctx, Object val) {
|
private static String cleanupFlags(Environment env, Object val) {
|
||||||
if (val == null) return "";
|
if (val == null) return "";
|
||||||
return Values.toString(ctx, val);
|
return Values.toString(env, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean checkEscaped(String s, int pos) {
|
private static boolean checkEscaped(String s, int pos) {
|
||||||
|
@ -4,7 +4,7 @@ import java.util.ArrayList;
|
|||||||
import java.util.LinkedHashSet;
|
import java.util.LinkedHashSet;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import me.topchetoeu.jscript.runtime.Context;
|
import me.topchetoeu.jscript.runtime.environment.Environment;
|
||||||
import me.topchetoeu.jscript.runtime.values.ArrayValue;
|
import me.topchetoeu.jscript.runtime.values.ArrayValue;
|
||||||
import me.topchetoeu.jscript.runtime.values.ObjectValue;
|
import me.topchetoeu.jscript.runtime.values.ObjectValue;
|
||||||
import me.topchetoeu.jscript.runtime.values.Values;
|
import me.topchetoeu.jscript.runtime.values.Values;
|
||||||
@ -24,13 +24,13 @@ public class SetLib {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Expose public ObjectValue __entries(Arguments args) {
|
@Expose public ObjectValue __entries(Arguments args) {
|
||||||
return Values.toJSIterator(args.ctx, set.stream().map(v -> new ArrayValue(args.ctx, v, v)).collect(Collectors.toList()));
|
return Values.toJSIterator(args.env, set.stream().map(v -> new ArrayValue(args.env, v, v)).collect(Collectors.toList()));
|
||||||
}
|
}
|
||||||
@Expose public ObjectValue __keys(Arguments args) {
|
@Expose public ObjectValue __keys(Arguments args) {
|
||||||
return Values.toJSIterator(args.ctx, set);
|
return Values.toJSIterator(args.env, set);
|
||||||
}
|
}
|
||||||
@Expose public ObjectValue __values(Arguments args) {
|
@Expose public ObjectValue __values(Arguments args) {
|
||||||
return Values.toJSIterator(args.ctx, set);
|
return Values.toJSIterator(args.env, set);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Expose public Object __add(Arguments args) {
|
@Expose public Object __add(Arguments args) {
|
||||||
@ -55,15 +55,15 @@ public class SetLib {
|
|||||||
@Expose public void __forEach(Arguments args) {
|
@Expose public void __forEach(Arguments args) {
|
||||||
var keys = new ArrayList<>(set);
|
var keys = new ArrayList<>(set);
|
||||||
|
|
||||||
for (var el : keys) Values.call(args.ctx, args.get(0), args.get(1), el, el, args.self);
|
for (var el : keys) Values.call(args.env, args.get(0), args.get(1), el, el, args.self);
|
||||||
}
|
}
|
||||||
|
|
||||||
public SetLib(Context ctx, Object iterable) {
|
public SetLib(Environment env, Object iterable) {
|
||||||
for (var el : Values.fromJSIterator(ctx, iterable)) set.add(el);
|
for (var el : Values.fromJSIterator(env, iterable)) set.add(el);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ExposeConstructor
|
@ExposeConstructor
|
||||||
public static SetLib __constructor(Arguments args) {
|
public static SetLib __constructor(Arguments args) {
|
||||||
return new SetLib(args.ctx, args.get(0));
|
return new SetLib(args.env, args.get(0));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@ package me.topchetoeu.jscript.lib;
|
|||||||
|
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
import me.topchetoeu.jscript.runtime.Environment;
|
import me.topchetoeu.jscript.runtime.environment.Environment;
|
||||||
import me.topchetoeu.jscript.runtime.exceptions.EngineException;
|
import me.topchetoeu.jscript.runtime.exceptions.EngineException;
|
||||||
import me.topchetoeu.jscript.runtime.values.ArrayValue;
|
import me.topchetoeu.jscript.runtime.values.ArrayValue;
|
||||||
import me.topchetoeu.jscript.runtime.values.FunctionValue;
|
import me.topchetoeu.jscript.runtime.values.FunctionValue;
|
||||||
@ -101,23 +101,23 @@ public class StringLib {
|
|||||||
var val = passThis(args, "indexOf");
|
var val = passThis(args, "indexOf");
|
||||||
var term = args.get(0);
|
var term = args.get(0);
|
||||||
var start = args.getInt(1);
|
var start = args.getInt(1);
|
||||||
var search = Values.getMember(args.ctx, term, Symbol.get("Symbol.search"));
|
var search = Values.getMember(args.env, term, Symbol.get("Symbol.search"));
|
||||||
|
|
||||||
if (search instanceof FunctionValue) {
|
if (search instanceof FunctionValue) {
|
||||||
return (int)Values.toNumber(args.ctx, Values.call(args.ctx, search, term, val, false, start));
|
return (int)Values.toNumber(args.env, Values.call(args.env, search, term, val, false, start));
|
||||||
}
|
}
|
||||||
else return val.indexOf(Values.toString(args.ctx, term), start);
|
else return val.indexOf(Values.toString(args.env, term), start);
|
||||||
}
|
}
|
||||||
@Expose public static int __lastIndexOf(Arguments args) {
|
@Expose public static int __lastIndexOf(Arguments args) {
|
||||||
var val = passThis(args, "lastIndexOf");
|
var val = passThis(args, "lastIndexOf");
|
||||||
var term = args.get(0);
|
var term = args.get(0);
|
||||||
var start = args.getInt(1);
|
var start = args.getInt(1);
|
||||||
var search = Values.getMember(args.ctx, term, Symbol.get("Symbol.search"));
|
var search = Values.getMember(args.env, term, Symbol.get("Symbol.search"));
|
||||||
|
|
||||||
if (search instanceof FunctionValue) {
|
if (search instanceof FunctionValue) {
|
||||||
return (int)Values.toNumber(args.ctx, Values.call(args.ctx, search, term, val, true, start));
|
return (int)Values.toNumber(args.env, Values.call(args.env, search, term, val, true, start));
|
||||||
}
|
}
|
||||||
else return val.lastIndexOf(Values.toString(args.ctx, term), start);
|
else return val.lastIndexOf(Values.toString(args.env, term), start);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Expose public static boolean __includes(Arguments args) {
|
@Expose public static boolean __includes(Arguments args) {
|
||||||
@ -128,23 +128,23 @@ public class StringLib {
|
|||||||
var val = passThis(args, "replace");
|
var val = passThis(args, "replace");
|
||||||
var term = args.get(0);
|
var term = args.get(0);
|
||||||
var replacement = args.get(1);
|
var replacement = args.get(1);
|
||||||
var replace = Values.getMember(args.ctx, term, Symbol.get("Symbol.replace"));
|
var replace = Values.getMember(args.env, term, Symbol.get("Symbol.replace"));
|
||||||
|
|
||||||
if (replace instanceof FunctionValue) {
|
if (replace instanceof FunctionValue) {
|
||||||
return Values.toString(args.ctx, Values.call(args.ctx, replace, term, val, replacement));
|
return Values.toString(args.env, Values.call(args.env, replace, term, val, replacement));
|
||||||
}
|
}
|
||||||
else return val.replaceFirst(Pattern.quote(Values.toString(args.ctx, term)), Values.toString(args.ctx, replacement));
|
else return val.replaceFirst(Pattern.quote(Values.toString(args.env, term)), Values.toString(args.env, replacement));
|
||||||
}
|
}
|
||||||
@Expose public static String __replaceAll(Arguments args) {
|
@Expose public static String __replaceAll(Arguments args) {
|
||||||
var val = passThis(args, "replaceAll");
|
var val = passThis(args, "replaceAll");
|
||||||
var term = args.get(0);
|
var term = args.get(0);
|
||||||
var replacement = args.get(1);
|
var replacement = args.get(1);
|
||||||
var replace = Values.getMember(args.ctx, term, Symbol.get("Symbol.replace"));
|
var replace = Values.getMember(args.env, term, Symbol.get("Symbol.replace"));
|
||||||
|
|
||||||
if (replace instanceof FunctionValue) {
|
if (replace instanceof FunctionValue) {
|
||||||
return Values.toString(args.ctx, Values.call(args.ctx, replace, term, val, replacement));
|
return Values.toString(args.env, Values.call(args.env, replace, term, val, replacement));
|
||||||
}
|
}
|
||||||
else return val.replace(Values.toString(args.ctx, term), Values.toString(args.ctx, replacement));
|
else return val.replace(Values.toString(args.env, term), Values.toString(args.env, replacement));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Expose public static ArrayValue __match(Arguments args) {
|
@Expose public static ArrayValue __match(Arguments args) {
|
||||||
@ -154,21 +154,21 @@ public class StringLib {
|
|||||||
FunctionValue match;
|
FunctionValue match;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
var _match = Values.getMember(args.ctx, term, Symbol.get("Symbol.match"));
|
var _match = Values.getMember(args.env, term, Symbol.get("Symbol.match"));
|
||||||
if (_match instanceof FunctionValue) match = (FunctionValue)_match;
|
if (_match instanceof FunctionValue) match = (FunctionValue)_match;
|
||||||
else if (args.ctx.hasNotNull(Environment.REGEX_CONSTR)) {
|
else if (args.env.hasNotNull(Environment.REGEX_CONSTR)) {
|
||||||
var regex = Values.callNew(args.ctx, args.ctx.get(Environment.REGEX_CONSTR), Values.toString(args.ctx, term), "");
|
var regex = Values.callNew(args.env, args.env.get(Environment.REGEX_CONSTR), Values.toString(args.env, term), "");
|
||||||
_match = Values.getMember(args.ctx, regex, Symbol.get("Symbol.match"));
|
_match = Values.getMember(args.env, 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(args.ctx, ""); }
|
catch (IllegalArgumentException e) { return new ArrayValue(args.env, ""); }
|
||||||
|
|
||||||
var res = match.call(args.ctx, term, val);
|
var res = match.call(args.env, term, val);
|
||||||
if (res instanceof ArrayValue) return (ArrayValue)res;
|
if (res instanceof ArrayValue) return (ArrayValue)res;
|
||||||
else return new ArrayValue(args.ctx, "");
|
else return new ArrayValue(args.env, "");
|
||||||
}
|
}
|
||||||
@Expose public static Object __matchAll(Arguments args) {
|
@Expose public static Object __matchAll(Arguments args) {
|
||||||
var val = passThis(args, "matchAll");
|
var val = passThis(args, "matchAll");
|
||||||
@ -177,20 +177,20 @@ public class StringLib {
|
|||||||
FunctionValue match = null;
|
FunctionValue match = null;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
var _match = Values.getMember(args.ctx, term, Symbol.get("Symbol.matchAll"));
|
var _match = Values.getMember(args.env, 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 && args.ctx.hasNotNull(Environment.REGEX_CONSTR)) {
|
if (match == null && args.env.hasNotNull(Environment.REGEX_CONSTR)) {
|
||||||
var regex = Values.callNew(args.ctx, args.ctx.get(Environment.REGEX_CONSTR), Values.toString(args.ctx, term), "g");
|
var regex = Values.callNew(args.env, args.env.get(Environment.REGEX_CONSTR), Values.toString(args.env, term), "g");
|
||||||
var _match = Values.getMember(args.ctx, regex, Symbol.get("Symbol.matchAll"));
|
var _match = Values.getMember(args.env, 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(args.ctx, term, val);
|
return match.call(args.env, term, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Expose public static ArrayValue __split(Arguments args) {
|
@Expose public static ArrayValue __split(Arguments args) {
|
||||||
@ -199,23 +199,23 @@ public class StringLib {
|
|||||||
var lim = args.get(1);
|
var lim = args.get(1);
|
||||||
var sensible = args.getBoolean(2);
|
var sensible = args.getBoolean(2);
|
||||||
|
|
||||||
if (lim != null) lim = Values.toNumber(args.ctx, lim);
|
if (lim != null) lim = Values.toNumber(args.env, lim);
|
||||||
|
|
||||||
if (term != null && term != Values.NULL && !(term instanceof String)) {
|
if (term != null && term != Values.NULL && !(term instanceof String)) {
|
||||||
var replace = Values.getMember(args.ctx, term, Symbol.get("Symbol.replace"));
|
var replace = Values.getMember(args.env, term, Symbol.get("Symbol.replace"));
|
||||||
if (replace instanceof FunctionValue) {
|
if (replace instanceof FunctionValue) {
|
||||||
var tmp = ((FunctionValue)replace).call(args.ctx, term, val, lim, sensible);
|
var tmp = ((FunctionValue)replace).call(args.env, 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(args.ctx, i, Values.toString(args.ctx, ((ArrayValue)tmp).get(i)));
|
for (int i = 0; i < parts.size(); i++) parts.set(args.env, i, Values.toString(args.env, ((ArrayValue)tmp).get(i)));
|
||||||
return parts;
|
return parts;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
String[] parts;
|
String[] parts;
|
||||||
var pattern = Pattern.quote(Values.toString(args.ctx, term));
|
var pattern = Pattern.quote(Values.toString(args.env, term));
|
||||||
|
|
||||||
if (lim == null) parts = val.split(pattern);
|
if (lim == null) parts = val.split(pattern);
|
||||||
else if ((double)lim < 1) return new ArrayValue();
|
else if ((double)lim < 1) return new ArrayValue();
|
||||||
@ -228,7 +228,7 @@ public class StringLib {
|
|||||||
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(args.ctx, i, parts[i]);
|
for (var i = 0; i < parts.length && i < limit; i++) res.set(args.env, i, parts[i]);
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
@ -238,7 +238,7 @@ public class StringLib {
|
|||||||
|
|
||||||
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(args.ctx, i, parts[i]);
|
res.set(args.env, i, parts[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
@ -249,7 +249,7 @@ public class StringLib {
|
|||||||
var start = normalizeI(args.getInt(0), self.length(), false);
|
var start = normalizeI(args.getInt(0), self.length(), false);
|
||||||
var end = normalizeI(args.getInt(1, self.length()), self.length(), false);
|
var end = normalizeI(args.getInt(1, self.length()), self.length(), false);
|
||||||
|
|
||||||
return __substring(new Arguments(args.ctx, self, start, end));
|
return __substring(new Arguments(args.env, self, start, end));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Expose public static String __concat(Arguments args) {
|
@Expose public static String __concat(Arguments args) {
|
||||||
|
@ -76,6 +76,6 @@ public class SymbolLib {
|
|||||||
}
|
}
|
||||||
@Expose(target = ExposeTarget.STATIC)
|
@Expose(target = ExposeTarget.STATIC)
|
||||||
public static String __keyFor(Arguments args) {
|
public static String __keyFor(Arguments args) {
|
||||||
return passThis(new Arguments(args.ctx, args.get(0)), "keyFor").value;
|
return passThis(new Arguments(args.env, args.get(0)), "keyFor").value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +0,0 @@
|
|||||||
package me.topchetoeu.jscript.runtime;
|
|
||||||
|
|
||||||
public interface Childable {
|
|
||||||
Object child();
|
|
||||||
}
|
|
@ -2,6 +2,9 @@ package me.topchetoeu.jscript.runtime;
|
|||||||
|
|
||||||
import me.topchetoeu.jscript.common.Filename;
|
import me.topchetoeu.jscript.common.Filename;
|
||||||
import me.topchetoeu.jscript.common.FunctionBody;
|
import me.topchetoeu.jscript.common.FunctionBody;
|
||||||
|
import me.topchetoeu.jscript.runtime.debug.DebugContext;
|
||||||
|
import me.topchetoeu.jscript.runtime.environment.Environment;
|
||||||
|
import me.topchetoeu.jscript.runtime.environment.Key;
|
||||||
import me.topchetoeu.jscript.runtime.exceptions.EngineException;
|
import me.topchetoeu.jscript.runtime.exceptions.EngineException;
|
||||||
import me.topchetoeu.jscript.runtime.scope.ValueVariable;
|
import me.topchetoeu.jscript.runtime.scope.ValueVariable;
|
||||||
import me.topchetoeu.jscript.runtime.values.CodeFunction;
|
import me.topchetoeu.jscript.runtime.values.CodeFunction;
|
||||||
@ -11,13 +14,14 @@ public interface Compiler {
|
|||||||
|
|
||||||
public FunctionBody compile(Filename filename, String source);
|
public FunctionBody compile(Filename filename, String source);
|
||||||
|
|
||||||
public static Compiler get(Extensions ext) {
|
public static Compiler get(Environment ext) {
|
||||||
return ext.get(KEY, (filename, src) -> {
|
return ext.get(KEY, (filename, src) -> {
|
||||||
throw EngineException.ofError("No compiler attached to engine.");
|
throw EngineException.ofError("No compiler attached to engine.");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public static CodeFunction compile(Environment env, Filename filename, String raw) {
|
public static CodeFunction compile(Environment env, Filename filename, String raw) {
|
||||||
|
DebugContext.get(env).onSource(filename, raw);
|
||||||
return new CodeFunction(env, filename.toString(), Compiler.get(env).compile(filename, raw), new ValueVariable[0]);
|
return new CodeFunction(env, filename.toString(), Compiler.get(env).compile(filename, raw), new ValueVariable[0]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,98 +0,0 @@
|
|||||||
package me.topchetoeu.jscript.runtime;
|
|
||||||
|
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import me.topchetoeu.jscript.common.Filename;
|
|
||||||
import me.topchetoeu.jscript.runtime.debug.DebugContext;
|
|
||||||
import me.topchetoeu.jscript.runtime.exceptions.EngineException;
|
|
||||||
import me.topchetoeu.jscript.runtime.scope.ValueVariable;
|
|
||||||
import me.topchetoeu.jscript.runtime.values.CodeFunction;
|
|
||||||
import me.topchetoeu.jscript.runtime.values.FunctionValue;
|
|
||||||
|
|
||||||
public class Context implements Extensions {
|
|
||||||
public final Context parent;
|
|
||||||
public final Extensions extensions;
|
|
||||||
public final Frame frame;
|
|
||||||
public final int stackSize;
|
|
||||||
|
|
||||||
@Override public <T> void add(Key<T> key, T obj) {
|
|
||||||
if (extensions != null) extensions.add(key, obj);
|
|
||||||
}
|
|
||||||
@Override public <T> T get(Key<T> key) {
|
|
||||||
if (extensions != null && extensions.has(key)) return extensions.get(key);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
@Override public boolean has(Key<?> key) {
|
|
||||||
return extensions != null && extensions.has(key);
|
|
||||||
}
|
|
||||||
@Override public boolean remove(Key<?> key) {
|
|
||||||
var res = false;
|
|
||||||
if (extensions != null) res |= extensions.remove(key);
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
@Override public Iterable<Key<?>> keys() {
|
|
||||||
if (extensions == null) return List.of();
|
|
||||||
else return extensions.keys();
|
|
||||||
}
|
|
||||||
|
|
||||||
public FunctionValue compile(Filename filename, String raw) {
|
|
||||||
DebugContext.get(this).onSource(filename, raw);
|
|
||||||
var result = new CodeFunction(extensions, filename.toString(), Compiler.get(this).compile(filename, raw), new ValueVariable[0]);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Context pushFrame(Frame frame) {
|
|
||||||
var res = new Context(this, frame.function.extensions, frame, stackSize + 1);
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Iterable<Frame> frames() {
|
|
||||||
var self = this;
|
|
||||||
return () -> new Iterator<Frame>() {
|
|
||||||
private Context curr = self;
|
|
||||||
|
|
||||||
private void update() {
|
|
||||||
while (curr != null && curr.frame == null) curr = curr.parent;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public boolean hasNext() {
|
|
||||||
update();
|
|
||||||
return curr != null;
|
|
||||||
}
|
|
||||||
@Override public Frame next() {
|
|
||||||
update();
|
|
||||||
var res = curr.frame;
|
|
||||||
curr = curr.parent;
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
private Context(Context parent, Extensions ext, Frame frame, int stackSize) {
|
|
||||||
this.parent = parent;
|
|
||||||
this.extensions = ext;
|
|
||||||
this.frame = frame;
|
|
||||||
this.stackSize = stackSize;
|
|
||||||
|
|
||||||
if (hasNotNull(Environment.MAX_STACK_COUNT) && stackSize > (int)get(Environment.MAX_STACK_COUNT)) {
|
|
||||||
throw EngineException.ofRange("Stack overflow!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public Context() {
|
|
||||||
this(null, null, null, 0);
|
|
||||||
}
|
|
||||||
public Context(Extensions ext) {
|
|
||||||
this(null, clean(ext), null, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Context of(Extensions ext) {
|
|
||||||
if (ext instanceof Context) return (Context)ext;
|
|
||||||
return new Context(ext);
|
|
||||||
}
|
|
||||||
public static Extensions clean(Extensions ext) {
|
|
||||||
if (ext instanceof Context) return clean(((Context)ext).extensions);
|
|
||||||
else return ext;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,5 +0,0 @@
|
|||||||
package me.topchetoeu.jscript.runtime;
|
|
||||||
|
|
||||||
public interface Copyable {
|
|
||||||
Object copy();
|
|
||||||
}
|
|
@ -1,61 +0,0 @@
|
|||||||
package me.topchetoeu.jscript.runtime;
|
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
|
|
||||||
import me.topchetoeu.jscript.runtime.exceptions.EngineException;
|
|
||||||
import me.topchetoeu.jscript.runtime.values.FunctionValue;
|
|
||||||
import me.topchetoeu.jscript.runtime.values.NativeFunction;
|
|
||||||
import me.topchetoeu.jscript.runtime.values.ObjectValue;
|
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public class Environment implements Extensions {
|
|
||||||
public static final Key<Compiler> COMPILE_FUNC = new Key<>();
|
|
||||||
|
|
||||||
public static final Key<FunctionValue> REGEX_CONSTR = new Key<>();
|
|
||||||
public static final Key<Integer> MAX_STACK_COUNT = new Key<>();
|
|
||||||
public static final Key<Boolean> HIDE_STACK = new Key<>();
|
|
||||||
|
|
||||||
public static final Key<ObjectValue> OBJECT_PROTO = new Key<>();
|
|
||||||
public static final Key<ObjectValue> FUNCTION_PROTO = new Key<>();
|
|
||||||
public static final Key<ObjectValue> ARRAY_PROTO = new Key<>();
|
|
||||||
public static final Key<ObjectValue> BOOL_PROTO = new Key<>();
|
|
||||||
public static final Key<ObjectValue> NUMBER_PROTO = new Key<>();
|
|
||||||
public static final Key<ObjectValue> STRING_PROTO = new Key<>();
|
|
||||||
public static final Key<ObjectValue> SYMBOL_PROTO = new Key<>();
|
|
||||||
public static final Key<ObjectValue> ERROR_PROTO = new Key<>();
|
|
||||||
public static final Key<ObjectValue> SYNTAX_ERR_PROTO = new Key<>();
|
|
||||||
public static final Key<ObjectValue> TYPE_ERR_PROTO = new Key<>();
|
|
||||||
public static final Key<ObjectValue> RANGE_ERR_PROTO = new Key<>();
|
|
||||||
|
|
||||||
private HashMap<Key<?>, Object> data = new HashMap<>();
|
|
||||||
|
|
||||||
@Override public <T> void add(Key<T> key, T obj) {
|
|
||||||
data.put(key, obj);
|
|
||||||
}
|
|
||||||
@Override public <T> T get(Key<T> key) {
|
|
||||||
return (T)data.get(key);
|
|
||||||
}
|
|
||||||
@Override public boolean remove(Key<?> key) {
|
|
||||||
if (data.containsKey(key)) {
|
|
||||||
data.remove(key);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
@Override public boolean has(Key<?> key) {
|
|
||||||
return data.containsKey(key);
|
|
||||||
}
|
|
||||||
@Override public Iterable<Key<?>> keys() {
|
|
||||||
return data.keySet();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static FunctionValue regexConstructor(Extensions ext) {
|
|
||||||
return ext.init(REGEX_CONSTR, new NativeFunction("RegExp", args -> {
|
|
||||||
throw EngineException.ofError("Regular expressions not supported.").setExtensions(args.ctx);
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
public Context context() {
|
|
||||||
return new Context(this);
|
|
||||||
}
|
|
||||||
}
|
|
@ -3,13 +3,15 @@ package me.topchetoeu.jscript.runtime;
|
|||||||
import me.topchetoeu.jscript.common.Filename;
|
import me.topchetoeu.jscript.common.Filename;
|
||||||
import me.topchetoeu.jscript.common.ResultRunnable;
|
import me.topchetoeu.jscript.common.ResultRunnable;
|
||||||
import me.topchetoeu.jscript.common.events.DataNotifier;
|
import me.topchetoeu.jscript.common.events.DataNotifier;
|
||||||
|
import me.topchetoeu.jscript.runtime.environment.Environment;
|
||||||
|
import me.topchetoeu.jscript.runtime.environment.Key;
|
||||||
import me.topchetoeu.jscript.runtime.exceptions.EngineException;
|
import me.topchetoeu.jscript.runtime.exceptions.EngineException;
|
||||||
import me.topchetoeu.jscript.runtime.values.FunctionValue;
|
import me.topchetoeu.jscript.runtime.values.FunctionValue;
|
||||||
|
|
||||||
public interface EventLoop {
|
public interface EventLoop {
|
||||||
public static final Key<EventLoop> KEY = new Key<>();
|
public static final Key<EventLoop> KEY = new Key<>();
|
||||||
|
|
||||||
public static EventLoop get(Extensions ext) {
|
public static EventLoop get(Environment ext) {
|
||||||
if (ext.hasNotNull(KEY)) return ext.get(KEY);
|
if (ext.hasNotNull(KEY)) return ext.get(KEY);
|
||||||
else return new EventLoop() {
|
else return new EventLoop() {
|
||||||
@Override public <T> DataNotifier<T> pushMsg(ResultRunnable<T> runnable, boolean micro) {
|
@Override public <T> DataNotifier<T> pushMsg(ResultRunnable<T> runnable, boolean micro) {
|
||||||
@ -23,15 +25,10 @@ public interface EventLoop {
|
|||||||
return pushMsg(() -> { runnable.run(); return null; }, micro);
|
return pushMsg(() -> { runnable.run(); return null; }, micro);
|
||||||
}
|
}
|
||||||
|
|
||||||
public default DataNotifier<Object> pushMsg(boolean micro, Extensions ext, FunctionValue func, Object thisArg, Object ...args) {
|
public default DataNotifier<Object> pushMsg(boolean micro, Environment env, FunctionValue func, Object thisArg, Object ...args) {
|
||||||
return pushMsg(() -> {
|
return pushMsg(() -> func.call(env, thisArg, args), micro);
|
||||||
return func.call(Context.of(ext), thisArg, args);
|
|
||||||
}, micro);
|
|
||||||
}
|
}
|
||||||
public default DataNotifier<Object> pushMsg(boolean micro, Extensions ext, Filename filename, String raw, Object thisArg, Object ...args) {
|
public default DataNotifier<Object> pushMsg(boolean micro, Environment env, Filename filename, String raw, Object thisArg, Object ...args) {
|
||||||
return pushMsg(() -> {
|
return pushMsg(() -> Compiler.compile(env, filename, raw).call(env, thisArg, args), micro);
|
||||||
var ctx = Context.of(ext);
|
|
||||||
return ctx.compile(filename, raw).call(Context.of(ext), thisArg, args);
|
|
||||||
}, micro);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,77 +0,0 @@
|
|||||||
package me.topchetoeu.jscript.runtime;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public interface Extensions extends Childable, Copyable {
|
|
||||||
public static Extensions EMPTY = new Extensions() {
|
|
||||||
@Override public <T> void add(Key<T> key, T obj) { }
|
|
||||||
@Override public boolean remove(Key<?> key) { return false; }
|
|
||||||
|
|
||||||
@Override public <T> T get(Key<T> key) { return null; }
|
|
||||||
@Override public boolean has(Key<?> key) { return false; }
|
|
||||||
@Override public Iterable<Key<?>> keys() { return List.of(); }
|
|
||||||
};
|
|
||||||
|
|
||||||
<T> T get(Key<T> key);
|
|
||||||
<T> void add(Key<T> key, T obj);
|
|
||||||
Iterable<Key<?>> keys();
|
|
||||||
|
|
||||||
boolean has(Key<?> key);
|
|
||||||
boolean remove(Key<?> key);
|
|
||||||
|
|
||||||
default void add(Key<Void> key) {
|
|
||||||
add(key, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
default boolean hasNotNull(Key<?> key) {
|
|
||||||
return has(key) && get(key) != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
default <T> T get(Key<T> key, T defaultVal) {
|
|
||||||
if (has(key)) return get(key);
|
|
||||||
else return defaultVal;
|
|
||||||
}
|
|
||||||
|
|
||||||
default <T> T init(Key<T> key, T val) {
|
|
||||||
if (has(key)) return get(key);
|
|
||||||
else {
|
|
||||||
add(key, val);
|
|
||||||
return val;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
default void addAll(Extensions source) {
|
|
||||||
if (source == null) return;
|
|
||||||
for (var key : source.keys()) {
|
|
||||||
add((Key<Object>)key, (Object)source.get(key));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
default Extensions copy() {
|
|
||||||
var res = new Environment();
|
|
||||||
for (var key : keys()) {
|
|
||||||
var val = get(key);
|
|
||||||
if (val instanceof Copyable) val = ((Copyable)val).copy();
|
|
||||||
res.add((Key<Object>)key, val);
|
|
||||||
}
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
@Override
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
default Extensions child() {
|
|
||||||
var res = new Environment();
|
|
||||||
for (var key : keys()) {
|
|
||||||
var val = get(key);
|
|
||||||
if (val instanceof Childable) val = ((Childable)val).child();
|
|
||||||
res.add((Key<Object>)key, val);
|
|
||||||
}
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Extensions wrap(Extensions ext) {
|
|
||||||
if (ext == null) return EMPTY;
|
|
||||||
else return ext;
|
|
||||||
}
|
|
||||||
}
|
|
@ -5,6 +5,8 @@ import java.util.Stack;
|
|||||||
|
|
||||||
import me.topchetoeu.jscript.common.Instruction;
|
import me.topchetoeu.jscript.common.Instruction;
|
||||||
import me.topchetoeu.jscript.runtime.debug.DebugContext;
|
import me.topchetoeu.jscript.runtime.debug.DebugContext;
|
||||||
|
import me.topchetoeu.jscript.runtime.environment.Environment;
|
||||||
|
import me.topchetoeu.jscript.runtime.environment.Key;
|
||||||
import me.topchetoeu.jscript.runtime.exceptions.EngineException;
|
import me.topchetoeu.jscript.runtime.exceptions.EngineException;
|
||||||
import me.topchetoeu.jscript.runtime.exceptions.InterruptException;
|
import me.topchetoeu.jscript.runtime.exceptions.InterruptException;
|
||||||
import me.topchetoeu.jscript.runtime.scope.LocalScope;
|
import me.topchetoeu.jscript.runtime.scope.LocalScope;
|
||||||
@ -16,6 +18,8 @@ import me.topchetoeu.jscript.runtime.values.ScopeValue;
|
|||||||
import me.topchetoeu.jscript.runtime.values.Values;
|
import me.topchetoeu.jscript.runtime.values.Values;
|
||||||
|
|
||||||
public class Frame {
|
public class Frame {
|
||||||
|
public static final Key<Frame> KEY = new Key<>();
|
||||||
|
|
||||||
public static enum TryState {
|
public static enum TryState {
|
||||||
TRY,
|
TRY,
|
||||||
CATCH,
|
CATCH,
|
||||||
@ -94,11 +98,13 @@ public class Frame {
|
|||||||
public final Object[] args;
|
public final Object[] args;
|
||||||
public final Stack<TryCtx> tryStack = new Stack<>();
|
public final Stack<TryCtx> tryStack = new Stack<>();
|
||||||
public final CodeFunction function;
|
public final CodeFunction function;
|
||||||
public final Context ctx;
|
public final Environment env;
|
||||||
|
|
||||||
public Object[] stack = new Object[32];
|
public Object[] stack = new Object[32];
|
||||||
public int stackPtr = 0;
|
public int stackPtr = 0;
|
||||||
public int codePtr = 0;
|
public int codePtr = 0;
|
||||||
public boolean jumpFlag = false, popTryFlag = false;
|
public boolean jumpFlag = false;
|
||||||
|
public boolean popTryFlag = false;
|
||||||
|
|
||||||
public void addTry(int start, int end, int catchStart, int finallyStart) {
|
public void addTry(int start, int end, int catchStart, int finallyStart) {
|
||||||
var err = tryStack.empty() ? null : tryStack.peek().error;
|
var err = tryStack.empty() ? null : tryStack.peek().error;
|
||||||
@ -137,10 +143,10 @@ public class Frame {
|
|||||||
System.arraycopy(stack, 0, newStack, 0, stack.length);
|
System.arraycopy(stack, 0, newStack, 0, stack.length);
|
||||||
stack = newStack;
|
stack = newStack;
|
||||||
}
|
}
|
||||||
stack[stackPtr++] = Values.normalize(ctx, val);
|
stack[stackPtr++] = Values.normalize(env, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Object next(Object value, Object returnValue, EngineException error) {
|
private Object next(Object value, Object returnValue, EngineException error) {
|
||||||
if (value != Values.NO_RETURN) push(value);
|
if (value != Values.NO_RETURN) push(value);
|
||||||
|
|
||||||
Instruction instr = null;
|
Instruction instr = null;
|
||||||
@ -148,18 +154,18 @@ public class Frame {
|
|||||||
|
|
||||||
if (returnValue == Values.NO_RETURN && error == null) {
|
if (returnValue == Values.NO_RETURN && error == null) {
|
||||||
try {
|
try {
|
||||||
if (Thread.currentThread().isInterrupted()) throw new InterruptException();
|
if (Thread.interrupted()) throw new InterruptException();
|
||||||
|
|
||||||
if (instr == null) returnValue = null;
|
if (instr == null) returnValue = null;
|
||||||
else {
|
else {
|
||||||
DebugContext.get(ctx).onInstruction(ctx, this, instr, Values.NO_RETURN, null, false);
|
DebugContext.get(env).onInstruction(env, this, instr, Values.NO_RETURN, null, false);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
this.jumpFlag = this.popTryFlag = false;
|
this.jumpFlag = this.popTryFlag = false;
|
||||||
returnValue = InstructionRunner.exec(ctx, instr, this);
|
returnValue = InstructionRunner.exec(env, instr, this);
|
||||||
}
|
}
|
||||||
catch (EngineException e) {
|
catch (EngineException e) {
|
||||||
error = e.add(ctx, function.name, DebugContext.get(ctx).getMapOrEmpty(function).toLocation(codePtr, true));
|
error = e.add(env, function.name, DebugContext.get(env).getMapOrEmpty(function).toLocation(codePtr, true));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -201,6 +207,7 @@ public class Frame {
|
|||||||
tryStack.pop();
|
tryStack.pop();
|
||||||
tryStack.push(newCtx);
|
tryStack.push(newCtx);
|
||||||
}
|
}
|
||||||
|
|
||||||
error = null;
|
error = null;
|
||||||
returnValue = Values.NO_RETURN;
|
returnValue = Values.NO_RETURN;
|
||||||
break;
|
break;
|
||||||
@ -239,33 +246,75 @@ public class Frame {
|
|||||||
if (error != null) {
|
if (error != null) {
|
||||||
var caught = false;
|
var caught = false;
|
||||||
|
|
||||||
for (var frame : ctx.frames()) {
|
for (var frame : DebugContext.get(env).getStackFrames()) {
|
||||||
for (var tryCtx : frame.tryStack) {
|
for (var tryCtx : frame.tryStack) {
|
||||||
if (tryCtx.state == TryState.TRY) caught = true;
|
if (tryCtx.state == TryState.TRY) caught = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DebugContext.get(ctx).onInstruction(ctx, this, instr, null, error, caught);
|
DebugContext.get(env).onInstruction(env, this, instr, null, error, caught);
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
if (returnValue != Values.NO_RETURN) {
|
if (returnValue != Values.NO_RETURN) {
|
||||||
DebugContext.get(ctx).onInstruction(ctx, this, instr, returnValue, null, false);
|
DebugContext.get(env).onInstruction(env, this, instr, returnValue, null, false);
|
||||||
return returnValue;
|
return returnValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Values.NO_RETURN;
|
return Values.NO_RETURN;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onPush() {
|
/**
|
||||||
DebugContext.get(ctx).onFramePush(ctx, this);
|
* Executes the next instruction in the frame
|
||||||
|
*/
|
||||||
|
public Object next() {
|
||||||
|
return next(Values.NO_RETURN, Values.NO_RETURN, null);
|
||||||
}
|
}
|
||||||
public void onPop() {
|
/**
|
||||||
DebugContext.get(ctx.parent).onFramePop(ctx.parent, this);
|
* Induces a value on the stack (as if it were returned by the last function call)
|
||||||
|
* and executes the next instruction in the frame.
|
||||||
|
*
|
||||||
|
* @param value The value to induce
|
||||||
|
*/
|
||||||
|
public Object next(Object value) {
|
||||||
|
return next(value, Values.NO_RETURN, null);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Induces a thrown error and executes the next instruction.
|
||||||
|
* Note that this is different than just throwing the error outside the
|
||||||
|
* function, as the function executed could have a try-catch which
|
||||||
|
* would otherwise handle the error
|
||||||
|
*
|
||||||
|
* @param error The error to induce
|
||||||
|
*/
|
||||||
|
public Object induceError(EngineException error) {
|
||||||
|
return next(Values.NO_RETURN, Values.NO_RETURN, error);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Induces a return, as if there was a return statement before
|
||||||
|
* the currently executed instruction and executes the next instruction.
|
||||||
|
* Note that this is different than just returning the value outside the
|
||||||
|
* function, as the function executed could have a try-catch which
|
||||||
|
* would otherwise handle the error
|
||||||
|
*
|
||||||
|
* @param value The retunr value to induce
|
||||||
|
*/
|
||||||
|
public Object induceReturn(Object value) {
|
||||||
|
return next(Values.NO_RETURN, value, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void onPush() {
|
||||||
|
DebugContext.get(env).onFramePush(env, this);
|
||||||
|
}
|
||||||
|
public void onPop() {
|
||||||
|
DebugContext.get(env).onFramePop(env, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets an object proxy of the local scope
|
||||||
|
*/
|
||||||
public ObjectValue getLocalScope() {
|
public ObjectValue getLocalScope() {
|
||||||
var names = new String[scope.locals.length];
|
var names = new String[scope.locals.length];
|
||||||
var map = DebugContext.get(ctx).getMapOrEmpty(function);
|
var map = DebugContext.get(env).getMapOrEmpty(function);
|
||||||
|
|
||||||
for (int i = 0; i < scope.locals.length; i++) {
|
for (int i = 0; i < scope.locals.length; i++) {
|
||||||
var name = "local_" + (i - 2);
|
var name = "local_" + (i - 2);
|
||||||
@ -279,9 +328,12 @@ public class Frame {
|
|||||||
|
|
||||||
return new ScopeValue(scope.locals, names);
|
return new ScopeValue(scope.locals, names);
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* Gets an object proxy of the capture scope
|
||||||
|
*/
|
||||||
public ObjectValue getCaptureScope() {
|
public ObjectValue getCaptureScope() {
|
||||||
var names = new String[scope.captures.length];
|
var names = new String[scope.captures.length];
|
||||||
var map = DebugContext.get(ctx).getMapOrEmpty(function);
|
var map = DebugContext.get(env).getMapOrEmpty(function);
|
||||||
|
|
||||||
for (int i = 0; i < scope.captures.length; i++) {
|
for (int i = 0; i < scope.captures.length; i++) {
|
||||||
var name = "capture_" + (i - 2);
|
var name = "capture_" + (i - 2);
|
||||||
@ -291,16 +343,19 @@ public class Frame {
|
|||||||
|
|
||||||
return new ScopeValue(scope.captures, names);
|
return new ScopeValue(scope.captures, names);
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* Gets an array proxy of the local scope
|
||||||
|
*/
|
||||||
public ObjectValue getValStackScope() {
|
public ObjectValue getValStackScope() {
|
||||||
return new ObjectValue() {
|
return new ObjectValue() {
|
||||||
@Override
|
@Override
|
||||||
protected Object getField(Extensions ext, Object key) {
|
protected Object getField(Environment ext, Object key) {
|
||||||
var i = (int)Values.toNumber(ext, key);
|
var i = (int)Values.toNumber(ext, key);
|
||||||
if (i < 0 || i >= stackPtr) return null;
|
if (i < 0 || i >= stackPtr) return null;
|
||||||
else return stack[i];
|
else return stack[i];
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
protected boolean hasField(Extensions ext, Object key) {
|
protected boolean hasField(Environment ext, Object key) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
@ -312,18 +367,18 @@ public class Frame {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public Frame(Context ctx, Object thisArg, Object[] args, CodeFunction func) {
|
public Frame(Environment env, Object thisArg, Object[] args, CodeFunction func) {
|
||||||
|
this.env = env;
|
||||||
this.args = args.clone();
|
this.args = args.clone();
|
||||||
this.scope = new LocalScope(func.body.localsN, func.captures);
|
this.scope = new LocalScope(func.body.localsN, func.captures);
|
||||||
this.scope.get(0).set(null, thisArg);
|
this.scope.get(0).set(null, thisArg);
|
||||||
var argsObj = new ArrayValue();
|
var argsObj = new ArrayValue();
|
||||||
for (var i = 0; i < args.length; i++) {
|
for (var i = 0; i < args.length; i++) {
|
||||||
argsObj.set(ctx, i, args[i]);
|
argsObj.set(env, i, args[i]);
|
||||||
}
|
}
|
||||||
this.scope.get(1).value = argsObj;
|
this.scope.get(1).value = argsObj;
|
||||||
|
|
||||||
this.thisArg = thisArg;
|
this.thisArg = thisArg;
|
||||||
this.function = func;
|
this.function = func;
|
||||||
this.ctx = ctx.pushFrame(this);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@ import java.util.Collections;
|
|||||||
|
|
||||||
import me.topchetoeu.jscript.common.Instruction;
|
import me.topchetoeu.jscript.common.Instruction;
|
||||||
import me.topchetoeu.jscript.common.Operation;
|
import me.topchetoeu.jscript.common.Operation;
|
||||||
|
import me.topchetoeu.jscript.runtime.environment.Environment;
|
||||||
import me.topchetoeu.jscript.runtime.exceptions.EngineException;
|
import me.topchetoeu.jscript.runtime.exceptions.EngineException;
|
||||||
import me.topchetoeu.jscript.runtime.scope.GlobalScope;
|
import me.topchetoeu.jscript.runtime.scope.GlobalScope;
|
||||||
import me.topchetoeu.jscript.runtime.scope.ValueVariable;
|
import me.topchetoeu.jscript.runtime.scope.ValueVariable;
|
||||||
@ -15,17 +16,17 @@ import me.topchetoeu.jscript.runtime.values.Symbol;
|
|||||||
import me.topchetoeu.jscript.runtime.values.Values;
|
import me.topchetoeu.jscript.runtime.values.Values;
|
||||||
|
|
||||||
public class InstructionRunner {
|
public class InstructionRunner {
|
||||||
private static Object execReturn(Extensions ext, Instruction instr, Frame frame) {
|
private static Object execReturn(Environment ext, Instruction instr, Frame frame) {
|
||||||
return frame.pop();
|
return frame.pop();
|
||||||
}
|
}
|
||||||
private static Object execThrow(Extensions ext, Instruction instr, Frame frame) {
|
private static Object execThrow(Environment ext, Instruction instr, Frame frame) {
|
||||||
throw new EngineException(frame.pop());
|
throw new EngineException(frame.pop());
|
||||||
}
|
}
|
||||||
private static Object execThrowSyntax(Extensions ext, Instruction instr, Frame frame) {
|
private static Object execThrowSyntax(Environment ext, Instruction instr, Frame frame) {
|
||||||
throw EngineException.ofSyntax((String)instr.get(0));
|
throw EngineException.ofSyntax((String)instr.get(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Object execCall(Extensions ext, Instruction instr, Frame frame) {
|
private static Object execCall(Environment ext, Instruction instr, Frame frame) {
|
||||||
var callArgs = frame.take(instr.get(0));
|
var callArgs = frame.take(instr.get(0));
|
||||||
var func = frame.pop();
|
var func = frame.pop();
|
||||||
var thisArg = frame.pop();
|
var thisArg = frame.pop();
|
||||||
@ -35,7 +36,7 @@ public class InstructionRunner {
|
|||||||
frame.codePtr++;
|
frame.codePtr++;
|
||||||
return Values.NO_RETURN;
|
return Values.NO_RETURN;
|
||||||
}
|
}
|
||||||
private static Object execCallNew(Extensions ext, Instruction instr, Frame frame) {
|
private static Object execCallNew(Environment ext, Instruction instr, Frame frame) {
|
||||||
var callArgs = frame.take(instr.get(0));
|
var callArgs = frame.take(instr.get(0));
|
||||||
var funcObj = frame.pop();
|
var funcObj = frame.pop();
|
||||||
|
|
||||||
@ -45,13 +46,13 @@ public class InstructionRunner {
|
|||||||
return Values.NO_RETURN;
|
return Values.NO_RETURN;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Object execMakeVar(Extensions ext, Instruction instr, Frame frame) {
|
private static Object execMakeVar(Environment ext, Instruction instr, Frame frame) {
|
||||||
var name = (String)instr.get(0);
|
var name = (String)instr.get(0);
|
||||||
GlobalScope.get(ext).define(ext, name);
|
GlobalScope.get(ext).define(ext, name);
|
||||||
frame.codePtr++;
|
frame.codePtr++;
|
||||||
return Values.NO_RETURN;
|
return Values.NO_RETURN;
|
||||||
}
|
}
|
||||||
private static Object execDefProp(Extensions ext, Instruction instr, Frame frame) {
|
private static Object execDefProp(Environment ext, Instruction instr, Frame frame) {
|
||||||
var setter = frame.pop();
|
var setter = frame.pop();
|
||||||
var getter = frame.pop();
|
var getter = frame.pop();
|
||||||
var name = frame.pop();
|
var name = frame.pop();
|
||||||
@ -66,7 +67,7 @@ public class InstructionRunner {
|
|||||||
frame.codePtr++;
|
frame.codePtr++;
|
||||||
return Values.NO_RETURN;
|
return Values.NO_RETURN;
|
||||||
}
|
}
|
||||||
private static Object execKeys(Extensions ext, Instruction instr, Frame frame) {
|
private static Object execKeys(Environment ext, Instruction instr, Frame frame) {
|
||||||
var val = frame.pop();
|
var val = frame.pop();
|
||||||
|
|
||||||
var members = Values.getMembers(ext, val, false, false);
|
var members = Values.getMembers(ext, val, false, false);
|
||||||
@ -85,7 +86,7 @@ public class InstructionRunner {
|
|||||||
return Values.NO_RETURN;
|
return Values.NO_RETURN;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Object execTryStart(Extensions ext, Instruction instr, Frame frame) {
|
private static Object execTryStart(Environment ext, Instruction instr, Frame frame) {
|
||||||
int start = frame.codePtr + 1;
|
int start = frame.codePtr + 1;
|
||||||
int catchStart = (int)instr.get(0);
|
int catchStart = (int)instr.get(0);
|
||||||
int finallyStart = (int)instr.get(1);
|
int finallyStart = (int)instr.get(1);
|
||||||
@ -96,12 +97,12 @@ public class InstructionRunner {
|
|||||||
frame.codePtr++;
|
frame.codePtr++;
|
||||||
return Values.NO_RETURN;
|
return Values.NO_RETURN;
|
||||||
}
|
}
|
||||||
private static Object execTryEnd(Extensions ext, Instruction instr, Frame frame) {
|
private static Object execTryEnd(Environment ext, Instruction instr, Frame frame) {
|
||||||
frame.popTryFlag = true;
|
frame.popTryFlag = true;
|
||||||
return Values.NO_RETURN;
|
return Values.NO_RETURN;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Object execDup(Extensions ext, Instruction instr, Frame frame) {
|
private static Object execDup(Environment ext, Instruction instr, Frame frame) {
|
||||||
int count = instr.get(0);
|
int count = instr.get(0);
|
||||||
|
|
||||||
for (var i = 0; i < count; i++) {
|
for (var i = 0; i < count; i++) {
|
||||||
@ -111,7 +112,7 @@ public class InstructionRunner {
|
|||||||
frame.codePtr++;
|
frame.codePtr++;
|
||||||
return Values.NO_RETURN;
|
return Values.NO_RETURN;
|
||||||
}
|
}
|
||||||
private static Object execLoadValue(Extensions ext, Instruction instr, Frame frame) {
|
private static Object execLoadValue(Environment ext, Instruction instr, Frame frame) {
|
||||||
switch (instr.type) {
|
switch (instr.type) {
|
||||||
case PUSH_UNDEFINED: frame.push(null); break;
|
case PUSH_UNDEFINED: frame.push(null); break;
|
||||||
case PUSH_NULL: frame.push(Values.NULL); break;
|
case PUSH_NULL: frame.push(Values.NULL); break;
|
||||||
@ -121,7 +122,7 @@ public class InstructionRunner {
|
|||||||
frame.codePtr++;
|
frame.codePtr++;
|
||||||
return Values.NO_RETURN;
|
return Values.NO_RETURN;
|
||||||
}
|
}
|
||||||
private static Object execLoadVar(Extensions ext, Instruction instr, Frame frame) {
|
private static Object execLoadVar(Environment ext, Instruction instr, Frame frame) {
|
||||||
var i = instr.get(0);
|
var i = instr.get(0);
|
||||||
|
|
||||||
if (i instanceof String) frame.push(GlobalScope.get(ext).get(ext, (String)i));
|
if (i instanceof String) frame.push(GlobalScope.get(ext).get(ext, (String)i));
|
||||||
@ -130,24 +131,24 @@ public class InstructionRunner {
|
|||||||
frame.codePtr++;
|
frame.codePtr++;
|
||||||
return Values.NO_RETURN;
|
return Values.NO_RETURN;
|
||||||
}
|
}
|
||||||
private static Object execLoadObj(Extensions ext, Instruction instr, Frame frame) {
|
private static Object execLoadObj(Environment ext, Instruction instr, Frame frame) {
|
||||||
frame.push(new ObjectValue());
|
frame.push(new ObjectValue());
|
||||||
frame.codePtr++;
|
frame.codePtr++;
|
||||||
return Values.NO_RETURN;
|
return Values.NO_RETURN;
|
||||||
}
|
}
|
||||||
private static Object execLoadGlob(Extensions ext, Instruction instr, Frame frame) {
|
private static Object execLoadGlob(Environment ext, Instruction instr, Frame frame) {
|
||||||
frame.push(GlobalScope.get(ext).obj);
|
frame.push(GlobalScope.get(ext).obj);
|
||||||
frame.codePtr++;
|
frame.codePtr++;
|
||||||
return Values.NO_RETURN;
|
return Values.NO_RETURN;
|
||||||
}
|
}
|
||||||
private static Object execLoadArr(Extensions ext, Instruction instr, Frame frame) {
|
private static Object execLoadArr(Environment ext, Instruction instr, Frame frame) {
|
||||||
var res = new ArrayValue();
|
var res = new ArrayValue();
|
||||||
res.setSize(instr.get(0));
|
res.setSize(instr.get(0));
|
||||||
frame.push(res);
|
frame.push(res);
|
||||||
frame.codePtr++;
|
frame.codePtr++;
|
||||||
return Values.NO_RETURN;
|
return Values.NO_RETURN;
|
||||||
}
|
}
|
||||||
private static Object execLoadFunc(Extensions ext, Instruction instr, Frame frame) {
|
private static Object execLoadFunc(Environment ext, Instruction instr, Frame frame) {
|
||||||
int id = instr.get(0);
|
int id = instr.get(0);
|
||||||
var captures = new ValueVariable[instr.params.length - 1];
|
var captures = new ValueVariable[instr.params.length - 1];
|
||||||
|
|
||||||
@ -162,7 +163,7 @@ public class InstructionRunner {
|
|||||||
frame.codePtr++;
|
frame.codePtr++;
|
||||||
return Values.NO_RETURN;
|
return Values.NO_RETURN;
|
||||||
}
|
}
|
||||||
private static Object execLoadMember(Extensions ext, Instruction instr, Frame frame) {
|
private static Object execLoadMember(Environment ext, Instruction instr, Frame frame) {
|
||||||
var key = frame.pop();
|
var key = frame.pop();
|
||||||
var obj = frame.pop();
|
var obj = frame.pop();
|
||||||
|
|
||||||
@ -175,7 +176,7 @@ public class InstructionRunner {
|
|||||||
frame.codePtr++;
|
frame.codePtr++;
|
||||||
return Values.NO_RETURN;
|
return Values.NO_RETURN;
|
||||||
}
|
}
|
||||||
private static Object execLoadRegEx(Extensions ext, Instruction instr, Frame frame) {
|
private static Object execLoadRegEx(Environment ext, Instruction instr, Frame frame) {
|
||||||
if (ext.hasNotNull(Environment.REGEX_CONSTR)) {
|
if (ext.hasNotNull(Environment.REGEX_CONSTR)) {
|
||||||
frame.push(Values.callNew(ext, ext.get(Environment.REGEX_CONSTR), instr.get(0), instr.get(1)));
|
frame.push(Values.callNew(ext, ext.get(Environment.REGEX_CONSTR), instr.get(0), instr.get(1)));
|
||||||
}
|
}
|
||||||
@ -186,12 +187,12 @@ public class InstructionRunner {
|
|||||||
return Values.NO_RETURN;
|
return Values.NO_RETURN;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Object execDiscard(Extensions ext, Instruction instr, Frame frame) {
|
private static Object execDiscard(Environment ext, Instruction instr, Frame frame) {
|
||||||
frame.pop();
|
frame.pop();
|
||||||
frame.codePtr++;
|
frame.codePtr++;
|
||||||
return Values.NO_RETURN;
|
return Values.NO_RETURN;
|
||||||
}
|
}
|
||||||
private static Object execStoreMember(Extensions ext, Instruction instr, Frame frame) {
|
private static Object execStoreMember(Environment ext, Instruction instr, Frame frame) {
|
||||||
var val = frame.pop();
|
var val = frame.pop();
|
||||||
var key = frame.pop();
|
var key = frame.pop();
|
||||||
var obj = frame.pop();
|
var obj = frame.pop();
|
||||||
@ -201,7 +202,7 @@ public class InstructionRunner {
|
|||||||
frame.codePtr++;
|
frame.codePtr++;
|
||||||
return Values.NO_RETURN;
|
return Values.NO_RETURN;
|
||||||
}
|
}
|
||||||
private static Object execStoreVar(Extensions ext, Instruction instr, Frame frame) {
|
private static Object execStoreVar(Environment ext, Instruction instr, Frame frame) {
|
||||||
var val = (boolean)instr.get(1) ? frame.peek() : frame.pop();
|
var val = (boolean)instr.get(1) ? frame.peek() : frame.pop();
|
||||||
var i = instr.get(0);
|
var i = instr.get(0);
|
||||||
|
|
||||||
@ -211,18 +212,18 @@ public class InstructionRunner {
|
|||||||
frame.codePtr++;
|
frame.codePtr++;
|
||||||
return Values.NO_RETURN;
|
return Values.NO_RETURN;
|
||||||
}
|
}
|
||||||
private static Object execStoreSelfFunc(Extensions ext, Instruction instr, Frame frame) {
|
private static Object execStoreSelfFunc(Environment ext, Instruction instr, Frame frame) {
|
||||||
frame.scope.locals[(int)instr.get(0)].set(ext, frame.function);
|
frame.scope.locals[(int)instr.get(0)].set(ext, frame.function);
|
||||||
frame.codePtr++;
|
frame.codePtr++;
|
||||||
return Values.NO_RETURN;
|
return Values.NO_RETURN;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Object execJmp(Extensions ext, Instruction instr, Frame frame) {
|
private static Object execJmp(Environment ext, Instruction instr, Frame frame) {
|
||||||
frame.codePtr += (int)instr.get(0);
|
frame.codePtr += (int)instr.get(0);
|
||||||
frame.jumpFlag = true;
|
frame.jumpFlag = true;
|
||||||
return Values.NO_RETURN;
|
return Values.NO_RETURN;
|
||||||
}
|
}
|
||||||
private static Object execJmpIf(Extensions ext, Instruction instr, Frame frame) {
|
private static Object execJmpIf(Environment ext, Instruction instr, Frame frame) {
|
||||||
if (Values.toBoolean(frame.pop())) {
|
if (Values.toBoolean(frame.pop())) {
|
||||||
frame.codePtr += (int)instr.get(0);
|
frame.codePtr += (int)instr.get(0);
|
||||||
frame.jumpFlag = true;
|
frame.jumpFlag = true;
|
||||||
@ -230,7 +231,7 @@ public class InstructionRunner {
|
|||||||
else frame.codePtr ++;
|
else frame.codePtr ++;
|
||||||
return Values.NO_RETURN;
|
return Values.NO_RETURN;
|
||||||
}
|
}
|
||||||
private static Object execJmpIfNot(Extensions ext, Instruction instr, Frame frame) {
|
private static Object execJmpIfNot(Environment ext, Instruction instr, Frame frame) {
|
||||||
if (Values.not(frame.pop())) {
|
if (Values.not(frame.pop())) {
|
||||||
frame.codePtr += (int)instr.get(0);
|
frame.codePtr += (int)instr.get(0);
|
||||||
frame.jumpFlag = true;
|
frame.jumpFlag = true;
|
||||||
@ -239,7 +240,7 @@ public class InstructionRunner {
|
|||||||
return Values.NO_RETURN;
|
return Values.NO_RETURN;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Object execTypeof(Extensions ext, Instruction instr, Frame frame) {
|
private static Object execTypeof(Environment ext, Instruction instr, Frame frame) {
|
||||||
String name = instr.get(0);
|
String name = instr.get(0);
|
||||||
Object obj;
|
Object obj;
|
||||||
|
|
||||||
@ -256,12 +257,12 @@ public class InstructionRunner {
|
|||||||
frame.codePtr++;
|
frame.codePtr++;
|
||||||
return Values.NO_RETURN;
|
return Values.NO_RETURN;
|
||||||
}
|
}
|
||||||
private static Object execNop(Extensions ext, Instruction instr, Frame frame) {
|
private static Object execNop(Environment ext, Instruction instr, Frame frame) {
|
||||||
frame.codePtr++;
|
frame.codePtr++;
|
||||||
return Values.NO_RETURN;
|
return Values.NO_RETURN;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Object execDelete(Extensions ext, Instruction instr, Frame frame) {
|
private static Object execDelete(Environment ext, Instruction instr, Frame frame) {
|
||||||
var key = frame.pop();
|
var key = frame.pop();
|
||||||
var val = frame.pop();
|
var val = frame.pop();
|
||||||
|
|
||||||
@ -270,7 +271,7 @@ public class InstructionRunner {
|
|||||||
return Values.NO_RETURN;
|
return Values.NO_RETURN;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Object execOperation(Extensions ext, Instruction instr, Frame frame) {
|
private static Object execOperation(Environment ext, Instruction instr, Frame frame) {
|
||||||
Operation op = instr.get(0);
|
Operation op = instr.get(0);
|
||||||
var args = new Object[op.operands];
|
var args = new Object[op.operands];
|
||||||
|
|
||||||
@ -281,7 +282,7 @@ public class InstructionRunner {
|
|||||||
return Values.NO_RETURN;
|
return Values.NO_RETURN;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Object exec(Extensions ext, Instruction instr, Frame frame) {
|
public static Object exec(Environment ext, Instruction instr, Frame frame) {
|
||||||
switch (instr.type) {
|
switch (instr.type) {
|
||||||
case NOP: return execNop(ext, instr, frame);
|
case NOP: return execNop(ext, instr, frame);
|
||||||
case RETURN: return execReturn(ext, instr, frame);
|
case RETURN: return execReturn(ext, instr, frame);
|
||||||
|
@ -1,5 +0,0 @@
|
|||||||
package me.topchetoeu.jscript.runtime;
|
|
||||||
|
|
||||||
public class Key<T> {
|
|
||||||
|
|
||||||
}
|
|
@ -1,5 +1,6 @@
|
|||||||
package me.topchetoeu.jscript.runtime;
|
package me.topchetoeu.jscript.runtime;
|
||||||
|
|
||||||
|
import me.topchetoeu.jscript.runtime.environment.Environment;
|
||||||
import me.topchetoeu.jscript.runtime.values.FunctionValue;
|
import me.topchetoeu.jscript.runtime.values.FunctionValue;
|
||||||
import me.topchetoeu.jscript.runtime.values.ObjectValue;
|
import me.topchetoeu.jscript.runtime.values.ObjectValue;
|
||||||
|
|
||||||
|
@ -10,10 +10,9 @@ import me.topchetoeu.jscript.common.FunctionBody;
|
|||||||
import me.topchetoeu.jscript.common.Instruction;
|
import me.topchetoeu.jscript.common.Instruction;
|
||||||
import me.topchetoeu.jscript.common.Location;
|
import me.topchetoeu.jscript.common.Location;
|
||||||
import me.topchetoeu.jscript.common.mapping.FunctionMap;
|
import me.topchetoeu.jscript.common.mapping.FunctionMap;
|
||||||
import me.topchetoeu.jscript.runtime.Context;
|
|
||||||
import me.topchetoeu.jscript.runtime.Extensions;
|
|
||||||
import me.topchetoeu.jscript.runtime.Frame;
|
import me.topchetoeu.jscript.runtime.Frame;
|
||||||
import me.topchetoeu.jscript.runtime.Key;
|
import me.topchetoeu.jscript.runtime.environment.Environment;
|
||||||
|
import me.topchetoeu.jscript.runtime.environment.Key;
|
||||||
import me.topchetoeu.jscript.runtime.exceptions.EngineException;
|
import me.topchetoeu.jscript.runtime.exceptions.EngineException;
|
||||||
import me.topchetoeu.jscript.runtime.values.CodeFunction;
|
import me.topchetoeu.jscript.runtime.values.CodeFunction;
|
||||||
import me.topchetoeu.jscript.runtime.values.FunctionValue;
|
import me.topchetoeu.jscript.runtime.values.FunctionValue;
|
||||||
@ -71,15 +70,19 @@ public class DebugContext {
|
|||||||
if (maps == null || !(func instanceof CodeFunction)) return FunctionMap.EMPTY;
|
if (maps == null || !(func instanceof CodeFunction)) return FunctionMap.EMPTY;
|
||||||
return getMapOrEmpty(((CodeFunction)func).body);
|
return getMapOrEmpty(((CodeFunction)func).body);
|
||||||
}
|
}
|
||||||
|
public List<Frame> getStackFrames() {
|
||||||
|
return this.debugger.getStackFrame();
|
||||||
|
}
|
||||||
|
|
||||||
public void onFramePop(Context ctx, Frame frame) {
|
public void onFramePop(Environment env, Frame frame) {
|
||||||
if (debugger != null) debugger.onFramePop(ctx, frame);
|
if (debugger != null) debugger.onFramePop(env, frame);
|
||||||
}
|
}
|
||||||
public void onFramePush(Context ctx, Frame frame) {
|
public void onFramePush(Environment env, Frame frame) {
|
||||||
if (debugger != null) debugger.onFramePush(ctx, frame);
|
if (debugger != null) debugger.onFramePush(env, frame);
|
||||||
}
|
}
|
||||||
public boolean onInstruction(Context ctx, Frame frame, Instruction instruction, Object returnVal, EngineException error, boolean caught) {
|
|
||||||
if (debugger != null) return debugger.onInstruction(ctx, frame, instruction, returnVal, error, caught);
|
public boolean onInstruction(Environment env, Frame frame, Instruction instruction, Object returnVal, EngineException error, boolean caught) {
|
||||||
|
if (debugger != null) return debugger.onInstruction(env, frame, instruction, returnVal, error, caught);
|
||||||
else return false;
|
else return false;
|
||||||
}
|
}
|
||||||
public void onSource(Filename filename, String source) {
|
public void onSource(Filename filename, String source) {
|
||||||
@ -102,26 +105,26 @@ public class DebugContext {
|
|||||||
this(true);
|
this(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean enabled(Extensions exts) {
|
public static boolean enabled(Environment exts) {
|
||||||
return exts != null && exts.hasNotNull(KEY) && !exts.has(IGNORE);
|
return exts != null && exts.hasNotNull(KEY) && !exts.has(IGNORE);
|
||||||
}
|
}
|
||||||
public static DebugContext get(Extensions exts) {
|
public static DebugContext get(Environment exts) {
|
||||||
if (enabled(exts)) return exts.get(KEY);
|
if (enabled(exts)) return exts.get(KEY);
|
||||||
else return new DebugContext(false);
|
else return new DebugContext(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static List<String> stackTrace(Context ctx) {
|
public static List<String> stackTrace(Environment env) {
|
||||||
var res = new ArrayList<String>();
|
var res = new ArrayList<String>();
|
||||||
var dbgCtx = get(ctx);
|
var dbgCtx = get(env);
|
||||||
|
|
||||||
for (var el : ctx.frames()) {
|
for (var frame : dbgCtx.getStackFrames()) {
|
||||||
var name = el.function.name;
|
var name = frame.function.name;
|
||||||
|
|
||||||
var map = dbgCtx.getMapOrEmpty(el.function);
|
var map = dbgCtx.getMapOrEmpty(frame.function);
|
||||||
Location loc = null;
|
Location loc = null;
|
||||||
|
|
||||||
if (map != null) {
|
if (map != null) {
|
||||||
loc = map.toLocation(el.codePtr, true);
|
loc = map.toLocation(frame.codePtr, true);
|
||||||
if (loc == null) loc = map.start();
|
if (loc == null) loc = map.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,11 +1,13 @@
|
|||||||
package me.topchetoeu.jscript.runtime.debug;
|
package me.topchetoeu.jscript.runtime.debug;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import me.topchetoeu.jscript.common.Filename;
|
import me.topchetoeu.jscript.common.Filename;
|
||||||
import me.topchetoeu.jscript.common.FunctionBody;
|
import me.topchetoeu.jscript.common.FunctionBody;
|
||||||
import me.topchetoeu.jscript.common.Instruction;
|
import me.topchetoeu.jscript.common.Instruction;
|
||||||
import me.topchetoeu.jscript.common.mapping.FunctionMap;
|
import me.topchetoeu.jscript.common.mapping.FunctionMap;
|
||||||
import me.topchetoeu.jscript.runtime.Context;
|
|
||||||
import me.topchetoeu.jscript.runtime.Frame;
|
import me.topchetoeu.jscript.runtime.Frame;
|
||||||
|
import me.topchetoeu.jscript.runtime.environment.Environment;
|
||||||
import me.topchetoeu.jscript.runtime.exceptions.EngineException;
|
import me.topchetoeu.jscript.runtime.exceptions.EngineException;
|
||||||
|
|
||||||
public interface DebugHandler {
|
public interface DebugHandler {
|
||||||
@ -35,7 +37,7 @@ public interface DebugHandler {
|
|||||||
/**
|
/**
|
||||||
* Called immediatly before an instruction is executed, as well as after an instruction, if it has threw or returned.
|
* Called immediatly before an instruction is executed, as well as after an instruction, if it has threw or returned.
|
||||||
* This function might pause in order to await debugging commands.
|
* This function might pause in order to await debugging commands.
|
||||||
* @param ctx The context of execution
|
* @param env The context of execution
|
||||||
* @param frame The frame in which execution is occuring
|
* @param frame The frame in which execution is occuring
|
||||||
* @param instruction The instruction which was or will be executed
|
* @param instruction The instruction which was or will be executed
|
||||||
* @param returnVal The return value of the instruction, Values.NO_RETURN if none
|
* @param returnVal The return value of the instruction, Values.NO_RETURN if none
|
||||||
@ -43,32 +45,35 @@ public interface DebugHandler {
|
|||||||
* @param caught Whether or not the error has been caught
|
* @param caught Whether or not the error has been caught
|
||||||
* @return Whether or not the frame should restart (currently does nothing)
|
* @return Whether or not the frame should restart (currently does nothing)
|
||||||
*/
|
*/
|
||||||
boolean onInstruction(Context ctx, Frame frame, Instruction instruction, Object returnVal, EngineException error, boolean caught);
|
boolean onInstruction(Environment env, Frame frame, Instruction instruction, Object returnVal, EngineException error, boolean caught);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called immediatly before a frame has been pushed on the frame stack.
|
* Called immediatly before a frame has been pushed on the frame stack.
|
||||||
* This function might pause in order to await debugging commands.
|
* This function might pause in order to await debugging commands.
|
||||||
* @param ctx The context of execution
|
* @param env The context of execution
|
||||||
* @param frame The code frame which was pushed
|
* @param frame The code frame which was pushed
|
||||||
*/
|
*/
|
||||||
void onFramePush(Context ctx, Frame frame);
|
void onFramePush(Environment env, Frame frame);
|
||||||
/**
|
/**
|
||||||
* Called immediatly after a frame has been popped out of the frame stack.
|
* Called immediatly after a frame has been popped out of the frame stack.
|
||||||
* This function might pause in order to await debugging commands.
|
* This function might pause in order to await debugging commands.
|
||||||
* @param ctx The context of execution
|
* @param env The context of execution
|
||||||
* @param frame The code frame which was popped out
|
* @param frame The code frame which was popped out
|
||||||
*/
|
*/
|
||||||
void onFramePop(Context ctx, Frame frame);
|
void onFramePop(Environment env, Frame frame);
|
||||||
|
|
||||||
|
List<Frame> getStackFrame();
|
||||||
|
|
||||||
public static DebugHandler empty() {
|
public static DebugHandler empty() {
|
||||||
return new DebugHandler () {
|
return new DebugHandler () {
|
||||||
@Override public void onFramePop(Context ctx, Frame frame) { }
|
@Override public void onFramePop(Environment env, Frame frame) { }
|
||||||
@Override public void onFramePush(Context ctx, Frame frame) { }
|
@Override public void onFramePush(Environment env, Frame frame) { }
|
||||||
@Override public boolean onInstruction(Context ctx, Frame frame, Instruction instruction, Object returnVal, EngineException error, boolean caught) {
|
@Override public boolean onInstruction(Environment env, Frame frame, Instruction instruction, Object returnVal, EngineException error, boolean caught) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@Override public void onSourceLoad(Filename filename, String source) { }
|
@Override public void onSourceLoad(Filename filename, String source) { }
|
||||||
@Override public void onFunctionLoad(FunctionBody body, FunctionMap map) { }
|
@Override public void onFunctionLoad(FunctionBody body, FunctionMap map) { }
|
||||||
|
@Override public List<Frame> getStackFrame() { return List.of(); }
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,144 @@
|
|||||||
|
package me.topchetoeu.jscript.runtime.environment;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Random;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
|
import me.topchetoeu.jscript.runtime.Compiler;
|
||||||
|
import me.topchetoeu.jscript.runtime.values.FunctionValue;
|
||||||
|
import me.topchetoeu.jscript.runtime.values.ObjectValue;
|
||||||
|
|
||||||
|
public class Environment {
|
||||||
|
public static final Key<Compiler> COMPILE_FUNC = new Key<>();
|
||||||
|
|
||||||
|
public static final Key<FunctionValue> REGEX_CONSTR = new Key<>();
|
||||||
|
public static final Key<Integer> MAX_STACK_COUNT = new Key<>();
|
||||||
|
public static final Key<Boolean> HIDE_STACK = new Key<>();
|
||||||
|
|
||||||
|
public static final Key<ObjectValue> OBJECT_PROTO = new Key<>();
|
||||||
|
public static final Key<ObjectValue> FUNCTION_PROTO = new Key<>();
|
||||||
|
public static final Key<ObjectValue> ARRAY_PROTO = new Key<>();
|
||||||
|
public static final Key<ObjectValue> BOOL_PROTO = new Key<>();
|
||||||
|
public static final Key<ObjectValue> NUMBER_PROTO = new Key<>();
|
||||||
|
public static final Key<ObjectValue> STRING_PROTO = new Key<>();
|
||||||
|
public static final Key<ObjectValue> SYMBOL_PROTO = new Key<>();
|
||||||
|
public static final Key<ObjectValue> ERROR_PROTO = new Key<>();
|
||||||
|
public static final Key<ObjectValue> SYNTAX_ERR_PROTO = new Key<>();
|
||||||
|
public static final Key<ObjectValue> TYPE_ERR_PROTO = new Key<>();
|
||||||
|
public static final Key<ObjectValue> RANGE_ERR_PROTO = new Key<>();
|
||||||
|
|
||||||
|
public final Environment parent;
|
||||||
|
private final Map<Key<Object>, Object> map = new HashMap<>();
|
||||||
|
private final Set<Key<Object>> hidden = new HashSet<>();
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public <T> T get(Key<T> key) {
|
||||||
|
if (map.containsKey(key)) return (T)map.get(key);
|
||||||
|
else if (!hidden.contains(key) && parent != null) return parent.get(key);
|
||||||
|
else return null;
|
||||||
|
}
|
||||||
|
public boolean has(Key<?> key) {
|
||||||
|
if (map.containsKey(key)) return true;
|
||||||
|
else if (!hidden.contains(key) && parent != null) return parent.has(key);
|
||||||
|
else return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("all")
|
||||||
|
public Set<Key<?>> keys() {
|
||||||
|
if (parent != null) {
|
||||||
|
if (map.size() == 0) return (Set)map.keySet();
|
||||||
|
|
||||||
|
var res = new HashSet();
|
||||||
|
res.addAll(parent.keys());
|
||||||
|
res.addAll(map.keySet());
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
else return (Set)map.keySet();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasNotNull(Key<?> key) {
|
||||||
|
return get(key) != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T> T get(Key<T> key, T defaultVal) {
|
||||||
|
if (has(key)) return get(key);
|
||||||
|
else return defaultVal;
|
||||||
|
}
|
||||||
|
public <T> T get(Key<T> key, Supplier<T> defaultVal) {
|
||||||
|
if (has(key)) return get(key);
|
||||||
|
else return defaultVal.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public <T> Environment add(Key<T> key, T val) {
|
||||||
|
map.put((Key<Object>)key, val);
|
||||||
|
hidden.remove(key);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public Environment add(Key<Void> key) {
|
||||||
|
map.put((Key<Object>)(Key<?>)key, null);
|
||||||
|
hidden.remove(key);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
@SuppressWarnings("all")
|
||||||
|
public Environment addAll(Map<Key<?>, ?> map) {
|
||||||
|
map.putAll((Map)map);
|
||||||
|
hidden.removeAll(map.keySet());
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
public Environment addAll(Environment env) {
|
||||||
|
this.map.putAll(env.map);
|
||||||
|
this.hidden.removeAll(env.map.keySet());
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public Environment remove(Key<?> key) {
|
||||||
|
map.remove((Key<Object>)key);
|
||||||
|
hidden.add((Key<Object>)key);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T> Environment init(Key<T> key, T val) {
|
||||||
|
if (!has(key)) this.add(key, val);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
public <T> Environment init(Key<T> key, Supplier<T> val) {
|
||||||
|
if (!has(key)) this.add(key, val.get());
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Environment child() {
|
||||||
|
return new Environment(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Environment(Environment parent) {
|
||||||
|
this.parent = parent;
|
||||||
|
}
|
||||||
|
public Environment() {
|
||||||
|
this.parent = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Environment wrap(Environment ext) {
|
||||||
|
if (ext == null) return empty();
|
||||||
|
else return ext;
|
||||||
|
}
|
||||||
|
|
||||||
|
// public static Environment chain(int id, Environment ...envs) {
|
||||||
|
// var res = new Environment();
|
||||||
|
// for (var env : envs) res.addAll(env);
|
||||||
|
// return res;
|
||||||
|
// }
|
||||||
|
|
||||||
|
public static Environment empty() {
|
||||||
|
return new Environment();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int nextId() {
|
||||||
|
return new Random().nextInt();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,5 @@
|
|||||||
|
package me.topchetoeu.jscript.runtime.environment;
|
||||||
|
|
||||||
|
public class Key<T> {
|
||||||
|
|
||||||
|
}
|
@ -4,9 +4,7 @@ import java.util.ArrayList;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import me.topchetoeu.jscript.common.Location;
|
import me.topchetoeu.jscript.common.Location;
|
||||||
import me.topchetoeu.jscript.runtime.Context;
|
import me.topchetoeu.jscript.runtime.environment.Environment;
|
||||||
import me.topchetoeu.jscript.runtime.Environment;
|
|
||||||
import me.topchetoeu.jscript.runtime.Extensions;
|
|
||||||
import me.topchetoeu.jscript.runtime.values.ObjectValue;
|
import me.topchetoeu.jscript.runtime.values.ObjectValue;
|
||||||
import me.topchetoeu.jscript.runtime.values.Values;
|
import me.topchetoeu.jscript.runtime.values.Values;
|
||||||
import me.topchetoeu.jscript.runtime.values.ObjectValue.PlaceholderProto;
|
import me.topchetoeu.jscript.runtime.values.ObjectValue.PlaceholderProto;
|
||||||
@ -15,7 +13,7 @@ public class EngineException extends RuntimeException {
|
|||||||
public static class StackElement {
|
public static class StackElement {
|
||||||
public final Location location;
|
public final Location location;
|
||||||
public final String name;
|
public final String name;
|
||||||
public final Extensions ext;
|
public final Environment ext;
|
||||||
|
|
||||||
public boolean visible() {
|
public boolean visible() {
|
||||||
return ext == null || !ext.get(Environment.HIDE_STACK, false);
|
return ext == null || !ext.get(Environment.HIDE_STACK, false);
|
||||||
@ -30,12 +28,12 @@ public class EngineException extends RuntimeException {
|
|||||||
return res.trim();
|
return res.trim();
|
||||||
}
|
}
|
||||||
|
|
||||||
public StackElement(Extensions ext, Location location, String name) {
|
public StackElement(Environment ext, Location location, String name) {
|
||||||
if (name != null) name = name.trim();
|
if (name != null) name = name.trim();
|
||||||
if (name.equals("")) name = null;
|
if (name.equals("")) name = null;
|
||||||
|
|
||||||
if (ext == null) this.ext = null;
|
if (ext == null) this.ext = null;
|
||||||
else this.ext = Context.clean(ext);
|
else this.ext = ext;
|
||||||
|
|
||||||
this.location = location;
|
this.location = location;
|
||||||
this.name = name;
|
this.name = name;
|
||||||
@ -44,13 +42,13 @@ public class EngineException extends RuntimeException {
|
|||||||
|
|
||||||
public final Object value;
|
public final Object value;
|
||||||
public EngineException cause;
|
public EngineException cause;
|
||||||
public Extensions ext = null;
|
public Environment env = null;
|
||||||
public final List<StackElement> stackTrace = new ArrayList<>();
|
public final List<StackElement> stackTrace = new ArrayList<>();
|
||||||
|
|
||||||
public EngineException add(Extensions ext, String name, Location location) {
|
public EngineException add(Environment env, String name, Location location) {
|
||||||
var el = new StackElement(ext, location, name);
|
var el = new StackElement(env, location, name);
|
||||||
if (el.name == null && el.location == null) return this;
|
if (el.name == null && el.location == null) return this;
|
||||||
setExtensions(ext);
|
setEnvironment(env);
|
||||||
stackTrace.add(el);
|
stackTrace.add(el);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
@ -58,12 +56,12 @@ public class EngineException extends RuntimeException {
|
|||||||
this.cause = cause;
|
this.cause = cause;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
public EngineException setExtensions(Extensions ext) {
|
public EngineException setEnvironment(Environment env) {
|
||||||
if (this.ext == null) this.ext = Context.clean(ext);
|
if (this.env == null) this.env = env;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String toString(Extensions ext) {
|
public String toString(Environment ext) {
|
||||||
var ss = new StringBuilder();
|
var ss = new StringBuilder();
|
||||||
try {
|
try {
|
||||||
ss.append(Values.toString(ext, value)).append('\n');
|
ss.append(Values.toString(ext, value)).append('\n');
|
||||||
|
@ -3,8 +3,8 @@ package me.topchetoeu.jscript.runtime.scope;
|
|||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import me.topchetoeu.jscript.runtime.Extensions;
|
import me.topchetoeu.jscript.runtime.environment.Environment;
|
||||||
import me.topchetoeu.jscript.runtime.Key;
|
import me.topchetoeu.jscript.runtime.environment.Key;
|
||||||
import me.topchetoeu.jscript.runtime.exceptions.EngineException;
|
import me.topchetoeu.jscript.runtime.exceptions.EngineException;
|
||||||
import me.topchetoeu.jscript.runtime.values.FunctionValue;
|
import me.topchetoeu.jscript.runtime.values.FunctionValue;
|
||||||
import me.topchetoeu.jscript.runtime.values.NativeFunction;
|
import me.topchetoeu.jscript.runtime.values.NativeFunction;
|
||||||
@ -16,7 +16,7 @@ public class GlobalScope {
|
|||||||
|
|
||||||
public final ObjectValue obj;
|
public final ObjectValue obj;
|
||||||
|
|
||||||
public boolean has(Extensions ext, String name) {
|
public boolean has(Environment ext, String name) {
|
||||||
return Values.hasMember(ext, obj, name, false);
|
return Values.hasMember(ext, obj, name, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -26,33 +26,33 @@ public class GlobalScope {
|
|||||||
return new GlobalScope(obj);
|
return new GlobalScope(obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Object define(Extensions ext, String name) {
|
public Object define(Environment ext, String name) {
|
||||||
if (Values.hasMember(ext, obj, name, false)) return name;
|
if (Values.hasMember(ext, obj, name, false)) return name;
|
||||||
obj.defineProperty(ext, name, null);
|
obj.defineProperty(ext, name, null);
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
public void define(Extensions ext, String name, Variable val) {
|
public void define(Environment ext, String name, Variable val) {
|
||||||
obj.defineProperty(ext, name,
|
obj.defineProperty(ext, name,
|
||||||
new NativeFunction("get " + name, args -> val.get(args.ctx)),
|
new NativeFunction("get " + name, args -> val.get(args.env)),
|
||||||
new NativeFunction("set " + name, args -> { val.set(args.ctx, args.get(0)); return null; }),
|
new NativeFunction("set " + name, args -> { val.set(args.env, args.get(0)); return null; }),
|
||||||
true, true
|
true, true
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
public void define(Extensions ext, String name, boolean readonly, Object val) {
|
public void define(Environment ext, String name, boolean readonly, Object val) {
|
||||||
obj.defineProperty(ext, name, val, readonly, true, true);
|
obj.defineProperty(ext, name, val, readonly, true, true);
|
||||||
}
|
}
|
||||||
public void define(Extensions ext, String ...names) {
|
public void define(Environment ext, String ...names) {
|
||||||
for (var n : names) define(ext, n);
|
for (var n : names) define(ext, n);
|
||||||
}
|
}
|
||||||
public void define(Extensions ext, boolean readonly, FunctionValue val) {
|
public void define(Environment ext, boolean readonly, FunctionValue val) {
|
||||||
define(ext, val.name, readonly, val);
|
define(ext, val.name, readonly, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Object get(Extensions ext, String name) {
|
public Object get(Environment ext, String name) {
|
||||||
if (!Values.hasMember(ext, obj, name, false)) throw EngineException.ofSyntax("The variable '" + name + "' doesn't exist.");
|
if (!Values.hasMember(ext, obj, name, false)) throw EngineException.ofSyntax("The variable '" + name + "' doesn't exist.");
|
||||||
else return Values.getMember(ext, obj, name);
|
else return Values.getMember(ext, obj, name);
|
||||||
}
|
}
|
||||||
public void set(Extensions ext, String name, Object val) {
|
public void set(Environment ext, String name, Object val) {
|
||||||
if (!Values.hasMember(ext, obj, name, false)) throw EngineException.ofSyntax("The variable '" + name + "' doesn't exist.");
|
if (!Values.hasMember(ext, obj, name, false)) throw EngineException.ofSyntax("The variable '" + name + "' doesn't exist.");
|
||||||
if (!Values.setMember(ext, obj, name, val)) throw EngineException.ofSyntax("The global '" + name + "' is readonly.");
|
if (!Values.setMember(ext, obj, name, val)) throw EngineException.ofSyntax("The global '" + name + "' is readonly.");
|
||||||
}
|
}
|
||||||
@ -74,7 +74,7 @@ public class GlobalScope {
|
|||||||
this.obj = val;
|
this.obj = val;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static GlobalScope get(Extensions ext) {
|
public static GlobalScope get(Environment ext) {
|
||||||
if (ext.has(KEY)) return ext.get(KEY);
|
if (ext.has(KEY)) return ext.get(KEY);
|
||||||
else return new GlobalScope();
|
else return new GlobalScope();
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
package me.topchetoeu.jscript.runtime.scope;
|
package me.topchetoeu.jscript.runtime.scope;
|
||||||
|
|
||||||
import me.topchetoeu.jscript.runtime.Extensions;
|
import me.topchetoeu.jscript.runtime.environment.Environment;
|
||||||
import me.topchetoeu.jscript.runtime.values.Values;
|
import me.topchetoeu.jscript.runtime.values.Values;
|
||||||
|
|
||||||
public class ValueVariable implements Variable {
|
public class ValueVariable implements Variable {
|
||||||
@ -11,12 +11,12 @@ public class ValueVariable implements Variable {
|
|||||||
public boolean readonly() { return readonly; }
|
public boolean readonly() { return readonly; }
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object get(Extensions ext) {
|
public Object get(Environment ext) {
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void set(Extensions ext, Object val) {
|
public void set(Environment ext, Object val) {
|
||||||
if (readonly) return;
|
if (readonly) return;
|
||||||
this.value = Values.normalize(ext, val);
|
this.value = Values.normalize(ext, val);
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
package me.topchetoeu.jscript.runtime.scope;
|
package me.topchetoeu.jscript.runtime.scope;
|
||||||
|
|
||||||
import me.topchetoeu.jscript.runtime.Extensions;
|
import me.topchetoeu.jscript.runtime.environment.Environment;
|
||||||
|
|
||||||
public interface Variable {
|
public interface Variable {
|
||||||
Object get(Extensions ext);
|
Object get(Environment ext);
|
||||||
default boolean readonly() { return true; }
|
default boolean readonly() { return true; }
|
||||||
default void set(Extensions ext, Object val) { }
|
default void set(Environment ext, Object val) { }
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,7 @@ import java.util.Comparator;
|
|||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import me.topchetoeu.jscript.runtime.Extensions;
|
import me.topchetoeu.jscript.runtime.environment.Environment;
|
||||||
|
|
||||||
// TODO: Make methods generic
|
// TODO: Make methods generic
|
||||||
public class ArrayValue extends ObjectValue implements Iterable<Object> {
|
public class ArrayValue extends ObjectValue implements Iterable<Object> {
|
||||||
@ -41,7 +41,7 @@ public class ArrayValue extends ObjectValue implements Iterable<Object> {
|
|||||||
if (res == UNDEFINED) return null;
|
if (res == UNDEFINED) return null;
|
||||||
else return res;
|
else return res;
|
||||||
}
|
}
|
||||||
public void set(Extensions ext, int i, Object val) {
|
public void set(Environment ext, int i, Object val) {
|
||||||
if (i < 0) return;
|
if (i < 0) return;
|
||||||
|
|
||||||
values = alloc(i);
|
values = alloc(i);
|
||||||
@ -99,7 +99,7 @@ public class ArrayValue extends ObjectValue implements Iterable<Object> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void copyFrom(Extensions ext, Object[] arr, int sourceStart, int destStart, int count) {
|
public void copyFrom(Environment ext, Object[] arr, int sourceStart, int destStart, int count) {
|
||||||
for (var i = 0; i < count; i++) {
|
for (var i = 0; i < count; i++) {
|
||||||
set(ext, i + destStart, arr[i + sourceStart]);
|
set(ext, i + destStart, arr[i + sourceStart]);
|
||||||
}
|
}
|
||||||
@ -131,7 +131,7 @@ public class ArrayValue extends ObjectValue implements Iterable<Object> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Object getField(Extensions ext, Object key) {
|
protected Object getField(Environment ext, Object key) {
|
||||||
if (key instanceof Number) {
|
if (key instanceof Number) {
|
||||||
var i = ((Number)key).doubleValue();
|
var i = ((Number)key).doubleValue();
|
||||||
if (i >= 0 && i - Math.floor(i) == 0) {
|
if (i >= 0 && i - Math.floor(i) == 0) {
|
||||||
@ -142,7 +142,7 @@ public class ArrayValue extends ObjectValue implements Iterable<Object> {
|
|||||||
return super.getField(ext, key);
|
return super.getField(ext, key);
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
protected boolean setField(Extensions ext, Object key, Object val) {
|
protected boolean setField(Environment ext, Object key, Object val) {
|
||||||
if (key instanceof Number) {
|
if (key instanceof Number) {
|
||||||
var i = Values.number(key);
|
var i = Values.number(key);
|
||||||
if (i >= 0 && i - Math.floor(i) == 0) {
|
if (i >= 0 && i - Math.floor(i) == 0) {
|
||||||
@ -154,7 +154,7 @@ public class ArrayValue extends ObjectValue implements Iterable<Object> {
|
|||||||
return super.setField(ext, key, val);
|
return super.setField(ext, key, val);
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
protected boolean hasField(Extensions ext, Object key) {
|
protected boolean hasField(Environment ext, Object key) {
|
||||||
if (key instanceof Number) {
|
if (key instanceof Number) {
|
||||||
var i = Values.number(key);
|
var i = Values.number(key);
|
||||||
if (i >= 0 && i - Math.floor(i) == 0) {
|
if (i >= 0 && i - Math.floor(i) == 0) {
|
||||||
@ -165,7 +165,7 @@ public class ArrayValue extends ObjectValue implements Iterable<Object> {
|
|||||||
return super.hasField(ext, key);
|
return super.hasField(ext, key);
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
protected void deleteField(Extensions ext, Object key) {
|
protected void deleteField(Environment ext, Object key) {
|
||||||
if (key instanceof Number) {
|
if (key instanceof Number) {
|
||||||
var i = Values.number(key);
|
var i = Values.number(key);
|
||||||
if (i >= 0 && i - Math.floor(i) == 0) {
|
if (i >= 0 && i - Math.floor(i) == 0) {
|
||||||
@ -213,7 +213,7 @@ public class ArrayValue extends ObjectValue implements Iterable<Object> {
|
|||||||
values = new Object[cap];
|
values = new Object[cap];
|
||||||
size = 0;
|
size = 0;
|
||||||
}
|
}
|
||||||
public ArrayValue(Extensions ext, Object ...values) {
|
public ArrayValue(Environment ext, Object ...values) {
|
||||||
this();
|
this();
|
||||||
this.values = new Object[values.length];
|
this.values = new Object[values.length];
|
||||||
size = values.length;
|
size = values.length;
|
||||||
@ -221,7 +221,7 @@ public class ArrayValue extends ObjectValue implements Iterable<Object> {
|
|||||||
for (var i = 0; i < size; i++) this.values[i] = Values.normalize(ext, values[i]);
|
for (var i = 0; i < size; i++) this.values[i] = Values.normalize(ext, values[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ArrayValue of(Extensions ext, Collection<?> values) {
|
public static ArrayValue of(Environment ext, Collection<?> values) {
|
||||||
return new ArrayValue(ext, values.toArray(Object[]::new));
|
return new ArrayValue(ext, values.toArray(Object[]::new));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,15 +1,14 @@
|
|||||||
package me.topchetoeu.jscript.runtime.values;
|
package me.topchetoeu.jscript.runtime.values;
|
||||||
|
|
||||||
import me.topchetoeu.jscript.common.FunctionBody;
|
import me.topchetoeu.jscript.common.FunctionBody;
|
||||||
import me.topchetoeu.jscript.runtime.Context;
|
|
||||||
import me.topchetoeu.jscript.runtime.Extensions;
|
|
||||||
import me.topchetoeu.jscript.runtime.Frame;
|
import me.topchetoeu.jscript.runtime.Frame;
|
||||||
|
import me.topchetoeu.jscript.runtime.environment.Environment;
|
||||||
import me.topchetoeu.jscript.runtime.scope.ValueVariable;
|
import me.topchetoeu.jscript.runtime.scope.ValueVariable;
|
||||||
|
|
||||||
public class CodeFunction extends FunctionValue {
|
public class CodeFunction extends FunctionValue {
|
||||||
public final FunctionBody body;
|
public final FunctionBody body;
|
||||||
public final ValueVariable[] captures;
|
public final ValueVariable[] captures;
|
||||||
public Extensions extensions;
|
public Environment env;
|
||||||
|
|
||||||
// public Location loc() {
|
// public Location loc() {
|
||||||
// for (var instr : body.instructions) {
|
// for (var instr : body.instructions) {
|
||||||
@ -24,15 +23,13 @@ public class CodeFunction extends FunctionValue {
|
|||||||
// else return name + "@" + loc;
|
// else return name + "@" + loc;
|
||||||
// }
|
// }
|
||||||
|
|
||||||
@Override
|
@Override public Object call(Environment env, Object thisArg, Object ...args) {
|
||||||
public Object call(Extensions ext, Object thisArg, Object ...args) {
|
var frame = new Frame(env, thisArg, args, this);
|
||||||
var frame = new Frame(Context.of(ext), thisArg, args, this);
|
|
||||||
|
|
||||||
frame.onPush();
|
frame.onPush();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
while (true) {
|
while (true) {
|
||||||
var res = frame.next(Values.NO_RETURN, Values.NO_RETURN, null);
|
var res = frame.next();
|
||||||
if (res != Values.NO_RETURN) return res;
|
if (res != Values.NO_RETURN) return res;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -41,10 +38,10 @@ public class CodeFunction extends FunctionValue {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public CodeFunction(Extensions extensions, String name, FunctionBody body, ValueVariable[] captures) {
|
public CodeFunction(Environment env, String name, FunctionBody body, ValueVariable[] captures) {
|
||||||
super(name, body.argsN);
|
super(name, body.argsN);
|
||||||
this.captures = captures;
|
this.captures = captures;
|
||||||
this.extensions = Context.clean(extensions);
|
this.env = env;
|
||||||
this.body = body;
|
this.body = body;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@ package me.topchetoeu.jscript.runtime.values;
|
|||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import me.topchetoeu.jscript.runtime.Extensions;
|
import me.topchetoeu.jscript.runtime.environment.Environment;
|
||||||
|
|
||||||
public abstract class FunctionValue extends ObjectValue {
|
public abstract class FunctionValue extends ObjectValue {
|
||||||
public String name = "";
|
public String name = "";
|
||||||
@ -13,26 +13,26 @@ public abstract class FunctionValue extends ObjectValue {
|
|||||||
return String.format("function %s(...)", name);
|
return String.format("function %s(...)", name);
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract Object call(Extensions ext, Object thisArg, Object ...args);
|
public abstract Object call(Environment ext, Object thisArg, Object ...args);
|
||||||
public Object call(Extensions ext) {
|
public Object call(Environment ext) {
|
||||||
return call(ext, null);
|
return call(ext, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Object getField(Extensions ext, Object key) {
|
protected Object getField(Environment ext, Object key) {
|
||||||
if ("name".equals(key)) return name;
|
if ("name".equals(key)) return name;
|
||||||
if ("length".equals(key)) return length;
|
if ("length".equals(key)) return length;
|
||||||
return super.getField(ext, key);
|
return super.getField(ext, key);
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
protected boolean setField(Extensions ext, Object key, Object val) {
|
protected boolean setField(Environment ext, Object key, Object val) {
|
||||||
if ("name".equals(key)) name = Values.toString(ext, val);
|
if ("name".equals(key)) name = Values.toString(ext, val);
|
||||||
else if ("length".equals(key)) length = (int)Values.toNumber(ext, val);
|
else if ("length".equals(key)) length = (int)Values.toNumber(ext, val);
|
||||||
else return super.setField(ext, key, val);
|
else return super.setField(ext, key, val);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
protected boolean hasField(Extensions ext, Object key) {
|
protected boolean hasField(Environment ext, Object key) {
|
||||||
if ("name".equals(key)) return true;
|
if ("name".equals(key)) return true;
|
||||||
if ("length".equals(key)) return true;
|
if ("length".equals(key)) return true;
|
||||||
return super.hasField(ext, key);
|
return super.hasField(ext, key);
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
package me.topchetoeu.jscript.runtime.values;
|
package me.topchetoeu.jscript.runtime.values;
|
||||||
|
|
||||||
import me.topchetoeu.jscript.runtime.Context;
|
import me.topchetoeu.jscript.runtime.environment.Environment;
|
||||||
import me.topchetoeu.jscript.runtime.Extensions;
|
|
||||||
import me.topchetoeu.jscript.utils.interop.Arguments;
|
import me.topchetoeu.jscript.utils.interop.Arguments;
|
||||||
|
|
||||||
public class NativeFunction extends FunctionValue {
|
public class NativeFunction extends FunctionValue {
|
||||||
@ -12,8 +11,8 @@ public class NativeFunction extends FunctionValue {
|
|||||||
public final NativeFunctionRunner action;
|
public final NativeFunctionRunner action;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object call(Extensions ext, Object thisArg, Object ...args) {
|
public Object call(Environment env, Object thisArg, Object ...args) {
|
||||||
return action.run(new Arguments(Context.of(ext), thisArg, args));
|
return action.run(new Arguments(env, thisArg, args));
|
||||||
}
|
}
|
||||||
|
|
||||||
public NativeFunction(String name, NativeFunctionRunner action) {
|
public NativeFunction(String name, NativeFunctionRunner action) {
|
||||||
|
@ -2,8 +2,8 @@ package me.topchetoeu.jscript.runtime.values;
|
|||||||
|
|
||||||
import java.util.WeakHashMap;
|
import java.util.WeakHashMap;
|
||||||
|
|
||||||
import me.topchetoeu.jscript.runtime.Extensions;
|
import me.topchetoeu.jscript.runtime.environment.Environment;
|
||||||
import me.topchetoeu.jscript.runtime.Key;
|
import me.topchetoeu.jscript.runtime.environment.Key;
|
||||||
import me.topchetoeu.jscript.utils.interop.NativeWrapperProvider;
|
import me.topchetoeu.jscript.utils.interop.NativeWrapperProvider;
|
||||||
|
|
||||||
public class NativeWrapper extends ObjectValue {
|
public class NativeWrapper extends ObjectValue {
|
||||||
@ -28,12 +28,12 @@ public class NativeWrapper extends ObjectValue {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final Key<WeakHashMap<MapKey, NativeWrapper>> WRAPPERS = new Key<>();
|
private static final Key<WeakHashMap<MapKey, NativeWrapper>> WRAPPER_MAP = new Key<>();
|
||||||
private static final Object NATIVE_PROTO = new Object();
|
private static final Object NATIVE_PROTO = new Object();
|
||||||
public final Object wrapped;
|
public final Object wrapped;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ObjectValue getPrototype(Extensions ext) {
|
public ObjectValue getPrototype(Environment ext) {
|
||||||
if (ext != null && prototype == NATIVE_PROTO) {
|
if (ext != null && prototype == NATIVE_PROTO) {
|
||||||
var clazz = wrapped.getClass();
|
var clazz = wrapped.getClass();
|
||||||
var res = NativeWrapperProvider.get(ext).getProto(clazz);
|
var res = NativeWrapperProvider.get(ext).getProto(clazz);
|
||||||
@ -60,17 +60,13 @@ public class NativeWrapper extends ObjectValue {
|
|||||||
prototype = NATIVE_PROTO;
|
prototype = NATIVE_PROTO;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static NativeWrapper of(Extensions exts, Object wrapped) {
|
public static NativeWrapper of(Environment env, Object wrapped) {
|
||||||
if (exts == null) return new NativeWrapper(wrapped);
|
if (env == null) return new NativeWrapper(wrapped);
|
||||||
var wrappers = exts.get(WRAPPERS);
|
|
||||||
|
|
||||||
if (wrappers == null) {
|
var wrappers = env.get(WRAPPER_MAP);
|
||||||
wrappers = new WeakHashMap<>();
|
if (wrappers == null) return new NativeWrapper(wrapped);
|
||||||
exts.add(WRAPPERS, wrappers);
|
|
||||||
}
|
|
||||||
|
|
||||||
var key = new MapKey(wrapped);
|
var key = new MapKey(wrapped);
|
||||||
|
|
||||||
if (wrappers.containsKey(key)) return wrappers.get(key);
|
if (wrappers.containsKey(key)) return wrappers.get(key);
|
||||||
|
|
||||||
var res = new NativeWrapper(wrapped);
|
var res = new NativeWrapper(wrapped);
|
||||||
|
@ -6,8 +6,7 @@ import java.util.LinkedHashSet;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import me.topchetoeu.jscript.runtime.Environment;
|
import me.topchetoeu.jscript.runtime.environment.Environment;
|
||||||
import me.topchetoeu.jscript.runtime.Extensions;
|
|
||||||
|
|
||||||
public class ObjectValue {
|
public class ObjectValue {
|
||||||
public static enum PlaceholderProto {
|
public static enum PlaceholderProto {
|
||||||
@ -54,10 +53,10 @@ public class ObjectValue {
|
|||||||
public LinkedHashSet<Object> nonConfigurableSet = new LinkedHashSet<>();
|
public LinkedHashSet<Object> nonConfigurableSet = new LinkedHashSet<>();
|
||||||
public LinkedHashSet<Object> nonEnumerableSet = new LinkedHashSet<>();
|
public LinkedHashSet<Object> nonEnumerableSet = new LinkedHashSet<>();
|
||||||
|
|
||||||
private Property getProperty(Extensions ext, Object key) {
|
private Property getProperty(Environment env, Object key) {
|
||||||
if (properties.containsKey(key)) return properties.get(key);
|
if (properties.containsKey(key)) return properties.get(key);
|
||||||
var proto = getPrototype(ext);
|
var proto = getPrototype(env);
|
||||||
if (proto != null) return proto.getProperty(ext, key);
|
if (proto != null) return proto.getProperty(env, key);
|
||||||
else return null;
|
else return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -86,8 +85,8 @@ public class ObjectValue {
|
|||||||
state = State.FROZEN;
|
state = State.FROZEN;
|
||||||
}
|
}
|
||||||
|
|
||||||
public final boolean defineProperty(Extensions ext, Object key, Object val, boolean writable, boolean configurable, boolean enumerable) {
|
public final boolean defineProperty(Environment env, Object key, Object val, boolean writable, boolean configurable, boolean enumerable) {
|
||||||
key = Values.normalize(ext, key); val = Values.normalize(ext, val);
|
key = Values.normalize(env, key); val = Values.normalize(env, val);
|
||||||
boolean reconfigured =
|
boolean reconfigured =
|
||||||
writable != memberWritable(key) ||
|
writable != memberWritable(key) ||
|
||||||
configurable != memberConfigurable(key) ||
|
configurable != memberConfigurable(key) ||
|
||||||
@ -125,11 +124,11 @@ public class ObjectValue {
|
|||||||
values.put(key, val);
|
values.put(key, val);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
public final boolean defineProperty(Extensions ext, Object key, Object val) {
|
public final boolean defineProperty(Environment env, Object key, Object val) {
|
||||||
return defineProperty(ext, key, val, true, true, true);
|
return defineProperty(env, key, val, true, true, true);
|
||||||
}
|
}
|
||||||
public final boolean defineProperty(Extensions ext, Object key, FunctionValue getter, FunctionValue setter, boolean configurable, boolean enumerable) {
|
public final boolean defineProperty(Environment env, Object key, FunctionValue getter, FunctionValue setter, boolean configurable, boolean enumerable) {
|
||||||
key = Values.normalize(ext, key);
|
key = Values.normalize(env, key);
|
||||||
if (
|
if (
|
||||||
properties.containsKey(key) &&
|
properties.containsKey(key) &&
|
||||||
properties.get(key).getter == getter &&
|
properties.get(key).getter == getter &&
|
||||||
@ -152,17 +151,17 @@ public class ObjectValue {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ObjectValue getPrototype(Extensions ext) {
|
public ObjectValue getPrototype(Environment env) {
|
||||||
if (prototype instanceof ObjectValue || prototype == null) return (ObjectValue)prototype;
|
if (prototype instanceof ObjectValue || prototype == null) return (ObjectValue)prototype;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (prototype == ARR_PROTO) return ext.get(Environment.ARRAY_PROTO);
|
if (prototype == ARR_PROTO) return env.get(Environment.ARRAY_PROTO);
|
||||||
if (prototype == FUNC_PROTO) return ext.get(Environment.FUNCTION_PROTO);
|
if (prototype == FUNC_PROTO) return env.get(Environment.FUNCTION_PROTO);
|
||||||
if (prototype == ERR_PROTO) return ext.get(Environment.ERROR_PROTO);
|
if (prototype == ERR_PROTO) return env.get(Environment.ERROR_PROTO);
|
||||||
if (prototype == RANGE_ERR_PROTO) return ext.get(Environment.RANGE_ERR_PROTO);
|
if (prototype == RANGE_ERR_PROTO) return env.get(Environment.RANGE_ERR_PROTO);
|
||||||
if (prototype == SYNTAX_ERR_PROTO) return ext.get(Environment.SYNTAX_ERR_PROTO);
|
if (prototype == SYNTAX_ERR_PROTO) return env.get(Environment.SYNTAX_ERR_PROTO);
|
||||||
if (prototype == TYPE_ERR_PROTO) return ext.get(Environment.TYPE_ERR_PROTO);
|
if (prototype == TYPE_ERR_PROTO) return env.get(Environment.TYPE_ERR_PROTO);
|
||||||
return ext.get(Environment.OBJECT_PROTO);
|
return env.get(Environment.OBJECT_PROTO);
|
||||||
}
|
}
|
||||||
catch (NullPointerException e) { return null; }
|
catch (NullPointerException e) { return null; }
|
||||||
}
|
}
|
||||||
@ -185,10 +184,10 @@ public class ObjectValue {
|
|||||||
* A method, used to get the value of a field. If a property is bound to
|
* A method, used to get the value of a field. If a property is bound to
|
||||||
* this key, but not a field, this method should return null.
|
* this key, but not a field, this method should return null.
|
||||||
*/
|
*/
|
||||||
protected Object getField(Extensions ext, Object key) {
|
protected Object getField(Environment env, Object key) {
|
||||||
if (values.containsKey(key)) return values.get(key);
|
if (values.containsKey(key)) return values.get(key);
|
||||||
var proto = getPrototype(ext);
|
var proto = getPrototype(env);
|
||||||
if (proto != null) return proto.getField(ext, key);
|
if (proto != null) return proto.getField(env, key);
|
||||||
else return null;
|
else return null;
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
@ -196,9 +195,9 @@ public class ObjectValue {
|
|||||||
* bound to this key, a new field should be created with the given value
|
* bound to this key, a new field should be created with the given value
|
||||||
* @return Whether or not the operation was successful
|
* @return Whether or not the operation was successful
|
||||||
*/
|
*/
|
||||||
protected boolean setField(Extensions ext, Object key, Object val) {
|
protected boolean setField(Environment env, Object key, Object val) {
|
||||||
if (val instanceof FunctionValue && ((FunctionValue)val).name.equals("")) {
|
if (val instanceof FunctionValue && ((FunctionValue)val).name.equals("")) {
|
||||||
((FunctionValue)val).name = Values.toString(ext, key);
|
((FunctionValue)val).name = Values.toString(env, key);
|
||||||
}
|
}
|
||||||
|
|
||||||
values.put(key, val);
|
values.put(key, val);
|
||||||
@ -207,40 +206,40 @@ public class ObjectValue {
|
|||||||
/**
|
/**
|
||||||
* Deletes the field bound to the given key.
|
* Deletes the field bound to the given key.
|
||||||
*/
|
*/
|
||||||
protected void deleteField(Extensions ext, Object key) {
|
protected void deleteField(Environment env, Object key) {
|
||||||
values.remove(key);
|
values.remove(key);
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Returns whether or not there is a field bound to the given key.
|
* Returns whether or not there is a field bound to the given key.
|
||||||
* This must ignore properties
|
* This must ignore properties
|
||||||
*/
|
*/
|
||||||
protected boolean hasField(Extensions ext, Object key) {
|
protected boolean hasField(Environment env, Object key) {
|
||||||
return values.containsKey(key);
|
return values.containsKey(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
public final Object getMember(Extensions ext, Object key, Object thisArg) {
|
public final Object getMember(Environment env, Object key, Object thisArg) {
|
||||||
key = Values.normalize(ext, key);
|
key = Values.normalize(env, key);
|
||||||
|
|
||||||
if ("__proto__".equals(key)) {
|
if ("__proto__".equals(key)) {
|
||||||
var res = getPrototype(ext);
|
var res = getPrototype(env);
|
||||||
return res == null ? Values.NULL : res;
|
return res == null ? Values.NULL : res;
|
||||||
}
|
}
|
||||||
|
|
||||||
var prop = getProperty(ext, key);
|
var prop = getProperty(env, key);
|
||||||
|
|
||||||
if (prop != null) {
|
if (prop != null) {
|
||||||
if (prop.getter == null) return null;
|
if (prop.getter == null) return null;
|
||||||
else return prop.getter.call(ext, Values.normalize(ext, thisArg));
|
else return prop.getter.call(env, Values.normalize(env, thisArg));
|
||||||
}
|
}
|
||||||
else return getField(ext, key);
|
else return getField(env, key);
|
||||||
}
|
}
|
||||||
public final boolean setMember(Extensions ext, Object key, Object val, Object thisArg, boolean onlyProps) {
|
public final boolean setMember(Environment env, Object key, Object val, Object thisArg, boolean onlyProps) {
|
||||||
key = Values.normalize(ext, key); val = Values.normalize(ext, val);
|
key = Values.normalize(env, key); val = Values.normalize(env, val);
|
||||||
|
|
||||||
var prop = getProperty(ext, key);
|
var prop = getProperty(env, key);
|
||||||
if (prop != null) {
|
if (prop != null) {
|
||||||
if (prop.setter == null) return false;
|
if (prop.setter == null) return false;
|
||||||
prop.setter.call(ext, Values.normalize(ext, thisArg), val);
|
prop.setter.call(env, Values.normalize(env, thisArg), val);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else if (onlyProps) return false;
|
else if (onlyProps) return false;
|
||||||
@ -249,32 +248,32 @@ public class ObjectValue {
|
|||||||
values.put(key, val);
|
values.put(key, val);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else if ("__proto__".equals(key)) return setPrototype(ext, val);
|
else if ("__proto__".equals(key)) return setPrototype(env, val);
|
||||||
else if (nonWritableSet.contains(key)) return false;
|
else if (nonWritableSet.contains(key)) return false;
|
||||||
else return setField(ext, key, val);
|
else return setField(env, key, val);
|
||||||
}
|
}
|
||||||
public final boolean hasMember(Extensions ext, Object key, boolean own) {
|
public final boolean hasMember(Environment env, Object key, boolean own) {
|
||||||
key = Values.normalize(ext, key);
|
key = Values.normalize(env, key);
|
||||||
|
|
||||||
if (key != null && "__proto__".equals(key)) return true;
|
if (key != null && "__proto__".equals(key)) return true;
|
||||||
if (hasField(ext, key)) return true;
|
if (hasField(env, key)) return true;
|
||||||
if (properties.containsKey(key)) return true;
|
if (properties.containsKey(key)) return true;
|
||||||
if (own) return false;
|
if (own) return false;
|
||||||
var proto = getPrototype(ext);
|
var proto = getPrototype(env);
|
||||||
return proto != null && proto.hasMember(ext, key, own);
|
return proto != null && proto.hasMember(env, key, own);
|
||||||
}
|
}
|
||||||
public final boolean deleteMember(Extensions ext, Object key) {
|
public final boolean deleteMember(Environment env, Object key) {
|
||||||
key = Values.normalize(ext, key);
|
key = Values.normalize(env, key);
|
||||||
|
|
||||||
if (!memberConfigurable(key)) return false;
|
if (!memberConfigurable(key)) return false;
|
||||||
properties.remove(key);
|
properties.remove(key);
|
||||||
nonWritableSet.remove(key);
|
nonWritableSet.remove(key);
|
||||||
nonEnumerableSet.remove(key);
|
nonEnumerableSet.remove(key);
|
||||||
deleteField(ext, key);
|
deleteField(env, key);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
public final boolean setPrototype(Extensions ext, Object val) {
|
public final boolean setPrototype(Environment env, Object val) {
|
||||||
val = Values.normalize(ext, val);
|
val = Values.normalize(env, val);
|
||||||
|
|
||||||
if (!extensible()) return false;
|
if (!extensible()) return false;
|
||||||
if (val == null || val == Values.NULL) {
|
if (val == null || val == Values.NULL) {
|
||||||
@ -284,14 +283,14 @@ public class ObjectValue {
|
|||||||
else if (val instanceof ObjectValue) {
|
else if (val instanceof ObjectValue) {
|
||||||
var obj = (ObjectValue)val;
|
var obj = (ObjectValue)val;
|
||||||
|
|
||||||
if (ext != null) {
|
if (env != null) {
|
||||||
if (obj == ext.get(Environment.OBJECT_PROTO)) prototype = OBJ_PROTO;
|
if (obj == env.get(Environment.OBJECT_PROTO)) prototype = OBJ_PROTO;
|
||||||
else if (obj == ext.get(Environment.ARRAY_PROTO)) prototype = ARR_PROTO;
|
else if (obj == env.get(Environment.ARRAY_PROTO)) prototype = ARR_PROTO;
|
||||||
else if (obj == ext.get(Environment.FUNCTION_PROTO)) prototype = FUNC_PROTO;
|
else if (obj == env.get(Environment.FUNCTION_PROTO)) prototype = FUNC_PROTO;
|
||||||
else if (obj == ext.get(Environment.ERROR_PROTO)) prototype = ERR_PROTO;
|
else if (obj == env.get(Environment.ERROR_PROTO)) prototype = ERR_PROTO;
|
||||||
else if (obj == ext.get(Environment.SYNTAX_ERR_PROTO)) prototype = SYNTAX_ERR_PROTO;
|
else if (obj == env.get(Environment.SYNTAX_ERR_PROTO)) prototype = SYNTAX_ERR_PROTO;
|
||||||
else if (obj == ext.get(Environment.TYPE_ERR_PROTO)) prototype = TYPE_ERR_PROTO;
|
else if (obj == env.get(Environment.TYPE_ERR_PROTO)) prototype = TYPE_ERR_PROTO;
|
||||||
else if (obj == ext.get(Environment.RANGE_ERR_PROTO)) prototype = RANGE_ERR_PROTO;
|
else if (obj == env.get(Environment.RANGE_ERR_PROTO)) prototype = RANGE_ERR_PROTO;
|
||||||
else prototype = obj;
|
else prototype = obj;
|
||||||
}
|
}
|
||||||
else prototype = obj;
|
else prototype = obj;
|
||||||
@ -301,22 +300,22 @@ public class ObjectValue {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public final ObjectValue getMemberDescriptor(Extensions ext, Object key) {
|
public final ObjectValue getMemberDescriptor(Environment env, Object key) {
|
||||||
key = Values.normalize(ext, key);
|
key = Values.normalize(env, key);
|
||||||
|
|
||||||
var prop = properties.get(key);
|
var prop = properties.get(key);
|
||||||
var res = new ObjectValue();
|
var res = new ObjectValue();
|
||||||
|
|
||||||
res.defineProperty(ext, "configurable", memberConfigurable(key));
|
res.defineProperty(env, "configurable", memberConfigurable(key));
|
||||||
res.defineProperty(ext, "enumerable", memberEnumerable(key));
|
res.defineProperty(env, "enumerable", memberEnumerable(key));
|
||||||
|
|
||||||
if (prop != null) {
|
if (prop != null) {
|
||||||
res.defineProperty(ext, "get", prop.getter);
|
res.defineProperty(env, "get", prop.getter);
|
||||||
res.defineProperty(ext, "set", prop.setter);
|
res.defineProperty(env, "set", prop.setter);
|
||||||
}
|
}
|
||||||
else if (hasField(ext, key)) {
|
else if (hasField(env, key)) {
|
||||||
res.defineProperty(ext, "value", values.get(key));
|
res.defineProperty(env, "value", values.get(key));
|
||||||
res.defineProperty(ext, "writable", memberWritable(key));
|
res.defineProperty(env, "writable", memberWritable(key));
|
||||||
}
|
}
|
||||||
else return null;
|
else return null;
|
||||||
return res;
|
return res;
|
||||||
@ -337,10 +336,10 @@ public class ObjectValue {
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ObjectValue(Extensions ext, Map<?, ?> values) {
|
public ObjectValue(Environment env, Map<?, ?> values) {
|
||||||
this(PlaceholderProto.OBJECT);
|
this(PlaceholderProto.OBJECT);
|
||||||
for (var el : values.entrySet()) {
|
for (var el : values.entrySet()) {
|
||||||
defineProperty(ext, el.getKey(), el.getValue());
|
defineProperty(env, el.getKey(), el.getValue());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public ObjectValue(PlaceholderProto proto) {
|
public ObjectValue(PlaceholderProto proto) {
|
||||||
|
@ -3,7 +3,7 @@ package me.topchetoeu.jscript.runtime.values;
|
|||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import me.topchetoeu.jscript.runtime.Extensions;
|
import me.topchetoeu.jscript.runtime.environment.Environment;
|
||||||
import me.topchetoeu.jscript.runtime.scope.ValueVariable;
|
import me.topchetoeu.jscript.runtime.scope.ValueVariable;
|
||||||
|
|
||||||
public class ScopeValue extends ObjectValue {
|
public class ScopeValue extends ObjectValue {
|
||||||
@ -11,12 +11,12 @@ public class ScopeValue extends ObjectValue {
|
|||||||
public final HashMap<String, Integer> names = new HashMap<>();
|
public final HashMap<String, Integer> names = new HashMap<>();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Object getField(Extensions ext, Object key) {
|
protected Object getField(Environment ext, Object key) {
|
||||||
if (names.containsKey(key)) return variables[names.get(key)].get(ext);
|
if (names.containsKey(key)) return variables[names.get(key)].get(ext);
|
||||||
return super.getField(ext, key);
|
return super.getField(ext, key);
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
protected boolean setField(Extensions ext, Object key, Object val) {
|
protected boolean setField(Environment ext, Object key, Object val) {
|
||||||
if (names.containsKey(key)) {
|
if (names.containsKey(key)) {
|
||||||
variables[names.get(key)].set(ext, val);
|
variables[names.get(key)].set(ext, val);
|
||||||
return true;
|
return true;
|
||||||
@ -28,12 +28,12 @@ public class ScopeValue extends ObjectValue {
|
|||||||
return super.setField(ext, key, val);
|
return super.setField(ext, key, val);
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
protected void deleteField(Extensions ext, Object key) {
|
protected void deleteField(Environment ext, Object key) {
|
||||||
if (names.containsKey(key)) return;
|
if (names.containsKey(key)) return;
|
||||||
super.deleteField(ext, key);
|
super.deleteField(ext, key);
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
protected boolean hasField(Extensions ext, Object key) {
|
protected boolean hasField(Environment ext, Object key) {
|
||||||
if (names.containsKey(key)) return true;
|
if (names.containsKey(key)) return true;
|
||||||
return super.hasField(ext, key);
|
return super.hasField(ext, key);
|
||||||
}
|
}
|
||||||
|
733
src/java/me/topchetoeu/jscript/runtime/values/Value.java
Normal file
733
src/java/me/topchetoeu/jscript/runtime/values/Value.java
Normal file
@ -0,0 +1,733 @@
|
|||||||
|
package me.topchetoeu.jscript.runtime.values;
|
||||||
|
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.PrintStream;
|
||||||
|
import java.lang.reflect.Array;
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import me.topchetoeu.jscript.common.Operation;
|
||||||
|
// import me.topchetoeu.jscript.lib.PromiseLib;
|
||||||
|
import me.topchetoeu.jscript.runtime.debug.DebugContext;
|
||||||
|
import me.topchetoeu.jscript.runtime.environment.Environment;
|
||||||
|
import me.topchetoeu.jscript.runtime.exceptions.ConvertException;
|
||||||
|
import me.topchetoeu.jscript.runtime.exceptions.EngineException;
|
||||||
|
import me.topchetoeu.jscript.runtime.exceptions.SyntaxException;
|
||||||
|
import me.topchetoeu.jscript.utils.interop.NativeWrapperProvider;
|
||||||
|
|
||||||
|
public interface Value {
|
||||||
|
public static enum CompareResult {
|
||||||
|
NOT_EQUAL,
|
||||||
|
EQUAL,
|
||||||
|
LESS,
|
||||||
|
GREATER;
|
||||||
|
|
||||||
|
public boolean less() { return this == LESS; }
|
||||||
|
public boolean greater() { return this == GREATER; }
|
||||||
|
public boolean lessOrEqual() { return this == LESS || this == EQUAL; }
|
||||||
|
public boolean greaterOrEqual() { return this == GREATER || this == EQUAL; }
|
||||||
|
|
||||||
|
public static CompareResult from(int cmp) {
|
||||||
|
if (cmp < 0) return LESS;
|
||||||
|
if (cmp > 0) return GREATER;
|
||||||
|
return EQUAL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final Object NULL = new Object();
|
||||||
|
public static final Object NO_RETURN = new Object();
|
||||||
|
|
||||||
|
public static double number(Object val) {
|
||||||
|
if (val instanceof Number) return ((Number)val).doubleValue();
|
||||||
|
else return Double.NaN;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public static <T> T wrapper(Object val, Class<T> clazz) {
|
||||||
|
if (isWrapper(val)) val = ((NativeWrapper)val).wrapped;
|
||||||
|
if (val != null && clazz.isInstance(val)) return (T)val;
|
||||||
|
else return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String type(Object val) {
|
||||||
|
if (val == null) return "undefined";
|
||||||
|
if (val instanceof String) return "string";
|
||||||
|
if (val instanceof Number) return "number";
|
||||||
|
if (val instanceof Boolean) return "boolean";
|
||||||
|
if (val instanceof Symbol) return "symbol";
|
||||||
|
if (val instanceof FunctionValue) return "function";
|
||||||
|
return "object";
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isPrimitive();
|
||||||
|
public BooleanValue toBoolean();
|
||||||
|
|
||||||
|
public default Value call(Environment env, Value self, Value ...args) {
|
||||||
|
throw EngineException.ofType("Tried to call a non-function value.");
|
||||||
|
}
|
||||||
|
public default Value callNew(Environment env, Value ...args) {
|
||||||
|
var res = new ObjectValue();
|
||||||
|
|
||||||
|
try {
|
||||||
|
var proto = Values.getMember(env, this, "prototype");
|
||||||
|
setPrototype(env, res, proto);
|
||||||
|
|
||||||
|
var ret = this.call(env, res, args);
|
||||||
|
|
||||||
|
if (!ret.isPrimitive()) return ret;
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
catch (IllegalArgumentException e) {
|
||||||
|
throw EngineException.ofType("Tried to call new on an invalid constructor.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public default Value toPrimitive(Environment env, Value val) {
|
||||||
|
if (val.isPrimitive()) return val;
|
||||||
|
|
||||||
|
if (env != null) {
|
||||||
|
var valueOf = getMember(env, val, "valueOf");
|
||||||
|
|
||||||
|
if (valueOf instanceof FunctionValue) {
|
||||||
|
var res = valueOf.call(env, val);
|
||||||
|
if (res.isPrimitive()) return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
var toString = getMember(env, val, "toString");
|
||||||
|
if (toString instanceof FunctionValue) {
|
||||||
|
var res = toString.call(env, val);
|
||||||
|
if (res.isPrimitive()) return res;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw EngineException.ofType("Value couldn't be converted to a primitive.");
|
||||||
|
}
|
||||||
|
public default NumberValue toNumber(Environment ext, Object obj) {
|
||||||
|
var val = this.toPrimitive(ext, obj, ConvertHint.VALUEOF);
|
||||||
|
|
||||||
|
if (val instanceof NumberValue) return number(val);
|
||||||
|
if (val instanceof Boolean) return ((Boolean)val) ? 1 : 0;
|
||||||
|
if (val instanceof String) {
|
||||||
|
try { return Double.parseDouble((String)val); }
|
||||||
|
catch (NumberFormatException e) { return Double.NaN; }
|
||||||
|
}
|
||||||
|
return Double.NaN;
|
||||||
|
}
|
||||||
|
public default StringValue toString(Environment ext, Object obj) {
|
||||||
|
var val = toPrimitive(ext, obj, ConvertHint.VALUEOF);
|
||||||
|
|
||||||
|
if (val == null) return "undefined";
|
||||||
|
if (val == NULL) return "null";
|
||||||
|
|
||||||
|
if (val instanceof Number) {
|
||||||
|
var d = number(val);
|
||||||
|
if (d == Double.NEGATIVE_INFINITY) return "-Infinity";
|
||||||
|
if (d == Double.POSITIVE_INFINITY) return "Infinity";
|
||||||
|
if (Double.isNaN(d)) return "NaN";
|
||||||
|
return BigDecimal.valueOf(d).stripTrailingZeros().toPlainString();
|
||||||
|
}
|
||||||
|
if (val instanceof Boolean) return (Boolean)val ? "true" : "false";
|
||||||
|
if (val instanceof String) return (String)val;
|
||||||
|
if (val instanceof Symbol) return val.toString();
|
||||||
|
|
||||||
|
return "Unknown value";
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Object add(Environment ext, Object a, Object b) {
|
||||||
|
if (a instanceof String || b instanceof String) return toString(ext, a) + toString(ext, b);
|
||||||
|
else return toNumber(ext, a) + toNumber(ext, b);
|
||||||
|
}
|
||||||
|
public static double subtract(Environment ext, Object a, Object b) {
|
||||||
|
return toNumber(ext, a) - toNumber(ext, b);
|
||||||
|
}
|
||||||
|
public static double multiply(Environment ext, Object a, Object b) {
|
||||||
|
return toNumber(ext, a) * toNumber(ext, b);
|
||||||
|
}
|
||||||
|
public static double divide(Environment ext, Object a, Object b) {
|
||||||
|
return toNumber(ext, a) / toNumber(ext, b);
|
||||||
|
}
|
||||||
|
public static double modulo(Environment ext, Object a, Object b) {
|
||||||
|
return toNumber(ext, a) % toNumber(ext, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static double negative(Environment ext, Object obj) {
|
||||||
|
return -toNumber(ext, obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int and(Environment ext, Object a, Object b) {
|
||||||
|
return (int)toNumber(ext, a) & (int)toNumber(ext, b);
|
||||||
|
}
|
||||||
|
public static int or(Environment ext, Object a, Object b) {
|
||||||
|
return (int)toNumber(ext, a) | (int)toNumber(ext, b);
|
||||||
|
}
|
||||||
|
public static int xor(Environment ext, Object a, Object b) {
|
||||||
|
return (int)toNumber(ext, a) ^ (int)toNumber(ext, b);
|
||||||
|
}
|
||||||
|
public static int bitwiseNot(Environment ext, Object obj) {
|
||||||
|
return ~(int)toNumber(ext, obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int shiftLeft(Environment ext, Object a, Object b) {
|
||||||
|
return (int)toNumber(ext, a) << (int)toNumber(ext, b);
|
||||||
|
}
|
||||||
|
public static int shiftRight(Environment ext, Object a, Object b) {
|
||||||
|
return (int)toNumber(ext, a) >> (int)toNumber(ext, b);
|
||||||
|
}
|
||||||
|
public static long unsignedShiftRight(Environment ext, Object a, Object b) {
|
||||||
|
long _a = (long)toNumber(ext, a);
|
||||||
|
long _b = (long)toNumber(ext, b);
|
||||||
|
|
||||||
|
if (_a < 0) _a += 0x100000000l;
|
||||||
|
if (_b < 0) _b += 0x100000000l;
|
||||||
|
return _a >>> _b;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static CompareResult compare(Environment ext, Object a, Object b) {
|
||||||
|
a = toPrimitive(ext, a, ConvertHint.VALUEOF);
|
||||||
|
b = toPrimitive(ext, b, ConvertHint.VALUEOF);
|
||||||
|
|
||||||
|
if (a instanceof String && b instanceof String) CompareResult.from(((String)a).compareTo((String)b));
|
||||||
|
|
||||||
|
var _a = toNumber(ext, a);
|
||||||
|
var _b = toNumber(ext, b);
|
||||||
|
|
||||||
|
if (Double.isNaN(_a) || Double.isNaN(_b)) return CompareResult.NOT_EQUAL;
|
||||||
|
|
||||||
|
return CompareResult.from(Double.compare(_a, _b));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean not(Object obj) {
|
||||||
|
return !toBoolean(obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isInstanceOf(Environment ext, Object obj, Object proto) {
|
||||||
|
if (obj == null || obj == NULL || proto == null || proto == NULL) return false;
|
||||||
|
var val = getPrototype(ext, obj);
|
||||||
|
|
||||||
|
while (val != null) {
|
||||||
|
if (val.equals(proto)) return true;
|
||||||
|
val = val.getPrototype(ext);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Object operation(Environment ext, Operation op, Object ...args) {
|
||||||
|
switch (op) {
|
||||||
|
case ADD: return add(ext, args[0], args[1]);
|
||||||
|
case SUBTRACT: return subtract(ext, args[0], args[1]);
|
||||||
|
case DIVIDE: return divide(ext, args[0], args[1]);
|
||||||
|
case MULTIPLY: return multiply(ext, args[0], args[1]);
|
||||||
|
case MODULO: return modulo(ext, args[0], args[1]);
|
||||||
|
|
||||||
|
case AND: return and(ext, args[0], args[1]);
|
||||||
|
case OR: return or(ext, args[0], args[1]);
|
||||||
|
case XOR: return xor(ext, args[0], args[1]);
|
||||||
|
|
||||||
|
case EQUALS: return strictEquals(ext, args[0], args[1]);
|
||||||
|
case NOT_EQUALS: return !strictEquals(ext, args[0], args[1]);
|
||||||
|
case LOOSE_EQUALS: return looseEqual(ext, args[0], args[1]);
|
||||||
|
case LOOSE_NOT_EQUALS: return !looseEqual(ext, args[0], args[1]);
|
||||||
|
|
||||||
|
case GREATER: return compare(ext, args[0], args[1]).greater();
|
||||||
|
case GREATER_EQUALS: return compare(ext, args[0], args[1]).greaterOrEqual();
|
||||||
|
case LESS: return compare(ext, args[0], args[1]).less();
|
||||||
|
case LESS_EQUALS: return compare(ext, args[0], args[1]).lessOrEqual();
|
||||||
|
|
||||||
|
case INVERSE: return bitwiseNot(ext, args[0]);
|
||||||
|
case NOT: return not(args[0]);
|
||||||
|
case POS: return toNumber(ext, args[0]);
|
||||||
|
case NEG: return negative(ext, args[0]);
|
||||||
|
|
||||||
|
case SHIFT_LEFT: return shiftLeft(ext, args[0], args[1]);
|
||||||
|
case SHIFT_RIGHT: return shiftRight(ext, args[0], args[1]);
|
||||||
|
case USHIFT_RIGHT: return unsignedShiftRight(ext, args[0], args[1]);
|
||||||
|
|
||||||
|
case IN: return hasMember(ext, args[1], args[0], false);
|
||||||
|
case INSTANCEOF: {
|
||||||
|
var proto = getMember(ext, args[1], "prototype");
|
||||||
|
return isInstanceOf(ext, args[0], proto);
|
||||||
|
}
|
||||||
|
|
||||||
|
default: return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Object getMember(Environment ctx, Object obj, Object key) {
|
||||||
|
obj = normalize(ctx, obj); key = normalize(ctx, key);
|
||||||
|
if (obj == null) throw new IllegalArgumentException("Tried to access member of undefined.");
|
||||||
|
if (obj == NULL) throw new IllegalArgumentException("Tried to access member of null.");
|
||||||
|
if (obj instanceof ObjectValue) return ((ObjectValue)obj).getMember(ctx, key, obj);
|
||||||
|
|
||||||
|
if (obj instanceof String && key instanceof Number) {
|
||||||
|
var i = number(key);
|
||||||
|
var s = (String)obj;
|
||||||
|
if (i >= 0 && i < s.length() && i - Math.floor(i) == 0) {
|
||||||
|
return s.charAt((int)i) + "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var proto = getPrototype(ctx, obj);
|
||||||
|
|
||||||
|
if (proto == null) return "__proto__".equals(key) ? NULL : null;
|
||||||
|
else if (key != null && "__proto__".equals(key)) return proto;
|
||||||
|
else return proto.getMember(ctx, key, obj);
|
||||||
|
}
|
||||||
|
public static Object getMemberPath(Environment ctx, Object obj, Object ...path) {
|
||||||
|
var res = obj;
|
||||||
|
for (var key : path) res = getMember(ctx, res, key);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
public static boolean setMember(Environment ctx, Object obj, Object key, Object val) {
|
||||||
|
obj = normalize(ctx, obj); key = normalize(ctx, key); val = normalize(ctx, val);
|
||||||
|
if (obj == null) throw EngineException.ofType("Tried to access member of undefined.");
|
||||||
|
if (obj == NULL) throw EngineException.ofType("Tried to access member of null.");
|
||||||
|
if (key != null && "__proto__".equals(key)) return setPrototype(ctx, obj, val);
|
||||||
|
if (obj instanceof ObjectValue) return ((ObjectValue)obj).setMember(ctx, key, val, obj, false);
|
||||||
|
|
||||||
|
var proto = getPrototype(ctx, obj);
|
||||||
|
return proto.setMember(ctx, key, val, obj, true);
|
||||||
|
}
|
||||||
|
public static boolean hasMember(Environment ctx, Object obj, Object key, boolean own) {
|
||||||
|
if (obj == null || obj == NULL) return false;
|
||||||
|
obj = normalize(ctx, obj); key = normalize(ctx, key);
|
||||||
|
|
||||||
|
if ("__proto__".equals(key)) return true;
|
||||||
|
if (obj instanceof ObjectValue) return ((ObjectValue)obj).hasMember(ctx, key, own);
|
||||||
|
|
||||||
|
if (obj instanceof String && key instanceof Number) {
|
||||||
|
var i = number(key);
|
||||||
|
var s = (String)obj;
|
||||||
|
if (i >= 0 && i < s.length() && i - Math.floor(i) == 0) return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (own) return false;
|
||||||
|
|
||||||
|
var proto = getPrototype(ctx, obj);
|
||||||
|
return proto != null && proto.hasMember(ctx, key, own);
|
||||||
|
}
|
||||||
|
public static boolean deleteMember(Environment ext, Object obj, Object key) {
|
||||||
|
if (obj == null || obj == NULL) return false;
|
||||||
|
obj = normalize(ext, obj); key = normalize(ext, key);
|
||||||
|
|
||||||
|
if (obj instanceof ObjectValue) return ((ObjectValue)obj).deleteMember(ext, key);
|
||||||
|
else return false;
|
||||||
|
}
|
||||||
|
public static ObjectValue getPrototype(Environment ext, Object obj) {
|
||||||
|
if (obj == null || obj == NULL) return null;
|
||||||
|
obj = normalize(ext, obj);
|
||||||
|
if (obj instanceof ObjectValue) return ((ObjectValue)obj).getPrototype(ext);
|
||||||
|
if (ext == null) return null;
|
||||||
|
|
||||||
|
if (obj instanceof String) return ext.get(Environment.STRING_PROTO);
|
||||||
|
else if (obj instanceof Number) return ext.get(Environment.NUMBER_PROTO);
|
||||||
|
else if (obj instanceof Boolean) return ext.get(Environment.BOOL_PROTO);
|
||||||
|
else if (obj instanceof Symbol) return ext.get(Environment.SYMBOL_PROTO);
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
public static boolean setPrototype(Environment ext, Object obj, Object proto) {
|
||||||
|
obj = normalize(ext, obj);
|
||||||
|
return obj instanceof ObjectValue && ((ObjectValue)obj).setPrototype(ext, proto);
|
||||||
|
}
|
||||||
|
public static void makePrototypeChain(Environment ext, Object... chain) {
|
||||||
|
for(var i = 1; i < chain.length; i++) {
|
||||||
|
setPrototype(ext, chain[i], chain[i - 1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public static List<Object> getMembers(Environment ext, Object obj, boolean own, boolean includeNonEnumerable) {
|
||||||
|
List<Object> res = new ArrayList<>();
|
||||||
|
|
||||||
|
if (obj instanceof ObjectValue) res = ((ObjectValue)obj).keys(includeNonEnumerable);
|
||||||
|
if (obj instanceof String) {
|
||||||
|
for (var i = 0; i < ((String)obj).length(); i++) res.add((double)i);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!own) {
|
||||||
|
var proto = getPrototype(ext, obj);
|
||||||
|
|
||||||
|
while (proto != null) {
|
||||||
|
res.addAll(proto.keys(includeNonEnumerable));
|
||||||
|
proto = getPrototype(ext, proto);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
public static ObjectValue getMemberDescriptor(Environment ext, Object obj, Object key) {
|
||||||
|
if (obj instanceof ObjectValue) return ((ObjectValue)obj).getMemberDescriptor(ext, key);
|
||||||
|
else if (obj instanceof String && key instanceof Number) {
|
||||||
|
var i = ((Number)key).intValue();
|
||||||
|
var _i = ((Number)key).doubleValue();
|
||||||
|
if (i - _i != 0) return null;
|
||||||
|
if (i < 0 || i >= ((String)obj).length()) return null;
|
||||||
|
|
||||||
|
return new ObjectValue(ext, Map.of(
|
||||||
|
"value", ((String)obj).charAt(i) + "",
|
||||||
|
"writable", false,
|
||||||
|
"enumerable", true,
|
||||||
|
"configurable", false
|
||||||
|
));
|
||||||
|
}
|
||||||
|
else return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean strictEquals(Environment ext, Object a, Object b) {
|
||||||
|
a = normalize(ext, a);
|
||||||
|
b = normalize(ext, b);
|
||||||
|
|
||||||
|
if (a == null || b == null) return a == null && b == null;
|
||||||
|
if (isNan(a) || isNan(b)) return false;
|
||||||
|
if (a instanceof Number && number(a) == -0.) a = 0.;
|
||||||
|
if (b instanceof Number && number(b) == -0.) b = 0.;
|
||||||
|
|
||||||
|
return a == b || a.equals(b);
|
||||||
|
}
|
||||||
|
public static boolean looseEqual(Environment ext, Object a, Object b) {
|
||||||
|
a = normalize(ext, a); b = normalize(ext, b);
|
||||||
|
|
||||||
|
// In loose equality, null is equivalent to undefined
|
||||||
|
if (a == NULL) a = null;
|
||||||
|
if (b == NULL) b = null;
|
||||||
|
|
||||||
|
if (a == null || b == null) return a == null && b == null;
|
||||||
|
// If both are objects, just compare their references
|
||||||
|
if (!isPrimitive(a) && !isPrimitive(b)) return a == b;
|
||||||
|
|
||||||
|
// Convert values to primitives
|
||||||
|
a = toPrimitive(ext, a, ConvertHint.VALUEOF);
|
||||||
|
b = toPrimitive(ext, b, ConvertHint.VALUEOF);
|
||||||
|
|
||||||
|
// Compare symbols by reference
|
||||||
|
if (a instanceof Symbol || b instanceof Symbol) return a == b;
|
||||||
|
if (a instanceof Boolean || b instanceof Boolean) return toBoolean(a) == toBoolean(b);
|
||||||
|
if (a instanceof Number || b instanceof Number) return strictEquals(ext, toNumber(ext, a), toNumber(ext, b));
|
||||||
|
|
||||||
|
// Default to strings
|
||||||
|
return toString(ext, a).equals(toString(ext, b));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Object normalize(Environment ext, Object val) {
|
||||||
|
if (val instanceof Number) return number(val);
|
||||||
|
if (isPrimitive(val) || val instanceof ObjectValue) return val;
|
||||||
|
if (val instanceof Character) return val + "";
|
||||||
|
|
||||||
|
if (val instanceof Map) {
|
||||||
|
var res = new ObjectValue();
|
||||||
|
|
||||||
|
for (var entry : ((Map<?, ?>)val).entrySet()) {
|
||||||
|
res.defineProperty(ext, entry.getKey(), entry.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (val instanceof Iterable) {
|
||||||
|
var res = new ArrayValue();
|
||||||
|
|
||||||
|
for (var entry : ((Iterable<?>)val)) {
|
||||||
|
res.set(ext, res.size(), entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (val instanceof Class) {
|
||||||
|
if (ext == null) return null;
|
||||||
|
else return NativeWrapperProvider.get(ext).getConstr((Class<?>)val);
|
||||||
|
}
|
||||||
|
|
||||||
|
return NativeWrapper.of(ext, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public static <T> T convert(Environment ext, Object obj, Class<T> clazz) {
|
||||||
|
if (clazz == Void.class) return null;
|
||||||
|
|
||||||
|
if (obj instanceof NativeWrapper) {
|
||||||
|
var res = ((NativeWrapper)obj).wrapped;
|
||||||
|
if (clazz.isInstance(res)) return (T)res;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (clazz == null || clazz == Object.class) return (T)obj;
|
||||||
|
|
||||||
|
if (obj instanceof ArrayValue) {
|
||||||
|
if (clazz.isAssignableFrom(ArrayList.class)) {
|
||||||
|
var raw = ((ArrayValue)obj).toArray();
|
||||||
|
var res = new ArrayList<>();
|
||||||
|
for (var i = 0; i < raw.length; i++) res.add(convert(ext, raw[i], Object.class));
|
||||||
|
return (T)new ArrayList<>(res);
|
||||||
|
}
|
||||||
|
if (clazz.isAssignableFrom(HashSet.class)) {
|
||||||
|
var raw = ((ArrayValue)obj).toArray();
|
||||||
|
var res = new HashSet<>();
|
||||||
|
for (var i = 0; i < raw.length; i++) res.add(convert(ext, raw[i], Object.class));
|
||||||
|
return (T)new HashSet<>(res);
|
||||||
|
}
|
||||||
|
if (clazz.isArray()) {
|
||||||
|
var raw = ((ArrayValue)obj).toArray();
|
||||||
|
Object res = Array.newInstance(clazz.getComponentType(), raw.length);
|
||||||
|
for (var i = 0; i < raw.length; i++) Array.set(res, i, convert(ext, raw[i], Object.class));
|
||||||
|
return (T)res;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (obj instanceof ObjectValue && clazz.isAssignableFrom(HashMap.class)) {
|
||||||
|
var res = new HashMap<>();
|
||||||
|
for (var el : ((ObjectValue)obj).values.entrySet()) res.put(
|
||||||
|
convert(ext, el.getKey(), null),
|
||||||
|
convert(ext, el.getValue(), null)
|
||||||
|
);
|
||||||
|
return (T)res;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (clazz == String.class) return (T)toString(ext, obj);
|
||||||
|
if (clazz == Boolean.class || clazz == Boolean.TYPE) return (T)(Boolean)toBoolean(obj);
|
||||||
|
if (clazz == Byte.class || clazz == byte.class) return (T)(Byte)(byte)toNumber(ext, obj);
|
||||||
|
if (clazz == Integer.class || clazz == int.class) return (T)(Integer)(int)toNumber(ext, obj);
|
||||||
|
if (clazz == Long.class || clazz == long.class) return (T)(Long)(long)toNumber(ext, obj);
|
||||||
|
if (clazz == Short.class || clazz == short.class) return (T)(Short)(short)toNumber(ext, obj);
|
||||||
|
if (clazz == Float.class || clazz == float.class) return (T)(Float)(float)toNumber(ext, obj);
|
||||||
|
if (clazz == Double.class || clazz == double.class) return (T)(Double)toNumber(ext, obj);
|
||||||
|
|
||||||
|
if (clazz == Character.class || clazz == char.class) {
|
||||||
|
if (obj instanceof Number) return (T)(Character)(char)number(obj);
|
||||||
|
else {
|
||||||
|
var res = toString(ext, obj);
|
||||||
|
if (res.length() == 0) throw new ConvertException("\"\"", "Character");
|
||||||
|
else return (T)(Character)res.charAt(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (obj == null) return null;
|
||||||
|
if (clazz.isInstance(obj)) return (T)obj;
|
||||||
|
if (clazz.isAssignableFrom(NativeWrapper.class)) {
|
||||||
|
return (T)NativeWrapper.of(ext, obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new ConvertException(type(obj), clazz.getSimpleName());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Iterable<Object> fromJSIterator(Environment ext, Object obj) {
|
||||||
|
return () -> {
|
||||||
|
try {
|
||||||
|
var symbol = Symbol.get("Symbol.iterator");
|
||||||
|
|
||||||
|
var iteratorFunc = getMember(ext, obj, symbol);
|
||||||
|
if (!(iteratorFunc instanceof FunctionValue)) return Collections.emptyIterator();
|
||||||
|
var iterator = iteratorFunc instanceof FunctionValue ?
|
||||||
|
((FunctionValue)iteratorFunc).call(ext, obj, obj) :
|
||||||
|
iteratorFunc;
|
||||||
|
var nextFunc = getMember(ext, call(ext, iteratorFunc, obj), "next");
|
||||||
|
|
||||||
|
if (!(nextFunc instanceof FunctionValue)) return Collections.emptyIterator();
|
||||||
|
|
||||||
|
return new Iterator<Object>() {
|
||||||
|
private Object value = null;
|
||||||
|
public boolean consumed = true;
|
||||||
|
private FunctionValue next = (FunctionValue)nextFunc;
|
||||||
|
|
||||||
|
private void loadNext() {
|
||||||
|
if (next == null) value = null;
|
||||||
|
else if (consumed) {
|
||||||
|
var curr = next.call(ext, iterator);
|
||||||
|
if (curr == null) { next = null; value = null; }
|
||||||
|
if (toBoolean(Values.getMember(ext, curr, "done"))) { next = null; value = null; }
|
||||||
|
else {
|
||||||
|
this.value = Values.getMember(ext, curr, "value");
|
||||||
|
consumed = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasNext() {
|
||||||
|
loadNext();
|
||||||
|
return next != null;
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public Object next() {
|
||||||
|
loadNext();
|
||||||
|
var res = value;
|
||||||
|
value = null;
|
||||||
|
consumed = true;
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
catch (IllegalArgumentException | NullPointerException e) {
|
||||||
|
return Collections.emptyIterator();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ObjectValue toJSIterator(Environment ext, Iterator<?> it) {
|
||||||
|
var res = new ObjectValue();
|
||||||
|
|
||||||
|
try {
|
||||||
|
var key = getMember(ext, getMember(ext, ext.get(Environment.SYMBOL_PROTO), "constructor"), "iterator");
|
||||||
|
res.defineProperty(ext, key, new NativeFunction("", args -> args.self));
|
||||||
|
}
|
||||||
|
catch (IllegalArgumentException | NullPointerException e) { }
|
||||||
|
|
||||||
|
res.defineProperty(ext, "next", new NativeFunction("", args -> {
|
||||||
|
if (!it.hasNext()) return new ObjectValue(ext, Map.of("done", true));
|
||||||
|
else {
|
||||||
|
var obj = new ObjectValue();
|
||||||
|
obj.defineProperty(args.env, "value", it.next());
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ObjectValue toJSIterator(Environment ext, Iterable<?> it) {
|
||||||
|
return toJSIterator(ext, it.iterator());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ObjectValue toJSAsyncIterator(Environment ext, Iterator<?> it) {
|
||||||
|
var res = new ObjectValue();
|
||||||
|
|
||||||
|
try {
|
||||||
|
var key = getMemberPath(ext, ext.get(Environment.SYMBOL_PROTO), "constructor", "asyncIterator");
|
||||||
|
res.defineProperty(ext, key, new NativeFunction("", args -> args.self));
|
||||||
|
}
|
||||||
|
catch (IllegalArgumentException | NullPointerException e) { }
|
||||||
|
|
||||||
|
res.defineProperty(ext, "next", new NativeFunction("", args -> {
|
||||||
|
return PromiseLib.await(args.env, () -> {
|
||||||
|
if (!it.hasNext()) return new ObjectValue(ext, Map.of("done", true));
|
||||||
|
else {
|
||||||
|
var obj = new ObjectValue();
|
||||||
|
obj.defineProperty(args.env, "value", it.next());
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}));
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isEmptyFunc(ObjectValue val) {
|
||||||
|
if (!(val instanceof FunctionValue)) return false;
|
||||||
|
if (!val.values.containsKey("prototype") || val.values.size() + val.properties.size() > 1) return false;
|
||||||
|
var proto = val.values.get("prototype");
|
||||||
|
if (!(proto instanceof ObjectValue)) return false;
|
||||||
|
var protoObj = (ObjectValue)proto;
|
||||||
|
if (protoObj.values.get("constructor") != val) return false;
|
||||||
|
if (protoObj.values.size() + protoObj.properties.size() != 1) return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
private static String toReadable(Environment ext, Object val, HashSet<Object> passed, int tab) {
|
||||||
|
if (tab == 0 && val instanceof String) return (String)val;
|
||||||
|
|
||||||
|
if (passed.contains(val)) return "[circular]";
|
||||||
|
|
||||||
|
var printed = true;
|
||||||
|
var res = new StringBuilder();
|
||||||
|
var dbg = DebugContext.get(ext);
|
||||||
|
|
||||||
|
if (val instanceof FunctionValue) {
|
||||||
|
res.append(val.toString());
|
||||||
|
var loc = val instanceof CodeFunction ? dbg.getMapOrEmpty((CodeFunction)val).start() : null;
|
||||||
|
|
||||||
|
if (loc != null) res.append(" @ " + loc);
|
||||||
|
}
|
||||||
|
else if (val instanceof ArrayValue) {
|
||||||
|
res.append("[");
|
||||||
|
var obj = ((ArrayValue)val);
|
||||||
|
for (int i = 0; i < obj.size(); i++) {
|
||||||
|
if (i != 0) res.append(", ");
|
||||||
|
else res.append(" ");
|
||||||
|
if (obj.has(i)) res.append(toReadable(ext, obj.get(i), passed, tab));
|
||||||
|
else res.append("<empty>");
|
||||||
|
}
|
||||||
|
res.append(" ] ");
|
||||||
|
}
|
||||||
|
else if (val instanceof NativeWrapper) {
|
||||||
|
var obj = ((NativeWrapper)val).wrapped;
|
||||||
|
res.append("Native " + obj.toString() + " ");
|
||||||
|
}
|
||||||
|
else printed = false;
|
||||||
|
|
||||||
|
if (val instanceof ObjectValue) {
|
||||||
|
if (tab > 3) {
|
||||||
|
return "{...}";
|
||||||
|
}
|
||||||
|
|
||||||
|
passed.add(val);
|
||||||
|
|
||||||
|
var obj = (ObjectValue)val;
|
||||||
|
if (obj.values.size() + obj.properties.size() == 0 || isEmptyFunc(obj)) {
|
||||||
|
if (!printed) res.append("{}\n");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
res.append("{\n");
|
||||||
|
|
||||||
|
for (var el : obj.values.entrySet()) {
|
||||||
|
for (int i = 0; i < tab + 1; i++) res.append(" ");
|
||||||
|
res.append(toReadable(ext, el.getKey(), passed, tab + 1));
|
||||||
|
res.append(": ");
|
||||||
|
res.append(toReadable(ext, el.getValue(), passed, tab + 1));
|
||||||
|
res.append(",\n");
|
||||||
|
}
|
||||||
|
for (var el : obj.properties.entrySet()) {
|
||||||
|
for (int i = 0; i < tab + 1; i++) res.append(" ");
|
||||||
|
res.append(toReadable(ext, el.getKey(), passed, tab + 1));
|
||||||
|
res.append(": [prop],\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < tab; i++) res.append(" ");
|
||||||
|
res.append("}");
|
||||||
|
}
|
||||||
|
|
||||||
|
passed.remove(val);
|
||||||
|
}
|
||||||
|
else if (val == null) return "undefined";
|
||||||
|
else if (val == Values.NULL) return "null";
|
||||||
|
else if (val instanceof String) return "'" + val + "'";
|
||||||
|
else return Values.toString(ext, val);
|
||||||
|
|
||||||
|
return res.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String toReadable(Environment ext, Object val) {
|
||||||
|
return toReadable(ext, val, new HashSet<>(), 0);
|
||||||
|
}
|
||||||
|
public static String errorToReadable(RuntimeException err, String prefix) {
|
||||||
|
prefix = prefix == null ? "Uncaught" : "Uncaught " + prefix;
|
||||||
|
if (err instanceof EngineException) {
|
||||||
|
var ee = ((EngineException)err);
|
||||||
|
try {
|
||||||
|
return prefix + " " + ee.toString(ee.env);
|
||||||
|
}
|
||||||
|
catch (EngineException ex) {
|
||||||
|
return prefix + " " + toReadable(ee.env, ee.value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (err instanceof SyntaxException) {
|
||||||
|
return prefix + " SyntaxError " + ((SyntaxException)err).msg;
|
||||||
|
}
|
||||||
|
else if (err.getCause() instanceof InterruptedException) return "";
|
||||||
|
else {
|
||||||
|
var str = new ByteArrayOutputStream();
|
||||||
|
err.printStackTrace(new PrintStream(str));
|
||||||
|
|
||||||
|
return prefix + " internal error " + str.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public static void printValue(Environment ext, Object val) {
|
||||||
|
System.out.print(toReadable(ext, val));
|
||||||
|
}
|
||||||
|
public static void printError(RuntimeException err, String prefix) {
|
||||||
|
System.out.println(errorToReadable(err, prefix));
|
||||||
|
}
|
||||||
|
}
|
@ -13,10 +13,9 @@ import java.util.List;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import me.topchetoeu.jscript.common.Operation;
|
import me.topchetoeu.jscript.common.Operation;
|
||||||
import me.topchetoeu.jscript.lib.PromiseLib;
|
// import me.topchetoeu.jscript.lib.PromiseLib;
|
||||||
import me.topchetoeu.jscript.runtime.Environment;
|
|
||||||
import me.topchetoeu.jscript.runtime.Extensions;
|
|
||||||
import me.topchetoeu.jscript.runtime.debug.DebugContext;
|
import me.topchetoeu.jscript.runtime.debug.DebugContext;
|
||||||
|
import me.topchetoeu.jscript.runtime.environment.Environment;
|
||||||
import me.topchetoeu.jscript.runtime.exceptions.ConvertException;
|
import me.topchetoeu.jscript.runtime.exceptions.ConvertException;
|
||||||
import me.topchetoeu.jscript.runtime.exceptions.EngineException;
|
import me.topchetoeu.jscript.runtime.exceptions.EngineException;
|
||||||
import me.topchetoeu.jscript.runtime.exceptions.SyntaxException;
|
import me.topchetoeu.jscript.runtime.exceptions.SyntaxException;
|
||||||
@ -74,7 +73,7 @@ public class Values {
|
|||||||
return "object";
|
return "object";
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Object tryCallConvertFunc(Extensions ext, Object obj, String name) {
|
private static Object tryCallConvertFunc(Environment ext, Object obj, String name) {
|
||||||
var func = getMember(ext, obj, name);
|
var func = getMember(ext, obj, name);
|
||||||
|
|
||||||
if (func instanceof FunctionValue) {
|
if (func instanceof FunctionValue) {
|
||||||
@ -95,7 +94,7 @@ public class Values {
|
|||||||
obj == NULL;
|
obj == NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Object toPrimitive(Extensions ext, Object obj, ConvertHint hint) {
|
public static Object toPrimitive(Environment ext, Object obj, ConvertHint hint) {
|
||||||
obj = normalize(ext, obj);
|
obj = normalize(ext, obj);
|
||||||
if (isPrimitive(obj)) return obj;
|
if (isPrimitive(obj)) return obj;
|
||||||
|
|
||||||
@ -116,7 +115,7 @@ public class Values {
|
|||||||
if (obj instanceof Boolean) return (Boolean)obj;
|
if (obj instanceof Boolean) return (Boolean)obj;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
public static double toNumber(Extensions ext, Object obj) {
|
public static double toNumber(Environment ext, Object obj) {
|
||||||
var val = toPrimitive(ext, obj, ConvertHint.VALUEOF);
|
var val = toPrimitive(ext, obj, ConvertHint.VALUEOF);
|
||||||
|
|
||||||
if (val instanceof Number) return number(val);
|
if (val instanceof Number) return number(val);
|
||||||
@ -127,7 +126,7 @@ public class Values {
|
|||||||
}
|
}
|
||||||
return Double.NaN;
|
return Double.NaN;
|
||||||
}
|
}
|
||||||
public static String toString(Extensions ext, Object obj) {
|
public static String toString(Environment ext, Object obj) {
|
||||||
var val = toPrimitive(ext, obj, ConvertHint.VALUEOF);
|
var val = toPrimitive(ext, obj, ConvertHint.VALUEOF);
|
||||||
|
|
||||||
if (val == null) return "undefined";
|
if (val == null) return "undefined";
|
||||||
@ -147,47 +146,47 @@ public class Values {
|
|||||||
return "Unknown value";
|
return "Unknown value";
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Object add(Extensions ext, Object a, Object b) {
|
public static Object add(Environment ext, Object a, Object b) {
|
||||||
if (a instanceof String || b instanceof String) return toString(ext, a) + toString(ext, b);
|
if (a instanceof String || b instanceof String) return toString(ext, a) + toString(ext, b);
|
||||||
else return toNumber(ext, a) + toNumber(ext, b);
|
else return toNumber(ext, a) + toNumber(ext, b);
|
||||||
}
|
}
|
||||||
public static double subtract(Extensions ext, Object a, Object b) {
|
public static double subtract(Environment ext, Object a, Object b) {
|
||||||
return toNumber(ext, a) - toNumber(ext, b);
|
return toNumber(ext, a) - toNumber(ext, b);
|
||||||
}
|
}
|
||||||
public static double multiply(Extensions ext, Object a, Object b) {
|
public static double multiply(Environment ext, Object a, Object b) {
|
||||||
return toNumber(ext, a) * toNumber(ext, b);
|
return toNumber(ext, a) * toNumber(ext, b);
|
||||||
}
|
}
|
||||||
public static double divide(Extensions ext, Object a, Object b) {
|
public static double divide(Environment ext, Object a, Object b) {
|
||||||
return toNumber(ext, a) / toNumber(ext, b);
|
return toNumber(ext, a) / toNumber(ext, b);
|
||||||
}
|
}
|
||||||
public static double modulo(Extensions ext, Object a, Object b) {
|
public static double modulo(Environment ext, Object a, Object b) {
|
||||||
return toNumber(ext, a) % toNumber(ext, b);
|
return toNumber(ext, a) % toNumber(ext, b);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static double negative(Extensions ext, Object obj) {
|
public static double negative(Environment ext, Object obj) {
|
||||||
return -toNumber(ext, obj);
|
return -toNumber(ext, obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int and(Extensions ext, Object a, Object b) {
|
public static int and(Environment ext, Object a, Object b) {
|
||||||
return (int)toNumber(ext, a) & (int)toNumber(ext, b);
|
return (int)toNumber(ext, a) & (int)toNumber(ext, b);
|
||||||
}
|
}
|
||||||
public static int or(Extensions ext, Object a, Object b) {
|
public static int or(Environment ext, Object a, Object b) {
|
||||||
return (int)toNumber(ext, a) | (int)toNumber(ext, b);
|
return (int)toNumber(ext, a) | (int)toNumber(ext, b);
|
||||||
}
|
}
|
||||||
public static int xor(Extensions ext, Object a, Object b) {
|
public static int xor(Environment ext, Object a, Object b) {
|
||||||
return (int)toNumber(ext, a) ^ (int)toNumber(ext, b);
|
return (int)toNumber(ext, a) ^ (int)toNumber(ext, b);
|
||||||
}
|
}
|
||||||
public static int bitwiseNot(Extensions ext, Object obj) {
|
public static int bitwiseNot(Environment ext, Object obj) {
|
||||||
return ~(int)toNumber(ext, obj);
|
return ~(int)toNumber(ext, obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int shiftLeft(Extensions ext, Object a, Object b) {
|
public static int shiftLeft(Environment ext, Object a, Object b) {
|
||||||
return (int)toNumber(ext, a) << (int)toNumber(ext, b);
|
return (int)toNumber(ext, a) << (int)toNumber(ext, b);
|
||||||
}
|
}
|
||||||
public static int shiftRight(Extensions ext, Object a, Object b) {
|
public static int shiftRight(Environment ext, Object a, Object b) {
|
||||||
return (int)toNumber(ext, a) >> (int)toNumber(ext, b);
|
return (int)toNumber(ext, a) >> (int)toNumber(ext, b);
|
||||||
}
|
}
|
||||||
public static long unsignedShiftRight(Extensions ext, Object a, Object b) {
|
public static long unsignedShiftRight(Environment ext, Object a, Object b) {
|
||||||
long _a = (long)toNumber(ext, a);
|
long _a = (long)toNumber(ext, a);
|
||||||
long _b = (long)toNumber(ext, b);
|
long _b = (long)toNumber(ext, b);
|
||||||
|
|
||||||
@ -196,7 +195,7 @@ public class Values {
|
|||||||
return _a >>> _b;
|
return _a >>> _b;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static CompareResult compare(Extensions ext, Object a, Object b) {
|
public static CompareResult compare(Environment ext, Object a, Object b) {
|
||||||
a = toPrimitive(ext, a, ConvertHint.VALUEOF);
|
a = toPrimitive(ext, a, ConvertHint.VALUEOF);
|
||||||
b = toPrimitive(ext, b, ConvertHint.VALUEOF);
|
b = toPrimitive(ext, b, ConvertHint.VALUEOF);
|
||||||
|
|
||||||
@ -214,7 +213,7 @@ public class Values {
|
|||||||
return !toBoolean(obj);
|
return !toBoolean(obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isInstanceOf(Extensions ext, Object obj, Object proto) {
|
public static boolean isInstanceOf(Environment ext, Object obj, Object proto) {
|
||||||
if (obj == null || obj == NULL || proto == null || proto == NULL) return false;
|
if (obj == null || obj == NULL || proto == null || proto == NULL) return false;
|
||||||
var val = getPrototype(ext, obj);
|
var val = getPrototype(ext, obj);
|
||||||
|
|
||||||
@ -226,7 +225,7 @@ public class Values {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Object operation(Extensions ext, Operation op, Object ...args) {
|
public static Object operation(Environment ext, Operation op, Object ...args) {
|
||||||
switch (op) {
|
switch (op) {
|
||||||
case ADD: return add(ext, args[0], args[1]);
|
case ADD: return add(ext, args[0], args[1]);
|
||||||
case SUBTRACT: return subtract(ext, args[0], args[1]);
|
case SUBTRACT: return subtract(ext, args[0], args[1]);
|
||||||
@ -267,7 +266,7 @@ public class Values {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Object getMember(Extensions ctx, Object obj, Object key) {
|
public static Object getMember(Environment ctx, Object obj, Object key) {
|
||||||
obj = normalize(ctx, obj); key = normalize(ctx, key);
|
obj = normalize(ctx, obj); key = normalize(ctx, key);
|
||||||
if (obj == null) throw new IllegalArgumentException("Tried to access member of undefined.");
|
if (obj == null) throw new IllegalArgumentException("Tried to access member of undefined.");
|
||||||
if (obj == NULL) throw new IllegalArgumentException("Tried to access member of null.");
|
if (obj == NULL) throw new IllegalArgumentException("Tried to access member of null.");
|
||||||
@ -287,12 +286,12 @@ public class Values {
|
|||||||
else if (key != null && "__proto__".equals(key)) return proto;
|
else if (key != null && "__proto__".equals(key)) return proto;
|
||||||
else return proto.getMember(ctx, key, obj);
|
else return proto.getMember(ctx, key, obj);
|
||||||
}
|
}
|
||||||
public static Object getMemberPath(Extensions ctx, Object obj, Object ...path) {
|
public static Object getMemberPath(Environment ctx, Object obj, Object ...path) {
|
||||||
var res = obj;
|
var res = obj;
|
||||||
for (var key : path) res = getMember(ctx, res, key);
|
for (var key : path) res = getMember(ctx, res, key);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
public static boolean setMember(Extensions ctx, Object obj, Object key, Object val) {
|
public static boolean setMember(Environment ctx, Object obj, Object key, Object val) {
|
||||||
obj = normalize(ctx, obj); key = normalize(ctx, key); val = normalize(ctx, val);
|
obj = normalize(ctx, obj); key = normalize(ctx, key); val = normalize(ctx, val);
|
||||||
if (obj == null) throw EngineException.ofType("Tried to access member of undefined.");
|
if (obj == null) throw EngineException.ofType("Tried to access member of undefined.");
|
||||||
if (obj == NULL) throw EngineException.ofType("Tried to access member of null.");
|
if (obj == NULL) throw EngineException.ofType("Tried to access member of null.");
|
||||||
@ -302,7 +301,7 @@ public class Values {
|
|||||||
var proto = getPrototype(ctx, obj);
|
var proto = getPrototype(ctx, obj);
|
||||||
return proto.setMember(ctx, key, val, obj, true);
|
return proto.setMember(ctx, key, val, obj, true);
|
||||||
}
|
}
|
||||||
public static boolean hasMember(Extensions ctx, Object obj, Object key, boolean own) {
|
public static boolean hasMember(Environment ctx, Object obj, Object key, boolean own) {
|
||||||
if (obj == null || obj == NULL) return false;
|
if (obj == null || obj == NULL) return false;
|
||||||
obj = normalize(ctx, obj); key = normalize(ctx, key);
|
obj = normalize(ctx, obj); key = normalize(ctx, key);
|
||||||
|
|
||||||
@ -320,14 +319,14 @@ public class Values {
|
|||||||
var proto = getPrototype(ctx, obj);
|
var proto = getPrototype(ctx, obj);
|
||||||
return proto != null && proto.hasMember(ctx, key, own);
|
return proto != null && proto.hasMember(ctx, key, own);
|
||||||
}
|
}
|
||||||
public static boolean deleteMember(Extensions ext, Object obj, Object key) {
|
public static boolean deleteMember(Environment ext, Object obj, Object key) {
|
||||||
if (obj == null || obj == NULL) return false;
|
if (obj == null || obj == NULL) return false;
|
||||||
obj = normalize(ext, obj); key = normalize(ext, key);
|
obj = normalize(ext, obj); key = normalize(ext, key);
|
||||||
|
|
||||||
if (obj instanceof ObjectValue) return ((ObjectValue)obj).deleteMember(ext, key);
|
if (obj instanceof ObjectValue) return ((ObjectValue)obj).deleteMember(ext, key);
|
||||||
else return false;
|
else return false;
|
||||||
}
|
}
|
||||||
public static ObjectValue getPrototype(Extensions ext, Object obj) {
|
public static ObjectValue getPrototype(Environment ext, Object obj) {
|
||||||
if (obj == null || obj == NULL) return null;
|
if (obj == null || obj == NULL) return null;
|
||||||
obj = normalize(ext, obj);
|
obj = normalize(ext, obj);
|
||||||
if (obj instanceof ObjectValue) return ((ObjectValue)obj).getPrototype(ext);
|
if (obj instanceof ObjectValue) return ((ObjectValue)obj).getPrototype(ext);
|
||||||
@ -340,16 +339,16 @@ public class Values {
|
|||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
public static boolean setPrototype(Extensions ext, Object obj, Object proto) {
|
public static boolean setPrototype(Environment ext, Object obj, Object proto) {
|
||||||
obj = normalize(ext, obj);
|
obj = normalize(ext, obj);
|
||||||
return obj instanceof ObjectValue && ((ObjectValue)obj).setPrototype(ext, proto);
|
return obj instanceof ObjectValue && ((ObjectValue)obj).setPrototype(ext, proto);
|
||||||
}
|
}
|
||||||
public static void makePrototypeChain(Extensions ext, Object... chain) {
|
public static void makePrototypeChain(Environment ext, Object... chain) {
|
||||||
for(var i = 1; i < chain.length; i++) {
|
for(var i = 1; i < chain.length; i++) {
|
||||||
setPrototype(ext, chain[i], chain[i - 1]);
|
setPrototype(ext, chain[i], chain[i - 1]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public static List<Object> getMembers(Extensions ext, Object obj, boolean own, boolean includeNonEnumerable) {
|
public static List<Object> getMembers(Environment ext, Object obj, boolean own, boolean includeNonEnumerable) {
|
||||||
List<Object> res = new ArrayList<>();
|
List<Object> res = new ArrayList<>();
|
||||||
|
|
||||||
if (obj instanceof ObjectValue) res = ((ObjectValue)obj).keys(includeNonEnumerable);
|
if (obj instanceof ObjectValue) res = ((ObjectValue)obj).keys(includeNonEnumerable);
|
||||||
@ -369,7 +368,7 @@ public class Values {
|
|||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
public static ObjectValue getMemberDescriptor(Extensions ext, Object obj, Object key) {
|
public static ObjectValue getMemberDescriptor(Environment ext, Object obj, Object key) {
|
||||||
if (obj instanceof ObjectValue) return ((ObjectValue)obj).getMemberDescriptor(ext, key);
|
if (obj instanceof ObjectValue) return ((ObjectValue)obj).getMemberDescriptor(ext, key);
|
||||||
else if (obj instanceof String && key instanceof Number) {
|
else if (obj instanceof String && key instanceof Number) {
|
||||||
var i = ((Number)key).intValue();
|
var i = ((Number)key).intValue();
|
||||||
@ -387,11 +386,11 @@ public class Values {
|
|||||||
else return null;
|
else return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Object call(Extensions ext, Object func, Object thisArg, Object ...args) {
|
public static Object call(Environment ext, Object func, Object thisArg, Object ...args) {
|
||||||
if (!(func instanceof FunctionValue)) throw EngineException.ofType("Tried to call a non-function value.");
|
if (!(func instanceof FunctionValue)) throw EngineException.ofType("Tried to call a non-function value.");
|
||||||
return ((FunctionValue)func).call(ext, thisArg, args);
|
return ((FunctionValue)func).call(ext, thisArg, args);
|
||||||
}
|
}
|
||||||
public static Object callNew(Extensions ext, Object func, Object ...args) {
|
public static Object callNew(Environment ext, Object func, Object ...args) {
|
||||||
var res = new ObjectValue();
|
var res = new ObjectValue();
|
||||||
try {
|
try {
|
||||||
var proto = Values.getMember(ext, func, "prototype");
|
var proto = Values.getMember(ext, func, "prototype");
|
||||||
@ -407,7 +406,7 @@ public class Values {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean strictEquals(Extensions ext, Object a, Object b) {
|
public static boolean strictEquals(Environment ext, Object a, Object b) {
|
||||||
a = normalize(ext, a);
|
a = normalize(ext, a);
|
||||||
b = normalize(ext, b);
|
b = normalize(ext, b);
|
||||||
|
|
||||||
@ -418,7 +417,7 @@ public class Values {
|
|||||||
|
|
||||||
return a == b || a.equals(b);
|
return a == b || a.equals(b);
|
||||||
}
|
}
|
||||||
public static boolean looseEqual(Extensions ext, Object a, Object b) {
|
public static boolean looseEqual(Environment ext, Object a, Object b) {
|
||||||
a = normalize(ext, a); b = normalize(ext, b);
|
a = normalize(ext, a); b = normalize(ext, b);
|
||||||
|
|
||||||
// In loose equality, null is equivalent to undefined
|
// In loose equality, null is equivalent to undefined
|
||||||
@ -442,7 +441,7 @@ public class Values {
|
|||||||
return toString(ext, a).equals(toString(ext, b));
|
return toString(ext, a).equals(toString(ext, b));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Object normalize(Extensions ext, Object val) {
|
public static Object normalize(Environment ext, Object val) {
|
||||||
if (val instanceof Number) return number(val);
|
if (val instanceof Number) return number(val);
|
||||||
if (isPrimitive(val) || val instanceof ObjectValue) return val;
|
if (isPrimitive(val) || val instanceof ObjectValue) return val;
|
||||||
if (val instanceof Character) return val + "";
|
if (val instanceof Character) return val + "";
|
||||||
@ -476,7 +475,7 @@ public class Values {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public static <T> T convert(Extensions ext, Object obj, Class<T> clazz) {
|
public static <T> T convert(Environment ext, Object obj, Class<T> clazz) {
|
||||||
if (clazz == Void.class) return null;
|
if (clazz == Void.class) return null;
|
||||||
|
|
||||||
if (obj instanceof NativeWrapper) {
|
if (obj instanceof NativeWrapper) {
|
||||||
@ -543,7 +542,7 @@ public class Values {
|
|||||||
throw new ConvertException(type(obj), clazz.getSimpleName());
|
throw new ConvertException(type(obj), clazz.getSimpleName());
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Iterable<Object> fromJSIterator(Extensions ext, Object obj) {
|
public static Iterable<Object> fromJSIterator(Environment ext, Object obj) {
|
||||||
return () -> {
|
return () -> {
|
||||||
try {
|
try {
|
||||||
var symbol = Symbol.get("Symbol.iterator");
|
var symbol = Symbol.get("Symbol.iterator");
|
||||||
@ -596,7 +595,7 @@ public class Values {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ObjectValue toJSIterator(Extensions ext, Iterator<?> it) {
|
public static ObjectValue toJSIterator(Environment ext, Iterator<?> it) {
|
||||||
var res = new ObjectValue();
|
var res = new ObjectValue();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@ -609,7 +608,7 @@ public class Values {
|
|||||||
if (!it.hasNext()) return new ObjectValue(ext, Map.of("done", true));
|
if (!it.hasNext()) return new ObjectValue(ext, Map.of("done", true));
|
||||||
else {
|
else {
|
||||||
var obj = new ObjectValue();
|
var obj = new ObjectValue();
|
||||||
obj.defineProperty(args.ctx, "value", it.next());
|
obj.defineProperty(args.env, "value", it.next());
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
@ -617,11 +616,11 @@ public class Values {
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ObjectValue toJSIterator(Extensions ext, Iterable<?> it) {
|
public static ObjectValue toJSIterator(Environment ext, Iterable<?> it) {
|
||||||
return toJSIterator(ext, it.iterator());
|
return toJSIterator(ext, it.iterator());
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ObjectValue toJSAsyncIterator(Extensions ext, Iterator<?> it) {
|
public static ObjectValue toJSAsyncIterator(Environment ext, Iterator<?> it) {
|
||||||
var res = new ObjectValue();
|
var res = new ObjectValue();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@ -631,11 +630,11 @@ public class Values {
|
|||||||
catch (IllegalArgumentException | NullPointerException e) { }
|
catch (IllegalArgumentException | NullPointerException e) { }
|
||||||
|
|
||||||
res.defineProperty(ext, "next", new NativeFunction("", args -> {
|
res.defineProperty(ext, "next", new NativeFunction("", args -> {
|
||||||
return PromiseLib.await(args.ctx, () -> {
|
return PromiseLib.await(args.env, () -> {
|
||||||
if (!it.hasNext()) return new ObjectValue(ext, Map.of("done", true));
|
if (!it.hasNext()) return new ObjectValue(ext, Map.of("done", true));
|
||||||
else {
|
else {
|
||||||
var obj = new ObjectValue();
|
var obj = new ObjectValue();
|
||||||
obj.defineProperty(args.ctx, "value", it.next());
|
obj.defineProperty(args.env, "value", it.next());
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -654,7 +653,7 @@ public class Values {
|
|||||||
if (protoObj.values.size() + protoObj.properties.size() != 1) return false;
|
if (protoObj.values.size() + protoObj.properties.size() != 1) return false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
private static String toReadable(Extensions ext, Object val, HashSet<Object> passed, int tab) {
|
private static String toReadable(Environment ext, Object val, HashSet<Object> passed, int tab) {
|
||||||
if (tab == 0 && val instanceof String) return (String)val;
|
if (tab == 0 && val instanceof String) return (String)val;
|
||||||
|
|
||||||
if (passed.contains(val)) return "[circular]";
|
if (passed.contains(val)) return "[circular]";
|
||||||
@ -727,7 +726,7 @@ public class Values {
|
|||||||
return res.toString();
|
return res.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String toReadable(Extensions ext, Object val) {
|
public static String toReadable(Environment ext, Object val) {
|
||||||
return toReadable(ext, val, new HashSet<>(), 0);
|
return toReadable(ext, val, new HashSet<>(), 0);
|
||||||
}
|
}
|
||||||
public static String errorToReadable(RuntimeException err, String prefix) {
|
public static String errorToReadable(RuntimeException err, String prefix) {
|
||||||
@ -735,10 +734,10 @@ public class Values {
|
|||||||
if (err instanceof EngineException) {
|
if (err instanceof EngineException) {
|
||||||
var ee = ((EngineException)err);
|
var ee = ((EngineException)err);
|
||||||
try {
|
try {
|
||||||
return prefix + " " + ee.toString(ee.ext);
|
return prefix + " " + ee.toString(ee.env);
|
||||||
}
|
}
|
||||||
catch (EngineException ex) {
|
catch (EngineException ex) {
|
||||||
return prefix + " " + toReadable(ee.ext, ee.value);
|
return prefix + " " + toReadable(ee.env, ee.value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (err instanceof SyntaxException) {
|
else if (err instanceof SyntaxException) {
|
||||||
@ -752,7 +751,7 @@ public class Values {
|
|||||||
return prefix + " internal error " + str.toString();
|
return prefix + " internal error " + str.toString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public static void printValue(Extensions ext, Object val) {
|
public static void printValue(Environment ext, Object val) {
|
||||||
System.out.print(toReadable(ext, val));
|
System.out.print(toReadable(ext, val));
|
||||||
}
|
}
|
||||||
public static void printError(RuntimeException err, String prefix) {
|
public static void printError(RuntimeException err, String prefix) {
|
||||||
|
@ -5,11 +5,11 @@ import me.topchetoeu.jscript.common.FunctionBody;
|
|||||||
import me.topchetoeu.jscript.compilation.CompileResult;
|
import me.topchetoeu.jscript.compilation.CompileResult;
|
||||||
import me.topchetoeu.jscript.compilation.parsing.Parsing;
|
import me.topchetoeu.jscript.compilation.parsing.Parsing;
|
||||||
import me.topchetoeu.jscript.runtime.Compiler;
|
import me.topchetoeu.jscript.runtime.Compiler;
|
||||||
import me.topchetoeu.jscript.runtime.Extensions;
|
|
||||||
import me.topchetoeu.jscript.runtime.debug.DebugContext;
|
import me.topchetoeu.jscript.runtime.debug.DebugContext;
|
||||||
|
import me.topchetoeu.jscript.runtime.environment.Environment;
|
||||||
|
|
||||||
public class JSCompiler implements Compiler {
|
public class JSCompiler implements Compiler {
|
||||||
public final Extensions ext;
|
public final Environment ext;
|
||||||
|
|
||||||
private void registerFunc(FunctionBody body, CompileResult res) {
|
private void registerFunc(FunctionBody body, CompileResult res) {
|
||||||
var map = res.map();
|
var map = res.map();
|
||||||
@ -30,7 +30,7 @@ public class JSCompiler implements Compiler {
|
|||||||
return func;
|
return func;
|
||||||
}
|
}
|
||||||
|
|
||||||
public JSCompiler(Extensions ext) {
|
public JSCompiler(Environment ext) {
|
||||||
this.ext = ext;
|
this.ext = ext;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,11 +10,10 @@ import me.topchetoeu.jscript.common.Metadata;
|
|||||||
import me.topchetoeu.jscript.common.Reading;
|
import me.topchetoeu.jscript.common.Reading;
|
||||||
import me.topchetoeu.jscript.lib.Internals;
|
import me.topchetoeu.jscript.lib.Internals;
|
||||||
import me.topchetoeu.jscript.runtime.Compiler;
|
import me.topchetoeu.jscript.runtime.Compiler;
|
||||||
import me.topchetoeu.jscript.runtime.Context;
|
|
||||||
import me.topchetoeu.jscript.runtime.Engine;
|
import me.topchetoeu.jscript.runtime.Engine;
|
||||||
import me.topchetoeu.jscript.runtime.Environment;
|
|
||||||
import me.topchetoeu.jscript.runtime.EventLoop;
|
import me.topchetoeu.jscript.runtime.EventLoop;
|
||||||
import me.topchetoeu.jscript.runtime.debug.DebugContext;
|
import me.topchetoeu.jscript.runtime.debug.DebugContext;
|
||||||
|
import me.topchetoeu.jscript.runtime.environment.Environment;
|
||||||
import me.topchetoeu.jscript.runtime.exceptions.EngineException;
|
import me.topchetoeu.jscript.runtime.exceptions.EngineException;
|
||||||
import me.topchetoeu.jscript.runtime.exceptions.InterruptException;
|
import me.topchetoeu.jscript.runtime.exceptions.InterruptException;
|
||||||
import me.topchetoeu.jscript.runtime.exceptions.SyntaxException;
|
import me.topchetoeu.jscript.runtime.exceptions.SyntaxException;
|
||||||
@ -29,7 +28,6 @@ import me.topchetoeu.jscript.utils.filesystem.Mode;
|
|||||||
import me.topchetoeu.jscript.utils.filesystem.PhysicalFilesystem;
|
import me.topchetoeu.jscript.utils.filesystem.PhysicalFilesystem;
|
||||||
import me.topchetoeu.jscript.utils.filesystem.RootFilesystem;
|
import me.topchetoeu.jscript.utils.filesystem.RootFilesystem;
|
||||||
import me.topchetoeu.jscript.utils.filesystem.STDFilesystem;
|
import me.topchetoeu.jscript.utils.filesystem.STDFilesystem;
|
||||||
import me.topchetoeu.jscript.utils.interop.NativeWrapperProvider;
|
|
||||||
import me.topchetoeu.jscript.utils.modules.ModuleRepo;
|
import me.topchetoeu.jscript.utils.modules.ModuleRepo;
|
||||||
import me.topchetoeu.jscript.utils.permissions.PermissionsManager;
|
import me.topchetoeu.jscript.utils.permissions.PermissionsManager;
|
||||||
import me.topchetoeu.jscript.utils.permissions.PermissionsProvider;
|
import me.topchetoeu.jscript.utils.permissions.PermissionsProvider;
|
||||||
@ -38,7 +36,7 @@ public class JScriptRepl {
|
|||||||
static Thread engineTask, debugTask;
|
static Thread engineTask, debugTask;
|
||||||
static Engine engine = new Engine();
|
static Engine engine = new Engine();
|
||||||
static DebugServer debugServer = new DebugServer();
|
static DebugServer debugServer = new DebugServer();
|
||||||
static Environment environment = new Environment();
|
static Environment environment = Environment.empty();
|
||||||
|
|
||||||
static int j = 0;
|
static int j = 0;
|
||||||
static String[] args;
|
static String[] args;
|
||||||
@ -97,8 +95,8 @@ public class JScriptRepl {
|
|||||||
glob.define(null, false, new NativeFunction("go", args -> {
|
glob.define(null, false, new NativeFunction("go", args -> {
|
||||||
try {
|
try {
|
||||||
var f = Path.of("do.js");
|
var f = Path.of("do.js");
|
||||||
var func = args.ctx.compile(new Filename("do", "do/" + j++ + ".js"), new String(Files.readAllBytes(f)));
|
var func = Compiler.compile(args.env, new Filename("do", "do/" + j++ + ".js"), new String(Files.readAllBytes(f)));
|
||||||
return func.call(args.ctx);
|
return func.call(args.env);
|
||||||
}
|
}
|
||||||
catch (IOException e) {
|
catch (IOException e) {
|
||||||
throw new EngineException("Couldn't open do.js");
|
throw new EngineException("Couldn't open do.js");
|
||||||
@ -106,7 +104,7 @@ public class JScriptRepl {
|
|||||||
}));
|
}));
|
||||||
glob.define(null, false, new NativeFunction("log", args -> {
|
glob.define(null, false, new NativeFunction("log", args -> {
|
||||||
for (var el : args.args) {
|
for (var el : args.args) {
|
||||||
Values.printValue(args.ctx, el);
|
Values.printValue(args.env, el);
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
@ -120,7 +118,7 @@ public class JScriptRepl {
|
|||||||
environment.add(PermissionsProvider.KEY, PermissionsManager.ALL_PERMS);
|
environment.add(PermissionsProvider.KEY, PermissionsManager.ALL_PERMS);
|
||||||
environment.add(Filesystem.KEY, fs);
|
environment.add(Filesystem.KEY, fs);
|
||||||
environment.add(ModuleRepo.KEY, ModuleRepo.ofFilesystem(fs));
|
environment.add(ModuleRepo.KEY, ModuleRepo.ofFilesystem(fs));
|
||||||
environment.add(Compiler.KEY, new JSCompiler(new Context(environment)));
|
environment.add(Compiler.KEY, new JSCompiler(environment));
|
||||||
environment.add(EventLoop.KEY, engine);
|
environment.add(EventLoop.KEY, engine);
|
||||||
}
|
}
|
||||||
private static void initEngine() {
|
private static void initEngine() {
|
||||||
|
212
src/java/me/topchetoeu/jscript/utils/debug/ObjectManager.java
Normal file
212
src/java/me/topchetoeu/jscript/utils/debug/ObjectManager.java
Normal file
@ -0,0 +1,212 @@
|
|||||||
|
package me.topchetoeu.jscript.utils.debug;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
|
import me.topchetoeu.jscript.common.json.JSON;
|
||||||
|
import me.topchetoeu.jscript.common.json.JSONMap;
|
||||||
|
import me.topchetoeu.jscript.runtime.environment.Environment;
|
||||||
|
import me.topchetoeu.jscript.runtime.exceptions.EngineException;
|
||||||
|
import me.topchetoeu.jscript.runtime.values.ArrayValue;
|
||||||
|
import me.topchetoeu.jscript.runtime.values.FunctionValue;
|
||||||
|
import me.topchetoeu.jscript.runtime.values.ObjectValue;
|
||||||
|
import me.topchetoeu.jscript.runtime.values.Symbol;
|
||||||
|
import me.topchetoeu.jscript.runtime.values.Values;
|
||||||
|
|
||||||
|
class ObjectManager {
|
||||||
|
public static class ObjRef {
|
||||||
|
public final ObjectValue obj;
|
||||||
|
public final Environment ext;
|
||||||
|
public final HashSet<String> heldGroups = new HashSet<>();
|
||||||
|
public boolean held = true;
|
||||||
|
|
||||||
|
public boolean shouldRelease() {
|
||||||
|
return !held && heldGroups.size() == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ObjRef(Environment ext, ObjectValue obj) {
|
||||||
|
this.ext = ext;
|
||||||
|
this.obj = obj;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Supplier<Integer> idSupplier;
|
||||||
|
private HashMap<Integer, ObjRef> idToObject = new HashMap<>();
|
||||||
|
private HashMap<ObjectValue, Integer> objectToId = new HashMap<>();
|
||||||
|
private HashMap<String, ArrayList<ObjRef>> objectGroups = new HashMap<>();
|
||||||
|
|
||||||
|
public JSONMap serialize(Environment env, Object val, boolean byValue) {
|
||||||
|
val = Values.normalize(null, val);
|
||||||
|
env = SimpleDebugger.sanitizeEnvironment(env);
|
||||||
|
|
||||||
|
if (val == Values.NULL) {
|
||||||
|
return new JSONMap()
|
||||||
|
.set("type", "object")
|
||||||
|
.set("subtype", "null")
|
||||||
|
.setNull("value")
|
||||||
|
.set("description", "null");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (val instanceof ObjectValue) {
|
||||||
|
var obj = (ObjectValue)val;
|
||||||
|
int id;
|
||||||
|
|
||||||
|
if (objectToId.containsKey(obj)) id = objectToId.get(obj);
|
||||||
|
else {
|
||||||
|
id = idSupplier.get();
|
||||||
|
var ref = new ObjRef(env, obj);
|
||||||
|
objectToId.put(obj, id);
|
||||||
|
idToObject.put(id, ref);
|
||||||
|
}
|
||||||
|
|
||||||
|
var type = "object";
|
||||||
|
String subtype = null;
|
||||||
|
String className = null;
|
||||||
|
|
||||||
|
if (obj instanceof FunctionValue) type = "function";
|
||||||
|
if (obj instanceof ArrayValue) subtype = "array";
|
||||||
|
|
||||||
|
try { className = Values.toString(env, Values.getMemberPath(env, obj, "constructor", "name")); }
|
||||||
|
catch (Exception e) { }
|
||||||
|
|
||||||
|
var res = new JSONMap()
|
||||||
|
.set("type", type)
|
||||||
|
.set("objectId", id + "");
|
||||||
|
|
||||||
|
if (subtype != null) res.set("subtype", subtype);
|
||||||
|
if (className != null) {
|
||||||
|
res.set("className", className);
|
||||||
|
res.set("description", className);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (obj instanceof ArrayValue) res.set("description", "Array(" + ((ArrayValue)obj).size() + ")");
|
||||||
|
else if (obj instanceof FunctionValue) res.set("description", obj.toString());
|
||||||
|
else {
|
||||||
|
var defaultToString = false;
|
||||||
|
|
||||||
|
try {
|
||||||
|
defaultToString =
|
||||||
|
Values.getMember(env, obj, "toString") ==
|
||||||
|
Values.getMember(env, env.get(Environment.OBJECT_PROTO), "toString");
|
||||||
|
}
|
||||||
|
catch (Exception e) { }
|
||||||
|
|
||||||
|
try { res.set("description", className + (defaultToString ? "" : " { " + Values.toString(env, obj) + " }")); }
|
||||||
|
catch (Exception e) { }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (byValue) try { res.put("value", JSON.fromJs(env, obj)); }
|
||||||
|
catch (Exception e) { }
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (val == null) return new JSONMap().set("type", "undefined");
|
||||||
|
if (val instanceof String) return new JSONMap().set("type", "string").set("value", (String)val);
|
||||||
|
if (val instanceof Boolean) return new JSONMap().set("type", "boolean").set("value", (Boolean)val);
|
||||||
|
if (val instanceof Symbol) return new JSONMap().set("type", "symbol").set("description", val.toString());
|
||||||
|
if (val instanceof Number) {
|
||||||
|
var num = (double)(Number)val;
|
||||||
|
var res = new JSONMap().set("type", "number");
|
||||||
|
|
||||||
|
if (Double.POSITIVE_INFINITY == num) res.set("unserializableValue", "Infinity");
|
||||||
|
else if (Double.NEGATIVE_INFINITY == num) res.set("unserializableValue", "-Infinity");
|
||||||
|
else if (Double.doubleToRawLongBits(num) == Double.doubleToRawLongBits(-0d)) res.set("unserializableValue", "-0");
|
||||||
|
else if (Double.doubleToRawLongBits(num) == Double.doubleToRawLongBits(0d)) res.set("unserializableValue", "0");
|
||||||
|
else if (Double.isNaN(num)) res.set("unserializableValue", "NaN");
|
||||||
|
else res.set("value", num);
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new IllegalArgumentException("Unexpected JS object.");
|
||||||
|
}
|
||||||
|
public JSONMap serialize(Environment ext, Object val) {
|
||||||
|
return serialize(ext, val, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addToGroup(String name, Object val) {
|
||||||
|
if (val instanceof ObjectValue) {
|
||||||
|
var obj = (ObjectValue)val;
|
||||||
|
var id = objectToId.getOrDefault(obj, -1);
|
||||||
|
if (id < 0) return;
|
||||||
|
|
||||||
|
var ref = idToObject.get(id);
|
||||||
|
|
||||||
|
if (objectGroups.containsKey(name)) objectGroups.get(name).add(ref);
|
||||||
|
else objectGroups.put(name, new ArrayList<>(List.of(ref)));
|
||||||
|
|
||||||
|
ref.heldGroups.add(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public void removeGroup(String name) {
|
||||||
|
var objs = objectGroups.remove(name);
|
||||||
|
|
||||||
|
if (objs != null) {
|
||||||
|
for (var obj : objs) {
|
||||||
|
if (obj.heldGroups.remove(name) && obj.shouldRelease()) {
|
||||||
|
var id = objectToId.remove(obj.obj);
|
||||||
|
if (id != null) idToObject.remove(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public ObjRef get(int id) {
|
||||||
|
return idToObject.get(id);
|
||||||
|
}
|
||||||
|
public void release(int id) {
|
||||||
|
var ref = idToObject.get(id);
|
||||||
|
ref.held = false;
|
||||||
|
|
||||||
|
if (ref.shouldRelease()) {
|
||||||
|
objectToId.remove(ref.obj);
|
||||||
|
idToObject.remove(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object deserializeArgument(JSONMap val) {
|
||||||
|
if (val.isString("objectId")) return get(Integer.parseInt(val.string("objectId"))).obj;
|
||||||
|
else if (val.isString("unserializableValue")) switch (val.string("unserializableValue")) {
|
||||||
|
case "NaN": return Double.NaN;
|
||||||
|
case "-Infinity": return Double.NEGATIVE_INFINITY;
|
||||||
|
case "Infinity": return Double.POSITIVE_INFINITY;
|
||||||
|
case "-0": return -0.;
|
||||||
|
}
|
||||||
|
|
||||||
|
var res = val.get("value");
|
||||||
|
|
||||||
|
if (res == null) return null;
|
||||||
|
else return JSON.toJs(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
public JSONMap serializeException(Environment ext, EngineException err) {
|
||||||
|
String text = null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
text = Values.toString(ext, err.value);
|
||||||
|
}
|
||||||
|
catch (EngineException e) {
|
||||||
|
text = "[error while stringifying]";
|
||||||
|
}
|
||||||
|
|
||||||
|
return new JSONMap()
|
||||||
|
.set("exceptionId", idSupplier.get())
|
||||||
|
.set("exception", serialize(ext, err.value))
|
||||||
|
.set("text", text);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void clear() {
|
||||||
|
this.idToObject.clear();
|
||||||
|
this.objectToId.clear();
|
||||||
|
this.objectGroups.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
public ObjectManager(Supplier<Integer> idSupplier) {
|
||||||
|
this.idSupplier = idSupplier;
|
||||||
|
}
|
||||||
|
}
|
@ -23,20 +23,17 @@ import me.topchetoeu.jscript.common.json.JSONList;
|
|||||||
import me.topchetoeu.jscript.common.json.JSONMap;
|
import me.topchetoeu.jscript.common.json.JSONMap;
|
||||||
import me.topchetoeu.jscript.common.mapping.FunctionMap;
|
import me.topchetoeu.jscript.common.mapping.FunctionMap;
|
||||||
import me.topchetoeu.jscript.compilation.parsing.Parsing;
|
import me.topchetoeu.jscript.compilation.parsing.Parsing;
|
||||||
import me.topchetoeu.jscript.runtime.Context;
|
|
||||||
import me.topchetoeu.jscript.runtime.Engine;
|
import me.topchetoeu.jscript.runtime.Engine;
|
||||||
import me.topchetoeu.jscript.runtime.Environment;
|
|
||||||
import me.topchetoeu.jscript.runtime.EventLoop;
|
import me.topchetoeu.jscript.runtime.EventLoop;
|
||||||
import me.topchetoeu.jscript.runtime.Extensions;
|
|
||||||
import me.topchetoeu.jscript.runtime.Frame;
|
import me.topchetoeu.jscript.runtime.Frame;
|
||||||
import me.topchetoeu.jscript.runtime.debug.DebugContext;
|
import me.topchetoeu.jscript.runtime.debug.DebugContext;
|
||||||
|
import me.topchetoeu.jscript.runtime.environment.Environment;
|
||||||
import me.topchetoeu.jscript.runtime.exceptions.EngineException;
|
import me.topchetoeu.jscript.runtime.exceptions.EngineException;
|
||||||
import me.topchetoeu.jscript.runtime.exceptions.SyntaxException;
|
import me.topchetoeu.jscript.runtime.exceptions.SyntaxException;
|
||||||
import me.topchetoeu.jscript.runtime.scope.GlobalScope;
|
import me.topchetoeu.jscript.runtime.scope.GlobalScope;
|
||||||
import me.topchetoeu.jscript.runtime.values.ArrayValue;
|
import me.topchetoeu.jscript.runtime.values.ArrayValue;
|
||||||
import me.topchetoeu.jscript.runtime.values.FunctionValue;
|
import me.topchetoeu.jscript.runtime.values.FunctionValue;
|
||||||
import me.topchetoeu.jscript.runtime.values.ObjectValue;
|
import me.topchetoeu.jscript.runtime.values.ObjectValue;
|
||||||
import me.topchetoeu.jscript.runtime.values.Symbol;
|
|
||||||
import me.topchetoeu.jscript.runtime.values.Values;
|
import me.topchetoeu.jscript.runtime.values.Values;
|
||||||
|
|
||||||
// very simple indeed
|
// very simple indeed
|
||||||
@ -150,10 +147,10 @@ public class SimpleDebugger implements Debugger {
|
|||||||
this.frame = frame;
|
this.frame = frame;
|
||||||
this.id = id;
|
this.id = id;
|
||||||
|
|
||||||
this.global = GlobalScope.get(frame.ctx).obj;
|
this.global = GlobalScope.get(frame.env).obj;
|
||||||
this.local = frame.getLocalScope();
|
this.local = frame.getLocalScope();
|
||||||
this.capture = frame.getCaptureScope();
|
this.capture = frame.getCaptureScope();
|
||||||
Values.makePrototypeChain(frame.ctx, global, capture, local);
|
Values.makePrototypeChain(frame.env, global, capture, local);
|
||||||
this.valstack = frame.getValStackScope();
|
this.valstack = frame.getValStackScope();
|
||||||
|
|
||||||
this.serialized = new JSONMap()
|
this.serialized = new JSONMap()
|
||||||
@ -163,48 +160,32 @@ public class SimpleDebugger implements Debugger {
|
|||||||
.add(new JSONMap()
|
.add(new JSONMap()
|
||||||
.set("type", "local")
|
.set("type", "local")
|
||||||
.set("name", "Local Scope")
|
.set("name", "Local Scope")
|
||||||
.set("object", serializeObj(frame.ctx, local))
|
.set("object", objects.serialize(frame.env, local))
|
||||||
)
|
)
|
||||||
.add(new JSONMap()
|
.add(new JSONMap()
|
||||||
.set("type", "closure")
|
.set("type", "closure")
|
||||||
.set("name", "Closure")
|
.set("name", "Closure")
|
||||||
.set("object", serializeObj(frame.ctx, capture))
|
.set("object", objects.serialize(frame.env, capture))
|
||||||
)
|
)
|
||||||
.add(new JSONMap()
|
.add(new JSONMap()
|
||||||
.set("type", "global")
|
.set("type", "global")
|
||||||
.set("name", "Global Scope")
|
.set("name", "Global Scope")
|
||||||
.set("object", serializeObj(frame.ctx.extensions, global))
|
.set("object", objects.serialize(frame.env, global))
|
||||||
)
|
)
|
||||||
.add(new JSONMap()
|
.add(new JSONMap()
|
||||||
.set("type", "other")
|
.set("type", "other")
|
||||||
.set("name", "Value Stack")
|
.set("name", "Value Stack")
|
||||||
.set("object", serializeObj(frame.ctx.extensions, valstack))
|
.set("object", objects.serialize(frame.env, valstack))
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private class ObjRef {
|
|
||||||
public final ObjectValue obj;
|
|
||||||
public final Extensions ext;
|
|
||||||
public final HashSet<String> heldGroups = new HashSet<>();
|
|
||||||
public boolean held = true;
|
|
||||||
|
|
||||||
public boolean shouldRelease() {
|
|
||||||
return !held && heldGroups.size() == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ObjRef(Extensions ext, ObjectValue obj) {
|
|
||||||
this.ext = ext;
|
|
||||||
this.obj = obj;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class RunResult {
|
private static class RunResult {
|
||||||
public final Extensions ext;
|
public final Environment ext;
|
||||||
public final Object result;
|
public final Object result;
|
||||||
public final EngineException error;
|
public final EngineException error;
|
||||||
|
|
||||||
public RunResult(Extensions ext, Object result, EngineException error) {
|
public RunResult(Environment ext, Object result, EngineException error) {
|
||||||
this.ext = ext;
|
this.ext = ext;
|
||||||
this.result = result;
|
this.result = result;
|
||||||
this.error = error;
|
this.error = error;
|
||||||
@ -232,15 +213,17 @@ public class SimpleDebugger implements Debugger {
|
|||||||
private HashMap<Integer, DebugFrame> idToFrame = new HashMap<>();
|
private HashMap<Integer, DebugFrame> idToFrame = new HashMap<>();
|
||||||
private HashMap<Frame, DebugFrame> codeFrameToFrame = new HashMap<>();
|
private HashMap<Frame, DebugFrame> codeFrameToFrame = new HashMap<>();
|
||||||
|
|
||||||
private HashMap<Integer, ObjRef> idToObject = new HashMap<>();
|
private ObjectManager objects = new ObjectManager(this::nextId);
|
||||||
private HashMap<ObjectValue, Integer> objectToId = new HashMap<>();
|
// private HashMap<Integer, ObjRef> idToObject = new HashMap<>();
|
||||||
private HashMap<String, ArrayList<ObjRef>> objectGroups = new HashMap<>();
|
// private HashMap<ObjectValue, Integer> objectToId = new HashMap<>();
|
||||||
|
// private HashMap<String, ArrayList<ObjRef>> objectGroups = new HashMap<>();
|
||||||
|
|
||||||
private Notifier updateNotifier = new Notifier();
|
private Notifier updateNotifier = new Notifier();
|
||||||
private boolean pendingPause = false;
|
private boolean pendingPause = false;
|
||||||
|
|
||||||
private int nextId = 0;
|
private int nextId = 0;
|
||||||
private DebugFrame stepOutFrame = null, currFrame = null;
|
private DebugFrame stepOutFrame = null;
|
||||||
|
private List<DebugFrame> frames = new ArrayList<>();
|
||||||
private int stepOutPtr = 0;
|
private int stepOutPtr = 0;
|
||||||
|
|
||||||
private boolean compare(String src, String target) {
|
private boolean compare(String src, String target) {
|
||||||
@ -288,18 +271,14 @@ public class SimpleDebugger implements Debugger {
|
|||||||
}
|
}
|
||||||
else return codeFrameToFrame.get(frame);
|
else return codeFrameToFrame.get(frame);
|
||||||
}
|
}
|
||||||
private synchronized void updateFrames(Context ctx) {
|
|
||||||
var frame = ctx.frame;
|
|
||||||
if (frame == null) return;
|
|
||||||
|
|
||||||
currFrame = getFrame(frame);
|
private JSONList serializeFrames(Environment env) {
|
||||||
}
|
|
||||||
private JSONList serializeFrames(Context ctx) {
|
|
||||||
var res = new JSONList();
|
var res = new JSONList();
|
||||||
|
|
||||||
for (var el : ctx.frames()) {
|
for (var el : DebugContext.get(env).getStackFrames()) {
|
||||||
var frame = getFrame(el);
|
var frame = getFrame(el);
|
||||||
if (frame.location == null) continue;
|
if (frame.location == null) continue;
|
||||||
|
|
||||||
frame.serialized.set("location", serializeLocation(frame.location));
|
frame.serialized.set("location", serializeLocation(frame.location));
|
||||||
if (frame.location != null) res.add(frame.serialized);
|
if (frame.location != null) res.add(frame.serialized);
|
||||||
}
|
}
|
||||||
@ -339,151 +318,6 @@ public class SimpleDebugger implements Debugger {
|
|||||||
.set("columnNumber", loc.start() - 1);
|
.set("columnNumber", loc.start() - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
private JSONMap serializeObj(Extensions env, Object val, boolean byValue) {
|
|
||||||
val = Values.normalize(null, val);
|
|
||||||
env = sanitizeEnvironment(env);
|
|
||||||
var ctx = Context.of(env);
|
|
||||||
|
|
||||||
if (val == Values.NULL) {
|
|
||||||
return new JSONMap()
|
|
||||||
.set("type", "object")
|
|
||||||
.set("subtype", "null")
|
|
||||||
.setNull("value")
|
|
||||||
.set("description", "null");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (val instanceof ObjectValue) {
|
|
||||||
var obj = (ObjectValue)val;
|
|
||||||
int id;
|
|
||||||
|
|
||||||
if (objectToId.containsKey(obj)) id = objectToId.get(obj);
|
|
||||||
else {
|
|
||||||
id = nextId();
|
|
||||||
var ref = new ObjRef(env, obj);
|
|
||||||
objectToId.put(obj, id);
|
|
||||||
idToObject.put(id, ref);
|
|
||||||
}
|
|
||||||
|
|
||||||
var type = "object";
|
|
||||||
String subtype = null;
|
|
||||||
String className = null;
|
|
||||||
|
|
||||||
if (obj instanceof FunctionValue) type = "function";
|
|
||||||
if (obj instanceof ArrayValue) subtype = "array";
|
|
||||||
|
|
||||||
try { className = Values.toString(ctx, Values.getMemberPath(ctx, obj, "constructor", "name")); }
|
|
||||||
catch (Exception e) { }
|
|
||||||
|
|
||||||
var res = new JSONMap()
|
|
||||||
.set("type", type)
|
|
||||||
.set("objectId", id + "");
|
|
||||||
|
|
||||||
if (subtype != null) res.set("subtype", subtype);
|
|
||||||
if (className != null) {
|
|
||||||
res.set("className", className);
|
|
||||||
res.set("description", className);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (obj instanceof ArrayValue) res.set("description", "Array(" + ((ArrayValue)obj).size() + ")");
|
|
||||||
else if (obj instanceof FunctionValue) res.set("description", obj.toString());
|
|
||||||
else {
|
|
||||||
var defaultToString = false;
|
|
||||||
|
|
||||||
try {
|
|
||||||
defaultToString =
|
|
||||||
Values.getMember(ctx, obj, "toString") ==
|
|
||||||
Values.getMember(ctx, env.get(Environment.OBJECT_PROTO), "toString");
|
|
||||||
}
|
|
||||||
catch (Exception e) { }
|
|
||||||
|
|
||||||
try { res.set("description", className + (defaultToString ? "" : " { " + Values.toString(ctx, obj) + " }")); }
|
|
||||||
catch (Exception e) { }
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (byValue) try { res.put("value", JSON.fromJs(env, obj)); }
|
|
||||||
catch (Exception e) { }
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (val == null) return new JSONMap().set("type", "undefined");
|
|
||||||
if (val instanceof String) return new JSONMap().set("type", "string").set("value", (String)val);
|
|
||||||
if (val instanceof Boolean) return new JSONMap().set("type", "boolean").set("value", (Boolean)val);
|
|
||||||
if (val instanceof Symbol) return new JSONMap().set("type", "symbol").set("description", val.toString());
|
|
||||||
if (val instanceof Number) {
|
|
||||||
var num = (double)(Number)val;
|
|
||||||
var res = new JSONMap().set("type", "number");
|
|
||||||
|
|
||||||
if (Double.POSITIVE_INFINITY == num) res.set("unserializableValue", "Infinity");
|
|
||||||
else if (Double.NEGATIVE_INFINITY == num) res.set("unserializableValue", "-Infinity");
|
|
||||||
else if (Double.doubleToRawLongBits(num) == Double.doubleToRawLongBits(-0d)) res.set("unserializableValue", "-0");
|
|
||||||
else if (Double.doubleToRawLongBits(num) == Double.doubleToRawLongBits(0d)) res.set("unserializableValue", "0");
|
|
||||||
else if (Double.isNaN(num)) res.set("unserializableValue", "NaN");
|
|
||||||
else res.set("value", num);
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new IllegalArgumentException("Unexpected JS object.");
|
|
||||||
}
|
|
||||||
private JSONMap serializeObj(Extensions ext, Object val) {
|
|
||||||
return serializeObj(ext, val, false);
|
|
||||||
}
|
|
||||||
private void addObjectGroup(String name, Object val) {
|
|
||||||
if (val instanceof ObjectValue) {
|
|
||||||
var obj = (ObjectValue)val;
|
|
||||||
var id = objectToId.getOrDefault(obj, -1);
|
|
||||||
if (id < 0) return;
|
|
||||||
|
|
||||||
var ref = idToObject.get(id);
|
|
||||||
|
|
||||||
if (objectGroups.containsKey(name)) objectGroups.get(name).add(ref);
|
|
||||||
else objectGroups.put(name, new ArrayList<>(List.of(ref)));
|
|
||||||
|
|
||||||
ref.heldGroups.add(name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
private void releaseGroup(String name) {
|
|
||||||
var objs = objectGroups.remove(name);
|
|
||||||
|
|
||||||
if (objs != null) for (var obj : objs) {
|
|
||||||
if (obj.heldGroups.remove(name) && obj.shouldRelease()) {
|
|
||||||
var id = objectToId.remove(obj.obj);
|
|
||||||
if (id != null) idToObject.remove(id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
private Object deserializeArgument(JSONMap val) {
|
|
||||||
if (val.isString("objectId")) return idToObject.get(Integer.parseInt(val.string("objectId"))).obj;
|
|
||||||
else if (val.isString("unserializableValue")) switch (val.string("unserializableValue")) {
|
|
||||||
case "NaN": return Double.NaN;
|
|
||||||
case "-Infinity": return Double.NEGATIVE_INFINITY;
|
|
||||||
case "Infinity": return Double.POSITIVE_INFINITY;
|
|
||||||
case "-0": return -0.;
|
|
||||||
}
|
|
||||||
var res = val.get("value");
|
|
||||||
if (res == null) return null;
|
|
||||||
else return JSON.toJs(res);
|
|
||||||
}
|
|
||||||
|
|
||||||
private JSONMap serializeException(Extensions ext, EngineException err) {
|
|
||||||
String text = null;
|
|
||||||
|
|
||||||
try {
|
|
||||||
text = Values.toString(Context.of(ext), err.value);
|
|
||||||
}
|
|
||||||
catch (EngineException e) {
|
|
||||||
text = "[error while stringifying]";
|
|
||||||
}
|
|
||||||
|
|
||||||
var res = new JSONMap()
|
|
||||||
.set("exceptionId", nextId())
|
|
||||||
.set("exception", serializeObj(ext, err.value))
|
|
||||||
.set("text", text);
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void resume(State state) {
|
private void resume(State state) {
|
||||||
try {
|
try {
|
||||||
@ -496,11 +330,11 @@ public class SimpleDebugger implements Debugger {
|
|||||||
close();
|
close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private void pauseDebug(Context ctx, Breakpoint bp) {
|
private void pauseDebug(Environment env, Breakpoint bp) {
|
||||||
try {
|
try {
|
||||||
state = State.PAUSED_NORMAL;
|
state = State.PAUSED_NORMAL;
|
||||||
var map = new JSONMap()
|
var map = new JSONMap()
|
||||||
.set("callFrames", serializeFrames(ctx))
|
.set("callFrames", serializeFrames(env))
|
||||||
.set("reason", "debugCommand");
|
.set("reason", "debugCommand");
|
||||||
|
|
||||||
if (bp != null) map.set("hitBreakpoints", new JSONList().add(bp.id + ""));
|
if (bp != null) map.set("hitBreakpoints", new JSONList().add(bp.id + ""));
|
||||||
@ -511,11 +345,11 @@ public class SimpleDebugger implements Debugger {
|
|||||||
close();
|
close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private void pauseException(Context ctx) {
|
private void pauseException(Environment env) {
|
||||||
try {
|
try {
|
||||||
state = State.PAUSED_EXCEPTION;
|
state = State.PAUSED_EXCEPTION;
|
||||||
var map = new JSONMap()
|
var map = new JSONMap()
|
||||||
.set("callFrames", serializeFrames(ctx))
|
.set("callFrames", serializeFrames(env))
|
||||||
.set("reason", "exception");
|
.set("reason", "exception");
|
||||||
|
|
||||||
ws.send(new V8Event("Debugger.paused", map));
|
ws.send(new V8Event("Debugger.paused", map));
|
||||||
@ -540,26 +374,19 @@ public class SimpleDebugger implements Debugger {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Extensions sanitizeEnvironment(Extensions ext) {
|
static Environment sanitizeEnvironment(Environment env) {
|
||||||
var res = ext.child();
|
return env.child().remove(EventLoop.KEY).remove(DebugContext.KEY).add(DebugContext.IGNORE);
|
||||||
|
|
||||||
res.remove(EventLoop.KEY);
|
|
||||||
res.remove(DebugContext.KEY);
|
|
||||||
res.add(DebugContext.IGNORE);
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private RunResult run(DebugFrame codeFrame, String code) {
|
private RunResult run(DebugFrame codeFrame, String code) {
|
||||||
if (codeFrame == null) return new RunResult(null, code, new EngineException("Invalid code frame!"));
|
if (codeFrame == null) return new RunResult(null, code, new EngineException("Invalid code frame!"));
|
||||||
var engine = new Engine();
|
var engine = new Engine();
|
||||||
var env = codeFrame.frame.ctx.extensions.copy();
|
|
||||||
|
|
||||||
env.remove(DebugContext.KEY);
|
var env = codeFrame.frame.env.child()
|
||||||
env.remove(EventLoop.KEY);
|
.remove(DebugContext.KEY)
|
||||||
env.remove(GlobalScope.KEY);
|
.add(DebugContext.IGNORE)
|
||||||
env.add(EventLoop.KEY, engine);
|
.add(EventLoop.KEY, engine)
|
||||||
env.add(GlobalScope.KEY, new GlobalScope(codeFrame.local));
|
.add(GlobalScope.KEY, new GlobalScope(codeFrame.local));
|
||||||
|
|
||||||
var awaiter = engine.pushMsg(false, env, new Filename("jscript", "eval"), code, codeFrame.frame.thisArg, codeFrame.frame.args);
|
var awaiter = engine.pushMsg(false, env, new Filename("jscript", "eval"), code, codeFrame.frame.thisArg, codeFrame.frame.args);
|
||||||
|
|
||||||
@ -571,20 +398,19 @@ public class SimpleDebugger implements Debugger {
|
|||||||
catch (SyntaxException e) { return new RunResult(env, null, EngineException.ofSyntax(e.toString())); }
|
catch (SyntaxException e) { return new RunResult(env, null, EngineException.ofSyntax(e.toString())); }
|
||||||
}
|
}
|
||||||
|
|
||||||
private ObjectValue vscodeAutoSuggest(Extensions ext, Object target, String query, boolean variable) {
|
private ObjectValue vscodeAutoSuggest(Environment env, Object target, String query, boolean variable) {
|
||||||
var res = new ArrayValue();
|
var res = new ArrayValue();
|
||||||
var passed = new HashSet<String>();
|
var passed = new HashSet<String>();
|
||||||
var tildas = "~";
|
var tildas = "~";
|
||||||
var ctx = Context.of(ext);
|
if (target == null) target = GlobalScope.get(env);
|
||||||
if (target == null) target = GlobalScope.get(ext);
|
|
||||||
|
|
||||||
for (var proto = target; proto != null && proto != Values.NULL; proto = Values.getPrototype(ctx, proto)) {
|
for (var proto = target; proto != null && proto != Values.NULL; proto = Values.getPrototype(env, proto)) {
|
||||||
for (var el : Values.getMembers(ctx, proto, true, true)) {
|
for (var el : Values.getMembers(env, proto, true, true)) {
|
||||||
var strKey = Values.toString(ctx, el);
|
var strKey = Values.toString(env, el);
|
||||||
if (passed.contains(strKey)) continue;
|
if (passed.contains(strKey)) continue;
|
||||||
passed.add(strKey);
|
passed.add(strKey);
|
||||||
|
|
||||||
var val = Values.getMember(ctx, Values.getMemberDescriptor(ctx, proto, el), "value");
|
var val = Values.getMember(env, Values.getMemberDescriptor(env, proto, el), "value");
|
||||||
var desc = new ObjectValue();
|
var desc = new ObjectValue();
|
||||||
var sortText = "";
|
var sortText = "";
|
||||||
if (strKey.startsWith(query)) sortText += "0@";
|
if (strKey.startsWith(query)) sortText += "0@";
|
||||||
@ -594,27 +420,27 @@ public class SimpleDebugger implements Debugger {
|
|||||||
else sortText += "4@";
|
else sortText += "4@";
|
||||||
sortText += tildas + strKey;
|
sortText += tildas + strKey;
|
||||||
|
|
||||||
desc.defineProperty(ctx, "label", strKey);
|
desc.defineProperty(env, "label", strKey);
|
||||||
desc.defineProperty(ctx, "sortText", sortText);
|
desc.defineProperty(env, "sortText", sortText);
|
||||||
|
|
||||||
if (val instanceof FunctionValue) {
|
if (val instanceof FunctionValue) {
|
||||||
if (strKey.equals("constructor")) desc.defineProperty(ctx, "type", "name");
|
if (strKey.equals("constructor")) desc.defineProperty(env, "type", "name");
|
||||||
else desc.defineProperty(ctx, "type", variable ? "function" : "method");
|
else desc.defineProperty(env, "type", variable ? "function" : "method");
|
||||||
}
|
}
|
||||||
else desc.defineProperty(ctx, "type", variable ? "variable" : "property");
|
else desc.defineProperty(env, "type", variable ? "variable" : "property");
|
||||||
|
|
||||||
switch (Values.type(val)) {
|
switch (Values.type(val)) {
|
||||||
case "number":
|
case "number":
|
||||||
case "boolean":
|
case "boolean":
|
||||||
desc.defineProperty(ctx, "detail", Values.toString(ctx, val));
|
desc.defineProperty(env, "detail", Values.toString(env, val));
|
||||||
break;
|
break;
|
||||||
case "object":
|
case "object":
|
||||||
if (val == Values.NULL) desc.defineProperty(ctx, "detail", "null");
|
if (val == Values.NULL) desc.defineProperty(env, "detail", "null");
|
||||||
else try {
|
else try {
|
||||||
desc.defineProperty(ctx, "detail", Values.getMemberPath(ctx, target, "constructor", "name"));
|
desc.defineProperty(env, "detail", Values.getMemberPath(env, target, "constructor", "name"));
|
||||||
}
|
}
|
||||||
catch (IllegalArgumentException e) {
|
catch (IllegalArgumentException e) {
|
||||||
desc.defineProperty(ctx, "detail", "object");
|
desc.defineProperty(env, "detail", "object");
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case "function": {
|
case "function": {
|
||||||
@ -624,15 +450,15 @@ public class SimpleDebugger implements Debugger {
|
|||||||
type += "?";
|
type += "?";
|
||||||
}
|
}
|
||||||
type += ")";
|
type += ")";
|
||||||
desc.defineProperty(ctx, "detail", type);
|
desc.defineProperty(env, "detail", type);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
desc.defineProperty(ctx, "type", Values.type(val));
|
desc.defineProperty(env, "type", Values.type(val));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
res.set(ctx, res.size(), desc);
|
res.set(env, res.size(), desc);
|
||||||
}
|
}
|
||||||
|
|
||||||
tildas += "~";
|
tildas += "~";
|
||||||
@ -640,8 +466,8 @@ public class SimpleDebugger implements Debugger {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var resObj = new ObjectValue();
|
var resObj = new ObjectValue();
|
||||||
resObj.defineProperty(ctx, "result", res);
|
resObj.defineProperty(env, "result", res);
|
||||||
resObj.defineProperty(ctx, "isArray", target instanceof ArrayValue);
|
resObj.defineProperty(env, "isArray", target instanceof ArrayValue);
|
||||||
return resObj;
|
return resObj;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -679,13 +505,12 @@ public class SimpleDebugger implements Debugger {
|
|||||||
idToFrame.clear();
|
idToFrame.clear();
|
||||||
codeFrameToFrame.clear();
|
codeFrameToFrame.clear();
|
||||||
|
|
||||||
idToObject.clear();
|
objects.clear();
|
||||||
objectToId.clear();
|
|
||||||
objectGroups.clear();
|
|
||||||
|
|
||||||
pendingPause = false;
|
pendingPause = false;
|
||||||
|
|
||||||
stepOutFrame = currFrame = null;
|
frames.clear();
|
||||||
|
stepOutFrame = null;
|
||||||
stepOutPtr = 0;
|
stepOutPtr = 0;
|
||||||
|
|
||||||
for (var ctx : contexts.keySet()) ctx.detachDebugger(this);
|
for (var ctx : contexts.keySet()) ctx.detachDebugger(this);
|
||||||
@ -744,7 +569,6 @@ public class SimpleDebugger implements Debugger {
|
|||||||
var bpt = new Breakpoint(nextId(), regex, line, col, cond);
|
var bpt = new Breakpoint(nextId(), regex, line, col, cond);
|
||||||
idToBreakpoint.put(bpt.id, bpt);
|
idToBreakpoint.put(bpt.id, bpt);
|
||||||
|
|
||||||
|
|
||||||
for (var el : mappings.entrySet()) {
|
for (var el : mappings.entrySet()) {
|
||||||
bpt.addFunc(el.getKey(), el.getValue());
|
bpt.addFunc(el.getKey(), el.getValue());
|
||||||
}
|
}
|
||||||
@ -794,8 +618,8 @@ public class SimpleDebugger implements Debugger {
|
|||||||
@Override public synchronized void stepInto(V8Message msg) throws IOException {
|
@Override public synchronized void stepInto(V8Message msg) throws IOException {
|
||||||
if (state == State.RESUMED) ws.send(new V8Error("Debugger is resumed."));
|
if (state == State.RESUMED) ws.send(new V8Error("Debugger is resumed."));
|
||||||
else {
|
else {
|
||||||
stepOutFrame = currFrame;
|
stepOutFrame = frames.get(frames.size() - 1);
|
||||||
stepOutPtr = currFrame.frame.codePtr;
|
stepOutPtr = stepOutFrame.frame.codePtr;
|
||||||
resume(State.STEPPING_IN);
|
resume(State.STEPPING_IN);
|
||||||
ws.send(msg.respond());
|
ws.send(msg.respond());
|
||||||
}
|
}
|
||||||
@ -803,8 +627,8 @@ public class SimpleDebugger implements Debugger {
|
|||||||
@Override public synchronized void stepOut(V8Message msg) throws IOException {
|
@Override public synchronized void stepOut(V8Message msg) throws IOException {
|
||||||
if (state == State.RESUMED) ws.send(new V8Error("Debugger is resumed."));
|
if (state == State.RESUMED) ws.send(new V8Error("Debugger is resumed."));
|
||||||
else {
|
else {
|
||||||
stepOutFrame = currFrame;
|
stepOutFrame = frames.get(frames.size() - 1);
|
||||||
stepOutPtr = currFrame.frame.codePtr;
|
stepOutPtr = stepOutFrame.frame.codePtr;
|
||||||
resume(State.STEPPING_OUT);
|
resume(State.STEPPING_OUT);
|
||||||
ws.send(msg.respond());
|
ws.send(msg.respond());
|
||||||
}
|
}
|
||||||
@ -812,8 +636,8 @@ public class SimpleDebugger implements Debugger {
|
|||||||
@Override public synchronized void stepOver(V8Message msg) throws IOException {
|
@Override public synchronized void stepOver(V8Message msg) throws IOException {
|
||||||
if (state == State.RESUMED) ws.send(new V8Error("Debugger is resumed."));
|
if (state == State.RESUMED) ws.send(new V8Error("Debugger is resumed."));
|
||||||
else {
|
else {
|
||||||
stepOutFrame = currFrame;
|
stepOutFrame = frames.get(frames.size() - 1);
|
||||||
stepOutPtr = currFrame.frame.codePtr;
|
stepOutPtr = stepOutFrame.frame.codePtr;
|
||||||
resume(State.STEPPING_OVER);
|
resume(State.STEPPING_OVER);
|
||||||
ws.send(msg.respond());
|
ws.send(msg.respond());
|
||||||
}
|
}
|
||||||
@ -827,34 +651,26 @@ public class SimpleDebugger implements Debugger {
|
|||||||
var cf = idToFrame.get(cfId);
|
var cf = idToFrame.get(cfId);
|
||||||
var res = run(cf, expr);
|
var res = run(cf, expr);
|
||||||
|
|
||||||
if (group != null) addObjectGroup(group, res.result);
|
if (group != null) objects.addToGroup(group, res.result);
|
||||||
|
|
||||||
if (res.error != null) ws.send(msg.respond(new JSONMap().set("exceptionDetails", serializeException(res.ext, res.error))));
|
if (res.error != null) ws.send(msg.respond(new JSONMap().set("exceptionDetails", objects.serializeException(res.ext, res.error))));
|
||||||
else ws.send(msg.respond(new JSONMap().set("result", serializeObj(res.ext, res.result))));
|
else ws.send(msg.respond(new JSONMap().set("result", objects.serialize(res.ext, res.result))));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override public synchronized void releaseObjectGroup(V8Message msg) throws IOException {
|
@Override public synchronized void releaseObjectGroup(V8Message msg) throws IOException {
|
||||||
var group = msg.params.string("objectGroup");
|
var group = msg.params.string("objectGroup");
|
||||||
releaseGroup(group);
|
objects.removeGroup(group);
|
||||||
ws.send(msg.respond());
|
ws.send(msg.respond());
|
||||||
}
|
}
|
||||||
@Override public synchronized void releaseObject(V8Message msg) throws IOException {
|
@Override public synchronized void releaseObject(V8Message msg) throws IOException {
|
||||||
var id = Integer.parseInt(msg.params.string("objectId"));
|
var id = Integer.parseInt(msg.params.string("objectId"));
|
||||||
var ref = idToObject.get(id);
|
objects.release(id);
|
||||||
ref.held = false;
|
|
||||||
|
|
||||||
if (ref.shouldRelease()) {
|
|
||||||
objectToId.remove(ref.obj);
|
|
||||||
idToObject.remove(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
ws.send(msg.respond());
|
ws.send(msg.respond());
|
||||||
}
|
}
|
||||||
@Override public synchronized void getProperties(V8Message msg) throws IOException {
|
@Override public synchronized void getProperties(V8Message msg) throws IOException {
|
||||||
var ref = idToObject.get(Integer.parseInt(msg.params.string("objectId")));
|
var ref = objects.get(Integer.parseInt(msg.params.string("objectId")));
|
||||||
var obj = ref.obj;
|
var obj = ref.obj;
|
||||||
var ext = ref.ext;
|
var env = ref.ext;
|
||||||
var ctx = Context.of(ext);
|
|
||||||
var res = new JSONList();
|
var res = new JSONList();
|
||||||
var own = true;
|
var own = true;
|
||||||
|
|
||||||
@ -866,17 +682,17 @@ public class SimpleDebugger implements Debugger {
|
|||||||
if (obj.properties.containsKey(key)) {
|
if (obj.properties.containsKey(key)) {
|
||||||
var prop = obj.properties.get(key);
|
var prop = obj.properties.get(key);
|
||||||
|
|
||||||
propDesc.set("name", Values.toString(ctx, key));
|
propDesc.set("name", Values.toString(env, key));
|
||||||
if (prop.getter != null) propDesc.set("get", serializeObj(ext, prop.getter));
|
if (prop.getter != null) propDesc.set("get", objects.serialize(env, prop.getter));
|
||||||
if (prop.setter != null) propDesc.set("set", serializeObj(ext, prop.setter));
|
if (prop.setter != null) propDesc.set("set", objects.serialize(env, prop.setter));
|
||||||
propDesc.set("enumerable", obj.memberEnumerable(key));
|
propDesc.set("enumerable", obj.memberEnumerable(key));
|
||||||
propDesc.set("configurable", obj.memberConfigurable(key));
|
propDesc.set("configurable", obj.memberConfigurable(key));
|
||||||
propDesc.set("isOwn", true);
|
propDesc.set("isOwn", true);
|
||||||
res.add(propDesc);
|
res.add(propDesc);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
propDesc.set("name", Values.toString(ctx, key));
|
propDesc.set("name", Values.toString(env, key));
|
||||||
propDesc.set("value", serializeObj(ext, Values.getMember(ctx, obj, key)));
|
propDesc.set("value", objects.serialize(env, Values.getMember(env, obj, key)));
|
||||||
propDesc.set("writable", obj.memberWritable(key));
|
propDesc.set("writable", obj.memberWritable(key));
|
||||||
propDesc.set("enumerable", obj.memberEnumerable(key));
|
propDesc.set("enumerable", obj.memberEnumerable(key));
|
||||||
propDesc.set("configurable", obj.memberConfigurable(key));
|
propDesc.set("configurable", obj.memberConfigurable(key));
|
||||||
@ -885,12 +701,12 @@ public class SimpleDebugger implements Debugger {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var proto = Values.getPrototype(ctx, obj);
|
var proto = Values.getPrototype(env, obj);
|
||||||
|
|
||||||
if (own) {
|
if (own) {
|
||||||
var protoDesc = new JSONMap();
|
var protoDesc = new JSONMap();
|
||||||
protoDesc.set("name", "__proto__");
|
protoDesc.set("name", "__proto__");
|
||||||
protoDesc.set("value", serializeObj(ext, proto == null ? Values.NULL : proto));
|
protoDesc.set("value", objects.serialize(env, proto == null ? Values.NULL : proto));
|
||||||
protoDesc.set("writable", true);
|
protoDesc.set("writable", true);
|
||||||
protoDesc.set("enumerable", false);
|
protoDesc.set("enumerable", false);
|
||||||
protoDesc.set("configurable", false);
|
protoDesc.set("configurable", false);
|
||||||
@ -911,14 +727,13 @@ public class SimpleDebugger implements Debugger {
|
|||||||
.list("arguments", new JSONList())
|
.list("arguments", new JSONList())
|
||||||
.stream()
|
.stream()
|
||||||
.map(v -> v.map())
|
.map(v -> v.map())
|
||||||
.map(this::deserializeArgument)
|
.map(objects::deserializeArgument)
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
var byValue = msg.params.bool("returnByValue", false);
|
var byValue = msg.params.bool("returnByValue", false);
|
||||||
|
|
||||||
var thisArgRef = idToObject.get(Integer.parseInt(msg.params.string("objectId")));
|
var thisArgRef = objects.get(Integer.parseInt(msg.params.string("objectId")));
|
||||||
var thisArg = thisArgRef.obj;
|
var thisArg = thisArgRef.obj;
|
||||||
var ext = thisArgRef.ext;
|
var env = thisArgRef.ext;
|
||||||
var ctx = Context.of(ext);
|
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
var start = src.lastIndexOf("//# sourceURL=");
|
var start = src.lastIndexOf("//# sourceURL=");
|
||||||
@ -934,27 +749,27 @@ public class SimpleDebugger implements Debugger {
|
|||||||
else if (compare(src, VSCODE_SELF)) res = thisArg;
|
else if (compare(src, VSCODE_SELF)) res = thisArg;
|
||||||
else if (compare(src, CHROME_GET_PROP_FUNC)) {
|
else if (compare(src, CHROME_GET_PROP_FUNC)) {
|
||||||
res = thisArg;
|
res = thisArg;
|
||||||
for (var el : JSON.parse(null, (String)args.get(0)).list()) res = Values.getMember(ctx, res, JSON.toJs(el));
|
for (var el : JSON.parse(null, (String)args.get(0)).list()) res = Values.getMember(env, res, JSON.toJs(el));
|
||||||
}
|
}
|
||||||
else if (compare(src, CHROME_GET_PROP_FUNC_2)) {
|
else if (compare(src, CHROME_GET_PROP_FUNC_2)) {
|
||||||
res = Values.call(ctx, args.get(0), thisArg);
|
res = Values.call(env, args.get(0), thisArg);
|
||||||
}
|
}
|
||||||
else if (compare(src, VSCODE_CALL)) {
|
else if (compare(src, VSCODE_CALL)) {
|
||||||
var func = (FunctionValue)(args.size() < 1 ? null : args.get(0));
|
var func = (FunctionValue)(args.size() < 1 ? null : args.get(0));
|
||||||
ws.send(msg.respond(new JSONMap().set("result", serializeObj(ext, func.call(ctx, thisArg)))));
|
ws.send(msg.respond(new JSONMap().set("result", objects.serialize(env, func.call(env, thisArg)))));
|
||||||
}
|
}
|
||||||
else if (compare(src, VSCODE_AUTOCOMPLETE)) {
|
else if (compare(src, VSCODE_AUTOCOMPLETE)) {
|
||||||
var target = args.get(0);
|
var target = args.get(0);
|
||||||
if (target == null) target = thisArg;
|
if (target == null) target = thisArg;
|
||||||
res = vscodeAutoSuggest(ext, target, Values.toString(ctx, args.get(1)), Values.toBoolean(args.get(2)));
|
res = vscodeAutoSuggest(env, target, Values.toString(env, args.get(1)), Values.toBoolean(args.get(2)));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
ws.send(new V8Error("Please use well-known functions with callFunctionOn"));
|
ws.send(new V8Error("Please use well-known functions with callFunctionOn"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
ws.send(msg.respond(new JSONMap().set("result", serializeObj(ext, res, byValue))));
|
ws.send(msg.respond(new JSONMap().set("result", objects.serialize(env, res, byValue))));
|
||||||
}
|
}
|
||||||
catch (EngineException e) { ws.send(msg.respond(new JSONMap().set("exceptionDetails", serializeException(ext, e)))); }
|
catch (EngineException e) { ws.send(msg.respond(new JSONMap().set("exceptionDetails", objects.serializeException(env, e)))); }
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override public synchronized void runtimeEnable(V8Message msg) throws IOException {
|
@Override public synchronized void runtimeEnable(V8Message msg) throws IOException {
|
||||||
@ -977,7 +792,7 @@ public class SimpleDebugger implements Debugger {
|
|||||||
}
|
}
|
||||||
mappings.put(body, map);
|
mappings.put(body, map);
|
||||||
}
|
}
|
||||||
@Override public boolean onInstruction(Context ctx, Frame cf, Instruction instruction, Object returnVal, EngineException error, boolean caught) {
|
@Override public boolean onInstruction(Environment env, Frame cf, Instruction instruction, Object returnVal, EngineException error, boolean caught) {
|
||||||
if (!enabled) return false;
|
if (!enabled) return false;
|
||||||
|
|
||||||
boolean isBreakpointable;
|
boolean isBreakpointable;
|
||||||
@ -988,7 +803,7 @@ public class SimpleDebugger implements Debugger {
|
|||||||
synchronized (this) {
|
synchronized (this) {
|
||||||
frame = getFrame(cf);
|
frame = getFrame(cf);
|
||||||
|
|
||||||
var map = DebugContext.get(ctx).getMap(frame.frame.function);
|
var map = DebugContext.get(env).getMap(frame.frame.function);
|
||||||
|
|
||||||
frame.updateLoc(map.toLocation(frame.frame.codePtr));
|
frame.updateLoc(map.toLocation(frame.frame.codePtr));
|
||||||
loc = frame.location;
|
loc = frame.location;
|
||||||
@ -996,27 +811,27 @@ public class SimpleDebugger implements Debugger {
|
|||||||
isBreakpointable = loc != null && (bptType.shouldStepIn());
|
isBreakpointable = loc != null && (bptType.shouldStepIn());
|
||||||
|
|
||||||
if (error != null && (execptionType == CatchType.ALL || execptionType == CatchType.UNCAUGHT && !caught)) {
|
if (error != null && (execptionType == CatchType.ALL || execptionType == CatchType.UNCAUGHT && !caught)) {
|
||||||
pauseException(ctx);
|
pauseException(env);
|
||||||
}
|
}
|
||||||
else if (
|
else if (
|
||||||
loc != null &&
|
loc != null &&
|
||||||
(state == State.STEPPING_IN || state == State.STEPPING_OVER) &&
|
(state == State.STEPPING_IN || state == State.STEPPING_OVER) &&
|
||||||
returnVal != Values.NO_RETURN && stepOutFrame == frame
|
returnVal != Values.NO_RETURN && stepOutFrame == frame
|
||||||
) {
|
) {
|
||||||
pauseDebug(ctx, null);
|
pauseDebug(env, null);
|
||||||
}
|
}
|
||||||
else if (isBreakpointable && bpLocs.containsKey(loc)) {
|
else if (isBreakpointable && bpLocs.containsKey(loc)) {
|
||||||
for (var bp : bpLocs.get(loc)) {
|
for (var bp : bpLocs.get(loc)) {
|
||||||
var ok = bp.condition == null ? true : Values.toBoolean(run(currFrame, bp.condition).result);
|
var ok = bp.condition == null ? true : Values.toBoolean(run(frames.get(frames.size() - 1), bp.condition).result);
|
||||||
if (ok) pauseDebug(ctx, bp);
|
if (ok) pauseDebug(env, bp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// else if (isBreakpointable && tmpBreakpts.remove(loc)) pauseDebug(ctx, null);
|
// else if (isBreakpointable && tmpBreakpts.remove(loc)) pauseDebug(ctx, null);
|
||||||
else if (isBreakpointable && pendingPause) {
|
else if (isBreakpointable && pendingPause) {
|
||||||
pauseDebug(ctx, null);
|
pauseDebug(env, null);
|
||||||
pendingPause = false;
|
pendingPause = false;
|
||||||
}
|
}
|
||||||
else if (instruction.type == Type.NOP && instruction.match("debug")) pauseDebug(ctx, null);
|
else if (instruction.type == Type.NOP && instruction.match("debug")) pauseDebug(env, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1039,11 +854,11 @@ public class SimpleDebugger implements Debugger {
|
|||||||
else if (stepOutPtr != frame.frame.codePtr) {
|
else if (stepOutPtr != frame.frame.codePtr) {
|
||||||
|
|
||||||
if (state == State.STEPPING_IN && bptType.shouldStepIn()) {
|
if (state == State.STEPPING_IN && bptType.shouldStepIn()) {
|
||||||
pauseDebug(ctx, null);
|
pauseDebug(env, null);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
else if (state == State.STEPPING_OVER && bptType.shouldStepOver()) {
|
else if (state == State.STEPPING_OVER && bptType.shouldStepOver()) {
|
||||||
pauseDebug(ctx, null);
|
pauseDebug(env, null);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1056,28 +871,32 @@ public class SimpleDebugger implements Debugger {
|
|||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@Override public void onFramePush(Context ctx, Frame frame) {
|
@Override public void onFramePush(Environment env, Frame frame) {
|
||||||
var prevFrame = currFrame;
|
var prevFrame = frames.get(frames.size() - 1);
|
||||||
updateFrames(ctx);
|
var newFrame = getFrame(frame);
|
||||||
|
frames.add(newFrame);
|
||||||
|
|
||||||
if (stepOutFrame != null && stepOutFrame.frame == prevFrame.frame && state == State.STEPPING_IN) {
|
if (stepOutFrame != null && stepOutFrame.frame == prevFrame.frame && state == State.STEPPING_IN) {
|
||||||
stepOutFrame = currFrame;
|
stepOutFrame = newFrame;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@Override public void onFramePop(Context ctx, Frame frame) {
|
@Override public void onFramePop(Environment env, Frame frame) {
|
||||||
updateFrames(ctx);
|
frames.remove(frames.size() - 1);
|
||||||
|
|
||||||
try { idToFrame.remove(codeFrameToFrame.remove(frame).id); }
|
try { idToFrame.remove(codeFrameToFrame.remove(frame).id); }
|
||||||
catch (NullPointerException e) { }
|
catch (NullPointerException e) { }
|
||||||
|
|
||||||
if (ctx.stackSize == 0) {
|
if (frames.size() == 0) {
|
||||||
if (state == State.PAUSED_EXCEPTION || state == State.PAUSED_NORMAL) resume(State.RESUMED);
|
if (state == State.PAUSED_EXCEPTION || state == State.PAUSED_NORMAL) resume(State.RESUMED);
|
||||||
}
|
}
|
||||||
else if (stepOutFrame != null && stepOutFrame.frame == frame && state == State.STEPPING_OUT) {
|
else if (stepOutFrame != null && stepOutFrame.frame == frame && state == State.STEPPING_OUT) {
|
||||||
state = State.STEPPING_IN;
|
state = State.STEPPING_IN;
|
||||||
stepOutFrame = currFrame;
|
stepOutFrame = frames.get(frames.size() - 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@Override public List<Frame> getStackFrame() {
|
||||||
|
return frames.stream().map(v -> v.frame).collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
public SimpleDebugger attach(DebugContext ctx) {
|
public SimpleDebugger attach(DebugContext ctx) {
|
||||||
ctx.attachDebugger(this);
|
ctx.attachDebugger(this);
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
package me.topchetoeu.jscript.utils.filesystem;
|
package me.topchetoeu.jscript.utils.filesystem;
|
||||||
|
|
||||||
import me.topchetoeu.jscript.runtime.Extensions;
|
import me.topchetoeu.jscript.runtime.environment.Environment;
|
||||||
import me.topchetoeu.jscript.runtime.Key;
|
import me.topchetoeu.jscript.runtime.environment.Key;
|
||||||
|
|
||||||
public interface Filesystem {
|
public interface Filesystem {
|
||||||
public static final Key<Filesystem> KEY = new Key<>();
|
public static final Key<Filesystem> KEY = new Key<>();
|
||||||
@ -12,7 +12,7 @@ public interface Filesystem {
|
|||||||
FileStat stat(String path);
|
FileStat stat(String path);
|
||||||
void close();
|
void close();
|
||||||
|
|
||||||
public static Filesystem get(Extensions exts) {
|
public static Filesystem get(Environment exts) {
|
||||||
return exts.get(KEY);
|
return exts.get(KEY);
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -2,32 +2,14 @@ package me.topchetoeu.jscript.utils.interop;
|
|||||||
|
|
||||||
import java.lang.reflect.Array;
|
import java.lang.reflect.Array;
|
||||||
|
|
||||||
import me.topchetoeu.jscript.runtime.Context;
|
import me.topchetoeu.jscript.runtime.environment.Environment;
|
||||||
import me.topchetoeu.jscript.runtime.Extensions;
|
|
||||||
import me.topchetoeu.jscript.runtime.Key;
|
|
||||||
import me.topchetoeu.jscript.runtime.values.NativeWrapper;
|
import me.topchetoeu.jscript.runtime.values.NativeWrapper;
|
||||||
import me.topchetoeu.jscript.runtime.values.Values;
|
import me.topchetoeu.jscript.runtime.values.Values;
|
||||||
|
|
||||||
public class Arguments implements Extensions {
|
public class Arguments {
|
||||||
public final Object self;
|
public final Object self;
|
||||||
public final Object[] args;
|
public final Object[] args;
|
||||||
public final Context ctx;
|
public final Environment env;
|
||||||
|
|
||||||
@Override public <T> void add(Key<T> key, T obj) {
|
|
||||||
ctx.add(key, obj);
|
|
||||||
}
|
|
||||||
@Override public <T> T get(Key<T> key) {
|
|
||||||
return ctx.get(key);
|
|
||||||
}
|
|
||||||
@Override public boolean has(Key<?> key) {
|
|
||||||
return ctx.has(key);
|
|
||||||
}
|
|
||||||
@Override public boolean remove(Key<?> key) {
|
|
||||||
return ctx.remove(key);
|
|
||||||
}
|
|
||||||
@Override public Iterable<Key<?>> keys() {
|
|
||||||
return ctx.keys();
|
|
||||||
}
|
|
||||||
|
|
||||||
public int n() {
|
public int n() {
|
||||||
return args.length;
|
return args.length;
|
||||||
@ -41,7 +23,7 @@ public class Arguments implements Extensions {
|
|||||||
return convert(-1, type);
|
return convert(-1, type);
|
||||||
}
|
}
|
||||||
public <T> T convert(int i, Class<T> type) {
|
public <T> T convert(int i, Class<T> type) {
|
||||||
return Values.convert(ctx, get(i), type);
|
return Values.convert(env, get(i), type);
|
||||||
}
|
}
|
||||||
public Object get(int i, boolean unwrap) {
|
public Object get(int i, boolean unwrap) {
|
||||||
Object res = null;
|
Object res = null;
|
||||||
@ -63,7 +45,7 @@ public class Arguments implements Extensions {
|
|||||||
public Arguments slice(int start) {
|
public Arguments slice(int start) {
|
||||||
var res = new Object[Math.max(0, args.length - start)];
|
var res = new Object[Math.max(0, args.length - start)];
|
||||||
for (int j = start; j < args.length; j++) res[j - start] = get(j);
|
for (int j = start; j < args.length; j++) res[j - start] = get(j);
|
||||||
return new Arguments(ctx, args, res);
|
return new Arguments(env, args, res);
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
@ -113,26 +95,26 @@ public class Arguments implements Extensions {
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getString(int i) { return Values.toString(ctx, get(i)); }
|
public String getString(int i) { return Values.toString(env, get(i)); }
|
||||||
public boolean getBoolean(int i) { return Values.toBoolean(get(i)); }
|
public boolean getBoolean(int i) { return Values.toBoolean(get(i)); }
|
||||||
public int getInt(int i) { return (int)Values.toNumber(ctx, get(i)); }
|
public int getInt(int i) { return (int)Values.toNumber(env, get(i)); }
|
||||||
public long getLong(int i) { return (long)Values.toNumber(ctx, get(i)); }
|
public long getLong(int i) { return (long)Values.toNumber(env, get(i)); }
|
||||||
public double getDouble(int i) { return Values.toNumber(ctx, get(i)); }
|
public double getDouble(int i) { return Values.toNumber(env, get(i)); }
|
||||||
public float getFloat(int i) { return (float)Values.toNumber(ctx, get(i)); }
|
public float getFloat(int i) { return (float)Values.toNumber(env, get(i)); }
|
||||||
|
|
||||||
public int getInt(int i, int def) {
|
public int getInt(int i, int def) {
|
||||||
var res = get(i);
|
var res = get(i);
|
||||||
if (res == null) return def;
|
if (res == null) return def;
|
||||||
else return (int)Values.toNumber(ctx, res);
|
else return (int)Values.toNumber(env, res);
|
||||||
}
|
}
|
||||||
public String getString(int i, String def) {
|
public String getString(int i, String def) {
|
||||||
var res = get(i);
|
var res = get(i);
|
||||||
if (res == null) return def;
|
if (res == null) return def;
|
||||||
else return Values.toString(ctx, res);
|
else return Values.toString(env, res);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Arguments(Context ctx, Object thisArg, Object... args) {
|
public Arguments(Environment env, Object thisArg, Object... args) {
|
||||||
this.ctx = ctx;
|
this.env = env;
|
||||||
this.args = args;
|
this.args = args;
|
||||||
this.self = thisArg;
|
this.self = thisArg;
|
||||||
}
|
}
|
||||||
|
@ -12,10 +12,8 @@ import java.util.stream.Collectors;
|
|||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
import me.topchetoeu.jscript.common.Location;
|
import me.topchetoeu.jscript.common.Location;
|
||||||
import me.topchetoeu.jscript.runtime.Context;
|
import me.topchetoeu.jscript.runtime.environment.Environment;
|
||||||
import me.topchetoeu.jscript.runtime.Copyable;
|
import me.topchetoeu.jscript.runtime.environment.Key;
|
||||||
import me.topchetoeu.jscript.runtime.Extensions;
|
|
||||||
import me.topchetoeu.jscript.runtime.Key;
|
|
||||||
import me.topchetoeu.jscript.runtime.exceptions.EngineException;
|
import me.topchetoeu.jscript.runtime.exceptions.EngineException;
|
||||||
import me.topchetoeu.jscript.runtime.exceptions.InterruptException;
|
import me.topchetoeu.jscript.runtime.exceptions.InterruptException;
|
||||||
import me.topchetoeu.jscript.runtime.values.FunctionValue;
|
import me.topchetoeu.jscript.runtime.values.FunctionValue;
|
||||||
@ -24,7 +22,7 @@ import me.topchetoeu.jscript.runtime.values.ObjectValue;
|
|||||||
import me.topchetoeu.jscript.runtime.values.Symbol;
|
import me.topchetoeu.jscript.runtime.values.Symbol;
|
||||||
import me.topchetoeu.jscript.runtime.values.Values;
|
import me.topchetoeu.jscript.runtime.values.Values;
|
||||||
|
|
||||||
public class NativeWrapperProvider implements Copyable {
|
public class NativeWrapperProvider {
|
||||||
public static final Key<NativeWrapperProvider> KEY = new Key<>();
|
public static final Key<NativeWrapperProvider> KEY = new Key<>();
|
||||||
|
|
||||||
private final HashMap<Class<?>, FunctionValue> constructors = new HashMap<>();
|
private final HashMap<Class<?>, FunctionValue> constructors = new HashMap<>();
|
||||||
@ -35,7 +33,7 @@ public class NativeWrapperProvider implements Copyable {
|
|||||||
private final HashMap<Class<?>, Class<?>> interfaceToProxy = new HashMap<>();
|
private final HashMap<Class<?>, Class<?>> interfaceToProxy = new HashMap<>();
|
||||||
private final HashSet<Class<?>> ignore = new HashSet<>();
|
private final HashSet<Class<?>> ignore = new HashSet<>();
|
||||||
|
|
||||||
private static Object call(Context ctx, String name, Method method, Object thisArg, Object... args) {
|
private static Object call(Environment ctx, String name, Method method, Object thisArg, Object... args) {
|
||||||
try {
|
try {
|
||||||
var realArgs = new Object[method.getParameterCount()];
|
var realArgs = new Object[method.getParameterCount()];
|
||||||
System.arraycopy(args, 0, realArgs, 0, realArgs.length);
|
System.arraycopy(args, 0, realArgs, 0, realArgs.length);
|
||||||
@ -60,7 +58,7 @@ public class NativeWrapperProvider implements Copyable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
private static FunctionValue create(String name, Method method) {
|
private static FunctionValue create(String name, Method method) {
|
||||||
return new NativeFunction(name, args -> call(args.ctx, name, method, args.self, args));
|
return new NativeFunction(name, args -> call(args.env, name, method, args.self, args));
|
||||||
}
|
}
|
||||||
private static void checkSignature(Method method, boolean forceStatic, Class<?> ...params) {
|
private static void checkSignature(Method method, boolean forceStatic, Class<?> ...params) {
|
||||||
if (forceStatic && !Modifier.isStatic(method.getModifiers())) throw new IllegalArgumentException(String.format(
|
if (forceStatic && !Modifier.isStatic(method.getModifiers())) throw new IllegalArgumentException(String.format(
|
||||||
@ -335,8 +333,8 @@ public class NativeWrapperProvider implements Copyable {
|
|||||||
var parentConstr = getConstr(parent);
|
var parentConstr = getConstr(parent);
|
||||||
|
|
||||||
if (parentProto != null && parentConstr != null) {
|
if (parentProto != null && parentConstr != null) {
|
||||||
Values.setPrototype(Extensions.EMPTY, proto, parentProto);
|
Values.setPrototype(Environment.empty(), proto, parentProto);
|
||||||
Values.setPrototype(Extensions.EMPTY, constr, parentConstr);
|
Values.setPrototype(Environment.empty(), constr, parentConstr);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -450,7 +448,7 @@ public class NativeWrapperProvider implements Copyable {
|
|||||||
|
|
||||||
public NativeWrapperProvider() { }
|
public NativeWrapperProvider() { }
|
||||||
|
|
||||||
public static NativeWrapperProvider get(Extensions ext) {
|
public static NativeWrapperProvider get(Environment ext) {
|
||||||
return ext.get(KEY);
|
return ext.get(KEY);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
package me.topchetoeu.jscript.utils.modules;
|
package me.topchetoeu.jscript.utils.modules;
|
||||||
|
|
||||||
import me.topchetoeu.jscript.runtime.Context;
|
import me.topchetoeu.jscript.runtime.environment.Environment;
|
||||||
|
|
||||||
public abstract class Module {
|
public abstract class Module {
|
||||||
private Object value;
|
private Object value;
|
||||||
@ -9,9 +9,9 @@ public abstract class Module {
|
|||||||
public Object value() { return value; }
|
public Object value() { return value; }
|
||||||
public boolean loaded() { return loaded; }
|
public boolean loaded() { return loaded; }
|
||||||
|
|
||||||
protected abstract Object onLoad(Context ctx);
|
protected abstract Object onLoad(Environment ctx);
|
||||||
|
|
||||||
public void load(Context ctx) {
|
public void load(Environment ctx) {
|
||||||
if (loaded) return;
|
if (loaded) return;
|
||||||
this.value = onLoad(ctx);
|
this.value = onLoad(ctx);
|
||||||
this.loaded = true;
|
this.loaded = true;
|
||||||
|
@ -3,9 +3,8 @@ package me.topchetoeu.jscript.utils.modules;
|
|||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
|
||||||
import me.topchetoeu.jscript.common.Filename;
|
import me.topchetoeu.jscript.common.Filename;
|
||||||
import me.topchetoeu.jscript.runtime.Context;
|
import me.topchetoeu.jscript.runtime.environment.Environment;
|
||||||
import me.topchetoeu.jscript.runtime.Extensions;
|
import me.topchetoeu.jscript.runtime.environment.Key;
|
||||||
import me.topchetoeu.jscript.runtime.Key;
|
|
||||||
import me.topchetoeu.jscript.runtime.scope.GlobalScope;
|
import me.topchetoeu.jscript.runtime.scope.GlobalScope;
|
||||||
import me.topchetoeu.jscript.utils.filesystem.Filesystem;
|
import me.topchetoeu.jscript.utils.filesystem.Filesystem;
|
||||||
import me.topchetoeu.jscript.utils.filesystem.Mode;
|
import me.topchetoeu.jscript.utils.filesystem.Mode;
|
||||||
@ -14,34 +13,34 @@ public interface ModuleRepo {
|
|||||||
public static final Key<ModuleRepo> KEY = new Key<>();
|
public static final Key<ModuleRepo> KEY = new Key<>();
|
||||||
public static final Key<String> CWD = new Key<>();
|
public static final Key<String> CWD = new Key<>();
|
||||||
|
|
||||||
public Module getModule(Context ctx, String cwd, String name);
|
public Module getModule(Environment ctx, String cwd, String name);
|
||||||
|
|
||||||
public static ModuleRepo ofFilesystem(Filesystem fs) {
|
public static ModuleRepo ofFilesystem(Filesystem fs) {
|
||||||
var modules = new HashMap<String, Module>();
|
var modules = new HashMap<String, Module>();
|
||||||
|
|
||||||
return (ctx, cwd, name) -> {
|
return (env, cwd, name) -> {
|
||||||
name = fs.normalize(cwd, name);
|
name = fs.normalize(cwd, name);
|
||||||
var filename = Filename.parse(name);
|
var filename = Filename.parse(name);
|
||||||
var src = fs.open(name, Mode.READ).readToString();
|
var src = fs.open(name, Mode.READ).readToString();
|
||||||
|
|
||||||
if (modules.containsKey(name)) return modules.get(name);
|
if (modules.containsKey(name)) return modules.get(name);
|
||||||
|
|
||||||
var env = Context.clean(ctx.extensions).child();
|
var moduleEnv = env.child()
|
||||||
env.add(CWD, fs.normalize(name, ".."));
|
.add(CWD, fs.normalize(name, ".."))
|
||||||
var glob = env.get(GlobalScope.KEY);
|
.add(GlobalScope.KEY, env.hasNotNull(GlobalScope.KEY) ? env.get(GlobalScope.KEY).child() : new GlobalScope());
|
||||||
env.add(GlobalScope.KEY, glob.child());
|
|
||||||
|
|
||||||
var mod = new SourceModule(filename, src, env);
|
var mod = new SourceModule(filename, src, moduleEnv);
|
||||||
modules.put(name, mod);
|
modules.put(name, mod);
|
||||||
|
|
||||||
return mod;
|
return mod;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String cwd(Extensions exts) {
|
public static String cwd(Environment exts) {
|
||||||
return exts.init(CWD, "/");
|
exts.init(CWD, "/");
|
||||||
|
return "/";
|
||||||
}
|
}
|
||||||
public static ModuleRepo get(Extensions exts) {
|
public static ModuleRepo get(Environment exts) {
|
||||||
return exts.get(KEY);
|
return exts.get(KEY);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,14 +2,14 @@ package me.topchetoeu.jscript.utils.modules;
|
|||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
|
||||||
import me.topchetoeu.jscript.runtime.Context;
|
import me.topchetoeu.jscript.runtime.environment.Environment;
|
||||||
import me.topchetoeu.jscript.runtime.exceptions.EngineException;
|
import me.topchetoeu.jscript.runtime.exceptions.EngineException;
|
||||||
|
|
||||||
public class RootModuleRepo implements ModuleRepo {
|
public class RootModuleRepo implements ModuleRepo {
|
||||||
public final HashMap<String, ModuleRepo> repos = new HashMap<>();
|
public final HashMap<String, ModuleRepo> repos = new HashMap<>();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Module getModule(Context ctx, String cwd, String name) {
|
public Module getModule(Environment env, String cwd, String name) {
|
||||||
var i = name.indexOf(":");
|
var i = name.indexOf(":");
|
||||||
String repoName, modName;
|
String repoName, modName;
|
||||||
|
|
||||||
@ -25,6 +25,6 @@ public class RootModuleRepo implements ModuleRepo {
|
|||||||
var repo = repos.get(repoName);
|
var repo = repos.get(repoName);
|
||||||
if (repo == null) throw EngineException.ofError("ModuleError", "Couldn't find module repo '" + repoName + "'.");
|
if (repo == null) throw EngineException.ofError("ModuleError", "Couldn't find module repo '" + repoName + "'.");
|
||||||
|
|
||||||
return repo.getModule(ctx, cwd, modName);
|
return repo.getModule(env, cwd, modName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,21 +1,20 @@
|
|||||||
package me.topchetoeu.jscript.utils.modules;
|
package me.topchetoeu.jscript.utils.modules;
|
||||||
|
|
||||||
import me.topchetoeu.jscript.common.Filename;
|
import me.topchetoeu.jscript.common.Filename;
|
||||||
import me.topchetoeu.jscript.runtime.Context;
|
import me.topchetoeu.jscript.runtime.Compiler;
|
||||||
import me.topchetoeu.jscript.runtime.Extensions;
|
import me.topchetoeu.jscript.runtime.environment.Environment;
|
||||||
|
|
||||||
public class SourceModule extends Module {
|
public class SourceModule extends Module {
|
||||||
public final Filename filename;
|
public final Filename filename;
|
||||||
public final String source;
|
public final String source;
|
||||||
public final Extensions ext;
|
public final Environment ext;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Object onLoad(Context ctx) {
|
protected Object onLoad(Environment env) {
|
||||||
var res = new Context(ext).compile(filename, source);
|
return Compiler.compile(env, filename, source).call(env);
|
||||||
return res.call(ctx);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public SourceModule(Filename filename, String source, Extensions ext) {
|
public SourceModule(Filename filename, String source, Environment ext) {
|
||||||
this.filename = filename;
|
this.filename = filename;
|
||||||
this.source = source;
|
this.source = source;
|
||||||
this.ext = ext;
|
this.ext = ext;
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
package me.topchetoeu.jscript.utils.permissions;
|
package me.topchetoeu.jscript.utils.permissions;
|
||||||
|
|
||||||
import me.topchetoeu.jscript.runtime.Extensions;
|
import me.topchetoeu.jscript.runtime.environment.Environment;
|
||||||
import me.topchetoeu.jscript.runtime.Key;
|
import me.topchetoeu.jscript.runtime.environment.Key;
|
||||||
|
|
||||||
public interface PermissionsProvider {
|
public interface PermissionsProvider {
|
||||||
public static final Key<PermissionsProvider> KEY = new Key<>();
|
public static final Key<PermissionsProvider> KEY = new Key<>();
|
||||||
@ -20,7 +20,7 @@ public interface PermissionsProvider {
|
|||||||
return hasPermission(new Permission(perm, matcher));
|
return hasPermission(new Permission(perm, matcher));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static PermissionsProvider get(Extensions exts) {
|
public static PermissionsProvider get(Environment exts) {
|
||||||
return (perm, value) -> {
|
return (perm, value) -> {
|
||||||
if (exts.hasNotNull(KEY)) return exts.get(KEY).hasPermission(perm);
|
if (exts.hasNotNull(KEY)) return exts.get(KEY).hasPermission(perm);
|
||||||
else return true;
|
else return true;
|
||||||
|
Loading…
Reference in New Issue
Block a user