Change Type enum to interface

Also removes legacy v1 code from v2
This commit is contained in:
Astrash
2023-10-23 13:12:35 +11:00
parent 433d695e8b
commit 375f0ba60f
97 changed files with 329 additions and 4731 deletions

View File

@@ -8,9 +8,6 @@
package com.dfsek.terra.addons.terrascript;
import com.dfsek.terra.addons.manifest.api.AddonInitializer;
import com.dfsek.terra.addons.terrascript.legacy.parser.exceptions.ParseException;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.functions.FunctionBuilder;
import com.dfsek.terra.addons.terrascript.legacy.script.StructureScript;
import com.dfsek.terra.api.Platform;
import com.dfsek.terra.api.addon.BaseAddon;
import com.dfsek.terra.api.event.events.config.pack.ConfigPackPreLoadEvent;
@@ -38,6 +35,7 @@ public class TerraScriptAddon implements AddonInitializer {
.then(event -> {
CheckedRegistry<Structure> structureRegistry = event.getPack().getOrCreateRegistry(Structure.class);
CheckedRegistry<LootTable> lootRegistry = event.getPack().getOrCreateRegistry(LootTable.class);
/*
event.getPack().getLoader().open("", ".tesf").thenEntries(
entries ->
entries.stream()
@@ -58,6 +56,8 @@ public class TerraScriptAddon implements AddonInitializer {
.toList()
.forEach(structureRegistry::register))
.close();
*/
})
.priority(100)
.failThrough();

View File

@@ -2,25 +2,26 @@ package com.dfsek.terra.addons.terrascript;
import java.util.Optional;
// TODO - Make not enum
// TODO - Add integer type
public enum Type {
NUMBER,
STRING,
BOOLEAN,
VOID;
public interface Type {
public java.lang.reflect.Type javaType() {
return switch(this) {
case NUMBER -> double.class;
case STRING -> String.class;
case BOOLEAN -> boolean.class;
case VOID -> void.class;
static Type fromString(String lexeme) throws TypeException {
return switch(lexeme) {
case "num" -> NUMBER;
case "int" -> INTEGER;
case "str" -> STRING;
case "bool" -> BOOLEAN;
case "()" -> VOID;
default -> throw new TypeException();
};
}
public static Optional<Type> from(Class<?> clazz) {
java.lang.reflect.Type javaType();
default boolean typeOf(Type type) {
return this.equals(type);
}
static Optional<Type> from(Class<?> clazz) {
return Optional.ofNullable(
clazz == double.class ? NUMBER :
clazz == String.class ? STRING :
@@ -28,4 +29,69 @@ public enum Type {
clazz == void.class ? VOID :
null);
}
Type NUMBER = new Type() {
@Override
public java.lang.reflect.Type javaType() {
return double.class;
}
@Override
public String toString() {
return "num";
}
};
Type INTEGER = new Type() {
@Override
public java.lang.reflect.Type javaType() {
return int.class;
}
@Override
public String toString() {
return "int";
}
};
Type STRING = new Type() {
@Override
public java.lang.reflect.Type javaType() {
return String.class;
}
@Override
public String toString() {
return "str";
}
};
Type BOOLEAN = new Type() {
@Override
public java.lang.reflect.Type javaType() {
return boolean.class;
}
@Override
public String toString() {
return "bool";
}
};
Type VOID = new Type() {
@Override
public java.lang.reflect.Type javaType() {
return void.class;
}
@Override
public String toString() {
return "()";
}
};
class TypeException extends Exception {
}
}

View File

@@ -0,0 +1,141 @@
package com.dfsek.terra.addons.terrascript.codegen;
import com.dfsek.terra.addons.terrascript.Type;
import com.dfsek.terra.addons.terrascript.exception.CompilerBugException;
import org.objectweb.asm.Opcodes;
import java.util.Map;
public class CodegenType {
private final InstructionType instructionType;
private final String descriptor;
public CodegenType(InstructionType instructionType, String descriptor) {
this.instructionType = instructionType;
this.descriptor = descriptor;
}
public InstructionType bytecodeType() {
return instructionType;
}
public String getDescriptor() {
return descriptor;
}
public static final CodegenType BOOLEAN_PRIMITIVE = new CodegenType(InstructionType.INTEGER, "Z");
private static final Map<Type, CodegenType> TYPE_MAP = Map.of(
Type.BOOLEAN, BOOLEAN_PRIMITIVE,
Type.STRING, new CodegenType(InstructionType.OBJECT, "Ljava/lang/String;"),
Type.NUMBER, new CodegenType(InstructionType.DOUBLE, "D"),
Type.VOID, new CodegenType(InstructionType.VOID, "V")
);
public static CodegenType codegenType(Type type) {
CodegenType out = TYPE_MAP.get(type);
if(out == null)
throw new CompilerBugException();
return out;
}
public enum InstructionType {
DOUBLE {
@Override
public int slotSize() {
return 2;
}
@Override
public int returnInsn() {
return Opcodes.DRETURN;
}
@Override
public int loadInsn() {
return Opcodes.DLOAD;
}
@Override
public int storeInsn() {
return Opcodes.DSTORE;
}
},
OBJECT {
@Override
public int slotSize() {
return 1;
}
@Override
public int returnInsn() {
return Opcodes.ARETURN;
}
@Override
public int loadInsn() {
return Opcodes.ALOAD;
}
@Override
public int storeInsn() {
return Opcodes.ASTORE;
}
},
INTEGER {
@Override
public int slotSize() {
return 1;
}
@Override
public int returnInsn() {
return Opcodes.IRETURN;
}
@Override
public int loadInsn() {
return Opcodes.ILOAD;
}
@Override
public int storeInsn() {
return Opcodes.ISTORE;
}
},
VOID {
@Override
public int slotSize() {
throw new UnsupportedOperationException();
}
@Override
public int returnInsn() {
return Opcodes.RETURN;
}
@Override
public int loadInsn() {
throw new UnsupportedOperationException();
}
@Override
public int storeInsn() {
throw new UnsupportedOperationException();
}
};
public abstract int slotSize();
public abstract int returnInsn();
public abstract int loadInsn();
public abstract int storeInsn();
}
}

View File

@@ -23,6 +23,8 @@ import com.dfsek.terra.addons.terrascript.ast.TypedStmt.Return;
import com.dfsek.terra.addons.terrascript.ast.TypedStmt.VariableDeclaration;
import com.dfsek.terra.addons.terrascript.ast.TypedStmt.While;
import com.dfsek.terra.addons.terrascript.codegen.CodegenType;
import com.dfsek.terra.addons.terrascript.codegen.CodegenType.InstructionType;
import com.dfsek.terra.addons.terrascript.codegen.NativeFunction;
import com.dfsek.terra.addons.terrascript.codegen.TerraScript;
import com.dfsek.terra.addons.terrascript.exception.CompilerBugException;
@@ -45,7 +47,10 @@ import java.util.Deque;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import static com.dfsek.terra.addons.terrascript.codegen.CodegenType.BOOLEAN_PRIMITIVE;
import static com.dfsek.terra.addons.terrascript.codegen.CodegenType.codegenType;
import static com.dfsek.terra.addons.terrascript.codegen.asm.OpcodeAlias.CMP_EQUALS;
import static com.dfsek.terra.addons.terrascript.codegen.asm.OpcodeAlias.BOOL_FALSE;
import static com.dfsek.terra.addons.terrascript.codegen.asm.OpcodeAlias.CMP_GREATER_EQUALS;
@@ -175,12 +180,13 @@ public class TerraScriptClassGenerator {
case EQUALS, NOT_EQUALS, BOOLEAN_AND, BOOLEAN_OR, GREATER, GREATER_EQUALS, LESS, LESS_EQUALS -> pushComparisonBool(expr);
case ADD -> {
pushBinaryOperands(expr);
switch(expr.type) {
case NUMBER -> method.visitInsn(Opcodes.DADD);
CodegenType codegenType = codegenType(expr.type);
if(codegenType.bytecodeType() == InstructionType.DOUBLE)
method.visitInsn(Opcodes.DADD);
else if (Objects.equals(codegenType.getDescriptor(), "Ljava/lang/String;"))
// TODO - Optimize string concatenation
case STRING -> method.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/String", "concat", "(Ljava/lang/String;)Ljava/lang/String;", false);
default -> throw new RuntimeException("Could not generate bytecode for ADD binary operator returning type " + expr.type);
}
method.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/String", "concat", "(Ljava/lang/String;)Ljava/lang/String;", false);
else throw new RuntimeException("Could not generate bytecode for ADD binary operator returning type " + expr.type);
}
case SUBTRACT -> binaryInsn(expr, Opcodes.DSUB);
case MULTIPLY -> binaryInsn(expr, Opcodes.DMUL);
@@ -198,10 +204,9 @@ public class TerraScriptClassGenerator {
@Override
public Void visitLiteralTypedExpr(Literal expr) {
switch (expr.type) {
case BOOLEAN -> { if ((boolean) expr.value) pushTrue(); else pushFalse(); }
case NUMBER, STRING -> method.visitLdcInsn(expr.value);
}
if(codegenType(expr.type) == BOOLEAN_PRIMITIVE)
if ((boolean) expr.value) pushTrue(); else pushFalse();
else method.visitLdcInsn(expr.value);
return null;
}
@@ -233,12 +238,7 @@ public class TerraScriptClassGenerator {
@Override
public Void visitVariableTypedExpr(Variable expr) {
Type varType = expr.type;
method.visitVarInsn(switch(varType) {
case NUMBER -> Opcodes.DLOAD;
case STRING -> Opcodes.ALOAD;
case BOOLEAN -> Opcodes.ILOAD;
default -> throw new RuntimeException("Unable to load local variable, unhandled type '" + varType + "'");
}, lvTable.get(expr.identifier));
method.visitVarInsn(codegenType(varType).bytecodeType().loadInsn(), lvTable.get(expr.identifier));
return null;
}
@@ -246,12 +246,7 @@ public class TerraScriptClassGenerator {
public Void visitAssignmentTypedExpr(Assignment expr) {
expr.rValue.accept(this);
Type type = expr.lValue.type;
method.visitVarInsn(switch(type) {
case NUMBER -> Opcodes.DSTORE;
case STRING -> Opcodes.ASTORE;
case BOOLEAN -> Opcodes.ISTORE;
default -> throw new RuntimeException("Unable to assign local variable, unhandled type '" + type + "'");
}, lvTable.get(expr.lValue.identifier));
method.visitVarInsn(codegenType(type).bytecodeType().storeInsn(), lvTable.get(expr.lValue.identifier));
return null;
}
@@ -293,11 +288,7 @@ public class TerraScriptClassGenerator {
int lvidx = 0;
for (Pair<String, Type> parameter : stmt.parameters) {
funcGenerator.lvTable.put(parameter.getLeft(), lvidx);
lvidx += switch(parameter.getRight()) { // Increment by how many slots data type takes
case NUMBER -> 2;
case STRING, BOOLEAN -> 1;
default -> throw new RuntimeException("Unable to register local variable index for parameter, unknown parameter type '" + parameter.getRight() + "'");
};
lvidx += codegenType(parameter.getRight()).bytecodeType().slotSize(); // Increment by how many slots data type takes
}
// Generate method bytecode
@@ -315,24 +306,14 @@ public class TerraScriptClassGenerator {
public Void visitVariableDeclarationTypedStmt(VariableDeclaration stmt) {
stmt.value.accept(this);
lvTable.put(stmt.identifier, lvs.newLocal(ASMUtil.tsTypeToAsmType(stmt.type)));
method.visitVarInsn(switch(stmt.type) {
case NUMBER -> Opcodes.DSTORE;
case STRING -> Opcodes.ASTORE;
case BOOLEAN -> Opcodes.ISTORE;
default -> throw new RuntimeException("Unable to declare local variable, unknown parameter type '" + stmt.type + "'");
}, lvTable.get(stmt.identifier));
method.visitVarInsn(codegenType(stmt.type).bytecodeType().storeInsn(), lvTable.get(stmt.identifier));
return null;
}
@Override
public Void visitReturnTypedStmt(Return stmt) {
stmt.value.accept(this);
switch(stmt.value.type) {
case NUMBER -> method.visitInsn(Opcodes.DRETURN);
case STRING -> method.visitInsn(Opcodes.ARETURN);
case BOOLEAN -> method.visitInsn(Opcodes.IRETURN);
default -> throw new CompilerBugException();
}
method.visitInsn(codegenType(stmt.value.type).bytecodeType().returnInsn());
return null;
}
@@ -557,19 +538,9 @@ public class TerraScriptClassGenerator {
private String getFunctionDescriptor(List<Type> parameters, Type returnType) {
StringBuilder sb = new StringBuilder().append("(");
parameters.stream().map(p -> switch (p) {
case NUMBER -> "D";
case STRING -> "Ljava/lang/String;";
case BOOLEAN -> "Z";
default -> throw new RuntimeException("Unable to generate method descriptor, unknown parameter type '" + p + "'");
}).forEach(sb::append);
parameters.stream().map(parameter -> codegenType(parameter).getDescriptor()).forEach(sb::append);
sb.append(")");
sb.append(switch (returnType) {
case NUMBER -> "D";
case STRING -> "Ljava/lang/String;";
case BOOLEAN -> "Z";
case VOID -> "V";
});
sb.append(codegenType(returnType).getDescriptor());
return sb.toString();
}
}

View File

@@ -9,8 +9,8 @@ package com.dfsek.terra.addons.terrascript.exception.lexer;
import java.io.Serial;
import com.dfsek.terra.addons.terrascript.legacy.parser.exceptions.ParseException;
import com.dfsek.terra.addons.terrascript.lexer.SourcePosition;
import com.dfsek.terra.addons.terrascript.parser.ParseException;
public abstract class TokenizerException extends ParseException {

View File

@@ -1,589 +0,0 @@
/*
* Copyright (c) 2020-2021 Polyhedral Development
*
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
* reference the LICENSE file in this module's root directory.
*/
package com.dfsek.terra.addons.terrascript.legacy.parser;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
import java.util.function.Function;
import com.dfsek.terra.addons.terrascript.Type;
import com.dfsek.terra.addons.terrascript.legacy.parser.exceptions.ParseException;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.Block;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.Executable;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.Expression;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.Scope;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.constants.BooleanConstant;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.constants.NumericConstant;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.constants.StringConstant;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.functions.FunctionBuilder;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.functions.UserDefinedFunctionBuilder;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.keywords.flow.BreakKeyword;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.keywords.flow.ContinueKeyword;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.keywords.flow.FailKeyword;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.keywords.flow.ReturnKeyword;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.keywords.looplike.ForKeyword;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.keywords.looplike.IfKeyword;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.keywords.looplike.WhileKeyword;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.operations.BooleanAndOperation;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.operations.BooleanNotOperation;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.operations.BooleanOrOperation;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.operations.ConcatenationOperation;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.operations.DivisionOperation;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.operations.ModuloOperation;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.operations.MultiplicationOperation;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.operations.NegationOperation;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.operations.NumberAdditionOperation;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.operations.SubtractionOperation;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.operations.statements.EqualsStatement;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.operations.statements.GreaterOrEqualsThanStatement;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.operations.statements.GreaterThanStatement;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.operations.statements.LessThanOrEqualsStatement;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.operations.statements.LessThanStatement;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.operations.statements.NotEqualsStatement;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.variables.assign.BoolAssignmentNode;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.variables.assign.NumAssignmentNode;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.variables.assign.StrAssignmentNode;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.variables.assign.VariableAssignmentNode;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.variables.reference.BoolVariableReferenceNode;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.variables.reference.NumVariableReferenceNode;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.variables.reference.StrVariableReferenceNode;
import com.dfsek.terra.addons.terrascript.lexer.Lexer;
import com.dfsek.terra.addons.terrascript.lexer.SourcePosition;
import com.dfsek.terra.addons.terrascript.lexer.Token;
import com.dfsek.terra.addons.terrascript.lexer.Token.TokenType;
import com.dfsek.terra.api.util.generic.pair.Pair;
public class Parser {
private final List<String> ignoredFunctions = new ArrayList<>();
private final Lexer lexer;
public Parser(Lexer lexer) {
this.lexer = lexer;
}
/**
* Parse input
*
* @return executable {@link Block}
*
* @throws ParseException If parsing fails.
*/
public Executable parse(Scope.ScopeBuilder scopeBuilder) {
return new Executable(parseBlock(scopeBuilder, Type.VOID), scopeBuilder);
}
private WhileKeyword parseWhileLoop(Scope.ScopeBuilder scopeBuilder) {
SourcePosition start = lexer.consume("Expected 'while' keyword at beginning of while loop", TokenType.WHILE_LOOP).position();
lexer.consume("Expected '(' proceeding 'while' keyword", TokenType.OPEN_PAREN);
scopeBuilder = scopeBuilder.innerLoopScope();
Expression<?> condition = parseExpression(scopeBuilder);
ParserUtil.ensureReturnType(condition, Type.BOOLEAN);
lexer.consume("Expected ')' proceeding while loop condition", TokenType.CLOSE_PAREN);
return new WhileKeyword(parseStatementBlock(scopeBuilder, Type.VOID), (Expression<Boolean>) condition,
start); // While loop
}
private IfKeyword parseIfStatement(Scope.ScopeBuilder scopeBuilder) {
SourcePosition start = lexer.consume("Expected 'if' keyword at beginning of if statement", TokenType.IF_STATEMENT).position();
lexer.consume("Expected '(' proceeding 'if' keyword", TokenType.OPEN_PAREN);
Expression<?> condition = parseExpression(scopeBuilder);
ParserUtil.ensureReturnType(condition, Type.BOOLEAN);
lexer.consume("Expected ')' proceeding if statement condition", TokenType.CLOSE_PAREN);
Block elseBlock = null;
Block statement = parseStatementBlock(scopeBuilder, Type.VOID);
List<Pair<Expression<Boolean>, Block>> elseIf = new ArrayList<>();
while(lexer.hasNext() && lexer.current().isType(TokenType.ELSE)) {
lexer.consumeUnchecked(); // Consume else.
if(lexer.current().isType(TokenType.IF_STATEMENT)) {
lexer.consumeUnchecked(); // Consume if.
Expression<?> elseCondition = parseExpression(scopeBuilder);
ParserUtil.ensureReturnType(elseCondition, Type.BOOLEAN);
elseIf.add(Pair.of((Expression<Boolean>) elseCondition, parseStatementBlock(scopeBuilder, Type.VOID)));
} else {
elseBlock = parseStatementBlock(scopeBuilder, Type.VOID);
break; // Else must be last.
}
}
return new IfKeyword(statement, (Expression<Boolean>) condition, elseIf, elseBlock, start); // If statement
}
private Block parseStatementBlock(Scope.ScopeBuilder scopeBuilder, Type blockReturnType) {
if(lexer.current().isType(TokenType.BLOCK_BEGIN)) {
lexer.consumeUnchecked();
Block block = parseBlock(scopeBuilder, blockReturnType);
lexer.consume("Expected block end '}' after block statements", TokenType.BLOCK_END);
return block;
} else {
SourcePosition position = lexer.current().position();
return new Block(Collections.singletonList(parseStatement(scopeBuilder)), position, blockReturnType);
}
}
private ForKeyword parseForLoop(Scope.ScopeBuilder scopeBuilder) {
SourcePosition start = lexer.consume("Expected 'for' keyword at beginning of for loop", TokenType.FOR_LOOP).position();
lexer.consume("Expected '(' after 'for' keyword", TokenType.OPEN_PAREN);
scopeBuilder = scopeBuilder.innerLoopScope(); // new scope
Expression<?> initializer = switch(lexer.current().type()) {
case TYPE_NUMBER, TYPE_STRING, TYPE_BOOLEAN -> {
Token type = lexer.consume("Expected type before declaration", TokenType.TYPE_STRING, TokenType.TYPE_NUMBER,
TokenType.TYPE_BOOLEAN, TokenType.TYPE_VOID);
Token identifier = lexer.consume("Expected identifier after type", TokenType.IDENTIFIER);
Expression<?> expr = parseVariableDeclaration(scopeBuilder, type, identifier);
lexer.consume("Expected ';' after initializer within for loop", TokenType.STATEMENT_END);
yield expr;
}
case IDENTIFIER -> {
Expression<?> expr = parseAssignment(scopeBuilder);
lexer.consume("Expected ';' after initializer within for loop", TokenType.STATEMENT_END);
yield expr;
}
case STATEMENT_END -> {
lexer.consumeUnchecked();
yield Expression.NOOP;
}
default -> throw new ParseException("Unexpected token '" + lexer.current() + "', expected variable declaration or assignment",
lexer.current().position());
};
Expression<?> conditional;
if(lexer.current().isType(TokenType.STATEMENT_END)) // If no conditional is provided, conditional defaults to true
conditional = new BooleanConstant(true, lexer.current().position());
else
conditional = parseExpression(scopeBuilder);
ParserUtil.ensureReturnType(conditional, Type.BOOLEAN);
lexer.consume("Expected ';' separator after conditional within for loop", TokenType.STATEMENT_END);
Expression<?> incrementer;
if(lexer.current().isType(TokenType.CLOSE_PAREN))
// If no incrementer is provided, do nothing
incrementer = Expression.NOOP;
else if(scopeBuilder.containsVariable(lexer.current().lexeme())) // Assume variable assignment
incrementer = parseAssignment(scopeBuilder);
else
incrementer = parseFunctionInvocation(
lexer.consume("Expected function call within for loop incrementer, found '" + lexer.current().lexeme() + "' instead",
TokenType.IDENTIFIER), scopeBuilder);
lexer.consume("Expected ')' after for loop incrementer", TokenType.CLOSE_PAREN);
return new ForKeyword(parseStatementBlock(scopeBuilder, Type.VOID), initializer, (Expression<Boolean>) conditional,
incrementer,
start);
}
private Expression<?> parseExpression(Scope.ScopeBuilder scopeBuilder) {
return parseLogicOr(scopeBuilder);
}
private Expression<?> parseLogicOr(Scope.ScopeBuilder scopeBuilder) {
return parseLeftAssociativeBinaryOperation(this::parseLogicAnd, scopeBuilder, (op) -> {
ParserUtil.ensureReturnType(op.left, Type.BOOLEAN);
ParserUtil.ensureReturnType(op.right, Type.BOOLEAN);
}, Map.of(TokenType.BOOLEAN_OR,
(op) -> new BooleanOrOperation((Expression<Boolean>) op.left, (Expression<Boolean>) op.right, op.operator.position())));
}
private Expression<?> parseLogicAnd(Scope.ScopeBuilder scopeBuilder) {
return parseLeftAssociativeBinaryOperation(this::parseEquality, scopeBuilder, (op) -> {
ParserUtil.ensureReturnType(op.left, Type.BOOLEAN);
ParserUtil.ensureReturnType(op.right, Type.BOOLEAN);
}, Map.of(TokenType.BOOLEAN_AND,
(op) -> new BooleanAndOperation((Expression<Boolean>) op.left, (Expression<Boolean>) op.right, op.operator.position())));
}
private Expression<?> parseEquality(Scope.ScopeBuilder scopeBuilder) {
return parseLeftAssociativeBinaryOperation(this::parseComparison, scopeBuilder, Map.of(
TokenType.EQUALS_EQUALS,
(op) -> new EqualsStatement((Expression<Object>) op.left, (Expression<Object>) op.right, op.operator.position()),
TokenType.BANG_EQUALS,
(op) -> new NotEqualsStatement((Expression<Object>) op.left, (Expression<Object>) op.right, op.operator.position())
));
}
private Expression<?> parseComparison(Scope.ScopeBuilder scopeBuilder) {
return parseLeftAssociativeBinaryOperation(this::parseTerm, scopeBuilder, (op) -> {
ParserUtil.ensureReturnType(op.left, Type.NUMBER);
ParserUtil.ensureReturnType(op.right, Type.NUMBER);
}, Map.of(
TokenType.LESS,
(op) -> new LessThanStatement((Expression<Number>) op.left, (Expression<Number>) op.right, op.operator.position()),
TokenType.LESS_EQUALS,
(op) -> new LessThanOrEqualsStatement((Expression<Number>) op.left, (Expression<Number>) op.right, op.operator.position()),
TokenType.GREATER,
(op) -> new GreaterThanStatement((Expression<Number>) op.left, (Expression<Number>) op.right, op.operator.position()),
TokenType.GREATER_EQUAL,
(op) -> new GreaterOrEqualsThanStatement((Expression<Number>) op.left, (Expression<Number>) op.right,
op.operator.position())
));
}
private Expression<?> parseTerm(Scope.ScopeBuilder scopeBuilder) {
return parseLeftAssociativeBinaryOperation(this::parseFactor, scopeBuilder, Map.of(
TokenType.MINUS, (op) -> {
ParserUtil.ensureReturnType(op.left, Type.NUMBER);
ParserUtil.ensureReturnType(op.right, Type.NUMBER);
return new SubtractionOperation((Expression<Number>) op.left, (Expression<Number>) op.right, op.operator.position());
},
TokenType.PLUS, (op) -> {
if(op.left.returnType() == Type.NUMBER && op.right.returnType() == Type.NUMBER)
return new NumberAdditionOperation((Expression<Number>) op.left, (Expression<Number>) op.right,
op.operator.position());
else
return new ConcatenationOperation((Expression<Object>) op.left, (Expression<Object>) op.right,
op.operator.position());
}));
}
private Expression<?> parseFactor(Scope.ScopeBuilder scopeBuilder) {
return parseLeftAssociativeBinaryOperation(this::parseUnary, scopeBuilder, (op) -> {
ParserUtil.ensureReturnType(op.left, Type.NUMBER);
ParserUtil.ensureReturnType(op.right, Type.NUMBER);
}, Map.of(
TokenType.STAR,
(op) -> new MultiplicationOperation((Expression<Number>) op.left, (Expression<Number>) op.right, op.operator.position()),
TokenType.FORWARD_SLASH,
(op) -> new DivisionOperation((Expression<Number>) op.left, (Expression<Number>) op.right, op.operator.position()),
TokenType.MODULO_OPERATOR,
(op) -> new ModuloOperation((Expression<Number>) op.left, (Expression<Number>) op.right, op.operator.position())
));
}
private Expression<?> parseUnary(Scope.ScopeBuilder scopeBuilder) {
if(lexer.current().isType(TokenType.BANG, TokenType.MINUS)) {
Token operator = lexer.consumeUnchecked();
Expression<?> right = parseUnary(scopeBuilder);
return switch(operator.type()) {
case BANG -> {
ParserUtil.ensureReturnType(right, Type.BOOLEAN);
yield new BooleanNotOperation((Expression<Boolean>) right, operator.position());
}
case MINUS -> {
ParserUtil.ensureReturnType(right, Type.NUMBER);
yield new NegationOperation((Expression<Number>) right, operator.position());
}
default -> throw new IllegalStateException();
};
}
return parsePrimary(scopeBuilder);
}
private Expression<?> parsePrimary(Scope.ScopeBuilder scopeBuilder) {
Token token = lexer.consumeUnchecked();
return switch(token.type()) {
case NUMBER -> {
String content = token.lexeme();
yield new NumericConstant(content.contains(".") ? Double.parseDouble(content) : Integer.parseInt(content),
token.position());
}
case STRING -> new StringConstant(token.lexeme(), token.position());
case BOOLEAN -> new BooleanConstant(Boolean.parseBoolean(token.lexeme()), token.position());
case OPEN_PAREN -> {
Expression<?> expr = parseExpression(scopeBuilder);
lexer.consume("Missing ')' at end of expression group", TokenType.CLOSE_PAREN);
yield expr;
}
case IDENTIFIER -> {
if(scopeBuilder.containsFunction(token.lexeme()))
yield parseFunctionInvocation(token, scopeBuilder);
else if(scopeBuilder.containsVariable(token.lexeme())) {
Type variableType = scopeBuilder.getVaraibleType(token.lexeme());
yield switch(variableType) {
case NUMBER -> new NumVariableReferenceNode(token.position(), variableType, scopeBuilder.getIndex(token.lexeme()));
case BOOLEAN -> new BoolVariableReferenceNode(token.position(), variableType,
scopeBuilder.getIndex(token.lexeme()));
case STRING -> new StrVariableReferenceNode(token.position(), variableType, scopeBuilder.getIndex(token.lexeme()));
default -> throw new ParseException("Illegal type for variable reference: " + variableType, token.position());
};
}
throw new ParseException("Identifier '" + token.lexeme() + "' is not defined in this scope", token.position());
}
default -> throw new ParseException("Unexpected token '" + token.lexeme() + "' when parsing expression", token.position());
};
}
/**
* Parses expressions of higher precedence, then sequentially parses any binary operators of the same
* precedence from left to right. Operands for each operation are parsed with the higher precedence rule first.
* <p>
* E.g. for expression <pre>'a * b + c - d * e + f'</pre> where - and + are at same precedence, and * at a higher precedence:
* <pre>
* 1. Start parsing higher precedence:
* a ...
*
* 2. Higher precedence stops because +:
* (a * b) + ...
*
* 3. Parse right of + at higher precedence until current precedence operator or end:
* (a * b) + (c) - ...
*
* 4. Group as one expression:
* ((a * b) + (c)) - ...
*
* 5. Repeat 3-4 until end of expression:
* ((((a * b) + (c)) - (d * e)) + (f))
* </pre>
*
* @param higherPrecedence Parsing rule for expression of higher precedence
* @param scopeBuilder
* @param init Initial code to run for any matching operands + operator
* @param operators List of binary operators of this precedence mapped to how to parse them
*
* @return
*/
private Expression<?> parseLeftAssociativeBinaryOperation(Function<Scope.ScopeBuilder, Expression<?>> higherPrecedence,
Scope.ScopeBuilder scopeBuilder,
Consumer<BinaryOperationInfo> init,
Map<TokenType, Function<BinaryOperationInfo, Expression<?>>> operators) {
Expression<?> expr = higherPrecedence.apply(scopeBuilder);
TokenType[] opTypes = operators.keySet().toArray(new TokenType[0]);
while(lexer.current().isType(opTypes)) { // Parse binary operator if a matching token of this precedence
Token operator = lexer.consumeUnchecked();
Expression<?> right = higherPrecedence.apply(scopeBuilder);
BinaryOperationInfo op = new BinaryOperationInfo(expr, operator, right);
init.accept(op);
expr = operators.get(operator.type()).apply(op);
}
return expr;
}
private Expression<?> parseLeftAssociativeBinaryOperation(Function<Scope.ScopeBuilder, Expression<?>> higherPrecedence,
Scope.ScopeBuilder scopeBuilder,
Map<TokenType, Function<BinaryOperationInfo, Expression<?>>> operators) {
return parseLeftAssociativeBinaryOperation(higherPrecedence, scopeBuilder, (op) -> { }, operators);
}
private record BinaryOperationInfo(Expression<?> left, Token operator, Expression<?> right) {
}
private Expression<?> parseDeclaration(Scope.ScopeBuilder scopeBuilder) {
Token type = lexer.consume("Expected type before declaration", TokenType.TYPE_STRING, TokenType.TYPE_NUMBER, TokenType.TYPE_BOOLEAN,
TokenType.TYPE_VOID);
Token identifier = lexer.consume("Expected identifier after type", TokenType.IDENTIFIER);
return switch(lexer.current().type()) {
case ASSIGNMENT -> parseVariableDeclaration(scopeBuilder, type, identifier);
case OPEN_PAREN -> parseFunctionDeclaration(scopeBuilder, type, identifier);
default -> throw new ParseException(
"Expected '=' for variable assignment or '(' for function declaration after identifier '" + identifier.lexeme() + "'",
lexer.current().position());
};
}
private Expression<?> parseVariableDeclaration(Scope.ScopeBuilder scopeBuilder, Token type, Token identifier) {
lexer.consume("Expected '=' after identifier '" + identifier.lexeme() + "' for variable declaration", TokenType.ASSIGNMENT);
if(!(type.isType(TokenType.TYPE_STRING)
|| type.isType(TokenType.TYPE_BOOLEAN)
|| type.isType(TokenType.TYPE_NUMBER))) throw new ParseException("Expected type specification at beginning of variable declaration",
type.position());
if(scopeBuilder.containsVariable(identifier.lexeme()))
throw new ParseException(identifier.lexeme() + " is already defined in this scope", identifier.position());
Expression<?> value = parseExpression(scopeBuilder);
ParserUtil.ensureReturnType(value, ParserUtil.getVariableReturnType(type));
String variableName = identifier.lexeme();
return switch(value.returnType()) {
case NUMBER -> new NumAssignmentNode((Expression<Number>) value, identifier.position(),
scopeBuilder.declareNum(variableName));
case STRING -> new StrAssignmentNode((Expression<String>) value, identifier.position(),
scopeBuilder.declareStr(variableName));
case BOOLEAN -> new BoolAssignmentNode((Expression<Boolean>) value, identifier.position(),
scopeBuilder.declareBool(variableName));
default -> throw new ParseException("Illegal type for variable declaration: " + type, value.getPosition());
};
}
private Expression<?> parseFunctionDeclaration(Scope.ScopeBuilder scopeBuilder, Token type, Token identifier) {
lexer.consume("Expected '(' after identifier '" + identifier.lexeme() + "' for function declaration", TokenType.OPEN_PAREN);
if(!(type.isType(TokenType.TYPE_STRING, TokenType.TYPE_BOOLEAN, TokenType.TYPE_NUMBER, TokenType.TYPE_VOID)))
throw new ParseException("Invalid function declaration return type specification " + type.type(), type.position());
if(scopeBuilder.containsVariable(identifier.lexeme()))
throw new ParseException(identifier.lexeme() + " is already defined in this scope", identifier.position());
Type returnType = ParserUtil.getVariableReturnType(type);
Scope.ScopeBuilder functionBodyScope = scopeBuilder.functionScope();
// Declare parameter names into function body scope
List<Pair<Integer, Type>> parameterInfo = getFunctionParameterDeclaration().stream().map(
arg -> Pair.of(switch(arg.getRight()) {
case NUMBER -> functionBodyScope.declareNum(arg.getLeft());
case BOOLEAN -> functionBodyScope.declareBool(arg.getLeft());
case STRING -> functionBodyScope.declareStr(arg.getLeft());
default -> throw new IllegalArgumentException("Unsupported parameter type: " + arg.getRight());
}, arg.getRight())).toList();
Block body = parseStatementBlock(functionBodyScope, returnType);
FunctionBuilder<?> functionBuilder = new UserDefinedFunctionBuilder<>(returnType, parameterInfo, body, functionBodyScope);
scopeBuilder.registerFunction(identifier.lexeme(), functionBuilder);
return Expression.NOOP;
}
private List<Pair<String, Type>> getFunctionParameterDeclaration() {
List<Pair<String, Type>> parameters = new ArrayList<>();
while(lexer.current().type() != TokenType.CLOSE_PAREN) {
// Parse parameter type
Token typeToken = lexer.consume("Expected function parameter type declaration", TokenType.TYPE_BOOLEAN, TokenType.TYPE_STRING,
TokenType.TYPE_NUMBER);
Type type = ParserUtil.getVariableReturnType(typeToken);
// Parse parameter name
Token identifierToken = lexer.consume("Expected function parameter identifier", TokenType.IDENTIFIER);
String name = identifierToken.lexeme();
parameters.add(Pair.of(name, type));
// Consume separator if present, trailing separators are allowed
if(lexer.current().isType(TokenType.SEPARATOR)) lexer.consumeUnchecked();
}
lexer.consume("Expected ')' after function parameter declaration", TokenType.CLOSE_PAREN);
return parameters;
}
private Block parseBlock(Scope.ScopeBuilder scopeBuilder, Type blockReturnType) {
List<Expression<?>> expressions = new ArrayList<>();
scopeBuilder = scopeBuilder.innerScope(); // Create new inner scope for the block
SourcePosition startPosition = lexer.current().position();
boolean hasReturn = false;
// Parse each statement
while(lexer.hasNext() && !lexer.current().isType(TokenType.BLOCK_END)) {
Expression<?> expression = parseStatement(scopeBuilder);
if(expression != Expression.NOOP) {
expressions.add(expression);
}
if(expression instanceof ReturnKeyword returnKeyword) {
hasReturn = true;
if(returnKeyword.dataReturnType() != blockReturnType)
throw new ParseException(
"Invalid return type, expected " + blockReturnType + ", found " + returnKeyword.dataReturnType(),
expression.getPosition());
}
}
if(blockReturnType != Type.VOID && !hasReturn)
throw new ParseException("Block does not contain a return statement, must return type " + blockReturnType, startPosition);
return new Block(expressions, startPosition, blockReturnType);
}
private Expression<?> parseStatement(Scope.ScopeBuilder scopeBuilder) {
Token token = lexer.current();
Expression<?> expression = switch(token.type()) {
case FOR_LOOP -> parseForLoop(scopeBuilder);
case IF_STATEMENT -> parseIfStatement(scopeBuilder);
case WHILE_LOOP -> parseWhileLoop(scopeBuilder);
case IDENTIFIER -> {
if(scopeBuilder.containsVariable(token.lexeme())) yield parseAssignment(scopeBuilder); // Assume variable assignment
else yield parseFunctionInvocation(lexer.consumeUnchecked(), scopeBuilder);
}
case TYPE_NUMBER, TYPE_STRING, TYPE_BOOLEAN, TYPE_VOID -> parseDeclaration(scopeBuilder);
case RETURN -> parseReturn(scopeBuilder);
case BREAK -> {
if(!scopeBuilder.isInLoop()) throw new ParseException("Break statements can only be defined inside loops",
token.position());
yield new BreakKeyword(lexer.consumeUnchecked().position());
}
case CONTINUE -> {
if(!scopeBuilder.isInLoop()) throw new ParseException("Continue statements can only be defined inside loops",
token.position());
yield new ContinueKeyword(lexer.consumeUnchecked().position());
}
case FAIL -> new FailKeyword(lexer.consumeUnchecked().position());
case STATEMENT_END -> Expression.NOOP;
default -> throw new ParseException("Unexpected token '" + token.lexeme() + "' while parsing statement", token.position());
};
if(!(token.isType(TokenType.IF_STATEMENT)
|| token.isType(TokenType.WHILE_LOOP)
|| token.isType(TokenType.FOR_LOOP)) && expression != Expression.NOOP) lexer.consume("Expected ';' at end of statement",
TokenType.STATEMENT_END);
return expression;
}
private ReturnKeyword parseReturn(Scope.ScopeBuilder scopeBuilder) {
Token returnToken = lexer.consume("Expected 'return' keyword at beginning of return statement", TokenType.RETURN);
Expression<?> data = null;
if(!lexer.current().isType(TokenType.STATEMENT_END)) {
data = parseExpression(scopeBuilder);
}
return new ReturnKeyword(data, returnToken.position());
}
private VariableAssignmentNode<?> parseAssignment(Scope.ScopeBuilder scopeBuilder) {
Token identifier = lexer.consume("Expected identifier at beginning of assignment", TokenType.IDENTIFIER);
lexer.consume("Expected '=' after identifier for variable assignment", TokenType.ASSIGNMENT);
Expression<?> value = parseExpression(scopeBuilder);
String id = identifier.lexeme();
ParserUtil.ensureReturnType(value, scopeBuilder.getVaraibleType(id));
Type type = value.returnType();
return switch(type) {
case NUMBER -> new NumAssignmentNode((Expression<Number>) value, identifier.position(), scopeBuilder.getIndex(id));
case STRING -> new StrAssignmentNode((Expression<String>) value, identifier.position(), scopeBuilder.getIndex(id));
case BOOLEAN -> new BoolAssignmentNode((Expression<Boolean>) value, identifier.position(), scopeBuilder.getIndex(id));
default -> throw new ParseException("Illegal type for variable assignment: " + type, value.getPosition());
};
}
private Expression<?> parseFunctionInvocation(Token identifier, Scope.ScopeBuilder scopeBuilder) {
if(!scopeBuilder.containsFunction(identifier.lexeme()))
throw new ParseException("Function '" + identifier.lexeme() + "' is not defined in this scope", identifier.position());
FunctionBuilder<?> builder = scopeBuilder.getFunction(identifier.lexeme());
lexer.consume("Expected '(' after identifier " + identifier.lexeme(), TokenType.OPEN_PAREN); // Invocation starts with open paren
List<Expression<?>> args = new ArrayList<>();
while(!lexer.current().isType(TokenType.CLOSE_PAREN)) {
args.add(parseExpression(scopeBuilder));
if(lexer.current().isType(TokenType.CLOSE_PAREN)) break;
lexer.consume("Expected ',' between function parameters", TokenType.SEPARATOR);
}
lexer.consume("Expected ')' after function parameters", TokenType.CLOSE_PAREN);
if(ignoredFunctions.contains(identifier.lexeme())) {
return Expression.NOOP;
}
if(builder.argNumber() != -1 && args.size() != builder.argNumber())
throw new ParseException("Expected " + builder.argNumber() + " parameters, found " + args.size(), identifier.position());
for(int i = 0; i < args.size(); i++) {
Expression<?> argument = args.get(i);
if(builder.getArgument(i) == null)
throw new ParseException("Unexpected argument at position " + i + " in function " + identifier.lexeme(),
identifier.position());
ParserUtil.ensureReturnType(argument, builder.getArgument(i));
}
return builder.build(args, identifier.position());
}
}

View File

@@ -1,41 +0,0 @@
/*
* Copyright (c) 2020-2021 Polyhedral Development
*
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
* reference the LICENSE file in this module's root directory.
*/
package com.dfsek.terra.addons.terrascript.legacy.parser;
import java.util.Arrays;
import com.dfsek.terra.addons.terrascript.Type;
import com.dfsek.terra.addons.terrascript.legacy.parser.exceptions.ParseException;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.Expression;
import com.dfsek.terra.addons.terrascript.lexer.Token;
public class ParserUtil {
// public static void ensureType(Token token, TokenType... expected) {
// for(TokenType type : expected) if(token.getType().equals(type)) return;
// throw new ParseException("Expected " + Arrays.toString(expected) + " but found " + token.getType(), token.getPosition());
// }
public static void ensureReturnType(Expression<?> returnable, Type... types) {
for(Type type : types) if(returnable.returnType().equals(type)) return;
throw new ParseException("Invalid type " + returnable.returnType() + ", expected " +
(types.length == 1 ? types[0].toString() : "one of " + Arrays.toString(types)), returnable.getPosition());
}
public static Type getVariableReturnType(Token varToken) {
return switch(varToken.type()) {
case TYPE_NUMBER -> Type.NUMBER;
case TYPE_STRING -> Type.STRING;
case TYPE_BOOLEAN -> Type.BOOLEAN;
case TYPE_VOID -> Type.VOID;
default -> throw new ParseException("Unexpected token " + varToken.type() + "; expected type",
varToken.position());
};
}
}

View File

@@ -1,70 +0,0 @@
/*
* Copyright (c) 2020-2021 Polyhedral Development
*
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
* reference the LICENSE file in this module's root directory.
*/
package com.dfsek.terra.addons.terrascript.legacy.parser.lang;
import java.util.List;
import com.dfsek.terra.addons.terrascript.Type;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.Block.EvaluationInfo;
import com.dfsek.terra.addons.terrascript.lexer.SourcePosition;
public class Block implements Expression<EvaluationInfo<?>> {
private final List<Expression<?>> items;
private final SourcePosition position;
private final Type returnType;
public Block(List<Expression<?>> items, SourcePosition position, Type returnType) {
this.items = items;
this.position = position;
this.returnType = returnType;
}
@Override
public Type returnType() {
return returnType;
}
@Override
public EvaluationInfo<?> evaluate(ImplementationArguments implementationArguments, Scope scope) {
for(Expression<?> item : items) {
Object result = item.evaluate(implementationArguments, scope);
if(result instanceof EvaluationInfo<?> evalInfo) {
if(!evalInfo.level().equals(EvaluationLevel.NONE)) return evalInfo;
}
}
return new EvaluationInfo<>(EvaluationLevel.NONE, NOOP);
}
@Override
public SourcePosition getPosition() {
return position;
}
public enum EvaluationLevel {
NONE(false),
BREAK(false),
CONTINUE(false),
RETURN(true),
FAIL(true);
private final boolean returnFast;
EvaluationLevel(boolean returnFast) {
this.returnFast = returnFast;
}
public boolean isReturnFast() {
return returnFast;
}
}
public record EvaluationInfo<T extends Expression<?>>(EvaluationLevel level, T data) {
}
}

View File

@@ -1,16 +0,0 @@
package com.dfsek.terra.addons.terrascript.legacy.parser.lang;
public class Executable {
private final Block script;
private final ThreadLocal<Scope> scope;
public Executable(Block script, Scope.ScopeBuilder scopeBuilder) {
this.script = script;
this.scope = ThreadLocal.withInitial(scopeBuilder::build);
}
public boolean execute(ImplementationArguments arguments) {
return script.evaluate(arguments, scope.get()).level() != Block.EvaluationLevel.FAIL;
}
}

View File

@@ -1,47 +0,0 @@
/*
* Copyright (c) 2020-2021 Polyhedral Development
*
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
* reference the LICENSE file in this module's root directory.
*/
package com.dfsek.terra.addons.terrascript.legacy.parser.lang;
import com.dfsek.terra.addons.terrascript.Type;
import com.dfsek.terra.addons.terrascript.lexer.SourcePosition;
public interface Expression<T> {
Expression<Void> NOOP = new Expression<>() {
@Override
public Type returnType() {
return Type.VOID;
}
@Override
public Void evaluate(ImplementationArguments implementationArguments, Scope scope) {
return null;
}
@Override
public SourcePosition getPosition() {
return null;
}
};
Type 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();
}

View File

@@ -1,14 +0,0 @@
/*
* Copyright (c) 2020-2021 Polyhedral Development
*
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
* reference the LICENSE file in this module's root directory.
*/
package com.dfsek.terra.addons.terrascript.legacy.parser.lang;
/**
* Arguments passed to {@link Expression}s by the implementation
*/
public interface ImplementationArguments {
}

View File

@@ -1,11 +0,0 @@
/*
* Copyright (c) 2020-2021 Polyhedral Development
*
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
* reference the LICENSE file in this module's root directory.
*/
package com.dfsek.terra.addons.terrascript.legacy.parser.lang;
public interface Keyword<T> extends Expression<T> {
}

View File

@@ -1,172 +0,0 @@
package com.dfsek.terra.addons.terrascript.legacy.parser.lang;
import net.jafama.FastMath;
import java.util.HashMap;
import java.util.Map;
import com.dfsek.terra.addons.terrascript.Type;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.functions.Function;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.functions.FunctionBuilder;
import com.dfsek.terra.api.util.generic.pair.Pair;
public class Scope {
private final double[] num;
private final boolean[] bool;
private final String[] str;
private Scope(int numSize, int boolSize, int strSize) {
this.num = new double[numSize];
this.bool = new boolean[boolSize];
this.str = new String[strSize];
}
public double getNum(int index) {
return num[index];
}
public boolean getBool(int index) {
return bool[index];
}
public String getStr(int index) {
return str[index];
}
public void setNum(int index, double value) {
num[index] = value;
}
public void setBool(int index, boolean value) {
bool[index] = value;
}
public void setStr(int index, String value) {
str[index] = value;
}
public static final class ScopeBuilder {
private final Map<String, FunctionBuilder<? extends Function<?>>> functions;
private final Map<String, Pair<Integer, Type>> indices;
private int numSize, boolSize, strSize = 0;
private ScopeBuilder parent;
private boolean inLoop;
public ScopeBuilder() {
this.functions = new HashMap<>();
this.indices = new HashMap<>();
}
private ScopeBuilder(ScopeBuilder parent, boolean inLoop) {
this.parent = parent;
this.numSize = parent.numSize;
this.boolSize = parent.boolSize;
this.strSize = parent.strSize;
this.functions = new HashMap<>(parent.functions);
this.indices = new HashMap<>(parent.indices);
this.inLoop = inLoop;
}
private ScopeBuilder(Map<String, FunctionBuilder<? extends Function<?>>> functions) {
this.functions = new HashMap<>(functions);
this.indices = new HashMap<>();
}
public Scope build() {
return new Scope(numSize, boolSize, strSize);
}
public ScopeBuilder innerScope() {
return new ScopeBuilder(this, inLoop);
}
public ScopeBuilder innerLoopScope() { return new ScopeBuilder(this, true); }
public ScopeBuilder functionScope() { return new ScopeBuilder(functions); }
public ScopeBuilder registerFunction(String name, FunctionBuilder<? extends Function<?>> functionBuilder) {
functions.put(name, functionBuilder);
return this;
}
public boolean containsFunction(String functionName) {
return functions.containsKey(functionName);
}
public FunctionBuilder<?> getFunction(String functionName) {
return functions.get(functionName);
}
private String check(String id) {
if(indices.containsKey(id)) {
throw new IllegalArgumentException("Variable with ID " + id + " already registered.");
}
return id;
}
public boolean isInLoop() {
return inLoop;
}
public int declareNum(String id) {
int num = numSize;
indices.put(check(id), Pair.of(num, Type.NUMBER));
numSize++;
updateNumSize(numSize);
return num;
}
public int declareStr(String id) {
int str = strSize;
indices.put(check(id), Pair.of(str, Type.STRING));
strSize++;
updateStrSize(strSize);
return str;
}
public int declareBool(String id) {
int bool = boolSize;
indices.put(check(id), Pair.of(bool, Type.BOOLEAN));
boolSize++;
updateBoolSize(boolSize);
return bool;
}
private void updateBoolSize(int size) {
this.boolSize = FastMath.max(boolSize, size);
if(parent != null) {
parent.updateBoolSize(size);
}
}
private void updateNumSize(int size) {
this.numSize = FastMath.max(numSize, size);
if(parent != null) {
parent.updateNumSize(size);
}
}
private void updateStrSize(int size) {
this.strSize = FastMath.max(strSize, size);
if(parent != null) {
parent.updateStrSize(size);
}
}
public int getIndex(String id) {
return indices.get(id).getLeft();
}
public Type getVaraibleType(String id) {
return indices.get(id).getRight();
}
public boolean containsVariable(String id) {
return indices.containsKey(id);
}
}
}

View File

@@ -1,33 +0,0 @@
/*
* Copyright (c) 2020-2021 Polyhedral Development
*
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
* reference the LICENSE file in this module's root directory.
*/
package com.dfsek.terra.addons.terrascript.legacy.parser.lang.constants;
import com.dfsek.terra.addons.terrascript.Type;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.ImplementationArguments;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.Scope;
import com.dfsek.terra.addons.terrascript.lexer.SourcePosition;
public class BooleanConstant extends ConstantExpression<Boolean> {
private final boolean constant;
public BooleanConstant(Boolean constant, SourcePosition position) {
super(constant, position);
this.constant = constant;
}
@Override
public boolean applyBoolean(ImplementationArguments implementationArguments, Scope scope) {
return constant;
}
@Override
public Type returnType() {
return Type.BOOLEAN;
}
}

View File

@@ -1,38 +0,0 @@
/*
* Copyright (c) 2020-2021 Polyhedral Development
*
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
* reference the LICENSE file in this module's root directory.
*/
package com.dfsek.terra.addons.terrascript.legacy.parser.lang.constants;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.Expression;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.ImplementationArguments;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.Scope;
import com.dfsek.terra.addons.terrascript.lexer.SourcePosition;
public abstract class ConstantExpression<T> implements Expression<T> {
private final T constant;
private final SourcePosition position;
public ConstantExpression(T constant, SourcePosition position) {
this.constant = constant;
this.position = position;
}
@Override
public T evaluate(ImplementationArguments implementationArguments, Scope scope) {
return constant;
}
@Override
public SourcePosition getPosition() {
return position;
}
public T getConstant() {
return constant;
}
}

View File

@@ -1,33 +0,0 @@
/*
* Copyright (c) 2020-2021 Polyhedral Development
*
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
* reference the LICENSE file in this module's root directory.
*/
package com.dfsek.terra.addons.terrascript.legacy.parser.lang.constants;
import com.dfsek.terra.addons.terrascript.Type;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.ImplementationArguments;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.Scope;
import com.dfsek.terra.addons.terrascript.lexer.SourcePosition;
public class NumericConstant extends ConstantExpression<Number> {
private final double constant;
public NumericConstant(Number constant, SourcePosition position) {
super(constant, position);
this.constant = constant.doubleValue();
}
@Override
public double applyDouble(ImplementationArguments implementationArguments, Scope scope) {
return constant;
}
@Override
public Type returnType() {
return Type.NUMBER;
}
}

View File

@@ -1,23 +0,0 @@
/*
* Copyright (c) 2020-2021 Polyhedral Development
*
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
* reference the LICENSE file in this module's root directory.
*/
package com.dfsek.terra.addons.terrascript.legacy.parser.lang.constants;
import com.dfsek.terra.addons.terrascript.Type;
import com.dfsek.terra.addons.terrascript.lexer.SourcePosition;
public class StringConstant extends ConstantExpression<String> {
public StringConstant(String constant, SourcePosition position) {
super(constant, position);
}
@Override
public Type returnType() {
return Type.STRING;
}
}

View File

@@ -1,26 +0,0 @@
/*
* Copyright (c) 2020-2021 Polyhedral Development
*
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
* reference the LICENSE file in this module's root directory.
*/
package com.dfsek.terra.addons.terrascript.legacy.parser.lang.functions;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.Expression;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.ImplementationArguments;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.Scope;
public interface Function<T> extends Expression<T> {
@Override
default double applyDouble(ImplementationArguments implementationArguments, Scope scope) {
return ((Number) evaluate(implementationArguments, scope)).doubleValue();
}
@Override
default boolean applyBoolean(ImplementationArguments implementationArguments, Scope scope) {
return (Boolean) evaluate(implementationArguments, scope);
}
}

View File

@@ -1,26 +0,0 @@
/*
* Copyright (c) 2020-2021 Polyhedral Development
*
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
* reference the LICENSE file in this module's root directory.
*/
package com.dfsek.terra.addons.terrascript.legacy.parser.lang.functions;
import java.util.List;
import com.dfsek.terra.addons.terrascript.Type;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.Expression;
import com.dfsek.terra.addons.terrascript.lexer.SourcePosition;
public interface FunctionBuilder<T extends Function<?>> {
T build(List<Expression<?>> argumentList, SourcePosition position);
/**
* @return Number of function parameters, -1 if the function uses a vararg at the end
*/
int argNumber();
Type getArgument(int position);
}

View File

@@ -1,74 +0,0 @@
package com.dfsek.terra.addons.terrascript.legacy.parser.lang.functions;
import java.util.List;
import com.dfsek.terra.addons.terrascript.Type;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.Block;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.Expression;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.ImplementationArguments;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.Scope;
import com.dfsek.terra.addons.terrascript.lexer.SourcePosition;
import com.dfsek.terra.api.util.generic.pair.Pair;
public class UserDefinedFunctionBuilder<T extends Function<?>> implements FunctionBuilder<T> {
private final Type returnType;
private final List<Pair<Integer, Type>> parameterInfo;
private final Scope.ScopeBuilder bodyScopeBuilder;
private final Block body;
public UserDefinedFunctionBuilder(Type returnType, List<Pair<Integer, Type>> parameterInfo, Block body,
Scope.ScopeBuilder functionBodyScope) {
this.returnType = returnType;
this.bodyScopeBuilder = functionBodyScope;
this.body = body;
this.parameterInfo = parameterInfo;
}
@Override
public T build(List<Expression<?>> argumentList, SourcePosition position) {
//noinspection unchecked
return (T) new Function() {
private final ThreadLocal<Scope> threadLocalScope = ThreadLocal.withInitial(bodyScopeBuilder::build);
@Override
public Type returnType() {
return returnType;
}
@Override
public Object evaluate(ImplementationArguments implementationArguments, Scope scope) {
Scope bodyScope = threadLocalScope.get();
// Pass parameters into scope of function body
for(int i = 0; i < argumentList.size(); i++) {
Pair<Integer, Type> paramInfo = parameterInfo.get(i);
Expression<?> argExpression = argumentList.get(i);
switch(paramInfo.getRight()) {
case NUMBER -> bodyScope.setNum(paramInfo.getLeft(), argExpression.applyDouble(implementationArguments, scope));
case BOOLEAN -> bodyScope.setBool(paramInfo.getLeft(), argExpression.applyBoolean(implementationArguments, scope));
case STRING -> bodyScope.setStr(paramInfo.getLeft(),
(String) argExpression.evaluate(implementationArguments, scope));
}
}
return body.evaluate(implementationArguments, bodyScope).data().evaluate(implementationArguments, scope);
}
@Override
public SourcePosition getPosition() {
return position;
}
};
}
@Override
public int argNumber() {
return parameterInfo.size();
}
@Override
public Type getArgument(int position) {
return parameterInfo.get(position).getRight();
}
}

View File

@@ -1,40 +0,0 @@
/*
* Copyright (c) 2020-2021 Polyhedral Development
*
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
* reference the LICENSE file in this module's root directory.
*/
package com.dfsek.terra.addons.terrascript.legacy.parser.lang.keywords.flow;
import com.dfsek.terra.addons.terrascript.Type;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.Block.EvaluationInfo;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.Block.EvaluationLevel;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.ImplementationArguments;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.Keyword;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.Scope;
import com.dfsek.terra.addons.terrascript.lexer.SourcePosition;
public class BreakKeyword implements Keyword<EvaluationInfo<?>> {
private final SourcePosition position;
public BreakKeyword(SourcePosition position) {
this.position = position;
}
@Override
public EvaluationInfo<?> evaluate(ImplementationArguments implementationArguments, Scope scope) {
return new EvaluationInfo<>(EvaluationLevel.BREAK, null);
}
@Override
public SourcePosition getPosition() {
return position;
}
@Override
public Type returnType() {
return Type.VOID;
}
}

View File

@@ -1,40 +0,0 @@
/*
* Copyright (c) 2020-2021 Polyhedral Development
*
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
* reference the LICENSE file in this module's root directory.
*/
package com.dfsek.terra.addons.terrascript.legacy.parser.lang.keywords.flow;
import com.dfsek.terra.addons.terrascript.Type;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.Block.EvaluationInfo;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.Block.EvaluationLevel;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.ImplementationArguments;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.Keyword;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.Scope;
import com.dfsek.terra.addons.terrascript.lexer.SourcePosition;
public class ContinueKeyword implements Keyword<EvaluationInfo<?>> {
private final SourcePosition position;
public ContinueKeyword(SourcePosition position) {
this.position = position;
}
@Override
public EvaluationInfo<?> evaluate(ImplementationArguments implementationArguments, Scope scope) {
return new EvaluationInfo<>(EvaluationLevel.CONTINUE, null);
}
@Override
public SourcePosition getPosition() {
return position;
}
@Override
public Type returnType() {
return Type.VOID;
}
}

View File

@@ -1,40 +0,0 @@
/*
* Copyright (c) 2020-2021 Polyhedral Development
*
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
* reference the LICENSE file in this module's root directory.
*/
package com.dfsek.terra.addons.terrascript.legacy.parser.lang.keywords.flow;
import com.dfsek.terra.addons.terrascript.Type;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.Block.EvaluationInfo;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.Block.EvaluationLevel;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.ImplementationArguments;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.Keyword;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.Scope;
import com.dfsek.terra.addons.terrascript.lexer.SourcePosition;
public class FailKeyword implements Keyword<EvaluationInfo<?>> {
private final SourcePosition position;
public FailKeyword(SourcePosition position) {
this.position = position;
}
@Override
public EvaluationInfo<?> evaluate(ImplementationArguments implementationArguments, Scope scope) {
return new EvaluationInfo<>(EvaluationLevel.FAIL, null);
}
@Override
public SourcePosition getPosition() {
return position;
}
@Override
public Type returnType() {
return Type.VOID;
}
}

View File

@@ -1,54 +0,0 @@
/*
* Copyright (c) 2020-2021 Polyhedral Development
*
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
* reference the LICENSE file in this module's root directory.
*/
package com.dfsek.terra.addons.terrascript.legacy.parser.lang.keywords.flow;
import javax.annotation.Nullable;
import com.dfsek.terra.addons.terrascript.Type;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.Block.EvaluationInfo;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.Block.EvaluationLevel;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.Expression;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.ImplementationArguments;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.Keyword;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.Scope;
import com.dfsek.terra.addons.terrascript.lexer.SourcePosition;
public class ReturnKeyword implements Keyword<EvaluationInfo<?>> {
private final SourcePosition position;
private final Expression<?> data;
public ReturnKeyword(@Nullable Expression<?> data, SourcePosition position) {
this.data = data;
this.position = position;
}
@Override
public EvaluationInfo<?> evaluate(ImplementationArguments implementationArguments, Scope scope) {
return new EvaluationInfo<>(EvaluationLevel.RETURN, data);
}
@Override
public SourcePosition getPosition() {
return position;
}
@Override
public Type returnType() {
return Type.VOID;
}
public Type dataReturnType() {
if(data != null) {
return data.returnType();
} else {
return Type.VOID;
}
}
}

View File

@@ -1,57 +0,0 @@
/*
* Copyright (c) 2020-2021 Polyhedral Development
*
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
* reference the LICENSE file in this module's root directory.
*/
package com.dfsek.terra.addons.terrascript.legacy.parser.lang.keywords.looplike;
import com.dfsek.terra.addons.terrascript.Type;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.Block;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.Block.EvaluationLevel;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.Expression;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.ImplementationArguments;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.Keyword;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.Scope;
import com.dfsek.terra.addons.terrascript.lexer.SourcePosition;
public class ForKeyword implements Keyword<Block.EvaluationInfo<?>> {
private final Block conditional;
private final Expression<?> initializer;
private final Expression<Boolean> statement;
private final Expression<?> incrementer;
private final SourcePosition position;
public ForKeyword(Block conditional, Expression<?> initializer, Expression<Boolean> statement, Expression<?> incrementer,
SourcePosition position) {
this.conditional = conditional;
this.initializer = initializer;
this.statement = statement;
this.incrementer = incrementer;
this.position = position;
}
@Override
public Block.EvaluationInfo<?> evaluate(ImplementationArguments implementationArguments, Scope scope) {
for(initializer.evaluate(implementationArguments, scope);
statement.evaluate(implementationArguments, scope);
incrementer.evaluate(implementationArguments, scope)) {
Block.EvaluationInfo<?> level = conditional.evaluate(implementationArguments, scope);
if(level.level().equals(EvaluationLevel.BREAK)) break;
if(level.level().isReturnFast()) return level;
}
return new Block.EvaluationInfo<>(EvaluationLevel.NONE, null);
}
@Override
public SourcePosition getPosition() {
return position;
}
@Override
public Type returnType() {
return Type.VOID;
}
}

View File

@@ -1,64 +0,0 @@
/*
* Copyright (c) 2020-2021 Polyhedral Development
*
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
* reference the LICENSE file in this module's root directory.
*/
package com.dfsek.terra.addons.terrascript.legacy.parser.lang.keywords.looplike;
import org.jetbrains.annotations.Nullable;
import java.util.List;
import com.dfsek.terra.addons.terrascript.Type;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.Block;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.Block.EvaluationLevel;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.Expression;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.ImplementationArguments;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.Keyword;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.Scope;
import com.dfsek.terra.addons.terrascript.lexer.SourcePosition;
import com.dfsek.terra.api.util.generic.pair.Pair;
public class IfKeyword implements Keyword<Block.EvaluationInfo<?>> {
private final Block conditional;
private final Expression<Boolean> statement;
private final SourcePosition position;
private final List<Pair<Expression<Boolean>, Block>> elseIf;
private final Block elseBlock;
public IfKeyword(Block conditional, Expression<Boolean> statement, List<Pair<Expression<Boolean>, Block>> elseIf,
@Nullable Block elseBlock, SourcePosition position) {
this.conditional = conditional;
this.statement = statement;
this.position = position;
this.elseIf = elseIf;
this.elseBlock = elseBlock;
}
@Override
public Block.EvaluationInfo<?> 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().evaluate(implementationArguments, scope)) {
return pair.getRight().evaluate(implementationArguments, scope);
}
}
if(elseBlock != null) return elseBlock.evaluate(implementationArguments, scope);
}
return new Block.EvaluationInfo<>(EvaluationLevel.NONE, null);
}
@Override
public SourcePosition getPosition() {
return position;
}
@Override
public Type returnType() {
return Type.VOID;
}
}

View File

@@ -1,51 +0,0 @@
/*
* Copyright (c) 2020-2021 Polyhedral Development
*
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
* reference the LICENSE file in this module's root directory.
*/
package com.dfsek.terra.addons.terrascript.legacy.parser.lang.keywords.looplike;
import com.dfsek.terra.addons.terrascript.Type;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.Block;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.Block.EvaluationInfo;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.Block.EvaluationLevel;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.Expression;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.ImplementationArguments;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.Keyword;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.Scope;
import com.dfsek.terra.addons.terrascript.lexer.SourcePosition;
public class WhileKeyword implements Keyword<EvaluationInfo<?>> {
private final Block conditional;
private final Expression<Boolean> statement;
private final SourcePosition position;
public WhileKeyword(Block conditional, Expression<Boolean> statement, SourcePosition position) {
this.conditional = conditional;
this.statement = statement;
this.position = position;
}
@Override
public EvaluationInfo<?> evaluate(ImplementationArguments implementationArguments, Scope scope) {
while(statement.evaluate(implementationArguments, scope)) {
EvaluationInfo<?> level = conditional.evaluate(implementationArguments, scope);
if(level.level().equals(EvaluationLevel.BREAK)) break;
if(level.level().isReturnFast()) return level;
}
return new EvaluationInfo<>(EvaluationLevel.NONE, null);
}
@Override
public SourcePosition getPosition() {
return position;
}
@Override
public Type returnType() {
return Type.VOID;
}
}

View File

@@ -1,29 +0,0 @@
/*
* Copyright (c) 2020-2021 Polyhedral Development
*
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
* reference the LICENSE file in this module's root directory.
*/
package com.dfsek.terra.addons.terrascript.legacy.parser.lang.operations;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.Expression;
import com.dfsek.terra.addons.terrascript.lexer.SourcePosition;
public abstract class BinaryOperation<I, O> implements Expression<O> {
protected final Expression<I> left;
protected final Expression<I> right;
private final SourcePosition start;
public BinaryOperation(Expression<I> left, Expression<I> right, SourcePosition start) {
this.left = left;
this.right = right;
this.start = start;
}
@Override
public SourcePosition getPosition() {
return start;
}
}

View File

@@ -1,36 +0,0 @@
/*
* Copyright (c) 2020-2021 Polyhedral Development
*
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
* reference the LICENSE file in this module's root directory.
*/
package com.dfsek.terra.addons.terrascript.legacy.parser.lang.operations;
import com.dfsek.terra.addons.terrascript.Type;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.Expression;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.ImplementationArguments;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.Scope;
import com.dfsek.terra.addons.terrascript.lexer.SourcePosition;
public class BooleanAndOperation extends BinaryOperation<Boolean, Boolean> {
public BooleanAndOperation(Expression<Boolean> left, Expression<Boolean> right, SourcePosition start) {
super(left, right, start);
}
@Override
public Type returnType() {
return Type.BOOLEAN;
}
@Override
public Boolean evaluate(ImplementationArguments implementationArguments, Scope scope) {
return applyBoolean(implementationArguments, scope);
}
@Override
public boolean applyBoolean(ImplementationArguments implementationArguments, Scope scope) {
return left.applyBoolean(implementationArguments, scope) && right.applyBoolean(implementationArguments, scope);
}
}

View File

@@ -1,36 +0,0 @@
/*
* Copyright (c) 2020-2021 Polyhedral Development
*
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
* reference the LICENSE file in this module's root directory.
*/
package com.dfsek.terra.addons.terrascript.legacy.parser.lang.operations;
import com.dfsek.terra.addons.terrascript.Type;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.Expression;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.ImplementationArguments;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.Scope;
import com.dfsek.terra.addons.terrascript.lexer.SourcePosition;
public class BooleanNotOperation extends UnaryOperation<Boolean> {
public BooleanNotOperation(Expression<Boolean> input, SourcePosition position) {
super(input, position);
}
@Override
public Boolean evaluate(ImplementationArguments implementationArguments, Scope scope) {
return applyBoolean(implementationArguments, scope);
}
@Override
public boolean applyBoolean(ImplementationArguments implementationArguments, Scope scope) {
return !input.applyBoolean(implementationArguments, scope);
}
@Override
public Type returnType() {
return Type.BOOLEAN;
}
}

View File

@@ -1,36 +0,0 @@
/*
* Copyright (c) 2020-2021 Polyhedral Development
*
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
* reference the LICENSE file in this module's root directory.
*/
package com.dfsek.terra.addons.terrascript.legacy.parser.lang.operations;
import com.dfsek.terra.addons.terrascript.Type;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.Expression;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.ImplementationArguments;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.Scope;
import com.dfsek.terra.addons.terrascript.lexer.SourcePosition;
public class BooleanOrOperation extends BinaryOperation<Boolean, Boolean> {
public BooleanOrOperation(Expression<Boolean> left, Expression<Boolean> right, SourcePosition start) {
super(left, right, start);
}
@Override
public Boolean evaluate(ImplementationArguments implementationArguments, Scope scope) {
return applyBoolean(implementationArguments, scope);
}
@Override
public boolean applyBoolean(ImplementationArguments implementationArguments, Scope scope) {
return left.applyBoolean(implementationArguments, scope) || right.applyBoolean(implementationArguments, scope);
}
@Override
public Type returnType() {
return Type.BOOLEAN;
}
}

View File

@@ -1,42 +0,0 @@
/*
* Copyright (c) 2020-2021 Polyhedral Development
*
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
* reference the LICENSE file in this module's root directory.
*/
package com.dfsek.terra.addons.terrascript.legacy.parser.lang.operations;
import com.dfsek.terra.addons.terrascript.Type;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.Expression;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.ImplementationArguments;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.Scope;
import com.dfsek.terra.addons.terrascript.lexer.SourcePosition;
public class ConcatenationOperation extends BinaryOperation<Object, Object> {
public ConcatenationOperation(Expression<Object> left, Expression<Object> right, SourcePosition position) {
super(left, right, position);
}
private static String toString(Object object) {
String s = object.toString();
if(object instanceof Double) {
int l = s.length();
if(s.charAt(l - 2) == '.' && s.charAt(l - 1) == '0') {
s = s.substring(0, s.length() - 2);
}
}
return s;
}
@Override
public Type returnType() {
return Type.STRING;
}
@Override
public Object evaluate(ImplementationArguments implementationArguments, Scope scope) {
return toString(left.evaluate(implementationArguments, scope)) + toString(right.evaluate(implementationArguments, scope));
}
}

View File

@@ -1,36 +0,0 @@
/*
* Copyright (c) 2020-2021 Polyhedral Development
*
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
* reference the LICENSE file in this module's root directory.
*/
package com.dfsek.terra.addons.terrascript.legacy.parser.lang.operations;
import com.dfsek.terra.addons.terrascript.Type;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.Expression;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.ImplementationArguments;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.Scope;
import com.dfsek.terra.addons.terrascript.lexer.SourcePosition;
public class DivisionOperation extends BinaryOperation<Number, Number> {
public DivisionOperation(Expression<Number> left, Expression<Number> right, SourcePosition position) {
super(left, right, position);
}
@Override
public Type returnType() {
return Type.NUMBER;
}
@Override
public Number evaluate(ImplementationArguments implementationArguments, Scope scope) {
return applyDouble(implementationArguments, scope);
}
@Override
public double applyDouble(ImplementationArguments implementationArguments, Scope scope) {
return left.applyDouble(implementationArguments, scope) / right.applyDouble(implementationArguments, scope);
}
}

View File

@@ -1,36 +0,0 @@
/*
* Copyright (c) 2020-2021 Polyhedral Development
*
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
* reference the LICENSE file in this module's root directory.
*/
package com.dfsek.terra.addons.terrascript.legacy.parser.lang.operations;
import com.dfsek.terra.addons.terrascript.Type;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.Expression;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.ImplementationArguments;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.Scope;
import com.dfsek.terra.addons.terrascript.lexer.SourcePosition;
public class ModuloOperation extends BinaryOperation<Number, Number> {
public ModuloOperation(Expression<Number> left, Expression<Number> right, SourcePosition start) {
super(left, right, start);
}
@Override
public Number evaluate(ImplementationArguments implementationArguments, Scope scope) {
return applyDouble(implementationArguments, scope);
}
@Override
public double applyDouble(ImplementationArguments implementationArguments, Scope scope) {
return left.applyDouble(implementationArguments, scope) % right.applyDouble(implementationArguments, scope);
}
@Override
public Type returnType() {
return Type.NUMBER;
}
}

View File

@@ -1,36 +0,0 @@
/*
* Copyright (c) 2020-2021 Polyhedral Development
*
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
* reference the LICENSE file in this module's root directory.
*/
package com.dfsek.terra.addons.terrascript.legacy.parser.lang.operations;
import com.dfsek.terra.addons.terrascript.Type;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.Expression;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.ImplementationArguments;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.Scope;
import com.dfsek.terra.addons.terrascript.lexer.SourcePosition;
public class MultiplicationOperation extends BinaryOperation<Number, Number> {
public MultiplicationOperation(Expression<Number> left, Expression<Number> right, SourcePosition position) {
super(left, right, position);
}
@Override
public Number evaluate(ImplementationArguments implementationArguments, Scope scope) {
return applyDouble(implementationArguments, scope);
}
@Override
public double applyDouble(ImplementationArguments implementationArguments, Scope scope) {
return left.applyDouble(implementationArguments, scope) * right.applyDouble(implementationArguments, scope);
}
@Override
public Type returnType() {
return Type.NUMBER;
}
}

View File

@@ -1,36 +0,0 @@
/*
* Copyright (c) 2020-2021 Polyhedral Development
*
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
* reference the LICENSE file in this module's root directory.
*/
package com.dfsek.terra.addons.terrascript.legacy.parser.lang.operations;
import com.dfsek.terra.addons.terrascript.Type;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.Expression;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.ImplementationArguments;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.Scope;
import com.dfsek.terra.addons.terrascript.lexer.SourcePosition;
public class NegationOperation extends UnaryOperation<Number> {
public NegationOperation(Expression<Number> input, SourcePosition position) {
super(input, position);
}
@Override
public Type returnType() {
return Type.NUMBER;
}
@Override
public Number evaluate(ImplementationArguments implementationArguments, Scope scope) {
return applyDouble(implementationArguments, scope);
}
@Override
public double applyDouble(ImplementationArguments implementationArguments, Scope scope) {
return -input.applyDouble(implementationArguments, scope);
}
}

View File

@@ -1,36 +0,0 @@
/*
* Copyright (c) 2020-2021 Polyhedral Development
*
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
* reference the LICENSE file in this module's root directory.
*/
package com.dfsek.terra.addons.terrascript.legacy.parser.lang.operations;
import com.dfsek.terra.addons.terrascript.Type;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.Expression;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.ImplementationArguments;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.Scope;
import com.dfsek.terra.addons.terrascript.lexer.SourcePosition;
public class NumberAdditionOperation extends BinaryOperation<Number, Number> {
public NumberAdditionOperation(Expression<Number> left, Expression<Number> right, SourcePosition position) {
super(left, right, position);
}
@Override
public Number evaluate(ImplementationArguments implementationArguments, Scope scope) {
return applyDouble(implementationArguments, scope);
}
@Override
public double applyDouble(ImplementationArguments implementationArguments, Scope scope) {
return left.applyDouble(implementationArguments, scope) + right.applyDouble(implementationArguments, scope);
}
@Override
public Type returnType() {
return Type.NUMBER;
}
}

View File

@@ -1,36 +0,0 @@
/*
* Copyright (c) 2020-2021 Polyhedral Development
*
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
* reference the LICENSE file in this module's root directory.
*/
package com.dfsek.terra.addons.terrascript.legacy.parser.lang.operations;
import com.dfsek.terra.addons.terrascript.Type;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.Expression;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.ImplementationArguments;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.Scope;
import com.dfsek.terra.addons.terrascript.lexer.SourcePosition;
public class SubtractionOperation extends BinaryOperation<Number, Number> {
public SubtractionOperation(Expression<Number> left, Expression<Number> right, SourcePosition position) {
super(left, right, position);
}
@Override
public Number evaluate(ImplementationArguments implementationArguments, Scope scope) {
return applyDouble(implementationArguments, scope);
}
@Override
public double applyDouble(ImplementationArguments implementationArguments, Scope scope) {
return left.applyDouble(implementationArguments, scope) - right.applyDouble(implementationArguments, scope);
}
@Override
public Type returnType() {
return Type.NUMBER;
}
}

View File

@@ -1,27 +0,0 @@
/*
* Copyright (c) 2020-2021 Polyhedral Development
*
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
* reference the LICENSE file in this module's root directory.
*/
package com.dfsek.terra.addons.terrascript.legacy.parser.lang.operations;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.Expression;
import com.dfsek.terra.addons.terrascript.lexer.SourcePosition;
public abstract class UnaryOperation<T> implements Expression<T> {
protected final Expression<T> input;
private final SourcePosition position;
public UnaryOperation(Expression<T> input, SourcePosition position) {
this.input = input;
this.position = position;
}
@Override
public SourcePosition getPosition() {
return position;
}
}

View File

@@ -1,49 +0,0 @@
/*
* Copyright (c) 2020-2021 Polyhedral Development
*
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
* reference the LICENSE file in this module's root directory.
*/
package com.dfsek.terra.addons.terrascript.legacy.parser.lang.operations.statements;
import net.jafama.FastMath;
import com.dfsek.terra.addons.terrascript.Type;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.Expression;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.ImplementationArguments;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.Scope;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.operations.BinaryOperation;
import com.dfsek.terra.addons.terrascript.lexer.SourcePosition;
import static com.dfsek.terra.api.util.MathUtil.EPSILON;
public class EqualsStatement extends BinaryOperation<Object, Boolean> {
public EqualsStatement(Expression<Object> left, Expression<Object> right, SourcePosition position) {
super(left, right, position);
}
@Override
public Type returnType() {
return Type.BOOLEAN;
}
@Override
public Boolean evaluate(ImplementationArguments implementationArguments, Scope scope) {
return applyBoolean(implementationArguments, scope);
}
@Override
public boolean applyBoolean(ImplementationArguments implementationArguments, Scope 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;
}
return leftValue.equals(rightValue);
}
}

View File

@@ -1,37 +0,0 @@
/*
* Copyright (c) 2020-2021 Polyhedral Development
*
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
* reference the LICENSE file in this module's root directory.
*/
package com.dfsek.terra.addons.terrascript.legacy.parser.lang.operations.statements;
import com.dfsek.terra.addons.terrascript.Type;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.Expression;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.ImplementationArguments;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.Scope;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.operations.BinaryOperation;
import com.dfsek.terra.addons.terrascript.lexer.SourcePosition;
public class GreaterOrEqualsThanStatement extends BinaryOperation<Number, Boolean> {
public GreaterOrEqualsThanStatement(Expression<Number> left, Expression<Number> right, SourcePosition position) {
super(left, right, position);
}
@Override
public Type returnType() {
return Type.BOOLEAN;
}
@Override
public Boolean evaluate(ImplementationArguments implementationArguments, Scope scope) {
return applyBoolean(implementationArguments, scope);
}
@Override
public boolean applyBoolean(ImplementationArguments implementationArguments, Scope scope) {
return left.applyDouble(implementationArguments, scope) >= right.applyDouble(implementationArguments, scope);
}
}

View File

@@ -1,38 +0,0 @@
/*
* Copyright (c) 2020-2021 Polyhedral Development
*
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
* reference the LICENSE file in this module's root directory.
*/
package com.dfsek.terra.addons.terrascript.legacy.parser.lang.operations.statements;
import com.dfsek.terra.addons.terrascript.Type;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.Expression;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.ImplementationArguments;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.Scope;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.operations.BinaryOperation;
import com.dfsek.terra.addons.terrascript.lexer.SourcePosition;
public class GreaterThanStatement extends BinaryOperation<Number, Boolean> {
public GreaterThanStatement(Expression<Number> left, Expression<Number> right, SourcePosition position) {
super(left, right, position);
}
@Override
public Boolean evaluate(ImplementationArguments implementationArguments, Scope scope) {
return applyBoolean(implementationArguments, scope);
}
@Override
public boolean applyBoolean(ImplementationArguments implementationArguments, Scope scope) {
return left.applyDouble(implementationArguments, scope) > right.applyDouble(implementationArguments, scope);
}
@Override
public Type returnType() {
return Type.BOOLEAN;
}
}

View File

@@ -1,38 +0,0 @@
/*
* Copyright (c) 2020-2021 Polyhedral Development
*
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
* reference the LICENSE file in this module's root directory.
*/
package com.dfsek.terra.addons.terrascript.legacy.parser.lang.operations.statements;
import com.dfsek.terra.addons.terrascript.Type;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.Expression;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.ImplementationArguments;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.Scope;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.operations.BinaryOperation;
import com.dfsek.terra.addons.terrascript.lexer.SourcePosition;
public class LessThanOrEqualsStatement extends BinaryOperation<Number, Boolean> {
public LessThanOrEqualsStatement(Expression<Number> left, Expression<Number> right, SourcePosition position) {
super(left, right, position);
}
@Override
public Boolean evaluate(ImplementationArguments implementationArguments, Scope scope) {
return applyBoolean(implementationArguments, scope);
}
@Override
public boolean applyBoolean(ImplementationArguments implementationArguments, Scope scope) {
return left.applyDouble(implementationArguments, scope) <= right.applyDouble(implementationArguments, scope);
}
@Override
public Type returnType() {
return Type.BOOLEAN;
}
}

View File

@@ -1,38 +0,0 @@
/*
* Copyright (c) 2020-2021 Polyhedral Development
*
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
* reference the LICENSE file in this module's root directory.
*/
package com.dfsek.terra.addons.terrascript.legacy.parser.lang.operations.statements;
import com.dfsek.terra.addons.terrascript.Type;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.Expression;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.ImplementationArguments;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.Scope;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.operations.BinaryOperation;
import com.dfsek.terra.addons.terrascript.lexer.SourcePosition;
public class LessThanStatement extends BinaryOperation<Number, Boolean> {
public LessThanStatement(Expression<Number> left, Expression<Number> right, SourcePosition position) {
super(left, right, position);
}
@Override
public Boolean evaluate(ImplementationArguments implementationArguments, Scope scope) {
return applyBoolean(implementationArguments, scope);
}
@Override
public boolean applyBoolean(ImplementationArguments implementationArguments, Scope scope) {
return left.applyDouble(implementationArguments, scope) < right.applyDouble(implementationArguments, scope);
}
@Override
public Type returnType() {
return Type.BOOLEAN;
}
}

View File

@@ -1,47 +0,0 @@
/*
* Copyright (c) 2020-2021 Polyhedral Development
*
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
* reference the LICENSE file in this module's root directory.
*/
package com.dfsek.terra.addons.terrascript.legacy.parser.lang.operations.statements;
import net.jafama.FastMath;
import com.dfsek.terra.addons.terrascript.Type;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.Expression;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.ImplementationArguments;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.Scope;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.operations.BinaryOperation;
import com.dfsek.terra.addons.terrascript.lexer.SourcePosition;
import static com.dfsek.terra.api.util.MathUtil.EPSILON;
public class NotEqualsStatement extends BinaryOperation<Object, Boolean> {
public NotEqualsStatement(Expression<Object> left, Expression<Object> right, SourcePosition position) {
super(left, right, position);
}
@Override
public Boolean evaluate(ImplementationArguments implementationArguments, Scope scope) {
return applyBoolean(implementationArguments, scope);
}
@Override
public boolean applyBoolean(ImplementationArguments implementationArguments, Scope 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;
}
return !leftValue.equals(rightValue);
}
@Override
public Type returnType() {
return Type.BOOLEAN;
}
}

View File

@@ -1,42 +0,0 @@
/*
* Copyright (c) 2020-2021 Polyhedral Development
*
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
* reference the LICENSE file in this module's root directory.
*/
package com.dfsek.terra.addons.terrascript.legacy.parser.lang.variables;
import com.dfsek.terra.addons.terrascript.Type;
import com.dfsek.terra.addons.terrascript.lexer.SourcePosition;
public class BooleanVariable implements Variable<Boolean> {
private final SourcePosition position;
private Boolean value;
public BooleanVariable(Boolean value, SourcePosition position) {
this.value = value;
this.position = position;
}
@Override
public Boolean getValue() {
return value;
}
@Override
public void setValue(Boolean value) {
this.value = value;
}
@Override
public Type getType() {
return Type.BOOLEAN;
}
@Override
public SourcePosition getPosition() {
return position;
}
}

View File

@@ -1,42 +0,0 @@
/*
* Copyright (c) 2020-2021 Polyhedral Development
*
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
* reference the LICENSE file in this module's root directory.
*/
package com.dfsek.terra.addons.terrascript.legacy.parser.lang.variables;
import com.dfsek.terra.addons.terrascript.Type;
import com.dfsek.terra.addons.terrascript.lexer.SourcePosition;
public class NumberVariable implements Variable<Number> {
private final SourcePosition position;
private Number value;
public NumberVariable(Number value, SourcePosition position) {
this.value = value;
this.position = position;
}
@Override
public Number getValue() {
return value;
}
@Override
public void setValue(Number value) {
this.value = value;
}
@Override
public Type getType() {
return Type.NUMBER;
}
@Override
public SourcePosition getPosition() {
return position;
}
}

View File

@@ -1,42 +0,0 @@
/*
* Copyright (c) 2020-2021 Polyhedral Development
*
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
* reference the LICENSE file in this module's root directory.
*/
package com.dfsek.terra.addons.terrascript.legacy.parser.lang.variables;
import com.dfsek.terra.addons.terrascript.Type;
import com.dfsek.terra.addons.terrascript.lexer.SourcePosition;
public class StringVariable implements Variable<String> {
private final SourcePosition position;
private String value;
public StringVariable(String value, SourcePosition position) {
this.value = value;
this.position = position;
}
@Override
public String getValue() {
return value;
}
@Override
public void setValue(String value) {
this.value = value;
}
@Override
public Type getType() {
return Type.STRING;
}
@Override
public SourcePosition getPosition() {
return position;
}
}

View File

@@ -1,22 +0,0 @@
/*
* Copyright (c) 2020-2021 Polyhedral Development
*
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
* reference the LICENSE file in this module's root directory.
*/
package com.dfsek.terra.addons.terrascript.legacy.parser.lang.variables;
import com.dfsek.terra.addons.terrascript.Type;
import com.dfsek.terra.addons.terrascript.lexer.SourcePosition;
public interface Variable<T> {
T getValue();
void setValue(T value);
Type getType();
SourcePosition getPosition();
}

View File

@@ -1,31 +0,0 @@
package com.dfsek.terra.addons.terrascript.legacy.parser.lang.variables.assign;
import com.dfsek.terra.addons.terrascript.Type;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.Expression;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.ImplementationArguments;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.Scope;
import com.dfsek.terra.addons.terrascript.lexer.SourcePosition;
public class BoolAssignmentNode extends VariableAssignmentNode<Boolean> {
public BoolAssignmentNode(Expression<Boolean> value, SourcePosition position, int index) {
super(value, position, index);
}
@Override
public Type returnType() {
return Type.BOOLEAN;
}
@Override
public Boolean evaluate(ImplementationArguments implementationArguments, Scope scope) {
return applyBoolean(implementationArguments, scope);
}
@Override
public boolean applyBoolean(ImplementationArguments implementationArguments, Scope scope) {
boolean val = value.applyBoolean(implementationArguments, scope);
scope.setBool(index, val);
return val;
}
}

View File

@@ -1,31 +0,0 @@
package com.dfsek.terra.addons.terrascript.legacy.parser.lang.variables.assign;
import com.dfsek.terra.addons.terrascript.Type;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.Expression;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.ImplementationArguments;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.Scope;
import com.dfsek.terra.addons.terrascript.lexer.SourcePosition;
public class NumAssignmentNode extends VariableAssignmentNode<Number> {
public NumAssignmentNode(Expression<Number> value, SourcePosition position, int index) {
super(value, position, index);
}
@Override
public Type returnType() {
return Type.NUMBER;
}
@Override
public Number evaluate(ImplementationArguments implementationArguments, Scope scope) {
return applyDouble(implementationArguments, scope);
}
@Override
public double applyDouble(ImplementationArguments implementationArguments, Scope scope) {
double val = value.applyDouble(implementationArguments, scope);
scope.setNum(index, val);
return val;
}
}

View File

@@ -1,27 +0,0 @@
package com.dfsek.terra.addons.terrascript.legacy.parser.lang.variables.assign;
import com.dfsek.terra.addons.terrascript.Type;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.Expression;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.ImplementationArguments;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.Scope;
import com.dfsek.terra.addons.terrascript.lexer.SourcePosition;
public class StrAssignmentNode extends VariableAssignmentNode<String> {
public StrAssignmentNode(Expression<String> value, SourcePosition position, int index) {
super(value, position, index);
}
@Override
public Type returnType() {
return Type.STRING;
}
@Override
public String evaluate(ImplementationArguments implementationArguments, Scope scope) {
String val = value.evaluate(implementationArguments, scope);
scope.setStr(index, val);
return val;
}
}

View File

@@ -1,30 +0,0 @@
/*
* Copyright (c) 2020-2021 Polyhedral Development
*
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
* reference the LICENSE file in this module's root directory.
*/
package com.dfsek.terra.addons.terrascript.legacy.parser.lang.variables.assign;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.Expression;
import com.dfsek.terra.addons.terrascript.lexer.SourcePosition;
public abstract class VariableAssignmentNode<T> implements Expression<T> {
protected final Expression<T> value;
protected final int index;
private final SourcePosition position;
public VariableAssignmentNode(Expression<T> value, SourcePosition position, int index) {
this.value = value;
this.index = index;
this.position = position;
}
@Override
public SourcePosition getPosition() {
return position;
}
}

View File

@@ -1,23 +0,0 @@
package com.dfsek.terra.addons.terrascript.legacy.parser.lang.variables.reference;
import com.dfsek.terra.addons.terrascript.Type;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.ImplementationArguments;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.Scope;
import com.dfsek.terra.addons.terrascript.lexer.SourcePosition;
public class BoolVariableReferenceNode extends VariableReferenceNode<Boolean> {
public BoolVariableReferenceNode(SourcePosition position, Type type, int index) {
super(position, type, index);
}
@Override
public Boolean evaluate(ImplementationArguments implementationArguments, Scope scope) {
return scope.getBool(index);
}
@Override
public boolean applyBoolean(ImplementationArguments implementationArguments, Scope scope) {
return scope.getBool(index);
}
}

View File

@@ -1,23 +0,0 @@
package com.dfsek.terra.addons.terrascript.legacy.parser.lang.variables.reference;
import com.dfsek.terra.addons.terrascript.Type;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.ImplementationArguments;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.Scope;
import com.dfsek.terra.addons.terrascript.lexer.SourcePosition;
public class NumVariableReferenceNode extends VariableReferenceNode<Number> {
public NumVariableReferenceNode(SourcePosition position, Type type, int index) {
super(position, type, index);
}
@Override
public Number evaluate(ImplementationArguments implementationArguments, Scope scope) {
return scope.getNum(index);
}
@Override
public double applyDouble(ImplementationArguments implementationArguments, Scope scope) {
return scope.getNum(index);
}
}

View File

@@ -1,18 +0,0 @@
package com.dfsek.terra.addons.terrascript.legacy.parser.lang.variables.reference;
import com.dfsek.terra.addons.terrascript.Type;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.ImplementationArguments;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.Scope;
import com.dfsek.terra.addons.terrascript.lexer.SourcePosition;
public class StrVariableReferenceNode extends VariableReferenceNode<String> {
public StrVariableReferenceNode(SourcePosition position, Type type, int index) {
super(position, type, index);
}
@Override
public String evaluate(ImplementationArguments implementationArguments, Scope scope) {
return scope.getStr(index);
}
}

View File

@@ -1,35 +0,0 @@
/*
* Copyright (c) 2020-2021 Polyhedral Development
*
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
* reference the LICENSE file in this module's root directory.
*/
package com.dfsek.terra.addons.terrascript.legacy.parser.lang.variables.reference;
import com.dfsek.terra.addons.terrascript.Type;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.Expression;
import com.dfsek.terra.addons.terrascript.lexer.SourcePosition;
public abstract class VariableReferenceNode<T> implements Expression<T> {
protected final int index;
private final SourcePosition position;
private final Type type;
public VariableReferenceNode(SourcePosition position, Type type, int index) {
this.position = position;
this.type = type;
this.index = index;
}
@Override
public Type returnType() {
return type;
}
@Override
public SourcePosition getPosition() {
return position;
}
}

View File

@@ -1,162 +0,0 @@
/*
* Copyright (c) 2020-2021 Polyhedral Development
*
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
* reference the LICENSE file in this module's root directory.
*/
package com.dfsek.terra.addons.terrascript.legacy.script;
import net.jafama.FastMath;
import org.apache.commons.io.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.Charset;
import java.util.Random;
import com.dfsek.terra.addons.terrascript.Type;
import com.dfsek.terra.addons.terrascript.legacy.parser.Parser;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.Executable;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.Scope.ScopeBuilder;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.functions.FunctionBuilder;
import com.dfsek.terra.addons.terrascript.legacy.script.builders.BinaryNumberFunctionBuilder;
import com.dfsek.terra.addons.terrascript.legacy.script.builders.BiomeFunctionBuilder;
import com.dfsek.terra.addons.terrascript.legacy.script.builders.BlockFunctionBuilder;
import com.dfsek.terra.addons.terrascript.legacy.script.builders.CheckBlockFunctionBuilder;
import com.dfsek.terra.addons.terrascript.legacy.script.builders.EntityFunctionBuilder;
import com.dfsek.terra.addons.terrascript.legacy.script.builders.GetMarkFunctionBuilder;
import com.dfsek.terra.addons.terrascript.legacy.script.builders.LootFunctionBuilder;
import com.dfsek.terra.addons.terrascript.legacy.script.builders.PullFunctionBuilder;
import com.dfsek.terra.addons.terrascript.legacy.script.builders.RandomFunctionBuilder;
import com.dfsek.terra.addons.terrascript.legacy.script.builders.RecursionsFunctionBuilder;
import com.dfsek.terra.addons.terrascript.legacy.script.builders.SetMarkFunctionBuilder;
import com.dfsek.terra.addons.terrascript.legacy.script.builders.StateFunctionBuilder;
import com.dfsek.terra.addons.terrascript.legacy.script.builders.StructureFunctionBuilder;
import com.dfsek.terra.addons.terrascript.legacy.script.builders.UnaryBooleanFunctionBuilder;
import com.dfsek.terra.addons.terrascript.legacy.script.builders.UnaryNumberFunctionBuilder;
import com.dfsek.terra.addons.terrascript.legacy.script.builders.UnaryStringFunctionBuilder;
import com.dfsek.terra.addons.terrascript.legacy.script.builders.ZeroArgFunctionBuilder;
import com.dfsek.terra.addons.terrascript.lexer.Lexer;
import com.dfsek.terra.api.Platform;
import com.dfsek.terra.api.registry.Registry;
import com.dfsek.terra.api.registry.key.Keyed;
import com.dfsek.terra.api.registry.key.RegistryKey;
import com.dfsek.terra.api.structure.LootTable;
import com.dfsek.terra.api.structure.Structure;
import com.dfsek.terra.api.util.Rotation;
import com.dfsek.terra.api.util.vector.Vector3Int;
import com.dfsek.terra.api.world.WritableWorld;
public class StructureScript implements Structure, Keyed<StructureScript> {
private static final Logger LOGGER = LoggerFactory.getLogger(StructureScript.class);
private final Executable executable;
private final RegistryKey id;
private final String profile;
private final Platform platform;
@SuppressWarnings("rawtypes")
public StructureScript(InputStream source, RegistryKey id, Platform platform, Registry<Structure> structureRegistry,
Registry<LootTable> lootRegistry,
Registry<FunctionBuilder> functionRegistry) {
Lexer lexer;
try {
lexer = new Lexer(IOUtils.toString(source, Charset.defaultCharset()));
} catch(IOException e) {
throw new RuntimeException(e);
}
Parser parser = new Parser(lexer);
this.id = id;
this.profile = "terrascript_direct:" + id;
ScopeBuilder scope = new ScopeBuilder();
functionRegistry.forEach((key, function) -> scope.registerFunction(key.getID(), function)); // Register registry functions.
scope
.registerFunction("block", new BlockFunctionBuilder(platform))
.registerFunction("debugBlock", new BlockFunctionBuilder(platform))
.registerFunction("structure", new StructureFunctionBuilder(structureRegistry, platform))
.registerFunction("recursions", new RecursionsFunctionBuilder())
.registerFunction("setMark", new SetMarkFunctionBuilder())
.registerFunction("getMark", new GetMarkFunctionBuilder())
.registerFunction("pull", new PullFunctionBuilder(platform))
.registerFunction("loot", new LootFunctionBuilder(platform, lootRegistry, this))
.registerFunction("entity", new EntityFunctionBuilder(platform))
.registerFunction("getBiome", new BiomeFunctionBuilder(platform))
.registerFunction("getBlock", new CheckBlockFunctionBuilder())
.registerFunction("state", new StateFunctionBuilder(platform))
.registerFunction("setWaterlog", new UnaryBooleanFunctionBuilder((waterlog, args) -> args.setWaterlog(waterlog)))
.registerFunction("originX", new ZeroArgFunctionBuilder<Number>(arguments -> arguments.getOrigin().getX(),
Type.NUMBER))
.registerFunction("originY", new ZeroArgFunctionBuilder<Number>(arguments -> arguments.getOrigin().getY(),
Type.NUMBER))
.registerFunction("originZ", new ZeroArgFunctionBuilder<Number>(arguments -> arguments.getOrigin().getZ(),
Type.NUMBER))
.registerFunction("rotation", new ZeroArgFunctionBuilder<>(arguments -> arguments.getRotation().toString(),
Type.STRING))
.registerFunction("rotationDegrees", new ZeroArgFunctionBuilder<>(arguments -> arguments.getRotation().getDegrees(),
Type.NUMBER))
.registerFunction("print",
new UnaryStringFunctionBuilder(string -> LOGGER.info("[TerraScript:{}] {}", id, string)))
.registerFunction("randomInt", new RandomFunctionBuilder())
.registerFunction("abs", new UnaryNumberFunctionBuilder(number -> FastMath.abs(number.doubleValue())))
.registerFunction("pow2", new UnaryNumberFunctionBuilder(number -> FastMath.pow2(number.doubleValue())))
.registerFunction("pow", new BinaryNumberFunctionBuilder(
(number, number2) -> FastMath.pow(number.doubleValue(), number2.doubleValue())))
.registerFunction("sqrt", new UnaryNumberFunctionBuilder(number -> FastMath.sqrt(number.doubleValue())))
.registerFunction("floor", new UnaryNumberFunctionBuilder(number -> FastMath.floor(number.doubleValue())))
.registerFunction("ceil", new UnaryNumberFunctionBuilder(number -> FastMath.ceil(number.doubleValue())))
.registerFunction("log", new UnaryNumberFunctionBuilder(number -> FastMath.log(number.doubleValue())))
.registerFunction("round", new UnaryNumberFunctionBuilder(number -> FastMath.round(number.doubleValue())))
.registerFunction("sin", new UnaryNumberFunctionBuilder(number -> FastMath.sin(number.doubleValue())))
.registerFunction("cos", new UnaryNumberFunctionBuilder(number -> FastMath.cos(number.doubleValue())))
.registerFunction("tan", new UnaryNumberFunctionBuilder(number -> FastMath.tan(number.doubleValue())))
.registerFunction("asin", new UnaryNumberFunctionBuilder(number -> FastMath.asin(number.doubleValue())))
.registerFunction("acos", new UnaryNumberFunctionBuilder(number -> FastMath.acos(number.doubleValue())))
.registerFunction("atan", new UnaryNumberFunctionBuilder(number -> FastMath.atan(number.doubleValue())))
.registerFunction("max", new BinaryNumberFunctionBuilder(
(number, number2) -> FastMath.max(number.doubleValue(), number2.doubleValue())))
.registerFunction("min", new BinaryNumberFunctionBuilder(
(number, number2) -> FastMath.min(number.doubleValue(), number2.doubleValue())));
executable = parser.parse(scope);
this.platform = platform;
}
@Override
@SuppressWarnings("try")
public boolean generate(Vector3Int location, WritableWorld world, Random random, Rotation rotation) {
platform.getProfiler().push(profile);
boolean result = execute(new TerraImplementationArguments(location, rotation, random, world, 0));
platform.getProfiler().pop(profile);
return result;
}
public boolean generate(Vector3Int location, WritableWorld world, Random random, Rotation rotation, int recursions) {
platform.getProfiler().push(profile);
boolean result = execute(new TerraImplementationArguments(location, rotation, random, world, recursions));
platform.getProfiler().pop(profile);
return result;
}
private boolean execute(TerraImplementationArguments arguments) {
try {
return executable.execute(arguments);
} catch(RuntimeException e) {
LOGGER.error("Failed to generate structure at {}", arguments.getOrigin(), e);
return false;
}
}
@Override
public RegistryKey getRegistryKey() {
return id;
}
}

View File

@@ -1,73 +0,0 @@
/*
* Copyright (c) 2020-2021 Polyhedral Development
*
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
* reference the LICENSE file in this module's root directory.
*/
package com.dfsek.terra.addons.terrascript.legacy.script;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.ImplementationArguments;
import com.dfsek.terra.api.util.Rotation;
import com.dfsek.terra.api.util.vector.Vector3;
import com.dfsek.terra.api.util.vector.Vector3Int;
import com.dfsek.terra.api.world.WritableWorld;
public class TerraImplementationArguments implements ImplementationArguments {
private final Rotation rotation;
private final Random random;
private final WritableWorld world;
private final Map<Vector3, String> marks = new HashMap<>();
private final int recursions;
private final Vector3Int origin;
private boolean waterlog = false;
public TerraImplementationArguments(Vector3Int origin, Rotation rotation, Random random, WritableWorld world, int recursions) {
this.rotation = rotation;
this.random = random;
this.world = world;
this.recursions = recursions;
this.origin = origin;
}
public int getRecursions() {
return recursions;
}
public Random getRandom() {
return random;
}
public Rotation getRotation() {
return rotation;
}
public boolean isWaterlog() {
return waterlog;
}
public void setWaterlog(boolean waterlog) {
this.waterlog = waterlog;
}
public WritableWorld getWorld() {
return world;
}
public Vector3Int getOrigin() {
return origin;
}
public void setMark(Vector3 pos, String mark) {
marks.put(pos, mark);
}
public String getMark(Vector3 pos) {
return marks.get(pos);
}
}

View File

@@ -1,62 +0,0 @@
/*
* Copyright (c) 2020-2021 Polyhedral Development
*
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
* reference the LICENSE file in this module's root directory.
*/
package com.dfsek.terra.addons.terrascript.legacy.script.builders;
import java.util.List;
import java.util.function.BiFunction;
import com.dfsek.terra.addons.terrascript.Type;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.Expression;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.ImplementationArguments;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.Scope;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.functions.Function;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.functions.FunctionBuilder;
import com.dfsek.terra.addons.terrascript.lexer.SourcePosition;
public class BinaryNumberFunctionBuilder implements FunctionBuilder<Function<Number>> {
private final BiFunction<Number, Number, Number> function;
public BinaryNumberFunctionBuilder(BiFunction<Number, Number, Number> function) {
this.function = function;
}
@Override
public Function<Number> build(List<Expression<?>> argumentList, SourcePosition position) {
return new Function<>() {
@Override
public Type returnType() {
return Type.NUMBER;
}
@SuppressWarnings("unchecked")
@Override
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
public SourcePosition getPosition() {
return position;
}
};
}
@Override
public int argNumber() {
return 2;
}
@Override
public Type getArgument(int position) {
if(position == 0 || position == 1) return Type.NUMBER;
return null;
}
}

View File

@@ -1,46 +0,0 @@
/*
* Copyright (c) 2020-2021 Polyhedral Development
*
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
* reference the LICENSE file in this module's root directory.
*/
package com.dfsek.terra.addons.terrascript.legacy.script.builders;
import java.util.List;
import com.dfsek.terra.addons.terrascript.Type;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.Expression;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.functions.FunctionBuilder;
import com.dfsek.terra.addons.terrascript.legacy.script.functions.BiomeFunction;
import com.dfsek.terra.addons.terrascript.lexer.SourcePosition;
import com.dfsek.terra.api.Platform;
public class BiomeFunctionBuilder implements FunctionBuilder<BiomeFunction> {
private final Platform platform;
public BiomeFunctionBuilder(Platform platform) {
this.platform = platform;
}
@SuppressWarnings("unchecked")
@Override
public BiomeFunction build(List<Expression<?>> argumentList, SourcePosition position) {
return new BiomeFunction((Expression<Number>) argumentList.get(0), (Expression<Number>) argumentList.get(1),
(Expression<Number>) argumentList.get(2), position);
}
@Override
public int argNumber() {
return 3;
}
@Override
public Type getArgument(int position) {
return switch(position) {
case 0, 1, 2 -> Type.NUMBER;
default -> null;
};
}
}

View File

@@ -1,60 +0,0 @@
/*
* Copyright (c) 2020-2021 Polyhedral Development
*
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
* reference the LICENSE file in this module's root directory.
*/
package com.dfsek.terra.addons.terrascript.legacy.script.builders;
import java.util.List;
import com.dfsek.terra.addons.terrascript.Type;
import com.dfsek.terra.addons.terrascript.legacy.parser.exceptions.ParseException;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.Expression;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.constants.BooleanConstant;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.constants.StringConstant;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.functions.FunctionBuilder;
import com.dfsek.terra.addons.terrascript.legacy.script.functions.BlockFunction;
import com.dfsek.terra.addons.terrascript.lexer.SourcePosition;
import com.dfsek.terra.api.Platform;
public class BlockFunctionBuilder implements FunctionBuilder<BlockFunction> {
private final Platform platform;
public BlockFunctionBuilder(Platform platform) {
this.platform = platform;
}
@SuppressWarnings("unchecked")
@Override
public BlockFunction build(List<Expression<?>> argumentList, SourcePosition position) {
if(argumentList.size() < 4) throw new ParseException("Expected data", position);
Expression<Boolean> booleanReturnable = new BooleanConstant(true, position);
if(argumentList.size() == 5) booleanReturnable = (Expression<Boolean>) argumentList.get(4);
if(argumentList.get(3) instanceof StringConstant) {
return new BlockFunction.Constant((Expression<Number>) argumentList.get(0), (Expression<Number>) argumentList.get(1),
(Expression<Number>) argumentList.get(2), (StringConstant) argumentList.get(3),
booleanReturnable, platform, position);
}
return new BlockFunction((Expression<Number>) argumentList.get(0), (Expression<Number>) argumentList.get(1),
(Expression<Number>) argumentList.get(2), (Expression<String>) argumentList.get(3), booleanReturnable,
platform, position);
}
@Override
public int argNumber() {
return -1;
}
@Override
public Type getArgument(int position) {
return switch(position) {
case 0, 1, 2 -> Type.NUMBER;
case 3 -> Type.STRING;
case 4 -> Type.BOOLEAN;
default -> null;
};
}
}

View File

@@ -1,39 +0,0 @@
/*
* Copyright (c) 2020-2021 Polyhedral Development
*
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
* reference the LICENSE file in this module's root directory.
*/
package com.dfsek.terra.addons.terrascript.legacy.script.builders;
import java.util.List;
import com.dfsek.terra.addons.terrascript.Type;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.Expression;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.functions.FunctionBuilder;
import com.dfsek.terra.addons.terrascript.legacy.script.functions.CheckBlockFunction;
import com.dfsek.terra.addons.terrascript.lexer.SourcePosition;
public class CheckBlockFunctionBuilder implements FunctionBuilder<CheckBlockFunction> {
@SuppressWarnings("unchecked")
@Override
public CheckBlockFunction build(List<Expression<?>> argumentList, SourcePosition position) {
return new CheckBlockFunction((Expression<Number>) argumentList.get(0), (Expression<Number>) argumentList.get(1),
(Expression<Number>) argumentList.get(2), position);
}
@Override
public int argNumber() {
return 3;
}
@Override
public Type getArgument(int position) {
return switch(position) {
case 0, 1, 2 -> Type.NUMBER;
default -> null;
};
}
}

View File

@@ -1,47 +0,0 @@
/*
* Copyright (c) 2020-2021 Polyhedral Development
*
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
* reference the LICENSE file in this module's root directory.
*/
package com.dfsek.terra.addons.terrascript.legacy.script.builders;
import java.util.List;
import com.dfsek.terra.addons.terrascript.Type;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.Expression;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.functions.FunctionBuilder;
import com.dfsek.terra.addons.terrascript.legacy.script.functions.EntityFunction;
import com.dfsek.terra.addons.terrascript.lexer.SourcePosition;
import com.dfsek.terra.api.Platform;
public class EntityFunctionBuilder implements FunctionBuilder<EntityFunction> {
private final Platform platform;
public EntityFunctionBuilder(Platform platform) {
this.platform = platform;
}
@SuppressWarnings("unchecked")
@Override
public EntityFunction build(List<Expression<?>> argumentList, SourcePosition position) {
return new EntityFunction((Expression<Number>) argumentList.get(0), (Expression<Number>) argumentList.get(1),
(Expression<Number>) argumentList.get(2), (Expression<String>) argumentList.get(3), platform, position);
}
@Override
public int argNumber() {
return 4;
}
@Override
public Type getArgument(int position) {
return switch(position) {
case 0, 1, 2 -> Type.NUMBER;
case 3 -> Type.STRING;
default -> null;
};
}
}

View File

@@ -1,43 +0,0 @@
/*
* Copyright (c) 2020-2021 Polyhedral Development
*
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
* reference the LICENSE file in this module's root directory.
*/
package com.dfsek.terra.addons.terrascript.legacy.script.builders;
import java.util.List;
import com.dfsek.terra.addons.terrascript.Type;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.Expression;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.functions.FunctionBuilder;
import com.dfsek.terra.addons.terrascript.legacy.script.functions.GetMarkFunction;
import com.dfsek.terra.addons.terrascript.lexer.SourcePosition;
public class GetMarkFunctionBuilder implements FunctionBuilder<GetMarkFunction> {
public GetMarkFunctionBuilder() {
}
@SuppressWarnings("unchecked")
@Override
public GetMarkFunction build(List<Expression<?>> argumentList, SourcePosition position) {
return new GetMarkFunction((Expression<Number>) argumentList.get(0), (Expression<Number>) argumentList.get(1),
(Expression<Number>) argumentList.get(2), position);
}
@Override
public int argNumber() {
return 3;
}
@Override
public Type getArgument(int position) {
return switch(position) {
case 0, 1, 2 -> Type.NUMBER;
default -> null;
};
}
}

View File

@@ -1,55 +0,0 @@
/*
* Copyright (c) 2020-2021 Polyhedral Development
*
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
* reference the LICENSE file in this module's root directory.
*/
package com.dfsek.terra.addons.terrascript.legacy.script.builders;
import java.util.List;
import com.dfsek.terra.addons.terrascript.Type;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.Expression;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.functions.FunctionBuilder;
import com.dfsek.terra.addons.terrascript.legacy.script.StructureScript;
import com.dfsek.terra.addons.terrascript.legacy.script.functions.LootFunction;
import com.dfsek.terra.addons.terrascript.lexer.SourcePosition;
import com.dfsek.terra.api.Platform;
import com.dfsek.terra.api.registry.Registry;
import com.dfsek.terra.api.structure.LootTable;
public class LootFunctionBuilder implements FunctionBuilder<LootFunction> {
private final Platform platform;
private final Registry<LootTable> registry;
private final StructureScript script;
public LootFunctionBuilder(Platform platform, Registry<LootTable> registry, StructureScript script) {
this.platform = platform;
this.registry = registry;
this.script = script;
}
@SuppressWarnings("unchecked")
@Override
public LootFunction build(List<Expression<?>> argumentList, SourcePosition position) {
return new LootFunction(registry, (Expression<Number>) argumentList.get(0), (Expression<Number>) argumentList.get(1),
(Expression<Number>) argumentList.get(2), (Expression<String>) argumentList.get(3), platform, position,
script);
}
@Override
public int argNumber() {
return 4;
}
@Override
public Type getArgument(int position) {
return switch(position) {
case 0, 1, 2 -> Type.NUMBER;
case 3 -> Type.STRING;
default -> null;
};
}
}

View File

@@ -1,47 +0,0 @@
/*
* Copyright (c) 2020-2021 Polyhedral Development
*
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
* reference the LICENSE file in this module's root directory.
*/
package com.dfsek.terra.addons.terrascript.legacy.script.builders;
import java.util.List;
import com.dfsek.terra.addons.terrascript.Type;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.Expression;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.functions.FunctionBuilder;
import com.dfsek.terra.addons.terrascript.legacy.script.functions.PullFunction;
import com.dfsek.terra.addons.terrascript.lexer.SourcePosition;
import com.dfsek.terra.api.Platform;
public class PullFunctionBuilder implements FunctionBuilder<PullFunction> {
private final Platform platform;
public PullFunctionBuilder(Platform platform) {
this.platform = platform;
}
@SuppressWarnings("unchecked")
@Override
public PullFunction build(List<Expression<?>> argumentList, SourcePosition position) {
return new PullFunction((Expression<Number>) argumentList.get(0), (Expression<Number>) argumentList.get(1),
(Expression<Number>) argumentList.get(2), (Expression<String>) argumentList.get(3), platform, position);
}
@Override
public int argNumber() {
return 4;
}
@Override
public Type getArgument(int position) {
return switch(position) {
case 0, 1, 2 -> Type.NUMBER;
case 3 -> Type.STRING;
default -> null;
};
}
}

View File

@@ -1,36 +0,0 @@
/*
* Copyright (c) 2020-2021 Polyhedral Development
*
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
* reference the LICENSE file in this module's root directory.
*/
package com.dfsek.terra.addons.terrascript.legacy.script.builders;
import java.util.List;
import com.dfsek.terra.addons.terrascript.Type;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.Expression;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.functions.FunctionBuilder;
import com.dfsek.terra.addons.terrascript.legacy.script.functions.RandomFunction;
import com.dfsek.terra.addons.terrascript.lexer.SourcePosition;
public class RandomFunctionBuilder implements FunctionBuilder<RandomFunction> {
@SuppressWarnings("unchecked")
@Override
public RandomFunction build(List<Expression<?>> argumentList, SourcePosition position) {
return new RandomFunction((Expression<Number>) argumentList.get(0), position);
}
@Override
public int argNumber() {
return 1;
}
@Override
public Type getArgument(int position) {
if(position == 0) return Type.NUMBER;
return null;
}
}

View File

@@ -1,34 +0,0 @@
/*
* Copyright (c) 2020-2021 Polyhedral Development
*
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
* reference the LICENSE file in this module's root directory.
*/
package com.dfsek.terra.addons.terrascript.legacy.script.builders;
import java.util.List;
import com.dfsek.terra.addons.terrascript.Type;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.Expression;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.functions.FunctionBuilder;
import com.dfsek.terra.addons.terrascript.legacy.script.functions.RecursionsFunction;
import com.dfsek.terra.addons.terrascript.lexer.SourcePosition;
public class RecursionsFunctionBuilder implements FunctionBuilder<RecursionsFunction> {
@Override
public RecursionsFunction build(List<Expression<?>> argumentList, SourcePosition position) {
return new RecursionsFunction(position);
}
@Override
public int argNumber() {
return 0;
}
@Override
public Type getArgument(int position) {
return null;
}
}

View File

@@ -1,44 +0,0 @@
/*
* Copyright (c) 2020-2021 Polyhedral Development
*
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
* reference the LICENSE file in this module's root directory.
*/
package com.dfsek.terra.addons.terrascript.legacy.script.builders;
import java.util.List;
import com.dfsek.terra.addons.terrascript.Type;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.Expression;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.functions.FunctionBuilder;
import com.dfsek.terra.addons.terrascript.legacy.script.functions.SetMarkFunction;
import com.dfsek.terra.addons.terrascript.lexer.SourcePosition;
public class SetMarkFunctionBuilder implements FunctionBuilder<SetMarkFunction> {
public SetMarkFunctionBuilder() {
}
@SuppressWarnings("unchecked")
@Override
public SetMarkFunction build(List<Expression<?>> argumentList, SourcePosition position) {
return new SetMarkFunction((Expression<Number>) argumentList.get(0), (Expression<Number>) argumentList.get(1),
(Expression<Number>) argumentList.get(2), (Expression<String>) argumentList.get(3), position);
}
@Override
public int argNumber() {
return 4;
}
@Override
public Type getArgument(int position) {
return switch(position) {
case 0, 1, 2 -> Type.NUMBER;
case 3 -> Type.STRING;
default -> null;
};
}
}

View File

@@ -1,49 +0,0 @@
/*
* Copyright (c) 2020-2021 Polyhedral Development
*
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
* reference the LICENSE file in this module's root directory.
*/
package com.dfsek.terra.addons.terrascript.legacy.script.builders;
import java.util.List;
import com.dfsek.terra.addons.terrascript.Type;
import com.dfsek.terra.addons.terrascript.legacy.parser.exceptions.ParseException;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.Expression;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.functions.FunctionBuilder;
import com.dfsek.terra.addons.terrascript.legacy.script.functions.StateFunction;
import com.dfsek.terra.addons.terrascript.lexer.SourcePosition;
import com.dfsek.terra.api.Platform;
public class StateFunctionBuilder implements FunctionBuilder<StateFunction> {
private final Platform platform;
public StateFunctionBuilder(Platform platform) {
this.platform = platform;
}
@SuppressWarnings("unchecked")
@Override
public StateFunction build(List<Expression<?>> argumentList, SourcePosition position) {
if(argumentList.size() < 4) throw new ParseException("Expected data", position);
return new StateFunction((Expression<Number>) argumentList.get(0), (Expression<Number>) argumentList.get(1),
(Expression<Number>) argumentList.get(2), (Expression<String>) argumentList.get(3), position);
}
@Override
public int argNumber() {
return 4;
}
@Override
public Type getArgument(int position) {
return switch(position) {
case 0, 1, 2 -> Type.NUMBER;
case 3 -> Type.STRING;
default -> null;
};
}
}

View File

@@ -1,56 +0,0 @@
/*
* Copyright (c) 2020-2021 Polyhedral Development
*
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
* reference the LICENSE file in this module's root directory.
*/
package com.dfsek.terra.addons.terrascript.legacy.script.builders;
import java.util.List;
import java.util.stream.Collectors;
import com.dfsek.terra.addons.terrascript.Type;
import com.dfsek.terra.addons.terrascript.legacy.parser.exceptions.ParseException;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.Expression;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.functions.FunctionBuilder;
import com.dfsek.terra.addons.terrascript.legacy.script.functions.StructureFunction;
import com.dfsek.terra.addons.terrascript.lexer.SourcePosition;
import com.dfsek.terra.api.Platform;
import com.dfsek.terra.api.registry.Registry;
import com.dfsek.terra.api.structure.Structure;
public class StructureFunctionBuilder implements FunctionBuilder<StructureFunction> {
private final Registry<Structure> registry;
private final Platform platform;
public StructureFunctionBuilder(Registry<Structure> registry, Platform platform) {
this.registry = registry;
this.platform = platform;
}
@SuppressWarnings("unchecked")
@Override
public StructureFunction build(List<Expression<?>> argumentList, SourcePosition position) {
if(argumentList.size() < 5) throw new ParseException("Expected rotations", position);
return new StructureFunction((Expression<Number>) argumentList.remove(0), (Expression<Number>) argumentList.remove(0),
(Expression<Number>) argumentList.remove(0), (Expression<String>) argumentList.remove(0),
argumentList.stream().map(item -> ((Expression<String>) item)).collect(Collectors.toList()), registry,
position, platform);
}
@Override
public int argNumber() {
return -1;
}
@Override
public Type getArgument(int position) {
return switch(position) {
case 0, 1, 2 -> Type.NUMBER;
default -> Type.STRING;
};
}
}

View File

@@ -1,64 +0,0 @@
/*
* Copyright (c) 2020-2021 Polyhedral Development
*
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
* reference the LICENSE file in this module's root directory.
*/
package com.dfsek.terra.addons.terrascript.legacy.script.builders;
import java.util.List;
import java.util.function.BiConsumer;
import com.dfsek.terra.addons.terrascript.Type;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.Expression;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.ImplementationArguments;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.Scope;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.functions.Function;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.functions.FunctionBuilder;
import com.dfsek.terra.addons.terrascript.legacy.script.TerraImplementationArguments;
import com.dfsek.terra.addons.terrascript.lexer.SourcePosition;
public class UnaryBooleanFunctionBuilder implements FunctionBuilder<Function<Void>> {
private final BiConsumer<Boolean, TerraImplementationArguments> function;
public UnaryBooleanFunctionBuilder(BiConsumer<Boolean, TerraImplementationArguments> function) {
this.function = function;
}
@Override
public Function<Void> build(List<Expression<?>> argumentList, SourcePosition position) {
return new Function<>() {
@Override
public Type returnType() {
return Type.VOID;
}
@SuppressWarnings("unchecked")
@Override
public Void evaluate(ImplementationArguments implementationArguments, Scope scope) {
function.accept(((Expression<Boolean>) argumentList.get(0)).evaluate(implementationArguments, scope),
(TerraImplementationArguments) implementationArguments);
return null;
}
@Override
public SourcePosition getPosition() {
return position;
}
};
}
@Override
public int argNumber() {
return 1;
}
@Override
public Type getArgument(int position) {
if(position == 0) return Type.BOOLEAN;
return null;
}
}

View File

@@ -1,60 +0,0 @@
/*
* Copyright (c) 2020-2021 Polyhedral Development
*
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
* reference the LICENSE file in this module's root directory.
*/
package com.dfsek.terra.addons.terrascript.legacy.script.builders;
import java.util.List;
import com.dfsek.terra.addons.terrascript.Type;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.Expression;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.ImplementationArguments;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.Scope;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.functions.Function;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.functions.FunctionBuilder;
import com.dfsek.terra.addons.terrascript.lexer.SourcePosition;
public class UnaryNumberFunctionBuilder implements FunctionBuilder<Function<Number>> {
private final java.util.function.Function<Number, Number> function;
public UnaryNumberFunctionBuilder(java.util.function.Function<Number, Number> function) {
this.function = function;
}
@Override
public Function<Number> build(List<Expression<?>> argumentList, SourcePosition position) {
return new Function<>() {
@Override
public Type returnType() {
return Type.NUMBER;
}
@SuppressWarnings("unchecked")
@Override
public Number evaluate(ImplementationArguments implementationArguments, Scope scope) {
return function.apply(((Expression<Number>) argumentList.get(0)).evaluate(implementationArguments, scope));
}
@Override
public SourcePosition getPosition() {
return position;
}
};
}
@Override
public int argNumber() {
return 1;
}
@Override
public Type getArgument(int position) {
if(position == 0) return Type.NUMBER;
return null;
}
}

View File

@@ -1,61 +0,0 @@
/*
* Copyright (c) 2020-2021 Polyhedral Development
*
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
* reference the LICENSE file in this module's root directory.
*/
package com.dfsek.terra.addons.terrascript.legacy.script.builders;
import java.util.List;
import com.dfsek.terra.addons.terrascript.Type;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.Expression;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.ImplementationArguments;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.Scope;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.functions.Function;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.functions.FunctionBuilder;
import com.dfsek.terra.addons.terrascript.lexer.SourcePosition;
public class UnaryStringFunctionBuilder implements FunctionBuilder<Function<Void>> {
private final java.util.function.Consumer<String> function;
public UnaryStringFunctionBuilder(java.util.function.Consumer<String> function) {
this.function = function;
}
@Override
public Function<Void> build(List<Expression<?>> argumentList, SourcePosition position) {
return new Function<>() {
@Override
public Type returnType() {
return Type.VOID;
}
@SuppressWarnings("unchecked")
@Override
public Void evaluate(ImplementationArguments implementationArguments, Scope scope) {
function.accept(((Expression<String>) argumentList.get(0)).evaluate(implementationArguments, scope));
return null;
}
@Override
public SourcePosition getPosition() {
return position;
}
};
}
@Override
public int argNumber() {
return 1;
}
@Override
public Type getArgument(int position) {
if(position == 0) return Type.STRING;
return null;
}
}

View File

@@ -1,61 +0,0 @@
/*
* Copyright (c) 2020-2021 Polyhedral Development
*
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
* reference the LICENSE file in this module's root directory.
*/
package com.dfsek.terra.addons.terrascript.legacy.script.builders;
import java.util.List;
import com.dfsek.terra.addons.terrascript.Type;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.Expression;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.ImplementationArguments;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.Scope;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.functions.Function;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.functions.FunctionBuilder;
import com.dfsek.terra.addons.terrascript.legacy.script.TerraImplementationArguments;
import com.dfsek.terra.addons.terrascript.lexer.SourcePosition;
public class ZeroArgFunctionBuilder<T> implements FunctionBuilder<Function<T>> {
private final java.util.function.Function<TerraImplementationArguments, T> function;
private final Type type;
public ZeroArgFunctionBuilder(java.util.function.Function<TerraImplementationArguments, T> function, Type type) {
this.function = function;
this.type = type;
}
@Override
public Function<T> build(List<Expression<?>> argumentList, SourcePosition position) {
return new Function<>() {
@Override
public Type returnType() {
return type;
}
@Override
public T evaluate(ImplementationArguments implementationArguments, Scope scope) {
return function.apply((TerraImplementationArguments) implementationArguments);
}
@Override
public SourcePosition getPosition() {
return position;
}
};
}
@Override
public int argNumber() {
return 0;
}
@Override
public Type getArgument(int position) {
if(position == 0) return type;
return null;
}
}

View File

@@ -1,66 +0,0 @@
/*
* Copyright (c) 2020-2021 Polyhedral Development
*
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
* reference the LICENSE file in this module's root directory.
*/
package com.dfsek.terra.addons.terrascript.legacy.script.functions;
import net.jafama.FastMath;
import com.dfsek.terra.addons.terrascript.Type;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.Expression;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.ImplementationArguments;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.Scope;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.functions.Function;
import com.dfsek.terra.addons.terrascript.legacy.script.TerraImplementationArguments;
import com.dfsek.terra.addons.terrascript.lexer.SourcePosition;
import com.dfsek.terra.api.util.RotationUtil;
import com.dfsek.terra.api.util.vector.Vector2;
import com.dfsek.terra.api.util.vector.Vector3;
import com.dfsek.terra.api.world.biome.generation.BiomeProvider;
public class BiomeFunction implements Function<String> {
private final Expression<Number> x, y, z;
private final SourcePosition position;
public BiomeFunction(Expression<Number> x, Expression<Number> y, Expression<Number> z, SourcePosition position) {
this.x = x;
this.y = y;
this.z = z;
this.position = position;
}
@Override
public String evaluate(ImplementationArguments implementationArguments, Scope scope) {
TerraImplementationArguments arguments = (TerraImplementationArguments) implementationArguments;
Vector2 xz = RotationUtil.rotateVector(Vector2.of(x.evaluate(implementationArguments, scope).doubleValue(),
z.evaluate(implementationArguments, scope).doubleValue()),
arguments.getRotation());
BiomeProvider grid = arguments.getWorld().getBiomeProvider();
return grid.getBiome(arguments.getOrigin()
.toVector3()
.mutable()
.add(Vector3.of(FastMath.roundToInt(xz.getX()),
y.evaluate(implementationArguments, scope).intValue(),
FastMath.roundToInt(xz.getZ()))).immutable(), arguments.getWorld().getSeed()).getID();
}
@Override
public SourcePosition getPosition() {
return position;
}
@Override
public Type returnType() {
return Type.STRING;
}
}

View File

@@ -1,107 +0,0 @@
/*
* Copyright (c) 2020-2021 Polyhedral Development
*
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
* reference the LICENSE file in this module's root directory.
*/
package com.dfsek.terra.addons.terrascript.legacy.script.functions;
import net.jafama.FastMath;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.HashMap;
import java.util.Map;
import com.dfsek.terra.addons.terrascript.Type;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.Expression;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.ImplementationArguments;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.Scope;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.constants.StringConstant;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.functions.Function;
import com.dfsek.terra.addons.terrascript.legacy.script.TerraImplementationArguments;
import com.dfsek.terra.addons.terrascript.lexer.SourcePosition;
import com.dfsek.terra.api.Platform;
import com.dfsek.terra.api.block.state.BlockState;
import com.dfsek.terra.api.util.RotationUtil;
import com.dfsek.terra.api.util.vector.Vector2;
import com.dfsek.terra.api.util.vector.Vector3;
public class BlockFunction implements Function<Void> {
private static final Logger logger = LoggerFactory.getLogger(BlockFunction.class);
protected final Expression<Number> x, y, z;
protected final Expression<String> blockData;
protected final Platform platform;
private final Map<String, BlockState> data = new HashMap<>();
private final Expression<Boolean> overwrite;
private final SourcePosition position;
public BlockFunction(Expression<Number> x, Expression<Number> y, Expression<Number> z, Expression<String> blockData,
Expression<Boolean> overwrite, Platform platform, SourcePosition position) {
this.x = x;
this.y = y;
this.z = z;
this.blockData = blockData;
this.overwrite = overwrite;
this.platform = platform;
this.position = position;
}
@Override
public Void evaluate(ImplementationArguments implementationArguments, Scope scope) {
TerraImplementationArguments arguments = (TerraImplementationArguments) implementationArguments;
BlockState rot = getBlockState(implementationArguments, scope);
setBlock(implementationArguments, scope, arguments, rot);
return null;
}
@Override
public SourcePosition getPosition() {
return position;
}
@Override
public Type returnType() {
return Type.VOID;
}
void setBlock(ImplementationArguments implementationArguments, Scope scope,
TerraImplementationArguments arguments, BlockState rot) {
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.evaluate(implementationArguments, scope).doubleValue(),
FastMath.roundToInt(xz.getZ())).mutable().add(arguments.getOrigin());
BlockState current = arguments.getWorld().getBlockState(set);
if(overwrite.evaluate(implementationArguments, scope) || current.isAir()) {
arguments.getWorld().setBlockState(set, rot);
}
} catch(RuntimeException e) {
logger.error("Failed to place block at location {}", arguments.getOrigin(), e);
}
}
protected BlockState getBlockState(ImplementationArguments arguments, Scope scope) {
return data.computeIfAbsent(blockData.evaluate(arguments, scope), platform.getWorldHandle()::createBlockState);
}
public static class Constant extends BlockFunction {
private final BlockState state;
public Constant(Expression<Number> x, Expression<Number> y, Expression<Number> z, StringConstant blockData,
Expression<Boolean> overwrite, Platform platform, SourcePosition position) {
super(x, y, z, blockData, overwrite, platform, position);
this.state = platform.getWorldHandle().createBlockState(blockData.getConstant());
}
@Override
protected BlockState getBlockState(ImplementationArguments arguments, Scope scope) {
return state;
}
}
}

View File

@@ -1,66 +0,0 @@
/*
* Copyright (c) 2020-2021 Polyhedral Development
*
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
* reference the LICENSE file in this module's root directory.
*/
package com.dfsek.terra.addons.terrascript.legacy.script.functions;
import net.jafama.FastMath;
import com.dfsek.terra.addons.terrascript.Type;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.Expression;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.ImplementationArguments;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.Scope;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.functions.Function;
import com.dfsek.terra.addons.terrascript.legacy.script.TerraImplementationArguments;
import com.dfsek.terra.addons.terrascript.lexer.SourcePosition;
import com.dfsek.terra.api.util.RotationUtil;
import com.dfsek.terra.api.util.vector.Vector2;
import com.dfsek.terra.api.util.vector.Vector3;
public class CheckBlockFunction implements Function<String> {
private final Expression<Number> x, y, z;
private final SourcePosition position;
public CheckBlockFunction(Expression<Number> x, Expression<Number> y, Expression<Number> z, SourcePosition position) {
this.x = x;
this.y = y;
this.z = z;
this.position = position;
}
@Override
public String evaluate(ImplementationArguments implementationArguments, Scope scope) {
TerraImplementationArguments arguments = (TerraImplementationArguments) implementationArguments;
Vector2 xz = RotationUtil.rotateVector(Vector2.of(x.evaluate(implementationArguments, scope).doubleValue(),
z.evaluate(implementationArguments, scope).doubleValue()),
arguments.getRotation());
String data = arguments.getWorld()
.getBlockState(arguments.getOrigin()
.toVector3()
.mutable()
.add(Vector3.of(FastMath.roundToInt(xz.getX()),
y.evaluate(implementationArguments, scope)
.doubleValue(), FastMath.roundToInt(xz.getZ()))))
.getAsString();
if(data.contains("[")) return data.substring(0, data.indexOf('[')); // Strip properties
else return data;
}
@Override
public SourcePosition getPosition() {
return position;
}
@Override
public Type returnType() {
return Type.STRING;
}
}

View File

@@ -1,72 +0,0 @@
/*
* Copyright (c) 2020-2021 Polyhedral Development
*
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
* reference the LICENSE file in this module's root directory.
*/
package com.dfsek.terra.addons.terrascript.legacy.script.functions;
import com.dfsek.terra.addons.terrascript.Type;
import com.dfsek.terra.addons.terrascript.legacy.parser.exceptions.ParseException;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.Expression;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.ImplementationArguments;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.Scope;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.constants.ConstantExpression;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.functions.Function;
import com.dfsek.terra.addons.terrascript.legacy.script.TerraImplementationArguments;
import com.dfsek.terra.addons.terrascript.lexer.SourcePosition;
import com.dfsek.terra.api.Platform;
import com.dfsek.terra.api.entity.Entity;
import com.dfsek.terra.api.entity.EntityType;
import com.dfsek.terra.api.event.events.world.generation.EntitySpawnEvent;
import com.dfsek.terra.api.util.RotationUtil;
import com.dfsek.terra.api.util.vector.Vector2;
import com.dfsek.terra.api.util.vector.Vector3;
public class EntityFunction implements Function<Void> {
private final EntityType data;
private final Expression<Number> x, y, z;
private final SourcePosition position;
private final Platform platform;
public EntityFunction(Expression<Number> x, Expression<Number> y, Expression<Number> z, Expression<String> data, Platform platform,
SourcePosition position) {
this.position = position;
this.platform = platform;
if(!(data instanceof ConstantExpression)) throw new ParseException("Entity data must be constant", data.getPosition());
this.data = platform.getWorldHandle().getEntity(((ConstantExpression<String>) data).getConstant());
this.x = x;
this.y = y;
this.z = z;
}
@Override
public Void evaluate(ImplementationArguments implementationArguments, Scope scope) {
TerraImplementationArguments arguments = (TerraImplementationArguments) implementationArguments;
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.evaluate(implementationArguments, scope).doubleValue(),
xz.getZ())
.mutable()
.add(arguments.getOrigin())
.add(0.5, 0, 0.5)
.immutable(), data);
platform.getEventManager().callEvent(new EntitySpawnEvent(entity.world().getPack(), entity));
return null;
}
@Override
public SourcePosition getPosition() {
return position;
}
@Override
public Type returnType() {
return Type.VOID;
}
}

View File

@@ -1,60 +0,0 @@
/*
* Copyright (c) 2020-2021 Polyhedral Development
*
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
* reference the LICENSE file in this module's root directory.
*/
package com.dfsek.terra.addons.terrascript.legacy.script.functions;
import net.jafama.FastMath;
import com.dfsek.terra.addons.terrascript.Type;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.Expression;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.ImplementationArguments;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.Scope;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.functions.Function;
import com.dfsek.terra.addons.terrascript.legacy.script.TerraImplementationArguments;
import com.dfsek.terra.addons.terrascript.lexer.SourcePosition;
import com.dfsek.terra.api.util.RotationUtil;
import com.dfsek.terra.api.util.vector.Vector2;
import com.dfsek.terra.api.util.vector.Vector3;
public class GetMarkFunction implements Function<String> {
private final Expression<Number> x, y, z;
private final SourcePosition position;
public GetMarkFunction(Expression<Number> x, Expression<Number> y, Expression<Number> z, SourcePosition position) {
this.position = position;
this.x = x;
this.y = y;
this.z = z;
}
@Override
public String evaluate(ImplementationArguments implementationArguments, Scope scope) {
TerraImplementationArguments arguments = (TerraImplementationArguments) implementationArguments;
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.evaluate(implementationArguments, scope).doubleValue()),
FastMath.floorToInt(xz.getZ()))
.mutable()
.add(arguments.getOrigin())
.immutable());
return mark == null ? "" : mark;
}
@Override
public SourcePosition getPosition() {
return position;
}
@Override
public Type returnType() {
return Type.STRING;
}
}

