Allow for cyclic import but disallow cyclic using import and export

This commit is contained in:
Ginger Bill
2017-10-07 11:37:43 +01:00
parent 91cc0b282a
commit df7a4eda8a
+49 -36
View File
@@ -228,8 +228,8 @@ struct Scope {
Array<Scope *> shared;
Array<AstNode *> delayed_file_decls;
PtrSet<Scope *> import_succ;
PtrSet<Scope *> imported;
PtrSet<Scope *> exported; // NOTE(bhall): Contains `using import` too
bool is_proc;
bool is_global;
bool is_file;
@@ -248,7 +248,6 @@ void scope_reset(Scope *scope) {
map_clear (&scope->elements);
map_clear (&scope->implicit);
array_clear(&scope->shared);
ptr_set_clear(&scope->import_succ);
ptr_set_clear(&scope->imported);
}
@@ -387,6 +386,7 @@ int import_graph_node_cmp(ImportGraphNode **data, isize i, isize j) {
bool xg = x->scope->is_global;
bool yg = y->scope->is_global;
if (xg != yg) return xg ? -1 : +1;
if (xg && yg) return x->file_id < y->file_id ? -1 : +1;
if (x->dep_count < y->dep_count) return -1;
if (x->dep_count > y->dep_count) return +1;
return 0;
@@ -564,11 +564,11 @@ bool decl_info_has_init(DeclInfo *d) {
Scope *create_scope(Scope *parent, gbAllocator allocator) {
Scope *s = gb_alloc_item(allocator, Scope);
s->parent = parent;
map_init(&s->elements, heap_allocator());
map_init(&s->implicit, heap_allocator());
array_init(&s->shared, heap_allocator());
map_init(&s->elements, heap_allocator());
map_init(&s->implicit, heap_allocator());
array_init(&s->shared, heap_allocator());
ptr_set_init(&s->imported, heap_allocator());
ptr_set_init(&s->import_succ, heap_allocator());
ptr_set_init(&s->exported, heap_allocator());
if (parent != nullptr && parent != universal_scope) {
DLIST_APPEND(parent->first_child, parent->last_child, s);
@@ -625,7 +625,6 @@ void destroy_scope(Scope *scope) {
array_free(&scope->shared);
array_free(&scope->delayed_file_decls);
ptr_set_destroy(&scope->imported);
ptr_set_destroy(&scope->import_succ);
// NOTE(bill): No need to free scope as it "should" be allocated in an arena (except for the global scope)
}
@@ -2305,11 +2304,12 @@ void add_import_dependency_node(Checker *c, AstNode *decl, Map<ImportGraphNode *
n = *found_node;
// TODO(bill): How should the edges be attched for `import`?
if (id->is_using) {
}
import_graph_node_set_add(&n->succ, m);
import_graph_node_set_add(&m->pred, n);
ptr_set_add(&m->scope->imported, n->scope);
if (id->is_using) {
ptr_set_add(&m->scope->exported, n->scope);
}
case_end;
@@ -2343,7 +2343,7 @@ void add_import_dependency_node(Checker *c, AstNode *decl, Map<ImportGraphNode *
import_graph_node_set_add(&n->succ, m);
import_graph_node_set_add(&m->pred, n);
ptr_set_add(&m->scope->imported, n->scope);
ptr_set_add(&m->scope->exported, n->scope);
case_end;
case_ast_node(ws, WhenStmt, decl);
@@ -2413,7 +2413,6 @@ Array<ImportGraphNode *> generate_import_dependency_graph(Checker *c) {
return G;
}
Array<Scope *> find_import_path(Map<Scope *> *file_scopes, Scope *start, Scope *end, PtrSet<Scope *> *visited = nullptr) {
PtrSet<Scope *> visited_ = {};
bool made_visited = false;
@@ -2438,8 +2437,8 @@ Array<Scope *> find_import_path(Map<Scope *> *file_scopes, Scope *start, Scope *
Scope **found = map_get(file_scopes, key);
if (found) {
Scope *scope = *found;
for_array(i, scope->imported.entries) {
Scope *dep = scope->imported.entries[i].ptr;
for_array(i, scope->exported.entries) {
Scope *dep = scope->exported.entries[i].ptr;
if (dep == end) {
Array<Scope *> path = {};
array_init(&path, heap_allocator());
@@ -2452,6 +2451,17 @@ Array<Scope *> find_import_path(Map<Scope *> *file_scopes, Scope *start, Scope *
return next_path;
}
}
// NOTE(bill): Disallow importing of the same file
for_array(i, scope->imported.entries) {
Scope *dep = scope->imported.entries[i].ptr;
if (dep == start) {
Array<Scope *> path = {};
array_init(&path, heap_allocator());
array_add(&path, dep);
return path;
}
}
}
return empty_path;
}
@@ -2487,6 +2497,19 @@ void check_add_import_decl(Checker *c, AstNodeImportDecl *id) {
ptr_set_add(&parent_scope->imported, scope);
}
String import_name = path_to_entity_name(id->import_name.string, id->fullpath);
if (is_blank_ident(import_name)) {
error(token, "File name, %.*s, cannot be use as an import name as it is not a valid identifier", LIT(id->import_name.string));
} else {
GB_ASSERT(id->import_name.pos.line != 0);
id->import_name.string = import_name;
Entity *e = make_entity_import_name(c->allocator, parent_scope, id->import_name, t_invalid,
id->fullpath, id->import_name.string,
scope);
add_entity(c, parent_scope, nullptr, e);
}
if (id->is_using) {
if (parent_scope->is_global) {
error(id->import_name, "#shared_global_scope imports cannot use using");
@@ -2506,19 +2529,6 @@ void check_add_import_decl(Checker *c, AstNodeImportDecl *id) {
if (ok) map_set(&parent_scope->implicit, hash_entity(e), true);
}
}
} else {
String import_name = path_to_entity_name(id->import_name.string, id->fullpath);
if (is_blank_ident(import_name)) {
error(token, "File name, %.*s, cannot be use as an import name as it is not a valid identifier", LIT(id->import_name.string));
} else {
GB_ASSERT(id->import_name.pos.line != 0);
id->import_name.string = import_name;
Entity *e = make_entity_import_name(c->allocator, parent_scope, id->import_name, t_invalid,
id->fullpath, id->import_name.string,
scope);
add_entity(c, parent_scope, nullptr, e);
}
}
ptr_set_add(&c->checked_files, scope->file);
scope->has_been_imported = true;
@@ -2832,16 +2842,19 @@ void check_import_entities(Checker *c) {
auto path = find_import_path(&c->file_scopes, s, s);
defer (array_free(&path));
if (path.count > 0) {
// TODO(bill): This needs better TokenPos finding
auto const mt = [](Scope *s) -> Token {
Token token = {};
token.pos = token_pos(s->file->tokenizer.fullpath, 1, 1);
token.string = remove_directory_from_path(s->file->tokenizer.fullpath);
return token;
};
// TODO(bill): This needs better TokenPos finding
auto const mt = [](Scope *s) -> Token {
Token token = {};
token.pos = token_pos(s->file->tokenizer.fullpath, 1, 1);
token.string = remove_directory_from_path(s->file->tokenizer.fullpath);
return token;
};
if (path.count == 1) {
Scope *s = path[0];
Token token = mt(s);
error(token, "Self importation of `%.*s`", LIT(token.string));
} else if (path.count > 0) {
Scope *s = path[path.count-1];
Token token = mt(s);
error(token, "Cyclic importation of `%.*s`", LIT(token.string));
@@ -2884,7 +2897,7 @@ void check_import_entities(Checker *c) {
// for_array(file_index, c->file_order) {
// ImportGraphNode *node = c->file_order[file_index];
// AstFile *f = node->scope->file;
// gb_printf_err("--- %.*s\n", LIT(f->fullpath));
// gb_printf_err("--- %.*s -> %td\n", LIT(f->fullpath), node->succ.entries.count);
// }
for (;;) {