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"); } }
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"); } }