Beispiel #1
0
        private void pushObject(Object o)
        {
            GCHandle gch = GCHandle.Alloc(o);

            // Store the GCHandle so that it won't get garbage collected.
            mLuaReferences.Add(gch);

            // Push a userdata onto the stack (we don't care about the returned address)
            // This is needed because we cannot create a metatable for a lightuserdata.
            // So we make the light userdata a member of it's metatable.
            IntPtr p = LuaDll.lua_newuserdata(L, 8);

            // Write the IntPtr of the object handle to the userdata.
            Marshal.WriteIntPtr(p, GCHandle.ToIntPtr(gch));

            // Pushes the metatable of the given class onto the stack
            pushMetatable(o.GetType());

            // We should have a metatable of this object's class on the top of the stack.
            // Now register the object, which is below that (-2)
            // o.__metatable = mt
            LuaDll.lua_setmetatable(L, -2);

            // The exported object should now be on the top of the stack.
        }
Beispiel #2
0
        /// <summary>
        /// Returns the value at stack index i as a C# object.
        /// </summary>
        /// <param name="i">Index of object</param>
        /// <returns>Returns object at index i</returns>
        private object getValue(int i)
        {
            object result = null;

            int t = LuaDll.lua_type(L, i);

            switch (t)
            {
            case LuaDll.LUA_TSTRING:      /* strings */
                result = LuaDll.lua_tostring(L, i);
                break;

            case LuaDll.LUA_TBOOLEAN:      /* booleans */
                result = LuaDll.lua_toboolean(L, i);
                break;

            case LuaDll.LUA_TNUMBER:      /* numbers */
                result = LuaDll.lua_tonumber(L, i);
                break;

            case LuaDll.LUA_TUSERDATA:        /* user data */
                IntPtr p = LuaDll.lua_touserdata(L, i);
                result = GCHandle.FromIntPtr(Marshal.ReadIntPtr(p)).Target;
                break;

            default:      /* other values */
                Console.WriteLine("getValue({0}) : Unsupported type [{1}]", i, LuaDll.lua_typename(L, t));
                break;
            }

            return(result);
        }
Beispiel #3
0
        private int pushFunctionLut(System.Reflection.MethodInfo mi, string bindName)
        {
            int top = LuaDll.lua_gettop(L);

            // Push global lut to the stack
            string globalLutName = "__Lua.cs__LUT__";

            LuaDll.lua_getfield(L, LuaDll.LUA_REGISTRYINDEX, globalLutName);
            if (LuaDll.lua_isnil(L, -1))
            {
                // If the global lut does not exist then create it and push it onto the stack.

                // Pop the nil value
                LuaDll.lua_pop(L, 1);

                // Push a new table and set it as the global globalLutName
                LuaDll.lua_newtable(L);
                LuaDll.lua_pushvalue(L, -1);    // Dupe for setglobal call.
                LuaDll.lua_setfield(L, LuaDll.LUA_REGISTRYINDEX, globalLutName);
            }
            int lut = LuaDll.lua_gettop(L);

            Debug.Assert(lut == (top + 1));

            // Push function lut to the stack.
            string fullName = mi.ReflectedType.FullName + "." + bindName;

            LuaDll.lua_getfield(L, lut, fullName);

            if (LuaDll.lua_isnil(L, -1))
            {
                // If the function lut does not exist then create it.

                // Pop off the nil result.
                LuaDll.lua_pop(L, 1);

                // Push in a new table
                LuaDll.lua_newtable(L);

                // Add the name to the table as kFunctionNameKey
                LuaDll.lua_pushstring(L, bindName);
                LuaDll.lua_setfield(L, -2, kFunctionNameKey);

                // Add this to the global lut, keyed on FullName
                LuaDll.lua_pushvalue(L, -1);
                LuaDll.lua_setfield(L, lut, fullName);
            }

            // Remove the global lut
            LuaDll.lua_remove(L, lut);

            // Now we have the function lut at the top of the stack.
            int result = LuaDll.lua_gettop(L);

            Debug.Assert(result == top + 1);

            // Return the stack position of the lut.
            return(result);
        }
