diff --git a/src/main/java/me/topchetoeu/jscript/runtime/Frame.java b/src/main/java/me/topchetoeu/jscript/runtime/Frame.java
index 636a881..62ef129 100644
--- a/src/main/java/me/topchetoeu/jscript/runtime/Frame.java
+++ b/src/main/java/me/topchetoeu/jscript/runtime/Frame.java
@@ -1,5 +1,6 @@
package me.topchetoeu.jscript.runtime;
+import java.util.Arrays;
import java.util.Stack;
import java.util.concurrent.CancellationException;
@@ -12,6 +13,7 @@ import me.topchetoeu.jscript.runtime.values.Value;
import me.topchetoeu.jscript.runtime.values.functions.CodeFunction;
import me.topchetoeu.jscript.runtime.values.objects.ArrayLikeValue;
import me.topchetoeu.jscript.runtime.values.objects.ObjectValue;
+import me.topchetoeu.jscript.runtime.values.primitives.numbers.IntValue;
public final class Frame {
public static final Key KEY = Key.of();
@@ -95,17 +97,26 @@ public final class Frame {
}
/**
- * A list of one-element arrays of values. This is so that we can pass captures to other functions
+ * An array of captures from the parent function
*/
public final Value[][] captures;
+ /**
+ * An array of non-capture variables
+ */
public final Value[] locals;
+ /**
+ * An array of children-captured variables
+ */
public final Value[][] capturables;
- public final Value argsVal;
- public Value self;
- public Value fakeArgs;
+
+ public final Value self;
public final Value[] args;
- public final boolean isNew;
- public final Stack tryStack = new Stack<>();
+ public final Value argsVal;
+ public final Value argsLen;
+
+ public final boolean isNew;
+
+ public final Stack tryStack = new Stack<>();
public final CodeFunction function;
public final Environment env;
private final DebugContext dbg;
@@ -275,11 +286,8 @@ public final class Frame {
}
if (returnValue != null) {
- if (self == null) error = EngineException.ofError("Super constructor must be called before returning");
- else {
dbg.onInstruction(env, this, instr, returnValue, null, false);
return returnValue;
- }
}
if (error != null) {
var caught = false;
@@ -358,18 +366,21 @@ public final class Frame {
};
}
- public Frame(Environment env, boolean isNew, Value thisArg, Value[] args, CodeFunction func) {
+ public Frame(Environment env, boolean isNew, Value self, Value[] args, CodeFunction func) {
this.env = env;
this.dbg = DebugContext.get(env);
this.function = func;
this.isNew = isNew;
- this.self = thisArg;
+ this.self = self;
this.args = args;
this.argsVal = new ArgumentsValue(this, args);
+ this.argsLen = new IntValue(args.length);
this.captures = func.captures;
this.locals = new Value[func.body.localsN];
+ Arrays.fill(this.locals, Value.UNDEFINED);
this.capturables = new Value[func.body.capturablesN][1];
+ for (var i = 0; i < this.capturables.length; i++) this.capturables[i][0] = Value.UNDEFINED;
}
}
diff --git a/src/main/java/me/topchetoeu/jscript/runtime/InstructionRunner.java b/src/main/java/me/topchetoeu/jscript/runtime/InstructionRunner.java
index db4ec83..cbb6857 100644
--- a/src/main/java/me/topchetoeu/jscript/runtime/InstructionRunner.java
+++ b/src/main/java/me/topchetoeu/jscript/runtime/InstructionRunner.java
@@ -34,23 +34,7 @@ public class InstructionRunner {
var func = frame.pop();
var self = (boolean)instr.get(1) ? frame.pop() : Value.UNDEFINED;
- frame.push(func.apply(env, instr.get(2), self, callArgs));
-
- frame.codePtr++;
- return null;
- }
- private static Value execCallSuper(Environment env, Instruction instr, Frame frame) {
- if (!frame.isNew) throw EngineException.ofError("Super constructor may be called only when constructing");
- if (frame.self != null) throw EngineException.ofError("Super constructor may be called once");
-
- var callArgs = frame.take(instr.get(0));
- var superFunc = frame.pop();
-
- var self = new ObjectValue();
- if (frame.function.prototype instanceof ObjectValue objProto) self.setPrototype(env, objProto);
-
- frame.self = superFunc.construct(env, "super", self, callArgs);
- frame.push(frame.self);
+ frame.push(func.apply(env, self, callArgs));
frame.codePtr++;
return null;
@@ -74,10 +58,10 @@ public class InstructionRunner {
if (val == Value.UNDEFINED) accessor = null;
else if (val instanceof FunctionValue func) accessor = func;
- else throw EngineException.ofType("Getter must be a function or undefined.");
+ else throw EngineException.ofType("Getter must be a function or undefined");
- if ((boolean)instr.get(0)) obj.defineOwnMember(env, key, new PropertyMember(obj, null, accessor, true, instr.get(1)));
- else obj.defineOwnMember(env, key, new PropertyMember(obj, accessor, null, true, instr.get(1)));
+ if ((boolean)instr.get(0)) obj.defineOwnMember(env, key, new PropertyMember(obj, null, accessor, true, true));
+ else obj.defineOwnMember(env, key, new PropertyMember(obj, accessor, null, true, true));
frame.codePtr++;
return null;
@@ -87,7 +71,7 @@ public class InstructionRunner {
var key = frame.pop();
var obj = frame.pop();
- obj.defineOwnMember(env, key, FieldMember.of(obj, val, true, instr.get(0), true));
+ obj.defineOwnMember(env, key, FieldMember.of(obj, val, true, true, true));
frame.codePtr++;
return null;
@@ -155,9 +139,7 @@ public class InstructionRunner {
private static Value execLoadVar(Environment env, Instruction instr, Frame frame) {
int i = instr.get(0);
- var res = frame.getVar(i);
- if (res == null) throw EngineException.ofSyntax("Uninitialized variable");
- frame.push(res);
+ frame.push(frame.getVar(i));
frame.codePtr++;
return null;
@@ -189,25 +171,14 @@ public class InstructionRunner {
private static Value execLoadFunc(Environment env, Instruction instr, Frame frame) {
int id = instr.get(0);
String name = instr.get(1);
- boolean callable = instr.get(2);
- boolean constructible = instr.get(3);
- boolean captureThis = instr.get(4);
- boolean noThis = instr.get(5);
- var captures = new Value[instr.params.length - 6][];
+ var captures = new Value[instr.params.length - 2][];
- for (var i = 6; i < instr.params.length; i++) {
- captures[i - 6] = frame.captureVar(instr.get(i));
+ for (var i = 2; i < instr.params.length; i++) {
+ captures[i - 2] = frame.captureVar(instr.get(i));
}
var func = new CodeFunction(env, name, frame.function.body.children[id], captures);
- if (!callable) func.enableCall = false;
- if (!constructible) func.enableNew = false;
- if (captureThis) {
- func.self = frame.self;
- func.argsVal = frame.argsVal;
- }
- if (noThis) func.mustCallSuper = true;
frame.push(func);
@@ -254,7 +225,7 @@ public class InstructionRunner {
frame.push(env.get(Value.REGEX_CONSTR).construct(env, instr.get(0), instr.get(1)));
}
else {
- throw EngineException.ofSyntax("Regex is not supported.");
+ throw EngineException.ofSyntax("Regex is not supported");
}
frame.codePtr++;
@@ -271,7 +242,7 @@ public class InstructionRunner {
var key = frame.pop();
var obj = frame.pop();
- if (!obj.setMember(env, key, val)) throw EngineException.ofSyntax("Can't set member '" + key.toReadable(env) + "'.");
+ if (!obj.setMember(env, key, val)) throw EngineException.ofSyntax("Can't set member '" + key.toReadable(env) + "'");
if ((boolean)instr.get(0)) frame.push(val);
frame.codePtr++;
return null;
@@ -280,7 +251,7 @@ public class InstructionRunner {
var val = frame.pop();
var obj = frame.pop();
- if (!obj.setMember(env, (String)instr.get(0), val)) throw EngineException.ofSyntax("Can't set member '" + instr.get(0) + "'.");
+ if (!obj.setMember(env, (String)instr.get(0), val)) throw EngineException.ofSyntax("Can't set member '" + instr.get(0) + "'");
if ((boolean)instr.get(1)) frame.push(val);
frame.codePtr++;
return null;
@@ -289,7 +260,7 @@ public class InstructionRunner {
var val = frame.pop();
var obj = frame.pop();
- if (!obj.setMember(env, (int)instr.get(0), val)) throw EngineException.ofSyntax("Can't set member '" + instr.get(0) + "'.");
+ if (!obj.setMember(env, (int)instr.get(0), val)) throw EngineException.ofSyntax("Can't set member '" + instr.get(0) + "'");
if ((boolean)instr.get(1)) frame.push(val);
frame.codePtr++;
return null;
@@ -298,7 +269,6 @@ public class InstructionRunner {
var val = (boolean)instr.get(1) ? frame.peek() : frame.pop();
int i = instr.get(0);
- if (!(boolean)instr.get(2) && frame.getVar(i) == null) throw EngineException.ofSyntax("Uninitialized variable");
frame.setVar(i, val);
frame.codePtr++;
@@ -348,7 +318,7 @@ public class InstructionRunner {
var key = frame.pop();
var val = frame.pop();
- if (!val.deleteMember(env, key)) throw EngineException.ofSyntax("Can't delete member '" + key.toReadable(env) + "'.");
+ if (!val.deleteMember(env, key)) throw EngineException.ofSyntax("Can't delete member '" + key.toReadable(env) + "'");
frame.codePtr++;
return null;
}
@@ -456,7 +426,7 @@ public class InstructionRunner {
return null;
}
- private static Value exexGlobDef(Environment env, Instruction instr, Frame frame) {
+ private static Value execGlobDef(Environment env, Instruction instr, Frame frame) {
var name = (String)instr.get(0);
if (!Value.global(env).hasMember(env, name, false)) {
@@ -466,7 +436,7 @@ public class InstructionRunner {
frame.codePtr++;
return null;
}
- private static Value exexGlobGet(Environment env, Instruction instr, Frame frame) {
+ private static Value execGlobGet(Environment env, Instruction instr, Frame frame) {
var name = (String)instr.get(0);
if ((boolean)instr.get(1)) {
frame.push(Value.global(env).getMember(env, name));
@@ -481,7 +451,7 @@ public class InstructionRunner {
frame.codePtr++;
return null;
}
- private static Value exexGlobSet(Environment env, Instruction instr, Frame frame) {
+ private static Value execGlobSet(Environment env, Instruction instr, Frame frame) {
var name = (String)instr.get(0);
var keep = (boolean)instr.get(1);
var define = (boolean)instr.get(2);
@@ -497,34 +467,19 @@ public class InstructionRunner {
frame.codePtr++;
return null;
}
- private static Value execExtend(Environment env, Instruction instr, Frame frame) {
- var superVal = frame.peek(0);
- var derivedVal = frame.peek(1);
-
- if (!(superVal instanceof FunctionValue superFunc)) throw EngineException.ofType("Illegal EXTENDS instruction");
- if (!(superFunc.prototype instanceof ObjectValue superProto)) throw EngineException.ofType("Illegal EXTENDS instruction");
- if (!(derivedVal instanceof FunctionValue derivedFunc)) throw EngineException.ofType("Illegal EXTENDS instruction");
-
- derivedFunc.setPrototype(env, superFunc);
- derivedFunc.prototype.setPrototype(env, superProto);
+ private static Value execLoadArg(Environment env, Instruction instr, Frame frame) {
+ frame.push(frame.args[(int)instr.get(0)]);
+ frame.codePtr++;
+ return null;
+ }
+ private static Value execLoadArgsN(Environment env, Instruction instr, Frame frame) {
+ frame.push(frame.argsLen);
frame.codePtr++;
return null;
}
-
private static Value execLoadArgs(Environment env, Instruction instr, Frame frame) {
- if ((boolean)instr.get(0) || frame.fakeArgs == null) frame.push(frame.argsVal);
- else frame.push(frame.fakeArgs);
- frame.codePtr++;
- return null;
- }
- private static Value execLoadRestArgs(Environment env, Instruction instr, Frame frame) {
- int offset = instr.get(0);
- var res = new ArrayValue();
-
- if (offset < frame.args.length) res.copyFrom(frame.args, instr.get(0), 0, frame.args.length - offset);
-
- frame.push(res);
+ frame.push(frame.argsVal);
frame.codePtr++;
return null;
}
@@ -545,26 +500,7 @@ public class InstructionRunner {
return null;
}
- private static Value execVarInit(Environment env, Instruction instr, Frame frame) {
- if ((boolean)instr.get(1) || frame.getVar(instr.get(0)) == null) {
- frame.setVar(instr.get(0), Value.UNDEFINED);
- }
-
- frame.codePtr++;
- return null;
- }
- private static Value execVarFree(Environment env, Instruction instr, Frame frame) {
- frame.locals[(int)instr.get(0)] = null;
- frame.codePtr++;
- return null;
- }
- private static Value execCapFree(Environment env, Instruction instr, Frame frame) {
- frame.capturables[(int)instr.get(0) - frame.locals.length] = new Value[1];
- frame.codePtr++;
- return null;
- }
-
- public static Value exec(Environment env, Instruction instr, Frame frame) {
+ public static Value exec(Environment env, Instruction instr, Frame frame) {
switch (instr.type) {
case NOP: return execNop(env, instr, frame);
case RETURN: return execReturn(env, instr, frame);
@@ -572,7 +508,6 @@ public class InstructionRunner {
case THROW_SYNTAX: return execThrowSyntax(env, instr, frame);
case CALL: return execCall(env, instr, frame);
case CALL_NEW: return execCallNew(env, instr, frame);
- case CALL_SUPER: return execCallSuper(env, instr, frame);
case TRY_START: return execTryStart(env, instr, frame);
case TRY_END: return execTryEnd(env, instr, frame);
@@ -593,12 +528,14 @@ public class InstructionRunner {
case LOAD_REGEX: return execLoadRegEx(env, instr, frame);
case LOAD_GLOB: return execLoadGlob(env, instr, frame);
case LOAD_INTRINSICS: return execLoadIntrinsics(env, instr, frame);
- case LOAD_ARGS: return execLoadArgs(env, instr, frame);
- case LOAD_REST_ARGS: return execLoadRestArgs(env, instr, frame);
- case LOAD_CALLEE: return execLoadCallee(env, instr, frame);
- case LOAD_THIS: return execLoadThis(env, instr, frame);
case LOAD_ERROR: return execLoadError(env, instr, frame);
+ case LOAD_THIS: return execLoadThis(env, instr, frame);
+ case LOAD_ARG: return execLoadArg(env, instr, frame);
+ case LOAD_ARGS: return execLoadArgs(env, instr, frame);
+ case LOAD_ARGS_N: return execLoadArgsN(env, instr, frame);
+ case LOAD_CALLED: return execLoadCallee(env, instr, frame);
+
case DISCARD: return execDiscard(env, instr, frame);
case STORE_MEMBER: return execStoreMember(env, instr, frame);
case STORE_MEMBER_STR: return execStoreMemberStr(env, instr, frame);
@@ -617,16 +554,11 @@ public class InstructionRunner {
case OPERATION: return execOperation(env, instr, frame);
- case GLOB_DEF: return exexGlobDef(env, instr, frame);
- case GLOB_GET: return exexGlobGet(env, instr, frame);
- case GLOB_SET: return exexGlobSet(env, instr, frame);
- case EXTEND: return execExtend(env, instr, frame);
+ case GLOB_DEF: return execGlobDef(env, instr, frame);
+ case GLOB_GET: return execGlobGet(env, instr, frame);
+ case GLOB_SET: return execGlobSet(env, instr, frame);
- case VAR_INIT: return execVarInit(env, instr, frame);
- case VAR_FREE: return execVarFree(env, instr, frame);
- case CAP_FREE: return execCapFree(env, instr, frame);
-
- default: throw EngineException.ofSyntax("Invalid instruction " + instr.type.name() + ".");
+ default: throw EngineException.ofSyntax("Invalid instruction " + instr.type.name() + "");
}
}
}
diff --git a/src/main/java/me/topchetoeu/jscript/runtime/SimpleRepl.java b/src/main/java/me/topchetoeu/jscript/runtime/SimpleRepl.java
index b6047dc..0e8bf90 100644
--- a/src/main/java/me/topchetoeu/jscript/runtime/SimpleRepl.java
+++ b/src/main/java/me/topchetoeu/jscript/runtime/SimpleRepl.java
@@ -212,12 +212,12 @@ public class SimpleRepl {
res.defineOwnMember(env, "setCallable", new NativeFunction(args -> {
var func = (FunctionValue)args.get(0);
- func.enableCall = args.get(1).toBoolean();
+ func.enableApply = args.get(1).toBoolean();
return Value.UNDEFINED;
}));
res.defineOwnMember(env, "setConstructable", new NativeFunction(args -> {
var func = (FunctionValue)args.get(0);
- func.enableNew = args.get(1).toBoolean();
+ func.enableConstruct = args.get(1).toBoolean();
return Value.UNDEFINED;
}));
res.defineOwnMember(env, "invokeType", new NativeFunction(args -> {
@@ -229,16 +229,14 @@ public class SimpleRepl {
var func = (FunctionValue)args.get(0);
var self = args.get(1);
var funcArgs = (ArrayValue)args.get(2);
- var name = args.get(3).toString(env);
- return func.apply(env, name, self, funcArgs.toArray());
+ return func.apply(env, self, funcArgs.toArray());
}));
res.defineOwnMember(env, "construct", new NativeFunction(args -> {
var func = (FunctionValue)args.get(0);
var funcArgs = (ArrayValue)args.get(1);
- var name = args.get(2).toString(env);
- return func.construct(env, name, funcArgs.toArray());
+ return func.construct(env, funcArgs.toArray());
}));
return res;
diff --git a/src/main/java/me/topchetoeu/jscript/runtime/values/Member.java b/src/main/java/me/topchetoeu/jscript/runtime/values/Member.java
index 36c7ac1..9e3d964 100644
--- a/src/main/java/me/topchetoeu/jscript/runtime/values/Member.java
+++ b/src/main/java/me/topchetoeu/jscript/runtime/values/Member.java
@@ -14,12 +14,12 @@ public interface Member {
public boolean enumerable;
@Override public Value get(Environment env, Value self) {
- if (getter != null) return getter.call(env, false, "", self);
+ if (getter != null) return getter.apply(env, self);
else return Value.UNDEFINED;
}
@Override public boolean set(Environment env, Value val, Value self) {
if (setter == null) return false;
- setter.call(env, false, "", self, val);
+ setter.apply(env, self, val);
return true;
}