Exemplo n.º 1
0
        public void RegisterFunction(string functionName, Delegate function, bool isOverWritable)
        {
            if (string.IsNullOrEmpty(functionName))
                throw new ArgumentNullException("functionName");

            if (function == null)
                throw new ArgumentNullException("function");

            Type funcType = function.GetType();

            if (!funcType.FullName.StartsWith("System.Func"))
                throw new ArgumentException("Only System.Func delegates are permitted.", "function");

            #if NETFX_CORE
            foreach (Type genericArgument in funcType.GenericTypeArguments)
            #else
            foreach (Type genericArgument in funcType.GetGenericArguments())
            #endif
                if (genericArgument != typeof(double))
                    throw new ArgumentException("Only doubles are supported as function arguments", "function");

            functionName = ConvertFunctionName(functionName);

            if (functions.ContainsKey(functionName) && !functions[functionName].IsOverWritable)
            {
                string message = string.Format("The function \"{0}\" cannot be overwriten.", functionName);
                throw new Exception(message);
            }

            #if NETFX_CORE
            int numberOfParameters = function.GetMethodInfo().GetParameters().Length;
            #else
            int numberOfParameters = function.Method.GetParameters().Length;
            #endif

            if (functions.ContainsKey(functionName) && functions[functionName].NumberOfParameters != numberOfParameters)
            {
                string message = string.Format("The number of parameters cannot be changed when overwriting a method.");
                throw new Exception(message);
            }

            FunctionInfo functionInfo = new FunctionInfo(functionName, numberOfParameters, isOverWritable, function);

            if (functions.ContainsKey(functionName))
                functions[functionName] = functionInfo;
            else
                functions.Add(functionName, functionInfo);
        }
