mirror of
https://github.com/PolyhedralDev/Terra.git
synced 2026-04-06 07:46:13 +00:00
Simplify code
This commit is contained in:
@@ -83,17 +83,17 @@ public class Lexer {
|
||||
|
||||
// Check if operator token
|
||||
if(reader.matchesString("==", true))
|
||||
return new Token("==", TokenType.EQUALS_OPERATOR, reader.getPosition());
|
||||
return new Token("==", TokenType.EQUALS_EQUALS, reader.getPosition());
|
||||
if(reader.matchesString("!=", true))
|
||||
return new Token("!=", TokenType.NOT_EQUALS_OPERATOR, reader.getPosition());
|
||||
return new Token("!=", TokenType.BANG_EQUALS, reader.getPosition());
|
||||
if(reader.matchesString(">=", true))
|
||||
return new Token(">=", TokenType.GREATER_THAN_OR_EQUALS_OPERATOR, reader.getPosition());
|
||||
return new Token(">=", TokenType.GREATER_EQUAL, reader.getPosition());
|
||||
if(reader.matchesString("<=", true))
|
||||
return new Token("<=", TokenType.LESS_THAN_OR_EQUALS_OPERATOR, reader.getPosition());
|
||||
return new Token("<=", TokenType.LESS_EQUALS, reader.getPosition());
|
||||
if(reader.matchesString(">", true))
|
||||
return new Token(">", TokenType.GREATER_THAN_OPERATOR, reader.getPosition());
|
||||
return new Token(">", TokenType.GREATER, reader.getPosition());
|
||||
if(reader.matchesString("<", true))
|
||||
return new Token("<", TokenType.LESS_THAN_OPERATOR, reader.getPosition());
|
||||
return new Token("<", TokenType.LESS, reader.getPosition());
|
||||
|
||||
// Check if logical operator
|
||||
if(reader.matchesString("||", true))
|
||||
@@ -131,9 +131,9 @@ public class Lexer {
|
||||
}
|
||||
|
||||
if(reader.current().is('('))
|
||||
return new Token(reader.consume().toString(), TokenType.GROUP_BEGIN, reader.getPosition());
|
||||
return new Token(reader.consume().toString(), TokenType.OPEN_PAREN, reader.getPosition());
|
||||
if(reader.current().is(')'))
|
||||
return new Token(reader.consume().toString(), TokenType.GROUP_END, reader.getPosition());
|
||||
return new Token(reader.consume().toString(), TokenType.CLOSE_PAREN, reader.getPosition());
|
||||
if(reader.current().is(';'))
|
||||
return new Token(reader.consume().toString(), TokenType.STATEMENT_END, reader.getPosition());
|
||||
if(reader.current().is(','))
|
||||
@@ -153,19 +153,19 @@ public class Lexer {
|
||||
if(reader.current().is('='))
|
||||
return new Token(reader.consume().toString(), TokenType.ASSIGNMENT, reader.getPosition());
|
||||
if(reader.current().is('+'))
|
||||
return new Token(reader.consume().toString(), TokenType.ADDITION_OPERATOR, reader.getPosition());
|
||||
return new Token(reader.consume().toString(), TokenType.PLUS, reader.getPosition());
|
||||
if(reader.current().is('-'))
|
||||
return new Token(reader.consume().toString(), TokenType.SUBTRACTION_OPERATOR,
|
||||
return new Token(reader.consume().toString(), TokenType.MINUS,
|
||||
reader.getPosition());
|
||||
if(reader.current().is('*'))
|
||||
return new Token(reader.consume().toString(), TokenType.MULTIPLICATION_OPERATOR,
|
||||
return new Token(reader.consume().toString(), TokenType.STAR,
|
||||
reader.getPosition());
|
||||
if(reader.current().is('/'))
|
||||
return new Token(reader.consume().toString(), TokenType.DIVISION_OPERATOR, reader.getPosition());
|
||||
return new Token(reader.consume().toString(), TokenType.FORWARD_SLASH, reader.getPosition());
|
||||
if(reader.current().is('%'))
|
||||
return new Token(reader.consume().toString(), TokenType.MODULO_OPERATOR, reader.getPosition());
|
||||
if(reader.current().is('!'))
|
||||
return new Token(reader.consume().toString(), TokenType.BOOLEAN_NOT, reader.getPosition());
|
||||
return new Token(reader.consume().toString(), TokenType.BANG, reader.getPosition());
|
||||
|
||||
// Read word
|
||||
StringBuilder token = new StringBuilder();
|
||||
|
||||
@@ -44,29 +44,29 @@ public class Token {
|
||||
}
|
||||
|
||||
public boolean isBinaryOperator() {
|
||||
return type.equals(TokenType.ADDITION_OPERATOR)
|
||||
|| type.equals(TokenType.SUBTRACTION_OPERATOR)
|
||||
|| type.equals(TokenType.MULTIPLICATION_OPERATOR)
|
||||
|| type.equals(TokenType.DIVISION_OPERATOR)
|
||||
|| type.equals(TokenType.EQUALS_OPERATOR)
|
||||
|| type.equals(TokenType.NOT_EQUALS_OPERATOR)
|
||||
|| type.equals(TokenType.LESS_THAN_OPERATOR)
|
||||
|| type.equals(TokenType.GREATER_THAN_OPERATOR)
|
||||
|| type.equals(TokenType.LESS_THAN_OR_EQUALS_OPERATOR)
|
||||
|| type.equals(TokenType.GREATER_THAN_OR_EQUALS_OPERATOR)
|
||||
return type.equals(TokenType.PLUS)
|
||||
|| type.equals(TokenType.MINUS)
|
||||
|| type.equals(TokenType.STAR)
|
||||
|| type.equals(TokenType.FORWARD_SLASH)
|
||||
|| type.equals(TokenType.EQUALS_EQUALS)
|
||||
|| type.equals(TokenType.BANG_EQUALS)
|
||||
|| type.equals(TokenType.LESS)
|
||||
|| type.equals(TokenType.GREATER)
|
||||
|| type.equals(TokenType.LESS_EQUALS)
|
||||
|| type.equals(TokenType.GREATER_EQUAL)
|
||||
|| type.equals(TokenType.BOOLEAN_OR)
|
||||
|| type.equals(TokenType.BOOLEAN_AND)
|
||||
|| type.equals(TokenType.MODULO_OPERATOR);
|
||||
}
|
||||
|
||||
public boolean isStrictNumericOperator() {
|
||||
return type.equals(TokenType.SUBTRACTION_OPERATOR)
|
||||
|| type.equals(TokenType.MULTIPLICATION_OPERATOR)
|
||||
|| type.equals(TokenType.DIVISION_OPERATOR)
|
||||
|| type.equals(TokenType.GREATER_THAN_OPERATOR)
|
||||
|| type.equals(TokenType.LESS_THAN_OPERATOR)
|
||||
|| type.equals(TokenType.LESS_THAN_OR_EQUALS_OPERATOR)
|
||||
|| type.equals(TokenType.GREATER_THAN_OR_EQUALS_OPERATOR)
|
||||
return type.equals(TokenType.MINUS)
|
||||
|| type.equals(TokenType.STAR)
|
||||
|| type.equals(TokenType.FORWARD_SLASH)
|
||||
|| type.equals(TokenType.GREATER)
|
||||
|| type.equals(TokenType.LESS)
|
||||
|| type.equals(TokenType.LESS_EQUALS)
|
||||
|| type.equals(TokenType.GREATER_EQUAL)
|
||||
|| type.equals(TokenType.MODULO_OPERATOR);
|
||||
}
|
||||
|
||||
@@ -108,11 +108,11 @@ public class Token {
|
||||
/**
|
||||
* Beginning of group
|
||||
*/
|
||||
GROUP_BEGIN,
|
||||
OPEN_PAREN,
|
||||
/**
|
||||
* Ending of group
|
||||
*/
|
||||
GROUP_END,
|
||||
CLOSE_PAREN,
|
||||
/**
|
||||
* End of statement
|
||||
*/
|
||||
@@ -136,43 +136,43 @@ public class Token {
|
||||
/**
|
||||
* Boolean equals operator
|
||||
*/
|
||||
EQUALS_OPERATOR,
|
||||
EQUALS_EQUALS,
|
||||
/**
|
||||
* Boolean not equals operator
|
||||
*/
|
||||
NOT_EQUALS_OPERATOR,
|
||||
BANG_EQUALS,
|
||||
/**
|
||||
* Boolean greater than operator
|
||||
*/
|
||||
GREATER_THAN_OPERATOR,
|
||||
GREATER,
|
||||
/**
|
||||
* Boolean less than operator
|
||||
*/
|
||||
LESS_THAN_OPERATOR,
|
||||
LESS,
|
||||
/**
|
||||
* Boolean greater than or equal to operator
|
||||
*/
|
||||
GREATER_THAN_OR_EQUALS_OPERATOR,
|
||||
GREATER_EQUAL,
|
||||
/**
|
||||
* Boolean less than or equal to operator
|
||||
*/
|
||||
LESS_THAN_OR_EQUALS_OPERATOR,
|
||||
LESS_EQUALS,
|
||||
/**
|
||||
* Addition/concatenation operator
|
||||
*/
|
||||
ADDITION_OPERATOR,
|
||||
PLUS,
|
||||
/**
|
||||
* Subtraction operator
|
||||
*/
|
||||
SUBTRACTION_OPERATOR,
|
||||
MINUS,
|
||||
/**
|
||||
* Multiplication operator
|
||||
*/
|
||||
MULTIPLICATION_OPERATOR,
|
||||
STAR,
|
||||
/**
|
||||
* Division operator
|
||||
*/
|
||||
DIVISION_OPERATOR,
|
||||
FORWARD_SLASH,
|
||||
/**
|
||||
* Modulo operator.
|
||||
*/
|
||||
@@ -180,7 +180,7 @@ public class Token {
|
||||
/**
|
||||
* Boolean not operator
|
||||
*/
|
||||
BOOLEAN_NOT,
|
||||
BANG,
|
||||
/**
|
||||
* Boolean or
|
||||
*/
|
||||
|
||||
@@ -63,11 +63,12 @@ import com.dfsek.terra.api.util.generic.pair.Pair;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public class Parser {
|
||||
private final String source;
|
||||
private final List<String> ignoredFunctions = new ArrayList<>();
|
||||
|
||||
public Parser(String source) {
|
||||
this.source = source;
|
||||
private final Lexer lexer;
|
||||
|
||||
public Parser(Lexer lexer) {
|
||||
this.lexer = lexer;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -78,30 +79,30 @@ public class Parser {
|
||||
* @throws ParseException If parsing fails.
|
||||
*/
|
||||
public Executable parse(ScopeBuilder scopeBuilder) {
|
||||
return new Executable(parseBlock(new Lexer(source), scopeBuilder, ReturnType.VOID), scopeBuilder);
|
||||
return new Executable(parseBlock(scopeBuilder, ReturnType.VOID), scopeBuilder);
|
||||
}
|
||||
|
||||
private WhileKeyword parseWhileLoop(Lexer lexer, ScopeBuilder scopeBuilder) {
|
||||
private WhileKeyword parseWhileLoop(ScopeBuilder scopeBuilder) {
|
||||
SourcePosition start = lexer.consume().getPosition();
|
||||
ParserUtil.ensureType(lexer.consume(), TokenType.GROUP_BEGIN);
|
||||
ParserUtil.ensureType(lexer.consume(), TokenType.OPEN_PAREN);
|
||||
scopeBuilder = scopeBuilder.innerLoopScope();
|
||||
Expression<?> condition = parseExpression(lexer, true, scopeBuilder);
|
||||
Expression<?> condition = parseExpression(true, scopeBuilder);
|
||||
ParserUtil.ensureReturnType(condition, Expression.ReturnType.BOOLEAN);
|
||||
ParserUtil.ensureType(lexer.consume(), TokenType.GROUP_END);
|
||||
return new WhileKeyword(parseStatementBlock(lexer, scopeBuilder, ReturnType.VOID), (Expression<Boolean>) condition,
|
||||
ParserUtil.ensureType(lexer.consume(), TokenType.CLOSE_PAREN);
|
||||
return new WhileKeyword(parseStatementBlock(scopeBuilder, ReturnType.VOID), (Expression<Boolean>) condition,
|
||||
start); // While loop
|
||||
}
|
||||
|
||||
private IfKeyword parseIfStatement(Lexer lexer, ScopeBuilder scopeBuilder) {
|
||||
private IfKeyword parseIfStatement(ScopeBuilder scopeBuilder) {
|
||||
SourcePosition start = lexer.consume().getPosition();
|
||||
ParserUtil.ensureType(lexer.consume(), TokenType.GROUP_BEGIN);
|
||||
Expression<?> condition = parseExpression(lexer, true, scopeBuilder);
|
||||
ParserUtil.ensureType(lexer.consume(), TokenType.OPEN_PAREN);
|
||||
Expression<?> condition = parseExpression(true, scopeBuilder);
|
||||
ParserUtil.ensureReturnType(condition, Expression.ReturnType.BOOLEAN);
|
||||
|
||||
ParserUtil.ensureType(lexer.consume(), TokenType.GROUP_END);
|
||||
ParserUtil.ensureType(lexer.consume(), TokenType.CLOSE_PAREN);
|
||||
|
||||
Block elseBlock = null;
|
||||
Block statement = parseStatementBlock(lexer, scopeBuilder, ReturnType.VOID);
|
||||
Block statement = parseStatementBlock(scopeBuilder, ReturnType.VOID);
|
||||
|
||||
List<Pair<Expression<Boolean>, Block>> elseIf = new ArrayList<>();
|
||||
|
||||
@@ -109,11 +110,11 @@ public class Parser {
|
||||
lexer.consume(); // Consume else.
|
||||
if(lexer.current().isType(TokenType.IF_STATEMENT)) {
|
||||
lexer.consume(); // Consume if.
|
||||
Expression<?> elseCondition = parseExpression(lexer, true, scopeBuilder);
|
||||
Expression<?> elseCondition = parseExpression(true, scopeBuilder);
|
||||
ParserUtil.ensureReturnType(elseCondition, Expression.ReturnType.BOOLEAN);
|
||||
elseIf.add(Pair.of((Expression<Boolean>) elseCondition, parseStatementBlock(lexer, scopeBuilder, ReturnType.VOID)));
|
||||
elseIf.add(Pair.of((Expression<Boolean>) elseCondition, parseStatementBlock(scopeBuilder, ReturnType.VOID)));
|
||||
} else {
|
||||
elseBlock = parseStatementBlock(lexer, scopeBuilder, ReturnType.VOID);
|
||||
elseBlock = parseStatementBlock(scopeBuilder, ReturnType.VOID);
|
||||
break; // Else must be last.
|
||||
}
|
||||
}
|
||||
@@ -121,10 +122,10 @@ public class Parser {
|
||||
return new IfKeyword(statement, (Expression<Boolean>) condition, elseIf, elseBlock, start); // If statement
|
||||
}
|
||||
|
||||
private Block parseStatementBlock(Lexer lexer, ScopeBuilder scopeBuilder, ReturnType blockReturnType) {
|
||||
private Block parseStatementBlock(ScopeBuilder scopeBuilder, ReturnType blockReturnType) {
|
||||
if(lexer.current().isType(TokenType.BLOCK_BEGIN)) {
|
||||
ParserUtil.ensureType(lexer.consume(), TokenType.BLOCK_BEGIN);
|
||||
Block block = parseBlock(lexer, scopeBuilder, blockReturnType);
|
||||
Block block = parseBlock(scopeBuilder, blockReturnType);
|
||||
ParserUtil.ensureType(lexer.consume(), TokenType.BLOCK_END);
|
||||
return block;
|
||||
} else {
|
||||
@@ -133,61 +134,61 @@ public class Parser {
|
||||
}
|
||||
}
|
||||
|
||||
private ForKeyword parseForLoop(Lexer lexer, ScopeBuilder scopeBuilder) {
|
||||
private ForKeyword parseForLoop(ScopeBuilder scopeBuilder) {
|
||||
SourcePosition start = lexer.consume().getPosition();
|
||||
ParserUtil.ensureType(lexer.consume(), TokenType.GROUP_BEGIN);
|
||||
ParserUtil.ensureType(lexer.consume(), TokenType.OPEN_PAREN);
|
||||
scopeBuilder = scopeBuilder.innerLoopScope(); // new scope
|
||||
Token f = lexer.current();
|
||||
ParserUtil.ensureType(f, TokenType.TYPE_NUMBER, TokenType.TYPE_STRING, TokenType.TYPE_BOOLEAN, TokenType.IDENTIFIER);
|
||||
Expression<?> initializer;
|
||||
if(f.isVariableDeclaration()) {
|
||||
Expression<?> forVar = parseDeclaration(lexer, scopeBuilder);
|
||||
Expression<?> forVar = parseDeclaration(scopeBuilder);
|
||||
Token name = lexer.current();
|
||||
if(scopeBuilder.containsFunction(name.getContent()) || scopeBuilder.contains(name.getContent()))
|
||||
throw new ParseException(name.getContent() + " is already defined in this scope", name.getPosition());
|
||||
initializer = forVar;
|
||||
} else initializer = parseExpression(lexer, true, scopeBuilder);
|
||||
} else initializer = parseExpression(true, scopeBuilder);
|
||||
ParserUtil.ensureType(lexer.consume(), TokenType.STATEMENT_END);
|
||||
Expression<?> conditional = parseExpression(lexer, true, scopeBuilder);
|
||||
Expression<?> conditional = parseExpression(true, scopeBuilder);
|
||||
ParserUtil.ensureReturnType(conditional, Expression.ReturnType.BOOLEAN);
|
||||
ParserUtil.ensureType(lexer.consume(), TokenType.STATEMENT_END);
|
||||
|
||||
Expression<?> incrementer;
|
||||
Token token = lexer.current();
|
||||
if(scopeBuilder.contains(token.getContent())) { // Assume variable assignment
|
||||
incrementer = parseAssignment(lexer, scopeBuilder);
|
||||
} else incrementer = parseFunctionInvocation(lexer, true, scopeBuilder);
|
||||
incrementer = parseAssignment(scopeBuilder);
|
||||
} else incrementer = parseFunctionInvocation(true, scopeBuilder);
|
||||
|
||||
ParserUtil.ensureType(lexer.consume(), TokenType.GROUP_END);
|
||||
ParserUtil.ensureType(lexer.consume(), TokenType.CLOSE_PAREN);
|
||||
|
||||
return new ForKeyword(parseStatementBlock(lexer, scopeBuilder, ReturnType.VOID), initializer, (Expression<Boolean>) conditional,
|
||||
return new ForKeyword(parseStatementBlock(scopeBuilder, ReturnType.VOID), initializer, (Expression<Boolean>) conditional,
|
||||
incrementer,
|
||||
start);
|
||||
}
|
||||
|
||||
private Expression<?> parseExpression(Lexer lexer, boolean full, ScopeBuilder scopeBuilder) {
|
||||
private Expression<?> parseExpression(boolean full, ScopeBuilder scopeBuilder) {
|
||||
boolean booleanInverted = false; // Check for boolean not operator
|
||||
boolean negate = false;
|
||||
if(lexer.current().isType(TokenType.BOOLEAN_NOT)) {
|
||||
if(lexer.current().isType(TokenType.BANG)) {
|
||||
booleanInverted = true;
|
||||
lexer.consume();
|
||||
} else if(lexer.current().isType(TokenType.SUBTRACTION_OPERATOR)) {
|
||||
} else if(lexer.current().isType(TokenType.MINUS)) {
|
||||
negate = true;
|
||||
lexer.consume();
|
||||
}
|
||||
|
||||
Token id = lexer.current();
|
||||
|
||||
ParserUtil.ensureType(id, TokenType.IDENTIFIER, TokenType.BOOLEAN, TokenType.STRING, TokenType.NUMBER, TokenType.GROUP_BEGIN);
|
||||
ParserUtil.ensureType(id, TokenType.IDENTIFIER, TokenType.BOOLEAN, TokenType.STRING, TokenType.NUMBER, TokenType.OPEN_PAREN);
|
||||
|
||||
Expression<?> expression;
|
||||
if(id.isConstant()) {
|
||||
expression = parseConstantExpression(lexer);
|
||||
} else if(id.isType(TokenType.GROUP_BEGIN)) { // Parse grouped expression
|
||||
expression = parseExpressionGroup(lexer, scopeBuilder);
|
||||
} else if(id.isType(TokenType.OPEN_PAREN)) { // Parse grouped expression
|
||||
expression = parseExpressionGroup(scopeBuilder);
|
||||
} else {
|
||||
if(scopeBuilder.containsFunction(id.getContent()))
|
||||
expression = parseFunctionInvocation(lexer, false, scopeBuilder);
|
||||
expression = parseFunctionInvocation(false, scopeBuilder);
|
||||
else if(scopeBuilder.contains(id.getContent())) {
|
||||
ParserUtil.ensureType(lexer.consume(), TokenType.IDENTIFIER);
|
||||
String varId = id.getContent();
|
||||
@@ -211,7 +212,7 @@ public class Parser {
|
||||
}
|
||||
|
||||
if(full && lexer.current().isBinaryOperator()) { // Parse binary operations
|
||||
return parseBinaryOperation(expression, lexer, scopeBuilder);
|
||||
return parseBinaryOperation(expression, scopeBuilder);
|
||||
}
|
||||
return expression;
|
||||
}
|
||||
@@ -231,27 +232,26 @@ public class Parser {
|
||||
};
|
||||
}
|
||||
|
||||
private Expression<?> parseExpressionGroup(Lexer lexer, ScopeBuilder scopeBuilder) {
|
||||
ParserUtil.ensureType(lexer.consume(), TokenType.GROUP_BEGIN);
|
||||
Expression<?> expression = parseExpression(lexer, true, scopeBuilder); // Parse inside of group as a separate expression
|
||||
ParserUtil.ensureType(lexer.consume(), TokenType.GROUP_END);
|
||||
private Expression<?> parseExpressionGroup(ScopeBuilder scopeBuilder) {
|
||||
ParserUtil.ensureType(lexer.consume(), TokenType.OPEN_PAREN);
|
||||
Expression<?> expression = parseExpression(true, scopeBuilder); // Parse inside of group as a separate expression
|
||||
ParserUtil.ensureType(lexer.consume(), TokenType.CLOSE_PAREN);
|
||||
return expression;
|
||||
}
|
||||
|
||||
private BinaryOperation<?, ?> parseBinaryOperation(Expression<?> left, Lexer lexer,
|
||||
ScopeBuilder scopeBuilder) {
|
||||
private BinaryOperation<?, ?> parseBinaryOperation(Expression<?> left, ScopeBuilder scopeBuilder) {
|
||||
Token binaryOperator = lexer.consume();
|
||||
ParserUtil.checkBinaryOperator(binaryOperator);
|
||||
|
||||
Expression<?> right = parseExpression(lexer, false, scopeBuilder);
|
||||
Expression<?> right = parseExpression(false, scopeBuilder);
|
||||
|
||||
Token other = lexer.current();
|
||||
|
||||
if(ParserUtil.hasPrecedence(binaryOperator.getType(), other.getType()))
|
||||
return assemble(left, parseBinaryOperation(right, lexer, scopeBuilder), binaryOperator);
|
||||
return assemble(left, parseBinaryOperation(right, scopeBuilder), binaryOperator);
|
||||
|
||||
if(other.isBinaryOperator())
|
||||
return parseBinaryOperation(assemble(left, right, binaryOperator), lexer, scopeBuilder);
|
||||
return parseBinaryOperation(assemble(left, right, binaryOperator), scopeBuilder);
|
||||
|
||||
return assemble(left, right, binaryOperator);
|
||||
}
|
||||
@@ -261,29 +261,29 @@ public class Parser {
|
||||
ParserUtil.checkArithmeticOperation(left, right, binaryOperator); // Numeric type checking
|
||||
if(binaryOperator.isStrictBooleanOperator()) ParserUtil.checkBooleanOperation(left, right, binaryOperator); // Boolean type checking
|
||||
switch(binaryOperator.getType()) {
|
||||
case ADDITION_OPERATOR:
|
||||
case PLUS:
|
||||
if(left.returnType().equals(Expression.ReturnType.NUMBER) && right.returnType().equals(Expression.ReturnType.NUMBER)) {
|
||||
return new NumberAdditionOperation((Expression<Number>) left, (Expression<Number>) right, binaryOperator.getPosition());
|
||||
}
|
||||
return new ConcatenationOperation((Expression<Object>) left, (Expression<Object>) right, binaryOperator.getPosition());
|
||||
case SUBTRACTION_OPERATOR:
|
||||
case MINUS:
|
||||
return new SubtractionOperation((Expression<Number>) left, (Expression<Number>) right, binaryOperator.getPosition());
|
||||
case MULTIPLICATION_OPERATOR:
|
||||
case STAR:
|
||||
return new MultiplicationOperation((Expression<Number>) left, (Expression<Number>) right, binaryOperator.getPosition());
|
||||
case DIVISION_OPERATOR:
|
||||
case FORWARD_SLASH:
|
||||
return new DivisionOperation((Expression<Number>) left, (Expression<Number>) right, binaryOperator.getPosition());
|
||||
case EQUALS_OPERATOR:
|
||||
case EQUALS_EQUALS:
|
||||
return new EqualsStatement((Expression<Object>) left, (Expression<Object>) right, binaryOperator.getPosition());
|
||||
case NOT_EQUALS_OPERATOR:
|
||||
case BANG_EQUALS:
|
||||
return new NotEqualsStatement((Expression<Object>) left, (Expression<Object>) right, binaryOperator.getPosition());
|
||||
case GREATER_THAN_OPERATOR:
|
||||
case GREATER:
|
||||
return new GreaterThanStatement((Expression<Number>) left, (Expression<Number>) right, binaryOperator.getPosition());
|
||||
case LESS_THAN_OPERATOR:
|
||||
case LESS:
|
||||
return new LessThanStatement((Expression<Number>) left, (Expression<Number>) right, binaryOperator.getPosition());
|
||||
case GREATER_THAN_OR_EQUALS_OPERATOR:
|
||||
case GREATER_EQUAL:
|
||||
return new GreaterOrEqualsThanStatement((Expression<Number>) left, (Expression<Number>) right,
|
||||
binaryOperator.getPosition());
|
||||
case LESS_THAN_OR_EQUALS_OPERATOR:
|
||||
case LESS_EQUALS:
|
||||
return new LessThanOrEqualsStatement((Expression<Number>) left, (Expression<Number>) right, binaryOperator.getPosition());
|
||||
case BOOLEAN_AND:
|
||||
return new BooleanAndOperation((Expression<Boolean>) left, (Expression<Boolean>) right, binaryOperator.getPosition());
|
||||
@@ -296,30 +296,30 @@ public class Parser {
|
||||
}
|
||||
}
|
||||
|
||||
private Expression<?> parseDeclaration(Lexer lexer, ScopeBuilder scopeBuilder) {
|
||||
private Expression<?> parseDeclaration(ScopeBuilder scopeBuilder) {
|
||||
Token type = lexer.consume();
|
||||
|
||||
Token identifier = lexer.consume();
|
||||
ParserUtil.ensureType(identifier, TokenType.IDENTIFIER);
|
||||
|
||||
Token declarationType = lexer.consume();
|
||||
ParserUtil.ensureType(declarationType, TokenType.ASSIGNMENT, TokenType.GROUP_BEGIN);
|
||||
ParserUtil.ensureType(declarationType, TokenType.ASSIGNMENT, TokenType.OPEN_PAREN);
|
||||
|
||||
return switch(declarationType.getType()) {
|
||||
case ASSIGNMENT -> parseVariableDeclaration(lexer, scopeBuilder, type, identifier);
|
||||
case GROUP_BEGIN -> parseFunctionDeclaration(lexer, scopeBuilder, type, identifier);
|
||||
case ASSIGNMENT -> parseVariableDeclaration(scopeBuilder, type, identifier);
|
||||
case OPEN_PAREN -> parseFunctionDeclaration(scopeBuilder, type, identifier);
|
||||
default -> throw new ParseException("Illegal type for declaration: " + type, declarationType.getPosition());
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
private Expression<?> parseVariableDeclaration(Lexer lexer, ScopeBuilder scopeBuilder, Token type, Token identifier) {
|
||||
private Expression<?> parseVariableDeclaration(ScopeBuilder scopeBuilder, Token type, Token identifier) {
|
||||
ParserUtil.ensureType(type, TokenType.TYPE_STRING, TokenType.TYPE_BOOLEAN, TokenType.TYPE_NUMBER);
|
||||
|
||||
if(scopeBuilder.contains(identifier.getContent()))
|
||||
throw new ParseException(identifier.getContent() + " is already defined in this scope", identifier.getPosition());
|
||||
|
||||
Expression<?> value = parseExpression(lexer, true, scopeBuilder);
|
||||
Expression<?> value = parseExpression(true, scopeBuilder);
|
||||
ParserUtil.ensureReturnType(value, ParserUtil.getVariableReturnType(type));
|
||||
|
||||
String variableName = identifier.getContent();
|
||||
@@ -334,7 +334,7 @@ public class Parser {
|
||||
};
|
||||
}
|
||||
|
||||
private Expression<?> parseFunctionDeclaration(Lexer lexer, ScopeBuilder scopeBuilder, Token type, Token identifier) {
|
||||
private Expression<?> parseFunctionDeclaration(ScopeBuilder scopeBuilder, Token type, Token identifier) {
|
||||
ParserUtil.ensureType(type, TokenType.TYPE_STRING, TokenType.TYPE_BOOLEAN, TokenType.TYPE_NUMBER, TokenType.TYPE_VOID);
|
||||
|
||||
if(scopeBuilder.contains(identifier.getContent()))
|
||||
@@ -345,7 +345,7 @@ public class Parser {
|
||||
ScopeBuilder functionBodyScope = scopeBuilder.functionScope();
|
||||
|
||||
// Declare argument names into function body scope
|
||||
List<Pair<Integer, ReturnType>> argumentInfo = getFunctionArgumentsDeclaration(lexer).stream().map(
|
||||
List<Pair<Integer, ReturnType>> argumentInfo = getFunctionArgumentsDeclaration().stream().map(
|
||||
arg -> Pair.of(switch(arg.getRight()) {
|
||||
case NUMBER -> functionBodyScope.declareNum(arg.getLeft());
|
||||
case BOOLEAN -> functionBodyScope.declareBool(arg.getLeft());
|
||||
@@ -353,7 +353,7 @@ public class Parser {
|
||||
default -> throw new IllegalArgumentException("Unsupported argument type: " + arg.getRight());
|
||||
}, arg.getRight())).toList();
|
||||
|
||||
Block body = parseStatementBlock(lexer, functionBodyScope, returnType);
|
||||
Block body = parseStatementBlock(functionBodyScope, returnType);
|
||||
|
||||
FunctionBuilder<?> functionBuilder = new UserDefinedFunctionBuilder<>(returnType, argumentInfo, body, functionBodyScope);
|
||||
|
||||
@@ -361,9 +361,9 @@ public class Parser {
|
||||
return Expression.NOOP;
|
||||
}
|
||||
|
||||
private List<Pair<String, ReturnType>> getFunctionArgumentsDeclaration(Lexer lexer) {
|
||||
private List<Pair<String, ReturnType>> getFunctionArgumentsDeclaration() {
|
||||
List<Pair<String, ReturnType>> arguments = new ArrayList<>();
|
||||
while(lexer.current().getType() != TokenType.GROUP_END) {
|
||||
while(lexer.current().getType() != TokenType.CLOSE_PAREN) {
|
||||
// Parse argument type
|
||||
Token typeToken = lexer.consume();
|
||||
ParserUtil.ensureType(typeToken, TokenType.TYPE_BOOLEAN, TokenType.TYPE_STRING, TokenType.TYPE_NUMBER);
|
||||
@@ -379,11 +379,11 @@ public class Parser {
|
||||
// Consume separator if present, trailing separators are allowed
|
||||
if(lexer.current().isType(TokenType.SEPARATOR)) lexer.consume();
|
||||
}
|
||||
ParserUtil.ensureType(lexer.consume(), TokenType.GROUP_END);
|
||||
ParserUtil.ensureType(lexer.consume(), TokenType.CLOSE_PAREN);
|
||||
return arguments;
|
||||
}
|
||||
|
||||
private Block parseBlock(Lexer lexer, ScopeBuilder scopeBuilder, ReturnType blockReturnType) {
|
||||
private Block parseBlock(ScopeBuilder scopeBuilder, ReturnType blockReturnType) {
|
||||
List<Expression<?>> expressions = new ArrayList<>();
|
||||
scopeBuilder = scopeBuilder.innerScope();
|
||||
SourcePosition startPosition = lexer.current().getPosition();
|
||||
@@ -428,15 +428,15 @@ public class Parser {
|
||||
TokenType.FAIL);
|
||||
|
||||
Expression<?> expression = switch(token.getType()) {
|
||||
case FOR_LOOP -> parseForLoop(lexer, scopeBuilder);
|
||||
case IF_STATEMENT -> parseIfStatement(lexer, scopeBuilder);
|
||||
case WHILE_LOOP -> parseWhileLoop(lexer, scopeBuilder);
|
||||
case FOR_LOOP -> parseForLoop(scopeBuilder);
|
||||
case IF_STATEMENT -> parseIfStatement(scopeBuilder);
|
||||
case WHILE_LOOP -> parseWhileLoop(scopeBuilder);
|
||||
case IDENTIFIER -> {
|
||||
if(scopeBuilder.contains(token.getContent())) yield parseAssignment(lexer, scopeBuilder); // Assume variable assignment
|
||||
else yield parseFunctionInvocation(lexer, true, scopeBuilder);
|
||||
if(scopeBuilder.contains(token.getContent())) yield parseAssignment(scopeBuilder); // Assume variable assignment
|
||||
else yield parseFunctionInvocation(true, scopeBuilder);
|
||||
}
|
||||
case TYPE_NUMBER, TYPE_STRING, TYPE_BOOLEAN, TYPE_VOID -> parseDeclaration(lexer, scopeBuilder);
|
||||
case RETURN -> parseReturn(lexer, scopeBuilder);
|
||||
case TYPE_NUMBER, TYPE_STRING, TYPE_BOOLEAN, TYPE_VOID -> parseDeclaration(scopeBuilder);
|
||||
case RETURN -> parseReturn(scopeBuilder);
|
||||
case BREAK -> new BreakKeyword(lexer.consume().getPosition());
|
||||
case CONTINUE -> new ContinueKeyword(lexer.consume().getPosition());
|
||||
case FAIL -> new FailKeyword(lexer.consume().getPosition());
|
||||
@@ -446,24 +446,24 @@ public class Parser {
|
||||
return expression;
|
||||
}
|
||||
|
||||
private ReturnKeyword parseReturn(Lexer lexer, ScopeBuilder scopeBuilder) {
|
||||
private ReturnKeyword parseReturn(ScopeBuilder scopeBuilder) {
|
||||
Token returnToken = lexer.consume();
|
||||
ParserUtil.ensureType(returnToken, TokenType.RETURN);
|
||||
Expression<?> data = null;
|
||||
if(!lexer.current().isType(TokenType.STATEMENT_END)) {
|
||||
data = parseExpression(lexer, true, scopeBuilder);
|
||||
data = parseExpression(true, scopeBuilder);
|
||||
}
|
||||
return new ReturnKeyword(data, returnToken.getPosition());
|
||||
}
|
||||
|
||||
private VariableAssignmentNode<?> parseAssignment(Lexer lexer, ScopeBuilder scopeBuilder) {
|
||||
private VariableAssignmentNode<?> parseAssignment(ScopeBuilder scopeBuilder) {
|
||||
Token identifier = lexer.consume();
|
||||
|
||||
ParserUtil.ensureType(identifier, TokenType.IDENTIFIER);
|
||||
|
||||
ParserUtil.ensureType(lexer.consume(), TokenType.ASSIGNMENT);
|
||||
|
||||
Expression<?> value = parseExpression(lexer, true, scopeBuilder);
|
||||
Expression<?> value = parseExpression(true, scopeBuilder);
|
||||
|
||||
String id = identifier.getContent();
|
||||
|
||||
@@ -479,18 +479,18 @@ public class Parser {
|
||||
};
|
||||
}
|
||||
|
||||
private Expression<?> parseFunctionInvocation(Lexer lexer, boolean fullStatement, ScopeBuilder scopeBuilder) {
|
||||
private Expression<?> parseFunctionInvocation(boolean fullStatement, ScopeBuilder scopeBuilder) {
|
||||
Token identifier = lexer.consume();
|
||||
ParserUtil.ensureType(identifier, TokenType.IDENTIFIER); // First token must be identifier
|
||||
|
||||
if(!scopeBuilder.containsFunction(identifier.getContent()))
|
||||
throw new ParseException("Function \"" + identifier.getContent() + "\" is not defined in this scope", identifier.getPosition());
|
||||
|
||||
ParserUtil.ensureType(lexer.consume(), TokenType.GROUP_BEGIN); // Second is body begin
|
||||
ParserUtil.ensureType(lexer.consume(), TokenType.OPEN_PAREN); // Second is body begin
|
||||
|
||||
List<Expression<?>> args = getFunctionArgs(lexer, scopeBuilder); // Extract arguments, consume the rest.
|
||||
List<Expression<?>> args = getFunctionArgs(scopeBuilder); // Extract arguments, consume the rest.
|
||||
|
||||
ParserUtil.ensureType(lexer.consume(), TokenType.GROUP_END); // Remove body end
|
||||
ParserUtil.ensureType(lexer.consume(), TokenType.CLOSE_PAREN); // Remove body end
|
||||
|
||||
if(fullStatement) ParserUtil.ensureType(lexer.current(), TokenType.STATEMENT_END);
|
||||
|
||||
@@ -516,12 +516,12 @@ public class Parser {
|
||||
throw new UnsupportedOperationException("Unsupported function: " + identifier.getContent());
|
||||
}
|
||||
|
||||
private List<Expression<?>> getFunctionArgs(Lexer lexer, ScopeBuilder scopeBuilder) {
|
||||
private List<Expression<?>> getFunctionArgs(ScopeBuilder scopeBuilder) {
|
||||
List<Expression<?>> args = new ArrayList<>();
|
||||
|
||||
while(!lexer.current().isType(TokenType.GROUP_END)) {
|
||||
args.add(parseExpression(lexer, true, scopeBuilder));
|
||||
ParserUtil.ensureType(lexer.current(), TokenType.SEPARATOR, TokenType.GROUP_END);
|
||||
while(!lexer.current().isType(TokenType.CLOSE_PAREN)) {
|
||||
args.add(parseExpression(true, scopeBuilder));
|
||||
ParserUtil.ensureType(lexer.current(), TokenType.SEPARATOR, TokenType.CLOSE_PAREN);
|
||||
if(lexer.current().isType(TokenType.SEPARATOR)) lexer.consume();
|
||||
}
|
||||
return args;
|
||||
|
||||
@@ -21,21 +21,21 @@ import com.dfsek.terra.addons.terrascript.parser.lang.Expression;
|
||||
public class ParserUtil {
|
||||
|
||||
private static final Map<TokenType, Map<TokenType, Boolean>> PRECEDENCE = new HashMap<>(); // If second has precedence, true.
|
||||
private static final List<TokenType> ARITHMETIC = Arrays.asList(TokenType.ADDITION_OPERATOR, TokenType.SUBTRACTION_OPERATOR,
|
||||
TokenType.MULTIPLICATION_OPERATOR, TokenType.DIVISION_OPERATOR,
|
||||
private static final List<TokenType> ARITHMETIC = Arrays.asList(TokenType.PLUS, TokenType.MINUS,
|
||||
TokenType.STAR, TokenType.FORWARD_SLASH,
|
||||
TokenType.MODULO_OPERATOR);
|
||||
private static final List<TokenType> COMPARISON = Arrays.asList(TokenType.EQUALS_OPERATOR, TokenType.NOT_EQUALS_OPERATOR,
|
||||
TokenType.LESS_THAN_OPERATOR, TokenType.LESS_THAN_OR_EQUALS_OPERATOR,
|
||||
TokenType.GREATER_THAN_OPERATOR,
|
||||
TokenType.GREATER_THAN_OR_EQUALS_OPERATOR);
|
||||
private static final List<TokenType> COMPARISON = Arrays.asList(TokenType.EQUALS_EQUALS, TokenType.BANG_EQUALS,
|
||||
TokenType.LESS, TokenType.LESS_EQUALS,
|
||||
TokenType.GREATER,
|
||||
TokenType.GREATER_EQUAL);
|
||||
|
||||
static { // Setup precedence
|
||||
Map<TokenType, Boolean> add = new HashMap<>(); // Addition/subtraction before Multiplication/division.
|
||||
add.put(TokenType.MULTIPLICATION_OPERATOR, true);
|
||||
add.put(TokenType.DIVISION_OPERATOR, true);
|
||||
add.put(TokenType.STAR, true);
|
||||
add.put(TokenType.FORWARD_SLASH, true);
|
||||
|
||||
PRECEDENCE.put(TokenType.ADDITION_OPERATOR, add);
|
||||
PRECEDENCE.put(TokenType.SUBTRACTION_OPERATOR, add);
|
||||
PRECEDENCE.put(TokenType.PLUS, add);
|
||||
PRECEDENCE.put(TokenType.MINUS, add);
|
||||
|
||||
Map<TokenType, Boolean> numericBoolean = new HashMap<>();
|
||||
|
||||
|
||||
@@ -7,6 +7,8 @@
|
||||
|
||||
package com.dfsek.terra.addons.terrascript.script;
|
||||
|
||||
import com.dfsek.terra.addons.terrascript.lexer.Lexer;
|
||||
|
||||
import net.jafama.FastMath;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.slf4j.Logger;
|
||||
@@ -62,18 +64,18 @@ public class StructureScript implements Structure, Keyed<StructureScript> {
|
||||
public StructureScript(InputStream source, RegistryKey id, Platform platform, Registry<Structure> structureRegistry,
|
||||
Registry<LootTable> lootRegistry,
|
||||
Registry<FunctionBuilder> functionRegistry) {
|
||||
Parser parser;
|
||||
Lexer lexer;
|
||||
try {
|
||||
parser = new Parser(IOUtils.toString(source, Charset.defaultCharset()));
|
||||
lexer = new Lexer(IOUtils.toString(source, Charset.defaultCharset()));
|
||||
} catch(IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
Parser parser = new Parser(lexer);
|
||||
this.id = id;
|
||||
this.profile = "terrascript_direct:" + id;
|
||||
|
||||
ScopeBuilder scope = new ScopeBuilder();
|
||||
|
||||
//noinspection unchecked
|
||||
functionRegistry.forEach((key, function) -> scope.registerFunction(key.getID(), function)); // Register registry functions.
|
||||
|
||||
scope
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
package structure;
|
||||
|
||||
|
||||
import com.dfsek.terra.addons.terrascript.lexer.Lexer;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Scope.ScopeBuilder;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
@@ -32,8 +33,8 @@ import com.dfsek.terra.addons.terrascript.lexer.SourcePosition;
|
||||
public class ParserTest {
|
||||
@Test
|
||||
public void parse() throws IOException, ParseException {
|
||||
Parser parser = new Parser(
|
||||
IOUtils.toString(Objects.requireNonNull(getClass().getResourceAsStream("/test.tesf")), Charset.defaultCharset()));
|
||||
Lexer lexer = new Lexer(IOUtils.toString(Objects.requireNonNull(getClass().getResourceAsStream("/test.tesf")), Charset.defaultCharset()));
|
||||
Parser parser = new Parser(lexer);
|
||||
|
||||
ScopeBuilder scope = new ScopeBuilder();
|
||||
scope.registerFunction("test", new FunctionBuilder<Test1>() {
|
||||
|
||||
Reference in New Issue
Block a user