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

View File

@@ -16,8 +16,6 @@ import java.util.Map;
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.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.ReturnType;
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);
}
private Keyword<?> parseLoopLike(Tokenizer tokens, boolean loop, ScopeBuilder scopeBuilder) throws ParseException {
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);
private WhileKeyword parseWhileLoop(Tokenizer tokenizer, SourcePosition start, ScopeBuilder scopeBuilder) {
Expression<?> first = parseLogicMathExpression(tokenizer, true, scopeBuilder);
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) {
Expression<?> condition = parseExpression(tokens, true, scopeBuilder);
private IfKeyword parseIfStatement(Tokenizer tokenizer, SourcePosition start, boolean controlStructure, ScopeBuilder scopeBuilder) {
Expression<?> condition = parseLogicMathExpression(tokenizer, true, scopeBuilder);
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 statement = parseStatementBlock(tokens, loop, scopeBuilder);
Block statement = parseStatementBlock(tokenizer, controlStructure, scopeBuilder);
List<Pair<Expression<Boolean>, Block>> elseIf = new ArrayList<>();
while(tokens.hasNext() && tokens.current().getType().equals(Token.Type.ELSE)) {
tokens.consume(); // Consume else.
if(tokens.current().getType().equals(Token.Type.IF_STATEMENT)) {
tokens.consume(); // Consume if.
Expression<?> elseCondition = parseExpression(tokens, true, scopeBuilder);
while(tokenizer.hasNext() && tokenizer.current().isType(Token.Type.ELSE)) {
tokenizer.consume(); // Consume else.
if(tokenizer.current().isType(Token.Type.IF_STATEMENT)) {
tokenizer.consume(); // Consume if.
Expression<?> elseCondition = parseLogicMathExpression(tokenizer, true, scopeBuilder);
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 {
elseBlock = parseStatementBlock(tokens, loop, scopeBuilder);
elseBlock = parseStatementBlock(tokenizer, controlStructure, scopeBuilder);
break; // Else must be last.
}
}
@@ -148,75 +130,75 @@ public class Parser {
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)) {
ParserUtil.checkType(tokens.consume(), Token.Type.BLOCK_BEGIN);
Block block = parseBlock(tokens, loop, scopeBuilder);
ParserUtil.checkType(tokens.consume(), Token.Type.BLOCK_END);
if(tokenizer.current().isType(Token.Type.BLOCK_BEGIN)) {
ParserUtil.ensureType(tokenizer.consume(), Token.Type.BLOCK_BEGIN);
Block block = parseBlock(tokenizer, controlStructure, scopeBuilder);
ParserUtil.ensureType(tokenizer.consume(), Token.Type.BLOCK_END);
return block;
} else {
SourcePosition position = tokens.current().getPosition();
Block block = new Block(Collections.singletonList(parseStatement(tokens, loop, scopeBuilder)), position);
ParserUtil.checkType(tokens.consume(), Token.Type.STATEMENT_END);
SourcePosition position = tokenizer.current().getPosition();
Block block = new Block(Collections.singletonList(parseExpression(tokenizer, controlStructure, scopeBuilder)), position);
ParserUtil.ensureType(tokenizer.consume(), Token.Type.STATEMENT_END);
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
Token f = tokens.current();
ParserUtil.checkType(f, Token.Type.NUMBER_VARIABLE, Token.Type.STRING_VARIABLE, Token.Type.BOOLEAN_VARIABLE, Token.Type.IDENTIFIER);
Statement<?> initializer;
Token f = tokenizer.current();
ParserUtil.ensureType(f, Token.Type.NUMBER_VARIABLE, Token.Type.STRING_VARIABLE, Token.Type.BOOLEAN_VARIABLE, Token.Type.IDENTIFIER);
Expression<?> initializer;
if(f.isVariableDeclaration()) {
VariableAssignmentNode<?> forVar = parseVariableDeclaration(tokens, scopeBuilder);
Token name = tokens.current();
VariableAssignmentNode<?> forVar = parseVariableDeclaration(tokenizer, scopeBuilder);
Token name = tokenizer.current();
if(functions.containsKey(name.getContent()) || scopeBuilder.contains(name.getContent()))
throw new ParseException(name.getContent() + " is already defined in this scope", name.getPosition());
initializer = forVar;
} else initializer = parseExpression(tokens, true, scopeBuilder);
ParserUtil.checkType(tokens.consume(), Token.Type.STATEMENT_END);
Expression<?> conditional = parseExpression(tokens, true, scopeBuilder);
} else initializer = parseLogicMathExpression(tokenizer, true, scopeBuilder);
ParserUtil.ensureType(tokenizer.consume(), Token.Type.STATEMENT_END);
Expression<?> conditional = parseLogicMathExpression(tokenizer, true, scopeBuilder);
ParserUtil.checkReturnType(conditional, Expression.ReturnType.BOOLEAN);
ParserUtil.checkType(tokens.consume(), Token.Type.STATEMENT_END);
ParserUtil.ensureType(tokenizer.consume(), Token.Type.STATEMENT_END);
Statement<?> incrementer;
Token token = tokens.current();
Expression<?> incrementer;
Token token = tokenizer.current();
if(scopeBuilder.contains(token.getContent())) { // Assume variable assignment
incrementer = parseAssignment(tokens, scopeBuilder);
} else incrementer = parseFunction(tokens, true, scopeBuilder);
incrementer = parseAssignment(tokenizer, 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);
}
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 negate = false;
if(tokens.current().getType().equals(Token.Type.BOOLEAN_NOT)) {
if(tokenizer.current().isType(Token.Type.BOOLEAN_NOT)) {
booleanInverted = true;
tokens.consume();
} else if(tokens.current().getType().equals(Token.Type.SUBTRACTION_OPERATOR)) {
tokenizer.consume();
} else if(tokenizer.current().isType(Token.Type.SUBTRACTION_OPERATOR)) {
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;
if(id.isConstant()) {
expression = parseConstantExpression(tokens);
} else if(id.getType().equals(Token.Type.GROUP_BEGIN)) { // Parse grouped expression
expression = parseGroup(tokens, scopeBuilder);
expression = parseConstantExpression(tokenizer);
} else if(id.isType(Token.Type.GROUP_BEGIN)) { // Parse grouped expression
expression = parseGroup(tokenizer, scopeBuilder);
} else {
if(functions.containsKey(id.getContent()))
expression = parseFunction(tokens, false, scopeBuilder);
expression = parseFunction(tokenizer, false, scopeBuilder);
else if(scopeBuilder.contains(id.getContent())) {
ParserUtil.checkType(tokens.consume(), Token.Type.IDENTIFIER);
ParserUtil.ensureType(tokenizer.consume(), Token.Type.IDENTIFIER);
String varId = id.getContent();
ReturnType varType = scopeBuilder.getType(varId);
expression = switch(varType) {
@@ -237,14 +219,14 @@ public class Parser {
expression = new NegationOperation((Expression<Number>) expression, expression.getPosition());
}
if(full && tokens.current().isBinaryOperator()) { // Parse binary operations
return parseBinaryOperation(expression, tokens, scopeBuilder);
if(full && tokenizer.current().isBinaryOperator()) { // Parse binary operations
return parseBinaryOperation(expression, tokenizer, scopeBuilder);
}
return expression;
}
private ConstantExpression<?> parseConstantExpression(Tokenizer tokens) {
Token constantToken = tokens.consume();
private ConstantExpression<?> parseConstantExpression(Tokenizer tokenizer) {
Token constantToken = tokenizer.consume();
SourcePosition position = constantToken.getPosition();
switch(constantToken.getType()) {
case NUMBER:
@@ -260,25 +242,25 @@ public class Parser {
}
}
private Expression<?> parseGroup(Tokenizer tokens, ScopeBuilder scopeBuilder) {
ParserUtil.checkType(tokens.consume(), Token.Type.GROUP_BEGIN);
Expression<?> expression = parseExpression(tokens, true, scopeBuilder); // Parse inside of group as a separate expression
ParserUtil.checkType(tokens.consume(), Token.Type.GROUP_END);
private Expression<?> parseGroup(Tokenizer tokenizer, ScopeBuilder scopeBuilder) {
ParserUtil.ensureType(tokenizer.consume(), Token.Type.GROUP_BEGIN);
Expression<?> expression = parseLogicMathExpression(tokenizer, true, scopeBuilder); // Parse inside of group as a separate expression
ParserUtil.ensureType(tokenizer.consume(), Token.Type.GROUP_END);
return expression;
}
private BinaryOperation<?, ?> parseBinaryOperation(Expression<?> left, Tokenizer tokens,
private BinaryOperation<?, ?> parseBinaryOperation(Expression<?> left, Tokenizer tokenizer,
ScopeBuilder scopeBuilder) {
Token binaryOperator = tokens.consume();
Token binaryOperator = tokenizer.consume();
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())) {
return assemble(left, parseBinaryOperation(right, tokens, scopeBuilder), binaryOperator);
return assemble(left, parseBinaryOperation(right, tokenizer, scopeBuilder), binaryOperator);
} 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);
}
@@ -323,20 +305,20 @@ public class Parser {
}
}
private VariableAssignmentNode<?> parseVariableDeclaration(Tokenizer tokens, ScopeBuilder scopeBuilder) {
Token type = tokens.consume();
ParserUtil.checkType(type, Token.Type.STRING_VARIABLE, Token.Type.BOOLEAN_VARIABLE, Token.Type.NUMBER_VARIABLE);
private VariableAssignmentNode<?> parseVariableDeclaration(Tokenizer tokenizer, ScopeBuilder scopeBuilder) {
Token type = tokenizer.consume();
ParserUtil.ensureType(type, Token.Type.STRING_VARIABLE, Token.Type.BOOLEAN_VARIABLE, Token.Type.NUMBER_VARIABLE);
Expression.ReturnType returnType = ParserUtil.getVariableReturnType(type);
ParserUtil.checkVarType(type, returnType); // Check for type mismatch
Token identifier = tokens.consume();
ParserUtil.checkType(identifier, Token.Type.IDENTIFIER);
Token identifier = tokenizer.consume();
ParserUtil.ensureType(identifier, Token.Type.IDENTIFIER);
if(functions.containsKey(identifier.getContent()) || scopeBuilder.contains(identifier.getContent()))
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);
String id = identifier.getContent();
@@ -349,57 +331,67 @@ public class Parser {
};
}
private Block parseBlock(Tokenizer tokens, boolean loop, ScopeBuilder scopeBuilder) {
List<Statement<?>> statements = new ArrayList<>();
private Block parseBlock(Tokenizer tokenizer, boolean controlStructure, ScopeBuilder scopeBuilder) {
List<Expression<?>> expressions = new ArrayList<>();
scopeBuilder = scopeBuilder.sub();
Token first = tokens.current();
Token first = tokenizer.current();
while(tokens.hasNext()) {
Token token = tokens.current();
if(token.getType().equals(Token.Type.BLOCK_END)) break; // Stop parsing at block end.
Statement<?> statement = parseStatement(tokens, loop, scopeBuilder);
if(statement != Function.NULL) {
statements.add(statement);
while(tokenizer.hasNext()) {
Token token = tokenizer.current();
if(token.isType(Token.Type.BLOCK_END)) break; // Stop parsing at block end.
Expression<?> expression = parseExpression(tokenizer, controlStructure, scopeBuilder);
if(expression != Function.NULL) {
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) {
Token token = tokens.current();
if(loop) ParserUtil.checkType(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.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,
Token.Type.NUMBER_VARIABLE, Token.Type.STRING_VARIABLE, Token.Type.BOOLEAN_VARIABLE, Token.Type.RETURN,
Token.Type.FAIL);
private Expression<?> parseExpression(Tokenizer tokenizer, boolean controlStructure, ScopeBuilder scopeBuilder) {
Token token = tokenizer.current();
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.RETURN, Token.Type.BREAK, Token.Type.CONTINUE, Token.Type.FAIL);
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.FAIL);
if(token.isLoopLike()) { // Parse loop-like tokens (if, while, etc)
return parseLoopLike(tokens, loop, scopeBuilder);
} else if(token.isIdentifier()) { // Parse identifiers
if(scopeBuilder.contains(token.getContent())) { // Assume variable assignment
return parseAssignment(tokens, scopeBuilder);
} else return parseFunction(tokens, true, scopeBuilder);
} else if(token.isVariableDeclaration()) {
return parseVariableDeclaration(tokens, scopeBuilder);
} else if(token.getType().equals(Token.Type.RETURN)) return new ReturnKeyword(tokens.consume().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());
else throw new UnsupportedOperationException("Unexpected token " + token.getType() + ": " + token.getPosition());
Expression<?> expression = switch(token.getType()) {
case FOR_LOOP, IF_STATEMENT, WHILE_LOOP -> {
Token identifier = tokenizer.consume();
ParserUtil.ensureType(tokenizer.consume(), Token.Type.GROUP_BEGIN);
yield switch(identifier.getType()) {
case FOR_LOOP -> parseForLoop(tokenizer, identifier.getPosition(), scopeBuilder);
case IF_STATEMENT -> parseIfStatement(tokenizer, identifier.getPosition(), controlStructure, scopeBuilder);
case WHILE_LOOP -> parseWhileLoop(tokenizer, identifier.getPosition(), scopeBuilder);
default -> throw new UnsupportedOperationException("Unknown keyword " + identifier.getContent() + ": " + identifier.getPosition());
};
}
case IDENTIFIER -> {
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) {
Token identifier = tokens.consume();
private VariableAssignmentNode<?> parseAssignment(Tokenizer tokenizer, ScopeBuilder scopeBuilder) {
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();
@@ -415,21 +407,20 @@ public class Parser {
};
}
private Function<?> parseFunction(Tokenizer tokens, boolean fullStatement, ScopeBuilder scopeBuilder) {
Token identifier = tokens.consume();
ParserUtil.checkType(identifier, Token.Type.IDENTIFIER); // First token must be identifier
private Function<?> parseFunction(Tokenizer tokenizer, boolean fullStatement, ScopeBuilder scopeBuilder) {
Token identifier = tokenizer.consume();
ParserUtil.ensureType(identifier, Token.Type.IDENTIFIER); // First token must be identifier
if(!functions.containsKey(identifier.getContent()))
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.checkType(tokens.current(), Token.Type.STATEMENT_END);
if(fullStatement) ParserUtil.ensureType(tokenizer.current(), Token.Type.STATEMENT_END);
if(ignoredFunctions.contains(identifier.getContent())) {
return Function.NULL;
@@ -453,13 +444,13 @@ public class Parser {
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<>();
while(!tokens.current().getType().equals(Token.Type.GROUP_END)) {
args.add(parseExpression(tokens, true, scopeBuilder));
ParserUtil.checkType(tokens.current(), Token.Type.SEPARATOR, Token.Type.GROUP_END);
if(tokens.current().getType().equals(Token.Type.SEPARATOR)) tokens.consume();
while(!tokenizer.current().isType(Token.Type.GROUP_END)) {
args.add(parseLogicMathExpression(tokenizer, true, scopeBuilder));
ParserUtil.ensureType(tokenizer.current(), Token.Type.SEPARATOR, Token.Type.GROUP_END);
if(tokenizer.current().isType(Token.Type.SEPARATOR)) tokenizer.consume();
}
return args;
}

View File

@@ -51,7 +51,7 @@ public class ParserUtil {
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;
throw new ParseException("Expected " + Arrays.toString(expected) + " but found " + token.getType(), token.getPosition());
}

View File

@@ -13,19 +13,24 @@ import com.dfsek.terra.addons.terrascript.parser.lang.Block.ReturnInfo;
import com.dfsek.terra.addons.terrascript.tokenizer.SourcePosition;
public class Block implements Statement<ReturnInfo<?>> {
private final List<Statement<?>> items;
public class Block implements Expression<ReturnInfo<?>> {
private final List<Expression<?>> items;
private final SourcePosition position;
public Block(List<Statement<?>> items, SourcePosition position) {
public Block(List<Expression<?>> items, SourcePosition position) {
this.items = items;
this.position = position;
}
@Override
public ReturnInfo<?> invoke(ImplementationArguments implementationArguments, Scope scope) {
for(Statement<?> item : items) {
Object result = item.invoke(implementationArguments, scope);
public ReturnType returnType() {
return ReturnType.VOID;
}
@Override
public ReturnInfo<?> evaluate(ImplementationArguments implementationArguments, Scope scope) {
for(Expression<?> item : items) {
Object result = item.evaluate(implementationArguments, scope);
if(result instanceof ReturnInfo<?> level) {
if(!level.getLevel().equals(ReturnLevel.NONE)) return level;
}

View File

@@ -14,6 +14,6 @@ public class Executable {
}
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;
}
}

View File

@@ -7,9 +7,24 @@
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();
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 {
NUMBER(true),
STRING(true),

View File

@@ -7,19 +7,9 @@
package com.dfsek.terra.addons.terrascript.parser.lang;
import com.dfsek.terra.addons.terrascript.tokenizer.SourcePosition;
public interface Statement<T> {
T invoke(ImplementationArguments implementationArguments, Scope scope);
default double applyDouble(ImplementationArguments implementationArguments, Scope scope) {
throw new UnsupportedOperationException("Cannot apply " + this + " as double");
public interface Statement extends Expression<Void> {
@Override
default ReturnType returnType() {
return ReturnType.VOID;
}
default boolean applyBoolean(ImplementationArguments implementationArguments, Scope scope) {
throw new UnsupportedOperationException("Cannot apply " + this + " as double");
}
SourcePosition getPosition();
}

View File

@@ -23,7 +23,7 @@ public abstract class ConstantExpression<T> implements Expression<T> {
}
@Override
public T invoke(ImplementationArguments implementationArguments, Scope scope) {
public T evaluate(ImplementationArguments implementationArguments, Scope scope) {
return constant;
}

View File

@@ -21,7 +21,7 @@ public interface Function<T> extends Expression<T> {
}
@Override
public Object invoke(ImplementationArguments implementationArguments, Scope scope) {
public Object evaluate(ImplementationArguments implementationArguments, Scope scope) {
return null;
}
@@ -33,11 +33,11 @@ public interface Function<T> extends Expression<T> {
@Override
default double applyDouble(ImplementationArguments implementationArguments, Scope scope) {
return ((Number) invoke(implementationArguments, scope)).doubleValue();
return ((Number) evaluate(implementationArguments, scope)).doubleValue();
}
@Override
default boolean applyBoolean(ImplementationArguments implementationArguments, Scope scope) {
return (Boolean) invoke(implementationArguments, scope);
return (Boolean) evaluate(implementationArguments, scope);
}
}

View File

@@ -22,7 +22,7 @@ public class BreakKeyword implements Keyword<Block.ReturnInfo<?>> {
}
@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);
}

View File

@@ -22,7 +22,7 @@ public class ContinueKeyword implements Keyword<Block.ReturnInfo<?>> {
}
@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);
}

View File

@@ -22,7 +22,7 @@ public class FailKeyword implements Keyword<Block.ReturnInfo<?>> {
}
@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);
}

View File

@@ -22,7 +22,7 @@ public class ReturnKeyword implements Keyword<Block.ReturnInfo<?>> {
}
@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);
}

View File

@@ -18,12 +18,12 @@ import com.dfsek.terra.addons.terrascript.tokenizer.SourcePosition;
public class ForKeyword implements Keyword<Block.ReturnInfo<?>> {
private final Block conditional;
private final Statement<?> initializer;
private final Expression<?> initializer;
private final Expression<Boolean> statement;
private final Statement<?> incrementer;
private final Expression<?> incrementer;
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.initializer = initializer;
this.statement = statement;
@@ -32,11 +32,11 @@ public class ForKeyword implements Keyword<Block.ReturnInfo<?>> {
}
@Override
public Block.ReturnInfo<?> invoke(ImplementationArguments implementationArguments, Scope scope) {
for(initializer.invoke(implementationArguments, scope);
statement.invoke(implementationArguments, scope);
incrementer.invoke(implementationArguments, scope)) {
Block.ReturnInfo<?> level = conditional.invoke(implementationArguments, scope);
public Block.ReturnInfo<?> evaluate(ImplementationArguments implementationArguments, Scope scope) {
for(initializer.evaluate(implementationArguments, scope);
statement.evaluate(implementationArguments, scope);
incrementer.evaluate(implementationArguments, scope)) {
Block.ReturnInfo<?> level = conditional.evaluate(implementationArguments, scope);
if(level.getLevel().equals(Block.ReturnLevel.BREAK)) break;
if(level.getLevel().isReturnFast()) return level;
}

View File

@@ -37,15 +37,15 @@ public class IfKeyword implements Keyword<Block.ReturnInfo<?>> {
}
@Override
public Block.ReturnInfo<?> invoke(ImplementationArguments implementationArguments, Scope scope) {
if(statement.invoke(implementationArguments, scope)) return conditional.invoke(implementationArguments, scope);
public Block.ReturnInfo<?> evaluate(ImplementationArguments implementationArguments, Scope scope) {
if(statement.evaluate(implementationArguments, scope)) return conditional.evaluate(implementationArguments, scope);
else {
for(Pair<Expression<Boolean>, Block> pair : elseIf) {
if(pair.getLeft().invoke(implementationArguments, scope)) {
return pair.getRight().invoke(implementationArguments, scope);
if(pair.getLeft().evaluate(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);
}

View File

@@ -27,9 +27,9 @@ public class WhileKeyword implements Keyword<Block.ReturnInfo<?>> {
}
@Override
public Block.ReturnInfo<?> invoke(ImplementationArguments implementationArguments, Scope scope) {
while(statement.invoke(implementationArguments, scope)) {
Block.ReturnInfo<?> level = conditional.invoke(implementationArguments, scope);
public Block.ReturnInfo<?> evaluate(ImplementationArguments implementationArguments, Scope scope) {
while(statement.evaluate(implementationArguments, scope)) {
Block.ReturnInfo<?> level = conditional.evaluate(implementationArguments, scope);
if(level.getLevel().equals(Block.ReturnLevel.BREAK)) break;
if(level.getLevel().isReturnFast()) return level;
}

View File

@@ -24,7 +24,7 @@ public class BooleanAndOperation extends BinaryOperation<Boolean, Boolean> {
}
@Override
public Boolean invoke(ImplementationArguments implementationArguments, Scope scope) {
public Boolean evaluate(ImplementationArguments implementationArguments, Scope scope) {
return applyBoolean(implementationArguments, scope);
}

View File

@@ -19,7 +19,7 @@ public class BooleanNotOperation extends UnaryOperation<Boolean> {
}
@Override
public Boolean invoke(ImplementationArguments implementationArguments, Scope scope) {
public Boolean evaluate(ImplementationArguments implementationArguments, Scope scope) {
return applyBoolean(implementationArguments, scope);
}

View File

@@ -19,7 +19,7 @@ public class BooleanOrOperation extends BinaryOperation<Boolean, Boolean> {
}
@Override
public Boolean invoke(ImplementationArguments implementationArguments, Scope scope) {
public Boolean evaluate(ImplementationArguments implementationArguments, Scope scope) {
return applyBoolean(implementationArguments, scope);
}

View File

@@ -35,7 +35,7 @@ public class ConcatenationOperation extends BinaryOperation<Object, Object> {
}
@Override
public Object invoke(ImplementationArguments implementationArguments, Scope scope) {
return toString(left.invoke(implementationArguments, scope)) + toString(right.invoke(implementationArguments, scope));
public Object evaluate(ImplementationArguments implementationArguments, Scope scope) {
return toString(left.evaluate(implementationArguments, scope)) + toString(right.evaluate(implementationArguments, scope));
}
}

View File

@@ -24,7 +24,7 @@ public class DivisionOperation extends BinaryOperation<Number, Number> {
}
@Override
public Number invoke(ImplementationArguments implementationArguments, Scope scope) {
public Number evaluate(ImplementationArguments implementationArguments, Scope scope) {
return applyDouble(implementationArguments, scope);
}

View File

@@ -19,7 +19,7 @@ public class ModuloOperation extends BinaryOperation<Number, Number> {
}
@Override
public Number invoke(ImplementationArguments implementationArguments, Scope scope) {
public Number evaluate(ImplementationArguments implementationArguments, Scope scope) {
return applyDouble(implementationArguments, scope);
}

View File

@@ -19,7 +19,7 @@ public class MultiplicationOperation extends BinaryOperation<Number, Number> {
}
@Override
public Number invoke(ImplementationArguments implementationArguments, Scope scope) {
public Number evaluate(ImplementationArguments implementationArguments, Scope scope) {
return applyDouble(implementationArguments, scope);
}

View File

@@ -24,7 +24,7 @@ public class NegationOperation extends UnaryOperation<Number> {
}
@Override
public Number invoke(ImplementationArguments implementationArguments, Scope scope) {
public Number evaluate(ImplementationArguments implementationArguments, Scope scope) {
return applyDouble(implementationArguments, scope);
}

View File

@@ -19,7 +19,7 @@ public class NumberAdditionOperation extends BinaryOperation<Number, Number> {
}
@Override
public Number invoke(ImplementationArguments implementationArguments, Scope scope) {
public Number evaluate(ImplementationArguments implementationArguments, Scope scope) {
return applyDouble(implementationArguments, scope);
}

View File

@@ -19,7 +19,7 @@ public class SubtractionOperation extends BinaryOperation<Number, Number> {
}
@Override
public Number invoke(ImplementationArguments implementationArguments, Scope scope) {
public Number evaluate(ImplementationArguments implementationArguments, Scope scope) {
return applyDouble(implementationArguments, scope);
}

View File

@@ -31,14 +31,14 @@ public class EqualsStatement extends BinaryOperation<Object, Boolean> {
}
@Override
public Boolean invoke(ImplementationArguments implementationArguments, Scope scope) {
public Boolean evaluate(ImplementationArguments implementationArguments, Scope scope) {
return applyBoolean(implementationArguments, scope);
}
@Override
public boolean applyBoolean(ImplementationArguments implementationArguments, Scope scope) {
Object leftValue = left.invoke(implementationArguments, scope);
Object rightValue = right.invoke(implementationArguments, scope);
Object leftValue = left.evaluate(implementationArguments, scope);
Object rightValue = right.evaluate(implementationArguments, scope);
if(leftValue instanceof Number l && rightValue instanceof Number r) {
return FastMath.abs(l.doubleValue() - r.doubleValue()) <= EPSILON;
}

View File

@@ -25,7 +25,7 @@ public class GreaterOrEqualsThanStatement extends BinaryOperation<Number, Boolea
}
@Override
public Boolean invoke(ImplementationArguments implementationArguments, Scope scope) {
public Boolean evaluate(ImplementationArguments implementationArguments, Scope scope) {
return applyBoolean(implementationArguments, scope);
}

View File

@@ -21,7 +21,7 @@ public class GreaterThanStatement extends BinaryOperation<Number, Boolean> {
@Override
public Boolean invoke(ImplementationArguments implementationArguments, Scope scope) {
public Boolean evaluate(ImplementationArguments implementationArguments, Scope scope) {
return applyBoolean(implementationArguments, scope);
}

View File

@@ -21,7 +21,7 @@ public class LessThanOrEqualsStatement extends BinaryOperation<Number, Boolean>
@Override
public Boolean invoke(ImplementationArguments implementationArguments, Scope scope) {
public Boolean evaluate(ImplementationArguments implementationArguments, Scope scope) {
return applyBoolean(implementationArguments, scope);
}

View File

@@ -21,7 +21,7 @@ public class LessThanStatement extends BinaryOperation<Number, Boolean> {
@Override
public Boolean invoke(ImplementationArguments implementationArguments, Scope scope) {
public Boolean evaluate(ImplementationArguments implementationArguments, Scope scope) {
return applyBoolean(implementationArguments, scope);
}

View File

@@ -24,14 +24,14 @@ public class NotEqualsStatement extends BinaryOperation<Object, Boolean> {
}
@Override
public Boolean invoke(ImplementationArguments implementationArguments, Scope scope) {
public Boolean evaluate(ImplementationArguments implementationArguments, Scope scope) {
return applyBoolean(implementationArguments, scope);
}
@Override
public boolean applyBoolean(ImplementationArguments implementationArguments, Scope scope) {
Object leftValue = left.invoke(implementationArguments, scope);
Object rightValue = right.invoke(implementationArguments, scope);
Object leftValue = left.evaluate(implementationArguments, scope);
Object rightValue = right.evaluate(implementationArguments, scope);
if(leftValue instanceof Number l && rightValue instanceof Number r) {
return FastMath.abs(l.doubleValue() - r.doubleValue()) > EPSILON;
}

View File

@@ -12,7 +12,12 @@ public class BoolAssignmentNode extends VariableAssignmentNode<Boolean> {
}
@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);
}

View File

@@ -12,7 +12,12 @@ public class NumAssignmentNode extends VariableAssignmentNode<Number> {
}
@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);
}

View File

@@ -12,8 +12,13 @@ public class StrAssignmentNode extends VariableAssignmentNode<String> {
}
@Override
public String invoke(ImplementationArguments implementationArguments, Scope scope) {
String val = value.invoke(implementationArguments, scope);
public ReturnType returnType() {
return ReturnType.STRING;
}
@Override
public String evaluate(ImplementationArguments implementationArguments, Scope scope) {
String val = value.evaluate(implementationArguments, scope);
scope.setStr(index, val);
return val;
}

View File

@@ -12,7 +12,7 @@ import com.dfsek.terra.addons.terrascript.parser.lang.Expression;
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 int index;
private final SourcePosition position;

View File

@@ -11,7 +11,7 @@ public class BoolVariableReferenceNode extends VariableReferenceNode<Boolean> {
}
@Override
public Boolean invoke(ImplementationArguments implementationArguments, Scope scope) {
public Boolean evaluate(ImplementationArguments implementationArguments, Scope scope) {
return scope.getBool(index);
}

View File

@@ -11,7 +11,7 @@ public class NumVariableReferenceNode extends VariableReferenceNode<Number> {
}
@Override
public Number invoke(ImplementationArguments implementationArguments, Scope scope) {
public Number evaluate(ImplementationArguments implementationArguments, Scope scope) {
return scope.getNum(index);
}

View File

@@ -11,7 +11,7 @@ public class StrVariableReferenceNode extends VariableReferenceNode<String> {
}
@Override
public String invoke(ImplementationArguments implementationArguments, Scope scope) {
public String evaluate(ImplementationArguments implementationArguments, Scope scope) {
return scope.getStr(index);
}
}

View File

@@ -36,9 +36,9 @@ public class BinaryNumberFunctionBuilder implements FunctionBuilder<Function<Num
@SuppressWarnings("unchecked")
@Override
public Number invoke(ImplementationArguments implementationArguments, Scope scope) {
return function.apply(((Expression<Number>) argumentList.get(0)).invoke(implementationArguments, scope),
((Expression<Number>) argumentList.get(1)).invoke(implementationArguments, scope));
public Number evaluate(ImplementationArguments implementationArguments, Scope scope) {
return function.apply(((Expression<Number>) argumentList.get(0)).evaluate(implementationArguments, scope),
((Expression<Number>) argumentList.get(1)).evaluate(implementationArguments, scope));
}
@Override

View File

@@ -37,8 +37,8 @@ public class UnaryBooleanFunctionBuilder implements FunctionBuilder<Function<Voi
@SuppressWarnings("unchecked")
@Override
public Void invoke(ImplementationArguments implementationArguments, Scope scope) {
function.accept(((Expression<Boolean>) argumentList.get(0)).invoke(implementationArguments, scope),
public Void evaluate(ImplementationArguments implementationArguments, Scope scope) {
function.accept(((Expression<Boolean>) argumentList.get(0)).evaluate(implementationArguments, scope),
(TerraImplementationArguments) implementationArguments);
return null;
}

View File

@@ -35,8 +35,8 @@ public class UnaryNumberFunctionBuilder implements FunctionBuilder<Function<Numb
@SuppressWarnings("unchecked")
@Override
public Number invoke(ImplementationArguments implementationArguments, Scope scope) {
return function.apply(((Expression<Number>) argumentList.get(0)).invoke(implementationArguments, scope));
public Number evaluate(ImplementationArguments implementationArguments, Scope scope) {
return function.apply(((Expression<Number>) argumentList.get(0)).evaluate(implementationArguments, scope));
}
@Override

View File

@@ -35,8 +35,8 @@ public class UnaryStringFunctionBuilder implements FunctionBuilder<Function<Void
@SuppressWarnings("unchecked")
@Override
public Void invoke(ImplementationArguments implementationArguments, Scope scope) {
function.accept(((Expression<String>) argumentList.get(0)).invoke(implementationArguments, scope));
public Void evaluate(ImplementationArguments implementationArguments, Scope scope) {
function.accept(((Expression<String>) argumentList.get(0)).evaluate(implementationArguments, scope));
return null;
}

View File

@@ -36,7 +36,7 @@ public class ZeroArgFunctionBuilder<T> implements FunctionBuilder<Function<T>> {
}
@Override
public T invoke(ImplementationArguments implementationArguments, Scope scope) {
public T evaluate(ImplementationArguments implementationArguments, Scope scope) {
return function.apply((TerraImplementationArguments) implementationArguments);
}

View File

@@ -35,11 +35,11 @@ public class BiomeFunction implements Function<String> {
@Override
public String invoke(ImplementationArguments implementationArguments, Scope scope) {
public String evaluate(ImplementationArguments implementationArguments, Scope scope) {
TerraImplementationArguments arguments = (TerraImplementationArguments) implementationArguments;
Vector2 xz = RotationUtil.rotateVector(Vector2.of(x.invoke(implementationArguments, scope).doubleValue(),
z.invoke(implementationArguments, scope).doubleValue()),
Vector2 xz = RotationUtil.rotateVector(Vector2.of(x.evaluate(implementationArguments, scope).doubleValue(),
z.evaluate(implementationArguments, scope).doubleValue()),
arguments.getRotation());
@@ -49,7 +49,7 @@ public class BiomeFunction implements Function<String> {
.toVector3()
.mutable()
.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();
}

View File

@@ -49,7 +49,7 @@ public class BlockFunction implements Function<Void> {
}
@Override
public Void invoke(ImplementationArguments implementationArguments, Scope scope) {
public Void evaluate(ImplementationArguments implementationArguments, Scope scope) {
TerraImplementationArguments arguments = (TerraImplementationArguments) implementationArguments;
BlockState rot = getBlockState(implementationArguments, scope);
setBlock(implementationArguments, scope, arguments, rot);
@@ -68,14 +68,14 @@ public class BlockFunction implements Function<Void> {
void setBlock(ImplementationArguments implementationArguments, Scope scope,
TerraImplementationArguments arguments, BlockState rot) {
Vector2 xz = RotationUtil.rotateVector(Vector2.of(x.invoke(implementationArguments, scope).doubleValue(),
z.invoke(implementationArguments, scope).doubleValue()), arguments.getRotation());
Vector2 xz = RotationUtil.rotateVector(Vector2.of(x.evaluate(implementationArguments, scope).doubleValue(),
z.evaluate(implementationArguments, scope).doubleValue()), arguments.getRotation());
try {
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());
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);
}
} catch(RuntimeException e) {
@@ -84,7 +84,7 @@ public class BlockFunction implements Function<Void> {
}
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);
}

View File

@@ -33,11 +33,11 @@ public class CheckBlockFunction implements Function<String> {
@Override
public String invoke(ImplementationArguments implementationArguments, Scope scope) {
public String evaluate(ImplementationArguments implementationArguments, Scope scope) {
TerraImplementationArguments arguments = (TerraImplementationArguments) implementationArguments;
Vector2 xz = RotationUtil.rotateVector(Vector2.of(x.invoke(implementationArguments, scope).doubleValue(),
z.invoke(implementationArguments, scope).doubleValue()),
Vector2 xz = RotationUtil.rotateVector(Vector2.of(x.evaluate(implementationArguments, scope).doubleValue(),
z.evaluate(implementationArguments, scope).doubleValue()),
arguments.getRotation());
@@ -46,7 +46,7 @@ public class CheckBlockFunction implements Function<String> {
.toVector3()
.mutable()
.add(Vector3.of(FastMath.roundToInt(xz.getX()),
y.invoke(implementationArguments, scope)
y.evaluate(implementationArguments, scope)
.doubleValue(), FastMath.roundToInt(xz.getZ()))))
.getAsString();
if(data.contains("[")) return data.substring(0, data.indexOf('[')); // Strip properties

View File

@@ -43,12 +43,12 @@ public class EntityFunction implements Function<Void> {
}
@Override
public Void invoke(ImplementationArguments implementationArguments, Scope scope) {
public Void evaluate(ImplementationArguments implementationArguments, Scope scope) {
TerraImplementationArguments arguments = (TerraImplementationArguments) implementationArguments;
Vector2 xz = RotationUtil.rotateVector(Vector2.of(x.invoke(implementationArguments, scope).doubleValue(),
z.invoke(implementationArguments, scope).doubleValue()), arguments.getRotation());
Vector2 xz = RotationUtil.rotateVector(Vector2.of(x.evaluate(implementationArguments, scope).doubleValue(),
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())
.mutable()
.add(arguments.getOrigin())

View File

@@ -32,13 +32,13 @@ public class GetMarkFunction implements Function<String> {
}
@Override
public String invoke(ImplementationArguments implementationArguments, Scope scope) {
public String evaluate(ImplementationArguments implementationArguments, Scope scope) {
TerraImplementationArguments arguments = (TerraImplementationArguments) implementationArguments;
Vector2 xz = RotationUtil.rotateVector(Vector2.of(x.invoke(implementationArguments, scope).doubleValue(),
z.invoke(implementationArguments, scope).doubleValue()), arguments.getRotation());
Vector2 xz = RotationUtil.rotateVector(Vector2.of(x.evaluate(implementationArguments, scope).doubleValue(),
z.evaluate(implementationArguments, scope).doubleValue()), arguments.getRotation());
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()))
.mutable()
.add(arguments.getOrigin())

View File

@@ -54,20 +54,20 @@ public class LootFunction implements Function<Void> {
}
@Override
public Void invoke(ImplementationArguments implementationArguments, Scope scope) {
public Void evaluate(ImplementationArguments implementationArguments, Scope scope) {
TerraImplementationArguments arguments = (TerraImplementationArguments) implementationArguments;
Vector2 xz = RotationUtil.rotateVector(Vector2.of(x.invoke(implementationArguments, scope).doubleValue(),
z.invoke(implementationArguments, scope).doubleValue()),
Vector2 xz = RotationUtil.rotateVector(Vector2.of(x.evaluate(implementationArguments, scope).doubleValue(),
z.evaluate(implementationArguments, scope).doubleValue()),
arguments.getRotation());
String id = data.invoke(implementationArguments, scope);
String id = data.evaluate(implementationArguments, scope);
registry.get(RegistryKey.parse(id))
.ifPresentOrElse(table -> {
Vector3 apply = Vector3.of(FastMath.roundToInt(xz.getX()),
y.invoke(implementationArguments, scope)
y.evaluate(implementationArguments, scope)
.intValue(),
FastMath.roundToInt(xz.getZ())).mutable().add(arguments.getOrigin()).immutable();

View File

@@ -41,12 +41,12 @@ public class PullFunction implements Function<Void> {
}
@Override
public Void invoke(ImplementationArguments implementationArguments, Scope scope) {
public Void evaluate(ImplementationArguments implementationArguments, Scope scope) {
TerraImplementationArguments arguments = (TerraImplementationArguments) implementationArguments;
Vector2 xz = RotationUtil.rotateVector(Vector2.of(x.invoke(implementationArguments, scope).doubleValue(),
z.invoke(implementationArguments, scope).doubleValue()), arguments.getRotation());
Vector2 xz = RotationUtil.rotateVector(Vector2.of(x.evaluate(implementationArguments, scope).doubleValue(),
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());
while(mutable.getY() > arguments.getWorld().getMinHeight()) {
if(!arguments.getWorld().getBlockState(mutable).isAir()) {

View File

@@ -31,9 +31,9 @@ public class RandomFunction implements Function<Integer> {
}
@Override
public Integer invoke(ImplementationArguments implementationArguments, Scope scope) {
public Integer evaluate(ImplementationArguments implementationArguments, Scope scope) {
return ((TerraImplementationArguments) implementationArguments).getRandom().nextInt(
numberReturnable.invoke(implementationArguments, scope).intValue());
numberReturnable.evaluate(implementationArguments, scope).intValue());
}
@Override

View File

@@ -27,7 +27,7 @@ public class RecursionsFunction implements Function<Number> {
}
@Override
public Number invoke(ImplementationArguments implementationArguments, Scope scope) {
public Number evaluate(ImplementationArguments implementationArguments, Scope scope) {
return ((TerraImplementationArguments) implementationArguments).getRecursions();
}

View File

@@ -34,17 +34,17 @@ public class SetMarkFunction implements Function<Void> {
}
@Override
public Void invoke(ImplementationArguments implementationArguments, Scope scope) {
public Void evaluate(ImplementationArguments implementationArguments, Scope scope) {
TerraImplementationArguments arguments = (TerraImplementationArguments) implementationArguments;
Vector2 xz = RotationUtil.rotateVector(Vector2.of(x.invoke(implementationArguments, scope).doubleValue(),
z.invoke(implementationArguments, scope).doubleValue()), arguments.getRotation());
Vector2 xz = RotationUtil.rotateVector(Vector2.of(x.evaluate(implementationArguments, scope).doubleValue(),
z.evaluate(implementationArguments, scope).doubleValue()), arguments.getRotation());
arguments.setMark(Vector3.of(FastMath.floorToInt(xz.getX()),
FastMath.floorToInt(
y.invoke(implementationArguments, scope).doubleValue()),
y.evaluate(implementationArguments, scope).doubleValue()),
FastMath.floorToInt(xz.getZ())).mutable().add(arguments.getOrigin()).immutable(),
mark.invoke(implementationArguments, scope));
mark.evaluate(implementationArguments, scope));
return null;
}

View File

@@ -39,17 +39,17 @@ public class StateFunction implements Function<Void> {
}
@Override
public Void invoke(ImplementationArguments implementationArguments, Scope scope) {
public Void evaluate(ImplementationArguments implementationArguments, Scope scope) {
TerraImplementationArguments arguments = (TerraImplementationArguments) implementationArguments;
Vector2 xz = RotationUtil.rotateVector(Vector2.of(x.invoke(implementationArguments, scope).doubleValue(),
z.invoke(implementationArguments, scope).doubleValue()), arguments.getRotation());
Vector2 xz = RotationUtil.rotateVector(Vector2.of(x.evaluate(implementationArguments, scope).doubleValue(),
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();
try {
BlockEntity state = arguments.getWorld().getBlockEntity(origin);
state.applyState(data.invoke(implementationArguments, scope));
state.applyState(data.evaluate(implementationArguments, scope));
state.update(false);
} catch(Exception e) {
LOGGER.warn("Could not apply BlockState at {}", origin, e);

View File

@@ -55,20 +55,20 @@ public class StructureFunction implements Function<Boolean> {
}
@Override
public Boolean invoke(ImplementationArguments implementationArguments, Scope scope) {
public Boolean evaluate(ImplementationArguments implementationArguments, Scope scope) {
TerraImplementationArguments arguments = (TerraImplementationArguments) implementationArguments;
if(arguments.getRecursions() > platform.getTerraConfig().getMaxRecursion())
throw new RuntimeException("Structure recursion too deep: " + arguments.getRecursions());
Vector2 xz = RotationUtil.rotateVector(Vector2.of(x.invoke(implementationArguments, scope).doubleValue(),
z.invoke(implementationArguments, scope).doubleValue()), arguments.getRotation());
Vector2 xz = RotationUtil.rotateVector(Vector2.of(x.evaluate(implementationArguments, scope).doubleValue(),
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 -> {
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 {
rotation1 = Rotation.valueOf(rotString);
} catch(IllegalArgumentException e) {
@@ -80,7 +80,7 @@ public class StructureFunction implements Function<Boolean> {
return structureScript.generate(arguments.getOrigin(),
arguments.getWorld()
.buffer(FastMath.roundToInt(xz.getX()),
y.invoke(implementationArguments, scope).intValue(),
y.evaluate(implementationArguments, scope).intValue(),
FastMath.roundToInt(xz.getZ())),
arguments.getRandom(),
arguments.getRotation().rotate(rotation1), arguments.getRecursions() + 1);
@@ -88,7 +88,7 @@ public class StructureFunction implements Function<Boolean> {
return script.generate(arguments.getOrigin(),
arguments.getWorld()
.buffer(FastMath.roundToInt(xz.getX()),
y.invoke(implementationArguments, scope).intValue(),
y.evaluate(implementationArguments, scope).intValue(),
FastMath.roundToInt(xz.getZ())),
arguments.getRandom(),
arguments.getRotation().rotate(rotation1));

View File

@@ -39,6 +39,10 @@ public class Token {
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() {
return type.equals(Type.ADDITION_OPERATOR)
|| type.equals(Type.SUBTRACTION_OPERATOR)
@@ -77,16 +81,12 @@ public class Token {
|| type.equals(Type.NUMBER_VARIABLE);
}
public boolean isLoopLike() {
public boolean isControlStructure() {
return type.equals(Type.IF_STATEMENT)
|| type.equals(Type.WHILE_LOOP)
|| type.equals(Type.FOR_LOOP);
}
public boolean isIdentifier() {
return type.equals(Type.IDENTIFIER);
}
public enum Type {
/**
* Function identifier or language keyword

View File

@@ -11,13 +11,13 @@ import org.junit.jupiter.api.Test;
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
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++) {
System.out.print(lookahead.next(i).getCharacter());

View File

@@ -77,9 +77,9 @@ public class ParserTest {
}
@Override
public Void invoke(ImplementationArguments implementationArguments, Scope scope) {
System.out.println("string: " + a.invoke(implementationArguments, scope) + ", double: " +
b.invoke(implementationArguments, scope));
public Void evaluate(ImplementationArguments implementationArguments, Scope scope) {
System.out.println("string: " + a.evaluate(implementationArguments, scope) + ", double: " +
b.evaluate(implementationArguments, scope));
return null;
}

View File

@@ -37,19 +37,19 @@ public class CheckFunction implements Function<String> {
@Override
public String invoke(ImplementationArguments implementationArguments, Scope scope) {
public String evaluate(ImplementationArguments implementationArguments, Scope scope) {
TerraImplementationArguments arguments = (TerraImplementationArguments) implementationArguments;
Vector2 xz = Vector2.of(x.invoke(implementationArguments, scope).doubleValue(),
z.invoke(implementationArguments, scope).doubleValue());
Vector2 xz = Vector2.of(x.evaluate(implementationArguments, scope).doubleValue(),
z.evaluate(implementationArguments, scope).doubleValue());
RotationUtil.rotateVector(xz, arguments.getRotation());
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();
return apply(location, arguments.getWorld());

View File

@@ -32,16 +32,16 @@ public class ConstantSamplerFunction implements Function<Number> {
}
@Override
public Number invoke(ImplementationArguments implementationArguments, Scope scope) {
public Number evaluate(ImplementationArguments implementationArguments, Scope scope) {
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) {
return sampler.noise(arguments.getWorld().getSeed(), x, z);
} 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);
}
}

View File

@@ -37,17 +37,17 @@ public class SamplerFunction implements Function<Number> {
}
@Override
public Number invoke(ImplementationArguments implementationArguments, Scope scope) {
public Number evaluate(ImplementationArguments implementationArguments, Scope scope) {
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) {
return sampler.noise(arguments.getWorld().getSeed(), x, z);
} 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);
}
}