/* * Constructs the wrapper for a known MethodBase instance */ public LuaMethodWrapper(ObjectTranslator translator, object target, ProxyType targetType, MethodBase method) { InvokeFunction = Call; _translator = translator; _target = target; _extractTarget = translator.typeChecker.GetExtractor(targetType); _lastCalledMethod = new MethodCache(); _method = method; _methodName = method.Name; _isStatic = method.IsStatic; }
/* * Constructs the wrapper for a known method name */ public LuaMethodWrapper(ObjectTranslator translator, ProxyType targetType, string methodName, BindingFlags bindingType) { InvokeFunction = Call; _translator = translator; _methodName = methodName; _extractTarget = translator.typeChecker.GetExtractor(targetType); _lastCalledMethod = new MethodCache(); _isStatic = (bindingType & BindingFlags.Static) == BindingFlags.Static; _members = GetMethodsRecursively(targetType.UnderlyingSystemType, methodName, bindingType | BindingFlags.Public); }
/* * Checks if the method matches the arguments in the Lua stack, getting * the arguments if it does. */ internal bool MatchParameters (LuaState luaState, MethodBase method, ref MethodCache methodCache) { return metaFunctions.MatchParameters (luaState, method, ref methodCache); }
private int CallConstructorInternal (LuaState luaState) { var 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"); LuaLib.LuaPushNil (luaState); return 1; } else klass = (IReflect)obj; LuaLib.LuaRemove (luaState, 1); var constructors = klass.UnderlyingSystemType.GetConstructors (); foreach (var constructor in constructors) { bool isConstructor = MatchParameters (luaState, constructor, ref validConstructor); if (isConstructor) { try { translator.Push (luaState, constructor.Invoke (validConstructor.args)); } catch (TargetInvocationException e) { ThrowError (luaState, e); LuaLib.LuaPushNil (luaState); } catch { LuaLib.LuaPushNil (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)); LuaLib.LuaPushNil (luaState); return 1; }
/* * Matches a method against its arguments in the Lua stack. Returns * if the match was successful. It it was also returns the information * necessary to invoke the method. */ internal bool MatchParameters (LuaState luaState, MethodBase method, ref MethodCache methodCache) { ExtractValue extractValue; bool isMethod = true; var paramInfo = method.GetParameters (); int currentLuaParam = 1; int nLuaParams = LuaLib.LuaGetTop (luaState); var paramList = new List<object> (); var outList = new List<int> (); var argTypes = new List<MethodArgs> (); foreach (var currentNetParam in paramInfo) { #if !SILVERLIGHT if (!currentNetParam.IsIn && currentNetParam.IsOut) // Skips out params #else if (currentNetParam.IsOut) // Skips out params #endif { paramList.Add (null); outList.Add (paramList.LastIndexOf (null)); } else if (IsTypeCorrect (luaState, currentLuaParam, currentNetParam, out extractValue)) { // Type checking var value = extractValue (luaState, currentLuaParam); paramList.Add (value); int index = paramList.LastIndexOf (value); var 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 (IsParamsArray (luaState, currentLuaParam, currentNetParam, out extractValue)) { var paramArrayType = currentNetParam.ParameterType.GetElementType (); Func<int, object> extractDelegate = (currentParam) => { currentLuaParam ++; return extractValue (luaState, currentParam); }; int count = (nLuaParams - currentLuaParam) + 1; Array paramArray = TableToArray (extractDelegate, paramArrayType, currentLuaParam, count); paramList.Add (paramArray); int index = paramList.LastIndexOf (paramArray); var methodArg = new MethodArgs (); methodArg.index = index; methodArg.extractValue = extractValue; methodArg.isParamsArray = true; methodArg.paramsArrayType = paramArrayType; argTypes.Add (methodArg); } else if (currentLuaParam > nLuaParams) { // Adds optional parameters if (currentNetParam.IsOptional) paramList.Add (currentNetParam.DefaultValue); else { isMethod = false; break; } } 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; }
static int MatchOperator (LuaState luaState, string operation, ObjectTranslator translator) { var validOperator = new MethodCache (); object target = GetTargetObject (luaState, operation, translator); if (target == null) { translator.ThrowError (luaState, "Cannot call " + operation + " on a nil object"); LuaLib.LuaPushNil (luaState); return 1; } Type type = target.GetType (); var operators = type.GetMethods (operation, BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static); foreach (var op in operators) { bool isOk = translator.MatchParameters (luaState, op, ref validOperator); if (!isOk) continue; object result; if (op.IsStatic) result = op.Invoke (null, validOperator.args); else result = op.Invoke (target, validOperator.args); translator.Push (luaState, result); return 1; } translator.ThrowError (luaState, "Cannot call (" + operation + ") on object type " + type.Name); LuaLib.LuaPushNil (luaState); return 1; }
private int CallConstructorInternal (LuaState luaState) { var validConstructor = new MethodCache (); ProxyType klass; object obj = translator.GetRawNetObject (luaState, 1); if (obj == null || !(obj is ProxyType)) { translator.ThrowError (luaState, "trying to call constructor on an invalid type reference"); LuaLib.LuaPushNil (luaState); return 1; } else klass = (ProxyType)obj; LuaLib.LuaRemove (luaState, 1); var constructors = klass.UnderlyingSystemType.GetConstructors (); foreach (var constructor in constructors) { bool isConstructor = MatchParameters (luaState, constructor, ref validConstructor); if (isConstructor) { try { translator.Push (luaState, constructor.Invoke (validConstructor.args)); } catch (TargetInvocationException e) { ThrowError (luaState, e); LuaLib.LuaPushNil (luaState); } catch { LuaLib.LuaPushNil (luaState); } return 1; } } #if NETFX_CORE if (klass.UnderlyingSystemType.GetTypeInfo ().IsValueType) { #else if (klass.UnderlyingSystemType.IsValueType) { #endif int numLuaParams = LuaLib.LuaGetTop (luaState); if (numLuaParams == 0) { translator.Push (luaState, Activator.CreateInstance (klass.UnderlyingSystemType)); 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)); LuaLib.LuaPushNil (luaState); return 1; } static bool IsInteger(double x) { return Math.Ceiling(x) == x; }
int CallDelegateInternal (LuaState luaState) { object objDelegate = translator.GetRawNetObject (luaState, 1); if (objDelegate == null || !(objDelegate is Delegate)) { translator.ThrowError (luaState, "trying to invoke a not delegate or callable value"); LuaLib.LuaPushNil (luaState); return 1; } LuaLib.LuaRemove (luaState, 1); var validDelegate = new MethodCache (); Delegate del = (Delegate)objDelegate; #if NETFX_CORE || WP80 || NET45 || PCL MethodBase methodDelegate = del.GetMethodInfo (); #else MethodBase methodDelegate = del.Method; #endif bool isOk = MatchParameters (luaState, methodDelegate, ref validDelegate); if (isOk) { object result; if (methodDelegate.IsStatic) result = methodDelegate.Invoke (null, validDelegate.args); else result = methodDelegate.Invoke (del.Target, validDelegate.args); translator.Push (luaState, result); return 1; } translator.ThrowError (luaState, "Cannot invoke delegate (invalid arguments for " + methodDelegate.Name + ")"); LuaLib.LuaPushNil (luaState); return 1; }
/* * 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 (LuaCore.lua_State luaState, MethodBase method, ref MethodCache methodCache) { ExtractValue extractValue; bool isMethod = true; var paramInfo = method.GetParameters (); int currentLuaParam = 1; int nLuaParams = LuaLib.lua_gettop (luaState); var paramList = new ArrayList (); var outList = new List<int> (); var argTypes = new List<MethodArgs> (); foreach (var 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 (_IsTypeCorrect (luaState, currentLuaParam, currentNetParam, out extractValue)) { // Type checking int index = paramList.Add (extractValue (luaState, currentLuaParam)); var 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 (_IsParamsArray (luaState, currentLuaParam, currentNetParam, out extractValue)) { object luaParamValue = extractValue (luaState, currentLuaParam); var paramArrayType = currentNetParam.ParameterType.GetElementType (); Array paramArray; if (luaParamValue is LuaTable) { var table = (LuaTable)luaParamValue; var tableEnumerator = table.GetEnumerator (); paramArray = Array.CreateInstance (paramArrayType, table.Values.Count); tableEnumerator.Reset (); int paramArrayIndex = 0; while (tableEnumerator.MoveNext()) { paramArray.SetValue (Convert.ChangeType (tableEnumerator.Value, currentNetParam.ParameterType.GetElementType ()), paramArrayIndex); paramArrayIndex++; } } else { paramArray = Array.CreateInstance (paramArrayType, 1); paramArray.SetValue (luaParamValue, 0); } int index = paramList.Add (paramArray); var methodArg = new MethodArgs (); methodArg.index = index; methodArg.extractValue = extractValue; methodArg.isParamsArray = true; methodArg.paramsArrayType = paramArrayType; argTypes.Add (methodArg); currentLuaParam++; } 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; }