예제 #1
0
            private QueryNode ParseFunctionCallNode()
            {
                BinaryOperatorNode binaryNode = null;
                FunctionCallNode   node       = null;

                var stack = new Stack <FunctionCallNode>();

                while (this.tokens.Count > 0)
                {
                    var token = this.tokens.Dequeue();

                    switch (token.TokenType)
                    {
                    case TokenType.OpenParentheses:
                        if (this.tokens.Peek().TokenType == TokenType.CloseParentheses)
                        {
                            // All OData functions have at least 1 or 2 parameters
                            throw new ODataException(HttpStatusCode.BadRequest, Messages.UnableToParseFilter);
                        }

                        this.groupingDepth++;
                        stack.Push(node);
                        break;

                    case TokenType.CloseParentheses:
                        if (this.groupingDepth == 0)
                        {
                            throw new ODataException(HttpStatusCode.BadRequest, Messages.UnableToParseFilter);
                        }

                        this.groupingDepth--;

                        if (stack.Count > 0)
                        {
                            var lastNode = stack.Pop();

                            if (stack.Count > 0)
                            {
                                stack.Peek().AddParameter(lastNode);
                            }
                            else
                            {
                                if (binaryNode != null)
                                {
                                    binaryNode.Right = lastNode;
                                }
                                else
                                {
                                    node = lastNode;
                                }
                            }
                        }

                        break;

                    case TokenType.FunctionName:
                        node = new FunctionCallNode(token.Value);
                        break;

                    case TokenType.BinaryOperator:
                        binaryNode = new BinaryOperatorNode(node, token.Value.ToBinaryOperatorKind(), null);
                        break;

                    case TokenType.PropertyName:
                        var propertyAccessNode = new PropertyAccessNode(this.model.GetProperty(token.Value));

                        if (stack.Count > 0)
                        {
                            stack.Peek().AddParameter(propertyAccessNode);
                        }
                        else
                        {
                            binaryNode.Right = propertyAccessNode;
                        }

                        break;

                    case TokenType.Date:
                    case TokenType.DateTimeOffset:
                    case TokenType.Decimal:
                    case TokenType.Double:
                    case TokenType.Duration:
                    case TokenType.Enum:
                    case TokenType.False:
                    case TokenType.Guid:
                    case TokenType.Integer:
                    case TokenType.Null:
                    case TokenType.Single:
                    case TokenType.String:
                    case TokenType.TimeOfDay:
                    case TokenType.True:
                        var constantNode = ConstantNodeParser.ParseConstantNode(token);

                        if (stack.Count > 0)
                        {
                            stack.Peek().AddParameter(constantNode);
                        }
                        else
                        {
                            binaryNode.Right = constantNode;
                        }

                        break;

                    case TokenType.Comma:
                        if (this.tokens.Count < 2)
                        {
                            // If there is a comma in a function call, there should be another argument followed by a closing comma
                            throw new ODataException(HttpStatusCode.BadRequest, Messages.UnableToParseFilter);
                        }

                        break;
                    }
                }

                if (binaryNode != null)
                {
                    return(binaryNode);
                }

                return(node);
            }
예제 #2
0
            private QueryNode ParsePropertyAccessNode()
            {
                QueryNode result = null;

                QueryNode          leftNode     = null;
                BinaryOperatorKind operatorKind = BinaryOperatorKind.None;
                QueryNode          rightNode    = null;

                while (this.tokens.Count > 0)
                {
                    var token = this.tokens.Dequeue();

                    switch (token.TokenType)
                    {
                    case TokenType.BinaryOperator:
                        if (operatorKind != BinaryOperatorKind.None)
                        {
                            result    = new BinaryOperatorNode(leftNode, operatorKind, rightNode);
                            leftNode  = null;
                            rightNode = null;
                        }

                        operatorKind = token.Value.ToBinaryOperatorKind();
                        break;

                    case TokenType.OpenParentheses:
                        this.groupingDepth++;
                        break;

                    case TokenType.CloseParentheses:
                        this.groupingDepth--;
                        break;

                    case TokenType.FunctionName:
                        if (leftNode == null)
                        {
                            leftNode = new FunctionCallNode(token.Value);
                        }
                        else if (rightNode == null)
                        {
                            rightNode = new FunctionCallNode(token.Value);
                        }

                        break;

                    case TokenType.PropertyName:
                        var propertyAccessNode = new PropertyAccessNode(this.model.GetProperty(token.Value));

                        if (leftNode == null)
                        {
                            leftNode = propertyAccessNode;
                        }
                        else if (rightNode == null)
                        {
                            rightNode = propertyAccessNode;
                        }

                        break;

                    case TokenType.Date:
                    case TokenType.DateTimeOffset:
                    case TokenType.Decimal:
                    case TokenType.Double:
                    case TokenType.Duration:
                    case TokenType.Enum:
                    case TokenType.False:
                    case TokenType.Guid:
                    case TokenType.Integer:
                    case TokenType.Null:
                    case TokenType.Single:
                    case TokenType.String:
                    case TokenType.TimeOfDay:
                    case TokenType.True:
                        rightNode = ConstantNodeParser.ParseConstantNode(token);
                        break;
                    }
                }

                result = result == null
                    ? new BinaryOperatorNode(leftNode, operatorKind, rightNode)
                    : new BinaryOperatorNode(result, operatorKind, leftNode ?? rightNode);

                return(result);
            }