typedef struct AstOverloadedFunction AstOverloadedFunction;
typedef struct AstPolyParam AstPolyParam;
+typedef struct AstPolySolution AstPolySolution;
typedef struct AstPolyProc AstPolyProc;
typedef struct AstPackage AstPackage;
};
};
};
-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;
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);
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);
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);
}
static void scope_enter(Scope* new_scope) {
- // if (new_scope->parent == NULL)
- // new_scope->parent = semstate.curr_scope;
semstate.curr_scope = new_scope;
}
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);
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;
}
}
}
}
- 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);
}
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;
ent->state = next_state;
- if (ent->package) scope_leave();
+ if (ent->scope) {
+ semstate.curr_scope = old_scope;
+ }
}
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) {
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));
return "<anonymous procedure>";
}
+
+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;
+ }
+}