View File

@@ -1,109 +0,0 @@
/*
* Copyright (c) 2020-2021 Polyhedral Development
*
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
* reference the LICENSE file in this module's root directory.
*/
package com.dfsek.terra.addons.terrascript.legacy.script.functions;
import net.jafama.FastMath;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Random;
import com.dfsek.terra.addons.terrascript.Type;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.Expression;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.ImplementationArguments;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.Scope;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.functions.Function;
import com.dfsek.terra.addons.terrascript.legacy.script.StructureScript;
import com.dfsek.terra.addons.terrascript.legacy.script.TerraImplementationArguments;
import com.dfsek.terra.addons.terrascript.lexer.SourcePosition;
import com.dfsek.terra.api.Platform;
import com.dfsek.terra.api.block.entity.BlockEntity;
import com.dfsek.terra.api.block.entity.Container;
import com.dfsek.terra.api.event.events.world.generation.LootPopulateEvent;
import com.dfsek.terra.api.registry.Registry;
import com.dfsek.terra.api.registry.key.RegistryKey;
import com.dfsek.terra.api.structure.LootTable;
import com.dfsek.terra.api.util.RotationUtil;
import com.dfsek.terra.api.util.vector.Vector2;
import com.dfsek.terra.api.util.vector.Vector3;
public class LootFunction implements Function<Void> {
private static final Logger LOGGER = LoggerFactory.getLogger(LootFunction.class);
private final Registry<LootTable> registry;
private final Expression<String> data;
private final Expression<Number> x, y, z;
private final SourcePosition position;
private final Platform platform;
private final StructureScript script;
public LootFunction(Registry<LootTable> registry, Expression<Number> x, Expression<Number> y, Expression<Number> z,
Expression<String> data, Platform platform, SourcePosition position, StructureScript script) {
this.registry = registry;
this.position = position;
this.data = data;
this.x = x;
this.y = y;
this.z = z;
this.platform = platform;
this.script = script;
}
@Override
public Void evaluate(ImplementationArguments implementationArguments, Scope scope) {
TerraImplementationArguments arguments = (TerraImplementationArguments) implementationArguments;
Vector2 xz = RotationUtil.rotateVector(Vector2.of(x.evaluate(implementationArguments, scope).doubleValue(),
z.evaluate(implementationArguments, scope).doubleValue()),
arguments.getRotation());
String id = data.evaluate(implementationArguments, scope);
registry.get(RegistryKey.parse(id))
.ifPresentOrElse(table -> {
Vector3 apply = Vector3.of(FastMath.roundToInt(xz.getX()),
y.evaluate(implementationArguments, scope)
.intValue(),
FastMath.roundToInt(xz.getZ())).mutable().add(arguments.getOrigin()).immutable();
try {
BlockEntity data = arguments.getWorld().getBlockEntity(apply);
if(!(data instanceof Container container)) {
LOGGER.error("Failed to place loot at {}; block {} is not a container",
apply, data);
return;
}
LootPopulateEvent event = new LootPopulateEvent(container, table,
arguments.getWorld().getPack(), script);
platform.getEventManager().callEvent(event);
if(event.isCancelled()) return;
event.getTable().fillInventory(container.getInventory(),
new Random(apply.hashCode()));
data.update(false);
} catch(Exception e) {
LOGGER.error("Could not apply loot at {}", apply, e);
e.printStackTrace();
}
},
() -> LOGGER.error("No such loot table {}", id));
return null;
}
@Override
public SourcePosition getPosition() {
return position;
}
@Override
public Type returnType() {
return Type.VOID;
}
}

