mirror of
https://github.com/Ed94/Odin.git
synced 2026-07-25 00:47:55 +00:00
Library names - Only link with used foreign libraries
This commit is contained in:
@@ -319,6 +319,29 @@ void check_proc_lit(Checker *c, Entity *e, DeclInfo *d) {
|
||||
name = pd->foreign_name;
|
||||
}
|
||||
|
||||
AstNode *foreign_library = d->proc_lit->ProcLit.foreign_library;
|
||||
if (foreign_library == NULL) {
|
||||
error(e->token, "#foreign procedures must declare which library they are from");
|
||||
} else if (foreign_library->kind != AstNode_Ident) {
|
||||
error_node(foreign_library, "#foreign library names must be an identifier");
|
||||
} else {
|
||||
String name = foreign_library->Ident.string;
|
||||
Entity *found = scope_lookup_entity(c->context.scope, name);
|
||||
if (found == NULL) {
|
||||
if (str_eq(name, str_lit("_"))) {
|
||||
error_node(foreign_library, "`_` cannot be used as a value type");
|
||||
} else {
|
||||
error_node(foreign_library, "Undeclared name: %.*s", LIT(name));
|
||||
}
|
||||
} else if (found->kind != Entity_LibraryName) {
|
||||
error_node(foreign_library, "`_` cannot be used as a library name");
|
||||
} else {
|
||||
// TODO(bill): Extra stuff to do with library names?
|
||||
e->Procedure.foreign_library = found;
|
||||
add_entity_use(c, foreign_library, found);
|
||||
}
|
||||
}
|
||||
|
||||
e->Procedure.is_foreign = true;
|
||||
e->Procedure.foreign_name = name;
|
||||
|
||||
|
||||
@@ -985,6 +985,9 @@ void check_identifier(Checker *c, Operand *o, AstNode *n, Type *named_type, Type
|
||||
case Entity_ImportName:
|
||||
error_node(n, "Use of import `%.*s` not in selector", LIT(e->ImportName.name));
|
||||
return;
|
||||
case Entity_LibraryName:
|
||||
error_node(n, "Use of library `%.*s` not in #foreign tag", LIT(e->LibraryName.name));
|
||||
return;
|
||||
|
||||
case Entity_Nil:
|
||||
o->mode = Addressing_Value;
|
||||
|
||||
+73
-58
@@ -266,7 +266,6 @@ typedef struct CheckerInfo {
|
||||
MapIsize type_info_map; // Key: Type *
|
||||
isize type_info_count;
|
||||
Entity * implicit_values[ImplicitValue_Count];
|
||||
Array(String) foreign_libraries; // For the linker
|
||||
} CheckerInfo;
|
||||
|
||||
typedef struct Checker {
|
||||
@@ -476,7 +475,9 @@ void scope_lookup_parent_entity(Scope *scope, String name, Scope **scope_, Entit
|
||||
continue;
|
||||
}
|
||||
|
||||
if (e->kind == Entity_ImportName && gone_thru_file) {
|
||||
if ((e->kind == Entity_ImportName ||
|
||||
e->kind == Entity_LibraryName)
|
||||
&& gone_thru_file) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -515,13 +516,14 @@ Entity *scope_insert_entity(Scope *s, Entity *entity) {
|
||||
Entity *prev = NULL;
|
||||
if (found) {
|
||||
prev = *found;
|
||||
if (prev->kind != Entity_Procedure &&
|
||||
if (prev->kind != Entity_Procedure ||
|
||||
entity->kind != Entity_Procedure) {
|
||||
return prev;
|
||||
}
|
||||
}
|
||||
|
||||
if (prev != NULL && entity->kind == Entity_Procedure) {
|
||||
if (prev != NULL &&
|
||||
entity->kind == Entity_Procedure) {
|
||||
if (s->is_global) {
|
||||
return prev;
|
||||
}
|
||||
@@ -605,6 +607,9 @@ void init_universal_scope(BuildContext *bc) {
|
||||
add_global_constant(a, str_lit("false"), t_untyped_bool, make_exact_value_bool(false));
|
||||
|
||||
add_global_entity(make_entity_nil(a, str_lit("nil"), t_untyped_nil));
|
||||
add_global_entity(make_entity_library_name(a, universal_scope,
|
||||
make_token_ident(str_lit("__llvm_core")), t_invalid,
|
||||
str_lit(""), str_lit("__llvm_core")));
|
||||
|
||||
// TODO(bill): Set through flags in the compiler
|
||||
add_global_string_constant(a, str_lit("ODIN_OS"), bc->ODIN_OS);
|
||||
@@ -643,7 +648,6 @@ void init_checker_info(CheckerInfo *i) {
|
||||
map_entity_init(&i->foreign_procs, a);
|
||||
map_isize_init(&i->type_info_map, a);
|
||||
map_ast_file_init(&i->files, a);
|
||||
array_init(&i->foreign_libraries, a);
|
||||
i->type_info_count = 0;
|
||||
|
||||
}
|
||||
@@ -658,7 +662,6 @@ void destroy_checker_info(CheckerInfo *i) {
|
||||
map_entity_destroy(&i->foreign_procs);
|
||||
map_isize_destroy(&i->type_info_map);
|
||||
map_ast_file_destroy(&i->files);
|
||||
array_free(&i->foreign_libraries);
|
||||
}
|
||||
|
||||
|
||||
@@ -843,17 +846,6 @@ void add_entity_and_decl_info(Checker *c, AstNode *identifier, Entity *e, DeclIn
|
||||
map_decl_info_set(&c->info.entities, hash_pointer(e), d);
|
||||
}
|
||||
|
||||
// NOTE(bill): Returns true if it's added
|
||||
bool try_add_foreign_library_path(Checker *c, String import_file) {
|
||||
for_array(i, c->info.foreign_libraries) {
|
||||
String import = c->info.foreign_libraries.e[i];
|
||||
if (str_eq(import, import_file)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
array_add(&c->info.foreign_libraries, import_file);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void add_type_info_type(Checker *c, Type *t) {
|
||||
@@ -1047,6 +1039,9 @@ MapEntity generate_minimum_dependency_map(CheckerInfo *info, Entity *start) {
|
||||
if ((e->Procedure.tags & ProcTag_export) != 0) {
|
||||
add_dependency_to_map(&map, info, e);
|
||||
}
|
||||
if (e->Procedure.is_foreign) {
|
||||
add_dependency_to_map(&map, info, e->Procedure.foreign_library);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1555,6 +1550,43 @@ void check_all_global_entities(Checker *c) {
|
||||
}
|
||||
|
||||
|
||||
String path_to_entity_name(String name, String fullpath) {
|
||||
if (name.len != 0) {
|
||||
return name;
|
||||
}
|
||||
// NOTE(bill): use file name (without extension) as the identifier
|
||||
// If it is a valid identifier
|
||||
String filename = fullpath;
|
||||
isize slash = 0;
|
||||
isize dot = 0;
|
||||
for (isize i = filename.len-1; i >= 0; i--) {
|
||||
u8 c = filename.text[i];
|
||||
if (c == '/' || c == '\\') {
|
||||
break;
|
||||
}
|
||||
slash = i;
|
||||
}
|
||||
|
||||
filename.text += slash;
|
||||
filename.len -= slash;
|
||||
|
||||
dot = filename.len;
|
||||
while (dot --> 0) {
|
||||
u8 c = filename.text[dot];
|
||||
if (c == '.') {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
filename.len = dot;
|
||||
|
||||
if (is_string_an_identifier(filename)) {
|
||||
return filename;
|
||||
} else {
|
||||
return str_lit("_");
|
||||
}
|
||||
}
|
||||
|
||||
void check_import_entities(Checker *c, MapScope *file_scopes) {
|
||||
for_array(i, c->delayed_imports) {
|
||||
Scope *parent_scope = c->delayed_imports.e[i].parent;
|
||||
@@ -1615,49 +1647,23 @@ void check_import_entities(Checker *c, MapScope *file_scopes) {
|
||||
if (e->scope == parent_scope) {
|
||||
continue;
|
||||
}
|
||||
// NOTE(bill): Do not add other imported entities
|
||||
bool ok = add_entity(c, parent_scope, NULL, e);
|
||||
if (ok && id->is_import) { // `#import`ed entities don't get exported
|
||||
map_bool_set(&parent_scope->implicit, hash_pointer(e), true);
|
||||
switch (e->kind) {
|
||||
case Entity_ImportName:
|
||||
case Entity_LibraryName:
|
||||
break;
|
||||
default: {
|
||||
bool ok = add_entity(c, parent_scope, NULL, e);
|
||||
if (ok && id->is_import) { // `#import`ed entities don't get exported
|
||||
map_bool_set(&parent_scope->implicit, hash_pointer(e), true);
|
||||
}
|
||||
} break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
String import_name = id->import_name.string;
|
||||
if (import_name.len == 0) {
|
||||
// NOTE(bill): use file name (without extension) as the identifier
|
||||
// If it is a valid identifier
|
||||
String filename = id->fullpath;
|
||||
isize slash = 0;
|
||||
isize dot = 0;
|
||||
for (isize i = filename.len-1; i >= 0; i--) {
|
||||
u8 c = filename.text[i];
|
||||
if (c == '/' || c == '\\') {
|
||||
break;
|
||||
}
|
||||
slash = i;
|
||||
}
|
||||
|
||||
filename.text += slash;
|
||||
filename.len -= slash;
|
||||
|
||||
dot = filename.len;
|
||||
while (dot --> 0) {
|
||||
u8 c = filename.text[dot];
|
||||
if (c == '.') {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
filename.len = dot;
|
||||
|
||||
if (is_string_an_identifier(filename)) {
|
||||
import_name = filename;
|
||||
} else {
|
||||
error(token, "File name, %.*s, cannot be as an import name as it is not a valid identifier", LIT(filename));
|
||||
}
|
||||
}
|
||||
|
||||
if (import_name.len > 0) {
|
||||
String import_name = path_to_entity_name(id->import_name.string, id->fullpath);
|
||||
if (str_eq(import_name, str_lit("_"))) {
|
||||
error(token, "File name, %.*s, cannot be 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,
|
||||
@@ -1690,7 +1696,16 @@ void check_import_entities(Checker *c, MapScope *file_scopes) {
|
||||
file_str = import_file;
|
||||
}
|
||||
|
||||
try_add_foreign_library_path(c, file_str);
|
||||
String library_name = path_to_entity_name(fl->library_name.string, file_str);
|
||||
if (str_eq(library_name, str_lit("_"))) {
|
||||
error(fl->token, "File name, %.*s, cannot be as a library name as it is not a valid identifier", LIT(fl->library_name.string));
|
||||
} else {
|
||||
GB_ASSERT(fl->library_name.pos.line != 0);
|
||||
fl->library_name.string = library_name;
|
||||
Entity *e = make_entity_library_name(c->allocator, parent_scope, fl->library_name, t_invalid,
|
||||
file_str, library_name);
|
||||
add_entity(c, parent_scope, NULL, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@ typedef enum ImplicitValueId ImplicitValueId;
|
||||
ENTITY_KIND(Procedure) \
|
||||
ENTITY_KIND(Builtin) \
|
||||
ENTITY_KIND(ImportName) \
|
||||
ENTITY_KIND(LibraryName) \
|
||||
ENTITY_KIND(Nil) \
|
||||
ENTITY_KIND(ImplicitValue) \
|
||||
ENTITY_KIND(Count)
|
||||
@@ -72,6 +73,7 @@ struct Entity {
|
||||
struct {
|
||||
bool is_foreign;
|
||||
String foreign_name;
|
||||
Entity * foreign_library;
|
||||
String link_name;
|
||||
u64 tags;
|
||||
OverloadKind overload_kind;
|
||||
@@ -85,6 +87,11 @@ struct Entity {
|
||||
Scope *scope;
|
||||
bool used;
|
||||
} ImportName;
|
||||
struct {
|
||||
String path;
|
||||
String name;
|
||||
bool used;
|
||||
} LibraryName;
|
||||
i32 Nil;
|
||||
struct {
|
||||
// TODO(bill): Should this be a user-level construct rather than compiler-level?
|
||||
@@ -178,6 +185,14 @@ Entity *make_entity_import_name(gbAllocator a, Scope *scope, Token token, Type *
|
||||
return entity;
|
||||
}
|
||||
|
||||
Entity *make_entity_library_name(gbAllocator a, Scope *scope, Token token, Type *type,
|
||||
String path, String name) {
|
||||
Entity *entity = alloc_entity(a, Entity_LibraryName, scope, token, type);
|
||||
entity->LibraryName.path = path;
|
||||
entity->LibraryName.name = name;
|
||||
return entity;
|
||||
}
|
||||
|
||||
Entity *make_entity_nil(gbAllocator a, String name, Type *type) {
|
||||
Token token = make_token_ident(name);
|
||||
Entity *entity = alloc_entity(a, Entity_Nil, NULL, token, type);
|
||||
|
||||
@@ -43,13 +43,15 @@ typedef struct irModule {
|
||||
|
||||
Array(irProcedure *) procs; // NOTE(bill): All procedures with bodies
|
||||
irValueArray procs_to_generate; // NOTE(bill): Procedures to generate
|
||||
|
||||
Array(String) foreign_library_paths; // Only the ones that were used
|
||||
} irModule;
|
||||
|
||||
// NOTE(bill): For more info, see https://en.wikipedia.org/wiki/Dominator_(graph_theory)
|
||||
typedef struct irDomNode {
|
||||
irBlock * idom; // Parent (Immediate Dominator)
|
||||
Array(irBlock *) children;
|
||||
i32 pre, post; // Ordering in tree
|
||||
i32 pre, post; // Ordering in tree
|
||||
} irDomNode;
|
||||
|
||||
|
||||
@@ -5037,6 +5039,7 @@ void ir_init_module(irModule *m, Checker *c, BuildContext *build_context) {
|
||||
map_string_init(&m->type_names, heap_allocator());
|
||||
array_init(&m->procs, heap_allocator());
|
||||
array_init(&m->procs_to_generate, heap_allocator());
|
||||
array_init(&m->foreign_library_paths, heap_allocator());
|
||||
|
||||
// Default states
|
||||
m->stmt_state_flags = 0;
|
||||
@@ -5100,7 +5103,9 @@ void ir_destroy_module(irModule *m) {
|
||||
map_ir_value_destroy(&m->members);
|
||||
map_string_destroy(&m->type_names);
|
||||
map_ir_debug_info_destroy(&m->debug_info);
|
||||
array_free(&m->procs);
|
||||
array_free(&m->procs_to_generate);
|
||||
array_free(&m->foreign_library_paths);
|
||||
gb_arena_free(&m->arena);
|
||||
}
|
||||
|
||||
@@ -5199,6 +5204,22 @@ irValue *ir_type_info_member_offset(irProcedure *proc, irValue *data, isize coun
|
||||
return offset;
|
||||
}
|
||||
|
||||
void ir_add_foreign_library_path(irModule *m, Entity *e) {
|
||||
GB_ASSERT(e != NULL);
|
||||
String library_path = e->LibraryName.path;
|
||||
if (library_path.len == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
for_array(path_index, m->foreign_library_paths) {
|
||||
String path = m->foreign_library_paths.e[path_index];
|
||||
if (str_eq(path, library_path)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
array_add(&m->foreign_library_paths, library_path);
|
||||
}
|
||||
|
||||
void ir_gen_tree(irGen *s) {
|
||||
irModule *m = &s->module;
|
||||
CheckerInfo *info = m->info;
|
||||
@@ -5318,6 +5339,7 @@ void ir_gen_tree(irGen *s) {
|
||||
AstNode *body = pd->body;
|
||||
if (e->Procedure.is_foreign) {
|
||||
name = e->token.string; // NOTE(bill): Don't use the mangled name
|
||||
ir_add_foreign_library_path(m, e->Procedure.foreign_library);
|
||||
}
|
||||
if (pd->foreign_name.len > 0) {
|
||||
name = pd->foreign_name;
|
||||
|
||||
+5
-4
@@ -235,13 +235,14 @@ int main(int argc, char **argv) {
|
||||
|
||||
timings_start_section(&timings, str_lit("msvc-link"));
|
||||
|
||||
gbString lib_str = gb_string_make(heap_allocator(), "\"Kernel32.lib\"");
|
||||
gbString lib_str = gb_string_make(heap_allocator(), "");
|
||||
// defer (gb_string_free(lib_str));
|
||||
char lib_str_buf[1024] = {0};
|
||||
for_array(i, checker.info.foreign_libraries) {
|
||||
String lib = checker.info.foreign_libraries.e[i];
|
||||
for_array(i, ir_gen.module.foreign_library_paths) {
|
||||
String lib = ir_gen.module.foreign_library_paths.e[i];
|
||||
gb_printf_err("Linking lib: %.*s\n", LIT(lib));
|
||||
isize len = gb_snprintf(lib_str_buf, gb_size_of(lib_str_buf),
|
||||
" \"%.*s.lib\"", LIT(lib));
|
||||
" \"%.*s\"", LIT(lib));
|
||||
lib_str = gb_string_appendc(lib_str, lib_str_buf);
|
||||
}
|
||||
|
||||
|
||||
+66
-43
@@ -124,11 +124,12 @@ AstNodeArray make_ast_node_array(AstFile *f) {
|
||||
AstNode *expr; \
|
||||
}) \
|
||||
AST_NODE_KIND(ProcLit, "procedure literal", struct { \
|
||||
AstNode *type; \
|
||||
AstNode *body; \
|
||||
u64 tags; \
|
||||
String foreign_name; \
|
||||
String link_name; \
|
||||
AstNode *type; \
|
||||
AstNode *body; \
|
||||
u64 tags; \
|
||||
AstNode *foreign_library; \
|
||||
String foreign_name; \
|
||||
String link_name; \
|
||||
}) \
|
||||
AST_NODE_KIND(CompoundLit, "compound literal", struct { \
|
||||
AstNode *type; \
|
||||
@@ -302,6 +303,7 @@ AST_NODE_KIND(_DeclBegin, "", i32) \
|
||||
}) \
|
||||
AST_NODE_KIND(ForeignLibrary, "foreign library", struct { \
|
||||
Token token, filepath; \
|
||||
Token library_name; \
|
||||
String base_dir; \
|
||||
AstNode *cond; \
|
||||
bool is_system; \
|
||||
@@ -774,11 +776,12 @@ AstNode *make_ellipsis(AstFile *f, Token token, AstNode *expr) {
|
||||
}
|
||||
|
||||
|
||||
AstNode *make_proc_lit(AstFile *f, AstNode *type, AstNode *body, u64 tags, String foreign_name, String link_name) {
|
||||
AstNode *make_proc_lit(AstFile *f, AstNode *type, AstNode *body, u64 tags, AstNode *foreign_library, String foreign_name, String link_name) {
|
||||
AstNode *result = make_node(f, AstNode_ProcLit);
|
||||
result->ProcLit.type = type;
|
||||
result->ProcLit.body = body;
|
||||
result->ProcLit.tags = tags;
|
||||
result->ProcLit.foreign_library = foreign_library;
|
||||
result->ProcLit.foreign_name = foreign_name;
|
||||
result->ProcLit.link_name = link_name;
|
||||
return result;
|
||||
@@ -1112,14 +1115,6 @@ AstNode *make_enum_type(AstFile *f, Token token, AstNode *base_type, AstNodeArra
|
||||
return result;
|
||||
}
|
||||
|
||||
AstNode *make_foreign_library(AstFile *f, Token token, Token filepath, AstNode *cond, bool is_system) {
|
||||
AstNode *result = make_node(f, AstNode_ForeignLibrary);
|
||||
result->ForeignLibrary.token = token;
|
||||
result->ForeignLibrary.filepath = filepath;
|
||||
result->ForeignLibrary.cond = cond;
|
||||
result->ForeignLibrary.is_system = is_system;
|
||||
return result;
|
||||
}
|
||||
|
||||
AstNode *make_value_decl(AstFile *f, bool is_var, AstNodeArray names, AstNode *type, AstNodeArray values) {
|
||||
AstNode *result = make_node(f, AstNode_ValueDecl);
|
||||
@@ -1141,6 +1136,16 @@ AstNode *make_import_decl(AstFile *f, Token token, bool is_import, Token relpath
|
||||
return result;
|
||||
}
|
||||
|
||||
AstNode *make_foreign_library(AstFile *f, Token token, Token filepath, Token library_name, AstNode *cond, bool is_system) {
|
||||
AstNode *result = make_node(f, AstNode_ForeignLibrary);
|
||||
result->ForeignLibrary.token = token;
|
||||
result->ForeignLibrary.filepath = filepath;
|
||||
result->ForeignLibrary.library_name = library_name;
|
||||
result->ForeignLibrary.cond = cond;
|
||||
result->ForeignLibrary.is_system = is_system;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
bool next_token(AstFile *f) {
|
||||
Token prev = f->curr_token;
|
||||
@@ -1316,7 +1321,7 @@ bool is_semicolon_optional_for_node(AstFile *f, AstNode *s) {
|
||||
case AstNode_EnumType:
|
||||
return true;
|
||||
case AstNode_ProcLit:
|
||||
return true;
|
||||
return s->ProcLit.body != NULL;
|
||||
|
||||
case AstNode_ValueDecl:
|
||||
if (!s->ValueDecl.is_var) {
|
||||
@@ -1366,7 +1371,7 @@ void expect_semicolon(AstFile *f, AstNode *s) {
|
||||
|
||||
|
||||
AstNode * parse_expr(AstFile *f, bool lhs);
|
||||
AstNode * parse_proc_type(AstFile *f, String *foreign_name_, String *link_name_);
|
||||
AstNode * parse_proc_type(AstFile *f, AstNode **foreign_library, String *foreign_name, String *link_name);
|
||||
AstNodeArray parse_stmt_list(AstFile *f);
|
||||
AstNode * parse_stmt(AstFile *f);
|
||||
AstNode * parse_body(AstFile *f);
|
||||
@@ -1508,7 +1513,7 @@ bool is_foreign_name_valid(String name) {
|
||||
return true;
|
||||
}
|
||||
|
||||
void parse_proc_tags(AstFile *f, u64 *tags, String *foreign_name, String *link_name, ProcCallingConvention *calling_convention) {
|
||||
void parse_proc_tags(AstFile *f, u64 *tags, AstNode **foreign_library_token, String *foreign_name, String *link_name, ProcCallingConvention *calling_convention) {
|
||||
// TODO(bill): Add this to procedure literals too
|
||||
GB_ASSERT(tags != NULL);
|
||||
GB_ASSERT(link_name != NULL);
|
||||
@@ -1528,6 +1533,7 @@ void parse_proc_tags(AstFile *f, u64 *tags, String *foreign_name, String *link_n
|
||||
|
||||
if (str_eq(tag_name, str_lit("foreign"))) {
|
||||
check_proc_add_tag(f, tag_expr, tags, ProcTag_foreign, tag_name);
|
||||
*foreign_library_token = parse_identifier(f);
|
||||
if (f->curr_token.kind == Token_String) {
|
||||
*foreign_name = f->curr_token.string;
|
||||
// TODO(bill): Check if valid string
|
||||
@@ -1785,9 +1791,10 @@ AstNode *parse_operand(AstFile *f, bool lhs) {
|
||||
// Parse Procedure Type or Literal
|
||||
case Token_proc: {
|
||||
Token token = f->curr_token;
|
||||
AstNode *foreign_library = NULL;
|
||||
String foreign_name = {0};
|
||||
String link_name = {0};
|
||||
AstNode *type = parse_proc_type(f, &foreign_name, &link_name);
|
||||
AstNode *type = parse_proc_type(f, &foreign_library, &foreign_name, &link_name);
|
||||
u64 tags = type->ProcType.tags;
|
||||
|
||||
if (f->curr_token.kind == Token_OpenBrace) {
|
||||
@@ -1800,11 +1807,11 @@ AstNode *parse_operand(AstFile *f, bool lhs) {
|
||||
body = parse_body(f);
|
||||
f->curr_proc = curr_proc;
|
||||
|
||||
return make_proc_lit(f, type, body, tags, foreign_name, link_name);
|
||||
return make_proc_lit(f, type, body, tags, foreign_library, foreign_name, link_name);
|
||||
}
|
||||
|
||||
if ((tags & ProcTag_foreign) != 0) {
|
||||
return make_proc_lit(f, type, NULL, tags, foreign_name, link_name);
|
||||
return make_proc_lit(f, type, NULL, tags, foreign_library, foreign_name, link_name);
|
||||
}
|
||||
if (tags != 0) {
|
||||
syntax_error(token, "A procedure type cannot have tags");
|
||||
@@ -2312,7 +2319,7 @@ AstNode *parse_block_stmt(AstFile *f, b32 is_when) {
|
||||
|
||||
|
||||
|
||||
AstNode *parse_proc_type(AstFile *f, String *foreign_name_, String *link_name_) {
|
||||
AstNode *parse_proc_type(AstFile *f, AstNode **foreign_library_, String *foreign_name_, String *link_name_) {
|
||||
AstNodeArray params = {0};
|
||||
AstNodeArray results = {0};
|
||||
|
||||
@@ -2322,12 +2329,14 @@ AstNode *parse_proc_type(AstFile *f, String *foreign_name_, String *link_name_)
|
||||
u64 tags = 0;
|
||||
String foreign_name = {0};
|
||||
String link_name = {0};
|
||||
AstNode *foreign_library = NULL;
|
||||
ProcCallingConvention cc = ProcCC_Odin;
|
||||
|
||||
parse_proc_tags(f, &tags, &foreign_name, &link_name, &cc);
|
||||
parse_proc_tags(f, &tags, &foreign_library, &foreign_name, &link_name, &cc);
|
||||
|
||||
if (foreign_name_) *foreign_name_ = foreign_name;
|
||||
if (link_name_) *link_name_ = link_name;
|
||||
if (foreign_library_) *foreign_library_ = foreign_library;
|
||||
if (foreign_name_) *foreign_name_ = foreign_name;
|
||||
if (link_name_) *link_name_ = link_name;
|
||||
|
||||
return make_proc_type(f, proc_token, params, results, tags, cc);
|
||||
}
|
||||
@@ -2644,7 +2653,7 @@ AstNode *parse_identifier_or_type(AstFile *f) {
|
||||
|
||||
case Token_proc: {
|
||||
Token token = f->curr_token;
|
||||
AstNode *pt = parse_proc_type(f, NULL, NULL);
|
||||
AstNode *pt = parse_proc_type(f, NULL, NULL, NULL);
|
||||
if (pt->ProcType.tags != 0) {
|
||||
syntax_error(token, "A procedure type cannot have tags");
|
||||
}
|
||||
@@ -3327,6 +3336,21 @@ AstNode *parse_stmt(AstFile *f) {
|
||||
return s;
|
||||
} else if (str_eq(tag, str_lit("foreign_system_library"))) {
|
||||
AstNode *cond = NULL;
|
||||
Token lib_name = {0};
|
||||
|
||||
switch (f->curr_token.kind) {
|
||||
case Token_Ident:
|
||||
lib_name = f->curr_token;
|
||||
next_token(f);
|
||||
break;
|
||||
default:
|
||||
lib_name.pos = f->curr_token.pos;
|
||||
break;
|
||||
}
|
||||
|
||||
if (str_eq(lib_name.string, str_lit("_"))) {
|
||||
syntax_error(lib_name, "Illegal #foreign_library name: `_`");
|
||||
}
|
||||
Token file_path = expect_token(f, Token_String);
|
||||
|
||||
if (allow_token(f, Token_when)) {
|
||||
@@ -3334,7 +3358,7 @@ AstNode *parse_stmt(AstFile *f) {
|
||||
}
|
||||
|
||||
if (f->curr_proc == NULL) {
|
||||
s = make_foreign_library(f, hash_token, file_path, cond, true);
|
||||
s = make_foreign_library(f, hash_token, file_path, lib_name, cond, true);
|
||||
} else {
|
||||
syntax_error(token, "You cannot use #foreign_system_library within a procedure. This must be done at the file scope");
|
||||
s = make_bad_decl(f, token, file_path);
|
||||
@@ -3343,6 +3367,21 @@ AstNode *parse_stmt(AstFile *f) {
|
||||
return s;
|
||||
} else if (str_eq(tag, str_lit("foreign_library"))) {
|
||||
AstNode *cond = NULL;
|
||||
Token lib_name = {0};
|
||||
|
||||
switch (f->curr_token.kind) {
|
||||
case Token_Ident:
|
||||
lib_name = f->curr_token;
|
||||
next_token(f);
|
||||
break;
|
||||
default:
|
||||
lib_name.pos = f->curr_token.pos;
|
||||
break;
|
||||
}
|
||||
|
||||
if (str_eq(lib_name.string, str_lit("_"))) {
|
||||
syntax_error(lib_name, "Illegal #foreign_library name: `_`");
|
||||
}
|
||||
Token file_path = expect_token(f, Token_String);
|
||||
|
||||
if (allow_token(f, Token_when)) {
|
||||
@@ -3350,7 +3389,7 @@ AstNode *parse_stmt(AstFile *f) {
|
||||
}
|
||||
|
||||
if (f->curr_proc == NULL) {
|
||||
s = make_foreign_library(f, hash_token, file_path, cond, false);
|
||||
s = make_foreign_library(f, hash_token, file_path, lib_name, cond, false);
|
||||
} else {
|
||||
syntax_error(token, "You cannot use #foreign_library within a procedure. This must be done at the file scope");
|
||||
s = make_bad_decl(f, token, file_path);
|
||||
@@ -3513,22 +3552,6 @@ bool try_add_import_path(Parser *p, String path, String rel_path, TokenPos pos)
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// // NOTE(bill): Returns true if it's added
|
||||
// bool try_add_foreign_library_path(Parser *p, String import_file) {
|
||||
// gb_mutex_lock(&p->mutex);
|
||||
|
||||
// for_array(i, p->foreign_libraries) {
|
||||
// String import = p->foreign_libraries.e[i];
|
||||
// if (str_eq(import, import_file)) {
|
||||
// return false;
|
||||
// }
|
||||
// }
|
||||
// array_add(&p->foreign_libraries, import_file);
|
||||
// gb_mutex_unlock(&p->mutex);
|
||||
// return true;
|
||||
// }
|
||||
|
||||
gb_global Rune illegal_import_runes[] = {
|
||||
'"', '\'', '`', ' ', '\t', '\r', '\n', '\v', '\f',
|
||||
'\\', // NOTE(bill): Disallow windows style filepaths
|
||||
|
||||
Reference in New Issue
Block a user