namespace LuaInterface { using System; using System.IO; using System.Collections; using System.Reflection; using System.Collections.Generic; using System.Diagnostics; using Lua511; /* * Cached method */ struct MethodCache { public MethodBase cachedMethod; // List or arguments public object[] args; // Positions of out parameters public int[] outList; // Types of parameters public MethodArgs[] argTypes; } /* * Parameter information */ struct MethodArgs { // Position of parameter public int index; // Type-conversion function public ExtractValue extractValue; } /* * Argument extraction with type-conversion function */ delegate object ExtractValue(IntPtr luaState, int stackPos); /* * Wrapper class for methods/constructors accessed from Lua. * * Author: Fabio Mascarenhas * Version: 1.0 */ class LuaMethodWrapper { ObjectTranslator translator; MethodBase method; MethodCache lastCalledMethod=new MethodCache(); string methodName; MemberInfo[] members; IReflect targetType; ExtractValue extractTarget; object target; BindingFlags bindingType; /* * Constructs the wrapper for a known MethodBase instance */ public LuaMethodWrapper(ObjectTranslator translator, object target, IReflect targetType, MethodBase method) { this.translator=translator; this.target=target; this.targetType=targetType; if(targetType!=null) extractTarget=translator.typeChecker.getExtractor(targetType); this.method=method; this.methodName=method.Name; if(method.IsStatic) { bindingType=BindingFlags.Static; } else { bindingType=BindingFlags.Instance; } } /* * Constructs the wrapper for a known method name */ public LuaMethodWrapper(ObjectTranslator translator, IReflect targetType, string methodName, BindingFlags bindingType) { this.translator=translator; this.methodName=methodName; this.targetType=targetType; if(targetType!=null) extractTarget=translator.typeChecker.getExtractor(targetType); this.bindingType=bindingType; members=targetType.UnderlyingSystemType.GetMember(methodName,MemberTypes.Method,bindingType|BindingFlags.Public|BindingFlags.NonPublic); } /// /// Convert C# exceptions into Lua errors /// /// num of things on stack /// null for no pending exception int SetPendingException(Exception e) { return translator.interpreter.SetPendingException(e); } /* * 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 /// We keep track of what delegates we have auto attached to an event - to allow us to cleanly exit a LuaInterface session /// class EventHandlerContainer : IDisposable { Dictionary dict = new Dictionary(); public void Add(Delegate handler, RegisterEventHandler eventInfo) { dict.Add(handler, eventInfo); } public void Remove(Delegate handler) { bool found = dict.Remove(handler); Debug.Assert(found); } /// /// Remove any still registered handlers /// public void Dispose() { foreach (KeyValuePair pair in dict) { pair.Value.RemovePending(pair.Key); } dict.Clear(); } } /* * Wrapper class for events that does registration/deregistration * of event handlers. * * Author: Fabio Mascarenhas * Version: 1.0 */ class RegisterEventHandler { object target; EventInfo eventInfo; EventHandlerContainer pendingEvents; public RegisterEventHandler(EventHandlerContainer pendingEvents, object target, EventInfo eventInfo) { this.target=target; this.eventInfo=eventInfo; this.pendingEvents = pendingEvents; } /* * Adds a new event handler */ public Delegate Add(LuaFunction function) { MethodInfo mi = eventInfo.EventHandlerType.GetMethod("Invoke"); ParameterInfo[] pi = mi.GetParameters(); LuaEventHandler handler=CodeGeneration.Instance.GetEvent(pi[1].ParameterType,function); Delegate handlerDelegate=Delegate.CreateDelegate(eventInfo.EventHandlerType,handler,"HandleEvent"); eventInfo.AddEventHandler(target,handlerDelegate); pendingEvents.Add(handlerDelegate, this); return handlerDelegate; } /* * Removes an existing event handler */ public void Remove(Delegate handlerDelegate) { RemovePending(handlerDelegate); pendingEvents.Remove(handlerDelegate); } /* * Removes an existing event handler (without updating the pending handlers list) */ internal void RemovePending(Delegate handlerDelegate) { eventInfo.RemoveEventHandler(target, handlerDelegate); } } /* * Base wrapper class for Lua function event handlers. * Subclasses that do actual event handling are created * at runtime. * * Author: Fabio Mascarenhas * Version: 1.0 */ public class LuaEventHandler { public LuaFunction handler = null; public void handleEvent(object sender,object data) { handler.call(new object[] { sender,data },new Type[0]); } } /* * Wrapper class for Lua functions as delegates * Subclasses with correct signatures are created * at runtime. * * Author: Fabio Mascarenhas * Version: 1.0 */ public class LuaDelegate { public Type[] returnTypes; public LuaFunction function; public LuaDelegate() { function=null; returnTypes=null; } public object callFunction(object[] args,object[] inArgs,int[] outArgs) { // args is the return array of arguments, inArgs is the actual array // of arguments passed to the function (with in parameters only), outArgs // has the positions of out parameters object returnValue; int iRefArgs; object[] returnValues=function.call(inArgs,returnTypes); if(returnTypes[0] == typeof(void)) { returnValue=null; iRefArgs=0; } else { returnValue=returnValues[0]; iRefArgs=1; } // Sets the value of out and ref parameters (from // the values returned by the Lua function). for(int i=0;i