Browse Source

Allow for cyclic `import` but disallow cyclic `using import` and `export`

Ginger Bill 7 years ago
parent
commit
df7a4eda8a
1 changed files with 49 additions and 36 deletions
  1. 49 36
      src/checker.cpp

+ 49 - 36
src/checker.cpp

@@ -228,8 +228,8 @@ struct Scope {
 
 
 	Array<Scope *>   shared;
 	Array<Scope *>   shared;
 	Array<AstNode *> delayed_file_decls;
 	Array<AstNode *> delayed_file_decls;
-	PtrSet<Scope *>  import_succ;
 	PtrSet<Scope *>  imported;
 	PtrSet<Scope *>  imported;
+	PtrSet<Scope *>  exported; // NOTE(bhall): Contains `using import` too
 	bool             is_proc;
 	bool             is_proc;
 	bool             is_global;
 	bool             is_global;
 	bool             is_file;
 	bool             is_file;
@@ -248,7 +248,6 @@ void scope_reset(Scope *scope) {
 	map_clear  (&scope->elements);
 	map_clear  (&scope->elements);
 	map_clear  (&scope->implicit);
 	map_clear  (&scope->implicit);
 	array_clear(&scope->shared);
 	array_clear(&scope->shared);
-	ptr_set_clear(&scope->import_succ);
 	ptr_set_clear(&scope->imported);
 	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 xg = x->scope->is_global;
 	bool yg = y->scope->is_global;
 	bool yg = y->scope->is_global;
 	if (xg != yg) return xg ? -1 : +1;
 	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;
 	if (x->dep_count > y->dep_count) return +1;
 	if (x->dep_count > y->dep_count) return +1;
 	return 0;
 	return 0;
@@ -564,11 +564,11 @@ bool decl_info_has_init(DeclInfo *d) {
 Scope *create_scope(Scope *parent, gbAllocator allocator) {
 Scope *create_scope(Scope *parent, gbAllocator allocator) {
 	Scope *s = gb_alloc_item(allocator, Scope);
 	Scope *s = gb_alloc_item(allocator, Scope);
 	s->parent = parent;
 	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->imported, heap_allocator());
-	ptr_set_init(&s->import_succ, heap_allocator());
+	ptr_set_init(&s->exported, heap_allocator());
 
 
 	if (parent != nullptr && parent != universal_scope) {
 	if (parent != nullptr && parent != universal_scope) {
 		DLIST_APPEND(parent->first_child, parent->last_child, s);
 		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->shared);
 	array_free(&scope->delayed_file_decls);
 	array_free(&scope->delayed_file_decls);
 	ptr_set_destroy(&scope->imported);
 	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)
 	// 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;
 		n = *found_node;
 
 
 		// TODO(bill): How should the edges be attched for `import`?
 		// 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(&n->succ, m);
 		import_graph_node_set_add(&m->pred, n);
 		import_graph_node_set_add(&m->pred, n);
 		ptr_set_add(&m->scope->imported, n->scope);
 		ptr_set_add(&m->scope->imported, n->scope);
+		if (id->is_using) {
+			ptr_set_add(&m->scope->exported, n->scope);
+		}
 	case_end;
 	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(&n->succ, m);
 		import_graph_node_set_add(&m->pred, n);
 		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_end;
 
 
 	case_ast_node(ws, WhenStmt, decl);
 	case_ast_node(ws, WhenStmt, decl);
@@ -2413,7 +2413,6 @@ Array<ImportGraphNode *> generate_import_dependency_graph(Checker *c) {
 	return G;
 	return G;
 }
 }
 
 
-
 Array<Scope *> find_import_path(Map<Scope *> *file_scopes, Scope *start, Scope *end, PtrSet<Scope *> *visited = nullptr) {
 Array<Scope *> find_import_path(Map<Scope *> *file_scopes, Scope *start, Scope *end, PtrSet<Scope *> *visited = nullptr) {
 	PtrSet<Scope *> visited_ = {};
 	PtrSet<Scope *> visited_ = {};
 	bool made_visited = false;
 	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);
 	Scope **found = map_get(file_scopes, key);
 	if (found) {
 	if (found) {
 		Scope *scope = *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) {
 			if (dep == end) {
 				Array<Scope *> path = {};
 				Array<Scope *> path = {};
 				array_init(&path, heap_allocator());
 				array_init(&path, heap_allocator());
@@ -2452,6 +2451,17 @@ Array<Scope *> find_import_path(Map<Scope *> *file_scopes, Scope *start, Scope *
 				return next_path;
 				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;
 	return empty_path;
 }
 }
@@ -2487,6 +2497,19 @@ void check_add_import_decl(Checker *c, AstNodeImportDecl *id) {
 		ptr_set_add(&parent_scope->imported, scope);
 		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 (id->is_using) {
 		if (parent_scope->is_global) {
 		if (parent_scope->is_global) {
 			error(id->import_name, "#shared_global_scope imports cannot use using");
 			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);
 				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);
 	ptr_set_add(&c->checked_files, scope->file);
 	scope->has_been_imported = true;
 	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);
 			auto path = find_import_path(&c->file_scopes, s, s);
 			defer (array_free(&path));
 			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];
 				Scope *s = path[path.count-1];
 				Token token = mt(s);
 				Token token = mt(s);
 				error(token, "Cyclic importation of `%.*s`", LIT(token.string));
 				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) {
 	// for_array(file_index, c->file_order) {
 	// 	ImportGraphNode *node = c->file_order[file_index];
 	// 	ImportGraphNode *node = c->file_order[file_index];
 	// 	AstFile *f = node->scope->file;
 	// 	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 (;;) {
 	for (;;) {