/// <inheritdoc /> public Result <Expression <Func <double> > > TryEvaluateToExpressionTree(string expression) { Result <List <Token> > rpnResult = ShuntingYard.InfixToPostfixTokens(expression); if (!rpnResult.HasValue) { return(Result.FromError <Expression <Func <double> > >(rpnResult.ErrorMessage)); } var stack = new Stack <Expression>(); foreach (Token token in rpnResult.Value) { // Convert each token to an expression node and push it onto the stack. // As noted in comments below. Some nodes will consume other nodes by popping them off of the stack. switch (token.Type) { case TokenType.Number: // Numbers are transformed into an expression constant and pushed onto the stack. double value = double.Parse(token.SourceSlice); stack.Push(Expression.Constant(value)); break; case TokenType.Function: // Function consume their arguments by popping them from the stack and pushing the resulting // function call expression onto the stack. List <Expression> args; Result <Expression> functionResult = GenerateFunctionCallExpression(token, stack, out args); if (!functionResult.HasValue) { string message = string.Format("Failed to generate function call to '{0}({1}): {2}", token.SourceSlice, string.Join(", ", args), functionResult.ErrorMessage); return(Result.FromError <Expression <Func <double> > >(message)); } stack.Push(functionResult.Value); break; case TokenType.Operator: // Operators are similar to funtions in that they consume their operands by popping them from the // stack and pushing the resulting operator node onto the stack. Operator op = Operator.FromToken(token); try { stack.Push(op.ToExpression(stack)); } catch (InvalidOperationException) { return(Result.FromError <Expression <Func <double> > >( string.Format("Invalid expression '{0}'. " + "Missing one or more operands near token {1}", expression, token))); } break; default: return(Result.FromError <Expression <Func <double> > >( $"Unexpected token '{token}' found in RPN expression.")); } } if (stack.Count != 1) { string message = string.Format("Invalid expression '{0}'", expression); return(Result.FromError <Expression <Func <double> > >(message)); } return(Result.FromValue(Expression.Lambda <Func <double> >(stack.Pop()))); }