Beispiel #1
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 #2
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 #3
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 #4
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 #5
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 #6
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 #7
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 #8
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));
        }