예제 #1
0
        /// <summary>__index metafunction of type references, works on static members.</summary>
        int classIndex(lua.State L)
        {
            using (luanet.entercfunction(L, interpreter))
            {
                var klass = _checktyperef(L);

                switch (lua.type(L, 2))
                {
                case LUA.T.NUMBER:
                    var   size = lua.tonumber(L, 2);
                    Array array;
                    try { array = Array.CreateInstance(klass.UnderlyingSystemType, checked ((int)size)); }
                    catch (Exception ex) { return(translator.throwError(L, ex)); }
                    translator.push(L, array);
                    return(1);

                case LUA.T.STRING:
                    string methodName = lua.tostring(L, 2);
                    return(getMember(L, klass, null, methodName, BindingFlags.FlattenHierarchy | BindingFlags.Static));

                default:
                    return(luaL.typerror(L, 2, "string or number"));
                }
            }
        }
예제 #2
0
        /// <summary>
        /// [-(top-oldTop), +0, m] Gets the values from the provided index to the top of the stack and returns them in an array,
        /// casting them to the provided types.
        /// </summary>
        internal object[] popValues(lua.State L, int oldTop, Type[] popTypes)
        {
            Debug.Assert(interpreter.IsSameLua(L));
            Debug.Assert(oldTop >= 0, "oldTop must be a value previously returned by lua_gettop");
            int newTop = lua.gettop(L);

            if (oldTop >= newTop)
            {
                return(null);
            }

            var values = new object[newTop - oldTop];
            int j      = 0;

            if (popTypes == null)
            {
                for (int i = oldTop + 1; i <= newTop; ++i)
                {
                    values[j++] = getObject(L, i);
                }
            }
            else
            {
                int iTypes = popTypes[0] == typeof(void) ? 1 : 0;
                for (int i = oldTop + 1; i <= newTop; ++i)
                {
                    values[j++] = getAsType(L, i, popTypes[iTypes++]);
                }
            }

            lua.settop(L, oldTop);
            return(values);
        }
예제 #3
0
        /// <summary>Implementation of enum.</summary>
        int @enum(lua.State L)
        {
            Debug.Assert(interpreter.IsSameLua(L) && luanet.infunction(L));
            Type t = _classType(L, 1);

            if (!t.IsEnum)
            {
                return(luaL.argerror(L, 1, "enum type reference expected"));
            }

            object res;

            switch (lua.type(L, 2))
            {
            case LUA.T.NUMBER:
                res = Enum.ToObject(t, (int)lua.tonumber(L, 2));
                break;

            case LUA.T.STRING:
                try { res = Enum.Parse(t, lua.tostring(L, 2)); }
                catch (ArgumentException e) { return(luaL.argerror(L, 2, e.Message)); }
                break;

            default:
                return(luaL.typerror(L, 2, "number or string"));
            }
            pushObject(L, res);
            return(1);
        }
예제 #4
0
        /// <summary>Implementation of load_assembly. Throws an error if the assembly is not found.</summary>
        int loadAssembly(lua.State L)
        {
            Debug.Assert(interpreter.IsSameLua(L) && luanet.infunction(L));
            string assemblyName = luaL.checkstring(L, 1);

            try
            {
                Assembly assembly = null;
                try
                {
                                        #pragma warning disable 618 // LoadWithPartialName deprecated. No alternative exists.
                    assembly = Assembly.LoadWithPartialName(assemblyName);
                                        #pragma warning restore 618
                }
                catch (BadImageFormatException) {}                 // The assemblyName was invalid.  It is most likely a path.

                if (assembly == null)
                {
                    assembly = Assembly.Load(AssemblyName.GetAssemblyName(assemblyName));
                }

                if (assembly != null)
                {
                    LoadAssembly(assembly);
                }
            }
            catch (Exception e) { return(throwError(L, e)); }

            return(0);
        }
예제 #5
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();
        }
