Merge remote-tracking branch 'origin/develop' into claude/fix-issue-3989-db7e45

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
This commit is contained in:
Niels Lohmann committed 2026-10-11 08:33:14 +02:00
commit 545477ffa8
116 files changed
+4199 -2405

No files matched your search

+73 -189
View File
@@ -37,196 +37,15 @@ using nlohmann::json;
#include <utility>
#include <vector>
#include "sax_countdown.hpp"
#include "sax_event_loggers.hpp"
#include "test_utils.hpp"
using utils::SaxCountdown;
using utils::SaxEventLogger;
namespace
{
class SaxEventLogger
{
public:
bool null()
{
events.emplace_back("null()");
return true;
}
bool boolean(bool val)
{
events.emplace_back(val ? "boolean(true)" : "boolean(false)");
return true;
}
bool number_integer(json::number_integer_t val)
{
events.push_back("number_integer(" + std::to_string(val) + ")");
return true;
}
bool number_unsigned(json::number_unsigned_t val)
{
events.push_back("number_unsigned(" + std::to_string(val) + ")");
return true;
}
bool number_float(json::number_float_t /*unused*/, const std::string& s)
{
events.push_back("number_float(" + s + ")");
return true;
}
bool string(std::string& val)
{
events.push_back("string(" + val + ")");
return true;
}
bool binary(json::binary_t& val)
{
std::string binary_contents = "binary(";
std::string comma_space;
for (auto b : val)
{
binary_contents.append(comma_space);
binary_contents.append(std::to_string(static_cast<int>(b)));
comma_space = ", ";
}
binary_contents.append(")");
events.push_back(binary_contents);
return true;
}
bool start_object(std::size_t elements)
{
if (elements == (std::numeric_limits<std::size_t>::max)())
{
events.emplace_back("start_object()");
}
else
{
events.push_back("start_object(" + std::to_string(elements) + ")");
}
return true;
}
bool key(std::string& val)
{
events.push_back("key(" + val + ")");
return true;
}
bool end_object()
{
events.emplace_back("end_object()");
return true;
}
bool start_array(std::size_t elements)
{
if (elements == (std::numeric_limits<std::size_t>::max)())
{
events.emplace_back("start_array()");
}
else
{
events.push_back("start_array(" + std::to_string(elements) + ")");
}
return true;
}
bool end_array()
{
events.emplace_back("end_array()");
return true;
}
bool parse_error(std::size_t position, const std::string& /*unused*/, const json::exception& /*unused*/)
{
errored = true;
events.push_back("parse_error(" + std::to_string(position) + ")");
return recover;
}
std::vector<std::string> events {}; // NOLINT(readability-redundant-member-init)
bool errored = false;
/// whether parse_error() asks the parser to recover from the error (see #3989)
bool recover = false;
};
class SaxCountdown : public nlohmann::json::json_sax_t
{
public:
explicit SaxCountdown(const int count) : events_left(count)
{}
bool null() override
{
return events_left-- > 0;
}
bool boolean(bool /*val*/) override
{
return events_left-- > 0;
}
bool number_integer(json::number_integer_t /*val*/) override
{
return events_left-- > 0;
}
bool number_unsigned(json::number_unsigned_t /*val*/) override
{
return events_left-- > 0;
}
bool number_float(json::number_float_t /*val*/, const std::string& /*s*/) override
{
return events_left-- > 0;
}
bool string(std::string& /*val*/) override
{
return events_left-- > 0;
}
bool binary(json::binary_t& /*val*/) override
{
return events_left-- > 0;
}
bool start_object(std::size_t /*elements*/) override
{
return events_left-- > 0;
}
bool key(std::string& /*val*/) override
{
return events_left-- > 0;
}
bool end_object() override
{
return events_left-- > 0;
}
bool start_array(std::size_t /*elements*/) override
{
return events_left-- > 0;
}
bool end_array() override
{
return events_left-- > 0;
}
bool parse_error(std::size_t /*position*/, const std::string& /*last_token*/, const json::exception& /*ex*/) override
{
return false;
}
private:
int events_left = 0;
};
json parser_helper(const std::string& s);
bool accept_helper(const std::string& s);
void comments_helper(const std::string& s);
@@ -3197,15 +3016,80 @@ RecoveryResult parse_recovering(InputType&& input, const bool strict = true,
}
/// stops after a number of events, but recovers from errors
class RecoveringCountdown : public SaxCountdown
class RecoveringCountdown
{
public:
using SaxCountdown::SaxCountdown;
explicit RecoveringCountdown(const int count)
: countdown(count)
{}
bool parse_error(std::size_t /*position*/, const std::string& /*last_token*/, const json::exception& /*ex*/) override
bool null()
{
return countdown.null();
}
bool boolean(bool val)
{
return countdown.boolean(val);
}
bool number_integer(json::number_integer_t val)
{
return countdown.number_integer(val);
}
bool number_unsigned(json::number_unsigned_t val)
{
return countdown.number_unsigned(val);
}
bool number_float(json::number_float_t val, const std::string& s)
{
return countdown.number_float(val, s);
}
bool string(std::string& val)
{
return countdown.string(val);
}
bool binary(json::binary_t& val)
{
return countdown.binary(val);
}
bool start_object(std::size_t elements)
{
return countdown.start_object(elements);
}
bool key(std::string& val)
{
return countdown.key(val);
}
bool end_object()
{
return countdown.end_object();
}
bool start_array(std::size_t elements)
{
return countdown.start_array(elements);
}
bool end_array()
{
return countdown.end_array();
}
bool parse_error(std::size_t /*position*/, const std::string& /*last_token*/, const json::exception& /*ex*/) // NOLINT(readability-convert-member-functions-to-static)
{
return true;
}
private:
SaxCountdown countdown;
};
/// a repaired input: the value it is repaired to, and the number of errors