Code:
/ Dotnetfx_Win7_3.5.1 / Dotnetfx_Win7_3.5.1 / 3.5.1 / DEVDIV / depot / DevDiv / releases / Orcas / NetFXw7 / 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
- XamlClipboardData.cs
- Constraint.cs
- TextBox.cs
- RefreshPropertiesAttribute.cs
- DataGridViewEditingControlShowingEventArgs.cs
- CompositeControl.cs
- EasingKeyFrames.cs
- DataGridRowDetailsEventArgs.cs
- ReflectPropertyDescriptor.cs
- WindowsToolbarAsMenu.cs
- ToolStrip.cs
- ObfuscationAttribute.cs
- ThumbAutomationPeer.cs
- PeekCompletedEventArgs.cs
- Pen.cs
- NameTable.cs
- UnionExpr.cs
- XmlSortKeyAccumulator.cs
- XslAst.cs
- CommonRemoteMemoryBlock.cs
- ObjectDataSourceStatusEventArgs.cs
- SerializationEventsCache.cs
- TransformerConfigurationWizardBase.cs
- LinearGradientBrush.cs
- SimpleHandlerBuildProvider.cs
- InvalidOperationException.cs
- Point4D.cs
- ParsedAttributeCollection.cs
- ConnectionStringsExpressionBuilder.cs
- EngineSiteSapi.cs
- ValueSerializer.cs
- TextElement.cs
- MonitorWrapper.cs
- RangeValidator.cs
- SQLMembershipProvider.cs
- ChannelBinding.cs
- ToolStripRendererSwitcher.cs
- SelectionBorderGlyph.cs
- XmlTextReader.cs
- WebPartVerbCollection.cs
- PropertyGridEditorPart.cs
- CompilerErrorCollection.cs
- ObjectParameter.cs
- TypedDataSourceCodeGenerator.cs
- CodeRegionDirective.cs
- ExpressionPrefixAttribute.cs
- ObfuscateAssemblyAttribute.cs
- TextUtf8RawTextWriter.cs
- mediaeventargs.cs
- LineServices.cs
- InvalidAsynchronousStateException.cs
- HwndKeyboardInputProvider.cs
- TextCollapsingProperties.cs
- ReadOnlyDictionary.cs
- EntityCommandExecutionException.cs
- ListBase.cs
- MessageBox.cs
- EFTableProvider.cs
- Win32PrintDialog.cs
- SubpageParagraph.cs
- NullableDecimalSumAggregationOperator.cs
- ServiceReference.cs
- xmlglyphRunInfo.cs
- InternalConfigConfigurationFactory.cs
- SecurityUtils.cs
- ActivityCodeDomSerializationManager.cs
- CallContext.cs
- ExtensionSimplifierMarkupObject.cs
- BigInt.cs
- SerializationEventsCache.cs
- DoubleKeyFrameCollection.cs
- DataGridPreparingCellForEditEventArgs.cs
- StringExpressionSet.cs
- AvtEvent.cs
- SerialErrors.cs
- TraceRecord.cs
- BitmapFrameEncode.cs
- BindingOperations.cs
- SchemaImporterExtensionElementCollection.cs
- JsonStringDataContract.cs
- QualificationDataItem.cs
- AQNBuilder.cs
- ObjectAnimationUsingKeyFrames.cs
- VisualBrush.cs
- TextRangeEdit.cs
- NetWebProxyFinder.cs
- NamedPipeTransportManager.cs
- ServiceContractListItemList.cs
- EditorPartDesigner.cs
- ButtonBase.cs
- HostingEnvironmentException.cs
- ZipIOBlockManager.cs
- TypeResolver.cs
- URLString.cs
- SystemIPGlobalStatistics.cs
- FontNamesConverter.cs
- GenericWebPart.cs
- WindowsScroll.cs
- Decimal.cs
- InertiaRotationBehavior.cs