mirror of
https://github.com/Ed94/Odin.git
synced 2026-08-02 04:38:16 +00:00
#import "" as namespace
This commit is contained in:
+30
-22
@@ -315,7 +315,7 @@ void check_close_scope(Checker *c) {
|
||||
c->context.scope = c->context.scope->parent;
|
||||
}
|
||||
|
||||
void scope_lookup_parent_entity(Checker *c, Scope *scope, String name, Scope **scope_, Entity **entity_) {
|
||||
void scope_lookup_parent_entity(Scope *scope, String name, Scope **scope_, Entity **entity_) {
|
||||
b32 gone_thru_proc = false;
|
||||
HashKey key = hash_string(name);
|
||||
for (Scope *s = scope; s != NULL; s = s->parent) {
|
||||
@@ -366,9 +366,9 @@ void scope_lookup_parent_entity(Checker *c, Scope *scope, String name, Scope **s
|
||||
if (scope_) *scope_ = NULL;
|
||||
}
|
||||
|
||||
Entity *scope_lookup_entity(Checker *c, Scope *s, String name) {
|
||||
Entity *scope_lookup_entity(Scope *s, String name) {
|
||||
Entity *entity = NULL;
|
||||
scope_lookup_parent_entity(c, s, name, NULL, &entity);
|
||||
scope_lookup_parent_entity(s, name, NULL, &entity);
|
||||
return entity;
|
||||
}
|
||||
|
||||
@@ -949,33 +949,41 @@ void check_parsed_files(Checker *c) {
|
||||
|
||||
gb_for_array(decl_index, f->decls) {
|
||||
AstNode *decl = f->decls[decl_index];
|
||||
switch (decl->kind) {
|
||||
case_ast_node(id, ImportDecl, decl);
|
||||
HashKey key = hash_string(id->fullpath);
|
||||
auto found = map_get(&file_scopes, key);
|
||||
GB_ASSERT_MSG(found != NULL, "Unable to find scope for file: %.*s", LIT(id->fullpath));
|
||||
Scope *scope = *found;
|
||||
b32 previously_added = false;
|
||||
gb_for_array(import_index, file_scope->imported) {
|
||||
Scope *prev = file_scope->imported[import_index];
|
||||
if (prev == scope) {
|
||||
previously_added = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!previously_added) {
|
||||
gb_array_append(file_scope->imported, scope);
|
||||
}
|
||||
if (decl->kind != AstNode_ImportDecl) {
|
||||
continue;
|
||||
}
|
||||
ast_node(id, ImportDecl, decl);
|
||||
|
||||
HashKey key = hash_string(id->fullpath);
|
||||
auto found = map_get(&file_scopes, key);
|
||||
GB_ASSERT_MSG(found != NULL, "Unable to find scope for file: %.*s", LIT(id->fullpath));
|
||||
Scope *scope = *found;
|
||||
b32 previously_added = false;
|
||||
gb_for_array(import_index, file_scope->imported) {
|
||||
Scope *prev = file_scope->imported[import_index];
|
||||
if (prev == scope) {
|
||||
previously_added = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!previously_added) {
|
||||
gb_array_append(file_scope->imported, scope);
|
||||
}
|
||||
|
||||
if (are_strings_equal(id->import_name.string, make_string("_"))) {
|
||||
// NOTE(bill): Add imported entities to this file's scope
|
||||
gb_for_array(elem_index, scope->elements.entries) {
|
||||
Entity *e = scope->elements.entries[elem_index].value;
|
||||
// NOTE(bill): Do not add other imported entities
|
||||
if (e->scope == scope) {
|
||||
if (e->scope == scope && e->kind != Entity_ImportName) {
|
||||
add_entity(c, file_scope, NULL, e);
|
||||
}
|
||||
}
|
||||
case_end;
|
||||
} else {
|
||||
Entity *e = make_entity_import_name(c->allocator, file_scope, id->import_name, t_invalid,
|
||||
id->fullpath, id->import_name.string,
|
||||
scope);
|
||||
add_entity(c, file_scope, NULL, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+19
-1
@@ -9,6 +9,7 @@ enum BuiltinProcId;
|
||||
ENTITY_KIND(TypeName), \
|
||||
ENTITY_KIND(Procedure), \
|
||||
ENTITY_KIND(Builtin), \
|
||||
ENTITY_KIND(ImportName), \
|
||||
ENTITY_KIND(Count),
|
||||
|
||||
|
||||
@@ -49,11 +50,19 @@ struct Entity {
|
||||
i32 field_index; // Order in source
|
||||
b8 is_field; // Is struct field
|
||||
} Variable;
|
||||
struct {} TypeName;
|
||||
struct {
|
||||
struct DeclInfo *decl; // Usually NULL
|
||||
} TypeName;
|
||||
struct {
|
||||
b8 pure;
|
||||
} Procedure;
|
||||
struct { BuiltinProcId id; } Builtin;
|
||||
struct {
|
||||
String path;
|
||||
String name;
|
||||
Scope *scope;
|
||||
b32 used;
|
||||
} ImportName;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -124,6 +133,15 @@ Entity *make_entity_builtin(gbAllocator a, Scope *scope, Token token, Type *type
|
||||
return entity;
|
||||
}
|
||||
|
||||
Entity *make_entity_import_name(gbAllocator a, Scope *scope, Token token, Type *type,
|
||||
String path, String name, Scope *import_scope) {
|
||||
Entity *entity = alloc_entity(a, Entity_ImportName, scope, token, type);
|
||||
entity->ImportName.path = path;
|
||||
entity->ImportName.name = name;
|
||||
entity->ImportName.scope = import_scope;
|
||||
return entity;
|
||||
}
|
||||
|
||||
Entity *make_entity_dummy_variable(gbAllocator a, Scope *file_scope, Token token) {
|
||||
token.string = make_string("_");
|
||||
return make_entity_variable(a, file_scope, token, NULL);
|
||||
|
||||
+114
-65
@@ -286,8 +286,9 @@ void check_fields(Checker *c, AstNode *node, AstNodeArray decls,
|
||||
Token name_token = td->name->Ident;
|
||||
|
||||
Entity *e = make_entity_type_name(c->allocator, c->context.scope, name_token, NULL);
|
||||
check_type_decl(c, e, td->type, NULL, NULL);
|
||||
add_entity(c, c->context.scope, td->name, e);
|
||||
gb_printf("%.*s\n", LIT(e->token.string));
|
||||
check_type_decl(c, e, td->type, NULL, NULL);
|
||||
|
||||
HashKey key = hash_string(name_token.string);
|
||||
if (map_get(&entity_map, key) != NULL) {
|
||||
@@ -728,10 +729,14 @@ void check_identifier(Checker *c, Operand *o, AstNode *n, Type *named_type, Cycl
|
||||
GB_ASSERT(n->kind == AstNode_Ident);
|
||||
o->mode = Addressing_Invalid;
|
||||
o->expr = n;
|
||||
Entity *e = scope_lookup_entity(c, c->context.scope, n->Ident.string);
|
||||
Entity *e = scope_lookup_entity(c->context.scope, n->Ident.string);
|
||||
if (e == NULL) {
|
||||
error(&c->error_collector, n->Ident,
|
||||
"Undeclared type or identifier `%.*s`", LIT(n->Ident.string));
|
||||
if (are_strings_equal(n->Ident.string, make_string("_"))) {
|
||||
error(&c->error_collector, n->Ident, "`_` cannot be used as a value type");
|
||||
} else {
|
||||
error(&c->error_collector, n->Ident,
|
||||
"Undeclared named: `%.*s`", LIT(n->Ident.string));
|
||||
}
|
||||
return;
|
||||
}
|
||||
add_entity_use(&c->info, n, e);
|
||||
@@ -744,14 +749,7 @@ void check_identifier(Checker *c, Operand *o, AstNode *n, Type *named_type, Cycl
|
||||
gb_array_free(local_cycle_checker.path);
|
||||
});
|
||||
|
||||
if (e->type == NULL) {
|
||||
auto *found = map_get(&c->info.entities, hash_pointer(e));
|
||||
if (found != NULL) {
|
||||
check_entity_decl(c, e, *found, named_type, cycle_checker);
|
||||
} else {
|
||||
GB_PANIC("Internal Compiler Error: DeclInfo not found!");
|
||||
}
|
||||
}
|
||||
check_entity_decl(c, e, NULL, named_type, cycle_checker);
|
||||
|
||||
if (e->type == NULL) {
|
||||
GB_PANIC("Compiler error: How did this happen? type: %s; identifier: %.*s\n", type_to_string(e->type), LIT(n->Ident.string));
|
||||
@@ -808,6 +806,10 @@ void check_identifier(Checker *c, Operand *o, AstNode *n, Type *named_type, Cycl
|
||||
o->mode = Addressing_Builtin;
|
||||
break;
|
||||
|
||||
case Entity_ImportName:
|
||||
error(&c->error_collector, ast_node_token(n), "Use of import `%.*s` not in selector", LIT(e->ImportName.name));
|
||||
return;
|
||||
|
||||
default:
|
||||
GB_PANIC("Compiler error: Unknown EntityKind");
|
||||
break;
|
||||
@@ -875,18 +877,30 @@ Type *check_type(Checker *c, AstNode *e, Type *named_type, CycleChecker *cycle_c
|
||||
|
||||
case_ast_node(se, SelectorExpr, e);
|
||||
Operand o = {};
|
||||
o.mode = Addressing_Type;
|
||||
o.type = check_type(c, se->expr, named_type, cycle_checker);
|
||||
// gb_printf_err("mode: %.*s\n", LIT(addressing_mode_strings[o.mode]));
|
||||
check_selector(c, &o, e);
|
||||
// gb_printf_err("%s.%s\n", expr_to_string(se->expr), expr_to_string(se->selector));
|
||||
// gb_printf_err("%s\n", type_to_string(o.type));
|
||||
// gb_printf_err("mode: %.*s\n", LIT(addressing_mode_strings[o.mode]));
|
||||
|
||||
if (o.mode == Addressing_Type) {
|
||||
switch (o.mode) {
|
||||
case Addressing_Type:
|
||||
GB_ASSERT(o.type != NULL);
|
||||
set_base_type(type, o.type);
|
||||
o.type->flags |= e->type_flags;
|
||||
return o.type;
|
||||
|
||||
case Addressing_Invalid:
|
||||
break;
|
||||
case Addressing_NoValue: {
|
||||
gbString err = expr_to_string(e);
|
||||
defer (gb_string_free(err));
|
||||
error(&c->error_collector, ast_node_token(e), "`%s` used as a type", err);
|
||||
} break;
|
||||
default: {
|
||||
gbString err = expr_to_string(e);
|
||||
defer (gb_string_free(err));
|
||||
error(&c->error_collector, ast_node_token(e), "`%s` is not a type", err);
|
||||
} break;
|
||||
}
|
||||
|
||||
if (o.mode == Addressing_Type) {
|
||||
}
|
||||
case_end;
|
||||
|
||||
@@ -1959,54 +1973,90 @@ b32 check_index_value(Checker *c, AstNode *index_value, i64 max_count, i64 *valu
|
||||
}
|
||||
|
||||
Entity *check_selector(Checker *c, Operand *operand, AstNode *node) {
|
||||
GB_ASSERT(node->kind == AstNode_SelectorExpr);
|
||||
|
||||
ast_node(se, SelectorExpr, node);
|
||||
|
||||
b32 check_op_expr = true;
|
||||
Entity *entity = NULL;
|
||||
|
||||
AstNode *op_expr = se->expr;
|
||||
AstNode *selector = se->selector;
|
||||
if (selector) {
|
||||
Entity *entity = lookup_field(operand->type, selector->Ident.string, operand->mode == Addressing_Type).entity;
|
||||
if (entity == NULL) {
|
||||
gbString op_str = expr_to_string(op_expr);
|
||||
gbString type_str = type_to_string(operand->type);
|
||||
gbString sel_str = expr_to_string(selector);
|
||||
defer (gb_string_free(op_str));
|
||||
defer (gb_string_free(type_str));
|
||||
defer (gb_string_free(sel_str));
|
||||
error(&c->error_collector, ast_node_token(op_expr), "`%s` (`%s`) has no field `%s`", op_str, type_str, sel_str);
|
||||
operand->mode = Addressing_Invalid;
|
||||
operand->expr = node;
|
||||
return NULL;
|
||||
}
|
||||
add_entity_use(&c->info, selector, entity);
|
||||
|
||||
operand->type = entity->type;
|
||||
operand->expr = node;
|
||||
switch (entity->kind) {
|
||||
case Entity_Constant:
|
||||
operand->mode = Addressing_Constant;
|
||||
operand->value = entity->Constant.value;
|
||||
break;
|
||||
case Entity_Variable:
|
||||
operand->mode = Addressing_Variable;
|
||||
break;
|
||||
case Entity_TypeName:
|
||||
operand->mode = Addressing_Type;
|
||||
break;
|
||||
case Entity_Procedure:
|
||||
operand->mode = Addressing_Value;
|
||||
break;
|
||||
case Entity_Builtin:
|
||||
operand->mode = Addressing_Builtin;
|
||||
operand->builtin_id = entity->Builtin.id;
|
||||
break;
|
||||
}
|
||||
|
||||
return entity;
|
||||
} else {
|
||||
operand->mode = Addressing_Invalid;
|
||||
operand->expr = node;
|
||||
AstNode *selector = unparen_expr(se->selector);
|
||||
if (selector == NULL) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
GB_ASSERT(selector->kind == AstNode_Ident);
|
||||
|
||||
if (op_expr->kind == AstNode_Ident) {
|
||||
String name = op_expr->Ident.string;
|
||||
Entity *e = scope_lookup_entity(c->context.scope, name);
|
||||
add_entity_use(&c->info, op_expr, e);
|
||||
if (e != NULL && e->kind == Entity_ImportName) {
|
||||
check_op_expr = false;
|
||||
entity = scope_lookup_entity(e->ImportName.scope, selector->Ident.string);
|
||||
add_entity_use(&c->info, selector, entity);
|
||||
if (entity == NULL) {
|
||||
gbString sel_str = expr_to_string(selector);
|
||||
defer (gb_string_free(sel_str));
|
||||
error(&c->error_collector, ast_node_token(op_expr), "`%s` is not declared in `%.*s`", sel_str, LIT(name));
|
||||
goto error;
|
||||
}
|
||||
if (entity->type == NULL) { // Not setup yet
|
||||
check_entity_decl(c, entity, NULL, NULL);
|
||||
}
|
||||
GB_ASSERT(entity->type != NULL);
|
||||
}
|
||||
}
|
||||
if (check_op_expr) {
|
||||
check_expr_base(c, operand, op_expr);
|
||||
if (operand->mode == Addressing_Invalid) {
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
if (entity == NULL) {
|
||||
entity = lookup_field(operand->type, selector->Ident.string, operand->mode == Addressing_Type).entity;
|
||||
}
|
||||
if (entity == NULL) {
|
||||
gbString op_str = expr_to_string(op_expr);
|
||||
gbString type_str = type_to_string(operand->type);
|
||||
gbString sel_str = expr_to_string(selector);
|
||||
defer (gb_string_free(op_str));
|
||||
defer (gb_string_free(type_str));
|
||||
defer (gb_string_free(sel_str));
|
||||
error(&c->error_collector, ast_node_token(op_expr), "`%s` (`%s`) has no field `%s`", op_str, type_str, sel_str);
|
||||
goto error;
|
||||
}
|
||||
|
||||
|
||||
add_entity_use(&c->info, selector, entity);
|
||||
|
||||
operand->type = entity->type;
|
||||
operand->expr = node;
|
||||
switch (entity->kind) {
|
||||
case Entity_Constant:
|
||||
operand->mode = Addressing_Constant;
|
||||
operand->value = entity->Constant.value;
|
||||
break;
|
||||
case Entity_Variable:
|
||||
operand->mode = Addressing_Variable;
|
||||
break;
|
||||
case Entity_TypeName:
|
||||
operand->mode = Addressing_Type;
|
||||
break;
|
||||
case Entity_Procedure:
|
||||
operand->mode = Addressing_Value;
|
||||
break;
|
||||
case Entity_Builtin:
|
||||
operand->mode = Addressing_Builtin;
|
||||
operand->builtin_id = entity->Builtin.id;
|
||||
break;
|
||||
}
|
||||
|
||||
return entity;
|
||||
|
||||
error:
|
||||
operand->mode = Addressing_Invalid;
|
||||
operand->expr = node;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -3202,7 +3252,6 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint
|
||||
|
||||
|
||||
case_ast_node(se, SelectorExpr, node);
|
||||
check_expr_base(c, o, se->expr);
|
||||
check_selector(c, o, node);
|
||||
case_end;
|
||||
|
||||
|
||||
+40
-10
@@ -171,7 +171,7 @@ Type *check_assignment_variable(Checker *c, Operand *op_a, AstNode *lhs) {
|
||||
b32 used = false;
|
||||
if (node->kind == AstNode_Ident) {
|
||||
ast_node(i, Ident, node);
|
||||
e = scope_lookup_entity(c, c->context.scope, i->string);
|
||||
e = scope_lookup_entity(c->context.scope, i->string);
|
||||
if (e != NULL && e->kind == Entity_Variable) {
|
||||
used = e->Variable.used; // TODO(bill): Make backup just in case
|
||||
}
|
||||
@@ -374,9 +374,8 @@ void check_type_decl(Checker *c, Entity *e, AstNode *type_expr, Type *def, Cycle
|
||||
gb_array_free(local_cycle_checker.path);
|
||||
});
|
||||
|
||||
check_type(c, type_expr, named, cycle_checker_add(cycle_checker, e));
|
||||
|
||||
|
||||
Type *base_type = check_type(c, type_expr, named, cycle_checker_add(cycle_checker, e));
|
||||
named->Named.base = base_type;
|
||||
named->Named.base = get_base_type(named->Named.base);
|
||||
if (named->Named.base == t_invalid) {
|
||||
// gb_printf("check_type_decl: %s\n", type_to_string(named));
|
||||
@@ -562,22 +561,41 @@ void check_var_decl(Checker *c, Entity *e, Entity **entities, isize entity_count
|
||||
|
||||
|
||||
void check_entity_decl(Checker *c, Entity *e, DeclInfo *d, Type *named_type, CycleChecker *cycle_checker) {
|
||||
if (e->type != NULL)
|
||||
return;
|
||||
if (e->type != NULL) {
|
||||
if (e->type->kind == Type_Named && e->type->Named.base == NULL) {
|
||||
// NOTE(bill): Some weird declaration error from Entity_ImportName
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (d == NULL) {
|
||||
DeclInfo **found = map_get(&c->info.entities, hash_pointer(e));
|
||||
if (found) {
|
||||
d = *found;
|
||||
} else {
|
||||
GB_PANIC("`%.*s` should been declared!", LIT(e->token.string));
|
||||
}
|
||||
}
|
||||
|
||||
switch (e->kind) {
|
||||
case Entity_Constant: {
|
||||
Scope *prev = c->context.scope;
|
||||
c->context.scope = d->scope;
|
||||
defer (c->context.scope = prev);
|
||||
c->context.decl = d;
|
||||
|
||||
check_const_decl(c, e, d->type_expr, d->init_expr);
|
||||
|
||||
c->context.scope = prev;
|
||||
} break;
|
||||
case Entity_Variable: {
|
||||
Scope *prev = c->context.scope;
|
||||
c->context.scope = d->scope;
|
||||
defer (c->context.scope = prev);
|
||||
c->context.decl = d;
|
||||
|
||||
check_var_decl(c, e, d->entities, d->entity_count, d->type_expr, d->init_expr);
|
||||
|
||||
c->context.scope = prev;
|
||||
} break;
|
||||
case Entity_TypeName: {
|
||||
CycleChecker local_cycle_checker = {};
|
||||
@@ -1234,7 +1252,7 @@ void check_stmt(Checker *c, AstNode *node, u32 flags) {
|
||||
AstNode *expr = unparen_expr(es->expr);
|
||||
if (expr->kind == AstNode_Ident) {
|
||||
String name = expr->Ident.string;
|
||||
e = scope_lookup_entity(c, c->context.scope, name);
|
||||
e = scope_lookup_entity(c->context.scope, name);
|
||||
} else if (expr->kind == AstNode_SelectorExpr) {
|
||||
Operand o = {};
|
||||
check_expr_base(c, &o, expr->SelectorExpr.expr);
|
||||
@@ -1285,6 +1303,18 @@ void check_stmt(Checker *c, AstNode *node, u32 flags) {
|
||||
}
|
||||
} break;
|
||||
|
||||
case Entity_ImportName: {
|
||||
Scope *scope = e->ImportName.scope;
|
||||
gb_for_array(i, scope->elements.entries) {
|
||||
Entity *decl = scope->elements.entries[i].value;
|
||||
Entity *found = scope_insert_entity(c->context.scope, decl);
|
||||
if (found != NULL) {
|
||||
error(&c->error_collector, us->token, "Namespace collision while `using` `%s` of: %.*s", expr_str, LIT(found->token.string));
|
||||
return;
|
||||
}
|
||||
}
|
||||
} break;
|
||||
|
||||
case Entity_Constant:
|
||||
error(&c->error_collector, us->token, "`using` cannot be applied to a constant");
|
||||
break;
|
||||
@@ -1334,7 +1364,7 @@ void check_stmt(Checker *c, AstNode *node, u32 flags) {
|
||||
AstNode *item = vd->names[name_index];
|
||||
ast_node(i, Ident, item);
|
||||
String name = i->string;
|
||||
Entity *e = scope_lookup_entity(c, c->context.scope, name);
|
||||
Entity *e = scope_lookup_entity(c->context.scope, name);
|
||||
Type *t = get_base_type(type_deref(e->type));
|
||||
if (is_type_struct(t) || is_type_raw_union(t)) {
|
||||
Scope **found = map_get(&c->info.scopes, hash_pointer(t->Record.node));
|
||||
|
||||
Reference in New Issue
Block a user