authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-04-18 15:47:21-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-04-18 15:47:21-07:00
log5e33175517807c6e50fe66f8d6c65fc094c8e11a
tree004fc843be6c452f0c925915d080b8ab09432723
parent832454f38b3ef635ee03fb54c382d8be02ac7c9e

add @embed_file builtin function


7 files changed, 98 insertions(+), 4 deletions(-)

src/all_types.hpp+1
...@@ -1088,6 +1088,7 @@ enum BuiltinFnId {...@@ -1088,6 +1088,7 @@ enum BuiltinFnId {
1088 BuiltinFnIdCImport,1088 BuiltinFnIdCImport,
1089 BuiltinFnIdErrName,1089 BuiltinFnIdErrName,
1090 BuiltinFnIdBreakpoint,1090 BuiltinFnIdBreakpoint,
1091 BuiltinFnIdEmbedFile,
1091};1092};
10921093
1093struct BuiltinFnEntry {1094struct BuiltinFnEntry {
src/analyze.cpp+41
...@@ -4101,6 +4101,45 @@ static TypeTableEntry *analyze_err_name(CodeGen *g, ImportTableEntry *import,...@@ -4101,6 +4101,45 @@ static TypeTableEntry *analyze_err_name(CodeGen *g, ImportTableEntry *import,
4101 return str_type;4101 return str_type;
4102}4102}
41034103
4104static 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
4104static TypeTableEntry *analyze_builtin_fn_call_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,4143static TypeTableEntry *analyze_builtin_fn_call_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
4105 TypeTableEntry *expected_type, AstNode *node)4144 TypeTableEntry *expected_type, AstNode *node)
4106{4145{
...@@ -4434,6 +4473,8 @@ static TypeTableEntry *analyze_builtin_fn_call_expr(CodeGen *g, ImportTableEntry...@@ -4434,6 +4473,8 @@ static TypeTableEntry *analyze_builtin_fn_call_expr(CodeGen *g, ImportTableEntry
4434 case BuiltinFnIdBreakpoint:4473 case BuiltinFnIdBreakpoint:
4435 mark_impure_fn(context);4474 mark_impure_fn(context);
4436 return g->builtin_types.entry_void;4475 return g->builtin_types.entry_void;
4476 case BuiltinFnIdEmbedFile:
4477 return analyze_embed_file(g, import, context, node);
4437 }4478 }
4438 zig_unreachable();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,6 +507,7 @@ static LLVMValueRef gen_builtin_fn_call_expr(CodeGen *g, AstNode *node) {
507 case BuiltinFnIdMaxValue:507 case BuiltinFnIdMaxValue:
508 case BuiltinFnIdMemberCount:508 case BuiltinFnIdMemberCount:
509 case BuiltinFnIdConstEval:509 case BuiltinFnIdConstEval:
510 case BuiltinFnIdEmbedFile:
510 // caught by constant expression eval codegen511 // caught by constant expression eval codegen
511 zig_unreachable();512 zig_unreachable();
512 case BuiltinFnIdCompileVar:513 case BuiltinFnIdCompileVar:
...@@ -3896,6 +3897,7 @@ static void define_builtin_fns(CodeGen *g) {...@@ -3896,6 +3897,7 @@ static void define_builtin_fns(CodeGen *g) {
3896 create_builtin_fn_with_arg_count(g, BuiltinFnIdImport, "import", 1);3897 create_builtin_fn_with_arg_count(g, BuiltinFnIdImport, "import", 1);
3897 create_builtin_fn_with_arg_count(g, BuiltinFnIdCImport, "c_import", 1);3898 create_builtin_fn_with_arg_count(g, BuiltinFnIdCImport, "c_import", 1);
3898 create_builtin_fn_with_arg_count(g, BuiltinFnIdErrName, "err_name", 1);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}
39003902
3901static void init(CodeGen *g, Buf *source_path) {3903static 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,6 +696,7 @@ static bool eval_fn_call_builtin(EvalFn *ef, AstNode *node, ConstExprValue *out_
696 case BuiltinFnIdImport:696 case BuiltinFnIdImport:
697 case BuiltinFnIdCImport:697 case BuiltinFnIdCImport:
698 case BuiltinFnIdErrName:698 case BuiltinFnIdErrName:
699 case BuiltinFnIdEmbedFile:
699 zig_panic("TODO");700 zig_panic("TODO");
700 case BuiltinFnIdBreakpoint:701 case BuiltinFnIdBreakpoint:
701 case BuiltinFnIdInvalid: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,6 +91,10 @@ void os_spawn_process(const char *exe, ZigList<const char *> &args, int *return_
91#endif91#endif
92}92}
9393
94void os_path_dirname(Buf *full_path, Buf *out_dirname) {
95 return os_path_split(full_path, out_dirname, nullptr);
96}
97
94void os_path_split(Buf *full_path, Buf *out_dirname, Buf *out_basename) {98void os_path_split(Buf *full_path, Buf *out_dirname, Buf *out_basename) {
95 int last_index = buf_len(full_path) - 1;99 int last_index = buf_len(full_path) - 1;
96 if (last_index >= 0 && buf_ptr(full_path)[last_index] == '/') {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,13 +103,17 @@ void os_path_split(Buf *full_path, Buf *out_dirname, Buf *out_basename) {
99 for (int i = last_index; i >= 0; i -= 1) {103 for (int i = last_index; i >= 0; i -= 1) {
100 uint8_t c = buf_ptr(full_path)[i];104 uint8_t c = buf_ptr(full_path)[i];
101 if (c == '/') {105 if (c == '/') {
102 buf_init_from_mem(out_dirname, buf_ptr(full_path), i);106 if (out_dirname) {
103 buf_init_from_mem(out_basename, buf_ptr(full_path) + i + 1, buf_len(full_path) - (i + 1));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 return;112 return;
105 }113 }
106 }114 }
107 buf_init_from_mem(out_dirname, ".", 1);115 if (out_dirname) buf_init_from_mem(out_dirname, ".", 1);
108 buf_init_from_buf(out_basename, full_path);116 if (out_basename) buf_init_from_buf(out_basename, full_path);
109}117}
110118
111void os_path_join(Buf *dirname, Buf *basename, Buf *out_full_path) {119void 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,6 +154,26 @@ int os_path_real(Buf *rel_path, Buf *out_abs_path) {
146#endif154#endif
147}155}
148156
157bool 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
167void 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
149int os_fetch_file(FILE *f, Buf *out_buf) {177int os_fetch_file(FILE *f, Buf *out_buf) {
150 static const ssize_t buf_size = 0x2000;178 static const ssize_t buf_size = 0x2000;
151 buf_resize(out_buf, buf_size);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,9 +18,12 @@ void os_spawn_process(const char *exe, ZigList<const char *> &args, int *return_
18int os_exec_process(const char *exe, ZigList<const char *> &args,18int os_exec_process(const char *exe, ZigList<const char *> &args,
19 int *return_code, Buf *out_stderr, Buf *out_stdout);19 int *return_code, Buf *out_stderr, Buf *out_stdout);
2020
21void os_path_dirname(Buf *full_path, Buf *out_dirname);
21void os_path_split(Buf *full_path, Buf *out_dirname, Buf *out_basename);22void os_path_split(Buf *full_path, Buf *out_dirname, Buf *out_basename);
22void os_path_join(Buf *dirname, Buf *basename, Buf *out_full_path);23void os_path_join(Buf *dirname, Buf *basename, Buf *out_full_path);
23int os_path_real(Buf *rel_path, Buf *out_abs_path);24int os_path_real(Buf *rel_path, Buf *out_abs_path);
25void os_path_resolve(Buf *ref_path, Buf *target_path, Buf *out_abs_path);
26bool os_path_is_absolute(Buf *path);
2427
25void os_write_file(Buf *full_path, Buf *contents);28void os_write_file(Buf *full_path, Buf *contents);
2629
test/run_tests.cpp+18
...@@ -600,6 +600,20 @@ fn do_test() -> %void {...@@ -600,6 +600,20 @@ fn do_test() -> %void {
600}600}
601fn its_gonna_pass() -> %void { }601fn its_gonna_pass() -> %void { }
602 )SOURCE", "before\nafter\ndefer3\ndefer1\n");602 )SOURCE", "before\nafter\ndefer3\ndefer1\n");
603
604
605 {
606 TestCase *tc = add_simple_case("@embed_file", R"SOURCE(
607const foo_txt = @embed_file("foo.txt");
608const io = @import("std").io;
609
610pub 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}
604618
605619
...@@ -1173,6 +1187,10 @@ fn fibbonaci(x: i32) -> i32 {...@@ -1173,6 +1187,10 @@ fn fibbonaci(x: i32) -> i32 {
1173 ".tmp_source.zig:3:1: error: function evaluation exceeded 1000 branches",1187 ".tmp_source.zig:3:1: error: function evaluation exceeded 1000 branches",
1174 ".tmp_source.zig:2:37: note: called from here",1188 ".tmp_source.zig:2:37: note: called from here",
1175 ".tmp_source.zig:4:40: note: quota exceeded here");1189 ".tmp_source.zig:4:40: note: quota exceeded here");
1190
1191 add_compile_fail_case("@embed_file with bogus file", R"SOURCE(
1192const resource = @embed_file("bogus.txt");
1193 )SOURCE", 1, ".tmp_source.zig:2:18: error: unable to find './bogus.txt'");
1176}1194}
11771195
1178//////////////////////////////////////////////////////////////////////////////1196//////////////////////////////////////////////////////////////////////////////