bool JSON_Parser::CompleteNumberLiteral()

in Release/src/json/json_parsing.cpp [392:544]


bool JSON_Parser<CharType>::CompleteNumberLiteral(CharType first, Token& token)
{
    bool minus_sign;

    if (first == '-')
    {
        minus_sign = true;

        // Safe to cast because the check after this if/else statement will cover EOF.
        first = static_cast<CharType>(NextCharacter());
    }
    else
    {
        minus_sign = false;
    }

    if (first < '0' || first > '9') return false;

    auto ch = PeekCharacter();

    // Check for two (or more) zeros at the beginning
    if (first == '0' && ch == '0') return false;

    // Parse the number assuming its integer
    uint64_t val64;
    bool complete = ParseInt64(first, val64);

    ch = PeekCharacter();
    if (complete && ch != '.' && ch != 'E' && ch != 'e')
    {
        if (minus_sign)
        {
            if (val64 > static_cast<uint64_t>(1) << 63)
            {
                // It is negative and cannot be represented in int64, so we resort to double
                token.double_val = 0 - static_cast<double>(val64);
                token.signed_number = true;
                token.kind = JSON_Parser<CharType>::Token::TKN_NumberLiteral;
                return true;
            }

            // It is negative, but fits into int64
            token.int64_val = 0 - static_cast<int64_t>(val64);
            token.kind = JSON_Parser<CharType>::Token::TKN_IntegerLiteral;
            token.signed_number = true;
            return true;
        }

        // It is positive so we use unsigned int64
        token.uint64_val = val64;
        token.kind = JSON_Parser<CharType>::Token::TKN_IntegerLiteral;
        token.signed_number = false;
        return true;
    }

    // Magic number 5 leaves room for decimal point, null terminator, etc (in most cases)
    ::std::vector<CharType> buf(::std::numeric_limits<uint64_t>::digits10 + 5);
    int count = print_llu(buf.data(), buf.size(), val64);
    _ASSERTE(count >= 0);
    _ASSERTE((size_t)count < buf.size());
    // Resize to cut off the null terminator
    buf.resize(count);

    bool decimal = false;

    while (ch != eof<CharType>())
    {
        // Digit encountered?
        if (ch >= '0' && ch <= '9')
        {
            buf.push_back(static_cast<CharType>(ch));
            NextCharacter();
            ch = PeekCharacter();
        }

        // Decimal dot?
        else if (ch == '.')
        {
            if (decimal) return false;

            decimal = true;
            buf.push_back(static_cast<CharType>(ch));

            NextCharacter();
            ch = PeekCharacter();

            // Check that the following char is a digit
            if (ch < '0' || ch > '9') return false;

            buf.push_back(static_cast<CharType>(ch));
            NextCharacter();
            ch = PeekCharacter();
        }

        // Exponent?
        else if (ch == 'E' || ch == 'e')
        {
            buf.push_back(static_cast<CharType>(ch));
            NextCharacter();
            ch = PeekCharacter();

            // Check for the exponent sign
            if (ch == '+')
            {
                buf.push_back(static_cast<CharType>(ch));
                NextCharacter();
                ch = PeekCharacter();
            }
            else if (ch == '-')
            {
                buf.push_back(static_cast<CharType>(ch));
                NextCharacter();
                ch = PeekCharacter();
            }

            // First number of the exponent
            if (ch >= '0' && ch <= '9')
            {
                buf.push_back(static_cast<CharType>(ch));
                NextCharacter();
                ch = PeekCharacter();
            }
            else
                return false;

            // The rest of the exponent
            while (ch >= '0' && ch <= '9')
            {
                buf.push_back(static_cast<CharType>(ch));
                NextCharacter();
                ch = PeekCharacter();
            }

            // The peeked character is not a number, so we can break from the loop and construct the number
            break;
        }
        else
        {
            // Not expected number character?
            break;
        }
    };

    buf.push_back('\0');
    token.double_val = anystod(buf.data());
    if (minus_sign)
    {
        token.double_val = -token.double_val;
    }
    token.kind = (JSON_Parser<CharType>::Token::TKN_NumberLiteral);

    return true;
}