feat: extend Json

This commit is contained in:
dualfroz committed 2026-09-07 22:59:43 +02:00
1 parent fde84ea3d7
commit 1656cdc870
1 file changed
+143
+143
View File
@@ -155,3 +155,146 @@ private:
return true; return true;
} }
bool parseValue(int depth, JsonValue& out) {
if (atEnd()) {
fail("unexpected end of input, expected a value");
return false;
}
char c = peek();
if (c == '{') return parseObject(depth, out);
if (c == '[') return parseArray(depth, out);
if (c == '"') {
std::string text;
if (!parseString(text)) return false;
out = JsonValue::makeString(std::move(text));
return true;
}
if (c == '-' || (c >= '0' && c <= '9')) return parseNumber(out);
if (c == 't') return parseLiteral("true", JsonValue::makeBool(true), out);
if (c == 'f') return parseLiteral("false", JsonValue::makeBool(false), out);
if (c == 'n') return parseLiteral("null", JsonValue::makeNull(), out);
fail(std::string("unexpected character '") + c + "', expected a value");
return false;
}
bool parseLiteral(const char* word, JsonValue value, JsonValue& out) {
std::size_t length = std::strlen(word);
if (src.compare(cursor, length, word) != 0) {
fail(std::string("unknown literal, expected ") + word);
return false;
}
for (std::size_t i = 0u; i < length; ++i) advance();
out = std::move(value);
return true;
}
bool parseObject(int depth, JsonValue& out) {
if (depth > depthLimit) {
fail("nesting deeper than the " + std::to_string(depthLimit) + " level limit");
return false;
}
advance();
out = JsonValue::makeObject();
skipWhitespace();
if (!atEnd() && peek() == '}') {
advance();
return true;
}
for (;;) {
skipWhitespace();
if (atEnd() || peek() != '"') {
fail("expected a quoted member name");
return false;
}
std::string key;
if (!parseString(key)) return false;
skipWhitespace();
if (!expect(':', "expected ':' after the member name")) return false;
skipWhitespace();
JsonValue member;
if (!parseValue(depth + 1, member)) return false;
out.set(key, std::move(member));
skipWhitespace();
if (atEnd()) {
fail("unexpected end of input, expected ',' or '}'");
return false;
}
char c = peek();
if (c == ',') {
advance();
skipWhitespace();
if (!atEnd() && peek() == '}') {
fail("trailing comma before '}'");
return false;
}
continue;
}
if (c == '}') {
advance();
return true;
}
fail(std::string("unexpected character '") + c + "', expected ',' or '}'");
return false;
}
}
bool parseArray(int depth, JsonValue& out) {
if (depth > depthLimit) {
fail("nesting deeper than the " + std::to_string(depthLimit) + " level limit");
return false;
}
advance();
out = JsonValue::makeArray();
skipWhitespace();
if (!atEnd() && peek() == ']') {
advance();
return true;
}
for (;;) {
skipWhitespace();
JsonValue element;
if (!parseValue(depth + 1, element)) return false;
out.push(std::move(element));
skipWhitespace();
if (atEnd()) {
fail("unexpected end of input, expected ',' or ']'");
return false;
}
char c = peek();
if (c == ',') {
advance();
skipWhitespace();
if (!atEnd() && peek() == ']') {
fail("trailing comma before ']'");
return false;
}
continue;
}
if (c == ']') {
advance();
return true;
}
fail(std::string("unexpected character '") + c + "', expected ',' or ']'");
return false;
}
}
bool parseHexQuad(uint32_t& out) {
uint32_t value = 0u;
for (int i = 0; i < 4; ++i) {
if (atEnd()) {
fail("unexpected end of input inside a \\u escape");
return false;
}
int digit = hexDigitValue(peek());
if (digit < 0) {
fail(std::string("'") + peek() + "' is not a hexadecimal digit");
return false;
}
value = (value << 4) | static_cast<uint32_t>(digit);
advance();
}
out = value;
return true;
}