Beispiel #4
0
        /// <summary>
        /// Pushes the object v into the lua stack and returns the number of values that were pushed.
        /// If v is a MultiValue then it might push more than one value.
        /// Will automatically register the class of the object if not yet registered
        /// </summary>
        /// <param name="v">Object to push onto the stack</param>
        /// <returns></returns>
        private int pushValue(object v)
        {
            if (v == null)
            {
                return(0);
            }

            Type t = v.GetType();

            if (t == typeof(int))
            {
                LuaDll.lua_pushinteger(L, (int)v);
                return(1);
            }
            else if ((t == typeof(double)) || (t == typeof(float)))
            {
                LuaDll.lua_pushnumber(L, (double)v);
                return(1);
            }
            else if (t == typeof(string))
            {
                LuaDll.lua_pushstring(L, (string)v);
                return(1);
            }
            else if (t == typeof(bool))
            {
                LuaDll.lua_pushboolean(L, ((bool)v)?1:0);
                return(1);
            }
            else if (t == typeof(MultiValue))
            {
                // Special case to push multiple values onto the stack
                MultiValue mv     = (MultiValue)v;
                int        result = 0;

                for (int i = 0; i < mv.Length; ++i)
                {
                    // Since this is recursive, we could end up with arrays inside arrays.
                    // Should we catch that?
                    result += pushValue(mv[i]);
                }

                return(result);
            }
            else if (t.IsClass)
            {
                // If the is an object, then store a reference to it in the static
                // list of lua references.  It can be removed from this list once
                // lua is done with it.
                pushObject(v);
                return(1);
            }
            else
            {
                // Error, unexpected type, cannot push.
                Console.WriteLine("pushValue() Cannot push type [{0}]", t.FullName);
                return(0);
            }
        }
Beispiel #5
0
        private void registerFunctionAs(System.Reflection.MethodInfo mi, string name)
        {
            // Push the function delgate
            pushFunction(mi, name);

            // Set the function as a global in the lua scope with the same name.
            LuaDll.lua_setglobal(L, name);
        }
Beispiel #6
0
        public void registerObject(string name, Object o)
        {
            // Push the object onto the stack (this will also register the class as needed)
            pushObject(o);

            // Now set the object (which is now at the top of the stack) to be a global
            // with the given name.
            LuaDll.lua_setglobal(L, name);
        }
Beispiel #7
0
        private void registerClass(Type t)
        {
            string className = t.FullName;

            if (LuaDll.luaL_newmetatable(L, className) == 1)
            {
                int top = LuaDll.lua_gettop(L);

                Console.WriteLine("Registering class " + className);

                foreach (System.Reflection.MethodInfo mi in t.GetMethods())
                {
                    if (mi.IsPublic)
                    {
                        // Check that this method has been declared as bindable?
                        if (isBindable(mi))
                        {
                            // If the name is set, then bind using that name.
                            string bindName = getBindableName(mi, mi.Name);

                            // Push the method
                            pushFunction(mi, bindName);

                            // Set the pushed closure as a member of our table.
                            // The method should be at the top of the stack (-1), and the table below that (-2)
                            // mt[mi.Name] = method;
                            LuaDll.lua_setfield(L, -2, bindName);
                        }
                    }
                }

                // Register some luaisms
                // __gc
                LuaDll.lua_pushcfunction(L, mgcAdapterDelegate);
                LuaDll.lua_setfield(L, -2, "__gc");

                // __tostring
                LuaDll.lua_pushcfunction(L, mtostringAdapterDelegate);
                LuaDll.lua_setfield(L, -2, "__tostring");

                // __eq
                // Comparison operator
                LuaDll.lua_pushcfunction(L, meqAdapterDelegate);
                LuaDll.lua_setfield(L, -2, "__eq");

                LuaDll.lua_pushstring(L, "__index");    // Push "__index"
                LuaDll.lua_pushvalue(L, -2);            // Copy the metatable to the top of the stack
                LuaDll.lua_settable(L, -3);             // mt["__index"] = mt

                // metatable should be at top of stack.
                Debug.Assert(top == LuaDll.lua_gettop(L), "Top is wrong");
            }
        }
