|
@@ -1079,7 +1079,7 @@ gb_internal bool check_builtin_simd_operation(CheckerContext *c, Operand *operan
|
|
return false;
|
|
return false;
|
|
}
|
|
}
|
|
|
|
|
|
-gb_internal bool cache_load_file_directive(CheckerContext *c, Ast *call, String const &original_string, bool err_on_not_found, LoadFileCache **cache_) {
|
|
|
|
|
|
+gb_internal bool cache_load_file_directive(CheckerContext *c, Ast *call, String const &original_string, bool err_on_not_found, LoadFileCache **cache_, LoadFileTier tier) {
|
|
ast_node(ce, CallExpr, call);
|
|
ast_node(ce, CallExpr, call);
|
|
ast_node(bd, BasicDirective, ce->proc);
|
|
ast_node(bd, BasicDirective, ce->proc);
|
|
String builtin_name = bd->name.string;
|
|
String builtin_name = bd->name.string;
|
|
@@ -1105,12 +1105,16 @@ gb_internal bool cache_load_file_directive(CheckerContext *c, Ast *call, String
|
|
|
|
|
|
gbFileError file_error = gbFileError_None;
|
|
gbFileError file_error = gbFileError_None;
|
|
String data = {};
|
|
String data = {};
|
|
|
|
+ bool exists = false;
|
|
|
|
+ LoadFileTier cache_tier = LoadFileTier_Invalid;
|
|
|
|
|
|
LoadFileCache **cache_ptr = string_map_get(&c->info->load_file_cache, path);
|
|
LoadFileCache **cache_ptr = string_map_get(&c->info->load_file_cache, path);
|
|
LoadFileCache *cache = cache_ptr ? *cache_ptr : nullptr;
|
|
LoadFileCache *cache = cache_ptr ? *cache_ptr : nullptr;
|
|
if (cache) {
|
|
if (cache) {
|
|
file_error = cache->file_error;
|
|
file_error = cache->file_error;
|
|
data = cache->data;
|
|
data = cache->data;
|
|
|
|
+ exists = cache->exists;
|
|
|
|
+ cache_tier = cache->tier;
|
|
}
|
|
}
|
|
defer ({
|
|
defer ({
|
|
if (cache == nullptr) {
|
|
if (cache == nullptr) {
|
|
@@ -1118,60 +1122,78 @@ gb_internal bool cache_load_file_directive(CheckerContext *c, Ast *call, String
|
|
new_cache->path = path;
|
|
new_cache->path = path;
|
|
new_cache->data = data;
|
|
new_cache->data = data;
|
|
new_cache->file_error = file_error;
|
|
new_cache->file_error = file_error;
|
|
|
|
+ new_cache->exists = exists;
|
|
|
|
+ new_cache->tier = cache_tier;
|
|
string_map_init(&new_cache->hashes, 32);
|
|
string_map_init(&new_cache->hashes, 32);
|
|
string_map_set(&c->info->load_file_cache, path, new_cache);
|
|
string_map_set(&c->info->load_file_cache, path, new_cache);
|
|
if (cache_) *cache_ = new_cache;
|
|
if (cache_) *cache_ = new_cache;
|
|
} else {
|
|
} else {
|
|
cache->data = data;
|
|
cache->data = data;
|
|
cache->file_error = file_error;
|
|
cache->file_error = file_error;
|
|
|
|
+ cache->exists = exists;
|
|
|
|
+ cache->tier = cache_tier;
|
|
if (cache_) *cache_ = cache;
|
|
if (cache_) *cache_ = cache;
|
|
}
|
|
}
|
|
});
|
|
});
|
|
|
|
|
|
- TEMPORARY_ALLOCATOR_GUARD();
|
|
|
|
- char *c_str = alloc_cstring(temporary_allocator(), path);
|
|
|
|
|
|
+ if (tier > cache_tier) {
|
|
|
|
+ cache_tier = tier;
|
|
|
|
|
|
- gbFile f = {};
|
|
|
|
- if (cache == nullptr) {
|
|
|
|
|
|
+ TEMPORARY_ALLOCATOR_GUARD();
|
|
|
|
+ char *c_str = alloc_cstring(temporary_allocator(), path);
|
|
|
|
+
|
|
|
|
+ gbFile f = {};
|
|
file_error = gb_file_open(&f, c_str);
|
|
file_error = gb_file_open(&f, c_str);
|
|
|
|
+ defer (gb_file_close(&f));
|
|
|
|
+
|
|
|
|
+ if (file_error == gbFileError_None) {
|
|
|
|
+ exists = true;
|
|
|
|
+
|
|
|
|
+ switch(tier) {
|
|
|
|
+ case LoadFileTier_Exists:
|
|
|
|
+ // Nothing to do.
|
|
|
|
+ break;
|
|
|
|
+ case LoadFileTier_Contents: {
|
|
|
|
+ isize file_size = cast(isize)gb_file_size(&f);
|
|
|
|
+ if (file_size > 0) {
|
|
|
|
+ u8 *ptr = cast(u8 *)gb_alloc(permanent_allocator(), file_size+1);
|
|
|
|
+ gb_file_read_at(&f, ptr, file_size, 0);
|
|
|
|
+ ptr[file_size] = '\0';
|
|
|
|
+ data.text = ptr;
|
|
|
|
+ data.len = file_size;
|
|
|
|
+ }
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ default:
|
|
|
|
+ GB_PANIC("Unhandled LoadFileTier");
|
|
|
|
+ };
|
|
|
|
+ }
|
|
}
|
|
}
|
|
- defer (gb_file_close(&f));
|
|
|
|
|
|
|
|
switch (file_error) {
|
|
switch (file_error) {
|
|
default:
|
|
default:
|
|
case gbFileError_Invalid:
|
|
case gbFileError_Invalid:
|
|
if (err_on_not_found) {
|
|
if (err_on_not_found) {
|
|
- error(ce->proc, "Failed to `#%.*s` file: %s; invalid file or cannot be found", LIT(builtin_name), c_str);
|
|
|
|
|
|
+ error(ce->proc, "Failed to `#%.*s` file: %.*s; invalid file or cannot be found", LIT(builtin_name), LIT(path));
|
|
}
|
|
}
|
|
call->state_flags |= StateFlag_DirectiveWasFalse;
|
|
call->state_flags |= StateFlag_DirectiveWasFalse;
|
|
return false;
|
|
return false;
|
|
case gbFileError_NotExists:
|
|
case gbFileError_NotExists:
|
|
if (err_on_not_found) {
|
|
if (err_on_not_found) {
|
|
- error(ce->proc, "Failed to `#%.*s` file: %s; file cannot be found", LIT(builtin_name), c_str);
|
|
|
|
|
|
+ error(ce->proc, "Failed to `#%.*s` file: %.*s; file cannot be found", LIT(builtin_name), LIT(path));
|
|
}
|
|
}
|
|
call->state_flags |= StateFlag_DirectiveWasFalse;
|
|
call->state_flags |= StateFlag_DirectiveWasFalse;
|
|
return false;
|
|
return false;
|
|
case gbFileError_Permission:
|
|
case gbFileError_Permission:
|
|
if (err_on_not_found) {
|
|
if (err_on_not_found) {
|
|
- error(ce->proc, "Failed to `#%.*s` file: %s; file permissions problem", LIT(builtin_name), c_str);
|
|
|
|
|
|
+ error(ce->proc, "Failed to `#%.*s` file: %.*s; file permissions problem", LIT(builtin_name), LIT(path));
|
|
}
|
|
}
|
|
call->state_flags |= StateFlag_DirectiveWasFalse;
|
|
call->state_flags |= StateFlag_DirectiveWasFalse;
|
|
return false;
|
|
return false;
|
|
case gbFileError_None:
|
|
case gbFileError_None:
|
|
// Okay
|
|
// Okay
|
|
break;
|
|
break;
|
|
- }
|
|
|
|
-
|
|
|
|
- if (cache == nullptr) {
|
|
|
|
- isize file_size = cast(isize)gb_file_size(&f);
|
|
|
|
- if (file_size > 0) {
|
|
|
|
- u8 *ptr = cast(u8 *)gb_alloc(permanent_allocator(), file_size+1);
|
|
|
|
- gb_file_read_at(&f, ptr, file_size, 0);
|
|
|
|
- ptr[file_size] = '\0';
|
|
|
|
- data.text = ptr;
|
|
|
|
- data.len = file_size;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
|
|
+ };
|
|
|
|
|
|
return true;
|
|
return true;
|
|
}
|
|
}
|
|
@@ -1263,7 +1285,7 @@ gb_internal LoadDirectiveResult check_load_directive(CheckerContext *c, Operand
|
|
operand->mode = Addressing_Constant;
|
|
operand->mode = Addressing_Constant;
|
|
|
|
|
|
LoadFileCache *cache = nullptr;
|
|
LoadFileCache *cache = nullptr;
|
|
- if (cache_load_file_directive(c, call, o.value.value_string, err_on_not_found, &cache)) {
|
|
|
|
|
|
+ if (cache_load_file_directive(c, call, o.value.value_string, err_on_not_found, &cache, LoadFileTier_Contents)) {
|
|
operand->value = exact_value_string(cache->data);
|
|
operand->value = exact_value_string(cache->data);
|
|
return LoadDirective_Success;
|
|
return LoadDirective_Success;
|
|
}
|
|
}
|
|
@@ -1345,6 +1367,8 @@ gb_internal LoadDirectiveResult check_load_directory_directive(CheckerContext *c
|
|
map_set(&c->info->load_directory_map, call, new_cache);
|
|
map_set(&c->info->load_directory_map, call, new_cache);
|
|
} else {
|
|
} else {
|
|
cache->file_error = file_error;
|
|
cache->file_error = file_error;
|
|
|
|
+
|
|
|
|
+ map_set(&c->info->load_directory_map, call, cache);
|
|
}
|
|
}
|
|
});
|
|
});
|
|
|
|
|
|
@@ -1389,7 +1413,7 @@ gb_internal LoadDirectiveResult check_load_directory_directive(CheckerContext *c
|
|
|
|
|
|
for (FileInfo fi : list) {
|
|
for (FileInfo fi : list) {
|
|
LoadFileCache *cache = nullptr;
|
|
LoadFileCache *cache = nullptr;
|
|
- if (cache_load_file_directive(c, call, fi.fullpath, err_on_not_found, &cache)) {
|
|
|
|
|
|
+ if (cache_load_file_directive(c, call, fi.fullpath, err_on_not_found, &cache, LoadFileTier_Contents)) {
|
|
array_add(&file_caches, cache);
|
|
array_add(&file_caches, cache);
|
|
} else {
|
|
} else {
|
|
result = LoadDirective_Error;
|
|
result = LoadDirective_Error;
|
|
@@ -1488,6 +1512,30 @@ gb_internal bool check_builtin_procedure_directive(CheckerContext *c, Operand *o
|
|
|
|
|
|
operand->type = t_source_code_location;
|
|
operand->type = t_source_code_location;
|
|
operand->mode = Addressing_Value;
|
|
operand->mode = Addressing_Value;
|
|
|
|
+ } else if (name == "exists") {
|
|
|
|
+ if (ce->args.count != 1) {
|
|
|
|
+ error(ce->close, "'#exists' expects 1 argument, got %td", ce->args.count);
|
|
|
|
+ return false;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ Operand o = {};
|
|
|
|
+ check_expr(c, &o, ce->args[0]);
|
|
|
|
+ if (o.mode != Addressing_Constant || !is_type_string(o.type)) {
|
|
|
|
+ error(ce->args[0], "'#exists' expected a constant string argument");
|
|
|
|
+ return false;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ operand->type = t_untyped_bool;
|
|
|
|
+ operand->mode = Addressing_Constant;
|
|
|
|
+
|
|
|
|
+ String original_string = o.value.value_string;
|
|
|
|
+ LoadFileCache *cache = nullptr;
|
|
|
|
+ if (cache_load_file_directive(c, call, original_string, /* err_on_not_found=*/ false, &cache, LoadFileTier_Exists)) {
|
|
|
|
+ operand->value = exact_value_bool(cache->exists);
|
|
|
|
+ } else {
|
|
|
|
+ operand->value = exact_value_bool(false);
|
|
|
|
+ }
|
|
|
|
+
|
|
} else if (name == "load") {
|
|
} else if (name == "load") {
|
|
return check_load_directive(c, operand, call, type_hint, true) == LoadDirective_Success;
|
|
return check_load_directive(c, operand, call, type_hint, true) == LoadDirective_Success;
|
|
} else if (name == "load_directory") {
|
|
} else if (name == "load_directory") {
|
|
@@ -1540,7 +1588,7 @@ gb_internal bool check_builtin_procedure_directive(CheckerContext *c, Operand *o
|
|
String hash_kind = o_hash.value.value_string;
|
|
String hash_kind = o_hash.value.value_string;
|
|
|
|
|
|
LoadFileCache *cache = nullptr;
|
|
LoadFileCache *cache = nullptr;
|
|
- if (cache_load_file_directive(c, call, original_string, true, &cache)) {
|
|
|
|
|
|
+ if (cache_load_file_directive(c, call, original_string, true, &cache, LoadFileTier_Contents)) {
|
|
MUTEX_GUARD(&c->info->load_file_mutex);
|
|
MUTEX_GUARD(&c->info->load_file_mutex);
|
|
// TODO(bill): make these procedures fast :P
|
|
// TODO(bill): make these procedures fast :P
|
|
u64 hash_value = 0;
|
|
u64 hash_value = 0;
|