View File

@@ -1,72 +0,0 @@
/*
* Copyright (c) 2020-2021 Polyhedral Development
*
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
* reference the LICENSE file in this module's root directory.
*/
package com.dfsek.terra.addons.terrascript.legacy.script.functions;
import net.jafama.FastMath;
import com.dfsek.terra.addons.terrascript.Type;
import com.dfsek.terra.addons.terrascript.legacy.parser.exceptions.ParseException;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.Expression;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.ImplementationArguments;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.Scope;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.constants.ConstantExpression;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.functions.Function;
import com.dfsek.terra.addons.terrascript.legacy.script.TerraImplementationArguments;
import com.dfsek.terra.addons.terrascript.lexer.SourcePosition;
import com.dfsek.terra.api.Platform;
import com.dfsek.terra.api.block.state.BlockState;
import com.dfsek.terra.api.util.RotationUtil;
import com.dfsek.terra.api.util.vector.Vector2;
import com.dfsek.terra.api.util.vector.Vector3;
public class PullFunction implements Function<Void> {
private final BlockState data;
private final Expression<Number> x, y, z;
private final SourcePosition position;
public PullFunction(Expression<Number> x, Expression<Number> y, Expression<Number> z, Expression<String> data, Platform platform,
SourcePosition position) {
this.position = position;
if(!(data instanceof ConstantExpression)) throw new ParseException("Block data must be constant", data.getPosition());
this.data = platform.getWorldHandle().createBlockState(((ConstantExpression<String>) data).getConstant());
this.x = x;
this.y = y;
this.z = z;
}
@Override
public Void evaluate(ImplementationArguments implementationArguments, Scope scope) {
TerraImplementationArguments arguments = (TerraImplementationArguments) implementationArguments;
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.evaluate(implementationArguments, scope).intValue(),
FastMath.roundToInt(xz.getZ())).mutable().add(arguments.getOrigin());
while(mutable.getY() > arguments.getWorld().getMinHeight()) {
if(!arguments.getWorld().getBlockState(mutable).isAir()) {
arguments.getWorld().setBlockState(mutable, data);
break;
}
mutable.subtract(0, 1, 0);
}
return null;
}
@Override
public SourcePosition getPosition() {
return position;
}
@Override
public Type returnType() {
return Type.VOID;
}
}

