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 MethodTable BuildMethodTable(IEnumerable <Method> source) { var sourceList = source.ToList(); string name = null; var methods = new List <List <Method> >(); var paramsMethods = new List <Method>(); foreach (var method in sourceList) { if (name == null) { name = method.Name; } if (method.HasParams) { paramsMethods.Add(method); } for (var i = method.RequiredMondParameterCount; i <= method.MondParameterCount; i++) { while (methods.Count <= i) { methods.Add(new List <Method>()); } methods[i].Add(method); } } for (var i = 0; i < methods.Count; i++) { methods[i].Sort(); methods[i] = methods[i].Distinct(new MethodParameterEqualityComparer(i)).ToList(); } paramsMethods.Sort(); // make sure all functions made it in var sourceMethodInfo = sourceList.Select(m => m.Info); var tableMethodInfo = methods.SelectMany(l => l).Select(m => m.Info); var paramsMethodInfo = paramsMethods.Select(m => m.Info); var difference = sourceMethodInfo .Except(tableMethodInfo.Concat(paramsMethodInfo)) .ToList(); if (difference.Count > 0) { throw new MondBindingException(BindingError.MethodsHiddenError(difference)); } return(new MethodTable(name, methods, paramsMethods)); }
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))); }); }
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)); }