Generic modules are back, slightly different.

This commit is contained in:
Christoffer Lerno
2021-05-29 20:02:38 +02:00
committed by Christoffer Lerno
parent 97ac957cb7
commit d9566ef894
27 changed files with 980 additions and 845 deletions

View File

@@ -14,286 +14,3 @@ macro make_zero($Type, usize elements)
$Type* ptr = mem::calloc($Type.sizeof, elements);
return ptr[0..(elements - 1)];
}
template vararray <Type>
{
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 <Type>
{
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--;
}
}

View File

@@ -0,0 +1,167 @@
module std::array::linkedlist<Type>;
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--;
}

114
resources/lib/std/list.c3 Normal file
View File

@@ -0,0 +1,114 @@
module std::array::list<Type>;
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;
}

View File

@@ -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);

View File

@@ -3,6 +3,7 @@
// a copy of which can be found in the LICENSE file.
#include "compiler_internal.h"
#include "parser_internal.h"
#include <unistd.h>
#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;
}

View File

@@ -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);

View File

@@ -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)

View File

@@ -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;

View File

@@ -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,

View File

@@ -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
}

View File

@@ -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;
}

View File

@@ -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<int, double>.
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<int, double>::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;

View File

@@ -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;

View File

@@ -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);

View File

@@ -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;

View File

@@ -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);

View File

@@ -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]);

View File

@@ -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,

View File

@@ -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:

View File

@@ -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:

View File

@@ -1 +1 @@
#define COMPILER_VERSION "A224"
#define COMPILER_VERSION "A225"

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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
}
}

View File

@@ -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()

View File

@@ -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
}