From 9447913de6cb934604672a2b62ff47826c698900 Mon Sep 17 00:00:00 2001 From: Christoffer Lerno Date: Fri, 20 Sep 2024 00:39:10 +0200 Subject: [PATCH] Use arena with JSON parser. Slightly altered output for json printing. --- src/build/common_build.c | 16 ++-- src/build/libraries.c | 7 +- src/build/project.c | 7 +- src/build/project_manipulation.c | 57 +++--------- src/compiler/mac_support.c | 10 +- src/compiler_tests/tests.c | 10 +- src/utils/json.c | 151 ++++++++++--------------------- src/utils/json.h | 35 ++++--- 8 files changed, 104 insertions(+), 189 deletions(-) diff --git a/src/build/common_build.c b/src/build/common_build.c index a263ff150..12f4e4a86 100644 --- a/src/build/common_build.c +++ b/src/build/common_build.c @@ -7,9 +7,8 @@ void check_json_keys(const char* valid_keys[][2], size_t key_count, const char* { static bool failed_shown = false; bool failed = false; - for (size_t i = 0; i < json->member_len; i++) + FOREACH(const char *, key, json->keys) { - const char *key = json->keys[i]; for (size_t j = 0; j < key_count; j++) { if (str_eq(key, valid_keys[j][0])) goto OK; @@ -36,7 +35,7 @@ void check_json_keys(const char* valid_keys[][2], size_t key_count, const char* const char *get_optional_string(const char *file, const char *category, JSONObject *table, const char *key) { - JSONObject *value = json_obj_get(table, key); + JSONObject *value = json_map_get(table, key); if (!value) return NULL; if (value->type != J_STRING) { @@ -67,7 +66,7 @@ const char *get_string(const char *file, const char *category, JSONObject *table int get_valid_bool(const char *file, const char *target, JSONObject *json, const char *key, int default_val) { - JSONObject *value = json_obj_get(json, key); + JSONObject *value = json_map_get(json, key); if (!value) return default_val; if (value->type != J_BOOL) { @@ -79,7 +78,7 @@ int get_valid_bool(const char *file, const char *target, JSONObject *json, const const char **get_string_array(const char *file, const char *category, JSONObject *table, const char *key, bool mandatory) { - JSONObject *value = json_obj_get(table, key); + JSONObject *value = json_map_get(table, key); if (!value) { if (mandatory) @@ -91,9 +90,8 @@ const char **get_string_array(const char *file, const char *category, JSONObject } if (value->type != J_ARRAY) goto NOT_ARRAY; const char **values = NULL; - for (unsigned i = 0; i < value->array_len; i++) + FOREACH(JSONObject *, val, value->elements) { - JSONObject *val = value->elements[i]; if (val->type != J_STRING) goto NOT_ARRAY; vec_add(values, val->str); } @@ -163,7 +161,7 @@ void get_list_append_strings(const char *file, const char *target, JSONObject *j int get_valid_string_setting(const char *file, const char *target, JSONObject *json, const char *key, const char** values, int first_result, int count, const char *expected) { - JSONObject *value = json_obj_get(json, key); + JSONObject *value = json_map_get(json, key); if (!value) { return -1; @@ -193,7 +191,7 @@ int get_valid_enum_from_string(const char *str, const char *target, const char * long get_valid_integer(JSONObject *table, const char *key, const char *category, bool mandatory) { - JSONObject *value = json_obj_get(table, key); + JSONObject *value = json_map_get(table, key); if (!value) { if (mandatory) diff --git a/src/build/libraries.c b/src/build/libraries.c index aca739d98..840312271 100644 --- a/src/build/libraries.c +++ b/src/build/libraries.c @@ -49,9 +49,8 @@ static inline void parse_library_type(Library *library, LibraryTarget ***target_ { if (!object) return; if (object->type != J_OBJECT) error_exit("Expected a set of targets in %s.", library->dir); - for (size_t i = 0; i < object->member_len; i++) + FOREACH_IDX(i, JSONObject *, member, object->members) { - JSONObject *member = object->members[i]; const char *key = object->keys[i]; if (member->type != J_OBJECT) error_exit("Expected a list of properties for a target in %s.", library->dir); check_json_keys(manifest_target_keys, manifest_target_keys_count, manifest_deprecated_target_keys, manifest_deprecated_target_key_count, member, key, "--list-manifest-properties"); @@ -115,7 +114,7 @@ static Library *add_library(JSONObject *object, const char *dir) library->win_crt = (WinCrtLinking)get_valid_string_setting(library->dir, NULL, object, "wincrt", wincrt_linking, 0, 3, "'none', 'static' or 'dynamic'."); get_list_append_strings(library->dir, NULL, object, &library->csource_dirs, "c-sources", "c-sources-override", "c-sources-add"); get_list_append_strings(library->dir, NULL, object, &library->cinclude_dirs, "c-include-dirs", "c-include-dirs-override", "c-include-dirs-add"); - parse_library_type(library, &library->targets, json_obj_get(object, "targets")); + parse_library_type(library, &library->targets, json_map_get(object, "targets")); return library; } @@ -166,7 +165,7 @@ INLINE void zip_check_err(const char *lib, const char *error) INLINE JSONObject* read_manifest(const char *lib, const char *manifest_data) { JsonParser parser; - json_init_string(&parser, manifest_data, &malloc_arena); + json_init_string(&parser, manifest_data); JSONObject *json = json_parse(&parser); if (parser.error_message) { diff --git a/src/build/project.c b/src/build/project.c index 22d730227..0acd8a795 100644 --- a/src/build/project.c +++ b/src/build/project.c @@ -448,7 +448,7 @@ static void project_add_targets(const char *filename, Project *project, JSONObje BuildTarget default_target = default_build_target; load_into_build_target(filename, project_data, NULL, &default_target); - JSONObject *targets_json = json_obj_get(project_data, "targets"); + JSONObject *targets_json = json_map_get(project_data, "targets"); if (!targets_json) { error_exit("No targets found in project."); @@ -457,9 +457,8 @@ static void project_add_targets(const char *filename, Project *project, JSONObje { error_exit("'targets' did not contain map of targets."); } - for (unsigned i = 0; i < targets_json->member_len; i++) + FOREACH_IDX(i, JSONObject *, object, targets_json->members) { - JSONObject *object = targets_json->members[i]; const char *key = targets_json->keys[i]; if (object->type != J_OBJECT) { @@ -519,7 +518,7 @@ Project *project_load(const char **filename_ref) const char *filename = *filename_ref = file_exists(PROJECT_JSON5) ? PROJECT_JSON5 : PROJECT_JSON; char *read = file_read_all(filename, &size); JsonParser parser; - json_init_string(&parser, read, &malloc_arena); + json_init_string(&parser, read); JSONObject *json = json_parse(&parser); if (parser.error_message) { diff --git a/src/build/project_manipulation.c b/src/build/project_manipulation.c index 89dc87adc..e79c1806f 100644 --- a/src/build/project_manipulation.c +++ b/src/build/project_manipulation.c @@ -10,7 +10,7 @@ static JSONObject *read_project(const char **file_used) *file_used = project_filename; char *read = file_read_all(project_filename, &size); JsonParser parser; - json_init_string(&parser, read, &malloc_arena); + json_init_string(&parser, read); JSONObject *json = json_parse(&parser); if (parser.error_message) { @@ -259,41 +259,31 @@ void add_libraries_to_project_file(const char** libs, const char* target_name) { const char *filename; JSONObject *project_json = read_project(&filename); - // TODO! check if target is specified and exists (NULL at the moment) - JSONObject *libraries_json = json_obj_get(project_json, "dependencies"); + JSONObject *libraries_json = json_map_get(project_json, "dependencies"); const char** dependencies = NULL; - for(int i = 0; i < libraries_json->array_len; i++) + FOREACH(JSONObject *, element, libraries_json->elements) { - vec_add(dependencies, libraries_json->elements[i]->str); + vec_add(dependencies, element->str); } // check if libraries are already present FOREACH(const char*, lib, libs) { if (str_findlist(lib, vec_size(dependencies), dependencies)!=-1) continue; - vec_add(dependencies, lib); } JSONObject** elements = NULL; - FOREACH(const char*, dep, dependencies) { - JSONObject* obj = json_new_object(&malloc_arena, J_STRING); - obj->str = dep; - vec_add(elements, obj); + vec_add(elements, json_new_string(dep)); } - // TODO fancier functions for altering JSON file (quite cumbersome at the moment) - // TODO! check if "dependency" entry exists in the project.json file. - // Apply changes to JSON object - libraries_json->elements = elements; - libraries_json->array_len = vec_size(dependencies); // write to project json file FILE *file = fopen(filename, "w"); @@ -306,36 +296,19 @@ void add_target_project(BuildOptions *build_options) { const char *filename; JSONObject *project_json = read_project(&filename); - JSONObject *targets_json = json_obj_get(project_json, "targets"); + JSONObject *targets_json = json_map_get(project_json, "targets"); - for (unsigned i = 0; i < targets_json->member_len; i++) + if (json_map_get(targets_json, build_options->project_options.target_name) != NULL) { - JSONObject *object = targets_json->members[i]; - const char *key = targets_json->keys[i]; - - if (str_eq(key, build_options->project_options.target_name)) - { - error_exit("Target with name '%s' already exists", key); - } + error_exit("Target with name '%s' already exists", build_options->project_options.target_name); } - JSONObject *target_type_obj = json_new_object(&malloc_arena, J_STRING); - target_type_obj->str = targets[build_options->project_options.target_type]; + JSONObject *target_type_obj = json_new_string(targets[build_options->project_options.target_type]); + JSONObject *new_target = json_new_map(); + json_map_set(new_target, "type", target_type_obj); - JSONObject *new_target = json_new_object(&malloc_arena, J_OBJECT); - new_target->members = malloc_arena(sizeof(JSONObject) * 16); - new_target->keys = malloc_arena(sizeof(JSONObject) * 16); - - new_target->keys[0] = "type"; - new_target->members[0] = target_type_obj; - new_target->member_len = 1; - - - size_t index = targets_json->member_len; - targets_json->members[index] = new_target; - targets_json->keys[index] = build_options->project_options.target_name; - targets_json->member_len++; + json_map_set(targets_json, build_options->project_options.target_name, new_target); FILE *file = fopen(filename, "w"); print_json_to_file(project_json, file); @@ -400,7 +373,7 @@ void view_project(BuildOptions *build_options) /* Target information */ PRINTFN("Targets: "); - JSONObject *targets_json = json_obj_get(project_json, "targets"); + JSONObject *targets_json = json_map_get(project_json, "targets"); if (!targets_json) { error_exit("No targets found in project."); @@ -410,11 +383,9 @@ void view_project(BuildOptions *build_options) error_exit("'targets' did not contain map of targets."); } - for (unsigned i = 0; i < targets_json->member_len; i++) + FOREACH_IDX(i, JSONObject *, object, targets_json->members) { - JSONObject *object = targets_json->members[i]; const char *key = targets_json->keys[i]; - if (object->type != J_OBJECT) { error_exit("Invalid data in target '%s'", key); diff --git a/src/compiler/mac_support.c b/src/compiler/mac_support.c index feb19d8d2..2f8ff4546 100644 --- a/src/compiler/mac_support.c +++ b/src/compiler/mac_support.c @@ -30,16 +30,16 @@ MacSDK *macos_sysroot_sdk_information(const char *sdk_path) const char *settings_json_path = scratch_buffer_to_string(); if (!file_exists(settings_json_path)) error_exit("Invalid MacOS SDK path: '%s'.", sdk_path); const char *file = file_read_all(settings_json_path, &len); - json_init_string(&parser, file, &malloc_arena); + json_init_string(&parser, file); MacSDK *sdk = CALLOCS(MacSDK); JSONObject *top_object = json_parse(&parser); - JSONObject *supported_targets = json_obj_get(top_object, "SupportedTargets"); - JSONObject *macosx_target = json_obj_get(supported_targets, "macosx"); + JSONObject *supported_targets = json_map_get(top_object, "SupportedTargets"); + JSONObject *macosx_target = json_map_get(supported_targets, "macosx"); - const char *default_deploy_target = json_obj_get(macosx_target, "DefaultDeploymentTarget")->str; + const char *default_deploy_target = json_map_get(macosx_target, "DefaultDeploymentTarget")->str; parse_version(default_deploy_target, &sdk->macos_deploy_target); - const char *min_deploy_target = json_obj_get(macosx_target, "MinimumDeploymentTarget")->str; + const char *min_deploy_target = json_map_get(macosx_target, "MinimumDeploymentTarget")->str; parse_version(min_deploy_target, &sdk->macos_min_deploy_target); return sdk; diff --git a/src/compiler_tests/tests.c b/src/compiler_tests/tests.c index ba553479e..9863ac6f9 100644 --- a/src/compiler_tests/tests.c +++ b/src/compiler_tests/tests.c @@ -169,20 +169,20 @@ static void test_json(void) { printf("Begin json testing.\n"); JsonParser parser; - json_init_string(&parser, "123", &malloc); + json_init_string(&parser, "123"); JSONObject *obj = json_parse(&parser); TEST_ASSERT(obj->type == J_NUMBER, "Expected number"); TEST_ASSERT(obj->f == 123.0, "Expected number match"); - json_init_string(&parser, "[123, 23.123]", &malloc); + json_init_string(&parser, "[123, 23.123]"); JSONObject *array = json_parse(&parser); TEST_ASSERT(array->type == J_ARRAY, "Expected array"); - TEST_ASSERT(array->array_len == 2, "Expected 2 elements"); + TEST_ASSERT(vec_size(array->elements) == 2, "Expected 2 elements"); TEST_ASSERT(array->elements[0]->f == 123.0, "Matching element 1"); TEST_ASSERT(array->elements[1]->f == 23.123, "Matching element 1"); - json_init_string(&parser, "[\"hello\\nworld\\t.\", 123]", &malloc); + json_init_string(&parser, "[\"hello\\nworld\\t.\", 123]"); array = json_parse(&parser); TEST_ASSERT(array->type == J_ARRAY, "Expected array"); - TEST_ASSERT(array->array_len == 2, "Expected 2 elements"); + TEST_ASSERT(vec_size(array->elements) == 2, "Expected 2 elements"); TEST_ASSERT(array->elements[1]->f == 123.0, "Matching element 1"); TEST_ASSERT(array->elements[0]->type == J_STRING, "Matching element 0"); TEST_ASSERT(strcmp(array->elements[0]->str, "hello\nworld\t.") == 0, "Mismatching string"); diff --git a/src/utils/json.c b/src/utils/json.c index b4adb82e6..30669b13a 100644 --- a/src/utils/json.c +++ b/src/utils/json.c @@ -1,14 +1,12 @@ #include "lib.h" #include "json.h" - #define PRINTF(file, string, ...) fprintf(file, string, ##__VA_ARGS__) /* NOLINT */ JSONObject error = { .type = J_ERROR }; JSONObject true_val = { .type = J_BOOL, .b = true }; JSONObject false_val = { .type = J_BOOL, .b = false }; JSONObject zero_val = { .type = J_NUMBER, .f = 0.0 }; -JSONObject empty_obj_val = { .type = J_OBJECT, .member_len = 0 }; #define CONSUME(token_) do { if (!consume(parser, token_)) { json_error(parser, "Unexpected character encountered."); return &error; } } while(0) @@ -111,7 +109,7 @@ static void json_parse_string(JsonParser *parser) if (c == '\\' && current[0] != '\0') current++; } size_t max_size = current - parser->current; - char *str = parser->allocator(max_size + 1); + char *str = malloc_arena(max_size + 1); char *str_current = str; while (1) { @@ -274,55 +272,37 @@ static inline bool consume(JsonParser *parser, JSONTokenType token) JSONObject *json_parse_array(JsonParser *parser) { CONSUME(T_LBRACKET); + JSONObject *array = json_new_object(J_ARRAY); if (consume(parser, T_RBRACKET)) { - JSONObject *array = json_new_object(parser->allocator, J_ARRAY); - array->array_len = 0; return array; } size_t capacity = 16; - JSONObject *array = json_new_object(parser->allocator, J_ARRAY); - JSONObject **elements = parser->allocator(sizeof(JSONObject *) * capacity); size_t index = 0; while (1) { JSONObject *parsed = json_parse(parser); - if (parser->error_message) return &error; - if (index >= capacity) - { - JSONObject **elements_old = elements; - size_t copy_size = capacity * sizeof(JSONObject *); - capacity *= 2; - elements = parser->allocator(sizeof(JSONObject *) * capacity); - memcpy(elements, elements_old, copy_size); - } - elements[index++] = parsed; + vec_add(array->elements, parsed); if (consume(parser, T_RBRACKET)) break; CONSUME(T_COMMA); // Allow trailing comma if (consume(parser, T_RBRACKET)) break; } - array->elements = elements; - array->array_len = index; return array; } JSONObject *json_parse_object(JsonParser *parser) { CONSUME(T_LBRACE); - + JSONObject *obj = json_new_map(); if (consume(parser, T_RBRACE)) { - return &empty_obj_val; + return obj; } - size_t capacity = 16; - JSONObject *obj = json_new_object(parser->allocator, J_OBJECT); - JSONObject **elements = parser->allocator(sizeof(JSONObject *) * capacity); - const char **keys = parser->allocator(sizeof(JSONObject *) * capacity); size_t index = 0; while (1) { @@ -334,20 +314,8 @@ JSONObject *json_parse_object(JsonParser *parser) JSONObject *value = json_parse(parser); if (parser->error_message) return NULL; - if (index >= capacity) - { - JSONObject **elements_old = elements; - const char **keys_old = keys; - size_t copy_size = capacity * sizeof(void *); - capacity *= 2; - elements = parser->allocator(sizeof(JSONObject *) * capacity); - keys = parser->allocator(sizeof(JSONObject *) * capacity); - memcpy(elements, elements_old, copy_size); - memcpy(keys, keys_old, copy_size); - } - - keys[index] = key; - elements[index++] = value; + vec_add(obj->keys, key); + vec_add(obj->members, value); if (consume(parser, T_RBRACE)) break; if (!consume(parser, T_COMMA)) @@ -358,19 +326,29 @@ JSONObject *json_parse_object(JsonParser *parser) // Allow trailing comma if (consume(parser, T_RBRACE)) break; } - obj->members = elements; - obj->keys = keys; - obj->member_len = index; return obj; } -JSONObject *json_obj_get(JSONObject *obj, const char *key) +void json_map_set(JSONObject *obj, const char *key, JSONObject *value) +{ + FOREACH_IDX(i, const char *, a_key, obj->keys) + { + if (str_eq(a_key, key)) + { + obj->members[i] = value; + } + } + vec_add(obj->members, value); + vec_add(obj->keys, key); +} + +JSONObject *json_map_get(JSONObject *obj, const char *key) { assert(obj->type == J_OBJECT); - for (unsigned i = 0; i < obj->member_len; i++) + FOREACH_IDX(i, const char *, a_key, obj->keys) { - if (strcmp(obj->keys[i], key) == 0) return obj->elements[i]; + if (str_eq(a_key, key)) return obj->members[i]; } return NULL; } @@ -396,9 +374,7 @@ JSONObject *json_parse(JsonParser *parser) return NULL; case T_STRING: { - JSONObject *obj = json_new_object(parser->allocator, J_STRING); - obj->type = J_STRING; - obj->str = parser->last_string; + JSONObject *obj = json_new_string(parser->last_string); json_lexer_advance(parser); return obj; } @@ -410,7 +386,7 @@ JSONObject *json_parse(JsonParser *parser) json_lexer_advance(parser); return &zero_val; } - obj = json_new_object(parser->allocator, J_NUMBER); + obj = json_new_object(J_NUMBER); obj->type = J_NUMBER; obj->f = parser->last_number; json_lexer_advance(parser); @@ -429,10 +405,9 @@ JSONObject *json_parse(JsonParser *parser) UNREACHABLE } -void json_init_string(JsonParser *parser, const char *str, JsonAllocator *allocator) +void json_init_string(JsonParser *parser, const char *str) { parser->current = str; - parser->allocator = allocator; parser->error_message = NULL; parser->line = 1; json_lexer_advance(parser); @@ -444,44 +419,9 @@ bool is_freable(JSONObject *obj) if (obj == &true_val) return false; if (obj == &false_val) return false; if (obj == &zero_val) return false; - if (obj == &empty_obj_val) return false; return true; } -void json_free(JsonDeallocator *deallocator, JSONObject **ptr) -{ - JSONObject *obj = *ptr; - - if (!is_freable(obj)) return; - - switch (obj->type) - { - case J_OBJECT: - for (size_t i = 0; i < obj->member_len; i++) - { - json_free(deallocator, &obj->members[i]); - deallocator((char *)obj->keys[i]); - } - deallocator(obj->keys); - deallocator(obj->members); - break; - case J_ARRAY: - for (size_t i = 0; i < obj->array_len; i++) - { - json_free(deallocator, &obj->elements[i]); - } - deallocator(obj->elements); - break; - case J_STRING: - deallocator((char *)obj->str); - break; - default: - break; - } - deallocator(*ptr); - *ptr = NULL; -} - static inline void print_indent(int indent_level, FILE *file) { for (int i = 0; i < indent_level; i++) @@ -510,57 +450,58 @@ static inline void print_json(JSONObject *obj, int indent_level, FILE *file) break; case J_ARRAY: fputs(" [ ", file); - - if (obj->array_len == 0) + if (!vec_size(obj->elements)) { fputs(" ]", file); break; } bool should_print_item_per_line = false; - - for (size_t i = 0; i < obj->array_len; i++) + FOREACH(JSONObject *, object, obj->elements) { - if (obj->elements[i]->type == J_OBJECT) + if (object->type == J_OBJECT) { should_print_item_per_line = true; break; } } - - if (!should_print_item_per_line && obj->array_len < 5) + if (!should_print_item_per_line && vec_size(obj->elements) < 5) { - for (size_t i = 0; i < obj->array_len; i++) + FOREACH_IDX(i, JSONObject *, object, obj->elements) { if (i != 0) fputs(", ", file); - print_json(obj->elements[i], indent_level, file); + print_json(object, indent_level, file); } fputs(" ]", file); break; } - fputs("\n", file); - for (size_t i = 0; i < obj->array_len; i++) { - print_indent(indent_level + 1, file); - print_json(obj->elements[i], indent_level + 1, file); - fputs(",\n", file); + fputs("\n", file); + FOREACH_IDX(i, JSONObject *, object, obj->elements) + { + if (i != 0) fputs(",\n", file); + print_indent(indent_level + 1, file); + print_json(object, indent_level + 1, file); + } + fputs("\n ]", file); } - - fputs(" ]", file); break; case J_OBJECT: + { fputs("{\n", file); - for (size_t i = 0; i < obj->member_len; i++) + FOREACH_IDX(i, JSONObject *, object, obj->members) { + if (i != 0) fputs(",\n", file); print_indent(indent_level + 1, file); PRINTF(file, "\"%s\": ", obj->keys[i]); - print_json(obj->members[i], indent_level + 1, file); - fputs(",\n", file); + print_json(object, indent_level + 1, file); } + fputs("\n", file); print_indent(indent_level, file); fputs("}", file); break; + } default: break; } diff --git a/src/utils/json.h b/src/utils/json.h index b446f863b..219810c1a 100644 --- a/src/utils/json.h +++ b/src/utils/json.h @@ -21,13 +21,11 @@ typedef struct JSONObject_ struct { struct JSONObject_ **elements; - size_t array_len; }; struct { struct JSONObject_ **members; const char **keys; - size_t member_len; }; }; } JSONObject; @@ -49,31 +47,40 @@ typedef enum JSONTokenType_ T_EOF } JSONTokenType; -typedef void *(JsonAllocator)(size_t); -typedef void *(JsonDeallocator)(void *); - typedef struct { unsigned line; const char *current; JSONTokenType current_token_type; const char *error_message; - JsonAllocator *allocator; const char *last_string; double last_number; } JsonParser; -void json_init_string(JsonParser *parser, const char *str, JsonAllocator *allocator); +void json_init_string(JsonParser *parser, const char *str); JSONObject *json_parse(JsonParser *parser); -JSONObject *json_obj_get(JSONObject *obj, const char *key); -INLINE JSONObject *json_new_object(JsonAllocator *allocator, JSONType type); -void json_free(JsonDeallocator *deallocator, JSONObject **ptr); +JSONObject *json_map_get(JSONObject *obj, const char *key); +void json_map_set(JSONObject *obj, const char *key, JSONObject *value); +INLINE JSONObject *json_new_object(JSONType type); void print_json_to_file(JSONObject *obj, FILE *file); - -INLINE JSONObject *json_new_object(JsonAllocator *allocator, JSONType type) +INLINE JSONObject *json_new_string(const char *str) { - JSONObject *obj = allocator(sizeof(JSONObject)); - obj->type = type; + JSONObject *obj = malloc_arena(sizeof(JSONObject)); + *obj = (JSONObject) { .type = J_STRING, .str = str }; + return obj; +} + +INLINE JSONObject *json_new_map(void) +{ + JSONObject *obj = malloc_arena(sizeof(JSONObject)); + *obj = (JSONObject) { .type = J_OBJECT }; + return obj; +} + +INLINE JSONObject *json_new_object(JSONType type) +{ + JSONObject *obj = malloc_arena(sizeof(JSONObject)); + *obj = (JSONObject) { .type = type }; return obj; }