From 46921480fc775ab172567f52a4ae4f007905c10c Mon Sep 17 00:00:00 2001 From: yuyi Date: Thu, 10 Nov 2022 10:09:51 +0800 Subject: [PATCH] comptime: fix embed file with variable argument (fix #16360) (#16375) --- vlib/v/ast/ast.v | 6 +-- vlib/v/checker/comptime.v | 41 +++++++++++++++++++ .../tests/embed_file_with_variable_arg_test.v | 6 +++ vlib/v/fmt/fmt.v | 4 +- vlib/v/parser/comptime.v | 36 +++------------- 5 files changed, 58 insertions(+), 35 deletions(-) create mode 100644 vlib/v/embed_file/tests/embed_file_with_variable_arg_test.v diff --git a/vlib/v/ast/ast.v b/vlib/v/ast/ast.v index 5f6eea627..fb074c959 100644 --- a/vlib/v/ast/ast.v +++ b/vlib/v/ast/ast.v @@ -712,10 +712,10 @@ pub mut: [minify] pub struct EmbeddedFile { pub: - rpath string // used in the source code, as an ID/key to the embed - apath string // absolute path during compilation to the resource compression_type string pub mut: + rpath string // used in the source code, as an ID/key to the embed + apath string // absolute path during compilation to the resource // these are set by gen_embed_file_init in v/gen/c/embed is_compressed bool bytes []u8 @@ -1683,7 +1683,6 @@ pub: method_pos token.Pos scope &Scope = unsafe { nil } left Expr - args_var string // is_vweb bool vweb_tmpl File @@ -1698,6 +1697,7 @@ pub mut: left_type Type result_type Type env_value string + args_var string args []CallArg embed_file EmbeddedFile } diff --git a/vlib/v/checker/comptime.v b/vlib/v/checker/comptime.v index 4a186ff91..9d4019ce1 100644 --- a/vlib/v/checker/comptime.v +++ b/vlib/v/checker/comptime.v @@ -2,6 +2,7 @@ // Use of this source code is governed by an MIT license that can be found in the LICENSE file. module checker +import os import v.ast import v.pref import v.token @@ -29,6 +30,46 @@ fn (mut c Checker) comptime_call(mut node ast.ComptimeCall) ast.Type { return ast.string_type } if node.is_embed { + if node.args.len == 1 { + embed_arg := node.args[0] + mut raw_path := '' + if embed_arg.expr is ast.StringLiteral { + raw_path = embed_arg.expr.val + } else if embed_arg.expr is ast.Ident { + if var := c.fn_scope.find_var(embed_arg.expr.name) { + if var.expr is ast.StringLiteral { + raw_path = var.expr.val + } + } + } + mut escaped_path := raw_path.replace('/', os.path_separator) + // Validate that the epath exists, and that it is actually a file. + if escaped_path == '' { + c.error('supply a valid relative or absolute file path to the file to embed, that is known at compile time', + node.pos) + return ast.string_type + } + abs_path := os.real_path(escaped_path) + // check absolute path first + if !os.exists(abs_path) { + // ... look relative to the source file: + escaped_path = os.real_path(os.join_path_single(os.dir(c.file.path), escaped_path)) + if !os.exists(escaped_path) { + c.error('"$escaped_path" does not exist so it cannot be embedded', + node.pos) + return ast.string_type + } + if !os.is_file(escaped_path) { + c.error('"$escaped_path" is not a file so it cannot be embedded', + node.pos) + return ast.string_type + } + } else { + escaped_path = abs_path + } + node.embed_file.rpath = raw_path + node.embed_file.apath = escaped_path + } // c.file.embedded_files << node.embed_file if node.embed_file.compression_type !in constants.valid_comptime_compression_types { supported := constants.valid_comptime_compression_types.map('.$it').join(', ') diff --git a/vlib/v/embed_file/tests/embed_file_with_variable_arg_test.v b/vlib/v/embed_file/tests/embed_file_with_variable_arg_test.v new file mode 100644 index 000000000..1f1fd10ca --- /dev/null +++ b/vlib/v/embed_file/tests/embed_file_with_variable_arg_test.v @@ -0,0 +1,6 @@ +fn test_embed_file_with_variable_arg() { + path := './a.txt' + s := $embed_file(path).to_string() + println(s) + assert s.trim_space() == 'test' +} diff --git a/vlib/v/fmt/fmt.v b/vlib/v/fmt/fmt.v index 76cb8715d..89d12486d 100644 --- a/vlib/v/fmt/fmt.v +++ b/vlib/v/fmt/fmt.v @@ -1882,9 +1882,9 @@ pub fn (mut f Fmt) comptime_call(node ast.ComptimeCall) { } else { if node.is_embed { if node.embed_file.compression_type == 'none' { - f.write("\$embed_file('$node.embed_file.rpath')") + f.write('\$embed_file(${node.args[0].expr})') } else { - f.write("\$embed_file('$node.embed_file.rpath', .$node.embed_file.compression_type)") + f.write('\$embed_file(${node.args[0].expr}, .$node.embed_file.compression_type)') } } else if node.is_env { f.write("\$env('$node.args_var')") diff --git a/vlib/v/parser/comptime.v b/vlib/v/parser/comptime.v index a574d92cb..9f52bb92b 100644 --- a/vlib/v/parser/comptime.v +++ b/vlib/v/parser/comptime.v @@ -123,8 +123,12 @@ fn (mut p Parser) comptime_call() ast.ComptimeCall { } literal_string_param := if is_html { '' } else { p.tok.lit } path_of_literal_string_param := literal_string_param.replace('/', os.path_separator) + mut arg := ast.CallArg{} if !is_html { - p.check(.string) + arg_expr := p.expr(0) + arg = ast.CallArg{ + expr: arg_expr + } } mut embed_compression_type := 'none' if is_embed_file { @@ -137,33 +141,6 @@ fn (mut p Parser) comptime_call() ast.ComptimeCall { p.check(.rpar) // $embed_file('/path/to/file') if is_embed_file { - mut epath := path_of_literal_string_param - // Validate that the epath exists, and that it is actually a file. - if epath == '' { - p.error_with_pos('supply a valid relative or absolute file path to the file to embed', - start_pos) - return err_node - } - if !p.pref.is_fmt { - abs_path := os.real_path(epath) - // check absolute path first - if !os.exists(abs_path) { - // ... look relative to the source file: - epath = os.real_path(os.join_path_single(os.dir(p.file_name), epath)) - if !os.exists(epath) { - p.error_with_pos('"$epath" does not exist so it cannot be embedded', - start_pos) - return err_node - } - if !os.is_file(epath) { - p.error_with_pos('"$epath" is not a file so it cannot be embedded', - start_pos) - return err_node - } - } else { - epath = abs_path - } - } p.register_auto_import('v.preludes.embed_file') if embed_compression_type == 'zlib' { p.register_auto_import('v.preludes.embed_file.zlib') @@ -172,10 +149,9 @@ fn (mut p Parser) comptime_call() ast.ComptimeCall { scope: 0 is_embed: true embed_file: ast.EmbeddedFile{ - rpath: literal_string_param - apath: epath compression_type: embed_compression_type } + args: [arg] pos: start_pos.extend(p.prev_tok.pos()) } } -- 2.39.5