View File

@@ -1,44 +0,0 @@
/*
* Copyright (c) 2020-2021 Polyhedral Development
*
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
* reference the LICENSE file in this module's root directory.
*/
package com.dfsek.terra.addons.terrascript.legacy.script.functions;
import com.dfsek.terra.addons.terrascript.Type;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.Expression;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.ImplementationArguments;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.Scope;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.functions.Function;
import com.dfsek.terra.addons.terrascript.legacy.script.TerraImplementationArguments;
import com.dfsek.terra.addons.terrascript.lexer.SourcePosition;
public class RandomFunction implements Function<Integer> {
private final Expression<Number> numberReturnable;
private final SourcePosition position;
public RandomFunction(Expression<Number> numberReturnable, SourcePosition position) {
this.numberReturnable = numberReturnable;
this.position = position;
}
@Override
public Type returnType() {
return Type.NUMBER;
}
@Override
public Integer evaluate(ImplementationArguments implementationArguments, Scope scope) {
return ((TerraImplementationArguments) implementationArguments).getRandom().nextInt(
numberReturnable.evaluate(implementationArguments, scope).intValue());
}
@Override
public SourcePosition getPosition() {
return position;
}
}

View File

@@ -1,39 +0,0 @@
/*
* Copyright (c) 2020-2021 Polyhedral Development
*
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
* reference the LICENSE file in this module's root directory.
*/
package com.dfsek.terra.addons.terrascript.legacy.script.functions;
import com.dfsek.terra.addons.terrascript.Type;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.ImplementationArguments;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.Scope;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.functions.Function;
import com.dfsek.terra.addons.terrascript.legacy.script.TerraImplementationArguments;
import com.dfsek.terra.addons.terrascript.lexer.SourcePosition;
public class RecursionsFunction implements Function<Number> {
private final SourcePosition position;
public RecursionsFunction(SourcePosition position) {
this.position = position;
}
@Override
public Type returnType() {
return Type.NUMBER;
}
@Override
public Number evaluate(ImplementationArguments implementationArguments, Scope scope) {
return ((TerraImplementationArguments) implementationArguments).getRecursions();
}
@Override
public SourcePosition getPosition() {
return position;
}
}

