5392 lines
127 KiB
C#
5392 lines
127 KiB
C#
using System;
|
|
using System.Diagnostics.CodeAnalysis;
|
|
using System.Globalization;
|
|
using System.Text;
|
|
using Microsoft.CodeAnalysis.PooledObjects;
|
|
using Microsoft.CodeAnalysis.Syntax.InternalSyntax;
|
|
using Microsoft.CodeAnalysis.Text;
|
|
using Roslyn.Utilities;
|
|
|
|
namespace Microsoft.CodeAnalysis.CSharp.Syntax.InternalSyntax;
|
|
|
|
internal class Lexer : AbstractLexer
|
|
{
|
|
internal struct TokenInfo
|
|
{
|
|
internal SyntaxKind Kind;
|
|
|
|
internal SyntaxKind ContextualKind;
|
|
|
|
internal string? Text;
|
|
|
|
internal SpecialType ValueKind;
|
|
|
|
internal bool RequiresTextForXmlEntity;
|
|
|
|
internal bool HasIdentifierEscapeSequence;
|
|
|
|
internal string? StringValue;
|
|
|
|
internal char CharValue;
|
|
|
|
internal int IntValue;
|
|
|
|
internal uint UintValue;
|
|
|
|
internal long LongValue;
|
|
|
|
internal ulong UlongValue;
|
|
|
|
internal float FloatValue;
|
|
|
|
internal double DoubleValue;
|
|
|
|
internal decimal DecimalValue;
|
|
|
|
internal bool IsVerbatim;
|
|
}
|
|
|
|
internal readonly struct Interpolation
|
|
{
|
|
public readonly Range OpenBraceRange;
|
|
|
|
public readonly Range ColonRange;
|
|
|
|
public readonly Range CloseBraceRange;
|
|
|
|
public bool HasColon => ColonRange.Start.Value != ColonRange.End.Value;
|
|
|
|
public Interpolation(Range openBraceRange, Range colonRange, Range closeBraceRange)
|
|
{
|
|
OpenBraceRange = openBraceRange;
|
|
ColonRange = colonRange;
|
|
CloseBraceRange = closeBraceRange;
|
|
}
|
|
}
|
|
|
|
internal enum InterpolatedStringKind
|
|
{
|
|
Normal,
|
|
Verbatim,
|
|
SingleLineRaw,
|
|
MultiLineRaw
|
|
}
|
|
|
|
[NonCopyable]
|
|
private ref struct InterpolatedStringScanner(Lexer lexer)
|
|
{
|
|
private readonly Lexer _lexer = lexer;
|
|
|
|
public SyntaxDiagnosticInfo? Error = null;
|
|
|
|
private bool IsAtEnd(InterpolatedStringKind kind)
|
|
{
|
|
bool allowNewline = ((kind == InterpolatedStringKind.Verbatim || kind == InterpolatedStringKind.MultiLineRaw) ? true : false);
|
|
return IsAtEnd(allowNewline);
|
|
}
|
|
|
|
private bool IsAtEnd(bool allowNewline)
|
|
{
|
|
char c = _lexer.TextWindow.PeekChar();
|
|
if (allowNewline || !SyntaxFacts.IsNewLine(c))
|
|
{
|
|
if (c == '\uffff')
|
|
{
|
|
return _lexer.TextWindow.IsReallyAtEnd();
|
|
}
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
private void TrySetError(SyntaxDiagnosticInfo error)
|
|
{
|
|
if (Error == null)
|
|
{
|
|
Error = error;
|
|
}
|
|
}
|
|
|
|
internal void ScanInterpolatedStringLiteralTop(out InterpolatedStringKind kind, out Range openQuoteRange, ArrayBuilder<Interpolation>? interpolations, out Range closeQuoteRange)
|
|
{
|
|
int position = _lexer.TextWindow.Position;
|
|
int startingDollarSignCount;
|
|
int startingQuoteCount;
|
|
bool num = ScanOpenQuote(out kind, out startingDollarSignCount, out startingQuoteCount);
|
|
openQuoteRange = position.._lexer.TextWindow.Position;
|
|
if (!num)
|
|
{
|
|
closeQuoteRange = _lexer.TextWindow.Position.._lexer.TextWindow.Position;
|
|
return;
|
|
}
|
|
ScanInterpolatedStringLiteralContents(kind, startingDollarSignCount, startingQuoteCount, interpolations);
|
|
ScanInterpolatedStringLiteralEnd(kind, startingQuoteCount, out closeQuoteRange);
|
|
}
|
|
|
|
private bool ScanOpenQuote(out InterpolatedStringKind kind, out int startingDollarSignCount, out int startingQuoteCount)
|
|
{
|
|
SlidingTextWindow textWindow = _lexer.TextWindow;
|
|
int position = textWindow.Position;
|
|
char c = textWindow.PeekChar(0);
|
|
char c2 = textWindow.PeekChar(1);
|
|
char c3 = textWindow.PeekChar(2);
|
|
if (c != '$')
|
|
{
|
|
if (c == '@' && c2 == '$')
|
|
{
|
|
goto IL_004a;
|
|
}
|
|
}
|
|
else if (c2 == '@')
|
|
{
|
|
goto IL_004a;
|
|
}
|
|
goto IL_0055;
|
|
IL_0058:
|
|
bool flag;
|
|
if (flag)
|
|
{
|
|
kind = InterpolatedStringKind.Verbatim;
|
|
startingDollarSignCount = 1;
|
|
startingQuoteCount = 1;
|
|
textWindow.AdvanceChar(3);
|
|
return true;
|
|
}
|
|
char num = textWindow.PeekChar(0);
|
|
c3 = textWindow.PeekChar(1);
|
|
c2 = textWindow.PeekChar(2);
|
|
c = textWindow.PeekChar(3);
|
|
if ((num == '$' && c3 == '"' && (c2 != '"' || c != '"')) ? true : false)
|
|
{
|
|
kind = InterpolatedStringKind.Normal;
|
|
startingDollarSignCount = 1;
|
|
startingQuoteCount = 1;
|
|
textWindow.AdvanceChar(2);
|
|
return true;
|
|
}
|
|
int num2 = _lexer.ConsumeAtSignSequence();
|
|
startingDollarSignCount = _lexer.ConsumeDollarSignSequence();
|
|
int num3 = _lexer.ConsumeAtSignSequence();
|
|
startingQuoteCount = _lexer.ConsumeQuoteSequence();
|
|
int num4 = num2 + num3;
|
|
if (startingQuoteCount == 0)
|
|
{
|
|
TrySetError(_lexer.MakeError(position, textWindow.Position - position, ErrorCode.ERR_StringMustStartWithQuoteCharacter));
|
|
kind = ((num4 == 1 && startingDollarSignCount == 1) ? InterpolatedStringKind.Verbatim : InterpolatedStringKind.SingleLineRaw);
|
|
return false;
|
|
}
|
|
if (num4 > 0)
|
|
{
|
|
TrySetError(_lexer.MakeError(position, textWindow.Position - position, ErrorCode.ERR_IllegalAtSequence));
|
|
}
|
|
if (startingQuoteCount < 3)
|
|
{
|
|
TrySetError(_lexer.MakeError(textWindow.Position - startingQuoteCount, startingQuoteCount, ErrorCode.ERR_NotEnoughQuotesForRawString));
|
|
}
|
|
int position2 = textWindow.Position;
|
|
_lexer.ConsumeWhitespace(null);
|
|
if (SyntaxFacts.IsNewLine(textWindow.PeekChar()))
|
|
{
|
|
textWindow.AdvancePastNewLine();
|
|
kind = InterpolatedStringKind.MultiLineRaw;
|
|
}
|
|
else
|
|
{
|
|
textWindow.Reset(position2);
|
|
kind = InterpolatedStringKind.SingleLineRaw;
|
|
}
|
|
return true;
|
|
IL_004a:
|
|
if (c3 != '"')
|
|
{
|
|
goto IL_0055;
|
|
}
|
|
flag = true;
|
|
goto IL_0058;
|
|
IL_0055:
|
|
flag = false;
|
|
goto IL_0058;
|
|
}
|
|
|
|
private void ScanInterpolatedStringLiteralEnd(InterpolatedStringKind kind, int startingQuoteCount, out Range closeQuoteRange)
|
|
{
|
|
int position = _lexer.TextWindow.Position;
|
|
if ((uint)kind <= 1u)
|
|
{
|
|
ScanNormalOrVerbatimInterpolatedStringLiteralEnd(kind);
|
|
}
|
|
else
|
|
{
|
|
ScanRawInterpolatedStringLiteralEnd(kind, startingQuoteCount);
|
|
}
|
|
closeQuoteRange = position.._lexer.TextWindow.Position;
|
|
}
|
|
|
|
private void ScanNormalOrVerbatimInterpolatedStringLiteralEnd(InterpolatedStringKind kind)
|
|
{
|
|
if (_lexer.TextWindow.PeekChar() != '"')
|
|
{
|
|
TrySetError(_lexer.MakeError(IsAtEnd(allowNewline: true) ? (_lexer.TextWindow.Position - 1) : _lexer.TextWindow.Position, 1, ErrorCode.ERR_UnterminatedStringLit));
|
|
}
|
|
else
|
|
{
|
|
_lexer.TextWindow.AdvanceChar();
|
|
}
|
|
}
|
|
|
|
private void ScanRawInterpolatedStringLiteralEnd(InterpolatedStringKind kind, int startingQuoteCount)
|
|
{
|
|
if (kind == InterpolatedStringKind.SingleLineRaw)
|
|
{
|
|
if (_lexer.TextWindow.PeekChar() != '"')
|
|
{
|
|
TrySetError(_lexer.MakeError(IsAtEnd(allowNewline: true) ? (_lexer.TextWindow.Position - 1) : _lexer.TextWindow.Position, 1, ErrorCode.ERR_UnterminatedRawString));
|
|
return;
|
|
}
|
|
int num = _lexer.ConsumeQuoteSequence();
|
|
if (num > startingQuoteCount)
|
|
{
|
|
int num2 = num - startingQuoteCount;
|
|
TrySetError(_lexer.MakeError(_lexer.TextWindow.Position - num2, num2, ErrorCode.ERR_TooManyQuotesForRawString));
|
|
}
|
|
}
|
|
else if (IsAtEnd(kind))
|
|
{
|
|
TrySetError(_lexer.MakeError(_lexer.TextWindow.Position - 1, 1, ErrorCode.ERR_UnterminatedRawString));
|
|
}
|
|
else if (_lexer.TextWindow.PeekChar() == '"')
|
|
{
|
|
int num3 = _lexer.ConsumeQuoteSequence();
|
|
TrySetError(_lexer.MakeError(_lexer.TextWindow.Position - num3, num3, ErrorCode.ERR_RawStringDelimiterOnOwnLine));
|
|
}
|
|
else
|
|
{
|
|
_lexer.TextWindow.AdvancePastNewLine();
|
|
_lexer.ConsumeWhitespace(null);
|
|
int num4 = _lexer.ConsumeQuoteSequence();
|
|
if (num4 > startingQuoteCount)
|
|
{
|
|
int num5 = num4 - startingQuoteCount;
|
|
TrySetError(_lexer.MakeError(_lexer.TextWindow.Position - num5, num5, ErrorCode.ERR_TooManyQuotesForRawString));
|
|
}
|
|
}
|
|
}
|
|
|
|
private void ScanInterpolatedStringLiteralContents(InterpolatedStringKind kind, int startingDollarSignCount, int startingQuoteCount, ArrayBuilder<Interpolation>? interpolations)
|
|
{
|
|
if (CheckForIllegalEmptyMultiLineRawStringLiteral(kind, startingQuoteCount))
|
|
{
|
|
return;
|
|
}
|
|
while (!IsAtEnd(kind) && !IsAtEndOfMultiLineRawLiteral(kind, startingQuoteCount))
|
|
{
|
|
switch (_lexer.TextWindow.PeekChar())
|
|
{
|
|
case '"':
|
|
if (IsEndDelimiterOtherwiseConsume(kind, startingQuoteCount))
|
|
{
|
|
return;
|
|
}
|
|
break;
|
|
case '}':
|
|
HandleCloseBraceInContent(kind, startingDollarSignCount);
|
|
break;
|
|
case '{':
|
|
HandleOpenBraceInContent(kind, startingDollarSignCount, interpolations);
|
|
break;
|
|
case '\\':
|
|
if (kind == InterpolatedStringKind.Normal)
|
|
{
|
|
int position = _lexer.TextWindow.Position;
|
|
char surrogateCharacter;
|
|
char c = _lexer.ScanEscapeSequence(out surrogateCharacter);
|
|
if ((c == '{' || c == '}') ? true : false)
|
|
{
|
|
TrySetError(_lexer.MakeError(position, _lexer.TextWindow.Position - position, ErrorCode.ERR_EscapedCurly, c));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
_lexer.TextWindow.AdvanceChar();
|
|
}
|
|
break;
|
|
default:
|
|
_lexer.TextWindow.AdvanceChar();
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
private bool CheckForIllegalEmptyMultiLineRawStringLiteral(InterpolatedStringKind kind, int startingQuoteCount)
|
|
{
|
|
if (kind == InterpolatedStringKind.MultiLineRaw)
|
|
{
|
|
_lexer.ConsumeWhitespace(null);
|
|
int position = _lexer.TextWindow.Position;
|
|
int num = _lexer.ConsumeQuoteSequence();
|
|
if (num >= startingQuoteCount)
|
|
{
|
|
TrySetError(_lexer.MakeError(_lexer.TextWindow.Position - num, num, ErrorCode.ERR_RawStringMustContainContent));
|
|
_lexer.TextWindow.Reset(position);
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
private bool IsAtEndOfMultiLineRawLiteral(InterpolatedStringKind kind, int startingQuoteCount)
|
|
{
|
|
if (kind == InterpolatedStringKind.MultiLineRaw)
|
|
{
|
|
int position = _lexer.TextWindow.Position;
|
|
if (SyntaxFacts.IsNewLine(_lexer.TextWindow.PeekChar()))
|
|
{
|
|
_lexer.TextWindow.AdvancePastNewLine();
|
|
_lexer.ConsumeWhitespace(null);
|
|
int num = _lexer.ConsumeQuoteSequence();
|
|
_lexer.TextWindow.Reset(position);
|
|
if (num >= startingQuoteCount)
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
private bool IsEndDelimiterOtherwiseConsume(InterpolatedStringKind kind, int startingQuoteCount)
|
|
{
|
|
if ((uint)kind <= 1u)
|
|
{
|
|
if (RecoveringFromRunawayLexing())
|
|
{
|
|
return true;
|
|
}
|
|
if (kind == InterpolatedStringKind.Normal)
|
|
{
|
|
return true;
|
|
}
|
|
if (_lexer.TextWindow.PeekChar(1) != '"')
|
|
{
|
|
return true;
|
|
}
|
|
_lexer.TextWindow.AdvanceChar(2);
|
|
}
|
|
else
|
|
{
|
|
int position = _lexer.TextWindow.Position;
|
|
if (_lexer.ConsumeQuoteSequence() >= startingQuoteCount)
|
|
{
|
|
_lexer.TextWindow.Reset(position);
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
private void HandleCloseBraceInContent(InterpolatedStringKind kind, int startingDollarSignCount)
|
|
{
|
|
if ((uint)kind <= 1u)
|
|
{
|
|
int position = _lexer.TextWindow.Position;
|
|
_lexer.TextWindow.AdvanceChar();
|
|
if (_lexer.TextWindow.PeekChar() == '}')
|
|
{
|
|
_lexer.TextWindow.AdvanceChar();
|
|
return;
|
|
}
|
|
TrySetError(_lexer.MakeError(position, 1, ErrorCode.ERR_UnescapedCurly, "}"));
|
|
}
|
|
else
|
|
{
|
|
int num = _lexer.ConsumeCloseBraceSequence();
|
|
if (num >= startingDollarSignCount)
|
|
{
|
|
TrySetError(_lexer.MakeError(_lexer.TextWindow.Position - num, num, ErrorCode.ERR_TooManyCloseBracesForRawString));
|
|
}
|
|
}
|
|
}
|
|
|
|
private void HandleOpenBraceInContent(InterpolatedStringKind kind, int startingDollarSignCount, ArrayBuilder<Interpolation>? interpolations)
|
|
{
|
|
if ((uint)kind <= 1u)
|
|
{
|
|
HandleOpenBraceInNormalOrVerbatimContent(kind, interpolations);
|
|
}
|
|
else
|
|
{
|
|
HandleOpenBraceInRawContent(kind, startingDollarSignCount, interpolations);
|
|
}
|
|
}
|
|
|
|
private void HandleOpenBraceInNormalOrVerbatimContent(InterpolatedStringKind kind, ArrayBuilder<Interpolation>? interpolations)
|
|
{
|
|
if (_lexer.TextWindow.PeekChar(1) == '{')
|
|
{
|
|
_lexer.TextWindow.AdvanceChar(2);
|
|
return;
|
|
}
|
|
int position = _lexer.TextWindow.Position;
|
|
_lexer.TextWindow.AdvanceChar();
|
|
ScanInterpolatedStringLiteralHoleBalancedText(kind, '}', isHole: true, out var colonRange);
|
|
int position2 = _lexer.TextWindow.Position;
|
|
if (_lexer.TextWindow.PeekChar() == '}')
|
|
{
|
|
_lexer.TextWindow.AdvanceChar();
|
|
}
|
|
else
|
|
{
|
|
TrySetError(_lexer.MakeError(position - 1, 2, ErrorCode.ERR_UnclosedExpressionHole));
|
|
}
|
|
interpolations?.Add(new Interpolation(position..(position + 1), colonRange, position2.._lexer.TextWindow.Position));
|
|
}
|
|
|
|
private void HandleOpenBraceInRawContent(InterpolatedStringKind kind, int startingDollarSignCount, ArrayBuilder<Interpolation>? interpolations)
|
|
{
|
|
int position = _lexer.TextWindow.Position;
|
|
int num = _lexer.ConsumeOpenBraceSequence();
|
|
if (num >= startingDollarSignCount)
|
|
{
|
|
int position2 = _lexer.TextWindow.Position;
|
|
if (num >= 2 * startingDollarSignCount)
|
|
{
|
|
TrySetError(_lexer.MakeError(position, num - startingDollarSignCount, ErrorCode.ERR_TooManyOpenBracesForRawString));
|
|
}
|
|
ScanInterpolatedStringLiteralHoleBalancedText(kind, '}', isHole: true, out var colonRange);
|
|
int position3 = _lexer.TextWindow.Position;
|
|
int num2 = _lexer.ConsumeCloseBraceSequence();
|
|
if (num2 == 0)
|
|
{
|
|
TrySetError(_lexer.MakeError(position2 - startingDollarSignCount, startingDollarSignCount, ErrorCode.ERR_UnclosedExpressionHole));
|
|
}
|
|
else if (num2 < startingDollarSignCount)
|
|
{
|
|
TrySetError(_lexer.MakeError(position, num - startingDollarSignCount, ErrorCode.ERR_NotEnoughCloseBracesForRawString));
|
|
}
|
|
else
|
|
{
|
|
_lexer.TextWindow.Reset(position3 + startingDollarSignCount);
|
|
}
|
|
interpolations?.Add(new Interpolation((position2 - startingDollarSignCount)..position2, colonRange, position3.._lexer.TextWindow.Position));
|
|
}
|
|
}
|
|
|
|
private void ScanFormatSpecifier(InterpolatedStringKind kind)
|
|
{
|
|
_lexer.TextWindow.AdvanceChar();
|
|
while (true)
|
|
{
|
|
char c = _lexer.TextWindow.PeekChar();
|
|
if (c == '\\' && kind == InterpolatedStringKind.Normal)
|
|
{
|
|
int position = _lexer.TextWindow.Position;
|
|
c = _lexer.ScanEscapeSequence(out var _);
|
|
if ((c == '{' || c == '}') ? true : false)
|
|
{
|
|
TrySetError(_lexer.MakeError(position, 1, ErrorCode.ERR_EscapedCurly, c));
|
|
}
|
|
continue;
|
|
}
|
|
switch (c)
|
|
{
|
|
case '"':
|
|
if (kind == InterpolatedStringKind.Verbatim && _lexer.TextWindow.PeekChar(1) == '"')
|
|
{
|
|
_lexer.TextWindow.AdvanceChar(2);
|
|
break;
|
|
}
|
|
return;
|
|
case '{':
|
|
TrySetError(_lexer.MakeError(_lexer.TextWindow.Position, 1, ErrorCode.ERR_UnexpectedCharacter, c));
|
|
_lexer.TextWindow.AdvanceChar();
|
|
break;
|
|
case '}':
|
|
return;
|
|
default:
|
|
if (IsAtEnd(allowNewline: true))
|
|
{
|
|
return;
|
|
}
|
|
_lexer.TextWindow.AdvanceChar();
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
private void ScanInterpolatedStringLiteralHoleBalancedText(InterpolatedStringKind kind, char endingChar, bool isHole, out Range colonRange)
|
|
{
|
|
colonRange = default(Range);
|
|
while (true)
|
|
{
|
|
char c = _lexer.TextWindow.PeekChar();
|
|
if (IsAtEnd(allowNewline: true))
|
|
{
|
|
break;
|
|
}
|
|
switch (c)
|
|
{
|
|
case '#':
|
|
TrySetError(_lexer.MakeError(_lexer.TextWindow.Position, 1, ErrorCode.ERR_SyntaxError, endingChar.ToString()));
|
|
_lexer.TextWindow.AdvanceChar();
|
|
continue;
|
|
case '$':
|
|
{
|
|
TokenInfo info2 = default(TokenInfo);
|
|
if (_lexer.TryScanInterpolatedString(ref info2))
|
|
{
|
|
continue;
|
|
}
|
|
break;
|
|
}
|
|
case ':':
|
|
if (isHole)
|
|
{
|
|
colonRange = _lexer.TextWindow.Position..(_lexer.TextWindow.Position + 1);
|
|
ScanFormatSpecifier(kind);
|
|
return;
|
|
}
|
|
break;
|
|
case ')':
|
|
case ']':
|
|
case '}':
|
|
if (c == endingChar)
|
|
{
|
|
return;
|
|
}
|
|
TrySetError(_lexer.MakeError(_lexer.TextWindow.Position, 1, ErrorCode.ERR_SyntaxError, endingChar.ToString()));
|
|
break;
|
|
case '"':
|
|
if (RecoveringFromRunawayLexing())
|
|
{
|
|
return;
|
|
}
|
|
ScanInterpolatedStringLiteralNestedString();
|
|
continue;
|
|
case '\'':
|
|
ScanInterpolatedStringLiteralNestedString();
|
|
continue;
|
|
case '@':
|
|
{
|
|
TokenInfo info = default(TokenInfo);
|
|
if (_lexer.TryScanAtStringToken(ref info))
|
|
{
|
|
continue;
|
|
}
|
|
break;
|
|
}
|
|
case '/':
|
|
switch (_lexer.TextWindow.PeekChar(1))
|
|
{
|
|
case '/':
|
|
_lexer.ScanToEndOfLine();
|
|
break;
|
|
case '*':
|
|
{
|
|
_lexer.ScanMultiLineComment(out var _);
|
|
break;
|
|
}
|
|
default:
|
|
_lexer.TextWindow.AdvanceChar();
|
|
break;
|
|
}
|
|
continue;
|
|
case '{':
|
|
ScanInterpolatedStringLiteralHoleBracketed(kind, '{', '}');
|
|
continue;
|
|
case '(':
|
|
ScanInterpolatedStringLiteralHoleBracketed(kind, '(', ')');
|
|
continue;
|
|
case '[':
|
|
ScanInterpolatedStringLiteralHoleBracketed(kind, '[', ']');
|
|
continue;
|
|
}
|
|
_lexer.TextWindow.AdvanceChar();
|
|
}
|
|
}
|
|
|
|
private bool RecoveringFromRunawayLexing()
|
|
{
|
|
return Error != null;
|
|
}
|
|
|
|
private void ScanInterpolatedStringLiteralNestedString()
|
|
{
|
|
TokenInfo info = default(TokenInfo);
|
|
_lexer.ScanStringLiteral(ref info, inDirective: false);
|
|
}
|
|
|
|
private void ScanInterpolatedStringLiteralHoleBracketed(InterpolatedStringKind kind, char start, char end)
|
|
{
|
|
_lexer.TextWindow.AdvanceChar();
|
|
ScanInterpolatedStringLiteralHoleBalancedText(kind, end, isHole: false, out var _);
|
|
if (_lexer.TextWindow.PeekChar() == end)
|
|
{
|
|
_lexer.TextWindow.AdvanceChar();
|
|
}
|
|
}
|
|
}
|
|
|
|
private enum QuickScanState : byte
|
|
{
|
|
Initial,
|
|
FollowingWhite,
|
|
FollowingCR,
|
|
Ident,
|
|
Number,
|
|
Punctuation,
|
|
Dot,
|
|
CompoundPunctStart,
|
|
DoneAfterNext,
|
|
Done,
|
|
Bad
|
|
}
|
|
|
|
private enum CharFlags : byte
|
|
{
|
|
White,
|
|
CR,
|
|
LF,
|
|
Letter,
|
|
Digit,
|
|
Punct,
|
|
Dot,
|
|
CompoundPunctStart,
|
|
Slash,
|
|
Complex,
|
|
EndOfFile
|
|
}
|
|
|
|
private const int TriviaListInitialCapacity = 8;
|
|
|
|
private readonly CSharpParseOptions _options;
|
|
|
|
private LexerMode _mode;
|
|
|
|
private readonly StringBuilder _builder;
|
|
|
|
private char[] _identBuffer;
|
|
|
|
private int _identLen;
|
|
|
|
private DirectiveStack _directives;
|
|
|
|
private readonly LexerCache _cache;
|
|
|
|
private readonly bool _allowPreprocessorDirectives;
|
|
|
|
private readonly bool _interpolationFollowedByColon;
|
|
|
|
private DocumentationCommentParser? _xmlParser;
|
|
|
|
private int _badTokenCount;
|
|
|
|
private SyntaxListBuilder _leadingTriviaCache = new SyntaxListBuilder(10);
|
|
|
|
private SyntaxListBuilder _trailingTriviaCache = new SyntaxListBuilder(10);
|
|
|
|
private static readonly int s_conflictMarkerLength = "<<<<<<<".Length;
|
|
|
|
private Func<SyntaxTrivia>? _createWhitespaceTriviaFunction;
|
|
|
|
internal const int MaxCachedTokenSize = 42;
|
|
|
|
private static readonly byte[,] s_stateTransitions = new byte[9, 11]
|
|
{
|
|
{
|
|
0, 0, 0, 3, 4, 5, 6, 7, 10, 10,
|
|
10
|
|
},
|
|
{
|
|
1, 2, 8, 9, 9, 9, 9, 9, 10, 10,
|
|
9
|
|
},
|
|
{
|
|
9, 9, 8, 9, 9, 9, 9, 9, 9, 9,
|
|
9
|
|
},
|
|
{
|
|
1, 2, 8, 3, 3, 9, 9, 9, 10, 10,
|
|
9
|
|
},
|
|
{
|
|
1, 2, 8, 10, 4, 9, 10, 9, 10, 10,
|
|
9
|
|
},
|
|
{
|
|
1, 2, 8, 9, 9, 9, 9, 9, 10, 10,
|
|
9
|
|
},
|
|
{
|
|
1, 2, 8, 9, 4, 9, 10, 9, 10, 10,
|
|
9
|
|
},
|
|
{
|
|
1, 2, 8, 9, 9, 10, 9, 10, 10, 10,
|
|
9
|
|
},
|
|
{
|
|
9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
|
|
9
|
|
}
|
|
};
|
|
|
|
private readonly Func<SyntaxToken> _createQuickTokenFunction;
|
|
|
|
public bool SuppressDocumentationCommentParse => (int)((ParseOptions)_options).DocumentationMode < 1;
|
|
|
|
public CSharpParseOptions Options => _options;
|
|
|
|
public DirectiveStack Directives => _directives;
|
|
|
|
public bool InterpolationFollowedByColon => _interpolationFollowedByColon;
|
|
|
|
private bool InDocumentationComment
|
|
{
|
|
get
|
|
{
|
|
switch (ModeOf(_mode))
|
|
{
|
|
case LexerMode.XmlDocComment:
|
|
case LexerMode.XmlElementTag:
|
|
case LexerMode.XmlAttributeTextQuote:
|
|
case LexerMode.XmlAttributeTextDoubleQuote:
|
|
case LexerMode.XmlCrefQuote:
|
|
case LexerMode.XmlCrefDoubleQuote:
|
|
case LexerMode.XmlNameQuote:
|
|
case LexerMode.XmlNameDoubleQuote:
|
|
case LexerMode.XmlCDataSectionText:
|
|
case LexerMode.XmlCommentText:
|
|
case LexerMode.XmlProcessingInstructionText:
|
|
case LexerMode.XmlCharacter:
|
|
return true;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
private bool InXmlCrefOrNameAttributeValue
|
|
{
|
|
get
|
|
{
|
|
switch (_mode & LexerMode.MaskLexMode)
|
|
{
|
|
case LexerMode.XmlCrefQuote:
|
|
case LexerMode.XmlCrefDoubleQuote:
|
|
case LexerMode.XmlNameQuote:
|
|
case LexerMode.XmlNameDoubleQuote:
|
|
return true;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
private bool InXmlNameAttributeValue
|
|
{
|
|
get
|
|
{
|
|
LexerMode lexerMode = _mode & LexerMode.MaskLexMode;
|
|
if (lexerMode == LexerMode.XmlNameQuote || lexerMode == LexerMode.XmlNameDoubleQuote)
|
|
{
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
}
|
|
|
|
private static ReadOnlySpan<byte> CharProperties => new byte[384]
|
|
{
|
|
9, 9, 9, 9, 9, 9, 9, 9, 9, 0,
|
|
2, 0, 0, 1, 9, 9, 9, 9, 9, 9,
|
|
9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
|
|
9, 9, 0, 7, 9, 9, 9, 7, 7, 9,
|
|
5, 5, 7, 7, 5, 7, 6, 8, 4, 4,
|
|
4, 4, 4, 4, 4, 4, 4, 4, 7, 5,
|
|
7, 7, 7, 7, 9, 3, 3, 3, 3, 3,
|
|
3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
|
3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
|
3, 5, 9, 5, 7, 3, 9, 3, 3, 3,
|
|
3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
|
3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
|
3, 3, 3, 5, 7, 5, 7, 9, 9, 9,
|
|
9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
|
|
9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
|
|
9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
|
|
9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
|
|
3, 9, 9, 9, 9, 9, 9, 9, 9, 9,
|
|
9, 3, 9, 9, 9, 9, 3, 9, 9, 9,
|
|
9, 9, 3, 3, 3, 3, 3, 3, 3, 3,
|
|
3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
|
3, 3, 3, 3, 3, 9, 3, 3, 3, 3,
|
|
3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
|
3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
|
3, 3, 3, 3, 3, 3, 3, 9, 3, 3,
|
|
3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
|
3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
|
3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
|
3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
|
3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
|
3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
|
3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
|
3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
|
3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
|
3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
|
3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
|
3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
|
3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
|
3, 3, 3, 3
|
|
};
|
|
|
|
public Lexer(SourceText text, CSharpParseOptions options, bool allowPreprocessorDirectives = true, bool interpolationFollowedByColon = false)
|
|
: base(text)
|
|
{
|
|
//IL_0003: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_000d: Expected O, but got Unknown
|
|
//IL_0010: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_001a: Expected O, but got Unknown
|
|
_options = options;
|
|
_builder = new StringBuilder();
|
|
_identBuffer = new char[32];
|
|
_cache = new LexerCache();
|
|
_createQuickTokenFunction = CreateQuickToken;
|
|
_allowPreprocessorDirectives = allowPreprocessorDirectives;
|
|
_interpolationFollowedByColon = interpolationFollowedByColon;
|
|
}
|
|
|
|
public override void Dispose()
|
|
{
|
|
_cache.Free();
|
|
if (_xmlParser != null)
|
|
{
|
|
_xmlParser.Dispose();
|
|
}
|
|
base.Dispose();
|
|
}
|
|
|
|
public void Reset(int position, DirectiveStack directives)
|
|
{
|
|
TextWindow.Reset(position);
|
|
_directives = directives;
|
|
}
|
|
|
|
private static LexerMode ModeOf(LexerMode mode)
|
|
{
|
|
return mode & LexerMode.MaskLexMode;
|
|
}
|
|
|
|
private bool ModeIs(LexerMode mode)
|
|
{
|
|
return ModeOf(_mode) == mode;
|
|
}
|
|
|
|
private static XmlDocCommentLocation LocationOf(LexerMode mode)
|
|
{
|
|
return (XmlDocCommentLocation)((int)(mode & LexerMode.MaskXmlDocCommentLocation) >> 16);
|
|
}
|
|
|
|
private bool LocationIs(XmlDocCommentLocation location)
|
|
{
|
|
return LocationOf(_mode) == location;
|
|
}
|
|
|
|
private void MutateLocation(XmlDocCommentLocation location)
|
|
{
|
|
_mode &= ~LexerMode.MaskXmlDocCommentLocation;
|
|
_mode |= (LexerMode)((int)location << 16);
|
|
}
|
|
|
|
private static XmlDocCommentStyle StyleOf(LexerMode mode)
|
|
{
|
|
return (XmlDocCommentStyle)((int)(mode & LexerMode.MaskXmlDocCommentStyle) >> 20);
|
|
}
|
|
|
|
private bool StyleIs(XmlDocCommentStyle style)
|
|
{
|
|
return StyleOf(_mode) == style;
|
|
}
|
|
|
|
public SyntaxToken Lex(ref LexerMode mode)
|
|
{
|
|
SyntaxToken result = Lex(mode);
|
|
mode = _mode;
|
|
return result;
|
|
}
|
|
|
|
public SyntaxToken Lex(LexerMode mode)
|
|
{
|
|
_mode = mode;
|
|
switch (_mode)
|
|
{
|
|
case LexerMode.Syntax:
|
|
case LexerMode.DebuggerSyntax:
|
|
return QuickScanSyntaxToken() ?? LexSyntaxToken();
|
|
case LexerMode.Directive:
|
|
return LexDirectiveToken();
|
|
default:
|
|
switch (ModeOf(_mode))
|
|
{
|
|
case LexerMode.XmlDocComment:
|
|
return LexXmlToken();
|
|
case LexerMode.XmlElementTag:
|
|
return LexXmlElementTagToken();
|
|
case LexerMode.XmlAttributeTextQuote:
|
|
case LexerMode.XmlAttributeTextDoubleQuote:
|
|
return LexXmlAttributeTextToken();
|
|
case LexerMode.XmlCDataSectionText:
|
|
return LexXmlCDataSectionTextToken();
|
|
case LexerMode.XmlCommentText:
|
|
return LexXmlCommentTextToken();
|
|
case LexerMode.XmlProcessingInstructionText:
|
|
return LexXmlProcessingInstructionTextToken();
|
|
case LexerMode.XmlCrefQuote:
|
|
case LexerMode.XmlCrefDoubleQuote:
|
|
return LexXmlCrefOrNameToken();
|
|
case LexerMode.XmlNameQuote:
|
|
case LexerMode.XmlNameDoubleQuote:
|
|
return LexXmlCrefOrNameToken();
|
|
case LexerMode.XmlCharacter:
|
|
return LexXmlCharacter();
|
|
default:
|
|
throw ExceptionUtilities.UnexpectedValue((object)ModeOf(_mode));
|
|
}
|
|
}
|
|
}
|
|
|
|
private static int GetFullWidth(SyntaxListBuilder? builder)
|
|
{
|
|
int num = 0;
|
|
if (builder != null)
|
|
{
|
|
for (int i = 0; i < builder.Count; i++)
|
|
{
|
|
num += builder[i].FullWidth;
|
|
}
|
|
}
|
|
return num;
|
|
}
|
|
|
|
private SyntaxToken LexSyntaxToken()
|
|
{
|
|
_leadingTriviaCache.Clear();
|
|
LexSyntaxTrivia(TextWindow.Position > 0, isTrailing: false, ref _leadingTriviaCache);
|
|
SyntaxListBuilder leadingTriviaCache = _leadingTriviaCache;
|
|
TokenInfo info = default(TokenInfo);
|
|
Start();
|
|
ScanSyntaxToken(ref info);
|
|
SyntaxDiagnosticInfo[] errors = GetErrors(GetFullWidth(leadingTriviaCache));
|
|
_trailingTriviaCache.Clear();
|
|
LexSyntaxTrivia(afterFirstToken: true, isTrailing: true, ref _trailingTriviaCache);
|
|
SyntaxListBuilder trailingTriviaCache = _trailingTriviaCache;
|
|
return Create(in info, leadingTriviaCache, trailingTriviaCache, errors);
|
|
}
|
|
|
|
internal SyntaxTriviaList LexSyntaxLeadingTrivia()
|
|
{
|
|
//IL_0029: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_003c: Unknown result type (might be due to invalid IL or missing references)
|
|
_leadingTriviaCache.Clear();
|
|
LexSyntaxTrivia(TextWindow.Position > 0, isTrailing: false, ref _leadingTriviaCache);
|
|
SyntaxToken val = default(SyntaxToken);
|
|
return new SyntaxTriviaList(ref val, _leadingTriviaCache.ToListNode(), 0, 0);
|
|
}
|
|
|
|
internal SyntaxTriviaList LexSyntaxTrailingTrivia()
|
|
{
|
|
//IL_001c: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_002f: Unknown result type (might be due to invalid IL or missing references)
|
|
_trailingTriviaCache.Clear();
|
|
LexSyntaxTrivia(afterFirstToken: true, isTrailing: true, ref _trailingTriviaCache);
|
|
SyntaxToken val = default(SyntaxToken);
|
|
return new SyntaxTriviaList(ref val, _trailingTriviaCache.ToListNode(), 0, 0);
|
|
}
|
|
|
|
private SyntaxToken Create(in TokenInfo info, SyntaxListBuilder? leading, SyntaxListBuilder? trailing, SyntaxDiagnosticInfo[]? errors)
|
|
{
|
|
//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_00f4: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_00f6: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_00fa: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_011c: Expected I4, but got Unknown
|
|
//IL_02af: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_02b5: Invalid comparison between Unknown and I4
|
|
//IL_01d1: Unknown result type (might be due to invalid IL or missing references)
|
|
GreenNode leading2 = ((leading != null) ? leading.ToListNode() : null);
|
|
GreenNode trailing2 = ((trailing != null) ? trailing.ToListNode() : null);
|
|
SyntaxToken syntaxToken;
|
|
if (info.RequiresTextForXmlEntity)
|
|
{
|
|
syntaxToken = SyntaxFactory.Token(leading2, info.Kind, info.Text, info.StringValue, trailing2);
|
|
}
|
|
else
|
|
{
|
|
switch (info.Kind)
|
|
{
|
|
case SyntaxKind.IdentifierToken:
|
|
syntaxToken = SyntaxFactory.Identifier(info.ContextualKind, leading2, info.Text, info.StringValue, trailing2);
|
|
break;
|
|
case SyntaxKind.NumericLiteralToken:
|
|
{
|
|
SpecialType valueKind = info.ValueKind;
|
|
syntaxToken = (valueKind - 13) switch
|
|
{
|
|
0 => SyntaxFactory.Literal(leading2, info.Text, info.IntValue, trailing2),
|
|
1 => SyntaxFactory.Literal(leading2, info.Text, info.UintValue, trailing2),
|
|
2 => SyntaxFactory.Literal(leading2, info.Text, info.LongValue, trailing2),
|
|
3 => SyntaxFactory.Literal(leading2, info.Text, info.UlongValue, trailing2),
|
|
5 => SyntaxFactory.Literal(leading2, info.Text, info.FloatValue, trailing2),
|
|
6 => SyntaxFactory.Literal(leading2, info.Text, info.DoubleValue, trailing2),
|
|
4 => SyntaxFactory.Literal(leading2, info.Text, info.DecimalValue, trailing2),
|
|
_ => throw ExceptionUtilities.UnexpectedValue((object)info.ValueKind),
|
|
};
|
|
break;
|
|
}
|
|
case SyntaxKind.InterpolatedStringToken:
|
|
syntaxToken = SyntaxFactory.Literal(leading2, info.Text, info.Kind, info.Text, trailing2);
|
|
break;
|
|
case SyntaxKind.StringLiteralToken:
|
|
case SyntaxKind.SingleLineRawStringLiteralToken:
|
|
case SyntaxKind.MultiLineRawStringLiteralToken:
|
|
case SyntaxKind.Utf8StringLiteralToken:
|
|
case SyntaxKind.Utf8SingleLineRawStringLiteralToken:
|
|
case SyntaxKind.Utf8MultiLineRawStringLiteralToken:
|
|
syntaxToken = SyntaxFactory.Literal(leading2, info.Text, info.Kind, info.StringValue, trailing2);
|
|
break;
|
|
case SyntaxKind.CharacterLiteralToken:
|
|
syntaxToken = SyntaxFactory.Literal(leading2, info.Text, info.CharValue, trailing2);
|
|
break;
|
|
case SyntaxKind.XmlTextLiteralNewLineToken:
|
|
syntaxToken = SyntaxFactory.XmlTextNewLine(leading2, info.Text, info.StringValue, trailing2);
|
|
break;
|
|
case SyntaxKind.XmlTextLiteralToken:
|
|
syntaxToken = SyntaxFactory.XmlTextLiteral(leading2, info.Text, info.StringValue, trailing2);
|
|
break;
|
|
case SyntaxKind.XmlEntityLiteralToken:
|
|
syntaxToken = SyntaxFactory.XmlEntity(leading2, info.Text, info.StringValue, trailing2);
|
|
break;
|
|
case SyntaxKind.EndOfDocumentationCommentToken:
|
|
case SyntaxKind.EndOfFileToken:
|
|
syntaxToken = SyntaxFactory.Token(leading2, info.Kind, trailing2);
|
|
break;
|
|
case SyntaxKind.None:
|
|
syntaxToken = SyntaxFactory.BadToken(leading2, info.Text, trailing2);
|
|
break;
|
|
default:
|
|
syntaxToken = SyntaxFactory.Token(leading2, info.Kind, trailing2);
|
|
break;
|
|
}
|
|
}
|
|
if (errors != null && ((int)((ParseOptions)_options).DocumentationMode >= 2 || !InDocumentationComment))
|
|
{
|
|
syntaxToken = GreenNodeExtensions.WithDiagnosticsGreen<SyntaxToken>(syntaxToken, (DiagnosticInfo[])(object)errors);
|
|
}
|
|
return syntaxToken;
|
|
}
|
|
|
|
private void ScanSyntaxToken(ref TokenInfo info)
|
|
{
|
|
//IL_06db: Unknown result type (might be due to invalid IL or missing references)
|
|
info.Kind = SyntaxKind.None;
|
|
info.ContextualKind = SyntaxKind.None;
|
|
info.Text = null;
|
|
bool flag = false;
|
|
int position = TextWindow.Position;
|
|
char c = TextWindow.PeekChar();
|
|
char surrogateCharacter;
|
|
switch (c)
|
|
{
|
|
case '"':
|
|
case '\'':
|
|
ScanStringLiteral(ref info, inDirective: false);
|
|
break;
|
|
case '/':
|
|
TextWindow.AdvanceChar();
|
|
info.Kind = (TextWindow.TryAdvance('=') ? SyntaxKind.SlashEqualsToken : SyntaxKind.SlashToken);
|
|
break;
|
|
case '.':
|
|
if (ScanNumericLiteral(ref info))
|
|
{
|
|
break;
|
|
}
|
|
TextWindow.AdvanceChar();
|
|
if (TextWindow.TryAdvance('.'))
|
|
{
|
|
if (TextWindow.PeekChar() == '.')
|
|
{
|
|
AddError(ErrorCode.ERR_TripleDotNotAllowed);
|
|
}
|
|
info.Kind = SyntaxKind.DotDotToken;
|
|
}
|
|
else
|
|
{
|
|
info.Kind = SyntaxKind.DotToken;
|
|
}
|
|
break;
|
|
case ',':
|
|
TextWindow.AdvanceChar();
|
|
info.Kind = SyntaxKind.CommaToken;
|
|
break;
|
|
case ':':
|
|
TextWindow.AdvanceChar();
|
|
info.Kind = (TextWindow.TryAdvance(':') ? SyntaxKind.ColonColonToken : SyntaxKind.ColonToken);
|
|
break;
|
|
case ';':
|
|
TextWindow.AdvanceChar();
|
|
info.Kind = SyntaxKind.SemicolonToken;
|
|
break;
|
|
case '~':
|
|
TextWindow.AdvanceChar();
|
|
info.Kind = SyntaxKind.TildeToken;
|
|
break;
|
|
case '!':
|
|
TextWindow.AdvanceChar();
|
|
info.Kind = (TextWindow.TryAdvance('=') ? SyntaxKind.ExclamationEqualsToken : SyntaxKind.ExclamationToken);
|
|
break;
|
|
case '=':
|
|
TextWindow.AdvanceChar();
|
|
info.Kind = (TextWindow.TryAdvance('=') ? SyntaxKind.EqualsEqualsToken : (TextWindow.TryAdvance('>') ? SyntaxKind.EqualsGreaterThanToken : SyntaxKind.EqualsToken));
|
|
break;
|
|
case '*':
|
|
TextWindow.AdvanceChar();
|
|
info.Kind = (TextWindow.TryAdvance('=') ? SyntaxKind.AsteriskEqualsToken : SyntaxKind.AsteriskToken);
|
|
break;
|
|
case '(':
|
|
TextWindow.AdvanceChar();
|
|
info.Kind = SyntaxKind.OpenParenToken;
|
|
break;
|
|
case ')':
|
|
TextWindow.AdvanceChar();
|
|
info.Kind = SyntaxKind.CloseParenToken;
|
|
break;
|
|
case '{':
|
|
TextWindow.AdvanceChar();
|
|
info.Kind = SyntaxKind.OpenBraceToken;
|
|
break;
|
|
case '}':
|
|
TextWindow.AdvanceChar();
|
|
info.Kind = SyntaxKind.CloseBraceToken;
|
|
break;
|
|
case '[':
|
|
TextWindow.AdvanceChar();
|
|
info.Kind = SyntaxKind.OpenBracketToken;
|
|
break;
|
|
case ']':
|
|
TextWindow.AdvanceChar();
|
|
info.Kind = SyntaxKind.CloseBracketToken;
|
|
break;
|
|
case '?':
|
|
TextWindow.AdvanceChar();
|
|
info.Kind = ((!TextWindow.TryAdvance('?')) ? SyntaxKind.QuestionToken : (TextWindow.TryAdvance('=') ? SyntaxKind.QuestionQuestionEqualsToken : SyntaxKind.QuestionQuestionToken));
|
|
break;
|
|
case '+':
|
|
TextWindow.AdvanceChar();
|
|
info.Kind = (TextWindow.TryAdvance('=') ? SyntaxKind.PlusEqualsToken : (TextWindow.TryAdvance('+') ? SyntaxKind.PlusPlusToken : SyntaxKind.PlusToken));
|
|
break;
|
|
case '-':
|
|
TextWindow.AdvanceChar();
|
|
info.Kind = (TextWindow.TryAdvance('=') ? SyntaxKind.MinusEqualsToken : (TextWindow.TryAdvance('-') ? SyntaxKind.MinusMinusToken : (TextWindow.TryAdvance('>') ? SyntaxKind.MinusGreaterThanToken : SyntaxKind.MinusToken)));
|
|
break;
|
|
case '%':
|
|
TextWindow.AdvanceChar();
|
|
info.Kind = (TextWindow.TryAdvance('=') ? SyntaxKind.PercentEqualsToken : SyntaxKind.PercentToken);
|
|
break;
|
|
case '&':
|
|
TextWindow.AdvanceChar();
|
|
info.Kind = (TextWindow.TryAdvance('=') ? SyntaxKind.AmpersandEqualsToken : (TextWindow.TryAdvance('&') ? SyntaxKind.AmpersandAmpersandToken : SyntaxKind.AmpersandToken));
|
|
break;
|
|
case '^':
|
|
TextWindow.AdvanceChar();
|
|
info.Kind = (TextWindow.TryAdvance('=') ? SyntaxKind.CaretEqualsToken : SyntaxKind.CaretToken);
|
|
break;
|
|
case '|':
|
|
TextWindow.AdvanceChar();
|
|
info.Kind = (TextWindow.TryAdvance('=') ? SyntaxKind.BarEqualsToken : (TextWindow.TryAdvance('|') ? SyntaxKind.BarBarToken : SyntaxKind.BarToken));
|
|
break;
|
|
case '<':
|
|
TextWindow.AdvanceChar();
|
|
info.Kind = (TextWindow.TryAdvance('=') ? SyntaxKind.LessThanEqualsToken : ((!TextWindow.TryAdvance('<')) ? SyntaxKind.LessThanToken : (TextWindow.TryAdvance('=') ? SyntaxKind.LessThanLessThanEqualsToken : SyntaxKind.LessThanLessThanToken)));
|
|
break;
|
|
case '>':
|
|
TextWindow.AdvanceChar();
|
|
info.Kind = (TextWindow.TryAdvance('=') ? SyntaxKind.GreaterThanEqualsToken : SyntaxKind.GreaterThanToken);
|
|
break;
|
|
case '@':
|
|
if (!TryScanAtStringToken(ref info) && !ScanIdentifierOrKeyword(ref info))
|
|
{
|
|
ConsumeAtSignSequence();
|
|
info.Text = TextWindow.GetText(intern: true);
|
|
AddError(ErrorCode.ERR_ExpectedVerbatimLiteral);
|
|
}
|
|
break;
|
|
case '$':
|
|
if (!TryScanInterpolatedString(ref info))
|
|
{
|
|
if (ModeIs(LexerMode.DebuggerSyntax))
|
|
{
|
|
goto case 'A';
|
|
}
|
|
goto default;
|
|
}
|
|
break;
|
|
case 'A':
|
|
case 'B':
|
|
case 'C':
|
|
case 'D':
|
|
case 'E':
|
|
case 'F':
|
|
case 'G':
|
|
case 'H':
|
|
case 'I':
|
|
case 'J':
|
|
case 'K':
|
|
case 'L':
|
|
case 'M':
|
|
case 'N':
|
|
case 'O':
|
|
case 'P':
|
|
case 'Q':
|
|
case 'R':
|
|
case 'S':
|
|
case 'T':
|
|
case 'U':
|
|
case 'V':
|
|
case 'W':
|
|
case 'X':
|
|
case 'Y':
|
|
case 'Z':
|
|
case '_':
|
|
case 'a':
|
|
case 'b':
|
|
case 'c':
|
|
case 'd':
|
|
case 'e':
|
|
case 'f':
|
|
case 'g':
|
|
case 'h':
|
|
case 'i':
|
|
case 'j':
|
|
case 'k':
|
|
case 'l':
|
|
case 'm':
|
|
case 'n':
|
|
case 'o':
|
|
case 'p':
|
|
case 'q':
|
|
case 'r':
|
|
case 's':
|
|
case 't':
|
|
case 'u':
|
|
case 'v':
|
|
case 'w':
|
|
case 'x':
|
|
case 'y':
|
|
case 'z':
|
|
ScanIdentifierOrKeyword(ref info);
|
|
break;
|
|
case '0':
|
|
case '1':
|
|
case '2':
|
|
case '3':
|
|
case '4':
|
|
case '5':
|
|
case '6':
|
|
case '7':
|
|
case '8':
|
|
case '9':
|
|
ScanNumericLiteral(ref info);
|
|
break;
|
|
case '\\':
|
|
flag = true;
|
|
c = PeekCharOrUnicodeEscape(out surrogateCharacter);
|
|
if (SyntaxFacts.IsIdentifierStartCharacter(c))
|
|
{
|
|
goto case 'A';
|
|
}
|
|
goto default;
|
|
case '\uffff':
|
|
if (TextWindow.IsReallyAtEnd())
|
|
{
|
|
if (_directives.HasUnfinishedIf())
|
|
{
|
|
AddError(ErrorCode.ERR_EndifDirectiveExpected);
|
|
}
|
|
if (_directives.HasUnfinishedRegion())
|
|
{
|
|
AddError(ErrorCode.ERR_EndRegionDirectiveExpected);
|
|
}
|
|
info.Kind = SyntaxKind.EndOfFileToken;
|
|
break;
|
|
}
|
|
goto default;
|
|
default:
|
|
if (!SyntaxFacts.IsIdentifierStartCharacter(c))
|
|
{
|
|
if (flag)
|
|
{
|
|
NextCharOrUnicodeEscape(out surrogateCharacter, out SyntaxDiagnosticInfo info2);
|
|
AddError(info2);
|
|
}
|
|
else
|
|
{
|
|
TextWindow.AdvanceChar();
|
|
if (char.IsHighSurrogate(c) && char.IsLowSurrogate(TextWindow.PeekChar()))
|
|
{
|
|
TextWindow.AdvanceChar();
|
|
}
|
|
}
|
|
if (_badTokenCount++ <= 200)
|
|
{
|
|
info.Text = TextWindow.GetText(intern: true);
|
|
}
|
|
else
|
|
{
|
|
int length = TextWindow.Text.Length;
|
|
info.Text = TextWindow.Text.ToString(TextSpan.FromBounds(position, length));
|
|
TextWindow.Reset(length);
|
|
}
|
|
string text = (flag ? info.Text : ObjectDisplay.FormatLiteral(info.Text, (ObjectDisplayOptions)16));
|
|
AddError(ErrorCode.ERR_UnexpectedCharacter, text);
|
|
break;
|
|
}
|
|
goto case 'A';
|
|
}
|
|
}
|
|
|
|
private bool TryScanAtStringToken(ref TokenInfo info)
|
|
{
|
|
int i;
|
|
for (i = 0; TextWindow.PeekChar(i) == '@'; i++)
|
|
{
|
|
}
|
|
if (TextWindow.PeekChar(i) == '"')
|
|
{
|
|
ScanVerbatimStringLiteral(ref info);
|
|
return true;
|
|
}
|
|
if (TextWindow.PeekChar(i) == '$')
|
|
{
|
|
ScanInterpolatedStringLiteral(ref info);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
private bool TryScanInterpolatedString(ref TokenInfo info)
|
|
{
|
|
char c = TextWindow.PeekChar(1);
|
|
if ((c == '"' || c == '$' || c == '@') ? true : false)
|
|
{
|
|
ScanInterpolatedStringLiteral(ref info);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
private void CheckFeatureAvailability(MessageID feature)
|
|
{
|
|
CSDiagnosticInfo featureAvailabilityDiagnosticInfo = feature.GetFeatureAvailabilityDiagnosticInfo(Options);
|
|
if (featureAvailabilityDiagnosticInfo != null)
|
|
{
|
|
AddError(featureAvailabilityDiagnosticInfo.Code, ((DiagnosticInfo)featureAvailabilityDiagnosticInfo).Arguments);
|
|
}
|
|
}
|
|
|
|
private bool ScanInteger()
|
|
{
|
|
int position = TextWindow.Position;
|
|
while (true)
|
|
{
|
|
char c = TextWindow.PeekChar();
|
|
if (c < '0' || c > '9')
|
|
{
|
|
break;
|
|
}
|
|
TextWindow.AdvanceChar();
|
|
}
|
|
return position < TextWindow.Position;
|
|
}
|
|
|
|
private void ScanNumericLiteralSingleInteger(ref bool underscoreInWrongPlace, ref bool usedUnderscore, ref bool firstCharWasUnderscore, bool isHex, bool isBinary)
|
|
{
|
|
if (TextWindow.PeekChar() == '_')
|
|
{
|
|
if (isHex || isBinary)
|
|
{
|
|
firstCharWasUnderscore = true;
|
|
}
|
|
else
|
|
{
|
|
underscoreInWrongPlace = true;
|
|
}
|
|
}
|
|
bool flag = false;
|
|
while (true)
|
|
{
|
|
char c = TextWindow.PeekChar();
|
|
if (c == '_')
|
|
{
|
|
usedUnderscore = true;
|
|
flag = true;
|
|
}
|
|
else
|
|
{
|
|
if (!(isHex ? SyntaxFacts.IsHexDigit(c) : (isBinary ? SyntaxFacts.IsBinaryDigit(c) : SyntaxFacts.IsDecDigit(c))))
|
|
{
|
|
break;
|
|
}
|
|
_builder.Append(c);
|
|
flag = false;
|
|
}
|
|
TextWindow.AdvanceChar();
|
|
}
|
|
if (flag)
|
|
{
|
|
underscoreInWrongPlace = true;
|
|
}
|
|
}
|
|
|
|
private bool ScanNumericLiteral(ref TokenInfo info)
|
|
{
|
|
//IL_001f: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0589: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_058e: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0590: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0594: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_05a6: Expected I4, but got Unknown
|
|
//IL_0409: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0372: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0437: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_03a0: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0465: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_03db: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_03ce: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0705: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0631: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_06f3: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_06e1: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_06b8: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_06a5: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_064d: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0685: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0670: Unknown result type (might be due to invalid IL or missing references)
|
|
int position = TextWindow.Position;
|
|
bool flag = false;
|
|
bool flag2 = false;
|
|
bool flag3 = false;
|
|
bool flag4 = false;
|
|
info.Text = null;
|
|
info.ValueKind = (SpecialType)0;
|
|
_builder.Clear();
|
|
bool flag5 = false;
|
|
bool flag6 = false;
|
|
bool underscoreInWrongPlace = false;
|
|
bool usedUnderscore = false;
|
|
bool firstCharWasUnderscore = false;
|
|
char c = TextWindow.PeekChar();
|
|
if (c == '0')
|
|
{
|
|
switch (TextWindow.PeekChar(1))
|
|
{
|
|
case 'X':
|
|
case 'x':
|
|
TextWindow.AdvanceChar(2);
|
|
flag = true;
|
|
break;
|
|
case 'B':
|
|
case 'b':
|
|
CheckFeatureAvailability(MessageID.IDS_FeatureBinaryLiteral);
|
|
TextWindow.AdvanceChar(2);
|
|
flag2 = true;
|
|
break;
|
|
}
|
|
}
|
|
if (flag || flag2)
|
|
{
|
|
ScanNumericLiteralSingleInteger(ref underscoreInWrongPlace, ref usedUnderscore, ref firstCharWasUnderscore, flag, flag2);
|
|
char c2 = TextWindow.PeekChar();
|
|
if ((c2 == 'L' || c2 == 'l') ? true : false)
|
|
{
|
|
TextWindow.AdvanceChar();
|
|
flag6 = true;
|
|
c2 = TextWindow.PeekChar();
|
|
if ((c2 == 'U' || c2 == 'u') ? true : false)
|
|
{
|
|
TextWindow.AdvanceChar();
|
|
flag5 = true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
c2 = TextWindow.PeekChar();
|
|
if ((c2 == 'U' || c2 == 'u') ? true : false)
|
|
{
|
|
TextWindow.AdvanceChar();
|
|
flag5 = true;
|
|
c2 = TextWindow.PeekChar();
|
|
if ((c2 == 'L' || c2 == 'l') ? true : false)
|
|
{
|
|
TextWindow.AdvanceChar();
|
|
flag6 = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ScanNumericLiteralSingleInteger(ref underscoreInWrongPlace, ref usedUnderscore, ref firstCharWasUnderscore, isHex: false, isBinary: false);
|
|
if (ModeIs(LexerMode.DebuggerSyntax) && TextWindow.PeekChar() == '#')
|
|
{
|
|
TextWindow.AdvanceChar();
|
|
info.StringValue = (info.Text = TextWindow.GetText(intern: true));
|
|
info.Kind = SyntaxKind.IdentifierToken;
|
|
AddError(AbstractLexer.MakeError(ErrorCode.ERR_LegacyObjectIdSyntax));
|
|
return true;
|
|
}
|
|
if ((c = TextWindow.PeekChar()) == '.')
|
|
{
|
|
char c3 = TextWindow.PeekChar(1);
|
|
if (c3 >= '0' && c3 <= '9')
|
|
{
|
|
flag3 = true;
|
|
_builder.Append(c);
|
|
TextWindow.AdvanceChar();
|
|
ScanNumericLiteralSingleInteger(ref underscoreInWrongPlace, ref usedUnderscore, ref firstCharWasUnderscore, isHex: false, isBinary: false);
|
|
}
|
|
else if (_builder.Length == 0)
|
|
{
|
|
TextWindow.Reset(position);
|
|
return false;
|
|
}
|
|
}
|
|
char c2 = (c = TextWindow.PeekChar());
|
|
if ((c2 == 'E' || c2 == 'e') ? true : false)
|
|
{
|
|
_builder.Append(c);
|
|
TextWindow.AdvanceChar();
|
|
flag4 = true;
|
|
c2 = (c = TextWindow.PeekChar());
|
|
if ((c2 == '+' || c2 == '-') ? true : false)
|
|
{
|
|
_builder.Append(c);
|
|
TextWindow.AdvanceChar();
|
|
}
|
|
if (((c = TextWindow.PeekChar()) < '0' || c > '9') && c != '_')
|
|
{
|
|
AddError(AbstractLexer.MakeError(ErrorCode.ERR_InvalidReal));
|
|
_builder.Append('0');
|
|
}
|
|
else
|
|
{
|
|
ScanNumericLiteralSingleInteger(ref underscoreInWrongPlace, ref usedUnderscore, ref firstCharWasUnderscore, isHex: false, isBinary: false);
|
|
}
|
|
}
|
|
c = TextWindow.PeekChar();
|
|
if (flag4 || flag3)
|
|
{
|
|
if ((c == 'F' || c == 'f') ? true : false)
|
|
{
|
|
TextWindow.AdvanceChar();
|
|
info.ValueKind = (SpecialType)18;
|
|
}
|
|
else if ((c == 'D' || c == 'd') ? true : false)
|
|
{
|
|
TextWindow.AdvanceChar();
|
|
info.ValueKind = (SpecialType)19;
|
|
}
|
|
else if ((c == 'M' || c == 'm') ? true : false)
|
|
{
|
|
TextWindow.AdvanceChar();
|
|
info.ValueKind = (SpecialType)17;
|
|
}
|
|
else
|
|
{
|
|
info.ValueKind = (SpecialType)19;
|
|
}
|
|
}
|
|
else if ((c == 'F' || c == 'f') ? true : false)
|
|
{
|
|
TextWindow.AdvanceChar();
|
|
info.ValueKind = (SpecialType)18;
|
|
}
|
|
else if ((c == 'D' || c == 'd') ? true : false)
|
|
{
|
|
TextWindow.AdvanceChar();
|
|
info.ValueKind = (SpecialType)19;
|
|
}
|
|
else if ((c == 'M' || c == 'm') ? true : false)
|
|
{
|
|
TextWindow.AdvanceChar();
|
|
info.ValueKind = (SpecialType)17;
|
|
}
|
|
else if ((c == 'L' || c == 'l') ? true : false)
|
|
{
|
|
TextWindow.AdvanceChar();
|
|
flag6 = true;
|
|
c2 = TextWindow.PeekChar();
|
|
if ((c2 == 'U' || c2 == 'u') ? true : false)
|
|
{
|
|
TextWindow.AdvanceChar();
|
|
flag5 = true;
|
|
}
|
|
}
|
|
else if (c == 'u' || c == 'U')
|
|
{
|
|
flag5 = true;
|
|
TextWindow.AdvanceChar();
|
|
c2 = TextWindow.PeekChar();
|
|
if ((c2 == 'L' || c2 == 'l') ? true : false)
|
|
{
|
|
TextWindow.AdvanceChar();
|
|
flag6 = true;
|
|
}
|
|
}
|
|
}
|
|
if (underscoreInWrongPlace)
|
|
{
|
|
AddError(MakeError(position, TextWindow.Position - position, ErrorCode.ERR_InvalidNumber));
|
|
}
|
|
else if (firstCharWasUnderscore)
|
|
{
|
|
CheckFeatureAvailability(MessageID.IDS_FeatureLeadingDigitSeparator);
|
|
}
|
|
else if (usedUnderscore)
|
|
{
|
|
CheckFeatureAvailability(MessageID.IDS_FeatureDigitSeparator);
|
|
}
|
|
info.Kind = SyntaxKind.NumericLiteralToken;
|
|
info.Text = TextWindow.GetText(intern: true);
|
|
string text = TextWindow.Intern(_builder);
|
|
SpecialType valueKind = info.ValueKind;
|
|
switch (valueKind - 17)
|
|
{
|
|
case 1:
|
|
info.FloatValue = GetValueSingle(text);
|
|
break;
|
|
case 2:
|
|
info.DoubleValue = GetValueDouble(text);
|
|
break;
|
|
case 0:
|
|
info.DecimalValue = GetValueDecimal(text, position, TextWindow.Position);
|
|
break;
|
|
default:
|
|
{
|
|
ulong num;
|
|
if (string.IsNullOrEmpty(text))
|
|
{
|
|
if (!underscoreInWrongPlace)
|
|
{
|
|
AddError(AbstractLexer.MakeError(ErrorCode.ERR_InvalidNumber));
|
|
}
|
|
num = 0uL;
|
|
}
|
|
else
|
|
{
|
|
num = GetValueUInt64(text, flag, flag2);
|
|
}
|
|
if (!flag5 && !flag6)
|
|
{
|
|
if (num <= int.MaxValue)
|
|
{
|
|
info.ValueKind = (SpecialType)13;
|
|
info.IntValue = (int)num;
|
|
}
|
|
else if (num <= uint.MaxValue)
|
|
{
|
|
info.ValueKind = (SpecialType)14;
|
|
info.UintValue = (uint)num;
|
|
}
|
|
else if (num <= long.MaxValue)
|
|
{
|
|
info.ValueKind = (SpecialType)15;
|
|
info.LongValue = (long)num;
|
|
}
|
|
else
|
|
{
|
|
info.ValueKind = (SpecialType)16;
|
|
info.UlongValue = num;
|
|
}
|
|
}
|
|
else if (flag5 && !flag6)
|
|
{
|
|
if (num <= uint.MaxValue)
|
|
{
|
|
info.ValueKind = (SpecialType)14;
|
|
info.UintValue = (uint)num;
|
|
}
|
|
else
|
|
{
|
|
info.ValueKind = (SpecialType)16;
|
|
info.UlongValue = num;
|
|
}
|
|
}
|
|
else if (!flag5 && flag6)
|
|
{
|
|
if (num <= long.MaxValue)
|
|
{
|
|
info.ValueKind = (SpecialType)15;
|
|
info.LongValue = (long)num;
|
|
}
|
|
else
|
|
{
|
|
info.ValueKind = (SpecialType)16;
|
|
info.UlongValue = num;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
info.ValueKind = (SpecialType)16;
|
|
info.UlongValue = num;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
private static bool TryParseBinaryUInt64(string text, out ulong value)
|
|
{
|
|
value = 0uL;
|
|
foreach (char c in text)
|
|
{
|
|
if ((value & 0x8000000000000000uL) != 0L)
|
|
{
|
|
return false;
|
|
}
|
|
ulong num = (ulong)SyntaxFacts.BinaryValue(c);
|
|
value = (value << 1) | num;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
private int GetValueInt32(string text, bool isHex)
|
|
{
|
|
if (!int.TryParse(text, isHex ? NumberStyles.AllowHexSpecifier : NumberStyles.None, CultureInfo.InvariantCulture, out var result))
|
|
{
|
|
AddError(AbstractLexer.MakeError(ErrorCode.ERR_IntOverflow));
|
|
}
|
|
return result;
|
|
}
|
|
|
|
private ulong GetValueUInt64(string text, bool isHex, bool isBinary)
|
|
{
|
|
ulong result;
|
|
if (isBinary)
|
|
{
|
|
if (!TryParseBinaryUInt64(text, out result))
|
|
{
|
|
AddError(AbstractLexer.MakeError(ErrorCode.ERR_IntOverflow));
|
|
}
|
|
}
|
|
else if (!ulong.TryParse(text, isHex ? NumberStyles.AllowHexSpecifier : NumberStyles.None, CultureInfo.InvariantCulture, out result))
|
|
{
|
|
AddError(AbstractLexer.MakeError(ErrorCode.ERR_IntOverflow));
|
|
}
|
|
return result;
|
|
}
|
|
|
|
private double GetValueDouble(string text)
|
|
{
|
|
double result = default(double);
|
|
if (!RealParser.TryParseDouble(text, ref result))
|
|
{
|
|
AddError(AbstractLexer.MakeError(ErrorCode.ERR_FloatOverflow, "double"));
|
|
}
|
|
return result;
|
|
}
|
|
|
|
private float GetValueSingle(string text)
|
|
{
|
|
float result = default(float);
|
|
if (!RealParser.TryParseFloat(text, ref result))
|
|
{
|
|
AddError(AbstractLexer.MakeError(ErrorCode.ERR_FloatOverflow, "float"));
|
|
}
|
|
return result;
|
|
}
|
|
|
|
private decimal GetValueDecimal(string text, int start, int end)
|
|
{
|
|
if (!decimal.TryParse(text, NumberStyles.AllowDecimalPoint | NumberStyles.AllowExponent, CultureInfo.InvariantCulture, out var result))
|
|
{
|
|
AddError(MakeError(start, end - start, ErrorCode.ERR_FloatOverflow, "decimal"));
|
|
}
|
|
return result;
|
|
}
|
|
|
|
private void ResetIdentBuffer()
|
|
{
|
|
_identLen = 0;
|
|
}
|
|
|
|
private void AddIdentChar(char ch)
|
|
{
|
|
if (_identLen >= _identBuffer.Length)
|
|
{
|
|
GrowIdentBuffer();
|
|
}
|
|
_identBuffer[_identLen++] = ch;
|
|
}
|
|
|
|
private void GrowIdentBuffer()
|
|
{
|
|
char[] array = new char[_identBuffer.Length * 2];
|
|
Array.Copy(_identBuffer, array, _identBuffer.Length);
|
|
_identBuffer = array;
|
|
}
|
|
|
|
private bool ScanIdentifier(ref TokenInfo info)
|
|
{
|
|
if (!ScanIdentifier_FastPath(ref info))
|
|
{
|
|
if (!InXmlCrefOrNameAttributeValue)
|
|
{
|
|
return ScanIdentifier_SlowPath(ref info);
|
|
}
|
|
return ScanIdentifier_CrefSlowPath(ref info);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
private bool ScanIdentifier_FastPath(ref TokenInfo info)
|
|
{
|
|
if ((_mode & LexerMode.MaskLexMode) == LexerMode.DebuggerSyntax)
|
|
{
|
|
return false;
|
|
}
|
|
int i = TextWindow.Offset;
|
|
char[] characterWindow = TextWindow.CharacterWindow;
|
|
int characterWindowCount = TextWindow.CharacterWindowCount;
|
|
int num = i;
|
|
for (; i != characterWindowCount; i++)
|
|
{
|
|
switch (characterWindow[i])
|
|
{
|
|
case '&':
|
|
if (InXmlCrefOrNameAttributeValue)
|
|
{
|
|
return false;
|
|
}
|
|
goto case '\0';
|
|
case '\0':
|
|
case '\t':
|
|
case '\n':
|
|
case '\r':
|
|
case ' ':
|
|
case '!':
|
|
case '"':
|
|
case '%':
|
|
case '\'':
|
|
case '(':
|
|
case ')':
|
|
case '*':
|
|
case '+':
|
|
case ',':
|
|
case '-':
|
|
case '.':
|
|
case '/':
|
|
case ':':
|
|
case ';':
|
|
case '<':
|
|
case '=':
|
|
case '>':
|
|
case '?':
|
|
case '[':
|
|
case ']':
|
|
case '^':
|
|
case '{':
|
|
case '|':
|
|
case '}':
|
|
case '~':
|
|
{
|
|
int num2 = i - num;
|
|
TextWindow.AdvanceChar(num2);
|
|
info.Text = (info.StringValue = TextWindow.Intern(characterWindow, num, num2));
|
|
info.IsVerbatim = false;
|
|
return true;
|
|
}
|
|
case '0':
|
|
case '1':
|
|
case '2':
|
|
case '3':
|
|
case '4':
|
|
case '5':
|
|
case '6':
|
|
case '7':
|
|
case '8':
|
|
case '9':
|
|
if (i == num)
|
|
{
|
|
return false;
|
|
}
|
|
break;
|
|
case 'A':
|
|
case 'B':
|
|
case 'C':
|
|
case 'D':
|
|
case 'E':
|
|
case 'F':
|
|
case 'G':
|
|
case 'H':
|
|
case 'I':
|
|
case 'J':
|
|
case 'K':
|
|
case 'L':
|
|
case 'M':
|
|
case 'N':
|
|
case 'O':
|
|
case 'P':
|
|
case 'Q':
|
|
case 'R':
|
|
case 'S':
|
|
case 'T':
|
|
case 'U':
|
|
case 'V':
|
|
case 'W':
|
|
case 'X':
|
|
case 'Y':
|
|
case 'Z':
|
|
case '_':
|
|
case 'a':
|
|
case 'b':
|
|
case 'c':
|
|
case 'd':
|
|
case 'e':
|
|
case 'f':
|
|
case 'g':
|
|
case 'h':
|
|
case 'i':
|
|
case 'j':
|
|
case 'k':
|
|
case 'l':
|
|
case 'm':
|
|
case 'n':
|
|
case 'o':
|
|
case 'p':
|
|
case 'q':
|
|
case 'r':
|
|
case 's':
|
|
case 't':
|
|
case 'u':
|
|
case 'v':
|
|
case 'w':
|
|
case 'x':
|
|
case 'y':
|
|
case 'z':
|
|
break;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
private bool ScanIdentifier_SlowPath(ref TokenInfo info)
|
|
{
|
|
int position = TextWindow.Position;
|
|
ResetIdentBuffer();
|
|
while (TextWindow.PeekChar() == '@')
|
|
{
|
|
TextWindow.AdvanceChar();
|
|
}
|
|
int num = TextWindow.Position - position;
|
|
info.IsVerbatim = num > 0;
|
|
bool flag = false;
|
|
while (true)
|
|
{
|
|
char surrogateCharacter = '\uffff';
|
|
bool flag2 = false;
|
|
char c = TextWindow.PeekChar();
|
|
while (true)
|
|
{
|
|
switch (c)
|
|
{
|
|
case '\\':
|
|
if (!flag2 && IsUnicodeEscape())
|
|
{
|
|
goto IL_0133;
|
|
}
|
|
goto default;
|
|
case '$':
|
|
if (ModeIs(LexerMode.DebuggerSyntax) && _identLen <= 0)
|
|
{
|
|
goto case 'A';
|
|
}
|
|
goto case '\t';
|
|
case '\uffff':
|
|
if (!TextWindow.IsReallyAtEnd())
|
|
{
|
|
goto default;
|
|
}
|
|
goto case '\t';
|
|
case '0':
|
|
if (_identLen == 0)
|
|
{
|
|
if (!info.IsVerbatim || !ModeIs(LexerMode.DebuggerSyntax) || char.ToLower(TextWindow.PeekChar(1)) != 'x')
|
|
{
|
|
goto case '\t';
|
|
}
|
|
flag = true;
|
|
}
|
|
goto case 'A';
|
|
case '1':
|
|
case '2':
|
|
case '3':
|
|
case '4':
|
|
case '5':
|
|
case '6':
|
|
case '7':
|
|
case '8':
|
|
case '9':
|
|
if (_identLen != 0)
|
|
{
|
|
goto case 'A';
|
|
}
|
|
goto case '\t';
|
|
case '<':
|
|
if (_identLen == 0 && ModeIs(LexerMode.DebuggerSyntax) && TextWindow.PeekChar(1) == '>')
|
|
{
|
|
TextWindow.AdvanceChar(2);
|
|
AddIdentChar('<');
|
|
AddIdentChar('>');
|
|
break;
|
|
}
|
|
goto case '\t';
|
|
default:
|
|
if (_identLen != 0 || c <= '\u007f' || !SyntaxFacts.IsIdentifierStartCharacter(c))
|
|
{
|
|
if (_identLen <= 0 || c <= '\u007f' || !SyntaxFacts.IsIdentifierPartCharacter(c))
|
|
{
|
|
goto case '\t';
|
|
}
|
|
if (UnicodeCharacterUtilities.IsFormattingChar(c))
|
|
{
|
|
if (flag2)
|
|
{
|
|
NextCharOrUnicodeEscape(out surrogateCharacter, out SyntaxDiagnosticInfo info3);
|
|
AddError(info3);
|
|
}
|
|
else
|
|
{
|
|
TextWindow.AdvanceChar();
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
goto case 'A';
|
|
case 'A':
|
|
case 'B':
|
|
case 'C':
|
|
case 'D':
|
|
case 'E':
|
|
case 'F':
|
|
case 'G':
|
|
case 'H':
|
|
case 'I':
|
|
case 'J':
|
|
case 'K':
|
|
case 'L':
|
|
case 'M':
|
|
case 'N':
|
|
case 'O':
|
|
case 'P':
|
|
case 'Q':
|
|
case 'R':
|
|
case 'S':
|
|
case 'T':
|
|
case 'U':
|
|
case 'V':
|
|
case 'W':
|
|
case 'X':
|
|
case 'Y':
|
|
case 'Z':
|
|
case '_':
|
|
case 'a':
|
|
case 'b':
|
|
case 'c':
|
|
case 'd':
|
|
case 'e':
|
|
case 'f':
|
|
case 'g':
|
|
case 'h':
|
|
case 'i':
|
|
case 'j':
|
|
case 'k':
|
|
case 'l':
|
|
case 'm':
|
|
case 'n':
|
|
case 'o':
|
|
case 'p':
|
|
case 'q':
|
|
case 'r':
|
|
case 's':
|
|
case 't':
|
|
case 'u':
|
|
case 'v':
|
|
case 'w':
|
|
case 'x':
|
|
case 'y':
|
|
case 'z':
|
|
if (flag2)
|
|
{
|
|
NextCharOrUnicodeEscape(out surrogateCharacter, out SyntaxDiagnosticInfo info2);
|
|
AddError(info2);
|
|
}
|
|
else
|
|
{
|
|
TextWindow.AdvanceChar();
|
|
}
|
|
AddIdentChar(c);
|
|
if (surrogateCharacter != '\uffff')
|
|
{
|
|
AddIdentChar(surrogateCharacter);
|
|
}
|
|
break;
|
|
case '\t':
|
|
case ' ':
|
|
case '(':
|
|
case ')':
|
|
case ',':
|
|
case '.':
|
|
case ';':
|
|
{
|
|
int width = TextWindow.Width;
|
|
if (_identLen > 0)
|
|
{
|
|
info.Text = TextWindow.GetInternedText();
|
|
if (_identLen == width)
|
|
{
|
|
info.StringValue = info.Text;
|
|
}
|
|
else
|
|
{
|
|
info.StringValue = TextWindow.Intern(_identBuffer, 0, _identLen);
|
|
}
|
|
if (flag)
|
|
{
|
|
string text = TextWindow.Intern(_identBuffer, 2, _identLen - 2);
|
|
if (text.Length == 0 || !StringExtensions.All(text, (Predicate<char>)SyntaxFacts.IsHexDigit))
|
|
{
|
|
goto IL_0391;
|
|
}
|
|
GetValueUInt64(text, isHex: true, isBinary: false);
|
|
}
|
|
if (num >= 2)
|
|
{
|
|
AddError(position, num, ErrorCode.ERR_IllegalAtSequence);
|
|
}
|
|
return true;
|
|
}
|
|
goto IL_0391;
|
|
}
|
|
IL_0391:
|
|
info.Text = null;
|
|
info.StringValue = null;
|
|
TextWindow.Reset(position);
|
|
return false;
|
|
}
|
|
break;
|
|
IL_0133:
|
|
info.HasIdentifierEscapeSequence = true;
|
|
flag2 = true;
|
|
c = PeekUnicodeEscape(out surrogateCharacter);
|
|
}
|
|
}
|
|
}
|
|
|
|
private bool ScanIdentifier_CrefSlowPath(ref TokenInfo info)
|
|
{
|
|
int position = TextWindow.Position;
|
|
ResetIdentBuffer();
|
|
if (AdvanceIfMatches('@'))
|
|
{
|
|
if (InXmlNameAttributeValue)
|
|
{
|
|
AddIdentChar('@');
|
|
}
|
|
else
|
|
{
|
|
info.IsVerbatim = true;
|
|
}
|
|
}
|
|
while (true)
|
|
{
|
|
int position2 = TextWindow.Position;
|
|
char ch;
|
|
char surrogate;
|
|
if (TextWindow.PeekChar() == '&')
|
|
{
|
|
if (!TryScanXmlEntity(out ch, out surrogate))
|
|
{
|
|
TextWindow.Reset(position2);
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ch = TextWindow.NextChar();
|
|
surrogate = '\uffff';
|
|
}
|
|
bool flag = false;
|
|
while (true)
|
|
{
|
|
switch (ch)
|
|
{
|
|
case '\\':
|
|
{
|
|
bool flag2 = !flag && TextWindow.Position == position2 + 1;
|
|
if (flag2)
|
|
{
|
|
char c = TextWindow.PeekChar();
|
|
bool flag3 = ((c == 'U' || c == 'u') ? true : false);
|
|
flag2 = flag3;
|
|
}
|
|
if (flag2)
|
|
{
|
|
info.HasIdentifierEscapeSequence = true;
|
|
TextWindow.Reset(position2);
|
|
flag = true;
|
|
ch = NextUnicodeEscape(out surrogate, out SyntaxDiagnosticInfo info2);
|
|
AddCrefError((DiagnosticInfo?)(object)info2);
|
|
continue;
|
|
}
|
|
goto IL_01e5;
|
|
}
|
|
case '0':
|
|
case '1':
|
|
case '2':
|
|
case '3':
|
|
case '4':
|
|
case '5':
|
|
case '6':
|
|
case '7':
|
|
case '8':
|
|
case '9':
|
|
break;
|
|
case '\t':
|
|
case ' ':
|
|
case '$':
|
|
case '(':
|
|
case ')':
|
|
case ',':
|
|
case '.':
|
|
case ';':
|
|
case '<':
|
|
goto IL_01bc;
|
|
case '\uffff':
|
|
goto IL_01ca;
|
|
default:
|
|
goto IL_01e5;
|
|
case 'A':
|
|
case 'B':
|
|
case 'C':
|
|
case 'D':
|
|
case 'E':
|
|
case 'F':
|
|
case 'G':
|
|
case 'H':
|
|
case 'I':
|
|
case 'J':
|
|
case 'K':
|
|
case 'L':
|
|
case 'M':
|
|
case 'N':
|
|
case 'O':
|
|
case 'P':
|
|
case 'Q':
|
|
case 'R':
|
|
case 'S':
|
|
case 'T':
|
|
case 'U':
|
|
case 'V':
|
|
case 'W':
|
|
case 'X':
|
|
case 'Y':
|
|
case 'Z':
|
|
case '_':
|
|
case 'a':
|
|
case 'b':
|
|
case 'c':
|
|
case 'd':
|
|
case 'e':
|
|
case 'f':
|
|
case 'g':
|
|
case 'h':
|
|
case 'i':
|
|
case 'j':
|
|
case 'k':
|
|
case 'l':
|
|
case 'm':
|
|
case 'n':
|
|
case 'o':
|
|
case 'p':
|
|
case 'q':
|
|
case 'r':
|
|
case 's':
|
|
case 't':
|
|
case 'u':
|
|
case 'v':
|
|
case 'w':
|
|
case 'x':
|
|
case 'y':
|
|
case 'z':
|
|
goto IL_022b;
|
|
}
|
|
break;
|
|
}
|
|
if (_identLen == 0)
|
|
{
|
|
TextWindow.Reset(position2);
|
|
break;
|
|
}
|
|
goto IL_022b;
|
|
IL_01ca:
|
|
if (TextWindow.IsReallyAtEnd())
|
|
{
|
|
TextWindow.Reset(position2);
|
|
break;
|
|
}
|
|
goto IL_01e5;
|
|
IL_01bc:
|
|
TextWindow.Reset(position2);
|
|
break;
|
|
IL_022b:
|
|
AddIdentChar(ch);
|
|
if (surrogate != '\uffff')
|
|
{
|
|
AddIdentChar(surrogate);
|
|
}
|
|
continue;
|
|
IL_01e5:
|
|
if (_identLen != 0 || ch <= '\u007f' || !SyntaxFacts.IsIdentifierStartCharacter(ch))
|
|
{
|
|
if (_identLen <= 0 || ch <= '\u007f' || !SyntaxFacts.IsIdentifierPartCharacter(ch))
|
|
{
|
|
TextWindow.Reset(position2);
|
|
break;
|
|
}
|
|
if (UnicodeCharacterUtilities.IsFormattingChar(ch))
|
|
{
|
|
continue;
|
|
}
|
|
}
|
|
goto IL_022b;
|
|
}
|
|
if (_identLen > 0)
|
|
{
|
|
int width = TextWindow.Width;
|
|
if (_identLen == width)
|
|
{
|
|
info.StringValue = TextWindow.GetInternedText();
|
|
info.Text = info.StringValue;
|
|
}
|
|
else
|
|
{
|
|
info.StringValue = TextWindow.Intern(_identBuffer, 0, _identLen);
|
|
info.Text = TextWindow.GetText(intern: false);
|
|
}
|
|
return true;
|
|
}
|
|
info.Text = null;
|
|
info.StringValue = null;
|
|
TextWindow.Reset(position);
|
|
return false;
|
|
}
|
|
|
|
private bool ScanIdentifierOrKeyword(ref TokenInfo info)
|
|
{
|
|
info.ContextualKind = SyntaxKind.None;
|
|
if (ScanIdentifier(ref info))
|
|
{
|
|
if (!info.IsVerbatim && !info.HasIdentifierEscapeSequence)
|
|
{
|
|
if (ModeIs(LexerMode.Directive))
|
|
{
|
|
SyntaxKind preprocessorKeywordKind = SyntaxFacts.GetPreprocessorKeywordKind(info.Text);
|
|
if (SyntaxFacts.IsPreprocessorContextualKeyword(preprocessorKeywordKind))
|
|
{
|
|
info.Kind = SyntaxKind.IdentifierToken;
|
|
info.ContextualKind = preprocessorKeywordKind;
|
|
}
|
|
else
|
|
{
|
|
info.Kind = preprocessorKeywordKind;
|
|
}
|
|
}
|
|
else if (!_cache.TryGetKeywordKind(info.Text, out info.Kind))
|
|
{
|
|
info.ContextualKind = (info.Kind = SyntaxKind.IdentifierToken);
|
|
}
|
|
else if (SyntaxFacts.IsContextualKeyword(info.Kind))
|
|
{
|
|
info.ContextualKind = info.Kind;
|
|
info.Kind = SyntaxKind.IdentifierToken;
|
|
}
|
|
if (info.Kind == SyntaxKind.None)
|
|
{
|
|
info.Kind = SyntaxKind.IdentifierToken;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
info.ContextualKind = (info.Kind = SyntaxKind.IdentifierToken);
|
|
}
|
|
return true;
|
|
}
|
|
info.Kind = SyntaxKind.None;
|
|
return false;
|
|
}
|
|
|
|
private void LexSyntaxTrivia(bool afterFirstToken, bool isTrailing, ref SyntaxListBuilder triviaList)
|
|
{
|
|
bool flag = !isTrailing;
|
|
while (true)
|
|
{
|
|
Start();
|
|
char c = TextWindow.PeekChar();
|
|
if (c == ' ')
|
|
{
|
|
AddTrivia(ScanWhitespace(), ref triviaList);
|
|
continue;
|
|
}
|
|
if (c > '\u007f')
|
|
{
|
|
if (SyntaxFacts.IsWhitespace(c))
|
|
{
|
|
c = ' ';
|
|
}
|
|
else if (SyntaxFacts.IsNewLine(c))
|
|
{
|
|
c = '\n';
|
|
}
|
|
}
|
|
switch (c)
|
|
{
|
|
default:
|
|
return;
|
|
case '\t':
|
|
case '\v':
|
|
case '\f':
|
|
case '\u001a':
|
|
case ' ':
|
|
AddTrivia(ScanWhitespace(), ref triviaList);
|
|
break;
|
|
case '/':
|
|
{
|
|
if ((c = TextWindow.PeekChar(1)) == '/')
|
|
{
|
|
if (!SuppressDocumentationCommentParse && TextWindow.PeekChar(2) == '/' && TextWindow.PeekChar(3) != '/')
|
|
{
|
|
if (isTrailing)
|
|
{
|
|
return;
|
|
}
|
|
AddTrivia(LexXmlDocComment(XmlDocCommentStyle.SingleLine), ref triviaList);
|
|
}
|
|
else
|
|
{
|
|
ScanToEndOfLine();
|
|
string text = TextWindow.GetText(intern: false);
|
|
AddTrivia(SyntaxFactory.Comment(text), ref triviaList);
|
|
flag = false;
|
|
}
|
|
break;
|
|
}
|
|
if (c != '*')
|
|
{
|
|
return;
|
|
}
|
|
if (!SuppressDocumentationCommentParse && TextWindow.PeekChar(2) == '*' && TextWindow.PeekChar(3) != '*' && TextWindow.PeekChar(3) != '/')
|
|
{
|
|
if (isTrailing)
|
|
{
|
|
return;
|
|
}
|
|
AddTrivia(LexXmlDocComment(XmlDocCommentStyle.Delimited), ref triviaList);
|
|
break;
|
|
}
|
|
ScanMultiLineComment(out var isTerminated);
|
|
if (!isTerminated)
|
|
{
|
|
AddError(ErrorCode.ERR_OpenEndedComment);
|
|
}
|
|
string text2 = TextWindow.GetText(intern: false);
|
|
AddTrivia(SyntaxFactory.Comment(text2), ref triviaList);
|
|
flag = false;
|
|
break;
|
|
}
|
|
case '\n':
|
|
case '\r':
|
|
{
|
|
CSharpSyntaxNode trivia = ScanEndOfLine();
|
|
AddTrivia(trivia, ref triviaList);
|
|
if (isTrailing)
|
|
{
|
|
return;
|
|
}
|
|
flag = true;
|
|
break;
|
|
}
|
|
case '#':
|
|
if (_allowPreprocessorDirectives)
|
|
{
|
|
LexDirectiveAndExcludedTrivia(afterFirstToken, isTrailing || !flag, ref triviaList);
|
|
break;
|
|
}
|
|
return;
|
|
case '<':
|
|
case '=':
|
|
case '|':
|
|
if (!isTrailing && IsConflictMarkerTrivia())
|
|
{
|
|
LexConflictMarkerTrivia(ref triviaList);
|
|
break;
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
private bool IsConflictMarkerTrivia()
|
|
{
|
|
int position = TextWindow.Position;
|
|
SourceText text = TextWindow.Text;
|
|
if (position == 0 || SyntaxFacts.IsNewLine(text[position - 1]))
|
|
{
|
|
char c = text[position];
|
|
if (position + s_conflictMarkerLength <= text.Length)
|
|
{
|
|
int i = 0;
|
|
for (int num = s_conflictMarkerLength; i < num; i++)
|
|
{
|
|
if (text[position + i] != c)
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
if ((c == '=' || c == '|') ? true : false)
|
|
{
|
|
return true;
|
|
}
|
|
if (position + s_conflictMarkerLength < text.Length)
|
|
{
|
|
return text[position + s_conflictMarkerLength] == ' ';
|
|
}
|
|
return false;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
private void LexConflictMarkerTrivia(ref SyntaxListBuilder triviaList)
|
|
{
|
|
Start();
|
|
AddError(TextWindow.Position, s_conflictMarkerLength, ErrorCode.ERR_Merge_conflict_marker_encountered);
|
|
char c = TextWindow.PeekChar();
|
|
LexConflictMarkerHeader(ref triviaList);
|
|
LexConflictMarkerEndOfLine(ref triviaList);
|
|
if ((c == '=' || c == '|') ? true : false)
|
|
{
|
|
LexConflictMarkerDisabledText(c == '=', ref triviaList);
|
|
}
|
|
}
|
|
|
|
private SyntaxListBuilder LexConflictMarkerDisabledText(bool atSecondMiddleMarker, ref SyntaxListBuilder triviaList)
|
|
{
|
|
Start();
|
|
bool flag = false;
|
|
while (true)
|
|
{
|
|
char c = TextWindow.PeekChar();
|
|
if (c == '\uffff')
|
|
{
|
|
break;
|
|
}
|
|
if (!atSecondMiddleMarker && c == '=' && IsConflictMarkerTrivia())
|
|
{
|
|
flag = true;
|
|
break;
|
|
}
|
|
if (c == '>' && IsConflictMarkerTrivia())
|
|
{
|
|
flag = true;
|
|
break;
|
|
}
|
|
TextWindow.AdvanceChar();
|
|
}
|
|
if (TextWindow.Width > 0)
|
|
{
|
|
AddTrivia(SyntaxFactory.DisabledText(TextWindow.GetText(intern: false)), ref triviaList);
|
|
}
|
|
if (flag)
|
|
{
|
|
LexConflictMarkerTrivia(ref triviaList);
|
|
}
|
|
return triviaList;
|
|
}
|
|
|
|
private void LexConflictMarkerEndOfLine(ref SyntaxListBuilder triviaList)
|
|
{
|
|
Start();
|
|
while (SyntaxFacts.IsNewLine(TextWindow.PeekChar()))
|
|
{
|
|
TextWindow.AdvanceChar();
|
|
}
|
|
if (TextWindow.Width > 0)
|
|
{
|
|
AddTrivia(SyntaxFactory.EndOfLine(TextWindow.GetText(intern: false)), ref triviaList);
|
|
}
|
|
}
|
|
|
|
private void LexConflictMarkerHeader(ref SyntaxListBuilder triviaList)
|
|
{
|
|
while (true)
|
|
{
|
|
char c = TextWindow.PeekChar();
|
|
if (c == '\uffff' || SyntaxFacts.IsNewLine(c))
|
|
{
|
|
break;
|
|
}
|
|
TextWindow.AdvanceChar();
|
|
}
|
|
AddTrivia(SyntaxFactory.ConflictMarker(TextWindow.GetText(intern: false)), ref triviaList);
|
|
}
|
|
|
|
private void AddTrivia(CSharpSyntaxNode trivia, [NotNull] ref SyntaxListBuilder? list)
|
|
{
|
|
//IL_001f: Unknown result type (might be due to invalid IL or missing references)
|
|
//IL_0025: Expected O, but got Unknown
|
|
if (base.HasErrors)
|
|
{
|
|
CSharpSyntaxNode cSharpSyntaxNode = trivia;
|
|
DiagnosticInfo[] errors = (DiagnosticInfo[])(object)GetErrors(0);
|
|
trivia = GreenNodeExtensions.WithDiagnosticsGreen<CSharpSyntaxNode>(cSharpSyntaxNode, errors);
|
|
}
|
|
if (list == null)
|
|
{
|
|
list = new SyntaxListBuilder(8);
|
|
}
|
|
list.Add((GreenNode)(object)trivia);
|
|
}
|
|
|
|
private bool ScanMultiLineComment(out bool isTerminated)
|
|
{
|
|
if (TextWindow.PeekChar() == '/' && TextWindow.PeekChar(1) == '*')
|
|
{
|
|
TextWindow.AdvanceChar(2);
|
|
while (true)
|
|
{
|
|
char c;
|
|
if ((c = TextWindow.PeekChar()) == '\uffff' && TextWindow.IsReallyAtEnd())
|
|
{
|
|
isTerminated = false;
|
|
break;
|
|
}
|
|
if (c == '*' && TextWindow.PeekChar(1) == '/')
|
|
{
|
|
TextWindow.AdvanceChar(2);
|
|
isTerminated = true;
|
|
break;
|
|
}
|
|
TextWindow.AdvanceChar();
|
|
}
|
|
return true;
|
|
}
|
|
isTerminated = false;
|
|
return false;
|
|
}
|
|
|
|
private void ScanToEndOfLine()
|
|
{
|
|
char c;
|
|
while (!SyntaxFacts.IsNewLine(c = TextWindow.PeekChar()) && (c != '\uffff' || !TextWindow.IsReallyAtEnd()))
|
|
{
|
|
TextWindow.AdvanceChar();
|
|
}
|
|
}
|
|
|
|
private CSharpSyntaxNode? ScanEndOfLine()
|
|
{
|
|
char ch;
|
|
switch (ch = TextWindow.PeekChar())
|
|
{
|
|
case '\r':
|
|
TextWindow.AdvanceChar();
|
|
if (!TextWindow.TryAdvance('\n'))
|
|
{
|
|
return SyntaxFactory.CarriageReturn;
|
|
}
|
|
return SyntaxFactory.CarriageReturnLineFeed;
|
|
case '\n':
|
|
TextWindow.AdvanceChar();
|
|
return SyntaxFactory.LineFeed;
|
|
default:
|
|
if (SyntaxFacts.IsNewLine(ch))
|
|
{
|
|
TextWindow.AdvanceChar();
|
|
return SyntaxFactory.EndOfLine(ch.ToString());
|
|
}
|
|
return null;
|
|
}
|
|
}
|
|
|
|
private SyntaxTrivia ScanWhitespace()
|
|
{
|
|
if (_createWhitespaceTriviaFunction == null)
|
|
{
|
|
_createWhitespaceTriviaFunction = CreateWhitespaceTrivia;
|
|
}
|
|
int num = -2128831035;
|
|
bool flag = true;
|
|
while (true)
|
|
{
|
|
char c = TextWindow.PeekChar();
|
|
switch (c)
|
|
{
|
|
default:
|
|
if (c != '\u001a')
|
|
{
|
|
if (c == ' ')
|
|
{
|
|
goto IL_0059;
|
|
}
|
|
if (c <= '\u007f' || !SyntaxFacts.IsWhitespace(c))
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
goto case '\t';
|
|
case '\t':
|
|
case '\v':
|
|
case '\f':
|
|
flag = false;
|
|
goto IL_0059;
|
|
case '\n':
|
|
case '\r':
|
|
break;
|
|
}
|
|
break;
|
|
IL_0059:
|
|
TextWindow.AdvanceChar();
|
|
num = Hash.CombineFNVHash(num, c);
|
|
}
|
|
if (TextWindow.Width == 1 && flag)
|
|
{
|
|
return SyntaxFactory.Space;
|
|
}
|
|
int width = TextWindow.Width;
|
|
if (width < 42)
|
|
{
|
|
return _cache.LookupTrivia(TextWindow.CharacterWindow, TextWindow.LexemeRelativeStart, width, num, _createWhitespaceTriviaFunction);
|
|
}
|
|
return _createWhitespaceTriviaFunction();
|
|
}
|
|
|
|
private SyntaxTrivia CreateWhitespaceTrivia()
|
|
{
|
|
return SyntaxFactory.Whitespace(TextWindow.GetText(intern: true));
|
|
}
|
|
|
|
private void LexDirectiveAndExcludedTrivia(bool afterFirstToken, bool afterNonWhitespaceOnLine, ref SyntaxListBuilder triviaList)
|
|
{
|
|
if (LexSingleDirective(isActive: true, endIsActive: true, afterFirstToken, afterNonWhitespaceOnLine, ref triviaList) is BranchingDirectiveTriviaSyntax { BranchTaken: false })
|
|
{
|
|
LexExcludedDirectivesAndTrivia(endIsActive: true, ref triviaList);
|
|
}
|
|
}
|
|
|
|
private void LexExcludedDirectivesAndTrivia(bool endIsActive, ref SyntaxListBuilder triviaList)
|
|
{
|
|
while (true)
|
|
{
|
|
bool followedByDirective;
|
|
CSharpSyntaxNode cSharpSyntaxNode = LexDisabledText(out followedByDirective);
|
|
if (cSharpSyntaxNode != null)
|
|
{
|
|
AddTrivia(cSharpSyntaxNode, ref triviaList);
|
|
}
|
|
if (followedByDirective)
|
|
{
|
|
CSharpSyntaxNode cSharpSyntaxNode2 = LexSingleDirective(isActive: false, endIsActive, afterFirstToken: false, afterNonWhitespaceOnLine: false, ref triviaList);
|
|
BranchingDirectiveTriviaSyntax branchingDirectiveTriviaSyntax = cSharpSyntaxNode2 as BranchingDirectiveTriviaSyntax;
|
|
if (cSharpSyntaxNode2.Kind != SyntaxKind.EndIfDirectiveTrivia && (branchingDirectiveTriviaSyntax == null || !branchingDirectiveTriviaSyntax.BranchTaken))
|
|
{
|
|
if (cSharpSyntaxNode2.Kind == SyntaxKind.IfDirectiveTrivia)
|
|
{
|
|
LexExcludedDirectivesAndTrivia(endIsActive: false, ref triviaList);
|
|
}
|
|
continue;
|
|
}
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
private CSharpSyntaxNode LexSingleDirective(bool isActive, bool endIsActive, bool afterFirstToken, bool afterNonWhitespaceOnLine, ref SyntaxListBuilder triviaList)
|
|
{
|
|
if (SyntaxFacts.IsWhitespace(TextWindow.PeekChar()))
|
|
{
|
|
Start();
|
|
AddTrivia(ScanWhitespace(), ref triviaList);
|
|
}
|
|
LexerMode mode = _mode;
|
|
CSharpSyntaxNode cSharpSyntaxNode;
|
|
using (DirectiveParser directiveParser = new DirectiveParser(this, _directives))
|
|
{
|
|
cSharpSyntaxNode = directiveParser.ParseDirective(isActive, endIsActive, afterFirstToken, afterNonWhitespaceOnLine);
|
|
}
|
|
AddTrivia(cSharpSyntaxNode, ref triviaList);
|
|
_directives = cSharpSyntaxNode.ApplyDirectives(_directives);
|
|
_mode = mode;
|
|
return cSharpSyntaxNode;
|
|
}
|
|
|
|
private CSharpSyntaxNode? LexDisabledText(out bool followedByDirective)
|
|
{
|
|
Start();
|
|
int position = TextWindow.Position;
|
|
int num = 0;
|
|
bool flag = true;
|
|
while (true)
|
|
{
|
|
char c = TextWindow.PeekChar();
|
|
if ((uint)c <= 13u)
|
|
{
|
|
if (c == '\n' || c == '\r')
|
|
{
|
|
goto IL_00cb;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
switch (c)
|
|
{
|
|
case '\uffff':
|
|
if (TextWindow.IsReallyAtEnd())
|
|
{
|
|
followedByDirective = false;
|
|
if (TextWindow.Width <= 0)
|
|
{
|
|
return null;
|
|
}
|
|
return SyntaxFactory.DisabledText(TextWindow.GetText(intern: false));
|
|
}
|
|
break;
|
|
case '#':
|
|
if (!_allowPreprocessorDirectives)
|
|
{
|
|
break;
|
|
}
|
|
followedByDirective = true;
|
|
if (position >= TextWindow.Position || flag)
|
|
{
|
|
TextWindow.Reset(position);
|
|
if (TextWindow.Width <= 0)
|
|
{
|
|
return null;
|
|
}
|
|
return SyntaxFactory.DisabledText(TextWindow.GetText(intern: false));
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
if (!SyntaxFacts.IsNewLine(c))
|
|
{
|
|
flag = flag && SyntaxFacts.IsWhitespace(c);
|
|
TextWindow.AdvanceChar();
|
|
continue;
|
|
}
|
|
goto IL_00cb;
|
|
IL_00cb:
|
|
ScanEndOfLine();
|
|
position = TextWindow.Position;
|
|
flag = true;
|
|
num++;
|
|
}
|
|
}
|
|
|
|
private SyntaxToken LexDirectiveToken()
|
|
{
|
|
Start();
|
|
TokenInfo info = default(TokenInfo);
|
|
ScanDirectiveToken(ref info);
|
|
SyntaxDiagnosticInfo[] errors = GetErrors(0);
|
|
SyntaxListBuilder trailing = LexDirectiveTrailingTrivia(info.Kind == SyntaxKind.EndOfDirectiveToken);
|
|
return Create(in info, null, trailing, errors);
|
|
}
|
|
|
|
public SyntaxToken LexEndOfDirectiveWithOptionalPreprocessingMessage()
|
|
{
|
|
PooledStringBuilder val = null;
|
|
while (true)
|
|
{
|
|
char c = TextWindow.PeekChar();
|
|
if (SyntaxFacts.IsNewLine(c) || (c == '\uffff' && TextWindow.IsReallyAtEnd()))
|
|
{
|
|
break;
|
|
}
|
|
if (val == null)
|
|
{
|
|
val = PooledStringBuilder.GetInstance();
|
|
}
|
|
val.Builder.Append(c);
|
|
TextWindow.AdvanceChar();
|
|
}
|
|
SyntaxTrivia leading = ((val == null) ? null : SyntaxFactory.PreprocessingMessage(val.ToStringAndFree()));
|
|
SyntaxListBuilder? obj = LexDirectiveTrailingTrivia(includeEndOfLine: true);
|
|
GreenNode trailing = ((obj != null) ? obj.ToListNode() : null);
|
|
return SyntaxFactory.Token((GreenNode)(object)leading, SyntaxKind.EndOfDirectiveToken, trailing);
|
|
}
|
|
|
|
private bool ScanDirectiveToken(ref TokenInfo info)
|
|
{
|
|
//IL_028b: Unknown result type (might be due to invalid IL or missing references)
|
|
bool flag = false;
|
|
char ch;
|
|
char surrogateCharacter;
|
|
switch (ch = TextWindow.PeekChar())
|
|
{
|
|
case '\uffff':
|
|
if (TextWindow.IsReallyAtEnd())
|
|
{
|
|
info.Kind = SyntaxKind.EndOfDirectiveToken;
|
|
break;
|
|
}
|
|
goto default;
|
|
case '\n':
|
|
case '\r':
|
|
info.Kind = SyntaxKind.EndOfDirectiveToken;
|
|
break;
|
|
case '#':
|
|
TextWindow.AdvanceChar();
|
|
info.Kind = SyntaxKind.HashToken;
|
|
break;
|
|
case '(':
|
|
TextWindow.AdvanceChar();
|
|
info.Kind = SyntaxKind.OpenParenToken;
|
|
break;
|
|
case ')':
|
|
TextWindow.AdvanceChar();
|
|
info.Kind = SyntaxKind.CloseParenToken;
|
|
break;
|
|
case ',':
|
|
TextWindow.AdvanceChar();
|
|
info.Kind = SyntaxKind.CommaToken;
|
|
break;
|
|
case '-':
|
|
TextWindow.AdvanceChar();
|
|
info.Kind = SyntaxKind.MinusToken;
|
|
break;
|
|
case '!':
|
|
TextWindow.AdvanceChar();
|
|
if (TextWindow.PeekChar() == '=')
|
|
{
|
|
TextWindow.AdvanceChar();
|
|
info.Kind = SyntaxKind.ExclamationEqualsToken;
|
|
}
|
|
else
|
|
{
|
|
info.Kind = SyntaxKind.ExclamationToken;
|
|
}
|
|
break;
|
|
case '=':
|
|
TextWindow.AdvanceChar();
|
|
if (TextWindow.PeekChar() == '=')
|
|
{
|
|
TextWindow.AdvanceChar();
|
|
info.Kind = SyntaxKind.EqualsEqualsToken;
|
|
}
|
|
else
|
|
{
|
|
info.Kind = SyntaxKind.EqualsToken;
|
|
}
|
|
break;
|
|
case '&':
|
|
if (TextWindow.PeekChar(1) == '&')
|
|
{
|
|
TextWindow.AdvanceChar(2);
|
|
info.Kind = SyntaxKind.AmpersandAmpersandToken;
|
|
break;
|
|
}
|
|
goto default;
|
|
case '|':
|
|
if (TextWindow.PeekChar(1) == '|')
|
|
{
|
|
TextWindow.AdvanceChar(2);
|
|
info.Kind = SyntaxKind.BarBarToken;
|
|
break;
|
|
}
|
|
goto default;
|
|
case '0':
|
|
case '1':
|
|
case '2':
|
|
case '3':
|
|
case '4':
|
|
case '5':
|
|
case '6':
|
|
case '7':
|
|
case '8':
|
|
case '9':
|
|
ScanInteger();
|
|
info.Kind = SyntaxKind.NumericLiteralToken;
|
|
info.Text = TextWindow.GetText(intern: true);
|
|
info.ValueKind = (SpecialType)13;
|
|
info.IntValue = GetValueInt32(info.Text, isHex: false);
|
|
break;
|
|
case '"':
|
|
ScanStringLiteral(ref info, inDirective: true);
|
|
break;
|
|
case '\\':
|
|
ch = PeekCharOrUnicodeEscape(out surrogateCharacter);
|
|
flag = true;
|
|
if (SyntaxFacts.IsIdentifierStartCharacter(ch))
|
|
{
|
|
ScanIdentifierOrKeyword(ref info);
|
|
break;
|
|
}
|
|
goto default;
|
|
default:
|
|
if (flag || !SyntaxFacts.IsNewLine(ch))
|
|
{
|
|
if (SyntaxFacts.IsIdentifierStartCharacter(ch))
|
|
{
|
|
ScanIdentifierOrKeyword(ref info);
|
|
break;
|
|
}
|
|
if (flag)
|
|
{
|
|
NextCharOrUnicodeEscape(out surrogateCharacter, out SyntaxDiagnosticInfo info2);
|
|
AddError(info2);
|
|
}
|
|
else
|
|
{
|
|
TextWindow.AdvanceChar();
|
|
}
|
|
info.Kind = SyntaxKind.None;
|
|
info.Text = TextWindow.GetText(intern: true);
|
|
break;
|
|
}
|
|
goto case '\n';
|
|
}
|
|
return info.Kind != SyntaxKind.None;
|
|
}
|
|
|
|
private SyntaxListBuilder? LexDirectiveTrailingTrivia(bool includeEndOfLine)
|
|
{
|
|
SyntaxListBuilder list = null;
|
|
while (true)
|
|
{
|
|
int position = TextWindow.Position;
|
|
CSharpSyntaxNode cSharpSyntaxNode = LexDirectiveTrivia();
|
|
if (cSharpSyntaxNode == null)
|
|
{
|
|
break;
|
|
}
|
|
if (cSharpSyntaxNode.Kind == SyntaxKind.EndOfLineTrivia)
|
|
{
|
|
if (includeEndOfLine)
|
|
{
|
|
AddTrivia(cSharpSyntaxNode, ref list);
|
|
}
|
|
else
|
|
{
|
|
TextWindow.Reset(position);
|
|
}
|
|
break;
|
|
}
|
|
AddTrivia(cSharpSyntaxNode, ref list);
|
|
}
|
|
return list;
|
|
}
|
|
|
|
private CSharpSyntaxNode? LexDirectiveTrivia()
|
|
{
|
|
CSharpSyntaxNode result = null;
|
|
Start();
|
|
char c = TextWindow.PeekChar();
|
|
switch (c)
|
|
{
|
|
case '/':
|
|
if (TextWindow.PeekChar(1) == '/')
|
|
{
|
|
ScanToEndOfLine();
|
|
result = SyntaxFactory.Comment(TextWindow.GetText(intern: false));
|
|
}
|
|
break;
|
|
case '\n':
|
|
case '\r':
|
|
result = ScanEndOfLine();
|
|
break;
|
|
case '\t':
|
|
case '\v':
|
|
case '\f':
|
|
case ' ':
|
|
result = ScanWhitespace();
|
|
break;
|
|
default:
|
|
if (!SyntaxFacts.IsWhitespace(c))
|
|
{
|
|
if (!SyntaxFacts.IsNewLine(c))
|
|
{
|
|
break;
|
|
}
|
|
goto case '\n';
|
|
}
|
|
goto case '\t';
|
|
}
|
|
return result;
|
|
}
|
|
|
|
private CSharpSyntaxNode LexXmlDocComment(XmlDocCommentStyle style)
|
|
{
|
|
LexerMode mode = _mode;
|
|
LexerMode modeflags = ((style != XmlDocCommentStyle.SingleLine) ? LexerMode.XmlDocCommentStyleDelimited : LexerMode.XmlDocCommentLocationStart);
|
|
if (_xmlParser == null)
|
|
{
|
|
_xmlParser = new DocumentationCommentParser(this, modeflags);
|
|
}
|
|
else
|
|
{
|
|
_xmlParser.ReInitialize(modeflags);
|
|
}
|
|
bool isTerminated;
|
|
DocumentationCommentTriviaSyntax result = _xmlParser.ParseDocumentationComment(out isTerminated);
|
|
_mode = mode;
|
|
if (!isTerminated)
|
|
{
|
|
AddError(TextWindow.LexemeStartPosition, TextWindow.Width, ErrorCode.ERR_OpenEndedComment);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
private SyntaxToken LexXmlToken()
|
|
{
|
|
TokenInfo info = default(TokenInfo);
|
|
SyntaxListBuilder trivia = null;
|
|
LexXmlDocCommentLeadingTrivia(ref trivia);
|
|
Start();
|
|
ScanXmlToken(ref info);
|
|
SyntaxDiagnosticInfo[] errors = GetErrors(GetFullWidth(trivia));
|
|
return Create(in info, trivia, null, errors);
|
|
}
|
|
|
|
private bool ScanXmlToken(ref TokenInfo info)
|
|
{
|
|
if (LocationIs(XmlDocCommentLocation.End))
|
|
{
|
|
info.Kind = SyntaxKind.EndOfDocumentationCommentToken;
|
|
return true;
|
|
}
|
|
char ch;
|
|
char c = (ch = TextWindow.PeekChar());
|
|
if ((uint)c <= 13u)
|
|
{
|
|
if (c == '\n' || c == '\r')
|
|
{
|
|
goto IL_0066;
|
|
}
|
|
goto IL_0089;
|
|
}
|
|
if (c != '&')
|
|
{
|
|
if (c != '<')
|
|
{
|
|
if (c != '\uffff' || !TextWindow.IsReallyAtEnd())
|
|
{
|
|
goto IL_0089;
|
|
}
|
|
info.Kind = SyntaxKind.EndOfDocumentationCommentToken;
|
|
}
|
|
else
|
|
{
|
|
ScanXmlTagStart(ref info);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ScanXmlEntity(ref info);
|
|
info.Kind = SyntaxKind.XmlEntityLiteralToken;
|
|
}
|
|
goto IL_00a3;
|
|
IL_0066:
|
|
ScanXmlTextLiteralNewLineToken(ref info);
|
|
goto IL_00a3;
|
|
IL_0089:
|
|
if (SyntaxFacts.IsNewLine(ch))
|
|
{
|
|
goto IL_0066;
|
|
}
|
|
ScanXmlText(ref info);
|
|
info.Kind = SyntaxKind.XmlTextLiteralToken;
|
|
goto IL_00a3;
|
|
IL_00a3:
|
|
return info.Kind != SyntaxKind.None;
|
|
}
|
|
|
|
private void ScanXmlTextLiteralNewLineToken(ref TokenInfo info)
|
|
{
|
|
ScanEndOfLine();
|
|
info.StringValue = (info.Text = TextWindow.GetText(intern: false));
|
|
info.Kind = SyntaxKind.XmlTextLiteralNewLineToken;
|
|
MutateLocation(XmlDocCommentLocation.Exterior);
|
|
}
|
|
|
|
private void ScanXmlTagStart(ref TokenInfo info)
|
|
{
|
|
if (TextWindow.PeekChar(1) == '!')
|
|
{
|
|
if (TextWindow.PeekChar(2) == '-' && TextWindow.PeekChar(3) == '-')
|
|
{
|
|
TextWindow.AdvanceChar(4);
|
|
info.Kind = SyntaxKind.XmlCommentStartToken;
|
|
}
|
|
else if (TextWindow.PeekChar(2) == '[' && TextWindow.PeekChar(3) == 'C' && TextWindow.PeekChar(4) == 'D' && TextWindow.PeekChar(5) == 'A' && TextWindow.PeekChar(6) == 'T' && TextWindow.PeekChar(7) == 'A' && TextWindow.PeekChar(8) == '[')
|
|
{
|
|
TextWindow.AdvanceChar(9);
|
|
info.Kind = SyntaxKind.XmlCDataStartToken;
|
|
}
|
|
else
|
|
{
|
|
TextWindow.AdvanceChar();
|
|
info.Kind = SyntaxKind.LessThanToken;
|
|
}
|
|
}
|
|
else if (TextWindow.PeekChar(1) == '/')
|
|
{
|
|
TextWindow.AdvanceChar(2);
|
|
info.Kind = SyntaxKind.LessThanSlashToken;
|
|
}
|
|
else if (TextWindow.PeekChar(1) == '?')
|
|
{
|
|
TextWindow.AdvanceChar(2);
|
|
info.Kind = SyntaxKind.XmlProcessingInstructionStartToken;
|
|
}
|
|
else
|
|
{
|
|
TextWindow.AdvanceChar();
|
|
info.Kind = SyntaxKind.LessThanToken;
|
|
}
|
|
}
|
|
|
|
private void ScanXmlEntity(ref TokenInfo info)
|
|
{
|
|
info.StringValue = null;
|
|
TextWindow.AdvanceChar();
|
|
_builder.Clear();
|
|
XmlParseErrorCode? xmlParseErrorCode = null;
|
|
object[] array = null;
|
|
char c;
|
|
if (IsXmlNameStartChar(c = TextWindow.PeekChar()))
|
|
{
|
|
while (IsXmlNameChar(c = TextWindow.PeekChar()))
|
|
{
|
|
TextWindow.AdvanceChar();
|
|
_builder.Append(c);
|
|
}
|
|
switch (_builder.ToString())
|
|
{
|
|
case "lt":
|
|
info.StringValue = "<";
|
|
break;
|
|
case "gt":
|
|
info.StringValue = ">";
|
|
break;
|
|
case "amp":
|
|
info.StringValue = "&";
|
|
break;
|
|
case "apos":
|
|
info.StringValue = "'";
|
|
break;
|
|
case "quot":
|
|
info.StringValue = "\"";
|
|
break;
|
|
default:
|
|
{
|
|
xmlParseErrorCode = XmlParseErrorCode.XML_RefUndefinedEntity_1;
|
|
object[] array2 = new string[1] { _builder.ToString() };
|
|
array = array2;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else if (c == '#')
|
|
{
|
|
TextWindow.AdvanceChar();
|
|
bool num = TextWindow.PeekChar() == 'x';
|
|
uint num2 = 0u;
|
|
if (num)
|
|
{
|
|
TextWindow.AdvanceChar();
|
|
while (SyntaxFacts.IsHexDigit(c = TextWindow.PeekChar()))
|
|
{
|
|
TextWindow.AdvanceChar();
|
|
if (num2 <= 134217727)
|
|
{
|
|
num2 = (num2 << 4) + (uint)SyntaxFacts.HexValue(c);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
while (SyntaxFacts.IsDecDigit(c = TextWindow.PeekChar()))
|
|
{
|
|
TextWindow.AdvanceChar();
|
|
if (num2 <= 134217727)
|
|
{
|
|
num2 = (num2 << 3) + (num2 << 1) + (uint)SyntaxFacts.DecValue(c);
|
|
}
|
|
}
|
|
}
|
|
if (TextWindow.PeekChar() != ';')
|
|
{
|
|
xmlParseErrorCode = XmlParseErrorCode.XML_InvalidCharEntity;
|
|
}
|
|
if (MatchesProductionForXmlChar(num2))
|
|
{
|
|
char lowSurrogate;
|
|
char charsFromUtf = SlidingTextWindow.GetCharsFromUtf32(num2, out lowSurrogate);
|
|
_builder.Append(charsFromUtf);
|
|
if (lowSurrogate != '\uffff')
|
|
{
|
|
_builder.Append(lowSurrogate);
|
|
}
|
|
info.StringValue = _builder.ToString();
|
|
}
|
|
else if (!xmlParseErrorCode.HasValue)
|
|
{
|
|
xmlParseErrorCode = XmlParseErrorCode.XML_InvalidUnicodeChar;
|
|
}
|
|
}
|
|
else if (SyntaxFacts.IsWhitespace(c) || SyntaxFacts.IsNewLine(c))
|
|
{
|
|
if (!xmlParseErrorCode.HasValue)
|
|
{
|
|
xmlParseErrorCode = XmlParseErrorCode.XML_InvalidWhitespace;
|
|
}
|
|
}
|
|
else if (!xmlParseErrorCode.HasValue)
|
|
{
|
|
xmlParseErrorCode = XmlParseErrorCode.XML_InvalidToken;
|
|
object[] array2 = new string[1] { c.ToString() };
|
|
array = array2;
|
|
}
|
|
c = TextWindow.PeekChar();
|
|
if (c == ';')
|
|
{
|
|
TextWindow.AdvanceChar();
|
|
}
|
|
else if (!xmlParseErrorCode.HasValue)
|
|
{
|
|
xmlParseErrorCode = XmlParseErrorCode.XML_InvalidToken;
|
|
object[] array2 = new string[1] { c.ToString() };
|
|
array = array2;
|
|
}
|
|
info.Text = TextWindow.GetText(intern: true);
|
|
if (info.StringValue == null)
|
|
{
|
|
info.StringValue = info.Text;
|
|
}
|
|
if (xmlParseErrorCode.HasValue)
|
|
{
|
|
AddError(xmlParseErrorCode.Value, array ?? Array.Empty<object>());
|
|
}
|
|
}
|
|
|
|
private static bool MatchesProductionForXmlChar(uint charValue)
|
|
{
|
|
if (charValue != 9 && charValue != 10 && charValue != 13 && (charValue < 32 || charValue > 55295) && (charValue < 57344 || charValue > 65533))
|
|
{
|
|
if (charValue >= 65536)
|
|
{
|
|
return charValue <= 1114111;
|
|
}
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
private void ScanXmlText(ref TokenInfo info)
|
|
{
|
|
if (TextWindow.PeekChar() == ']' && TextWindow.PeekChar(1) == ']' && TextWindow.PeekChar(2) == '>')
|
|
{
|
|
TextWindow.AdvanceChar(3);
|
|
info.StringValue = (info.Text = TextWindow.GetText(intern: false));
|
|
AddError(XmlParseErrorCode.XML_CDataEndTagNotAllowed);
|
|
return;
|
|
}
|
|
while (true)
|
|
{
|
|
char c = TextWindow.PeekChar();
|
|
if ((uint)c <= 38u)
|
|
{
|
|
if (c == '\n' || c == '\r' || c == '&')
|
|
{
|
|
goto IL_00d7;
|
|
}
|
|
}
|
|
else if ((uint)c <= 60u)
|
|
{
|
|
if (c != '*')
|
|
{
|
|
if (c == '<')
|
|
{
|
|
goto IL_00d7;
|
|
}
|
|
}
|
|
else if (StyleIs(XmlDocCommentStyle.Delimited) && TextWindow.PeekChar(1) == '/')
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
switch (c)
|
|
{
|
|
case '\uffff':
|
|
if (TextWindow.IsReallyAtEnd())
|
|
{
|
|
info.StringValue = (info.Text = TextWindow.GetText(intern: false));
|
|
return;
|
|
}
|
|
break;
|
|
case ']':
|
|
if (TextWindow.PeekChar(1) == ']' && TextWindow.PeekChar(2) == '>')
|
|
{
|
|
info.StringValue = (info.Text = TextWindow.GetText(intern: false));
|
|
return;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
if (!SyntaxFacts.IsNewLine(c))
|
|
{
|
|
TextWindow.AdvanceChar();
|
|
continue;
|
|
}
|
|
goto IL_00d7;
|
|
IL_00d7:
|
|
info.StringValue = (info.Text = TextWindow.GetText(intern: false));
|
|
return;
|
|
}
|
|
info.StringValue = (info.Text = TextWindow.GetText(intern: false));
|
|
}
|
|
|
|
private SyntaxToken LexXmlElementTagToken()
|
|
{
|
|
TokenInfo info = default(TokenInfo);
|
|
SyntaxListBuilder trivia = null;
|
|
LexXmlDocCommentLeadingTriviaWithWhitespace(ref trivia);
|
|
Start();
|
|
ScanXmlElementTagToken(ref info);
|
|
SyntaxDiagnosticInfo[] errors = GetErrors(GetFullWidth(trivia));
|
|
if (errors == null && info.ContextualKind == SyntaxKind.None && info.Kind == SyntaxKind.IdentifierToken)
|
|
{
|
|
SyntaxToken syntaxToken = DocumentationCommentXmlTokens.LookupToken(info.Text, trivia);
|
|
if (syntaxToken != null)
|
|
{
|
|
return syntaxToken;
|
|
}
|
|
}
|
|
return Create(in info, trivia, null, errors);
|
|
}
|
|
|
|
private bool ScanXmlElementTagToken(ref TokenInfo info)
|
|
{
|
|
if (LocationIs(XmlDocCommentLocation.End))
|
|
{
|
|
info.Kind = SyntaxKind.EndOfDocumentationCommentToken;
|
|
return true;
|
|
}
|
|
char ch;
|
|
switch (ch = TextWindow.PeekChar())
|
|
{
|
|
case '<':
|
|
ScanXmlTagStart(ref info);
|
|
break;
|
|
case '>':
|
|
TextWindow.AdvanceChar();
|
|
info.Kind = SyntaxKind.GreaterThanToken;
|
|
break;
|
|
case '/':
|
|
if (TextWindow.PeekChar(1) == '>')
|
|
{
|
|
TextWindow.AdvanceChar(2);
|
|
info.Kind = SyntaxKind.SlashGreaterThanToken;
|
|
break;
|
|
}
|
|
goto default;
|
|
case '"':
|
|
TextWindow.AdvanceChar();
|
|
info.Kind = SyntaxKind.DoubleQuoteToken;
|
|
break;
|
|
case '\'':
|
|
TextWindow.AdvanceChar();
|
|
info.Kind = SyntaxKind.SingleQuoteToken;
|
|
break;
|
|
case '=':
|
|
TextWindow.AdvanceChar();
|
|
info.Kind = SyntaxKind.EqualsToken;
|
|
break;
|
|
case ':':
|
|
TextWindow.AdvanceChar();
|
|
info.Kind = SyntaxKind.ColonToken;
|
|
break;
|
|
case '\uffff':
|
|
if (TextWindow.IsReallyAtEnd())
|
|
{
|
|
info.Kind = SyntaxKind.EndOfDocumentationCommentToken;
|
|
break;
|
|
}
|
|
goto default;
|
|
case '*':
|
|
if (StyleIs(XmlDocCommentStyle.Delimited) && TextWindow.PeekChar(1) == '/')
|
|
{
|
|
break;
|
|
}
|
|
goto default;
|
|
default:
|
|
if (IsXmlNameStartChar(ch))
|
|
{
|
|
ScanXmlName(ref info);
|
|
info.StringValue = info.Text;
|
|
info.Kind = SyntaxKind.IdentifierToken;
|
|
}
|
|
else if (!SyntaxFacts.IsWhitespace(ch) && !SyntaxFacts.IsNewLine(ch))
|
|
{
|
|
TextWindow.AdvanceChar();
|
|
info.Kind = SyntaxKind.None;
|
|
info.StringValue = (info.Text = TextWindow.GetText(intern: false));
|
|
}
|
|
break;
|
|
case '\n':
|
|
case '\r':
|
|
break;
|
|
}
|
|
return info.Kind != SyntaxKind.None;
|
|
}
|
|
|
|
private void ScanXmlName(ref TokenInfo info)
|
|
{
|
|
int position = TextWindow.Position;
|
|
while (true)
|
|
{
|
|
char c = TextWindow.PeekChar();
|
|
if (c == ':' || !IsXmlNameChar(c))
|
|
{
|
|
break;
|
|
}
|
|
TextWindow.AdvanceChar();
|
|
}
|
|
info.Text = TextWindow.GetText(position, TextWindow.Position - position, intern: true);
|
|
}
|
|
|
|
private static bool IsXmlNameStartChar(char ch)
|
|
{
|
|
return XmlCharType.IsStartNCNameCharXml4e(ch);
|
|
}
|
|
|
|
private static bool IsXmlNameChar(char ch)
|
|
{
|
|
return XmlCharType.IsNCNameCharXml4e(ch);
|
|
}
|
|
|
|
private SyntaxToken LexXmlAttributeTextToken()
|
|
{
|
|
TokenInfo info = default(TokenInfo);
|
|
SyntaxListBuilder trivia = null;
|
|
LexXmlDocCommentLeadingTrivia(ref trivia);
|
|
Start();
|
|
ScanXmlAttributeTextToken(ref info);
|
|
SyntaxDiagnosticInfo[] errors = GetErrors(GetFullWidth(trivia));
|
|
return Create(in info, trivia, null, errors);
|
|
}
|
|
|
|
private bool ScanXmlAttributeTextToken(ref TokenInfo info)
|
|
{
|
|
if (LocationIs(XmlDocCommentLocation.End))
|
|
{
|
|
info.Kind = SyntaxKind.EndOfDocumentationCommentToken;
|
|
return true;
|
|
}
|
|
char ch;
|
|
char c = (ch = TextWindow.PeekChar());
|
|
if ((uint)c <= 34u)
|
|
{
|
|
if (c == '\n' || c == '\r')
|
|
{
|
|
goto IL_00e2;
|
|
}
|
|
if (c != '"' || !ModeIs(LexerMode.XmlAttributeTextDoubleQuote))
|
|
{
|
|
goto IL_0105;
|
|
}
|
|
TextWindow.AdvanceChar();
|
|
info.Kind = SyntaxKind.DoubleQuoteToken;
|
|
}
|
|
else if ((uint)c <= 39u)
|
|
{
|
|
if (c != '&')
|
|
{
|
|
if (c != '\'' || !ModeIs(LexerMode.XmlAttributeTextQuote))
|
|
{
|
|
goto IL_0105;
|
|
}
|
|
TextWindow.AdvanceChar();
|
|
info.Kind = SyntaxKind.SingleQuoteToken;
|
|
}
|
|
else
|
|
{
|
|
ScanXmlEntity(ref info);
|
|
info.Kind = SyntaxKind.XmlEntityLiteralToken;
|
|
}
|
|
}
|
|
else if (c != '<')
|
|
{
|
|
if (c != '\uffff' || !TextWindow.IsReallyAtEnd())
|
|
{
|
|
goto IL_0105;
|
|
}
|
|
info.Kind = SyntaxKind.EndOfDocumentationCommentToken;
|
|
}
|
|
else
|
|
{
|
|
TextWindow.AdvanceChar();
|
|
info.Kind = SyntaxKind.LessThanToken;
|
|
}
|
|
goto IL_011f;
|
|
IL_0105:
|
|
if (SyntaxFacts.IsNewLine(ch))
|
|
{
|
|
goto IL_00e2;
|
|
}
|
|
ScanXmlAttributeText(ref info);
|
|
info.Kind = SyntaxKind.XmlTextLiteralToken;
|
|
goto IL_011f;
|
|
IL_011f:
|
|
return info.Kind != SyntaxKind.None;
|
|
IL_00e2:
|
|
ScanXmlTextLiteralNewLineToken(ref info);
|
|
goto IL_011f;
|
|
}
|
|
|
|
private void ScanXmlAttributeText(ref TokenInfo info)
|
|
{
|
|
while (true)
|
|
{
|
|
char c = TextWindow.PeekChar();
|
|
switch (c)
|
|
{
|
|
case '"':
|
|
if (ModeIs(LexerMode.XmlAttributeTextDoubleQuote))
|
|
{
|
|
info.StringValue = (info.Text = TextWindow.GetText(intern: false));
|
|
return;
|
|
}
|
|
goto default;
|
|
case '\'':
|
|
if (ModeIs(LexerMode.XmlAttributeTextQuote))
|
|
{
|
|
info.StringValue = (info.Text = TextWindow.GetText(intern: false));
|
|
return;
|
|
}
|
|
goto default;
|
|
case '\n':
|
|
case '\r':
|
|
case '&':
|
|
case '<':
|
|
info.StringValue = (info.Text = TextWindow.GetText(intern: false));
|
|
return;
|
|
case '\uffff':
|
|
if (TextWindow.IsReallyAtEnd())
|
|
{
|
|
info.StringValue = (info.Text = TextWindow.GetText(intern: false));
|
|
return;
|
|
}
|
|
goto default;
|
|
case '*':
|
|
if (StyleIs(XmlDocCommentStyle.Delimited) && TextWindow.PeekChar(1) == '/')
|
|
{
|
|
info.StringValue = (info.Text = TextWindow.GetText(intern: false));
|
|
return;
|
|
}
|
|
goto default;
|
|
default:
|
|
if (!SyntaxFacts.IsNewLine(c))
|
|
{
|
|
break;
|
|
}
|
|
goto case '\n';
|
|
}
|
|
TextWindow.AdvanceChar();
|
|
}
|
|
}
|
|
|
|
private SyntaxToken LexXmlCharacter()
|
|
{
|
|
TokenInfo info = default(TokenInfo);
|
|
SyntaxListBuilder trivia = null;
|
|
LexXmlDocCommentLeadingTriviaWithWhitespace(ref trivia);
|
|
Start();
|
|
ScanXmlCharacter(ref info);
|
|
SyntaxDiagnosticInfo[] errors = GetErrors(GetFullWidth(trivia));
|
|
return Create(in info, trivia, null, errors);
|
|
}
|
|
|
|
private bool ScanXmlCharacter(ref TokenInfo info)
|
|
{
|
|
if (LocationIs(XmlDocCommentLocation.End))
|
|
{
|
|
info.Kind = SyntaxKind.EndOfDocumentationCommentToken;
|
|
return true;
|
|
}
|
|
char c = TextWindow.PeekChar();
|
|
if (c != '&')
|
|
{
|
|
if (c == '\uffff' && TextWindow.IsReallyAtEnd())
|
|
{
|
|
info.Kind = SyntaxKind.EndOfFileToken;
|
|
}
|
|
else
|
|
{
|
|
info.Kind = SyntaxKind.XmlTextLiteralToken;
|
|
info.Text = (info.StringValue = TextWindow.NextChar().ToString());
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ScanXmlEntity(ref info);
|
|
info.Kind = SyntaxKind.XmlEntityLiteralToken;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
private SyntaxToken LexXmlCrefOrNameToken()
|
|
{
|
|
TokenInfo info = default(TokenInfo);
|
|
SyntaxListBuilder trivia = null;
|
|
LexXmlDocCommentLeadingTriviaWithWhitespace(ref trivia);
|
|
Start();
|
|
ScanXmlCrefToken(ref info);
|
|
SyntaxDiagnosticInfo[] errors = GetErrors(GetFullWidth(trivia));
|
|
return Create(in info, trivia, null, errors);
|
|
}
|
|
|
|
private bool ScanXmlCrefToken(ref TokenInfo info)
|
|
{
|
|
if (LocationIs(XmlDocCommentLocation.End))
|
|
{
|
|
info.Kind = SyntaxKind.EndOfDocumentationCommentToken;
|
|
return true;
|
|
}
|
|
int position = TextWindow.Position;
|
|
char ch = TextWindow.NextChar();
|
|
char surrogate = '\uffff';
|
|
if ((uint)ch <= 38u)
|
|
{
|
|
if ((uint)ch <= 13u)
|
|
{
|
|
if (ch == '\n' || ch == '\r')
|
|
{
|
|
goto IL_0131;
|
|
}
|
|
goto IL_0188;
|
|
}
|
|
if (ch != '"')
|
|
{
|
|
if (ch != '&')
|
|
{
|
|
goto IL_0188;
|
|
}
|
|
TextWindow.Reset(position);
|
|
if (!TryScanXmlEntity(out ch, out surrogate))
|
|
{
|
|
TextWindow.Reset(position);
|
|
ScanXmlEntity(ref info);
|
|
info.Kind = SyntaxKind.XmlEntityLiteralToken;
|
|
return true;
|
|
}
|
|
}
|
|
else if (ModeIs(LexerMode.XmlCrefDoubleQuote) || ModeIs(LexerMode.XmlNameDoubleQuote))
|
|
{
|
|
info.Kind = SyntaxKind.DoubleQuoteToken;
|
|
return true;
|
|
}
|
|
}
|
|
else if ((uint)ch <= 60u)
|
|
{
|
|
if (ch != '\'')
|
|
{
|
|
if (ch != '<')
|
|
{
|
|
goto IL_0188;
|
|
}
|
|
info.Text = TextWindow.GetText(intern: false);
|
|
AddError(XmlParseErrorCode.XML_LessThanInAttributeValue, info.Text);
|
|
return true;
|
|
}
|
|
if (ModeIs(LexerMode.XmlCrefQuote) || ModeIs(LexerMode.XmlNameQuote))
|
|
{
|
|
info.Kind = SyntaxKind.SingleQuoteToken;
|
|
return true;
|
|
}
|
|
}
|
|
else if (ch != '{')
|
|
{
|
|
if (ch != '}')
|
|
{
|
|
if (ch != '\uffff' || !TextWindow.IsReallyAtEnd())
|
|
{
|
|
goto IL_0188;
|
|
}
|
|
info.Kind = SyntaxKind.EndOfDocumentationCommentToken;
|
|
return true;
|
|
}
|
|
ch = '>';
|
|
}
|
|
else
|
|
{
|
|
ch = '<';
|
|
}
|
|
goto IL_0190;
|
|
IL_0190:
|
|
switch (ch)
|
|
{
|
|
case '(':
|
|
info.Kind = SyntaxKind.OpenParenToken;
|
|
break;
|
|
case ')':
|
|
info.Kind = SyntaxKind.CloseParenToken;
|
|
break;
|
|
case '[':
|
|
info.Kind = SyntaxKind.OpenBracketToken;
|
|
break;
|
|
case ']':
|
|
info.Kind = SyntaxKind.CloseBracketToken;
|
|
break;
|
|
case ',':
|
|
info.Kind = SyntaxKind.CommaToken;
|
|
break;
|
|
case '.':
|
|
if (AdvanceIfMatches('.'))
|
|
{
|
|
if (TextWindow.PeekChar() == '.')
|
|
{
|
|
AddCrefError(ErrorCode.ERR_UnexpectedCharacter, ".");
|
|
}
|
|
info.Kind = SyntaxKind.DotDotToken;
|
|
}
|
|
else
|
|
{
|
|
info.Kind = SyntaxKind.DotToken;
|
|
}
|
|
break;
|
|
case '?':
|
|
info.Kind = SyntaxKind.QuestionToken;
|
|
break;
|
|
case '&':
|
|
info.Kind = SyntaxKind.AmpersandToken;
|
|
break;
|
|
case '*':
|
|
info.Kind = SyntaxKind.AsteriskToken;
|
|
break;
|
|
case '|':
|
|
info.Kind = SyntaxKind.BarToken;
|
|
break;
|
|
case '^':
|
|
info.Kind = SyntaxKind.CaretToken;
|
|
break;
|
|
case '%':
|
|
info.Kind = SyntaxKind.PercentToken;
|
|
break;
|
|
case '/':
|
|
info.Kind = SyntaxKind.SlashToken;
|
|
break;
|
|
case '~':
|
|
info.Kind = SyntaxKind.TildeToken;
|
|
break;
|
|
case '{':
|
|
info.Kind = SyntaxKind.LessThanToken;
|
|
break;
|
|
case '}':
|
|
info.Kind = SyntaxKind.GreaterThanToken;
|
|
break;
|
|
case ':':
|
|
if (AdvanceIfMatches(':'))
|
|
{
|
|
info.Kind = SyntaxKind.ColonColonToken;
|
|
}
|
|
else
|
|
{
|
|
info.Kind = SyntaxKind.ColonToken;
|
|
}
|
|
break;
|
|
case '=':
|
|
if (AdvanceIfMatches('='))
|
|
{
|
|
info.Kind = SyntaxKind.EqualsEqualsToken;
|
|
}
|
|
else
|
|
{
|
|
info.Kind = SyntaxKind.EqualsToken;
|
|
}
|
|
break;
|
|
case '!':
|
|
if (AdvanceIfMatches('='))
|
|
{
|
|
info.Kind = SyntaxKind.ExclamationEqualsToken;
|
|
}
|
|
else
|
|
{
|
|
info.Kind = SyntaxKind.ExclamationToken;
|
|
}
|
|
break;
|
|
case '>':
|
|
if (AdvanceIfMatches('='))
|
|
{
|
|
info.Kind = SyntaxKind.GreaterThanEqualsToken;
|
|
}
|
|
else
|
|
{
|
|
info.Kind = SyntaxKind.GreaterThanToken;
|
|
}
|
|
break;
|
|
case '<':
|
|
if (AdvanceIfMatches('='))
|
|
{
|
|
info.Kind = SyntaxKind.LessThanEqualsToken;
|
|
}
|
|
else if (AdvanceIfMatches('<'))
|
|
{
|
|
info.Kind = SyntaxKind.LessThanLessThanToken;
|
|
}
|
|
else
|
|
{
|
|
info.Kind = SyntaxKind.LessThanToken;
|
|
}
|
|
break;
|
|
case '+':
|
|
if (AdvanceIfMatches('+'))
|
|
{
|
|
info.Kind = SyntaxKind.PlusPlusToken;
|
|
}
|
|
else
|
|
{
|
|
info.Kind = SyntaxKind.PlusToken;
|
|
}
|
|
break;
|
|
case '-':
|
|
if (AdvanceIfMatches('-'))
|
|
{
|
|
info.Kind = SyntaxKind.MinusMinusToken;
|
|
}
|
|
else
|
|
{
|
|
info.Kind = SyntaxKind.MinusToken;
|
|
}
|
|
break;
|
|
}
|
|
if (info.Kind != SyntaxKind.None)
|
|
{
|
|
string text = SyntaxFacts.GetText(info.Kind);
|
|
string text2 = TextWindow.GetText(intern: false);
|
|
if (!string.IsNullOrEmpty(text) && text2 != text)
|
|
{
|
|
info.RequiresTextForXmlEntity = true;
|
|
info.Text = text2;
|
|
info.StringValue = text;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
TextWindow.Reset(position);
|
|
if (ScanIdentifier(ref info) && info.Text.Length > 0)
|
|
{
|
|
if (!InXmlNameAttributeValue && !info.IsVerbatim && !info.HasIdentifierEscapeSequence && _cache.TryGetKeywordKind(info.StringValue, out var kind))
|
|
{
|
|
if (SyntaxFacts.IsContextualKeyword(kind))
|
|
{
|
|
info.Kind = SyntaxKind.IdentifierToken;
|
|
info.ContextualKind = kind;
|
|
}
|
|
else
|
|
{
|
|
info.Kind = kind;
|
|
info.RequiresTextForXmlEntity = info.Text != info.StringValue;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
info.ContextualKind = (info.Kind = SyntaxKind.IdentifierToken);
|
|
}
|
|
}
|
|
else if (ch == '@')
|
|
{
|
|
if (TextWindow.PeekChar() == '@')
|
|
{
|
|
TextWindow.NextChar();
|
|
info.Text = TextWindow.GetText(intern: true);
|
|
info.StringValue = "";
|
|
}
|
|
else
|
|
{
|
|
ScanXmlEntity(ref info);
|
|
}
|
|
info.Kind = SyntaxKind.IdentifierToken;
|
|
AddError(ErrorCode.ERR_ExpectedVerbatimLiteral);
|
|
}
|
|
else if (TextWindow.PeekChar() == '&')
|
|
{
|
|
ScanXmlEntity(ref info);
|
|
info.Kind = SyntaxKind.XmlEntityLiteralToken;
|
|
AddCrefError(ErrorCode.ERR_UnexpectedCharacter, info.Text);
|
|
}
|
|
else
|
|
{
|
|
char charValue = TextWindow.NextChar();
|
|
info.Text = TextWindow.GetText(intern: false);
|
|
if (MatchesProductionForXmlChar(charValue))
|
|
{
|
|
AddCrefError(ErrorCode.ERR_UnexpectedCharacter, info.Text);
|
|
}
|
|
else
|
|
{
|
|
AddError(XmlParseErrorCode.XML_InvalidUnicodeChar);
|
|
}
|
|
}
|
|
}
|
|
return info.Kind != SyntaxKind.None;
|
|
IL_0188:
|
|
if (SyntaxFacts.IsNewLine(ch))
|
|
{
|
|
goto IL_0131;
|
|
}
|
|
goto IL_0190;
|
|
IL_0131:
|
|
TextWindow.Reset(position);
|
|
ScanXmlTextLiteralNewLineToken(ref info);
|
|
goto IL_0190;
|
|
}
|
|
|
|
private bool AdvanceIfMatches(char ch)
|
|
{
|
|
char c = TextWindow.PeekChar();
|
|
if (c == ch || (c == '{' && ch == '<') || (c == '}' && ch == '>'))
|
|
{
|
|
TextWindow.AdvanceChar();
|
|
return true;
|
|
}
|
|
if (c == '&')
|
|
{
|
|
int position = TextWindow.Position;
|
|
if (TryScanXmlEntity(out var ch2, out var surrogate) && ch2 == ch && surrogate == '\uffff')
|
|
{
|
|
return true;
|
|
}
|
|
TextWindow.Reset(position);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
private void AddCrefError(ErrorCode code, params object[] args)
|
|
{
|
|
AddCrefError((DiagnosticInfo?)(object)AbstractLexer.MakeError(code, args));
|
|
}
|
|
|
|
private void AddCrefError(DiagnosticInfo? info)
|
|
{
|
|
if (info != null)
|
|
{
|
|
AddError(ErrorCode.WRN_ErrorOverride, info, info.Code);
|
|
}
|
|
}
|
|
|
|
private SyntaxToken LexXmlCDataSectionTextToken()
|
|
{
|
|
TokenInfo info = default(TokenInfo);
|
|
SyntaxListBuilder trivia = null;
|
|
LexXmlDocCommentLeadingTrivia(ref trivia);
|
|
Start();
|
|
ScanXmlCDataSectionTextToken(ref info);
|
|
SyntaxDiagnosticInfo[] errors = GetErrors(GetFullWidth(trivia));
|
|
return Create(in info, trivia, null, errors);
|
|
}
|
|
|
|
private bool ScanXmlCDataSectionTextToken(ref TokenInfo info)
|
|
{
|
|
if (LocationIs(XmlDocCommentLocation.End))
|
|
{
|
|
info.Kind = SyntaxKind.EndOfDocumentationCommentToken;
|
|
return true;
|
|
}
|
|
char ch;
|
|
char c = (ch = TextWindow.PeekChar());
|
|
if ((uint)c <= 13u)
|
|
{
|
|
if (c == '\n' || c == '\r')
|
|
{
|
|
goto IL_007d;
|
|
}
|
|
goto IL_00a0;
|
|
}
|
|
if (c != ']')
|
|
{
|
|
if (c != '\uffff' || !TextWindow.IsReallyAtEnd())
|
|
{
|
|
goto IL_00a0;
|
|
}
|
|
info.Kind = SyntaxKind.EndOfDocumentationCommentToken;
|
|
}
|
|
else
|
|
{
|
|
if (TextWindow.PeekChar(1) != ']' || TextWindow.PeekChar(2) != '>')
|
|
{
|
|
goto IL_00a0;
|
|
}
|
|
TextWindow.AdvanceChar(3);
|
|
info.Kind = SyntaxKind.XmlCDataEndToken;
|
|
}
|
|
goto IL_00ba;
|
|
IL_00ba:
|
|
return true;
|
|
IL_00a0:
|
|
if (SyntaxFacts.IsNewLine(ch))
|
|
{
|
|
goto IL_007d;
|
|
}
|
|
ScanXmlCDataSectionText(ref info);
|
|
info.Kind = SyntaxKind.XmlTextLiteralToken;
|
|
goto IL_00ba;
|
|
IL_007d:
|
|
ScanXmlTextLiteralNewLineToken(ref info);
|
|
goto IL_00ba;
|
|
}
|
|
|
|
private void ScanXmlCDataSectionText(ref TokenInfo info)
|
|
{
|
|
while (true)
|
|
{
|
|
char c = TextWindow.PeekChar();
|
|
if ((uint)c <= 13u)
|
|
{
|
|
if (c == '\n' || c == '\r')
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
switch (c)
|
|
{
|
|
case ']':
|
|
if (TextWindow.PeekChar(1) == ']' && TextWindow.PeekChar(2) == '>')
|
|
{
|
|
info.StringValue = (info.Text = TextWindow.GetText(intern: false));
|
|
return;
|
|
}
|
|
break;
|
|
case '\uffff':
|
|
if (TextWindow.IsReallyAtEnd())
|
|
{
|
|
info.StringValue = (info.Text = TextWindow.GetText(intern: false));
|
|
return;
|
|
}
|
|
break;
|
|
case '*':
|
|
if (StyleIs(XmlDocCommentStyle.Delimited) && TextWindow.PeekChar(1) == '/')
|
|
{
|
|
info.StringValue = (info.Text = TextWindow.GetText(intern: false));
|
|
return;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
if (SyntaxFacts.IsNewLine(c))
|
|
{
|
|
break;
|
|
}
|
|
TextWindow.AdvanceChar();
|
|
}
|
|
info.StringValue = (info.Text = TextWindow.GetText(intern: false));
|
|
}
|
|
|
|
private SyntaxToken LexXmlCommentTextToken()
|
|
{
|
|
TokenInfo info = default(TokenInfo);
|
|
SyntaxListBuilder trivia = null;
|
|
LexXmlDocCommentLeadingTrivia(ref trivia);
|
|
Start();
|
|
ScanXmlCommentTextToken(ref info);
|
|
SyntaxDiagnosticInfo[] errors = GetErrors(GetFullWidth(trivia));
|
|
return Create(in info, trivia, null, errors);
|
|
}
|
|
|
|
private bool ScanXmlCommentTextToken(ref TokenInfo info)
|
|
{
|
|
if (LocationIs(XmlDocCommentLocation.End))
|
|
{
|
|
info.Kind = SyntaxKind.EndOfDocumentationCommentToken;
|
|
return true;
|
|
}
|
|
char ch;
|
|
char c = (ch = TextWindow.PeekChar());
|
|
if ((uint)c <= 13u)
|
|
{
|
|
if (c == '\n' || c == '\r')
|
|
{
|
|
goto IL_0099;
|
|
}
|
|
goto IL_00bc;
|
|
}
|
|
if (c != '-')
|
|
{
|
|
if (c != '\uffff' || !TextWindow.IsReallyAtEnd())
|
|
{
|
|
goto IL_00bc;
|
|
}
|
|
info.Kind = SyntaxKind.EndOfDocumentationCommentToken;
|
|
}
|
|
else
|
|
{
|
|
if (TextWindow.PeekChar(1) != '-')
|
|
{
|
|
goto IL_00bc;
|
|
}
|
|
if (TextWindow.PeekChar(2) == '>')
|
|
{
|
|
TextWindow.AdvanceChar(3);
|
|
info.Kind = SyntaxKind.XmlCommentEndToken;
|
|
}
|
|
else
|
|
{
|
|
TextWindow.AdvanceChar(2);
|
|
info.Kind = SyntaxKind.MinusMinusToken;
|
|
}
|
|
}
|
|
goto IL_00d6;
|
|
IL_00d6:
|
|
return true;
|
|
IL_00bc:
|
|
if (SyntaxFacts.IsNewLine(ch))
|
|
{
|
|
goto IL_0099;
|
|
}
|
|
ScanXmlCommentText(ref info);
|
|
info.Kind = SyntaxKind.XmlTextLiteralToken;
|
|
goto IL_00d6;
|
|
IL_0099:
|
|
ScanXmlTextLiteralNewLineToken(ref info);
|
|
goto IL_00d6;
|
|
}
|
|
|
|
private void ScanXmlCommentText(ref TokenInfo info)
|
|
{
|
|
while (true)
|
|
{
|
|
char c = TextWindow.PeekChar();
|
|
if ((uint)c <= 13u)
|
|
{
|
|
if (c == '\n' || c == '\r')
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
switch (c)
|
|
{
|
|
case '-':
|
|
if (TextWindow.PeekChar(1) == '-')
|
|
{
|
|
info.StringValue = (info.Text = TextWindow.GetText(intern: false));
|
|
return;
|
|
}
|
|
break;
|
|
case '\uffff':
|
|
if (TextWindow.IsReallyAtEnd())
|
|
{
|
|
info.StringValue = (info.Text = TextWindow.GetText(intern: false));
|
|
return;
|
|
}
|
|
break;
|
|
case '*':
|
|
if (StyleIs(XmlDocCommentStyle.Delimited) && TextWindow.PeekChar(1) == '/')
|
|
{
|
|
info.StringValue = (info.Text = TextWindow.GetText(intern: false));
|
|
return;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
if (SyntaxFacts.IsNewLine(c))
|
|
{
|
|
break;
|
|
}
|
|
TextWindow.AdvanceChar();
|
|
}
|
|
info.StringValue = (info.Text = TextWindow.GetText(intern: false));
|
|
}
|
|
|
|
private SyntaxToken LexXmlProcessingInstructionTextToken()
|
|
{
|
|
TokenInfo info = default(TokenInfo);
|
|
SyntaxListBuilder trivia = null;
|
|
LexXmlDocCommentLeadingTrivia(ref trivia);
|
|
Start();
|
|
ScanXmlProcessingInstructionTextToken(ref info);
|
|
SyntaxDiagnosticInfo[] errors = GetErrors(GetFullWidth(trivia));
|
|
return Create(in info, trivia, null, errors);
|
|
}
|
|
|
|
private bool ScanXmlProcessingInstructionTextToken(ref TokenInfo info)
|
|
{
|
|
if (LocationIs(XmlDocCommentLocation.End))
|
|
{
|
|
info.Kind = SyntaxKind.EndOfDocumentationCommentToken;
|
|
return true;
|
|
}
|
|
char ch;
|
|
char c = (ch = TextWindow.PeekChar());
|
|
if ((uint)c <= 13u)
|
|
{
|
|
if (c == '\n' || c == '\r')
|
|
{
|
|
goto IL_006d;
|
|
}
|
|
goto IL_0090;
|
|
}
|
|
if (c != '?')
|
|
{
|
|
if (c != '\uffff' || !TextWindow.IsReallyAtEnd())
|
|
{
|
|
goto IL_0090;
|
|
}
|
|
info.Kind = SyntaxKind.EndOfDocumentationCommentToken;
|
|
}
|
|
else
|
|
{
|
|
if (TextWindow.PeekChar(1) != '>')
|
|
{
|
|
goto IL_0090;
|
|
}
|
|
TextWindow.AdvanceChar(2);
|
|
info.Kind = SyntaxKind.XmlProcessingInstructionEndToken;
|
|
}
|
|
goto IL_00aa;
|
|
IL_006d:
|
|
ScanXmlTextLiteralNewLineToken(ref info);
|
|
goto IL_00aa;
|
|
IL_00aa:
|
|
return true;
|
|
IL_0090:
|
|
if (SyntaxFacts.IsNewLine(ch))
|
|
{
|
|
goto IL_006d;
|
|
}
|
|
ScanXmlProcessingInstructionText(ref info);
|
|
info.Kind = SyntaxKind.XmlTextLiteralToken;
|
|
goto IL_00aa;
|
|
}
|
|
|
|
private void ScanXmlProcessingInstructionText(ref TokenInfo info)
|
|
{
|
|
while (true)
|
|
{
|
|
char c = TextWindow.PeekChar();
|
|
if ((uint)c <= 13u)
|
|
{
|
|
if (c == '\n' || c == '\r')
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
switch (c)
|
|
{
|
|
case '?':
|
|
if (TextWindow.PeekChar(1) == '>')
|
|
{
|
|
info.StringValue = (info.Text = TextWindow.GetText(intern: false));
|
|
return;
|
|
}
|
|
break;
|
|
case '\uffff':
|
|
if (TextWindow.IsReallyAtEnd())
|
|
{
|
|
info.StringValue = (info.Text = TextWindow.GetText(intern: false));
|
|
return;
|
|
}
|
|
break;
|
|
case '*':
|
|
if (StyleIs(XmlDocCommentStyle.Delimited) && TextWindow.PeekChar(1) == '/')
|
|
{
|
|
info.StringValue = (info.Text = TextWindow.GetText(intern: false));
|
|
return;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
if (SyntaxFacts.IsNewLine(c))
|
|
{
|
|
break;
|
|
}
|
|
TextWindow.AdvanceChar();
|
|
}
|
|
info.StringValue = (info.Text = TextWindow.GetText(intern: false));
|
|
}
|
|
|
|
private void LexXmlDocCommentLeadingTrivia(ref SyntaxListBuilder? trivia)
|
|
{
|
|
int position = TextWindow.Position;
|
|
Start();
|
|
if (LocationIs(XmlDocCommentLocation.Start) && StyleIs(XmlDocCommentStyle.Delimited))
|
|
{
|
|
if (TextWindow.PeekChar() == '/' && TextWindow.PeekChar(1) == '*' && TextWindow.PeekChar(2) == '*' && TextWindow.PeekChar(3) != '*')
|
|
{
|
|
TextWindow.AdvanceChar(3);
|
|
string text = TextWindow.GetText(intern: true);
|
|
AddTrivia(SyntaxFactory.DocumentationCommentExteriorTrivia(text), ref trivia);
|
|
MutateLocation(XmlDocCommentLocation.Interior);
|
|
}
|
|
}
|
|
else if (LocationIs(XmlDocCommentLocation.Start) || LocationIs(XmlDocCommentLocation.Exterior))
|
|
{
|
|
while (true)
|
|
{
|
|
char c = TextWindow.PeekChar();
|
|
switch (c)
|
|
{
|
|
case '\t':
|
|
case '\v':
|
|
case '\f':
|
|
case ' ':
|
|
goto IL_00fb;
|
|
case '/':
|
|
if (StyleIs(XmlDocCommentStyle.SingleLine) && TextWindow.PeekChar(1) == '/' && TextWindow.PeekChar(2) == '/' && TextWindow.PeekChar(3) != '/')
|
|
{
|
|
TextWindow.AdvanceChar(3);
|
|
string text3 = TextWindow.GetText(intern: true);
|
|
AddTrivia(SyntaxFactory.DocumentationCommentExteriorTrivia(text3), ref trivia);
|
|
MutateLocation(XmlDocCommentLocation.Interior);
|
|
return;
|
|
}
|
|
break;
|
|
case '*':
|
|
if (StyleIs(XmlDocCommentStyle.Delimited))
|
|
{
|
|
while (TextWindow.PeekChar() == '*' && TextWindow.PeekChar(1) != '/')
|
|
{
|
|
TextWindow.AdvanceChar();
|
|
}
|
|
string text2 = TextWindow.GetText(intern: true);
|
|
if (!string.IsNullOrEmpty(text2))
|
|
{
|
|
AddTrivia(SyntaxFactory.DocumentationCommentExteriorTrivia(text2), ref trivia);
|
|
}
|
|
if (TextWindow.PeekChar() == '*' && TextWindow.PeekChar(1) == '/')
|
|
{
|
|
TextWindow.AdvanceChar(2);
|
|
AddTrivia(SyntaxFactory.DocumentationCommentExteriorTrivia("*/"), ref trivia);
|
|
MutateLocation(XmlDocCommentLocation.End);
|
|
}
|
|
else
|
|
{
|
|
MutateLocation(XmlDocCommentLocation.Interior);
|
|
}
|
|
return;
|
|
}
|
|
break;
|
|
}
|
|
if (!SyntaxFacts.IsWhitespace(c))
|
|
{
|
|
break;
|
|
}
|
|
goto IL_00fb;
|
|
IL_00fb:
|
|
TextWindow.AdvanceChar();
|
|
}
|
|
if (StyleIs(XmlDocCommentStyle.SingleLine))
|
|
{
|
|
TextWindow.Reset(position);
|
|
MutateLocation(XmlDocCommentLocation.End);
|
|
return;
|
|
}
|
|
string text4 = TextWindow.GetText(intern: true);
|
|
if (!string.IsNullOrEmpty(text4))
|
|
{
|
|
AddTrivia(SyntaxFactory.DocumentationCommentExteriorTrivia(text4), ref trivia);
|
|
}
|
|
MutateLocation(XmlDocCommentLocation.Interior);
|
|
}
|
|
else if (!LocationIs(XmlDocCommentLocation.End) && StyleIs(XmlDocCommentStyle.Delimited) && TextWindow.PeekChar() == '*' && TextWindow.PeekChar(1) == '/')
|
|
{
|
|
TextWindow.AdvanceChar(2);
|
|
string text5 = TextWindow.GetText(intern: true);
|
|
AddTrivia(SyntaxFactory.DocumentationCommentExteriorTrivia(text5), ref trivia);
|
|
MutateLocation(XmlDocCommentLocation.End);
|
|
}
|
|
}
|
|
|
|
private void LexXmlDocCommentLeadingTriviaWithWhitespace(ref SyntaxListBuilder? trivia)
|
|
{
|
|
while (true)
|
|
{
|
|
LexXmlDocCommentLeadingTrivia(ref trivia);
|
|
char ch = TextWindow.PeekChar();
|
|
if (LocationIs(XmlDocCommentLocation.Interior) && (SyntaxFacts.IsWhitespace(ch) || SyntaxFacts.IsNewLine(ch)))
|
|
{
|
|
LexXmlWhitespaceAndNewLineTrivia(ref trivia);
|
|
continue;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
private void LexXmlWhitespaceAndNewLineTrivia(ref SyntaxListBuilder? trivia)
|
|
{
|
|
Start();
|
|
if (!LocationIs(XmlDocCommentLocation.Interior))
|
|
{
|
|
return;
|
|
}
|
|
char c = TextWindow.PeekChar();
|
|
switch (c)
|
|
{
|
|
case '\t':
|
|
case '\v':
|
|
case '\f':
|
|
case ' ':
|
|
AddTrivia(ScanWhitespace(), ref trivia);
|
|
break;
|
|
case '\n':
|
|
case '\r':
|
|
{
|
|
CSharpSyntaxNode trivia2 = ScanEndOfLine();
|
|
AddTrivia(trivia2, ref trivia);
|
|
MutateLocation(XmlDocCommentLocation.Exterior);
|
|
break;
|
|
}
|
|
case '*':
|
|
if (StyleIs(XmlDocCommentStyle.Delimited) && TextWindow.PeekChar(1) == '/')
|
|
{
|
|
break;
|
|
}
|
|
goto default;
|
|
default:
|
|
if (SyntaxFacts.IsWhitespace(c))
|
|
{
|
|
goto case '\t';
|
|
}
|
|
if (!SyntaxFacts.IsNewLine(c))
|
|
{
|
|
break;
|
|
}
|
|
goto case '\n';
|
|
}
|
|
}
|
|
|
|
private bool IsUnicodeEscape()
|
|
{
|
|
if (TextWindow.PeekChar() == '\\')
|
|
{
|
|
char c = TextWindow.PeekChar(1);
|
|
if (c == 'U' || c == 'u')
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
private char PeekCharOrUnicodeEscape(out char surrogateCharacter)
|
|
{
|
|
if (IsUnicodeEscape())
|
|
{
|
|
return PeekUnicodeEscape(out surrogateCharacter);
|
|
}
|
|
surrogateCharacter = '\uffff';
|
|
return TextWindow.PeekChar();
|
|
}
|
|
|
|
private char PeekUnicodeEscape(out char surrogateCharacter)
|
|
{
|
|
int position = TextWindow.Position;
|
|
SyntaxDiagnosticInfo info;
|
|
char result = ScanUnicodeEscape(peek: true, out surrogateCharacter, out info);
|
|
TextWindow.Reset(position);
|
|
return result;
|
|
}
|
|
|
|
private char NextCharOrUnicodeEscape(out char surrogateCharacter, out SyntaxDiagnosticInfo? info)
|
|
{
|
|
char c = TextWindow.PeekChar();
|
|
if (c == '\\')
|
|
{
|
|
char c2 = TextWindow.PeekChar(1);
|
|
if (c2 == 'U' || c2 == 'u')
|
|
{
|
|
return ScanUnicodeEscape(peek: false, out surrogateCharacter, out info);
|
|
}
|
|
}
|
|
surrogateCharacter = '\uffff';
|
|
info = null;
|
|
TextWindow.AdvanceChar();
|
|
return c;
|
|
}
|
|
|
|
private char NextUnicodeEscape(out char surrogateCharacter, out SyntaxDiagnosticInfo? info)
|
|
{
|
|
return ScanUnicodeEscape(peek: false, out surrogateCharacter, out info);
|
|
}
|
|
|
|
private char ScanUnicodeEscape(bool peek, out char surrogateCharacter, out SyntaxDiagnosticInfo? info)
|
|
{
|
|
surrogateCharacter = '\uffff';
|
|
info = null;
|
|
int position = TextWindow.Position;
|
|
char c = TextWindow.PeekChar();
|
|
TextWindow.AdvanceChar();
|
|
c = TextWindow.PeekChar();
|
|
if (c == 'U')
|
|
{
|
|
uint num = 0u;
|
|
TextWindow.AdvanceChar();
|
|
if (!SyntaxFacts.IsHexDigit(TextWindow.PeekChar()))
|
|
{
|
|
if (!peek)
|
|
{
|
|
info = CreateIllegalEscapeDiagnostic(position);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (int i = 0; i < 8; i++)
|
|
{
|
|
c = TextWindow.PeekChar();
|
|
if (!SyntaxFacts.IsHexDigit(c))
|
|
{
|
|
if (!peek)
|
|
{
|
|
info = CreateIllegalEscapeDiagnostic(position);
|
|
}
|
|
break;
|
|
}
|
|
num = (uint)((num << 4) + SyntaxFacts.HexValue(c));
|
|
TextWindow.AdvanceChar();
|
|
}
|
|
if (num > 1114111)
|
|
{
|
|
if (!peek)
|
|
{
|
|
info = CreateIllegalEscapeDiagnostic(position);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
c = GetCharsFromUtf32(num, out surrogateCharacter);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
int num2 = 0;
|
|
TextWindow.AdvanceChar();
|
|
if (!SyntaxFacts.IsHexDigit(TextWindow.PeekChar()))
|
|
{
|
|
if (!peek)
|
|
{
|
|
info = CreateIllegalEscapeDiagnostic(position);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (int j = 0; j < 4; j++)
|
|
{
|
|
char c2 = TextWindow.PeekChar();
|
|
if (!SyntaxFacts.IsHexDigit(c2))
|
|
{
|
|
if (c == 'u' && !peek)
|
|
{
|
|
info = CreateIllegalEscapeDiagnostic(position);
|
|
}
|
|
break;
|
|
}
|
|
num2 = (num2 << 4) + SyntaxFacts.HexValue(c2);
|
|
TextWindow.AdvanceChar();
|
|
}
|
|
c = (char)num2;
|
|
}
|
|
}
|
|
return c;
|
|
}
|
|
|
|
public bool TryScanXmlEntity(out char ch, out char surrogate)
|
|
{
|
|
ch = '&';
|
|
TextWindow.AdvanceChar();
|
|
surrogate = '\uffff';
|
|
switch (TextWindow.PeekChar())
|
|
{
|
|
case 'l':
|
|
if (TextWindow.AdvanceIfMatches("lt;"))
|
|
{
|
|
ch = '<';
|
|
return true;
|
|
}
|
|
break;
|
|
case 'g':
|
|
if (TextWindow.AdvanceIfMatches("gt;"))
|
|
{
|
|
ch = '>';
|
|
return true;
|
|
}
|
|
break;
|
|
case 'a':
|
|
if (TextWindow.AdvanceIfMatches("amp;"))
|
|
{
|
|
ch = '&';
|
|
return true;
|
|
}
|
|
if (TextWindow.AdvanceIfMatches("apos;"))
|
|
{
|
|
ch = '\'';
|
|
return true;
|
|
}
|
|
break;
|
|
case 'q':
|
|
if (TextWindow.AdvanceIfMatches("quot;"))
|
|
{
|
|
ch = '"';
|
|
return true;
|
|
}
|
|
break;
|
|
case '#':
|
|
{
|
|
TextWindow.AdvanceChar();
|
|
uint num = 0u;
|
|
if (TextWindow.AdvanceIfMatches("x"))
|
|
{
|
|
char c;
|
|
while (SyntaxFacts.IsHexDigit(c = TextWindow.PeekChar()))
|
|
{
|
|
TextWindow.AdvanceChar();
|
|
if (num <= 134217727)
|
|
{
|
|
num = (num << 4) + (uint)SyntaxFacts.HexValue(c);
|
|
continue;
|
|
}
|
|
return false;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
char c2;
|
|
while (SyntaxFacts.IsDecDigit(c2 = TextWindow.PeekChar()))
|
|
{
|
|
TextWindow.AdvanceChar();
|
|
if (num <= 134217727)
|
|
{
|
|
num = (num << 3) + (num << 1) + (uint)SyntaxFacts.DecValue(c2);
|
|
continue;
|
|
}
|
|
return false;
|
|
}
|
|
}
|
|
if (TextWindow.AdvanceIfMatches(";"))
|
|
{
|
|
ch = GetCharsFromUtf32(num, out surrogate);
|
|
return true;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
private SyntaxDiagnosticInfo CreateIllegalEscapeDiagnostic(int start)
|
|
{
|
|
return new SyntaxDiagnosticInfo(start - TextWindow.LexemeStartPosition, TextWindow.Position - start, ErrorCode.ERR_IllegalEscape);
|
|
}
|
|
|
|
internal static char GetCharsFromUtf32(uint codepoint, out char lowSurrogate)
|
|
{
|
|
if (codepoint < 65536)
|
|
{
|
|
lowSurrogate = '\uffff';
|
|
return (char)codepoint;
|
|
}
|
|
lowSurrogate = (char)((codepoint - 65536) % 1024 + 56320);
|
|
return (char)((codepoint - 65536) / 1024 + 55296);
|
|
}
|
|
|
|
private int ConsumeCharSequence(char ch)
|
|
{
|
|
int position = TextWindow.Position;
|
|
while (TextWindow.PeekChar() == ch)
|
|
{
|
|
TextWindow.AdvanceChar();
|
|
}
|
|
return TextWindow.Position - position;
|
|
}
|
|
|
|
private int ConsumeQuoteSequence()
|
|
{
|
|
return ConsumeCharSequence('"');
|
|
}
|
|
|
|
private int ConsumeDollarSignSequence()
|
|
{
|
|
return ConsumeCharSequence('$');
|
|
}
|
|
|
|
private int ConsumeAtSignSequence()
|
|
{
|
|
return ConsumeCharSequence('@');
|
|
}
|
|
|
|
private int ConsumeOpenBraceSequence()
|
|
{
|
|
return ConsumeCharSequence('{');
|
|
}
|
|
|
|
private int ConsumeCloseBraceSequence()
|
|
{
|
|
return ConsumeCharSequence('}');
|
|
}
|
|
|
|
private void ConsumeWhitespace(StringBuilder? builder)
|
|
{
|
|
while (true)
|
|
{
|
|
char c = TextWindow.PeekChar();
|
|
if (SyntaxFacts.IsWhitespace(c))
|
|
{
|
|
builder?.Append(c);
|
|
TextWindow.AdvanceChar();
|
|
continue;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
private bool IsAtEndOfText(char currentChar)
|
|
{
|
|
if (currentChar == '\uffff')
|
|
{
|
|
return TextWindow.IsReallyAtEnd();
|
|
}
|
|
return false;
|
|
}
|
|
|
|
private void ScanRawStringLiteral(ref TokenInfo info, bool inDirective)
|
|
{
|
|
_builder.Length = 0;
|
|
int num = ConsumeQuoteSequence();
|
|
ConsumeWhitespace(null);
|
|
if (SyntaxFacts.IsNewLine(TextWindow.PeekChar()))
|
|
{
|
|
ScanMultiLineRawStringLiteral(ref info, num);
|
|
}
|
|
else
|
|
{
|
|
ScanSingleLineRawStringLiteral(ref info, num);
|
|
}
|
|
if (base.HasErrors)
|
|
{
|
|
int num2 = TextWindow.LexemeStartPosition + num;
|
|
int length = TextWindow.Position - num2;
|
|
info.StringValue = TextWindow.GetText(num2, length, intern: true);
|
|
}
|
|
if (!inDirective && ScanUtf8Suffix())
|
|
{
|
|
switch (info.Kind)
|
|
{
|
|
case SyntaxKind.SingleLineRawStringLiteralToken:
|
|
info.Kind = SyntaxKind.Utf8SingleLineRawStringLiteralToken;
|
|
break;
|
|
case SyntaxKind.MultiLineRawStringLiteralToken:
|
|
info.Kind = SyntaxKind.Utf8MultiLineRawStringLiteralToken;
|
|
break;
|
|
default:
|
|
throw ExceptionUtilities.UnexpectedValue((object)info.Kind);
|
|
}
|
|
}
|
|
info.Text = TextWindow.GetText(intern: true);
|
|
}
|
|
|
|
private void ScanSingleLineRawStringLiteral(ref TokenInfo info, int startingQuoteCount)
|
|
{
|
|
info.Kind = SyntaxKind.SingleLineRawStringLiteralToken;
|
|
int position;
|
|
int num;
|
|
while (true)
|
|
{
|
|
char c = TextWindow.PeekChar();
|
|
if (SyntaxFacts.IsNewLine(c))
|
|
{
|
|
AddError(TextWindow.Position, TextWindow.GetNewLineWidth(), ErrorCode.ERR_UnterminatedRawString);
|
|
return;
|
|
}
|
|
if (IsAtEndOfText(c))
|
|
{
|
|
AddError(TextWindow.Position, 0, ErrorCode.ERR_UnterminatedRawString);
|
|
return;
|
|
}
|
|
if (c != '"')
|
|
{
|
|
TextWindow.AdvanceChar();
|
|
continue;
|
|
}
|
|
position = TextWindow.Position;
|
|
num = ConsumeQuoteSequence();
|
|
if (num >= startingQuoteCount)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
if (num > startingQuoteCount)
|
|
{
|
|
int num2 = num - startingQuoteCount;
|
|
AddError(TextWindow.Position - num2, num2, ErrorCode.ERR_TooManyQuotesForRawString);
|
|
}
|
|
int num3 = TextWindow.LexemeStartPosition + startingQuoteCount;
|
|
int length = position - num3;
|
|
info.StringValue = TextWindow.GetText(num3, length, intern: true);
|
|
}
|
|
|
|
private void ScanMultiLineRawStringLiteral(ref TokenInfo info, int startingQuoteCount)
|
|
{
|
|
info.Kind = SyntaxKind.MultiLineRawStringLiteralToken;
|
|
PooledStringBuilder instance = PooledStringBuilder.GetInstance();
|
|
PooledStringBuilder instance2 = PooledStringBuilder.GetInstance();
|
|
try
|
|
{
|
|
int position = TextWindow.Position;
|
|
int num = 0;
|
|
while (ScanMultiLineRawStringLiteralLine(startingQuoteCount, instance.Builder))
|
|
{
|
|
num++;
|
|
}
|
|
if (base.HasErrors)
|
|
{
|
|
return;
|
|
}
|
|
if (num == 0)
|
|
{
|
|
AddError(TextWindow.Position - startingQuoteCount, startingQuoteCount, ErrorCode.ERR_RawStringMustContainContent);
|
|
return;
|
|
}
|
|
int position2 = TextWindow.Position;
|
|
TextWindow.Reset(position);
|
|
for (int i = 0; i < num; i++)
|
|
{
|
|
AddMultiLineRawStringLiteralLineContents(instance.Builder, instance2.Builder, i == 0);
|
|
if (base.HasErrors)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
info.StringValue = (base.HasErrors ? "" : TextWindow.Intern(_builder));
|
|
TextWindow.Reset(position2);
|
|
}
|
|
finally
|
|
{
|
|
instance.Free();
|
|
instance2.Free();
|
|
}
|
|
}
|
|
|
|
private bool ScanMultiLineRawStringLiteralLine(int startingQuoteCount, StringBuilder indentationWhitespace)
|
|
{
|
|
TextWindow.AdvancePastNewLine();
|
|
indentationWhitespace.Clear();
|
|
ConsumeWhitespace(indentationWhitespace);
|
|
int num = ConsumeQuoteSequence();
|
|
if (num >= startingQuoteCount)
|
|
{
|
|
if (num > startingQuoteCount)
|
|
{
|
|
int num2 = num - startingQuoteCount;
|
|
AddError(TextWindow.Position - num2, num2, ErrorCode.ERR_TooManyQuotesForRawString);
|
|
}
|
|
return false;
|
|
}
|
|
while (true)
|
|
{
|
|
char c = TextWindow.PeekChar();
|
|
if (IsAtEndOfText(c))
|
|
{
|
|
AddError(TextWindow.Position, 0, ErrorCode.ERR_UnterminatedRawString);
|
|
return false;
|
|
}
|
|
if (SyntaxFacts.IsNewLine(c))
|
|
{
|
|
return true;
|
|
}
|
|
if (c == '"')
|
|
{
|
|
num = ConsumeQuoteSequence();
|
|
if (num >= startingQuoteCount)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
TextWindow.AdvanceChar();
|
|
}
|
|
}
|
|
AddError(TextWindow.Position - num, num, ErrorCode.ERR_RawStringDelimiterOnOwnLine);
|
|
return false;
|
|
}
|
|
|
|
private void AddMultiLineRawStringLiteralLineContents(StringBuilder indentationWhitespace, StringBuilder currentLineWhitespace, bool firstContentLine)
|
|
{
|
|
int newLineWidth = TextWindow.GetNewLineWidth();
|
|
for (int i = 0; i < newLineWidth; i++)
|
|
{
|
|
if (!firstContentLine)
|
|
{
|
|
_builder.Append(TextWindow.PeekChar());
|
|
}
|
|
TextWindow.AdvanceChar();
|
|
}
|
|
int position = TextWindow.Position;
|
|
currentLineWhitespace.Clear();
|
|
ConsumeWhitespace(currentLineWhitespace);
|
|
if (!StartsWith(currentLineWhitespace, indentationWhitespace) && (!SyntaxFacts.IsNewLine(TextWindow.PeekChar()) || !StartsWith(indentationWhitespace, currentLineWhitespace)))
|
|
{
|
|
if (CheckForSpaceDifference(currentLineWhitespace, indentationWhitespace, out string currentLineMessage, out string indentationLineMessage))
|
|
{
|
|
AddError(position, TextWindow.Position - position, ErrorCode.ERR_LineContainsDifferentWhitespace, currentLineMessage, indentationLineMessage);
|
|
}
|
|
else
|
|
{
|
|
AddError(position, TextWindow.Position - position, ErrorCode.ERR_LineDoesNotStartWithSameWhitespace);
|
|
}
|
|
return;
|
|
}
|
|
for (int j = indentationWhitespace.Length; j < currentLineWhitespace.Length; j++)
|
|
{
|
|
_builder.Append(currentLineWhitespace[j]);
|
|
}
|
|
while (true)
|
|
{
|
|
char c = TextWindow.PeekChar();
|
|
if (SyntaxFacts.IsNewLine(c))
|
|
{
|
|
break;
|
|
}
|
|
_builder.Append(c);
|
|
TextWindow.AdvanceChar();
|
|
}
|
|
}
|
|
|
|
private static bool CheckForSpaceDifference(StringBuilder currentLineWhitespace, StringBuilder indentationLineWhitespace, [NotNullWhen(true)] out string? currentLineMessage, [NotNullWhen(true)] out string? indentationLineMessage)
|
|
{
|
|
int i = 0;
|
|
for (int num = Math.Min(currentLineWhitespace.Length, indentationLineWhitespace.Length); i < num; i++)
|
|
{
|
|
char c = currentLineWhitespace[i];
|
|
char c2 = indentationLineWhitespace[i];
|
|
if (c != c2 && SyntaxFacts.IsWhitespace(c) && SyntaxFacts.IsWhitespace(c2))
|
|
{
|
|
currentLineMessage = CharToString(c);
|
|
indentationLineMessage = CharToString(c2);
|
|
return true;
|
|
}
|
|
}
|
|
currentLineMessage = null;
|
|
indentationLineMessage = null;
|
|
return false;
|
|
}
|
|
|
|
public static string CharToString(char ch)
|
|
{
|
|
return ch switch
|
|
{
|
|
'\t' => "\\t",
|
|
'\v' => "\\v",
|
|
'\f' => "\\f",
|
|
_ => $"\\u{(int)ch:x4}",
|
|
};
|
|
}
|
|
|
|
private static bool StartsWith(StringBuilder sb, StringBuilder value)
|
|
{
|
|
if (sb.Length < value.Length)
|
|
{
|
|
return false;
|
|
}
|
|
for (int i = 0; i < value.Length; i++)
|
|
{
|
|
if (sb[i] != value[i])
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
private void ScanStringLiteral(ref TokenInfo info, bool inDirective)
|
|
{
|
|
char c = TextWindow.PeekChar();
|
|
if (TextWindow.PeekChar() == '"' && TextWindow.PeekChar(1) == '"' && TextWindow.PeekChar(2) == '"')
|
|
{
|
|
ScanRawStringLiteral(ref info, inDirective);
|
|
if (inDirective)
|
|
{
|
|
info.Kind = SyntaxKind.StringLiteralToken;
|
|
info.StringValue = "";
|
|
AddError(ErrorCode.ERR_RawStringNotInDirectives);
|
|
}
|
|
return;
|
|
}
|
|
TextWindow.AdvanceChar();
|
|
_builder.Length = 0;
|
|
while (true)
|
|
{
|
|
char c2 = TextWindow.PeekChar();
|
|
if (c2 == '\\' && !inDirective)
|
|
{
|
|
c2 = ScanEscapeSequence(out var surrogateCharacter);
|
|
_builder.Append(c2);
|
|
if (surrogateCharacter != '\uffff')
|
|
{
|
|
_builder.Append(surrogateCharacter);
|
|
}
|
|
continue;
|
|
}
|
|
if (c2 == c)
|
|
{
|
|
TextWindow.AdvanceChar();
|
|
break;
|
|
}
|
|
if (SyntaxFacts.IsNewLine(c2) || (c2 == '\uffff' && TextWindow.IsReallyAtEnd()))
|
|
{
|
|
AddError(ErrorCode.ERR_NewlineInConst);
|
|
break;
|
|
}
|
|
TextWindow.AdvanceChar();
|
|
_builder.Append(c2);
|
|
}
|
|
if (c == '\'')
|
|
{
|
|
info.Text = TextWindow.GetText(intern: true);
|
|
info.Kind = SyntaxKind.CharacterLiteralToken;
|
|
if (_builder.Length != 1)
|
|
{
|
|
AddError((_builder.Length != 0) ? ErrorCode.ERR_TooManyCharsInConst : ErrorCode.ERR_EmptyCharConst);
|
|
}
|
|
if (_builder.Length > 0)
|
|
{
|
|
info.StringValue = TextWindow.Intern(_builder);
|
|
info.CharValue = info.StringValue[0];
|
|
}
|
|
else
|
|
{
|
|
info.StringValue = string.Empty;
|
|
info.CharValue = '\uffff';
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (!inDirective && ScanUtf8Suffix())
|
|
{
|
|
info.Kind = SyntaxKind.Utf8StringLiteralToken;
|
|
}
|
|
else
|
|
{
|
|
info.Kind = SyntaxKind.StringLiteralToken;
|
|
}
|
|
info.Text = TextWindow.GetText(intern: true);
|
|
if (_builder.Length > 0)
|
|
{
|
|
info.StringValue = TextWindow.Intern(_builder);
|
|
}
|
|
else
|
|
{
|
|
info.StringValue = string.Empty;
|
|
}
|
|
}
|
|
}
|
|
|
|
private bool ScanUtf8Suffix()
|
|
{
|
|
char c = TextWindow.PeekChar();
|
|
bool flag = ((c == 'U' || c == 'u') ? true : false);
|
|
if (flag && TextWindow.PeekChar(1) == '8')
|
|
{
|
|
TextWindow.AdvanceChar(2);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
private char ScanEscapeSequence(out char surrogateCharacter)
|
|
{
|
|
int position = TextWindow.Position;
|
|
surrogateCharacter = '\uffff';
|
|
char c = TextWindow.NextChar();
|
|
c = TextWindow.NextChar();
|
|
switch (c)
|
|
{
|
|
case '0':
|
|
c = '\0';
|
|
break;
|
|
case 'a':
|
|
c = '\a';
|
|
break;
|
|
case 'b':
|
|
c = '\b';
|
|
break;
|
|
case 'f':
|
|
c = '\f';
|
|
break;
|
|
case 'n':
|
|
c = '\n';
|
|
break;
|
|
case 'r':
|
|
c = '\r';
|
|
break;
|
|
case 't':
|
|
c = '\t';
|
|
break;
|
|
case 'v':
|
|
c = '\v';
|
|
break;
|
|
case 'U':
|
|
case 'u':
|
|
case 'x':
|
|
{
|
|
TextWindow.Reset(position);
|
|
c = NextUnicodeEscape(out surrogateCharacter, out SyntaxDiagnosticInfo info);
|
|
AddError(info);
|
|
break;
|
|
}
|
|
default:
|
|
AddError(position, TextWindow.Position - position, ErrorCode.ERR_IllegalEscape);
|
|
break;
|
|
case '"':
|
|
case '\'':
|
|
case '\\':
|
|
break;
|
|
}
|
|
return c;
|
|
}
|
|
|
|
private void ScanVerbatimStringLiteral(ref TokenInfo info)
|
|
{
|
|
_builder.Length = 0;
|
|
int position = TextWindow.Position;
|
|
while (TextWindow.PeekChar() == '@')
|
|
{
|
|
TextWindow.AdvanceChar();
|
|
}
|
|
if (TextWindow.Position - position >= 2)
|
|
{
|
|
AddError(position, TextWindow.Position - position, ErrorCode.ERR_IllegalAtSequence);
|
|
}
|
|
TextWindow.AdvanceChar();
|
|
while (true)
|
|
{
|
|
char c = TextWindow.PeekChar();
|
|
if (c == '"')
|
|
{
|
|
TextWindow.AdvanceChar();
|
|
if (TextWindow.PeekChar() != '"')
|
|
{
|
|
break;
|
|
}
|
|
TextWindow.AdvanceChar();
|
|
_builder.Append(c);
|
|
}
|
|
else
|
|
{
|
|
if (c == '\uffff' && TextWindow.IsReallyAtEnd())
|
|
{
|
|
AddError(ErrorCode.ERR_UnterminatedStringLit);
|
|
break;
|
|
}
|
|
TextWindow.AdvanceChar();
|
|
_builder.Append(c);
|
|
}
|
|
}
|
|
if (ScanUtf8Suffix())
|
|
{
|
|
info.Kind = SyntaxKind.Utf8StringLiteralToken;
|
|
}
|
|
else
|
|
{
|
|
info.Kind = SyntaxKind.StringLiteralToken;
|
|
}
|
|
info.Text = TextWindow.GetText(intern: false);
|
|
info.StringValue = _builder.ToString();
|
|
}
|
|
|
|
private void ScanInterpolatedStringLiteral(ref TokenInfo info)
|
|
{
|
|
ScanInterpolatedStringLiteralTop(ref info, out SyntaxDiagnosticInfo error, out InterpolatedStringKind _, out Range _, null, out Range _);
|
|
AddError(error);
|
|
}
|
|
|
|
internal void ScanInterpolatedStringLiteralTop(ref TokenInfo info, out SyntaxDiagnosticInfo? error, out InterpolatedStringKind kind, out Range openQuoteRange, ArrayBuilder<Interpolation>? interpolations, out Range closeQuoteRange)
|
|
{
|
|
InterpolatedStringScanner interpolatedStringScanner = new InterpolatedStringScanner(this);
|
|
interpolatedStringScanner.ScanInterpolatedStringLiteralTop(out kind, out openQuoteRange, interpolations, out closeQuoteRange);
|
|
error = interpolatedStringScanner.Error;
|
|
info.Kind = SyntaxKind.InterpolatedStringToken;
|
|
info.Text = TextWindow.GetText(intern: false);
|
|
}
|
|
|
|
internal static SyntaxToken RescanInterpolatedString(InterpolatedStringExpressionSyntax interpolatedString)
|
|
{
|
|
string text = ((object)interpolatedString).ToString();
|
|
SyntaxKind kind = SyntaxKind.InterpolatedStringToken;
|
|
return SyntaxFactory.Literal(interpolatedString.GetFirstToken().GetLeadingTrivia(), text, kind, text, interpolatedString.GetLastToken().GetTrailingTrivia());
|
|
}
|
|
|
|
private SyntaxToken? QuickScanSyntaxToken()
|
|
{
|
|
Start();
|
|
QuickScanState quickScanState = QuickScanState.Initial;
|
|
int num = TextWindow.Offset;
|
|
int characterWindowCount = TextWindow.CharacterWindowCount;
|
|
characterWindowCount = Math.Min(characterWindowCount, num + 42);
|
|
int num2 = -2128831035;
|
|
char[] characterWindow = TextWindow.CharacterWindow;
|
|
int length = CharProperties.Length;
|
|
while (true)
|
|
{
|
|
if (num < characterWindowCount)
|
|
{
|
|
int num3 = characterWindow[num];
|
|
CharFlags charFlags = (CharFlags)((num3 < length) ? CharProperties[num3] : 9);
|
|
quickScanState = (QuickScanState)s_stateTransitions[(uint)quickScanState, (uint)charFlags];
|
|
if ((int)quickScanState >= 9)
|
|
{
|
|
break;
|
|
}
|
|
num2 = (num2 ^ num3) * 16777619;
|
|
num++;
|
|
continue;
|
|
}
|
|
quickScanState = QuickScanState.Bad;
|
|
break;
|
|
}
|
|
TextWindow.AdvanceChar(num - TextWindow.Offset);
|
|
if (quickScanState == QuickScanState.Done)
|
|
{
|
|
return _cache.LookupToken(TextWindow.CharacterWindow, TextWindow.LexemeRelativeStart, num - TextWindow.LexemeRelativeStart, num2, _createQuickTokenFunction);
|
|
}
|
|
TextWindow.Reset(TextWindow.LexemeStartPosition);
|
|
return null;
|
|
}
|
|
|
|
private SyntaxToken CreateQuickToken()
|
|
{
|
|
TextWindow.Reset(TextWindow.LexemeStartPosition);
|
|
return LexSyntaxToken();
|
|
}
|
|
}
|