Compare commits
2 Commits
a660c76fb7
...
c1f05d604f
| Author | SHA1 | Date | |
|---|---|---|---|
| c1f05d604f | |||
| 609ee13e23 |
187
json.c
187
json.c
@@ -6,13 +6,6 @@
|
||||
|
||||
#include "s8slice.h"
|
||||
|
||||
struct json {
|
||||
struct json_value* root;
|
||||
struct json_value** ctx;
|
||||
S8Slice pending_key;
|
||||
bool has_pending_key;
|
||||
};
|
||||
|
||||
struct json_value {
|
||||
S8Slice key;
|
||||
struct json_value* next;
|
||||
@@ -30,12 +23,20 @@ struct json_value {
|
||||
double number;
|
||||
S8Slice string;
|
||||
bool boolean;
|
||||
struct json_value* object_head;
|
||||
struct json_value* array_head;
|
||||
struct json_value* child;
|
||||
};
|
||||
};
|
||||
|
||||
static struct json_value* new_value(struct json* j)
|
||||
struct json_builder {
|
||||
struct json_value root;
|
||||
struct json_value** ctx;
|
||||
|
||||
struct json_value* ancestry_stack[1024];
|
||||
size_t ancestry_stack_len;
|
||||
};
|
||||
|
||||
|
||||
static struct json_value* new_value(struct json_builder* j)
|
||||
{
|
||||
struct json_value* new = calloc(1, sizeof(struct json_value));
|
||||
if (!new) {
|
||||
@@ -45,85 +46,189 @@ static struct json_value* new_value(struct json* j)
|
||||
return new;
|
||||
}
|
||||
|
||||
void json_init(struct json* j)
|
||||
static inline void push(struct json_builder* j, struct json_value* v)
|
||||
{
|
||||
j->ctx = &j->root;
|
||||
if (j->ancestry_stack_len > sizeof j->ancestry_stack / sizeof *j->ancestry_stack) {
|
||||
fprintf(stderr, "depth too deep\n");
|
||||
abort();
|
||||
}
|
||||
j->ancestry_stack[j->ancestry_stack_len++] = v;
|
||||
}
|
||||
|
||||
void json_add_key(struct json* j, S8Slice key)
|
||||
static inline void pop(struct json_builder* j)
|
||||
{
|
||||
j->has_pending_key = true;
|
||||
j->pending_key = key;
|
||||
if (j->ancestry_stack_len <= 1) {
|
||||
fprintf(stderr, "popping root from stack\n");
|
||||
abort();
|
||||
}
|
||||
j->ctx = &j->ancestry_stack[--j->ancestry_stack_len]->next;
|
||||
}
|
||||
|
||||
void json_add_value(struct json* j, struct json_value* new)
|
||||
static inline bool parent_is_object(struct json_builder* j)
|
||||
{
|
||||
return j->ancestry_stack[j->ancestry_stack_len - 1]->kind == JSON_OBJECT;
|
||||
}
|
||||
|
||||
static void json_add_value(struct json_builder* j, S8Slice* key, struct json_value* new)
|
||||
{
|
||||
*j->ctx = new;
|
||||
j->ctx = &new->next;
|
||||
/*
|
||||
if (j->has_pending_key) {
|
||||
new->key = j->pending_key;
|
||||
j->has_pending_key = false;
|
||||
}
|
||||
*/
|
||||
if (parent_is_object(j)) {
|
||||
if (!key) {
|
||||
fprintf(stderr, "adding value with no key to object\n");
|
||||
abort();
|
||||
}
|
||||
new->key = *key;
|
||||
}
|
||||
}
|
||||
|
||||
void json_add_object(struct json* j)
|
||||
void json_init(struct json_builder* j)
|
||||
{
|
||||
j->root.kind = JSON_OBJECT;
|
||||
j->ctx = &j->root.child;
|
||||
push(j, &j->root);
|
||||
}
|
||||
|
||||
#define json_add_object(j, key) for (int _ = (json_add_object_(j, key), 1); _; _ = (pop(j), 0))
|
||||
void json_add_object_(struct json_builder* j, S8Slice* key)
|
||||
{
|
||||
|
||||
struct json_value* new = new_value(j);
|
||||
new->kind = JSON_OBJECT;
|
||||
json_add_value(j, new);
|
||||
j->ctx = &new->object_head;
|
||||
json_add_value(j, key, new);
|
||||
j->ctx = &new->child;
|
||||
|
||||
push(j, new);
|
||||
}
|
||||
|
||||
void json_add_number(struct json* j, double n)
|
||||
#define json_add_array(j, key) for (int _ = (json_add_array_(j, key), 1); _; _ = (pop(j), 0))
|
||||
void json_add_array_(struct json_builder* j, S8Slice* key)
|
||||
{
|
||||
struct json_value* new = new_value(j);
|
||||
new->kind = JSON_ARRAY;
|
||||
json_add_value(j, key, new);
|
||||
j->ctx = &new->child;
|
||||
|
||||
push(j, new);
|
||||
}
|
||||
|
||||
void json_add_number(struct json_builder* j, S8Slice* key, double n)
|
||||
{
|
||||
struct json_value* new = new_value(j);
|
||||
new->kind = JSON_NUMBER;
|
||||
new->number = n;
|
||||
json_add_value(j, new);
|
||||
json_add_value(j, key, new);
|
||||
}
|
||||
|
||||
void json_print_value(struct json_value* val, int depth)
|
||||
void json_add_string(struct json_builder* j, S8Slice* key, S8Slice str)
|
||||
{
|
||||
struct json_value* new = new_value(j);
|
||||
new->kind = JSON_STRING;
|
||||
new->string = str;
|
||||
json_add_value(j, key, new);
|
||||
}
|
||||
|
||||
void json_add_bool(struct json_builder* j, S8Slice* key, bool x)
|
||||
{
|
||||
struct json_value* new = new_value(j);
|
||||
new->kind = JSON_BOOL;
|
||||
new->boolean = x;
|
||||
json_add_value(j, key, new);
|
||||
}
|
||||
|
||||
void json_add_null(struct json_builder* j, S8Slice* key)
|
||||
{
|
||||
struct json_value* new = new_value(j);
|
||||
new->kind = JSON_NULL;
|
||||
json_add_value(j, key, new);
|
||||
}
|
||||
|
||||
void json_print_value(struct json_value* val, int depth, bool print_key)
|
||||
{
|
||||
#define print_indentation() do {for (int i = 0; i < depth; i++) {printf(" ");}} while(0)
|
||||
if (!val) {
|
||||
return;
|
||||
}
|
||||
for (int i = 0; i < depth; i++) {
|
||||
printf(" ");
|
||||
printf("\n");
|
||||
print_indentation();
|
||||
if (print_key) {
|
||||
printf("\"%.*s\": ", val->key.len, val->key.data);
|
||||
}
|
||||
switch (val->kind) {
|
||||
case JSON_NUMBER: {
|
||||
printf("%lf,\n", val->number);
|
||||
json_print_value(val->next, depth);
|
||||
printf("%lf", val->number);
|
||||
} break;
|
||||
|
||||
case JSON_STRING: {
|
||||
printf("\"%.*s\"", val->string.len, val->string.data);
|
||||
} break;
|
||||
|
||||
case JSON_BOOL: {
|
||||
const S8Slice bool_name[2] = {
|
||||
[false] = S("false"),
|
||||
[true] = S("true"),
|
||||
};
|
||||
S8Slice bs = bool_name[val->boolean];
|
||||
printf("%.*s", bs.len, bs.data);
|
||||
} break;
|
||||
|
||||
case JSON_NULL: {
|
||||
printf("null");
|
||||
} break;
|
||||
|
||||
case JSON_OBJECT: {
|
||||
json_print_value(val->object_head, depth+1);
|
||||
printf("{");
|
||||
json_print_value(val->child, depth+1, true);
|
||||
printf("\n");
|
||||
print_indentation();
|
||||
printf("}");
|
||||
} break;
|
||||
|
||||
case JSON_ARRAY: {
|
||||
printf("[");
|
||||
json_print_value(val->child, depth+1, false);
|
||||
printf("\n");
|
||||
print_indentation();
|
||||
printf("]");
|
||||
} break;
|
||||
|
||||
default: {
|
||||
fprintf(stderr, "not implemented");
|
||||
fprintf(stderr, "not implemented\n");
|
||||
abort();
|
||||
} break;
|
||||
}
|
||||
|
||||
printf(",");
|
||||
|
||||
json_print_value(val->next, depth, print_key);
|
||||
#undef print_indentation
|
||||
}
|
||||
|
||||
void json_print(struct json* j)
|
||||
void json_print(struct json_builder* j)
|
||||
{
|
||||
json_print_value(j->root, 0);
|
||||
json_print_value(&j->root, 0, false);
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
struct json j = {0};
|
||||
struct json_builder j = {0};
|
||||
json_init(&j);
|
||||
|
||||
json_add_number(&j, 53);
|
||||
json_add_number(&j, &S("foo"), 53);
|
||||
|
||||
json_add_object(&j);
|
||||
|
||||
json_add_number(&j, 12);
|
||||
json_add_object(&j, &S("bar")) {
|
||||
json_add_number(&j, &S("a"), 1);
|
||||
json_add_null(&j, &S("b"));
|
||||
json_add_bool(&j, &S("c"), true);
|
||||
json_add_array(&j, &S("d")) {
|
||||
json_add_number(&j, &S("e"), 4);
|
||||
json_add_number(&j, &S("f"), 5);
|
||||
json_add_number(&j, &S("g"), 6);
|
||||
}
|
||||
json_add_number(&j, &S("h"), 7);
|
||||
json_add_number(&j, &S("i"), 8);
|
||||
json_add_number(&j, &S("j"), 9);
|
||||
};
|
||||
|
||||
json_print(&j);
|
||||
|
||||
|
||||
10
s8slice.h
10
s8slice.h
@@ -8,7 +8,7 @@ typedef struct s8_slice {
|
||||
int64_t len;
|
||||
} S8Slice;
|
||||
|
||||
#define S8(str) (S8Slice) { \
|
||||
#define S(str) (S8Slice) { \
|
||||
.data = (uint8_t*)("" str), \
|
||||
.len = sizeof(str)-1, \
|
||||
}
|
||||
@@ -37,3 +37,11 @@ static inline S8Slice s8slice(const S8Slice* s, int64_t begin, int64_t end)
|
||||
.data = &s->data[begin]
|
||||
};
|
||||
}
|
||||
|
||||
static bool s8_equals(S8Slice a, S8Slice b)
|
||||
{
|
||||
if (a.len != b.len) {
|
||||
return false;
|
||||
}
|
||||
return memcmp(a.data, b.data, a.len);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user