refactor: distribute parse functions in node classes
This commit is contained in:
parent
bab59d454f
commit
ef0fc5a61d
@ -8,6 +8,7 @@ import me.topchetoeu.jscript.common.ParseRes;
|
||||
import me.topchetoeu.jscript.compilation.parsing.Operator;
|
||||
import me.topchetoeu.jscript.compilation.parsing.Parsing;
|
||||
import me.topchetoeu.jscript.compilation.parsing.Token;
|
||||
import me.topchetoeu.jscript.compilation.values.ConstantStatement;
|
||||
import me.topchetoeu.jscript.runtime.exceptions.SyntaxException;
|
||||
|
||||
public class JSON {
|
||||
@ -15,7 +16,7 @@ public class JSON {
|
||||
return Parsing.parseIdentifier(tokens, i);
|
||||
}
|
||||
public static ParseRes<String> parseString(Filename filename, List<Token> tokens, int i) {
|
||||
var res = Parsing.parseString(filename, tokens, i);
|
||||
var res = ConstantStatement.parseString(filename, tokens, i);
|
||||
if (res.isSuccess()) return ParseRes.res((String)res.result.value, res.n);
|
||||
else return res.transform();
|
||||
}
|
||||
@ -23,7 +24,7 @@ public class JSON {
|
||||
var minus = Parsing.isOperator(tokens, i, Operator.SUBTRACT);
|
||||
if (minus) i++;
|
||||
|
||||
var res = Parsing.parseNumber(filename, tokens, i);
|
||||
var res = ConstantStatement.parseNumber(filename, tokens, i);
|
||||
if (res.isSuccess()) return ParseRes.res((minus ? -1 : 1) * (Double)res.result.value, res.n + (minus ? 1 : 0));
|
||||
else return res.transform();
|
||||
}
|
||||
|
@ -1,7 +1,15 @@
|
||||
package me.topchetoeu.jscript.compilation;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import me.topchetoeu.jscript.common.Filename;
|
||||
import me.topchetoeu.jscript.common.Location;
|
||||
import me.topchetoeu.jscript.common.Operation;
|
||||
import me.topchetoeu.jscript.common.ParseRes;
|
||||
import me.topchetoeu.jscript.common.ParseRes.State;
|
||||
import me.topchetoeu.jscript.compilation.parsing.Operator;
|
||||
import me.topchetoeu.jscript.compilation.parsing.Parsing;
|
||||
import me.topchetoeu.jscript.compilation.parsing.Token;
|
||||
|
||||
public abstract class AssignableStatement extends Statement {
|
||||
public abstract Statement toAssign(Statement val, Operation operation);
|
||||
@ -9,4 +17,42 @@ public abstract class AssignableStatement extends Statement {
|
||||
protected AssignableStatement(Location loc) {
|
||||
super(loc);
|
||||
}
|
||||
|
||||
public static ParseRes<? extends Statement> parse(Filename filename, List<Token> tokens, int i, Statement prev, int precedence) {
|
||||
var loc = Parsing.getLoc(filename, tokens, i);
|
||||
int n = 0;
|
||||
|
||||
if (precedence > 2) return ParseRes.failed();
|
||||
|
||||
var opRes = Parsing.parseOperator(tokens, i + n++);
|
||||
if (opRes.state != State.SUCCESS) return ParseRes.failed();
|
||||
|
||||
var op = opRes.result;
|
||||
if (!op.isAssign()) return ParseRes.failed();
|
||||
|
||||
if (!(prev instanceof AssignableStatement)) {
|
||||
return ParseRes.error(loc, "Invalid expression on left hand side of assign operator.");
|
||||
}
|
||||
|
||||
var res = Parsing.parseValue(filename, tokens, i + n, 2);
|
||||
if (!res.isSuccess()) return ParseRes.error(loc, String.format("Expected value after assignment operator '%s'.", op.readable), res);
|
||||
n += res.n;
|
||||
|
||||
Operation operation = null;
|
||||
|
||||
if (op == Operator.ASSIGN_ADD) operation = Operation.ADD;
|
||||
if (op == Operator.ASSIGN_SUBTRACT) operation = Operation.SUBTRACT;
|
||||
if (op == Operator.ASSIGN_MULTIPLY) operation = Operation.MULTIPLY;
|
||||
if (op == Operator.ASSIGN_DIVIDE) operation = Operation.DIVIDE;
|
||||
if (op == Operator.ASSIGN_MODULO) operation = Operation.MODULO;
|
||||
if (op == Operator.ASSIGN_OR) operation = Operation.OR;
|
||||
if (op == Operator.ASSIGN_XOR) operation = Operation.XOR;
|
||||
if (op == Operator.ASSIGN_AND) operation = Operation.AND;
|
||||
if (op == Operator.ASSIGN_SHIFT_LEFT) operation = Operation.SHIFT_LEFT;
|
||||
if (op == Operator.ASSIGN_SHIFT_RIGHT) operation = Operation.SHIFT_RIGHT;
|
||||
if (op == Operator.ASSIGN_USHIFT_RIGHT) operation = Operation.USHIFT_RIGHT;
|
||||
|
||||
return ParseRes.res(((AssignableStatement)prev).toAssign(res.result, operation), n);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,11 +1,17 @@
|
||||
package me.topchetoeu.jscript.compilation;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Vector;
|
||||
|
||||
import me.topchetoeu.jscript.common.Filename;
|
||||
import me.topchetoeu.jscript.common.Instruction;
|
||||
import me.topchetoeu.jscript.common.Location;
|
||||
import me.topchetoeu.jscript.common.ParseRes;
|
||||
import me.topchetoeu.jscript.common.Instruction.BreakpointType;
|
||||
import me.topchetoeu.jscript.compilation.parsing.Operator;
|
||||
import me.topchetoeu.jscript.compilation.parsing.Parsing;
|
||||
import me.topchetoeu.jscript.compilation.parsing.Token;
|
||||
import me.topchetoeu.jscript.compilation.values.FunctionStatement;
|
||||
|
||||
public class CompoundStatement extends Statement {
|
||||
@ -61,4 +67,46 @@ public class CompoundStatement extends Statement {
|
||||
this.separateFuncs = separateFuncs;
|
||||
this.statements = statements;
|
||||
}
|
||||
|
||||
public static ParseRes<CompoundStatement> parseComma(Filename filename, List<Token> tokens, int i, Statement prev, int precedence) {
|
||||
var loc = Parsing.getLoc(filename, tokens, i);
|
||||
var n = 0;
|
||||
|
||||
if (precedence > 1) return ParseRes.failed();
|
||||
if (!Parsing.isOperator(tokens, i + n++, Operator.COMMA)) return ParseRes.failed();
|
||||
|
||||
var res = Parsing.parseValue(filename, tokens, i + n, 2);
|
||||
if (!res.isSuccess()) return ParseRes.error(loc, "Expected a value after the comma.", res);
|
||||
n += res.n;
|
||||
|
||||
return ParseRes.res(new CompoundStatement(loc, false, prev, res.result), n);
|
||||
}
|
||||
public static ParseRes<CompoundStatement> parse(Filename filename, List<Token> tokens, int i) {
|
||||
var loc = Parsing.getLoc(filename, tokens, i);
|
||||
int n = 0;
|
||||
if (!Parsing.isOperator(tokens, i + n++, Operator.BRACE_OPEN)) return ParseRes.failed();
|
||||
|
||||
var statements = new ArrayList<Statement>();
|
||||
|
||||
while (true) {
|
||||
if (Parsing.isOperator(tokens, i + n, Operator.BRACE_CLOSE)) {
|
||||
n++;
|
||||
break;
|
||||
}
|
||||
if (Parsing.isOperator(tokens, i + n, Operator.SEMICOLON)) {
|
||||
n++;
|
||||
continue;
|
||||
}
|
||||
|
||||
var res = Parsing.parseStatement(filename, tokens, i + n);
|
||||
if (!res.isSuccess()) {
|
||||
return ParseRes.error(Parsing.getLoc(filename, tokens, i), "Expected a statement.", res);
|
||||
}
|
||||
n += res.n;
|
||||
|
||||
statements.add(res.result);
|
||||
}
|
||||
|
||||
return ParseRes.res(new CompoundStatement(loc, true, statements.toArray(Statement[]::new)).setEnd(Parsing.getLoc(filename, tokens, i + n - 1)), n);
|
||||
}
|
||||
}
|
||||
|
@ -1,10 +1,16 @@
|
||||
package me.topchetoeu.jscript.compilation;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import me.topchetoeu.jscript.common.Filename;
|
||||
import me.topchetoeu.jscript.common.Instruction;
|
||||
import me.topchetoeu.jscript.common.Location;
|
||||
import me.topchetoeu.jscript.common.ParseRes;
|
||||
import me.topchetoeu.jscript.common.Instruction.BreakpointType;
|
||||
import me.topchetoeu.jscript.compilation.parsing.Operator;
|
||||
import me.topchetoeu.jscript.compilation.parsing.Parsing;
|
||||
import me.topchetoeu.jscript.compilation.parsing.Token;
|
||||
import me.topchetoeu.jscript.compilation.values.FunctionStatement;
|
||||
|
||||
public class VariableDeclareStatement extends Statement {
|
||||
@ -49,4 +55,49 @@ public class VariableDeclareStatement extends Statement {
|
||||
super(loc);
|
||||
this.values = values;
|
||||
}
|
||||
|
||||
public static ParseRes<VariableDeclareStatement> parse(Filename filename, List<Token> tokens, int i) {
|
||||
var loc = Parsing.getLoc(filename, tokens, i);
|
||||
int n = 0;
|
||||
if (!Parsing.isIdentifier(tokens, i + n++, "var")) return ParseRes.failed();
|
||||
|
||||
var res = new ArrayList<Pair>();
|
||||
|
||||
if (Parsing.isStatementEnd(tokens, i + n)) {
|
||||
if (Parsing.isOperator(tokens, i + n, Operator.SEMICOLON)) return ParseRes.res(new VariableDeclareStatement(loc, res), 2);
|
||||
else return ParseRes.res(new VariableDeclareStatement(loc, res), 1);
|
||||
}
|
||||
|
||||
while (true) {
|
||||
var nameLoc = Parsing.getLoc(filename, tokens, i + n);
|
||||
var nameRes = Parsing.parseIdentifier(tokens, i + n++);
|
||||
if (!nameRes.isSuccess()) return ParseRes.error(loc, "Expected a variable name.");
|
||||
|
||||
if (!Parsing.checkVarName(nameRes.result)) {
|
||||
return ParseRes.error(loc, String.format("Unexpected identifier '%s'.", nameRes.result));
|
||||
}
|
||||
|
||||
Statement val = null;
|
||||
|
||||
if (Parsing.isOperator(tokens, i + n, Operator.ASSIGN)) {
|
||||
n++;
|
||||
var valRes = Parsing.parseValue(filename, tokens, i + n, 2);
|
||||
if (!valRes.isSuccess()) return ParseRes.error(loc, "Expected a value after '='.", valRes);
|
||||
n += valRes.n;
|
||||
val = valRes.result;
|
||||
}
|
||||
|
||||
res.add(new Pair(nameRes.result, val, nameLoc));
|
||||
|
||||
if (Parsing.isOperator(tokens, i + n, Operator.COMMA)) {
|
||||
n++;
|
||||
continue;
|
||||
}
|
||||
else if (Parsing.isStatementEnd(tokens, i + n)) {
|
||||
if (Parsing.isOperator(tokens, i + n, Operator.SEMICOLON)) return ParseRes.res(new VariableDeclareStatement(loc, res), n + 1);
|
||||
else return ParseRes.res(new VariableDeclareStatement(loc, res), n);
|
||||
}
|
||||
else return ParseRes.error(loc, "Expected a comma or end of statement.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,15 +1,21 @@
|
||||
package me.topchetoeu.jscript.compilation.control;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import me.topchetoeu.jscript.common.Filename;
|
||||
import me.topchetoeu.jscript.common.Instruction;
|
||||
import me.topchetoeu.jscript.common.Location;
|
||||
import me.topchetoeu.jscript.common.ParseRes;
|
||||
import me.topchetoeu.jscript.compilation.CompileResult;
|
||||
import me.topchetoeu.jscript.compilation.Statement;
|
||||
import me.topchetoeu.jscript.compilation.parsing.Operator;
|
||||
import me.topchetoeu.jscript.compilation.parsing.Parsing;
|
||||
import me.topchetoeu.jscript.compilation.parsing.Token;
|
||||
|
||||
public class BreakStatement extends Statement {
|
||||
public final String label;
|
||||
|
||||
@Override
|
||||
public void compile(CompileResult target, boolean pollute) {
|
||||
@Override public void compile(CompileResult target, boolean pollute) {
|
||||
target.add(Instruction.nop("break", label));
|
||||
if (pollute) target.add(Instruction.pushUndefined());
|
||||
}
|
||||
@ -18,4 +24,23 @@ public class BreakStatement extends Statement {
|
||||
super(loc);
|
||||
this.label = label;
|
||||
}
|
||||
|
||||
public static ParseRes<BreakStatement> parseBreak(Filename filename, List<Token> tokens, int i) {
|
||||
if (!Parsing.isIdentifier(tokens, i, "break")) return ParseRes.failed();
|
||||
|
||||
if (Parsing.isStatementEnd(tokens, i + 1)) {
|
||||
if (Parsing.isOperator(tokens, i + 1, Operator.SEMICOLON)) return ParseRes.res(new BreakStatement(Parsing.getLoc(filename, tokens, i), null), 2);
|
||||
else return ParseRes.res(new BreakStatement(Parsing.getLoc(filename, tokens, i), null), 1);
|
||||
}
|
||||
|
||||
var labelRes = Parsing.parseIdentifier(tokens, i + 1);
|
||||
if (labelRes.isFailed()) return ParseRes.error(Parsing.getLoc(filename, tokens, i), "Expected a label name or an end of statement.");
|
||||
var label = labelRes.result;
|
||||
|
||||
if (Parsing.isStatementEnd(tokens, i + 2)) {
|
||||
if (Parsing.isOperator(tokens, i + 2, Operator.SEMICOLON)) return ParseRes.res(new BreakStatement(Parsing.getLoc(filename, tokens, i), label), 3);
|
||||
else return ParseRes.res(new BreakStatement(Parsing.getLoc(filename, tokens, i), label), 2);
|
||||
}
|
||||
else return ParseRes.error(Parsing.getLoc(filename, tokens, i), "Expected an end of statement.");
|
||||
}
|
||||
}
|
||||
|
@ -1,15 +1,21 @@
|
||||
package me.topchetoeu.jscript.compilation.control;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import me.topchetoeu.jscript.common.Filename;
|
||||
import me.topchetoeu.jscript.common.Instruction;
|
||||
import me.topchetoeu.jscript.common.Location;
|
||||
import me.topchetoeu.jscript.common.ParseRes;
|
||||
import me.topchetoeu.jscript.compilation.CompileResult;
|
||||
import me.topchetoeu.jscript.compilation.Statement;
|
||||
import me.topchetoeu.jscript.compilation.parsing.Operator;
|
||||
import me.topchetoeu.jscript.compilation.parsing.Parsing;
|
||||
import me.topchetoeu.jscript.compilation.parsing.Token;
|
||||
|
||||
public class ContinueStatement extends Statement {
|
||||
public final String label;
|
||||
|
||||
@Override
|
||||
public void compile(CompileResult target, boolean pollute) {
|
||||
@Override public void compile(CompileResult target, boolean pollute) {
|
||||
target.add(Instruction.nop("cont", label));
|
||||
if (pollute) target.add(Instruction.pushUndefined());
|
||||
}
|
||||
@ -18,4 +24,23 @@ public class ContinueStatement extends Statement {
|
||||
super(loc);
|
||||
this.label = label;
|
||||
}
|
||||
|
||||
public static ParseRes<ContinueStatement> parseContinue(Filename filename, List<Token> tokens, int i) {
|
||||
if (!Parsing.isIdentifier(tokens, i, "continue")) return ParseRes.failed();
|
||||
|
||||
if (Parsing.isStatementEnd(tokens, i + 1)) {
|
||||
if (Parsing.isOperator(tokens, i + 1, Operator.SEMICOLON)) return ParseRes.res(new ContinueStatement(Parsing.getLoc(filename, tokens, i), null), 2);
|
||||
else return ParseRes.res(new ContinueStatement(Parsing.getLoc(filename, tokens, i), null), 1);
|
||||
}
|
||||
|
||||
var labelRes = Parsing.parseIdentifier(tokens, i + 1);
|
||||
if (labelRes.isFailed()) return ParseRes.error(Parsing.getLoc(filename, tokens, i), "Expected a label name or an end of statement.");
|
||||
var label = labelRes.result;
|
||||
|
||||
if (Parsing.isStatementEnd(tokens, i + 2)) {
|
||||
if (Parsing.isOperator(tokens, i + 2, Operator.SEMICOLON)) return ParseRes.res(new ContinueStatement(Parsing.getLoc(filename, tokens, i), label), 3);
|
||||
else return ParseRes.res(new ContinueStatement(Parsing.getLoc(filename, tokens, i), label), 2);
|
||||
}
|
||||
else return ParseRes.error(Parsing.getLoc(filename, tokens, i), "Expected an end of statement.");
|
||||
}
|
||||
}
|
||||
|
@ -1,13 +1,19 @@
|
||||
package me.topchetoeu.jscript.compilation.control;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import me.topchetoeu.jscript.common.Filename;
|
||||
import me.topchetoeu.jscript.common.Instruction;
|
||||
import me.topchetoeu.jscript.common.Location;
|
||||
import me.topchetoeu.jscript.common.ParseRes;
|
||||
import me.topchetoeu.jscript.compilation.CompileResult;
|
||||
import me.topchetoeu.jscript.compilation.Statement;
|
||||
import me.topchetoeu.jscript.compilation.parsing.Operator;
|
||||
import me.topchetoeu.jscript.compilation.parsing.Parsing;
|
||||
import me.topchetoeu.jscript.compilation.parsing.Token;
|
||||
|
||||
public class DebugStatement extends Statement {
|
||||
@Override
|
||||
public void compile(CompileResult target, boolean pollute) {
|
||||
@Override public void compile(CompileResult target, boolean pollute) {
|
||||
target.add(Instruction.debug());
|
||||
if (pollute) target.add(Instruction.pushUndefined());
|
||||
}
|
||||
@ -15,4 +21,15 @@ public class DebugStatement extends Statement {
|
||||
public DebugStatement(Location loc) {
|
||||
super(loc);
|
||||
}
|
||||
|
||||
public static ParseRes<DebugStatement> parse(Filename filename, List<Token> tokens, int i) {
|
||||
if (!Parsing.isIdentifier(tokens, i, "debugger")) return ParseRes.failed();
|
||||
|
||||
if (Parsing.isStatementEnd(tokens, i + 1)) {
|
||||
if (Parsing.isOperator(tokens, i + 1, Operator.SEMICOLON)) return ParseRes.res(new DebugStatement(Parsing.getLoc(filename, tokens, i)), 2);
|
||||
else return ParseRes.res(new DebugStatement(Parsing.getLoc(filename, tokens, i)), 1);
|
||||
}
|
||||
else return ParseRes.error(Parsing.getLoc(filename, tokens, i), "Expected an end of statement.");
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,9 +1,18 @@
|
||||
package me.topchetoeu.jscript.compilation.control;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import me.topchetoeu.jscript.common.Filename;
|
||||
import me.topchetoeu.jscript.common.Instruction;
|
||||
import me.topchetoeu.jscript.common.Location;
|
||||
import me.topchetoeu.jscript.common.ParseRes;
|
||||
import me.topchetoeu.jscript.compilation.CompileResult;
|
||||
import me.topchetoeu.jscript.compilation.Statement;
|
||||
import me.topchetoeu.jscript.compilation.parsing.Parsing;
|
||||
import me.topchetoeu.jscript.compilation.parsing.Token;
|
||||
import me.topchetoeu.jscript.compilation.values.ConstantStatement;
|
||||
import me.topchetoeu.jscript.compilation.values.IndexStatement;
|
||||
import me.topchetoeu.jscript.compilation.values.VariableStatement;
|
||||
|
||||
public class DeleteStatement extends Statement {
|
||||
public final Statement key;
|
||||
@ -18,6 +27,25 @@ public class DeleteStatement extends Statement {
|
||||
if (pollute) target.add(Instruction.pushValue(true));
|
||||
}
|
||||
|
||||
public static ParseRes<? extends Statement> parseDelete(Filename filename, List<Token> tokens, int i) {
|
||||
var loc = Parsing.getLoc(filename, tokens, i);
|
||||
int n = 0;
|
||||
if (!Parsing.isIdentifier(tokens, i + n++, "delete")) return ParseRes.failed();
|
||||
|
||||
var valRes = Parsing.parseValue(filename, tokens, i + n, 15);
|
||||
if (!valRes.isSuccess()) return ParseRes.error(loc, "Expected a value after 'delete'.", valRes);
|
||||
n += valRes.n;
|
||||
|
||||
if (valRes.result instanceof IndexStatement) {
|
||||
var index = (IndexStatement)valRes.result;
|
||||
return ParseRes.res(new DeleteStatement(loc, index.index, index.object), n);
|
||||
}
|
||||
else if (valRes.result instanceof VariableStatement) {
|
||||
return ParseRes.error(loc, "A variable may not be deleted.");
|
||||
}
|
||||
else return ParseRes.res(new ConstantStatement(loc, true), n);
|
||||
}
|
||||
|
||||
public DeleteStatement(Location loc, Statement key, Statement value) {
|
||||
super(loc);
|
||||
this.key = key;
|
||||
|
@ -1,10 +1,17 @@
|
||||
package me.topchetoeu.jscript.compilation.control;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import me.topchetoeu.jscript.common.Filename;
|
||||
import me.topchetoeu.jscript.common.Instruction;
|
||||
import me.topchetoeu.jscript.common.Location;
|
||||
import me.topchetoeu.jscript.common.ParseRes;
|
||||
import me.topchetoeu.jscript.common.Instruction.BreakpointType;
|
||||
import me.topchetoeu.jscript.compilation.CompileResult;
|
||||
import me.topchetoeu.jscript.compilation.Statement;
|
||||
import me.topchetoeu.jscript.compilation.parsing.Operator;
|
||||
import me.topchetoeu.jscript.compilation.parsing.Parsing;
|
||||
import me.topchetoeu.jscript.compilation.parsing.Token;
|
||||
|
||||
public class DoWhileStatement extends Statement {
|
||||
public final Statement condition, body;
|
||||
@ -33,4 +40,35 @@ public class DoWhileStatement extends Statement {
|
||||
this.condition = condition;
|
||||
this.body = body;
|
||||
}
|
||||
|
||||
public static ParseRes<DoWhileStatement> parseDoWhile(Filename filename, List<Token> tokens, int i) {
|
||||
var loc = Parsing.getLoc(filename, tokens, i);
|
||||
int n = 0;
|
||||
|
||||
var labelRes = WhileStatement.parseLabel(tokens, i + n);
|
||||
n += labelRes.n;
|
||||
|
||||
if (!Parsing.isIdentifier(tokens, i + n++, "do")) return ParseRes.failed();
|
||||
var bodyRes = Parsing.parseStatement(filename, tokens, i + n);
|
||||
if (!bodyRes.isSuccess()) return ParseRes.error(loc, "Expected a do-while body.", bodyRes);
|
||||
n += bodyRes.n;
|
||||
|
||||
if (!Parsing.isIdentifier(tokens, i + n++, "while")) return ParseRes.error(loc, "Expected 'while' keyword.");
|
||||
if (!Parsing.isOperator(tokens, i + n++, Operator.PAREN_OPEN)) return ParseRes.error(loc, "Expected a open paren after 'while'.");
|
||||
|
||||
var condRes = Parsing.parseValue(filename, tokens, i + n, 0);
|
||||
if (!condRes.isSuccess()) return ParseRes.error(loc, "Expected a while condition.", condRes);
|
||||
n += condRes.n;
|
||||
|
||||
if (!Parsing.isOperator(tokens, i + n++, Operator.PAREN_CLOSE)) return ParseRes.error(loc, "Expected a closing paren after while condition.");
|
||||
|
||||
var res = ParseRes.res(new DoWhileStatement(loc, labelRes.result, condRes.result, bodyRes.result), n);
|
||||
|
||||
if (Parsing.isStatementEnd(tokens, i + n)) {
|
||||
if (Parsing.isOperator(tokens, i + n, Operator.SEMICOLON)) return res.addN(1);
|
||||
else return res;
|
||||
}
|
||||
else return ParseRes.error(Parsing.getLoc(filename, tokens, i), "Expected a semicolon.");
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,11 +1,18 @@
|
||||
package me.topchetoeu.jscript.compilation.control;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import me.topchetoeu.jscript.common.Filename;
|
||||
import me.topchetoeu.jscript.common.Instruction;
|
||||
import me.topchetoeu.jscript.common.Location;
|
||||
import me.topchetoeu.jscript.common.Operation;
|
||||
import me.topchetoeu.jscript.common.ParseRes;
|
||||
import me.topchetoeu.jscript.common.Instruction.BreakpointType;
|
||||
import me.topchetoeu.jscript.compilation.CompileResult;
|
||||
import me.topchetoeu.jscript.compilation.Statement;
|
||||
import me.topchetoeu.jscript.compilation.parsing.Operator;
|
||||
import me.topchetoeu.jscript.compilation.parsing.Parsing;
|
||||
import me.topchetoeu.jscript.compilation.parsing.Token;
|
||||
|
||||
public class ForInStatement extends Statement {
|
||||
public final String varName;
|
||||
@ -14,14 +21,12 @@ public class ForInStatement extends Statement {
|
||||
public final String label;
|
||||
public final Location varLocation;
|
||||
|
||||
@Override
|
||||
public void declare(CompileResult target) {
|
||||
@Override public void declare(CompileResult target) {
|
||||
body.declare(target);
|
||||
if (isDeclaration) target.scope.define(varName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void compile(CompileResult target, boolean pollute) {
|
||||
@Override public void compile(CompileResult target, boolean pollute) {
|
||||
var key = target.scope.getKey(varName);
|
||||
|
||||
if (key instanceof String) target.add(Instruction.makeVar((String)key));
|
||||
@ -66,4 +71,60 @@ public class ForInStatement extends Statement {
|
||||
this.object = object;
|
||||
this.body = body;
|
||||
}
|
||||
|
||||
public static ParseRes<ForInStatement> parse(Filename filename, List<Token> tokens, int i) {
|
||||
var loc = Parsing.getLoc(filename, tokens, i);
|
||||
int n = 0;
|
||||
|
||||
var labelRes = WhileStatement.parseLabel(tokens, i + n);
|
||||
var isDecl = false;
|
||||
n += labelRes.n;
|
||||
|
||||
if (!Parsing.isIdentifier(tokens, i + n++, "for")) return ParseRes.failed();
|
||||
if (!Parsing.isOperator(tokens, i + n++, Operator.PAREN_OPEN)) return ParseRes.error(loc, "Expected a open paren after 'for'.");
|
||||
|
||||
if (Parsing.isIdentifier(tokens, i + n, "var")) {
|
||||
isDecl = true;
|
||||
n++;
|
||||
}
|
||||
|
||||
var nameRes = Parsing.parseIdentifier(tokens, i + n);
|
||||
if (!nameRes.isSuccess()) return ParseRes.error(loc, "Expected a variable name for 'for' loop.");
|
||||
var nameLoc = Parsing.getLoc(filename, tokens, i + n);
|
||||
n += nameRes.n;
|
||||
|
||||
Statement varVal = null;
|
||||
|
||||
if (Parsing.isOperator(tokens, i + n, Operator.ASSIGN)) {
|
||||
n++;
|
||||
|
||||
var valRes = Parsing.parseValue(filename, tokens, i + n, 2);
|
||||
if (!valRes.isSuccess()) return ParseRes.error(loc, "Expected a value after '='.", valRes);
|
||||
n += nameRes.n;
|
||||
|
||||
varVal = valRes.result;
|
||||
}
|
||||
|
||||
if (!Parsing.isIdentifier(tokens, i + n++, "in")) {
|
||||
if (varVal == null) {
|
||||
if (nameRes.result.equals("const")) return ParseRes.error(loc, "'const' declarations are not supported.");
|
||||
else if (nameRes.result.equals("let")) return ParseRes.error(loc, "'let' declarations are not supported.");
|
||||
}
|
||||
return ParseRes.error(loc, "Expected 'in' keyword after variable declaration.");
|
||||
}
|
||||
|
||||
var objRes = Parsing.parseValue(filename, tokens, i + n, 0);
|
||||
if (!objRes.isSuccess()) return ParseRes.error(loc, "Expected a value.", objRes);
|
||||
n += objRes.n;
|
||||
|
||||
if (!Parsing.isOperator(tokens, i + n++, Operator.PAREN_CLOSE)) return ParseRes.error(loc, "Expected a closing paren after for.");
|
||||
|
||||
|
||||
var bodyRes = Parsing.parseStatement(filename, tokens, i + n);
|
||||
if (!bodyRes.isSuccess()) return ParseRes.error(loc, "Expected a for body.", bodyRes);
|
||||
n += bodyRes.n;
|
||||
|
||||
return ParseRes.res(new ForInStatement(loc, nameLoc, labelRes.result, isDecl, nameRes.result, varVal, objRes.result, bodyRes.result), n);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,10 +1,17 @@
|
||||
package me.topchetoeu.jscript.compilation.control;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import me.topchetoeu.jscript.common.Filename;
|
||||
import me.topchetoeu.jscript.common.Instruction;
|
||||
import me.topchetoeu.jscript.common.Location;
|
||||
import me.topchetoeu.jscript.common.ParseRes;
|
||||
import me.topchetoeu.jscript.common.Instruction.BreakpointType;
|
||||
import me.topchetoeu.jscript.compilation.CompileResult;
|
||||
import me.topchetoeu.jscript.compilation.Statement;
|
||||
import me.topchetoeu.jscript.compilation.parsing.Operator;
|
||||
import me.topchetoeu.jscript.compilation.parsing.Parsing;
|
||||
import me.topchetoeu.jscript.compilation.parsing.Token;
|
||||
|
||||
public class ForOfStatement extends Statement {
|
||||
public final String varName;
|
||||
@ -70,4 +77,45 @@ public class ForOfStatement extends Statement {
|
||||
this.iterable = object;
|
||||
this.body = body;
|
||||
}
|
||||
|
||||
public static ParseRes<ForOfStatement> parse(Filename filename, List<Token> tokens, int i) {
|
||||
var loc = Parsing.getLoc(filename, tokens, i);
|
||||
int n = 0;
|
||||
|
||||
var labelRes = WhileStatement.parseLabel(tokens, i + n);
|
||||
var isDecl = false;
|
||||
n += labelRes.n;
|
||||
|
||||
if (!Parsing.isIdentifier(tokens, i + n++, "for")) return ParseRes.failed();
|
||||
if (!Parsing.isOperator(tokens, i + n++, Operator.PAREN_OPEN)) return ParseRes.error(loc, "Expected a open paren after 'for'.");
|
||||
|
||||
if (Parsing.isIdentifier(tokens, i + n, "var")) {
|
||||
isDecl = true;
|
||||
n++;
|
||||
}
|
||||
|
||||
var nameRes = Parsing.parseIdentifier(tokens, i + n);
|
||||
if (!nameRes.isSuccess()) return ParseRes.error(loc, "Expected a variable name for 'for' loop.");
|
||||
var nameLoc = Parsing.getLoc(filename, tokens, i + n);
|
||||
n += nameRes.n;
|
||||
|
||||
if (!Parsing.isIdentifier(tokens, i + n++, "of")) {
|
||||
if (nameRes.result.equals("const")) return ParseRes.error(loc, "'const' declarations are not supported.");
|
||||
else if (nameRes.result.equals("let")) return ParseRes.error(loc, "'let' declarations are not supported.");
|
||||
else return ParseRes.error(loc, "Expected 'of' keyword after variable declaration.");
|
||||
}
|
||||
|
||||
var objRes = Parsing.parseValue(filename, tokens, i + n, 0);
|
||||
if (!objRes.isSuccess()) return ParseRes.error(loc, "Expected a value.", objRes);
|
||||
n += objRes.n;
|
||||
|
||||
if (!Parsing.isOperator(tokens, i + n++, Operator.PAREN_CLOSE)) return ParseRes.error(loc, "Expected a closing paren after for.");
|
||||
|
||||
|
||||
var bodyRes = Parsing.parseStatement(filename, tokens, i + n);
|
||||
if (!bodyRes.isSuccess()) return ParseRes.error(loc, "Expected a for body.", bodyRes);
|
||||
n += bodyRes.n;
|
||||
|
||||
return ParseRes.res(new ForOfStatement(loc, nameLoc, labelRes.result, isDecl, nameRes.result, objRes.result, bodyRes.result), n);
|
||||
}
|
||||
}
|
||||
|
@ -1,10 +1,20 @@
|
||||
package me.topchetoeu.jscript.compilation.control;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import me.topchetoeu.jscript.common.Filename;
|
||||
import me.topchetoeu.jscript.common.Instruction;
|
||||
import me.topchetoeu.jscript.common.Location;
|
||||
import me.topchetoeu.jscript.common.ParseRes;
|
||||
import me.topchetoeu.jscript.common.Instruction.BreakpointType;
|
||||
import me.topchetoeu.jscript.compilation.CompileResult;
|
||||
import me.topchetoeu.jscript.compilation.CompoundStatement;
|
||||
import me.topchetoeu.jscript.compilation.Statement;
|
||||
import me.topchetoeu.jscript.compilation.VariableDeclareStatement;
|
||||
import me.topchetoeu.jscript.compilation.parsing.Operator;
|
||||
import me.topchetoeu.jscript.compilation.parsing.Parsing;
|
||||
import me.topchetoeu.jscript.compilation.parsing.Token;
|
||||
import me.topchetoeu.jscript.compilation.values.ConstantStatement;
|
||||
|
||||
public class ForStatement extends Statement {
|
||||
public final Statement declaration, assignment, condition, body;
|
||||
@ -42,4 +52,62 @@ public class ForStatement extends Statement {
|
||||
this.assignment = assignment;
|
||||
this.body = body;
|
||||
}
|
||||
|
||||
public static ParseRes<ForStatement> parse(Filename filename, List<Token> tokens, int i) {
|
||||
var loc = Parsing.getLoc(filename, tokens, i);
|
||||
int n = 0;
|
||||
|
||||
var labelRes = WhileStatement.parseLabel(tokens, i + n);
|
||||
n += labelRes.n;
|
||||
|
||||
if (!Parsing.isIdentifier(tokens, i + n++, "for")) return ParseRes.failed();
|
||||
if (!Parsing.isOperator(tokens, i + n++, Operator.PAREN_OPEN)) return ParseRes.error(loc, "Expected a open paren after 'for'.");
|
||||
|
||||
Statement decl, cond, inc;
|
||||
|
||||
if (Parsing.isOperator(tokens, i + n, Operator.SEMICOLON)) {
|
||||
n++;
|
||||
decl = new CompoundStatement(loc, false);
|
||||
}
|
||||
else {
|
||||
var declRes = ParseRes.any(
|
||||
VariableDeclareStatement.parse(filename, tokens, i + n),
|
||||
Parsing.parseValueStatement(filename, tokens, i + n)
|
||||
);
|
||||
if (!declRes.isSuccess()) return ParseRes.error(loc, "Expected a declaration or an expression.", declRes);
|
||||
n += declRes.n;
|
||||
decl = declRes.result;
|
||||
}
|
||||
|
||||
if (Parsing.isOperator(tokens, i + n, Operator.SEMICOLON)) {
|
||||
n++;
|
||||
cond = new ConstantStatement(loc, 1);
|
||||
}
|
||||
else {
|
||||
var condRes = Parsing.parseValue(filename, tokens, i + n, 0);
|
||||
if (!condRes.isSuccess()) return ParseRes.error(loc, "Expected a condition.", condRes);
|
||||
n += condRes.n;
|
||||
if (!Parsing.isOperator(tokens, i + n++, Operator.SEMICOLON)) return ParseRes.error(loc, "Expected a semicolon.", condRes);
|
||||
cond = condRes.result;
|
||||
}
|
||||
|
||||
if (Parsing.isOperator(tokens, i + n, Operator.PAREN_CLOSE)) {
|
||||
n++;
|
||||
inc = new CompoundStatement(loc, false);
|
||||
}
|
||||
else {
|
||||
var incRes = Parsing.parseValue(filename, tokens, i + n, 0);
|
||||
if (!incRes.isSuccess()) return ParseRes.error(loc, "Expected a condition.", incRes);
|
||||
n += incRes.n;
|
||||
inc = incRes.result;
|
||||
if (!Parsing.isOperator(tokens, i + n++, Operator.PAREN_CLOSE)) return ParseRes.error(loc, "Expected a closing paren after for.");
|
||||
}
|
||||
|
||||
|
||||
var res = Parsing.parseStatement(filename, tokens, i + n);
|
||||
if (!res.isSuccess()) return ParseRes.error(loc, "Expected a for body.", res);
|
||||
n += res.n;
|
||||
|
||||
return ParseRes.res(new ForStatement(loc, labelRes.result, decl, cond, inc, res.result), n);
|
||||
}
|
||||
}
|
||||
|
@ -1,10 +1,17 @@
|
||||
package me.topchetoeu.jscript.compilation.control;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import me.topchetoeu.jscript.common.Filename;
|
||||
import me.topchetoeu.jscript.common.Instruction;
|
||||
import me.topchetoeu.jscript.common.Location;
|
||||
import me.topchetoeu.jscript.common.ParseRes;
|
||||
import me.topchetoeu.jscript.common.Instruction.BreakpointType;
|
||||
import me.topchetoeu.jscript.compilation.CompileResult;
|
||||
import me.topchetoeu.jscript.compilation.Statement;
|
||||
import me.topchetoeu.jscript.compilation.parsing.Operator;
|
||||
import me.topchetoeu.jscript.compilation.parsing.Parsing;
|
||||
import me.topchetoeu.jscript.compilation.parsing.Token;
|
||||
|
||||
public class IfStatement extends Statement {
|
||||
public final Statement condition, body, elseBody;
|
||||
@ -45,4 +52,51 @@ public class IfStatement extends Statement {
|
||||
this.body = body;
|
||||
this.elseBody = elseBody;
|
||||
}
|
||||
|
||||
public static ParseRes<IfStatement> parseTernary(Filename filename, List<Token> tokens, int i, Statement prev, int precedence) {
|
||||
var loc = Parsing.getLoc(filename, tokens, i);
|
||||
var n = 0;
|
||||
|
||||
if (precedence > 2) return ParseRes.failed();
|
||||
if (!Parsing.isOperator(tokens, i + n++, Operator.QUESTION)) return ParseRes.failed();
|
||||
|
||||
var a = Parsing.parseValue(filename, tokens, i + n, 2);
|
||||
if (!a.isSuccess()) return ParseRes.error(loc, "Expected a value after the ternary operator.", a);
|
||||
n += a.n;
|
||||
|
||||
if (!Parsing.isOperator(tokens, i + n++, Operator.COLON)) return ParseRes.failed();
|
||||
|
||||
var b = Parsing.parseValue(filename, tokens, i + n, 2);
|
||||
if (!b.isSuccess()) return ParseRes.error(loc, "Expected a second value after the ternary operator.", b);
|
||||
n += b.n;
|
||||
|
||||
return ParseRes.res(new IfStatement(loc, prev, a.result, b.result), n);
|
||||
}
|
||||
public static ParseRes<IfStatement> parse(Filename filename, List<Token> tokens, int i) {
|
||||
var loc = Parsing.getLoc(filename, tokens, i);
|
||||
int n = 0;
|
||||
|
||||
if (!Parsing.isIdentifier(tokens, i + n++, "if")) return ParseRes.failed();
|
||||
if (!Parsing.isOperator(tokens, i + n++, Operator.PAREN_OPEN)) return ParseRes.error(loc, "Expected a open paren after 'if'.");
|
||||
|
||||
var condRes = Parsing.parseValue(filename, tokens, i + n, 0);
|
||||
if (!condRes.isSuccess()) return ParseRes.error(loc, "Expected an if condition.", condRes);
|
||||
n += condRes.n;
|
||||
|
||||
if (!Parsing.isOperator(tokens, i + n++, Operator.PAREN_CLOSE)) return ParseRes.error(loc, "Expected a closing paren after if condition.");
|
||||
|
||||
var res = Parsing.parseStatement(filename, tokens, i + n);
|
||||
if (!res.isSuccess()) return ParseRes.error(loc, "Expected an if body.", res);
|
||||
n += res.n;
|
||||
|
||||
if (!Parsing.isIdentifier(tokens, i + n, "else")) return ParseRes.res(new IfStatement(loc, condRes.result, res.result, null), n);
|
||||
n++;
|
||||
|
||||
var elseRes = Parsing.parseStatement(filename, tokens, i + n);
|
||||
if (!elseRes.isSuccess()) return ParseRes.error(loc, "Expected an else body.", elseRes);
|
||||
n += elseRes.n;
|
||||
|
||||
return ParseRes.res(new IfStatement(loc, condRes.result, res.result, elseRes.result), n);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,9 +1,16 @@
|
||||
package me.topchetoeu.jscript.compilation.control;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import me.topchetoeu.jscript.common.Filename;
|
||||
import me.topchetoeu.jscript.common.Instruction;
|
||||
import me.topchetoeu.jscript.common.Location;
|
||||
import me.topchetoeu.jscript.common.ParseRes;
|
||||
import me.topchetoeu.jscript.compilation.CompileResult;
|
||||
import me.topchetoeu.jscript.compilation.Statement;
|
||||
import me.topchetoeu.jscript.compilation.parsing.Operator;
|
||||
import me.topchetoeu.jscript.compilation.parsing.Parsing;
|
||||
import me.topchetoeu.jscript.compilation.parsing.Token;
|
||||
|
||||
public class ReturnStatement extends Statement {
|
||||
public final Statement value;
|
||||
@ -19,4 +26,27 @@ public class ReturnStatement extends Statement {
|
||||
super(loc);
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public static ParseRes<ReturnStatement> parseReturn(Filename filename, List<Token> tokens, int i) {
|
||||
var loc = Parsing.getLoc(filename, tokens, i);
|
||||
int n = 0;
|
||||
if (!Parsing.isIdentifier(tokens, i + n++, "return")) return ParseRes.failed();
|
||||
|
||||
if (Parsing.isStatementEnd(tokens, i + n)) {
|
||||
if (Parsing.isOperator(tokens, i + n, Operator.SEMICOLON)) return ParseRes.res(new ReturnStatement(loc, null), 2);
|
||||
else return ParseRes.res(new ReturnStatement(loc, null), 1);
|
||||
}
|
||||
|
||||
var valRes = Parsing.parseValue(filename, tokens, i + n, 0);
|
||||
n += valRes.n;
|
||||
if (valRes.isError()) return ParseRes.error(loc, "Expected a return value.", valRes);
|
||||
|
||||
var res = ParseRes.res(new ReturnStatement(loc, valRes.result), n);
|
||||
|
||||
if (Parsing.isStatementEnd(tokens, i + n)) {
|
||||
if (Parsing.isOperator(tokens, i + n, Operator.SEMICOLON)) return res.addN(1);
|
||||
else return res;
|
||||
}
|
||||
else return ParseRes.error(Parsing.getLoc(filename, tokens, i), "Expected an end of statement.", valRes);
|
||||
}
|
||||
}
|
||||
|
@ -1,14 +1,22 @@
|
||||
package me.topchetoeu.jscript.compilation.control;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
import me.topchetoeu.jscript.common.Filename;
|
||||
import me.topchetoeu.jscript.common.Instruction;
|
||||
import me.topchetoeu.jscript.common.Location;
|
||||
import me.topchetoeu.jscript.common.Operation;
|
||||
import me.topchetoeu.jscript.common.ParseRes;
|
||||
import me.topchetoeu.jscript.common.Instruction.BreakpointType;
|
||||
import me.topchetoeu.jscript.common.Instruction.Type;
|
||||
import me.topchetoeu.jscript.compilation.CompileResult;
|
||||
import me.topchetoeu.jscript.compilation.CompoundStatement;
|
||||
import me.topchetoeu.jscript.compilation.Statement;
|
||||
import me.topchetoeu.jscript.compilation.parsing.Operator;
|
||||
import me.topchetoeu.jscript.compilation.parsing.Parsing;
|
||||
import me.topchetoeu.jscript.compilation.parsing.Token;
|
||||
|
||||
public class SwitchStatement extends Statement {
|
||||
public static class SwitchCase {
|
||||
@ -26,13 +34,11 @@ public class SwitchStatement extends Statement {
|
||||
public final Statement[] body;
|
||||
public final int defaultI;
|
||||
|
||||
@Override
|
||||
public void declare(CompileResult target) {
|
||||
@Override public void declare(CompileResult target) {
|
||||
for (var stm : body) stm.declare(target);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void compile(CompileResult target, boolean pollute) {
|
||||
@Override public void compile(CompileResult target, boolean pollute) {
|
||||
var caseToStatement = new HashMap<Integer, Integer>();
|
||||
var statementToIndex = new HashMap<Integer, Integer>();
|
||||
|
||||
@ -80,4 +86,85 @@ public class SwitchStatement extends Statement {
|
||||
this.cases = cases;
|
||||
this.body = body;
|
||||
}
|
||||
|
||||
private static ParseRes<Statement> parseSwitchCase(Filename filename, List<Token> tokens, int i) {
|
||||
var loc = Parsing.getLoc(filename, tokens, i);
|
||||
int n = 0;
|
||||
|
||||
if (!Parsing.isIdentifier(tokens, i + n++, "case")) return ParseRes.failed();
|
||||
|
||||
var valRes = Parsing.parseValue(filename, tokens, i + n, 0);
|
||||
if (!valRes.isSuccess()) return ParseRes.error(loc, "Expected a value after 'case'.", valRes);
|
||||
n += valRes.n;
|
||||
|
||||
if (!Parsing.isOperator(tokens, i + n++, Operator.COLON)) return ParseRes.error(loc, "Expected colons after 'case' value.");
|
||||
|
||||
return ParseRes.res(valRes.result, n);
|
||||
}
|
||||
private static ParseRes<Statement> parseDefaultCase(List<Token> tokens, int i) {
|
||||
if (!Parsing.isIdentifier(tokens, i, "default")) return ParseRes.failed();
|
||||
if (!Parsing.isOperator(tokens, i + 1, Operator.COLON)) return ParseRes.error(Parsing.getLoc(null, tokens, i), "Expected colons after 'default'.");
|
||||
|
||||
return ParseRes.res(null, 2);
|
||||
}
|
||||
public static ParseRes<SwitchStatement> parse(Filename filename, List<Token> tokens, int i) {
|
||||
var loc = Parsing.getLoc(filename, tokens, i);
|
||||
int n = 0;
|
||||
|
||||
if (!Parsing.isIdentifier(tokens, i + n++, "switch")) return ParseRes.failed();
|
||||
if (!Parsing.isOperator(tokens, i + n++, Operator.PAREN_OPEN)) return ParseRes.error(loc, "Expected a open paren after 'switch'.");
|
||||
|
||||
var valRes = Parsing.parseValue(filename, tokens, i + n, 0);
|
||||
if (!valRes.isSuccess()) return ParseRes.error(loc, "Expected a switch value.", valRes);
|
||||
n += valRes.n;
|
||||
|
||||
if (!Parsing.isOperator(tokens, i + n++, Operator.PAREN_CLOSE)) return ParseRes.error(loc, "Expected a closing paren after switch value.");
|
||||
if (!Parsing.isOperator(tokens, i + n++, Operator.BRACE_OPEN)) return ParseRes.error(loc, "Expected an opening brace after switch value.");
|
||||
|
||||
var statements = new ArrayList<Statement>();
|
||||
var cases = new ArrayList<SwitchCase>();
|
||||
var defaultI = -1;
|
||||
|
||||
while (true) {
|
||||
if (Parsing.isOperator(tokens, i + n, Operator.BRACE_CLOSE)) {
|
||||
n++;
|
||||
break;
|
||||
}
|
||||
if (Parsing.isOperator(tokens, i + n, Operator.SEMICOLON)) {
|
||||
n++;
|
||||
continue;
|
||||
}
|
||||
|
||||
var defaultRes = SwitchStatement.parseDefaultCase(tokens, i + n);
|
||||
var caseRes = SwitchStatement.parseSwitchCase(filename, tokens, i + n);
|
||||
|
||||
if (defaultRes.isSuccess()) {
|
||||
defaultI = statements.size();
|
||||
n += defaultRes.n;
|
||||
}
|
||||
else if (caseRes.isSuccess()) {
|
||||
cases.add(new SwitchCase(caseRes.result, statements.size()));
|
||||
n += caseRes.n;
|
||||
}
|
||||
else if (defaultRes.isError()) return defaultRes.transform();
|
||||
else if (caseRes.isError()) return defaultRes.transform();
|
||||
else {
|
||||
var res = ParseRes.any(
|
||||
Parsing.parseStatement(filename, tokens, i + n),
|
||||
CompoundStatement.parse(filename, tokens, i + n)
|
||||
);
|
||||
if (!res.isSuccess()) {
|
||||
return ParseRes.error(Parsing.getLoc(filename, tokens, i), "Expected a statement.", res);
|
||||
}
|
||||
n += res.n;
|
||||
statements.add(res.result);
|
||||
}
|
||||
}
|
||||
|
||||
return ParseRes.res(new SwitchStatement(
|
||||
loc, valRes.result, defaultI,
|
||||
cases.toArray(SwitchCase[]::new),
|
||||
statements.toArray(Statement[]::new)
|
||||
), n);
|
||||
}
|
||||
}
|
||||
|
@ -1,9 +1,16 @@
|
||||
package me.topchetoeu.jscript.compilation.control;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import me.topchetoeu.jscript.common.Filename;
|
||||
import me.topchetoeu.jscript.common.Instruction;
|
||||
import me.topchetoeu.jscript.common.Location;
|
||||
import me.topchetoeu.jscript.common.ParseRes;
|
||||
import me.topchetoeu.jscript.compilation.CompileResult;
|
||||
import me.topchetoeu.jscript.compilation.Statement;
|
||||
import me.topchetoeu.jscript.compilation.parsing.Operator;
|
||||
import me.topchetoeu.jscript.compilation.parsing.Parsing;
|
||||
import me.topchetoeu.jscript.compilation.parsing.Token;
|
||||
|
||||
public class ThrowStatement extends Statement {
|
||||
public final Statement value;
|
||||
@ -18,4 +25,22 @@ public class ThrowStatement extends Statement {
|
||||
super(loc);
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public static ParseRes<ThrowStatement> parseThrow(Filename filename, List<Token> tokens, int i) {
|
||||
var loc = Parsing.getLoc(filename, tokens, i);
|
||||
int n = 0;
|
||||
if (!Parsing.isIdentifier(tokens, i + n++, "throw")) return ParseRes.failed();
|
||||
|
||||
var valRes = Parsing.parseValue(filename, tokens, i + n, 0);
|
||||
n += valRes.n;
|
||||
if (valRes.isError()) return ParseRes.error(loc, "Expected a throw value.", valRes);
|
||||
|
||||
var res = ParseRes.res(new ThrowStatement(loc, valRes.result), n);
|
||||
|
||||
if (Parsing.isStatementEnd(tokens, i + n)) {
|
||||
if (Parsing.isOperator(tokens, i + n, Operator.SEMICOLON)) return res.addN(1);
|
||||
else return res;
|
||||
}
|
||||
else return ParseRes.error(Parsing.getLoc(filename, tokens, i), "Expected an end of statement.", valRes);
|
||||
}
|
||||
}
|
||||
|
@ -1,10 +1,17 @@
|
||||
package me.topchetoeu.jscript.compilation.control;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import me.topchetoeu.jscript.common.Filename;
|
||||
import me.topchetoeu.jscript.common.Instruction;
|
||||
import me.topchetoeu.jscript.common.Location;
|
||||
import me.topchetoeu.jscript.common.ParseRes;
|
||||
import me.topchetoeu.jscript.common.Instruction.BreakpointType;
|
||||
import me.topchetoeu.jscript.compilation.CompileResult;
|
||||
import me.topchetoeu.jscript.compilation.Statement;
|
||||
import me.topchetoeu.jscript.compilation.parsing.Operator;
|
||||
import me.topchetoeu.jscript.compilation.parsing.Parsing;
|
||||
import me.topchetoeu.jscript.compilation.parsing.Token;
|
||||
|
||||
public class TryStatement extends Statement {
|
||||
public final Statement tryBody;
|
||||
@ -12,15 +19,13 @@ public class TryStatement extends Statement {
|
||||
public final Statement finallyBody;
|
||||
public final String name;
|
||||
|
||||
@Override
|
||||
public void declare(CompileResult target) {
|
||||
@Override public void declare(CompileResult target) {
|
||||
tryBody.declare(target);
|
||||
if (catchBody != null) catchBody.declare(target);
|
||||
if (finallyBody != null) finallyBody.declare(target);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void compile(CompileResult target, boolean pollute, BreakpointType bpt) {
|
||||
@Override public void compile(CompileResult target, boolean pollute, BreakpointType bpt) {
|
||||
int replace = target.temp();
|
||||
|
||||
int start = replace + 1, catchStart = -1, finallyStart = -1;
|
||||
@ -55,4 +60,45 @@ public class TryStatement extends Statement {
|
||||
this.finallyBody = finallyBody;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public static ParseRes<TryStatement> parse(Filename filename, List<Token> tokens, int i) {
|
||||
var loc = Parsing.getLoc(filename, tokens, i);
|
||||
int n = 0;
|
||||
|
||||
if (!Parsing.isIdentifier(tokens, i + n++, "try")) return ParseRes.failed();
|
||||
|
||||
var res = Parsing.parseStatement(filename, tokens, i + n);
|
||||
if (!res.isSuccess()) return ParseRes.error(loc, "Expected an if body.", res);
|
||||
n += res.n;
|
||||
|
||||
String name = null;
|
||||
Statement catchBody = null, finallyBody = null;
|
||||
|
||||
|
||||
if (Parsing.isIdentifier(tokens, i + n, "catch")) {
|
||||
n++;
|
||||
if (Parsing.isOperator(tokens, i + n, Operator.PAREN_OPEN)) {
|
||||
n++;
|
||||
var nameRes = Parsing.parseIdentifier(tokens, i + n++);
|
||||
if (!nameRes.isSuccess()) return ParseRes.error(loc, "Expected a catch variable name.");
|
||||
name = nameRes.result;
|
||||
if (!Parsing.isOperator(tokens, i + n++, Operator.PAREN_CLOSE)) return ParseRes.error(loc, "Expected a closing paren after catch variable name.");
|
||||
}
|
||||
|
||||
var catchRes = Parsing.parseStatement(filename, tokens, i + n);
|
||||
if (!catchRes.isSuccess()) return ParseRes.error(loc, "Expected a catch body.", catchRes);
|
||||
n += catchRes.n;
|
||||
catchBody = catchRes.result;
|
||||
}
|
||||
|
||||
if (Parsing.isIdentifier(tokens, i + n, "finally")) {
|
||||
n++;
|
||||
var finallyRes = Parsing.parseStatement(filename, tokens, i + n);
|
||||
if (!finallyRes.isSuccess()) return ParseRes.error(loc, "Expected a finally body.", finallyRes);
|
||||
n += finallyRes.n;
|
||||
finallyBody = finallyRes.result;
|
||||
}
|
||||
|
||||
return ParseRes.res(new TryStatement(loc, res.result, catchBody, finallyBody, name), n);
|
||||
}
|
||||
}
|
||||
|
@ -1,11 +1,18 @@
|
||||
package me.topchetoeu.jscript.compilation.control;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import me.topchetoeu.jscript.common.Filename;
|
||||
import me.topchetoeu.jscript.common.Instruction;
|
||||
import me.topchetoeu.jscript.common.Location;
|
||||
import me.topchetoeu.jscript.common.ParseRes;
|
||||
import me.topchetoeu.jscript.common.Instruction.BreakpointType;
|
||||
import me.topchetoeu.jscript.common.Instruction.Type;
|
||||
import me.topchetoeu.jscript.compilation.CompileResult;
|
||||
import me.topchetoeu.jscript.compilation.Statement;
|
||||
import me.topchetoeu.jscript.compilation.parsing.Operator;
|
||||
import me.topchetoeu.jscript.compilation.parsing.Parsing;
|
||||
import me.topchetoeu.jscript.compilation.parsing.Token;
|
||||
|
||||
public class WhileStatement extends Statement {
|
||||
public final Statement condition, body;
|
||||
@ -31,6 +38,14 @@ public class WhileStatement extends Statement {
|
||||
if (pollute) target.add(Instruction.pushUndefined());
|
||||
}
|
||||
|
||||
public static ParseRes<String> parseLabel(List<Token> tokens, int i) {
|
||||
int n = 0;
|
||||
|
||||
var nameRes = Parsing.parseIdentifier(tokens, i + n++);
|
||||
if (!Parsing.isOperator(tokens, i + n++, Operator.COLON)) return ParseRes.failed();
|
||||
|
||||
return ParseRes.res(nameRes.result, n);
|
||||
}
|
||||
public WhileStatement(Location loc, String label, Statement condition, Statement body) {
|
||||
super(loc);
|
||||
this.label = label;
|
||||
@ -49,4 +64,27 @@ public class WhileStatement extends Statement {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static ParseRes<WhileStatement> parseWhile(Filename filename, List<Token> tokens, int i) {
|
||||
var loc = Parsing.getLoc(filename, tokens, i);
|
||||
int n = 0;
|
||||
|
||||
var labelRes = WhileStatement.parseLabel(tokens, i + n);
|
||||
n += labelRes.n;
|
||||
|
||||
if (!Parsing.isIdentifier(tokens, i + n++, "while")) return ParseRes.failed();
|
||||
if (!Parsing.isOperator(tokens, i + n++, Operator.PAREN_OPEN)) return ParseRes.error(loc, "Expected a open paren after 'while'.");
|
||||
|
||||
var condRes = Parsing.parseValue(filename, tokens, i + n, 0);
|
||||
if (!condRes.isSuccess()) return ParseRes.error(loc, "Expected a while condition.", condRes);
|
||||
n += condRes.n;
|
||||
|
||||
if (!Parsing.isOperator(tokens, i + n++, Operator.PAREN_CLOSE)) return ParseRes.error(loc, "Expected a closing paren after while condition.");
|
||||
|
||||
var res = Parsing.parseStatement(filename, tokens, i + n);
|
||||
if (!res.isSuccess()) return ParseRes.error(loc, "Expected a while body.", res);
|
||||
n += res.n;
|
||||
|
||||
return ParseRes.res(new WhileStatement(loc, labelRes.result, condRes.result, res.result), n);
|
||||
}
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,9 +1,17 @@
|
||||
package me.topchetoeu.jscript.compilation.values;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import me.topchetoeu.jscript.common.Filename;
|
||||
import me.topchetoeu.jscript.common.Instruction;
|
||||
import me.topchetoeu.jscript.common.Location;
|
||||
import me.topchetoeu.jscript.common.ParseRes;
|
||||
import me.topchetoeu.jscript.compilation.CompileResult;
|
||||
import me.topchetoeu.jscript.compilation.Statement;
|
||||
import me.topchetoeu.jscript.compilation.parsing.Operator;
|
||||
import me.topchetoeu.jscript.compilation.parsing.Parsing;
|
||||
import me.topchetoeu.jscript.compilation.parsing.Token;
|
||||
|
||||
public class ArrayStatement extends Statement {
|
||||
public final Statement[] statements;
|
||||
@ -37,4 +45,42 @@ public class ArrayStatement extends Statement {
|
||||
super(loc);
|
||||
this.statements = statements;
|
||||
}
|
||||
|
||||
public static ParseRes<ArrayStatement> parse(Filename filename, List<Token> tokens, int i) {
|
||||
var loc = Parsing.getLoc(filename, tokens, i);
|
||||
int n = 0;
|
||||
if (!Parsing.isOperator(tokens, i + n++, Operator.BRACKET_OPEN)) return ParseRes.failed();
|
||||
|
||||
var values = new ArrayList<Statement>();
|
||||
|
||||
loop: while (true) {
|
||||
if (Parsing.isOperator(tokens, i + n, Operator.BRACKET_CLOSE)) {
|
||||
n++;
|
||||
break;
|
||||
}
|
||||
|
||||
while (Parsing.isOperator(tokens, i + n, Operator.COMMA)) {
|
||||
n++;
|
||||
values.add(null);
|
||||
if (Parsing.isOperator(tokens, i + n, Operator.BRACKET_CLOSE)) {
|
||||
n++;
|
||||
break loop;
|
||||
}
|
||||
}
|
||||
|
||||
var res = Parsing.parseValue(filename, tokens, i + n, 2);
|
||||
if (!res.isSuccess()) return ParseRes.error(loc, "Expected an array element.", res);
|
||||
else n += res.n;
|
||||
|
||||
values.add(res.result);
|
||||
|
||||
if (Parsing.isOperator(tokens, i + n, Operator.COMMA)) n++;
|
||||
else if (Parsing.isOperator(tokens, i + n, Operator.BRACKET_CLOSE)) {
|
||||
n++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return ParseRes.res(new ArrayStatement(loc, values.toArray(Statement[]::new)), n);
|
||||
}
|
||||
}
|
||||
|
@ -1,18 +1,25 @@
|
||||
package me.topchetoeu.jscript.compilation.values;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import me.topchetoeu.jscript.common.Filename;
|
||||
import me.topchetoeu.jscript.common.Instruction;
|
||||
import me.topchetoeu.jscript.common.Location;
|
||||
import me.topchetoeu.jscript.common.ParseRes;
|
||||
import me.topchetoeu.jscript.common.Instruction.BreakpointType;
|
||||
import me.topchetoeu.jscript.compilation.CompileResult;
|
||||
import me.topchetoeu.jscript.compilation.Statement;
|
||||
import me.topchetoeu.jscript.compilation.parsing.Operator;
|
||||
import me.topchetoeu.jscript.compilation.parsing.Parsing;
|
||||
import me.topchetoeu.jscript.compilation.parsing.Token;
|
||||
|
||||
public class CallStatement extends Statement {
|
||||
public final Statement func;
|
||||
public final Statement[] args;
|
||||
public final boolean isNew;
|
||||
|
||||
@Override
|
||||
public void compile(CompileResult target, boolean pollute, BreakpointType type) {
|
||||
@Override public void compile(CompileResult target, boolean pollute, BreakpointType type) {
|
||||
if (isNew) func.compile(target, true);
|
||||
else if (func instanceof IndexStatement) {
|
||||
((IndexStatement)func).compile(target, true, true);
|
||||
@ -29,8 +36,7 @@ public class CallStatement extends Statement {
|
||||
|
||||
if (!pollute) target.add(Instruction.discard());
|
||||
}
|
||||
@Override
|
||||
public void compile(CompileResult target, boolean pollute) {
|
||||
@Override public void compile(CompileResult target, boolean pollute) {
|
||||
compile(target, pollute, BreakpointType.STEP_IN);
|
||||
}
|
||||
|
||||
@ -40,4 +46,52 @@ public class CallStatement extends Statement {
|
||||
this.func = func;
|
||||
this.args = args;
|
||||
}
|
||||
|
||||
public static ParseRes<CallStatement> parseCall(Filename filename, List<Token> tokens, int i, Statement prev, int precedence) {
|
||||
var loc = Parsing.getLoc(filename, tokens, i);
|
||||
var n = 0;
|
||||
|
||||
if (precedence > 17) return ParseRes.failed();
|
||||
if (!Parsing.isOperator(tokens, i + n++, Operator.PAREN_OPEN)) return ParseRes.failed();
|
||||
|
||||
var args = new ArrayList<Statement>();
|
||||
boolean prevArg = false;
|
||||
|
||||
while (true) {
|
||||
var argRes = Parsing.parseValue(filename, tokens, i + n, 2);
|
||||
if (argRes.isSuccess()) {
|
||||
args.add(argRes.result);
|
||||
n += argRes.n;
|
||||
prevArg = true;
|
||||
}
|
||||
else if (argRes.isError()) return argRes.transform();
|
||||
else if (prevArg && Parsing.isOperator(tokens, i + n, Operator.COMMA)) {
|
||||
prevArg = false;
|
||||
n++;
|
||||
}
|
||||
else if (Parsing.isOperator(tokens, i + n, Operator.PAREN_CLOSE)) {
|
||||
n++;
|
||||
break;
|
||||
}
|
||||
else return ParseRes.error(Parsing.getLoc(filename, tokens, i + n), prevArg ? "Expected a comma or a closing paren." : "Expected an expression or a closing paren.");
|
||||
}
|
||||
|
||||
return ParseRes.res(new CallStatement(loc, false, prev, args.toArray(Statement[]::new)), n);
|
||||
}
|
||||
public static ParseRes<CallStatement> parseNew(Filename filename, List<Token> tokens, int i) {
|
||||
var loc = Parsing.getLoc(filename, tokens, i);
|
||||
var n = 0;
|
||||
if (!Parsing.isIdentifier(tokens, i + n++, "new")) return ParseRes.failed();
|
||||
|
||||
var valRes = Parsing.parseValue(filename, tokens, i + n, 18);
|
||||
n += valRes.n;
|
||||
if (!valRes.isSuccess()) return ParseRes.error(loc, "Expected a value after 'new' keyword.", valRes);
|
||||
var callRes = CallStatement.parseCall(filename, tokens, i + n, valRes.result, 0);
|
||||
n += callRes.n;
|
||||
if (callRes.isError()) return callRes.transform();
|
||||
else if (callRes.isFailed()) return ParseRes.res(new CallStatement(loc, true, valRes.result), n);
|
||||
var call = (CallStatement)callRes.result;
|
||||
|
||||
return ParseRes.res(new CallStatement(loc, true, call.func, call.args), n);
|
||||
}
|
||||
}
|
||||
|
@ -1,19 +1,25 @@
|
||||
package me.topchetoeu.jscript.compilation.values;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import me.topchetoeu.jscript.common.Filename;
|
||||
import me.topchetoeu.jscript.common.Instruction;
|
||||
import me.topchetoeu.jscript.common.Location;
|
||||
import me.topchetoeu.jscript.common.Operation;
|
||||
import me.topchetoeu.jscript.common.ParseRes;
|
||||
import me.topchetoeu.jscript.compilation.AssignableStatement;
|
||||
import me.topchetoeu.jscript.compilation.CompileResult;
|
||||
import me.topchetoeu.jscript.compilation.Statement;
|
||||
import me.topchetoeu.jscript.compilation.parsing.Operator;
|
||||
import me.topchetoeu.jscript.compilation.parsing.Parsing;
|
||||
import me.topchetoeu.jscript.compilation.parsing.Token;
|
||||
|
||||
public class ChangeStatement extends Statement {
|
||||
public final AssignableStatement value;
|
||||
public final double addAmount;
|
||||
public final boolean postfix;
|
||||
|
||||
@Override
|
||||
public void compile(CompileResult target, boolean pollute) {
|
||||
@Override public void compile(CompileResult target, boolean pollute) {
|
||||
value.toAssign(new ConstantStatement(loc(), -addAmount), Operation.SUBTRACT).compile(target, true);
|
||||
if (!pollute) target.add(Instruction.discard());
|
||||
else if (postfix) {
|
||||
@ -28,4 +34,40 @@ public class ChangeStatement extends Statement {
|
||||
this.addAmount = addAmount;
|
||||
this.postfix = postfix;
|
||||
}
|
||||
|
||||
public static ParseRes<ChangeStatement> parsePrefix(Filename filename, List<Token> tokens, int i) {
|
||||
var loc = Parsing.getLoc(filename, tokens, i);
|
||||
int n = 0;
|
||||
|
||||
var opState = Parsing.parseOperator(tokens, i + n++);
|
||||
if (!opState.isSuccess()) return ParseRes.failed();
|
||||
|
||||
int change = 0;
|
||||
|
||||
if (opState.result == Operator.INCREASE) change = 1;
|
||||
else if (opState.result == Operator.DECREASE) change = -1;
|
||||
else return ParseRes.failed();
|
||||
|
||||
var res = Parsing.parseValue(filename, tokens, i + n, 15);
|
||||
if (!(res.result instanceof AssignableStatement)) return ParseRes.error(loc, "Expected assignable value after prefix operator.");
|
||||
return ParseRes.res(new ChangeStatement(loc, (AssignableStatement)res.result, change, false), n + res.n);
|
||||
}
|
||||
public static ParseRes<ChangeStatement> parsePostfix(Filename filename, List<Token> tokens, int i, Statement prev, int precedence) {
|
||||
var loc = Parsing.getLoc(filename, tokens, i);
|
||||
int n = 0;
|
||||
|
||||
if (precedence > 15) return ParseRes.failed();
|
||||
|
||||
var opState = Parsing.parseOperator(tokens, i + n++);
|
||||
if (!opState.isSuccess()) return ParseRes.failed();
|
||||
|
||||
int change = 0;
|
||||
|
||||
if (opState.result == Operator.INCREASE) change = 1;
|
||||
else if (opState.result == Operator.DECREASE) change = -1;
|
||||
else return ParseRes.failed();
|
||||
|
||||
if (!(prev instanceof AssignableStatement)) return ParseRes.error(loc, "Expected assignable value before suffix operator.");
|
||||
return ParseRes.res(new ChangeStatement(loc, (AssignableStatement)prev, change, true), n);
|
||||
}
|
||||
}
|
||||
|
@ -1,9 +1,15 @@
|
||||
package me.topchetoeu.jscript.compilation.values;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import me.topchetoeu.jscript.common.Filename;
|
||||
import me.topchetoeu.jscript.common.Instruction;
|
||||
import me.topchetoeu.jscript.common.Location;
|
||||
import me.topchetoeu.jscript.common.ParseRes;
|
||||
import me.topchetoeu.jscript.compilation.CompileResult;
|
||||
import me.topchetoeu.jscript.compilation.Statement;
|
||||
import me.topchetoeu.jscript.compilation.parsing.Parsing;
|
||||
import me.topchetoeu.jscript.compilation.parsing.Token;
|
||||
|
||||
public class ConstantStatement extends Statement {
|
||||
public final Object value;
|
||||
@ -44,4 +50,25 @@ public class ConstantStatement extends Statement {
|
||||
public static ConstantStatement ofNull(Location loc) {
|
||||
return new ConstantStatement(loc, null, true);
|
||||
}
|
||||
|
||||
public static ParseRes<ConstantStatement> parseNumber(Filename filename, List<Token> tokens, int i) {
|
||||
var loc = Parsing.getLoc(filename, tokens, i);
|
||||
if (Parsing.inBounds(tokens, i)) {
|
||||
if (tokens.get(i).isNumber()) {
|
||||
return ParseRes.res(new ConstantStatement(loc, tokens.get(i).number()), 1);
|
||||
}
|
||||
else return ParseRes.failed();
|
||||
}
|
||||
else return ParseRes.failed();
|
||||
}
|
||||
public static ParseRes<ConstantStatement> parseString(Filename filename, List<Token> tokens, int i) {
|
||||
var loc = Parsing.getLoc(filename, tokens, i);
|
||||
if (Parsing.inBounds(tokens, i)) {
|
||||
if (tokens.get(i).isString()) {
|
||||
return ParseRes.res(new ConstantStatement(loc, tokens.get(i).string()), 1);
|
||||
}
|
||||
else return ParseRes.failed();
|
||||
}
|
||||
else return ParseRes.failed();
|
||||
}
|
||||
}
|
||||
|
@ -1,9 +1,15 @@
|
||||
package me.topchetoeu.jscript.compilation.values;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import me.topchetoeu.jscript.common.Filename;
|
||||
import me.topchetoeu.jscript.common.Instruction;
|
||||
import me.topchetoeu.jscript.common.Location;
|
||||
import me.topchetoeu.jscript.common.ParseRes;
|
||||
import me.topchetoeu.jscript.compilation.CompileResult;
|
||||
import me.topchetoeu.jscript.compilation.Statement;
|
||||
import me.topchetoeu.jscript.compilation.parsing.Parsing;
|
||||
import me.topchetoeu.jscript.compilation.parsing.Token;
|
||||
|
||||
public class DiscardStatement extends Statement {
|
||||
public final Statement value;
|
||||
@ -20,4 +26,16 @@ public class DiscardStatement extends Statement {
|
||||
super(loc);
|
||||
this.value = val;
|
||||
}
|
||||
|
||||
public static ParseRes<DiscardStatement> parse(Filename filename, List<Token> tokens, int i) {
|
||||
var loc = Parsing.getLoc(filename, tokens, i);
|
||||
var n = 0;
|
||||
if (!Parsing.isIdentifier(tokens, i + n++, "void")) return ParseRes.failed();
|
||||
|
||||
var valRes = Parsing.parseValue(filename, tokens, i + n, 14);
|
||||
if (!valRes.isSuccess()) return ParseRes.error(loc, "Expected a value after 'void' keyword.", valRes);
|
||||
n += valRes.n;
|
||||
|
||||
return ParseRes.res(new DiscardStatement(loc, valRes.result), n);
|
||||
}
|
||||
}
|
||||
|
@ -1,12 +1,20 @@
|
||||
package me.topchetoeu.jscript.compilation.values;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import me.topchetoeu.jscript.common.Filename;
|
||||
import me.topchetoeu.jscript.common.Instruction;
|
||||
import me.topchetoeu.jscript.common.Location;
|
||||
import me.topchetoeu.jscript.common.ParseRes;
|
||||
import me.topchetoeu.jscript.common.Instruction.BreakpointType;
|
||||
import me.topchetoeu.jscript.common.Instruction.Type;
|
||||
import me.topchetoeu.jscript.compilation.CompileResult;
|
||||
import me.topchetoeu.jscript.compilation.CompoundStatement;
|
||||
import me.topchetoeu.jscript.compilation.Statement;
|
||||
import me.topchetoeu.jscript.compilation.parsing.Operator;
|
||||
import me.topchetoeu.jscript.compilation.parsing.Parsing;
|
||||
import me.topchetoeu.jscript.compilation.parsing.Token;
|
||||
import me.topchetoeu.jscript.runtime.exceptions.SyntaxException;
|
||||
|
||||
public class FunctionStatement extends Statement {
|
||||
@ -124,4 +132,48 @@ public class FunctionStatement extends Statement {
|
||||
if (stm instanceof FunctionStatement) ((FunctionStatement)stm).compile(target, pollute, name, bp);
|
||||
else stm.compile(target, pollute, bp);
|
||||
}
|
||||
|
||||
public static ParseRes<FunctionStatement> parseFunction(Filename filename, List<Token> tokens, int i, boolean statement) {
|
||||
var loc = Parsing.getLoc(filename, tokens, i);
|
||||
int n = 0;
|
||||
|
||||
if (!Parsing.isIdentifier(tokens, i + n++, "function")) return ParseRes.failed();
|
||||
|
||||
var nameRes = Parsing.parseIdentifier(tokens, i + n);
|
||||
if (!nameRes.isSuccess() && statement) return ParseRes.error(loc, "A statement function requires a name, one is not present.");
|
||||
var name = nameRes.result;
|
||||
n += nameRes.n;
|
||||
|
||||
if (!Parsing.isOperator(tokens, i + n++, Operator.PAREN_OPEN)) return ParseRes.error(loc, "Expected a parameter list.");
|
||||
|
||||
var args = new ArrayList<String>();
|
||||
|
||||
if (Parsing.isOperator(tokens, i + n, Operator.PAREN_CLOSE)) {
|
||||
n++;
|
||||
}
|
||||
else {
|
||||
while (true) {
|
||||
var argRes = Parsing.parseIdentifier(tokens, i + n);
|
||||
if (argRes.isSuccess()) {
|
||||
args.add(argRes.result);
|
||||
n++;
|
||||
if (Parsing.isOperator(tokens, i + n, Operator.COMMA)) {
|
||||
n++;
|
||||
}
|
||||
if (Parsing.isOperator(tokens, i + n, Operator.PAREN_CLOSE)) {
|
||||
n++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else return ParseRes.error(loc, "Expected an argument, comma or a closing brace.");
|
||||
}
|
||||
}
|
||||
|
||||
var res = CompoundStatement.parse(filename, tokens, i + n);
|
||||
n += res.n;
|
||||
var end = Parsing.getLoc(filename, tokens, i + n - 1);
|
||||
|
||||
if (res.isSuccess()) return ParseRes.res(new FunctionStatement(loc, end, name, args.toArray(String[]::new), statement, res.result), n);
|
||||
else return ParseRes.error(loc, "Expected a compound statement for function.", res);
|
||||
}
|
||||
}
|
||||
|
@ -1,12 +1,19 @@
|
||||
package me.topchetoeu.jscript.compilation.values;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import me.topchetoeu.jscript.common.Filename;
|
||||
import me.topchetoeu.jscript.common.Instruction;
|
||||
import me.topchetoeu.jscript.common.Location;
|
||||
import me.topchetoeu.jscript.common.Operation;
|
||||
import me.topchetoeu.jscript.common.ParseRes;
|
||||
import me.topchetoeu.jscript.common.Instruction.BreakpointType;
|
||||
import me.topchetoeu.jscript.compilation.AssignableStatement;
|
||||
import me.topchetoeu.jscript.compilation.CompileResult;
|
||||
import me.topchetoeu.jscript.compilation.Statement;
|
||||
import me.topchetoeu.jscript.compilation.parsing.Operator;
|
||||
import me.topchetoeu.jscript.compilation.parsing.Parsing;
|
||||
import me.topchetoeu.jscript.compilation.parsing.Token;
|
||||
|
||||
public class IndexStatement extends AssignableStatement {
|
||||
public final Statement object;
|
||||
@ -34,4 +41,34 @@ public class IndexStatement extends AssignableStatement {
|
||||
this.object = object;
|
||||
this.index = index;
|
||||
}
|
||||
|
||||
public static ParseRes<IndexStatement> parseIndex(Filename filename, List<Token> tokens, int i, Statement prev, int precedence) {
|
||||
var loc = Parsing.getLoc(filename, tokens, i);
|
||||
var n = 0;
|
||||
|
||||
if (precedence > 18) return ParseRes.failed();
|
||||
|
||||
if (!Parsing.isOperator(tokens, i + n++, Operator.BRACKET_OPEN)) return ParseRes.failed();
|
||||
|
||||
var valRes = Parsing.parseValue(filename, tokens, i + n, 0);
|
||||
if (!valRes.isSuccess()) return ParseRes.error(loc, "Expected a value in index expression.", valRes);
|
||||
n += valRes.n;
|
||||
|
||||
if (!Parsing.isOperator(tokens, i + n++, Operator.BRACKET_CLOSE)) return ParseRes.error(loc, "Expected a closing bracket.");
|
||||
|
||||
return ParseRes.res(new IndexStatement(loc, prev, valRes.result), n);
|
||||
}
|
||||
public static ParseRes<IndexStatement> parseMember(Filename filename, List<Token> tokens, int i, Statement prev, int precedence) {
|
||||
var loc = Parsing.getLoc(filename, tokens, i);
|
||||
var n = 0;
|
||||
|
||||
if (precedence > 18) return ParseRes.failed();
|
||||
|
||||
if (!Parsing.isOperator(tokens, i + n++, Operator.DOT)) return ParseRes.failed();
|
||||
|
||||
var literal = Parsing.parseIdentifier(tokens, i + n++);
|
||||
if (!literal.isSuccess()) return ParseRes.error(loc, "Expected an identifier after member access.");
|
||||
|
||||
return ParseRes.res(new IndexStatement(loc, prev, new ConstantStatement(loc, literal.result)), n);
|
||||
}
|
||||
}
|
||||
|
@ -1,12 +1,21 @@
|
||||
package me.topchetoeu.jscript.compilation.values;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import me.topchetoeu.jscript.common.Filename;
|
||||
import me.topchetoeu.jscript.common.Instruction;
|
||||
import me.topchetoeu.jscript.common.Location;
|
||||
import me.topchetoeu.jscript.common.ParseRes;
|
||||
import me.topchetoeu.jscript.compilation.CompileResult;
|
||||
import me.topchetoeu.jscript.compilation.CompoundStatement;
|
||||
import me.topchetoeu.jscript.compilation.Statement;
|
||||
import me.topchetoeu.jscript.compilation.parsing.Operator;
|
||||
import me.topchetoeu.jscript.compilation.parsing.Parsing;
|
||||
import me.topchetoeu.jscript.compilation.parsing.Parsing.ObjProp;
|
||||
import me.topchetoeu.jscript.compilation.parsing.Token;
|
||||
|
||||
public class ObjectStatement extends Statement {
|
||||
public final Map<String, Statement> map;
|
||||
@ -58,4 +67,104 @@ public class ObjectStatement extends Statement {
|
||||
this.getters = getters;
|
||||
this.setters = setters;
|
||||
}
|
||||
|
||||
private static ParseRes<String> parsePropName(Filename filename, List<Token> tokens, int i) {
|
||||
var loc = Parsing.getLoc(filename, tokens, i);
|
||||
|
||||
if (Parsing.inBounds(tokens, i)) {
|
||||
var token = tokens.get(i);
|
||||
|
||||
if (token.isNumber() || token.isIdentifier() || token.isString()) return ParseRes.res(token.rawValue, 1);
|
||||
else return ParseRes.error(loc, "Expected identifier, string or number literal.");
|
||||
}
|
||||
else return ParseRes.failed();
|
||||
}
|
||||
private static ParseRes<ObjProp> parseObjectProp(Filename filename, List<Token> tokens, int i) {
|
||||
var loc =Parsing. getLoc(filename, tokens, i);
|
||||
int n = 0;
|
||||
|
||||
var accessRes = Parsing.parseIdentifier(tokens, i + n++);
|
||||
if (!accessRes.isSuccess()) return ParseRes.failed();
|
||||
var access = accessRes.result;
|
||||
if (!access.equals("get") && !access.equals("set")) return ParseRes.failed();
|
||||
|
||||
var nameRes = parsePropName(filename, tokens, i + n);
|
||||
if (!nameRes.isSuccess()) return ParseRes.error(loc, "Expected a property name after '" + access + "'.");
|
||||
var name = nameRes.result;
|
||||
n += nameRes.n;
|
||||
|
||||
var argsRes = Parsing.parseParamList(filename, tokens, i + n);
|
||||
if (!argsRes.isSuccess()) return ParseRes.error(loc, "Expected an argument list.", argsRes);
|
||||
n += argsRes.n;
|
||||
|
||||
var res = CompoundStatement.parse(filename, tokens, i + n);
|
||||
if (!res.isSuccess()) return ParseRes.error(loc, "Expected a compound statement for property accessor.", res);
|
||||
n += res.n;
|
||||
|
||||
var end = Parsing.getLoc(filename, tokens, i + n - 1);
|
||||
|
||||
return ParseRes.res(new ObjProp(
|
||||
name, access,
|
||||
new FunctionStatement(loc, end, access + " " + name.toString(), argsRes.result.toArray(String[]::new), false, res.result)
|
||||
), n);
|
||||
}
|
||||
|
||||
public static ParseRes<ObjectStatement> parse(Filename filename, List<Token> tokens, int i) {
|
||||
var loc = Parsing.getLoc(filename, tokens, i);
|
||||
int n = 0;
|
||||
if (!Parsing.isOperator(tokens, i + n++, Operator.BRACE_OPEN)) return ParseRes.failed();
|
||||
|
||||
var values = new LinkedHashMap<String, Statement>();
|
||||
var getters = new LinkedHashMap<String, FunctionStatement>();
|
||||
var setters = new LinkedHashMap<String, FunctionStatement>();
|
||||
|
||||
if (Parsing.isOperator(tokens, i + n, Operator.BRACE_CLOSE)) {
|
||||
n++;
|
||||
return ParseRes.res(new ObjectStatement(loc, values, getters, setters), n);
|
||||
}
|
||||
|
||||
while (true) {
|
||||
var propRes = parseObjectProp(filename, tokens, i + n);
|
||||
|
||||
if (propRes.isSuccess()) {
|
||||
n += propRes.n;
|
||||
if (propRes.result.access.equals("set")) {
|
||||
setters.put(propRes.result.name, propRes.result.func);
|
||||
}
|
||||
else {
|
||||
getters.put(propRes.result.name, propRes.result.func);
|
||||
}
|
||||
}
|
||||
else {
|
||||
var nameRes = parsePropName(filename, tokens, i + n);
|
||||
if (!nameRes.isSuccess()) return ParseRes.error(loc, "Expected a field name.", propRes);
|
||||
n += nameRes.n;
|
||||
|
||||
if (!Parsing.isOperator(tokens, i + n++, Operator.COLON)) return ParseRes.error(loc, "Expected a colon.");
|
||||
|
||||
var valRes = Parsing.parseValue(filename, tokens, i + n, 2);
|
||||
if (!valRes.isSuccess()) return ParseRes.error(loc, "Expected a value in array list.", valRes);
|
||||
n += valRes.n;
|
||||
|
||||
values.put(nameRes.result, valRes.result);
|
||||
}
|
||||
|
||||
if (Parsing.isOperator(tokens, i + n, Operator.COMMA)) {
|
||||
n++;
|
||||
if (Parsing.isOperator(tokens, i + n, Operator.BRACE_CLOSE)) {
|
||||
n++;
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
else if (Parsing.isOperator(tokens, i + n, Operator.BRACE_CLOSE)) {
|
||||
n++;
|
||||
break;
|
||||
}
|
||||
else ParseRes.error(loc, "Expected a comma or a closing brace.");
|
||||
}
|
||||
|
||||
return ParseRes.res(new ObjectStatement(loc, values, getters, setters), n);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,10 +1,18 @@
|
||||
package me.topchetoeu.jscript.compilation.values;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import me.topchetoeu.jscript.common.Filename;
|
||||
import me.topchetoeu.jscript.common.Instruction;
|
||||
import me.topchetoeu.jscript.common.Location;
|
||||
import me.topchetoeu.jscript.common.Operation;
|
||||
import me.topchetoeu.jscript.common.ParseRes;
|
||||
import me.topchetoeu.jscript.compilation.AssignableStatement;
|
||||
import me.topchetoeu.jscript.compilation.CompileResult;
|
||||
import me.topchetoeu.jscript.compilation.Statement;
|
||||
import me.topchetoeu.jscript.compilation.parsing.Operator;
|
||||
import me.topchetoeu.jscript.compilation.parsing.Parsing;
|
||||
import me.topchetoeu.jscript.compilation.parsing.Token;
|
||||
|
||||
public class OperationStatement extends Statement {
|
||||
public final Statement[] args;
|
||||
@ -18,8 +26,7 @@ public class OperationStatement extends Statement {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void compile(CompileResult target, boolean pollute) {
|
||||
@Override public void compile(CompileResult target, boolean pollute) {
|
||||
for (var arg : args) {
|
||||
arg.compile(target, true);
|
||||
}
|
||||
@ -33,4 +40,76 @@ public class OperationStatement extends Statement {
|
||||
this.operation = operation;
|
||||
this.args = args;
|
||||
}
|
||||
|
||||
public static ParseRes<OperationStatement> parseUnary(Filename filename, List<Token> tokens, int i) {
|
||||
var loc = Parsing.getLoc(filename, tokens, i);
|
||||
int n = 0;
|
||||
|
||||
var opState = Parsing.parseOperator(tokens, i + n++);
|
||||
if (!opState.isSuccess()) return ParseRes.failed();
|
||||
var op = opState.result;
|
||||
|
||||
Operation operation = null;
|
||||
|
||||
if (op == Operator.ADD) operation = Operation.POS;
|
||||
else if (op == Operator.SUBTRACT) operation = Operation.NEG;
|
||||
else if (op == Operator.INVERSE) operation = Operation.INVERSE;
|
||||
else if (op == Operator.NOT) operation = Operation.NOT;
|
||||
else return ParseRes.failed();
|
||||
|
||||
var res = Parsing.parseValue(filename, tokens, n + i, 14);
|
||||
|
||||
if (res.isSuccess()) return ParseRes.res(new OperationStatement(loc, operation, res.result), n + res.n);
|
||||
else return ParseRes.error(loc, String.format("Expected a value after the unary operator '%s'.", op.readable), res);
|
||||
}
|
||||
public static ParseRes<OperationStatement> parseInstanceof(Filename filename, List<Token> tokens, int i, Statement prev, int precedence) {
|
||||
var loc = Parsing.getLoc(filename, tokens, i);
|
||||
int n = 0;
|
||||
|
||||
if (precedence > 9) return ParseRes.failed();
|
||||
if (!Parsing.isIdentifier(tokens, i + n++, "instanceof")) return ParseRes.failed();
|
||||
|
||||
var valRes = Parsing.parseValue(filename, tokens, i + n, 10);
|
||||
if (!valRes.isSuccess()) return ParseRes.error(loc, "Expected a value after 'instanceof'.", valRes);
|
||||
n += valRes.n;
|
||||
|
||||
return ParseRes.res(new OperationStatement(loc, Operation.INSTANCEOF, prev, valRes.result), n);
|
||||
}
|
||||
public static ParseRes<OperationStatement> parseIn(Filename filename, List<Token> tokens, int i, Statement prev, int precedence) {
|
||||
var loc = Parsing.getLoc(filename, tokens, i);
|
||||
int n = 0;
|
||||
|
||||
if (precedence > 9) return ParseRes.failed();
|
||||
if (!Parsing.isIdentifier(tokens, i + n++, "in")) return ParseRes.failed();
|
||||
|
||||
var valRes = Parsing.parseValue(filename, tokens, i + n, 10);
|
||||
if (!valRes.isSuccess()) return ParseRes.error(loc, "Expected a value after 'in'.", valRes);
|
||||
n += valRes.n;
|
||||
|
||||
return ParseRes.res(new OperationStatement(loc, Operation.IN, prev, valRes.result), n);
|
||||
}
|
||||
public static ParseRes<? extends Statement> parseOperator(Filename filename, List<Token> tokens, int i, Statement prev, int precedence) {
|
||||
var loc = Parsing.getLoc(filename, tokens, i);
|
||||
var n = 0;
|
||||
|
||||
var opRes = Parsing.parseOperator(tokens, i + n++);
|
||||
if (!opRes.isSuccess()) return ParseRes.failed();
|
||||
var op = opRes.result;
|
||||
|
||||
if (op.precedence < precedence) return ParseRes.failed();
|
||||
if (op.isAssign()) return AssignableStatement.parse(filename, tokens, i + n - 1, prev, precedence);
|
||||
|
||||
var res = Parsing.parseValue(filename, tokens, i + n, op.precedence + (op.reverse ? 0 : 1));
|
||||
if (!res.isSuccess()) return ParseRes.error(loc, String.format("Expected a value after the '%s' operator.", op.readable), res);
|
||||
n += res.n;
|
||||
|
||||
if (op == Operator.LAZY_AND) {
|
||||
return ParseRes.res(new LazyAndStatement(loc, prev, res.result), n);
|
||||
}
|
||||
if (op == Operator.LAZY_OR) {
|
||||
return ParseRes.res(new LazyOrStatement(loc, prev, res.result), n);
|
||||
}
|
||||
|
||||
return ParseRes.res(new OperationStatement(loc, op.operation, prev, res.result), n);
|
||||
}
|
||||
}
|
||||
|
@ -1,9 +1,15 @@
|
||||
package me.topchetoeu.jscript.compilation.values;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import me.topchetoeu.jscript.common.Filename;
|
||||
import me.topchetoeu.jscript.common.Instruction;
|
||||
import me.topchetoeu.jscript.common.Location;
|
||||
import me.topchetoeu.jscript.common.ParseRes;
|
||||
import me.topchetoeu.jscript.compilation.CompileResult;
|
||||
import me.topchetoeu.jscript.compilation.Statement;
|
||||
import me.topchetoeu.jscript.compilation.parsing.Parsing;
|
||||
import me.topchetoeu.jscript.compilation.parsing.Token;
|
||||
|
||||
public class RegexStatement extends Statement {
|
||||
public final String pattern, flags;
|
||||
@ -17,6 +23,21 @@ public class RegexStatement extends Statement {
|
||||
if (!pollute) target.add(Instruction.discard());
|
||||
}
|
||||
|
||||
public static ParseRes<RegexStatement> parse(Filename filename, List<Token> tokens, int i) {
|
||||
var loc = Parsing.getLoc(filename, tokens, i);
|
||||
if (Parsing.inBounds(tokens, i)) {
|
||||
if (tokens.get(i).isRegex()) {
|
||||
var val = tokens.get(i).regex();
|
||||
var index = val.lastIndexOf('/');
|
||||
var first = val.substring(1, index);
|
||||
var second = val.substring(index + 1);
|
||||
return ParseRes.res(new RegexStatement(loc, first, second), 1);
|
||||
}
|
||||
else return ParseRes.failed();
|
||||
}
|
||||
return ParseRes.failed();
|
||||
}
|
||||
|
||||
public RegexStatement(Location loc, String pattern, String flags) {
|
||||
super(loc);
|
||||
this.pattern = pattern;
|
||||
|
@ -1,9 +1,15 @@
|
||||
package me.topchetoeu.jscript.compilation.values;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import me.topchetoeu.jscript.common.Filename;
|
||||
import me.topchetoeu.jscript.common.Instruction;
|
||||
import me.topchetoeu.jscript.common.Location;
|
||||
import me.topchetoeu.jscript.common.ParseRes;
|
||||
import me.topchetoeu.jscript.compilation.CompileResult;
|
||||
import me.topchetoeu.jscript.compilation.Statement;
|
||||
import me.topchetoeu.jscript.compilation.parsing.Parsing;
|
||||
import me.topchetoeu.jscript.compilation.parsing.Token;
|
||||
|
||||
public class TypeofStatement extends Statement {
|
||||
public final Statement value;
|
||||
@ -29,4 +35,16 @@ public class TypeofStatement extends Statement {
|
||||
super(loc);
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public static ParseRes<TypeofStatement> parse(Filename filename, List<Token> tokens, int i) {
|
||||
var loc = Parsing.getLoc(filename, tokens, i);
|
||||
var n = 0;
|
||||
if (!Parsing.isIdentifier(tokens, i + n++, "typeof")) return ParseRes.failed();
|
||||
|
||||
var valRes = Parsing.parseValue(filename, tokens, i + n, 15);
|
||||
if (!valRes.isSuccess()) return ParseRes.error(loc, "Expected a value after 'typeof' keyword.", valRes);
|
||||
n += valRes.n;
|
||||
|
||||
return ParseRes.res(new TypeofStatement(loc, valRes.result), n);
|
||||
}
|
||||
}
|
||||
|
@ -1,11 +1,17 @@
|
||||
package me.topchetoeu.jscript.compilation.values;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import me.topchetoeu.jscript.common.Filename;
|
||||
import me.topchetoeu.jscript.common.Instruction;
|
||||
import me.topchetoeu.jscript.common.Location;
|
||||
import me.topchetoeu.jscript.common.Operation;
|
||||
import me.topchetoeu.jscript.common.ParseRes;
|
||||
import me.topchetoeu.jscript.compilation.AssignableStatement;
|
||||
import me.topchetoeu.jscript.compilation.CompileResult;
|
||||
import me.topchetoeu.jscript.compilation.Statement;
|
||||
import me.topchetoeu.jscript.compilation.parsing.Parsing;
|
||||
import me.topchetoeu.jscript.compilation.parsing.Token;
|
||||
|
||||
public class VariableStatement extends AssignableStatement {
|
||||
public final String name;
|
||||
@ -28,4 +34,20 @@ public class VariableStatement extends AssignableStatement {
|
||||
super(loc);
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public static ParseRes<VariableStatement> parseVariable(Filename filename, List<Token> tokens, int i) {
|
||||
var loc = Parsing.getLoc(filename, tokens, i);
|
||||
var literal = Parsing.parseIdentifier(tokens, i);
|
||||
|
||||
if (!literal.isSuccess()) return ParseRes.failed();
|
||||
|
||||
if (!Parsing.checkVarName(literal.result)) {
|
||||
if (literal.result.equals("await")) return ParseRes.error(loc, "'await' expressions are not supported.");
|
||||
if (literal.result.equals("const")) return ParseRes.error(loc, "'const' declarations are not supported.");
|
||||
if (literal.result.equals("let")) return ParseRes.error(loc, "'let' declarations are not supported.");
|
||||
return ParseRes.error(loc, String.format("Unexpected identifier '%s'.", literal.result));
|
||||
}
|
||||
|
||||
return ParseRes.res(new VariableStatement(loc, literal.result), 1);
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
package me.topchetoeu.jscript.runtime;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Stack;
|
||||
@ -19,6 +20,7 @@ import me.topchetoeu.jscript.runtime.values.functions.CodeFunction;
|
||||
import me.topchetoeu.jscript.runtime.values.objects.ArrayValue;
|
||||
import me.topchetoeu.jscript.runtime.values.objects.ObjectValue;
|
||||
import me.topchetoeu.jscript.runtime.values.objects.ScopeValue;
|
||||
import me.topchetoeu.jscript.runtime.values.primitives.VoidValue;
|
||||
|
||||
public class Frame {
|
||||
public static final Key<Frame> KEY = new Key<>();
|
||||
@ -124,7 +126,7 @@ public class Frame {
|
||||
else return stack[stackPtr - 1 - offset];
|
||||
}
|
||||
public Value pop() {
|
||||
if (stackPtr == 0) return null;
|
||||
if (stackPtr == 0) return VoidValue.UNDEFINED;
|
||||
return stack[--stackPtr];
|
||||
}
|
||||
public Value[] take(int n) {
|
||||
@ -135,6 +137,7 @@ public class Frame {
|
||||
int copyN = stackPtr - srcI;
|
||||
|
||||
Value[] res = new Value[n];
|
||||
Arrays.fill(res, VoidValue.UNDEFINED);
|
||||
System.arraycopy(stack, srcI, res, dstI, copyN);
|
||||
stackPtr -= copyN;
|
||||
|
||||
|
@ -16,6 +16,7 @@ import me.topchetoeu.jscript.runtime.exceptions.SyntaxException;
|
||||
import me.topchetoeu.jscript.runtime.scope.GlobalScope;
|
||||
import me.topchetoeu.jscript.runtime.values.Value;
|
||||
import me.topchetoeu.jscript.runtime.values.functions.NativeFunction;
|
||||
import me.topchetoeu.jscript.runtime.values.primitives.VoidValue;
|
||||
|
||||
public class SimpleRepl {
|
||||
static Thread engineTask, debugTask;
|
||||
@ -48,7 +49,7 @@ public class SimpleRepl {
|
||||
|
||||
if (raw == null) break;
|
||||
var func = Compiler.compile(environment, new Filename("jscript", "repl/" + i + ".js"), raw);
|
||||
var res = engine.pushMsg(false, environment, func, null).await();
|
||||
var res = engine.pushMsg(false, environment, func, VoidValue.UNDEFINED).await();
|
||||
System.err.println(res.toReadable(environment));
|
||||
}
|
||||
catch (EngineException | SyntaxException e) { System.err.println(Value.errorToReadable(e, null)); }
|
||||
|
Loading…
Reference in New Issue
Block a user