Completely refactored scope logic
authorBrendan Hansen <brendan.f.hansen@gmail.com>
Sat, 18 Jul 2020 17:43:20 +0000 (12:43 -0500)
committerBrendan Hansen <brendan.f.hansen@gmail.com>
Sat, 18 Jul 2020 17:43:20 +0000 (12:43 -0500)
include/onyxastnodes.h
include/onyxmsgs.h
include/onyxsempass.h
onyx
src/onyxchecker.c
src/onyxmsgs.c
src/onyxparser.c
src/onyxsempass.c
src/onyxsymres.c
src/onyxutils.c

index 3333e0a91f34d82f8854e72916d746267714eb67..f297648935d416d1fc69fa370632676f33dc2846 100644 (file)
@@ -4,6 +4,7 @@
 #include "onyxlex.h"
 #include "onyxtypes.h"
 
+
 typedef struct AstNode AstNode;
 typedef struct AstTyped AstTyped;
 
@@ -22,7 +23,6 @@ typedef struct AstReturn AstReturn;
 typedef struct AstBlock AstBlock;
 typedef struct AstIf AstIf;
 typedef struct AstWhile AstWhile;
-typedef struct AstLocalGroup AstLocalGroup;
 
 typedef struct AstType AstType;
 typedef struct AstBasicType AstBasicType;
@@ -35,6 +35,15 @@ typedef struct AstGlobal AstGlobal;
 typedef struct AstFunction AstFunction;
 typedef struct AstOverloadedFunction AstOverloadedFunction;
 
