Lua Stack-based C API
The party.iroiro.luajava.Lua
interface is a wrapper around the lua_State
pointer. Besides LuaValue
-relevant methods, it also provides the common parts from the C APIs of Lua 5.1 ~ 5.4 and LuaJIT. (You are recommended to use the LuaValue
API though.) You may refer to the Javadoc for more information.
Lua
interface
The Java API is mostly a wrapper around The Application Program Interface of Lua. Some common patterns are listed below to help you get started.
Setting a global value
Lua API bases on a Lua stack. You need to push the value onto the stack before assigning it to a global value with setGlobal
.
try (Lua L = new Lua54()) {
// Use LuaValue-based API
L.set("myStr", "string value");
L.run("assert(myStr == 'string value')");
// Or use stack-based API
L.push("string value");
L.setGlobal("myStr");
L.run("assert(myStr == 'string value')");
}
2
3
4
5
6
7
8
9
Getting a global value
Similarly, getGlobal
pushes a value onto the stack, instead of returning it.
try (Lua L = new Lua54()) {
L.run("a = 1024");
// Use LuaValue-based API
assertEquals(1024, L.get("a").toInteger());
// Or use stack-based API
L.getGlobal("a");
assertEquals(1024, L.toInteger(-1));
}
2
3
4
5
6
7
8
Querying a table
We need to make use of getField
, getTable
, rawGet
or rawGetI
.
try (Lua L = new Lua54()) {
L.run("return { a = 1 }"); // Pushes a table on stack
L.getField(-1, "a"); // Retrieves the value
assertEquals(1, L.toInteger(-1));
}
2
3
4
5
try (Lua L = new Lua54()) {
L.run("return { [20] = 1 }"); // Pushes a table on stack
L.rawGetI(-1, 20); // Retrieves the value
assertEquals(1, L.toInteger(-1));
}
2
3
4
5
try (Lua L = new Lua54()) {
L.run("return { a = 1 }"); // Pushes a table on stack
L.push("a"); // Pushes the key to look up
L.getTable(-2); // Retrieves the value
assertEquals(1, L.toInteger(-1));
}
2
3
4
5
6
try (Lua L = new Lua54()) {
L.run("return { a = 1 }"); // Pushes a table on stack
L.push("a"); // Pushes the key to look up
L.rawGet(-2); // Retrieves the value
assertEquals(1, L.toInteger(-1));
}
2
3
4
5
6
Updating a table
Similarly, we have setField
setTable
rawSet
and rawSetI
.
try (Lua L = new Lua54()) {
L.run("return { a = 1 }"); // Pushes a table on stack
L.push(2); // Pushes the new value
L.setField(-2, "a"); // Updates the value
}
2
3
4
5
try (Lua L = new Lua54()) {
L.run("return { [20] = 1 }"); // Pushes a table on stack
L.push(2); // Pushes the new value
L.rawSetI(-2, 20); // Updates the value
}
2
3
4
5
try (Lua L = new Lua54()) {
L.run("return { a = 1 }"); // Pushes a table on stack
L.push("a"); // Pushes the key
L.push(2); // Pushes the new value
L.getTable(-3); // Updates the value
}
2
3
4
5
6
try (Lua L = new Lua54()) {
L.run("return { a = 1 }"); // Pushes a table on stack
L.push("a"); // Pushes the key
L.push(2); // Pushes the new value
L.rawSet(-3); // Updates the value
}
2
3
4
5
6
Creating references
A reference is a unique integer key: table[reference] = referredValue
. Lua provides a convenient way to store values into a table, returning the generated reference key.
See ref()
ref(int)
refGet(int)
unref(int)
and unRef(int, int)
for more info.
Pre-compiled chunks
According to the Lua reference manual:
Chunks can also be pre-compiled into binary form; see program luac for details. Programs in source and compiled forms are interchangeable; Lua automatically detects the file type and acts accordingly.
Replacing Lua source files with pre-compiled chunks speeds up loading. However, according to luac
manual:
Precompiled chunks are not portable across different architectures. Moreover, the internal format of precompiled chunks is likely to change when a new version of Lua is released. Make sure you save the source files of all Lua programs that you precompile.
Binary chunks compiled on one platform may not run on another. Since we are using Java / JVM-based languages, this is absolutely not desirable. To work around this, you may either:
- Provide precompiled chunks for all your target platforms;
- Or compile them at runtime for once and just reuse the compiled binaries.
Here is a tiny example for the second approach:
try (Lua L = new Lua54()) {
ByteBuffer code = readFromFile("MyScript.lua");
// L.load(...) pushes on stack a precompiled function
L.load(code, "MyScript.lua");
// L.dump() calls lua_dump, dumping the precompiled binary
ByteBuffer precompiledChunk = L.dump();
L.load(precompiledChunk, "MyScript.precompiled");
}
2
3
4
5
6
7
8
try (Lua L = new Lua54()) {
L.openLibrary("string");
// string.dump(...) returns the precompiled binary as a Lua string
L.run("return string.dump(function(a, b) return a + b end)");
// L.toBuffer(...) stores the precompiled binary into a buffer and returns it
ByteBuffer precompiledChunk = L.toBuffer(-1);
L.load(precompiledChunk, "MyScript.precompiled");
}
2
3
4
5
6
7
8
Dumping functions involves some more Lua knowledge such as up-values and environments. What these terms mean might differ between versions and is not a topic of this document.
LuaNatives
interface
The LuaNatives
interface exposes common JNI bindings of the C API of Lua 5.1 ~ Lua 5.4. Use with caution.
- Get an instance of
LuaValue
withLuaValue::getLuaNatives()
. - Get the pointer to a
Lua
state withLua::getPointer()
.
If you want to use C API functions specific to a Lua version, simply cast them to the corresponding LuaNatives
implementation:
TIP
LuaJNatives
, which uses LuaJ, a Lua implementation in Java, is actually implemented in Java to provide a consistent API. It should not differ too much from other implementations though.