using System; using System.Collections; using System.Collections.Generic; using System.Reflection; using System.Reflection.Emit; using System.Threading; namespace LuaInterface { /* * Structure to store a type and the return types of * its methods (the type of the returned value and out/ref * parameters). */ struct LuaClassType { public Type klass; public Type[][] returnTypes; } /* * Common interface for types generated from tables. The method * returns the table that overrides some or all of the type's methods. */ public interface ILuaGeneratedType { LuaTable __luaInterface_getLuaTable(); } /* * Class used for generating delegates that get a function from the Lua * stack as a delegate of a specific type. * * Author: Fabio Mascarenhas * Version: 1.0 */ class DelegateGenerator { private ObjectTranslator translator; private Type delegateType; public DelegateGenerator(ObjectTranslator translator,Type delegateType) { this.translator=translator; this.delegateType=delegateType; } public object extractGenerated(IntPtr luaState,int stackPos) { return CodeGeneration.Instance.GetDelegate(delegateType,translator.getFunction(luaState,stackPos)); } } /* * Class used for generating delegates that get a table from the Lua * stack as a an object of a specific type. * * Author: Fabio Mascarenhas * Version: 1.0 */ class ClassGenerator { private ObjectTranslator translator; private Type klass; public ClassGenerator(ObjectTranslator translator,Type klass) { this.translator=translator; this.klass=klass; } public object extractGenerated(IntPtr luaState,int stackPos) { return CodeGeneration.Instance.GetClassInstance(klass,translator.getTable(luaState,stackPos)); } } /* * 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 Type eventHandlerParent=typeof(LuaEventHandler); private Dictionary eventHandlerCollection=new Dictionary(); private Type delegateParent=typeof(LuaDelegate); private Dictionary delegateCollection=new Dictionary(); private Type classHelper=typeof(LuaClassHelper); private Dictionary classCollection=new Dictionary(); private AssemblyName assemblyName; private AssemblyBuilder newAssembly; private ModuleBuilder newModule; private int luaClassNumber=1; private static readonly CodeGeneration instance = new CodeGeneration(); static CodeGeneration() { } private CodeGeneration() { // Create an assembly name assemblyName=new AssemblyName( ); assemblyName.Name="LuaInterface_generatedcode"; // Create a new assembly with one module. newAssembly=Thread.GetDomain().DefineDynamicAssembly( assemblyName, AssemblyBuilderAccess.Run); newModule=newAssembly.DefineDynamicModule("LuaInterface_generatedcode"); } /* * 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) { string typeName; lock(this) { typeName = "LuaGeneratedClass" + luaClassNumber; luaClassNumber++; } // Define a public class in the assembly, called typeName TypeBuilder myType=newModule.DefineType(typeName,TypeAttributes.Public,eventHandlerParent); // Defines the handler method. Its signature is void(object,) Type[] paramTypes = new Type[2]; paramTypes[0]=typeof(object); paramTypes[1]=eventHandlerType; Type returnType=typeof(void); MethodBuilder 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); MethodInfo miGenericEventHandler; miGenericEventHandler=eventHandlerParent.GetMethod("handleEvent"); generator.Emit(OpCodes.Call,miGenericEventHandler); // returns generator.Emit(OpCodes.Ret); // creates the new type return myType.CreateType(); } /* * Generates a type that can be used for instantiating a delegate * of the provided type, given a Lua function. */ private Type GenerateDelegate(Type delegateType) { string typeName; lock(this) { typeName = "LuaGeneratedClass" + luaClassNumber; luaClassNumber++; } // Define a public class in the assembly, called typeName TypeBuilder myType=newModule.DefineType(typeName,TypeAttributes.Public,delegateParent); // Defines the delegate method with the same signature as the // Invoke method of delegateType MethodInfo invokeMethod=delegateType.GetMethod("Invoke"); ParameterInfo[] paramInfo=invokeMethod.GetParameters(); Type[] paramTypes=new Type[paramInfo.Length]; Type returnType=invokeMethod.ReturnType; // Counts out and ref params, for use later int nOutParams=0; int nOutAndRefParams=0; for(int i=0;i returnTypesList=new List(); // Counts out and ref parameters, for later use, // and creates the list of return types int nOutParams=0; int nOutAndRefParams=0; Type returnType=method.ReturnType; returnTypesList.Add(returnType); for(int i=0;i returnTypes=new List(); Type luaDelegateType; if (delegateCollection.ContainsKey(delegateType)) { luaDelegateType=delegateCollection[delegateType]; } else { luaDelegateType=GenerateDelegate(delegateType); delegateCollection[delegateType] = luaDelegateType; } MethodInfo methodInfo=delegateType.GetMethod("Invoke"); returnTypes.Add(methodInfo.ReturnType); foreach(ParameterInfo paramInfo in methodInfo.GetParameters()) if(paramInfo.ParameterType.IsByRef) returnTypes.Add(paramInfo.ParameterType); LuaDelegate 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,luaTable); classCollection[klass] = luaClassType; } return Activator.CreateInstance(luaClassType.klass,new object[] {luaTable,luaClassType.returnTypes}); } } }