diff --git a/.gitattributes b/.gitattributes index 94f480d..0161913 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1 +1,3 @@ -* text=auto eol=lf \ No newline at end of file +* text=auto eol=lf +*.bat text eol=crlf +*.jar binary \ No newline at end of file diff --git a/build.gradle b/build.gradle index 507ee76..9f43df2 100644 --- a/build.gradle +++ b/build.gradle @@ -1,93 +1,135 @@ plugins { - id "org.jetbrains.kotlin.jvm" version "2.4.0" + id "org.jetbrains.kotlin.jvm" version "2.4.0" apply false id "java-library" id "maven-publish" id("net.neoforged.licenser") version "0.7.5" id("me.champeau.jmh") version "0.7.3" } -repositories { - mavenCentral() - maven { - url = uri("https://repo.redlance.org/public") // mirroring https://maven.pkg.github.com/bedrockk/MoLang +allprojects { + group = rootProject.group + version = rootProject.version + + repositories { + mavenCentral() + maven { + url = uri("https://repo.redlance.org/public") // mirroring https://maven.pkg.github.com/bedrockk/MoLang + } + maven { url = "https://maven.blamejared.com/" } // moonflower's molang-compiler } - maven { url = "https://maven.blamejared.com/"} // moonflower's molang-compiler } -dependencies { - implementation api("io.netty:netty-buffer:4.2.15.Final") - compileOnlyApi("org.jetbrains:annotations:26.1.0") +subprojects { + apply plugin: "java-library" + apply plugin: "maven-publish" + apply plugin: "net.neoforged.licenser" - // tests - testImplementation("org.junit.jupiter:junit-jupiter-api:6.1.1") - testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:6.1.1") - testRuntimeOnly("org.junit.platform:junit-platform-launcher:6.1.1") - testImplementation("org.jetbrains.kotlin:kotlin-stdlib:2.4.0") + dependencies { + compileOnlyApi("org.jetbrains:annotations:26.1.0") + compileOnlyApi("com.google.j2objc:j2objc-annotations:3.1") - // performance comparison with other libraries - jmhImplementation("com.bedrockk:molang:1.0-SNAPSHOT") - jmhImplementation("gg.moonflower:molang-compiler:3.1.1.19") -} - -tasks.register('generateExpectations', Exec) { - def nvmDir = file("${System.getenv('HOME')}/.nvm/versions/node") - executable nvmDir.isDirectory() ? "${nvmDir.listFiles().sort().last()}/bin/node" : 'node' - args 'scripts/generate_expectations.js' -} + testImplementation("org.junit.jupiter:junit-jupiter-api:6.1.1") + testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:6.1.1") + testRuntimeOnly("org.junit.platform:junit-platform-launcher:6.1.1") + } -tasks { - test { + tasks.named("test") { useJUnitPlatform() - dependsOn tasks.generateExpectations } - compileJmhJava { - sourceCompatibility = "24" - targetCompatibility = "24" - } - compileJava { + + tasks.named("compileJava") { sourceCompatibility = "24" targetCompatibility = "24" } - javadoc { + + tasks.named("javadoc") { failOnError = false } - compileKotlin { - enabled = false + + java { + withJavadocJar() + withSourcesJar() } -} -license { - header.set(rootProject.resources.text.fromFile("header.txt")) - include("**/*.java") - newLine = false -} + jar { + manifest.attributes("FMLModType": "GAMELIBRARY") + } -java { - withJavadocJar() - withSourcesJar() -} + license { + header.set(rootProject.resources.text.fromFile("header.txt")) + include("**/*.java") + newLine = false + } -jar { - manifest.attributes("FMLModType": "GAMELIBRARY") -} + publishing { + repositories { + maven { + name = "RedlanceMinecraft" + url = "https://repo.redlance.org/public" + credentials { + username = "dima_dencep" + password = System.getenv("MAVEN_PASSWORD") + } + } + } + publications { + maven(MavenPublication) { + groupId = "org.redlance.mochafloats" + artifactId = project.name + version = project.version -publishing { - repositories { - maven { - name = "RedlanceMinecraft" - url = "https://repo.redlance.org/public" - credentials { - username = "dima_dencep" - password = System.getenv("MAVEN_PASSWORD") + pom { + name = "MochaFloats ${project.name}" + description = "A lightweight, fast and efficient Molang lexer, parser, interpreter and compiler" + url = "https://github.com/PlayerAnimationLibrary/mochafloats" + + developers { + developer { + id = "dima_dencep" + name = "dima_dencep" + email = "dima_dencep@redlance.org" + } + developer { + id = "zigythebird" + name = "ZigyTheBird" + email = "imanyarandi222@gmail.com" + } + } + + licenses { + license { + name = "MIT" + url = "https://github.com/PlayerAnimationLibrary/mochafloats/blob/HEAD/license.txt" + } + } + + scm { + connection = "scm:git:github.com/PlayerAnimationLibrary/mochafloats.git" + developerConnection = "scm:git:github.com/PlayerAnimationLibrary/mochafloats.git" + url = "https://github.com/PlayerAnimationLibrary/mochafloats.git" + } + } + + from components.java } } } - publications { - maven(MavenPublication) { - groupId = "com.zigythebird" - artifactId = "mochafloats" - version = project.version - from components.java - } +} + +dependencies { + api project(":lexer") + api project(":parser") + api project(":runtime") + api project(":runtime-compiler") + + // performance comparison with other libraries + jmhImplementation("com.bedrockk:molang:1.0-SNAPSHOT") + jmhImplementation("gg.moonflower:molang-compiler:3.1.1.19") +} + +tasks { + compileJmhJava { + sourceCompatibility = "24" + targetCompatibility = "24" } -} \ No newline at end of file +} diff --git a/gradle.properties b/gradle.properties index cd68e05..fb6a72c 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ group=team.unnamed -version=5.0.0 +version=1.0.0 description=A lightweight, fast and efficient Molang lexer, parser, interpreter and compiler for Java 24+ kotlin.stdlib.default.dependency=false \ No newline at end of file diff --git a/gradlew.bat b/gradlew.bat index 8508ef6..a51ec4f 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -1,82 +1,82 @@ -@rem -@rem Copyright 2015 the original author or authors. -@rem -@rem Licensed under the Apache License, Version 2.0 (the "License"); -@rem you may not use this file except in compliance with the License. -@rem You may obtain a copy of the License at -@rem -@rem https://www.apache.org/licenses/LICENSE-2.0 -@rem -@rem Unless required by applicable law or agreed to in writing, software -@rem distributed under the License is distributed on an "AS IS" BASIS, -@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -@rem See the License for the specific language governing permissions and -@rem limitations under the License. -@rem -@rem SPDX-License-Identifier: Apache-2.0 -@rem - -@if "%DEBUG%"=="" @echo off -@rem ########################################################################## -@rem -@rem gradlew startup script for Windows -@rem -@rem ########################################################################## - -@rem Set local scope for the variables, and ensure extensions are enabled -setlocal EnableExtensions - -set DIRNAME=%~dp0 -if "%DIRNAME%"=="" set DIRNAME=. -@rem This is normally unused -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@rem Resolve any "." and ".." in APP_HOME to make it shorter. -for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi - -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" - -@rem Find java.exe -if defined JAVA_HOME goto findJavaFromJavaHome - -set JAVA_EXE=java.exe -%JAVA_EXE% -version >NUL 2>&1 -if %ERRORLEVEL% equ 0 goto execute - -echo. 1>&2 -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 -echo. 1>&2 -echo Please set the JAVA_HOME variable in your environment to match the 1>&2 -echo location of your Java installation. 1>&2 - -"%COMSPEC%" /c exit 1 - -:findJavaFromJavaHome -set JAVA_HOME=%JAVA_HOME:"=% -set JAVA_EXE=%JAVA_HOME%/bin/java.exe - -if exist "%JAVA_EXE%" goto execute - -echo. 1>&2 -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 -echo. 1>&2 -echo Please set the JAVA_HOME variable in your environment to match the 1>&2 -echo location of your Java installation. 1>&2 - -"%COMSPEC%" /c exit 1 - -:execute -@rem Setup the command line - - - -@rem Execute gradlew -@rem endlocal doesn't take effect until after the line is parsed and variables are expanded -@rem which allows us to clear the local environment before executing the java command -endlocal & "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* & call :exitWithErrorLevel - -:exitWithErrorLevel -@rem Use "%COMSPEC%" /c exit to allow operators to work properly in scripts -"%COMSPEC%" /c exit %ERRORLEVEL% +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem +@rem SPDX-License-Identifier: Apache-2.0 +@rem + +@if "%DEBUG%"=="" @echo off +@rem ########################################################################## +@rem +@rem gradlew startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables, and ensure extensions are enabled +setlocal EnableExtensions + +set DIRNAME=%~dp0 +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if %ERRORLEVEL% equ 0 goto execute + +echo. 1>&2 +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 + +"%COMSPEC%" /c exit 1 + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. 1>&2 +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 + +"%COMSPEC%" /c exit 1 + +:execute +@rem Setup the command line + + + +@rem Execute gradlew +@rem endlocal doesn't take effect until after the line is parsed and variables are expanded +@rem which allows us to clear the local environment before executing the java command +endlocal & "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* & call :exitWithErrorLevel + +:exitWithErrorLevel +@rem Use "%COMSPEC%" /c exit to allow operators to work properly in scripts +"%COMSPEC%" /c exit %ERRORLEVEL% diff --git a/lexer/build.gradle b/lexer/build.gradle new file mode 100644 index 0000000..87806a2 --- /dev/null +++ b/lexer/build.gradle @@ -0,0 +1 @@ +// no internal dependencies diff --git a/src/main/java/team/unnamed/mocha/lexer/Characters.java b/lexer/src/main/java/org/redlance/mocha/lexer/Characters.java similarity index 96% rename from src/main/java/team/unnamed/mocha/lexer/Characters.java rename to lexer/src/main/java/org/redlance/mocha/lexer/Characters.java index d7cff56..ce0115e 100644 --- a/src/main/java/team/unnamed/mocha/lexer/Characters.java +++ b/lexer/src/main/java/org/redlance/mocha/lexer/Characters.java @@ -1,27 +1,27 @@ -/* - * This file is part of mocha, licensed under the MIT license - * - * Copyright (c) 2021-2025 Unnamed Team - * - * 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. - */ -package team.unnamed.mocha.lexer; +/* + * This file is part of mocha, licensed under the MIT license + * + * Copyright (c) 2021-2025 Unnamed Team + * + * 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. + */ +package org.redlance.mocha.lexer; import org.jetbrains.annotations.ApiStatus; diff --git a/src/main/java/team/unnamed/mocha/lexer/Cursor.java b/lexer/src/main/java/org/redlance/mocha/lexer/Cursor.java similarity index 97% rename from src/main/java/team/unnamed/mocha/lexer/Cursor.java rename to lexer/src/main/java/org/redlance/mocha/lexer/Cursor.java index 2b6948e..7f7684f 100644 --- a/src/main/java/team/unnamed/mocha/lexer/Cursor.java +++ b/lexer/src/main/java/org/redlance/mocha/lexer/Cursor.java @@ -1,27 +1,27 @@ -/* - * This file is part of mocha, licensed under the MIT license - * - * Copyright (c) 2021-2025 Unnamed Team - * - * 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. - */ -package team.unnamed.mocha.lexer; +/* + * This file is part of mocha, licensed under the MIT license + * + * Copyright (c) 2021-2025 Unnamed Team + * + * 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. + */ +package org.redlance.mocha.lexer; import org.jetbrains.annotations.NotNull; diff --git a/src/main/java/team/unnamed/mocha/lexer/MolangLexer.java b/lexer/src/main/java/org/redlance/mocha/lexer/MolangLexer.java similarity index 99% rename from src/main/java/team/unnamed/mocha/lexer/MolangLexer.java rename to lexer/src/main/java/org/redlance/mocha/lexer/MolangLexer.java index c9dc0d3..31b91cf 100644 --- a/src/main/java/team/unnamed/mocha/lexer/MolangLexer.java +++ b/lexer/src/main/java/org/redlance/mocha/lexer/MolangLexer.java @@ -1,27 +1,27 @@ -/* - * This file is part of mocha, licensed under the MIT license - * - * Copyright (c) 2021-2025 Unnamed Team - * - * 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. - */ -package team.unnamed.mocha.lexer; +/* + * This file is part of mocha, licensed under the MIT license + * + * Copyright (c) 2021-2025 Unnamed Team + * + * 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. + */ +package org.redlance.mocha.lexer; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; diff --git a/src/main/java/team/unnamed/mocha/lexer/MolangLexerImpl.java b/lexer/src/main/java/org/redlance/mocha/lexer/MolangLexerImpl.java similarity index 99% rename from src/main/java/team/unnamed/mocha/lexer/MolangLexerImpl.java rename to lexer/src/main/java/org/redlance/mocha/lexer/MolangLexerImpl.java index c974a46..575ecd1 100644 --- a/src/main/java/team/unnamed/mocha/lexer/MolangLexerImpl.java +++ b/lexer/src/main/java/org/redlance/mocha/lexer/MolangLexerImpl.java @@ -1,27 +1,27 @@ -/* - * This file is part of mocha, licensed under the MIT license - * - * Copyright (c) 2021-2025 Unnamed Team - * - * 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. - */ -package team.unnamed.mocha.lexer; +/* + * This file is part of mocha, licensed under the MIT license + * + * Copyright (c) 2021-2025 Unnamed Team + * + * 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. + */ +package org.redlance.mocha.lexer; import org.jetbrains.annotations.NotNull; diff --git a/src/main/java/team/unnamed/mocha/lexer/Token.java b/lexer/src/main/java/org/redlance/mocha/lexer/Token.java similarity index 98% rename from src/main/java/team/unnamed/mocha/lexer/Token.java rename to lexer/src/main/java/org/redlance/mocha/lexer/Token.java index a1153d1..3efe666 100644 --- a/src/main/java/team/unnamed/mocha/lexer/Token.java +++ b/lexer/src/main/java/org/redlance/mocha/lexer/Token.java @@ -1,27 +1,27 @@ -/* - * This file is part of mocha, licensed under the MIT license - * - * Copyright (c) 2021-2025 Unnamed Team - * - * 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. - */ -package team.unnamed.mocha.lexer; +/* + * This file is part of mocha, licensed under the MIT license + * + * Copyright (c) 2021-2025 Unnamed Team + * + * 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. + */ +package org.redlance.mocha.lexer; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; diff --git a/src/main/java/team/unnamed/mocha/lexer/TokenKind.java b/lexer/src/main/java/org/redlance/mocha/lexer/TokenKind.java similarity index 98% rename from src/main/java/team/unnamed/mocha/lexer/TokenKind.java rename to lexer/src/main/java/org/redlance/mocha/lexer/TokenKind.java index 9e5c3cf..62a8735 100644 --- a/src/main/java/team/unnamed/mocha/lexer/TokenKind.java +++ b/lexer/src/main/java/org/redlance/mocha/lexer/TokenKind.java @@ -1,27 +1,27 @@ -/* - * This file is part of mocha, licensed under the MIT license - * - * Copyright (c) 2021-2025 Unnamed Team - * - * 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. - */ -package team.unnamed.mocha.lexer; +/* + * This file is part of mocha, licensed under the MIT license + * + * Copyright (c) 2021-2025 Unnamed Team + * + * 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. + */ +package org.redlance.mocha.lexer; import org.jetbrains.annotations.NotNull; diff --git a/src/main/java/team/unnamed/mocha/lexer/package-info.java b/lexer/src/main/java/org/redlance/mocha/lexer/package-info.java similarity index 91% rename from src/main/java/team/unnamed/mocha/lexer/package-info.java rename to lexer/src/main/java/org/redlance/mocha/lexer/package-info.java index b59988d..16ff1b0 100644 --- a/src/main/java/team/unnamed/mocha/lexer/package-info.java +++ b/lexer/src/main/java/org/redlance/mocha/lexer/package-info.java @@ -1,27 +1,27 @@ -/* - * This file is part of mocha, licensed under the MIT license - * - * Copyright (c) 2021-2025 Unnamed Team - * - * 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. - */ -/** +/* + * This file is part of mocha, licensed under the MIT license + * + * Copyright (c) 2021-2025 Unnamed Team + * + * 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. + */ +/** * Package containing classes related to lexicographical * analysis of Molang code. * @@ -31,4 +31,7 @@ * * @since 3.0.0 */ -package team.unnamed.mocha.lexer; \ No newline at end of file +@ReflectionSupport(ReflectionSupport.Level.NATIVE_ONLY) +package org.redlance.mocha.lexer; + +import com.google.j2objc.annotations.ReflectionSupport; \ No newline at end of file diff --git a/src/test/java/team/unnamed/mocha/lexer/LexerTest.java b/lexer/src/test/java/org/redlance/mocha/lexer/LexerTest.java similarity index 98% rename from src/test/java/team/unnamed/mocha/lexer/LexerTest.java rename to lexer/src/test/java/org/redlance/mocha/lexer/LexerTest.java index f115409..5066015 100644 --- a/src/test/java/team/unnamed/mocha/lexer/LexerTest.java +++ b/lexer/src/test/java/org/redlance/mocha/lexer/LexerTest.java @@ -1,27 +1,27 @@ -/* - * This file is part of mocha, licensed under the MIT license - * - * Copyright (c) 2021-2025 Unnamed Team - * - * 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. - */ -package team.unnamed.mocha.lexer; +/* + * This file is part of mocha, licensed under the MIT license + * + * Copyright (c) 2021-2025 Unnamed Team + * + * 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. + */ +package org.redlance.mocha.lexer; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -31,7 +31,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.fail; -import static team.unnamed.mocha.lexer.TokenKind.*; +import static org.redlance.mocha.lexer.TokenKind.*; public class LexerTest { diff --git a/parser/build.gradle b/parser/build.gradle new file mode 100644 index 0000000..ec30b60 --- /dev/null +++ b/parser/build.gradle @@ -0,0 +1,4 @@ +dependencies { + api project(":lexer") + api "io.netty:netty-buffer:4.2.15.Final" +} diff --git a/src/main/java/team/unnamed/mocha/parser/MolangParser.java b/parser/src/main/java/org/redlance/mocha/parser/MolangParser.java similarity index 96% rename from src/main/java/team/unnamed/mocha/parser/MolangParser.java rename to parser/src/main/java/org/redlance/mocha/parser/MolangParser.java index 81f1108..3fee7ab 100644 --- a/src/main/java/team/unnamed/mocha/parser/MolangParser.java +++ b/parser/src/main/java/org/redlance/mocha/parser/MolangParser.java @@ -1,34 +1,34 @@ -/* - * This file is part of mocha, licensed under the MIT license - * - * Copyright (c) 2021-2025 Unnamed Team - * - * 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. - */ -package team.unnamed.mocha.parser; +/* + * This file is part of mocha, licensed under the MIT license + * + * Copyright (c) 2021-2025 Unnamed Team + * + * 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. + */ +package org.redlance.mocha.parser; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import team.unnamed.mocha.lexer.Cursor; -import team.unnamed.mocha.lexer.MolangLexer; -import team.unnamed.mocha.lexer.TokenKind; -import team.unnamed.mocha.parser.ast.Expression; +import org.redlance.mocha.lexer.Cursor; +import org.redlance.mocha.lexer.MolangLexer; +import org.redlance.mocha.lexer.TokenKind; +import org.redlance.mocha.parser.ast.Expression; import java.io.Closeable; import java.io.IOException; diff --git a/src/main/java/team/unnamed/mocha/parser/MolangParserImpl.java b/parser/src/main/java/org/redlance/mocha/parser/MolangParserImpl.java similarity index 98% rename from src/main/java/team/unnamed/mocha/parser/MolangParserImpl.java rename to parser/src/main/java/org/redlance/mocha/parser/MolangParserImpl.java index 495d31f..cb1ddd2 100644 --- a/src/main/java/team/unnamed/mocha/parser/MolangParserImpl.java +++ b/parser/src/main/java/org/redlance/mocha/parser/MolangParserImpl.java @@ -1,34 +1,34 @@ -/* - * This file is part of mocha, licensed under the MIT license - * - * Copyright (c) 2021-2025 Unnamed Team - * - * 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. - */ -package team.unnamed.mocha.parser; +/* + * This file is part of mocha, licensed under the MIT license + * + * Copyright (c) 2021-2025 Unnamed Team + * + * 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. + */ +package org.redlance.mocha.parser; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import team.unnamed.mocha.lexer.MolangLexer; -import team.unnamed.mocha.lexer.Token; -import team.unnamed.mocha.lexer.TokenKind; -import team.unnamed.mocha.parser.ast.*; +import org.redlance.mocha.lexer.MolangLexer; +import org.redlance.mocha.lexer.Token; +import org.redlance.mocha.lexer.TokenKind; +import org.redlance.mocha.parser.ast.*; import java.io.IOException; import java.util.ArrayList; diff --git a/src/main/java/team/unnamed/mocha/parser/ParseException.java b/parser/src/main/java/org/redlance/mocha/parser/ParseException.java similarity index 96% rename from src/main/java/team/unnamed/mocha/parser/ParseException.java rename to parser/src/main/java/org/redlance/mocha/parser/ParseException.java index 0f80ca7..99b4f39 100644 --- a/src/main/java/team/unnamed/mocha/parser/ParseException.java +++ b/parser/src/main/java/org/redlance/mocha/parser/ParseException.java @@ -1,30 +1,30 @@ -/* - * This file is part of mocha, licensed under the MIT license - * - * Copyright (c) 2021-2025 Unnamed Team - * - * 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. - */ -package team.unnamed.mocha.parser; +/* + * This file is part of mocha, licensed under the MIT license + * + * Copyright (c) 2021-2025 Unnamed Team + * + * 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. + */ +package org.redlance.mocha.parser; import org.jetbrains.annotations.Nullable; -import team.unnamed.mocha.lexer.Cursor; +import org.redlance.mocha.lexer.Cursor; import java.io.IOException; diff --git a/src/main/java/team/unnamed/mocha/parser/ast/AccessExpression.java b/parser/src/main/java/org/redlance/mocha/parser/ast/AccessExpression.java similarity index 95% rename from src/main/java/team/unnamed/mocha/parser/ast/AccessExpression.java rename to parser/src/main/java/org/redlance/mocha/parser/ast/AccessExpression.java index fcc63b1..be933c4 100644 --- a/src/main/java/team/unnamed/mocha/parser/ast/AccessExpression.java +++ b/parser/src/main/java/org/redlance/mocha/parser/ast/AccessExpression.java @@ -1,32 +1,32 @@ -/* - * This file is part of mocha, licensed under the MIT license - * - * Copyright (c) 2021-2025 Unnamed Team - * - * 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. - */ -package team.unnamed.mocha.parser.ast; +/* + * This file is part of mocha, licensed under the MIT license + * + * Copyright (c) 2021-2025 Unnamed Team + * + * 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. + */ +package org.redlance.mocha.parser.ast; import io.netty.buffer.ByteBuf; import org.jetbrains.annotations.NotNull; -import team.unnamed.mocha.util.ExprBytesUtils; -import team.unnamed.mocha.util.network.ProtocolUtils; +import org.redlance.mocha.parser.util.ExprBytesUtils; +import org.redlance.mocha.parser.util.network.ProtocolUtils; import static java.util.Objects.requireNonNull; diff --git a/src/main/java/team/unnamed/mocha/parser/ast/ArrayAccessExpression.java b/parser/src/main/java/org/redlance/mocha/parser/ast/ArrayAccessExpression.java similarity index 97% rename from src/main/java/team/unnamed/mocha/parser/ast/ArrayAccessExpression.java rename to parser/src/main/java/org/redlance/mocha/parser/ast/ArrayAccessExpression.java index b671396..146f447 100644 --- a/src/main/java/team/unnamed/mocha/parser/ast/ArrayAccessExpression.java +++ b/parser/src/main/java/org/redlance/mocha/parser/ast/ArrayAccessExpression.java @@ -1,32 +1,32 @@ -/* - * This file is part of mocha, licensed under the MIT license - * - * Copyright (c) 2021-2025 Unnamed Team - * - * 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. - */ -package team.unnamed.mocha.parser.ast; +/* + * This file is part of mocha, licensed under the MIT license + * + * Copyright (c) 2021-2025 Unnamed Team + * + * 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. + */ +package org.redlance.mocha.parser.ast; import io.netty.buffer.ByteBuf; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import team.unnamed.mocha.util.ExprBytesUtils; +import org.redlance.mocha.parser.util.ExprBytesUtils; import static java.util.Objects.requireNonNull; diff --git a/src/main/java/team/unnamed/mocha/parser/ast/BinaryExpression.java b/parser/src/main/java/org/redlance/mocha/parser/ast/BinaryExpression.java similarity index 97% rename from src/main/java/team/unnamed/mocha/parser/ast/BinaryExpression.java rename to parser/src/main/java/org/redlance/mocha/parser/ast/BinaryExpression.java index 4f8da48..6366105 100644 --- a/src/main/java/team/unnamed/mocha/parser/ast/BinaryExpression.java +++ b/parser/src/main/java/org/redlance/mocha/parser/ast/BinaryExpression.java @@ -21,13 +21,13 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -package team.unnamed.mocha.parser.ast; +package org.redlance.mocha.parser.ast; import io.netty.buffer.ByteBuf; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; -import team.unnamed.mocha.util.ExprBytesUtils; -import team.unnamed.mocha.util.network.ProtocolUtils; +import org.redlance.mocha.parser.util.ExprBytesUtils; +import org.redlance.mocha.parser.util.network.ProtocolUtils; import static java.util.Objects.requireNonNull; diff --git a/src/main/java/team/unnamed/mocha/parser/ast/CallExpression.java b/parser/src/main/java/org/redlance/mocha/parser/ast/CallExpression.java similarity index 93% rename from src/main/java/team/unnamed/mocha/parser/ast/CallExpression.java rename to parser/src/main/java/org/redlance/mocha/parser/ast/CallExpression.java index c857c6e..9fe61ce 100644 --- a/src/main/java/team/unnamed/mocha/parser/ast/CallExpression.java +++ b/parser/src/main/java/org/redlance/mocha/parser/ast/CallExpression.java @@ -1,120 +1,120 @@ -/* - * This file is part of mocha, licensed under the MIT license - * - * Copyright (c) 2021-2025 Unnamed Team - * - * 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. - */ -package team.unnamed.mocha.parser.ast; - -import io.netty.buffer.ByteBuf; -import org.jetbrains.annotations.NotNull; -import team.unnamed.mocha.util.ExprBytesUtils; -import team.unnamed.mocha.util.ExpressionListUtils; - -import java.util.List; - -import static java.util.Objects.requireNonNull; - -/** - * Call expression implementation, executes functions - * with certain arguments. - * - *

Example call expressions: {@code print('hello')}, - * {@code math.sqrt(9)}, {@code math.pow(3, 2)}

- * - * @since 3.0.0 - */ -public final class CallExpression implements Expression { - private final List arguments; - private Expression function; - - public CallExpression(ByteBuf buf) { - this( - ExprBytesUtils.readExpression(buf), - ExprBytesUtils.readExpressions(buf) - ); - } - - public CallExpression(final @NotNull Expression function, final @NotNull List arguments) { - this.function = requireNonNull(function, "function"); - this.arguments = requireNonNull(arguments, "arguments"); - } - - /** - * Gets the function expression. - * - * @since 3.0.0 - */ - public @NotNull Expression function() { - return function; - } - - /** - * Sets the function expression. - * - * @since 3.0.0 - */ - public void function(final @NotNull Expression function) { - this.function = requireNonNull(function, "function"); - } - - /** - * Gets the list of arguments to pass to - * the function. - * - * @since 3.0.0 - */ - public @NotNull List arguments() { - return arguments; - } - - @Override - public R visit(final @NotNull ExpressionVisitor visitor) { - return visitor.visitCall(this); - } - - @Override - public void write(ByteBuf buf) { - ExprBytesUtils.writeExpression(function(), buf); - ExprBytesUtils.writeExpressions(arguments(), buf); - } - - @Override - public String toString() { - return String.format("%s(%s)", function, ExpressionListUtils.toString(this.arguments, ",")); - } - - @Override - public boolean equals(final Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - CallExpression that = (CallExpression) o; - if (!function.equals(that.function)) return false; - return arguments.equals(that.arguments); - } - - @Override - public int hashCode() { - int result = function.hashCode(); - result = 31 * result + arguments.hashCode(); - return result; - } - +/* + * This file is part of mocha, licensed under the MIT license + * + * Copyright (c) 2021-2025 Unnamed Team + * + * 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. + */ +package org.redlance.mocha.parser.ast; + +import io.netty.buffer.ByteBuf; +import org.jetbrains.annotations.NotNull; +import org.redlance.mocha.parser.util.ExprBytesUtils; +import org.redlance.mocha.parser.util.ExpressionListUtils; + +import java.util.List; + +import static java.util.Objects.requireNonNull; + +/** + * Call expression implementation, executes functions + * with certain arguments. + * + *

Example call expressions: {@code print('hello')}, + * {@code math.sqrt(9)}, {@code math.pow(3, 2)}

+ * + * @since 3.0.0 + */ +public final class CallExpression implements Expression { + private final List arguments; + private Expression function; + + public CallExpression(ByteBuf buf) { + this( + ExprBytesUtils.readExpression(buf), + ExprBytesUtils.readExpressions(buf) + ); + } + + public CallExpression(final @NotNull Expression function, final @NotNull List arguments) { + this.function = requireNonNull(function, "function"); + this.arguments = requireNonNull(arguments, "arguments"); + } + + /** + * Gets the function expression. + * + * @since 3.0.0 + */ + public @NotNull Expression function() { + return function; + } + + /** + * Sets the function expression. + * + * @since 3.0.0 + */ + public void function(final @NotNull Expression function) { + this.function = requireNonNull(function, "function"); + } + + /** + * Gets the list of arguments to pass to + * the function. + * + * @since 3.0.0 + */ + public @NotNull List arguments() { + return arguments; + } + + @Override + public R visit(final @NotNull ExpressionVisitor visitor) { + return visitor.visitCall(this); + } + + @Override + public void write(ByteBuf buf) { + ExprBytesUtils.writeExpression(function(), buf); + ExprBytesUtils.writeExpressions(arguments(), buf); + } + + @Override + public String toString() { + return String.format("%s(%s)", function, ExpressionListUtils.toString(this.arguments, ",")); + } + + @Override + public boolean equals(final Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + CallExpression that = (CallExpression) o; + if (!function.equals(that.function)) return false; + return arguments.equals(that.arguments); + } + + @Override + public int hashCode() { + int result = function.hashCode(); + result = 31 * result + arguments.hashCode(); + return result; + } + } \ No newline at end of file diff --git a/src/main/java/team/unnamed/mocha/parser/ast/ExecutionScopeExpression.java b/parser/src/main/java/org/redlance/mocha/parser/ast/ExecutionScopeExpression.java similarity index 92% rename from src/main/java/team/unnamed/mocha/parser/ast/ExecutionScopeExpression.java rename to parser/src/main/java/org/redlance/mocha/parser/ast/ExecutionScopeExpression.java index 14510eb..fb4e912 100644 --- a/src/main/java/team/unnamed/mocha/parser/ast/ExecutionScopeExpression.java +++ b/parser/src/main/java/org/redlance/mocha/parser/ast/ExecutionScopeExpression.java @@ -1,92 +1,92 @@ -/* - * This file is part of mocha, licensed under the MIT license - * - * Copyright (c) 2021-2025 Unnamed Team - * - * 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. - */ -package team.unnamed.mocha.parser.ast; - -import io.netty.buffer.ByteBuf; -import org.jetbrains.annotations.NotNull; -import team.unnamed.mocha.util.ExprBytesUtils; -import team.unnamed.mocha.util.ExpressionListUtils; - -import java.util.List; -import java.util.Objects; - -/** - * Execution scope expression implementation. Execution - * scopes define a new scope and a new sequence of - * expressions to evaluate. - * - *

Execution scope expression examples: {@code { print('a'); print('b'); }}, - * {@code { doThisFirst(); thenDoThis(); }}, {@code { v.x = v.x + 1; }}

- * - * @since 3.0.0 - */ -public final class ExecutionScopeExpression implements Expression { - - private final List expressions; - - public ExecutionScopeExpression(ByteBuf buf) { - this(ExprBytesUtils.readExpressions(buf)); - } - - public ExecutionScopeExpression(final @NotNull List expressions) { - this.expressions = Objects.requireNonNull(expressions, "expressions"); - } - - /** - * Returns the expressions inside this - * execution scope, never null - */ - public @NotNull List expressions() { - return expressions; - } - - @Override - public R visit(final @NotNull ExpressionVisitor visitor) { - return visitor.visitExecutionScope(this); - } - - @Override - public void write(ByteBuf buf) { - ExprBytesUtils.writeExpressions(expressions(), buf); - } - - @Override - public String toString() { - return String.format("{%s}", ExpressionListUtils.toString(this.expressions)); - } - - @Override - public boolean equals(final Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - ExecutionScopeExpression that = (ExecutionScopeExpression) o; - return expressions.equals(that.expressions); - } - - @Override - public int hashCode() { - return Objects.hash(expressions); - } - +/* + * This file is part of mocha, licensed under the MIT license + * + * Copyright (c) 2021-2025 Unnamed Team + * + * 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. + */ +package org.redlance.mocha.parser.ast; + +import io.netty.buffer.ByteBuf; +import org.jetbrains.annotations.NotNull; +import org.redlance.mocha.parser.util.ExprBytesUtils; +import org.redlance.mocha.parser.util.ExpressionListUtils; + +import java.util.List; +import java.util.Objects; + +/** + * Execution scope expression implementation. Execution + * scopes define a new scope and a new sequence of + * expressions to evaluate. + * + *

Execution scope expression examples: {@code { print('a'); print('b'); }}, + * {@code { doThisFirst(); thenDoThis(); }}, {@code { v.x = v.x + 1; }}

+ * + * @since 3.0.0 + */ +public final class ExecutionScopeExpression implements Expression { + + private final List expressions; + + public ExecutionScopeExpression(ByteBuf buf) { + this(ExprBytesUtils.readExpressions(buf)); + } + + public ExecutionScopeExpression(final @NotNull List expressions) { + this.expressions = Objects.requireNonNull(expressions, "expressions"); + } + + /** + * Returns the expressions inside this + * execution scope, never null + */ + public @NotNull List expressions() { + return expressions; + } + + @Override + public R visit(final @NotNull ExpressionVisitor visitor) { + return visitor.visitExecutionScope(this); + } + + @Override + public void write(ByteBuf buf) { + ExprBytesUtils.writeExpressions(expressions(), buf); + } + + @Override + public String toString() { + return String.format("{%s}", ExpressionListUtils.toString(this.expressions)); + } + + @Override + public boolean equals(final Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + ExecutionScopeExpression that = (ExecutionScopeExpression) o; + return expressions.equals(that.expressions); + } + + @Override + public int hashCode() { + return Objects.hash(expressions); + } + } \ No newline at end of file diff --git a/src/main/java/team/unnamed/mocha/parser/ast/Expression.java b/parser/src/main/java/org/redlance/mocha/parser/ast/Expression.java similarity index 97% rename from src/main/java/team/unnamed/mocha/parser/ast/Expression.java rename to parser/src/main/java/org/redlance/mocha/parser/ast/Expression.java index 981b857..6455afe 100644 --- a/src/main/java/team/unnamed/mocha/parser/ast/Expression.java +++ b/parser/src/main/java/org/redlance/mocha/parser/ast/Expression.java @@ -1,27 +1,27 @@ -/* - * This file is part of mocha, licensed under the MIT license - * - * Copyright (c) 2021-2025 Unnamed Team - * - * 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. - */ -package team.unnamed.mocha.parser.ast; +/* + * This file is part of mocha, licensed under the MIT license + * + * Copyright (c) 2021-2025 Unnamed Team + * + * 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. + */ +package org.redlance.mocha.parser.ast; import io.netty.buffer.ByteBuf; import org.jetbrains.annotations.ApiStatus; diff --git a/src/main/java/team/unnamed/mocha/parser/ast/ExpressionVisitor.java b/parser/src/main/java/org/redlance/mocha/parser/ast/ExpressionVisitor.java similarity index 95% rename from src/main/java/team/unnamed/mocha/parser/ast/ExpressionVisitor.java rename to parser/src/main/java/org/redlance/mocha/parser/ast/ExpressionVisitor.java index 39710db..d976479 100644 --- a/src/main/java/team/unnamed/mocha/parser/ast/ExpressionVisitor.java +++ b/parser/src/main/java/org/redlance/mocha/parser/ast/ExpressionVisitor.java @@ -1,178 +1,178 @@ -/* - * This file is part of mocha, licensed under the MIT license - * - * Copyright (c) 2021-2025 Unnamed Team - * - * 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. - */ -package team.unnamed.mocha.parser.ast; - -import org.jetbrains.annotations.NotNull; - -/** - * An {@link Expression} visitor. Provides a way to add - * functionalities to the expression interface and all - * of its implementations. - * - *

See the following example on visiting an expression:

- *
{@code
- *      Expression expr = ...;
- *      String str = expr.visit(new ToStringVisitor());
- * }
- * - *

Please note that users MUST use {@link Expression#visit(ExpressionVisitor)} - * and NOT ExpressionVisitor's {@link ExpressionVisitor#visit(Expression)}, because - * it will not work as intended.

- * - * @param The visit result type - * @since 3.0.0 - */ -public interface ExpressionVisitor { - - /** - * Evaluate for the given unknown expression. - * - * @param expression The expression. - * @return The result. - * @since 3.0.0 - */ - R visit(final @NotNull Expression expression); - - /** - * Evaluate for array access expression. - * - * @param expression The expression. - * @return The result. - * @since 3.0.0 - */ - default R visitArrayAccess(final @NotNull ArrayAccessExpression expression) { - return visit(expression); - } - - /** - * Evaluate for float expression. - * - * @param expression The expression. - * @return The result. - * @since 3.0.0 - */ - default R visitFloat(final @NotNull FloatExpression expression) { - return visit(expression); - } - - /** - * Evaluate for string expression. - * - * @param expression The expression. - * @return The result. - * @since 3.0.0 - */ - default R visitString(final @NotNull StringExpression expression) { - return visit(expression); - } - - /** - * Evaluate for identifier expression. - * - * @param expression The expression. - * @return The result. - * @since 3.0.0 - */ - default R visitIdentifier(final @NotNull IdentifierExpression expression) { - return visit(expression); - } - - /** - * Evaluate for ternary conditional expression. - * - * @param expression The expression. - * @return The result. - * @since 3.0.0 - */ - default R visitTernaryConditional(final @NotNull TernaryConditionalExpression expression) { - return visit(expression); - } - - /** - * Evaluate for unary expression. - * - * @param expression The expression. - * @return The result. - * @since 3.0.0 - */ - default R visitUnary(final @NotNull UnaryExpression expression) { - return visit(expression); - } - - /** - * Evaluate for execution scope expression. - * - * @param expression The expression. - * @return The result. - * @since 3.0.0 - */ - default R visitExecutionScope(final @NotNull ExecutionScopeExpression expression) { - return visit(expression); - } - - /** - * Evaluate for binary expression. - * - * @param expression The expression. - * @return The result. - * @since 3.0.0 - */ - default R visitBinary(final @NotNull BinaryExpression expression) { - return visit(expression); - } - - /** - * Evaluate for access expression. - * - * @param expression The expression. - * @return The result. - * @since 3.0.0 - */ - default R visitAccess(final @NotNull AccessExpression expression) { - return visit(expression); - } - - /** - * Evaluate for call expression. - * - * @param expression The expression. - * @return The result. - * @since 3.0.0 - */ - default R visitCall(final @NotNull CallExpression expression) { - return visit(expression); - } - - /** - * Evaluate for statement expression. - * - * @param expression The expression. - * @return The result. - * @since 3.0.0 - */ - default R visitStatement(final @NotNull StatementExpression expression) { - return visit(expression); - } - +/* + * This file is part of mocha, licensed under the MIT license + * + * Copyright (c) 2021-2025 Unnamed Team + * + * 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. + */ +package org.redlance.mocha.parser.ast; + +import org.jetbrains.annotations.NotNull; + +/** + * An {@link Expression} visitor. Provides a way to add + * functionalities to the expression interface and all + * of its implementations. + * + *

See the following example on visiting an expression:

+ *
{@code
+ *      Expression expr = ...;
+ *      String str = expr.visit(new ToStringVisitor());
+ * }
+ * + *

Please note that users MUST use {@link Expression#visit(ExpressionVisitor)} + * and NOT ExpressionVisitor's {@link ExpressionVisitor#visit(Expression)}, because + * it will not work as intended.

+ * + * @param The visit result type + * @since 3.0.0 + */ +public interface ExpressionVisitor { + + /** + * Evaluate for the given unknown expression. + * + * @param expression The expression. + * @return The result. + * @since 3.0.0 + */ + R visit(final @NotNull Expression expression); + + /** + * Evaluate for array access expression. + * + * @param expression The expression. + * @return The result. + * @since 3.0.0 + */ + default R visitArrayAccess(final @NotNull ArrayAccessExpression expression) { + return visit(expression); + } + + /** + * Evaluate for float expression. + * + * @param expression The expression. + * @return The result. + * @since 3.0.0 + */ + default R visitFloat(final @NotNull FloatExpression expression) { + return visit(expression); + } + + /** + * Evaluate for string expression. + * + * @param expression The expression. + * @return The result. + * @since 3.0.0 + */ + default R visitString(final @NotNull StringExpression expression) { + return visit(expression); + } + + /** + * Evaluate for identifier expression. + * + * @param expression The expression. + * @return The result. + * @since 3.0.0 + */ + default R visitIdentifier(final @NotNull IdentifierExpression expression) { + return visit(expression); + } + + /** + * Evaluate for ternary conditional expression. + * + * @param expression The expression. + * @return The result. + * @since 3.0.0 + */ + default R visitTernaryConditional(final @NotNull TernaryConditionalExpression expression) { + return visit(expression); + } + + /** + * Evaluate for unary expression. + * + * @param expression The expression. + * @return The result. + * @since 3.0.0 + */ + default R visitUnary(final @NotNull UnaryExpression expression) { + return visit(expression); + } + + /** + * Evaluate for execution scope expression. + * + * @param expression The expression. + * @return The result. + * @since 3.0.0 + */ + default R visitExecutionScope(final @NotNull ExecutionScopeExpression expression) { + return visit(expression); + } + + /** + * Evaluate for binary expression. + * + * @param expression The expression. + * @return The result. + * @since 3.0.0 + */ + default R visitBinary(final @NotNull BinaryExpression expression) { + return visit(expression); + } + + /** + * Evaluate for access expression. + * + * @param expression The expression. + * @return The result. + * @since 3.0.0 + */ + default R visitAccess(final @NotNull AccessExpression expression) { + return visit(expression); + } + + /** + * Evaluate for call expression. + * + * @param expression The expression. + * @return The result. + * @since 3.0.0 + */ + default R visitCall(final @NotNull CallExpression expression) { + return visit(expression); + } + + /** + * Evaluate for statement expression. + * + * @param expression The expression. + * @return The result. + * @since 3.0.0 + */ + default R visitStatement(final @NotNull StatementExpression expression) { + return visit(expression); + } + } \ No newline at end of file diff --git a/src/main/java/team/unnamed/mocha/parser/ast/FloatExpression.java b/parser/src/main/java/org/redlance/mocha/parser/ast/FloatExpression.java similarity index 98% rename from src/main/java/team/unnamed/mocha/parser/ast/FloatExpression.java rename to parser/src/main/java/org/redlance/mocha/parser/ast/FloatExpression.java index df189c1..f7def17 100644 --- a/src/main/java/team/unnamed/mocha/parser/ast/FloatExpression.java +++ b/parser/src/main/java/org/redlance/mocha/parser/ast/FloatExpression.java @@ -21,7 +21,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -package team.unnamed.mocha.parser.ast; +package org.redlance.mocha.parser.ast; import io.netty.buffer.ByteBuf; import org.jetbrains.annotations.NotNull; diff --git a/src/main/java/team/unnamed/mocha/parser/ast/IdentifierExpression.java b/parser/src/main/java/org/redlance/mocha/parser/ast/IdentifierExpression.java similarity index 94% rename from src/main/java/team/unnamed/mocha/parser/ast/IdentifierExpression.java rename to parser/src/main/java/org/redlance/mocha/parser/ast/IdentifierExpression.java index 4056a81..10da8ef 100644 --- a/src/main/java/team/unnamed/mocha/parser/ast/IdentifierExpression.java +++ b/parser/src/main/java/org/redlance/mocha/parser/ast/IdentifierExpression.java @@ -1,32 +1,31 @@ -/* - * This file is part of mocha, licensed under the MIT license - * - * Copyright (c) 2021-2025 Unnamed Team - * - * 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. - */ -package team.unnamed.mocha.parser.ast; +/* + * This file is part of mocha, licensed under the MIT license + * + * Copyright (c) 2021-2025 Unnamed Team + * + * 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. + */ +package org.redlance.mocha.parser.ast; import io.netty.buffer.ByteBuf; import org.jetbrains.annotations.NotNull; -import team.unnamed.mocha.util.ExprBytesUtils; -import team.unnamed.mocha.util.network.ProtocolUtils; +import org.redlance.mocha.parser.util.network.ProtocolUtils; import java.util.Locale; import java.util.Objects; diff --git a/src/main/java/team/unnamed/mocha/parser/ast/StatementExpression.java b/parser/src/main/java/org/redlance/mocha/parser/ast/StatementExpression.java similarity index 96% rename from src/main/java/team/unnamed/mocha/parser/ast/StatementExpression.java rename to parser/src/main/java/org/redlance/mocha/parser/ast/StatementExpression.java index 0c68804..7340e8c 100644 --- a/src/main/java/team/unnamed/mocha/parser/ast/StatementExpression.java +++ b/parser/src/main/java/org/redlance/mocha/parser/ast/StatementExpression.java @@ -1,31 +1,31 @@ -/* - * This file is part of mocha, licensed under the MIT license - * - * Copyright (c) 2021-2025 Unnamed Team - * - * 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. - */ -package team.unnamed.mocha.parser.ast; +/* + * This file is part of mocha, licensed under the MIT license + * + * Copyright (c) 2021-2025 Unnamed Team + * + * 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. + */ +package org.redlance.mocha.parser.ast; import io.netty.buffer.ByteBuf; import org.jetbrains.annotations.NotNull; -import team.unnamed.mocha.util.network.ProtocolUtils; +import org.redlance.mocha.parser.util.network.ProtocolUtils; import java.util.Objects; diff --git a/src/main/java/team/unnamed/mocha/parser/ast/StringExpression.java b/parser/src/main/java/org/redlance/mocha/parser/ast/StringExpression.java similarity index 93% rename from src/main/java/team/unnamed/mocha/parser/ast/StringExpression.java rename to parser/src/main/java/org/redlance/mocha/parser/ast/StringExpression.java index 42e8152..246f19b 100644 --- a/src/main/java/team/unnamed/mocha/parser/ast/StringExpression.java +++ b/parser/src/main/java/org/redlance/mocha/parser/ast/StringExpression.java @@ -1,90 +1,90 @@ -/* - * This file is part of mocha, licensed under the MIT license - * - * Copyright (c) 2021-2025 Unnamed Team - * - * 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. - */ -package team.unnamed.mocha.parser.ast; - -import io.netty.buffer.ByteBuf; -import org.jetbrains.annotations.NotNull; -import team.unnamed.mocha.util.network.ProtocolUtils; - -import java.util.Objects; - -/** - * String literal expression implementation for Molang. - * - *

Example string expressions: {@code 'hello world'}, - * {@code 'hey there'}, {@code 'name'}, {@code 'the game'}

- * - * @since 3.0.0 - */ -public final class StringExpression implements Expression { - - private final String value; - - public StringExpression(ByteBuf buf) { - this(ProtocolUtils.readString(buf)); - } - - public StringExpression(final @NotNull String value) { - this.value = Objects.requireNonNull(value, "value"); - } - - /** - * Gets the string value for this expression. - * - * @return The string value. - * @since 3.0.0 - */ - public @NotNull String value() { - return value; - } - - @Override - public R visit(final @NotNull ExpressionVisitor visitor) { - return visitor.visitString(this); - } - - @Override - public void write(ByteBuf buf) { - ProtocolUtils.writeString(buf, value()); - } - - @Override - public String toString() { - return String.format("'%s'", value); - } - - @Override - public boolean equals(final Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - StringExpression that = (StringExpression) o; - return value.equals(that.value); - } - - @Override - public int hashCode() { - return value.hashCode(); - } - +/* + * This file is part of mocha, licensed under the MIT license + * + * Copyright (c) 2021-2025 Unnamed Team + * + * 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. + */ +package org.redlance.mocha.parser.ast; + +import io.netty.buffer.ByteBuf; +import org.jetbrains.annotations.NotNull; +import org.redlance.mocha.parser.util.network.ProtocolUtils; + +import java.util.Objects; + +/** + * String literal expression implementation for Molang. + * + *

Example string expressions: {@code 'hello world'}, + * {@code 'hey there'}, {@code 'name'}, {@code 'the game'}

+ * + * @since 3.0.0 + */ +public final class StringExpression implements Expression { + + private final String value; + + public StringExpression(ByteBuf buf) { + this(ProtocolUtils.readString(buf)); + } + + public StringExpression(final @NotNull String value) { + this.value = Objects.requireNonNull(value, "value"); + } + + /** + * Gets the string value for this expression. + * + * @return The string value. + * @since 3.0.0 + */ + public @NotNull String value() { + return value; + } + + @Override + public R visit(final @NotNull ExpressionVisitor visitor) { + return visitor.visitString(this); + } + + @Override + public void write(ByteBuf buf) { + ProtocolUtils.writeString(buf, value()); + } + + @Override + public String toString() { + return String.format("'%s'", value); + } + + @Override + public boolean equals(final Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + StringExpression that = (StringExpression) o; + return value.equals(that.value); + } + + @Override + public int hashCode() { + return value.hashCode(); + } + } \ No newline at end of file diff --git a/src/main/java/team/unnamed/mocha/parser/ast/TernaryConditionalExpression.java b/parser/src/main/java/org/redlance/mocha/parser/ast/TernaryConditionalExpression.java similarity index 95% rename from src/main/java/team/unnamed/mocha/parser/ast/TernaryConditionalExpression.java rename to parser/src/main/java/org/redlance/mocha/parser/ast/TernaryConditionalExpression.java index ab0033d..61fb45f 100644 --- a/src/main/java/team/unnamed/mocha/parser/ast/TernaryConditionalExpression.java +++ b/parser/src/main/java/org/redlance/mocha/parser/ast/TernaryConditionalExpression.java @@ -1,159 +1,159 @@ -/* - * This file is part of mocha, licensed under the MIT license - * - * Copyright (c) 2021-2025 Unnamed Team - * - * 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. - */ -package team.unnamed.mocha.parser.ast; - -import io.netty.buffer.ByteBuf; -import org.jetbrains.annotations.NotNull; -import team.unnamed.mocha.util.ExprBytesUtils; - -import java.util.Objects; - -import static java.util.Objects.requireNonNull; - -/** - * Ternary conditional expression implementation, similar to - * "if {...} else {...}" expressions in other languages. - * - *

If the {@code conditional} expression evaluates to a - * truthy value, then {@code trueExpression} is evaluated - * as the result, otherwise, {@code falseExpression} is.

- * - *

Example ternary conditional expressions: {@code true ? 1 : 0}, - * {@code (age > 18) ? 'adult' : 'minor'}, {@code open ? 'open' : 'closed'}

- * - * @since 3.0.0 - */ -public final class TernaryConditionalExpression implements Expression { - private Expression conditional; - private Expression trueExpression; - private Expression falseExpression; - - public TernaryConditionalExpression(ByteBuf buf) { - this( - ExprBytesUtils.readExpression(buf), - ExprBytesUtils.readExpression(buf), - ExprBytesUtils.readExpression(buf) - ); - } - - public TernaryConditionalExpression(final @NotNull Expression conditional, final @NotNull Expression trueExpression, final @NotNull Expression falseExpression) { - this.conditional = requireNonNull(conditional, "conditional"); - this.trueExpression = requireNonNull(trueExpression, "trueExpression"); - this.falseExpression = requireNonNull(falseExpression, "falseExpression"); - } - - /** - * Gets the expression condition. - * - * @since 3.0.0 - */ - public @NotNull Expression condition() { - return conditional; - } - - /** - * Sets the expression condition. - * - * @param condition The condition - * @since 3.0.0 - */ - public void condition(final @NotNull Expression condition) { - this.conditional = requireNonNull(condition, "condition"); - } - - /** - * Gets the expression that should be used when - * condition is evaluated as a truthy value. - * - * @since 3.0.0 - */ - public @NotNull Expression trueExpression() { - return trueExpression; - } - - /** - * Sets the expression that should be used when - * condition is evaluated as a truthy value. - * - * @param trueExpression The true expression - * @since 3.0.0 - */ - public void trueExpression(final @NotNull Expression trueExpression) { - this.trueExpression = requireNonNull(trueExpression, "trueExpression"); - } - - /** - * Gets the expression that should be used when - * condition is evaluated as a falsy value. - * - * @since 3.0.0 - */ - public @NotNull Expression falseExpression() { - return falseExpression; - } - - /** - * Sets the expression that should be used when - * condition is evaluated as a falsy value. - * - * @param falseExpression The false expression - * @since 3.0.0 - */ - public void falseExpression(final @NotNull Expression falseExpression) { - this.falseExpression = requireNonNull(falseExpression, "falseExpression"); - } - - @Override - public R visit(final @NotNull ExpressionVisitor visitor) { - return visitor.visitTernaryConditional(this); - } - - @Override - public void write(ByteBuf buf) { - ExprBytesUtils.writeExpression(conditional, buf); - ExprBytesUtils.writeExpression(trueExpression, buf); - ExprBytesUtils.writeExpression(falseExpression, buf); - } - - @Override - public String toString() { - return String.format("(%s)?%s:%s", conditional, trueExpression, falseExpression); - } - - @Override - public boolean equals(final Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - TernaryConditionalExpression that = (TernaryConditionalExpression) o; - return conditional.equals(that.conditional) - && trueExpression.equals(that.trueExpression) - && falseExpression.equals(that.falseExpression); - } - - @Override - public int hashCode() { - return Objects.hash(conditional, trueExpression, falseExpression); - } - +/* + * This file is part of mocha, licensed under the MIT license + * + * Copyright (c) 2021-2025 Unnamed Team + * + * 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. + */ +package org.redlance.mocha.parser.ast; + +import io.netty.buffer.ByteBuf; +import org.jetbrains.annotations.NotNull; +import org.redlance.mocha.parser.util.ExprBytesUtils; + +import java.util.Objects; + +import static java.util.Objects.requireNonNull; + +/** + * Ternary conditional expression implementation, similar to + * "if {...} else {...}" expressions in other languages. + * + *

If the {@code conditional} expression evaluates to a + * truthy value, then {@code trueExpression} is evaluated + * as the result, otherwise, {@code falseExpression} is.

+ * + *

Example ternary conditional expressions: {@code true ? 1 : 0}, + * {@code (age > 18) ? 'adult' : 'minor'}, {@code open ? 'open' : 'closed'}

+ * + * @since 3.0.0 + */ +public final class TernaryConditionalExpression implements Expression { + private Expression conditional; + private Expression trueExpression; + private Expression falseExpression; + + public TernaryConditionalExpression(ByteBuf buf) { + this( + ExprBytesUtils.readExpression(buf), + ExprBytesUtils.readExpression(buf), + ExprBytesUtils.readExpression(buf) + ); + } + + public TernaryConditionalExpression(final @NotNull Expression conditional, final @NotNull Expression trueExpression, final @NotNull Expression falseExpression) { + this.conditional = requireNonNull(conditional, "conditional"); + this.trueExpression = requireNonNull(trueExpression, "trueExpression"); + this.falseExpression = requireNonNull(falseExpression, "falseExpression"); + } + + /** + * Gets the expression condition. + * + * @since 3.0.0 + */ + public @NotNull Expression condition() { + return conditional; + } + + /** + * Sets the expression condition. + * + * @param condition The condition + * @since 3.0.0 + */ + public void condition(final @NotNull Expression condition) { + this.conditional = requireNonNull(condition, "condition"); + } + + /** + * Gets the expression that should be used when + * condition is evaluated as a truthy value. + * + * @since 3.0.0 + */ + public @NotNull Expression trueExpression() { + return trueExpression; + } + + /** + * Sets the expression that should be used when + * condition is evaluated as a truthy value. + * + * @param trueExpression The true expression + * @since 3.0.0 + */ + public void trueExpression(final @NotNull Expression trueExpression) { + this.trueExpression = requireNonNull(trueExpression, "trueExpression"); + } + + /** + * Gets the expression that should be used when + * condition is evaluated as a falsy value. + * + * @since 3.0.0 + */ + public @NotNull Expression falseExpression() { + return falseExpression; + } + + /** + * Sets the expression that should be used when + * condition is evaluated as a falsy value. + * + * @param falseExpression The false expression + * @since 3.0.0 + */ + public void falseExpression(final @NotNull Expression falseExpression) { + this.falseExpression = requireNonNull(falseExpression, "falseExpression"); + } + + @Override + public R visit(final @NotNull ExpressionVisitor visitor) { + return visitor.visitTernaryConditional(this); + } + + @Override + public void write(ByteBuf buf) { + ExprBytesUtils.writeExpression(conditional, buf); + ExprBytesUtils.writeExpression(trueExpression, buf); + ExprBytesUtils.writeExpression(falseExpression, buf); + } + + @Override + public String toString() { + return String.format("(%s)?%s:%s", conditional, trueExpression, falseExpression); + } + + @Override + public boolean equals(final Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + TernaryConditionalExpression that = (TernaryConditionalExpression) o; + return conditional.equals(that.conditional) + && trueExpression.equals(that.trueExpression) + && falseExpression.equals(that.falseExpression); + } + + @Override + public int hashCode() { + return Objects.hash(conditional, trueExpression, falseExpression); + } + } \ No newline at end of file diff --git a/src/main/java/team/unnamed/mocha/parser/ast/UnaryExpression.java b/parser/src/main/java/org/redlance/mocha/parser/ast/UnaryExpression.java similarity index 93% rename from src/main/java/team/unnamed/mocha/parser/ast/UnaryExpression.java rename to parser/src/main/java/org/redlance/mocha/parser/ast/UnaryExpression.java index 732821e..ad9f964 100644 --- a/src/main/java/team/unnamed/mocha/parser/ast/UnaryExpression.java +++ b/parser/src/main/java/org/redlance/mocha/parser/ast/UnaryExpression.java @@ -1,138 +1,138 @@ -/* - * This file is part of mocha, licensed under the MIT license - * - * Copyright (c) 2021-2025 Unnamed Team - * - * 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. - */ -package team.unnamed.mocha.parser.ast; - -import io.netty.buffer.ByteBuf; -import org.jetbrains.annotations.NotNull; -import team.unnamed.mocha.util.ExprBytesUtils; -import team.unnamed.mocha.util.network.ProtocolUtils; - -import static java.util.Objects.requireNonNull; - -/** - * Unary expression implementation, performs a single operation - * to a single expression, like logical negation, arithmetical - * negation, or "return expr;". - * - *

Example unary expressions: {@code -hello}, {@code !p}, - * {@code !q}, {@code -(10 * 5)}, {@code return this}, - * {@code return 5}

- * - * @since 3.0.0 - */ -public final class UnaryExpression implements Expression { - private final Op op; - private Expression expression; - - public UnaryExpression(ByteBuf buf) { - this( - ProtocolUtils.readEnum(Op.class, buf), - ExprBytesUtils.readExpression(buf) - ); - } - - public UnaryExpression(final @NotNull Op op, final @NotNull Expression expression) { - this.op = requireNonNull(op, "op"); - this.expression = requireNonNull(expression, "expression"); - } - - /** - * Gets the unary expression operation. - * - * @return The unary expression operation. - * @since 3.0.0 - */ - public @NotNull Op op() { - return op; - } - - /** - * Gets the operated expression. - * - * @return The operated expression. - * @since 3.0.0 - */ - public @NotNull Expression expression() { - return expression; - } - - /** - * Sets the operated expression. - * - * @param expression The operated expression. - * @since 3.0.0 - */ - public void expression(final @NotNull Expression expression) { - this.expression = requireNonNull(expression, "expression"); - } - - @Override - public R visit(final @NotNull ExpressionVisitor visitor) { - return visitor.visitUnary(this); - } - - @Override - public void write(ByteBuf buf) { - ProtocolUtils.writeEnum(op(), buf); - ExprBytesUtils.writeExpression(this.expression, buf); - } - - @Override - public String toString() { - return String.format("%s(%s)", op, expression); - } - - @Override - public boolean equals(final Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - UnaryExpression that = (UnaryExpression) o; - if (op != that.op) return false; - return expression.equals(that.expression); - } - - @Override - public int hashCode() { - int result = op.hashCode(); - result = 31 * result + expression.hashCode(); - return result; - } - - public enum Op { - LOGICAL_NEGATION("!"), - ARITHMETICAL_NEGATION("-"), - RETURN("return "); - - private final String string; - - Op(String string) { - this.string = string; - } - - @Override - public String toString() { - return this.string; - } - } -} +/* + * This file is part of mocha, licensed under the MIT license + * + * Copyright (c) 2021-2025 Unnamed Team + * + * 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. + */ +package org.redlance.mocha.parser.ast; + +import io.netty.buffer.ByteBuf; +import org.jetbrains.annotations.NotNull; +import org.redlance.mocha.parser.util.ExprBytesUtils; +import org.redlance.mocha.parser.util.network.ProtocolUtils; + +import static java.util.Objects.requireNonNull; + +/** + * Unary expression implementation, performs a single operation + * to a single expression, like logical negation, arithmetical + * negation, or "return expr;". + * + *

Example unary expressions: {@code -hello}, {@code !p}, + * {@code !q}, {@code -(10 * 5)}, {@code return this}, + * {@code return 5}

+ * + * @since 3.0.0 + */ +public final class UnaryExpression implements Expression { + private final Op op; + private Expression expression; + + public UnaryExpression(ByteBuf buf) { + this( + ProtocolUtils.readEnum(Op.class, buf), + ExprBytesUtils.readExpression(buf) + ); + } + + public UnaryExpression(final @NotNull Op op, final @NotNull Expression expression) { + this.op = requireNonNull(op, "op"); + this.expression = requireNonNull(expression, "expression"); + } + + /** + * Gets the unary expression operation. + * + * @return The unary expression operation. + * @since 3.0.0 + */ + public @NotNull Op op() { + return op; + } + + /** + * Gets the operated expression. + * + * @return The operated expression. + * @since 3.0.0 + */ + public @NotNull Expression expression() { + return expression; + } + + /** + * Sets the operated expression. + * + * @param expression The operated expression. + * @since 3.0.0 + */ + public void expression(final @NotNull Expression expression) { + this.expression = requireNonNull(expression, "expression"); + } + + @Override + public R visit(final @NotNull ExpressionVisitor visitor) { + return visitor.visitUnary(this); + } + + @Override + public void write(ByteBuf buf) { + ProtocolUtils.writeEnum(op(), buf); + ExprBytesUtils.writeExpression(this.expression, buf); + } + + @Override + public String toString() { + return String.format("%s(%s)", op, expression); + } + + @Override + public boolean equals(final Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + UnaryExpression that = (UnaryExpression) o; + if (op != that.op) return false; + return expression.equals(that.expression); + } + + @Override + public int hashCode() { + int result = op.hashCode(); + result = 31 * result + expression.hashCode(); + return result; + } + + public enum Op { + LOGICAL_NEGATION("!"), + ARITHMETICAL_NEGATION("-"), + RETURN("return "); + + private final String string; + + Op(String string) { + this.string = string; + } + + @Override + public String toString() { + return this.string; + } + } +} diff --git a/src/main/java/team/unnamed/mocha/parser/ast/package-info.java b/parser/src/main/java/org/redlance/mocha/parser/ast/package-info.java similarity index 91% rename from src/main/java/team/unnamed/mocha/parser/ast/package-info.java rename to parser/src/main/java/org/redlance/mocha/parser/ast/package-info.java index fc81e5e..34d6017 100644 --- a/src/main/java/team/unnamed/mocha/parser/ast/package-info.java +++ b/parser/src/main/java/org/redlance/mocha/parser/ast/package-info.java @@ -1,27 +1,27 @@ -/* - * This file is part of mocha, licensed under the MIT license - * - * Copyright (c) 2021-2025 Unnamed Team - * - * 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. - */ -/** +/* + * This file is part of mocha, licensed under the MIT license + * + * Copyright (c) 2021-2025 Unnamed Team + * + * 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. + */ +/** * Package containing classes for Molang abstract syntax trees. * *

Syntax trees are structures made out of expressions. Some @@ -33,4 +33,7 @@ * * @since 3.0.0 */ -package team.unnamed.mocha.parser.ast; \ No newline at end of file +@ReflectionSupport(ReflectionSupport.Level.NATIVE_ONLY) +package org.redlance.mocha.parser.ast; + +import com.google.j2objc.annotations.ReflectionSupport; \ No newline at end of file diff --git a/src/main/java/team/unnamed/mocha/parser/package-info.java b/parser/src/main/java/org/redlance/mocha/parser/package-info.java similarity index 91% rename from src/main/java/team/unnamed/mocha/parser/package-info.java rename to parser/src/main/java/org/redlance/mocha/parser/package-info.java index cde79f2..31040c8 100644 --- a/src/main/java/team/unnamed/mocha/parser/package-info.java +++ b/parser/src/main/java/org/redlance/mocha/parser/package-info.java @@ -1,33 +1,36 @@ -/* - * This file is part of mocha, licensed under the MIT license - * - * Copyright (c) 2021-2025 Unnamed Team - * - * 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. - */ -/** - * Package containing classes related to parsing of Molang code. - * - *

This means converting a stream of tokens to a stream of - * Molang expressions, e.g. (float plus float) -> (Add(float, float)), - * or (identifier dot identifier)) -> (Access(identifier, identifier))

- * - * @since 3.0.0 - */ -package team.unnamed.mocha.parser; \ No newline at end of file +/* + * This file is part of mocha, licensed under the MIT license + * + * Copyright (c) 2021-2025 Unnamed Team + * + * 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. + */ +/** + * Package containing classes related to parsing of Molang code. + * + *

This means converting a stream of tokens to a stream of + * Molang expressions, e.g. (float plus float) -> (Add(float, float)), + * or (identifier dot identifier)) -> (Access(identifier, identifier))

+ * + * @since 3.0.0 + */ +@ReflectionSupport(ReflectionSupport.Level.NATIVE_ONLY) +package org.redlance.mocha.parser; + +import com.google.j2objc.annotations.ReflectionSupport; \ No newline at end of file diff --git a/src/main/java/team/unnamed/mocha/util/ExprBytesUtils.java b/parser/src/main/java/org/redlance/mocha/parser/util/ExprBytesUtils.java similarity index 96% rename from src/main/java/team/unnamed/mocha/util/ExprBytesUtils.java rename to parser/src/main/java/org/redlance/mocha/parser/util/ExprBytesUtils.java index e624595..1457b1d 100644 --- a/src/main/java/team/unnamed/mocha/util/ExprBytesUtils.java +++ b/parser/src/main/java/org/redlance/mocha/parser/util/ExprBytesUtils.java @@ -21,12 +21,12 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -package team.unnamed.mocha.util; +package org.redlance.mocha.parser.util; import io.netty.buffer.ByteBuf; import org.jetbrains.annotations.NotNull; -import team.unnamed.mocha.parser.ast.*; -import team.unnamed.mocha.util.network.ProtocolUtils; +import org.redlance.mocha.parser.ast.*; +import org.redlance.mocha.parser.util.network.ProtocolUtils; import java.util.HashMap; import java.util.List; diff --git a/src/main/java/team/unnamed/mocha/util/ExpressionListUtils.java b/parser/src/main/java/org/redlance/mocha/parser/util/ExpressionListUtils.java similarity index 94% rename from src/main/java/team/unnamed/mocha/util/ExpressionListUtils.java rename to parser/src/main/java/org/redlance/mocha/parser/util/ExpressionListUtils.java index 094d082..6e16459 100644 --- a/src/main/java/team/unnamed/mocha/util/ExpressionListUtils.java +++ b/parser/src/main/java/org/redlance/mocha/parser/util/ExpressionListUtils.java @@ -21,9 +21,9 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -package team.unnamed.mocha.util; +package org.redlance.mocha.parser.util; -import team.unnamed.mocha.parser.ast.Expression; +import org.redlance.mocha.parser.ast.Expression; import java.util.List; import java.util.stream.Collectors; diff --git a/src/main/java/team/unnamed/mocha/util/network/ProtocolUtils.java b/parser/src/main/java/org/redlance/mocha/parser/util/network/ProtocolUtils.java similarity index 98% rename from src/main/java/team/unnamed/mocha/util/network/ProtocolUtils.java rename to parser/src/main/java/org/redlance/mocha/parser/util/network/ProtocolUtils.java index 3378d07..8c05df7 100644 --- a/src/main/java/team/unnamed/mocha/util/network/ProtocolUtils.java +++ b/parser/src/main/java/org/redlance/mocha/parser/util/network/ProtocolUtils.java @@ -21,7 +21,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -package team.unnamed.mocha.util.network; +package org.redlance.mocha.parser.util.network; import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBufUtil; diff --git a/src/main/java/team/unnamed/mocha/util/network/VarIntUtils.java b/parser/src/main/java/org/redlance/mocha/parser/util/network/VarIntUtils.java similarity index 98% rename from src/main/java/team/unnamed/mocha/util/network/VarIntUtils.java rename to parser/src/main/java/org/redlance/mocha/parser/util/network/VarIntUtils.java index db2a08e..6039e99 100644 --- a/src/main/java/team/unnamed/mocha/util/network/VarIntUtils.java +++ b/parser/src/main/java/org/redlance/mocha/parser/util/network/VarIntUtils.java @@ -21,7 +21,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -package team.unnamed.mocha.util.network; +package org.redlance.mocha.parser.util.network; import io.netty.buffer.ByteBuf; diff --git a/parser/src/main/java/org/redlance/mocha/parser/util/network/package-info.java b/parser/src/main/java/org/redlance/mocha/parser/util/network/package-info.java new file mode 100644 index 0000000..d7eb29a --- /dev/null +++ b/parser/src/main/java/org/redlance/mocha/parser/util/network/package-info.java @@ -0,0 +1,4 @@ +@ReflectionSupport(ReflectionSupport.Level.NATIVE_ONLY) +package org.redlance.mocha.parser.util.network; + +import com.google.j2objc.annotations.ReflectionSupport; \ No newline at end of file diff --git a/parser/src/main/java/org/redlance/mocha/parser/util/package-info.java b/parser/src/main/java/org/redlance/mocha/parser/util/package-info.java new file mode 100644 index 0000000..a70bec8 --- /dev/null +++ b/parser/src/main/java/org/redlance/mocha/parser/util/package-info.java @@ -0,0 +1,4 @@ +@ReflectionSupport(ReflectionSupport.Level.NATIVE_ONLY) +package org.redlance.mocha.parser.util; + +import com.google.j2objc.annotations.ReflectionSupport; \ No newline at end of file diff --git a/src/test/java/team/unnamed/mocha/parser/ArrayAccessParseTest.java b/parser/src/test/java/org/redlance/mocha/parser/ArrayAccessParseTest.java similarity index 93% rename from src/test/java/team/unnamed/mocha/parser/ArrayAccessParseTest.java rename to parser/src/test/java/org/redlance/mocha/parser/ArrayAccessParseTest.java index 164ac8d..dd6a289 100644 --- a/src/test/java/team/unnamed/mocha/parser/ArrayAccessParseTest.java +++ b/parser/src/test/java/org/redlance/mocha/parser/ArrayAccessParseTest.java @@ -1,35 +1,35 @@ -/* - * This file is part of mocha, licensed under the MIT license - * - * Copyright (c) 2021-2025 Unnamed Team - * - * 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. - */ -package team.unnamed.mocha.parser; +/* + * This file is part of mocha, licensed under the MIT license + * + * Copyright (c) 2021-2025 Unnamed Team + * + * 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. + */ +package org.redlance.mocha.parser; import org.junit.jupiter.api.Test; -import team.unnamed.mocha.parser.ast.*; +import org.redlance.mocha.parser.ast.*; import java.util.Collections; -import static team.unnamed.mocha.MochaAssertions.assertCreateTree; -import static team.unnamed.mocha.MochaAssertions.assertParseError; +import static org.redlance.mocha.parser.ParserAssertions.assertCreateTree; +import static org.redlance.mocha.parser.ParserAssertions.assertParseError; class ArrayAccessParseTest { @Test diff --git a/src/test/java/team/unnamed/mocha/parser/CallParseTest.java b/parser/src/test/java/org/redlance/mocha/parser/CallParseTest.java similarity index 93% rename from src/test/java/team/unnamed/mocha/parser/CallParseTest.java rename to parser/src/test/java/org/redlance/mocha/parser/CallParseTest.java index cf5ac4e..07e9391 100644 --- a/src/test/java/team/unnamed/mocha/parser/CallParseTest.java +++ b/parser/src/test/java/org/redlance/mocha/parser/CallParseTest.java @@ -1,36 +1,36 @@ -/* - * This file is part of mocha, licensed under the MIT license - * - * Copyright (c) 2021-2025 Unnamed Team - * - * 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. - */ -package team.unnamed.mocha.parser; +/* + * This file is part of mocha, licensed under the MIT license + * + * Copyright (c) 2021-2025 Unnamed Team + * + * 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. + */ +package org.redlance.mocha.parser; import org.junit.jupiter.api.Test; -import team.unnamed.mocha.parser.ast.*; +import org.redlance.mocha.parser.ast.*; import java.util.Arrays; import java.util.Collections; -import static team.unnamed.mocha.MochaAssertions.assertCreateTree; -import static team.unnamed.mocha.MochaAssertions.assertParseError; +import static org.redlance.mocha.parser.ParserAssertions.assertCreateTree; +import static org.redlance.mocha.parser.ParserAssertions.assertParseError; class CallParseTest { @Test diff --git a/src/test/java/team/unnamed/mocha/parser/DoubleParseTest.java b/parser/src/test/java/org/redlance/mocha/parser/DoubleParseTest.java similarity index 88% rename from src/test/java/team/unnamed/mocha/parser/DoubleParseTest.java rename to parser/src/test/java/org/redlance/mocha/parser/DoubleParseTest.java index 14effc1..32f6a21 100644 --- a/src/test/java/team/unnamed/mocha/parser/DoubleParseTest.java +++ b/parser/src/test/java/org/redlance/mocha/parser/DoubleParseTest.java @@ -1,34 +1,34 @@ -/* - * This file is part of mocha, licensed under the MIT license - * - * Copyright (c) 2021-2025 Unnamed Team - * - * 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. - */ -package team.unnamed.mocha.parser; +/* + * This file is part of mocha, licensed under the MIT license + * + * Copyright (c) 2021-2025 Unnamed Team + * + * 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. + */ +package org.redlance.mocha.parser; import org.junit.jupiter.api.Test; -import team.unnamed.mocha.parser.ast.FloatExpression; -import team.unnamed.mocha.parser.ast.IdentifierExpression; -import team.unnamed.mocha.parser.ast.UnaryExpression; +import org.redlance.mocha.parser.ast.FloatExpression; +import org.redlance.mocha.parser.ast.IdentifierExpression; +import org.redlance.mocha.parser.ast.UnaryExpression; -import static team.unnamed.mocha.MochaAssertions.assertCreateTree; +import static org.redlance.mocha.parser.ParserAssertions.assertCreateTree; class DoubleParseTest { @Test diff --git a/src/test/java/team/unnamed/mocha/parser/HierarchyTest.java b/parser/src/test/java/org/redlance/mocha/parser/HierarchyTest.java similarity index 92% rename from src/test/java/team/unnamed/mocha/parser/HierarchyTest.java rename to parser/src/test/java/org/redlance/mocha/parser/HierarchyTest.java index 45b8562..a404c27 100644 --- a/src/test/java/team/unnamed/mocha/parser/HierarchyTest.java +++ b/parser/src/test/java/org/redlance/mocha/parser/HierarchyTest.java @@ -1,43 +1,43 @@ -/* - * This file is part of mocha, licensed under the MIT license - * - * Copyright (c) 2021-2025 Unnamed Team - * - * 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. - */ -package team.unnamed.mocha.parser; +/* + * This file is part of mocha, licensed under the MIT license + * + * Copyright (c) 2021-2025 Unnamed Team + * + * 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. + */ +package org.redlance.mocha.parser; import org.junit.jupiter.api.Test; -import team.unnamed.mocha.MochaEngine; -import team.unnamed.mocha.parser.ast.BinaryExpression; -import team.unnamed.mocha.parser.ast.Expression; +import org.redlance.mocha.parser.ast.BinaryExpression; +import org.redlance.mocha.parser.ast.Expression; import java.util.List; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; -import static team.unnamed.mocha.MochaAssertions.assertCreateSameTree; +import static org.redlance.mocha.parser.ParserAssertions.assertCreateSameTree; +import static org.redlance.mocha.parser.ParserAssertions.parse; class HierarchyTest { @Test void test_logical_hierarchy() throws Exception { - List expressions = MochaEngine.createStandard().parse("age <= 5 || age >= 70"); + List expressions = parse("age <= 5 || age >= 70"); assertEquals(1, expressions.size(), "Size must be 1: " + expressions); expressions.forEach(System.out::println); diff --git a/src/test/java/team/unnamed/mocha/MochaAssertions.java b/parser/src/test/java/org/redlance/mocha/parser/ParserAssertions.java similarity index 62% rename from src/test/java/team/unnamed/mocha/MochaAssertions.java rename to parser/src/test/java/org/redlance/mocha/parser/ParserAssertions.java index b51715a..da70dcd 100644 --- a/src/test/java/team/unnamed/mocha/MochaAssertions.java +++ b/parser/src/test/java/org/redlance/mocha/parser/ParserAssertions.java @@ -21,31 +21,40 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -package team.unnamed.mocha; +package org.redlance.mocha.parser; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import org.jetbrains.annotations.NotNull; -import team.unnamed.mocha.parser.ParseException; -import team.unnamed.mocha.parser.ast.Expression; -import team.unnamed.mocha.util.ExprBytesUtils; +import org.redlance.mocha.parser.ast.Expression; +import org.redlance.mocha.parser.util.ExprBytesUtils; +import java.io.IOException; +import java.io.StringReader; import java.util.Arrays; import java.util.List; -import java.util.function.UnaryOperator; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.fail; -public final class MochaAssertions { - private MochaAssertions() { +public final class ParserAssertions { + private ParserAssertions() { throw new UnsupportedOperationException("This class cannot be instantiated"); } - public static void assertCreateSameTree(final @NotNull String expr1, final @NotNull String expr2) throws Exception { - final MochaEngine engine = MochaEngine.createStandard(); - final List expressions1 = engine.parse(expr1); - final List expressions2 = engine.parse(expr2); + public static @NotNull List parse(final @NotNull String expr) throws ParseException { + try (final StringReader reader = new StringReader(expr)) { + return MolangParser.parser(reader).parseAll(); + } catch (final ParseException e) { + throw e; + } catch (final IOException e) { + throw new AssertionError("StringReader IOException", e); + } + } + + public static void assertCreateSameTree(final @NotNull String expr1, final @NotNull String expr2) throws ParseException { + final List expressions1 = parse(expr1); + final List expressions2 = parse(expr2); assertEquals(expressions1, expressions2, () -> "Expressions:\n\t- " + expr1 + "\n\t- " + @@ -61,16 +70,15 @@ public static void assertCreateTree(final @NotNull String expr, final @NotNull E } public static void assertCreateTree(final @NotNull String expr, final List expressions) { - final MochaEngine engine = MochaEngine.createStandard(); final List parsed; try { - parsed = engine.parse(expr); + parsed = parse(expr); } catch (final ParseException e) { fail("Failed to parse expression: '" + expr + "'", e); return; } - { // Network testing + { // Network round-trip ByteBuf buf = Unpooled.buffer(); ExprBytesUtils.writeExpressions(expressions, buf); @@ -90,32 +98,11 @@ public static void assertCreateTree(final @NotNull String expr, final List engine = MochaEngine.createStandard(); try { - final List expressions = engine.parse(expr); + final List expressions = parse(expr); fail("Expected parse error at column " + column + " for expression: '" + expr + "', instead, it was parsed as: " + expressions); } catch (final ParseException e) { assertEquals(column, e.cursor().column(), "Expected parse error at column " + column + " for expression: '" + expr + "'"); } } - - public static void assertEvaluates(final double expected, final @NotNull String expr, final @NotNull UnaryOperator> configurer) { - MochaEngine engine = MochaEngine.createStandard(); - engine = configurer.apply(engine); - final double result = engine.eval(expr); - assertEquals(expected, result, 0.0001, () -> "Expression: '" + expr + "' evaluated to " + result + ", expected " + expected); - } - - public static void assertEvaluates(final double expected, final @NotNull String expr) { - assertEvaluates(expected, expr, engine -> engine); - } - - public static void assertEvaluatesAndCompiles(final double expected, final @NotNull String expr) { - final MochaEngine engine = MochaEngine.createStandard(); - final double result = engine.eval(expr); - assertEquals(expected, result, 0.0001, () -> "(Interpreted) expression: '" + expr + "' evaluated to " + result + ", expected " + expected); - - final double compiledResult = engine.compile(expr).evaluate(); - assertEquals(expected, compiledResult, 0.0001, () -> "(Compiled) expression: '" + expr + "' evaluated to " + compiledResult + ", expected " + expected); - } } diff --git a/src/test/java/team/unnamed/mocha/parser/StringTest.java b/parser/src/test/java/org/redlance/mocha/parser/StringTest.java similarity index 88% rename from src/test/java/team/unnamed/mocha/parser/StringTest.java rename to parser/src/test/java/org/redlance/mocha/parser/StringTest.java index c2d3187..6362963 100644 --- a/src/test/java/team/unnamed/mocha/parser/StringTest.java +++ b/parser/src/test/java/org/redlance/mocha/parser/StringTest.java @@ -21,12 +21,11 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -package team.unnamed.mocha.parser; +package org.redlance.mocha.parser; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; -import team.unnamed.mocha.MochaEngine; -import team.unnamed.mocha.util.ExpressionListUtils; +import org.redlance.mocha.parser.util.ExpressionListUtils; import java.io.IOException; @@ -36,10 +35,10 @@ public class StringTest { private static void testToString(String expr) throws IOException { System.out.println("expr " + expr); - String original = ExpressionListUtils.toString(MochaEngine.createStandard().parse(expr)); + String original = ExpressionListUtils.toString(MolangParser.parseAll(expr)); System.out.println("original " + original); - String parsed = ExpressionListUtils.toString(MochaEngine.createStandard().parse(original)); + String parsed = ExpressionListUtils.toString(MolangParser.parseAll(original)); System.out.println("parsed " + parsed); System.out.flush(); diff --git a/src/test/java/team/unnamed/mocha/parser/TernaryParseTest.java b/parser/src/test/java/org/redlance/mocha/parser/TernaryParseTest.java similarity index 94% rename from src/test/java/team/unnamed/mocha/parser/TernaryParseTest.java rename to parser/src/test/java/org/redlance/mocha/parser/TernaryParseTest.java index 0b4a024..55c1972 100644 --- a/src/test/java/team/unnamed/mocha/parser/TernaryParseTest.java +++ b/parser/src/test/java/org/redlance/mocha/parser/TernaryParseTest.java @@ -1,34 +1,34 @@ -/* - * This file is part of mocha, licensed under the MIT license - * - * Copyright (c) 2021-2025 Unnamed Team - * - * 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. - */ -package team.unnamed.mocha.parser; +/* + * This file is part of mocha, licensed under the MIT license + * + * Copyright (c) 2021-2025 Unnamed Team + * + * 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. + */ +package org.redlance.mocha.parser; import org.junit.jupiter.api.Test; -import team.unnamed.mocha.parser.ast.*; +import org.redlance.mocha.parser.ast.*; import java.util.Collections; -import static team.unnamed.mocha.MochaAssertions.assertCreateTree; +import static org.redlance.mocha.parser.ParserAssertions.assertCreateTree; class TernaryParseTest { @Test diff --git a/runtime-compiler/build.gradle b/runtime-compiler/build.gradle new file mode 100644 index 0000000..2b9ecfd --- /dev/null +++ b/runtime-compiler/build.gradle @@ -0,0 +1,24 @@ +plugins { + id "org.jetbrains.kotlin.jvm" +} + +dependencies { + api project(":runtime") + + testImplementation("org.jetbrains.kotlin:kotlin-stdlib:2.3.21") +} + +tasks.register('generateExpectations', Exec) { + workingDir = rootProject.projectDir + def nvmDir = file("${System.getenv('HOME')}/.nvm/versions/node") + executable nvmDir.isDirectory() ? "${nvmDir.listFiles().sort().last()}/bin/node" : 'node' + args 'scripts/generate_expectations.js' +} + +tasks.named("compileTestKotlin") { + enabled = true +} + +tasks.named("test") { + dependsOn tasks.named("generateExpectations") +} diff --git a/src/main/java/team/unnamed/mocha/runtime/CompileVisitResult.java b/runtime-compiler/src/main/java/org/redlance/mocha/runtime/CompileVisitResult.java similarity index 96% rename from src/main/java/team/unnamed/mocha/runtime/CompileVisitResult.java rename to runtime-compiler/src/main/java/org/redlance/mocha/runtime/CompileVisitResult.java index b7889a9..af35af5 100644 --- a/src/main/java/team/unnamed/mocha/runtime/CompileVisitResult.java +++ b/runtime-compiler/src/main/java/org/redlance/mocha/runtime/CompileVisitResult.java @@ -21,13 +21,15 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -package team.unnamed.mocha.runtime; +package org.redlance.mocha.runtime; +import com.google.j2objc.annotations.J2ObjCIncompatible; import org.jetbrains.annotations.Nullable; import java.lang.constant.ClassDesc; import java.lang.constant.ConstantDescs; +@J2ObjCIncompatible final class CompileVisitResult { static final CompileVisitResult FLOAT = new CompileVisitResult(ConstantDescs.CD_float); static final CompileVisitResult DOUBLE = new CompileVisitResult(ConstantDescs.CD_double); diff --git a/src/main/java/team/unnamed/mocha/runtime/FunctionCompileState.java b/runtime-compiler/src/main/java/org/redlance/mocha/runtime/FunctionCompileState.java similarity index 94% rename from src/main/java/team/unnamed/mocha/runtime/FunctionCompileState.java rename to runtime-compiler/src/main/java/org/redlance/mocha/runtime/FunctionCompileState.java index 2e6423b..d61f47e 100644 --- a/src/main/java/team/unnamed/mocha/runtime/FunctionCompileState.java +++ b/runtime-compiler/src/main/java/org/redlance/mocha/runtime/FunctionCompileState.java @@ -21,10 +21,11 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -package team.unnamed.mocha.runtime; +package org.redlance.mocha.runtime; +import com.google.j2objc.annotations.J2ObjCIncompatible; import org.jetbrains.annotations.NotNull; -import team.unnamed.mocha.util.CaseInsensitiveStringHashMap; +import org.redlance.mocha.runtime.util.CaseInsensitiveStringHashMap; import java.lang.classfile.CodeBuilder; import java.lang.constant.ClassDesc; @@ -33,6 +34,7 @@ import static java.util.Objects.requireNonNull; +@J2ObjCIncompatible final class FunctionCompileState { private final MolangCompiler compiler; diff --git a/runtime-compiler/src/main/java/org/redlance/mocha/runtime/MochaEngine.java b/runtime-compiler/src/main/java/org/redlance/mocha/runtime/MochaEngine.java new file mode 100644 index 0000000..5bb0231 --- /dev/null +++ b/runtime-compiler/src/main/java/org/redlance/mocha/runtime/MochaEngine.java @@ -0,0 +1,100 @@ +/* + * This file is part of mocha, licensed under the MIT license + * + * Copyright (c) 2021-2025 Unnamed Team + * + * 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. + */ +package org.redlance.mocha.runtime; + +import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.NotNull; +import org.redlance.mocha.parser.MolangParser; + +/** + * Convenience holder that bundles a {@link MolangInterpreter} and a + * {@link MolangCompiler} sharing the same {@link Scope}. + * + *

The engine itself does not implement the parsing / interpreter / compiler + * APIs — those live on {@link MolangParser}, {@link MolangInterpreter} and + * {@link MolangCompiler}, accessed via {@link #interpreter()} and + * {@link #compiler()}. This class only exists so that callers that want both + * can construct them in one go with a shared scope.

+ * + * @since 3.0.0 + */ +public final class MochaEngine { + private final MolangInterpreter interpreter; + private final MolangCompiler compiler; + + public MochaEngine(final @NotNull MolangInterpreter interpreter, final @NotNull MolangCompiler compiler) { + this.interpreter = interpreter; + this.compiler = compiler; + } + + /** + * Builds a {@link MochaEngine} on top of an existing {@link MolangInterpreter}, + * sharing its {@link Scope} and entity with a freshly created + * {@link MolangCompiler}. + * + * @since 5.0.0 + */ + @Contract("_ -> new") + public static @NotNull MochaEngine from(final @NotNull MolangInterpreter interpreter) { + return new MochaEngine<>(interpreter, new MolangCompiler(interpreter.entity(), interpreter.scope())); + } + + @Contract("_ -> new") + public static @NotNull MochaEngine create(final T entity) { + return from(MolangInterpreter.create(entity)); + } + + @Contract("-> new") + public static @NotNull MochaEngine create() { + return from(MolangInterpreter.create()); + } + + /** + * Creates a {@link MochaEngine} pre-populated with the standard + * {@code math} / {@code variable} / {@code v} bindings. + * + * @since 3.0.0 + */ + @Contract("_ -> new") + public static @NotNull MochaEngine createStandard(final T entity) { + return from(MolangInterpreter.standard(entity)); + } + + @Contract("-> new") + public static @NotNull MochaEngine createStandard() { + return from(MolangInterpreter.standard()); + } + + public @NotNull MolangInterpreter interpreter() { + return interpreter; + } + + public @NotNull MolangCompiler compiler() { + return compiler; + } + + public @NotNull Scope scope() { + return interpreter.scope(); + } +} diff --git a/src/main/java/team/unnamed/mocha/runtime/MochaFunction.java b/runtime-compiler/src/main/java/org/redlance/mocha/runtime/MochaFunction.java similarity index 89% rename from src/main/java/team/unnamed/mocha/runtime/MochaFunction.java rename to runtime-compiler/src/main/java/org/redlance/mocha/runtime/MochaFunction.java index 2831a17..92f36a5 100644 --- a/src/main/java/team/unnamed/mocha/runtime/MochaFunction.java +++ b/runtime-compiler/src/main/java/org/redlance/mocha/runtime/MochaFunction.java @@ -1,30 +1,31 @@ -/* - * This file is part of mocha, licensed under the MIT license - * - * Copyright (c) 2021-2025 Unnamed Team - * - * 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. - */ -package team.unnamed.mocha.runtime; +/* + * This file is part of mocha, licensed under the MIT license + * + * Copyright (c) 2021-2025 Unnamed Team + * + * 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. + */ +package org.redlance.mocha.runtime; +import com.google.j2objc.annotations.ReflectionSupport; import org.jetbrains.annotations.NotNull; -import team.unnamed.mocha.runtime.compiled.MochaCompiledFunction; +import org.redlance.mocha.runtime.compiled.MochaCompiledFunction; /** * A {@link MochaCompiledFunction} that can be evaluated without arguments. @@ -32,6 +33,7 @@ * @since 3.0.0 */ @FunctionalInterface +@ReflectionSupport(ReflectionSupport.Level.FULL) public interface MochaFunction extends MochaCompiledFunction { static @NotNull MochaFunction nop() { return NopMochaFunctionHolder.NOP; diff --git a/src/main/java/team/unnamed/mocha/runtime/MolangCompiler.java b/runtime-compiler/src/main/java/org/redlance/mocha/runtime/MolangCompiler.java similarity index 75% rename from src/main/java/team/unnamed/mocha/runtime/MolangCompiler.java rename to runtime-compiler/src/main/java/org/redlance/mocha/runtime/MolangCompiler.java index 75688be..4e15b2b 100644 --- a/src/main/java/team/unnamed/mocha/runtime/MolangCompiler.java +++ b/runtime-compiler/src/main/java/org/redlance/mocha/runtime/MolangCompiler.java @@ -1,280 +1,377 @@ -/* - * This file is part of mocha, licensed under the MIT license - * - * Copyright (c) 2021-2025 Unnamed Team - * - * 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. - */ -package team.unnamed.mocha.runtime; - -import org.jetbrains.annotations.ApiStatus; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import team.unnamed.mocha.parser.ast.Expression; -import team.unnamed.mocha.runtime.compiled.MochaCompiledFunction; -import team.unnamed.mocha.runtime.compiled.Named; -import team.unnamed.mocha.util.CaseInsensitiveStringHashMap; -import team.unnamed.mocha.util.ClassFileUtil; - -import java.lang.classfile.ClassFile; -import java.lang.constant.ClassDesc; -import java.lang.constant.ConstantDescs; -import java.lang.constant.MethodTypeDesc; -import java.lang.invoke.MethodHandles; -import java.lang.reflect.Constructor; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.lang.reflect.Modifier; -import java.lang.reflect.Parameter; -import java.util.List; -import java.util.Map; -import java.util.concurrent.atomic.AtomicLong; -import java.util.function.Consumer; - -import static java.util.Objects.requireNonNull; -import static team.unnamed.mocha.util.ClassFileUtil.classDescOf; - -@ApiStatus.Internal -public final class MolangCompiler { - private static final AtomicLong CLASS_NAME_COUNTER = new AtomicLong(); - - private final Object entity; - private final Scope scope; - private Consumer postCompile; - - public MolangCompiler(final @Nullable Object entity, final @NotNull Scope scope) { - this.entity = entity; - this.scope = requireNonNull(scope, "scope"); - } - - public @Nullable Object entity() { - return entity; - } - - public void postCompile(final @Nullable Consumer postCompile) { - this.postCompile = postCompile; - } - - public @NotNull T compile(final @NotNull List expressions, final @NotNull Class clazz) { - requireNonNull(expressions, "expressions"); - requireNonNull(clazz, "clazz"); - - if (clazz == MochaFunction.class && expressions.isEmpty()) { - // no expressions and the target type is MochaFunction, - // we know the NOP function - return clazz.cast(MochaFunction.nop()); - } - - if (!clazz.isInterface()) { - throw new IllegalArgumentException("Target type must be an interface: " + clazz.getName()); - } - - Method implementedMethod = null; - for (final Method method : clazz.getDeclaredMethods()) { - if (Modifier.isStatic(method.getModifiers()) || method.isDefault()) { - continue; - } - if (implementedMethod != null) { - throw new IllegalArgumentException("Target type must have only one method: " + clazz.getName()); - } - implementedMethod = method; - } - - if (implementedMethod == null) { - throw new IllegalArgumentException("Target type must have a method to implement: " + clazz.getName()); - } - - final Map argumentParameterIndexes = new CaseInsensitiveStringHashMap<>(); - final ClassDesc[] paramDescs; - - // check method parameter types - { - final Parameter[] parameters = implementedMethod.getParameters(); - paramDescs = new ClassDesc[parameters.length]; - - for (int i = 0; i < parameters.length; ++i) { - final Parameter parameter = parameters[i]; - final Named named = parameter.getDeclaredAnnotation(Named.class); - final String name; - - if (named != null) { - name = named.value(); - } else if (parameter.isNamePresent()) { - name = parameter.getName(); - } else { - throw new IllegalArgumentException("Parameter " + parameter.getName() + " (index " + i - + ") must be annotated with @Named and specify a name"); - } - - argumentParameterIndexes.put(name, i); - paramDescs[i] = classDescOf(parameter.getType()); - } - } - - final ClassDesc interfaceDesc = classDescOf(clazz); - final String scriptClassName = getClass().getPackage().getName() + ".MolangFunctionImpl_" + clazz.getSimpleName() + "_" + implementedMethod.getName() - + "_" + Long.toHexString(CLASS_NAME_COUNTER.incrementAndGet()); - - final ClassDesc scriptClassDesc = ClassDesc.of(scriptClassName); - final ClassDesc returnDesc = classDescOf(implementedMethod.getReturnType()); - final MethodTypeDesc mainMethodTypeDesc = MethodTypeDesc.of(returnDesc, paramDescs); - - // We need to capture requirements and other state from within the lambda - final Map requirements = new CaseInsensitiveStringHashMap<>(); - final Method finalMethod = implementedMethod; - - final byte[] classBytes = ClassFile.of().build(scriptClassDesc, classBuilder -> { - classBuilder.withFlags(Modifier.PUBLIC | Modifier.FINAL); - classBuilder.withInterfaceSymbols(interfaceDesc); - - // compute initial max locals - final int initialMaxLocals; - { - int maxLocals = 1; // 1: this - for (final ClassDesc paramType : paramDescs) { - if (paramType.equals(ConstantDescs.CD_double) || paramType.equals(ConstantDescs.CD_long)) { - maxLocals += 2; - } else { - maxLocals++; - } - } - initialMaxLocals = maxLocals; - } - - // Add main method - classBuilder.withMethod( - finalMethod.getName(), - mainMethodTypeDesc, - Modifier.PUBLIC | Modifier.FINAL, - methodBuilder -> methodBuilder.withCode(codeBuilder -> { - final FunctionCompileState compileState = new FunctionCompileState( - this, scriptClassDesc, codeBuilder, finalMethod, scope, argumentParameterIndexes - ); - compileState.maxLocals(initialMaxLocals); - - // Copy requirements reference so visitor can populate it - final Map stateRequirements = compileState.requirements(); - - if (expressions.isEmpty()) { - ClassFileUtil.addConstZero(codeBuilder, returnDesc); - ClassFileUtil.addReturn(codeBuilder, returnDesc); - } else { - final MolangCompilingVisitor compiler = new MolangCompilingVisitor(compileState); - CompileVisitResult lastVisitResult = null; - - final ExpressionInliner inliner = new ExpressionInliner(new ExpressionInterpreter<>(null, scope), scope); - - for (final Expression expression : expressions) { - lastVisitResult = expression.visit(inliner).visit(compiler); - } - - if (lastVisitResult == null || !lastVisitResult.returned()) { - if (lastVisitResult == null || !returnDesc.equals(lastVisitResult.lastPushedType())) { - ClassFileUtil.addCast( - codeBuilder, - lastVisitResult == null ? ConstantDescs.CD_float : lastVisitResult.lastPushedType(), - returnDesc - ); - } - - compiler.endVisit(); - } - } - - // Copy requirements from compile state to outer map - requirements.putAll(stateRequirements); - })); - - // Add fields for requirements (populated during method compilation above) - for (final Map.Entry entry : requirements.entrySet()) { - final String fieldName = entry.getKey(); - final Object fieldValue = entry.getValue(); - final ClassDesc fieldType = classDescOf(fieldValue.getClass()); - classBuilder.withField(fieldName, fieldType, Modifier.PRIVATE); - } - - // Add constructor - final ClassDesc[] constructorParamDescs = new ClassDesc[requirements.size()]; - int j = 0; - for (final Map.Entry entry : requirements.entrySet()) { - constructorParamDescs[j] = classDescOf(entry.getValue().getClass()); - ++j; - } - - final MethodTypeDesc constructorTypeDesc = MethodTypeDesc.of(ConstantDescs.CD_void, constructorParamDescs); - classBuilder.withMethod( - ConstantDescs.INIT_NAME, - constructorTypeDesc, - Modifier.PUBLIC, - methodBuilder -> methodBuilder.withCode(ctorCode -> { - ctorCode.aload(0); - ctorCode.invokespecial(ConstantDescs.CD_Object, ConstantDescs.INIT_NAME, ConstantDescs.MTD_void); - - int parameterIndex = 0; - for (final Map.Entry entry : requirements.entrySet()) { - final String fieldName = entry.getKey(); - final Object fieldValue = entry.getValue(); - final ClassDesc fieldType = classDescOf(fieldValue.getClass()); - ctorCode.aload(0); // this - ctorCode.aload(parameterIndex + 1); // parameter - ctorCode.putfield(scriptClassDesc, fieldName, fieldType); - parameterIndex++; - } - ctorCode.return_(); - })); - }); - - if (postCompile != null) { - postCompile.accept(classBytes); - } - - final Class compiledClass; - try { - compiledClass = MethodHandles.lookup() - .defineHiddenClass(classBytes, true, MethodHandles.Lookup.ClassOption.NESTMATE) - .lookupClass(); - } catch (final IllegalAccessException e) { - throw new IllegalStateException("Couldn't define hidden class", e); - } - - // find the constructor with the requirements - final Class[] constructorParameterTypes = new Class[requirements.size()]; - final Object[] constructorArguments = new Object[requirements.size()]; - int i = 0; - for (final Object requirement : requirements.values()) { - constructorParameterTypes[i] = requirement.getClass(); - constructorArguments[i] = requirement; - ++i; - } - - final Constructor constructor; - try { - constructor = compiledClass.getDeclaredConstructor(constructorParameterTypes); - } catch (final NoSuchMethodException e) { - throw new IllegalStateException("Couldn't find constructor with parameters " + requirements.keySet(), e); - } - final Object instance; - try { - instance = constructor.newInstance(constructorArguments); - } catch (InstantiationException | IllegalAccessException | InvocationTargetException e) { - throw new IllegalStateException("Couldn't instantiate script class", e); - } - return clazz.cast(instance); - } -} +/* + * This file is part of mocha, licensed under the MIT license + * + * Copyright (c) 2021-2025 Unnamed Team + * + * 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. + */ +package org.redlance.mocha.runtime; + +import com.google.j2objc.annotations.J2ObjCIncompatible; +import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.redlance.mocha.parser.MolangParser; +import org.redlance.mocha.parser.ParseException; +import org.redlance.mocha.parser.ast.Expression; +import org.redlance.mocha.runtime.compiled.MochaCompiledFunction; +import org.redlance.mocha.runtime.compiled.Named; +import org.redlance.mocha.runtime.util.CaseInsensitiveStringHashMap; +import org.redlance.mocha.runtime.util.ClassFileUtil; + +import java.io.IOException; +import java.io.Reader; +import java.io.StringReader; +import java.io.UncheckedIOException; +import java.lang.classfile.ClassFile; +import java.lang.constant.ClassDesc; +import java.lang.constant.ConstantDescs; +import java.lang.constant.MethodTypeDesc; +import java.lang.invoke.MethodHandles; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.lang.reflect.Parameter; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.concurrent.atomic.AtomicLong; +import java.util.function.Consumer; + +import static java.util.Objects.requireNonNull; +import static org.redlance.mocha.runtime.util.ClassFileUtil.classDescOf; + +@J2ObjCIncompatible +public final class MolangCompiler { + private static final AtomicLong CLASS_NAME_COUNTER = new AtomicLong(); + + private final Object entity; + private final Scope scope; + private Consumer postCompile; + private Consumer<@NotNull ParseException> parseExceptionHandler; + + public MolangCompiler(final @Nullable Object entity, final @NotNull Scope scope) { + this.entity = entity; + this.scope = requireNonNull(scope, "scope"); + } + + public @Nullable Object entity() { + return entity; + } + + /** + * Sets the post-compile function, called after a script is compiled to a + * new class but before the class is loaded. The argument is the class + * bytecode, useful for writing it to a file for debugging. + * + *

By default this is null.

+ * + * @return This compiler instance. + * @since 3.0.0 + */ + @Contract("_ -> this") + public @NotNull MolangCompiler postCompile(final @Nullable Consumer postCompile) { + this.postCompile = postCompile; + return this; + } + + /** + * Sets the {@link ParseException} handler. Called whenever an internal + * call to {@link MolangParser} from {@link #compile(Reader, Class)} or + * its overloads fails. After the handler runs, the offending compile + * call falls back to compiling an empty body. + * + *

By default this is null.

+ * + * @return This compiler instance. + * @since 3.0.0 + */ + @Contract("_ -> this") + public @NotNull MolangCompiler handleParseExceptions(final @Nullable Consumer<@NotNull ParseException> exceptionHandler) { + this.parseExceptionHandler = exceptionHandler; + return this; + } + + public @NotNull T compile(final @NotNull List expressions, final @NotNull Class clazz) { + requireNonNull(expressions, "expressions"); + requireNonNull(clazz, "clazz"); + + if (clazz == MochaFunction.class && expressions.isEmpty()) { + // no expressions and the target type is MochaFunction, + // we know the NOP function + return clazz.cast(MochaFunction.nop()); + } + + if (!clazz.isInterface()) { + throw new IllegalArgumentException("Target type must be an interface: " + clazz.getName()); + } + + Method implementedMethod = null; + for (final Method method : clazz.getDeclaredMethods()) { + if (Modifier.isStatic(method.getModifiers()) || method.isDefault()) { + continue; + } + if (implementedMethod != null) { + throw new IllegalArgumentException("Target type must have only one method: " + clazz.getName()); + } + implementedMethod = method; + } + + if (implementedMethod == null) { + throw new IllegalArgumentException("Target type must have a method to implement: " + clazz.getName()); + } + + final Map argumentParameterIndexes = new CaseInsensitiveStringHashMap<>(); + final ClassDesc[] paramDescs; + + // check method parameter types + { + final Parameter[] parameters = implementedMethod.getParameters(); + paramDescs = new ClassDesc[parameters.length]; + + for (int i = 0; i < parameters.length; ++i) { + final Parameter parameter = parameters[i]; + final Named named = parameter.getDeclaredAnnotation(Named.class); + final String name; + + if (named != null) { + name = named.value(); + } else if (parameter.isNamePresent()) { + name = parameter.getName(); + } else { + throw new IllegalArgumentException("Parameter " + parameter.getName() + " (index " + i + + ") must be annotated with @Named and specify a name"); + } + + argumentParameterIndexes.put(name, i); + paramDescs[i] = classDescOf(parameter.getType()); + } + } + + final ClassDesc interfaceDesc = classDescOf(clazz); + final String scriptClassName = getClass().getPackage().getName() + ".MolangFunctionImpl_" + clazz.getSimpleName() + "_" + implementedMethod.getName() + + "_" + Long.toHexString(CLASS_NAME_COUNTER.incrementAndGet()); + + final ClassDesc scriptClassDesc = ClassDesc.of(scriptClassName); + final ClassDesc returnDesc = classDescOf(implementedMethod.getReturnType()); + final MethodTypeDesc mainMethodTypeDesc = MethodTypeDesc.of(returnDesc, paramDescs); + + // We need to capture requirements and other state from within the lambda + final Map requirements = new CaseInsensitiveStringHashMap<>(); + final Method finalMethod = implementedMethod; + + final byte[] classBytes = ClassFile.of().build(scriptClassDesc, classBuilder -> { + classBuilder.withFlags(Modifier.PUBLIC | Modifier.FINAL); + classBuilder.withInterfaceSymbols(interfaceDesc); + + // compute initial max locals + final int initialMaxLocals; + { + int maxLocals = 1; // 1: this + for (final ClassDesc paramType : paramDescs) { + if (paramType.equals(ConstantDescs.CD_double) || paramType.equals(ConstantDescs.CD_long)) { + maxLocals += 2; + } else { + maxLocals++; + } + } + initialMaxLocals = maxLocals; + } + + // Add main method + classBuilder.withMethod( + finalMethod.getName(), + mainMethodTypeDesc, + Modifier.PUBLIC | Modifier.FINAL, + methodBuilder -> methodBuilder.withCode(codeBuilder -> { + final FunctionCompileState compileState = new FunctionCompileState( + this, scriptClassDesc, codeBuilder, finalMethod, scope, argumentParameterIndexes + ); + compileState.maxLocals(initialMaxLocals); + + // Copy requirements reference so visitor can populate it + final Map stateRequirements = compileState.requirements(); + + if (expressions.isEmpty()) { + ClassFileUtil.addConstZero(codeBuilder, returnDesc); + ClassFileUtil.addReturn(codeBuilder, returnDesc); + } else { + final MolangCompilingVisitor compiler = new MolangCompilingVisitor(compileState); + CompileVisitResult lastVisitResult = null; + + final ExpressionInliner inliner = new ExpressionInliner(new ExpressionInterpreter<>(null, scope), scope); + + for (final Expression expression : expressions) { + lastVisitResult = expression.visit(inliner).visit(compiler); + } + + if (lastVisitResult == null || !lastVisitResult.returned()) { + if (lastVisitResult == null || !returnDesc.equals(lastVisitResult.lastPushedType())) { + ClassFileUtil.addCast( + codeBuilder, + lastVisitResult == null ? ConstantDescs.CD_float : lastVisitResult.lastPushedType(), + returnDesc + ); + } + + compiler.endVisit(); + } + } + + // Copy requirements from compile state to outer map + requirements.putAll(stateRequirements); + })); + + // Add fields for requirements (populated during method compilation above) + for (final Map.Entry entry : requirements.entrySet()) { + final String fieldName = entry.getKey(); + final Object fieldValue = entry.getValue(); + final ClassDesc fieldType = classDescOf(fieldValue.getClass()); + classBuilder.withField(fieldName, fieldType, Modifier.PRIVATE); + } + + // Add constructor + final ClassDesc[] constructorParamDescs = new ClassDesc[requirements.size()]; + int j = 0; + for (final Map.Entry entry : requirements.entrySet()) { + constructorParamDescs[j] = classDescOf(entry.getValue().getClass()); + ++j; + } + + final MethodTypeDesc constructorTypeDesc = MethodTypeDesc.of(ConstantDescs.CD_void, constructorParamDescs); + classBuilder.withMethod( + ConstantDescs.INIT_NAME, + constructorTypeDesc, + Modifier.PUBLIC, + methodBuilder -> methodBuilder.withCode(ctorCode -> { + ctorCode.aload(0); + ctorCode.invokespecial(ConstantDescs.CD_Object, ConstantDescs.INIT_NAME, ConstantDescs.MTD_void); + + int parameterIndex = 0; + for (final Map.Entry entry : requirements.entrySet()) { + final String fieldName = entry.getKey(); + final Object fieldValue = entry.getValue(); + final ClassDesc fieldType = classDescOf(fieldValue.getClass()); + ctorCode.aload(0); // this + ctorCode.aload(parameterIndex + 1); // parameter + ctorCode.putfield(scriptClassDesc, fieldName, fieldType); + parameterIndex++; + } + ctorCode.return_(); + })); + }); + + if (postCompile != null) { + postCompile.accept(classBytes); + } + + final Class compiledClass; + try { + compiledClass = MethodHandles.lookup() + .defineHiddenClass(classBytes, true, MethodHandles.Lookup.ClassOption.NESTMATE) + .lookupClass(); + } catch (final IllegalAccessException e) { + throw new IllegalStateException("Couldn't define hidden class", e); + } + + // find the constructor with the requirements + final Class[] constructorParameterTypes = new Class[requirements.size()]; + final Object[] constructorArguments = new Object[requirements.size()]; + int i = 0; + for (final Object requirement : requirements.values()) { + constructorParameterTypes[i] = requirement.getClass(); + constructorArguments[i] = requirement; + ++i; + } + + final Constructor constructor; + try { + constructor = compiledClass.getDeclaredConstructor(constructorParameterTypes); + } catch (final NoSuchMethodException e) { + throw new IllegalStateException("Couldn't find constructor with parameters " + requirements.keySet(), e); + } + final Object instance; + try { + instance = constructor.newInstance(constructorArguments); + } catch (InstantiationException | IllegalAccessException | InvocationTargetException e) { + throw new IllegalStateException("Couldn't instantiate script class", e); + } + return clazz.cast(instance); + } + + /** + * Parses {@code reader} and compiles the resulting AST into the given + * {@code interfaceType}. Parse errors are routed through + * {@link #handleParseExceptions(Consumer)}; on a parse failure the + * compiler falls back to compiling an empty body. + * + * @since 3.0.0 + */ + public @NotNull T compile(final @NotNull Reader reader, final @NotNull Class interfaceType) { + List parsed; + try { + parsed = MolangParser.parseAll(reader); + } catch (final ParseException e) { + if (parseExceptionHandler != null) parseExceptionHandler.accept(e); + parsed = Collections.emptyList(); + } catch (final IOException e) { + throw new UncheckedIOException("Failed to read from given reader", e); + } + return compile(parsed, interfaceType); + } + + /** + * @see #compile(Reader, Class) + * @since 3.0.0 + */ + public @NotNull T compile(final @NotNull String code, final @NotNull Class interfaceType) { + requireNonNull(code, "code"); + try (final StringReader reader = new StringReader(code)) { + return compile(reader, interfaceType); + } + } + + /** + * Compiles the given expressions into a no-arg {@link MochaFunction}. + * + * @since 4.0.4 + */ + public @NotNull MochaFunction compile(final @NotNull List expressions) { + return compile(expressions, MochaFunction.class); + } + + /** + * Parses {@code reader} and compiles the resulting AST into a no-arg + * {@link MochaFunction}. + * + * @since 3.0.0 + */ + public @NotNull MochaFunction compile(final @NotNull Reader reader) { + return compile(reader, MochaFunction.class); + } + + /** + * @see #compile(Reader) + * @since 3.0.0 + */ + public @NotNull MochaFunction compile(final @NotNull String code) { + return compile(code, MochaFunction.class); + } +} diff --git a/src/main/java/team/unnamed/mocha/runtime/MolangCompilingVisitor.java b/runtime-compiler/src/main/java/org/redlance/mocha/runtime/MolangCompilingVisitor.java similarity index 95% rename from src/main/java/team/unnamed/mocha/runtime/MolangCompilingVisitor.java rename to runtime-compiler/src/main/java/org/redlance/mocha/runtime/MolangCompilingVisitor.java index bba9470..7f10fb9 100644 --- a/src/main/java/team/unnamed/mocha/runtime/MolangCompilingVisitor.java +++ b/runtime-compiler/src/main/java/org/redlance/mocha/runtime/MolangCompilingVisitor.java @@ -1,650 +1,652 @@ -/* - * This file is part of mocha, licensed under the MIT license - * - * Copyright (c) 2021-2025 Unnamed Team - * - * 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. - */ -package team.unnamed.mocha.runtime; - -import org.jetbrains.annotations.NotNull; -import team.unnamed.mocha.parser.ast.*; -import team.unnamed.mocha.runtime.binding.Entity; -import team.unnamed.mocha.runtime.binding.JavaFieldBinding; -import team.unnamed.mocha.runtime.binding.JavaFunction; -import team.unnamed.mocha.runtime.binding.JavaObjectBinding; -import team.unnamed.mocha.runtime.value.Function; -import team.unnamed.mocha.runtime.value.NumberValue; -import team.unnamed.mocha.runtime.value.ObjectValue; -import team.unnamed.mocha.runtime.value.Value; -import team.unnamed.mocha.util.CaseInsensitiveStringHashMap; -import team.unnamed.mocha.util.ClassFileUtil; - -import java.lang.classfile.CodeBuilder; -import java.lang.classfile.Label; -import java.lang.constant.ClassDesc; -import java.lang.constant.MethodTypeDesc; -import java.lang.reflect.Field; -import java.lang.reflect.Method; -import java.lang.reflect.Modifier; -import java.lang.reflect.Parameter; -import java.util.Iterator; -import java.util.List; -import java.util.Locale; -import java.util.Map; - -import static java.lang.constant.ConstantDescs.*; -import static team.unnamed.mocha.util.ClassFileUtil.*; - -final class MolangCompilingVisitor implements ExpressionVisitor { - - private final CodeBuilder codeBuilder; - private final Method method; - - private final FunctionCompileState functionCompileState; - private final Map requirements; - private final Map argumentParameterIndexes; - - private final Map localsByName = new CaseInsensitiveStringHashMap<>(); - - private final ExpressionVisitor scopeResolver; - - /** - * The method return type - */ - private final ClassDesc methodReturnType; - /** - * The type that the current visitor method is expecting - * to be pushed to the stack. - */ - private ClassDesc expectedType; - - MolangCompilingVisitor(final @NotNull FunctionCompileState compileState) { - this.functionCompileState = compileState; - this.codeBuilder = compileState.codeBuilder(); - this.method = compileState.method(); - this.requirements = compileState.requirements(); - this.argumentParameterIndexes = compileState.argumentParameterIndexes(); - - this.methodReturnType = classDescOf(method.getReturnType()); - expectedType = methodReturnType; - - this.scopeResolver = new ExpressionVisitor<>() { - @Override - public @NotNull Value visitIdentifier(final @NotNull IdentifierExpression expression) { - return functionCompileState.scope().get(expression.name()); - } - - @Override - public @NotNull Value visitAccess(final @NotNull AccessExpression expression) { - final Value object = expression.object().visit(this); - if (object instanceof ObjectValue) { - return ((ObjectValue) object).get(expression.property()); - } else { - return NumberValue.zero(); - } - } - - @Override - public @NotNull Value visit(final @NotNull Expression expression) { - return NumberValue.zero(); - } - }; - } - - @Override - public CompileVisitResult visitBinary(final @NotNull BinaryExpression expression) { - final BinaryExpression.Op op = expression.op(); - - if (op == BinaryExpression.Op.ASSIGN) { - final Expression left = expression.left(); - if (left instanceof AccessExpression) { - final Expression objectExpr = ((AccessExpression) left).object(); - if (objectExpr instanceof IdentifierExpression) { - final String name = ((IdentifierExpression) objectExpr).name(); - final String property = ((AccessExpression) left).property(); - - if (name.equals("temp") || name.equals("t")) { - final CompileVisitResult result = expression.right().visit(this); - final int localIndex = localsByName.computeIfAbsent(property, k -> { - int index = functionCompileState.maxLocals(); - if (result.lastPushedType() != null && - (result.lastPushedType().equals(CD_double) || result.lastPushedType().equals(CD_long))) { - functionCompileState.maxLocals(index + 2); - } else { - functionCompileState.maxLocals(index + 1); - } - return index; - }); - codeBuilder.fstore(localIndex); - return null; - } - } - } - } - - final ClassDesc currentExpectedType = expectedType; - - //@formatter:off - switch (op) { - case AND: { - expectedType = CD_boolean; - expression.left().visit(this); - Label falseLabel = codeBuilder.newLabel(); - codeBuilder.ifeq(falseLabel); - expression.right().visit(this); - Label trueEnd = codeBuilder.newLabel(); - codeBuilder.ifeq(falseLabel); - addConst1(currentExpectedType); - codeBuilder.goto_(trueEnd); - codeBuilder.labelBinding(falseLabel); - addConst0(currentExpectedType); - codeBuilder.labelBinding(trueEnd); - expectedType = currentExpectedType; - return new CompileVisitResult(currentExpectedType); - } - case OR: { - expectedType = CD_boolean; - expression.left().visit(this); - Label trueLabel = codeBuilder.newLabel(); - codeBuilder.ifne(trueLabel); - expression.right().visit(this); - Label falseLabel = codeBuilder.newLabel(); - codeBuilder.ifeq(falseLabel); - codeBuilder.labelBinding(trueLabel); - addConst1(currentExpectedType); - Label end = codeBuilder.newLabel(); - codeBuilder.goto_(end); - codeBuilder.labelBinding(falseLabel); - addConst0(currentExpectedType); - codeBuilder.labelBinding(end); - expectedType = currentExpectedType; - return new CompileVisitResult(currentExpectedType); - } - case EQ: - case NEQ: - case LT: - case LTE: - case GT: - case GTE: { - expectedType = CD_float; - expression.left().visit(this); // pushes lhs value to stack - expression.right().visit(this); // pushes rhs value to stack - expectedType = currentExpectedType; - - codeBuilder.fcmpl(); - - Label trueLabel = codeBuilder.newLabel(); - Label end = codeBuilder.newLabel(); - - switch (op) { - case LT -> codeBuilder.iflt(trueLabel); - case LTE -> codeBuilder.ifle(trueLabel); - case GT -> codeBuilder.ifgt(trueLabel); - case GTE -> codeBuilder.ifge(trueLabel); - case EQ -> codeBuilder.ifeq(trueLabel); - case NEQ -> codeBuilder.ifne(trueLabel); - default -> throw new IllegalStateException(); - } - addConst0(expectedType == null ? CD_boolean : expectedType); - codeBuilder.goto_(end); - codeBuilder.labelBinding(trueLabel); - addConst1(expectedType == null ? CD_boolean : expectedType); - codeBuilder.labelBinding(end); - return new CompileVisitResult(expectedType == null ? CD_boolean : expectedType); - } - case ADD: { - expectedType = CD_float; - expression.left().visit(this); - expression.right().visit(this); - expectedType = currentExpectedType; - codeBuilder.fadd(); - return CompileVisitResult.FLOAT; - } - case SUB: { - expectedType = CD_float; - expression.left().visit(this); - expression.right().visit(this); - expectedType = currentExpectedType; - codeBuilder.fsub(); - return CompileVisitResult.FLOAT; - } - case MUL: { - expectedType = CD_float; - expression.left().visit(this); - expression.right().visit(this); - expectedType = currentExpectedType; - codeBuilder.fmul(); - return CompileVisitResult.FLOAT; - } - case DIV: { - expectedType = CD_float; - expression.left().visit(this); // pushes lhs value to stack - expression.right().visit(this); // pushes rhs value to stack - expectedType = currentExpectedType; - codeBuilder.fdiv(); - return CompileVisitResult.FLOAT; - } - case ARROW: - case NULL_COALESCE: - case CONDITIONAL: - break; - } - //@formatter:on - return null; - } - - public void endVisit() { - ClassFileUtil.addReturn(codeBuilder, methodReturnType); - } - - @Override - public @NotNull CompileVisitResult visitFloat(final @NotNull FloatExpression expression) { - final float value = expression.value(); - if (expectedType != null && expectedType.equals(CD_void)) { - // nothing! - return CompileVisitResult.VOID; - } else if (expectedType == null || expectedType.equals(CD_float)) { - // expects a float, happy! - codeBuilder.loadConstant(value); - return CompileVisitResult.FLOAT; - } else if (expectedType.equals(CD_boolean)) { - // expects a boolean, push boolean - if (value != 0.0D) { - codeBuilder.iconst_1(); - } else { - codeBuilder.iconst_0(); - } - return CompileVisitResult.BOOLEAN; - } else if (expectedType.equals(CD_int)) { - // expects an int, push int - codeBuilder.loadConstant((int) value); - return CompileVisitResult.INT; - } else if (expectedType.equals(CD_long)) { - // expects a long, push long - codeBuilder.loadConstant((long) value); - return CompileVisitResult.LONG; - } else if (expectedType.equals(CD_double)) { - // expects a double, push double - codeBuilder.loadConstant((double) value); - return CompileVisitResult.DOUBLE; - } else { - System.err.println("[warning] expected type " + expectedType + " has no possible cast from float (" + expression + ")"); - // evaluate to zero - addConstZero(codeBuilder, expectedType); - return new CompileVisitResult(expectedType); - } - } - - @Override - public @NotNull CompileVisitResult visitString(final @NotNull StringExpression expression) { - if (expectedType != null && expectedType.equals(CD_void)) { - // nothing! - return CompileVisitResult.VOID; - } else if (expectedType == null || expectedType.equals(CD_String)) { - // expected a string, happy - codeBuilder.loadConstant(expression.value()); - return CompileVisitResult.STRING; - } else { - // evaluate to zero - addConstZero(codeBuilder, expectedType); - return new CompileVisitResult(expectedType); - } - } - - @Override - public @NotNull CompileVisitResult visitUnary(final @NotNull UnaryExpression expression) { - switch (expression.op()) { - case RETURN: { - expectedType = methodReturnType; - expression.expression().visit(this); - expectedType = null; - ClassFileUtil.addReturn(codeBuilder, methodReturnType); - return new CompileVisitResult(methodReturnType, true); - } - case LOGICAL_NEGATION: { - if (expectedType != null && expectedType.equals(CD_void)) { - // void, - // we must evaluate in case of weird expressions - // like: !query.print('hello') - // won't push anything since expectedType is set to voidType - expression.expression().visit(this); - return CompileVisitResult.VOID; - } - - final ClassDesc currentExpectedType = expectedType; - - if (currentExpectedType != null && !currentExpectedType.isPrimitive()) { - // an unknown Object type, evaluate without pushing anything - // and then just push null in the stack - expectedType = CD_void; // set to void so that doesn't push anything - expression.expression().visit(this); - expectedType = currentExpectedType; - addConstZero(codeBuilder, currentExpectedType); - return new CompileVisitResult(currentExpectedType); - } - - // todo: wrap primitives to their wrapper class if needed - - expectedType = CD_boolean; - expression.expression().visit(this); // push boolean value to stack - expectedType = currentExpectedType; - - if (currentExpectedType != null && currentExpectedType.equals(CD_boolean)) { - // For boolean, leave value on stack and branch - // We need: if (value != 0) push 0 else push 1 - Label pushZero = codeBuilder.newLabel(); - Label end = codeBuilder.newLabel(); - codeBuilder.ifne(pushZero); - codeBuilder.iconst_1(); - codeBuilder.goto_(end); - codeBuilder.labelBinding(pushZero); - codeBuilder.iconst_0(); - codeBuilder.labelBinding(end); - return CompileVisitResult.BOOLEAN; - } - - Label pushConst0 = codeBuilder.newLabel(); - Label end = codeBuilder.newLabel(); - codeBuilder.ifne(pushConst0); - addConst1(currentExpectedType); - codeBuilder.goto_(end); - codeBuilder.labelBinding(pushConst0); - addConst0(currentExpectedType); - codeBuilder.labelBinding(end); - return new CompileVisitResult(currentExpectedType); - } - case ARITHMETICAL_NEGATION: { - final CompileVisitResult result = expression.expression().visit(this); // push value to stack - if (result.is(CD_double)) { - codeBuilder.dneg(); - } else if (result.is(CD_long)) { - codeBuilder.lneg(); - } else if (result.is(CD_float)) { - codeBuilder.fneg(); - } else if (result.is(CD_int)) { - codeBuilder.ineg(); - } else if (result.is(CD_boolean)) { - // logical negation - codeBuilder.iconst_1(); - codeBuilder.ixor(); - } else { - throw new IllegalStateException("Unsupported type for negation: " + result); - } - break; - } - default: - throw new UnsupportedOperationException("Unsupported unary operator: " + expression.op()); - } - return null; - } - - @Override - public @NotNull CompileVisitResult visitTernaryConditional(final @NotNull TernaryConditionalExpression expression) { - final Expression trueExpr = expression.trueExpression(); - final Expression falseExpr = expression.falseExpression(); - - final ClassDesc currentExpectedType = expectedType; - expectedType = CD_boolean; - final CompileVisitResult conditionRes = expression.condition().visit(this); - expectedType = currentExpectedType; - - if (conditionRes != null && conditionRes.lastPushedType() != null - && !conditionRes.is(CD_boolean) && !conditionRes.is(CD_int)) { - addConstZero(codeBuilder, conditionRes.lastPushedType()); - if (conditionRes.is(CD_double)) { - codeBuilder.dcmpl(); - } else if (conditionRes.is(CD_float)) { - codeBuilder.fcmpl(); - } else if (conditionRes.is(CD_long)) { - codeBuilder.lcmp(); - } else { - throw new IllegalStateException("Unsupported type for comparison: " + conditionRes); - } - } - - Label falseLabel = codeBuilder.newLabel(); - Label end = codeBuilder.newLabel(); - codeBuilder.ifeq(falseLabel); - trueExpr.visit(this); - codeBuilder.goto_(end); - codeBuilder.labelBinding(falseLabel); - falseExpr.visit(this); - codeBuilder.labelBinding(end); - return new CompileVisitResult(currentExpectedType); - } - - @Override - public CompileVisitResult visitIdentifier(final @NotNull IdentifierExpression expression) { - final String name = expression.name(); - final Integer paramIndex = argumentParameterIndexes.get(name); - if (paramIndex == null) { - throw new IllegalStateException("Unknown variable: " + name); - } - - final Parameter[] parameters = method.getParameters(); - final Parameter parameter = parameters[paramIndex]; - int loadIndex = 1; - for (int i = 0; i < paramIndex; i++) { - final Parameter param = parameters[i]; - final Class paramType = param.getType(); - if (paramType.equals(double.class) || paramType.equals(long.class)) { - loadIndex += 2; - } else { - loadIndex += 1; - } - } - - final ClassDesc parameterType = classDescOf(parameter.getType()); - - ClassFileUtil.addLoad(codeBuilder, loadIndex, parameterType); - - if (expectedType == null) { - // we are free to use anything, no need to cast - return new CompileVisitResult(parameterType); - } - - // convert to the expected type - ClassFileUtil.addCast(codeBuilder, parameterType, expectedType); - return new CompileVisitResult(expectedType); - } - - @Override - public CompileVisitResult visitAccess(final @NotNull AccessExpression expression) { - final Expression objectExpr = expression.object(); - final String property = expression.property(); - - if (objectExpr instanceof IdentifierExpression) { - final String name = ((IdentifierExpression) objectExpr).name(); - if (name.equals("temp") || name.equals("t")) { - // temps are locals - final Integer localIndex = localsByName.get(property); - if (localIndex == null) { - codeBuilder.fconst_0(); - } else { - codeBuilder.fload(localIndex); - } - return CompileVisitResult.FLOAT; - } - } - - final Value objectValue = objectExpr.visit(this.scopeResolver); - - if (objectValue instanceof ObjectValue) { - final ObjectValue actualObjectValue = (ObjectValue) objectValue; - if (actualObjectValue instanceof JavaObjectBinding) { - final JavaFieldBinding javaFieldBinding = ((JavaObjectBinding) actualObjectValue).getField(property); - if (javaFieldBinding == null) { - // push zero only - codeBuilder.fconst_0(); - } else if (javaFieldBinding.constant()) { - // inline const - codeBuilder.loadConstant(javaFieldBinding.get().getAsNumber()); - } else { - final Field field = javaFieldBinding.field(); - if (Modifier.isStatic(field.getModifiers())) { - codeBuilder.getstatic( - classDescOf(field.getDeclaringClass()), - field.getName(), - classDescOf(field.getType()) - ); - } - } - } - } - - return null; - } - - @Override - public CompileVisitResult visitCall(final @NotNull CallExpression expression) { - final ClassDesc targetType = this.expectedType; - final Expression functionExpr = expression.function(); - - final Value functionValue = functionExpr.visit(this.scopeResolver); - - if (!(functionValue instanceof Function)) { - // not a function, just add 0 - codeBuilder.fconst_0(); - return CompileVisitResult.FLOAT; - } - - final Function function = (Function) functionValue; - - if (function instanceof JavaFunction) { - // we can compile to directly call this function (Java Method) - final JavaFunction javaFunction = (JavaFunction) function; - final Method nativeMethod = javaFunction.method(); - final Parameter[] parameters = nativeMethod.getParameters(); - final List arguments = expression.arguments(); - - final ClassDesc[] ctParameters = new ClassDesc[parameters.length]; - for (int i = 0; i < parameters.length; i++) { - ctParameters[i] = classDescOf(parameters[i].getType()); - } - - final boolean isStatic = Modifier.isStatic(nativeMethod.getModifiers()); - - // load instance - if (!isStatic) { - final Object object = javaFunction.object(); - final String fieldName = object.getClass().getSimpleName().toLowerCase(Locale.ROOT) + Integer.toHexString(object.hashCode()); - requirements.put(fieldName, object); - - final ClassDesc requirementType = classDescOf(object.getClass()); - - // we must load object - codeBuilder.aload(0); - codeBuilder.getfield(functionCompileState.classDesc(), fieldName, requirementType); - } - - // load arguments - final Iterator it = arguments.iterator(); - for (int i = 0; i < parameters.length; i++) { - final Parameter parameter = parameters[i]; - final ClassDesc paramType = ctParameters[i]; - - if (parameter.isAnnotationPresent(Entity.class)) { - Object entity = functionCompileState.compiler().entity(); - if (entity == null || !parameter.getType().isInstance(entity)) { - // load null - addConstZero(codeBuilder, paramType); - } else { - // add entity requirement - requirements.put("__entity__", entity); - - // load entity requirement (field) - codeBuilder.aload(0); // load this - codeBuilder.getfield( - functionCompileState.classDesc(), - "__entity__", - paramType - ); - } - continue; - } - - if (!it.hasNext()) { - addConstZero(codeBuilder, paramType); - continue; - } - - // Set the expected type, then load - this.expectedType = paramType; - it.next().visit(this); - } - - final ClassDesc declaringClassDesc = classDescOf(nativeMethod.getDeclaringClass()); - final ClassDesc returnTypeDesc = classDescOf(nativeMethod.getReturnType()); - final MethodTypeDesc methodTypeDesc = MethodTypeDesc.of(returnTypeDesc, ctParameters); - - if (isStatic) { - // invoke static - codeBuilder.invokestatic(declaringClassDesc, nativeMethod.getName(), methodTypeDesc); - } else { - codeBuilder.invokevirtual(declaringClassDesc, nativeMethod.getName(), methodTypeDesc); - } - - if (nativeMethod.getReturnType() == void.class) { - if (targetType != null && !targetType.equals(CD_void)) { - addConstZero(codeBuilder, targetType); - return new CompileVisitResult(targetType); - } - return CompileVisitResult.VOID; - } else { - if (targetType != null && !returnTypeDesc.equals(targetType)) { - ClassFileUtil.addCast(codeBuilder, returnTypeDesc, targetType); - return new CompileVisitResult(targetType); - } - return new CompileVisitResult(returnTypeDesc); - } - } else { - throw new UnsupportedOperationException("Not supporting non-Java functions yet"); - } - } - - @Override - public CompileVisitResult visit(final @NotNull Expression expression) { - throw new UnsupportedOperationException("Unsupported expression type: " + expression); - } - - private void addConst0(final ClassDesc type) { - if (type == null || type.equals(CD_float)) { - codeBuilder.fconst_0(); - } else if (type.equals(CD_double)) { - codeBuilder.dconst_0(); - } else if (type.equals(CD_long)) { - codeBuilder.lconst_0(); - } else { - codeBuilder.iconst_0(); - } - } - - private void addConst1(final ClassDesc type) { - if (type == null || type.equals(CD_float)) { - codeBuilder.fconst_1(); - } else if (type.equals(CD_double)) { - codeBuilder.dconst_1(); - } else if (type.equals(CD_long)) { - codeBuilder.lconst_1(); - } else { - codeBuilder.iconst_1(); - } - } -} +/* + * This file is part of mocha, licensed under the MIT license + * + * Copyright (c) 2021-2025 Unnamed Team + * + * 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. + */ +package org.redlance.mocha.runtime; + +import com.google.j2objc.annotations.J2ObjCIncompatible; +import org.jetbrains.annotations.NotNull; +import org.redlance.mocha.parser.ast.*; +import org.redlance.mocha.runtime.binding.Entity; +import org.redlance.mocha.runtime.binding.JavaFieldBinding; +import org.redlance.mocha.runtime.binding.JavaFunction; +import org.redlance.mocha.runtime.binding.JavaObjectBinding; +import org.redlance.mocha.runtime.value.Function; +import org.redlance.mocha.runtime.value.NumberValue; +import org.redlance.mocha.runtime.value.ObjectValue; +import org.redlance.mocha.runtime.value.Value; +import org.redlance.mocha.runtime.util.CaseInsensitiveStringHashMap; +import org.redlance.mocha.runtime.util.ClassFileUtil; + +import java.lang.classfile.CodeBuilder; +import java.lang.classfile.Label; +import java.lang.constant.ClassDesc; +import java.lang.constant.MethodTypeDesc; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.lang.reflect.Parameter; +import java.util.Iterator; +import java.util.List; +import java.util.Locale; +import java.util.Map; + +import static java.lang.constant.ConstantDescs.*; +import static org.redlance.mocha.runtime.util.ClassFileUtil.*; + +@J2ObjCIncompatible +final class MolangCompilingVisitor implements ExpressionVisitor { + + private final CodeBuilder codeBuilder; + private final Method method; + + private final FunctionCompileState functionCompileState; + private final Map requirements; + private final Map argumentParameterIndexes; + + private final Map localsByName = new CaseInsensitiveStringHashMap<>(); + + private final ExpressionVisitor scopeResolver; + + /** + * The method return type + */ + private final ClassDesc methodReturnType; + /** + * The type that the current visitor method is expecting + * to be pushed to the stack. + */ + private ClassDesc expectedType; + + MolangCompilingVisitor(final @NotNull FunctionCompileState compileState) { + this.functionCompileState = compileState; + this.codeBuilder = compileState.codeBuilder(); + this.method = compileState.method(); + this.requirements = compileState.requirements(); + this.argumentParameterIndexes = compileState.argumentParameterIndexes(); + + this.methodReturnType = classDescOf(method.getReturnType()); + expectedType = methodReturnType; + + this.scopeResolver = new ExpressionVisitor<>() { + @Override + public @NotNull Value visitIdentifier(final @NotNull IdentifierExpression expression) { + return functionCompileState.scope().get(expression.name()); + } + + @Override + public @NotNull Value visitAccess(final @NotNull AccessExpression expression) { + final Value object = expression.object().visit(this); + if (object instanceof ObjectValue) { + return ((ObjectValue) object).get(expression.property()); + } else { + return NumberValue.zero(); + } + } + + @Override + public @NotNull Value visit(final @NotNull Expression expression) { + return NumberValue.zero(); + } + }; + } + + @Override + public CompileVisitResult visitBinary(final @NotNull BinaryExpression expression) { + final BinaryExpression.Op op = expression.op(); + + if (op == BinaryExpression.Op.ASSIGN) { + final Expression left = expression.left(); + if (left instanceof AccessExpression) { + final Expression objectExpr = ((AccessExpression) left).object(); + if (objectExpr instanceof IdentifierExpression) { + final String name = ((IdentifierExpression) objectExpr).name(); + final String property = ((AccessExpression) left).property(); + + if (name.equals("temp") || name.equals("t")) { + final CompileVisitResult result = expression.right().visit(this); + final int localIndex = localsByName.computeIfAbsent(property, k -> { + int index = functionCompileState.maxLocals(); + if (result.lastPushedType() != null && + (result.lastPushedType().equals(CD_double) || result.lastPushedType().equals(CD_long))) { + functionCompileState.maxLocals(index + 2); + } else { + functionCompileState.maxLocals(index + 1); + } + return index; + }); + codeBuilder.fstore(localIndex); + return null; + } + } + } + } + + final ClassDesc currentExpectedType = expectedType; + + //@formatter:off + switch (op) { + case AND: { + expectedType = CD_boolean; + expression.left().visit(this); + Label falseLabel = codeBuilder.newLabel(); + codeBuilder.ifeq(falseLabel); + expression.right().visit(this); + Label trueEnd = codeBuilder.newLabel(); + codeBuilder.ifeq(falseLabel); + addConst1(currentExpectedType); + codeBuilder.goto_(trueEnd); + codeBuilder.labelBinding(falseLabel); + addConst0(currentExpectedType); + codeBuilder.labelBinding(trueEnd); + expectedType = currentExpectedType; + return new CompileVisitResult(currentExpectedType); + } + case OR: { + expectedType = CD_boolean; + expression.left().visit(this); + Label trueLabel = codeBuilder.newLabel(); + codeBuilder.ifne(trueLabel); + expression.right().visit(this); + Label falseLabel = codeBuilder.newLabel(); + codeBuilder.ifeq(falseLabel); + codeBuilder.labelBinding(trueLabel); + addConst1(currentExpectedType); + Label end = codeBuilder.newLabel(); + codeBuilder.goto_(end); + codeBuilder.labelBinding(falseLabel); + addConst0(currentExpectedType); + codeBuilder.labelBinding(end); + expectedType = currentExpectedType; + return new CompileVisitResult(currentExpectedType); + } + case EQ: + case NEQ: + case LT: + case LTE: + case GT: + case GTE: { + expectedType = CD_float; + expression.left().visit(this); // pushes lhs value to stack + expression.right().visit(this); // pushes rhs value to stack + expectedType = currentExpectedType; + + codeBuilder.fcmpl(); + + Label trueLabel = codeBuilder.newLabel(); + Label end = codeBuilder.newLabel(); + + switch (op) { + case LT -> codeBuilder.iflt(trueLabel); + case LTE -> codeBuilder.ifle(trueLabel); + case GT -> codeBuilder.ifgt(trueLabel); + case GTE -> codeBuilder.ifge(trueLabel); + case EQ -> codeBuilder.ifeq(trueLabel); + case NEQ -> codeBuilder.ifne(trueLabel); + default -> throw new IllegalStateException(); + } + addConst0(expectedType == null ? CD_boolean : expectedType); + codeBuilder.goto_(end); + codeBuilder.labelBinding(trueLabel); + addConst1(expectedType == null ? CD_boolean : expectedType); + codeBuilder.labelBinding(end); + return new CompileVisitResult(expectedType == null ? CD_boolean : expectedType); + } + case ADD: { + expectedType = CD_float; + expression.left().visit(this); + expression.right().visit(this); + expectedType = currentExpectedType; + codeBuilder.fadd(); + return CompileVisitResult.FLOAT; + } + case SUB: { + expectedType = CD_float; + expression.left().visit(this); + expression.right().visit(this); + expectedType = currentExpectedType; + codeBuilder.fsub(); + return CompileVisitResult.FLOAT; + } + case MUL: { + expectedType = CD_float; + expression.left().visit(this); + expression.right().visit(this); + expectedType = currentExpectedType; + codeBuilder.fmul(); + return CompileVisitResult.FLOAT; + } + case DIV: { + expectedType = CD_float; + expression.left().visit(this); // pushes lhs value to stack + expression.right().visit(this); // pushes rhs value to stack + expectedType = currentExpectedType; + codeBuilder.fdiv(); + return CompileVisitResult.FLOAT; + } + case ARROW: + case NULL_COALESCE: + case CONDITIONAL: + break; + } + //@formatter:on + return null; + } + + public void endVisit() { + ClassFileUtil.addReturn(codeBuilder, methodReturnType); + } + + @Override + public @NotNull CompileVisitResult visitFloat(final @NotNull FloatExpression expression) { + final float value = expression.value(); + if (expectedType != null && expectedType.equals(CD_void)) { + // nothing! + return CompileVisitResult.VOID; + } else if (expectedType == null || expectedType.equals(CD_float)) { + // expects a float, happy! + codeBuilder.loadConstant(value); + return CompileVisitResult.FLOAT; + } else if (expectedType.equals(CD_boolean)) { + // expects a boolean, push boolean + if (value != 0.0D) { + codeBuilder.iconst_1(); + } else { + codeBuilder.iconst_0(); + } + return CompileVisitResult.BOOLEAN; + } else if (expectedType.equals(CD_int)) { + // expects an int, push int + codeBuilder.loadConstant((int) value); + return CompileVisitResult.INT; + } else if (expectedType.equals(CD_long)) { + // expects a long, push long + codeBuilder.loadConstant((long) value); + return CompileVisitResult.LONG; + } else if (expectedType.equals(CD_double)) { + // expects a double, push double + codeBuilder.loadConstant((double) value); + return CompileVisitResult.DOUBLE; + } else { + System.err.println("[warning] expected type " + expectedType + " has no possible cast from float (" + expression + ")"); + // evaluate to zero + addConstZero(codeBuilder, expectedType); + return new CompileVisitResult(expectedType); + } + } + + @Override + public @NotNull CompileVisitResult visitString(final @NotNull StringExpression expression) { + if (expectedType != null && expectedType.equals(CD_void)) { + // nothing! + return CompileVisitResult.VOID; + } else if (expectedType == null || expectedType.equals(CD_String)) { + // expected a string, happy + codeBuilder.loadConstant(expression.value()); + return CompileVisitResult.STRING; + } else { + // evaluate to zero + addConstZero(codeBuilder, expectedType); + return new CompileVisitResult(expectedType); + } + } + + @Override + public @NotNull CompileVisitResult visitUnary(final @NotNull UnaryExpression expression) { + switch (expression.op()) { + case RETURN: { + expectedType = methodReturnType; + expression.expression().visit(this); + expectedType = null; + ClassFileUtil.addReturn(codeBuilder, methodReturnType); + return new CompileVisitResult(methodReturnType, true); + } + case LOGICAL_NEGATION: { + if (expectedType != null && expectedType.equals(CD_void)) { + // void, + // we must evaluate in case of weird expressions + // like: !query.print('hello') + // won't push anything since expectedType is set to voidType + expression.expression().visit(this); + return CompileVisitResult.VOID; + } + + final ClassDesc currentExpectedType = expectedType; + + if (currentExpectedType != null && !currentExpectedType.isPrimitive()) { + // an unknown Object type, evaluate without pushing anything + // and then just push null in the stack + expectedType = CD_void; // set to void so that doesn't push anything + expression.expression().visit(this); + expectedType = currentExpectedType; + addConstZero(codeBuilder, currentExpectedType); + return new CompileVisitResult(currentExpectedType); + } + + // todo: wrap primitives to their wrapper class if needed + + expectedType = CD_boolean; + expression.expression().visit(this); // push boolean value to stack + expectedType = currentExpectedType; + + if (currentExpectedType != null && currentExpectedType.equals(CD_boolean)) { + // For boolean, leave value on stack and branch + // We need: if (value != 0) push 0 else push 1 + Label pushZero = codeBuilder.newLabel(); + Label end = codeBuilder.newLabel(); + codeBuilder.ifne(pushZero); + codeBuilder.iconst_1(); + codeBuilder.goto_(end); + codeBuilder.labelBinding(pushZero); + codeBuilder.iconst_0(); + codeBuilder.labelBinding(end); + return CompileVisitResult.BOOLEAN; + } + + Label pushConst0 = codeBuilder.newLabel(); + Label end = codeBuilder.newLabel(); + codeBuilder.ifne(pushConst0); + addConst1(currentExpectedType); + codeBuilder.goto_(end); + codeBuilder.labelBinding(pushConst0); + addConst0(currentExpectedType); + codeBuilder.labelBinding(end); + return new CompileVisitResult(currentExpectedType); + } + case ARITHMETICAL_NEGATION: { + final CompileVisitResult result = expression.expression().visit(this); // push value to stack + if (result.is(CD_double)) { + codeBuilder.dneg(); + } else if (result.is(CD_long)) { + codeBuilder.lneg(); + } else if (result.is(CD_float)) { + codeBuilder.fneg(); + } else if (result.is(CD_int)) { + codeBuilder.ineg(); + } else if (result.is(CD_boolean)) { + // logical negation + codeBuilder.iconst_1(); + codeBuilder.ixor(); + } else { + throw new IllegalStateException("Unsupported type for negation: " + result); + } + break; + } + default: + throw new UnsupportedOperationException("Unsupported unary operator: " + expression.op()); + } + return null; + } + + @Override + public @NotNull CompileVisitResult visitTernaryConditional(final @NotNull TernaryConditionalExpression expression) { + final Expression trueExpr = expression.trueExpression(); + final Expression falseExpr = expression.falseExpression(); + + final ClassDesc currentExpectedType = expectedType; + expectedType = CD_boolean; + final CompileVisitResult conditionRes = expression.condition().visit(this); + expectedType = currentExpectedType; + + if (conditionRes != null && conditionRes.lastPushedType() != null + && !conditionRes.is(CD_boolean) && !conditionRes.is(CD_int)) { + addConstZero(codeBuilder, conditionRes.lastPushedType()); + if (conditionRes.is(CD_double)) { + codeBuilder.dcmpl(); + } else if (conditionRes.is(CD_float)) { + codeBuilder.fcmpl(); + } else if (conditionRes.is(CD_long)) { + codeBuilder.lcmp(); + } else { + throw new IllegalStateException("Unsupported type for comparison: " + conditionRes); + } + } + + Label falseLabel = codeBuilder.newLabel(); + Label end = codeBuilder.newLabel(); + codeBuilder.ifeq(falseLabel); + trueExpr.visit(this); + codeBuilder.goto_(end); + codeBuilder.labelBinding(falseLabel); + falseExpr.visit(this); + codeBuilder.labelBinding(end); + return new CompileVisitResult(currentExpectedType); + } + + @Override + public CompileVisitResult visitIdentifier(final @NotNull IdentifierExpression expression) { + final String name = expression.name(); + final Integer paramIndex = argumentParameterIndexes.get(name); + if (paramIndex == null) { + throw new IllegalStateException("Unknown variable: " + name); + } + + final Parameter[] parameters = method.getParameters(); + final Parameter parameter = parameters[paramIndex]; + int loadIndex = 1; + for (int i = 0; i < paramIndex; i++) { + final Parameter param = parameters[i]; + final Class paramType = param.getType(); + if (paramType.equals(double.class) || paramType.equals(long.class)) { + loadIndex += 2; + } else { + loadIndex += 1; + } + } + + final ClassDesc parameterType = classDescOf(parameter.getType()); + + ClassFileUtil.addLoad(codeBuilder, loadIndex, parameterType); + + if (expectedType == null) { + // we are free to use anything, no need to cast + return new CompileVisitResult(parameterType); + } + + // convert to the expected type + ClassFileUtil.addCast(codeBuilder, parameterType, expectedType); + return new CompileVisitResult(expectedType); + } + + @Override + public CompileVisitResult visitAccess(final @NotNull AccessExpression expression) { + final Expression objectExpr = expression.object(); + final String property = expression.property(); + + if (objectExpr instanceof IdentifierExpression) { + final String name = ((IdentifierExpression) objectExpr).name(); + if (name.equals("temp") || name.equals("t")) { + // temps are locals + final Integer localIndex = localsByName.get(property); + if (localIndex == null) { + codeBuilder.fconst_0(); + } else { + codeBuilder.fload(localIndex); + } + return CompileVisitResult.FLOAT; + } + } + + final Value objectValue = objectExpr.visit(this.scopeResolver); + + if (objectValue instanceof ObjectValue) { + final ObjectValue actualObjectValue = (ObjectValue) objectValue; + if (actualObjectValue instanceof JavaObjectBinding) { + final JavaFieldBinding javaFieldBinding = ((JavaObjectBinding) actualObjectValue).getField(property); + if (javaFieldBinding == null) { + // push zero only + codeBuilder.fconst_0(); + } else if (javaFieldBinding.constant()) { + // inline const + codeBuilder.loadConstant(javaFieldBinding.get().getAsNumber()); + } else { + final Field field = javaFieldBinding.field(); + if (Modifier.isStatic(field.getModifiers())) { + codeBuilder.getstatic( + classDescOf(field.getDeclaringClass()), + field.getName(), + classDescOf(field.getType()) + ); + } + } + } + } + + return null; + } + + @Override + public CompileVisitResult visitCall(final @NotNull CallExpression expression) { + final ClassDesc targetType = this.expectedType; + final Expression functionExpr = expression.function(); + + final Value functionValue = functionExpr.visit(this.scopeResolver); + + if (!(functionValue instanceof Function)) { + // not a function, just add 0 + codeBuilder.fconst_0(); + return CompileVisitResult.FLOAT; + } + + final Function function = (Function) functionValue; + + if (function instanceof JavaFunction) { + // we can compile to directly call this function (Java Method) + final JavaFunction javaFunction = (JavaFunction) function; + final Method nativeMethod = javaFunction.method(); + final Parameter[] parameters = nativeMethod.getParameters(); + final List arguments = expression.arguments(); + + final ClassDesc[] ctParameters = new ClassDesc[parameters.length]; + for (int i = 0; i < parameters.length; i++) { + ctParameters[i] = classDescOf(parameters[i].getType()); + } + + final boolean isStatic = Modifier.isStatic(nativeMethod.getModifiers()); + + // load instance + if (!isStatic) { + final Object object = javaFunction.object(); + final String fieldName = object.getClass().getSimpleName().toLowerCase(Locale.ROOT) + Integer.toHexString(object.hashCode()); + requirements.put(fieldName, object); + + final ClassDesc requirementType = classDescOf(object.getClass()); + + // we must load object + codeBuilder.aload(0); + codeBuilder.getfield(functionCompileState.classDesc(), fieldName, requirementType); + } + + // load arguments + final Iterator it = arguments.iterator(); + for (int i = 0; i < parameters.length; i++) { + final Parameter parameter = parameters[i]; + final ClassDesc paramType = ctParameters[i]; + + if (parameter.isAnnotationPresent(Entity.class)) { + Object entity = functionCompileState.compiler().entity(); + if (entity == null || !parameter.getType().isInstance(entity)) { + // load null + addConstZero(codeBuilder, paramType); + } else { + // add entity requirement + requirements.put("__entity__", entity); + + // load entity requirement (field) + codeBuilder.aload(0); // load this + codeBuilder.getfield( + functionCompileState.classDesc(), + "__entity__", + paramType + ); + } + continue; + } + + if (!it.hasNext()) { + addConstZero(codeBuilder, paramType); + continue; + } + + // Set the expected type, then load + this.expectedType = paramType; + it.next().visit(this); + } + + final ClassDesc declaringClassDesc = classDescOf(nativeMethod.getDeclaringClass()); + final ClassDesc returnTypeDesc = classDescOf(nativeMethod.getReturnType()); + final MethodTypeDesc methodTypeDesc = MethodTypeDesc.of(returnTypeDesc, ctParameters); + + if (isStatic) { + // invoke static + codeBuilder.invokestatic(declaringClassDesc, nativeMethod.getName(), methodTypeDesc); + } else { + codeBuilder.invokevirtual(declaringClassDesc, nativeMethod.getName(), methodTypeDesc); + } + + if (nativeMethod.getReturnType() == void.class) { + if (targetType != null && !targetType.equals(CD_void)) { + addConstZero(codeBuilder, targetType); + return new CompileVisitResult(targetType); + } + return CompileVisitResult.VOID; + } else { + if (targetType != null && !returnTypeDesc.equals(targetType)) { + ClassFileUtil.addCast(codeBuilder, returnTypeDesc, targetType); + return new CompileVisitResult(targetType); + } + return new CompileVisitResult(returnTypeDesc); + } + } else { + throw new UnsupportedOperationException("Not supporting non-Java functions yet"); + } + } + + @Override + public CompileVisitResult visit(final @NotNull Expression expression) { + throw new UnsupportedOperationException("Unsupported expression type: " + expression); + } + + private void addConst0(final ClassDesc type) { + if (type == null || type.equals(CD_float)) { + codeBuilder.fconst_0(); + } else if (type.equals(CD_double)) { + codeBuilder.dconst_0(); + } else if (type.equals(CD_long)) { + codeBuilder.lconst_0(); + } else { + codeBuilder.iconst_0(); + } + } + + private void addConst1(final ClassDesc type) { + if (type == null || type.equals(CD_float)) { + codeBuilder.fconst_1(); + } else if (type.equals(CD_double)) { + codeBuilder.dconst_1(); + } else if (type.equals(CD_long)) { + codeBuilder.lconst_1(); + } else { + codeBuilder.iconst_1(); + } + } +} diff --git a/src/main/java/team/unnamed/mocha/runtime/compiled/MochaCompiledFunction.java b/runtime-compiler/src/main/java/org/redlance/mocha/runtime/compiled/MochaCompiledFunction.java similarity index 95% rename from src/main/java/team/unnamed/mocha/runtime/compiled/MochaCompiledFunction.java rename to runtime-compiler/src/main/java/org/redlance/mocha/runtime/compiled/MochaCompiledFunction.java index 6a4104a..b63a609 100644 --- a/src/main/java/team/unnamed/mocha/runtime/compiled/MochaCompiledFunction.java +++ b/runtime-compiler/src/main/java/org/redlance/mocha/runtime/compiled/MochaCompiledFunction.java @@ -1,29 +1,29 @@ -/* - * This file is part of mocha, licensed under the MIT license - * - * Copyright (c) 2021-2025 Unnamed Team - * - * 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. - */ -package team.unnamed.mocha.runtime.compiled; +/* + * This file is part of mocha, licensed under the MIT license + * + * Copyright (c) 2021-2025 Unnamed Team + * + * 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. + */ +package org.redlance.mocha.runtime.compiled; -import team.unnamed.mocha.runtime.MolangCompiler; +import org.redlance.mocha.runtime.MolangCompiler; /** * Marker interface for Molang compiled functions. diff --git a/src/main/java/team/unnamed/mocha/runtime/compiled/Named.java b/runtime-compiler/src/main/java/org/redlance/mocha/runtime/compiled/Named.java similarity index 95% rename from src/main/java/team/unnamed/mocha/runtime/compiled/Named.java rename to runtime-compiler/src/main/java/org/redlance/mocha/runtime/compiled/Named.java index b548d6d..14f53ea 100644 --- a/src/main/java/team/unnamed/mocha/runtime/compiled/Named.java +++ b/runtime-compiler/src/main/java/org/redlance/mocha/runtime/compiled/Named.java @@ -1,27 +1,27 @@ -/* - * This file is part of mocha, licensed under the MIT license - * - * Copyright (c) 2021-2025 Unnamed Team - * - * 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. - */ -package team.unnamed.mocha.runtime.compiled; +/* + * This file is part of mocha, licensed under the MIT license + * + * Copyright (c) 2021-2025 Unnamed Team + * + * 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. + */ +package org.redlance.mocha.runtime.compiled; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; diff --git a/runtime-compiler/src/main/java/org/redlance/mocha/runtime/compiled/package-info.java b/runtime-compiler/src/main/java/org/redlance/mocha/runtime/compiled/package-info.java new file mode 100644 index 0000000..2bd9793 --- /dev/null +++ b/runtime-compiler/src/main/java/org/redlance/mocha/runtime/compiled/package-info.java @@ -0,0 +1,4 @@ +@ReflectionSupport(ReflectionSupport.Level.FULL) +package org.redlance.mocha.runtime.compiled; + +import com.google.j2objc.annotations.ReflectionSupport; \ No newline at end of file diff --git a/runtime-compiler/src/main/java/org/redlance/mocha/runtime/package-info.java b/runtime-compiler/src/main/java/org/redlance/mocha/runtime/package-info.java new file mode 100644 index 0000000..a7c256a --- /dev/null +++ b/runtime-compiler/src/main/java/org/redlance/mocha/runtime/package-info.java @@ -0,0 +1,4 @@ +@ReflectionSupport(ReflectionSupport.Level.NATIVE_ONLY) +package org.redlance.mocha.runtime; + +import com.google.j2objc.annotations.ReflectionSupport; \ No newline at end of file diff --git a/src/main/java/team/unnamed/mocha/util/ClassFileUtil.java b/runtime-compiler/src/main/java/org/redlance/mocha/runtime/util/ClassFileUtil.java similarity index 98% rename from src/main/java/team/unnamed/mocha/util/ClassFileUtil.java rename to runtime-compiler/src/main/java/org/redlance/mocha/runtime/util/ClassFileUtil.java index 197318d..dfce3fa 100644 --- a/src/main/java/team/unnamed/mocha/util/ClassFileUtil.java +++ b/runtime-compiler/src/main/java/org/redlance/mocha/runtime/util/ClassFileUtil.java @@ -21,15 +21,15 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -package team.unnamed.mocha.util; +package org.redlance.mocha.runtime.util; +import com.google.j2objc.annotations.J2ObjCIncompatible; import org.jetbrains.annotations.NotNull; -import team.unnamed.mocha.runtime.TypeCastException; +import org.redlance.mocha.runtime.TypeCastException; import java.lang.classfile.CodeBuilder; import java.lang.classfile.Label; import java.lang.constant.ClassDesc; -import java.lang.constant.ConstantDescs; import java.lang.constant.MethodTypeDesc; import java.util.Map; import java.util.Set; @@ -37,6 +37,7 @@ import static java.lang.constant.ConstantDescs.*; import static java.util.Objects.requireNonNull; +@J2ObjCIncompatible public class ClassFileUtil { // Shared wrapper ClassDesc constants to avoid repeated ClassDesc.of() allocations diff --git a/runtime-compiler/src/main/java/org/redlance/mocha/runtime/util/package-info.java b/runtime-compiler/src/main/java/org/redlance/mocha/runtime/util/package-info.java new file mode 100644 index 0000000..4c32a2a --- /dev/null +++ b/runtime-compiler/src/main/java/org/redlance/mocha/runtime/util/package-info.java @@ -0,0 +1,4 @@ +@ReflectionSupport(ReflectionSupport.Level.NATIVE_ONLY) +package org.redlance.mocha.runtime.util; + +import com.google.j2objc.annotations.ReflectionSupport; \ No newline at end of file diff --git a/runtime-compiler/src/test/java/org/redlance/mocha/MochaAssertions.java b/runtime-compiler/src/test/java/org/redlance/mocha/MochaAssertions.java new file mode 100644 index 0000000..4f0f52e --- /dev/null +++ b/runtime-compiler/src/test/java/org/redlance/mocha/MochaAssertions.java @@ -0,0 +1,57 @@ +/* + * This file is part of mocha, licensed under the MIT license + * + * Copyright (c) 2021-2025 Unnamed Team + * + * 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. + */ +package org.redlance.mocha; + +import org.jetbrains.annotations.NotNull; +import org.redlance.mocha.runtime.MochaEngine; + +import java.util.function.UnaryOperator; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public final class MochaAssertions { + private MochaAssertions() { + throw new UnsupportedOperationException("This class cannot be instantiated"); + } + + public static void assertEvaluates(final double expected, final @NotNull String expr, final @NotNull UnaryOperator> configurer) { + MochaEngine engine = MochaEngine.createStandard(); + engine = configurer.apply(engine); + final double result = engine.interpreter().eval(expr); + assertEquals(expected, result, 0.0001, () -> "Expression: '" + expr + "' evaluated to " + result + ", expected " + expected); + } + + public static void assertEvaluates(final double expected, final @NotNull String expr) { + assertEvaluates(expected, expr, engine -> engine); + } + + public static void assertEvaluatesAndCompiles(final double expected, final @NotNull String expr) { + final MochaEngine engine = MochaEngine.createStandard(); + final double result = engine.interpreter().eval(expr); + assertEquals(expected, result, 0.0001, () -> "(Interpreted) expression: '" + expr + "' evaluated to " + result + ", expected " + expected); + + final double compiledResult = engine.compiler().compile(expr).evaluate(); + assertEquals(expected, compiledResult, 0.0001, () -> "(Compiled) expression: '" + expr + "' evaluated to " + compiledResult + ", expected " + expected); + } +} diff --git a/src/test/java/team/unnamed/mocha/runtime/ArrayAccessRuntimeTest.java b/runtime-compiler/src/test/java/org/redlance/mocha/runtime/ArrayAccessRuntimeTest.java similarity index 90% rename from src/test/java/team/unnamed/mocha/runtime/ArrayAccessRuntimeTest.java rename to runtime-compiler/src/test/java/org/redlance/mocha/runtime/ArrayAccessRuntimeTest.java index fba71d8..e060b92 100644 --- a/src/test/java/team/unnamed/mocha/runtime/ArrayAccessRuntimeTest.java +++ b/runtime-compiler/src/test/java/org/redlance/mocha/runtime/ArrayAccessRuntimeTest.java @@ -21,21 +21,20 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -package team.unnamed.mocha.runtime; +package org.redlance.mocha.runtime; import org.junit.jupiter.api.Test; -import team.unnamed.mocha.MochaEngine; -import team.unnamed.mocha.runtime.binding.Binding; +import org.redlance.mocha.runtime.binding.Binding; import java.util.function.UnaryOperator; -import static team.unnamed.mocha.MochaAssertions.assertEvaluates; +import static org.redlance.mocha.MochaAssertions.assertEvaluates; class ArrayAccessRuntimeTest { @Test void test() { final UnaryOperator> configurer = engine -> { - engine.bind(QueryImpl.class); + engine.interpreter().bind(QueryImpl.class); return engine; }; diff --git a/src/test/java/team/unnamed/mocha/runtime/BreakContinueTest.java b/runtime-compiler/src/test/java/org/redlance/mocha/runtime/BreakContinueTest.java similarity index 87% rename from src/test/java/team/unnamed/mocha/runtime/BreakContinueTest.java rename to runtime-compiler/src/test/java/org/redlance/mocha/runtime/BreakContinueTest.java index d28f339..d9a89c4 100644 --- a/src/test/java/team/unnamed/mocha/runtime/BreakContinueTest.java +++ b/runtime-compiler/src/test/java/org/redlance/mocha/runtime/BreakContinueTest.java @@ -1,59 +1,58 @@ -/* - * This file is part of mocha, licensed under the MIT license - * - * Copyright (c) 2021-2025 Unnamed Team - * - * 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. - */ -package team.unnamed.mocha.runtime; - -import org.junit.jupiter.api.Test; -import team.unnamed.mocha.MochaEngine; - -import static org.junit.jupiter.api.Assertions.assertEquals; - -class BreakContinueTest { - @Test - void test_break() { - final float value = MochaEngine.createStandard().eval(String.join("\n", - "t.i = 0;", - "loop(10, {", - " t.i = t.i + 1;", - " (t.i >= 5) ? break;", - "});", - "return t.i;" - )); - assertEquals(5.0F, value); - } - - @Test - void test_continue() { - final float value = MochaEngine.createStandard().eval( - "t.i = 0;" + - "t.sum = 0;" + - "loop(20, {" + - "t.i = t.i + 1;" + - "((t.i < 8) || (t.i > 17)) ? continue;" + - "t.sum = t.sum + t.i;" + - "});" + - "return t.sum;" - ); - assertEquals(125.0F, value); - } -} +/* + * This file is part of mocha, licensed under the MIT license + * + * Copyright (c) 2021-2025 Unnamed Team + * + * 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. + */ +package org.redlance.mocha.runtime; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +class BreakContinueTest { + @Test + void test_break() { + final float value = MochaEngine.createStandard().interpreter().eval(String.join("\n", + "t.i = 0;", + "loop(10, {", + " t.i = t.i + 1;", + " (t.i >= 5) ? break;", + "});", + "return t.i;" + )); + assertEquals(5.0F, value); + } + + @Test + void test_continue() { + final float value = MochaEngine.createStandard().interpreter().eval( + "t.i = 0;" + + "t.sum = 0;" + + "loop(20, {" + + "t.i = t.i + 1;" + + "((t.i < 8) || (t.i > 17)) ? continue;" + + "t.sum = t.sum + t.i;" + + "});" + + "return t.sum;" + ); + assertEquals(125.0F, value); + } +} diff --git a/src/test/java/team/unnamed/mocha/runtime/BytecodeKotlinTest.kt b/runtime-compiler/src/test/java/org/redlance/mocha/runtime/BytecodeKotlinTest.kt similarity index 57% rename from src/test/java/team/unnamed/mocha/runtime/BytecodeKotlinTest.kt rename to runtime-compiler/src/test/java/org/redlance/mocha/runtime/BytecodeKotlinTest.kt index f3feccf..664b2ce 100644 --- a/src/test/java/team/unnamed/mocha/runtime/BytecodeKotlinTest.kt +++ b/runtime-compiler/src/test/java/org/redlance/mocha/runtime/BytecodeKotlinTest.kt @@ -1,8 +1,7 @@ -package team.unnamed.mocha.runtime +package org.redlance.mocha.runtime import org.junit.jupiter.api.Test -import team.unnamed.mocha.MochaEngine -import team.unnamed.mocha.runtime.binding.Binding +import org.redlance.mocha.runtime.binding.Binding @Binding("plain") class NoArgument(var offset: Int) { @@ -22,34 +21,34 @@ class BytecodeTest { val engine = MochaEngine.createStandard() val plain = NoArgument(0) - engine.bindInstance(NoArgument::class.java, plain, "plain") + engine.interpreter().bindInstance(NoArgument::class.java, plain, "plain") val plainExpr = "plain.calc()" - val plainInterpreted = engine.prepareEval(plainExpr) + val plainInterpreted = engine.interpreter().prepareEval(plainExpr) plain.offset = 3 - println(plainInterpreted.evaluate()) + println(plainInterpreted.get()) plain.offset = 4 - println(plainInterpreted.evaluate()) + println(plainInterpreted.get()) - val plainCompiled = engine.compile(plainExpr) + val plainCompiled = engine.compiler().compile(plainExpr) plain.offset = 3 println(plainCompiled.evaluate()) plain.offset = 4 println(plainCompiled.evaluate()) val offset = WithOffset(0) - engine.bindInstance(WithOffset::class.java, offset, "offset") + engine.interpreter().bindInstance(WithOffset::class.java, offset, "offset") val offsetExpr = "offset.calc(1)" - val offsetInterpreted = engine.prepareEval(offsetExpr) + val offsetInterpreted = engine.interpreter().prepareEval(offsetExpr) offset.offset = 3 - println(offsetInterpreted.evaluate()) + println(offsetInterpreted.get()) offset.offset = 4 - println(offsetInterpreted.evaluate()) + println(offsetInterpreted.get()) - val offsetCompiled = engine.compile(offsetExpr) + val offsetCompiled = engine.compiler().compile(offsetExpr) offset.offset = 3 println(offsetCompiled.evaluate()) offset.offset = 4 diff --git a/src/test/java/team/unnamed/mocha/runtime/CaseSensitivityTest.java b/runtime-compiler/src/test/java/org/redlance/mocha/runtime/CaseSensitivityTest.java similarity index 96% rename from src/test/java/team/unnamed/mocha/runtime/CaseSensitivityTest.java rename to runtime-compiler/src/test/java/org/redlance/mocha/runtime/CaseSensitivityTest.java index 9a343c0..7770e2c 100644 --- a/src/test/java/team/unnamed/mocha/runtime/CaseSensitivityTest.java +++ b/runtime-compiler/src/test/java/org/redlance/mocha/runtime/CaseSensitivityTest.java @@ -21,11 +21,11 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -package team.unnamed.mocha.runtime; +package org.redlance.mocha.runtime; import org.junit.jupiter.api.Test; -import static team.unnamed.mocha.MochaAssertions.assertEvaluatesAndCompiles; +import static org.redlance.mocha.MochaAssertions.assertEvaluatesAndCompiles; class CaseSensitivityTest { @Test diff --git a/src/test/java/team/unnamed/mocha/runtime/CompareTest.java b/runtime-compiler/src/test/java/org/redlance/mocha/runtime/CompareTest.java similarity index 93% rename from src/test/java/team/unnamed/mocha/runtime/CompareTest.java rename to runtime-compiler/src/test/java/org/redlance/mocha/runtime/CompareTest.java index 45487b4..2d1d72d 100644 --- a/src/test/java/team/unnamed/mocha/runtime/CompareTest.java +++ b/runtime-compiler/src/test/java/org/redlance/mocha/runtime/CompareTest.java @@ -1,118 +1,117 @@ -/* - * This file is part of mocha, licensed under the MIT license - * - * Copyright (c) 2021-2025 Unnamed Team - * - * 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. - */ -package team.unnamed.mocha.runtime; - -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; -import team.unnamed.mocha.MochaEngine; - -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; - -/** - * Compares the results of this library with the - * results of other libraries - */ -public class CompareTest { - - private static final MochaEngine ENGINE = MochaEngine.createStandard(); - - //#region Helper code - private static BufferedReader createResourceReader(String name) { - InputStream stream = CompareTest.class - .getClassLoader() - .getResourceAsStream(name); - if (stream == null) { - throw new IllegalStateException("Resource not found: " + name); - } - return new BufferedReader(new InputStreamReader(stream)); - } - - private static String nextNonEmpty(BufferedReader reader) throws IOException { - String value; - do { - value = reader.readLine(); - if (value == null) { - break; - } else { - value = value.trim(); - } - } while (value.isEmpty() || value.charAt(0) == '#'); - return value; - } - - private static void compare(String expectationsName, String sourceName) throws IOException { - try (BufferedReader source = createResourceReader(sourceName)) { - try (BufferedReader expectations = createResourceReader(expectationsName)) { - while (true) { - String expression = nextNonEmpty(source); - String expected = nextNonEmpty(expectations); - - if (expression == null || expected == null) { - // end reached - break; - } - - float expectedValue = Float.parseFloat(expected); - - // eval expression - final float result = ENGINE.eval(expression); - Assertions.assertEquals( - expectedValue, - result, - 0.001f, - () -> "Incorrect result for INTERPRETED expression: " + expression - ); - - // compile and eval expression - try { - final float compileResult = ENGINE.compile(expression).evaluate(); - Assertions.assertEquals( - expectedValue, - compileResult, - 0.001f, - () -> "Incorrect result for COMPILED expression: " + expression - ); - } catch (Throwable e) { - throw new IllegalStateException("Error while compiling expression: " + expression, e); - } - } - } - } - } - - /** - * Compares this library results with MolangJS - * of JannisX11 - * https://github.com/JannisX11/MolangJS - */ - @Test - public void compare_with_molangjs() throws IOException { - compare("expectations.txt", "tests.txt"); - } - //#endregion - -} +/* + * This file is part of mocha, licensed under the MIT license + * + * Copyright (c) 2021-2025 Unnamed Team + * + * 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. + */ +package org.redlance.mocha.runtime; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; + +/** + * Compares the results of this library with the + * results of other libraries + */ +public class CompareTest { + + private static final MochaEngine ENGINE = MochaEngine.createStandard(); + + //#region Helper code + private static BufferedReader createResourceReader(String name) { + InputStream stream = CompareTest.class + .getClassLoader() + .getResourceAsStream(name); + if (stream == null) { + throw new IllegalStateException("Resource not found: " + name); + } + return new BufferedReader(new InputStreamReader(stream)); + } + + private static String nextNonEmpty(BufferedReader reader) throws IOException { + String value; + do { + value = reader.readLine(); + if (value == null) { + break; + } else { + value = value.trim(); + } + } while (value.isEmpty() || value.charAt(0) == '#'); + return value; + } + + private static void compare(String expectationsName, String sourceName) throws IOException { + try (BufferedReader source = createResourceReader(sourceName)) { + try (BufferedReader expectations = createResourceReader(expectationsName)) { + while (true) { + String expression = nextNonEmpty(source); + String expected = nextNonEmpty(expectations); + + if (expression == null || expected == null) { + // end reached + break; + } + + float expectedValue = Float.parseFloat(expected); + + // eval expression + final float result = ENGINE.interpreter().eval(expression); + Assertions.assertEquals( + expectedValue, + result, + 0.001f, + () -> "Incorrect result for INTERPRETED expression: " + expression + ); + + // compile and eval expression + try { + final float compileResult = ENGINE.compiler().compile(expression).evaluate(); + Assertions.assertEquals( + expectedValue, + compileResult, + 0.001f, + () -> "Incorrect result for COMPILED expression: " + expression + ); + } catch (Throwable e) { + throw new IllegalStateException("Error while compiling expression: " + expression, e); + } + } + } + } + } + + /** + * Compares this library results with MolangJS + * of JannisX11 + * https://github.com/JannisX11/MolangJS + */ + @Test + public void compare_with_molangjs() throws IOException { + compare("expectations.txt", "tests.txt"); + } + //#endregion + +} diff --git a/src/test/java/team/unnamed/mocha/runtime/ConstantValuesTest.java b/runtime-compiler/src/test/java/org/redlance/mocha/runtime/ConstantValuesTest.java similarity index 87% rename from src/test/java/team/unnamed/mocha/runtime/ConstantValuesTest.java rename to runtime-compiler/src/test/java/org/redlance/mocha/runtime/ConstantValuesTest.java index b83f06a..c3e8ec4 100644 --- a/src/test/java/team/unnamed/mocha/runtime/ConstantValuesTest.java +++ b/runtime-compiler/src/test/java/org/redlance/mocha/runtime/ConstantValuesTest.java @@ -1,34 +1,33 @@ -/* - * This file is part of mocha, licensed under the MIT license - * - * Copyright (c) 2021-2025 Unnamed Team - * - * 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. - */ -package team.unnamed.mocha.runtime; +/* + * This file is part of mocha, licensed under the MIT license + * + * Copyright (c) 2021-2025 Unnamed Team + * + * 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. + */ +package org.redlance.mocha.runtime; import org.junit.jupiter.api.Test; -import team.unnamed.mocha.MochaEngine; class ConstantValuesTest { @Test void test() { - MochaEngine.createStandard().compile("math.abs(-5) + math.abs(5) + math.sqrt(25)"); + MochaEngine.createStandard().compiler().compile("math.abs(-5) + math.abs(5) + math.sqrt(25)"); } } diff --git a/src/test/java/team/unnamed/mocha/runtime/FibonacciTest.java b/runtime-compiler/src/test/java/org/redlance/mocha/runtime/FibonacciTest.java similarity index 90% rename from src/test/java/team/unnamed/mocha/runtime/FibonacciTest.java rename to runtime-compiler/src/test/java/org/redlance/mocha/runtime/FibonacciTest.java index 3b9bb52..74de0a1 100644 --- a/src/test/java/team/unnamed/mocha/runtime/FibonacciTest.java +++ b/runtime-compiler/src/test/java/org/redlance/mocha/runtime/FibonacciTest.java @@ -1,35 +1,34 @@ -/* - * This file is part of mocha, licensed under the MIT license - * - * Copyright (c) 2021-2025 Unnamed Team - * - * 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. - */ -package team.unnamed.mocha.runtime; +/* + * This file is part of mocha, licensed under the MIT license + * + * Copyright (c) 2021-2025 Unnamed Team + * + * 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. + */ +package org.redlance.mocha.runtime; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; -import team.unnamed.mocha.MochaEngine; -import team.unnamed.mocha.runtime.value.Function; -import team.unnamed.mocha.runtime.value.NumberValue; -import team.unnamed.mocha.runtime.value.ObjectProperty; -import team.unnamed.mocha.runtime.value.ObjectValue; +import org.redlance.mocha.runtime.value.Function; +import org.redlance.mocha.runtime.value.NumberValue; +import org.redlance.mocha.runtime.value.ObjectProperty; +import org.redlance.mocha.runtime.value.ObjectValue; import java.io.ByteArrayOutputStream; import java.io.IOException; @@ -92,7 +91,7 @@ public void test() throws IOException { } return null; }); - final double result = engine.eval(code); + final double result = engine.interpreter().eval(code); assertEquals(expected, out.toString()); assertEquals(89D, result); diff --git a/src/test/java/team/unnamed/mocha/runtime/ForEachTest.java b/runtime-compiler/src/test/java/org/redlance/mocha/runtime/ForEachTest.java similarity index 88% rename from src/test/java/team/unnamed/mocha/runtime/ForEachTest.java rename to runtime-compiler/src/test/java/org/redlance/mocha/runtime/ForEachTest.java index 3c5f886..d66839e 100644 --- a/src/test/java/team/unnamed/mocha/runtime/ForEachTest.java +++ b/runtime-compiler/src/test/java/org/redlance/mocha/runtime/ForEachTest.java @@ -1,31 +1,30 @@ -/* - * This file is part of mocha, licensed under the MIT license - * - * Copyright (c) 2021-2025 Unnamed Team - * - * 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. - */ -package team.unnamed.mocha.runtime; +/* + * This file is part of mocha, licensed under the MIT license + * + * Copyright (c) 2021-2025 Unnamed Team + * + * 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. + */ +package org.redlance.mocha.runtime; import org.junit.jupiter.api.Test; -import team.unnamed.mocha.MochaEngine; -import team.unnamed.mocha.runtime.binding.Binding; +import org.redlance.mocha.runtime.binding.Binding; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -40,9 +39,9 @@ void test() { "return v.sum;"); final MochaEngine engine = MochaEngine.createStandard(); - engine.bind(QueryImpl.class); + engine.interpreter().bind(QueryImpl.class); - final double result = engine.eval(code); + final double result = engine.interpreter().eval(code); assertEquals(98, result); } diff --git a/src/test/java/team/unnamed/mocha/runtime/IndividualScopeTest.java b/runtime-compiler/src/test/java/org/redlance/mocha/runtime/IndividualScopeTest.java similarity index 79% rename from src/test/java/team/unnamed/mocha/runtime/IndividualScopeTest.java rename to runtime-compiler/src/test/java/org/redlance/mocha/runtime/IndividualScopeTest.java index 862e89d..93a7093 100644 --- a/src/test/java/team/unnamed/mocha/runtime/IndividualScopeTest.java +++ b/runtime-compiler/src/test/java/org/redlance/mocha/runtime/IndividualScopeTest.java @@ -21,14 +21,13 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -package team.unnamed.mocha.runtime; +package org.redlance.mocha.runtime; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; -import team.unnamed.mocha.MochaEngine; -import team.unnamed.mocha.parser.ast.Expression; -import team.unnamed.mocha.parser.ast.IdentifierExpression; -import team.unnamed.mocha.runtime.value.NumberValue; +import org.redlance.mocha.parser.ast.Expression; +import org.redlance.mocha.parser.ast.IdentifierExpression; +import org.redlance.mocha.runtime.value.NumberValue; import java.util.Collections; import java.util.List; @@ -39,10 +38,10 @@ public class IndividualScopeTest { @Test public void testThis() { final MochaEngine engine = MochaEngine.createStandard(); - Assertions.assertEquals(0F, engine.eval(THIS)); - Assertions.assertEquals(10F, engine.eval(THIS, scope -> + Assertions.assertEquals(0F, engine.interpreter().eval(THIS)); + Assertions.assertEquals(10F, engine.interpreter().eval(THIS, scope -> scope.set("this", NumberValue.of(10F)) )); - Assertions.assertEquals(0F, engine.eval(THIS)); + Assertions.assertEquals(0F, engine.interpreter().eval(THIS)); } } diff --git a/src/test/java/team/unnamed/mocha/runtime/InstanceMethodBindingTest.java b/runtime-compiler/src/test/java/org/redlance/mocha/runtime/InstanceMethodBindingTest.java similarity index 82% rename from src/test/java/team/unnamed/mocha/runtime/InstanceMethodBindingTest.java rename to runtime-compiler/src/test/java/org/redlance/mocha/runtime/InstanceMethodBindingTest.java index 1871a4e..fb88959 100644 --- a/src/test/java/team/unnamed/mocha/runtime/InstanceMethodBindingTest.java +++ b/runtime-compiler/src/test/java/org/redlance/mocha/runtime/InstanceMethodBindingTest.java @@ -1,39 +1,38 @@ -/* - * This file is part of mocha, licensed under the MIT license - * - * Copyright (c) 2021-2025 Unnamed Team - * - * 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. - */ -package team.unnamed.mocha.runtime; +/* + * This file is part of mocha, licensed under the MIT license + * + * Copyright (c) 2021-2025 Unnamed Team + * + * 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. + */ +package org.redlance.mocha.runtime; import org.junit.jupiter.api.Test; -import team.unnamed.mocha.MochaEngine; -import team.unnamed.mocha.runtime.binding.Binding; +import org.redlance.mocha.runtime.binding.Binding; class InstanceMethodBindingTest { @Test void test() { final MochaEngine engine = MochaEngine.createStandard(); - engine.bindInstance(TestInstanceMethods.class, new TestInstanceMethods("UnnamedTeam"), "instance"); - engine.eval("instance.print_name()"); - engine.compile("instance.print_name()").evaluate(); + engine.interpreter().bindInstance(TestInstanceMethods.class, new TestInstanceMethods("UnnamedTeam"), "instance"); + engine.interpreter().eval("instance.print_name()"); + engine.compiler().compile("instance.print_name()").evaluate(); } public static final class TestInstanceMethods { diff --git a/src/test/java/team/unnamed/mocha/runtime/IntCompiledFunctionTest.java b/runtime-compiler/src/test/java/org/redlance/mocha/runtime/IntCompiledFunctionTest.java similarity index 88% rename from src/test/java/team/unnamed/mocha/runtime/IntCompiledFunctionTest.java rename to runtime-compiler/src/test/java/org/redlance/mocha/runtime/IntCompiledFunctionTest.java index 60208af..6858416 100644 --- a/src/test/java/team/unnamed/mocha/runtime/IntCompiledFunctionTest.java +++ b/runtime-compiler/src/test/java/org/redlance/mocha/runtime/IntCompiledFunctionTest.java @@ -21,19 +21,18 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -package team.unnamed.mocha.runtime; +package org.redlance.mocha.runtime; import org.junit.jupiter.api.Test; -import team.unnamed.mocha.MochaEngine; -import team.unnamed.mocha.runtime.compiled.MochaCompiledFunction; -import team.unnamed.mocha.runtime.compiled.Named; +import org.redlance.mocha.runtime.compiled.MochaCompiledFunction; +import org.redlance.mocha.runtime.compiled.Named; import static org.junit.jupiter.api.Assertions.assertEquals; class IntCompiledFunctionTest { @Test void test() throws Exception { - final IntFunction function = MochaEngine.createStandard().compile("math.mod(value / 20, 3)", IntFunction.class); + final IntFunction function = MochaEngine.createStandard().compiler().compile("math.mod(value / 20, 3)", IntFunction.class); assertEquals(0, function.get(0)); assertEquals(1, function.get(20)); diff --git a/src/test/java/team/unnamed/mocha/runtime/ParseErrorTest.java b/runtime-compiler/src/test/java/org/redlance/mocha/runtime/ParseErrorTest.java similarity index 81% rename from src/test/java/team/unnamed/mocha/runtime/ParseErrorTest.java rename to runtime-compiler/src/test/java/org/redlance/mocha/runtime/ParseErrorTest.java index 332edee..e836f48 100644 --- a/src/test/java/team/unnamed/mocha/runtime/ParseErrorTest.java +++ b/runtime-compiler/src/test/java/org/redlance/mocha/runtime/ParseErrorTest.java @@ -1,32 +1,31 @@ -/* - * This file is part of mocha, licensed under the MIT license - * - * Copyright (c) 2021-2025 Unnamed Team - * - * 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. - */ -package team.unnamed.mocha.runtime; +/* + * This file is part of mocha, licensed under the MIT license + * + * Copyright (c) 2021-2025 Unnamed Team + * + * 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. + */ +package org.redlance.mocha.runtime; import org.jetbrains.annotations.NotNull; import org.junit.jupiter.api.Test; -import team.unnamed.mocha.MochaEngine; -import team.unnamed.mocha.runtime.binding.Binding; +import org.redlance.mocha.runtime.binding.Binding; import java.util.ArrayList; import java.util.List; @@ -37,12 +36,12 @@ class ParseErrorTest { @Test void test() { final MochaEngine engine = MochaEngine.createStandard(); - engine.bind(QueryImpl.class); + engine.interpreter().bind(QueryImpl.class); - engine.handleParseExceptions(e -> assertEquals("Found error token: Unexpected token '\"', expected single quote (') to start a string literal\n\tat line 1, column 11", e.getMessage())); + engine.interpreter().handleParseExceptions(e -> assertEquals("Found error token: Unexpected token '\"', expected single quote (') to start a string literal\n\tat line 1, column 11", e.getMessage())); // should error since strings only allow single quotes - engine.eval("query.log(\"Hello world!\");"); + engine.interpreter().eval("query.log(\"Hello world!\");"); } @Binding({"query", "q"}) diff --git a/src/test/java/team/unnamed/mocha/runtime/arrow/ArrowOperatorTest.java b/runtime-compiler/src/test/java/org/redlance/mocha/runtime/arrow/ArrowOperatorTest.java similarity index 88% rename from src/test/java/team/unnamed/mocha/runtime/arrow/ArrowOperatorTest.java rename to runtime-compiler/src/test/java/org/redlance/mocha/runtime/arrow/ArrowOperatorTest.java index d246f3a..5f6ca91 100644 --- a/src/test/java/team/unnamed/mocha/runtime/arrow/ArrowOperatorTest.java +++ b/runtime-compiler/src/test/java/org/redlance/mocha/runtime/arrow/ArrowOperatorTest.java @@ -1,92 +1,92 @@ -/* - * This file is part of mocha, licensed under the MIT license - * - * Copyright (c) 2021-2025 Unnamed Team - * - * 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. - */ -package team.unnamed.mocha.runtime.arrow; - -import org.junit.jupiter.api.Test; -import team.unnamed.mocha.MochaEngine; -import team.unnamed.mocha.runtime.binding.Binding; -import team.unnamed.mocha.runtime.binding.Entity; -import team.unnamed.mocha.runtime.value.JavaValue; - -import java.util.ArrayList; -import java.util.List; - -import static org.junit.jupiter.api.Assertions.assertEquals; - -class ArrowOperatorTest { - @Test - void test() { - final World world = new World(); - final Player self = new Player(world, 8, "Steve"); - new Player(world, 9, "Pig"); - new Player(world, 15, "Chicken"); - new Player(world, 0, "Zombie"); - - final MochaEngine engine = MochaEngine.createStandard(self); - engine.bind(QueryImpl.class); - engine.scope().set("self", new JavaValue(self)); - - final float result = engine.eval( - "v.result = 0;\n" - + "for_each(t.nearby, self->q.get_nearby_entities(5), {\n" - + " v.result = v.result + t.nearby->q.get_location();\n" - + "});\n" - + "return v.result;" - ); - assertEquals(17F, result); - - - final float result2 = engine.eval( - "v.result = 0;\n" - + "for_each(t.nearby, self->q.get_nearby_entities(500), {\n" // Same code but 500 instead of 5 - + " v.result = v.result + t.nearby->q.get_location();\n" - + "});\n" - + "return v.result;" - ); - assertEquals(32F, result2); - } - - @Binding({"query", "q"}) - public static final class QueryImpl { - @Binding("get_location") - public static double getLocation(final @Entity Player player) { - return player.location; - } - - @Binding("get_nearby_entities") - public static Player[] getNearbyEntities(final @Entity Player player, final double distance) { - final int from = (int) Math.max(player.location - distance, 0); - final int to = (int) Math.min(player.location + distance, player.world.entities.length); - - List found = new ArrayList<>(); - for (int i = from; i < to; i++) { - final Player nearby = player.world.entities[i]; - if (nearby != null) { - found.add(nearby); - } - } - return found.toArray(Player[]::new); - } - } -} +/* + * This file is part of mocha, licensed under the MIT license + * + * Copyright (c) 2021-2025 Unnamed Team + * + * 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. + */ +package org.redlance.mocha.runtime.arrow; + +import org.junit.jupiter.api.Test; +import org.redlance.mocha.runtime.MochaEngine; +import org.redlance.mocha.runtime.binding.Binding; +import org.redlance.mocha.runtime.binding.Entity; +import org.redlance.mocha.runtime.value.JavaValue; + +import java.util.ArrayList; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +class ArrowOperatorTest { + @Test + void test() { + final World world = new World(); + final Player self = new Player(world, 8, "Steve"); + new Player(world, 9, "Pig"); + new Player(world, 15, "Chicken"); + new Player(world, 0, "Zombie"); + + final MochaEngine engine = MochaEngine.createStandard(self); + engine.interpreter().bind(QueryImpl.class); + engine.scope().set("self", new JavaValue(self)); + + final float result = engine.interpreter().eval( + "v.result = 0;\n" + + "for_each(t.nearby, self->q.get_nearby_entities(5), {\n" + + " v.result = v.result + t.nearby->q.get_location();\n" + + "});\n" + + "return v.result;" + ); + assertEquals(17F, result); + + + final float result2 = engine.interpreter().eval( + "v.result = 0;\n" + + "for_each(t.nearby, self->q.get_nearby_entities(500), {\n" // Same code but 500 instead of 5 + + " v.result = v.result + t.nearby->q.get_location();\n" + + "});\n" + + "return v.result;" + ); + assertEquals(32F, result2); + } + + @Binding({"query", "q"}) + public static final class QueryImpl { + @Binding("get_location") + public static double getLocation(final @Entity Player player) { + return player.location; + } + + @Binding("get_nearby_entities") + public static Player[] getNearbyEntities(final @Entity Player player, final double distance) { + final int from = (int) Math.max(player.location - distance, 0); + final int to = (int) Math.min(player.location + distance, player.world.entities.length); + + List found = new ArrayList<>(); + for (int i = from; i < to; i++) { + final Player nearby = player.world.entities[i]; + if (nearby != null) { + found.add(nearby); + } + } + return found.toArray(Player[]::new); + } + } +} diff --git a/src/test/java/team/unnamed/mocha/runtime/arrow/Player.java b/runtime-compiler/src/test/java/org/redlance/mocha/runtime/arrow/Player.java similarity index 95% rename from src/test/java/team/unnamed/mocha/runtime/arrow/Player.java rename to runtime-compiler/src/test/java/org/redlance/mocha/runtime/arrow/Player.java index c912243..fc0d654 100644 --- a/src/test/java/team/unnamed/mocha/runtime/arrow/Player.java +++ b/runtime-compiler/src/test/java/org/redlance/mocha/runtime/arrow/Player.java @@ -1,27 +1,27 @@ -/* - * This file is part of mocha, licensed under the MIT license - * - * Copyright (c) 2021-2025 Unnamed Team - * - * 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. - */ -package team.unnamed.mocha.runtime.arrow; +/* + * This file is part of mocha, licensed under the MIT license + * + * Copyright (c) 2021-2025 Unnamed Team + * + * 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. + */ +package org.redlance.mocha.runtime.arrow; class Player { World world; diff --git a/src/test/java/team/unnamed/mocha/runtime/arrow/World.java b/runtime-compiler/src/test/java/org/redlance/mocha/runtime/arrow/World.java similarity index 95% rename from src/test/java/team/unnamed/mocha/runtime/arrow/World.java rename to runtime-compiler/src/test/java/org/redlance/mocha/runtime/arrow/World.java index 602be86..336b61c 100644 --- a/src/test/java/team/unnamed/mocha/runtime/arrow/World.java +++ b/runtime-compiler/src/test/java/org/redlance/mocha/runtime/arrow/World.java @@ -1,27 +1,27 @@ -/* - * This file is part of mocha, licensed under the MIT license - * - * Copyright (c) 2021-2025 Unnamed Team - * - * 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. - */ -package team.unnamed.mocha.runtime.arrow; +/* + * This file is part of mocha, licensed under the MIT license + * + * Copyright (c) 2021-2025 Unnamed Team + * + * 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. + */ +package org.redlance.mocha.runtime.arrow; class World { // 1-dimensional world Player[] entities = new Player[64]; diff --git a/src/test/java/team/unnamed/mocha/runtime/jvm/ArithmeticCompiledRuntimeTest.java b/runtime-compiler/src/test/java/org/redlance/mocha/runtime/jvm/ArithmeticCompiledRuntimeTest.java similarity index 83% rename from src/test/java/team/unnamed/mocha/runtime/jvm/ArithmeticCompiledRuntimeTest.java rename to runtime-compiler/src/test/java/org/redlance/mocha/runtime/jvm/ArithmeticCompiledRuntimeTest.java index 7ec9dcf..e2c8e18 100644 --- a/src/test/java/team/unnamed/mocha/runtime/jvm/ArithmeticCompiledRuntimeTest.java +++ b/runtime-compiler/src/test/java/org/redlance/mocha/runtime/jvm/ArithmeticCompiledRuntimeTest.java @@ -21,12 +21,12 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -package team.unnamed.mocha.runtime.jvm; +package org.redlance.mocha.runtime.jvm; import org.junit.jupiter.api.Test; -import team.unnamed.mocha.MochaEngine; -import team.unnamed.mocha.runtime.compiled.MochaCompiledFunction; -import team.unnamed.mocha.runtime.compiled.Named; +import org.redlance.mocha.runtime.MochaEngine; +import org.redlance.mocha.runtime.compiled.MochaCompiledFunction; +import org.redlance.mocha.runtime.compiled.Named; import static org.junit.jupiter.api.Assertions.*; @@ -44,7 +44,7 @@ void test() { // 7: goto 11 // 10: iconst_1 // 11: ireturn - final ComparisonFunction gt = engine.compile("a > b", ComparisonFunction.class); + final ComparisonFunction gt = engine.compiler().compile("a > b", ComparisonFunction.class); assertTrue(gt.compare(10, 5)); assertFalse(gt.compare(-50, -20)); assertFalse(gt.compare(3F, 3F)); @@ -59,7 +59,7 @@ void test() { // 7: goto 11 // 10: iconst_1 // 11: ireturn - final ComparisonFunction lt = engine.compile("a < b", ComparisonFunction.class); + final ComparisonFunction lt = engine.compiler().compile("a < b", ComparisonFunction.class); assertFalse(lt.compare(10, 5)); assertTrue(lt.compare(-50, -20)); assertFalse(lt.compare(3F, 3F)); @@ -74,7 +74,7 @@ void test() { // 7: goto 11 // 10: iconst_1 // 11: ireturn - final ComparisonFunction gte = engine.compile("a >= b", ComparisonFunction.class); + final ComparisonFunction gte = engine.compiler().compile("a >= b", ComparisonFunction.class); assertTrue(gte.compare(10, 5)); assertFalse(gte.compare(-50, -20)); assertTrue(gte.compare(3F, 3F)); @@ -89,7 +89,7 @@ void test() { // 7: goto 11 // 10: iconst_1 // 11: ireturn - final ComparisonFunction lte = engine.compile("a <= b", ComparisonFunction.class); + final ComparisonFunction lte = engine.compiler().compile("a <= b", ComparisonFunction.class); assertFalse(lte.compare(10, 5)); assertTrue(lte.compare(-50, -20)); assertTrue(lte.compare(3F, 3F)); @@ -104,7 +104,7 @@ void test() { // 7: goto 11 // 10: iconst_1 // 11: ireturn - final ComparisonFunction eq = engine.compile("a == b", ComparisonFunction.class); + final ComparisonFunction eq = engine.compiler().compile("a == b", ComparisonFunction.class); assertFalse(eq.compare(10, 5)); assertFalse(eq.compare(-50, -20)); assertTrue(eq.compare(3F, 3F)); @@ -119,7 +119,7 @@ void test() { // 7: goto 11 // 10: iconst_1 // 11: ireturn - final ComparisonFunction neq = engine.compile("a != b", ComparisonFunction.class); + final ComparisonFunction neq = engine.compiler().compile("a != b", ComparisonFunction.class); assertTrue(neq.compare(10, 5)); assertTrue(neq.compare(-50, -20)); assertFalse(neq.compare(3F, 3F)); @@ -135,7 +135,7 @@ void test() { // 7: goto 11 // 10: lconst_1 // 11: lreturn - final StupidLongComparisonFunction gt = engine.compile("a > b", StupidLongComparisonFunction.class); + final StupidLongComparisonFunction gt = engine.compiler().compile("a > b", StupidLongComparisonFunction.class); assertEquals(1L, gt.compare(10, 5)); assertEquals(0L, gt.compare(-50, -20)); assertEquals(0L, gt.compare(3F, 3F)); diff --git a/src/test/java/team/unnamed/mocha/runtime/jvm/LogicalCompiledRuntimeTest.java b/runtime-compiler/src/test/java/org/redlance/mocha/runtime/jvm/LogicalCompiledRuntimeTest.java similarity index 86% rename from src/test/java/team/unnamed/mocha/runtime/jvm/LogicalCompiledRuntimeTest.java rename to runtime-compiler/src/test/java/org/redlance/mocha/runtime/jvm/LogicalCompiledRuntimeTest.java index 9cd32f5..c3a568d 100644 --- a/src/test/java/team/unnamed/mocha/runtime/jvm/LogicalCompiledRuntimeTest.java +++ b/runtime-compiler/src/test/java/org/redlance/mocha/runtime/jvm/LogicalCompiledRuntimeTest.java @@ -1,32 +1,32 @@ -/* - * This file is part of mocha, licensed under the MIT license - * - * Copyright (c) 2021-2025 Unnamed Team - * - * 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. - */ -package team.unnamed.mocha.runtime.jvm; +/* + * This file is part of mocha, licensed under the MIT license + * + * Copyright (c) 2021-2025 Unnamed Team + * + * 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. + */ +package org.redlance.mocha.runtime.jvm; import org.junit.jupiter.api.Test; -import team.unnamed.mocha.MochaEngine; -import team.unnamed.mocha.runtime.compiled.MochaCompiledFunction; -import team.unnamed.mocha.runtime.compiled.Named; +import org.redlance.mocha.runtime.MochaEngine; +import org.redlance.mocha.runtime.compiled.MochaCompiledFunction; +import org.redlance.mocha.runtime.compiled.Named; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -45,7 +45,7 @@ void test() { // 9: goto +4 (13) // 12: iconst_0 // 13: ireturn - final LogicalFunction and = engine.compile("a && b", LogicalFunction.class); + final LogicalFunction and = engine.compiler().compile("a && b", LogicalFunction.class); assertTrue(and.apply(true, true)); assertFalse(and.apply(true, false)); assertFalse(and.apply(false, true)); @@ -61,7 +61,7 @@ void test() { // 9: goto +4 (13) // 12: iconst_0 // 13: ireturn - final LogicalFunction or = engine.compile("a || b", LogicalFunction.class); + final LogicalFunction or = engine.compiler().compile("a || b", LogicalFunction.class); assertTrue(or.apply(true, true)); assertTrue(or.apply(true, false)); assertTrue(or.apply(false, true)); diff --git a/src/test/java/team/unnamed/mocha/runtime/jvm/MathCompiledRuntimeTest.java b/runtime-compiler/src/test/java/org/redlance/mocha/runtime/jvm/MathCompiledRuntimeTest.java similarity index 83% rename from src/test/java/team/unnamed/mocha/runtime/jvm/MathCompiledRuntimeTest.java rename to runtime-compiler/src/test/java/org/redlance/mocha/runtime/jvm/MathCompiledRuntimeTest.java index 0e85a99..8b8fe9c 100644 --- a/src/test/java/team/unnamed/mocha/runtime/jvm/MathCompiledRuntimeTest.java +++ b/runtime-compiler/src/test/java/org/redlance/mocha/runtime/jvm/MathCompiledRuntimeTest.java @@ -1,64 +1,64 @@ -/* - * This file is part of mocha, licensed under the MIT license - * - * Copyright (c) 2021-2025 Unnamed Team - * - * 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. - */ -package team.unnamed.mocha.runtime.jvm; - -import org.junit.jupiter.api.Test; -import team.unnamed.mocha.MochaEngine; -import team.unnamed.mocha.runtime.compiled.MochaCompiledFunction; -import team.unnamed.mocha.runtime.compiled.Named; - -import static org.junit.jupiter.api.Assertions.assertEquals; - -class MathCompiledRuntimeTest { - @Test - void test() { - final MochaEngine engine = MochaEngine.createStandard(); - { - // 0: dload_1 - // 1: invokestatic - // 4: dreturn - final MathFunction cos = engine.compile("math.cos(x)", MathFunction.class); - assertEquals(1F, cos.apply(0), 0.0001); - assertEquals(4F / 5D, cos.apply(37), 0.01); - assertEquals(3F / 5D, cos.apply(53), 0.01); - assertEquals(0F, cos.apply(90), 0.0001); - assertEquals(-1F, cos.apply(180), 0.0001); - } - { - // 0: dload_1 - // 1: invokestatic - // 4: l2d - // 5: dreturn - final MathFunction round = engine.compile("math.round(x)", MathFunction.class); - assertEquals(5.0F, round.apply(5.4F)); - assertEquals(6.0F, round.apply(5.5F)); - assertEquals(6.0F, round.apply(5.6F)); - assertEquals(-5.0F, round.apply(-5.4F)); - } - } - - public interface MathFunction extends MochaCompiledFunction { - float apply(@Named("x") float x); - } -} +/* + * This file is part of mocha, licensed under the MIT license + * + * Copyright (c) 2021-2025 Unnamed Team + * + * 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. + */ +package org.redlance.mocha.runtime.jvm; + +import org.junit.jupiter.api.Test; +import org.redlance.mocha.runtime.MochaEngine; +import org.redlance.mocha.runtime.compiled.MochaCompiledFunction; +import org.redlance.mocha.runtime.compiled.Named; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +class MathCompiledRuntimeTest { + @Test + void test() { + final MochaEngine engine = MochaEngine.createStandard(); + { + // 0: dload_1 + // 1: invokestatic + // 4: dreturn + final MathFunction cos = engine.compiler().compile("math.cos(x)", MathFunction.class); + assertEquals(1F, cos.apply(0), 0.0001); + assertEquals(4F / 5D, cos.apply(37), 0.01); + assertEquals(3F / 5D, cos.apply(53), 0.01); + assertEquals(0F, cos.apply(90), 0.0001); + assertEquals(-1F, cos.apply(180), 0.0001); + } + { + // 0: dload_1 + // 1: invokestatic + // 4: l2d + // 5: dreturn + final MathFunction round = engine.compiler().compile("math.round(x)", MathFunction.class); + assertEquals(5.0F, round.apply(5.4F)); + assertEquals(6.0F, round.apply(5.5F)); + assertEquals(6.0F, round.apply(5.6F)); + assertEquals(-5.0F, round.apply(-5.4F)); + } + } + + public interface MathFunction extends MochaCompiledFunction { + float apply(@Named("x") float x); + } +} diff --git a/src/test/java/team/unnamed/mocha/runtime/jvm/MolangCompilerTest.java b/runtime-compiler/src/test/java/org/redlance/mocha/runtime/jvm/MolangCompilerTest.java similarity index 76% rename from src/test/java/team/unnamed/mocha/runtime/jvm/MolangCompilerTest.java rename to runtime-compiler/src/test/java/org/redlance/mocha/runtime/jvm/MolangCompilerTest.java index 6667a9e..c193731 100644 --- a/src/test/java/team/unnamed/mocha/runtime/jvm/MolangCompilerTest.java +++ b/runtime-compiler/src/test/java/org/redlance/mocha/runtime/jvm/MolangCompilerTest.java @@ -21,12 +21,12 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -package team.unnamed.mocha.runtime.jvm; +package org.redlance.mocha.runtime.jvm; import org.junit.jupiter.api.Test; -import team.unnamed.mocha.MochaEngine; -import team.unnamed.mocha.runtime.compiled.MochaCompiledFunction; -import team.unnamed.mocha.runtime.compiled.Named; +import org.redlance.mocha.runtime.MochaEngine; +import org.redlance.mocha.runtime.compiled.MochaCompiledFunction; +import org.redlance.mocha.runtime.compiled.Named; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -34,22 +34,22 @@ public class MolangCompilerTest { @Test void test() { final MochaEngine engine = MochaEngine.createStandard(); - final ScriptType script = engine.compile("false ? a : b", ScriptType.class); + final ScriptType script = engine.compiler().compile("false ? a : b", ScriptType.class); assertEquals(2, script.eval(1, 2)); assertEquals(50, script.eval(20, 50)); assertEquals(200, script.eval(50, 200)); - final ScriptType script2 = engine.compile("a + (b - a) * 0.5", ScriptType.class); + final ScriptType script2 = engine.compiler().compile("a + (b - a) * 0.5", ScriptType.class); assertEquals(5, script2.eval(1, 10)); assertEquals(20, script2.eval(20, 20)); assertEquals(50, script2.eval(-50, 150)); - final ScriptType script3 = engine.compile("(a > b) ? a : b", ScriptType.class); + final ScriptType script3 = engine.compiler().compile("(a > b) ? a : b", ScriptType.class); assertEquals(10, script3.eval(10, 5)); assertEquals(50, script3.eval(50, -20)); assertEquals(3, script3.eval(3F, 3F)); - final ScriptType script4 = engine.compile("(a < b) ? a : b", ScriptType.class); + final ScriptType script4 = engine.compiler().compile("(a < b) ? a : b", ScriptType.class); assertEquals(5, script4.eval(10, 5)); assertEquals(-20, script4.eval(50, -20)); assertEquals(3, script4.eval(3F, 3F)); @@ -59,7 +59,7 @@ void test() { void test_native() { final MochaEngine engine = MochaEngine.createStandard(); //compiler.registerStaticNatives(MolangCompilerTest.class); - System.out.println(engine.compile("3 * math.abs(5 * 5 * -1) + 1").evaluate()); + System.out.println(engine.compiler().compile("3 * math.abs(5 * 5 * -1) + 1").evaluate()); } public interface ScriptType extends MochaCompiledFunction { diff --git a/src/test/java/team/unnamed/mocha/runtime/standart/MochaMathTest.java b/runtime-compiler/src/test/java/org/redlance/mocha/runtime/standart/MochaMathTest.java similarity index 88% rename from src/test/java/team/unnamed/mocha/runtime/standart/MochaMathTest.java rename to runtime-compiler/src/test/java/org/redlance/mocha/runtime/standart/MochaMathTest.java index da4f762..49c3926 100644 --- a/src/test/java/team/unnamed/mocha/runtime/standart/MochaMathTest.java +++ b/runtime-compiler/src/test/java/org/redlance/mocha/runtime/standart/MochaMathTest.java @@ -21,16 +21,16 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -package team.unnamed.mocha.runtime.standart; +package org.redlance.mocha.runtime.standart; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; -import team.unnamed.mocha.MochaEngine; +import org.redlance.mocha.runtime.MochaEngine; public class MochaMathTest { @Test void test() { final MochaEngine engine = MochaEngine.createStandard(); - Assertions.assertEquals(Math.abs(-10F), engine.eval("math.abs(-10);")); + Assertions.assertEquals(Math.abs(-10F), engine.interpreter().eval("math.abs(-10);")); } } diff --git a/src/test/resources/expectations.txt b/runtime-compiler/src/test/resources/expectations.txt similarity index 100% rename from src/test/resources/expectations.txt rename to runtime-compiler/src/test/resources/expectations.txt diff --git a/src/test/resources/tests.txt b/runtime-compiler/src/test/resources/tests.txt similarity index 100% rename from src/test/resources/tests.txt rename to runtime-compiler/src/test/resources/tests.txt diff --git a/runtime/build.gradle b/runtime/build.gradle new file mode 100644 index 0000000..1f1b554 --- /dev/null +++ b/runtime/build.gradle @@ -0,0 +1,3 @@ +dependencies { + api project(":parser") +} diff --git a/src/main/java/team/unnamed/mocha/runtime/ExecutionContext.java b/runtime/src/main/java/org/redlance/mocha/runtime/ExecutionContext.java similarity index 90% rename from src/main/java/team/unnamed/mocha/runtime/ExecutionContext.java rename to runtime/src/main/java/org/redlance/mocha/runtime/ExecutionContext.java index 847ddba..32bf3a4 100644 --- a/src/main/java/team/unnamed/mocha/runtime/ExecutionContext.java +++ b/runtime/src/main/java/org/redlance/mocha/runtime/ExecutionContext.java @@ -1,32 +1,32 @@ -/* - * This file is part of mocha, licensed under the MIT license - * - * Copyright (c) 2021-2025 Unnamed Team - * - * 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. - */ -package team.unnamed.mocha.runtime; +/* + * This file is part of mocha, licensed under the MIT license + * + * Copyright (c) 2021-2025 Unnamed Team + * + * 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. + */ +package org.redlance.mocha.runtime; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import team.unnamed.mocha.parser.ast.Expression; -import team.unnamed.mocha.runtime.value.Value; +import org.redlance.mocha.parser.ast.Expression; +import org.redlance.mocha.runtime.value.Value; public interface ExecutionContext { T entity(); diff --git a/src/main/java/team/unnamed/mocha/runtime/ExpressionInliner.java b/runtime/src/main/java/org/redlance/mocha/runtime/ExpressionInliner.java similarity index 89% rename from src/main/java/team/unnamed/mocha/runtime/ExpressionInliner.java rename to runtime/src/main/java/org/redlance/mocha/runtime/ExpressionInliner.java index 95f2bb8..5c252a0 100644 --- a/src/main/java/team/unnamed/mocha/runtime/ExpressionInliner.java +++ b/runtime/src/main/java/org/redlance/mocha/runtime/ExpressionInliner.java @@ -1,35 +1,35 @@ -/* - * This file is part of mocha, licensed under the MIT license - * - * Copyright (c) 2021-2025 Unnamed Team - * - * 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. - */ -package team.unnamed.mocha.runtime; +/* + * This file is part of mocha, licensed under the MIT license + * + * Copyright (c) 2021-2025 Unnamed Team + * + * 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. + */ +package org.redlance.mocha.runtime; import org.jetbrains.annotations.NotNull; -import team.unnamed.mocha.parser.ast.BinaryExpression; -import team.unnamed.mocha.parser.ast.CallExpression; -import team.unnamed.mocha.parser.ast.FloatExpression; -import team.unnamed.mocha.parser.ast.Expression; -import team.unnamed.mocha.parser.ast.ExpressionVisitor; -import team.unnamed.mocha.parser.ast.TernaryConditionalExpression; +import org.redlance.mocha.parser.ast.BinaryExpression; +import org.redlance.mocha.parser.ast.CallExpression; +import org.redlance.mocha.parser.ast.FloatExpression; +import org.redlance.mocha.parser.ast.Expression; +import org.redlance.mocha.parser.ast.ExpressionVisitor; +import org.redlance.mocha.parser.ast.TernaryConditionalExpression; import static java.util.Objects.requireNonNull; diff --git a/src/main/java/team/unnamed/mocha/runtime/ExpressionInterpreter.java b/runtime/src/main/java/org/redlance/mocha/runtime/ExpressionInterpreter.java similarity index 96% rename from src/main/java/team/unnamed/mocha/runtime/ExpressionInterpreter.java rename to runtime/src/main/java/org/redlance/mocha/runtime/ExpressionInterpreter.java index c01a920..084da29 100644 --- a/src/main/java/team/unnamed/mocha/runtime/ExpressionInterpreter.java +++ b/runtime/src/main/java/org/redlance/mocha/runtime/ExpressionInterpreter.java @@ -1,478 +1,478 @@ -/* - * This file is part of mocha, licensed under the MIT license - * - * Copyright (c) 2021-2025 Unnamed Team - * - * 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. - */ -package team.unnamed.mocha.runtime; - -import org.jetbrains.annotations.ApiStatus; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import team.unnamed.mocha.parser.ast.*; -import team.unnamed.mocha.runtime.binding.JavaFunction; -import team.unnamed.mocha.runtime.value.*; - -import java.util.Arrays; -import java.util.List; - -import static java.util.Objects.requireNonNull; - -@ApiStatus.Internal -public final class ExpressionInterpreter implements ExpressionVisitor, ExecutionContext { - private static final List BINARY_EVALUATORS = Arrays.asList( - bool((a, b) -> a.eval() && b.eval()), - bool((a, b) -> a.eval() || b.eval()), - compare((a, b) -> a.eval() < b.eval()), - compare((a, b) -> a.eval() <= b.eval()), - compare((a, b) -> a.eval() > b.eval()), - compare((a, b) -> a.eval() >= b.eval()), - (evaluator, a, b) -> { - final Value aVal = a.visit(evaluator); - final Value bVal = b.visit(evaluator); - // string concatenation is not supported in molang - // if (aVal.isString() || bVal.isString()) { - // return StringValue.of(aVal.getAsString() + bVal.getAsString()); - // } else { - return NumberValue.of(aVal.getAsNumber() + bVal.getAsNumber()); - // } - }, - arithmetic((a, b) -> a.eval() - b.eval()), - arithmetic((a, b) -> a.eval() * b.eval()), - arithmetic((a, b) -> { - // Molang allows division by zero, - // which is always equal to 0 - final float dividend = a.eval(); - final float divisor = b.eval(); - if (divisor == 0) return 0; - else return dividend / divisor; - }), - (evaluator, a, b) -> { // arrow - final Value val = a.visit(evaluator); - if (!(val instanceof JavaValue)) { - return NumberValue.zero(); - } else { - return b.visit(evaluator.createChild(((JavaValue) val).value())); - } - }, - (evaluator, a, b) -> { // null coalesce - final Value val = a.visit(evaluator); - if (val.getAsBoolean()) { - return val; - } else { - return b.visit(evaluator); - } - }, - (evaluator, a, b) -> { // assignation - final Value val = b.visit(evaluator); - // we can only assign to values that are accessed - // like: - // temp.x = 1 - // t.location.world = 'world' - // but not: - // x = 1 - // i = 2 - if (a instanceof AccessExpression) { - final AccessExpression access = (AccessExpression) a; - final Value objectValue = access.object().visit(evaluator); - if (objectValue instanceof MutableObjectBinding) { - ((MutableObjectBinding) objectValue).set(access.property(), val); - } - } - return val; - }, - (evaluator, a, b) -> { // conditional - final Value conditionValue = a.visit(evaluator); - if (conditionValue.getAsBoolean()) { - final Value predicateVal = b.visit(evaluator); - if (predicateVal instanceof Function) { - return Value.of(((Function) predicateVal).evaluate(evaluator)); - } else { - return predicateVal; - } - } - return NumberValue.zero(); - }, - arithmetic((a, b) -> ((a.eval() == b.eval()) ? 1.0F : 0.0F)), // eq - arithmetic((a, b) -> ((a.eval() != b.eval()) ? 1.0F : 0.0F)) // neq - ); - - private final T entity; - private final Scope scope; - private @Nullable Object flag; - private @Nullable Value returnValue; - - private boolean warnOnReflectiveFunctionUsage; - - public ExpressionInterpreter(final @Nullable T entity, final @NotNull Scope scope) { - this.entity = entity; - this.scope = requireNonNull(scope, "scope"); - } - - private static Evaluator bool(BooleanOperator op) { - return (evaluator, a, b) -> Value.of(op.operate( - () -> a.visit(evaluator).getAsBoolean(), - () -> b.visit(evaluator).getAsBoolean() - )); - } - - private static Evaluator compare(Comparator comp) { - return (evaluator, a, b) -> Value.of(comp.compare( - () -> a.visit(evaluator).getAsNumber(), - () -> b.visit(evaluator).getAsNumber() - )); - } - - private static Evaluator arithmetic(ArithmeticOperator op) { - return (evaluator, a, b) -> NumberValue.of(op.operate( - () -> a.visit(evaluator).getAsNumber(), - () -> b.visit(evaluator).getAsNumber() - )); - } - - public void warnOnReflectiveFunctionUsage(final boolean warnOnReflectiveFunctionUsage) { - this.warnOnReflectiveFunctionUsage = warnOnReflectiveFunctionUsage; - } - - @Override - public @Nullable Object flag() { - return flag; - } - - @Override - public void flag(final @Nullable Object flag) { - this.flag = flag; - } - - @Override - public T entity() { - return entity; - } - - @Override - public @NotNull Value eval(final @NotNull Expression expression) { - return expression.visit(this); - } - - public @NotNull ExpressionInterpreter createChild(final @Nullable R entity) { - return new ExpressionInterpreter<>(entity, this.scope); - } - - public @NotNull ExpressionInterpreter createChild() { - // Note that it will have its own returnValue, but same bindings - // (Should we create new bindings?) - return new ExpressionInterpreter<>(this.entity, this.scope); - } - - public @NotNull Scope bindings() { - return scope; - } - - public @Nullable Value popReturnValue() { - final Value val = this.returnValue; - this.returnValue = null; - return val; - } - - @Override - public @NotNull Value visitArrayAccess(final @NotNull ArrayAccessExpression expression) { - final Value array = expression.array().visit(this); - final Value index = expression.index().visit(this); - if (!(array instanceof ArrayValue)) { - return Value.nil(); - } else { - final Value[] values = ((ArrayValue) array).values(); - final int validIndex = Math.max(0, (int) index.getAsNumber()) % values.length; - return values[validIndex]; - } - } - - @Override - public @NotNull Value visitAccess(final @NotNull AccessExpression expression) { - final Value objectValue = expression.object().visit(this); - if (objectValue instanceof ObjectValue) { - return ((ObjectValue) objectValue).get(expression.property()); - } - return NumberValue.zero(); - } - - @Override - public @NotNull Value visitCall(final @NotNull CallExpression expression) { - final List argumentsExpressions = expression.arguments(); - final Function.Argument[] arguments = new Function.Argument[argumentsExpressions.size()]; - for (int i = 0; i < argumentsExpressions.size(); i++) { - arguments[i] = new FunctionArgumentImpl(argumentsExpressions.get(i)); - } - final Function.Arguments args = new FunctionArguments(arguments); - - final Expression functionExpr = expression.function(); - if (functionExpr instanceof IdentifierExpression) { - final String identifierName = ((IdentifierExpression) functionExpr).name(); - if ("loop".equals(identifierName)) { - // loop built-in function - // Parameters: - // - float: How many times should we loop - // - CallableBinding: The looped expressions - int n = Math.round(args.next().eval().getAsNumber()); - Value expr = args.next().eval(); - - if (expr instanceof Function) { - final Function callable = (Function) expr; - for (int i = 0; i < n; i++) { - final ExpressionInterpreter evaluatorThisCall = createChild(); - callable.evaluate(evaluatorThisCall); - if (evaluatorThisCall.flag() == StatementExpression.Op.BREAK) { - break; - } - // (not necessary, callable already exits when returnValue - // is set to any non-null value) - // if (value == StatementExpression.Op.CONTINUE) continue; - } - } - return NumberValue.zero(); - } else if ("for_each".equals(identifierName)) { - // for each built-in function - // Parameters: - // - any: Variable - // - array: Any array - // - CallableBinding: The looped expressions - final Expression variableExpr = args.next().expression(); - if (!(variableExpr instanceof AccessExpression)) { - // first argument must be an access expression, - // e.g. 'variable.test', 'v.pig', 't.entity' or - // 't.entity.location.world' - return NumberValue.zero(); - } - final AccessExpression variableAccess = (AccessExpression) variableExpr; - final Expression objectExpr = variableAccess.object(); - final String propertyName = variableAccess.property(); - - final Value array = args.next().eval(); - final Iterable arrayIterable; - if (array instanceof ArrayValue) { - arrayIterable = Arrays.asList(((ArrayValue) array).values()); - } else { - // second argument must be an array or iterable - return NumberValue.zero(); - } - - final Value expr = args.next().eval(); - - if (expr instanceof Function) { - final Function callable = (Function) expr; - for (final Value val : arrayIterable) { - // set 'val' as current value - // eval (objectExpr.propertyName = val) - final Value evaluatedObjectValue = this.eval(objectExpr); - if (evaluatedObjectValue instanceof MutableObjectBinding) { - ((MutableObjectBinding) evaluatedObjectValue).set(propertyName, val); - } - final Object returnValue = callable.evaluate(this); - - if (returnValue == StatementExpression.Op.BREAK) { - break; - } - } - } - return NumberValue.zero(); - } - } - - final Value function = functionExpr.visit(this); - if (!(function instanceof Function)) { - return Value.nil(); - } - - if (warnOnReflectiveFunctionUsage && function instanceof JavaFunction) { - final JavaFunction javaFunction = (JavaFunction) function; - System.err.println("Warning: Reflective function usage detected for method: " + javaFunction.method()); - } - - return ((Function) function).evaluate(this, args); - } - - @Override - public @NotNull Value visitFloat(final @NotNull FloatExpression expression) { - return NumberValue.of(expression.value()); - } - - @Override - public @NotNull Value visitExecutionScope(final @NotNull ExecutionScopeExpression executionScope) { - List expressions = executionScope.expressions(); - return (Function) (context, arguments) -> { - for (Expression expression : expressions) { - // eval expression, ignore result - context.eval(expression); - - // check for return values - if (context.flag() != null) { - break; - } - } - return NumberValue.zero(); - }; - } - - @Override - public @NotNull Value visitIdentifier(final @NotNull IdentifierExpression expression) { - return scope.get(expression.name()); - } - - @Override - public @NotNull Value visitBinary(@NotNull BinaryExpression expression) { - return BINARY_EVALUATORS.get(expression.op().ordinal()).eval( - this, - expression.left(), - expression.right() - ); - } - - @Override - public @NotNull Value visitUnary(final @NotNull UnaryExpression expression) { - final Value value = expression.expression().visit(this); - switch (expression.op()) { - case LOGICAL_NEGATION: - return Value.of(!value.getAsBoolean()); - case ARITHMETICAL_NEGATION: - return NumberValue.of(-value.getAsNumber()); - case RETURN: { - this.returnValue = value; - return NumberValue.zero(); - } - default: - throw new IllegalStateException("Unknown operation"); - } - } - - @Override - public @NotNull Value visitStatement(final @NotNull StatementExpression expression) { - switch (expression.op()) { - case BREAK: { - this.flag = StatementExpression.Op.BREAK; - break; - } - case CONTINUE: { - this.flag = StatementExpression.Op.CONTINUE; - break; - } - } - return NumberValue.zero(); - } - - @Override - public @NotNull Value visitString(final @NotNull StringExpression expression) { - return StringValue.of(expression.value()); - } - - @Override - public @NotNull Value visitTernaryConditional(@NotNull TernaryConditionalExpression expression) { - final Value conditionResult = expression.condition().visit(this); - return conditionResult.getAsBoolean() - ? expression.trueExpression().visit(this) - : expression.falseExpression().visit(this); - } - - @Override - public Value visit(final @NotNull Expression expression) { - throw new UnsupportedOperationException("Unsupported expression type: " + expression); - } - - private interface Evaluator { - @NotNull Value eval(ExpressionInterpreter evaluator, Expression a, Expression b); - } - - private interface BooleanOperator { - boolean operate(LazyEvaluableBoolean a, LazyEvaluableBoolean b); - } - - interface LazyEvaluableBoolean { - boolean eval(); - } - - interface LazyEvaluableFloat { - float eval(); - } - - private interface Comparator { - boolean compare(LazyEvaluableFloat a, LazyEvaluableFloat b); - - } - - private interface ArithmeticOperator { - float operate(LazyEvaluableFloat a, LazyEvaluableFloat b); - } - - public static class FunctionArguments implements Function.Arguments { - public static final Function.Arguments EMPTY = new FunctionArguments(new Function.Argument[0]); - - private final Function.Argument[] arguments; - private int next; - - FunctionArguments(final @NotNull Function.Argument @NotNull [] arguments) { - this.arguments = requireNonNull(arguments, "arguments"); - } - - @Override - public Function.@NotNull Argument next() { - if (next < arguments.length) { - return arguments[next++]; - } else { - return EmptyFunctionArgument.EMPTY; - } - } - - @Override - public int length() { - return arguments.length; - } - } - - private static class EmptyFunctionArgument implements Function.Argument { - static final Function.Argument EMPTY = new EmptyFunctionArgument(); - - @Override - public @Nullable Expression expression() { - return null; - } - - @Override - public @Nullable Value eval() { - return NumberValue.zero(); - } - } - - private class FunctionArgumentImpl implements Function.Argument { - private final Expression expression; - - FunctionArgumentImpl(final @NotNull Expression expression) { - this.expression = expression; - } - - @Override - public @NotNull Expression expression() { - return expression; - } - - @Override - public @Nullable Value eval() { - return expression.visit(ExpressionInterpreter.this); - } - } -} +/* + * This file is part of mocha, licensed under the MIT license + * + * Copyright (c) 2021-2025 Unnamed Team + * + * 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. + */ +package org.redlance.mocha.runtime; + +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.redlance.mocha.parser.ast.*; +import org.redlance.mocha.runtime.binding.JavaFunction; +import org.redlance.mocha.runtime.value.*; + +import java.util.Arrays; +import java.util.List; + +import static java.util.Objects.requireNonNull; + +@ApiStatus.Internal +public final class ExpressionInterpreter implements ExpressionVisitor, ExecutionContext { + private static final List BINARY_EVALUATORS = Arrays.asList( + bool((a, b) -> a.eval() && b.eval()), + bool((a, b) -> a.eval() || b.eval()), + compare((a, b) -> a.eval() < b.eval()), + compare((a, b) -> a.eval() <= b.eval()), + compare((a, b) -> a.eval() > b.eval()), + compare((a, b) -> a.eval() >= b.eval()), + (evaluator, a, b) -> { + final Value aVal = a.visit(evaluator); + final Value bVal = b.visit(evaluator); + // string concatenation is not supported in molang + // if (aVal.isString() || bVal.isString()) { + // return StringValue.of(aVal.getAsString() + bVal.getAsString()); + // } else { + return NumberValue.of(aVal.getAsNumber() + bVal.getAsNumber()); + // } + }, + arithmetic((a, b) -> a.eval() - b.eval()), + arithmetic((a, b) -> a.eval() * b.eval()), + arithmetic((a, b) -> { + // Molang allows division by zero, + // which is always equal to 0 + final float dividend = a.eval(); + final float divisor = b.eval(); + if (divisor == 0) return 0; + else return dividend / divisor; + }), + (evaluator, a, b) -> { // arrow + final Value val = a.visit(evaluator); + if (!(val instanceof JavaValue)) { + return NumberValue.zero(); + } else { + return b.visit(evaluator.createChild(((JavaValue) val).value())); + } + }, + (evaluator, a, b) -> { // null coalesce + final Value val = a.visit(evaluator); + if (val.getAsBoolean()) { + return val; + } else { + return b.visit(evaluator); + } + }, + (evaluator, a, b) -> { // assignation + final Value val = b.visit(evaluator); + // we can only assign to values that are accessed + // like: + // temp.x = 1 + // t.location.world = 'world' + // but not: + // x = 1 + // i = 2 + if (a instanceof AccessExpression) { + final AccessExpression access = (AccessExpression) a; + final Value objectValue = access.object().visit(evaluator); + if (objectValue instanceof MutableObjectBinding) { + ((MutableObjectBinding) objectValue).set(access.property(), val); + } + } + return val; + }, + (evaluator, a, b) -> { // conditional + final Value conditionValue = a.visit(evaluator); + if (conditionValue.getAsBoolean()) { + final Value predicateVal = b.visit(evaluator); + if (predicateVal instanceof Function) { + return Value.of(((Function) predicateVal).evaluate(evaluator)); + } else { + return predicateVal; + } + } + return NumberValue.zero(); + }, + arithmetic((a, b) -> ((a.eval() == b.eval()) ? 1.0F : 0.0F)), // eq + arithmetic((a, b) -> ((a.eval() != b.eval()) ? 1.0F : 0.0F)) // neq + ); + + private final T entity; + private final Scope scope; + private @Nullable Object flag; + private @Nullable Value returnValue; + + private boolean warnOnReflectiveFunctionUsage; + + public ExpressionInterpreter(final @Nullable T entity, final @NotNull Scope scope) { + this.entity = entity; + this.scope = requireNonNull(scope, "scope"); + } + + private static Evaluator bool(BooleanOperator op) { + return (evaluator, a, b) -> Value.of(op.operate( + () -> a.visit(evaluator).getAsBoolean(), + () -> b.visit(evaluator).getAsBoolean() + )); + } + + private static Evaluator compare(Comparator comp) { + return (evaluator, a, b) -> Value.of(comp.compare( + () -> a.visit(evaluator).getAsNumber(), + () -> b.visit(evaluator).getAsNumber() + )); + } + + private static Evaluator arithmetic(ArithmeticOperator op) { + return (evaluator, a, b) -> NumberValue.of(op.operate( + () -> a.visit(evaluator).getAsNumber(), + () -> b.visit(evaluator).getAsNumber() + )); + } + + public void warnOnReflectiveFunctionUsage(final boolean warnOnReflectiveFunctionUsage) { + this.warnOnReflectiveFunctionUsage = warnOnReflectiveFunctionUsage; + } + + @Override + public @Nullable Object flag() { + return flag; + } + + @Override + public void flag(final @Nullable Object flag) { + this.flag = flag; + } + + @Override + public T entity() { + return entity; + } + + @Override + public @NotNull Value eval(final @NotNull Expression expression) { + return expression.visit(this); + } + + public @NotNull ExpressionInterpreter createChild(final @Nullable R entity) { + return new ExpressionInterpreter<>(entity, this.scope); + } + + public @NotNull ExpressionInterpreter createChild() { + // Note that it will have its own returnValue, but same bindings + // (Should we create new bindings?) + return new ExpressionInterpreter<>(this.entity, this.scope); + } + + public @NotNull Scope bindings() { + return scope; + } + + public @Nullable Value popReturnValue() { + final Value val = this.returnValue; + this.returnValue = null; + return val; + } + + @Override + public @NotNull Value visitArrayAccess(final @NotNull ArrayAccessExpression expression) { + final Value array = expression.array().visit(this); + final Value index = expression.index().visit(this); + if (!(array instanceof ArrayValue)) { + return Value.nil(); + } else { + final Value[] values = ((ArrayValue) array).values(); + final int validIndex = Math.max(0, (int) index.getAsNumber()) % values.length; + return values[validIndex]; + } + } + + @Override + public @NotNull Value visitAccess(final @NotNull AccessExpression expression) { + final Value objectValue = expression.object().visit(this); + if (objectValue instanceof ObjectValue) { + return ((ObjectValue) objectValue).get(expression.property()); + } + return NumberValue.zero(); + } + + @Override + public @NotNull Value visitCall(final @NotNull CallExpression expression) { + final List argumentsExpressions = expression.arguments(); + final Function.Argument[] arguments = new Function.Argument[argumentsExpressions.size()]; + for (int i = 0; i < argumentsExpressions.size(); i++) { + arguments[i] = new FunctionArgumentImpl(argumentsExpressions.get(i)); + } + final Function.Arguments args = new FunctionArguments(arguments); + + final Expression functionExpr = expression.function(); + if (functionExpr instanceof IdentifierExpression) { + final String identifierName = ((IdentifierExpression) functionExpr).name(); + if ("loop".equals(identifierName)) { + // loop built-in function + // Parameters: + // - float: How many times should we loop + // - CallableBinding: The looped expressions + int n = Math.round(args.next().eval().getAsNumber()); + Value expr = args.next().eval(); + + if (expr instanceof Function) { + final Function callable = (Function) expr; + for (int i = 0; i < n; i++) { + final ExpressionInterpreter evaluatorThisCall = createChild(); + callable.evaluate(evaluatorThisCall); + if (evaluatorThisCall.flag() == StatementExpression.Op.BREAK) { + break; + } + // (not necessary, callable already exits when returnValue + // is set to any non-null value) + // if (value == StatementExpression.Op.CONTINUE) continue; + } + } + return NumberValue.zero(); + } else if ("for_each".equals(identifierName)) { + // for each built-in function + // Parameters: + // - any: Variable + // - array: Any array + // - CallableBinding: The looped expressions + final Expression variableExpr = args.next().expression(); + if (!(variableExpr instanceof AccessExpression)) { + // first argument must be an access expression, + // e.g. 'variable.test', 'v.pig', 't.entity' or + // 't.entity.location.world' + return NumberValue.zero(); + } + final AccessExpression variableAccess = (AccessExpression) variableExpr; + final Expression objectExpr = variableAccess.object(); + final String propertyName = variableAccess.property(); + + final Value array = args.next().eval(); + final Iterable arrayIterable; + if (array instanceof ArrayValue) { + arrayIterable = Arrays.asList(((ArrayValue) array).values()); + } else { + // second argument must be an array or iterable + return NumberValue.zero(); + } + + final Value expr = args.next().eval(); + + if (expr instanceof Function) { + final Function callable = (Function) expr; + for (final Value val : arrayIterable) { + // set 'val' as current value + // eval (objectExpr.propertyName = val) + final Value evaluatedObjectValue = this.eval(objectExpr); + if (evaluatedObjectValue instanceof MutableObjectBinding) { + ((MutableObjectBinding) evaluatedObjectValue).set(propertyName, val); + } + final Object returnValue = callable.evaluate(this); + + if (returnValue == StatementExpression.Op.BREAK) { + break; + } + } + } + return NumberValue.zero(); + } + } + + final Value function = functionExpr.visit(this); + if (!(function instanceof Function)) { + return Value.nil(); + } + + if (warnOnReflectiveFunctionUsage && function instanceof JavaFunction) { + final JavaFunction javaFunction = (JavaFunction) function; + System.err.println("Warning: Reflective function usage detected for method: " + javaFunction.method()); + } + + return ((Function) function).evaluate(this, args); + } + + @Override + public @NotNull Value visitFloat(final @NotNull FloatExpression expression) { + return NumberValue.of(expression.value()); + } + + @Override + public @NotNull Value visitExecutionScope(final @NotNull ExecutionScopeExpression executionScope) { + List expressions = executionScope.expressions(); + return (Function) (context, arguments) -> { + for (Expression expression : expressions) { + // eval expression, ignore result + context.eval(expression); + + // check for return values + if (context.flag() != null) { + break; + } + } + return NumberValue.zero(); + }; + } + + @Override + public @NotNull Value visitIdentifier(final @NotNull IdentifierExpression expression) { + return scope.get(expression.name()); + } + + @Override + public @NotNull Value visitBinary(@NotNull BinaryExpression expression) { + return BINARY_EVALUATORS.get(expression.op().ordinal()).eval( + this, + expression.left(), + expression.right() + ); + } + + @Override + public @NotNull Value visitUnary(final @NotNull UnaryExpression expression) { + final Value value = expression.expression().visit(this); + switch (expression.op()) { + case LOGICAL_NEGATION: + return Value.of(!value.getAsBoolean()); + case ARITHMETICAL_NEGATION: + return NumberValue.of(-value.getAsNumber()); + case RETURN: { + this.returnValue = value; + return NumberValue.zero(); + } + default: + throw new IllegalStateException("Unknown operation"); + } + } + + @Override + public @NotNull Value visitStatement(final @NotNull StatementExpression expression) { + switch (expression.op()) { + case BREAK: { + this.flag = StatementExpression.Op.BREAK; + break; + } + case CONTINUE: { + this.flag = StatementExpression.Op.CONTINUE; + break; + } + } + return NumberValue.zero(); + } + + @Override + public @NotNull Value visitString(final @NotNull StringExpression expression) { + return StringValue.of(expression.value()); + } + + @Override + public @NotNull Value visitTernaryConditional(@NotNull TernaryConditionalExpression expression) { + final Value conditionResult = expression.condition().visit(this); + return conditionResult.getAsBoolean() + ? expression.trueExpression().visit(this) + : expression.falseExpression().visit(this); + } + + @Override + public Value visit(final @NotNull Expression expression) { + throw new UnsupportedOperationException("Unsupported expression type: " + expression); + } + + private interface Evaluator { + @NotNull Value eval(ExpressionInterpreter evaluator, Expression a, Expression b); + } + + private interface BooleanOperator { + boolean operate(LazyEvaluableBoolean a, LazyEvaluableBoolean b); + } + + interface LazyEvaluableBoolean { + boolean eval(); + } + + interface LazyEvaluableFloat { + float eval(); + } + + private interface Comparator { + boolean compare(LazyEvaluableFloat a, LazyEvaluableFloat b); + + } + + private interface ArithmeticOperator { + float operate(LazyEvaluableFloat a, LazyEvaluableFloat b); + } + + public static class FunctionArguments implements Function.Arguments { + public static final Function.Arguments EMPTY = new FunctionArguments(new Function.Argument[0]); + + private final Function.Argument[] arguments; + private int next; + + FunctionArguments(final @NotNull Function.Argument @NotNull [] arguments) { + this.arguments = requireNonNull(arguments, "arguments"); + } + + @Override + public Function.@NotNull Argument next() { + if (next < arguments.length) { + return arguments[next++]; + } else { + return EmptyFunctionArgument.EMPTY; + } + } + + @Override + public int length() { + return arguments.length; + } + } + + private static class EmptyFunctionArgument implements Function.Argument { + static final Function.Argument EMPTY = new EmptyFunctionArgument(); + + @Override + public @Nullable Expression expression() { + return null; + } + + @Override + public @Nullable Value eval() { + return NumberValue.zero(); + } + } + + private class FunctionArgumentImpl implements Function.Argument { + private final Expression expression; + + FunctionArgumentImpl(final @NotNull Expression expression) { + this.expression = expression; + } + + @Override + public @NotNull Expression expression() { + return expression; + } + + @Override + public @Nullable Value eval() { + return expression.visit(ExpressionInterpreter.this); + } + } +} diff --git a/src/main/java/team/unnamed/mocha/runtime/IsConstantExpression.java b/runtime/src/main/java/org/redlance/mocha/runtime/IsConstantExpression.java similarity index 95% rename from src/main/java/team/unnamed/mocha/runtime/IsConstantExpression.java rename to runtime/src/main/java/org/redlance/mocha/runtime/IsConstantExpression.java index e3af7cd..4d76216 100644 --- a/src/main/java/team/unnamed/mocha/runtime/IsConstantExpression.java +++ b/runtime/src/main/java/org/redlance/mocha/runtime/IsConstantExpression.java @@ -1,35 +1,36 @@ -/* - * This file is part of mocha, licensed under the MIT license - * - * Copyright (c) 2021-2025 Unnamed Team - * - * 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. - */ -package team.unnamed.mocha.runtime; +/* + * This file is part of mocha, licensed under the MIT license + * + * Copyright (c) 2021-2025 Unnamed Team + * + * 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. + */ +package org.redlance.mocha.runtime; +import com.google.j2objc.annotations.AutoreleasePool; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import team.unnamed.mocha.parser.ast.*; -import team.unnamed.mocha.runtime.value.Function; -import team.unnamed.mocha.runtime.value.ObjectProperty; -import team.unnamed.mocha.runtime.value.ObjectValue; -import team.unnamed.mocha.runtime.value.Value; +import org.redlance.mocha.parser.ast.*; +import org.redlance.mocha.runtime.value.Function; +import org.redlance.mocha.runtime.value.ObjectProperty; +import org.redlance.mocha.runtime.value.ObjectValue; +import org.redlance.mocha.runtime.value.Value; /** * A {@link ExpressionVisitor} that determines whether an expression is @@ -48,10 +49,12 @@ private IsConstantExpression(final @Nullable Scope scope) { this.scope = scope; } + @AutoreleasePool public static boolean test(final @NotNull Expression expression) { return expression.visit(INSTANCE); } + @AutoreleasePool public static boolean test(final @NotNull Expression expression, final @NotNull Scope scope) { return expression.visit(new IsConstantExpression(scope)); } diff --git a/src/main/java/team/unnamed/mocha/runtime/JavaTypes.java b/runtime/src/main/java/org/redlance/mocha/runtime/JavaTypes.java similarity index 96% rename from src/main/java/team/unnamed/mocha/runtime/JavaTypes.java rename to runtime/src/main/java/org/redlance/mocha/runtime/JavaTypes.java index a161da7..ae90dcc 100644 --- a/src/main/java/team/unnamed/mocha/runtime/JavaTypes.java +++ b/runtime/src/main/java/org/redlance/mocha/runtime/JavaTypes.java @@ -1,32 +1,32 @@ -/* - * This file is part of mocha, licensed under the MIT license - * - * Copyright (c) 2021-2025 Unnamed Team - * - * 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. - */ -package team.unnamed.mocha.runtime; +/* + * This file is part of mocha, licensed under the MIT license + * + * Copyright (c) 2021-2025 Unnamed Team + * + * 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. + */ +package org.redlance.mocha.runtime; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import team.unnamed.mocha.runtime.value.Value; +import org.redlance.mocha.runtime.value.Value; import java.util.HashMap; import java.util.Map; diff --git a/runtime/src/main/java/org/redlance/mocha/runtime/MolangInterpreter.java b/runtime/src/main/java/org/redlance/mocha/runtime/MolangInterpreter.java new file mode 100644 index 0000000..1f001d4 --- /dev/null +++ b/runtime/src/main/java/org/redlance/mocha/runtime/MolangInterpreter.java @@ -0,0 +1,396 @@ +/* + * This file is part of mocha, licensed under the MIT license + * + * Copyright (c) 2021-2025 Unnamed Team + * + * 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. + */ +package org.redlance.mocha.runtime; + +import com.google.j2objc.annotations.AutoreleasePool; +import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.redlance.mocha.parser.MolangParser; +import org.redlance.mocha.parser.ParseException; +import org.redlance.mocha.parser.ast.Expression; +import org.redlance.mocha.parser.ast.FloatExpression; +import org.redlance.mocha.runtime.binding.Binding; +import org.redlance.mocha.runtime.binding.JavaObjectBinding; +import org.redlance.mocha.runtime.standard.MochaMath; +import org.redlance.mocha.runtime.value.MutableObjectBinding; +import org.redlance.mocha.runtime.value.NumberValue; +import org.redlance.mocha.runtime.value.ObjectValue; +import org.redlance.mocha.runtime.value.Value; + +import java.io.IOException; +import java.io.Reader; +import java.io.StringReader; +import java.io.UncheckedIOException; +import java.util.List; +import java.util.function.Consumer; +import java.util.function.Supplier; + +import static java.util.Objects.requireNonNull; + +/** + * Stateful entry point for interpretation. Holds the entity, the global + * {@link Scope} and the runtime-side configuration (parse exception handler, + * "warn on reflective function usage" flag), and exposes {@code eval(...)} / + * {@code prepareEval(...)} variants plus binding helpers. + * + *

Each {@code eval} call gets its own copy of the scope with a fresh + * {@code temp} / {@code t} binding so concurrent or nested evaluations do + * not see each other's local state.

+ * + * @since 5.0.0 + */ +public final class MolangInterpreter { + private final T entity; + private final Scope scope; + private Consumer<@NotNull ParseException> parseExceptionHandler; + private boolean warnOnReflectiveFunctionUsage; + + public MolangInterpreter(final @Nullable T entity, final @NotNull Scope scope) { + this.entity = entity; + this.scope = requireNonNull(scope, "scope"); + } + + /** + * Creates an interpreter with the given {@code entity} and an empty, + * user-built {@link Scope}. + * + * @since 5.0.0 + */ + @Contract("_, _ -> new") + public static @NotNull MolangInterpreter create(final @Nullable T entity, final @NotNull Consumer scopeBuilder) { + final Scope.Builder builder = Scope.builder(); + scopeBuilder.accept(builder); + return new MolangInterpreter<>(entity, builder.build()); + } + + @Contract("_ -> new") + public static @NotNull MolangInterpreter create(final @Nullable T entity) { + return create(entity, b -> { + }); + } + + @Contract("-> new") + public static @NotNull MolangInterpreter create() { + return create(null); + } + + /** + * Creates an interpreter pre-populated with the standard + * {@code math} / {@code variable} / {@code v} bindings. Lives in the + * runtime module so a caller that only needs interpretation does not have + * to depend on the compiler module. + * + * @since 5.0.0 + */ + @Contract("_ -> new") + public static @NotNull MolangInterpreter standard(final @Nullable T entity) { + return create(entity, builder -> { + builder.set("math", JavaObjectBinding.of(MochaMath.class, null, new MochaMath())); + final MutableObjectBinding variableBinding = new MutableObjectBinding(); + builder.set("variable", variableBinding); + builder.set("v", variableBinding); + }); + } + + @Contract("-> new") + public static @NotNull MolangInterpreter standard() { + return standard(null); + } + + public @Nullable T entity() { + return entity; + } + + /** + * Returns the bindings for this interpreter instance. + * + * @since 3.0.0 + */ + public @NotNull Scope scope() { + return scope; + } + + //#region INTERPRETER API + + /** + * Evaluates the given {@code expressions}, these expressions are already + * parsed and are interpreted as fast as possible. + * + * @param expressions The expressions to evaluate. + * @param scopeConsumer Optional callback to populate per-call bindings on + * the local scope copy before evaluation. + * @return The result of the evaluation. + * @since 4.1.0 + */ + @AutoreleasePool + public float eval(final @NotNull List expressions, final @Nullable Consumer scopeConsumer) { + if (expressions.size() == 1 && expressions.get(0) instanceof FloatExpression expression) { + return expression.value(); + } + + final Scope local = scope.copy(); + { + final MutableObjectBinding temp = new MutableObjectBinding(); + local.set("temp", temp); + local.set("t", temp); + } + if (scopeConsumer != null && !local.readOnly()) scopeConsumer.accept(local); + local.readOnly(true); + + final ExpressionInterpreter evaluator = new ExpressionInterpreter<>(entity, local); + evaluator.warnOnReflectiveFunctionUsage(warnOnReflectiveFunctionUsage); + Value lastResult = NumberValue.zero(); + + for (final Expression expression : expressions) { + lastResult = expression.visit(evaluator); + final Value returnValue = evaluator.popReturnValue(); + if (returnValue != null) { + lastResult = returnValue; + break; + } + } + + return lastResult == null ? 0F : lastResult.getAsNumber(); + } + + /** + * @see #eval(List, Consumer) + * @since 3.0.0 + */ + public float eval(final @NotNull List expressions) { + return eval(expressions, null); + } + + /** + * Parses and evaluates the given Molang source. + * + *

Note that this method does not cache parsed expressions. If you want + * to re-use parsed expressions, parse them yourself with + * {@link MolangParser} and use {@link #eval(List, Consumer)}.

+ * + *

Parse errors are routed through the handler set by + * {@link #handleParseExceptions(Consumer)} and the call returns {@code 0}.

+ * + * @since 4.1.0 + */ + public float eval(final @NotNull Reader source, final @Nullable Consumer scopeConsumer) { + final List parsed; + try { + parsed = MolangParser.parseAll(source); + } catch (final ParseException e) { + if (parseExceptionHandler != null) parseExceptionHandler.accept(e); + return 0F; + } catch (final IOException e) { + throw new UncheckedIOException("Failed to read from given reader", e); + } + return eval(parsed, scopeConsumer); + } + + /** + * @see #eval(Reader, Consumer) + * @since 3.0.0 + */ + public float eval(final @NotNull Reader source) { + return eval(source, null); + } + + /** + * Parses and evaluates the given Molang source string. + * + * @see #eval(Reader, Consumer) + * @since 4.1.0 + */ + public float eval(final @NotNull String source, final @Nullable Consumer scopeConsumer) { + requireNonNull(source, "source"); + try (final StringReader reader = new StringReader(source)) { + return eval(reader, scopeConsumer); + } + } + + /** + * @see #eval(String, Consumer) + * @since 3.0.0 + */ + public float eval(final @NotNull String source) { + return eval(source, null); + } + + /** + * Parses {@code reader} once and returns a {@link Supplier} that runs the + * cached AST through the interpreter on each call. Parse errors go through + * {@link #handleParseExceptions(Consumer)}; a failed parse yields a + * supplier that always produces {@code 0}. + * + * @since 4.1.0 + */ + public @NotNull Supplier<@NotNull Float> prepareEval(final @NotNull Reader reader, final @Nullable Consumer scopeConsumer) { + final List parsed; + try { + parsed = MolangParser.parseAll(reader); + } catch (final ParseException e) { + if (parseExceptionHandler != null) parseExceptionHandler.accept(e); + return () -> 0F; + } catch (final IOException e) { + throw new UncheckedIOException("Failed to read from given reader", e); + } + return () -> eval(parsed, scopeConsumer); + } + + /** + * @see #prepareEval(Reader, Consumer) + * @since 3.0.0 + */ + public @NotNull Supplier<@NotNull Float> prepareEval(final @NotNull Reader reader) { + return prepareEval(reader, null); + } + + /** + * @see #prepareEval(Reader, Consumer) + * @since 4.1.0 + */ + public @NotNull Supplier<@NotNull Float> prepareEval(final @NotNull String code, final @Nullable Consumer scopeConsumer) { + requireNonNull(code, "code"); + try (final StringReader reader = new StringReader(code)) { + return prepareEval(reader, scopeConsumer); + } + } + + /** + * @see #prepareEval(String, Consumer) + * @since 3.0.0 + */ + public @NotNull Supplier<@NotNull Float> prepareEval(final @NotNull String code) { + return prepareEval(code, null); + } + + //#endregion + + //#region BINDING API + + /** + * Binds the given {@code clazz}'s static fields and methods into this + * interpreter's {@link Scope}. + * + *

Fields and methods are bound in the following format:

+ *
+     *     namespace.field
+     *     namespace.method()
+     *     namespace.method(arg1, arg2)
+     * 
+ * + *

Where {@code namespace} comes from the class' {@link Binding} + * annotation, and field/method names from {@link Binding} annotations on + * the members.

+ * + * @see Binding + * @since 3.0.0 + */ + public void bind(final @NotNull Class clazz) { + final JavaObjectBinding javaObjectBinding = JavaObjectBinding.of(clazz, null, null); + for (final String name : javaObjectBinding.names()) { + scope.set(name, javaObjectBinding); + } + } + + /** + * Binds the given {@code instance}'s non-static fields and methods. + * + *

Fields and methods are bound in the format:

+ *
+     *     name.field
+     *     name.method()
+     *     name.method(arg1, arg2)
+     * 
+ * + *

Where {@code name} comes from the {@code name} parameter, and field + * /method names from {@link Binding} annotations.

+ * + * @param clazz The instance's class (or interface) to use. + * @param instance The instance to bind. + * @param name The name to bind the instance to. + * @param aliases Additional names to bind the instance to. + * @param The instance's type. + * @since 3.0.0 + */ + public void bindInstance(final @NotNull Class clazz, final @NotNull B instance, final @NotNull String name, final @NotNull String @NotNull ... aliases) { + final JavaObjectBinding javaObjectBinding = JavaObjectBinding.of(clazz, instance, null); + scope.set(name, javaObjectBinding); + for (final String alias : aliases) { + scope.set(alias, javaObjectBinding); + } + } + + //#endregion + + //#region CONFIGURATION API + + public boolean warnOnReflectiveFunctionUsage() { + return warnOnReflectiveFunctionUsage; + } + + /** + * Sets the boolean value for the "warn on reflective function usage" + * option. + * + *

When set to true, {@link #eval} may log a warning when evaluating + * code that includes a call to a function that was registered using only + * annotations and therefore has to be invoked via Reflection, taking some + * extra time.

+ * + *

Note that this behavior can be avoided by setting an + * {@link ObjectValue} when binding static or non-static methods and fields.

+ * + *

By default this is false.

+ * + * @return This interpreter instance. + * @since 3.0.0 + */ + @Contract("_ -> this") + public @NotNull MolangInterpreter warnOnReflectiveFunctionUsage(final boolean warnOnReflectiveFunctionUsage) { + this.warnOnReflectiveFunctionUsage = warnOnReflectiveFunctionUsage; + return this; + } + + /** + * Sets the {@link ParseException} handler. This handler will be called + * whenever an internal call to {@link MolangParser} from + * {@link #eval(Reader, Consumer)} or {@link #prepareEval(Reader, Consumer)} + * fails. + * + *

Usually useful for logging/debugging purposes.

+ * + *

By default this is null.

+ * + * @return This interpreter instance. + * @since 3.0.0 + */ + @Contract("_ -> this") + public @NotNull MolangInterpreter handleParseExceptions(final @Nullable Consumer<@NotNull ParseException> exceptionHandler) { + this.parseExceptionHandler = exceptionHandler; + return this; + } + + //#endregion +} diff --git a/src/main/java/team/unnamed/mocha/runtime/Scope.java b/runtime/src/main/java/org/redlance/mocha/runtime/Scope.java similarity index 92% rename from src/main/java/team/unnamed/mocha/runtime/Scope.java rename to runtime/src/main/java/org/redlance/mocha/runtime/Scope.java index 2b7688c..3020c79 100644 --- a/src/main/java/team/unnamed/mocha/runtime/Scope.java +++ b/runtime/src/main/java/org/redlance/mocha/runtime/Scope.java @@ -1,31 +1,31 @@ -/* - * This file is part of mocha, licensed under the MIT license - * - * Copyright (c) 2021-2025 Unnamed Team - * - * 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. - */ -package team.unnamed.mocha.runtime; +/* + * This file is part of mocha, licensed under the MIT license + * + * Copyright (c) 2021-2025 Unnamed Team + * + * 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. + */ +package org.redlance.mocha.runtime; import org.jetbrains.annotations.NotNull; -import team.unnamed.mocha.runtime.value.ObjectValue; -import team.unnamed.mocha.runtime.value.Value; +import org.redlance.mocha.runtime.value.ObjectValue; +import org.redlance.mocha.runtime.value.Value; /** * Represents a scope, which is just a virtual object that diff --git a/src/main/java/team/unnamed/mocha/runtime/ScopeImpl.java b/runtime/src/main/java/org/redlance/mocha/runtime/ScopeImpl.java similarity index 92% rename from src/main/java/team/unnamed/mocha/runtime/ScopeImpl.java rename to runtime/src/main/java/org/redlance/mocha/runtime/ScopeImpl.java index ae8ab8e..206b43d 100644 --- a/src/main/java/team/unnamed/mocha/runtime/ScopeImpl.java +++ b/runtime/src/main/java/org/redlance/mocha/runtime/ScopeImpl.java @@ -1,33 +1,33 @@ -/* - * This file is part of mocha, licensed under the MIT license - * - * Copyright (c) 2021-2025 Unnamed Team - * - * 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. - */ -package team.unnamed.mocha.runtime; +/* + * This file is part of mocha, licensed under the MIT license + * + * Copyright (c) 2021-2025 Unnamed Team + * + * 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. + */ +package org.redlance.mocha.runtime; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import team.unnamed.mocha.runtime.value.ObjectProperty; -import team.unnamed.mocha.runtime.value.Value; -import team.unnamed.mocha.util.CaseInsensitiveStringHashMap; +import org.redlance.mocha.runtime.value.ObjectProperty; +import org.redlance.mocha.runtime.value.Value; +import org.redlance.mocha.runtime.util.CaseInsensitiveStringHashMap; import java.util.Map; diff --git a/src/main/java/team/unnamed/mocha/runtime/TypeCastException.java b/runtime/src/main/java/org/redlance/mocha/runtime/TypeCastException.java similarity index 96% rename from src/main/java/team/unnamed/mocha/runtime/TypeCastException.java rename to runtime/src/main/java/org/redlance/mocha/runtime/TypeCastException.java index 1b0815d..5edbc9e 100644 --- a/src/main/java/team/unnamed/mocha/runtime/TypeCastException.java +++ b/runtime/src/main/java/org/redlance/mocha/runtime/TypeCastException.java @@ -1,27 +1,27 @@ -/* - * This file is part of mocha, licensed under the MIT license - * - * Copyright (c) 2021-2025 Unnamed Team - * - * 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. - */ -package team.unnamed.mocha.runtime; +/* + * This file is part of mocha, licensed under the MIT license + * + * Copyright (c) 2021-2025 Unnamed Team + * + * 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. + */ +package org.redlance.mocha.runtime; import java.io.Serial; diff --git a/src/main/java/team/unnamed/mocha/runtime/binding/BindExternalFunction.java b/runtime/src/main/java/org/redlance/mocha/runtime/binding/BindExternalFunction.java similarity index 97% rename from src/main/java/team/unnamed/mocha/runtime/binding/BindExternalFunction.java rename to runtime/src/main/java/org/redlance/mocha/runtime/binding/BindExternalFunction.java index 40e5ba8..612ad18 100644 --- a/src/main/java/team/unnamed/mocha/runtime/binding/BindExternalFunction.java +++ b/runtime/src/main/java/org/redlance/mocha/runtime/binding/BindExternalFunction.java @@ -1,27 +1,27 @@ -/* - * This file is part of mocha, licensed under the MIT license - * - * Copyright (c) 2021-2025 Unnamed Team - * - * 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. - */ -package team.unnamed.mocha.runtime.binding; +/* + * This file is part of mocha, licensed under the MIT license + * + * Copyright (c) 2021-2025 Unnamed Team + * + * 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. + */ +package org.redlance.mocha.runtime.binding; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; diff --git a/src/main/java/team/unnamed/mocha/runtime/binding/Binding.java b/runtime/src/main/java/org/redlance/mocha/runtime/binding/Binding.java similarity index 98% rename from src/main/java/team/unnamed/mocha/runtime/binding/Binding.java rename to runtime/src/main/java/org/redlance/mocha/runtime/binding/Binding.java index 95e26ed..dd30267 100644 --- a/src/main/java/team/unnamed/mocha/runtime/binding/Binding.java +++ b/runtime/src/main/java/org/redlance/mocha/runtime/binding/Binding.java @@ -1,27 +1,27 @@ -/* - * This file is part of mocha, licensed under the MIT license - * - * Copyright (c) 2021-2025 Unnamed Team - * - * 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. - */ -package team.unnamed.mocha.runtime.binding; +/* + * This file is part of mocha, licensed under the MIT license + * + * Copyright (c) 2021-2025 Unnamed Team + * + * 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. + */ +package org.redlance.mocha.runtime.binding; import org.jetbrains.annotations.NotNull; diff --git a/src/main/java/team/unnamed/mocha/runtime/binding/Entity.java b/runtime/src/main/java/org/redlance/mocha/runtime/binding/Entity.java similarity index 95% rename from src/main/java/team/unnamed/mocha/runtime/binding/Entity.java rename to runtime/src/main/java/org/redlance/mocha/runtime/binding/Entity.java index 194fb60..c085f61 100644 --- a/src/main/java/team/unnamed/mocha/runtime/binding/Entity.java +++ b/runtime/src/main/java/org/redlance/mocha/runtime/binding/Entity.java @@ -1,27 +1,27 @@ -/* - * This file is part of mocha, licensed under the MIT license - * - * Copyright (c) 2021-2025 Unnamed Team - * - * 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. - */ -package team.unnamed.mocha.runtime.binding; +/* + * This file is part of mocha, licensed under the MIT license + * + * Copyright (c) 2021-2025 Unnamed Team + * + * 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. + */ +package org.redlance.mocha.runtime.binding; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; diff --git a/src/main/java/team/unnamed/mocha/runtime/binding/JavaFieldBinding.java b/runtime/src/main/java/org/redlance/mocha/runtime/binding/JavaFieldBinding.java similarity index 97% rename from src/main/java/team/unnamed/mocha/runtime/binding/JavaFieldBinding.java rename to runtime/src/main/java/org/redlance/mocha/runtime/binding/JavaFieldBinding.java index 1b8ee58..6218be0 100644 --- a/src/main/java/team/unnamed/mocha/runtime/binding/JavaFieldBinding.java +++ b/runtime/src/main/java/org/redlance/mocha/runtime/binding/JavaFieldBinding.java @@ -1,32 +1,32 @@ -/* - * This file is part of mocha, licensed under the MIT license - * - * Copyright (c) 2021-2025 Unnamed Team - * - * 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. - */ -package team.unnamed.mocha.runtime.binding; +/* + * This file is part of mocha, licensed under the MIT license + * + * Copyright (c) 2021-2025 Unnamed Team + * + * 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. + */ +package org.redlance.mocha.runtime.binding; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import team.unnamed.mocha.runtime.value.Value; +import org.redlance.mocha.runtime.value.Value; import java.lang.reflect.Field; import java.lang.reflect.Modifier; diff --git a/src/main/java/team/unnamed/mocha/runtime/binding/JavaFunction.java b/runtime/src/main/java/org/redlance/mocha/runtime/binding/JavaFunction.java similarity index 92% rename from src/main/java/team/unnamed/mocha/runtime/binding/JavaFunction.java rename to runtime/src/main/java/org/redlance/mocha/runtime/binding/JavaFunction.java index 26297e8..8abe37f 100644 --- a/src/main/java/team/unnamed/mocha/runtime/binding/JavaFunction.java +++ b/runtime/src/main/java/org/redlance/mocha/runtime/binding/JavaFunction.java @@ -1,34 +1,34 @@ -/* - * This file is part of mocha, licensed under the MIT license - * - * Copyright (c) 2021-2025 Unnamed Team - * - * 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. - */ -package team.unnamed.mocha.runtime.binding; +/* + * This file is part of mocha, licensed under the MIT license + * + * Copyright (c) 2021-2025 Unnamed Team + * + * 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. + */ +package org.redlance.mocha.runtime.binding; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import team.unnamed.mocha.runtime.ExecutionContext; -import team.unnamed.mocha.runtime.value.Function; -import team.unnamed.mocha.runtime.value.Value; +import org.redlance.mocha.runtime.ExecutionContext; +import org.redlance.mocha.runtime.value.Function; +import org.redlance.mocha.runtime.value.Value; import java.lang.reflect.Method; diff --git a/src/main/java/team/unnamed/mocha/runtime/binding/JavaObjectBinding.java b/runtime/src/main/java/org/redlance/mocha/runtime/binding/JavaObjectBinding.java similarity index 96% rename from src/main/java/team/unnamed/mocha/runtime/binding/JavaObjectBinding.java rename to runtime/src/main/java/org/redlance/mocha/runtime/binding/JavaObjectBinding.java index dbacfcb..b3cc0a7 100644 --- a/src/main/java/team/unnamed/mocha/runtime/binding/JavaObjectBinding.java +++ b/runtime/src/main/java/org/redlance/mocha/runtime/binding/JavaObjectBinding.java @@ -1,36 +1,36 @@ -/* - * This file is part of mocha, licensed under the MIT license - * - * Copyright (c) 2021-2025 Unnamed Team - * - * 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. - */ -package team.unnamed.mocha.runtime.binding; +/* + * This file is part of mocha, licensed under the MIT license + * + * Copyright (c) 2021-2025 Unnamed Team + * + * 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. + */ +package org.redlance.mocha.runtime.binding; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import team.unnamed.mocha.runtime.value.Function; -import team.unnamed.mocha.runtime.value.ObjectProperty; -import team.unnamed.mocha.runtime.value.ObjectValue; -import team.unnamed.mocha.runtime.value.Value; -import team.unnamed.mocha.util.CaseInsensitiveStringHashMap; +import org.redlance.mocha.runtime.value.Function; +import org.redlance.mocha.runtime.value.ObjectProperty; +import org.redlance.mocha.runtime.value.ObjectValue; +import org.redlance.mocha.runtime.value.Value; +import org.redlance.mocha.runtime.util.CaseInsensitiveStringHashMap; import java.lang.reflect.Field; import java.lang.reflect.Method; diff --git a/src/main/java/team/unnamed/mocha/runtime/binding/Lazy.java b/runtime/src/main/java/org/redlance/mocha/runtime/binding/Lazy.java similarity index 94% rename from src/main/java/team/unnamed/mocha/runtime/binding/Lazy.java rename to runtime/src/main/java/org/redlance/mocha/runtime/binding/Lazy.java index fa8ec4e..d8cf8ff 100644 --- a/src/main/java/team/unnamed/mocha/runtime/binding/Lazy.java +++ b/runtime/src/main/java/org/redlance/mocha/runtime/binding/Lazy.java @@ -1,27 +1,27 @@ -/* - * This file is part of mocha, licensed under the MIT license - * - * Copyright (c) 2021-2025 Unnamed Team - * - * 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. - */ -package team.unnamed.mocha.runtime.binding; +/* + * This file is part of mocha, licensed under the MIT license + * + * Copyright (c) 2021-2025 Unnamed Team + * + * 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. + */ +package org.redlance.mocha.runtime.binding; public interface Lazy { T get(); diff --git a/src/main/java/team/unnamed/mocha/runtime/binding/ReflectiveFunction.java b/runtime/src/main/java/org/redlance/mocha/runtime/binding/ReflectiveFunction.java similarity index 93% rename from src/main/java/team/unnamed/mocha/runtime/binding/ReflectiveFunction.java rename to runtime/src/main/java/org/redlance/mocha/runtime/binding/ReflectiveFunction.java index 4cc5fba..1d8cbe7 100644 --- a/src/main/java/team/unnamed/mocha/runtime/binding/ReflectiveFunction.java +++ b/runtime/src/main/java/org/redlance/mocha/runtime/binding/ReflectiveFunction.java @@ -1,38 +1,38 @@ -/* - * This file is part of mocha, licensed under the MIT license - * - * Copyright (c) 2021-2025 Unnamed Team - * - * 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. - */ -package team.unnamed.mocha.runtime.binding; +/* + * This file is part of mocha, licensed under the MIT license + * + * Copyright (c) 2021-2025 Unnamed Team + * + * 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. + */ +package org.redlance.mocha.runtime.binding; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import team.unnamed.mocha.runtime.ExecutionContext; -import team.unnamed.mocha.runtime.JavaTypes; -import team.unnamed.mocha.runtime.value.ArrayValue; -import team.unnamed.mocha.runtime.value.Function; -import team.unnamed.mocha.runtime.value.JavaValue; -import team.unnamed.mocha.runtime.value.NumberValue; -import team.unnamed.mocha.runtime.value.StringValue; -import team.unnamed.mocha.runtime.value.Value; +import org.redlance.mocha.runtime.ExecutionContext; +import org.redlance.mocha.runtime.JavaTypes; +import org.redlance.mocha.runtime.value.ArrayValue; +import org.redlance.mocha.runtime.value.Function; +import org.redlance.mocha.runtime.value.JavaValue; +import org.redlance.mocha.runtime.value.NumberValue; +import org.redlance.mocha.runtime.value.StringValue; +import org.redlance.mocha.runtime.value.Value; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; diff --git a/src/main/java/team/unnamed/mocha/runtime/binding/RegisteredBinding.java b/runtime/src/main/java/org/redlance/mocha/runtime/binding/RegisteredBinding.java similarity index 96% rename from src/main/java/team/unnamed/mocha/runtime/binding/RegisteredBinding.java rename to runtime/src/main/java/org/redlance/mocha/runtime/binding/RegisteredBinding.java index 0c09615..5f8ed00 100644 --- a/src/main/java/team/unnamed/mocha/runtime/binding/RegisteredBinding.java +++ b/runtime/src/main/java/org/redlance/mocha/runtime/binding/RegisteredBinding.java @@ -1,27 +1,27 @@ -/* - * This file is part of mocha, licensed under the MIT license - * - * Copyright (c) 2021-2025 Unnamed Team - * - * 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. - */ -package team.unnamed.mocha.runtime.binding; +/* + * This file is part of mocha, licensed under the MIT license + * + * Copyright (c) 2021-2025 Unnamed Team + * + * 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. + */ +package org.redlance.mocha.runtime.binding; /** * A registered binding. This is either a field or a method. diff --git a/runtime/src/main/java/org/redlance/mocha/runtime/binding/package-info.java b/runtime/src/main/java/org/redlance/mocha/runtime/binding/package-info.java new file mode 100644 index 0000000..cd195f3 --- /dev/null +++ b/runtime/src/main/java/org/redlance/mocha/runtime/binding/package-info.java @@ -0,0 +1,4 @@ +@ReflectionSupport(ReflectionSupport.Level.FULL) +package org.redlance.mocha.runtime.binding; + +import com.google.j2objc.annotations.ReflectionSupport; \ No newline at end of file diff --git a/runtime/src/main/java/org/redlance/mocha/runtime/package-info.java b/runtime/src/main/java/org/redlance/mocha/runtime/package-info.java new file mode 100644 index 0000000..a7c256a --- /dev/null +++ b/runtime/src/main/java/org/redlance/mocha/runtime/package-info.java @@ -0,0 +1,4 @@ +@ReflectionSupport(ReflectionSupport.Level.NATIVE_ONLY) +package org.redlance.mocha.runtime; + +import com.google.j2objc.annotations.ReflectionSupport; \ No newline at end of file diff --git a/src/main/java/team/unnamed/mocha/runtime/standard/MochaMath.java b/runtime/src/main/java/org/redlance/mocha/runtime/standard/MochaMath.java similarity index 96% rename from src/main/java/team/unnamed/mocha/runtime/standard/MochaMath.java rename to runtime/src/main/java/org/redlance/mocha/runtime/standard/MochaMath.java index e5a5989..ad4c2cb 100644 --- a/src/main/java/team/unnamed/mocha/runtime/standard/MochaMath.java +++ b/runtime/src/main/java/org/redlance/mocha/runtime/standard/MochaMath.java @@ -21,16 +21,16 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -package team.unnamed.mocha.runtime.standard; +package org.redlance.mocha.runtime.standard; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import team.unnamed.mocha.runtime.binding.BindExternalFunction; -import team.unnamed.mocha.runtime.binding.Binding; -import team.unnamed.mocha.runtime.value.NumberValue; -import team.unnamed.mocha.runtime.value.ObjectProperty; -import team.unnamed.mocha.runtime.value.ObjectValue; -import team.unnamed.mocha.util.CaseInsensitiveStringHashMap; +import org.redlance.mocha.runtime.binding.BindExternalFunction; +import org.redlance.mocha.runtime.binding.Binding; +import org.redlance.mocha.runtime.value.NumberValue; +import org.redlance.mocha.runtime.value.ObjectProperty; +import org.redlance.mocha.runtime.value.ObjectValue; +import org.redlance.mocha.runtime.util.CaseInsensitiveStringHashMap; import java.util.Map; import java.util.Random; diff --git a/runtime/src/main/java/org/redlance/mocha/runtime/standard/package-info.java b/runtime/src/main/java/org/redlance/mocha/runtime/standard/package-info.java new file mode 100644 index 0000000..f8bcba3 --- /dev/null +++ b/runtime/src/main/java/org/redlance/mocha/runtime/standard/package-info.java @@ -0,0 +1,4 @@ +@ReflectionSupport(ReflectionSupport.Level.FULL) +package org.redlance.mocha.runtime.standard; + +import com.google.j2objc.annotations.ReflectionSupport; \ No newline at end of file diff --git a/src/main/java/team/unnamed/mocha/util/CaseInsensitiveStringHashMap.java b/runtime/src/main/java/org/redlance/mocha/runtime/util/CaseInsensitiveStringHashMap.java similarity index 98% rename from src/main/java/team/unnamed/mocha/util/CaseInsensitiveStringHashMap.java rename to runtime/src/main/java/org/redlance/mocha/runtime/util/CaseInsensitiveStringHashMap.java index b85f7a4..e972c86 100644 --- a/src/main/java/team/unnamed/mocha/util/CaseInsensitiveStringHashMap.java +++ b/runtime/src/main/java/org/redlance/mocha/runtime/util/CaseInsensitiveStringHashMap.java @@ -1,27 +1,27 @@ -/* - * This file is part of mocha, licensed under the MIT license - * - * Copyright (c) 2021-2025 Unnamed Team - * - * 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. - */ -package team.unnamed.mocha.util; +/* + * This file is part of mocha, licensed under the MIT license + * + * Copyright (c) 2021-2025 Unnamed Team + * + * 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. + */ +package org.redlance.mocha.runtime.util; import org.jetbrains.annotations.NotNull; @@ -73,6 +73,7 @@ private static T lowercase(T key) { } private static Map lowercaseMap(Map m) { + if (m instanceof CaseInsensitiveStringHashMap) return m; final Map lowercased = new HashMap<>(); for (Entry entry : m.entrySet()) { lowercased.put(lowercase(entry.getKey()), entry.getValue()); @@ -97,6 +98,7 @@ public V put(String key, V value) { @Override public void putAll(Map m) { + if (m == this) return; super.putAll(lowercaseMap(m)); } diff --git a/runtime/src/main/java/org/redlance/mocha/runtime/util/package-info.java b/runtime/src/main/java/org/redlance/mocha/runtime/util/package-info.java new file mode 100644 index 0000000..4c32a2a --- /dev/null +++ b/runtime/src/main/java/org/redlance/mocha/runtime/util/package-info.java @@ -0,0 +1,4 @@ +@ReflectionSupport(ReflectionSupport.Level.NATIVE_ONLY) +package org.redlance.mocha.runtime.util; + +import com.google.j2objc.annotations.ReflectionSupport; \ No newline at end of file diff --git a/src/main/java/team/unnamed/mocha/runtime/value/ArrayValue.java b/runtime/src/main/java/org/redlance/mocha/runtime/value/ArrayValue.java similarity index 97% rename from src/main/java/team/unnamed/mocha/runtime/value/ArrayValue.java rename to runtime/src/main/java/org/redlance/mocha/runtime/value/ArrayValue.java index c850792..f041976 100644 --- a/src/main/java/team/unnamed/mocha/runtime/value/ArrayValue.java +++ b/runtime/src/main/java/org/redlance/mocha/runtime/value/ArrayValue.java @@ -1,27 +1,27 @@ -/* - * This file is part of mocha, licensed under the MIT license - * - * Copyright (c) 2021-2025 Unnamed Team - * - * 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. - */ -package team.unnamed.mocha.runtime.value; +/* + * This file is part of mocha, licensed under the MIT license + * + * Copyright (c) 2021-2025 Unnamed Team + * + * 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. + */ +package org.redlance.mocha.runtime.value; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; diff --git a/src/main/java/team/unnamed/mocha/runtime/value/Function.java b/runtime/src/main/java/org/redlance/mocha/runtime/value/Function.java similarity index 95% rename from src/main/java/team/unnamed/mocha/runtime/value/Function.java rename to runtime/src/main/java/org/redlance/mocha/runtime/value/Function.java index 17fbfd9..756c31d 100644 --- a/src/main/java/team/unnamed/mocha/runtime/value/Function.java +++ b/runtime/src/main/java/org/redlance/mocha/runtime/value/Function.java @@ -1,33 +1,33 @@ -/* - * This file is part of mocha, licensed under the MIT license - * - * Copyright (c) 2021-2025 Unnamed Team - * - * 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. - */ -package team.unnamed.mocha.runtime.value; +/* + * This file is part of mocha, licensed under the MIT license + * + * Copyright (c) 2021-2025 Unnamed Team + * + * 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. + */ +package org.redlance.mocha.runtime.value; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import team.unnamed.mocha.parser.ast.Expression; -import team.unnamed.mocha.runtime.ExecutionContext; -import team.unnamed.mocha.runtime.ExpressionInterpreter; +import org.redlance.mocha.parser.ast.Expression; +import org.redlance.mocha.runtime.ExecutionContext; +import org.redlance.mocha.runtime.ExpressionInterpreter; /** * Represents a Molang function. Receives a certain amount of diff --git a/src/main/java/team/unnamed/mocha/runtime/value/JavaValue.java b/runtime/src/main/java/org/redlance/mocha/runtime/value/JavaValue.java similarity index 95% rename from src/main/java/team/unnamed/mocha/runtime/value/JavaValue.java rename to runtime/src/main/java/org/redlance/mocha/runtime/value/JavaValue.java index 4d98ac4..bff2c70 100644 --- a/src/main/java/team/unnamed/mocha/runtime/value/JavaValue.java +++ b/runtime/src/main/java/org/redlance/mocha/runtime/value/JavaValue.java @@ -1,27 +1,27 @@ -/* - * This file is part of mocha, licensed under the MIT license - * - * Copyright (c) 2021-2025 Unnamed Team - * - * 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. - */ -package team.unnamed.mocha.runtime.value; +/* + * This file is part of mocha, licensed under the MIT license + * + * Copyright (c) 2021-2025 Unnamed Team + * + * 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. + */ +package org.redlance.mocha.runtime.value; public final class JavaValue implements Value { private final Object value; diff --git a/src/main/java/team/unnamed/mocha/runtime/value/MutableObjectBinding.java b/runtime/src/main/java/org/redlance/mocha/runtime/value/MutableObjectBinding.java similarity index 95% rename from src/main/java/team/unnamed/mocha/runtime/value/MutableObjectBinding.java rename to runtime/src/main/java/org/redlance/mocha/runtime/value/MutableObjectBinding.java index a0e1403..d340dad 100644 --- a/src/main/java/team/unnamed/mocha/runtime/value/MutableObjectBinding.java +++ b/runtime/src/main/java/org/redlance/mocha/runtime/value/MutableObjectBinding.java @@ -1,31 +1,31 @@ -/* - * This file is part of mocha, licensed under the MIT license - * - * Copyright (c) 2021-2025 Unnamed Team - * - * 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. - */ -package team.unnamed.mocha.runtime.value; +/* + * This file is part of mocha, licensed under the MIT license + * + * Copyright (c) 2021-2025 Unnamed Team + * + * 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. + */ +package org.redlance.mocha.runtime.value; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import team.unnamed.mocha.util.CaseInsensitiveStringHashMap; +import org.redlance.mocha.runtime.util.CaseInsensitiveStringHashMap; import java.util.Map; diff --git a/src/main/java/team/unnamed/mocha/runtime/value/NumberValue.java b/runtime/src/main/java/org/redlance/mocha/runtime/value/NumberValue.java similarity index 95% rename from src/main/java/team/unnamed/mocha/runtime/value/NumberValue.java rename to runtime/src/main/java/org/redlance/mocha/runtime/value/NumberValue.java index 12c96d0..aa7b00b 100644 --- a/src/main/java/team/unnamed/mocha/runtime/value/NumberValue.java +++ b/runtime/src/main/java/org/redlance/mocha/runtime/value/NumberValue.java @@ -1,86 +1,86 @@ -/* - * This file is part of mocha, licensed under the MIT license - * - * Copyright (c) 2021-2025 Unnamed Team - * - * 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. - */ -package team.unnamed.mocha.runtime.value; - -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -public final class NumberValue implements Value { - private static final NumberValue ONE = new NumberValue(1F); - private static final NumberValue ZERO = new NumberValue(0F); - - private final float value; - - private NumberValue(final float value) { - this.value = normalize(value); - } - - public static @NotNull NumberValue of(final double value) { - return NumberValue.of((float) value); - } - - public static @NotNull NumberValue of(final float value) { - if (value == ONE.value()) return ONE; - if (value == ZERO.value()) return ZERO; - return new NumberValue(value); - } - - public static @NotNull NumberValue one() { - return ONE; - } - - public static @NotNull NumberValue zero() { - return ZERO; - } - - public static double normalize(final double value) { - return Double.isNaN(value) || Double.isInfinite(value) ? 0D : value; - } - - public static float normalize(final float value) { - return Float.isNaN(value) || Float.isInfinite(value) ? 0F : value; - } - - public float value() { - return value; - } - - @Override - public @NotNull String toString() { - return "NumberValue(" + value + ')'; - } - - @Override - public boolean equals(final @Nullable Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - final NumberValue that = (NumberValue) o; - return Float.compare(that.value, value) == 0; - } - - @Override - public int hashCode() { - return Float.hashCode(value); - } -} +/* + * This file is part of mocha, licensed under the MIT license + * + * Copyright (c) 2021-2025 Unnamed Team + * + * 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. + */ +package org.redlance.mocha.runtime.value; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public final class NumberValue implements Value { + private static final NumberValue ONE = new NumberValue(1F); + private static final NumberValue ZERO = new NumberValue(0F); + + private final float value; + + private NumberValue(final float value) { + this.value = normalize(value); + } + + public static @NotNull NumberValue of(final double value) { + return NumberValue.of((float) value); + } + + public static @NotNull NumberValue of(final float value) { + if (value == ONE.value()) return ONE; + if (value == ZERO.value()) return ZERO; + return new NumberValue(value); + } + + public static @NotNull NumberValue one() { + return ONE; + } + + public static @NotNull NumberValue zero() { + return ZERO; + } + + public static double normalize(final double value) { + return Double.isNaN(value) || Double.isInfinite(value) ? 0D : value; + } + + public static float normalize(final float value) { + return Float.isNaN(value) || Float.isInfinite(value) ? 0F : value; + } + + public float value() { + return value; + } + + @Override + public @NotNull String toString() { + return "NumberValue(" + value + ')'; + } + + @Override + public boolean equals(final @Nullable Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + final NumberValue that = (NumberValue) o; + return Float.compare(that.value, value) == 0; + } + + @Override + public int hashCode() { + return Float.hashCode(value); + } +} diff --git a/src/main/java/team/unnamed/mocha/runtime/value/ObjectProperty.java b/runtime/src/main/java/org/redlance/mocha/runtime/value/ObjectProperty.java similarity index 97% rename from src/main/java/team/unnamed/mocha/runtime/value/ObjectProperty.java rename to runtime/src/main/java/org/redlance/mocha/runtime/value/ObjectProperty.java index e9b8ba9..cb80f0e 100644 --- a/src/main/java/team/unnamed/mocha/runtime/value/ObjectProperty.java +++ b/runtime/src/main/java/org/redlance/mocha/runtime/value/ObjectProperty.java @@ -1,27 +1,27 @@ -/* - * This file is part of mocha, licensed under the MIT license - * - * Copyright (c) 2021-2025 Unnamed Team - * - * 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. - */ -package team.unnamed.mocha.runtime.value; +/* + * This file is part of mocha, licensed under the MIT license + * + * Copyright (c) 2021-2025 Unnamed Team + * + * 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. + */ +package org.redlance.mocha.runtime.value; import org.jetbrains.annotations.NotNull; diff --git a/src/main/java/team/unnamed/mocha/runtime/value/ObjectPropertyImpl.java b/runtime/src/main/java/org/redlance/mocha/runtime/value/ObjectPropertyImpl.java similarity index 97% rename from src/main/java/team/unnamed/mocha/runtime/value/ObjectPropertyImpl.java rename to runtime/src/main/java/org/redlance/mocha/runtime/value/ObjectPropertyImpl.java index fad0ecd..b157267 100644 --- a/src/main/java/team/unnamed/mocha/runtime/value/ObjectPropertyImpl.java +++ b/runtime/src/main/java/org/redlance/mocha/runtime/value/ObjectPropertyImpl.java @@ -1,27 +1,27 @@ -/* - * This file is part of mocha, licensed under the MIT license - * - * Copyright (c) 2021-2025 Unnamed Team - * - * 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. - */ -package team.unnamed.mocha.runtime.value; +/* + * This file is part of mocha, licensed under the MIT license + * + * Copyright (c) 2021-2025 Unnamed Team + * + * 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. + */ +package org.redlance.mocha.runtime.value; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; diff --git a/src/main/java/team/unnamed/mocha/runtime/value/ObjectValue.java b/runtime/src/main/java/org/redlance/mocha/runtime/value/ObjectValue.java similarity index 96% rename from src/main/java/team/unnamed/mocha/runtime/value/ObjectValue.java rename to runtime/src/main/java/org/redlance/mocha/runtime/value/ObjectValue.java index 538697e..06930e1 100644 --- a/src/main/java/team/unnamed/mocha/runtime/value/ObjectValue.java +++ b/runtime/src/main/java/org/redlance/mocha/runtime/value/ObjectValue.java @@ -1,101 +1,101 @@ -/* - * This file is part of mocha, licensed under the MIT license - * - * Copyright (c) 2021-2025 Unnamed Team - * - * 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. - */ -package team.unnamed.mocha.runtime.value; - -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.Collections; -import java.util.Map; - -public non-sealed interface ObjectValue extends Value { - /** - * Returns the property for the given name ignoring - * its case. This method is CASE-INSENSITIVE. - * - * @param name The name of the property - * @return The property for the given name - * @since 3.0.0 - */ - @Nullable ObjectProperty getProperty(final @NotNull String name); - - /** - * Gets the value of the specified property, - * ignoring its casing. This method is - * CASE-INSENSITIVE. - * - * @param name The name of the property - * @return The value of the property - * @since 3.0.0 - */ - default @NotNull Value get(final @NotNull String name) { - final ObjectProperty property = getProperty(name); - if (property == null) { - return Value.nil(); - } else { - return property.value(); - } - } - - default boolean set(final @NotNull String name, final @Nullable Value value) { - return false; - } - - default @NotNull Map entries() { - return Collections.emptyMap(); - } - - // :) overloads - default void setFunction(final @NotNull String name, final @NotNull ObjectValue.FloatFunction function) { - set(name, (Function) (ctx, args) -> NumberValue.of(function.apply())); - } - - default void setFunction(final @NotNull String name, final @NotNull ObjectValue.FloatFunction1 function) { - set(name, (Function) (ctx, args) -> NumberValue.of(function.apply(args.next().eval().getAsNumber()))); - } - - default void setFunction(final @NotNull String name, final @NotNull ObjectValue.FloatFunction2 function) { - set(name, (Function) (ctx, args) -> NumberValue.of(function.apply(args.next().eval().getAsNumber(), args.next().eval().getAsNumber()))); - } - - default void setFunction(final @NotNull String name, final @NotNull ObjectValue.FloatFunction3 function) { - set(name, (Function) (ctx, args) -> NumberValue.of(function.apply(args.next().eval().getAsNumber(), args.next().eval().getAsNumber(), args.next().eval().getAsNumber()))); - } - - interface FloatFunction { - float apply(); - } - - interface FloatFunction1 { - float apply(float n); - } - - interface FloatFunction2 { - float apply(float n1, float n2); - } - - interface FloatFunction3 { - float apply(float n1, float n2, float n3); - } -} +/* + * This file is part of mocha, licensed under the MIT license + * + * Copyright (c) 2021-2025 Unnamed Team + * + * 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. + */ +package org.redlance.mocha.runtime.value; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Collections; +import java.util.Map; + +public non-sealed interface ObjectValue extends Value { + /** + * Returns the property for the given name ignoring + * its case. This method is CASE-INSENSITIVE. + * + * @param name The name of the property + * @return The property for the given name + * @since 3.0.0 + */ + @Nullable ObjectProperty getProperty(final @NotNull String name); + + /** + * Gets the value of the specified property, + * ignoring its casing. This method is + * CASE-INSENSITIVE. + * + * @param name The name of the property + * @return The value of the property + * @since 3.0.0 + */ + default @NotNull Value get(final @NotNull String name) { + final ObjectProperty property = getProperty(name); + if (property == null) { + return Value.nil(); + } else { + return property.value(); + } + } + + default boolean set(final @NotNull String name, final @Nullable Value value) { + return false; + } + + default @NotNull Map entries() { + return Collections.emptyMap(); + } + + // :) overloads + default void setFunction(final @NotNull String name, final @NotNull ObjectValue.FloatFunction function) { + set(name, (Function) (ctx, args) -> NumberValue.of(function.apply())); + } + + default void setFunction(final @NotNull String name, final @NotNull ObjectValue.FloatFunction1 function) { + set(name, (Function) (ctx, args) -> NumberValue.of(function.apply(args.next().eval().getAsNumber()))); + } + + default void setFunction(final @NotNull String name, final @NotNull ObjectValue.FloatFunction2 function) { + set(name, (Function) (ctx, args) -> NumberValue.of(function.apply(args.next().eval().getAsNumber(), args.next().eval().getAsNumber()))); + } + + default void setFunction(final @NotNull String name, final @NotNull ObjectValue.FloatFunction3 function) { + set(name, (Function) (ctx, args) -> NumberValue.of(function.apply(args.next().eval().getAsNumber(), args.next().eval().getAsNumber(), args.next().eval().getAsNumber()))); + } + + interface FloatFunction { + float apply(); + } + + interface FloatFunction1 { + float apply(float n); + } + + interface FloatFunction2 { + float apply(float n1, float n2); + } + + interface FloatFunction3 { + float apply(float n1, float n2, float n3); + } +} diff --git a/src/main/java/team/unnamed/mocha/runtime/value/StringValue.java b/runtime/src/main/java/org/redlance/mocha/runtime/value/StringValue.java similarity index 97% rename from src/main/java/team/unnamed/mocha/runtime/value/StringValue.java rename to runtime/src/main/java/org/redlance/mocha/runtime/value/StringValue.java index 33c5163..5c52412 100644 --- a/src/main/java/team/unnamed/mocha/runtime/value/StringValue.java +++ b/runtime/src/main/java/org/redlance/mocha/runtime/value/StringValue.java @@ -1,27 +1,27 @@ -/* - * This file is part of mocha, licensed under the MIT license - * - * Copyright (c) 2021-2025 Unnamed Team - * - * 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. - */ -package team.unnamed.mocha.runtime.value; +/* + * This file is part of mocha, licensed under the MIT license + * + * Copyright (c) 2021-2025 Unnamed Team + * + * 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. + */ +package org.redlance.mocha.runtime.value; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; diff --git a/src/main/java/team/unnamed/mocha/runtime/value/Value.java b/runtime/src/main/java/org/redlance/mocha/runtime/value/Value.java similarity index 98% rename from src/main/java/team/unnamed/mocha/runtime/value/Value.java rename to runtime/src/main/java/org/redlance/mocha/runtime/value/Value.java index 29ea9f5..b9301b7 100644 --- a/src/main/java/team/unnamed/mocha/runtime/value/Value.java +++ b/runtime/src/main/java/org/redlance/mocha/runtime/value/Value.java @@ -1,27 +1,27 @@ -/* - * This file is part of mocha, licensed under the MIT license - * - * Copyright (c) 2021-2025 Unnamed Team - * - * 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. - */ -package team.unnamed.mocha.runtime.value; +/* + * This file is part of mocha, licensed under the MIT license + * + * Copyright (c) 2021-2025 Unnamed Team + * + * 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. + */ +package org.redlance.mocha.runtime.value; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; diff --git a/runtime/src/main/java/org/redlance/mocha/runtime/value/package-info.java b/runtime/src/main/java/org/redlance/mocha/runtime/value/package-info.java new file mode 100644 index 0000000..b1cc491 --- /dev/null +++ b/runtime/src/main/java/org/redlance/mocha/runtime/value/package-info.java @@ -0,0 +1,4 @@ +@ReflectionSupport(ReflectionSupport.Level.NATIVE_ONLY) +package org.redlance.mocha.runtime.value; + +import com.google.j2objc.annotations.ReflectionSupport; \ No newline at end of file diff --git a/src/test/java/team/unnamed/mocha/runtime/value/ValueOfTest.java b/runtime/src/test/java/org/redlance/mocha/runtime/value/ValueOfTest.java similarity index 96% rename from src/test/java/team/unnamed/mocha/runtime/value/ValueOfTest.java rename to runtime/src/test/java/org/redlance/mocha/runtime/value/ValueOfTest.java index 40f6128..7d34219 100644 --- a/src/test/java/team/unnamed/mocha/runtime/value/ValueOfTest.java +++ b/runtime/src/test/java/org/redlance/mocha/runtime/value/ValueOfTest.java @@ -1,49 +1,49 @@ -/* - * This file is part of mocha, licensed under the MIT license - * - * Copyright (c) 2021-2025 Unnamed Team - * - * 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. - */ -package team.unnamed.mocha.runtime.value; - -import org.junit.jupiter.api.Test; - -import static org.junit.jupiter.api.Assertions.assertEquals; - -class ValueOfTest { - @Test - void test() { - assertEquals(NumberValue.of(5), Value.of(5)); - assertEquals(StringValue.of("hello"), Value.of("hello")); - assertEquals(NumberValue.of(1), Value.of(true)); - assertEquals(NumberValue.zero(), Value.of(false)); - assertEquals(NumberValue.zero(), Value.of(null)); - assertEquals(NumberValue.zero(), Value.of(new Object())); - assertEquals(ArrayValue.of(), Value.of(new Object[0])); - assertEquals(ArrayValue.of(), Value.of(new int[0])); - assertEquals(ArrayValue.of(), Value.of(new float[0])); - assertEquals(ArrayValue.of(NumberValue.of(1)), Value.of(new int[]{1})); - assertEquals(ArrayValue.of(NumberValue.of(1)), Value.of(new float[]{1})); - assertEquals(ArrayValue.of(NumberValue.of(1)), Value.of(new Object[]{1})); - assertEquals(ArrayValue.of(NumberValue.of(1), NumberValue.of(2)), Value.of(new int[]{1, 2})); - assertEquals(ArrayValue.of(NumberValue.of(1), NumberValue.of(2)), Value.of(new float[]{1, 2})); - assertEquals(ArrayValue.of(NumberValue.of(1), StringValue.of("hello"), NumberValue.zero()), Value.of(new Object[]{1, "hello", false})); - } -} +/* + * This file is part of mocha, licensed under the MIT license + * + * Copyright (c) 2021-2025 Unnamed Team + * + * 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. + */ +package org.redlance.mocha.runtime.value; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +class ValueOfTest { + @Test + void test() { + assertEquals(NumberValue.of(5), Value.of(5)); + assertEquals(StringValue.of("hello"), Value.of("hello")); + assertEquals(NumberValue.of(1), Value.of(true)); + assertEquals(NumberValue.zero(), Value.of(false)); + assertEquals(NumberValue.zero(), Value.of(null)); + assertEquals(NumberValue.zero(), Value.of(new Object())); + assertEquals(ArrayValue.of(), Value.of(new Object[0])); + assertEquals(ArrayValue.of(), Value.of(new int[0])); + assertEquals(ArrayValue.of(), Value.of(new float[0])); + assertEquals(ArrayValue.of(NumberValue.of(1)), Value.of(new int[]{1})); + assertEquals(ArrayValue.of(NumberValue.of(1)), Value.of(new float[]{1})); + assertEquals(ArrayValue.of(NumberValue.of(1)), Value.of(new Object[]{1})); + assertEquals(ArrayValue.of(NumberValue.of(1), NumberValue.of(2)), Value.of(new int[]{1, 2})); + assertEquals(ArrayValue.of(NumberValue.of(1), NumberValue.of(2)), Value.of(new float[]{1, 2})); + assertEquals(ArrayValue.of(NumberValue.of(1), StringValue.of("hello"), NumberValue.zero()), Value.of(new Object[]{1, "hello", false})); + } +} diff --git a/src/test/java/team/unnamed/mocha/util/CaseInsensitiveStringHashMapTest.java b/runtime/src/test/java/org/redlance/mocha/util/CaseInsensitiveStringHashMapTest.java similarity index 96% rename from src/test/java/team/unnamed/mocha/util/CaseInsensitiveStringHashMapTest.java rename to runtime/src/test/java/org/redlance/mocha/util/CaseInsensitiveStringHashMapTest.java index 7f3e49e..f2cf00f 100644 --- a/src/test/java/team/unnamed/mocha/util/CaseInsensitiveStringHashMapTest.java +++ b/runtime/src/test/java/org/redlance/mocha/util/CaseInsensitiveStringHashMapTest.java @@ -1,29 +1,30 @@ -/* - * This file is part of mocha, licensed under the MIT license - * - * Copyright (c) 2021-2025 Unnamed Team - * - * 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. - */ -package team.unnamed.mocha.util; +/* + * This file is part of mocha, licensed under the MIT license + * + * Copyright (c) 2021-2025 Unnamed Team + * + * 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. + */ +package org.redlance.mocha.util; import org.junit.jupiter.api.Test; +import org.redlance.mocha.runtime.util.CaseInsensitiveStringHashMap; import java.util.Arrays; import java.util.HashSet; diff --git a/scripts/generate_expectations.js b/scripts/generate_expectations.js index 0cbe2d1..7aef030 100755 --- a/scripts/generate_expectations.js +++ b/scripts/generate_expectations.js @@ -13,7 +13,7 @@ const parser = new (require('./lib/molang'))(); // create read/write streams to generate // results -const basePath = 'src/test/resources'; +const basePath = 'runtime-compiler/src/test/resources'; const input = fs.createReadStream(`${basePath}/tests.txt`); const output = fs.createWriteStream(`${basePath}/expectations.txt`); diff --git a/settings.gradle.kts b/settings.gradle.kts index 2338c7b..c7d1e96 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -6,3 +6,10 @@ pluginManagement { } rootProject.name = "mocha" + +include( + "lexer", + "parser", + "runtime", + "runtime-compiler", +) diff --git a/src/jmh/java/team/unnamed/mocha/CompareBenchmark.java b/src/jmh/java/team/unnamed/mocha/CompareBenchmark.java index 2fbeaef..cc598e1 100644 --- a/src/jmh/java/team/unnamed/mocha/CompareBenchmark.java +++ b/src/jmh/java/team/unnamed/mocha/CompareBenchmark.java @@ -1,27 +1,27 @@ -/* - * This file is part of mocha, licensed under the MIT license - * - * Copyright (c) 2021-2025 Unnamed Team - * - * 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. - */ -package team.unnamed.mocha; +/* + * This file is part of mocha, licensed under the MIT license + * + * Copyright (c) 2021-2025 Unnamed Team + * + * 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. + */ +package team.unnamed.mocha; import com.bedrockk.molang.MoLang; import com.bedrockk.molang.parser.Expression; @@ -42,7 +42,8 @@ import org.openjdk.jmh.runner.RunnerException; import org.openjdk.jmh.runner.options.Options; import org.openjdk.jmh.runner.options.OptionsBuilder; -import team.unnamed.mocha.runtime.MochaFunction; +import org.redlance.mocha.runtime.MochaEngine; +import org.redlance.mocha.runtime.MochaFunction; import java.util.List; import java.util.concurrent.TimeUnit; @@ -75,7 +76,7 @@ public void prepare() throws Exception { final String expr = "temp.t = 3; return 3*temp.t*temp.t - 2*temp.t*temp.t*temp.t;"; - function = mocha.compile(expr); + function = mocha.compiler().compile(expr); mlExpression = MolangCompiler.create(MolangCompiler.DEFAULT_FLAGS, getClass().getClassLoader()).compile(expr); mlExpressions = MoLang.newParser("temp.t = 3; return 3*temp.t*temp.t - 2*temp.t*temp.t*temp.t;").parse(); } diff --git a/src/main/java/team/unnamed/mocha/MochaEngine.java b/src/main/java/team/unnamed/mocha/MochaEngine.java deleted file mode 100644 index 77f4696..0000000 --- a/src/main/java/team/unnamed/mocha/MochaEngine.java +++ /dev/null @@ -1,458 +0,0 @@ -/* - * This file is part of mocha, licensed under the MIT license - * - * Copyright (c) 2021-2025 Unnamed Team - * - * 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. - */ -package team.unnamed.mocha; - -import org.jetbrains.annotations.Contract; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import team.unnamed.mocha.parser.ParseException; -import team.unnamed.mocha.parser.ast.Expression; -import team.unnamed.mocha.runtime.MochaFunction; -import team.unnamed.mocha.runtime.Scope; -import team.unnamed.mocha.runtime.binding.Binding; -import team.unnamed.mocha.runtime.binding.JavaObjectBinding; -import team.unnamed.mocha.runtime.compiled.MochaCompiledFunction; -import team.unnamed.mocha.runtime.standard.MochaMath; -import team.unnamed.mocha.runtime.value.MutableObjectBinding; -import team.unnamed.mocha.runtime.value.ObjectValue; - -import java.io.IOException; -import java.io.Reader; -import java.io.StringReader; -import java.io.UncheckedIOException; -import java.util.List; -import java.util.function.Consumer; - -import static java.util.Objects.requireNonNull; - -/** - * The engine's entry class. Provides methods to evaluate - * and parse Molang code from strings and readers. - * - * @since 3.0.0 - */ -public interface MochaEngine { - static MochaEngine create(T entity) { - return new MochaEngineImpl<>(entity, b -> { - }); - } - - static MochaEngine create(T entity, Consumer scopeBuilder) { - return new MochaEngineImpl<>(entity, scopeBuilder); - } - - static MochaEngine create() { - return new MochaEngineImpl<>(null, b -> { - }); - } - - /** - * Creates a new, clean and empty {@link MochaEngine} instance - * with the standard, default bindings. - * - * @return The created {@link MochaEngine} instance. - * @since 3.0.0 - */ - @Contract("_ -> new") - static @NotNull MochaEngine createStandard(T entity) { - return create(entity, builder -> { - builder.set("math", JavaObjectBinding.of(MochaMath.class, null, new MochaMath())); - final MutableObjectBinding variableBinding = new MutableObjectBinding(); - builder.set("variable", variableBinding); - builder.set("v", variableBinding); - }); - } - - /** - * Creates a new, clean and empty {@link MochaEngine} instance - * with the standard, default bindings. - * - * @return The created {@link MochaEngine} instance. - * @since 3.0.0 - */ - @Contract("-> new") - static @NotNull MochaEngine createStandard() { - return createStandard(null); - } - - //#region PARSING API - - /** - * Parses the data from the given {@code reader} - * to a {@link List} of {@link Expression} - * - * Note that this method won't close - * the given {@code reader} - * - * @param reader The reader to read the data from - * @return The list of parsed expressions - * @throws ParseException If read failed or there - * are syntax errors in the script - * @since 3.0.0 - */ - @NotNull List parse(final @NotNull Reader reader) throws IOException; - - /** - * Parses the given {@code string} to a list of - * {@link Expression} - * - * @param string The MoLang string - * @return The list of parsed expressions - * @throws ParseException If parsing fails - */ - default @NotNull List parse(final @NotNull String string) throws ParseException { - try (final StringReader reader = new StringReader(string)) { - return parse(reader); - } catch (final ParseException e) { - throw e; - } catch (final IOException e) { - throw new UncheckedIOException("Error occurred reading the source code: '" + string + "'", e); - } - } - - //#endregion END PARSING API - - //#region INTERPRETER API - - /** - * Evaluates the given {@code expressions}, these expressions - * are already parsed and are interpreted as fast as possible. - * - * @param expressions The expressions to evaluate. - * @return The result of the evaluation. - * @since 4.1.0 - */ - float eval(final @NotNull List expressions, final @Nullable Consumer scopeConsumer); - - /** - * See {@link #eval(List, Consumer)} - * @since 3.0.0 - */ - default float eval(final @NotNull List expressions) { - return eval(expressions, null); - } - - /** - * Parses and evaluates the given Molang source. - * - *

Note that the engine instance is not responsible - * for caching parsed expressions, so if you want to - * re-use parsed expressions, you should use the - * {@link #parse(Reader)} and {@link #eval(List, Consumer)} - * methods.

- * - * @param source The source to evaluate. - * @return The result of the evaluation. - * @see #parse(Reader) - * @see #eval(List, Consumer) - * @since 4.1.0 - */ - float eval(final @NotNull Reader source, final @Nullable Consumer scopeConsumer); - - /** - * See {@link #eval(Reader, Consumer)} - * @since 3.0.0 - */ - default float eval(final @NotNull Reader source) { - return eval(source, null); - } - - /** - * Parses and evaluates the given Molang source. - * - *

Note that the engine instance is not responsible - * for caching parsed expressions, so if you want to - * re-use parsed expressions, you should use the - * {@link #parse(String)} and {@link #eval(List, Consumer)} - * methods.

- * - * @param source The source to evaluate. - * @return The result of the evaluation. - * @see #parse(String) - * @see #eval(List, Consumer) - * @since 4.1.0 - */ - default float eval(final @NotNull String source, final @Nullable Consumer scopeConsumer) { - requireNonNull(source, "script"); - try (final StringReader reader = new StringReader(source)) { - return eval(reader, scopeConsumer); - } - } - - /** - * See {@link #eval(String, Consumer)} - * @since 3.0.0 - */ - default float eval(final @NotNull String source) { - return eval(source, null); - } - - /** - * Parses the data from the given {@code reader} and - * returns a cached, interpretable {@link MochaFunction}. - * - *
Note that this method won't close the given
-     * {@code reader}
- * - *

This approach is the same as parsing to a List of - * expressions, caching them and then evaluating using - * {@link #eval(List, Consumer)}, but easier, since it already keeps - * this {@link MochaEngine} instance.

- * - * @param reader The reader to read the data from - * @return The cached, interpretable function - * @since 4.1.0 - */ - @NotNull MochaFunction prepareEval(final @NotNull Reader reader, final @Nullable Consumer scopeConsumer); - - /** - * See {@link #prepareEval(Reader, Consumer)} - * @since 3.0.0 - */ - default @NotNull MochaFunction prepareEval(final @NotNull Reader reader) { - return prepareEval(reader, null); - } - - /** - * Parses the given {@code string} and returns a cached, - * interpretable {@link MochaFunction}. - * - *

This approach is the same as parsing to a List of - * expressions, caching them and then evaluating using - * {@link #eval(List, Consumer)}, but easier, since it already keeps - * this {@link MochaEngine} instance.

- * - * @param string The MoLang string - * @return The cached, interpretable function - * @since 4.1.0 - */ - default @NotNull MochaFunction prepareEval(final @NotNull String string, final @Nullable Consumer scopeConsumer) { - try (final StringReader reader = new StringReader(string)) { - return prepareEval(reader, scopeConsumer); - } - } - - /** - * See {@link #prepareEval(String, Consumer)} - * @since 3.0.0 - */ - default @NotNull MochaFunction prepareEval(final @NotNull String string) { - return prepareEval(string, null); - } - //#endregion END INTERPRETER API - - //#region COMPILING API - - /** - * Compiles the given code into a Molang function - * that can take arguments. - * - * @param reader The code to compile. - * @param interfaceType The interface to implement, must - * have a single method. - * @return The compiled function. - * @since 3.0.0 - */ - @NotNull F compile(final @NotNull Reader reader, final @NotNull Class interfaceType); - - /** - * Compiles the given code into a Molang function - * that can take arguments. - * - * @param expressions The code to compile. - * @param interfaceType The interface to implement, must - * have a single method. - * @return The compiled function. - * @since 4.0.4 - */ - @NotNull F compile(final @NotNull List expressions, final @NotNull Class interfaceType); - - /** - * Compiles the given code into a Molang function - * that can take arguments. - * - * @param code The code to compile. - * @param interfaceType The interface to implement, must - * have a single method. - * @return The compiled function. - * @since 3.0.0 - */ - default @NotNull F compile(final @NotNull String code, final @NotNull Class interfaceType) { - requireNonNull(code, "code"); - try (final StringReader reader = new StringReader(code)) { - return compile(reader, interfaceType); - } - } - - /** - * Compiles the given code into a Molang function - * that takes no arguments. - * - * @param reader The code to compile. - * @return The compiled function. - * @since 3.0.0 - */ - default @NotNull MochaFunction compile(final @NotNull Reader reader) { - return compile(reader, MochaFunction.class); - } - - /** - * Compiles the given code into a Molang function - * that takes no arguments. - * - * @param expressions The code to compile. - * @return The compiled function. - * @since 4.0.4 - */ - default @NotNull MochaFunction compile(final @NotNull List expressions) { - return compile(expressions, MochaFunction.class); - } - - /** - * Compiles the given code into a Molang function - * that takes no arguments. - * - * @param code The code to compile. - * @return The compiled function. - * @since 3.0.0 - */ - default @NotNull MochaFunction compile(final @NotNull String code) { - requireNonNull(code, "code"); - try (final StringReader reader = new StringReader(code)) { - return compile(reader); - } - } - - //#endregion END COMPILING API - - //#region BINDING API - - /** - * Binds the given {@code clazz} static fields and methods. - * - *

Fields and methods are bound in the following format:

- *
-     *     namespace.field
-     *     namespace.method()
-     *     namespace.method(arg1, arg2)
-     * 
- * - *

Where {@code namespace} is given by the given class' - * {@link Binding} annotation, and the field and method - * names are also given by {@link Binding} annotations.

- * - * @param clazz The class to bind. - * @see Binding - * @since 3.0.0 - */ - void bind(final @NotNull Class clazz); - - /** - * Binds the given {@code instance} non-static fields and methods. - * - *

Fields and methods are bound in the following format:

- *
-     *     name.field
-     *     name.method()
-     *     name.method(arg1, arg2)
-     * 
- * - *

Where {@code name} is given by the {@code name} parameter, - * and the field and method names are given by {@link Binding} - * annotations.

- * - * @param clazz The instance's class (or interface) to use. - * @param instance The instance to bind. - * @param name The name to bind the instance to. - * @param aliases The aliases to bind the instance to. - * @param The instance's type. - * @since 3.0.0 - */ - void bindInstance(final @NotNull Class clazz, final @NotNull B instance, final @NotNull String name, final @NotNull String @NotNull ... aliases); - //#endregion - - //#region CONFIGURATION API - - /** - * Sets the boolean value for the "warn on reflective function usage" - * option. - * - *

When set to true, {@link #eval} may log a warning when evaluating - * code that includes a call to a function that was registered using only - * annotations, and for so, has to be called using Reflection, taking some - * extra time.

- * - *

Note that this behavior can be avoided by setting a {@link ObjectValue} - * when binding static or non-static methods and fields

- * - *

By default this is false.

- * - * @param warnOnReflectiveFunctionUsage The new value for the option - * @return This engine instance - * @since 3.0.0 - */ - @Contract("_ -> this") - @NotNull MochaEngine warnOnReflectiveFunctionUsage(final boolean warnOnReflectiveFunctionUsage); - - /** - * Sets the {@link ParseException} handler. This handler will be called - * whenever an internal call to the {@link #parse} method fails. These - * internal calls commonly include interpreting or compiling code. - * - *

Usually useful for logging/debugging purposes.

- * - *

By default this is null.

- * - * @param exceptionHandler The new parse exception handler - * @return This engine instance - * @since 3.0.0 - */ - @Contract("_ -> this") - @NotNull MochaEngine handleParseExceptions(final @Nullable Consumer<@NotNull ParseException> exceptionHandler); - - /** - * Sets the post-compile function, which is called after a script - * is compiled to a new class, and before it is loaded. The received - * argument is the class bytecode, which can be written to a file for - * debugging purposes. - * - *

By default this is set to null.

- * - * @param bytecodeConsumer The new post-compile function - * @return This engine instance - * @since 3.0.0 - */ - @Contract("_ -> this") - @NotNull MochaEngine postCompile(final @Nullable Consumer bytecodeConsumer); - //#endregion - - /** - * Returns the bindings for this Molang engine - * instance. - * - * @return This engine's bindings - * @since 3.0.0 - */ - @NotNull Scope scope(); -} diff --git a/src/main/java/team/unnamed/mocha/MochaEngineImpl.java b/src/main/java/team/unnamed/mocha/MochaEngineImpl.java deleted file mode 100644 index 0e0cef5..0000000 --- a/src/main/java/team/unnamed/mocha/MochaEngineImpl.java +++ /dev/null @@ -1,243 +0,0 @@ -/* - * This file is part of mocha, licensed under the MIT license - * - * Copyright (c) 2021-2025 Unnamed Team - * - * 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. - */ -package team.unnamed.mocha; - -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import team.unnamed.mocha.parser.MolangParser; -import team.unnamed.mocha.parser.ParseException; -import team.unnamed.mocha.parser.ast.Expression; -import team.unnamed.mocha.parser.ast.FloatExpression; -import team.unnamed.mocha.runtime.ExpressionInterpreter; -import team.unnamed.mocha.runtime.MochaFunction; -import team.unnamed.mocha.runtime.MolangCompiler; -import team.unnamed.mocha.runtime.Scope; -import team.unnamed.mocha.runtime.binding.JavaObjectBinding; -import team.unnamed.mocha.runtime.compiled.MochaCompiledFunction; -import team.unnamed.mocha.runtime.value.MutableObjectBinding; -import team.unnamed.mocha.runtime.value.NumberValue; -import team.unnamed.mocha.runtime.value.Value; - -import java.io.IOException; -import java.io.Reader; -import java.io.UncheckedIOException; -import java.util.Collections; -import java.util.List; -import java.util.function.Consumer; - -final class MochaEngineImpl implements MochaEngine { - private final Scope scope; - private final T entity; - private final MolangCompiler compiler; - - private Consumer<@NotNull ParseException> parseExceptionHandler; - private boolean warnOnReflectiveFunctionUsage; - - public MochaEngineImpl(final T entity, final Consumer scopeBuilder) { - Scope.Builder builder = Scope.builder(); - scopeBuilder.accept(builder); - this.scope = builder.build(); - this.entity = entity; - this.compiler = new MolangCompiler(entity, scope); - } - - @Override - public float eval(final @NotNull List expressions, final @Nullable Consumer scopeConsumer) { - if (expressions.size() == 1 && expressions.get(0) instanceof FloatExpression expression) { - return expression.value(); - } - - // create bindings that just apply for this evaluation - final Scope local = scope.copy(); - { - // create temp bindings - MutableObjectBinding temp = new MutableObjectBinding(); - local.set("temp", temp); - local.set("t", temp); - } - if (scopeConsumer != null && !local.readOnly()) scopeConsumer.accept(local); - local.readOnly(true); - ExpressionInterpreter evaluator = new ExpressionInterpreter<>(entity, local); - evaluator.warnOnReflectiveFunctionUsage(warnOnReflectiveFunctionUsage); - Value lastResult = NumberValue.zero(); - - for (Expression expression : expressions) { - lastResult = expression.visit(evaluator); - Value returnValue = evaluator.popReturnValue(); - if (returnValue != null) { - lastResult = returnValue; - break; - } - } - - // ensure returned value is a number - return lastResult == null ? 0F : lastResult.getAsNumber(); - } - - @Override - public float eval(final @NotNull Reader source, final @Nullable Consumer scopeConsumer) { - final List parsed; - try { - parsed = parse(source); - } catch (final ParseException e) { - // parse errors just output zero - if (parseExceptionHandler != null) { - parseExceptionHandler.accept(e); - } - return 0; - } catch (final IOException e) { - throw new UncheckedIOException("Failed to read from given reader", e); - } - return eval(parsed, scopeConsumer); - } - - @Override - public @NotNull MochaFunction prepareEval(final @NotNull Reader reader, final @Nullable Consumer scopeConsumer) { - final List parsed; - try { - parsed = parse(reader); - } catch (final ParseException e) { - // parse errors just output zero - if (parseExceptionHandler != null) { - parseExceptionHandler.accept(e); - } - return () -> 0F; - } catch (final IOException e) { - throw new UncheckedIOException("Failed to read from given reader", e); - } - return new MochaFunction() { - @Override - public float evaluate() { - return eval(parsed, scopeConsumer); - } - - @Override - public @NotNull String toString() { - return "MochaPreparedFunction(" + parsed + ")"; - } - }; - } - - @Override - public @NotNull MochaFunction prepareEval(final @NotNull String code, final @Nullable Consumer scopeConsumer) { - final List parsed; - try { - parsed = parse(code); - } catch (final ParseException e) { - // parse errors just output zero - if (parseExceptionHandler != null) { - parseExceptionHandler.accept(e); - } - return new MochaFunction() { - @Override - public float evaluate() { - return 0F; - } - - @Override - public @NotNull String toString() { - return "MochaPreparedFunction('" + code + "', " + e.getMessage() + ")"; - } - }; - } - - return new MochaFunction() { - @Override - public float evaluate() { - return eval(parsed, scopeConsumer); - } - - @Override - public @NotNull String toString() { - return "MochaPreparedFunction(" + parsed + ")"; - } - }; - } - - @Override - public @NotNull F compile(final @NotNull Reader reader, final @NotNull Class interfaceType) { - List parsed; - try { - parsed = parse(reader); - } catch (final ParseException e) { - if (parseExceptionHandler != null) { - parseExceptionHandler.accept(e); - } - parsed = Collections.emptyList(); - } catch (final IOException e) { - throw new RuntimeException("Failed to read from given reader", e); - } - return compile(parsed, interfaceType); - } - - @Override - public @NotNull F compile(final @NotNull List parsed, final @NotNull Class interfaceType) { - return compiler.compile(parsed, interfaceType); - } - - @Override - public @NotNull Scope scope() { - return scope; - } - - @Override - public void bind(final @NotNull Class clazz) { - final JavaObjectBinding javaObjectBinding = JavaObjectBinding.of(clazz, null, null); - for (final String name : javaObjectBinding.names()) { - scope.set(name, javaObjectBinding); - } - } - - @Override - public void bindInstance(final @NotNull Class clazz, final @NotNull B instance, final @NotNull String name, final @NotNull String @NotNull ... aliases) { - final JavaObjectBinding javaObjectBinding = JavaObjectBinding.of(clazz, instance, null); - scope.set(name, javaObjectBinding); - for (final String alias : aliases) { - scope.set(alias, javaObjectBinding); - } - } - - @Override - public @NotNull List parse(final @NotNull Reader reader) throws IOException { - return MolangParser.parser(reader).parseAll(); - } - - @Override - public @NotNull MochaEngine warnOnReflectiveFunctionUsage(final boolean warnOnReflectiveFunctionUsage) { - this.warnOnReflectiveFunctionUsage = warnOnReflectiveFunctionUsage; - return this; - } - - @Override - public @NotNull MochaEngine handleParseExceptions(final @Nullable Consumer<@NotNull ParseException> exceptionHandler) { - this.parseExceptionHandler = exceptionHandler; - return this; - } - - @Override - public @NotNull MochaEngine postCompile(final @Nullable Consumer bytecodeConsumer) { - compiler.postCompile(bytecodeConsumer); - return this; - } -}