예제 #6
0
        /// <summary>Implementation of enum.</summary>
        int @enum(lua.State L)
        {
            var c = luanet.entercfunction(L, interpreter);

            try
            {
                Type t = _classType(L, 1);
                if (!t.IsEnum)
                {
                    return(luaL.argerror(L, 1, "enum type reference expected"));
                }

                object res;
                switch (lua.type(L, 2))
                {
                case LUA.T.NUMBER:
                    res = Enum.ToObject(t, checked ((int)lua.tonumber(L, 2)));
                    break;

                case LUA.T.STRING:
                    res = Enum.Parse(t, lua.tostring(L, 2));
                    break;

                default:
                    return(luaL.typerror(L, 2, "number or string"));
                }
                pushObject(L, res);
                return(1);
            }
            catch (LuaInternalException) { throw; }
            catch (Exception e) { return(luaL.argerror(L, 2, e.Message)); }
            finally { c.Dispose(); }
        }
예제 #7
0
        /// <summary>
        /// __call metafunction of type references.
        /// Searches for and calls a constructor for the type.
        /// Returns nil if the constructor is not found or if the arguments are invalid.
        /// Throws an error if the constructor generates an exception.
        /// </summary>
        int classCall(lua.State L)
        {
            using (luanet.entercfunction(L, interpreter))
            {
                var klass            = _checktyperef(L);
                var validConstructor = new MethodCache();
                lua.remove(L, 1);
                var constructors = klass.UnderlyingSystemType.GetConstructors();

                foreach (ConstructorInfo constructor in constructors)
                {
                    if (translator.matchParameters(L, constructor, ref validConstructor))
                    {
                        if (!translator.memberIsAllowed(constructor))
                        {
                            if (constructors.Length == 1)
                            {
                                return(luaL.error(L, "constructor call failed (access denied)"));
                            }
                            continue;
                        }
                        object result;
                        try { result = constructor.Invoke(validConstructor.args); }
                        catch (TargetInvocationException ex) { return(translator.throwError(L, luaclr.verifyex(ex.InnerException))); }
                        catch (Exception ex) { return(luaL.error(L, "constructor call failed (" + ex.Message + ")")); }
                        translator.push(L, result);
                        return(1);
                    }
                }
                return(luaL.error(L, "constructor arguments do not match (" + klass.UnderlyingSystemType + ")"));
            }
        }
예제 #8
0
        static Type _classType(lua.State L, int narg)
        {
            var pt = luaclr.checkref(L, narg, "luaNet_class");

            Debug.Assert(pt is ProxyType);
            return(((ProxyType)pt).UnderlyingSystemType);
        }
예제 #9
0
        /// <summary>Implementation of get_constructor_bysig.</summary>
        int getConstructorBysig(lua.State L)
        {
            var c = luanet.entercfunction(L, interpreter);

            try
            {
                var klass = (ProxyType)luaclr.checkref(L, 1, "luaNet_class");

                var signature = new Type[lua.gettop(L) - 1];
                for (int i = 0; i < signature.Length; ++i)
                {
                    signature[i] = FindType(L, lua.tostring(L, i + 2));
                }

                var constructor = klass.UnderlyingSystemType.GetConstructor(signature);
                if (constructor == null)
                {
                    return(luaL.error(L, "Constructor with the specified signature was not found."));
                }
                luaclr.pushcfunction(L, new LuaMethodWrapper(this, null, klass, constructor).call);
                return(1);
            }
            catch (LuaInternalException) { throw; }
            catch (Exception ex) { return(throwError(L, ex)); }
            finally { c.Dispose(); }
        }
예제 #10
0
        /// <summary>[-0, +0, -] Creates a <see cref="LuaValue"/> from the specified value on the stack. If <paramref name="detailed_tostring"/> is true, <see cref="luanet.summarizetable"/> will be used to preemptively generate and store a detailed <see cref="ToString"/> value.</summary>
        unsafe public static LuaValue read(lua.State L, int index, bool detailed_tostring)
        {
            var type = lua.type(L, index);

            switch (type)
            {
            case LUA.T.BOOLEAN:
                return(new LuaValue(lua.toboolean(L, index)));

            case LUA.T.LIGHTUSERDATA:
                return(new LuaValue(new IntPtr(lua.touserdata(L, index))));

            case LUA.T.NUMBER:
                return(new LuaValue(lua.tonumber(L, index)));

            case LUA.T.STRING:
                return(new LuaValue(lua.tostring(L, index)));

            case LUA.T.TABLE:
                return(new LuaValue(detailed_tostring ? luanet.summarizetable(L, index, 256) : null, LuaType.Table));

            default:
                return(new LuaValue((LuaType)type));
            }
        }