Beispiel #8
0
        /// <summary>
        /// Implementation of __tostring metamethod.
        /// Used to convert a userdata object to a string for printing.
        /// </summary>
        /// <param name="L">Lua state</param>
        /// <returns>Returns one string on the stack</returns>
        private int tostringAdapter(lua_State L)
        {
            // Get the object
            IntPtr   ud = LuaDll.lua_touserdata(L, 1);
            GCHandle gh = GCHandle.FromIntPtr(Marshal.ReadIntPtr(ud));

            // Generate the string result
            string result = String.Format("{0}: {1:X}", gh.Target.ToString(), ud.ToInt32());

            // Push the string and return it (return 1)
            LuaDll.lua_pushstring(L, result);
            return(1);
        }
Beispiel #9
0
        /// <summary>
        /// Implementation of __eq metamethod.
        /// This is used to compare two objects of the same type for equality.
        /// </summary>
        /// <param name="L">Lua state</param>
        /// <returns>Returns 0 on the stack if the arguments are not equal, 1 otherwise</returns>
        private int eqAdapter(lua_State L)
        {
            // Get the objects
            IntPtr   ud1 = LuaDll.lua_touserdata(L, 1);
            GCHandle gh1 = GCHandle.FromIntPtr(Marshal.ReadIntPtr(ud1));

            IntPtr   ud2 = LuaDll.lua_touserdata(L, 2);
            GCHandle gh2 = GCHandle.FromIntPtr(Marshal.ReadIntPtr(ud2));

            bool result = gh1.Target.Equals(gh2.Target);

            LuaDll.lua_pushboolean(L, result ? 1 : 0);

            return(1);
        }
Beispiel #10
0
        /// <summary>
        /// Implementation of __gc metamethod.
        /// Called when a userdata object is being released by the lua garbage collector.
        /// </summary>
        /// <param name="L">Lua state</param>
        /// <returns>Returns 0</returns>
        private int gcAdapter(lua_State L)
        {
            // Remove the referenced object from the global reference list so that
            // it can be cleaned up by the GC.
            IntPtr   ud = LuaDll.lua_touserdata(L, 1);
            GCHandle gh = GCHandle.FromIntPtr(Marshal.ReadIntPtr(ud));

            Console.WriteLine("[gcAdapter] - Releasing " + gh.Target.ToString());

            bool result = mLuaReferences.Remove(gh);

            Debug.Assert(result, "[gcAdapter] - garbage collector release object not in mLuaReferences");

            return(0);
        }
Beispiel #11
0
        public MultiValue dostring(string s)
        {
            int top = LuaDll.lua_gettop(L);
            int ret = LuaDll.luaL_dostring(L, s);

            if (ret != 0)
            {
                string err = LuaDll.lua_tostring(L, -1);
                Console.WriteLine("ERROR: " + err);
                LuaDll.lua_pop(L, 1);
            }
            else
            {
                int newtop = LuaDll.lua_gettop(L);
                return(getValues(top + 1, newtop - top));
            }

            return(null);
        }
Beispiel #12
0
        ///////////////////////////////////////////////////////////////////////
        /// <summary>
        /// Constructor - creates a new lua state.
        /// </summary>
        public LuaState()
        {
            mLuaFunctionCallAdapterDelegate = functionCallAdapter;
            mgcAdapterDelegate       = gcAdapter;
            mtostringAdapterDelegate = tostringAdapter;
            meqAdapterDelegate       = eqAdapter;

            L = LuaDll.luaL_newstate();
            LuaDll.luaL_openlibs(L);

            LuaDll.lua_atpanic(L, mPanicFunctionDelegate);

            // Redirect stderr from the Lua DLL to an error file.
            //FileStream fs = new FileStream("error.txt", FileMode.Create);
            //mOutputRef = new HandleRef(fs, fs.Handle);
            //SetStdHandle(-12, mOutputRef);

            // Install a new print function (to capture stdout)
            LuaDll.lua_register(L, "print", sLuaPrintDelegate);
        }
