Browse Source

`using in` importation statements

gingerBill 7 years ago
parent
commit
0d665c637f
2 changed files with 109 additions and 32 deletions
  1. 88 32
      src/checker.cpp
  2. 21 0
      src/parser.cpp

+ 88 - 32
src/checker.cpp

@@ -2642,21 +2642,24 @@ 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)) {
-		if (id->is_using) {
-			// TODO(bill): Should this be a warning?
+
+	if (id->using_in_list.count == 0) {
+		String import_name = path_to_entity_name(id->import_name.string, id->fullpath);
+		if (is_blank_ident(import_name)) {
+			if (id->is_using) {
+				// TODO(bill): Should this be a warning?
+			} else {
+				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 {
 		} else {
-			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);
+			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);
+			add_entity(c, parent_scope, nullptr, e);
+		}
 	}
 	}
 
 
 	if (id->is_using) {
 	if (id->is_using) {
@@ -2664,21 +2667,48 @@ void check_add_import_decl(Checker *c, AstNodeImportDecl *id) {
 			error(id->import_name, "#shared_global_scope imports cannot use using");
 			error(id->import_name, "#shared_global_scope imports cannot use using");
 			return;
 			return;
 		}
 		}
-		// NOTE(bill): Add imported entities to this file's scope
-		for_array(elem_index, scope->elements.entries) {
-			Entity *e = scope->elements.entries[elem_index].value;
-			if (e->scope == parent_scope) continue;
 
 
-			if (e->token.string == "get_proc_address") {
-				// gb_printf_err("%.*s %.*s get_proc_address\n", LIT(scope->file->fullpath), LIT(parent_scope->file->fullpath));
+		// NOTE(bill): Add imported entities to this file's scope
+		if (id->using_in_list.count > 0) {
+			for_array(list_index, id->using_in_list) {
+				AstNode *node = id->using_in_list[list_index];
+				ast_node(ident, Ident, node);
+				String name = ident->token.string;
+
+				Entity *e = scope_lookup_entity(scope, name);
+				if (e == nullptr) {
+					if (is_blank_ident(name)) {
+						error(node, "'_' cannot be used as a value");
+					} else {
+						error(node, "Undeclared name in this importation: '%.*s'", LIT(name));
+					}
+					continue;
+				}
+				if (e->scope == parent_scope) continue;
+
+				bool implicit_is_found = ptr_set_exists(&scope->implicit, e);
+				if (is_entity_exported(e) && !implicit_is_found) {
+					Entity *prev = scope_lookup_entity(parent_scope, e->token.string);
+					// if (prev) gb_printf_err("%.*s\n", LIT(prev->token.string));
+					bool ok = add_entity(c, parent_scope, e->identifier, e);
+					if (ok) ptr_set_add(&parent_scope->implicit, e);
+				} else {
+					error(node, "'%.*s' is exported from this scope", LIT(name));
+					continue;
+				}
 			}
 			}
-
-			bool implicit_is_found = ptr_set_exists(&scope->implicit, e);
-			if (is_entity_exported(e) && !implicit_is_found) {
-				Entity *prev = scope_lookup_entity(parent_scope, e->token.string);
-				// if (prev) gb_printf_err("%.*s\n", LIT(prev->token.string));
-				bool ok = add_entity(c, parent_scope, e->identifier, e);
-				if (ok) ptr_set_add(&parent_scope->implicit, e);
+		} else {
+			for_array(elem_index, scope->elements.entries) {
+				Entity *e = scope->elements.entries[elem_index].value;
+				if (e->scope == parent_scope) continue;
+
+				bool implicit_is_found = ptr_set_exists(&scope->implicit, e);
+				if (is_entity_exported(e) && !implicit_is_found) {
+					Entity *prev = scope_lookup_entity(parent_scope, e->token.string);
+					// if (prev) gb_printf_err("%.*s\n", LIT(prev->token.string));
+					bool ok = add_entity(c, parent_scope, e->identifier, e);
+					if (ok) ptr_set_add(&parent_scope->implicit, e);
+				}
 			}
 			}
 		}
 		}
 	}
 	}
