| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519 | //     __ _____ _____ _____//  __|  |   __|     |   | |  JSON for Modern C++// |  |  |__   |  |  | | | |  version 3.11.3// |_____|_____|_____|_|___|  https://github.com/nlohmann/json//// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>// SPDX-License-Identifier: MIT#pragma once#include <cmath> // isfinite#include <cstdint> // uint8_t#include <functional> // function#include <string> // string#include <utility> // move#include <vector> // vector#include <nlohmann/detail/exceptions.hpp>#include <nlohmann/detail/input/input_adapters.hpp>#include <nlohmann/detail/input/json_sax.hpp>#include <nlohmann/detail/input/lexer.hpp>#include <nlohmann/detail/macro_scope.hpp>#include <nlohmann/detail/meta/is_sax.hpp>#include <nlohmann/detail/string_concat.hpp>#include <nlohmann/detail/value_t.hpp>NLOHMANN_JSON_NAMESPACE_BEGINnamespace detail{////////////// parser //////////////enum class parse_event_t : std::uint8_t{    /// the parser read `{` and started to process a JSON object    object_start,    /// the parser read `}` and finished processing a JSON object    object_end,    /// the parser read `[` and started to process a JSON array    array_start,    /// the parser read `]` and finished processing a JSON array    array_end,    /// the parser read a key of a value in an object    key,    /// the parser finished reading a JSON value    value};template<typename BasicJsonType>using parser_callback_t =    std::function<bool(int /*depth*/, parse_event_t /*event*/, BasicJsonType& /*parsed*/)>;/*!@brief syntax analysisThis class implements a recursive descent parser.*/template<typename BasicJsonType, typename InputAdapterType>class parser{    using number_integer_t = typename BasicJsonType::number_integer_t;    using number_unsigned_t = typename BasicJsonType::number_unsigned_t;    using number_float_t = typename BasicJsonType::number_float_t;    using string_t = typename BasicJsonType::string_t;    using lexer_t = lexer<BasicJsonType, InputAdapterType>;    using token_type = typename lexer_t::token_type;  public:    /// a parser reading from an input adapter    explicit parser(InputAdapterType&& adapter,                    const parser_callback_t<BasicJsonType> cb = nullptr,                    const bool allow_exceptions_ = true,                    const bool skip_comments = false)        : callback(cb)        , m_lexer(std::move(adapter), skip_comments)        , allow_exceptions(allow_exceptions_)    {        // read first token        get_token();    }    /*!    @brief public parser interface    @param[in] strict      whether to expect the last token to be EOF    @param[in,out] result  parsed JSON value    @throw parse_error.101 in case of an unexpected token    @throw parse_error.102 if to_unicode fails or surrogate error    @throw parse_error.103 if to_unicode fails    */    void parse(const bool strict, BasicJsonType& result)    {        if (callback)        {            json_sax_dom_callback_parser<BasicJsonType> sdp(result, callback, allow_exceptions);            sax_parse_internal(&sdp);            // in strict mode, input must be completely read            if (strict && (get_token() != token_type::end_of_input))            {                sdp.parse_error(m_lexer.get_position(),                                m_lexer.get_token_string(),                                parse_error::create(101, m_lexer.get_position(),                                                    exception_message(token_type::end_of_input, "value"), nullptr));            }            // in case of an error, return discarded value            if (sdp.is_errored())            {                result = value_t::discarded;                return;            }            // set top-level value to null if it was discarded by the callback            // function            if (result.is_discarded())            {                result = nullptr;            }        }        else        {            json_sax_dom_parser<BasicJsonType> sdp(result, allow_exceptions);            sax_parse_internal(&sdp);            // in strict mode, input must be completely read            if (strict && (get_token() != token_type::end_of_input))            {                sdp.parse_error(m_lexer.get_position(),                                m_lexer.get_token_string(),                                parse_error::create(101, m_lexer.get_position(), exception_message(token_type::end_of_input, "value"), nullptr));            }            // in case of an error, return discarded value            if (sdp.is_errored())            {                result = value_t::discarded;                return;            }        }        result.assert_invariant();    }    /*!    @brief public accept interface    @param[in] strict  whether to expect the last token to be EOF    @return whether the input is a proper JSON text    */    bool accept(const bool strict = true)    {        json_sax_acceptor<BasicJsonType> sax_acceptor;        return sax_parse(&sax_acceptor, strict);    }    template<typename SAX>    JSON_HEDLEY_NON_NULL(2)    bool sax_parse(SAX* sax, const bool strict = true)    {        (void)detail::is_sax_static_asserts<SAX, BasicJsonType> {};        const bool result = sax_parse_internal(sax);        // strict mode: next byte must be EOF        if (result && strict && (get_token() != token_type::end_of_input))        {            return sax->parse_error(m_lexer.get_position(),                                    m_lexer.get_token_string(),                                    parse_error::create(101, m_lexer.get_position(), exception_message(token_type::end_of_input, "value"), nullptr));        }        return result;    }  private:    template<typename SAX>    JSON_HEDLEY_NON_NULL(2)    bool sax_parse_internal(SAX* sax)    {        // stack to remember the hierarchy of structured values we are parsing        // true = array; false = object        std::vector<bool> states;        // value to avoid a goto (see comment where set to true)        bool skip_to_state_evaluation = false;        while (true)        {            if (!skip_to_state_evaluation)            {                // invariant: get_token() was called before each iteration                switch (last_token)                {                    case token_type::begin_object:                    {                        if (JSON_HEDLEY_UNLIKELY(!sax->start_object(static_cast<std::size_t>(-1))))                        {                            return false;                        }                        // closing } -> we are done                        if (get_token() == token_type::end_object)                        {                            if (JSON_HEDLEY_UNLIKELY(!sax->end_object()))                            {                                return false;                            }                            break;                        }                        // parse key                        if (JSON_HEDLEY_UNLIKELY(last_token != token_type::value_string))                        {                            return sax->parse_error(m_lexer.get_position(),                                                    m_lexer.get_token_string(),                                                    parse_error::create(101, m_lexer.get_position(), exception_message(token_type::value_string, "object key"), nullptr));                        }                        if (JSON_HEDLEY_UNLIKELY(!sax->key(m_lexer.get_string())))                        {                            return false;                        }                        // parse separator (:)                        if (JSON_HEDLEY_UNLIKELY(get_token() != token_type::name_separator))                        {                            return sax->parse_error(m_lexer.get_position(),                                                    m_lexer.get_token_string(),                                                    parse_error::create(101, m_lexer.get_position(), exception_message(token_type::name_separator, "object separator"), nullptr));                        }                        // remember we are now inside an object                        states.push_back(false);                        // parse values                        get_token();                        continue;                    }                    case token_type::begin_array:                    {                        if (JSON_HEDLEY_UNLIKELY(!sax->start_array(static_cast<std::size_t>(-1))))                        {                            return false;                        }                        // closing ] -> we are done                        if (get_token() == token_type::end_array)                        {                            if (JSON_HEDLEY_UNLIKELY(!sax->end_array()))                            {                                return false;                            }                            break;                        }                        // remember we are now inside an array                        states.push_back(true);                        // parse values (no need to call get_token)                        continue;                    }                    case token_type::value_float:                    {                        const auto res = m_lexer.get_number_float();                        if (JSON_HEDLEY_UNLIKELY(!std::isfinite(res)))                        {                            return sax->parse_error(m_lexer.get_position(),                                                    m_lexer.get_token_string(),                                                    out_of_range::create(406, concat("number overflow parsing '", m_lexer.get_token_string(), '\''), nullptr));                        }                        if (JSON_HEDLEY_UNLIKELY(!sax->number_float(res, m_lexer.get_string())))                        {                            return false;                        }                        break;                    }                    case token_type::literal_false:                    {                        if (JSON_HEDLEY_UNLIKELY(!sax->boolean(false)))                        {                            return false;                        }                        break;                    }                    case token_type::literal_null:                    {                        if (JSON_HEDLEY_UNLIKELY(!sax->null()))                        {                            return false;                        }                        break;                    }                    case token_type::literal_true:                    {                        if (JSON_HEDLEY_UNLIKELY(!sax->boolean(true)))                        {                            return false;                        }                        break;                    }                    case token_type::value_integer:                    {                        if (JSON_HEDLEY_UNLIKELY(!sax->number_integer(m_lexer.get_number_integer())))                        {                            return false;                        }                        break;                    }                    case token_type::value_string:                    {                        if (JSON_HEDLEY_UNLIKELY(!sax->string(m_lexer.get_string())))                        {                            return false;                        }                        break;                    }                    case token_type::value_unsigned:                    {                        if (JSON_HEDLEY_UNLIKELY(!sax->number_unsigned(m_lexer.get_number_unsigned())))                        {                            return false;                        }                        break;                    }                    case token_type::parse_error:                    {                        // using "uninitialized" to avoid "expected" message                        return sax->parse_error(m_lexer.get_position(),                                                m_lexer.get_token_string(),                                                parse_error::create(101, m_lexer.get_position(), exception_message(token_type::uninitialized, "value"), nullptr));                    }                    case token_type::end_of_input:                    {                        if (JSON_HEDLEY_UNLIKELY(m_lexer.get_position().chars_read_total == 1))                        {                            return sax->parse_error(m_lexer.get_position(),                                                    m_lexer.get_token_string(),                                                    parse_error::create(101, m_lexer.get_position(),                                                            "attempting to parse an empty input; check that your input string or stream contains the expected JSON", nullptr));                        }                        return sax->parse_error(m_lexer.get_position(),                                                m_lexer.get_token_string(),                                                parse_error::create(101, m_lexer.get_position(), exception_message(token_type::literal_or_value, "value"), nullptr));                    }                    case token_type::uninitialized:                    case token_type::end_array:                    case token_type::end_object:                    case token_type::name_separator:                    case token_type::value_separator:                    case token_type::literal_or_value:                    default: // the last token was unexpected                    {                        return sax->parse_error(m_lexer.get_position(),                                                m_lexer.get_token_string(),                                                parse_error::create(101, m_lexer.get_position(), exception_message(token_type::literal_or_value, "value"), nullptr));                    }                }            }            else            {                skip_to_state_evaluation = false;            }            // we reached this line after we successfully parsed a value            if (states.empty())            {                // empty stack: we reached the end of the hierarchy: done                return true;            }            if (states.back())  // array            {                // comma -> next value                if (get_token() == token_type::value_separator)                {                    // parse a new value                    get_token();                    continue;                }                // closing ]                if (JSON_HEDLEY_LIKELY(last_token == token_type::end_array))                {                    if (JSON_HEDLEY_UNLIKELY(!sax->end_array()))                    {                        return false;                    }                    // We are done with this array. Before we can parse a                    // new value, we need to evaluate the new state first.                    // By setting skip_to_state_evaluation to false, we                    // are effectively jumping to the beginning of this if.                    JSON_ASSERT(!states.empty());                    states.pop_back();                    skip_to_state_evaluation = true;                    continue;                }                return sax->parse_error(m_lexer.get_position(),                                        m_lexer.get_token_string(),                                        parse_error::create(101, m_lexer.get_position(), exception_message(token_type::end_array, "array"), nullptr));            }            // states.back() is false -> object            // comma -> next value            if (get_token() == token_type::value_separator)            {                // parse key                if (JSON_HEDLEY_UNLIKELY(get_token() != token_type::value_string))                {                    return sax->parse_error(m_lexer.get_position(),                                            m_lexer.get_token_string(),                                            parse_error::create(101, m_lexer.get_position(), exception_message(token_type::value_string, "object key"), nullptr));                }                if (JSON_HEDLEY_UNLIKELY(!sax->key(m_lexer.get_string())))                {                    return false;                }                // parse separator (:)                if (JSON_HEDLEY_UNLIKELY(get_token() != token_type::name_separator))                {                    return sax->parse_error(m_lexer.get_position(),                                            m_lexer.get_token_string(),                                            parse_error::create(101, m_lexer.get_position(), exception_message(token_type::name_separator, "object separator"), nullptr));                }                // parse values                get_token();                continue;            }            // closing }            if (JSON_HEDLEY_LIKELY(last_token == token_type::end_object))            {                if (JSON_HEDLEY_UNLIKELY(!sax->end_object()))                {                    return false;                }                // We are done with this object. Before we can parse a                // new value, we need to evaluate the new state first.                // By setting skip_to_state_evaluation to false, we                // are effectively jumping to the beginning of this if.                JSON_ASSERT(!states.empty());                states.pop_back();                skip_to_state_evaluation = true;                continue;            }            return sax->parse_error(m_lexer.get_position(),                                    m_lexer.get_token_string(),                                    parse_error::create(101, m_lexer.get_position(), exception_message(token_type::end_object, "object"), nullptr));        }    }    /// get next token from lexer    token_type get_token()    {        return last_token = m_lexer.scan();    }    std::string exception_message(const token_type expected, const std::string& context)    {        std::string error_msg = "syntax error ";        if (!context.empty())        {            error_msg += concat("while parsing ", context, ' ');        }        error_msg += "- ";        if (last_token == token_type::parse_error)        {            error_msg += concat(m_lexer.get_error_message(), "; last read: '",                                m_lexer.get_token_string(), '\'');        }        else        {            error_msg += concat("unexpected ", lexer_t::token_type_name(last_token));        }        if (expected != token_type::uninitialized)        {            error_msg += concat("; expected ", lexer_t::token_type_name(expected));        }        return error_msg;    }  private:    /// callback function    const parser_callback_t<BasicJsonType> callback = nullptr;    /// the type of the last read token    token_type last_token = token_type::uninitialized;    /// the lexer    lexer_t m_lexer;    /// whether to throw exceptions in case of errors    const bool allow_exceptions = true;};}  // namespace detailNLOHMANN_JSON_NAMESPACE_END
 |