/// <summary>Tries to create a key segment for the given filter if it is non empty.</summary> /// <param name="previous">Segment on which to compose.</param> /// <param name="parenthesisExpression">Parenthesis expression of segment.</param> /// <param name="keySegment">The key segment that was created if the key was non-empty.</param> /// <returns>Whether the key was non-empty.</returns> internal static bool TryCreateKeySegmentFromParentheses(ODataPathSegment previous, string parenthesisExpression, out ODataPathSegment keySegment) { DebugUtils.CheckNoExternalCallers(); Debug.Assert(parenthesisExpression != null, "parenthesisExpression != null"); Debug.Assert(previous != null, "segment!= null"); ExceptionUtil.ThrowSyntaxErrorIfNotValid(!previous.SingleResult); SegmentArgumentParser key; ExceptionUtil.ThrowSyntaxErrorIfNotValid(SegmentArgumentParser.TryParseKeysFromUri(parenthesisExpression, out key)); // People/NS.Employees() is OK, just like People() is OK if (key.IsEmpty) { keySegment = null; return(false); } keySegment = CreateKeySegment(previous, key); return(true); }
/// <summary>Attempts to parse key values from the specified text.</summary> /// <param name='text'>Text to parse (not null).</param> /// <param name="allowNamedValues">Set to true if the parser should accept named values /// so syntax like Name='value'. If this is false, the parsing will fail on such constructs.</param> /// <param name="allowNull">Set to true if the parser should accept null values. /// If set to false, the parser will fail on null values.</param> /// <param name='instance'>After invocation, the parsed key instance.</param> /// <returns> /// true if the key instance was parsed; false if there was a /// syntactic error. /// </returns> /// <remarks> /// The returned instance contains only string values. To get typed values, a call to /// TryConvertValues is necessary. /// </remarks> private static bool TryParseFromUri(string text, bool allowNamedValues, bool allowNull, out SegmentArgumentParser instance) { Debug.Assert(text != null, "text != null"); Dictionary <string, string> namedValues = null; List <string> positionalValues = null; ExpressionLexer lexer = new ExpressionLexer(text, true, false); ExpressionToken currentToken = lexer.CurrentToken; if (currentToken.Kind == ExpressionTokenKind.End) { instance = Empty; return(true); } instance = null; do { if (currentToken.Kind == ExpressionTokenKind.Identifier && allowNamedValues) { // Name-value pair. if (positionalValues != null) { // We cannot mix named and non-named values. return(false); } string identifier = lexer.CurrentToken.GetIdentifier(); lexer.NextToken(); if (lexer.CurrentToken.Kind != ExpressionTokenKind.Equal) { return(false); } lexer.NextToken(); if (!lexer.CurrentToken.IsKeyValueToken) { return(false); } string namedValue = lexer.CurrentToken.Text; CreateIfNull(ref namedValues); if (namedValues.ContainsKey(identifier)) { // Duplicate name. return(false); } namedValues.Add(identifier, namedValue); } else if (currentToken.IsKeyValueToken || (allowNull && currentToken.Kind == ExpressionTokenKind.NullLiteral)) { // Positional value. if (namedValues != null) { // We cannot mix named and non-named values. return(false); } CreateIfNull(ref positionalValues); positionalValues.Add(lexer.CurrentToken.Text); } else { return(false); } // Read the next token. We should be at the end, or find // we have a comma followed by something. lexer.NextToken(); currentToken = lexer.CurrentToken; if (currentToken.Kind == ExpressionTokenKind.Comma) { lexer.NextToken(); currentToken = lexer.CurrentToken; if (currentToken.Kind == ExpressionTokenKind.End) { // Trailing comma. return(false); } } }while (currentToken.Kind != ExpressionTokenKind.End); instance = new SegmentArgumentParser(namedValues, positionalValues, false); return(true); }
/// <summary>Attempts to parse nullable values (only positional values, no name-value pairs) from the specified text.</summary> /// <param name='text'>Text to parse (not null).</param> /// <param name='instance'>After invocation, the parsed key instance.</param> /// <returns> /// true if the given values were parsed; false if there was a /// syntactic error. /// </returns> /// <remarks> /// The returned instance contains only string values. To get typed values, a call to /// TryConvertValues is necessary. /// </remarks> internal static bool TryParseNullableTokens(string text, out SegmentArgumentParser instance) { DebugUtils.CheckNoExternalCallers(); return(TryParseFromUri(text, false /*allowNamedValues*/, true /*allowNull*/, out instance)); }