bool _json_parse_null();
bool _json_parse_string(bool add);
bool _json_parse_number();
+ bool _json_parse_float();
bool _json_parse_int();
#define JSON_BEGIN() int __i = STRING_ITERATOR_SAVE(_json)
// Current keys
int _json_keys;
+ERASEABLE
bool _json_parse_object() {
JSON_BEGIN();
if (STRING_ITERATOR_GET(_json) != '{') JSON_FAIL("expected '{'");
JSON_END();
}
+ ERASEABLE
bool _json_parse_members() {
JSON_BEGIN();
for (;;) {
JSON_END();
}
+ ERASEABLE
bool _json_parse_pair() {
JSON_BEGIN();
if (!_json_parse_string(false)) JSON_FAIL("expected string");
JSON_END();
}
+ERASEABLE
bool _json_parse_array() {
JSON_BEGIN();
if (STRING_ITERATOR_GET(_json) != '[') JSON_FAIL("expected '['");
int len = bufstr_add(_json_buffer, "0", 0);
- bufstr_set(_json_buffer, len - 1, strcat(bufstr_get(_json_buffer, len - 1), ".length"));
- int n = -1;
+ if (len) bufstr_set(_json_buffer, len - 1, strcat(bufstr_get(_json_buffer, len - 1), ".length"));
bool required = false;
- for (;;) {
- bufstr_set(_json_buffer, len, ftos(++n));
- if (!_json_parse_value()) if (required) JSON_FAIL("expected value"); else break;
- bufstr_add(_json_buffer, strcat(_json_ns, ".", ftos(n)), 0);
+ for (int n = 0; ; n++) {
+ string key = ftos(n);
+ key = _json_ns ? strcat(_json_ns, ".", key) : key;
+ int it = bufstr_add(_json_buffer, key, 0);
+ bool ret = false; WITH(string, _json_ns, key, ret = _json_parse_value());
+ if (!ret) {
+ bufstr_free(_json_buffer, it);
+ if (required) JSON_FAIL("expected value"); else break;
+ }
+ bufstr_set(_json_buffer, len, ftos(n + 1));
if (STRING_ITERATOR_PEEK(_json) == ',') {
STRING_ITERATOR_NEXT(_json);
required = true;
JSON_END();
}
+ERASEABLE
bool _json_parse_value() {
JSON_BEGIN();
if (!(_json_parse_string(true)
JSON_END();
}
+ ERASEABLE
bool _json_parse_true() {
JSON_BEGIN();
if (!(STRING_ITERATOR_GET(_json) == 't'
JSON_END();
}
+ ERASEABLE
bool _json_parse_false() {
JSON_BEGIN();
if (!(STRING_ITERATOR_GET(_json) == 'f'
JSON_END();
}
+ ERASEABLE
bool _json_parse_null() {
JSON_BEGIN();
if (!(STRING_ITERATOR_GET(_json) == 'n'
JSON_END();
}
+ERASEABLE
bool _json_parse_string(bool add) {
JSON_BEGIN();
if (STRING_ITERATOR_GET(_json) != '"') JSON_FAIL("expected opening '\"'");
case '\\': esc = "\\"; break;
case 'n': esc = "\n"; break;
case 't': esc = "\t"; break;
+ case 'u': esc = "\\u"; break; // TODO
+ case '/': esc = "/"; break;
}
s = strcat(s, esc);
} else {
JSON_END();
}
+ERASEABLE
bool _json_parse_number() {
JSON_BEGIN();
- if (!_json_parse_int()) JSON_FAIL("expected number");
+ if (!(_json_parse_float() || _json_parse_int())) JSON_FAIL("expected number");
JSON_END();
}
+ ERASEABLE
+ bool _json_parse_float() {
+ JSON_BEGIN();
+ string s = "";
+ bool needdot = true;
+ for (int c; (c = STRING_ITERATOR_GET(_json)); ) {
+ if (!(c >= '0' && c <= '9')) {
+ if (c == '.' && needdot) {
+ // fine
+ needdot = false;
+ } else {
+ STRING_ITERATOR_UNGET(_json);
+ break;
+ }
+ }
+ s = strcat(s, chr2str(c));
+ }
+ if (s == "") JSON_FAIL("expected float");
+ bufstr_add(_json_buffer, s, 0);
+ JSON_END();
+ }
+
+ ERASEABLE
bool _json_parse_int() {
JSON_BEGIN();
string s = "";
JSON_END();
}
-int json_parse(string in) {
- // TODO: remove insignificant whitespace
- STRING_ITERATOR_SET(_json, in, 0);
+ERASEABLE
+int json_parse(string in, bool() func) {
+ string trimmed = "";
+ LABEL(trim) {
+ int o = strstrofs(in, "\"", 0);
+ if (o >= 0) {
+ string part = substring(in, 0, o + 1); in = substring(in, o + 1, -1);
+ part = strreplace(" ", "", part);
+ part = strreplace("\n", "", part);
+ trimmed = strcat(trimmed, part);
+ goto trim_str;
+ } else {
+ string part = in;
+ part = strreplace(" ", "", part);
+ part = strreplace("\n", "", part);
+ trimmed = strcat(trimmed, part);
+ goto done;
+ }
+ }
+ LABEL(trim_str) {
+ int o = strstrofs(in, "\"", 0);
+ int esc = strstrofs(in, "\\\"", 0);
+ if (o < esc || esc < 0) {
+ // simple string
+ string part = substring(in, 0, o + 1); in = substring(in, o + 1, -1);
+ trimmed = strcat(trimmed, part);
+ goto trim;
+ } else {
+ // has escape
+ string part = substring(in, 0, esc + 2); in = substring(in, esc + 2, -1);
+ trimmed = strcat(trimmed, part);
+ goto trim_str;
+ }
+ }
+ LABEL(done);
+
+ STRING_ITERATOR_SET(_json, trimmed, 0);
_json_buffer = buf_create();
- bool ret = _json_parse_object();
+ bool ret = func();
if (!ret) {
buf_del(_json_buffer);
_json_buffer = -1;
return _json_buffer;
}
+ERASEABLE
+string json_get(int buf, string key)
+{
+ for (int i = 1, n = buf_getsize(buf); i < n; i += 2) {
+ if (bufstr_get(buf, i) == key) return bufstr_get(buf, i + 1);
+ }
+ return string_null;
+}
+
+ERASEABLE
+void json_del(int buf)
+{
+ buf_del(buf);
+}
+
+ERASEABLE
+void json_dump(int buf)
+{
+ for (int i = 0, n = buf_getsize(buf); i < n; ++i) {
+ print(bufstr_get(buf, i), "\n");
+ }
+}
+
#undef JSON_BEGIN
#undef JSON_FAIL
#undef JSON_END
TEST(json, Parse)
{
- string s = "{\"m_string\":\"string\",\"m_int\":123,\"m_bool\":true,\"m_null\":null,\"m_obj\":{},\"m_arr\":[]}";
+ string s = "{\n\
+ \"m_string\": \"\\\"string\\\"\",\n\
+ \"m_int\": 123,\n\
+ \"m_bool\": true,\n\
+ \"m_null\": null,\n\
+ \"m_obj\": { },\n\
+ \"m_arr\": [ ]\n}"; // "
print(s, "\n");
- int buf = json_parse(s);
+ int buf = json_parse(s, _json_parse_object);
EXPECT_NE(-1, buf);
- for (int i = 0, n = buf_getsize(buf); i < n; ++i) {
- print(bufstr_get(buf, i), "\n");
- }
- SUCCEED();
+ json_dump(buf);
+ SUCCEED();
}