| File: parent\Shared\LanguageParser\tokenCharReader.cs | Web Access |
| Project: Microsoft.Build.Tasks.csproj (Microsoft.Build.Tasks.Core) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System; using System.IO; namespace Microsoft.Build.Shared.LanguageParser { /* * Class: TokenCharReader * * Reads over the contents of a source file (in the form of a string). * Provides utility functions for skipping and checking the value of characters. * */ internal class TokenCharReader { // The sources private StreamMappedString _sources; // Current character offset within sources. private int _position; // The current line. One-relative. private int _currentLine; // One-relative /* * Method: TokenCharReader * * Construct */ internal TokenCharReader(Stream binaryStream, bool forceANSI) { Reset(); _sources = new StreamMappedString(binaryStream, forceANSI); } /* * Method: Reset * * Reset to the top of the sources. */ internal void Reset() { _position = 0; _currentLine = 1; // One-relative } /* * Method: CurrentLine * * The current line number */ internal int CurrentLine { get { return _currentLine; } } /* * Method: Position * * The character offset within the sources. */ internal int Position { get { return _position; } // Having a set operator makes this class not forward-only. // If this becomes necessary later, then implement a push-pop // scheme for saving current positions and get rid of this. // This will force the caller to declare ahead of time whether // they may want to return here. set { _position = value; } } /* * Method: Skip * * Skip to the next character. */ protected void Skip() { if (TokenChar.IsNewLine(CurrentCharacter)) { ++_currentLine; } ++_position; } /* * Method: Skip (overload) * * Skip the next n characters. */ protected void Skip(int n) { for (int i = 0; i < n; ++i) { Skip(); } } /* * Method: CurrentCharacter * * Get the current character. */ internal char CurrentCharacter { get { return _sources.GetAt(_position); } } /* * Method: EndOfLines * * Return true if we've reached the end of sources. */ internal bool EndOfLines { get { return _sources.IsPastEnd(_position); } } /* * Method: GetCurrentMatchedString * * Get the string that starts with the given start position and ends with this.position. */ internal string GetCurrentMatchedString(int startPosition) { return _sources.Substring(startPosition, _position - startPosition); } /* * Method: Sink * * See if the next characters match the given string. If they do, * sink this string. */ internal bool Sink(string match) { return Sink(match, false); } /// <summary> /// See if the next characters match the given string. If they do, sink this string. /// </summary> /// <param name="match"></param> /// <param name="ignoreCase"></param> /// <returns></returns> private bool Sink(string match, bool ignoreCase) { // Is there enough left for this match? if (_sources.IsPastEnd(_position + match.Length - 1)) { return false; } string compare = _sources.Substring(_position, match.Length); if ( String.Equals( match, compare, (ignoreCase /* ignore case */) ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal)) { Skip(match.Length); return true; } return false; } /* * Method: SinkCharacter * * Sink and return one character. */ internal char SinkCharacter() { char c = CurrentCharacter; Skip(); return c; } /* * Method: SinkIgnoreCase * * See if the next characters match the given string without case. */ internal bool SinkIgnoreCase(string match) { return Sink(match, true); } /* * Method: MatchNextIdentifierStart * * Determine whether a given character is a C# or VB identifier start character. * Both languages agree on this format. */ internal bool MatchNextIdentifierStart() { // From 2.4.2 of the C# Language Specification // identifier-start-letter-character: if (CurrentCharacter == '_' || TokenChar.IsLetter(CurrentCharacter)) { return true; } return false; } /* * Method: SinkIdentifierStart * * Determine whether a given character is a C# or VB identifier start character. * Both languages agree on this format. */ internal bool SinkIdentifierStart() { if (MatchNextIdentifierStart()) { Skip(); return true; } return false; } /* * Method: SinkIdentifierPart * * Determine whether a given character is a C# or VB identifier part character * Both languages agree on this format. */ internal bool SinkIdentifierPart() { // From 2.4.2 of the C# Language Specification // identifier-part-letter-character: if ( TokenChar.IsLetter(CurrentCharacter) || TokenChar.IsDecimalDigit(CurrentCharacter) || TokenChar.IsConnecting(CurrentCharacter) || TokenChar.IsCombining(CurrentCharacter) || TokenChar.IsFormatting(CurrentCharacter)) { Skip(); return true; } return false; } /* * Method: SinkNewLine * * Sink a newline. */ internal bool SinkNewLine() { if (EndOfLines) { return false; } int originalPosition = _position; if (Sink("\xd\xa")) // This sequence is treated as a single new line. { ++_currentLine; Assumed.NotEqual(originalPosition, _position, "Expected position to be incremented."); return true; } if (TokenChar.IsNewLine(CurrentCharacter)) { Skip(); Assumed.NotEqual(originalPosition, _position, "Expected position to be incremented."); return true; } return false; } /* * Method: SinkToEndOfLine * * Sink from the current position to the first end-of-line. */ internal bool SinkToEndOfLine() { while (!TokenChar.IsNewLine(CurrentCharacter)) { Skip(); } return true; // Matching zero characters is ok. } /* * Method: SinkUntil * * Sink until the given string is found. Match including the given string. */ internal bool SinkUntil(string find) { bool found = false; while (!EndOfLines && !found) { if (Sink(find)) { found = true; } else { Skip(); } } return found; // Return true if the matching string was found. } /* * Method: SinkMultipleHexDigits * * Sink multiple hex digits. */ internal bool SinkMultipleHexDigits() { int count = 0; while (TokenChar.IsHexDigit(CurrentCharacter)) { ++count; Skip(); } return count > 0; // Must match at least one } /* * Method: SinkMultipleDecimalDigits * * Sink multiple decimal digits. */ internal bool SinkMultipleDecimalDigits() { int count = 0; while (TokenChar.IsDecimalDigit(CurrentCharacter)) { ++count; Skip(); } return count > 0; // Must match at least one } } }