Code archives/Miscellaneous/Lua-Scriptable Type
This code has been declared by its author to be Public Domain code.
Download source code
| |||||
This is sort of a rudimentary example of using LuGI to bind Lua functions to objects in Lua. It could be expanded upon (e.g., binding closures for different messages and such), but it works well enough for the sake of example. Speaking of examples, here's some code and a script to accompany it: woop.bmx woop.lua Bear in mind that this requires the most recent version of LuGI's master branch, since I added a handy method for binding glue functions to types. This was already possible, it just required you to be aware of the private API, which seems like a bad idea to me since it's only documented in the headers. | |||||
SuperStrict ?Debug Import LuGI.Generator ? Import LuGI.Core Include "scriptable_glue.bmx" 'LUGI_CATEGORIES="scriptable" 'GenerateGlueCode("scriptable_glue.bmx") 'End Type Scriptable {expose disablenew category="scriptable"} Field _state@Ptr Field _closures%=-2 Method Delete() Dispose End Method Method Init:Scriptable(state@Ptr) {hidden} _state = state lua_newtable(state) _closures = luaL_ref(state, LUA_REGISTRYINDEX) Return Self End Method Method GetScriptFunc:Int(L@Ptr, name$) Assert L=_state Else "Invalid Lua state for scriptable object" If _closures = -1 Then Return False EndIf lua_rawgeti(L, LUA_REGISTRYINDEX, _closures) '-1=table lua_pushstring(L, name) '-2=table,-1=name lua_gettable(L, -2) '-2=table,-1=value If lua_isfunction(L, -1) Then lua_remove(L, -2) '-1=value Return True Else lua_pop(L, 2) 'clear Return False EndIf End Method Method Dispose() If _state And _closures <> -2 Then If GetScriptFunc(_state, "Dispose") Then lua_pushbmaxobject(_state, Self) lua_pcall(_state, 1, 0, 0) EndIf luaL_unref(_state, LUA_REGISTRYINDEX, _closures) _closures = -2 EndIf End Method Method ToString$() Return "Scriptable" End Method End Type 'metadata isn't used since there's currently no way to use reflection to grab it for functions anyway Function l_Scriptable_SetScript%(L@Ptr) {bindto="Scriptable" as="SetScript"} Local so:Scriptable If lua_gettop(L) <> 3 Then lua_pushstring(L, "Invalid number of arguments to SetScript - expected 3, got "+lua_gettop(L)) lua_error(L) EndIf luaL_argcheck(L, lua_isbmaxobject(L, 1) And (Not lua_isnoneornil(L, 1)), 1, "must be a subclass of the Scriptable type") luaL_argcheck(L, lua_isstring(L, 2), 2, "must be a string naming the routine added to the object") luaL_argcheck(L, lua_isfunction(L, 3) Or lua_isnil(L, 3), 3, "must be a function or nil") so = Scriptable(lua_tobmaxobject(L, 1)) If Not so Then luaL_argerror(L, 1, "must be a subclass of the Scriptable type") EndIf If so._closures <> -2 Then lua_rawgeti(L, LUA_REGISTRYINDEX, so._closures) lua_insert(L, -3) lua_settable(L, -3) EndIf End Function Function l_Scriptable_GetScript%(L@Ptr) Local so:Scriptable luaL_argcheck(L, lua_isbmaxobject(L, 1) And (Not lua_isnoneornil(L, 1)), 1, "must be a subclass of the Scriptable type") so = Scriptable(lua_tobmaxobject(L, 1)) If Not so Then luaL_argerror(L, 1, "must be a subclass of the Scriptable type") EndIf Local args:Int = lua_gettop(L) For Local i:Int = 2 To args luaL_argcheck(L, lua_isstring(L, i), i, "must be a string naming a requested routine") If Not so.GetScriptFunc(L, lua_tostring(L, i)) Then lua_pushnil(L) EndIf Next Return args-1 End Function BindFunctionToType(l_Scriptable_SetScript, "SetScript", TTypeID.ForName("Scriptable")) BindFunctionToType(l_Scriptable_GetScript, "GetScript", TTypeID.ForName("Scriptable")) |
Comments
| ||
Thanks for all the stuff you've posted to do with Lua. It's helping me to understand the language and how to implement it in BlitzMax a lot. |
| ||
Updated this to make it slightly more versatile (and probably usable for whatever you wanted now). You can now assign functions with names, so you could have an "Update" routine, a "ReceiveHitDamage" routine, etc. Also fixed a bug from when I forgot to use SuperStrict - LUA_NOREF is apparently undefined. Odd, but it's just -2, so I changed it out. |
Code Archives Forum