예제 #11
0
        /// <summary>
        /// __newindex metafunction of CLR objects.
        /// Receives the object, the member name and the value to be stored as arguments.
        /// Throws and error if the assignment is invalid.
        /// </summary>
        int newIndex(lua.State L)
        {
            Debug.Assert(translator.interpreter.IsSameLua(L) && luanet.infunction(L));
            object target = luaclr.checkref(L, 1);

            Type type = target.GetType();

            // First try to look up the parameter as a property name
            string detailMessage;
            bool   didMember = trySetMember(L, type, target, BindingFlags.Instance, out detailMessage);

            if (didMember)
            {
                return(0);                      // Must have found the property name
            }
            // We didn't find a property name, now see if we can use a [] style this accessor to set array contents
            try
            {
                if (type.IsArray && lua.type(L, 2) == LUA.T.NUMBER)
                {
                    int index = (int)lua.tonumber(L, 2);

                    Array  arr = (Array)target;
                    object val = translator.getAsType(L, 3, arr.GetType().GetElementType());
                    arr.SetValue(val, index);
                }
                else
                {
                    // Try to see if we have a this[] accessor
                    MethodInfo setter = type.GetMethod("set_Item");
                    if (setter == null)
                    {
                        return(luaL.error(L, detailMessage));                        // Pass the original message from trySetMember because it is probably best
                    }
                    ParameterInfo[] args      = setter.GetParameters();
                    Type            valueType = args[1].ParameterType;

                    // The new val ue the user specified
                    object val = translator.getAsType(L, 3, valueType);

                    Type   indexType = args[0].ParameterType;
                    object index     = translator.getAsType(L, 2, indexType);

                    object[] methodArgs = new object[2];

                    // Just call the indexer - if out of bounds an exception will happen
                    methodArgs[0] = index;
                    methodArgs[1] = val;

                    setter.Invoke(target, methodArgs);
                }
            }
            catch (SEHException)
            {
                // If we are seeing a C++ exception - this must actually be for Lua's private use.  Let it handle it
                throw;
            }
            catch (Exception e) { ThrowError(L, e); }
            return(0);
        }
예제 #12
0
        // copied from Lua lbaselib.c costatus()
        static LuaCoStatus CoStatus(lua.State L, lua.State co)
        {
            if (L == co)
            {
                return(LuaCoStatus.Running);
            }
            switch (lua.status(co))
            {
            case LUA.YIELD:
                return(LuaCoStatus.Suspended);

            case 0: {
                var ar = default(lua.Debug);
                if (lua.getstack(co, 0, ref ar))                  // does it have frames?
                {
                    return(LuaCoStatus.Normal);                   // it is running
                }
                else if (lua.gettop(co) == 0)
                {
                    return(LuaCoStatus.Dead);
                }
                else
                {
                    return(LuaCoStatus.Suspended);                     // initial state
                }
            }

            default:              // some error occured
                return(LuaCoStatus.Dead);
            }
        }
        /// <summary>[-0, +1, m]</summary>
        static void _PushEnumeration <T>(lua.State L, Type type) where T : struct, IConvertible
        {
            Debug.Assert(typeof(T) == type);
            if (!type.IsEnum)
            {
                throw new ArgumentException("The type must be an enumeration.");
            }

            string[] names  = Enum.GetNames(type);
            var      values = (T[])Enum.GetValues(type);

            Debug.Assert(EzDelegate.Func(() => {
                if (values.Length == 0)
                {
                    return(true);
                }
                try { var x = values[0].ToDouble(null); return(true); }
                catch { return(false); }
            })(), "enum conversion to double isn't expected to throw exceptions");

            StackAssert.Start(L);
            luanet.checkstack(L, 3, "LuaRegistrationHelper._PushEnumeration");
            lua.createtable(L, 0, names.Length);
            for (int i = 0; i < names.Length; ++i)
            {
                lua.pushstring(L, names[i]);
                lua.pushnumber(L, values[i].ToDouble(null));
                lua.rawset(L, -3);
            }
            StackAssert.End(1);
        }
