added the basic of static if statements; complex cases are broken
authorBrendan Hansen <brendan.f.hansen@gmail.com>
Sat, 6 Feb 2021 17:55:11 +0000 (11:55 -0600)
committerBrendan Hansen <brendan.f.hansen@gmail.com>
Sat, 6 Feb 2021 17:55:11 +0000 (11:55 -0600)
bin/onyx
include/onyxastnodes.h
include/onyxparser.h
onyx.exe
src/onyx.c
src/onyxastnodes.c
src/onyxchecker.c
src/onyxentities.c
src/onyxparser.c
src/onyxsymres.c
src/onyxutils.c

index 103abee57dbd8dbaa2ab45f7c90670a8b7537426..231b7cdc33e74eea79963732e1d12c41c12ea6d1 100755 (executable)
Binary files a/bin/onyx and b/bin/onyx differ
index f8217c5b1b7d0edaaac582964d00325118256c27..0f440843f1d811310129bd25349179df5bb5c882 100644 (file)
@@ -897,6 +897,7 @@ typedef enum EntityType {
     Entity_Type_Load_File,
     Entity_Type_Binding,
     Entity_Type_Use_Package,
+    Entity_Type_Static_If,
     Entity_Type_String_Literal,
     Entity_Type_File_Contents,
     Entity_Type_Enum,
@@ -930,6 +931,7 @@ typedef struct Entity {
         AstInclude            *include;
         AstUsePackage         *use_package;
         AstBinding            *binding;
+        AstStaticIf           *static_if;
         AstFunction           *function;
         AstOverloadedFunction *overloaded_function;
         AstGlobal             *global;
@@ -957,7 +959,9 @@ void entity_heap_insert(EntityHeap* entities, Entity e);
 Entity* entity_heap_top(EntityHeap* entities);
 void entity_heap_change_top(EntityHeap* entities, Entity* new_top);
 void entity_heap_remove_top(EntityHeap* entities);
-void add_entities_for_node(AstNode* node, Scope* scope, Package* package);
+
+// If target_arr is null, the entities will be placed directly in the heap.
+void add_entities_for_node(bh_arr(Entity *)* target_arr, AstNode* node, Scope* scope, Package* package);
 
 void entity_bring_to_state(Entity* ent, EntityState state);
 void symres_entity(Entity* ent);
index c41622c91684b651aaf3ad390398a43d1a5c6d64..1f5112ef190a95fd7448efd445d9f1fc7bbe6cea 100644 (file)
@@ -26,6 +26,7 @@ typedef struct OnyxParser {
     PolymorphicContext polymorph_context;
 
     bh_arr(Scope *) scope_stack;
+    bh_arr(AstStaticIf *) static_if_stack;
 
     b32 hit_unexpected_token : 1;
 } OnyxParser;
index acff63a61a6562e68cafef39c7799378f72172ef..23f07482c2992ac3af58dae53a1d30e3e9af7e5c 100644 (file)
Binary files a/onyx.exe and b/onyx.exe differ
index 55bbecabf61c13d05dc3148989e8f1c242055faa..3c7a01bb0944ec3f1d8539ce1b2f1de7f42493a0 100644 (file)
@@ -124,9 +124,12 @@ typedef enum CompilerProgress {
     ONYX_COMPILER_PROGRESS_SUCCESS
 } CompilerProgress;
 
+static OnyxToken implicit_load_token = { '#', 1, 0, { 0, 0, 0, 0, 0 } };
 static AstInclude* create_load(bh_allocator alloc, char* filename) {
+
     AstInclude* include_node = onyx_ast_node_new(alloc, sizeof(AstInclude), Ast_Kind_Load_File);
     include_node->name = filename;
+    include_node->token = &implicit_load_token;
 
     return include_node;
 }
@@ -162,12 +165,12 @@ static void context_init(CompileOptions* opts) {
         .include = create_load(context.ast_alloc, "core/builtin"),
     }));
     
-    add_entities_for_node((AstNode *) &builtin_stack_top, context.global_scope, NULL);
+    add_entities_for_node(NULL, (AstNode *) &builtin_stack_top, context.global_scope, NULL);
 
     // NOTE: Add all files passed by command line to the queue
     bh_arr_each(const char *, filename, opts->files) {
         AstInclude* load_node = create_load(context.ast_alloc, (char *) *filename);
-        add_entities_for_node((AstNode *) load_node, context.global_scope, NULL);
+        add_entities_for_node(NULL, (AstNode *) load_node, context.global_scope, NULL);
     }
 }
 
