From 39987109948a29b37acf91317e8d4cea2c0290d0 Mon Sep 17 00:00:00 2001 From: lmp Date: Sun, 16 Jun 2024 00:25:35 +0200 Subject: [PATCH 01/25] comptime: support `-cv key=value` and `var := $compile_value/2` --- vlib/v/ast/ast.v | 42 ++++++++++--------- vlib/v/checker/comptime.v | 12 ++++++ .../comptime_const/using_comptime_const.vv | 15 +++++++ vlib/v/gen/c/comptime.v | 11 +++++ vlib/v/parser/comptime.v | 26 ++++++++++-- vlib/v/pref/pref.v | 17 ++++++++ 6 files changed, 100 insertions(+), 23 deletions(-) create mode 100644 vlib/v/checker/tests/comptime_const/using_comptime_const.vv diff --git a/vlib/v/ast/ast.v b/vlib/v/ast/ast.v index 27308b32ac4c17..5955f9a05a628a 100644 --- a/vlib/v/ast/ast.v +++ b/vlib/v/ast/ast.v @@ -1913,26 +1913,28 @@ pub mut: @[minify] pub struct ComptimeCall { pub: - pos token.Pos - has_parens bool // if $() is used, for vfmt - method_name string - method_pos token.Pos - scope &Scope = unsafe { nil } - is_vweb bool - is_embed bool - is_env bool - env_pos token.Pos - is_pkgconfig bool -pub mut: - vweb_tmpl File - left Expr - left_type Type - result_type Type - env_value string - args_var string - args []CallArg - embed_file EmbeddedFile - or_block OrExpr + pos token.Pos + has_parens bool // if $() is used, for vfmt + method_name string + method_pos token.Pos + scope &Scope = unsafe { nil } + is_vweb bool + is_embed bool // $embed_file(...) + is_env bool // $env(...) + is_compile_value bool // $compile_value(...) + env_pos token.Pos + is_pkgconfig bool +pub mut: + vweb_tmpl File + left Expr + left_type Type + result_type Type + env_value string + compile_value string + args_var string + args []CallArg + embed_file EmbeddedFile + or_block OrExpr } pub struct None { diff --git a/vlib/v/checker/comptime.v b/vlib/v/checker/comptime.v index 27a6b7a3ef96ed..20b1a17da55a93 100644 --- a/vlib/v/checker/comptime.v +++ b/vlib/v/checker/comptime.v @@ -29,6 +29,18 @@ fn (mut c Checker) comptime_call(mut node ast.ComptimeCall) ast.Type { node.env_value = env_value return ast.string_type } + if node.is_compile_value { + arg := node.args[0] or { + c.error('\$compile_value takes two arguments', node.pos) + return ast.void_type + } + typ := arg.expr.get_pure_type() + value := c.pref.compile_compile_values[node.args_var] or { arg.str() } + node.compile_value = value + node.result_type = typ + + return typ + } if node.is_embed { if node.args.len == 1 { embed_arg := node.args[0] diff --git a/vlib/v/checker/tests/comptime_const/using_comptime_const.vv b/vlib/v/checker/tests/comptime_const/using_comptime_const.vv new file mode 100644 index 00000000000000..29c50f9906c026 --- /dev/null +++ b/vlib/v/checker/tests/comptime_const/using_comptime_const.vv @@ -0,0 +1,15 @@ +//#flag -I $const('my_const','some_value')/xyz +//#include "$const('my_const','some_value')/stdio.h" + +const my_int = $compile_value('my_int',4) +const my_string = $compile_value('my_string','five') + +fn main() { + println(my_int) + println(my_string) + int_compile_value := $compile_value('my_const',5) + println(int_compile_value) + float_compile_value := $compile_value('my_float',1.0) + println(float_compile_value) + println('done') +} diff --git a/vlib/v/gen/c/comptime.v b/vlib/v/gen/c/comptime.v index c1d198d1d52e64..0565b8bacf1b86 100644 --- a/vlib/v/gen/c/comptime.v +++ b/vlib/v/gen/c/comptime.v @@ -52,6 +52,17 @@ fn (mut g Gen) comptime_call(mut node ast.ComptimeCall) { g.write('_SLIT("${val}")') return } + if node.method_name == 'compile_value' { + // $compile_value('some_string',) + val := util.cescaped_path(node.compile_value) + // dump(node) + if node.result_type == ast.string_type { + g.write('_SLIT("${val}")') + } else { + g.write('${val}') + } + return + } if node.method_name == 'res' { if node.args_var != '' { g.write('${g.defer_return_tmp_var}.arg${node.args_var}') diff --git a/vlib/v/parser/comptime.v b/vlib/v/parser/comptime.v index 42c5fb21218746..bf06214406f2f2 100644 --- a/vlib/v/parser/comptime.v +++ b/vlib/v/parser/comptime.v @@ -8,7 +8,7 @@ import v.ast import v.token const supported_comptime_calls = ['html', 'tmpl', 'env', 'embed_file', 'pkgconfig', 'compile_error', - 'compile_warn', 'res'] + 'compile_warn', 'compile_value', 'res'] const comptime_types = ['map', 'array', 'array_dynamic', 'array_fixed', 'int', 'float', 'struct', 'interface', 'enum', 'sumtype', 'alias', 'function', 'option', 'string'] @@ -106,7 +106,7 @@ fn (mut p Parser) comptime_call() ast.ComptimeCall { } start_pos := p.tok.pos() p.check(.dollar) - error_msg := 'only `\$tmpl()`, `\$env()`, `\$embed_file()`, `\$pkgconfig()`, `\$vweb.html()`, `\$compile_error()`, `\$compile_warn()` and `\$res()` comptime functions are supported right now' + error_msg := 'only `\$tmpl()`, `\$env()`, `\$embed_file()`, `\$pkgconfig()`, `\$vweb.html()`, `\$compile_error()`, `\$compile_warn()`, `\$compile_value()` and `\$res()` comptime functions are supported right now' if p.peek_tok.kind == .dot { name := p.check_name() // skip `vweb.html()` TODO if name != 'vweb' && name != 'veb' { @@ -122,7 +122,6 @@ fn (mut p Parser) comptime_call() ast.ComptimeCall { } is_embed_file := method_name == 'embed_file' is_html := method_name == 'html' - // $env('ENV_VAR_NAME') p.check(.lpar) arg_pos := p.tok.pos() if method_name in ['env', 'pkgconfig', 'compile_error', 'compile_warn'] { @@ -160,6 +159,27 @@ fn (mut p Parser) comptime_call() ast.ComptimeCall { method_name: method_name pos: start_pos.extend(p.prev_tok.pos()) } + } else if method_name == 'compile_value' { + const_string := p.tok.lit + // const_name_pos := p.tok.pos() + p.check(.string) + p.check(.comma) + arg_expr := p.expr(0) + args := [ + ast.CallArg{ + expr: arg_expr + pos: p.tok.pos() + }, + ] + p.check(.rpar) + return ast.ComptimeCall{ + scope: unsafe { nil } + is_compile_value: true + method_name: method_name + args_var: const_string + args: args + pos: start_pos.extend(p.prev_tok.pos()) + } } has_string_arg := p.tok.kind == .string mut literal_string_param := if is_html && !has_string_arg { '' } else { p.tok.lit } diff --git a/vlib/v/pref/pref.v b/vlib/v/pref/pref.v index f37fc529cb5ae8..76cecb8e95e968 100644 --- a/vlib/v/pref/pref.v +++ b/vlib/v/pref/pref.v @@ -193,6 +193,8 @@ pub mut: // -d vfmt and -d another=0 for `$if vfmt { will execute }` and `$if another ? { will NOT get here }` compile_defines []string // just ['vfmt'] compile_defines_all []string // contains both: ['vfmt','another'] + // -compile_value key=value + compile_compile_values map[string]string // run_args []string // `v run x.v 1 2 3` => `1 2 3` printfn_list []string // a list of generated function names, whose source should be shown, for debugging @@ -823,6 +825,12 @@ pub fn parse_args_and_show_errors(known_external_commands []string, args []strin res.build_options << '${arg} "${res.ldflags.trim_space()}"' i++ } + '-cv', '-compile-value' { + if compile_value := args[i..][1] { + res.parse_compile_value(compile_value) + } + i++ + } '-d', '-define' { if define := args[i..][1] { res.parse_define(define) @@ -1170,6 +1178,15 @@ pub fn cc_from_string(s string) CompilerType { } } +fn (mut prefs Preferences) parse_compile_value(define string) { + define_parts := define.split('=') + if define_parts.len == 2 { + prefs.compile_compile_values[define_parts[0]] = define_parts[1] + return + } + eprintln_exit('V error: Define argument value missing for ${define}.') +} + fn (mut prefs Preferences) parse_define(define string) { define_parts := define.split('=') prefs.diagnose_deprecated_defines(define_parts) From a3ee35af91cfd170ee992dc4c9b7ecaf03d9641b Mon Sep 17 00:00:00 2001 From: lmp Date: Sun, 16 Jun 2024 12:52:15 +0200 Subject: [PATCH 02/25] comptime: add `vfmt` support, tests, CI job for `$compile_value` --- .github/workflows/comptime_ci.yml | 51 +++++++++++++++++++ cmd/tools/vast/vast.v | 1 + vlib/v/checker/checker.v | 8 +++ vlib/v/checker/comptime.v | 51 +++++++++++++++++-- .../comptime_const/using_comptime_const.vv | 15 ------ .../default_comptime_values_test.v | 13 +++++ .../comptime_value/parser_errors_1.run.out | 3 ++ .../tests/comptime_value/parser_errors_1.vv | 1 + .../use_flag_comptime_values.vv | 15 ++++++ .../using_comptime_value.run.out | 3 ++ .../comptime_value/using_comptime_value.vv | 11 ++++ vlib/v/fmt/fmt.v | 9 ++++ vlib/v/fmt/tests/comptime_value_keep.vv | 7 +++ vlib/v/gen/c/comptime.v | 3 +- 14 files changed, 172 insertions(+), 19 deletions(-) create mode 100644 .github/workflows/comptime_ci.yml delete mode 100644 vlib/v/checker/tests/comptime_const/using_comptime_const.vv create mode 100644 vlib/v/checker/tests/comptime_value/default_comptime_values_test.v create mode 100644 vlib/v/checker/tests/comptime_value/parser_errors_1.run.out create mode 100644 vlib/v/checker/tests/comptime_value/parser_errors_1.vv create mode 100644 vlib/v/checker/tests/comptime_value/use_flag_comptime_values.vv create mode 100644 vlib/v/checker/tests/comptime_value/using_comptime_value.run.out create mode 100644 vlib/v/checker/tests/comptime_value/using_comptime_value.vv create mode 100644 vlib/v/fmt/tests/comptime_value_keep.vv diff --git a/.github/workflows/comptime_ci.yml b/.github/workflows/comptime_ci.yml new file mode 100644 index 00000000000000..78cc6c3c9d4255 --- /dev/null +++ b/.github/workflows/comptime_ci.yml @@ -0,0 +1,51 @@ +name: Time CI + +on: + push: + paths: + - 'vlib/**' + - '**/comptime_ci.yml' + - '!**.md' + pull_request: + paths: + - 'vlib/**' + - '**/comptime_ci.yml' + - '!**.md' + +concurrency: + group: ${{ github.workflow }}-${{ github.ref == 'refs/heads/master' && github.sha || github.ref }} + cancel-in-progress: true + +jobs: + test-comptime-linux: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Build V + run: make + - name: Test -cv values + run: ./v -cv my_f64=2.0 -cv my_int=3 -cv my_string="a four" -cv my_bool=true -cv my_char=g run vlib/v/checker/tests/comptime_value/use_flag_comptime_values.vv + - name: Test -compile-value values + run: ./v -compile-value my_f64=2.0 -compile-value my_int=3 -compile-value my_string="a four" -compile-value my_bool=true -compile-value my_char=g run vlib/v/checker/tests/comptime_value/use_flag_comptime_values.vv + + test-comptime-macos: + runs-on: macos-14 + steps: + - uses: actions/checkout@v4 + - name: Build V + run: make + - name: Test -cv values + run: ./v -cv my_f64=2.0 -cv my_int=3 -cv my_string="a four" -cv my_bool=true -cv my_char=g run vlib/v/checker/tests/comptime_value/use_flag_comptime_values.vv + - name: Test -compile-value values + run: ./v -compile-value my_f64=2.0 -compile-value my_int=3 -compile-value my_string="a four" -compile-value my_bool=true -compile-value my_char=g run vlib/v/checker/tests/comptime_value/use_flag_comptime_values.vv + + test-time-windows: + runs-on: windows-2019 + steps: + - uses: actions/checkout@v4 + - name: Build V + run: .\make.bat + - name: Test -cv values + run: ./v -cv my_f64=2.0 -cv my_int=3 -cv my_string="a four" -cv my_bool=true -cv my_char=g run vlib/v/checker/tests/comptime_value/use_flag_comptime_values.vv + - name: Test -compile-value values + run: ./v -compile-value my_f64=2.0 -compile-value my_int=3 -compile-value my_string="a four" -compile-value my_bool=true -compile-value my_char=g run vlib/v/checker/tests/comptime_value/use_flag_comptime_values.vv diff --git a/cmd/tools/vast/vast.v b/cmd/tools/vast/vast.v index f5374757244ebe..21999af3a9d82d 100644 --- a/cmd/tools/vast/vast.v +++ b/cmd/tools/vast/vast.v @@ -1019,6 +1019,7 @@ fn (t Tree) comptime_call(node ast.ComptimeCall) &Node { obj.add_terse('result_type', t.type_node(node.result_type)) obj.add('scope', t.scope(node.scope)) obj.add_terse('env_value', t.string_node(node.env_value)) + obj.add_terse('compile_value', t.string_node(node.compile_value)) obj.add('pos', t.pos(node.pos)) obj.add_terse('args', t.array_node_call_arg(node.args)) obj.add_terse('or_block', t.or_expr(node.or_block)) diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index 0eb5fff545a1ab..a07896f2053dd4 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -2428,6 +2428,10 @@ fn (mut c Checker) hash_stmt(mut node ast.HashStmt) { } node.main = env } + if flag.contains('\$compile_value(') { + c.error('\$compile_value is not supported in ${node.kind} yet', node.pos) + return + } flag_no_comment := flag.all_before('//').trim_space() if node.kind == 'include' || node.kind == 'preinclude' { if !((flag_no_comment.starts_with('"') && flag_no_comment.ends_with('"')) @@ -2511,6 +2515,10 @@ fn (mut c Checker) hash_stmt(mut node ast.HashStmt) { return } } + if flag.contains('\$compile_value(') { + c.error('\$compile_value is not supported in ${node.kind} yet', node.pos) + return + } for deprecated in ['@VMOD', '@VMODULE', '@VPATH', '@VLIB_PATH'] { if flag.contains(deprecated) { if !flag.contains('@VMODROOT') { diff --git a/vlib/v/checker/comptime.v b/vlib/v/checker/comptime.v index 20b1a17da55a93..1f855fd429935f 100644 --- a/vlib/v/checker/comptime.v +++ b/vlib/v/checker/comptime.v @@ -31,14 +31,23 @@ fn (mut c Checker) comptime_call(mut node ast.ComptimeCall) ast.Type { } if node.is_compile_value { arg := node.args[0] or { - c.error('\$compile_value takes two arguments', node.pos) + c.error('\$compile_value takes two arguments, a string and a primitive literal', + node.pos) + return ast.void_type + } + if !arg.expr.is_pure_literal() { + c.error('-cv/-compile-value values can only be pure literals', node.pos) return ast.void_type } typ := arg.expr.get_pure_type() - value := c.pref.compile_compile_values[node.args_var] or { arg.str() } + arg_as_string := arg.str().trim('`"\'') + value := c.pref.compile_compile_values[node.args_var] or { arg_as_string } + validate_type_string_is_pure_literal(typ, value) or { + c.error(err.msg(), node.pos) + return ast.void_type + } node.compile_value = value node.result_type = typ - return typ } if node.is_embed { @@ -581,6 +590,42 @@ fn (mut c Checker) eval_comptime_const_expr(expr ast.Expr, nlevel int) ?ast.Comp return none } +fn validate_type_string_is_pure_literal(typ ast.Type, str string) ! { + if typ == ast.bool_type { + if !(str == 'true' || str == 'false') { + return error('bool literal `true` or `false` expected, found "${str}"') + } + } else if typ == ast.char_type { + if str.starts_with('\\') { + if str.len <= 1 { + return error('empty escape sequence found') + } + if !is_escape_sequence(str[1]) { + return error('char literal escape sequence expected, found "${str}"') + } + } else if str.len != 1 { + return error('char literal expected, found "${str}"') + } + } else if typ == ast.f64_type { + if str.count('.') != 1 { + return error('f64 literal expected, found "${str}"') + } + } else if typ == ast.string_type { + } else if typ == ast.i64_type { + if !str.is_int() { + return error('i64 literal expected, found "${str}"') + } + } else { + return error('expected pure literal, found "${str}"') + } +} + +@[inline] +fn is_escape_sequence(c u8) bool { + return c in [`x`, `u`, `e`, `n`, `r`, `t`, `v`, `a`, `f`, `b`, `\\`, `\``, `$`, `@`, `?`, `{`, + `}`, `'`, `"`, `U`] +} + fn (mut c Checker) verify_vweb_params_for_method(node ast.Fn) (bool, int, int) { margs := node.params.len - 1 // first arg is the receiver/this // if node.attrs.len == 0 || (node.attrs.len == 1 && node.attrs[0].name == 'post') { diff --git a/vlib/v/checker/tests/comptime_const/using_comptime_const.vv b/vlib/v/checker/tests/comptime_const/using_comptime_const.vv deleted file mode 100644 index 29c50f9906c026..00000000000000 --- a/vlib/v/checker/tests/comptime_const/using_comptime_const.vv +++ /dev/null @@ -1,15 +0,0 @@ -//#flag -I $const('my_const','some_value')/xyz -//#include "$const('my_const','some_value')/stdio.h" - -const my_int = $compile_value('my_int',4) -const my_string = $compile_value('my_string','five') - -fn main() { - println(my_int) - println(my_string) - int_compile_value := $compile_value('my_const',5) - println(int_compile_value) - float_compile_value := $compile_value('my_float',1.0) - println(float_compile_value) - println('done') -} diff --git a/vlib/v/checker/tests/comptime_value/default_comptime_values_test.v b/vlib/v/checker/tests/comptime_value/default_comptime_values_test.v new file mode 100644 index 00000000000000..797941922aaabd --- /dev/null +++ b/vlib/v/checker/tests/comptime_value/default_comptime_values_test.v @@ -0,0 +1,13 @@ +const my_f64 = $compile_value('my_f64', 1.0) +const my_int = $compile_value('my_int', 2) +const my_string = $compile_value('my_string', 'three') +const my_bool = $compile_value('my_bool', false) +const my_char = $compile_value('my_char', `f`) + +fn test_default_compile_values() { + assert my_f64 == 1.0 + assert my_int == 2 + assert my_string == 'three' + assert my_bool == false + assert my_char == `f` +} diff --git a/vlib/v/checker/tests/comptime_value/parser_errors_1.run.out b/vlib/v/checker/tests/comptime_value/parser_errors_1.run.out new file mode 100644 index 00000000000000..aa2447e5828a08 --- /dev/null +++ b/vlib/v/checker/tests/comptime_value/parser_errors_1.run.out @@ -0,0 +1,3 @@ +vlib/v/checker/tests/comptime_value/parser_errors_1.vv:1:16: error: -cv/-compile-value values can only be pure literals + 1 | const my_f32 = $compile_value('my_f32', f32(42.0)) + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ \ No newline at end of file diff --git a/vlib/v/checker/tests/comptime_value/parser_errors_1.vv b/vlib/v/checker/tests/comptime_value/parser_errors_1.vv new file mode 100644 index 00000000000000..a142be5b2f8853 --- /dev/null +++ b/vlib/v/checker/tests/comptime_value/parser_errors_1.vv @@ -0,0 +1 @@ +const my_f32 = $compile_value('my_f32', f32(42.0)) diff --git a/vlib/v/checker/tests/comptime_value/use_flag_comptime_values.vv b/vlib/v/checker/tests/comptime_value/use_flag_comptime_values.vv new file mode 100644 index 00000000000000..93457e425343b4 --- /dev/null +++ b/vlib/v/checker/tests/comptime_value/use_flag_comptime_values.vv @@ -0,0 +1,15 @@ +// This file should pass if compiled/run with: +// v -cv my_f64=2.0 -cv my_int=3 -cv my_string="a four" -cv my_bool=true -cv my_char=g run vlib/v/checker/tests/comptime_value/use_flag_comptime_values.vv +const my_f64 = $compile_value('my_f64', 1.0) +const my_int = $compile_value('my_int', 2) +const my_string = $compile_value('my_string', 'three') +const my_bool = $compile_value('my_bool', false) +const my_char = $compile_value('my_char', `f`) + +fn main() { + assert my_f64 == 2.0 + assert my_int == 3 + assert my_string == 'a four' + assert my_bool == true + assert my_char == `g` +} diff --git a/vlib/v/checker/tests/comptime_value/using_comptime_value.run.out b/vlib/v/checker/tests/comptime_value/using_comptime_value.run.out new file mode 100644 index 00000000000000..a172d30507770b --- /dev/null +++ b/vlib/v/checker/tests/comptime_value/using_comptime_value.run.out @@ -0,0 +1,3 @@ +42.0 +false +done \ No newline at end of file diff --git a/vlib/v/checker/tests/comptime_value/using_comptime_value.vv b/vlib/v/checker/tests/comptime_value/using_comptime_value.vv new file mode 100644 index 00000000000000..4bf78c73c3b0af --- /dev/null +++ b/vlib/v/checker/tests/comptime_value/using_comptime_value.vv @@ -0,0 +1,11 @@ +// TODO: support #flag -I $const('my_flag','flag_value')/xyz +// TODO: support #include "$const('my_include','/usr/include')/stdio.h" + +const my_f64 = $compile_value('my_f64', 42.0) + +fn main() { + println(my_f64) + cv_bool := $compile_value('my_bool', false) + println(cv_bool) + println('done') +} diff --git a/vlib/v/fmt/fmt.v b/vlib/v/fmt/fmt.v index e553382e4eab1f..f5439d803e302a 100644 --- a/vlib/v/fmt/fmt.v +++ b/vlib/v/fmt/fmt.v @@ -2186,6 +2186,15 @@ pub fn (mut f Fmt) comptime_call(node ast.ComptimeCall) { f.write("\$${node.method_name}('${node.args_var}')") } } + node.method_name == 'compile_value' { + if node.args_var.contains("'") { + f.write('\$${node.method_name}("${node.args_var}", ') + } else { + f.write("\$${node.method_name}('${node.args_var}', ") + } + f.expr(node.args[0].expr) + f.write(')') + } node.method_name == 'res' { if node.args_var != '' { f.write('\$res(${node.args_var})') diff --git a/vlib/v/fmt/tests/comptime_value_keep.vv b/vlib/v/fmt/tests/comptime_value_keep.vv new file mode 100644 index 00000000000000..2b1dfeca174755 --- /dev/null +++ b/vlib/v/fmt/tests/comptime_value_keep.vv @@ -0,0 +1,7 @@ +fn main() { + val_str := $compile_value('key_str', 'value') + val_f64 := $compile_value('key_f64', 42.0) + val_int := $compile_value('key_int', 56) + val_bool := $compile_value('key_bool', false) + val_char := $compile_value('key_char', `f`) +} diff --git a/vlib/v/gen/c/comptime.v b/vlib/v/gen/c/comptime.v index 0565b8bacf1b86..0e1f477aee090f 100644 --- a/vlib/v/gen/c/comptime.v +++ b/vlib/v/gen/c/comptime.v @@ -55,9 +55,10 @@ fn (mut g Gen) comptime_call(mut node ast.ComptimeCall) { if node.method_name == 'compile_value' { // $compile_value('some_string',) val := util.cescaped_path(node.compile_value) - // dump(node) if node.result_type == ast.string_type { g.write('_SLIT("${val}")') + } else if node.result_type == ast.char_type { + g.write("'${val}'") } else { g.write('${val}') } From f5bf59c71bf896ae58394a6aec37113e215fa48d Mon Sep 17 00:00:00 2001 From: larpon <768942+larpon@users.noreply.github.com> Date: Sun, 16 Jun 2024 15:25:16 +0200 Subject: [PATCH 03/25] ci: update .github/workflows/comptime_ci.yml Co-authored-by: Jose Mendoza <56417208+StunxFS@users.noreply.github.com> --- .github/workflows/comptime_ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/comptime_ci.yml b/.github/workflows/comptime_ci.yml index 78cc6c3c9d4255..7e626b2c4bb702 100644 --- a/.github/workflows/comptime_ci.yml +++ b/.github/workflows/comptime_ci.yml @@ -1,4 +1,4 @@ -name: Time CI +name: Comptime CI on: push: From df29e38cb74a97c1da3a7565944173ae05ad0b64 Mon Sep 17 00:00:00 2001 From: larpon <768942+larpon@users.noreply.github.com> Date: Sun, 16 Jun 2024 15:25:34 +0200 Subject: [PATCH 04/25] ci: update .github/workflows/comptime_ci.yml Co-authored-by: Jose Mendoza <56417208+StunxFS@users.noreply.github.com> --- .github/workflows/comptime_ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/comptime_ci.yml b/.github/workflows/comptime_ci.yml index 7e626b2c4bb702..e0392b4db63859 100644 --- a/.github/workflows/comptime_ci.yml +++ b/.github/workflows/comptime_ci.yml @@ -39,7 +39,7 @@ jobs: - name: Test -compile-value values run: ./v -compile-value my_f64=2.0 -compile-value my_int=3 -compile-value my_string="a four" -compile-value my_bool=true -compile-value my_char=g run vlib/v/checker/tests/comptime_value/use_flag_comptime_values.vv - test-time-windows: + test-comptime-windows: runs-on: windows-2019 steps: - uses: actions/checkout@v4 From 6913bb3698ecbca171c865fbc05ea1538685b2fd Mon Sep 17 00:00:00 2001 From: Delyan Angelov Date: Sun, 16 Jun 2024 17:56:12 +0300 Subject: [PATCH 05/25] remove comptime_ci.yml, move use_flag_comptime_values.vv to vlib/v/gen/c/testdata/ --- .github/workflows/comptime_ci.yml | 51 ------------------- .../c/testdata/use_flag_comptime_values.out | 5 ++ .../c/testdata}/use_flag_comptime_values.vv | 7 ++- 3 files changed, 11 insertions(+), 52 deletions(-) delete mode 100644 .github/workflows/comptime_ci.yml create mode 100644 vlib/v/gen/c/testdata/use_flag_comptime_values.out rename vlib/v/{checker/tests/comptime_value => gen/c/testdata}/use_flag_comptime_values.vv (68%) diff --git a/.github/workflows/comptime_ci.yml b/.github/workflows/comptime_ci.yml deleted file mode 100644 index e0392b4db63859..00000000000000 --- a/.github/workflows/comptime_ci.yml +++ /dev/null @@ -1,51 +0,0 @@ -name: Comptime CI - -on: - push: - paths: - - 'vlib/**' - - '**/comptime_ci.yml' - - '!**.md' - pull_request: - paths: - - 'vlib/**' - - '**/comptime_ci.yml' - - '!**.md' - -concurrency: - group: ${{ github.workflow }}-${{ github.ref == 'refs/heads/master' && github.sha || github.ref }} - cancel-in-progress: true - -jobs: - test-comptime-linux: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - name: Build V - run: make - - name: Test -cv values - run: ./v -cv my_f64=2.0 -cv my_int=3 -cv my_string="a four" -cv my_bool=true -cv my_char=g run vlib/v/checker/tests/comptime_value/use_flag_comptime_values.vv - - name: Test -compile-value values - run: ./v -compile-value my_f64=2.0 -compile-value my_int=3 -compile-value my_string="a four" -compile-value my_bool=true -compile-value my_char=g run vlib/v/checker/tests/comptime_value/use_flag_comptime_values.vv - - test-comptime-macos: - runs-on: macos-14 - steps: - - uses: actions/checkout@v4 - - name: Build V - run: make - - name: Test -cv values - run: ./v -cv my_f64=2.0 -cv my_int=3 -cv my_string="a four" -cv my_bool=true -cv my_char=g run vlib/v/checker/tests/comptime_value/use_flag_comptime_values.vv - - name: Test -compile-value values - run: ./v -compile-value my_f64=2.0 -compile-value my_int=3 -compile-value my_string="a four" -compile-value my_bool=true -compile-value my_char=g run vlib/v/checker/tests/comptime_value/use_flag_comptime_values.vv - - test-comptime-windows: - runs-on: windows-2019 - steps: - - uses: actions/checkout@v4 - - name: Build V - run: .\make.bat - - name: Test -cv values - run: ./v -cv my_f64=2.0 -cv my_int=3 -cv my_string="a four" -cv my_bool=true -cv my_char=g run vlib/v/checker/tests/comptime_value/use_flag_comptime_values.vv - - name: Test -compile-value values - run: ./v -compile-value my_f64=2.0 -compile-value my_int=3 -compile-value my_string="a four" -compile-value my_bool=true -compile-value my_char=g run vlib/v/checker/tests/comptime_value/use_flag_comptime_values.vv diff --git a/vlib/v/gen/c/testdata/use_flag_comptime_values.out b/vlib/v/gen/c/testdata/use_flag_comptime_values.out new file mode 100644 index 00000000000000..d343dc6355d107 --- /dev/null +++ b/vlib/v/gen/c/testdata/use_flag_comptime_values.out @@ -0,0 +1,5 @@ +2.0 +3 +a four +true +g diff --git a/vlib/v/checker/tests/comptime_value/use_flag_comptime_values.vv b/vlib/v/gen/c/testdata/use_flag_comptime_values.vv similarity index 68% rename from vlib/v/checker/tests/comptime_value/use_flag_comptime_values.vv rename to vlib/v/gen/c/testdata/use_flag_comptime_values.vv index 93457e425343b4..064c5d51816a13 100644 --- a/vlib/v/checker/tests/comptime_value/use_flag_comptime_values.vv +++ b/vlib/v/gen/c/testdata/use_flag_comptime_values.vv @@ -1,5 +1,5 @@ // This file should pass if compiled/run with: -// v -cv my_f64=2.0 -cv my_int=3 -cv my_string="a four" -cv my_bool=true -cv my_char=g run vlib/v/checker/tests/comptime_value/use_flag_comptime_values.vv +// vtest vflags: -cv my_f64=2.0 -cv my_int=3 -cv my_string="a four" -cv my_bool=true -cv my_char=g const my_f64 = $compile_value('my_f64', 1.0) const my_int = $compile_value('my_int', 2) const my_string = $compile_value('my_string', 'three') @@ -12,4 +12,9 @@ fn main() { assert my_string == 'a four' assert my_bool == true assert my_char == `g` + println(my_f64) + println(my_int) + println(my_string) + println(my_bool) + println(rune(my_char)) } From ab2f197149cc6c75f9bcca2be9be0c3b77271a36 Mon Sep 17 00:00:00 2001 From: Delyan Angelov Date: Sun, 16 Jun 2024 17:59:17 +0300 Subject: [PATCH 06/25] compile_compile_values -> compile_values, small cleanup of the CLI parameter handling code --- vlib/v/checker/comptime.v | 2 +- vlib/v/pref/pref.v | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/vlib/v/checker/comptime.v b/vlib/v/checker/comptime.v index 1f855fd429935f..2ca3a65a90e09c 100644 --- a/vlib/v/checker/comptime.v +++ b/vlib/v/checker/comptime.v @@ -41,7 +41,7 @@ fn (mut c Checker) comptime_call(mut node ast.ComptimeCall) ast.Type { } typ := arg.expr.get_pure_type() arg_as_string := arg.str().trim('`"\'') - value := c.pref.compile_compile_values[node.args_var] or { arg_as_string } + value := c.pref.compile_values[node.args_var] or { arg_as_string } validate_type_string_is_pure_literal(typ, value) or { c.error(err.msg(), node.pos) return ast.void_type diff --git a/vlib/v/pref/pref.v b/vlib/v/pref/pref.v index 76cecb8e95e968..5454a0dd4d52b1 100644 --- a/vlib/v/pref/pref.v +++ b/vlib/v/pref/pref.v @@ -193,8 +193,7 @@ pub mut: // -d vfmt and -d another=0 for `$if vfmt { will execute }` and `$if another ? { will NOT get here }` compile_defines []string // just ['vfmt'] compile_defines_all []string // contains both: ['vfmt','another'] - // -compile_value key=value - compile_compile_values map[string]string + compile_values map[string]string // -compile_value key=value // run_args []string // `v run x.v 1 2 3` => `1 2 3` printfn_list []string // a list of generated function names, whose source should be shown, for debugging @@ -1179,12 +1178,13 @@ pub fn cc_from_string(s string) CompilerType { } fn (mut prefs Preferences) parse_compile_value(define string) { - define_parts := define.split('=') - if define_parts.len == 2 { - prefs.compile_compile_values[define_parts[0]] = define_parts[1] + if !define.contains('=') { + eprintln_exit('V error: Define argument value missing for ${define}.') return } - eprintln_exit('V error: Define argument value missing for ${define}.') + name := define.all_before('=') + value := define.all_after_first('=') + prefs.compile_values[name] = value } fn (mut prefs Preferences) parse_define(define string) { From 95a7e90b1f13c35515072c4986b1f3a40799688c Mon Sep 17 00:00:00 2001 From: Delyan Angelov Date: Sun, 16 Jun 2024 18:02:43 +0300 Subject: [PATCH 07/25] small cleanup of fmt.v --- vlib/v/fmt/fmt.v | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/vlib/v/fmt/fmt.v b/vlib/v/fmt/fmt.v index f5439d803e302a..74de6b6d4726ae 100644 --- a/vlib/v/fmt/fmt.v +++ b/vlib/v/fmt/fmt.v @@ -2187,11 +2187,7 @@ pub fn (mut f Fmt) comptime_call(node ast.ComptimeCall) { } } node.method_name == 'compile_value' { - if node.args_var.contains("'") { - f.write('\$${node.method_name}("${node.args_var}", ') - } else { - f.write("\$${node.method_name}('${node.args_var}', ") - } + f.write("\$compile_value('${node.args_var}', ") f.expr(node.args[0].expr) f.write(')') } From c4a8028b267d9a1f30c8f20570268934ef956719 Mon Sep 17 00:00:00 2001 From: Delyan Angelov Date: Sun, 16 Jun 2024 19:52:02 +0300 Subject: [PATCH 08/25] pref: save the -cv options to build_options too, so that they can be passed down to modules with -usecache, and invalidate the build cache --- vlib/v/pref/pref.v | 1 + 1 file changed, 1 insertion(+) diff --git a/vlib/v/pref/pref.v b/vlib/v/pref/pref.v index 5454a0dd4d52b1..b424fc562ecad0 100644 --- a/vlib/v/pref/pref.v +++ b/vlib/v/pref/pref.v @@ -826,6 +826,7 @@ pub fn parse_args_and_show_errors(known_external_commands []string, args []strin } '-cv', '-compile-value' { if compile_value := args[i..][1] { + res.build_options << '-cv ${compile_value}' res.parse_compile_value(compile_value) } i++ From ce7a17ffeb7230879334464defb2cc986a9a3666 Mon Sep 17 00:00:00 2001 From: Delyan Angelov Date: Mon, 17 Jun 2024 16:01:07 +0300 Subject: [PATCH 09/25] support `-d ident=value` in addition to `-d ident` --- .../c/testdata/use_flag_comptime_values.vv | 2 +- vlib/v/pref/pref.v | 34 ++++++------------- 2 files changed, 12 insertions(+), 24 deletions(-) diff --git a/vlib/v/gen/c/testdata/use_flag_comptime_values.vv b/vlib/v/gen/c/testdata/use_flag_comptime_values.vv index 064c5d51816a13..fb71a74e354b4f 100644 --- a/vlib/v/gen/c/testdata/use_flag_comptime_values.vv +++ b/vlib/v/gen/c/testdata/use_flag_comptime_values.vv @@ -1,5 +1,5 @@ // This file should pass if compiled/run with: -// vtest vflags: -cv my_f64=2.0 -cv my_int=3 -cv my_string="a four" -cv my_bool=true -cv my_char=g +// vtest vflags: -d my_f64=2.0 -d my_int=3 -d my_string="a four" -d my_bool -d my_char=g const my_f64 = $compile_value('my_f64', 1.0) const my_int = $compile_value('my_int', 2) const my_string = $compile_value('my_string', 'three') diff --git a/vlib/v/pref/pref.v b/vlib/v/pref/pref.v index b424fc562ecad0..71e94c358c9ce8 100644 --- a/vlib/v/pref/pref.v +++ b/vlib/v/pref/pref.v @@ -1189,38 +1189,26 @@ fn (mut prefs Preferences) parse_compile_value(define string) { } fn (mut prefs Preferences) parse_define(define string) { - define_parts := define.split('=') - prefs.diagnose_deprecated_defines(define_parts) if !(prefs.is_debug && define == 'debug') { prefs.build_options << '-d ${define}' } - if define_parts.len == 1 { + if !define.contains('=') { + prefs.compile_values[define] = 'true' prefs.compile_defines << define prefs.compile_defines_all << define return } - if define_parts.len == 2 { - prefs.compile_defines_all << define_parts[0] - match define_parts[1] { - '0' {} - '1' { - prefs.compile_defines << define_parts[0] - } - else { - eprintln_exit( - 'V error: Unknown define argument value `${define_parts[1]}` for ${define_parts[0]}.' + - ' Expected `0` or `1`.') - } + dname := define.all_before('=') + dvalue := define.all_after_first('=') + prefs.compile_values[dname] = dvalue + prefs.compile_defines_all << dname + match dvalue { + '0' {} + '1' { + prefs.compile_defines << dname } - return + else {} } - eprintln_exit('V error: Unknown define argument: ${define}. Expected at most one `=`.') -} - -fn (mut prefs Preferences) diagnose_deprecated_defines(define_parts []string) { - // if define_parts[0] == 'no_bounds_checking' { - // eprintln('`-d no_bounds_checking` was deprecated in 2022/10/30. Use `-no-bounds-checking` instead.') - // } } pub fn supported_test_runners_list() string { From 8d9a23eb1b142c60e5941d2c2771a30ccadb37b2 Mon Sep 17 00:00:00 2001 From: Delyan Angelov Date: Mon, 17 Jun 2024 21:46:18 +0300 Subject: [PATCH 10/25] use `$d()`, instead of `$compile_value()` --- vlib/v/ast/ast.v | 4 ++-- vlib/v/checker/checker.v | 8 ++++---- vlib/v/checker/comptime.v | 5 ++--- .../comptime_value/default_comptime_values_test.v | 10 +++++----- .../tests/comptime_value/parser_errors_1.run.out | 6 +++--- .../checker/tests/comptime_value/parser_errors_1.vv | 2 +- .../tests/comptime_value/using_comptime_value.vv | 12 ++++++------ vlib/v/fmt/fmt.v | 4 ++-- vlib/v/fmt/tests/comptime_value_keep.vv | 10 +++++----- vlib/v/gen/c/comptime.v | 5 +++-- vlib/v/gen/c/testdata/use_flag_comptime_values.vv | 10 +++++----- vlib/v/parser/comptime.v | 6 +++--- vlib/v/pref/pref.v | 9 +-------- 13 files changed, 42 insertions(+), 49 deletions(-) diff --git a/vlib/v/ast/ast.v b/vlib/v/ast/ast.v index 5955f9a05a628a..9f1746b6d4108c 100644 --- a/vlib/v/ast/ast.v +++ b/vlib/v/ast/ast.v @@ -1920,8 +1920,8 @@ pub: scope &Scope = unsafe { nil } is_vweb bool is_embed bool // $embed_file(...) - is_env bool // $env(...) - is_compile_value bool // $compile_value(...) + is_env bool // $env(...) // TODO: deprecate after $d() is stable + is_compile_value bool // $d(...) env_pos token.Pos is_pkgconfig bool pub mut: diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index a07896f2053dd4..fdd967b5fbe535 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -2428,8 +2428,8 @@ fn (mut c Checker) hash_stmt(mut node ast.HashStmt) { } node.main = env } - if flag.contains('\$compile_value(') { - c.error('\$compile_value is not supported in ${node.kind} yet', node.pos) + if flag.contains('\$d(') { + c.error('\$d() is not supported in ${node.kind} yet', node.pos) return } flag_no_comment := flag.all_before('//').trim_space() @@ -2515,8 +2515,8 @@ fn (mut c Checker) hash_stmt(mut node ast.HashStmt) { return } } - if flag.contains('\$compile_value(') { - c.error('\$compile_value is not supported in ${node.kind} yet', node.pos) + if flag.contains('\$d(') { + c.error('\$d() is not supported in ${node.kind} yet', node.pos) return } for deprecated in ['@VMOD', '@VMODULE', '@VPATH', '@VLIB_PATH'] { diff --git a/vlib/v/checker/comptime.v b/vlib/v/checker/comptime.v index 2ca3a65a90e09c..1d756689e37f8a 100644 --- a/vlib/v/checker/comptime.v +++ b/vlib/v/checker/comptime.v @@ -31,12 +31,11 @@ fn (mut c Checker) comptime_call(mut node ast.ComptimeCall) ast.Type { } if node.is_compile_value { arg := node.args[0] or { - c.error('\$compile_value takes two arguments, a string and a primitive literal', - node.pos) + c.error('\$d() takes two arguments, a string and a primitive literal', node.pos) return ast.void_type } if !arg.expr.is_pure_literal() { - c.error('-cv/-compile-value values can only be pure literals', node.pos) + c.error('-d values can only be pure literals', node.pos) return ast.void_type } typ := arg.expr.get_pure_type() diff --git a/vlib/v/checker/tests/comptime_value/default_comptime_values_test.v b/vlib/v/checker/tests/comptime_value/default_comptime_values_test.v index 797941922aaabd..89a65c6df4a830 100644 --- a/vlib/v/checker/tests/comptime_value/default_comptime_values_test.v +++ b/vlib/v/checker/tests/comptime_value/default_comptime_values_test.v @@ -1,8 +1,8 @@ -const my_f64 = $compile_value('my_f64', 1.0) -const my_int = $compile_value('my_int', 2) -const my_string = $compile_value('my_string', 'three') -const my_bool = $compile_value('my_bool', false) -const my_char = $compile_value('my_char', `f`) +const my_f64 = $d('my_f64', 1.0) +const my_int = $d('my_int', 2) +const my_string = $d('my_string', 'three') +const my_bool = $d('my_bool', false) +const my_char = $d('my_char', `f`) fn test_default_compile_values() { assert my_f64 == 1.0 diff --git a/vlib/v/checker/tests/comptime_value/parser_errors_1.run.out b/vlib/v/checker/tests/comptime_value/parser_errors_1.run.out index aa2447e5828a08..646412c880bc79 100644 --- a/vlib/v/checker/tests/comptime_value/parser_errors_1.run.out +++ b/vlib/v/checker/tests/comptime_value/parser_errors_1.run.out @@ -1,3 +1,3 @@ -vlib/v/checker/tests/comptime_value/parser_errors_1.vv:1:16: error: -cv/-compile-value values can only be pure literals - 1 | const my_f32 = $compile_value('my_f32', f32(42.0)) - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ \ No newline at end of file +vlib/v/checker/tests/comptime_value/parser_errors_1.vv:1:16: error: -d values can only be pure literals + 1 | const my_f32 = $d('my_f32', f32(42.0)) + | ~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/vlib/v/checker/tests/comptime_value/parser_errors_1.vv b/vlib/v/checker/tests/comptime_value/parser_errors_1.vv index a142be5b2f8853..7e52c4f3b4dcf7 100644 --- a/vlib/v/checker/tests/comptime_value/parser_errors_1.vv +++ b/vlib/v/checker/tests/comptime_value/parser_errors_1.vv @@ -1 +1 @@ -const my_f32 = $compile_value('my_f32', f32(42.0)) +const my_f32 = $d('my_f32', f32(42.0)) diff --git a/vlib/v/checker/tests/comptime_value/using_comptime_value.vv b/vlib/v/checker/tests/comptime_value/using_comptime_value.vv index 4bf78c73c3b0af..de9be77ccf7b22 100644 --- a/vlib/v/checker/tests/comptime_value/using_comptime_value.vv +++ b/vlib/v/checker/tests/comptime_value/using_comptime_value.vv @@ -1,11 +1,11 @@ -// TODO: support #flag -I $const('my_flag','flag_value')/xyz -// TODO: support #include "$const('my_include','/usr/include')/stdio.h" +// TODO: support #flag -I $d('my_flag','flag_value')/xyz +// TODO: support #include "$d('my_include','/usr/include')/stdio.h" -const my_f64 = $compile_value('my_f64', 42.0) +const my_f64 = $d('my_f64', 42.0) fn main() { - println(my_f64) - cv_bool := $compile_value('my_bool', false) - println(cv_bool) + println(my_f64) + cv_bool := $d('my_bool', false) + println(cv_bool) println('done') } diff --git a/vlib/v/fmt/fmt.v b/vlib/v/fmt/fmt.v index 74de6b6d4726ae..c9f85ce8fff4e7 100644 --- a/vlib/v/fmt/fmt.v +++ b/vlib/v/fmt/fmt.v @@ -2186,8 +2186,8 @@ pub fn (mut f Fmt) comptime_call(node ast.ComptimeCall) { f.write("\$${node.method_name}('${node.args_var}')") } } - node.method_name == 'compile_value' { - f.write("\$compile_value('${node.args_var}', ") + node.method_name == 'd' { + f.write("\$d('${node.args_var}', ") f.expr(node.args[0].expr) f.write(')') } diff --git a/vlib/v/fmt/tests/comptime_value_keep.vv b/vlib/v/fmt/tests/comptime_value_keep.vv index 2b1dfeca174755..7bb474537bd77e 100644 --- a/vlib/v/fmt/tests/comptime_value_keep.vv +++ b/vlib/v/fmt/tests/comptime_value_keep.vv @@ -1,7 +1,7 @@ fn main() { - val_str := $compile_value('key_str', 'value') - val_f64 := $compile_value('key_f64', 42.0) - val_int := $compile_value('key_int', 56) - val_bool := $compile_value('key_bool', false) - val_char := $compile_value('key_char', `f`) + val_str := $d('key_str', 'value') + val_f64 := $d('key_f64', 42.0) + val_int := $d('key_int', 56) + val_bool := $d('key_bool', false) + val_char := $d('key_char', `f`) } diff --git a/vlib/v/gen/c/comptime.v b/vlib/v/gen/c/comptime.v index 0e1f477aee090f..5902770680ae3f 100644 --- a/vlib/v/gen/c/comptime.v +++ b/vlib/v/gen/c/comptime.v @@ -48,12 +48,13 @@ fn (mut g Gen) comptime_call(mut node ast.ComptimeCall) { } if node.method_name == 'env' { // $env('ENV_VAR_NAME') + // TODO: deprecate after support for $d() is stable val := util.cescaped_path(os.getenv(node.args_var)) g.write('_SLIT("${val}")') return } - if node.method_name == 'compile_value' { - // $compile_value('some_string',) + if node.method_name == 'd' { + // $d('some_string',), affected by `-d some_string=actual_value` val := util.cescaped_path(node.compile_value) if node.result_type == ast.string_type { g.write('_SLIT("${val}")') diff --git a/vlib/v/gen/c/testdata/use_flag_comptime_values.vv b/vlib/v/gen/c/testdata/use_flag_comptime_values.vv index fb71a74e354b4f..2d31d2dc451a33 100644 --- a/vlib/v/gen/c/testdata/use_flag_comptime_values.vv +++ b/vlib/v/gen/c/testdata/use_flag_comptime_values.vv @@ -1,10 +1,10 @@ // This file should pass if compiled/run with: // vtest vflags: -d my_f64=2.0 -d my_int=3 -d my_string="a four" -d my_bool -d my_char=g -const my_f64 = $compile_value('my_f64', 1.0) -const my_int = $compile_value('my_int', 2) -const my_string = $compile_value('my_string', 'three') -const my_bool = $compile_value('my_bool', false) -const my_char = $compile_value('my_char', `f`) +const my_f64 = $d('my_f64', 1.0) +const my_int = $d('my_int', 2) +const my_string = $d('my_string', 'three') +const my_bool = $d('my_bool', false) +const my_char = $d('my_char', `f`) fn main() { assert my_f64 == 2.0 diff --git a/vlib/v/parser/comptime.v b/vlib/v/parser/comptime.v index bf06214406f2f2..367a555e17bf0a 100644 --- a/vlib/v/parser/comptime.v +++ b/vlib/v/parser/comptime.v @@ -8,7 +8,7 @@ import v.ast import v.token const supported_comptime_calls = ['html', 'tmpl', 'env', 'embed_file', 'pkgconfig', 'compile_error', - 'compile_warn', 'compile_value', 'res'] + 'compile_warn', 'd', 'res'] const comptime_types = ['map', 'array', 'array_dynamic', 'array_fixed', 'int', 'float', 'struct', 'interface', 'enum', 'sumtype', 'alias', 'function', 'option', 'string'] @@ -106,7 +106,7 @@ fn (mut p Parser) comptime_call() ast.ComptimeCall { } start_pos := p.tok.pos() p.check(.dollar) - error_msg := 'only `\$tmpl()`, `\$env()`, `\$embed_file()`, `\$pkgconfig()`, `\$vweb.html()`, `\$compile_error()`, `\$compile_warn()`, `\$compile_value()` and `\$res()` comptime functions are supported right now' + error_msg := 'only `\$tmpl()`, `\$env()`, `\$embed_file()`, `\$pkgconfig()`, `\$vweb.html()`, `\$compile_error()`, `\$compile_warn()`, `\$d()` and `\$res()` comptime functions are supported right now' if p.peek_tok.kind == .dot { name := p.check_name() // skip `vweb.html()` TODO if name != 'vweb' && name != 'veb' { @@ -159,7 +159,7 @@ fn (mut p Parser) comptime_call() ast.ComptimeCall { method_name: method_name pos: start_pos.extend(p.prev_tok.pos()) } - } else if method_name == 'compile_value' { + } else if method_name == 'd' { const_string := p.tok.lit // const_name_pos := p.tok.pos() p.check(.string) diff --git a/vlib/v/pref/pref.v b/vlib/v/pref/pref.v index 71e94c358c9ce8..9b4e3b0f7afe79 100644 --- a/vlib/v/pref/pref.v +++ b/vlib/v/pref/pref.v @@ -193,7 +193,7 @@ pub mut: // -d vfmt and -d another=0 for `$if vfmt { will execute }` and `$if another ? { will NOT get here }` compile_defines []string // just ['vfmt'] compile_defines_all []string // contains both: ['vfmt','another'] - compile_values map[string]string // -compile_value key=value + compile_values map[string]string // the map will contain for `-d key=value`: compile_values['key'] = 'value', and for `-d ident`, it will be: compile_values['ident'] = 'true' // run_args []string // `v run x.v 1 2 3` => `1 2 3` printfn_list []string // a list of generated function names, whose source should be shown, for debugging @@ -824,13 +824,6 @@ pub fn parse_args_and_show_errors(known_external_commands []string, args []strin res.build_options << '${arg} "${res.ldflags.trim_space()}"' i++ } - '-cv', '-compile-value' { - if compile_value := args[i..][1] { - res.build_options << '-cv ${compile_value}' - res.parse_compile_value(compile_value) - } - i++ - } '-d', '-define' { if define := args[i..][1] { res.parse_define(define) From e1be3eb263bd6ebf6da1fd5d5129eaef698ed7b4 Mon Sep 17 00:00:00 2001 From: lmp Date: Tue, 18 Jun 2024 10:44:17 +0200 Subject: [PATCH 11/25] comptime: add simple string support for `$d()` in `#flag`,`#include` statements --- vlib/v/checker/checker.v | 13 ++-- .../comptime_value/parser_errors_2.run.out | 1 + .../tests/comptime_value/parser_errors_2.vv | 1 + .../comptime_value/using_comptime_value.vv | 4 +- vlib/v/util/util.v | 64 +++++++++++++++++++ 5 files changed, 77 insertions(+), 6 deletions(-) create mode 100644 vlib/v/checker/tests/comptime_value/parser_errors_2.run.out create mode 100644 vlib/v/checker/tests/comptime_value/parser_errors_2.vv diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index fdd967b5fbe535..2021125b98279d 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -2429,8 +2429,11 @@ fn (mut c Checker) hash_stmt(mut node ast.HashStmt) { node.main = env } if flag.contains('\$d(') { - c.error('\$d() is not supported in ${node.kind} yet', node.pos) - return + d := util.resolve_d_value(c.pref.compile_values, flag) or { + c.error(err.msg(), node.pos) + return + } + node.main = d } flag_no_comment := flag.all_before('//').trim_space() if node.kind == 'include' || node.kind == 'preinclude' { @@ -2516,8 +2519,10 @@ fn (mut c Checker) hash_stmt(mut node ast.HashStmt) { } } if flag.contains('\$d(') { - c.error('\$d() is not supported in ${node.kind} yet', node.pos) - return + flag = util.resolve_d_value(c.pref.compile_values, flag) or { + c.error(err.msg(), node.pos) + return + } } for deprecated in ['@VMOD', '@VMODULE', '@VPATH', '@VLIB_PATH'] { if flag.contains(deprecated) { diff --git a/vlib/v/checker/tests/comptime_value/parser_errors_2.run.out b/vlib/v/checker/tests/comptime_value/parser_errors_2.run.out new file mode 100644 index 00000000000000..dbc4202d57e5c7 --- /dev/null +++ b/vlib/v/checker/tests/comptime_value/parser_errors_2.run.out @@ -0,0 +1 @@ +builder error: Header file "/opt/invalid/include/stdio.h", needed for module `main` was not found. Please install the corresponding development headers. \ No newline at end of file diff --git a/vlib/v/checker/tests/comptime_value/parser_errors_2.vv b/vlib/v/checker/tests/comptime_value/parser_errors_2.vv new file mode 100644 index 00000000000000..7557f5d9915573 --- /dev/null +++ b/vlib/v/checker/tests/comptime_value/parser_errors_2.vv @@ -0,0 +1 @@ +#include "$d('my_include','/opt/invalid/include')/stdio.h" diff --git a/vlib/v/checker/tests/comptime_value/using_comptime_value.vv b/vlib/v/checker/tests/comptime_value/using_comptime_value.vv index de9be77ccf7b22..827dc4616d562b 100644 --- a/vlib/v/checker/tests/comptime_value/using_comptime_value.vv +++ b/vlib/v/checker/tests/comptime_value/using_comptime_value.vv @@ -1,5 +1,5 @@ -// TODO: support #flag -I $d('my_flag','flag_value')/xyz -// TODO: support #include "$d('my_include','/usr/include')/stdio.h" +#flag -I $d('my_flag','flag_value')/xyz +#include "$d('my_include','/usr/include')/stdio.h" const my_f64 = $d('my_f64', 42.0) diff --git a/vlib/v/util/util.v b/vlib/v/util/util.v index eb7f4be57b92f6..9a10bdf85ce4a2 100644 --- a/vlib/v/util/util.v +++ b/vlib/v/util/util.v @@ -115,6 +115,70 @@ pub fn resolve_env_value(str string, check_for_presence bool) !string { return rep } +// resolve_d_value replaces all occurrences of `$d('ident','value')` +// in `str` with either the default `'value'` param or a compile value passed via `-d ident=value`. +pub fn resolve_d_value(compile_values map[string]string, str string) !string { + d_sig := "\$d('" + at := str.index(d_sig) or { + return error('no "${d_sig}' + '...\')" could be found in "${str}".') + } + mut all_parsed := d_sig + mut ch := u8(`.`) + mut d_ident := '' + mut i := 0 + for i = at + d_sig.len; i < str.len && ch != `'`; i++ { + ch = u8(str[i]) + all_parsed += ch.ascii_str() + if ch.is_letter() || ch.is_digit() || ch == `_` { + d_ident += ch.ascii_str() + } else { + if !(ch == `'`) { + if ch == `$` { + return error('cannot use string interpolation in compile time \$d() expression') + } + return error('invalid `\$d` identifier in "${str}", invalid character "${ch.ascii_str()}"') + } + } + } + if d_ident == '' { + return error('first argument of `\$d` must be a string identifier') + } + + // at this point we should have a valid identifier in `d_ident`. + // Next we parse out the default string value + + // advance past the `,` and the opening `'` in second argument, or ... eat whatever is there + all_parsed += u8(str[i]).ascii_str() + i++ + all_parsed += u8(str[i]).ascii_str() + i++ + // Rinse, repeat for the expected default value string + ch = u8(`.`) + mut d_default_value := '' + for ; i < str.len && ch != `'`; i++ { + ch = u8(str[i]) + all_parsed += ch.ascii_str() + if !(ch == `'`) { + d_default_value += ch.ascii_str() + } + if ch == `$` { + return error('cannot use string interpolation in compile time \$d() expression') + } + } + if d_default_value == '' { + return error('second argument of `\$d` must be a string identifier') + } + // at this point we have the identifier and the default value. + // now we need to resolve which one to use from `compile_values`. + d_value := compile_values[d_ident] or { d_default_value } + // if more `$d()` calls remains, resolve those as well: + rep := str.replace_once(all_parsed + ')', d_value) + if rep.contains(d_sig) { + return resolve_d_value(compile_values, rep) + } + return rep +} + // launch_tool - starts a V tool in a separate process, passing it the `args`. // All V tools are located in the cmd/tools folder, in files or folders prefixed by // the letter `v`, followed by the tool name, i.e. `cmd/tools/vdoc/` or `cmd/tools/vpm.v`. From a70006d580df3169012b84bcad36780e78e40827 Mon Sep 17 00:00:00 2001 From: lmp Date: Tue, 18 Jun 2024 11:45:41 +0200 Subject: [PATCH 12/25] docs: document `$d` in `docs.md` and `CHANGELOG.md` --- CHANGELOG.md | 5 +++++ doc/docs.md | 38 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index cd9df61a425845..86a5db489bc81b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +## V 0.4.7 (NEXT) + +#### Improvements in the language +- comptime: add support for `-d ident=value` and retrieval in code via `$d('ident', )`. + ## V 0.4.6 *20 May 2024* diff --git a/doc/docs.md b/doc/docs.md index 43ff4af722dcd3..f701b7e50aaf8f 100644 --- a/doc/docs.md +++ b/doc/docs.md @@ -6120,6 +6120,44 @@ V can bring in values at compile time from environment variables. `$env('ENV_VAR')` can also be used in top-level `#flag` and `#include` statements: `#flag linux -I $env('JAVA_HOME')/include`. +#### `$d` + +```v +module main + +const my_i64 = $d('my_i64', 1024) + +fn main() { + compile_time_value := $d('my_define', 'V rocks') + println(compile_time_value) + println(my_i64) +} +``` + +V can bring in values at compile time from `-d ident=value` flag defines. +If a flag is not provided via the command line, `$d` will return the default value +provided as the *second* argument. + +Supported default values are the following *pure* literals: +```v +fn main() { + val_str := $d('id_str', 'value') // can be changed by providing `-d id_str="my id"` + val_f64 := $d('id_f64', 42.0) // can be changed by providing `-d id_f64=84.0` + val_i64 := $d('id_i64', 56) // can be changed by providing `-d id_i64=123` + val_bool := $d('id_bool', false) // can be changed by providing `-d id_bool=true` + val_char := $d('id_char', `f`) // can be changed by providing `-d id_char=v`` + println(val_str) + println(val_f64) + println(val_i64) + println(val_bool) + println(rune(val_char)) +} +``` + +`$d('ident','value')` can also be used in top-level statements like `#flag` and `#include`: +`#flag linux -I $d('my_include','/usr')/include`. The default value for `$d` when used in these +statements should be literal `string`s. + #### `$compile_error` and `$compile_warn` These two comptime functions are very useful for displaying custom errors/warnings during From 4e68c084624029db79701fe1786d3598a4ca78a9 Mon Sep 17 00:00:00 2001 From: lmp Date: Tue, 18 Jun 2024 11:46:34 +0200 Subject: [PATCH 13/25] tests: use `my_i64` over `my_int` to clearify the default value of `$d` is parsed as `i64` --- vlib/v/gen/c/testdata/use_flag_comptime_values.vv | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/vlib/v/gen/c/testdata/use_flag_comptime_values.vv b/vlib/v/gen/c/testdata/use_flag_comptime_values.vv index 2d31d2dc451a33..7f17b36879e686 100644 --- a/vlib/v/gen/c/testdata/use_flag_comptime_values.vv +++ b/vlib/v/gen/c/testdata/use_flag_comptime_values.vv @@ -1,19 +1,19 @@ // This file should pass if compiled/run with: -// vtest vflags: -d my_f64=2.0 -d my_int=3 -d my_string="a four" -d my_bool -d my_char=g +// vtest vflags: -d my_f64=2.0 -d my_i64=3 -d my_string="a four" -d my_bool -d my_char=g const my_f64 = $d('my_f64', 1.0) -const my_int = $d('my_int', 2) +const my_i64 = $d('my_i64', 2) const my_string = $d('my_string', 'three') const my_bool = $d('my_bool', false) const my_char = $d('my_char', `f`) fn main() { assert my_f64 == 2.0 - assert my_int == 3 + assert my_i64 == 3 assert my_string == 'a four' assert my_bool == true assert my_char == `g` println(my_f64) - println(my_int) + println(my_i64) println(my_string) println(my_bool) println(rune(my_char)) From 3714382e029837239a9262ab69e42bf27b95645a Mon Sep 17 00:00:00 2001 From: lmp Date: Tue, 18 Jun 2024 11:53:53 +0200 Subject: [PATCH 14/25] tests: use `my_i64` over `my_int` to clearify the default value of `$d` is parsed as `i64` --- .../tests/comptime_value/default_comptime_values_test.v | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/vlib/v/checker/tests/comptime_value/default_comptime_values_test.v b/vlib/v/checker/tests/comptime_value/default_comptime_values_test.v index 89a65c6df4a830..a9927d8969fa56 100644 --- a/vlib/v/checker/tests/comptime_value/default_comptime_values_test.v +++ b/vlib/v/checker/tests/comptime_value/default_comptime_values_test.v @@ -1,12 +1,12 @@ const my_f64 = $d('my_f64', 1.0) -const my_int = $d('my_int', 2) +const my_i64 = $d('my_i64', 2) const my_string = $d('my_string', 'three') const my_bool = $d('my_bool', false) const my_char = $d('my_char', `f`) fn test_default_compile_values() { assert my_f64 == 1.0 - assert my_int == 2 + assert my_i64 == 2 assert my_string == 'three' assert my_bool == false assert my_char == `f` From 2c0d4630eb2597360cbb80ae3d904021d1bed0b2 Mon Sep 17 00:00:00 2001 From: lmp Date: Tue, 18 Jun 2024 12:00:26 +0200 Subject: [PATCH 15/25] docs: fix via 2x`VAUTOFIX=1 ./v check-md doc/docs.md` --- doc/docs.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/docs.md b/doc/docs.md index f701b7e50aaf8f..41dab8dfb01881 100644 --- a/doc/docs.md +++ b/doc/docs.md @@ -6130,7 +6130,7 @@ const my_i64 = $d('my_i64', 1024) fn main() { compile_time_value := $d('my_define', 'V rocks') println(compile_time_value) - println(my_i64) + println(my_i64) } ``` @@ -7769,4 +7769,4 @@ Assignment Operators += -= *= /= %= &= |= ^= >>= <<= >>>= -``` +``` \ No newline at end of file From 9e61095f65989a2e9979150916707753ad5b788e Mon Sep 17 00:00:00 2001 From: lmp Date: Tue, 18 Jun 2024 13:02:15 +0200 Subject: [PATCH 16/25] docs: add output examples with and without `-d` usage --- doc/docs.md | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/doc/docs.md b/doc/docs.md index 597899cf4a3cb3..62d6378bfe421c 100644 --- a/doc/docs.md +++ b/doc/docs.md @@ -6128,12 +6128,24 @@ module main const my_i64 = $d('my_i64', 1024) fn main() { - compile_time_value := $d('my_define', 'V rocks') + compile_time_value := $d('my_string', 'V') println(compile_time_value) println(my_i64) } ``` +Running the above with `v run .` will output: +``` +V +1024 +``` + +Running the above with `v -d my_i64=4096 -d my_string="V rocks" run .` will output: +``` +V rocks +4096 +``` + V can bring in values at compile time from `-d ident=value` flag defines. If a flag is not provided via the command line, `$d` will return the default value provided as the *second* argument. From ed003d7213bd259218852c3bbfd5f745ad01b97f Mon Sep 17 00:00:00 2001 From: lmp Date: Tue, 18 Jun 2024 13:10:49 +0200 Subject: [PATCH 17/25] docs: remove surplus "`" character --- doc/docs.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/docs.md b/doc/docs.md index 62d6378bfe421c..c7b8df9813c86b 100644 --- a/doc/docs.md +++ b/doc/docs.md @@ -6157,7 +6157,7 @@ fn main() { val_f64 := $d('id_f64', 42.0) // can be changed by providing `-d id_f64=84.0` val_i64 := $d('id_i64', 56) // can be changed by providing `-d id_i64=123` val_bool := $d('id_bool', false) // can be changed by providing `-d id_bool=true` - val_char := $d('id_char', `f`) // can be changed by providing `-d id_char=v`` + val_char := $d('id_char', `f`) // can be changed by providing `-d id_char=v` println(val_str) println(val_f64) println(val_i64) From 187eb649b3f098876eac669917a0dfac9ba59aa5 Mon Sep 17 00:00:00 2001 From: Delyan Angelov Date: Tue, 18 Jun 2024 17:27:29 +0300 Subject: [PATCH 18/25] checker,cgen: fix `$if $d(hi, false) {` bug --- vlib/v/checker/comptime.v | 10 ++ vlib/v/gen/c/comptime.v | 17 ++- .../c/testdata/use_flag_comptime_with_if.out | 44 +++++++ .../c/testdata/use_flag_comptime_with_if.vv | 111 ++++++++++++++++++ 4 files changed, 181 insertions(+), 1 deletion(-) create mode 100644 vlib/v/gen/c/testdata/use_flag_comptime_with_if.out create mode 100644 vlib/v/gen/c/testdata/use_flag_comptime_with_if.vv diff --git a/vlib/v/checker/comptime.v b/vlib/v/checker/comptime.v index 1d756689e37f8a..c7ba8175725d0a 100644 --- a/vlib/v/checker/comptime.v +++ b/vlib/v/checker/comptime.v @@ -1025,6 +1025,16 @@ fn (mut c Checker) comptime_if_branch(mut cond ast.Expr, pos token.Pos) Comptime return .skip } m.run() or { return .skip } + return .eval + } + if cond.is_compile_value { + t := c.expr(mut cond) + if t != ast.bool_type { + c.error('inside \$if, only \$d() expressions that return bool are allowed', + cond.pos) + return .skip + } + return .unknown // always fully generate the code for that branch } return .eval } diff --git a/vlib/v/gen/c/comptime.v b/vlib/v/gen/c/comptime.v index 5902770680ae3f..ad2786c8a1ded3 100644 --- a/vlib/v/gen/c/comptime.v +++ b/vlib/v/gen/c/comptime.v @@ -690,7 +690,22 @@ fn (mut g Gen) comptime_if_cond(cond ast.Expr, pkg_exist bool) (bool, bool) { return true, false } ast.ComptimeCall { - g.write('${pkg_exist}') + if cond.method_name == 'pkgconfig' { + g.write('${pkg_exist}') + return true, false + } + if cond.method_name == 'd' { + if cond.result_type == ast.bool_type { + if cond.compile_value == 'true' { + g.write('1') + } else { + g.write('0') + } + } else { + g.write('defined(CUSTOM_DEFINE_${cond.args_var})') + } + return true, false + } return true, false } ast.SelectorExpr { diff --git a/vlib/v/gen/c/testdata/use_flag_comptime_with_if.out b/vlib/v/gen/c/testdata/use_flag_comptime_with_if.out new file mode 100644 index 00000000000000..a12528a00a8f4a --- /dev/null +++ b/vlib/v/gen/c/testdata/use_flag_comptime_with_if.out @@ -0,0 +1,44 @@ +>>>>> Should be compiled with: `./v -d ddd1=true -d ddd2=false` +>>>>> Note that ddd3 is not passed *on purpose*, to test the default . +=========================================================================== +$d(ddd1, false) : true +$d(ddd1, true) : true +------------------------------------------------------------ +Checking $if with default false: +1 ddd1 is true +Checking $if with default true: +2 ddd1 is true +------------------------------------------------------------ +Checking $if !$d(ddd1) with default false: +3 !ddd1 is false +Checking $if !$d() with default true: +4 !ddd1 is false + +=========================================================================== +$d(ddd2, false) : false +$d(ddd2, true) : false +------------------------------------------------------------ +Checking $if with default false: +1 ddd2 is false +Checking $if with default true: +2 ddd2 is false +------------------------------------------------------------ +Checking $if !$d() with default false: +3 !ddd2 is true +Checking $if !$d() with default true: +4 !ddd2 is true + +=========================================================================== +$d(ddd3, false) : false +$d(ddd3, true) : true +------------------------------------------------------------ +Checking $if with default false: +1 ddd3 is false +Checking $if with default true: +2 ddd3 is true +------------------------------------------------------------ +Checking $if !$d() with default false: +3 !ddd3 is true +Checking $if !$d() with default true: +4 !ddd3 is false + diff --git a/vlib/v/gen/c/testdata/use_flag_comptime_with_if.vv b/vlib/v/gen/c/testdata/use_flag_comptime_with_if.vv new file mode 100644 index 00000000000000..89bb7916d8e151 --- /dev/null +++ b/vlib/v/gen/c/testdata/use_flag_comptime_with_if.vv @@ -0,0 +1,111 @@ +// vtest vflags: -d ddd1=true -d ddd2=false + +fn main() { + println('>>>>> Should be compiled with: `./v -d ddd1=true -d ddd2=false`') + println('>>>>> Note that ddd3 is not passed *on purpose*, to test the default .') + assert $d('ddd1', false) == true + assert $d('ddd2', true) == false + assert $d('ddd3', true) == true + check_ddd1() + check_ddd2() + check_ddd3() +} + +fn check_ddd1() { + println('===========================================================================') + println('\$d(ddd1, false) : ' + $d('ddd1', false).str()) + println('\$d(ddd1, true) : ' + $d('ddd1', true).str()) + println('------------------------------------------------------------') + println('Checking \$if with default false:') + $if $d('ddd1', false) { + println('1 ddd1 is true') + } $else { + println('1 ddd1 is false') + } + println('Checking \$if with default true:') + $if $d('ddd1', true) { + println('2 ddd1 is true') + } $else { + println('2 ddd1 is false') + } + println('------------------------------------------------------------') + println('Checking \$if !\$d(ddd1) with default false:') + $if !$d('ddd1', false) { + println('3 !ddd1 is true') + } $else { + println('3 !ddd1 is false') + } + println('Checking \$if !\$d() with default true:') + $if !$d('ddd1', true) { + println('4 !ddd1 is true') + } $else { + println('4 !ddd1 is false') + } + println('') +} + +fn check_ddd2() { + println('===========================================================================') + println('\$d(ddd2, false) : ' + $d('ddd2', false).str()) + println('\$d(ddd2, true) : ' + $d('ddd2', true).str()) + println('------------------------------------------------------------') + println('Checking \$if with default false:') + $if $d('ddd2', false) { + println('1 ddd2 is true') + } $else { + println('1 ddd2 is false') + } + println('Checking \$if with default true:') + $if $d('ddd2', true) { + println('2 ddd2 is true') + } $else { + println('2 ddd2 is false') + } + println('------------------------------------------------------------') + println('Checking \$if !\$d() with default false:') + $if !$d('ddd2', false) { + println('3 !ddd2 is true') + } $else { + println('3 !ddd2 is false') + } + println('Checking \$if !\$d() with default true:') + $if !$d('ddd2', true) { + println('4 !ddd2 is true') + } $else { + println('4 !ddd2 is false') + } + println('') +} + +fn check_ddd3() { + println('===========================================================================') + println('\$d(ddd3, false) : ' + $d('ddd3', false).str()) + println('\$d(ddd3, true) : ' + $d('ddd3', true).str()) + println('------------------------------------------------------------') + println('Checking \$if with default false:') + $if $d('ddd3', false) { + println('1 ddd3 is true') + } $else { + println('1 ddd3 is false') + } + println('Checking \$if with default true:') + $if $d('ddd3', true) { + println('2 ddd3 is true') + } $else { + println('2 ddd3 is false') + } + println('------------------------------------------------------------') + println('Checking \$if !\$d() with default false:') + $if !$d('ddd3', false) { + println('3 !ddd3 is true') + } $else { + println('3 !ddd3 is false') + } + println('Checking \$if !\$d() with default true:') + $if !$d('ddd3', true) { + println('4 !ddd3 is true') + } $else { + println('4 !ddd3 is false') + } + println('') +} From a485534e424b7ee06c427bd705160431d2deff82 Mon Sep 17 00:00:00 2001 From: Delyan Angelov Date: Tue, 18 Jun 2024 20:14:14 +0300 Subject: [PATCH 19/25] docs: use txt for the operator appendix --- doc/docs.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/docs.md b/doc/docs.md index c7b8df9813c86b..3f041c89d6203f 100644 --- a/doc/docs.md +++ b/doc/docs.md @@ -7747,7 +7747,7 @@ See also [V Types](#v-types). This lists operators for [primitive types](#primitive-types) only. -```v ignore +```txt + sum integers, floats, strings - difference integers, floats * product integers, floats From f19079d707bc67a4cf01863aae5a806150b4a18d Mon Sep 17 00:00:00 2001 From: Delyan Angelov Date: Tue, 18 Jun 2024 20:41:45 +0300 Subject: [PATCH 20/25] docs: describe `$if $d(ident, false) {`, expand the existing description a bit --- doc/docs.md | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/doc/docs.md b/doc/docs.md index 3f041c89d6203f..05874f01f00290 100644 --- a/doc/docs.md +++ b/doc/docs.md @@ -6122,6 +6122,17 @@ V can bring in values at compile time from environment variables. #### `$d` +V can bring in values at compile time from `-d ident=value` flag defines, passed on +the command line to the compiler. You can also pass `-d ident`, which will have the +same meaning as passing `-d ident=true`. + +To get the value in your code, use: `$d('ident', default)`, where `default` +can be `false` for booleans, `0` or `123` for i64 numbers, `0.0` or `113.0` +for f64 numbers, `'a string'` for strings. + +When a flag is not provided via the command line, `$d()` will return the `default` +value provided as the *second* argument. + ```v module main @@ -6146,11 +6157,7 @@ V rocks 4096 ``` -V can bring in values at compile time from `-d ident=value` flag defines. -If a flag is not provided via the command line, `$d` will return the default value -provided as the *second* argument. - -Supported default values are the following *pure* literals: +Here is an example of how to use the default values, which have to be *pure* literals: ```v fn main() { val_str := $d('id_str', 'value') // can be changed by providing `-d id_str="my id"` @@ -6170,6 +6177,10 @@ fn main() { `#flag linux -I $d('my_include','/usr')/include`. The default value for `$d` when used in these statements should be literal `string`s. +`$d('ident', false)` can also be used inside `$if $d('ident', false) {` statements, +granting you the ability to selectively turn on/off certain sections of code, at compile +time, without modifying your source code, or keeping different versions of it. + #### `$compile_error` and `$compile_warn` These two comptime functions are very useful for displaying custom errors/warnings during From 82e8d22c40966875937c70a8cecc16c0a8f3e7ab Mon Sep 17 00:00:00 2001 From: Delyan Angelov Date: Tue, 18 Jun 2024 20:46:29 +0300 Subject: [PATCH 21/25] docs: restore `v ignore` for the operator appendix --- doc/docs.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/docs.md b/doc/docs.md index 05874f01f00290..3dfc96fa888549 100644 --- a/doc/docs.md +++ b/doc/docs.md @@ -7758,7 +7758,7 @@ See also [V Types](#v-types). This lists operators for [primitive types](#primitive-types) only. -```txt +```v ignore + sum integers, floats, strings - difference integers, floats * product integers, floats From 27e6fa9024ab223180414f53fc5fdb687fbbc4d9 Mon Sep 17 00:00:00 2001 From: Delyan Angelov Date: Tue, 18 Jun 2024 20:48:32 +0300 Subject: [PATCH 22/25] v.util: small cleanup, extract d_sig as a constant --- vlib/v/util/util.v | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/vlib/v/util/util.v b/vlib/v/util/util.v index 9a10bdf85ce4a2..f38c10b02c76ac 100644 --- a/vlib/v/util/util.v +++ b/vlib/v/util/util.v @@ -115,18 +115,19 @@ pub fn resolve_env_value(str string, check_for_presence bool) !string { return rep } +const d_sig = "\$d('" + // resolve_d_value replaces all occurrences of `$d('ident','value')` // in `str` with either the default `'value'` param or a compile value passed via `-d ident=value`. pub fn resolve_d_value(compile_values map[string]string, str string) !string { - d_sig := "\$d('" - at := str.index(d_sig) or { - return error('no "${d_sig}' + '...\')" could be found in "${str}".') + at := str.index(util.d_sig) or { + return error('no "${util.d_sig}' + '...\')" could be found in "${str}".') } - mut all_parsed := d_sig + mut all_parsed := util.d_sig mut ch := u8(`.`) mut d_ident := '' mut i := 0 - for i = at + d_sig.len; i < str.len && ch != `'`; i++ { + for i = at + util.d_sig.len; i < str.len && ch != `'`; i++ { ch = u8(str[i]) all_parsed += ch.ascii_str() if ch.is_letter() || ch.is_digit() || ch == `_` { @@ -173,7 +174,7 @@ pub fn resolve_d_value(compile_values map[string]string, str string) !string { d_value := compile_values[d_ident] or { d_default_value } // if more `$d()` calls remains, resolve those as well: rep := str.replace_once(all_parsed + ')', d_value) - if rep.contains(d_sig) { + if rep.contains(util.d_sig) { return resolve_d_value(compile_values, rep) } return rep From a90f39d2ca145a56b6179f71104be5f75a10e0e9 Mon Sep 17 00:00:00 2001 From: Delyan Angelov Date: Tue, 18 Jun 2024 21:27:26 +0300 Subject: [PATCH 23/25] tests: move files to places where they will be used by `./v vlib/v/compiler_errors_test.v` and `./v test-self` --- vlib/v/checker/tests/comptime_value/parser_errors_1.run.out | 3 --- ...errors_2.run.out => comptime_value_d_in_include_errors.out} | 2 +- ...arser_errors_2.vv => comptime_value_d_in_include_errors.vv} | 0 .../comptime_value_d_values_can_only_be_pure_literals.out | 3 +++ ...vv => comptime_value_d_values_can_only_be_pure_literals.vv} | 0 .../using_comptime_d_value.run.out} | 2 +- .../using_comptime_value.vv => run/using_comptime_d_value.vv} | 0 vlib/v/compiler_errors_test.v | 2 ++ .../comptime_value_d_default_test.v} | 0 9 files changed, 7 insertions(+), 5 deletions(-) delete mode 100644 vlib/v/checker/tests/comptime_value/parser_errors_1.run.out rename vlib/v/checker/tests/{comptime_value/parser_errors_2.run.out => comptime_value_d_in_include_errors.out} (83%) rename vlib/v/checker/tests/{comptime_value/parser_errors_2.vv => comptime_value_d_in_include_errors.vv} (100%) create mode 100644 vlib/v/checker/tests/comptime_value_d_values_can_only_be_pure_literals.out rename vlib/v/checker/tests/{comptime_value/parser_errors_1.vv => comptime_value_d_values_can_only_be_pure_literals.vv} (100%) rename vlib/v/checker/tests/{comptime_value/using_comptime_value.run.out => run/using_comptime_d_value.run.out} (68%) rename vlib/v/checker/tests/{comptime_value/using_comptime_value.vv => run/using_comptime_d_value.vv} (100%) rename vlib/v/{checker/tests/comptime_value/default_comptime_values_test.v => tests/comptime_value_d_default_test.v} (100%) diff --git a/vlib/v/checker/tests/comptime_value/parser_errors_1.run.out b/vlib/v/checker/tests/comptime_value/parser_errors_1.run.out deleted file mode 100644 index 646412c880bc79..00000000000000 --- a/vlib/v/checker/tests/comptime_value/parser_errors_1.run.out +++ /dev/null @@ -1,3 +0,0 @@ -vlib/v/checker/tests/comptime_value/parser_errors_1.vv:1:16: error: -d values can only be pure literals - 1 | const my_f32 = $d('my_f32', f32(42.0)) - | ~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/vlib/v/checker/tests/comptime_value/parser_errors_2.run.out b/vlib/v/checker/tests/comptime_value_d_in_include_errors.out similarity index 83% rename from vlib/v/checker/tests/comptime_value/parser_errors_2.run.out rename to vlib/v/checker/tests/comptime_value_d_in_include_errors.out index dbc4202d57e5c7..58b4a71ccb2998 100644 --- a/vlib/v/checker/tests/comptime_value/parser_errors_2.run.out +++ b/vlib/v/checker/tests/comptime_value_d_in_include_errors.out @@ -1 +1 @@ -builder error: Header file "/opt/invalid/include/stdio.h", needed for module `main` was not found. Please install the corresponding development headers. \ No newline at end of file +builder error: Header file "/opt/invalid/include/stdio.h", needed for module `main` was not found. Please install the corresponding development headers. diff --git a/vlib/v/checker/tests/comptime_value/parser_errors_2.vv b/vlib/v/checker/tests/comptime_value_d_in_include_errors.vv similarity index 100% rename from vlib/v/checker/tests/comptime_value/parser_errors_2.vv rename to vlib/v/checker/tests/comptime_value_d_in_include_errors.vv diff --git a/vlib/v/checker/tests/comptime_value_d_values_can_only_be_pure_literals.out b/vlib/v/checker/tests/comptime_value_d_values_can_only_be_pure_literals.out new file mode 100644 index 00000000000000..17bb7e081bd1fb --- /dev/null +++ b/vlib/v/checker/tests/comptime_value_d_values_can_only_be_pure_literals.out @@ -0,0 +1,3 @@ +vlib/v/checker/tests/comptime_value_d_values_can_only_be_pure_literals.vv:1:16: error: -d values can only be pure literals + 1 | const my_f32 = $d('my_f32', f32(42.0)) + | ~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/vlib/v/checker/tests/comptime_value/parser_errors_1.vv b/vlib/v/checker/tests/comptime_value_d_values_can_only_be_pure_literals.vv similarity index 100% rename from vlib/v/checker/tests/comptime_value/parser_errors_1.vv rename to vlib/v/checker/tests/comptime_value_d_values_can_only_be_pure_literals.vv diff --git a/vlib/v/checker/tests/comptime_value/using_comptime_value.run.out b/vlib/v/checker/tests/run/using_comptime_d_value.run.out similarity index 68% rename from vlib/v/checker/tests/comptime_value/using_comptime_value.run.out rename to vlib/v/checker/tests/run/using_comptime_d_value.run.out index a172d30507770b..d1e104b41f04b1 100644 --- a/vlib/v/checker/tests/comptime_value/using_comptime_value.run.out +++ b/vlib/v/checker/tests/run/using_comptime_d_value.run.out @@ -1,3 +1,3 @@ 42.0 false -done \ No newline at end of file +done diff --git a/vlib/v/checker/tests/comptime_value/using_comptime_value.vv b/vlib/v/checker/tests/run/using_comptime_d_value.vv similarity index 100% rename from vlib/v/checker/tests/comptime_value/using_comptime_value.vv rename to vlib/v/checker/tests/run/using_comptime_d_value.vv diff --git a/vlib/v/compiler_errors_test.v b/vlib/v/compiler_errors_test.v index c5b8e1a5fe59d0..f4dd7ad9ef4676 100644 --- a/vlib/v/compiler_errors_test.v +++ b/vlib/v/compiler_errors_test.v @@ -237,6 +237,7 @@ fn (mut tasks Tasks) run() { // cleaner error message, than a generic C error, but without the explanation. m_skip_files << 'vlib/v/checker/tests/missing_c_lib_header_1.vv' m_skip_files << 'vlib/v/checker/tests/missing_c_lib_header_with_explanation_2.vv' + m_skip_files << 'vlib/v/checker/tests/comptime_value_d_in_include_errors.vv' } $if msvc { m_skip_files << 'vlib/v/checker/tests/asm_alias_does_not_exist.vv' @@ -244,6 +245,7 @@ fn (mut tasks Tasks) run() { // TODO: investigate why MSVC regressed m_skip_files << 'vlib/v/checker/tests/missing_c_lib_header_1.vv' m_skip_files << 'vlib/v/checker/tests/missing_c_lib_header_with_explanation_2.vv' + m_skip_files << 'vlib/v/checker/tests/comptime_value_d_in_include_errors.vv' } $if windows { m_skip_files << 'vlib/v/checker/tests/modules/deprecated_module' diff --git a/vlib/v/checker/tests/comptime_value/default_comptime_values_test.v b/vlib/v/tests/comptime_value_d_default_test.v similarity index 100% rename from vlib/v/checker/tests/comptime_value/default_comptime_values_test.v rename to vlib/v/tests/comptime_value_d_default_test.v From 1315786e9f59f712132de7d7ad1296a064a6c2cf Mon Sep 17 00:00:00 2001 From: Delyan Angelov Date: Tue, 18 Jun 2024 22:58:41 +0300 Subject: [PATCH 24/25] fix for using_comptime_d_value.vv (include relative to the main V project root, instead of /usr/include) --- vlib/v/checker/tests/run/using_comptime_d_value.vv | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vlib/v/checker/tests/run/using_comptime_d_value.vv b/vlib/v/checker/tests/run/using_comptime_d_value.vv index 827dc4616d562b..75725a79420bed 100644 --- a/vlib/v/checker/tests/run/using_comptime_d_value.vv +++ b/vlib/v/checker/tests/run/using_comptime_d_value.vv @@ -1,5 +1,5 @@ #flag -I $d('my_flag','flag_value')/xyz -#include "$d('my_include','/usr/include')/stdio.h" +#include "@VMODROOT/$d('my_include','vlib/v')/tests/project_with_c_code/mod1/c/header.h" const my_f64 = $d('my_f64', 42.0) From be034485114525f593650ae9b042b11a8979e69d Mon Sep 17 00:00:00 2001 From: Delyan Angelov Date: Wed, 19 Jun 2024 06:22:10 +0300 Subject: [PATCH 25/25] Update vlib/v/util/util.v Co-authored-by: larpon <768942+larpon@users.noreply.github.com> --- vlib/v/util/util.v | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vlib/v/util/util.v b/vlib/v/util/util.v index f38c10b02c76ac..edd14c1c09758f 100644 --- a/vlib/v/util/util.v +++ b/vlib/v/util/util.v @@ -167,7 +167,7 @@ pub fn resolve_d_value(compile_values map[string]string, str string) !string { } } if d_default_value == '' { - return error('second argument of `\$d` must be a string identifier') + return error('second argument of `\$d` must be a pure literal') } // at this point we have the identifier and the default value. // now we need to resolve which one to use from `compile_values`.