Exemplo n.º 2
0
        private Expression GenerateMethodBody(Operation operation, ParameterExpression contextParameter,
                                              IFunctionRegistry functionRegistry, IDictionary <string, double> variables)
        {
            if (operation == null)
            {
                throw new ArgumentNullException("operation");
            }

            if (operation.GetType() == typeof(IntegerConstant))
            {
                IntegerConstant constant = (IntegerConstant)operation;

                double value = constant.Value;
                return(Expression.Constant(value, typeof(double)));
            }
            else if (operation.GetType() == typeof(FloatingPointConstant))
            {
                FloatingPointConstant constant = (FloatingPointConstant)operation;

                return(Expression.Constant(constant.Value, typeof(double)));
            }
            else if (operation.GetType() == typeof(Variable))
            {
                Variable variable = (Variable)operation;

                Func <string, FormulaContext, double> getVariableValueOrThrow = PrecompiledMethods.GetVariableValueOrThrow;
                return(Expression.Call(null,
                                       getVariableValueOrThrow.Method,
                                       Expression.Constant(variable.Name),
                                       contextParameter));
            }
            else if (operation.GetType() == typeof(Multiplication))
            {
                Multiplication multiplication = (Multiplication)operation;
                Expression     argument1      = GenerateMethodBody(multiplication.Argument1, contextParameter, functionRegistry, variables);
                Expression     argument2      = GenerateMethodBody(multiplication.Argument2, contextParameter, functionRegistry, variables);

                return(Expression.Multiply(argument1, argument2));
            }
            else if (operation.GetType() == typeof(Addition))
            {
                Addition   addition  = (Addition)operation;
                Expression argument1 = GenerateMethodBody(addition.Argument1, contextParameter, functionRegistry, variables);
                Expression argument2 = GenerateMethodBody(addition.Argument2, contextParameter, functionRegistry, variables);

                return(Expression.Add(argument1, argument2));
            }
            else if (operation.GetType() == typeof(Subtraction))
            {
                Subtraction addition  = (Subtraction)operation;
                Expression  argument1 = GenerateMethodBody(addition.Argument1, contextParameter, functionRegistry, variables);
                Expression  argument2 = GenerateMethodBody(addition.Argument2, contextParameter, functionRegistry, variables);

                return(Expression.Subtract(argument1, argument2));
            }
            else if (operation.GetType() == typeof(Division))
            {
                Division   division = (Division)operation;
                Expression dividend = GenerateMethodBody(division.Dividend, contextParameter, functionRegistry, variables);
                Expression divisor  = GenerateMethodBody(division.Divisor, contextParameter, functionRegistry, variables);

                return(Expression.Divide(dividend, divisor));
            }
            else if (operation.GetType() == typeof(Modulo))
            {
                Modulo     modulo   = (Modulo)operation;
                Expression dividend = GenerateMethodBody(modulo.Dividend, contextParameter, functionRegistry, variables);
                Expression divisor  = GenerateMethodBody(modulo.Divisor, contextParameter, functionRegistry, variables);

                return(Expression.Modulo(dividend, divisor));
            }
            else if (operation.GetType() == typeof(Exponentiation))
            {
                Exponentiation exponentation = (Exponentiation)operation;
                Expression     @base         = GenerateMethodBody(exponentation.Base, contextParameter, functionRegistry, variables);
                Expression     exponent      = GenerateMethodBody(exponentation.Exponent, contextParameter, functionRegistry, variables);

                return(Expression.Call(null, typeof(Math).GetMethod("Pow", new Type[] { typeof(double), typeof(double) }), @base, exponent));
            }
            else if (operation.GetType() == typeof(UnaryMinus))
            {
                UnaryMinus unaryMinus = (UnaryMinus)operation;
                Expression argument   = GenerateMethodBody(unaryMinus.Argument, contextParameter, functionRegistry, variables);
                return(Expression.Negate(argument));
            }
            else if (operation.GetType() == typeof(And))
            {
                And        and       = (And)operation;
                Expression argument1 = Expression.NotEqual(GenerateMethodBody(and.Argument1, contextParameter, functionRegistry, variables), Expression.Constant(0.0));
                Expression argument2 = Expression.NotEqual(GenerateMethodBody(and.Argument2, contextParameter, functionRegistry, variables), Expression.Constant(0.0));

                return(Expression.Condition(Expression.And(argument1, argument2),
                                            Expression.Constant(1.0),
                                            Expression.Constant(0.0)));
            }
            else if (operation.GetType() == typeof(Or))
            {
                Or         and       = (Or)operation;
                Expression argument1 = Expression.NotEqual(GenerateMethodBody(and.Argument1, contextParameter, functionRegistry, variables), Expression.Constant(0.0));
                Expression argument2 = Expression.NotEqual(GenerateMethodBody(and.Argument2, contextParameter, functionRegistry, variables), Expression.Constant(0.0));

                return(Expression.Condition(Expression.Or(argument1, argument2),
                                            Expression.Constant(1.0),
                                            Expression.Constant(0.0)));
            }
            else if (operation.GetType() == typeof(LessThan))
            {
                LessThan   lessThan  = (LessThan)operation;
                Expression argument1 = GenerateMethodBody(lessThan.Argument1, contextParameter, functionRegistry, variables);
                Expression argument2 = GenerateMethodBody(lessThan.Argument2, contextParameter, functionRegistry, variables);

                return(Expression.Condition(Expression.LessThan(argument1, argument2),
                                            Expression.Constant(1.0),
                                            Expression.Constant(0.0)));
            }
            else if (operation.GetType() == typeof(LessOrEqualThan))
            {
                LessOrEqualThan lessOrEqualThan = (LessOrEqualThan)operation;
                Expression      argument1       = GenerateMethodBody(lessOrEqualThan.Argument1, contextParameter, functionRegistry, variables);
                Expression      argument2       = GenerateMethodBody(lessOrEqualThan.Argument2, contextParameter, functionRegistry, variables);

                return(Expression.Condition(Expression.LessThanOrEqual(argument1, argument2),
                                            Expression.Constant(1.0),
                                            Expression.Constant(0.0)));
            }
            else if (operation.GetType() == typeof(GreaterThan))
            {
                GreaterThan greaterThan = (GreaterThan)operation;
                Expression  argument1   = GenerateMethodBody(greaterThan.Argument1, contextParameter, functionRegistry, variables);
                Expression  argument2   = GenerateMethodBody(greaterThan.Argument2, contextParameter, functionRegistry, variables);

                return(Expression.Condition(Expression.GreaterThan(argument1, argument2),
                                            Expression.Constant(1.0),
                                            Expression.Constant(0.0)));
            }
            else if (operation.GetType() == typeof(GreaterOrEqualThan))
            {
                GreaterOrEqualThan greaterOrEqualThan = (GreaterOrEqualThan)operation;
                Expression         argument1          = GenerateMethodBody(greaterOrEqualThan.Argument1, contextParameter, functionRegistry, variables);
                Expression         argument2          = GenerateMethodBody(greaterOrEqualThan.Argument2, contextParameter, functionRegistry, variables);

                return(Expression.Condition(Expression.GreaterThanOrEqual(argument1, argument2),
                                            Expression.Constant(1.0),
                                            Expression.Constant(0.0)));
            }
            else if (operation.GetType() == typeof(Equal))
            {
                Equal      equal     = (Equal)operation;
                Expression argument1 = GenerateMethodBody(equal.Argument1, contextParameter, functionRegistry, variables);
                Expression argument2 = GenerateMethodBody(equal.Argument2, contextParameter, functionRegistry, variables);

                return(Expression.Condition(Expression.Equal(argument1, argument2),
                                            Expression.Constant(1.0),
                                            Expression.Constant(0.0)));
            }
            else if (operation.GetType() == typeof(NotEqual))
            {
                NotEqual   notEqual  = (NotEqual)operation;
                Expression argument1 = GenerateMethodBody(notEqual.Argument1, contextParameter, functionRegistry, variables);
                Expression argument2 = GenerateMethodBody(notEqual.Argument2, contextParameter, functionRegistry, variables);

                return(Expression.Condition(Expression.NotEqual(argument1, argument2),
                                            Expression.Constant(1.0),
                                            Expression.Constant(0.0)));
            }
            else if (operation.GetType() == typeof(Function))
            {
                Function function = (Function)operation;

                FunctionInfo functionInfo = functionRegistry.GetFunctionInfo(function.FunctionName);
                Type         funcType;
                Type[]       parameterTypes;
                Expression[] arguments;

                if (function.FunctionName == "isvardefined")
                {
                    if (function.Arguments.Count != 1)
                    {
                        throw new ArgumentException("Invalid number of arguments.");
                    }
                    if (function.Arguments[0].GetType() == typeof(Variable))
                    {
                        Variable variable = (Variable)function.Arguments[0];
                        double   value;
                        bool     variableFound = variables.TryGetValue(variable.Name, out value);

                        IntegerConstant newArgument = new IntegerConstant(variableFound ? 1 : 0);
                        function.Arguments[0] = newArgument;
                    }
                    else if (function.Arguments[0].GetType() == typeof(IntegerConstant))
                    {
                        IntegerConstant oldArgument = (IntegerConstant)function.Arguments[0];
                        IntegerConstant newArgument = new IntegerConstant(oldArgument.Value != 0 ? 1 : 0);
                        function.Arguments[0] = newArgument;
                    }
                    else if (function.Arguments[0].GetType() == typeof(FloatingPointConstant))
                    {
                        FloatingPointConstant oldArgument = (FloatingPointConstant)function.Arguments[0];
                        FloatingPointConstant newArgument = new FloatingPointConstant(oldArgument.Value != 0 ? 1 : 0);
                        function.Arguments[0] = newArgument;
                    }
                    else
                    {
                        throw new ArgumentException("Invalid argument for isVarDefined.");
                    }
                }

                if (functionInfo.IsDynamicFunc)
                {
                    funcType       = typeof(DynamicFunc <double, double>);
                    parameterTypes = new Type[] { typeof(double[]) };


                    Expression[] arrayArguments = new Expression[function.Arguments.Count];
                    for (int i = 0; i < function.Arguments.Count; i++)
                    {
                        arrayArguments[i] = GenerateMethodBody(function.Arguments[i], contextParameter, functionRegistry, variables);
                    }

                    arguments    = new Expression[1];
                    arguments[0] = NewArrayExpression.NewArrayInit(typeof(double), arrayArguments);
                }
                else
                {
                    funcType       = GetFuncType(functionInfo.NumberOfParameters);
                    parameterTypes = (from i in Enumerable.Range(0, functionInfo.NumberOfParameters)
                                      select typeof(double)).ToArray();

                    arguments = new Expression[functionInfo.NumberOfParameters];
                    for (int i = 0; i < functionInfo.NumberOfParameters; i++)
                    {
                        arguments[i] = GenerateMethodBody(function.Arguments[i], contextParameter, functionRegistry, variables);
                    }
                }

                Expression getFunctionRegistry = Expression.Property(contextParameter, "FunctionRegistry");

                ParameterExpression functionInfoVariable = Expression.Variable(typeof(FunctionInfo));

                Expression funcInstance;
                if (!functionInfo.IsOverWritable)
                {
                    funcInstance = Expression.Convert(
                        Expression.Property(
                            Expression.Call(
                                getFunctionRegistry,
                                typeof(IFunctionRegistry).GetMethod("GetFunctionInfo", new Type[] { typeof(string) }),
                                Expression.Constant(function.FunctionName)),
                            "Function"),
                        funcType);
                }
                else
                {
                    funcInstance = Expression.Constant(functionInfo.Function, funcType);
                }

                return(Expression.Call(
                           funcInstance,
                           funcType.GetMethod("Invoke", parameterTypes),
                           arguments));
            }
            else
            {
                throw new ArgumentException(string.Format("Unsupported operation \"{0}\".", operation.GetType().FullName), "operation");
            }
        }