Beispiel #13
0
        private void pushFunction(System.Reflection.MethodInfo mi, string bindName)
        {
            int top = LuaDll.lua_gettop(L);

            // Generate unique name based on parameter list.
            string mangle = buildMangledNameFromMethodInfo(mi, bindName);

            // Push the Look Up Table for this function onto the Lua stack.
            int flut = pushFunctionLut(mi, bindName);

            // Lookup the manged name.
            LuaDll.lua_getfield(L, flut, mangle);

            // If not already defined then go ahead and define it
            if (LuaDll.lua_isnil(L, -1))
            {
                // Pop nil value
                LuaDll.lua_pop(L, 1);

                // Store the function in a GCHandle in a global list so it
                // doesn't get garbage collected.
                GCHandle h = GCHandle.Alloc(mi);
                mLuaReferences.Add(h);

                // functionLut[mangledName] = MethodInfo
                LuaDll.lua_pushlightuserdata(L, GCHandle.ToIntPtr(h));
                LuaDll.lua_setfield(L, flut, mangle);

                // Push the function call delegate with the function lut as an up value.
                LuaDll.lua_pushcclosure(L, mLuaFunctionCallAdapterDelegate, 1);
            }
            else
            {
                System.Reflection.MethodInfo oldMi = (System.Reflection.MethodInfo)GCHandle.FromIntPtr(LuaDll.lua_touserdata(L, -1)).Target;
                throw new Exception(String.Format("Duplicate function registration of '{0}', old={1}, new={2}", demangleName(mangle), oldMi, mi));
            }

            Debug.Assert(LuaDll.lua_gettop(L) == top + 1);
        }
Beispiel #14
0
        public void inspectClass(Object o)
        {
            int top = LuaDll.lua_gettop(L);

            // check if this class is registered and inspect the metatable
            LuaDll.luaL_getmetatable(L, o.GetType().FullName);
            if (LuaDll.lua_isnil(L, -1))
            {
                Console.WriteLine("inspectClass - metatable not found for class [{0}]", o.GetType().FullName);
                return;
            }

            Console.WriteLine("Inspecting {0}", o.GetType().FullName);

            /* table is in the stack at index 't' */
            int t = LuaDll.lua_gettop(L);

            LuaDll.lua_pushnil(L);  /* first key */
            while (LuaDll.lua_next(L, t) != 0)
            {
                // Use built-in "print" function to print the two values on the stack.
                LuaDll.lua_getglobal(L, "print");
                LuaDll.lua_pushstring(L, "\t");
                LuaDll.lua_pushvalue(L, -4);
                LuaDll.lua_pushvalue(L, -4);
                LuaDll.lua_call(L, 3, 0);

                /* removes 'value'; keeps 'key' for next iteration */
                LuaDll.lua_pop(L, 1);
            }

            // Pop the metatable
            LuaDll.lua_pop(L, 1);

            Debug.Assert(top == LuaDll.lua_gettop(L), "Error in stack");
        }
Beispiel #15
0
        /// <summary>
        /// Build a mangled name from a lua function call.
        /// Assumes that the function arguments are on the stack.
        /// This is to allow each unique overloaded method in C# to have a unique name in lua.
        /// Method names must be in the same format generated by buildMangledNameFromMethodInfo.
        /// </summary>
        /// <param name="simpleName">Unmangled name of method</param>
        /// <returns>Returns a string containing a unique name of the given method</returns>
        /// <see>buildMangledNameFromMethodInfo</see>
        private string buildMangledNameFromLuaParameters(string simpleName)
        {
            StringBuilder sb = new StringBuilder(simpleName + "_");

            int paramcount = LuaDll.lua_gettop(L);

            Type[] types = new Type[paramcount];
            for (int i = 0; i < paramcount; ++i)
            {
                int luaType = LuaDll.lua_type(L, i + 1);
                switch (luaType)
                {
                case LuaDll.LUA_TBOOLEAN:
                    sb.Append("b");
                    break;

                case LuaDll.LUA_TNUMBER:
                    sb.Append("n");
                    break;

                case LuaDll.LUA_TSTRING:
                    sb.Append("s");
                    break;

                case LuaDll.LUA_TUSERDATA:
                    sb.Append("c");
                    break;

                default:
                    Console.WriteLine("Invalid parameter #{0} as {1}", i + 1, LuaDll.lua_typename(L, luaType));
                    break;
                }
            }

            return(sb.ToString());
        }
