public static CseObject Parse(CseObject environment, string methName, List<CseObject> args) {
MethResSettings mrSettings = new MethResSettings() {
Args = (args == null ? new CseObject[] { } : args.ToArray()),
Env = environment.Value,
Name = methName
};
List<MethResObject> appMeths = MethRes.GetApplicableMembers(mrSettings);
if (appMeths.Count == 0) {
mrSettings.IsExtInvocation = true;
appMeths = MethRes.GetApplicableMembers(mrSettings);
}
MethodInfo mi = null;
Type envType = TypeExp.GetTypeObj(environment.Value);
try {
switch (appMeths.Count) {
// No methods exist with that name
case 0:
// TODO: doesn't exist OR no applicable methods can be called
throw new CseLogicException(CseLogicExceptionType.METHOD_DOESNT_EXIST, methName);
// Only 1 method exists with that name, so try to do what's necessary to coerce args (if they exist)
// to match its signature.
case 1:
MethResObject mrObj = appMeths[0];
if (args != null) {
for (int i = 0; i < args.Count; i++) {
try {
args[i] = CastExp.Parse(environment, mrObj.MethInfo.GetParameters()[i].ParameterType.Name, args[i]);
}
catch (CseLogicException) {
// fuck it, continue
}
}
}
//NarrowAllIntTypes(ref args);
mi = mrObj.MethInfo;
break;
// Method is overloaded.
// Idea is to simulate C#'s best match algorithm for finding the most appropriate method to call
// and if still unsure, throw exception so user can use casting for further clarification.
default:
Type[] types = GetTypeArray(args);
mi = envType.GetMethod(methName, findFlags | BindingFlags.ExactBinding, null, types, null);
if (mi != null)
break;
if (CanCoerce(args)) {
NarrowAllIntTypes(ref args);
types = GetTypeArray(args);
}
MethodInfo tryMeth = envType.GetMethod(methName, findFlags, null, types, null);
foreach (MethResObject m in appMeths) {
if (m.MethInfo == tryMeth) {
mi = tryMeth;
break;
}
}
if (mi != null)
break;
// TODO: Attempt to coerce args to formal param types of overloaded methods
if (mi == null)
throw new CseLogicException(CseLogicExceptionType.METHOD_CALL_AMBIGUOUS, methName);
break;
}
}
catch (AmbiguousMatchException) {
throw new CseLogicException(CseLogicExceptionType.METHOD_CALL_AMBIGUOUS, methName);
}
catch (CseLogicException) {
throw;
}
catch {
throw new CseLogicException(CseLogicExceptionType.METHOD_EXISTS_BUT_CANT_BE_INVOKED, methName);
}
if (mi == null) {
throw new CseLogicException(CseLogicExceptionType.METHOD_EXISTS_BUT_CANT_BE_INVOKED, methName);
}
else {
dynamic result = mi.Invoke(environment.Value, GetObjArgs(args));
CseObject xo = new CseObject(result);
xo.CompileTimeType = mi.ReturnType;
if (args != null) {
foreach (CseObject arg in args) {
if (arg.CallMod != CallArgMod.VAL) {
AssignExp.Parse(arg.EnvChain, arg.EnvNames, arg.EnvIndices, arg.Value);
}
}
}
return xo;
}
}