+
+typedef struct Scope {
+    struct Scope *parent;
+    bh_table(AstNode *) symbols;
+} Scope;
+
+extern Scope* scope_create(bh_allocator a, Scope* parent);
+
+
 typedef enum AstKind {
     Ast_Kind_Error,
     Ast_Kind_Program,
@@ -195,8 +204,7 @@ struct AstArrayAccess   { AstTyped_base; AstTyped *addr; AstTyped *expr; u64 ele
 struct AstReturn        { AstNode_base;  AstTyped* expr; };
 
 // Structure Nodes
-struct AstLocalGroup    { AstNode_base;  AstLocalGroup *prev_group; AstLocal *last_local; };
-struct AstBlock         { AstNode_base;  AstNode *body; AstLocalGroup *locals; };
+struct AstBlock         { AstNode_base;  AstNode *body; Scope *scope; };
 struct AstWhile         { AstNode_base;  AstTyped *cond; AstNode *stmt; };
 struct AstIf {
     AstNode_base;
@@ -240,6 +248,7 @@ struct AstGlobal        {
 struct AstFunction      {
     AstTyped_base;
 
+    Scope *scope;
     AstBlock *body;
     AstLocal *params;
     bh_arr(AstLocal *) locals;
index 9c23a1a42d214cbd9320452da0d501eeb788ab49..8c9afeee286b56ba135f8a9d991d7b42bfcf84c3 100644 (file)
@@ -18,7 +18,7 @@ typedef enum OnyxMessageType {
     ONYX_MESSAGE_TYPE_UNKNOWN_SYMBOL,
     ONYX_MESSAGE_TYPE_UNKNOWN_DIRECTIVE,
 
-    ONYX_MESSAGE_TYPE_CONFLICTING_GLOBALS,
+    ONYX_MESSAGE_TYPE_REDECLARE_SYMBOL,
     ONYX_MESSAGE_TYPE_BINOP_MISMATCH_TYPE,
     ONYX_MESSAGE_TYPE_ASSIGNMENT_TYPE_MISMATCH,
     ONYX_MESSAGE_TYPE_GLOBAL_TYPE_MISMATCH,
index 97114bcfad39d0a86a2d404c4afe84ee52941e91..c9227a04915e63064b713c04bab29846a9ab8efb 100644 (file)
@@ -7,11 +7,6 @@
 #include "onyxastnodes.h"
 #include "onyxmsgs.h"
 
-typedef struct SemSymbol {
-    AstNode *node;
-    struct SemSymbol *shadowed;
-} SemSymbol;
-
 typedef struct SemState {
     // NOTE: Adding node_allocator in case we need
     // to make any more node in the tree
@@ -19,14 +14,12 @@ typedef struct SemState {
     OnyxMessages *msgs;
 
     // NOTE: Used in symbol resolution phase
-    AstLocalGroup* curr_local_group;
+    Scope*         global_scope;
+    Scope*         curr_scope;
     AstFunction*   curr_function;
 
     // NOTE: Used in type checking phase
     Type* expected_return_type;
-
-    // NOTE: All symbols a given point that we can resolve
-    bh_table(SemSymbol *) symbols;
 } SemState;
 
 // NOTE: Resolving all symbols in the tree
diff --git a/onyx b/onyx
index c54562e335a7617c2e847d83a3e31385ae978865..b356f8a4dedf47c866d40633a76409a632a8a61c 100755 (executable)
Binary files a/onyx and b/onyx differ
index c8b4761b6b19cc1941e01d959b230fa19bd47dae..709a76829842a3801abe1752d5b74e27d88acf2d 100644 (file)
@@ -509,15 +509,15 @@ CHECK(statement_chain, AstNode* start) {
 CHECK(block, AstBlock* block) {
     if (check_statement_chain(state, block->body)) return 1;
 
-    forll(AstLocal, local, block->locals->last_local, prev_local) {
-        if (local->type == NULL) {
+    bh_table_each_start(AstTyped *, block->scope->symbols);
+        if (value->type == NULL) {
             onyx_message_add(state->msgs,
                     ONYX_MESSAGE_TYPE_UNRESOLVED_TYPE,
-                    local->token->pos,
-                    local->token->text, local->token->length);
+                    value->token->pos,
+                    value->token->text, value->token->length);
             return 1;
         }
-    }
+    bh_table_each_end;
 
     return 0;
 }
index f7a6e52b4152232ecdcfb3e0b79156fd41a08dda..15768a387202d631e78b63e4faae011b6b6cc2aa 100644 (file)
@@ -14,7 +14,7 @@ static const char* msg_formats[] = {
     "unknown symbol '%s'",
     "unknown directive '%b'",
 
-    "conflicting declarations of global '%s'",
+    "redeclaration of symbol '%s'",
     "mismatched types for binary operator, '%s', '%s'",
     "mismatched types on assignment, expected '%s', got '%s'",
     "mismatched types for global '%b'; expected '%s', got '%s'",
index 8895cc427400eee5cfe7fb3e8abbcec2fafe0956..641c32d985eb224855f35339f9c7f50c79cb9e4f 100644 (file)
@@ -615,8 +615,6 @@ static AstNode* parse_statement(OnyxParser* parser) {
 // '{' <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->type == Token_Type_Empty_Block) {
index 0b502c6edcfbae67632625efb12b404aa49ab942..6d7936809302d49a07871a448d47381a3f76cfd6 100644 (file)
@@ -7,14 +7,12 @@ SemState onyx_sempass_create(bh_allocator alloc, bh_allocator node_alloc, OnyxMe
         .allocator = alloc,
         .node_allocator = node_alloc,
 
-        .msgs = msgs,
+        .global_scope = NULL,
+        .curr_scope = NULL,
 
-        .curr_local_group = NULL,
-        .symbols = NULL,
+        .msgs = msgs,
     };
 
-    bh_table_init(global_heap_allocator, state.symbols, 61);
-
     return state;
 }
 
index 37fa53071fa268ffcd271686a7c8aa1beb832d7b..c9779517bfca622c300d85a4610fcca3f715ba46 100644 (file)
@@ -1,13 +1,11 @@
 #define BH_DEBUG
 #include "onyxsempass.h"
 
-static void symbol_introduce(SemState* state, OnyxToken* tkn, AstNode* symbol);
-static void symbol_basic_type_introduce(SemState* state, AstBasicType* basic_type);
-static b32 symbol_unique_introduce(SemState* state, OnyxToken* tkn, AstNode* symbol);
-static void symbol_remove(SemState* state, OnyxToken* tkn);
+static b32  symbol_introduce(SemState* state, OnyxToken* tkn, AstNode* symbol);
 static AstNode* symbol_resolve(SemState* state, OnyxToken* tkn);
-static void local_group_enter(SemState* state, AstLocalGroup* local_group);
-static void local_group_leave(SemState* state);
+static void symbol_basic_type_introduce(SemState* state, AstBasicType* basic_type);
+static void scope_enter(SemState* state, Scope* new_scope);
+static void scope_leave(SemState* state);
 
 static AstType* symres_type(SemState* state, AstType* type);
 static void symres_local(SemState* state, AstLocal** local);
@@ -23,113 +21,71 @@ static void symres_function(SemState* state, AstFunction* func);
 static void symres_global(SemState* state, AstGlobal* global);
 static void symres_overloaded_function(SemState* state, AstOverloadedFunction* ofunc);
 
-static void symbol_introduce(SemState* state, OnyxToken* tkn, AstNode* symbol) {
+static b32 symbol_introduce(SemState* state, OnyxToken* tkn, AstNode* symbol) {
     token_toggle_end(tkn);
 
-    SemSymbol* sp_sym = (SemSymbol *) bh_alloc_item(state->allocator, SemSymbol);
-    sp_sym->node = symbol;
-    sp_sym->shadowed = NULL;
-
-    if (bh_table_has(SemSymbol *, state->symbols, tkn->text)) {
-        sp_sym->shadowed = bh_table_get(SemSymbol *, state->symbols, tkn->text);
+    if (bh_table_has(AstNode *, state->curr_scope->symbols, tkn->text)) {
+        onyx_message_add(state->msgs,
+                ONYX_MESSAGE_TYPE_REDECLARE_SYMBOL,
+                tkn->pos,
+                tkn->text);
+        token_toggle_end(tkn);
+        return 0;
     }
 
-    bh_table_put(SemSymbol *, state->symbols, tkn->text, sp_sym);
+    bh_table_put(AstNode *, state->curr_scope->symbols, tkn->text, symbol);
 
-    if (symbol->kind == Ast_Kind_Local) {
-        AstLocal* local = (AstLocal *) symbol;
-        local->prev_local = state->curr_local_group->last_local;
-        state->curr_local_group->last_local = local;
-
-        bh_arr_push(state->curr_function->locals, local);
-    }
+    if (symbol->kind == Ast_Kind_Local)
+        bh_arr_push(state->curr_function->locals, (AstLocal *) symbol);
 
     token_toggle_end(tkn);
+    return 1;
 }
 
-static void symbol_remove(SemState* state, OnyxToken* tkn) {
-    token_toggle_end(tkn);
-
-    SemSymbol* sp_sym = bh_table_get(SemSymbol *, state->symbols, tkn->text);
-
-    if (sp_sym->shadowed) {
-        bh_table_put(SemSymbol *, state->symbols, tkn->text, sp_sym->shadowed);
-    } else {
-        bh_table_delete(SemSymbol *, state->symbols, tkn->text);
-    }
-
-    token_toggle_end(tkn);
+static void symbol_basic_type_introduce(SemState* state, AstBasicType* basic_type) {
+    bh_table_put(AstNode *, state->curr_scope->symbols, basic_type->name, (AstNode *) basic_type);
 }
 
 static AstNode* symbol_resolve(SemState* state, OnyxToken* tkn) {
-    AstNode* res = NULL;
-
-    while (res == NULL || res->kind == Ast_Kind_Symbol) {
-        token_toggle_end(tkn);
+    token_toggle_end(tkn);
 
-        if (!bh_table_has(SemSymbol *, state->symbols, tkn->text)) {
-            onyx_message_add(state->msgs,
-                    ONYX_MESSAGE_TYPE_UNKNOWN_SYMBOL,
-                    tkn->pos,
-                    tkn->text);
+    AstNode* res = NULL;
+    Scope* scope = state->curr_scope;
 
-            token_toggle_end(tkn);
-            return NULL;
+    while (res == NULL && scope != NULL) {
+        if (bh_table_has(AstNode *, scope->symbols, tkn->text)) {
+            res = bh_table_get(AstNode *, scope->symbols, tkn->text);
+        } else {
+            scope = scope->parent;
         }
-
-        res = bh_table_get(SemSymbol *, state->symbols, tkn->text)->node;
-        token_toggle_end(tkn);
-
-        tkn = res->token;
     }
 
-    return res;
-}
-
-static void local_group_enter(SemState* state, AstLocalGroup* local_group) {
-    local_group->prev_group = state->curr_local_group;
-    state->curr_local_group = local_group;
-}
-
-static void local_group_leave(SemState* state) {
-    assert(state->curr_local_group != NULL);
-
-    for (AstLocal *walker = state->curr_local_group->last_local; walker != NULL; walker = walker->prev_local) {
-        symbol_remove(state, walker->token);
-    }
-
-    state->curr_local_group = state->curr_local_group->prev_group;
-}
-
-static void symbol_basic_type_introduce(SemState* state, AstBasicType* basic_type) {
-    SemSymbol* sp_sym = bh_alloc_item(state->allocator, SemSymbol);
-    sp_sym->node = (AstNode *) basic_type;
-    sp_sym->shadowed = NULL;
-    bh_table_put(SemSymbol *, state->symbols, basic_type->name, sp_sym);
-}
-
-static b32 symbol_unique_introduce(SemState* state, OnyxToken* tkn, AstNode* symbol) {
-    token_toggle_end(tkn);
-
-    // NOTE: If the function hasn't already been defined
-    if (!bh_table_has(SemSymbol *, state->symbols, tkn->text)) {
-        SemSymbol* sp_sym = bh_alloc_item(state->allocator, SemSymbol);
-        sp_sym->node = symbol;
-        sp_sym->shadowed = NULL;
-        bh_table_put(SemSymbol *, state->symbols, tkn->text, sp_sym);
-    } else {
+    if (res == NULL ) {
         onyx_message_add(state->msgs,
-                ONYX_MESSAGE_TYPE_CONFLICTING_GLOBALS,
+                ONYX_MESSAGE_TYPE_UNKNOWN_SYMBOL,
                 tkn->pos,
                 tkn->text);
 
-        // NOTE: I really wish C had defer...
         token_toggle_end(tkn);
-        return 0;
+        return NULL;
+    }
+
+    if (res->kind == Ast_Kind_Symbol) {
+        token_toggle_end(tkn);
+        return symbol_resolve(state, res->token);
     }
 
     token_toggle_end(tkn);
-    return 1;
+    return res;
+}
+
+static void scope_enter(SemState* state, Scope* new_scope) {
+    new_scope->parent = state->curr_scope;
+    state->curr_scope = new_scope;
+}
+
+static void scope_leave(SemState* state) {
+    state->curr_scope = state->curr_scope->parent;
 }
 
 static AstType* symres_type(SemState* state, AstType* type) {
@@ -290,13 +246,23 @@ static void symres_statement_chain(SemState* state, AstNode* walker, AstNode** t
 }
 
 static void symres_block(SemState* state, AstBlock* block) {
-    local_group_enter(state, block->locals);
+    if (block->scope == NULL)
+        block->scope = scope_create(state->node_allocator, state->curr_scope);
+
+    scope_enter(state, block->scope);
+
     if (block->body)
         symres_statement_chain(state, block->body, &block->body);
-    local_group_leave(state);
+
+    scope_leave(state);
 }
 
 static void symres_function(SemState* state, AstFunction* func) {
+    if (func->scope == NULL)
+        func->scope = scope_create(state->node_allocator, state->curr_scope);
+
+    scope_enter(state, func->scope);
+
     for (AstLocal *param = func->params; param != NULL; param = (AstLocal *) param->next) {
         param->type_node = symres_type(state, param->type_node);
 
@@ -310,9 +276,7 @@ static void symres_function(SemState* state, AstFunction* func) {
     state->curr_function = func;
     symres_block(state, func->body);
 
-    for (AstLocal *param = func->params; param != NULL; param = (AstLocal *) param->next) {
-        symbol_remove(state, param->token);
-    }
+    scope_leave(state);
 }
 
 static void symres_global(SemState* state, AstGlobal* global) {
@@ -357,6 +321,9 @@ static void symres_top_node(SemState* state, AstNode** node) {
 
 void onyx_resolve_symbols(SemState* state, ParserOutput* program) {
 
+    state->global_scope = scope_create(state->node_allocator, NULL);
+    scope_enter(state, state->global_scope);
+
     // NOTE: Add types to global scope
     symbol_basic_type_introduce(state, &basic_type_void);
     symbol_basic_type_introduce(state, &basic_type_bool);
@@ -373,7 +340,7 @@ void onyx_resolve_symbols(SemState* state, ParserOutput* program) {
     symbol_basic_type_introduce(state, &basic_type_rawptr);
 
     bh_arr_each(AstBinding *, binding, program->top_level_bindings)
-        if (!symbol_unique_introduce(state, (*binding)->token, (*binding)->node)) return;
+        if (!symbol_introduce(state, (*binding)->token, (*binding)->node)) return;
 
     bh_arr_each(AstNode *, node, program->nodes_to_process)
         symres_top_node(state, node);
index 24487a7b1b99d2a9f06101126dd03a6cbc1fee6b..96163fafbd3662dd3e7db18c6c7117bf8fa54fd9 100644 (file)
@@ -52,6 +52,18 @@ const char* onyx_ast_node_kind_string(AstKind kind) {
 }
 
 
+
+
+Scope* scope_create(bh_allocator a, Scope* parent) {
+    Scope* scope = bh_alloc_item(a, Scope);
+    scope->parent = parent;
+    scope->symbols = NULL;
+
+    bh_table_init(global_heap_allocator, scope->symbols, 16);
+
+    return scope;
+}
+
 void onyx_ast_print(AstNode* node, i32 indent) {
     assert(0);
 }