/// <summary> /// Tries to parse a collection of function parameters. Allows path and filter to share the core algorithm while representing parameters differently. /// </summary> /// <param name="lexer">The lexer to read from.</param> /// <param name="endTokenKind">The token kind that marks the end of the parameters.</param> /// <param name="splitParameters">The parameters if they were successfully split.</param> /// <returns>Whether the parameters could be split.</returns> private static bool TrySplitFunctionParameters(this ExpressionLexer lexer, ExpressionTokenKind endTokenKind, out ICollection <FunctionParameterToken> splitParameters) { DebugUtils.CheckNoExternalCallers(); Debug.Assert(lexer != null, "lexer != null"); var parameters = new List <FunctionParameterToken>(); splitParameters = parameters; ExpressionToken currentToken = lexer.CurrentToken; if (currentToken.Kind == endTokenKind) { return(true); } if (currentToken.Kind != ExpressionTokenKind.Identifier || lexer.PeekNextToken().Kind != ExpressionTokenKind.Equal) { return(false); } while (currentToken.Kind != endTokenKind) { lexer.ValidateToken(ExpressionTokenKind.Identifier); string identifier = lexer.CurrentToken.GetIdentifier(); lexer.NextToken(); lexer.ValidateToken(ExpressionTokenKind.Equal); lexer.NextToken(); QueryToken parameterValue; if (!TryCreateParameterValueToken(lexer.CurrentToken, out parameterValue)) { throw new ODataException(ODataErrorStrings.ExpressionLexer_SyntaxError(lexer.Position, lexer.ExpressionText)); } parameters.Add(new FunctionParameterToken(identifier, parameterValue)); // Read the next parameterToken. 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 == endTokenKind) { // Trailing comma. throw new ODataException(ODataErrorStrings.ExpressionLexer_SyntaxError(lexer.Position, lexer.ExpressionText)); } } } return(true); }
/// <summary> /// Parses null literals. /// </summary> /// <param name="lexer">The lexer to use.</param> /// <returns>The literal token produced by building the given literal.</returns> private static LiteralToken ParseNullLiteral(ExpressionLexer lexer) { Debug.Assert(lexer != null, "lexer != null"); Debug.Assert(lexer.CurrentToken.Kind == ExpressionTokenKind.NullLiteral, "this.lexer.CurrentToken.InternalKind == ExpressionTokenKind.NullLiteral"); LiteralToken result = new LiteralToken(null, lexer.CurrentToken.Text); lexer.NextToken(); return(result); }
/// <summary>Reads the next token, checks that it is a literal token type, converts to to a Common Language Runtime value as appropriate, and returns the value.</summary> /// <param name="expressionLexer">The expression lexer.</param> /// <returns>The value represented by the next token.</returns> internal static object ReadLiteralToken(this ExpressionLexer expressionLexer) { DebugUtils.CheckNoExternalCallers(); expressionLexer.NextToken(); if (expressionLexer.CurrentToken.Kind.IsLiteralType()) { return(TryParseLiteral(expressionLexer)); } throw new ODataException(ODataErrorStrings.ExpressionLexer_ExpectedLiteralToken(expressionLexer.CurrentToken.Text)); }
/// <summary> /// Parses typed literals. /// </summary> /// <param name="expressionLexer">The expression lexer.</param> /// <param name="targetTypeReference">Expected type to be parsed.</param> /// <returns>The literal token produced by building the given literal.</returns> private static object ParseTypedLiteral(this ExpressionLexer expressionLexer, IEdmPrimitiveTypeReference targetTypeReference) { object targetValue; if (!UriPrimitiveTypeParser.TryUriStringToPrimitive(expressionLexer.CurrentToken.Text, targetTypeReference, out targetValue)) { string message = ODataErrorStrings.UriQueryExpressionParser_UnrecognizedLiteral( targetTypeReference.FullName(), expressionLexer.CurrentToken.Text, expressionLexer.CurrentToken.Position, expressionLexer.ExpressionText); throw new ODataException(message); } expressionLexer.NextToken(); return(targetValue); }
/// <summary> /// Parses null literals. /// </summary> /// <param name="expressionLexer">The expression lexer.</param> /// <returns>The literal token produced by building the given literal.</returns> private static object ParseNullLiteral(this ExpressionLexer expressionLexer) { Debug.Assert(expressionLexer.CurrentToken.Kind == ExpressionTokenKind.NullLiteral, "this.lexer.CurrentToken.InternalKind == ExpressionTokenKind.NullLiteral"); expressionLexer.NextToken(); ODataUriNullValue nullValue = new ODataUriNullValue(); if (expressionLexer.ExpressionText == ExpressionConstants.KeywordNull) { return(nullValue); } int nullLiteralLength = ExpressionConstants.LiteralSingleQuote.Length * 2 + ExpressionConstants.KeywordNull.Length; int startOfTypeIndex = ExpressionConstants.LiteralSingleQuote.Length + ExpressionConstants.KeywordNull.Length; nullValue.TypeName = expressionLexer.ExpressionText.Substring(startOfTypeIndex, expressionLexer.ExpressionText.Length - nullLiteralLength); return(nullValue); }
/// <summary> /// Parses typed literals. /// </summary> /// <param name="lexer">The lexer to use.</param> /// <param name="targetTypeReference">Expected type to be parsed.</param> /// <param name="targetTypeName">The EDM type name of the expected type to be parsed.</param> /// <returns>The literal token produced by building the given literal.</returns> private static LiteralToken ParseTypedLiteral(ExpressionLexer lexer, IEdmPrimitiveTypeReference targetTypeReference, string targetTypeName) { Debug.Assert(lexer != null, "lexer != null"); object targetValue; if (!UriPrimitiveTypeParser.TryUriStringToPrimitive(lexer.CurrentToken.Text, targetTypeReference, out targetValue)) { string message = ODataErrorStrings.UriQueryExpressionParser_UnrecognizedLiteral( targetTypeName, lexer.CurrentToken.Text, lexer.CurrentToken.Position, lexer.ExpressionText); throw ParseError(message); } LiteralToken result = new LiteralToken(targetValue, lexer.CurrentToken.Text); lexer.NextToken(); return(result); }
/// <summary>Attempts to parse key values from the specified text.</summary> /// <param name='text'>Text to parse (not null).</param> /// <returns> /// Enumeration of key values or null if there was a syntax error. /// </returns> /// <remarks> /// The returned instance contains only string values. /// </remarks> private static IEnumerable<NamedValue> ParseKeyValuesFromUri(string text) { Debug.Assert(text != null, "text != null"); //// This is a modified copy of KeyInstance.TryParseFromUri ExpressionLexer lexer = new ExpressionLexer(text, true /*moveToFirstToken*/); ExpressionToken currentToken = lexer.CurrentToken; if (currentToken.Kind == ExpressionTokenKind.End) { return EmptyKeyValues; } List<NamedValue> keyValuesList = new List<NamedValue>(); do { if (currentToken.Kind == ExpressionTokenKind.Identifier) { // Name-value pair. string identifier = lexer.CurrentToken.GetIdentifier(); lexer.NextToken(); if (lexer.CurrentToken.Kind != ExpressionTokenKind.Equal) { return null; } lexer.NextToken(); if (!lexer.CurrentToken.IsKeyValueToken) { return null; } keyValuesList.Add(new NamedValue(identifier, ParseKeyValueLiteral(lexer))); } else if (currentToken.IsKeyValueToken) { // Unnamed value. keyValuesList.Add(new NamedValue(null, ParseKeyValueLiteral(lexer))); } else { return null; } // Read the next token. We should be at the end, or find // we have a comma followed by something. currentToken = lexer.NextToken(); if (currentToken.Kind == ExpressionTokenKind.Comma) { currentToken = lexer.NextToken(); if (currentToken.Kind == ExpressionTokenKind.End) { // Trailing comma. return null; } } } while (currentToken.Kind != ExpressionTokenKind.End); return keyValuesList; }
/// <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> /// Parses null literals. /// </summary> /// <param name="lexer">The lexer to use.</param> /// <returns>The literal token produced by building the given literal.</returns> private static LiteralQueryToken ParseNullLiteral(ExpressionLexer lexer) { Debug.Assert(lexer != null, "lexer != null"); Debug.Assert(lexer.CurrentToken.Kind == ExpressionTokenKind.NullLiteral, "this.lexer.CurrentToken.Kind == ExpressionTokenKind.NullLiteral"); LiteralQueryToken result = new LiteralQueryToken(null, lexer.CurrentToken.Text); lexer.NextToken(); return result; }
/// <summary> /// Parses typed literals. /// </summary> /// <param name="lexer">The lexer to use.</param> /// <param name="targetTypeReference">Expected type to be parsed.</param> /// <param name="targetTypeName">The EDM type name of the expected type to be parsed.</param> /// <returns>The literal token produced by building the given literal.</returns> private static LiteralQueryToken ParseTypedLiteral(ExpressionLexer lexer, IEdmPrimitiveTypeReference targetTypeReference, string targetTypeName) { Debug.Assert(lexer != null, "lexer != null"); object targetValue; if (!UriPrimitiveTypeParser.TryUriStringToPrimitive(lexer.CurrentToken.Text, targetTypeReference, out targetValue)) { string message = Strings.UriQueryExpressionParser_UnrecognizedLiteral( targetTypeName, lexer.CurrentToken.Text, lexer.CurrentToken.Position, lexer.ExpressionText); throw ParseError(message); } LiteralQueryToken result = new LiteralQueryToken(targetValue, lexer.CurrentToken.Text); lexer.NextToken(); return result; }
/// <summary>Attempts to parse key values from the specified text.</summary> /// <param name='text'>Text to parse (not null).</param> /// <returns> /// Enumeration of key values or null if there was a syntax error. /// </returns> /// <remarks> /// The returned instance contains only string values. /// </remarks> private static IEnumerable <NamedValue> ParseKeyValuesFromUri(string text) { Debug.Assert(text != null, "text != null"); //// This is a modified copy of KeyInstance.TryParseFromUri ExpressionLexer lexer = new ExpressionLexer(text, true /*moveToFirstToken*/); ExpressionToken currentToken = lexer.CurrentToken; if (currentToken.Kind == ExpressionTokenKind.End) { return(EmptyKeyValues); } List <NamedValue> keyValuesList = new List <NamedValue>(); do { if (currentToken.Kind == ExpressionTokenKind.Identifier) { // Name-value pair. string identifier = lexer.CurrentToken.GetIdentifier(); lexer.NextToken(); if (lexer.CurrentToken.Kind != ExpressionTokenKind.Equal) { return(null); } lexer.NextToken(); if (!lexer.CurrentToken.IsKeyValueToken) { return(null); } keyValuesList.Add(new NamedValue(identifier, ParseKeyValueLiteral(lexer))); } else if (currentToken.IsKeyValueToken) { // Unnamed value. keyValuesList.Add(new NamedValue(null, ParseKeyValueLiteral(lexer))); } else { return(null); } // Read the next token. We should be at the end, or find // we have a comma followed by something. currentToken = lexer.NextToken(); if (currentToken.Kind == ExpressionTokenKind.Comma) { currentToken = lexer.NextToken(); if (currentToken.Kind == ExpressionTokenKind.End) { // Trailing comma. return(null); } } }while (currentToken.Kind != ExpressionTokenKind.End); return(keyValuesList); }