Files
tokenizer/json.c
2025-11-14 22:42:24 +01:00

237 lines
5.5 KiB
C

#include <stdlib.h>
#include <stddef.h>
#include <stdbool.h>
#include <stdio.h>
#include "s8slice.h"
struct json_value {
S8Slice key;
struct json_value* next;
enum {
JSON_OBJECT,
JSON_ARRAY,
JSON_NUMBER,
JSON_STRING,
JSON_BOOL,
JSON_NULL,
} kind;
union {
double number;
S8Slice string;
bool boolean;
struct json_value* child;
};
};
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) {
perror("calloc");
abort();
}
return new;
}
static inline void push(struct json_builder* j, struct json_value* v)
{
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;
}
static inline void pop(struct json_builder* j)
{
if (j->ancestry_stack_len <= 1) {
fprintf(stderr, "popping root from stack\n");
abort();
}
j->ctx = &j->ancestry_stack[--j->ancestry_stack_len]->next;
}
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 (parent_is_object(j)) {
if (!key) {
fprintf(stderr, "adding value with no key to object\n");
abort();
}
new->key = *key;
}
}
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, key, new);
j->ctx = &new->child;
push(j, new);
}
#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, key, new);
}
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;
}
printf("\n");
print_indentation();
if (print_key) {
printf("\"%.*s\": ", val->key.len, val->key.data);
}
switch (val->kind) {
case JSON_NUMBER: {
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: {
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\n");
abort();
} break;
}
printf(",");
json_print_value(val->next, depth, print_key);
#undef print_indentation
}
void json_print(struct json_builder* j)
{
json_print_value(&j->root, 0, false);
}
int main()
{
struct json_builder j = {0};
json_init(&j);
json_add_number(&j, &S("foo"), 53);
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);
return EXIT_SUCCESS;
}