feat: extend Json
This commit is contained in:
1 parent
fde84ea3d7
commit
1656cdc870
1 file changed
+143
@@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
Reference in new issue
Block a user