From 892c7e887404a3ed430d480cc9593bdbde336385 Mon Sep 17 00:00:00 2001 From: Christoffer Lerno Date: Wed, 26 May 2021 22:50:27 +0200 Subject: [PATCH] Changed generic modules to internal templates. --- README.md | 2 +- resources/lib/std/array.c3 | 41 ++- resources/lib/std/mem.c3 | 7 + src/compiler/ast.c | 4 + src/compiler/compiler.c | 14 +- src/compiler/compiler_internal.h | 53 ++-- src/compiler/context.c | 24 +- src/compiler/copying.c | 13 +- src/compiler/enums.h | 42 +-- src/compiler/headers.c | 3 + src/compiler/llvm_codegen_expr.c | 1 + src/compiler/llvm_codegen_function.c | 8 + src/compiler/llvm_codegen_type.c | 8 +- src/compiler/parse_global.c | 264 ++++++++---------- src/compiler/parse_stmt.c | 1 + src/compiler/sema_decls.c | 263 +++++++++-------- src/compiler/sema_expr.c | 3 + src/compiler/sema_name_resolution.c | 25 +- src/compiler/sema_passes.c | 8 +- src/compiler/sema_stmts.c | 18 +- src/compiler/sema_types.c | 1 + src/compiler/tokens.c | 2 + src/compiler/types.c | 48 +++- src/version.h | 2 +- test/test_suite/abi/literal_load.c3t | 12 +- test/test_suite/abi/union_x64.c3t | 8 +- test/test_suite/arrays/array_struct.c3t | 2 +- .../test_suite/arrays/complex_array_const.c3t | 2 +- test/test_suite/distinct/distinct_invalid.c3 | 2 - .../test_suite/expressions/pointer_access.c3t | 68 ++--- test/test_suite/functions/assorted_tests.c3t | 20 +- test/test_suite/globals/external_global.c3t | 8 +- test/test_suite/struct/simple_struct.c3t | 4 +- test/test_suite/struct/struct_codegen.c3t | 8 +- .../struct/struct_codegen_empty.c3t | 20 +- .../struct/struct_const_construct_simple.c3t | 18 +- .../struct/struct_pack_and_align.c3t | 34 +-- test/test_suite/union/union_codegen_const.c3t | 4 +- test/test_suite/union/union_codegen_empty.c3t | 24 +- .../union/union_codegen_overwrite_call.c3t | 8 +- test/test_suite/union/union_in_struct.c3t | 6 +- 41 files changed, 601 insertions(+), 502 deletions(-) diff --git a/README.md b/README.md index ef6cd3509..66ca74d02 100644 --- a/README.md +++ b/README.md @@ -91,7 +91,7 @@ work on Windows. Also, parts of the code is still rough and needs to be made sol - [x] Expression blocks - [x] Do-without-while - [x] Foreach statement -- [x] Generic modules +- [x] Templates - [x] Distinct types - [x] Built-in linking - [x] CT only macros evaluating to constants diff --git a/resources/lib/std/array.c3 b/resources/lib/std/array.c3 index 5969be682..3aa3708a6 100644 --- a/resources/lib/std/array.c3 +++ b/resources/lib/std/array.c3 @@ -1,5 +1,4 @@ module std::array; - import std::mem; public macro make($Type, usize elements) @@ -14,4 +13,42 @@ public macro make_zero($Type, usize elements) assert(elements > 0); $Type* ptr = mem::calloc($Type.sizeof, elements); return ptr[0..(elements - 1)]; -} \ No newline at end of file +} + +public template vararray +{ + public struct VarArray + { + usize size; + usize capacity; + Type *entries; + } + + public func void VarArray.append(VarArray *array, Type element) + { + if (array.capacity == array.size) + { + array.capacity = array.capacity ? 2 * array.capacity : 16; + array.entries = mem::realloc(array.entries, Type.sizeof * array.capacity); + } + array.entries[array.size++] = element; + } + + public func usize VarArray.len(VarArray *array) + { + return array.size; + } + + public func Type VarArray.get(VarArray *array, usize index) + { + return array.entries[index]; + } + + public func void VarArray.free(VarArray *array) + { + mem::free(array.entries); + array.capacity = 0; + array.size = 0; + } +} + diff --git a/resources/lib/std/mem.c3 b/resources/lib/std/mem.c3 index 8e8e7cb08..b30636005 100644 --- a/resources/lib/std/mem.c3 +++ b/resources/lib/std/mem.c3 @@ -117,6 +117,7 @@ public macro malloc($Type) { return ($Type*)(mem::alloc($Type.sizeof)); } + public func void* alloc(usize size, usize elements = 1) @inline { return _malloc(size * elements); @@ -126,6 +127,12 @@ public func void* calloc(usize size, usize elements = 1) @inline { return _calloc(size, elements); } + +public func void* realloc(void *ptr, usize size) @inline +{ + return _realloc(ptr, size); +} + public func void free(void* ptr) @inline { _free(ptr); diff --git a/src/compiler/ast.c b/src/compiler/ast.c index 9e0e44494..5d36841f3 100644 --- a/src/compiler/ast.c +++ b/src/compiler/ast.c @@ -106,6 +106,7 @@ Decl *decl_new_with_type(TokenId name, DeclKind decl_type, Visibility visibility case DECL_CT_SWITCH: case DECL_CT_CASE: case DECL_DEFINE: + case DECL_TEMPLATE: UNREACHABLE } Type *type = type_new(kind, !name.index ? "anon" : TOKSTR(name)); @@ -782,6 +783,9 @@ void fprint_decl_recursive(Context *context, FILE *file, Decl *decl, int indent) if (!decl) return; switch (decl->decl_kind) { + case DECL_TEMPLATE: + DUMPF("(template %s", decl->name); + DUMPEND(); case DECL_INTERFACE: DUMPF("(interface %s", decl->name); DUMPDECLS(decl->interface_decl.functions); diff --git a/src/compiler/compiler.c b/src/compiler/compiler.c index 690809f5d..76a60de82 100644 --- a/src/compiler/compiler.c +++ b/src/compiler/compiler.c @@ -41,7 +41,6 @@ void compiler_init(const char *std_lib_dir) stable_init(&global_context.modules, 64); stable_init(&global_context.scratch_table, 32); global_context.module_list = NULL; - global_context.generic_module_list = NULL; stable_init(&global_context.global_symbols, 0x1000); vmem_init(&ast_arena, 4 * 1024); vmem_init(&expr_arena, 4 * 1024); @@ -431,7 +430,7 @@ Module *global_context_find_module(const char *name) return stable_get(&global_context.modules, name); } -Module *compiler_find_or_create_module(Path *module_name, TokenId *parameters) +Module *compiler_find_or_create_module(Path *module_name) { Module *module = global_context_find_module(module_name->module); if (module) return module; @@ -441,18 +440,9 @@ Module *compiler_find_or_create_module(Path *module_name, TokenId *parameters) module = CALLOCS(Module); module->name = module_name; module->stage = ANALYSIS_NOT_BEGUN; - module->parameters = parameters; stable_init(&module->symbols, 0x10000); stable_set(&global_context.modules, module_name->module, module); - if (parameters) - { - vec_add(global_context.generic_module_list, module); - } - else - { - vec_add(global_context.module_list, module); - } - + vec_add(global_context.module_list, module); return module; } diff --git a/src/compiler/compiler_internal.h b/src/compiler/compiler_internal.h index 58c2d036b..091b1a372 100644 --- a/src/compiler/compiler_internal.h +++ b/src/compiler/compiler_internal.h @@ -36,8 +36,8 @@ typedef struct #define NO_TOKEN ((Token) { .type = TOKEN_INVALID_TOKEN }) #define INVALID_TOKEN_ID ((TokenId) { UINT32_MAX }) #define INVALID_RANGE ((SourceSpan){ INVALID_TOKEN_ID, INVALID_TOKEN_ID }) -#define MAX_LOCALS 0xFFFF -#define MAX_SCOPE_DEPTH 0x1000 +#define MAX_LOCALS 0xFFF +#define MAX_SCOPE_DEPTH 0x100 #define MAX_STRING_BUFFER 0x10000 #define MAX_MACRO_NESTING 1024 #define MAX_FUNCTION_SIGNATURE_SIZE 2048 @@ -320,6 +320,13 @@ typedef struct Decl **body; } CtCaseDecl; +typedef struct +{ + struct Context_ *parent_context; + TokenId *params; + Decl **body; +} TemplateDecl; + typedef struct { Expr *expr; @@ -387,6 +394,7 @@ typedef struct typedef struct { bool is_func : 1; + bool is_distinct : 1; union { FunctionSignature function_signature; @@ -428,28 +436,32 @@ typedef struct typedef enum { - DEFINE_FUNC, - DEFINE_DISTINCT_TYPE, - DEFINE_TYPE_ALIAS, + DEFINE_TYPE_TEMPLATE, DEFINE_IDENT_ALIAS, + DEFINE_IDENT_TEMPLATE, } DefineType; typedef struct { DefineType define_kind: 5; - bool is_parameterized : 1; union { - FunctionSignature function_signature; - TypeInfo *type_info; struct { - Path *path; + union + { + Path *path; + struct + { + Path *template_path; + TokenId template_name; + TypeInfo **template_params; + }; + }; TokenId identifier; }; Decl *alias; }; - TypeInfo **params; } DefineDecl; typedef struct @@ -528,6 +540,7 @@ typedef struct Decl_ CtCaseDecl ct_case_decl; Decl** ct_else_decl; Expr *incr_array_decl; + TemplateDecl template_decl; }; } Decl; @@ -1149,12 +1162,11 @@ typedef struct Ast_ typedef struct Module_ { Path *name; - TokenId *parameters; bool is_external : 1; bool is_c_library : 1; bool is_exported : 1; - bool is_generic : 1; + struct Context_ *template_parent_context; AnalysisStage stage : 6; Ast **files; // Asts @@ -1229,6 +1241,7 @@ typedef struct Context_ Decl **macros; Decl **generics; Decl **interfaces; + Decl **templates; Decl **methods; Decl **vars; Decl **incr_array; @@ -1270,6 +1283,8 @@ typedef struct Context_ STable external_symbols; Decl **external_symbol_list; }; + Decl* locals[MAX_LOCALS]; + DynamicScope scopes[MAX_SCOPE_DEPTH]; Lexer lexer; Token tok; TokenId prev_tok; @@ -1284,7 +1299,6 @@ typedef struct { STable modules; Module **module_list; - Module **generic_module_list; STable global_symbols; STable qualified_symbols; Type **type; @@ -1296,8 +1310,6 @@ typedef struct unsigned warnings_found; char scratch_buffer[MAX_STRING_BUFFER]; size_t scratch_buffer_len; - Decl* locals[MAX_LOCALS]; - DynamicScope scopes[MAX_SCOPE_DEPTH]; STable scratch_table; Module std_module; Path std_module_path; @@ -1550,7 +1562,7 @@ void header_gen(Module *module); void global_context_add_type(Type *type); Decl *compiler_find_symbol(const char *name); -Module *compiler_find_or_create_module(Path *module_name, TokenId *parameters); +Module *compiler_find_or_create_module(Path *module_name); Module *global_context_find_module(const char *name); void compiler_register_public_symbol(Decl *decl); @@ -1559,8 +1571,10 @@ void context_register_global_decl(Context *context, Decl *decl); void context_register_external_symbol(Context *context, Decl *decl); bool context_add_import(Context *context, Path *path, Token symbol, Token alias, bool private_import); bool context_set_module_from_filename(Context *context); -bool context_set_module(Context *context, Path *path, TokenId *generic_parameters); + +bool context_set_module(Context *context, Path *path); void context_print_ast(Context *context, FILE *file); +Decl **context_get_imports(Context *context); #pragma mark --- Decl functions @@ -1579,7 +1593,7 @@ static inline bool decl_is_struct_type(Decl *decl); static inline DeclKind decl_from_token(TokenType type); static inline Decl *decl_flatten(Decl *decl) { - if (decl->decl_kind == DECL_DEFINE && decl->define_decl.define_kind == DEFINE_IDENT_ALIAS) + if (decl->decl_kind == DECL_DEFINE && decl->define_decl.define_kind != DEFINE_TYPE_TEMPLATE) { return decl->define_decl.alias; } @@ -1671,6 +1685,7 @@ const char *resolve_status_to_string(ResolveStatus status); void sema_analysis_pass_process_imports(Module *module); void sema_analysis_pass_register_globals(Module *module); void sema_analysis_pass_conditional_compilation(Module *module); +void sema_analysis_pass_templates(Module *module); void sema_analysis_pass_decls(Module *module); void sema_analysis_pass_ct_assert(Module *module); void sema_analysis_pass_functions(Module *module); @@ -1978,7 +1993,7 @@ static inline Type *type_flatten_distinct(Type *type) type = type->canonical; while (type->type_kind == TYPE_DISTINCT) { - type = type->decl->define_decl.type_info->type->canonical; + type = type->decl->distinct_decl.base_type; } return type; } diff --git a/src/compiler/context.c b/src/compiler/context.c index 3dcf18fbf..d3cbcea2d 100644 --- a/src/compiler/context.c +++ b/src/compiler/context.c @@ -15,12 +15,12 @@ Context *context_create(File *file) } -static inline bool create_module_or_check_name(Context *context, Path *module_name, TokenId *parameters) +static inline bool create_module_or_check_name(Context *context, Path *module_name) { context->module_name = module_name; if (context->module == NULL) { - context->module = compiler_find_or_create_module(module_name, parameters); + context->module = compiler_find_or_create_module(module_name); return true; } @@ -55,10 +55,10 @@ bool context_set_module_from_filename(Context *context) path->span = INVALID_RANGE; path->module = module_name; path->len = len; - return create_module_or_check_name(context, path, NULL); + return create_module_or_check_name(context, path); } -bool context_set_module(Context *context, Path *path, TokenId *generic_parameters) +bool context_set_module(Context *context, Path *path) { // Note that we allow the illegal name for now, to be able to parse further. context->module_name = path; @@ -68,7 +68,7 @@ bool context_set_module(Context *context, Path *path, TokenId *generic_parameter return false; } - return create_module_or_check_name(context, path, generic_parameters); + return create_module_or_check_name(context, path); } @@ -91,6 +91,11 @@ void context_register_global_decl(Context *context, Decl *decl) { case DECL_POISONED: break; + case DECL_TEMPLATE: + vec_add(context->templates, decl); + decl->template_decl.parent_context = context; + decl_set_external_name(decl); + break; case DECL_INTERFACE: vec_add(context->interfaces, decl); decl_set_external_name(decl); @@ -107,13 +112,11 @@ void context_register_global_decl(Context *context, Decl *decl) if (decl->func.type_parent) { vec_add(context->methods, decl); - // TODO set name return; } else { vec_add(context->functions, decl); - decl_set_external_name(decl); } break; case DECL_VAR: @@ -212,6 +215,13 @@ bool context_add_import(Context *context, Path *path, Token token, Token alias, return true; } +Decl **context_get_imports(Context *context) +{ + Context *parent_context = context->module->template_parent_context; + if (parent_context) return parent_context->imports; + return context->imports; +} + void context_print_ast(Context *context, FILE *file) { VECEACH(context->enums, i) diff --git a/src/compiler/copying.c b/src/compiler/copying.c index 7a049b486..e77ffd926 100644 --- a/src/compiler/copying.c +++ b/src/compiler/copying.c @@ -471,6 +471,9 @@ Decl *copy_decl(Decl *decl) { case DECL_POISONED: break; + case DECL_TEMPLATE: + MACRO_COPY_DECL_LIST(copy->template_decl.body); + break; case DECL_UNION: case DECL_STRUCT: case DECL_ERR: @@ -559,15 +562,11 @@ Decl *copy_decl(Decl *decl) case DECL_ATTRIBUTE: TODO case DECL_DEFINE: - MACRO_COPY_TYPE_LIST(decl->define_decl.params); switch (decl->define_decl.define_kind) { - case DEFINE_FUNC: - copy_function_signature_deep(&decl->define_decl.function_signature); - break; - case DEFINE_DISTINCT_TYPE: - case DEFINE_TYPE_ALIAS: - MACRO_COPY_TYPE(decl->define_decl.type_info); + case DEFINE_TYPE_TEMPLATE: + case DEFINE_IDENT_TEMPLATE: + MACRO_COPY_TYPE_LIST(decl->define_decl.template_params); break; case DEFINE_IDENT_ALIAS: break; diff --git a/src/compiler/enums.h b/src/compiler/enums.h index 746e704a0..d81033b6c 100644 --- a/src/compiler/enums.h +++ b/src/compiler/enums.h @@ -136,34 +136,35 @@ typedef enum typedef enum { DECL_POISONED = 0, - DECL_FUNC, - DECL_VAR, - DECL_LABEL, - DECL_ENUM_CONSTANT, - DECL_TYPEDEF, - DECL_DISTINCT, - DECL_STRUCT, - DECL_UNION, - DECL_ENUM, - DECL_ERR, - DECL_ARRAY_VALUE, - DECL_IMPORT, - DECL_MACRO, - DECL_GENERIC, - DECL_CT_IF, - DECL_CT_ELSE, - DECL_CT_ELIF, - DECL_CT_SWITCH, - DECL_CT_CASE, DECL_ATTRIBUTE, + DECL_ARRAY_VALUE, + DECL_CT_CASE, + DECL_CT_ELIF, + DECL_CT_ELSE, + DECL_CT_IF, + DECL_CT_SWITCH, DECL_DEFINE, + DECL_DISTINCT, + DECL_ENUM, + DECL_ENUM_CONSTANT, + DECL_ERR, + DECL_FUNC, + DECL_GENERIC, + DECL_IMPORT, DECL_INTERFACE, + DECL_LABEL, + DECL_MACRO, + DECL_STRUCT, + DECL_TEMPLATE, + DECL_TYPEDEF, + DECL_UNION, + DECL_VAR, } DeclKind; #define NON_TYPE_DECLS DECL_ARRAY_VALUE: case DECL_IMPORT: case DECL_MACRO: \ case DECL_GENERIC: case DECL_CT_IF: case DECL_CT_ELSE: case DECL_CT_ELIF: \ case DECL_CT_SWITCH: case DECL_CT_CASE: case DECL_ATTRIBUTE: case DECL_LABEL: \ - case DECL_DEFINE + case DECL_DEFINE: case DECL_TEMPLATE typedef enum { @@ -431,6 +432,7 @@ typedef enum TOKEN_STATIC, TOKEN_STRUCT, TOKEN_SWITCH, + TOKEN_TEMPLATE, TOKEN_TRUE, TOKEN_TRY, TOKEN_TYPEOF, diff --git a/src/compiler/headers.c b/src/compiler/headers.c index 8170765ab..d6fe3735c 100644 --- a/src/compiler/headers.c +++ b/src/compiler/headers.c @@ -230,6 +230,9 @@ static void header_gen_decl(FILE *file, int indent, Decl *decl) case DECL_ERR: header_gen_err(file, indent, decl); return; + case DECL_TEMPLATE: + // Skipped + return; } UNREACHABLE } diff --git a/src/compiler/llvm_codegen_expr.c b/src/compiler/llvm_codegen_expr.c index 4cfd117d6..85060038d 100644 --- a/src/compiler/llvm_codegen_expr.c +++ b/src/compiler/llvm_codegen_expr.c @@ -2624,6 +2624,7 @@ void llvm_emit_call_expr(GenContext *c, BEValue *be_value, Expr *expr) // 2b. Set signature, function and function type signature = &function_decl->func.function_signature; func = function_decl->backend_ref; + assert(func); func_type = llvm_get_type(c, function_decl->type); } else diff --git a/src/compiler/llvm_codegen_function.c b/src/compiler/llvm_codegen_function.c index 77299f6eb..a51f40c7b 100644 --- a/src/compiler/llvm_codegen_function.c +++ b/src/compiler/llvm_codegen_function.c @@ -634,10 +634,18 @@ void llvm_emit_extern_decl(GenContext *context, Decl *decl) case DECL_STRUCT: case DECL_UNION: case DECL_ERR: + VECEACH(decl->methods, i) + { + llvm_emit_function_decl(context, decl->methods[i]); + } llvm_get_type(context, decl->type); // TODO // Fix typeid break; case DECL_ENUM: + VECEACH(decl->methods, i) + { + llvm_emit_function_decl(context, decl->methods[i]); + } TODO case NON_TYPE_DECLS: case DECL_INTERFACE: diff --git a/src/compiler/llvm_codegen_type.c b/src/compiler/llvm_codegen_type.c index 79da7a647..e570dafbb 100644 --- a/src/compiler/llvm_codegen_type.c +++ b/src/compiler/llvm_codegen_type.c @@ -13,8 +13,8 @@ static inline LLVMTypeRef llvm_type_from_decl(GenContext *c, Decl *decl) case DECL_VAR: case DECL_ENUM_CONSTANT: case DECL_POISONED: - case NON_TYPE_DECLS: case DECL_INTERFACE: + case NON_TYPE_DECLS: UNREACHABLE case DECL_FUNC: { @@ -36,7 +36,7 @@ static inline LLVMTypeRef llvm_type_from_decl(GenContext *c, Decl *decl) case DECL_STRUCT: { LLVMTypeRef *types = NULL; - LLVMTypeRef type = LLVMStructCreateNamed(c->context, decl->external_name); + LLVMTypeRef type = LLVMStructCreateNamed(c->context, decl->name ?: "anon"); // Avoid recursive issues. decl->type->backend_type = type; Decl **members = decl->strukt.members; @@ -58,7 +58,7 @@ static inline LLVMTypeRef llvm_type_from_decl(GenContext *c, Decl *decl) } case DECL_UNION: { - LLVMTypeRef type = LLVMStructCreateNamed(c->context, decl->external_name); + LLVMTypeRef type = LLVMStructCreateNamed(c->context, decl->name ?: "anon"); // Avoid recursive issues. decl->type->backend_type = type; Decl **members = decl->strukt.members; @@ -87,7 +87,7 @@ static inline LLVMTypeRef llvm_type_from_decl(GenContext *c, Decl *decl) return llvm_get_type(c, decl->type); case DECL_ERR: { - LLVMTypeRef err_type = LLVMStructCreateNamed(c->context, decl->external_name); + LLVMTypeRef err_type = LLVMStructCreateNamed(c->context, decl->name); // Avoid recursive issues. decl->type->backend_type = err_type; LLVMTypeRef *types = NULL; diff --git a/src/compiler/parse_global.c b/src/compiler/parse_global.c index ec9fdf2a0..30f51f46a 100644 --- a/src/compiler/parse_global.c +++ b/src/compiler/parse_global.c @@ -4,6 +4,11 @@ static Decl *parse_const_declaration(Context *context, Visibility visibility); static inline Decl *parse_func_definition(Context *context, Visibility visibility, bool is_interface); +static bool context_next_is_path_prefix_start(Context *context) +{ + return context->tok.type == TOKEN_IDENT && context->next_tok.type == TOKEN_SCOPE; +} + /** * Walk forward through the token stream to identify a type on the format: foo::bar::Type * @@ -12,7 +17,7 @@ static inline Decl *parse_func_definition(Context *context, Visibility visibilit static bool context_next_is_type_with_path_prefix(Context *context) { // We assume it's called after "foo::" parsing. - assert(context->tok.type == TOKEN_IDENT && context->next_tok.type == TOKEN_SCOPE); + if (!context_next_is_path_prefix_start(context)) return false; TokenId current = context->next_tok.id; while (1) @@ -274,60 +279,7 @@ static inline Path *parse_module_path(Context *context) /** - * - * module_param - * : TYPE_IDENT - * | IDENT - * ; - * - * module_params - * : module_param - * | module_params ',' module_param - * ; - */ -static inline bool parse_optional_module_params(Context *context, TokenId **tokens) -{ - - *tokens = NULL; - - if (!try_consume(context, TOKEN_LPAREN)) return true; - - if (try_consume(context, TOKEN_RPAREN)) - { - SEMA_TOKEN_ERROR(context->tok, "Generic parameter list cannot be empty."); - return false; - } - - // No params - while (1) - { - switch (context->tok.type) - { - case TOKEN_IDENT: - case TOKEN_TYPE_IDENT: - break; - case TOKEN_COMMA: - SEMA_TOKEN_ERROR(context->tok, "Unexpected ','"); - return false; - case TOKEN_CT_IDENT: - case TOKEN_CT_TYPE_IDENT: - SEMA_TOKEN_ERROR(context->tok, "The module parameter cannot be a $-prefixed name."); - return false; - default: - SEMA_TOKEN_ERROR(context->tok, "Only generic parameters are allowed here as parameters to the module."); - return false; - } - *tokens = VECADD(*tokens, context->tok.id); - advance(context); - if (!try_consume(context, TOKEN_COMMA)) - { - return consume(context, TOKEN_RPAREN, "Expected ')'."); - } - } - -} -/** - * module ::= MODULE module_path ('(' module_params ')')? EOS + * module ::= MODULE module_path EOS */ bool parse_module(Context *context) { @@ -338,7 +290,7 @@ bool parse_module(Context *context) if (!TOKEN_IS(TOKEN_IDENT)) { - SEMA_TOKEN_ERROR(context->tok, "Module statement should be followed by the name of the module to import."); + SEMA_TOKEN_ERROR(context->tok, "Module statement should be followed by the name of the module."); return false; } @@ -351,20 +303,12 @@ bool parse_module(Context *context) path->len = strlen("INVALID"); path->module = "INVALID"; path->span = INVALID_RANGE; - context_set_module(context, path, NULL); + context_set_module(context, path); recover_top_level(context); return false; } - // Is this a generic module? - TokenId *generic_parameters = NULL; - if (!parse_optional_module_params(context, &generic_parameters)) - { - context_set_module(context, path, NULL); - recover_top_level(context); - return true; - } - context_set_module(context, path, generic_parameters); + context_set_module(context, path); TRY_CONSUME_EOS_OR(false); return true; } @@ -1499,49 +1443,44 @@ static inline TypeInfo **parse_parameterized_define(Context *context) return types; } -/** - * func_define ::= failable_type opt_parameter_type_list - */ -static inline bool parse_func_define(Context *context, Decl *decl, Visibility visibility, TypeInfo *return_type) +static inline bool parse_define_optional_path(Context *context, Path **path) { - decl->define_decl.define_kind = DEFINE_FUNC; - if (try_consume(context, TOKEN_BANG)) + if (context->tok.type != TOKEN_IDENT || context->next_tok.type != TOKEN_SCOPE) { - decl->define_decl.function_signature.failable = true; - } - decl->define_decl.function_signature.rtype = return_type; - if (!parse_opt_parameter_type_list(context, visibility, &(decl->typedef_decl.function_signature), true)) - { - return false; + *path = NULL; + return true; } + bool error = false; + *path = parse_path_prefix(context, &error); + if (error) return false; return true; } - -static inline Decl *parse_typedef_body_function_ptr(Context *context, Decl *decl) -{ - decl->typedef_decl.is_func = true; - assert(decl->typedef_decl.type_info); - decl->typedef_decl.function_signature.rtype = decl->typedef_decl.type_info; - if (try_consume(context, TOKEN_BANG)) - { - decl->typedef_decl.function_signature.failable = true; - } - if (!parse_opt_parameter_type_list(context, decl->visibility, &(decl->typedef_decl.function_signature), true)) - { - return poisoned_decl; - } - TRY_CONSUME_OR(TOKEN_STAR, "Function pointers must end with a '*'", poisoned_decl); - RANGE_EXTEND_PREV(decl); - TRY_CONSUME_EOS_OR(poisoned_decl); - return decl; -} - - /** - * define_type_body ::= - * TYPE_IDENT '=' typedef_body | generic_define (('distinct') type ('!' parameter_type_list '*')?) | (path TYPE_IDENT '(' type_list ')') + * template ::= IDENT '<' TYPE_INDENT (',' TYPE_IDENT)* '>' '::' + */ +static inline bool parse_define_template(Context *context, Decl *decl) +{ + decl->define_decl.template_name = context->tok.id; + // These should already be checked. + advance_and_verify(context, TOKEN_IDENT); + advance_and_verify(context, TOKEN_LESS); + if (TOKEN_IS(TOKEN_GREATER)) + { + SEMA_TOKEN_ERROR(context->tok, "Expected at least one type as a parameter."); + return false; + } + TypeInfo **types = parse_parameterized_define(context); + if (!types) return false; + decl->define_decl.template_params = types; + TRY_CONSUME_OR(TOKEN_SCOPE, "Expected a template name.", false); + return true; +} +/** + * define_type_body ::= TYPE_IDENT '=' 'distinct'? (func_typedef | type_template | type) ';' * + * func_typedef ::= 'func' failable_type parameter_type_list + * type_template ::= path? IDENT '<' TYPE_IDENT (',' TYPE_IDENT)+ '>' '::' TYPE_IDENT */ static inline Decl *parse_define_type(Context *context, Visibility visibility) { @@ -1549,6 +1488,7 @@ static inline Decl *parse_define_type(Context *context, Visibility visibility) advance_and_verify(context, TOKEN_DEFINE); TokenId alias_name = context->tok.id; + DEBUG_LOG("Parse define %s", TOKSTR(alias_name)); advance_and_verify(context, TOKEN_TYPE_IDENT); CONSUME_OR(TOKEN_EQ, poisoned_decl); bool distinct = false; @@ -1558,14 +1498,13 @@ static inline Decl *parse_define_type(Context *context, Visibility visibility) advance(context); } - // 1. Did we have `func`? In that case it's a function pointer. if (try_consume(context, TOKEN_FUNC)) { - assert(!distinct && "TODO"); Decl *decl = decl_new_with_type(alias_name, DECL_TYPEDEF, visibility); decl->span.loc = start; decl->typedef_decl.is_func = true; + decl->typedef_decl.is_distinct = distinct; TypeInfo *type_info = TRY_TYPE_OR(parse_type(context), poisoned_decl); decl->typedef_decl.function_signature.rtype = type_info; if (try_consume(context, TOKEN_BANG)) @@ -1581,12 +1520,11 @@ static inline Decl *parse_define_type(Context *context, Visibility visibility) return decl; } - TypeInfo *type_info = TRY_TYPE_OR(parse_type(context), poisoned_decl); - // 2. define Foo = foo::bar::Type; - // this is always a normal typedef / distinct. - if (TOKEN_IS(TOKEN_EOS)) + // 2. Do we have a regular foo::bar::baz::Type? Then this is a regular typedef. + if (token_is_any_type(context->tok.type) || context_next_is_type_with_path_prefix(context)) { + TypeInfo *type_info = TRY_TYPE_OR(parse_type(context), poisoned_decl); Decl *decl = decl_new_with_type(alias_name, distinct ? DECL_DISTINCT : DECL_TYPEDEF, visibility); decl->span.loc = start; decl->typedef_decl.type_info = type_info; @@ -1598,37 +1536,41 @@ static inline Decl *parse_define_type(Context *context, Visibility visibility) decl->decl_kind = DECL_DISTINCT; } RANGE_EXTEND_PREV(decl); - advance_and_verify(context, TOKEN_EOS); + TRY_CONSUME_EOS_OR(poisoned_decl); return decl; } - // 3. Assume we missed a ';' if we don't see '<' - if (!TOKEN_IS(TOKEN_LESS)) + // 3. This must be a template, e.g. define foo::bar::template_name::Baz; + Decl *decl = decl_new(DECL_DEFINE, alias_name, visibility); + if (!parse_define_optional_path(context, &decl->define_decl.template_path)) return poisoned_decl; + if (!TOKEN_IS(TOKEN_IDENT)) { - SEMA_TOKEN_ERROR(context->tok, "Expected a ';' here"); - return false; - } - - advance(context); - // 4. We assume parameterization - if (TOKEN_IS(TOKEN_GREATER)) - { - SEMA_TOKEN_ERROR(context->tok, "Expected at least one type as a parameter."); + SEMA_TOKEN_ERROR(context->tok, "Expected a template name here."); return poisoned_decl; } - TypeInfo **types = parse_parameterized_define(context); - if (!types) return poisoned_decl; - Decl *decl = decl_new(DECL_DEFINE, alias_name, visibility); - decl->span.loc = start; - decl->define_decl.is_parameterized = true; - decl->define_decl.params = types; - decl->define_decl.define_kind = DEFINE_TYPE_ALIAS; - decl->define_decl.type_info = type_info; - RANGE_EXTEND_PREV(decl); + if (context->next_tok.type != TOKEN_LESS) + { + SEMA_TOKEN_ERROR(context->tok, "Expected a template definition."); + return poisoned_decl; + } + if (!parse_define_template(context, decl)) return poisoned_decl; + + // 4. We've now read up to the last :: so we just read the type name: + TRY_CONSUME_OR(TOKEN_TYPE_IDENT, "Expected the templated type", poisoned_decl); + decl->define_decl.identifier = context->prev_tok; + decl->define_decl.define_kind = DEFINE_TYPE_TEMPLATE; TRY_CONSUME_EOS_OR(poisoned_decl); + return decl; } +/** + * define_ident ::= 'define' (IDENT | CONST_IDENT) '=' (identifier_alias | template_identifier) + * + * identifier_alias ::= path? (IDENT | CONST_IDENT) + * template_identifier ::= path? IDENT '<' TYPE_IDENT (',' TYPE_IDENT)+ '>' '::' (IDENT | CONST_IDENT) + * + */ static inline Decl *parse_define_ident(Context *context, Visibility visibility) { // 1. Store the beginning of the define. @@ -1655,14 +1597,26 @@ static inline Decl *parse_define_ident(Context *context, Visibility visibility) // 5. Here we may an (optional) path, we just check if it starts // with IDENT '::' - decl->define_decl.path = NULL; - if (TOKEN_IS(TOKEN_IDENT) && context->next_tok.type == TOKEN_SCOPE) + Path *path = NULL; + if (context_next_is_path_prefix_start(context)) { bool error; - decl->define_decl.path = parse_path_prefix(context, &error); + path = parse_path_prefix(context, &error); if (error) return poisoned_decl; } + // 6. Is the next part IDENT '<'? If so it's a template name. + if (TOKEN_IS(TOKEN_IDENT) && context->next_tok.type == TOKEN_LESS) + { + decl->define_decl.template_path = path; + decl->define_decl.define_kind = DEFINE_IDENT_TEMPLATE; + if (!parse_define_template(context, decl)) return poisoned_decl; + } + else + { + decl->define_decl.path = path; + } + // 6. Check that the token after the path is of the same type. if (context->tok.type != alias_type) { @@ -1681,23 +1635,8 @@ static inline Decl *parse_define_ident(Context *context, Visibility visibility) decl->define_decl.identifier = context->tok.id; advance(context); - // 8. Is this one parameterized? If so parse the parameters. - if (try_consume(context, TOKEN_LESS)) - { - if (TOKEN_IS(TOKEN_GREATER)) - { - SEMA_TOKEN_ERROR(context->tok, "Expected at least one type as a parameter."); - return poisoned_decl; - } - TypeInfo **types = parse_parameterized_define(context); - if (!types) return poisoned_decl; - decl->define_decl.is_parameterized = true; - decl->define_decl.params = types; - } - RANGE_EXTEND_PREV(decl); TRY_CONSUME_EOS_OR(poisoned_decl); - return decl; } /** @@ -2036,6 +1975,36 @@ static inline Decl *parse_func_definition(Context *context, Visibility visibilit return func; } +/** + * template_declaration ::= 'template' IDENT '<' TYPE_IDENT (',' TYPE_IDENT)* '>' template_body + * template_body = '{' top_level* '}' + */ +static inline Decl *parse_template_declaration(Context *context, Visibility visibility) +{ + advance_and_verify(context, TOKEN_TEMPLATE); + TokenId name = context->tok.id; + if (!consume_ident(context, "template")) return poisoned_decl; + Decl *decl = decl_new(DECL_TEMPLATE, name, visibility); + CONSUME_OR(TOKEN_LESS, poisoned_decl); + TokenId *params = NULL; + while (1) + { + vec_add(params, context->tok.id); + if (!consume_type_name(context, "type")) return poisoned_decl; + if (try_consume(context, TOKEN_GREATER)) break; + CONSUME_OR(TOKEN_COMMA, poisoned_decl); + } + decl->template_decl.params = params; + CONSUME_OR(TOKEN_LBRACE, poisoned_decl); + Decl **body = NULL; + while (!try_consume(context, TOKEN_RBRACE)) + { + Decl *statement = parse_top_level_statement(context); + vec_add(body, statement); + } + decl->template_decl.body = body; + return decl; +} /** * interface_declaration ::= INTERFACE TYPE '{' func_decl* '}' @@ -2359,6 +2328,9 @@ Decl *parse_top_level_statement(Context *context) case TOKEN_CONST: decl = TRY_DECL_OR(parse_top_level_const_declaration(context, visibility), poisoned_decl); break; + case TOKEN_TEMPLATE: + decl = TRY_DECL_OR(parse_template_declaration(context, visibility), poisoned_decl); + break; case TOKEN_INTERFACE: decl = TRY_DECL_OR(parse_interface_declaration(context, visibility), poisoned_decl); break; diff --git a/src/compiler/parse_stmt.c b/src/compiler/parse_stmt.c index 46c9e0864..81362b059 100644 --- a/src/compiler/parse_stmt.c +++ b/src/compiler/parse_stmt.c @@ -1167,6 +1167,7 @@ Ast *parse_stmt(Context *context) case TOKEN_RBRAPIPE: case TOKEN_BANGBANG: case TOKEN_UNDERSCORE: + case TOKEN_TEMPLATE: SEMA_TOKEN_ERROR(context->tok, "Unexpected '%s' found when expecting a statement.", token_type_to_string(context->tok.type)); advance(context); return poisoned_ast; diff --git a/src/compiler/sema_decls.c b/src/compiler/sema_decls.c index 1d377f347..9443426b5 100644 --- a/src/compiler/sema_decls.c +++ b/src/compiler/sema_decls.c @@ -576,8 +576,23 @@ static inline bool sema_analyse_method(Context *context, Decl *decl) return false; } } + scratch_buffer_clear(); + if (decl->visibility <= VISIBLE_MODULE) + { + scratch_buffer_append(parent->name); + scratch_buffer_append_char('.'); + scratch_buffer_append(decl->name); + } + else + { + scratch_buffer_append(parent->external_name); + scratch_buffer_append("__"); + scratch_buffer_append(decl->name); + } + decl->external_name = scratch_buffer_interned(); DEBUG_LOG("Method '%s.%s' analysed.", parent->name, decl->name); vec_add(parent->methods, decl); + return true; } @@ -685,7 +700,7 @@ static AttributeType sema_analyse_attribute(Context *context, Attr *attr, Attrib return type; case ATTRIBUTE_SECTION: case ATTRIBUTE_CNAME: - if (context->module->is_generic) + if (context->module->template_parent_context) { SEMA_TOKID_ERROR(attr->name, "'cname' attributes are not allowed in generic modules."); return false; @@ -723,6 +738,19 @@ static inline bool sema_analyse_func(Context *context, Decl *decl) { if (!sema_analyse_method(context, decl)) return decl_poison(decl); } + else + { + if (decl->name == kw_main) + { + if (decl->visibility == VISIBLE_LOCAL) + { + SEMA_ERROR(decl, "'main' cannot have local visibility."); + return false; + } + decl->visibility = VISIBLE_EXTERN; + } + decl_set_external_name(decl); + } VECEACH(decl->attributes, i) { Attr *attr = decl->attributes[i]; @@ -766,15 +794,6 @@ static inline bool sema_analyse_func(Context *context, Decl *decl) return decl_poison(decl); } } - if (decl->name == kw_main) - { - if (decl->visibility == VISIBLE_LOCAL) - { - SEMA_ERROR(decl, "'main' cannot have local visibility."); - return false; - } - decl->visibility = VISIBLE_EXTERN; - } DEBUG_LOG("Function analysis done."); return true; } @@ -816,6 +835,25 @@ static inline bool sema_analyse_macro(Context *context, Decl *decl) } +static inline bool sema_analyse_template(Context *context, Decl *decl) +{ + decl->template_decl.parent_context = context; + stable_clear(&global_context.scratch_table); + VECEACH(decl->template_decl.params, i) + { + TokenId *param = &decl->template_decl.params[i]; + const char *key = TOKSTR(*param); + TokenId *ptr = stable_set(&global_context.scratch_table, key, param); + if (ptr) + { + SEMA_TOKID_ERROR(*param, "Duplicate parameter name '%s'.", TOKSTR(*param)); + return false; + } + } + return true; +} + + static inline bool sema_analyse_global(Context *context, Decl *decl) @@ -998,19 +1036,20 @@ static Context *copy_context(Module *module, Context *c) return copy; } -static Module *sema_instantiate_module(Context *context, Module *module, Path *path, TypeInfo **parms) +static Module *sema_instantiate_template(Context *context, Decl *template, Path *path, TypeInfo **parms) { - Module *new_module = compiler_find_or_create_module(path, NULL); - new_module->is_generic = true; - Context **contexts = module->contexts; - VECEACH(contexts, i) + DEBUG_LOG("Instantiate template %s", path->module); + Module *new_module = compiler_find_or_create_module(path); + Context *source_context = template->template_decl.parent_context; + + Context *new_context = context_create(context->file); + new_context->module = new_module; + new_module->template_parent_context = source_context; + new_context->global_decls = copy_decl_list(template->template_decl.body); + vec_add(new_module->contexts, new_context); + VECEACH(template->template_decl.params, i) { - vec_add(new_module->contexts, copy_context(new_module, contexts[i])); - } - Context *first_context = new_module->contexts[0]; - VECEACH(module->parameters, i) - { - TokenId param = module->parameters[i]; + TokenId param = template->template_decl.params[i]; Decl *decl = decl_new_with_type(param, DECL_TYPEDEF, VISIBLE_PUBLIC); decl->resolve_status = RESOLVE_DONE; TypeInfo *type_info = parms[i]; @@ -1018,175 +1057,124 @@ static Module *sema_instantiate_module(Context *context, Module *module, Path *p decl->typedef_decl.type_info = type_info; decl->type->name = decl->name; decl->type->canonical = type_info->type->canonical; - vec_add(first_context->global_decls, decl); + vec_add(new_context->global_decls, decl); } return new_module; } static Decl *sema_analyse_parameterized_define(Context *c, Decl *decl) { - Path *decl_path; - bool mismatch = false; - const char *name; - SourceSpan mismatch_span = INVALID_RANGE; - switch (decl->define_decl.define_kind) + Decl *ambiguous = NULL; + Decl *private_decl = NULL; + TokenId template_token = decl->define_decl.template_name; + const char *template_name = TOKSTR(template_token); + DEBUG_LOG("Analyse %s", decl->name); + Decl *template_decl = sema_resolve_symbol(c, template_name, decl->define_decl.template_path, &ambiguous, &private_decl); + if (!template_decl) { - case DEFINE_IDENT_ALIAS: - decl_path = decl->define_decl.path; - name = TOKSTR(decl->define_decl.identifier); - break; - case DEFINE_TYPE_ALIAS: + if (private_decl && private_decl->decl_kind == DECL_TEMPLATE) { - TypeInfo *define_type = decl->define_decl.type_info; - mismatch_span = define_type->span; - decl_path = define_type->unresolved.path; - name = TOKSTR(define_type->unresolved.name_loc); - mismatch = define_type->kind != TYPE_INFO_IDENTIFIER; - break; + SEMA_TOKID_ERROR(template_token, "'%s' is a private template.", private_decl->name); + return poisoned_decl; } - default: - UNREACHABLE - } - if (mismatch) - { - sema_error_range(mismatch_span, "A variable, type or constant was expected here."); + if (ambiguous) + { + SEMA_TOKID_ERROR(template_token, "Is an ambiguous symbol, you need to add a path."); + return poisoned_decl; + } + SEMA_TOKID_ERROR(template_token, "Unknown template '%s', did you spell it right?", template_name); return poisoned_decl; } - if (!decl_path) + if (template_decl->decl_kind != DECL_TEMPLATE) { - sema_error_range(mismatch_span, "Parameterization requires the full path, please add it."); - return poisoned_decl; - } - Decl *import_found = NULL; - VECEACH(c->imports, i) - { - Decl *import = c->imports[i]; - if (decl_path->module == import->import.path->module) - { - import_found = import; - break; - } - } - if (!import_found) - { - sema_error_range(mismatch_span, "It was not possible to find a matching module, did you use the full path?"); + SEMA_TOKID_ERROR(template_token, "'%s' is not a template, did you spell it right?", template_name); return poisoned_decl; } - Module *module = import_found->module; - TypeInfo **params = decl->define_decl.params; - unsigned parameter_count = vec_size(module->parameters); + if (!sema_analyse_decl(template_decl->template_decl.parent_context, template_decl)) return poisoned_decl; + TypeInfo **params = decl->define_decl.template_params; + unsigned parameter_count = vec_size(template_decl->template_decl.params); assert(parameter_count > 0); if (parameter_count != vec_size(params)) { - sema_error_range((SourceSpan) { params[0]->span.loc, VECLAST(params)->span.end_loc }, "The generic module expected %d arguments, but you only supplied %d, did you make a mistake?", - parameter_count, vec_size(decl->define_decl.params)); + sema_error_range((SourceSpan) { params[0]->span.loc, VECLAST(params)->span.end_loc }, "The template expected %d arguments, but you only supplied %d, did you make a mistake?", + parameter_count, vec_size(decl->define_decl.template_params)); return poisoned_decl; } scratch_buffer_clear(); - scratch_buffer_append_len(module->name->module, module->name->len); - scratch_buffer_append_char('.'); - VECEACH(decl->define_decl.params, i) + scratch_buffer_append(template_decl->external_name); + VECEACH(decl->define_decl.template_params, i) { - TypeInfo *type_info = decl->define_decl.params[i]; + TypeInfo *type_info = decl->define_decl.template_params[i]; if (!sema_resolve_type_info(c, type_info)) return poisoned_decl; - if (i != 0) scratch_buffer_append_char('.'); + scratch_buffer_append_char('.'); const char *type_name = type_info->type->canonical->name; scratch_buffer_append(type_name); } - TokenType ident_type = TOKEN_IDENT; const char *path_string = scratch_buffer_interned(); Module *instantiated_module = global_context_find_module(path_string); if (!instantiated_module) { Path *path = CALLOCS(Path); path->module = path_string; - path->span = module->name->span; + path->span = decl->span; path->len = global_context.scratch_buffer_len; - instantiated_module = sema_instantiate_module(c, module, path, decl->define_decl.params); - sema_analyze_stage(instantiated_module, c->module->stage - 1); + instantiated_module = sema_instantiate_template(c, template_decl, path, decl->define_decl.template_params); + sema_analyze_stage(instantiated_module, c->module->stage); } + const char *name = TOKSTR(decl->define_decl.identifier); Decl *symbol = module_find_symbol(instantiated_module, name); if (!symbol) { - SEMA_ERROR(decl, "Identifier '%s' could not be found.", name); + SEMA_TOKID_ERROR(decl->define_decl.identifier, "Identifier '%s' could not be found.", name); return poisoned_decl; } - if (symbol->visibility <= VISIBLE_MODULE && !import_found->import.private) + if (symbol->visibility <= VISIBLE_MODULE) { SEMA_TOKID_ERROR(decl->name_token, "'%s' is not visible from this module.", symbol->name); return poisoned_decl; } + if (!sema_analyse_decl(template_decl->template_decl.parent_context, symbol)) return poisoned_decl; + context_register_external_symbol(c, symbol); return symbol; } -static void decl_define_type(Decl *decl, Type *actual_type) -{ - Type *type = type_new(TYPE_TYPEDEF, decl->name); - type->decl = decl; - type->canonical = actual_type->canonical; - decl->type = type; -} static inline bool sema_analyse_define(Context *c, Decl *decl) { Decl *symbol; - if (decl->define_decl.is_parameterized) - { - symbol = TRY_DECL_OR(sema_analyse_parameterized_define(c, decl), poisoned_decl); - } - else - { - switch (decl->define_decl.define_kind) - { - case DEFINE_FUNC: - { - Type *func_type = sema_analyse_function_signature(c, &decl->define_decl.function_signature, false); - if (!func_type) return false; - decl_define_type(decl, type_get_ptr(func_type)); - return true; - } - case DEFINE_TYPE_ALIAS: - if (!sema_resolve_type_info(c, decl->define_decl.type_info)) return false; - decl_define_type(decl, decl->define_decl.type_info->type); - return true; - case DEFINE_DISTINCT_TYPE: - { - if (!sema_resolve_type_info(c, decl->define_decl.type_info)) return false; - Type *type = type_new(TYPE_DISTINCT, decl->name); - type->decl = decl; - type->canonical = type; - decl->type = type; - return true; - } - case DEFINE_IDENT_ALIAS: - { - Decl *ambiguous_decl = NULL; - Decl *private_symbol = NULL; - symbol = sema_resolve_symbol(c, - TOKSTR(decl->define_decl.identifier), - decl->define_decl.path, - &ambiguous_decl, - &private_symbol); - if (!symbol) TODO; - break; - } - } - } + Type *type; switch (decl->define_decl.define_kind) { - case DEFINE_FUNC: - case DEFINE_DISTINCT_TYPE: - UNREACHABLE - case DEFINE_TYPE_ALIAS: - decl_define_type(decl, symbol->type); - break; - case DEFINE_IDENT_ALIAS: + case DEFINE_TYPE_TEMPLATE: + symbol = TRY_DECL_OR(sema_analyse_parameterized_define(c, decl), false); + type = type_new(TYPE_TYPEDEF, decl->name); + type->decl = decl; + type->canonical = symbol->type->canonical; + decl->type = type; + decl->decl_kind = DECL_TYPEDEF; + return true; + case DEFINE_IDENT_TEMPLATE: + symbol = TRY_DECL_OR(sema_analyse_parameterized_define(c, decl), false); decl->type = symbol->type; decl->define_decl.alias = symbol; - break; + return true; + case DEFINE_IDENT_ALIAS: + { + Decl *ambiguous_decl = NULL; + Decl *private_symbol = NULL; + symbol = sema_resolve_symbol(c, + TOKSTR(decl->define_decl.identifier), + decl->define_decl.path, + &ambiguous_decl, + &private_symbol); + if (!symbol) TODO; + decl->type = symbol->type; + decl->define_decl.alias = symbol; + return true; + } } - return true; + UNREACHABLE } @@ -1235,6 +1223,10 @@ bool sema_analyse_decl(Context *context, Decl *decl) { case DECL_INTERFACE: TODO + case DECL_TEMPLATE: + if (!sema_analyse_template(context, decl)) return decl_poison(decl); + decl_set_external_name(decl); + break; case DECL_STRUCT: case DECL_UNION: if (!sema_analyse_struct_union(context, decl)) return decl_poison(decl); @@ -1242,7 +1234,6 @@ bool sema_analyse_decl(Context *context, Decl *decl) break; case DECL_FUNC: if (!sema_analyse_func(context, decl)) return decl_poison(decl); - decl_set_external_name(decl); break; case DECL_MACRO: if (!sema_analyse_macro(context, decl)) return decl_poison(decl); diff --git a/src/compiler/sema_expr.c b/src/compiler/sema_expr.c index fd81cde15..ffbd6178a 100644 --- a/src/compiler/sema_expr.c +++ b/src/compiler/sema_expr.c @@ -166,6 +166,9 @@ static inline bool sema_cast_ident_rvalue(Context *context, Type *to, Expr *expr switch (decl->decl_kind) { + case DECL_TEMPLATE: + SEMA_ERROR(expr, "Templates cannot appear inside of expressions."); + return expr_poison(expr); case DECL_FUNC: SEMA_ERROR(expr, "Expected function followed by (...) or prefixed by &."); return expr_poison(expr); diff --git a/src/compiler/sema_name_resolution.c b/src/compiler/sema_name_resolution.c index 43eb5ca5f..0736b36eb 100644 --- a/src/compiler/sema_name_resolution.c +++ b/src/compiler/sema_name_resolution.c @@ -47,14 +47,12 @@ static Decl *sema_resolve_path_symbol(Context *context, const char *symbol, Path return module_find_symbol(context->module, symbol); } + Decl **imports = context_get_imports(context); + printf("Looking for path: %s\n", path->module); // 3. Loop over imports. - VECEACH(context->imports, i) + VECEACH(imports, i) { - Decl *import = context->imports[i]; - // 4. Don't look through parameterized modules. - if (import->module->parameters) continue; - - // TODO handle partial imports. + Decl *import = imports[i]; // 5. Can we match a subpath? if (path->len > import->import.path->len) continue; @@ -134,7 +132,7 @@ Decl *sema_resolve_symbol(Context *context, const char *symbol, Path *path, Decl if (context->current_scope) { - Decl **first = &global_context.locals[0]; + Decl **first = &context->locals[0]; if (context->macro_nesting) first = context->macro_locals_start; Decl **current = context->last_local - 1; while (current >= first) @@ -152,6 +150,12 @@ Decl *sema_resolve_symbol(Context *context, const char *symbol, Path *path, Decl // Search in the module. decl = module_find_symbol(context->module, symbol); + // Is this a template, in that case we also search the parent module. + if (!decl && context->module->template_parent_context) + { + decl = module_find_symbol(context->module->template_parent_context->module, symbol); + } + if (decl) { context_register_external_symbol(context, decl); @@ -159,9 +163,10 @@ Decl *sema_resolve_symbol(Context *context, const char *symbol, Path *path, Decl } // Search in imports - VECEACH(context->imports, i) + Decl **imports = context_get_imports(context); + VECEACH(imports, i) { - Decl *import = context->imports[i]; + Decl *import = imports[i]; if (!decl_ok(import)) continue; Decl *found = module_find_symbol(import->module, symbol); if (!found) continue; @@ -187,7 +192,7 @@ Decl *sema_resolve_symbol(Context *context, const char *symbol, Path *path, Decl static inline bool sema_append_local(Context *context, Decl *decl) { - if (context->last_local == &global_context.locals[MAX_LOCALS - 1]) + if (context->last_local == &context->locals[MAX_LOCALS - 1]) { SEMA_ERROR(decl, "Reached the maximum number of locals."); return false; diff --git a/src/compiler/sema_passes.c b/src/compiler/sema_passes.c index e9f0d9228..7900e05de 100644 --- a/src/compiler/sema_passes.c +++ b/src/compiler/sema_passes.c @@ -190,9 +190,9 @@ void sema_analysis_pass_decls(Module *module) VECEACH(module->contexts, index) { Context *context = module->contexts[index]; - context->current_scope = &global_context.scopes[0]; + context->current_scope = &context->scopes[0]; context->current_scope->scope_id = 0; - context->last_local = &global_context.locals[0]; + context->last_local = &context->locals[0]; VECEACH(context->enums, i) { sema_analyse_decl(context, context->enums[i]); @@ -201,6 +201,10 @@ void sema_analysis_pass_decls(Module *module) { sema_analyse_decl(context, context->types[i]); } + VECEACH(context->templates, i) + { + sema_analyse_decl(context, context->templates[i]); + } VECEACH(context->macros, i) { sema_analyse_decl(context, context->macros[i]); diff --git a/src/compiler/sema_stmts.c b/src/compiler/sema_stmts.c index 4e6c8b882..d57560205 100644 --- a/src/compiler/sema_stmts.c +++ b/src/compiler/sema_stmts.c @@ -8,7 +8,7 @@ void context_push_scope_with_flags(Context *context, ScopeFlags flags) { - if (context->current_scope == &global_context.scopes[MAX_SCOPE_DEPTH - 1]) + if (context->current_scope == &context->scopes[MAX_SCOPE_DEPTH - 1]) { FATAL_ERROR("Too deeply nested scopes."); } @@ -66,7 +66,7 @@ static inline void context_pop_defers_to(Context *context, DeferList *list) void context_pop_scope(Context *context) { - assert(context->current_scope != &global_context.scopes[0]); + assert(context->current_scope != &context->scopes[0]); context->last_local = context->current_scope->local_decl_start; assert(context_start_defer(context) == context->current_scope->defer_last); @@ -113,7 +113,7 @@ static void context_pop_defers_and_replace_ast(Context *context, Ast *ast) AstId context_start_defer(Context *context) { - if (context->current_scope == global_context.scopes) return 0; + if (context->current_scope == context->scopes) return 0; if (context->current_scope->in_defer != context->current_scope[-1].in_defer) return 0; return context->current_scope[-1].defer_last; } @@ -930,7 +930,7 @@ static DynamicScope *context_find_scope_by_id(Context *context, ScopeId scope_id while (1) { if (scope->scope_id == scope_id) return scope; - assert(scope != &global_context.scopes[0]); + assert(scope != &context->scopes[0]); scope--; } UNREACHABLE @@ -965,7 +965,7 @@ static inline Decl *sema_analyse_label(Context *context, Ast *stmt) static bool context_labels_exist_in_scope(Context *context) { - for (Decl **from = &global_context.locals[0]; from < context->last_local; from++) + for (Decl **from = &context->locals[0]; from < context->last_local; from++) { if ((*from)->decl_kind == DECL_LABEL) return true; } @@ -1916,7 +1916,7 @@ bool sema_analyse_function_body(Context *context, Decl *func) FunctionSignature *signature = &func->func.function_signature; context->active_function_for_analysis = func; context->rtype = signature->rtype->type; - context->current_scope = &global_context.scopes[0]; + context->current_scope = &context->scopes[0]; context->current_scope->scope_id = 0; context->failable_return = signature->failable; @@ -1927,7 +1927,7 @@ bool sema_analyse_function_body(Context *context, Decl *func) vec_resize(context->returns, 0); context->scope_id = 0; context->expected_block_type = NULL; - context->last_local = &global_context.locals[0]; + context->last_local = &context->locals[0]; context->in_volatile_section = 0; context->macro_counter = 0; context->macro_nesting = 0; @@ -1938,13 +1938,13 @@ bool sema_analyse_function_body(Context *context, Decl *func) func->func.annotations = CALLOCS(FuncAnnotations); context_push_scope(context); Decl **params = signature->params; - assert(context->current_scope == &global_context.scopes[1]); + assert(context->current_scope == &context->scopes[1]); VECEACH(params, i) { if (!sema_add_local(context, params[i])) return false; } if (!sema_analyse_compound_statement_no_scope(context, func->func.body)) return false; - assert(context->current_scope == &global_context.scopes[1]); + assert(context->current_scope == &context->scopes[1]); if (!context->current_scope->jump_end) { Type *canonical_rtype = signature->rtype->type->canonical; diff --git a/src/compiler/sema_types.c b/src/compiler/sema_types.c index eeeb85354..0dec66025 100644 --- a/src/compiler/sema_types.c +++ b/src/compiler/sema_types.c @@ -141,6 +141,7 @@ static bool sema_resolve_type_identifier(Context *context, TypeInfo *type_info) case DECL_MACRO: case DECL_GENERIC: case DECL_LABEL: + case DECL_TEMPLATE: SEMA_TOKID_ERROR(type_info->unresolved.name_loc, "This is not a type."); return type_info_poison(type_info); case DECL_CT_ELSE: diff --git a/src/compiler/tokens.c b/src/compiler/tokens.c index ca9d8b640..02e2b4b2d 100644 --- a/src/compiler/tokens.c +++ b/src/compiler/tokens.c @@ -242,6 +242,8 @@ const char *token_type_to_string(TokenType type) return "struct"; case TOKEN_SWITCH: return "switch"; + case TOKEN_TEMPLATE: + return "template"; case TOKEN_TRUE: return "true"; case TOKEN_TRY: diff --git a/src/compiler/types.c b/src/compiler/types.c index 0a39b6136..658ae4c87 100644 --- a/src/compiler/types.c +++ b/src/compiler/types.c @@ -1079,11 +1079,57 @@ static void type_append_name_to_scratch(Type *type) case TYPE_ENUM: case TYPE_STRUCT: case TYPE_UNION: + case TYPE_DISTINCT: scratch_buffer_append(type->decl->external_name); break; - default: + case TYPE_POINTER: + type_append_name_to_scratch(type->pointer); + scratch_buffer_append_char('*'); + break; + case TYPE_SUBARRAY: + type_append_name_to_scratch(type->pointer); + scratch_buffer_append("[]"); + case TYPE_VOID: + case TYPE_BOOL: + case TYPE_I8: + case TYPE_I16: + case TYPE_I32: + case TYPE_I64: + case TYPE_I128: + case TYPE_U8: + case TYPE_U16: + case TYPE_U32: + case TYPE_U64: + case TYPE_U128: + case TYPE_F16: + case TYPE_F32: + case TYPE_F64: + case TYPE_F128: + case TYPE_TYPEID: + case TYPE_ERR_UNION: + case TYPE_VIRTUAL_ANY: + case TYPE_COMPLEX: + case TYPE_VECTOR: scratch_buffer_append(type->name); break; + case TYPE_IXX: + case TYPE_FXX: + case TYPE_STRLIT: + case TYPE_INFERRED_ARRAY: + case TYPE_TYPEINFO: + case TYPE_MEMBER: + UNREACHABLE + break; + case TYPE_FUNC: + scratch_buffer_append(type->func.mangled_function_signature); + break; + case TYPE_ARRAY: + TODO + case TYPE_VARARRAY: + TODO + case TYPE_VIRTUAL: + scratch_buffer_append("virtual "); + scratch_buffer_append(type->decl->name); } } diff --git a/src/version.h b/src/version.h index 56adff314..8d2468530 100644 --- a/src/version.h +++ b/src/version.h @@ -1 +1 @@ -#define COMPILER_VERSION "A223" \ No newline at end of file +#define COMPILER_VERSION "A224" \ No newline at end of file diff --git a/test/test_suite/abi/literal_load.c3t b/test/test_suite/abi/literal_load.c3t index 20bbad40f..951fe4fc0 100644 --- a/test/test_suite/abi/literal_load.c3t +++ b/test/test_suite/abi/literal_load.c3t @@ -17,15 +17,15 @@ func Test creator() // #expect: literal_load.ll - %literal = alloca %literal_load.Test, align 4 - %literal1 = alloca %literal_load.Test, align 4 - %0 = bitcast %literal_load.Test* %literal to i8* + %literal = alloca %Test, align 4 + %literal1 = alloca %Test, align 4 + %0 = bitcast %Test* %literal to i8* call void @llvm.memset.p0i8.i64(i8* align 4 %0, i8 0, i64 4, i1 false) - %1 = bitcast %literal_load.Test* %literal to i32* + %1 = bitcast %Test* %literal to i32* %coerced = load i32, i32* %1, align 4 call void @blorg(i32 %coerced) - %2 = bitcast %literal_load.Test* %literal1 to i8* + %2 = bitcast %Test* %literal1 to i8* call void @llvm.memset.p0i8.i64(i8* align 4 %2, i8 0, i64 4, i1 false) - %3 = bitcast %literal_load.Test* %literal1 to i32* + %3 = bitcast %Test* %literal1 to i32* %coerced2 = load i32, i32* %3, align 4 ret i32 %coerced2 \ No newline at end of file diff --git a/test/test_suite/abi/union_x64.c3t b/test/test_suite/abi/union_x64.c3t index 4e0bc1ff5..e0620fd23 100644 --- a/test/test_suite/abi/union_x64.c3t +++ b/test/test_suite/abi/union_x64.c3t @@ -16,19 +16,19 @@ func void hello(Foo f) // #expect: unionx64.ll -%unionx64.Foo = type { i64, [8 x i8] } +%Foo = type { i64, [8 x i8] } declare void @hello2(i64, i64) #0 define void @unionx64.hello(i64 %0, i64 %1) - %f = alloca %unionx64.Foo, align 8 - %pair = bitcast %unionx64.Foo* %f to { i64, i64 }* + %f = alloca %Foo, align 8 + %pair = bitcast %Foo* %f to { i64, i64 }* %lo = getelementptr inbounds { i64, i64 }, { i64, i64 }* %pair, i32 0, i32 0 store i64 %0, i64* %lo, align 8 %hi = getelementptr inbounds { i64, i64 }, { i64, i64 }* %pair, i32 0, i32 1 store i64 %1, i64* %hi, align 8 - %casttemp = bitcast %unionx64.Foo* %f to { i64, i64 }* + %casttemp = bitcast %Foo* %f to { i64, i64 }* %lo1 = getelementptr inbounds { i64, i64 }, { i64, i64 }* %casttemp, i32 0, i32 0 %lo2 = load i64, i64* %lo1, align 8 %hi3 = getelementptr inbounds { i64, i64 }, { i64, i64 }* %casttemp, i32 0, i32 1 diff --git a/test/test_suite/arrays/array_struct.c3t b/test/test_suite/arrays/array_struct.c3t index 556e084a0..cf46f5a5b 100644 --- a/test/test_suite/arrays/array_struct.c3t +++ b/test/test_suite/arrays/array_struct.c3t @@ -10,4 +10,4 @@ Foo[10] array; // #expect: test.ll -@test.array = protected global [10 x %test.Foo] zeroinitializer, align 16 \ No newline at end of file +@test.array = protected global [10 x %Foo] zeroinitializer, align 16 \ No newline at end of file diff --git a/test/test_suite/arrays/complex_array_const.c3t b/test/test_suite/arrays/complex_array_const.c3t index 8a50ea175..717ecedfc 100644 --- a/test/test_suite/arrays/complex_array_const.c3t +++ b/test/test_suite/arrays/complex_array_const.c3t @@ -18,4 +18,4 @@ Connection[3] link @.str = private constant [6 x i8] c"link1\00", align 1 @.str.1 = private constant [6 x i8] c"link2\00", align 1 @.str.2 = private constant [6 x i8] c"link3\00", align 1 -@test.link = protected global [3 x %test.Connection] [%test.Connection { i64 1, i8* getelementptr inbounds ([6 x i8], [6 x i8]* @.str, i32 0, i32 0), i64 10 }, %test.Connection { i64 2, i8* getelementptr inbounds ([6 x i8], [6 x i8]* @.str.1, i32 0, i32 0), i64 20 }, %test.Connection { i64 3, i8* getelementptr inbounds ([6 x i8], [6 x i8]* @.str.2, i32 0, i32 0), i64 30 }], align 16 +@test.link = protected global [3 x %Connection] [%Connection { i64 1, i8* getelementptr inbounds ([6 x i8], [6 x i8]* @.str, i32 0, i32 0), i64 10 }, %Connection { i64 2, i8* getelementptr inbounds ([6 x i8], [6 x i8]* @.str.1, i32 0, i32 0), i64 20 }, %Connection { i64 3, i8* getelementptr inbounds ([6 x i8], [6 x i8]* @.str.2, i32 0, i32 0), i64 30 }], align 16 diff --git a/test/test_suite/distinct/distinct_invalid.c3 b/test/test_suite/distinct/distinct_invalid.c3 index 5cfa24c85..2d6ac44d0 100644 --- a/test/test_suite/distinct/distinct_invalid.c3 +++ b/test/test_suite/distinct/distinct_invalid.c3 @@ -3,8 +3,6 @@ error Error define Foo1 = distinct Error; // #error: You cannot create a distinct type from an error -define Foo2 = distinct error; // #error: You cannot create a distinct type from an error union - define Foo3 = distinct void; // #error: create a distinct type from 'void' define Foo4 = distinct typeid; // #error: create a distinct type from 'typeid' diff --git a/test/test_suite/expressions/pointer_access.c3t b/test/test_suite/expressions/pointer_access.c3t index 707c4ae63..d37d32c0a 100644 --- a/test/test_suite/expressions/pointer_access.c3t +++ b/test/test_suite/expressions/pointer_access.c3t @@ -37,62 +37,62 @@ func void testSimple() // TODO these may be wrong. // #expect: pointer_access.ll -%pointer_access.ExtraSimple = type { i32, i32, %pointer_access.c, %pointer_access.anon, %pointer_access.anon.0, i32 } -%pointer_access.c = type { double, double, double, double, double } -%pointer_access.anon = type { i32, i32 } -%pointer_access.anon.0 = type { double } +%ExtraSimple = type { i32, i32, %c, %anon, %anon.0, i32 } +%c = type { double, double, double, double, double } +%anon = type { i32, i32 } +%anon.0 = type { double } @ExtraSimple = linkonce_odr constant i8 1 entry: - %a = alloca %pointer_access.ExtraSimple, align 8 - %0 = getelementptr inbounds %pointer_access.ExtraSimple, %pointer_access.ExtraSimple* %a, i32 0, i32 0 + %a = alloca %ExtraSimple, align 8 + %0 = getelementptr inbounds %ExtraSimple, %ExtraSimple* %a, i32 0, i32 0 store i32 0, i32* %0, align 8 - %1 = getelementptr inbounds %pointer_access.ExtraSimple, %pointer_access.ExtraSimple* %a, i32 0, i32 1 + %1 = getelementptr inbounds %ExtraSimple, %ExtraSimple* %a, i32 0, i32 1 store i32 0, i32* %1, align 4 - %2 = getelementptr inbounds %pointer_access.ExtraSimple, %pointer_access.ExtraSimple* %a, i32 0, i32 2 - %3 = getelementptr inbounds %pointer_access.c, %pointer_access.c* %2, i32 0, i32 0 + %2 = getelementptr inbounds %ExtraSimple, %ExtraSimple* %a, i32 0, i32 2 + %3 = getelementptr inbounds %c, %c* %2, i32 0, i32 0 store double 0.000000e+00, double* %3, align 8 - %4 = getelementptr inbounds %pointer_access.c, %pointer_access.c* %2, i32 0, i32 1 + %4 = getelementptr inbounds %c, %c* %2, i32 0, i32 1 store double 0.000000e+00, double* %4, align 8 - %5 = getelementptr inbounds %pointer_access.c, %pointer_access.c* %2, i32 0, i32 2 + %5 = getelementptr inbounds %c, %c* %2, i32 0, i32 2 store double 0.000000e+00, double* %5, align 8 - %6 = getelementptr inbounds %pointer_access.c, %pointer_access.c* %2, i32 0, i32 3 + %6 = getelementptr inbounds %c, %c* %2, i32 0, i32 3 store double 0.000000e+00, double* %6, align 8 - %7 = getelementptr inbounds %pointer_access.c, %pointer_access.c* %2, i32 0, i32 4 + %7 = getelementptr inbounds %c, %c* %2, i32 0, i32 4 store double 3.300000e+00, double* %7, align 8 - %8 = getelementptr inbounds %pointer_access.ExtraSimple, %pointer_access.ExtraSimple* %a, i32 0, i32 3 - %9 = bitcast %pointer_access.anon* %8 to i8* + %8 = getelementptr inbounds %ExtraSimple, %ExtraSimple* %a, i32 0, i32 3 + %9 = bitcast %anon* %8 to i8* call void @llvm.memset.p0i8.i64(i8* align 8 %9, i8 0, i64 8, i1 false) - %10 = getelementptr inbounds %pointer_access.ExtraSimple, %pointer_access.ExtraSimple* %a, i32 0, i32 4 - %11 = bitcast %pointer_access.anon.0* %10 to i8* + %10 = getelementptr inbounds %ExtraSimple, %ExtraSimple* %a, i32 0, i32 4 + %11 = bitcast %anon.0* %10 to i8* call void @llvm.memset.p0i8.i64(i8* align 8 %11, i8 0, i64 8, i1 false) - %12 = getelementptr inbounds %pointer_access.ExtraSimple, %pointer_access.ExtraSimple* %a, i32 0, i32 5 + %12 = getelementptr inbounds %ExtraSimple, %ExtraSimple* %a, i32 0, i32 5 store i32 0, i32* %12, align 8 - %13 = getelementptr inbounds %pointer_access.ExtraSimple, %pointer_access.ExtraSimple* %a, i32 0, i32 2 - %14 = getelementptr inbounds %pointer_access.c, %pointer_access.c* %13, i32 0, i32 4 + %13 = getelementptr inbounds %ExtraSimple, %ExtraSimple* %a, i32 0, i32 2 + %14 = getelementptr inbounds %c, %c* %13, i32 0, i32 4 store double 3.400000e+00, double* %14, align 8 - %15 = getelementptr inbounds %pointer_access.ExtraSimple, %pointer_access.ExtraSimple* %a, i32 0, i32 0 + %15 = getelementptr inbounds %ExtraSimple, %ExtraSimple* %a, i32 0, i32 0 %16 = load i32, i32* %15, align 8 - %17 = getelementptr inbounds %pointer_access.ExtraSimple, %pointer_access.ExtraSimple* %a, i32 0, i32 2 - %18 = getelementptr inbounds %pointer_access.c, %pointer_access.c* %17, i32 0, i32 0 + %17 = getelementptr inbounds %ExtraSimple, %ExtraSimple* %a, i32 0, i32 2 + %18 = getelementptr inbounds %c, %c* %17, i32 0, i32 0 %19 = load double, double* %18, align 8 - %20 = getelementptr inbounds %pointer_access.ExtraSimple, %pointer_access.ExtraSimple* %a, i32 0, i32 2 - %21 = getelementptr inbounds %pointer_access.c, %pointer_access.c* %20, i32 0, i32 3 + %20 = getelementptr inbounds %ExtraSimple, %ExtraSimple* %a, i32 0, i32 2 + %21 = getelementptr inbounds %c, %c* %20, i32 0, i32 3 %22 = load double, double* %21, align 8 - %23 = getelementptr inbounds %pointer_access.ExtraSimple, %pointer_access.ExtraSimple* %a, i32 0, i32 2 - %24 = getelementptr inbounds %pointer_access.c, %pointer_access.c* %23, i32 0, i32 4 + %23 = getelementptr inbounds %ExtraSimple, %ExtraSimple* %a, i32 0, i32 2 + %24 = getelementptr inbounds %c, %c* %23, i32 0, i32 4 %25 = load double, double* %24, align 8 - %26 = getelementptr inbounds %pointer_access.ExtraSimple, %pointer_access.ExtraSimple* %a, i32 0, i32 5 + %26 = getelementptr inbounds %ExtraSimple, %ExtraSimple* %a, i32 0, i32 5 %27 = load i32, i32* %26, align 8 - %28 = getelementptr inbounds %pointer_access.ExtraSimple, %pointer_access.ExtraSimple* %a, i32 0, i32 4 - %29 = bitcast %pointer_access.anon.0* %28 to double* + %28 = getelementptr inbounds %ExtraSimple, %ExtraSimple* %a, i32 0, i32 4 + %29 = bitcast %anon.0* %28 to double* %30 = load double, double* %29, align 8 - %31 = getelementptr inbounds %pointer_access.ExtraSimple, %pointer_access.ExtraSimple* %a, i32 0, i32 3 - %32 = getelementptr inbounds %pointer_access.anon, %pointer_access.anon* %31, i32 0, i32 0 + %31 = getelementptr inbounds %ExtraSimple, %ExtraSimple* %a, i32 0, i32 3 + %32 = getelementptr inbounds %anon, %anon* %31, i32 0, i32 0 %33 = load i32, i32* %32, align 8 - %34 = getelementptr inbounds %pointer_access.ExtraSimple, %pointer_access.ExtraSimple* %a, i32 0, i32 3 - %35 = getelementptr inbounds %pointer_access.anon, %pointer_access.anon* %34, i32 0, i32 1 + %34 = getelementptr inbounds %ExtraSimple, %ExtraSimple* %a, i32 0, i32 3 + %35 = getelementptr inbounds %anon, %anon* %34, i32 0, i32 1 %36 = load i32, i32* %35, align 4 call void (i8*, ...) @printf(i8* getelementptr inbounds ([71 x i8], [71 x i8]* @.str, i32 0, i32 0), i32 %16, double %19, double %22, double %25, i32 %27, double %30, i32 %33, i32 %36) ret void diff --git a/test/test_suite/functions/assorted_tests.c3t b/test/test_suite/functions/assorted_tests.c3t index b78c619f3..2d97dd283 100644 --- a/test/test_suite/functions/assorted_tests.c3t +++ b/test/test_suite/functions/assorted_tests.c3t @@ -101,18 +101,18 @@ if.exit: ret i32 %add1 -void @test.setInternalFPFZero(%test.InternalFPF* %0) - %dest = alloca %test.InternalFPF*, align 8 - store %test.InternalFPF* %0, %test.InternalFPF** %dest, align 8 - %1 = load %test.InternalFPF*, %test.InternalFPF** %dest, align 8 - %2 = getelementptr inbounds %test.InternalFPF, %test.InternalFPF* %1, i32 0, i32 0 +void @test.setInternalFPFZero(%InternalFPF* %0) + %dest = alloca %InternalFPF*, align 8 + store %InternalFPF* %0, %InternalFPF** %dest, align 8 + %1 = load %InternalFPF*, %InternalFPF** %dest, align 8 + %2 = getelementptr inbounds %InternalFPF, %InternalFPF* %1, i32 0, i32 0 store i8 0, i8* %2, align 8 ret void -void @test.denormalize(%test.InternalFPF* %0) +void @test.denormalize(%InternalFPF* %0) entry: - %ptr = alloca %test.InternalFPF*, align 8 - store %test.InternalFPF* %0, %test.InternalFPF** %ptr, align 8 - %1 = load %test.InternalFPF*, %test.InternalFPF** %ptr, align 8 - call void @test.setInternalFPFZero(%test.InternalFPF* %1) + %ptr = alloca %InternalFPF*, align 8 + store %InternalFPF* %0, %InternalFPF** %ptr, align 8 + %1 = load %InternalFPF*, %InternalFPF** %ptr, align 8 + call void @test.setInternalFPFZero(%InternalFPF* %1) ret void diff --git a/test/test_suite/globals/external_global.c3t b/test/test_suite/globals/external_global.c3t index 5f24ea566..5f6ccbb4f 100644 --- a/test/test_suite/globals/external_global.c3t +++ b/test/test_suite/globals/external_global.c3t @@ -23,12 +23,12 @@ func int extract_or_test_files() // #expect: test.ll -%test.UzGlobs = type { i8, [1 x %test.MinInfo], %test.MinInfo* } -%test.MinInfo = type { i64, i32 } +%UzGlobs = type { i8, [1 x %MinInfo], %MinInfo* } +%MinInfo = type { i64, i32 } -@g = external global %test.UzGlobs, align 8 +@g = external global %UzGlobs, align 8 entry: - store %test.MinInfo* getelementptr inbounds (%test.UzGlobs, %test.UzGlobs* @g, i32 0, i32 1, i32 0), %test.MinInfo** getelementptr inbounds (%test.UzGlobs, %test.UzGlobs* @g, i32 0, i32 2), align 8 + store %MinInfo* getelementptr inbounds (%UzGlobs, %UzGlobs* @g, i32 0, i32 1, i32 0), %MinInfo** getelementptr inbounds (%UzGlobs, %UzGlobs* @g, i32 0, i32 2), align 8 ret i32 0 } \ No newline at end of file diff --git a/test/test_suite/struct/simple_struct.c3t b/test/test_suite/struct/simple_struct.c3t index 5eb49eb47..7a85d15d8 100644 --- a/test/test_suite/struct/simple_struct.c3t +++ b/test/test_suite/struct/simple_struct.c3t @@ -10,5 +10,5 @@ struct Foo // #expect: test.ll -%test.Foo = type { i32, double } -@test.a = protected global %test.Foo zeroinitializer, align 8 \ No newline at end of file +%Foo = type { i32, double } +@test.a = protected global %Foo zeroinitializer, align 8 \ No newline at end of file diff --git a/test/test_suite/struct/struct_codegen.c3t b/test/test_suite/struct/struct_codegen.c3t index b1edcdabc..33c39ac39 100644 --- a/test/test_suite/struct/struct_codegen.c3t +++ b/test/test_suite/struct/struct_codegen.c3t @@ -14,11 +14,11 @@ func void test1() // #expect: test.ll -%test.Point = type { i32, i32 } +%Point = type { i32, i32 } @Point = linkonce_odr constant i8 1 entry: - %p = alloca %test.Point, align 4 - %0 = bitcast %test.Point* %p to i8* - call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 4 %0, i8* align 4 bitcast (%test.Point* @.__const to i8*), i32 8, i1 false) + %p = alloca %Point, align 4 + %0 = bitcast %Point* %p to i8* + call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 4 %0, i8* align 4 bitcast (%Point* @.__const to i8*), i32 8, i1 false) diff --git a/test/test_suite/struct/struct_codegen_empty.c3t b/test/test_suite/struct/struct_codegen_empty.c3t index d881f322d..bf1318cc3 100644 --- a/test/test_suite/struct/struct_codegen_empty.c3t +++ b/test/test_suite/struct/struct_codegen_empty.c3t @@ -22,18 +22,18 @@ func void test() // #expect: struct_codegen_empty.ll - %a = alloca %struct_codegen_empty.StructA, align 4 - %a2 = alloca %struct_codegen_empty.StructA, align 4 - %b = alloca %struct_codegen_empty.StructB, align 4 - %b2 = alloca %struct_codegen_empty.StructB, align 4 - %b3 = alloca %struct_codegen_empty.StructB, align 4 - %0 = bitcast %struct_codegen_empty.StructA* %a to i8* + %a = alloca %StructA, align 4 + %a2 = alloca %StructA, align 4 + %b = alloca %StructB, align 4 + %b2 = alloca %StructB, align 4 + %b3 = alloca %StructB, align 4 + %0 = bitcast %StructA* %a to i8* call void @llvm.memset.p0i8.i64(i8* align 4 %0, i8 0, i64 4, i1 false) - %1 = bitcast %struct_codegen_empty.StructA* %a2 to i8* + %1 = bitcast %StructA* %a2 to i8* call void @llvm.memset.p0i8.i64(i8* align 4 %1, i8 0, i64 4, i1 false) - %2 = bitcast %struct_codegen_empty.StructB* %b to i8* + %2 = bitcast %StructB* %b to i8* call void @llvm.memset.p0i8.i64(i8* align 4 %2, i8 0, i64 4, i1 false) - %3 = bitcast %struct_codegen_empty.StructB* %b2 to i8* + %3 = bitcast %StructB* %b2 to i8* call void @llvm.memset.p0i8.i64(i8* align 4 %3, i8 0, i64 4, i1 false) - %4 = bitcast %struct_codegen_empty.StructB* %b3 to i8* + %4 = bitcast %StructB* %b3 to i8* call void @llvm.memset.p0i8.i64(i8* align 4 %4, i8 0, i64 4, i1 false) \ No newline at end of file diff --git a/test/test_suite/struct/struct_const_construct_simple.c3t b/test/test_suite/struct/struct_const_construct_simple.c3t index acd19eff2..db80a9b7d 100644 --- a/test/test_suite/struct/struct_const_construct_simple.c3t +++ b/test/test_suite/struct/struct_const_construct_simple.c3t @@ -19,15 +19,15 @@ Foo foo8 = FOO7; // #expect: structo.ll -%structo.Foo = type { i32, i64 } +%Foo = type { i32, i64 } @Foo = linkonce_odr constant i8 1 @structo.x = protected global i64 16, align 8 -@structo.foo1 = protected global %structo.Foo { i32 1, i64 2 }, align 8 -@structo.foo2 = protected global %structo.Foo { i32 2, i64 0 }, align 8 -@structo.foo3 = protected global %structo.Foo { i32 0, i64 3 }, align 8 -@structo.foo4 = protected global %structo.Foo { i32 4, i64 1 }, align 8 -@structo.foo5 = protected global %structo.Foo zeroinitializer, align 8 -@structo.foo6 = protected global %structo.Foo zeroinitializer, align 8 -@structo.FOO7 = protected constant %structo.Foo { i32 1, i64 2 }, align 8 -@structo.foo8 = protected global %structo.Foo { i32 1, i64 2 }, align 8 +@structo.foo1 = protected global %Foo { i32 1, i64 2 }, align 8 +@structo.foo2 = protected global %Foo { i32 2, i64 0 }, align 8 +@structo.foo3 = protected global %Foo { i32 0, i64 3 }, align 8 +@structo.foo4 = protected global %Foo { i32 4, i64 1 }, align 8 +@structo.foo5 = protected global %Foo zeroinitializer, align 8 +@structo.foo6 = protected global %Foo zeroinitializer, align 8 +@structo.FOO7 = protected constant %Foo { i32 1, i64 2 }, align 8 +@structo.foo8 = protected global %Foo { i32 1, i64 2 }, align 8 diff --git a/test/test_suite/struct/struct_pack_and_align.c3t b/test/test_suite/struct/struct_pack_and_align.c3t index b52be0c01..d16a11338 100644 --- a/test/test_suite/struct/struct_pack_and_align.c3t +++ b/test/test_suite/struct/struct_pack_and_align.c3t @@ -69,34 +69,34 @@ public Foo6 foo6 = { 1, 2, 3 }; // #expect: struct2.ll -%struct2.Foo1 = type <{ i64, i8, [3 x i8] }> -%struct2.Foo2 = type <{ i8, i64, [3 x i8] }> -%struct2.Foo3 = type <{ i8, i64, [7 x i8] }> -%struct2.Foo4 = type <{ i8, i64 }> -%struct2.Foo5 = type { i32, [12 x i8], i8, [15 x i8] } -%struct2.Foo6 = type { i32, i16, i16 } +%Foo1 = type <{ i64, i8, [3 x i8] }> +%Foo2 = type <{ i8, i64, [3 x i8] }> +%Foo3 = type <{ i8, i64, [7 x i8] }> +%Foo4 = type <{ i8, i64 }> +%Foo5 = type { i32, [12 x i8], i8, [15 x i8] } +%Foo6 = type { i32, i16, i16 } -@struct2.foo1 = global %struct2.Foo1 <{ i64 1, i8 2, [3 x i8] undef }>, align 4 -@struct2.foo2 = global %struct2.Foo2 <{ i8 1, i64 2, [3 x i8] undef }>, align 4 -@struct2.foo3 = global %struct2.Foo3 <{ i8 1, i64 2, [7 x i8] undef }>, align 8 -@struct2.foo4 = global %struct2.Foo4 <{ i8 1, i64 2 }>, align 1 -@struct2.foo5 = global %struct2.Foo5 { i32 1, [12 x i8] undef, i8 2, [15 x i8] undef }, align 16 -@struct2.foo6 = global %struct2.Foo6 { i32 1, i16 2, i16 3 }, align 1 +@struct2.foo1 = global %Foo1 <{ i64 1, i8 2, [3 x i8] undef }>, align 4 +@struct2.foo2 = global %Foo2 <{ i8 1, i64 2, [3 x i8] undef }>, align 4 +@struct2.foo3 = global %Foo3 <{ i8 1, i64 2, [7 x i8] undef }>, align 8 +@struct2.foo4 = global %Foo4 <{ i8 1, i64 2 }>, align 1 +@struct2.foo5 = global %Foo5 { i32 1, [12 x i8] undef, i8 2, [15 x i8] undef }, align 16 +@struct2.foo6 = global %Foo6 { i32 1, i16 2, i16 3 }, align 1 @struct2.test5 entry: %x = alloca i8, align 1 - %y = alloca %struct2.Foo5, align 16 + %y = alloca %Foo5, align 16 store i8 %0, i8* %x, align 1 - %1 = bitcast %struct2.Foo5* %y to i8* + %1 = bitcast %Foo5* %y to i8* call void @llvm.memset.p0i8.i64(i8* align 16 %1, i8 0, i64 32, i1 false) - %2 = getelementptr inbounds %struct2.Foo5, %struct2.Foo5* %y, i32 0, i32 2 + %2 = getelementptr inbounds %Foo5, %Foo5* %y, i32 0, i32 2 %3 = load i8, i8* %x, align 1 store i8 %3, i8* %2, align 16 - %4 = getelementptr inbounds %struct2.Foo5, %struct2.Foo5* %y, i32 0, i32 2 + %4 = getelementptr inbounds %Foo5, %Foo5* %y, i32 0, i32 2 %5 = load i8, i8* %4, align 16 %sisiext = sext i8 %5 to i32 - %6 = getelementptr inbounds %struct2.Foo5, %struct2.Foo5* %y, i32 0, i32 0 + %6 = getelementptr inbounds %Foo5, %Foo5* %y, i32 0, i32 0 %7 = load i32, i32* %6, align 16 %add = add i32 %sisiext, %7 ret i32 %add diff --git a/test/test_suite/union/union_codegen_const.c3t b/test/test_suite/union/union_codegen_const.c3t index 574664bc1..618dd557c 100644 --- a/test/test_suite/union/union_codegen_const.c3t +++ b/test/test_suite/union/union_codegen_const.c3t @@ -14,7 +14,7 @@ Foo i = { .b = 2.3, .a = 23 }; // #expect: test.ll @test.f = protected global { i32, [4 x i8] } { i32 23, [4 x i8] undef }, align 8 -@test.g = protected global %test.Foo { double 2.300000e+00 }, align 8 -@test.h = protected global %test.Foo { double 2.300000e+00 }, align 8 +@test.g = protected global %Foo { double 2.300000e+00 }, align 8 +@test.h = protected global %Foo { double 2.300000e+00 }, align 8 @test.i = protected global { i32, [4 x i8] } { i32 23, [4 x i8] undef }, align 8 diff --git a/test/test_suite/union/union_codegen_empty.c3t b/test/test_suite/union/union_codegen_empty.c3t index 6939d14dc..53384beab 100644 --- a/test/test_suite/union/union_codegen_empty.c3t +++ b/test/test_suite/union/union_codegen_empty.c3t @@ -25,21 +25,21 @@ func void test() // #expect: union_codegen_empty.ll -%a = alloca %union_codegen_empty.UnionA, align 4 -%a2 = alloca %union_codegen_empty.UnionA, align 4 -%b = alloca %union_codegen_empty.UnionB, align 8 -%b2 = alloca %union_codegen_empty.UnionB, align 8 -%b3 = alloca %union_codegen_empty.UnionB, align 8 -%b4 = alloca %union_codegen_empty.UnionB, align 8 -%0 = bitcast %union_codegen_empty.UnionA* %a to i8* +%a = alloca %UnionA, align 4 +%a2 = alloca %UnionA, align 4 +%b = alloca %UnionB, align 8 +%b2 = alloca %UnionB, align 8 +%b3 = alloca %UnionB, align 8 +%b4 = alloca %UnionB, align 8 +%0 = bitcast %UnionA* %a to i8* call void @llvm.memset.p0i8.i64(i8* align 4 %0, i8 0, i64 4, i1 false) -%1 = bitcast %union_codegen_empty.UnionA* %a2 to i8* +%1 = bitcast %UnionA* %a2 to i8* call void @llvm.memset.p0i8.i64(i8* align 4 %1, i8 0, i64 4, i1 false) -%2 = bitcast %union_codegen_empty.UnionB* %b to i8* +%2 = bitcast %UnionB* %b to i8* call void @llvm.memset.p0i8.i64(i8* align 8 %2, i8 0, i64 8, i1 false) - %3 = bitcast %union_codegen_empty.UnionB* %b2 to i8* + %3 = bitcast %UnionB* %b2 to i8* call void @llvm.memset.p0i8.i64(i8* align 8 %3, i8 0, i64 8, i1 false) -%4 = bitcast %union_codegen_empty.UnionB* %b3 to i8* +%4 = bitcast %UnionB* %b3 to i8* call void @llvm.memset.p0i8.i64(i8* align 8 %4, i8 0, i64 8, i1 false) -%5 = bitcast %union_codegen_empty.UnionB* %b4 to i8* +%5 = bitcast %UnionB* %b4 to i8* call void @llvm.memset.p0i8.i64(i8* align 8 %5, i8 0, i64 8, i1 false) diff --git a/test/test_suite/union/union_codegen_overwrite_call.c3t b/test/test_suite/union/union_codegen_overwrite_call.c3t index d99b80d02..1771d3f2c 100644 --- a/test/test_suite/union/union_codegen_overwrite_call.c3t +++ b/test/test_suite/union/union_codegen_overwrite_call.c3t @@ -20,12 +20,12 @@ func void test() // #expect: test.ll entry: -%b = alloca %test.UnionB, align 8 -%0 = bitcast %test.UnionB* %b to i32* +%b = alloca %UnionB, align 8 +%0 = bitcast %UnionB* %b to i32* %1 = call i32 @bar() store i32 %1, i32* %0, align 4 -%2 = bitcast %test.UnionB* %b to %test.b* -%3 = bitcast %test.b* %2 to i8* +%2 = bitcast %UnionB* %b to %b* +%3 = bitcast %b* %2 to i8* call void @llvm.memset.p0i8.i64(i8* align 4 %3, i8 0, i64 4, i1 false) ret void diff --git a/test/test_suite/union/union_in_struct.c3t b/test/test_suite/union/union_in_struct.c3t index 3da70fa11..8e71a4006 100644 --- a/test/test_suite/union/union_in_struct.c3t +++ b/test/test_suite/union/union_in_struct.c3t @@ -20,10 +20,10 @@ func void test(Blend_Map_Entry* foo) // #expect: test.ll -%test.Blend_Map_Entry = type { %test.vals } -%test.vals = type { [2 x double], [8 x i8] } +%Blend_Map_Entry = type { %vals } +%vals = type { [2 x double], [8 x i8] } @test.a = protected global { { [5 x float], [4 x i8] } } { { [5 x float], [4 x i8] } { [5 x float] [float 1.000000e+00, float 2.000000e+00, float 3.000000e+00, float 4.000000e+00, float 5.000000e+00], [4 x i8] undef } }, align 8 -@test.b = protected global %test.Blend_Map_Entry { %test.vals { [2 x double] [double 6.000000e+00, double 7.000000e+00], [8 x i8] undef } }, align 8 +@test.b = protected global %Blend_Map_Entry { %vals { [2 x double] [double 6.000000e+00, double 7.000000e+00], [8 x i8] undef } }, align 8 @test.c = protected global { { { [2 x float], float, [2 x float] }, [4 x i8] } } { { { [2 x float], float, [2 x float] }, [4 x i8] } { { [2 x float], float, [2 x float] } { [2 x float] zeroinitializer, float 1.000000e+00, [2 x float] zeroinitializer }, [4 x i8] undef } }, align 8 @test.d = protected global { { [5 x float], [4 x i8] } } { { [5 x float], [4 x i8] } { [5 x float] [float 1.000000e+00, float 2.000000e+00, float 3.000000e+00, float 4.000000e+00, float 5.000000e+00], [4 x i8] undef } }, align 8