From: Brendan Hansen Date: Sat, 18 Jul 2020 17:43:20 +0000 (-0500) Subject: Completely refactored scope logic X-Git-Url: https://git.brendanfh.com/?a=commitdiff_plain;h=5161d109ed2d92ffc2a6096c7ea6ccecc3da5db9;p=onyx.git Completely refactored scope logic --- diff --git a/include/onyxastnodes.h b/include/onyxastnodes.h index 3333e0a9..f2976489 100644 --- a/include/onyxastnodes.h +++ b/include/onyxastnodes.h @@ -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; diff --git a/include/onyxmsgs.h b/include/onyxmsgs.h index 9c23a1a4..8c9afeee 100644 --- a/include/onyxmsgs.h +++ b/include/onyxmsgs.h @@ -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, diff --git a/include/onyxsempass.h b/include/onyxsempass.h index 97114bcf..c9227a04 100644 --- a/include/onyxsempass.h +++ b/include/onyxsempass.h @@ -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 c54562e3..b356f8a4 100755 Binary files a/onyx and b/onyx differ diff --git a/src/onyxchecker.c b/src/onyxchecker.c index c8b4761b..709a7682 100644 --- a/src/onyxchecker.c +++ b/src/onyxchecker.c @@ -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; } diff --git a/src/onyxmsgs.c b/src/onyxmsgs.c index f7a6e52b..15768a38 100644 --- a/src/onyxmsgs.c +++ b/src/onyxmsgs.c @@ -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'", diff --git a/src/onyxparser.c b/src/onyxparser.c index 8895cc42..641c32d9 100644 --- a/src/onyxparser.c +++ b/src/onyxparser.c @@ -615,8 +615,6 @@ static AstNode* parse_statement(OnyxParser* parser) { // '{' '}' 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) { diff --git a/src/onyxsempass.c b/src/onyxsempass.c index 0b502c6e..6d793680 100644 --- a/src/onyxsempass.c +++ b/src/onyxsempass.c @@ -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; } diff --git a/src/onyxsymres.c b/src/onyxsymres.c index 37fa5307..c9779517 100644 --- a/src/onyxsymres.c +++ b/src/onyxsymres.c @@ -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); diff --git a/src/onyxutils.c b/src/onyxutils.c index 24487a7b..96163faf 100644 --- a/src/onyxutils.c +++ b/src/onyxutils.c @@ -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); }