aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorgingerBill <bill@gingerbill.org>2019-11-01 19:26:22 +0000
committergingerBill <bill@gingerbill.org>2019-11-01 19:26:22 +0000
commit3b898e5224872a507bd4a8e8be75c80643943d2a (patch)
treecb07b7ad1945061de9e900d9957b0aec7147a6cb
parent44a303e5778fb8564964d53523634f34f8589489 (diff)
Add `@force` to `foreign import`
-rw-r--r--core/odin/ast/ast.odin1
-rw-r--r--core/odin/parser/parser.odin3
-rw-r--r--src/checker.cpp26
-rw-r--r--src/checker.hpp3
-rw-r--r--src/ir.cpp5
-rw-r--r--src/parser.cpp6
-rw-r--r--src/parser.hpp1
7 files changed, 44 insertions, 1 deletions
diff --git a/core/odin/ast/ast.odin b/core/odin/ast/ast.odin
index 309d2c147..52845ea4e 100644
--- a/core/odin/ast/ast.odin
+++ b/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,
}
diff --git a/core/odin/parser/parser.odin b/core/odin/parser/parser.odin
index fb3a87e8b..7da4a0b44 100644
--- a/core/odin/parser/parser.odin
+++ b/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);
diff --git a/src/checker.cpp b/src/checker.cpp
index e7b347f1a..4490caa69 100644
--- a/src/checker.cpp
+++ b/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) {
diff --git a/src/checker.hpp b/src/checker.hpp
index c33514511..c5d6f71cd 100644
--- a/src/checker.hpp
+++ b/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'
diff --git a/src/ir.cpp b/src/ir.cpp
index e7317a960..8d5587341 100644
--- a/src/ir.cpp
+++ b/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
diff --git a/src/parser.cpp b/src/parser.cpp
index 10aa10119..cb04ca1f5 100644
--- a/src/parser.cpp
+++ b/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);
}
diff --git a/src/parser.hpp b/src/parser.hpp
index f07f3ce0d..b9e53dbe8 100644
--- a/src/parser.hpp
+++ b/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; \
}) \