refactor: clean up assigning
This commit is contained in:
parent
5f88061ee7
commit
8e64d13c87
@ -404,10 +404,10 @@ public class Instruction {
|
|||||||
return new Instruction(Type.LOAD_ARR, count);
|
return new Instruction(Type.LOAD_ARR, count);
|
||||||
}
|
}
|
||||||
public static Instruction dup() {
|
public static Instruction dup() {
|
||||||
return new Instruction(Type.DUP, 1);
|
return new Instruction(Type.DUP, 1, 0);
|
||||||
}
|
}
|
||||||
public static Instruction dup(int count) {
|
public static Instruction dup(int count, int offset) {
|
||||||
return new Instruction(Type.DUP, count);
|
return new Instruction(Type.DUP, count, offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Instruction storeVar(int i) {
|
public static Instruction storeVar(int i) {
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
package me.topchetoeu.jscript.compilation;
|
package me.topchetoeu.jscript.compilation;
|
||||||
|
|
||||||
import me.topchetoeu.jscript.common.Operation;
|
|
||||||
|
|
||||||
public interface AssignableNode {
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -33,7 +33,7 @@ public abstract class FunctionNode extends Node {
|
|||||||
return new CompileResult(env, scope, params.params.size(), target -> {
|
return new CompileResult(env, scope, params.params.size(), target -> {
|
||||||
if (params.params.size() > 0) {
|
if (params.params.size() > 0) {
|
||||||
target.add(Instruction.loadArgs(true));
|
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;
|
var i = 0;
|
||||||
|
|
||||||
for (var param : params.params) {
|
for (var param : params.params) {
|
||||||
|
@ -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.DiscardNode;
|
||||||
import me.topchetoeu.jscript.compilation.values.operations.IndexNode;
|
import me.topchetoeu.jscript.compilation.values.operations.IndexNode;
|
||||||
import me.topchetoeu.jscript.compilation.values.operations.OperationNode;
|
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.compilation.values.operations.TypeofNode;
|
||||||
import me.topchetoeu.jscript.runtime.exceptions.SyntaxException;
|
import me.topchetoeu.jscript.runtime.exceptions.SyntaxException;
|
||||||
|
|
||||||
@ -140,8 +141,8 @@ public final class JavaScript {
|
|||||||
ParseRes<Node> res = ParseRes.first(src, i + n,
|
ParseRes<Node> res = ParseRes.first(src, i + n,
|
||||||
(s, j) -> OperationNode.parseInstanceof(s, j, _prev, precedence),
|
(s, j) -> OperationNode.parseInstanceof(s, j, _prev, precedence),
|
||||||
(s, j) -> OperationNode.parseIn(s, j, _prev, precedence),
|
(s, j) -> OperationNode.parseIn(s, j, _prev, precedence),
|
||||||
(s, j) -> ChangeNode.parsePostfixIncrease(s, j, _prev, precedence),
|
(s, j) -> PostfixNode.parsePostfixIncrease(s, j, _prev, precedence),
|
||||||
(s, j) -> ChangeNode.parsePostfixDecrease(s, j, _prev, precedence),
|
(s, j) -> PostfixNode.parsePostfixDecrease(s, j, _prev, precedence),
|
||||||
(s, j) -> OperationNode.parseOperator(s, j, _prev, precedence),
|
(s, j) -> OperationNode.parseOperator(s, j, _prev, precedence),
|
||||||
(s, j) -> IfNode.parseTernary(s, j, _prev, precedence),
|
(s, j) -> IfNode.parseTernary(s, j, _prev, precedence),
|
||||||
(s, j) -> IndexNode.parseMember(s, j, _prev, precedence),
|
(s, j) -> IndexNode.parseMember(s, j, _prev, precedence),
|
||||||
|
@ -4,7 +4,6 @@ import java.util.function.IntFunction;
|
|||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
import me.topchetoeu.jscript.common.Instruction;
|
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.Location;
|
||||||
import me.topchetoeu.jscript.common.parsing.ParseRes;
|
import me.topchetoeu.jscript.common.parsing.ParseRes;
|
||||||
import me.topchetoeu.jscript.common.parsing.Parsing;
|
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.CompileResult;
|
||||||
import me.topchetoeu.jscript.compilation.JavaScript;
|
import me.topchetoeu.jscript.compilation.JavaScript;
|
||||||
import me.topchetoeu.jscript.compilation.Node;
|
import me.topchetoeu.jscript.compilation.Node;
|
||||||
import me.topchetoeu.jscript.compilation.values.operations.VariableAssignNode;
|
|
||||||
import me.topchetoeu.jscript.runtime.exceptions.SyntaxException;
|
import me.topchetoeu.jscript.runtime.exceptions.SyntaxException;
|
||||||
|
|
||||||
public class VariableNode extends Node implements AssignableNode {
|
public class VariableNode extends Node implements AssignableNode {
|
||||||
public final String name;
|
public final String name;
|
||||||
|
|
||||||
@Override public Node toAssign(Node val, Operation operation) {
|
@Override public String assignName() { return name; }
|
||||||
return new VariableAssignNode(loc(), name, val, operation);
|
|
||||||
|
@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) {
|
@Override public void compile(CompileResult target, boolean pollute) {
|
||||||
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
@ -13,24 +13,22 @@ import me.topchetoeu.jscript.compilation.Node;
|
|||||||
import me.topchetoeu.jscript.compilation.values.constants.NumberNode;
|
import me.topchetoeu.jscript.compilation.values.constants.NumberNode;
|
||||||
|
|
||||||
public class ChangeNode extends Node {
|
public class ChangeNode extends Node {
|
||||||
public final AssignableNode value;
|
public final AssignableNode assignable;
|
||||||
public final double addAmount;
|
public final Node value;
|
||||||
public final boolean postfix;
|
public final Operation op;
|
||||||
|
|
||||||
@Override public void compile(CompileResult target, boolean pollute) {
|
@Override public void compile(CompileResult target, boolean pollute) {
|
||||||
value.toAssign(new NumberNode(loc(), -addAmount), Operation.SUBTRACT).compile(target, true);
|
assignable.compileBeforeAssign(target, true);
|
||||||
if (!pollute) target.add(Instruction.discard());
|
value.compile(target, true);
|
||||||
else if (postfix) {
|
target.add(Instruction.operation(op));
|
||||||
target.add(Instruction.pushValue(addAmount));
|
assignable.compileAfterAssign(target, true, pollute);
|
||||||
target.add(Instruction.operation(Operation.SUBTRACT));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public ChangeNode(Location loc, AssignableNode value, double addAmount, boolean postfix) {
|
public ChangeNode(Location loc, AssignableNode assignable, Node value, Operation op) {
|
||||||
super(loc);
|
super(loc);
|
||||||
|
this.assignable = assignable;
|
||||||
this.value = value;
|
this.value = value;
|
||||||
this.addAmount = addAmount;
|
this.op = op;
|
||||||
this.postfix = postfix;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ParseRes<ChangeNode> parsePrefixIncrease(Source src, int i) {
|
public static ParseRes<ChangeNode> 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.");
|
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.");
|
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<ChangeNode> parsePrefixDecrease(Source src, int i) {
|
public static ParseRes<ChangeNode> parsePrefixDecrease(Source src, int i) {
|
||||||
var n = Parsing.skipEmpty(src, 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.");
|
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.");
|
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<ChangeNode> 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<ChangeNode> 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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,7 +1,6 @@
|
|||||||
package me.topchetoeu.jscript.compilation.values.operations;
|
package me.topchetoeu.jscript.compilation.values.operations;
|
||||||
|
|
||||||
import me.topchetoeu.jscript.common.Instruction;
|
import me.topchetoeu.jscript.common.Instruction;
|
||||||
import me.topchetoeu.jscript.common.Operation;
|
|
||||||
import me.topchetoeu.jscript.common.Instruction.BreakpointType;
|
import me.topchetoeu.jscript.common.Instruction.BreakpointType;
|
||||||
import me.topchetoeu.jscript.common.parsing.Location;
|
import me.topchetoeu.jscript.common.parsing.Location;
|
||||||
import me.topchetoeu.jscript.common.parsing.ParseRes;
|
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 object;
|
||||||
public final Node index;
|
public final Node index;
|
||||||
|
|
||||||
@Override public Node toAssign(Node val, Operation operation) {
|
@Override public void compileBeforeAssign(CompileResult target, boolean op) {
|
||||||
return new IndexAssignNode(loc(), object, index, val, operation);
|
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) {
|
public void compile(CompileResult target, boolean dupObj, boolean pollute) {
|
||||||
object.compile(target, true);
|
object.compile(target, true);
|
||||||
if (dupObj) target.add(Instruction.dup());
|
if (dupObj) target.add(Instruction.dup());
|
||||||
|
@ -58,7 +58,9 @@ public class OperationNode extends Node {
|
|||||||
|
|
||||||
var other = JavaScript.parseExpression(src, i, precedence);
|
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));
|
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) {
|
public AssignmentOperatorFactory(String token, int precedence, Operation operation) {
|
||||||
|
@ -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<ChangeNode> 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<ChangeNode> 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);
|
||||||
|
}
|
||||||
|
}
|
@ -41,10 +41,8 @@ public final class Engine implements EventLoop {
|
|||||||
try {
|
try {
|
||||||
((Task<Object>)task).notifier.complete(task.runnable.get());
|
((Task<Object>)task).notifier.complete(task.runnable.get());
|
||||||
}
|
}
|
||||||
catch (RuntimeException e) {
|
catch (InterruptException e) { throw e; }
|
||||||
if (e instanceof InterruptException) throw e;
|
catch (RuntimeException e) { task.notifier.completeExceptionally(e); }
|
||||||
task.notifier.completeExceptionally(e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
catch (InterruptedException | InterruptException e) {
|
catch (InterruptedException | InterruptException e) {
|
||||||
for (var msg : tasks) msg.notifier.cancel(false);
|
for (var msg : tasks) msg.notifier.cancel(false);
|
||||||
|
@ -229,12 +229,21 @@ public class SimpleRepl {
|
|||||||
if (((ArgumentsValue)args.get(0)).frame.isNew) return new StringValue("new");
|
if (((ArgumentsValue)args.get(0)).frame.isNew) return new StringValue("new");
|
||||||
else return new StringValue("call");
|
else return new StringValue("call");
|
||||||
}));
|
}));
|
||||||
|
|
||||||
res.defineOwnMember(env, "invoke", new NativeFunction(args -> {
|
res.defineOwnMember(env, "invoke", new NativeFunction(args -> {
|
||||||
var func = (FunctionValue)args.get(0);
|
var func = (FunctionValue)args.get(0);
|
||||||
var self = args.get(1);
|
var self = args.get(1);
|
||||||
var funcArgs = (ArrayValue)args.get(2);
|
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;
|
return res;
|
||||||
@ -264,7 +273,7 @@ public class SimpleRepl {
|
|||||||
var self = args.get(1);
|
var self = args.get(1);
|
||||||
var funcArgs = (ArrayValue)args.get(2);
|
var funcArgs = (ArrayValue)args.get(2);
|
||||||
|
|
||||||
return func.call(env, self, funcArgs.toArray());
|
return func.invoke(env, self, funcArgs.toArray());
|
||||||
}));
|
}));
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
@ -303,6 +312,12 @@ public class SimpleRepl {
|
|||||||
case "object":
|
case "object":
|
||||||
args.env.add(Value.OBJECT_PROTO, obj);
|
args.env.add(Value.OBJECT_PROTO, obj);
|
||||||
break;
|
break;
|
||||||
|
case "function":
|
||||||
|
args.env.add(Value.FUNCTION_PROTO, obj);
|
||||||
|
break;
|
||||||
|
case "array":
|
||||||
|
args.env.add(Value.ARRAY_PROTO, obj);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Value.UNDEFINED;
|
return Value.UNDEFINED;
|
||||||
|
@ -13,12 +13,12 @@ public interface Member {
|
|||||||
public final boolean enumerable;
|
public final boolean enumerable;
|
||||||
|
|
||||||
@Override public Value get(Environment env, Value self) {
|
@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;
|
else return Value.UNDEFINED;
|
||||||
}
|
}
|
||||||
@Override public boolean set(Environment env, Value val, Value self) {
|
@Override public boolean set(Environment env, Value val, Value self) {
|
||||||
if (setter == null) return false;
|
if (setter == null) return false;
|
||||||
setter.call(env, self, val);
|
setter.call(env, false, "", self, val);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,7 +1,5 @@
|
|||||||
package me.topchetoeu.jscript.runtime.values.primitives;
|
package me.topchetoeu.jscript.runtime.values.primitives;
|
||||||
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
import me.topchetoeu.jscript.common.environment.Environment;
|
import me.topchetoeu.jscript.common.environment.Environment;
|
||||||
import me.topchetoeu.jscript.runtime.exceptions.EngineException;
|
import me.topchetoeu.jscript.runtime.exceptions.EngineException;
|
||||||
import me.topchetoeu.jscript.runtime.values.KeyCache;
|
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) {
|
@Override public Member getOwnMember(Environment env, KeyCache key) {
|
||||||
throw EngineException.ofError(String.format("Cannot read properties of %s (reading '%s')", name, key.toString(env)));
|
throw EngineException.ofError(String.format("Cannot read properties of %s (reading '%s')", name, key.toString(env)));
|
||||||
}
|
}
|
||||||
@Override public Set<String> getOwnMembers(Environment env, boolean onlyEnumerable) {
|
|
||||||
throw EngineException.ofError(String.format("Cannot read properties of %s (listing all members)", name));
|
|
||||||
}
|
|
||||||
@Override public Set<SymbolValue> 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) {
|
public VoidValue(String name, StringValue type) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
|
@ -29,6 +29,7 @@ const invokeType = primordials.function.invokeType;
|
|||||||
const setConstructable = primordials.function.setConstructable;
|
const setConstructable = primordials.function.setConstructable;
|
||||||
const setCallable = primordials.function.setCallable;
|
const setCallable = primordials.function.setCallable;
|
||||||
const invoke = primordials.function.invoke;
|
const invoke = primordials.function.invoke;
|
||||||
|
const construct = primordials.function.construct;
|
||||||
|
|
||||||
const json = primordials.json;
|
const json = primordials.json;
|
||||||
|
|
||||||
@ -305,9 +306,7 @@ defineField(Function.prototype, "valueOf", true, false, true, function() {
|
|||||||
|
|
||||||
target.Function = Function;
|
target.Function = Function;
|
||||||
|
|
||||||
let spread_obj;
|
setIntrinsic("spread_obj", target.spread_obj = (target, obj) => {
|
||||||
|
|
||||||
setIntrinsic("spread_obj", spread_obj = (target, obj) => {
|
|
||||||
if (obj === null || obj === undefined) return;
|
if (obj === null || obj === undefined) return;
|
||||||
const members = getOwnMembers(obj, true);
|
const members = getOwnMembers(obj, true);
|
||||||
const symbols = getOwnSymbolMembers(obj, true);
|
const symbols = getOwnSymbolMembers(obj, true);
|
||||||
@ -322,11 +321,16 @@ setIntrinsic("spread_obj", spread_obj = (target, obj) => {
|
|||||||
target[member] = obj[member];
|
target[member] = obj[member];
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
setIntrinsic("apply", target.spread_call = (func, self, args) => {
|
||||||
target.spread_obj = spread_obj;
|
return invoke(func, self, args);
|
||||||
|
});
|
||||||
|
setIntrinsic("apply", target.spread_new = (func, args) => {
|
||||||
|
return invoke(func, null, args);
|
||||||
|
});
|
||||||
|
|
||||||
setGlobalPrototype("string", String.prototype);
|
setGlobalPrototype("string", String.prototype);
|
||||||
setGlobalPrototype("number", Number.prototype);
|
setGlobalPrototype("number", Number.prototype);
|
||||||
setGlobalPrototype("boolean", Boolean.prototype);
|
setGlobalPrototype("boolean", Boolean.prototype);
|
||||||
setGlobalPrototype("symbol", Symbol.prototype);
|
setGlobalPrototype("symbol", Symbol.prototype);
|
||||||
setGlobalPrototype("object", Object.prototype);
|
setGlobalPrototype("object", Object.prototype);
|
||||||
|
setGlobalPrototype("function", Function.prototype);
|
||||||
|
Loading…
Reference in New Issue
Block a user