From 5fb4999ca8a2c9c21c52cf581e6c70b776454a31 Mon Sep 17 00:00:00 2001 From: Krzosa Karol Date: Sat, 1 Apr 2023 09:28:35 +0200 Subject: [PATCH] Polymorphs --- core_codegen_c_language.cpp | 2 + core_parsing.cpp | 1 + core_polymorph.cpp | 461 +++++++++++++++++++----------------- core_typechecking.cpp | 38 ++- examples/_polymorphism.core | 2 +- 5 files changed, 278 insertions(+), 226 deletions(-) diff --git a/core_codegen_c_language.cpp b/core_codegen_c_language.cpp index 2b65aaf..814281e 100644 --- a/core_codegen_c_language.cpp +++ b/core_codegen_c_language.cpp @@ -832,6 +832,7 @@ CORE_Static String compile_to_c_code() { pctx->time.code_generation = os_time(); +#if 0 String core_stringify(Ast *); For(pctx->ordered_decls) { Ast *copy = ast_copy(it, 0); @@ -843,6 +844,7 @@ compile_to_c_code() { printf("%s\n", r.str); } pctx->gen.reset(); +#endif #if 0 int di = 0; diff --git a/core_parsing.cpp b/core_parsing.cpp index d89da6b..49d2e08 100644 --- a/core_parsing.cpp +++ b/core_parsing.cpp @@ -733,6 +733,7 @@ parse_struct(Token *pos, Ast_Kind kind) { compiler_error(it->pos, "All struct arguments are required to be polymorphic"); } } + params = params.tight_copy(pctx->perm); } Ast_Scope *scope = begin_decl_scope(scratch.arena, token_get()); diff --git a/core_polymorph.cpp b/core_polymorph.cpp index 7806db6..24720a3 100644 --- a/core_polymorph.cpp +++ b/core_polymorph.cpp @@ -1,230 +1,22 @@ -Ast_Decl *get_or_instantiate_polymorph_type(Ast_Decl *poly, Array params) { +Ast_Decl *get_or_instantiate_polymorph_type(Token *pos, Ast_Decl *poly, Array params, Ast_Scope *field_access_scope) { + if (params.len != poly->polymorph_parameters.len) { + compiler_error(pos, "Invalid count of polymorphic arguments"); + } + 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"); + } + + Operand op = resolve_expr(it->item, AST_CANT_BE_NULL, 0, field_access_scope); + } + return 0; } -const unsigned AST_NODE_END = 128; - -struct Ast_Iter { - Array stack; - Ast *ast; - Ast_Kind kind; - bool skip_children; - uint32_t visit_id; - uint32_t di; -}; - -uint32_t Ast_Iter_VisitIDGen; -Ast_Iter iterate_depth_first(Allocator *a, Ast *ast) { - assert(ast); - Ast_Iter result = {}; - result.stack = {a}; - result.ast = ast; - result.kind = ast->kind; - result.visit_id = ++Ast_Iter_VisitIDGen; - return result; -} - -void next(Ast_Iter *iter) { - Ast *ast = iter->ast; - ast->visit_id = iter->visit_id; - - if (iter->skip_children) { - iter->skip_children = false; - goto end_of_switch; - } - - switch (iter->kind) { - case AST_SCOPE: { - Ast_Scope *node = (Ast_Scope *)ast; - iter->stack.add(node); - For(node->stmts) iter->stack.add(it); - For(node->decls) iter->stack.add(it); - } break; - - case AST_MODULE: break; // This happens when we import stuff - case AST_FILE: invalid_codepath; break; - - case AST_IDENT: - case AST_VALUE: { - Ast_Atom *node = (Ast_Atom *)ast; - } break; - - case AST_INDEX: { - Ast_Index *node = (Ast_Index *)ast; - iter->stack.add(node); - iter->stack.add(node->index); - iter->stack.add(node->expr); - assert(node->index); - assert(node->expr); - } break; - - case AST_UNARY: { - Ast_Unary *node = (Ast_Unary *)ast; - iter->stack.add(node); - iter->stack.add(node->expr); - assert(node->expr); - } break; - - case AST_BINARY: { - Ast_Binary *node = (Ast_Binary *)ast; - iter->stack.add(node); - iter->stack.add(node->right); - iter->stack.add(node->left); - assert(node->right); - assert(node->left); - } break; - - case AST_CALL_ITEM: { - Ast_Call_Item *node = (Ast_Call_Item *)ast; - iter->stack.add(node); - iter->stack.add(node->item); - assert(node->item); - if (node->call_flags & CALL_INDEX) { - iter->stack.add(node->index); - assert(node->index); - } - else if (node->call_flags & CALL_NAME) { - iter->stack.add(node->name); - assert(node->name); - } - } break; - - case AST_COMPOUND: - case AST_CALL: { - Ast_Call *node = (Ast_Call *)ast; - iter->stack.add(node); - For(node->exprs) iter->stack.add(it); - if (node->name) iter->stack.add(node->name); - } 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 *node = (Ast_Builtin *)ast; - iter->stack.add(node); - iter->stack.add(node->expr); - assert(node->expr); - } break; - - case AST_SWITCH: { - Ast_Switch *node = (Ast_Switch *)ast; - iter->stack.add(node); - if (node->default_scope) iter->stack.add(node->default_scope); - For(node->cases) iter->stack.add(it); - iter->stack.add(node->value); - assert(node->value); - } break; - - case AST_SWITCH_CASE: { - Ast_Switch_Case *node = (Ast_Switch_Case *)ast; - iter->stack.add(node); - iter->stack.add(node->scope); - assert(node->scope); - For(node->labels) iter->stack.add(it); - } break; - - case AST_VAR_UNPACK: { - Ast_Var_Unpack *node = (Ast_Var_Unpack *)ast; - iter->stack.add(node); - iter->stack.add(node->expr); - assert(node->expr); - For(node->vars) iter->stack.add(it); - } break; - - case AST_PASS: - case AST_BREAK: { - Ast *node = (Ast *)ast; - } 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 *node = (Ast_Decl *)ast; - - iter->stack.add(node); - if (node->scope) iter->stack.add(node->scope); - if (node->expr) iter->stack.add(node->expr); - if (node->typespec) iter->stack.add(node->typespec); - - // omitting polymorphs - // omitting polymorph parameters - } break; - - case AST_ARRAY: { - Ast_Array *node = (Ast_Array *)ast; - iter->stack.add(node); - if (node->expr) iter->stack.add(node->expr); - } break; - - case AST_FOR: { - Ast_For *node = (Ast_For *)ast; - iter->stack.add(node); - iter->stack.add(node->scope); - assert(node->scope); - if (node->iter) iter->stack.add(node->iter); - if (node->cond) iter->stack.add(node->cond); - if (node->init) iter->stack.add(node->init); - } break; - - case AST_IF: { - Ast_If *node = (Ast_If *)ast; - iter->stack.add(node); - For(node->ifs) iter->stack.add(it); - } break; - - case AST_IF_NODE: { - Ast_If_Node *node = (Ast_If_Node *)ast; - iter->stack.add(node); - iter->stack.add(node->scope); - assert(node->scope); - if (node->expr) iter->stack.add(node->expr); - if (node->init) iter->stack.add(node->init); - } break; - - case AST_RETURN: { - Ast_Return *node = (Ast_Return *)ast; - iter->stack.add(node); - For(node->expr) iter->stack.add(it); - } break; - - case AST_LAMBDA_EXPR: { - Ast_Lambda *node = (Ast_Lambda *)ast; - iter->stack.add(node); - if (node->scope) iter->stack.add(node->scope); - For(node->ret) iter->stack.add(it); - For(node->args) iter->stack.add(it); - } break; - - default: assert(!"Invalid default case"); - } -end_of_switch: - - if (iter->stack.len <= 0) { - iter->ast = 0; - iter->kind = AST_NONE; - iter->stack.dealloc(); - return; - } - - iter->ast = iter->stack.pop(); - assert(iter->ast != 0); - iter->di += 1; - iter->kind = iter->ast->kind; - if (iter->ast->visit_id == iter->visit_id) { - iter->kind = (Ast_Kind)((unsigned)iter->kind + AST_NODE_END); - } -} - #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; @@ -468,4 +260,227 @@ Ast *ast_copy(Ast *ast, Ast_Scope *parent_scope) { default: assert(!"Invalid default case"); } invalid_return; -} \ No newline at end of file +} + +// ITERATOR + +const unsigned AST_NODE_END = 128; + +struct Ast_Iter { + Array stack; + Ast *ast; + Ast_Kind kind; + bool skip_children; + uint32_t visit_id; + uint32_t di; +}; + +uint32_t Ast_Iter_VisitIDGen; +Ast_Iter iterate_depth_first(Allocator *a, Ast *ast) { + assert(ast); + Ast_Iter result = {}; + result.stack = {a}; + result.ast = ast; + result.kind = ast->kind; + result.visit_id = ++Ast_Iter_VisitIDGen; + return result; +} + +void next(Ast_Iter *iter) { + Ast *ast = iter->ast; + ast->visit_id = iter->visit_id; + + if (iter->skip_children) { + iter->skip_children = false; + goto end_of_switch; + } + + switch (iter->kind) { + case AST_SCOPE: { + Ast_Scope *node = (Ast_Scope *)ast; + iter->stack.add(node); + For(node->stmts) iter->stack.add(it); + For(node->decls) iter->stack.add(it); + } break; + + case AST_MODULE: break; // This happens when we import stuff + case AST_FILE: invalid_codepath; break; + + case AST_IDENT: + case AST_VALUE: { + Ast_Atom *node = (Ast_Atom *)ast; + } break; + + case AST_INDEX: { + Ast_Index *node = (Ast_Index *)ast; + iter->stack.add(node); + iter->stack.add(node->index); + iter->stack.add(node->expr); + assert(node->index); + assert(node->expr); + } break; + + case AST_UNARY: { + Ast_Unary *node = (Ast_Unary *)ast; + iter->stack.add(node); + iter->stack.add(node->expr); + assert(node->expr); + } break; + + case AST_BINARY: { + Ast_Binary *node = (Ast_Binary *)ast; + iter->stack.add(node); + iter->stack.add(node->right); + iter->stack.add(node->left); + assert(node->right); + assert(node->left); + } break; + + case AST_CALL_ITEM: { + Ast_Call_Item *node = (Ast_Call_Item *)ast; + iter->stack.add(node); + iter->stack.add(node->item); + assert(node->item); + if (node->call_flags & CALL_INDEX) { + iter->stack.add(node->index); + assert(node->index); + } + else if (node->call_flags & CALL_NAME) { + iter->stack.add(node->name); + assert(node->name); + } + } break; + + case AST_COMPOUND: + case AST_CALL: { + Ast_Call *node = (Ast_Call *)ast; + iter->stack.add(node); + For(node->exprs) iter->stack.add(it); + if (node->name) iter->stack.add(node->name); + } 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 *node = (Ast_Builtin *)ast; + iter->stack.add(node); + iter->stack.add(node->expr); + assert(node->expr); + } break; + + case AST_SWITCH: { + Ast_Switch *node = (Ast_Switch *)ast; + iter->stack.add(node); + if (node->default_scope) iter->stack.add(node->default_scope); + For(node->cases) iter->stack.add(it); + iter->stack.add(node->value); + assert(node->value); + } break; + + case AST_SWITCH_CASE: { + Ast_Switch_Case *node = (Ast_Switch_Case *)ast; + iter->stack.add(node); + iter->stack.add(node->scope); + assert(node->scope); + For(node->labels) iter->stack.add(it); + } break; + + case AST_VAR_UNPACK: { + Ast_Var_Unpack *node = (Ast_Var_Unpack *)ast; + iter->stack.add(node); + iter->stack.add(node->expr); + assert(node->expr); + For(node->vars) iter->stack.add(it); + } break; + + case AST_PASS: + case AST_BREAK: { + Ast *node = (Ast *)ast; + } 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 *node = (Ast_Decl *)ast; + + iter->stack.add(node); + if (node->scope) iter->stack.add(node->scope); + if (node->expr) iter->stack.add(node->expr); + if (node->typespec) iter->stack.add(node->typespec); + + // omitting polymorphs + // omitting polymorph parameters + } break; + + case AST_ARRAY: { + Ast_Array *node = (Ast_Array *)ast; + iter->stack.add(node); + if (node->expr) iter->stack.add(node->expr); + } break; + + case AST_FOR: { + Ast_For *node = (Ast_For *)ast; + iter->stack.add(node); + iter->stack.add(node->scope); + assert(node->scope); + if (node->iter) iter->stack.add(node->iter); + if (node->cond) iter->stack.add(node->cond); + if (node->init) iter->stack.add(node->init); + } break; + + case AST_IF: { + Ast_If *node = (Ast_If *)ast; + iter->stack.add(node); + For(node->ifs) iter->stack.add(it); + } break; + + case AST_IF_NODE: { + Ast_If_Node *node = (Ast_If_Node *)ast; + iter->stack.add(node); + iter->stack.add(node->scope); + assert(node->scope); + if (node->expr) iter->stack.add(node->expr); + if (node->init) iter->stack.add(node->init); + } break; + + case AST_RETURN: { + Ast_Return *node = (Ast_Return *)ast; + iter->stack.add(node); + For(node->expr) iter->stack.add(it); + } break; + + case AST_LAMBDA_EXPR: { + Ast_Lambda *node = (Ast_Lambda *)ast; + iter->stack.add(node); + if (node->scope) iter->stack.add(node->scope); + For(node->ret) iter->stack.add(it); + For(node->args) iter->stack.add(it); + } break; + + default: assert(!"Invalid default case"); + } +end_of_switch: + + if (iter->stack.len <= 0) { + iter->ast = 0; + iter->kind = AST_NONE; + iter->stack.dealloc(); + return; + } + + iter->ast = iter->stack.pop(); + assert(iter->ast != 0); + iter->di += 1; + iter->kind = iter->ast->kind; + if (iter->ast->visit_id == iter->visit_id) { + iter->kind = (Ast_Kind)((unsigned)iter->kind + AST_NODE_END); + } +} diff --git a/core_typechecking.cpp b/core_typechecking.cpp index 9c9208e..ddaa15d 100644 --- a/core_typechecking.cpp +++ b/core_typechecking.cpp @@ -1572,14 +1572,48 @@ resolve_expr(Ast_Expr *ast, Resolve_Flag flags, Ast_Type *compound_and_const_str if (name.type_val->kind != TYPE_POLYMORPH) { compiler_error(node->pos, "Parenthesis are not valid for types that are not polymorphic"); } - Ast_Decl *poly = name.resolved_decl; + assert(poly->flags & AST_POLYMORPH); + // node->exprs = params - Ast_Decl *instance = get_or_instantiate_polymorph_type(poly, node->exprs); + Ast_Decl *instance = get_or_instantiate_polymorph_type(node->pos, poly, node->exprs, field_access_scope); // type_complete(decl); return {}; // operand_type(resolved_type); } + /* @todo: + We need an algorithm and other concretes for correct matching of arrays, var args and others. + + (a: int = 5, b: int) Disallowed, this is not lua where table has indexed and keyed values at the same time + (a: int = 5, b: int = 10) + (a = 2, b = 10) + (32, 4) + (32, b = 32) + (32, a = 32) Error + (b = 3, b = 4) Error + + (a: int, b: ..String) + (a: int, b: ..Any) + (10, 10, 10) + (10, b = {10, 10, 10, 10}) + (10, ..slice) // We want to avoid accidental slice pass + (10, b = ..slice) + (a = 10, 10, 10) error, there shouldn't be normal args after named + + + (a: int, b: ..#vargs) // Var args will banish all forms of named arguments + (a = 10, b = 10) error + (b = 10, 10) error + (10, 10) OK + Any form of named arguments is invalid + + + (a: int, b: []Any) + (a = 10, b = {1, 2, "asd"}) + (a: int, b: []String) + + */ + // // Regular call // diff --git a/examples/_polymorphism.core b/examples/_polymorphism.core index 6db866c..3bcac37 100644 --- a/examples/_polymorphism.core +++ b/examples/_polymorphism.core @@ -25,6 +25,6 @@ Array :: struct($T: Type) cap: int main :: (argc: int, argv: **char): int - // array: Array(int) + array: Array(int) return 0 \ No newline at end of file