import "./core.zc" import "./vec.zc" import "./map.zc" import "./string.zc" import "./result.zc" import "./option.zc" import "./mem.zc" @derive(Eq) enum JsonType { JSON_NULL, JSON_BOOL, JSON_NUMBER, JSON_STRING, JSON_ARRAY, JSON_OBJECT } struct JsonValue { kind: JsonType; string_val: char*; number_val: f64; bool_val: bool; array_val: Vec*; object_val: Map*; } alias JsonValuePtr = JsonValue*; fn _json_skip_ws(data: char*, pos: usize*) { while (data[*pos] == ' ' || data[*pos] == '\t' || data[*pos] == '\n' || data[*pos] == '\r') { *pos = *pos + 1; } } fn _json_parse_string(data: char*, pos: usize*) -> char* { if (data[*pos] != '"') return NULL; *pos = *pos + 1; let v = Vec::new(); while (data[*pos] != 0 && data[*pos] != '"') { if (data[*pos] == '\\' && data[*pos + 1] != 0) { *pos = *pos + 1; let c = data[*pos]; if (c == 'n') v.push('\n'); else if (c == 't') v.push('\t'); else if (c == 'r') v.push('\r'); else if (c == '"') v.push('"'); else if (c == '\\') v.push('\\'); else if (c == '/') v.push('/'); else if (c == 'b') v.push('\b'); else if (c == 'f') v.push('\f'); else v.push(c); } else { v.push(data[*pos]); } *pos = *pos + 1; } if (data[*pos] == '"') { *pos = *pos + 1; } v.push(0); let result = v.data; v.forget(); return result; } fn _json_parse_value(data: char*, pos: usize*) -> JsonValue*; fn _json_parse_array(data: char*, pos: usize*) -> JsonValue*; fn _json_parse_object(data: char*, pos: usize*) -> JsonValue*; fn _json_make_null() -> JsonValue* { let v: JsonValue* = alloc(); *v = JsonValue { kind: JsonType::JSON_NULL(), string_val: NULL, number_val: 0.0, bool_val: false, array_val: NULL, object_val: NULL }; return v; } fn _json_make_bool(b: bool) -> JsonValue* { let v: JsonValue* = alloc(); *v = JsonValue { kind: JsonType::JSON_BOOL(), string_val: NULL, number_val: 0.0, bool_val: b, array_val: NULL, object_val: NULL }; return v; } fn _json_make_string(s: char*) -> JsonValue* { let v: JsonValue* = alloc(); *v = JsonValue { kind: JsonType::JSON_STRING(), string_val: s, number_val: 0.0, bool_val: false, array_val: NULL, object_val: NULL }; return v; } fn _json_make_number(n: f64) -> JsonValue* { let v: JsonValue* = alloc(); *v = JsonValue { kind: JsonType::JSON_NUMBER(), string_val: NULL, number_val: n, bool_val: false, array_val: NULL, object_val: NULL }; return v; } fn _json_make_array(v: Vec*) -> JsonValue* { let arr: JsonValue* = alloc(); *arr = JsonValue { kind: JsonType::JSON_ARRAY(), string_val: NULL, number_val: 0.0, bool_val: false, array_val: v, object_val: NULL }; return arr; } fn _json_make_object(m: Map*) -> JsonValue* { let obj: JsonValue* = alloc(); *obj = JsonValue { kind: JsonType::JSON_OBJECT(), string_val: NULL, number_val: 0.0, bool_val: false, array_val: NULL, object_val: m }; return obj; } fn _json_parse_value(data: char*, pos: usize*) -> JsonValue* { _json_skip_ws(data, pos); if (data[*pos] == 0) return NULL; if (strncmp(data + *pos, "null", 4) == 0) { *pos = *pos + 4; return _json_make_null(); } if (strncmp(data + *pos, "true", 4) == 0) { *pos = *pos + 4; return _json_make_bool(true); } if (strncmp(data + *pos, "false", 5) == 0) { *pos = *pos + 5; return _json_make_bool(false); } if (data[*pos] == '"') { let s = _json_parse_string(data, pos); if (s == NULL) return NULL; return _json_make_string(s); } if (data[*pos] == '-' || (data[*pos] >= '0' && data[*pos] <= '9')) { let end: char*; let num = strtod(data + *pos, &end); if (end == data + *pos) return NULL; *pos = (usize)(end - data); return _json_make_number(num); } if (data[*pos] == '[') { return _json_parse_array(data, pos); } if (data[*pos] == '{') { return _json_parse_object(data, pos); } return NULL; } fn _json_parse_array(data: char*, pos: usize*) -> JsonValue* { if (data[*pos] != '[') return NULL; *pos = *pos + 1; let v: Vec* = alloc>(); *v = Vec__JsonValuePtr::new(); _json_skip_ws(data, pos); if (data[*pos] == ']') { *pos = *pos + 1; return _json_make_array(v); } while (true) { _json_skip_ws(data, pos); let val = _json_parse_value(data, pos); if (val == NULL) return NULL; Vec__JsonValuePtr__push(v, val); _json_skip_ws(data, pos); if (data[*pos] == ']') { *pos = *pos + 1; return _json_make_array(v); } if (data[*pos] != ',') return NULL; *pos = *pos + 1; } } fn _json_parse_object(data: char*, pos: usize*) -> JsonValue* { if (data[*pos] != '{') return NULL; *pos = *pos + 1; let m: Map* = alloc>(); *m = Map__JsonValuePtr::new(); _json_skip_ws(data, pos); if (data[*pos] == '}') { *pos = *pos + 1; return _json_make_object(m); } while (true) { _json_skip_ws(data, pos); let key = _json_parse_string(data, pos); if (key == NULL) return NULL; _json_skip_ws(data, pos); if (data[*pos] != ':') { dealloc(key); return NULL; } *pos = *pos + 1; _json_skip_ws(data, pos); let val = _json_parse_value(data, pos); if (val == NULL) { dealloc(key); return NULL; } Map__JsonValuePtr__put(m, key, val); dealloc(key); _json_skip_ws(data, pos); if (data[*pos] == '}') { *pos = *pos + 1; return _json_make_object(m); } if (data[*pos] != ',') return NULL; *pos = *pos + 1; } } fn _json_do_parse(json: char*) -> JsonValue* { let pos: usize = 0; return _json_parse_value(json, &pos); } impl JsonValue { /// Creates a JSON null value. fn null() -> JsonValue { return JsonValue { kind: JsonType::JSON_NULL(), string_val: NULL, number_val: 0.0, bool_val: false, array_val: NULL, object_val: NULL }; } /// Creates a JSON boolean. fn bool(b: bool) -> JsonValue { return JsonValue { kind: JsonType::JSON_BOOL(), string_val: NULL, number_val: 0.0, bool_val: b, array_val: NULL, object_val: NULL }; } /// Creates a JSON number. fn number(n: f64) -> JsonValue { return JsonValue { kind: JsonType::JSON_NUMBER(), string_val: NULL, number_val: n, bool_val: false, array_val: NULL, object_val: NULL }; } /// Creates a JSON string. fn string(s: char*) -> JsonValue { let len = strlen(s); let dup: char* = alloc_n(len + 1); if (dup != NULL) { memcpy(dup, s, len + 1); } return JsonValue { kind: JsonType::JSON_STRING(), string_val: dup, number_val: 0.0, bool_val: false, array_val: NULL, object_val: NULL }; } /// Creates a JSON array. fn array() -> JsonValue { let v: Vec* = alloc>(); *v = Vec__JsonValuePtr::new(); return JsonValue { kind: JsonType::JSON_ARRAY(), string_val: NULL, number_val: 0.0, bool_val: false, array_val: v, object_val: NULL }; } /// Creates a JSON object. fn object() -> JsonValue { let m: Map* = alloc>(); *m = Map__JsonValuePtr::new(); return JsonValue { kind: JsonType::JSON_OBJECT(), string_val: NULL, number_val: 0.0, bool_val: false, array_val: NULL, object_val: m }; } // Heap-allocated factory methods (returns pointers) /// Creates a heap-allocated JSON null value. fn null_ptr() -> JsonValue* { let p: JsonValue* = alloc(); *p = JsonValue::null(); return p; } /// Creates a heap-allocated JSON boolean. fn bool_ptr(b: bool) -> JsonValue* { let p: JsonValue* = alloc(); *p = JsonValue::bool(b); return p; } /// Creates a heap-allocated JSON number. fn number_ptr(n: f64) -> JsonValue* { let p: JsonValue* = alloc(); *p = JsonValue::number(n); return p; } /// Creates a heap-allocated JSON string. fn string_ptr(s: char*) -> JsonValue* { let p: JsonValue* = alloc(); *p = JsonValue::string(s); return p; } /// Creates a heap-allocated JSON array. fn array_ptr() -> JsonValue* { let p: JsonValue* = alloc(); *p = JsonValue::array(); return p; } /// Creates a heap-allocated JSON object. fn object_ptr() -> JsonValue* { let p: JsonValue* = alloc(); *p = JsonValue::object(); return p; } /// Appends a value to the array. fn push(self, val: JsonValue) { if (self.kind.tag != JsonType::JSON_ARRAY().tag) return; let p: JsonValue* = alloc(); *p = val; self.array_val.push(p); } /// Sets an object field. fn set(self, key: char*, val: JsonValue) { if (self.kind.tag != JsonType::JSON_OBJECT().tag) return; let p: JsonValue* = alloc(); *p = val; self.object_val.put(key, p); } /// Parses a JSON string into a JsonValue. fn parse(json: char*) -> Result { let result: JsonValue* = _json_do_parse(json); if (result != NULL) { return Result::Ok(result); } return Result::Err("JSON parse error"); } /// Parses a JSON string into an owned JsonValue. fn parse_val(json: char*) -> Result { let result: JsonValue* = _json_do_parse(json); if (result != NULL) { let val: JsonValue = *result; dealloc(result); return Result::Ok(val); } return Result::Err("JSON parse error"); } // Type checking helpers /// Returns whether the value is null. fn is_null(self) -> bool { return self.kind.tag == JsonType::JSON_NULL().tag; } /// Returns whether the value is a boolean. fn is_bool(self) -> bool { return self.kind.tag == JsonType::JSON_BOOL().tag; } /// Returns whether the value is a number. fn is_number(self) -> bool { return self.kind.tag == JsonType::JSON_NUMBER().tag; } /// Returns whether the value is a string. fn is_string(self) -> bool { return self.kind.tag == JsonType::JSON_STRING().tag; } /// Returns whether the value is an array. fn is_array(self) -> bool { return self.kind.tag == JsonType::JSON_ARRAY().tag; } /// Returns whether the value is an object. fn is_object(self) -> bool { return self.kind.tag == JsonType::JSON_OBJECT().tag; } // Direct value extractors /// Returns the string value when it is a string. fn as_string(self) -> Option { if self.kind.tag == JsonType::JSON_STRING().tag { return Option::Some(self.string_val); } return Option::None(); } /// Returns the integer value when it is a number. fn as_int(self) -> Option { if self.kind.tag == JsonType::JSON_NUMBER().tag { return Option::Some((int)self.number_val); } return Option::None(); } /// Returns the floating-point value when it is a number. fn as_float(self) -> Option { if self.kind.tag == JsonType::JSON_NUMBER().tag { return Option::Some(self.number_val); } return Option::None(); } /// Returns the boolean value when it is a boolean. fn as_bool(self) -> Option { if self.kind.tag == JsonType::JSON_BOOL().tag { return Option::Some(self.bool_val); } return Option::None(); } // Object key accessors /// Returns the object field value for `key`. fn get(self, key: char*) -> Option { if self.kind.tag != JsonType::JSON_OBJECT().tag { return Option::None(); } if Map::contains(self.object_val, key) { return Map::get(self.object_val, key); } return Option::None(); } /// Returns the string field for `key`, or `None`. fn get_string(self, key: char*) -> Option { let opt = self.get(key); if opt.is_none() { return Option::None(); } let val = opt.unwrap(); return (*val).as_string(); } /// Returns the integer field for `key`, or `None`. fn get_int(self, key: char*) -> Option { let opt = self.get(key); if opt.is_none() { return Option::None(); } let val = opt.unwrap(); return (*val).as_int(); } /// Returns the floating-point field for `key`, or `None`. fn get_float(self, key: char*) -> Option { let opt = self.get(key); if opt.is_none() { return Option::None(); } let val = opt.unwrap(); return (*val).as_float(); } /// Returns the boolean field for `key`, or `None`. fn get_bool(self, key: char*) -> Option { let opt = self.get(key); if opt.is_none() { return Option::None(); } let val = opt.unwrap(); return (*val).as_bool(); } /// Returns the object field for `key`, or `None`. fn get_object(self, key: char*) -> Option { let opt = self.get(key); if opt.is_none() { return Option::None(); } let val = opt.unwrap(); if (*val).kind.tag == JsonType::JSON_OBJECT().tag { return Option::Some(val); } return Option::None(); } /// Returns the array field for `key`, or `None`. fn get_array(self, key: char*) -> Option { let opt = self.get(key); if opt.is_none() { return Option::None(); } let val = opt.unwrap(); if (*val).kind.tag == JsonType::JSON_ARRAY().tag { return Option::Some(val); } return Option::None(); } // Array accessors /// Returns the array element at `index`. fn at(self, index: usize) -> Option { if self.kind.tag != JsonType::JSON_ARRAY().tag { return Option::None(); } if index >= self.array_val.length() { return Option::None(); } return Option::Some(self.array_val.get(index)); } /// Returns the array/object size. fn length(self) -> usize { if self.kind.tag == JsonType::JSON_ARRAY().tag { return self.array_val.length(); } if self.kind.tag == JsonType::JSON_OBJECT().tag { return self.object_val.length(); } return 0; } // Deprecated alias; use `length`. /// Returns the array/object size (deprecated; use `length`). fn len(self) -> usize { return self.length(); } /// Recursively frees the value and its children. fn free(self) { if (self.kind.tag == JsonType::JSON_STRING().tag) dealloc(self.string_val); if (self.kind.tag == JsonType::JSON_ARRAY().tag) { let v: Vec* = self.array_val; for (let i: usize = 0; i < v.length(); i = i + 1) { let item: JsonValue* = v.get(i); item.free(); dealloc(item); } v.clear(); dealloc(v.data); dealloc>(v); } if (self.kind.tag == JsonType::JSON_OBJECT().tag) { let m: Map* = self.object_val; for (let i: usize = 0; i < m.capacity(); i = i + 1) { if (m.is_slot_occupied(i)) { let child: JsonValue* = m.val_at(i); child.free(); dealloc(child); } } m.free(); dealloc>(m); } } } impl Drop for JsonValue { fn drop(self) { self.free(); } } impl JsonValue { /// Returns a serialized JSON string (caller frees). fn to_string(self) -> char* { let s = String::new(""); self.stringify(&s); let out = s.c_str(); s.forget(); return out; } /// Serializes the value into the given String buffer. fn stringify(self, buf: String*) { if (self.kind.tag == JsonType::JSON_NULL().tag) { buf.append_c_ptr("null"); } else if (self.kind.tag == JsonType::JSON_BOOL().tag) { if (self.bool_val) { buf.append_c_ptr("true"); } else { buf.append_c_ptr("false"); } } else if (self.kind.tag == JsonType::JSON_NUMBER().tag) { let tmp: char[64]; sprintf((char*)tmp, "%.15g", self.number_val); buf.append_c_ptr((char*)tmp); } else if (self.kind.tag == JsonType::JSON_STRING().tag) { buf.append_c_ptr("\""); let p = self.string_val; let len = strlen(p); for (let i = 0; i < len; i = i + 1) { let c = p[i]; if (c == '"') buf.append_c_ptr("\\\""); else if (c == '\\') buf.append_c_ptr("\\\\"); else if (c == '\n') buf.append_c_ptr("\\n"); else if (c == '\t') buf.append_c_ptr("\\t"); else if (c == '\r') buf.append_c_ptr("\\r"); else if (c == '\b') buf.append_c_ptr("\\b"); else if (c == '\f') buf.append_c_ptr("\\f"); else { let tmp: char[2]; tmp[0] = c; tmp[1] = 0; buf.append_c_ptr((char*)tmp); } } buf.append_c_ptr("\""); } else if (self.kind.tag == JsonType::JSON_ARRAY().tag) { buf.append_c_ptr("["); let v = self.array_val; for (let i: usize = 0; i < v.length(); i = i + 1) { if (i > 0) buf.append_c_ptr(","); let item = v.get(i); (*item).stringify(buf); } buf.append_c_ptr("]"); } else if (self.kind.tag == JsonType::JSON_OBJECT().tag) { buf.append_c_ptr("{{"); let m = self.object_val; let first = true; for (let i: usize = 0; i < m.capacity(); i = i + 1) { if (m.is_slot_occupied(i)) { if (!first) buf.append_c_ptr(","); first = false; let key = m.key_at(i); buf.append_c_ptr("\""); buf.append_c_ptr(key); buf.append_c_ptr("\":"); let val = m.val_at(i); val.stringify(buf); } } buf.append_c_ptr("}"); } } }