View File

@@ -1,63 +0,0 @@
/*
* Copyright (c) 2020-2021 Polyhedral Development
*
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
* reference the LICENSE file in this module's root directory.
*/
package com.dfsek.terra.addons.terrascript.legacy.script.functions;
import net.jafama.FastMath;
import com.dfsek.terra.addons.terrascript.Type;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.Expression;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.ImplementationArguments;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.Scope;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.functions.Function;
import com.dfsek.terra.addons.terrascript.legacy.script.TerraImplementationArguments;
import com.dfsek.terra.addons.terrascript.lexer.SourcePosition;
import com.dfsek.terra.api.util.RotationUtil;
import com.dfsek.terra.api.util.vector.Vector2;
import com.dfsek.terra.api.util.vector.Vector3;
public class SetMarkFunction implements Function<Void> {
private final Expression<Number> x, y, z;
private final SourcePosition position;
private final Expression<String> mark;
public SetMarkFunction(Expression<Number> x, Expression<Number> y, Expression<Number> z, Expression<String> mark,
SourcePosition position) {
this.position = position;
this.mark = mark;
this.x = x;
this.y = y;
this.z = z;
}
@Override
public Void evaluate(ImplementationArguments implementationArguments, Scope scope) {
TerraImplementationArguments arguments = (TerraImplementationArguments) implementationArguments;
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.evaluate(implementationArguments, scope).doubleValue()),
FastMath.floorToInt(xz.getZ())).mutable().add(arguments.getOrigin()).immutable(),
mark.evaluate(implementationArguments, scope));
return null;
}
@Override
public SourcePosition getPosition() {
return position;
}
@Override
public Type returnType() {
return Type.VOID;
}
}

