/* * Implementation of get_constructor_bysig. Returns nil * if no matching constructor is found. */ private int getConstructorSignature(LuaCore.lua_State luaState) { IReflect klass = null; int udata = LuaLib.luanet_checkudata(luaState, 1, "luaNet_class"); if (udata != -1) { klass = (IReflect)objects[udata]; } if (klass.IsNull()) { throwError(luaState, "get_constructor_bysig: first arg is invalid type reference"); } var signature = new Type[LuaLib.lua_gettop(luaState) - 1]; for (int i = 0; i < signature.Length; i++) { signature[i] = FindType(LuaLib.lua_tostring(luaState, i + 2).ToString()); } try { ConstructorInfo constructor = klass.UnderlyingSystemType.GetConstructor(signature); pushFunction(luaState, new LuaCore.lua_CFunction((new LuaMethodWrapper(this, null, klass, constructor)).call)); } catch (Exception e) { throwError(luaState, e); LuaLib.lua_pushnil(luaState); } return(1); }
/* * __index metafunction of base classes (the base field of Lua tables). * Adds a prefix to the method name to call the base version of the method. */ private int getBaseMethod(LuaCore.lua_State luaState) { object obj = translator.getRawNetObject(luaState, 1); if (obj.IsNull()) { translator.throwError(luaState, "trying to index an invalid object reference"); LuaLib.lua_pushnil(luaState); LuaLib.lua_pushboolean(luaState, false); return(2); } string methodName = LuaLib.lua_tostring(luaState, 2).ToString(); if (methodName.IsNull()) { LuaLib.lua_pushnil(luaState); LuaLib.lua_pushboolean(luaState, false); return(2); } getMember(luaState, obj.GetType(), obj, "__luaInterface_base_" + methodName, BindingFlags.Instance | BindingFlags.IgnoreCase); LuaLib.lua_settop(luaState, -2); if (LuaLib.lua_type(luaState, -1) == LuaTypes.Nil) { LuaLib.lua_settop(luaState, -2); return(getMember(luaState, obj.GetType(), obj, methodName, BindingFlags.Instance | BindingFlags.IgnoreCase)); } LuaLib.lua_pushboolean(luaState, false); return(2); }
/* * __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. */ private int callConstructor(LuaCore.lua_State luaState) { var validConstructor = new MethodCache(); IReflect klass; object obj = translator.getRawNetObject(luaState, 1); if (obj.IsNull() || !(obj is IReflect)) { translator.throwError(luaState, "trying to call constructor on an invalid type reference"); LuaLib.lua_pushnil(luaState); return(1); } else { klass = (IReflect)obj; } LuaLib.lua_remove(luaState, 1); var constructors = klass.UnderlyingSystemType.GetConstructors(); foreach (var constructor in constructors) { bool isConstructor = matchParameters(luaState, constructor, ref validConstructor); if (isConstructor) { try { translator.push(luaState, constructor.Invoke(validConstructor.args)); } catch (TargetInvocationException e) { ThrowError(luaState, e); LuaLib.lua_pushnil(luaState); } catch { LuaLib.lua_pushnil(luaState); } return(1); } } string constructorName = (constructors.Length == 0) ? "unknown" : constructors[0].Name; translator.throwError(luaState, String.Format("{0} does not contain constructor({1}) argument match", klass.UnderlyingSystemType, constructorName)); LuaLib.lua_pushnil(luaState); return(1); }
/* * Pushes the object into the Lua stack according to its type. */ internal void push(LuaCore.lua_State luaState, object o) { if (o.IsNull()) { LuaLib.lua_pushnil(luaState); } else if (o is sbyte || o is byte || o is short || o is ushort || o is int || o is uint || o is long || o is float || o is ulong || o is decimal || o is double) { double d = Convert.ToDouble(o); LuaLib.lua_pushnumber(luaState, d); } else if (o is char) { double d = (char)o; LuaLib.lua_pushnumber(luaState, d); } else if (o is string) { string str = (string)o; LuaLib.lua_pushstring(luaState, str); } else if (o is bool) { bool b = (bool)o; LuaLib.lua_pushboolean(luaState, b); } else if (IsILua(o)) { (((ILuaGeneratedType)o).__luaInterface_getLuaTable()).push(luaState); } else if (o is LuaTable) { ((LuaTable)o).push(luaState); } else if (o is LuaCore.lua_CFunction) { pushFunction(luaState, (LuaCore.lua_CFunction)o); } else if (o is LuaFunction) { ((LuaFunction)o).push(luaState); } else { pushObject(luaState, o, "luaNet_metatable"); } }
/* * __tostring metafunction of CLR objects. */ private int toString(LuaCore.lua_State luaState) { object obj = translator.getRawNetObject(luaState, 1); if (!obj.IsNull()) { translator.push(luaState, obj.ToString() + ": " + obj.GetHashCode()); } else { LuaLib.lua_pushnil(luaState); } return(1); }
/// <summary> /// Convert C# exceptions into Lua errors /// </summary> /// <returns>num of things on stack</returns> /// <param name = "e">null for no pending exception</param> internal int SetPendingException(Exception e) { var caughtExcept = e; if (!caughtExcept.IsNull()) { translator.throwError(luaState, caughtExcept); LuaLib.lua_pushnil(luaState); return(1); } else { return(0); } }
/* * Implementation of get_method_bysig. Returns nil * if no matching method is not found. */ private int getMethodSignature(LuaCore.lua_State luaState) { IReflect klass; object target; int udata = LuaLib.luanet_checkudata(luaState, 1, "luaNet_class"); if (udata != -1) { klass = (IReflect)objects[udata]; target = null; } else { target = getRawNetObject(luaState, 1); if (target.IsNull()) { throwError(luaState, "get_method_bysig: first arg is not type or object reference"); LuaLib.lua_pushnil(luaState); return(1); } klass = target.GetType(); } string methodName = LuaLib.lua_tostring(luaState, 2).ToString(); var signature = new Type[LuaLib.lua_gettop(luaState) - 2]; for (int i = 0; i < signature.Length; i++) { signature[i] = FindType(LuaLib.lua_tostring(luaState, i + 3).ToString()); } try { //CP: Added ignore case var method = klass.GetMethod(methodName, BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance | BindingFlags.FlattenHierarchy | BindingFlags.IgnoreCase, null, signature, null); pushFunction(luaState, new LuaCore.lua_CFunction((new LuaMethodWrapper(this, target, klass, method)).call)); } catch (Exception e) { throwError(luaState, e); LuaLib.lua_pushnil(luaState); } return(1); }
/* * Implementation of import_type. Returns nil if the * type is not found. */ private int importType(LuaCore.lua_State luaState) { string className = LuaLib.lua_tostring(luaState, 1).ToString(); var klass = FindType(className); if (!klass.IsNull()) { pushType(luaState, klass); } else { LuaLib.lua_pushnil(luaState); } return(1); }
public ListDictionary GetTableDict(LuaTable table) { var dict = new ListDictionary(); int oldTop = LuaLib.lua_gettop(luaState); translator.push(luaState, table); LuaLib.lua_pushnil(luaState); while (LuaLib.lua_next(luaState, -2) != 0) { dict[translator.getObject(luaState, -2)] = translator.getObject(luaState, -1); LuaLib.lua_settop(luaState, -2); } LuaLib.lua_settop(luaState, oldTop); return(dict); }
/* * Implementation of free_object. Clears the metatable and the * base field, freeing the created object for garbage-collection */ private int unregisterTable(LuaCore.lua_State luaState) { try { if (LuaLib.lua_getmetatable(luaState, 1) != 0) { LuaLib.lua_pushstring(luaState, "__index"); LuaLib.lua_gettable(luaState, -2); object obj = getRawNetObject(luaState, -1); if (obj.IsNull()) { throwError(luaState, "unregister_table: arg is not valid table"); } var luaTableField = obj.GetType().GetField("__luaInterface_luaTable"); if (luaTableField.IsNull()) { throwError(luaState, "unregister_table: arg is not valid table"); } luaTableField.SetValue(obj, null); LuaLib.lua_pushnil(luaState); LuaLib.lua_setmetatable(luaState, 1); LuaLib.lua_pushstring(luaState, "base"); LuaLib.lua_pushnil(luaState); LuaLib.lua_settable(luaState, 1); } else { throwError(luaState, "unregister_table: arg is not valid table"); } } catch (Exception e) { throwError(luaState, e.Message); } return(0); }
/* * Pushes a CLR object into the Lua stack as an userdata * with the provided metatable */ internal void pushObject(LuaCore.lua_State luaState, object o, string metatable) { int index = -1; // Pushes nil if (o.IsNull()) { LuaLib.lua_pushnil(luaState); return; } // Object already in the list of Lua objects? Push the stored reference. bool found = objectsBackMap.TryGetValue(o, out index); if (found) { LuaLib.luaL_getmetatable(luaState, "luaNet_objects"); LuaLib.lua_rawgeti(luaState, -1, index); // Note: starting with lua5.1 the garbage collector may remove weak reference items (such as our luaNet_objects values) when the initial GC sweep // occurs, but the actual call of the __gc finalizer for that object may not happen until a little while later. During that window we might call // this routine and find the element missing from luaNet_objects, but collectObject() has not yet been called. In that case, we go ahead and call collect // object here // did we find a non nil object in our table? if not, we need to call collect object var type = LuaLib.lua_type(luaState, -1); if (type != LuaTypes.Nil) { LuaLib.lua_remove(luaState, -2); // drop the metatable - we're going to leave our object on the stack return; } // MetaFunctions.dumpStack(this, luaState); LuaLib.lua_remove(luaState, -1); // remove the nil object value LuaLib.lua_remove(luaState, -1); // remove the metatable collectObject(o, index); // Remove from both our tables and fall out to get a new ID } index = addObject(o); pushNewObject(luaState, o, index, metatable); }
/* * __index metafunction of type references, works on static members. */ private int getClassMethod(LuaCore.lua_State luaState) { IReflect klass; object obj = translator.getRawNetObject(luaState, 1); if (obj.IsNull() || !(obj is IReflect)) { translator.throwError(luaState, "trying to index an invalid type reference"); LuaLib.lua_pushnil(luaState); return(1); } else { klass = (IReflect)obj; } if (LuaLib.lua_isnumber(luaState, 2)) { int size = (int)LuaLib.lua_tonumber(luaState, 2); translator.push(luaState, Array.CreateInstance(klass.UnderlyingSystemType, size)); return(1); } else { string methodName = LuaLib.lua_tostring(luaState, 2).ToString(); if (methodName.IsNull()) { LuaLib.lua_pushnil(luaState); return(1); } //CP: Ignore case else { return(getMember(luaState, klass, null, methodName, BindingFlags.FlattenHierarchy | BindingFlags.Static | BindingFlags.IgnoreCase)); } } }
/* * Pushes 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 the type of the object and the name of the member). */ private int getMember(LuaCore.lua_State luaState, IReflect objType, object obj, string methodName, BindingFlags bindingType) { bool implicitStatic = false; MemberInfo member = null; object cachedMember = checkMemberCache(memberCache, objType, methodName); //object cachedMember=null; if (cachedMember is LuaCore.lua_CFunction) { translator.pushFunction(luaState, (LuaCore.lua_CFunction)cachedMember); translator.push(luaState, true); return(2); } else if (!cachedMember.IsNull()) { member = (MemberInfo)cachedMember; } else { //CP: Removed NonPublic binding search var members = objType.GetMember(methodName, bindingType | BindingFlags.Public | BindingFlags.IgnoreCase /*| BindingFlags.NonPublic*/); if (members.Length > 0) { member = members[0]; } else { // If we can't find any suitable instance members, try to find them as statics - but we only want to allow implicit static // lookups for fields/properties/events -kevinh //CP: Removed NonPublic binding search and made case insensitive members = objType.GetMember(methodName, bindingType | BindingFlags.Static | BindingFlags.Public | BindingFlags.IgnoreCase /*| BindingFlags.NonPublic*/); if (members.Length > 0) { member = members[0]; implicitStatic = true; } } } if (!member.IsNull()) { if (member.MemberType == MemberTypes.Field) { var field = (FieldInfo)member; if (cachedMember.IsNull()) { setMemberCache(memberCache, objType, methodName, member); } try { translator.push(luaState, field.GetValue(obj)); } catch { LuaLib.lua_pushnil(luaState); } } else if (member.MemberType == MemberTypes.Property) { var property = (PropertyInfo)member; if (cachedMember.IsNull()) { setMemberCache(memberCache, objType, methodName, member); } try { object val = property.GetValue(obj, null); translator.push(luaState, val); } catch (ArgumentException) { // If we can't find the getter in our class, recurse up to the base class and see // if they can help. if (objType is Type && !(((Type)objType) == typeof(object))) { return(getMember(luaState, ((Type)objType).BaseType, obj, methodName, bindingType)); } else { LuaLib.lua_pushnil(luaState); } } catch (TargetInvocationException e) // Convert this exception into a Lua error { ThrowError(luaState, e); LuaLib.lua_pushnil(luaState); } } else if (member.MemberType == MemberTypes.Event) { var eventInfo = (EventInfo)member; if (cachedMember.IsNull()) { setMemberCache(memberCache, objType, methodName, member); } translator.push(luaState, new RegisterEventHandler(translator.pendingEvents, obj, eventInfo)); } else if (!implicitStatic) { if (member.MemberType == MemberTypes.NestedType) { // kevinh - added support for finding nested types // cache us if (cachedMember.IsNull()) { setMemberCache(memberCache, objType, methodName, member); } // Find the name of our class string name = member.Name; var dectype = member.DeclaringType; // Build a new long name and try to find the type by name string longname = dectype.FullName + "+" + name; var nestedType = translator.FindType(longname); translator.pushType(luaState, nestedType); } else { // Member type must be 'method' var wrapper = new LuaCore.lua_CFunction((new LuaMethodWrapper(translator, objType, methodName, bindingType)).call); if (cachedMember.IsNull()) { setMemberCache(memberCache, objType, methodName, wrapper); } translator.pushFunction(luaState, wrapper); translator.push(luaState, true); return(2); } } else { // If we reach this point we found a static method, but can't use it in this context because the user passed in an instance translator.throwError(luaState, "can't pass instance to static method " + methodName); LuaLib.lua_pushnil(luaState); } } else { // kevinh - we want to throw an exception because meerly 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. translator.throwError(luaState, "unknown member name " + methodName); LuaLib.lua_pushnil(luaState); } // push false because we are NOT returning a function (see luaIndexFunction) translator.push(luaState, false); return(2); }
/* * Called by the __index metafunction of CLR objects in case the * method is not cached or it is a field/property/event. * Receives the object and the member name as arguments and returns * either the value of the member or a delegate to call it. * If the member does not exist returns nil. */ private int getMethod(LuaCore.lua_State luaState) { object obj = translator.getRawNetObject(luaState, 1); if (obj.IsNull()) { translator.throwError(luaState, "trying to index an invalid object reference"); LuaLib.lua_pushnil(luaState); return(1); } object index = translator.getObject(luaState, 2); //var indexType = index.GetType(); string methodName = index as string; // will be null if not a string arg var objType = obj.GetType(); // Handle the most common case, looking up the method by name. // CP: This will fail when using indexers and attempting to get a value with the same name as a property of the object, // ie: xmlelement['item'] <- item is a property of xmlelement try { if (!methodName.IsNull() && isMemberPresent(objType, methodName)) { return(getMember(luaState, objType, obj, methodName, BindingFlags.Instance | BindingFlags.IgnoreCase)); } } catch { } // Try to access by array if the type is right and index is an int (lua numbers always come across as double) if (objType.IsArray && index is double) { int intIndex = (int)((double)index); if (objType.UnderlyingSystemType == typeof(float[])) { float[] arr = ((float[])obj); translator.push(luaState, arr[intIndex]); } else if (objType.UnderlyingSystemType == typeof(double[])) { double[] arr = ((double[])obj); translator.push(luaState, arr[intIndex]); } else if (objType.UnderlyingSystemType == typeof(int[])) { int[] arr = ((int[])obj); translator.push(luaState, arr[intIndex]); } else { object[] arr = (object[])obj; translator.push(luaState, arr[intIndex]); } } else { // Try to use get_Item to index into this .net object //MethodInfo getter = objType.GetMethod("get_Item"); var methods = objType.GetMethods(); foreach (var mInfo in methods) { if (mInfo.Name == "get_Item") { //check if the signature matches the input if (mInfo.GetParameters().Length == 1) { var getter = mInfo; var actualParms = (!getter.IsNull()) ? getter.GetParameters() : null; if (actualParms.IsNull() || actualParms.Length != 1) { translator.throwError(luaState, "method not found (or no indexer): " + index); LuaLib.lua_pushnil(luaState); } else { // Get the index in a form acceptable to the getter index = translator.getAsType(luaState, 2, actualParms[0].ParameterType); object[] args = new object[1]; // Just call the indexer - if out of bounds an exception will happen args[0] = index; try { object result = getter.Invoke(obj, args); translator.push(luaState, result); } catch (TargetInvocationException e) { // Provide a more readable description for the common case of key not found if (e.InnerException is KeyNotFoundException) { translator.throwError(luaState, "key '" + index + "' not found "); } else { translator.throwError(luaState, "exception indexing '" + index + "' " + e.Message); } LuaLib.lua_pushnil(luaState); } } } } } } LuaLib.lua_pushboolean(luaState, false); return(2); }