ES6 Support Groundwork + Fixes (OLD ONE DON'T LOOK AT ME!!!) #22

Merged
TopchetoEU merged 49 commits from ES6 into master 2024-09-05 14:17:52 +00:00
64 changed files with 1943 additions and 1241 deletions
Showing only changes of commit 3475e3a130 - Show all commits

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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)) {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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() {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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) {

View File

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

View File

@ -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) {

View File

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

View File

@ -1,5 +0,0 @@
package me.topchetoeu.jscript.runtime;
public interface Childable {
Object child();
}

View File

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

View File

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

View File

@ -1,5 +0,0 @@
package me.topchetoeu.jscript.runtime;
public interface Copyable {
Object copy();
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,5 +0,0 @@
package me.topchetoeu.jscript.runtime;
public class Key<T> {
}

View File

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

View File

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

View File

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

View File

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

View File

@ -0,0 +1,5 @@
package me.topchetoeu.jscript.runtime.environment;
public class Key<T> {
}

View File

@ -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');

View File

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

View File

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

View File

@ -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) { }
} }

View File

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

View File

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

View File

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

View File

@ -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) {

View File

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

View File

@ -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) {

View File

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

View 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));
}
}

View File

@ -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) {

View File

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

View File

@ -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() {

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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