예제 #14
0
 /// <summary>[-0, +1, -] Push the referenced object onto the stack without verifying its type matches the class. For internal use only. Should only be used when calling lua functions that can safely accept any type.</summary>
 /// <remarks>DO NOT call this from within your <see cref="push"/> implementation; it redirects to <see cref="push"/> in debug builds.</remarks>
 protected virtual void rawpush(lua.State L)
 {
                 #if DEBUG
     try { push(L); return; }
     catch (Exception ex) { Debug.Fail(ex.ToString()); }
                 #endif
     luaL.getref(L, Reference);
 }
예제 #15
0
 /// <summary>Implementation of ctype.</summary>
 int ctype(lua.State L)
 {
     using (luanet.entercfunction(L, interpreter))
     {
         pushObject(L, _classType(L, 1));
         return(1);
     }
 }
예제 #16
0
 /// <summary>[-0, +0, m, requires checkstack(1)] Add CLR object instance metatable entries to a new ref metatable at the top of the stack.</summary>
 public void BuildObjectMetatable(lua.State L)
 {
     Debug.Assert(interpreter.IsSameLua(L) && luaclr.isrefmeta(L, -1));
     lua.newtable(L);                lua.setfield(L, -2, "cache");
     lua.pushcfunction(L, _index); lua.setfield(L, -2, "__index");
     lua.pushcfunction(L, _toString); lua.setfield(L, -2, "__tostring");
     lua.pushcfunction(L, _newindex); lua.setfield(L, -2, "__newindex");
 }
예제 #17
0
 /// <summary>[-0, +1, -] Push the referenced object onto the stack without verifying its type matches the class. For internal use only. Should only be used when calling lua functions that can safely accept any type.</summary>
 protected void rawpush(lua.State L)
 {
                 #if DEBUG
     push(L);
                 #else
     Debug.Assert(Owner.IsSameLua(L));
     luaL.getref(L, Reference);
                 #endif
 }
예제 #18
0
 /// <summary>[-0, +1, m] Pushes a type reference into the stack</summary>
 internal static void pushType(lua.State L, Type t)
 {
     Debug.Assert(Lua.GetOwner(L) != null && t != null);
     luaL.checkstack(L, 2, "ObjectTranslator.pushType");
     luaclr.newref(L, new ProxyType(t));
     luaL.getmetatable(L, "luaNet_class");
     Debug.Assert(lua.istable(L, -1));
     lua.setmetatable(L, -2);
 }
예제 #19
0
        bool consistent(lua.State L, lua.State co)
        {
            Debug.Assert(luaclr.mainthread(co) != co, "The Lua coroutine library never gives Lua scripts a reference to the main thread. Are you sure it is safe and useful to do that?");
            rawpush(L);
            bool ret = lua.tothread(L, -1) == co;

            lua.pop(L, 1);
            return(ret);
        }
예제 #20
0
        /// <summary>
        /// __newindex metafunction of CLR objects.
        /// Receives the object, the member name and the value to be stored as arguments.
        /// Throws and error if the assignment is invalid.
        /// </summary>
        int newIndex(lua.State L)
        {
            using (luanet.entercfunction(L, interpreter))
            {
                object target = luaclr.checkref(L, 1);
                Type   type   = target.GetType();

                // First try to look up the parameter as a property name
                string detailMessage;
                if (trySetMember(L, type, target, BindingFlags.Instance, out detailMessage))
                {
                    return(0);                          // found and set the property
                }
                // We didn't find a property name, now see if we can use a [] style this accessor to set array contents
                try
                {
                    if (type.IsArray && lua.type(L, 2) == LUA.T.NUMBER)
                    {
                        int index = (int)lua.tonumber(L, 2);

                        var    arr = (Array)target;
                        object val = translator.getAsType(L, 3, type.GetElementType());
                        arr.SetValue(val, index);
                    }
                    else
                    {
                        // Try to see if we have a this[] accessor
                        MethodInfo setter = type.GetMethod("set_Item");                         // todo: overloads
                        if (setter == null)
                        {
                            return(luaL.error(L, detailMessage));                            // Pass the original message from trySetMember because it is probably best
                        }
                        ParameterInfo[] args = setter.GetParameters();
                        if (args.Length != 2)                         // avoid throwing IndexOutOfRangeException for functions that take less than 2 arguments. that would be confusing in this context.
                        {
                            return(luaL.error(L, detailMessage));
                        }

                        if (!translator.memberIsAllowed(setter))
                        {
                            return(luaL.error(L, "index setter call failed (access denied)"));
                        }

                        object index = translator.getAsType(L, 2, args[0].ParameterType);
                        // The new value the user specified
                        object val = translator.getAsType(L, 3, args[1].ParameterType);

                        // Just call the indexer - if out of bounds an exception will happen
                        setter.Invoke(target, new object[] { index, val });
                    }
                    return(0);
                }
                catch (TargetInvocationException ex) { return(translator.throwError(L, luaclr.verifyex(ex.InnerException))); }
                catch (LuaInternalException) { throw; }
                catch (Exception ex) { return(luaL.error(L, "index setter call failed (" + ex.Message + ")")); }
            }
        }
