#define DEBUG using System; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Runtime.CompilerServices; using System.Text; using Microsoft.VisualBasic; using Microsoft.VisualBasic.CompilerServices; namespace AspClassic.Parser; /// /// A lexical analyzer for Visual Basic .NET. It produces a stream of lexical tokens. /// public sealed class Scanner : IDisposable { private TextReader _Source; private char _PeekCache; private bool _PeekCacheHasValue; private char _PeekAheadCache; private bool _PeekAheadCacheHasValue; private int _Index; private int _Line; private int _Column; private List _Tokens; private int _Position; private bool _Disposed; private int _TabSpaces; private LanguageVersion _Version; [SpecialName] private Dictionary _0024STATIC_0024ScanPossibleTypeCharacter_00242011182E41182E4_0024TypeCharacterTable; /// /// How many columns a tab character should be considered. /// public int TabSpaces { get { return _TabSpaces; } set { if (value < 1) { throw new ArgumentException("Tabs cannot represent less than one space."); } _TabSpaces = value; } } /// /// The version of Visual Basic this scanner operates on. /// public LanguageVersion Version => _Version; private Location CurrentLocation => new Location(_Index, _Line, _Column); /// /// Whether the stream is positioned on the first token. /// public bool IsOnFirstToken => _Position == -1; /// /// Constructs a scanner for a string. /// /// The string to scan. public Scanner(string source) { _PeekCacheHasValue = false; _PeekAheadCacheHasValue = false; _Index = 0; _Line = 1; _Column = 1; _Tokens = new List(); _Position = -1; _Disposed = false; _TabSpaces = 4; _Version = LanguageVersion.VisualBasic80; if (source == null) { throw new ArgumentNullException("Source"); } _Source = new StringReader(source); } /// /// Constructs a scanner for a string. /// /// The string to scan. /// The language version to parse. public Scanner(string source, LanguageVersion version) { _PeekCacheHasValue = false; _PeekAheadCacheHasValue = false; _Index = 0; _Line = 1; _Column = 1; _Tokens = new List(); _Position = -1; _Disposed = false; _TabSpaces = 4; _Version = LanguageVersion.VisualBasic80; if (source == null) { throw new ArgumentNullException("Source"); } if (version != LanguageVersion.VisualBasic71 && version != LanguageVersion.VisualBasic80) { throw new ArgumentOutOfRangeException("Version"); } _Source = new StringReader(source); _Version = version; } /// /// Constructs a scanner for a stream. /// /// The stream to scan. public Scanner(Stream source) { _PeekCacheHasValue = false; _PeekAheadCacheHasValue = false; _Index = 0; _Line = 1; _Column = 1; _Tokens = new List(); _Position = -1; _Disposed = false; _TabSpaces = 4; _Version = LanguageVersion.VisualBasic80; if (source == null) { throw new ArgumentNullException("Source"); } _Source = new StreamReader(source); } /// /// Constructs a scanner for a stream. /// /// The stream to scan. /// The language version to parse. public Scanner(Stream source, LanguageVersion version) { _PeekCacheHasValue = false; _PeekAheadCacheHasValue = false; _Index = 0; _Line = 1; _Column = 1; _Tokens = new List(); _Position = -1; _Disposed = false; _TabSpaces = 4; _Version = LanguageVersion.VisualBasic80; if (source == null) { throw new ArgumentNullException("Source"); } if (version != LanguageVersion.VisualBasic71 && version != LanguageVersion.VisualBasic80) { throw new ArgumentOutOfRangeException("Version"); } _Source = new StreamReader(source); _Version = version; } /// /// Constructs a canner for a general TextReader. /// /// The TextReader to scan. public Scanner(TextReader source) { _PeekCacheHasValue = false; _PeekAheadCacheHasValue = false; _Index = 0; _Line = 1; _Column = 1; _Tokens = new List(); _Position = -1; _Disposed = false; _TabSpaces = 4; _Version = LanguageVersion.VisualBasic80; if (source == null) { throw new ArgumentNullException("Source"); } _Source = source; } /// /// Constructs a canner for a general TextReader. /// /// The TextReader to scan. /// The language version to parse. public Scanner(TextReader source, LanguageVersion version) { _PeekCacheHasValue = false; _PeekAheadCacheHasValue = false; _Index = 0; _Line = 1; _Column = 1; _Tokens = new List(); _Position = -1; _Disposed = false; _TabSpaces = 4; _Version = LanguageVersion.VisualBasic80; if (source == null) { throw new ArgumentNullException("Source"); } if (version != LanguageVersion.VisualBasic71 && version != LanguageVersion.VisualBasic80) { throw new ArgumentOutOfRangeException("Version"); } _Source = source; _Version = version; } /// /// Closes/disposes the scanner. /// public void Close() { if (!_Disposed) { _Disposed = true; _Source.Close(); } } void IDisposable.Dispose() { //ILSpy generated this explicit interface implementation from .override directive in Close this.Close(); } private char ReadChar() { char c; if (_PeekCacheHasValue) { c = _PeekCache; _PeekCacheHasValue = false; if (_PeekAheadCacheHasValue) { _PeekCache = _PeekAheadCache; _PeekCacheHasValue = true; _PeekAheadCacheHasValue = false; } } else { Debug.Assert(!_PeekAheadCacheHasValue, "Cache incorrect!"); c = Strings.ChrW(_Source.Read()); } checked { _Index++; if (c == '\t') { _Column += _TabSpaces; } else { _Column++; } return c; } } private char PeekChar() { if (!_PeekCacheHasValue) { _PeekCache = Strings.ChrW(_Source.Read()); _PeekCacheHasValue = true; } return _PeekCache; } private char PeekAheadChar() { if (!_PeekAheadCacheHasValue) { if (!_PeekCacheHasValue) { PeekChar(); } _PeekAheadCache = Strings.ChrW(_Source.Read()); _PeekAheadCacheHasValue = true; } return _PeekAheadCache; } private Span SpanFrom(Location start) { return new Span(start, CurrentLocation); } private static bool IsAlphaClass(UnicodeCategory c) { return c == UnicodeCategory.UppercaseLetter || c == UnicodeCategory.LowercaseLetter || c == UnicodeCategory.TitlecaseLetter || c == UnicodeCategory.OtherLetter || c == UnicodeCategory.ModifierLetter || c == UnicodeCategory.LetterNumber; } private static bool IsNumericClass(UnicodeCategory c) { return c == UnicodeCategory.DecimalDigitNumber; } private static bool IsUnderscoreClass(UnicodeCategory c) { return c == UnicodeCategory.ConnectorPunctuation; } private static bool IsSingleQuote(char c) { return c == '\'' || c == ''' || c == '‘' || c == '’'; } private static bool IsDoubleQuote(char c) { return c == '"' || c == '"' || c == '“' || c == '”'; } private static bool IsDigit(char c) { return (c >= '0' && c <= '9') || (c >= '0' && c <= '9'); } private static bool IsOctalDigit(char c) { return (c >= '0' && c <= '7') || (c >= '0' && c <= '7'); } private static bool IsHexDigit(char c) { return IsDigit(c) || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'); } private static bool IsEquals(char c) { return c == '=' || c == '='; } private static bool IsLessThan(char c) { return c == '<' || c == '<'; } private static bool IsGreaterThan(char c) { return c == '>' || c == '>'; } private static bool IsAmpersand(char c) { return c == '&' || c == '&'; } private static bool IsUnderscore(char c) { return IsUnderscoreClass(char.GetUnicodeCategory(c)); } private static bool IsHexDesignator(char c) { return c == 'H' || c == 'h' || c == 'h' || c == 'H'; } private static bool IsOctalDesignator(char c) { return c == 'O' || c == 'o' || c == 'O' || c == 'o'; } private static bool IsPeriod(char c) { return c == '.' || c == '.'; } private static bool IsExponentDesignator(char c) { return c == 'e' || c == 'E' || c == 'e' || c == 'E'; } private static bool IsPlus(char c) { return c == '+' || c == '+'; } private static bool IsMinus(char c) { return c == '-' || c == '-'; } private static bool IsForwardSlash(char c) { return c == '/' || c == '/'; } private static bool IsColon(char c) { return c == ':' || c == ':'; } private static bool IsPound(char c) { return c == '#' || c == '#'; } private static bool IsA(char c) { return c == 'a' || c == 'a' || c == 'A' || c == 'A'; } private static bool IsP(char c) { return c == 'p' || c == 'p' || c == 'P' || c == 'P'; } private static bool IsM(char c) { return c == 'm' || c == 'm' || c == 'M' || c == 'M'; } private static bool IsCharDesignator(char c) { return c == 'c' || c == 'C' || c == 'c' || c == 'C'; } private static bool IsLeftBracket(char c) { return c == '[' || c == '['; } private static bool IsRightBracket(char c) { return c == ']' || c == ']'; } private static bool IsUnsignedTypeChar(char c) { return c == 'u' || c == 'U' || c == 'U' || c == 'u'; } private static bool IsIdentifier(char c) { UnicodeCategory CharClass = char.GetUnicodeCategory(c); return IsAlphaClass(CharClass) || IsNumericClass(CharClass) || CharClass == UnicodeCategory.SpacingCombiningMark || CharClass == UnicodeCategory.NonSpacingMark || CharClass == UnicodeCategory.Format || IsUnderscoreClass(CharClass); } internal static char MakeHalfWidth(char c) { if (c < '!' || c > '~') { return c; } checked { return Strings.ChrW(unchecked((int)c) - 65280 + 32); } } internal static char MakeFullWidth(char c) { if (c < '!' || c > '~') { return c; } checked { return Strings.ChrW(unchecked((int)c) + 65280 - 32); } } internal static string MakeFullWidth(string s) { StringBuilder Builder = new StringBuilder(s); checked { int num = Builder.Length - 1; for (int Index = 0; Index <= num; Index++) { Builder[Index] = MakeFullWidth(Builder[Index]); } return Builder.ToString(); } } private TypeCharacter ScanPossibleTypeCharacter(TypeCharacter ValidTypeCharacters) { char TypeChar = PeekChar(); if (_0024STATIC_0024ScanPossibleTypeCharacter_00242011182E41182E4_0024TypeCharacterTable == null) { Dictionary Table = new Dictionary(StringComparer.InvariantCultureIgnoreCase); string[] TypeCharacters = new string[15] { "$", "%", "&", "S", "I", "L", "!", "#", "@", "F", "R", "D", "US", "UI", "UL" }; TypeCharacter TypeCharacter2 = TypeCharacter.StringSymbol; int num = checked(TypeCharacters.Length - 1); for (int Index = 0; Index <= num; Index = checked(Index + 1)) { Dictionary dictionary = Table; dictionary.Add(TypeCharacters[Index], TypeCharacter2); dictionary.Add(MakeFullWidth(TypeCharacters[Index]), TypeCharacter2); dictionary = null; TypeCharacter2 = (TypeCharacter)((int)TypeCharacter2 << 1); } _0024STATIC_0024ScanPossibleTypeCharacter_00242011182E41182E4_0024TypeCharacterTable = Table; } string TypeString = ((!IsUnsignedTypeChar(TypeChar) || _Version <= LanguageVersion.VisualBasic71) ? Conversions.ToString(TypeChar) : (Conversions.ToString(TypeChar) + Conversions.ToString(PeekAheadChar()))); if (_0024STATIC_0024ScanPossibleTypeCharacter_00242011182E41182E4_0024TypeCharacterTable.ContainsKey(TypeString)) { TypeCharacter TypeCharacter = _0024STATIC_0024ScanPossibleTypeCharacter_00242011182E41182E4_0024TypeCharacterTable[TypeString]; if ((TypeCharacter & ValidTypeCharacters) != 0) { if (TypeCharacter == TypeCharacter.SingleSymbol && CanStartIdentifier(PeekAheadChar())) { return TypeCharacter.None; } ReadChar(); if (IsUnsignedTypeChar(TypeChar)) { ReadChar(); } return TypeCharacter; } } return TypeCharacter.None; } private PunctuatorToken ScanPossibleMultiCharacterPunctuator(char leadingCharacter, Location start) { char NextChar = PeekChar(); string PunctuatorString = Conversions.ToString(leadingCharacter); Debug.Assert(PunctuatorToken.TokenTypeFromString(Conversions.ToString(leadingCharacter)) != TokenType.None); TokenType Punctuator; if (IsEquals(NextChar) || IsLessThan(NextChar) || IsGreaterThan(NextChar)) { PunctuatorString += Conversions.ToString(NextChar); Punctuator = PunctuatorToken.TokenTypeFromString(PunctuatorString); if (Punctuator != 0) { ReadChar(); if ((Punctuator == TokenType.LessThanLessThan || Punctuator == TokenType.GreaterThanGreaterThan) && IsEquals(PeekChar())) { PunctuatorString += Conversions.ToString(ReadChar()); Punctuator = PunctuatorToken.TokenTypeFromString(PunctuatorString); } return new PunctuatorToken(Punctuator, SpanFrom(start)); } } Punctuator = PunctuatorToken.TokenTypeFromString(Conversions.ToString(leadingCharacter)); return new PunctuatorToken(Punctuator, SpanFrom(start)); } private Token ScanNumericLiteral() { Location Start = CurrentLocation; StringBuilder Literal = new StringBuilder(); IntegerBase Base = IntegerBase.Decimal; TypeCharacter TypeCharacter = TypeCharacter.None; Debug.Assert(CanStartNumericLiteral()); checked { if (IsAmpersand(PeekChar())) { Literal.Append(MakeHalfWidth(ReadChar())); if (IsHexDesignator(PeekChar())) { Literal.Append(MakeHalfWidth(ReadChar())); Base = IntegerBase.Hexadecimal; while (IsHexDigit(PeekChar())) { Literal.Append(MakeHalfWidth(ReadChar())); } } else if (IsOctalDesignator(PeekChar())) { Literal.Append(MakeHalfWidth(ReadChar())); Base = IntegerBase.Octal; while (IsOctalDigit(PeekChar())) { Literal.Append(MakeHalfWidth(ReadChar())); } } else { if (!IsOctalDigit(PeekChar())) { return ScanPossibleMultiCharacterPunctuator('&', Start); } Base = IntegerBase.Octal; Literal.Append('O'); while (IsOctalDigit(PeekChar())) { Literal.Append(MakeHalfWidth(ReadChar())); } if (IsAmpersand(PeekChar())) { ReadChar(); } } if (Literal.Length > 2) { TypeCharacter = ScanPossibleTypeCharacter(TypeCharacter.IntegerSymbol | TypeCharacter.LongSymbol | TypeCharacter.ShortChar | TypeCharacter.IntegerChar | TypeCharacter.LongChar | TypeCharacter.UnsignedShortChar | TypeCharacter.UnsignedIntegerChar | TypeCharacter.UnsignedLongChar); try { switch (TypeCharacter) { case TypeCharacter.ShortChar: { long Value3 = Conversions.ToLong(Literal.ToString()); if (Value3 <= 65535) { if (Value3 > 32767) { Value3 = -(65536 - Value3); } if (Value3 >= -32768 && Value3 <= 32767) { return new IntegerLiteralToken((short)Value3, Base, TypeCharacter, SpanFrom(Start)); } } break; } case TypeCharacter.UnsignedShortChar: { ulong Value4 = Conversions.ToULong(Literal.ToString()); if (decimal.Compare(new decimal(Value4), new decimal(65535L)) <= 0 && Value4 >= 0 && Value4 <= 65535) { return new UnsignedIntegerLiteralToken((ushort)Value4, Base, TypeCharacter, SpanFrom(Start)); } break; } case TypeCharacter.IntegerSymbol: case TypeCharacter.IntegerChar: { long Value = Conversions.ToLong(Literal.ToString()); if (Value <= uint.MaxValue) { if (Value > int.MaxValue) { Value = -(4294967296L - Value); } if (Value >= int.MinValue && Value <= int.MaxValue) { return new IntegerLiteralToken((int)Value, Base, TypeCharacter, SpanFrom(Start)); } } break; } case TypeCharacter.UnsignedIntegerChar: { ulong Value2 = Conversions.ToULong(Literal.ToString()); if (decimal.Compare(new decimal(Value2), new decimal(4294967295L)) <= 0 && Value2 >= 0 && Value2 <= uint.MaxValue) { return new UnsignedIntegerLiteralToken((uint)Value2, Base, TypeCharacter, SpanFrom(Start)); } break; } case TypeCharacter.LongSymbol: case TypeCharacter.LongChar: return new IntegerLiteralToken(ParseInt(Literal.ToString()), Base, TypeCharacter, SpanFrom(Start)); case TypeCharacter.UnsignedLongChar: return new UnsignedIntegerLiteralToken(Conversions.ToULong(Literal.ToString()), Base, TypeCharacter, SpanFrom(Start)); default: TypeCharacter = TypeCharacter.None; return new IntegerLiteralToken(ParseInt(Literal.ToString()), Base, TypeCharacter, SpanFrom(Start)); } } catch (OverflowException ex7) { ProjectData.SetProjectError(ex7); OverflowException ex6 = ex7; Token ScanNumericLiteral = new ErrorToken(SyntaxErrorType.InvalidIntegerLiteral, SpanFrom(Start)); ProjectData.ClearProjectError(); return ScanNumericLiteral; } catch (InvalidCastException ex8) { ProjectData.SetProjectError(ex8); InvalidCastException ex5 = ex8; Token ScanNumericLiteral = new ErrorToken(SyntaxErrorType.InvalidIntegerLiteral, SpanFrom(Start)); ProjectData.ClearProjectError(); return ScanNumericLiteral; } } return new ErrorToken(SyntaxErrorType.InvalidIntegerLiteral, SpanFrom(Start)); } while (IsDigit(PeekChar())) { Literal.Append(MakeHalfWidth(ReadChar())); } if (IsPeriod(PeekChar()) || IsExponentDesignator(PeekChar())) { SyntaxErrorType ErrorType = SyntaxErrorType.None; if (IsPeriod(PeekChar())) { Literal.Append(MakeHalfWidth(ReadChar())); if (!IsDigit(PeekChar()) & (Literal.Length == 1)) { return new PunctuatorToken(TokenType.Period, SpanFrom(Start)); } while (IsDigit(PeekChar())) { Literal.Append(MakeHalfWidth(ReadChar())); } } if (IsExponentDesignator(PeekChar())) { Literal.Append(MakeHalfWidth(ReadChar())); if (IsPlus(PeekChar()) || IsMinus(PeekChar())) { Literal.Append(MakeHalfWidth(ReadChar())); } if (!IsDigit(PeekChar())) { return new ErrorToken(SyntaxErrorType.InvalidFloatingPointLiteral, SpanFrom(Start)); } while (IsDigit(PeekChar())) { Literal.Append(MakeHalfWidth(ReadChar())); } } TypeCharacter = ScanPossibleTypeCharacter(TypeCharacter.SingleSymbol | TypeCharacter.DoubleSymbol | TypeCharacter.DecimalSymbol | TypeCharacter.SingleChar | TypeCharacter.DoubleChar | TypeCharacter.DecimalChar); try { switch (TypeCharacter) { case TypeCharacter.DecimalSymbol: case TypeCharacter.DecimalChar: ErrorType = SyntaxErrorType.InvalidDecimalLiteral; return new DecimalLiteralToken(Conversions.ToDecimal(Literal.ToString()), TypeCharacter, SpanFrom(Start)); case TypeCharacter.SingleSymbol: case TypeCharacter.SingleChar: ErrorType = SyntaxErrorType.InvalidFloatingPointLiteral; return new FloatingPointLiteralToken(Conversions.ToSingle(Literal.ToString()), TypeCharacter, SpanFrom(Start)); case TypeCharacter.DoubleSymbol: case TypeCharacter.DoubleChar: ErrorType = SyntaxErrorType.InvalidFloatingPointLiteral; return new FloatingPointLiteralToken(Conversions.ToDouble(Literal.ToString()), TypeCharacter, SpanFrom(Start)); default: ErrorType = SyntaxErrorType.InvalidFloatingPointLiteral; TypeCharacter = TypeCharacter.None; return new FloatingPointLiteralToken(Conversions.ToDouble(Literal.ToString()), TypeCharacter, SpanFrom(Start)); } } catch (OverflowException ex9) { ProjectData.SetProjectError(ex9); OverflowException ex2 = ex9; Token ScanNumericLiteral = new ErrorToken(ErrorType, SpanFrom(Start)); ProjectData.ClearProjectError(); return ScanNumericLiteral; } catch (InvalidCastException ex10) { ProjectData.SetProjectError(ex10); InvalidCastException ex = ex10; Token ScanNumericLiteral = new ErrorToken(ErrorType, SpanFrom(Start)); ProjectData.ClearProjectError(); return ScanNumericLiteral; } } SyntaxErrorType ErrorType2 = SyntaxErrorType.None; TypeCharacter = ScanPossibleTypeCharacter(TypeCharacter.IntegerSymbol | TypeCharacter.LongSymbol | TypeCharacter.ShortChar | TypeCharacter.IntegerChar | TypeCharacter.LongChar | TypeCharacter.SingleSymbol | TypeCharacter.DoubleSymbol | TypeCharacter.DecimalSymbol | TypeCharacter.SingleChar | TypeCharacter.DoubleChar | TypeCharacter.DecimalChar | TypeCharacter.UnsignedShortChar | TypeCharacter.UnsignedIntegerChar | TypeCharacter.UnsignedLongChar); try { switch (TypeCharacter) { case TypeCharacter.ShortChar: ErrorType2 = SyntaxErrorType.InvalidIntegerLiteral; return new IntegerLiteralToken(Conversions.ToShort(Literal.ToString()), Base, TypeCharacter, SpanFrom(Start)); case TypeCharacter.UnsignedShortChar: ErrorType2 = SyntaxErrorType.InvalidIntegerLiteral; return new UnsignedIntegerLiteralToken(Conversions.ToUShort(Literal.ToString()), Base, TypeCharacter, SpanFrom(Start)); case TypeCharacter.IntegerSymbol: case TypeCharacter.IntegerChar: ErrorType2 = SyntaxErrorType.InvalidIntegerLiteral; return new IntegerLiteralToken(Conversions.ToInteger(Literal.ToString()), Base, TypeCharacter, SpanFrom(Start)); case TypeCharacter.UnsignedIntegerChar: ErrorType2 = SyntaxErrorType.InvalidIntegerLiteral; return new UnsignedIntegerLiteralToken(Conversions.ToUInteger(Literal.ToString()), Base, TypeCharacter, SpanFrom(Start)); case TypeCharacter.LongSymbol: case TypeCharacter.LongChar: ErrorType2 = SyntaxErrorType.InvalidIntegerLiteral; return new IntegerLiteralToken(Conversions.ToInteger(Literal.ToString()), Base, TypeCharacter, SpanFrom(Start)); case TypeCharacter.UnsignedLongChar: ErrorType2 = SyntaxErrorType.InvalidIntegerLiteral; return new UnsignedIntegerLiteralToken(Conversions.ToULong(Literal.ToString()), Base, TypeCharacter, SpanFrom(Start)); case TypeCharacter.DecimalSymbol: case TypeCharacter.DecimalChar: ErrorType2 = SyntaxErrorType.InvalidDecimalLiteral; return new DecimalLiteralToken(Conversions.ToDecimal(Literal.ToString()), TypeCharacter, SpanFrom(Start)); case TypeCharacter.SingleSymbol: case TypeCharacter.SingleChar: ErrorType2 = SyntaxErrorType.InvalidFloatingPointLiteral; return new FloatingPointLiteralToken(Conversions.ToSingle(Literal.ToString()), TypeCharacter, SpanFrom(Start)); case TypeCharacter.DoubleSymbol: case TypeCharacter.DoubleChar: ErrorType2 = SyntaxErrorType.InvalidFloatingPointLiteral; return new FloatingPointLiteralToken(Conversions.ToDouble(Literal.ToString()), TypeCharacter, SpanFrom(Start)); default: ErrorType2 = SyntaxErrorType.InvalidIntegerLiteral; return new IntegerLiteralToken(Conversions.ToInteger(Literal.ToString()), Base, TypeCharacter.None, SpanFrom(Start)); } } catch (OverflowException ex11) { ProjectData.SetProjectError(ex11); OverflowException ex4 = ex11; Token ScanNumericLiteral = new ErrorToken(ErrorType2, SpanFrom(Start)); ProjectData.ClearProjectError(); return ScanNumericLiteral; } catch (InvalidCastException ex12) { ProjectData.SetProjectError(ex12); InvalidCastException ex3 = ex12; Token ScanNumericLiteral = new ErrorToken(ErrorType2, SpanFrom(Start)); ProjectData.ClearProjectError(); return ScanNumericLiteral; } } } private bool CanStartNumericLiteral() { return IsPeriod(PeekChar()) || IsAmpersand(PeekChar()) || IsDigit(PeekChar()); } private long ReadIntegerLiteral() { long Value = 0L; checked { while (IsDigit(PeekChar())) { char c = MakeHalfWidth(ReadChar()); Value *= 10; Value += unchecked((int)c) - 48; } return Value; } } private Token ScanDateLiteral() { Location Start = CurrentLocation; int Month = 0; int Day = 0; int Year = 0; int Hour = 0; int Minute = 0; int Second = 0; bool HaveDateValue = false; bool HaveTimeValue = false; Debug.Assert(CanStartDateLiteral()); ReadChar(); Location PossibleEnd = CurrentLocation; EatWhitespace(); if (!IsDigit(PeekChar())) { return new PunctuatorToken(TokenType.Pound, new Span(Start, PossibleEnd)); } long Value = ReadIntegerLiteral(); EatWhitespace(); if (!IsForwardSlash(PeekChar()) && !IsMinus(PeekChar())) { goto IL_024d; } char Separator = ReadChar(); HaveDateValue = true; checked { if (Value >= 1 && Value <= 12) { Month = (int)Value; EatWhitespace(); if (IsDigit(PeekChar())) { Value = ReadIntegerLiteral(); if (Value >= 1 && Value <= 31) { Day = (int)Value; EatWhitespace(); if (PeekChar() == Separator) { ReadChar(); EatWhitespace(); if (IsDigit(PeekChar())) { Location YearStart = CurrentLocation; Value = ReadIntegerLiteral(); if (Value >= 1 && Value <= 9999) { Year = (int)Value; if (CurrentLocation.Column - YearStart.Column == 2) { Year = ((Year <= 30) ? (Year + 1900) : (Year + 2000)); } else if (CurrentLocation.Column - YearStart.Column != 4) { goto IL_042a; } if (Day <= DateTime.DaysInMonth(Year, Month)) { EatWhitespace(); if (IsDigit(PeekChar())) { Value = ReadIntegerLiteral(); if (!IsColon(PeekChar())) { goto IL_042a; } } goto IL_024d; } } } } } } } goto IL_042a; } IL_03ed: if (IsPound(PeekChar())) { ReadChar(); if (HaveTimeValue || HaveDateValue) { if (HaveDateValue) { if (HaveTimeValue) { return new DateLiteralToken(new DateTime(Year, Month, Day, Hour, Minute, Second), SpanFrom(Start)); } return new DateLiteralToken(new DateTime(Year, Month, Day), SpanFrom(Start)); } return new DateLiteralToken(new DateTime(1, 1, 1, Hour, Minute, Second), SpanFrom(Start)); } } goto IL_042a; IL_0327: EatWhitespace(); if (IsA(PeekChar())) { ReadChar(); if (IsM(PeekChar())) { ReadChar(); if (Hour >= 1 && Hour <= 12) { goto IL_03ed; } } } else { if (!IsP(PeekChar())) { goto IL_03ed; } ReadChar(); if (IsM(PeekChar())) { ReadChar(); if (Hour >= 1 && Hour <= 12) { Hour = checked(Hour + 12); if (Hour == 24) { Hour = 12; } goto IL_03ed; } } } goto IL_042a; IL_042a: while (!IsPound(PeekChar()) && !CanStartLineTerminator()) { ReadChar(); } if (IsPound(PeekChar())) { ReadChar(); } return new ErrorToken(SyntaxErrorType.InvalidDateLiteral, SpanFrom(Start)); IL_024d: if (!IsColon(PeekChar())) { goto IL_03ed; } ReadChar(); HaveTimeValue = true; checked { if (Value >= 0 && Value <= 23) { Hour = (int)Value; if (IsDigit(PeekChar())) { Value = ReadIntegerLiteral(); if (Value >= 0 && Value <= 59) { Minute = (int)Value; if (!IsColon(PeekChar())) { goto IL_0327; } ReadChar(); if (IsDigit(PeekChar())) { Value = ReadIntegerLiteral(); if (Value >= 0 && Value <= 59) { Second = (int)Value; goto IL_0327; } } } } } goto IL_042a; } } private bool CanStartDateLiteral() { return IsPound(PeekChar()); } private Token ScanStringLiteral() { Location Start = CurrentLocation; StringBuilder s = new StringBuilder(); Debug.Assert(CanStartStringLiteral()); ReadChar(); while (true) { if (!IsDoubleQuote(PeekChar()) && !CanStartLineTerminator()) { s.Append(ReadChar()); continue; } if (IsDoubleQuote(PeekChar())) { ReadChar(); if (IsDoubleQuote(PeekChar())) { ReadChar(); s.Append('"'); continue; } break; } return new ErrorToken(SyntaxErrorType.InvalidStringLiteral, SpanFrom(Start)); } if (IsCharDesignator(PeekChar())) { ReadChar(); if (s.Length != 1) { return new ErrorToken(SyntaxErrorType.InvalidCharacterLiteral, SpanFrom(Start)); } return new CharacterLiteralToken(s[0], SpanFrom(Start)); } return new StringLiteralToken(s.ToString(), SpanFrom(Start)); } private bool CanStartStringLiteral() { return IsDoubleQuote(PeekChar()); } private Token ScanIdentifier() { Location Start = CurrentLocation; bool Escaped = false; TypeCharacter TypeCharacter = TypeCharacter.None; StringBuilder s = new StringBuilder(); TokenType Type = TokenType.Identifier; TokenType UnreservedType = TokenType.Identifier; Debug.Assert(CanStartIdentifier()); if (IsLeftBracket(PeekChar())) { Escaped = true; ReadChar(); if (!CanStartNonEscapedIdentifier()) { while (!IsRightBracket(PeekChar()) && !CanStartLineTerminator()) { ReadChar(); } if (IsRightBracket(PeekChar())) { ReadChar(); } return new ErrorToken(SyntaxErrorType.InvalidEscapedIdentifier, SpanFrom(Start)); } } s.Append(ReadChar()); if (IsUnderscore(s[0]) && !IsIdentifier(PeekChar())) { Location End = CurrentLocation; EatWhitespace(); if (CanStartLineTerminator()) { ScanLineTerminator(produceToken: false); return null; } return new ErrorToken(SyntaxErrorType.InvalidIdentifier, new Span(Start, End)); } while (IsIdentifier(PeekChar())) { s.Append(ReadChar()); } string Identifier = s.ToString(); if (Escaped) { if (!IsRightBracket(PeekChar())) { while (!IsRightBracket(PeekChar()) && !CanStartLineTerminator()) { ReadChar(); } if (IsRightBracket(PeekChar())) { ReadChar(); } return new ErrorToken(SyntaxErrorType.InvalidEscapedIdentifier, SpanFrom(Start)); } ReadChar(); } else { Type = IdentifierToken.TokenTypeFromString(Identifier, _Version, IncludeUnreserved: false); if (Type == TokenType.REM) { return ScanComment(Start); } UnreservedType = IdentifierToken.TokenTypeFromString(Identifier, _Version, IncludeUnreserved: true); if (Type != TokenType.Identifier && TypeCharacter != 0) { if (_Version <= LanguageVersion.VisualBasic71) { return new ErrorToken(SyntaxErrorType.InvalidTypeCharacterOnKeyword, SpanFrom(Start)); } Type = TokenType.Identifier; } } return new IdentifierToken(Type, UnreservedType, Identifier, Escaped, TypeCharacter, SpanFrom(Start)); } private bool CanStartNonEscapedIdentifier() { return CanStartNonEscapedIdentifier(PeekChar()); } private static bool CanStartNonEscapedIdentifier(char c) { UnicodeCategory CharClass = char.GetUnicodeCategory(c); return IsAlphaClass(CharClass) || IsUnderscoreClass(CharClass); } private bool CanStartIdentifier() { return CanStartIdentifier(PeekChar()); } private static bool CanStartIdentifier(char c) { return IsLeftBracket(c) || CanStartNonEscapedIdentifier(c); } private CommentToken ScanComment() { StringBuilder s = new StringBuilder(); Location Start = CurrentLocation; Debug.Assert(CanStartComment()); ReadChar(); while (!CanStartLineTerminator()) { s.Append(ReadChar()); } return new CommentToken(s.ToString(), isREM: false, SpanFrom(Start)); } private CommentToken ScanComment(Location start) { StringBuilder s = new StringBuilder(); while (!CanStartLineTerminator()) { s.Append(ReadChar()); } return new CommentToken(s.ToString(), isREM: true, SpanFrom(start)); } private bool CanStartComment() { return IsSingleQuote(PeekChar()); } private Token ScanLineTerminator(bool produceToken = true) { Location Start = CurrentLocation; Token Token = null; Debug.Assert(CanStartLineTerminator()); checked { if (PeekChar() == '\uffff') { Token = new EndOfStreamToken(SpanFrom(Start)); } else { if (ReadChar() == '\r' && PeekChar() == '\n') { ReadChar(); } if (produceToken) { Token = new LineTerminatorToken(SpanFrom(Start)); } _Line++; _Column = 1; } return Token; } } private bool CanStartLineTerminator() { char c = PeekChar(); return c == '\r' || c == '\n' || c == '\u2028' || c == '\u2029' || c == '\uffff'; } private bool EatWhitespace() { char c = PeekChar(); bool EatWhitespace = default(bool); while (c == '\t' || char.GetUnicodeCategory(c) == UnicodeCategory.SpaceSeparator) { ReadChar(); EatWhitespace = true; c = PeekChar(); } return EatWhitespace; } private Token Read(bool advance) { Token CurrentToken = ((_Position <= -1) ? null : _Tokens[_Position]); if (CurrentToken != null && CurrentToken.Type == TokenType.EndOfStream) { return CurrentToken; } checked { if (_Position == _Tokens.Count - 1) { Token TokenRead; while (true) { EatWhitespace(); if (CanStartLineTerminator()) { TokenRead = ScanLineTerminator(); break; } if (CanStartComment()) { TokenRead = ScanComment(); break; } if (CanStartIdentifier()) { Token Token = ScanIdentifier(); if (Token == null) { continue; } TokenRead = Token; break; } if (CanStartStringLiteral()) { TokenRead = ScanStringLiteral(); break; } if (CanStartDateLiteral()) { TokenRead = ScanDateLiteral(); break; } if (CanStartNumericLiteral()) { TokenRead = ScanNumericLiteral(); break; } Location Start = CurrentLocation; if (PunctuatorToken.TokenTypeFromString(Conversions.ToString(PeekChar())) != 0) { TokenRead = ScanPossibleMultiCharacterPunctuator(ReadChar(), Start); break; } ReadChar(); TokenRead = new ErrorToken(SyntaxErrorType.InvalidCharacter, SpanFrom(Start)); break; } _Tokens.Add(TokenRead); } if (advance) { _Position++; return _Tokens[_Position]; } return _Tokens[_Position + 1]; } } /// /// Seeks backwards in the stream position to a particular token. /// /// The token to seek back to. /// Thrown when the scanner has been closed. /// Thrown when token was not produced by this scanner. public void Seek(Token token) { int StartPosition = _Position; bool TokenFound = false; if (_Disposed) { throw new ObjectDisposedException("Scanner"); } checked { if (StartPosition == _Tokens.Count - 1) { StartPosition--; } int num = StartPosition; int CurrentPosition; for (CurrentPosition = num; CurrentPosition >= -1; CurrentPosition += -1) { if (_Tokens[CurrentPosition + 1] == token) { TokenFound = true; break; } } if (!TokenFound) { throw new ArgumentException("Token not created by this scanner."); } _Position = CurrentPosition; } } /// /// Fetches the previous token in the stream. /// /// The previous token. /// Thrown when the scanner has been closed. /// Thrown when the scanner is positioned on the first token. public Token Previous() { if (_Disposed) { throw new ObjectDisposedException("Scanner"); } if (_Position == -1) { throw new InvalidOperationException("Scanner is positioned on the first token."); } return _Tokens[_Position]; } /// /// Fetches the current token without advancing the stream position. /// /// The current token. /// Thrown when the scanner has been closed. public Token Peek() { if (_Disposed) { throw new ObjectDisposedException("Scanner"); } return Read(advance: false); } /// /// Fetches the current token and advances the stream position. /// /// The current token. /// Thrown when the scanner has been closed. public Token Read() { if (_Disposed) { throw new ObjectDisposedException("Scanner"); } return Read(advance: true); } /// /// Fetches more than one token at a time from the stream. /// /// The array to put the tokens into. /// The location in the array to start putting the tokens into. /// The number of tokens to read. /// The number of tokens read. /// Thrown when the scanner has been closed. /// Thrown when the buffer is Nothing. /// Thrown when the index or count is invalid, or when there isn't enough room in the buffer. public int ReadBlock(Token[] buffer, int index, int count) { int FinalCount = 0; if (buffer == null) { throw new ArgumentNullException("buffer"); } if (index < 0 || count < 0) { throw new ArgumentException("Index or count cannot be negative."); } checked { if (buffer.Length - index < count) { throw new ArgumentException("Not enough room in buffer."); } if (_Disposed) { throw new ObjectDisposedException("Scanner"); } while (count > 0) { Token CurrentToken = Read(); if (CurrentToken.Type == TokenType.EndOfStream) { return FinalCount; } buffer[FinalCount + index] = CurrentToken; count--; FinalCount++; } return FinalCount; } } /// /// Reads all of the tokens between the current position and the end of the line (or the end of the stream). /// /// The tokens read. /// Thrown when the scanner has been closed. public Token[] ReadLine() { List TokenArray = new List(); if (_Disposed) { throw new ObjectDisposedException("Scanner"); } while ((Peek().Type != TokenType.EndOfStream) & (Peek().Type != TokenType.LineTerminator)) { TokenArray.Add(Read()); } return TokenArray.ToArray(); } /// /// Reads all the tokens between the current position and the end of the stream. /// /// The tokens read. /// Thrown when the scanner has been closed. public Token[] ReadToEnd() { List TokenArray = new List(); if (_Disposed) { throw new ObjectDisposedException("Scanner"); } while (Peek().Type != TokenType.EndOfStream) { TokenArray.Add(Read()); } return TokenArray.ToArray(); } private int ParseInt(string literal) { int @base; if (literal.StartsWith("&")) { @base = ((literal[1] != 'H' && literal[1] != 'h') ? 8 : 16); literal = literal.Substring(2); } else { @base = 10; } return Convert.ToInt32(literal, @base); } }