123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490 |
- Strict
- Rem
- bbdoc: System/Lua scripting
- End Rem
- Module BRL.MaxLua
- ModuleInfo "Version: 1.00"
- ModuleInfo "License: zlib/libpng"
- ModuleInfo "Copyright: Blitz Research Ltd"
- ModuleInfo "Author: Mark Sibly"
- ModuleInfo "Modserver: BRL"
- ModuleInfo "History: 1.00"
- Import Pub.Lua
- Import BRL.Reflection
- Import "lua_object.c"
- Private
- Extern
- Function lua_boxobject( L:Byte Ptr,obj:Object )
- Function lua_unboxobject:Object( L:Byte Ptr,index )
- Function lua_pushlightobject( L:Byte Ptr,obj:Object )
- Function lua_tolightobject:Object( L:Byte Ptr,index )
- Function lua_gcobject:Int( L:Byte Ptr )
- End Extern
- Function LuaState:Byte Ptr(reset:Int = False)
- Global _luaState:Byte Ptr
- If reset And _luaState Then
- lua_close(_luaState)
- _luaState = Null
- End If
- If Not _luaState
- _luaState=luaL_newstate()
- luaL_openlibs _luaState
- EndIf
- Return _luaState
- End Function
- Function LuaRegInt( name:String,value )
- lua_pushinteger LuaState(),value
- lua_setfield LuaState(),LUA_GLOBALSINDEX,name
- End Function
- Function LuaRegFunc( name:String,value:Byte Ptr )
- lua_pushcclosure LuaState(),value,0
- lua_setfield LuaState(),LUA_GLOBALSINDEX,name
- End Function
- Function LuaDumpErr()
- WriteStdout "ERROR~n"
- WriteStdout lua_tostring( LuaState(),-1 )
- End Function
- Function Invoke( L:Byte Ptr )
- Local obj:Object=lua_unboxobject( L,LUA_GLOBALSINDEX-1 )
- Local meth:TMethod=TMethod( lua_tolightobject( L,LUA_GLOBALSINDEX-2 ) )
- Local tys:TTypeId[]=meth.ArgTypes(),args:Object[tys.length]
- For Local i=0 Until args.length
- Select tys[i]
- Case IntTypeId, ShortTypeId, ByteTypeId
- args[i]=String.FromInt( Int(lua_tointeger( L,i+1 )) )
- Case LongTypeId
- args[i]=String.FromLong( lua_tointeger( L,i+1 ) )
- Case FloatTypeId
- args[i]=String.FromFloat( Float(lua_tonumber( L,i+1 )) )
- Case DoubleTypeId
- args[i]=String.FromDouble( lua_tonumber( L,i+1 ) )
- Case StringTypeId
- args[i]=lua_tostring( L,i+1 )
- Default
- If lua_isnil(L, i + 1)
- 'correctly pass null
- args[i] = null
- ElseIf lua_isuserdata(L, i + 1)
- 'got valid data to unbox
- Local obj:object = lua_unboxobject(L, i + 1)
- 'invalid object
- If not obj
- Throw "MaxLua - Invoke(): "+meth.name()+"() got broken param #"+i+" (expected ~q"+tys[i].name()+"~q, got ~qNULL~q)."
- 'given param derives from requested param type
- ElseIf TTypeID.ForObject(obj).ExtendsType(tys[i])
- args[i] = obj
- Else
- Throw "MaxLua - Invoke(): "+meth.name()+"() got broken param #"+i+" (expected ~q"+tys[i].name()+"~q, got ~q"+TTypeID.ForObject(obj).name()+"~q)."
- EndIf
- Else
- 'something "non object" got passed
- Throw "MaxLua - Invoke(): "+meth.name()+"() got broken param #"+i+" (expected ~q"+tys[i].name()+"~q)."
- EndIf
- End Select
- Next
- Local t:Object=meth.Invoke( obj,args )
- Select meth.ReturnType()
- Case IntTypeId, ShortTypeId, ByteTypeId, LongTypeId
- lua_pushinteger L,t.ToString().ToInt()
- Case FloatTypeId
- lua_pushnumber L,t.ToString().ToFloat()
- Case DoubleTypeId
- lua_pushnumber L,t.ToString().ToDouble()
- Case StringTypeId
- Local s:String=t.ToString()
- lua_pushlstring L,s,s.length
- Default
- lua_pushobject L,t
- End Select
- Return 1
- End Function
- Function Index( L:Byte Ptr )
- Local obj:Object=lua_unboxobject( L,1 )
- Local typeId:TTypeId=TTypeId.ForObject( obj )
- Local ident:String=lua_tostring( L,2 )
-
- Local mth:TMethod=typeId.FindMethod( ident )
- If mth
- lua_pushvalue L,1
- lua_pushlightobject L,mth
- lua_pushcclosure L,Invoke,2
- Return True
- EndIf
-
- Local fld:TField=typeId.FindField( ident )
- If fld
- Select fld.TypeId() ' BaH - added more types
- Case IntTypeId, ShortTypeId, ByteTypeId, LongTypeId
- lua_pushinteger L,fld.GetInt( obj )
- Case FloatTypeId
- lua_pushnumber L,fld.GetFloat( obj )
- Case DoubleTypeId
- lua_pushnumber L,fld.GetDouble( obj )
- Case StringTypeId
- Local t:String=fld.GetString( obj )
- lua_pushlstring L,t,t.length
- Default
- lua_pushobject L,fld.Get( obj )
- End Select
- Return True
- EndIf
- End Function
- Function NewIndex( L:Byte Ptr )
- Local obj:Object=lua_unboxobject( L,1 )
- Local typeId:TTypeId=TTypeId.ForObject( obj )
- Local ident:String=lua_tostring( L,2 )
- Local mth:TMethod=typeId.FindMethod( ident )
- If mth
- Throw "ERROR"
- EndIf
-
- Local fld:TField=typeId.FindField( ident )
- If fld
- Select fld.TypeId()
- Case IntTypeId, ShortTypeId, ByteTypeId
- fld.SetInt obj,Int(lua_tointeger( L,3 ))
- Case LongTypeId
- fld.SetLong obj,lua_tointeger( L,3 )
- Case FloatTypeId
- fld.SetFloat obj,Float(lua_tonumber( L,3 ))
- Case DoubleTypeId
- fld.SetDouble obj,lua_tonumber( L,3 )
- Case StringTypeId
- fld.SetString obj,lua_tostring( L,3 )
- Default
- fld.Set obj,lua_unboxobject( L,3 )
- End Select
- Return True
- EndIf
- End Function
- Function IndexObject( L:Byte Ptr )
- If Index( L ) Return 1
- End Function
- Function NewIndexObject( L:Byte Ptr )
- If NewIndex( L ) Return
- Throw "ERROR"
- End Function
- Function IndexSelf( L:Byte Ptr )
- lua_getfield( L,1,"super" )
- lua_replace L,1
- If Index( L ) Return 1
- lua_remove L,1
- lua_gettable L,LUA_GLOBALSINDEX
- Return 1
- End Function
- Function NewIndexSelf( L:Byte Ptr )
- lua_rawset L,1
- End Function
- Function ObjMetaTable()
- Global _objMetaTable,done
- If Not done
- lua_newtable LuaState()
- lua_pushcfunction LuaState(),lua_gcobject
- lua_setfield LuaState(),-2,"__gc"
- lua_pushcfunction LuaState(),IndexObject
- lua_setfield LuaState(),-2,"__index"
- lua_pushcfunction LuaState(),NewIndexObject
- lua_setfield LuaState(),-2,"__newindex"
- _objMetaTable=luaL_ref( LuaState(),LUA_REGISTRYINDEX )
- done=True
- EndIf
- Return _objMetaTable
- End Function
- Function lua_pushobject( L:Byte Ptr,obj:Object )
- lua_boxobject L,obj
- lua_rawgeti L,LUA_REGISTRYINDEX,ObjMetaTable()
- lua_setmetatable L,-2
- End Function
- ' create a table and load with array contents
- Function lua_pusharray( L:Byte Ptr,obj:Object )
- Local typeId:TTypeId=TTypeId.ForObject( obj )
- Local size:Int = typeId.ArrayLength(obj)
-
- lua_createtable L,size,0
-
- For Local i:Int = 0 Until size
-
- ' the index
- lua_pushinteger L, i
-
- Select typeId.ElementType()
- Case IntTypeId, ShortTypeId, ByteTypeId, LongTypeId
- lua_pushinteger L, typeId.GetArrayElement(obj, i).ToString().ToInt()
- Case FloatTypeId
- lua_pushnumber L, typeId.GetArrayElement(obj, i).ToString().ToFloat()
- Case DoubleTypeId
- lua_pushnumber L, typeId.GetArrayElement(obj, i).ToString().ToDouble()
- Case StringTypeId
- Local s:String = typeId.GetArrayElement(obj, i).ToString()
- lua_pushlstring L, s, s.length
- Case ArrayTypeId
- lua_pusharray(L, typeId.GetArrayElement(obj, i))
- Default ' for everything else, we just push the object..
- lua_pushobject L, typeId.GetArrayElement(obj, i)
- End Select
-
- lua_settable L, -3
- Next
-
- End Function
- Function lua_registerobject( L:Byte Ptr,obj:Object,name:String )
- lua_pushobject L,obj
- lua_setglobal L,name
- End Function
- Type TDummyLuaSuper
- End Type
- Global DummyLuaSuper:TDummyLuaSuper=New TDummyLuaSuper
- Public
- Rem
- bbdoc: A Lua 'object'
- End Rem
- Type TLuaObject
- Rem
- bbdoc: Initialize the lua object
- about:
- Sets the object's class and super object.
-
- If the object was created with the TLuaObject.Create function, you do not need to call
- this method.
- End Rem
- Method Init:TLuaObject( class:TLuaClass,supr:Object )
- Local L:Byte Ptr=LuaState()
-
- 'Currently needs a super object
- If Not supr supr=DummyLuaSuper
- 'push class block
- If Not class.lua_pushchunk() Return
-
- 'create fenv table
- lua_newtable L
-
- 'saveit
- lua_pushvalue L,-1
- _fenv=luaL_ref( L,LUA_REGISTRYINDEX )
- _class=class
-
- If supr
- 'set self/super object
- lua_pushvalue L,-1
- lua_setfield L,-2,"self"
- lua_pushobject L,supr
- lua_setfield L,-2,"super"
- 'set meta indices
- lua_pushcfunction L,IndexSelf
- lua_setfield L,-2,"__index"
- lua_pushcfunction L,NewIndexSelf
- lua_setfield L,-2,"__newindex"
- EndIf
-
- 'set fenv metatable
- lua_pushvalue L,-1
- lua_setmetatable L,-2
-
- 'ready!
- lua_setfenv L,-2
- If lua_pcall( L,0,0,0 ) LuaDumpErr
-
- Return Self
- End Method
- Rem
- bbdoc: Invoke an object method
- about:
- @name should refer to a function within the object's classes' source code.
- End Rem
- Method Invoke:Object( name:String,args:Object[] )
- Local L:Byte Ptr=LuaState()
-
- lua_pushfenv
- lua_getfield L,-1,name
- If lua_isnil( L,-1 )
- lua_pop L,2
- Return
- EndIf
- For Local i=0 Until args.length
- Local typeId:TTypeId=TTypeId.ForObject( args[i] )
- Select typeId
- Case IntTypeId, ShortTypeId, ByteTypeId, LongTypeId
- lua_pushinteger L, args[i].ToString().ToInt()
- Case FloatTypeId
- lua_pushnumber L, args[i].ToString().ToFloat()
- Case DoubleTypeId
- lua_pushnumber L, args[i].ToString().ToDouble()
- Case StringTypeId
- Local s:String = args[i].ToString()
- lua_pushlstring L,s,s.length
- Case ArrayTypeId
- lua_pusharray(L, args[i])
- Default
- lua_pushobject L,args[i]
- End Select
- Next
- If lua_pcall( L,args.length,1,0 ) LuaDumpErr
-
-
- Local ret:Object
- If Not lua_isnil( L,-1 ) Then
- ' TODO: returning arrays from tables might be nice!
- ret = lua_tostring( L, -1 )
- End If
- ' pop the result
- lua_pop L,1
-
- ' pop the fenv ?
- lua_pop L,1
-
- Return ret
- End Method
-
- Rem
- bbdoc: Create a lua object
- about:
- Once a lua object has been created, object methods (actually lua functions defined in the
- class) can be invoked using the #Invoke method.
- End Rem
- Function Create:TLuaObject( class:TLuaClass,supr:Object )
- Return New TLuaObject.Init( class,supr )
- End Function
-
- Method lua_pushfenv()
- Local L:Byte Ptr=LuaState()
- lua_rawgeti L,LUA_REGISTRYINDEX,_fenv
- End Method
-
- Method Delete()
- Local L:Byte Ptr=LuaState()
- luaL_unref L,LUA_REGISTRYINDEX,_fenv
- End Method
-
-
- Field _fenv
- Field _class:TLuaClass
- End Type
- Rem
- bbdoc: A Lua 'class'
- about:
- The TLuaClass type is used to contain lua source code.
- The source code should consist of a series of one or more lua functions.
- To actually invoke these functions a lua object must first be created - see #TLuaObject.
- End Rem
- Type TLuaClass
- Rem
- bbdoc: Get source code
- returns: The lua source code for the class.
- End Rem
- Method SourceCode:String()
- Return _source
- End Method
- Rem
- bbdoc: Set source code
- about:
- Sets the class source code.
- If the class was created with the TLuaClass.Create function, you do not need to call this
- method.
- End Rem
- Method SetSourceCode:TLuaClass( source:String )
- Local L:Byte Ptr=LuaState()
- _source=source
- If _chunk
- luaL_unref L,LUA_REGISTRYINDEX,_chunk
- _chunk=0
- EndIf
- Return Self
- End Method
- Rem
- bbdoc: Create a lua class
- returns: A new lua class object.
- about:
- The @source parameter must be valid Lua source code, and should contain a series of one or
- more lua function definitions.
-
- These functions can later be invoked by using the TLuaObject.Invoke method.
- End Rem
- Function Create:TLuaClass( source:String )
- Return New TLuaClass.SetSourceCode( source )
- End Function
-
- Method lua_pushchunk()
- Local L:Byte Ptr=LuaState()
- If Not _chunk
- If luaL_loadstring( L,_source )
- WriteStdout "Error loading script :~n" + lua_tostring( L,-1 ) + "~n"
- lua_pop L,1
- Return False
- EndIf
- _chunk=luaL_ref( L,LUA_REGISTRYINDEX )
- EndIf
- lua_rawgeti L,LUA_REGISTRYINDEX,_chunk
- Return True
- End Method
-
- Method Delete()
- Local L:Byte Ptr=LuaState()
- luaL_unref L,LUA_REGISTRYINDEX,_chunk
- End Method
-
- Field _source:String
- Field _chunk
- End Type
- Rem
- bbdoc: Register a global object with Lua
- about:
- Once registered, the object can be accessed from within Lua scripts using the @name identifer.
- End Rem
- Function LuaRegisterObject( obj:Object,name:String )
- lua_registerobject LuaState(),obj,name
- End Function
- Function LuaDeregisterObject(name:String)
- lua_pushnil(LuaState())
- lua_setglobal(LuaState(), name)
- End Function
- Function LuaShutdown()
- LuaState(True)
- End Function
|