WIP
This commit is contained in:
187
json.c
187
json.c
@@ -6,13 +6,6 @@
|
|||||||
|
|
||||||
#include "s8slice.h"
|
#include "s8slice.h"
|
||||||
|
|
||||||
struct json {
|
|
||||||
struct json_value* root;
|
|
||||||
struct json_value** ctx;
|
|
||||||
S8Slice pending_key;
|
|
||||||
bool has_pending_key;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct json_value {
|
struct json_value {
|
||||||
S8Slice key;
|
S8Slice key;
|
||||||
struct json_value* next;
|
struct json_value* next;
|
||||||
@@ -30,12 +23,20 @@ struct json_value {
|
|||||||
double number;
|
double number;
|
||||||
S8Slice string;
|
S8Slice string;
|
||||||
bool boolean;
|
bool boolean;
|
||||||
struct json_value* object_head;
|
struct json_value* child;
|
||||||
struct json_value* array_head;
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
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));
|
struct json_value* new = calloc(1, sizeof(struct json_value));
|
||||||
if (!new) {
|
if (!new) {
|
||||||
@@ -45,85 +46,189 @@ static struct json_value* new_value(struct json* j)
|
|||||||
return new;
|
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;
|
if (j->ancestry_stack_len <= 1) {
|
||||||
j->pending_key = key;
|
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;
|
||||||
j->ctx = &new->next;
|
j->ctx = &new->next;
|
||||||
/*
|
if (parent_is_object(j)) {
|
||||||
if (j->has_pending_key) {
|
if (!key) {
|
||||||
new->key = j->pending_key;
|
fprintf(stderr, "adding value with no key to object\n");
|
||||||
j->has_pending_key = false;
|
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);
|
struct json_value* new = new_value(j);
|
||||||
new->kind = JSON_OBJECT;
|
new->kind = JSON_OBJECT;
|
||||||
json_add_value(j, new);
|
json_add_value(j, key, new);
|
||||||
j->ctx = &new->object_head;
|
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);
|
struct json_value* new = new_value(j);
|
||||||
new->kind = JSON_NUMBER;
|
new->kind = JSON_NUMBER;
|
||||||
new->number = n;
|
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) {
|
if (!val) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
for (int i = 0; i < depth; i++) {
|
printf("\n");
|
||||||
printf(" ");
|
print_indentation();
|
||||||
|
if (print_key) {
|
||||||
|
printf("\"%.*s\": ", val->key.len, val->key.data);
|
||||||
}
|
}
|
||||||
switch (val->kind) {
|
switch (val->kind) {
|
||||||
case JSON_NUMBER: {
|
case JSON_NUMBER: {
|
||||||
printf("%lf,\n", val->number);
|
printf("%lf", val->number);
|
||||||
json_print_value(val->next, depth);
|
} 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;
|
} break;
|
||||||
|
|
||||||
case JSON_OBJECT: {
|
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;
|
} break;
|
||||||
|
|
||||||
default: {
|
default: {
|
||||||
fprintf(stderr, "not implemented");
|
fprintf(stderr, "not implemented\n");
|
||||||
abort();
|
abort();
|
||||||
} break;
|
} 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()
|
int main()
|
||||||
{
|
{
|
||||||
struct json j = {0};
|
struct json_builder j = {0};
|
||||||
json_init(&j);
|
json_init(&j);
|
||||||
|
|
||||||
json_add_number(&j, 53);
|
json_add_number(&j, &S("foo"), 53);
|
||||||
|
|
||||||
json_add_object(&j);
|
json_add_object(&j, &S("bar")) {
|
||||||
|
json_add_number(&j, &S("a"), 1);
|
||||||
json_add_number(&j, 12);
|
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);
|
json_print(&j);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user