//~LuaFunction() //{ // if (reference != 0) // interpreter.dispose(reference); //} //bool disposed = false; //~LuaFunction() //{ // Dispose(false); //} //public void Dispose() //{ // Dispose(true); // GC.SuppressFinalize(this); //} //public virtual void Dispose(bool disposeManagedResources) //{ // if (!this.disposed) // { // if (disposeManagedResources) // { // if (_Reference != 0) // _Interpreter.dispose(_Reference); // } // disposed = true; // } //} /* * Calls the function casting return values to the types * in returnTypes */ internal object[] call(object[] args, Type[] returnTypes) { //return _Interpreter.callFunction(this, args, returnTypes); int nArgs = 0; int oldTop = LuaDLL.lua_gettop(L); if (!LuaDLL.lua_checkstack(L, args.Length + 6)) { throw new LuaException("Lua stack overflow"); } translator.push(L, this); if (args != null) { nArgs = args.Length; for (int i = 0; i < args.Length; i++) { translator.push(L, args[i]); } } int error = LuaDLL.lua_pcall(L, nArgs, -1, 0); if (error != 0) { ThrowExceptionFromError(oldTop); } if (returnTypes != null) { return(translator.popValues(L, oldTop, returnTypes)); } else { return(translator.popValues(L, oldTop)); } }
/* * Indexer for global variables from the LuaInterpreter * Supports navigation of tables by using . operator */ public object this[string fullPath] { get { object returnValue = null; int oldTop = LuaLib.lua_gettop(luaState); string[] path = fullPath.Split(new char[] { '.' }); LuaLib.lua_getglobal(luaState, path[0]); returnValue = translator.getObject(luaState, -1); if (path.Length > 1) { string[] remainingPath = new string[path.Length - 1]; Array.Copy(path, 1, remainingPath, 0, path.Length - 1); returnValue = getObject(remainingPath); } LuaLib.lua_settop(luaState, oldTop); return(returnValue); } set { int oldTop = LuaLib.lua_gettop(luaState); string[] path = fullPath.Split(new char[] { '.' }); if (path.Length == 1) { translator.push(luaState, value); LuaLib.lua_setglobal(luaState, fullPath); } else { LuaLib.lua_getglobal(luaState, path[0]); string[] remainingPath = new string[path.Length - 1]; Array.Copy(path, 1, remainingPath, 0, path.Length - 1); setObject(remainingPath, value); } LuaLib.lua_settop(luaState, oldTop); // Globals auto-complete if (value.IsNull()) { // Remove now obsolete entries globals.Remove(fullPath); } else { // Add new entries if (!globals.Contains(fullPath)) { registerGlobal(fullPath, value.GetType(), 0); } } } }
/* * Indexer for global variables from the LuaInterpreter * Supports navigation of tables by using . operator */ public object this[string fullPath] { get { object returnValue = null; int oldTop = LuaDLL.lua_gettop(L); string[] path = fullPath.Split(new char[] { '.' }); LuaDLL.lua_getglobal(L, path[0]); returnValue = translator.getObject(L, -1); if (path.Length > 1) { string[] remainingPath = new string[path.Length - 1]; Array.Copy(path, 1, remainingPath, 0, path.Length - 1); returnValue = getObject(remainingPath); } LuaDLL.lua_settop(L, oldTop); return(returnValue); } set { int oldTop = LuaDLL.lua_gettop(L); string[] path = fullPath.Split(new char[] { '.' }); if (path.Length == 1) { translator.push(L, value); LuaDLL.lua_setglobal(L, fullPath); } else { LuaDLL.lua_getglobal(L, path[0]); string[] remainingPath = new string[path.Length - 1]; Array.Copy(path, 1, remainingPath, 0, path.Length - 1); setObject(remainingPath, value); } LuaDLL.lua_settop(L, oldTop); // Globals auto-complete // comment by topameng, too many time cost, you shound register you type in other position /*if (value == null) * { * // Remove now obsolete entries * globals.Remove(fullPath); * } * else * { * // Add new entries * if (!globals.Contains(fullPath)) * registerGlobal(fullPath, value.GetType(), 0); * }*/ } }
//int BeginPCall() //{ // LuaDLL.lua_getglobal(L, "traceback"); // int oldTop = LuaDLL.lua_gettop(L); // push(L); // return oldTop; //} //bool PCall(int oldTop, int args) //{ // if (LuaDLL.lua_pcall(L, args, -1, -args - 2) != 0) // { // string err = LuaDLL.lua_tostring(L, -1); // LuaDLL.lua_settop(L, oldTop); // LuaDLL.lua_pop(L, 1); // if (err == null) err = "Unknown Lua Error"; // throw new LuaScriptException(err.ToString(), ""); // } // return true; //} //object[] EndPCall(int oldTop) //{ // object[] ret = translator.popValues(L, oldTop); // LuaDLL.lua_pop(L, 1); // return ret; //} //public object[] Call() //{ // int oldTop = BeginPCall(); // if (PCall(oldTop, 0)) // { // return EndPCall(oldTop); // } // return null; //} //public object[] Call<T1>(T1 t1) //{ // int oldTop = BeginPCall(); // PushArgs(L, t1); // if (PCall(oldTop, 1)) // { // return EndPCall(oldTop); // } // return null; //} //public object[] Call<T1, T2>(T1 t1, T2 t2) //{ // int oldTop = BeginPCall(); // PushArgs(L, t1); // PushArgs(L, t2); // if (PCall(oldTop, 2)) // { // return EndPCall(oldTop); // } // return null; //} //public object[] Call<T1, T2, T3>(T1 t1, T2 t2, T3 t3) //{ // int oldTop = BeginPCall(); // PushArgs(L, t1); // PushArgs(L, t2); // PushArgs(L, t3); // if (PCall(oldTop, 3)) // { // return EndPCall(oldTop); // } // return null; //} //public object[] Call<T1, T2, T3, T4>(T1 t1, T2 t2, T3 t3, T4 t4) //{ // int oldTop = BeginPCall(); // PushArgs(L, t1); // PushArgs(L, t2); // PushArgs(L, t3); // PushArgs(L, t4); // if (PCall(oldTop, 4)) // { // return EndPCall(oldTop); // } // return null; //} //public object[] Call<T1, T2, T3, T4, T5>(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5) //{ // int oldTop = BeginPCall(); // PushArgs(L, t1); // PushArgs(L, t2); // PushArgs(L, t3); // PushArgs(L, t4); // PushArgs(L, t5); // if (PCall(oldTop, 5)) // { // return EndPCall(oldTop); // } // return null; //} void PushArgs(IntPtr L, object o) { if (o == null) { LuaScriptMgr.PushObject(L, o); return; } Type type = o.GetType(); if (type.IsArray) { LuaScriptMgr.PushArray(L, o); } else if (type.IsEnum) { LuaScriptMgr.PushEnum(L, o); } else { translator.push(L, o); } }
public static int getClassMethod(IntPtr luaState) { ObjectTranslator objectTranslator = ObjectTranslator.FromState(luaState); object rawNetObject = objectTranslator.getRawNetObject(luaState, 1); if (rawNetObject == null || !(rawNetObject is IReflect)) { objectTranslator.throwError(luaState, "trying to index an invalid type reference"); LuaDLL.lua_pushnil(luaState); return(1); } IReflect reflect = (IReflect)rawNetObject; if (LuaDLL.lua_isnumber(luaState, 2)) { int length = (int)LuaDLL.lua_tonumber(luaState, 2); objectTranslator.push(luaState, Array.CreateInstance(reflect.UnderlyingSystemType, length)); return(1); } string text = LuaDLL.lua_tostring(luaState, 2); if (text == null) { LuaDLL.lua_pushnil(luaState); return(1); } return(objectTranslator.metaFunctions.getMember(luaState, reflect, null, text, BindingFlags.IgnoreCase | BindingFlags.Static | BindingFlags.FlattenHierarchy)); }
public object this[string fullPath] { get { object returnValue = null; int oldTop = LuaAPI.lua_gettop(L); string[] path = fullPath.Split(new char[] { '.' }); LuaAPI.lua_getglobal(L, path[0]); returnValue = translator.getObject(L, -1); if (path.Length > 1) { string[] remainingPath = new string[path.Length - 1]; Array.Copy(path, 1, remainingPath, 0, path.Length - 1); returnValue = getObject(remainingPath); } LuaAPI.lua_settop(L, oldTop); return(returnValue); } set { int oldTop = LuaAPI.lua_gettop(L); string[] path = fullPath.Split(new char[] { '.' }); if (path.Length == 1) { translator.push(L, value); LuaAPI.lua_setglobal(L, fullPath); } else { LuaAPI.lua_getglobal(L, path[0]); LuaTypes type = LuaAPI.lua_type(L, -1); if (type == LuaTypes.LUA_TNIL) { Debugger.LogError("Table {0} not exists", path[0]); LuaAPI.lua_settop(L, oldTop); return; } string[] remainingPath = new string[path.Length - 1]; Array.Copy(path, 1, remainingPath, 0, path.Length - 1); setObject(remainingPath, value); } LuaAPI.lua_settop(L, oldTop); } }
public static int callConstructor(IntPtr luaState) { ObjectTranslator translator = ObjectTranslator.FromState(luaState); MethodCache validConstructor = new MethodCache(); IReflect klass; object obj = translator.getRawNetObject(luaState, 1); if (obj == null || !(obj is IReflect)) { translator.throwError(luaState, "trying to call constructor on an invalid type reference"); LuaDLL.lua_pushnil(luaState); return(1); } else { klass = (IReflect)obj; } LuaDLL.lua_remove(luaState, 1); ConstructorInfo[] constructors = klass.UnderlyingSystemType.GetConstructors(); foreach (ConstructorInfo constructor in constructors) { bool isConstructor = translator.metaFunctions.matchParameters(luaState, constructor, ref validConstructor); if (isConstructor) { try { translator.push(luaState, constructor.Invoke(validConstructor.args)); } catch (TargetInvocationException e) { translator.metaFunctions.ThrowError(luaState, e); LuaDLL.lua_pushnil(luaState); } catch { LuaDLL.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)); LuaDLL.lua_pushnil(luaState); return(1); }
public static int toString(IntPtr luaState) { ObjectTranslator objectTranslator = ObjectTranslator.FromState(luaState); object rawNetObject = objectTranslator.getRawNetObject(luaState, 1); if (rawNetObject != null) { objectTranslator.push(luaState, rawNetObject.ToString() + ": " + rawNetObject.GetHashCode()); } else { LuaDLL.lua_pushnil(luaState); } return(1); }
public static int toString(IntPtr luaState) { ObjectTranslator translator = ObjectTranslator.FromState(luaState); object obj = translator.getRawNetObject(luaState, 1); if (obj != null) { translator.push(luaState, obj.ToString() + ": " + obj.GetHashCode()); } else { LuaDLL.lua_pushnil(luaState); } return(1); }
public static int callConstructor(IntPtr luaState) { ObjectTranslator objectTranslator = ObjectTranslator.FromState(luaState); MethodCache methodCache = default(MethodCache); object rawNetObject = objectTranslator.getRawNetObject(luaState, 1); if (rawNetObject == null || !(rawNetObject is IReflect)) { LuaDLL.luaL_error(luaState, "trying to call constructor on an invalid type reference"); LuaDLL.lua_pushnil(luaState); return(1); } IReflect reflect = (IReflect)rawNetObject; LuaDLL.lua_remove(luaState, 1); ConstructorInfo[] constructors = reflect.UnderlyingSystemType.GetConstructors(); ConstructorInfo[] array = constructors; for (int i = 0; i < array.Length; i++) { ConstructorInfo constructorInfo = array[i]; bool flag = objectTranslator.metaFunctions.matchParameters(luaState, constructorInfo, ref methodCache); if (flag) { try { objectTranslator.push(luaState, constructorInfo.Invoke(methodCache.args)); } catch (TargetInvocationException e) { objectTranslator.metaFunctions.ThrowError(luaState, e); LuaDLL.lua_pushnil(luaState); } catch { LuaDLL.lua_pushnil(luaState); } return(1); } } string arg = (constructors.Length != 0) ? constructors[0].Name : "unknown"; LuaDLL.luaL_error(luaState, string.Format("{0} does not contain constructor({1}) argument match", reflect.UnderlyingSystemType, arg)); LuaDLL.lua_pushnil(luaState); return(1); }
/* * Indexer for global variables from the LuaInterpreter * Supports navigation of tables by using . operator */ public object this[string fullPath] { get { object returnValue = null; int oldTop = LuaDLL.lua_gettop(luaState); string[] path = fullPath.Split(new char[] { '.' }); LuaDLL.lua_getglobal(luaState, path[0]); returnValue = translator.getObject(luaState, -1); if (path.Length > 1) { string[] remainingPath = new string[path.Length - 1]; Array.Copy(path, 1, remainingPath, 0, path.Length - 1); returnValue = getObject(remainingPath); } LuaDLL.lua_settop(luaState, oldTop); return(returnValue); } set { int oldTop = LuaDLL.lua_gettop(luaState); string[] path = fullPath.Split(new char[] { '.' }); if (path.Length == 1) { translator.push(luaState, value); LuaDLL.lua_setglobal(luaState, fullPath); } else { LuaDLL.lua_getglobal(luaState, path[0]); string[] remainingPath = new string[path.Length - 1]; Array.Copy(path, 1, remainingPath, 0, path.Length - 1); setObject(remainingPath, value); } LuaDLL.lua_settop(luaState, oldTop); } }
public static int getClassMethod(IntPtr luaState) { ObjectTranslator translator = ObjectTranslator.FromState(luaState); IReflect klass; object obj = translator.getRawNetObject(luaState, 1); if (obj == null || !(obj is IReflect)) { translator.throwError(luaState, "trying to index an invalid type reference"); LuaDLL.lua_pushnil(luaState); return(1); } else { klass = (IReflect)obj; } if (LuaDLL.lua_isnumber(luaState, 2)) { int size = (int)LuaDLL.lua_tonumber(luaState, 2); translator.push(luaState, Array.CreateInstance(klass.UnderlyingSystemType, size)); return(1); } else { string methodName = LuaDLL.lua_tostring(luaState, 2); if (methodName == null) { LuaDLL.lua_pushnil(luaState); return(1); } //CP: Ignore case else { return(translator.metaFunctions.getMember(luaState, klass, null, methodName, BindingFlags.FlattenHierarchy | BindingFlags.Static | BindingFlags.IgnoreCase)); } } }
/* * Calls the method. Receives the arguments from the Lua stack * and returns values in it. */ public int call(IntPtr 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; if (numArgsPassed == lastCalledMethod.argTypes.Length) // No. of args match? { if (!LuaDLL.lua_checkstack(luaState, lastCalledMethod.outList.Length + 6)) { throw new LuaException("Lua stack overflow"); } try { for (int i = 0; i < lastCalledMethod.argTypes.Length; i++) { lastCalledMethod.args[lastCalledMethod.argTypes[i].index] = lastCalledMethod.argTypes[i].extractValue(luaState, i + 1 + numStackToSkip); if (lastCalledMethod.args[lastCalledMethod.argTypes[i].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, 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)); } } 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.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++; //for(int i=0;i<lastCalledMethod.outList.Length;i++) translator.push(luaState, lastCalledMethod.args[lastCalledMethod.outList[index]]); } return(nReturnValues < 1 ? 1 : nReturnValues); }
/* * Excutes a Lua file and returns all the chunk's return * values in an array */ public object[] DoFile(string fileName, LuaTable env) { LuaDLL.lua_pushstdcallcfunction(L, tracebackFunction); int oldTop = LuaDLL.lua_gettop(L); // Load with Unity3D resources byte[] text = LuaStatic.LoadLua(fileName); if (text == null) { ThrowExceptionFromError(oldTop); } //Encoding.UTF8.GetByteCount(text) if (LuaDLL.luaL_loadbuffer(L, text, text.Length, fileName) == 0) { if (env != null) { env.push(L); //LuaDLL.lua_setfenv(L, -1); LuaDLL.lua_setfenv(L, -2); } // lxc Test添加文件名参数作为模块名字 string moduleName = Path.GetFileNameWithoutExtension(fileName); translator.push(L, moduleName); //if (LuaDLL.lua_pcall(L, 0, -1, -2) == 0) if (LuaDLL.lua_pcall(L, 1, -1, -2) == 0) { object[] results = translator.popValues(L, oldTop); LuaDLL.lua_pop(L, 1); return(results); } else { ThrowExceptionFromError(oldTop); } } else { ThrowExceptionFromError(oldTop); } return(null); // Never reached - keeps compiler happy }
/* * 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(IntPtr 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 LuaCSFunction) { translator.pushFunction(luaState, (LuaCSFunction)cachedMember); translator.push(luaState, true); return(2); } else if (cachedMember != null) { member = (MemberInfo)cachedMember; } else { //CP: Removed NonPublic binding search MemberInfo[] 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 != 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' LuaCSFunction wrapper = new LuaCSFunction((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); }
public static int getMethod(IntPtr luaState) { ObjectTranslator translator = ObjectTranslator.FromState(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(); //* not used 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. // 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 != null && translator.metaFunctions.isMemberPresent(objType, methodName)) { return(translator.metaFunctions.getMember(luaState, objType, obj, methodName, BindingFlags.Instance | BindingFlags.IgnoreCase)); } } catch { } bool failed = true; // 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); Array aa = obj as Array; if (intIndex >= aa.Length) { return(translator.pushError(luaState, "array index out of bounds: " + intIndex + " " + aa.Length)); } object val = aa.GetValue(intIndex); translator.push(luaState, val); failed = false; } else { // Try to use get_Item to index into this .net object //MethodInfo getter = objType.GetMethod("get_Item"); // issue here is that there may be multiple indexers.. MethodInfo[] methods = objType.GetMethods(); foreach (MethodInfo mInfo in methods) { if (mInfo.Name == "get_Item") { //check if the signature matches the input if (mInfo.GetParameters().Length == 1) { MethodInfo getter = mInfo; ParameterInfo[] actualParms = (getter != null) ? getter.GetParameters() : null; if (actualParms == null || actualParms.Length != 1) { return(translator.pushError(luaState, "method not found (or no indexer): " + index)); } else { // Get the index in a form acceptable to the getter index = translator.getAsType(luaState, 2, actualParms[0].ParameterType); // Just call the indexer - if out of bounds an exception will happen try { object result = getter.Invoke(obj, new object[] { index }); translator.push(luaState, result); failed = false; } catch (TargetInvocationException e) { // Provide a more readable description for the common case of key not found if (e.InnerException is KeyNotFoundException) { return(translator.pushError(luaState, "key '" + index + "' not found ")); } else { return(translator.pushError(luaState, "exception indexing '" + index + "' " + e.Message)); } } } } } } } if (failed) { return(translator.pushError(luaState, "cannot find " + index)); } LuaDLL.lua_pushboolean(luaState, false); return(2); }
public static int getMethod(IntPtr luaState) { ObjectTranslator objectTranslator = ObjectTranslator.FromState(luaState); object rawNetObject = objectTranslator.getRawNetObject(luaState, 1); if (rawNetObject == null) { objectTranslator.throwError(luaState, "trying to index an invalid object reference"); LuaDLL.lua_pushnil(luaState); return(1); } object obj = objectTranslator.getObject(luaState, 2); string text = obj as string; Type type = rawNetObject.GetType(); try { if (text != null && objectTranslator.metaFunctions.isMemberPresent(type, text)) { int result = objectTranslator.metaFunctions.getMember(luaState, type, rawNetObject, text, BindingFlags.IgnoreCase | BindingFlags.Instance); return(result); } } catch { } bool flag = true; if (type.IsArray && obj is double) { int num = (int)((double)obj); Array array = rawNetObject as Array; if (num >= array.Length) { return(objectTranslator.pushError(luaState, string.Concat(new object[] { "array index out of bounds: ", num, " ", array.Length }))); } object value = array.GetValue(num); objectTranslator.push(luaState, value); flag = false; } else { MethodInfo[] methods = type.GetMethods(); MethodInfo[] array2 = methods; for (int i = 0; i < array2.Length; i++) { MethodInfo methodInfo = array2[i]; if (methodInfo.Name == "get_Item" && methodInfo.GetParameters().Length == 1) { MethodInfo methodInfo2 = methodInfo; ParameterInfo[] array3 = (methodInfo2 == null) ? null : methodInfo2.GetParameters(); if (array3 == null || array3.Length != 1) { return(objectTranslator.pushError(luaState, "method not found (or no indexer): " + obj)); } obj = objectTranslator.getAsType(luaState, 2, array3[0].ParameterType); try { object o = methodInfo2.Invoke(rawNetObject, new object[] { obj }); objectTranslator.push(luaState, o); flag = false; } catch (TargetInvocationException ex) { int result; if (ex.InnerException is KeyNotFoundException) { result = objectTranslator.pushError(luaState, "key '" + obj + "' not found "); return(result); } result = objectTranslator.pushError(luaState, string.Concat(new object[] { "exception indexing '", obj, "' ", ex.Message })); return(result); } } } } if (flag) { return(objectTranslator.pushError(luaState, "cannot find " + obj)); } LuaDLL.lua_pushboolean(luaState, false); return(2); }
public int call(IntPtr luaState) { object targetObject; bool failedCall = true; int nReturnValues = 0; if (!LuaAPI.lua_checkstack(luaState, 5)) { throw new LuaException("Lua stack overflow"); } bool isStatic = (_BindingType & BindingFlags.Static) == BindingFlags.Static; SetPendingException(null); if (isStatic) { targetObject = null; } else { targetObject = _ExtractTarget(luaState, 1); } 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 = LuaAPI.lua_gettop(luaState) - numStackToSkip; MethodBase method = _LastCalledMethod.cachedMethod; if (numArgsPassed == _LastCalledMethod.argTypes.Length) // No. of args match? { if (!LuaAPI.lua_checkstack(luaState, _LastCalledMethod.outList.Length + 6)) { throw new LuaException("Lua stack overflow"); } //这里 args 只是将 _LastCalledMethod.args 拿来做缓冲区用,避免内存再分配, 里面的值是可以干掉的 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 && !LuaAPI.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) { return(SetPendingException(e.GetBaseException())); } catch (Exception e) { if (_Members.Length == 1) { return(SetPendingException(e)); } } } } // Cache miss if (failedCall) { if (!isStatic) { if (targetObject == null) { _Translator.throwError(luaState, String.Format("instance method '{0}' requires a non null target object", _MethodName)); LuaAPI.lua_pushnil(luaState); return(1); } LuaAPI.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); LuaAPI.luaL_error(luaState, msg); LuaAPI.lua_pushnil(luaState); ClearCachedArgs(); return(1); } } if (failedCall) { if (!LuaAPI.lua_checkstack(luaState, _LastCalledMethod.outList.Length + 6)) { ClearCachedArgs(); 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) { ClearCachedArgs(); return(SetPendingException(e.GetBaseException())); } catch (Exception e) { ClearCachedArgs(); 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]]); } //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++; } ClearCachedArgs(); return(nReturnValues < 1 ? 1 : nReturnValues); }
/* * __tostring metafunction of CLR objects. */ private int toString(KopiLua.Lua.lua_State luaState) { object obj = translator.getRawNetObject(luaState, 1); if (obj != null) { translator.push(luaState, obj.ToString() + ": " + obj.GetHashCode()); } else { LuaDLL.lua_pushnil(luaState); } return(1); }
/// <summary>[-0, +2, e] /// 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. /// </summary> int getMethod(lua.State L) { Debug.Assert(interpreter.IsSameLua(L) && luanet.infunction(L)); object obj = luaclr.checkref(L, 1); object index = translator.getObject(L, 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. // 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 if (methodName != null && isMemberPresent(objType, methodName)) { return(getMember(L, objType, obj, methodName, BindingFlags.Instance)); } bool failed = true; // 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 val; try { val = ((Array)obj).GetValue((int)(double)index); } catch (Exception ex) { return(translator.throwError(L, ex)); } translator.push(L, val); failed = false; } else { try { // Try to use get_Item to index into this .net object //MethodInfo getter = objType.GetMethod("get_Item"); // issue here is that there may be multiple indexers.. foreach (MethodInfo mInfo in objType.GetMethods()) { if (mInfo.Name == "get_Item") { ParameterInfo[] actualParms = mInfo.GetParameters(); if (actualParms.Length != 1) //check if the signature matches the input { continue; } if (!translator.memberIsAllowed(mInfo)) { continue; } // Get the index in a form acceptable to the getter index = translator.getAsType(L, 2, actualParms[0].ParameterType); // Just call the indexer - if out of bounds an exception will happen object o = mInfo.Invoke(obj, new[] { index }); failed = false; translator.push(L, o); break; } } } catch (TargetInvocationException ex) { return(translator.throwError(L, luaclr.verifyex(ex.InnerException))); } catch (LuaInternalException) { throw; } catch (Exception ex) { return(luaL.error(L, "unable to index {0}: {1}", objType, ex.Message)); } } if (failed) { return(luaL.error(L, "cannot find " + index)); } lua.pushboolean(L, false); return(2); }
/* * __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); }
/* * 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); }
/// <summary> /// Implementation of get_object_member. 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. /// </summary> int getMethod(lua.State L) { Debug.Assert(translator.interpreter.IsSameLua(L) && luanet.infunction(L)); object obj = luaclr.checkref(L, 1); object index = translator.getObject(L, 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. // 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 { // todo: investigate: getMember throws lua errors. all other call sites are also CFunctions and do not use try{}. // possible reasons: (1) the author didn't know that Lua errors pass through catch{} // (2) it is passing unusual input that might generate exceptions not seen in the other use cases // (3) it is a hasty fix for a bug if (methodName != null && isMemberPresent(objType, methodName)) { return(getMember(L, objType, obj, methodName, BindingFlags.Instance)); } } catch { } bool failed = true; // 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); var aa = (Array)obj; if (intIndex >= aa.Length) { return(pushError(L, "array index out of bounds: " + intIndex + " " + aa.Length)); } object val = aa.GetValue(intIndex); translator.push(L, val); failed = false; } else { // Try to use get_Item to index into this .net object //MethodInfo getter = objType.GetMethod("get_Item"); // issue here is that there may be multiple indexers.. foreach (MethodInfo mInfo in objType.GetMethods()) { if (mInfo.Name == "get_Item") { ParameterInfo[] actualParms = mInfo.GetParameters(); if (actualParms.Length != 1) //check if the signature matches the input { continue; } // Get the index in a form acceptable to the getter index = translator.getAsType(L, 2, actualParms[0].ParameterType); // Just call the indexer - if out of bounds an exception will happen try { translator.push(L, mInfo.Invoke(obj, new[] { index })); failed = false; } catch (TargetInvocationException e) { // Provide a more readable description for the common case of key not found if (e.InnerException is KeyNotFoundException) { return(pushError(L, "key '" + index + "' not found ")); } else { return(pushError(L, "exception indexing '" + index + "' " + e.InnerException.Message)); } } } } } if (failed) { return(pushError(L, "cannot find " + index)); } lua.pushboolean(L, false); return(2); }