@@ -226,7 +229,7 @@ static void parse_source_file(bh_file_contents* file_contents) {
     onyx_parser_free(&parser);
 }
 
-static void process_source_file(char* filename) {
+static void process_source_file(char* filename, OnyxFilePos error_pos) {
     bh_arr_each(bh_file_contents, fc, context.loaded_files) {
         // CLEANUP: Add duplicate resolutions, such as
         //          ./foo and ./test/../foo
@@ -237,7 +240,7 @@ static void process_source_file(char* filename) {
     bh_file file;
     bh_file_error err = bh_file_open(&file, filename);
     if (err != BH_FILE_ERROR_NONE) {
-        onyx_report_error((OnyxFilePos) { 0 }, "Failed to open file %s\n", filename);
+        onyx_report_error(error_pos, "Failed to open file %s", filename);
         return;
     }
 
@@ -260,7 +263,7 @@ static void process_load_entity(Entity* ent) {
         char* filename = lookup_included_file(include->name);
         char* formatted_name = bh_strdup(global_heap_allocator, filename);
 
-        process_source_file(formatted_name);
+        process_source_file(formatted_name, include->token->pos);
 
     } else if (include->kind == Ast_Kind_Load_Path) {
         bh_arr_push(context.options->included_folders, include->name);
@@ -310,8 +313,12 @@ static b32 process_entity(Entity* ent) {
             ent->state = Entity_State_Finalized;
             break;
 
+        case Entity_State_Comptime_Resolve_Symbols:
         case Entity_State_Resolve_Symbols: symres_entity(ent); break;
+
+        case Entity_State_Comptime_Check_Types:
         case Entity_State_Check_Types:     check_entity(ent);  break;
+        
         case Entity_State_Code_Gen:        emit_entity(ent);   break;
 
         default:
index 89f7cba4a6790f14bf8da16cd3f6c2b50c5ce40e..d7a700c142ba167608f39447de666138a68afde8 100644 (file)
@@ -124,6 +124,7 @@ const char* entity_type_strings[Entity_Type_Count] = {
     "Load File",
     "Binding (Declaration)",
     "Use Package",
+    "Static If",
     "String Literal",
     "File Contents",
     "Enum",
index 51de8a54f8b82d90d5e5ece4bdbc813d23b47f41..0de1b0d998b3749928d3b6ddb2a6af09ece39b34 100644 (file)
@@ -8,12 +8,15 @@
 
 #define CHECK(kind, ...) do { \
     CheckStatus cs = check_ ## kind (__VA_ARGS__); \
-    if (cs != Check_Success) return cs; \
+    if (cs > Check_Errors_Start) return cs; \
     } while (0)
 
 typedef enum CheckStatus {
-    Check_Success,
-    Check_Error,
+    Check_Success,  // The node was successfully checked with out errors
+    Check_Complete, // The node is done processing
+
+    Check_Errors_Start,
+    Check_Error,    // There was an error when checking the node
 } CheckStatus;
 
 CheckStatus check_block(AstBlock* block);
@@ -1794,6 +1797,27 @@ CheckStatus check_type(AstType* type) {
     return Check_Success;
 }
 
+CheckStatus check_static_if(AstStaticIf* static_if) {
+    CHECK(expression, &static_if->cond);
+
+    if (static_if->cond->flags & Ast_Flag_Comptime) {
+        AstNumLit* condition_value = (AstNumLit *) static_if->cond;
+        assert(condition_value->kind == Ast_Kind_NumLit); // This should be right, right?
+
+        if (condition_value->value.i) {
+            bh_arr_each(Entity *, ent, static_if->true_entities) {
+                entity_heap_insert_existing(&context.entities, *ent);
+            }
+        }
+
+    } else {
+        onyx_report_error(static_if->token->pos, "Expected this condition to be compile time known.");
+        return Check_Error;
+    }
+
+    return Check_Complete;
+}
+
 CheckStatus check_node(AstNode* node) {
     switch (node->kind) {
         case Ast_Kind_Function:             return check_function((AstFunction *) node);
@@ -1838,7 +1862,7 @@ void check_entity(Entity* ent) {
             if (ent->type_alias->kind == Ast_Kind_Struct_Type)
                 cs = check_struct((AstStructType *) ent->type_alias);
             else
-                check_type(ent->type_alias);
+                cs = check_type(ent->type_alias);
             break;
 
         case Entity_Type_Memory_Reservation_Type:
@@ -1849,12 +1873,15 @@ void check_entity(Entity* ent) {
             cs = check_memres(ent->mem_res);
             break;
 
+        case Entity_Type_Static_If:
+            cs = check_static_if(ent->static_if);
+            break;
+
         default: break;
     }
 
-    if (cs == Check_Success) {
-        ent->state = Entity_State_Code_Gen;
-    }
+    if (cs == Check_Success)  ent->state = Entity_State_Code_Gen;
+    if (cs == Check_Complete) ent->state = Entity_State_Finalized;
     // else if (cs == Check_Yield) {
     //     ent->attempts++;
     // }
index 2164fbfdb4e45aa459baf21a6b4d05e29f816e6a..40945214aba505caa3e4e2d9529638af005f0f3d 100644 (file)
@@ -101,7 +101,18 @@ void entity_heap_remove_top(EntityHeap* entities) {
 }
 
 // NOTE(Brendan Hansen): Uses the entity heap in the context structure
-void add_entities_for_node(AstNode* node, Scope* scope, Package* package) {
+void add_entities_for_node(bh_arr(Entity *) *target_arr, AstNode* node, Scope* scope, Package* package) {
+#define ENTITY_INSERT(_ent) {                                   \
+    Entity* entity = entity_heap_register(entities, _ent);       \
+    if (target_arr) {                                           \
+        bh_arr(Entity *) __tmp_arr = *target_arr;               \
+        bh_arr_push(__tmp_arr, entity);                         \
+        *target_arr = __tmp_arr;                                \
+    } else {                                                    \
+        entity_heap_insert_existing(entities, entity);          \
+    }                                                           \
+    }
+
     EntityHeap* entities = &context.entities;
     
     Entity ent;
@@ -114,7 +125,7 @@ void add_entities_for_node(AstNode* node, Scope* scope, Package* package) {
             ent.state = Entity_State_Parse;
             ent.type = Entity_Type_Load_File;
             ent.include = (AstInclude *) node;
-            entity_heap_insert(entities, ent);
+            ENTITY_INSERT(ent);
             break;
         }
         
@@ -122,7 +133,7 @@ void add_entities_for_node(AstNode* node, Scope* scope, Package* package) {
             ent.state = Entity_State_Parse;
             ent.type = Entity_Type_Load_Path;
             ent.include = (AstInclude *) node;
-            entity_heap_insert(entities, ent);
+            ENTITY_INSERT(ent);
             break;
         }
         
@@ -130,7 +141,7 @@ void add_entities_for_node(AstNode* node, Scope* scope, Package* package) {
             ent.state   = Entity_State_Introduce_Symbols;
             ent.type    = Entity_Type_Binding;
             ent.binding = (AstBinding *) node;
-            entity_heap_insert(entities, ent);
+            ENTITY_INSERT(ent);
             break;
         }
         
@@ -138,16 +149,16 @@ void add_entities_for_node(AstNode* node, Scope* scope, Package* package) {
             if ((node->flags & Ast_Flag_Foreign) != 0) {
                 ent.type     = Entity_Type_Foreign_Function_Header;
                 ent.function = (AstFunction *) node;
-                entity_heap_insert(entities, ent);
+                ENTITY_INSERT(ent);
                 
             } else {
                 ent.type     = Entity_Type_Function_Header;
                 ent.function = (AstFunction *) node;
-                entity_heap_insert(entities, ent);
+                ENTITY_INSERT(ent);
                 
                 ent.type     = Entity_Type_Function;
                 ent.function = (AstFunction *) node;
-                entity_heap_insert(entities, ent);
+                ENTITY_INSERT(ent);
             }
             break;
         }
@@ -155,7 +166,7 @@ void add_entities_for_node(AstNode* node, Scope* scope, Package* package) {
         case Ast_Kind_Overloaded_Function: {
             ent.type                = Entity_Type_Overloaded_Function;
             ent.overloaded_function = (AstOverloadedFunction *) node;
-            entity_heap_insert(entities, ent);
+            ENTITY_INSERT(ent);
             break;
         }
         
@@ -163,16 +174,16 @@ void add_entities_for_node(AstNode* node, Scope* scope, Package* package) {
             if ((node->flags & Ast_Flag_Foreign) != 0) {
                 ent.type   = Entity_Type_Foreign_Global_Header;
                 ent.global = (AstGlobal *) node;
-                entity_heap_insert(entities, ent);
+                ENTITY_INSERT(ent);
                 
             } else {
                 ent.type   = Entity_Type_Global_Header;
                 ent.global = (AstGlobal *) node;
-                entity_heap_insert(entities, ent);
+                ENTITY_INSERT(ent);
                 
                 ent.type   = Entity_Type_Global;
                 ent.global = (AstGlobal *) node;
-                entity_heap_insert(entities, ent);
+                ENTITY_INSERT(ent);
             }
             break;
         }
@@ -180,21 +191,21 @@ void add_entities_for_node(AstNode* node, Scope* scope, Package* package) {
         case Ast_Kind_StrLit: {
             ent.type   = Entity_Type_String_Literal;
             ent.strlit = (AstStrLit *) node;
-            entity_heap_insert(entities, ent);
+            ENTITY_INSERT(ent);
             break;
         }
         
         case Ast_Kind_File_Contents: {
             ent.type = Entity_Type_File_Contents;
             ent.file_contents = (AstFileContents *) node;
-            entity_heap_insert(entities, ent);
+            ENTITY_INSERT(ent);
             break;
         }
         
         case Ast_Kind_Struct_Type: {
             ent.type = Entity_Type_Struct_Member_Default;
             ent.type_alias = (AstType *) node;
-            entity_heap_insert(entities, ent);
+            ENTITY_INSERT(ent);
             // fallthrough
         }
         
@@ -202,53 +213,62 @@ void add_entities_for_node(AstNode* node, Scope* scope, Package* package) {
         case Ast_Kind_Type_Alias: {
             ent.type = Entity_Type_Type_Alias;
             ent.type_alias = (AstType *) node;
-            entity_heap_insert(entities, ent);
+            ENTITY_INSERT(ent);
             break;
         }
         
         case Ast_Kind_Enum_Type: {
             ent.type = Entity_Type_Enum;
             ent.enum_type = (AstEnumType *) node;
-            entity_heap_insert(entities, ent);
+            ENTITY_INSERT(ent);
             break;
         }
         
         case Ast_Kind_Use_Package: {
+            ent.state = Entity_State_Comptime_Resolve_Symbols;
             ent.type = Entity_Type_Use_Package;
             ent.use_package = (AstUsePackage *) node;
-            entity_heap_insert(entities, ent);
+            ENTITY_INSERT(ent);
             break;
         }
         
         case Ast_Kind_Use: {
             ent.type = Entity_Type_Use;
             ent.use = (AstUse *) node;
-            entity_heap_insert(entities, ent);
+            ENTITY_INSERT(ent);
             break;
         }
         
         case Ast_Kind_Memres: {
             ent.type = Entity_Type_Memory_Reservation_Type;
             ent.mem_res = (AstMemRes *) node;
-            entity_heap_insert(entities, ent);
+            ENTITY_INSERT(ent);
             
             ent.type = Entity_Type_Memory_Reservation;
             ent.mem_res = (AstMemRes *) node;
-            entity_heap_insert(entities, ent);
+            ENTITY_INSERT(ent);
             break;
         }
         
         case Ast_Kind_Polymorphic_Proc: {
             ent.type = Entity_Type_Polymorphic_Proc;
             ent.poly_proc = (AstPolyProc *) node;
-            entity_heap_insert(entities, ent);
+            ENTITY_INSERT(ent);
+            break;
+        }
+
+        case Ast_Kind_Static_If: {
+            ent.state = Entity_State_Comptime_Resolve_Symbols;
+            ent.type = Entity_Type_Static_If;
+            ent.static_if = (AstStaticIf *) node;
+            ENTITY_INSERT(ent);
             break;
         }
         
         default: {
             ent.type = Entity_Type_Expression;
             ent.expr = (AstTyped *) node;
-            entity_heap_insert(entities, ent);
+            ENTITY_INSERT(ent);
             break;
         }
     }
index 14c2c38777b45a7e0aafa73085a096e2124aeaa7..bb140cb2fa579eb511d6ae129396a7f7518eb49f 100644 (file)
 #include "onyxparser.h"
 #include "onyxutils.h"
 
-// NOTE: The one weird define you need to know before read the code below
 #define make_node(nclass, kind)             onyx_ast_node_new(parser->allocator, sizeof(nclass), kind)
 #define peek_token(ahead)                   (parser->curr + ahead)
-#define ENTITY_SUBMIT(node)                 (add_entities_for_node((AstNode *) (node), bh_arr_last(parser->scope_stack), parser->package))
-#define ENTITY_SUBMIT_IN_SCOPE(node, scope) (add_entities_for_node((AstNode *) (node), scope, parser->package))
 
 static AstNode error_node = { Ast_Kind_Error, 0, NULL, NULL };
 
+#define ENTITY_SUBMIT(node)                 (submit_entity_in_scope(parser, (AstNode *) (node), bh_arr_last(parser->scope_stack), parser->package))
+#define ENTITY_SUBMIT_IN_SCOPE(node, scope) (submit_entity_in_scope(parser, (AstNode *) (node), scope, parser->package))
+
+void submit_entity_in_scope(OnyxParser* parser, AstNode* node, Scope* scope, Package* package) {
+    if (bh_arr_length(parser->static_if_stack) == 0) {
+        add_entities_for_node(NULL, node, scope, package);
+
+    } else {
+        AstStaticIf* static_if = bh_arr_last(parser->static_if_stack);
+
+        // nocheckin This should also be able to place them in the false entities
+        add_entities_for_node(&static_if->true_entities, node, scope, package);
+    }
+}
+
+// Parsing Utilities
 static void consume_token(OnyxParser* parser);
 static void unconsume_token(OnyxParser* parser);
 static OnyxToken* expect_token(OnyxParser* parser, TokenType token_type);
 static b32 consume_token_if_next(OnyxParser* parser, TokenType token_type);
+static b32 next_tokens_are(OnyxParser* parser, i32 n, ...);
+static OnyxToken* find_matching_paren(OnyxToken* paren);
 
 static AstNumLit*     parse_int_literal(OnyxParser* parser);
 static AstNumLit*     parse_float_literal(OnyxParser* parser);
@@ -54,7 +69,7 @@ static AstTyped*      parse_global_declaration(OnyxParser* parser);
 static AstEnumType*   parse_enum_declaration(OnyxParser* parser);
 static AstTyped*      parse_top_level_expression(OnyxParser* parser);
 static AstBinding*    parse_top_level_binding(OnyxParser* parser, OnyxToken* symbol);
-static AstNode*       parse_top_level_statement(OnyxParser* parser);
+static void           parse_top_level_statement(OnyxParser* parser);
 static AstPackage*    parse_package_name(OnyxParser* parser);
 
 static void consume_token(OnyxParser* parser) {
@@ -201,7 +216,7 @@ static AstNumLit* parse_float_literal(OnyxParser* parser) {
 }
 
 static b32 parse_possible_directive(OnyxParser* parser, const char* dir) {
-    if (parser->curr->type != '#') return 0;
+    if (peek_token(0)->type != '#' || peek_token(1)->type != Token_Type_Symbol) return 0;
 
     expect_token(parser, '#');
     OnyxToken* sym = expect_token(parser, Token_Type_Symbol);
@@ -2093,6 +2108,29 @@ static AstEnumType* parse_enum_declaration(OnyxParser* parser) {
     return enum_node;
 }
 
+static AstStaticIf* parse_static_if_stmt(OnyxParser* parser) {
+    AstStaticIf* static_if_node = make_node(AstStaticIf, Ast_Kind_Static_If);
+    static_if_node->token = expect_token(parser, '#');
+    expect_token(parser, Token_Type_Keyword_If);
+
+    static_if_node->cond = parse_expression(parser, 0);
+
+    // TODO: Add else statements to static ifs
+    bh_arr_new(global_heap_allocator, static_if_node->true_entities, 4);
+    bh_arr_push(parser->static_if_stack, static_if_node);
+
+    expect_token(parser, '{');
+    while (!consume_token_if_next(parser, '}')) {
+        if (parser->hit_unexpected_token) return static_if_node;
+
+        parse_top_level_statement(parser);
+    }
+
+    bh_arr_pop(parser->static_if_stack);
+
+    return static_if_node;
+}
+
 static AstTyped* parse_top_level_expression(OnyxParser* parser) {
     if (parser->curr->type == Token_Type_Keyword_Proc) {
         OnyxToken* proc_token = expect_token(parser, Token_Type_Keyword_Proc);
@@ -2176,38 +2214,33 @@ static AstBinding* parse_top_level_binding(OnyxParser* parser, OnyxToken* symbol
     return binding;
 }
 
-static AstNode* parse_top_level_statement(OnyxParser* parser) {
+static void parse_top_level_statement(OnyxParser* parser) {
     AstFlags private_kind = 0;
-    if (parse_possible_directive(parser, "private")) {
-        private_kind = Ast_Flag_Private_Package;
-    }
+    if      (parse_possible_directive(parser, "private"))      private_kind = Ast_Flag_Private_Package;
+    else if (parse_possible_directive(parser, "private_file")) private_kind = Ast_Flag_Private_File;
 
-    else if (parse_possible_directive(parser, "private_file")) {
-        private_kind = Ast_Flag_Private_File;
-    }
+    AstBinding* binding = NULL;
     
-    // CLEANUP
     switch ((u16) parser->curr->type) {
         case Token_Type_Keyword_Use: {
             AstNode* use_node = parse_use_stmt(parser);
             ENTITY_SUBMIT(use_node);
-            return NULL;
+            return;
         }
 
         case Token_Type_Keyword_Proc:
             parse_top_level_expression(parser);
-            return NULL;
+            return;
 
         case Token_Type_Symbol: {
             OnyxToken* symbol = expect_token(parser, Token_Type_Symbol);
             expect_token(parser, ':');
 
             if (parser->curr->type == ':') {
-                AstBinding* binding = parse_top_level_binding(parser, symbol);
-
+                binding = parse_top_level_binding(parser, symbol);
                 if (binding != NULL) binding->node->flags |= private_kind;
 
-                return (AstNode *) binding;
+                goto submit_binding_to_entities;
             }
             
             AstMemRes* memres = make_node(AstMemRes, Ast_Kind_Memres);
@@ -2223,52 +2256,56 @@ static AstNode* parse_top_level_statement(OnyxParser* parser) {
             
             ENTITY_SUBMIT(memres);
             
-            AstBinding* binding = make_node(AstBinding, Ast_Kind_Binding);
+            binding = make_node(AstBinding, Ast_Kind_Binding);
             binding->token = symbol;
             binding->node = (AstNode *) memres;
 
-            return (AstNode *) binding;
+            goto submit_binding_to_entities;
         }
 
         case '#': {
-            while (parser->curr->type == '#') {
-                OnyxToken* dir_token = parser->curr;
-
-                if (parse_possible_directive(parser, "load")) {
-                    AstInclude* include = make_node(AstInclude, Ast_Kind_Load_File);
-                    include->token = dir_token;
-
-                    OnyxToken* str_token = expect_token(parser, Token_Type_Literal_String);
-                    if (str_token != NULL) {
-                        token_toggle_end(str_token);
-                        include->name = bh_strdup(parser->allocator, str_token->text);
-                        token_toggle_end(str_token);
-                    }
-                    
-                    ENTITY_SUBMIT(include);
-                    return NULL;
+            if (next_tokens_are(parser, 2, '#', Token_Type_Keyword_If)) {
+                AstStaticIf* static_if = parse_static_if_stmt(parser);
+                ENTITY_SUBMIT(static_if);
+                return;
+            }
+
+            OnyxToken* dir_token = parser->curr;
+
+            if (parse_possible_directive(parser, "load")) {
+                AstInclude* include = make_node(AstInclude, Ast_Kind_Load_File);
+                include->token = dir_token;
+
+                OnyxToken* str_token = expect_token(parser, Token_Type_Literal_String);
+                if (str_token != NULL) {
+                    token_toggle_end(str_token);
+                    include->name = bh_strdup(parser->allocator, str_token->text);
+                    token_toggle_end(str_token);
                 }
-                else if (parse_possible_directive(parser, "load_path")) {
-                    AstInclude* include = make_node(AstInclude, Ast_Kind_Load_Path);
-                    include->token = dir_token;
-                    
-                    OnyxToken* str_token = expect_token(parser, Token_Type_Literal_String);
-                    if (str_token != NULL) {
-                        token_toggle_end(str_token);
-                        include->name = bh_strdup(parser->allocator, str_token->text);
-                        token_toggle_end(str_token);
-                    }
-                    
-                    ENTITY_SUBMIT(include);
-                    return NULL;
+                
+                ENTITY_SUBMIT(include);
+                return;
+            }
+            else if (parse_possible_directive(parser, "load_path")) {
+                AstInclude* include = make_node(AstInclude, Ast_Kind_Load_Path);
+                include->token = dir_token;
+                
+                OnyxToken* str_token = expect_token(parser, Token_Type_Literal_String);
+                if (str_token != NULL) {
+                    token_toggle_end(str_token);
+                    include->name = bh_strdup(parser->allocator, str_token->text);
+                    token_toggle_end(str_token);
                 }
-                else {
-                    OnyxToken* directive_token = expect_token(parser, '#');
-                    OnyxToken* symbol_token = expect_token(parser, Token_Type_Symbol);
+                
+                ENTITY_SUBMIT(include);
+                return;
+            }
+            else {
+                OnyxToken* directive_token = expect_token(parser, '#');
+                OnyxToken* symbol_token = expect_token(parser, Token_Type_Symbol);
 
-                    onyx_report_error(directive_token->pos, "unknown directive '#%b'.", symbol_token->text, symbol_token->length);
-                    return NULL;
-                }
+                onyx_report_error(directive_token->pos, "unknown directive '#%b'.", symbol_token->text, symbol_token->length);
+                return;
             }
         }
 
@@ -2276,7 +2313,21 @@ static AstNode* parse_top_level_statement(OnyxParser* parser) {
     }
 
     expect_token(parser, ';');
-    return NULL;
+    return;
+
+submit_binding_to_entities:
+    {
+        if (!binding) return;
+
+        Scope* target_scope = parser->package->scope;
+
+        if (binding->node->flags & Ast_Flag_Private_Package)
+            target_scope = parser->package->private_scope;
+        if (binding->node->flags & Ast_Flag_Private_File)
+            target_scope = parser->file_scope;
+        
+        ENTITY_SUBMIT_IN_SCOPE(binding, target_scope);
+    }
 }
 
 static AstPackage* parse_package_name(OnyxParser* parser) {
@@ -2350,6 +2401,7 @@ OnyxParser onyx_parser_create(bh_allocator alloc, OnyxTokenizer *tokenizer) {
     parser.prev = NULL;
     parser.hit_unexpected_token = 0;
     parser.scope_stack = NULL;
+    parser.static_if_stack = NULL;
 
     parser.polymorph_context = (PolymorphicContext) {
         .root_node = NULL,
@@ -2357,6 +2409,7 @@ OnyxParser onyx_parser_create(bh_allocator alloc, OnyxTokenizer *tokenizer) {
     };
 
     bh_arr_new(global_heap_allocator, parser.scope_stack, 4);
+    bh_arr_new(global_heap_allocator, parser.static_if_stack, 4);
 
     return parser;
 }
@@ -2378,33 +2431,9 @@ void onyx_parse(OnyxParser *parser) {
     ENTITY_SUBMIT(implicit_use_builtin);
     
     while (parser->curr->type != Token_Type_End_Stream) {
-        if (parser->hit_unexpected_token) return;
-
-        AstNode* curr_stmt = parse_top_level_statement(parser);
-
-        if (curr_stmt != NULL && curr_stmt != &error_node) {
-            while (curr_stmt != NULL) {
-                if (parser->hit_unexpected_token) return;
-
-                switch (curr_stmt->kind) {
-                    case Ast_Kind_Binding: {
-                        Scope* target_scope = parser->package->scope;
-
-                        if (((AstBinding *) curr_stmt)->node->flags & Ast_Flag_Private_Package)
-                            target_scope = parser->package->private_scope;
-                        if (((AstBinding *) curr_stmt)->node->flags & Ast_Flag_Private_File)
-                            target_scope = parser->file_scope;
-                        
-                        ENTITY_SUBMIT_IN_SCOPE(curr_stmt, target_scope);
-                        break;
-                    }
-
-                    default: assert(("Invalid top level node", 0));
-                }
-
-                curr_stmt = curr_stmt->next;
-            }
-        }
+        if (parser->hit_unexpected_token) break;
+        if (onyx_has_errors()) break;
+        parse_top_level_statement(parser);
     }
 
     bh_arr_pop(parser->scope_stack);
index 4d54afb413c8233f59193ec941a41bff6862ad4f..3c914c13c2e703736a2538bc154693f8d8a6aeb3 100644 (file)
@@ -9,6 +9,7 @@ static Scope*       curr_scope    = NULL;
 static Package*     curr_package  = NULL;
 static AstFunction* curr_function = NULL;
 bh_arr(AstBlock *)  block_stack   = NULL;
+static b32 report_unresolved_symbols = 1;
 
 AstType* symres_type(AstType* type);
 static void symres_local(AstLocal** local, b32 add_to_block_locals);
@@ -37,6 +38,7 @@ static void symres_enum(AstEnumType* enum_node);
 static void symres_memres_type(AstMemRes** memres);
 static void symres_memres(AstMemRes** memres);
 static void symres_struct_defaults(AstType* st);
+static void symres_static_if(AstStaticIf* static_if);
 
 static void scope_enter(Scope* new_scope) {
     curr_scope = new_scope;
@@ -46,6 +48,20 @@ static void scope_leave() {
     curr_scope = curr_scope->parent;
 }
 
+static void symres_symbol(AstNode** symbol_node) {
+    OnyxToken* token = (*symbol_node)->token;
+    AstNode* res = symbol_resolve(curr_scope, token);    
+
+    if (!res) { // :SymresStall
+        onyx_report_error(token->pos,
+            "Unable to resolve symbol '%b'",
+            token->text,
+            token->length);
+    } else {
+        *symbol_node = res;
+    }
+}
+
 AstType* symres_type(AstType* type) {
     if (type == NULL) return NULL;
 
@@ -55,7 +71,8 @@ AstType* symres_type(AstType* type) {
     }
 
     if (type->kind == Ast_Kind_Symbol) {
-        return (AstType *) symbol_resolve(curr_scope, ((AstNode *) type)->token);
+        symres_symbol((AstNode **) &type);
+        return type;
     }
 
     if (type->kind == Ast_Kind_Field_Access) {
@@ -387,9 +404,7 @@ static void symres_expression(AstTyped** expr) {
     }
 
     switch ((*expr)->kind) {
-        case Ast_Kind_Symbol:
-            *expr = (AstTyped *) symbol_resolve(curr_scope, ((AstNode *) *expr)->token);
-            break;
+        case Ast_Kind_Symbol: symres_symbol((AstNode **) expr); break;
 
         case Ast_Kind_Binary_Op:
             symres_expression(&((AstBinaryOp *)(*expr))->left);
@@ -825,8 +840,8 @@ static void symres_use_package(AstUsePackage* package) {
         bh_arr_each(AstAlias *, alias, package->only) {
 
             AstNode* thing = symbol_resolve(p->scope, (*alias)->token);
-            if (thing == NULL) {
-                onyx_report_error((*alias)->token->pos, "not found in package");
+            if (thing == NULL) { // :SymresStall
+                onyx_report_error((*alias)->token->pos, "This symbol was not found in this package.");
                 return;
             }
 
@@ -844,9 +859,7 @@ static void symres_use_package(AstUsePackage* package) {
 }
 
 static void symres_enum(AstEnumType* enum_node) {
-    if (enum_node->backing->kind == Ast_Kind_Symbol) {
-        enum_node->backing = (AstType *) symbol_resolve(curr_scope, enum_node->backing->token);
-    }
+    if (enum_node->backing->kind == Ast_Kind_Symbol) symres_symbol((AstNode **) &enum_node->backing);
     if (enum_node->backing == NULL) return;
 
     enum_node->backing_type = type_build_from_ast(context.ast_alloc, enum_node->backing);
@@ -942,6 +955,10 @@ static void symres_polyproc(AstPolyProc* pp) {
     }
 }
 
+static void symres_static_if(AstStaticIf* static_if) {
+    symres_expression(&static_if->cond);
+}
+
 void symres_entity(Entity* ent) {
     if (block_stack == NULL)
         bh_arr_new(global_heap_allocator, block_stack, 16);
@@ -962,6 +979,12 @@ void symres_entity(Entity* ent) {
             next_state = Entity_State_Finalized;
             break;
         }
+
+        case Entity_Type_Static_If: {
+            symres_static_if(ent->static_if);
+            next_state = Entity_State_Comptime_Check_Types;
+            break;
+        }
         
         case Entity_Type_Foreign_Function_Header:
         case Entity_Type_Function_Header:         symres_function_header(ent->function); break;
index b1d99c21da39c2ae76fa2d82682d17f2603bca46..c13a654e57acee1855c299580487b01a586290dd 100644 (file)
@@ -129,14 +129,8 @@ AstNode* symbol_raw_resolve(Scope* start_scope, char* sym) {
 AstNode* symbol_resolve(Scope* start_scope, OnyxToken* tkn) {
     token_toggle_end(tkn);
     AstNode* res = symbol_raw_resolve(start_scope, tkn->text);
-
-    if (res == NULL) {
-        onyx_report_error(tkn->pos, "Unable to resolve symbol '%s'.", tkn->text);
-        token_toggle_end(tkn);
-        return &empty_node;
-    }
-
     token_toggle_end(tkn);
+    
     return res;
 }