mirror of
https://github.com/Ed94/Odin.git
synced 2026-08-06 15:48:51 +00:00
Begin moving foreign import import paths to be evaluated in the semantic phase rather than parsing.
This commit is contained in:
+38
-1
@@ -4883,7 +4883,44 @@ gb_internal void check_add_foreign_import_decl(CheckerContext *ctx, Ast *decl) {
|
|||||||
Scope *parent_scope = ctx->scope;
|
Scope *parent_scope = ctx->scope;
|
||||||
GB_ASSERT(parent_scope->flags&ScopeFlag_File);
|
GB_ASSERT(parent_scope->flags&ScopeFlag_File);
|
||||||
|
|
||||||
GB_ASSERT(fl->fullpaths.count > 0);
|
String base_dir = dir_from_path(decl->file()->fullpath);
|
||||||
|
|
||||||
|
auto fullpaths = array_make<String>(permanent_allocator(), 0, fl->filepaths.count);
|
||||||
|
|
||||||
|
for (Ast *fp_node : fl->filepaths) {
|
||||||
|
Operand op = {};
|
||||||
|
check_expr(ctx, &op, fp_node);
|
||||||
|
if (op.mode != Addressing_Constant && op.value.kind != ExactValue_String) {
|
||||||
|
gbString s = expr_to_string(op.expr);
|
||||||
|
error(fp_node, "Expected a constant string value, got '%s'", s);
|
||||||
|
gb_string_free(s);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!is_type_string(op.type)) {
|
||||||
|
gbString s = type_to_string(op.type);
|
||||||
|
error(fp_node, "Expected a constant string value, got value of type '%s'", s);
|
||||||
|
gb_string_free(s);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
String file_str = op.value.value_string;
|
||||||
|
file_str = string_trim_whitespace(file_str);
|
||||||
|
|
||||||
|
String fullpath = file_str;
|
||||||
|
if (allow_check_foreign_filepath()) {
|
||||||
|
String foreign_path = {};
|
||||||
|
bool ok = determine_path_from_string(nullptr, decl, base_dir, file_str, &foreign_path);
|
||||||
|
gb_unused(ok);
|
||||||
|
fullpath = foreign_path;
|
||||||
|
}
|
||||||
|
array_add(&fullpaths, fullpath);
|
||||||
|
}
|
||||||
|
fl->fullpaths = slice_from_array(fullpaths);
|
||||||
|
|
||||||
|
|
||||||
|
if (fl->fullpaths.count == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
String fullpath = fl->fullpaths[0];
|
String fullpath = fl->fullpaths[0];
|
||||||
String library_name = path_to_entity_name(fl->library_name.string, fullpath);
|
String library_name = path_to_entity_name(fl->library_name.string, fullpath);
|
||||||
if (is_blank_ident(library_name)) {
|
if (is_blank_ident(library_name)) {
|
||||||
|
|||||||
+29
-36
@@ -1284,7 +1284,7 @@ gb_internal Ast *ast_import_decl(AstFile *f, Token token, Token relpath, Token i
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
gb_internal Ast *ast_foreign_import_decl(AstFile *f, Token token, Array<Token> filepaths, Token library_name,
|
gb_internal Ast *ast_foreign_import_decl(AstFile *f, Token token, Array<Ast *> filepaths, Token library_name,
|
||||||
CommentGroup *docs, CommentGroup *comment) {
|
CommentGroup *docs, CommentGroup *comment) {
|
||||||
Ast *result = alloc_ast_node(f, Ast_ForeignImportDecl);
|
Ast *result = alloc_ast_node(f, Ast_ForeignImportDecl);
|
||||||
result->ForeignImportDecl.token = token;
|
result->ForeignImportDecl.token = token;
|
||||||
@@ -4882,14 +4882,14 @@ gb_internal Ast *parse_foreign_decl(AstFile *f) {
|
|||||||
if (is_blank_ident(lib_name)) {
|
if (is_blank_ident(lib_name)) {
|
||||||
syntax_error(lib_name, "Illegal foreign import name: '_'");
|
syntax_error(lib_name, "Illegal foreign import name: '_'");
|
||||||
}
|
}
|
||||||
Array<Token> filepaths = {};
|
Array<Ast *> filepaths = {};
|
||||||
if (allow_token(f, Token_OpenBrace)) {
|
if (allow_token(f, Token_OpenBrace)) {
|
||||||
array_init(&filepaths, ast_allocator(f));
|
array_init(&filepaths, ast_allocator(f));
|
||||||
|
|
||||||
while (f->curr_token.kind != Token_CloseBrace &&
|
while (f->curr_token.kind != Token_CloseBrace &&
|
||||||
f->curr_token.kind != Token_EOF) {
|
f->curr_token.kind != Token_EOF) {
|
||||||
|
|
||||||
Token path = expect_token(f, Token_String);
|
Ast *path = parse_expr(f, true);
|
||||||
array_add(&filepaths, path);
|
array_add(&filepaths, path);
|
||||||
|
|
||||||
if (!allow_field_separator(f)) {
|
if (!allow_field_separator(f)) {
|
||||||
@@ -4898,9 +4898,10 @@ gb_internal Ast *parse_foreign_decl(AstFile *f) {
|
|||||||
}
|
}
|
||||||
expect_closing_brace_of_field_list(f);
|
expect_closing_brace_of_field_list(f);
|
||||||
} else {
|
} else {
|
||||||
filepaths = array_make<Token>(ast_allocator(f), 0, 1);
|
filepaths = array_make<Ast *>(ast_allocator(f), 0, 1);
|
||||||
Token path = expect_token(f, Token_String);
|
Token path = expect_token(f, Token_String);
|
||||||
array_add(&filepaths, path);
|
Ast *lit = ast_basic_lit(f, path);
|
||||||
|
array_add(&filepaths, lit);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ast *s = nullptr;
|
Ast *s = nullptr;
|
||||||
@@ -4909,7 +4910,7 @@ gb_internal Ast *parse_foreign_decl(AstFile *f) {
|
|||||||
s = ast_bad_decl(f, lib_name, f->curr_token);
|
s = ast_bad_decl(f, lib_name, f->curr_token);
|
||||||
} else if (f->curr_proc != nullptr) {
|
} else if (f->curr_proc != nullptr) {
|
||||||
syntax_error(lib_name, "You cannot use foreign import within a procedure. This must be done at the file scope");
|
syntax_error(lib_name, "You cannot use foreign import within a procedure. This must be done at the file scope");
|
||||||
s = ast_bad_decl(f, lib_name, filepaths[0]);
|
s = ast_bad_decl(f, lib_name, ast_token(filepaths[0]));
|
||||||
} else {
|
} else {
|
||||||
s = ast_foreign_import_decl(f, token, filepaths, lib_name, docs, f->line_comment);
|
s = ast_foreign_import_decl(f, token, filepaths, lib_name, docs, f->line_comment);
|
||||||
}
|
}
|
||||||
@@ -5648,9 +5649,19 @@ gb_internal bool is_package_name_reserved(String const &name) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
gb_internal bool determine_path_from_string(BlockingMutex *file_mutex, Ast *node, String base_dir, String const &original_string, String *path) {
|
gb_internal bool determine_path_from_string(BlockingMutex *file_mutex, Ast *node, String base_dir, String const &original_string, String *path, bool use_check_errors=false) {
|
||||||
GB_ASSERT(path != nullptr);
|
GB_ASSERT(path != nullptr);
|
||||||
|
|
||||||
|
void (*do_error)(Ast *, char const *, ...);
|
||||||
|
void (*do_warning)(Token const &, char const *, ...);
|
||||||
|
|
||||||
|
do_error = &syntax_error;
|
||||||
|
do_warning = &syntax_warning;
|
||||||
|
if (use_check_errors) {
|
||||||
|
do_error = &error;
|
||||||
|
do_error = &warning;
|
||||||
|
}
|
||||||
|
|
||||||
// NOTE(bill): if file_mutex == nullptr, this means that the code is used within the semantics stage
|
// NOTE(bill): if file_mutex == nullptr, this means that the code is used within the semantics stage
|
||||||
|
|
||||||
String collection_name = {};
|
String collection_name = {};
|
||||||
@@ -5677,7 +5688,7 @@ gb_internal bool determine_path_from_string(BlockingMutex *file_mutex, Ast *node
|
|||||||
|
|
||||||
String file_str = {};
|
String file_str = {};
|
||||||
if (colon_pos == 0) {
|
if (colon_pos == 0) {
|
||||||
syntax_error(node, "Expected a collection name");
|
do_error(node, "Expected a collection name");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -5692,11 +5703,11 @@ gb_internal bool determine_path_from_string(BlockingMutex *file_mutex, Ast *node
|
|||||||
if (has_windows_drive) {
|
if (has_windows_drive) {
|
||||||
String sub_file_path = substring(file_str, 3, file_str.len);
|
String sub_file_path = substring(file_str, 3, file_str.len);
|
||||||
if (!is_import_path_valid(sub_file_path)) {
|
if (!is_import_path_valid(sub_file_path)) {
|
||||||
syntax_error(node, "Invalid import path: '%.*s'", LIT(file_str));
|
do_error(node, "Invalid import path: '%.*s'", LIT(file_str));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else if (!is_import_path_valid(file_str)) {
|
} else if (!is_import_path_valid(file_str)) {
|
||||||
syntax_error(node, "Invalid import path: '%.*s'", LIT(file_str));
|
do_error(node, "Invalid import path: '%.*s'", LIT(file_str));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -5718,16 +5729,16 @@ gb_internal bool determine_path_from_string(BlockingMutex *file_mutex, Ast *node
|
|||||||
}
|
}
|
||||||
if (replace_with_base) {
|
if (replace_with_base) {
|
||||||
if (ast_file_vet_deprecated(node->file())) {
|
if (ast_file_vet_deprecated(node->file())) {
|
||||||
syntax_error(node, "import \"core:%.*s\" has been deprecated in favour of \"base:%.*s\"", LIT(file_str), LIT(file_str));
|
do_error(node, "import \"core:%.*s\" has been deprecated in favour of \"base:%.*s\"", LIT(file_str), LIT(file_str));
|
||||||
} else {
|
} else {
|
||||||
syntax_warning(ast_token(node), "import \"core:%.*s\" has been deprecated in favour of \"base:%.*s\"", LIT(file_str), LIT(file_str));
|
do_warning(ast_token(node), "import \"core:%.*s\" has been deprecated in favour of \"base:%.*s\"", LIT(file_str), LIT(file_str));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (collection_name == "system") {
|
if (collection_name == "system") {
|
||||||
if (node->kind != Ast_ForeignImportDecl) {
|
if (node->kind != Ast_ForeignImportDecl) {
|
||||||
syntax_error(node, "The library collection 'system' is restrict for 'foreign_library'");
|
do_error(node, "The library collection 'system' is restrict for 'foreign import'");
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
*path = file_str;
|
*path = file_str;
|
||||||
@@ -5735,7 +5746,7 @@ gb_internal bool determine_path_from_string(BlockingMutex *file_mutex, Ast *node
|
|||||||
}
|
}
|
||||||
} else if (!find_library_collection_path(collection_name, &base_dir)) {
|
} else if (!find_library_collection_path(collection_name, &base_dir)) {
|
||||||
// NOTE(bill): It's a naughty name
|
// NOTE(bill): It's a naughty name
|
||||||
syntax_error(node, "Unknown library collection: '%.*s'", LIT(collection_name));
|
do_error(node, "Unknown library collection: '%.*s'", LIT(collection_name));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -5759,7 +5770,7 @@ gb_internal bool determine_path_from_string(BlockingMutex *file_mutex, Ast *node
|
|||||||
if (collection_name == "core" || collection_name == "base") {
|
if (collection_name == "core" || collection_name == "base") {
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
syntax_error(node, "The package '%.*s' must be imported with the 'base' library collection: 'base:%.*s'", LIT(file_str), LIT(file_str));
|
do_error(node, "The package '%.*s' must be imported with the 'base' library collection: 'base:%.*s'", LIT(file_str), LIT(file_str));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -5844,31 +5855,13 @@ gb_internal void parse_setup_file_decls(Parser *p, AstFile *f, String const &bas
|
|||||||
} else if (node->kind == Ast_ForeignImportDecl) {
|
} else if (node->kind == Ast_ForeignImportDecl) {
|
||||||
ast_node(fl, ForeignImportDecl, node);
|
ast_node(fl, ForeignImportDecl, node);
|
||||||
|
|
||||||
auto fullpaths = array_make<String>(permanent_allocator(), 0, fl->filepaths.count);
|
if (fl->filepaths.count == 0) {
|
||||||
|
|
||||||
for (Token const &fp : fl->filepaths) {
|
|
||||||
String file_str = string_trim_whitespace(string_value_from_token(f, fp));
|
|
||||||
String fullpath = file_str;
|
|
||||||
if (allow_check_foreign_filepath()) {
|
|
||||||
String foreign_path = {};
|
|
||||||
bool ok = determine_path_from_string(&p->file_decl_mutex, node, base_dir, file_str, &foreign_path);
|
|
||||||
if (!ok) {
|
|
||||||
decls[i] = ast_bad_decl(f, fp, fl->filepaths[fl->filepaths.count-1]);
|
|
||||||
goto end;
|
|
||||||
}
|
|
||||||
fullpath = foreign_path;
|
|
||||||
}
|
|
||||||
array_add(&fullpaths, fullpath);
|
|
||||||
}
|
|
||||||
if (fullpaths.count == 0) {
|
|
||||||
syntax_error(decls[i], "No foreign paths found");
|
syntax_error(decls[i], "No foreign paths found");
|
||||||
decls[i] = ast_bad_decl(f, fl->filepaths[0], fl->filepaths[fl->filepaths.count-1]);
|
decls[i] = ast_bad_decl(f, ast_token(fl->filepaths[0]), ast_end_token(fl->filepaths[fl->filepaths.count-1]));
|
||||||
goto end;
|
goto end;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fl->fullpaths = slice_from_array(fullpaths);
|
|
||||||
|
|
||||||
|
|
||||||
} else if (node->kind == Ast_WhenStmt) {
|
} else if (node->kind == Ast_WhenStmt) {
|
||||||
ast_node(ws, WhenStmt, node);
|
ast_node(ws, WhenStmt, node);
|
||||||
parse_setup_file_when_stmt(p, f, base_dir, ws);
|
parse_setup_file_when_stmt(p, f, base_dir, ws);
|
||||||
|
|||||||
+1
-1
@@ -631,7 +631,7 @@ AST_KIND(_DeclBegin, "", bool) \
|
|||||||
}) \
|
}) \
|
||||||
AST_KIND(ForeignImportDecl, "foreign import declaration", struct { \
|
AST_KIND(ForeignImportDecl, "foreign import declaration", struct { \
|
||||||
Token token; \
|
Token token; \
|
||||||
Slice<Token> filepaths; \
|
Slice<Ast *> filepaths; \
|
||||||
Token library_name; \
|
Token library_name; \
|
||||||
String collection_name; \
|
String collection_name; \
|
||||||
Slice<String> fullpaths; \
|
Slice<String> fullpaths; \
|
||||||
|
|||||||
+1
-1
@@ -278,7 +278,7 @@ Token ast_end_token(Ast *node) {
|
|||||||
case Ast_ImportDecl: return node->ImportDecl.relpath;
|
case Ast_ImportDecl: return node->ImportDecl.relpath;
|
||||||
case Ast_ForeignImportDecl:
|
case Ast_ForeignImportDecl:
|
||||||
if (node->ForeignImportDecl.filepaths.count > 0) {
|
if (node->ForeignImportDecl.filepaths.count > 0) {
|
||||||
return node->ForeignImportDecl.filepaths[node->ForeignImportDecl.filepaths.count-1];
|
return ast_end_token(node->ForeignImportDecl.filepaths[node->ForeignImportDecl.filepaths.count-1]);
|
||||||
}
|
}
|
||||||
if (node->ForeignImportDecl.library_name.kind != Token_Invalid) {
|
if (node->ForeignImportDecl.library_name.kind != Token_Invalid) {
|
||||||
return node->ForeignImportDecl.library_name;
|
return node->ForeignImportDecl.library_name;
|
||||||
|
|||||||
Reference in New Issue
Block a user