More refactoring

This commit is contained in:
Astrash
2023-07-23 17:55:29 +10:00
parent f3d1751c87
commit 76728fe593
61 changed files with 317 additions and 301 deletions
@@ -16,8 +16,6 @@ import java.util.Map;
import com.dfsek.terra.addons.terrascript.parser.exceptions.ParseException; import com.dfsek.terra.addons.terrascript.parser.exceptions.ParseException;
import com.dfsek.terra.addons.terrascript.parser.lang.Block; import com.dfsek.terra.addons.terrascript.parser.lang.Block;
import com.dfsek.terra.addons.terrascript.parser.lang.Executable; import com.dfsek.terra.addons.terrascript.parser.lang.Executable;
import com.dfsek.terra.addons.terrascript.parser.lang.Statement;
import com.dfsek.terra.addons.terrascript.parser.lang.Keyword;
import com.dfsek.terra.addons.terrascript.parser.lang.Expression; import com.dfsek.terra.addons.terrascript.parser.lang.Expression;
import com.dfsek.terra.addons.terrascript.parser.lang.Expression.ReturnType; import com.dfsek.terra.addons.terrascript.parser.lang.Expression.ReturnType;
import com.dfsek.terra.addons.terrascript.parser.lang.Scope.ScopeBuilder; import com.dfsek.terra.addons.terrascript.parser.lang.Scope.ScopeBuilder;
@@ -96,51 +94,35 @@ public class Parser {
return new Executable(parseBlock(new Tokenizer(source), false, scopeBuilder), scopeBuilder); return new Executable(parseBlock(new Tokenizer(source), false, scopeBuilder), scopeBuilder);
} }
private Keyword<?> parseLoopLike(Tokenizer tokens, boolean loop, ScopeBuilder scopeBuilder) throws ParseException { private WhileKeyword parseWhileLoop(Tokenizer tokenizer, SourcePosition start, ScopeBuilder scopeBuilder) {
Expression<?> first = parseLogicMathExpression(tokenizer, true, scopeBuilder);
Token identifier = tokens.consume();
ParserUtil.checkType(identifier, Token.Type.IF_STATEMENT, Token.Type.WHILE_LOOP, Token.Type.FOR_LOOP);
ParserUtil.checkType(tokens.consume(), Token.Type.GROUP_BEGIN);
return switch(identifier.getType()) {
case FOR_LOOP -> parseForLoop(tokens, identifier.getPosition(), scopeBuilder);
case IF_STATEMENT -> parseIfStatement(tokens, identifier.getPosition(), loop, scopeBuilder);
case WHILE_LOOP -> parseWhileLoop(tokens, identifier.getPosition(), scopeBuilder);
default -> throw new UnsupportedOperationException(
"Unknown keyword " + identifier.getContent() + ": " + identifier.getPosition());
};
}
private WhileKeyword parseWhileLoop(Tokenizer tokens, SourcePosition start, ScopeBuilder scopeBuilder) {
Expression<?> first = parseExpression(tokens, true, scopeBuilder);
ParserUtil.checkReturnType(first, Expression.ReturnType.BOOLEAN); ParserUtil.checkReturnType(first, Expression.ReturnType.BOOLEAN);
ParserUtil.checkType(tokens.consume(), Token.Type.GROUP_END); ParserUtil.ensureType(tokenizer.consume(), Token.Type.GROUP_END);
return new WhileKeyword(parseStatementBlock(tokens, true, scopeBuilder), (Expression<Boolean>) first, start); // While loop return new WhileKeyword(parseStatementBlock(tokenizer, true, scopeBuilder), (Expression<Boolean>) first, start); // While loop
} }
private IfKeyword parseIfStatement(Tokenizer tokens, SourcePosition start, boolean loop, ScopeBuilder scopeBuilder) { private IfKeyword parseIfStatement(Tokenizer tokenizer, SourcePosition start, boolean controlStructure, ScopeBuilder scopeBuilder) {
Expression<?> condition = parseExpression(tokens, true, scopeBuilder); Expression<?> condition = parseLogicMathExpression(tokenizer, true, scopeBuilder);
ParserUtil.checkReturnType(condition, Expression.ReturnType.BOOLEAN); ParserUtil.checkReturnType(condition, Expression.ReturnType.BOOLEAN);
ParserUtil.checkType(tokens.consume(), Token.Type.GROUP_END); ParserUtil.ensureType(tokenizer.consume(), Token.Type.GROUP_END);
Block elseBlock = null; Block elseBlock = null;
Block statement = parseStatementBlock(tokens, loop, scopeBuilder); Block statement = parseStatementBlock(tokenizer, controlStructure, scopeBuilder);
List<Pair<Expression<Boolean>, Block>> elseIf = new ArrayList<>(); List<Pair<Expression<Boolean>, Block>> elseIf = new ArrayList<>();
while(tokens.hasNext() && tokens.current().getType().equals(Token.Type.ELSE)) { while(tokenizer.hasNext() && tokenizer.current().isType(Token.Type.ELSE)) {
tokens.consume(); // Consume else. tokenizer.consume(); // Consume else.
if(tokens.current().getType().equals(Token.Type.IF_STATEMENT)) { if(tokenizer.current().isType(Token.Type.IF_STATEMENT)) {
tokens.consume(); // Consume if. tokenizer.consume(); // Consume if.
Expression<?> elseCondition = parseExpression(tokens, true, scopeBuilder); Expression<?> elseCondition = parseLogicMathExpression(tokenizer, true, scopeBuilder);
ParserUtil.checkReturnType(elseCondition, Expression.ReturnType.BOOLEAN); ParserUtil.checkReturnType(elseCondition, Expression.ReturnType.BOOLEAN);
elseIf.add(Pair.of((Expression<Boolean>) elseCondition, parseStatementBlock(tokens, loop, scopeBuilder))); elseIf.add(Pair.of((Expression<Boolean>) elseCondition, parseStatementBlock(tokenizer, controlStructure, scopeBuilder)));
} else { } else {
elseBlock = parseStatementBlock(tokens, loop, scopeBuilder); elseBlock = parseStatementBlock(tokenizer, controlStructure, scopeBuilder);
break; // Else must be last. break; // Else must be last.
} }
} }
@@ -148,75 +130,75 @@ public class Parser {
return new IfKeyword(statement, (Expression<Boolean>) condition, elseIf, elseBlock, start); // If statement return new IfKeyword(statement, (Expression<Boolean>) condition, elseIf, elseBlock, start); // If statement
} }
private Block parseStatementBlock(Tokenizer tokens, boolean loop, ScopeBuilder scopeBuilder) { private Block parseStatementBlock(Tokenizer tokenizer, boolean controlStructure, ScopeBuilder scopeBuilder) {
if(tokens.current().getType().equals(Token.Type.BLOCK_BEGIN)) { if(tokenizer.current().isType(Token.Type.BLOCK_BEGIN)) {
ParserUtil.checkType(tokens.consume(), Token.Type.BLOCK_BEGIN); ParserUtil.ensureType(tokenizer.consume(), Token.Type.BLOCK_BEGIN);
Block block = parseBlock(tokens, loop, scopeBuilder); Block block = parseBlock(tokenizer, controlStructure, scopeBuilder);
ParserUtil.checkType(tokens.consume(), Token.Type.BLOCK_END); ParserUtil.ensureType(tokenizer.consume(), Token.Type.BLOCK_END);
return block; return block;
} else { } else {
SourcePosition position = tokens.current().getPosition(); SourcePosition position = tokenizer.current().getPosition();
Block block = new Block(Collections.singletonList(parseStatement(tokens, loop, scopeBuilder)), position); Block block = new Block(Collections.singletonList(parseExpression(tokenizer, controlStructure, scopeBuilder)), position);
ParserUtil.checkType(tokens.consume(), Token.Type.STATEMENT_END); ParserUtil.ensureType(tokenizer.consume(), Token.Type.STATEMENT_END);
return block; return block;
} }
} }
private ForKeyword parseForLoop(Tokenizer tokens, SourcePosition start, ScopeBuilder scopeBuilder) { private ForKeyword parseForLoop(Tokenizer tokenizer, SourcePosition start, ScopeBuilder scopeBuilder) {
scopeBuilder = scopeBuilder.sub(); // new scope scopeBuilder = scopeBuilder.sub(); // new scope
Token f = tokens.current(); Token f = tokenizer.current();
ParserUtil.checkType(f, Token.Type.NUMBER_VARIABLE, Token.Type.STRING_VARIABLE, Token.Type.BOOLEAN_VARIABLE, Token.Type.IDENTIFIER); ParserUtil.ensureType(f, Token.Type.NUMBER_VARIABLE, Token.Type.STRING_VARIABLE, Token.Type.BOOLEAN_VARIABLE, Token.Type.IDENTIFIER);
Statement<?> initializer; Expression<?> initializer;
if(f.isVariableDeclaration()) { if(f.isVariableDeclaration()) {
VariableAssignmentNode<?> forVar = parseVariableDeclaration(tokens, scopeBuilder); VariableAssignmentNode<?> forVar = parseVariableDeclaration(tokenizer, scopeBuilder);
Token name = tokens.current(); Token name = tokenizer.current();
if(functions.containsKey(name.getContent()) || scopeBuilder.contains(name.getContent())) if(functions.containsKey(name.getContent()) || scopeBuilder.contains(name.getContent()))
throw new ParseException(name.getContent() + " is already defined in this scope", name.getPosition()); throw new ParseException(name.getContent() + " is already defined in this scope", name.getPosition());
initializer = forVar; initializer = forVar;
} else initializer = parseExpression(tokens, true, scopeBuilder); } else initializer = parseLogicMathExpression(tokenizer, true, scopeBuilder);
ParserUtil.checkType(tokens.consume(), Token.Type.STATEMENT_END); ParserUtil.ensureType(tokenizer.consume(), Token.Type.STATEMENT_END);
Expression<?> conditional = parseExpression(tokens, true, scopeBuilder); Expression<?> conditional = parseLogicMathExpression(tokenizer, true, scopeBuilder);
ParserUtil.checkReturnType(conditional, Expression.ReturnType.BOOLEAN); ParserUtil.checkReturnType(conditional, Expression.ReturnType.BOOLEAN);
ParserUtil.checkType(tokens.consume(), Token.Type.STATEMENT_END); ParserUtil.ensureType(tokenizer.consume(), Token.Type.STATEMENT_END);
Statement<?> incrementer; Expression<?> incrementer;
Token token = tokens.current(); Token token = tokenizer.current();
if(scopeBuilder.contains(token.getContent())) { // Assume variable assignment if(scopeBuilder.contains(token.getContent())) { // Assume variable assignment
incrementer = parseAssignment(tokens, scopeBuilder); incrementer = parseAssignment(tokenizer, scopeBuilder);
} else incrementer = parseFunction(tokens, true, scopeBuilder); } else incrementer = parseFunction(tokenizer, true, scopeBuilder);
ParserUtil.checkType(tokens.consume(), Token.Type.GROUP_END); ParserUtil.ensureType(tokenizer.consume(), Token.Type.GROUP_END);
return new ForKeyword(parseStatementBlock(tokens, true, scopeBuilder), initializer, (Expression<Boolean>) conditional, incrementer, return new ForKeyword(parseStatementBlock(tokenizer, true, scopeBuilder), initializer, (Expression<Boolean>) conditional, incrementer,
start); start);
} }
private Expression<?> parseExpression(Tokenizer tokens, boolean full, ScopeBuilder scopeBuilder) { private Expression<?> parseLogicMathExpression(Tokenizer tokenizer, boolean full, ScopeBuilder scopeBuilder) {
boolean booleanInverted = false; // Check for boolean not operator boolean booleanInverted = false; // Check for boolean not operator
boolean negate = false; boolean negate = false;
if(tokens.current().getType().equals(Token.Type.BOOLEAN_NOT)) { if(tokenizer.current().isType(Token.Type.BOOLEAN_NOT)) {
booleanInverted = true; booleanInverted = true;
tokens.consume(); tokenizer.consume();
} else if(tokens.current().getType().equals(Token.Type.SUBTRACTION_OPERATOR)) { } else if(tokenizer.current().isType(Token.Type.SUBTRACTION_OPERATOR)) {
negate = true; negate = true;
tokens.consume(); tokenizer.consume();
} }
Token id = tokens.current(); Token id = tokenizer.current();
ParserUtil.checkType(id, Token.Type.IDENTIFIER, Token.Type.BOOLEAN, Token.Type.STRING, Token.Type.NUMBER, Token.Type.GROUP_BEGIN); ParserUtil.ensureType(id, Token.Type.IDENTIFIER, Token.Type.BOOLEAN, Token.Type.STRING, Token.Type.NUMBER, Token.Type.GROUP_BEGIN);
Expression<?> expression; Expression<?> expression;
if(id.isConstant()) { if(id.isConstant()) {
expression = parseConstantExpression(tokens); expression = parseConstantExpression(tokenizer);
} else if(id.getType().equals(Token.Type.GROUP_BEGIN)) { // Parse grouped expression } else if(id.isType(Token.Type.GROUP_BEGIN)) { // Parse grouped expression
expression = parseGroup(tokens, scopeBuilder); expression = parseGroup(tokenizer, scopeBuilder);
} else { } else {
if(functions.containsKey(id.getContent())) if(functions.containsKey(id.getContent()))
expression = parseFunction(tokens, false, scopeBuilder); expression = parseFunction(tokenizer, false, scopeBuilder);
else if(scopeBuilder.contains(id.getContent())) { else if(scopeBuilder.contains(id.getContent())) {
ParserUtil.checkType(tokens.consume(), Token.Type.IDENTIFIER); ParserUtil.ensureType(tokenizer.consume(), Token.Type.IDENTIFIER);
String varId = id.getContent(); String varId = id.getContent();
ReturnType varType = scopeBuilder.getType(varId); ReturnType varType = scopeBuilder.getType(varId);
expression = switch(varType) { expression = switch(varType) {
@@ -237,14 +219,14 @@ public class Parser {
expression = new NegationOperation((Expression<Number>) expression, expression.getPosition()); expression = new NegationOperation((Expression<Number>) expression, expression.getPosition());
} }
if(full && tokens.current().isBinaryOperator()) { // Parse binary operations if(full && tokenizer.current().isBinaryOperator()) { // Parse binary operations
return parseBinaryOperation(expression, tokens, scopeBuilder); return parseBinaryOperation(expression, tokenizer, scopeBuilder);
} }
return expression; return expression;
} }
private ConstantExpression<?> parseConstantExpression(Tokenizer tokens) { private ConstantExpression<?> parseConstantExpression(Tokenizer tokenizer) {
Token constantToken = tokens.consume(); Token constantToken = tokenizer.consume();
SourcePosition position = constantToken.getPosition(); SourcePosition position = constantToken.getPosition();
switch(constantToken.getType()) { switch(constantToken.getType()) {
case NUMBER: case NUMBER:
@@ -260,25 +242,25 @@ public class Parser {
} }
} }
private Expression<?> parseGroup(Tokenizer tokens, ScopeBuilder scopeBuilder) { private Expression<?> parseGroup(Tokenizer tokenizer, ScopeBuilder scopeBuilder) {
ParserUtil.checkType(tokens.consume(), Token.Type.GROUP_BEGIN); ParserUtil.ensureType(tokenizer.consume(), Token.Type.GROUP_BEGIN);
Expression<?> expression = parseExpression(tokens, true, scopeBuilder); // Parse inside of group as a separate expression Expression<?> expression = parseLogicMathExpression(tokenizer, true, scopeBuilder); // Parse inside of group as a separate expression
ParserUtil.checkType(tokens.consume(), Token.Type.GROUP_END); ParserUtil.ensureType(tokenizer.consume(), Token.Type.GROUP_END);
return expression; return expression;
} }
private BinaryOperation<?, ?> parseBinaryOperation(Expression<?> left, Tokenizer tokens, private BinaryOperation<?, ?> parseBinaryOperation(Expression<?> left, Tokenizer tokenizer,
ScopeBuilder scopeBuilder) { ScopeBuilder scopeBuilder) {
Token binaryOperator = tokens.consume(); Token binaryOperator = tokenizer.consume();
ParserUtil.checkBinaryOperator(binaryOperator); ParserUtil.checkBinaryOperator(binaryOperator);
Expression<?> right = parseExpression(tokens, false, scopeBuilder); Expression<?> right = parseLogicMathExpression(tokenizer, false, scopeBuilder);
Token other = tokens.current(); Token other = tokenizer.current();
if(ParserUtil.hasPrecedence(binaryOperator.getType(), other.getType())) { if(ParserUtil.hasPrecedence(binaryOperator.getType(), other.getType())) {
return assemble(left, parseBinaryOperation(right, tokens, scopeBuilder), binaryOperator); return assemble(left, parseBinaryOperation(right, tokenizer, scopeBuilder), binaryOperator);
} else if(other.isBinaryOperator()) { } else if(other.isBinaryOperator()) {
return parseBinaryOperation(assemble(left, right, binaryOperator), tokens, scopeBuilder); return parseBinaryOperation(assemble(left, right, binaryOperator), tokenizer, scopeBuilder);
} }
return assemble(left, right, binaryOperator); return assemble(left, right, binaryOperator);
} }
@@ -323,20 +305,20 @@ public class Parser {
} }
} }
private VariableAssignmentNode<?> parseVariableDeclaration(Tokenizer tokens, ScopeBuilder scopeBuilder) { private VariableAssignmentNode<?> parseVariableDeclaration(Tokenizer tokenizer, ScopeBuilder scopeBuilder) {
Token type = tokens.consume(); Token type = tokenizer.consume();
ParserUtil.checkType(type, Token.Type.STRING_VARIABLE, Token.Type.BOOLEAN_VARIABLE, Token.Type.NUMBER_VARIABLE); ParserUtil.ensureType(type, Token.Type.STRING_VARIABLE, Token.Type.BOOLEAN_VARIABLE, Token.Type.NUMBER_VARIABLE);
Expression.ReturnType returnType = ParserUtil.getVariableReturnType(type); Expression.ReturnType returnType = ParserUtil.getVariableReturnType(type);
ParserUtil.checkVarType(type, returnType); // Check for type mismatch ParserUtil.checkVarType(type, returnType); // Check for type mismatch
Token identifier = tokens.consume(); Token identifier = tokenizer.consume();
ParserUtil.checkType(identifier, Token.Type.IDENTIFIER); ParserUtil.ensureType(identifier, Token.Type.IDENTIFIER);
if(functions.containsKey(identifier.getContent()) || scopeBuilder.contains(identifier.getContent())) if(functions.containsKey(identifier.getContent()) || scopeBuilder.contains(identifier.getContent()))
throw new ParseException(identifier.getContent() + " is already defined in this scope", identifier.getPosition()); throw new ParseException(identifier.getContent() + " is already defined in this scope", identifier.getPosition());
ParserUtil.checkType(tokens.consume(), Token.Type.ASSIGNMENT); ParserUtil.ensureType(tokenizer.consume(), Token.Type.ASSIGNMENT);
Expression<?> value = parseExpression(tokens, true, scopeBuilder); Expression<?> value = parseLogicMathExpression(tokenizer, true, scopeBuilder);
ParserUtil.checkReturnType(value, returnType); ParserUtil.checkReturnType(value, returnType);
String id = identifier.getContent(); String id = identifier.getContent();
@@ -349,57 +331,67 @@ public class Parser {
}; };
} }
private Block parseBlock(Tokenizer tokens, boolean loop, ScopeBuilder scopeBuilder) { private Block parseBlock(Tokenizer tokenizer, boolean controlStructure, ScopeBuilder scopeBuilder) {
List<Statement<?>> statements = new ArrayList<>(); List<Expression<?>> expressions = new ArrayList<>();
scopeBuilder = scopeBuilder.sub(); scopeBuilder = scopeBuilder.sub();
Token first = tokens.current(); Token first = tokenizer.current();
while(tokens.hasNext()) { while(tokenizer.hasNext()) {
Token token = tokens.current(); Token token = tokenizer.current();
if(token.getType().equals(Token.Type.BLOCK_END)) break; // Stop parsing at block end. if(token.isType(Token.Type.BLOCK_END)) break; // Stop parsing at block end.
Statement<?> statement = parseStatement(tokens, loop, scopeBuilder); Expression<?> expression = parseExpression(tokenizer, controlStructure, scopeBuilder);
if(statement != Function.NULL) { if(expression != Function.NULL) {
statements.add(statement); expressions.add(expression);
} }
if(tokens.hasNext() && !token.isLoopLike()) ParserUtil.checkType(tokens.consume(), Token.Type.STATEMENT_END); if(tokenizer.hasNext() && !token.isControlStructure()) ParserUtil.ensureType(tokenizer.consume(), Token.Type.STATEMENT_END);
} }
return new Block(statements, first.getPosition()); return new Block(expressions, first.getPosition());
} }
private Statement<?> parseStatement(Tokenizer tokens, boolean loop, ScopeBuilder scopeBuilder) { private Expression<?> parseExpression(Tokenizer tokenizer, boolean controlStructure, ScopeBuilder scopeBuilder) {
Token token = tokens.current(); Token token = tokenizer.current();
if(loop) ParserUtil.checkType(token, Token.Type.IDENTIFIER, Token.Type.IF_STATEMENT, Token.Type.WHILE_LOOP, Token.Type.FOR_LOOP, if(controlStructure) ParserUtil.ensureType(token, Token.Type.IDENTIFIER, Token.Type.IF_STATEMENT, Token.Type.WHILE_LOOP, Token.Type.FOR_LOOP,
Token.Type.NUMBER_VARIABLE, Token.Type.STRING_VARIABLE, Token.Type.BOOLEAN_VARIABLE, Token.Type.NUMBER_VARIABLE, Token.Type.STRING_VARIABLE, Token.Type.BOOLEAN_VARIABLE,
Token.Type.RETURN, Token.Type.BREAK, Token.Type.CONTINUE, Token.Type.FAIL); Token.Type.RETURN, Token.Type.BREAK, Token.Type.CONTINUE, Token.Type.FAIL);
else ParserUtil.checkType(token, Token.Type.IDENTIFIER, Token.Type.IF_STATEMENT, Token.Type.WHILE_LOOP, Token.Type.FOR_LOOP, else ParserUtil.ensureType(token, Token.Type.IDENTIFIER, Token.Type.IF_STATEMENT, Token.Type.WHILE_LOOP, Token.Type.FOR_LOOP,
Token.Type.NUMBER_VARIABLE, Token.Type.STRING_VARIABLE, Token.Type.BOOLEAN_VARIABLE, Token.Type.RETURN, Token.Type.NUMBER_VARIABLE, Token.Type.STRING_VARIABLE, Token.Type.BOOLEAN_VARIABLE, Token.Type.RETURN,
Token.Type.FAIL); Token.Type.FAIL);
if(token.isLoopLike()) { // Parse loop-like tokens (if, while, etc) Expression<?> expression = switch(token.getType()) {
return parseLoopLike(tokens, loop, scopeBuilder); case FOR_LOOP, IF_STATEMENT, WHILE_LOOP -> {
} else if(token.isIdentifier()) { // Parse identifiers Token identifier = tokenizer.consume();
if(scopeBuilder.contains(token.getContent())) { // Assume variable assignment ParserUtil.ensureType(tokenizer.consume(), Token.Type.GROUP_BEGIN);
return parseAssignment(tokens, scopeBuilder); yield switch(identifier.getType()) {
} else return parseFunction(tokens, true, scopeBuilder); case FOR_LOOP -> parseForLoop(tokenizer, identifier.getPosition(), scopeBuilder);
} else if(token.isVariableDeclaration()) { case IF_STATEMENT -> parseIfStatement(tokenizer, identifier.getPosition(), controlStructure, scopeBuilder);
return parseVariableDeclaration(tokens, scopeBuilder); case WHILE_LOOP -> parseWhileLoop(tokenizer, identifier.getPosition(), scopeBuilder);
} else if(token.getType().equals(Token.Type.RETURN)) return new ReturnKeyword(tokens.consume().getPosition()); default -> throw new UnsupportedOperationException("Unknown keyword " + identifier.getContent() + ": " + identifier.getPosition());
else if(token.getType().equals(Token.Type.BREAK)) return new BreakKeyword(tokens.consume().getPosition()); };
else if(token.getType().equals(Token.Type.CONTINUE)) return new ContinueKeyword(tokens.consume().getPosition()); }
else if(token.getType().equals(Token.Type.FAIL)) return new FailKeyword(tokens.consume().getPosition()); case IDENTIFIER -> {
else throw new UnsupportedOperationException("Unexpected token " + token.getType() + ": " + token.getPosition()); if(scopeBuilder.contains(token.getContent())) yield parseAssignment(tokenizer, scopeBuilder); // Assume variable assignment
else yield parseFunction(tokenizer, true, scopeBuilder);
}
case NUMBER_VARIABLE, STRING_VARIABLE, BOOLEAN_VARIABLE -> parseVariableDeclaration(tokenizer, scopeBuilder);
case RETURN -> new ReturnKeyword(tokenizer.consume().getPosition());
case BREAK -> new BreakKeyword(tokenizer.consume().getPosition());
case CONTINUE -> new ContinueKeyword(tokenizer.consume().getPosition());
case FAIL -> new FailKeyword(tokenizer.consume().getPosition());
default -> throw new UnsupportedOperationException("Unexpected token " + token.getType() + ": " + token.getPosition());
};
return expression;
} }
private VariableAssignmentNode<?> parseAssignment(Tokenizer tokens, ScopeBuilder scopeBuilder) { private VariableAssignmentNode<?> parseAssignment(Tokenizer tokenizer, ScopeBuilder scopeBuilder) {
Token identifier = tokens.consume(); Token identifier = tokenizer.consume();
ParserUtil.checkType(identifier, Token.Type.IDENTIFIER); ParserUtil.ensureType(identifier, Token.Type.IDENTIFIER);
ParserUtil.checkType(tokens.consume(), Token.Type.ASSIGNMENT); ParserUtil.ensureType(tokenizer.consume(), Token.Type.ASSIGNMENT);
Expression<?> value = parseExpression(tokens, true, scopeBuilder); Expression<?> value = parseLogicMathExpression(tokenizer, true, scopeBuilder);
String id = identifier.getContent(); String id = identifier.getContent();
@@ -415,21 +407,20 @@ public class Parser {
}; };
} }
private Function<?> parseFunction(Tokenizer tokens, boolean fullStatement, ScopeBuilder scopeBuilder) { private Function<?> parseFunction(Tokenizer tokenizer, boolean fullStatement, ScopeBuilder scopeBuilder) {
Token identifier = tokens.consume(); Token identifier = tokenizer.consume();
ParserUtil.checkType(identifier, Token.Type.IDENTIFIER); // First token must be identifier ParserUtil.ensureType(identifier, Token.Type.IDENTIFIER); // First token must be identifier
if(!functions.containsKey(identifier.getContent())) if(!functions.containsKey(identifier.getContent()))
throw new ParseException("No such function \"" + identifier.getContent() + "\"", identifier.getPosition()); throw new ParseException("No such function \"" + identifier.getContent() + "\"", identifier.getPosition());
ParserUtil.checkType(tokens.consume(), Token.Type.GROUP_BEGIN); // Second is body begin ParserUtil.ensureType(tokenizer.consume(), Token.Type.GROUP_BEGIN); // Second is body begin
List<Expression<?>> args = getFunctionArgs(tokenizer, scopeBuilder); // Extract arguments, consume the rest.
List<Expression<?>> args = getArgs(tokens, scopeBuilder); // Extract arguments, consume the rest. ParserUtil.ensureType(tokenizer.consume(), Token.Type.GROUP_END); // Remove body end
ParserUtil.checkType(tokens.consume(), Token.Type.GROUP_END); // Remove body end if(fullStatement) ParserUtil.ensureType(tokenizer.current(), Token.Type.STATEMENT_END);
if(fullStatement) ParserUtil.checkType(tokens.current(), Token.Type.STATEMENT_END);
if(ignoredFunctions.contains(identifier.getContent())) { if(ignoredFunctions.contains(identifier.getContent())) {
return Function.NULL; return Function.NULL;
@@ -453,13 +444,13 @@ public class Parser {
throw new UnsupportedOperationException("Unsupported function: " + identifier.getContent()); throw new UnsupportedOperationException("Unsupported function: " + identifier.getContent());
} }
private List<Expression<?>> getArgs(Tokenizer tokens, ScopeBuilder scopeBuilder) { private List<Expression<?>> getFunctionArgs(Tokenizer tokenizer, ScopeBuilder scopeBuilder) {
List<Expression<?>> args = new ArrayList<>(); List<Expression<?>> args = new ArrayList<>();
while(!tokens.current().getType().equals(Token.Type.GROUP_END)) { while(!tokenizer.current().isType(Token.Type.GROUP_END)) {
args.add(parseExpression(tokens, true, scopeBuilder)); args.add(parseLogicMathExpression(tokenizer, true, scopeBuilder));
ParserUtil.checkType(tokens.current(), Token.Type.SEPARATOR, Token.Type.GROUP_END); ParserUtil.ensureType(tokenizer.current(), Token.Type.SEPARATOR, Token.Type.GROUP_END);
if(tokens.current().getType().equals(Token.Type.SEPARATOR)) tokens.consume(); if(tokenizer.current().isType(Token.Type.SEPARATOR)) tokenizer.consume();
} }
return args; return args;
} }
@@ -51,7 +51,7 @@ public class ParserUtil {
PRECEDENCE.put(Token.Type.BOOLEAN_OR, booleanOps); PRECEDENCE.put(Token.Type.BOOLEAN_OR, booleanOps);
} }
public static void checkType(Token token, Token.Type... expected) { public static void ensureType(Token token, Token.Type... expected) {
for(Token.Type type : expected) if(token.getType().equals(type)) return; for(Token.Type type : expected) if(token.getType().equals(type)) return;
throw new ParseException("Expected " + Arrays.toString(expected) + " but found " + token.getType(), token.getPosition()); throw new ParseException("Expected " + Arrays.toString(expected) + " but found " + token.getType(), token.getPosition());
} }
@@ -13,19 +13,24 @@ import com.dfsek.terra.addons.terrascript.parser.lang.Block.ReturnInfo;
import com.dfsek.terra.addons.terrascript.tokenizer.SourcePosition; import com.dfsek.terra.addons.terrascript.tokenizer.SourcePosition;
public class Block implements Statement<ReturnInfo<?>> { public class Block implements Expression<ReturnInfo<?>> {
private final List<Statement<?>> items; private final List<Expression<?>> items;
private final SourcePosition position; private final SourcePosition position;
public Block(List<Statement<?>> items, SourcePosition position) { public Block(List<Expression<?>> items, SourcePosition position) {
this.items = items; this.items = items;
this.position = position; this.position = position;
} }
@Override @Override
public ReturnInfo<?> invoke(ImplementationArguments implementationArguments, Scope scope) { public ReturnType returnType() {
for(Statement<?> item : items) { return ReturnType.VOID;
Object result = item.invoke(implementationArguments, scope); }
@Override
public ReturnInfo<?> evaluate(ImplementationArguments implementationArguments, Scope scope) {
for(Expression<?> item : items) {
Object result = item.evaluate(implementationArguments, scope);
if(result instanceof ReturnInfo<?> level) { if(result instanceof ReturnInfo<?> level) {
if(!level.getLevel().equals(ReturnLevel.NONE)) return level; if(!level.getLevel().equals(ReturnLevel.NONE)) return level;
} }
@@ -14,6 +14,6 @@ public class Executable {
} }
public boolean execute(ImplementationArguments arguments) { public boolean execute(ImplementationArguments arguments) {
return script.invoke(arguments, scope.get()).getLevel() != Block.ReturnLevel.FAIL; return script.evaluate(arguments, scope.get()).getLevel() != Block.ReturnLevel.FAIL;
} }
} }
@@ -7,9 +7,24 @@
package com.dfsek.terra.addons.terrascript.parser.lang; package com.dfsek.terra.addons.terrascript.parser.lang;
public interface Expression<T> extends Statement<T> { import com.dfsek.terra.addons.terrascript.tokenizer.SourcePosition;
public interface Expression<T> {
ReturnType returnType(); ReturnType returnType();
T evaluate(ImplementationArguments implementationArguments, Scope scope);
default double applyDouble(ImplementationArguments implementationArguments, Scope scope) {
throw new UnsupportedOperationException("Cannot apply " + this + " as double");
}
default boolean applyBoolean(ImplementationArguments implementationArguments, Scope scope) {
throw new UnsupportedOperationException("Cannot apply " + this + " as double");
}
SourcePosition getPosition();
enum ReturnType { enum ReturnType {
NUMBER(true), NUMBER(true),
STRING(true), STRING(true),
@@ -7,19 +7,9 @@
package com.dfsek.terra.addons.terrascript.parser.lang; package com.dfsek.terra.addons.terrascript.parser.lang;
import com.dfsek.terra.addons.terrascript.tokenizer.SourcePosition; public interface Statement extends Expression<Void> {
@Override
default ReturnType returnType() {
public interface Statement<T> { return ReturnType.VOID;
T invoke(ImplementationArguments implementationArguments, Scope scope);
default double applyDouble(ImplementationArguments implementationArguments, Scope scope) {
throw new UnsupportedOperationException("Cannot apply " + this + " as double");
} }
default boolean applyBoolean(ImplementationArguments implementationArguments, Scope scope) {
throw new UnsupportedOperationException("Cannot apply " + this + " as double");
}
SourcePosition getPosition();
} }
@@ -23,7 +23,7 @@ public abstract class ConstantExpression<T> implements Expression<T> {
} }
@Override @Override
public T invoke(ImplementationArguments implementationArguments, Scope scope) { public T evaluate(ImplementationArguments implementationArguments, Scope scope) {
return constant; return constant;
} }
@@ -21,7 +21,7 @@ public interface Function<T> extends Expression<T> {
} }
@Override @Override
public Object invoke(ImplementationArguments implementationArguments, Scope scope) { public Object evaluate(ImplementationArguments implementationArguments, Scope scope) {
return null; return null;
} }
@@ -33,11 +33,11 @@ public interface Function<T> extends Expression<T> {
@Override @Override
default double applyDouble(ImplementationArguments implementationArguments, Scope scope) { default double applyDouble(ImplementationArguments implementationArguments, Scope scope) {
return ((Number) invoke(implementationArguments, scope)).doubleValue(); return ((Number) evaluate(implementationArguments, scope)).doubleValue();
} }
@Override @Override
default boolean applyBoolean(ImplementationArguments implementationArguments, Scope scope) { default boolean applyBoolean(ImplementationArguments implementationArguments, Scope scope) {
return (Boolean) invoke(implementationArguments, scope); return (Boolean) evaluate(implementationArguments, scope);
} }
} }
@@ -22,7 +22,7 @@ public class BreakKeyword implements Keyword<Block.ReturnInfo<?>> {
} }
@Override @Override
public Block.ReturnInfo<?> invoke(ImplementationArguments implementationArguments, Scope scope) { public Block.ReturnInfo<?> evaluate(ImplementationArguments implementationArguments, Scope scope) {
return new Block.ReturnInfo<>(Block.ReturnLevel.BREAK, null); return new Block.ReturnInfo<>(Block.ReturnLevel.BREAK, null);
} }
@@ -22,7 +22,7 @@ public class ContinueKeyword implements Keyword<Block.ReturnInfo<?>> {
} }
@Override @Override
public Block.ReturnInfo<?> invoke(ImplementationArguments implementationArguments, Scope scope) { public Block.ReturnInfo<?> evaluate(ImplementationArguments implementationArguments, Scope scope) {
return new Block.ReturnInfo<>(Block.ReturnLevel.CONTINUE, null); return new Block.ReturnInfo<>(Block.ReturnLevel.CONTINUE, null);
} }
@@ -22,7 +22,7 @@ public class FailKeyword implements Keyword<Block.ReturnInfo<?>> {
} }
@Override @Override
public Block.ReturnInfo<?> invoke(ImplementationArguments implementationArguments, Scope scope) { public Block.ReturnInfo<?> evaluate(ImplementationArguments implementationArguments, Scope scope) {
return new Block.ReturnInfo<>(Block.ReturnLevel.FAIL, null); return new Block.ReturnInfo<>(Block.ReturnLevel.FAIL, null);
} }
@@ -22,7 +22,7 @@ public class ReturnKeyword implements Keyword<Block.ReturnInfo<?>> {
} }
@Override @Override
public Block.ReturnInfo<?> invoke(ImplementationArguments implementationArguments, Scope scope) { public Block.ReturnInfo<?> evaluate(ImplementationArguments implementationArguments, Scope scope) {
return new Block.ReturnInfo<>(Block.ReturnLevel.RETURN, null); return new Block.ReturnInfo<>(Block.ReturnLevel.RETURN, null);
} }
@@ -18,12 +18,12 @@ import com.dfsek.terra.addons.terrascript.tokenizer.SourcePosition;
public class ForKeyword implements Keyword<Block.ReturnInfo<?>> { public class ForKeyword implements Keyword<Block.ReturnInfo<?>> {
private final Block conditional; private final Block conditional;
private final Statement<?> initializer; private final Expression<?> initializer;
private final Expression<Boolean> statement; private final Expression<Boolean> statement;
private final Statement<?> incrementer; private final Expression<?> incrementer;
private final SourcePosition position; private final SourcePosition position;
public ForKeyword(Block conditional, Statement<?> initializer, Expression<Boolean> statement, Statement<?> incrementer, SourcePosition position) { public ForKeyword(Block conditional, Expression<?> initializer, Expression<Boolean> statement, Expression<?> incrementer, SourcePosition position) {
this.conditional = conditional; this.conditional = conditional;
this.initializer = initializer; this.initializer = initializer;
this.statement = statement; this.statement = statement;
@@ -32,11 +32,11 @@ public class ForKeyword implements Keyword<Block.ReturnInfo<?>> {
} }
@Override @Override
public Block.ReturnInfo<?> invoke(ImplementationArguments implementationArguments, Scope scope) { public Block.ReturnInfo<?> evaluate(ImplementationArguments implementationArguments, Scope scope) {
for(initializer.invoke(implementationArguments, scope); for(initializer.evaluate(implementationArguments, scope);
statement.invoke(implementationArguments, scope); statement.evaluate(implementationArguments, scope);
incrementer.invoke(implementationArguments, scope)) { incrementer.evaluate(implementationArguments, scope)) {
Block.ReturnInfo<?> level = conditional.invoke(implementationArguments, scope); Block.ReturnInfo<?> level = conditional.evaluate(implementationArguments, scope);
if(level.getLevel().equals(Block.ReturnLevel.BREAK)) break; if(level.getLevel().equals(Block.ReturnLevel.BREAK)) break;
if(level.getLevel().isReturnFast()) return level; if(level.getLevel().isReturnFast()) return level;
} }
@@ -37,15 +37,15 @@ public class IfKeyword implements Keyword<Block.ReturnInfo<?>> {
} }
@Override @Override
public Block.ReturnInfo<?> invoke(ImplementationArguments implementationArguments, Scope scope) { public Block.ReturnInfo<?> evaluate(ImplementationArguments implementationArguments, Scope scope) {
if(statement.invoke(implementationArguments, scope)) return conditional.invoke(implementationArguments, scope); if(statement.evaluate(implementationArguments, scope)) return conditional.evaluate(implementationArguments, scope);
else { else {
for(Pair<Expression<Boolean>, Block> pair : elseIf) { for(Pair<Expression<Boolean>, Block> pair : elseIf) {
if(pair.getLeft().invoke(implementationArguments, scope)) { if(pair.getLeft().evaluate(implementationArguments, scope)) {
return pair.getRight().invoke(implementationArguments, scope); return pair.getRight().evaluate(implementationArguments, scope);
} }
} }
if(elseBlock != null) return elseBlock.invoke(implementationArguments, scope); if(elseBlock != null) return elseBlock.evaluate(implementationArguments, scope);
} }
return new Block.ReturnInfo<>(Block.ReturnLevel.NONE, null); return new Block.ReturnInfo<>(Block.ReturnLevel.NONE, null);
} }
@@ -27,9 +27,9 @@ public class WhileKeyword implements Keyword<Block.ReturnInfo<?>> {
} }
@Override @Override
public Block.ReturnInfo<?> invoke(ImplementationArguments implementationArguments, Scope scope) { public Block.ReturnInfo<?> evaluate(ImplementationArguments implementationArguments, Scope scope) {
while(statement.invoke(implementationArguments, scope)) { while(statement.evaluate(implementationArguments, scope)) {
Block.ReturnInfo<?> level = conditional.invoke(implementationArguments, scope); Block.ReturnInfo<?> level = conditional.evaluate(implementationArguments, scope);
if(level.getLevel().equals(Block.ReturnLevel.BREAK)) break; if(level.getLevel().equals(Block.ReturnLevel.BREAK)) break;
if(level.getLevel().isReturnFast()) return level; if(level.getLevel().isReturnFast()) return level;
} }
@@ -24,7 +24,7 @@ public class BooleanAndOperation extends BinaryOperation<Boolean, Boolean> {
} }
@Override @Override
public Boolean invoke(ImplementationArguments implementationArguments, Scope scope) { public Boolean evaluate(ImplementationArguments implementationArguments, Scope scope) {
return applyBoolean(implementationArguments, scope); return applyBoolean(implementationArguments, scope);
} }
@@ -19,7 +19,7 @@ public class BooleanNotOperation extends UnaryOperation<Boolean> {
} }
@Override @Override
public Boolean invoke(ImplementationArguments implementationArguments, Scope scope) { public Boolean evaluate(ImplementationArguments implementationArguments, Scope scope) {
return applyBoolean(implementationArguments, scope); return applyBoolean(implementationArguments, scope);
} }
@@ -19,7 +19,7 @@ public class BooleanOrOperation extends BinaryOperation<Boolean, Boolean> {
} }
@Override @Override
public Boolean invoke(ImplementationArguments implementationArguments, Scope scope) { public Boolean evaluate(ImplementationArguments implementationArguments, Scope scope) {
return applyBoolean(implementationArguments, scope); return applyBoolean(implementationArguments, scope);
} }
@@ -35,7 +35,7 @@ public class ConcatenationOperation extends BinaryOperation<Object, Object> {
} }
@Override @Override
public Object invoke(ImplementationArguments implementationArguments, Scope scope) { public Object evaluate(ImplementationArguments implementationArguments, Scope scope) {
return toString(left.invoke(implementationArguments, scope)) + toString(right.invoke(implementationArguments, scope)); return toString(left.evaluate(implementationArguments, scope)) + toString(right.evaluate(implementationArguments, scope));
} }
} }
@@ -24,7 +24,7 @@ public class DivisionOperation extends BinaryOperation<Number, Number> {
} }
@Override @Override
public Number invoke(ImplementationArguments implementationArguments, Scope scope) { public Number evaluate(ImplementationArguments implementationArguments, Scope scope) {
return applyDouble(implementationArguments, scope); return applyDouble(implementationArguments, scope);
} }
@@ -19,7 +19,7 @@ public class ModuloOperation extends BinaryOperation<Number, Number> {
} }
@Override @Override
public Number invoke(ImplementationArguments implementationArguments, Scope scope) { public Number evaluate(ImplementationArguments implementationArguments, Scope scope) {
return applyDouble(implementationArguments, scope); return applyDouble(implementationArguments, scope);
} }
@@ -19,7 +19,7 @@ public class MultiplicationOperation extends BinaryOperation<Number, Number> {
} }
@Override @Override
public Number invoke(ImplementationArguments implementationArguments, Scope scope) { public Number evaluate(ImplementationArguments implementationArguments, Scope scope) {
return applyDouble(implementationArguments, scope); return applyDouble(implementationArguments, scope);
} }
@@ -24,7 +24,7 @@ public class NegationOperation extends UnaryOperation<Number> {
} }
@Override @Override
public Number invoke(ImplementationArguments implementationArguments, Scope scope) { public Number evaluate(ImplementationArguments implementationArguments, Scope scope) {
return applyDouble(implementationArguments, scope); return applyDouble(implementationArguments, scope);
} }
@@ -19,7 +19,7 @@ public class NumberAdditionOperation extends BinaryOperation<Number, Number> {
} }
@Override @Override
public Number invoke(ImplementationArguments implementationArguments, Scope scope) { public Number evaluate(ImplementationArguments implementationArguments, Scope scope) {
return applyDouble(implementationArguments, scope); return applyDouble(implementationArguments, scope);
} }
@@ -19,7 +19,7 @@ public class SubtractionOperation extends BinaryOperation<Number, Number> {
} }
@Override @Override
public Number invoke(ImplementationArguments implementationArguments, Scope scope) { public Number evaluate(ImplementationArguments implementationArguments, Scope scope) {
return applyDouble(implementationArguments, scope); return applyDouble(implementationArguments, scope);
} }
@@ -31,14 +31,14 @@ public class EqualsStatement extends BinaryOperation<Object, Boolean> {
} }
@Override @Override
public Boolean invoke(ImplementationArguments implementationArguments, Scope scope) { public Boolean evaluate(ImplementationArguments implementationArguments, Scope scope) {
return applyBoolean(implementationArguments, scope); return applyBoolean(implementationArguments, scope);
} }
@Override @Override
public boolean applyBoolean(ImplementationArguments implementationArguments, Scope scope) { public boolean applyBoolean(ImplementationArguments implementationArguments, Scope scope) {
Object leftValue = left.invoke(implementationArguments, scope); Object leftValue = left.evaluate(implementationArguments, scope);
Object rightValue = right.invoke(implementationArguments, scope); Object rightValue = right.evaluate(implementationArguments, scope);
if(leftValue instanceof Number l && rightValue instanceof Number r) { if(leftValue instanceof Number l && rightValue instanceof Number r) {
return FastMath.abs(l.doubleValue() - r.doubleValue()) <= EPSILON; return FastMath.abs(l.doubleValue() - r.doubleValue()) <= EPSILON;
} }
@@ -25,7 +25,7 @@ public class GreaterOrEqualsThanStatement extends BinaryOperation<Number, Boolea
} }
@Override @Override
public Boolean invoke(ImplementationArguments implementationArguments, Scope scope) { public Boolean evaluate(ImplementationArguments implementationArguments, Scope scope) {
return applyBoolean(implementationArguments, scope); return applyBoolean(implementationArguments, scope);
} }
@@ -21,7 +21,7 @@ public class GreaterThanStatement extends BinaryOperation<Number, Boolean> {
@Override @Override
public Boolean invoke(ImplementationArguments implementationArguments, Scope scope) { public Boolean evaluate(ImplementationArguments implementationArguments, Scope scope) {
return applyBoolean(implementationArguments, scope); return applyBoolean(implementationArguments, scope);
} }
@@ -21,7 +21,7 @@ public class LessThanOrEqualsStatement extends BinaryOperation<Number, Boolean>
@Override @Override
public Boolean invoke(ImplementationArguments implementationArguments, Scope scope) { public Boolean evaluate(ImplementationArguments implementationArguments, Scope scope) {
return applyBoolean(implementationArguments, scope); return applyBoolean(implementationArguments, scope);
} }
@@ -21,7 +21,7 @@ public class LessThanStatement extends BinaryOperation<Number, Boolean> {
@Override @Override
public Boolean invoke(ImplementationArguments implementationArguments, Scope scope) { public Boolean evaluate(ImplementationArguments implementationArguments, Scope scope) {
return applyBoolean(implementationArguments, scope); return applyBoolean(implementationArguments, scope);
} }
@@ -24,14 +24,14 @@ public class NotEqualsStatement extends BinaryOperation<Object, Boolean> {
} }
@Override @Override
public Boolean invoke(ImplementationArguments implementationArguments, Scope scope) { public Boolean evaluate(ImplementationArguments implementationArguments, Scope scope) {
return applyBoolean(implementationArguments, scope); return applyBoolean(implementationArguments, scope);
} }
@Override @Override
public boolean applyBoolean(ImplementationArguments implementationArguments, Scope scope) { public boolean applyBoolean(ImplementationArguments implementationArguments, Scope scope) {
Object leftValue = left.invoke(implementationArguments, scope); Object leftValue = left.evaluate(implementationArguments, scope);
Object rightValue = right.invoke(implementationArguments, scope); Object rightValue = right.evaluate(implementationArguments, scope);
if(leftValue instanceof Number l && rightValue instanceof Number r) { if(leftValue instanceof Number l && rightValue instanceof Number r) {
return FastMath.abs(l.doubleValue() - r.doubleValue()) > EPSILON; return FastMath.abs(l.doubleValue() - r.doubleValue()) > EPSILON;
} }
@@ -12,7 +12,12 @@ public class BoolAssignmentNode extends VariableAssignmentNode<Boolean> {
} }
@Override @Override
public Boolean invoke(ImplementationArguments implementationArguments, Scope scope) { public ReturnType returnType() {
return ReturnType.BOOLEAN;
}
@Override
public Boolean evaluate(ImplementationArguments implementationArguments, Scope scope) {
return applyBoolean(implementationArguments, scope); return applyBoolean(implementationArguments, scope);
} }
@@ -12,7 +12,12 @@ public class NumAssignmentNode extends VariableAssignmentNode<Number> {
} }
@Override @Override
public Number invoke(ImplementationArguments implementationArguments, Scope scope) { public ReturnType returnType() {
return ReturnType.NUMBER;
}
@Override
public Number evaluate(ImplementationArguments implementationArguments, Scope scope) {
return applyDouble(implementationArguments, scope); return applyDouble(implementationArguments, scope);
} }
@@ -12,8 +12,13 @@ public class StrAssignmentNode extends VariableAssignmentNode<String> {
} }
@Override @Override
public String invoke(ImplementationArguments implementationArguments, Scope scope) { public ReturnType returnType() {
String val = value.invoke(implementationArguments, scope); return ReturnType.STRING;
}
@Override
public String evaluate(ImplementationArguments implementationArguments, Scope scope) {
String val = value.evaluate(implementationArguments, scope);
scope.setStr(index, val); scope.setStr(index, val);
return val; return val;
} }
@@ -12,7 +12,7 @@ import com.dfsek.terra.addons.terrascript.parser.lang.Expression;
import com.dfsek.terra.addons.terrascript.tokenizer.SourcePosition; import com.dfsek.terra.addons.terrascript.tokenizer.SourcePosition;
public abstract class VariableAssignmentNode<T> implements Statement<T> { public abstract class VariableAssignmentNode<T> implements Expression<T> {
protected final Expression<T> value; protected final Expression<T> value;
protected final int index; protected final int index;
private final SourcePosition position; private final SourcePosition position;
@@ -11,7 +11,7 @@ public class BoolVariableReferenceNode extends VariableReferenceNode<Boolean> {
} }
@Override @Override
public Boolean invoke(ImplementationArguments implementationArguments, Scope scope) { public Boolean evaluate(ImplementationArguments implementationArguments, Scope scope) {
return scope.getBool(index); return scope.getBool(index);
} }
@@ -11,7 +11,7 @@ public class NumVariableReferenceNode extends VariableReferenceNode<Number> {
} }
@Override @Override
public Number invoke(ImplementationArguments implementationArguments, Scope scope) { public Number evaluate(ImplementationArguments implementationArguments, Scope scope) {
return scope.getNum(index); return scope.getNum(index);
} }
@@ -11,7 +11,7 @@ public class StrVariableReferenceNode extends VariableReferenceNode<String> {
} }
@Override @Override
public String invoke(ImplementationArguments implementationArguments, Scope scope) { public String evaluate(ImplementationArguments implementationArguments, Scope scope) {
return scope.getStr(index); return scope.getStr(index);
} }
} }
@@ -36,9 +36,9 @@ public class BinaryNumberFunctionBuilder implements FunctionBuilder<Function<Num
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@Override @Override
public Number invoke(ImplementationArguments implementationArguments, Scope scope) { public Number evaluate(ImplementationArguments implementationArguments, Scope scope) {
return function.apply(((Expression<Number>) argumentList.get(0)).invoke(implementationArguments, scope), return function.apply(((Expression<Number>) argumentList.get(0)).evaluate(implementationArguments, scope),
((Expression<Number>) argumentList.get(1)).invoke(implementationArguments, scope)); ((Expression<Number>) argumentList.get(1)).evaluate(implementationArguments, scope));
} }
@Override @Override
@@ -37,8 +37,8 @@ public class UnaryBooleanFunctionBuilder implements FunctionBuilder<Function<Voi
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@Override @Override
public Void invoke(ImplementationArguments implementationArguments, Scope scope) { public Void evaluate(ImplementationArguments implementationArguments, Scope scope) {
function.accept(((Expression<Boolean>) argumentList.get(0)).invoke(implementationArguments, scope), function.accept(((Expression<Boolean>) argumentList.get(0)).evaluate(implementationArguments, scope),
(TerraImplementationArguments) implementationArguments); (TerraImplementationArguments) implementationArguments);
return null; return null;
} }
@@ -35,8 +35,8 @@ public class UnaryNumberFunctionBuilder implements FunctionBuilder<Function<Numb
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@Override @Override
public Number invoke(ImplementationArguments implementationArguments, Scope scope) { public Number evaluate(ImplementationArguments implementationArguments, Scope scope) {
return function.apply(((Expression<Number>) argumentList.get(0)).invoke(implementationArguments, scope)); return function.apply(((Expression<Number>) argumentList.get(0)).evaluate(implementationArguments, scope));
} }
@Override @Override
@@ -35,8 +35,8 @@ public class UnaryStringFunctionBuilder implements FunctionBuilder<Function<Void
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@Override @Override
public Void invoke(ImplementationArguments implementationArguments, Scope scope) { public Void evaluate(ImplementationArguments implementationArguments, Scope scope) {
function.accept(((Expression<String>) argumentList.get(0)).invoke(implementationArguments, scope)); function.accept(((Expression<String>) argumentList.get(0)).evaluate(implementationArguments, scope));
return null; return null;
} }
@@ -36,7 +36,7 @@ public class ZeroArgFunctionBuilder<T> implements FunctionBuilder<Function<T>> {
} }
@Override @Override
public T invoke(ImplementationArguments implementationArguments, Scope scope) { public T evaluate(ImplementationArguments implementationArguments, Scope scope) {
return function.apply((TerraImplementationArguments) implementationArguments); return function.apply((TerraImplementationArguments) implementationArguments);
} }
@@ -35,11 +35,11 @@ public class BiomeFunction implements Function<String> {
@Override @Override
public String invoke(ImplementationArguments implementationArguments, Scope scope) { public String evaluate(ImplementationArguments implementationArguments, Scope scope) {
TerraImplementationArguments arguments = (TerraImplementationArguments) implementationArguments; TerraImplementationArguments arguments = (TerraImplementationArguments) implementationArguments;
Vector2 xz = RotationUtil.rotateVector(Vector2.of(x.invoke(implementationArguments, scope).doubleValue(), Vector2 xz = RotationUtil.rotateVector(Vector2.of(x.evaluate(implementationArguments, scope).doubleValue(),
z.invoke(implementationArguments, scope).doubleValue()), z.evaluate(implementationArguments, scope).doubleValue()),
arguments.getRotation()); arguments.getRotation());
@@ -49,7 +49,7 @@ public class BiomeFunction implements Function<String> {
.toVector3() .toVector3()
.mutable() .mutable()
.add(Vector3.of(FastMath.roundToInt(xz.getX()), .add(Vector3.of(FastMath.roundToInt(xz.getX()),
y.invoke(implementationArguments, scope).intValue(), y.evaluate(implementationArguments, scope).intValue(),
FastMath.roundToInt(xz.getZ()))).immutable(), arguments.getWorld().getSeed()).getID(); FastMath.roundToInt(xz.getZ()))).immutable(), arguments.getWorld().getSeed()).getID();
} }
@@ -49,7 +49,7 @@ public class BlockFunction implements Function<Void> {
} }
@Override @Override
public Void invoke(ImplementationArguments implementationArguments, Scope scope) { public Void evaluate(ImplementationArguments implementationArguments, Scope scope) {
TerraImplementationArguments arguments = (TerraImplementationArguments) implementationArguments; TerraImplementationArguments arguments = (TerraImplementationArguments) implementationArguments;
BlockState rot = getBlockState(implementationArguments, scope); BlockState rot = getBlockState(implementationArguments, scope);
setBlock(implementationArguments, scope, arguments, rot); setBlock(implementationArguments, scope, arguments, rot);
@@ -68,14 +68,14 @@ public class BlockFunction implements Function<Void> {
void setBlock(ImplementationArguments implementationArguments, Scope scope, void setBlock(ImplementationArguments implementationArguments, Scope scope,
TerraImplementationArguments arguments, BlockState rot) { TerraImplementationArguments arguments, BlockState rot) {
Vector2 xz = RotationUtil.rotateVector(Vector2.of(x.invoke(implementationArguments, scope).doubleValue(), Vector2 xz = RotationUtil.rotateVector(Vector2.of(x.evaluate(implementationArguments, scope).doubleValue(),
z.invoke(implementationArguments, scope).doubleValue()), arguments.getRotation()); z.evaluate(implementationArguments, scope).doubleValue()), arguments.getRotation());
try { try {
Vector3.Mutable set = Vector3.of(FastMath.roundToInt(xz.getX()), Vector3.Mutable set = Vector3.of(FastMath.roundToInt(xz.getX()),
y.invoke(implementationArguments, scope).doubleValue(), y.evaluate(implementationArguments, scope).doubleValue(),
FastMath.roundToInt(xz.getZ())).mutable().add(arguments.getOrigin()); FastMath.roundToInt(xz.getZ())).mutable().add(arguments.getOrigin());
BlockState current = arguments.getWorld().getBlockState(set); BlockState current = arguments.getWorld().getBlockState(set);
if(overwrite.invoke(implementationArguments, scope) || current.isAir()) { if(overwrite.evaluate(implementationArguments, scope) || current.isAir()) {
arguments.getWorld().setBlockState(set, rot); arguments.getWorld().setBlockState(set, rot);
} }
} catch(RuntimeException e) { } catch(RuntimeException e) {
@@ -84,7 +84,7 @@ public class BlockFunction implements Function<Void> {
} }
protected BlockState getBlockState(ImplementationArguments arguments, Scope scope) { protected BlockState getBlockState(ImplementationArguments arguments, Scope scope) {
return data.computeIfAbsent(blockData.invoke(arguments, scope), platform.getWorldHandle()::createBlockState); return data.computeIfAbsent(blockData.evaluate(arguments, scope), platform.getWorldHandle()::createBlockState);
} }
@@ -33,11 +33,11 @@ public class CheckBlockFunction implements Function<String> {
@Override @Override
public String invoke(ImplementationArguments implementationArguments, Scope scope) { public String evaluate(ImplementationArguments implementationArguments, Scope scope) {
TerraImplementationArguments arguments = (TerraImplementationArguments) implementationArguments; TerraImplementationArguments arguments = (TerraImplementationArguments) implementationArguments;
Vector2 xz = RotationUtil.rotateVector(Vector2.of(x.invoke(implementationArguments, scope).doubleValue(), Vector2 xz = RotationUtil.rotateVector(Vector2.of(x.evaluate(implementationArguments, scope).doubleValue(),
z.invoke(implementationArguments, scope).doubleValue()), z.evaluate(implementationArguments, scope).doubleValue()),
arguments.getRotation()); arguments.getRotation());
@@ -46,7 +46,7 @@ public class CheckBlockFunction implements Function<String> {
.toVector3() .toVector3()
.mutable() .mutable()
.add(Vector3.of(FastMath.roundToInt(xz.getX()), .add(Vector3.of(FastMath.roundToInt(xz.getX()),
y.invoke(implementationArguments, scope) y.evaluate(implementationArguments, scope)
.doubleValue(), FastMath.roundToInt(xz.getZ())))) .doubleValue(), FastMath.roundToInt(xz.getZ()))))
.getAsString(); .getAsString();
if(data.contains("[")) return data.substring(0, data.indexOf('[')); // Strip properties if(data.contains("[")) return data.substring(0, data.indexOf('[')); // Strip properties
@@ -43,12 +43,12 @@ public class EntityFunction implements Function<Void> {
} }
@Override @Override
public Void invoke(ImplementationArguments implementationArguments, Scope scope) { public Void evaluate(ImplementationArguments implementationArguments, Scope scope) {
TerraImplementationArguments arguments = (TerraImplementationArguments) implementationArguments; TerraImplementationArguments arguments = (TerraImplementationArguments) implementationArguments;
Vector2 xz = RotationUtil.rotateVector(Vector2.of(x.invoke(implementationArguments, scope).doubleValue(), Vector2 xz = RotationUtil.rotateVector(Vector2.of(x.evaluate(implementationArguments, scope).doubleValue(),
z.invoke(implementationArguments, scope).doubleValue()), arguments.getRotation()); z.evaluate(implementationArguments, scope).doubleValue()), arguments.getRotation());
Entity entity = arguments.getWorld().spawnEntity(Vector3.of(xz.getX(), y.invoke(implementationArguments, scope).doubleValue(), Entity entity = arguments.getWorld().spawnEntity(Vector3.of(xz.getX(), y.evaluate(implementationArguments, scope).doubleValue(),
xz.getZ()) xz.getZ())
.mutable() .mutable()
.add(arguments.getOrigin()) .add(arguments.getOrigin())
@@ -32,13 +32,13 @@ public class GetMarkFunction implements Function<String> {
} }
@Override @Override
public String invoke(ImplementationArguments implementationArguments, Scope scope) { public String evaluate(ImplementationArguments implementationArguments, Scope scope) {
TerraImplementationArguments arguments = (TerraImplementationArguments) implementationArguments; TerraImplementationArguments arguments = (TerraImplementationArguments) implementationArguments;
Vector2 xz = RotationUtil.rotateVector(Vector2.of(x.invoke(implementationArguments, scope).doubleValue(), Vector2 xz = RotationUtil.rotateVector(Vector2.of(x.evaluate(implementationArguments, scope).doubleValue(),
z.invoke(implementationArguments, scope).doubleValue()), arguments.getRotation()); z.evaluate(implementationArguments, scope).doubleValue()), arguments.getRotation());
String mark = arguments.getMark(Vector3.of(FastMath.floorToInt(xz.getX()), FastMath.floorToInt( String mark = arguments.getMark(Vector3.of(FastMath.floorToInt(xz.getX()), FastMath.floorToInt(
y.invoke(implementationArguments, scope).doubleValue()), y.evaluate(implementationArguments, scope).doubleValue()),
FastMath.floorToInt(xz.getZ())) FastMath.floorToInt(xz.getZ()))
.mutable() .mutable()
.add(arguments.getOrigin()) .add(arguments.getOrigin())
@@ -54,20 +54,20 @@ public class LootFunction implements Function<Void> {
} }
@Override @Override
public Void invoke(ImplementationArguments implementationArguments, Scope scope) { public Void evaluate(ImplementationArguments implementationArguments, Scope scope) {
TerraImplementationArguments arguments = (TerraImplementationArguments) implementationArguments; TerraImplementationArguments arguments = (TerraImplementationArguments) implementationArguments;
Vector2 xz = RotationUtil.rotateVector(Vector2.of(x.invoke(implementationArguments, scope).doubleValue(), Vector2 xz = RotationUtil.rotateVector(Vector2.of(x.evaluate(implementationArguments, scope).doubleValue(),
z.invoke(implementationArguments, scope).doubleValue()), z.evaluate(implementationArguments, scope).doubleValue()),
arguments.getRotation()); arguments.getRotation());
String id = data.invoke(implementationArguments, scope); String id = data.evaluate(implementationArguments, scope);
registry.get(RegistryKey.parse(id)) registry.get(RegistryKey.parse(id))
.ifPresentOrElse(table -> { .ifPresentOrElse(table -> {
Vector3 apply = Vector3.of(FastMath.roundToInt(xz.getX()), Vector3 apply = Vector3.of(FastMath.roundToInt(xz.getX()),
y.invoke(implementationArguments, scope) y.evaluate(implementationArguments, scope)
.intValue(), .intValue(),
FastMath.roundToInt(xz.getZ())).mutable().add(arguments.getOrigin()).immutable(); FastMath.roundToInt(xz.getZ())).mutable().add(arguments.getOrigin()).immutable();
@@ -41,12 +41,12 @@ public class PullFunction implements Function<Void> {
} }
@Override @Override
public Void invoke(ImplementationArguments implementationArguments, Scope scope) { public Void evaluate(ImplementationArguments implementationArguments, Scope scope) {
TerraImplementationArguments arguments = (TerraImplementationArguments) implementationArguments; TerraImplementationArguments arguments = (TerraImplementationArguments) implementationArguments;
Vector2 xz = RotationUtil.rotateVector(Vector2.of(x.invoke(implementationArguments, scope).doubleValue(), Vector2 xz = RotationUtil.rotateVector(Vector2.of(x.evaluate(implementationArguments, scope).doubleValue(),
z.invoke(implementationArguments, scope).doubleValue()), arguments.getRotation()); z.evaluate(implementationArguments, scope).doubleValue()), arguments.getRotation());
Vector3.Mutable mutable = Vector3.of(FastMath.roundToInt(xz.getX()), y.invoke(implementationArguments, scope).intValue(), Vector3.Mutable mutable = Vector3.of(FastMath.roundToInt(xz.getX()), y.evaluate(implementationArguments, scope).intValue(),
FastMath.roundToInt(xz.getZ())).mutable().add(arguments.getOrigin()); FastMath.roundToInt(xz.getZ())).mutable().add(arguments.getOrigin());
while(mutable.getY() > arguments.getWorld().getMinHeight()) { while(mutable.getY() > arguments.getWorld().getMinHeight()) {
if(!arguments.getWorld().getBlockState(mutable).isAir()) { if(!arguments.getWorld().getBlockState(mutable).isAir()) {
@@ -31,9 +31,9 @@ public class RandomFunction implements Function<Integer> {
} }
@Override @Override
public Integer invoke(ImplementationArguments implementationArguments, Scope scope) { public Integer evaluate(ImplementationArguments implementationArguments, Scope scope) {
return ((TerraImplementationArguments) implementationArguments).getRandom().nextInt( return ((TerraImplementationArguments) implementationArguments).getRandom().nextInt(
numberReturnable.invoke(implementationArguments, scope).intValue()); numberReturnable.evaluate(implementationArguments, scope).intValue());
} }
@Override @Override
@@ -27,7 +27,7 @@ public class RecursionsFunction implements Function<Number> {
} }
@Override @Override
public Number invoke(ImplementationArguments implementationArguments, Scope scope) { public Number evaluate(ImplementationArguments implementationArguments, Scope scope) {
return ((TerraImplementationArguments) implementationArguments).getRecursions(); return ((TerraImplementationArguments) implementationArguments).getRecursions();
} }
@@ -34,17 +34,17 @@ public class SetMarkFunction implements Function<Void> {
} }
@Override @Override
public Void invoke(ImplementationArguments implementationArguments, Scope scope) { public Void evaluate(ImplementationArguments implementationArguments, Scope scope) {
TerraImplementationArguments arguments = (TerraImplementationArguments) implementationArguments; TerraImplementationArguments arguments = (TerraImplementationArguments) implementationArguments;
Vector2 xz = RotationUtil.rotateVector(Vector2.of(x.invoke(implementationArguments, scope).doubleValue(), Vector2 xz = RotationUtil.rotateVector(Vector2.of(x.evaluate(implementationArguments, scope).doubleValue(),
z.invoke(implementationArguments, scope).doubleValue()), arguments.getRotation()); z.evaluate(implementationArguments, scope).doubleValue()), arguments.getRotation());
arguments.setMark(Vector3.of(FastMath.floorToInt(xz.getX()), arguments.setMark(Vector3.of(FastMath.floorToInt(xz.getX()),
FastMath.floorToInt( FastMath.floorToInt(
y.invoke(implementationArguments, scope).doubleValue()), y.evaluate(implementationArguments, scope).doubleValue()),
FastMath.floorToInt(xz.getZ())).mutable().add(arguments.getOrigin()).immutable(), FastMath.floorToInt(xz.getZ())).mutable().add(arguments.getOrigin()).immutable(),
mark.invoke(implementationArguments, scope)); mark.evaluate(implementationArguments, scope));
return null; return null;
} }
@@ -39,17 +39,17 @@ public class StateFunction implements Function<Void> {
} }
@Override @Override
public Void invoke(ImplementationArguments implementationArguments, Scope scope) { public Void evaluate(ImplementationArguments implementationArguments, Scope scope) {
TerraImplementationArguments arguments = (TerraImplementationArguments) implementationArguments; TerraImplementationArguments arguments = (TerraImplementationArguments) implementationArguments;
Vector2 xz = RotationUtil.rotateVector(Vector2.of(x.invoke(implementationArguments, scope).doubleValue(), Vector2 xz = RotationUtil.rotateVector(Vector2.of(x.evaluate(implementationArguments, scope).doubleValue(),
z.invoke(implementationArguments, scope).doubleValue()), arguments.getRotation()); z.evaluate(implementationArguments, scope).doubleValue()), arguments.getRotation());
Vector3 origin = Vector3.of(FastMath.roundToInt(xz.getX()), y.invoke(implementationArguments, scope).intValue(), Vector3 origin = Vector3.of(FastMath.roundToInt(xz.getX()), y.evaluate(implementationArguments, scope).intValue(),
FastMath.roundToInt(xz.getZ())).mutable().add(arguments.getOrigin()).immutable(); FastMath.roundToInt(xz.getZ())).mutable().add(arguments.getOrigin()).immutable();
try { try {
BlockEntity state = arguments.getWorld().getBlockEntity(origin); BlockEntity state = arguments.getWorld().getBlockEntity(origin);
state.applyState(data.invoke(implementationArguments, scope)); state.applyState(data.evaluate(implementationArguments, scope));
state.update(false); state.update(false);
} catch(Exception e) { } catch(Exception e) {
LOGGER.warn("Could not apply BlockState at {}", origin, e); LOGGER.warn("Could not apply BlockState at {}", origin, e);
@@ -55,20 +55,20 @@ public class StructureFunction implements Function<Boolean> {
} }
@Override @Override
public Boolean invoke(ImplementationArguments implementationArguments, Scope scope) { public Boolean evaluate(ImplementationArguments implementationArguments, Scope scope) {
TerraImplementationArguments arguments = (TerraImplementationArguments) implementationArguments; TerraImplementationArguments arguments = (TerraImplementationArguments) implementationArguments;
if(arguments.getRecursions() > platform.getTerraConfig().getMaxRecursion()) if(arguments.getRecursions() > platform.getTerraConfig().getMaxRecursion())
throw new RuntimeException("Structure recursion too deep: " + arguments.getRecursions()); throw new RuntimeException("Structure recursion too deep: " + arguments.getRecursions());
Vector2 xz = RotationUtil.rotateVector(Vector2.of(x.invoke(implementationArguments, scope).doubleValue(), Vector2 xz = RotationUtil.rotateVector(Vector2.of(x.evaluate(implementationArguments, scope).doubleValue(),
z.invoke(implementationArguments, scope).doubleValue()), arguments.getRotation()); z.evaluate(implementationArguments, scope).doubleValue()), arguments.getRotation());
String app = id.invoke(implementationArguments, scope); String app = id.evaluate(implementationArguments, scope);
return registry.getByID(app).map(script -> { return registry.getByID(app).map(script -> {
Rotation rotation1; Rotation rotation1;
String rotString = rotations.get(arguments.getRandom().nextInt(rotations.size())).invoke(implementationArguments, scope); String rotString = rotations.get(arguments.getRandom().nextInt(rotations.size())).evaluate(implementationArguments, scope);
try { try {
rotation1 = Rotation.valueOf(rotString); rotation1 = Rotation.valueOf(rotString);
} catch(IllegalArgumentException e) { } catch(IllegalArgumentException e) {
@@ -80,7 +80,7 @@ public class StructureFunction implements Function<Boolean> {
return structureScript.generate(arguments.getOrigin(), return structureScript.generate(arguments.getOrigin(),
arguments.getWorld() arguments.getWorld()
.buffer(FastMath.roundToInt(xz.getX()), .buffer(FastMath.roundToInt(xz.getX()),
y.invoke(implementationArguments, scope).intValue(), y.evaluate(implementationArguments, scope).intValue(),
FastMath.roundToInt(xz.getZ())), FastMath.roundToInt(xz.getZ())),
arguments.getRandom(), arguments.getRandom(),
arguments.getRotation().rotate(rotation1), arguments.getRecursions() + 1); arguments.getRotation().rotate(rotation1), arguments.getRecursions() + 1);
@@ -88,7 +88,7 @@ public class StructureFunction implements Function<Boolean> {
return script.generate(arguments.getOrigin(), return script.generate(arguments.getOrigin(),
arguments.getWorld() arguments.getWorld()
.buffer(FastMath.roundToInt(xz.getX()), .buffer(FastMath.roundToInt(xz.getX()),
y.invoke(implementationArguments, scope).intValue(), y.evaluate(implementationArguments, scope).intValue(),
FastMath.roundToInt(xz.getZ())), FastMath.roundToInt(xz.getZ())),
arguments.getRandom(), arguments.getRandom(),
arguments.getRotation().rotate(rotation1)); arguments.getRotation().rotate(rotation1));
@@ -39,6 +39,10 @@ public class Token {
return this.type.equals(Type.NUMBER) || this.type.equals(Type.STRING) || this.type.equals(Type.BOOLEAN); return this.type.equals(Type.NUMBER) || this.type.equals(Type.STRING) || this.type.equals(Type.BOOLEAN);
} }
public boolean isType(Type type) {
return type == getType();
}
public boolean isBinaryOperator() { public boolean isBinaryOperator() {
return type.equals(Type.ADDITION_OPERATOR) return type.equals(Type.ADDITION_OPERATOR)
|| type.equals(Type.SUBTRACTION_OPERATOR) || type.equals(Type.SUBTRACTION_OPERATOR)
@@ -77,16 +81,12 @@ public class Token {
|| type.equals(Type.NUMBER_VARIABLE); || type.equals(Type.NUMBER_VARIABLE);
} }
public boolean isLoopLike() { public boolean isControlStructure() {
return type.equals(Type.IF_STATEMENT) return type.equals(Type.IF_STATEMENT)
|| type.equals(Type.WHILE_LOOP) || type.equals(Type.WHILE_LOOP)
|| type.equals(Type.FOR_LOOP); || type.equals(Type.FOR_LOOP);
} }
public boolean isIdentifier() {
return type.equals(Type.IDENTIFIER);
}
public enum Type { public enum Type {
/** /**
* Function identifier or language keyword * Function identifier or language keyword
@@ -11,13 +11,13 @@ import org.junit.jupiter.api.Test;
import java.io.StringReader; import java.io.StringReader;
import com.dfsek.terra.addons.terrascript.tokenizer.PeekableStream; import com.dfsek.terra.addons.terrascript.tokenizer.LookaheadStream;
public class PeekableStreamTest { public class LookaheadStreamTest {
@Test @Test
public void lookahead() { public void lookahead() {
PeekableStream lookahead = new PeekableStream(new StringReader("Test string...")); LookaheadStream lookahead = new LookaheadStream(new StringReader("Test string..."));
for(int i = 0; lookahead.next(i) != null; i++) { for(int i = 0; lookahead.next(i) != null; i++) {
System.out.print(lookahead.next(i).getCharacter()); System.out.print(lookahead.next(i).getCharacter());
@@ -77,9 +77,9 @@ public class ParserTest {
} }
@Override @Override
public Void invoke(ImplementationArguments implementationArguments, Scope scope) { public Void evaluate(ImplementationArguments implementationArguments, Scope scope) {
System.out.println("string: " + a.invoke(implementationArguments, scope) + ", double: " + System.out.println("string: " + a.evaluate(implementationArguments, scope) + ", double: " +
b.invoke(implementationArguments, scope)); b.evaluate(implementationArguments, scope));
return null; return null;
} }
@@ -37,19 +37,19 @@ public class CheckFunction implements Function<String> {
@Override @Override
public String invoke(ImplementationArguments implementationArguments, Scope scope) { public String evaluate(ImplementationArguments implementationArguments, Scope scope) {
TerraImplementationArguments arguments = (TerraImplementationArguments) implementationArguments; TerraImplementationArguments arguments = (TerraImplementationArguments) implementationArguments;
Vector2 xz = Vector2.of(x.invoke(implementationArguments, scope).doubleValue(), Vector2 xz = Vector2.of(x.evaluate(implementationArguments, scope).doubleValue(),
z.invoke(implementationArguments, scope).doubleValue()); z.evaluate(implementationArguments, scope).doubleValue());
RotationUtil.rotateVector(xz, arguments.getRotation()); RotationUtil.rotateVector(xz, arguments.getRotation());
Vector3 location = arguments.getOrigin().toVector3Mutable().add( Vector3 location = arguments.getOrigin().toVector3Mutable().add(
Vector3.of(FastMath.roundToInt(xz.getX()), y.invoke(implementationArguments, scope).doubleValue(), Vector3.of(FastMath.roundToInt(xz.getX()), y.evaluate(implementationArguments, scope).doubleValue(),
FastMath.roundToInt(xz.getZ()))).immutable(); FastMath.roundToInt(xz.getZ()))).immutable();
return apply(location, arguments.getWorld()); return apply(location, arguments.getWorld());
@@ -32,16 +32,16 @@ public class ConstantSamplerFunction implements Function<Number> {
} }
@Override @Override
public Number invoke(ImplementationArguments implementationArguments, Scope scope) { public Number evaluate(ImplementationArguments implementationArguments, Scope scope) {
TerraImplementationArguments arguments = (TerraImplementationArguments) implementationArguments; TerraImplementationArguments arguments = (TerraImplementationArguments) implementationArguments;
double x = this.x.invoke(implementationArguments, scope).doubleValue(); double x = this.x.evaluate(implementationArguments, scope).doubleValue();
double z = this.z.invoke(implementationArguments, scope).doubleValue(); double z = this.z.evaluate(implementationArguments, scope).doubleValue();
if(twoD) { if(twoD) {
return sampler.noise(arguments.getWorld().getSeed(), x, z); return sampler.noise(arguments.getWorld().getSeed(), x, z);
} else { } else {
double y = this.y.invoke(implementationArguments, scope).doubleValue(); double y = this.y.evaluate(implementationArguments, scope).doubleValue();
return sampler.noise(arguments.getWorld().getSeed(), x, y, z); return sampler.noise(arguments.getWorld().getSeed(), x, y, z);
} }
} }
@@ -37,17 +37,17 @@ public class SamplerFunction implements Function<Number> {
} }
@Override @Override
public Number invoke(ImplementationArguments implementationArguments, Scope scope) { public Number evaluate(ImplementationArguments implementationArguments, Scope scope) {
TerraImplementationArguments arguments = (TerraImplementationArguments) implementationArguments; TerraImplementationArguments arguments = (TerraImplementationArguments) implementationArguments;
double x = this.x.invoke(implementationArguments, scope).doubleValue(); double x = this.x.evaluate(implementationArguments, scope).doubleValue();
double z = this.z.invoke(implementationArguments, scope).doubleValue(); double z = this.z.evaluate(implementationArguments, scope).doubleValue();
NoiseSampler sampler = samplerFunction.apply(() -> function.invoke(implementationArguments, scope)); NoiseSampler sampler = samplerFunction.apply(() -> function.evaluate(implementationArguments, scope));
if(twoD) { if(twoD) {
return sampler.noise(arguments.getWorld().getSeed(), x, z); return sampler.noise(arguments.getWorld().getSeed(), x, z);
} else { } else {
double y = this.y.invoke(implementationArguments, scope).doubleValue(); double y = this.y.evaluate(implementationArguments, scope).doubleValue();
return sampler.noise(arguments.getWorld().getSeed(), x, y, z); return sampler.noise(arguments.getWorld().getSeed(), x, y, z);
} }
} }