Read-only mirrors. Development, issues and pull requests are on GitHub.

summaryrefslogtreecommitdiffhomepage
path: root/extras/catch_amalgamated.cpp
diff options
context:
space:
mode:
authorLeitwolf2026-10-29 12:18:33 +0300
committerGitHub2026-10-29 12:18:33 +0300
commit1d48419b7ef642917ebf7dfd16c3bc1b3050d8f1 (patch)
tree2e3327fb973f9560b5067d654f3a21ff12a821aa /extras/catch_amalgamated.cpp
parentd2e3e074bb2e1b8ffd9fc990d0b87667ea602f58 (diff)
parent30176b75937e87eafbb4f5557eb0be9697753ddf (diff)
downloadcatch3-1d48419b7ef642917ebf7dfd16c3bc1b3050d8f1.tar.gz
Merge pull request #19 from Progmasoft/feature/yyjson-pugixml
Read and write JSON with yyjson and JUnit XML with pugixml
Diffstat (limited to 'extras/catch_amalgamated.cpp')
-rw-r--r--extras/catch_amalgamated.cpp941
1 files changed, 241 insertions, 700 deletions
diff --git a/extras/catch_amalgamated.cpp b/extras/catch_amalgamated.cpp
index 0f336b53..a9cdb04b 100644
--- a/extras/catch_amalgamated.cpp
+++ b/extras/catch_amalgamated.cpp
@@ -7,7 +7,7 @@
// SPDX-License-Identifier: BSL-1.0
// Catch3 v0.3.0, on the Catch2 v3.16.1 engine
-// Generated: 2026-10-25 02:37:10.065190
+// Generated: 2026-10-25 13:52:54.556111
// ----------------------------------------------------------
// This file is an amalgamation of multiple different files.
// You probably shouldn't edit it directly.
@@ -658,9 +658,6 @@ namespace Progmasoft::Catch3::Runner
private:
void
- Write(std::string &output, int indent, int depth) const;
-
- void
Destroy() noexcept;
void
@@ -8976,6 +8973,8 @@ namespace Progmasoft::Catch3
// Copyright (c) 2026 Progmasoft.
// SPDX-License-Identifier: MPL-2.0 WITH AdditionRef-Progmasoft-Exception-1.1
+#include "catch_amalgamated_third_party.hpp"
+
#include <ostream>
#include <sstream>
#include <string_view>
@@ -9055,63 +9054,50 @@ namespace Progmasoft::Catch3
(value >= 0x10000 && value <= 0x10FFFF);
}
- void
- WriteEscaped(std::string_view value, std::ostream &output, bool attribute)
+ /// The text as XML can hold it: every byte that is not part of a
+ /// well-formed character XML allows becomes U+FFFD, replaced and not
+ /// dropped, so the reader sees that something was there. pugixml
+ /// escapes the rest.
+ std::string
+ XmlText(std::string_view value)
{
+ std::string result;
+ result.reserve(value.size());
for (std::size_t index = 0; index < value.size();)
{
const DecodedCharacter character = DecodeUtf8(value, index);
if (character.length == 0 || !IsXmlCharacter(character.value))
{
- // A character XML cannot hold is replaced, not dropped,
- // so the reader sees that something was there.
- output << "&#xFFFD;";
+ result += "\xEF\xBF\xBD";
++index;
continue;
}
- if (character.value < 0x80)
- {
- switch (static_cast<char>(character.value))
- {
- case '&':
- output << "&amp;";
- break;
- case '<':
- output << "&lt;";
- break;
- case '>':
- output << "&gt;";
- break;
- case '"':
- output << (attribute ? "&quot;" : "\"");
- break;
- case '\'':
- output << (attribute ? "&apos;" : "'");
- break;
- case '\n':
- output << (attribute ? "&#10;" : "\n");
- break;
- default:
- output.put(static_cast<char>(character.value));
- }
- }
- else
- {
- output.write(value.data() + index,
- static_cast<std::streamsize>(character.length));
- }
+ result.append(value.data() + index, character.length);
index += character.length;
}
+ return result;
}
void
- WriteAttribute(std::ostream &output,
- std::string_view name,
+ AddAttribute(pugi::xml_node node,
+ const char *name,
+ std::string_view value)
+ {
+ node.append_attribute(name).set_value(XmlText(value).c_str());
+ }
+
+ void
+ AddText(pugi::xml_node node, std::string_view value)
+ {
+ node.text().set(XmlText(value).c_str());
+ }
+
+ void
+ AddTextElement(pugi::xml_node parent,
+ const char *name,
std::string_view value)
{
- output << ' ' << name << "=\"";
- WriteEscaped(value, output, true);
- output << '"';
+ AddText(parent.append_child(name), value);
}
std::string
@@ -9125,27 +9111,6 @@ namespace Progmasoft::Catch3
"." + fraction;
}
- void
- WriteIndent(std::ostream &output, unsigned level)
- {
- for (unsigned index = 0; index < level; ++index)
- {
- output << " ";
- }
- }
-
- void
- WriteTextElement(std::ostream &output,
- unsigned indent,
- std::string_view name,
- std::string_view value)
- {
- WriteIndent(output, indent);
- output << '<' << name << '>';
- WriteEscaped(value, output, false);
- output << "</" << name << ">\n";
- }
-
std::string
Output(const Attempt &attempt, bool errors)
{
@@ -9159,27 +9124,22 @@ namespace Progmasoft::Catch3
/// An earlier attempt: `<rerunFailure>` before a final failure,
/// `<flakyFailure>` before a final pass.
void
- WriteEarlierAttempt(std::ostream &output,
- const Attempt &attempt,
- std::string_view element)
- {
- WriteIndent(output, 3);
- output << '<' << element;
- WriteAttribute(output, "message", SummarizeFailure(attempt));
- WriteAttribute(output, "type", CategoryName(attempt.category));
- output << ">\n";
- WriteTextElement(output, 4, "stackTrace", DescribeFailure(attempt));
+ AddEarlierAttempt(pugi::xml_node testCase,
+ const Attempt &attempt,
+ const char *element)
+ {
+ pugi::xml_node node = testCase.append_child(element);
+ AddAttribute(node, "message", SummarizeFailure(attempt));
+ AddAttribute(node, "type", CategoryName(attempt.category));
+ AddTextElement(node, "stackTrace", DescribeFailure(attempt));
if (!attempt.standardOutput.empty())
{
- WriteTextElement(
- output, 4, "system-out", Output(attempt, false));
+ AddTextElement(node, "system-out", Output(attempt, false));
}
if (!Output(attempt, true).empty())
{
- WriteTextElement(output, 4, "system-err", Output(attempt, true));
+ AddTextElement(node, "system-err", Output(attempt, true));
}
- WriteIndent(output, 3);
- output << "</" << element << ">\n";
}
std::string
@@ -9200,23 +9160,21 @@ namespace Progmasoft::Catch3
}
void
- WriteTestCase(std::ostream &output,
- const TestResult &test,
- std::string_view suiteName)
- {
- WriteIndent(output, 2);
- output << "<testcase";
- WriteAttribute(output,
- "classname",
- test.className.empty() ? suiteName : test.className);
- WriteAttribute(output, "name", test.name);
- WriteAttribute(output, "time", JUnitSeconds(test.DurationMicroseconds()));
+ AddTestCase(pugi::xml_node suite,
+ const TestResult &test,
+ std::string_view suiteName)
+ {
+ pugi::xml_node node = suite.append_child("testcase");
+ AddAttribute(node,
+ "classname",
+ test.className.empty() ? suiteName : test.className);
+ AddAttribute(node, "name", test.name);
+ AddAttribute(node, "time", JUnitSeconds(test.DurationMicroseconds()));
if (!test.file.empty())
{
- WriteAttribute(output, "file", test.file);
- WriteAttribute(output, "line", std::to_string(test.line));
+ AddAttribute(node, "file", test.file);
+ AddAttribute(node, "line", std::to_string(test.line));
}
- output << ">\n";
const Attempt *last =
test.attempts.empty() ? nullptr : &test.attempts.back();
@@ -9226,12 +9184,10 @@ namespace Progmasoft::Catch3
const bool error = test.outcome != Outcome::kFailed ||
last->category ==
FailureCategory::kInfrastructure;
- const std::string_view element = error ? "error" : "failure";
- WriteIndent(output, 3);
- output << '<' << element;
- WriteAttribute(output, "message", SummarizeFailure(*last));
- WriteAttribute(output, "type", CategoryName(test.category));
- output << '>';
+ pugi::xml_node failure =
+ node.append_child(error ? "error" : "failure");
+ AddAttribute(failure, "message", SummarizeFailure(*last));
+ AddAttribute(failure, "type", CategoryName(test.category));
std::string details = DescribeFailure(*last);
for (const auto &finding : test.analysis)
{
@@ -9241,18 +9197,15 @@ namespace Progmasoft::Catch3
{
details += "replay: " + test.replayCommand + "\n";
}
- WriteEscaped(details, output, false);
- output << "</" << element << ">\n";
+ AddText(failure, details);
}
else if (test.outcome == Outcome::kSkipped ||
test.outcome == Outcome::kBlocked ||
test.outcome == Outcome::kNotRun ||
test.outcome == Outcome::kUpToDate)
{
- WriteIndent(output, 3);
- output << "<skipped";
- WriteAttribute(output, "message", SkipReason(test));
- output << "/>\n";
+ AddAttribute(
+ node.append_child("skipped"), "message", SkipReason(test));
}
// Every earlier failed attempt, so retries stay visible.
for (std::size_t index = 0; index + 1 < test.attempts.size();
@@ -9263,20 +9216,36 @@ namespace Progmasoft::Catch3
{
continue;
}
- WriteEarlierAttempt(output,
- attempt,
- failedRun ? "rerunFailure" : "flakyFailure");
+ AddEarlierAttempt(node,
+ attempt,
+ failedRun ? "rerunFailure" : "flakyFailure");
}
if (last != nullptr && !last->standardOutput.empty())
{
- WriteTextElement(output, 3, "system-out", Output(*last, false));
+ AddTextElement(node, "system-out", Output(*last, false));
}
if (last != nullptr && !Output(*last, true).empty())
{
- WriteTextElement(output, 3, "system-err", Output(*last, true));
+ AddTextElement(node, "system-err", Output(*last, true));
}
- WriteIndent(output, 2);
- output << "</testcase>\n";
+ }
+
+ void
+ AddCounts(pugi::xml_node node,
+ const RunResult &run,
+ const RunSummary &summary)
+ {
+ AddAttribute(node, "name", run.binary);
+ AddAttribute(node, "tests", std::to_string(summary.tests));
+ AddAttribute(node, "failures", std::to_string(summary.failed));
+ AddAttribute(node,
+ "errors",
+ std::to_string(summary.crashed + summary.timedOut));
+ AddAttribute(node,
+ "skipped",
+ std::to_string(summary.skipped + summary.blocked +
+ summary.notRun + summary.upToDate));
+ AddAttribute(node, "time", JUnitSeconds(run.wallMicroseconds));
}
} // namespace
@@ -9284,38 +9253,21 @@ namespace Progmasoft::Catch3
JUnitXmlWriter::Write(const RunResult &run, std::ostream &output)
{
const RunSummary summary = Summarize(run);
- const std::size_t errors = summary.crashed + summary.timedOut;
- const std::size_t failures = summary.failed;
- const std::size_t skipped =
- summary.skipped + summary.blocked + summary.notRun +
- summary.upToDate;
- const std::string time = JUnitSeconds(run.wallMicroseconds);
- output << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<testsuites";
- WriteAttribute(output, "name", run.binary);
- WriteAttribute(output, "tests", std::to_string(summary.tests));
- WriteAttribute(output, "failures", std::to_string(failures));
- WriteAttribute(output, "errors", std::to_string(errors));
- WriteAttribute(output, "skipped", std::to_string(skipped));
- WriteAttribute(output, "time", time);
- output << ">\n";
- WriteIndent(output, 1);
- output << "<testsuite";
- WriteAttribute(output, "name", run.binary);
- WriteAttribute(output, "tests", std::to_string(summary.tests));
- WriteAttribute(output, "failures", std::to_string(failures));
- WriteAttribute(output, "errors", std::to_string(errors));
- WriteAttribute(output, "skipped", std::to_string(skipped));
- WriteAttribute(output, "time", time);
- output << ">\n";
- WriteIndent(output, 2);
- output << "<properties>\n";
- const auto property = [&](std::string_view name,
- const std::string &value) {
- WriteIndent(output, 3);
- output << "<property";
- WriteAttribute(output, "name", name);
- WriteAttribute(output, "value", value);
- output << "/>\n";
+ pugi::xml_document document;
+ pugi::xml_node declaration =
+ document.append_child(pugi::node_declaration);
+ declaration.append_attribute("version").set_value("1.0");
+ declaration.append_attribute("encoding").set_value("UTF-8");
+
+ pugi::xml_node suites = document.append_child("testsuites");
+ AddCounts(suites, run, summary);
+ pugi::xml_node suite = suites.append_child("testsuite");
+ AddCounts(suite, run, summary);
+ pugi::xml_node properties = suite.append_child("properties");
+ const auto property = [&](const char *name, const std::string &value) {
+ pugi::xml_node node = properties.append_child("property");
+ AddAttribute(node, "name", name);
+ AddAttribute(node, "value", value);
};
property("random-seed", std::to_string(run.seed));
property("workers", std::to_string(run.workers));
@@ -9327,14 +9279,12 @@ namespace Progmasoft::Catch3
}
property("flaky", std::to_string(summary.flaky));
property("quarantined", std::to_string(summary.quarantined));
- WriteIndent(output, 2);
- output << "</properties>\n";
for (const auto &test : run.tests)
{
- WriteTestCase(output, test, run.binary);
+ AddTestCase(suite, test, run.binary);
}
- WriteIndent(output, 1);
- output << "</testsuite>\n</testsuites>\n";
+
+ document.save(output, " ", pugi::format_indent, pugi::encoding_utf8);
return static_cast<bool>(output);
}
@@ -12180,12 +12130,9 @@ namespace Progmasoft::Catch3::Runner
// Copyright (c) 2026 Progmasoft.
// SPDX-License-Identifier: MPL-2.0 WITH AdditionRef-Progmasoft-Exception-1.1
-#include <clocale>
+
#include <cmath>
-#include <cstdio>
#include <cstdlib>
-#include <limits>
-#include <optional>
namespace Progmasoft::Catch3::Runner
{
@@ -12223,481 +12170,160 @@ namespace Progmasoft::Catch3::Runner
}
/// Documents nested deeper than this are refused, so a hostile or
- /// broken file cannot exhaust the stack of the parser.
+ /// broken file cannot exhaust the stack while it is converted.
constexpr int kMaximumDepth = 256;
- void
- AppendUtf8(std::string &output, std::uint32_t codePoint)
- {
- if (codePoint < 0x80)
- {
- output.push_back(static_cast<char>(codePoint));
- }
- else if (codePoint < 0x800)
- {
- output.push_back(static_cast<char>(0xC0 | (codePoint >> 6)));
- output.push_back(static_cast<char>(0x80 | (codePoint & 0x3F)));
- }
- else if (codePoint < 0x10000)
- {
- output.push_back(static_cast<char>(0xE0 | (codePoint >> 12)));
- output.push_back(
- static_cast<char>(0x80 | ((codePoint >> 6) & 0x3F)));
- output.push_back(static_cast<char>(0x80 | (codePoint & 0x3F)));
- }
- else
- {
- output.push_back(static_cast<char>(0xF0 | (codePoint >> 18)));
- output.push_back(
- static_cast<char>(0x80 | ((codePoint >> 12) & 0x3F)));
- output.push_back(
- static_cast<char>(0x80 | ((codePoint >> 6) & 0x3F)));
- output.push_back(static_cast<char>(0x80 | (codePoint & 0x3F)));
- }
- }
+ /// Strings are bytes: test names and output need not be UTF-8, and
+ /// they come back as they were written.
+ constexpr yyjson_read_flag kReadFlags =
+ YYJSON_READ_ALLOW_INVALID_UNICODE;
- /// Reads a JSON number exactly. The grammar is checked here; strtod
- /// does the rounding, with the point replaced by the decimal
- /// separator of the current locale, which a test may have changed.
- std::optional<double>
- ToDouble(std::string_view digits)
- {
- std::size_t index = 0;
- const auto skipDigits = [&] {
- const std::size_t start = index;
- while (index < digits.size() && digits[index] >= '0' &&
- digits[index] <= '9')
- {
- ++index;
- }
- return index > start;
- };
- if (index < digits.size() && digits[index] == '-')
- {
- ++index;
- }
- if (!skipDigits())
- {
- return std::nullopt;
- }
- std::size_t point = std::string_view::npos;
- if (index < digits.size() && digits[index] == '.')
- {
- point = index++;
- if (!skipDigits())
- {
- return std::nullopt;
- }
- }
- if (index < digits.size() &&
- (digits[index] == 'e' || digits[index] == 'E'))
- {
- ++index;
- if (index < digits.size() &&
- (digits[index] == '+' || digits[index] == '-'))
- {
- ++index;
- }
- if (!skipDigits())
- {
- return std::nullopt;
- }
- }
- if (index != digits.size())
- {
- return std::nullopt;
- }
- std::string copy{digits};
- if (point != std::string_view::npos)
- {
- const char *separator = std::localeconv()->decimal_point;
- copy.replace(point,
- 1,
- separator == nullptr || *separator == '\0'
- ? "."
- : separator);
- }
- return std::strtod(copy.c_str(), nullptr);
- }
+ /// JSON has no infinities; null is the conventional stand-in.
+ constexpr yyjson_write_flag kWriteFlags =
+ YYJSON_WRITE_ALLOW_INVALID_UNICODE |
+ YYJSON_WRITE_INF_AND_NAN_AS_NULL;
- class Parser final
+ /// Converts a value of yyjson's tree; false when it is nested too
+ /// deeply.
+ bool
+ FromYyjson(yyjson_val *value, int depth, JsonValue &result)
{
- public:
- explicit Parser(std::string_view text)
- : text_{text}
+ if (depth > kMaximumDepth)
{
+ return false;
}
-
- Expected<JsonValue>
- ParseDocument()
- {
- SkipWhitespace();
- auto value = ParseValue(0);
- if (!value)
- {
- return value;
- }
- SkipWhitespace();
- if (position_ != text_.size())
- {
- return Fail("unexpected text after the value");
- }
- return value;
- }
-
- private:
- Error
- Fail(const std::string &message) const
- {
- return Error{"invalid JSON at offset " +
- std::to_string(position_) + ": " + message};
- }
-
- void
- SkipWhitespace()
+ switch (yyjson_get_type(value))
{
- while (position_ < text_.size())
+ case YYJSON_TYPE_BOOL:
+ result = JsonValue{yyjson_get_bool(value)};
+ return true;
+ case YYJSON_TYPE_NUM:
+ result = JsonValue{yyjson_get_num(value)};
+ return true;
+ case YYJSON_TYPE_STR:
+ result = JsonValue{std::string_view{
+ yyjson_get_str(value), yyjson_get_len(value)}};
+ return true;
+ case YYJSON_TYPE_ARR:
{
- const char character = text_[position_];
- if (character != ' ' && character != '\t' &&
- character != '\n' && character != '\r')
+ JsonValue array = JsonValue::Array();
+ auto &items = array.MutableItems();
+ items.reserve(yyjson_arr_size(value));
+ yyjson_arr_iter iterator = yyjson_arr_iter_with(value);
+ while (yyjson_val *item = yyjson_arr_iter_next(&iterator))
{
- return;
+ items.emplace_back();
+ if (!FromYyjson(item, depth + 1, items.back()))
+ {
+ return false;
+ }
}
- ++position_;
- }
- }
-
- bool
- Consume(std::string_view word)
- {
- if (text_.substr(position_, word.size()) == word)
- {
- position_ += word.size();
+ result = std::move(array);
return true;
}
- return false;
- }
-
- Expected<JsonValue>
- ParseValue(int depth)
- {
- if (depth > kMaximumDepth)
- {
- return Fail("nested too deeply");
- }
- if (position_ >= text_.size())
- {
- return Fail("a value was expected");
- }
- const char character = text_[position_];
- if (character == '{')
- {
- return ParseObject(depth);
- }
- if (character == '[')
- {
- return ParseArray(depth);
- }
- if (character == '"')
+ case YYJSON_TYPE_OBJ:
{
- auto text = ParseString();
- if (!text)
+ JsonValue object = JsonValue::Object();
+ auto &members = object.MutableMembers();
+ members.reserve(yyjson_obj_size(value));
+ yyjson_obj_iter iterator = yyjson_obj_iter_with(value);
+ while (yyjson_val *key = yyjson_obj_iter_next(&iterator))
{
- return text.GetError();
+ members.emplace_back(
+ std::string{yyjson_get_str(key),
+ yyjson_get_len(key)},
+ JsonValue{});
+ if (!FromYyjson(yyjson_obj_iter_get_val(key),
+ depth + 1,
+ members.back().second))
+ {
+ return false;
+ }
}
- return JsonValue{std::move(*text)};
- }
- if (Consume("true"))
- {
- return JsonValue{true};
- }
- if (Consume("false"))
- {
- return JsonValue{false};
- }
- if (Consume("null"))
- {
- return JsonValue{};
+ result = std::move(object);
+ return true;
}
- return ParseNumber();
+ default:
+ result = JsonValue{};
+ return true;
}
+ }
- Expected<JsonValue>
- ParseNumber()
+ /// A whole number within the exact range of a double is written as
+ /// an integer, anything else as the shortest text that reads back as
+ /// the same double.
+ yyjson_mut_val *
+ ToYyjsonNumber(yyjson_mut_doc *document, double value)
+ {
+ if (std::isfinite(value) &&
+ std::fabs(value) < 9.007199254740992e15 &&
+ value == std::trunc(value))
{
- const std::size_t start = position_;
- if (position_ < text_.size() && text_[position_] == '-')
- {
- ++position_;
- }
- while (position_ < text_.size())
- {
- const char character = text_[position_];
- const bool numeric =
- (character >= '0' && character <= '9') ||
- character == '.' || character == 'e' ||
- character == 'E' || character == '+' ||
- character == '-';
- if (!numeric)
- {
- break;
- }
- ++position_;
- }
- if (position_ == start)
- {
- return Fail("a value was expected");
- }
- const std::string_view digits =
- text_.substr(start, position_ - start);
- const auto value = ToDouble(digits);
- if (!value)
- {
- position_ = start;
- return Fail("malformed number");
- }
- return JsonValue{*value};
+ return yyjson_mut_sint(document,
+ static_cast<std::int64_t>(value));
}
+ return yyjson_mut_real(document, value);
+ }
- Expected<std::uint32_t>
- ParseHexQuad()
+ /// Builds yyjson's tree of a value. Strings are referenced, not
+ /// copied: the tree is written before `value` can change.
+ yyjson_mut_val *
+ ToYyjson(yyjson_mut_doc *document, const JsonValue &value)
+ {
+ switch (value.GetKind())
{
- if (position_ + 4 > text_.size())
+ case JsonValue::Kind::kNull:
+ return yyjson_mut_null(document);
+ case JsonValue::Kind::kBoolean:
+ return yyjson_mut_bool(document, value.AsBoolean());
+ case JsonValue::Kind::kNumber:
+ return ToYyjsonNumber(document, value.AsNumber());
+ case JsonValue::Kind::kString:
{
- return Fail("truncated \\u escape");
+ const std::string &text = value.AsString();
+ return yyjson_mut_strn(document, text.data(), text.size());
}
- std::uint32_t value = 0;
- for (int index = 0; index < 4; ++index)
+ case JsonValue::Kind::kArray:
{
- const char character = text_[position_++];
- value <<= 4;
- if (character >= '0' && character <= '9')
- {
- value |= static_cast<std::uint32_t>(character - '0');
- }
- else if (character >= 'a' && character <= 'f')
+ yyjson_mut_val *array = yyjson_mut_arr(document);
+ for (const auto &item : value.Items())
{
- value |=
- static_cast<std::uint32_t>(character - 'a' + 10);
- }
- else if (character >= 'A' && character <= 'F')
- {
- value |=
- static_cast<std::uint32_t>(character - 'A' + 10);
- }
- else
- {
- return Fail("malformed \\u escape");
- }
- }
- return value;
- }
-
- Expected<std::string>
- ParseString()
- {
- ++position_; // The opening quote.
- std::string result;
- while (position_ < text_.size())
- {
- const char character = text_[position_++];
- if (character == '"')
- {
- return result;
- }
- if (static_cast<unsigned char>(character) < 0x20)
- {
- return Fail("control character in a string");
- }
- if (character != '\\')
- {
- result.push_back(character);
- continue;
- }
- if (position_ >= text_.size())
- {
- break;
- }
- const char escape = text_[position_++];
- switch (escape)
- {
- case '"':
- case '\\':
- case '/':
- result.push_back(escape);
- break;
- case 'b':
- result.push_back('\b');
- break;
- case 'f':
- result.push_back('\f');
- break;
- case 'n':
- result.push_back('\n');
- break;
- case 'r':
- result.push_back('\r');
- break;
- case 't':
- result.push_back('\t');
- break;
- case 'u':
- {
- auto high = ParseHexQuad();
- if (!high)
- {
- return high.GetError();
- }
- std::uint32_t codePoint = *high;
- if (codePoint >= 0xD800 && codePoint <= 0xDBFF &&
- Consume("\\u"))
- {
- auto low = ParseHexQuad();
- if (!low)
- {
- return low.GetError();
- }
- if (*low >= 0xDC00 && *low <= 0xDFFF)
- {
- codePoint = 0x10000 +
- ((codePoint - 0xD800) << 10) +
- (*low - 0xDC00);
- }
- }
- AppendUtf8(result, codePoint);
- break;
- }
- default:
- return Fail("unknown escape");
+ yyjson_mut_arr_append(array, ToYyjson(document, item));
}
- }
- return Fail("unterminated string");
- }
-
- Expected<JsonValue>
- ParseArray(int depth)
- {
- ++position_;
- JsonValue array = JsonValue::Array();
- SkipWhitespace();
- if (Consume("]"))
- {
return array;
}
- while (true)
+ case JsonValue::Kind::kObject:
{
- SkipWhitespace();
- auto item = ParseValue(depth + 1);
- if (!item)
+ yyjson_mut_val *object = yyjson_mut_obj(document);
+ for (const auto &[name, member] : value.Members())
{
- return item;
+ yyjson_mut_obj_add(
+ object,
+