| author | |
| committer | |
| log | 5e33175517807c6e50fe66f8d6c65fc094c8e11a |
| tree | 004fc843be6c452f0c925915d080b8ab09432723 |
| parent | 832454f38b3ef635ee03fb54c382d8be02ac7c9e |
7 files changed, 98 insertions(+), 4 deletions(-)
src/all_types.hpp+1| ... | ... | @@ -1088,6 +1088,7 @@ enum BuiltinFnId { |
| 1088 | 1088 | BuiltinFnIdCImport, |
| 1089 | 1089 | BuiltinFnIdErrName, |
| 1090 | 1090 | BuiltinFnIdBreakpoint, |
| 1091 | BuiltinFnIdEmbedFile, | |
| 1091 | 1092 | }; |
| 1092 | 1093 | |
| 1093 | 1094 | struct BuiltinFnEntry { |
src/analyze.cpp+41| ... | ... | @@ -4101,6 +4101,45 @@ static TypeTableEntry *analyze_err_name(CodeGen *g, ImportTableEntry *import, |
| 4101 | 4101 | return str_type; |
| 4102 | 4102 | } |
| 4103 | 4103 | |
| 4104 | static TypeTableEntry *analyze_embed_file(CodeGen *g, ImportTableEntry *import, | |
| 4105 | BlockContext *context, AstNode *node) | |
| 4106 | { | |
| 4107 | assert(node->type == NodeTypeFnCallExpr); | |
| 4108 | ||
| 4109 | AstNode **first_param_node = &node->data.fn_call_expr.params.at(0); | |
| 4110 | Buf *rel_file_path = resolve_const_expr_str(g, import, context, first_param_node); | |
| 4111 | if (!rel_file_path) { | |
| 4112 | return g->builtin_types.entry_invalid; | |
| 4113 | } | |
| 4114 | ||
| 4115 | // figure out absolute path to resource | |
| 4116 | Buf source_dir_path = BUF_INIT; | |
| 4117 | os_path_dirname(import->path, &source_dir_path); | |
| 4118 | ||
| 4119 | Buf file_path = BUF_INIT; | |
| 4120 | os_path_resolve(&source_dir_path, rel_file_path, &file_path); | |
| 4121 | ||
| 4122 | // load from file system into const expr | |
| 4123 | Buf file_contents = BUF_INIT; | |
| 4124 | int err; | |
| 4125 | if ((err = os_fetch_file_path(&file_path, &file_contents))) { | |
| 4126 | if (err == ErrorFileNotFound) { | |
| 4127 | add_node_error(g, node, | |
| 4128 | buf_sprintf("unable to find '%s'", buf_ptr(&file_path))); | |
| 4129 | return g->builtin_types.entry_invalid; | |
| 4130 | } else { | |
| 4131 | add_node_error(g, node, | |
| 4132 | buf_sprintf("unable to open '%s': %s", buf_ptr(&file_path), err_str(err))); | |
| 4133 | return g->builtin_types.entry_invalid; | |
| 4134 | } | |
| 4135 | } | |
| 4136 | ||
| 4137 | // TODO add dependency on the file we embedded so that we know if it changes | |
| 4138 | // we'll have to invalidate the cache | |
| 4139 | ||
| 4140 | return resolve_expr_const_val_as_string_lit(g, node, &file_contents); | |
| 4141 | } | |
| 4142 | ||
| 4104 | 4143 | static TypeTableEntry *analyze_builtin_fn_call_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, |
| 4105 | 4144 | TypeTableEntry *expected_type, AstNode *node) |
| 4106 | 4145 | { |
| ... | ... | @@ -4434,6 +4473,8 @@ static TypeTableEntry *analyze_builtin_fn_call_expr(CodeGen *g, ImportTableEntry |
| 4434 | 4473 | case BuiltinFnIdBreakpoint: |
| 4435 | 4474 | mark_impure_fn(context); |
| 4436 | 4475 | return g->builtin_types.entry_void; |
| 4476 | case BuiltinFnIdEmbedFile: | |
| 4477 | return analyze_embed_file(g, import, context, node); | |
| 4437 | 4478 | } |
| 4438 | 4479 | zig_unreachable(); |
| 4439 | 4480 | } |
src/codegen.cpp+2| ... | ... | @@ -507,6 +507,7 @@ static LLVMValueRef gen_builtin_fn_call_expr(CodeGen *g, AstNode *node) { |
| 507 | 507 | case BuiltinFnIdMaxValue: |
| 508 | 508 | case BuiltinFnIdMemberCount: |
| 509 | 509 | case BuiltinFnIdConstEval: |
| 510 | case BuiltinFnIdEmbedFile: | |
| 510 | 511 | // caught by constant expression eval codegen |
| 511 | 512 | zig_unreachable(); |
| 512 | 513 | case BuiltinFnIdCompileVar: |
| ... | ... | @@ -3896,6 +3897,7 @@ static void define_builtin_fns(CodeGen *g) { |
| 3896 | 3897 | create_builtin_fn_with_arg_count(g, BuiltinFnIdImport, "import", 1); |
| 3897 | 3898 | create_builtin_fn_with_arg_count(g, BuiltinFnIdCImport, "c_import", 1); |
| 3898 | 3899 | create_builtin_fn_with_arg_count(g, BuiltinFnIdErrName, "err_name", 1); |
| 3900 | create_builtin_fn_with_arg_count(g, BuiltinFnIdEmbedFile, "embed_file", 1); | |
| 3899 | 3901 | } |
| 3900 | 3902 | |
| 3901 | 3903 | static void init(CodeGen *g, Buf *source_path) { |
src/eval.cpp+1| ... | ... | @@ -696,6 +696,7 @@ static bool eval_fn_call_builtin(EvalFn *ef, AstNode *node, ConstExprValue *out_ |
| 696 | 696 | case BuiltinFnIdImport: |
| 697 | 697 | case BuiltinFnIdCImport: |
| 698 | 698 | case BuiltinFnIdErrName: |
| 699 | case BuiltinFnIdEmbedFile: | |
| 699 | 700 | zig_panic("TODO"); |
| 700 | 701 | case BuiltinFnIdBreakpoint: |
| 701 | 702 | case BuiltinFnIdInvalid: |
src/os.cpp+32-4| ... | ... | @@ -91,6 +91,10 @@ void os_spawn_process(const char *exe, ZigList<const char *> &args, int *return_ |
| 91 | 91 | #endif |
| 92 | 92 | } |
| 93 | 93 | |
| 94 | void os_path_dirname(Buf *full_path, Buf *out_dirname) { | |
| 95 | return os_path_split(full_path, out_dirname, nullptr); | |
| 96 | } | |
| 97 | ||
| 94 | 98 | void os_path_split(Buf *full_path, Buf *out_dirname, Buf *out_basename) { |
| 95 | 99 | int last_index = buf_len(full_path) - 1; |
| 96 | 100 | 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) { |
| 99 | 103 | for (int i = last_index; i >= 0; i -= 1) { |
| 100 | 104 | uint8_t c = buf_ptr(full_path)[i]; |
| 101 | 105 | if (c == '/') { |
| 102 | buf_init_from_mem(out_dirname, buf_ptr(full_path), i); | |
| 103 | buf_init_from_mem(out_basename, buf_ptr(full_path) + i + 1, buf_len(full_path) - (i + 1)); | |
| 106 | if (out_dirname) { | |
| 107 | buf_init_from_mem(out_dirname, buf_ptr(full_path), i); | |
| 108 | } | |
| 109 | if (out_basename) { | |
| 110 | buf_init_from_mem(out_basename, buf_ptr(full_path) + i + 1, buf_len(full_path) - (i + 1)); | |
| 111 | } | |
| 104 | 112 | return; |
| 105 | 113 | } |
| 106 | 114 | } |
| 107 | buf_init_from_mem(out_dirname, ".", 1); | |
| 108 | buf_init_from_buf(out_basename, full_path); | |
| 115 | if (out_dirname) buf_init_from_mem(out_dirname, ".", 1); | |
| 116 | if (out_basename) buf_init_from_buf(out_basename, full_path); | |
| 109 | 117 | } |
| 110 | 118 | |
| 111 | 119 | 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) { |
| 146 | 154 | #endif |
| 147 | 155 | } |
| 148 | 156 | |
| 157 | bool os_path_is_absolute(Buf *path) { | |
| 158 | #if defined(ZIG_OS_WINDOWS) | |
| 159 | #error "missing os_path_is_absolute implementation" | |
| 160 | #elif defined(ZIG_OS_POSIX) | |
| 161 | return buf_ptr(path)[0] == '/'; | |
| 162 | #else | |
| 163 | #error "missing os_path_is_absolute implementation" | |
| 164 | #endif | |
| 165 | } | |
| 166 | ||
| 167 | void os_path_resolve(Buf *ref_path, Buf *target_path, Buf *out_abs_path) { | |
| 168 | if (os_path_is_absolute(target_path)) { | |
| 169 | buf_init_from_buf(out_abs_path, target_path); | |
| 170 | return; | |
| 171 | } | |
| 172 | ||
| 173 | os_path_join(ref_path, target_path, out_abs_path); | |
| 174 | return; | |
| 175 | } | |
| 176 | ||
| 149 | 177 | int os_fetch_file(FILE *f, Buf *out_buf) { |
| 150 | 178 | static const ssize_t buf_size = 0x2000; |
| 151 | 179 | buf_resize(out_buf, buf_size); |
src/os.hpp+3| ... | ... | @@ -18,9 +18,12 @@ void os_spawn_process(const char *exe, ZigList<const char *> &args, int *return_ |
| 18 | 18 | int os_exec_process(const char *exe, ZigList<const char *> &args, |
| 19 | 19 | int *return_code, Buf *out_stderr, Buf *out_stdout); |
| 20 | 20 | |
| 21 | void os_path_dirname(Buf *full_path, Buf *out_dirname); | |
| 21 | 22 | void os_path_split(Buf *full_path, Buf *out_dirname, Buf *out_basename); |
| 22 | 23 | void os_path_join(Buf *dirname, Buf *basename, Buf *out_full_path); |
| 23 | 24 | int os_path_real(Buf *rel_path, Buf *out_abs_path); |
| 25 | void os_path_resolve(Buf *ref_path, Buf *target_path, Buf *out_abs_path); | |
| 26 | bool os_path_is_absolute(Buf *path); | |
| 24 | 27 | |
| 25 | 28 | void os_write_file(Buf *full_path, Buf *contents); |
| 26 | 29 |
test/run_tests.cpp+18| ... | ... | @@ -600,6 +600,20 @@ fn do_test() -> %void { |
| 600 | 600 | } |
| 601 | 601 | fn its_gonna_pass() -> %void { } |
| 602 | 602 | )SOURCE", "before\nafter\ndefer3\ndefer1\n"); |
| 603 | ||
| 604 | ||
| 605 | { | |
| 606 | TestCase *tc = add_simple_case("@embed_file", R"SOURCE( | |
| 607 | const foo_txt = @embed_file("foo.txt"); | |
| 608 | const io = @import("std").io; | |
| 609 | ||
| 610 | pub fn main(args: [][]u8) -> %void { | |
| 611 | %%io.stdout.printf(foo_txt); | |
| 612 | } | |
| 613 | )SOURCE", "1234\nabcd\n"); | |
| 614 | ||
| 615 | add_source_file(tc, "foo.txt", "1234\nabcd\n"); | |
| 616 | } | |
| 603 | 617 | } |
| 604 | 618 | |
| 605 | 619 | |
| ... | ... | @@ -1173,6 +1187,10 @@ fn fibbonaci(x: i32) -> i32 { |
| 1173 | 1187 | ".tmp_source.zig:3:1: error: function evaluation exceeded 1000 branches", |
| 1174 | 1188 | ".tmp_source.zig:2:37: note: called from here", |
| 1175 | 1189 | ".tmp_source.zig:4:40: note: quota exceeded here"); |
| 1190 | ||
| 1191 | add_compile_fail_case("@embed_file with bogus file", R"SOURCE( | |
| 1192 | const resource = @embed_file("bogus.txt"); | |
| 1193 | )SOURCE", 1, ".tmp_source.zig:2:18: error: unable to find './bogus.txt'"); | |
| 1176 | 1194 | } |
| 1177 | 1195 | |
| 1178 | 1196 | ////////////////////////////////////////////////////////////////////////////// |