Low level bindings for Luau.
There is a lot of prior art for interacting with Lua to/from Java:
- LuaJ (and its many forks)
- luajava (and its many forks)
- LuaTruffle for GraalVM
However, these solutions generally do not have strong sandboxing guarantees (or track record), or lose much of the performance benefit of Lua. Enter Luau. It has been proven at Roblox to be performant, well sandboxed, and easier to use through its introduction of progressive typing.
luau-java
and the associated native libraries are all available
on maven central. All projects must depend on
the main luau artifact, as well as at least one of the platform specific natives. It is valid to depend on multiple
natives artifacts at the same time, they will not conflict.
Important
luau-java
uses the
new Foreign Function and Memory API (FFM) introduced as a preview feature in Java 21.
This means that you will be required to enable preview features when using luau-java
. This can be done by
adding --enable-preview
and --enable-native-access=ALL-UNNAMED
to your JVM arguments.
Gradle
dependencies {
implementation("dev.hollowcube:luau:${version}")
implementation("dev.hollowcube:luau-natives-${platform}:${version}")
}
Maven
<dependencies>
<dependency>
<groupId>dev.hollowcube</groupId>
<artifactId>luau</artifactId>
<version>${version}</version>
</dependency>
<dependency>
<groupId>dev.hollowcube</groupId>
<artifactId>luau-natives-${platform}</artifactId>
<version>${version}</version>
</dependency>
</dependencies>
Replace ${platform}
and ${version}
with one of the following entries. Note that the core library version may be
different from the native library version.
Platform | ${platform} |
${version} |
---|---|---|
- | - | |
Windows (x64) | windows-x64 |
|
Linux (x64) | linux-x64 |
|
macOS (x64) | macos-x64 |
|
macOS (arm64) | macos-arm64 |
A hello world print from Luau would look something like the following:
public class HelloWorld {
public static void main(String[] args) throws LuauCompileException {
final byte[] bytecode = LuauCompiler.DEFAULT.compile("""
print("Hello, Luau!")
""");
final LuaState state = LuaState.newState();
try {
state.openLibs(); // Open all libraries
state.sandbox(); // Sandbox the global state so it cannot be edited by a script
var thread = state.newThread();
thread.sandboxThread(); // Create a mutable global env for scripts to use
thread.load("helloworld.luau", bytecode); // Load the script into the VM
thread.pcall(0, 0); // Eval the script
state.pop(1); // Pop the thread off the stack
} finally {
// Always remember to close the state when you're done with it, or you will leak memory.
state.close();
}
}
}
The test sources contain library examples, which should help you to get started.
Prerequisites: JDK 21+, CMake 3.15+, JExtract (Only required to update bindings)
git clone [email protected]:hollow-cube/luau-java.git --recurse-submodules && cd luau-java
./gradlew build
Bindings are generated using JExtract. They are already included in the repository
inside of src/generated/java
. They may need to be updated as Luau is updated.
./gradlew jextract
Contributions via PRs and issues are always welcome.
This project is licensed under the MIT License.