View File

@@ -1,72 +0,0 @@
/*
* Copyright (c) 2020-2021 Polyhedral Development
*
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
* reference the LICENSE file in this module's root directory.
*/
package com.dfsek.terra.addons.terrascript.legacy.script.functions;
import net.jafama.FastMath;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.dfsek.terra.addons.terrascript.Type;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.Expression;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.ImplementationArguments;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.Scope;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.functions.Function;
import com.dfsek.terra.addons.terrascript.legacy.script.TerraImplementationArguments;
import com.dfsek.terra.addons.terrascript.lexer.SourcePosition;
import com.dfsek.terra.api.block.entity.BlockEntity;
import com.dfsek.terra.api.util.RotationUtil;
import com.dfsek.terra.api.util.vector.Vector2;
import com.dfsek.terra.api.util.vector.Vector3;
public class StateFunction implements Function<Void> {
private static final Logger LOGGER = LoggerFactory.getLogger(StateFunction.class);
private final Expression<String> data;
private final Expression<Number> x, y, z;
private final SourcePosition position;
public StateFunction(Expression<Number> x, Expression<Number> y, Expression<Number> z, Expression<String> data,
SourcePosition position) {
this.position = position;
this.data = data;
this.x = x;
this.y = y;
this.z = z;
}
@Override
public Void evaluate(ImplementationArguments implementationArguments, Scope scope) {
TerraImplementationArguments arguments = (TerraImplementationArguments) implementationArguments;
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.evaluate(implementationArguments, scope).intValue(),
FastMath.roundToInt(xz.getZ())).mutable().add(arguments.getOrigin()).immutable();
try {
BlockEntity state = arguments.getWorld().getBlockEntity(origin);
state.applyState(data.evaluate(implementationArguments, scope));
state.update(false);
} catch(Exception e) {
LOGGER.warn("Could not apply BlockState at {}", origin, e);
e.printStackTrace();
}
return null;
}
@Override
public SourcePosition getPosition() {
return position;
}
@Override
public Type returnType() {
return Type.VOID;
}
}

