maxlua.bmx 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490
  1. Strict
  2. Rem
  3. bbdoc: System/Lua scripting
  4. End Rem
  5. Module BRL.MaxLua
  6. ModuleInfo "Version: 1.00"
  7. ModuleInfo "License: zlib/libpng"
  8. ModuleInfo "Copyright: Blitz Research Ltd"
  9. ModuleInfo "Author: Mark Sibly"
  10. ModuleInfo "Modserver: BRL"
  11. ModuleInfo "History: 1.00"
  12. Import Pub.Lua
  13. Import BRL.Reflection
  14. Import "lua_object.c"
  15. Private
  16. Extern
  17. Function lua_boxobject( L:Byte Ptr,obj:Object )
  18. Function lua_unboxobject:Object( L:Byte Ptr,index )
  19. Function lua_pushlightobject( L:Byte Ptr,obj:Object )
  20. Function lua_tolightobject:Object( L:Byte Ptr,index )
  21. Function lua_gcobject:Int( L:Byte Ptr )
  22. End Extern
  23. Function LuaState:Byte Ptr(reset:Int = False)
  24. Global _luaState:Byte Ptr
  25. If reset And _luaState Then
  26. lua_close(_luaState)
  27. _luaState = Null
  28. End If
  29. If Not _luaState
  30. _luaState=luaL_newstate()
  31. luaL_openlibs _luaState
  32. EndIf
  33. Return _luaState
  34. End Function
  35. Function LuaRegInt( name:String,value )
  36. lua_pushinteger LuaState(),value
  37. lua_setfield LuaState(),LUA_GLOBALSINDEX,name
  38. End Function
  39. Function LuaRegFunc( name:String,value:Byte Ptr )
  40. lua_pushcclosure LuaState(),value,0
  41. lua_setfield LuaState(),LUA_GLOBALSINDEX,name
  42. End Function
  43. Function LuaDumpErr()
  44. WriteStdout "ERROR~n"
  45. WriteStdout lua_tostring( LuaState(),-1 )
  46. End Function
  47. Function Invoke( L:Byte Ptr )
  48. Local obj:Object=lua_unboxobject( L,LUA_GLOBALSINDEX-1 )
  49. Local meth:TMethod=TMethod( lua_tolightobject( L,LUA_GLOBALSINDEX-2 ) )
  50. Local tys:TTypeId[]=meth.ArgTypes(),args:Object[tys.length]
  51. For Local i=0 Until args.length
  52. Select tys[i]
  53. Case IntTypeId, ShortTypeId, ByteTypeId
  54. args[i]=String.FromInt( Int(lua_tointeger( L,i+1 )) )
  55. Case LongTypeId
  56. args[i]=String.FromLong( lua_tointeger( L,i+1 ) )
  57. Case FloatTypeId
  58. args[i]=String.FromFloat( Float(lua_tonumber( L,i+1 )) )
  59. Case DoubleTypeId
  60. args[i]=String.FromDouble( lua_tonumber( L,i+1 ) )
  61. Case StringTypeId
  62. args[i]=lua_tostring( L,i+1 )
  63. Default
  64. If lua_isnil(L, i + 1)
  65. 'correctly pass null
  66. args[i] = null
  67. ElseIf lua_isuserdata(L, i + 1)
  68. 'got valid data to unbox
  69. Local obj:object = lua_unboxobject(L, i + 1)
  70. 'invalid object
  71. If not obj
  72. Throw "MaxLua - Invoke(): "+meth.name()+"() got broken param #"+i+" (expected ~q"+tys[i].name()+"~q, got ~qNULL~q)."
  73. 'given param derives from requested param type
  74. ElseIf TTypeID.ForObject(obj).ExtendsType(tys[i])
  75. args[i] = obj
  76. Else
  77. Throw "MaxLua - Invoke(): "+meth.name()+"() got broken param #"+i+" (expected ~q"+tys[i].name()+"~q, got ~q"+TTypeID.ForObject(obj).name()+"~q)."
  78. EndIf
  79. Else
  80. 'something "non object" got passed
  81. Throw "MaxLua - Invoke(): "+meth.name()+"() got broken param #"+i+" (expected ~q"+tys[i].name()+"~q)."
  82. EndIf
  83. End Select
  84. Next
  85. Local t:Object=meth.Invoke( obj,args )
  86. Select meth.ReturnType()
  87. Case IntTypeId, ShortTypeId, ByteTypeId, LongTypeId
  88. lua_pushinteger L,t.ToString().ToInt()
  89. Case FloatTypeId
  90. lua_pushnumber L,t.ToString().ToFloat()
  91. Case DoubleTypeId
  92. lua_pushnumber L,t.ToString().ToDouble()
  93. Case StringTypeId
  94. Local s:String=t.ToString()
  95. lua_pushlstring L,s,s.length
  96. Default
  97. lua_pushobject L,t
  98. End Select
  99. Return 1
  100. End Function
  101. Function Index( L:Byte Ptr )
  102. Local obj:Object=lua_unboxobject( L,1 )
  103. Local typeId:TTypeId=TTypeId.ForObject( obj )
  104. Local ident:String=lua_tostring( L,2 )
  105. Local mth:TMethod=typeId.FindMethod( ident )
  106. If mth
  107. lua_pushvalue L,1
  108. lua_pushlightobject L,mth
  109. lua_pushcclosure L,Invoke,2
  110. Return True
  111. EndIf
  112. Local fld:TField=typeId.FindField( ident )
  113. If fld
  114. Select fld.TypeId() ' BaH - added more types
  115. Case IntTypeId, ShortTypeId, ByteTypeId, LongTypeId
  116. lua_pushinteger L,fld.GetInt( obj )
  117. Case FloatTypeId
  118. lua_pushnumber L,fld.GetFloat( obj )
  119. Case DoubleTypeId
  120. lua_pushnumber L,fld.GetDouble( obj )
  121. Case StringTypeId
  122. Local t:String=fld.GetString( obj )
  123. lua_pushlstring L,t,t.length
  124. Default
  125. lua_pushobject L,fld.Get( obj )
  126. End Select
  127. Return True
  128. EndIf
  129. End Function
  130. Function NewIndex( L:Byte Ptr )
  131. Local obj:Object=lua_unboxobject( L,1 )
  132. Local typeId:TTypeId=TTypeId.ForObject( obj )
  133. Local ident:String=lua_tostring( L,2 )
  134. Local mth:TMethod=typeId.FindMethod( ident )
  135. If mth
  136. Throw "ERROR"
  137. EndIf
  138. Local fld:TField=typeId.FindField( ident )
  139. If fld
  140. Select fld.TypeId()
  141. Case IntTypeId, ShortTypeId, ByteTypeId
  142. fld.SetInt obj,Int(lua_tointeger( L,3 ))
  143. Case LongTypeId
  144. fld.SetLong obj,lua_tointeger( L,3 )
  145. Case FloatTypeId
  146. fld.SetFloat obj,Float(lua_tonumber( L,3 ))
  147. Case DoubleTypeId
  148. fld.SetDouble obj,lua_tonumber( L,3 )
  149. Case StringTypeId
  150. fld.SetString obj,lua_tostring( L,3 )
  151. Default
  152. fld.Set obj,lua_unboxobject( L,3 )
  153. End Select
  154. Return True
  155. EndIf
  156. End Function
  157. Function IndexObject( L:Byte Ptr )
  158. If Index( L ) Return 1
  159. End Function
  160. Function NewIndexObject( L:Byte Ptr )
  161. If NewIndex( L ) Return
  162. Throw "ERROR"
  163. End Function
  164. Function IndexSelf( L:Byte Ptr )
  165. lua_getfield( L,1,"super" )
  166. lua_replace L,1
  167. If Index( L ) Return 1
  168. lua_remove L,1
  169. lua_gettable L,LUA_GLOBALSINDEX
  170. Return 1
  171. End Function
  172. Function NewIndexSelf( L:Byte Ptr )
  173. lua_rawset L,1
  174. End Function
  175. Function ObjMetaTable()
  176. Global _objMetaTable,done
  177. If Not done
  178. lua_newtable LuaState()
  179. lua_pushcfunction LuaState(),lua_gcobject
  180. lua_setfield LuaState(),-2,"__gc"
  181. lua_pushcfunction LuaState(),IndexObject
  182. lua_setfield LuaState(),-2,"__index"
  183. lua_pushcfunction LuaState(),NewIndexObject
  184. lua_setfield LuaState(),-2,"__newindex"
  185. _objMetaTable=luaL_ref( LuaState(),LUA_REGISTRYINDEX )
  186. done=True
  187. EndIf
  188. Return _objMetaTable
  189. End Function
  190. Function lua_pushobject( L:Byte Ptr,obj:Object )
  191. lua_boxobject L,obj
  192. lua_rawgeti L,LUA_REGISTRYINDEX,ObjMetaTable()
  193. lua_setmetatable L,-2
  194. End Function
  195. ' create a table and load with array contents
  196. Function lua_pusharray( L:Byte Ptr,obj:Object )
  197. Local typeId:TTypeId=TTypeId.ForObject( obj )
  198. Local size:Int = typeId.ArrayLength(obj)
  199. lua_createtable L,size,0
  200. For Local i:Int = 0 Until size
  201. ' the index
  202. lua_pushinteger L, i
  203. Select typeId.ElementType()
  204. Case IntTypeId, ShortTypeId, ByteTypeId, LongTypeId
  205. lua_pushinteger L, typeId.GetArrayElement(obj, i).ToString().ToInt()
  206. Case FloatTypeId
  207. lua_pushnumber L, typeId.GetArrayElement(obj, i).ToString().ToFloat()
  208. Case DoubleTypeId
  209. lua_pushnumber L, typeId.GetArrayElement(obj, i).ToString().ToDouble()
  210. Case StringTypeId
  211. Local s:String = typeId.GetArrayElement(obj, i).ToString()
  212. lua_pushlstring L, s, s.length
  213. Case ArrayTypeId
  214. lua_pusharray(L, typeId.GetArrayElement(obj, i))
  215. Default ' for everything else, we just push the object..
  216. lua_pushobject L, typeId.GetArrayElement(obj, i)
  217. End Select
  218. lua_settable L, -3
  219. Next
  220. End Function
  221. Function lua_registerobject( L:Byte Ptr,obj:Object,name:String )
  222. lua_pushobject L,obj
  223. lua_setglobal L,name
  224. End Function
  225. Type TDummyLuaSuper
  226. End Type
  227. Global DummyLuaSuper:TDummyLuaSuper=New TDummyLuaSuper
  228. Public
  229. Rem
  230. bbdoc: A Lua 'object'
  231. End Rem
  232. Type TLuaObject
  233. Rem
  234. bbdoc: Initialize the lua object
  235. about:
  236. Sets the object's class and super object.
  237. If the object was created with the TLuaObject.Create function, you do not need to call
  238. this method.
  239. End Rem
  240. Method Init:TLuaObject( class:TLuaClass,supr:Object )
  241. Local L:Byte Ptr=LuaState()
  242. 'Currently needs a super object
  243. If Not supr supr=DummyLuaSuper
  244. 'push class block
  245. If Not class.lua_pushchunk() Return
  246. 'create fenv table
  247. lua_newtable L
  248. 'saveit
  249. lua_pushvalue L,-1
  250. _fenv=luaL_ref( L,LUA_REGISTRYINDEX )
  251. _class=class
  252. If supr
  253. 'set self/super object
  254. lua_pushvalue L,-1
  255. lua_setfield L,-2,"self"
  256. lua_pushobject L,supr
  257. lua_setfield L,-2,"super"
  258. 'set meta indices
  259. lua_pushcfunction L,IndexSelf
  260. lua_setfield L,-2,"__index"
  261. lua_pushcfunction L,NewIndexSelf
  262. lua_setfield L,-2,"__newindex"
  263. EndIf
  264. 'set fenv metatable
  265. lua_pushvalue L,-1
  266. lua_setmetatable L,-2
  267. 'ready!
  268. lua_setfenv L,-2
  269. If lua_pcall( L,0,0,0 ) LuaDumpErr
  270. Return Self
  271. End Method
  272. Rem
  273. bbdoc: Invoke an object method
  274. about:
  275. @name should refer to a function within the object's classes' source code.
  276. End Rem
  277. Method Invoke:Object( name:String,args:Object[] )
  278. Local L:Byte Ptr=LuaState()
  279. lua_pushfenv
  280. lua_getfield L,-1,name
  281. If lua_isnil( L,-1 )
  282. lua_pop L,2
  283. Return
  284. EndIf
  285. For Local i=0 Until args.length
  286. Local typeId:TTypeId=TTypeId.ForObject( args[i] )
  287. Select typeId
  288. Case IntTypeId, ShortTypeId, ByteTypeId, LongTypeId
  289. lua_pushinteger L, args[i].ToString().ToInt()
  290. Case FloatTypeId
  291. lua_pushnumber L, args[i].ToString().ToFloat()
  292. Case DoubleTypeId
  293. lua_pushnumber L, args[i].ToString().ToDouble()
  294. Case StringTypeId
  295. Local s:String = args[i].ToString()
  296. lua_pushlstring L,s,s.length
  297. Case ArrayTypeId
  298. lua_pusharray(L, args[i])
  299. Default
  300. lua_pushobject L,args[i]
  301. End Select
  302. Next
  303. If lua_pcall( L,args.length,1,0 ) LuaDumpErr
  304. Local ret:Object
  305. If Not lua_isnil( L,-1 ) Then
  306. ' TODO: returning arrays from tables might be nice!
  307. ret = lua_tostring( L, -1 )
  308. End If
  309. ' pop the result
  310. lua_pop L,1
  311. ' pop the fenv ?
  312. lua_pop L,1
  313. Return ret
  314. End Method
  315. Rem
  316. bbdoc: Create a lua object
  317. about:
  318. Once a lua object has been created, object methods (actually lua functions defined in the
  319. class) can be invoked using the #Invoke method.
  320. End Rem
  321. Function Create:TLuaObject( class:TLuaClass,supr:Object )
  322. Return New TLuaObject.Init( class,supr )
  323. End Function
  324. Method lua_pushfenv()
  325. Local L:Byte Ptr=LuaState()
  326. lua_rawgeti L,LUA_REGISTRYINDEX,_fenv
  327. End Method
  328. Method Delete()
  329. Local L:Byte Ptr=LuaState()
  330. luaL_unref L,LUA_REGISTRYINDEX,_fenv
  331. End Method
  332. Field _fenv
  333. Field _class:TLuaClass
  334. End Type
  335. Rem
  336. bbdoc: A Lua 'class'
  337. about:
  338. The TLuaClass type is used to contain lua source code.
  339. The source code should consist of a series of one or more lua functions.
  340. To actually invoke these functions a lua object must first be created - see #TLuaObject.
  341. End Rem
  342. Type TLuaClass
  343. Rem
  344. bbdoc: Get source code
  345. returns: The lua source code for the class.
  346. End Rem
  347. Method SourceCode:String()
  348. Return _source
  349. End Method
  350. Rem
  351. bbdoc: Set source code
  352. about:
  353. Sets the class source code.
  354. If the class was created with the TLuaClass.Create function, you do not need to call this
  355. method.
  356. End Rem
  357. Method SetSourceCode:TLuaClass( source:String )
  358. Local L:Byte Ptr=LuaState()
  359. _source=source
  360. If _chunk
  361. luaL_unref L,LUA_REGISTRYINDEX,_chunk
  362. _chunk=0
  363. EndIf
  364. Return Self
  365. End Method
  366. Rem
  367. bbdoc: Create a lua class
  368. returns: A new lua class object.
  369. about:
  370. The @source parameter must be valid Lua source code, and should contain a series of one or
  371. more lua function definitions.
  372. These functions can later be invoked by using the TLuaObject.Invoke method.
  373. End Rem
  374. Function Create:TLuaClass( source:String )
  375. Return New TLuaClass.SetSourceCode( source )
  376. End Function
  377. Method lua_pushchunk()
  378. Local L:Byte Ptr=LuaState()
  379. If Not _chunk
  380. If luaL_loadstring( L,_source )
  381. WriteStdout "Error loading script :~n" + lua_tostring( L,-1 ) + "~n"
  382. lua_pop L,1
  383. Return False
  384. EndIf
  385. _chunk=luaL_ref( L,LUA_REGISTRYINDEX )
  386. EndIf
  387. lua_rawgeti L,LUA_REGISTRYINDEX,_chunk
  388. Return True
  389. End Method
  390. Method Delete()
  391. Local L:Byte Ptr=LuaState()
  392. luaL_unref L,LUA_REGISTRYINDEX,_chunk
  393. End Method
  394. Field _source:String
  395. Field _chunk
  396. End Type
  397. Rem
  398. bbdoc: Register a global object with Lua
  399. about:
  400. Once registered, the object can be accessed from within Lua scripts using the @name identifer.
  401. End Rem
  402. Function LuaRegisterObject( obj:Object,name:String )
  403. lua_registerobject LuaState(),obj,name
  404. End Function
  405. Function LuaDeregisterObject(name:String)
  406. lua_pushnil(LuaState())
  407. lua_setglobal(LuaState(), name)
  408. End Function
  409. Function LuaShutdown()
  410. LuaState(True)
  411. End Function