MAJOR CHANGES TO THE LANGUAGE
authorBrendan Hansen <brendan.f.hansen@gmail.com>
Thu, 16 Jul 2020 00:27:48 +0000 (19:27 -0500)
committerBrendan Hansen <brendan.f.hansen@gmail.com>
Thu, 16 Jul 2020 00:27:48 +0000 (19:27 -0500)
Removed some keywords and changed the way somethings work

17 files changed:
docs/thoughts
include/onyxastnodes.h
include/onyxparser.h
misc/onyx.vim
onyx
progs/basic.onyx
progs/other.onyx
progs/print_funcs.onyx
progs/test.onyx
src/onyx.c
src/onyxchecker.c
src/onyxlex.c
src/onyxparser.c
src/onyxsempass.c
src/onyxsymres.c
src/onyxutils.c
src/onyxwasm.c

index 639488db595bbf374229bb4b3bc036ab5c63b4c6..b9402481a6078e69f1c5ddf9d6013ca3c071c5c0 100644 (file)
-Memory design:\r
-    - Pointers will work very similar to how they do in C\r
-        - A pointer is a u32\r
-        - Pointers will be notated:\r
-            ^u32  <- Pointer to u32\r
-\r
-        - Pointer operations will be:\r
-            * will take the address of a value\r
-                - This operation will not be defined well for a while\r
-                - You can't take the address of a local since it doesn't exist in memory\r
-\r
-            << will take the value out of a pointer\r
-\r
-            Example use:\r
-            {{{\r
-                ptr: ^i32 = 0; // Address starting at 0\r
-                ptr_ptr := ^ptr;\r
-            }}}\r
+Memory design:
+    - Pointers will work very similar to how they do in C
+        - A pointer is a u32
+        - Pointers will be notated:
+            ^u32  <- Pointer to u32
+
+        - Pointer operations will be:
+            * will take the address of a value
+                - This operation will not be defined well for a while
+                - You can't take the address of a local since it doesn't exist in memory
+
+            << will take the value out of a pointer
+
+            Example use:
+            {{{
+                ptr: ^i32 = 0; // Address starting at 0
+                ptr_ptr := ^ptr;
+            }}}
+
+
+
+
+
+Treating top level declarations differently:
+    Currently, top level declarations are treated special, as they would correspond to
+    the structure of the WASM that would be generated. For example,
+
+        inc :: proc (a: i32) -> i32 { return a + 1; }
+
+    would be turned into an AstFunction node with a token of 'inc', and,
+
+        global :: 5
+
+    would be turned into a AstGlobal node with a token of 'global'.
+
+    The problem I have with this approach is it creates an inconsistency when thinking
+    about what is going on in the various stages in the compiler.
+
+    A better approach would be to have a AstBinding node, that represents a binding
+    from a symbol, stored on the token member, to another Ast Node. The node definition
+    would be:
+
+        struct AstBinding { AstTyped base; AstNode* node; }
+
+    For a function definition such as 'inc' above, the node structure would look like:
+
+        AstBinding (inc)
+            .node -> AstFunction
+                        .params -> AstLocal (a) -> NULL
+                        .body -> ...
+
+    This way, in symbol resolution, the top level bindings are added to the table and
+    there are no special cases.
+
+    Other nuances:
+
+        global :: 5     - This would replace all instances of 'global' with the integer constant
+                            5. This would not make a global in WASM.
+
+        global := 5     - This would work as expected but will make generating the WASM more difficult.
+                            This feature may wait to come back.
+
+        global :: i32   - This would work as a type alias. 'global' would have the type node as it's 'node'
+
+        print :: proc #foriegn "host" "print" (...) ---
+
+
+Explicit overriden functions:
+    Considered syntax:
+
+        foo_i32 :: proc (val: i32) -> i32 ---
+        foo_i64 :: proc (val: i64) -> i64 ---
+        foo_f32 :: proc (val: f32) -> f32 ---
+        foo_f64 :: proc (val: f64) -> f64 ---
+
+        foo :: proc #overload {
+            foo_i32, foo_i64, foo_f32, foo_f64
+        }
+
+        foo(10);        // calls foo_i32
+        foo(2.0f);      // calls foo_f32
+
+
+        min_f32 :: proc #intrinsic (a: f32, b:f32) -> f32 ---
+        min_f64 :: proc #intrinsic (a: f64, b:f64) -> f64 ---
+
+        min_i32 :: proc (a: i32, b: i32) -> i32 {
+            least := a;
+            if b < a { least = b; }
+
+            return least;
+        }
+
+        min_i64 :: proc (a: i64, b: i64) -> i64 {
+            least := a;
+            if b < a { least = b; }
+
+            return least;
+        }
+
+        min :: proc #overload { min_i32, min_i64, min_f32, min_f64 }
+
+        min(2, 5);
+        min(4.5, 10.4);
index a39b876cc7c1f6767ed813c99ec0c10f3f031fcd..ba6fe398d75dcbf11d6c455bb7cf4e7bee2a7010 100644 (file)
@@ -11,28 +11,33 @@ typedef struct AstBinOp AstBinaryOp;
 typedef struct AstAssign AstAssign;
 typedef struct AstNumLit AstNumLit;
 typedef struct AstLocal AstLocal;
-typedef struct AstLocalGroup AstLocalGroup;
 typedef struct AstReturn AstReturn;
-typedef struct AstBlock AstBlock;
-typedef struct AstIf AstIf;
-typedef struct AstWhile AstWhile;
-typedef struct AstFunction AstFunction;
-typedef struct AstForeign AstForeign;
-typedef struct AstGlobal AstGlobal;
 typedef struct AstCall AstCall;
 typedef struct AstIntrinsicCall AstIntrinsicCall;
 typedef struct AstArgument AstArgument;
-typedef struct AstUse AstUse;
+
+typedef struct AstBlock AstBlock;
+typedef struct AstIf AstIf;
+typedef struct AstWhile AstWhile;
+typedef struct AstLocalGroup AstLocalGroup;
 
 typedef struct AstType AstType;
 typedef struct AstBasicType AstBasicType;
 typedef struct AstPointerType AstPointerType;
