diff --git a/src/main/java/me/topchetoeu/jscript/runtime/Frame.java b/src/main/java/me/topchetoeu/jscript/runtime/Frame.java
index cf22b35..f5f8b2f 100644
--- a/src/main/java/me/topchetoeu/jscript/runtime/Frame.java
+++ b/src/main/java/me/topchetoeu/jscript/runtime/Frame.java
@@ -16,7 +16,7 @@ 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 = new Key<>();
+ public static final Key> KEY = new Key<>();
public static final EngineException STACK_OVERFLOW;
static {
STACK_OVERFLOW = EngineException.ofRange("Stack overflow!");
@@ -110,6 +110,7 @@ public final class Frame {
public final Value[][] capturables;
public final Value self;
+ public final Value target;
public final Value[] args;
public final Value argsVal;
public final Value argsLen;
@@ -345,9 +346,11 @@ public final class Frame {
}
public void onPush() {
+ get(env).push(this);
DebugContext.get(env).onFramePush(env, this);
}
public void onPop() {
+ get(env).pop();
DebugContext.get(env).onFramePop(env, this);
}
@@ -366,11 +369,12 @@ public final class Frame {
};
}
- public Frame(Environment env, boolean isNew, Value self, Value[] args, CodeFunction func) {
+ public Frame(Environment env, boolean isNew, Value target, Value self, Value[] args, CodeFunction func) {
this.env = env;
this.dbg = DebugContext.get(env);
this.function = func;
this.isNew = isNew;
+ this.target = target;
this.self = self;
this.args = args;
@@ -383,4 +387,17 @@ public final class Frame {
this.capturables = new Value[func.body.capturablesN][1];
for (var i = 0; i < this.capturables.length; i++) this.capturables[i][0] = Value.UNDEFINED;
}
+
+ public static Stack get(Environment env) {
+ if (env.has(KEY)) return env.get(KEY);
+ else {
+ var stack = new Stack();
+ env.add(KEY, stack);
+ return stack;
+ }
+ }
+ public static Frame get(Environment env, int i) {
+ var stack = get(env);
+ return stack.get(stack.size() - i - 1);
+ }
}
diff --git a/src/main/java/me/topchetoeu/jscript/runtime/values/Value.java b/src/main/java/me/topchetoeu/jscript/runtime/values/Value.java
index 0d41128..72e4ba2 100644
--- a/src/main/java/me/topchetoeu/jscript/runtime/values/Value.java
+++ b/src/main/java/me/topchetoeu/jscript/runtime/values/Value.java
@@ -85,20 +85,12 @@ public abstract class Value {
public Value apply(Environment env, Value self, Value ...args) {
throw EngineException.ofType("Value is not a function");
}
- public Value construct(Environment env, Value self, Value ...args) {
+ public Value construct(Environment env, Value target, Value ...args) {
throw EngineException.ofType("Value is not a constructor");
}
public final Value constructNoSelf(Environment env, Value ...args) {
- var res = new ObjectValue();
- var proto = getMember(env, StringValue.of("prototype"));
-
- if (proto instanceof ObjectValue) res.setPrototype(env, (ObjectValue)proto);
-
- var ret = this.construct(env, res, args);
-
- if (ret == Value.UNDEFINED || ret.isPrimitive()) return res;
- return ret;
+ return this.construct(env, this, args);
}
diff --git a/src/main/java/me/topchetoeu/jscript/runtime/values/functions/Arguments.java b/src/main/java/me/topchetoeu/jscript/runtime/values/functions/Arguments.java
index 984cb2b..f7a3dac 100644
--- a/src/main/java/me/topchetoeu/jscript/runtime/values/functions/Arguments.java
+++ b/src/main/java/me/topchetoeu/jscript/runtime/values/functions/Arguments.java
@@ -3,6 +3,7 @@ package me.topchetoeu.jscript.runtime.values.functions;
import me.topchetoeu.jscript.common.environment.Environment;
import me.topchetoeu.jscript.runtime.values.Value;
+import me.topchetoeu.jscript.runtime.values.objects.ObjectValue;
import me.topchetoeu.jscript.runtime.values.primitives.UserValue;
public class Arguments {
@@ -11,6 +12,15 @@ public class Arguments {
public final Environment env;
public final boolean isNew;
+ public final T setTargetProto(T obj) {
+ if (!self.isPrimitive()) {
+ var proto = self.getMember(env, "prototype");
+ if (proto instanceof ObjectValue objProto) self.setPrototype(env, objProto);
+ else if (proto == Value.NULL) self.setPrototype(env, null);
+ }
+ return obj;
+ }
+
public int n() {
return args.length;
}
diff --git a/src/main/java/me/topchetoeu/jscript/runtime/values/functions/CodeFunction.java b/src/main/java/me/topchetoeu/jscript/runtime/values/functions/CodeFunction.java
index 0b9568a..e43511d 100644
--- a/src/main/java/me/topchetoeu/jscript/runtime/values/functions/CodeFunction.java
+++ b/src/main/java/me/topchetoeu/jscript/runtime/values/functions/CodeFunction.java
@@ -4,6 +4,7 @@ import me.topchetoeu.jscript.common.FunctionBody;
import me.topchetoeu.jscript.common.environment.Environment;
import me.topchetoeu.jscript.runtime.Frame;
import me.topchetoeu.jscript.runtime.values.Value;
+import me.topchetoeu.jscript.runtime.values.objects.ObjectValue;
public final class CodeFunction extends FunctionValue {
public final FunctionBody body;
@@ -24,13 +25,24 @@ public final class CodeFunction extends FunctionValue {
}
}
- @Override public Value onCall(Environment env, boolean isNew, Value self, Value ...args) {
- var frame = new Frame(env, isNew, self, args, this);
-
+ @Override protected Value onApply(Environment ext, Value self, Value... args) {
+ var frame = new Frame(env, false, null, self, args, this);
var res = onCall(frame);
+ return res;
+ }
+ @Override protected Value onConstruct(Environment ext, Value target, Value... args) {
+ var self = new ObjectValue();
- if (isNew) return frame.self;
- else return res;
+ var proto = target.getMember(env, "prototype");
+ if (proto instanceof ObjectValue) self.setPrototype(env, (ObjectValue)proto);
+ else if (proto == Value.NULL) self.setPrototype(env, null);
+
+ var frame = new Frame(env, true, target, self, args, this);
+
+ var ret = onCall(frame);
+
+ if (ret == Value.UNDEFINED || ret.isPrimitive()) return self;
+ return ret;
}
public CodeFunction(Environment env, String name, FunctionBody body, Value[][] captures) {
diff --git a/src/main/java/me/topchetoeu/jscript/runtime/values/functions/FunctionValue.java b/src/main/java/me/topchetoeu/jscript/runtime/values/functions/FunctionValue.java
index cef538e..d080ef2 100644
--- a/src/main/java/me/topchetoeu/jscript/runtime/values/functions/FunctionValue.java
+++ b/src/main/java/me/topchetoeu/jscript/runtime/values/functions/FunctionValue.java
@@ -52,16 +52,17 @@ public abstract class FunctionValue extends ObjectValue {
}
};
- protected abstract Value onCall(Environment ext, boolean isNew, Value thisArg, Value ...args);
+ protected abstract Value onApply(Environment ext, Value thisArg, Value ...args);
+ protected abstract Value onConstruct(Environment ext, Value target, Value ...args);
@Override public String toString() { return String.format("function %s(...)", name); }
@Override public Value apply(Environment env, Value self, Value... args) {
if (!enableApply) throw EngineException.ofType("Function cannot be applied");
- return onCall(env, false, self, args);
+ return onApply(env, self, args);
}
- @Override public Value construct(Environment env, Value self, Value... args) {
+ @Override public Value construct(Environment env, Value target, Value... args) {
if (!enableConstruct) throw EngineException.ofType("Function cannot be constructed");
- return onCall(env, true, self, args);
+ return onConstruct(env, target, args);
}
@Override public Member getOwnMember(Environment env, KeyCache key) {
diff --git a/src/main/java/me/topchetoeu/jscript/runtime/values/functions/NativeFunction.java b/src/main/java/me/topchetoeu/jscript/runtime/values/functions/NativeFunction.java
index a4a81e3..bbdc58f 100644
--- a/src/main/java/me/topchetoeu/jscript/runtime/values/functions/NativeFunction.java
+++ b/src/main/java/me/topchetoeu/jscript/runtime/values/functions/NativeFunction.java
@@ -10,8 +10,11 @@ public final class NativeFunction extends FunctionValue {
public final NativeFunctionRunner action;
- @Override public Value onCall(Environment env, boolean isNew, Value self, Value ...args) {
- return action.run(new Arguments(env, isNew, self, args));
+ @Override protected Value onApply(Environment env, Value self, Value... args) {
+ return action.run(new Arguments(env, false, self, args));
+ }
+ @Override protected Value onConstruct(Environment env, Value target, Value... args) {
+ return action.run(new Arguments(env, true, target, args));
}
public NativeFunction(String name, NativeFunctionRunner action) {