mirror of
https://github.com/Ed94/Odin.git
synced 2026-06-16 19:02:23 -07:00
Merge remote-tracking branch 'origin/master'
This commit is contained in:
@@ -296,6 +296,14 @@ Source_Code_Location :: struct {
|
||||
procedure: string,
|
||||
}
|
||||
|
||||
/*
|
||||
Used by the built-in directory `#load_directory(path: string) -> []Load_Directory_File`
|
||||
*/
|
||||
Load_Directory_File :: struct {
|
||||
name: string,
|
||||
data: []byte, // immutable data
|
||||
}
|
||||
|
||||
Assertion_Failure_Proc :: #type proc(prefix, message: string, loc: Source_Code_Location) -> !
|
||||
|
||||
// Allocation Stuff
|
||||
|
||||
@@ -130,6 +130,7 @@ foreign kernel32 {
|
||||
ResumeThread :: proc(thread: HANDLE) -> DWORD ---
|
||||
GetThreadPriority :: proc(thread: HANDLE) -> c_int ---
|
||||
SetThreadPriority :: proc(thread: HANDLE, priority: c_int) -> BOOL ---
|
||||
SetThreadDescription :: proc(hThread: HANDLE, lpThreadDescription: PCWSTR) -> HRESULT ---
|
||||
GetExitCodeThread :: proc(thread: HANDLE, exit_code: ^DWORD) -> BOOL ---
|
||||
TerminateThread :: proc(thread: HANDLE, exit_code: DWORD) -> BOOL ---
|
||||
SuspendThread :: proc(hThread: HANDLE) -> DWORD ---
|
||||
|
||||
@@ -53,6 +53,7 @@ foreign user32 {
|
||||
DispatchMessageW :: proc(lpMsg: ^MSG) -> LRESULT ---
|
||||
|
||||
WaitMessage :: proc() -> BOOL ---
|
||||
MsgWaitForMultipleObjects :: proc(nCount: DWORD, pHandles: ^HANDLE, fWaitAll: bool, dwMilliseconds: DWORD, dwWakeMask: DWORD) -> DWORD ---
|
||||
|
||||
PeekMessageA :: proc(lpMsg: ^MSG, hWnd: HWND, wMsgFilterMin: UINT, wMsgFilterMax: UINT, wRemoveMsg: UINT) -> BOOL ---
|
||||
PeekMessageW :: proc(lpMsg: ^MSG, hWnd: HWND, wMsgFilterMin: UINT, wMsgFilterMax: UINT, wRemoveMsg: UINT) -> BOOL ---
|
||||
|
||||
+135
-52
@@ -1264,6 +1264,139 @@ gb_internal LoadDirectiveResult check_load_directive(CheckerContext *c, Operand
|
||||
|
||||
}
|
||||
|
||||
gb_internal int file_cache_sort_cmp(void const *x, void const *y) {
|
||||
LoadFileCache const *a = *(LoadFileCache const **)(x);
|
||||
LoadFileCache const *b = *(LoadFileCache const **)(y);
|
||||
return string_compare(a->path, b->path);
|
||||
}
|
||||
|
||||
gb_internal LoadDirectiveResult check_load_directory_directive(CheckerContext *c, Operand *operand, Ast *call, Type *type_hint, bool err_on_not_found) {
|
||||
ast_node(ce, CallExpr, call);
|
||||
ast_node(bd, BasicDirective, ce->proc);
|
||||
String name = bd->name.string;
|
||||
GB_ASSERT(name == "load_directory");
|
||||
|
||||
if (ce->args.count != 1) {
|
||||
error(ce->args[0], "'#%.*s' expects 1 argument, got %td", LIT(name), ce->args.count);
|
||||
return LoadDirective_Error;
|
||||
}
|
||||
|
||||
Ast *arg = ce->args[0];
|
||||
Operand o = {};
|
||||
check_expr(c, &o, arg);
|
||||
if (o.mode != Addressing_Constant) {
|
||||
error(arg, "'#%.*s' expected a constant string argument", LIT(name));
|
||||
return LoadDirective_Error;
|
||||
}
|
||||
|
||||
if (!is_type_string(o.type)) {
|
||||
gbString str = type_to_string(o.type);
|
||||
error(arg, "'#%.*s' expected a constant string, got %s", LIT(name), str);
|
||||
gb_string_free(str);
|
||||
return LoadDirective_Error;
|
||||
}
|
||||
|
||||
GB_ASSERT(o.value.kind == ExactValue_String);
|
||||
|
||||
init_core_load_directory_file(c->checker);
|
||||
|
||||
operand->type = t_load_directory_file_slice;
|
||||
operand->mode = Addressing_Value;
|
||||
|
||||
|
||||
String original_string = o.value.value_string;
|
||||
String path;
|
||||
if (gb_path_is_absolute((char*)original_string.text)) {
|
||||
path = original_string;
|
||||
} else {
|
||||
String base_dir = dir_from_path(get_file_path_string(call->file_id));
|
||||
|
||||
BlockingMutex *ignore_mutex = nullptr;
|
||||
bool ok = determine_path_from_string(ignore_mutex, call, base_dir, original_string, &path);
|
||||
gb_unused(ok);
|
||||
}
|
||||
MUTEX_GUARD(&c->info->load_directory_mutex);
|
||||
|
||||
|
||||
gbFileError file_error = gbFileError_None;
|
||||
|
||||
Array<LoadFileCache *> file_caches = {};
|
||||
|
||||
LoadDirectoryCache **cache_ptr = string_map_get(&c->info->load_directory_cache, path);
|
||||
LoadDirectoryCache *cache = cache_ptr ? *cache_ptr : nullptr;
|
||||
if (cache) {
|
||||
file_error = cache->file_error;
|
||||
}
|
||||
defer ({
|
||||
if (cache == nullptr) {
|
||||
LoadDirectoryCache *new_cache = gb_alloc_item(permanent_allocator(), LoadDirectoryCache);
|
||||
new_cache->path = path;
|
||||
new_cache->files = file_caches;
|
||||
new_cache->file_error = file_error;
|
||||
string_map_set(&c->info->load_directory_cache, path, new_cache);
|
||||
|
||||
map_set(&c->info->load_directory_map, call, new_cache);
|
||||
} else {
|
||||
cache->file_error = file_error;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
LoadDirectiveResult result = LoadDirective_Success;
|
||||
|
||||
|
||||
if (cache == nullptr) {
|
||||
Array<FileInfo> list = {};
|
||||
ReadDirectoryError rd_err = read_directory(path, &list);
|
||||
defer (array_free(&list));
|
||||
|
||||
if (list.count == 1) {
|
||||
GB_ASSERT(path != list[0].fullpath);
|
||||
}
|
||||
|
||||
|
||||
switch (rd_err) {
|
||||
case ReadDirectory_InvalidPath:
|
||||
error(call, "%.*s error - invalid path: %.*s", LIT(name), LIT(original_string));
|
||||
return LoadDirective_NotFound;
|
||||
case ReadDirectory_NotExists:
|
||||
error(call, "%.*s error - path does not exist: %.*s", LIT(name), LIT(original_string));
|
||||
return LoadDirective_NotFound;
|
||||
case ReadDirectory_Permission:
|
||||
error(call, "%.*s error - unknown error whilst reading path, %.*s", LIT(name), LIT(original_string));
|
||||
return LoadDirective_Error;
|
||||
case ReadDirectory_NotDir:
|
||||
error(call, "%.*s error - expected a directory, got a file: %.*s", LIT(name), LIT(original_string));
|
||||
return LoadDirective_Error;
|
||||
case ReadDirectory_Empty:
|
||||
error(call, "%.*s error - empty directory: %.*s", LIT(name), LIT(original_string));
|
||||
return LoadDirective_NotFound;
|
||||
case ReadDirectory_Unknown:
|
||||
error(call, "%.*s error - unknown error whilst reading path %.*s", LIT(name), LIT(original_string));
|
||||
return LoadDirective_Error;
|
||||
}
|
||||
|
||||
isize files_to_reserve = list.count+1; // always reserve 1
|
||||
|
||||
file_caches = array_make<LoadFileCache *>(heap_allocator(), 0, files_to_reserve);
|
||||
|
||||
for (FileInfo fi : list) {
|
||||
LoadFileCache *cache = nullptr;
|
||||
if (cache_load_file_directive(c, call, fi.fullpath, err_on_not_found, &cache)) {
|
||||
array_add(&file_caches, cache);
|
||||
} else {
|
||||
result = LoadDirective_Error;
|
||||
}
|
||||
}
|
||||
|
||||
gb_sort_array(file_caches.data, file_caches.count, file_cache_sort_cmp);
|
||||
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
gb_internal bool check_builtin_procedure_directive(CheckerContext *c, Operand *operand, Ast *call, Type *type_hint) {
|
||||
ast_node(ce, CallExpr, call);
|
||||
@@ -1291,6 +1424,8 @@ gb_internal bool check_builtin_procedure_directive(CheckerContext *c, Operand *o
|
||||
operand->mode = Addressing_Value;
|
||||
} else if (name == "load") {
|
||||
return check_load_directive(c, operand, call, type_hint, true) == LoadDirective_Success;
|
||||
} else if (name == "load_directory") {
|
||||
return check_load_directory_directive(c, operand, call, type_hint, true) == LoadDirective_Success;
|
||||
} else if (name == "load_hash") {
|
||||
if (ce->args.count != 2) {
|
||||
if (ce->args.count == 0) {
|
||||
@@ -1408,58 +1543,6 @@ gb_internal bool check_builtin_procedure_directive(CheckerContext *c, Operand *o
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
} else if (name == "load_or") {
|
||||
error(call, "'#load_or' has now been removed in favour of '#load(path) or_else default'");
|
||||
|
||||
if (ce->args.count != 2) {
|
||||
if (ce->args.count == 0) {
|
||||
error(ce->close, "'#load_or' expects 2 arguments, got 0");
|
||||
} else {
|
||||
error(ce->args[0], "'#load_or' expects 2 arguments, got %td", ce->args.count);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
Ast *arg = ce->args[0];
|
||||
Operand o = {};
|
||||
check_expr(c, &o, arg);
|
||||
if (o.mode != Addressing_Constant) {
|
||||
error(arg, "'#load_or' expected a constant string argument");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!is_type_string(o.type)) {
|
||||
gbString str = type_to_string(o.type);
|
||||
error(arg, "'#load_or' expected a constant string, got %s", str);
|
||||
gb_string_free(str);
|
||||
return false;
|
||||
}
|
||||
|
||||
Ast *default_arg = ce->args[1];
|
||||
Operand default_op = {};
|
||||
check_expr_with_type_hint(c, &default_op, default_arg, t_u8_slice);
|
||||
if (default_op.mode != Addressing_Constant) {
|
||||
error(arg, "'#load_or' expected a constant '[]byte' argument");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!are_types_identical(base_type(default_op.type), t_u8_slice)) {
|
||||
gbString str = type_to_string(default_op.type);
|
||||
error(arg, "'#load_or' expected a constant '[]byte', got %s", str);
|
||||
gb_string_free(str);
|
||||
return false;
|
||||
}
|
||||
GB_ASSERT(o.value.kind == ExactValue_String);
|
||||
String original_string = o.value.value_string;
|
||||
|
||||
operand->type = t_u8_slice;
|
||||
operand->mode = Addressing_Constant;
|
||||
LoadFileCache *cache = nullptr;
|
||||
if (cache_load_file_directive(c, call, original_string, false, &cache)) {
|
||||
operand->value = exact_value_string(cache->data);
|
||||
} else {
|
||||
operand->value = default_op.value;
|
||||
}
|
||||
} else if (name == "assert") {
|
||||
if (ce->args.count != 1 && ce->args.count != 2) {
|
||||
error(call, "'#assert' expects either 1 or 2 arguments, got %td", ce->args.count);
|
||||
|
||||
+3
-2
@@ -7107,8 +7107,8 @@ gb_internal ExprKind check_call_expr(CheckerContext *c, Operand *operand, Ast *c
|
||||
name == "defined" ||
|
||||
name == "config" ||
|
||||
name == "load" ||
|
||||
name == "load_hash" ||
|
||||
name == "load_or"
|
||||
name == "load_directory" ||
|
||||
name == "load_hash"
|
||||
) {
|
||||
operand->mode = Addressing_Builtin;
|
||||
operand->builtin_id = BuiltinProc_DIRECTIVE;
|
||||
@@ -7958,6 +7958,7 @@ gb_internal ExprKind check_basic_directive_expr(CheckerContext *c, Operand *o, A
|
||||
name == "config" ||
|
||||
name == "load" ||
|
||||
name == "load_hash" ||
|
||||
name == "load_directory" ||
|
||||
name == "load_or"
|
||||
) {
|
||||
error(node, "'#%.*s' must be used as a call", LIT(name));
|
||||
|
||||
@@ -1257,6 +1257,9 @@ gb_internal void init_checker_info(CheckerInfo *i) {
|
||||
mpsc_init(&i->required_global_variable_queue, a); // 1<<10);
|
||||
mpsc_init(&i->required_foreign_imports_through_force_queue, a); // 1<<10);
|
||||
mpsc_init(&i->intrinsics_entry_point_usage, a); // 1<<10); // just waste some memory here, even if it probably never used
|
||||
|
||||
string_map_init(&i->load_directory_cache);
|
||||
map_init(&i->load_directory_map);
|
||||
}
|
||||
|
||||
gb_internal void destroy_checker_info(CheckerInfo *i) {
|
||||
@@ -1280,6 +1283,8 @@ gb_internal void destroy_checker_info(CheckerInfo *i) {
|
||||
|
||||
map_destroy(&i->objc_msgSend_types);
|
||||
string_map_destroy(&i->load_file_cache);
|
||||
string_map_destroy(&i->load_directory_cache);
|
||||
map_destroy(&i->load_directory_map);
|
||||
}
|
||||
|
||||
gb_internal CheckerContext make_checker_context(Checker *c) {
|
||||
@@ -2958,6 +2963,16 @@ gb_internal void init_core_source_code_location(Checker *c) {
|
||||
t_source_code_location_ptr = alloc_type_pointer(t_source_code_location);
|
||||
}
|
||||
|
||||
gb_internal void init_core_load_directory_file(Checker *c) {
|
||||
if (t_load_directory_file != nullptr) {
|
||||
return;
|
||||
}
|
||||
t_load_directory_file = find_core_type(c, str_lit("Load_Directory_File"));
|
||||
t_load_directory_file_ptr = alloc_type_pointer(t_load_directory_file);
|
||||
t_load_directory_file_slice = alloc_type_slice(t_load_directory_file);
|
||||
}
|
||||
|
||||
|
||||
gb_internal void init_core_map_type(Checker *c) {
|
||||
if (t_map_info != nullptr) {
|
||||
return;
|
||||
|
||||
@@ -340,6 +340,19 @@ struct LoadFileCache {
|
||||
StringMap<u64> hashes;
|
||||
};
|
||||
|
||||
|
||||
struct LoadDirectoryFile {
|
||||
String file_name;
|
||||
String data;
|
||||
};
|
||||
|
||||
struct LoadDirectoryCache {
|
||||
String path;
|
||||
gbFileError file_error;
|
||||
Array<LoadFileCache *> files;
|
||||
};
|
||||
|
||||
|
||||
struct GenProcsData {
|
||||
Array<Entity *> procs;
|
||||
RwMutex mutex;
|
||||
@@ -416,6 +429,11 @@ struct CheckerInfo {
|
||||
BlockingMutex instrumentation_mutex;
|
||||
Entity *instrumentation_enter_entity;
|
||||
Entity *instrumentation_exit_entity;
|
||||
|
||||
|
||||
BlockingMutex load_directory_mutex;
|
||||
StringMap<LoadDirectoryCache *> load_directory_cache;
|
||||
PtrMap<Ast *, LoadDirectoryCache *> load_directory_map; // Key: Ast_CallExpr *
|
||||
};
|
||||
|
||||
struct CheckerContext {
|
||||
|
||||
+14
-18
@@ -482,37 +482,33 @@ gb_internal i32 linker_stage(LinkerData *gen) {
|
||||
gbString platform_lib_str = gb_string_make(heap_allocator(), "");
|
||||
defer (gb_string_free(platform_lib_str));
|
||||
if (build_context.metrics.os == TargetOs_darwin) {
|
||||
platform_lib_str = gb_string_appendc(platform_lib_str, "-Wl,-syslibroot /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk -L/usr/local/lib");
|
||||
platform_lib_str = gb_string_appendc(platform_lib_str, "-Wl,-syslibroot /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk -L/usr/local/lib ");
|
||||
|
||||
// Homebrew's default library path, checking if it exists to avoid linking warnings.
|
||||
if (gb_file_exists("/opt/homebrew/lib")) {
|
||||
platform_lib_str = gb_string_appendc(platform_lib_str, " -L/opt/homebrew/lib");
|
||||
platform_lib_str = gb_string_appendc(platform_lib_str, "-L/opt/homebrew/lib ");
|
||||
}
|
||||
|
||||
// MacPort's default library path, checking if it exists to avoid linking warnings.
|
||||
if (gb_file_exists("/opt/local/lib")) {
|
||||
platform_lib_str = gb_string_appendc(platform_lib_str, " -L/opt/local/lib");
|
||||
platform_lib_str = gb_string_appendc(platform_lib_str, "-L/opt/local/lib ");
|
||||
}
|
||||
|
||||
#if defined(GB_SYSTEM_OSX)
|
||||
if(!build_context.no_crt) {
|
||||
platform_lib_str = gb_string_appendc(platform_lib_str, " -lm ");
|
||||
if(gen->needs_system_library_linked == 1) {
|
||||
platform_lib_str = gb_string_appendc(platform_lib_str, " -lSystem ");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
platform_lib_str = gb_string_appendc(platform_lib_str, "-lc -lm");
|
||||
}
|
||||
|
||||
if (build_context.metrics.os == TargetOs_darwin) {
|
||||
// This sets a requirement of Mountain Lion and up, but the compiler doesn't work without this limit.
|
||||
if (build_context.minimum_os_version_string.len) {
|
||||
link_settings = gb_string_append_fmt(link_settings, " -mmacosx-version-min=%.*s ", LIT(build_context.minimum_os_version_string));
|
||||
link_settings = gb_string_append_fmt(link_settings, "-mmacosx-version-min=%.*s ", LIT(build_context.minimum_os_version_string));
|
||||
}
|
||||
// This points the linker to where the entry point is
|
||||
link_settings = gb_string_appendc(link_settings, " -e _main ");
|
||||
link_settings = gb_string_appendc(link_settings, "-e _main ");
|
||||
}
|
||||
|
||||
if (!build_context.no_crt) {
|
||||
platform_lib_str = gb_string_appendc(platform_lib_str, "-lm ");
|
||||
if (build_context.metrics.os == TargetOs_darwin) {
|
||||
platform_lib_str = gb_string_appendc(platform_lib_str, "-lSystem ");
|
||||
} else {
|
||||
platform_lib_str = gb_string_appendc(platform_lib_str, "-lc ");
|
||||
}
|
||||
}
|
||||
|
||||
gbString link_command_line = gb_string_make(heap_allocator(), "clang -Wno-unused-command-line-argument ");
|
||||
|
||||
@@ -567,6 +567,8 @@ gb_internal LLVMTypeRef lb_type_internal_for_procedures_raw(lbModule *m, Type *t
|
||||
|
||||
gb_internal lbValue lb_emit_source_code_location_as_global_ptr(lbProcedure *p, String const &procedure, TokenPos const &pos);
|
||||
|
||||
gb_internal LLVMMetadataRef lb_debug_location_from_token_pos(lbProcedure *p, TokenPos pos);
|
||||
|
||||
gb_internal LLVMTypeRef llvm_array_type(LLVMTypeRef ElementType, uint64_t ElementCount) {
|
||||
#if LB_USE_NEW_PASS_SYSTEM
|
||||
return LLVMArrayType2(ElementType, ElementCount);
|
||||
|
||||
@@ -380,9 +380,19 @@ gb_internal void lb_run_remove_dead_instruction_pass(lbProcedure *p) {
|
||||
}
|
||||
}
|
||||
|
||||
gb_internal LLVMValueRef lb_run_instrumentation_pass_insert_call(lbProcedure *p, Entity *entity, LLVMBuilderRef dummy_builder) {
|
||||
gb_internal LLVMValueRef lb_run_instrumentation_pass_insert_call(lbProcedure *p, Entity *entity, LLVMBuilderRef dummy_builder, bool is_enter) {
|
||||
lbModule *m = p->module;
|
||||
|
||||
if (p->debug_info != nullptr) {
|
||||
TokenPos pos = {};
|
||||
if (is_enter) {
|
||||
pos = ast_token(p->body).pos;
|
||||
} else {
|
||||
pos = ast_end_token(p->body).pos;
|
||||
}
|
||||
LLVMSetCurrentDebugLocation2(dummy_builder, lb_debug_location_from_token_pos(p, pos));
|
||||
}
|
||||
|
||||
lbValue cc = lb_find_procedure_value_from_entity(m, entity);
|
||||
|
||||
LLVMValueRef args[3] = {};
|
||||
@@ -430,7 +440,7 @@ gb_internal void lb_run_instrumentation_pass(lbProcedure *p) {
|
||||
|
||||
LLVMBasicBlockRef entry_bb = p->entry_block->block;
|
||||
LLVMPositionBuilder(dummy_builder, entry_bb, LLVMGetFirstInstruction(entry_bb));
|
||||
lb_run_instrumentation_pass_insert_call(p, enter, dummy_builder);
|
||||
lb_run_instrumentation_pass_insert_call(p, enter, dummy_builder, true);
|
||||
LLVMRemoveStringAttributeAtIndex(p->value, LLVMAttributeIndex_FunctionIndex, LLVM_V_NAME("instrument-function-entry"));
|
||||
|
||||
unsigned bb_count = LLVMCountBasicBlocks(p->value);
|
||||
@@ -451,7 +461,7 @@ gb_internal void lb_run_instrumentation_pass(lbProcedure *p) {
|
||||
|
||||
|
||||
LLVMPositionBuilderBefore(dummy_builder, terminator);
|
||||
lb_run_instrumentation_pass_insert_call(p, exit, dummy_builder);
|
||||
lb_run_instrumentation_pass_insert_call(p, exit, dummy_builder, false);
|
||||
}
|
||||
|
||||
LLVMRemoveStringAttributeAtIndex(p->value, LLVMAttributeIndex_FunctionIndex, LLVM_V_NAME("instrument-function-exit"));
|
||||
@@ -471,6 +481,8 @@ gb_internal void lb_run_function_pass_manager(LLVMPassManagerRef fpm, lbProcedur
|
||||
// are not removed
|
||||
lb_run_remove_dead_instruction_pass(p);
|
||||
|
||||
lb_run_instrumentation_pass(p);
|
||||
|
||||
switch (pass_manager_kind) {
|
||||
case lbFunctionPassManager_none:
|
||||
return;
|
||||
@@ -481,7 +493,6 @@ gb_internal void lb_run_function_pass_manager(LLVMPassManagerRef fpm, lbProcedur
|
||||
}
|
||||
break;
|
||||
}
|
||||
lb_run_instrumentation_pass(p);
|
||||
|
||||
LLVMRunFunctionPassManager(fpm, p->value);
|
||||
}
|
||||
|
||||
+51
-14
@@ -1693,24 +1693,61 @@ gb_internal lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValu
|
||||
case BuiltinProc_DIRECTIVE: {
|
||||
ast_node(bd, BasicDirective, ce->proc);
|
||||
String name = bd->name.string;
|
||||
GB_ASSERT(name == "location");
|
||||
String procedure = p->entity->token.string;
|
||||
TokenPos pos = ast_token(ce->proc).pos;
|
||||
if (ce->args.count > 0) {
|
||||
Ast *ident = unselector_expr(ce->args[0]);
|
||||
GB_ASSERT(ident->kind == Ast_Ident);
|
||||
Entity *e = entity_of_node(ident);
|
||||
GB_ASSERT(e != nullptr);
|
||||
if (name == "location") {
|
||||
String procedure = p->entity->token.string;
|
||||
TokenPos pos = ast_token(ce->proc).pos;
|
||||
if (ce->args.count > 0) {
|
||||
Ast *ident = unselector_expr(ce->args[0]);
|
||||
GB_ASSERT(ident->kind == Ast_Ident);
|
||||
Entity *e = entity_of_node(ident);
|
||||
GB_ASSERT(e != nullptr);
|
||||
|
||||
if (e->parent_proc_decl != nullptr && e->parent_proc_decl->entity != nullptr) {
|
||||
procedure = e->parent_proc_decl->entity->token.string;
|
||||
} else {
|
||||
procedure = str_lit("");
|
||||
}
|
||||
pos = e->token.pos;
|
||||
|
||||
if (e->parent_proc_decl != nullptr && e->parent_proc_decl->entity != nullptr) {
|
||||
procedure = e->parent_proc_decl->entity->token.string;
|
||||
} else {
|
||||
procedure = str_lit("");
|
||||
}
|
||||
pos = e->token.pos;
|
||||
return lb_emit_source_code_location_as_global(p, procedure, pos);
|
||||
} else if (name == "load_directory") {
|
||||
lbModule *m = p->module;
|
||||
TEMPORARY_ALLOCATOR_GUARD();
|
||||
LoadDirectoryCache *cache = map_must_get(&m->info->load_directory_map, expr);
|
||||
isize count = cache->files.count;
|
||||
|
||||
LLVMValueRef *elements = gb_alloc_array(temporary_allocator(), LLVMValueRef, count);
|
||||
for_array(i, cache->files) {
|
||||
LoadFileCache *file = cache->files[i];
|
||||
|
||||
String file_name = filename_without_directory(file->path);
|
||||
|
||||
LLVMValueRef values[2] = {};
|
||||
values[0] = lb_const_string(m, file_name).value;
|
||||
values[1] = lb_const_string(m, file->data).value;
|
||||
LLVMValueRef element = llvm_const_named_struct(m, t_load_directory_file, values, gb_count_of(values));
|
||||
elements[i] = element;
|
||||
}
|
||||
|
||||
LLVMValueRef backing_array = llvm_const_array(lb_type(m, t_load_directory_file), elements, count);
|
||||
|
||||
Type *array_type = alloc_type_array(t_load_directory_file, count);
|
||||
lbAddr backing_array_addr = lb_add_global_generated(m, array_type, {backing_array, array_type}, nullptr);
|
||||
lb_make_global_private_const(backing_array_addr);
|
||||
|
||||
LLVMValueRef backing_array_ptr = backing_array_addr.addr.value;
|
||||
backing_array_ptr = LLVMConstPointerCast(backing_array_ptr, lb_type(m, t_load_directory_file_ptr));
|
||||
|
||||
LLVMValueRef const_slice = llvm_const_slice_internal(m, backing_array_ptr, LLVMConstInt(lb_type(m, t_int), count, false));
|
||||
|
||||
lbAddr addr = lb_add_global_generated(p->module, tv.type, {const_slice, t_load_directory_file_slice}, nullptr);
|
||||
lb_make_global_private_const(addr);
|
||||
|
||||
return lb_addr_load(p, addr);
|
||||
} else {
|
||||
GB_PANIC("UNKNOWN DIRECTIVE: %.*s", LIT(name));
|
||||
}
|
||||
return lb_emit_source_code_location_as_global(p, procedure, pos);
|
||||
}
|
||||
|
||||
case BuiltinProc_type_info_of: {
|
||||
|
||||
@@ -293,6 +293,18 @@ gb_internal String filename_from_path(String s) {
|
||||
return make_string(nullptr, 0);
|
||||
}
|
||||
|
||||
|
||||
gb_internal String filename_without_directory(String s) {
|
||||
isize j = 0;
|
||||
for (j = s.len-1; j >= 0; j--) {
|
||||
if (s[j] == '/' ||
|
||||
s[j] == '\\') {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return substring(s, gb_max(j+1, 0), s.len);
|
||||
}
|
||||
|
||||
gb_internal String concatenate_strings(gbAllocator a, String const &x, String const &y) {
|
||||
isize len = x.len+y.len;
|
||||
u8 *data = gb_alloc_array(a, u8, len+1);
|
||||
|
||||
@@ -679,6 +679,10 @@ gb_global Type *t_allocator_error = nullptr;
|
||||
gb_global Type *t_source_code_location = nullptr;
|
||||
gb_global Type *t_source_code_location_ptr = nullptr;
|
||||
|
||||
gb_global Type *t_load_directory_file = nullptr;
|
||||
gb_global Type *t_load_directory_file_ptr = nullptr;
|
||||
gb_global Type *t_load_directory_file_slice = nullptr;
|
||||
|
||||
gb_global Type *t_map_info = nullptr;
|
||||
gb_global Type *t_map_cell_info = nullptr;
|
||||
gb_global Type *t_raw_map = nullptr;
|
||||
|
||||
Reference in New Issue
Block a user