aboutsummaryrefslogtreecommitdiff
path: root/src/compiler.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/compiler.c')
-rw-r--r--src/compiler.c138
1 files changed, 115 insertions, 23 deletions
diff --git a/src/compiler.c b/src/compiler.c
index c56221b..f0e5928 100644
--- a/src/compiler.c
+++ b/src/compiler.c
@@ -3,13 +3,21 @@
#include "../include/ssa/ssa.h"
#include "../include/std/log.h"
#include "../include/std/mem.h"
+#include "../include/std/hash.h"
+#include "../include/std/file.h"
#include "../include/std/alloc.h"
#include <stdlib.h>
#include <stdio.h>
+#include <limits.h>
#include <assert.h>
#define MIN(a, b) ((a) < (b) ? (a) : (b))
+typedef struct {
+ BufferView path;
+ Scope *file_scope;
+} FileQueueItem;
+
static CHECK_RESULT int get_thread_count_env_var(int *thread_count) {
char *threads;
threads = getenv("THREADS");
@@ -19,6 +27,49 @@ static CHECK_RESULT int get_thread_count_env_var(int *thread_count) {
return 0;
}
+static usize strnlen(const char *str, usize max_length) {
+ usize len;
+ len = 0;
+ while(len < max_length && *str != '\0') {
+ ++len;
+ ++str;
+ }
+ return len;
+}
+
+/* TODO: Allow to specify size and members? */
+static CHECK_RESULT int create_default_type(amal_compiler *compiler, const char *name) {
+ StructDecl *struct_decl;
+ LhsExpr *lhs_expr;
+ Ast expr;
+
+ return_if_error(scoped_allocator_alloc(&compiler->allocator, sizeof(StructDecl), (void**)&struct_decl));
+ return_if_error(structdecl_init(struct_decl, &compiler->root_scope, &compiler->allocator));
+
+ return_if_error(scoped_allocator_alloc(&compiler->allocator, sizeof(LhsExpr), (void**)&lhs_expr));
+ lhsexpr_init(lhs_expr, bool_true, create_buffer_view(name, strnlen(name, PATH_MAX)));
+ ast_init(&lhs_expr->rhs_expr, struct_decl, AST_STRUCT_DECL);
+ ast_init(&expr, lhs_expr, AST_LHS);
+ return scope_add_child(&compiler->root_scope, &expr);
+}
+
+static CHECK_RESULT int init_default_types(amal_compiler *compiler) {
+ return_if_error(create_default_type(compiler, "i8"));
+ return_if_error(create_default_type(compiler, "i16"));
+ return_if_error(create_default_type(compiler, "i32"));
+ return_if_error(create_default_type(compiler, "i64"));
+ return_if_error(create_default_type(compiler, "u8"));
+ return_if_error(create_default_type(compiler, "u16"));
+ return_if_error(create_default_type(compiler, "u32"));
+ return_if_error(create_default_type(compiler, "u64"));
+ return_if_error(create_default_type(compiler, "isize"));
+ return_if_error(create_default_type(compiler, "usize"));
+ return_if_error(create_default_type(compiler, "f32"));
+ return_if_error(create_default_type(compiler, "f64"));
+ return_if_error(create_default_type(compiler, "str"));
+ return 0;
+}
+
int amal_compiler_init(amal_compiler *self) {
int i;
int result;
@@ -37,20 +88,22 @@ int amal_compiler_init(amal_compiler *self) {
}
am_memset(&self->allocator, 0, sizeof(self->allocator));
- am_memset(&self->main_thread_allocator, 0, sizeof(self->main_thread_allocator));
+ am_memset(&self->root_scope, 0, sizeof(self->root_scope));
self->started = bool_false;
self->generic_work_object_index = 0;
amal_mutex_init(&self->mutex);
return_if_error(scoped_allocator_init(&self->allocator));
- cleanup_if_error(scoped_allocator_init(&self->main_thread_allocator));
+ cleanup_if_error(scope_init(&self->root_scope, NULL, &self->allocator));
cleanup_if_error(buffer_init(&self->parsers, &self->allocator));
cleanup_if_error(buffer_init(&self->queued_files, &self->allocator));
+ cleanup_if_error(hash_map_init(&self->file_scopes, &self->allocator, sizeof(FileScopeReference*), hash_compare_string, amal_hash_string));
cleanup_if_error(scoped_allocator_alloc(&self->allocator,
self->usable_thread_count * sizeof(ParserThreadData),
(void**)&self->threads));
for(i = 0; i < self->usable_thread_count; ++i)
cleanup_if_error(parser_thread_data_init(&self->threads[i]));
+ cleanup_if_error(init_default_types(self));
return AMAL_COMPILER_OK;
cleanup:
@@ -72,7 +125,6 @@ int amal_compiler_deinit(amal_compiler *self) {
amal_mutex_deinit(&self->mutex);
scoped_allocator_deinit(&self->allocator);
- scoped_allocator_deinit(&self->main_thread_allocator);
return result;
}
@@ -108,11 +160,13 @@ static CHECK_RESULT int amal_compiler_load_in_this_thread(amal_compiler *self, B
int result;
result = AMAL_COMPILER_ERR;
- return_if_error(scoped_allocator_alloc(&self->allocator, sizeof(Parser), (void**)&parser));
+ amal_log_info("Started parsing %.*s", (int)filepath.size, filepath.data);
+ return_if_error(scoped_allocator_alloc(allocator, sizeof(Parser), (void**)&parser));
return_if_error(parser_init(parser, self, allocator));
return_if_error(parser_parse_file(parser, filepath));
cleanup_if_error(amal_mutex_lock(&self->mutex, "amal_compiler_load_in_this_thread"));
cleanup_if_error(buffer_append(&self->parsers, &parser, sizeof(parser)));
+ amal_log_info("Finished parsing %.*s", (int)filepath.size, filepath.data);
result = AMAL_COMPILER_OK;
cleanup:
@@ -156,13 +210,10 @@ static CHECK_RESULT int thread_resolve_ast(Parser *parser) {
compiler_context.parser = parser;
compiler_context.scope = NULL;
result = setjmp(compiler_context.env);
- assert(!parser->scope.parent);
if(result == 0) {
amal_log_debug("Resolving AST for file: %.*s", parser->tokenizer.code_name.size, parser->tokenizer.code_name.data);
scope_resolve(&parser->scope, &compiler_context);
}
- if(result == 0)
- assert(!compiler_context.scope);
return result;
}
@@ -226,7 +277,7 @@ static CHECK_RESULT int amal_compiler_select_thread_for_work(amal_compiler *self
void *thread_user_data;
thread_user_data = NULL;
*thread_selected = NULL;
- result = AMAL_COMPILER_ERR;
+ result = AMAL_COMPILER_OK;
cleanup_if_error(amal_mutex_lock(&self->mutex, "amal_compiler_select_thread_for_work"));
for(i = 0; i < self->usable_thread_count; ++i) {
@@ -270,23 +321,21 @@ static CHECK_RESULT int amal_compiler_select_thread_for_work(amal_compiler *self
return result;
}
-static CHECK_RESULT int amal_compiler_check_all_threads_done(amal_compiler *self, bool *done) {
+static CHECK_RESULT bool amal_compiler_check_all_threads_done(amal_compiler *self) {
int i;
- int result;
- result = AMAL_COMPILER_OK;
- *done = bool_false;
+ bool result;
+ result = bool_false;
cleanup_if_error(amal_mutex_lock(&self->mutex, "amal_compiler_check_all_threads_done"));
for(i = 0; i < self->usable_thread_count; ++i) {
ParserThreadData *parser_thread_data;
parser_thread_data = &self->threads[i];
if(parser_thread_data->status == PARSER_THREAD_STATUS_RUNNING) {
- result = AMAL_COMPILER_ERR;
goto cleanup;
}
}
- *done = bool_true;
+ result = bool_true;
cleanup:
amal_mutex_tryunlock(&self->mutex);
return result;
@@ -316,7 +365,8 @@ static CHECK_RESULT int amal_compiler_load_file_join_threads(amal_compiler *self
amal_mutex_tryunlock(&self->mutex);
if(result != 0)
goto cleanup;
- ignore_result_int(parser_thread_data_join(parser_thread_data, &thread_return_data));
+ /* TODO: Cleanup remaining threads if join fails */
+ cleanup_if_error(parser_thread_data_join(parser_thread_data, &thread_return_data));
if(thread_return_data != NULL) {
/* TODO: Somehow exit running jobs */
amal_log_error("Failed, waiting for jobs to finish");
@@ -324,7 +374,7 @@ static CHECK_RESULT int amal_compiler_load_file_join_threads(amal_compiler *self
}
}
- cleanup_if_error(amal_compiler_check_all_threads_done(self, &done));
+ done = amal_compiler_check_all_threads_done(self);
if(done)
break;
}
@@ -355,19 +405,56 @@ static CHECK_RESULT int amal_compiler_dispatch_generic(amal_compiler *self, Thre
return amal_compiler_load_file_join_threads(self);
}
+static CHECK_RESULT int try_create_file_scope(amal_compiler *compiler, const char *filepath, FileScopeReference **file_scope, bool *new_entry) {
+ int ret;
+ char *result_path;
+ usize result_path_size;
+ BufferView path_view;
+
+ ret = -1;
+ result_path = NULL;
+ *new_entry = bool_false;
+
+ return_if_error(file_get_canonical_path(filepath, &result_path, &result_path_size));
+ path_view = create_buffer_view(result_path, result_path_size);
+ cleanup_if_error(amal_mutex_lock(&compiler->mutex, "try_create_file_scope"));
+ if(!hash_map_get(&compiler->file_scopes, path_view, file_scope)) {
+ cleanup_if_error(scoped_allocator_alloc(&compiler->allocator, sizeof(FileScopeReference), (void**)file_scope));
+ /* @(*file_scope)->canonical_path won't change after this, so it's fine if allocator belongs to non-thread safe compiler instance */
+ cleanup_if_error(file_scope_reference_init(*file_scope, path_view, &compiler->allocator));
+ cleanup_if_error(hash_map_insert(&compiler->file_scopes, path_view, file_scope));
+ *new_entry = bool_true;
+ }
+
+ ret = 0;
+ cleanup:
+ amal_mutex_tryunlock(&compiler->mutex);
+ am_free(result_path);
+ return ret;
+}
+
/*
amal_compiler_load_file is called by the user for the first file to compile
but also called by the parser when it sees @import
*/
-int amal_compiler_load_file(amal_compiler *self, BufferView filepath) {
+int amal_compiler_load_file(amal_compiler *self, const char *filepath, FileScopeReference **file_scope) {
int result;
+ BufferView filepath_view;
ParserThreadData *parser_thread_data;
ThreadWorkData thread_work_data;
bool main_job;
+ bool new_entry;
+
+ return_if_error(try_create_file_scope(self, filepath, file_scope, &new_entry));
+ filepath_view = create_buffer_view((*file_scope)->canonical_path.data, (*file_scope)->canonical_path.size);
+ if(!new_entry) {
+ amal_log_info("amal_compiler_load_file: file already parsed: %.*s", filepath_view.size, filepath_view.data);
+ return 0;
+ }
result = AMAL_COMPILER_ERR;
thread_work_data.type = THREAD_WORK_PARSE;
- thread_work_data.value.filepath = filepath;
+ thread_work_data.value.filepath = filepath_view;
main_job = bool_false;
/* The first time we get here, this will run single-threaded so this part doesn't need mutex */
@@ -379,13 +466,18 @@ int amal_compiler_load_file(amal_compiler *self, BufferView filepath) {
return_if_error(amal_compiler_select_thread_for_work(self, thread_work_data, &parser_thread_data));
if(main_job) {
- /*amal_log_info("Parsing %.*s using %d thread(s)", (int)filepath.size, filepath.data, self->usable_thread_count);*/
- /*return_if_error(amal_compiler_load_first_this_thread(self, filepath, &self->main_thread_allocator));*/
return_if_error(amal_compiler_load_file_join_threads(self));
- amal_log_debug("Finished parsing all files, resolving AST");
+ assert(amal_compiler_check_all_threads_done(self));
+ amal_log_info("Finished parsing all files, resolving AST");
+
return_if_error(amal_compiler_dispatch_generic(self, THREAD_WORK_RESOLVE_AST));
- amal_log_debug("Finished resolving AST, generating SSA");
+ assert(amal_compiler_check_all_threads_done(self));
+ amal_log_info("Finished resolving AST, generating SSA");
+
return_if_error(amal_compiler_dispatch_generic(self, THREAD_WORK_GENERATE_SSA));
+ assert(amal_compiler_check_all_threads_done(self));
+ amal_log_info("Finished generating SSA");
+
return AMAL_COMPILER_OK;
}
@@ -393,7 +485,7 @@ int amal_compiler_load_file(amal_compiler *self, BufferView filepath) {
return AMAL_COMPILER_OK;
cleanup_if_error(amal_mutex_lock(&self->mutex, "amal_compiler_load_file"));
- cleanup_if_error(buffer_append(&self->queued_files, &filepath, sizeof(filepath)));
+ cleanup_if_error(buffer_append(&self->queued_files, &filepath_view, sizeof(filepath_view)));
result = AMAL_COMPILER_OK;
cleanup: