Code:
/ Dotnetfx_Vista_SP2 / Dotnetfx_Vista_SP2 / 8.0.50727.4016 / DEVDIV / depot / DevDiv / releases / Orcas / QFE / ndp / fx / src / DataWeb / Server / System / Data / Services / Parsing / ExpressionLexer.cs / 1 / ExpressionLexer.cs
//---------------------------------------------------------------------- //// Copyright (c) Microsoft Corporation. All rights reserved. // //// Provides a type to tokenize text. // // // @owner [....] //--------------------------------------------------------------------- namespace System.Data.Services.Parsing { using System; using System.Diagnostics; using System.Text; ///Use this class to parse an expression in the Astoria URI format. ////// Literals (non-normative "handy" reference - see spec for correct expression): /// Null null /// Boolean true | false /// Int32 (digit+) /// Int64 (digit+)L /// Decimal (digit+ ['.' digit+])M /// Float (digit+ ['.' digit+][e|E [+|-] digit+)f /// Double (digit+ ['.' digit+][e|E [+|-] digit+) /// String "'" .* "'" /// DateTime datetime"'"dddd-dd-dd[T|' ']dd:mm[ss[.fffffff]]"'" /// Binary (binary|X)'digit*' /// GUID guid'digit*' /// [DebuggerDisplay("ExpressionLexer ({text} @ {textPos} [{token}]")] internal class ExpressionLexer { #region Private fields. ///Text being parsed. private readonly string text; ///Length of text being parsed. private readonly int textLen; ///Position on text being parsed. private int textPos; ///Character being processed. private char ch; ///Token being processed. private Token token; #endregion Private fields. #region Constructors. ///Initializes a new /// Expression to parse. internal ExpressionLexer(string expression) { Debug.Assert(expression != null, "expression != null"); this.text = expression; this.textLen = this.text.Length; this.SetTextPos(0); this.NextToken(); } #endregion Constructors. #region Internal properties. ///. Token being processed. internal Token CurrentToken { get { return this.token; } set { this.token = value; } } ///Text being parsed. internal string ExpressionText { get { return this.text; } } ///Position on text being parsed. internal int Position { get { return this.token.Position; } } #endregion Internal properties. #region Internal methods. ///Whether the specified token identifier is a numeric literal. /// Token to check. ///true if it's a numeric literal; false otherwise. internal static bool IsNumeric(TokenId id) { return id == TokenId.IntegerLiteral || id == TokenId.DecimalLiteral || id == TokenId.DoubleLiteral || id == TokenId.Int64Literal || id == TokenId.SingleLiteral; } ///Reads the next token, skipping whitespace as necessary. internal void NextToken() { while (Char.IsWhiteSpace(this.ch)) { this.NextChar(); } TokenId t; int tokenPos = this.textPos; switch (this.ch) { case '(': this.NextChar(); t = TokenId.OpenParen; break; case ')': this.NextChar(); t = TokenId.CloseParen; break; case ',': this.NextChar(); t = TokenId.Comma; break; case '-': bool hasNext = this.textPos + 1 < this.textLen; if (hasNext && Char.IsDigit(this.text[this.textPos + 1])) { this.NextChar(); t = this.ParseFromDigit(); if (IsNumeric(t)) { break; } // If it looked like a numeric but wasn't (because it was a binary 0x... value for example), // we'll rewind and fall through to a simple '-' token. this.SetTextPos(tokenPos); } else if (hasNext && this.text[tokenPos + 1] == XmlConstants.XmlInfinityLiteral[0]) { this.NextChar(); this.ParseIdentifier(); if (SubstringEqualsOrdinal(this.text, tokenPos + 1, XmlConstants.XmlInfinityLiteral)) { t = TokenId.DoubleLiteral; break; } // If it looked like '-INF' but wasn't we'll rewind and fall through to a simple '-' token. this.SetTextPos(tokenPos); } this.NextChar(); t = TokenId.Minus; break; case '=': this.NextChar(); t = TokenId.Equal; break; case '/': this.NextChar(); t = TokenId.Slash; break; case '?': this.NextChar(); t = TokenId.Question; break; case '.': this.NextChar(); t = TokenId.Dot; break; case '\'': char quote = this.ch; do { this.NextChar(); while (this.textPos < this.textLen && this.ch != quote) { this.NextChar(); } if (this.textPos == this.textLen) { throw ParseError(Strings.RequestQueryParser_UnterminatedStringLiteral(this.textPos, this.text)); } this.NextChar(); } while (this.ch == quote); t = TokenId.StringLiteral; break; default: if (Char.IsLetter(this.ch) || this.ch == '_') { this.ParseIdentifier(); t = TokenId.Identifier; break; } if (Char.IsDigit(this.ch)) { t = this.ParseFromDigit(); break; } if (this.textPos == this.textLen) { t = TokenId.End; break; } throw ParseError(Strings.RequestQueryParser_InvalidCharacter(this.ch, this.textPos)); } this.token.Id = t; this.token.Text = this.text.Substring(tokenPos, this.textPos - tokenPos); this.token.Position = tokenPos; // Handle type-prefixed literals such as binary, datetime or guid. this.HandleTypePrefixedLiterals(); // Handle keywords. if (this.token.Id == TokenId.Identifier) { if (this.token.Text == XmlConstants.XmlInfinityLiteral || this.token.Text == XmlConstants.XmlNaNLiteral) { this.token.Id = TokenId.DoubleLiteral; } else if (this.token.Text == ExpressionConstants.KeywordTrue || this.token.Text == ExpressionConstants.KeywordFalse) { this.token.Id = TokenId.BooleanLiteral; } else if (this.token.Text == ExpressionConstants.KeywordNull) { this.token.Id = TokenId.NullLiteral; } } } ////// Starting from an identifier, reads a sequence of dots and /// identifiers, and returns the text for it, with whitespace /// stripped. /// ///The dotted identifier starting at the current identifie. internal string ReadDottedIdentifier() { this.ValidateToken(TokenId.Identifier); StringBuilder builder = null; string result = this.CurrentToken.Text; this.NextToken(); while (this.CurrentToken.Id == TokenId.Dot) { this.NextToken(); this.ValidateToken(TokenId.Identifier); if (builder == null) { builder = new StringBuilder(result, result.Length + 1 + this.CurrentToken.Text.Length); } builder.Append('.'); builder.Append(this.CurrentToken.Text); this.NextToken(); } if (builder != null) { result = builder.ToString(); } return result; } ///Returns the next token without advancing the lexer. ///The next token. internal Token PeekNextToken() { int savedTextPos = this.textPos; char savedChar = this.ch; Token savedToken = this.token; this.NextToken(); Token result = this.token; this.textPos = savedTextPos; this.ch = savedChar; this.token = savedToken; return result; } ///Validates the current token is of the specified kind. /// Expected token kind. internal void ValidateToken(TokenId t) { if (this.token.Id != t) { throw ParseError(Strings.RequestQueryParser_SyntaxError(this.textPos)); } } #endregion Internal methods. #region Private methods. ////// Checks whether /// Text to look in. /// Index intocontains at position /// . /// . /// Text to look for. /// true if the substring is equal using an ordinal comparison; false otherwise. private static bool SubstringEqualsOrdinal(string text, int index, string match) { Debug.Assert(text != null, "text != null"); Debug.Assert(match != null, "match != null"); return String.CompareOrdinal(text, index, match, 0, match.Length) == 0; } ///Creates an exception for a parse error. /// Message text. ///A new Exception. private static Exception ParseError(string message) { return DataServiceException.CreateSyntaxError(message); } ///Handles lexemes that are formed by an identifier followed by a quoted string. ///This method modified the token field as necessary. private void HandleTypePrefixedLiterals() { TokenId id = this.token.Id; if (id != TokenId.Identifier) { return; } bool quoteFollows = this.ch == '\''; if (!quoteFollows) { return; } string tokenText = this.token.Text; if (String.Equals(tokenText, "datetime", StringComparison.OrdinalIgnoreCase)) { id = TokenId.DateTimeLiteral; } else if (String.Equals(tokenText, "guid", StringComparison.OrdinalIgnoreCase)) { id = TokenId.GuidLiteral; } else if (String.Equals(tokenText, "binary", StringComparison.OrdinalIgnoreCase) || tokenText == "X") { id = TokenId.BinaryLiteral; } else { return; } int tokenPos = this.token.Position; do { this.NextChar(); } while (this.ch != '\0' && this.ch != '\''); if (this.ch == '\0') { throw ParseError(Strings.RequestQueryParser_UnterminatedLiteral(this.textPos, this.text)); } this.NextChar(); this.token.Id = id; this.token.Text = this.text.Substring(tokenPos, this.textPos - tokenPos); } ///Advanced to the next character. private void NextChar() { if (this.textPos < this.textLen) { this.textPos++; } this.ch = this.textPos < this.textLen ? this.text[this.textPos] : '\0'; } ///Parses a token that starts with a digit. ///The kind of token recognized. private TokenId ParseFromDigit() { Debug.Assert(Char.IsDigit(this.ch), "Char.IsDigit(this.ch)"); TokenId result; char startChar = this.ch; this.NextChar(); if (startChar == '0' && this.ch == 'x') { result = TokenId.BinaryLiteral; do { this.NextChar(); } while (WebConvert.IsCharHexDigit(this.ch)); } else { result = TokenId.IntegerLiteral; while (Char.IsDigit(this.ch)) { this.NextChar(); } if (this.ch == '.') { result = TokenId.DoubleLiteral; this.NextChar(); this.ValidateDigit(); do { this.NextChar(); } while (Char.IsDigit(this.ch)); } if (this.ch == 'E' || this.ch == 'e') { result = TokenId.DoubleLiteral; this.NextChar(); if (this.ch == '+' || this.ch == '-') { this.NextChar(); } this.ValidateDigit(); do { this.NextChar(); } while (Char.IsDigit(this.ch)); } if (this.ch == 'M') { result = TokenId.DecimalLiteral; this.NextChar(); } else if (this.ch == 'L') { result = TokenId.Int64Literal; this.NextChar(); } else if (this.ch == 'f') { result = TokenId.SingleLiteral; this.NextChar(); } } return result; } ///Parses an identifier by advancing the current character. private void ParseIdentifier() { Debug.Assert(Char.IsLetter(this.ch) || this.ch == '_', "Char.IsLetter(this.ch) || this.ch == '_'"); do { this.NextChar(); } while (Char.IsLetterOrDigit(this.ch) || this.ch == '_'); } ///Sets the text position. /// New text position. private void SetTextPos(int pos) { this.textPos = pos; this.ch = this.textPos < this.textLen ? this.text[this.textPos] : '\0'; } ///Validates the current character is a digit. private void ValidateDigit() { if (!Char.IsDigit(this.ch)) { throw ParseError(Strings.RequestQueryParser_DigitExpected(this.textPos)); } } #endregion Private methods. } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. //---------------------------------------------------------------------- //// Copyright (c) Microsoft Corporation. All rights reserved. // //// Provides a type to tokenize text. // // // @owner [....] //--------------------------------------------------------------------- namespace System.Data.Services.Parsing { using System; using System.Diagnostics; using System.Text; ///Use this class to parse an expression in the Astoria URI format. ////// Literals (non-normative "handy" reference - see spec for correct expression): /// Null null /// Boolean true | false /// Int32 (digit+) /// Int64 (digit+)L /// Decimal (digit+ ['.' digit+])M /// Float (digit+ ['.' digit+][e|E [+|-] digit+)f /// Double (digit+ ['.' digit+][e|E [+|-] digit+) /// String "'" .* "'" /// DateTime datetime"'"dddd-dd-dd[T|' ']dd:mm[ss[.fffffff]]"'" /// Binary (binary|X)'digit*' /// GUID guid'digit*' /// [DebuggerDisplay("ExpressionLexer ({text} @ {textPos} [{token}]")] internal class ExpressionLexer { #region Private fields. ///Text being parsed. private readonly string text; ///Length of text being parsed. private readonly int textLen; ///Position on text being parsed. private int textPos; ///Character being processed. private char ch; ///Token being processed. private Token token; #endregion Private fields. #region Constructors. ///Initializes a new /// Expression to parse. internal ExpressionLexer(string expression) { Debug.Assert(expression != null, "expression != null"); this.text = expression; this.textLen = this.text.Length; this.SetTextPos(0); this.NextToken(); } #endregion Constructors. #region Internal properties. ///. Token being processed. internal Token CurrentToken { get { return this.token; } set { this.token = value; } } ///Text being parsed. internal string ExpressionText { get { return this.text; } } ///Position on text being parsed. internal int Position { get { return this.token.Position; } } #endregion Internal properties. #region Internal methods. ///Whether the specified token identifier is a numeric literal. /// Token to check. ///true if it's a numeric literal; false otherwise. internal static bool IsNumeric(TokenId id) { return id == TokenId.IntegerLiteral || id == TokenId.DecimalLiteral || id == TokenId.DoubleLiteral || id == TokenId.Int64Literal || id == TokenId.SingleLiteral; } ///Reads the next token, skipping whitespace as necessary. internal void NextToken() { while (Char.IsWhiteSpace(this.ch)) { this.NextChar(); } TokenId t; int tokenPos = this.textPos; switch (this.ch) { case '(': this.NextChar(); t = TokenId.OpenParen; break; case ')': this.NextChar(); t = TokenId.CloseParen; break; case ',': this.NextChar(); t = TokenId.Comma; break; case '-': bool hasNext = this.textPos + 1 < this.textLen; if (hasNext && Char.IsDigit(this.text[this.textPos + 1])) { this.NextChar(); t = this.ParseFromDigit(); if (IsNumeric(t)) { break; } // If it looked like a numeric but wasn't (because it was a binary 0x... value for example), // we'll rewind and fall through to a simple '-' token. this.SetTextPos(tokenPos); } else if (hasNext && this.text[tokenPos + 1] == XmlConstants.XmlInfinityLiteral[0]) { this.NextChar(); this.ParseIdentifier(); if (SubstringEqualsOrdinal(this.text, tokenPos + 1, XmlConstants.XmlInfinityLiteral)) { t = TokenId.DoubleLiteral; break; } // If it looked like '-INF' but wasn't we'll rewind and fall through to a simple '-' token. this.SetTextPos(tokenPos); } this.NextChar(); t = TokenId.Minus; break; case '=': this.NextChar(); t = TokenId.Equal; break; case '/': this.NextChar(); t = TokenId.Slash; break; case '?': this.NextChar(); t = TokenId.Question; break; case '.': this.NextChar(); t = TokenId.Dot; break; case '\'': char quote = this.ch; do { this.NextChar(); while (this.textPos < this.textLen && this.ch != quote) { this.NextChar(); } if (this.textPos == this.textLen) { throw ParseError(Strings.RequestQueryParser_UnterminatedStringLiteral(this.textPos, this.text)); } this.NextChar(); } while (this.ch == quote); t = TokenId.StringLiteral; break; default: if (Char.IsLetter(this.ch) || this.ch == '_') { this.ParseIdentifier(); t = TokenId.Identifier; break; } if (Char.IsDigit(this.ch)) { t = this.ParseFromDigit(); break; } if (this.textPos == this.textLen) { t = TokenId.End; break; } throw ParseError(Strings.RequestQueryParser_InvalidCharacter(this.ch, this.textPos)); } this.token.Id = t; this.token.Text = this.text.Substring(tokenPos, this.textPos - tokenPos); this.token.Position = tokenPos; // Handle type-prefixed literals such as binary, datetime or guid. this.HandleTypePrefixedLiterals(); // Handle keywords. if (this.token.Id == TokenId.Identifier) { if (this.token.Text == XmlConstants.XmlInfinityLiteral || this.token.Text == XmlConstants.XmlNaNLiteral) { this.token.Id = TokenId.DoubleLiteral; } else if (this.token.Text == ExpressionConstants.KeywordTrue || this.token.Text == ExpressionConstants.KeywordFalse) { this.token.Id = TokenId.BooleanLiteral; } else if (this.token.Text == ExpressionConstants.KeywordNull) { this.token.Id = TokenId.NullLiteral; } } } ////// Starting from an identifier, reads a sequence of dots and /// identifiers, and returns the text for it, with whitespace /// stripped. /// ///The dotted identifier starting at the current identifie. internal string ReadDottedIdentifier() { this.ValidateToken(TokenId.Identifier); StringBuilder builder = null; string result = this.CurrentToken.Text; this.NextToken(); while (this.CurrentToken.Id == TokenId.Dot) { this.NextToken(); this.ValidateToken(TokenId.Identifier); if (builder == null) { builder = new StringBuilder(result, result.Length + 1 + this.CurrentToken.Text.Length); } builder.Append('.'); builder.Append(this.CurrentToken.Text); this.NextToken(); } if (builder != null) { result = builder.ToString(); } return result; } ///Returns the next token without advancing the lexer. ///The next token. internal Token PeekNextToken() { int savedTextPos = this.textPos; char savedChar = this.ch; Token savedToken = this.token; this.NextToken(); Token result = this.token; this.textPos = savedTextPos; this.ch = savedChar; this.token = savedToken; return result; } ///Validates the current token is of the specified kind. /// Expected token kind. internal void ValidateToken(TokenId t) { if (this.token.Id != t) { throw ParseError(Strings.RequestQueryParser_SyntaxError(this.textPos)); } } #endregion Internal methods. #region Private methods. ////// Checks whether /// Text to look in. /// Index intocontains at position /// . /// . /// Text to look for. /// true if the substring is equal using an ordinal comparison; false otherwise. private static bool SubstringEqualsOrdinal(string text, int index, string match) { Debug.Assert(text != null, "text != null"); Debug.Assert(match != null, "match != null"); return String.CompareOrdinal(text, index, match, 0, match.Length) == 0; } ///Creates an exception for a parse error. /// Message text. ///A new Exception. private static Exception ParseError(string message) { return DataServiceException.CreateSyntaxError(message); } ///Handles lexemes that are formed by an identifier followed by a quoted string. ///This method modified the token field as necessary. private void HandleTypePrefixedLiterals() { TokenId id = this.token.Id; if (id != TokenId.Identifier) { return; } bool quoteFollows = this.ch == '\''; if (!quoteFollows) { return; } string tokenText = this.token.Text; if (String.Equals(tokenText, "datetime", StringComparison.OrdinalIgnoreCase)) { id = TokenId.DateTimeLiteral; } else if (String.Equals(tokenText, "guid", StringComparison.OrdinalIgnoreCase)) { id = TokenId.GuidLiteral; } else if (String.Equals(tokenText, "binary", StringComparison.OrdinalIgnoreCase) || tokenText == "X") { id = TokenId.BinaryLiteral; } else { return; } int tokenPos = this.token.Position; do { this.NextChar(); } while (this.ch != '\0' && this.ch != '\''); if (this.ch == '\0') { throw ParseError(Strings.RequestQueryParser_UnterminatedLiteral(this.textPos, this.text)); } this.NextChar(); this.token.Id = id; this.token.Text = this.text.Substring(tokenPos, this.textPos - tokenPos); } ///Advanced to the next character. private void NextChar() { if (this.textPos < this.textLen) { this.textPos++; } this.ch = this.textPos < this.textLen ? this.text[this.textPos] : '\0'; } ///Parses a token that starts with a digit. ///The kind of token recognized. private TokenId ParseFromDigit() { Debug.Assert(Char.IsDigit(this.ch), "Char.IsDigit(this.ch)"); TokenId result; char startChar = this.ch; this.NextChar(); if (startChar == '0' && this.ch == 'x') { result = TokenId.BinaryLiteral; do { this.NextChar(); } while (WebConvert.IsCharHexDigit(this.ch)); } else { result = TokenId.IntegerLiteral; while (Char.IsDigit(this.ch)) { this.NextChar(); } if (this.ch == '.') { result = TokenId.DoubleLiteral; this.NextChar(); this.ValidateDigit(); do { this.NextChar(); } while (Char.IsDigit(this.ch)); } if (this.ch == 'E' || this.ch == 'e') { result = TokenId.DoubleLiteral; this.NextChar(); if (this.ch == '+' || this.ch == '-') { this.NextChar(); } this.ValidateDigit(); do { this.NextChar(); } while (Char.IsDigit(this.ch)); } if (this.ch == 'M') { result = TokenId.DecimalLiteral; this.NextChar(); } else if (this.ch == 'L') { result = TokenId.Int64Literal; this.NextChar(); } else if (this.ch == 'f') { result = TokenId.SingleLiteral; this.NextChar(); } } return result; } ///Parses an identifier by advancing the current character. private void ParseIdentifier() { Debug.Assert(Char.IsLetter(this.ch) || this.ch == '_', "Char.IsLetter(this.ch) || this.ch == '_'"); do { this.NextChar(); } while (Char.IsLetterOrDigit(this.ch) || this.ch == '_'); } ///Sets the text position. /// New text position. private void SetTextPos(int pos) { this.textPos = pos; this.ch = this.textPos < this.textLen ? this.text[this.textPos] : '\0'; } ///Validates the current character is a digit. private void ValidateDigit() { if (!Char.IsDigit(this.ch)) { throw ParseError(Strings.RequestQueryParser_DigitExpected(this.textPos)); } } #endregion Private methods. } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007.
Link Menu
This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- UrlRoutingHandler.cs
- QilName.cs
- BamlRecordWriter.cs
- DataGridSortCommandEventArgs.cs
- _Rfc2616CacheValidators.cs
- MD5CryptoServiceProvider.cs
- SafeBitVector32.cs
- QilInvokeLateBound.cs
- DataServiceConfiguration.cs
- State.cs
- PrefixQName.cs
- BufferModesCollection.cs
- ResourceReferenceKeyNotFoundException.cs
- OrthographicCamera.cs
- DeviceContexts.cs
- ObjectSecurity.cs
- DropShadowBitmapEffect.cs
- ToolStripContainer.cs
- Size.cs
- FileDialog.cs
- ConnectionManagementSection.cs
- ToolStripStatusLabel.cs
- NullableFloatMinMaxAggregationOperator.cs
- VirtualizingStackPanel.cs
- documentsequencetextpointer.cs
- InternalEnumValidator.cs
- URLMembershipCondition.cs
- IResourceProvider.cs
- TableItemStyle.cs
- CalendarDataBindingHandler.cs
- TextServicesCompartmentContext.cs
- ToolStripOverflowButton.cs
- CustomValidator.cs
- InfoCardAsymmetricCrypto.cs
- WSUtilitySpecificationVersion.cs
- MutexSecurity.cs
- PropertyIdentifier.cs
- GB18030Encoding.cs
- ServiceModelSecurityTokenTypes.cs
- LogicalExpr.cs
- HotCommands.cs
- TemplateInstanceAttribute.cs
- WindowsRegion.cs
- PerspectiveCamera.cs
- ConfigurationSectionGroupCollection.cs
- dtdvalidator.cs
- DataObject.cs
- ISFTagAndGuidCache.cs
- RoleExceptions.cs
- Point4DValueSerializer.cs
- BindingExpressionBase.cs
- ToolStripSeparatorRenderEventArgs.cs
- CheckPair.cs
- ToolStripDropDown.cs
- TypeKeyValue.cs
- RequestCacheValidator.cs
- ConfigXmlComment.cs
- PowerModeChangedEventArgs.cs
- MailBnfHelper.cs
- FieldBuilder.cs
- TextLineResult.cs
- StringKeyFrameCollection.cs
- ContentOperations.cs
- PerfService.cs
- ButtonChrome.cs
- x509store.cs
- MasterPage.cs
- ToolStripLabel.cs
- ObjectParameter.cs
- AsymmetricSignatureFormatter.cs
- mediaeventshelper.cs
- SystemEvents.cs
- FilterQueryOptionExpression.cs
- ParagraphResult.cs
- MobileUserControlDesigner.cs
- WebPartVerb.cs
- webeventbuffer.cs
- RawMouseInputReport.cs
- DataGridState.cs
- StringValueSerializer.cs
- RecordConverter.cs
- ReadOnlyHierarchicalDataSource.cs
- SuppressIldasmAttribute.cs
- UIElementParagraph.cs
- TransportContext.cs
- ServiceNotStartedException.cs
- MessageEnumerator.cs
- UniformGrid.cs
- InfoCardRSACryptoProvider.cs
- XmlReflectionImporter.cs
- BindingOperations.cs
- RegexCaptureCollection.cs
- RadioButtonRenderer.cs
- TreeIterator.cs
- WebPartsPersonalization.cs
- ServicePointManagerElement.cs
- StaticTextPointer.cs
- DesignBindingEditor.cs
- BamlLocalizerErrorNotifyEventArgs.cs
- UnsafeNetInfoNativeMethods.cs