Compare commits

..

2 Commits

Author SHA1 Message Date
c1f05d604f WIP 2025-11-14 22:42:24 +01:00
609ee13e23 s8slice: add bool s8_equals(a, b) function 2025-11-14 07:31:44 +01:00
2 changed files with 155 additions and 42 deletions

187
json.c
View File

@@ -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);

View File

@@ -8,7 +8,7 @@ typedef struct s8_slice {
int64_t len; int64_t len;
} S8Slice; } S8Slice;
#define S8(str) (S8Slice) { \ #define S(str) (S8Slice) { \
.data = (uint8_t*)("" str), \ .data = (uint8_t*)("" str), \
.len = sizeof(str)-1, \ .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] .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);
}