Kahlua Java-based Lua Virtual Machine

repository·master·Indexed 40 days ago

https://github.com/krka/kahlua2

A Lua-compatible virtual machine and standard library implemented in Java, optimized for resource-constrained environments like J2ME (CLDC 1.1) and compatible with standard Java (J2SE/J2EE). It provides a mapping of Lua types to Java types, a JavaFunction interface for exporting Java logic to Lua, and a specialized implementation of pcall and collectgarbage.

Tokens
1.8K
Snippets
3
Records
13
Agent score
0%

What's inside Kahlua

  1. Overview of Kahlua Virtual Machine

    master

    Kahlua is a Lua-compatible Virtual Machine and standard library implemented entirely in Java. It is designed to emulate Lua behavior by reverse-engineering Lua features (using the Lua reference manual and PiL as guides) rather than direct porting.

    Key characteristics:

    • Target Platform: Optimized for J2ME (CLDC 1.1), making it suitable for mobile environments, but also compatible with standard Java (J2SE/J2EE).
    • Integration: Designed for easy integration into J2ME projects. For J2SE/J2EE environments, note that Kahlua lacks a built-in Lua compiler, so a standalone Lua compiler must be used.
    • Goals: Focuses on a small class file footprint, fast runtime for common operations, and high test coverage while maintaining Lua-standard behavior.
  2. Understand Kahlua type mappings

    master

    Kahlua maps fundamental Lua types to Java types as follows:

    Lua TypeKahlua/Java Type
    nilnull
    numberDouble
    booleanBoolean
    stringString (UTF-16)
    tableLuaTable
    coroutineLuaThread
    function (Lua)LuaClosure
    function (Java)JavaFunction interface
  3. Handle Lua strings and equality in Kahlua

    master

    In recent versions of Kahlua, strings are no longer interned everywhere to prevent PermGen heap exhaustion (especially critical on J2ME devices) and to simplify the Java API.

    When working with Kahlua, you must follow these rules:

    1. Do not assume identity equality: Do not assume that strings coming from Lua are interned. You cannot rely on == (identity comparison) for string equality; use standard string equality methods instead.
    2. Avoid manual interning: Do not manually intern strings that you are sending to Lua.
  4. Handle Userdata in Kahlua

    master

    Kahlua does not use the standard Lua userdata concept. Instead, you can pass any Java object directly into Kahlua.

    To operate on these objects, you must set the metatable for the specific class. Note that this applies to all objects of that exact class, but does not automatically apply to subclasses. The recommended way to manipulate these objects is to export Java functions that can operate on them.

  5. Build Kahlua using Apache Ant

    master

    Kahlua uses Apache Ant for its build process. To compile, package, and run all test cases, execute the ant command from the project root.

    After building, you can find:

    • A test report at testreport.html.
    • A coverage report at testsuite/coverage/coverage.html.
    ant
  6. Inspect Lua objects from Java

    master

    Unlike standard Lua which requires a stack-based API (like lua_gettable), Kahlua allows you to interact with Lua objects directly using Java objects. You primarily need LuaState.getEnvironment() to access the global scope.

    To get a value from a Lua table:

    1. Get the environment from the LuaState.
    2. Use rawget(key) on the LuaTable to retrieve the object.
    3. Use instanceof to check the type and cast to the appropriate Java type (e.g., Boolean, Double, String).
    LuaState state = myState;
    // Access a global table
    LuaTable table = (LuaTable) state.getEnvironment().rawget("myTable");
    
    // Access a key within that table
    Object value = table.rawget("myKey");
    
    if (value instanceof Boolean) {
        boolean boolVal = (Boolean) value;
    }
  7. Export Java functions to Lua using JavaFunction

    master

    To expose Java logic to Lua, implement the JavaFunction interface.

    Implementation Steps:

    1. Implement int call(LuaCallFrame callFrame, int nArguments).
    2. Access arguments using callFrame.get(i) (where 0 <= i < nArguments).
    3. Note on Types: All Lua numbers arrive as Double. You must manually convert them to int or long if needed.
    4. Handling Arguments: Be prepared for nArguments to differ from what you expect.
    5. Returning Values:
      • Use callFrame.push(object) to push return values, then return the count of objects pushed.
      • OR use callFrame.setTop(nReturnValues) and callFrame.set(index, object).
      • Crucial: You MUST return the number of return values as an integer >= 0.

    It is safe to throw RuntimeException from call(); Kahlua will convert it into a Lua error.

    public class MyFunction implements JavaFunction {
        @Override
        public int call(LuaCallFrame callFrame, int nArguments) {
            // Accessing an argument
            Double arg0 = (Double) callFrame.get(0);
            
            // Pushing a return value
            callFrame.push("Hello from Java!");
            
            // Return the number of values pushed
            return 1;
        }
    }
  8. Access the environment from a LuaState

    master

    In Kahlua, environments are stored per LuaThread rather than per LuaState.

    To access the environment of the current thread, do not attempt to access LuaState.environment directly (as it is no longer available). Instead, use the convenience method LuaState.getEnvironment(), which retrieves the environment associated with the current thread.

  9. Use debugstacktrace for stack inspection

    master

    Kahlua provides debugstacktrace(thread, level, count, halt_at) as an alternative to Lua's debug.traceback.

    • thread: The thread to inspect (nil for current thread).
    • level: Integer >= 0. The stack level to start at (0 is debugstacktrace itself, 1 is the caller). Defaults to 0.
    • count: Integer representing the upper limit of stackframes to return. Defaults to all.
    • halt_at: Integer representing the stack height at which to stop. Defaults to 0.
  10. Use collectgarbage in Kahlua

    master

    Kahlua's collectgarbage([opt]) is tied to Java's garbage collection. Supported options are:

    • null, "step", or "collect": Runs System.gc() in Java (behavior is not guaranteed).
    • "count": Returns three values: usedMemory, freeMemory, and totalMemory (all in KB).

    All other values for opt will result in an error. Note that __gc metatable modes and standard Lua collectgarbage options are not supported.

  11. Use error(message, [stacktrace]) in Kahlua

    master
    Kahlua's error function signature is error(message, [stacktrace]). This differs from Lua's error(message, [level]). The provided stacktrace is appended to the total stacktrace when caught by pcall. If error is called with zero parameters, it does nothing.
  12. Differences in pcall behavior

    master

    In Kahlua, pcall returns additional information on failure compared to standard Lua.

    Standard Lua returns:

    • false, errormessage

    Kahlua returns:

    1. false
    2. errormessage
    3. stacktrace (a string with newlines separating each call frame)
    4. The original Java exception