Better compiler frontend; compile many files at once
authorBrendan Hansen <brendan.f.hansen@gmail.com>
Wed, 24 Jun 2020 22:33:39 +0000 (17:33 -0500)
committerBrendan Hansen <brendan.f.hansen@gmail.com>
Wed, 24 Jun 2020 22:33:39 +0000 (17:33 -0500)
17 files changed:
.vimspector.json
docs/plan
include/bh.h
include/onyxparser.h
include/onyxsempass.h
include/onyxwasm.h
onyx
progs/demo.onyx [deleted file]
progs/minimal.onyx
progs/other.onyx [new file with mode: 0644]
progs/test.onyx
src/onyx.c
src/onyxparser.c
src/onyxsempass.c
src/onyxsymres.c
src/onyxtypecheck.c
src/onyxwasm.c

index 6444b264eff9b2fbb9a8b049af33825b3945fe41..e309f7f9bf9838e0c2649137abd51c35f11dd304 100644 (file)
@@ -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": [],
index ac906133951ed9c8266054db870dcdbd18ee4678..649fc86b38fa45e742dc5ed81e689e6ab22c14a0 100644 (file)
--- 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).
 
index 063989c8f5a516715696b741095396ae12ec53f1..20a9e9f078b00591303d918a5e66f100eab7f175 100644 (file)
@@ -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]);
index c9d77e6ba4d454f800891ff708c63f8b5eec1ec7..27b903a38dc80eda4c054d0e99215c05b80dd0d0 100644 (file)
@@ -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
index 238e1035a4ee727b37c85ded1353508eaaf573ef..12d879204eaa369716ac820d4b9a4e0770bf928e 100644 (file)
@@ -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
index 1fcd8d36a3b708c648f294630e16abc4dbebf6ae..adebd8bc7070b4edc631771e652fd2fe818d1448 100644 (file)
@@ -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 b4bfa5a720d8fa7f9f1b3a9c0d8ae25ec2738ca7..0a10774a060fda1613f33dedddd8a4a609b13473 100755 (executable)
Binary files a/onyx and b/onyx differ
diff --git a/progs/demo.onyx b/progs/demo.onyx
deleted file mode 100644 (file)
index b36b5c8..0000000
+++ /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;
-};
index 319c48f2522ef8af73a76f2da82f56c1e82ee201..76197666ae3c3a823f91036a6f90c1647d83a452 100644 (file)
@@ -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 (file)
index 0000000..1dadc9e
--- /dev/null
@@ -0,0 +1,4 @@
+
+other_value :: proc -> i32 {
+    return 8675309 + something_else();
+}
index 5c6f36714a1d673f0ac6bb93b340674c539269e2..ad83c20a1590390d8ccb0a9c10cdc537e6970a24 100644 (file)
@@ -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);
 }
index 6561b53c96afb0f034738e607fa8702d131e6584..dee3930b4e642032feb83aad85164e91c7ec6f7f 100644 (file)
@@ -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.
index a0edfa656644413220bf9095634bbd39ed1ea712..743333fd472a77d4a56fab63428bfda2e07f925c 100644 (file)
@@ -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);
index 587786a4641daa650dd2cde88a5cf7839c208d49..d86a30900135550398f30b6684f31978fa815ac7 100644 (file)
@@ -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);
 }
index 6e2b2a2a9bb32e8a344f754e443e241f1fe1596d..cfe7f19ddbc67ccca333524ef9d1bd1df41ada8c 100644 (file)
@@ -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;
     }
 }
index 3f0cb9e738157b836882d692f9a8a9ad14c31f52..6949bf57b68c6ceb84d17c40ac86b917613862db 100644 (file)
@@ -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;
     }
 }
index 94a83ba59e502eb04bb27f779140ec207d9ae9b5..2eef58d7e15063957fd6f021d919261db44f3593 100644 (file)
@@ -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) {