@@ -2722,13 +2752,39 @@ void check_add_export_decl(Checker *c, AstNodeExportDecl *ed) {
 		ptr_set_add(&parent_scope->imported, scope);
 		ptr_set_add(&parent_scope->imported, scope);
 	}
 	}
 
 
-	// NOTE(bill): Add imported entities to this file's scope
-	for_array(elem_index, scope->elements.entries) {
-		Entity *e = scope->elements.entries[elem_index].value;
-		if (e->scope == parent_scope) continue;
+	if (ed->using_in_list.count > 0) {
+		for_array(list_index, ed->using_in_list) {
+			AstNode *node = ed->using_in_list[list_index];
+			ast_node(ident, Ident, node);
+			String name = ident->token.string;
+
+			Entity *e = scope_lookup_entity(scope, name);
+			if (e == nullptr) {
+				if (is_blank_ident(name)) {
+					error(node, "'_' cannot be used as a value");
+				} else {
+					error(node, "Undeclared name in this importation: '%.*s'", LIT(name));
+				}
+				continue;
+			}
+			if (e->scope == parent_scope) continue;
 
 
-		if (is_entity_kind_exported(e->kind)) {
-			add_entity(c, parent_scope, e->identifier, e);
+			if (is_entity_exported(e)) {
+				add_entity(c, parent_scope, e->identifier, e);
+			} else {
+				error(node, "'%.*s' is exported from this scope", LIT(name));
+				continue;
+			}
+		}
+	} else {
+		// NOTE(bill): Add imported entities to this file's scope
+		for_array(elem_index, scope->elements.entries) {
+			Entity *e = scope->elements.entries[elem_index].value;
+			if (e->scope == parent_scope) continue;
+
+			if (is_entity_kind_exported(e->kind)) {
+				add_entity(c, parent_scope, e->identifier, e);
+			}
 		}
 		}
 	}
 	}
 
 

+ 21 - 0
src/parser.cpp

@@ -362,6 +362,7 @@ AST_NODE_KIND(_DeclBegin,      "", i32) \
 		Token    import_name;   \
 		Token    import_name;   \
 		bool     is_using;      \
 		bool     is_using;      \
 		bool     been_handled;  \
 		bool     been_handled;  \
+		Array<AstNode *> using_in_list; \
 		CommentGroup docs;      \
 		CommentGroup docs;      \
 		CommentGroup comment;   \
 		CommentGroup comment;   \
 	}) \
 	}) \
@@ -371,6 +372,7 @@ AST_NODE_KIND(_DeclBegin,      "", i32) \
 		Token    relpath;       \
 		Token    relpath;       \
 		String   fullpath;      \
 		String   fullpath;      \
 		bool     been_handled;  \
 		bool     been_handled;  \
+		Array<AstNode *> using_in_list; \
 		CommentGroup docs;      \
 		CommentGroup docs;      \
 		CommentGroup comment;   \
 		CommentGroup comment;   \
 	}) \
 	}) \
@@ -4518,6 +4520,25 @@ AstNode *parse_stmt(AstFile *f) {
 			return ast_bad_stmt(f, token, f->curr_token);
 			return ast_bad_stmt(f, token, f->curr_token);
 		}
 		}
 
 
+		if (f->curr_token.kind == Token_in) {
+			Token in_token = expect_token(f, Token_in);
+			if (f->curr_token.kind == Token_import) {
+				AstNode *import_decl = parse_import_decl(f, true);
+				if (import_decl->kind == AstNode_ImportDecl) {
+					import_decl->ImportDecl.using_in_list = list;
+				}
+				return import_decl;
+			} else if (f->curr_token.kind == Token_export) {
+				AstNode *export_decl = parse_export_decl(f);
+				if (export_decl->kind == AstNode_ExportDecl) {
+					export_decl->ExportDecl.using_in_list = list;
+				}
+				return export_decl;
+			}
+			syntax_error(token, "Illegal use of 'using' statement");
+			return ast_bad_stmt(f, token, f->curr_token);
+		}
+
 		if (f->curr_token.kind != Token_Colon) {
 		if (f->curr_token.kind != Token_Colon) {
 			expect_semicolon(f, list[list.count-1]);
 			expect_semicolon(f, list[list.count-1]);
 			return ast_using_stmt(f, token, list);
 			return ast_using_stmt(f, token, list);