View File

@@ -1,107 +0,0 @@
/*
* Copyright (c) 2020-2021 Polyhedral Development
*
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
* reference the LICENSE file in this module's root directory.
*/
package com.dfsek.terra.addons.terrascript.legacy.script.functions;
import net.jafama.FastMath;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.List;
import com.dfsek.terra.addons.terrascript.Type;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.Expression;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.ImplementationArguments;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.Scope;
import com.dfsek.terra.addons.terrascript.legacy.parser.lang.functions.Function;
import com.dfsek.terra.addons.terrascript.legacy.script.StructureScript;
import com.dfsek.terra.addons.terrascript.legacy.script.TerraImplementationArguments;
import com.dfsek.terra.addons.terrascript.lexer.SourcePosition;
import com.dfsek.terra.api.Platform;
import com.dfsek.terra.api.registry.Registry;
import com.dfsek.terra.api.structure.Structure;
import com.dfsek.terra.api.util.Rotation;
import com.dfsek.terra.api.util.RotationUtil;
import com.dfsek.terra.api.util.vector.Vector2;
public class StructureFunction implements Function<Boolean> {
private static final Logger LOGGER = LoggerFactory.getLogger(StructureFunction.class);
private final Registry<Structure> registry;
private final Expression<String> id;
private final Expression<Number> x, y, z;
private final SourcePosition position;
private final Platform platform;
private final List<Expression<String>> rotations;
public StructureFunction(Expression<Number> x, Expression<Number> y, Expression<Number> z, Expression<String> id,
List<Expression<String>> rotations, Registry<Structure> registry, SourcePosition position, Platform platform) {
this.registry = registry;
this.id = id;
this.position = position;
this.x = x;
this.y = y;
this.z = z;
this.platform = platform;
this.rotations = rotations;
}
@Override
public Type returnType() {
return Type.BOOLEAN;
}
@Override
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.evaluate(implementationArguments, scope).doubleValue(),
z.evaluate(implementationArguments, scope).doubleValue()),
arguments.getRotation());
String app = id.evaluate(implementationArguments, scope);
return registry.getByID(app).map(script -> {
Rotation rotation1;
String rotString = rotations.get(arguments.getRandom().nextInt(rotations.size())).evaluate(implementationArguments, scope);
try {
rotation1 = Rotation.valueOf(rotString);
} catch(IllegalArgumentException e) {
LOGGER.warn("Invalid rotation {}", rotString);
return false;
}
if(script instanceof StructureScript structureScript) {
return structureScript.generate(arguments.getOrigin(),
arguments.getWorld()
.buffer(FastMath.roundToInt(xz.getX()),
y.evaluate(implementationArguments, scope).intValue(),
FastMath.roundToInt(xz.getZ())),
arguments.getRandom(),
arguments.getRotation().rotate(rotation1), arguments.getRecursions() + 1);
}
return script.generate(arguments.getOrigin(),
arguments.getWorld()
.buffer(FastMath.roundToInt(xz.getX()),
y.evaluate(implementationArguments, scope).intValue(),
FastMath.roundToInt(xz.getZ())),
arguments.getRandom(),
arguments.getRotation().rotate(rotation1));
}).orElseGet(() -> {
LOGGER.error("No such structure {}", app);
return false;
});
}
@Override
public SourcePosition getPosition() {
return position;
}
}

View File

