Added back WASM globals; small name changes
authorBrendan Hansen <brendan.f.hansen@gmail.com>
Fri, 17 Jul 2020 04:24:13 +0000 (23:24 -0500)
committerBrendan Hansen <brendan.f.hansen@gmail.com>
Fri, 17 Jul 2020 04:24:13 +0000 (23:24 -0500)
15 files changed:
.vimspector.json
include/onyxastnodes.h
include/onyxlex.h
include/onyxparser.h
misc/onyx.vim
onyx
progs/basic.onyx
progs/test.onyx
src/onyx.c
src/onyxchecker.c
src/onyxir.c
src/onyxlex.c
src/onyxparser.c
src/onyxsymres.c
src/onyxwasm.c

index e309f7f9bf9838e0c2649137abd51c35f11dd304..88493853a3314d6b6d7717d1fe5c86193f4b554c 100644 (file)
@@ -6,7 +6,7 @@
                 "type": "cppdbg",
                 "request": "launch",
                 "program": "${workspaceFolder}/onyx",
-                "args": ["progs/test.onyx"],
+                "args": ["progs/basic.onyx"],
                 "stopAtEntry": true,
                 "cwd": "${workspaceFolder}",
                 "environment": [],
index 189a3f0f14bc13f2d8e28bf9db1d46d1cde81fa0..7f6278f05d07c2d547fe802c8a814478dfe65f0c 100644 (file)
@@ -180,8 +180,21 @@ struct AstFunctionType  { AstType base; AstType* return_type; u64 param_count; A
 // Top level nodes
 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 AstGlobal        {
+    AstTyped base;
+
+    union {
+        // NOTE: Used when a global is exported with a specific name
+        OnyxToken* exported_name;
+
+        // NOTE: Used when the global is declared as foreign
+        struct {
+            OnyxToken* foreign_module;
+            OnyxToken* foreign_name;
+        };
+    };
+};
 struct AstFunction      {
     AstTyped base;
 
@@ -192,11 +205,13 @@ struct AstFunction      {
         // NOTE: Used when a function is exported with a specific name
         OnyxToken* exported_name;
         OnyxToken* intrinsic_name;
-    };
 
-    // NOTE: Used when the function is declared as foreign
-    OnyxToken* foreign_module;
-    OnyxToken* foreign_name;
+        // NOTE: Used when the function is declared as foreign
+        struct {
+            OnyxToken* foreign_module;
+            OnyxToken* foreign_name;
+        };
+    };
 };
 
 typedef enum OnyxIntrinsic {
@@ -237,6 +252,7 @@ typedef struct ParserOutput {
     bh_arr(AstNode *)     nodes_to_process;
 
     bh_arr(AstFunction *) functions;
+    bh_arr(AstGlobal *)   globals;
 } ParserOutput;
 
 
index 9a6d407a0a9156831de828fce5a409927544a868..87e957e7e85b49eccb93d6a011bff65ee140db16 100644 (file)
@@ -17,7 +17,7 @@ typedef enum TokenType {
     Token_Type_Keyword_Else         = 263,
     Token_Type_Keyword_Elseif       = 264,
     Token_Type_Keyword_Return       = 265,
-    Token_Type_Keyword_Foreign      = 266,
+    Token_Type_Keyword_Global       = 266,
     Token_Type_Keyword_Proc         = 267,
     Token_Type_Keyword_Cast         = 268,
     Token_Type_Keyword_While        = 269,
@@ -71,8 +71,8 @@ typedef struct OnyxTokenizer {
     bh_arr(OnyxToken) tokens;
 } OnyxTokenizer;
 
-const char* onyx_get_token_type_name(TokenType tkn_type);
-void onyx_token_null_toggle(OnyxToken* tkn);
+const char* token_name(TokenType tkn_type);
+void token_toggle_end(OnyxToken* tkn);
 OnyxToken* onyx_get_token(OnyxTokenizer* tokenizer);
 OnyxTokenizer onyx_tokenizer_create(bh_allocator allocator, bh_file_contents *fc);
 void onyx_tokenizer_free(OnyxTokenizer* tokenizer);
index fba6bfaf1eba264e506f0870586409fcbc4d47c9..74ad60303587f00bd28a2cf2a9d87c3c25057be0 100644 (file)
@@ -23,8 +23,8 @@ typedef struct OnyxParser {
 
     // NOTE: not used since all tokens are lexed before parsing starts
     OnyxTokenizer *tokenizer;
-    OnyxToken *prev_token;
-    OnyxToken *curr_token;
+    OnyxToken *prev;
+    OnyxToken *curr;
 
     OnyxMessages *msgs;
 
index 23ebf5b7e3d6175014a74821c09a380d00844470..bf1fdd66aeb33f43e317f2db0ad95749646b3e0a 100644 (file)
@@ -10,7 +10,7 @@ endif
 let s:cpo_save = &cpo
 set cpo&vim
 
-syn keyword onyxKeyword struct proc use
+syn keyword onyxKeyword struct proc use global
 syn keyword onyxKeyword if elseif else
 syn keyword onyxKeyword for while do
 syn keyword onyxKeyword break continue return
diff --git a/onyx b/onyx
index 9d590f0dfd7a1948f0226e39658a488e6c90b6b0..fd4bedcb20862c19a59c7121606cc59296155794 100755 (executable)
Binary files a/onyx and b/onyx differ
index fdba0aec73de5ad58cac029ae25bb7d8a6162711..1d10f18e1ceca8aa10cff85fe6c076d991251fd7 100644 (file)
@@ -1,5 +1,3 @@
-use "progs/intrinsics"
-
 pointer_test :: proc {
     p := 0 as ^i32;
 }
@@ -23,16 +21,19 @@ foo :: proc (n: i32) -> i32 {
 // OR
 // This could be immediately substituted in the expression tree. i.e.
 //      4 + global       =>       4 + (5 * 2 + 6)
-global :: 5 * 2 + 6
+global_value :: 5 * 2 + 6
 
 // WASM globals would be declared as such:
-// wasm_global :: global i32
+wasm_global :: global i32
 
 main :: proc #export {
     a := 16;
     print(clz_i32(a));
 
-    print(4 + global);
+    wasm_global = 5 + global_value;
+    print(wasm_global);
+
+    print(4 + global_value);
 
     b := 1 + foo(2);
     print(b);
@@ -45,3 +46,6 @@ main :: proc #export {
     cond :: true;
     print(test(cond) as i32);
 }
+
+use "progs/intrinsics"
+
index 1e6a92774e4e5ca9324dab24480c5d8583979b93..3d546c1541d573ff6cbfd757df98c3382655d09f 100644 (file)
@@ -17,8 +17,9 @@ echo :: proc (n: i32) -> i32 {
 
 global_value :: echo(fib(4) * 2);
 
-local_brute :: proc {
+test_proc :: local_brute;
 
+local_brute :: proc {
     a := 123;
     b := 123.0f;
     c := 123.0;
@@ -36,10 +37,6 @@ local_brute :: proc {
     print_f64(c);
 }
 
-main3 :: proc #export {
-    local_brute();
-}
-
 // This is the entry point
 main2 :: proc #export {
     i := 0;
@@ -90,6 +87,7 @@ main2 :: proc #export {
 // }
 
 main :: proc #export {
+    test_proc();
     local_brute();
 
     print_i32(clz_i32(16));
index 93824ca0d0b5c43668241b00f1006eab402f2638..d0a6da5fea32a6cfe5fbd68bedece3b78ac4c429 100644 (file)
@@ -172,6 +172,7 @@ static void compiler_state_init(CompilerState* compiler_state, OnyxCompileOption
     bh_arr_new(global_heap_allocator, compiler_state->parse_output.top_level_bindings, 4);
     bh_arr_new(global_heap_allocator, compiler_state->parse_output.nodes_to_process, 4);
     bh_arr_new(global_heap_allocator, compiler_state->parse_output.functions, 4);
+    bh_arr_new(global_heap_allocator, compiler_state->parse_output.globals, 4);
 
     bh_arena_init(&compiler_state->msg_arena, opts->allocator, 4096);
     compiler_state->msg_alloc = bh_arena_allocator(&compiler_state->msg_arena);
@@ -271,6 +272,7 @@ int main(int argc, char *argv[]) {
             .nodes_to_process   = NULL,
 
             .functions = NULL,
+            .globals   = NULL,
         },
         .wasm_mod = { 0 }
     };
index 51e3d552947b6522809e7ca1cc9c9937c941787e..05f34e44ef21d2e3a57c962e712a02c538f88c01 100644 (file)
@@ -146,7 +146,7 @@ static b32 check_call(OnyxSemPassState* state, AstCall* call) {
         call->base.kind = Ast_Kind_Intrinsic_Call;
         call->callee = NULL;
 
-        onyx_token_null_toggle(callee->intrinsic_name);
+        token_toggle_end(callee->intrinsic_name);
 
         char* intr_name = callee->intrinsic_name->text;
         OnyxIntrinsic intrinsic = ONYX_INTRINSIC_UNDEFINED;
@@ -200,7 +200,7 @@ static b32 check_call(OnyxSemPassState* state, AstCall* call) {
 
         ((AstIntrinsicCall *)call)->intrinsic = intrinsic;
 
-        onyx_token_null_toggle(callee->intrinsic_name);
+        token_toggle_end(callee->intrinsic_name);
     }
 
     call->base.type = callee->base.type->Function.return_type;
@@ -379,34 +379,16 @@ static b32 check_expression(OnyxSemPassState* state, AstTyped* expr) {
 }
 
 static b32 check_global(OnyxSemPassState* state, AstGlobal* global) {
-    if (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);
-        }
-
-        if (global->base.type != NULL) {
-            if (!types_are_compatible(global->base.type, global->initial_value->type)) {
-                onyx_message_add(state->msgs,
-                        ONYX_MESSAGE_TYPE_GLOBAL_TYPE_MISMATCH,
-                        global->base.token->pos,
-                        global->base.token->text, global->base.token->length,
-                        type_get_name(global->base.type),
-                        type_get_name(global->initial_value->type));
-                return 1;
-            }
-        } else {
-            if (global->initial_value->type)
-                global->base.type = global->initial_value->type;
-        }
-    }
+    if (global->base.type == NULL)
+        global->base.type = type_build_from_ast(state->allocator, global->base.type_node);
 
     if (global->base.type == NULL) {
         onyx_message_add(state->msgs,
-                ONYX_MESSAGE_TYPE_LITERAL,
+                ONYX_MESSAGE_TYPE_UNRESOLVED_TYPE,
                 global->base.token->pos,
-                "global variable with unknown type");
+                global->exported_name->text,
+                global->exported_name->length);
+
         return 1;
     }
 
@@ -541,5 +523,9 @@ void onyx_type_check(OnyxSemPassState* state, ParserOutput* program) {
         if ((*node)->kind == Ast_Kind_Function) {
             bh_arr_push(program->functions, (AstFunction *) *node);
         }
+
+        if ((*node)->kind == Ast_Kind_Global) {
+            bh_arr_push(program->globals, (AstGlobal *) *node);
+        }
     }
 }
index 1002249b19b038189089f4d04865681786382999..e326eed7251224635b35e320c4d74fb5b2eefb24 100644 (file)
@@ -90,25 +90,25 @@ IR_FUNC(ir_function, AstFunction* ast_func) {
     func->is_intrinsic = (ast_func->base.flags & Ast_Flag_Intrinsic) != 0;
 
     if (func->is_intrinsic) {
-        onyx_token_null_toggle(ast_func->base.token);
+        token_toggle_end(ast_func->base.token);
         func->intrinsic = intrinsic_lookup(ast_func->base.token->text);
-        onyx_token_null_toggle(ast_func->base.token);
+        token_toggle_end(ast_func->base.token);
     }
 
     else if (func->is_exported) {
-        onyx_token_null_toggle(ast_func->base.token);
+        token_toggle_end(ast_func->base.token);
         func->exported_name = bh_aprintf(c->allocator, "%s", ast_func->base.token->text);
-        onyx_token_null_toggle(ast_func->base.token);
+        token_toggle_end(ast_func->base.token);
     }
 
     else if (func->is_foreign) {
-        onyx_token_null_toggle(ast_func->foreign_module);
+        token_toggle_end(ast_func->foreign_module);
         func->foreign_module = bh_aprintf(c->allocator, "%s", ast_func->foreign_module);
-        onyx_token_null_toggle(ast_func->foreign_module);
+        token_toggle_end(ast_func->foreign_module);
 
-        onyx_token_null_toggle(ast_func->foreign_name);
+        token_toggle_end(ast_func->foreign_name);
         func->foreign_module = bh_aprintf(c->allocator, "%s", ast_func->foreign_name);
-        onyx_token_null_toggle(ast_func->foreign_name);
+        token_toggle_end(ast_func->foreign_name);
     }
 
     if (func->body != NULL) {
index 6987e51babd5d39296b85e1853b438ce68211ec5..1c6edea84312af007cd9b8be035502f6347b8819 100644 (file)
@@ -15,7 +15,7 @@ static const char* token_type_names[] = {
     "else",
     "elseif",
     "return",
-    "foreign",
+    "global",
     "proc",
     "as",
     "while",
@@ -79,7 +79,7 @@ static b32 token_lit(OnyxTokenizer* tokenizer, OnyxToken* tk, char* lit, b32 is_
     return 0;
 }
 
-const char* onyx_get_token_type_name(TokenType tkn_type) {
+const char* token_name(TokenType tkn_type) {
     if (tkn_type < Token_Type_Ascii_End) {
         return bh_aprintf(global_scratch_allocator, "%c", (char) tkn_type);
     } else {
@@ -87,7 +87,7 @@ const char* onyx_get_token_type_name(TokenType tkn_type) {
     }
 }
 
-void onyx_token_null_toggle(OnyxToken* tkn) {
+void token_toggle_end(OnyxToken* tkn) {
     static char backup = 0;
     char tmp = tkn->text[tkn->length];
     tkn->text[tkn->length] = backup;
@@ -129,12 +129,11 @@ OnyxToken* onyx_get_token(OnyxTokenizer* tokenizer) {
     }
 
     LITERAL_TOKEN("struct",     1, Token_Type_Keyword_Struct);
-//     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("global",     1, Token_Type_Keyword_Global);
     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 4879993591e9fc40f110fe59cdfde0cff6bf2b35..a8ef82ec9d625f5ed5a3e8945d76b57acaa546f7 100644 (file)
@@ -23,10 +23,10 @@ AstBasicType basic_type_f64    = { { Ast_Kind_Basic_Type, 0, "f64"    }, &basic_
 AstBasicType basic_type_rawptr = { { Ast_Kind_Basic_Type, 0, "rawptr" }, &basic_types[Basic_Kind_Rawptr] };
 
 // NOTE: Forward declarations
-static void parser_next_token(OnyxParser* parser);
-static void parser_prev_token(OnyxParser* parser);
+static void consume_token(OnyxParser* parser);
+static void unconsume_token(OnyxParser* parser);
 static b32 is_terminating_token(TokenType token_type);
-static OnyxToken* expect(OnyxParser* parser, TokenType token_type);
+static OnyxToken* expect_token(OnyxParser* parser, TokenType token_type);
 
 static AstNumLit*   parse_numeric_literal(OnyxParser* parser);
 static AstTyped*    parse_factor(OnyxParser* parser);
@@ -40,19 +40,21 @@ 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 AstTyped*    parse_global_declaration(OnyxParser* parser);
+static AstTyped*    parse_top_level_expression(OnyxParser* parser);
 static AstNode*     parse_top_level_statement(OnyxParser* parser);
 
-static void parser_next_token(OnyxParser* parser) {
-    parser->prev_token = parser->curr_token;
-    parser->curr_token++;
-    while (parser->curr_token->type == Token_Type_Comment) parser->curr_token++;
+static void consume_token(OnyxParser* parser) {
+    parser->prev = parser->curr;
+    parser->curr++;
+    while (parser->curr->type == Token_Type_Comment) parser->curr++;
 }
 
-static void parser_prev_token(OnyxParser* parser) {
+static void unconsume_token(OnyxParser* parser) {
     // TODO: This is probably wrong
-    while (parser->prev_token->type == Token_Type_Comment) parser->prev_token--;
-    parser->curr_token = parser->prev_token;
-    parser->prev_token--;
+    while (parser->prev->type == Token_Type_Comment) parser->prev--;
+    parser->curr = parser->prev;
+    parser->prev--;
 }
 
 static b32 is_terminating_token(TokenType token_type) {
@@ -63,21 +65,21 @@ static b32 is_terminating_token(TokenType token_type) {
 }
 
 static void find_token(OnyxParser* parser, TokenType token_type) {
-    while (parser->curr_token->type != token_type && !is_terminating_token(parser->curr_token->type)) {
-        parser_next_token(parser);
+    while (parser->curr->type != token_type && !is_terminating_token(parser->curr->type)) {
+        consume_token(parser);
     }
 }
 
 // Advances to next token no matter what
-static OnyxToken* expect(OnyxParser* parser, TokenType token_type) {
-    OnyxToken* token = parser->curr_token;
-    parser_next_token(parser);
+static OnyxToken* expect_token(OnyxParser* parser, TokenType token_type) {
+    OnyxToken* token = parser->curr;
+    consume_token(parser);
 
     if (token->type != token_type) {
         onyx_message_add(parser->msgs,
                          ONYX_MESSAGE_TYPE_EXPECTED_TOKEN,
                          token->pos,
-                         onyx_get_token_type_name(token_type), onyx_get_token_type_name(token->type));
+                         token_name(token_type), token_name(token->type));
         return NULL;
     }
 
@@ -86,12 +88,12 @@ static OnyxToken* expect(OnyxParser* parser, TokenType token_type) {
 
 static AstNumLit* parse_numeric_literal(OnyxParser* parser) {
     AstNumLit* lit_node = make_node(AstNumLit, Ast_Kind_Literal);
-    lit_node->base.token = expect(parser, Token_Type_Literal_Numeric);
+    lit_node->base.token = expect_token(parser, Token_Type_Literal_Numeric);
     lit_node->base.flags |= Ast_Flag_Comptime;
     lit_node->value.l = 0ll;
 
     AstType* type;
-    onyx_token_null_toggle(lit_node->base.token);
+    token_toggle_end(lit_node->base.token);
     char* tok = lit_node->base.token->text;
 
     // NOTE: charset_contains() behaves more like string_contains()
@@ -116,26 +118,35 @@ static AstNumLit* parse_numeric_literal(OnyxParser* parser) {
     }
 
     lit_node->base.type_node = type;
-    onyx_token_null_toggle(lit_node->base.token);
+    token_toggle_end(lit_node->base.token);
     return lit_node;
 }
 
+// ( <expr> )
+// - <factor>
+// ! <factor>
+// proc ...
+// <symbol> ( '(' <exprlist> ')' )?
+// <numlit>
+// 'true'
+// 'false'
+// All of these could be followed by a cast
 static AstTyped* parse_factor(OnyxParser* parser) {
     AstTyped* retval = NULL;
 
-    switch ((u16) parser->curr_token->type) {
+    switch ((u16) parser->curr->type) {
         case '(':
             {
-                parser_next_token(parser);
+                consume_token(parser);
                 AstTyped* expr = parse_expression(parser);
-                expect(parser, ')');
+                expect_token(parser, ')');
                 retval = expr;
                 break;
             }
 
         case '-':
             {
-                parser_next_token(parser);
+                consume_token(parser);
                 AstTyped* factor = parse_factor(parser);
 
                 AstUnaryOp* negate_node = make_node(AstUnaryOp, Ast_Kind_Unary_Op);
@@ -154,7 +165,7 @@ static AstTyped* parse_factor(OnyxParser* parser) {
             {
                 AstUnaryOp* not_node = make_node(AstUnaryOp, Ast_Kind_Unary_Op);
                 not_node->operation = Unary_Op_Not;
-                not_node->base.token = expect(parser, '!');
+                not_node->base.token = expect_token(parser, '!');
                 not_node->expr = parse_factor(parser);
 
                 if ((not_node->expr->flags & Ast_Flag_Comptime) != 0) {
@@ -167,25 +178,25 @@ static AstTyped* parse_factor(OnyxParser* parser) {
 
         case Token_Type_Symbol:
             {
-                OnyxToken* sym_token = expect(parser, Token_Type_Symbol);
+                OnyxToken* sym_token = expect_token(parser, Token_Type_Symbol);
                 AstTyped* sym_node = make_node(AstTyped, Ast_Kind_Symbol);
                 sym_node->token = sym_token;
 
-                if (parser->curr_token->type != '(') {
+                if (parser->curr->type != '(') {
                     retval = sym_node;
                     break;
                 }
 
                 // NOTE: Function call
                 AstCall* call_node = make_node(AstCall, Ast_Kind_Call);
-                call_node->base.token = expect(parser, '(');
+                call_node->base.token = expect_token(parser, '(');
                 call_node->callee = (AstNode *) sym_node;
 
                 AstArgument** prev = &call_node->arguments;
                 AstArgument* curr = NULL;
-                while (parser->curr_token->type != ')') {
+                while (parser->curr->type != ')') {
                     curr = make_node(AstArgument, Ast_Kind_Argument);
-                    curr->base.token = parser->curr_token;
+                    curr->base.token = parser->curr;
                     curr->value = parse_expression(parser);
 
                     if (curr != NULL && curr->base.kind != Ast_Kind_Error) {
@@ -193,21 +204,21 @@ static AstTyped* parse_factor(OnyxParser* parser) {
                         prev = (AstArgument **) &curr->base.next;
                     }
 
-                    if (parser->curr_token->type == ')')
+                    if (parser->curr->type == ')')
                         break;
 
-                    if (parser->curr_token->type != ',') {
+                    if (parser->curr->type != ',') {
                         onyx_message_add(parser->msgs,
                                 ONYX_MESSAGE_TYPE_EXPECTED_TOKEN,
-                                parser->curr_token->pos,
-                                onyx_get_token_type_name(','),
-                                onyx_get_token_type_name(parser->curr_token->type));
+                                parser->curr->pos,
+                                token_name(','),
+                                token_name(parser->curr->type));
                         return (AstTyped *) &error_node;
                     }
 
-                    parser_next_token(parser);
+                    consume_token(parser);
                 }
-                parser_next_token(parser);
+                consume_token(parser);
 
                 retval = (AstTyped *) call_node;
                 break;
@@ -221,7 +232,7 @@ static AstTyped* parse_factor(OnyxParser* parser) {
             {
                 AstNumLit* bool_node = make_node(AstNumLit, Ast_Kind_Literal);
                 bool_node->base.type_node = (AstType *) &basic_type_bool;
-                bool_node->base.token = expect(parser, Token_Type_Literal_True);
+                bool_node->base.token = expect_token(parser, Token_Type_Literal_True);
                 bool_node->value.i = 1;
                 retval = (AstTyped *) bool_node;
                 break;
@@ -231,32 +242,22 @@ static AstTyped* parse_factor(OnyxParser* parser) {
             {
                 AstNumLit* bool_node = make_node(AstNumLit, Ast_Kind_Literal);
                 bool_node->base.type_node = (AstType *) &basic_type_bool;
-                bool_node->base.token = expect(parser, Token_Type_Literal_False);
+                bool_node->base.token = expect_token(parser, Token_Type_Literal_False);
                 bool_node->value.i = 0;
                 retval = (AstTyped *) bool_node;
                 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,
-                    parser->curr_token->pos,
-                    onyx_get_token_type_name(parser->curr_token->type));
+                    parser->curr->pos,
+                    token_name(parser->curr->type));
             return NULL;
     }
 
-    while (parser->curr_token->type == Token_Type_Keyword_Cast) {
-        parser_next_token(parser);
+    while (parser->curr->type == Token_Type_Keyword_Cast) {
+        consume_token(parser);
 
         AstUnaryOp* cast_node = make_node(AstUnaryOp, Ast_Kind_Unary_Op);
         cast_node->base.type_node = parse_type(parser);
@@ -289,6 +290,18 @@ static inline i32 get_precedence(BinaryOp kind) {
     }
 }
 
+// <factor> + <factor>
+// <factor> - <factor>
+// <factor> * <factor>
+// <factor> / <factor>
+// <factor> % <factor>
+// <factor> == <factor>
+// <factor> != <factor>
+// <factor> <= <factor>
+// <factor> >= <factor>
+// <factor> < <factor>
+// <factor> > <factor>
+// With expected precedence rules
 static AstTyped* parse_expression(OnyxParser* parser) {
     bh_arr(AstBinaryOp*) tree_stack = NULL;
     bh_arr_new(global_scratch_allocator, tree_stack, 4);
@@ -303,7 +316,7 @@ static AstTyped* parse_expression(OnyxParser* parser) {
 
     while (1) {
         bin_op_kind = -1;
-        switch ((u16) parser->curr_token->type) {
+        switch ((u16) parser->curr->type) {
             case Token_Type_Equal_Equal:    bin_op_kind = Binary_Op_Equal; break;
             case Token_Type_Not_Equal:      bin_op_kind = Binary_Op_Not_Equal; break;
             case Token_Type_Less_Equal:     bin_op_kind = Binary_Op_Less_Equal; break;
@@ -320,8 +333,8 @@ static AstTyped* parse_expression(OnyxParser* parser) {
         }
 
         if (bin_op_kind != -1) {
-            bin_op_tok = parser->curr_token;
-            parser_next_token(parser);
+            bin_op_tok = parser->curr;
+            consume_token(parser);
 
             AstBinaryOp* bin_op = make_node(AstBinaryOp, Ast_Kind_Binary_Op);
             bin_op->operation = bin_op_kind;
@@ -355,8 +368,9 @@ expression_done:
     return root;
 }
 
+// 'if' <expr> <block> ('elseif' <cond> <block>)* ('else' <block>)?
 static AstIf* parse_if_stmt(OnyxParser* parser) {
-    expect(parser, Token_Type_Keyword_If);
+    expect_token(parser, Token_Type_Keyword_If);
 
     AstTyped* cond = parse_expression(parser);
     AstBlock* true_block = parse_block(parser);
@@ -368,8 +382,8 @@ static AstIf* parse_if_stmt(OnyxParser* parser) {
     if (true_block != NULL)
         if_node->true_block.as_block = true_block;
 
-    while (parser->curr_token->type == Token_Type_Keyword_Elseif) {
-        parser_next_token(parser);
+    while (parser->curr->type == Token_Type_Keyword_Elseif) {
+        consume_token(parser);
         AstIf* elseif_node = make_node(AstIf, Ast_Kind_If);
 
         cond = parse_expression(parser);
@@ -383,8 +397,8 @@ static AstIf* parse_if_stmt(OnyxParser* parser) {
         if_node = elseif_node;
     }
 
-    if (parser->curr_token->type == Token_Type_Keyword_Else) {
-        parser_next_token(parser);
+    if (parser->curr->type == Token_Type_Keyword_Else) {
+        consume_token(parser);
 
         AstBlock* false_block = parse_block(parser);
         if (false_block != NULL)
@@ -394,8 +408,9 @@ static AstIf* parse_if_stmt(OnyxParser* parser) {
     return root_if;
 }
 
+// 'while' <expr> <block>
 static AstWhile* parse_while_stmt(OnyxParser* parser) {
-    OnyxToken* while_token = expect(parser, Token_Type_Keyword_While);
+    OnyxToken* while_token = expect_token(parser, Token_Type_Keyword_While);
 
     AstTyped* cond = parse_expression(parser);
     AstBlock* body = parse_block(parser);
@@ -410,20 +425,30 @@ static AstWhile* parse_while_stmt(OnyxParser* parser) {
 
 // Returns 1 if the symbol was consumed. Returns 0 otherwise
 // ret is set to the statement to insert
+// <symbol> : <type> = <expr>
+// <symbol> : <type> : <expr>
+// <symbol> := <expr>
+// <symbol> :: <expr>
+// <symbol> = <expr>
+// <symbol> += <expr>
+// <symbol> -= <expr>
+// <symbol> *= <expr>
+// <symbol> /= <expr>
+// <symbol> %= <expr>
 static b32 parse_symbol_statement(OnyxParser* parser, AstNode** ret) {
-    if (parser->curr_token->type != Token_Type_Symbol) return 0;
-    OnyxToken* symbol = expect(parser, Token_Type_Symbol);
+    if (parser->curr->type != Token_Type_Symbol) return 0;
+    OnyxToken* symbol = expect_token(parser, Token_Type_Symbol);
 
-    switch ((u16) parser->curr_token->type) {
+    switch ((u16) parser->curr->type) {
         // NOTE: Declaration
         case ':':
             {
-                parser_next_token(parser);
+                consume_token(parser);
                 AstType* type_node = NULL;
 
                 // NOTE: var: type
-                if (parser->curr_token->type != ':'
-                        && parser->curr_token->type != '=') {
+                if (parser->curr->type != ':'
+                        && parser->curr->type != '=') {
                     type_node = parse_type(parser);
                 }
 
@@ -433,24 +458,24 @@ static b32 parse_symbol_statement(OnyxParser* parser, AstNode** ret) {
                 local->base.flags |= Ast_Flag_Lval; // NOTE: DELETE
                 *ret = (AstNode *) local;
 
-                if (parser->curr_token->type == '=' || parser->curr_token->type == ':') {
-                    if (parser->curr_token->type == ':') {
+                if (parser->curr->type == '=' || parser->curr->type == ':') {
+                    if (parser->curr->type == ':') {
                         local->base.flags |= Ast_Flag_Const;
                     }
 
                     AstAssign* assignment = make_node(AstAssign, Ast_Kind_Assignment);
                     local->base.next = (AstNode *) assignment;
-                    assignment->base.token = parser->curr_token;
-                    parser_next_token(parser);
+                    assignment->base.token = parser->curr;
+                    consume_token(parser);
 
                     AstTyped* expr = parse_expression(parser);
                     if (expr == NULL) {
-                        onyx_token_null_toggle(parser->curr_token);
+                        token_toggle_end(parser->curr);
                         onyx_message_add(parser->msgs,
                                 ONYX_MESSAGE_TYPE_EXPECTED_EXPRESSION,
                                 assignment->base.token->pos,
-                                parser->curr_token->text);
-                        onyx_token_null_toggle(parser->curr_token);
+                                parser->curr->text);
+                        token_toggle_end(parser->curr);
                         return 1;
                     }
                     assignment->expr = expr;
@@ -466,8 +491,8 @@ static b32 parse_symbol_statement(OnyxParser* parser, AstNode** ret) {
         case '=':
             {
                 AstAssign* assignment = make_node(AstAssign, Ast_Kind_Assignment);
-                assignment->base.token = parser->curr_token;
-                parser_next_token(parser);
+                assignment->base.token = parser->curr;
+                consume_token(parser);
 
                 AstNode* lval = make_node(AstNode, Ast_Kind_Symbol);
                 lval->token = symbol;
@@ -486,17 +511,17 @@ static b32 parse_symbol_statement(OnyxParser* parser, AstNode** ret) {
         case Token_Type_Percent_Equal:
             {
                 BinaryOp bin_op;
-                if      (parser->curr_token->type == Token_Type_Plus_Equal)    bin_op = Binary_Op_Add;
-                else if (parser->curr_token->type == Token_Type_Minus_Equal)   bin_op = Binary_Op_Minus;
-                else if (parser->curr_token->type == Token_Type_Star_Equal)    bin_op = Binary_Op_Multiply;
-                else if (parser->curr_token->type == Token_Type_Fslash_Equal)  bin_op = Binary_Op_Divide;
-                else if (parser->curr_token->type == Token_Type_Percent_Equal) bin_op = Binary_Op_Modulus;
+                if      (parser->curr->type == Token_Type_Plus_Equal)    bin_op = Binary_Op_Add;
+                else if (parser->curr->type == Token_Type_Minus_Equal)   bin_op = Binary_Op_Minus;
+                else if (parser->curr->type == Token_Type_Star_Equal)    bin_op = Binary_Op_Multiply;
+                else if (parser->curr->type == Token_Type_Fslash_Equal)  bin_op = Binary_Op_Divide;
+                else if (parser->curr->type == Token_Type_Percent_Equal) bin_op = Binary_Op_Modulus;
 
                 AstBinaryOp* bin_op_node = make_node(AstBinaryOp, Ast_Kind_Binary_Op);
                 bin_op_node->operation = bin_op;
-                bin_op_node->base.token = parser->curr_token;
+                bin_op_node->base.token = parser->curr;
 
-                parser_next_token(parser);
+                consume_token(parser);
                 AstTyped* expr = parse_expression(parser);
 
                 AstNode* bin_op_left = make_node(AstNode, Ast_Kind_Symbol);
@@ -519,19 +544,20 @@ static b32 parse_symbol_statement(OnyxParser* parser, AstNode** ret) {
             }
 
         default:
-            parser_prev_token(parser);
+            unconsume_token(parser);
     }
 
     return 0;
 }
 
+// 'return' <expr>?
 static AstReturn* parse_return_statement(OnyxParser* parser) {
     AstReturn* return_node = make_node(AstReturn, Ast_Kind_Return);
-    return_node->base.token = expect(parser, Token_Type_Keyword_Return);
+    return_node->base.token = expect_token(parser, Token_Type_Keyword_Return);
 
     AstTyped* expr = NULL;
 
-    if (parser->curr_token->type != ';') {
+    if (parser->curr->type != ';') {
         expr = parse_expression(parser);
 
         if (expr == NULL || expr == (AstTyped *) &error_node) {
@@ -544,11 +570,19 @@ static AstReturn* parse_return_statement(OnyxParser* parser) {
     return return_node;
 }
 
+// <return> ;
+// <block>
+// <symbol_statement> ;
+// <expr> ;
+// <if>
+// <while>
+// 'break' ;
+// 'continue' ;
 static AstNode* parse_statement(OnyxParser* parser) {
     b32 needs_semicolon = 1;
     AstNode* retval = NULL;
 
-    switch ((u16) parser->curr_token->type) {
+    switch ((u16) parser->curr->type) {
         case Token_Type_Keyword_Return:
             retval = (AstNode *) parse_return_statement(parser);
             break;
@@ -583,12 +617,12 @@ static AstNode* parse_statement(OnyxParser* parser) {
 
         case Token_Type_Keyword_Break:
             retval = make_node(AstNode, Ast_Kind_Break);
-            retval->token = expect(parser, Token_Type_Keyword_Break);
+            retval->token = expect_token(parser, Token_Type_Keyword_Break);
             break;
 
         case Token_Type_Keyword_Continue:
             retval = make_node(AstNode, Ast_Kind_Break);
-            retval->token = expect(parser, Token_Type_Keyword_Continue);
+            retval->token = expect_token(parser, Token_Type_Keyword_Continue);
             break;
 
         default:
@@ -596,37 +630,39 @@ static AstNode* parse_statement(OnyxParser* parser) {
     }
 
     if (needs_semicolon) {
-        if (parser->curr_token->type != ';') {
+        if (parser->curr->type != ';') {
             onyx_message_add(parser->msgs,
                 ONYX_MESSAGE_TYPE_EXPECTED_TOKEN,
-                parser->curr_token->pos,
-                onyx_get_token_type_name(';'),
-                onyx_get_token_type_name(parser->curr_token->type));
+                parser->curr->pos,
+                token_name(';'),
+                token_name(parser->curr->type));
 
             find_token(parser, ';');
         }
-        parser_next_token(parser);
+        consume_token(parser);
     }
 
     return retval;
 }
 
+// '---'
+// '{' <stmtlist> '}'
 static AstBlock* parse_block(OnyxParser* parser) {
     AstBlock* block = make_node(AstBlock, Ast_Kind_Block);
     AstLocalGroup* lg = make_node(AstLocalGroup, Ast_Kind_Local_Group);
     block->locals = lg;
 
     // NOTE: --- is for an empty block
-    if (parser->curr_token->type == Token_Type_Empty_Block) {
-        expect(parser, Token_Type_Empty_Block);
+    if (parser->curr->type == Token_Type_Empty_Block) {
+        expect_token(parser, Token_Type_Empty_Block);
         return block;
     }
 
-    expect(parser, '{');
+    expect_token(parser, '{');
 
     AstNode** next = &block->body;
     AstNode* stmt = NULL;
-    while (parser->curr_token->type != '}') {
+    while (parser->curr->type != '}') {
         stmt = parse_statement(parser);
 
         if (stmt != NULL && stmt->kind != Ast_Kind_Error) {
@@ -637,40 +673,42 @@ static AstBlock* parse_block(OnyxParser* parser) {
         }
     }
 
-    expect(parser, '}');
+    expect_token(parser, '}');
 
     return block;
 }
 
+// <symbol>
+// '^' <type>
 static AstType* parse_type(OnyxParser* parser) {
     AstType* root = NULL;
     AstType** next_insertion = &root;
 
     while (1) {
-        if (parser->curr_token->type == '^') {
-            parser_next_token(parser);
+        if (parser->curr->type == '^') {
+            consume_token(parser);
             AstPointerType* new = make_node(AstPointerType, Ast_Kind_Pointer_Type);
             new->base.flags |= Basic_Flag_Pointer;
             *next_insertion = (AstType *) new;
             next_insertion = &new->elem;
         }
 
-        else if (parser->curr_token->type == Token_Type_Symbol) {
+        else if (parser->curr->type == Token_Type_Symbol) {
             AstNode* symbol_node = make_node(AstNode, Ast_Kind_Symbol);
-            symbol_node->token = expect(parser, Token_Type_Symbol);
+            symbol_node->token = expect_token(parser, Token_Type_Symbol);
             *next_insertion = (AstType *) symbol_node;
             next_insertion = NULL;
         }
 
         else {
-            onyx_token_null_toggle(parser->curr_token);
+            token_toggle_end(parser->curr);
             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);
+                    parser->curr->pos,
+                    parser->curr->text);
+            token_toggle_end(parser->curr);
 
-            parser_next_token(parser);
+            consume_token(parser);
             break;
         }
 
@@ -680,14 +718,16 @@ static AstType* parse_type(OnyxParser* parser) {
     return root;
 }
 
+// e
+// '(' (<symbol>: <type>,?)* ')'
 static AstLocal* parse_function_params(OnyxParser* parser) {
-    if (parser->curr_token->type != '(')
+    if (parser->curr->type != '(')
         return NULL;
 
-    expect(parser, '(');
+    expect_token(parser, '(');
 
-    if (parser->curr_token->type == ')') {
-        parser_next_token(parser);
+    if (parser->curr->type == ')') {
+        consume_token(parser);
         return NULL;
     }
 
@@ -696,11 +736,11 @@ static AstLocal* parse_function_params(OnyxParser* parser) {
     AstLocal* trailer = NULL;
 
     OnyxToken* symbol;
-    while (parser->curr_token->type != ')') {
-        if (parser->curr_token->type == ',') parser_next_token(parser);
+    while (parser->curr->type != ')') {
+        if (parser->curr->type == ',') consume_token(parser);
 
-        symbol = expect(parser, Token_Type_Symbol);
-        expect(parser, ':');
+        symbol = expect_token(parser, Token_Type_Symbol);
+        expect_token(parser, ':');
 
         curr_param = make_node(AstLocal, Ast_Kind_Param);
         curr_param->base.token = symbol;
@@ -715,35 +755,38 @@ static AstLocal* parse_function_params(OnyxParser* parser) {
         trailer = curr_param;
     }
 
-    parser_next_token(parser); // Skip the )
+    consume_token(parser); // Skip the )
     return first_param;
 }
 
+// e
+// '#' <symbol>
 static b32 parse_possible_directive(OnyxParser* parser, const char* dir) {
-    if (parser->curr_token->type != '#') return 0;
+    if (parser->curr->type != '#') return 0;
 
-    expect(parser, '#');
-    OnyxToken* sym = expect(parser, Token_Type_Symbol);
+    expect_token(parser, '#');
+    OnyxToken* sym = expect_token(parser, Token_Type_Symbol);
 
     b32 match = (strlen(dir) == sym->length) && (strncmp(dir, sym->text, sym->length) == 0);
     if (!match) {
-        parser_prev_token(parser);
-        parser_prev_token(parser);
+        unconsume_token(parser);
+        unconsume_token(parser);
     }
     return match;
 }
 
+// 'proc' <directive>* <func_params> ('->' <type>)? <block>
 static AstFunction* parse_function_definition(OnyxParser* parser) {
 
     AstFunction* func_def = make_node(AstFunction, Ast_Kind_Function);
-    func_def->base.token = expect(parser, Token_Type_Keyword_Proc);
+    func_def->base.token = expect_token(parser, Token_Type_Keyword_Proc);
 
-    while (parser->curr_token->type == '#') {
+    while (parser->curr->type == '#') {
         if (parse_possible_directive(parser, "intrinsic")) {
             func_def->base.flags |= Ast_Flag_Intrinsic;
 
-            if (parser->curr_token->type == Token_Type_Literal_String) {
-                OnyxToken* str_token = expect(parser, Token_Type_Literal_String);
+            if (parser->curr->type == Token_Type_Literal_String) {
+                OnyxToken* str_token = expect_token(parser, Token_Type_Literal_String);
                 func_def->intrinsic_name = str_token;
             }
         }
@@ -753,8 +796,8 @@ static AstFunction* parse_function_definition(OnyxParser* parser) {
         }
 
         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->foreign_module = expect_token(parser, Token_Type_Literal_String);
+            func_def->foreign_name   = expect_token(parser, Token_Type_Literal_String);
 
             func_def->base.flags |= Ast_Flag_Foreign;
         }
@@ -762,15 +805,15 @@ static AstFunction* parse_function_definition(OnyxParser* parser) {
         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);
+            if (parser->curr->type == Token_Type_Literal_String) {
+                OnyxToken* str_token = expect_token(parser, Token_Type_Literal_String);
                 func_def->exported_name = str_token;
             }
         }
 
         else {
-            OnyxToken* directive_token = expect(parser, '#');
-            OnyxToken* symbol_token = expect(parser, Token_Type_Symbol);
+            OnyxToken* directive_token = expect_token(parser, '#');
+            OnyxToken* symbol_token = expect_token(parser, Token_Type_Symbol);
 
             onyx_message_add(parser->msgs,
                     ONYX_MESSAGE_TYPE_UNKNOWN_DIRECTIVE,
@@ -783,8 +826,8 @@ static AstFunction* parse_function_definition(OnyxParser* parser) {
     func_def->params = params;
 
     AstType* return_type = (AstType *) &basic_type_void;
-    if (parser->curr_token->type == Token_Type_Right_Arrow) {
-        expect(parser, Token_Type_Right_Arrow);
+    if (parser->curr->type == Token_Type_Right_Arrow) {
+        expect_token(parser, Token_Type_Right_Arrow);
 
         return_type = parse_type(parser);
     }
@@ -815,80 +858,99 @@ 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 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);
+// 'global' <type>
+static AstTyped* parse_global_declaration(OnyxParser* parser) {
+    AstGlobal* global_node = make_node(AstGlobal, Ast_Kind_Global);
+    global_node->base.token = expect_token(parser, Token_Type_Keyword_Global);
+
+    while (parser->curr->type == '#') {
+        if (parse_possible_directive(parser, "foreign")) {
+            global_node->foreign_module = expect_token(parser, Token_Type_Literal_String);
+            global_node->foreign_name   = expect_token(parser, Token_Type_Literal_String);
+
+            global_node->base.flags |= Ast_Flag_Foreign;
+        }
+
+        else if (parse_possible_directive(parser, "export")) {
+            global_node->base.flags |= Ast_Flag_Exported;
+
+            if (parser->curr->type == Token_Type_Literal_String) {
+                OnyxToken* str_token = expect_token(parser, Token_Type_Literal_String);
+                global_node->exported_name = str_token;
+            }
+        }
+
+        else {
+            OnyxToken* directive_token = expect_token(parser, '#');
+            OnyxToken* symbol_token = expect_token(parser, Token_Type_Symbol);
+
+            onyx_message_add(parser->msgs,
+                    ONYX_MESSAGE_TYPE_UNKNOWN_DIRECTIVE,
+                    directive_token->pos,
+                    symbol_token->text, symbol_token->length);
+        }
+    }
+
+    global_node->base.type_node = parse_type(parser);
+    global_node->base.flags |= Ast_Flag_Lval;
+
+
+    bh_arr_push(parser->results.nodes_to_process, (AstNode *) global_node);
+
+    return (AstTyped *) global_node;
+}
+
+static AstTyped* parse_top_level_expression(OnyxParser* parser) {
+    if (parser->curr->type == Token_Type_Keyword_Proc) {
+        AstFunction* func_node = parse_function_definition(parser);
+
+        bh_arr_push(parser->results.nodes_to_process, (AstNode *) func_node);
+
+        return (AstTyped *) func_node;
+    }
+    else if (parser->curr->type == Token_Type_Keyword_Global) {
+        return parse_global_declaration(parser);
+    }
+    else {
+        return parse_expression(parser);
+    }
 }
 
+// 'use' <string>
+// <symbol> :: <expr>
 static AstNode* parse_top_level_statement(OnyxParser* parser) {
-    switch (parser->curr_token->type) {
+    switch (parser->curr->type) {
         case Token_Type_Keyword_Use:
             {
                 AstUse* use_node = make_node(AstUse, Ast_Kind_Use);
-                use_node->base.token = expect(parser, Token_Type_Keyword_Use);
-                use_node->filename = expect(parser, Token_Type_Literal_String);
+                use_node->base.token = expect_token(parser, Token_Type_Keyword_Use);
+                use_node->filename = expect_token(parser, Token_Type_Literal_String);
 
                 return (AstNode *) use_node;
             }
 
         case Token_Type_Symbol:
             {
-                OnyxToken* symbol = parser->curr_token;
-                parser_next_token(parser);
+                OnyxToken* symbol = parser->curr;
+                consume_token(parser);
 
-                expect(parser, ':');
-                expect(parser, ':');
+                expect_token(parser, ':');
+                expect_token(parser, ':');
 
-                AstTyped* node = parse_top_level_constant_symbol(parser);
+                AstTyped* node = parse_top_level_expression(parser);
 
                 if (node->kind == Ast_Kind_Function) {
                     AstFunction* func = (AstFunction *) node;
 
                     if (func->exported_name == NULL)
                         func->exported_name = symbol;
+
+                } else if (node->kind == Ast_Kind_Global) {
+                    AstGlobal* global = (AstGlobal *) node;
+
+                    if (global->exported_name == NULL)
+                        global->exported_name = symbol;
+
                 } else {
                     // HACK
                     bh_arr_push(parser->results.nodes_to_process, (AstNode *) node);
@@ -904,7 +966,7 @@ static AstNode* parse_top_level_statement(OnyxParser* parser) {
         default: break;
     }
 
-    parser_next_token(parser);
+    consume_token(parser);
     return NULL;
 }
 
@@ -927,8 +989,8 @@ 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.curr = tokenizer->tokens;
+    parser.prev = NULL;
     parser.msgs = msgs;
 
     parser.results = (ParseResults) {
@@ -950,7 +1012,7 @@ void onyx_parser_free(OnyxParser* parser) {
 }
 
 ParseResults onyx_parse(OnyxParser *parser) {
-    while (parser->curr_token->type != Token_Type_End_Stream) {
+    while (parser->curr->type != Token_Type_End_Stream) {
         AstNode* curr_stmt = parse_top_level_statement(parser);
 
         if (curr_stmt != NULL && curr_stmt != &error_node) {
index 7a9a5857e999a34fe702036edbad891a87ed9aac..2aa84b359e4aa5fafbb03a1d61ac53d975efc0c8 100644 (file)
@@ -9,6 +9,7 @@ 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 AstType* symres_type(OnyxSemPassState* state, AstType* type);
 static void symres_local(OnyxSemPassState* state, AstLocal** local);
 static void symres_call(OnyxSemPassState* state, AstCall* call);
 static void symres_expression(OnyxSemPassState* state, AstTyped** expr);
@@ -20,10 +21,10 @@ static void symres_statement_chain(OnyxSemPassState* state, AstNode* walker, Ast
 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 symres_global(OnyxSemPassState* state, AstGlobal* global);
 
 static void symbol_introduce(OnyxSemPassState* state, OnyxToken* tkn, AstNode* symbol) {
-    onyx_token_null_toggle(tkn);
+    token_toggle_end(tkn);
 
     SemPassSymbol* sp_sym = (SemPassSymbol *) bh_alloc_item(state->allocator, SemPassSymbol);
     sp_sym->node = symbol;
@@ -41,11 +42,11 @@ static void symbol_introduce(OnyxSemPassState* state, OnyxToken* tkn, AstNode* s
         state->curr_local_group->last_local = local;
     }
 
-    onyx_token_null_toggle(tkn);
+    token_toggle_end(tkn);
 }
 
 static void symbol_remove(OnyxSemPassState* state, OnyxToken* tkn) {
-    onyx_token_null_toggle(tkn);
+    token_toggle_end(tkn);
 
     SemPassSymbol* sp_sym = bh_table_get(SemPassSymbol *, state->symbols, tkn->text);
 
@@ -55,26 +56,32 @@ static void symbol_remove(OnyxSemPassState* state, OnyxToken* tkn) {
         bh_table_delete(SemPassSymbol *, state->symbols, tkn->text);
     }
 
-    onyx_token_null_toggle(tkn);
+    token_toggle_end(tkn);
 }
 
 static AstNode* symbol_resolve(OnyxSemPassState* state, OnyxToken* tkn) {
-    onyx_token_null_toggle(tkn);
+    AstNode* res = NULL;
 
-    if (!bh_table_has(SemPassSymbol *, state->symbols, tkn->text)) {
-        onyx_message_add(state->msgs,
-                ONYX_MESSAGE_TYPE_UNKNOWN_SYMBOL,
-                tkn->pos,
-                tkn->text);
+    while (res == NULL || res->kind == Ast_Kind_Symbol) {
+        token_toggle_end(tkn);
 
-        onyx_token_null_toggle(tkn);
-        return NULL;
-    }
+        if (!bh_table_has(SemPassSymbol *, state->symbols, tkn->text)) {
+            onyx_message_add(state->msgs,
+                    ONYX_MESSAGE_TYPE_UNKNOWN_SYMBOL,
+                    tkn->pos,
+                    tkn->text);
 
-    SemPassSymbol* sp_sym = bh_table_get(SemPassSymbol *, state->symbols, tkn->text);
+            token_toggle_end(tkn);
+            return NULL;
+        }
+
+        res = bh_table_get(SemPassSymbol *, state->symbols, tkn->text)->node;
+        token_toggle_end(tkn);
+
+        tkn = res->token;
+    }
 
-    onyx_token_null_toggle(tkn);
-    return sp_sym->node;
+    return res;
 }
 
 static void local_group_enter(OnyxSemPassState* state, AstLocalGroup* local_group) {
@@ -100,7 +107,7 @@ static void symbol_basic_type_introduce(OnyxSemPassState* state, AstBasicType* b
 }
 
 static b32 symbol_unique_introduce(OnyxSemPassState* state, OnyxToken* tkn, AstNode* symbol) {
-    onyx_token_null_toggle(tkn);
+    token_toggle_end(tkn);
 
     // NOTE: If the function hasn't already been defined
     if (!bh_table_has(SemPassSymbol *, state->symbols, tkn->text)) {
@@ -115,11 +122,11 @@ static b32 symbol_unique_introduce(OnyxSemPassState* state, OnyxToken* tkn, AstN
                 tkn->text);
 
         // NOTE: I really wish C had defer...
-        onyx_token_null_toggle(tkn);
+        token_toggle_end(tkn);
         return 0;
     }
 
-    onyx_token_null_toggle(tkn);
+    token_toggle_end(tkn);
     return 1;
 }
 
@@ -165,12 +172,12 @@ static void symres_call(OnyxSemPassState* state, AstCall* call) {
     if (callee)
         call->callee = callee;
     else {
-        onyx_token_null_toggle(call->callee->token);
+        token_toggle_end(call->callee->token);
         onyx_message_add(state->msgs,
                 ONYX_MESSAGE_TYPE_UNKNOWN_SYMBOL,
                 call->callee->token->pos,
                 call->callee->token->text);
-        onyx_token_null_toggle(call->callee->token);
+        token_toggle_end(call->callee->token);
         return;
     }
 
@@ -315,6 +322,10 @@ static void symres_function(OnyxSemPassState* state, AstFunction* func) {
     }
 }
 
+static void symres_global(OnyxSemPassState* state, AstGlobal* global) {
+    global->base.type_node = symres_type(state, global->base.type_node);
+}
+
 static void symres_top_node(OnyxSemPassState* state, AstNode** node) {
     switch ((*node)->kind) {
         case Ast_Kind_Call:
@@ -325,6 +336,10 @@ static void symres_top_node(OnyxSemPassState* state, AstNode** node) {
              symres_expression(state, (AstTyped **) node);
              break;
 
+        case Ast_Kind_Global:
+             symres_global(state, (AstGlobal *) *node);
+             break;
+
         case Ast_Kind_Function:
              symres_function(state, (AstFunction *) *node);
              break;
index 66123bff807320364dc7159a24f804302419887d..56a9a025fc2d8695b1df52a2c8b769343f354d62 100644 (file)
@@ -5,17 +5,17 @@
 // NOTE: Allows easier testing of types since most of the characters
 // corresponding to these values are not printable
 #if 1
-const WasmType WASM_TYPE_INT32 = 0x7F;
-const WasmType WASM_TYPE_INT64 = 0x7E;
-const WasmType WASM_TYPE_FLOAT32 = 0x7D;
-const WasmType WASM_TYPE_FLOAT64 = 0x7C;
-const WasmType WASM_TYPE_VOID = 0x00;
+#define WASM_TYPE_INT32   0x7F
+#define WASM_TYPE_INT64   0x7E
+#define WASM_TYPE_FLOAT32 0x7D
+#define WASM_TYPE_FLOAT64 0x7C
+#define WASM_TYPE_VOID    0x00
 #else
-const WasmType WASM_TYPE_INT32 = 'A';
-const WasmType WASM_TYPE_INT64 = 'B';
-const WasmType WASM_TYPE_FLOAT32 = 'C';
-const WasmType WASM_TYPE_FLOAT64 = 'D';
-const WasmType WASM_TYPE_VOID = '\0';
+#define WASM_TYPE_INT32   'A'
+#define WASM_TYPE_INT64   'B'
+#define WASM_TYPE_FLOAT32 'C'
+#define WASM_TYPE_FLOAT64 'D'
+#define WASM_TYPE_VOID    'E'
 #endif
 
 static const char* wi_string(WasmInstructionType wit) {
@@ -826,7 +826,7 @@ static void compile_function(OnyxWasmModule* mod, AstFunction* fd) {
     bh_arr_new(mod->allocator, wasm_func.code, 4);
 
     if (fd->base.flags & Ast_Flag_Exported) {
-        onyx_token_null_toggle(fd->exported_name);
+        token_toggle_end(fd->exported_name);
 
         i32 func_idx = (i32) bh_imap_get(&mod->func_map, (u64) fd);
 
@@ -837,7 +837,7 @@ static void compile_function(OnyxWasmModule* mod, AstFunction* fd) {
         bh_table_put(WasmExport, mod->exports, fd->exported_name->text, wasm_export);
         mod->export_count++;
 
-        onyx_token_null_toggle(fd->exported_name);
+        token_toggle_end(fd->exported_name);
     }
 
     // If there is no body then don't process the code
@@ -880,22 +880,28 @@ static void compile_function(OnyxWasmModule* mod, AstFunction* fd) {
 }
 
 static void compile_global_declaration(OnyxWasmModule* module, AstGlobal* global) {
+    WasmType global_type = onyx_type_to_wasm_type(global->base.type);
+
+    if (global->base.flags & Ast_Flag_Foreign) {
+        WasmImport import = {
+            .kind = WASM_FOREIGN_GLOBAL,
+            .idx  = global_type,
+            .mod  = global->foreign_module,
+            .name = global->foreign_name,
+        };
+
+        bh_arr_push(module->imports, import);
+        return;
+    }
+
     WasmGlobal glob = {
-        .type = onyx_type_to_wasm_type(global->base.type),
+        .type = global_type,
         .mutable = (global->base.flags & Ast_Flag_Const) == 0,
         .initial_value = NULL,
     };
 
-    if (!global->initial_value) {
-        onyx_message_add(module->msgs,
-                ONYX_MESSAGE_TYPE_LITERAL,
-                global->base.token->pos,
-                "global without initial value");
-        return;
-    }
-
     if ((global->base.flags & Ast_Flag_Exported) != 0) {
-        onyx_token_null_toggle(global->base.token);
+        token_toggle_end(global->exported_name);
 
         i32 global_idx = (i32) bh_imap_get(&module->func_map, (u64) global);
 
@@ -903,46 +909,24 @@ static void compile_global_declaration(OnyxWasmModule* module, AstGlobal* global
             .kind = WASM_FOREIGN_GLOBAL,
             .idx = global_idx,
         };
-        bh_table_put(WasmExport, module->exports, global->base.token->text, wasm_export);
+        bh_table_put(WasmExport, module->exports, global->exported_name->text, wasm_export);
         module->export_count++;
 
-        onyx_token_null_toggle(global->base.token);
+        token_toggle_end(global->exported_name);
     }
 
-    compile_expression(module, &glob.initial_value, global->initial_value);
-    bh_arr_push(module->globals, glob);
-}
+    bh_arr_new(global_heap_allocator, glob.initial_value, 1);
 
-static void compile_foreign(OnyxWasmModule* module, AstForeign* foreign) {
-    if (foreign->import->kind == Ast_Kind_Function) {
-        i32 type_idx = generate_type_idx(module, (AstFunction *) foreign->import);
+    switch (global_type) {
+        case WASM_TYPE_INT32:   bh_arr_push(glob.initial_value, ((WasmInstruction) { WI_I32_CONST, 0 })); break;
+        case WASM_TYPE_INT64:   bh_arr_push(glob.initial_value, ((WasmInstruction) { WI_I64_CONST, 0 })); break;
+        case WASM_TYPE_FLOAT32: bh_arr_push(glob.initial_value, ((WasmInstruction) { WI_F32_CONST, 0 })); break;
+        case WASM_TYPE_FLOAT64: bh_arr_push(glob.initial_value, ((WasmInstruction) { WI_F64_CONST, 0 })); break;
 
-        WasmImport import = {
-            .kind = WASM_FOREIGN_FUNCTION,
-            .idx = type_idx,
-            .mod = foreign->mod_token,
-            .name = foreign->name_token,
-        };
-
-        bh_arr_push(module->imports, import);
-
-    } else if (foreign->import->kind == Ast_Kind_Global) {
-        WasmType global_type = onyx_type_to_wasm_type(((AstGlobal *) foreign->import)->base.type);
-
-        WasmImport import = {
-            .kind = WASM_FOREIGN_GLOBAL,
-            .idx = global_type,
-            .mod = foreign->mod_token,
-            .name = foreign->name_token,
-        };
-
-        bh_arr_push(module->imports, import);
-
-    } else {
-        DEBUG_HERE;
-        // NOTE: Invalid foreign
-        assert(0);
+        default: assert(("Invalid global type", 0)); break;
     }
+
+    bh_arr_push(module->globals, glob);
 }
 
 OnyxWasmModule onyx_wasm_module_create(bh_allocator alloc, OnyxMessages* msgs) {
@@ -994,6 +978,12 @@ void onyx_wasm_module_compile(OnyxWasmModule* module, ParserOutput* program) {
         }
     }
 
+    bh_arr_each(AstGlobal *, global, program->globals) {
+        if ((*global)->base.flags & Ast_Flag_Foreign) {
+            bh_imap_put(&module->global_map, (u64) *global, module->next_global_idx++);
+        }
+    }
+
     bh_arr_each(AstFunction *, function, program->functions) {
         if ((*function)->base.flags & Ast_Flag_Foreign) continue;
 
@@ -1001,7 +991,16 @@ void onyx_wasm_module_compile(OnyxWasmModule* module, ParserOutput* program) {
             bh_imap_put(&module->func_map, (u64) *function, module->next_func_idx++);
     }
 
+    bh_arr_each(AstGlobal *, global, program->globals) {
+        if ((*global)->base.flags & Ast_Flag_Foreign) continue;
+
+        bh_imap_put(&module->global_map, (u64) *global, module->next_global_idx++);
+    }
+
     // NOTE: Then, compile everything
+    bh_arr_each(AstGlobal *, global, program->globals)
+        compile_global_declaration(module, *global);
+
     bh_arr_each(AstFunction *, function, program->functions)
         compile_function(module, *function);