fixed implementation vaults

This commit is contained in:
Sven Vogel 2024-05-31 21:25:37 +02:00
parent 76b011511a
commit 8f24596779
4 changed files with 260 additions and 74 deletions

View File

@ -27,6 +27,8 @@ set(CMAKE_C_STANDARD_REQUIRED TRUE)
set(GEMSTONE_TEST_DIR ${PROJECT_SOURCE_DIR}/tests) set(GEMSTONE_TEST_DIR ${PROJECT_SOURCE_DIR}/tests)
set(GEMSTONE_BINARY_DIR ${PROJECT_SOURCE_DIR}/bin) set(GEMSTONE_BINARY_DIR ${PROJECT_SOURCE_DIR}/bin)
add_compile_definitions(GSC_VERSION="${PROJECT_VERSION}")
include(CTest) include(CTest)
if(BUILD_TESTING) if(BUILD_TESTING)
@ -144,6 +146,9 @@ target_compile_options(release PUBLIC ${FLAGS} ${RELEASE_FLAGS})
# add src directory as include path # add src directory as include path
target_include_directories(release PUBLIC src) target_include_directories(release PUBLIC src)
# disable assertions
target_compile_definitions(release PUBLIC NDEBUG="1")
# ------------------------------------------------ # # ------------------------------------------------ #
# Target DEBUG # # Target DEBUG #
# ------------------------------------------------ # # ------------------------------------------------ #

View File