예제 #21
0
        /// <summary>[-0, +1, e] Pushes the object into the Lua stack according to its type. Disposes orphaned objects. (<see cref="LuaTable.IsOrphaned"/>)</summary>
        internal void pushReturnValue(lua.State L, object o)
        {
            push(L, o);
            var t = o as LuaTable;

            if (t != null && t.IsOrphaned)
            {
                t.Dispose();
            }
        }
예제 #22
0
        /// <summary>[-1, +0, -] Creates a <see cref="LuaValue"/> from the value on the top of the stack and pops it. If <paramref name="detailed_tostring"/> is true, <see cref="luanet.summarizetable"/> will be used to preemptively generate and store a detailed <see cref="ToString"/> value.</summary>
        public static LuaValue pop(lua.State L, bool detailed_tostring)
        {
            var ret = read(L, -1, detailed_tostring);

            if (ret.Type != (LuaType)LUA.T.NONE)
            {
                lua.pop(L, 1);
            }
            return(ret);
        }
예제 #23
0
        /// <summary>__tostring metafunction of CLR objects.</summary>
        int toString(lua.State L)
        {
            Debug.Assert(translator.interpreter.IsSameLua(L) && luanet.infunction(L));
            var    obj = luaclr.checkref(L, 1);
            string s;

            try { s = obj.ToString(); }
            catch (Exception ex) { return(translator.throwError(L, ex)); }
            lua.pushstring(L, s ?? "");
            return(1);
        }
예제 #24
0
        /// <summary>[-0, +1, -] Push the referenced object onto the stack. The type of the value is guaranteed to match the class.</summary>
        protected internal void push(lua.State L)
        {
            Debug.Assert(Owner.IsSameLua(L));
            luaL.getref(L, this.Reference);
            var actual = lua.type(L, -1);

            if (actual != this.Type)                                  // the type shouldn't change unless we have the wrong lua_State, the registry has been corrupted, or we are being hacked
            {
                System.Environment.FailFast(FormatTypeError(actual)); // this is not overkill
            }
        }
예제 #25
0
        /// <summary>Gets an object from the Lua stack with the desired type, if it matches, otherwise returns null.</summary>
        internal object getAsType(lua.State L, int index, Type paramType)
        {
            Debug.Assert(interpreter.IsSameLua(L));
            ExtractValue extractor = typeChecker.checkType(L, index, paramType);

            if (extractor == null)
            {
                return(null);
            }
            return(extractor(L, index));
        }
예제 #26
0
        static bool isString(lua.State L, int index)
        {
            switch (lua.type(L, index))
            {
            case LUA.T.NIL:
            case LUA.T.STRING:
                return(true);

            default:
                return(false);
            }
        }
예제 #27
0
        static bool isFunction(lua.State L, int index)
        {
            switch (lua.type(L, index))
            {
            case LUA.T.NIL:
            case LUA.T.FUNCTION:
                return(true);

            default:
                return(false);
            }
        }
예제 #28
0
        static bool isThread(lua.State L, int index)
        {
            switch (lua.type(L, index))
            {
            case LUA.T.NIL:
            case LUA.T.THREAD:
                return(true);

            default:
                return(false);
            }
        }
예제 #29
0
        static bool isUserData(lua.State L, int index)
        {
            switch (lua.type(L, index))
            {
            case LUA.T.NIL:
            case LUA.T.USERDATA:
                return(true);

            default:
                return(false);
            }
        }
예제 #30
0
        static bool isTable(lua.State L, int index)
        {
            switch (lua.type(L, index))
            {
            case LUA.T.NIL:
            case LUA.T.TABLE:
                return(true);

            default:
                return(false);
            }
        }