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