@ -4,41 +4,47 @@
#include <cfg/opt.h> #include <cfg/opt.h>
#include <string.h> #include <string.h>
#include <sys/log.h>
#define MAX_TARGETS_PER_PROJECT 100 TargetConfig* default_target_config() {
DEBUG("generating default target config...");
TargetConfig default_target_config() { TargetConfig* config = malloc(sizeof(TargetConfig));
TargetConfig config;
config.name = "debug"; config->name = NULL;
config.print_ast = false; config->print_ast = false;
config.print_asm = false; config->print_asm = false;
config.print_ir = false; config->print_ir = false;
config.mode = Application; config->mode = Application;
config.archive_directory = "archive"; config->archive_directory = NULL;
config.archive_directory = "bin"; config->archive_directory = NULL;
config.optimization_level = 1; config->optimization_level = 1;
config.root_module = NULL; config->root_module = NULL;
return config; return config;
} }
TargetConfig default_target_config_from_args(int argc, char *argv[]) { TargetConfig* default_target_config_from_args(int argc, char *argv[]) {
TargetConfig config = default_target_config(); DEBUG("generating default target from command line...");
TargetConfig* config = default_target_config();
for (int i = 0; i < argc; i++) { for (int i = 0; i < argc; i++) {
DEBUG("processing argument: %ld %s", i, argv[i]);
char *option = argv[i]; char *option = argv[i];
if (strcmp(option, "--print-ast") == 0) { if (strcmp(option, "--print-ast") == 0) {
config.print_ast = true; config->print_ast = true;
} else if (strcmp(option, "--print-asm") == 0) { } else if (strcmp(option, "--print-asm") == 0) {
config.print_asm = true; config->print_asm = true;
} else if (strcmp(option, "--print-ir") == 0) { } else if (strcmp(option, "--print-ir") == 0) {
config.print_ir = true; config->print_ir = true;
} else if (strcmp(option, "--mode=app") == 0) { } else if (strcmp(option, "--mode=app") == 0) {
config.mode = Application; config->mode = Application;
} else if (strcmp(option, "--mode=lib") == 0) { } else if (strcmp(option, "--mode=lib") == 0) {
config.mode = Library; config->mode = Library;
} else {
config->root_module = option;
} }
} }
@ -46,11 +52,14 @@ TargetConfig default_target_config_from_args(int argc, char *argv[]) {
} }
void print_help(void) { void print_help(void) {
DEBUG("printing help dialog...");
const char *lines[] = { const char *lines[] = {
"Gemstone Compiler (C) GPL-2.0\n", "Gemstone Compiler (C) GPL-2.0",
"Compile file(s): gsc <options> [files]", "Build a project target: gsc build [target]|all",
"Build project (build.toml): gsc [directory] [target]|all", "Compile non-project file: gsc compile <options> [file]",
"Options:", "Options:",
" --version print the version",
" --print-ast print resulting abstract syntax tree to a file", " --print-ast print resulting abstract syntax tree to a file",
" --print-asm print resulting assembly language to a file", " --print-asm print resulting assembly language to a file",
" --print-ir print resulting LLVM-IR to a file", " --print-ir print resulting LLVM-IR to a file",
@ -62,35 +71,42 @@ void print_help(void) {
} }
} }
#define PROJECT_OK 0
#define PROJECT_TOML_ERR 1
#define PROJECT_SEMANTIC_ERR 2
static void get_bool(bool* boolean, toml_table_t *table, const char* name) { static void get_bool(bool* boolean, toml_table_t *table, const char* name) {
DEBUG("retrieving boolean %s", name);
toml_datum_t datum = toml_bool_in(table, name); toml_datum_t datum = toml_bool_in(table, name);
if (datum.ok) { if (datum.ok) {
*boolean = datum.u.b; *boolean = datum.u.b;
DEBUG("boolean has value: %d", datum.u.b);
} }
} }
static void get_str(char** string, toml_table_t *table, const char* name) { static void get_str(char** string, toml_table_t *table, const char* name) {
DEBUG("retrieving string %s", name);
toml_datum_t datum = toml_string_in(table, name); toml_datum_t datum = toml_string_in(table, name);
if (datum.ok) { if (datum.ok) {
*string = datum.u.s; *string = datum.u.s;
DEBUG("string has value: %s", datum.u.s);
} }
} }
static void get_int(int* integer, toml_table_t *table, const char* name) { static void get_int(int* integer, toml_table_t *table, const char* name) {
DEBUG("retrieving integer %s", name);
toml_datum_t datum = toml_int_in(table, name); toml_datum_t datum = toml_int_in(table, name);
if (datum.ok) { if (datum.ok) {
*integer = (int) datum.u.i; *integer = (int) datum.u.i;
DEBUG("integer has value: %ld", datum.u.i);
} }
} }
static int parse_project_table(ProjectConfig *config, toml_table_t *project_table) { static int parse_project_table(ProjectConfig *config, toml_table_t *project_table) {
DEBUG("parsing project table...");
// project name // project name
get_str(&config->name, project_table, "version"); get_str(&config->name, project_table, "version");
if (config->name == NULL) { if (config->name == NULL) {
@ -99,7 +115,7 @@ static int parse_project_table(ProjectConfig *config, toml_table_t *project_tabl
} }
// project version // project version
get_str(&config->name, project_table, "version"); get_str(&config->name, project_table, "name");
// author names // author names
toml_array_t *authors = toml_array_in(project_table, "authors"); toml_array_t *authors = toml_array_in(project_table, "authors");
@ -136,34 +152,44 @@ static int get_mode_from_str(TargetCompilationMode* mode, const char* name) {
} }
static int parse_target(ProjectConfig *config, toml_table_t *target_table, const char* name) { static int parse_target(ProjectConfig *config, toml_table_t *target_table, const char* name) {
TargetConfig target_config = default_target_config(); DEBUG("parsing target table...");
target_config.name = (char*) name; TargetConfig* target_config = default_target_config();
get_bool(&target_config.print_ast, target_table, "print_ast"); target_config->name = (char*) name;
get_bool(&target_config.print_asm, target_table, "print_asm");
get_bool(&target_config.print_ir, target_table, "print_ir");
get_str(&target_config.root_module, target_table, "root"); get_bool(&target_config->print_ast, target_table, "print_ast");
get_str(&target_config.output_directory, target_table, "output"); get_bool(&target_config->print_asm, target_table, "print_asm");
get_str(&target_config.archive_directory, target_table, "archive"); get_bool(&target_config->print_ir, target_table, "print_ir");
get_int(&target_config.optimization_level, target_table, "opt"); get_str(&target_config->root_module, target_table, "root");
get_str(&target_config->output_directory, target_table, "output");
get_str(&target_config->archive_directory, target_table, "archive");
get_int(&target_config->optimization_level, target_table, "opt");
char* mode = NULL; char* mode = NULL;
get_str(&mode, target_table, "mode"); get_str(&mode, target_table, "mode");
int err = get_mode_from_str(&target_config.mode, mode); int err = get_mode_from_str(&target_config->mode, mode);
if (err != PROJECT_OK) { if (err != PROJECT_OK) {
return err; return err;
} }
g_array_append_val(config->targets, target_config); g_hash_table_insert(config->targets, target_config->name, target_config);
return PROJECT_OK; return PROJECT_OK;
} }
static int parse_targets(ProjectConfig *config, toml_table_t *root) { static int parse_targets(ProjectConfig *config, toml_table_t *root) {
DEBUG("parsing targets of project \"%s\"", config->name);
toml_table_t *targets = toml_table_in(root, "target"); toml_table_t *targets = toml_table_in(root, "target");
if (targets == NULL) {
printf("Project has no targets\n");
return PROJECT_SEMANTIC_ERR;
}
config->targets = g_hash_table_new(g_str_hash, g_str_equal);
for (int i = 0; i < MAX_TARGETS_PER_PROJECT; i++) { for (int i = 0; i < MAX_TARGETS_PER_PROJECT; i++) {
const char *key = toml_key_in(targets, i); const char *key = toml_key_in(targets, i);
@ -179,8 +205,12 @@ static int parse_targets(ProjectConfig *config, toml_table_t *root) {
} }
int load_project_config(ProjectConfig *config) { int load_project_config(ProjectConfig *config) {
FILE *config_file = fopen("build.toml", "r"); DEBUG("loading project config...");
FILE *config_file = fopen(PROJECT_CONFIG_FILE, "r");
if (config_file == NULL) { if (config_file == NULL) {
printf("Cannot open file %s: %s\n", PROJECT_CONFIG_FILE, strerror(errno));
ERROR("project file not found");
return PROJECT_TOML_ERR; return PROJECT_TOML_ERR;
} }
@ -197,7 +227,7 @@ int load_project_config(ProjectConfig *config) {
toml_table_t *project = toml_table_in(conf, "project"); toml_table_t *project = toml_table_in(conf, "project");
if (project) { if (project) {
if (parse_project_table(config, project) == PROJECT_OK) { if (parse_project_table(config, project) == PROJECT_OK) {
return parse_targets(config, project); return parse_targets(config, conf);
} }
} else { } else {
printf("Invalid project configuration: missing project table\n\n"); printf("Invalid project configuration: missing project table\n\n");
@ -206,3 +236,62 @@ int load_project_config(ProjectConfig *config) {
toml_free(conf); toml_free(conf);
return PROJECT_SEMANTIC_ERR; return PROJECT_SEMANTIC_ERR;
} }
void delete_target_config(TargetConfig* config) {
if (config->root_module != NULL) {
free(config->root_module);
}
if (config->archive_directory != NULL) {
free(config->archive_directory);
}
if (config->name != NULL) {
free(config->name);
}
if (config->output_directory != NULL) {
free(config->output_directory);
}
free(config);
}
void delete_project_config(ProjectConfig* config) {
if (config->name != NULL) {
free(config->name);
}
if (config->authors != NULL) {
g_array_free(config->authors, TRUE);
}
if (config->desc != NULL) {
free(config->desc);
}
if (config->license != NULL) {
free(config->license);
}
if (config->targets != NULL) {
GHashTableIter iter;
g_hash_table_iter_init(&iter, config->targets);
char* key;
TargetConfig* val;
while (g_hash_table_iter_next(&iter, (gpointer) &key, (gpointer) &val)) {
delete_target_config(val);
}
g_hash_table_destroy(config->targets);
}
free(config);
}
ProjectConfig* default_project_config() {
ProjectConfig* config = malloc(sizeof(ProjectConfig));
config->authors = NULL;
config->name = NULL;
config->targets = NULL;
config->license = NULL;
config->version = NULL;
config->desc = NULL;
return config;
}

View File

@ -8,6 +8,13 @@
#include <toml.h> #include <toml.h>
#include <glib.h> #include <glib.h>
#define MAX_TARGETS_PER_PROJECT 100
#define PROJECT_CONFIG_FILE "build.toml"
#define PROJECT_OK 0
#define PROJECT_TOML_ERR 1
#define PROJECT_SEMANTIC_ERR 2
typedef enum TargetCompilationMode_t { typedef enum TargetCompilationMode_t {
Application, Application,
Library Library
@ -42,13 +49,21 @@ typedef struct ProjectConfig_t {
char* license; char* license;
// list of authors // list of authors
GArray* authors; GArray* authors;
GArray* targets; GHashTable* targets;
} ProjectConfig; } ProjectConfig;
TargetConfig default_target_config(); TargetConfig* default_target_config();
TargetConfig default_target_config_from_args(int argc, char* argv[]); ProjectConfig* default_project_config();
TargetConfig* default_target_config_from_args(int argc, char* argv[]);
int load_project_config(ProjectConfig *config);
void print_help(void); void print_help(void);
void delete_project_config(ProjectConfig* config);
void delete_target_config(TargetConfig*);
#endif //GEMSTONE_OPT_H #endif //GEMSTONE_OPT_H

View File

@ -6,6 +6,7 @@
#include <lex/util.h> #include <lex/util.h>
#include <io/files.h> #include <io/files.h>
#include <assert.h> #include <assert.h>
#include <cfg/opt.h>
extern void yyrestart(FILE *); extern void yyrestart(FILE *);
@ -22,6 +23,7 @@ ModuleFile *current_file;
*/ */
[[nodiscard("AST may be in invalid state")]] [[nodiscard("AST may be in invalid state")]]
[[gnu::nonnull(1), gnu::nonnull(1)]] [[gnu::nonnull(1), gnu::nonnull(1)]]
static size_t compile_file_to_ast(AST_NODE_PTR ast, ModuleFile *file) { static size_t compile_file_to_ast(AST_NODE_PTR ast, ModuleFile *file) {
assert(file->path != NULL); assert(file->path != NULL);
assert(ast != NULL); assert(ast != NULL);
@ -30,6 +32,7 @@ static size_t compile_file_to_ast(AST_NODE_PTR ast, ModuleFile *file) {
if (file->handle == NULL) { if (file->handle == NULL) {
INFO("unable to open file: %s", file->path); INFO("unable to open file: %s", file->path);
printf("Cannot open file %s: %s\n", file->path, strerror(errno));
return 1; return 1;
} }
@ -92,16 +95,8 @@ void setup(void) {
DEBUG("finished starting up gemstone..."); DEBUG("finished starting up gemstone...");
} }
int main(int argc, char *argv[]) { void build_target(ModuleFileStack *unit, TargetConfig *target) {
printf("Compiling file: %s\n\n", target->root_module);
setup();
atexit(close_file);
ModuleFileStack files;
files.files = NULL;
for (int i = 1; i < argc; i++) {
printf("Compiling file: %s\n\n", argv[i]);
TokenLocation location = { TokenLocation location = {
.line_start = 0, .line_start = 0,
@ -110,7 +105,7 @@ int main(int argc, char *argv[]) {
.col_end = 0 .col_end = 0
}; };
AST_NODE_PTR ast = AST_new_node(location, AST_Module, NULL); AST_NODE_PTR ast = AST_new_node(location, AST_Module, NULL);
ModuleFile *file = push_file(&files, argv[i]); ModuleFile *file = push_file(unit, target->root_module);
if (compile_file_to_ast(ast, file) == EXIT_SUCCESS) { if (compile_file_to_ast(ast, file) == EXIT_SUCCESS) {
// TODO: parse AST to semantic values // TODO: parse AST to semantic values
@ -122,13 +117,95 @@ int main(int argc, char *argv[]) {
print_file_statistics(file); print_file_statistics(file);
} }
void compile_file(ModuleFileStack *unit, int argc, char *argv[]) {
INFO("compiling basic files...");
TargetConfig *target = default_target_config_from_args(argc, argv);
if (target->root_module == NULL) {
printf("No input file specified\n");
delete_target_config(target);
return;
}
build_target(unit, target);
delete_target_config(target);
}
void build_project_targets(ModuleFileStack *unit, ProjectConfig *config, const char *filter) {
if (strcmp(filter, "all") == 0) {
GHashTableIter iter;
g_hash_table_iter_init(&iter, config->targets);
char* key;
TargetConfig* val;
while (g_hash_table_iter_next(&iter, (gpointer) &key, (gpointer) &val)) {
build_target(unit, val);
}
} else if (g_hash_table_contains(config->targets, filter)) {
build_target(unit, g_hash_table_lookup(config->targets, filter));
}
}
void build_project(ModuleFileStack *unit, int argc, char *argv[]) {
if (argc >= 1) {
ProjectConfig* config = default_project_config();
int err = load_project_config(config);
if (err == PROJECT_OK) {
if (argc == 1) {
build_project_targets(unit, config, "all");
} else {
build_project_targets(unit, config, argv[0]);
}
}
delete_project_config(config);
} else {
printf("Expected 1 target to run\n");
}
}
void configure_run_mode(int argc, char *argv[]) {
if (argc > 1) {
ModuleFileStack files;
files.files = NULL;
if (strcmp(argv[1], "build") == 0) {
build_project(&files, argc - 2, &argv[2]);
} else if (strcmp(argv[1], "compile") == 0) {
compile_file(&files, argc - 2, &argv[2]);
} else {
printf("invalid mode of operation\n");
}
if (files.files == NULL) { if (files.files == NULL) {
printf("No input files, nothing to do.\n\n"); printf("No input files, nothing to do.\n\n");
exit(1); exit(1);
} }
print_unit_statistics(&files); print_unit_statistics(&files);
delete_files(&files); delete_files(&files);
return;
}
INFO("no arguments provided");
print_help();
}
int main(int argc, char *argv[]) {
setup();
atexit(close_file);
printf("running GSC version %s\n", GSC_VERSION);
configure_run_mode(argc, argv);
return 0; return 0;
} }