/* * This file is part of LuaInterface. * * Copyright (C) 2003-2005 Fabio Mascarenhas de Queiroz. * Copyright (C) 2012 Megax * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ using System; using System.Threading; using System.Reflection; #if !MONOTOUCH using System.Reflection.Emit; #endif using System.Collections; using System.Collections.Generic; using LuaInterface.Method; namespace LuaInterface { /* * Dynamically generates new types from existing types and * Lua function and table values. Generated types are event handlers, * delegates, interface implementations and subclasses. * * Author: Fabio Mascarenhas * Version: 1.0 */ class CodeGeneration { private Dictionary classCollection = new Dictionary(); private Dictionary eventHandlerCollection = new Dictionary(); private Dictionary delegateCollection = new Dictionary(); private static readonly CodeGeneration instance = new CodeGeneration(); private Type eventHandlerParent = typeof(LuaEventHandler); private Type delegateParent = typeof(LuaDelegate); private Type classHelper = typeof(LuaClassHelper); private AssemblyName assemblyName; #if !MONOTOUCH private AssemblyBuilder newAssembly; private ModuleBuilder newModule; #endif private int luaClassNumber = 1; static CodeGeneration() { } private CodeGeneration() { // Create an assembly name assemblyName = new AssemblyName(); assemblyName.Name = "LuaInterface_generatedcode"; // Create a new assembly with one module. #if !MONOTOUCH newAssembly = Thread.GetDomain().DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run); newModule = newAssembly.DefineDynamicModule("LuaInterface_generatedcode"); #endif } /* * Singleton instance of the class */ public static CodeGeneration Instance { get { return instance; } } /* * Generates an event handler that calls a Lua function */ private Type GenerateEvent(Type eventHandlerType) { #if MONOTOUCH throw new NotImplementedException (" Emit not available on MonoTouch "); #else string typeName; lock(this) { typeName = "LuaGeneratedClass" + luaClassNumber; luaClassNumber++; } // Define a public class in the assembly, called typeName var myType = newModule.DefineType(typeName, TypeAttributes.Public, eventHandlerParent); // Defines the handler method. Its signature is void(object, ) var paramTypes = new Type[2]; paramTypes[0] = typeof(object); paramTypes[1] = eventHandlerType; var returnType = typeof(void); var handleMethod = myType.DefineMethod("HandleEvent", MethodAttributes.Public | MethodAttributes.HideBySig, returnType, paramTypes); // Emits the IL for the method. It loads the arguments // and calls the handleEvent method of the base class ILGenerator generator = handleMethod.GetILGenerator(); generator.Emit(OpCodes.Ldarg_0); generator.Emit(OpCodes.Ldarg_1); generator.Emit(OpCodes.Ldarg_2); var miGenericEventHandler = eventHandlerParent.GetMethod("handleEvent"); generator.Emit(OpCodes.Call, miGenericEventHandler); // returns generator.Emit(OpCodes.Ret); // creates the new type return myType.CreateType(); #endif } /* * Generates a type that can be used for instantiating a delegate * of the provided type, given a Lua function. */ private Type GenerateDelegate(Type delegateType) { #if MONOTOUCH throw new NotImplementedException ("GenerateDelegate is not available on iOS, please register your LuaDelegate type with Lua.RegisterLuaDelegateType( yourDelegate, theLuaDelegateHandler) "); #else string typeName; lock(this) { typeName = "LuaGeneratedClass" + luaClassNumber; luaClassNumber++; } // Define a public class in the assembly, called typeName var myType = newModule.DefineType(typeName, TypeAttributes.Public, delegateParent); // Defines the delegate method with the same signature as the // Invoke method of delegateType var invokeMethod = delegateType.GetMethod("Invoke"); var paramInfo = invokeMethod.GetParameters(); var paramTypes = new Type[paramInfo.Length]; var returnType = invokeMethod.ReturnType; // Counts out and ref params, for use later int nOutParams = 0; int nOutAndRefParams = 0; for(int i = 0; i < paramTypes.Length; i++) { paramTypes[i] = paramInfo[i].ParameterType; if((!paramInfo[i].IsIn) && paramInfo[i].IsOut) nOutParams++; if(paramTypes[i].IsByRef) nOutAndRefParams++; } int[] refArgs = new int[nOutAndRefParams]; var delegateMethod = myType.DefineMethod("CallFunction", invokeMethod.Attributes, returnType, paramTypes); // Generates the IL for the method ILGenerator generator = delegateMethod.GetILGenerator( ); generator.DeclareLocal(typeof(object[])); // original arguments generator.DeclareLocal(typeof(object[])); // with out-only arguments removed generator.DeclareLocal(typeof(int[])); // indexes of out and ref arguments if(!(returnType == typeof(void))) // return value generator.DeclareLocal(returnType); else generator.DeclareLocal(typeof(object)); // Initializes local variables generator.Emit(OpCodes.Ldc_I4, paramTypes.Length); generator.Emit(OpCodes.Newarr, typeof(object)); generator.Emit(OpCodes.Stloc_0); generator.Emit(OpCodes.Ldc_I4, paramTypes.Length-nOutParams); generator.Emit(OpCodes.Newarr, typeof(object)); generator.Emit(OpCodes.Stloc_1); generator.Emit(OpCodes.Ldc_I4, nOutAndRefParams); generator.Emit(OpCodes.Newarr, typeof(int)); generator.Emit(OpCodes.Stloc_2); // Stores the arguments in the local variables for(int iArgs = 0, iInArgs = 0, iOutArgs = 0; iArgs < paramTypes.Length; iArgs++) { generator.Emit(OpCodes.Ldloc_0); generator.Emit(OpCodes.Ldc_I4, iArgs); generator.Emit(OpCodes.Ldarg, iArgs+1); if(paramTypes[iArgs].IsByRef) { if(paramTypes[iArgs].GetElementType().IsValueType) { generator.Emit(OpCodes.Ldobj, paramTypes[iArgs].GetElementType()); generator.Emit(OpCodes.Box, paramTypes[iArgs].GetElementType()); } else generator.Emit(OpCodes.Ldind_Ref); } else { if(paramTypes[iArgs].IsValueType) generator.Emit(OpCodes.Box, paramTypes[iArgs]); } generator.Emit(OpCodes.Stelem_Ref); if(paramTypes[iArgs].IsByRef) { generator.Emit(OpCodes.Ldloc_2); generator.Emit(OpCodes.Ldc_I4, iOutArgs); generator.Emit(OpCodes.Ldc_I4, iArgs); generator.Emit(OpCodes.Stelem_I4); refArgs[iOutArgs] = iArgs; iOutArgs++; } if(paramInfo[iArgs].IsIn || (!paramInfo[iArgs].IsOut)) { generator.Emit(OpCodes.Ldloc_1); generator.Emit(OpCodes.Ldc_I4, iInArgs); generator.Emit(OpCodes.Ldarg, iArgs+1); if(paramTypes[iArgs].IsByRef) { if(paramTypes[iArgs].GetElementType().IsValueType) { generator.Emit(OpCodes.Ldobj, paramTypes[iArgs].GetElementType()); generator.Emit(OpCodes.Box, paramTypes[iArgs].GetElementType()); } else generator.Emit(OpCodes.Ldind_Ref); } else { if(paramTypes[iArgs].IsValueType) generator.Emit(OpCodes.Box, paramTypes[iArgs]); } generator.Emit(OpCodes.Stelem_Ref); iInArgs++; } } // Calls the callFunction method of the base class generator.Emit(OpCodes.Ldarg_0); generator.Emit(OpCodes.Ldloc_0); generator.Emit(OpCodes.Ldloc_1); generator.Emit(OpCodes.Ldloc_2); var miGenericEventHandler = delegateParent.GetMethod("callFunction"); generator.Emit(OpCodes.Call, miGenericEventHandler); // Stores return value if(returnType == typeof(void)) { generator.Emit(OpCodes.Pop); generator.Emit(OpCodes.Ldnull); } else if(returnType.IsValueType) { generator.Emit(OpCodes.Unbox, returnType); generator.Emit(OpCodes.Ldobj, returnType); } else generator.Emit(OpCodes.Castclass, returnType); generator.Emit(OpCodes.Stloc_3); // Stores new value of out and ref params for(int i = 0; i < refArgs.Length; i++) { generator.Emit(OpCodes.Ldarg, refArgs[i]+1); generator.Emit(OpCodes.Ldloc_0); generator.Emit(OpCodes.Ldc_I4, refArgs[i]); generator.Emit(OpCodes.Ldelem_Ref); if(paramTypes[refArgs[i]].GetElementType().IsValueType) { generator.Emit(OpCodes.Unbox, paramTypes[refArgs[i]].GetElementType()); generator.Emit(OpCodes.Ldobj, paramTypes[refArgs[i]].GetElementType()); generator.Emit(OpCodes.Stobj, paramTypes[refArgs[i]].GetElementType()); } else { generator.Emit(OpCodes.Castclass, paramTypes[refArgs[i]].GetElementType()); generator.Emit(OpCodes.Stind_Ref); } } // Returns if(!(returnType == typeof(void))) generator.Emit(OpCodes.Ldloc_3); generator.Emit(OpCodes.Ret); return myType.CreateType(); // creates the new type #endif } void GetReturnTypesFromClass (Type klass, out Type[][] returnTypes) { var classMethods = klass.GetMethods(); returnTypes = new Type[classMethods.Length][]; int i = 0; foreach(var method in classMethods) { if(klass.IsInterface) { GetReturnTypesFromMethod (method, out returnTypes[i]); i++; } else { if(!method.IsPrivate && !method.IsFinal && method.IsVirtual) { GetReturnTypesFromMethod (method, out returnTypes[i]); i++; } } } } /* * Generates an implementation of klass, if it is an interface, or * a subclass of klass that delegates its virtual methods to a Lua table. */ public void GenerateClass(Type klass, out Type newType, out Type[][] returnTypes) { #if MONOTOUCH throw new NotImplementedException (" Emit not available on MonoTouch "); #else string typeName; lock(this) { typeName = "LuaGeneratedClass" + luaClassNumber; luaClassNumber++; } TypeBuilder myType; // Define a public class in the assembly, called typeName if(klass.IsInterface) myType = newModule.DefineType(typeName, TypeAttributes.Public, typeof(object), new Type[] { klass, typeof(ILuaGeneratedType) }); else myType = newModule.DefineType(typeName, TypeAttributes.Public, klass, new Type[] { typeof(ILuaGeneratedType) }); // Field that stores the Lua table var luaTableField = myType.DefineField("__luaInterface_luaTable", typeof(LuaTable), FieldAttributes.Public); // Field that stores the return types array var returnTypesField = myType.DefineField("__luaInterface_returnTypes", typeof(Type[][]), FieldAttributes.Public); // Generates the constructor for the new type, it takes a Lua table and an array // of return types and stores them in the respective fields var constructor = myType.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard, new Type[] { typeof(LuaTable), typeof(Type[][]) }); ILGenerator generator = constructor.GetILGenerator(); generator.Emit(OpCodes.Ldarg_0); if(klass.IsInterface) generator.Emit(OpCodes.Call, typeof(object).GetConstructor(Type.EmptyTypes)); else generator.Emit(OpCodes.Call, klass.GetConstructor(Type.EmptyTypes)); generator.Emit(OpCodes.Ldarg_0); generator.Emit(OpCodes.Ldarg_1); generator.Emit(OpCodes.Stfld, luaTableField); generator.Emit(OpCodes.Ldarg_0); generator.Emit(OpCodes.Ldarg_2); generator.Emit(OpCodes.Stfld, returnTypesField); generator.Emit(OpCodes.Ret); // Generates overriden versions of the klass' public virtual methods var classMethods = klass.GetMethods(); returnTypes = new Type[classMethods.Length][]; int i = 0; foreach(var method in classMethods) { if(klass.IsInterface) { GenerateMethod(myType, method, MethodAttributes.HideBySig|MethodAttributes.Virtual|MethodAttributes.NewSlot, i, luaTableField, returnTypesField, false, out returnTypes[i]); i++; } else { if(!method.IsPrivate && !method.IsFinal && method.IsVirtual) { GenerateMethod(myType, method, (method.Attributes|MethodAttributes.NewSlot)^MethodAttributes.NewSlot, i, luaTableField, returnTypesField, true, out returnTypes[i]); i++; } } } // Generates an implementation of the __luaInterface_getLuaTable method var returnTableMethod = myType.DefineMethod("__luaInterface_getLuaTable", MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.Virtual, typeof(LuaTable), new Type[0]); myType.DefineMethodOverride(returnTableMethod, typeof(ILuaGeneratedType).GetMethod("__luaInterface_getLuaTable")); generator = returnTableMethod.GetILGenerator(); generator.Emit(OpCodes.Ldfld, luaTableField); generator.Emit(OpCodes.Ret); newType = myType.CreateType(); // Creates the type #endif } void GetReturnTypesFromMethod (MethodInfo method, out Type[] returnTypes) { var paramInfo = method.GetParameters(); var paramTypes = new Type[paramInfo.Length]; var returnTypesList = new List(); // Counts out and ref parameters, for later use, // and creates the list of return types int nOutParams = 0; int nOutAndRefParams = 0; var returnType = method.ReturnType; returnTypesList.Add(returnType); for(int i = 0; i < paramTypes.Length; i++) { paramTypes[i] = paramInfo[i].ParameterType; if((!paramInfo[i].IsIn) && paramInfo[i].IsOut) nOutParams++; if(paramTypes[i].IsByRef) { returnTypesList.Add(paramTypes[i].GetElementType()); nOutAndRefParams++; } } int[] refArgs = new int[nOutAndRefParams]; returnTypes = returnTypesList.ToArray(); } #if !MONOTOUCH /* * Generates an overriden implementation of method inside myType that delegates * to a function in a Lua table with the same name, if the function exists. If it * doesn't the method calls the base method (or does nothing, in case of interface * implementations). */ private void GenerateMethod(TypeBuilder myType, MethodInfo method, MethodAttributes attributes, int methodIndex, FieldInfo luaTableField, FieldInfo returnTypesField, bool generateBase, out Type[] returnTypes) { var paramInfo = method.GetParameters(); var paramTypes = new Type[paramInfo.Length]; var returnTypesList = new List(); // Counts out and ref parameters, for later use, // and creates the list of return types int nOutParams = 0; int nOutAndRefParams = 0; var returnType = method.ReturnType; returnTypesList.Add(returnType); for(int i = 0; i < paramTypes.Length; i++) { paramTypes[i] = paramInfo[i].ParameterType; if((!paramInfo[i].IsIn) && paramInfo[i].IsOut) nOutParams++; if(paramTypes[i].IsByRef) { returnTypesList.Add(paramTypes[i].GetElementType()); nOutAndRefParams++; } } int[] refArgs = new int[nOutAndRefParams]; returnTypes = returnTypesList.ToArray(); // Generates a version of the method that calls the base implementation // directly, for use by the base field of the table if(generateBase) { var baseMethod = myType.DefineMethod("__luaInterface_base_"+method.Name, MethodAttributes.Private|MethodAttributes.NewSlot|MethodAttributes.HideBySig, returnType, paramTypes); ILGenerator generatorBase = baseMethod.GetILGenerator(); generatorBase.Emit(OpCodes.Ldarg_0); for(int i = 0; i < paramTypes.Length; i++) generatorBase.Emit(OpCodes.Ldarg, i+1); generatorBase.Emit(OpCodes.Call, method); if(returnType == typeof(void)) generatorBase.Emit(OpCodes.Pop); generatorBase.Emit(OpCodes.Ret); } // Defines the method var methodImpl = myType.DefineMethod(method.Name, attributes, returnType, paramTypes); // If it's an implementation of an interface tells what method it // is overriding if(myType.BaseType.Equals(typeof(object))) myType.DefineMethodOverride(methodImpl, method); ILGenerator generator = methodImpl.GetILGenerator( ); generator.DeclareLocal(typeof(object[])); // original arguments generator.DeclareLocal(typeof(object[])); // with out-only arguments removed generator.DeclareLocal(typeof(int[])); // indexes of out and ref arguments if(!(returnType == typeof(void))) // return value generator.DeclareLocal(returnType); else generator.DeclareLocal(typeof(object)); // Initializes local variables generator.Emit(OpCodes.Ldc_I4, paramTypes.Length); generator.Emit(OpCodes.Newarr, typeof(object)); generator.Emit(OpCodes.Stloc_0); generator.Emit(OpCodes.Ldc_I4, paramTypes.Length-nOutParams+1); generator.Emit(OpCodes.Newarr, typeof(object)); generator.Emit(OpCodes.Stloc_1); generator.Emit(OpCodes.Ldc_I4, nOutAndRefParams); generator.Emit(OpCodes.Newarr, typeof(int)); generator.Emit(OpCodes.Stloc_2); generator.Emit(OpCodes.Ldloc_1); generator.Emit(OpCodes.Ldc_I4_0); generator.Emit(OpCodes.Ldarg_0); generator.Emit(OpCodes.Ldfld, luaTableField); generator.Emit(OpCodes.Stelem_Ref); // Stores the arguments into the local variables, as needed for(int iArgs = 0, iInArgs = 1, iOutArgs = 0; iArgs < paramTypes.Length; iArgs++) { generator.Emit(OpCodes.Ldloc_0); generator.Emit(OpCodes.Ldc_I4, iArgs); generator.Emit(OpCodes.Ldarg, iArgs+1); if(paramTypes[iArgs].IsByRef) { if(paramTypes[iArgs].GetElementType().IsValueType) { generator.Emit(OpCodes.Ldobj, paramTypes[iArgs].GetElementType()); generator.Emit(OpCodes.Box, paramTypes[iArgs].GetElementType()); } else generator.Emit(OpCodes.Ldind_Ref); } else { if(paramTypes[iArgs].IsValueType) generator.Emit(OpCodes.Box, paramTypes[iArgs]); } generator.Emit(OpCodes.Stelem_Ref); if(paramTypes[iArgs].IsByRef) { generator.Emit(OpCodes.Ldloc_2); generator.Emit(OpCodes.Ldc_I4, iOutArgs); generator.Emit(OpCodes.Ldc_I4, iArgs); generator.Emit(OpCodes.Stelem_I4); refArgs[iOutArgs] = iArgs; iOutArgs++; } if(paramInfo[iArgs].IsIn || (!paramInfo[iArgs].IsOut)) { generator.Emit(OpCodes.Ldloc_1); generator.Emit(OpCodes.Ldc_I4, iInArgs); generator.Emit(OpCodes.Ldarg, iArgs+1); if(paramTypes[iArgs].IsByRef) { if(paramTypes[iArgs].GetElementType().IsValueType) { generator.Emit(OpCodes.Ldobj, paramTypes[iArgs].GetElementType()); generator.Emit(OpCodes.Box, paramTypes[iArgs].GetElementType()); } else generator.Emit(OpCodes.Ldind_Ref); } else { if(paramTypes[iArgs].IsValueType) generator.Emit(OpCodes.Box, paramTypes[iArgs]); } generator.Emit(OpCodes.Stelem_Ref); iInArgs++; } } // Gets the function the method will delegate to by calling // the getTableFunction method of class LuaClassHelper generator.Emit(OpCodes.Ldarg_0); generator.Emit(OpCodes.Ldfld, luaTableField); generator.Emit(OpCodes.Ldstr, method.Name); generator.Emit(OpCodes.Call, classHelper.GetMethod("getTableFunction")); var lab1 = generator.DefineLabel(); generator.Emit(OpCodes.Dup); generator.Emit(OpCodes.Brtrue_S, lab1); // Function does not exist, call base method generator.Emit(OpCodes.Pop); if(!method.IsAbstract) { generator.Emit(OpCodes.Ldarg_0); for(int i = 0; i < paramTypes.Length; i++) generator.Emit(OpCodes.Ldarg, i+1); generator.Emit(OpCodes.Call, method); if(returnType == typeof(void)) generator.Emit(OpCodes.Pop); generator.Emit(OpCodes.Ret); generator.Emit(OpCodes.Ldnull); } else generator.Emit(OpCodes.Ldnull); var lab2 = generator.DefineLabel(); generator.Emit(OpCodes.Br_S, lab2); generator.MarkLabel(lab1); // Function exists, call using method callFunction of LuaClassHelper generator.Emit(OpCodes.Ldloc_0); generator.Emit(OpCodes.Ldarg_0); generator.Emit(OpCodes.Ldfld, returnTypesField); generator.Emit(OpCodes.Ldc_I4, methodIndex); generator.Emit(OpCodes.Ldelem_Ref); generator.Emit(OpCodes.Ldloc_1); generator.Emit(OpCodes.Ldloc_2); generator.Emit(OpCodes.Call, classHelper.GetMethod("callFunction")); generator.MarkLabel(lab2); // Stores the function return value if(returnType == typeof(void)) { generator.Emit(OpCodes.Pop); generator.Emit(OpCodes.Ldnull); } else if(returnType.IsValueType) { generator.Emit(OpCodes.Unbox, returnType); generator.Emit(OpCodes.Ldobj, returnType); } else generator.Emit(OpCodes.Castclass, returnType); generator.Emit(OpCodes.Stloc_3); // Sets return values of out and ref parameters for(int i = 0; i < refArgs.Length; i++) { generator.Emit(OpCodes.Ldarg, refArgs[i]+1); generator.Emit(OpCodes.Ldloc_0); generator.Emit(OpCodes.Ldc_I4, refArgs[i]); generator.Emit(OpCodes.Ldelem_Ref); if(paramTypes[refArgs[i]].GetElementType().IsValueType) { generator.Emit(OpCodes.Unbox, paramTypes[refArgs[i]].GetElementType()); generator.Emit(OpCodes.Ldobj, paramTypes[refArgs[i]].GetElementType()); generator.Emit(OpCodes.Stobj, paramTypes[refArgs[i]].GetElementType()); } else { generator.Emit(OpCodes.Castclass, paramTypes[refArgs[i]].GetElementType()); generator.Emit(OpCodes.Stind_Ref); } } // Returns if(!(returnType == typeof(void))) generator.Emit(OpCodes.Ldloc_3); generator.Emit(OpCodes.Ret); } #endif /* * Gets an event handler for the event type that delegates to the eventHandler Lua function. * Caches the generated type. */ public LuaEventHandler GetEvent(Type eventHandlerType, LuaFunction eventHandler) { #if MONOTOUCH throw new NotImplementedException (" Emit not available on MonoTouch "); #else Type eventConsumerType; if(eventHandlerCollection.ContainsKey(eventHandlerType)) eventConsumerType = eventHandlerCollection[eventHandlerType]; else { eventConsumerType = GenerateEvent(eventHandlerType); eventHandlerCollection[eventHandlerType] = eventConsumerType; } var luaEventHandler = (LuaEventHandler)Activator.CreateInstance(eventConsumerType); luaEventHandler.handler = eventHandler; return luaEventHandler; #endif } public void RegisterLuaDelegateType (Type delegateType, Type luaDelegateType) { delegateCollection[delegateType] = luaDelegateType; } public void RegisterLuaClassType (Type klass, Type luaClass) { LuaClassType luaClassType = new LuaClassType(); luaClassType.klass = luaClass; GetReturnTypesFromClass (klass, out luaClassType.returnTypes); classCollection[klass] = luaClassType; } /* * Gets a delegate with delegateType that calls the luaFunc Lua function * Caches the generated type. */ public Delegate GetDelegate(Type delegateType, LuaFunction luaFunc) { var returnTypes = new List(); Type luaDelegateType; if(delegateCollection.ContainsKey(delegateType)) luaDelegateType = delegateCollection[delegateType]; else { luaDelegateType = GenerateDelegate(delegateType); delegateCollection[delegateType] = luaDelegateType; } var methodInfo = delegateType.GetMethod("Invoke"); returnTypes.Add(methodInfo.ReturnType); foreach(ParameterInfo paramInfo in methodInfo.GetParameters()) { if(paramInfo.ParameterType.IsByRef) returnTypes.Add(paramInfo.ParameterType); } var luaDelegate = (LuaDelegate)Activator.CreateInstance(luaDelegateType); luaDelegate.function = luaFunc; luaDelegate.returnTypes = returnTypes.ToArray(); return Delegate.CreateDelegate(delegateType, luaDelegate, "CallFunction"); } /* * Gets an instance of an implementation of the klass interface or * subclass of klass that delegates public virtual methods to the * luaTable table. * Caches the generated type. */ public object GetClassInstance(Type klass, LuaTable luaTable) { LuaClassType luaClassType; if(classCollection.ContainsKey(klass)) luaClassType = classCollection[klass]; else { luaClassType = new LuaClassType(); GenerateClass(klass, out luaClassType.klass, out luaClassType.returnTypes); classCollection[klass] = luaClassType; } return Activator.CreateInstance(luaClassType.klass, new object[] {luaTable, luaClassType.returnTypes}); } } }