@@ -7,6 +7,8 @@
package com.dfsek.terra.addons.terrascript.lexer;
import com.dfsek.terra.addons.terrascript.parser.ParseException;
import com.google.common.collect.Sets;
import java.util.ArrayList;
@@ -17,7 +19,6 @@ import java.util.Set;
import com.dfsek.terra.addons.terrascript.exception.lexer.EOFException;
import com.dfsek.terra.addons.terrascript.exception.lexer.FormatException;
import com.dfsek.terra.addons.terrascript.exception.lexer.TokenizerException;
import com.dfsek.terra.addons.terrascript.legacy.parser.exceptions.ParseException;
import com.dfsek.terra.addons.terrascript.lexer.Token.TokenType;
@@ -190,14 +191,8 @@ public class Lexer {
if(tokenString.equals("false"))
return new Token(tokenString, TokenType.BOOLEAN, position);
if(tokenString.equals("num"))
return new Token(tokenString, TokenType.TYPE_NUMBER, position);
if(tokenString.equals("str"))
return new Token(tokenString, TokenType.TYPE_STRING, position);
if(tokenString.equals("bool"))
return new Token(tokenString, TokenType.TYPE_BOOLEAN, position);
if(tokenString.equals("void"))
return new Token(tokenString, TokenType.TYPE_VOID, position);
if(tokenString.equals("var"))
return new Token(tokenString, TokenType.VARIABLE, position);
if(tokenString.equals("fun"))
return new Token(tokenString, TokenType.FUNCTION, position);

View File

@@ -159,21 +159,9 @@ public class Token {
*/
BOOLEAN_AND,
/**
* Numeric variable declaration
* Variable declaration
*/
TYPE_NUMBER,
/**
* String variable declaration
*/
TYPE_STRING,
/**
* Boolean variable declaration
*/
TYPE_BOOLEAN,
/**
* Void type declaration
*/
TYPE_VOID,
VARIABLE,
/**
* Function declaration
*/

View File

@@ -5,7 +5,7 @@
* reference the LICENSE file in this module's root directory.
*/
package com.dfsek.terra.addons.terrascript.legacy.parser.exceptions;
package com.dfsek.terra.addons.terrascript.parser;
import java.io.Serial;

View File

@@ -8,12 +8,11 @@ import java.util.Optional;
import java.util.function.Supplier;
import com.dfsek.terra.addons.terrascript.Type;
import com.dfsek.terra.addons.terrascript.Type.TypeException;
import com.dfsek.terra.addons.terrascript.ast.Expr;
import com.dfsek.terra.addons.terrascript.ast.Expr.Variable;
import com.dfsek.terra.addons.terrascript.ast.Stmt;
import com.dfsek.terra.addons.terrascript.ast.Stmt.Block;
import com.dfsek.terra.addons.terrascript.legacy.parser.ParserUtil;
import com.dfsek.terra.addons.terrascript.legacy.parser.exceptions.ParseException;
import com.dfsek.terra.addons.terrascript.lexer.SourcePosition;
import com.dfsek.terra.addons.terrascript.lexer.Token;
import com.dfsek.terra.addons.terrascript.lexer.Token.TokenType;
@@ -77,7 +76,7 @@ public class Parser {
return switch(current().type()) {
case BLOCK_BEGIN -> block();
case FUNCTION -> functionDeclaration();
case TYPE_STRING, TYPE_BOOLEAN, TYPE_NUMBER -> variableDeclaration();
case VARIABLE -> variableDeclaration();
case RETURN -> returnStmt();
case IF_STATEMENT -> ifStmt();
case FOR_LOOP -> forLoop();
@@ -104,7 +103,7 @@ public class Parser {
paramToken.position());
consume("Expected type declaration after parameter name. Example: '" + paramId + ": <type>'", TokenType.COLON);
Type paramType = ParserUtil.getVariableReturnType(consumeUnchecked());
Type paramType = typeExpr();
params.add(Pair.of(paramId, paramType));
@@ -118,7 +117,7 @@ public class Parser {
TokenType.CLOSE_PAREN);
if(current().isType(TokenType.COLON)) {
consumeUnchecked();
funcReturn = ParserUtil.getVariableReturnType(consumeUnchecked());
funcReturn = typeExpr();
}
Stmt.Block body = blockOrSingleStatement();
@@ -127,22 +126,26 @@ public class Parser {
}
private Stmt.VariableDeclaration variableDeclaration() {
Token typeToken = consumeUnchecked();
SourcePosition position = typeToken.position();
Type type = switch(typeToken.type()) {
case TYPE_BOOLEAN -> Type.BOOLEAN;
case TYPE_NUMBER -> Type.NUMBER;
case TYPE_STRING -> Type.STRING;
default -> throw new ParseException("Invalid token '" + typeToken.lexeme() + "' specified as variable type", position);
};
SourcePosition position = consume("Expected 'var' keyword at start of variable declaration", TokenType.VARIABLE).position();
String id = consume("Expected variable name after type for variable declaration", TokenType.IDENTIFIER).lexeme();
consume("Expected '=' following variable name '" + id + "' for variable declaration", TokenType.ASSIGNMENT);
consume("Expected ':' after variable name", TokenType.COLON);
Type type = typeExpr();
consume("Expected '=' following variable type declaration", TokenType.ASSIGNMENT);
Expr expr = expression();
consumeStatementEnd("variable declaration");
return new Stmt.VariableDeclaration(type, id, expr, position);
}
private Type typeExpr() {
Token typeToken = consume("Expected " + TokenType.IDENTIFIER + " specified as variable type", TokenType.IDENTIFIER);
try {
return Type.fromString(typeToken.lexeme());
} catch(TypeException e) {
throw new ParseException("Failed to parse type expression", typeToken.position());
}
}
private Stmt.Return returnStmt() {
SourcePosition position = consume("Expected 'return' keyword, found '" + current().lexeme() + "'", TokenType.RETURN).position();
Expr value = new Expr.Void(position);
@@ -371,4 +374,6 @@ public class Parser {
private Expr variable(Token identifier) {
return new Expr.Variable(identifier.lexeme(), identifier.position());
}
}

View File

@@ -25,7 +25,7 @@ import com.dfsek.terra.addons.terrascript.ast.Stmt.Return;
import com.dfsek.terra.addons.terrascript.ast.Stmt.VariableDeclaration;
import com.dfsek.terra.addons.terrascript.ast.Stmt.While;
import com.dfsek.terra.addons.terrascript.exception.semanticanalysis.UndefinedReferenceException;
import com.dfsek.terra.addons.terrascript.legacy.parser.exceptions.ParseException;
import com.dfsek.terra.addons.terrascript.parser.ParseException;
import com.dfsek.terra.api.util.generic.pair.Pair;

View File

@@ -19,7 +19,7 @@ import com.dfsek.terra.addons.terrascript.ast.Expr.Void;
import com.dfsek.terra.addons.terrascript.ast.Stmt;
import com.dfsek.terra.addons.terrascript.exception.semanticanalysis.IdentifierAlreadyDeclaredException;
import com.dfsek.terra.addons.terrascript.exception.semanticanalysis.UndefinedReferenceException;
import com.dfsek.terra.addons.terrascript.legacy.parser.exceptions.ParseException;
import com.dfsek.terra.addons.terrascript.parser.ParseException;
import com.dfsek.terra.api.util.generic.pair.Pair;

View File

@@ -21,7 +21,7 @@ import com.dfsek.terra.addons.terrascript.ast.TypedExpr;
import com.dfsek.terra.addons.terrascript.ast.TypedStmt;
import com.dfsek.terra.addons.terrascript.exception.semanticanalysis.InvalidFunctionDeclarationException;
import com.dfsek.terra.addons.terrascript.exception.semanticanalysis.InvalidTypeException;
import com.dfsek.terra.addons.terrascript.legacy.parser.exceptions.ParseException;
import com.dfsek.terra.addons.terrascript.parser.ParseException;
import com.dfsek.terra.api.util.generic.pair.Pair;
import static com.dfsek.terra.addons.terrascript.util.OrdinalUtil.ordinalOf;
@@ -47,31 +47,31 @@ public class TypeChecker implements Visitor<TypedExpr>, Stmt.Visitor<TypedStmt>
Type type = switch(expr.operator) {
case BOOLEAN_OR, BOOLEAN_AND -> {
if(leftType != Type.BOOLEAN || rightType != Type.BOOLEAN)
errorHandler.add(new InvalidTypeException("Both operands of '" + expr.operator + "' operator must be of type '" + Type.NUMBER + "', found types '" + leftType + "' and '" + rightType + "'", expr.position));
if(!leftType.typeOf(Type.BOOLEAN) || !rightType.typeOf(Type.BOOLEAN))
errorHandler.add(new InvalidTypeException("Both operands of '" + expr.operator + "' operator must be of type '" + Type.BOOLEAN + "', found types '" + leftType + "' and '" + rightType + "'", expr.position));
yield Type.BOOLEAN;
}
case EQUALS, NOT_EQUALS -> {
if(leftType != rightType) errorHandler.add(new InvalidTypeException("Both operands of equality operator (==) must be of the same type, found mismatched types '" + leftType + "' and '" + rightType + "'", expr.position));
if(!leftType.typeOf(rightType)) errorHandler.add(new InvalidTypeException("Both operands of equality operator (==) must be of the same type, found mismatched types '" + leftType + "' and '" + rightType + "'", expr.position));
yield Type.BOOLEAN;
}
case GREATER, GREATER_EQUALS, LESS, LESS_EQUALS -> {
if(leftType != Type.NUMBER || rightType != Type.NUMBER)
if(!leftType.typeOf(Type.NUMBER) || !rightType.typeOf(Type.NUMBER))
errorHandler.add(new InvalidTypeException("Both operands of '" + expr.operator + "' operator must be of type '" + Type.NUMBER + "', found types '" + leftType + "' and '" + rightType + "'", expr.position));
yield Type.BOOLEAN;
}
case ADD -> {
if(leftType == Type.NUMBER && rightType == Type.NUMBER) {
if(leftType.typeOf(Type.NUMBER) && rightType.typeOf(Type.NUMBER)) {
yield Type.NUMBER;
}
if(leftType == Type.STRING || rightType == Type.STRING) {
if(leftType.typeOf(Type.STRING) || rightType.typeOf(Type.STRING)) {
yield Type.STRING;
}
errorHandler.add(new RuntimeException("Addition operands must be either both numbers, or one of type string"));
errorHandler.add(new RuntimeException("Addition operands must be either both of type '" + Type.NUMBER + "', or one of type '" + Type.STRING + "'"));
yield Type.VOID;
}
case SUBTRACT, MULTIPLY, DIVIDE, MODULO -> {
if(leftType != Type.NUMBER || rightType != Type.NUMBER)
if(!leftType.typeOf(Type.NUMBER) || !rightType.typeOf(Type.NUMBER))
errorHandler.add(new InvalidTypeException("Both operands of '" + expr.operator + "' operator must be of type '" + Type.NUMBER + "', found types '" + leftType + "' and '" + rightType + "'", expr.position));
yield Type.NUMBER;
}
@@ -94,11 +94,11 @@ public class TypeChecker implements Visitor<TypedExpr>, Stmt.Visitor<TypedStmt>
TypedExpr right = expr.operand.accept(this);
Type type = switch(expr.operator) {
case NOT -> {
if(right.type != Type.BOOLEAN) throw new RuntimeException();
if(!right.type.typeOf(Type.BOOLEAN)) throw new RuntimeException();
yield Type.BOOLEAN;
}
case NEGATE -> {
if(right.type != Type.NUMBER) throw new RuntimeException();
if(!right.type.typeOf(Type.NUMBER)) throw new RuntimeException();
yield Type.NUMBER;
}
};
@@ -122,7 +122,7 @@ public class TypeChecker implements Visitor<TypedExpr>, Stmt.Visitor<TypedStmt>
for(int i = 0; i < parameters.size(); i++) {
Type expectedType = parameters.get(i);
Type providedType = arguments.get(i).type;
if(expectedType != providedType)
if(!expectedType.typeOf(providedType))
errorHandler.add(new InvalidTypeException(
ordinalOf(i + 1) + " argument provided for function '" + id + "' expects type " + expectedType + ", found " +
providedType + " instead", expr.position));
@@ -142,9 +142,9 @@ public class TypeChecker implements Visitor<TypedExpr>, Stmt.Visitor<TypedStmt>
TypedExpr right = expr.rValue.accept(this);
Type expected = left.type;
String id = expr.lValue.identifier;
if(right.type != expected)
if(!right.type.typeOf(expected))
errorHandler.add(new InvalidTypeException(
"Cannot assign variable '" + id + "' to type " + right + ", '" + id + "' is declared with type " + expected,
"Cannot assign variable '" + id + "' to value of type " + right.type + ", '" + id + "' is declared with type " + expected,
expr.position));
return new TypedExpr.Assignment(left, right, right.type);
}
@@ -168,7 +168,7 @@ public class TypeChecker implements Visitor<TypedExpr>, Stmt.Visitor<TypedStmt>
public TypedStmt visitFunctionDeclarationStmt(Stmt.FunctionDeclaration stmt) {
TypedStmt.Block body = new TypedStmt.Block(stmt.body.statements.stream().map(s -> s.accept(this)).toList());
boolean hasReturn = alwaysReturns(body, stmt);
if(stmt.returnType != Type.VOID && !hasReturn) {
if(!stmt.returnType.typeOf(Type.VOID) && !hasReturn) {
errorHandler.add(
new InvalidFunctionDeclarationException("Function body for '" + stmt.identifier + "' does not contain return statement",
stmt.position));
@@ -178,7 +178,7 @@ public class TypeChecker implements Visitor<TypedExpr>, Stmt.Visitor<TypedStmt>
private boolean alwaysReturns(TypedStmt stmt, Stmt.FunctionDeclaration function) {
if(stmt instanceof TypedStmt.Return ret) {
if(ret.value.type != function.returnType)
if(!ret.value.type.typeOf(function.returnType))
errorHandler.add(new InvalidTypeException(
"Return statement must match function's return type. Function '" + function.identifier + "' expects " +
function.returnType + ", found " + ret.value.type + " instead", function.position));
@@ -196,10 +196,10 @@ public class TypeChecker implements Visitor<TypedExpr>, Stmt.Visitor<TypedStmt>
@Override
public TypedStmt visitVariableDeclarationStmt(Stmt.VariableDeclaration stmt) {
TypedExpr value = stmt.value.accept(this);
if(stmt.type != value.type)
if(!stmt.type.typeOf(value.type))
errorHandler.add(new InvalidTypeException(
"Type " + stmt.type + " declared for variable '" + stmt.identifier + "' does not match assigned value type " +
value.type, stmt.position));
"Type of value assigned to variable '" + stmt.identifier + "' does not match variable's declared type. Expected type '" +
stmt.type + "', found '" + value.type +"' instead", stmt.position));
return new TypedStmt.VariableDeclaration(stmt.type, stmt.identifier, value);
}
@@ -211,12 +211,12 @@ public class TypeChecker implements Visitor<TypedExpr>, Stmt.Visitor<TypedStmt>
@Override
public TypedStmt visitIfStmt(Stmt.If stmt) {
TypedExpr condition = stmt.condition.accept(this);
if(condition.type != Type.BOOLEAN) errorHandler.add(new InvalidTypeException("If statement conditional must be of type '" + Type.BOOLEAN + "', found '" + condition.type + "' instead.", stmt.position));
if(!condition.type.typeOf(Type.BOOLEAN)) errorHandler.add(new InvalidTypeException("If statement conditional must be of type '" + Type.BOOLEAN + "', found '" + condition.type + "' instead.", stmt.position));
TypedStmt.Block trueBody = (TypedStmt.Block) stmt.trueBody.accept(this);
List<Pair<TypedExpr, TypedStmt.Block>> elseIfClauses = stmt.elseIfClauses.stream().map(c -> {
TypedExpr clauseCondition = c.getLeft().accept(this);
if (clauseCondition.type != Type.BOOLEAN) errorHandler.add(new InvalidTypeException("Else if clause conditional must be of type '" + Type.BOOLEAN + "', found '" + condition.type + "' instead.", stmt.position));
if (!clauseCondition.type.typeOf(Type.BOOLEAN)) errorHandler.add(new InvalidTypeException("Else if clause conditional must be of type '" + Type.BOOLEAN + "', found '" + condition.type + "' instead.", stmt.position));
return Pair.of(clauseCondition, (TypedStmt.Block) c.getRight().accept(this));
}).toList();
@@ -229,7 +229,7 @@ public class TypeChecker implements Visitor<TypedExpr>, Stmt.Visitor<TypedStmt>
public TypedStmt visitForStmt(Stmt.For stmt) {
TypedStmt initializer = stmt.initializer.accept(this);
TypedExpr condition = stmt.condition.accept(this);
if(condition.type != Type.BOOLEAN) errorHandler.add(new InvalidTypeException("For statement conditional must be of type '" + Type.BOOLEAN + "', found '" + condition.type + "' instead.", stmt.position));
if(!condition.type.typeOf(Type.BOOLEAN)) errorHandler.add(new InvalidTypeException("For statement conditional must be of type '" + Type.BOOLEAN + "', found '" + condition.type + "' instead.", stmt.position));
TypedExpr incrementer = stmt.incrementer.accept(this);
return new TypedStmt.For(initializer, condition, incrementer, (TypedStmt.Block) stmt.body.accept(this));
}
@@ -237,7 +237,7 @@ public class TypeChecker implements Visitor<TypedExpr>, Stmt.Visitor<TypedStmt>
@Override
public TypedStmt visitWhileStmt(Stmt.While stmt) {
TypedExpr condition = stmt.condition.accept(this);
if(condition.type != Type.BOOLEAN) errorHandler.add(new InvalidTypeException("While statement conditional must be of type '" + Type.BOOLEAN + "', found '" + condition.type + "' instead.", stmt.position));
if(!condition.type.typeOf(Type.BOOLEAN)) errorHandler.add(new InvalidTypeException("While statement conditional must be of type '" + Type.BOOLEAN + "', found '" + condition.type + "' instead.", stmt.position));
return new TypedStmt.While(condition, (TypedStmt.Block) stmt.body.accept(this));
}

View File

@@ -23,9 +23,9 @@ public class CodeGenTest {
if (1 == 1) print("Dis is true");
num a = 1;
num b = 2;
str e = "test";
var a: num = 1;
var b: num = 2;
var e: str = "test";
if (a <= b) {
print("a is <= b");
@@ -48,17 +48,19 @@ public class CodeGenTest {
}
fun loopTwiceThenBreak() {
num i = 0;
var i: num = 0;
while (true) {
if (i == 2) break;
print("looped");
if (i == 1) break;
i = i + 1;
}
}
print("Should loop twice:");
loopTwiceThenBreak();
retNum();
bool bln = true;
var bln: bool = true;
print(takesArgs("test", 3, true));
print(retStr());
@@ -84,9 +86,9 @@ public class CodeGenTest {
fun concatTwo(a: str, b: str): str {
return a + b;
}
str hello = "Hell";
var hello: str = "Hell";
hello = concatTwo(hello, "o");
str world = "world!";
var world: str = "world!";
return concatThree(hello, " ", world);
}

View File

@@ -20,22 +20,22 @@ public class SemanticAnalyzerTest {
@Test
public void testVariableReference() {
// Use of declared variable
testValid("num a = 1; a + a;");
testValid("var a: num = 1; a + a;");
// Can't use undeclared variable
testInvalid("a + a;", UndefinedReferenceException.class);
// Can't reference variable before declaration
testInvalid("a + a; num a = 1;", UndefinedReferenceException.class);
testInvalid("a + a; var a: num = 1;", UndefinedReferenceException.class);
// Variable declarations shouldn't be accessible from inner scopes
testInvalid("{ num a = 1; } a + a;", UndefinedReferenceException.class);
testInvalid("{ var a: num = 1; } a + a;", UndefinedReferenceException.class);
// Can access variables declared in outer scope
testValid("num a = 3; { a + a; }");
testValid("var a: num = 3; { a + a; }");
// Should not be able to use variables from outer scope if they're declared after scope
testInvalid("{ a + a; } num a = 2;", UndefinedReferenceException.class);
testInvalid("{ a + a; } var a: num = 2;", UndefinedReferenceException.class);
// Can't use undeclared variable as function argument
testInvalid("fun test(p: str) {} test(a);", UndefinedReferenceException.class);
@@ -47,34 +47,34 @@ public class SemanticAnalyzerTest {
testInvalid("a = 1;", UndefinedReferenceException.class);
// Cannot assign to variable declared after assignment
testInvalid("a = 2; num a = 1;", UndefinedReferenceException.class);
testInvalid("a = 2; var a: num = 1;", UndefinedReferenceException.class);
}
@Test
public void testAssignment() {
// Simple assignment
testValid("num a = 1; a = 2;");
testValid("var a: num = 1; a = 2;");
// Can assign variables declared in outer scope
testValid("""
num a = 1;
var a: num = 1;
{ a = 2; }
""");
// Cannot assign variables declared in inner scope
testInvalid("""
{ num a = 1; }
{ var a: num = 1; }
a = 2;
""", UndefinedReferenceException.class);
// Cannot assign variables declared in outer scope after reference
testInvalid("""
{ a = 2; }
num a = 1;
var a: num = 1;
""", UndefinedReferenceException.class);
// Cannot assign variable to expression of different type
testInvalid("num a = 1; a = true;", InvalidTypeException.class);
testInvalid("var a: num = 1; a = true;", InvalidTypeException.class);
}
@Test
@@ -293,8 +293,8 @@ public class SemanticAnalyzerTest {
testInvalid("fun test(a: num, b: num) { a + c; }", UndefinedReferenceException.class);
// Function bodies can't use variables from outer scope
testInvalid("num a = 1; fun doStuff() { a + 2; }", UndefinedReferenceException.class);
testInvalid("fun doStuff() { a + 2; } num a = 1;", UndefinedReferenceException.class);
testInvalid("var a: num = 1; fun doStuff() { a + 2; }", UndefinedReferenceException.class);
testInvalid("fun doStuff() { a + 2; } var a: num = 1;", UndefinedReferenceException.class);
// Type checking parameters
testValid("fun takesNum(a: num) {} fun test(numberParam: num) { takesNum(numberParam); }");
@@ -304,20 +304,20 @@ public class SemanticAnalyzerTest {
@Test
public void testShadowing() {
// Can't shadow variable in immediate scope
testInvalid("num a = 1; num a = 2;", IdentifierAlreadyDeclaredException.class);
testInvalid("var a: num = 1; var a: num = 2;", IdentifierAlreadyDeclaredException.class);
// Can shadow variable from outer scope
testValid("num a = 1; { num a = 2; }");
testValid("var a: num = 1; { var a: num = 2; }");
// Can declare variable after same identifier is used previously in an inner scope
testValid("{ num a = 2; } num a = 1;");
testValid("{ var a: num = 2; } var a: num = 1;");
// Ensure shadowed variable type is used
testValid("""
fun takesNum(p: num) {}
bool a = false;
var a: bool = false;
{
num a = 1;
var a: num = 1;
takesNum(a);
}
""");
@@ -325,9 +325,9 @@ public class SemanticAnalyzerTest {
// Should not be able to use type of shadowed variable in use of shadowing variable
testInvalid("""
fun takesNum(p: num) {}
num a = false;
var a: num = false;
{
bool a = 1;
var a: bool = 1;
takesNum(a);
}
""", InvalidTypeException.class);
@@ -350,7 +350,7 @@ public class SemanticAnalyzerTest {
""", IdentifierAlreadyDeclaredException.class);
// Can't use function name that is already declared as a variable
testInvalid("num id = 1; fun id() {}", IdentifierAlreadyDeclaredException.class);
testInvalid("var id: num = 1; fun id() {}", IdentifierAlreadyDeclaredException.class);
}
private <T extends Exception> void testInvalid(String invalidSource, Class<T> exceptionType) {