From 433d695e8b2e58238717e2ff09cdf548d8c0e1b9 Mon Sep 17 00:00:00 2001 From: Astrash Date: Mon, 23 Oct 2023 13:10:32 +1100 Subject: [PATCH] Re-add terrascript v1 module --- .../structure-terrascript-loader-v1/LICENSE | 21 + .../structure-terrascript-loader-v1/README.md | 4 + .../build.gradle.kts | 15 + .../addons/terrascript/TerraScriptAddon.java | 64 +++ .../addons/terrascript/parser/Parser.java | 468 ++++++++++++++++++ .../addons/terrascript/parser/ParserUtil.java | 115 +++++ .../parser/exceptions/ParseException.java | 38 ++ .../addons/terrascript/parser/lang/Block.java | 76 +++ .../terrascript/parser/lang/Executable.java | 19 + .../parser/lang/ImplementationArguments.java | 14 + .../addons/terrascript/parser/lang/Item.java | 25 + .../terrascript/parser/lang/Keyword.java | 11 + .../terrascript/parser/lang/Returnable.java | 30 ++ .../addons/terrascript/parser/lang/Scope.java | 138 ++++++ .../terrascript/parser/lang/Statement.java | 11 + .../lang/constants/BooleanConstant.java | 32 ++ .../lang/constants/ConstantExpression.java | 38 ++ .../lang/constants/NumericConstant.java | 33 ++ .../parser/lang/constants/StringConstant.java | 23 + .../parser/lang/functions/Function.java | 43 ++ .../lang/functions/FunctionBuilder.java | 22 + .../lang/keywords/flow/BreakKeyword.java | 38 ++ .../lang/keywords/flow/ContinueKeyword.java | 38 ++ .../lang/keywords/flow/FailKeyword.java | 38 ++ .../lang/keywords/flow/ReturnKeyword.java | 38 ++ .../lang/keywords/looplike/ForKeyword.java | 55 ++ .../lang/keywords/looplike/IfKeyword.java | 62 +++ .../lang/keywords/looplike/WhileKeyword.java | 48 ++ .../lang/operations/BinaryOperation.java | 29 ++ .../lang/operations/BooleanAndOperation.java | 35 ++ .../lang/operations/BooleanNotOperation.java | 35 ++ .../lang/operations/BooleanOrOperation.java | 35 ++ .../operations/ConcatenationOperation.java | 41 ++ .../lang/operations/DivisionOperation.java | 35 ++ .../lang/operations/ModuloOperation.java | 35 ++ .../operations/MultiplicationOperation.java | 35 ++ .../lang/operations/NegationOperation.java | 35 ++ .../operations/NumberAdditionOperation.java | 35 ++ .../lang/operations/SubtractionOperation.java | 35 ++ .../lang/operations/UnaryOperation.java | 27 + .../statements/EqualsStatement.java | 48 ++ .../GreaterOrEqualsThanStatement.java | 36 ++ .../statements/GreaterThanStatement.java | 37 ++ .../statements/LessThanOrEqualsStatement.java | 37 ++ .../statements/LessThanStatement.java | 37 ++ .../statements/NotEqualsStatement.java | 46 ++ .../lang/variables/BooleanVariable.java | 42 ++ .../parser/lang/variables/NumberVariable.java | 42 ++ .../parser/lang/variables/StringVariable.java | 42 ++ .../parser/lang/variables/Variable.java | 22 + .../variables/assign/BoolAssignmentNode.java | 25 + .../variables/assign/NumAssignmentNode.java | 25 + .../variables/assign/StrAssignmentNode.java | 21 + .../assign/VariableAssignmentNode.java | 31 ++ .../reference/BoolVariableReferenceNode.java | 22 + .../reference/NumVariableReferenceNode.java | 22 + .../reference/StrVariableReferenceNode.java | 17 + .../reference/VariableReferenceNode.java | 34 ++ .../terrascript/script/StructureScript.java | 160 ++++++ .../script/TerraImplementationArguments.java | 73 +++ .../builders/BinaryNumberFunctionBuilder.java | 61 +++ .../script/builders/BiomeFunctionBuilder.java | 45 ++ .../script/builders/BlockFunctionBuilder.java | 61 +++ .../builders/CheckBlockFunctionBuilder.java | 38 ++ .../builders/EntityFunctionBuilder.java | 46 ++ .../builders/GetMarkFunctionBuilder.java | 42 ++ .../script/builders/LootFunctionBuilder.java | 54 ++ .../script/builders/PullFunctionBuilder.java | 46 ++ .../builders/RandomFunctionBuilder.java | 35 ++ .../builders/RecursionsFunctionBuilder.java | 33 ++ .../builders/SetMarkFunctionBuilder.java | 43 ++ .../script/builders/StateFunctionBuilder.java | 48 ++ .../builders/StructureFunctionBuilder.java | 55 ++ .../builders/UnaryBooleanFunctionBuilder.java | 63 +++ .../builders/UnaryNumberFunctionBuilder.java | 59 +++ .../builders/UnaryStringFunctionBuilder.java | 60 +++ .../builders/ZeroArgFunctionBuilder.java | 60 +++ .../script/functions/BiomeFunction.java | 65 +++ .../script/functions/BlockFunction.java | 107 ++++ .../script/functions/CheckBlockFunction.java | 65 +++ .../script/functions/EntityFunction.java | 70 +++ .../script/functions/GetMarkFunction.java | 58 +++ .../script/functions/LootFunction.java | 108 ++++ .../script/functions/PullFunction.java | 70 +++ .../script/functions/RandomFunction.java | 43 ++ .../script/functions/RecursionsFunction.java | 38 ++ .../script/functions/SetMarkFunction.java | 60 +++ .../script/functions/StateFunction.java | 70 +++ .../script/functions/StructureFunction.java | 105 ++++ .../addons/terrascript/tokenizer/Char.java | 63 +++ .../terrascript/tokenizer/Lookahead.java | 130 +++++ .../terrascript/tokenizer/Position.java | 23 + .../addons/terrascript/tokenizer/Token.java | 237 +++++++++ .../terrascript/tokenizer/Tokenizer.java | 247 +++++++++ .../tokenizer/exceptions/EOFException.java | 27 + .../tokenizer/exceptions/FormatException.java | 27 + .../exceptions/TokenizerException.java | 28 ++ .../src/main/resources/terra.addon.yml | 12 + .../test/java/structure/LookaheadTest.java | 29 ++ .../src/test/java/structure/ParserTest.java | 96 ++++ .../src/test/resources/test.tesf | 97 ++++ 101 files changed, 5512 insertions(+) create mode 100644 common/addons/structure-terrascript-loader-v1/LICENSE create mode 100644 common/addons/structure-terrascript-loader-v1/README.md create mode 100644 common/addons/structure-terrascript-loader-v1/build.gradle.kts create mode 100644 common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/TerraScriptAddon.java create mode 100644 common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/Parser.java create mode 100644 common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/ParserUtil.java create mode 100644 common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/exceptions/ParseException.java create mode 100644 common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/Block.java create mode 100644 common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/Executable.java create mode 100644 common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/ImplementationArguments.java create mode 100644 common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/Item.java create mode 100644 common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/Keyword.java create mode 100644 common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/Returnable.java create mode 100644 common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/Scope.java create mode 100644 common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/Statement.java create mode 100644 common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/constants/BooleanConstant.java create mode 100644 common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/constants/ConstantExpression.java create mode 100644 common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/constants/NumericConstant.java create mode 100644 common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/constants/StringConstant.java create mode 100644 common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/functions/Function.java create mode 100644 common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/functions/FunctionBuilder.java create mode 100644 common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/keywords/flow/BreakKeyword.java create mode 100644 common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/keywords/flow/ContinueKeyword.java create mode 100644 common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/keywords/flow/FailKeyword.java create mode 100644 common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/keywords/flow/ReturnKeyword.java create mode 100644 common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/keywords/looplike/ForKeyword.java create mode 100644 common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/keywords/looplike/IfKeyword.java create mode 100644 common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/keywords/looplike/WhileKeyword.java create mode 100644 common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/operations/BinaryOperation.java create mode 100644 common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/operations/BooleanAndOperation.java create mode 100644 common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/operations/BooleanNotOperation.java create mode 100644 common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/operations/BooleanOrOperation.java create mode 100644 common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/operations/ConcatenationOperation.java create mode 100644 common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/operations/DivisionOperation.java create mode 100644 common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/operations/ModuloOperation.java create mode 100644 common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/operations/MultiplicationOperation.java create mode 100644 common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/operations/NegationOperation.java create mode 100644 common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/operations/NumberAdditionOperation.java create mode 100644 common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/operations/SubtractionOperation.java create mode 100644 common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/operations/UnaryOperation.java create mode 100644 common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/operations/statements/EqualsStatement.java create mode 100644 common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/operations/statements/GreaterOrEqualsThanStatement.java create mode 100644 common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/operations/statements/GreaterThanStatement.java create mode 100644 common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/operations/statements/LessThanOrEqualsStatement.java create mode 100644 common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/operations/statements/LessThanStatement.java create mode 100644 common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/operations/statements/NotEqualsStatement.java create mode 100644 common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/variables/BooleanVariable.java create mode 100644 common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/variables/NumberVariable.java create mode 100644 common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/variables/StringVariable.java create mode 100644 common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/variables/Variable.java create mode 100644 common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/variables/assign/BoolAssignmentNode.java create mode 100644 common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/variables/assign/NumAssignmentNode.java create mode 100644 common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/variables/assign/StrAssignmentNode.java create mode 100644 common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/variables/assign/VariableAssignmentNode.java create mode 100644 common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/variables/reference/BoolVariableReferenceNode.java create mode 100644 common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/variables/reference/NumVariableReferenceNode.java create mode 100644 common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/variables/reference/StrVariableReferenceNode.java create mode 100644 common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/variables/reference/VariableReferenceNode.java create mode 100644 common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/script/StructureScript.java create mode 100644 common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/script/TerraImplementationArguments.java create mode 100644 common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/script/builders/BinaryNumberFunctionBuilder.java create mode 100644 common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/script/builders/BiomeFunctionBuilder.java create mode 100644 common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/script/builders/BlockFunctionBuilder.java create mode 100644 common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/script/builders/CheckBlockFunctionBuilder.java create mode 100644 common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/script/builders/EntityFunctionBuilder.java create mode 100644 common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/script/builders/GetMarkFunctionBuilder.java create mode 100644 common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/script/builders/LootFunctionBuilder.java create mode 100644 common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/script/builders/PullFunctionBuilder.java create mode 100644 common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/script/builders/RandomFunctionBuilder.java create mode 100644 common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/script/builders/RecursionsFunctionBuilder.java create mode 100644 common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/script/builders/SetMarkFunctionBuilder.java create mode 100644 common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/script/builders/StateFunctionBuilder.java create mode 100644 common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/script/builders/StructureFunctionBuilder.java create mode 100644 common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/script/builders/UnaryBooleanFunctionBuilder.java create mode 100644 common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/script/builders/UnaryNumberFunctionBuilder.java create mode 100644 common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/script/builders/UnaryStringFunctionBuilder.java create mode 100644 common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/script/builders/ZeroArgFunctionBuilder.java create mode 100644 common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/script/functions/BiomeFunction.java create mode 100644 common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/script/functions/BlockFunction.java create mode 100644 common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/script/functions/CheckBlockFunction.java create mode 100644 common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/script/functions/EntityFunction.java create mode 100644 common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/script/functions/GetMarkFunction.java create mode 100644 common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/script/functions/LootFunction.java create mode 100644 common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/script/functions/PullFunction.java create mode 100644 common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/script/functions/RandomFunction.java create mode 100644 common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/script/functions/RecursionsFunction.java create mode 100644 common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/script/functions/SetMarkFunction.java create mode 100644 common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/script/functions/StateFunction.java create mode 100644 common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/script/functions/StructureFunction.java create mode 100644 common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/tokenizer/Char.java create mode 100644 common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/tokenizer/Lookahead.java create mode 100644 common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/tokenizer/Position.java create mode 100644 common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/tokenizer/Token.java create mode 100644 common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/tokenizer/Tokenizer.java create mode 100644 common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/tokenizer/exceptions/EOFException.java create mode 100644 common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/tokenizer/exceptions/FormatException.java create mode 100644 common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/tokenizer/exceptions/TokenizerException.java create mode 100644 common/addons/structure-terrascript-loader-v1/src/main/resources/terra.addon.yml create mode 100644 common/addons/structure-terrascript-loader-v1/src/test/java/structure/LookaheadTest.java create mode 100644 common/addons/structure-terrascript-loader-v1/src/test/java/structure/ParserTest.java create mode 100644 common/addons/structure-terrascript-loader-v1/src/test/resources/test.tesf diff --git a/common/addons/structure-terrascript-loader-v1/LICENSE b/common/addons/structure-terrascript-loader-v1/LICENSE new file mode 100644 index 000000000..64c1cd516 --- /dev/null +++ b/common/addons/structure-terrascript-loader-v1/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2020-2021 Polyhedral Development + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/common/addons/structure-terrascript-loader-v1/README.md b/common/addons/structure-terrascript-loader-v1/README.md new file mode 100644 index 000000000..5bf8f622a --- /dev/null +++ b/common/addons/structure-terrascript-loader-v1/README.md @@ -0,0 +1,4 @@ +# structure-terrascript-loader + +Implements the TerraScript structure scripting language, and loads all `*.tesf` +files into the Structure registry. \ No newline at end of file diff --git a/common/addons/structure-terrascript-loader-v1/build.gradle.kts b/common/addons/structure-terrascript-loader-v1/build.gradle.kts new file mode 100644 index 000000000..18d4019b9 --- /dev/null +++ b/common/addons/structure-terrascript-loader-v1/build.gradle.kts @@ -0,0 +1,15 @@ +import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar + +version = version("1.1.0") + +dependencies { + api("commons-io:commons-io:2.7") + compileOnlyApi(project(":common:addons:manifest-addon-loader")) + implementation("net.jafama", "jafama", Versions.Libraries.Internal.jafama) + testImplementation("net.jafama", "jafama", Versions.Libraries.Internal.jafama) +} + +tasks.named("shadowJar") { + relocate("org.apache.commons", "com.dfsek.terra.addons.terrascript.lib.commons") + relocate("net.jafama", "com.dfsek.terra.addons.terrascript.lib.jafama") +} \ No newline at end of file diff --git a/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/TerraScriptAddon.java b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/TerraScriptAddon.java new file mode 100644 index 000000000..f2e1d0055 --- /dev/null +++ b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/TerraScriptAddon.java @@ -0,0 +1,64 @@ +/* + * 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; + +import com.dfsek.terra.addons.manifest.api.AddonInitializer; +import com.dfsek.terra.addons.terrascript.parser.exceptions.ParseException; +import com.dfsek.terra.addons.terrascript.parser.lang.functions.FunctionBuilder; +import com.dfsek.terra.addons.terrascript.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; +import com.dfsek.terra.api.event.functional.FunctionalEventHandler; +import com.dfsek.terra.api.inject.annotations.Inject; +import com.dfsek.terra.api.registry.CheckedRegistry; +import com.dfsek.terra.api.structure.LootTable; +import com.dfsek.terra.api.structure.Structure; +import com.dfsek.terra.api.util.StringUtil; + + +public class TerraScriptAddon implements AddonInitializer { + @Inject + private Platform platform; + + @Inject + private BaseAddon addon; + + @Override + public void initialize() { + platform.getEventManager() + .getHandler(FunctionalEventHandler.class) + .register(addon, ConfigPackPreLoadEvent.class) + .then(event -> { + CheckedRegistry structureRegistry = event.getPack().getOrCreateRegistry(Structure.class); + CheckedRegistry lootRegistry = event.getPack().getOrCreateRegistry(LootTable.class); + event.getPack().getLoader().open("", ".tesf").thenEntries( + entries -> + entries.stream() + .parallel() + .map(entry -> { + try { + String id = StringUtil.fileName(entry.getKey()); + return new StructureScript(entry.getValue(), + addon.key(id), + platform, + structureRegistry, + lootRegistry, + event.getPack().getOrCreateRegistry(FunctionBuilder.class)); + } catch(ParseException e) { + throw new RuntimeException("Failed to load script \"" + entry.getKey() + "\"", e); + } + }) + .toList() + .forEach(structureRegistry::register)) + .close(); + }) + .priority(100) + .failThrough(); + } +} diff --git a/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/Parser.java b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/Parser.java new file mode 100644 index 000000000..2b344343a --- /dev/null +++ b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/Parser.java @@ -0,0 +1,468 @@ +/* + * 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.parser; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import com.dfsek.terra.addons.terrascript.parser.exceptions.ParseException; +import com.dfsek.terra.addons.terrascript.parser.lang.Block; +import com.dfsek.terra.addons.terrascript.parser.lang.Executable; +import com.dfsek.terra.addons.terrascript.parser.lang.Item; +import com.dfsek.terra.addons.terrascript.parser.lang.Keyword; +import com.dfsek.terra.addons.terrascript.parser.lang.Returnable; +import com.dfsek.terra.addons.terrascript.parser.lang.Returnable.ReturnType; +import com.dfsek.terra.addons.terrascript.parser.lang.Scope.ScopeBuilder; +import com.dfsek.terra.addons.terrascript.parser.lang.constants.BooleanConstant; +import com.dfsek.terra.addons.terrascript.parser.lang.constants.ConstantExpression; +import com.dfsek.terra.addons.terrascript.parser.lang.constants.NumericConstant; +import com.dfsek.terra.addons.terrascript.parser.lang.constants.StringConstant; +import com.dfsek.terra.addons.terrascript.parser.lang.functions.Function; +import com.dfsek.terra.addons.terrascript.parser.lang.functions.FunctionBuilder; +import com.dfsek.terra.addons.terrascript.parser.lang.keywords.flow.BreakKeyword; +import com.dfsek.terra.addons.terrascript.parser.lang.keywords.flow.ContinueKeyword; +import com.dfsek.terra.addons.terrascript.parser.lang.keywords.flow.FailKeyword; +import com.dfsek.terra.addons.terrascript.parser.lang.keywords.flow.ReturnKeyword; +import com.dfsek.terra.addons.terrascript.parser.lang.keywords.looplike.ForKeyword; +import com.dfsek.terra.addons.terrascript.parser.lang.keywords.looplike.IfKeyword; +import com.dfsek.terra.addons.terrascript.parser.lang.keywords.looplike.WhileKeyword; +import com.dfsek.terra.addons.terrascript.parser.lang.operations.BinaryOperation; +import com.dfsek.terra.addons.terrascript.parser.lang.operations.BooleanAndOperation; +import com.dfsek.terra.addons.terrascript.parser.lang.operations.BooleanNotOperation; +import com.dfsek.terra.addons.terrascript.parser.lang.operations.BooleanOrOperation; +import com.dfsek.terra.addons.terrascript.parser.lang.operations.ConcatenationOperation; +import com.dfsek.terra.addons.terrascript.parser.lang.operations.DivisionOperation; +import com.dfsek.terra.addons.terrascript.parser.lang.operations.ModuloOperation; +import com.dfsek.terra.addons.terrascript.parser.lang.operations.MultiplicationOperation; +import com.dfsek.terra.addons.terrascript.parser.lang.operations.NegationOperation; +import com.dfsek.terra.addons.terrascript.parser.lang.operations.NumberAdditionOperation; +import com.dfsek.terra.addons.terrascript.parser.lang.operations.SubtractionOperation; +import com.dfsek.terra.addons.terrascript.parser.lang.operations.statements.EqualsStatement; +import com.dfsek.terra.addons.terrascript.parser.lang.operations.statements.GreaterOrEqualsThanStatement; +import com.dfsek.terra.addons.terrascript.parser.lang.operations.statements.GreaterThanStatement; +import com.dfsek.terra.addons.terrascript.parser.lang.operations.statements.LessThanOrEqualsStatement; +import com.dfsek.terra.addons.terrascript.parser.lang.operations.statements.LessThanStatement; +import com.dfsek.terra.addons.terrascript.parser.lang.operations.statements.NotEqualsStatement; +import com.dfsek.terra.addons.terrascript.parser.lang.variables.assign.BoolAssignmentNode; +import com.dfsek.terra.addons.terrascript.parser.lang.variables.assign.NumAssignmentNode; +import com.dfsek.terra.addons.terrascript.parser.lang.variables.assign.StrAssignmentNode; +import com.dfsek.terra.addons.terrascript.parser.lang.variables.assign.VariableAssignmentNode; +import com.dfsek.terra.addons.terrascript.parser.lang.variables.reference.BoolVariableReferenceNode; +import com.dfsek.terra.addons.terrascript.parser.lang.variables.reference.NumVariableReferenceNode; +import com.dfsek.terra.addons.terrascript.parser.lang.variables.reference.StrVariableReferenceNode; +import com.dfsek.terra.addons.terrascript.tokenizer.Position; +import com.dfsek.terra.addons.terrascript.tokenizer.Token; +import com.dfsek.terra.addons.terrascript.tokenizer.Tokenizer; +import com.dfsek.terra.api.util.generic.pair.Pair; + + +@SuppressWarnings("unchecked") +public class Parser { + private final String data; + private final Map>> functions = new HashMap<>(); + private final List ignoredFunctions = new ArrayList<>(); + + public Parser(String data) { + this.data = data; + } + + public Parser registerFunction(String name, FunctionBuilder> functionBuilder) { + functions.put(name, functionBuilder); + return this; + } + + public Parser ignoreFunction(String name) { + ignoredFunctions.add(name); + return this; + } + + /** + * Parse input + * + * @return executable {@link Block} + * + * @throws ParseException If parsing fails. + */ + public Executable parse() { + ScopeBuilder scopeBuilder = new ScopeBuilder(); + return new Executable(parseBlock(new Tokenizer(data), false, scopeBuilder), scopeBuilder); + } + + private Keyword parseLoopLike(Tokenizer tokens, boolean loop, ScopeBuilder scopeBuilder) throws ParseException { + + Token identifier = tokens.consume(); + ParserUtil.checkType(identifier, Token.Type.IF_STATEMENT, Token.Type.WHILE_LOOP, Token.Type.FOR_LOOP); + + ParserUtil.checkType(tokens.consume(), Token.Type.GROUP_BEGIN); + + return switch(identifier.getType()) { + case FOR_LOOP -> parseForLoop(tokens, identifier.getPosition(), scopeBuilder); + case IF_STATEMENT -> parseIfStatement(tokens, identifier.getPosition(), loop, scopeBuilder); + case WHILE_LOOP -> parseWhileLoop(tokens, identifier.getPosition(), scopeBuilder); + default -> throw new UnsupportedOperationException( + "Unknown keyword " + identifier.getContent() + ": " + identifier.getPosition()); + }; + } + + private WhileKeyword parseWhileLoop(Tokenizer tokens, Position start, ScopeBuilder scopeBuilder) { + Returnable first = parseExpression(tokens, true, scopeBuilder); + ParserUtil.checkReturnType(first, Returnable.ReturnType.BOOLEAN); + + ParserUtil.checkType(tokens.consume(), Token.Type.GROUP_END); + + return new WhileKeyword(parseStatementBlock(tokens, true, scopeBuilder), (Returnable) first, start); // While loop + } + + private IfKeyword parseIfStatement(Tokenizer tokens, Position start, boolean loop, ScopeBuilder scopeBuilder) { + Returnable condition = parseExpression(tokens, true, scopeBuilder); + ParserUtil.checkReturnType(condition, Returnable.ReturnType.BOOLEAN); + + ParserUtil.checkType(tokens.consume(), Token.Type.GROUP_END); + + Block elseBlock = null; + Block statement = parseStatementBlock(tokens, loop, scopeBuilder); + + List, Block>> elseIf = new ArrayList<>(); + + while(tokens.hasNext() && tokens.get().getType().equals(Token.Type.ELSE)) { + tokens.consume(); // Consume else. + if(tokens.get().getType().equals(Token.Type.IF_STATEMENT)) { + tokens.consume(); // Consume if. + Returnable elseCondition = parseExpression(tokens, true, scopeBuilder); + ParserUtil.checkReturnType(elseCondition, Returnable.ReturnType.BOOLEAN); + elseIf.add(Pair.of((Returnable) elseCondition, parseStatementBlock(tokens, loop, scopeBuilder))); + } else { + elseBlock = parseStatementBlock(tokens, loop, scopeBuilder); + break; // Else must be last. + } + } + + return new IfKeyword(statement, (Returnable) condition, elseIf, elseBlock, start); // If statement + } + + private Block parseStatementBlock(Tokenizer tokens, boolean loop, ScopeBuilder scopeBuilder) { + + if(tokens.get().getType().equals(Token.Type.BLOCK_BEGIN)) { + ParserUtil.checkType(tokens.consume(), Token.Type.BLOCK_BEGIN); + Block block = parseBlock(tokens, loop, scopeBuilder); + ParserUtil.checkType(tokens.consume(), Token.Type.BLOCK_END); + return block; + } else { + Position position = tokens.get().getPosition(); + Block block = new Block(Collections.singletonList(parseItem(tokens, loop, scopeBuilder)), position); + ParserUtil.checkType(tokens.consume(), Token.Type.STATEMENT_END); + return block; + } + } + + private ForKeyword parseForLoop(Tokenizer tokens, Position start, ScopeBuilder scopeBuilder) { + scopeBuilder = scopeBuilder.sub(); // new scope + Token f = tokens.get(); + ParserUtil.checkType(f, Token.Type.NUMBER_VARIABLE, Token.Type.STRING_VARIABLE, Token.Type.BOOLEAN_VARIABLE, Token.Type.IDENTIFIER); + Item initializer; + if(f.isVariableDeclaration()) { + VariableAssignmentNode forVar = parseVariableDeclaration(tokens, scopeBuilder); + Token name = tokens.get(); + if(functions.containsKey(name.getContent()) || scopeBuilder.contains(name.getContent())) + throw new ParseException(name.getContent() + " is already defined in this scope", name.getPosition()); + initializer = forVar; + } else initializer = parseExpression(tokens, true, scopeBuilder); + ParserUtil.checkType(tokens.consume(), Token.Type.STATEMENT_END); + Returnable conditional = parseExpression(tokens, true, scopeBuilder); + ParserUtil.checkReturnType(conditional, Returnable.ReturnType.BOOLEAN); + ParserUtil.checkType(tokens.consume(), Token.Type.STATEMENT_END); + + Item incrementer; + Token token = tokens.get(); + if(scopeBuilder.contains(token.getContent())) { // Assume variable assignment + incrementer = parseAssignment(tokens, scopeBuilder); + } else incrementer = parseFunction(tokens, true, scopeBuilder); + + ParserUtil.checkType(tokens.consume(), Token.Type.GROUP_END); + + return new ForKeyword(parseStatementBlock(tokens, true, scopeBuilder), initializer, (Returnable) conditional, incrementer, + start); + } + + private Returnable parseExpression(Tokenizer tokens, boolean full, ScopeBuilder scopeBuilder) { + boolean booleanInverted = false; // Check for boolean not operator + boolean negate = false; + if(tokens.get().getType().equals(Token.Type.BOOLEAN_NOT)) { + booleanInverted = true; + tokens.consume(); + } else if(tokens.get().getType().equals(Token.Type.SUBTRACTION_OPERATOR)) { + negate = true; + tokens.consume(); + } + + Token id = tokens.get(); + + ParserUtil.checkType(id, Token.Type.IDENTIFIER, Token.Type.BOOLEAN, Token.Type.STRING, Token.Type.NUMBER, Token.Type.GROUP_BEGIN); + + Returnable expression; + if(id.isConstant()) { + expression = parseConstantExpression(tokens); + } else if(id.getType().equals(Token.Type.GROUP_BEGIN)) { // Parse grouped expression + expression = parseGroup(tokens, scopeBuilder); + } else { + if(functions.containsKey(id.getContent())) + expression = parseFunction(tokens, false, scopeBuilder); + else if(scopeBuilder.contains(id.getContent())) { + ParserUtil.checkType(tokens.consume(), Token.Type.IDENTIFIER); + String varId = id.getContent(); + ReturnType varType = scopeBuilder.getType(varId); + expression = switch(varType) { + case NUMBER -> new NumVariableReferenceNode(id.getPosition(), varType, scopeBuilder.getIndex(varId)); + case STRING -> new StrVariableReferenceNode(id.getPosition(), varType, scopeBuilder.getIndex(varId)); + case BOOLEAN -> new BoolVariableReferenceNode(id.getPosition(), varType, scopeBuilder.getIndex(varId)); + default -> throw new ParseException("Illegal type for variable reference: " + varType, id.getPosition()); + }; + + } else throw new ParseException("Unexpected token \" " + id.getContent() + "\"", id.getPosition()); + } + + if(booleanInverted) { // Invert operation if boolean not detected + ParserUtil.checkReturnType(expression, Returnable.ReturnType.BOOLEAN); + expression = new BooleanNotOperation((Returnable) expression, expression.getPosition()); + } else if(negate) { + ParserUtil.checkReturnType(expression, Returnable.ReturnType.NUMBER); + expression = new NegationOperation((Returnable) expression, expression.getPosition()); + } + + if(full && tokens.get().isBinaryOperator()) { // Parse binary operations + return parseBinaryOperation(expression, tokens, scopeBuilder); + } + return expression; + } + + private ConstantExpression parseConstantExpression(Tokenizer tokens) { + Token constantToken = tokens.consume(); + Position position = constantToken.getPosition(); + switch(constantToken.getType()) { + case NUMBER: + String content = constantToken.getContent(); + return new NumericConstant(content.contains(".") ? Double.parseDouble(content) : Integer.parseInt(content), position); + case STRING: + return new StringConstant(constantToken.getContent(), position); + case BOOLEAN: + return new BooleanConstant(Boolean.parseBoolean(constantToken.getContent()), position); + default: + throw new UnsupportedOperationException( + "Unsupported constant token: " + constantToken.getType() + " at position: " + position); + } + } + + private Returnable parseGroup(Tokenizer tokens, ScopeBuilder scopeBuilder) { + ParserUtil.checkType(tokens.consume(), Token.Type.GROUP_BEGIN); + Returnable expression = parseExpression(tokens, true, scopeBuilder); // Parse inside of group as a separate expression + ParserUtil.checkType(tokens.consume(), Token.Type.GROUP_END); + return expression; + } + + private BinaryOperation parseBinaryOperation(Returnable left, Tokenizer tokens, + ScopeBuilder scopeBuilder) { + Token binaryOperator = tokens.consume(); + ParserUtil.checkBinaryOperator(binaryOperator); + + Returnable right = parseExpression(tokens, false, scopeBuilder); + + Token other = tokens.get(); + if(ParserUtil.hasPrecedence(binaryOperator.getType(), other.getType())) { + return assemble(left, parseBinaryOperation(right, tokens, scopeBuilder), binaryOperator); + } else if(other.isBinaryOperator()) { + return parseBinaryOperation(assemble(left, right, binaryOperator), tokens, scopeBuilder); + } + return assemble(left, right, binaryOperator); + } + + private BinaryOperation assemble(Returnable left, Returnable right, Token binaryOperator) { + if(binaryOperator.isStrictNumericOperator()) + ParserUtil.checkArithmeticOperation(left, right, binaryOperator); // Numeric type checking + if(binaryOperator.isStrictBooleanOperator()) ParserUtil.checkBooleanOperation(left, right, binaryOperator); // Boolean type checking + switch(binaryOperator.getType()) { + case ADDITION_OPERATOR: + if(left.returnType().equals(Returnable.ReturnType.NUMBER) && right.returnType().equals(Returnable.ReturnType.NUMBER)) { + return new NumberAdditionOperation((Returnable) left, (Returnable) right, binaryOperator.getPosition()); + } + return new ConcatenationOperation((Returnable) left, (Returnable) right, binaryOperator.getPosition()); + case SUBTRACTION_OPERATOR: + return new SubtractionOperation((Returnable) left, (Returnable) right, binaryOperator.getPosition()); + case MULTIPLICATION_OPERATOR: + return new MultiplicationOperation((Returnable) left, (Returnable) right, binaryOperator.getPosition()); + case DIVISION_OPERATOR: + return new DivisionOperation((Returnable) left, (Returnable) right, binaryOperator.getPosition()); + case EQUALS_OPERATOR: + return new EqualsStatement((Returnable) left, (Returnable) right, binaryOperator.getPosition()); + case NOT_EQUALS_OPERATOR: + return new NotEqualsStatement((Returnable) left, (Returnable) right, binaryOperator.getPosition()); + case GREATER_THAN_OPERATOR: + return new GreaterThanStatement((Returnable) left, (Returnable) right, binaryOperator.getPosition()); + case LESS_THAN_OPERATOR: + return new LessThanStatement((Returnable) left, (Returnable) right, binaryOperator.getPosition()); + case GREATER_THAN_OR_EQUALS_OPERATOR: + return new GreaterOrEqualsThanStatement((Returnable) left, (Returnable) right, + binaryOperator.getPosition()); + case LESS_THAN_OR_EQUALS_OPERATOR: + return new LessThanOrEqualsStatement((Returnable) left, (Returnable) right, binaryOperator.getPosition()); + case BOOLEAN_AND: + return new BooleanAndOperation((Returnable) left, (Returnable) right, binaryOperator.getPosition()); + case BOOLEAN_OR: + return new BooleanOrOperation((Returnable) left, (Returnable) right, binaryOperator.getPosition()); + case MODULO_OPERATOR: + return new ModuloOperation((Returnable) left, (Returnable) right, binaryOperator.getPosition()); + default: + throw new UnsupportedOperationException("Unsupported binary operator: " + binaryOperator.getType()); + } + } + + private VariableAssignmentNode parseVariableDeclaration(Tokenizer tokens, ScopeBuilder scopeBuilder) { + Token type = tokens.consume(); + ParserUtil.checkType(type, Token.Type.STRING_VARIABLE, Token.Type.BOOLEAN_VARIABLE, Token.Type.NUMBER_VARIABLE); + + Returnable.ReturnType returnType = ParserUtil.getVariableReturnType(type); + + ParserUtil.checkVarType(type, returnType); // Check for type mismatch + Token identifier = tokens.consume(); + ParserUtil.checkType(identifier, Token.Type.IDENTIFIER); + if(functions.containsKey(identifier.getContent()) || scopeBuilder.contains(identifier.getContent())) + throw new ParseException(identifier.getContent() + " is already defined in this scope", identifier.getPosition()); + ParserUtil.checkType(tokens.consume(), Token.Type.ASSIGNMENT); + + Returnable value = parseExpression(tokens, true, scopeBuilder); + ParserUtil.checkReturnType(value, returnType); + + String id = identifier.getContent(); + + return switch(value.returnType()) { + case NUMBER -> new NumAssignmentNode((Returnable) value, identifier.getPosition(), scopeBuilder.num(id)); + case STRING -> new StrAssignmentNode((Returnable) value, identifier.getPosition(), scopeBuilder.str(id)); + case BOOLEAN -> new BoolAssignmentNode((Returnable) value, identifier.getPosition(), scopeBuilder.bool(id)); + default -> throw new ParseException("Illegal type for variable declaration: " + type, value.getPosition()); + }; + } + + private Block parseBlock(Tokenizer tokens, boolean loop, ScopeBuilder scopeBuilder) { + List> parsedItems = new ArrayList<>(); + + scopeBuilder = scopeBuilder.sub(); + + Token first = tokens.get(); + + while(tokens.hasNext()) { + Token token = tokens.get(); + if(token.getType().equals(Token.Type.BLOCK_END)) break; // Stop parsing at block end. + Item parsedItem = parseItem(tokens, loop, scopeBuilder); + if(parsedItem != Function.NULL) { + parsedItems.add(parsedItem); + } + if(tokens.hasNext() && !token.isLoopLike()) ParserUtil.checkType(tokens.consume(), Token.Type.STATEMENT_END); + } + return new Block(parsedItems, first.getPosition()); + } + + private Item parseItem(Tokenizer tokens, boolean loop, ScopeBuilder scopeBuilder) { + Token token = tokens.get(); + if(loop) ParserUtil.checkType(token, Token.Type.IDENTIFIER, Token.Type.IF_STATEMENT, Token.Type.WHILE_LOOP, Token.Type.FOR_LOOP, + Token.Type.NUMBER_VARIABLE, Token.Type.STRING_VARIABLE, Token.Type.BOOLEAN_VARIABLE, + Token.Type.RETURN, Token.Type.BREAK, Token.Type.CONTINUE, Token.Type.FAIL); + else ParserUtil.checkType(token, Token.Type.IDENTIFIER, Token.Type.IF_STATEMENT, Token.Type.WHILE_LOOP, Token.Type.FOR_LOOP, + Token.Type.NUMBER_VARIABLE, Token.Type.STRING_VARIABLE, Token.Type.BOOLEAN_VARIABLE, Token.Type.RETURN, + Token.Type.FAIL); + + if(token.isLoopLike()) { // Parse loop-like tokens (if, while, etc) + return parseLoopLike(tokens, loop, scopeBuilder); + } else if(token.isIdentifier()) { // Parse identifiers + if(scopeBuilder.contains(token.getContent())) { // Assume variable assignment + return parseAssignment(tokens, scopeBuilder); + } else return parseFunction(tokens, true, scopeBuilder); + } else if(token.isVariableDeclaration()) { + + return parseVariableDeclaration(tokens, scopeBuilder); + + } else if(token.getType().equals(Token.Type.RETURN)) return new ReturnKeyword(tokens.consume().getPosition()); + else if(token.getType().equals(Token.Type.BREAK)) return new BreakKeyword(tokens.consume().getPosition()); + else if(token.getType().equals(Token.Type.CONTINUE)) return new ContinueKeyword(tokens.consume().getPosition()); + else if(token.getType().equals(Token.Type.FAIL)) return new FailKeyword(tokens.consume().getPosition()); + else throw new UnsupportedOperationException("Unexpected token " + token.getType() + ": " + token.getPosition()); + } + + private VariableAssignmentNode parseAssignment(Tokenizer tokens, ScopeBuilder scopeBuilder) { + Token identifier = tokens.consume(); + + ParserUtil.checkType(identifier, Token.Type.IDENTIFIER); + + ParserUtil.checkType(tokens.consume(), Token.Type.ASSIGNMENT); + + Returnable value = parseExpression(tokens, true, scopeBuilder); + + String id = identifier.getContent(); + + ParserUtil.checkReturnType(value, scopeBuilder.getType(id)); + + ReturnType type = value.returnType(); + + return switch(type) { + case NUMBER -> new NumAssignmentNode((Returnable) value, identifier.getPosition(), scopeBuilder.getIndex(id)); + case STRING -> new StrAssignmentNode((Returnable) value, identifier.getPosition(), scopeBuilder.getIndex(id)); + case BOOLEAN -> new BoolAssignmentNode((Returnable) value, identifier.getPosition(), scopeBuilder.getIndex(id)); + default -> throw new ParseException("Illegal type for variable assignment: " + type, value.getPosition()); + }; + } + + private Function parseFunction(Tokenizer tokens, boolean fullStatement, ScopeBuilder scopeBuilder) { + Token identifier = tokens.consume(); + ParserUtil.checkType(identifier, Token.Type.IDENTIFIER); // First token must be identifier + + if(!functions.containsKey(identifier.getContent())) + throw new ParseException("No such function \"" + identifier.getContent() + "\"", identifier.getPosition()); + + ParserUtil.checkType(tokens.consume(), Token.Type.GROUP_BEGIN); // Second is body begin + + + List> args = getArgs(tokens, scopeBuilder); // Extract arguments, consume the rest. + + ParserUtil.checkType(tokens.consume(), Token.Type.GROUP_END); // Remove body end + + if(fullStatement) ParserUtil.checkType(tokens.get(), Token.Type.STATEMENT_END); + + if(ignoredFunctions.contains(identifier.getContent())) { + return Function.NULL; + } + + if(functions.containsKey(identifier.getContent())) { + FunctionBuilder builder = functions.get(identifier.getContent()); + + if(builder.argNumber() != -1 && args.size() != builder.argNumber()) + throw new ParseException("Expected " + builder.argNumber() + " arguments, found " + args.size(), identifier.getPosition()); + + for(int i = 0; i < args.size(); i++) { + Returnable argument = args.get(i); + if(builder.getArgument(i) == null) + throw new ParseException("Unexpected argument at position " + i + " in function " + identifier.getContent(), + identifier.getPosition()); + ParserUtil.checkReturnType(argument, builder.getArgument(i)); + } + return builder.build(args, identifier.getPosition()); + } + throw new UnsupportedOperationException("Unsupported function: " + identifier.getContent()); + } + + private List> getArgs(Tokenizer tokens, ScopeBuilder scopeBuilder) { + List> args = new ArrayList<>(); + + while(!tokens.get().getType().equals(Token.Type.GROUP_END)) { + args.add(parseExpression(tokens, true, scopeBuilder)); + ParserUtil.checkType(tokens.get(), Token.Type.SEPARATOR, Token.Type.GROUP_END); + if(tokens.get().getType().equals(Token.Type.SEPARATOR)) tokens.consume(); + } + return args; + } +} diff --git a/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/ParserUtil.java b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/ParserUtil.java new file mode 100644 index 000000000..6a7f0c7bf --- /dev/null +++ b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/ParserUtil.java @@ -0,0 +1,115 @@ +/* + * 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.parser; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import com.dfsek.terra.addons.terrascript.parser.exceptions.ParseException; +import com.dfsek.terra.addons.terrascript.parser.lang.Returnable; +import com.dfsek.terra.addons.terrascript.tokenizer.Token; + + +public class ParserUtil { + + private static final Map> PRECEDENCE = new HashMap<>(); // If second has precedence, true. + private static final List ARITHMETIC = Arrays.asList(Token.Type.ADDITION_OPERATOR, Token.Type.SUBTRACTION_OPERATOR, + Token.Type.MULTIPLICATION_OPERATOR, Token.Type.DIVISION_OPERATOR, + Token.Type.MODULO_OPERATOR); + private static final List COMPARISON = Arrays.asList(Token.Type.EQUALS_OPERATOR, Token.Type.NOT_EQUALS_OPERATOR, + Token.Type.LESS_THAN_OPERATOR, Token.Type.LESS_THAN_OR_EQUALS_OPERATOR, + Token.Type.GREATER_THAN_OPERATOR, + Token.Type.GREATER_THAN_OR_EQUALS_OPERATOR); + + static { // Setup precedence + Map add = new HashMap<>(); // Addition/subtraction before Multiplication/division. + add.put(Token.Type.MULTIPLICATION_OPERATOR, true); + add.put(Token.Type.DIVISION_OPERATOR, true); + + PRECEDENCE.put(Token.Type.ADDITION_OPERATOR, add); + PRECEDENCE.put(Token.Type.SUBTRACTION_OPERATOR, add); + + Map numericBoolean = new HashMap<>(); + + ARITHMETIC.forEach(op -> numericBoolean.put(op, true)); // Numbers before comparison + COMPARISON.forEach(op -> PRECEDENCE.put(op, numericBoolean)); + + + Map booleanOps = new HashMap<>(); + ARITHMETIC.forEach(op -> booleanOps.put(op, true)); // Everything before boolean + COMPARISON.forEach(op -> booleanOps.put(op, true)); + + + PRECEDENCE.put(Token.Type.BOOLEAN_AND, booleanOps); + PRECEDENCE.put(Token.Type.BOOLEAN_OR, booleanOps); + } + + public static void checkType(Token token, Token.Type... expected) { + for(Token.Type type : expected) if(token.getType().equals(type)) return; + throw new ParseException("Expected " + Arrays.toString(expected) + " but found " + token.getType(), token.getPosition()); + } + + public static void checkReturnType(Returnable returnable, Returnable.ReturnType... types) { + for(Returnable.ReturnType type : types) if(returnable.returnType().equals(type)) return; + throw new ParseException("Expected " + Arrays.toString(types) + " but found " + returnable.returnType(), returnable.getPosition()); + } + + public static void checkArithmeticOperation(Returnable left, Returnable right, Token operation) { + if(!left.returnType().equals(Returnable.ReturnType.NUMBER) || !right.returnType().equals(Returnable.ReturnType.NUMBER)) { + throw new ParseException( + "Operation " + operation.getType() + " not supported between " + left.returnType() + " and " + right.returnType(), + operation.getPosition()); + } + } + + public static void checkBooleanOperation(Returnable left, Returnable right, Token operation) { + if(!left.returnType().equals(Returnable.ReturnType.BOOLEAN) || !right.returnType().equals(Returnable.ReturnType.BOOLEAN)) { + throw new ParseException( + "Operation " + operation.getType() + " not supported between " + left.returnType() + " and " + right.returnType(), + operation.getPosition()); + } + } + + public static void checkVarType(Token token, Returnable.ReturnType returnType) { + if(returnType.equals(Returnable.ReturnType.STRING) && token.getType().equals(Token.Type.STRING_VARIABLE)) return; + if(returnType.equals(Returnable.ReturnType.NUMBER) && token.getType().equals(Token.Type.NUMBER_VARIABLE)) return; + if(returnType.equals(Returnable.ReturnType.BOOLEAN) && token.getType().equals(Token.Type.BOOLEAN_VARIABLE)) return; + throw new ParseException("Type mismatch, cannot convert from " + returnType + " to " + token.getType(), token.getPosition()); + } + + /** + * Checks if token is a binary operator + * + * @param token Token to check + * + * @throws ParseException If token isn't a binary operator + */ + public static void checkBinaryOperator(Token token) { + if(!token.isBinaryOperator()) + throw new ParseException("Expected binary operator, found " + token.getType(), token.getPosition()); + } + + public static Returnable.ReturnType getVariableReturnType(Token varToken) { + return switch(varToken.getType()) { + case NUMBER_VARIABLE -> Returnable.ReturnType.NUMBER; + case STRING_VARIABLE -> Returnable.ReturnType.STRING; + case BOOLEAN_VARIABLE -> Returnable.ReturnType.BOOLEAN; + default -> throw new ParseException("Unexpected token " + varToken.getType() + "; expected variable declaration", + varToken.getPosition()); + }; + } + + public static boolean hasPrecedence(Token.Type first, Token.Type second) { + if(!PRECEDENCE.containsKey(first)) return false; + Map pre = PRECEDENCE.get(first); + if(!pre.containsKey(second)) return false; + return pre.get(second); + } +} diff --git a/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/exceptions/ParseException.java b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/exceptions/ParseException.java new file mode 100644 index 000000000..59fdb01ae --- /dev/null +++ b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/exceptions/ParseException.java @@ -0,0 +1,38 @@ +/* + * 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.parser.exceptions; + +import java.io.Serial; + +import com.dfsek.terra.addons.terrascript.tokenizer.Position; + + +public class ParseException extends RuntimeException { + @Serial + private static final long serialVersionUID = 6744390543046766386L; + private final Position position; + + public ParseException(String message, Position position) { + super(message); + this.position = position; + } + + public ParseException(String message, Position position, Throwable cause) { + super(message, cause); + this.position = position; + } + + @Override + public String getMessage() { + return super.getMessage() + ": " + position; + } + + public Position getPosition() { + return position; + } +} diff --git a/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/Block.java b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/Block.java new file mode 100644 index 000000000..65a8dbf7e --- /dev/null +++ b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/Block.java @@ -0,0 +1,76 @@ +/* + * 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.parser.lang; + +import java.util.List; + +import com.dfsek.terra.addons.terrascript.tokenizer.Position; + + +public class Block implements Item> { + private final List> items; + private final Position position; + + public Block(List> items, Position position) { + this.items = items; + this.position = position; + } + + @Override + public ReturnInfo apply(ImplementationArguments implementationArguments, Scope scope) { + for(Item item : items) { + Object result = item.apply(implementationArguments, scope); + if(result instanceof ReturnInfo level) { + if(!level.getLevel().equals(ReturnLevel.NONE)) return level; + } + } + return new ReturnInfo<>(ReturnLevel.NONE, null); + } + + @Override + public Position getPosition() { + return position; + } + + public enum ReturnLevel { + NONE(false), + BREAK(false), + CONTINUE(false), + RETURN(true), + FAIL(true); + + private final boolean returnFast; + + ReturnLevel(boolean returnFast) { + this.returnFast = returnFast; + } + + public boolean isReturnFast() { + return returnFast; + } + } + + + public static class ReturnInfo { + private final ReturnLevel level; + private final T data; + + public ReturnInfo(ReturnLevel level, T data) { + this.level = level; + this.data = data; + } + + public ReturnLevel getLevel() { + return level; + } + + public T getData() { + return data; + } + } +} diff --git a/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/Executable.java b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/Executable.java new file mode 100644 index 000000000..6f9c026a0 --- /dev/null +++ b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/Executable.java @@ -0,0 +1,19 @@ +package com.dfsek.terra.addons.terrascript.parser.lang; + + +import com.dfsek.terra.addons.terrascript.parser.lang.Scope.ScopeBuilder; + + +public class Executable { + private final Block script; + private final ThreadLocal scope; + + public Executable(Block script, ScopeBuilder scopeBuilder) { + this.script = script; + this.scope = ThreadLocal.withInitial(scopeBuilder::build); + } + + public boolean execute(ImplementationArguments arguments) { + return script.apply(arguments, scope.get()).getLevel() != Block.ReturnLevel.FAIL; + } +} diff --git a/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/ImplementationArguments.java b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/ImplementationArguments.java new file mode 100644 index 000000000..a0f78aefb --- /dev/null +++ b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/ImplementationArguments.java @@ -0,0 +1,14 @@ +/* + * 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.parser.lang; + +/** + * Arguments passed to {@link Item}s by the implementation + */ +public interface ImplementationArguments { +} diff --git a/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/Item.java b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/Item.java new file mode 100644 index 000000000..27947c291 --- /dev/null +++ b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/Item.java @@ -0,0 +1,25 @@ +/* + * 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.parser.lang; + +import com.dfsek.terra.addons.terrascript.tokenizer.Position; + + +public interface Item { + T apply(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"); + } + + Position getPosition(); +} diff --git a/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/Keyword.java b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/Keyword.java new file mode 100644 index 000000000..56bb8bfd8 --- /dev/null +++ b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/Keyword.java @@ -0,0 +1,11 @@ +/* + * 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.parser.lang; + +public interface Keyword extends Returnable { +} diff --git a/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/Returnable.java b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/Returnable.java new file mode 100644 index 000000000..ac6578f4c --- /dev/null +++ b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/Returnable.java @@ -0,0 +1,30 @@ +/* + * 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.parser.lang; + +public interface Returnable extends Item { + ReturnType returnType(); + + enum ReturnType { + NUMBER(true), + STRING(true), + BOOLEAN(false), + VOID(false), + OBJECT(false); + + private final boolean comparable; + + ReturnType(boolean comparable) { + this.comparable = comparable; + } + + public boolean isComparable() { + return comparable; + } + } +} diff --git a/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/Scope.java b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/Scope.java new file mode 100644 index 000000000..511c486bd --- /dev/null +++ b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/Scope.java @@ -0,0 +1,138 @@ +package com.dfsek.terra.addons.terrascript.parser.lang; + + +import net.jafama.FastMath; + +import java.util.HashMap; +import java.util.Map; + +import com.dfsek.terra.addons.terrascript.parser.lang.Returnable.ReturnType; +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> indices; + private int numSize, boolSize, strSize = 0; + private ScopeBuilder parent; + + public ScopeBuilder() { + this.indices = new HashMap<>(); + } + + private ScopeBuilder(ScopeBuilder parent) { + this.parent = parent; + this.numSize = parent.numSize; + this.boolSize = parent.boolSize; + this.strSize = parent.strSize; + this.indices = new HashMap<>(parent.indices); + } + + public Scope build() { + return new Scope(numSize, boolSize, strSize); + } + + public ScopeBuilder sub() { + return new ScopeBuilder(this); + } + + private String check(String id) { + if(indices.containsKey(id)) { + throw new IllegalArgumentException("Variable with ID " + id + " already registered."); + } + return id; + } + + public int num(String id) { + int num = numSize; + indices.put(check(id), Pair.of(num, ReturnType.NUMBER)); + numSize++; + updateNumSize(numSize); + return num; + } + + public int str(String id) { + int str = strSize; + indices.put(check(id), Pair.of(str, ReturnType.STRING)); + strSize++; + updateStrSize(strSize); + return str; + } + + public int bool(String id) { + int bool = boolSize; + indices.put(check(id), Pair.of(bool, ReturnType.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 ReturnType getType(String id) { + return indices.get(id).getRight(); + } + + + public boolean contains(String id) { + return indices.containsKey(id); + } + } +} diff --git a/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/Statement.java b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/Statement.java new file mode 100644 index 000000000..14300e5fa --- /dev/null +++ b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/Statement.java @@ -0,0 +1,11 @@ +/* + * 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.parser.lang; + +public interface Statement extends Item { +} diff --git a/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/constants/BooleanConstant.java b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/constants/BooleanConstant.java new file mode 100644 index 000000000..3782344d1 --- /dev/null +++ b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/constants/BooleanConstant.java @@ -0,0 +1,32 @@ +/* + * 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.parser.lang.constants; + +import com.dfsek.terra.addons.terrascript.parser.lang.ImplementationArguments; +import com.dfsek.terra.addons.terrascript.parser.lang.Scope; +import com.dfsek.terra.addons.terrascript.tokenizer.Position; + + +public class BooleanConstant extends ConstantExpression { + private final boolean constant; + + public BooleanConstant(Boolean constant, Position position) { + super(constant, position); + this.constant = constant; + } + + @Override + public boolean applyBoolean(ImplementationArguments implementationArguments, Scope scope) { + return constant; + } + + @Override + public ReturnType returnType() { + return ReturnType.BOOLEAN; + } +} diff --git a/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/constants/ConstantExpression.java b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/constants/ConstantExpression.java new file mode 100644 index 000000000..dc783a628 --- /dev/null +++ b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/constants/ConstantExpression.java @@ -0,0 +1,38 @@ +/* + * 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.parser.lang.constants; + +import com.dfsek.terra.addons.terrascript.parser.lang.ImplementationArguments; +import com.dfsek.terra.addons.terrascript.parser.lang.Returnable; +import com.dfsek.terra.addons.terrascript.parser.lang.Scope; +import com.dfsek.terra.addons.terrascript.tokenizer.Position; + + +public abstract class ConstantExpression implements Returnable { + private final T constant; + private final Position position; + + public ConstantExpression(T constant, Position position) { + this.constant = constant; + this.position = position; + } + + @Override + public T apply(ImplementationArguments implementationArguments, Scope scope) { + return constant; + } + + @Override + public Position getPosition() { + return position; + } + + public T getConstant() { + return constant; + } +} diff --git a/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/constants/NumericConstant.java b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/constants/NumericConstant.java new file mode 100644 index 000000000..296b0c3e4 --- /dev/null +++ b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/constants/NumericConstant.java @@ -0,0 +1,33 @@ +/* + * 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.parser.lang.constants; + +import com.dfsek.terra.addons.terrascript.parser.lang.ImplementationArguments; +import com.dfsek.terra.addons.terrascript.parser.lang.Returnable; +import com.dfsek.terra.addons.terrascript.parser.lang.Scope; +import com.dfsek.terra.addons.terrascript.tokenizer.Position; + + +public class NumericConstant extends ConstantExpression { + private final double constant; + + public NumericConstant(Number constant, Position position) { + super(constant, position); + this.constant = constant.doubleValue(); + } + + @Override + public double applyDouble(ImplementationArguments implementationArguments, Scope scope) { + return constant; + } + + @Override + public Returnable.ReturnType returnType() { + return Returnable.ReturnType.NUMBER; + } +} diff --git a/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/constants/StringConstant.java b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/constants/StringConstant.java new file mode 100644 index 000000000..3e44bea10 --- /dev/null +++ b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/constants/StringConstant.java @@ -0,0 +1,23 @@ +/* + * 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.parser.lang.constants; + +import com.dfsek.terra.addons.terrascript.parser.lang.Returnable; +import com.dfsek.terra.addons.terrascript.tokenizer.Position; + + +public class StringConstant extends ConstantExpression { + public StringConstant(String constant, Position position) { + super(constant, position); + } + + @Override + public Returnable.ReturnType returnType() { + return Returnable.ReturnType.STRING; + } +} diff --git a/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/functions/Function.java b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/functions/Function.java new file mode 100644 index 000000000..9c1da1155 --- /dev/null +++ b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/functions/Function.java @@ -0,0 +1,43 @@ +/* + * 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.parser.lang.functions; + +import com.dfsek.terra.addons.terrascript.parser.lang.ImplementationArguments; +import com.dfsek.terra.addons.terrascript.parser.lang.Returnable; +import com.dfsek.terra.addons.terrascript.parser.lang.Scope; +import com.dfsek.terra.addons.terrascript.tokenizer.Position; + + +public interface Function extends Returnable { + Function NULL = new Function<>() { + @Override + public ReturnType returnType() { + return null; + } + + @Override + public Object apply(ImplementationArguments implementationArguments, Scope scope) { + return null; + } + + @Override + public Position getPosition() { + return null; + } + }; + + @Override + default double applyDouble(ImplementationArguments implementationArguments, Scope scope) { + return ((Number) apply(implementationArguments, scope)).doubleValue(); + } + + @Override + default boolean applyBoolean(ImplementationArguments implementationArguments, Scope scope) { + return (Boolean) apply(implementationArguments, scope); + } +} diff --git a/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/functions/FunctionBuilder.java b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/functions/FunctionBuilder.java new file mode 100644 index 000000000..d43121c6f --- /dev/null +++ b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/functions/FunctionBuilder.java @@ -0,0 +1,22 @@ +/* + * 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.parser.lang.functions; + +import java.util.List; + +import com.dfsek.terra.addons.terrascript.parser.lang.Returnable; +import com.dfsek.terra.addons.terrascript.tokenizer.Position; + + +public interface FunctionBuilder> { + T build(List> argumentList, Position position); + + int argNumber(); + + Returnable.ReturnType getArgument(int position); +} diff --git a/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/keywords/flow/BreakKeyword.java b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/keywords/flow/BreakKeyword.java new file mode 100644 index 000000000..b70b656ee --- /dev/null +++ b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/keywords/flow/BreakKeyword.java @@ -0,0 +1,38 @@ +/* + * 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.parser.lang.keywords.flow; + +import com.dfsek.terra.addons.terrascript.parser.lang.Block; +import com.dfsek.terra.addons.terrascript.parser.lang.ImplementationArguments; +import com.dfsek.terra.addons.terrascript.parser.lang.Keyword; +import com.dfsek.terra.addons.terrascript.parser.lang.Scope; +import com.dfsek.terra.addons.terrascript.tokenizer.Position; + + +public class BreakKeyword implements Keyword> { + private final Position position; + + public BreakKeyword(Position position) { + this.position = position; + } + + @Override + public Block.ReturnInfo apply(ImplementationArguments implementationArguments, Scope scope) { + return new Block.ReturnInfo<>(Block.ReturnLevel.BREAK, null); + } + + @Override + public Position getPosition() { + return position; + } + + @Override + public ReturnType returnType() { + return ReturnType.VOID; + } +} diff --git a/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/keywords/flow/ContinueKeyword.java b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/keywords/flow/ContinueKeyword.java new file mode 100644 index 000000000..f7b03d3b4 --- /dev/null +++ b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/keywords/flow/ContinueKeyword.java @@ -0,0 +1,38 @@ +/* + * 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.parser.lang.keywords.flow; + +import com.dfsek.terra.addons.terrascript.parser.lang.Block; +import com.dfsek.terra.addons.terrascript.parser.lang.ImplementationArguments; +import com.dfsek.terra.addons.terrascript.parser.lang.Keyword; +import com.dfsek.terra.addons.terrascript.parser.lang.Scope; +import com.dfsek.terra.addons.terrascript.tokenizer.Position; + + +public class ContinueKeyword implements Keyword> { + private final Position position; + + public ContinueKeyword(Position position) { + this.position = position; + } + + @Override + public Block.ReturnInfo apply(ImplementationArguments implementationArguments, Scope scope) { + return new Block.ReturnInfo<>(Block.ReturnLevel.CONTINUE, null); + } + + @Override + public Position getPosition() { + return position; + } + + @Override + public ReturnType returnType() { + return ReturnType.VOID; + } +} diff --git a/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/keywords/flow/FailKeyword.java b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/keywords/flow/FailKeyword.java new file mode 100644 index 000000000..4f6a82f50 --- /dev/null +++ b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/keywords/flow/FailKeyword.java @@ -0,0 +1,38 @@ +/* + * 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.parser.lang.keywords.flow; + +import com.dfsek.terra.addons.terrascript.parser.lang.Block; +import com.dfsek.terra.addons.terrascript.parser.lang.ImplementationArguments; +import com.dfsek.terra.addons.terrascript.parser.lang.Keyword; +import com.dfsek.terra.addons.terrascript.parser.lang.Scope; +import com.dfsek.terra.addons.terrascript.tokenizer.Position; + + +public class FailKeyword implements Keyword> { + private final Position position; + + public FailKeyword(Position position) { + this.position = position; + } + + @Override + public Block.ReturnInfo apply(ImplementationArguments implementationArguments, Scope scope) { + return new Block.ReturnInfo<>(Block.ReturnLevel.FAIL, null); + } + + @Override + public Position getPosition() { + return position; + } + + @Override + public ReturnType returnType() { + return ReturnType.VOID; + } +} diff --git a/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/keywords/flow/ReturnKeyword.java b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/keywords/flow/ReturnKeyword.java new file mode 100644 index 000000000..997098af1 --- /dev/null +++ b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/keywords/flow/ReturnKeyword.java @@ -0,0 +1,38 @@ +/* + * 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.parser.lang.keywords.flow; + +import com.dfsek.terra.addons.terrascript.parser.lang.Block; +import com.dfsek.terra.addons.terrascript.parser.lang.ImplementationArguments; +import com.dfsek.terra.addons.terrascript.parser.lang.Keyword; +import com.dfsek.terra.addons.terrascript.parser.lang.Scope; +import com.dfsek.terra.addons.terrascript.tokenizer.Position; + + +public class ReturnKeyword implements Keyword> { + private final Position position; + + public ReturnKeyword(Position position) { + this.position = position; + } + + @Override + public Block.ReturnInfo apply(ImplementationArguments implementationArguments, Scope scope) { + return new Block.ReturnInfo<>(Block.ReturnLevel.RETURN, null); + } + + @Override + public Position getPosition() { + return position; + } + + @Override + public ReturnType returnType() { + return ReturnType.VOID; + } +} diff --git a/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/keywords/looplike/ForKeyword.java b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/keywords/looplike/ForKeyword.java new file mode 100644 index 000000000..49f874724 --- /dev/null +++ b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/keywords/looplike/ForKeyword.java @@ -0,0 +1,55 @@ +/* + * 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.parser.lang.keywords.looplike; + +import com.dfsek.terra.addons.terrascript.parser.lang.Block; +import com.dfsek.terra.addons.terrascript.parser.lang.ImplementationArguments; +import com.dfsek.terra.addons.terrascript.parser.lang.Item; +import com.dfsek.terra.addons.terrascript.parser.lang.Keyword; +import com.dfsek.terra.addons.terrascript.parser.lang.Returnable; +import com.dfsek.terra.addons.terrascript.parser.lang.Scope; +import com.dfsek.terra.addons.terrascript.tokenizer.Position; + + +public class ForKeyword implements Keyword> { + private final Block conditional; + private final Item initializer; + private final Returnable statement; + private final Item incrementer; + private final Position position; + + public ForKeyword(Block conditional, Item initializer, Returnable statement, Item incrementer, Position position) { + this.conditional = conditional; + this.initializer = initializer; + this.statement = statement; + this.incrementer = incrementer; + this.position = position; + } + + @Override + public Block.ReturnInfo apply(ImplementationArguments implementationArguments, Scope scope) { + for(initializer.apply(implementationArguments, scope); + statement.apply(implementationArguments, scope); + incrementer.apply(implementationArguments, scope)) { + Block.ReturnInfo level = conditional.apply(implementationArguments, scope); + if(level.getLevel().equals(Block.ReturnLevel.BREAK)) break; + if(level.getLevel().isReturnFast()) return level; + } + return new Block.ReturnInfo<>(Block.ReturnLevel.NONE, null); + } + + @Override + public Position getPosition() { + return position; + } + + @Override + public ReturnType returnType() { + return ReturnType.VOID; + } +} diff --git a/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/keywords/looplike/IfKeyword.java b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/keywords/looplike/IfKeyword.java new file mode 100644 index 000000000..f49cab112 --- /dev/null +++ b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/keywords/looplike/IfKeyword.java @@ -0,0 +1,62 @@ +/* + * 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.parser.lang.keywords.looplike; + +import org.jetbrains.annotations.Nullable; + +import java.util.List; + +import com.dfsek.terra.addons.terrascript.parser.lang.Block; +import com.dfsek.terra.addons.terrascript.parser.lang.ImplementationArguments; +import com.dfsek.terra.addons.terrascript.parser.lang.Keyword; +import com.dfsek.terra.addons.terrascript.parser.lang.Returnable; +import com.dfsek.terra.addons.terrascript.parser.lang.Scope; +import com.dfsek.terra.addons.terrascript.tokenizer.Position; +import com.dfsek.terra.api.util.generic.pair.Pair; + + +public class IfKeyword implements Keyword> { + private final Block conditional; + private final Returnable statement; + private final Position position; + private final List, Block>> elseIf; + private final Block elseBlock; + + public IfKeyword(Block conditional, Returnable statement, List, Block>> elseIf, + @Nullable Block elseBlock, Position position) { + this.conditional = conditional; + this.statement = statement; + this.position = position; + this.elseIf = elseIf; + this.elseBlock = elseBlock; + } + + @Override + public Block.ReturnInfo apply(ImplementationArguments implementationArguments, Scope scope) { + if(statement.apply(implementationArguments, scope)) return conditional.apply(implementationArguments, scope); + else { + for(Pair, Block> pair : elseIf) { + if(pair.getLeft().apply(implementationArguments, scope)) { + return pair.getRight().apply(implementationArguments, scope); + } + } + if(elseBlock != null) return elseBlock.apply(implementationArguments, scope); + } + return new Block.ReturnInfo<>(Block.ReturnLevel.NONE, null); + } + + @Override + public Position getPosition() { + return position; + } + + @Override + public ReturnType returnType() { + return ReturnType.VOID; + } +} diff --git a/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/keywords/looplike/WhileKeyword.java b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/keywords/looplike/WhileKeyword.java new file mode 100644 index 000000000..d5126e7db --- /dev/null +++ b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/keywords/looplike/WhileKeyword.java @@ -0,0 +1,48 @@ +/* + * 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.parser.lang.keywords.looplike; + +import com.dfsek.terra.addons.terrascript.parser.lang.Block; +import com.dfsek.terra.addons.terrascript.parser.lang.ImplementationArguments; +import com.dfsek.terra.addons.terrascript.parser.lang.Keyword; +import com.dfsek.terra.addons.terrascript.parser.lang.Returnable; +import com.dfsek.terra.addons.terrascript.parser.lang.Scope; +import com.dfsek.terra.addons.terrascript.tokenizer.Position; + + +public class WhileKeyword implements Keyword> { + private final Block conditional; + private final Returnable statement; + private final Position position; + + public WhileKeyword(Block conditional, Returnable statement, Position position) { + this.conditional = conditional; + this.statement = statement; + this.position = position; + } + + @Override + public Block.ReturnInfo apply(ImplementationArguments implementationArguments, Scope scope) { + while(statement.apply(implementationArguments, scope)) { + Block.ReturnInfo level = conditional.apply(implementationArguments, scope); + if(level.getLevel().equals(Block.ReturnLevel.BREAK)) break; + if(level.getLevel().isReturnFast()) return level; + } + return new Block.ReturnInfo<>(Block.ReturnLevel.NONE, null); + } + + @Override + public Position getPosition() { + return position; + } + + @Override + public ReturnType returnType() { + return ReturnType.VOID; + } +} diff --git a/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/operations/BinaryOperation.java b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/operations/BinaryOperation.java new file mode 100644 index 000000000..fdacebe4c --- /dev/null +++ b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/operations/BinaryOperation.java @@ -0,0 +1,29 @@ +/* + * 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.parser.lang.operations; + +import com.dfsek.terra.addons.terrascript.parser.lang.Returnable; +import com.dfsek.terra.addons.terrascript.tokenizer.Position; + + +public abstract class BinaryOperation implements Returnable { + protected final Returnable left; + protected final Returnable right; + private final Position start; + + public BinaryOperation(Returnable left, Returnable right, Position start) { + this.left = left; + this.right = right; + this.start = start; + } + + @Override + public Position getPosition() { + return start; + } +} diff --git a/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/operations/BooleanAndOperation.java b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/operations/BooleanAndOperation.java new file mode 100644 index 000000000..94a08bbe6 --- /dev/null +++ b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/operations/BooleanAndOperation.java @@ -0,0 +1,35 @@ +/* + * 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.parser.lang.operations; + +import com.dfsek.terra.addons.terrascript.parser.lang.ImplementationArguments; +import com.dfsek.terra.addons.terrascript.parser.lang.Returnable; +import com.dfsek.terra.addons.terrascript.parser.lang.Scope; +import com.dfsek.terra.addons.terrascript.tokenizer.Position; + + +public class BooleanAndOperation extends BinaryOperation { + public BooleanAndOperation(Returnable left, Returnable right, Position start) { + super(left, right, start); + } + + @Override + public ReturnType returnType() { + return ReturnType.BOOLEAN; + } + + @Override + public Boolean apply(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); + } +} diff --git a/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/operations/BooleanNotOperation.java b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/operations/BooleanNotOperation.java new file mode 100644 index 000000000..a65e00184 --- /dev/null +++ b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/operations/BooleanNotOperation.java @@ -0,0 +1,35 @@ +/* + * 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.parser.lang.operations; + +import com.dfsek.terra.addons.terrascript.parser.lang.ImplementationArguments; +import com.dfsek.terra.addons.terrascript.parser.lang.Returnable; +import com.dfsek.terra.addons.terrascript.parser.lang.Scope; +import com.dfsek.terra.addons.terrascript.tokenizer.Position; + + +public class BooleanNotOperation extends UnaryOperation { + public BooleanNotOperation(Returnable input, Position position) { + super(input, position); + } + + @Override + public Boolean apply(ImplementationArguments implementationArguments, Scope scope) { + return applyBoolean(implementationArguments, scope); + } + + @Override + public boolean applyBoolean(ImplementationArguments implementationArguments, Scope scope) { + return !input.applyBoolean(implementationArguments, scope); + } + + @Override + public ReturnType returnType() { + return ReturnType.BOOLEAN; + } +} diff --git a/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/operations/BooleanOrOperation.java b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/operations/BooleanOrOperation.java new file mode 100644 index 000000000..4722e175c --- /dev/null +++ b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/operations/BooleanOrOperation.java @@ -0,0 +1,35 @@ +/* + * 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.parser.lang.operations; + +import com.dfsek.terra.addons.terrascript.parser.lang.ImplementationArguments; +import com.dfsek.terra.addons.terrascript.parser.lang.Returnable; +import com.dfsek.terra.addons.terrascript.parser.lang.Scope; +import com.dfsek.terra.addons.terrascript.tokenizer.Position; + + +public class BooleanOrOperation extends BinaryOperation { + public BooleanOrOperation(Returnable left, Returnable right, Position start) { + super(left, right, start); + } + + @Override + public Boolean apply(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 ReturnType returnType() { + return ReturnType.BOOLEAN; + } +} diff --git a/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/operations/ConcatenationOperation.java b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/operations/ConcatenationOperation.java new file mode 100644 index 000000000..1ff9d11b1 --- /dev/null +++ b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/operations/ConcatenationOperation.java @@ -0,0 +1,41 @@ +/* + * 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.parser.lang.operations; + +import com.dfsek.terra.addons.terrascript.parser.lang.ImplementationArguments; +import com.dfsek.terra.addons.terrascript.parser.lang.Returnable; +import com.dfsek.terra.addons.terrascript.parser.lang.Scope; +import com.dfsek.terra.addons.terrascript.tokenizer.Position; + + +public class ConcatenationOperation extends BinaryOperation { + public ConcatenationOperation(Returnable left, Returnable right, Position 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 Returnable.ReturnType returnType() { + return Returnable.ReturnType.STRING; + } + + @Override + public Object apply(ImplementationArguments implementationArguments, Scope scope) { + return toString(left.apply(implementationArguments, scope)) + toString(right.apply(implementationArguments, scope)); + } +} diff --git a/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/operations/DivisionOperation.java b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/operations/DivisionOperation.java new file mode 100644 index 000000000..793012549 --- /dev/null +++ b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/operations/DivisionOperation.java @@ -0,0 +1,35 @@ +/* + * 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.parser.lang.operations; + +import com.dfsek.terra.addons.terrascript.parser.lang.ImplementationArguments; +import com.dfsek.terra.addons.terrascript.parser.lang.Returnable; +import com.dfsek.terra.addons.terrascript.parser.lang.Scope; +import com.dfsek.terra.addons.terrascript.tokenizer.Position; + + +public class DivisionOperation extends BinaryOperation { + public DivisionOperation(Returnable left, Returnable right, Position position) { + super(left, right, position); + } + + @Override + public Returnable.ReturnType returnType() { + return Returnable.ReturnType.NUMBER; + } + + @Override + public Number apply(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); + } +} diff --git a/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/operations/ModuloOperation.java b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/operations/ModuloOperation.java new file mode 100644 index 000000000..b305f4c90 --- /dev/null +++ b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/operations/ModuloOperation.java @@ -0,0 +1,35 @@ +/* + * 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.parser.lang.operations; + +import com.dfsek.terra.addons.terrascript.parser.lang.ImplementationArguments; +import com.dfsek.terra.addons.terrascript.parser.lang.Returnable; +import com.dfsek.terra.addons.terrascript.parser.lang.Scope; +import com.dfsek.terra.addons.terrascript.tokenizer.Position; + + +public class ModuloOperation extends BinaryOperation { + public ModuloOperation(Returnable left, Returnable right, Position start) { + super(left, right, start); + } + + @Override + public Number apply(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 ReturnType returnType() { + return ReturnType.NUMBER; + } +} diff --git a/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/operations/MultiplicationOperation.java b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/operations/MultiplicationOperation.java new file mode 100644 index 000000000..2a2cdbfe6 --- /dev/null +++ b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/operations/MultiplicationOperation.java @@ -0,0 +1,35 @@ +/* + * 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.parser.lang.operations; + +import com.dfsek.terra.addons.terrascript.parser.lang.ImplementationArguments; +import com.dfsek.terra.addons.terrascript.parser.lang.Returnable; +import com.dfsek.terra.addons.terrascript.parser.lang.Scope; +import com.dfsek.terra.addons.terrascript.tokenizer.Position; + + +public class MultiplicationOperation extends BinaryOperation { + public MultiplicationOperation(Returnable left, Returnable right, Position position) { + super(left, right, position); + } + + @Override + public Number apply(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 ReturnType returnType() { + return ReturnType.NUMBER; + } +} diff --git a/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/operations/NegationOperation.java b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/operations/NegationOperation.java new file mode 100644 index 000000000..32d8f39b6 --- /dev/null +++ b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/operations/NegationOperation.java @@ -0,0 +1,35 @@ +/* + * 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.parser.lang.operations; + +import com.dfsek.terra.addons.terrascript.parser.lang.ImplementationArguments; +import com.dfsek.terra.addons.terrascript.parser.lang.Returnable; +import com.dfsek.terra.addons.terrascript.parser.lang.Scope; +import com.dfsek.terra.addons.terrascript.tokenizer.Position; + + +public class NegationOperation extends UnaryOperation { + public NegationOperation(Returnable input, Position position) { + super(input, position); + } + + @Override + public ReturnType returnType() { + return ReturnType.NUMBER; + } + + @Override + public Number apply(ImplementationArguments implementationArguments, Scope scope) { + return applyDouble(implementationArguments, scope); + } + + @Override + public double applyDouble(ImplementationArguments implementationArguments, Scope scope) { + return -input.applyDouble(implementationArguments, scope); + } +} diff --git a/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/operations/NumberAdditionOperation.java b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/operations/NumberAdditionOperation.java new file mode 100644 index 000000000..075a27619 --- /dev/null +++ b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/operations/NumberAdditionOperation.java @@ -0,0 +1,35 @@ +/* + * 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.parser.lang.operations; + +import com.dfsek.terra.addons.terrascript.parser.lang.ImplementationArguments; +import com.dfsek.terra.addons.terrascript.parser.lang.Returnable; +import com.dfsek.terra.addons.terrascript.parser.lang.Scope; +import com.dfsek.terra.addons.terrascript.tokenizer.Position; + + +public class NumberAdditionOperation extends BinaryOperation { + public NumberAdditionOperation(Returnable left, Returnable right, Position position) { + super(left, right, position); + } + + @Override + public Number apply(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 ReturnType returnType() { + return ReturnType.NUMBER; + } +} diff --git a/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/operations/SubtractionOperation.java b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/operations/SubtractionOperation.java new file mode 100644 index 000000000..9a11c430f --- /dev/null +++ b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/operations/SubtractionOperation.java @@ -0,0 +1,35 @@ +/* + * 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.parser.lang.operations; + +import com.dfsek.terra.addons.terrascript.parser.lang.ImplementationArguments; +import com.dfsek.terra.addons.terrascript.parser.lang.Returnable; +import com.dfsek.terra.addons.terrascript.parser.lang.Scope; +import com.dfsek.terra.addons.terrascript.tokenizer.Position; + + +public class SubtractionOperation extends BinaryOperation { + public SubtractionOperation(Returnable left, Returnable right, Position position) { + super(left, right, position); + } + + @Override + public Number apply(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 ReturnType returnType() { + return ReturnType.NUMBER; + } +} diff --git a/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/operations/UnaryOperation.java b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/operations/UnaryOperation.java new file mode 100644 index 000000000..d83ab0ad2 --- /dev/null +++ b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/operations/UnaryOperation.java @@ -0,0 +1,27 @@ +/* + * 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.parser.lang.operations; + +import com.dfsek.terra.addons.terrascript.parser.lang.Returnable; +import com.dfsek.terra.addons.terrascript.tokenizer.Position; + + +public abstract class UnaryOperation implements Returnable { + protected final Returnable input; + private final Position position; + + public UnaryOperation(Returnable input, Position position) { + this.input = input; + this.position = position; + } + + @Override + public Position getPosition() { + return position; + } +} diff --git a/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/operations/statements/EqualsStatement.java b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/operations/statements/EqualsStatement.java new file mode 100644 index 000000000..f402e4862 --- /dev/null +++ b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/operations/statements/EqualsStatement.java @@ -0,0 +1,48 @@ +/* + * 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.parser.lang.operations.statements; + +import net.jafama.FastMath; + +import com.dfsek.terra.addons.terrascript.parser.lang.ImplementationArguments; +import com.dfsek.terra.addons.terrascript.parser.lang.Returnable; +import com.dfsek.terra.addons.terrascript.parser.lang.Scope; +import com.dfsek.terra.addons.terrascript.parser.lang.operations.BinaryOperation; +import com.dfsek.terra.addons.terrascript.tokenizer.Position; + +import static com.dfsek.terra.api.util.MathUtil.EPSILON; + + +public class EqualsStatement extends BinaryOperation { + + public EqualsStatement(Returnable left, Returnable right, Position position) { + super(left, right, position); + } + + + @Override + public Returnable.ReturnType returnType() { + return Returnable.ReturnType.BOOLEAN; + } + + @Override + public Boolean apply(ImplementationArguments implementationArguments, Scope scope) { + return applyBoolean(implementationArguments, scope); + } + + @Override + public boolean applyBoolean(ImplementationArguments implementationArguments, Scope scope) { + Object leftValue = left.apply(implementationArguments, scope); + Object rightValue = right.apply(implementationArguments, scope); + if(leftValue instanceof Number l && rightValue instanceof Number r) { + return FastMath.abs(l.doubleValue() - r.doubleValue()) <= EPSILON; + } + + return leftValue.equals(rightValue); + } +} diff --git a/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/operations/statements/GreaterOrEqualsThanStatement.java b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/operations/statements/GreaterOrEqualsThanStatement.java new file mode 100644 index 000000000..d25f6bd0d --- /dev/null +++ b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/operations/statements/GreaterOrEqualsThanStatement.java @@ -0,0 +1,36 @@ +/* + * 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.parser.lang.operations.statements; + +import com.dfsek.terra.addons.terrascript.parser.lang.ImplementationArguments; +import com.dfsek.terra.addons.terrascript.parser.lang.Returnable; +import com.dfsek.terra.addons.terrascript.parser.lang.Scope; +import com.dfsek.terra.addons.terrascript.parser.lang.operations.BinaryOperation; +import com.dfsek.terra.addons.terrascript.tokenizer.Position; + + +public class GreaterOrEqualsThanStatement extends BinaryOperation { + public GreaterOrEqualsThanStatement(Returnable left, Returnable right, Position position) { + super(left, right, position); + } + + @Override + public Returnable.ReturnType returnType() { + return Returnable.ReturnType.BOOLEAN; + } + + @Override + public Boolean apply(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); + } +} diff --git a/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/operations/statements/GreaterThanStatement.java b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/operations/statements/GreaterThanStatement.java new file mode 100644 index 000000000..8e5cc4aee --- /dev/null +++ b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/operations/statements/GreaterThanStatement.java @@ -0,0 +1,37 @@ +/* + * 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.parser.lang.operations.statements; + +import com.dfsek.terra.addons.terrascript.parser.lang.ImplementationArguments; +import com.dfsek.terra.addons.terrascript.parser.lang.Returnable; +import com.dfsek.terra.addons.terrascript.parser.lang.Scope; +import com.dfsek.terra.addons.terrascript.parser.lang.operations.BinaryOperation; +import com.dfsek.terra.addons.terrascript.tokenizer.Position; + + +public class GreaterThanStatement extends BinaryOperation { + public GreaterThanStatement(Returnable left, Returnable right, Position position) { + super(left, right, position); + } + + + @Override + public Boolean apply(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 Returnable.ReturnType returnType() { + return Returnable.ReturnType.BOOLEAN; + } +} diff --git a/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/operations/statements/LessThanOrEqualsStatement.java b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/operations/statements/LessThanOrEqualsStatement.java new file mode 100644 index 000000000..891210395 --- /dev/null +++ b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/operations/statements/LessThanOrEqualsStatement.java @@ -0,0 +1,37 @@ +/* + * 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.parser.lang.operations.statements; + +import com.dfsek.terra.addons.terrascript.parser.lang.ImplementationArguments; +import com.dfsek.terra.addons.terrascript.parser.lang.Returnable; +import com.dfsek.terra.addons.terrascript.parser.lang.Scope; +import com.dfsek.terra.addons.terrascript.parser.lang.operations.BinaryOperation; +import com.dfsek.terra.addons.terrascript.tokenizer.Position; + + +public class LessThanOrEqualsStatement extends BinaryOperation { + public LessThanOrEqualsStatement(Returnable left, Returnable right, Position position) { + super(left, right, position); + } + + + @Override + public Boolean apply(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 Returnable.ReturnType returnType() { + return Returnable.ReturnType.BOOLEAN; + } +} diff --git a/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/operations/statements/LessThanStatement.java b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/operations/statements/LessThanStatement.java new file mode 100644 index 000000000..969f0e27e --- /dev/null +++ b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/operations/statements/LessThanStatement.java @@ -0,0 +1,37 @@ +/* + * 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.parser.lang.operations.statements; + +import com.dfsek.terra.addons.terrascript.parser.lang.ImplementationArguments; +import com.dfsek.terra.addons.terrascript.parser.lang.Returnable; +import com.dfsek.terra.addons.terrascript.parser.lang.Scope; +import com.dfsek.terra.addons.terrascript.parser.lang.operations.BinaryOperation; +import com.dfsek.terra.addons.terrascript.tokenizer.Position; + + +public class LessThanStatement extends BinaryOperation { + public LessThanStatement(Returnable left, Returnable right, Position position) { + super(left, right, position); + } + + + @Override + public Boolean apply(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 Returnable.ReturnType returnType() { + return Returnable.ReturnType.BOOLEAN; + } +} diff --git a/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/operations/statements/NotEqualsStatement.java b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/operations/statements/NotEqualsStatement.java new file mode 100644 index 000000000..3241c8657 --- /dev/null +++ b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/operations/statements/NotEqualsStatement.java @@ -0,0 +1,46 @@ +/* + * 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.parser.lang.operations.statements; + +import net.jafama.FastMath; + +import com.dfsek.terra.addons.terrascript.parser.lang.ImplementationArguments; +import com.dfsek.terra.addons.terrascript.parser.lang.Returnable; +import com.dfsek.terra.addons.terrascript.parser.lang.Scope; +import com.dfsek.terra.addons.terrascript.parser.lang.operations.BinaryOperation; +import com.dfsek.terra.addons.terrascript.tokenizer.Position; + +import static com.dfsek.terra.api.util.MathUtil.EPSILON; + + +public class NotEqualsStatement extends BinaryOperation { + public NotEqualsStatement(Returnable left, Returnable right, Position position) { + super(left, right, position); + } + + @Override + public Boolean apply(ImplementationArguments implementationArguments, Scope scope) { + return applyBoolean(implementationArguments, scope); + } + + @Override + public boolean applyBoolean(ImplementationArguments implementationArguments, Scope scope) { + Object leftValue = left.apply(implementationArguments, scope); + Object rightValue = right.apply(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 Returnable.ReturnType returnType() { + return Returnable.ReturnType.BOOLEAN; + } +} diff --git a/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/variables/BooleanVariable.java b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/variables/BooleanVariable.java new file mode 100644 index 000000000..205c99e6f --- /dev/null +++ b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/variables/BooleanVariable.java @@ -0,0 +1,42 @@ +/* + * 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.parser.lang.variables; + +import com.dfsek.terra.addons.terrascript.parser.lang.Returnable; +import com.dfsek.terra.addons.terrascript.tokenizer.Position; + + +public class BooleanVariable implements Variable { + private final Position position; + private Boolean value; + + public BooleanVariable(Boolean value, Position position) { + this.value = value; + this.position = position; + } + + @Override + public Boolean getValue() { + return value; + } + + @Override + public void setValue(Boolean value) { + this.value = value; + } + + @Override + public Returnable.ReturnType getType() { + return Returnable.ReturnType.BOOLEAN; + } + + @Override + public Position getPosition() { + return position; + } +} diff --git a/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/variables/NumberVariable.java b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/variables/NumberVariable.java new file mode 100644 index 000000000..698afdd4d --- /dev/null +++ b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/variables/NumberVariable.java @@ -0,0 +1,42 @@ +/* + * 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.parser.lang.variables; + +import com.dfsek.terra.addons.terrascript.parser.lang.Returnable; +import com.dfsek.terra.addons.terrascript.tokenizer.Position; + + +public class NumberVariable implements Variable { + private final Position position; + private Number value; + + public NumberVariable(Number value, Position position) { + this.value = value; + this.position = position; + } + + @Override + public Number getValue() { + return value; + } + + @Override + public void setValue(Number value) { + this.value = value; + } + + @Override + public Returnable.ReturnType getType() { + return Returnable.ReturnType.NUMBER; + } + + @Override + public Position getPosition() { + return position; + } +} diff --git a/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/variables/StringVariable.java b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/variables/StringVariable.java new file mode 100644 index 000000000..3ed471cd6 --- /dev/null +++ b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/variables/StringVariable.java @@ -0,0 +1,42 @@ +/* + * 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.parser.lang.variables; + +import com.dfsek.terra.addons.terrascript.parser.lang.Returnable; +import com.dfsek.terra.addons.terrascript.tokenizer.Position; + + +public class StringVariable implements Variable { + private final Position position; + private String value; + + public StringVariable(String value, Position position) { + this.value = value; + this.position = position; + } + + @Override + public String getValue() { + return value; + } + + @Override + public void setValue(String value) { + this.value = value; + } + + @Override + public Returnable.ReturnType getType() { + return Returnable.ReturnType.STRING; + } + + @Override + public Position getPosition() { + return position; + } +} diff --git a/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/variables/Variable.java b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/variables/Variable.java new file mode 100644 index 000000000..4bf0d6752 --- /dev/null +++ b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/variables/Variable.java @@ -0,0 +1,22 @@ +/* + * 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.parser.lang.variables; + +import com.dfsek.terra.addons.terrascript.parser.lang.Returnable; +import com.dfsek.terra.addons.terrascript.tokenizer.Position; + + +public interface Variable { + T getValue(); + + void setValue(T value); + + Returnable.ReturnType getType(); + + Position getPosition(); +} diff --git a/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/variables/assign/BoolAssignmentNode.java b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/variables/assign/BoolAssignmentNode.java new file mode 100644 index 000000000..8f0f47ee9 --- /dev/null +++ b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/variables/assign/BoolAssignmentNode.java @@ -0,0 +1,25 @@ +package com.dfsek.terra.addons.terrascript.parser.lang.variables.assign; + +import com.dfsek.terra.addons.terrascript.parser.lang.ImplementationArguments; +import com.dfsek.terra.addons.terrascript.parser.lang.Returnable; +import com.dfsek.terra.addons.terrascript.parser.lang.Scope; +import com.dfsek.terra.addons.terrascript.tokenizer.Position; + + +public class BoolAssignmentNode extends VariableAssignmentNode { + public BoolAssignmentNode(Returnable value, Position position, int index) { + super(value, position, index); + } + + @Override + public Boolean apply(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; + } +} diff --git a/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/variables/assign/NumAssignmentNode.java b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/variables/assign/NumAssignmentNode.java new file mode 100644 index 000000000..1b67e7150 --- /dev/null +++ b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/variables/assign/NumAssignmentNode.java @@ -0,0 +1,25 @@ +package com.dfsek.terra.addons.terrascript.parser.lang.variables.assign; + +import com.dfsek.terra.addons.terrascript.parser.lang.ImplementationArguments; +import com.dfsek.terra.addons.terrascript.parser.lang.Returnable; +import com.dfsek.terra.addons.terrascript.parser.lang.Scope; +import com.dfsek.terra.addons.terrascript.tokenizer.Position; + + +public class NumAssignmentNode extends VariableAssignmentNode { + public NumAssignmentNode(Returnable value, Position position, int index) { + super(value, position, index); + } + + @Override + public Number apply(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; + } +} diff --git a/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/variables/assign/StrAssignmentNode.java b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/variables/assign/StrAssignmentNode.java new file mode 100644 index 000000000..ee811dbd8 --- /dev/null +++ b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/variables/assign/StrAssignmentNode.java @@ -0,0 +1,21 @@ +package com.dfsek.terra.addons.terrascript.parser.lang.variables.assign; + +import com.dfsek.terra.addons.terrascript.parser.lang.ImplementationArguments; +import com.dfsek.terra.addons.terrascript.parser.lang.Returnable; +import com.dfsek.terra.addons.terrascript.parser.lang.Scope; +import com.dfsek.terra.addons.terrascript.tokenizer.Position; + + +public class StrAssignmentNode extends VariableAssignmentNode { + public StrAssignmentNode(Returnable value, Position position, int index) { + super(value, position, index); + } + + @Override + public String apply(ImplementationArguments implementationArguments, Scope scope) { + String val = value.apply(implementationArguments, scope); + scope.setStr(index, val); + return val; + } + +} diff --git a/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/variables/assign/VariableAssignmentNode.java b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/variables/assign/VariableAssignmentNode.java new file mode 100644 index 000000000..ebca757b5 --- /dev/null +++ b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/variables/assign/VariableAssignmentNode.java @@ -0,0 +1,31 @@ +/* + * 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.parser.lang.variables.assign; + +import com.dfsek.terra.addons.terrascript.parser.lang.Item; +import com.dfsek.terra.addons.terrascript.parser.lang.Returnable; +import com.dfsek.terra.addons.terrascript.tokenizer.Position; + + +public abstract class VariableAssignmentNode implements Item { + protected final Returnable value; + protected final int index; + private final Position position; + + + public VariableAssignmentNode(Returnable value, Position position, int index) { + this.value = value; + this.index = index; + this.position = position; + } + + @Override + public Position getPosition() { + return position; + } +} diff --git a/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/variables/reference/BoolVariableReferenceNode.java b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/variables/reference/BoolVariableReferenceNode.java new file mode 100644 index 000000000..c2295f2e2 --- /dev/null +++ b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/variables/reference/BoolVariableReferenceNode.java @@ -0,0 +1,22 @@ +package com.dfsek.terra.addons.terrascript.parser.lang.variables.reference; + +import com.dfsek.terra.addons.terrascript.parser.lang.ImplementationArguments; +import com.dfsek.terra.addons.terrascript.parser.lang.Scope; +import com.dfsek.terra.addons.terrascript.tokenizer.Position; + + +public class BoolVariableReferenceNode extends VariableReferenceNode { + public BoolVariableReferenceNode(Position position, ReturnType type, int index) { + super(position, type, index); + } + + @Override + public Boolean apply(ImplementationArguments implementationArguments, Scope scope) { + return scope.getBool(index); + } + + @Override + public boolean applyBoolean(ImplementationArguments implementationArguments, Scope scope) { + return scope.getBool(index); + } +} diff --git a/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/variables/reference/NumVariableReferenceNode.java b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/variables/reference/NumVariableReferenceNode.java new file mode 100644 index 000000000..a266dcca9 --- /dev/null +++ b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/variables/reference/NumVariableReferenceNode.java @@ -0,0 +1,22 @@ +package com.dfsek.terra.addons.terrascript.parser.lang.variables.reference; + +import com.dfsek.terra.addons.terrascript.parser.lang.ImplementationArguments; +import com.dfsek.terra.addons.terrascript.parser.lang.Scope; +import com.dfsek.terra.addons.terrascript.tokenizer.Position; + + +public class NumVariableReferenceNode extends VariableReferenceNode { + public NumVariableReferenceNode(Position position, ReturnType type, int index) { + super(position, type, index); + } + + @Override + public Number apply(ImplementationArguments implementationArguments, Scope scope) { + return scope.getNum(index); + } + + @Override + public double applyDouble(ImplementationArguments implementationArguments, Scope scope) { + return scope.getNum(index); + } +} diff --git a/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/variables/reference/StrVariableReferenceNode.java b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/variables/reference/StrVariableReferenceNode.java new file mode 100644 index 000000000..d67acc557 --- /dev/null +++ b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/variables/reference/StrVariableReferenceNode.java @@ -0,0 +1,17 @@ +package com.dfsek.terra.addons.terrascript.parser.lang.variables.reference; + +import com.dfsek.terra.addons.terrascript.parser.lang.ImplementationArguments; +import com.dfsek.terra.addons.terrascript.parser.lang.Scope; +import com.dfsek.terra.addons.terrascript.tokenizer.Position; + + +public class StrVariableReferenceNode extends VariableReferenceNode { + public StrVariableReferenceNode(Position position, ReturnType type, int index) { + super(position, type, index); + } + + @Override + public String apply(ImplementationArguments implementationArguments, Scope scope) { + return scope.getStr(index); + } +} diff --git a/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/variables/reference/VariableReferenceNode.java b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/variables/reference/VariableReferenceNode.java new file mode 100644 index 000000000..ecfebedca --- /dev/null +++ b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/parser/lang/variables/reference/VariableReferenceNode.java @@ -0,0 +1,34 @@ +/* + * 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.parser.lang.variables.reference; + +import com.dfsek.terra.addons.terrascript.parser.lang.Returnable; +import com.dfsek.terra.addons.terrascript.tokenizer.Position; + + +public abstract class VariableReferenceNode implements Returnable { + protected final int index; + private final Position position; + private final ReturnType type; + + public VariableReferenceNode(Position position, ReturnType type, int index) { + this.position = position; + this.type = type; + this.index = index; + } + + @Override + public ReturnType returnType() { + return type; + } + + @Override + public Position getPosition() { + return position; + } +} diff --git a/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/script/StructureScript.java b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/script/StructureScript.java new file mode 100644 index 000000000..e865d0d6d --- /dev/null +++ b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/script/StructureScript.java @@ -0,0 +1,160 @@ +/* + * 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.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.parser.Parser; +import com.dfsek.terra.addons.terrascript.parser.lang.Executable; +import com.dfsek.terra.addons.terrascript.parser.lang.Returnable; +import com.dfsek.terra.addons.terrascript.parser.lang.functions.FunctionBuilder; +import com.dfsek.terra.addons.terrascript.script.builders.BinaryNumberFunctionBuilder; +import com.dfsek.terra.addons.terrascript.script.builders.BiomeFunctionBuilder; +import com.dfsek.terra.addons.terrascript.script.builders.BlockFunctionBuilder; +import com.dfsek.terra.addons.terrascript.script.builders.CheckBlockFunctionBuilder; +import com.dfsek.terra.addons.terrascript.script.builders.EntityFunctionBuilder; +import com.dfsek.terra.addons.terrascript.script.builders.GetMarkFunctionBuilder; +import com.dfsek.terra.addons.terrascript.script.builders.LootFunctionBuilder; +import com.dfsek.terra.addons.terrascript.script.builders.PullFunctionBuilder; +import com.dfsek.terra.addons.terrascript.script.builders.RandomFunctionBuilder; +import com.dfsek.terra.addons.terrascript.script.builders.RecursionsFunctionBuilder; +import com.dfsek.terra.addons.terrascript.script.builders.SetMarkFunctionBuilder; +import com.dfsek.terra.addons.terrascript.script.builders.StateFunctionBuilder; +import com.dfsek.terra.addons.terrascript.script.builders.StructureFunctionBuilder; +import com.dfsek.terra.addons.terrascript.script.builders.UnaryBooleanFunctionBuilder; +import com.dfsek.terra.addons.terrascript.script.builders.UnaryNumberFunctionBuilder; +import com.dfsek.terra.addons.terrascript.script.builders.UnaryStringFunctionBuilder; +import com.dfsek.terra.addons.terrascript.script.builders.ZeroArgFunctionBuilder; +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 { + private static final Logger LOGGER = LoggerFactory.getLogger(StructureScript.class); + private final Executable block; + private final RegistryKey id; + + private final String profile; + private final Platform platform; + + @SuppressWarnings("rawtypes") + public StructureScript(InputStream inputStream, RegistryKey id, Platform platform, Registry registry, + Registry lootRegistry, + Registry functionRegistry) { + Parser parser; + try { + parser = new Parser(IOUtils.toString(inputStream, Charset.defaultCharset())); + } catch(IOException e) { + throw new RuntimeException(e); + } + this.id = id; + this.profile = "terrascript_direct:" + id; + + //noinspection unchecked + functionRegistry.forEach((key, function) -> parser.registerFunction(key.getID(), function)); // Register registry functions. + + parser + .registerFunction("block", new BlockFunctionBuilder(platform)) + .registerFunction("debugBlock", new BlockFunctionBuilder(platform)) + .registerFunction("structure", new StructureFunctionBuilder(registry, platform)) + .registerFunction("randomInt", new RandomFunctionBuilder()) + .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(arguments -> arguments.getOrigin().getX(), + Returnable.ReturnType.NUMBER)) + .registerFunction("originY", new ZeroArgFunctionBuilder(arguments -> arguments.getOrigin().getY(), + Returnable.ReturnType.NUMBER)) + .registerFunction("originZ", new ZeroArgFunctionBuilder(arguments -> arguments.getOrigin().getZ(), + Returnable.ReturnType.NUMBER)) + .registerFunction("rotation", new ZeroArgFunctionBuilder<>(arguments -> arguments.getRotation().toString(), + Returnable.ReturnType.STRING)) + .registerFunction("rotationDegrees", new ZeroArgFunctionBuilder<>(arguments -> arguments.getRotation().getDegrees(), + Returnable.ReturnType.NUMBER)) + .registerFunction("print", + new UnaryStringFunctionBuilder(string -> LOGGER.info("[TerraScript:{}] {}", id, string))) + .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()))); + + if(!platform.getTerraConfig().isDebugScript()) { + parser.ignoreFunction("debugBlock"); + } + + block = parser.parse(); + this.platform = platform; + } + + @Override + @SuppressWarnings("try") + public boolean generate(Vector3Int location, WritableWorld world, Random random, Rotation rotation) { + platform.getProfiler().push(profile); + boolean result = applyBlock(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 = applyBlock(new TerraImplementationArguments(location, rotation, random, world, recursions)); + platform.getProfiler().pop(profile); + return result; + } + + private boolean applyBlock(TerraImplementationArguments arguments) { + try { + return block.execute(arguments); + } catch(RuntimeException e) { + LOGGER.error("Failed to generate structure at {}", arguments.getOrigin(), e); + return false; + } + } + + @Override + public RegistryKey getRegistryKey() { + return id; + } +} diff --git a/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/script/TerraImplementationArguments.java b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/script/TerraImplementationArguments.java new file mode 100644 index 000000000..b9b9af058 --- /dev/null +++ b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/script/TerraImplementationArguments.java @@ -0,0 +1,73 @@ +/* + * 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.script; + +import java.util.HashMap; +import java.util.Map; +import java.util.Random; + +import com.dfsek.terra.addons.terrascript.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 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); + } +} diff --git a/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/script/builders/BinaryNumberFunctionBuilder.java b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/script/builders/BinaryNumberFunctionBuilder.java new file mode 100644 index 000000000..0e55e4d3d --- /dev/null +++ b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/script/builders/BinaryNumberFunctionBuilder.java @@ -0,0 +1,61 @@ +/* + * 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.script.builders; + +import java.util.List; +import java.util.function.BiFunction; + +import com.dfsek.terra.addons.terrascript.parser.lang.ImplementationArguments; +import com.dfsek.terra.addons.terrascript.parser.lang.Returnable; +import com.dfsek.terra.addons.terrascript.parser.lang.Scope; +import com.dfsek.terra.addons.terrascript.parser.lang.functions.Function; +import com.dfsek.terra.addons.terrascript.parser.lang.functions.FunctionBuilder; +import com.dfsek.terra.addons.terrascript.tokenizer.Position; + + +public class BinaryNumberFunctionBuilder implements FunctionBuilder> { + + private final BiFunction function; + + public BinaryNumberFunctionBuilder(BiFunction function) { + this.function = function; + } + + @Override + public Function build(List> argumentList, Position position) { + return new Function<>() { + @Override + public ReturnType returnType() { + return ReturnType.NUMBER; + } + + @SuppressWarnings("unchecked") + @Override + public Number apply(ImplementationArguments implementationArguments, Scope scope) { + return function.apply(((Returnable) argumentList.get(0)).apply(implementationArguments, scope), + ((Returnable) argumentList.get(1)).apply(implementationArguments, scope)); + } + + @Override + public Position getPosition() { + return position; + } + }; + } + + @Override + public int argNumber() { + return 2; + } + + @Override + public Returnable.ReturnType getArgument(int position) { + if(position == 0 || position == 1) return Returnable.ReturnType.NUMBER; + return null; + } +} diff --git a/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/script/builders/BiomeFunctionBuilder.java b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/script/builders/BiomeFunctionBuilder.java new file mode 100644 index 000000000..98d5e951b --- /dev/null +++ b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/script/builders/BiomeFunctionBuilder.java @@ -0,0 +1,45 @@ +/* + * 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.script.builders; + +import java.util.List; + +import com.dfsek.terra.addons.terrascript.parser.lang.Returnable; +import com.dfsek.terra.addons.terrascript.parser.lang.functions.FunctionBuilder; +import com.dfsek.terra.addons.terrascript.script.functions.BiomeFunction; +import com.dfsek.terra.addons.terrascript.tokenizer.Position; +import com.dfsek.terra.api.Platform; + + +public class BiomeFunctionBuilder implements FunctionBuilder { + private final Platform platform; + + public BiomeFunctionBuilder(Platform platform) { + this.platform = platform; + } + + @SuppressWarnings("unchecked") + @Override + public BiomeFunction build(List> argumentList, Position position) { + return new BiomeFunction((Returnable) argumentList.get(0), (Returnable) argumentList.get(1), + (Returnable) argumentList.get(2), position); + } + + @Override + public int argNumber() { + return 3; + } + + @Override + public Returnable.ReturnType getArgument(int position) { + return switch(position) { + case 0, 1, 2 -> Returnable.ReturnType.NUMBER; + default -> null; + }; + } +} diff --git a/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/script/builders/BlockFunctionBuilder.java b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/script/builders/BlockFunctionBuilder.java new file mode 100644 index 000000000..c2b6dc965 --- /dev/null +++ b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/script/builders/BlockFunctionBuilder.java @@ -0,0 +1,61 @@ +/* + * 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.script.builders; + +import java.util.List; + +import com.dfsek.terra.addons.terrascript.parser.exceptions.ParseException; +import com.dfsek.terra.addons.terrascript.parser.lang.Returnable; +import com.dfsek.terra.addons.terrascript.parser.lang.constants.BooleanConstant; +import com.dfsek.terra.addons.terrascript.parser.lang.constants.StringConstant; +import com.dfsek.terra.addons.terrascript.parser.lang.functions.FunctionBuilder; +import com.dfsek.terra.addons.terrascript.script.functions.BlockFunction; +import com.dfsek.terra.addons.terrascript.tokenizer.Position; +import com.dfsek.terra.api.Platform; + + +public class BlockFunctionBuilder implements FunctionBuilder { + private final Platform platform; + + public BlockFunctionBuilder(Platform platform) { + this.platform = platform; + } + + @SuppressWarnings("unchecked") + @Override + public BlockFunction build(List> argumentList, Position position) { + if(argumentList.size() < 4) throw new ParseException("Expected data", position); + Returnable overwrite = new BooleanConstant(true, position); + if(argumentList.size() >= 5) overwrite = (Returnable) argumentList.get(4); + Returnable physics = new BooleanConstant(false, position); + if(argumentList.size() == 6) physics = (Returnable) argumentList.get(5); + if(argumentList.get(3) instanceof StringConstant) { + return new BlockFunction.Constant((Returnable) argumentList.get(0), (Returnable) argumentList.get(1), + (Returnable) argumentList.get(2), (StringConstant) argumentList.get(3), + overwrite, physics, platform, position); + } + return new BlockFunction((Returnable) argumentList.get(0), (Returnable) argumentList.get(1), + (Returnable) argumentList.get(2), (Returnable) argumentList.get(3), overwrite, physics, + platform, position); + } + + @Override + public int argNumber() { + return -1; + } + + @Override + public Returnable.ReturnType getArgument(int position) { + return switch(position) { + case 0, 1, 2 -> Returnable.ReturnType.NUMBER; + case 3 -> Returnable.ReturnType.STRING; + case 4, 5 -> Returnable.ReturnType.BOOLEAN; + default -> null; + }; + } +} diff --git a/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/script/builders/CheckBlockFunctionBuilder.java b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/script/builders/CheckBlockFunctionBuilder.java new file mode 100644 index 000000000..2e32cf363 --- /dev/null +++ b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/script/builders/CheckBlockFunctionBuilder.java @@ -0,0 +1,38 @@ +/* + * 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.script.builders; + +import java.util.List; + +import com.dfsek.terra.addons.terrascript.parser.lang.Returnable; +import com.dfsek.terra.addons.terrascript.parser.lang.functions.FunctionBuilder; +import com.dfsek.terra.addons.terrascript.script.functions.CheckBlockFunction; +import com.dfsek.terra.addons.terrascript.tokenizer.Position; + + +public class CheckBlockFunctionBuilder implements FunctionBuilder { + @SuppressWarnings("unchecked") + @Override + public CheckBlockFunction build(List> argumentList, Position position) { + return new CheckBlockFunction((Returnable) argumentList.get(0), (Returnable) argumentList.get(1), + (Returnable) argumentList.get(2), position); + } + + @Override + public int argNumber() { + return 3; + } + + @Override + public Returnable.ReturnType getArgument(int position) { + return switch(position) { + case 0, 1, 2 -> Returnable.ReturnType.NUMBER; + default -> null; + }; + } +} diff --git a/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/script/builders/EntityFunctionBuilder.java b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/script/builders/EntityFunctionBuilder.java new file mode 100644 index 000000000..305105180 --- /dev/null +++ b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/script/builders/EntityFunctionBuilder.java @@ -0,0 +1,46 @@ +/* + * 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.script.builders; + +import java.util.List; + +import com.dfsek.terra.addons.terrascript.parser.lang.Returnable; +import com.dfsek.terra.addons.terrascript.parser.lang.functions.FunctionBuilder; +import com.dfsek.terra.addons.terrascript.script.functions.EntityFunction; +import com.dfsek.terra.addons.terrascript.tokenizer.Position; +import com.dfsek.terra.api.Platform; + + +public class EntityFunctionBuilder implements FunctionBuilder { + private final Platform platform; + + public EntityFunctionBuilder(Platform platform) { + this.platform = platform; + } + + @SuppressWarnings("unchecked") + @Override + public EntityFunction build(List> argumentList, Position position) { + return new EntityFunction((Returnable) argumentList.get(0), (Returnable) argumentList.get(1), + (Returnable) argumentList.get(2), (Returnable) argumentList.get(3), platform, position); + } + + @Override + public int argNumber() { + return 4; + } + + @Override + public Returnable.ReturnType getArgument(int position) { + return switch(position) { + case 0, 1, 2 -> Returnable.ReturnType.NUMBER; + case 3 -> Returnable.ReturnType.STRING; + default -> null; + }; + } +} diff --git a/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/script/builders/GetMarkFunctionBuilder.java b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/script/builders/GetMarkFunctionBuilder.java new file mode 100644 index 000000000..c38c406d4 --- /dev/null +++ b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/script/builders/GetMarkFunctionBuilder.java @@ -0,0 +1,42 @@ +/* + * 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.script.builders; + +import java.util.List; + +import com.dfsek.terra.addons.terrascript.parser.lang.Returnable; +import com.dfsek.terra.addons.terrascript.parser.lang.functions.FunctionBuilder; +import com.dfsek.terra.addons.terrascript.script.functions.GetMarkFunction; +import com.dfsek.terra.addons.terrascript.tokenizer.Position; + + +public class GetMarkFunctionBuilder implements FunctionBuilder { + + public GetMarkFunctionBuilder() { + } + + @SuppressWarnings("unchecked") + @Override + public GetMarkFunction build(List> argumentList, Position position) { + return new GetMarkFunction((Returnable) argumentList.get(0), (Returnable) argumentList.get(1), + (Returnable) argumentList.get(2), position); + } + + @Override + public int argNumber() { + return 3; + } + + @Override + public Returnable.ReturnType getArgument(int position) { + return switch(position) { + case 0, 1, 2 -> Returnable.ReturnType.NUMBER; + default -> null; + }; + } +} diff --git a/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/script/builders/LootFunctionBuilder.java b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/script/builders/LootFunctionBuilder.java new file mode 100644 index 000000000..293b5278c --- /dev/null +++ b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/script/builders/LootFunctionBuilder.java @@ -0,0 +1,54 @@ +/* + * 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.script.builders; + +import java.util.List; + +import com.dfsek.terra.addons.terrascript.parser.lang.Returnable; +import com.dfsek.terra.addons.terrascript.parser.lang.functions.FunctionBuilder; +import com.dfsek.terra.addons.terrascript.script.StructureScript; +import com.dfsek.terra.addons.terrascript.script.functions.LootFunction; +import com.dfsek.terra.addons.terrascript.tokenizer.Position; +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 { + private final Platform platform; + private final Registry registry; + private final StructureScript script; + + public LootFunctionBuilder(Platform platform, Registry registry, StructureScript script) { + this.platform = platform; + this.registry = registry; + this.script = script; + } + + @SuppressWarnings("unchecked") + @Override + public LootFunction build(List> argumentList, Position position) { + return new LootFunction(registry, (Returnable) argumentList.get(0), (Returnable) argumentList.get(1), + (Returnable) argumentList.get(2), (Returnable) argumentList.get(3), platform, position, + script); + } + + @Override + public int argNumber() { + return 4; + } + + @Override + public Returnable.ReturnType getArgument(int position) { + return switch(position) { + case 0, 1, 2 -> Returnable.ReturnType.NUMBER; + case 3 -> Returnable.ReturnType.STRING; + default -> null; + }; + } +} diff --git a/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/script/builders/PullFunctionBuilder.java b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/script/builders/PullFunctionBuilder.java new file mode 100644 index 000000000..ff970735d --- /dev/null +++ b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/script/builders/PullFunctionBuilder.java @@ -0,0 +1,46 @@ +/* + * 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.script.builders; + +import java.util.List; + +import com.dfsek.terra.addons.terrascript.parser.lang.Returnable; +import com.dfsek.terra.addons.terrascript.parser.lang.functions.FunctionBuilder; +import com.dfsek.terra.addons.terrascript.script.functions.PullFunction; +import com.dfsek.terra.addons.terrascript.tokenizer.Position; +import com.dfsek.terra.api.Platform; + + +public class PullFunctionBuilder implements FunctionBuilder { + private final Platform platform; + + public PullFunctionBuilder(Platform platform) { + this.platform = platform; + } + + @SuppressWarnings("unchecked") + @Override + public PullFunction build(List> argumentList, Position position) { + return new PullFunction((Returnable) argumentList.get(0), (Returnable) argumentList.get(1), + (Returnable) argumentList.get(2), (Returnable) argumentList.get(3), platform, position); + } + + @Override + public int argNumber() { + return 4; + } + + @Override + public Returnable.ReturnType getArgument(int position) { + return switch(position) { + case 0, 1, 2 -> Returnable.ReturnType.NUMBER; + case 3 -> Returnable.ReturnType.STRING; + default -> null; + }; + } +} diff --git a/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/script/builders/RandomFunctionBuilder.java b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/script/builders/RandomFunctionBuilder.java new file mode 100644 index 000000000..6cfeaa52d --- /dev/null +++ b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/script/builders/RandomFunctionBuilder.java @@ -0,0 +1,35 @@ +/* + * 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.script.builders; + +import java.util.List; + +import com.dfsek.terra.addons.terrascript.parser.lang.Returnable; +import com.dfsek.terra.addons.terrascript.parser.lang.functions.FunctionBuilder; +import com.dfsek.terra.addons.terrascript.script.functions.RandomFunction; +import com.dfsek.terra.addons.terrascript.tokenizer.Position; + + +public class RandomFunctionBuilder implements FunctionBuilder { + @SuppressWarnings("unchecked") + @Override + public RandomFunction build(List> argumentList, Position position) { + return new RandomFunction((Returnable) argumentList.get(0), position); + } + + @Override + public int argNumber() { + return 1; + } + + @Override + public Returnable.ReturnType getArgument(int position) { + if(position == 0) return Returnable.ReturnType.NUMBER; + return null; + } +} diff --git a/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/script/builders/RecursionsFunctionBuilder.java b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/script/builders/RecursionsFunctionBuilder.java new file mode 100644 index 000000000..f4b34673e --- /dev/null +++ b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/script/builders/RecursionsFunctionBuilder.java @@ -0,0 +1,33 @@ +/* + * 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.script.builders; + +import java.util.List; + +import com.dfsek.terra.addons.terrascript.parser.lang.Returnable; +import com.dfsek.terra.addons.terrascript.parser.lang.functions.FunctionBuilder; +import com.dfsek.terra.addons.terrascript.script.functions.RecursionsFunction; +import com.dfsek.terra.addons.terrascript.tokenizer.Position; + + +public class RecursionsFunctionBuilder implements FunctionBuilder { + @Override + public RecursionsFunction build(List> argumentList, Position position) { + return new RecursionsFunction(position); + } + + @Override + public int argNumber() { + return 0; + } + + @Override + public Returnable.ReturnType getArgument(int position) { + return null; + } +} diff --git a/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/script/builders/SetMarkFunctionBuilder.java b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/script/builders/SetMarkFunctionBuilder.java new file mode 100644 index 000000000..52babac7f --- /dev/null +++ b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/script/builders/SetMarkFunctionBuilder.java @@ -0,0 +1,43 @@ +/* + * 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.script.builders; + +import java.util.List; + +import com.dfsek.terra.addons.terrascript.parser.lang.Returnable; +import com.dfsek.terra.addons.terrascript.parser.lang.functions.FunctionBuilder; +import com.dfsek.terra.addons.terrascript.script.functions.SetMarkFunction; +import com.dfsek.terra.addons.terrascript.tokenizer.Position; + + +public class SetMarkFunctionBuilder implements FunctionBuilder { + + public SetMarkFunctionBuilder() { + } + + @SuppressWarnings("unchecked") + @Override + public SetMarkFunction build(List> argumentList, Position position) { + return new SetMarkFunction((Returnable) argumentList.get(0), (Returnable) argumentList.get(1), + (Returnable) argumentList.get(2), (Returnable) argumentList.get(3), position); + } + + @Override + public int argNumber() { + return 4; + } + + @Override + public Returnable.ReturnType getArgument(int position) { + return switch(position) { + case 0, 1, 2 -> Returnable.ReturnType.NUMBER; + case 3 -> Returnable.ReturnType.STRING; + default -> null; + }; + } +} diff --git a/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/script/builders/StateFunctionBuilder.java b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/script/builders/StateFunctionBuilder.java new file mode 100644 index 000000000..cecd17112 --- /dev/null +++ b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/script/builders/StateFunctionBuilder.java @@ -0,0 +1,48 @@ +/* + * 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.script.builders; + +import java.util.List; + +import com.dfsek.terra.addons.terrascript.parser.exceptions.ParseException; +import com.dfsek.terra.addons.terrascript.parser.lang.Returnable; +import com.dfsek.terra.addons.terrascript.parser.lang.functions.FunctionBuilder; +import com.dfsek.terra.addons.terrascript.script.functions.StateFunction; +import com.dfsek.terra.addons.terrascript.tokenizer.Position; +import com.dfsek.terra.api.Platform; + + +public class StateFunctionBuilder implements FunctionBuilder { + private final Platform platform; + + public StateFunctionBuilder(Platform platform) { + this.platform = platform; + } + + @SuppressWarnings("unchecked") + @Override + public StateFunction build(List> argumentList, Position position) { + if(argumentList.size() < 4) throw new ParseException("Expected data", position); + return new StateFunction((Returnable) argumentList.get(0), (Returnable) argumentList.get(1), + (Returnable) argumentList.get(2), (Returnable) argumentList.get(3), position); + } + + @Override + public int argNumber() { + return 4; + } + + @Override + public Returnable.ReturnType getArgument(int position) { + return switch(position) { + case 0, 1, 2 -> Returnable.ReturnType.NUMBER; + case 3 -> Returnable.ReturnType.STRING; + default -> null; + }; + } +} diff --git a/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/script/builders/StructureFunctionBuilder.java b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/script/builders/StructureFunctionBuilder.java new file mode 100644 index 000000000..69b05554d --- /dev/null +++ b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/script/builders/StructureFunctionBuilder.java @@ -0,0 +1,55 @@ +/* + * 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.script.builders; + +import java.util.List; +import java.util.stream.Collectors; + +import com.dfsek.terra.addons.terrascript.parser.exceptions.ParseException; +import com.dfsek.terra.addons.terrascript.parser.lang.Returnable; +import com.dfsek.terra.addons.terrascript.parser.lang.functions.FunctionBuilder; +import com.dfsek.terra.addons.terrascript.script.functions.StructureFunction; +import com.dfsek.terra.addons.terrascript.tokenizer.Position; +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 { + private final Registry registry; + private final Platform platform; + + public StructureFunctionBuilder(Registry registry, Platform platform) { + this.registry = registry; + this.platform = platform; + } + + @SuppressWarnings("unchecked") + @Override + public StructureFunction build(List> argumentList, Position position) { + if(argumentList.size() < 5) throw new ParseException("Expected rotations", position); + + return new StructureFunction((Returnable) argumentList.remove(0), (Returnable) argumentList.remove(0), + (Returnable) argumentList.remove(0), (Returnable) argumentList.remove(0), + argumentList.stream().map(item -> ((Returnable) item)).collect(Collectors.toList()), registry, + position, platform); + } + + @Override + public int argNumber() { + return -1; + } + + @Override + public Returnable.ReturnType getArgument(int position) { + return switch(position) { + case 0, 1, 2 -> Returnable.ReturnType.NUMBER; + default -> Returnable.ReturnType.STRING; + }; + } +} diff --git a/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/script/builders/UnaryBooleanFunctionBuilder.java b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/script/builders/UnaryBooleanFunctionBuilder.java new file mode 100644 index 000000000..922f4842f --- /dev/null +++ b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/script/builders/UnaryBooleanFunctionBuilder.java @@ -0,0 +1,63 @@ +/* + * 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.script.builders; + +import java.util.List; +import java.util.function.BiConsumer; + +import com.dfsek.terra.addons.terrascript.parser.lang.ImplementationArguments; +import com.dfsek.terra.addons.terrascript.parser.lang.Returnable; +import com.dfsek.terra.addons.terrascript.parser.lang.Scope; +import com.dfsek.terra.addons.terrascript.parser.lang.functions.Function; +import com.dfsek.terra.addons.terrascript.parser.lang.functions.FunctionBuilder; +import com.dfsek.terra.addons.terrascript.script.TerraImplementationArguments; +import com.dfsek.terra.addons.terrascript.tokenizer.Position; + + +public class UnaryBooleanFunctionBuilder implements FunctionBuilder> { + + private final BiConsumer function; + + public UnaryBooleanFunctionBuilder(BiConsumer function) { + this.function = function; + } + + @Override + public Function build(List> argumentList, Position position) { + return new Function<>() { + @Override + public ReturnType returnType() { + return ReturnType.VOID; + } + + @SuppressWarnings("unchecked") + @Override + public Void apply(ImplementationArguments implementationArguments, Scope scope) { + function.accept(((Returnable) argumentList.get(0)).apply(implementationArguments, scope), + (TerraImplementationArguments) implementationArguments); + return null; + } + + @Override + public Position getPosition() { + return position; + } + }; + } + + @Override + public int argNumber() { + return 1; + } + + @Override + public Returnable.ReturnType getArgument(int position) { + if(position == 0) return Returnable.ReturnType.BOOLEAN; + return null; + } +} diff --git a/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/script/builders/UnaryNumberFunctionBuilder.java b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/script/builders/UnaryNumberFunctionBuilder.java new file mode 100644 index 000000000..c20bf2479 --- /dev/null +++ b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/script/builders/UnaryNumberFunctionBuilder.java @@ -0,0 +1,59 @@ +/* + * 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.script.builders; + +import java.util.List; + +import com.dfsek.terra.addons.terrascript.parser.lang.ImplementationArguments; +import com.dfsek.terra.addons.terrascript.parser.lang.Returnable; +import com.dfsek.terra.addons.terrascript.parser.lang.Scope; +import com.dfsek.terra.addons.terrascript.parser.lang.functions.Function; +import com.dfsek.terra.addons.terrascript.parser.lang.functions.FunctionBuilder; +import com.dfsek.terra.addons.terrascript.tokenizer.Position; + + +public class UnaryNumberFunctionBuilder implements FunctionBuilder> { + + private final java.util.function.Function function; + + public UnaryNumberFunctionBuilder(java.util.function.Function function) { + this.function = function; + } + + @Override + public Function build(List> argumentList, Position position) { + return new Function<>() { + @Override + public ReturnType returnType() { + return ReturnType.NUMBER; + } + + @SuppressWarnings("unchecked") + @Override + public Number apply(ImplementationArguments implementationArguments, Scope scope) { + return function.apply(((Returnable) argumentList.get(0)).apply(implementationArguments, scope)); + } + + @Override + public Position getPosition() { + return position; + } + }; + } + + @Override + public int argNumber() { + return 1; + } + + @Override + public Returnable.ReturnType getArgument(int position) { + if(position == 0) return Returnable.ReturnType.NUMBER; + return null; + } +} diff --git a/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/script/builders/UnaryStringFunctionBuilder.java b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/script/builders/UnaryStringFunctionBuilder.java new file mode 100644 index 000000000..8bc6d7fd1 --- /dev/null +++ b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/script/builders/UnaryStringFunctionBuilder.java @@ -0,0 +1,60 @@ +/* + * 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.script.builders; + +import java.util.List; + +import com.dfsek.terra.addons.terrascript.parser.lang.ImplementationArguments; +import com.dfsek.terra.addons.terrascript.parser.lang.Returnable; +import com.dfsek.terra.addons.terrascript.parser.lang.Scope; +import com.dfsek.terra.addons.terrascript.parser.lang.functions.Function; +import com.dfsek.terra.addons.terrascript.parser.lang.functions.FunctionBuilder; +import com.dfsek.terra.addons.terrascript.tokenizer.Position; + + +public class UnaryStringFunctionBuilder implements FunctionBuilder> { + + private final java.util.function.Consumer function; + + public UnaryStringFunctionBuilder(java.util.function.Consumer function) { + this.function = function; + } + + @Override + public Function build(List> argumentList, Position position) { + return new Function<>() { + @Override + public ReturnType returnType() { + return ReturnType.VOID; + } + + @SuppressWarnings("unchecked") + @Override + public Void apply(ImplementationArguments implementationArguments, Scope scope) { + function.accept(((Returnable) argumentList.get(0)).apply(implementationArguments, scope)); + return null; + } + + @Override + public Position getPosition() { + return position; + } + }; + } + + @Override + public int argNumber() { + return 1; + } + + @Override + public Returnable.ReturnType getArgument(int position) { + if(position == 0) return Returnable.ReturnType.STRING; + return null; + } +} diff --git a/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/script/builders/ZeroArgFunctionBuilder.java b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/script/builders/ZeroArgFunctionBuilder.java new file mode 100644 index 000000000..da7806051 --- /dev/null +++ b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/script/builders/ZeroArgFunctionBuilder.java @@ -0,0 +1,60 @@ +/* + * 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.script.builders; + +import java.util.List; + +import com.dfsek.terra.addons.terrascript.parser.lang.ImplementationArguments; +import com.dfsek.terra.addons.terrascript.parser.lang.Returnable; +import com.dfsek.terra.addons.terrascript.parser.lang.Scope; +import com.dfsek.terra.addons.terrascript.parser.lang.functions.Function; +import com.dfsek.terra.addons.terrascript.parser.lang.functions.FunctionBuilder; +import com.dfsek.terra.addons.terrascript.script.TerraImplementationArguments; +import com.dfsek.terra.addons.terrascript.tokenizer.Position; + + +public class ZeroArgFunctionBuilder implements FunctionBuilder> { + private final java.util.function.Function function; + private final Returnable.ReturnType type; + + public ZeroArgFunctionBuilder(java.util.function.Function function, Returnable.ReturnType type) { + this.function = function; + this.type = type; + } + + @Override + public Function build(List> argumentList, Position position) { + return new Function<>() { + @Override + public ReturnType returnType() { + return type; + } + + @Override + public T apply(ImplementationArguments implementationArguments, Scope scope) { + return function.apply((TerraImplementationArguments) implementationArguments); + } + + @Override + public Position getPosition() { + return position; + } + }; + } + + @Override + public int argNumber() { + return 0; + } + + @Override + public Returnable.ReturnType getArgument(int position) { + if(position == 0) return type; + return null; + } +} diff --git a/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/script/functions/BiomeFunction.java b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/script/functions/BiomeFunction.java new file mode 100644 index 000000000..452b9f43b --- /dev/null +++ b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/script/functions/BiomeFunction.java @@ -0,0 +1,65 @@ +/* + * 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.script.functions; + +import net.jafama.FastMath; + +import com.dfsek.terra.addons.terrascript.parser.lang.ImplementationArguments; +import com.dfsek.terra.addons.terrascript.parser.lang.Returnable; +import com.dfsek.terra.addons.terrascript.parser.lang.Scope; +import com.dfsek.terra.addons.terrascript.parser.lang.functions.Function; +import com.dfsek.terra.addons.terrascript.script.TerraImplementationArguments; +import com.dfsek.terra.addons.terrascript.tokenizer.Position; +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 { + private final Returnable x, y, z; + private final Position position; + + + public BiomeFunction(Returnable x, Returnable y, Returnable z, Position position) { + this.x = x; + this.y = y; + this.z = z; + this.position = position; + } + + + @Override + public String apply(ImplementationArguments implementationArguments, Scope scope) { + TerraImplementationArguments arguments = (TerraImplementationArguments) implementationArguments; + + Vector2 xz = RotationUtil.rotateVector(Vector2.of(x.apply(implementationArguments, scope).doubleValue(), + z.apply(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.apply(implementationArguments, scope).intValue(), + FastMath.roundToInt(xz.getZ()))).immutable(), arguments.getWorld().getSeed()).getID(); + } + + @Override + public Position getPosition() { + return position; + } + + @Override + public ReturnType returnType() { + return ReturnType.STRING; + } +} diff --git a/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/script/functions/BlockFunction.java b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/script/functions/BlockFunction.java new file mode 100644 index 000000000..7997a15aa --- /dev/null +++ b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/script/functions/BlockFunction.java @@ -0,0 +1,107 @@ +/* + * 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.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.parser.lang.ImplementationArguments; +import com.dfsek.terra.addons.terrascript.parser.lang.Returnable; +import com.dfsek.terra.addons.terrascript.parser.lang.Scope; +import com.dfsek.terra.addons.terrascript.parser.lang.constants.StringConstant; +import com.dfsek.terra.addons.terrascript.parser.lang.functions.Function; +import com.dfsek.terra.addons.terrascript.script.TerraImplementationArguments; +import com.dfsek.terra.addons.terrascript.tokenizer.Position; +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 { + private static final Logger logger = LoggerFactory.getLogger(BlockFunction.class); + protected final Returnable x, y, z; + protected final Returnable blockData; + protected final Platform platform; + private final Map data = new HashMap<>(); + private final Returnable overwrite; + private final Returnable physics; + private final Position position; + + public BlockFunction(Returnable x, Returnable y, Returnable z, Returnable blockData, + Returnable overwrite, Returnable physics, Platform platform, Position position) { + this.x = x; + this.y = y; + this.z = z; + this.blockData = blockData; + this.overwrite = overwrite; + this.platform = platform; + this.position = position; + this.physics = physics; + } + + @Override + public Void apply(ImplementationArguments implementationArguments, Scope scope) { + TerraImplementationArguments arguments = (TerraImplementationArguments) implementationArguments; + BlockState rot = getBlockState(implementationArguments, scope); + setBlock(implementationArguments, scope, arguments, rot); + return null; + } + + @Override + public Position getPosition() { + return position; + } + + @Override + public ReturnType returnType() { + return ReturnType.VOID; + } + + void setBlock(ImplementationArguments implementationArguments, Scope scope, + TerraImplementationArguments arguments, BlockState rot) { + Vector2 xz = RotationUtil.rotateVector(Vector2.of(x.apply(implementationArguments, scope).doubleValue(), + z.apply(implementationArguments, scope).doubleValue()), arguments.getRotation()); + try { + Vector3.Mutable set = Vector3.of(FastMath.roundToInt(xz.getX()), + y.apply(implementationArguments, scope).doubleValue(), + FastMath.roundToInt(xz.getZ())).mutable().add(arguments.getOrigin()); + BlockState current = arguments.getWorld().getBlockState(set); + if(overwrite.apply(implementationArguments, scope) || current.isAir()) { + arguments.getWorld().setBlockState(set, rot, physics.apply(implementationArguments, scope)); + } + } 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.apply(arguments, scope), platform.getWorldHandle()::createBlockState); + } + + + public static class Constant extends BlockFunction { + private final BlockState state; + + public Constant(Returnable x, Returnable y, Returnable z, StringConstant blockData, + Returnable overwrite, Returnable physics, Platform platform, Position position) { + super(x, y, z, blockData, overwrite, physics, platform, position); + this.state = platform.getWorldHandle().createBlockState(blockData.getConstant()); + } + + @Override + protected BlockState getBlockState(ImplementationArguments arguments, Scope scope) { + return state; + } + } +} diff --git a/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/script/functions/CheckBlockFunction.java b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/script/functions/CheckBlockFunction.java new file mode 100644 index 000000000..d2fddf169 --- /dev/null +++ b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/script/functions/CheckBlockFunction.java @@ -0,0 +1,65 @@ +/* + * 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.script.functions; + +import net.jafama.FastMath; + +import com.dfsek.terra.addons.terrascript.parser.lang.ImplementationArguments; +import com.dfsek.terra.addons.terrascript.parser.lang.Returnable; +import com.dfsek.terra.addons.terrascript.parser.lang.Scope; +import com.dfsek.terra.addons.terrascript.parser.lang.functions.Function; +import com.dfsek.terra.addons.terrascript.script.TerraImplementationArguments; +import com.dfsek.terra.addons.terrascript.tokenizer.Position; +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 { + private final Returnable x, y, z; + private final Position position; + + public CheckBlockFunction(Returnable x, Returnable y, Returnable z, Position position) { + this.x = x; + this.y = y; + this.z = z; + this.position = position; + } + + + @Override + public String apply(ImplementationArguments implementationArguments, Scope scope) { + TerraImplementationArguments arguments = (TerraImplementationArguments) implementationArguments; + + Vector2 xz = RotationUtil.rotateVector(Vector2.of(x.apply(implementationArguments, scope).doubleValue(), + z.apply(implementationArguments, scope).doubleValue()), + arguments.getRotation()); + + + String data = arguments.getWorld() + .getBlockState(arguments.getOrigin() + .toVector3() + .mutable() + .add(Vector3.of(FastMath.roundToInt(xz.getX()), + y.apply(implementationArguments, scope) + .doubleValue(), FastMath.roundToInt(xz.getZ())))) + .getAsString(); + if(data.contains("[")) return data.substring(0, data.indexOf('[')); // Strip properties + else return data; + } + + @Override + public Position getPosition() { + return position; + } + + @Override + public ReturnType returnType() { + return ReturnType.STRING; + } +} diff --git a/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/script/functions/EntityFunction.java b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/script/functions/EntityFunction.java new file mode 100644 index 000000000..9fd51ceac --- /dev/null +++ b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/script/functions/EntityFunction.java @@ -0,0 +1,70 @@ +/* + * 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.script.functions; + +import com.dfsek.terra.addons.terrascript.parser.exceptions.ParseException; +import com.dfsek.terra.addons.terrascript.parser.lang.ImplementationArguments; +import com.dfsek.terra.addons.terrascript.parser.lang.Returnable; +import com.dfsek.terra.addons.terrascript.parser.lang.Scope; +import com.dfsek.terra.addons.terrascript.parser.lang.constants.ConstantExpression; +import com.dfsek.terra.addons.terrascript.parser.lang.functions.Function; +import com.dfsek.terra.addons.terrascript.script.TerraImplementationArguments; +import com.dfsek.terra.addons.terrascript.tokenizer.Position; +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 { + private final EntityType data; + private final Returnable x, y, z; + private final Position position; + private final Platform platform; + + public EntityFunction(Returnable x, Returnable y, Returnable z, Returnable data, Platform platform, + Position 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) data).getConstant()); + this.x = x; + this.y = y; + this.z = z; + } + + @Override + public Void apply(ImplementationArguments implementationArguments, Scope scope) { + TerraImplementationArguments arguments = (TerraImplementationArguments) implementationArguments; + Vector2 xz = RotationUtil.rotateVector(Vector2.of(x.apply(implementationArguments, scope).doubleValue(), + z.apply(implementationArguments, scope).doubleValue()), arguments.getRotation()); + + Entity entity = arguments.getWorld().spawnEntity(Vector3.of(xz.getX(), y.apply(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 Position getPosition() { + return position; + } + + @Override + public ReturnType returnType() { + return ReturnType.VOID; + } +} diff --git a/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/script/functions/GetMarkFunction.java b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/script/functions/GetMarkFunction.java new file mode 100644 index 000000000..09e735665 --- /dev/null +++ b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/script/functions/GetMarkFunction.java @@ -0,0 +1,58 @@ +/* + * 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.script.functions; + +import net.jafama.FastMath; + +import com.dfsek.terra.addons.terrascript.parser.lang.ImplementationArguments; +import com.dfsek.terra.addons.terrascript.parser.lang.Returnable; +import com.dfsek.terra.addons.terrascript.parser.lang.Scope; +import com.dfsek.terra.addons.terrascript.parser.lang.functions.Function; +import com.dfsek.terra.addons.terrascript.script.TerraImplementationArguments; +import com.dfsek.terra.addons.terrascript.tokenizer.Position; +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 { + private final Returnable x, y, z; + private final Position position; + + public GetMarkFunction(Returnable x, Returnable y, Returnable z, Position position) { + this.position = position; + this.x = x; + this.y = y; + this.z = z; + } + + @Override + public String apply(ImplementationArguments implementationArguments, Scope scope) { + TerraImplementationArguments arguments = (TerraImplementationArguments) implementationArguments; + Vector2 xz = RotationUtil.rotateVector(Vector2.of(x.apply(implementationArguments, scope).doubleValue(), + z.apply(implementationArguments, scope).doubleValue()), arguments.getRotation()); + + String mark = arguments.getMark(Vector3.of(FastMath.floorToInt(xz.getX()), FastMath.floorToInt( + y.apply(implementationArguments, scope).doubleValue()), + FastMath.floorToInt(xz.getZ())) + .mutable() + .add(arguments.getOrigin()) + .immutable()); + return mark == null ? "" : mark; + } + + @Override + public Position getPosition() { + return position; + } + + @Override + public ReturnType returnType() { + return ReturnType.STRING; + } +} diff --git a/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/script/functions/LootFunction.java b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/script/functions/LootFunction.java new file mode 100644 index 000000000..ebadb9288 --- /dev/null +++ b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/script/functions/LootFunction.java @@ -0,0 +1,108 @@ +/* + * 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.script.functions; + +import net.jafama.FastMath; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Random; + +import com.dfsek.terra.addons.terrascript.parser.lang.ImplementationArguments; +import com.dfsek.terra.addons.terrascript.parser.lang.Returnable; +import com.dfsek.terra.addons.terrascript.parser.lang.Scope; +import com.dfsek.terra.addons.terrascript.parser.lang.functions.Function; +import com.dfsek.terra.addons.terrascript.script.StructureScript; +import com.dfsek.terra.addons.terrascript.script.TerraImplementationArguments; +import com.dfsek.terra.addons.terrascript.tokenizer.Position; +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 { + private static final Logger LOGGER = LoggerFactory.getLogger(LootFunction.class); + private final Registry registry; + private final Returnable data; + private final Returnable x, y, z; + private final Position position; + private final Platform platform; + private final StructureScript script; + + public LootFunction(Registry registry, Returnable x, Returnable y, Returnable z, + Returnable data, Platform platform, Position 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 apply(ImplementationArguments implementationArguments, Scope scope) { + TerraImplementationArguments arguments = (TerraImplementationArguments) implementationArguments; + Vector2 xz = RotationUtil.rotateVector(Vector2.of(x.apply(implementationArguments, scope).doubleValue(), + z.apply(implementationArguments, scope).doubleValue()), + arguments.getRotation()); + + + String id = data.apply(implementationArguments, scope); + + + registry.get(RegistryKey.parse(id)) + .ifPresentOrElse(table -> { + Vector3 apply = Vector3.of(FastMath.roundToInt(xz.getX()), + y.apply(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 Position getPosition() { + return position; + } + + @Override + public ReturnType returnType() { + return ReturnType.VOID; + } +} diff --git a/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/script/functions/PullFunction.java b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/script/functions/PullFunction.java new file mode 100644 index 000000000..70fbbafc5 --- /dev/null +++ b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/script/functions/PullFunction.java @@ -0,0 +1,70 @@ +/* + * 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.script.functions; + +import net.jafama.FastMath; + +import com.dfsek.terra.addons.terrascript.parser.exceptions.ParseException; +import com.dfsek.terra.addons.terrascript.parser.lang.ImplementationArguments; +import com.dfsek.terra.addons.terrascript.parser.lang.Returnable; +import com.dfsek.terra.addons.terrascript.parser.lang.Scope; +import com.dfsek.terra.addons.terrascript.parser.lang.constants.ConstantExpression; +import com.dfsek.terra.addons.terrascript.parser.lang.functions.Function; +import com.dfsek.terra.addons.terrascript.script.TerraImplementationArguments; +import com.dfsek.terra.addons.terrascript.tokenizer.Position; +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 { + private final BlockState data; + private final Returnable x, y, z; + private final Position position; + + public PullFunction(Returnable x, Returnable y, Returnable z, Returnable data, Platform platform, + Position position) { + this.position = position; + if(!(data instanceof ConstantExpression)) throw new ParseException("Block data must be constant", data.getPosition()); + + this.data = platform.getWorldHandle().createBlockState(((ConstantExpression) data).getConstant()); + this.x = x; + this.y = y; + this.z = z; + } + + @Override + public Void apply(ImplementationArguments implementationArguments, Scope scope) { + TerraImplementationArguments arguments = (TerraImplementationArguments) implementationArguments; + Vector2 xz = RotationUtil.rotateVector(Vector2.of(x.apply(implementationArguments, scope).doubleValue(), + z.apply(implementationArguments, scope).doubleValue()), arguments.getRotation()); + + Vector3.Mutable mutable = Vector3.of(FastMath.roundToInt(xz.getX()), y.apply(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 Position getPosition() { + return position; + } + + @Override + public ReturnType returnType() { + return ReturnType.VOID; + } +} diff --git a/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/script/functions/RandomFunction.java b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/script/functions/RandomFunction.java new file mode 100644 index 000000000..3170d2645 --- /dev/null +++ b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/script/functions/RandomFunction.java @@ -0,0 +1,43 @@ +/* + * 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.script.functions; + +import com.dfsek.terra.addons.terrascript.parser.lang.ImplementationArguments; +import com.dfsek.terra.addons.terrascript.parser.lang.Returnable; +import com.dfsek.terra.addons.terrascript.parser.lang.Scope; +import com.dfsek.terra.addons.terrascript.parser.lang.functions.Function; +import com.dfsek.terra.addons.terrascript.script.TerraImplementationArguments; +import com.dfsek.terra.addons.terrascript.tokenizer.Position; + + +public class RandomFunction implements Function { + private final Returnable numberReturnable; + private final Position position; + + public RandomFunction(Returnable numberReturnable, Position position) { + this.numberReturnable = numberReturnable; + this.position = position; + } + + + @Override + public ReturnType returnType() { + return ReturnType.NUMBER; + } + + @Override + public Integer apply(ImplementationArguments implementationArguments, Scope scope) { + return ((TerraImplementationArguments) implementationArguments).getRandom().nextInt( + numberReturnable.apply(implementationArguments, scope).intValue()); + } + + @Override + public Position getPosition() { + return position; + } +} diff --git a/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/script/functions/RecursionsFunction.java b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/script/functions/RecursionsFunction.java new file mode 100644 index 000000000..6343c1002 --- /dev/null +++ b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/script/functions/RecursionsFunction.java @@ -0,0 +1,38 @@ +/* + * 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.script.functions; + +import com.dfsek.terra.addons.terrascript.parser.lang.ImplementationArguments; +import com.dfsek.terra.addons.terrascript.parser.lang.Scope; +import com.dfsek.terra.addons.terrascript.parser.lang.functions.Function; +import com.dfsek.terra.addons.terrascript.script.TerraImplementationArguments; +import com.dfsek.terra.addons.terrascript.tokenizer.Position; + + +public class RecursionsFunction implements Function { + private final Position position; + + public RecursionsFunction(Position position) { + this.position = position; + } + + @Override + public ReturnType returnType() { + return ReturnType.NUMBER; + } + + @Override + public Number apply(ImplementationArguments implementationArguments, Scope scope) { + return ((TerraImplementationArguments) implementationArguments).getRecursions(); + } + + @Override + public Position getPosition() { + return position; + } +} diff --git a/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/script/functions/SetMarkFunction.java b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/script/functions/SetMarkFunction.java new file mode 100644 index 000000000..43a7436b9 --- /dev/null +++ b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/script/functions/SetMarkFunction.java @@ -0,0 +1,60 @@ +/* + * 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.script.functions; + +import net.jafama.FastMath; + +import com.dfsek.terra.addons.terrascript.parser.lang.ImplementationArguments; +import com.dfsek.terra.addons.terrascript.parser.lang.Returnable; +import com.dfsek.terra.addons.terrascript.parser.lang.Scope; +import com.dfsek.terra.addons.terrascript.parser.lang.functions.Function; +import com.dfsek.terra.addons.terrascript.script.TerraImplementationArguments; +import com.dfsek.terra.addons.terrascript.tokenizer.Position; +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 { + private final Returnable x, y, z; + private final Position position; + private final Returnable mark; + + public SetMarkFunction(Returnable x, Returnable y, Returnable z, Returnable mark, Position position) { + this.position = position; + this.mark = mark; + this.x = x; + this.y = y; + this.z = z; + } + + @Override + public Void apply(ImplementationArguments implementationArguments, Scope scope) { + TerraImplementationArguments arguments = (TerraImplementationArguments) implementationArguments; + Vector2 xz = RotationUtil.rotateVector(Vector2.of(x.apply(implementationArguments, scope).doubleValue(), + z.apply(implementationArguments, scope).doubleValue()), arguments.getRotation()); + + + arguments.setMark(Vector3.of(FastMath.floorToInt(xz.getX()), + FastMath.floorToInt( + y.apply(implementationArguments, scope).doubleValue()), + FastMath.floorToInt(xz.getZ())).mutable().add(arguments.getOrigin()).immutable(), + mark.apply(implementationArguments, scope)); + return null; + } + + @Override + public Position getPosition() { + return position; + } + + @Override + public ReturnType returnType() { + return ReturnType.VOID; + } +} diff --git a/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/script/functions/StateFunction.java b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/script/functions/StateFunction.java new file mode 100644 index 000000000..6ccbe1a80 --- /dev/null +++ b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/script/functions/StateFunction.java @@ -0,0 +1,70 @@ +/* + * 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.script.functions; + +import net.jafama.FastMath; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.dfsek.terra.addons.terrascript.parser.lang.ImplementationArguments; +import com.dfsek.terra.addons.terrascript.parser.lang.Returnable; +import com.dfsek.terra.addons.terrascript.parser.lang.Scope; +import com.dfsek.terra.addons.terrascript.parser.lang.functions.Function; +import com.dfsek.terra.addons.terrascript.script.TerraImplementationArguments; +import com.dfsek.terra.addons.terrascript.tokenizer.Position; +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 { + private static final Logger LOGGER = LoggerFactory.getLogger(StateFunction.class); + private final Returnable data; + private final Returnable x, y, z; + private final Position position; + + public StateFunction(Returnable x, Returnable y, Returnable z, Returnable data, + Position position) { + this.position = position; + this.data = data; + this.x = x; + this.y = y; + this.z = z; + } + + @Override + public Void apply(ImplementationArguments implementationArguments, Scope scope) { + TerraImplementationArguments arguments = (TerraImplementationArguments) implementationArguments; + Vector2 xz = RotationUtil.rotateVector(Vector2.of(x.apply(implementationArguments, scope).doubleValue(), + z.apply(implementationArguments, scope).doubleValue()), arguments.getRotation()); + + + Vector3 origin = Vector3.of(FastMath.roundToInt(xz.getX()), y.apply(implementationArguments, scope).intValue(), + FastMath.roundToInt(xz.getZ())).mutable().add(arguments.getOrigin()).immutable(); + try { + BlockEntity state = arguments.getWorld().getBlockEntity(origin); + state.applyState(data.apply(implementationArguments, scope)); + state.update(false); + } catch(Exception e) { + LOGGER.warn("Could not apply BlockState at {}", origin, e); + e.printStackTrace(); + } + return null; + } + + @Override + public Position getPosition() { + return position; + } + + @Override + public ReturnType returnType() { + return ReturnType.VOID; + } +} diff --git a/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/script/functions/StructureFunction.java b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/script/functions/StructureFunction.java new file mode 100644 index 000000000..51fb47054 --- /dev/null +++ b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/script/functions/StructureFunction.java @@ -0,0 +1,105 @@ +/* + * 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.script.functions; + +import net.jafama.FastMath; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.List; + +import com.dfsek.terra.addons.terrascript.parser.lang.ImplementationArguments; +import com.dfsek.terra.addons.terrascript.parser.lang.Returnable; +import com.dfsek.terra.addons.terrascript.parser.lang.Scope; +import com.dfsek.terra.addons.terrascript.parser.lang.functions.Function; +import com.dfsek.terra.addons.terrascript.script.StructureScript; +import com.dfsek.terra.addons.terrascript.script.TerraImplementationArguments; +import com.dfsek.terra.addons.terrascript.tokenizer.Position; +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 { + private static final Logger LOGGER = LoggerFactory.getLogger(StructureFunction.class); + private final Registry registry; + private final Returnable id; + private final Returnable x, y, z; + private final Position position; + private final Platform platform; + private final List> rotations; + + public StructureFunction(Returnable x, Returnable y, Returnable z, Returnable id, + List> rotations, Registry registry, Position 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 ReturnType returnType() { + return ReturnType.BOOLEAN; + } + + @Override + public Boolean apply(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.apply(implementationArguments, scope).doubleValue(), + z.apply(implementationArguments, scope).doubleValue()), arguments.getRotation()); + + + String app = id.apply(implementationArguments, scope); + return registry.getByID(app).map(script -> { + Rotation rotation1; + String rotString = rotations.get(arguments.getRandom().nextInt(rotations.size())).apply(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.apply(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.apply(implementationArguments, scope).intValue(), + FastMath.roundToInt(xz.getZ())), + arguments.getRandom(), + arguments.getRotation().rotate(rotation1)); + }).orElseGet(() -> { + LOGGER.error("No such structure {}", app); + return false; + }); + } + + @Override + public Position getPosition() { + return position; + } +} diff --git a/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/tokenizer/Char.java b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/tokenizer/Char.java new file mode 100644 index 000000000..c9a361492 --- /dev/null +++ b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/tokenizer/Char.java @@ -0,0 +1,63 @@ +/* + * 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.tokenizer; + +public class Char { + private final char character; + private final int index; + private final int line; + + + public Char(char character, int index, int line) { + this.character = character; + this.index = index; + this.line = line; + } + + public boolean is(char... tests) { + for(char test : tests) { + if(test == character && test != '\0') { + return true; + } + } + return false; + } + + @Override + public String toString() { + return Character.toString(character); + } + + public char getCharacter() { + return character; + } + + public int getIndex() { + return index; + } + + public int getLine() { + return line; + } + + public boolean isWhitespace() { + return Character.isWhitespace(character); + } + + public boolean isNewLine() { + return character == '\n'; + } + + public boolean isDigit() { + return Character.isDigit(character); + } + + public boolean isEOF() { + return character == '\0'; + } +} diff --git a/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/tokenizer/Lookahead.java b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/tokenizer/Lookahead.java new file mode 100644 index 000000000..4778b70af --- /dev/null +++ b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/tokenizer/Lookahead.java @@ -0,0 +1,130 @@ +/* + * 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.tokenizer; + + +import java.io.IOException; +import java.io.Reader; +import java.util.ArrayList; +import java.util.List; + + +/** + * Stream-like data structure that allows viewing future elements without consuming current. + */ +public class Lookahead { + private final List buffer = new ArrayList<>(); + private final Reader input; + private int index = 0; + private int line = 0; + private boolean end = false; + + public Lookahead(Reader r) { + this.input = r; + } + + /** + * Get the current character without consuming it. + * + * @return current character + */ + public Char current() { + return next(0); + } + + + /** + * Consume and return one character. + * + * @return Character that was consumed. + */ + public Char consume() { + Char consumed = current(); + consume(1); + return consumed; + } + + /** + * Fetch a future character without consuming it. + * + * @param ahead Distance ahead to peek + * + * @return Character + */ + public Char next(int ahead) { + if(ahead < 0) throw new IllegalArgumentException(); + + while(buffer.size() <= ahead && !end) { + Char item = fetch(); + if(item != null) { + buffer.add(item); + } else end = true; + } + + if(ahead >= buffer.size()) { + return null; + } else return buffer.get(ahead); + } + + /** + * Consume an amount of characters + * + * @param amount Number of characters to consume + */ + public void consume(int amount) { + if(amount < 0) throw new IllegalArgumentException(); + while(amount-- > 0) { + if(!buffer.isEmpty()) buffer.remove(0); // Remove top item from buffer. + else { + if(end) return; + Char item = fetch(); + if(item == null) end = true; + } + } + } + + public boolean matches(String check, boolean consume) { + if(check == null) return false; + + for(int i = 0; i < check.length(); i++) { + if(!next(i).is(check.charAt(i))) return false; + } + + if(consume) consume(check.length()); // Consume string + return true; + } + + /** + * Fetch the next character. + * + * @return Next character + */ + private Char fetch() { + try { + int c = input.read(); + if(c == -1) return null; + if(c == '\n') { + line++; + index = 0; + } + index++; + return new Char((char) c, line, index); + } catch(IOException e) { + e.printStackTrace(); + return null; + } + } + + public int getLine() { + return line; + } + + public int getIndex() { + return index; + } +} diff --git a/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/tokenizer/Position.java b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/tokenizer/Position.java new file mode 100644 index 000000000..9e5c7c675 --- /dev/null +++ b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/tokenizer/Position.java @@ -0,0 +1,23 @@ +/* + * 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.tokenizer; + +public class Position { + private final int line; + private final int index; + + public Position(int line, int index) { + this.line = line; + this.index = index; + } + + @Override + public String toString() { + return (line + 1) + ":" + index; + } +} diff --git a/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/tokenizer/Token.java b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/tokenizer/Token.java new file mode 100644 index 000000000..6ab278807 --- /dev/null +++ b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/tokenizer/Token.java @@ -0,0 +1,237 @@ +/* + * 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.tokenizer; + +public class Token { + private final String content; + private final Type type; + private final Position start; + + public Token(String content, Type type, Position start) { + this.content = content; + this.type = type; + this.start = start; + } + + @Override + public String toString() { + return type + ": '" + content + "'"; + } + + public Type getType() { + return type; + } + + public String getContent() { + return content; + } + + public Position getPosition() { + return start; + } + + public boolean isConstant() { + return this.type.equals(Type.NUMBER) || this.type.equals(Type.STRING) || this.type.equals(Type.BOOLEAN); + } + + public boolean isBinaryOperator() { + return type.equals(Type.ADDITION_OPERATOR) + || type.equals(Type.SUBTRACTION_OPERATOR) + || type.equals(Type.MULTIPLICATION_OPERATOR) + || type.equals(Type.DIVISION_OPERATOR) + || type.equals(Type.EQUALS_OPERATOR) + || type.equals(Type.NOT_EQUALS_OPERATOR) + || type.equals(Type.LESS_THAN_OPERATOR) + || type.equals(Type.GREATER_THAN_OPERATOR) + || type.equals(Type.LESS_THAN_OR_EQUALS_OPERATOR) + || type.equals(Type.GREATER_THAN_OR_EQUALS_OPERATOR) + || type.equals(Type.BOOLEAN_OR) + || type.equals(Type.BOOLEAN_AND) + || type.equals(Type.MODULO_OPERATOR); + } + + public boolean isStrictNumericOperator() { + return type.equals(Type.SUBTRACTION_OPERATOR) + || type.equals(Type.MULTIPLICATION_OPERATOR) + || type.equals(Type.DIVISION_OPERATOR) + || type.equals(Type.GREATER_THAN_OPERATOR) + || type.equals(Type.LESS_THAN_OPERATOR) + || type.equals(Type.LESS_THAN_OR_EQUALS_OPERATOR) + || type.equals(Type.GREATER_THAN_OR_EQUALS_OPERATOR) + || type.equals(Type.MODULO_OPERATOR); + } + + public boolean isStrictBooleanOperator() { + return type.equals(Type.BOOLEAN_AND) + || type.equals(Type.BOOLEAN_OR); + } + + public boolean isVariableDeclaration() { + return type.equals(Type.STRING_VARIABLE) + || type.equals(Type.BOOLEAN_VARIABLE) + || type.equals(Type.NUMBER_VARIABLE); + } + + public boolean isLoopLike() { + return type.equals(Type.IF_STATEMENT) + || type.equals(Type.WHILE_LOOP) + || type.equals(Type.FOR_LOOP); + } + + public boolean isIdentifier() { + return type.equals(Type.IDENTIFIER); + } + + public enum Type { + /** + * Function identifier or language keyword + */ + IDENTIFIER, + + /** + * Numeric literal + */ + NUMBER, + /** + * String literal + */ + STRING, + /** + * Boolean literal + */ + BOOLEAN, + /** + * Beginning of group + */ + GROUP_BEGIN, + /** + * Ending of group + */ + GROUP_END, + /** + * End of statement + */ + STATEMENT_END, + /** + * Argument separator + */ + SEPARATOR, + /** + * Beginning of code block + */ + BLOCK_BEGIN, + /** + * End of code block + */ + BLOCK_END, + /** + * assignment operator + */ + ASSIGNMENT, + /** + * Boolean equals operator + */ + EQUALS_OPERATOR, + /** + * Boolean not equals operator + */ + NOT_EQUALS_OPERATOR, + /** + * Boolean greater than operator + */ + GREATER_THAN_OPERATOR, + /** + * Boolean less than operator + */ + LESS_THAN_OPERATOR, + /** + * Boolean greater than or equal to operator + */ + GREATER_THAN_OR_EQUALS_OPERATOR, + /** + * Boolean less than or equal to operator + */ + LESS_THAN_OR_EQUALS_OPERATOR, + /** + * Addition/concatenation operator + */ + ADDITION_OPERATOR, + /** + * Subtraction operator + */ + SUBTRACTION_OPERATOR, + /** + * Multiplication operator + */ + MULTIPLICATION_OPERATOR, + /** + * Division operator + */ + DIVISION_OPERATOR, + /** + * Modulo operator. + */ + MODULO_OPERATOR, + /** + * Boolean not operator + */ + BOOLEAN_NOT, + /** + * Boolean or + */ + BOOLEAN_OR, + /** + * Boolean and + */ + BOOLEAN_AND, + /** + * Numeric variable declaration + */ + NUMBER_VARIABLE, + /** + * String variable declaration + */ + STRING_VARIABLE, + /** + * Boolean variable declaration + */ + BOOLEAN_VARIABLE, + /** + * If statement declaration + */ + IF_STATEMENT, + /** + * While loop declaration + */ + WHILE_LOOP, + /** + * Return statement + */ + RETURN, + /** + * Continue statement + */ + CONTINUE, + /** + * Break statement + */ + BREAK, + /** + * Fail statement. Like return keyword, but specifies that generation has failed. + */ + FAIL, + /** + * For loop initializer token + */ + FOR_LOOP, + /** + * Else keyword + */ + ELSE + } +} diff --git a/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/tokenizer/Tokenizer.java b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/tokenizer/Tokenizer.java new file mode 100644 index 000000000..16ede7b3a --- /dev/null +++ b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/tokenizer/Tokenizer.java @@ -0,0 +1,247 @@ +/* + * 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.tokenizer; + +import com.google.common.collect.Sets; + +import java.io.StringReader; +import java.util.Set; +import java.util.Stack; + +import com.dfsek.terra.addons.terrascript.parser.exceptions.ParseException; +import com.dfsek.terra.addons.terrascript.tokenizer.exceptions.EOFException; +import com.dfsek.terra.addons.terrascript.tokenizer.exceptions.FormatException; +import com.dfsek.terra.addons.terrascript.tokenizer.exceptions.TokenizerException; + + +public class Tokenizer { + public static final Set syntaxSignificant = Sets.newHashSet(';', '(', ')', '"', ',', '\\', '=', '{', '}', '+', '-', '*', '/', + '>', '<', '!'); // Reserved chars + private final Lookahead reader; + private final Stack brackets = new Stack<>(); + private Token current; + private Token last; + + public Tokenizer(String data) { + reader = new Lookahead(new StringReader(data + '\0')); + current = fetchCheck(); + } + + /** + * Get the first token. + * + * @return First token + * + * @throws ParseException If token does not exist + */ + public Token get() { + if(!hasNext()) throw new ParseException("Unexpected end of input", last.getPosition()); + return current; + } + + /** + * Consume (get and remove) the first token. + * + * @return First token + * + * @throws ParseException If token does not exist + */ + public Token consume() { + if(!hasNext()) throw new ParseException("Unexpected end of input", last.getPosition()); + Token temp = current; + current = fetchCheck(); + return temp; + } + + private Token fetchCheck() { + Token fetch = fetch(); + if(fetch != null) { + last = fetch; + if(fetch.getType() == Token.Type.BLOCK_BEGIN) brackets.push(fetch); // Opening bracket + else if(fetch.getType() == Token.Type.BLOCK_END) { + if(!brackets.isEmpty()) brackets.pop(); + else throw new ParseException("Dangling opening brace", new Position(0, 0)); + } + } else if(!brackets.isEmpty()) { + throw new ParseException("Dangling closing brace", brackets.peek().getPosition()); + } + return fetch; + } + + private Token fetch() throws TokenizerException { + while(!reader.current().isEOF() && reader.current().isWhitespace()) reader.consume(); + + while(reader.matches("//", true)) skipLine(); // Skip line if comment + + if(reader.matches("/*", true)) skipTo("*/"); // Skip multi line comment + + if(reader.current().isEOF()) return null; // EOF + + if(reader.matches("==", true)) + return new Token("==", Token.Type.EQUALS_OPERATOR, new Position(reader.getLine(), reader.getIndex())); + if(reader.matches("!=", true)) + return new Token("!=", Token.Type.NOT_EQUALS_OPERATOR, new Position(reader.getLine(), reader.getIndex())); + if(reader.matches(">=", true)) + return new Token(">=", Token.Type.GREATER_THAN_OR_EQUALS_OPERATOR, new Position(reader.getLine(), reader.getIndex())); + if(reader.matches("<=", true)) + return new Token("<=", Token.Type.LESS_THAN_OR_EQUALS_OPERATOR, new Position(reader.getLine(), reader.getIndex())); + if(reader.matches(">", true)) + return new Token(">", Token.Type.GREATER_THAN_OPERATOR, new Position(reader.getLine(), reader.getIndex())); + if(reader.matches("<", true)) + return new Token("<", Token.Type.LESS_THAN_OPERATOR, new Position(reader.getLine(), reader.getIndex())); + + + if(reader.matches("||", true)) + return new Token("||", Token.Type.BOOLEAN_OR, new Position(reader.getLine(), reader.getIndex())); + if(reader.matches("&&", true)) + return new Token("&&", Token.Type.BOOLEAN_AND, new Position(reader.getLine(), reader.getIndex())); + + + if(isNumberStart()) { + StringBuilder num = new StringBuilder(); + while(!reader.current().isEOF() && isNumberLike()) { + num.append(reader.consume()); + } + return new Token(num.toString(), Token.Type.NUMBER, new Position(reader.getLine(), reader.getIndex())); + } + + if(reader.current().is('"')) { + reader.consume(); // Consume first quote + StringBuilder string = new StringBuilder(); + boolean ignoreNext = false; + while((!reader.current().is('"')) || ignoreNext) { + if(reader.current().is('\\') && !ignoreNext) { + ignoreNext = true; + reader.consume(); + continue; + } else ignoreNext = false; + if(reader.current().isEOF()) + throw new FormatException("No end of string literal found. ", new Position(reader.getLine(), reader.getIndex())); + string.append(reader.consume()); + } + reader.consume(); // Consume last quote + + return new Token(string.toString(), Token.Type.STRING, new Position(reader.getLine(), reader.getIndex())); + } + + if(reader.current().is('(')) + return new Token(reader.consume().toString(), Token.Type.GROUP_BEGIN, new Position(reader.getLine(), reader.getIndex())); + if(reader.current().is(')')) + return new Token(reader.consume().toString(), Token.Type.GROUP_END, new Position(reader.getLine(), reader.getIndex())); + if(reader.current().is(';')) + return new Token(reader.consume().toString(), Token.Type.STATEMENT_END, new Position(reader.getLine(), reader.getIndex())); + if(reader.current().is(',')) + return new Token(reader.consume().toString(), Token.Type.SEPARATOR, new Position(reader.getLine(), reader.getIndex())); + if(reader.current().is('{')) + return new Token(reader.consume().toString(), Token.Type.BLOCK_BEGIN, new Position(reader.getLine(), reader.getIndex())); + if(reader.current().is('}')) + return new Token(reader.consume().toString(), Token.Type.BLOCK_END, new Position(reader.getLine(), reader.getIndex())); + if(reader.current().is('=')) + return new Token(reader.consume().toString(), Token.Type.ASSIGNMENT, new Position(reader.getLine(), reader.getIndex())); + if(reader.current().is('+')) + return new Token(reader.consume().toString(), Token.Type.ADDITION_OPERATOR, new Position(reader.getLine(), reader.getIndex())); + if(reader.current().is('-')) + return new Token(reader.consume().toString(), Token.Type.SUBTRACTION_OPERATOR, + new Position(reader.getLine(), reader.getIndex())); + if(reader.current().is('*')) + return new Token(reader.consume().toString(), Token.Type.MULTIPLICATION_OPERATOR, + new Position(reader.getLine(), reader.getIndex())); + if(reader.current().is('/')) + return new Token(reader.consume().toString(), Token.Type.DIVISION_OPERATOR, new Position(reader.getLine(), reader.getIndex())); + if(reader.current().is('%')) + return new Token(reader.consume().toString(), Token.Type.MODULO_OPERATOR, new Position(reader.getLine(), reader.getIndex())); + if(reader.current().is('!')) + return new Token(reader.consume().toString(), Token.Type.BOOLEAN_NOT, new Position(reader.getLine(), reader.getIndex())); + + StringBuilder token = new StringBuilder(); + while(!reader.current().isEOF() && !isSyntaxSignificant(reader.current().getCharacter())) { + Char c = reader.consume(); + if(c.isWhitespace()) break; + token.append(c); + } + + String tokenString = token.toString(); + + if(tokenString.equals("true")) + return new Token(tokenString, Token.Type.BOOLEAN, new Position(reader.getLine(), reader.getIndex())); + if(tokenString.equals("false")) + return new Token(tokenString, Token.Type.BOOLEAN, new Position(reader.getLine(), reader.getIndex())); + + if(tokenString.equals("num")) + return new Token(tokenString, Token.Type.NUMBER_VARIABLE, new Position(reader.getLine(), reader.getIndex())); + if(tokenString.equals("str")) + return new Token(tokenString, Token.Type.STRING_VARIABLE, new Position(reader.getLine(), reader.getIndex())); + if(tokenString.equals("bool")) + return new Token(tokenString, Token.Type.BOOLEAN_VARIABLE, new Position(reader.getLine(), reader.getIndex())); + + if(tokenString.equals("if")) + return new Token(tokenString, Token.Type.IF_STATEMENT, new Position(reader.getLine(), reader.getIndex())); + if(tokenString.equals("else")) + return new Token(tokenString, Token.Type.ELSE, new Position(reader.getLine(), reader.getIndex())); + if(tokenString.equals("while")) + return new Token(tokenString, Token.Type.WHILE_LOOP, new Position(reader.getLine(), reader.getIndex())); + if(tokenString.equals("for")) + return new Token(tokenString, Token.Type.FOR_LOOP, new Position(reader.getLine(), reader.getIndex())); + + if(tokenString.equals("return")) + return new Token(tokenString, Token.Type.RETURN, new Position(reader.getLine(), reader.getIndex())); + if(tokenString.equals("continue")) + return new Token(tokenString, Token.Type.CONTINUE, new Position(reader.getLine(), reader.getIndex())); + if(tokenString.equals("break")) + return new Token(tokenString, Token.Type.BREAK, new Position(reader.getLine(), reader.getIndex())); + if(tokenString.equals("fail")) + return new Token(tokenString, Token.Type.FAIL, new Position(reader.getLine(), reader.getIndex())); + + return new Token(tokenString, Token.Type.IDENTIFIER, new Position(reader.getLine(), reader.getIndex())); + } + + private void skipLine() { + while(!reader.current().isEOF() && !reader.current().isNewLine()) reader.consume(); + consumeWhitespace(); + } + + private void consumeWhitespace() { + while(!reader.current().isEOF() && reader.current().isWhitespace()) reader.consume(); // Consume whitespace. + } + + private void skipTo(String s) throws EOFException { + Position begin = new Position(reader.getLine(), reader.getIndex()); + while(!reader.current().isEOF()) { + if(reader.matches(s, true)) { + consumeWhitespace(); + return; + } + reader.consume(); + } + throw new EOFException("No end of expression found.", begin); + } + + /** + * Whether this {@code Tokenizer} contains additional tokens. + * + * @return {@code true} if more tokens are present, otherwise {@code false} + */ + public boolean hasNext() { + return !(current == null); + } + + private boolean isNumberLike() { + return reader.current().isDigit() + || reader.current().is('_', '.', 'E'); + } + + private boolean isNumberStart() { + return reader.current().isDigit() + || reader.current().is('.') && reader.next(1).isDigit(); + } + + public boolean isSyntaxSignificant(char c) { + return syntaxSignificant.contains(c); + } + +} diff --git a/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/tokenizer/exceptions/EOFException.java b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/tokenizer/exceptions/EOFException.java new file mode 100644 index 000000000..bd9097946 --- /dev/null +++ b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/tokenizer/exceptions/EOFException.java @@ -0,0 +1,27 @@ +/* + * 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.tokenizer.exceptions; + +import java.io.Serial; + +import com.dfsek.terra.addons.terrascript.tokenizer.Position; + + +public class EOFException extends TokenizerException { + + @Serial + private static final long serialVersionUID = 3980047409902809440L; + + public EOFException(String message, Position position) { + super(message, position); + } + + public EOFException(String message, Position position, Throwable cause) { + super(message, position, cause); + } +} diff --git a/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/tokenizer/exceptions/FormatException.java b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/tokenizer/exceptions/FormatException.java new file mode 100644 index 000000000..067b49b70 --- /dev/null +++ b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/tokenizer/exceptions/FormatException.java @@ -0,0 +1,27 @@ +/* + * 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.tokenizer.exceptions; + +import java.io.Serial; + +import com.dfsek.terra.addons.terrascript.tokenizer.Position; + + +public class FormatException extends TokenizerException { + + @Serial + private static final long serialVersionUID = -791308012940744455L; + + public FormatException(String message, Position position) { + super(message, position); + } + + public FormatException(String message, Position position, Throwable cause) { + super(message, position, cause); + } +} diff --git a/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/tokenizer/exceptions/TokenizerException.java b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/tokenizer/exceptions/TokenizerException.java new file mode 100644 index 000000000..079f17226 --- /dev/null +++ b/common/addons/structure-terrascript-loader-v1/src/main/java/com/dfsek/terra/addons/terrascript/tokenizer/exceptions/TokenizerException.java @@ -0,0 +1,28 @@ +/* + * 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.tokenizer.exceptions; + +import java.io.Serial; + +import com.dfsek.terra.addons.terrascript.parser.exceptions.ParseException; +import com.dfsek.terra.addons.terrascript.tokenizer.Position; + + +public abstract class TokenizerException extends ParseException { + + @Serial + private static final long serialVersionUID = 2792384010083575420L; + + public TokenizerException(String message, Position position) { + super(message, position); + } + + public TokenizerException(String message, Position position, Throwable cause) { + super(message, position, cause); + } +} diff --git a/common/addons/structure-terrascript-loader-v1/src/main/resources/terra.addon.yml b/common/addons/structure-terrascript-loader-v1/src/main/resources/terra.addon.yml new file mode 100644 index 000000000..0850687c9 --- /dev/null +++ b/common/addons/structure-terrascript-loader-v1/src/main/resources/terra.addon.yml @@ -0,0 +1,12 @@ +schema-version: 1 +contributors: + - Terra contributors +id: structure-terrascript-loader +version: @VERSION@ +entrypoints: + - "com.dfsek.terra.addons.terrascript.TerraScriptAddon" +website: + issues: https://github.com/PolyhedralDev/Terra/issues + source: https://github.com/PolyhedralDev/Terra + docs: https://terra.polydev.org +license: MIT License \ No newline at end of file diff --git a/common/addons/structure-terrascript-loader-v1/src/test/java/structure/LookaheadTest.java b/common/addons/structure-terrascript-loader-v1/src/test/java/structure/LookaheadTest.java new file mode 100644 index 000000000..e428f67cf --- /dev/null +++ b/common/addons/structure-terrascript-loader-v1/src/test/java/structure/LookaheadTest.java @@ -0,0 +1,29 @@ +/* + * 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 structure; + +import org.junit.jupiter.api.Test; + +import java.io.StringReader; + +import com.dfsek.terra.addons.terrascript.tokenizer.Lookahead; + + +public class LookaheadTest { + @Test + public void lookahead() { + Lookahead lookahead = new Lookahead(new StringReader("Test string...")); + + for(int i = 0; lookahead.next(i) != null; i++) { + System.out.print(lookahead.next(i).getCharacter()); + } + while(lookahead.next(0) != null) { + System.out.print(lookahead.consume().getCharacter()); + } + } +} diff --git a/common/addons/structure-terrascript-loader-v1/src/test/java/structure/ParserTest.java b/common/addons/structure-terrascript-loader-v1/src/test/java/structure/ParserTest.java new file mode 100644 index 000000000..fc0fcf532 --- /dev/null +++ b/common/addons/structure-terrascript-loader-v1/src/test/java/structure/ParserTest.java @@ -0,0 +1,96 @@ +/* + * 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 structure; + + +import org.apache.commons.io.IOUtils; +import org.junit.jupiter.api.Test; + +import java.io.IOException; +import java.nio.charset.Charset; +import java.util.List; +import java.util.Objects; + +import com.dfsek.terra.addons.terrascript.parser.Parser; +import com.dfsek.terra.addons.terrascript.parser.exceptions.ParseException; +import com.dfsek.terra.addons.terrascript.parser.lang.Executable; +import com.dfsek.terra.addons.terrascript.parser.lang.ImplementationArguments; +import com.dfsek.terra.addons.terrascript.parser.lang.Returnable; +import com.dfsek.terra.addons.terrascript.parser.lang.Scope; +import com.dfsek.terra.addons.terrascript.parser.lang.functions.Function; +import com.dfsek.terra.addons.terrascript.parser.lang.functions.FunctionBuilder; +import com.dfsek.terra.addons.terrascript.tokenizer.Position; + + +public class ParserTest { + @Test + public void parse() throws IOException, ParseException { + Parser parser = new Parser( + IOUtils.toString(Objects.requireNonNull(getClass().getResourceAsStream("/test.tesf")), Charset.defaultCharset())); + + parser.registerFunction("test", new FunctionBuilder() { + @Override + public Test1 build(List> argumentList, Position position) { + return new Test1(argumentList.get(0), argumentList.get(1), position); + } + + @Override + public int argNumber() { + return 2; + } + + @Override + public Returnable.ReturnType getArgument(int position) { + return switch(position) { + case 0 -> Returnable.ReturnType.STRING; + case 1 -> Returnable.ReturnType.NUMBER; + default -> null; + }; + } + + }); + + long l = System.nanoTime(); + Executable block = parser.parse(); + long t = System.nanoTime() - l; + System.out.println("Took " + (double) t / 1000000); + + block.execute(null); + + block.execute(null); + } + + private static class Test1 implements Function { + private final Returnable a; + private final Returnable b; + private final Position position; + + public Test1(Returnable a, Returnable b, Position position) { + this.a = a; + this.b = b; + this.position = position; + } + + @Override + public Void apply(ImplementationArguments implementationArguments, Scope scope) { + System.out.println("string: " + a.apply(implementationArguments, scope) + ", double: " + + b.apply(implementationArguments, scope)); + return null; + } + + @Override + public Position getPosition() { + return position; + } + + @Override + public ReturnType returnType() { + return ReturnType.VOID; + } + } +} diff --git a/common/addons/structure-terrascript-loader-v1/src/test/resources/test.tesf b/common/addons/structure-terrascript-loader-v1/src/test/resources/test.tesf new file mode 100644 index 000000000..8bcce7177 --- /dev/null +++ b/common/addons/structure-terrascript-loader-v1/src/test/resources/test.tesf @@ -0,0 +1,97 @@ +bool thing1 = 2 > (2+2) || false; + +if(2 > 2 || 3 + 4 <= 2 && 4 + 5 > 2 / 3) { + test("ok", 2); +} + +test("minecraft:green_w" + "ool", (2 * (3+1) * (2 * (1+1)))); +// + +num testVar = 3.4; +bool boolean = true; +str stringVar = "hello!"; + +num precedence = 3 + 2 * 2 + 3; +test("precedence: " + precedence, 2); +num precedence2 = 3 * 2 + 2 * 3; +test("precedence 2: " + precedence2, 2); + +bool iftest = false; + +bool truetest = false; + +num iterator = 0; +num thing = 4 - 2-2+2-2+2; +test("4 - 2 = " + thing, 2); + +thing = -2; +test("-2 = " + thing, 2); +thing = -thing; +test("--2 = " + thing, 2); + + + +for(num i = 0; i < 5; i = i + 1) { + test("i = " + i, iterator); + if(i > 1 + 1) { + test("more than 2", iterator); + continue; + } +} + +for(num i = 0; i < 5; i = i + 1) { + test("i = " + i, iterator); +} + +for(num j = 0; j < 5; j = j + 1) test("single statement j = " + j, iterator); + +if(4 + 2 == 2 + 4) { + test("new thing " + 2, iterator); +} + +while(iterator < 5) { + test("always, even after " + 2, iterator); + iterator = iterator + 1; + if(iterator > 2) { + continue; + } + test("not after " + 2, iterator); +} + +if(true) test("single statement" + 2, iterator); +else if(true) test("another single statement" + 2, iterator); + +if(true) { + test("true!" + 2, iterator); +} else { + test("false!" + 2, iterator); + } + +if(false) { + test("true!" + 2, iterator); +} else { + test("false!" + 2, iterator); +} + +if(false) { + test("true again!" + 2, iterator); +} else if(true == true) { + test("false again!" + 2, iterator); +} else { + test("not logged!" + 2, iterator); +} + + + +// comment + +/* +fsdfsd +*/ + +test("fdsgdf" + 2, 1 + testVar); + +if(true && !(boolean && false) && true) { + num scopedVar = 2; + test("if statement" + 2 + stringVar, 1 + testVar + scopedVar); +} \ No newline at end of file