private bool ScanNumericLiteral()

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;
        }