summaryrefslogtreecommitdiff
path: root/std/json.zc
diff options
context:
space:
mode:
authorZuhaitz Méndez Fernández de Aránguiz <zuhaitz@debian>2026-01-11 17:47:30 +0000
committerZuhaitz Méndez Fernández de Aránguiz <zuhaitz@debian>2026-01-11 17:47:30 +0000
commitba5ee94871e670fbe1ea091dd5731e593df0b29f (patch)
tree3b706a9ab11effa4acb094482f3d657c986ef501 /std/json.zc
parentaba9191ab3ef0699b0f9507ee3d03161f9ee7771 (diff)
Some std for you
Diffstat (limited to 'std/json.zc')
-rw-r--r--std/json.zc250
1 files changed, 250 insertions, 0 deletions
diff --git a/std/json.zc b/std/json.zc
new file mode 100644
index 0000000..ee2d43d
--- /dev/null
+++ b/std/json.zc
@@ -0,0 +1,250 @@
+
+import "./core.zc"
+import "./vec.zc"
+import "./map.zc"
+import "./string.zc"
+import "./result.zc"
+
+@derive(Eq)
+enum JsonType {
+ JSON_NULL,
+ JSON_BOOL,
+ JSON_NUMBER,
+ JSON_STRING,
+ JSON_ARRAY,
+ JSON_OBJECT
+}
+
+@derive(Eq)
+struct JsonValue {
+ kind: JsonType;
+ string_val: char*;
+ number_val: double;
+ bool_val: bool;
+ array_val: Vec<JsonValue*>*;
+ object_val: Map<JsonValue*>*;
+}
+
+raw {
+ Vec_JsonValuePtr Vec_JsonValuePtr_new();
+ void Vec_JsonValuePtr_push(Vec_JsonValuePtr* self, JsonValue* item);
+ Map_JsonValuePtr Map_JsonValuePtr_new();
+ void Map_JsonValuePtr_put(Map_JsonValuePtr* self, char* key, JsonValue* val);
+
+ static void _json_skip_ws(const char** p) {
+ while (**p == ' ' || **p == '\t' || **p == '\n' || **p == '\r') (*p)++;
+ }
+
+ static char* _json_parse_string(const char** p) {
+ if (**p != '"') return NULL;
+ (*p)++;
+ char buf[4096]; int len = 0;
+ while (**p && **p != '"') {
+ if (**p == '\\' && (*p)[1]) {
+ (*p)++;
+ char c = **p;
+ if (c == 'n') buf[len++] = '\n';
+ else if (c == 't') buf[len++] = '\t';
+ else if (c == 'r') buf[len++] = '\r';
+ else if (c == '"') buf[len++] = '"';
+ else if (c == '\\') buf[len++] = '\\';
+ else buf[len++] = c;
+ } else {
+ buf[len++] = **p;
+ }
+ (*p)++;
+ }
+ if (**p == '"') (*p)++;
+ buf[len] = '\0';
+ return strdup(buf);
+ }
+
+ static struct JsonValue* _json_parse_value(const char** p);
+
+ static struct JsonValue* _json_parse_array(const char** p) {
+ if (**p != '[') return NULL;
+ (*p)++;
+ struct JsonValue* arr = malloc(sizeof(struct JsonValue));
+ arr->kind = JsonType_JSON_ARRAY();
+ arr->string_val = 0; arr->number_val = 0; arr->bool_val = 0; arr->object_val = 0;
+ arr->array_val = malloc(sizeof(Vec_JsonValuePtr));
+ *(arr->array_val) = Vec_JsonValuePtr_new();
+
+ _json_skip_ws(p);
+ if (**p == ']') { (*p)++; return arr; }
+
+ while (1) {
+ _json_skip_ws(p);
+ struct JsonValue* val = _json_parse_value(p);
+ if (!val) return NULL;
+ Vec_JsonValuePtr_push(arr->array_val, val);
+ _json_skip_ws(p);
+ if (**p == ']') { (*p)++; return arr; }
+ if (**p != ',') return NULL;
+ (*p)++;
+ }
+ }
+
+ static struct JsonValue* _json_parse_object(const char** p) {
+ if (**p != '{') return NULL;
+ (*p)++;
+ struct JsonValue* obj = malloc(sizeof(struct JsonValue));
+ obj->kind = JsonType_JSON_OBJECT();
+ obj->string_val = 0; obj->number_val = 0; obj->bool_val = 0; obj->array_val = 0;
+ obj->object_val = malloc(sizeof(Map_JsonValuePtr));
+ *(obj->object_val) = Map_JsonValuePtr_new();
+
+ _json_skip_ws(p);
+ if (**p == '}') { (*p)++; return obj; }
+
+ while (1) {
+ _json_skip_ws(p);
+ char* key = _json_parse_string(p);
+ if (!key) return NULL;
+ _json_skip_ws(p);
+ if (**p != ':') { free(key); return NULL; }
+ (*p)++;
+ _json_skip_ws(p);
+ struct JsonValue* val = _json_parse_value(p);
+ if (!val) { free(key); return NULL; }
+ Map_JsonValuePtr_put(obj->object_val, key, val);
+ free(key);
+ _json_skip_ws(p);
+ if (**p == '}') { (*p)++; return obj; }
+ if (**p != ',') return NULL;
+ (*p)++;
+ }
+ }
+
+ static struct JsonValue* _json_parse_value(const char** p) {
+ _json_skip_ws(p);
+ if (**p == '\0') return NULL;
+
+ if (strncmp(*p, "null", 4) == 0) {
+ *p += 4;
+ struct JsonValue* v = malloc(sizeof(struct JsonValue));
+ v->kind = JsonType_JSON_NULL();
+ v->string_val = 0; v->number_val = 0; v->bool_val = 0; v->array_val = 0; v->object_val = 0;
+ return v;
+ }
+ if (strncmp(*p, "true", 4) == 0) {
+ *p += 4;
+ struct JsonValue* v = malloc(sizeof(struct JsonValue));
+ v->kind = JsonType_JSON_BOOL();
+ v->string_val = 0; v->number_val = 0; v->bool_val = 1; v->array_val = 0; v->object_val = 0;
+ return v;
+ }
+ if (strncmp(*p, "false", 5) == 0) {
+ *p += 5;
+ struct JsonValue* v = malloc(sizeof(struct JsonValue));
+ v->kind = JsonType_JSON_BOOL();
+ v->string_val = 0; v->number_val = 0; v->bool_val = 0; v->array_val = 0; v->object_val = 0;
+ return v;
+ }
+ if (**p == '"') {
+ char* s = _json_parse_string(p);
+ if (!s) return NULL;
+ struct JsonValue* v = malloc(sizeof(struct JsonValue));
+ v->kind = JsonType_JSON_STRING();
+ v->string_val = s; v->number_val = 0; v->bool_val = 0; v->array_val = 0; v->object_val = 0;
+ return v;
+ }
+ if (**p == '-' || (**p >= '0' && **p <= '9')) {
+ char* end;
+ double num = strtod(*p, &end);
+ if (end == *p) return NULL;
+ *p = end;
+ struct JsonValue* v = malloc(sizeof(struct JsonValue));
+ v->kind = JsonType_JSON_NUMBER();
+ v->string_val = 0; v->number_val = num; v->bool_val = 0; v->array_val = 0; v->object_val = 0;
+ return v;
+ }
+ if (**p == '[') return _json_parse_array(p);
+ if (**p == '{') return _json_parse_object(p);
+ return NULL;
+ }
+
+ struct JsonValue* _json_do_parse(const char* json) {
+ const char* ptr = json;
+ return _json_parse_value(&ptr);
+ }
+}
+
+impl JsonValue {
+ fn null() -> JsonValue {
+ return JsonValue { kind: JsonType::JSON_NULL(), string_val: 0, number_val: 0, bool_val: false, array_val: 0, object_val: 0 };
+ }
+
+ fn bool(b: bool) -> JsonValue {
+ return JsonValue { kind: JsonType::JSON_BOOL(), string_val: 0, number_val: 0, bool_val: b, array_val: 0, object_val: 0 };
+ }
+
+ fn number(n: double) -> JsonValue {
+ return JsonValue { kind: JsonType::JSON_NUMBER(), string_val: 0, number_val: n, bool_val: false, array_val: 0, object_val: 0 };
+ }
+
+ fn string(s: char*) -> JsonValue {
+ return JsonValue { kind: JsonType::JSON_STRING(), string_val: strdup(s), number_val: 0, bool_val: false, array_val: 0, object_val: 0 };
+ }
+
+ fn array() -> JsonValue {
+ var v: Vec<JsonValue*>* = malloc(sizeof(Vec_JsonValuePtr));
+ *v = Vec_JsonValuePtr::new();
+ return JsonValue { kind: JsonType::JSON_ARRAY(), string_val: 0, number_val: 0, bool_val: false, array_val: v, object_val: 0 };
+ }
+
+ fn object() -> JsonValue {
+ var m: Map<JsonValue*>* = malloc(sizeof(Map_JsonValuePtr));
+ *m = Map_JsonValuePtr::new();
+ return JsonValue { kind: JsonType::JSON_OBJECT(), string_val: 0, number_val: 0, bool_val: false, array_val: 0, object_val: m };
+ }
+
+ fn push(self, val: JsonValue) {
+ if (self.kind.tag != JsonType::JSON_ARRAY().tag) return;
+ var p: JsonValue* = malloc(sizeof(JsonValue));
+ *p = val;
+ self.array_val.push(p);
+ }
+
+ fn set(self, key: char*, val: JsonValue) {
+ if (self.kind.tag != JsonType::JSON_OBJECT().tag) return;
+ var p: JsonValue* = malloc(sizeof(JsonValue));
+ *p = val;
+ self.object_val.put(key, p);
+ }
+
+ fn parse(json: char*) -> Result<JsonValue*> {
+ var result: JsonValue* = _json_do_parse(json);
+ if (result != NULL) {
+ return Result<JsonValue*>::Ok(result);
+ }
+ return Result<JsonValue*>::Err("JSON parse error");
+ }
+
+ fn free(self) {
+ if (self.kind.tag == JsonType::JSON_STRING().tag) free(self.string_val);
+ if (self.kind.tag == JsonType::JSON_ARRAY().tag) {
+ var v: Vec<JsonValue*>* = self.array_val;
+ for (var i: usize = 0; i < v.length(); i = i + 1) {
+ var item: JsonValue* = v.get(i);
+ item.free();
+ free(item);
+ }
+ v.clear();
+ free(v.data);
+ free(v);
+ }
+ if (self.kind.tag == JsonType::JSON_OBJECT().tag) {
+ var m: Map<JsonValue*>* = self.object_val;
+ for (var i: usize = 0; i < m.capacity(); i = i + 1) {
+ if (m.is_slot_occupied(i)) {
+ var child: JsonValue* = m.val_at(i);
+ child.free();
+ free(child);
+ }
+ }
+ m.free();
+ free(m);
+ }
+ }
+}