Ejemplo n.º 1
0
        /// <summary>
        /// Generates MondInstanceFunction bindings for the given methods.
        /// </summary>
        internal static IEnumerable <Tuple <string, MondInstanceFunction> > BindInstance(
            string className,
            ICollection <MethodInfo> methods,
            Type type             = null,
            MethodType methodType = MethodType.Normal,
            string nameOverride   = null)
        {
            if (className == null)
            {
                throw new ArgumentNullException(nameof(className));
            }

            if (type == null && methods.Any(m => !m.IsStatic))
            {
                throw new MondBindingException("BindInstance requires a type for non-static methods");
            }

            var methodTables = BuildMethodTables((IEnumerable <MethodBase>)methods, methodType, nameOverride);

            foreach (var table in methodTables)
            {
#if !NO_EXPRESSIONS
                BindCallFactory callFactory = (e, m, p, a, r) => BindFunctionCall(e, m, type, true, p, a, r);
                yield return(Tuple.Create(table.Name, BindImpl <MondInstanceFunction, MondValue>(className, table, true, callFactory)));
#else
                yield return(Tuple.Create(table.Name, BindInstanceImpl(className, table, nameOverride, type == null)));
#endif
            }
        }
Ejemplo n.º 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());
        }
Ejemplo n.º 3
0
        /// <summary>
        /// Generates a MondConstructor binding for the given constructors.
        /// </summary>
        internal static MondConstructor BindConstructor(string className, ICollection <ConstructorInfo> constructors)
        {
            if (className == null)
            {
                throw new ArgumentNullException(nameof(className));
            }

            var methodTable = BuildMethodTables((IEnumerable <MethodBase>)constructors, MethodType.Constructor).FirstOrDefault();

            if (methodTable == null || (methodTable.Methods.Count == 0 && methodTable.ParamsMethods.Count == 0))
            {
                return(null);
            }

#if !NO_EXPRESSIONS
            BindCallFactory callFactory = (e, m, p, a, r) => BindConstructorCall(m, a, r);
            return(BindImpl <MondConstructor, object>(className, methodTable, true, callFactory));
#else
            return(BindConstructorImpl(className, methodTable));
#endif
        }
Ejemplo n.º 4
0
        /// <summary>
        /// Generates MondFunction bindings for the given methods.
        /// </summary>
        internal static IEnumerable <Tuple <string, MondFunction> > BindStatic(
            string moduleName,
            ICollection <MethodInfo> methods,
            MethodType methodType = MethodType.Normal,
            string nameOverride   = null)
        {
            if (methods.Any(m => !m.IsStatic))
            {
                throw new MondBindingException("BindStatic only supports static methods");
            }

            var methodTables = BuildMethodTables(methods, methodType, nameOverride);

            foreach (var table in methodTables)
            {
#if !NO_EXPRESSIONS
                BindCallFactory callFactory = (e, m, p, a, r) => BindFunctionCall(e, m, null, false, p, a, r);
                yield return(Tuple.Create(table.Name, BindImpl <MondFunction, MondValue>(moduleName, table, false, callFactory)));
#else
                yield return(Tuple.Create(table.Name, BindImpl(moduleName, table, nameOverride)));
#endif
            }
        }
