Exemple #1
0
        private static Expression BindFunctionCall(MethodInfo method, Type instanceType, bool instanceFunction, List <ParameterExpression> parameters, IEnumerable <Expression> arguments, LabelTarget returnLabel)
        {
            var returnType = method.ReturnType;

            Expression callExpr;

            if (instanceFunction && instanceType != null)
            {
                // instance functions store the instance in UserData
                var userData = Expression.Convert(Expression.PropertyOrField(parameters[1], "UserData"), instanceType);
                callExpr = Expression.Call(userData, method, arguments);
            }
            else
            {
                callExpr = Expression.Call(method, arguments);
            }

            if (returnType != typeof(void))
            {
                var output = callExpr;

                Func <Expression, Expression> outputConversion;
                if (ConversionMap.TryGetValue(returnType, out outputConversion))
                {
                    output = outputConversion(output);
                }

                callExpr = Expression.Return(returnLabel, Expression.Convert(output, typeof(MondValue)));
            }

            return(callExpr);
        }
Exemple #2
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());
        }