Exemplo n.º 3
0
        public double Execute(Operation operation,
                              IFunctionRegistry functionRegistry,
                              IConstantRegistry constantRegistry,
                              IDictionary <string, double> variables)
        {
            if (operation == null)
            {
                throw new ArgumentNullException("operation");
            }

            if (operation.GetType() == typeof(IntegerConstant))
            {
                IntegerConstant constant = (IntegerConstant)operation;
                return(constant.Value);
            }
            else if (operation.GetType() == typeof(FloatingPointConstant))
            {
                FloatingPointConstant constant = (FloatingPointConstant)operation;
                return(constant.Value);
            }
            else if (operation.GetType() == typeof(Variable))
            {
                Variable variable = (Variable)operation;

                double value;
                bool   variableFound = variables.TryGetValue(variable.Name, out value);

                if (variableFound)
                {
                    return(value);
                }
                else
                {
                    throw new VariableNotDefinedException(string.Format("The variable \"{0}\" used is not defined.", variable.Name));
                }
            }
            else if (operation.GetType() == typeof(Multiplication))
            {
                Multiplication multiplication = (Multiplication)operation;
                return(Execute(multiplication.Argument1, functionRegistry, constantRegistry, variables) * Execute(multiplication.Argument2, functionRegistry, constantRegistry, variables));
            }
            else if (operation.GetType() == typeof(Addition))
            {
                Addition addition = (Addition)operation;
                return(Execute(addition.Argument1, functionRegistry, constantRegistry, variables) + Execute(addition.Argument2, functionRegistry, constantRegistry, variables));
            }
            else if (operation.GetType() == typeof(Subtraction))
            {
                Subtraction addition = (Subtraction)operation;
                return(Execute(addition.Argument1, functionRegistry, constantRegistry, variables) - Execute(addition.Argument2, functionRegistry, constantRegistry, variables));
            }
            else if (operation.GetType() == typeof(Division))
            {
                Division division = (Division)operation;
                return(Execute(division.Dividend, functionRegistry, constantRegistry, variables) / Execute(division.Divisor, functionRegistry, constantRegistry, variables));
            }
            else if (operation.GetType() == typeof(Modulo))
            {
                Modulo division = (Modulo)operation;
                return(Execute(division.Dividend, functionRegistry, constantRegistry, variables) % Execute(division.Divisor, functionRegistry, constantRegistry, variables));
            }
            else if (operation.GetType() == typeof(Exponentiation))
            {
                Exponentiation exponentiation = (Exponentiation)operation;
                return(Math.Pow(Execute(exponentiation.Base, functionRegistry, constantRegistry, variables), Execute(exponentiation.Exponent, functionRegistry, constantRegistry, variables)));
            }
            else if (operation.GetType() == typeof(UnaryMinus))
            {
                UnaryMinus unaryMinus = (UnaryMinus)operation;
                return(-Execute(unaryMinus.Argument, functionRegistry, constantRegistry, variables));
            }
            else if (operation.GetType() == typeof(And))
            {
                And and        = (And)operation;
                var operation1 = Execute(and.Argument1, functionRegistry, constantRegistry, variables) != 0;
                var operation2 = Execute(and.Argument2, functionRegistry, constantRegistry, variables) != 0;

                return((operation1 && operation2) ? 1.0 : 0.0);
            }
            else if (operation.GetType() == typeof(Or))
            {
                Or  or         = (Or)operation;
                var operation1 = Execute(or.Argument1, functionRegistry, constantRegistry, variables) != 0;
                var operation2 = Execute(or.Argument2, functionRegistry, constantRegistry, variables) != 0;

                return((operation1 || operation2) ? 1.0 : 0.0);
            }
            else if (operation.GetType() == typeof(LessThan))
            {
                LessThan lessThan = (LessThan)operation;
                return((Execute(lessThan.Argument1, functionRegistry, constantRegistry, variables) < Execute(lessThan.Argument2, functionRegistry, constantRegistry, variables)) ? 1.0 : 0.0);
            }
            else if (operation.GetType() == typeof(LessOrEqualThan))
            {
                LessOrEqualThan lessOrEqualThan = (LessOrEqualThan)operation;
                return((Execute(lessOrEqualThan.Argument1, functionRegistry, constantRegistry, variables) <= Execute(lessOrEqualThan.Argument2, functionRegistry, constantRegistry, variables)) ? 1.0 : 0.0);
            }
            else if (operation.GetType() == typeof(GreaterThan))
            {
                GreaterThan greaterThan = (GreaterThan)operation;
                return((Execute(greaterThan.Argument1, functionRegistry, constantRegistry, variables) > Execute(greaterThan.Argument2, functionRegistry, constantRegistry, variables)) ? 1.0 : 0.0);
            }
            else if (operation.GetType() == typeof(GreaterOrEqualThan))
            {
                GreaterOrEqualThan greaterOrEqualThan = (GreaterOrEqualThan)operation;
                return((Execute(greaterOrEqualThan.Argument1, functionRegistry, constantRegistry, variables) >= Execute(greaterOrEqualThan.Argument2, functionRegistry, constantRegistry, variables)) ? 1.0 : 0.0);
            }
            else if (operation.GetType() == typeof(Equal))
            {
                Equal equal = (Equal)operation;
                return((Execute(equal.Argument1, functionRegistry, constantRegistry, variables) == Execute(equal.Argument2, functionRegistry, constantRegistry, variables)) ? 1.0 : 0.0);
            }
            else if (operation.GetType() == typeof(NotEqual))
            {
                NotEqual notEqual = (NotEqual)operation;
                return((Execute(notEqual.Argument1, functionRegistry, constantRegistry, variables) != Execute(notEqual.Argument2, functionRegistry, constantRegistry, variables)) ? 1.0 : 0.0);
            }
            else if (operation.GetType() == typeof(Function))
            {
                Function function = (Function)operation;

                FunctionInfo functionInfo = functionRegistry.GetFunctionInfo(function.FunctionName);

                double[] arguments = new double[functionInfo.IsDynamicFunc ? function.Arguments.Count : functionInfo.NumberOfParameters];
                for (int i = 0; i < arguments.Length; i++)
                {
                    arguments[i] = Execute(function.Arguments[i], functionRegistry, constantRegistry, variables);
                }

                return(Invoke(functionInfo.Function, arguments));
            }
            else
            {
                throw new ArgumentException(string.Format("Unsupported operation \"{0}\".", operation.GetType().FullName), "operation");
            }
        }
Exemplo n.º 4
0
        private void GenerateMethodBody(ILGenerator generator, Operation operation,
                                        IFunctionRegistry functionRegistry)
        {
            if (operation == null)
            {
                throw new ArgumentNullException("operation");
            }

            if (operation.GetType() == typeof(IntegerConstant))
            {
                IntegerConstant constant = (IntegerConstant)operation;

                generator.Emit(OpCodes.Ldc_I4, constant.Value);
                generator.Emit(OpCodes.Conv_R8);
            }
            else if (operation.GetType() == typeof(FloatingPointConstant))
            {
                FloatingPointConstant constant = (FloatingPointConstant)operation;

                generator.Emit(OpCodes.Ldc_R8, constant.Value);
            }
            else if (operation.GetType() == typeof(Variable))
            {
                Type dictionaryType = typeof(Dictionary <string, double>);

                Variable variable = (Variable)operation;

                Label throwExceptionLabel = generator.DefineLabel();
                Label returnLabel         = generator.DefineLabel();

                generator.Emit(OpCodes.Ldarg_0);
                generator.Emit(OpCodes.Callvirt, typeof(FormulaContext).GetProperty("Variables").GetGetMethod());
                generator.Emit(OpCodes.Ldstr, variable.Name);
                generator.Emit(OpCodes.Callvirt, dictionaryType.GetMethod("ContainsKey", new Type[] { typeof(string) }));
                generator.Emit(OpCodes.Ldc_I4_0);
                generator.Emit(OpCodes.Ceq);
                generator.Emit(OpCodes.Brtrue_S, throwExceptionLabel);

                generator.Emit(OpCodes.Ldarg_0);
                generator.Emit(OpCodes.Callvirt, typeof(FormulaContext).GetProperty("Variables").GetGetMethod());
                generator.Emit(OpCodes.Ldstr, variable.Name);
                generator.Emit(OpCodes.Callvirt, dictionaryType.GetMethod("get_Item", new Type[] { typeof(string) }));
                generator.Emit(OpCodes.Br_S, returnLabel);

                generator.MarkLabel(throwExceptionLabel);
                generator.Emit(OpCodes.Ldstr, string.Format("The variable \"{0}\" used is not defined.", variable.Name));
                generator.Emit(OpCodes.Newobj, typeof(VariableNotDefinedException).GetConstructor(new Type[] { typeof(string) }));
                generator.Emit(OpCodes.Throw);

                generator.MarkLabel(returnLabel);
            }
            else if (operation.GetType() == typeof(Multiplication))
            {
                Multiplication multiplication = (Multiplication)operation;
                GenerateMethodBody(generator, multiplication.Argument1, functionRegistry);
                GenerateMethodBody(generator, multiplication.Argument2, functionRegistry);

                generator.Emit(OpCodes.Mul);
            }
            else if (operation.GetType() == typeof(Addition))
            {
                Addition addition = (Addition)operation;
                GenerateMethodBody(generator, addition.Argument1, functionRegistry);
                GenerateMethodBody(generator, addition.Argument2, functionRegistry);

                generator.Emit(OpCodes.Add);
            }
            else if (operation.GetType() == typeof(Subtraction))
            {
                Subtraction addition = (Subtraction)operation;
                GenerateMethodBody(generator, addition.Argument1, functionRegistry);
                GenerateMethodBody(generator, addition.Argument2, functionRegistry);

                generator.Emit(OpCodes.Sub);
            }
            else if (operation.GetType() == typeof(Division))
            {
                Division division = (Division)operation;
                GenerateMethodBody(generator, division.Dividend, functionRegistry);
                GenerateMethodBody(generator, division.Divisor, functionRegistry);

                generator.Emit(OpCodes.Div);
            }
            else if (operation.GetType() == typeof(Modulo))
            {
                Modulo modulo = (Modulo)operation;
                GenerateMethodBody(generator, modulo.Dividend, functionRegistry);
                GenerateMethodBody(generator, modulo.Divisor, functionRegistry);

                generator.Emit(OpCodes.Rem);
            }
            else if (operation.GetType() == typeof(Exponentiation))
            {
                Exponentiation exponentation = (Exponentiation)operation;
                GenerateMethodBody(generator, exponentation.Base, functionRegistry);
                GenerateMethodBody(generator, exponentation.Exponent, functionRegistry);

                generator.Emit(OpCodes.Call, typeof(Math).GetMethod("Pow"));
            }
            else if (operation.GetType() == typeof(UnaryMinus))
            {
                UnaryMinus unaryMinus = (UnaryMinus)operation;
                GenerateMethodBody(generator, unaryMinus.Argument, functionRegistry);

                generator.Emit(OpCodes.Neg);
            }
            else if (operation.GetType() == typeof(Function))
            {
                Function function = (Function)operation;

                FunctionInfo functionInfo = functionRegistry.GetFunctionInfo(function.FunctionName);
                Type         funcType     = GetFuncType(functionInfo.NumberOfParameters);

                generator.Emit(OpCodes.Ldarg_0);
                generator.Emit(OpCodes.Callvirt, typeof(FormulaContext).GetProperty("FunctionRegistry").GetGetMethod());
                generator.Emit(OpCodes.Ldstr, function.FunctionName);
                generator.Emit(OpCodes.Callvirt, typeof(IFunctionRegistry).GetMethod("GetFunctionInfo", new Type[] { typeof(string) }));
                generator.Emit(OpCodes.Callvirt, typeof(FunctionInfo).GetProperty("Function").GetGetMethod());
                generator.Emit(OpCodes.Castclass, funcType);

                for (int i = 0; i < functionInfo.NumberOfParameters; i++)
                {
                    GenerateMethodBody(generator, function.Arguments[i], functionRegistry);
                }

                generator.Emit(OpCodes.Call, funcType.GetMethod("Invoke"));
            }
            else
            {
                throw new ArgumentException(string.Format("Unsupported operation \"{0}\".", operation.GetType().FullName), "operation");
            }
        }
