/* * This file is part of LuaInterface. * * Copyright (C) 2003-2005 Fabio Mascarenhas de Queiroz. * Copyright (C) 2012 Megax * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ using System; using System.IO; using System.Threading; using System.Reflection; using System.Collections; using System.Collections.Generic; using System.Collections.Specialized; using LuaInterface.Event; namespace LuaInterface { /* * Main class of LuaInterface * Object-oriented wrapper to Lua API * * Author: Fabio Mascarenhas * Version: 1.0 * * // steffenj: important changes in Lua class: * - removed all Open*Lib() functions * - all libs automatically open in the Lua class constructor (just assign nil to unwanted libs) * */ [CLSCompliant(true)] public class Lua : IDisposable { static string init_luanet = "local metatable = {} \n"+ "local import_type = luanet.import_type \n"+ "local load_assembly = luanet.load_assembly \n"+ " \n"+ "-- Lookup a .NET identifier component. \n"+ "function metatable:__index(key) -- key is e.g. \"Form\" \n"+ " -- Get the fully-qualified name, e.g. \"System.Windows.Forms.Form\" \n"+ " local fqn = ((rawget(self,\".fqn\") and rawget(self,\".fqn\") .. \n"+ " \".\") or \"\") .. key \n"+ " \n"+ " -- Try to find either a luanet function or a CLR type \n"+ " local obj = rawget(luanet,key) or import_type(fqn) \n"+ " \n"+ " -- If key is neither a luanet function or a CLR type, then it is simply \n"+ " -- an identifier component. \n"+ " if obj == nil then \n"+ " -- It might be an assembly, so we load it too. \n"+ " load_assembly(fqn) \n"+ " obj = { [\".fqn\"] = fqn } \n"+ " setmetatable(obj, metatable) \n"+ " end \n"+ " \n"+ " -- Cache this lookup \n"+ " rawset(self, key, obj) \n"+ " return obj \n"+ "end \n"+ " \n"+ "-- A non-type has been called; e.g. foo = System.Foo() \n"+ "function metatable:__call(...) \n"+ " error(\"No such type: \" .. rawget(self,\".fqn\"), 2) \n"+ "end \n"+ " \n"+ "-- This is the root of the .NET namespace \n"+ "luanet[\".fqn\"] = false \n"+ "setmetatable(luanet, metatable) \n"+ " \n"+ "-- Preload the mscorlib assembly \n"+ "luanet.load_assembly(\"mscorlib\") \n"; private /*readonly */ KopiLua.Lua.lua_State luaState; private ObjectTranslator translator; private KopiLua.Lua.lua_CFunction panicCallback; /// /// Used to ensure multiple .net threads all get serialized by this single lock for access to the lua stack/objects /// private object luaLock = new object(); public Lua() { luaState = KopiLua.Lua.luaL_newstate(); // steffenj: Lua 5.1.1 API change (lua_open is gone) //KopiLua.Lua.luaopen_base(luaState); // steffenj: luaopen_* no longer used KopiLua.Lua.luaL_openlibs(luaState); // steffenj: Lua 5.1.1 API change (luaopen_base is gone, just open all libs right here) KopiLua.Lua.lua_pushstring(luaState, "LUAINTERFACE LOADED"); KopiLua.Lua.lua_pushboolean(luaState, 1); KopiLua.Lua.lua_settable(luaState, (int)PseudoIndex.Registry); KopiLua.Lua.lua_newtable(luaState); KopiLua.Lua.lua_setglobal(luaState, "luanet"); KopiLua.Lua.lua_pushvalue(luaState, (int)PseudoIndex.Globals); KopiLua.Lua.lua_getglobal(luaState, "luanet"); KopiLua.Lua.lua_pushstring(luaState, "getmetatable"); KopiLua.Lua.lua_getglobal(luaState, "getmetatable"); KopiLua.Lua.lua_settable(luaState, -3); KopiLua.Lua.lua_replace(luaState, (int)PseudoIndex.Globals); translator=new ObjectTranslator(this,luaState); KopiLua.Lua.lua_replace(luaState, (int)PseudoIndex.Globals); LuaLib.luaL_dostring(luaState, Lua.init_luanet); // steffenj: lua_dostring renamed to luaL_dostring // We need to keep this in a managed reference so the delegate doesn't get garbage collected panicCallback = new KopiLua.Lua.lua_CFunction(PanicCallback); KopiLua.Lua.lua_atpanic(luaState, panicCallback); //KopiLua.Lua.lua_atlock(luaState, lockCallback = new KopiLua.Lua.lua_CFunction(LockCallback)); //KopiLua.Lua.lua_atunlock(luaState, unlockCallback = new KopiLua.Lua.lua_CFunction(UnlockCallback)); } private bool _StatePassed; /* * CAUTION: LuaInterface.Lua instances can't share the same lua state! */ public Lua(KopiLua.Lua.lua_State luaState) { KopiLua.Lua.lua_State lState = luaState; KopiLua.Lua.lua_pushstring(lState, "LUAINTERFACE LOADED"); KopiLua.Lua.lua_gettable(lState, (int)PseudoIndex.Registry); if(KopiLua.Lua.lua_toboolean(lState,-1).ToBoolean()) { KopiLua.Lua.lua_settop(lState,-2); throw new LuaException("There is already a LuaInterface.Lua instance associated with this Lua state"); } else { KopiLua.Lua.lua_settop(lState,-2); KopiLua.Lua.lua_pushstring(lState, "LUAINTERFACE LOADED"); KopiLua.Lua.lua_pushboolean(lState, 1); KopiLua.Lua.lua_settable(lState, (int)PseudoIndex.Registry); this.luaState=lState; KopiLua.Lua.lua_pushvalue(lState, (int)PseudoIndex.Globals); KopiLua.Lua.lua_getglobal(lState, "luanet"); KopiLua.Lua.lua_pushstring(lState, "getmetatable"); KopiLua.Lua.lua_getglobal(lState, "getmetatable"); KopiLua.Lua.lua_settable(lState, -3); KopiLua.Lua.lua_replace(lState, (int)PseudoIndex.Globals); translator=new ObjectTranslator(this, this.luaState); KopiLua.Lua.lua_replace(lState, (int)PseudoIndex.Globals); LuaLib.luaL_dostring(lState, Lua.init_luanet); // steffenj: lua_dostring renamed to luaL_dostring } _StatePassed = true; } /// /// Called for each lua_lock call /// /// /// Not yet used int LockCallback(KopiLua.Lua.lua_State luaState) { // Monitor.Enter(luaLock); return 0; } /// /// Called for each lua_unlock call /// /// /// Not yet used int UnlockCallback(KopiLua.Lua.lua_State luaState) { // Monitor.Exit(luaLock); return 0; } public void Close() { if (_StatePassed) return; ////// if (luaState != KopiLua.Lua.lua_State.Zero) if (luaState != null) KopiLua.Lua.lua_close(luaState); //luaState = KopiLua.Lua.lua_State.Zero; <- suggested by Christopher Cebulski http://luaforge.net/forum/forum.php?thread_id=44593&forum_id=146 } static int PanicCallback(KopiLua.Lua.lua_State luaState) { // string desc = KopiLua.Lua.lua_tostring(luaState, 1); string reason = String.Format("unprotected error in call to Lua API ({0})", KopiLua.Lua.lua_tostring(luaState, -1)); // lua_tostring(L, -1); throw new LuaException(reason); } /// /// Assuming we have a Lua error string sitting on the stack, throw a C# exception out to the user's app /// /// Thrown if the script caused an exception void ThrowExceptionFromError(int oldTop) { object err = translator.getObject(luaState, -1); KopiLua.Lua.lua_settop(luaState, oldTop); // A pre-wrapped exception - just rethrow it (stack trace of InnerException will be preserved) LuaScriptException luaEx = err as LuaScriptException; if (luaEx != null) throw luaEx; // A non-wrapped Lua error (best interpreted as a string) - wrap it and throw it if (err == null) err = "Unknown Lua Error"; throw new LuaScriptException(err.ToString(), ""); } /// /// Convert C# exceptions into Lua errors /// /// num of things on stack /// null for no pending exception internal int SetPendingException(Exception e) { Exception caughtExcept = e; if (caughtExcept != null) { translator.throwError(luaState, caughtExcept); KopiLua.Lua.lua_pushnil(luaState); return 1; } else return 0; } private bool executing; /// /// True while a script is being executed /// public bool IsExecuting { get { return executing; } } /// /// /// /// /// /// public LuaFunction LoadString(string chunk, string name) { int oldTop = KopiLua.Lua.lua_gettop(luaState); executing = true; try { if (LuaLib.luaL_loadbuffer(luaState, chunk, name) != 0) ThrowExceptionFromError(oldTop); } finally { executing = false; } LuaFunction result = translator.getFunction(luaState, -1); translator.popValues(luaState, oldTop); return result; } /// /// /// /// /// public LuaFunction LoadFile(string fileName) { int oldTop = KopiLua.Lua.lua_gettop(luaState); if (KopiLua.Lua.luaL_loadfile(luaState, fileName) != 0) ThrowExceptionFromError(oldTop); LuaFunction result = translator.getFunction(luaState, -1); translator.popValues(luaState, oldTop); return result; } /* * Excutes a Lua chunk and returns all the chunk's return * values in an array */ public object[] DoString(string chunk) { int oldTop=KopiLua.Lua.lua_gettop(luaState); if (LuaLib.luaL_loadbuffer(luaState, chunk, "chunk") == 0) { executing = true; try { if (KopiLua.Lua.lua_pcall(luaState, 0, -1, 0) == 0) return translator.popValues(luaState, oldTop); else ThrowExceptionFromError(oldTop); } finally { executing = false; } } else ThrowExceptionFromError(oldTop); return null; // Never reached - keeps compiler happy } /// /// Executes a Lua chnk and returns all the chunk's return values in an array. /// /// Chunk to execute /// Name to associate with the chunk /// public object[] DoString(string chunk, string chunkName) { int oldTop = KopiLua.Lua.lua_gettop(luaState); executing = true; if (LuaLib.luaL_loadbuffer(luaState, chunk, chunkName) == 0) { try { if (KopiLua.Lua.lua_pcall(luaState, 0, -1, 0) == 0) return translator.popValues(luaState, oldTop); else ThrowExceptionFromError(oldTop); } finally { executing = false; } } else ThrowExceptionFromError(oldTop); return null; // Never reached - keeps compiler happy } /* * Excutes a Lua file and returns all the chunk's return * values in an array */ public object[] DoFile(string fileName) { int oldTop=KopiLua.Lua.lua_gettop(luaState); if(KopiLua.Lua.luaL_loadfile(luaState,fileName)==0) { executing = true; try { if (KopiLua.Lua.lua_pcall(luaState, 0, -1, 0) == 0) return translator.popValues(luaState, oldTop); else ThrowExceptionFromError(oldTop); } finally { executing = false; } } else ThrowExceptionFromError(oldTop); return null; // Never reached - keeps compiler happy } /* * Indexer for global variables from the LuaInterpreter * Supports navigation of tables by using . operator */ public object this[string fullPath] { get { object returnValue=null; int oldTop=KopiLua.Lua.lua_gettop(luaState); string[] path=fullPath.Split(new char[] { '.' }); KopiLua.Lua.lua_getglobal(luaState,path[0]); returnValue=translator.getObject(luaState,-1); if(path.Length>1) { string[] remainingPath=new string[path.Length-1]; Array.Copy(path,1,remainingPath,0,path.Length-1); returnValue=getObject(remainingPath); } KopiLua.Lua.lua_settop(luaState,oldTop); return returnValue; } set { int oldTop=KopiLua.Lua.lua_gettop(luaState); string[] path=fullPath.Split(new char[] { '.' }); if(path.Length==1) { translator.push(luaState,value); KopiLua.Lua.lua_setglobal(luaState,fullPath); } else { KopiLua.Lua.lua_getglobal(luaState,path[0]); string[] remainingPath=new string[path.Length-1]; Array.Copy(path,1,remainingPath,0,path.Length-1); setObject(remainingPath,value); } KopiLua.Lua.lua_settop(luaState,oldTop); // Globals auto-complete if (value == null) { // Remove now obsolete entries globals.Remove(fullPath); } else { // Add new entries if (!globals.Contains(fullPath)) registerGlobal(fullPath, value.GetType(), 0); } } } #region Globals auto-complete private readonly List globals = new List(); private bool globalsSorted; /// /// An alphabetically sorted list of all globals (objects, methods, etc.) externally added to this Lua instance /// /// Members of globals are also listed. The formatting is optimized for text input auto-completion. public IEnumerable Globals { get { // Only sort list when necessary if (!globalsSorted) { globals.Sort(); globalsSorted = true; } return globals; } } /// /// Adds an entry to (recursivley handles 2 levels of members) /// /// The index accessor path ot the entry /// The type of the entry /// How deep have we gone with recursion? private void registerGlobal(string path, Type type, int recursionCounter) { // If the type is a global method, list it directly if (type == typeof(KopiLua.Lua.lua_CFunction)) { // Format for easy method invocation globals.Add(path + "("); } // If the type is a class or an interface and recursion hasn't been running too long, list the members else if ((type.IsClass || type.IsInterface) && type != typeof(string) && recursionCounter < 2) { #region Methods foreach (MethodInfo method in type.GetMethods(BindingFlags.Public | BindingFlags.Instance)) { if ( // Check that the LuaHideAttribute and LuaGlobalAttribute were not applied (method.GetCustomAttributes(typeof(LuaHideAttribute), false).Length == 0) && (method.GetCustomAttributes(typeof(LuaGlobalAttribute), false).Length == 0) && // Exclude some generic .NET methods that wouldn't be very usefull in Lua method.Name != "GetType" && method.Name != "GetHashCode" && method.Name != "Equals" && method.Name != "ToString" && method.Name != "Clone" && method.Name != "Dispose" && method.Name != "GetEnumerator" && method.Name != "CopyTo" && !method.Name.StartsWith("get_", StringComparison.Ordinal) && !method.Name.StartsWith("set_", StringComparison.Ordinal) && !method.Name.StartsWith("add_", StringComparison.Ordinal) && !method.Name.StartsWith("remove_", StringComparison.Ordinal)) { // Format for easy method invocation string command = path + ":" + method.Name + "("; if (method.GetParameters().Length == 0) command += ")"; globals.Add(command); } } #endregion #region Fields foreach (FieldInfo field in type.GetFields(BindingFlags.Public | BindingFlags.Instance)) { if ( // Check that the LuaHideAttribute and LuaGlobalAttribute were not applied (field.GetCustomAttributes(typeof(LuaHideAttribute), false).Length == 0) && (field.GetCustomAttributes(typeof(LuaGlobalAttribute), false).Length == 0)) { // Go into recursion for members registerGlobal(path + "." + field.Name, field.FieldType, recursionCounter + 1); } } #endregion #region Properties foreach (PropertyInfo property in type.GetProperties(BindingFlags.Public | BindingFlags.Instance)) { if ( // Check that the LuaHideAttribute and LuaGlobalAttribute were not applied (property.GetCustomAttributes(typeof(LuaHideAttribute), false).Length == 0) && (property.GetCustomAttributes(typeof(LuaGlobalAttribute), false).Length == 0) // Exclude some generic .NET properties that wouldn't be very usefull in Lua && property.Name != "Item") { // Go into recursion for members registerGlobal(path + "." + property.Name, property.PropertyType, recursionCounter + 1); } } #endregion } // Otherwise simply add the element to the list else globals.Add(path); // List will need to be sorted on next access globalsSorted = false; } #endregion /* * Navigates a table in the top of the stack, returning * the value of the specified field */ internal object getObject(string[] remainingPath) { object returnValue=null; for(int i=0;i /// lua hook calback delegate /// /// Reinhard Ostermeier private KopiLua.Lua.lua_Hook hookCallback = null; /// /// Activates the debug hook /// /// Mask /// Count /// see lua docs. -1 if hook is already set /// Reinhard Ostermeier /*public int SetDebugHook(EventMasks mask, int count) { if (hookCallback == null) { hookCallback = new KopiLua.Lua.lua_Hook(DebugHookCallback); return KopiLua.Lua.lua_sethook(luaState, hookCallback, (int)mask, count); } return -1; }*/ /// /// Removes the debug hook /// /// see lua docs /// Reinhard Ostermeier public int RemoveDebugHook() { hookCallback = null; return KopiLua.Lua.lua_sethook(luaState, null, 0, 0); } /// /// Gets the hook mask. /// /// hook mask /// Reinhard Ostermeier public EventMasks GetHookMask() { return (EventMasks)KopiLua.Lua.lua_gethookmask(luaState); } /// /// Gets the hook count /// /// see lua docs /// Reinhard Ostermeier public int GetHookCount() { return KopiLua.Lua.lua_gethookcount(luaState); } /// /// Gets the stack entry on a given level /// /// level /// lua debug structure /// Returns true if level was allowed, false if level was invalid. /// Reinhard Ostermeier /*public bool GetStack(int level, out LuaDebug luaDebug) { luaDebug = new LuaDebug(); KopiLua.Lua.lua_State ld = System.Runtime.InteropServices.Marshal.AllocHGlobal(System.Runtime.InteropServices.Marshal.SizeOf(luaDebug)); System.Runtime.InteropServices.Marshal.StructureToPtr(luaDebug, ld, false); try { return KopiLua.Lua.lua_getstack(luaState, level, ld) != 0; } finally { luaDebug = (LuaDebug)System.Runtime.InteropServices.Marshal.PtrToStructure(ld, typeof(LuaDebug)); System.Runtime.InteropServices.Marshal.FreeHGlobal(ld); } }*/ /// /// Gets info (see lua docs) /// /// what (see lua docs) /// lua debug structure /// see lua docs /// Reinhard Ostermeier /*public int GetInfo(String what, ref LuaDebug luaDebug) { KopiLua.Lua.lua_State ld = System.Runtime.InteropServices.Marshal.AllocHGlobal(System.Runtime.InteropServices.Marshal.SizeOf(luaDebug)); System.Runtime.InteropServices.Marshal.StructureToPtr(luaDebug, ld, false); try { return KopiLua.Lua.lua_getinfo(luaState, what, ld); } finally { luaDebug = (LuaDebug)System.Runtime.InteropServices.Marshal.PtrToStructure(ld, typeof(LuaDebug)); System.Runtime.InteropServices.Marshal.FreeHGlobal(ld); } }*/ /// /// Gets local (see lua docs) /// /// lua debug structure /// see lua docs /// see lua docs /// Reinhard Ostermeier /*public String GetLocal(LuaDebug luaDebug, int n) { KopiLua.Lua.lua_State ld = System.Runtime.InteropServices.Marshal.AllocHGlobal(System.Runtime.InteropServices.Marshal.SizeOf(luaDebug)); System.Runtime.InteropServices.Marshal.StructureToPtr(luaDebug, ld, false); try { return KopiLua.Lua.lua_getlocal(luaState, ld, n); } finally { System.Runtime.InteropServices.Marshal.FreeHGlobal(ld); } }*/ /// /// Sets local (see lua docs) /// /// lua debug structure /// see lua docs /// see lua docs /// Reinhard Ostermeier /*public String SetLocal(LuaDebug luaDebug, int n) { KopiLua.Lua.lua_State ld = System.Runtime.InteropServices.Marshal.AllocHGlobal(System.Runtime.InteropServices.Marshal.SizeOf(luaDebug)); System.Runtime.InteropServices.Marshal.StructureToPtr(luaDebug, ld, false); try { return KopiLua.Lua.lua_setlocal(luaState, ld, n); } finally { System.Runtime.InteropServices.Marshal.FreeHGlobal(ld); } }*/ /// /// Gets up value (see lua docs) /// /// see lua docs /// see lua docs /// see lua docs /// Reinhard Ostermeier public String GetUpValue(int funcindex, int n) { return KopiLua.Lua.lua_getupvalue(luaState, funcindex, n).ToString(); } /// /// Sets up value (see lua docs) /// /// see lua docs /// see lua docs /// see lua docs /// Reinhard Ostermeier public String SetUpValue(int funcindex, int n) { return KopiLua.Lua.lua_setupvalue(luaState, funcindex, n).ToString(); } /// /// Delegate that is called on lua hook callback /// /// lua state /// Pointer to LuaDebug (lua_debug) structure /// Reinhard Ostermeier /*private void DebugHookCallback(KopiLua.Lua.lua_State luaState, KopiLua.Lua.lua_Debug luaDebug) { try { LuaDebug ld = (LuaDebug)System.Runtime.InteropServices.Marshal.PtrToStructure(luaDebug, typeof(LuaDebug)); EventHandler temp = DebugHook; if (temp != null) { temp(this, new DebugHookEventArgs(ld)); } } catch (Exception ex) { OnHookException(new HookExceptionEventArgs(ex)); } }*/ /// /// Event that is raised when an exception occures during a hook call. /// /// Reinhard Ostermeier public event EventHandler HookException; private void OnHookException(HookExceptionEventArgs e) { EventHandler temp = HookException; if (temp != null) { temp(this, e); } } /// /// Event when lua hook callback is called /// /// /// Is only raised if SetDebugHook is called before. /// /// Reinhard Ostermeier public event EventHandler DebugHook; /// /// Pops a value from the lua stack. /// /// Returns the top value from the lua stack. /// Reinhard Ostermeier public object Pop() { int top = KopiLua.Lua.lua_gettop(luaState); return translator.popValues(luaState, top - 1)[0]; } /// /// Pushes a value onto the lua stack. /// /// Value to push. /// Reinhard Ostermeier public void Push(object value) { translator.push(luaState, value); } #endregion internal void dispose(int reference) { ///////////// if (luaState != KopiLua.Lua.lua_State.Zero) if (luaState != null) //Fix submitted by Qingrui Li LuaLib.lua_unref(luaState,reference); } /* * Gets a field of the table corresponding to the provided reference * using rawget (do not use metatables) */ internal object rawGetObject(int reference,string field) { int oldTop=KopiLua.Lua.lua_gettop(luaState); LuaLib.lua_getref(luaState,reference); KopiLua.Lua.lua_pushstring(luaState,field); KopiLua.Lua.lua_rawget(luaState,-2); object obj=translator.getObject(luaState,-1); KopiLua.Lua.lua_settop(luaState,oldTop); return obj; } /* * Gets a field of the table or userdata corresponding to the provided reference */ internal object getObject(int reference,string field) { int oldTop=KopiLua.Lua.lua_gettop(luaState); LuaLib.lua_getref(luaState,reference); object returnValue=getObject(field.Split(new char[] {'.'})); KopiLua.Lua.lua_settop(luaState,oldTop); return returnValue; } /* * Gets a numeric field of the table or userdata corresponding the the provided reference */ internal object getObject(int reference,object field) { int oldTop=KopiLua.Lua.lua_gettop(luaState); LuaLib.lua_getref(luaState,reference); translator.push(luaState,field); KopiLua.Lua.lua_gettable(luaState,-2); object returnValue=translator.getObject(luaState,-1); KopiLua.Lua.lua_settop(luaState,oldTop); return returnValue; } /* * Sets a field of the table or userdata corresponding the the provided reference * to the provided value */ internal void setObject(int reference, string field, object val) { int oldTop=KopiLua.Lua.lua_gettop(luaState); LuaLib.lua_getref(luaState,reference); setObject(field.Split(new char[] {'.'}),val); KopiLua.Lua.lua_settop(luaState,oldTop); } /* * Sets a numeric field of the table or userdata corresponding the the provided reference * to the provided value */ internal void setObject(int reference, object field, object val) { int oldTop=KopiLua.Lua.lua_gettop(luaState); LuaLib.lua_getref(luaState,reference); translator.push(luaState,field); translator.push(luaState,val); KopiLua.Lua.lua_settable(luaState,-3); KopiLua.Lua.lua_settop(luaState,oldTop); } /* * Registers an object's method as a Lua function (global or table field) * The method may have any signature */ 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) { // We leave nothing on the stack when we are done int oldTop = KopiLua.Lua.lua_gettop(luaState); LuaMethodWrapper wrapper=new LuaMethodWrapper(translator,target,function.DeclaringType,function); translator.push(luaState,new KopiLua.Lua.lua_CFunction(wrapper.call)); this[path]=translator.getObject(luaState,-1); LuaFunction f = GetFunction(path); KopiLua.Lua.lua_settop(luaState, oldTop); return f; } /* * Compares the two values referenced by ref1 and ref2 for equality */ internal bool compareRef(int ref1, int ref2) { int top=KopiLua.Lua.lua_gettop(luaState); LuaLib.lua_getref(luaState,ref1); LuaLib.lua_getref(luaState,ref2); int equal=KopiLua.Lua.lua_equal(luaState,-1,-2); KopiLua.Lua.lua_settop(luaState,top); return (equal!=0); } internal void pushCSFunction(KopiLua.Lua.lua_CFunction function) { translator.pushFunction(luaState,function); } #region IDisposable Members public virtual void Dispose() { if (translator != null) { translator.pendingEvents.Dispose(); translator = null; } this.Close(); System.GC.Collect(); System.GC.WaitForPendingFinalizers(); } #endregion } }