mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
Use arena with JSON parser. Slightly altered output for json printing.
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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");
|
||||
|
||||
151
src/utils/json.c
151
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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user