mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 20:11:17 +00:00
Generic modules are back, slightly different.
This commit is contained in:
committed by
Christoffer Lerno
parent
97ac957cb7
commit
d9566ef894
@@ -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--;
|
||||
}
|
||||
}
|
||||
|
||||
167
resources/lib/std/linkedlist.c3
Normal file
167
resources/lib/std/linkedlist.c3
Normal 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
114
resources/lib/std/list.c3
Normal 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;
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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]);
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -1 +1 @@
|
||||
#define COMPILER_VERSION "A224"
|
||||
#define COMPILER_VERSION "A225"
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user