Ejemplo n.º 5
0
        private static T BindImpl <T>(string moduleName, string methodName, MethodBase method, bool instanceFunction, BindCallFactory callFactory)
        {
            // TODO: clean up everything below this line

            var arguments = GetArguments(method, instanceFunction).ToArray();

            var errorPrefix = string.Format("{0}{1}{2}: ", moduleName ?? "", moduleName != null ? "." : "", methodName);

            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];

            Func <int, Expression> argumentIndex = i => Expression.ArrayIndex(argumentsParam, Expression.Constant(i));

            var statements  = new List <Expression>();
            var returnLabel = Expression.Label(typeof(MondValue));

            // argument count check
            var argLength         = Expression.Condition(Expression.Equal(argumentsParam, Expression.Constant(null)), Expression.Constant(0), Expression.PropertyOrField(argumentsParam, "Length"));
            var requiredArgLength = arguments.Count(a => a.Index >= 0);
            var argLengthError    = string.Format("{0}must be called with {1} argument{2}", errorPrefix, requiredArgLength, requiredArgLength != 1 ? "s" : "");

            statements.Add(Expression.IfThen(Expression.NotEqual(argLength, Expression.Constant(requiredArgLength)), Throw(argLengthError)));

            // argument type checks
            for (var i = 0; i < arguments.Length; i++)
            {
                var arg = arguments[i];

                if (arg.Index < 0 || arg.Type == typeof(MondValue) || arg.Type == typeof(MondState))
                {
                    continue;
                }

                statements.Add(TypeCheck(errorPrefix, i + 1, argumentIndex(arg.Index), arg.Type));
            }

            // call
            var callArgs = new List <Expression>();

            foreach (var arg in arguments)
            {
                if (arg.Type == typeof(MondState))
                {
                    callArgs.Add(parameters[0]);
                    continue;
                }

                if (arg.Type == typeof(MondValue))
                {
                    if (instanceFunction && arg.Name == "instance")
                    {
                        callArgs.Add(parameters[1]);
                    }
                    else
                    {
                        callArgs.Add(argumentIndex(arg.Index));
                    }

                    continue;
                }

                var input = argumentIndex(arg.Index);

                Func <Expression, Expression> inputConversion;
                if (ConversionMap.TryGetValue(arg.Type, out inputConversion))
                {
                    input = inputConversion(input);
                }

                callArgs.Add(Expression.Convert(input, arg.Type));
            }

            statements.Add(callFactory(parameters, callArgs, returnLabel));

            // end / default return
            statements.Add(Expression.Label(returnLabel, Expression.Constant(MondValue.Undefined)));

            var block = Expression.Block(statements);

            return(Expression.Lambda <T>(block, parameters).Compile());
        }
Ejemplo n.º 6
0
        private static List <Expression> BuildDispatchExpression(
            string errorPrefix,
            IEnumerable <Method> methods,
            int checkedArguments,
            List <ParameterExpression> parameters,
            bool instanceFunction,
            LabelTarget returnLabel,
            BindCallFactory callFactory)
        {
            var stateParam     = parameters[0];
            var argumentsParam = parameters[instanceFunction ? 2 : 1];
            var instanceParam  = parameters[instanceFunction ? 1 : 0];

            Func <int, Expression> argumentIndex = i =>
                                                   Expression.ArrayIndex(argumentsParam, Expression.Constant(i));

            var result = new List <Expression>();

            foreach (var method in methods)
            {
                Expression typeCondition = Expression.Constant(true);

                if (checkedArguments > 0 && method.ValueParameters.Count > 0)
                {
                    typeCondition = method.ValueParameters
                                    .Take(checkedArguments)
                                    .Select((p, i) => TypeCheck(argumentIndex(i), p))
                                    .Aggregate(Expression.AndAlso);
                }

                var arguments = new List <Expression>();

                var j = 0;
                foreach (var param in method.Parameters)
                {
                    switch (param.Type)
                    {
                    case ParameterType.Value:
                        if (j < checkedArguments)
                        {
                            arguments.Add(param.Conversion(argumentIndex(j++)));
                        }
                        else
                        {
                            arguments.Add(Expression.Constant(param.Info.DefaultValue, param.Info.ParameterType));
                        }
                        break;

                    case ParameterType.Params:
                        var sliceMethod = typeof(MondFunctionBinder).GetMethod("Slice", BindingFlags.NonPublic | BindingFlags.Static);
                        arguments.Add(Expression.Call(sliceMethod, argumentsParam, Expression.Constant(method.RequiredMondParameterCount)));
                        break;

                    case ParameterType.Instance:
                        arguments.Add(instanceParam);
                        break;

                    case ParameterType.State:
                        arguments.Add(stateParam);
                        break;

                    default:
                        throw new NotSupportedException();
                    }
                }

                var callExpression = callFactory(errorPrefix, method, parameters, arguments, returnLabel);

                result.Add(Expression.IfThen(typeCondition, callExpression));
            }

            return(result);
        }