mirror of
https://github.com/ziglang/zig.git
synced 2026-02-15 13:58:27 +00:00
add @embed_file builtin function
This commit is contained in:
parent
832454f38b
commit
5e33175517
@ -1088,6 +1088,7 @@ enum BuiltinFnId {
|
||||
BuiltinFnIdCImport,
|
||||
BuiltinFnIdErrName,
|
||||
BuiltinFnIdBreakpoint,
|
||||
BuiltinFnIdEmbedFile,
|
||||
};
|
||||
|
||||
struct BuiltinFnEntry {
|
||||
|
||||
@ -4101,6 +4101,45 @@ static TypeTableEntry *analyze_err_name(CodeGen *g, ImportTableEntry *import,
|
||||
return str_type;
|
||||
}
|
||||
|
||||
static TypeTableEntry *analyze_embed_file(CodeGen *g, ImportTableEntry *import,
|
||||
BlockContext *context, AstNode *node)
|
||||
{
|
||||
assert(node->type == NodeTypeFnCallExpr);
|
||||
|
||||
AstNode **first_param_node = &node->data.fn_call_expr.params.at(0);
|
||||
Buf *rel_file_path = resolve_const_expr_str(g, import, context, first_param_node);
|
||||
if (!rel_file_path) {
|
||||
return g->builtin_types.entry_invalid;
|
||||
}
|
||||
|
||||
// figure out absolute path to resource
|
||||
Buf source_dir_path = BUF_INIT;
|
||||
os_path_dirname(import->path, &source_dir_path);
|
||||
|
||||
Buf file_path = BUF_INIT;
|
||||
os_path_resolve(&source_dir_path, rel_file_path, &file_path);
|
||||
|
||||
// load from file system into const expr
|
||||
Buf file_contents = BUF_INIT;
|
||||
int err;
|
||||
if ((err = os_fetch_file_path(&file_path, &file_contents))) {
|
||||
if (err == ErrorFileNotFound) {
|
||||
add_node_error(g, node,
|
||||
buf_sprintf("unable to find '%s'", buf_ptr(&file_path)));
|
||||
return g->builtin_types.entry_invalid;
|
||||
} else {
|
||||
add_node_error(g, node,
|
||||
buf_sprintf("unable to open '%s': %s", buf_ptr(&file_path), err_str(err)));
|
||||
return g->builtin_types.entry_invalid;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO add dependency on the file we embedded so that we know if it changes
|
||||
// we'll have to invalidate the cache
|
||||
|
||||
return resolve_expr_const_val_as_string_lit(g, node, &file_contents);
|
||||
}
|
||||
|
||||
static TypeTableEntry *analyze_builtin_fn_call_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
|
||||
TypeTableEntry *expected_type, AstNode *node)
|
||||
{
|
||||
@ -4434,6 +4473,8 @@ static TypeTableEntry *analyze_builtin_fn_call_expr(CodeGen *g, ImportTableEntry
|
||||
case BuiltinFnIdBreakpoint:
|
||||
mark_impure_fn(context);
|
||||
return g->builtin_types.entry_void;
|
||||
case BuiltinFnIdEmbedFile:
|
||||
return analyze_embed_file(g, import, context, node);
|
||||
}
|
||||
zig_unreachable();
|
||||
}
|
||||
|
||||
@ -507,6 +507,7 @@ static LLVMValueRef gen_builtin_fn_call_expr(CodeGen *g, AstNode *node) {
|
||||
case BuiltinFnIdMaxValue:
|
||||
case BuiltinFnIdMemberCount:
|
||||
case BuiltinFnIdConstEval:
|
||||
case BuiltinFnIdEmbedFile:
|
||||
// caught by constant expression eval codegen
|
||||
zig_unreachable();
|
||||
case BuiltinFnIdCompileVar:
|
||||
@ -3896,6 +3897,7 @@ static void define_builtin_fns(CodeGen *g) {
|
||||
create_builtin_fn_with_arg_count(g, BuiltinFnIdImport, "import", 1);
|
||||
create_builtin_fn_with_arg_count(g, BuiltinFnIdCImport, "c_import", 1);
|
||||
create_builtin_fn_with_arg_count(g, BuiltinFnIdErrName, "err_name", 1);
|
||||
create_builtin_fn_with_arg_count(g, BuiltinFnIdEmbedFile, "embed_file", 1);
|
||||
}
|
||||
|
||||
static void init(CodeGen *g, Buf *source_path) {
|
||||
|
||||
@ -696,6 +696,7 @@ static bool eval_fn_call_builtin(EvalFn *ef, AstNode *node, ConstExprValue *out_
|
||||
case BuiltinFnIdImport:
|
||||
case BuiltinFnIdCImport:
|
||||
case BuiltinFnIdErrName:
|
||||
case BuiltinFnIdEmbedFile:
|
||||
zig_panic("TODO");
|
||||
case BuiltinFnIdBreakpoint:
|
||||
case BuiltinFnIdInvalid:
|
||||
|
||||
36
src/os.cpp
36
src/os.cpp
@ -91,6 +91,10 @@ void os_spawn_process(const char *exe, ZigList<const char *> &args, int *return_
|
||||
#endif
|
||||
}
|
||||
|
||||
void os_path_dirname(Buf *full_path, Buf *out_dirname) {
|
||||
return os_path_split(full_path, out_dirname, nullptr);
|
||||
}
|
||||
|
||||
void os_path_split(Buf *full_path, Buf *out_dirname, Buf *out_basename) {
|
||||
int last_index = buf_len(full_path) - 1;
|
||||
if (last_index >= 0 && buf_ptr(full_path)[last_index] == '/') {
|
||||
@ -99,13 +103,17 @@ void os_path_split(Buf *full_path, Buf *out_dirname, Buf *out_basename) {
|
||||
for (int i = last_index; i >= 0; i -= 1) {
|
||||
uint8_t c = buf_ptr(full_path)[i];
|
||||
if (c == '/') {
|
||||
buf_init_from_mem(out_dirname, buf_ptr(full_path), i);
|
||||
buf_init_from_mem(out_basename, buf_ptr(full_path) + i + 1, buf_len(full_path) - (i + 1));
|
||||
if (out_dirname) {
|
||||
buf_init_from_mem(out_dirname, buf_ptr(full_path), i);
|
||||
}
|
||||
if (out_basename) {
|
||||
buf_init_from_mem(out_basename, buf_ptr(full_path) + i + 1, buf_len(full_path) - (i + 1));
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
buf_init_from_mem(out_dirname, ".", 1);
|
||||
buf_init_from_buf(out_basename, full_path);
|
||||
if (out_dirname) buf_init_from_mem(out_dirname, ".", 1);
|
||||
if (out_basename) buf_init_from_buf(out_basename, full_path);
|
||||
}
|
||||
|
||||
void os_path_join(Buf *dirname, Buf *basename, Buf *out_full_path) {
|
||||
@ -146,6 +154,26 @@ int os_path_real(Buf *rel_path, Buf *out_abs_path) {
|
||||
#endif
|
||||
}
|
||||
|
||||
bool os_path_is_absolute(Buf *path) {
|
||||
#if defined(ZIG_OS_WINDOWS)
|
||||
#error "missing os_path_is_absolute implementation"
|
||||
#elif defined(ZIG_OS_POSIX)
|
||||
return buf_ptr(path)[0] == '/';
|
||||
#else
|
||||
#error "missing os_path_is_absolute implementation"
|
||||
#endif
|
||||
}
|
||||
|
||||
void os_path_resolve(Buf *ref_path, Buf *target_path, Buf *out_abs_path) {
|
||||
if (os_path_is_absolute(target_path)) {
|
||||
buf_init_from_buf(out_abs_path, target_path);
|
||||
return;
|
||||
}
|
||||
|
||||
os_path_join(ref_path, target_path, out_abs_path);
|
||||
return;
|
||||
}
|
||||
|
||||
int os_fetch_file(FILE *f, Buf *out_buf) {
|
||||
static const ssize_t buf_size = 0x2000;
|
||||
buf_resize(out_buf, buf_size);
|
||||
|
||||
@ -18,9 +18,12 @@ void os_spawn_process(const char *exe, ZigList<const char *> &args, int *return_
|
||||
int os_exec_process(const char *exe, ZigList<const char *> &args,
|
||||
int *return_code, Buf *out_stderr, Buf *out_stdout);
|
||||
|
||||
void os_path_dirname(Buf *full_path, Buf *out_dirname);
|
||||
void os_path_split(Buf *full_path, Buf *out_dirname, Buf *out_basename);
|
||||
void os_path_join(Buf *dirname, Buf *basename, Buf *out_full_path);
|
||||
int os_path_real(Buf *rel_path, Buf *out_abs_path);
|
||||
void os_path_resolve(Buf *ref_path, Buf *target_path, Buf *out_abs_path);
|
||||
bool os_path_is_absolute(Buf *path);
|
||||
|
||||
void os_write_file(Buf *full_path, Buf *contents);
|
||||
|
||||
|
||||
@ -600,6 +600,20 @@ fn do_test() -> %void {
|
||||
}
|
||||
fn its_gonna_pass() -> %void { }
|
||||
)SOURCE", "before\nafter\ndefer3\ndefer1\n");
|
||||
|
||||
|
||||
{
|
||||
TestCase *tc = add_simple_case("@embed_file", R"SOURCE(
|
||||
const foo_txt = @embed_file("foo.txt");
|
||||
const io = @import("std").io;
|
||||
|
||||
pub fn main(args: [][]u8) -> %void {
|
||||
%%io.stdout.printf(foo_txt);
|
||||
}
|
||||
)SOURCE", "1234\nabcd\n");
|
||||
|
||||
add_source_file(tc, "foo.txt", "1234\nabcd\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1173,6 +1187,10 @@ fn fibbonaci(x: i32) -> i32 {
|
||||
".tmp_source.zig:3:1: error: function evaluation exceeded 1000 branches",
|
||||
".tmp_source.zig:2:37: note: called from here",
|
||||
".tmp_source.zig:4:40: note: quota exceeded here");
|
||||
|
||||
add_compile_fail_case("@embed_file with bogus file", R"SOURCE(
|
||||
const resource = @embed_file("bogus.txt");
|
||||
)SOURCE", 1, ".tmp_source.zig:2:18: error: unable to find './bogus.txt'");
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user