public Lua() { luaState = LuaDLL.luaL_newstate(); // steffenj: Lua 5.1.1 API change (lua_open is gone) //LuaDLL.luaopen_base(luaState); // steffenj: luaopen_* no longer used LuaDLL.luaL_openlibs(luaState); // steffenj: Lua 5.1.1 API change (luaopen_base is gone, just open all libs right here) LuaDLL.lua_pushstring(luaState, "LUAINTERFACE LOADED"); LuaDLL.lua_pushboolean(luaState, true); LuaDLL.lua_settable(luaState, (int) LuaIndexes.LUA_REGISTRYINDEX); LuaDLL.lua_newtable(luaState); LuaDLL.lua_setglobal(luaState, "luanet"); LuaDLL.lua_pushvalue(luaState, (int)LuaIndexes.LUA_GLOBALSINDEX); LuaDLL.lua_getglobal(luaState, "luanet"); LuaDLL.lua_pushstring(luaState, "getmetatable"); LuaDLL.lua_getglobal(luaState, "getmetatable"); LuaDLL.lua_settable(luaState, -3); LuaDLL.lua_replace(luaState, (int)LuaIndexes.LUA_GLOBALSINDEX); translator=new ObjectTranslator(this,luaState); LuaDLL.lua_replace(luaState, (int)LuaIndexes.LUA_GLOBALSINDEX); LuaDLL.luaL_dostring(luaState, Lua.init_luanet); // steffenj: lua_dostring renamed to luaL_dostring // We need to keep this in a managed reference so the delegate doesn't get garbage collected panicCallback = new KopiLua.Lua.lua_CFunction(PanicCallback); LuaDLL.lua_atpanic(luaState, panicCallback); // LuaDLL.lua_atlock(luaState, lockCallback = new KopiLua.Lua.lua_CFunction(LockCallback)); // LuaDLL.lua_atunlock(luaState, unlockCallback = new KopiLua.Lua.lua_CFunction(UnlockCallback)); }
public object getAsNetObject(KopiLua.Lua.lua_State luaState, int stackPos) { object obj = translator.getNetObject(luaState, stackPos); if (obj == null && LuaDLL.lua_type(luaState, stackPos) == LuaTypes.LUA_TTABLE) { if (LuaDLL.luaL_getmetafield(luaState, stackPos, "__index")) { if (LuaDLL.luaL_checkmetatable(luaState, -1)) { LuaDLL.lua_insert(luaState, stackPos); LuaDLL.lua_remove(luaState, stackPos + 1); obj = translator.getNetObject(luaState, stackPos); } else { LuaDLL.lua_settop(luaState, -2); } } } return(obj); }
/// <summary> /// Debug tool to dump the lua stack /// </summary> /// FIXME, move somewhere else public static void dumpStack(ObjectTranslator translator, KopiLua.Lua.lua_State luaState) { int depth = LuaDll.lua_gettop(luaState); Debug.WriteLine("lua stack depth: " + depth); for (int i = 1; i <= depth; i++) { LuaTypes type = LuaDll.lua_type(luaState, i); // we dump stacks when deep in calls, calling typename while the stack is in flux can fail sometimes, so manually check for key types string typestr = (type == LuaTypes.LUA_TTABLE) ? "table" : LuaDll.lua_typename(luaState, type); string strrep = LuaDll.lua_tostring(luaState, i); if (type == LuaTypes.LUA_TUSERDATA) { object obj = translator.getRawNetObject(luaState, i); strrep = obj.ToString(); } Debug.WriteLine("{0}: ({1}) {2}", i, typestr, strrep); //Debug.Print("{0}: ({1}) {2}", i, typestr, strrep); } }
private int enumFromInt(KopiLua.Lua.lua_State luaState) { Type t = typeOf(luaState, 1); if (t == null || !t.IsEnum) { return(pushError(luaState, "not an enum")); } object res = null; LuaTypes lt = LuaDLL.lua_type(luaState, 2); if (lt == LuaTypes.LUA_TNUMBER) { int ival = (int)LuaDLL.lua_tonumber(luaState, 2); res = Enum.ToObject(t, ival); } else if (lt == LuaTypes.LUA_TSTRING) { string sflags = LuaDLL.lua_tostring(luaState, 2); string err = null; try { res = Enum.Parse(t, sflags); } catch (ArgumentException e) { err = e.Message; } if (err != null) { return(pushError(luaState, err)); } } else { return(pushError(luaState, "second argument must be a integer or a string")); } pushObject(luaState, res, "luaNet_metatable"); return(1); }
/* * Passes errors (argument e) to the Lua interpreter */ internal void throwError(KopiLua.Lua.lua_State luaState, object e) { // If the argument is a mere string, we are free to add extra info to it (as opposed to some private C# exception object or somesuch, which we just pass up) if (e is string) { // We use this to remove anything pushed by luaL_where int oldTop = LuaDLL.lua_gettop(luaState); // Stack frame #1 is our C# wrapper, so not very interesting to the user // Stack frame #2 must be the lua code that called us, so that's what we want to use LuaDLL.luaL_where(luaState, 2); object[] curlev = popValues(luaState, oldTop); // Debug.WriteLine(curlev); if (curlev.Length > 0) { e = curlev[0].ToString() + e; } } push(luaState, e); LuaDLL.lua_error(luaState); }
/* * Implementation of free_object. Clears the metatable and the * base field, freeing the created object for garbage-collection */ private int unregisterTable(KopiLua.Lua.lua_State luaState) { try { if (LuaDLL.lua_getmetatable(luaState, 1) != 0) { LuaDLL.lua_pushstring(luaState, "__index"); LuaDLL.lua_gettable(luaState, -2); object obj = getRawNetObject(luaState, -1); if (obj == null) { throwError(luaState, "unregister_table: arg is not valid table"); } FieldInfo luaTableField = obj.GetType().GetField("__luaInterface_luaTable"); if (luaTableField == null) { throwError(luaState, "unregister_table: arg is not valid table"); } luaTableField.SetValue(obj, null); LuaDLL.lua_pushnil(luaState); LuaDLL.lua_setmetatable(luaState, 1); LuaDLL.lua_pushstring(luaState, "base"); LuaDLL.lua_pushnil(luaState); LuaDLL.lua_settable(luaState, 1); } else { throwError(luaState, "unregister_table: arg is not valid table"); } } catch (Exception e) { throwError(luaState, e.Message); } return(0); }
public ObjectTranslator(Lua interpreter, KopiLua.Lua.lua_State luaState) { this.interpreter = interpreter; typeChecker = new CheckType(this); metaFunctions = new MetaFunctions(this); assemblies = new List <Assembly>(); importTypeFunction = new KopiLua.Lua.lua_CFunction(this.importType); loadAssemblyFunction = new KopiLua.Lua.lua_CFunction(this.loadAssembly); registerTableFunction = new KopiLua.Lua.lua_CFunction(this.registerTable); unregisterTableFunction = new KopiLua.Lua.lua_CFunction(this.unregisterTable); getMethodSigFunction = new KopiLua.Lua.lua_CFunction(this.getMethodSignature); getConstructorSigFunction = new KopiLua.Lua.lua_CFunction(this.getConstructorSignature); ctypeFunction = new KopiLua.Lua.lua_CFunction(this.ctype); enumFromIntFunction = new KopiLua.Lua.lua_CFunction(this.enumFromInt); createLuaObjectList(luaState); createIndexingMetaFunction(luaState); createBaseClassMetatable(luaState); createClassMetatable(luaState); createFunctionMetatable(luaState); setGlobalFunctions(luaState); }
/* * Gets the userdata in the index positon of the Lua stack. */ internal LuaUserData getUserData(KopiLua.Lua.lua_State luaState, int index) { LuaDLL.lua_pushvalue(luaState, index); return(new LuaUserData(LuaDLL.lua_ref(luaState, 1), interpreter)); }
/* * Gets the table in the index positon of the Lua stack. */ internal LuaTable getTable(KopiLua.Lua.lua_State luaState, int index) { LuaDLL.lua_pushvalue(luaState, index); return(new LuaTable(LuaDLL.lua_ref(luaState, 1), interpreter)); }
/* * Pushes a delegate into the stack */ internal void pushFunction(KopiLua.Lua.lua_State luaState, KopiLua.Lua.lua_CFunction func) { pushObject(luaState, func, "luaNet_function"); }
private object getAsTable(KopiLua.Lua.lua_State luaState, int stackPos) { return(translator.getTable(luaState, stackPos)); }
/// <summary> /// Tries to set a named property or field /// </summary> /// <param name="luaState"></param> /// <param name="targetType"></param> /// <param name="target"></param> /// <param name="bindingType"></param> /// <returns>false if unable to find the named member, true for success</returns> private bool trySetMember(KopiLua.Lua.lua_State luaState, IReflect targetType, object target, BindingFlags bindingType, out string detailMessage) { detailMessage = null; // No error yet // If not already a string just return - we don't want to call tostring - which has the side effect of // changing the lua typecode to string // Note: We don't use isstring because the standard lua C isstring considers either strings or numbers to // be true for isstring. if (LuaDLL.lua_type(luaState, 2) != LuaTypes.LUA_TSTRING) { detailMessage = "property names must be strings"; return(false); } // We only look up property names by string string fieldName = LuaDLL.lua_tostring(luaState, 2); if (fieldName == null || fieldName.Length < 1 || !(char.IsLetter(fieldName[0]) || fieldName[0] == '_')) { detailMessage = "invalid property name"; return(false); } // Find our member via reflection or the cache MemberInfo member = (MemberInfo)checkMemberCache(memberCache, targetType, fieldName); if (member == null) { MemberInfo[] members = targetType.GetMember(fieldName, bindingType | BindingFlags.Public | BindingFlags.NonPublic); if (members.Length > 0) { member = members[0]; setMemberCache(memberCache, targetType, fieldName, member); } else { detailMessage = "field or property '" + fieldName + "' does not exist"; return(false); } } if (member.MemberType == MemberTypes.Field) { FieldInfo field = (FieldInfo)member; object val = translator.getAsType(luaState, 3, field.FieldType); try { field.SetValue(target, val); } catch (Exception e) { ThrowError(luaState, e); } // We did a call return(true); } else if (member.MemberType == MemberTypes.Property) { PropertyInfo property = (PropertyInfo)member; object val = translator.getAsType(luaState, 3, property.PropertyType); try { property.SetValue(target, val, null); } catch (Exception e) { ThrowError(luaState, e); } // We did a call return(true); } detailMessage = "'" + fieldName + "' is not a .net field or property"; return(false); }
/* * 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(KopiLua.Lua.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 KopiLua.Lua.lua_CFunction) { translator.pushFunction(luaState, (KopiLua.Lua.lua_CFunction)cachedMember); translator.push(luaState, true); return(2); } else if (cachedMember != null) { member = (MemberInfo)cachedMember; } else { MemberInfo[] members = objType.GetMember(methodName, bindingType | BindingFlags.Public | 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 members = objType.GetMember(methodName, bindingType | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); if (members.Length > 0) { member = members[0]; implicitStatic = true; } } } if (member != null) { if (member.MemberType == MemberTypes.Field) { FieldInfo field = (FieldInfo)member; if (cachedMember == null) { setMemberCache(memberCache, objType, methodName, member); } try { translator.push(luaState, field.GetValue(obj)); } catch { LuaDLL.lua_pushnil(luaState); } } else if (member.MemberType == MemberTypes.Property) { PropertyInfo property = (PropertyInfo)member; if (cachedMember == null) { 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 { LuaDLL.lua_pushnil(luaState); } } catch (TargetInvocationException e) // Convert this exception into a Lua error { ThrowError(luaState, e); LuaDLL.lua_pushnil(luaState); } } else if (member.MemberType == MemberTypes.Event) { EventInfo eventInfo = (EventInfo)member; if (cachedMember == null) { 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 == null) { setMemberCache(memberCache, objType, methodName, member); } // Find the name of our class string name = member.Name; Type dectype = member.DeclaringType; // Build a new long name and try to find the type by name string longname = dectype.FullName + "+" + name; Type nestedType = translator.FindType(longname); translator.pushType(luaState, nestedType); } else { // Member type must be 'method' KopiLua.Lua.lua_CFunction wrapper = new KopiLua.Lua.lua_CFunction((new LuaMethodWrapper(translator, objType, methodName, bindingType)).call); if (cachedMember == null) { 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); LuaDLL.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); LuaDLL.lua_pushnil(luaState); } // push false because we are NOT returning a function (see luaIndexFunction) translator.push(luaState, false); return(2); }
/* * CAUTION: LuaInterface.Lua instances can't share the same lua state! */ public Lua(KopiLua.Lua.lua_State lState) { //IntPtr lState = new IntPtr(luaState); LuaDLL.lua_pushstring(lState, "LUAINTERFACE LOADED"); LuaDLL.lua_gettable(lState, (int)LuaIndexes.LUA_REGISTRYINDEX); if(LuaDLL.lua_toboolean(lState,-1)) { LuaDLL.lua_settop(lState,-2); throw new LuaException("There is already a LuaInterface.Lua instance associated with this Lua state"); } else { LuaDLL.lua_settop(lState,-2); LuaDLL.lua_pushstring(lState, "LUAINTERFACE LOADED"); LuaDLL.lua_pushboolean(lState, true); LuaDLL.lua_settable(lState, (int)LuaIndexes.LUA_REGISTRYINDEX); this.luaState=lState; LuaDLL.lua_pushvalue(lState, (int)LuaIndexes.LUA_GLOBALSINDEX); LuaDLL.lua_getglobal(lState, "luanet"); LuaDLL.lua_pushstring(lState, "getmetatable"); LuaDLL.lua_getglobal(lState, "getmetatable"); LuaDLL.lua_settable(lState, -3); LuaDLL.lua_replace(lState, (int)LuaIndexes.LUA_GLOBALSINDEX); translator=new ObjectTranslator(this, this.luaState); LuaDLL.lua_replace(lState, (int)LuaIndexes.LUA_GLOBALSINDEX); LuaDLL.luaL_dostring(lState, Lua.init_luanet); // steffenj: lua_dostring renamed to luaL_dostring } _StatePassed = true; }
//[DllImport(LUADLL,CallingConvention=CallingConvention.Cdecl)] public static void luaL_where(KopiLua.Lua.lua_State luaState, int level) { KopiLua.Lua.luaL_where(luaState, level); }
public object extractGenerated(KopiLua.Lua.lua_State luaState, int stackPos) { return(CodeGeneration.Instance.GetDelegate(delegateType, translator.getFunction(luaState, stackPos))); }
public object extractGenerated(KopiLua.Lua.lua_State luaState, int stackPos) { return(CodeGeneration.Instance.GetClassInstance(klass, translator.getTable(luaState, stackPos))); }
internal ExtractValue checkType(KopiLua.Lua.lua_State luaState, int stackPos, Type paramType) { LuaTypes luatype = LuaDLL.lua_type(luaState, stackPos); if (paramType.IsByRef) { paramType = paramType.GetElementType(); } Type underlyingType = Nullable.GetUnderlyingType(paramType); if (underlyingType != null) { paramType = underlyingType; // Silently convert nullable types to their non null requics } long runtimeHandleValue = paramType.TypeHandle.Value.ToInt64(); if (paramType.Equals(typeof(object))) { return(extractValues[runtimeHandleValue]); } //CP: Added support for generic parameters if (paramType.IsGenericParameter) { if (luatype == LuaTypes.LUA_TBOOLEAN) { return(extractValues[typeof(bool).TypeHandle.Value.ToInt64()]); } else if (luatype == LuaTypes.LUA_TSTRING) { return(extractValues[typeof(string).TypeHandle.Value.ToInt64()]); } else if (luatype == LuaTypes.LUA_TTABLE) { return(extractValues[typeof(LuaTable).TypeHandle.Value.ToInt64()]); } else if (luatype == LuaTypes.LUA_TUSERDATA) { return(extractValues[typeof(object).TypeHandle.Value.ToInt64()]); } else if (luatype == LuaTypes.LUA_TFUNCTION) { return(extractValues[typeof(LuaFunction).TypeHandle.Value.ToInt64()]); } else if (luatype == LuaTypes.LUA_TNUMBER) { return(extractValues[typeof(double).TypeHandle.Value.ToInt64()]); } //else // suppress CS0642 ; //an unsupported type was encountered } if (LuaDLL.lua_isnumber(luaState, stackPos)) { return(extractValues[runtimeHandleValue]); } if (paramType == typeof(bool)) { if (LuaDLL.lua_isboolean(luaState, stackPos)) { return(extractValues[runtimeHandleValue]); } } else if (paramType == typeof(string)) { if (LuaDLL.lua_isstring(luaState, stackPos)) { return(extractValues[runtimeHandleValue]); } else if (luatype == LuaTypes.LUA_TNIL) { return(extractNetObject); // kevinh - silently convert nil to a null string pointer } } else if (paramType == typeof(LuaTable)) { if (luatype == LuaTypes.LUA_TTABLE) { return(extractValues[runtimeHandleValue]); } } else if (paramType == typeof(LuaUserData)) { if (luatype == LuaTypes.LUA_TUSERDATA) { return(extractValues[runtimeHandleValue]); } } else if (paramType == typeof(LuaFunction)) { if (luatype == LuaTypes.LUA_TFUNCTION) { return(extractValues[runtimeHandleValue]); } } else if (typeof(Delegate).IsAssignableFrom(paramType) && luatype == LuaTypes.LUA_TFUNCTION) { return(new ExtractValue(new DelegateGenerator(translator, paramType).extractGenerated)); } else if (paramType.IsInterface && luatype == LuaTypes.LUA_TTABLE) { return(new ExtractValue(new ClassGenerator(translator, paramType).extractGenerated)); } else if ((paramType.IsInterface || paramType.IsClass) && luatype == LuaTypes.LUA_TNIL) { // kevinh - allow nil to be silently converted to null - extractNetObject will return null when the item ain't found return(extractNetObject); } else if (LuaDLL.lua_type(luaState, stackPos) == LuaTypes.LUA_TTABLE) { if (LuaDLL.luaL_getmetafield(luaState, stackPos, "__index")) { object obj = translator.getNetObject(luaState, -1); LuaDLL.lua_settop(luaState, -2); if (obj != null && paramType.IsAssignableFrom(obj.GetType())) { return(extractNetObject); } } else { return(null); } } else { object obj = translator.getNetObject(luaState, stackPos); if (obj != null && paramType.IsAssignableFrom(obj.GetType())) { return(extractNetObject); } } return(null); }
private object getAsUserdata(KopiLua.Lua.lua_State luaState, int stackPos) { return(translator.getUserData(luaState, stackPos)); }
private object getAsFunction(KopiLua.Lua.lua_State luaState, int stackPos) { return(translator.getFunction(luaState, stackPos)); }
/* * Gets the function in the index positon of the Lua stack. */ internal LuaFunction getFunction(KopiLua.Lua.lua_State luaState, int index) { LuaDLL.lua_pushvalue(luaState, index); return(new LuaFunction(LuaDLL.lua_ref(luaState, 1), interpreter)); }
/* * Matches a method against its arguments in the Lua stack. Returns * if the match was succesful. It it was also returns the information * necessary to invoke the method. */ internal bool matchParameters(KopiLua.Lua.lua_State luaState, MethodBase method, ref MethodCache methodCache) { ExtractValue extractValue; bool isMethod = true; ParameterInfo[] paramInfo = method.GetParameters(); int currentLuaParam = 1; int nLuaParams = LuaDLL.lua_gettop(luaState); ArrayList paramList = new ArrayList(); List <int> outList = new List <int>(); List <MethodArgs> argTypes = new List <MethodArgs>(); foreach (ParameterInfo currentNetParam in paramInfo) { if (!currentNetParam.IsIn && currentNetParam.IsOut) // Skips out params { outList.Add(paramList.Add(null)); } else if (currentLuaParam > nLuaParams) // Adds optional parameters { if (currentNetParam.IsOptional) { paramList.Add(currentNetParam.DefaultValue); } else { isMethod = false; break; } } else if ((extractValue = translator.typeChecker.checkType(luaState, currentLuaParam, currentNetParam.ParameterType)) != null) // Type checking { int index = paramList.Add(extractValue(luaState, currentLuaParam)); MethodArgs methodArg = new MethodArgs(); methodArg.index = index; methodArg.extractValue = extractValue; argTypes.Add(methodArg); if (currentNetParam.ParameterType.IsByRef) { outList.Add(index); } currentLuaParam++; } // Type does not match, ignore if the parameter is optional else if (currentNetParam.IsOptional) { paramList.Add(currentNetParam.DefaultValue); } else // No match { isMethod = false; break; } } if (currentLuaParam != nLuaParams + 1) // Number of parameters does not match { isMethod = false; } if (isMethod) { methodCache.args = paramList.ToArray(); methodCache.cachedMethod = method; methodCache.outList = outList.ToArray(); methodCache.argTypes = argTypes.ToArray(); } return(isMethod); }
/* * Checks if the method matches the arguments in the Lua stack, getting * the arguments if it does. */ internal bool matchParameters(KopiLua.Lua.lua_State luaState, MethodBase method, ref MethodCache methodCache) { return(metaFunctions.matchParameters(luaState, method, ref methodCache)); }
//[DllImport(LUADLL,CallingConvention=CallingConvention.Cdecl)] public static void lua_pushlightuserdata(KopiLua.Lua.lua_State luaState, Object udata) { KopiLua.Lua.lua_pushlightuserdata(luaState, udata); }
/* * 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(KopiLua.Lua.lua_State luaState) { object obj = translator.getRawNetObject(luaState, 1); if (obj == null) { translator.throwError(luaState, "trying to index an invalid object reference"); LuaDLL.lua_pushnil(luaState); return(1); } object index = translator.getObject(luaState, 2); Type indexType = index.GetType(); string methodName = index as string; // will be null if not a string arg Type objType = obj.GetType(); // Handle the most common case, looking up the method by name if (methodName != null && isMemberPresent(objType, methodName)) { return(getMember(luaState, objType, obj, methodName, BindingFlags.Instance)); } // 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) { object[] arr = (object[])obj; translator.push(luaState, arr[(int)((double)index)]); } else { // Try to use get_Item to index into this .net object MethodInfo getter = objType.GetMethod("get_Item"); ParameterInfo[] actualParms = (getter != null) ? getter.GetParameters() : null; if (actualParms == null || actualParms.Length != 1) { translator.throwError(luaState, "method not found (or no indexer): " + index); LuaDLL.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); } LuaDLL.lua_pushnil(luaState); } } } LuaDLL.lua_pushboolean(luaState, false); return(2); }
//[DllImport(LUADLL,CallingConvention=CallingConvention.Cdecl)] public static int lua_next(KopiLua.Lua.lua_State luaState, int index) { return(KopiLua.Lua.lua_next(luaState, index)); }
/* * __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. */ private int setFieldOrProperty(KopiLua.Lua.lua_State luaState) { object target = translator.getRawNetObject(luaState, 1); if (target == null) { translator.throwError(luaState, "trying to index and invalid object reference"); return(0); } Type type = target.GetType(); // First try to look up the parameter as a property name string detailMessage; bool didMember = trySetMember(luaState, 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 && LuaDLL.lua_isnumber(luaState, 2)) { int index = (int)LuaDLL.lua_tonumber(luaState, 2); Array arr = (Array)target; object val = translator.getAsType(luaState, 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) { ParameterInfo[] args = setter.GetParameters(); Type valueType = args[1].ParameterType; // The new val ue the user specified object val = translator.getAsType(luaState, 3, valueType); Type indexType = args[0].ParameterType; object index = translator.getAsType(luaState, 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); } else { translator.throwError(luaState, detailMessage); // Pass the original message from trySetMember because it is probably best } } } #if false catch (SEHException) { // If we are seeing a C++ exception - this must actually be for Lua's private use. Let it handle it throw; } #endif catch (Exception e) { ThrowError(luaState, e); } return(0); }
/* * Pushes a type reference into the stack */ internal void pushType(KopiLua.Lua.lua_State luaState, Type t) { pushObject(luaState, new ProxyType(t), "luaNet_class"); }
/* * __call metafunction of CLR delegates, retrieves and calls the delegate. */ private int runFunctionDelegate(KopiLua.Lua.lua_State luaState) { KopiLua.Lua.lua_CFunction func = (KopiLua.Lua.lua_CFunction)translator.getRawNetObject(luaState, 1); LuaDLL.lua_remove(luaState, 1); return(func(luaState)); }
private object getAsBoolean(KopiLua.Lua.lua_State luaState, int stackPos) { return(LuaDLL.lua_toboolean(luaState, stackPos)); }
/* * Calls the method. Receives the arguments from the Lua stack * and returns values in it. */ public int call(KopiLua.Lua.lua_State luaState) { MethodBase methodToCall = _Method; object targetObject = _Target; bool failedCall = true; int nReturnValues = 0; if (!LuaDLL.lua_checkstack(luaState, 5)) { throw new LuaException("Lua stack overflow"); } bool isStatic = (_BindingType & BindingFlags.Static) == BindingFlags.Static; SetPendingException(null); if (methodToCall == null) // Method from name { if (isStatic) { targetObject = null; } else { targetObject = _ExtractTarget(luaState, 1); } //LuaDLL.lua_remove(luaState,1); // Pops the receiver if (_LastCalledMethod.cachedMethod != null) // Cached? { int numStackToSkip = isStatic ? 0 : 1; // If this is an instance invoe we will have an extra arg on the stack for the targetObject int numArgsPassed = LuaDLL.lua_gettop(luaState) - numStackToSkip; MethodBase method = _LastCalledMethod.cachedMethod; if (numArgsPassed == _LastCalledMethod.argTypes.Length) // No. of args match? { if (!LuaDLL.lua_checkstack(luaState, _LastCalledMethod.outList.Length + 6)) { throw new LuaException("Lua stack overflow"); } object[] args = _LastCalledMethod.args; try { for (int i = 0; i < _LastCalledMethod.argTypes.Length; i++) { MethodArgs type = _LastCalledMethod.argTypes[i]; object luaParamValue = type.extractValue(luaState, i + 1 + numStackToSkip); if (_LastCalledMethod.argTypes[i].isParamsArray) { args[type.index] = _Translator.tableToArray(luaParamValue, type.paramsArrayType); } else { args[type.index] = luaParamValue; } if (args[type.index] == null && !LuaDLL.lua_isnil(luaState, i + 1 + numStackToSkip)) { throw new LuaException("argument number " + (i + 1) + " is invalid"); } } if ((_BindingType & BindingFlags.Static) == BindingFlags.Static) { _Translator.push(luaState, method.Invoke(null, args)); } else { if (_LastCalledMethod.cachedMethod.IsConstructor) { _Translator.push(luaState, ((ConstructorInfo)method).Invoke(args)); } else { _Translator.push(luaState, method.Invoke(targetObject, args)); } } failedCall = false; } catch (TargetInvocationException e) { // Failure of method invocation return(SetPendingException(e.GetBaseException())); } catch (Exception e) { if (_Members.Length == 1) // Is the method overloaded? // No, throw error { return(SetPendingException(e)); } } } } // Cache miss if (failedCall) { // System.Diagnostics.Debug.WriteLine("cache miss on " + methodName); // If we are running an instance variable, we can now pop the targetObject from the stack if (!isStatic) { if (targetObject == null) { _Translator.throwError(luaState, String.Format("instance method '{0}' requires a non null target object", _MethodName)); LuaDLL.lua_pushnil(luaState); return(1); } LuaDLL.lua_remove(luaState, 1); // Pops the receiver } bool hasMatch = false; string candidateName = null; foreach (MemberInfo member in _Members) { candidateName = member.ReflectedType.Name + "." + member.Name; MethodBase m = (MethodInfo)member; bool isMethod = _Translator.matchParameters(luaState, m, ref _LastCalledMethod); if (isMethod) { hasMatch = true; break; } } if (!hasMatch) { string msg = (candidateName == null) ? "invalid arguments to method call" : ("invalid arguments to method: " + candidateName); _Translator.throwError(luaState, msg); LuaDLL.lua_pushnil(luaState); return(1); } } } else // Method from MethodBase instance { if (methodToCall.ContainsGenericParameters) { // bool isMethod = //* not used _Translator.matchParameters(luaState, methodToCall, ref _LastCalledMethod); if (methodToCall.IsGenericMethodDefinition) { //need to make a concrete type of the generic method definition List <Type> typeArgs = new List <Type>(); foreach (object arg in _LastCalledMethod.args) { typeArgs.Add(arg.GetType()); } MethodInfo concreteMethod = (methodToCall as MethodInfo).MakeGenericMethod(typeArgs.ToArray()); _Translator.push(luaState, concreteMethod.Invoke(targetObject, _LastCalledMethod.args)); failedCall = false; } else if (methodToCall.ContainsGenericParameters) { _Translator.throwError(luaState, "unable to invoke method on generic class as the current method is an open generic method"); LuaDLL.lua_pushnil(luaState); return(1); } } else { if (!methodToCall.IsStatic && !methodToCall.IsConstructor && targetObject == null) { targetObject = _ExtractTarget(luaState, 1); LuaDLL.lua_remove(luaState, 1); // Pops the receiver } if (!_Translator.matchParameters(luaState, methodToCall, ref _LastCalledMethod)) { _Translator.throwError(luaState, "invalid arguments to method call"); LuaDLL.lua_pushnil(luaState); return(1); } } } if (failedCall) { if (!LuaDLL.lua_checkstack(luaState, _LastCalledMethod.outList.Length + 6)) { throw new LuaException("Lua stack overflow"); } try { if (isStatic) { _Translator.push(luaState, _LastCalledMethod.cachedMethod.Invoke(null, _LastCalledMethod.args)); } else { if (_LastCalledMethod.cachedMethod.IsConstructor) { _Translator.push(luaState, ((ConstructorInfo)_LastCalledMethod.cachedMethod).Invoke(_LastCalledMethod.args)); } else { _Translator.push(luaState, _LastCalledMethod.cachedMethod.Invoke(targetObject, _LastCalledMethod.args)); } } } catch (TargetInvocationException e) { return(SetPendingException(e.GetBaseException())); } catch (Exception e) { return(SetPendingException(e)); } } // Pushes out and ref return values for (int index = 0; index < _LastCalledMethod.outList.Length; index++) { nReturnValues++; _Translator.push(luaState, _LastCalledMethod.args[_LastCalledMethod.outList[index]]); } //by isSingle 2010-09-10 11:26:31 //Desc: // if not return void,we need add 1, // or we will lost the function's return value // when call dotnet function like "int foo(arg1,out arg2,out arg3)" in lua code if (!_LastCalledMethod.IsReturnVoid && nReturnValues > 0) { nReturnValues++; } return(nReturnValues < 1 ? 1 : nReturnValues); }
public int pushError(KopiLua.Lua.lua_State luaState, string msg) { LuaDLL.lua_pushnil(luaState); LuaDLL.lua_pushstring(luaState, msg); return(2); }