From b776b5257060b946f92b660be5220a12369d42d9 Mon Sep 17 00:00:00 2001 From: Brendan Hansen Date: Fri, 21 Apr 2023 10:20:55 -0500 Subject: [PATCH] changed: getting ready for onyx watch --- compiler/include/astnodes.h | 19 ++++++++ compiler/src/builtins.c | 31 +++++++++++++ compiler/src/checker.c | 90 +++++++++++++++++-------------------- compiler/src/onyx.c | 65 +++++++++++++-------------- compiler/src/parser.c | 2 + compiler/src/utils.c | 7 ++- 6 files changed, 125 insertions(+), 89 deletions(-) diff --git a/compiler/include/astnodes.h b/compiler/include/astnodes.h index 7f2c8e10..c3e8c73a 100644 --- a/compiler/include/astnodes.h +++ b/compiler/include/astnodes.h @@ -1667,6 +1667,18 @@ typedef struct OnyxDocInfo { } OnyxDocInfo; +typedef struct CheckerData { + b32 expression_types_must_be_known; + b32 all_checks_are_final; + b32 inside_for_iterator; + bh_arr(AstFor *) for_node_stack; + bh_imap __binop_impossible_cache[Binary_Op_Count]; + AstCall __op_maybe_overloaded; + Entity *current_entity; + bh_arr(Type **) expected_return_type_stack; +} CheckerData; + + typedef struct CompileOptions CompileOptions; struct CompileOptions { bh_allocator allocator; @@ -1728,8 +1740,14 @@ struct Context { struct SymbolInfoTable *symbol_info; struct OnyxDocInfo *doc_info; + CheckerData checker; + u32 next_package_id; + u32 next_scope_id; + u32 cycle_almost_detected : 2; b32 cycle_detected : 1; + + b32 builtins_initialized : 1; }; extern Context context; @@ -1815,6 +1833,7 @@ extern IntrinsicTable intrinsic_table; extern bh_arr(OverloadOption) operator_overloads[Binary_Op_Count]; extern bh_arr(OverloadOption) unary_operator_overloads[Unary_Op_Count]; +void prepare_builtins(); void initialize_builtins(bh_allocator a); void initalize_special_globals(); void introduce_build_options(bh_allocator a); diff --git a/compiler/src/builtins.c b/compiler/src/builtins.c index 6491f385..671f2c16 100644 --- a/compiler/src/builtins.c +++ b/compiler/src/builtins.c @@ -376,6 +376,33 @@ static IntrinsicMap builtin_intrinsics[] = { bh_arr(OverloadOption) operator_overloads[Binary_Op_Count] = { 0 }; bh_arr(OverloadOption) unary_operator_overloads[Unary_Op_Count] = { 0 }; +void prepare_builtins() { + builtin_string_type = NULL; + builtin_cstring_type = NULL; + builtin_range_type = NULL; + builtin_range_type_type = NULL; + builtin_vararg_type = NULL; + builtin_vararg_type_type = NULL; + builtin_context_variable = NULL; + builtin_allocator_type = NULL; + builtin_iterator_type = NULL; + builtin_optional_type = NULL; + builtin_callsite_type = NULL; + builtin_any_type = NULL; + builtin_code_type = NULL; + builtin_link_options_type = NULL; + builtin_package_id_type = NULL; + + type_table_node = NULL; + foreign_blocks_node = NULL; + foreign_block_type = NULL; + tagged_procedures_node = NULL; + builtin_initialize_data_segments = NULL; + builtin_run_init_procedures = NULL; + init_procedures = NULL; + builtin_implicit_bool_cast = NULL; +} + void initialize_builtins(bh_allocator a) { // HACK builtin_package_token.text = bh_strdup(global_heap_allocator, builtin_package_token.text); @@ -491,17 +518,21 @@ void initialize_builtins(bh_allocator a) { return; } + init_procedures = NULL; bh_arr_new(global_heap_allocator, init_procedures, 4); fori (i, 0, Binary_Op_Count) { + operator_overloads[i] = NULL; bh_arr_new(global_heap_allocator, operator_overloads[i], 4); } fori (i, 0, Unary_Op_Count) { + unary_operator_overloads[i] = NULL; bh_arr_new(global_heap_allocator, unary_operator_overloads[i], 4); } IntrinsicMap* intrinsic = &builtin_intrinsics[0]; + intrinsic_table = NULL; while (intrinsic->name != NULL) { shput(intrinsic_table, intrinsic->name, intrinsic->intrinsic); intrinsic++; diff --git a/compiler/src/checker.c b/compiler/src/checker.c index 9d30c077..2515038a 100644 --- a/compiler/src/checker.c +++ b/compiler/src/checker.c @@ -1,3 +1,4 @@ +#define BH_INTERNAL_ALLOCATOR (global_heap_allocator) #define BH_DEBUG #include "parser.h" #include "utils.h" @@ -111,15 +112,6 @@ CheckStatus check_polyquery(AstPolyQuery *query); CheckStatus check_directive_first(AstDirectiveFirst *first); CheckStatus check_directive_export_name(AstDirectiveExportName *ename); -// HACK HACK HACK -b32 expression_types_must_be_known = 0; -b32 all_checks_are_final = 1; -b32 inside_for_iterator = 0; -bh_arr(AstFor *) for_node_stack = NULL; -static bh_imap __binop_impossible_cache[Binary_Op_Count]; -static AstCall __op_maybe_overloaded; -static Entity *current_entity = NULL; - #define STATEMENT_LEVEL 1 #define EXPRESSION_LEVEL 2 @@ -133,17 +125,14 @@ static inline void fill_in_type(AstTyped* node) { } } -// HACK: This should be baked into a structure, not a global variable. -static bh_arr(Type **) expected_return_type_stack = NULL; - CheckStatus check_return(AstReturn* retnode) { Type ** expected_return_type; - if (retnode->count >= (u32) bh_arr_length(expected_return_type_stack)) { + if (retnode->count >= (u32) bh_arr_length(context.checker.expected_return_type_stack)) { ERROR_(retnode->token->pos, "Too many repeated 'return's here. Expected a maximum of %d.", - bh_arr_length(expected_return_type_stack)); + bh_arr_length(context.checker.expected_return_type_stack)); } - expected_return_type = expected_return_type_stack[bh_arr_length(expected_return_type_stack) - retnode->count - 1]; + expected_return_type = context.checker.expected_return_type_stack[bh_arr_length(context.checker.expected_return_type_stack) - retnode->count - 1]; if (retnode->expr) { CHECK(expression, &retnode->expr); @@ -353,22 +342,22 @@ CheckStatus check_for(AstFor* fornode) { fornode_expr_checked: - bh_arr_push(for_node_stack, fornode); + bh_arr_push(context.checker.for_node_stack, fornode); - old_inside_for_iterator = inside_for_iterator; - inside_for_iterator = 0; + old_inside_for_iterator = context.checker.inside_for_iterator; + context.checker.inside_for_iterator = 0; iter_type = fornode->iter->type; if (type_struct_constructed_from_poly_struct(iter_type, builtin_iterator_type)) { - inside_for_iterator = 1; + context.checker.inside_for_iterator = 1; } do { CheckStatus cs = check_block(fornode->stmt); - inside_for_iterator = old_inside_for_iterator; + context.checker.inside_for_iterator = old_inside_for_iterator; if (cs > Check_Errors_Start) return cs; } while(0); - bh_arr_pop(for_node_stack); + bh_arr_pop(context.checker.for_node_stack); return Check_Success; } @@ -817,7 +806,7 @@ static void report_bad_binaryop(AstBinaryOp* binop) { } static AstCall* binaryop_try_operator_overload(AstBinaryOp* binop, AstTyped* third_argument) { - if (bh_arr_length(operator_overloads[binop->operation]) == 0) return &__op_maybe_overloaded; + if (bh_arr_length(operator_overloads[binop->operation]) == 0) return &context.checker.__op_maybe_overloaded; if (binop->overload_args == NULL || binop->overload_args->values[1] == NULL) { if (binop->overload_args == NULL) { @@ -829,12 +818,12 @@ static AstCall* binaryop_try_operator_overload(AstBinaryOp* binop, AstTyped* thi if (binop_is_assignment(binop->operation)) { binop->overload_args->values[0] = (AstTyped *) make_address_of(context.ast_alloc, binop->left); - u32 current_all_checks_are_final = all_checks_are_final; - all_checks_are_final = 0; + u32 current_all_checks_are_final = context.checker.all_checks_are_final; + context.checker.all_checks_are_final = 0; u32 current_checking_level_store = current_checking_level; CheckStatus cs = check_address_of((AstAddressOf **) &binop->overload_args->values[0]); current_checking_level = current_checking_level_store; - all_checks_are_final = current_all_checks_are_final; + context.checker.all_checks_are_final = current_all_checks_are_final; if (cs == Check_Yield_Macro) return (AstCall *) &node_that_signals_a_yield; if (cs == Check_Error) return NULL; @@ -862,7 +851,7 @@ static AstCall* binaryop_try_operator_overload(AstBinaryOp* binop, AstTyped* thi } static AstCall* unaryop_try_operator_overload(AstUnaryOp* unop) { - if (bh_arr_length(unary_operator_overloads[unop->operation]) == 0) return &__op_maybe_overloaded; + if (bh_arr_length(unary_operator_overloads[unop->operation]) == 0) return &context.checker.__op_maybe_overloaded; if (unop->overload_args == NULL || unop->overload_args->values[0] == NULL) { if (unop->overload_args == NULL) { @@ -1231,7 +1220,7 @@ CheckStatus check_binaryop(AstBinaryOp** pbinop) { binop->flags |= Ast_Flag_Comptime; } - if (expression_types_must_be_known) { + if (context.checker.expression_types_must_be_known) { if (binop->left->type == NULL || binop->right->type == NULL) { ERROR(binop->token->pos, "Internal compiler error: one of the operands types is unknown here."); } @@ -1242,13 +1231,13 @@ CheckStatus check_binaryop(AstBinaryOp** pbinop) { u64 cache_key = 0; if (binop->left->type && binop->right->type) { - if (!__binop_impossible_cache[binop->operation].hashes) { - bh_imap_init(&__binop_impossible_cache[binop->operation], global_heap_allocator, 256); + if (!context.checker.__binop_impossible_cache[binop->operation].hashes) { + bh_imap_init(&context.checker.__binop_impossible_cache[binop->operation], global_heap_allocator, 256); } cache_key = ((u64) (binop->left->type->id) << 32ll) | (u64) binop->right->type->id; - if (bh_imap_has(&__binop_impossible_cache[binop->operation], cache_key)) { + if (bh_imap_has(&context.checker.__binop_impossible_cache[binop->operation], cache_key)) { goto definitely_not_op_overload; } } @@ -1258,7 +1247,7 @@ CheckStatus check_binaryop(AstBinaryOp** pbinop) { if (implicit_call == (AstCall *) &node_that_signals_a_yield) YIELD(binop->token->pos, "Trying to resolve operator overload."); - if (implicit_call != NULL && implicit_call != &__op_maybe_overloaded) { + if (implicit_call != NULL && implicit_call != &context.checker.__op_maybe_overloaded) { // NOTE: Not a binary op implicit_call->next = binop->next; *pbinop = (AstBinaryOp *) implicit_call; @@ -1267,8 +1256,8 @@ CheckStatus check_binaryop(AstBinaryOp** pbinop) { return Check_Success; } - if (cache_key && implicit_call != &__op_maybe_overloaded) { - bh_imap_put(&__binop_impossible_cache[binop->operation], cache_key, 1); + if (cache_key && implicit_call != &context.checker.__op_maybe_overloaded) { + bh_imap_put(&context.checker.__binop_impossible_cache[binop->operation], cache_key, 1); } } @@ -1340,7 +1329,7 @@ CheckStatus check_binaryop(AstBinaryOp** pbinop) { binop->type = &basic_types[Basic_Kind_Bool]; } - if (all_checks_are_final) { + if (context.checker.all_checks_are_final) { binop->flags |= Ast_Flag_Has_Been_Checked; if (binop->flags & Ast_Flag_Comptime) { @@ -1403,7 +1392,7 @@ CheckStatus check_unaryop(AstUnaryOp** punop) { if (unaryop->operation == Unary_Op_Try) { AstCall* call = unaryop_try_operator_overload(unaryop); if (call == (AstCall *) &node_that_signals_a_yield) YIELD(unaryop->token->pos, "Waiting on potential operator overload."); - if (call != NULL && call != &__op_maybe_overloaded) { + if (call != NULL && call != &context.checker.__op_maybe_overloaded) { call->next = unaryop->next; *(AstCall **) punop = call; @@ -1689,14 +1678,14 @@ CheckStatus check_do_block(AstDoBlock** pdoblock) { fill_in_type((AstTyped *) doblock); - bh_arr_push(expected_return_type_stack, &doblock->type); + bh_arr_push(context.checker.expected_return_type_stack, &doblock->type); doblock->block->rules = Block_Rule_Do_Block; CHECK(block, doblock->block); if (doblock->type == &type_auto_return) doblock->type = &basic_types[Basic_Kind_Void]; - bh_arr_pop(expected_return_type_stack); + bh_arr_pop(context.checker.expected_return_type_stack); doblock->flags |= Ast_Flag_Has_Been_Checked; return Check_Success; @@ -2336,7 +2325,7 @@ CheckStatus check_directive_solidify(AstDirectiveSolidify** psolid) { } CheckStatus check_remove_directive(AstDirectiveRemove *remove) { - if (!inside_for_iterator) { + if (!context.checker.inside_for_iterator) { ERROR(remove->token->pos, "#remove is only allowed in the body of a for-loop over an iterator."); } @@ -2344,11 +2333,11 @@ CheckStatus check_remove_directive(AstDirectiveRemove *remove) { } CheckStatus check_directive_first(AstDirectiveFirst *first) { - if (bh_arr_length(for_node_stack) == 0) { + if (bh_arr_length(context.checker.for_node_stack) == 0) { ERROR(first->token->pos, "#first is only allowed in the body of a for-loop."); } - first->for_node = bh_arr_last(for_node_stack); + first->for_node = bh_arr_last(context.checker.for_node_stack); assert(first->for_node); first->for_node->has_first = 1; @@ -2542,11 +2531,11 @@ CheckStatus check_function(AstFunction* func) { } } - bh_arr_clear(expected_return_type_stack); - bh_arr_push(expected_return_type_stack, &func->type->Function.return_type); + bh_arr_clear(context.checker.expected_return_type_stack); + bh_arr_push(context.checker.expected_return_type_stack, &func->type->Function.return_type); - inside_for_iterator = 0; - if (for_node_stack) bh_arr_clear(for_node_stack); + context.checker.inside_for_iterator = 0; + if (context.checker.for_node_stack) bh_arr_clear(context.checker.for_node_stack); if (func->body) { CheckStatus status = check_block(func->body); @@ -2558,8 +2547,8 @@ CheckStatus check_function(AstFunction* func) { } } - if (*bh_arr_last(expected_return_type_stack) == &type_auto_return) { - *bh_arr_last(expected_return_type_stack) = &basic_types[Basic_Kind_Void]; + if (*bh_arr_last(context.checker.expected_return_type_stack) == &type_auto_return) { + *bh_arr_last(context.checker.expected_return_type_stack) = &basic_types[Basic_Kind_Void]; } func->flags |= Ast_Flag_Has_Been_Checked; @@ -3083,9 +3072,9 @@ CheckStatus check_type(AstType** ptype) { } CheckStatus check_static_if(AstIf* static_if) { - expression_types_must_be_known = 1; + context.checker.expression_types_must_be_known = 1; CheckStatus result = check_expression(&static_if->cond); - expression_types_must_be_known = 0; + context.checker.expression_types_must_be_known = 0; if (result == Check_Yield_Macro) return Check_Yield_Macro; if (result > Check_Errors_Start || !(static_if->cond->flags & Ast_Flag_Comptime)) { @@ -3215,7 +3204,7 @@ CheckStatus check_process_directive(AstNode* directive) { if (inject->dest->kind == Ast_Kind_Package) { pac = ((AstPackage *) inject->dest)->package; } else { - pac = current_entity->package; + pac = context.checker.current_entity->package; } add_entities_for_node(NULL, (AstNode *) binding, scope, pac); @@ -3541,7 +3530,8 @@ CheckStatus check_arbitrary_job(EntityJobData *job) { void check_entity(Entity* ent) { CheckStatus cs = Check_Success; - current_entity = ent; + context.checker.current_entity = ent; + context.checker.all_checks_are_final = 1; switch (ent->type) { case Entity_Type_Foreign_Function_Header: diff --git a/compiler/src/onyx.c b/compiler/src/onyx.c index 6996d6a0..5501b5ac 100644 --- a/compiler/src/onyx.c +++ b/compiler/src/onyx.c @@ -122,7 +122,7 @@ static CompileOptions compile_opts_parse(bh_allocator alloc, int argc, char *arg core_installation = CORE_INSTALLATION; #endif #ifdef _BH_WINDOWS - core_installation = bh_alloc_array(global_heap_allocator, u8, 512); + core_installation = bh_alloc_array(alloc, u8, 512); GetEnvironmentVariableA("ONYX_PATH", core_installation, 512); #endif @@ -151,7 +151,7 @@ static CompileOptions compile_opts_parse(bh_allocator alloc, int argc, char *arg options.passthrough_argument_data = &argv[2]; arg_parse_start = argc; - bh_arr_push(options.files, bh_aprintf(global_heap_allocator, "%s/tools/onyx-pkg.onyx", core_installation)); + bh_arr_push(options.files, bh_aprintf(alloc, "%s/tools/onyx-pkg.onyx", core_installation)); } #ifdef ENABLE_RUN_WITH_WASMER else if (!strcmp(argv[1], "run")) { @@ -322,6 +322,9 @@ static Entity *runtime_info_proc_tags_entity; static void context_init(CompileOptions* opts) { types_init(); + prepare_builtins(); + + memset(&context, 0, sizeof context); context.options = opts; context.cycle_detected = 0; @@ -428,8 +431,6 @@ static void context_init(CompileOptions* opts) { static void context_free() { bh_arena_free(&context.ast_arena); bh_arr_free(context.loaded_files); - - compile_opts_free(context.options); } static void parse_source_file(bh_file_contents* file_contents) { @@ -558,10 +559,6 @@ static b32 process_entity(Entity* ent) { (u32) ent->micro_attempts); } - // CLEANUP: There should be a nicer way to track if the builtins have - // already been initialized. - static b32 builtins_initialized = 0; - EntityState before_state = ent->state; switch (before_state) { case Entity_State_Error: @@ -584,8 +581,8 @@ static b32 process_entity(Entity* ent) { break; case Entity_State_Parse: - if (!builtins_initialized) { - builtins_initialized = 1; + if (!context.builtins_initialized) { + context.builtins_initialized = 1; initialize_builtins(context.ast_alloc); introduce_build_options(context.ast_alloc); } @@ -906,23 +903,29 @@ static b32 onyx_run() { } #endif -bh_managed_heap mh; - -int main(int argc, char *argv[]) { +static bh_managed_heap mh; +CompilerProgress do_compilation(CompileOptions *compile_opts) { bh_scratch_init(&global_scratch, bh_heap_allocator(), 256 * 1024); // NOTE: 256 KiB global_scratch_allocator = bh_scratch_allocator(&global_scratch); - // SPEED: This used to be a managed heap allocator where all allocations - // were tracked and would be automatically freed at the end of execution. - // I don't know why I ever did that because that is the job of the operating - // system when a process exits. - // global_heap_allocator = bh_heap_allocator(); - bh_managed_heap_init(&mh); - global_heap_allocator = bh_managed_heap_allocator(&mh); + // bh_managed_heap_init(&mh); + // global_heap_allocator = bh_managed_heap_allocator(&mh); + global_heap_allocator = bh_heap_allocator(); + context_init(compile_opts); + + return onyx_compile(); +} + +void cleanup_compilation() { + context_free(); + + bh_scratch_free(&global_scratch); + // bh_managed_heap_free(&mh); +} - CompileOptions compile_opts = compile_opts_parse(global_heap_allocator, argc, argv); - context_init(&compile_opts); +int main(int argc, char *argv[]) { + CompileOptions compile_opts = compile_opts_parse(bh_heap_allocator(), argc, argv); CompilerProgress compiler_progress = ONYX_COMPILER_PROGRESS_ERROR; switch (compile_opts.action) { @@ -936,11 +939,11 @@ int main(int argc, char *argv[]) { } case ONYX_COMPILE_ACTION_CHECK: - compiler_progress = onyx_compile(); + compiler_progress = do_compilation(&compile_opts); break; case ONYX_COMPILE_ACTION_COMPILE: - compiler_progress = onyx_compile(); + compiler_progress = do_compilation(&compile_opts); if (compiler_progress == ONYX_COMPILER_PROGRESS_SUCCESS) { onyx_flush_module(); } @@ -948,7 +951,7 @@ int main(int argc, char *argv[]) { #ifdef ENABLE_RUN_WITH_WASMER case ONYX_COMPILE_ACTION_RUN: - compiler_progress = onyx_compile(); + compiler_progress = do_compilation(&compile_opts); if (compiler_progress == ONYX_COMPILER_PROGRESS_SUCCESS) { if (!onyx_run()) { compiler_progress = ONYX_COMPILER_PROGRESS_ERROR; @@ -969,21 +972,13 @@ int main(int argc, char *argv[]) { } switch (compiler_progress) { - case ONYX_COMPILER_PROGRESS_ERROR: - break; - case ONYX_COMPILER_PROGRESS_FAILED_OUTPUT: bh_printf_err("Failed to open file for writing: '%s'\n", compile_opts.target_file); break; - - case ONYX_COMPILER_PROGRESS_SUCCESS: - break; } - context_free(); - - bh_scratch_free(&global_scratch); - bh_managed_heap_free(&mh); + cleanup_compilation(); + compile_opts_free(&compile_opts); return compiler_progress != ONYX_COMPILER_PROGRESS_SUCCESS; } diff --git a/compiler/src/parser.c b/compiler/src/parser.c index 62559ee0..b0314f63 100644 --- a/compiler/src/parser.c +++ b/compiler/src/parser.c @@ -3,6 +3,8 @@ // such as procedure definitions, string literals, struct definitions // and declarations to be introduced into scopes. +#define BH_INTERNAL_ALLOCATOR (global_heap_allocator) + #include "parser.h" #include "lex.h" #include "errors.h" diff --git a/compiler/src/utils.c b/compiler/src/utils.c index cbc8fff4..0183be6a 100644 --- a/compiler/src/utils.c +++ b/compiler/src/utils.c @@ -1,3 +1,4 @@ +#define BH_INTERNAL_ALLOCATOR (global_heap_allocator) #define BH_DEBUG #include "utils.h" @@ -18,7 +19,6 @@ bh_allocator global_heap_allocator; // // Program info and packages // -static u64 next_package_id = 1; Package* package_lookup(char* package_name) { i32 index = shgeti(context.packages, package_name); @@ -44,7 +44,7 @@ Package* package_lookup_or_create(char* package_name, Scope* parent_scope, bh_al package->name = pac_name; package->unqualified_name = pac_name + bh_str_last_index_of(pac_name, '.'); package->use_package_entities = NULL; - package->id = next_package_id++; + package->id = ++context.next_package_id; package->parent_id = -1; bh_arr_new(global_heap_allocator, package->sub_packages, 4); @@ -114,11 +114,10 @@ void package_mark_as_used(Package* package) { // // Scoping // -static u64 next_scope_id = 1; Scope* scope_create(bh_allocator a, Scope* parent, OnyxFilePos created_at) { Scope* scope = bh_alloc_item(a, Scope); - scope->id = next_scope_id++; + scope->id = ++context.next_scope_id; scope->parent = parent; scope->created_at = created_at; scope->name = NULL; -- 2.25.1