Exemplo n.º 5
0
        private Expression GenerateMethodBody(Operation operation, ParameterExpression contextParameter,
                                              IFunctionRegistry functionRegistry)
        {
            if (operation == null)
            {
                throw new ArgumentNullException("operation");
            }

            if (operation.GetType() == typeof(IntegerConstant))
            {
                IntegerConstant constant = (IntegerConstant)operation;

                return(Expression.Convert(Expression.Constant(constant.Value, typeof(int)), typeof(double)));
            }
            else if (operation.GetType() == typeof(FloatingPointConstant))
            {
                FloatingPointConstant constant = (FloatingPointConstant)operation;

                return(Expression.Constant(constant.Value, typeof(double)));
            }
            else if (operation.GetType() == typeof(Variable))
            {
                Type contextType    = typeof(FormulaContext);
                Type dictionaryType = typeof(IDictionary <string, double>);

                Variable variable = (Variable)operation;

                Expression          getVariables = Expression.Property(contextParameter, "Variables");
                ParameterExpression value        = Expression.Variable(typeof(double), "value");

                Expression variableFound = Expression.Call(getVariables,
                                                           dictionaryType.GetRuntimeMethod("TryGetValue", new Type[] { typeof(string), typeof(double).MakeByRefType() }),
                                                           Expression.Constant(variable.Name),
                                                           value);

                Expression throwException = Expression.Throw(
                    Expression.New(typeof(VariableNotDefinedException).GetConstructor(new Type[] { typeof(string) }),
                                   Expression.Constant(string.Format("The variable \"{0}\" used is not defined.", variable.Name))));

                LabelTarget returnLabel = Expression.Label(typeof(double));

                return(Expression.Block(
                           new[] { value },
                           Expression.IfThenElse(
                               variableFound,
                               Expression.Return(returnLabel, value),
                               throwException
                               ),
                           Expression.Label(returnLabel, Expression.Constant(0.0))
                           ));
            }
            else if (operation.GetType() == typeof(Multiplication))
            {
                Multiplication multiplication = (Multiplication)operation;
                Expression     argument1      = GenerateMethodBody(multiplication.Argument1, contextParameter, functionRegistry);
                Expression     argument2      = GenerateMethodBody(multiplication.Argument2, contextParameter, functionRegistry);

                return(Expression.Multiply(argument1, argument2));
            }
            else if (operation.GetType() == typeof(Addition))
            {
                Addition   addition  = (Addition)operation;
                Expression argument1 = GenerateMethodBody(addition.Argument1, contextParameter, functionRegistry);
                Expression argument2 = GenerateMethodBody(addition.Argument2, contextParameter, functionRegistry);

                return(Expression.Add(argument1, argument2));
            }
            else if (operation.GetType() == typeof(Subtraction))
            {
                Subtraction addition  = (Subtraction)operation;
                Expression  argument1 = GenerateMethodBody(addition.Argument1, contextParameter, functionRegistry);
                Expression  argument2 = GenerateMethodBody(addition.Argument2, contextParameter, functionRegistry);

                return(Expression.Subtract(argument1, argument2));
            }
            else if (operation.GetType() == typeof(Division))
            {
                Division   division = (Division)operation;
                Expression dividend = GenerateMethodBody(division.Dividend, contextParameter, functionRegistry);
                Expression divisor  = GenerateMethodBody(division.Divisor, contextParameter, functionRegistry);

                return(Expression.Divide(dividend, divisor));
            }
            else if (operation.GetType() == typeof(Modulo))
            {
                Modulo     modulo   = (Modulo)operation;
                Expression dividend = GenerateMethodBody(modulo.Dividend, contextParameter, functionRegistry);
                Expression divisor  = GenerateMethodBody(modulo.Divisor, contextParameter, functionRegistry);

                return(Expression.Modulo(dividend, divisor));
            }
            else if (operation.GetType() == typeof(Exponentiation))
            {
                Exponentiation exponentation = (Exponentiation)operation;
                Expression     @base         = GenerateMethodBody(exponentation.Base, contextParameter, functionRegistry);
                Expression     exponent      = GenerateMethodBody(exponentation.Exponent, contextParameter, functionRegistry);

                return(Expression.Call(null, typeof(Math).GetRuntimeMethod("Pow", new Type[] { typeof(double), typeof(double) }), @base, exponent));
            }
            else if (operation.GetType() == typeof(UnaryMinus))
            {
                UnaryMinus unaryMinus = (UnaryMinus)operation;
                Expression argument   = GenerateMethodBody(unaryMinus.Argument, contextParameter, functionRegistry);
                return(Expression.Negate(argument));
            }
            else if (operation.GetType() == typeof(LessThan))
            {
                LessThan   lessThan  = (LessThan)operation;
                Expression argument1 = GenerateMethodBody(lessThan.Argument1, contextParameter, functionRegistry);
                Expression argument2 = GenerateMethodBody(lessThan.Argument2, contextParameter, functionRegistry);

                return(Expression.Condition(Expression.LessThan(argument1, argument2),
                                            Expression.Constant(1.0),
                                            Expression.Constant(0.0)));
            }
            else if (operation.GetType() == typeof(LessOrEqualThan))
            {
                LessOrEqualThan lessOrEqualThan = (LessOrEqualThan)operation;
                Expression      argument1       = GenerateMethodBody(lessOrEqualThan.Argument1, contextParameter, functionRegistry);
                Expression      argument2       = GenerateMethodBody(lessOrEqualThan.Argument2, contextParameter, functionRegistry);

                return(Expression.Condition(Expression.LessThanOrEqual(argument1, argument2),
                                            Expression.Constant(1.0),
                                            Expression.Constant(0.0)));
            }
            else if (operation.GetType() == typeof(GreaterThan))
            {
                GreaterThan greaterThan = (GreaterThan)operation;
                Expression  argument1   = GenerateMethodBody(greaterThan.Argument1, contextParameter, functionRegistry);
                Expression  argument2   = GenerateMethodBody(greaterThan.Argument2, contextParameter, functionRegistry);

                return(Expression.Condition(Expression.GreaterThan(argument1, argument2),
                                            Expression.Constant(1.0),
                                            Expression.Constant(0.0)));
            }
            else if (operation.GetType() == typeof(GreaterOrEqualThan))
            {
                GreaterOrEqualThan greaterOrEqualThan = (GreaterOrEqualThan)operation;
                Expression         argument1          = GenerateMethodBody(greaterOrEqualThan.Argument1, contextParameter, functionRegistry);
                Expression         argument2          = GenerateMethodBody(greaterOrEqualThan.Argument2, contextParameter, functionRegistry);

                return(Expression.Condition(Expression.GreaterThanOrEqual(argument1, argument2),
                                            Expression.Constant(1.0),
                                            Expression.Constant(0.0)));
            }
            else if (operation.GetType() == typeof(Equal))
            {
                Equal      equal     = (Equal)operation;
                Expression argument1 = GenerateMethodBody(equal.Argument1, contextParameter, functionRegistry);
                Expression argument2 = GenerateMethodBody(equal.Argument2, contextParameter, functionRegistry);

                return(Expression.Condition(Expression.Equal(argument1, argument2),
                                            Expression.Constant(1.0),
                                            Expression.Constant(0.0)));
            }
            else if (operation.GetType() == typeof(NotEqual))
            {
                NotEqual   notEqual  = (NotEqual)operation;
                Expression argument1 = GenerateMethodBody(notEqual.Argument1, contextParameter, functionRegistry);
                Expression argument2 = GenerateMethodBody(notEqual.Argument2, contextParameter, functionRegistry);

                return(Expression.Condition(Expression.NotEqual(argument1, argument2),
                                            Expression.Constant(1.0),
                                            Expression.Constant(0.0)));
            }
            else if (operation.GetType() == typeof(Function))
            {
                Function function = (Function)operation;

                FunctionInfo functionInfo = functionRegistry.GetFunctionInfo(function.FunctionName);
                Type         funcType;
                Type[]       parameterTypes;
                Expression[] arguments;

                if (functionInfo.IsDynamicFunc)
                {
                    funcType       = typeof(DynamicFunc <double, double>);
                    parameterTypes = new Type[] { typeof(double[]) };


                    Expression[] arrayArguments = new Expression[function.Arguments.Count];
                    for (int i = 0; i < function.Arguments.Count; i++)
                    {
                        arrayArguments[i] = GenerateMethodBody(function.Arguments[i], contextParameter, functionRegistry);
                    }

                    arguments    = new Expression[1];
                    arguments[0] = NewArrayExpression.NewArrayInit(typeof(double), arrayArguments);
                }
                else
                {
                    funcType       = GetFuncType(functionInfo.NumberOfParameters);
                    parameterTypes = (from i in Enumerable.Range(0, functionInfo.NumberOfParameters)
                                      select typeof(double)).ToArray();

                    arguments = new Expression[functionInfo.NumberOfParameters];
                    for (int i = 0; i < functionInfo.NumberOfParameters; i++)
                    {
                        arguments[i] = GenerateMethodBody(function.Arguments[i], contextParameter, functionRegistry);
                    }
                }

                Expression getFunctionRegistry = Expression.Property(contextParameter, "FunctionRegistry");

                ParameterExpression functionInfoVariable = Expression.Variable(typeof(FunctionInfo));

                return(Expression.Block(
                           new[] { functionInfoVariable },
                           Expression.Assign(
                               functionInfoVariable,
                               Expression.Call(getFunctionRegistry, typeof(IFunctionRegistry).GetRuntimeMethod("GetFunctionInfo", new Type[] { typeof(string) }), Expression.Constant(function.FunctionName))
                               ),
                           Expression.Call(
                               Expression.Convert(Expression.Property(functionInfoVariable, "Function"), funcType),
                               funcType.GetRuntimeMethod("Invoke", parameterTypes),
                               arguments)));
            }
            else
            {
                throw new ArgumentException(string.Format("Unsupported operation \"{0}\".", operation.GetType().FullName), "operation");
            }
        }
