diff --git a/base_arena.cpp b/base_arena.cpp index dd92a90..9bb4faa 100644 --- a/base_arena.cpp +++ b/base_arena.cpp @@ -76,6 +76,15 @@ arena_push_size(Arena *a, size_t size) { return result; } +#define push_struct_copy(a, T, p) (T *)push_copy(a, p, sizeof(T)) +CORE_Static void * +push_copy(Arena *a, void *p, size_t size) { + if (p == 0) return 0; + void *result = arena_push_size(a, size); + memory_copy(result, p, size); + return result; +} + CORE_Static Arena push_arena(Allocator *allocator, size_t size, String debug_name) { Arena result = {}; diff --git a/base_data_structures.cpp b/base_data_structures.cpp index 3dfcb12..af85a11 100644 --- a/base_data_structures.cpp +++ b/base_data_structures.cpp @@ -50,6 +50,10 @@ struct Array { } } + void reset() { + len = 0; + } + void add(T item) { grow(1); data[len++] = item; diff --git a/core_ast.cpp b/core_ast.cpp index 6d6090f..907ff7c 100644 --- a/core_ast.cpp +++ b/core_ast.cpp @@ -237,7 +237,7 @@ ast_struct(Token *pos, Ast_Scope *scope, Ast_Kind kind, Array polymo CORE_Static Ast_Decl * ast_enum(Token *pos, Ast_Expr *typespec, Ast_Scope *scope) { - AST_NEW(Decl, ENUM, pos, AST_DECL | AST_AGGREGATE); + AST_NEW(Decl, ENUM, pos, AST_DECL); result->scope = scope; result->typespec = typespec; return result; diff --git a/core_compiler.cpp b/core_compiler.cpp index bb19652..207cfeb 100644 --- a/core_compiler.cpp +++ b/core_compiler.cpp @@ -291,7 +291,9 @@ resolve_everything_in_module(Ast_Module *module) { For_Named(file->decls, decl) { resolve_name(file, decl->pos, decl->name); - if (decl->kind == AST_STRUCT || decl->kind == AST_UNION) { + bool is_agg = decl->kind == AST_STRUCT || decl->kind == AST_UNION; + bool is_polymorph = decl->flags & AST_POLYMORPH; + if (is_agg && !is_polymorph) { type_complete(decl->type_val); } } diff --git a/core_compiler_includes.cpp b/core_compiler_includes.cpp index 838c224..79986d1 100644 --- a/core_compiler_includes.cpp +++ b/core_compiler_includes.cpp @@ -27,6 +27,7 @@ #include "core_parsing.cpp" #include "core_typechecking.h" #include "core_types.cpp" +#include "core_polymorph.cpp" #include "core_typechecking.cpp" #include "core_compiler.cpp" #include "core_codegen_c_language.cpp" \ No newline at end of file diff --git a/core_compiler_interface.hpp b/core_compiler_interface.hpp index c31fdad..697d868 100644 --- a/core_compiler_interface.hpp +++ b/core_compiler_interface.hpp @@ -211,6 +211,8 @@ enum Ast_Type_Kind { TYPE_COMPLETING, TYPE_INCOMPLETE, + TYPE_POLYMORPH, + TYPE_UNTYPED_BOOL, // FIRST_TYPED_NUMERIC, FIRST_NUMERIC TYPE_UNTYPED_INT, TYPE_UNTYPED_FLOAT, // LAST_TYPED_NUMERIC @@ -306,7 +308,6 @@ enum Ast_Kind : uint32_t { AST_FILE, AST_SCOPE, AST_VALUE, - AST_CAST, AST_IDENT, AST_INDEX, AST_UNARY, @@ -329,19 +330,15 @@ enum Ast_Kind : uint32_t { AST_TYPE, AST_VAR, AST_CONST, - AST_POINTER, AST_ARRAY, AST_FOR, AST_IF, AST_IF_NODE, AST_RETURN, - AST_BLOCK, AST_PASS, AST_LAMBDA, AST_LAMBDA_EXPR, - AST_LAMBDA_ARG, AST_ENUM, - AST_ENUM_MEMBER, AST_STRUCT, AST_UNION, }; @@ -371,6 +368,7 @@ struct Ast { Token *pos; Ast_Kind kind; + Ast_Scope *parent_scope; Ast_Flag flags; }; @@ -492,8 +490,8 @@ struct Ast_If : Ast { Array ifs; }; -struct Ast_Pass : Ast {}; -struct Ast_Break : Ast {}; +#define Ast_Pass Ast +#define Ast_Break Ast struct Ast_For : Ast { Ast_Expr *init; @@ -506,6 +504,9 @@ struct Ast_For : Ast { bool is_also_slice_traversal; }; +// @cleanup @refactor: return value shouldn't be a array of expressions. +// It should be a single expression. So probably need a special type +// for that. struct Ast_Lambda : Ast_Expr { Array args; Array ret; @@ -602,7 +603,9 @@ struct Ast_Decl : Ast { uint64_t operator_overload_arguments_hash; Ast_Operator_Info *overload_op_info; + Array polymorph_parameters; + Array polymorphs; // instantiated polymorphs Ast_Scope *scope; Ast_Expr *typespec; diff --git a/core_parsing.cpp b/core_parsing.cpp index 39f04e8..52305ec 100644 --- a/core_parsing.cpp +++ b/core_parsing.cpp @@ -735,8 +735,7 @@ parse_struct(Token *pos, Ast_Kind kind) { Ast_Expr *typespec = parse_expr(); Ast_Decl *decl = ast_var(token, typespec, token->intern_val, 0); - decl->flags = set_flag(decl->flags, AST_AGGREGATE_CHILD); - + set_flag(decl->flags, AST_AGGREGATE_CHILD); add(pctx->perm, &scope->decls, decl); } while (token_match(SAME_SCOPE)); @@ -760,7 +759,6 @@ parse_enum(Token *pos) { Ast_Expr *value = 0; if (token_match(TK_DoubleColon)) value = parse_expr(); Ast_Decl *member = ast_const(name, name->intern_val, value); - member->flags = set_flag(member->flags, AST_AGGREGATE_CHILD); add(pctx->perm, &scope->decls, member); } while (token_match(SAME_SCOPE)); finalize_decl_scope(scope); diff --git a/core_polymorph.cpp b/core_polymorph.cpp new file mode 100644 index 0000000..f573479 --- /dev/null +++ b/core_polymorph.cpp @@ -0,0 +1,351 @@ + + +Ast_Decl *get_or_instantiate_polymorph_type(Ast_Decl *poly, Array params) { + return 0; +} + +/* @todo +for (Ast_Iter iter = iterate_depth_first(ast); iter.ast; next(&iter)) { + Ast *ast = iter.ast; + + switch(ast->kind) { + case AST_CALL: { + + } break; + case AST_CALL_END: { + + } break; + } +} +*/ + +struct Ast_Iter { + Array stack; + Ast *ast; + Ast_Kind kind; +}; + +Ast_Iter iterate_depth_first(Allocator *a, Ast *ast) { + Ast_Iter result = {}; + result.stack = {a}; + result.ast = ast; + result.kind = ast->kind; + return result; +} + +void next(Ast_Iter *iter) { + Ast *ast = iter->ast; + switch (ast->kind) { + case AST_NAMESPACE: { + } break; + case AST_MODULE: { + } break; + case AST_FILE: { + } break; + case AST_SCOPE: { + } break; + case AST_VALUE: { + } break; + case AST_IDENT: { + } break; + case AST_INDEX: { + } break; + case AST_UNARY: { + } break; + case AST_BINARY: { + } break; + case AST_CALL_ITEM: { + } break; + case AST_CALL: { + } break; + case AST_CONSTANT_ASSERT: { + } break; + case AST_RUNTIME_ASSERT: { + } break; + case AST_SIZE_OF: { + } break; + case AST_LENGTH_OF: { + } break; + case AST_ALIGN_OF: { + } break; + case AST_TYPE_OF: { + } break; + case AST_SWITCH: { + } break; + case AST_SWITCH_CASE: { + } break; + case AST_VAR_UNPACK: { + } break; + case AST_BREAK: { + } break; + case AST_COMPOUND: { + } break; + case AST_TYPE: { + } break; + case AST_VAR: { + } break; + case AST_CONST: { + } break; + case AST_ARRAY: { + } break; + case AST_FOR: { + } break; + case AST_IF: { + } break; + case AST_IF_NODE: { + } break; + case AST_RETURN: { + } break; + case AST_PASS: { + } break; + case AST_LAMBDA: { + } break; + case AST_LAMBDA_EXPR: { + } break; + case AST_ENUM: { + } break; + case AST_STRUCT: { + } break; + case AST_UNION: { + } break; + } +} + +// We are not copying module and file Ast's +// We are not copying resolved data +// @todo: Need to copy Ast->parent_scope somehow +// @todo: reserve array sizes and use perm +Ast *ast_copy(Ast *ast) { + if (!ast) return 0; + switch (ast->kind) { + case AST_SCOPE: { + Ast_Scope *src = (Ast_Scope *)ast; + Ast_Scope *dst = push_struct_copy(pctx->perm, Ast_Scope, ast); + + dst->implicit_imports = {}; + For(src->implicit_imports) { + Ast_Scope *copy = (Ast_Scope *)ast_copy(it); + add(pctx->perm, &dst->implicit_imports, copy); + } + + dst->decls = {}; + For(src->decls) { + Ast_Decl *copy = (Ast_Decl *)ast_copy(it); + add(pctx->perm, &dst->decls, copy); + } + + dst->stmts = {}; + For(src->stmts) { + Ast *copy = ast_copy(it); + dst->stmts.add(copy); + } + return dst; + } break; + + case AST_MODULE: invalid_codepath; break; + case AST_FILE: invalid_codepath; break; + + case AST_IDENT: + case AST_VALUE: { + Ast_Atom *src = (Ast_Atom *)ast; + Ast_Atom *dst = push_struct_copy(pctx->perm, Ast_Atom, ast); + return dst; + } break; + + case AST_INDEX: { + Ast_Index *src = (Ast_Index *)ast; + Ast_Index *dst = push_struct_copy(pctx->perm, Ast_Index, ast); + dst->expr = (Ast_Expr *)ast_copy(src->expr); + dst->index = (Ast_Expr *)ast_copy(src->index); + return dst; + } break; + + case AST_UNARY: { + Ast_Unary *src = (Ast_Unary *)ast; + Ast_Unary *dst = push_struct_copy(pctx->perm, Ast_Unary, ast); + dst->expr = (Ast_Expr *)ast_copy(src->expr); + return dst; + } break; + + case AST_BINARY: { + Ast_Binary *src = (Ast_Binary *)ast; + Ast_Binary *dst = push_struct_copy(pctx->perm, Ast_Binary, ast); + dst->left = (Ast_Expr *)ast_copy(src->left); + dst->right = (Ast_Expr *)ast_copy(src->right); + return dst; + } break; + + case AST_CALL_ITEM: { + Ast_Call_Item *src = (Ast_Call_Item *)ast; + Ast_Call_Item *dst = push_struct_copy(pctx->perm, Ast_Call_Item, ast); + dst->item = (Ast_Expr *)ast_copy(src->item); + if (src->call_flags & CALL_INDEX) { + dst->index = (Ast_Expr *)ast_copy(src->index); + } + else if (src->call_flags & CALL_NAME) { + dst->name = (Ast_Atom *)ast_copy(src->name); + } + return dst; + } break; + + case AST_COMPOUND: + case AST_CALL: { + Ast_Call *src = (Ast_Call *)ast; + Ast_Call *dst = push_struct_copy(pctx->perm, Ast_Call, ast); + dst->name = (Ast_Expr *)ast_copy(src->name); + + dst->exprs = {}; + For(dst->exprs) { + auto copy = (Ast_Call_Item *)ast_copy(it); + dst->exprs.add(copy); + } + return 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 = push_struct_copy(pctx->perm, Ast_Builtin, ast); + dst->expr = (Ast_Expr *)ast_copy(src->expr); + return dst; + } break; + + case AST_SWITCH: { + Ast_Switch *src = (Ast_Switch *)ast; + Ast_Switch *dst = push_struct_copy(pctx->perm, Ast_Switch, ast); + dst->value = (Ast_Expr *)ast_copy(src->value); + dst->default_scope = (Ast_Scope *)ast_copy(src->default_scope); + dst->cases = {}; + For(src->cases) { + auto copy = (Ast_Switch_Case *)ast_copy(it); + assert(copy->kind == AST_SWITCH_CASE); + dst->cases.add(copy); + } + return dst; + } break; + + case AST_SWITCH_CASE: { + Ast_Switch_Case *src = (Ast_Switch_Case *)ast; + Ast_Switch_Case *dst = push_struct_copy(pctx->perm, Ast_Switch_Case, ast); + + dst->scope = (Ast_Scope *)ast_copy(src->scope); + dst->labels = {}; + For(src->labels) { + auto copy = (Ast_Expr *)ast_copy(it); + dst->labels.add(copy); + } + return dst; + } break; + + case AST_VAR_UNPACK: { + Ast_Var_Unpack *src = (Ast_Var_Unpack *)ast; + Ast_Var_Unpack *dst = push_struct_copy(pctx->perm, Ast_Var_Unpack, ast); + + dst->expr = (Ast_Expr *)ast_copy(src->expr); + dst->vars = {}; + For(src->vars) { + auto copy = (Ast_Decl *)ast_copy(it); + dst->vars.add(copy); + } + return dst; + } break; + + case AST_PASS: + case AST_BREAK: { + Ast *src = (Ast *)ast; + Ast *dst = push_struct_copy(pctx->perm, Ast, ast); + return 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 = push_struct_copy(pctx->perm, Ast_Decl, ast); + dst->overload_op_info = push_struct_copy(pctx->perm, Ast_Operator_Info, src->overload_op_info); + // omitting polymorphs + // omitting polymorph parameters + // For(src->polymorph_parameters) { + // auto copy = (Ast_Decl *)ast_copy(it); + // dst->polymorph_parameters.add(copy); + // } + dst->scope = (Ast_Scope *)ast_copy(src->scope); + dst->typespec = (Ast_Expr *)ast_copy(src->typespec); + dst->expr = (Ast_Expr *)ast_copy(src->expr); + return dst; + } break; + + case AST_ARRAY: { + Ast_Array *src = (Ast_Array *)ast; + Ast_Array *dst = push_struct_copy(pctx->perm, Ast_Array, ast); + dst->expr = (Ast_Expr *)ast_copy(src->expr); + return dst; + } break; + + case AST_FOR: { + Ast_For *src = (Ast_For *)ast; + Ast_For *dst = push_struct_copy(pctx->perm, Ast_For, ast); + dst->init = (Ast_Expr *)ast_copy(src->init); + dst->cond = (Ast_Expr *)ast_copy(src->cond); + dst->iter = (Ast_Expr *)ast_copy(src->iter); + dst->scope = (Ast_Scope *)ast_copy(src->scope); + return dst; + } break; + + case AST_IF: { + Ast_If *src = (Ast_If *)ast; + Ast_If *dst = push_struct_copy(pctx->perm, Ast_If, ast); + dst->ifs = {}; + For(src->ifs) { + auto copy = (Ast_If_Node *)ast_copy(it); + assert(copy->kind == AST_IF_NODE); + dst->ifs.add(copy); + } + return dst; + } break; + + case AST_IF_NODE: { + Ast_If_Node *src = (Ast_If_Node *)ast; + Ast_If_Node *dst = push_struct_copy(pctx->perm, Ast_If_Node, ast); + dst->expr = (Ast_Expr *)ast_copy(src->expr); + dst->init = (Ast_Binary *)ast_copy(src->init); + dst->scope = (Ast_Scope *)ast_copy(src->scope); + return dst; + } break; + + case AST_RETURN: { + Ast_Return *src = (Ast_Return *)ast; + Ast_Return *dst = push_struct_copy(pctx->perm, Ast_Return, ast); + For(src->expr) { + auto copy = (Ast_Expr *)ast_copy(it); + dst->expr.add(copy); + } + return dst; + } break; + + case AST_LAMBDA_EXPR: { + Ast_Lambda *src = (Ast_Lambda *)ast; + Ast_Lambda *dst = push_struct_copy(pctx->perm, Ast_Lambda, ast); + For(src->args) { + auto copy = (Ast_Decl *)ast_copy(it); + dst->args.add(copy); + } + For(src->ret) { + auto copy = (Ast_Expr *)ast_copy(it); + dst->ret.add(copy); + } + dst->scope = (Ast_Scope *)ast_copy(src->scope); + return dst; + } break; + } + invalid_return; +} \ No newline at end of file diff --git a/core_typechecking.cpp b/core_typechecking.cpp index efc2b90..018936a 100644 --- a/core_typechecking.cpp +++ b/core_typechecking.cpp @@ -1555,6 +1555,25 @@ resolve_expr(Ast_Expr *ast, Resolve_Flag flags, Ast_Type *compound_and_const_str else { Operand name = resolve_expr(node->name, inherit_flag(flags, AST_CANT_BE_NULL), 0, field_access_scope); + + // + // Polymorphic instantiation + // + if (name.type == pctx->type_type) { + 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; + // node->exprs = params + Ast_Decl *instance = get_or_instantiate_polymorph_type(poly, node->exprs); + // type_complete(decl); + return {}; // operand_type(resolved_type); + } + + // + // Regular call + // if (name.type->kind != TYPE_LAMBDA) { compiler_error(node->pos, "Calling %Q which is not a [Lambda]", typestring(name.type)); } @@ -1615,7 +1634,7 @@ resolve_expr(Ast_Expr *ast, Resolve_Flag flags, Ast_Type *compound_and_const_str compiler_error(node->pos, node->resolved_decl->pos, "Required value: %Q in lambda call was not passed", lambda_arg->name); } - // @note: default values are typechecked when they get resolved + // default values are typechecked when they get resolved Ast_Call_Item *call_item = ast_call_item(lambda_arg->expr->pos, 0, 0, lambda_arg->expr); call_item->resolved_type = lambda_arg->expr->resolved_type; call_item->resolved_index = lambda->args.get_index(&lambda_arg); @@ -1624,7 +1643,7 @@ resolve_expr(Ast_Expr *ast, Resolve_Flag flags, Ast_Type *compound_and_const_str } } - // @note: check if all arguments are included and cleanup + // check if all arguments are included and cleanup For(node->exprs) { if (!is_flag_set(it->call_flags, CALL_INCLUDED)) compiler_error(it->pos, "Unknown argument to a function call, couldn't match it with any of the declared arguments"); diff --git a/core_types.cpp b/core_types.cpp index c2ffc4c..35b6908 100644 --- a/core_types.cpp +++ b/core_types.cpp @@ -219,7 +219,9 @@ type_enum(Ast_Decl *ast, Ast_Type *type) { CORE_Static Ast_Type * type_incomplete(Ast *ast) { - Ast_Type *result = type_new(pctx->perm, TYPE_INCOMPLETE, 0, 0); + Ast_Type_Kind kind = TYPE_INCOMPLETE; + if (is_flag_set(ast->flags, AST_POLYMORPH)) kind = TYPE_POLYMORPH; + Ast_Type *result = type_new(pctx->perm, kind, 0, 0); result->ast = ast; return result; } diff --git a/examples/polymorphism.core b/examples/polymorphism.core index 2694134..3bcac37 100644 --- a/examples/polymorphism.core +++ b/examples/polymorphism.core @@ -25,4 +25,6 @@ Array :: struct($T: Type) cap: int main :: (argc: int, argv: **char): int + array: Array(int) + return 0 \ No newline at end of file