From d9566ef894c68bd42e05b45f1517da5d74a79697 Mon Sep 17 00:00:00 2001 From: Christoffer Lerno Date: Sat, 29 May 2021 20:02:38 +0200 Subject: [PATCH] Generic modules are back, slightly different. --- resources/lib/std/array.c3 | 283 -------------- resources/lib/std/linkedlist.c3 | 167 ++++++++ resources/lib/std/list.c3 | 114 ++++++ src/compiler/ast.c | 95 ++++- src/compiler/compiler.c | 87 ++++- src/compiler/compiler_internal.h | 42 +- src/compiler/context.c | 22 +- src/compiler/copying.c | 9 +- src/compiler/enums.h | 4 +- src/compiler/headers.c | 3 - src/compiler/parse_expr.c | 10 +- src/compiler/parse_global.c | 202 +++++----- src/compiler/parse_stmt.c | 1 - src/compiler/sema_decls.c | 206 +++++----- src/compiler/sema_expr.c | 130 ++----- src/compiler/sema_name_resolution.c | 364 +++++++++++++----- src/compiler/sema_passes.c | 7 +- src/compiler/sema_stmts.c | 13 +- src/compiler/sema_types.c | 40 +- src/compiler/tokens.c | 2 - src/version.h | 2 +- .../expressions/casts/cast_unknown.c3 | 8 +- .../expressions/ternary_no_ident.c3 | 6 +- test/test_suite/macros/hash_ident.c3 | 2 +- test/test_suite/statements/switch_errors.c3 | 2 +- test/test_suite/types/enum_errors.c3 | 2 +- test/test_suite/visibility/ambiguous_var.c3t | 2 +- 27 files changed, 980 insertions(+), 845 deletions(-) create mode 100644 resources/lib/std/linkedlist.c3 create mode 100644 resources/lib/std/list.c3 diff --git a/resources/lib/std/array.c3 b/resources/lib/std/array.c3 index 9d750b34d..f588ee0d4 100644 --- a/resources/lib/std/array.c3 +++ b/resources/lib/std/array.c3 @@ -14,286 +14,3 @@ macro make_zero($Type, usize elements) $Type* ptr = mem::calloc($Type.sizeof, elements); return ptr[0..(elements - 1)]; } - -template vararray -{ - struct List - { - usize size; - usize capacity; - Type *entries; - } - - static func void List.ensureCapacity(List *list) @inline - { - if (list.capacity == list.size) - { - list.capacity = list.capacity ? 2 * list.capacity : 16; - list.entries = mem::realloc(list.entries, Type.sizeof * list.capacity); - } - } - - func void List.push(List *list, Type element) @inline - { - list.append(element); - } - - func void List.append(List *list, Type element) - { - list.ensureCapacity(); - list.entries[list.size++] = element; - } - - /** - * @require list.size > 0 - */ - func Type List.pop(List *list) - { - return list.entries[--list.size]; - } - - /** - * @require list.size > 0 - */ - func Type List.popFirst(List *list) - { - Type value = list.entries[0]; - list.removeAt(0); - return value; - } - - func void List.removeAt(List *list, usize index) - { - for (usize i = index + 1; i < list.size; i++) - { - list.entries[i - 1] = list.entries[i]; - } - list.size--; - } - - func void List.pushFront(List *list, Type type) @inline - { - list.insertAt(0, type); - } - - func void List.insertAt(List *list, usize index, Type type) - { - list.ensureCapacity(); - for (usize i = list.size; i > index; i--) - { - list.entries[i] = list.entries[i - 1]; - } - list.size++; - list.entries[index] = type; - } - - func void List.removeLast(List *list) - { - list.size--; - } - - func void List.removeFirst(List *list) - { - list.removeAt(0); - } - - func Type* List.first(List *list) - { - return list.size ? &list.entries[0] : null; - } - - func Type* List.last(List *list) - { - return list.size ? &list.entries[list.size - 1] : null; - } - - func bool List.isEmpty(List *list) - { - return list.size; - } - - func usize List.len(List *list) - { - return list.size; - } - - func Type List.get(List *list, usize index) - { - return list.entries[index]; - } - - func void List.free(List *list) - { - mem::free(list.entries); - list.capacity = 0; - list.size = 0; - } -} - -template linklist -{ - static struct Node - { - Node *next; - Node *prev; - Type value; - } - - struct LinkedList - { - usize size; - Node *first; - Node *last; - } - - func void LinkedList.push(LinkedList *list, Type value) - { - list.linkLast(value); - } - - static func void LinkedList.linkFirst(LinkedList *list, Type value) - { - Node *first = list.first; - Node *new_node = @mem::malloc(Node); - *new_node = { .next = first, .value = value }; - list.first = new_node; - if (!first) - { - list.last = new_node; - } - else - { - first.prev = new_node; - } - list.size++; - } - - static func void LinkedList.linkLast(LinkedList *list, Type value) - { - Node *last = list.last; - Node *new_node = mem::alloc(Node.sizeof); - *new_node = { .prev = last, .value = value }; - list.last = new_node; - if (!last) - { - list.first = new_node; - } - else - { - last.next = new_node; - } - list.size++; - } - - func void LinkedList.free(LinkedList *list) - { - for (Node* node = list.first; node != null;) - { - Node* next = node.next; - mem::free(node); - node = next; - } - list.first = null; - list.last = null; - list.size = 0; - } - - func usize LinkedList.len(LinkedList* list) @inline - { - return list.size; - } - - func Type LinkedList.get(LinkedList* list, usize index) - { - Node* node = list.first; - while (index--) - { - node = node.next; - } - return node.value; - } - /** - * @require succ != null - **/ - static func void LinkedList.linkBefore(LinkedList *list, Node *succ, Type value) - { - Node* pred = succ.prev; - Node* new_node = @mem::malloc(Node); - *new_node = { .prev = pred, .next = succ, .value = value }; - succ.prev = new_node; - if (!pred) - { - list.first = new_node; - } - else - { - pred.next = new_node; - } - list.size++; - } - - /** - * @require f == list.first && f != null - **/ - static func void unlinkFirst(LinkedList* list, Node* f) - { - Node* next = f.next; - mem::free(f); - list.first = next; - if (!next) - { - list.last = null; - } - else - { - next.prev = null; - } - list.size--; - } - - /** - * @require l == list.last && l != null - **/ - static func void LinkedList.unlinkLast(LinkedList *list, Node* l) - { - Node* prev = l.prev; - list.last = prev; - mem::free(l); - if (!prev) - { - list.first = null; - } - else - { - prev.next = null; - } - list.size--; - } - - /** - * @require x != null - **/ - static func void LinkedList.unlink(LinkedList* list, Node* x) - { - Node* next = x.next; - Node* prev = x.prev; - if (!prev) - { - list.first = next; - } - else - { - prev.next = next; - } - if (!next) - { - list.last = prev; - } - else - { - next.prev = prev; - } - mem::free(x); - list.size--; - } -} diff --git a/resources/lib/std/linkedlist.c3 b/resources/lib/std/linkedlist.c3 new file mode 100644 index 000000000..93f90058f --- /dev/null +++ b/resources/lib/std/linkedlist.c3 @@ -0,0 +1,167 @@ +module std::array::linkedlist; +import std::mem; + +static struct Node +{ + Node *next; + Node *prev; + Type value; +} + +struct LinkedList +{ + usize size; + Node *first; + Node *last; +} + +func void LinkedList.push(LinkedList *list, Type value) +{ + list.linkLast(value); +} + +static func void LinkedList.linkFirst(LinkedList *list, Type value) +{ + Node *first = list.first; + Node *new_node = @mem::malloc(Node); + *new_node = { .next = first, .value = value }; + list.first = new_node; + if (!first) + { + list.last = new_node; + } + else + { + first.prev = new_node; + } + list.size++; +} + +static func void LinkedList.linkLast(LinkedList *list, Type value) +{ + Node *last = list.last; + Node *new_node = mem::alloc(Node.sizeof); + *new_node = { .prev = last, .value = value }; + list.last = new_node; + if (!last) + { + list.first = new_node; + } + else + { + last.next = new_node; + } + list.size++; +} + +func void LinkedList.free(LinkedList *list) +{ + for (Node* node = list.first; node != null;) + { + Node* next = node.next; + mem::free(node); + node = next; + } + list.first = null; + list.last = null; + list.size = 0; +} + +func usize LinkedList.len(LinkedList* list) @inline +{ + return list.size; +} + +func Type LinkedList.get(LinkedList* list, usize index) +{ + Node* node = list.first; + while (index--) + { + node = node.next; + } + return node.value; +} +/** + * @require succ != null + **/ +static func void LinkedList.linkBefore(LinkedList *list, Node *succ, Type value) +{ + Node* pred = succ.prev; + Node* new_node = @mem::malloc(Node); + *new_node = { .prev = pred, .next = succ, .value = value }; + succ.prev = new_node; + if (!pred) + { + list.first = new_node; + } + else + { + pred.next = new_node; + } + list.size++; +} + +/** + * @require f == list.first && f != null + **/ +static func void unlinkFirst(LinkedList* list, Node* f) +{ + Node* next = f.next; + mem::free(f); + list.first = next; + if (!next) + { + list.last = null; + } + else + { + next.prev = null; + } + list.size--; +} + +/** + * @require l == list.last && l != null + **/ +static func void LinkedList.unlinkLast(LinkedList *list, Node* l) +{ + Node* prev = l.prev; + list.last = prev; + mem::free(l); + if (!prev) + { + list.first = null; + } + else + { + prev.next = null; + } + list.size--; +} + +/** + * @require x != null + **/ +static func void LinkedList.unlink(LinkedList* list, Node* x) +{ + Node* next = x.next; + Node* prev = x.prev; + if (!prev) + { + list.first = next; + } + else + { + prev.next = next; + } + if (!next) + { + list.last = prev; + } + else + { + next.prev = prev; + } + mem::free(x); + list.size--; +} diff --git a/resources/lib/std/list.c3 b/resources/lib/std/list.c3 new file mode 100644 index 000000000..f20972369 --- /dev/null +++ b/resources/lib/std/list.c3 @@ -0,0 +1,114 @@ +module std::array::list; +import std::mem; + +struct List +{ + usize size; + usize capacity; + Type *entries; +} + +static func void List.ensureCapacity(List *list) @inline +{ + if (list.capacity == list.size) + { + list.capacity = list.capacity ? 2 * list.capacity : 16; + list.entries = mem::realloc(list.entries, Type.sizeof * list.capacity); + } +} + +func void List.push(List *list, Type element) @inline +{ + list.append(element); +} + +func void List.append(List *list, Type element) +{ + list.ensureCapacity(); + list.entries[list.size++] = element; +} + +/** + * @require list.size > 0 + */ +func Type List.pop(List *list) +{ + return list.entries[--list.size]; +} + +/** + * @require list.size > 0 + */ +func Type List.popFirst(List *list) +{ + Type value = list.entries[0]; + list.removeAt(0); + return value; +} + +func void List.removeAt(List *list, usize index) +{ + for (usize i = index + 1; i < list.size; i++) + { + list.entries[i - 1] = list.entries[i]; + } + list.size--; +} + +func void List.pushFront(List *list, Type type) @inline +{ + list.insertAt(0, type); +} + +func void List.insertAt(List *list, usize index, Type type) +{ + list.ensureCapacity(); + for (usize i = list.size; i > index; i--) + { + list.entries[i] = list.entries[i - 1]; + } + list.size++; + list.entries[index] = type; +} + +func void List.removeLast(List *list) +{ + list.size--; +} + +func void List.removeFirst(List *list) +{ + list.removeAt(0); +} + +func Type* List.first(List *list) +{ + return list.size ? &list.entries[0] : null; +} + +func Type* List.last(List *list) +{ + return list.size ? &list.entries[list.size - 1] : null; +} + +func bool List.isEmpty(List *list) +{ + return list.size; +} + +func usize List.len(List *list) +{ + return list.size; +} + +func Type List.get(List *list, usize index) +{ + return list.entries[index]; +} + +func void List.free(List *list) +{ + mem::free(list.entries); + list.capacity = 0; + list.size = 0; +} diff --git a/src/compiler/ast.c b/src/compiler/ast.c index 5d36841f3..cd1fd192f 100644 --- a/src/compiler/ast.c +++ b/src/compiler/ast.c @@ -46,6 +46,85 @@ static TypeInfo poison_type_info = { .kind = TYPE_INFO_POISON }; Type *poisoned_type = &poison_type; TypeInfo *poisoned_type_info = &poison_type_info; +const char *decl_to_name(Decl *decl) +{ + switch (decl->decl_kind) + { + case DECL_POISONED: + return "poisoned decl"; + case DECL_CT_CASE: + return "compile time case"; + case DECL_CT_ELIF: + return "compile time else if"; + case DECL_CT_ELSE: + return "compile time else"; + case DECL_CT_IF: + return "compile time if"; + case DECL_CT_SWITCH: + return "compile time switch"; + case DECL_ARRAY_VALUE: + UNREACHABLE; + case DECL_IMPORT: + return "import"; + case DECL_LABEL: + return "label"; + case DECL_ATTRIBUTE: + return "attribute"; + case DECL_DEFINE: + case DECL_TYPEDEF: + return "define"; + case DECL_DISTINCT: + return "distinct type"; + case DECL_ENUM: + return "enum"; + case DECL_ENUM_CONSTANT: + return "enum value"; + case DECL_ERR: + return "error"; + case DECL_FUNC: + return "function"; + case DECL_GENERIC: + return "generic"; + case DECL_INTERFACE: + return "interface"; + case DECL_MACRO: + return "macro"; + case DECL_STRUCT: + return "struct"; + case DECL_UNION: + return "union"; + case DECL_VAR: + switch (decl->var.kind) + { + case VARDECL_CONST: + return "constant"; + case VARDECL_GLOBAL: + return "global variable"; + case VARDECL_LOCAL: + return "variable"; + case VARDECL_PARAM: + return "parameter"; + case VARDECL_MEMBER: + return "member"; + case VARDECL_PARAM_CT: + return "compile time parameter"; + case VARDECL_PARAM_CT_TYPE: + return "compile time type parameter"; + case VARDECL_PARAM_REF: + return "ref parameter"; + case VARDECL_PARAM_EXPR: + return "extpression parameter"; + case VARDECL_LOCAL_CT: + return "compile time variable"; + case VARDECL_LOCAL_CT_TYPE: + return "compile time type variable"; + case VARDECL_ALIAS: + return "alias"; + } + UNREACHABLE + } + UNREACHABLE +} void decl_set_external_name(Decl *decl) { if (decl->visibility == VISIBLE_EXTERN) @@ -106,7 +185,6 @@ 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)); @@ -551,27 +629,27 @@ void fprint_expr_recursive(Context *context, FILE *file, Expr *expr, int indent) DUMPEXPR(expr->failable_expr); DUMPEND(); case EXPR_MACRO_IDENTIFIER: - DUMPF("(ident @%s", expr->macro_identifier_expr.identifier); + DUMPF("(ident @%s", TOKSTR(expr->macro_identifier_expr.identifier)); DUMPEXPC(expr); DUMPEND(); case EXPR_IDENTIFIER: - DUMPF("(ident %s", expr->identifier_expr.identifier); + DUMPF("(ident %s", TOKSTR(expr->identifier_expr.identifier)); DUMPEXPC(expr); DUMPEND(); case EXPR_CT_IDENT: - DUMPF("(ctident %s", expr->ct_ident_expr.identifier); + DUMPF("(ctident %s", TOKSTR(expr->ct_ident_expr.identifier)); DUMPEXPC(expr); DUMPEND(); case EXPR_HASH_IDENT: - DUMPF("(hashident %s", expr->hash_ident_expr.identifier); + DUMPF("(hashident %s", TOKSTR(expr->hash_ident_expr.identifier)); DUMPEXPC(expr); DUMPEND(); case EXPR_MACRO_CT_IDENTIFIER: - DUMPF("(macroctident @%s", expr->ct_ident_expr.identifier); + DUMPF("(macroctident @%s", TOKSTR(expr->ct_ident_expr.identifier)); DUMPEXPC(expr); DUMPEND(); case EXPR_CONST_IDENTIFIER: - DUMPF("(ident %s", expr->identifier_expr.identifier); + DUMPF("(ident %s", TOKSTR(expr->identifier_expr.identifier)); DUMPEXPC(expr); DUMPEND(); case EXPR_MACRO_BLOCK: @@ -783,9 +861,6 @@ 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 76a60de82..73df5f9ea 100644 --- a/src/compiler/compiler.c +++ b/src/compiler/compiler.c @@ -3,6 +3,7 @@ // a copy of which can be found in the LICENSE file. #include "compiler_internal.h" +#include "parser_internal.h" #include #if PLATFORM_POSIX @@ -41,6 +42,7 @@ 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); @@ -144,9 +146,73 @@ void sema_analyze_stage(Module *module, AnalysisStage stage) } } +static void register_generic_decls(Module *module, Decl **decls) +{ + VECEACH(decls, i) + { + Decl *decl = decls[i]; + decl->module = module; + switch (decl->decl_kind) + { + case DECL_POISONED: + case DECL_ARRAY_VALUE: + case DECL_ENUM_CONSTANT: + case DECL_IMPORT: + case DECL_LABEL: + continue; + case DECL_ATTRIBUTE: + break; + case DECL_CT_CASE: + register_generic_decls(module, decl->ct_case_decl.body); + continue; + case DECL_CT_ELIF: + register_generic_decls(module, decl->ct_elif_decl.then); + continue; + case DECL_CT_ELSE: + register_generic_decls(module, decl->ct_else_decl); + continue; + case DECL_CT_IF: + register_generic_decls(module, decl->ct_if_decl.then); + continue; + case DECL_CT_SWITCH: + register_generic_decls(module, decl->ct_switch_decl.cases); + continue; + case DECL_DEFINE: + case DECL_DISTINCT: + case DECL_ENUM: + case DECL_GENERIC: + case DECL_INTERFACE: + case DECL_ERR: + case DECL_FUNC: + case DECL_MACRO: + case DECL_STRUCT: + case DECL_TYPEDEF: + case DECL_UNION: + case DECL_VAR: + break; + } + if (decl->visibility > VISIBLE_MODULE) + { + stable_set(&module->public_symbols, decl->name, decl); + } + stable_set(&module->symbols, decl->name, decl); + } + +} +static void analyze_generic_module(Module *module) +{ + assert(module->parameters); + // TODO maybe do this analysis: sema_analysis_pass_process_imports(module); + VECEACH(module->contexts, index) + { + Context *context = module->contexts[index]; + register_generic_decls(module, context->global_decls); + } +} + static void analyze_to_stage(AnalysisStage stage) { - for (unsigned i = 0; i < vec_size(global_context.module_list); i++) + VECEACH(global_context.module_list, i) { sema_analyze_stage(global_context.module_list[i], stage); } @@ -196,6 +262,8 @@ void compiler_compile(void) vec_add(global_context.sources, strformat("%s/std/runtime.c3", global_context.lib_dir)); vec_add(global_context.sources, strformat("%s/std/builtin.c3", global_context.lib_dir)); vec_add(global_context.sources, strformat("%s/std/io.c3", global_context.lib_dir)); + vec_add(global_context.sources, strformat("%s/std/list.c3", global_context.lib_dir)); + vec_add(global_context.sources, strformat("%s/std/linkedlist.c3", global_context.lib_dir)); vec_add(global_context.sources, strformat("%s/std/mem.c3", global_context.lib_dir)); vec_add(global_context.sources, strformat("%s/std/array.c3", global_context.lib_dir)); vec_add(global_context.sources, strformat("%s/std/math.c3", global_context.lib_dir)); @@ -221,6 +289,10 @@ void compiler_compile(void) error_exit("No source files to compile."); } assert(contexts); + VECEACH(global_context.generic_module_list, i) + { + analyze_generic_module(global_context.generic_module_list[i]); + } for (AnalysisStage stage = ANALYSIS_NOT_BEGUN + 1; stage <= ANALYSIS_LAST; stage++) { analyze_to_stage(stage); @@ -430,7 +502,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) +Module *compiler_find_or_create_module(Path *module_name, TokenId *parameters) { Module *module = global_context_find_module(module_name->module); if (module) return module; @@ -440,9 +512,18 @@ Module *compiler_find_or_create_module(Path *module_name) 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); - vec_add(global_context.module_list, module); + if (parameters) + { + vec_add(global_context.generic_module_list, module); + } + else + { + vec_add(global_context.module_list, module); + } + return module; } diff --git a/src/compiler/compiler_internal.h b/src/compiler/compiler_internal.h index 091b1a372..ef67ea353 100644 --- a/src/compiler/compiler_internal.h +++ b/src/compiler/compiler_internal.h @@ -320,13 +320,6 @@ typedef struct Decl **body; } CtCaseDecl; -typedef struct -{ - struct Context_ *parent_context; - TokenId *params; - Decl **body; -} TemplateDecl; - typedef struct { Expr *expr; @@ -436,9 +429,9 @@ typedef struct typedef enum { - DEFINE_TYPE_TEMPLATE, + DEFINE_TYPE_GENERIC, DEFINE_IDENT_ALIAS, - DEFINE_IDENT_TEMPLATE, + DEFINE_IDENT_GENERIC, } DefineType; typedef struct @@ -450,15 +443,14 @@ typedef struct { union { - Path *path; + TypeInfo *type_info; struct { - Path *template_path; - TokenId template_name; - TypeInfo **template_params; + Path *path; + TokenId identifier; }; }; - TokenId identifier; + TypeInfo **generic_params; }; Decl *alias; }; @@ -540,7 +532,6 @@ typedef struct Decl_ CtCaseDecl ct_case_decl; Decl** ct_else_decl; Expr *incr_array_decl; - TemplateDecl template_decl; }; } Decl; @@ -702,7 +693,7 @@ typedef struct typedef struct { Path *path; - const char *identifier; + TokenId identifier; bool is_ref : 1; bool is_rvalue : 1; Decl *decl; @@ -710,7 +701,7 @@ typedef struct typedef struct { - const char *identifier; + TokenId identifier; bool is_ref : 1; bool is_rvalue : 1; Decl *decl; @@ -1162,11 +1153,12 @@ typedef struct Ast_ typedef struct Module_ { Path *name; + TokenId *parameters; bool is_external : 1; bool is_c_library : 1; bool is_exported : 1; - struct Context_ *template_parent_context; + bool is_generic : 1; AnalysisStage stage : 6; Ast **files; // Asts @@ -1299,6 +1291,7 @@ typedef struct { STable modules; Module **module_list; + Module **generic_module_list; STable global_symbols; STable qualified_symbols; Type **type; @@ -1562,7 +1555,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); +Module *compiler_find_or_create_module(Path *module_name, TokenId *parameters); Module *global_context_find_module(const char *name); void compiler_register_public_symbol(Decl *decl); @@ -1571,10 +1564,8 @@ 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); +bool context_set_module(Context *context, Path *path, TokenId *generic_parameters); void context_print_ast(Context *context, FILE *file); -Decl **context_get_imports(Context *context); #pragma mark --- Decl functions @@ -1585,6 +1576,7 @@ Decl *decl_new_var(TokenId name, TypeInfo *type, VarDeclKind kind, Visibility vi #define DECL_NEW_WITH_TYPE(_kind, _vis) decl_new_with_type(context->tok.id, _kind, _vis) #define DECL_NEW_VAR(_type, _kind, _vis) decl_new_var(context->tok.id, _type, _kind, _vis) void decl_set_external_name(Decl *decl); +const char *decl_to_name(Decl *decl); const char *decl_var_to_string(VarDeclKind kind); static inline Decl *decl_raw(Decl *decl); static inline bool decl_ok(Decl *decl) { return !decl || decl->decl_kind != DECL_POISONED; } @@ -1593,7 +1585,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_TYPE_TEMPLATE) + if (decl->decl_kind == DECL_DEFINE && decl->define_decl.define_kind != DEFINE_TYPE_GENERIC) { return decl->define_decl.alias; } @@ -1685,7 +1677,6 @@ 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); @@ -1705,7 +1696,8 @@ bool sema_analyse_statement(Context *context, Ast *statement); bool sema_expr_analyse_assign_right_side(Context *context, Expr *expr, Type *left_type, Expr *right, ExprFailableStatus lhs_is_failable); Decl *sema_resolve_symbol_in_current_dynamic_scope(Context *context, const char *symbol); -Decl *sema_resolve_symbol(Context *context, const char *symbol, Path *path, Decl **ambiguous_other_decl, Decl **private_decl); +Decl *sema_resolve_parameterized_symbol(Context *context, TokenId symbol, Path *path); +Decl *sema_resolve_normal_symbol(Context *context, TokenId symbol, Path *path, bool handle_error); bool sema_resolve_type_info(Context *context, TypeInfo *type_info); bool sema_resolve_type_info_maybe_inferred(Context *context, TypeInfo *type_info, bool allow_inferred_type); bool sema_resolve_type_shallow(Context *context, TypeInfo *type_info, bool allow_inferred_type); diff --git a/src/compiler/context.c b/src/compiler/context.c index d3cbcea2d..4e6f0a2ac 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) +static inline bool create_module_or_check_name(Context *context, Path *module_name, TokenId *parameters) { context->module_name = module_name; if (context->module == NULL) { - context->module = compiler_find_or_create_module(module_name); + context->module = compiler_find_or_create_module(module_name, parameters); 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); + return create_module_or_check_name(context, path, NULL); } -bool context_set_module(Context *context, Path *path) +bool context_set_module(Context *context, Path *path, TokenId *generic_parameters) { // 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) return false; } - return create_module_or_check_name(context, path); + return create_module_or_check_name(context, path, generic_parameters); } @@ -91,11 +91,6 @@ 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); @@ -215,13 +210,6 @@ 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 e77ffd926..fc2aa4c10 100644 --- a/src/compiler/copying.c +++ b/src/compiler/copying.c @@ -471,9 +471,6 @@ 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: @@ -564,9 +561,9 @@ Decl *copy_decl(Decl *decl) case DECL_DEFINE: switch (decl->define_decl.define_kind) { - case DEFINE_TYPE_TEMPLATE: - case DEFINE_IDENT_TEMPLATE: - MACRO_COPY_TYPE_LIST(decl->define_decl.template_params); + case DEFINE_TYPE_GENERIC: + case DEFINE_IDENT_GENERIC: + MACRO_COPY_TYPE_LIST(decl->define_decl.generic_params); break; case DEFINE_IDENT_ALIAS: break; diff --git a/src/compiler/enums.h b/src/compiler/enums.h index 3c8e61a19..7e69a9f53 100644 --- a/src/compiler/enums.h +++ b/src/compiler/enums.h @@ -155,7 +155,6 @@ typedef enum DECL_LABEL, DECL_MACRO, DECL_STRUCT, - DECL_TEMPLATE, DECL_TYPEDEF, DECL_UNION, DECL_VAR, @@ -164,7 +163,7 @@ typedef enum #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_TEMPLATE + case DECL_DEFINE typedef enum { @@ -431,7 +430,6 @@ 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 d6fe3735c..8170765ab 100644 --- a/src/compiler/headers.c +++ b/src/compiler/headers.c @@ -230,9 +230,6 @@ 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/parse_expr.c b/src/compiler/parse_expr.c index 3a24d85b6..6400bc334 100644 --- a/src/compiler/parse_expr.c +++ b/src/compiler/parse_expr.c @@ -186,7 +186,7 @@ static Expr *parse_macro_ident(Context *context, Expr *left) advance_and_verify(context, TOKEN_AT); if (TOKEN_IS(TOKEN_CT_IDENT)) { - macro_ident->ct_macro_ident_expr.identifier = TOKSTR(context->tok); + macro_ident->ct_macro_ident_expr.identifier = context->tok.id; macro_ident->expr_kind = EXPR_MACRO_CT_IDENTIFIER; advance_and_verify(context, TOKEN_CT_IDENT); RANGE_EXTEND_PREV(macro_ident); @@ -195,7 +195,7 @@ static Expr *parse_macro_ident(Context *context, Expr *left) bool had_error = false; macro_ident->identifier_expr.path = parse_path_prefix(context, &had_error); if (had_error) return poisoned_expr; - macro_ident->identifier_expr.identifier = TOKSTR(context->tok); + macro_ident->identifier_expr.identifier = context->tok.id; CONSUME_OR(TOKEN_IDENT, poisoned_expr); RANGE_EXTEND_PREV(macro_ident); return macro_ident; @@ -552,7 +552,7 @@ static Expr *parse_access_expr(Context *context, Expr *left) static Expr *parse_identifier_with_path(Context *context, Path *path) { Expr *expr = EXPR_NEW_TOKEN(context->tok.type == TOKEN_CONST_IDENT ? EXPR_CONST_IDENTIFIER : EXPR_IDENTIFIER , context->tok); - expr->identifier_expr.identifier = TOKSTR(context->tok); + expr->identifier_expr.identifier = context->tok.id; expr->identifier_expr.path = path; advance(context); return expr; @@ -567,7 +567,7 @@ static Expr *parse_ct_ident(Context *context, Expr *left) return poisoned_expr; } Expr *expr = EXPR_NEW_TOKEN(EXPR_CT_IDENT, context->tok); - expr->ct_ident_expr.identifier = TOKSTR(context->tok); + expr->ct_ident_expr.identifier = context->tok.id; advance(context); return expr; } @@ -576,7 +576,7 @@ static Expr *parse_hash_ident(Context *context, Expr *left) { assert(!left && "Unexpected left hand side"); Expr *expr = EXPR_NEW_TOKEN(EXPR_HASH_IDENT, context->tok); - expr->ct_ident_expr.identifier = TOKSTR(context->tok); + expr->ct_ident_expr.identifier = context->tok.id; advance(context); return expr; } diff --git a/src/compiler/parse_global.c b/src/compiler/parse_global.c index 712527004..45b224d8d 100644 --- a/src/compiler/parse_global.c +++ b/src/compiler/parse_global.c @@ -277,9 +277,63 @@ static inline Path *parse_module_path(Context *context) #pragma mark --- Parse import and module - /** - * module ::= MODULE module_path EOS + * + * 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_LESS)) return true; + + if (try_consume(context, TOKEN_GREATER)) + { + SEMA_TOKEN_ERROR(context->tok, "Generic parameter list cannot be empty."); + return false; + } + + // No params + while (1) + { + switch (context->tok.type) + { + case TOKEN_TYPE_IDENT: + break; + case TOKEN_COMMA: + SEMA_TOKEN_ERROR(context->tok, "Unexpected ','"); + return false; + case TOKEN_IDENT: + SEMA_TOKEN_ERROR(context->tok, "The module parameter must be a type."); + 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_GREATER, "Expected '>'."); + } + } + +} +/** + * module ::= MODULE module_path ('(' module_params ')')? EOS */ bool parse_module(Context *context) { @@ -303,12 +357,20 @@ bool parse_module(Context *context) path->len = strlen("INVALID"); path->module = "INVALID"; path->span = INVALID_RANGE; - context_set_module(context, path); + context_set_module(context, path, NULL); recover_top_level(context); return false; } - context_set_module(context, path); + // 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); TRY_CONSUME_EOS_OR(false); return true; } @@ -1428,7 +1490,7 @@ static inline Decl *parse_generics_declaration(Context *context, Visibility visi * * @return NULL if parsing failed, otherwise a list of Type* */ -static inline TypeInfo **parse_parameterized_define(Context *context) +static inline TypeInfo **parse_generic_parameters(Context *context) { TypeInfo **types = NULL; while (!try_consume(context, TOKEN_GREATER)) @@ -1457,30 +1519,9 @@ static inline bool parse_define_optional_path(Context *context, Path **path) } /** - * 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) ';' + * define_type_body ::= TYPE_IDENT '=' 'distinct'? (func_typedef | type generic_params?) ';' * * 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) { @@ -1518,58 +1559,45 @@ static inline Decl *parse_define_type(Context *context, Visibility visibility) RANGE_EXTEND_PREV(decl); TRY_CONSUME_EOS_OR(poisoned_decl); return decl; - } - // 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)) + // 2. Now parse the type which we know is here. + TypeInfo *type_info = TRY_TYPE_OR(parse_type(context), poisoned_decl); + + // 3. Do we have '<' if so it's a parameterized type e.g. foo::bar::Type. + if (try_consume(context, TOKEN_LESS)) { - 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); + TypeInfo **params = parse_generic_parameters(context); + if (!params) return poisoned_decl; + Decl *decl = decl_new(DECL_DEFINE, alias_name, visibility); decl->span.loc = start; - decl->typedef_decl.type_info = type_info; - decl->typedef_decl.is_func = false; - if (distinct) - { - decl->distinct_decl.typedef_decl = decl->typedef_decl; - decl->type->type_kind = TYPE_DISTINCT; - decl->decl_kind = DECL_DISTINCT; - } + decl->define_decl.define_kind = DEFINE_TYPE_GENERIC; + decl->define_decl.type_info = type_info; + decl->define_decl.generic_params = params; RANGE_EXTEND_PREV(decl); TRY_CONSUME_EOS_OR(poisoned_decl); return decl; } - // 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)) + 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; + decl->typedef_decl.is_func = false; + if (distinct) { - SEMA_TOKEN_ERROR(context->tok, "Expected a template name here."); - return poisoned_decl; + decl->distinct_decl.typedef_decl = decl->typedef_decl; + decl->type->type_kind = TYPE_DISTINCT; + decl->decl_kind = DECL_DISTINCT; } - 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; + RANGE_EXTEND_PREV(decl); TRY_CONSUME_EOS_OR(poisoned_decl); - return decl; } /** - * define_ident ::= 'define' (IDENT | CONST_IDENT) '=' (identifier_alias | template_identifier) + * define_ident ::= 'define' (IDENT | CONST_IDENT) '=' identifier_alias generic_params? * * 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) { @@ -1605,17 +1633,7 @@ static inline Decl *parse_define_ident(Context *context, Visibility visibility) 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; - } + decl->define_decl.path = path; // 6. Check that the token after the path is of the same type. if (context->tok.type != alias_type) @@ -1635,6 +1653,13 @@ static inline Decl *parse_define_ident(Context *context, Visibility visibility) decl->define_decl.identifier = context->tok.id; advance(context); + if (try_consume(context, TOKEN_LESS)) + { + decl->define_decl.define_kind = DEFINE_IDENT_GENERIC; + TypeInfo **params = parse_generic_parameters(context); + if (!params) return poisoned_decl; + decl->define_decl.generic_params = params; + } RANGE_EXTEND_PREV(decl); TRY_CONSUME_EOS_OR(poisoned_decl); return decl; @@ -1975,36 +2000,6 @@ 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 = TRY_DECL_OR(parse_top_level_statement(context), poisoned_decl); - vec_add(body, statement); - } - decl->template_decl.body = body; - return decl; -} /** * interface_declaration ::= INTERFACE TYPE '{' func_decl* '}' @@ -2320,9 +2315,6 @@ 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 642087c7e..e49411d05 100644 --- a/src/compiler/parse_stmt.c +++ b/src/compiler/parse_stmt.c @@ -1166,7 +1166,6 @@ 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 9443426b5..30f6446f4 100644 --- a/src/compiler/sema_decls.c +++ b/src/compiler/sema_decls.c @@ -700,7 +700,7 @@ static AttributeType sema_analyse_attribute(Context *context, Attr *attr, Attrib return type; case ATTRIBUTE_SECTION: case ATTRIBUTE_CNAME: - if (context->module->template_parent_context) + if (context->module->parameters) { SEMA_TOKID_ERROR(attr->name, "'cname' attributes are not allowed in generic modules."); return false; @@ -835,26 +835,6 @@ 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) { @@ -1036,20 +1016,19 @@ static Context *copy_context(Module *module, Context *c) return copy; } -static Module *sema_instantiate_template(Context *context, Decl *template, Path *path, TypeInfo **parms) +static Module *sema_instantiate_module(Context *context, Module *module, Path *path, TypeInfo **parms) { - 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) + Module *new_module = compiler_find_or_create_module(path, NULL); + new_module->is_generic = true; + Context **contexts = module->contexts; + VECEACH(contexts, i) { - TokenId param = 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]; Decl *decl = decl_new_with_type(param, DECL_TYPEDEF, VISIBLE_PUBLIC); decl->resolve_status = RESOLVE_DONE; TypeInfo *type_info = parms[i]; @@ -1057,124 +1036,121 @@ static Module *sema_instantiate_template(Context *context, Decl *template, Path decl->typedef_decl.type_info = type_info; decl->type->name = decl->name; decl->type->canonical = type_info->type->canonical; - vec_add(new_context->global_decls, decl); + vec_add(first_context->global_decls, decl); } return new_module; } -static Decl *sema_analyse_parameterized_define(Context *c, Decl *decl) +static bool sema_analyse_parameterized_define(Context *c, Decl *decl) { - 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) + Path *decl_path; + TokenId name; + switch (decl->define_decl.define_kind) { - if (private_decl && private_decl->decl_kind == DECL_TEMPLATE) + case DEFINE_IDENT_GENERIC: + decl_path = decl->define_decl.path; + name = decl->define_decl.identifier; + break; + case DEFINE_TYPE_GENERIC: { - SEMA_TOKID_ERROR(template_token, "'%s' is a private template.", private_decl->name); - return poisoned_decl; + TypeInfo *define_type = decl->define_decl.type_info; + if (define_type->resolve_status == RESOLVE_DONE && type_is_user_defined(define_type->type)) + { + SEMA_ERROR(define_type, "Expected a user defined type for parameterization."); + return poisoned_decl; + } + decl_path = define_type->unresolved.path; + name = define_type->unresolved.name_loc; + break; } - 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; + default: + UNREACHABLE } - if (template_decl->decl_kind != DECL_TEMPLATE) + Decl *alias = sema_resolve_parameterized_symbol(c, name, decl_path); + if (!decl_ok(alias)) { - SEMA_TOKID_ERROR(template_token, "'%s' is not a template, did you spell it right?", template_name); - return poisoned_decl; + return decl_poison(decl); } - 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); + Module *module = alias->module; + TypeInfo **params = decl->define_decl.generic_params; + unsigned parameter_count = vec_size(module->parameters); assert(parameter_count > 0); if (parameter_count != vec_size(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; + 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.generic_params)); + return decl_poison(decl); } scratch_buffer_clear(); - scratch_buffer_append(template_decl->external_name); - VECEACH(decl->define_decl.template_params, i) + scratch_buffer_append_len(module->name->module, module->name->len); + scratch_buffer_append_char('.'); + VECEACH(decl->define_decl.generic_params, i) { - TypeInfo *type_info = decl->define_decl.template_params[i]; + TypeInfo *type_info = decl->define_decl.generic_params[i]; if (!sema_resolve_type_info(c, type_info)) return poisoned_decl; - scratch_buffer_append_char('.'); + if (i != 0) 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 = decl->span; + path->span = module->name->span; path->len = global_context.scratch_buffer_len; - instantiated_module = sema_instantiate_template(c, template_decl, path, decl->define_decl.template_params); + instantiated_module = sema_instantiate_module(c, module, path, decl->define_decl.generic_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_TOKID_ERROR(decl->define_decl.identifier, "Identifier '%s' could not be found.", name); - return poisoned_decl; - } - 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; - + const char *name_str = TOKSTR(name); + Decl *symbol = module_find_symbol(instantiated_module, name_str); + assert(symbol); context_register_external_symbol(c, symbol); - return symbol; + switch (decl->define_decl.define_kind) + { + case DEFINE_IDENT_GENERIC: + decl->define_decl.alias = symbol; + return true; + case DEFINE_TYPE_GENERIC: + { + Type *type = type_new(TYPE_TYPEDEF, decl->name); + decl->type = type; + decl->decl_kind = DECL_TYPEDEF; + type->canonical = symbol->type->canonical; + return true; + } + default: + UNREACHABLE + } +} +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; - Type *type; - switch (decl->define_decl.define_kind) + // 1. The plain define + if (decl->define_decl.define_kind == 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; - 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; - } + Decl *symbol = sema_resolve_normal_symbol(c, + decl->define_decl.identifier, + decl->define_decl.path, + true); + if (!decl_ok(symbol)) return false; + decl->type = symbol->type; + decl->define_decl.alias = symbol; + return true; } - UNREACHABLE + + // 2. Handle type generics. + return sema_analyse_parameterized_define(c, decl); } @@ -1223,10 +1199,6 @@ 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); diff --git a/src/compiler/sema_expr.c b/src/compiler/sema_expr.c index ffbd6178a..00183648c 100644 --- a/src/compiler/sema_expr.c +++ b/src/compiler/sema_expr.c @@ -166,9 +166,6 @@ 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); @@ -374,8 +371,9 @@ static inline bool sema_expr_analyse_ternary(Context *context, Type *to, Expr *e -static inline Decl *decl_find_enum_constant(const char *name, Decl *decl) +static inline Decl *decl_find_enum_constant(TokenId token, Decl *decl) { + const char *name = TOKSTR(token); VECEACH(decl->enums.values, i) { Decl *enum_constant = decl->enums.values[i]; @@ -387,7 +385,7 @@ static inline Decl *decl_find_enum_constant(const char *name, Decl *decl) return NULL; } -static inline bool sema_expr_analyse_enum_constant(Expr *expr, const char *name, Decl *decl) +static inline bool sema_expr_analyse_enum_constant(Expr *expr, TokenId name, Decl *decl) { Decl *enum_constant = decl_find_enum_constant(name, decl); if (!enum_constant) return false; @@ -423,12 +421,10 @@ static inline bool sema_expr_analyse_identifier_resolve(Context *context, Type * Decl *private_symbol = NULL; expr->pure = true; - DEBUG_LOG("Now resolving %s", id_expr->identifier); - Decl *decl = sema_resolve_symbol(context, - id_expr->identifier, - id_expr->path, - &ambiguous_decl, - &private_symbol); + DEBUG_LOG("Now resolving %s", TOKSTR(id_expr->identifier)); + Decl *decl = sema_resolve_normal_symbol(context, + id_expr->identifier, + id_expr->path, false); if (!decl && !id_expr->path && to) { if (find_possible_inferred_identifier(to, expr)) return true; @@ -436,34 +432,14 @@ static inline bool sema_expr_analyse_identifier_resolve(Context *context, Type * if (!decl) { - if (private_symbol) - { - SEMA_ERROR(expr, "'%s' is not visible from this module.", id_expr->identifier); - } - else if (ambiguous_decl) - { - SEMA_ERROR(expr, "The name '%s' ambiguous, please add a path.", id_expr->identifier); - } - else - { - SEMA_ERROR(expr, "'%s' could not be found, did you spell it right?", id_expr->identifier); - } + decl = sema_resolve_normal_symbol(context, id_expr->identifier, id_expr->path, true); + assert(!decl_ok(decl) && "Expected a poisoned decl here."); return false; } // Already handled if (!decl_ok(decl)) return false; - if (ambiguous_decl) - { - SEMA_ERROR(expr, - "Ambiguous symbol '%s' – both defined in %s and %s, please add the module name to resolve the ambiguity", - id_expr->identifier, - decl->module->name->module, - ambiguous_decl->module->name->module); - return false; - } - if (decl->decl_kind == DECL_FUNC && !id_expr->path && decl->module != context->module) { SEMA_ERROR(expr, "Functions from other modules must be prefixed with the module name, please add '%s' in front.", decl->module->name->module); @@ -545,48 +521,29 @@ static inline bool sema_expr_analyse_identifier(Context *context, Type *to, Expr Decl *private_symbol = NULL; expr->pure = true; - DEBUG_LOG("Now resolving %s", expr->identifier_expr.identifier); - Decl *decl = sema_resolve_symbol(context, - expr->identifier_expr.identifier, - expr->identifier_expr.path, - &ambiguous_decl, - &private_symbol); + DEBUG_LOG("Now resolving %s", TOKSTR(expr->identifier_expr.identifier)); + Decl *decl = sema_resolve_normal_symbol(context, + expr->identifier_expr.identifier, + expr->identifier_expr.path, + false); if (!decl_ok(decl)) return false; if (!decl && !expr->identifier_expr.path && to) { if (find_possible_inferred_identifier(to, expr)) return true; } - if (!decl) { - if (private_symbol) - { - SEMA_ERROR(expr, "'%s' is not visible from this module.", expr->identifier_expr.identifier); - } - else if (ambiguous_decl) - { - SEMA_ERROR(expr, "The name '%s' ambiguous, please add a path.", expr->identifier_expr.identifier); - } - else - { - SEMA_ERROR(expr, "Identifier '%s' could not be found.", expr->identifier_expr.identifier); - } + decl = sema_resolve_normal_symbol(context, + expr->identifier_expr.identifier, + expr->identifier_expr.path, + true); + assert(!decl_ok(decl)); return false; } // Already handled if (!decl_ok(decl)) return false; - if (ambiguous_decl) - { - SEMA_ERROR(expr, - "Ambiguous symbol '%s' – both defined in %s and %s, please add the module name to resolve the ambiguity", - expr->identifier_expr.identifier, - decl->module->name->module, - ambiguous_decl->module->name->module); - return false; - } - if (decl->decl_kind == DECL_FUNC && !expr->identifier_expr.path && decl->module != context->module) { SEMA_ERROR(expr, "Functions from other modules, must be prefixed with the module name"); @@ -654,23 +611,12 @@ static inline bool sema_expr_analyse_identifier(Context *context, Type *to, Expr static inline bool sema_expr_analyse_ct_identifier(Context *context, Expr *expr) { - Decl *ambiguous_decl = NULL; - Decl *private_symbol = NULL; expr->pure = true; - DEBUG_LOG("Now resolving %s", expr->ct_ident_expr.identifier); - Decl *decl = sema_resolve_symbol(context, - expr->ct_ident_expr.identifier, - NULL, - &ambiguous_decl, - &private_symbol); - - assert(!ambiguous_decl && !private_symbol); - if (!decl) - { - SEMA_ERROR(expr, "Compile time variable '%s' could not be found.", expr->ct_ident_expr.identifier); - return false; - } + DEBUG_LOG("Now resolving %s", TOKSTR(expr->ct_ident_expr.identifier)); + Decl *decl = sema_resolve_normal_symbol(context, + expr->ct_ident_expr.identifier, + NULL, true); // Already handled if (!decl_ok(decl)) @@ -691,23 +637,12 @@ static inline bool sema_expr_analyse_ct_identifier(Context *context, Expr *expr) static inline bool sema_expr_analyse_hash_identifier(Context *context, Type *to, Expr *expr) { - Decl *ambiguous_decl = NULL; - Decl *private_symbol = NULL; expr->pure = true; - DEBUG_LOG("Now resolving %s", expr->hash_ident_expr.identifier); - Decl *decl = sema_resolve_symbol(context, - expr->hash_ident_expr.identifier, - NULL, - &ambiguous_decl, - &private_symbol); - - assert(!ambiguous_decl && !private_symbol); - if (!decl) - { - SEMA_ERROR(expr, "Compile time variable '%s' could not be found.", expr->ct_ident_expr.identifier); - return false; - } + DEBUG_LOG("Now resolving %s", TOKSTR(expr->hash_ident_expr.identifier)); + Decl *decl = sema_resolve_normal_symbol(context, + expr->hash_ident_expr.identifier, + NULL, true); // Already handled if (!decl_ok(decl)) @@ -1863,7 +1798,7 @@ static inline bool sema_expr_analyse_type_access(Expr *expr, TypeInfo *parent, b case DECL_ENUM: if (type == TOKEN_CONST_IDENT) { - if (!sema_expr_analyse_enum_constant(expr, name, decl)) + if (!sema_expr_analyse_enum_constant(expr, expr->access_expr.sub_element, decl)) { SEMA_ERROR(expr, "'%s' has no enumeration value '%s'.", decl->name, name); return false; @@ -3020,13 +2955,10 @@ static inline bool sema_expr_analyse_ct_identifier_lvalue(Context *context, Expr Decl *ambiguous_decl = NULL; Decl *private_symbol = NULL; - DEBUG_LOG("Now resolving %s", expr->ct_ident_expr.identifier); - Decl *decl = sema_resolve_symbol(context, + DEBUG_LOG("Now resolving %s", TOKSTR(expr->ct_ident_expr.identifier)); + Decl *decl = sema_resolve_normal_symbol(context, expr->ct_ident_expr.identifier, - NULL, - &ambiguous_decl, - &private_symbol); - assert(!ambiguous_decl && !private_symbol); + NULL, false); // Skip if poisoned. if (!decl_ok(decl)) return false; diff --git a/src/compiler/sema_name_resolution.c b/src/compiler/sema_name_resolution.c index 0736b36eb..e43567867 100644 --- a/src/compiler/sema_name_resolution.c +++ b/src/compiler/sema_name_resolution.c @@ -26,85 +26,6 @@ static inline bool matches_subpath(Path *path_to_check, Path *path_to_find) return 0 == memcmp(path_to_check->module + compare_start, path_to_find->module, path_to_find->len); } -static Decl *sema_resolve_path_symbol(Context *context, const char *symbol, Path *path, Decl **ambiguous_other_decl, - Decl **private_decl) -{ - assert(path && "Expected path."); - *ambiguous_other_decl = NULL; - Decl *decl = NULL; - bool path_found = false; - - // 0. std module special handling. - if (path->module == global_context.std_module_path.module) - { - return module_find_symbol(&global_context.std_module, symbol); - } - - // 1. Do we match our own path? - if (matches_subpath(context->module->name, path)) - { - // 2. If so just get the symbol. - 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(imports, i) - { - Decl *import = imports[i]; - - // 5. Can we match a subpath? - if (path->len > import->import.path->len) continue; - if (!matches_subpath(import->import.path, path)) continue; - - // 6. We have a sub path match at least. - path_found = true; - - // 7. Find the symbol - Decl *found = module_find_symbol(import->module, symbol); - - // 8. No match, so continue - if (!found) continue; - - // 9. If we found something private and we don't import privately? - if (found->visibility <= VISIBLE_MODULE && !import->import.private && !decl) - { - // 10. Register this as a possible private decl. - *private_decl = found; - continue; - } - - // 11. Did we already have a match? - if (decl) - { - // 12. Then set an ambiguous match. - *ambiguous_other_decl = found; - continue; - } - - // 13. We've found a match. - decl = found; - *private_decl = NULL; - } - // 14. If we didn't find one. - if (!decl) - { - // 15. If the path wasn't found, then let's say that. - if (!path_found) - { - SEMA_ERROR(path, "Unknown module '%.*s', did you forget to import it?", path->len, path->module); - return poisoned_decl; - } - // 16. Otherwise return null. - return NULL; - } - - // 17. Store that this external symbol is used and return. - context_register_external_symbol(context, decl); - return decl; -} - Decl *sema_resolve_symbol_in_current_dynamic_scope(Context *context, const char *symbol) { if (context->current_scope) @@ -120,15 +41,75 @@ Decl *sema_resolve_symbol_in_current_dynamic_scope(Context *context, const char return NULL; } -Decl *sema_resolve_symbol(Context *context, const char *symbol, Path *path, Decl **ambiguous_other_decl, - Decl **private_decl) +static Decl *sema_resolve_path_symbol(Context *context, const char *symbol, Path *path, Decl **ambiguous_other_decl, + Decl **private_decl, bool *path_found) { - if (path) + assert(path && "Expected path."); + *ambiguous_other_decl = NULL; + Decl *decl = NULL; + *path_found = false; + + // 0. std module special handling. + if (path->module == global_context.std_module_path.module) { - return sema_resolve_path_symbol(context, symbol, path, ambiguous_other_decl, private_decl); + return module_find_symbol(&global_context.std_module, symbol); } - *ambiguous_other_decl = NULL; + // 1. Do we match our own path? + if (matches_subpath(context->module->name, path)) + { + // 2. If so just get the symbol. + return module_find_symbol(context->module, symbol); + } + + // 3. Loop over imports. + VECEACH(context->imports, i) + { + Decl *import = context->imports[i]; + + if (import->module->parameters) continue; + + // 4. Can we match a subpath? + if (path->len > import->import.path->len) continue; + if (!matches_subpath(import->import.path, path)) continue; + + // 5. We have a sub path match at least. + *path_found = true; + + // 6. Find the symbol + Decl *found = module_find_symbol(import->module, symbol); + + // 7. No match, so continue + if (!found) continue; + + // 8. If we found something private and we don't import privately? + if (found->visibility <= VISIBLE_MODULE && !import->import.private && !decl) + { + // 9. Register this as a possible private decl. + *private_decl = found; + continue; + } + + // 10. Did we already have a match? + if (decl) + { + // 11. Then set an ambiguous match. + *ambiguous_other_decl = found; + continue; + } + + // 12. We've found a match. + decl = found; + *private_decl = NULL; + } + + return decl; +} + +static Decl *sema_resolve_no_path_symbol(Context *context, const char *symbol, + Decl **ambiguous_other_decl, Decl **private_decl) +{ + Decl *decl = NULL; if (context->current_scope) { @@ -143,53 +124,226 @@ Decl *sema_resolve_symbol(Context *context, const char *symbol, Path *path, Decl } // Search in file scope. - Decl *decl = stable_get(&context->local_symbols, symbol); + decl = stable_get(&context->local_symbols, symbol); if (decl) return 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); - return decl; - } + if (decl) return decl; // Search in imports - Decl **imports = context_get_imports(context); - VECEACH(imports, i) + VECEACH(context->imports, i) { - Decl *import = imports[i]; + Decl *import = context->imports[i]; if (!decl_ok(import)) continue; + + // Skip parameterized modules + if (import->module->parameters) continue; + Decl *found = module_find_symbol(import->module, symbol); if (!found) continue; // If we found something private and we don't import privately? if (found->visibility <= VISIBLE_MODULE && !import->import.private && !decl) { - // 10. Register this as a possible private decl. + // Register this as a possible private decl. *private_decl = found; continue; } if (decl) { + // Register this an ambiguous decl. *ambiguous_other_decl = found; continue; } + decl = found; - *private_decl = found; + private_decl = NULL; } - if (!decl) return NULL; - context_register_external_symbol(context, decl); return decl; } + +static void sema_report_error_on_decl(const char *symbol_str, TokenId symbol, Decl *found, Decl *ambiguous_decl, + Decl *private_decl) +{ + if (!found && private_decl) + { + SEMA_TOKID_ERROR(symbol, "The %s '%s' is not visible from this module.", decl_to_name(private_decl), symbol_str); + return; + } + if (ambiguous_decl) + { + assert(found); + const char *symbol_type = decl_to_name(found); + SEMA_TOKID_ERROR(symbol, + "The %s '%s' is defined in both '%s' and '%s', please use either %s::%s or %s::%s to resolve the ambiguity.", + symbol_type, + symbol_str, + found->module->name->module, + ambiguous_decl->module->name->module, + found->module->name->module, + symbol_str, + ambiguous_decl->module->name->module, + symbol_str); + return; + } + assert(!found); + switch (TOKTYPE(symbol)) + { + case TOKEN_TYPE_IDENT: + SEMA_TOKID_ERROR(symbol, "The type '%s' could not be found, did you spell it right?", symbol_str); + break; + case TOKEN_CONST_IDENT: + SEMA_TOKID_ERROR(symbol, "The constant '%s' could not be found, did you spell it right?", symbol_str); + break; + default: + SEMA_TOKID_ERROR(symbol, "The identifier '%s' could not be found, did you spell it right?", symbol_str); + break; + } +} + +static Decl *sema_resolve_symbol(Context *context, TokenId symbol, Path *path, bool report_error) +{ + Decl *ambiguous_other_decl = NULL; + Decl *private_decl = NULL; + bool path_found = false; + Decl *decl; + const char *symbol_str = TOKSTR(symbol); + if (path) + { + decl = sema_resolve_path_symbol(context, symbol_str, path, &ambiguous_other_decl, &private_decl, &path_found); + if (!decl && !path_found && report_error) + { + SEMA_ERROR(path, "Unknown module '%.*s', did you forget to import it?", path->len, path->module); + return poisoned_decl; + } + } + else + { + decl = sema_resolve_no_path_symbol(context, symbol_str, &ambiguous_other_decl, &private_decl); + } + + if (!decl || ambiguous_other_decl) + { + if (!report_error) return NULL; + sema_report_error_on_decl(symbol_str, symbol, decl, ambiguous_other_decl, private_decl); + return poisoned_decl; + } + if (decl->module && decl->module != context->module) + { + context_register_external_symbol(context, decl); + } + return decl; +} + +Decl *sema_resolve_parameterized_symbol(Context *context, TokenId symbol, Path *path) +{ + Decl *ambiguous_other_decl = NULL; + Decl *private_decl = NULL; + bool path_found = false; + Decl *decl = NULL; + const char *symbol_str = TOKSTR(symbol); + if (path) + { + // 3. Loop over imports. + VECEACH(context->imports, i) + { + Decl *import = context->imports[i]; + + // Skip any without parameters. + if (!import->module->parameters) continue; + + // 5. Can we match a subpath? + if (path->len > import->import.path->len) continue; + if (!matches_subpath(import->import.path, path)) continue; + + // 6. We have a sub path match at least. + path_found = true; + + // 7. Find the symbol + Decl *found = module_find_symbol(import->module, symbol_str); + + // 8. No match, so continue + if (!found) continue; + + // 9. If we found something private and we don't import privately? + if (found->visibility <= VISIBLE_MODULE && !import->import.private && !decl) + { + // 10. Register this as a possible private decl. + private_decl = found; + continue; + } + + // 11. Did we already have a match? + if (decl) + { + // 12. Then set an ambiguous match. + ambiguous_other_decl = found; + continue; + } + + // 13. We've found a match. + decl = found; + private_decl = NULL; + } + // 14. Error report + if (!decl || ambiguous_other_decl) + { + sema_report_error_on_decl(symbol_str, symbol, decl, ambiguous_other_decl, private_decl); + return poisoned_decl; + } + return decl; + } + // 15. Loop over imports. + VECEACH(context->imports, i) + { + Decl *import = context->imports[i]; + + // Skip any without parameters. + if (!import->module->parameters) continue; + + // 7. Find the symbol + Decl *found = module_find_symbol(import->module, symbol_str); + + // 8. No match, so continue + if (!found) continue; + + // 9. If we found something private and we don't import privately? + if (found->visibility <= VISIBLE_MODULE && !import->import.private && !decl) + { + // 10. Register this as a possible private decl. + private_decl = found; + continue; + } + + // 11. Did we already have a match? + if (decl) + { + // 12. Then set an ambiguous match. + ambiguous_other_decl = found; + continue; + } + + // 13. We've found a match. + decl = found; + private_decl = NULL; + } + // 14. Error report + if (!decl || ambiguous_other_decl) + { + sema_report_error_on_decl(symbol_str, symbol, decl, ambiguous_other_decl, private_decl); + return poisoned_decl; + } + return decl; +} + +Decl *sema_resolve_normal_symbol(Context *context, TokenId symbol, Path *path, bool handle_error) +{ + return sema_resolve_symbol(context, symbol, path, handle_error); +} + static inline bool sema_append_local(Context *context, Decl *decl) { if (context->last_local == &context->locals[MAX_LOCALS - 1]) @@ -209,9 +363,7 @@ bool sema_add_member(Context *context, Decl *decl) bool sema_add_local(Context *context, Decl *decl) { - Decl *dummy; - Decl *dummy2; - Decl *other = sema_resolve_symbol(context, decl->name, NULL, &dummy, &dummy2); + Decl *other = sema_resolve_normal_symbol(context, decl->name_token, NULL, false); if (other) { sema_shadow_error(decl, other); diff --git a/src/compiler/sema_passes.c b/src/compiler/sema_passes.c index 7900e05de..58a7518e2 100644 --- a/src/compiler/sema_passes.c +++ b/src/compiler/sema_passes.c @@ -57,7 +57,7 @@ void sema_analysis_pass_process_imports(Module *module) continue; } - // 6. Assign the module. + // 7. Assign the module. DEBUG_LOG("* Import of %s.", path->module); import->module = import_module; for (unsigned j = 0; j < i; j++) @@ -89,6 +89,7 @@ void sema_analysis_pass_register_globals(Module *module) VECEACH(module->contexts, index) { Context *context = module->contexts[index]; + context->module = module; DEBUG_LOG("Processing %s.", context->file->name); Decl **decls = context->global_decls; VECEACH(decls, i) @@ -201,10 +202,6 @@ 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 d57560205..dd6762862 100644 --- a/src/compiler/sema_stmts.c +++ b/src/compiler/sema_stmts.c @@ -940,7 +940,7 @@ static inline Decl *sema_analyse_label(Context *context, Ast *stmt) { Decl *ambiguous; Decl *dummy; - Decl *target = sema_resolve_symbol(context, stmt->contbreak_stmt.label.name, NULL, &ambiguous, &dummy); + Decl *target = sema_resolve_normal_symbol(context, stmt->contbreak_stmt.label.span, NULL, false); if (!target) { SEMA_ERROR(stmt, "Cannot find a labelled statement with the name '%s'.", stmt->contbreak_stmt.label.name); @@ -1017,9 +1017,7 @@ static bool sema_analyse_next_stmt(Context *context, Ast *statement) if (statement->next_stmt.label.name) { - Decl *ambiguous; - Decl *dummy; - Decl *target = sema_resolve_symbol(context, statement->next_stmt.label.name, NULL, &ambiguous, &dummy); + Decl *target = sema_resolve_normal_symbol(context, statement->next_stmt.label.span, NULL, false); if (!target) { SEMA_ERROR(statement, "Cannot find a switch statement with the name '%s'.", statement->next_stmt.label.name); @@ -1593,10 +1591,9 @@ static bool sema_analyse_catch_stmt(Context *context, Ast *statement) { Decl *ambiguous_decl; Decl *dummy; - Decl *error_var_decl = sema_resolve_symbol(context, - left->identifier_expr.identifier, - left->identifier_expr.path, - &ambiguous_decl, &dummy); + Decl *error_var_decl = sema_resolve_normal_symbol(context, + left->identifier_expr.identifier, + left->identifier_expr.path, false); if (!error_var_decl) { error_var = decl_new_var(left->span.loc, type_info_new_base(type_error, left->span), VARDECL_LOCAL, diff --git a/src/compiler/sema_types.c b/src/compiler/sema_types.c index 0dec66025..506d0c599 100644 --- a/src/compiler/sema_types.c +++ b/src/compiler/sema_types.c @@ -70,45 +70,16 @@ static inline bool sema_resolve_array_type(Context *context, TypeInfo *type) static bool sema_resolve_type_identifier(Context *context, TypeInfo *type_info) { - Decl *ambiguous_decl = NULL; - Decl *private_decl = NULL; - Decl *decl = sema_resolve_symbol(context, - TOKSTR(type_info->unresolved.name_loc), - type_info->unresolved.path, - &ambiguous_decl, &private_decl); - if (!decl) - { - if (private_decl) - { - SEMA_TOKID_ERROR(type_info->unresolved.name_loc, "Type '%s' is not visible from this module.", TOKSTR(type_info->unresolved.name_loc)); - } - else if (ambiguous_decl) - { - SEMA_TOKID_ERROR(type_info->unresolved.name_loc, "The type '%s' ambiguous, please add a path.", TOKSTR(type_info->unresolved.name_loc)); - } - else - { - SEMA_TOKID_ERROR(type_info->unresolved.name_loc, "Unknown type '%s'.", TOKSTR(type_info->unresolved.name_loc)); - } - return type_info_poison(type_info); - } - + Decl *decl = sema_resolve_normal_symbol(context, + type_info->unresolved.name_loc, + type_info->unresolved.path, true); + decl = decl_flatten(decl); // Already handled if (!decl_ok(decl)) { return type_info_poison(type_info); } - - if (ambiguous_decl) - { - SEMA_TOKID_ERROR(type_info->unresolved.name_loc, - "Ambiguous type '%s' – both defined in %s and %s, please add the module name to resolve the ambiguity", - TOKSTR(type_info->unresolved.name_loc), - decl->module->name->module, - ambiguous_decl->module->name->module); - return type_info_poison(type_info); - } switch (decl->decl_kind) { case DECL_STRUCT: @@ -116,13 +87,13 @@ static bool sema_resolve_type_identifier(Context *context, TypeInfo *type_info) case DECL_ERR: case DECL_ENUM: case DECL_TYPEDEF: - case DECL_DEFINE: case DECL_DISTINCT: case DECL_INTERFACE: type_info->type = decl->type; type_info->resolve_status = RESOLVE_DONE; DEBUG_LOG("Resolved %s.", TOKSTR(type_info->unresolved.name_loc)); return true; + case DECL_DEFINE: case DECL_POISONED: return type_info_poison(type_info); case DECL_VAR: @@ -141,7 +112,6 @@ 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 c1346ff56..af46837b3 100644 --- a/src/compiler/tokens.c +++ b/src/compiler/tokens.c @@ -240,8 +240,6 @@ 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/version.h b/src/version.h index 8d2468530..0f458e403 100644 --- a/src/version.h +++ b/src/version.h @@ -1 +1 @@ -#define COMPILER_VERSION "A224" \ No newline at end of file +#define COMPILER_VERSION "A225" \ No newline at end of file diff --git a/test/test_suite/expressions/casts/cast_unknown.c3 b/test/test_suite/expressions/casts/cast_unknown.c3 index 2bb470156..39f3e7a19 100644 --- a/test/test_suite/expressions/casts/cast_unknown.c3 +++ b/test/test_suite/expressions/casts/cast_unknown.c3 @@ -6,16 +6,16 @@ func void test1() int b = (Number)(a); - int c = (Foo)(a); // #error: Unknown type 'Foo'. + int c = (Foo)(a); // #error: type 'Foo' could not be found } func void test2() { - int d = (Number)(bar);; // #error: Identifier 'bar' could not be found. + int d = (Number)(bar);; // #error: identifier 'bar' could not be found } func void test3() { - int e = (Bar)( // #error: Unknown type 'Bar'. - faa); // #error: Identifier 'faa' could not be found. + int e = (Bar)( // #error: type 'Bar' could not be found + faa); // #error: identifier 'faa' could not be found } diff --git a/test/test_suite/expressions/ternary_no_ident.c3 b/test/test_suite/expressions/ternary_no_ident.c3 index 34d528105..e0f711a3b 100644 --- a/test/test_suite/expressions/ternary_no_ident.c3 +++ b/test/test_suite/expressions/ternary_no_ident.c3 @@ -1,14 +1,14 @@ func void test1() { - int a = (i ? 1 : 1); // #error: Identifier 'i' could not be found. + int a = (i ? 1 : 1); // #error: identifier 'i' could not be found, did you spell it right } func void test2() { - int a = (1 ? i : 2); // #error: Identifier 'i' could not be found. + int a = (1 ? i : 2); // #error: identifier 'i' could not be found, did you spell it right } func void test3() { - int a = (1 ? 2 : i); // #error: Identifier 'i' could not be found. + int a = (1 ? 2 : i); // #error: identifier 'i' could not be found, did you spell it right } diff --git a/test/test_suite/macros/hash_ident.c3 b/test/test_suite/macros/hash_ident.c3 index a6b026223..3dc1b1b2e 100644 --- a/test/test_suite/macros/hash_ident.c3 +++ b/test/test_suite/macros/hash_ident.c3 @@ -19,6 +19,6 @@ func void main() @cofefe(x += 1); @cofefe(xx()); @cofefe($x += 1); // #error: Cannot modify '$x' inside of a runtime scope. - @cofefe(y += 1); // #error: Identifier 'y' could not be found. + @cofefe(y += 1); // #error: identifier 'y' could not be found } diff --git a/test/test_suite/statements/switch_errors.c3 b/test/test_suite/statements/switch_errors.c3 index 0bd07e8e9..89912b6fe 100644 --- a/test/test_suite/statements/switch_errors.c3 +++ b/test/test_suite/statements/switch_errors.c3 @@ -43,7 +43,7 @@ func void test_scope(int i) int a = 0; break; case 2: - test_scope(a + 1); // #error: Identifier 'a' could not be found + test_scope(a + 1); // #error: identifier 'a' could not be found, did you spell it right } } diff --git a/test/test_suite/types/enum_errors.c3 b/test/test_suite/types/enum_errors.c3 index 55e5541f4..63b0434ef 100644 --- a/test/test_suite/types/enum_errors.c3 +++ b/test/test_suite/types/enum_errors.c3 @@ -1,7 +1,7 @@ enum EnumTestErrorType3 : int { - A = FOO // #error: Identifier 'FOO' could not be found + A = FOO // #error: constant 'FOO' could not be found, did you spell it } func int foo() diff --git a/test/test_suite/visibility/ambiguous_var.c3t b/test/test_suite/visibility/ambiguous_var.c3t index afce417da..f5e7cd15c 100644 --- a/test/test_suite/visibility/ambiguous_var.c3t +++ b/test/test_suite/visibility/ambiguous_var.c3t @@ -23,5 +23,5 @@ static func void test2() c = foo::b; c = bar::b; c = foo::a; - c = b; // #error: Ambiguous symbol 'b' – both defined in foo and bar, please add the module name to resolve the ambiguity + c = b; // #error: global variable 'b' is defined in both 'foo' and 'bar', please use either foo::b or bar::b to resolve the ambiguity }