From 8e64d13c873cc36b786a662175611f3659093925 Mon Sep 17 00:00:00 2001 From: TopchetoEU <36534413+TopchetoEU@users.noreply.github.com> Date: Fri, 6 Sep 2024 15:48:22 +0300 Subject: [PATCH] refactor: clean up assigning --- .../jscript/common/Instruction.java | 6 +- .../jscript/compilation/AssignableNode.java | 8 +- .../jscript/compilation/FunctionNode.java | 2 +- .../jscript/compilation/JavaScript.java | 5 +- .../compilation/values/VariableNode.java | 13 +++- .../values/operations/AssignNode.java | 23 ++++++ .../values/operations/ChangeNode.java | 51 +++---------- .../values/operations/IndexAssignNode.java | 74 ------------------- .../values/operations/IndexNode.java | 42 ++++++++++- .../values/operations/OperationNode.java | 4 +- .../values/operations/PostfixNode.java | 52 +++++++++++++ .../me/topchetoeu/jscript/runtime/Engine.java | 6 +- .../jscript/runtime/SimpleRepl.java | 19 ++++- .../jscript/runtime/values/Member.java | 4 +- .../runtime/values/primitives/VoidValue.java | 8 -- src/main/resources/lib/index.js | 14 ++-- 16 files changed, 180 insertions(+), 151 deletions(-) create mode 100644 src/main/java/me/topchetoeu/jscript/compilation/values/operations/AssignNode.java delete mode 100644 src/main/java/me/topchetoeu/jscript/compilation/values/operations/IndexAssignNode.java create mode 100644 src/main/java/me/topchetoeu/jscript/compilation/values/operations/PostfixNode.java diff --git a/src/main/java/me/topchetoeu/jscript/common/Instruction.java b/src/main/java/me/topchetoeu/jscript/common/Instruction.java index c418e10..f64c718 100644 --- a/src/main/java/me/topchetoeu/jscript/common/Instruction.java +++ b/src/main/java/me/topchetoeu/jscript/common/Instruction.java @@ -404,10 +404,10 @@ public class Instruction { return new Instruction(Type.LOAD_ARR, count); } public static Instruction dup() { - return new Instruction(Type.DUP, 1); + return new Instruction(Type.DUP, 1, 0); } - public static Instruction dup(int count) { - return new Instruction(Type.DUP, count); + public static Instruction dup(int count, int offset) { + return new Instruction(Type.DUP, count, offset); } public static Instruction storeVar(int i) { diff --git a/src/main/java/me/topchetoeu/jscript/compilation/AssignableNode.java b/src/main/java/me/topchetoeu/jscript/compilation/AssignableNode.java index e684c44..6dd3333 100644 --- a/src/main/java/me/topchetoeu/jscript/compilation/AssignableNode.java +++ b/src/main/java/me/topchetoeu/jscript/compilation/AssignableNode.java @@ -1,7 +1,9 @@ package me.topchetoeu.jscript.compilation; -import me.topchetoeu.jscript.common.Operation; - public interface AssignableNode { - public abstract Node toAssign(Node val, Operation operation); + public void compileBeforeAssign(CompileResult target, boolean operator); + public void compileAfterAssign(CompileResult target, boolean operator, boolean pollute); + public default String assignName() { + return null; + } } diff --git a/src/main/java/me/topchetoeu/jscript/compilation/FunctionNode.java b/src/main/java/me/topchetoeu/jscript/compilation/FunctionNode.java index 9e09ff2..f0ade70 100644 --- a/src/main/java/me/topchetoeu/jscript/compilation/FunctionNode.java +++ b/src/main/java/me/topchetoeu/jscript/compilation/FunctionNode.java @@ -33,7 +33,7 @@ public abstract class FunctionNode extends Node { return new CompileResult(env, scope, params.params.size(), target -> { if (params.params.size() > 0) { target.add(Instruction.loadArgs(true)); - if (params.params.size() > 1) target.add(Instruction.dup(params.params.size() - 1)); + if (params.params.size() > 1) target.add(Instruction.dup(params.params.size() - 1, 0)); var i = 0; for (var param : params.params) { diff --git a/src/main/java/me/topchetoeu/jscript/compilation/JavaScript.java b/src/main/java/me/topchetoeu/jscript/compilation/JavaScript.java index 87d3d7e..082d7ec 100644 --- a/src/main/java/me/topchetoeu/jscript/compilation/JavaScript.java +++ b/src/main/java/me/topchetoeu/jscript/compilation/JavaScript.java @@ -39,6 +39,7 @@ import me.topchetoeu.jscript.compilation.values.operations.ChangeNode; import me.topchetoeu.jscript.compilation.values.operations.DiscardNode; import me.topchetoeu.jscript.compilation.values.operations.IndexNode; import me.topchetoeu.jscript.compilation.values.operations.OperationNode; +import me.topchetoeu.jscript.compilation.values.operations.PostfixNode; import me.topchetoeu.jscript.compilation.values.operations.TypeofNode; import me.topchetoeu.jscript.runtime.exceptions.SyntaxException; @@ -140,8 +141,8 @@ public final class JavaScript { ParseRes res = ParseRes.first(src, i + n, (s, j) -> OperationNode.parseInstanceof(s, j, _prev, precedence), (s, j) -> OperationNode.parseIn(s, j, _prev, precedence), - (s, j) -> ChangeNode.parsePostfixIncrease(s, j, _prev, precedence), - (s, j) -> ChangeNode.parsePostfixDecrease(s, j, _prev, precedence), + (s, j) -> PostfixNode.parsePostfixIncrease(s, j, _prev, precedence), + (s, j) -> PostfixNode.parsePostfixDecrease(s, j, _prev, precedence), (s, j) -> OperationNode.parseOperator(s, j, _prev, precedence), (s, j) -> IfNode.parseTernary(s, j, _prev, precedence), (s, j) -> IndexNode.parseMember(s, j, _prev, precedence), diff --git a/src/main/java/me/topchetoeu/jscript/compilation/values/VariableNode.java b/src/main/java/me/topchetoeu/jscript/compilation/values/VariableNode.java index eb4db6f..c4b7edb 100644 --- a/src/main/java/me/topchetoeu/jscript/compilation/values/VariableNode.java +++ b/src/main/java/me/topchetoeu/jscript/compilation/values/VariableNode.java @@ -4,7 +4,6 @@ import java.util.function.IntFunction; import java.util.function.Supplier; import me.topchetoeu.jscript.common.Instruction; -import me.topchetoeu.jscript.common.Operation; import me.topchetoeu.jscript.common.parsing.Location; import me.topchetoeu.jscript.common.parsing.ParseRes; import me.topchetoeu.jscript.common.parsing.Parsing; @@ -13,14 +12,20 @@ import me.topchetoeu.jscript.compilation.AssignableNode; import me.topchetoeu.jscript.compilation.CompileResult; import me.topchetoeu.jscript.compilation.JavaScript; import me.topchetoeu.jscript.compilation.Node; -import me.topchetoeu.jscript.compilation.values.operations.VariableAssignNode; import me.topchetoeu.jscript.runtime.exceptions.SyntaxException; public class VariableNode extends Node implements AssignableNode { public final String name; - @Override public Node toAssign(Node val, Operation operation) { - return new VariableAssignNode(loc(), name, val, operation); + @Override public String assignName() { return name; } + + @Override public void compileBeforeAssign(CompileResult target, boolean operator) { + if (operator) { + target.add(VariableNode.toGet(target, loc(), name)); + } + } + @Override public void compileAfterAssign(CompileResult target, boolean operator, boolean pollute) { + target.add(VariableNode.toSet(target, loc(), name, pollute, false)); } @Override public void compile(CompileResult target, boolean pollute) { diff --git a/src/main/java/me/topchetoeu/jscript/compilation/values/operations/AssignNode.java b/src/main/java/me/topchetoeu/jscript/compilation/values/operations/AssignNode.java new file mode 100644 index 0000000..e80f6f7 --- /dev/null +++ b/src/main/java/me/topchetoeu/jscript/compilation/values/operations/AssignNode.java @@ -0,0 +1,23 @@ +package me.topchetoeu.jscript.compilation.values.operations; + +import me.topchetoeu.jscript.common.parsing.Location; +import me.topchetoeu.jscript.compilation.AssignableNode; +import me.topchetoeu.jscript.compilation.CompileResult; +import me.topchetoeu.jscript.compilation.Node; + +public class AssignNode extends Node { + public final AssignableNode assignable; + public final Node value; + + @Override public void compile(CompileResult target, boolean pollute) { + assignable.compileBeforeAssign(target, false); + value.compile(target, true); + assignable.compileAfterAssign(target, false, pollute); + } + + public AssignNode(Location loc, AssignableNode assignable, Node value) { + super(loc); + this.assignable = assignable; + this.value = value; + } +} diff --git a/src/main/java/me/topchetoeu/jscript/compilation/values/operations/ChangeNode.java b/src/main/java/me/topchetoeu/jscript/compilation/values/operations/ChangeNode.java index e8b403a..e72b937 100644 --- a/src/main/java/me/topchetoeu/jscript/compilation/values/operations/ChangeNode.java +++ b/src/main/java/me/topchetoeu/jscript/compilation/values/operations/ChangeNode.java @@ -13,24 +13,22 @@ import me.topchetoeu.jscript.compilation.Node; import me.topchetoeu.jscript.compilation.values.constants.NumberNode; public class ChangeNode extends Node { - public final AssignableNode value; - public final double addAmount; - public final boolean postfix; + public final AssignableNode assignable; + public final Node value; + public final Operation op; @Override public void compile(CompileResult target, boolean pollute) { - value.toAssign(new NumberNode(loc(), -addAmount), Operation.SUBTRACT).compile(target, true); - if (!pollute) target.add(Instruction.discard()); - else if (postfix) { - target.add(Instruction.pushValue(addAmount)); - target.add(Instruction.operation(Operation.SUBTRACT)); - } + assignable.compileBeforeAssign(target, true); + value.compile(target, true); + target.add(Instruction.operation(op)); + assignable.compileAfterAssign(target, true, pollute); } - public ChangeNode(Location loc, AssignableNode value, double addAmount, boolean postfix) { + public ChangeNode(Location loc, AssignableNode assignable, Node value, Operation op) { super(loc); + this.assignable = assignable; this.value = value; - this.addAmount = addAmount; - this.postfix = postfix; + this.op = op; } public static ParseRes parsePrefixIncrease(Source src, int i) { @@ -44,7 +42,7 @@ public class ChangeNode extends Node { if (!res.isSuccess()) return res.chainError(src.loc(i + n), "Expected assignable value after prefix operator."); else if (!(res.result instanceof AssignableNode)) return ParseRes.error(src.loc(i + n), "Expected assignable value after prefix operator."); - return ParseRes.res(new ChangeNode(loc, (AssignableNode)res.result, 1, false), n + res.n); + return ParseRes.res(new ChangeNode(loc, (AssignableNode)res.result, new NumberNode(loc, -1), Operation.SUBTRACT), n + res.n); } public static ParseRes parsePrefixDecrease(Source src, int i) { var n = Parsing.skipEmpty(src, i); @@ -57,31 +55,6 @@ public class ChangeNode extends Node { if (!res.isSuccess()) return res.chainError(src.loc(i + n), "Expected assignable value after prefix operator."); else if (!(res.result instanceof AssignableNode)) return ParseRes.error(src.loc(i + n), "Expected assignable value after prefix operator."); - return ParseRes.res(new ChangeNode(loc, (AssignableNode)res.result, -1, false), n + res.n); - } - - public static ParseRes parsePostfixIncrease(Source src, int i, Node prev, int precedence) { - if (precedence > 15) return ParseRes.failed(); - - var n = Parsing.skipEmpty(src, i); - var loc = src.loc(i + n); - - if (!src.is(i + n, "++")) return ParseRes.failed(); - if (!(prev instanceof AssignableNode)) return ParseRes.error(src.loc(i + n), "Expected assignable value before suffix operator."); - n += 2; - - return ParseRes.res(new ChangeNode(loc, (AssignableNode)prev, 1, true), n); - } - public static ParseRes parsePostfixDecrease(Source src, int i, Node prev, int precedence) { - if (precedence > 15) return ParseRes.failed(); - - var n = Parsing.skipEmpty(src, i); - var loc = src.loc(i + n); - - if (!src.is(i + n, "--")) return ParseRes.failed(); - if (!(prev instanceof AssignableNode)) return ParseRes.error(src.loc(i + n), "Expected assignable value before suffix operator."); - n += 2; - - return ParseRes.res(new ChangeNode(loc, (AssignableNode)prev, -1, true), n); + return ParseRes.res(new ChangeNode(loc, (AssignableNode)res.result, new NumberNode(loc, 1), Operation.SUBTRACT), n + res.n); } } diff --git a/src/main/java/me/topchetoeu/jscript/compilation/values/operations/IndexAssignNode.java b/src/main/java/me/topchetoeu/jscript/compilation/values/operations/IndexAssignNode.java deleted file mode 100644 index 8765690..0000000 --- a/src/main/java/me/topchetoeu/jscript/compilation/values/operations/IndexAssignNode.java +++ /dev/null @@ -1,74 +0,0 @@ -package me.topchetoeu.jscript.compilation.values.operations; - -import me.topchetoeu.jscript.common.Instruction; -import me.topchetoeu.jscript.common.Operation; -import me.topchetoeu.jscript.common.Instruction.BreakpointType; -import me.topchetoeu.jscript.common.parsing.Location; -import me.topchetoeu.jscript.compilation.CompileResult; -import me.topchetoeu.jscript.compilation.Node; -import me.topchetoeu.jscript.compilation.values.constants.NumberNode; -import me.topchetoeu.jscript.compilation.values.constants.StringNode; - -public class IndexAssignNode extends Node { - public final Node object; - public final Node index; - public final Node value; - public final Operation operation; - - @Override public void compile(CompileResult target, boolean pollute) { - if (operation != null) { - object.compile(target, true); - - if (index instanceof NumberNode num && (int)num.value == num.value) { - target.add(Instruction.loadMember((int)num.value)); - value.compile(target, true); - target.add(Instruction.operation(operation)); - target.add(Instruction.storeMember((int)num.value, pollute)); - } - else if (index instanceof StringNode str) { - target.add(Instruction.loadMember(str.value)); - value.compile(target, true); - target.add(Instruction.operation(operation)); - target.add(Instruction.storeMember(str.value, pollute)); - } - else { - index.compile(target, true); - target.add(Instruction.dup(2)); - - target.add(Instruction.loadMember()); - value.compile(target, true); - target.add(Instruction.operation(operation)); - - target.add(Instruction.storeMember(pollute)); - } - target.setLocationAndDebug(loc(), BreakpointType.STEP_IN); - } - else { - object.compile(target, true); - - if (index instanceof NumberNode num && (int)num.value == num.value) { - value.compile(target, true); - target.add(Instruction.storeMember((int)num.value, pollute)); - } - else if (index instanceof StringNode str) { - value.compile(target, true); - target.add(Instruction.storeMember(str.value, pollute)); - } - else { - index.compile(target, true); - value.compile(target, true); - target.add(Instruction.storeMember(pollute)); - } - - target.setLocationAndDebug(loc(), BreakpointType.STEP_IN);; - } - } - - public IndexAssignNode(Location loc, Node object, Node index, Node value, Operation operation) { - super(loc); - this.object = object; - this.index = index; - this.value = value; - this.operation = operation; - } -} diff --git a/src/main/java/me/topchetoeu/jscript/compilation/values/operations/IndexNode.java b/src/main/java/me/topchetoeu/jscript/compilation/values/operations/IndexNode.java index d2791ac..cba4934 100644 --- a/src/main/java/me/topchetoeu/jscript/compilation/values/operations/IndexNode.java +++ b/src/main/java/me/topchetoeu/jscript/compilation/values/operations/IndexNode.java @@ -1,7 +1,6 @@ package me.topchetoeu.jscript.compilation.values.operations; import me.topchetoeu.jscript.common.Instruction; -import me.topchetoeu.jscript.common.Operation; import me.topchetoeu.jscript.common.Instruction.BreakpointType; import me.topchetoeu.jscript.common.parsing.Location; import me.topchetoeu.jscript.common.parsing.ParseRes; @@ -18,9 +17,46 @@ public class IndexNode extends Node implements AssignableNode { public final Node object; public final Node index; - @Override public Node toAssign(Node val, Operation operation) { - return new IndexAssignNode(loc(), object, index, val, operation); + @Override public void compileBeforeAssign(CompileResult target, boolean op) { + object.compile(target, true); + + if (index instanceof NumberNode num && (int)num.value == num.value) { + if (op) { + target.add(Instruction.dup()); + target.add(Instruction.loadMember((int)num.value)); + } + } + else if (index instanceof StringNode str) { + if (op) { + target.add(Instruction.dup()); + target.add(Instruction.loadMember(str.value)); + } + } + else { + index.compile(target, true); + + if (op) { + target.add(Instruction.dup(1, 1)); + target.add(Instruction.dup(1, 1)); + target.add(Instruction.loadMember()); + } + } } + @Override public void compileAfterAssign(CompileResult target, boolean op, boolean pollute) { + if (index instanceof NumberNode num && (int)num.value == num.value) { + target.add(Instruction.storeMember((int)num.value, pollute)); + } + else if (index instanceof StringNode str) { + target.add(Instruction.storeMember(str.value, pollute)); + } + else { + target.add(Instruction.storeMember(pollute)); + } + } + + // @Override public Node toAssign(Node val, Operation operation) { + // return new IndexAssignNode(loc(), object, index, val, operation); + // } public void compile(CompileResult target, boolean dupObj, boolean pollute) { object.compile(target, true); if (dupObj) target.add(Instruction.dup()); diff --git a/src/main/java/me/topchetoeu/jscript/compilation/values/operations/OperationNode.java b/src/main/java/me/topchetoeu/jscript/compilation/values/operations/OperationNode.java index 57039c6..b3f4350 100644 --- a/src/main/java/me/topchetoeu/jscript/compilation/values/operations/OperationNode.java +++ b/src/main/java/me/topchetoeu/jscript/compilation/values/operations/OperationNode.java @@ -58,7 +58,9 @@ public class OperationNode extends Node { var other = JavaScript.parseExpression(src, i, precedence); if (!other.isSuccess()) return other.chainError(src.loc(i + other.n), String.format("Expected a value after '%s'", token)); - return ParseRes.res(((AssignableNode)prev).toAssign(other.result, operation), other.n); + + if (operation == null) return ParseRes.res(new AssignNode(loc, ((AssignableNode)prev), other.result), other.n); + else return ParseRes.res(new ChangeNode(loc, ((AssignableNode)prev), other.result, operation), other.n); } public AssignmentOperatorFactory(String token, int precedence, Operation operation) { diff --git a/src/main/java/me/topchetoeu/jscript/compilation/values/operations/PostfixNode.java b/src/main/java/me/topchetoeu/jscript/compilation/values/operations/PostfixNode.java new file mode 100644 index 0000000..420ea74 --- /dev/null +++ b/src/main/java/me/topchetoeu/jscript/compilation/values/operations/PostfixNode.java @@ -0,0 +1,52 @@ +package me.topchetoeu.jscript.compilation.values.operations; + +import me.topchetoeu.jscript.common.Instruction; +import me.topchetoeu.jscript.common.Operation; +import me.topchetoeu.jscript.common.parsing.Location; +import me.topchetoeu.jscript.common.parsing.ParseRes; +import me.topchetoeu.jscript.common.parsing.Parsing; +import me.topchetoeu.jscript.common.parsing.Source; +import me.topchetoeu.jscript.compilation.AssignableNode; +import me.topchetoeu.jscript.compilation.CompileResult; +import me.topchetoeu.jscript.compilation.Node; +import me.topchetoeu.jscript.compilation.values.constants.NumberNode; + +public class PostfixNode extends ChangeNode { + @Override public void compile(CompileResult target, boolean pollute) { + super.compile(target, pollute); + + if (pollute) { + value.compile(target, true); + target.add(Instruction.operation(Operation.ADD)); + } + } + + public PostfixNode(Location loc, AssignableNode value, double addAmount) { + super(loc, value, new NumberNode(loc, -addAmount), Operation.SUBTRACT); + } + + public static ParseRes parsePostfixIncrease(Source src, int i, Node prev, int precedence) { + if (precedence > 15) return ParseRes.failed(); + + var n = Parsing.skipEmpty(src, i); + var loc = src.loc(i + n); + + if (!src.is(i + n, "++")) return ParseRes.failed(); + if (!(prev instanceof AssignableNode)) return ParseRes.error(src.loc(i + n), "Expected assignable value before suffix operator."); + n += 2; + + return ParseRes.res(new PostfixNode(loc, (AssignableNode)prev, 1), n); + } + public static ParseRes parsePostfixDecrease(Source src, int i, Node prev, int precedence) { + if (precedence > 15) return ParseRes.failed(); + + var n = Parsing.skipEmpty(src, i); + var loc = src.loc(i + n); + + if (!src.is(i + n, "--")) return ParseRes.failed(); + if (!(prev instanceof AssignableNode)) return ParseRes.error(src.loc(i + n), "Expected assignable value before suffix operator."); + n += 2; + + return ParseRes.res(new PostfixNode(loc, (AssignableNode)prev, -1), n); + } +} diff --git a/src/main/java/me/topchetoeu/jscript/runtime/Engine.java b/src/main/java/me/topchetoeu/jscript/runtime/Engine.java index e3cb05e..f9e80f9 100644 --- a/src/main/java/me/topchetoeu/jscript/runtime/Engine.java +++ b/src/main/java/me/topchetoeu/jscript/runtime/Engine.java @@ -41,10 +41,8 @@ public final class Engine implements EventLoop { try { ((Task)task).notifier.complete(task.runnable.get()); } - catch (RuntimeException e) { - if (e instanceof InterruptException) throw e; - task.notifier.completeExceptionally(e); - } + catch (InterruptException e) { throw e; } + catch (RuntimeException e) { task.notifier.completeExceptionally(e); } } catch (InterruptedException | InterruptException e) { for (var msg : tasks) msg.notifier.cancel(false); diff --git a/src/main/java/me/topchetoeu/jscript/runtime/SimpleRepl.java b/src/main/java/me/topchetoeu/jscript/runtime/SimpleRepl.java index 65f32a3..653655b 100644 --- a/src/main/java/me/topchetoeu/jscript/runtime/SimpleRepl.java +++ b/src/main/java/me/topchetoeu/jscript/runtime/SimpleRepl.java @@ -229,12 +229,21 @@ public class SimpleRepl { if (((ArgumentsValue)args.get(0)).frame.isNew) return new StringValue("new"); else return new StringValue("call"); })); + res.defineOwnMember(env, "invoke", new NativeFunction(args -> { var func = (FunctionValue)args.get(0); var self = args.get(1); var funcArgs = (ArrayValue)args.get(2); + var name = args.get(3).toString(env).value; - return func.call(env, self, funcArgs.toArray()); + return func.invoke(env, name, 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).value; + + return func.construct(env, name, funcArgs.toArray()); })); return res; @@ -264,7 +273,7 @@ public class SimpleRepl { var self = args.get(1); var funcArgs = (ArrayValue)args.get(2); - return func.call(env, self, funcArgs.toArray()); + return func.invoke(env, self, funcArgs.toArray()); })); return res; @@ -303,6 +312,12 @@ public class SimpleRepl { case "object": args.env.add(Value.OBJECT_PROTO, obj); break; + case "function": + args.env.add(Value.FUNCTION_PROTO, obj); + break; + case "array": + args.env.add(Value.ARRAY_PROTO, obj); + break; } return Value.UNDEFINED; 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 92828a0..5b2895b 100644 --- a/src/main/java/me/topchetoeu/jscript/runtime/values/Member.java +++ b/src/main/java/me/topchetoeu/jscript/runtime/values/Member.java @@ -13,12 +13,12 @@ public interface Member { public final boolean enumerable; @Override public Value get(Environment env, Value self) { - if (getter != null) return getter.call(env, self); + if (getter != null) return getter.call(env, false, "", self); else return Value.UNDEFINED; } @Override public boolean set(Environment env, Value val, Value self) { if (setter == null) return false; - setter.call(env, self, val); + setter.call(env, false, "", self, val); return true; } diff --git a/src/main/java/me/topchetoeu/jscript/runtime/values/primitives/VoidValue.java b/src/main/java/me/topchetoeu/jscript/runtime/values/primitives/VoidValue.java index 4c7c199..0a40322 100644 --- a/src/main/java/me/topchetoeu/jscript/runtime/values/primitives/VoidValue.java +++ b/src/main/java/me/topchetoeu/jscript/runtime/values/primitives/VoidValue.java @@ -1,7 +1,5 @@ package me.topchetoeu.jscript.runtime.values.primitives; -import java.util.Set; - import me.topchetoeu.jscript.common.environment.Environment; import me.topchetoeu.jscript.runtime.exceptions.EngineException; import me.topchetoeu.jscript.runtime.values.KeyCache; @@ -24,12 +22,6 @@ public final class VoidValue extends PrimitiveValue { @Override public Member getOwnMember(Environment env, KeyCache key) { throw EngineException.ofError(String.format("Cannot read properties of %s (reading '%s')", name, key.toString(env))); } - @Override public Set getOwnMembers(Environment env, boolean onlyEnumerable) { - throw EngineException.ofError(String.format("Cannot read properties of %s (listing all members)", name)); - } - @Override public Set getOwnSymbolMembers(Environment env, boolean onlyEnumerable) { - throw EngineException.ofError(String.format("Cannot read properties of %s (listing all symbol members)", name)); - } public VoidValue(String name, StringValue type) { this.name = name; diff --git a/src/main/resources/lib/index.js b/src/main/resources/lib/index.js index b901359..550cfa5 100644 --- a/src/main/resources/lib/index.js +++ b/src/main/resources/lib/index.js @@ -29,6 +29,7 @@ const invokeType = primordials.function.invokeType; const setConstructable = primordials.function.setConstructable; const setCallable = primordials.function.setCallable; const invoke = primordials.function.invoke; +const construct = primordials.function.construct; const json = primordials.json; @@ -305,9 +306,7 @@ defineField(Function.prototype, "valueOf", true, false, true, function() { target.Function = Function; -let spread_obj; - -setIntrinsic("spread_obj", spread_obj = (target, obj) => { +setIntrinsic("spread_obj", target.spread_obj = (target, obj) => { if (obj === null || obj === undefined) return; const members = getOwnMembers(obj, true); const symbols = getOwnSymbolMembers(obj, true); @@ -322,11 +321,16 @@ setIntrinsic("spread_obj", spread_obj = (target, obj) => { target[member] = obj[member]; } }); - -target.spread_obj = spread_obj; +setIntrinsic("apply", target.spread_call = (func, self, args) => { + return invoke(func, self, args); +}); +setIntrinsic("apply", target.spread_new = (func, args) => { + return invoke(func, null, args); +}); setGlobalPrototype("string", String.prototype); setGlobalPrototype("number", Number.prototype); setGlobalPrototype("boolean", Boolean.prototype); setGlobalPrototype("symbol", Symbol.prototype); setGlobalPrototype("object", Object.prototype); +setGlobalPrototype("function", Function.prototype);