diff options
| author | Ginger Bill <bill@gingerbill.org> | 2017-10-07 11:37:43 +0100 |
|---|---|---|
| committer | Ginger Bill <bill@gingerbill.org> | 2017-10-07 11:37:43 +0100 |
| commit | df7a4eda8aaeb134e10a507b21c31637c84781e1 (patch) | |
| tree | 264b33f3d2821d78c3cdf0dc0fd9f634de27fc06 /src/checker.cpp | |
| parent | 91cc0b282a7dec026e8608dd16b109470ab1a60b (diff) | |
Allow for cyclic `import` but disallow cyclic `using import` and `export`
Diffstat (limited to 'src/checker.cpp')
| -rw-r--r-- | src/checker.cpp | 85 |
1 files changed, 49 insertions, 36 deletions
diff --git a/src/checker.cpp b/src/checker.cpp index eeac82b6e..82124cd90 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -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 (;;) { |