mirror of
https://github.com/PolyhedralDev/Terra.git
synced 2026-04-04 23:06:05 +00:00
Change Type enum to interface
Also removes legacy v1 code from v2
This commit is contained in:
@@ -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();
|
||||
|
||||
@@ -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 {
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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());
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -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) {
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
|
||||
|
||||
}
|
||||
@@ -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 {
|
||||
}
|
||||
@@ -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> {
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
*/
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user