Exemplo n.º 6
0
        public void RegisterFunction(string functionName, Delegate function, bool isOverWritable)
        {
            if (string.IsNullOrEmpty(functionName))
            {
                throw new ArgumentNullException("functionName");
            }

            if (function == null)
            {
                throw new ArgumentNullException("function");
            }

            Type funcType = function.GetType();

            if (!funcType.FullName.StartsWith("System.Func"))
            {
                throw new ArgumentException("Only System.Func delegates are permitted.", "function");
            }

#if NETFX_CORE
            foreach (Type genericArgument in funcType.GenericTypeArguments)
#else
            foreach (Type genericArgument in funcType.GetGenericArguments())
#endif
            { if (genericArgument != typeof(double))
              {
                  throw new ArgumentException("Only doubles are supported as function arguments", "function");
              }
            }

            functionName = ConvertFunctionName(functionName);

            if (functions.ContainsKey(functionName) && !functions[functionName].IsOverWritable)
            {
                string message = string.Format("The function \"{0}\" cannot be overwriten.", functionName);
                throw new Exception(message);
            }

#if NETFX_CORE
            int numberOfParameters = function.GetMethodInfo().GetParameters().Length;
#else
            int numberOfParameters = function.Method.GetParameters().Length;
#endif

            if (functions.ContainsKey(functionName) && functions[functionName].NumberOfParameters != numberOfParameters)
            {
                string message = string.Format("The number of parameters cannot be changed when overwriting a method.");
                throw new Exception(message);
            }

            FunctionInfo functionInfo = new FunctionInfo(functionName, numberOfParameters, isOverWritable, function);

            if (functions.ContainsKey(functionName))
            {
                functions[functionName] = functionInfo;
            }
            else
            {
                functions.Add(functionName, functionInfo);
            }
        }