Tutorial
editInitialization and Deinitialization
editLua scripts are usually run in a VM (Virtual Machine). Therefore we first start one and then load the basic Lua libraries:
Local LuaState:byte ptr = luaL_newstate() luaL_openlibs(LuaState)
The byte pointer returned by luaL_newstate() is needed for every Lua function call. Now you're done with initialization and can begin running scripts.
Closing the Lua VM afterwards is done by a single function:
lua_close(LuaState)
Running a simple script
editLua Scripts can be executed directly from Blitzmax Strings.
Local Script:String = "print(~qHello World!~q)" luaL_loadString(LuaState,Script)
This code loads and compiles the script. luaL_loadString() returns a value <> 0 if something went wrong.
lua_getfield(LuaState, LUA_GLOBALSINDEX, "debug")' get global "debug" lua_getfield(LuaState, -1, "traceback") ' get "debug.traceback" lua_remove (LuaState, -2) ' remove "debug" table from stack
These commands are not important for now, they're just there to get proper error messages.
lua_pcall(LuaState,1,-1,-1)' use "debug.traceback" as err.hdlr
This line actually executes the script. Again, if it's return value is <> 0, an error occurred. If everything worked though, the program will display a "Hello World!", as intended.
Calling BlitzMax functions from Lua
editBasics
editAs you may have noticed, being able only to run a script but not to interact with BlitzMax isn't extraordinarily useful. Therefore the next step consists of learning how to call a BlitzMax function from a Lua script. Unfortunately we can't just use an arbitrary function, as the function has to follow a specific layout:
Function BMXName:int (LuaState:Byte Ptr) ... ' handling of parameters passed from Lua (if required) ... ' actual function body ... ' passing results back to Lua (if required) return 0 ' number of values returned to Lua function End Function
Obviously, the arguments submitted with the function in the Lua script aren't directly transmitted to the BlitzMax function. We'll have to handle them manually, but not right away. First we have to register the function to Lua:
lua_register(LuaState, "luaname", BMXName)
BMXName() can now be called from Lua (globally) as luaname(). You may choose to name your functions the same as in BlitzMax, but you don't have to.
Handling parameters from Lua
editLet's say we've tried to call
luaname(810, "Hallo!")
from Lua using the example function above. Lua didn't complain about the additional parameters but we're not able to access them from within the function, either. Where have they gone? Lua has placed them onto the parameter stack. Each parameter is assigned an index through which it can be identified. The indices are consecutively numbered and begin with 1. Thus, 810 can be found at index 1 and "Hallo!" at index 2. Now we just need to know the respective commands to read the values from the parameter stack and we're done:
Function BMXName:Int (LuaState:Byte Ptr) Local int_value:Int = luaL_checkinteger(LuaState, 1) Local str_value:String = luaL_checkstring(LuaState, 2) Print int_value Print str_value Return 0 ' number of values returned to Lua function End Function
Returning Values to Lua
editReturning one or several values to the Lua script works similarly, but you don't have to specify indices as values are automatically appended to the stack. Here's an example:
Function BMXName:Int (LuaState:Byte Ptr) lua_pushnumber(LuaState, 810) lua_pushstring(LuaState, "Hallo!") Return 2 ' number of values returned to Lua function End Function
In most cases you'll be returning only one or no value at all, but as shown, more are possible, too.
Calling single Lua functions from BlitzMax
editWe know how to execute whole Lua scripts, but what if we only need a single function? In that case, you first have to put the function to be called onto the stack, then the parameters. Here's an example. Lua Script:
function luafunc(para, str) print(para, str) end
BlitzMax Code:
lua_getfield(LuaState, LUA_GLOBALSINDEX, "luafunc") 'Puts the function onto the stack lua_pushinteger(LuaState, 810) 'First Argument lua_pushstring(LuaState, "Hallo!") 'Second Argument lua_call(LuaState, 2, 0) 'Call the function with 2 arguments and no result
Returned values, if any, are placed onto the stack after the function was executed.
Accessing Lua Globals from BlitzMax
editDefining or changing a global variable
editlua_pushstring(LuaState, "Hallo!") lua_setglobal (LuaState, "luaglobal")
The first command writes "Hallo!" onto the Stack and the second puts it into the global luaglobal.
Reading a global variable
editlua_getglobal(LuaState, "luaglobal") Local str:String = lua_tostring(LuaState, -1)
The first command puts the value onto the stack, the second puts it into the BlitzMax variable.
Accessing all global variables
editIf you want to save the current status of your Lua VM, you need to find a way to get all global variables. One way to do this is using the lua_next function:
lua_pushnil(LuaState) ' first key While (lua_next(LuaState, LUA_GLOBALSINDEX) <> 0) ' iterate through all values of the global environment table ' uses 'key' (at index -2) and 'value' (at index -1) Print(lua_typename(LuaState,lua_type(LuaState , - 1))+" - "+lua_tostring(LuaState,-2)+"-"+lua_tostring(LuaState,-1)) ' removes 'value'; keeps 'key' for next iteration lua_pop(LuaState, 1); Wend
Note that this method returns not only global variables, but also functions, tables, etc. which you need to sort out using the lua_type command.