/*
* 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);
}