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 super B> 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 extends String, ? extends V> lowercaseMap(Map extends String, ? extends V> m) {
+ if (m instanceof CaseInsensitiveStringHashMap) return m;
final Map lowercased = new HashMap<>();
for (Entry extends String, ? extends V> 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 extends String, ? extends V> 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 super B> 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 super B> 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;
- }
-}