Пример #1
0
        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)));
            });
        }
Пример #2
0
        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());
        }
Пример #3
0
        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));
        }
Пример #4
0
        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));
            });
        }
Пример #5
0
        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)));
            });
        }
Пример #6
0
        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));
        }