Ejemplo n.º 1
0
        public MetaFunctions(lua.State L, ObjectTranslator translator)
        {
            Debug.Assert(translator.interpreter.IsSameLua(L));
            this.translator  = translator;
            this.interpreter = translator.interpreter;

            // used by BuildObjectMetatable
            _toString = this.toString;
            _index    = this.index;
            _newindex = this.newIndex;

            luaL.checkstack(L, 2, "new MetaFunctions");
            StackAssert.Start(L);

            // Creates the metatable for superclasses (the base field of registered tables)
            bool didnt_exist = luaclr.newrefmeta(L, "luaNet_searchbase", 3);

            Debug.Assert(didnt_exist);
            lua.pushcfunction(L, _toString); lua.setfield(L, -2, "__tostring");
            lua.pushcfunction(L, _baseIndex = this.baseIndex); lua.setfield(L, -2, "__index");
            lua.pushcfunction(L, _newindex); lua.setfield(L, -2, "__newindex");
            lua.pop(L, 1);

            // Creates the metatable for type references
            didnt_exist = luaclr.newrefmeta(L, "luaNet_class", 4);
            Debug.Assert(didnt_exist);
            lua.pushcfunction(L, _toString); lua.setfield(L, -2, "__tostring");
            lua.pushcfunction(L, _classIndex    = this.classIndex); lua.setfield(L, -2, "__index");
            lua.pushcfunction(L, _classNewindex = this.classNewIndex); lua.setfield(L, -2, "__newindex");
            lua.pushcfunction(L, _classCall     = this.classCall); lua.setfield(L, -2, "__call");
            lua.pop(L, 1);

            StackAssert.End();
        }
Ejemplo n.º 2
0
        [TestMethod] public void InFunction()
        {
            using (var l = new Lua())
            {
                var L = luanet.getstate(l);

                lua.cpcall(L, L2 =>
                {
                    Assert.AreEqual(1, L2.Length);
                    lua.pop(L2, 1);
                    Assert.AreEqual(3, L.Sum(si => si.Type == LUA.T.NONE ? 0 : 1));
                    Assert.AreEqual(LUA.T.NONE, L2[lua.upvalueindex(1)].Type);
                    return(0);
                }, default(IntPtr));
                Assert.AreEqual(0, L.Length);

                lua.CFunction cf = L2 =>
                {
                    Assert.AreEqual(0, L2.Length);
                    Assert.AreEqual(4, L2.Sum(si => si.Type == LUA.T.NONE ? 0 : 1));
                    Assert.AreEqual(LUA.T.BOOLEAN, L2[lua.upvalueindex(1)].Type);
                    return(0);
                };
                lua.pushboolean(L, true);
                lua.pushcclosure(L, cf, 1);
                lua.call(L, 0, 0);

                GC.KeepAlive(cf);
                Assert.AreEqual(0, L.Length);
            }
        }
Ejemplo n.º 3
0
        public void push()
        {
            _keys[_keys.Length - 1].VerifySupport();
            var L = Parent.L;

            luanet.checkstack(L, 2, "StackIndexChild.push"); StackAssert.Start(L);
            Dbg.Assert(_keys.All(k => k.IsSupported));
            var keys = _keys;

            lua.CFunction tryBlock = L2 =>
            {
                for (int i = 0; i < keys.Length; ++i)
                {
                    keys[i].push(L2);
                    lua.gettable(L2, -2);
                    lua.remove(L2, -2);
                }
                return(1);
            };
            // parent should be pushed first. it might be pointing to the index we're about to fill
            this.Parent.push();
            lua.pushcfunction(L, tryBlock);
            lua.insert(L, -2);
            var ex = luanet.pcall(L, 1, 1);

            if (ex != null)
            {
                StackAssert.End();
                Trace.TraceError("push failed: " + ex.Message);
                throw ex;
            }
            GC.KeepAlive(tryBlock);                          StackAssert.End(1);
        }
Ejemplo n.º 4
0
        /// <summary>[-n, +1, m] Pushes a new C closure onto the stack. <paramref name="n"/> can be up to 254; the last slot is reserved for a garbage collection userdata that keeps the delegate alive.</summary>
        public static void pushcclosure(lua.State L, lua.CFunction f, int n)
        {
            Debug.Assert(f != null);
            Debug.Assert(n <= 254 && n >= 0);
            luaL.checkstack(L, 2, "luaclr.pushcclosure");

            luaclr.newref(L, f);
            luaclr.newrefmeta(L, "LuaCLR CFunction anchor", 0);
            // nothing to add to this metatable other than gc, it just needs to exist and then not exist
            lua.setmetatable(L, -2);

            lua.pushcclosure(L, f, n + 1);
        }
