Ejemplo n.º 1
0
        public ExecutionResult Execute(Operation operation, IFunctionRegistry functionRegistry,
                                       IDictionary <string, ExecutionResult> variables)
        {
            if (operation == null)
            {
                throw new ArgumentNullException("operation");
            }

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

                ExecutionResult 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;
                var            executionResult1 = Execute(multiplication.Argument1, functionRegistry, variables);
                var            executionResult2 = Execute(multiplication.Argument2, functionRegistry, variables);
                return(ExecuteMultiplication(executionResult1, executionResult2));
            }
            else if (operation.GetType() == typeof(Addition))
            {
                Addition addition         = (Addition)operation;
                var      executionResult1 = Execute(addition.Argument1, functionRegistry, variables);
                var      executionResult2 = Execute(addition.Argument2, functionRegistry, variables);
                return(ExecuteAddition(executionResult1, executionResult2));;
            }
            else if (operation.GetType() == typeof(Subtraction))
            {
                Subtraction addition         = (Subtraction)operation;
                var         executionResult1 = Execute(addition.Argument1, functionRegistry, variables);
                var         executionResult2 = Execute(addition.Argument2, functionRegistry, variables);
                return(ExecuteSubtraction(executionResult1, executionResult2));
            }
            else if (operation.GetType() == typeof(Division))
            {
                Division division         = (Division)operation;
                var      executionResult1 = Execute(division.Dividend, functionRegistry, variables);
                var      executionResult2 = Execute(division.Divisor, functionRegistry, variables);
                return(ExecuteDivision(executionResult1, executionResult2));
            }
            else if (operation.GetType() == typeof(Exponentiation))
            {
                Exponentiation exponentiation   = (Exponentiation)operation;
                var            executionResult1 = Execute(exponentiation.Base, functionRegistry, variables);
                var            executionResult2 = Execute(exponentiation.Exponent, functionRegistry, variables);
                return(ExecuteExponentiation(executionResult1, executionResult2));
            }
            else if (operation.GetType() == typeof(ChangeUnit))
            {
                ChangeUnit exponentiation   = (ChangeUnit)operation;
                var        executionResult1 = Execute(exponentiation.Argument1, functionRegistry, variables);
                return(ExecuteUnitChange(executionResult1, exponentiation.Unit));
            }
            else if (operation.GetType() == typeof(UnaryMinus))
            {
                UnaryMinus unaryMinus      = (UnaryMinus)operation;
                var        executionResult = Execute(unaryMinus.Argument, functionRegistry, variables);
                if (executionResult.DataType == DataType.Number)
                {
                    return(new ExecutionResult(-(double)executionResult.Value));
                }
                else
                {
                    return(new ExecutionResult(-(UnitNumber)executionResult.Value));
                }
            }
            else if (operation.GetType() == typeof(Function))
            {
                Function function = (Function)operation;

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

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

                return(Invoke(functionInfo.Function, arguments));
            }
            else
            {
                throw new ArgumentException(string.Format("Unsupported operation \"{0}\".", operation.GetType().FullName), "operation");
            }
        }
Ejemplo n.º 2
0
        private Expression GenerateMethodBody(Operation operation, ParameterExpression contextParameter,
                                              IFunctionRegistry functionRegistry)
        {
            if (operation == null)
            {
                throw new ArgumentNullException("operation");
            }

            if (operation.GetType() == typeof(UnitNumberConstant))
            {
                var constant = (UnitNumberConstant)operation;
                var ret      = new ExecutionResult(constant.Value);
                return(Expression.Constant(ret, typeof(ExecutionResult)));
            }
            else if (operation.GetType() == typeof(FloatingPointConstant))
            {
                FloatingPointConstant constant = (FloatingPointConstant)operation;
                var ret = new ExecutionResult(constant.Value);
                return(Expression.Constant(ret, typeof(ExecutionResult)));
            }
            else if (operation.GetType() == typeof(Variable))
            {
                Type contextType    = typeof(FormulaContext);
                Type dictionaryType = typeof(IDictionary <string, ExecutionResult>);

                Variable variable = (Variable)operation;

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

                Expression variableFound = Expression.Call(getVariables,
                                                           dictionaryType.GetMethod("TryGetValue",
                                                                                    new Type[] { typeof(string), typeof(ExecutionResult).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(ExecutionResult));

                return(Expression.Block(
                           new[] { value },
                           Expression.IfThenElse(
                               variableFound,
                               Expression.Return(returnLabel, value),
                               throwException
                               ),
                           Expression.Label(returnLabel, Expression.Constant(new ExecutionResult(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(Exponentiation))
            {
                Exponentiation exponentation = (Exponentiation)operation;
                Expression     @base         = GenerateMethodBody(exponentation.Base, contextParameter, functionRegistry);
                Expression     exponent      = GenerateMethodBody(exponentation.Exponent, contextParameter, functionRegistry);

                return(Expression.Call(@base, typeof(ExecutionResult).GetMethod("Pow", new Type[] { typeof(ExecutionResult) }), 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(Function))
            {
                Function function = (Function)operation;

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

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


                    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] = Expression.NewArrayInit(typeof(ExecutionResult), arrayArguments);
                }
                else
                {
                    funcType       = GetFuncType(functionInfo.NumberOfParameters);
                    parameterTypes = (from i in Enumerable.Range(0, functionInfo.NumberOfParameters)
                                      select typeof(ExecutionResult)).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).GetMethod("GetFunctionInfo", new Type[] { typeof(string) }),
                                               Expression.Constant(function.FunctionName))
                               ),
                           Expression.Call(
                               Expression.Convert(Expression.Property(functionInfoVariable, "Function"), funcType),
                               funcType.GetMethod("Invoke", parameterTypes),
                               arguments)));
            }
            else if (operation.GetType() == typeof(ChangeUnit))
            {
                ChangeUnit oper     = (ChangeUnit)operation;
                Expression argument = GenerateMethodBody(oper.Argument1, contextParameter, functionRegistry);
                return(Expression.Call(argument, typeof(ExecutionResult).GetMethod("ChangeUnit", new Type[] { typeof(Unit) }), Expression.Constant(oper.Unit, typeof(Unit))));
            }
            else
            {
                throw new ArgumentException(
                          string.Format("Unsupported operation \"{0}\".", operation.GetType().FullName), "operation");
            }
        }