Beispiel #16
0
        public MultiValue call(string func, params object[] args)
        {
            int top = LuaDll.lua_gettop(L);

            MultiValue mv = new MultiValue(args);

            LuaDll.lua_getfield(L, LuaDll.LUA_GLOBALSINDEX, func);
            int count = pushValue(mv);
            int ret   = LuaDll.lua_pcall(L, count, LuaDll.LUA_MULTRET, 0);

            if (ret != 0)
            {
                string err = LuaDll.lua_tostring(L, -1);
                Console.WriteLine("ERROR: " + err);
                LuaDll.lua_pop(L, 1);
            }
            else
            {
                int newtop = LuaDll.lua_gettop(L);
                return(getValues(top + 1, newtop - top));
            }

            return(null);
        }
Beispiel #17
0
        /// <summary>
        /// Single lua function used for all C# function or method calls from lua.
        /// </summary>
        /// <param name="L">Lua state</param>
        /// <returns>Returns number of results pushed onto the stack</returns>
        private int functionCallAdapter(lua_State L)
        {
            // Figure out which function to call.
            // Our upvalue is a table of all methods with the same name as this one.

            // Get the function name.
            LuaDll.lua_getfield(L, LuaDll.lua_upvalueindex(1), kFunctionNameKey);
            string simpleName = LuaDll.lua_tostring(L, -1);

            LuaDll.lua_pop(L, 1);

            // Lookup the mangled name from the lut stored at upvalueindex.
            string mangledName = buildMangledNameFromLuaParameters(simpleName);

            LuaDll.lua_getfield(L, LuaDll.lua_upvalueindex(1), mangledName);

            if (LuaDll.lua_isnil(L, -1))
            {
                LuaDll.luaL_error(L, "Unknown function " + mangledName + " \"" + demangleName(mangledName) + "\"");
                return(0);
            }

            // Get the function delegate from the stack.
            GCHandle h = GCHandle.FromIntPtr(LuaDll.lua_topointer(L, -1));

            LuaDll.lua_pop(L, 1);

            System.Reflection.MethodInfo      fd    = (System.Reflection.MethodInfo)h.Target;
            System.Reflection.ParameterInfo[] pinfo = fd.GetParameters();
            int    firstParam = 0;
            Object self       = null;

            // Check if this is a static method or not.  If it is not static, then the first
            // parameter must be an instance of the class.
            if (!fd.IsStatic)
            {
                // Get the pointer to the object (and verify the type).
                IntPtr ud = LuaDll.luaL_checkudata(L, 1, fd.ReflectedType.FullName);

                // Copy the address of the object from the userdata.
                GCHandle hSelf = GCHandle.FromIntPtr(Marshal.ReadIntPtr(ud));

                // Since this is a non-static method, it will have an extra parameter.
                firstParam = 1;
                self       = hSelf.Target;
            }

            // Verify that we are getting the correct number of parameters
            if (pinfo.Length != (LuaDll.lua_gettop(L) - firstParam))
            {
                LuaDll.luaL_error(L, "Invalid number of parameters for function '{0}'", fd.Name);
                return(1);
            }

            Object[] parms         = new Object[pinfo.Length];
            int      firstLuaParam = firstParam + 1;

            for (int i = 0; i < pinfo.Length; ++i)
            {
                if (pinfo[i].ParameterType == typeof(int))
                {
                    parms[i] = LuaDll.luaL_checkinteger(L, i + firstLuaParam);
                }
                else if (pinfo[i].ParameterType == typeof(double))
                {
                    parms[i] = LuaDll.luaL_checknumber(L, i + firstLuaParam);
                }
                else if (pinfo[i].ParameterType == typeof(string))
                {
                    parms[i] = LuaDll.luaL_checkstring(L, i + firstLuaParam);
                }
                else if (pinfo[i].ParameterType == typeof(bool))
                {
                    LuaDll.luaL_checktype(L, i + firstLuaParam, LuaDll.LUA_TBOOLEAN);
                    parms[i] = LuaDll.lua_toboolean(L, i + firstLuaParam);
                }
                else
                {
                    // Get the pointer to the object.
                    IntPtr ud = LuaDll.lua_touserdata(L, i + firstLuaParam);
                    parms[i] = GCHandle.FromIntPtr(Marshal.ReadIntPtr(ud)).Target;
                }
            }
            object result = fd.Invoke(self, parms);

            return(pushValue(result));
        }