Ejemplo n.º 5
0
        public ObjectTranslator(lua.State L, Lua interpreter)
        {
            Debug.Assert(interpreter.IsSameLua(L));
            luaclr.checkstack(L, 1, "new ObjectTranslator");
            this.interpreter = interpreter;
            typeChecker      = new CheckType(interpreter);
            metaFunctions    = new MetaFunctions(L, this);

            StackAssert.Start(L);
            lua.pushcfunction(L, _loadAssembly        = this.loadAssembly); lua.setglobal(L, "load_assembly");
            lua.pushcfunction(L, _importType          = this.importType); lua.setglobal(L, "import_type");
            lua.pushcfunction(L, _makeObject          = this.makeObject); lua.setglobal(L, "make_object");
            lua.pushcfunction(L, _freeObject          = this.freeObject); lua.setglobal(L, "free_object");
            lua.pushcfunction(L, _getMethodBysig      = this.getMethodBysig); lua.setglobal(L, "get_method_bysig");
            lua.pushcfunction(L, _getConstructorBysig = this.getConstructorBysig); lua.setglobal(L, "get_constructor_bysig");
            lua.pushcfunction(L, _ctype = this.ctype); lua.setglobal(L, "ctype");
            lua.pushcfunction(L, _enum  = this.@enum); lua.setglobal(L, "enum");
            StackAssert.End();
        }
Ejemplo n.º 6
0
 public void CallViaThunk(Action function)
 {
     if (function == null)
     {
         throw new ArgumentNullException("function");
     }
     // todo: is it more performant to actually pass a GCHandle in through the ud parameter versus creating and GCing delegate thunks?
     lua.CFunction wrapper = L =>
     {
         lua.settop(L, 0);
         // no need for luanet.entercfunction here because it's guaranteed to be the same state
         try { function(); }
         catch (LuaInternalException) { throw; }
         catch (Exception ex) { luanet.error(L, _interpreter, ex); }
         return(0);
     };
     {
         var L = _L;
         if (lua.cpcall(L, wrapper, default(IntPtr)) != LUA.ERR.Success)
         {
             throw luanet.exceptionfromerror(L, _interpreter, -2);
         }
     }
 }
Ejemplo n.º 7
0
        /// <summary>[-0, +2, e]
        /// Returns to Lua the value of a member or a delegate to call it, depending on the type of the member.
        /// Works with static or instance members. Uses reflection to find members,
        /// and stores the reflected MemberInfo object in a cache (indexed by <paramref name="objType"/> and <paramref name="methodName"/>).
        /// </summary>
        /// <exception cref="ArgumentNullException"><paramref name="objType"/> and <paramref name="methodName"/> are required</exception>
        int getMember(lua.State L, IReflect objType, object obj, string methodName, BindingFlags bindingType)
        {
            Debug.Assert(interpreter.IsSameLua(L));
            Debug.Assert(objType != null && methodName != null);

            Debug.Assert((obj == null) == (objType is ProxyType));
            Debug.Assert((obj == null) != (objType is Type));
            Debug.Assert((obj == null) == ((bindingType & BindingFlags.Static) == BindingFlags.Static));
            Debug.Assert((obj == null) != ((bindingType & BindingFlags.Instance) == BindingFlags.Instance));

            MemberInfo member       = null;
            object     cachedMember = checkMemberCache(objType, methodName);

            if (cachedMember != null)
            {
                var cachedMethod = cachedMember as lua.CFunction;
                if (cachedMethod != null)
                {
                    luaclr.pushcfunction(L, cachedMethod);
                    lua.pushboolean(L, true);
                    return(2);
                }
                Debug.Assert(cachedMember is MemberInfo);
                member = (MemberInfo)cachedMember;
            }
            else
            {
                MemberInfo[] members = objType.GetMember(methodName, bindingType | luanet.LuaBindingFlags);
                if (members.Length != 0)
                {
                    member = members[0];
                                        #if DEBUG
                    if (!(members.Length == 1 || member is MethodBase))                     // todo
                    {
                        return(luaL.error(L, "Overloads for members other than methods are not implemented."));
                    }
                                        #endif
                }
            }

            object value = null;

            switch (member == null ? MemberTypes.All : member.MemberType)
            {
            default:             // not found or found a constructor
                // kevinh - we want to throw an error because merely returning 'nil' in this case
                // is not sufficient.  valid data members may return nil and therefore there must be some
                // way to know the member just doesn't exist.
                return(luaL.error(L, string.Format("'{0}' does not contain a definition for '{1}'", objType.UnderlyingSystemType.FullName, methodName)));

            case MemberTypes.Method:
                var wrapper = new lua.CFunction((new LuaMethodWrapper(translator, objType, methodName, bindingType)).call);

                if (cachedMember == null)
                {
                    setMemberCache(objType, methodName, wrapper);
                }
                luaclr.pushcfunction(L, wrapper);
                lua.pushboolean(L, true);
                return(2);

            case MemberTypes.Field:
                if (!translator.memberIsAllowed(member))
                {
                    return(luaL.error(L, "field read failed (access denied)"));
                }
                try { value = ((FieldInfo)member).GetValue(obj); }
                catch { goto default; }
                translator.push(L, value);
                break;

            case MemberTypes.Property:
                // todo: support indexed properties
                if (!translator.memberIsAllowed(member))
                {
                    return(luaL.error(L, "property call failed (access denied)"));
                }
                try { value = ((PropertyInfo)member).GetValue(obj, null); }
                catch (TargetInvocationException ex) { return(translator.throwError(L, luaclr.verifyex(ex.InnerException))); }
                catch { goto default; }
                translator.push(L, value);
                break;

            case MemberTypes.Event:
                if (!translator.memberIsAllowed(member))
                {
                    return(luaL.error(L, "event read failed (access denied)"));
                }
                value = new RegisterEventHandler(translator.pendingEvents, obj, (EventInfo)member);
                translator.push(L, value);
                break;

            case MemberTypes.NestedType:
                var nestedType = (Type)member;
                if (translator.FindType(nestedType))                 // don't hand out class references unless loaded/whitelisted
                {
                    ObjectTranslator.pushType(L, nestedType);
                }
                else
                {
                    lua.pushnil(L);
                }
                break;
            }

            if (cachedMember == null)
            {
                setMemberCache(objType, methodName, member);
            }
            // push false because we are NOT returning a function (see luaIndexFunction)
            lua.pushboolean(L, false);
            return(2);
        }
