From: Brendan Hansen Date: Wed, 24 Jun 2020 22:33:39 +0000 (-0500) Subject: Better compiler frontend; compile many files at once X-Git-Url: https://git.brendanfh.com/?a=commitdiff_plain;h=781b87e9574acc6049b9bd1405cfdb0c57c38c82;p=onyx.git Better compiler frontend; compile many files at once --- diff --git a/.vimspector.json b/.vimspector.json index 6444b264..e309f7f9 100644 --- a/.vimspector.json +++ b/.vimspector.json @@ -6,7 +6,7 @@ "type": "cppdbg", "request": "launch", "program": "${workspaceFolder}/onyx", - "args": ["progs/new_minimal.onyx"], + "args": ["progs/test.onyx"], "stopAtEntry": true, "cwd": "${workspaceFolder}", "environment": [], diff --git a/docs/plan b/docs/plan index ac906133..649fc86b 100644 --- a/docs/plan +++ b/docs/plan @@ -78,6 +78,12 @@ HOW: [X] Consequence of the above, recursion works + [X] Better compiler interface + - Proper command line options + - Compiling multiple files at once + - Changing output location + - Viewing help screen + [ ] Devise and implement a simple set of implicit type casting rules. - Numeric literals always type cast to whatever type is needed (very flexible). diff --git a/include/bh.h b/include/bh.h index 063989c8..20a9e9f0 100644 --- a/include/bh.h +++ b/include/bh.h @@ -1653,6 +1653,8 @@ b32 bh__arr_shrink(void** arr, i32 elemsize, i32 cap) { } b32 bh__arr_free(void **arr) { + if (*arr == NULL) return 0; + bh__arr* arrptr = bh__arrhead(*arr); bh_free(arrptr->allocator, arrptr); *arr = NULL; @@ -1739,6 +1741,8 @@ b32 bh__table_init(bh_allocator allocator, bh__table **table, i32 table_size) { } b32 bh__table_free(bh__table **table) { + if (*table == NULL) return 0; + for (i32 i = 0; i < (*table)->table_size; i++) { if ((*table)->arrs[i] != NULL) { bh_arr_free((*table)->arrs[i]); diff --git a/include/onyxparser.h b/include/onyxparser.h index c9d77e6b..27b903a3 100644 --- a/include/onyxparser.h +++ b/include/onyxparser.h @@ -16,6 +16,7 @@ typedef struct OnyxAstNodeParam OnyxAstNodeParam; typedef struct OnyxAstNodeFuncDef OnyxAstNodeFuncDef; typedef struct OnyxAstNodeForeign OnyxAstNodeForeign; typedef struct OnyxAstNodeCall OnyxAstNodeCall; +typedef struct OnyxAstNodeFile OnyxAstNodeFile; typedef struct OnyxParser { OnyxTokenizer *tokenizer; // NOTE: not used since all tokens are lexed before parsing starts @@ -198,6 +199,15 @@ struct OnyxAstNodeCall { // unless this becomes used by something else }; +struct OnyxAstNodeFile { + OnyxAstNodeKind kind; + u32 flags; + OnyxToken *token; // NOTE: unused + OnyxTypeInfo *type; // NOTE: unused + OnyxAstNodeFile *next; // NOTE: next file + OnyxAstNode *contents; // NOTE: the first top-level element +}; + union OnyxAstNode { // Generic node structure for capturing all binary ops and statements @@ -220,12 +230,13 @@ union OnyxAstNode { OnyxAstNodeNumLit as_numlit; OnyxAstNodeForeign as_foreign; OnyxAstNodeIf as_if; + OnyxAstNodeFile as_file; }; const char* onyx_ast_node_kind_string(OnyxAstNodeKind kind); OnyxAstNode* onyx_ast_node_new(bh_allocator alloc, OnyxAstNodeKind kind); OnyxParser onyx_parser_create(bh_allocator alloc, OnyxTokenizer *tokenizer, OnyxMessages* msgs); void onyx_parser_free(OnyxParser* parser); -OnyxAstNode* onyx_parse(OnyxParser *parser); +OnyxAstNodeFile* onyx_parse(OnyxParser *parser); #endif // #ifndef ONYXPARSER_H diff --git a/include/onyxsempass.h b/include/onyxsempass.h index 238e1035..12d87920 100644 --- a/include/onyxsempass.h +++ b/include/onyxsempass.h @@ -28,13 +28,13 @@ typedef struct OnyxSemPassState { } OnyxSemPassState; // NOTE: Resolving all symbols in the tree -void onyx_resolve_symbols(OnyxSemPassState* state, OnyxAstNode* root_node); +void onyx_resolve_symbols(OnyxSemPassState* state, OnyxAstNodeFile* root_node); // NOTE: Inferring and checking types in the tree -void onyx_type_check(OnyxSemPassState* state, OnyxAstNode* root_node); +void onyx_type_check(OnyxSemPassState* state, OnyxAstNodeFile* root_node); // NOTE: Full semantic pass OnyxSemPassState onyx_sempass_create(bh_allocator alloc, bh_allocator node_alloc, OnyxMessages* msgs); -void onyx_sempass(OnyxSemPassState* state, OnyxAstNode* root_node); +void onyx_sempass(OnyxSemPassState* state, OnyxAstNodeFile* root_node); #endif diff --git a/include/onyxwasm.h b/include/onyxwasm.h index 1fcd8d36..adebd8bc 100644 --- a/include/onyxwasm.h +++ b/include/onyxwasm.h @@ -293,7 +293,7 @@ typedef struct OnyxWasmModule { } OnyxWasmModule; OnyxWasmModule onyx_wasm_module_create(bh_allocator alloc); -void onyx_wasm_module_compile(OnyxWasmModule* module, OnyxAstNode* program); +void onyx_wasm_module_compile(OnyxWasmModule* module, OnyxAstNodeFile* program); void onyx_wasm_module_free(OnyxWasmModule* module); void onyx_wasm_module_write_to_file(OnyxWasmModule* module, bh_file file); diff --git a/onyx b/onyx index b4bfa5a7..0a10774a 100755 Binary files a/onyx and b/onyx differ diff --git a/progs/demo.onyx b/progs/demo.onyx deleted file mode 100644 index b36b5c89..00000000 --- a/progs/demo.onyx +++ /dev/null @@ -1,7 +0,0 @@ -use "core"; /* Looks for "core.onyx" in the current directory */ - -Foo :: struct { x i32, y i32 }; - -add :: proc (a i32, b i32) -> i32 { - return a + b + 1234.56; -}; diff --git a/progs/minimal.onyx b/progs/minimal.onyx index 319c48f2..76197666 100644 --- a/progs/minimal.onyx +++ b/progs/minimal.onyx @@ -19,8 +19,6 @@ export main :: proc { print(fib(5)); - { a :: 2; b :: 3; print(a + b); } - print(output); print_float(float_test()); diff --git a/progs/other.onyx b/progs/other.onyx new file mode 100644 index 00000000..1dadc9e7 --- /dev/null +++ b/progs/other.onyx @@ -0,0 +1,4 @@ + +other_value :: proc -> i32 { + return 8675309 + something_else(); +} diff --git a/progs/test.onyx b/progs/test.onyx index 5c6f3671..ad83c20a 100644 --- a/progs/test.onyx +++ b/progs/test.onyx @@ -1,17 +1,21 @@ // Foreign functions are included this way: // sym_name :: foreign "module" "name" proc ... -print :: foreign "host" "print" proc (value i32) --- - -get_value :: foreign "env" "get_val" proc -> i32 --- +print :: foreign "host" "print" proc (value i32) --- +something_else :: proc -> i32 { + return 100; +} // This is the entry point export main :: proc { nineteen :: 5 * 3 + 4; - thirty_five :: 5 * (3 + 4) + get_value(); + thirty_five :: 5 * (3 + 4); + + something :: other_value(); print(nineteen); print(thirty_five); + print(something); } diff --git a/src/onyx.c b/src/onyx.c index 6561b53c..dee3930b 100644 --- a/src/onyx.c +++ b/src/onyx.c @@ -9,6 +9,175 @@ #include "onyxutils.h" #include "onyxwasm.h" +#define VERSION "0.1" + +static const char* docstring = "Onyx compiler version " VERSION "\n" + "\n" + "The standard compiler for the Onyx programming language.\n"; + +typedef enum CompileAction { + ONYX_COMPILE_ACTION_COMPILE, + ONYX_COMPILE_ACTION_CHECK_ERRORS, + ONYX_COMPILE_ACTION_PRINT_HELP, +} CompileAction; + +typedef struct OnyxCompileOptions { + bh_allocator allocator; + CompileAction action; + + bh_arr(const char *) files; + const char* target_file; +} OnyxCompileOptions; + +typedef enum CompilerProgress { + ONYX_COMPILER_PROGRESS_FAILED_READ, + ONYX_COMPILER_PROGRESS_FAILED_PARSE, + ONYX_COMPILER_PROGRESS_FAILED_SEMPASS, + ONYX_COMPILER_PROGRESS_FAILED_BINARY_GEN, + ONYX_COMPILER_PROGRESS_FAILED_OUTPUT, + ONYX_COMPILER_PROGRESS_SUCCESS +} CompilerProgress; + +typedef struct CompilerState { + bh_arena token_arena, ast_arena, msg_arena, sp_arena; + bh_allocator token_alloc, ast_alloc, msg_alloc, sp_alloc; + bh_table(bh_file_contents) loaded_files; + + OnyxMessages msgs; + OnyxWasmModule wasm_mod; +} CompilerState; + +static OnyxCompileOptions compile_opts_parse(bh_allocator alloc, int argc, char *argv[]) { + OnyxCompileOptions options = { + .allocator = alloc, + .action = ONYX_COMPILE_ACTION_PRINT_HELP, + + .files = NULL, + .target_file = "out.wasm", + }; + + bh_arr_new(alloc, options.files, 1); + + fori(i, 1, argc - 1) { + if (!strcmp(argv[i], "--help")) { + options.action = ONYX_COMPILE_ACTION_PRINT_HELP; + break; + } + else if (!strcmp(argv[i], "-o")) { + options.action = ONYX_COMPILE_ACTION_COMPILE; + options.target_file = argv[++i]; + } + else { + options.action = ONYX_COMPILE_ACTION_COMPILE; + bh_arr_push(options.files, argv[i]); + } + } + + return options; +} + +void compile_opts_free(OnyxCompileOptions* opts) { + bh_arr_free(opts->files); +} + +OnyxAstNodeFile* parse_source_file(bh_file_contents* file_contents, CompilerState* compiler_state) { + // NOTE: Maybe don't want to recreate the tokenizer and parser for every file + OnyxTokenizer tokenizer = onyx_tokenizer_create(compiler_state->token_alloc, file_contents); + onyx_lex_tokens(&tokenizer); + + OnyxParser parser = onyx_parser_create(compiler_state->ast_alloc, &tokenizer, &compiler_state->msgs); + return onyx_parse(&parser); +} + +i32 onyx_compile(OnyxCompileOptions* opts, CompilerState* compiler_state) { + + bh_arena_init(&compiler_state->msg_arena, opts->allocator, 4096); + compiler_state->msg_alloc = bh_arena_allocator(&compiler_state->msg_arena); + + onyx_message_create(compiler_state->msg_alloc, &compiler_state->msgs); + + // NOTE: Create the arena for tokens from the lexer + bh_arena_init(&compiler_state->token_arena, opts->allocator, 16 * 1024 * 1024); // 16 MB + compiler_state->token_alloc = bh_arena_allocator(&compiler_state->token_arena); + + // NOTE: Create the arena where AST nodes will exist + // Prevents nodes from being scattered across memory due to fragmentation + bh_arena_init(&compiler_state->ast_arena, opts->allocator, 16 * 1024 * 1024); // 16MB + compiler_state->ast_alloc = bh_arena_allocator(&compiler_state->ast_arena); + + bh_arena_init(&compiler_state->sp_arena, opts->allocator, 16 * 1024); + compiler_state->sp_alloc = bh_arena_allocator(&compiler_state->sp_arena); + + bh_table_init(opts->allocator, compiler_state->loaded_files, 7); + + bh_arr_each(const char *, filename, opts->files) { + bh_file file; + + bh_file_error err = bh_file_open(&file, *filename); + if (err != BH_FILE_ERROR_NONE) { + bh_printf_err("Failed to open file %s\n", filename); + return ONYX_COMPILER_PROGRESS_FAILED_READ; + } + + bh_file_contents fc = bh_file_read_contents(compiler_state->token_alloc, &file); + bh_file_close(&file); + + bh_table_put(bh_file_contents, compiler_state->loaded_files, (char *) filename, fc); + } + + OnyxAstNodeFile* root_file = NULL; + OnyxAstNodeFile* prev_file = NULL; + bh_table_each_start(bh_file_contents, compiler_state->loaded_files); + OnyxAstNodeFile* file_node = parse_source_file(&value, compiler_state); + + if (!root_file) { + root_file = file_node; + } + + if (prev_file) { + prev_file->next = file_node; + } + + prev_file = file_node; + bh_table_each_end; + + if (onyx_message_has_errors(&compiler_state->msgs)) { + return ONYX_COMPILER_PROGRESS_FAILED_PARSE; + } + + OnyxSemPassState sp_state = onyx_sempass_create( compiler_state->sp_alloc, compiler_state->ast_alloc, &compiler_state->msgs); + onyx_sempass(&sp_state, root_file); + + if (onyx_message_has_errors(&compiler_state->msgs)) { + return ONYX_COMPILER_PROGRESS_FAILED_SEMPASS; + } + + compiler_state->wasm_mod = onyx_wasm_module_create(opts->allocator); + onyx_wasm_module_compile(&compiler_state->wasm_mod, root_file); + + if (onyx_message_has_errors(&compiler_state->msgs)) { + return ONYX_COMPILER_PROGRESS_FAILED_BINARY_GEN; + } + + bh_file output_file; + if (bh_file_create(&output_file, opts->target_file) != BH_FILE_ERROR_NONE) { + return ONYX_COMPILER_PROGRESS_FAILED_OUTPUT; + } + + onyx_wasm_module_write_to_file(&compiler_state->wasm_mod, output_file); + + return ONYX_COMPILER_PROGRESS_SUCCESS; +} + +void compiler_state_free(CompilerState* cs) { + bh_arena_free(&cs->ast_arena); + bh_arena_free(&cs->msg_arena); + bh_arena_free(&cs->token_arena); + bh_arena_free(&cs->sp_arena); + bh_table_free(cs->loaded_files); + onyx_wasm_module_free(&cs->wasm_mod); +} + int main(int argc, char *argv[]) { bh_allocator alloc = bh_heap_allocator(); @@ -16,77 +185,50 @@ int main(int argc, char *argv[]) { bh_scratch_init(&global_scratch, alloc, 16 * 1024); // NOTE: 16 KB global_scratch_allocator = bh_scratch_allocator(&global_scratch); - bh_file source_file; - bh_file_error err = bh_file_open(&source_file, argv[1]); - if (err != BH_FILE_ERROR_NONE) { - bh_printf_err("Failed to open file %s\n", argv[1]); - return EXIT_FAILURE; - } + OnyxCompileOptions compile_opts = compile_opts_parse(alloc, argc, argv); + CompilerState compile_state = { + .wasm_mod = { 0 } + }; - // NOTE: 1st: Read file contents - bh_file_contents fc = bh_file_read_contents(alloc, &source_file); - bh_file_close(&source_file); + CompilerProgress compiler_progress = ONYX_COMPILER_PROGRESS_FAILED_READ; - // NOTE: 2nd: Tokenize the contents - OnyxTokenizer tokenizer = onyx_tokenizer_create(alloc, &fc); - onyx_lex_tokens(&tokenizer); - bh_arr(OnyxToken) token_arr = tokenizer.tokens; + switch (compile_opts.action) { + case ONYX_COMPILE_ACTION_PRINT_HELP: + // NOTE: This could probably be made better + bh_printf(docstring); + return 1; - // NOTE: Create the buffer for where compiler messages will be written - bh_arena msg_arena; - bh_arena_init(&msg_arena, alloc, 4096); - bh_allocator msg_alloc = bh_arena_allocator(&msg_arena); + case ONYX_COMPILE_ACTION_COMPILE: + compiler_progress = onyx_compile(&compile_opts, &compile_state); - OnyxMessages msgs; - onyx_message_create(msg_alloc, &msgs); + break; - // NOTE: Create the arena where AST nodes will exist - // Prevents nodes from being scattered across memory due to fragmentation - bh_arena ast_arena; - bh_arena_init(&ast_arena, alloc, 16 * 1024 * 1024); // 16MB - bh_allocator ast_alloc = bh_arena_allocator(&ast_arena); - - // NOTE: 3rd: parse the tokens to an AST - OnyxParser parser = onyx_parser_create(ast_alloc, &tokenizer, &msgs); - OnyxAstNode* program = onyx_parse(&parser); - - bh_arena sp_arena; - bh_arena_init(&sp_arena, alloc, 16 * 1024); - bh_allocator sp_alloc = bh_arena_allocator(&sp_arena); - - OnyxSemPassState sp_state = onyx_sempass_create(sp_alloc, ast_alloc, &msgs); - onyx_sempass(&sp_state, program); - - // NOTE: if there are errors, assume the parse tree was generated wrong, - // even if it may have still been generated correctly. - if (onyx_message_has_errors(&msgs)) { - onyx_message_print(&msgs); - goto main_exit; - } else { - // onyx_ast_print(program, 1); - bh_printf("\nNo errors.\n"); + default: break; + } + + switch (compiler_progress) { + case ONYX_COMPILER_PROGRESS_FAILED_READ: + // NOTE: Do nothing since it was already printed above + break; + + case ONYX_COMPILER_PROGRESS_FAILED_PARSE: + case ONYX_COMPILER_PROGRESS_FAILED_SEMPASS: + case ONYX_COMPILER_PROGRESS_FAILED_BINARY_GEN: + onyx_message_print(&compile_state.msgs); + 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: + bh_printf("Successfully compiled to '%s'\n", compile_opts.target_file); + break; } - // NOTE: 4th: Generate a WASM module from the parse tree and - // write it to a file. - OnyxWasmModule wasm_mod = onyx_wasm_module_create(alloc); - onyx_wasm_module_compile(&wasm_mod, program); - - bh_file out_file; - bh_file_create(&out_file, "out.wasm"); - onyx_wasm_module_write_to_file(&wasm_mod, out_file); - bh_file_close(&out_file); - - onyx_wasm_module_free(&wasm_mod); -main_exit: // NOTE: Cleanup, since C doesn't have defer - bh_arena_free(&sp_arena); - bh_arena_free(&msg_arena); - bh_arena_free(&ast_arena); - onyx_parser_free(&parser); - onyx_tokenizer_free(&tokenizer); - bh_file_contents_free(&fc); - - return 0; + compiler_state_free(&compile_state); + + return compiler_progress == ONYX_COMPILER_PROGRESS_SUCCESS; } // NOTE: Old bits of code that may be useful again at some point. diff --git a/src/onyxparser.c b/src/onyxparser.c index a0edfa65..743333fd 100644 --- a/src/onyxparser.c +++ b/src/onyxparser.c @@ -779,10 +779,10 @@ void onyx_parser_free(OnyxParser* parser) { bh_table_free(parser->identifiers); } -OnyxAstNode* onyx_parse(OnyxParser *parser) { - OnyxAstNode* program = onyx_ast_node_new(parser->allocator, ONYX_AST_NODE_KIND_PROGRAM); +OnyxAstNodeFile* onyx_parse(OnyxParser *parser) { + OnyxAstNodeFile* program = (OnyxAstNodeFile *) onyx_ast_node_new(parser->allocator, ONYX_AST_NODE_KIND_PROGRAM); - OnyxAstNode** prev_stmt = &program->next; + OnyxAstNode** prev_stmt = &program->contents; OnyxAstNode* curr_stmt = NULL; while (parser->curr_token->type != TOKEN_TYPE_END_STREAM) { curr_stmt = parse_top_level_statement(parser); diff --git a/src/onyxsempass.c b/src/onyxsempass.c index 587786a4..d86a3090 100644 --- a/src/onyxsempass.c +++ b/src/onyxsempass.c @@ -23,66 +23,77 @@ OnyxSemPassState onyx_sempass_create(bh_allocator alloc, bh_allocator node_alloc // WASM, this function may not be needed. It brings all of the locals // defined in sub-scopes up to the function-block level. This is a // requirement of WASM, but not of other targets. -static void collapse_scopes(OnyxAstNode* root_node) { +static void collapse_scopes(OnyxAstNodeFile* root_node) { bh_arr(OnyxAstNodeBlock*) traversal_queue = NULL; bh_arr_new(global_scratch_allocator, traversal_queue, 4); bh_arr_set_length(traversal_queue, 0); - OnyxAstNode* walker = root_node; - while (walker) { - if (walker->kind == ONYX_AST_NODE_KIND_FUNCDEF) { - OnyxAstNodeScope* top_scope = walker->as_funcdef.body->scope; + OnyxAstNode* walker; + OnyxAstNodeFile* top_walker = root_node; + while (top_walker) { - bh_arr_push(traversal_queue, walker->as_funcdef.body); - while (!bh_arr_is_empty(traversal_queue)) { - OnyxAstNodeBlock* block = traversal_queue[0]; + walker = top_walker->contents; + while (walker) { + if (walker->kind == ONYX_AST_NODE_KIND_FUNCDEF) { + OnyxAstNodeScope* top_scope = walker->as_funcdef.body->scope; - if (block->kind == ONYX_AST_NODE_KIND_IF) { - OnyxAstNodeIf* if_node = (OnyxAstNodeIf *) block; - if (if_node->true_block) - bh_arr_push(traversal_queue, (OnyxAstNodeBlock *) if_node->true_block); + bh_arr_push(traversal_queue, walker->as_funcdef.body); + while (!bh_arr_is_empty(traversal_queue)) { + OnyxAstNodeBlock* block = traversal_queue[0]; - if (if_node->false_block) - bh_arr_push(traversal_queue, (OnyxAstNodeBlock *) if_node->false_block); + if (block->kind == ONYX_AST_NODE_KIND_IF) { + OnyxAstNodeIf* if_node = (OnyxAstNodeIf *) block; + if (if_node->true_block) + bh_arr_push(traversal_queue, (OnyxAstNodeBlock *) if_node->true_block); - } else { + if (if_node->false_block) + bh_arr_push(traversal_queue, (OnyxAstNodeBlock *) if_node->false_block); - if (block->scope != top_scope && block->scope->last_local != NULL) { - OnyxAstNodeLocal* last_local = block->scope->last_local; - while (last_local && last_local->prev_local != NULL) last_local = last_local->prev_local; + } else { - last_local->prev_local = top_scope->last_local; - top_scope->last_local = block->scope->last_local; - block->scope->last_local = NULL; - } + if (block->scope != top_scope && block->scope->last_local != NULL) { + OnyxAstNodeLocal* last_local = block->scope->last_local; + while (last_local && last_local->prev_local != NULL) last_local = last_local->prev_local; - OnyxAstNode* walker = block->body; - while (walker) { - if (walker->kind == ONYX_AST_NODE_KIND_BLOCK) { - bh_arr_push(traversal_queue, (OnyxAstNodeBlock *) walker); + last_local->prev_local = top_scope->last_local; + top_scope->last_local = block->scope->last_local; + block->scope->last_local = NULL; + } - } else if (walker->kind == ONYX_AST_NODE_KIND_IF) { - if (walker->as_if.true_block) - bh_arr_push(traversal_queue, (OnyxAstNodeBlock *) walker->as_if.true_block); + OnyxAstNode* walker = block->body; + while (walker) { + if (walker->kind == ONYX_AST_NODE_KIND_BLOCK) { + bh_arr_push(traversal_queue, (OnyxAstNodeBlock *) walker); - if (walker->as_if.false_block) - bh_arr_push(traversal_queue, (OnyxAstNodeBlock *) walker->as_if.false_block); - } + } else if (walker->kind == ONYX_AST_NODE_KIND_IF) { + if (walker->as_if.true_block) + bh_arr_push(traversal_queue, (OnyxAstNodeBlock *) walker->as_if.true_block); - walker = walker->next; + if (walker->as_if.false_block) + bh_arr_push(traversal_queue, (OnyxAstNodeBlock *) walker->as_if.false_block); + } + + walker = walker->next; + } } - } - bh_arr_deleten(traversal_queue, 0, 1); + bh_arr_deleten(traversal_queue, 0, 1); + } } + + walker = walker->next; } - walker = walker->next; + top_walker = top_walker->next; } } -void onyx_sempass(OnyxSemPassState* state, OnyxAstNode* root_node) { +void onyx_sempass(OnyxSemPassState* state, OnyxAstNodeFile* root_node) { onyx_resolve_symbols(state, root_node); + if (onyx_message_has_errors(state->msgs)) return; + onyx_type_check(state, root_node); + if (onyx_message_has_errors(state->msgs)) return; + collapse_scopes(root_node); } diff --git a/src/onyxsymres.c b/src/onyxsymres.c index 6e2b2a2a..cfe7f19d 100644 --- a/src/onyxsymres.c +++ b/src/onyxsymres.c @@ -261,35 +261,48 @@ static void symres_function_definition(OnyxSemPassState* state, OnyxAstNodeFuncD } } -void onyx_resolve_symbols(OnyxSemPassState* state, OnyxAstNode* root_node) { - OnyxAstNode* walker = root_node; - while (walker) { - switch (walker->kind) { - case ONYX_AST_NODE_KIND_FUNCDEF: - if (!define_function(state, &walker->as_funcdef)) return; - break; - - case ONYX_AST_NODE_KIND_FOREIGN: - if (walker->as_foreign.import->kind == ONYX_AST_NODE_KIND_FUNCDEF) { - if (!define_function(state, &walker->as_foreign.import->as_funcdef)) return; - } - break; - - default: break; +void onyx_resolve_symbols(OnyxSemPassState* state, OnyxAstNodeFile* root_node) { + OnyxAstNode* walker; + OnyxAstNodeFile* top_walker = root_node; + while (top_walker) { + + walker = top_walker->contents; + while (walker) { + switch (walker->kind) { + case ONYX_AST_NODE_KIND_FUNCDEF: + if (!define_function(state, &walker->as_funcdef)) return; + break; + + case ONYX_AST_NODE_KIND_FOREIGN: + if (walker->as_foreign.import->kind == ONYX_AST_NODE_KIND_FUNCDEF) { + if (!define_function(state, &walker->as_foreign.import->as_funcdef)) return; + } + break; + + default: break; + } + + walker = walker->next; } - walker = walker->next; + top_walker = top_walker->next; } - walker = root_node; - while (walker) { - switch (walker->kind) { - case ONYX_AST_NODE_KIND_FUNCDEF: - symres_function_definition(state, &walker->as_funcdef); - break; - default: break; + top_walker = root_node; + while (top_walker) { + + walker = top_walker->contents; + while (walker) { + switch (walker->kind) { + case ONYX_AST_NODE_KIND_FUNCDEF: + symres_function_definition(state, &walker->as_funcdef); + break; + default: break; + } + + walker = walker->next; } - walker = walker->next; + top_walker = top_walker->next; } } diff --git a/src/onyxtypecheck.c b/src/onyxtypecheck.c index 3f0cb9e7..6949bf57 100644 --- a/src/onyxtypecheck.c +++ b/src/onyxtypecheck.c @@ -301,16 +301,23 @@ static void typecheck_function_defintion(OnyxSemPassState* state, OnyxAstNodeFun } } -void onyx_type_check(OnyxSemPassState* state, OnyxAstNode* root_node) { - OnyxAstNode* walker = root_node; - while (walker) { - switch (walker->kind) { - case ONYX_AST_NODE_KIND_FUNCDEF: - typecheck_function_defintion(state, &walker->as_funcdef); - break; - default: break; +void onyx_type_check(OnyxSemPassState* state, OnyxAstNodeFile* root_node) { + OnyxAstNode* walker; + OnyxAstNodeFile* top_walker = root_node; + while (top_walker) { + + walker = top_walker->contents; + while (walker) { + switch (walker->kind) { + case ONYX_AST_NODE_KIND_FUNCDEF: + typecheck_function_defintion(state, &walker->as_funcdef); + break; + default: break; + } + + walker = walker->next; } - walker = walker->next; + top_walker = top_walker->next; } } diff --git a/src/onyxwasm.c b/src/onyxwasm.c index 94a83ba5..2eef58d7 100644 --- a/src/onyxwasm.c +++ b/src/onyxwasm.c @@ -674,50 +674,69 @@ OnyxWasmModule onyx_wasm_module_create(bh_allocator alloc) { return module; } -void onyx_wasm_module_compile(OnyxWasmModule* module, OnyxAstNode* program) { - OnyxAstNode* walker = program; - while (walker) { - if (walker->kind == ONYX_AST_NODE_KIND_FOREIGN - && walker->as_foreign.import->kind == ONYX_AST_NODE_KIND_FUNCDEF) { - module->next_func_idx++; +void onyx_wasm_module_compile(OnyxWasmModule* module, OnyxAstNodeFile* program) { + OnyxAstNode* walker; + OnyxAstNodeFile* top_walker = program; + while (top_walker) { + + walker = top_walker->contents; + while (walker) { + if (walker->kind == ONYX_AST_NODE_KIND_FOREIGN + && walker->as_foreign.import->kind == ONYX_AST_NODE_KIND_FUNCDEF) { + module->next_func_idx++; + } + + walker = walker->next; } - walker = walker->next; + top_walker = top_walker->next; } - walker = program; - while (walker) { - if (walker->kind == ONYX_AST_NODE_KIND_FUNCDEF) { - i32 func_idx = module->next_func_idx++; - bh_imap_put(&module->func_map, (u64) walker, func_idx); - } + top_walker = program; + while (top_walker) { + + walker = top_walker->contents; + while (walker) { + if (walker->kind == ONYX_AST_NODE_KIND_FUNCDEF) { + i32 func_idx = module->next_func_idx++; + bh_imap_put(&module->func_map, (u64) walker, func_idx); + } - if (walker->kind == ONYX_AST_NODE_KIND_FOREIGN) { - OnyxAstNodeForeign* foreign = &walker->as_foreign; + if (walker->kind == ONYX_AST_NODE_KIND_FOREIGN) { + OnyxAstNodeForeign* foreign = &walker->as_foreign; - if (foreign->import->kind == ONYX_AST_NODE_KIND_FUNCDEF) { - i32 func_idx = module->next_import_func_idx++; - bh_imap_put(&module->func_map, (u64) foreign->import, func_idx); + if (foreign->import->kind == ONYX_AST_NODE_KIND_FUNCDEF) { + i32 func_idx = module->next_import_func_idx++; + bh_imap_put(&module->func_map, (u64) foreign->import, func_idx); + } } + + walker = walker->next; } - walker = walker->next; + top_walker = top_walker->next; } - walker = program; - while (walker) { - switch (walker->kind) { - case ONYX_AST_NODE_KIND_FUNCDEF: - compile_function_definition(module, &walker->as_funcdef); - break; - case ONYX_AST_NODE_KIND_FOREIGN: - compile_foreign(module, &walker->as_foreign); - break; - default: break; - } + top_walker = program; + while (top_walker) { + + walker = top_walker->contents; + while (walker) { + switch (walker->kind) { + case ONYX_AST_NODE_KIND_FUNCDEF: + compile_function_definition(module, &walker->as_funcdef); + break; + case ONYX_AST_NODE_KIND_FOREIGN: + compile_foreign(module, &walker->as_foreign); + break; + default: break; + } - walker = walker->next; - } + walker = walker->next; + } + + top_walker = top_walker->next; + } } void onyx_wasm_module_free(OnyxWasmModule* module) {