private JSToken ScanNumber()

in AjaxMinDll/JavaScript/jsscanner.cs [1878:2038]


        private JSToken ScanNumber(char leadChar)
        {
            bool noMoreDot = '.' == leadChar;
            JSToken token = noMoreDot ? JSToken.NumericLiteral : JSToken.IntegerLiteral;
            bool exponent = false;
            char c;
            m_literalIssues = false;

            if ('0' == leadChar)
            {
                // c is now the character AFTER the leading zero
                c = GetChar(m_currentPosition);
                if ('x' == c || 'X' == c)
                {
                    if (JSScanner.IsHexDigit(GetChar(m_currentPosition + 1)))
                    {
                        while (JSScanner.IsHexDigit(GetChar(++m_currentPosition)))
                        {
                            // empty
                        }
                    }

                    return CheckForNumericBadEnding(token);
                }
                else if ('b' == c || 'B' == c)
                {
                    // ES6 binary literal?
                    c = GetChar(m_currentPosition + 1);
                    if (c == '1' || c == '0')
                    {
                        while ('0' == (c = GetChar(++m_currentPosition)) || c == '1')
                        {
                            // iterator handled in the condition
                        }
                    }

                    return CheckForNumericBadEnding(token);
                }
                else if ('o' == c || 'O' == c)
                {
                    // ES6 octal literal?
                    c = GetChar(m_currentPosition + 1);
                    if ('0' <= c && c <= '7')
                    {
                        while ('0' <= (c = GetChar(++m_currentPosition)) && c <= '7')
                        {
                            // iterator handled in the condition
                        }
                    }

                    return CheckForNumericBadEnding(token);
                }
                else if ('0' <= c && c <= '7')
                {
                    // this is a zero followed by a digit between 0 and 7.
                    // This could be interpreted as an octal literal, which isn't strictly supported.
                    while ('0' <= c && c <= '7')
                    {
                        c = GetChar(++m_currentPosition);
                    }

                    // bad octal?
                    if (IsDigit(c) && '7' < c)
                    {
                        // bad octal. Skip any other digits, throw an error, mark it has having issues
                        m_literalIssues = true;
                        while ('0' <= c && c <= '9')
                        {
                            c = GetChar(++m_currentPosition);
                        }

                        HandleError(JSError.BadNumericLiteral);
                    }

                    // return the integer token with issues, which should cause it to be output
                    // as-is and not combined with other literals or anything.
                    m_literalIssues = true;
                    HandleError(JSError.OctalLiteralsDeprecated);
                    return token;
                }
                else if (c != 'e' && c != 'E' && IsValidIdentifierStart(m_strSourceCode, m_currentPosition))
                {
                    // invalid for an integer (in this case '0') the be followed by
                    // an identifier part. The 'e' is okay, though, because that will
                    // be the exponent part.
                    // we know the 0 and the next character are both invalid, so skip them and 
                    // anything else after it that's identifier-like, and throw an error.
                    return CheckForNumericBadEnding(token);
                }
            }

            for (;;)
            {
                c = GetChar(m_currentPosition);
                if (!IsDigit(c))
                {
                    if ('.' == c)
                    {
                        if (noMoreDot)
                        {
                            break;
                        }

                        noMoreDot = true;
                        token = JSToken.NumericLiteral;
                    }
                    else if ('e' == c || 'E' == c)
                    {
                        if (exponent)
                        {
                            break;
                        }

                        exponent = noMoreDot = true;
                        token = JSToken.NumericLiteral;
                    }
                    else if ('+' == c || '-' == c)
                    {
                        char e = GetChar(m_currentPosition - 1);
                        if ('e' != e && 'E' != e)
                        {
                            break;
                        }
                    }
                    else
                    {
                        break;
                    }
                }

                m_currentPosition++;
            }

            // get the last character of the number
            c = GetChar(m_currentPosition - 1);
            if ('+' == c || '-' == c)
            {
                // if it's a + or -, then it's not part of the number; back it up one
                m_currentPosition--;
                c = GetChar(m_currentPosition - 1);
            }

            if ('e' == c || 'E' == c)
            {
                // if it's an e, it's not part of the number; back it up one
                m_currentPosition--;
                c = GetChar(m_currentPosition - 1);
            }

            if (token == JSToken.NumericLiteral && c == '.')
            {
                // if we thought this was a numeric value and not an integer, but the last
                // value was the decimal point, treat it as an integer.
                token = JSToken.IntegerLiteral;
            }

            // it is invalid for a numeric literal to be immediately followed by another
            // digit or an identifier start character. So check for those and return an
            // invalid numeric literal if true.
            return CheckForNumericBadEnding(token);
        }