Ejemplo n.º 8
0
        [TestMethod] public void CFunctions()
        {
            const uint iterations = 2048 * 2048;

            using (var li = new Lua())
            {
                var L = luanet.getstate(li);
                Trace.WriteLine(iterations.ToString("N0") + " iterations");
                Noop(L);                 // jit


                var timer = Stopwatch.StartNew();
                for (uint i = 0; i < iterations; ++i)
                {
                    Noop(L);
                }
                timer.Stop();
                Display(timer, "CLR -> CLR");


                luaL.loadstring(L, @"
					local Noop = Noop
					for i=1,"                     + iterations + @" do
						Noop()
					end
				"                );

                                #pragma warning disable 618
                luanet.CSFunction cs_function = Noop;
                luanet.pushstdcallcfunction(L, cs_function);
                lua.setglobal(L, "Noop");

                lua.pushvalue(L, -1);
                timer.Reset(); timer.Start();
                lua.call(L, 0, 0);
                timer.Stop();
                Display(timer, "Lua -> stdcall -> CLR");

                GC.KeepAlive(cs_function);
                                #pragma warning restore 618


                lua.CFunction c_function = Noop;
                lua.pushcfunction(L, c_function);
                lua.setglobal(L, "Noop");

                lua.pushvalue(L, -1);
                timer.Reset(); timer.Start();
                lua.call(L, 0, 0);
                timer.Stop();
                Display(timer, "Lua -> cdecl -> CLR");

                GC.KeepAlive(c_function);


                luaL.dostring(L, "function Noop() end");

                lua.pushvalue(L, -1);
                timer.Reset(); timer.Start();
                lua.call(L, 0, 0);
                timer.Stop();
                Display(timer, "Lua -> Lua");

                /*
                 *      4,194,304 iterations
                 *      CLR -> CLR: 12ms
                 *      Lua -> stdcall -> CLR: 731ms
                 *      Lua -> cdecl -> CLR: 420ms
                 *      Lua -> Lua: 468ms
                 */
            }
        }
Ejemplo n.º 9
0
 /// <summary>[-0, +1, m] Pushes a C function onto the stack just like lua_pushcfunction except the delegate will be automatically kept alive by storing an opaque userdata in an upvalue.</summary>
 [MethodImpl(INLINE)] public static void pushcfunction(lua.State L, lua.CFunction f)
 {
     luaclr.pushcclosure(L, f, 0);
 }