private static MondInstanceFunction BindInstanceImpl(string className, MethodTable method, string nameOverride = null, bool fakeInstance = false) { var errorPrefix = BindingError.ErrorPrefix(className, nameOverride ?? method.Name); if (!fakeInstance) { return((state, instance, args) => { MethodBase function; ReturnConverter returnConversion; var parameters = BuildParameterArray(errorPrefix, method, state, instance, args, out function, out returnConversion); var classInstance = instance.UserData; if (ReferenceEquals(classInstance, null)) { throw new MondRuntimeException(errorPrefix + BindingError.RequiresInstance); } return returnConversion(errorPrefix, state, Call(() => function.Invoke(classInstance, parameters))); }); } return((state, instance, args) => { MethodBase function; ReturnConverter returnConversion; var parameters = BuildParameterArray(errorPrefix, method, state, instance, args, out function, out returnConversion); return returnConversion(errorPrefix, state, Call(() => function.Invoke(null, parameters))); }); }
private static TFunc BindImpl <TFunc, TReturn>( string moduleName, MethodTable methodTable, bool instanceFunction, BindCallFactory callFactory) { var errorPrefix = BindingError.ErrorPrefix(moduleName, methodTable.Name); var parameters = new List <ParameterExpression> { Expression.Parameter(typeof(MondState), "state"), Expression.Parameter(typeof(MondValue[]), "arguments") }; if (instanceFunction) { parameters.Insert(1, Expression.Parameter(typeof(MondValue), "instance")); } var argumentsParam = parameters[instanceFunction ? 2 : 1]; var statements = new List <Expression>(); var returnLabel = Expression.Label(typeof(TReturn)); var argumentsLength = Expression.PropertyOrField(argumentsParam, "Length"); for (var i = 0; i < methodTable.Methods.Count; i++) { var dispatches = BuildDispatchExpression(errorPrefix, methodTable.Methods[i], i, parameters, instanceFunction, returnLabel, callFactory); if (dispatches.Count == 0) { continue; } var requiredArgCount = Expression.Constant(i); var argLengthEqual = Expression.Equal(argumentsLength, requiredArgCount); var argBranch = Expression.IfThen(argLengthEqual, Expression.Block(dispatches)); statements.Add(argBranch); } foreach (var group in methodTable.ParamsMethods.GroupBy(p => p.RequiredMondParameterCount)) { var dispatches = BuildDispatchExpression(errorPrefix, group, int.MaxValue, parameters, instanceFunction, returnLabel, callFactory); var requiredArgCount = Expression.Constant(group.Key); var argLengthAtLeast = Expression.GreaterThanOrEqual(argumentsLength, requiredArgCount); var argBranch = Expression.IfThen(argLengthAtLeast, Expression.Block(dispatches)); statements.Add(argBranch); } statements.Add(ThrowParameterTypeError(errorPrefix, methodTable)); statements.Add(Expression.Label(returnLabel, Expression.Default(typeof(TReturn)))); var block = Expression.Block(statements); return(Expression.Lambda <TFunc>(block, parameters).Compile()); }
private static Expression ThrowParameterTypeError(string errorPrefix, MethodTable methodTable) { var parameterTypeError = typeof(BindingError).GetMethod("ParameterTypeError", BindingFlags.Public | BindingFlags.Static); var errorString = Expression.Call(parameterTypeError, Expression.Constant(errorPrefix), Expression.Constant(methodTable)); return(Expression.Throw(Expression.New(RuntimeExceptionConstructor, errorString))); }
private static MondConstructor BindConstructorImpl(string moduleName, MethodTable method) { var errorPrefix = BindingError.ErrorPrefix(moduleName, "#ctor"); return((state, instance, args) => { MethodBase constructor; ReturnConverter returnConversion; var parameters = BuildParameterArray(errorPrefix, method, state, instance, args, out constructor, out returnConversion); return Call(() => ((ConstructorInfo)constructor).Invoke(parameters)); }); }
private static MondFunction BindImpl(string moduleName, MethodTable method, string nameOverride = null) { var errorPrefix = BindingError.ErrorPrefix(moduleName, nameOverride ?? method.Name); return((state, args) => { MethodBase function; ReturnConverter returnConversion; var parameters = BuildParameterArray(errorPrefix, method, state, null, args, out function, out returnConversion); return returnConversion(errorPrefix, state, Call(() => function.Invoke(null, parameters))); }); }
public static string ParameterTypeError(string prefix, MethodTable methodTable) { var sb = new StringBuilder(); sb.Append(prefix); sb.AppendLine("argument types do not match any available functions"); var methods = methodTable.Methods .SelectMany(l => l) .Concat(methodTable.ParamsMethods) .Distinct(); foreach (var method in methods) { sb.Append("- "); sb.AppendLine(method.ToString()); } return(sb.ToString()); }
private static object[] BuildParameterArray( string errorPrefix, MethodTable methodTable, MondState state, MondValue instance, MondValue[] args, out MethodBase methodBase, out ReturnConverter returnConversion) { Method method = null; if (args.Length < methodTable.Methods.Count) { method = FindMatch(methodTable.Methods[args.Length], args); } if (method == null) { method = FindMatch(methodTable.ParamsMethods, args); } if (method != null) { methodBase = method.Info; returnConversion = method.ReturnConversion; var parameters = method.Parameters; var result = new object[parameters.Count]; var j = 0; for (var i = 0; i < result.Length; i++) { var param = parameters[i]; switch (param.Type) { case ParameterType.Value: if (j < args.Length) { result[i] = param.Conversion(args[j++]); } else { result[i] = param.Info.DefaultValue; } break; case ParameterType.Params: result[i] = Slice(args, method.MondParameterCount); break; case ParameterType.Instance: result[i] = instance; break; case ParameterType.State: result[i] = state; break; default: throw new NotSupportedException(); } } return(result); } throw new MondBindingException(BindingError.ParameterTypeError(errorPrefix, methodTable)); }
private static object[] BuildParameterArray( string errorPrefix, MethodTable methodTable, MondState state, in MondValue instance,