示例#1
0
        /// <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())));
        }