public static object ConvertFromUriLiteral(string value, ODataVersion version, IEdmModel model, IEdmTypeReference typeReference) { Exception exception; ExpressionToken token; ExceptionUtils.CheckArgumentNotNull<string>(value, "value"); if ((typeReference != null) && (model == null)) { throw new ODataException(Microsoft.Data.OData.Strings.ODataUriUtils_ConvertFromUriLiteralTypeRefWithoutModel); } if (model == null) { model = EdmCoreModel.Instance; } ExpressionLexer lexer = new ExpressionLexer(value, false); if (!lexer.TryPeekNextToken(out token, out exception)) { return ODataUriConversionUtils.ConvertFromComplexOrCollectionValue(value, version, model, typeReference); } object primitiveValue = lexer.ReadLiteralToken(); if (typeReference != null) { primitiveValue = ODataUriConversionUtils.VerifyAndCoerceUriPrimitiveLiteral(primitiveValue, model, typeReference, version); } if (primitiveValue is ISpatial) { ODataVersionChecker.CheckSpatialValue(version); } return primitiveValue; }
/// <summary> /// Parse an Identifier into the right QueryToken /// </summary> /// <param name="parameters">parameters passed in to the UriQueryExpressionParser</param> /// <param name="functionCallParser">Object to use to handle parsing function calls.</param> public IdentifierTokenizer(HashSet <string> parameters, IFunctionCallParser functionCallParser) { ExceptionUtils.CheckArgumentNotNull(parameters, "parameters"); ExceptionUtils.CheckArgumentNotNull(functionCallParser, "functionCallParser"); this.lexer = functionCallParser.Lexer; this.parameters = parameters; this.functionCallParser = functionCallParser; }
internal string GetIdentifier() { if (this.Kind != ExpressionTokenKind.Identifier) { throw ExpressionLexer.ParseError(Strings.ExpressionToken_IdentifierExpected(this.Position)); } return(this.Text); }
/// <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 a literal. /// </summary> /// <param name="lexer">The lexer to use.</param> /// <returns>The literal query token or null if something else was found.</returns> internal static LiteralToken TryParseLiteral(ExpressionLexer lexer) { DebugUtils.CheckNoExternalCallers(); Debug.Assert(lexer != null, "lexer != null"); switch (lexer.CurrentToken.Kind) { case ExpressionTokenKind.BooleanLiteral: return(ParseTypedLiteral(lexer, EdmCoreModel.Instance.GetBoolean(false), Microsoft.Data.OData.Metadata.EdmConstants.EdmBooleanTypeName)); case ExpressionTokenKind.DateTimeLiteral: return(ParseTypedLiteral(lexer, EdmCoreModel.Instance.GetTemporal(EdmPrimitiveTypeKind.DateTime, false), Microsoft.Data.OData.Metadata.EdmConstants.EdmDateTimeTypeName)); case ExpressionTokenKind.DateTimeOffsetLiteral: return(ParseTypedLiteral(lexer, EdmCoreModel.Instance.GetTemporal(EdmPrimitiveTypeKind.DateTimeOffset, false), Microsoft.Data.OData.Metadata.EdmConstants.EdmDateTimeOffsetTypeName)); case ExpressionTokenKind.TimeLiteral: return(ParseTypedLiteral(lexer, EdmCoreModel.Instance.GetTemporal(EdmPrimitiveTypeKind.Time, false), Microsoft.Data.OData.Metadata.EdmConstants.EdmTimeTypeName)); case ExpressionTokenKind.DecimalLiteral: return(ParseTypedLiteral(lexer, EdmCoreModel.Instance.GetDecimal(false), Microsoft.Data.OData.Metadata.EdmConstants.EdmDecimalTypeName)); case ExpressionTokenKind.NullLiteral: return(ParseNullLiteral(lexer)); case ExpressionTokenKind.StringLiteral: return(ParseTypedLiteral(lexer, EdmCoreModel.Instance.GetString(true), Microsoft.Data.OData.Metadata.EdmConstants.EdmStringTypeName)); case ExpressionTokenKind.Int64Literal: return(ParseTypedLiteral(lexer, EdmCoreModel.Instance.GetInt64(false), Microsoft.Data.OData.Metadata.EdmConstants.EdmInt64TypeName)); case ExpressionTokenKind.IntegerLiteral: return(ParseTypedLiteral(lexer, EdmCoreModel.Instance.GetInt32(false), Microsoft.Data.OData.Metadata.EdmConstants.EdmInt32TypeName)); case ExpressionTokenKind.DoubleLiteral: return(ParseTypedLiteral(lexer, EdmCoreModel.Instance.GetDouble(false), Microsoft.Data.OData.Metadata.EdmConstants.EdmDoubleTypeName)); case ExpressionTokenKind.SingleLiteral: return(ParseTypedLiteral(lexer, EdmCoreModel.Instance.GetSingle(false), Microsoft.Data.OData.Metadata.EdmConstants.EdmSingleTypeName)); case ExpressionTokenKind.GuidLiteral: return(ParseTypedLiteral(lexer, EdmCoreModel.Instance.GetGuid(false), Microsoft.Data.OData.Metadata.EdmConstants.EdmGuidTypeName)); case ExpressionTokenKind.BinaryLiteral: return(ParseTypedLiteral(lexer, EdmCoreModel.Instance.GetBinary(true), Microsoft.Data.OData.Metadata.EdmConstants.EdmBinaryTypeName)); case ExpressionTokenKind.GeographyLiteral: return(ParseTypedLiteral(lexer, EdmCoreModel.Instance.GetSpatial(EdmPrimitiveTypeKind.Geography, false), Microsoft.Data.OData.Metadata.EdmConstants.EdmGeographyTypeName)); case ExpressionTokenKind.GeometryLiteral: return(ParseTypedLiteral(lexer, EdmCoreModel.Instance.GetSpatial(EdmPrimitiveTypeKind.Geometry, false), Microsoft.Data.OData.Metadata.EdmConstants.EdmGeometryTypeName)); default: return(null); } }
/// <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> /// Parses a literal. /// Precondition: lexer is at a literal token type: Boolean, DateTime, Decimal, Null, String, Int64, Integer, Double, Single, Guid, Binary. /// </summary> /// <returns>The literal query token or null if something else was found.</returns> private object TryParseLiteral() { DebugUtils.CheckNoExternalCallers(); Debug.Assert(ExpressionLexer.IsLiteralType(this.CurrentToken.Kind), "TryParseLiteral called when not at a literal type token"); switch (this.CurrentToken.Kind) { case ExpressionTokenKind.BooleanLiteral: return(this.ParseTypedLiteral(EdmCoreModel.Instance.GetBoolean(false))); case ExpressionTokenKind.DateTimeLiteral: return(this.ParseTypedLiteral(EdmCoreModel.Instance.GetTemporal(EdmPrimitiveTypeKind.DateTime, false))); case ExpressionTokenKind.DecimalLiteral: return(this.ParseTypedLiteral(EdmCoreModel.Instance.GetDecimal(false))); case ExpressionTokenKind.NullLiteral: return(this.ParseNullLiteral()); case ExpressionTokenKind.StringLiteral: return(this.ParseTypedLiteral(EdmCoreModel.Instance.GetString(true))); case ExpressionTokenKind.Int64Literal: return(this.ParseTypedLiteral(EdmCoreModel.Instance.GetInt64(false))); case ExpressionTokenKind.IntegerLiteral: return(this.ParseTypedLiteral(EdmCoreModel.Instance.GetInt32(false))); case ExpressionTokenKind.DoubleLiteral: return(this.ParseTypedLiteral(EdmCoreModel.Instance.GetDouble(false))); case ExpressionTokenKind.SingleLiteral: return(this.ParseTypedLiteral(EdmCoreModel.Instance.GetSingle(false))); case ExpressionTokenKind.GuidLiteral: return(this.ParseTypedLiteral(EdmCoreModel.Instance.GetGuid(false))); case ExpressionTokenKind.BinaryLiteral: return(this.ParseTypedLiteral(EdmCoreModel.Instance.GetBinary(true))); case ExpressionTokenKind.DateTimeOffsetLiteral: return(this.ParseTypedLiteral(EdmCoreModel.Instance.GetDateTimeOffset(false))); case ExpressionTokenKind.TimeLiteral: return(this.ParseTypedLiteral(EdmCoreModel.Instance.GetTemporal(EdmPrimitiveTypeKind.Time, false))); case ExpressionTokenKind.GeographyLiteral: return(this.ParseTypedLiteral(EdmCoreModel.Instance.GetSpatial(EdmPrimitiveTypeKind.Geography, false))); case ExpressionTokenKind.GeometryLiteral: return(this.ParseTypedLiteral(EdmCoreModel.Instance.GetSpatial(EdmPrimitiveTypeKind.Geometry, false))); } return(null); }
/// <summary>Gets the current identifier text.</summary> /// <returns>The current identifier text.</returns> internal string GetIdentifier() { DebugUtils.CheckNoExternalCallers(); if (this.Kind != ExpressionTokenKind.Identifier) { throw ExpressionLexer.ParseError(Strings.ExpressionToken_IdentifierExpected(this.Position)); } Debug.Assert(this.Text != null, "Text is null"); return(this.Text); }
/// <summary> /// Parses the key value literal. /// </summary> /// <param name="lexer">The lexer positioned on the key value.</param> /// <returns>The literal query token.</returns> private static LiteralQueryToken ParseKeyValueLiteral(ExpressionLexer lexer) { Debug.Assert(lexer != null, "lexer != null"); LiteralQueryToken result = UriQueryExpressionParser.TryParseLiteral(lexer); if (result == null) { throw new ODataException(Strings.UriQueryPathParser_InvalidKeyValueLiteral(lexer.CurrentToken.Text)); } return(result); }
/// <summary> /// Parses the $filter expression. /// </summary> /// <param name="filter">The $filter expression string to parse.</param> /// <returns>The lexical token representing the filter.</returns> internal QueryToken ParseFilter(string filter) { DebugUtils.CheckNoExternalCallers(); Debug.Assert(filter != null, "filter != null"); this.recursionDepth = 0; this.lexer = new ExpressionLexer(filter, true /*moveToFirstToken*/); QueryToken result = this.ParseExpression(); this.lexer.ValidateToken(ExpressionTokenKind.End); 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>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> /// <returns>The value represented by the next token.</returns> internal object ReadLiteralToken() { DebugUtils.CheckNoExternalCallers(); this.NextToken(); if (ExpressionLexer.IsLiteralType(this.CurrentToken.Kind)) { return(this.TryParseLiteral()); } throw new ODataException(o.Strings.ExpressionLexer_ExpectedLiteralToken(this.CurrentToken.Text)); }
/// <summary> /// Parses the $filter expression. /// </summary> /// <param name="filter">The $filter expression string to parse.</param> /// <returns>The lexical token representing the filter.</returns> internal QueryToken ParseFilter(string filter) { DebugUtils.CheckNoExternalCallers(); Debug.Assert(filter != null, "filter != null"); this.recursionDepth = 0; this.lexer = CreateLexerForFilterOrOrderByExpression(filter); QueryToken result = this.ParseExpression(); this.lexer.ValidateToken(ExpressionTokenKind.End); return(result); }
/// <summary> /// Tries to parse a collection of function parameters for path. /// </summary> /// <param name="functionName">The function name to use in error messages.</param> /// <param name="parenthesisExpression">The contents of the parentheses portion of the current path segment.</param> /// <param name="splitParameters">The parameters if they were successfully split.</param> /// <returns>Whether the parameters could be split.</returns> internal static bool TrySplitFunctionParameters(string functionName, string parenthesisExpression, out ICollection <FunctionParameterToken> splitParameters) { DebugUtils.CheckNoExternalCallers(); Debug.Assert(!string.IsNullOrEmpty(parenthesisExpression), "!string.IsNullOrEmpty(parenthesisExpression)"); var lexer = new ExpressionLexer(parenthesisExpression, true /*moveToFirstToken*/, false /*useSemicolonDelimiter*/, true /*parsingFunctionParameters*/); if (lexer.CurrentToken.IsFunctionParameterToken) { splitParameters = null; return(false); } return(TrySplitFunctionParameters(lexer, ExpressionTokenKind.End, out splitParameters)); }
/// <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 a literal. /// </summary> /// <param name="lexer">The lexer to use.</param> /// <returns>The literal query token or null if something else was found.</returns> internal static LiteralQueryToken TryParseLiteral(ExpressionLexer lexer) { DebugUtils.CheckNoExternalCallers(); Debug.Assert(lexer != null, "lexer != null"); switch (lexer.CurrentToken.Kind) { case ExpressionTokenKind.BooleanLiteral: return ParseTypedLiteral(lexer, EdmCoreModel.Instance.GetBoolean(false), Microsoft.Data.OData.Metadata.EdmConstants.EdmBooleanTypeName); case ExpressionTokenKind.DateTimeLiteral: return ParseTypedLiteral(lexer, EdmCoreModel.Instance.GetTemporal(EdmPrimitiveTypeKind.DateTime, false), Microsoft.Data.OData.Metadata.EdmConstants.EdmDateTimeTypeName); case ExpressionTokenKind.DateTimeOffsetLiteral: return ParseTypedLiteral(lexer, EdmCoreModel.Instance.GetTemporal(EdmPrimitiveTypeKind.DateTimeOffset, false), Microsoft.Data.OData.Metadata.EdmConstants.EdmDateTimeOffsetTypeName); case ExpressionTokenKind.TimeLiteral: return ParseTypedLiteral(lexer, EdmCoreModel.Instance.GetTemporal(EdmPrimitiveTypeKind.Time, false), Microsoft.Data.OData.Metadata.EdmConstants.EdmTimeTypeName); case ExpressionTokenKind.DecimalLiteral: return ParseTypedLiteral(lexer, EdmCoreModel.Instance.GetDecimal(false), Microsoft.Data.OData.Metadata.EdmConstants.EdmDecimalTypeName); case ExpressionTokenKind.NullLiteral: return ParseNullLiteral(lexer); case ExpressionTokenKind.StringLiteral: return ParseTypedLiteral(lexer, EdmCoreModel.Instance.GetString(true), Microsoft.Data.OData.Metadata.EdmConstants.EdmStringTypeName); case ExpressionTokenKind.Int64Literal: return ParseTypedLiteral(lexer, EdmCoreModel.Instance.GetInt64(false), Microsoft.Data.OData.Metadata.EdmConstants.EdmInt64TypeName); case ExpressionTokenKind.IntegerLiteral: return ParseTypedLiteral(lexer, EdmCoreModel.Instance.GetInt32(false), Microsoft.Data.OData.Metadata.EdmConstants.EdmInt32TypeName); case ExpressionTokenKind.DoubleLiteral: return ParseTypedLiteral(lexer, EdmCoreModel.Instance.GetDouble(false), Microsoft.Data.OData.Metadata.EdmConstants.EdmDoubleTypeName); case ExpressionTokenKind.SingleLiteral: return ParseTypedLiteral(lexer, EdmCoreModel.Instance.GetSingle(false), Microsoft.Data.OData.Metadata.EdmConstants.EdmSingleTypeName); case ExpressionTokenKind.GuidLiteral: return ParseTypedLiteral(lexer, EdmCoreModel.Instance.GetGuid(false), Microsoft.Data.OData.Metadata.EdmConstants.EdmGuidTypeName); case ExpressionTokenKind.BinaryLiteral: return ParseTypedLiteral(lexer, EdmCoreModel.Instance.GetBinary(true), Microsoft.Data.OData.Metadata.EdmConstants.EdmBinaryTypeName); case ExpressionTokenKind.GeographyLiteral: return ParseTypedLiteral(lexer, EdmCoreModel.Instance.GetSpatial(EdmPrimitiveTypeKind.Geography, false), Microsoft.Data.OData.Metadata.EdmConstants.EdmGeographyTypeName); case ExpressionTokenKind.GeometryLiteral: return ParseTypedLiteral(lexer, EdmCoreModel.Instance.GetSpatial(EdmPrimitiveTypeKind.Geometry, false), Microsoft.Data.OData.Metadata.EdmConstants.EdmGeometryTypeName); default: return null; } }
/// <summary> /// Converts the given <paramref name="value"/> to a corresponding CLR type. Expects the /// <paramref name="value"/> to have already been properly unescaped from an actual Uri. /// </summary> /// <param name="value">Value from a Uri to be converted.</param> /// <param name="version">Version to be compliant with.</param> /// <param name="model">Optional model to perform verification against.</param> /// <param name="typeReference">Optional IEdmTypeReference to perform verification against. /// Callers must provide a <paramref name="model"/> containing this type if it is specified.</param> /// <returns>A CLR object that the <paramref name="value"/> represents.</returns> public static object ConvertFromUriLiteral(string value, ODataVersion version, IEdmModel model, IEdmTypeReference typeReference) { ExceptionUtils.CheckArgumentNotNull(value, "value"); if (typeReference != null && model == null) { throw new ODataException(ODataErrorStrings.ODataUriUtils_ConvertFromUriLiteralTypeRefWithoutModel); } if (model == null) { model = Microsoft.Data.Edm.Library.EdmCoreModel.Instance; } // Let ExpressionLexer try to get a primitive ExpressionLexer lexer = new ExpressionLexer(value, false /*moveToFirstToken*/, false /*useSemicolonDelimeter*/); Exception error; ExpressionToken token; lexer.TryPeekNextToken(out token, out error); if (token.Kind == ExpressionTokenKind.BracketedExpression) { // Should be a complex or collection value return(ODataUriConversionUtils.ConvertFromComplexOrCollectionValue(value, version, model, typeReference)); } object result = lexer.ReadLiteralToken(); // If we have a typeReference then perform verification and convert if necessary if (typeReference != null) { result = ODataUriConversionUtils.VerifyAndCoerceUriPrimitiveLiteral(result, model, typeReference, version); } if (result is ISpatial) { ODataVersionChecker.CheckSpatialValue(version); } 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 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> /// Converts the given <paramref name="value"/> to a corresponding CLR type. Expects the /// <paramref name="value"/> to have already been properly unescaped from an actual Uri. /// </summary> /// <param name="value">Value from a Uri to be converted.</param> /// <param name="version">Version to be compliant with.</param> /// <param name="model">Optional model to perform verification against.</param> /// <param name="typeReference">Optional IEdmTypeReference to perform verification against. /// Callers must provide a <paramref name="model"/> containing this type if it is specified.</param> /// <returns>A CLR object that the <paramref name="value"/> represents.</returns> public static object ConvertFromUriLiteral(string value, ODataVersion version, IEdmModel model, IEdmTypeReference typeReference) { ExceptionUtils.CheckArgumentNotNull(value, "value"); if (typeReference != null && model == null) { throw new ODataException(o.Strings.ODataUriUtils_ConvertFromUriLiteralTypeRefWithoutModel); } if (model == null) { model = Microsoft.Data.Edm.Library.EdmCoreModel.Instance; } // Let ExpressionLexer try to get a primitive ExpressionLexer lexer = new ExpressionLexer(value, false /*moveToFirstToken*/); Exception error; ExpressionToken token; if (lexer.TryPeekNextToken(out token, out error)) { object result = lexer.ReadLiteralToken(); // If we have a typeReference then perform verification and convert if necessary if (typeReference != null) { result = ODataUriConversionUtils.VerifyAndCoerceUriPrimitiveLiteral(result, model, typeReference, version); } if (result is ISpatial) { ODataVersionChecker.CheckSpatialValue(version); } return result; } // Should be a complex or collection value return ODataUriConversionUtils.ConvertFromComplexOrCollectionValue(value, version, model, typeReference); }
/// <summary> /// Parses the $expand expression. /// </summary> /// <param name="expand">The $expand expression string to parse.</param> /// <returns>The lexical token representing the expand.</returns> internal ExpandQueryToken ParseExpand(string expand) { DebugUtils.CheckNoExternalCallers(); Debug.Assert(expand != null, "expand != null"); this.lexer = new ExpressionLexer(expand, true /*moveToFirstToken*/); List <QueryToken> properties = new List <QueryToken>(); while (true) { properties.Add(this.ParseExpression()); if (this.lexer.CurrentToken.Kind != ExpressionTokenKind.Comma) { break; } this.lexer.NextToken(); } return(new ExpandQueryToken(properties)); }
/// <summary> /// Parses the $orderby expression. /// </summary> /// <param name="orderBy">The $orderby expression string to parse.</param> /// <returns>The enumeraion of lexical tokens representing order by tokens.</returns> internal IEnumerable <OrderByToken> ParseOrderBy(string orderBy) { DebugUtils.CheckNoExternalCallers(); Debug.Assert(orderBy != null, "orderBy != null"); this.recursionDepth = 0; this.lexer = CreateLexerForFilterOrOrderByExpression(orderBy); List <OrderByToken> orderByTokens = new List <OrderByToken>(); while (true) { QueryToken expression = this.ParseExpression(); bool ascending = true; if (this.TokenIdentifierIs(ExpressionConstants.KeywordAscending)) { this.lexer.NextToken(); } else if (this.TokenIdentifierIs(ExpressionConstants.KeywordDescending)) { this.lexer.NextToken(); ascending = false; } OrderByToken orderByToken = new OrderByToken(expression, ascending ? OrderByDirection.Ascending : OrderByDirection.Descending); orderByTokens.Add(orderByToken); if (this.lexer.CurrentToken.Kind != ExpressionTokenKind.Comma) { break; } this.lexer.NextToken(); } this.lexer.ValidateToken(ExpressionTokenKind.End); return(new ReadOnlyCollection <OrderByToken>(orderByTokens)); }
/// <summary> /// Parses the -, not unary operators. /// </summary> /// <returns>The lexical token representing the expression.</returns> private QueryToken ParseUnary() { this.RecurseEnter(); if (this.lexer.CurrentToken.Kind == ExpressionTokenKind.Minus || this.lexer.CurrentToken.IdentifierIs(ExpressionConstants.KeywordNot)) { ExpressionToken operatorToken = this.lexer.CurrentToken; this.lexer.NextToken(); if (operatorToken.Kind == ExpressionTokenKind.Minus && (ExpressionLexer.IsNumeric(this.lexer.CurrentToken.Kind))) { ExpressionToken numberLiteral = this.lexer.CurrentToken; numberLiteral.Text = "-" + numberLiteral.Text; numberLiteral.Position = operatorToken.Position; this.lexer.CurrentToken = numberLiteral; this.RecurseLeave(); return(this.ParsePrimary()); } QueryToken operand = this.ParseUnary(); UnaryOperatorKind unaryOperatorKind; if (operatorToken.Kind == ExpressionTokenKind.Minus) { unaryOperatorKind = UnaryOperatorKind.Negate; } else { Debug.Assert(operatorToken.IdentifierIs(ExpressionConstants.KeywordNot), "Was a new unary operator added?"); unaryOperatorKind = UnaryOperatorKind.Not; } this.RecurseLeave(); return(new UnaryOperatorQueryToken(unaryOperatorKind, operand)); } this.RecurseLeave(); return(this.ParsePrimary()); }
/// <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> /// 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="splitParameters">The parameters if they were successfully split.</param> /// <returns>Whether the parameters could be split.</returns> internal static bool TrySplitFunctionParameters(this ExpressionLexer lexer, out ICollection <FunctionParameterToken> splitParameters) { DebugUtils.CheckNoExternalCallers(); return(lexer.TrySplitFunctionParameters(ExpressionTokenKind.CloseParen, out splitParameters)); }
/// <summary> /// Parses the $filter expression. /// </summary> /// <param name="filter">The $filter expression string to parse.</param> /// <returns>The lexical token representing the filter.</returns> internal QueryToken ParseFilter(string filter) { DebugUtils.CheckNoExternalCallers(); Debug.Assert(filter != null, "filter != null"); this.recursionDepth = 0; this.lexer = new ExpressionLexer(filter, true /*moveToFirstToken*/); QueryToken result = this.ParseExpression(); this.lexer.ValidateToken(ExpressionTokenKind.End); return result; }
/// <summary> /// Parses the $orderby expression. /// </summary> /// <param name="orderBy">The $orderby expression string to parse.</param> /// <returns>The enumeraion of lexical tokens representing order by tokens.</returns> internal IEnumerable<OrderByQueryToken> ParseOrderBy(string orderBy) { DebugUtils.CheckNoExternalCallers(); Debug.Assert(orderBy != null, "orderBy != null"); this.recursionDepth = 0; this.lexer = new ExpressionLexer(orderBy, true /*moveToFirstToken*/); List<OrderByQueryToken> orderByTokens = new List<OrderByQueryToken>(); while (true) { QueryToken expression = this.ParseExpression(); bool ascending = true; if (this.TokenIdentifierIs(ExpressionConstants.KeywordAscending)) { this.lexer.NextToken(); } else if (this.TokenIdentifierIs(ExpressionConstants.KeywordDescending)) { this.lexer.NextToken(); ascending = false; } OrderByQueryToken orderByToken = new OrderByQueryToken(expression, ascending ? OrderByDirection.Ascending : OrderByDirection.Descending); orderByTokens.Add(orderByToken); if (this.lexer.CurrentToken.Kind != ExpressionTokenKind.Comma) { break; } this.lexer.NextToken(); } this.lexer.ValidateToken(ExpressionTokenKind.End); return new ReadOnlyCollection<OrderByQueryToken>(orderByTokens); }
/// <summary> /// Parses the key value literal. /// </summary> /// <param name="lexer">The lexer positioned on the key value.</param> /// <returns>The literal query token.</returns> private static LiteralQueryToken ParseKeyValueLiteral(ExpressionLexer lexer) { Debug.Assert(lexer != null, "lexer != null"); LiteralQueryToken result = UriQueryExpressionParser.TryParseLiteral(lexer); if (result == null) { throw new ODataException(Strings.UriQueryPathParser_InvalidKeyValueLiteral(lexer.CurrentToken.Text)); } 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> /// Parses the $expand expression. /// </summary> /// <param name="expand">The $expand expression string to parse.</param> /// <returns>The lexical token representing the expand.</returns> internal ExpandQueryToken ParseExpand(string expand) { DebugUtils.CheckNoExternalCallers(); Debug.Assert(expand != null, "expand != null"); this.lexer = new ExpressionLexer(expand, true /*moveToFirstToken*/); List<QueryToken> properties = new List<QueryToken>(); while (true) { properties.Add(this.ParseExpression()); if (this.lexer.CurrentToken.Kind != ExpressionTokenKind.Comma) { break; } this.lexer.NextToken(); } return new ExpandQueryToken(properties); }
/// <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> /// 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>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> /// Create a SelectExpandTermParser /// </summary> /// <param name="clauseToParse">the clause to parse</param> /// <param name="maxDepth">the maximum recursive depth</param> protected SelectExpandTermParser(string clauseToParse, int maxDepth) { this.maxDepth = maxDepth; this.recursionDepth = 0; this.Lexer = clauseToParse != null ? new ExpressionLexer(clauseToParse, false, true) : null; }