From: Brendan Hansen Date: Thu, 24 Dec 2020 20:04:46 +0000 (-0600) Subject: massive clean up of polymorphic procedure generation X-Git-Url: https://git.brendanfh.com/?a=commitdiff_plain;h=036706eda3e41b84896b95be30ba771dc44dd0fc;p=onyx.git massive clean up of polymorphic procedure generation --- diff --git a/include/onyxastnodes.h b/include/onyxastnodes.h index 7b2d5c74..1ecbee00 100644 --- a/include/onyxastnodes.h +++ b/include/onyxastnodes.h @@ -65,6 +65,7 @@ typedef struct AstFunction AstFunction; typedef struct AstOverloadedFunction AstOverloadedFunction; typedef struct AstPolyParam AstPolyParam; +typedef struct AstPolySolution AstPolySolution; typedef struct AstPolyProc AstPolyProc; typedef struct AstPackage AstPackage; @@ -712,7 +713,23 @@ struct AstFunction { }; }; }; -struct AstPolyParam { AstNode* poly_sym; AstType* type_expr; u64 idx; }; +struct AstPolyParam { + // The symbol node that represents the polymorphic variable. + AstNode* poly_sym; + + // The type expression that contains `poly_sym` in it somewhere. + // Matching polymorphic variables does a parallel tree traversal + // to find the pairing of the actual type and polymorphic variable + // symbol. + AstType* type_expr; + + // The parameter index where the polymorphic variable occurs. + u64 idx; +}; +struct AstPolySolution { + AstNode* poly_sym; + Type* type; +}; struct AstPolyProc { AstNode_base; @@ -811,6 +828,7 @@ Entity entity_heap_top(EntityHeap* entities); void entity_heap_change_top(EntityHeap* entities, Entity new_top); void entity_heap_remove_top(EntityHeap* entities); +void entity_bring_to_state(Entity* ent, EntityState state); void symres_entity(Entity* ent); void check_entity(Entity* ent); void emit_entity(Entity* ent); @@ -892,6 +910,7 @@ typedef enum PolyProcLookupMethod { PPLM_By_Function_Type, } PolyProcLookupMethod; AstFunction* polymorphic_proc_lookup(AstPolyProc* pp, PolyProcLookupMethod pp_lookup, ptr actual, OnyxFilePos pos); +AstFunction* polymorphic_proc_solidify(AstPolyProc* pp, bh_arr(AstPolySolution) slns, OnyxFilePos pos); AstStructType* polymorphic_struct_lookup(AstPolyStructType* ps_type, bh_arr(Type *) params, OnyxFilePos pos); diff --git a/include/onyxsempass.h b/include/onyxsempass.h index 9293353b..9897a55b 100644 --- a/include/onyxsempass.h +++ b/include/onyxsempass.h @@ -31,11 +31,8 @@ typedef struct SemState { extern SemState semstate; AstType* symres_type(AstType* type); -void symres_function(AstFunction* func); b32 check_expression(AstTyped** expr); -b32 check_function_header(AstFunction* func); -b32 check_function(AstFunction* func); // TODO: This should be moved elsewhere. void onyx_sempass_init(bh_allocator alloc, bh_allocator node_alloc); diff --git a/onyx b/onyx index c8f1d378..722bd518 100755 Binary files a/onyx and b/onyx differ diff --git a/src/onyxsymres.c b/src/onyxsymres.c index 4639913e..185480c7 100644 --- a/src/onyxsymres.c +++ b/src/onyxsymres.c @@ -24,6 +24,7 @@ static void symres_use(AstUse* use); static void symres_statement_chain(AstNode** walker); static b32 symres_statement(AstNode** stmt); static void symres_block(AstBlock* block); +void symres_function_header(AstFunction* func); void symres_function(AstFunction* func); static void symres_global(AstGlobal* global); static void symres_overloaded_function(AstOverloadedFunction* ofunc); @@ -40,8 +41,6 @@ static AstFieldAccess* make_field_access(AstTyped* node, char* field) { } static void scope_enter(Scope* new_scope) { - // if (new_scope->parent == NULL) - // new_scope->parent = semstate.curr_scope; semstate.curr_scope = new_scope; } @@ -642,7 +641,7 @@ static void symres_block(AstBlock* block) { scope_leave(); } -void symres_function(AstFunction* func) { +void symres_function_header(AstFunction* func) { if (func->scope == NULL) func->scope = scope_create(semstate.node_allocator, semstate.curr_scope, func->token->pos); @@ -651,6 +650,13 @@ void symres_function(AstFunction* func) { symres_expression(¶m->default_value); if (onyx_has_errors()) return; + // HACK: It shouldn't be necessary to do this twice, but right now + // if `null` is the default parameter and it hasn't been used anywhere in + // code yet, it doesn't resolve properly. So for now I am just checking symbols twice. + // -brendanfh 2020/12/24 + symres_expression(¶m->default_value); + if (onyx_has_errors()) return; + if (check_expression(¶m->default_value)) return; } } @@ -744,9 +750,11 @@ void symres_function(AstFunction* func) { } } - if (func->type_node != NULL) { - func->type_node = symres_type(func->type_node); - } + scope_leave(); +} + +void symres_function(AstFunction* func) { + scope_enter(func->scope); semstate.curr_function = func; symres_block(func->body); @@ -864,20 +872,24 @@ static void symres_memres(AstMemRes** memres) { } static void symres_polyproc(AstPolyProc* pp) { - pp->poly_scope = scope_create(semstate.node_allocator, semstate.curr_scope, pp->token->pos); + pp->poly_scope = semstate.curr_scope; } void symres_entity(Entity* ent) { - if (ent->package) { + if (ent->package) semstate.curr_package = ent->package; + + Scope* old_scope; + if (ent->scope) { + old_scope = semstate.curr_scope; scope_enter(ent->scope); - semstate.curr_package = ent->package; } EntityState next_state = Entity_State_Check_Types; switch (ent->type) { case Entity_Type_Foreign_Function_Header: - case Entity_Type_Function: symres_function(ent->function); break; + case Entity_Type_Function_Header: symres_function_header(ent->function); break; + case Entity_Type_Function: symres_function(ent->function); break; case Entity_Type_Foreign_Global_Header: case Entity_Type_Global_Header: symres_global(ent->global); break; @@ -900,5 +912,7 @@ void symres_entity(Entity* ent) { ent->state = next_state; - if (ent->package) scope_leave(); + if (ent->scope) { + semstate.curr_scope = old_scope; + } } diff --git a/src/onyxutils.c b/src/onyxutils.c index 85bb259d..86562e25 100644 --- a/src/onyxutils.c +++ b/src/onyxutils.c @@ -533,10 +533,12 @@ AstFunction* polymorphic_proc_lookup(AstPolyProc* pp, PolyProcLookupMethod pp_lo bh_table_init(global_heap_allocator, pp->concrete_funcs, 8); } - scope_clear(pp->poly_scope); + bh_arr(AstPolySolution) slns = NULL; + bh_arr_new(global_heap_allocator, slns, bh_arr_length(pp->poly_params)); bh_arr_each(AstPolyParam, param, pp->poly_params) { Type* actual_type; + if (pp_lookup == PPLM_By_Call) { AstArgument* arg = ((AstCall *) actual)->arguments; if (param->idx >= ((AstCall *) actual)->arg_count) { @@ -570,71 +572,89 @@ AstFunction* polymorphic_proc_lookup(AstPolyProc* pp, PolyProcLookupMethod pp_lo return NULL; } - AstTypeRawAlias* raw = onyx_ast_node_new(semstate.node_allocator, sizeof(AstTypeRawAlias), Ast_Kind_Type_Raw_Alias); - raw->to = resolved_type; - - symbol_introduce(pp->poly_scope, param->poly_sym->token, (AstNode *) raw); + bh_arr_push(slns, ((AstPolySolution) { + .poly_sym = param->poly_sym, + .type = resolved_type + })); } - // HACK(Brendan): Maybe each type should be given a unique id upon creation? - // Then that could be used to uniquely identify the type, instead of relying - // on the name being unique. - brendanfh 2020/12/14 + AstFunction* result = polymorphic_proc_solidify(pp, slns, pos); + + bh_arr_free(slns); + return result; +} + +// NOTE: This returns a volatile string. Do not store it without copying it. +static char* build_polyproc_unique_key(bh_arr(AstPolySolution) slns) { static char key_buf[1024]; fori (i, 0, 1024) key_buf[i] = 0; - bh_table_each_start(AstNode *, pp->poly_scope->symbols); - strncat(key_buf, key, 1023); + + bh_arr_each(AstPolySolution, sln, slns) { + token_toggle_end(sln->poly_sym->token); + + strncat(key_buf, sln->poly_sym->token->text, 1023); strncat(key_buf, "=", 1023); - strncat(key_buf, type_get_unique_name(((AstTypeRawAlias *) value)->to), 1023); + strncat(key_buf, type_get_unique_name(sln->type), 1023); strncat(key_buf, ";", 1023); - bh_table_each_end; - if (bh_table_has(AstFunction *, pp->concrete_funcs, key_buf)) { - return bh_table_get(AstFunction *, pp->concrete_funcs, key_buf); + token_toggle_end(sln->poly_sym->token); } - Type* old_return_type = semstate.expected_return_type; - Scope* old_scope = semstate.curr_scope; - semstate.curr_scope = pp->poly_scope; + return key_buf; +} - AstFunction* func = (AstFunction *) ast_clone(semstate.node_allocator, pp->base_func); - bh_table_put(AstFunction *, pp->concrete_funcs, key_buf, func); +AstFunction* polymorphic_proc_solidify(AstPolyProc* pp, bh_arr(AstPolySolution) slns, OnyxFilePos pos) { + if (pp->concrete_funcs == NULL) { + bh_table_init(global_heap_allocator, pp->concrete_funcs, 8); + } - symres_function(func); - semstate.curr_scope = old_scope; + // NOTE: Check if a version of this polyproc has already been created. + char* unique_key = build_polyproc_unique_key(slns); + if (bh_table_has(AstFunction *, pp->concrete_funcs, unique_key)) { + return bh_table_get(AstFunction *, pp->concrete_funcs, unique_key); + } - if (onyx_has_errors()) goto has_error; - if (check_function_header(func)) goto has_error; - goto no_errors; + Scope* poly_scope = scope_create(semstate.node_allocator, pp->poly_scope, pos); + bh_arr_each(AstPolySolution, sln, slns) { + AstTypeRawAlias* raw = onyx_ast_node_new(semstate.node_allocator, sizeof(AstTypeRawAlias), Ast_Kind_Type_Raw_Alias); + raw->to = sln->type; -has_error: - onyx_report_error(pos, "Error in polymorphic procedure generated from this call site."); - semstate.expected_return_type = old_return_type; - return NULL; + symbol_introduce(poly_scope, sln->poly_sym->token, (AstNode *) raw); + } -no_errors: - semstate.expected_return_type = old_return_type; + AstFunction* func = (AstFunction *) ast_clone(semstate.node_allocator, pp->base_func); + bh_table_put(AstFunction *, pp->concrete_funcs, unique_key, func); + + func->flags |= Ast_Flag_Function_Used; - entity_heap_insert(&semstate.program->entities, (Entity) { - .state = Entity_State_Code_Gen, + Entity func_header_entity = { + .state = Entity_State_Resolve_Symbols, .type = Entity_Type_Function_Header, .function = func, .package = NULL, - }); + .scope = poly_scope, + }; + + entity_bring_to_state(&func_header_entity, Entity_State_Code_Gen); + if (onyx_has_errors()) { + onyx_report_error(pos, "Error in polymorphic procedure header generated from this call site."); + return NULL; + } - entity_heap_insert(&semstate.program->entities, (Entity) { - .state = Entity_State_Check_Types, + Entity func_entity = { + .state = Entity_State_Resolve_Symbols, .type = Entity_Type_Function, .function = func, .package = NULL, - }); - - func->flags |= Ast_Flag_Function_Used; + .scope = poly_scope, + }; + entity_heap_insert(&semstate.program->entities, func_header_entity); + entity_heap_insert(&semstate.program->entities, func_entity); return func; } - AstStructType* polymorphic_struct_lookup(AstPolyStructType* ps_type, bh_arr(Type *) params, OnyxFilePos pos) { // @Cleanup assert(bh_arr_length(ps_type->poly_params) == bh_arr_length(params)); @@ -887,3 +907,17 @@ char* get_function_name(AstFunction* func) { return ""; } + +void entity_bring_to_state(Entity* ent, EntityState state) { + while (ent->state != state) { + switch (ent->state) { + case Entity_State_Resolve_Symbols: symres_entity(ent); break; + case Entity_State_Check_Types: check_entity(ent); break; + case Entity_State_Code_Gen: emit_entity(ent); break; + + default: return; + } + + if (onyx_has_errors()) return; + } +}