Feature/add-target (#1) (#1350)

Feature/add target (#1) project add-target command
This commit is contained in:
kostyavechkanov
2024-08-13 21:34:53 +10:00
committed by GitHub
parent ddecf2d5f0
commit 800ad9e898
9 changed files with 295 additions and 116 deletions

View File

@@ -3,8 +3,8 @@
// Use of this source code is governed by the GNU LGPLv3.0 license
// a copy of which can be found in the LICENSE file.
#include "../version.h"
#include "../utils/lib.h"
#include "../version.h"
#include <stdint.h>
#define MAX_BUILD_LIB_DIRS 1024
@@ -48,16 +48,16 @@ typedef enum
COMMAND_PROJECT,
} CompilerCommand;
typedef enum
{
SUBCOMMAND_MISSING = 0,
SUBCOMMAND_VIEW
SUBCOMMAND_VIEW,
SUBCOMMAND_ADD
} ProjectSubcommand;
typedef enum
{
DIAG_NONE = 0, // Don't use!
DIAG_NONE = 0, // Don't use!
DIAG_WARNING_TYPE, // Don't use!
DIAG_UNUSED,
DIAG_UNUSED_PARAMETER,
@@ -133,10 +133,10 @@ typedef enum
typedef enum
{
OPTIMIZATION_NOT_SET = -1,
OPTIMIZATION_NONE = 0, // -O0
OPTIMIZATION_LESS = 1, // -O1
OPTIMIZATION_MORE = 2, // -O2
OPTIMIZATION_AGGRESSIVE = 3, // -O3
OPTIMIZATION_NONE = 0, // -O0
OPTIMIZATION_LESS = 1, // -O1
OPTIMIZATION_MORE = 2, // -O2
OPTIMIZATION_AGGRESSIVE = 3, // -O3
} OptimizationLevel;
typedef enum
@@ -149,7 +149,7 @@ typedef enum
typedef enum
{
SINGLE_MODULE_NOT_SET = -1,
SINGLE_MODULE_OFF = 0, // NOLINT
SINGLE_MODULE_OFF = 0, // NOLINT
SINGLE_MODULE_ON = 1
} SingleModule;
@@ -211,9 +211,9 @@ typedef enum
typedef enum
{
SIZE_OPTIMIZATION_NOT_SET = -1,
SIZE_OPTIMIZATION_NONE = 0, // None
SIZE_OPTIMIZATION_SMALL = 1, // -Os
SIZE_OPTIMIZATION_TINY = 2, // -Oz
SIZE_OPTIMIZATION_NONE = 0, // None
SIZE_OPTIMIZATION_SMALL = 1, // -Os
SIZE_OPTIMIZATION_TINY = 2, // -Oz
} SizeOptimizationLevel;
typedef enum
@@ -233,7 +233,7 @@ typedef enum
typedef enum
{
STRUCT_RETURN_DEFAULT = -1,
STRUCT_RETURN_STACK = 0, // NOLINT
STRUCT_RETURN_STACK = 0, // NOLINT
STRUCT_RETURN_REG = 1
} StructReturn;
@@ -351,6 +351,34 @@ typedef enum
#define ANY_WINDOWS_ARCH_OS WINDOWS_AARCH64: case WINDOWS_X64: case MINGW_X64
typedef enum
{
TARGET_TYPE_EXECUTABLE,
TARGET_TYPE_STATIC_LIB,
TARGET_TYPE_DYNAMIC_LIB,
TARGET_TYPE_OBJECT_FILES,
TARGET_TYPE_BENCHMARK,
TARGET_TYPE_TEST,
} TargetType;
static const char *targets[6] = {
[TARGET_TYPE_EXECUTABLE] = "executable",
[TARGET_TYPE_STATIC_LIB] = "static-lib",
[TARGET_TYPE_DYNAMIC_LIB] = "dynamic-lib",
[TARGET_TYPE_BENCHMARK] = "benchmark",
[TARGET_TYPE_TEST] = "test",
[TARGET_TYPE_OBJECT_FILES] = "object-files"
};
static const char *target_desc[6] = {
[TARGET_TYPE_EXECUTABLE] = "Executable",
[TARGET_TYPE_STATIC_LIB] = "Static library",
[TARGET_TYPE_DYNAMIC_LIB] = "Dynamic library",
[TARGET_TYPE_BENCHMARK] = "benchmark suite",
[TARGET_TYPE_TEST] = "test suite",
[TARGET_TYPE_OBJECT_FILES] = "object files"
};
typedef struct BuildOptions_
{
const char *lib_dir[MAX_BUILD_LIB_DIRS];
@@ -365,17 +393,20 @@ typedef struct BuildOptions_
size_t linker_lib_count;
const char* std_lib_dir;
VectorConv vector_conv;
struct {
struct
{
const char *sdk;
const char *def;
WinCrtLinking crt_linking;
} win;
struct {
struct
{
const char *sysroot;
const char *min_version;
const char *sdk_version;
} macos;
struct {
struct
{
const char *crt;
const char *crtbegin;
} linuxpaths;
@@ -397,7 +428,12 @@ typedef struct BuildOptions_
bool silence_deprecation;
CompilerBackend backend;
CompilerCommand command;
ProjectSubcommand subcommand;
struct
{
ProjectSubcommand command;
const char *target_name;
TargetType target_type;
} project_options;
CompileOption compile_option;
TrustLevel trust_level;
DiagnosticsSeverity severity[DIAG_END_SENTINEL];
@@ -459,16 +495,6 @@ typedef struct BuildOptions_
bool testing;
} BuildOptions;
typedef enum
{
TARGET_TYPE_EXECUTABLE,
TARGET_TYPE_STATIC_LIB,
TARGET_TYPE_DYNAMIC_LIB,
TARGET_TYPE_OBJECT_FILES,
TARGET_TYPE_BENCHMARK,
TARGET_TYPE_TEST,
} TargetType;
typedef struct
{
struct Library__ *parent;
@@ -500,7 +526,6 @@ typedef struct Library__
LibraryTarget **targets;
} Library;
typedef struct
{
TargetType type;
@@ -681,8 +706,10 @@ BuildOptions parse_arguments(int argc, const char *argv[]);
ArchOsTarget arch_os_target_from_string(const char *target);
bool command_accepts_files(CompilerCommand command);
bool command_passes_args(CompilerCommand command);
void update_build_target_with_opt_level(BuildTarget *target, OptimizationSetting level);
void update_build_target_with_opt_level(BuildTarget *target,
OptimizationSetting level);
void create_project(BuildOptions *build_options);
void create_library(BuildOptions *build_options);
void resolve_libraries(BuildTarget *build_target);
void view_project(BuildOptions *build_options);
void view_project(BuildOptions *build_options);
void add_target_project(BuildOptions *build_options);

View File

@@ -104,7 +104,7 @@ BuildTarget *project_select_target(Project *project, const char *optional_target
void update_feature_flags(const char ***flags, const char ***removed_flag, const char *arg, bool add);
const char *get_string(const char *file, const char *category, JSONObject *table, const char *key,
const char *default_value);
const char *default_value);
int get_valid_bool(const char *file, const char *target, JSONObject *json, const char *key, int default_val);
const char *get_optional_string(const char *file, const char *category, JSONObject *table, const char *key);
const char *get_mandatory_string(const char *file, const char *category, JSONObject *object, const char *key);
@@ -112,7 +112,8 @@ const char **get_string_array(const char *file, const char *category, JSONObject
const char **get_optional_string_array(const char *file, const char *target, JSONObject *table, const char *key);
const char *get_cflags(const char *file, const char *target, JSONObject *json, const char *original_flags);
void get_list_append_strings(const char *file, const char *target, JSONObject *json, const char ***list_ptr,
const char *base, const char *override, const char *add);
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);
void check_json_keys(const char* valid_keys[][2], size_t key_count, const char* deprecated_keys[], size_t deprecated_key_count, JSONObject *json, const char *target_name, const char *option);
const char *base, const char *override, const char *add);
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);
int get_valid_enum_from_string(const char *str, const char *target, const char **values, int count, const char *expected);
void check_json_keys(const char *valid_keys[][2], size_t key_count, const char *deprecated_keys[], size_t deprecated_key_count, JSONObject *json, const char *target_name, const char *option);
long get_valid_integer(JSONObject *table, const char *key, const char *category, bool mandatory);

View File

@@ -2,8 +2,9 @@
// Use of this source code is governed by the GNU LGPLv3.0 license
// a copy of which can be found in the LICENSE file.
#include "build_internal.h"
#include "../utils/whereami.h"
#include "build.h"
#include "build_internal.h"
extern int llvm_version_major;
bool silence_deprecation;
@@ -216,7 +217,6 @@ static inline const char *next_arg()
return current_arg;
}
static inline bool next_is_opt()
{
return args[arg_index + 1][0] == '-';
@@ -283,26 +283,43 @@ static void project_usage()
PRINTF("Usage: %s [<options>] project <subcommand> [<args>]", args[0]);
PRINTF("");
PRINTF("Project Subcommands:");
PRINTF(" view view the current projects structure");
PRINTF(" view view the current projects structure");
PRINTF(" add-target <name> <target_type> add a new target to the project");
}
static void parse_project_subcommand(BuildOptions *options)
{
if (arg_match("view"))
{
options->subcommand = SUBCOMMAND_VIEW;
options->project_options.command = SUBCOMMAND_VIEW;
return;
}
PROJECT_FAIL_WITH_ERR("Cannot process the unknown subcommand \"%s\".", current_arg);
if (arg_match("add-target"))
{
options->project_options.command = SUBCOMMAND_ADD;
if (at_end() || next_is_opt()) error_exit("Expected a target name");
options->project_options.target_name = next_arg();
if (at_end() || next_is_opt()) error_exit("Expected a target type like 'executable' or 'static-lib'");
options->project_options.target_type = (TargetType)get_valid_enum_from_string(next_arg(), "type", targets, ELEMENTLEN(targets), "a target type like 'executable' or 'static-lib'");
return;
}
PROJECT_FAIL_WITH_ERR("Cannot process the unknown subcommand \"%s\".",
current_arg);
}
static void parse_project_options(BuildOptions *options)
{
options->project_options.command = SUBCOMMAND_MISSING;
if (at_end())
{
project_usage();
return;
}
next_arg();
parse_project_subcommand(options);
}
@@ -437,7 +454,6 @@ static void parse_command(BuildOptions *options)
if (arg_match("project"))
{
options->command = COMMAND_PROJECT;
options->subcommand = SUBCOMMAND_MISSING;
parse_project_options(options);
return;
}
@@ -1185,7 +1201,6 @@ static void parse_option(BuildOptions *options)
FAIL_WITH_ERR("Cannot process the unknown option \"%s\".", current_arg);
}
BuildOptions parse_arguments(int argc, const char *argv[])
{
arg_count = argc;
@@ -1284,7 +1299,6 @@ BuildOptions parse_arguments(int argc, const char *argv[])
return build_options;
}
ArchOsTarget arch_os_target_from_string(const char *target)
{
for (unsigned i = 1; i <= ARCH_OS_TARGET_LAST; i++)

View File

@@ -180,6 +180,17 @@ int get_valid_string_setting(const char *file, const char *target, JSONObject *j
error_exit("In file '%s': Invalid value for '%s', expected %s", file, key, expected);
}
int get_valid_enum_from_string(const char *str, const char *target, const char **values, int count, const char *expected)
{
int res = str_findlist(str, count, values);
if (res >= 0) return res;
if (target)
{
error_exit("'%s' had an invalid value, expected %s", target, expected);
}
error_exit("Invalid value, expected %s", expected);
}
long get_valid_integer(JSONObject *table, const char *key, const char *category, bool mandatory)
{
JSONObject *value = json_obj_get(table, key);

View File

@@ -423,22 +423,6 @@ static void project_add_target(Project *project, BuildTarget *default_target, J
static void project_add_targets(Project *project, JSONObject *project_data)
{
assert(project_data->type == J_OBJECT);
static const char* targets[6] = {
[TARGET_TYPE_EXECUTABLE] = "executable",
[TARGET_TYPE_STATIC_LIB] = "static-lib",
[TARGET_TYPE_DYNAMIC_LIB] = "dynamic-lib",
[TARGET_TYPE_BENCHMARK] = "benchmark",
[TARGET_TYPE_TEST] = "test",
[TARGET_TYPE_OBJECT_FILES] = "object-files"
};
static const char *target_desc[6] = {
[TARGET_TYPE_EXECUTABLE] = "Executable",
[TARGET_TYPE_STATIC_LIB] = "Static library",
[TARGET_TYPE_DYNAMIC_LIB] = "Dynamic library",
[TARGET_TYPE_BENCHMARK] = "benchmark suite",
[TARGET_TYPE_TEST] = "test suite",
[TARGET_TYPE_OBJECT_FILES] = "object files"
};
BuildTarget default_target = default_build_target;
load_into_build_target(project_data, NULL, &default_target);

View File

@@ -1,7 +1,7 @@
#include "build_internal.h"
#define PRINTFN(string, ...) fprintf(stdout, string "\n", ##__VA_ARGS__) // NOLINT
#define PRINTF(string, ...) fprintf(stdout, string, ##__VA_ARGS__) // NOLINT
static JSONObject* read_project()
static JSONObject *read_project()
{
size_t size;
char *read = file_read_all(PROJECT_JSON, &size);
@@ -19,52 +19,52 @@ static JSONObject* read_project()
return json;
}
static void print_vec(const char* header, const char** vec, bool opt)
static void print_vec(const char *header, const char **vec, bool opt)
{
if (opt && !vec) return;
PRINTF("%s: ", header);
if (!vec_size(vec))
if (!vec_size(vec))
{
PRINTFN("*none*");
return;
}
FOREACH_IDX(i, const char *, item, vec)
}
FOREACH_IDX(i, const char *, item, vec)
{
if (i > 0) PRINTF(", ");
PRINTF("%s",item);
PRINTF("%s", item);
}
PRINTFN("");
}
static void print_opt_str(const char* header, const char* str)
static void print_opt_str(const char *header, const char *str)
{
if (!str) return;
PRINTFN("%s: %s", header, str);
}
static void print_opt_setting(const char* header, int setting, const char** values)
static void print_opt_setting(const char *header, int setting, const char **values)
{
if (setting < 0) return;
PRINTFN("%s: %s", header, values[setting]);
}
static void print_opt_bool(const char* header, int b)
static void print_opt_bool(const char *header, int b)
{
if (b == -1) return;
PRINTF("%s: ", header);
PRINTFN(b ? "true" : "false");
}
static void print_opt_int(const char* header, long v)
static void print_opt_int(const char *header, long v)
{
if (v < 0) return;
PRINTFN("%s: %ld", header, v);
}
static const char* generate_expected(const char** options, size_t n)
static const char *generate_expected(const char **options, size_t n)
{
scratch_buffer_clear();
for (size_t i = 0; i < n; i++)
for (size_t i = 0; i < n; i++)
{
if (i > 0) scratch_buffer_append(", ");
if (i == n - 1) scratch_buffer_append(" or ");
@@ -74,7 +74,7 @@ static const char* generate_expected(const char** options, size_t n)
}
const char* optimization_levels[] = {
const char *optimization_levels[] = {
[OPT_SETTING_O0] = "O0",
[OPT_SETTING_O1] = "O1",
[OPT_SETTING_O2] = "O2",
@@ -82,10 +82,10 @@ const char* optimization_levels[] = {
[OPT_SETTING_O4] = "O4",
[OPT_SETTING_O5] = "O5",
[OPT_SETTING_OSMALL] = "Os",
[OPT_SETTING_OTINY] = "Oz"
[OPT_SETTING_OTINY] = "Oz"
};
const char* debug_levels[] = {
const char *debug_levels[] = {
[DEBUG_INFO_NONE] = "none",
[DEBUG_INFO_LINE_TABLES] = "line-tables",
[DEBUG_INFO_FULL] = "full"
@@ -171,12 +171,12 @@ do {\
print_opt_int("\t" header, v);\
} while(0);
static void view_target(const char* name, JSONObject* target)
static void view_target(const char *name, JSONObject *target)
{
/* General target information */
PRINTFN("- %s",name);
PRINTFN("- %s", name);
print_opt_str("\tName", name);
TARGET_VIEW_MANDATORY_STRING("Type","type");
TARGET_VIEW_MANDATORY_STRING("Type", "type");
TARGET_VIEW_STRING("Target language target", "langrev");
TARGET_VIEW_STRING_ARRAY("Warnings used", "warnings");
TARGET_VIEW_STRING_ARRAY("Additional c3l library search paths", "dependency-search-paths");
@@ -204,7 +204,7 @@ static void view_target(const char* name, JSONObject* target)
TARGET_VIEW_SETTING("Floating point behaviour", "fp-math", fp_math);
TARGET_VIEW_STRING_ARRAY("Additional linked libraries", "linked-libraries");
TARGET_VIEW_STRING_ARRAY("Linked libraries (override)", "linked-libraries-override");
TARGET_VIEW_STRING("Linker","linker");
TARGET_VIEW_STRING("Linker", "linker");
TARGET_VIEW_STRING_ARRAY("Additional linker search paths", "linker-search-paths");
TARGET_VIEW_STRING_ARRAY("Linker search paths (override)", "linker-search-paths-override");
TARGET_VIEW_STRING_ARRAY("Additional linker arguments", "link-args");
@@ -236,13 +236,52 @@ static void view_target(const char* name, JSONObject* target)
TARGET_VIEW_BOOL("Return structs on the stack", "x86-stack-struct-return");
}
void view_project(BuildOptions *build_options)
void add_target_project(BuildOptions *build_options)
{
JSONObject* project_json = read_project();
JSONObject *project_json = read_project();
JSONObject *targets_json = json_obj_get(project_json, "targets");
for (unsigned i = 0; i < targets_json->member_len; i++)
{
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);
}
}
JSONObject *target_type_obj = json_new_object(&malloc_arena, J_STRING);
target_type_obj->str = targets[build_options->project_options.target_type];
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++;
FILE *file = fopen(PROJECT_JSON, "w");
print_json_to_file(project_json, file);
fclose(file);
}
void view_project(BuildOptions *build_options)
{
JSONObject *project_json = read_project();
/* General information */
VIEW_MANDATORY_STRING_ARRAY("Authors","authors");
VIEW_MANDATORY_STRING("Version","version");
VIEW_MANDATORY_STRING_ARRAY("Authors", "authors");
VIEW_MANDATORY_STRING("Version", "version");
VIEW_MANDATORY_STRING("Project language target", "langrev");
VIEW_MANDATORY_STRING_ARRAY("Warnings used", "warnings");
VIEW_MANDATORY_STRING_ARRAY("c3l library search paths", "dependency-search-paths");
@@ -262,7 +301,7 @@ void view_project(BuildOptions *build_options)
VIEW_STRING_ARRAY("Enabled features", "features");
VIEW_SETTING("Floating point behaviour", "fp-math", fp_math);
VIEW_STRING_ARRAY("Linked libraries", "linked-libraries");
VIEW_STRING("Linker","linker");
VIEW_STRING("Linker", "linker");
VIEW_STRING_ARRAY("Linker search paths", "linker-search-paths");
VIEW_STRING_ARRAY("Linker arguments", "link-args");
VIEW_BOOL("Link libc", "link-libc");
@@ -303,14 +342,15 @@ 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++)
for (unsigned i = 0; i < targets_json->member_len; i++)
{
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);
}
view_target(key,object);
view_target(key, object);
}
}

View File

@@ -1,8 +1,9 @@
#include <compiler_tests/benchmark.h>
#include "compiler/compiler.h"
#include "build/build.h"
#include "compiler/compiler.h"
#include "compiler_tests/tests.h"
#include "utils/lib.h"
#include <compiler_tests/benchmark.h>
bool debug_log = false;
bool debug_stats = false;
@@ -99,13 +100,16 @@ int main_real(int argc, const char *argv[])
compile_file_list(&build_options);
break;
case COMMAND_PROJECT:
switch (build_options.subcommand)
switch (build_options.project_options.command)
{
case SUBCOMMAND_VIEW:
view_project(&build_options);
break;
case SUBCOMMAND_ADD:
add_target_project(&build_options);
break;
case SUBCOMMAND_MISSING:
UNREACHABLE
break;
}
break;
case COMMAND_MISSING:
@@ -121,7 +125,7 @@ int main_real(int argc, const char *argv[])
int wmain(int argc, const uint16_t *argv[])
{
char** args = malloc(sizeof(void*) * (unsigned)argc);
char **args = malloc(sizeof(void *) * (unsigned)argc);
for (unsigned i = 0; i < (unsigned)argc; i++)
{
args[i] = win_utf16to8(argv[i]);
@@ -131,9 +135,6 @@ int wmain(int argc, const uint16_t *argv[])
#else
int main(int argc, const char *argv[])
{
return main_real(argc, argv);
}
int main(int argc, const char *argv[]) { return main_real(argc, argv); }
#endif
#endif

View File

@@ -2,6 +2,8 @@
#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 };
@@ -16,7 +18,7 @@ static inline void json_skip_whitespace(JsonParser *parser)
char c;
while (1)
{
RETRY:
RETRY:
switch (parser->current[0])
{
case '/':
@@ -24,7 +26,7 @@ static inline void json_skip_whitespace(JsonParser *parser)
if (c == '/')
{
parser->current++;
while ((c = (++parser->current)[0]) && c != '\n') {}
while ((c = (++parser->current)[0]) && c != '\n') { }
goto RETRY;
}
if (c == '*')
@@ -259,6 +261,7 @@ static inline void json_lexer_advance(JsonParser *parser)
}
UNREACHABLE
}
static inline bool consume(JsonParser *parser, JSONTokenType token)
{
if (parser->current_token_type == token)
@@ -272,27 +275,27 @@ static inline bool consume(JsonParser *parser, JSONTokenType token)
JSONObject *json_parse_array(JsonParser *parser)
{
CONSUME(T_LBRACKET);
if (consume(parser, T_RBRACKET))
{
return &empty_array_val;
}
if (consume(parser, T_RBRACKET)) return &empty_array_val;
size_t capacity = 16;
JSONObject *array = json_new_object(parser->allocator, J_ARRAY);
JSONObject** elements = parser->allocator(sizeof(JSONObject*) * capacity);
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*);
size_t copy_size = capacity * sizeof(JSONObject *);
capacity *= 2;
elements = parser->allocator(sizeof(JSONObject*) * capacity);
elements = parser->allocator(sizeof(JSONObject *) * capacity);
memcpy(elements, elements_old, copy_size);
}
elements[index++] = parsed;
if (consume(parser, T_RBRACKET)) break;
CONSUME(T_COMMA);
// Allow trailing comma
@@ -306,35 +309,42 @@ JSONObject *json_parse_array(JsonParser *parser)
JSONObject *json_parse_object(JsonParser *parser)
{
CONSUME(T_LBRACE);
if (consume(parser, T_RBRACE))
{
return &empty_obj_val;
}
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);
JSONObject **elements = parser->allocator(sizeof(JSONObject *) * capacity);
const char **keys = parser->allocator(sizeof(JSONObject *) * capacity);
size_t index = 0;
while (1)
{
const char *key = parser->last_string;
CONSUME(T_STRING);
CONSUME(T_COLON);
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*);
size_t copy_size = capacity * sizeof(void *);
capacity *= 2;
elements = parser->allocator(sizeof(JSONObject*) * capacity);
keys = parser->allocator(sizeof(JSONObject*) * capacity);
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;
if (consume(parser, T_RBRACE)) break;
if (!consume(parser, T_COMMA))
{
@@ -391,7 +401,7 @@ JSONObject *json_parse(JsonParser *parser)
case T_NUMBER:
{
JSONObject *obj = NULL;
if (parser->last_number == 0)
if (parser->last_number == 0)
{
json_lexer_advance(parser);
return &zero_val;
@@ -441,13 +451,13 @@ void json_free(JsonDeallocator *deallocator, JSONObject **ptr)
if (!is_freable(obj)) return;
switch(obj->type)
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((char *)obj->keys[i]);
}
deallocator(obj->keys);
deallocator(obj->members);
@@ -460,7 +470,7 @@ void json_free(JsonDeallocator *deallocator, JSONObject **ptr)
deallocator(obj->elements);
break;
case J_STRING:
deallocator((char*)obj->str);
deallocator((char *)obj->str);
break;
default:
break;
@@ -468,3 +478,93 @@ void json_free(JsonDeallocator *deallocator, JSONObject **ptr)
deallocator(*ptr);
*ptr = NULL;
}
static inline void print_indent(int indent_level, FILE *file)
{
for (int i = 0; i < indent_level; i++)
{
fputs(" ", file);
}
}
static inline void print_json(JSONObject *obj, int indent_level, FILE *file)
{
if (obj == NULL)
{
return;
}
switch (obj->type)
{
case J_BOOL:
PRINTF(file, "%s", obj->b ? "true" : "false");
break;
case J_STRING:
PRINTF(file, "\"%s\"", obj->str);
break;
case J_NUMBER:
PRINTF(file, "%f", obj->f);
break;
case J_ARRAY:
fputs(" [ ", file);
if (obj->array_len == 0)
{
fputs(" ]", file);
break;
}
bool should_print_item_per_line = false;
for (size_t i = 0; i < obj->array_len; i++)
{
if (obj->elements[i]->type == J_OBJECT)
{
should_print_item_per_line = true;
break;
}
}
if (!should_print_item_per_line && obj->array_len < 5)
{
for (size_t i = 0; i < obj->array_len; i++)
{
if (i != 0) fputs(", ", file);
print_json(obj->elements[i], 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(" ]", file);
break;
case J_OBJECT:
fputs("{\n", file);
for (size_t i = 0; i < obj->member_len; i++)
{
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_indent(indent_level, file);
fputs("}", file);
break;
default:
break;
}
}
void print_json_to_file(JSONObject *obj, FILE *file)
{
print_json(obj, 0, file);
}

View File

@@ -6,7 +6,7 @@ typedef enum
J_ARRAY,
J_NUMBER,
J_BOOL,
J_ERROR,
J_ERROR
} JSONType;
@@ -46,11 +46,11 @@ typedef enum JSONTokenType_
T_TRUE,
T_FALSE,
T_NULL,
T_EOF,
T_EOF
} JSONTokenType;
typedef void*(JsonAllocator)(size_t);
typedef void*(JsonDeallocator)(void*);
typedef void *(JsonAllocator)(size_t);
typedef void *(JsonDeallocator)(void *);
typedef struct
{
@@ -68,6 +68,7 @@ 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);
void print_json_to_file(JSONObject *obj, FILE *file);
INLINE JSONObject *json_new_object(JsonAllocator *allocator, JSONType type)