diff --git a/src/cfg/opt.c b/src/cfg/opt.c index ad86285..f58c93e 100644 --- a/src/cfg/opt.c +++ b/src/cfg/opt.c @@ -7,6 +7,7 @@ #include #include #include +#include static GHashTable* args = NULL; @@ -188,10 +189,10 @@ void print_help(void) { } } -static void get_bool(bool* boolean, toml_table_t *table, const char* name) { +static void get_bool(bool* boolean, const toml_table_t *table, const char* name) { DEBUG("retrieving boolean %s", name); - toml_datum_t datum = toml_bool_in(table, name); + const toml_datum_t datum = toml_bool_in(table, name); if (datum.ok) { *boolean = datum.u.b; @@ -199,10 +200,10 @@ static void get_bool(bool* boolean, toml_table_t *table, const char* name) { } } -static void get_str(char** string, toml_table_t *table, const char* name) { +static void get_str(char** string, const toml_table_t *table, const char* name) { DEBUG("retrieving string %s", name); - toml_datum_t datum = toml_string_in(table, name); + const toml_datum_t datum = toml_string_in(table, name); if (datum.ok) { *string = datum.u.s; @@ -210,10 +211,10 @@ static void get_str(char** string, toml_table_t *table, const char* name) { } } -static void get_int(int* integer, toml_table_t *table, const char* name) { +static void get_int(int* integer, const toml_table_t *table, const char* name) { DEBUG("retrieving integer %s", name); - toml_datum_t datum = toml_int_in(table, name); + const toml_datum_t datum = toml_int_in(table, name); if (datum.ok) { *integer = (int) datum.u.i; @@ -221,7 +222,7 @@ static void get_int(int* integer, toml_table_t *table, const char* name) { } } -static int parse_project_table(ProjectConfig *config, toml_table_t *project_table) { +static int parse_project_table(ProjectConfig *config, const toml_table_t *project_table) { DEBUG("parsing project table..."); // project name @@ -268,7 +269,7 @@ static int get_mode_from_str(TargetCompilationMode* mode, const char* name) { return PROJECT_SEMANTIC_ERR; } -static int parse_target(ProjectConfig *config, toml_table_t *target_table, const char* name) { +static int parse_target(const ProjectConfig *config, const toml_table_t *target_table, const char* name) { DEBUG("parsing target table..."); TargetConfig* target_config = default_target_config(); @@ -297,7 +298,7 @@ static int parse_target(ProjectConfig *config, toml_table_t *target_table, const return PROJECT_OK; } -static int parse_targets(ProjectConfig *config, toml_table_t *root) { +static int parse_targets(ProjectConfig *config, const toml_table_t *root) { DEBUG("parsing targets of project \"%s\"", config->name); toml_table_t *targets = toml_table_in(root, "target"); @@ -311,7 +312,7 @@ static int parse_targets(ProjectConfig *config, toml_table_t *root) { for (int i = 0; i < MAX_TARGETS_PER_PROJECT; i++) { const char *key = toml_key_in(targets, i); - if (!key) + if (key == NULL) break; toml_table_t *target = toml_table_in(targets, key); @@ -331,18 +332,18 @@ int load_project_config(ProjectConfig *config) { return PROJECT_TOML_ERR; } - char err_buf[200]; + char err_buf[TOML_ERROR_MSG_BUF]; toml_table_t *conf = toml_parse_file(config_file, err_buf, sizeof(err_buf)); fclose(config_file); - if (!conf) { + if (conf == NULL) { print_message(Error, "Invalid project configuration: %s", err_buf); return PROJECT_SEMANTIC_ERR; } toml_table_t *project = toml_table_in(conf, "project"); - if (!project) { + if (project == NULL) { print_message(Error, "Invalid project configuration: missing project table."); } diff --git a/src/cfg/opt.h b/src/cfg/opt.h index 9f0b7c0..eca919f 100644 --- a/src/cfg/opt.h +++ b/src/cfg/opt.h @@ -5,7 +5,6 @@ #ifndef GEMSTONE_OPT_H #define GEMSTONE_OPT_H -#include #include #define MAX_TARGETS_PER_PROJECT 100 @@ -15,11 +14,20 @@ #define PROJECT_TOML_ERR 1 #define PROJECT_SEMANTIC_ERR 2 +#define TOML_ERROR_MSG_BUF 256 + typedef enum TargetCompilationMode_t { + // output an executable binary Application, + // output a binary object file Library } TargetCompilationMode; +/** + * @brief A target defines a source file which is to be compiled into a specific + * format. Additionally properties such as output folders can be set. + * Intermediate representations can be printed as well. + */ typedef struct TargetConfig_t { char* name; bool print_ast; @@ -38,6 +46,11 @@ typedef struct TargetConfig_t { int optimization_level; } TargetConfig; +/** + * @brief A project is a collection of targets. Each target can point to + * very different sources. The project binds these targets together + * and specifies metadata about the authors and others. + */ typedef struct ProjectConfig_t { // name of the project char* name; @@ -52,35 +65,102 @@ typedef struct ProjectConfig_t { GHashTable* targets; } ProjectConfig; +/** + * @brief Represents a command line option. + */ typedef struct Option_t { + // index in which the option appeared in the argument array int index; + // identifier of the option const char* string; + // option if format is equals to --option=value const char* value; + // whether or not this option has a value bool is_opt; } Option; +/** + * @brief Create the default configuration for targets. + * @return A pointer to a new target configuration. + */ +[[nodiscard("must be freed")]] TargetConfig* default_target_config(); +/** + * @brief Create the default configuration for a project. + * Contains no targets. + * @return A pointer to a new project configuration. + */ +[[nodiscard("must be freed")]] ProjectConfig* default_project_config(); +/** + * @brief Create a new default target configuration an write command line + * option onto the default configuration. + * @return A default config with user specified values. + */ +[[nodiscard("must be freed")]] TargetConfig* default_target_config_from_args(); +/** + * @brief Load a project configuration from a TOML file with the name + * PROJECT_CONFIG_FILE. + * @param config Configuration to fill values from file into. + * @return + */ +[[gnu::nonnull(1)]] int load_project_config(ProjectConfig *config); +/** + * @brief Print a help dialog to stdout. + */ void print_help(void); +/** + * @brief Delete a project config by deallocation. + * @param config The config to free. + */ +[[gnu::nonnull(1)]] void delete_project_config(ProjectConfig* config); +/** + * @brief Delete a target configuration by deallocation. + */ +[[gnu::nonnull(1)]] void delete_target_config(TargetConfig*); +/** + * @brief Parse the given command line arguments so that calls to + * is_option_set() and get_option() can be made safely. + * @param argc Number of arguments + * @param argv Array of arguments + */ void parse_options(int argc, char* argv[]); +/** + * @brief Tests whether an option was set as argument. + * @attention Requires a previous call to parse_options() + * @param option Name of option to check for. + * @return 1 if the options was set, 0 otherwise + */ [[gnu::nonnull(1)]] bool is_option_set(const char* option); +/** + * @brief Returns the options information if present + * @attention Requires a previous call to parse_options() + * @param option + * @return A valid option struct or NULL if not found. + */ [[gnu::nonnull(1)]] const Option* get_option(const char* option); +/** + * @brief Put a copy of all options whos index is greather than the index + * of the option specified by command. + * @param command + * @return an array of options that followed command. + */ [[gnu::nonnull(1)]] [[nodiscard("must be freed")]] GArray* get_non_options_after(const char* command); diff --git a/src/compiler.c b/src/compiler.c index 69e4e02..709592e 100644 --- a/src/compiler.c +++ b/src/compiler.c @@ -72,9 +72,7 @@ static int setup_target_environment(const TargetConfig *target) { assert(target->output_directory != NULL); assert(target->archive_directory != NULL); - int result; - - result = create_directory(target->archive_directory); + int result = create_directory(target->archive_directory); if (result != 0 && errno != EEXIST) { const char *message = get_last_error(); assert(message != NULL); @@ -102,7 +100,7 @@ static int setup_target_environment(const TargetConfig *target) { * @param ast * @param target */ -static void print_ast_to_file(AST_NODE_PTR ast, TargetConfig *target) { +static void print_ast_to_file(const AST_NODE_PTR ast, const TargetConfig *target) { assert(ast != NULL); assert(target != NULL); @@ -132,7 +130,7 @@ static void print_ast_to_file(AST_NODE_PTR ast, TargetConfig *target) { * @param unit * @param target */ -static void build_target(ModuleFileStack *unit, TargetConfig *target) { +static void build_target(ModuleFileStack *unit, const TargetConfig *target) { print_message(Info, "Building target: %s", target->name); AST_NODE_PTR ast = AST_new_node(empty_location(), AST_Module, NULL); @@ -157,8 +155,6 @@ static void build_target(ModuleFileStack *unit, TargetConfig *target) { * @brief Compile a single file. * Creates a single target by the given command line arguments. * @param unit - * @param argc - * @param argv */ static void compile_file(ModuleFileStack *unit) { INFO("compiling basic files..."); @@ -181,7 +177,7 @@ static void compile_file(ModuleFileStack *unit) { * @param unit * @param config */ -static void build_project_targets(ModuleFileStack *unit, ProjectConfig *config) { +static void build_project_targets(ModuleFileStack *unit, const ProjectConfig *config) { if (is_option_set("all")) { // build all targets in the project GHashTableIter iter; diff --git a/src/io/files.c b/src/io/files.c index 0ea8993..5f3ad02 100644 --- a/src/io/files.c +++ b/src/io/files.c @@ -6,7 +6,6 @@ #include #include #include -#include #ifdef __unix__ @@ -49,7 +48,7 @@ ModuleFile *push_file(ModuleFileStack *stack, const char *path) { void delete_files(ModuleFileStack *stack) { for (size_t i = 0; i < stack->files->len; i++) { - ModuleFile *file = ((ModuleFile *) stack->files->data) + i; + const ModuleFile *file = (ModuleFile *) stack->files->data + i; if (file->handle != NULL) { DEBUG("closing file: %s", file->path); @@ -62,6 +61,8 @@ void delete_files(ModuleFileStack *stack) { DEBUG("deleted module file stack"); } +// Number of bytes to read at once whilest +// seeking the current line in print_diagnostic() #define SEEK_BUF_BYTES 256 static inline unsigned long int min(unsigned long int a, unsigned long int b) { @@ -121,16 +122,15 @@ void print_diagnostic(ModuleFile *file, TokenLocation *location, Message kind, c free((void *) absolute_path); - size_t lines = location->line_end - location->line_start + 1; + const size_t lines = location->line_end - location->line_start + 1; for (size_t l = 0; l < lines; l++) { printf(" %4ld | ", location->line_start + l); - size_t limit; size_t chars = 0; // print line before token group start - limit = min(location->col_start, SEEK_BUF_BYTES); + size_t limit = min(location->col_start, SEEK_BUF_BYTES); while (limit > 1) { custom_fgets(buffer, (int) limit, file->handle); chars += printf("%s", buffer);