Lua.cs 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857
  1. #if UNITY_IPHONE
  2. #define __NOGEN__
  3. #endif
  4. namespace LuaInterface
  5. {
  6. using System;
  7. using System.IO;
  8. using System.Collections;
  9. using System.Collections.Generic;
  10. using System.Collections.Specialized;
  11. using System.Reflection;
  12. using System.Security;
  13. using System.Runtime.InteropServices;
  14. using System.Threading;
  15. using System.Text;
  16. public class LuaState : IDisposable
  17. {
  18. public IntPtr L;
  19. internal LuaCSFunction tracebackFunction;
  20. internal ObjectTranslator translator;
  21. internal LuaCSFunction panicCallback;
  22. public LuaState()
  23. {
  24. // Create State
  25. L = LuaDLL.luaL_newstate();
  26. // Create LuaInterface library
  27. LuaDLL.luaL_openlibs(L);
  28. LuaDLL.lua_pushstring(L, "LUAINTERFACE LOADED");
  29. LuaDLL.lua_pushboolean(L, true);
  30. LuaDLL.lua_settable(L, (int) LuaIndexes.LUA_REGISTRYINDEX);
  31. LuaDLL.lua_newtable(L);
  32. LuaDLL.lua_setglobal(L, "luanet");
  33. LuaDLL.lua_pushvalue(L, (int)LuaIndexes.LUA_GLOBALSINDEX);
  34. LuaDLL.lua_getglobal(L, "luanet");
  35. LuaDLL.lua_pushstring(L, "getmetatable");
  36. LuaDLL.lua_getglobal(L, "getmetatable");
  37. LuaDLL.lua_settable(L, -3);
  38. // Set luanet as global for object translator
  39. LuaDLL.lua_replace(L, (int)LuaIndexes.LUA_GLOBALSINDEX);
  40. translator = new ObjectTranslator(this,L);
  41. LuaDLL.lua_replace(L, (int)LuaIndexes.LUA_GLOBALSINDEX);
  42. GCHandle handle = GCHandle.Alloc(translator, GCHandleType.Pinned);
  43. IntPtr thisptr = GCHandle.ToIntPtr(handle);
  44. LuaDLL.lua_pushlightuserdata(L, thisptr);
  45. LuaDLL.lua_setglobal(L, "_translator");
  46. }
  47. public void Close()
  48. {
  49. if (L != IntPtr.Zero)
  50. {
  51. LuaDLL.lua_close(L);
  52. }
  53. }
  54. /// <summary>
  55. /// Assuming we have a Lua error string sitting on the stack, throw a C# exception out to the user's app
  56. /// </summary>
  57. /// <exception cref="LuaScriptException">Thrown if the script caused an exception</exception>
  58. public void ThrowExceptionFromError(int oldTop)
  59. {
  60. object err = translator.getObject(L, -1);
  61. LuaDLL.lua_settop(L, oldTop);
  62. // A pre-wrapped exception - just rethrow it (stack trace of InnerException will be preserved)
  63. LuaScriptException luaEx = err as LuaScriptException;
  64. if (luaEx != null) throw luaEx;
  65. // A non-wrapped Lua error (best interpreted as a string) - wrap it and throw it
  66. if (err == null) err = "Unknown Lua Error";
  67. throw new LuaScriptException(err.ToString(), "");
  68. }
  69. /// <summary>
  70. /// Convert C# exceptions into Lua errors
  71. /// </summary>
  72. /// <returns>num of things on stack</returns>
  73. /// <param name="e">null for no pending exception</param>
  74. internal int SetPendingException(Exception e)
  75. {
  76. Exception caughtExcept = e;
  77. if (caughtExcept != null)
  78. {
  79. translator.throwError(L, caughtExcept);
  80. LuaDLL.lua_pushnil(L);
  81. return 1;
  82. }
  83. else
  84. return 0;
  85. }
  86. /// <summary>
  87. ///
  88. /// </summary>
  89. /// <param name="chunk"></param>
  90. /// <param name="name"></param>
  91. /// <returns></returns>
  92. public LuaFunction LoadString(string chunk, string name, LuaTable env)
  93. {
  94. int oldTop = LuaDLL.lua_gettop(L);
  95. if (LuaDLL.luaL_loadbuffer(L, chunk, Encoding.UTF8.GetByteCount(chunk), name) != 0)
  96. ThrowExceptionFromError(oldTop);
  97. if (env != null)
  98. {
  99. env.push(L);
  100. LuaDLL.lua_setfenv(L, -2);
  101. }
  102. LuaFunction result = translator.getFunction(L, -1);
  103. translator.popValues(L, oldTop);
  104. return result;
  105. }
  106. public LuaFunction LoadString(string chunk, string name)
  107. {
  108. return LoadString(chunk, name, null);
  109. }
  110. /// <summary>
  111. ///
  112. /// </summary>
  113. /// <param name="fileName"></param>
  114. /// <returns></returns>
  115. protected LuaFunction LoadFile(string fileName)
  116. {
  117. int oldTop = LuaDLL.lua_gettop(L);
  118. if (LuaDLL.luaL_loadfile(L, fileName) != 0)
  119. ThrowExceptionFromError(oldTop);
  120. LuaFunction result = translator.getFunction(L, -1);
  121. translator.popValues(L, oldTop);
  122. return result;
  123. }
  124. /*
  125. * Excutes a Lua chunk and returns all the chunk's return
  126. * values in an array
  127. */
  128. public object[] DoString(string chunk)
  129. {
  130. return DoString(chunk,"chunk", null);
  131. }
  132. /// <summary>
  133. /// Executes a Lua chnk and returns all the chunk's return values in an array.
  134. /// </summary>
  135. /// <param name="chunk">Chunk to execute</param>
  136. /// <param name="chunkName">Name to associate with the chunk</param>
  137. /// <returns></returns>
  138. public object[] DoString(string chunk, string chunkName, LuaTable env)
  139. {
  140. int oldTop = LuaDLL.lua_gettop(L);
  141. if (LuaDLL.luaL_loadbuffer(L, chunk, Encoding.UTF8.GetByteCount(chunk), chunkName) == 0)
  142. {
  143. if (env != null)
  144. {
  145. env.push(L);
  146. //LuaDLL.lua_setfenv(L, -1);
  147. LuaDLL.lua_setfenv(L, -2);
  148. }
  149. if (LuaDLL.lua_pcall(L, 0, -1, 0) == 0)
  150. return translator.popValues(L, oldTop);
  151. else
  152. ThrowExceptionFromError(oldTop);
  153. }
  154. else
  155. ThrowExceptionFromError(oldTop);
  156. return null; // Never reached - keeps compiler happy
  157. }
  158. public object[] DoFile(string fileName)
  159. {
  160. return DoFile(fileName, null);
  161. }
  162. /*
  163. * Excutes a Lua file and returns all the chunk's return
  164. * values in an array
  165. */
  166. protected object[] DoFile(string fileName, LuaTable env)
  167. {
  168. LuaDLL.lua_pushstdcallcfunction(L,tracebackFunction);
  169. int oldTop = LuaDLL.lua_gettop(L);
  170. if (LuaDLL.luaL_loadfile(L, fileName) == 0)
  171. {
  172. try
  173. {
  174. if (LuaDLL.lua_pcall(L, 0, -1, -2) == 0)
  175. return translator.popValues(L, oldTop);
  176. else
  177. ThrowExceptionFromError(oldTop);
  178. }
  179. finally {}
  180. }
  181. else
  182. ThrowExceptionFromError(oldTop);
  183. return null; // Never reached - keeps compiler happy
  184. }
  185. /*
  186. * Indexer for global variables from the LuaInterpreter
  187. * Supports navigation of tables by using . operator
  188. */
  189. public object this[string fullPath]
  190. {
  191. get
  192. {
  193. object returnValue=null;
  194. int oldTop=LuaDLL.lua_gettop(L);
  195. string[] path=fullPath.Split(new char[] { '.' });
  196. LuaDLL.lua_getglobal(L,path[0]);
  197. returnValue=translator.getObject(L,-1);
  198. if(path.Length>1)
  199. {
  200. string[] remainingPath=new string[path.Length-1];
  201. Array.Copy(path,1,remainingPath,0,path.Length-1);
  202. returnValue=getObject(remainingPath);
  203. }
  204. LuaDLL.lua_settop(L,oldTop);
  205. return returnValue;
  206. }
  207. set
  208. {
  209. int oldTop=LuaDLL.lua_gettop(L);
  210. string[] path=fullPath.Split(new char[] { '.' });
  211. if(path.Length==1)
  212. {
  213. translator.push(L,value);
  214. LuaDLL.lua_setglobal(L,fullPath);
  215. }
  216. else
  217. {
  218. LuaDLL.lua_getglobal(L,path[0]);
  219. string[] remainingPath=new string[path.Length-1];
  220. Array.Copy(path,1,remainingPath,0,path.Length-1);
  221. setObject(remainingPath,value);
  222. }
  223. LuaDLL.lua_settop(L,oldTop);
  224. // Globals auto-complete
  225. if (value == null)
  226. {
  227. // Remove now obsolete entries
  228. globals.Remove(fullPath);
  229. }
  230. else
  231. {
  232. // Add new entries
  233. if (!globals.Contains(fullPath))
  234. registerGlobal(fullPath, value.GetType(), 0);
  235. }
  236. }
  237. }
  238. #region Globals auto-complete
  239. private readonly List<string> globals = new List<string>();
  240. private bool globalsSorted;
  241. /// <summary>
  242. /// An alphabetically sorted list of all globals (objects, methods, etc.) externally added to this Lua instance
  243. /// </summary>
  244. /// <remarks>Members of globals are also listed. The formatting is optimized for text input auto-completion.</remarks>
  245. public IEnumerable<string> Globals
  246. {
  247. get
  248. {
  249. // Only sort list when necessary
  250. if (!globalsSorted)
  251. {
  252. globals.Sort();
  253. globalsSorted = true;
  254. }
  255. return globals;
  256. }
  257. }
  258. /// <summary>
  259. /// Adds an entry to <see cref="globals"/> (recursivley handles 2 levels of members)
  260. /// </summary>
  261. /// <param name="path">The index accessor path ot the entry</param>
  262. /// <param name="type">The type of the entry</param>
  263. /// <param name="recursionCounter">How deep have we gone with recursion?</param>
  264. private void registerGlobal(string path, Type type, int recursionCounter)
  265. {
  266. // If the type is a global method, list it directly
  267. if (type == typeof(LuaCSFunction))
  268. {
  269. // Format for easy method invocation
  270. globals.Add(path + "(");
  271. }
  272. // If the type is a class or an interface and recursion hasn't been running too long, list the members
  273. else if ((type.IsClass || type.IsInterface) && type != typeof(string) && recursionCounter < 2)
  274. {
  275. #region Methods
  276. foreach (MethodInfo method in type.GetMethods(BindingFlags.Public | BindingFlags.Instance))
  277. {
  278. if (
  279. // Check that the LuaHideAttribute and LuaGlobalAttribute were not applied
  280. (method.GetCustomAttributes(typeof(LuaHideAttribute), false).Length == 0) &&
  281. (method.GetCustomAttributes(typeof(LuaGlobalAttribute), false).Length == 0) &&
  282. // Exclude some generic .NET methods that wouldn't be very usefull in Lua
  283. method.Name != "GetType" && method.Name != "GetHashCode" && method.Name != "Equals" &&
  284. method.Name != "ToString" && method.Name != "Clone" && method.Name != "Dispose" &&
  285. method.Name != "GetEnumerator" && method.Name != "CopyTo" &&
  286. !method.Name.StartsWith("get_", StringComparison.Ordinal) &&
  287. !method.Name.StartsWith("set_", StringComparison.Ordinal) &&
  288. !method.Name.StartsWith("add_", StringComparison.Ordinal) &&
  289. !method.Name.StartsWith("remove_", StringComparison.Ordinal))
  290. {
  291. // Format for easy method invocation
  292. string command = path + ":" + method.Name + "(";
  293. if (method.GetParameters().Length == 0) command += ")";
  294. globals.Add(command);
  295. }
  296. }
  297. #endregion
  298. #region Fields
  299. foreach (FieldInfo field in type.GetFields(BindingFlags.Public | BindingFlags.Instance))
  300. {
  301. if (
  302. // Check that the LuaHideAttribute and LuaGlobalAttribute were not applied
  303. (field.GetCustomAttributes(typeof(LuaHideAttribute), false).Length == 0) &&
  304. (field.GetCustomAttributes(typeof(LuaGlobalAttribute), false).Length == 0))
  305. {
  306. // Go into recursion for members
  307. registerGlobal(path + "." + field.Name, field.FieldType, recursionCounter + 1);
  308. }
  309. }
  310. #endregion
  311. #region Properties
  312. foreach (PropertyInfo property in type.GetProperties(BindingFlags.Public | BindingFlags.Instance))
  313. {
  314. if (
  315. // Check that the LuaHideAttribute and LuaGlobalAttribute were not applied
  316. (property.GetCustomAttributes(typeof(LuaHideAttribute), false).Length == 0) &&
  317. (property.GetCustomAttributes(typeof(LuaGlobalAttribute), false).Length == 0)
  318. // Exclude some generic .NET properties that wouldn't be very usefull in Lua
  319. && property.Name != "Item")
  320. {
  321. // Go into recursion for members
  322. registerGlobal(path + "." + property.Name, property.PropertyType, recursionCounter + 1);
  323. }
  324. }
  325. #endregion
  326. }
  327. // Otherwise simply add the element to the list
  328. else globals.Add(path);
  329. // List will need to be sorted on next access
  330. globalsSorted = false;
  331. }
  332. #endregion
  333. /*
  334. * Navigates a table in the top of the stack, returning
  335. * the value of the specified field
  336. */
  337. internal object getObject(string[] remainingPath)
  338. {
  339. object returnValue=null;
  340. for(int i=0;i<remainingPath.Length;i++)
  341. {
  342. LuaDLL.lua_pushstring(L,remainingPath[i]);
  343. LuaDLL.lua_gettable(L,-2);
  344. returnValue=translator.getObject(L,-1);
  345. if(returnValue==null) break;
  346. }
  347. return returnValue;
  348. }
  349. /*
  350. * Gets a numeric global variable
  351. */
  352. public double GetNumber(string fullPath)
  353. {
  354. return (double)this[fullPath];
  355. }
  356. /*
  357. * Gets a string global variable
  358. */
  359. public string GetString(string fullPath)
  360. {
  361. return (string)this[fullPath];
  362. }
  363. /*
  364. * Gets a table global variable
  365. */
  366. public LuaTable GetTable(string fullPath)
  367. {
  368. return (LuaTable)this[fullPath];
  369. }
  370. #if ! __NOGEN__
  371. /*
  372. * Gets a table global variable as an object implementing
  373. * the interfaceType interface
  374. */
  375. public object GetTable(Type interfaceType, string fullPath)
  376. {
  377. translator.throwError(L,"Tables as interfaces not implemnented");
  378. return CodeGeneration.Instance.GetClassInstance(interfaceType,GetTable(fullPath));
  379. }
  380. #endif
  381. /*
  382. * Gets a function global variable
  383. */
  384. public LuaFunction GetFunction(string fullPath)
  385. {
  386. object obj=this[fullPath];
  387. return (obj is LuaCSFunction ? new LuaFunction((LuaCSFunction)obj,this) : (LuaFunction)obj);
  388. }
  389. /*
  390. * Gets a function global variable as a delegate of
  391. * type delegateType
  392. */
  393. public Delegate GetFunction(Type delegateType,string fullPath)
  394. {
  395. #if __NOGEN__
  396. translator.throwError(L,"function delegates not implemnented");
  397. return null;
  398. #else
  399. return CodeGeneration.Instance.GetDelegate(delegateType,GetFunction(fullPath));
  400. #endif
  401. }
  402. /*
  403. * Calls the object as a function with the provided arguments,
  404. * returning the function's returned values inside an array
  405. */
  406. internal object[] callFunction(object function,object[] args)
  407. {
  408. return callFunction(function, args, null);
  409. }
  410. /*
  411. * Calls the object as a function with the provided arguments and
  412. * casting returned values to the types in returnTypes before returning
  413. * them in an array
  414. */
  415. internal object[] callFunction(object function,object[] args,Type[] returnTypes)
  416. {
  417. int nArgs=0;
  418. int oldTop=LuaDLL.lua_gettop(L);
  419. if(!LuaDLL.lua_checkstack(L,args.Length+6))
  420. throw new LuaException("Lua stack overflow");
  421. translator.push(L,function);
  422. if(args!=null)
  423. {
  424. nArgs=args.Length;
  425. for(int i=0;i<args.Length;i++)
  426. {
  427. translator.push(L,args[i]);
  428. }
  429. }
  430. int error = LuaDLL.lua_pcall(L, nArgs, -1, 0);
  431. if (error != 0)
  432. ThrowExceptionFromError(oldTop);
  433. if(returnTypes != null)
  434. return translator.popValues(L,oldTop,returnTypes);
  435. else
  436. return translator.popValues(L, oldTop);
  437. }
  438. /*
  439. * Navigates a table to set the value of one of its fields
  440. */
  441. internal void setObject(string[] remainingPath, object val)
  442. {
  443. for(int i=0; i<remainingPath.Length-1;i++)
  444. {
  445. LuaDLL.lua_pushstring(L,remainingPath[i]);
  446. LuaDLL.lua_gettable(L,-2);
  447. }
  448. LuaDLL.lua_pushstring(L,remainingPath[remainingPath.Length-1]);
  449. translator.push(L,val);
  450. LuaDLL.lua_settable(L,-3);
  451. }
  452. /*
  453. * Creates a new table as a global variable or as a field
  454. * inside an existing table
  455. */
  456. public void NewTable(string fullPath)
  457. {
  458. string[] path=fullPath.Split(new char[] { '.' });
  459. int oldTop=LuaDLL.lua_gettop(L);
  460. if(path.Length==1)
  461. {
  462. LuaDLL.lua_newtable(L);
  463. LuaDLL.lua_setglobal(L,fullPath);
  464. }
  465. else
  466. {
  467. LuaDLL.lua_getglobal(L,path[0]);
  468. for(int i=1; i<path.Length-1;i++)
  469. {
  470. LuaDLL.lua_pushstring(L,path[i]);
  471. LuaDLL.lua_gettable(L,-2);
  472. }
  473. LuaDLL.lua_pushstring(L,path[path.Length-1]);
  474. LuaDLL.lua_newtable(L);
  475. LuaDLL.lua_settable(L,-3);
  476. }
  477. LuaDLL.lua_settop(L,oldTop);
  478. }
  479. public LuaTable NewTable()
  480. {
  481. int oldTop=LuaDLL.lua_gettop(L);
  482. LuaDLL.lua_newtable(L);
  483. LuaTable returnVal = (LuaTable)translator.getObject(L,-1);
  484. LuaDLL.lua_settop(L,oldTop);
  485. return returnVal;
  486. }
  487. public ListDictionary GetTableDict(LuaTable table)
  488. {
  489. ListDictionary dict = new ListDictionary();
  490. int oldTop = LuaDLL.lua_gettop(L);
  491. translator.push(L, table);
  492. LuaDLL.lua_pushnil(L);
  493. while (LuaDLL.lua_next(L, -2) != 0)
  494. {
  495. dict[translator.getObject(L, -2)] = translator.getObject(L, -1);
  496. LuaDLL.lua_settop(L, -2);
  497. }
  498. LuaDLL.lua_settop(L, oldTop);
  499. return dict;
  500. }
  501. /*
  502. * Lets go of a previously allocated reference to a table, function
  503. * or userdata
  504. */
  505. internal void dispose(int reference)
  506. {
  507. if (L != IntPtr.Zero) //Fix submitted by Qingrui Li
  508. LuaDLL.lua_unref(L,reference);
  509. }
  510. /*
  511. * Gets a field of the table corresponding to the provided reference
  512. * using rawget (do not use metatables)
  513. */
  514. internal object rawGetObject(int reference,string field)
  515. {
  516. int oldTop=LuaDLL.lua_gettop(L);
  517. LuaDLL.lua_getref(L,reference);
  518. LuaDLL.lua_pushstring(L,field);
  519. LuaDLL.lua_rawget(L,-2);
  520. object obj=translator.getObject(L,-1);
  521. LuaDLL.lua_settop(L,oldTop);
  522. return obj;
  523. }
  524. /*
  525. * Gets a field of the table or userdata corresponding to the provided reference
  526. */
  527. internal object getObject(int reference,string field)
  528. {
  529. int oldTop=LuaDLL.lua_gettop(L);
  530. LuaDLL.lua_getref(L,reference);
  531. object returnValue=getObject(field.Split(new char[] {'.'}));
  532. LuaDLL.lua_settop(L,oldTop);
  533. return returnValue;
  534. }
  535. /*
  536. * Gets a numeric field of the table or userdata corresponding the the provided reference
  537. */
  538. internal object getObject(int reference,object field)
  539. {
  540. int oldTop=LuaDLL.lua_gettop(L);
  541. LuaDLL.lua_getref(L,reference);
  542. translator.push(L,field);
  543. LuaDLL.lua_gettable(L,-2);
  544. object returnValue=translator.getObject(L,-1);
  545. LuaDLL.lua_settop(L,oldTop);
  546. return returnValue;
  547. }
  548. /*
  549. * Sets a field of the table or userdata corresponding the the provided reference
  550. * to the provided value
  551. */
  552. internal void setObject(int reference, string field, object val)
  553. {
  554. int oldTop=LuaDLL.lua_gettop(L);
  555. LuaDLL.lua_getref(L,reference);
  556. setObject(field.Split(new char[] {'.'}),val);
  557. LuaDLL.lua_settop(L,oldTop);
  558. }
  559. /*
  560. * Sets a numeric field of the table or userdata corresponding the the provided reference
  561. * to the provided value
  562. */
  563. internal void setObject(int reference, object field, object val)
  564. {
  565. int oldTop=LuaDLL.lua_gettop(L);
  566. LuaDLL.lua_getref(L,reference);
  567. translator.push(L,field);
  568. translator.push(L,val);
  569. LuaDLL.lua_settable(L,-3);
  570. LuaDLL.lua_settop(L,oldTop);
  571. }
  572. /*
  573. * Registers an object's method as a Lua function (global or table field)
  574. * The method may have any signature
  575. */
  576. public LuaFunction RegisterFunction(string path, object target, MethodBase function /*MethodInfo function*/) //CP: Fix for struct constructor by Alexander Kappner (link: http://luaforge.net/forum/forum.php?thread_id=2859&forum_id=145)
  577. {
  578. // We leave nothing on the stack when we are done
  579. int oldTop = LuaDLL.lua_gettop(L);
  580. LuaMethodWrapper wrapper=new LuaMethodWrapper(translator,target,function.DeclaringType,function);
  581. translator.push(L,new LuaCSFunction(wrapper.call));
  582. this[path]=translator.getObject(L,-1);
  583. LuaFunction f = GetFunction(path);
  584. LuaDLL.lua_settop(L, oldTop);
  585. return f;
  586. }
  587. public LuaFunction CreateFunction(object target, MethodBase function /*MethodInfo function*/) //CP: Fix for struct constructor by Alexander Kappner (link: http://luaforge.net/forum/forum.php?thread_id=2859&forum_id=145)
  588. {
  589. // We leave nothing on the stack when we are done
  590. int oldTop = LuaDLL.lua_gettop(L);
  591. LuaMethodWrapper wrapper=new LuaMethodWrapper(translator,target,function.DeclaringType,function);
  592. translator.push(L,new LuaCSFunction(wrapper.call));
  593. object obj = translator.getObject(L,-1);
  594. LuaFunction f = (obj is LuaCSFunction ? new LuaFunction((LuaCSFunction)obj,this) : (LuaFunction)obj);
  595. LuaDLL.lua_settop(L, oldTop);
  596. return f;
  597. }
  598. /*
  599. * Compares the two values referenced by ref1 and ref2 for equality
  600. */
  601. internal bool compareRef(int ref1, int ref2)
  602. {
  603. int top=LuaDLL.lua_gettop(L);
  604. LuaDLL.lua_getref(L,ref1);
  605. LuaDLL.lua_getref(L,ref2);
  606. int equal=LuaDLL.lua_equal(L,-1,-2);
  607. LuaDLL.lua_settop(L,top);
  608. return (equal!=0);
  609. }
  610. internal void pushCSFunction(LuaCSFunction function)
  611. {
  612. translator.pushFunction(L,function);
  613. }
  614. #region IDisposable Members
  615. public void Dispose()
  616. {
  617. Dispose(true);
  618. System.GC.Collect();
  619. System.GC.WaitForPendingFinalizers();
  620. }
  621. public virtual void Dispose(bool dispose)
  622. {
  623. if( dispose )
  624. {
  625. if (translator != null)
  626. {
  627. translator.pendingEvents.Dispose();
  628. translator = null;
  629. }
  630. }
  631. }
  632. #endregion
  633. }
  634. public class LuaThread : LuaState
  635. {
  636. // Tracks if thread is running or not
  637. private bool start = false;
  638. // Keeps reference of thread in registry to prevent GC
  639. private int threadRef;
  640. // Hold on to parent for later
  641. private LuaState parent;
  642. // Func running on
  643. private LuaFunction func;
  644. public LuaThread( LuaState parentState, LuaFunction threadFunc )
  645. {
  646. // Copy from parent
  647. this.tracebackFunction = parentState.tracebackFunction;
  648. this.translator = parentState.translator;
  649. this.translator.interpreter = this;
  650. this.panicCallback = parentState.panicCallback;
  651. //this.printFunction = parentState.printFunction;
  652. //this.loadfileFunction = parentState.loadfileFunction;
  653. //this.loaderFunction = parentState.loaderFunction;
  654. //this.dofileFunction = parentState.dofileFunction;
  655. // Assign to store
  656. func = threadFunc;
  657. parent = parentState;
  658. // Create Thread
  659. L = LuaDLL.lua_newthread( parent.L );
  660. // Store thread in registry
  661. threadRef = LuaDLL.luaL_ref( parent.L, LuaIndexes.LUA_REGISTRYINDEX );
  662. }
  663. #region IDisposable Members
  664. public override void Dispose(bool dispose)
  665. {
  666. if( dispose )
  667. {
  668. LuaDLL.luaL_unref( parent.L, LuaIndexes.LUA_REGISTRYINDEX, threadRef );
  669. }
  670. }
  671. #endregion
  672. public void Start()
  673. {
  674. if(IsInactive() && !start)
  675. {
  676. start = true;
  677. }
  678. }
  679. public int Resume()
  680. {
  681. return Resume(null, null);
  682. }
  683. public int Resume(object[] args, LuaTable env)
  684. {
  685. int result = 0;
  686. int oldTop = LuaDLL.lua_gettop(L);
  687. // If thread isn't started, it needs to be restarted
  688. if( start )
  689. {
  690. start = false;
  691. func.push( L );
  692. if (env != null)
  693. {
  694. env.push(L);
  695. LuaDLL.lua_setfenv(L, -2);
  696. }
  697. result = resume(args, oldTop);
  698. }
  699. // If thread is suspended, resume it
  700. else if( IsSuspended() )
  701. {
  702. result = resume(args, oldTop);
  703. }
  704. return result;
  705. }
  706. private int resume(object[] args, int oldTop)
  707. {
  708. int nArgs=0;
  709. // Push args
  710. if(args!=null)
  711. {
  712. nArgs=args.Length;
  713. for(int i=0;i<args.Length;i++)
  714. {
  715. translator.push(L,args[i]);
  716. }
  717. }
  718. // Call func
  719. int r = 0;
  720. r = LuaDLL.lua_resume( L, nArgs );
  721. if( r > (int)LuaThreadStatus.LUA_YIELD )
  722. {
  723. // Error
  724. int top = LuaDLL.lua_gettop(L);
  725. ThrowExceptionFromError(top);
  726. }
  727. return r;
  728. }
  729. public bool IsStarted()
  730. {
  731. return start;
  732. }
  733. public bool IsSuspended()
  734. {
  735. int status = LuaDLL.lua_status( L );
  736. return (status == (int)LuaThreadStatus.LUA_YIELD);
  737. }
  738. public bool IsDead()
  739. {
  740. int status = LuaDLL.lua_status( L );
  741. return (status > (int)LuaThreadStatus.LUA_YIELD);
  742. }
  743. public bool IsInactive()
  744. {
  745. int status = LuaDLL.lua_status( L );
  746. return (status == 0);
  747. }
  748. }
  749. }