Files
corelang/core_polymorph.cpp
Krzosa Karol 41d2baa56b We are working! POLYMORPHS There was an error where we have to reconstruct exact
typespec from type. This means we will probably have problems with namespaces!!
2023-04-02 15:07:47 +02:00

479 lines
18 KiB
C++

CORE_Static Intern_String
get_unique_name() {
static uint64_t counter;
static char char_counter;
if (char_counter == 0 || char_counter > 'Z') char_counter = 'A';
return pctx->internf("%c%uUnique", char_counter++, counter++);
}
CORE_Static Intern_String
get_unique_name_for_decl(Ast_Decl *decl) {
static char char_counter;
if (char_counter == 0 || char_counter > 'Z') char_counter = 'A';
return pctx->internf("%c%u_%Q", char_counter++, decl->di, decl->name);
}
CORE_Static String core_type_to_string(Ast_Type *type);
Ast_Expr *create_typespec_from_type(Token *pos, Ast_Scope *parent_scope, Ast_Type *type) {
Ast_Expr *result = 0;
switch (type->kind) {
case TYPE_NONE:
case TYPE_TUPLE:
case TYPE_COMPLETING:
case TYPE_INCOMPLETE:
case TYPE_POLYMORPH:
case TYPE_UNTYPED_BOOL:
case TYPE_UNTYPED_INT:
case TYPE_UNTYPED_FLOAT:
case TYPE_UNTYPED_STRING: {
invalid_codepath;
} break;
case TYPE_TYPE:
case TYPE_S64:
case TYPE_S32:
case TYPE_S16:
case TYPE_S8:
case TYPE_INT:
case TYPE_CHAR:
case TYPE_U64:
case TYPE_U32:
case TYPE_U16:
case TYPE_U8:
case TYPE_F32:
case TYPE_F64:
case TYPE_BOOL:
case TYPE_STRING:
case TYPE_VOID: {
String s = core_type_to_string(type);
result = ast_ident(pos, pctx->intern(s));
} break;
case TYPE_POINTER: {
result = ast_expr_unary(pos, TK_Pointer, create_typespec_from_type(pos, parent_scope, type->base));
} break;
case TYPE_ARRAY: {
Ast_Array *arr = ast_array(pos, create_typespec_from_type(pos, parent_scope, type->arr.base));
arr->expr = ast_int(pos, type->arr.size);
arr->expr->parent_scope = parent_scope;
result = arr;
} break;
case TYPE_SLICE: {
Ast_Array *arr = ast_array(pos, create_typespec_from_type(pos, parent_scope, type->arr.base));
result = arr;
} break;
case TYPE_LAMBDA: {
invalid_codepath;
} break;
case TYPE_STRUCT:
case TYPE_UNION:
case TYPE_ENUM: {
Ast_Decl *decl = (Ast_Decl *)type->ast;
// @warning:
// Can we do this differently?
// WE MIGHT HAVE PROBLEM WITH NAMESPACES in the future!!!
if (decl->flags & AST_POLYMORPH_INSTANCE) {
Ast_Atom *ident = ast_ident(pos, decl->name);
ident->parent_scope = parent_scope;
result = ast_call(pos, ident, decl->instantiation_call_items);
}
else result = ast_ident(pos, decl->name);
} break;
}
result->parent_scope = parent_scope;
return result;
}
#define ast_create_copy(parent_scope, T, ast) (T *)ast__create_copy(parent_scope, sizeof(T), ast)
Ast *ast__create_copy(Ast_Scope *parent_scope, size_t size, Ast *ast) {
if (ast == 0) return 0;
Ast *result = (Ast *)push_copy(pctx->perm, ast, size);
result->parent_scope = parent_scope;
result->di = ++pctx->unique_ids;
return result;
}
// We are not copying module and file Ast's
// We are not copying resolved data
Ast *ast_copy(Ast *ast, Ast_Scope *parent_scope, Array<Ast_Decl *> *replace, Array<Ast_Call_Item *> *with) {
if (!ast) return 0;
Ast *result = 0;
switch (ast->kind) {
case AST_SCOPE: {
Ast_Scope *src = (Ast_Scope *)ast;
Ast_Scope *dst = ast_create_copy(parent_scope, Ast_Scope, src);
dst->decls = {};
For(src->decls) {
Ast_Decl *copy = (Ast_Decl *)ast_copy(it, src, replace, with);
add(pctx->perm, &dst->decls, copy);
}
dst->stmts.init(pctx->perm, src->stmts.len);
For(src->stmts) {
Ast *copy = ast_copy(it, dst, replace, with);
dst->stmts.add(copy);
}
result = dst;
} break;
case AST_MODULE: invalid_codepath; break;
case AST_FILE: invalid_codepath; break;
case AST_IDENT: {
Ast_Atom *src = (Ast_Atom *)ast;
Ast_Atom *dst = ast_create_copy(parent_scope, Ast_Atom, ast);
if (replace && with) {
// @todo: IF ITS STRUCT we only want to replace TYPESPECS
For(*replace) {
if (it->flags & AST_IDENT_POLYMORPH) {
assert(it->type == pctx->type_type);
if (it->name == dst->intern_val) {
S64 it_index = replace->get_index(it);
Ast_Call_Item *replacement = with[0][it_index];
Ast *replacement_v = replacement->item;
dst = (Ast_Atom *)ast_copy(replacement_v, parent_scope, 0, 0);
}
}
else if (it->flags & AST_TYPE_POLYMORPH) {
Ast_Expr *typespec = it->typespec;
assert(typespec);
assert(typespec->kind == AST_IDENT);
Ast_Atom *t = (Ast_Atom *)typespec;
if (t->intern_val == dst->intern_val) {
S64 it_index = replace->get_index(it);
// @todo: This probably should be resolved
// before calling the ast_copy function
// or something
Ast_Call_Item *replacement = with[0][it_index];
Ast_Type *type_to_replace = replacement->item->resolved_type;
dst = (Ast_Atom *)create_typespec_from_type(dst->pos, parent_scope, type_to_replace);
// dst = (Ast_Atom *)ast_copy(replacement_v, parent_scope, 0, 0);
}
}
}
}
result = dst;
} break;
case AST_VALUE: {
Ast_Atom *src = (Ast_Atom *)ast;
Ast_Atom *dst = ast_create_copy(parent_scope, Ast_Atom, ast);
result = dst;
} break;
case AST_INDEX: {
Ast_Index *src = (Ast_Index *)ast;
Ast_Index *dst = ast_create_copy(parent_scope, Ast_Index, ast);
dst->expr = (Ast_Expr *)ast_copy(src->expr, parent_scope, replace, with);
dst->index = (Ast_Expr *)ast_copy(src->index, parent_scope, replace, with);
result = dst;
} break;
case AST_UNARY: {
Ast_Unary *src = (Ast_Unary *)ast;
Ast_Unary *dst = ast_create_copy(parent_scope, Ast_Unary, ast);
dst->expr = (Ast_Expr *)ast_copy(src->expr, parent_scope, replace, with);
result = dst;
} break;
case AST_BINARY: {
Ast_Binary *src = (Ast_Binary *)ast;
Ast_Binary *dst = ast_create_copy(parent_scope, Ast_Binary, ast);
dst->left = (Ast_Expr *)ast_copy(src->left, parent_scope, replace, with);
dst->right = (Ast_Expr *)ast_copy(src->right, parent_scope, replace, with);
result = dst;
} break;
case AST_CALL_ITEM: {
Ast_Call_Item *src = (Ast_Call_Item *)ast;
Ast_Call_Item *dst = ast_create_copy(parent_scope, Ast_Call_Item, ast);
dst->item = (Ast_Expr *)ast_copy(src->item, parent_scope, replace, with);
if (src->call_flags & CALL_INDEX) {
dst->index = (Ast_Expr *)ast_copy(src->index, parent_scope, replace, with);
}
else if (src->call_flags & CALL_NAME) {
dst->name = (Ast_Atom *)ast_copy(src->name, parent_scope, replace, with);
}
result = dst;
} break;
case AST_COMPOUND:
case AST_CALL: {
Ast_Call *src = (Ast_Call *)ast;
Ast_Call *dst = ast_create_copy(parent_scope, Ast_Call, ast);
dst->name = (Ast_Expr *)ast_copy(src->name, parent_scope, replace, with);
dst->exprs.init(pctx->perm, src->exprs.len);
For(src->exprs) {
auto copy = (Ast_Call_Item *)ast_copy(it, parent_scope, replace, with);
dst->exprs.add(copy);
}
result = dst;
} break;
case AST_TYPE_OF:
case AST_LENGTH_OF:
case AST_ALIGN_OF:
case AST_SIZE_OF:
case AST_RUNTIME_ASSERT:
case AST_CONSTANT_ASSERT: {
Ast_Builtin *src = (Ast_Builtin *)ast;
Ast_Builtin *dst = ast_create_copy(parent_scope, Ast_Builtin, ast);
dst->expr = (Ast_Expr *)ast_copy(src->expr, parent_scope, replace, with);
result = dst;
} break;
case AST_SWITCH: {
Ast_Switch *src = (Ast_Switch *)ast;
Ast_Switch *dst = ast_create_copy(parent_scope, Ast_Switch, ast);
dst->value = (Ast_Expr *)ast_copy(src->value, parent_scope, replace, with);
dst->default_scope = (Ast_Scope *)ast_copy(src->default_scope, parent_scope, replace, with);
dst->cases.init(pctx->perm, src->cases.len);
For(src->cases) {
auto copy = (Ast_Switch_Case *)ast_copy(it, parent_scope, replace, with);
assert(copy->kind == AST_SWITCH_CASE);
dst->cases.add(copy);
}
result = dst;
} break;
case AST_SWITCH_CASE: {
Ast_Switch_Case *src = (Ast_Switch_Case *)ast;
Ast_Switch_Case *dst = ast_create_copy(parent_scope, Ast_Switch_Case, ast);
dst->scope = (Ast_Scope *)ast_copy(src->scope, parent_scope, replace, with);
dst->labels.init(pctx->perm, src->labels.len);
For(src->labels) {
auto copy = (Ast_Expr *)ast_copy(it, parent_scope, replace, with);
dst->labels.add(copy);
}
result = dst;
} break;
case AST_VAR_UNPACK: {
Ast_Var_Unpack *src = (Ast_Var_Unpack *)ast;
Ast_Var_Unpack *dst = ast_create_copy(parent_scope, Ast_Var_Unpack, ast);
dst->expr = (Ast_Expr *)ast_copy(src->expr, parent_scope, replace, with);
dst->vars.init(pctx->perm, src->vars.len);
For(src->vars) {
auto copy = (Ast_Decl *)ast_copy(it, parent_scope, replace, with);
dst->vars.add(copy);
}
result = dst;
} break;
case AST_PASS:
case AST_BREAK: {
Ast *src = (Ast *)ast;
Ast *dst = ast_create_copy(parent_scope, Ast, ast);
result = dst;
} break;
case AST_NAMESPACE:
case AST_STRUCT:
case AST_UNION:
case AST_ENUM:
case AST_LAMBDA:
case AST_TYPE: // @cleanup: what is this used for?
case AST_CONST:
case AST_VAR: {
Ast_Decl *src = (Ast_Decl *)ast;
Ast_Decl *dst = ast_create_copy(parent_scope, Ast_Decl, ast);
// dst->overload_op_info = ast_create_copy(parent_scope, Ast_Operator_Info, src->overload_op_info);
// omitting polymorphs
// omitting polymorph parameters
dst->scope = (Ast_Scope *)ast_copy(src->scope, parent_scope, replace, with);
dst->typespec = (Ast_Expr *)ast_copy(src->typespec, parent_scope, replace, with);
dst->expr = (Ast_Expr *)ast_copy(src->expr, parent_scope, replace, with);
result = dst;
} break;
case AST_ARRAY: {
Ast_Array *src = (Ast_Array *)ast;
Ast_Array *dst = ast_create_copy(parent_scope, Ast_Array, ast);
dst->expr = (Ast_Expr *)ast_copy(src->expr, parent_scope, replace, with);
result = dst;
} break;
case AST_FOR: {
Ast_For *src = (Ast_For *)ast;
Ast_For *dst = ast_create_copy(parent_scope, Ast_For, ast);
dst->scope = (Ast_Scope *)ast_copy(src->scope, parent_scope, replace, with);
dst->init = (Ast_Expr *)ast_copy(src->init, parent_scope, replace, with);
dst->cond = (Ast_Expr *)ast_copy(src->cond, parent_scope, replace, with);
dst->iter = (Ast_Expr *)ast_copy(src->iter, parent_scope, replace, with);
result = dst;
} break;
case AST_IF: {
Ast_If *src = (Ast_If *)ast;
Ast_If *dst = ast_create_copy(parent_scope, Ast_If, ast);
dst->ifs.init(pctx->perm, src->ifs.len);
For(src->ifs) {
auto copy = (Ast_If_Node *)ast_copy(it, parent_scope, replace, with);
assert(copy->kind == AST_IF_NODE);
dst->ifs.add(copy);
}
result = dst;
} break;
case AST_IF_NODE: {
Ast_If_Node *src = (Ast_If_Node *)ast;
Ast_If_Node *dst = ast_create_copy(parent_scope, Ast_If_Node, ast);
dst->expr = (Ast_Expr *)ast_copy(src->expr, parent_scope, replace, with);
dst->init = (Ast_Binary *)ast_copy(src->init, parent_scope, replace, with);
dst->scope = (Ast_Scope *)ast_copy(src->scope, parent_scope, replace, with);
result = dst;
} break;
case AST_RETURN: {
Ast_Return *src = (Ast_Return *)ast;
Ast_Return *dst = ast_create_copy(parent_scope, Ast_Return, ast);
dst->expr.init(pctx->perm, src->expr.len);
For(src->expr) {
auto copy = (Ast_Expr *)ast_copy(it, parent_scope, replace, with);
dst->expr.add(copy);
}
result = dst;
} break;
case AST_LAMBDA_EXPR: {
Ast_Lambda *src = (Ast_Lambda *)ast;
Ast_Lambda *dst = ast_create_copy(parent_scope, Ast_Lambda, ast);
dst->args.init(pctx->perm, src->args.len);
For(src->args) {
if (it->flags & AST_IDENT_POLYMORPH) continue;
auto copy = (Ast_Decl *)ast_copy(it, parent_scope, replace, with);
dst->args.add(copy);
}
dst->ret.init(pctx->perm, src->ret.len);
For(src->ret) {
auto copy = (Ast_Expr *)ast_copy(it, parent_scope, replace, with);
dst->ret.add(copy);
}
dst->scope = (Ast_Scope *)ast_copy(src->scope, parent_scope, replace, with);
result = dst;
} break;
default: assert(!"Invalid default case");
}
assert(result);
unset_flag(result->flags, AST_POLYMORPH | AST_PARENT_POLYMORPH);
set_flag(result->flags, AST_POLYMORPH_INSTANCE);
return result;
}
Ast_Decl *get_or_instantiate_polymorph_type(Token *pos, Ast_Decl *poly, Array<Ast_Call_Item *> params, Ast_Scope *field_access_scope) {
if (params.len != poly->polymorph_parameters.len) compiler_error(pos, "Invalid count of polymorphic arguments");
int i = 0;
uint64_t hash = 91;
For(params) {
bool indexed = (it->flags & CALL_INDEX);
bool named = (it->flags & CALL_NAME);
if (indexed == false && named == false) compiler_error(it->pos, "Polymorphic type cannot have named/indexed arguments");
Ast_Decl *poly_decl = poly->polymorph_parameters[i++];
resolve_decl(poly_decl);
if (poly_decl->type != pctx->type_type) compiler_error(poly_decl->pos, "Invalid type of polymorphic struct argument");
Operand op = resolve_expr(it->item, AST_CANT_BE_NULL, 0, field_access_scope);
if (!op.is_const) compiler_error(it->pos, "Argument is required to be compile time known");
if (op.type != pctx->type_type) compiler_error(it->pos, "Struct argument required to be a type");
hash = hash_mix(hash, hash_ptr(op.type_val));
}
Ast_Decl *result = 0;
For(poly->polymorphs) {
if (it->polymorph_hash == hash) {
result = it;
break;
}
}
if (poly->kind == AST_LAMBDA) Breakpoint;
if (!result) {
result = (Ast_Decl *)ast_copy(poly, poly->parent_scope, &poly->polymorph_parameters, &params);
result->type_val = type_incomplete(result);
result->polymorph_hash = hash;
result->instantiation_call_items = params.tight_copy(pctx->perm);
assert(result->di != poly->di);
result->unique_name = get_unique_name_for_decl(result);
poly->polymorphs.allocator = pctx->heap;
poly->polymorphs.add(result);
}
resolve_decl(result);
type_complete(result->type_val);
return result;
}
Ast_Decl *get_or_instantiate_polymorph_lambda(Token *pos, Ast_Decl *poly, Array<Ast_Call_Item *> params, Ast_Scope *field_access_scope) {
if (params.len != poly->polymorph_parameters.len) compiler_error(pos, "Invalid count of polymorphic arguments");
Scoped_Arena scratch(pctx->scratch);
int i = 0;
uint64_t hash = 91;
For(params) {
Ast_Decl *poly_decl = poly->polymorph_parameters[i++];
if (poly_decl->flags & AST_IDENT_POLYMORPH) {
resolve_decl(poly_decl);
if (poly_decl->type != pctx->type_type) compiler_error(poly_decl->pos, "Invalid type of polymorphic struct argument");
Operand op = resolve_expr(it->item, AST_CANT_BE_NULL, 0, field_access_scope);
if (!op.is_const) compiler_error(it->pos, "Argument is required to be compile time known");
if (op.type != pctx->type_type) compiler_error(it->pos, "Struct argument required to be a type");
hash = hash_mix(hash, hash_ptr(op.type_val));
}
else {
Operand op = resolve_expr(it->item, AST_CANT_BE_NULL, 0, field_access_scope);
try_converting_untyped_to_default_type(&op);
try_propagating_resolved_type_to_untyped_literals(it->item, op.type);
// type_complete(op.type);
assert(it->item->resolved_type == op.type);
hash = hash_mix(hash, hash_ptr(op.type));
}
}
Ast_Decl *result = 0;
For(poly->polymorphs) {
if (it->polymorph_hash == hash) {
result = it;
break;
}
}
if (!result) {
result = (Ast_Decl *)ast_copy(poly, poly->parent_scope, &poly->polymorph_parameters, &params);
result->polymorph_hash = hash;
assert(result->di != poly->di);
result->unique_name = get_unique_name_for_decl(result);
poly->polymorphs.allocator = pctx->heap;
poly->polymorphs.add(result);
}
resolve_decl(result);
return result;
}