maxlua.bmx 10 KB

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