in src/Compilers/CSharp/Portable/Parser/Lexer.cs [981:1303]
private bool ScanNumericLiteral(ref TokenInfo info)
{
int start = TextWindow.Position;
char ch;
bool isHex = false;
bool isBinary = false;
bool hasDecimal = false;
bool hasExponent = false;
info.Text = null;
info.ValueKind = SpecialType.None;
_builder.Clear();
bool hasUSuffix = false;
bool hasLSuffix = false;
bool underscoreInWrongPlace = false;
bool usedUnderscore = false;
bool firstCharWasUnderscore = false;
ch = TextWindow.PeekChar();
if (ch == '0')
{
ch = TextWindow.PeekChar(1);
if (ch == 'x' || ch == 'X')
{
TextWindow.AdvanceChar(2);
isHex = true;
}
else if (ch == 'b' || ch == 'B')
{
CheckFeatureAvailability(MessageID.IDS_FeatureBinaryLiteral);
TextWindow.AdvanceChar(2);
isBinary = true;
}
}
if (isHex || isBinary)
{
// It's OK if it has no digits after the '0x' -- we'll catch it in ScanNumericLiteral
// and give a proper error then.
ScanNumericLiteralSingleInteger(ref underscoreInWrongPlace, ref usedUnderscore, ref firstCharWasUnderscore, isHex, isBinary);
if ((ch = TextWindow.PeekChar()) == 'L' || ch == 'l')
{
if (ch == 'l')
{
this.AddError(TextWindow.Position, 1, ErrorCode.WRN_LowercaseEllSuffix);
}
TextWindow.AdvanceChar();
hasLSuffix = true;
if ((ch = TextWindow.PeekChar()) == 'u' || ch == 'U')
{
TextWindow.AdvanceChar();
hasUSuffix = true;
}
}
else if ((ch = TextWindow.PeekChar()) == 'u' || ch == 'U')
{
TextWindow.AdvanceChar();
hasUSuffix = true;
if ((ch = TextWindow.PeekChar()) == 'L' || ch == 'l')
{
TextWindow.AdvanceChar();
hasLSuffix = true;
}
}
}
else
{
ScanNumericLiteralSingleInteger(ref underscoreInWrongPlace, ref usedUnderscore, ref firstCharWasUnderscore, isHex: false, isBinary: false);
if (this.ModeIs(LexerMode.DebuggerSyntax) && TextWindow.PeekChar() == '#')
{
// Previously, in DebuggerSyntax mode, "123#" was a valid identifier.
TextWindow.AdvanceChar();
info.StringValue = info.Text = TextWindow.GetText(intern: true);
info.Kind = SyntaxKind.IdentifierToken;
this.AddError(MakeError(ErrorCode.ERR_LegacyObjectIdSyntax));
return true;
}
if ((ch = TextWindow.PeekChar()) == '.')
{
var ch2 = TextWindow.PeekChar(1);
if (ch2 >= '0' && ch2 <= '9')
{
hasDecimal = true;
_builder.Append(ch);
TextWindow.AdvanceChar();
ScanNumericLiteralSingleInteger(ref underscoreInWrongPlace, ref usedUnderscore, ref firstCharWasUnderscore, isHex: false, isBinary: false);
}
else if (_builder.Length == 0)
{
// we only have the dot so far.. (no preceding number or following number)
info.Kind = SyntaxKind.DotToken;
TextWindow.Reset(start);
return false;
}
}
if ((ch = TextWindow.PeekChar()) == 'E' || ch == 'e')
{
_builder.Append(ch);
TextWindow.AdvanceChar();
hasExponent = true;
if ((ch = TextWindow.PeekChar()) == '-' || ch == '+')
{
_builder.Append(ch);
TextWindow.AdvanceChar();
}
if (!(((ch = TextWindow.PeekChar()) >= '0' && ch <= '9') || ch == '_'))
{
// use this for now (CS0595), cant use CS0594 as we dont know 'type'
this.AddError(MakeError(ErrorCode.ERR_InvalidReal));
// add dummy exponent, so parser does not blow up
_builder.Append('0');
}
else
{
ScanNumericLiteralSingleInteger(ref underscoreInWrongPlace, ref usedUnderscore, ref firstCharWasUnderscore, isHex: false, isBinary: false);
}
}
if (hasExponent || hasDecimal)
{
if ((ch = TextWindow.PeekChar()) == 'f' || ch == 'F')
{
TextWindow.AdvanceChar();
info.ValueKind = SpecialType.System_Single;
}
else if (ch == 'D' || ch == 'd')
{
TextWindow.AdvanceChar();
info.ValueKind = SpecialType.System_Double;
}
else if (ch == 'm' || ch == 'M')
{
TextWindow.AdvanceChar();
info.ValueKind = SpecialType.System_Decimal;
}
else
{
info.ValueKind = SpecialType.System_Double;
}
}
else if ((ch = TextWindow.PeekChar()) == 'f' || ch == 'F')
{
TextWindow.AdvanceChar();
info.ValueKind = SpecialType.System_Single;
}
else if (ch == 'D' || ch == 'd')
{
TextWindow.AdvanceChar();
info.ValueKind = SpecialType.System_Double;
}
else if (ch == 'm' || ch == 'M')
{
TextWindow.AdvanceChar();
info.ValueKind = SpecialType.System_Decimal;
}
else if (ch == 'L' || ch == 'l')
{
if (ch == 'l')
{
this.AddError(TextWindow.Position, 1, ErrorCode.WRN_LowercaseEllSuffix);
}
TextWindow.AdvanceChar();
hasLSuffix = true;
if ((ch = TextWindow.PeekChar()) == 'u' || ch == 'U')
{
TextWindow.AdvanceChar();
hasUSuffix = true;
}
}
else if (ch == 'u' || ch == 'U')
{
hasUSuffix = true;
TextWindow.AdvanceChar();
if ((ch = TextWindow.PeekChar()) == 'L' || ch == 'l')
{
TextWindow.AdvanceChar();
hasLSuffix = true;
}
}
}
if (underscoreInWrongPlace)
{
this.AddError(MakeError(start, TextWindow.Position - start, 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(true);
Debug.Assert(info.Text != null);
var valueText = TextWindow.Intern(_builder);
ulong val;
switch (info.ValueKind)
{
case SpecialType.System_Single:
info.FloatValue = this.GetValueSingle(valueText);
break;
case SpecialType.System_Double:
info.DoubleValue = this.GetValueDouble(valueText);
break;
case SpecialType.System_Decimal:
info.DecimalValue = this.GetValueDecimal(valueText, start, TextWindow.Position);
break;
default:
if (string.IsNullOrEmpty(valueText))
{
if (!underscoreInWrongPlace)
{
this.AddError(MakeError(ErrorCode.ERR_InvalidNumber));
}
val = 0; //safe default
}
else
{
val = this.GetValueUInt64(valueText, isHex, isBinary);
}
// 2.4.4.2 Integer literals
// ...
// The type of an integer literal is determined as follows:
// * If the literal has no suffix, it has the first of these types in which its value can be represented: int, uint, long, ulong.
if (!hasUSuffix && !hasLSuffix)
{
if (val <= Int32.MaxValue)
{
info.ValueKind = SpecialType.System_Int32;
info.IntValue = (int)val;
}
else if (val <= UInt32.MaxValue)
{
info.ValueKind = SpecialType.System_UInt32;
info.UintValue = (uint)val;
// TODO: See below, it may be desirable to mark this token
// as special for folding if its value is 2147483648.
}
else if (val <= Int64.MaxValue)
{
info.ValueKind = SpecialType.System_Int64;
info.LongValue = (long)val;
}
else
{
info.ValueKind = SpecialType.System_UInt64;
info.UlongValue = val;
// TODO: See below, it may be desirable to mark this token
// as special for folding if its value is 9223372036854775808
}
}
else if (hasUSuffix && !hasLSuffix)
{
// * If the literal is suffixed by U or u, it has the first of these types in which its value can be represented: uint, ulong.
if (val <= UInt32.MaxValue)
{
info.ValueKind = SpecialType.System_UInt32;
info.UintValue = (uint)val;
}
else
{
info.ValueKind = SpecialType.System_UInt64;
info.UlongValue = val;
}
}
// * If the literal is suffixed by L or l, it has the first of these types in which its value can be represented: long, ulong.
else if (!hasUSuffix & hasLSuffix)
{
if (val <= Int64.MaxValue)
{
info.ValueKind = SpecialType.System_Int64;
info.LongValue = (long)val;
}
else
{
info.ValueKind = SpecialType.System_UInt64;
info.UlongValue = val;
// TODO: See below, it may be desirable to mark this token
// as special for folding if its value is 9223372036854775808
}
}
// * If the literal is suffixed by UL, Ul, uL, ul, LU, Lu, lU, or lu, it is of type ulong.
else
{
Debug.Assert(hasUSuffix && hasLSuffix);
info.ValueKind = SpecialType.System_UInt64;
info.UlongValue = val;
}
break;
// Note, the following portion of the spec is not implemented here. It is implemented
// in the unary minus analysis.
// * When a decimal-integer-literal with the value 2147483648 (231) and no integer-type-suffix appears
// as the token immediately following a unary minus operator token (§7.7.2), the result is a constant
// of type int with the value −2147483648 (−231). In all other situations, such a decimal-integer-
// literal is of type uint.
// * When a decimal-integer-literal with the value 9223372036854775808 (263) and no integer-type-suffix
// or the integer-type-suffix L or l appears as the token immediately following a unary minus operator
// token (§7.7.2), the result is a constant of type long with the value −9223372036854775808 (−263).
// In all other situations, such a decimal-integer-literal is of type ulong.
}
return true;
}