+typedef struct AstFunctionType AstFunctionType;
+
+typedef struct AstBinding AstBinding;
+typedef struct AstFunction AstFunction;
+typedef struct AstForeign AstForeign;
+typedef struct AstGlobal AstGlobal;
+typedef struct AstUse AstUse;
 
 typedef enum AstKind {
     Ast_Kind_Error,
     Ast_Kind_Program,
     Ast_Kind_Use,
 
+    Ast_Kind_Binding,
     Ast_Kind_Function,
     Ast_Kind_Foreign,
     Ast_Kind_Block,
@@ -44,9 +49,12 @@ typedef enum AstKind {
     Ast_Kind_Unary_Op,
     Ast_Kind_Binary_Op,
 
+    Ast_Kind_Type_Start,
     Ast_Kind_Type,
     Ast_Kind_Basic_Type,
     Ast_Kind_Pointer_Type,
+    Ast_Kind_Function_Type,
+    Ast_Kind_Type_End,
 
     Ast_Kind_Literal,
     Ast_Kind_Param,
@@ -76,6 +84,7 @@ typedef enum AstFlags {
     // Function flags
     Ast_Flag_Inline          = BH_BIT(8),
     Ast_Flag_Intrinsic       = BH_BIT(9),
+    Ast_Flag_Foreign         = BH_BIT(10),
 } AstFlags;
 
 typedef enum UnaryOp {
@@ -137,10 +146,10 @@ struct AstTyped {
 // Expression Nodes
 struct AstBinOp         { AstTyped base; BinaryOp operation; AstTyped *left, *right; };
 struct AstUnaryOp       { AstTyped base; UnaryOp operation; AstTyped *expr; };
-struct AstAssign        { AstNode base;  AstTyped* lval; AstTyped* expr; };
+struct AstAssign        { AstNode  base; AstTyped* lval; AstTyped* expr; };
 struct AstNumLit        { AstTyped base; union { i32 i; i64 l; f32 f; f64 d; } value; };
 struct AstLocal         { AstTyped base; AstLocal *prev_local; };
-struct AstReturn        { AstNode base;  AstTyped* expr; };
+struct AstReturn        { AstNode  base; AstTyped* expr; };
 struct AstCall          { AstTyped base; AstArgument *arguments; AstNode *callee; };
 struct AstArgument      { AstTyped base; AstTyped *value; };
 
@@ -166,12 +175,26 @@ struct AstIf {
 struct AstType          { AstKind kind; u32 flags; char* name; };
 struct AstBasicType     { AstType base; Type* type; };
 struct AstPointerType   { AstType base; AstType* elem; };
+struct AstFunctionType  { AstType base; bh_arr(AstType *) params; AstType* results; };
 
 // Top level nodes
-struct AstFunction      { AstTyped base; AstBlock *body; AstLocal *params; };
-struct AstForeign       { AstNode base;  OnyxToken *mod_token, *name_token; AstNode *import; };
+struct AstBinding       { AstTyped base; AstNode* node; };
+struct AstForeign       { AstNode  base; OnyxToken *mod_token, *name_token; AstNode *import; };
 struct AstGlobal        { AstTyped base; AstTyped *initial_value; };
-struct AstUse           { AstNode base;  OnyxToken *filename; };
+struct AstUse           { AstNode  base; OnyxToken *filename; };
+struct AstFunction      {
+    AstTyped base;
+
+    AstBlock *body;
+    AstLocal *params;
+
+    // NOTE: Used when a function is exported with a specific name
+    char* exported_name;
+
+    // NOTE: Used when the function is declared as foreign
+    OnyxToken* foreign_module;
+    OnyxToken* foreign_name;
+};
 
 typedef enum OnyxIntrinsic {
     ONYX_INTRINSIC_UNDEFINED,
@@ -206,9 +229,10 @@ typedef enum OnyxIntrinsic {
 struct AstIntrinsicCall { AstTyped base; AstArgument *arguments; OnyxIntrinsic intrinsic; };
 
 typedef struct OnyxProgram {
-    bh_arr(AstGlobal *) globals;
+    bh_arr(AstBinding *)  top_level_bindings;
+    bh_arr(AstNode *)     nodes_to_process;
+
     bh_arr(AstFunction *) functions;
-    bh_arr(AstForeign *) foreigns;
 } OnyxProgram;
 
 
index fbf30cbbf51d1cb51db9cf48f264b9ea87cbffcf..fba6bfaf1eba264e506f0870586409fcbc4d47c9 100644 (file)
@@ -7,20 +7,34 @@
 #include "onyxmsgs.h"
 #include "onyxastnodes.h"
 
+typedef struct ParseResults {
+    // NOTE: The allocator used to make the arrays below
+    bh_allocator allocator;
+
+    bh_arr(AstUse *) uses;
+    bh_arr(AstBinding *) bindings;
+
+    // NOTE: Contains all the nodes that will need some processing (symbol resolution, type checking)
+    bh_arr(AstNode *) nodes_to_process;
+} ParseResults;
+
 typedef struct OnyxParser {
-    OnyxTokenizer *tokenizer; // NOTE: not used since all tokens are lexed before parsing starts
+    bh_allocator allocator;
+
+    // NOTE: not used since all tokens are lexed before parsing starts
+    OnyxTokenizer *tokenizer;
     OnyxToken *prev_token;
     OnyxToken *curr_token;
 
     OnyxMessages *msgs;
 
-    bh_allocator allocator;
+    ParseResults results;
 } OnyxParser;
 
 const char* onyx_ast_node_kind_string(AstKind kind);
 void* onyx_ast_node_new(bh_allocator alloc, i32 size, AstKind kind);
 OnyxParser onyx_parser_create(bh_allocator alloc, OnyxTokenizer *tokenizer, OnyxMessages* msgs);
 void onyx_parser_free(OnyxParser* parser);
-bh_arr(AstNode *) onyx_parse(OnyxParser *parser);
+ParseResults onyx_parse(OnyxParser *parser);
 
 #endif // #ifndef ONYXPARSER_H
index ca189a5e981c9acd10d78f804e6756a6f3bf4422..23ebf5b7e3d6175014a74821c09a380d00844470 100644 (file)
@@ -10,9 +10,9 @@ endif
 let s:cpo_save = &cpo
 set cpo&vim
 
-syn keyword onyxKeyword struct proc use export foreign
+syn keyword onyxKeyword struct proc use
 syn keyword onyxKeyword if elseif else
-syn keyword onyxKeyword for while loop return do
+syn keyword onyxKeyword for while do
 syn keyword onyxKeyword break continue return
 syn keyword onyxKeyword as
 
diff --git a/onyx b/onyx
index be28846fee968f54df9eca91182a3ede8434a47d..9fb8a4b9ebbe69027e5cec4721d2b8fd8a5fc919 100755 (executable)
Binary files a/onyx and b/onyx differ
index d8e5bcb833851662b0433f1371f54b03a2dee5d2..e7a0c5f00e11e20abe4ddbe69b17f54d249de954 100644 (file)
@@ -4,7 +4,9 @@ pointer_test :: proc {
     p := 0 as ^i32;
 }
 
-print :: foreign "host" "print" proc (val: i32) ---
+print :: proc
+    #foreign "host" "print"
+    (val: i32) ---
 
 test :: proc (a: bool) -> bool {
     return !a;
@@ -16,10 +18,22 @@ foo :: proc (n: i32) -> i32 {
     return or_i32(a, b);
 }
 
-export main :: proc {
+// THOUGHT: This could be a WASM global that is immutable and it
+// would be accessed using global.get
+// OR
+// This could be immediately substituted in the expression tree. i.e.
+//      4 + global       =>       4 + (5 * 2 + 6)
+global :: 5 * 2 + 6
+
+// WASM globals would be declared as such:
+// wasm_global :: global i32
+
+main :: proc #export {
     a := 16;
     print(clz_i32(a));
 
+    print(4 + global);
+
     b := 1 + foo(2);
     print(b);
 
index 7bab1efb8f7e8a05e23688299bac48777f04985d..70b9a52e273ef12228f83f8cc807fec053851c31 100644 (file)
@@ -4,7 +4,7 @@ other_value :: proc (n: i32) -> i32 {
     return 8675309 + something_else(n) + global_value;
 }
 
-export fib :: proc (n: i32) -> i32 {
+fib :: proc #export (n: i32) -> i32 {
     if n == 0 { return 1; }
     if n == 1 { return 1; }
 
@@ -24,7 +24,7 @@ export fib :: proc (n: i32) -> i32 {
     return a;
 }
 
-export factorial :: proc (n: i32) -> i32 {
+factorial :: proc #export (n: i32) -> i32 {
     if n <= 1 { return 1; }
 
     f := 1;
index bb2a3d6093a0f69a626604060e8ce4789fb15936..3ac27828645e6312d0af12662fa32707a4c25ba6 100644 (file)
@@ -1,5 +1,5 @@
-print_bool :: foreign "host" "print" proc (value: bool) ---
-print_i32  :: foreign "host" "print" proc (value: i32) ---
-print_f32  :: foreign "host" "print" proc (value: f32) ---
-print_i64  :: foreign "host" "print" proc (value: i64) ---
-print_f64  :: foreign "host" "print" proc (value: f64) ---
+print_bool :: proc #foreign "host" "print" (value: bool) ---
+print_i32  :: proc #foreign "host" "print" (value: i32) ---
+print_f32  :: proc #foreign "host" "print" (value: f32) ---
+print_i64  :: proc #foreign "host" "print" (value: i64) ---
+print_f64  :: proc #foreign "host" "print" (value: f64) ---
index db16c2b9232f6c7043bd2373ac808237601e45b6..6214b2789b9f8a668b4e81ae7fbe801fdfed6cca 100644 (file)
@@ -6,17 +6,46 @@ something_else :: proc (n: i32) -> i32 {
     return 100 * n + global_value;
 }
 
-global_value := 100
-
-export in_unit_circle :: proc (x: f32, y: f32) -> bool {
+in_unit_circle :: proc #export (x: f32, y: f32) -> bool {
     return (x * x) + (y * y) < 1.0f;
 }
 
+echo :: proc (n: i32) -> i32 {
+    print_i32(n);
+    return n;
+}
+
+global_value :: echo(fib(4) * 2);
+
+local_brute :: proc {
+
+    a := 123;
+    b := 123.0f;
+    c := 123.0;
+
+    {
+        a := 5.0f;
+        b := 12.3;
+
+        print_f32(a);
+        print_f64(b);
+    }
+
+    print_i32(a);
+    print_f32(b);
+    print_f64(c);
+}
+
+main3 :: proc #export {
+    local_brute();
+}
+
+
 // This is the entry point
-export main2 :: proc {
+main2 :: proc #export {
     i := 0;
     while i < 10 {
-        res :: fib(i);
+        res :: clz_i32(fib(i));
         print_i32(res);
         i += 1;
     }
@@ -61,7 +90,7 @@ export main2 :: proc {
 //     z : f32;
 // }
 
-export main :: proc {
+main :: proc #export {
     print_i32(clz_i32(16));
     print_f32(sqrt_f32(2.0f));
 
@@ -69,10 +98,9 @@ export main :: proc {
     print_bool(in_unit_circle(0.5f, 0.5f));
 
     big_num := fib(factorial(4));
-    something :: other_value(0);
 
-    global_value = 1000;
-    something_else :: other_value(0);
+    something       :: other_value(0);
+    something_else  :: other_value(1);
 
     condition := big_num < something;
 
index 7c2abd826cd97cfde19d1de3f7261ddac69718f6..b7c24e298fb726590ed79107296a439c60856ca1 100644 (file)
@@ -106,7 +106,7 @@ static void compile_opts_free(OnyxCompileOptions* opts) {
     bh_arr_free(opts->files);
 }
 
-static bh_arr(AstNode *) parse_source_file(CompilerState* compiler_state, bh_file_contents* file_contents) {
+static ParseResults parse_source_file(CompilerState* compiler_state, bh_file_contents* file_contents) {
     // NOTE: Maybe don't want to recreate the tokenizer and parser for every file
     if (compiler_state->options->verbose_output)
         bh_printf("[Lexing]       %s\n", file_contents->filename);
@@ -142,35 +142,9 @@ static CompilerProgress process_source_file(CompilerState* compiler_state, char*
     bh_table_put(bh_file_contents, compiler_state->loaded_files, (char *) filename, fc);
     fc = bh_table_get(bh_file_contents, compiler_state->loaded_files, (char *) filename);
 
-    bh_arr(AstNode *) top_nodes = parse_source_file(compiler_state, &fc);
+    ParseResults results = parse_source_file(compiler_state, &fc);
 
-    bh_arr(AstUse *) uses = NULL;
-
-    bh_arr_each(AstNode *, node, top_nodes) {
-        switch ((*node)->kind) {
-            case Ast_Kind_Use:
-                bh_arr_push(uses, (AstUse *) *node);
-                break;
-
-            case Ast_Kind_Global:
-                bh_arr_push(compiler_state->program.globals, (AstGlobal *) (*node));
-                break;
-
-            case Ast_Kind_Foreign:
-                bh_arr_push(compiler_state->program.foreigns, (AstForeign *) (*node));
-                break;
-
-            case Ast_Kind_Function:
-                bh_arr_push(compiler_state->program.functions, (AstFunction *) (*node));
-                break;
-
-            default:
-                assert(("Invalid top level node", 0));
-                break;
-        }
-    }
-
-    bh_arr_each(AstUse *, use_node, uses) {
+    bh_arr_each(AstUse *, use_node, results.uses) {
         char* formatted_name = bh_aprintf(
                 global_heap_allocator,
                 "%b.onyx",
@@ -179,7 +153,11 @@ static CompilerProgress process_source_file(CompilerState* compiler_state, char*
         bh_arr_push(compiler_state->queued_files, formatted_name);
     }
 
-    bh_arr_free(uses);
+    bh_arr_each(AstBinding *, binding_node, results.bindings)
+        bh_arr_push(compiler_state->program.top_level_bindings, *binding_node);
+
+    bh_arr_each(AstNode *, node, results.nodes_to_process)
+        bh_arr_push(compiler_state->program.nodes_to_process, *node);
 
     if (onyx_message_has_errors(&compiler_state->msgs)) {
         return ONYX_COMPILER_PROGRESS_FAILED_PARSE;
@@ -191,8 +169,7 @@ static CompilerProgress process_source_file(CompilerState* compiler_state, char*
 static void compiler_state_init(CompilerState* compiler_state, OnyxCompileOptions* opts) {
     compiler_state->options = opts;
 
-    bh_arr_new(global_heap_allocator, compiler_state->program.foreigns, 4);
-    bh_arr_new(global_heap_allocator, compiler_state->program.globals, 4);
+    bh_arr_new(global_heap_allocator, compiler_state->program.top_level_bindings, 4);
     bh_arr_new(global_heap_allocator, compiler_state->program.functions, 4);
 
     bh_arena_init(&compiler_state->msg_arena, opts->allocator, 4096);
@@ -289,9 +266,10 @@ int main(int argc, char *argv[]) {
     OnyxCompileOptions compile_opts = compile_opts_parse(global_heap_allocator, argc, argv);
     CompilerState compile_state = {
         .program = {
-            .foreigns = NULL,
-            .globals = NULL,
-            .functions = NULL
+            .top_level_bindings = NULL,
+            .nodes_to_process   = NULL,
+
+            .functions = NULL,
         },
         .wasm_mod = { 0 }
     };
index 531ebd32801938d378dd5b95be94c498e8afbb11..365a11c9033a00b440d2e01a6dd490328a69fc50 100644 (file)
@@ -1,26 +1,26 @@
 #define BH_DEBUG
 #include "onyxsempass.h"
 
-static void check_function(OnyxSemPassState* state, AstFunction* func);
-static void check_block(OnyxSemPassState* state, AstBlock* block);
-static void check_statement_chain(OnyxSemPassState* state, AstNode* start);
-static void check_statement(OnyxSemPassState* state, AstNode* stmt);
-static void check_assignment(OnyxSemPassState* state, AstAssign* assign);
-static void check_return(OnyxSemPassState* state, AstReturn* retnode);
-static void check_if(OnyxSemPassState* state, AstIf* ifnode);
-static void check_while(OnyxSemPassState* state, AstWhile* whilenode);
-static void check_call(OnyxSemPassState* state, AstCall* call);
-static void check_binaryop(OnyxSemPassState* state, AstBinaryOp* binop);
-static void check_expression(OnyxSemPassState* state, AstTyped* expr);
-static void check_global(OnyxSemPassState* state, AstGlobal* global);
-
-static void check_assignment(OnyxSemPassState* state, AstAssign* assign) {
+static b32 check_function(OnyxSemPassState* state, AstFunction* func);
+static b32 check_block(OnyxSemPassState* state, AstBlock* block);
+static b32 check_statement_chain(OnyxSemPassState* state, AstNode* start);
+static b32 check_statement(OnyxSemPassState* state, AstNode* stmt);
+static b32 check_assignment(OnyxSemPassState* state, AstAssign* assign);
+static b32 check_return(OnyxSemPassState* state, AstReturn* retnode);
+static b32 check_if(OnyxSemPassState* state, AstIf* ifnode);
+static b32 check_while(OnyxSemPassState* state, AstWhile* whilenode);
+static b32 check_call(OnyxSemPassState* state, AstCall* call);
+static b32 check_binaryop(OnyxSemPassState* state, AstBinaryOp* binop);
+static b32 check_expression(OnyxSemPassState* state, AstTyped* expr);
+static b32 check_global(OnyxSemPassState* state, AstGlobal* global);
+
+static b32 check_assignment(OnyxSemPassState* state, AstAssign* assign) {
     if (assign->lval->kind == Ast_Kind_Symbol) {
         onyx_message_add(state->msgs,
                 ONYX_MESSAGE_TYPE_UNRESOLVED_SYMBOL,
                 assign->lval->token->pos,
                 assign->lval->token->text, assign->lval->token->length);
-        return;
+        return 1;
     }
 
     if ((assign->lval->flags & Ast_Flag_Const) != 0 && assign->lval->type != NULL) {
@@ -28,7 +28,7 @@ static void check_assignment(OnyxSemPassState* state, AstAssign* assign) {
                 ONYX_MESSAGE_TYPE_ASSIGN_CONST,
                 assign->base.token->pos,
                 assign->lval->token->text, assign->lval->token->length);
-        return;
+        return 1;
     }
 
     if ((assign->lval->flags & Ast_Flag_Lval) == 0) {
@@ -36,14 +36,14 @@ static void check_assignment(OnyxSemPassState* state, AstAssign* assign) {
                 ONYX_MESSAGE_TYPE_NOT_LVAL,
                 assign->base.token->pos,
                 assign->lval->token->text, assign->lval->token->length);
-        return;
+        return 1;
     }
 
     if (assign->lval->type == NULL) {
         assign->lval->type = type_build_from_ast(state->node_allocator, assign->lval->type_node);
     }
 
-    check_expression(state, assign->expr);
+    if (check_expression(state, assign->expr)) return 1;
 
     if (assign->lval->type == NULL) {
         assign->lval->type = assign->expr->type;
@@ -54,14 +54,16 @@ static void check_assignment(OnyxSemPassState* state, AstAssign* assign) {
                     assign->base.token->pos,
                     type_get_name(assign->lval->type),
                     type_get_name(assign->expr->type));
-            return;
+            return 1;
         }
     }
+
+    return 0;
 }
 
-static void check_return(OnyxSemPassState* state, AstReturn* retnode) {
+static b32 check_return(OnyxSemPassState* state, AstReturn* retnode) {
     if (retnode->expr) {
-        check_expression(state, retnode->expr);
+        if (check_expression(state, retnode->expr)) return 1;
 
         if (!types_are_compatible(retnode->expr->type, state->expected_return_type)) {
             onyx_message_add(state->msgs,
@@ -69,6 +71,7 @@ static void check_return(OnyxSemPassState* state, AstReturn* retnode) {
                     retnode->expr->token->pos,
                     type_get_name(retnode->expr->type),
                     type_get_name(state->expected_return_type));
+            return 1;
         }
     } else {
         if (state->expected_return_type->Basic.size > 0) {
@@ -76,12 +79,15 @@ static void check_return(OnyxSemPassState* state, AstReturn* retnode) {
                     ONYX_MESSAGE_TYPE_LITERAL,
                     retnode->base.token->pos,
                     "returning from non-void function without value");
+            return 1;
         }
     }
+
+    return 0;
 }
 
-static void check_if(OnyxSemPassState* state, AstIf* ifnode) {
-    check_expression(state, ifnode->cond);
+static b32 check_if(OnyxSemPassState* state, AstIf* ifnode) {
+    if (check_expression(state, ifnode->cond)) return 1;
 
     if (ifnode->cond->type == NULL
             || ifnode->cond->type->kind != Type_Kind_Basic
@@ -91,15 +97,17 @@ static void check_if(OnyxSemPassState* state, AstIf* ifnode) {
                 ONYX_MESSAGE_TYPE_LITERAL,
                 ifnode->cond->token->pos,
                 "expected boolean type for condition");
-        return;
+        return 1;
     }
 
-    if (ifnode->true_block.as_if)  check_statement(state, (AstNode *) ifnode->true_block.as_block);
-    if (ifnode->false_block.as_if) check_statement(state, (AstNode *) ifnode->false_block.as_block);
+    if (ifnode->true_block.as_if)  if (check_statement(state, (AstNode *) ifnode->true_block.as_block))  return 1;
+    if (ifnode->false_block.as_if) if (check_statement(state, (AstNode *) ifnode->false_block.as_block)) return 1;
+
+    return 0;
 }
 
-static void check_while(OnyxSemPassState* state, AstWhile* whilenode) {
-    check_expression(state, whilenode->cond);
+static b32 check_while(OnyxSemPassState* state, AstWhile* whilenode) {
+    if (check_expression(state, whilenode->cond)) return 1;
 
     if (whilenode->cond->type == NULL
             || whilenode->cond->type->kind != Type_Kind_Basic
@@ -109,13 +117,13 @@ static void check_while(OnyxSemPassState* state, AstWhile* whilenode) {
                 ONYX_MESSAGE_TYPE_LITERAL,
                 whilenode->cond->token->pos,
                 "expected boolean type for condition");
-        return;
+        return 1;
     }
 
-    check_block(state, whilenode->body);
+    return check_block(state, whilenode->body);
 }
 
-static void check_call(OnyxSemPassState* state, AstCall* call) {
+static b32 check_call(OnyxSemPassState* state, AstCall* call) {
     AstFunction* callee = (AstFunction *) call->callee;
 
     if (callee->base.kind == Ast_Kind_Symbol) {
@@ -123,7 +131,7 @@ static void check_call(OnyxSemPassState* state, AstCall* call) {
                 ONYX_MESSAGE_TYPE_UNRESOLVED_SYMBOL,
                 callee->base.token->pos,
                 callee->base.token->text, callee->base.token->length);
-        return;
+        return 1;
     }
 
     if (callee->base.kind != Ast_Kind_Function) {
@@ -131,7 +139,7 @@ static void check_call(OnyxSemPassState* state, AstCall* call) {
                 ONYX_MESSAGE_TYPE_CALL_NON_FUNCTION,
                 call->base.token->pos,
                 callee->base.token->text, callee->base.token->length);
-        return;
+        return 1;
     }
 
     // NOTE: If we calling an intrinsic function, translate the
@@ -207,7 +215,7 @@ static void check_call(OnyxSemPassState* state, AstCall* call) {
 
     i32 arg_pos = 0;
     while (formal_param != NULL && actual_param != NULL) {
-        check_expression(state, (AstTyped *) actual_param);
+        if (check_expression(state, (AstTyped *) actual_param)) return 1;
 
         if (formal_param->base.type == NULL) {
             formal_param->base.type = type_build_from_ast(state->node_allocator, formal_param->base.type_node);
@@ -221,7 +229,7 @@ static void check_call(OnyxSemPassState* state, AstCall* call) {
                     type_get_name(formal_param->base.type),
                     arg_pos,
                     type_get_name(actual_param->base.type));
-            return;
+            return 1;
         }
 
         arg_pos++;
@@ -234,7 +242,7 @@ static void check_call(OnyxSemPassState* state, AstCall* call) {
                 ONYX_MESSAGE_TYPE_LITERAL,
                 call->base.token->pos,
                 "too few arguments to function call");
-        return;
+        return 1;
     }
 
     if (formal_param == NULL && actual_param != NULL) {
@@ -242,20 +250,22 @@ static void check_call(OnyxSemPassState* state, AstCall* call) {
                 ONYX_MESSAGE_TYPE_LITERAL,
                 call->base.token->pos,
                 "too many arguments to function call");
-        return;
+        return 1;
     }
+
+    return 0;
 }
 
-static void check_binaryop(OnyxSemPassState* state, AstBinaryOp* binop) {
-    check_expression(state, binop->left);
-    check_expression(state, binop->right);
+static b32 check_binaryop(OnyxSemPassState* state, AstBinaryOp* binop) {
+    if (check_expression(state, binop->left)) return 1;
+    if (check_expression(state, binop->right)) return 1;
 
     if (binop->left->type == NULL) {
         onyx_message_add(state->msgs,
                 ONYX_MESSAGE_TYPE_UNRESOLVED_TYPE,
                 binop->base.token->pos,
                 NULL, 0);
-        return;
+        return 1;
     }
 
     if (binop->right->type == NULL) {
@@ -263,7 +273,7 @@ static void check_binaryop(OnyxSemPassState* state, AstBinaryOp* binop) {
                 ONYX_MESSAGE_TYPE_UNRESOLVED_TYPE,
                 binop->base.token->pos,
                 NULL, 0);
-        return;
+        return 1;
     }
 
     if (type_is_pointer(binop->left->type)
@@ -272,7 +282,7 @@ static void check_binaryop(OnyxSemPassState* state, AstBinaryOp* binop) {
                 ONYX_MESSAGE_TYPE_LITERAL,
                 binop->base.token->pos,
                 "binary operations are not supported for pointers (yet).");
-        return;
+        return 1;
     }
 
     if (!types_are_compatible(binop->left->type, binop->right->type)) {
@@ -281,7 +291,7 @@ static void check_binaryop(OnyxSemPassState* state, AstBinaryOp* binop) {
                 binop->base.token->pos,
                 type_get_name(binop->left->type),
                 type_get_name(binop->right->type));
-        return;
+        return 1;
     }
 
     if (binop->operation >= Binary_Op_Equal
@@ -290,39 +300,44 @@ static void check_binaryop(OnyxSemPassState* state, AstBinaryOp* binop) {
     } else {
         binop->base.type = binop->left->type;
     }
+
+    return 0;
 }
 
-static void check_expression(OnyxSemPassState* state, AstTyped* expr) {
+static b32 check_expression(OnyxSemPassState* state, AstTyped* expr) {
+    if (expr->kind > Ast_Kind_Type_Start && expr->kind < Ast_Kind_Type_End) {
+        onyx_message_add(state->msgs,
+                ONYX_MESSAGE_TYPE_LITERAL,
+                (OnyxFilePos) { 0 },
+                "type used as part of an expression");
+        return 1;
+    }
+
     if (expr->type == NULL) {
         expr->type = type_build_from_ast(state->node_allocator, expr->type_node);
     }
 
+    i32 retval = 0;
     switch (expr->kind) {
-        case Ast_Kind_Binary_Op:
-            check_binaryop(state, (AstBinaryOp *) expr);
-            break;
+        case Ast_Kind_Binary_Op: retval = check_binaryop(state, (AstBinaryOp *) expr); break;
 
         case Ast_Kind_Unary_Op:
-            check_expression(state, ((AstUnaryOp *) expr)->expr);
+            retval = check_expression(state, ((AstUnaryOp *) expr)->expr);
 
             if (((AstUnaryOp *) expr)->operation != Unary_Op_Cast) {
                 expr->type = ((AstUnaryOp *) expr)->expr->type;
             }
             break;
 
-        case Ast_Kind_Call:
-            check_call(state, (AstCall *) expr);
-            break;
-
-        case Ast_Kind_Block:
-            check_block(state, (AstBlock *) expr);
-            break;
+        case Ast_Kind_Call:  retval = check_call(state, (AstCall *) expr); break;
+        case Ast_Kind_Block: retval = check_block(state, (AstBlock *) expr); break;
 
         case Ast_Kind_Symbol:
             onyx_message_add(state->msgs,
                     ONYX_MESSAGE_TYPE_UNRESOLVED_SYMBOL,
                     expr->token->pos,
                     expr->token->text, expr->token->length);
+            retval = 1;
             break;
 
         case Ast_Kind_Local:
@@ -332,6 +347,7 @@ static void check_expression(OnyxSemPassState* state, AstTyped* expr) {
                         ONYX_MESSAGE_TYPE_LITERAL,
                         expr->token->pos,
                         "local variable with unknown type");
+                retval = 1;
             }
             break;
 
@@ -341,11 +357,12 @@ static void check_expression(OnyxSemPassState* state, AstTyped* expr) {
                         ONYX_MESSAGE_TYPE_LITERAL,
                         expr->token->pos,
                         "global with unknown type");
+                retval = 1;
             }
             break;
 
         case Ast_Kind_Argument:
-            check_expression(state, ((AstArgument *) expr)->value);
+            retval = check_expression(state, ((AstArgument *) expr)->value);
             expr->type = ((AstArgument *) expr)->value->type;
             break;
 
@@ -356,14 +373,17 @@ static void check_expression(OnyxSemPassState* state, AstTyped* expr) {
             break;
 
         default:
+            retval = 1;
             DEBUG_HERE;
             break;
     }
+
+    return retval;
 }
 
-static void check_global(OnyxSemPassState* state, AstGlobal* global) {
+static b32 check_global(OnyxSemPassState* state, AstGlobal* global) {
     if (global->initial_value) {
-        check_expression(state, global->initial_value);
+        if (check_expression(state, global->initial_value)) return 1;
 
         if (global->base.type == NULL) {
             global->base.type = type_build_from_ast(state->node_allocator, global->base.type_node);
@@ -377,7 +397,7 @@ static void check_global(OnyxSemPassState* state, AstGlobal* global) {
                         global->base.token->text, global->base.token->length,
                         type_get_name(global->base.type),
                         type_get_name(global->initial_value->type));
-                return;
+                return 1;
             }
         } else {
             if (global->initial_value->type)
@@ -390,31 +410,36 @@ static void check_global(OnyxSemPassState* state, AstGlobal* global) {
                 ONYX_MESSAGE_TYPE_LITERAL,
                 global->base.token->pos,
                 "global variable with unknown type");
+        return 1;
     }
+
+    return 0;
 }
 
-static void check_statement(OnyxSemPassState* state, AstNode* stmt) {
+static b32 check_statement(OnyxSemPassState* state, AstNode* stmt) {
     switch (stmt->kind) {
-        case Ast_Kind_Assignment: check_assignment(state, (AstAssign *) stmt); break;
-        case Ast_Kind_Return:     check_return(state, (AstReturn *) stmt); break;
-        case Ast_Kind_If:         check_if(state, (AstIf *) stmt); break;
-        case Ast_Kind_While:      check_while(state, (AstWhile *) stmt); break;
-        case Ast_Kind_Call:       check_call(state, (AstCall *) stmt); break;
-        case Ast_Kind_Block:      check_block(state, (AstBlock *) stmt); break;
-
-        default: break;
+        case Ast_Kind_Assignment: return check_assignment(state, (AstAssign *) stmt);
+        case Ast_Kind_Return:     return check_return(state, (AstReturn *) stmt);
+        case Ast_Kind_If:         return check_if(state, (AstIf *) stmt);
+        case Ast_Kind_While:      return check_while(state, (AstWhile *) stmt);
+        case Ast_Kind_Call:       return check_call(state, (AstCall *) stmt);
+        case Ast_Kind_Block:      return check_block(state, (AstBlock *) stmt);
+
+        default: return 0;
     }
 }
 
-static void check_statement_chain(OnyxSemPassState* state, AstNode* start) {
+static b32 check_statement_chain(OnyxSemPassState* state, AstNode* start) {
     while (start) {
-        check_statement(state, start);
+        if (check_statement(state, start)) return 1;
         start = start->next;
     }
+
+    return 0;
 }
 
-static void check_block(OnyxSemPassState* state, AstBlock* block) {
-    check_statement_chain(state, block->body);
+static b32 check_block(OnyxSemPassState* state, AstBlock* block) {
+    if (check_statement_chain(state, block->body)) return 1;
 
     forll(AstLocal, local, block->locals->last_local, prev_local) {
         if (local->base.type == NULL) {
@@ -422,12 +447,14 @@ static void check_block(OnyxSemPassState* state, AstBlock* block) {
                     ONYX_MESSAGE_TYPE_UNRESOLVED_TYPE,
                     local->base.token->pos,
                     local->base.token->text, local->base.token->length);
-            return;
+            return 1;
         }
     }
+
+    return 0;
 }
 
-static void check_function(OnyxSemPassState* state, AstFunction* func) {
+static b32 check_function(OnyxSemPassState* state, AstFunction* func) {
     for (AstLocal *param = func->params; param != NULL; param = (AstLocal *) param->base.next) {
         if (param->base.type == NULL) {
             param->base.type = type_build_from_ast(state->node_allocator, param->base.type_node);
@@ -438,7 +465,7 @@ static void check_function(OnyxSemPassState* state, AstFunction* func) {
                     ONYX_MESSAGE_TYPE_LITERAL,
                     param->base.token->pos,
                     "function parameter types must be known");
-            return;
+            return 1;
         }
 
         if (param->base.type->Basic.size == 0) {
@@ -446,29 +473,80 @@ static void check_function(OnyxSemPassState* state, AstFunction* func) {
                     ONYX_MESSAGE_TYPE_LITERAL,
                     param->base.token->pos,
                     "function parameters must have non-void types");
-            return;
+            return 1;
         }
     }
 
+    // NOTE: Acutally the return type
     if (func->base.type == NULL) {
         func->base.type = type_build_from_ast(state->node_allocator, func->base.type_node);
     }
 
+    if ((func->base.flags & Ast_Flag_Exported) != 0) {
+        if ((func->base.flags & Ast_Flag_Foreign) != 0) {
+            onyx_message_add(state->msgs,
+                    ONYX_MESSAGE_TYPE_LITERAL,
+                    func->base.token->pos,
+                    "exporting a foreign function");
+            return 1;
+        }
+
+        if ((func->base.flags & Ast_Flag_Intrinsic) != 0) {
+            onyx_message_add(state->msgs,
+                    ONYX_MESSAGE_TYPE_LITERAL,
+                    func->base.token->pos,
+                    "exporting a intrinsic function");
+            return 1;
+        }
+
+        if ((func->base.flags & Ast_Flag_Inline) != 0) {
+            onyx_message_add(state->msgs,
+                    ONYX_MESSAGE_TYPE_LITERAL,
+                    func->base.token->pos,
+                    "exporting a inlined function");
+            return 1;
+        }
+    }
+
     state->expected_return_type = func->base.type;
     if (func->body) {
-        check_block(state, func->body);
+        return check_block(state, func->body);
+    }
+
+    return 0;
+}
+
+static b32 check_node(OnyxSemPassState* state, AstNode* node) {
+    switch (node->kind) {
+        case Ast_Kind_Function: return check_function(state, (AstFunction *) node);
+        case Ast_Kind_Block: return check_block(state, (AstBlock *) node);
+        case Ast_Kind_Assignment: return check_assignment(state, (AstAssign *) node);
+        case Ast_Kind_Return: return check_return(state, (AstReturn *) node);
+        case Ast_Kind_If: return check_if(state, (AstIf *) node);
+        case Ast_Kind_While: return check_while(state, (AstWhile *) node);
+        case Ast_Kind_Call: return check_call(state, (AstCall *) node);
+        case Ast_Kind_Binary_Op: return check_binaryop(state, (AstBinaryOp *) node);
+        default: return check_expression(state, (AstTyped *) node);
     }
 }
 
 void onyx_type_check(OnyxSemPassState* state, OnyxProgram* program) {
 
-    bh_arr_each(AstForeign *, foreign, program->foreigns)
-        if ((*foreign)->import->kind == Ast_Kind_Function)
-            check_function(state, (AstFunction *) (*foreign)->import);
+    // bh_arr_each(AstForeign *, foreign, program->foreigns)
+    //     if ((*foreign)->import->kind == Ast_Kind_Function)
+    //         check_function(state, (AstFunction *) (*foreign)->import);
 
-    bh_arr_each(AstGlobal *, global, program->globals)
-        check_global(state, *global);
+    // bh_arr_each(AstGlobal *, global, program->globals)
+    //     check_global(state, *global);
 
-    bh_arr_each(AstFunction *, function, program->functions)
-        check_function(state, *function);
+    // bh_arr_each(AstFunction *, function, program->functions)
+    //     check_function(state, *function);
+
+    bh_arr_each(AstNode *, node, program->nodes_to_process) {
+        check_node(state, *node);
+
+        if ((*node)->kind == Ast_Kind_Function) {
+            bh_arr_push(program->functions, (AstFunction *) *node);
+        }
+    }
 }
index 8368a011f53f9dcc8501b38cc092808fd15c218c..6987e51babd5d39296b85e1853b438ce68211ec5 100644 (file)
@@ -129,12 +129,12 @@ OnyxToken* onyx_get_token(OnyxTokenizer* tokenizer) {
     }
 
     LITERAL_TOKEN("struct",     1, Token_Type_Keyword_Struct);
-    LITERAL_TOKEN("export",     1, Token_Type_Keyword_Export);
+//     LITERAL_TOKEN("export",     1, Token_Type_Keyword_Export);
     LITERAL_TOKEN("use",        1, Token_Type_Keyword_Use);
     LITERAL_TOKEN("if",         1, Token_Type_Keyword_If);
     LITERAL_TOKEN("elseif",     1, Token_Type_Keyword_Elseif);
     LITERAL_TOKEN("else",       1, Token_Type_Keyword_Else);
-    LITERAL_TOKEN("foreign",    1, Token_Type_Keyword_Foreign);
+    // LITERAL_TOKEN("foreign",    1, Token_Type_Keyword_Foreign);
     LITERAL_TOKEN("return",     1, Token_Type_Keyword_Return);
     LITERAL_TOKEN("proc",       1, Token_Type_Keyword_Proc);
     LITERAL_TOKEN("as",         1, Token_Type_Keyword_Cast);
index 3a0113ad1f5de5502f00834bc3c4d414521a6e0f..c99608b532a41a51cc33cf846ae9eac5a7bbb232 100644 (file)
@@ -27,19 +27,20 @@ static void parser_next_token(OnyxParser* parser);
 static void parser_prev_token(OnyxParser* parser);
 static b32 is_terminating_token(TokenType token_type);
 static OnyxToken* expect(OnyxParser* parser, TokenType token_type);
-static AstNumLit* parse_numeric_literal(OnyxParser* parser);
-static AstTyped* parse_factor(OnyxParser* parser);
-static AstTyped* parse_expression(OnyxParser* parser);
-static AstIf* parse_if_stmt(OnyxParser* parser);
-static AstWhile* parse_while_stmt(OnyxParser* parser);
-static b32 parse_symbol_statement(OnyxParser* parser, AstNode** ret);
-static AstReturn* parse_return_statement(OnyxParser* parser);
-static AstBlock* parse_block(OnyxParser* parser);
-static AstNode* parse_statement(OnyxParser* parser);
-static AstType* parse_type(OnyxParser* parser);
-static AstLocal* parse_function_params(OnyxParser* parser);
+
+static AstNumLit*   parse_numeric_literal(OnyxParser* parser);
+static AstTyped*    parse_factor(OnyxParser* parser);
+static AstTyped*    parse_expression(OnyxParser* parser);
+static AstIf*       parse_if_stmt(OnyxParser* parser);
+static AstWhile*    parse_while_stmt(OnyxParser* parser);
+static b32          parse_symbol_statement(OnyxParser* parser, AstNode** ret);
+static AstReturn*   parse_return_statement(OnyxParser* parser);
+static AstBlock*    parse_block(OnyxParser* parser);
+static AstNode*     parse_statement(OnyxParser* parser);
+static AstType*     parse_type(OnyxParser* parser);
+static AstLocal*    parse_function_params(OnyxParser* parser);
 static AstFunction* parse_function_definition(OnyxParser* parser);
-static AstNode* parse_top_level_statement(OnyxParser* parser);
+static AstNode*     parse_top_level_statement(OnyxParser* parser);
 
 static void parser_next_token(OnyxParser* parser) {
     parser->prev_token = parser->curr_token;
@@ -236,6 +237,16 @@ static AstTyped* parse_factor(OnyxParser* parser) {
                 break;
             }
 
+        case Token_Type_Keyword_Proc:
+            {
+                AstFunction* func_node = parse_function_definition(parser);
+
+                bh_arr_push(parser->results.nodes_to_process, (AstNode *) func_node);
+
+                retval = (AstTyped *) func_node;
+                break;
+            }
+
         default:
             onyx_message_add(parser->msgs,
                     ONYX_MESSAGE_TYPE_UNEXPECTED_TOKEN,
@@ -736,6 +747,26 @@ static AstFunction* parse_function_definition(OnyxParser* parser) {
             func_def->base.flags |= Ast_Flag_Inline;
         }
 
+        else if (parse_possible_directive(parser, "foreign")) {
+            func_def->foreign_module = expect(parser, Token_Type_Literal_String);
+            func_def->foreign_name   = expect(parser, Token_Type_Literal_String);
+
+            func_def->base.flags |= Ast_Flag_Foreign;
+        }
+
+        else if (parse_possible_directive(parser, "export")) {
+            func_def->base.flags |= Ast_Flag_Exported;
+
+            if (parser->curr_token->type == Token_Type_Literal_String) {
+                OnyxToken* str_token = expect(parser, Token_Type_Literal_String);
+                func_def->exported_name =
+                    bh_aprintf(global_heap_allocator,
+                            "%b",
+                            str_token->text,
+                            str_token->length);
+            }
+        }
+
         else {
             OnyxToken* directive_token = expect(parser, '#');
             OnyxToken* symbol_token = expect(parser, Token_Type_Symbol);
@@ -764,50 +795,52 @@ static AstFunction* parse_function_definition(OnyxParser* parser) {
     return func_def;
 }
 
-static AstNode* parse_foreign(OnyxParser* parser) {
-    expect(parser, Token_Type_Keyword_Foreign);
-
-    AstForeign* foreign = make_node(AstForeign, Ast_Kind_Foreign);
-    foreign->mod_token = expect(parser, Token_Type_Literal_String);
-    foreign->name_token = expect(parser, Token_Type_Literal_String);
-
-    if (parser->curr_token->type == Token_Type_Keyword_Proc) {
-        foreign->import = (AstNode *) parse_function_definition(parser);
-
-    } else {
-        AstType* type = parse_type(parser);
-
-        AstGlobal* global = make_node(AstGlobal, Ast_Kind_Global);
-        global->base.type_node = type;
-        global->base.flags |= Ast_Flag_Lval;
-
-        foreign->import = (AstNode *) global;
-    }
-
-    return (AstNode *) foreign;
-}
-
-static AstNode* parse_top_level_constant_symbol(OnyxParser* parser) {
-    if (parser->curr_token->type == Token_Type_Keyword_Proc) {
-        return (AstNode *) parse_function_definition(parser);
-
-    } else if (parser->curr_token->type == Token_Type_Keyword_Struct) {
-        // Handle struct case
-        assert(0);
-
-    } else if (parser->curr_token->type == Token_Type_Keyword_Foreign) {
-        return (AstNode *) parse_foreign(parser);
-
-    } else {
-        // Global constant with initial value
-        AstGlobal* global = make_node(AstGlobal, Ast_Kind_Global);
-        global->initial_value = parse_expression(parser);
-        global->base.flags |= Ast_Flag_Const;
-        global->base.flags |= Ast_Flag_Lval;
-        global->base.flags |= Ast_Flag_Comptime;
-
-        return (AstNode *) global;
-    }
+// static AstNode* parse_foreign(OnyxParser* parser) {
+//     expect(parser, Token_Type_Keyword_Foreign);
+//
+//     AstForeign* foreign = make_node(AstForeign, Ast_Kind_Foreign);
+//     foreign->mod_token = expect(parser, Token_Type_Literal_String);
+//     foreign->name_token = expect(parser, Token_Type_Literal_String);
+//
+//     if (parser->curr_token->type == Token_Type_Keyword_Proc) {
+//         foreign->import = (AstNode *) parse_function_definition(parser);
+//
+//     } else {
+//         AstType* type = parse_type(parser);
+//
+//         AstGlobal* global = make_node(AstGlobal, Ast_Kind_Global);
+//         global->base.type_node = type;
+//         global->base.flags |= Ast_Flag_Lval;
+//
+//         foreign->import = (AstNode *) global;
+//     }
+//
+//     return (AstNode *) foreign;
+// }
+
+static AstTyped* parse_top_level_constant_symbol(OnyxParser* parser) {
+//     if (parser->curr_token->type == Token_Type_Keyword_Proc) {
+//        return (AstNode *) parse_function_definition(parser);
+//
+//    } else if (parser->curr_token->type == Token_Type_Keyword_Struct) {
+//        // Handle struct case
+//        assert(0);
+//
+//    } else if (parser->curr_token->type == Token_Type_Keyword_Foreign) {
+//        return (AstNode *) parse_foreign(parser);
+//
+//    } else {
+//        // Global constant with initial value
+//        AstGlobal* global = make_node(AstGlobal, Ast_Kind_Global);
+//        global->initial_value = parse_expression(parser);
+//        global->base.flags |= Ast_Flag_Const;
+//        global->base.flags |= Ast_Flag_Lval;
+//        global->base.flags |= Ast_Flag_Comptime;
+//
+//        return (AstNode *) global;
+//    }
+
+    return parse_expression(parser);
 }
 
 static AstNode* parse_top_level_statement(OnyxParser* parser) {
@@ -821,75 +854,28 @@ static AstNode* parse_top_level_statement(OnyxParser* parser) {
                 return (AstNode *) use_node;
             }
 
-        case Token_Type_Keyword_Export:
-            {
-                expect(parser, Token_Type_Keyword_Export);
-                if (parser->curr_token->type != Token_Type_Symbol) {
-                    onyx_message_add(parser->msgs,
-                            ONYX_MESSAGE_TYPE_EXPECTED_TOKEN,
-                            parser->curr_token->pos,
-                            onyx_get_token_type_name(Token_Type_Symbol),
-                            onyx_get_token_type_name(parser->curr_token->type));
-                    break;
-                }
-
-                AstNode* top_level_decl = parse_top_level_statement(parser);
-                top_level_decl->flags |= Ast_Flag_Exported;
-                return top_level_decl;
-            }
-
         case Token_Type_Symbol:
             {
                 OnyxToken* symbol = parser->curr_token;
                 parser_next_token(parser);
 
+                expect(parser, ':');
                 expect(parser, ':');
 
-                AstType* type = NULL;
-
-                if (parser->curr_token->type == Token_Type_Symbol) {
-                    type = parse_type(parser);
-                }
-
-                if (parser->curr_token->type == ':') {
-                    parser_next_token(parser);
-
-                    AstNode* node = parse_top_level_constant_symbol(parser);
-
-                    if (node->kind == Ast_Kind_Global) {
-                        ((AstGlobal *) node)->base.type_node = type;
-                    }
-
-                    if (node->kind == Ast_Kind_Foreign) {
-                        ((AstForeign *) node)->import->token = symbol;
-
-                    } else {
-                        node->token = symbol;
-                    }
-
-                    return node;
-
-                } else if (parser->curr_token->type == '=') {
-                    parser_next_token(parser);
-
-                    AstGlobal* global = make_node(AstGlobal, Ast_Kind_Global);
-                    global->base.token = symbol;
-                    global->base.flags |= Ast_Flag_Lval;
-                    global->initial_value = parse_expression(parser);
-                    global->base.type_node = type;
-
-                    return (AstNode *) global;
+                AstTyped* node = parse_top_level_constant_symbol(parser);
 
+                if (node->kind == Ast_Kind_Function) {
+                    node->token = symbol;
                 } else {
-                    onyx_token_null_toggle(parser->curr_token);
-                    onyx_message_add(parser->msgs,
-                            ONYX_MESSAGE_TYPE_UNEXPECTED_TOKEN,
-                            parser->curr_token->pos,
-                            parser->curr_token->text);
-                    onyx_token_null_toggle(parser->curr_token);
+                    // HACK
+                    bh_arr_push(parser->results.nodes_to_process, (AstNode *) node);
                 }
 
-                return &error_node;
+                AstBinding* binding = make_node(AstBinding, Ast_Kind_Binding);
+                binding->base.token = symbol;
+                binding->node = (AstNode *) node;
+
+                return (AstNode *) binding;
             }
 
         default: break;
@@ -919,28 +905,44 @@ OnyxParser onyx_parser_create(bh_allocator alloc, OnyxTokenizer *tokenizer, Onyx
     parser.allocator = alloc;
     parser.tokenizer = tokenizer;
     parser.curr_token = tokenizer->tokens;
-    parser.prev_token = NULL; parser.msgs = msgs;
+    parser.prev_token = NULL;
+    parser.msgs = msgs;
+
+    parser.results = (ParseResults) {
+        .allocator = global_heap_allocator,
+
+        .uses = NULL,
+        .bindings = NULL,
+        .nodes_to_process = NULL,
+    };
+
+    bh_arr_new(parser.results.allocator, parser.results.uses, 4);
+    bh_arr_new(parser.results.allocator, parser.results.bindings, 4);
+    bh_arr_new(parser.results.allocator, parser.results.nodes_to_process, 4);
+
     return parser;
 }
 
 void onyx_parser_free(OnyxParser* parser) {
 }
 
-bh_arr(AstNode *) onyx_parse(OnyxParser *parser) {
-    bh_arr(AstNode *) top_level_nodes = NULL;
-    bh_arr_new(global_heap_allocator, top_level_nodes, 4);
-
+ParseResults onyx_parse(OnyxParser *parser) {
     while (parser->curr_token->type != Token_Type_End_Stream) {
         AstNode* curr_stmt = parse_top_level_statement(parser);
 
-        // Building a linked list of statements down the "next" chain
         if (curr_stmt != NULL && curr_stmt != &error_node) {
             while (curr_stmt != NULL) {
-                bh_arr_push(top_level_nodes, curr_stmt);
+
+                switch (curr_stmt->kind) {
+                    case Ast_Kind_Use:     bh_arr_push(parser->results.uses, (AstUse *) curr_stmt); break;
+                    case Ast_Kind_Binding: bh_arr_push(parser->results.bindings, (AstBinding *) curr_stmt); break;
+                    default: assert(("Invalid top level node", 0));
+                }
+
                 curr_stmt = curr_stmt->next;
             }
         }
     }
 
-    return top_level_nodes;
+    return parser->results;
 }
index 7f2b4bc85fb602f05387ee13a7831b7fa8d42d80..9c8d225c30ff5031577651a4bbd40fd27f727913 100644 (file)
@@ -23,61 +23,61 @@ 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(OnyxProgram* program) {
-    bh_arr(AstBlock*) traversal_queue = NULL;
-    bh_arr_new(global_scratch_allocator, traversal_queue, 4);
-    bh_arr_set_length(traversal_queue, 0);
-
-    bh_arr_each(AstFunction *, func, program->functions) {
-        AstLocalGroup* top_locals = (*func)->body->locals;
-
-        bh_arr_push(traversal_queue, (*func)->body);
-        while (!bh_arr_is_empty(traversal_queue)) {
-            AstBlock* block = traversal_queue[0];
-
-            if (block->base.kind == Ast_Kind_If) {
-                AstIf* if_node = (AstIf *) block;
-                if (if_node->true_block.as_block != NULL)
-                    bh_arr_push(traversal_queue, if_node->true_block.as_block);
-
-                if (if_node->false_block.as_block != NULL)
-                    bh_arr_push(traversal_queue, if_node->false_block.as_block);
-
-            } else {
-
-                if (block->locals != top_locals && block->locals->last_local != NULL) {
-                    AstLocal* last_local = block->locals->last_local;
-                    while (last_local && last_local->prev_local != NULL) last_local = last_local->prev_local;
-
-                    last_local->prev_local = top_locals->last_local;
-                    top_locals->last_local = block->locals->last_local;
-                    block->locals->last_local = NULL;
-                }
-
-                AstNode* walker = block->body;
-                while (walker) {
-                    if (walker->kind == Ast_Kind_Block) {
-                        bh_arr_push(traversal_queue, (AstBlock *) walker);
-
-                    } else if (walker->kind == Ast_Kind_While) {
-                        bh_arr_push(traversal_queue, ((AstWhile *) walker)->body);
-
-                    } else if (walker->kind == Ast_Kind_If) {
-                        if (((AstIf *) walker)->true_block.as_block != NULL)
-                            bh_arr_push(traversal_queue, ((AstIf *) walker)->true_block.as_block);
-
-                        if (((AstIf *) walker)->false_block.as_block != NULL)
-                            bh_arr_push(traversal_queue, ((AstIf *) walker)->false_block.as_block);
-                    }
-
-                    walker = walker->next;
-                }
-            }
-
-            bh_arr_deleten(traversal_queue, 0, 1);
-        }
-    }
-}
+// static void collapse_scopes(OnyxProgram* program) {
+//     bh_arr(AstBlock*) traversal_queue = NULL;
+//     bh_arr_new(global_scratch_allocator, traversal_queue, 4);
+//     bh_arr_set_length(traversal_queue, 0);
+//
+//     bh_arr_each(AstFunction *, func, program->functions) {
+//         AstLocalGroup* top_locals = (*func)->body->locals;
+//
+//         bh_arr_push(traversal_queue, (*func)->body);
+//         while (!bh_arr_is_empty(traversal_queue)) {
+//             AstBlock* block = traversal_queue[0];
+//
+//             if (block->base.kind == Ast_Kind_If) {
+//                 AstIf* if_node = (AstIf *) block;
+//                 if (if_node->true_block.as_block != NULL)
+//                     bh_arr_push(traversal_queue, if_node->true_block.as_block);
+//
+//                 if (if_node->false_block.as_block != NULL)
+//                     bh_arr_push(traversal_queue, if_node->false_block.as_block);
+//
+//             } else {
+//
+//                 if (block->locals != top_locals && block->locals->last_local != NULL) {
+//                     AstLocal* last_local = block->locals->last_local;
+//                     while (last_local && last_local->prev_local != NULL) last_local = last_local->prev_local;
+//
+//                     last_local->prev_local = top_locals->last_local;
+//                     top_locals->last_local = block->locals->last_local;
+//                     block->locals->last_local = NULL;
+//                 }
+//
+//                 AstNode* walker = block->body;
+//                 while (walker) {
+//                     if (walker->kind == Ast_Kind_Block) {
+//                         bh_arr_push(traversal_queue, (AstBlock *) walker);
+//
+//                     } else if (walker->kind == Ast_Kind_While) {
+//                         bh_arr_push(traversal_queue, ((AstWhile *) walker)->body);
+//
+//                     } else if (walker->kind == Ast_Kind_If) {
+//                         if (((AstIf *) walker)->true_block.as_block != NULL)
+//                             bh_arr_push(traversal_queue, ((AstIf *) walker)->true_block.as_block);
+//
+//                         if (((AstIf *) walker)->false_block.as_block != NULL)
+//                             bh_arr_push(traversal_queue, ((AstIf *) walker)->false_block.as_block);
+//                     }
+//
+//                     walker = walker->next;
+//                 }
+//             }
+//
+//             bh_arr_deleten(traversal_queue, 0, 1);
+//         }
+//     }
+// }
 
 void onyx_sempass(OnyxSemPassState* state, OnyxProgram* program) {
     onyx_resolve_symbols(state, program);
@@ -86,5 +86,5 @@ void onyx_sempass(OnyxSemPassState* state, OnyxProgram* program) {
     onyx_type_check(state, program);
     if (onyx_message_has_errors(state->msgs)) return;
 
-    collapse_scopes(program);
+    // collapse_scopes(program);
 }
index 1460832f5b8427cb36446e1ef9c2d634ef9b27bc..c363c3962700a491defe0674cd4c2f871d87c9f9 100644 (file)
@@ -1,13 +1,14 @@
 #define BH_DEBUG
 #include "onyxsempass.h"
 
-static void symbol_introduce(OnyxSemPassState* state, AstNode* symbol);
+static void symbol_introduce(OnyxSemPassState* state, OnyxToken* tkn, AstNode* symbol);
 static void symbol_basic_type_introduce(OnyxSemPassState* state, AstBasicType* basic_type);
-static b32 symbol_unique_introduce(OnyxSemPassState* state, AstNode* symbol);
-static void symbol_remove(OnyxSemPassState* state, AstNode* symbol);
-static AstNode* symbol_resolve(OnyxSemPassState* state, AstNode* symbol);
+static b32 symbol_unique_introduce(OnyxSemPassState* state, OnyxToken* tkn, AstNode* symbol);
+static void symbol_remove(OnyxSemPassState* state, OnyxToken* tkn);
+static AstNode* symbol_resolve(OnyxSemPassState* state, OnyxToken* tkn);
 static void local_group_enter(OnyxSemPassState* state, AstLocalGroup* local_group);
 static void local_group_leave(OnyxSemPassState* state);
+
 static void symres_local(OnyxSemPassState* state, AstLocal** local);
 static void symres_call(OnyxSemPassState* state, AstCall* call);
 static void symres_expression(OnyxSemPassState* state, AstTyped** expr);
@@ -16,23 +17,23 @@ static void symres_return(OnyxSemPassState* state, AstReturn* ret);
 static void symres_if(OnyxSemPassState* state, AstIf* ifnode);
 static void symres_while(OnyxSemPassState* state, AstWhile* whilenode);
 static void symres_statement_chain(OnyxSemPassState* state, AstNode* walker, AstNode** trailer);
-static b32 symres_statement(OnyxSemPassState* state, AstNode* stmt);
+static b32  symres_statement(OnyxSemPassState* state, AstNode* stmt);
 static void symres_block(OnyxSemPassState* state, AstBlock* block);
 static void symres_function(OnyxSemPassState* state, AstFunction* func);
 static AstType* symres_type(OnyxSemPassState* state, AstType* type);
 
-static void symbol_introduce(OnyxSemPassState* state, AstNode* symbol) {
-    onyx_token_null_toggle(symbol->token);
+static void symbol_introduce(OnyxSemPassState* state, OnyxToken* tkn, AstNode* symbol) {
+    onyx_token_null_toggle(tkn);
 
     SemPassSymbol* sp_sym = (SemPassSymbol *) bh_alloc_item(state->allocator, SemPassSymbol);
     sp_sym->node = symbol;
     sp_sym->shadowed = NULL;
 
-    if (bh_table_has(SemPassSymbol *, state->symbols, symbol->token->text)) {
-        sp_sym->shadowed = bh_table_get(SemPassSymbol *, state->symbols, symbol->token->text);
+    if (bh_table_has(SemPassSymbol *, state->symbols, tkn->text)) {
+        sp_sym->shadowed = bh_table_get(SemPassSymbol *, state->symbols, tkn->text);
     }
 
-    bh_table_put(SemPassSymbol *, state->symbols, symbol->token->text, sp_sym);
+    bh_table_put(SemPassSymbol *, state->symbols, tkn->text, sp_sym);
 
     if (symbol->kind == Ast_Kind_Local) {
         AstLocal* local = (AstLocal *) symbol;
@@ -40,39 +41,39 @@ static void symbol_introduce(OnyxSemPassState* state, AstNode* symbol) {
         state->curr_local_group->last_local = local;
     }
 
-    onyx_token_null_toggle(symbol->token);
+    onyx_token_null_toggle(tkn);
 }
 
-static void symbol_remove(OnyxSemPassState* state, AstNode* symbol) {
-    onyx_token_null_toggle(symbol->token);
+static void symbol_remove(OnyxSemPassState* state, OnyxToken* tkn) {
+    onyx_token_null_toggle(tkn);
 
-    SemPassSymbol* sp_sym = bh_table_get(SemPassSymbol *, state->symbols, symbol->token->text);
+    SemPassSymbol* sp_sym = bh_table_get(SemPassSymbol *, state->symbols, tkn->text);
 
     if (sp_sym->shadowed) {
-        bh_table_put(SemPassSymbol *, state->symbols, symbol->token->text, sp_sym->shadowed);
+        bh_table_put(SemPassSymbol *, state->symbols, tkn->text, sp_sym->shadowed);
     } else {
-        bh_table_delete(SemPassSymbol *, state->symbols, symbol->token->text);
+        bh_table_delete(SemPassSymbol *, state->symbols, tkn->text);
     }
 
-    onyx_token_null_toggle(symbol->token);
+    onyx_token_null_toggle(tkn);
 }
 
-static AstNode* symbol_resolve(OnyxSemPassState* state, AstNode* symbol) {
-    onyx_token_null_toggle(symbol->token);
+static AstNode* symbol_resolve(OnyxSemPassState* state, OnyxToken* tkn) {
+    onyx_token_null_toggle(tkn);
 
-    if (!bh_table_has(SemPassSymbol *, state->symbols, symbol->token->text)) {
+    if (!bh_table_has(SemPassSymbol *, state->symbols, tkn->text)) {
         onyx_message_add(state->msgs,
                 ONYX_MESSAGE_TYPE_UNKNOWN_SYMBOL,
-                symbol->token->pos,
-                symbol->token->text);
+                tkn->pos,
+                tkn->text);
 
-        onyx_token_null_toggle(symbol->token);
-        return symbol;
+        onyx_token_null_toggle(tkn);
+        return NULL;
     }
 
-    SemPassSymbol* sp_sym = bh_table_get(SemPassSymbol *, state->symbols, symbol->token->text);
+    SemPassSymbol* sp_sym = bh_table_get(SemPassSymbol *, state->symbols, tkn->text);
 
-    onyx_token_null_toggle(symbol->token);
+    onyx_token_null_toggle(tkn);
     return sp_sym->node;
 }
 
@@ -85,7 +86,7 @@ static void local_group_leave(OnyxSemPassState* state) {
     assert(state->curr_local_group != NULL);
 
     for (AstLocal *walker = state->curr_local_group->last_local; walker != NULL; walker = walker->prev_local) {
-        symbol_remove(state, (AstNode *) walker);
+        symbol_remove(state, walker->base.token);
     }
 
     state->curr_local_group = state->curr_local_group->prev_group;
@@ -98,27 +99,27 @@ static void symbol_basic_type_introduce(OnyxSemPassState* state, AstBasicType* b
     bh_table_put(SemPassSymbol *, state->symbols, basic_type->base.name, sp_sym);
 }
 
-static b32 symbol_unique_introduce(OnyxSemPassState* state, AstNode* symbol) {
-    onyx_token_null_toggle(symbol->token);
+static b32 symbol_unique_introduce(OnyxSemPassState* state, OnyxToken* tkn, AstNode* symbol) {
+    onyx_token_null_toggle(tkn);
 
     // NOTE: If the function hasn't already been defined
-    if (!bh_table_has(SemPassSymbol *, state->symbols, symbol->token->text)) {
+    if (!bh_table_has(SemPassSymbol *, state->symbols, tkn->text)) {
         SemPassSymbol* sp_sym = bh_alloc_item(state->allocator, SemPassSymbol);
         sp_sym->node = symbol;
         sp_sym->shadowed = NULL;
-        bh_table_put(SemPassSymbol *, state->symbols, symbol->token->text, sp_sym);
+        bh_table_put(SemPassSymbol *, state->symbols, tkn->text, sp_sym);
     } else {
         onyx_message_add(state->msgs,
                 ONYX_MESSAGE_TYPE_CONFLICTING_GLOBALS,
-                symbol->token->pos,
-                symbol->token->text);
+                tkn->pos,
+                tkn->text);
 
         // NOTE: I really wish C had defer...
-        onyx_token_null_toggle(symbol->token);
+        onyx_token_null_toggle(tkn);
         return 0;
     }
 
-    onyx_token_null_toggle(symbol->token);
+    onyx_token_null_toggle(tkn);
     return 1;
 }
 
@@ -126,7 +127,7 @@ static AstType* symres_type(OnyxSemPassState* state, AstType* type) {
     if (type == NULL) return NULL;
 
     if (type->kind == Ast_Kind_Symbol) {
-        return (AstType *) symbol_resolve(state, (AstNode *) type);
+        return (AstType *) symbol_resolve(state, ((AstNode *) type)->token);
     }
 
     // NOTE: Already resolved
@@ -143,11 +144,11 @@ static AstType* symres_type(OnyxSemPassState* state, AstType* type) {
 
 static void symres_local(OnyxSemPassState* state, AstLocal** local) {
     (*local)->base.type_node = symres_type(state, (*local)->base.type_node);
-    symbol_introduce(state, (AstNode *) *local);
+    symbol_introduce(state, (*local)->base.token, (AstNode *) *local);
 }
 
 static void symres_call(OnyxSemPassState* state, AstCall* call) {
-    AstNode* callee = symbol_resolve(state, call->callee);
+    AstNode* callee = symbol_resolve(state, call->callee->token);
     if (callee) call->callee = callee;
     else DEBUG_HERE;
 
@@ -178,7 +179,7 @@ static void symres_expression(OnyxSemPassState* state, AstTyped** expr) {
         case Ast_Kind_Block: symres_block(state, (AstBlock *) *expr); break;
 
         case Ast_Kind_Symbol:
-            *expr = (AstTyped *) symbol_resolve(state, (AstNode *) *expr);
+            *expr = (AstTyped *) symbol_resolve(state, ((AstNode *) *expr)->token);
             break;
 
         // NOTE: This is a good case, since it means the symbol is already resolved
@@ -195,7 +196,7 @@ static void symres_expression(OnyxSemPassState* state, AstTyped** expr) {
 }
 
 static void symres_assignment(OnyxSemPassState* state, AstAssign* assign) {
-    AstTyped* lval = (AstTyped *) symbol_resolve(state, (AstNode *) assign->lval);
+    AstTyped* lval = (AstTyped *) symbol_resolve(state, assign->lval->token);
     if (lval == NULL) return;
     assign->lval = lval;
 
@@ -277,7 +278,7 @@ static void symres_function(OnyxSemPassState* state, AstFunction* func) {
     for (AstLocal *param = func->params; param != NULL; param = (AstLocal *) param->base.next) {
         param->base.type_node = symres_type(state, param->base.type_node);
 
-        symbol_introduce(state, (AstNode *) param);
+        symbol_introduce(state, param->base.token, (AstNode *) param);
     }
 
     if (func->base.type_node != NULL) {
@@ -289,7 +290,27 @@ static void symres_function(OnyxSemPassState* state, AstFunction* func) {
     symres_block(state, func->body);
 
     for (AstLocal *param = func->params; param != NULL; param = (AstLocal *) param->base.next) {
-        symbol_remove(state, (AstNode *) param);
+        symbol_remove(state, param->base.token);
+    }
+}
+
+static void symres_top_node(OnyxSemPassState* state, AstNode** node) {
+    switch ((*node)->kind) {
+        case Ast_Kind_Call:
+        case Ast_Kind_Unary_Op:
+        case Ast_Kind_Binary_Op:
+        case Ast_Kind_Literal:
+        case Ast_Kind_Symbol:
+             symres_expression(state, (AstTyped **) node);
+             break;
+
+        case Ast_Kind_Function:
+             symres_function(state, (AstFunction *) *node);
+             break;
+
+        default:
+             DEBUG_HERE;
+             break;
     }
 }
 
@@ -311,26 +332,29 @@ void onyx_resolve_symbols(OnyxSemPassState* state, OnyxProgram* program) {
     symbol_basic_type_introduce(state, &basic_type_rawptr);
 
     // NOTE: Introduce all global symbols
-    bh_arr_each(AstGlobal *, global, program->globals)
-        if (!symbol_unique_introduce(state, (AstNode *) *global)) return;
+    // bh_arr_each(AstGlobal *, global, program->globals)
+    //     if (!symbol_unique_introduce(state, (AstNode *) *global)) return;
 
-    bh_arr_each(AstFunction *, function, program->functions)
-        if (!symbol_unique_introduce(state, (AstNode *) *function)) return;
+    // bh_arr_each(AstFunction *, function, program->functions)
+    //     if (!symbol_unique_introduce(state, (AstNode *) *function)) return;
 
-    bh_arr_each(AstForeign *, foreign, program->foreigns) {
-        AstKind import_kind = (*foreign)->import->kind;
+    // bh_arr_each(AstForeign *, foreign, program->foreigns) {
+    //     AstKind import_kind = (*foreign)->import->kind;
 
-        if (import_kind == Ast_Kind_Function || import_kind == Ast_Kind_Global)
-            if (!symbol_unique_introduce(state, (*foreign)->import)) return;
-    }
+    //     if (import_kind == Ast_Kind_Function || import_kind == Ast_Kind_Global)
+    //         if (!symbol_unique_introduce(state, (*foreign)->import)) return;
+    // }
 
-    // NOTE: Then, resolve all symbols in all functions
-    bh_arr_each(AstForeign *, foreign, program->foreigns) {
-        if ((*foreign)->import->kind == Ast_Kind_Function) {
-            symres_function(state, (AstFunction *) (*foreign)->import);
-        }
-    }
+    // // NOTE: Then, resolve all symbols in all functions
+    // bh_arr_each(AstForeign *, foreign, program->foreigns) {
+    //     if ((*foreign)->import->kind == Ast_Kind_Function) {
+    //         symres_function(state, (AstFunction *) (*foreign)->import);
+    //     }
+    // }
+
+    bh_arr_each(AstBinding *, binding, program->top_level_bindings)
+        if (!symbol_unique_introduce(state, (*binding)->base.token, (*binding)->node)) return;
 
-    bh_arr_each(AstFunction *, function, program->functions)
-        symres_function(state, *function);
+    bh_arr_each(AstNode *, node, program->nodes_to_process)
+        symres_top_node(state, node);
 }
index b98f5dd85abbd4e909e114d42442bfe6a20d50c4..26a384f33e78fc99a7e571a1dac54e0987452df6 100644 (file)
@@ -13,6 +13,7 @@ static const char* ast_node_names[] = {
     "PROGRAM",
     "USE",
 
+    "BINDING",
     "FUNCTION",
     "FOREIGN",
     "BLOCK",
@@ -24,7 +25,12 @@ static const char* ast_node_names[] = {
     "UN_OP",
     "BIN_OP",
 
+    "TYPE_START (BAD)"
     "TYPE",
+    "POINTER_TYPE",
+    "FUNCTION_TYPE",
+    "TYPE_END (BAD)"
+
     "LITERAL",
     "PARAM",
     "ARGUMENT",
index 7c81780845d06dba3845180c3270c3a7874d9bc5..b67b091e50157ef5465922c3102f9582f5f25455 100644 (file)
@@ -219,23 +219,24 @@ static WasmType onyx_type_to_wasm_type(Type* type) {
 
 #define WI(instr) bh_arr_push(code, ((WasmInstruction){ instr, 0x00 }));
 #define WID(instr, data) bh_arr_push(code, ((WasmInstruction){ instr, data }));
-
-static void compile_function_body(OnyxWasmModule* mod, bh_arr(WasmInstruction)* pcode, AstFunction* fd);
-static void compile_block(OnyxWasmModule* mod, bh_arr(WasmInstruction)* pcode, AstBlock* block);
-static void compile_statement(OnyxWasmModule* mod, bh_arr(WasmInstruction)* pcode, AstNode* stmt);
-static void compile_assign_lval(OnyxWasmModule* mod, bh_arr(WasmInstruction)* pcode, AstTyped* lval);
-static void compile_assignment(OnyxWasmModule* mod, bh_arr(WasmInstruction)* pcode, AstAssign* assign);
-static void compile_if(OnyxWasmModule* mod, bh_arr(WasmInstruction)* pcode, AstIf* if_node);
-static void compile_while(OnyxWasmModule* mod, bh_arr(WasmInstruction)* pcode, AstWhile* while_node);
-static void compile_binop(OnyxWasmModule* mod, bh_arr(WasmInstruction)* pcode, AstBinaryOp* binop);
-static void compile_unaryop(OnyxWasmModule* mod, bh_arr(WasmInstruction)* pcode, AstUnaryOp* unop);
-static void compile_call(OnyxWasmModule* mod, bh_arr(WasmInstruction)* pcode, AstCall* call);
-static void compile_intrinsic_call(OnyxWasmModule* mod, bh_arr(WasmInstruction)* pcode, AstIntrinsicCall* call);
-static void compile_expression(OnyxWasmModule* mod, bh_arr(WasmInstruction)* pcode, AstTyped* expr);
-static void compile_cast(OnyxWasmModule* mod, bh_arr(WasmInstruction)* pcode, AstUnaryOp* cast);
-static void compile_return(OnyxWasmModule* mod, bh_arr(WasmInstruction)* pcode, AstReturn* ret);
-
-static void compile_function_body(OnyxWasmModule* mod, bh_arr(WasmInstruction)* pcode, AstFunction* fd) {
+#define COMPILE_FUNC(kind, ...) static void compile_ ## kind (OnyxWasmModule* mod, bh_arr(WasmInstruction)* pcode, __VA_ARGS__)
+
+COMPILE_FUNC(function_body,  AstFunction* fd);
+COMPILE_FUNC(block,          AstBlock* block);
+COMPILE_FUNC(statement,      AstNode* stmt);
+COMPILE_FUNC(assign_lval,    AstTyped* lval);
+COMPILE_FUNC(assignment,     AstAssign* assign);
+COMPILE_FUNC(if,             AstIf* if_node);
+COMPILE_FUNC(while,          AstWhile* while_node);
+COMPILE_FUNC(binop,          AstBinaryOp* binop);
+COMPILE_FUNC(unaryop,        AstUnaryOp* unop);
+COMPILE_FUNC(call,           AstCall* call);
+COMPILE_FUNC(intrinsic_call, AstIntrinsicCall* call);
+COMPILE_FUNC(expression,     AstTyped* expr);
+COMPILE_FUNC(cast,           AstUnaryOp* cast);
+COMPILE_FUNC(return,         AstReturn* ret);
+
+COMPILE_FUNC(function_body, AstFunction* fd) {
     if (fd->body == NULL) return;
 
     bh_arr(WasmInstruction) code = *pcode;
@@ -249,7 +250,7 @@ static void compile_function_body(OnyxWasmModule* mod, bh_arr(WasmInstruction)*
     *pcode = code;
 }
 
-static void compile_block(OnyxWasmModule* mod, bh_arr(WasmInstruction)* pcode, AstBlock* block) {
+COMPILE_FUNC(block, AstBlock* block) {
     bh_arr(WasmInstruction) code = *pcode;
 
     bh_arr_push(mod->structured_jump_target, 1);
@@ -265,7 +266,7 @@ static void compile_block(OnyxWasmModule* mod, bh_arr(WasmInstruction)* pcode, A
     *pcode = code;
 }
 
-static void compile_structured_jump(OnyxWasmModule* mod, bh_arr(WasmInstruction)* pcode, b32 jump_backward) {
+COMPILE_FUNC(structured_jump, b32 jump_backward) {
     bh_arr(WasmInstruction) code = *pcode;
 
     i32 labelidx = 0;
@@ -291,7 +292,7 @@ static void compile_structured_jump(OnyxWasmModule* mod, bh_arr(WasmInstruction)
     *pcode = code;
 }
 
-static void compile_statement(OnyxWasmModule* mod, bh_arr(WasmInstruction)* pcode, AstNode* stmt) {
+COMPILE_FUNC(statement, AstNode* stmt) {
     bh_arr(WasmInstruction) code = *pcode;
 
     switch (stmt->kind) {
@@ -315,7 +316,7 @@ static void compile_statement(OnyxWasmModule* mod, bh_arr(WasmInstruction)* pcod
     *pcode = code;
 }
 
-static void compile_assign_lval(OnyxWasmModule* mod, bh_arr(WasmInstruction)* pcode, AstTyped* lval) {
+COMPILE_FUNC(assign_lval, AstTyped* lval) {
     bh_arr(WasmInstruction) code = *pcode;
 
     if (lval->kind == Ast_Kind_Local || lval->kind == Ast_Kind_Param) {
@@ -335,7 +336,7 @@ static void compile_assign_lval(OnyxWasmModule* mod, bh_arr(WasmInstruction)* pc
     *pcode = code;
 }
 
-static void compile_if(OnyxWasmModule* mod, bh_arr(WasmInstruction)* pcode, AstIf* if_node) {
+COMPILE_FUNC(if, AstIf* if_node) {
     bh_arr(WasmInstruction) code = *pcode;
 
     compile_expression(mod, &code, if_node->cond);
@@ -378,7 +379,7 @@ static void compile_if(OnyxWasmModule* mod, bh_arr(WasmInstruction)* pcode, AstI
     *pcode = code;
 }
 
-static void compile_while(OnyxWasmModule* mod, bh_arr(WasmInstruction)* pcode, AstWhile* while_node) {
+COMPILE_FUNC(while, AstWhile* while_node) {
     bh_arr(WasmInstruction) code = *pcode;
 
     WID(WI_BLOCK_START, 0x40);
@@ -406,7 +407,7 @@ static void compile_while(OnyxWasmModule* mod, bh_arr(WasmInstruction)* pcode, A
     *pcode = code;
 }
 
-static void compile_assignment(OnyxWasmModule* mod, bh_arr(WasmInstruction)* pcode, AstAssign* assign) {
+COMPILE_FUNC(assignment, AstAssign* assign) {
     bh_arr(WasmInstruction) code = *pcode;
 
     compile_expression(mod, &code, assign->expr);
@@ -433,7 +434,7 @@ static const WasmInstructionType binop_map[][4] = {
     /* GTE */ { WI_I32_GE_S,  WI_I64_GE_S,  WI_F32_GE,  WI_F64_GE },
 };
 
-static void compile_binop(OnyxWasmModule* mod, bh_arr(WasmInstruction)* pcode, AstBinaryOp* binop) {
+COMPILE_FUNC(binop, AstBinaryOp* binop) {
     bh_arr(WasmInstruction) code = *pcode;
 
     b32 is_sign_significant = 0;
@@ -480,7 +481,7 @@ static void compile_binop(OnyxWasmModule* mod, bh_arr(WasmInstruction)* pcode, A
     *pcode = code;
 }
 
-static void compile_unaryop(OnyxWasmModule* mod, bh_arr(WasmInstruction)* pcode, AstUnaryOp* unop) {
+COMPILE_FUNC(unaryop, AstUnaryOp* unop) {
     bh_arr(WasmInstruction) code = *pcode;
 
     switch (unop->operation) {
@@ -527,7 +528,7 @@ static void compile_unaryop(OnyxWasmModule* mod, bh_arr(WasmInstruction)* pcode,
     *pcode = code;
 }
 
-static void compile_call(OnyxWasmModule* mod, bh_arr(WasmInstruction)* pcode, AstCall* call) {
+COMPILE_FUNC(call, AstCall* call) {
     bh_arr(WasmInstruction) code = *pcode;
 
     for (AstArgument *arg = call->arguments;
@@ -542,7 +543,7 @@ static void compile_call(OnyxWasmModule* mod, bh_arr(WasmInstruction)* pcode, As
     *pcode = code;
 }
 
-static void compile_intrinsic_call(OnyxWasmModule* mod, bh_arr(WasmInstruction)* pcode, AstIntrinsicCall* call) {
+COMPILE_FUNC(intrinsic_call, AstIntrinsicCall* call) {
     bh_arr(WasmInstruction) code = *pcode;
 
     i32 place_arguments_normally = 1;
@@ -613,7 +614,7 @@ static void compile_intrinsic_call(OnyxWasmModule* mod, bh_arr(WasmInstruction)*
     *pcode = code;
 }
 
-static void compile_expression(OnyxWasmModule* mod, bh_arr(WasmInstruction)* pcode, AstTyped* expr) {
+COMPILE_FUNC(expression, AstTyped* expr) {
     bh_arr(WasmInstruction) code = *pcode;
 
     switch (expr->kind) {
@@ -696,7 +697,7 @@ static const WasmInstructionType cast_map[][6] = {
     /* F64 */ { WI_I32_FROM_F64_S, WI_I32_FROM_F64_U, WI_I64_FROM_F64_S, WI_I64_FROM_F64_U, WI_F32_FROM_F64,   WI_NOP,           },
 };
 
-static void compile_cast(OnyxWasmModule* mod, bh_arr(WasmInstruction)* pcode, AstUnaryOp* cast) {
+COMPILE_FUNC(cast, AstUnaryOp* cast) {
     bh_arr(WasmInstruction) code = *pcode;
 
     compile_expression(mod, &code, cast->expr);
@@ -739,7 +740,7 @@ static void compile_cast(OnyxWasmModule* mod, bh_arr(WasmInstruction)* pcode, As
     *pcode = code;
 }
 
-static void compile_return(OnyxWasmModule* mod, bh_arr(WasmInstruction)* pcode, AstReturn* ret) {
+COMPILE_FUNC(return, AstReturn* ret) {
     bh_arr(WasmInstruction) code = *pcode;
 
     if (ret->expr) {
@@ -799,6 +800,18 @@ static void compile_function(OnyxWasmModule* mod, AstFunction* fd) {
 
     i32 type_idx = generate_type_idx(mod, fd);
 
+    if (fd->base.flags & Ast_Flag_Foreign) {
+        WasmImport import = {
+            .kind = WASM_FOREIGN_FUNCTION,
+            .idx  = type_idx,
+            .mod  = fd->foreign_module,
+            .name = fd->foreign_name,
+        };
+
+        bh_arr_push(mod->imports, import);
+        return;
+    }
+
     WasmFunc wasm_func = {
         .type_idx = type_idx,
         .locals = {
@@ -979,36 +992,40 @@ OnyxWasmModule onyx_wasm_module_create(bh_allocator alloc, OnyxMessages* msgs) {
 void onyx_wasm_module_compile(OnyxWasmModule* module, OnyxProgram* program) {
 
     // NOTE: First, introduce all indicies for globals and functions
-    bh_arr_each(AstForeign *, foreign, program->foreigns) {
-        AstKind import_kind = (*foreign)->import->kind;
+    // bh_arr_each(AstForeign *, foreign, program->foreigns) {
+    //     AstKind import_kind = (*foreign)->import->kind;
 
-        if (import_kind == Ast_Kind_Function) {
-            module->next_func_idx++;
-            bh_imap_put(&module->func_map, (u64) (*foreign)->import, module->next_import_func_idx++);
-        }
-        else if (import_kind == Ast_Kind_Global) {
-            module->next_global_idx++;
-            bh_imap_put(&module->global_map, (u64) (*foreign)->import, module->next_import_global_idx++);
-        }
+    //     if (import_kind == Ast_Kind_Function) {
+    //         module->next_func_idx++;
+    //         bh_imap_put(&module->func_map, (u64) (*foreign)->import, module->next_import_func_idx++);
+    //     }
+    //     else if (import_kind == Ast_Kind_Global) {
+    //         module->next_global_idx++;
+    //         bh_imap_put(&module->global_map, (u64) (*foreign)->import, module->next_import_global_idx++);
+    //     }
 
-        compile_foreign(module, *foreign);
+    //     compile_foreign(module, *foreign);
+    // }
+
+    bh_arr_each(AstFunction *, function, program->functions) {
+        if ((*function)->base.flags & Ast_Flag_Foreign) {
+            bh_imap_put(&module->func_map, (u64) *function, module->next_func_idx++);
+        }
     }
 
     bh_arr_each(AstFunction *, function, program->functions) {
+        if ((*function)->base.flags & Ast_Flag_Foreign) continue;
+        
         if (((*function)->base.flags & Ast_Flag_Intrinsic) == 0)
             bh_imap_put(&module->func_map, (u64) *function, module->next_func_idx++);
     }
 
-    bh_arr_each(AstGlobal *, global, program->globals)
-        bh_imap_put(&module->global_map, (u64) *global, module->next_global_idx++);
-
-
     // NOTE: Then, compile everything
     bh_arr_each(AstFunction *, function, program->functions)
         compile_function(module, *function);
 
-    bh_arr_each(AstGlobal *, global, program->globals)
-        compile_global_declaration(module, *global);
+    // bh_arr_each(AstGlobal *, global, program->globals)
+    //     compile_global_declaration(module, *global);
 }
 
 void onyx_wasm_module_free(OnyxWasmModule* module) {