Browse Source

Add `@force` to `foreign import`

gingerBill 5 years ago
parent
commit
3b898e5224
7 changed files with 44 additions and 1 deletions
  1. 1 0
      core/odin/ast/ast.odin
  2. 3 0
      core/odin/parser/parser.odin
  3. 26 0
      src/checker.cpp
  4. 3 0
      src/checker.hpp
  5. 5 0
      src/ir.cpp
  6. 5 1
      src/parser.cpp
  7. 1 0
      src/parser.hpp

+ 1 - 0
core/odin/ast/ast.odin

@@ -410,6 +410,7 @@ Foreign_Import_Decl :: struct {
 	name:            ^Ident,
 	collection_name: string,
 	fullpaths:       []string,
+	attributes:      [dynamic]^Attribute, // dynamic as parsing will add to them lazily
 	comment:         ^Comment_Group,
 }
 

+ 3 - 0
core/odin/parser/parser.odin

@@ -827,6 +827,9 @@ parse_attribute :: proc(p: ^Parser, tok: tokenizer.Token, open_kind, close_kind:
 	case ast.Foreign_Block_Decl:
 		if d.docs == nil do d.docs = docs;
 		append(&d.attributes, attribute);
+	case ast.Foreign_Import_Decl:
+		if d.docs == nil do d.docs = docs;
+		append(&d.attributes, attribute);
 	case:
 		error(p, decl.pos, "expected a value or foreign declaration after an attribute");
 		free(attribute);

+ 26 - 0
src/checker.cpp

@@ -803,6 +803,7 @@ void init_checker_info(CheckerInfo *i) {
 	map_init(&i->files,           a);
 	map_init(&i->packages,        a);
 	array_init(&i->variable_init_order, a);
+	array_init(&i->required_foreign_imports_through_force, a);
 
 	i->allow_identifier_uses = build_context.query_data_set_settings.kind == QueryDataSet_GoToDefinitions;
 	if (i->allow_identifier_uses) {
@@ -823,6 +824,8 @@ void destroy_checker_info(CheckerInfo *i) {
 	map_destroy(&i->packages);
 	array_free(&i->variable_init_order);
 	array_free(&i->identifier_uses);
+	array_free(&i->required_foreign_imports_through_force);
+
 }
 
 CheckerContext make_checker_context(Checker *c) {
@@ -1696,6 +1699,11 @@ void generate_minimum_dependency_set(Checker *c, Entity *start) {
 		}
 	}
 
+	for_array(i, c->info.required_foreign_imports_through_force) {
+		Entity *e = c->info.required_foreign_imports_through_force[i];
+		add_dependency_to_set(c, e);
+	}
+
 	add_dependency_to_set(c, start);
 }
 
@@ -3172,6 +3180,16 @@ void check_add_import_decl(CheckerContext *ctx, Ast *decl) {
 	scope->flags |= ScopeFlag_HasBeenImported;
 }
 
+DECL_ATTRIBUTE_PROC(foreign_import_decl_attribute) {
+	if (name == "force") {
+		if (value != nullptr) {
+			error(elem, "Expected no parameter for '%.*s'", LIT(name));
+		}
+		ac->force_foreign_import = true;
+		return true;
+	}
+	return false;
+}
 
 void check_add_foreign_import_decl(CheckerContext *ctx, Ast *decl) {
 	if (decl->been_handled) return;
@@ -3216,6 +3234,14 @@ void check_add_foreign_import_decl(CheckerContext *ctx, Ast *decl) {
 	Entity *e = alloc_entity_library_name(parent_scope, fl->library_name, t_invalid,
 	                                      fl->fullpaths, library_name);
 	add_entity(ctx->checker, parent_scope, nullptr, e);
+
+
+	AttributeContext ac = {};
+	check_decl_attributes(ctx, fl->attributes, foreign_import_decl_attribute, &ac);
+	if (ac.force_foreign_import) {
+		array_add(&ctx->info->required_foreign_imports_through_force, e);
+		add_entity_use(ctx, nullptr, e);
+	}
 }
 
 bool collect_checked_packages_from_decl_list(Checker *c, Array<Ast *> const &decls) {

+ 3 - 0
src/checker.hpp

@@ -98,6 +98,7 @@ struct AttributeContext {
 	bool    is_export;
 	bool    is_static;
 	bool    require_results;
+	bool    force_foreign_import;
 	String  link_name;
 	String  link_prefix;
 	isize   init_expr_list_count;
@@ -249,6 +250,8 @@ struct CheckerInfo {
 	PtrSet<Entity *>      minimum_dependency_set;
 	PtrSet<isize>         minimum_dependency_type_info_set;
 
+	Array<Entity *>       required_foreign_imports_through_force;
+
 
 	bool allow_identifier_uses;
 	Array<Ast *> identifier_uses; // only used by 'odin query'

+ 5 - 0
src/ir.cpp

@@ -11335,6 +11335,11 @@ void ir_gen_tree(irGen *s) {
 		}
 	}
 
+	for_array(i, m->info->required_foreign_imports_through_force) {
+		Entity *e = m->info->required_foreign_imports_through_force[i];
+		ir_add_foreign_library_path(m, e);
+	}
+
 #endif
 	{ // Startup Runtime
 		// Cleanup(bill): probably better way of doing code insertion

+ 5 - 1
src/parser.cpp

@@ -1049,6 +1049,8 @@ Ast *ast_foreign_import_decl(AstFile *f, Token token, Array<Token> filepaths, To
 	result->ForeignImportDecl.library_name = library_name;
 	result->ForeignImportDecl.docs         = docs;
 	result->ForeignImportDecl.comment      = comment;
+	result->ForeignImportDecl.attributes.allocator = heap_allocator();
+
 	return result;
 }
 
@@ -3865,7 +3867,9 @@ Ast *parse_attribute(AstFile *f, Token token, TokenKind open_kind, TokenKind clo
 		array_add(&decl->ValueDecl.attributes, attribute);
 	} else if (decl->kind == Ast_ForeignBlockDecl) {
 		array_add(&decl->ForeignBlockDecl.attributes, attribute);
-	} else {
+	} else if (decl->kind == Ast_ForeignImportDecl) {
+		array_add(&decl->ForeignImportDecl.attributes, attribute);
+	}else {
 		syntax_error(decl, "Expected a value or foreign declaration after an attribute, got %.*s", LIT(ast_strings[decl->kind]));
 		return ast_bad_stmt(f, token, f->curr_token);
 	}

+ 1 - 0
src/parser.hpp

@@ -426,6 +426,7 @@ AST_KIND(_DeclBegin,      "", bool) \
 		Token    library_name;    \
 		String   collection_name; \
 		Array<String> fullpaths;  \
+		Array<Ast *> attributes;  \
 		CommentGroup *docs;       \
 		CommentGroup *comment;    \
 	}) \