From 18c7da9a5ee7c16b58147926c037cc3c41738660 Mon Sep 17 00:00:00 2001 From: Alexander Medvednikov Date: Thu, 27 Oct 2022 11:00:51 +0300 Subject: [PATCH] all: new string interpolation "hello {name}!" --- .github/workflows/ci.yml | 1 + ROADMAP.md | 2 +- cmd/tools/gen_vc.v | 4 +-- cmd/tools/modules/vgit/vgit.v | 6 ++-- cmd/tools/vdoctor.v | 2 +- cmd/tools/vpm.v | 2 +- vlib/builtin/string_interpolation.v | 12 +++---- vlib/builtin/string_test.v | 5 +++ vlib/v/eval/gen/infix_gen.v | 30 ++++++++-------- vlib/v/fmt/fmt.v | 2 +- vlib/v/gen/c/assign.v | 2 +- vlib/v/gen/c/auto_eq_methods.v | 2 +- vlib/v/gen/c/auto_str_methods.v | 52 ++++++++++++++-------------- vlib/v/gen/c/cgen.v | 17 +++++---- vlib/v/gen/c/cheaders.v | 10 +++--- vlib/v/gen/c/fn.v | 2 +- vlib/v/gen/c/for.v | 2 +- vlib/v/gen/c/sql.v | 2 +- vlib/v/gen/c/str.v | 2 +- vlib/v/gen/c/str_intp.v | 4 +-- vlib/v/gen/c/struct.v | 2 +- vlib/v/gen/js/auto_str_methods.v | 8 ++--- vlib/v/gen/js/fn.v | 2 +- vlib/v/gen/js/sourcemap/basic_test.v | 4 +-- vlib/v/scanner/scanner.v | 33 +++++++++++++++++- vlib/v/token/pos.v | 2 +- 26 files changed, 124 insertions(+), 88 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 457c7e0e7..9a1149c66 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -222,6 +222,7 @@ jobs: git clone --depth 1 https://github.com/vlang/ved cd ved && ../v -o ved . ../v -autofree . + ../v -prod . cd .. # - name: Test c2v # run: | diff --git a/ROADMAP.md b/ROADMAP.md index b4f41f07d..58f519b3e 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -9,7 +9,7 @@ - [ ] Recursive structs via optionals: `struct Node { next ?Node }` - [ ] Optional function struct fields - [ ] Handle function pointers safely, remove `if function == 0 {` -- [ ] Bundle OpenSSL like GC +- [x] Bundle OpenSSL like GC - [x] Anonymous structs - [ ] -usecache on by default - [ ] -skip-unused on by default diff --git a/cmd/tools/gen_vc.v b/cmd/tools/gen_vc.v index 7428bb433..9d1e04540 100644 --- a/cmd/tools/gen_vc.v +++ b/cmd/tools/gen_vc.v @@ -169,10 +169,10 @@ pub fn (mut ws WebhookServer) genhook() { ws.gen_vc.generate() // error in generate if ws.gen_vc.gen_error { - ws.json('{status: "failed"}') + ws.json('{ status: "failed" }') return } - ws.json('{status: "ok"}') + ws.json('{ status: "ok" }') } pub fn (ws &WebhookServer) reset() { diff --git a/cmd/tools/modules/vgit/vgit.v b/cmd/tools/modules/vgit/vgit.v index e85c743d3..4f3b32425 100644 --- a/cmd/tools/modules/vgit/vgit.v +++ b/cmd/tools/modules/vgit/vgit.v @@ -112,10 +112,10 @@ pub fn (mut vgit_context VGitContext) compile_oldv_if_needed() { mut command_for_selfbuilding := '' if 'windows' == os.user_os() { command_for_building_v_from_c_source = '$vgit_context.cc -std=c99 -I ./thirdparty/stdatomic/win -municode -w -o cv.exe "$vgit_context.path_vc/v_win.c" ' - command_for_selfbuilding = './cv.exe -o $vgit_context.vexename {SOURCE}' + command_for_selfbuilding = './cv.exe -o $vgit_context.vexename \{SOURCE}' } else { command_for_building_v_from_c_source = '$vgit_context.cc -std=gnu11 -I ./thirdparty/stdatomic/nix -w -o cv "$vgit_context.path_vc/v.c" -lm -lpthread' - command_for_selfbuilding = './cv -o $vgit_context.vexename {SOURCE}' + command_for_selfbuilding = './cv -o $vgit_context.vexename \{SOURCE}' } scripting.chdir(vgit_context.workdir) clone_or_pull(vgit_context.v_repo_url, vgit_context.path_v) @@ -146,7 +146,7 @@ pub fn (mut vgit_context VGitContext) compile_oldv_if_needed() { scripting.run('make fresh_tcc') } scripting.run(command_for_building_v_from_c_source) - build_cmd := command_for_selfbuilding.replace('{SOURCE}', vgit_context.vvlocation) + build_cmd := command_for_selfbuilding.replace('\{SOURCE}', vgit_context.vvlocation) scripting.run(build_cmd) // At this point, there exists a file vgit_context.vexepath // which should be a valid working V executable. diff --git a/cmd/tools/vdoctor.v b/cmd/tools/vdoctor.v index f5243fa40..64ae8acaa 100644 --- a/cmd/tools/vdoctor.v +++ b/cmd/tools/vdoctor.v @@ -72,7 +72,7 @@ fn (mut a App) collect_info() { os_details += ' (WSL)' } // From https://unix.stackexchange.com/a/14346 - awk_cmd := '[ "$(awk \'\$5=="/" {print \$1}\' ' 'lt': '<' @@ -46,7 +46,7 @@ fn main() { for lt2 in literal_types { b.write_string('$lt2{return left.val${op}right}') } - b.write_string("else{e.error('invalid operands to $op: $ct and \$right.type_name()')}}}") + b.write_string("else{ e.error('invalid operands to $op: $ct and \$right.type_name()')}}}") } for lt in literal_types { b.write_string('$lt {match right{') @@ -61,9 +61,9 @@ fn main() { b.write_string(" literal and \$right.type_name()')}}}") } if op in ['==', '!='] { - b.write_string('string{match right{string{return left${op}right}else{e.error(\'invalid operands to $op: string and \$right.type_name()\')}}}') + b.write_string('string{ match right{ string{ return left${op}right}else{ e.error(\'invalid operands to $op: string and \$right.type_name()\')}}}') } - b.write_string("else {e.error('invalid operands to $op: \$left.type_name() and \$right.type_name()')}}}") + b.write_string("else { e.error('invalid operands to $op: \$left.type_name() and \$right.type_name()')}}}") } for math, op in math_ops { b.write_string('.$math{match left{') @@ -77,9 +77,9 @@ fn main() { continue } unsafe_start, unsafe_end := if op in ['<<', '>>'] { 'unsafe{', '}' } else { '', '' } - b.write_string('$ct2{if expecting in ast.signed_integer_type_idxs{return Int{i64(left.val)${op}i64(right.val),i8(e.type_to_size(expecting))}}else if expecting in ast.unsigned_integer_type_idxs{return Uint{u64(left.val)${op}u64(right.val),i8(e.type_to_size(expecting))}}else if expecting==ast.int_literal_type_idx{${unsafe_start}return i64(i64(left.val)${op}i64(right.val))$unsafe_end}') + b.write_string('$ct2{ if expecting in ast.signed_integer_type_idxs{ return Int{ i64(left.val)${op}i64(right.val),i8(e.type_to_size(expecting))}}else if expecting in ast.unsigned_integer_type_idxs{ return Uint{ u64(left.val)${op}u64(right.val),i8(e.type_to_size(expecting))}}else if expecting==ast.int_literal_type_idx{${unsafe_start}return i64(i64(left.val)${op}i64(right.val))$unsafe_end}') if op !in ['<<', '>>'] { - b.write_string('else if expecting in ast.float_type_idxs{return Float{f64(left.val)${op}f64(right.val), i8(e.type_to_size(expecting))}}else if expecting==ast.float_literal_type_idx{return f64(f64(left.val)${op}f64(right.val))}') + b.write_string('else if expecting in ast.float_type_idxs{ return Float{ f64(left.val)${op}f64(right.val),i8(e.type_to_size(expecting))}}else if expecting==ast.float_literal_type_idx{ return f64(f64(left.val)${op}f64(right.val))}') } b.write_string(uk_expect_footer) } @@ -88,13 +88,13 @@ fn main() { continue } unsafe_start, unsafe_end := if op in ['<<', '>>'] { 'unsafe{', '}' } else { '', '' } - b.write_string('$lt2{if expecting in ast.signed_integer_type_idxs{return Int{i64(left.val)${op}i64(right),i8(e.type_to_size(expecting))}}else if expecting in ast.unsigned_integer_type_idxs{return Uint{u64(left.val)${op}u64(right),i8(e.type_to_size(expecting))}}else if expecting==ast.int_literal_type_idx{${unsafe_start}return i64(i64(left.val)${op}i64(right))$unsafe_end}') + b.write_string('$lt2{ if expecting in ast.signed_integer_type_idxs{ return Int{ i64(left.val)${op}i64(right),i8(e.type_to_size(expecting))}}else if expecting in ast.unsigned_integer_type_idxs{ return Uint{ u64(left.val)${op}u64(right),i8(e.type_to_size(expecting))}}else if expecting==ast.int_literal_type_idx{${unsafe_start}return i64(i64(left.val)${op}i64(right))$unsafe_end}') if op !in ['<<', '>>'] { - b.write_string('else if expecting in ast.float_type_idxs{return Float{f64(left.val)${op}f64(right), i8(e.type_to_size(expecting))}}else if expecting==ast.float_literal_type_idx{return f64(f64(left.val)${op}f64(right))}') + b.write_string('else if expecting in ast.float_type_idxs{ return Float{ f64(left.val)${op}f64(right), i8(e.type_to_size(expecting))}}else if expecting==ast.float_literal_type_idx{ return f64(f64(left.val)${op}f64(right))}') } b.write_string(uk_expect_footer) } - b.write_string("else {e.error('invalid operands to $op: $ct and \$right.type_name()')}}}") + b.write_string("else { e.error('invalid operands to $op: $ct and \$right.type_name()')}}}") } for lt in literal_types { if op in ['<<', '>>'] && lt == 'f64' { @@ -106,9 +106,9 @@ fn main() { continue } unsafe_start, unsafe_end := if op in ['<<', '>>'] { 'unsafe{', '}' } else { '', '' } - b.write_string('$ct2{if expecting in ast.signed_integer_type_idxs{return Int{i64(left)${op}i64(right.val),i8(e.type_to_size(expecting))}}else if expecting in ast.unsigned_integer_type_idxs{return Uint{u64(left)${op}u64(right.val),i8(e.type_to_size(expecting))}}else if expecting==ast.int_literal_type_idx{${unsafe_start}return i64(i64(left)${op}i64(right.val))$unsafe_end}') + b.write_string('$ct2{ if expecting in ast.signed_integer_type_idxs{ return Int{ i64(left)${op}i64(right.val),i8(e.type_to_size(expecting))}}else if expecting in ast.unsigned_integer_type_idxs{ return Uint{ u64(left)${op}u64(right.val),i8(e.type_to_size(expecting))}}else if expecting==ast.int_literal_type_idx{${unsafe_start}return i64(i64(left)${op}i64(right.val))$unsafe_end}') if op !in ['<<', '>>'] { - b.write_string('else if expecting in ast.float_type_idxs{return Float{f64(left)${op}f64(right.val), i8(e.type_to_size(expecting))}}else if expecting==ast.float_literal_type_idx{return f64(f64(left)${op}f64(right.val))}') + b.write_string('else if expecting in ast.float_type_idxs{ return Float{ f64(left)${op}f64(right.val), i8(e.type_to_size(expecting))}}else if expecting==ast.float_literal_type_idx{ return f64(f64(left)${op}f64(right.val))}') } b.write_string(uk_expect_footer) } @@ -117,9 +117,9 @@ fn main() { continue } unsafe_start, unsafe_end := if op in ['<<', '>>'] { 'unsafe{', '}' } else { '', '' } - b.write_string('$lt2{if expecting in ast.signed_integer_type_idxs{return Int{i64(left)${op}i64(right),i8(e.type_to_size(expecting))}}else if expecting in ast.unsigned_integer_type_idxs{return Uint{u64(left)${op}u64(right),i8(e.type_to_size(expecting))}}else if expecting==ast.int_literal_type_idx{${unsafe_start}return i64(i64(left)${op}i64(right))$unsafe_end}') + b.write_string('$lt2{if expecting in ast.signed_integer_type_idxs{ return Int{ i64(left)${op}i64(right),i8(e.type_to_size(expecting))}}else if expecting in ast.unsigned_integer_type_idxs{ return Uint{ u64(left)${op}u64(right),i8(e.type_to_size(expecting))}}else if expecting==ast.int_literal_type_idx{${unsafe_start}return i64(i64(left)${op}i64(right))$unsafe_end}') if op !in ['<<', '>>'] { - b.write_string('else if expecting in ast.float_type_idxs{return Float{f64(left)${op}f64(right), i8(e.type_to_size(expecting))}}else if expecting==ast.float_literal_type_idx{return f64(f64(left)${op}f64(right))}') + b.write_string('else if expecting in ast.float_type_idxs{ return Float{ f64(left)${op}f64(right), i8(e.type_to_size(expecting))}}else if expecting==ast.float_literal_type_idx{ return f64(f64(left)${op}f64(right))}') } b.write_string(uk_expect_footer) } @@ -127,7 +127,7 @@ fn main() { b.write_string(if lt == 'i64' { 'int' } else { 'float' }) b.write_string(" literal and \$right.type_name()')}}}") } - b.write_string("else {e.error('invalid operands to $op: \$left.type_name() and \$right.type_name()')}}}") + b.write_string("else { e.error('invalid operands to $op: \$left.type_name() and \$right.type_name()')}}}") } b.write_string(footer) diff --git a/vlib/v/fmt/fmt.v b/vlib/v/fmt/fmt.v index c4d1ca05e..1240281f9 100644 --- a/vlib/v/fmt/fmt.v +++ b/vlib/v/fmt/fmt.v @@ -1663,7 +1663,7 @@ pub fn (mut f Fmt) array_init(node ast.ArrayInit) { } f.write(f.table.type_to_str_using_aliases(node.elem_type, f.mod2alias)) if node.has_default { - f.write('{init: ') + f.write('\{init: ') f.expr(node.default_expr) f.write('}') } else { diff --git a/vlib/v/gen/c/assign.v b/vlib/v/gen/c/assign.v index 90959daa5..bcdbacd5f 100644 --- a/vlib/v/gen/c/assign.v +++ b/vlib/v/gen/c/assign.v @@ -209,7 +209,7 @@ fn (mut g Gen) assign_stmt(node_ ast.AssignStmt) { g.expr(val) } else { if left_sym.kind == .function { - g.write('{void* _ = ') + g.write('{ void* _ = ') } else { g.write('{$styp _ = ') } diff --git a/vlib/v/gen/c/auto_eq_methods.v b/vlib/v/gen/c/auto_eq_methods.v index 56a47e4ae..d7a116a38 100644 --- a/vlib/v/gen/c/auto_eq_methods.v +++ b/vlib/v/gen/c/auto_eq_methods.v @@ -352,7 +352,7 @@ fn (mut g Gen) gen_map_equality_fn(left_type ast.Type) string { } match kind { .string { - fn_builder.writeln('\t\tif (!fast_string_eq(*(string*)map_get(&b, k, &(string[]){_SLIT("")}), v)) {') + fn_builder.writeln('\t\tif (!fast_string_eq(*(string*)map_get(&b, k, &(string[]){ _SLIT("")}), v)) {') } .sum_type { eq_fn := g.gen_sumtype_equality_fn(value.typ) diff --git a/vlib/v/gen/c/auto_str_methods.v b/vlib/v/gen/c/auto_str_methods.v index f10f9adc1..b4230f3dc 100644 --- a/vlib/v/gen/c/auto_str_methods.v +++ b/vlib/v/gen/c/auto_str_methods.v @@ -237,9 +237,9 @@ fn (mut g Gen) gen_str_for_alias(info ast.Alias, styp string, str_fn_name string g.auto_str_funcs.writeln('\tstring indents = string_repeat(_SLIT(" "), indent_count);') g.auto_str_funcs.writeln('\tstring tmp_ds = ${parent_str_fn_name}(it);') g.auto_str_funcs.writeln('\tstring res = str_intp(3, _MOV((StrIntpData[]){ - {_SLIT0, $c.si_s_code, {.d_s = indents }}, - {_SLIT("${clean_type_v_type_name}("), $c.si_s_code, {.d_s = tmp_ds }}, - {_SLIT(")"), 0, {.d_c = 0 }} + { _SLIT0, $c.si_s_code, {.d_s = indents }}, + { _SLIT("${clean_type_v_type_name}("), $c.si_s_code, {.d_s = tmp_ds }}, + { _SLIT(")"), 0, {.d_c = 0 }} }));') g.auto_str_funcs.writeln('\tstring_free(&indents);') g.auto_str_funcs.writeln('\tstring_free(&tmp_ds);') @@ -307,7 +307,7 @@ fn (mut g Gen) gen_str_for_enum(info ast.Enum, styp string, str_fn_name string) g.auto_str_funcs.writeln('\tstring ret = _SLIT("$clean_name{");') g.auto_str_funcs.writeln('\tint first = 1;') for i, val in info.vals { - g.auto_str_funcs.writeln('\tif (it & (1 << $i)) {if (!first) {ret = string__plus(ret, _SLIT(" | "));} ret = string__plus(ret, _SLIT(".$val")); first = 0;}') + g.auto_str_funcs.writeln('\tif (it & (1 << $i)) { if (!first) { ret = string__plus(ret, _SLIT(" | "));} ret = string__plus(ret, _SLIT(".$val")); first = 0;}') } g.auto_str_funcs.writeln('\tret = string__plus(ret, _SLIT("}"));') g.auto_str_funcs.writeln('\treturn ret;') @@ -366,8 +366,8 @@ fn (mut g Gen) gen_str_for_interface(info ast.Interface, styp string, str_fn_nam } val += ')' res := 'str_intp(2, _MOV((StrIntpData[]){ - {_SLIT("${clean_interface_v_type_name}(\'"), $c.si_s_code, {.d_s = $val}}, - {_SLIT("\')"), 0, {.d_c = 0 }} + { _SLIT("${clean_interface_v_type_name}(\'"), $c.si_s_code, {.d_s = $val}}, + { _SLIT("\')"), 0, {.d_c = 0 }} }))' fn_builder.write_string('\tif (x._typ == _${styp}_${sub_sym.cname}_index)') fn_builder.write_string(' return $res;') @@ -378,8 +378,8 @@ fn (mut g Gen) gen_str_for_interface(info ast.Interface, styp string, str_fn_nam } val += ')' res := 'str_intp(2, _MOV((StrIntpData[]){ - {_SLIT("${clean_interface_v_type_name}("), $c.si_s_code, {.d_s = $val}}, - {_SLIT(")"), 0, {.d_c = 0 }} + { _SLIT("${clean_interface_v_type_name}("), $c.si_s_code, {.d_s = $val}}, + { _SLIT(")"), 0, {.d_c = 0 }} }))' fn_builder.write_string('\tif (x._typ == _${styp}_${sub_sym.cname}_index)') fn_builder.write_string(' return $res;\n') @@ -435,8 +435,8 @@ fn (mut g Gen) gen_str_for_union_sum_type(info ast.SumType, styp string, str_fn_ } val += ')' res := 'str_intp(2, _MOV((StrIntpData[]){ - {_SLIT("${clean_sum_type_v_type_name}(\'"), $c.si_s_code, {.d_s = $val}}, - {_SLIT("\')"), 0, {.d_c = 0 }} + { _SLIT("${clean_sum_type_v_type_name}(\'"), $c.si_s_code, {.d_s = $val}}, + { _SLIT("\')"), 0, {.d_c = 0 }} }))' fn_builder.write_string('\t\tcase $typ.idx(): return $res;\n') } else { @@ -446,8 +446,8 @@ fn (mut g Gen) gen_str_for_union_sum_type(info ast.SumType, styp string, str_fn_ } val += ')' res := 'str_intp(2, _MOV((StrIntpData[]){ - {_SLIT("${clean_sum_type_v_type_name}("), $c.si_s_code, {.d_s = $val}}, - {_SLIT(")"), 0, {.d_c = 0 }} + { _SLIT("${clean_sum_type_v_type_name}("), $c.si_s_code, {.d_s = $val}}, + { _SLIT(")"), 0, {.d_c = 0 }} }))' fn_builder.write_string('\t\tcase $typ.idx(): return $res;\n') } @@ -573,12 +573,12 @@ fn (mut g Gen) gen_str_for_array(info ast.Array, styp string, str_fn_name string } } else if sym.kind == .rune { // Rune are managed at this level as strings - g.auto_str_funcs.writeln('\t\tstring x = str_intp(2, _MOV((StrIntpData[]){{_SLIT("\`"), $c.si_s_code, {.d_s = ${elem_str_fn_name}(it) }}, {_SLIT("\`"), 0, {.d_c = 0 }}}));\n') + g.auto_str_funcs.writeln('\t\tstring x = str_intp(2, _MOV((StrIntpData[]){{ _SLIT("\`"), $c.si_s_code, {.d_s = ${elem_str_fn_name}(it) }}, { _SLIT("\`"), 0, {.d_c = 0 }}}));\n') } else if sym.kind == .string { if is_elem_ptr { - g.auto_str_funcs.writeln('\t\tstring x = str_intp(2, _MOV((StrIntpData[]){{_SLIT("&\'"), $c.si_s_code, {.d_s = *it }}, {_SLIT("\'"), 0, {.d_c = 0 }}}));\n') + g.auto_str_funcs.writeln('\t\tstring x = str_intp(2, _MOV((StrIntpData[]){{ _SLIT("&\'"), $c.si_s_code, {.d_s = *it }}, { _SLIT("\'"), 0, {.d_c = 0 }}}));\n') } else { - g.auto_str_funcs.writeln('\t\tstring x = str_intp(2, _MOV((StrIntpData[]){{_SLIT("\'"), $c.si_s_code, {.d_s = it }}, {_SLIT("\'"), 0, {.d_c = 0 }}}));\n') + g.auto_str_funcs.writeln('\t\tstring x = str_intp(2, _MOV((StrIntpData[]){{ _SLIT("\'"), $c.si_s_code, {.d_s = it }}, { _SLIT("\'"), 0, {.d_c = 0 }}}));\n') } } else { // There is a custom .str() method, so use it. @@ -854,7 +854,7 @@ fn (mut g Gen) gen_str_for_struct(info ast.Struct, styp string, str_fn_name stri } } fn_body.writeln('\tstring res = str_intp( ${(info.fields.len - field_skips.len) * 4 + 3}, _MOV((StrIntpData[]){') - fn_body.writeln('\t\t{_SLIT("$clean_struct_v_type_name{\\n"), 0, {.d_c=0}},') + fn_body.writeln('\t\t{ _SLIT("$clean_struct_v_type_name{\\n"), 0, {.d_c=0}},') mut is_first := true for i, field in info.fields { // Skip `str:skip` fields @@ -886,10 +886,10 @@ fn (mut g Gen) gen_str_for_struct(info ast.Struct, styp string, str_fn_name stri if is_first { // first field doesn't need \n - fn_body.write_string('\t\t{_SLIT0, $c.si_s_code, {.d_s=indents}}, {_SLIT(" $field.name: $ptr_amp$prefix"), 0, {.d_c=0}}, ') + fn_body.write_string('\t\t{ _SLIT0, $c.si_s_code, {.d_s=indents}}, { _SLIT(" $field.name: $ptr_amp$prefix"), 0, {.d_c=0}}, ') is_first = false } else { - fn_body.write_string('\t\t{_SLIT("\\n"), $c.si_s_code, {.d_s=indents}}, {_SLIT(" $field.name: $ptr_amp$prefix"), 0, {.d_c=0}}, ') + fn_body.write_string('\t\t{ _SLIT("\\n"), $c.si_s_code, {.d_s=indents}}, { _SLIT(" $field.name: $ptr_amp$prefix"), 0, {.d_c=0}}, ') } // custom methods management @@ -908,10 +908,10 @@ fn (mut g Gen) gen_str_for_struct(info ast.Struct, styp string, str_fn_name stri // with floats we use always the g representation: if sym.kind !in [.f32, .f64] { - fn_body.write_string('{_SLIT("$quote_str"), ${int(base_fmt)}, {.${data_str(base_fmt)}=') + fn_body.write_string('{ _SLIT("$quote_str"), ${int(base_fmt)}, {.${data_str(base_fmt)}=') } else { g_fmt := '0x' + (u32(base_fmt) | u32(0x7F) << 9).hex() - fn_body.write_string('{_SLIT("$quote_str"), $g_fmt, {.${data_str(base_fmt)}=') + fn_body.write_string('{ _SLIT("$quote_str"), $g_fmt, {.${data_str(base_fmt)}=') } mut funcprefix := '' @@ -954,9 +954,9 @@ fn (mut g Gen) gen_str_for_struct(info ast.Struct, styp string, str_fn_name stri } } - fn_body.writeln('}}, {_SLIT("$quote_str"), 0, {.d_c=0}},') + fn_body.writeln('}}, { _SLIT("$quote_str"), 0, {.d_c=0}},') } - fn_body.writeln('\t\t{_SLIT("\\n"), $c.si_s_code, {.d_s=indents}}, {_SLIT("}"), 0, {.d_c=0}},') + fn_body.writeln('\t\t{ _SLIT("\\n"), $c.si_s_code, {.d_s=indents}}, { _SLIT("}"), 0, {.d_c=0}},') fn_body.writeln('\t}));') } @@ -994,18 +994,18 @@ fn struct_auto_str_func(sym &ast.TypeSymbol, _field_type ast.Type, fn_name strin // ptr int can be "nil", so this needs to be casted to a string if sym.kind == .f32 { return 'str_intp(1, _MOV((StrIntpData[]){ - {_SLIT0, $si_g32_code, {.d_f32 = *$method_str }} + { _SLIT0, $si_g32_code, {.d_f32 = *$method_str }} }))', true } else if sym.kind == .f64 { return 'str_intp(1, _MOV((StrIntpData[]){ - {_SLIT0, $si_g64_code, {.d_f64 = *$method_str }} + { _SLIT0, $si_g64_code, {.d_f64 = *$method_str }} }))', true } else if sym.kind == .u64 { fmt_type := StrIntpType.si_u64 - return 'str_intp(1, _MOV((StrIntpData[]){{_SLIT0, ${u32(fmt_type) | 0xfe00}, {.d_u64 = *$method_str }}}))', true + return 'str_intp(1, _MOV((StrIntpData[]){{ _SLIT0, ${u32(fmt_type) | 0xfe00}, {.d_u64 = *$method_str }}}))', true } fmt_type := StrIntpType.si_i32 - return 'str_intp(1, _MOV((StrIntpData[]){{_SLIT0, ${u32(fmt_type) | 0xfe00}, {.d_i32 = *$method_str }}}))', true + return 'str_intp(1, _MOV((StrIntpData[]){{ _SLIT0, ${u32(fmt_type) | 0xfe00}, {.d_i32 = *$method_str }}}))', true } return method_str, false } diff --git a/vlib/v/gen/c/cgen.v b/vlib/v/gen/c/cgen.v index c76fac365..60f64956d 100644 --- a/vlib/v/gen/c/cgen.v +++ b/vlib/v/gen/c/cgen.v @@ -1250,7 +1250,7 @@ fn (mut g Gen) write_chan_pop_optional_fns() { static inline $opt_el_type __Option_${styp}_popval($styp ch) { $opt_el_type _tmp = {0}; if (sync__Channel_try_pop_priv(ch, _tmp.data, false)) { - return ($opt_el_type){ .state = 2, .err = _v_error(_SLIT("channel closed")), .data = {EMPTY_STRUCT_INITIALIZATION} }; + return ($opt_el_type){ .state = 2, .err = _v_error(_SLIT("channel closed")), .data = { EMPTY_STRUCT_INITIALIZATION} }; } return _tmp; }') @@ -1272,8 +1272,7 @@ fn (mut g Gen) write_chan_push_optional_fns() { g.channel_definitions.writeln(' static inline ${c.option_name}_void __Option_${styp}_pushval($styp ch, $el_type e) { if (sync__Channel_try_push_priv(ch, &e, false)) { - return (${c.option_name}_void){ .state = 2, .err = _v_error(_SLIT("channel closed")), .data = {EMPTY_STRUCT_INITIALIZATION} }; - } + return (${c.option_name}_void){ .state = 2, .err = _v_error(_SLIT("channel closed")), .data = { EMPTY_STRUCT_INITIALIZATION} }; } return (${c.option_name}_void){0}; }') } @@ -2289,7 +2288,7 @@ fn (mut g Gen) call_cfn_for_casting_expr(fname string, expr ast.Expr, exp_is_ptr } } if got_styp == 'none' && !g.cur_fn.return_type.has_flag(.optional) { - g.write('(none){EMPTY_STRUCT_INITIALIZATION}') + g.write('(none){ EMPTY_STRUCT_INITIALIZATION}') } else { g.expr(expr) } @@ -4260,7 +4259,7 @@ fn (mut g Gen) gen_result_error(target_type ast.Type, expr ast.Expr) { styp := g.typ(target_type) g.write('($styp){ .is_error=true, .err=') g.expr(expr) - g.write(', .data={EMPTY_STRUCT_INITIALIZATION} }') + g.write(', .data={ EMPTY_STRUCT_INITIALIZATION} }') } // NB: remove this when optional has no errors anymore @@ -4268,7 +4267,7 @@ fn (mut g Gen) gen_optional_error(target_type ast.Type, expr ast.Expr) { styp := g.typ(target_type) g.write('($styp){ .state=2, .err=') g.expr(expr) - g.write(', .data={EMPTY_STRUCT_INITIALIZATION} }') + g.write(', .data={ EMPTY_STRUCT_INITIALIZATION} }') } fn (mut g Gen) return_stmt(node ast.Return) { @@ -5124,13 +5123,13 @@ fn (mut g Gen) write_init_function() { // Note: os.args in this case will be []. g.writeln('__attribute__ ((constructor))') g.writeln('void _vinit_caller() {') - g.writeln('\tstatic bool once = false; if (once) {return;} once = true;') + g.writeln('\tstatic bool once = false; if (once) { return;} once = true;') g.writeln('\t_vinit(0,0);') g.writeln('}') g.writeln('__attribute__ ((destructor))') g.writeln('void _vcleanup_caller() {') - g.writeln('\tstatic bool once = false; if (once) {return;} once = true;') + g.writeln('\tstatic bool once = false; if (once) { return;} once = true;') g.writeln('\t_vcleanup();') g.writeln('}') } @@ -5686,7 +5685,7 @@ fn (mut g Gen) type_default(typ_ ast.Type) string { if field_sym.info is ast.Struct && field_sym.language == .v { if field_sym.info.fields.len == 0 && field_sym.info.embeds.len == 0 { - zero_str = '{EMPTY_STRUCT_INITIALIZATION}' + zero_str = '{ EMPTY_STRUCT_INITIALIZATION}' } } } diff --git a/vlib/v/gen/c/cheaders.v b/vlib/v/gen/c/cheaders.v index 8f77ccc5c..0a6d4970c 100644 --- a/vlib/v/gen/c/cheaders.v +++ b/vlib/v/gen/c/cheaders.v @@ -483,14 +483,14 @@ const c_helper_macros = '//============================== HELPER C MACROS ====== #define _SLEN(s, n) ((string){.str=(byteptr)("" s), .len=n, .is_lit=1}) // take the address of an rvalue -#define ADDR(type, expr) (&((type[]){expr}[0])) +#define ADDR(type, expr) (&((type[]){ expr }[0])) // copy something to the heap -#define HEAP(type, expr) ((type*)memdup((void*)&((type[]){expr}[0]), sizeof(type))) -#define HEAP_noscan(type, expr) ((type*)memdup_noscan((void*)&((type[]){expr}[0]), sizeof(type))) +#define HEAP(type, expr) ((type*)memdup((void*)&((type[]){ expr }[0]), sizeof(type))) +#define HEAP_noscan(type, expr) ((type*)memdup_noscan((void*)&((type[]){ expr }[0]), sizeof(type))) -#define _PUSH_MANY(arr, val, tmp, tmp_typ) {tmp_typ tmp = (val); array_push_many(arr, tmp.data, tmp.len);} -#define _PUSH_MANY_noscan(arr, val, tmp, tmp_typ) {tmp_typ tmp = (val); array_push_many_noscan(arr, tmp.data, tmp.len);} +#define _PUSH_MANY(arr, val, tmp, tmp_typ) { tmp_typ tmp = (val); array_push_many(arr, tmp.data, tmp.len);} +#define _PUSH_MANY_noscan(arr, val, tmp, tmp_typ) { tmp_typ tmp = (val); array_push_many_noscan(arr, tmp.data, tmp.len);} ' const c_headers = c_helper_macros + c_unsigned_comparison_functions + c_common_macros + diff --git a/vlib/v/gen/c/fn.v b/vlib/v/gen/c/fn.v index 1e1ddf6af..ecc1e9e83 100644 --- a/vlib/v/gen/c/fn.v +++ b/vlib/v/gen/c/fn.v @@ -723,7 +723,7 @@ fn (mut g Gen) call_expr(node ast.CallExpr) { $if msvc { // MSVC has no support for the statement expressions used below } $else { - g.write(', ({VUNREACHABLE();})') + g.write(', ({ VUNREACHABLE(); })') } } } diff --git a/vlib/v/gen/c/for.v b/vlib/v/gen/c/for.v index a74595aa4..3e74d8f76 100644 --- a/vlib/v/gen/c/for.v +++ b/vlib/v/gen/c/for.v @@ -290,7 +290,7 @@ fn (mut g Gen) for_in_stmt(node_ ast.ForInStmt) { g.writeln('\t$idx = -1;') g.writeln('\tcontinue;') g.writeln('}') - g.writeln('if (!DenseArray_has_index(&$cond_var${arw_or_pt}key_values, $idx)) {continue;}') + g.writeln('if (!DenseArray_has_index(&$cond_var${arw_or_pt}key_values, $idx)) { continue;}') if node.key_var != '_' { key_styp := g.typ(node.key_type) key := c_name(node.key_var) diff --git a/vlib/v/gen/c/sql.v b/vlib/v/gen/c/sql.v index 97b429825..91d280f1c 100644 --- a/vlib/v/gen/c/sql.v +++ b/vlib/v/gen/c/sql.v @@ -183,7 +183,7 @@ fn (mut g Gen) sql_insert(node ast.SqlStmtLine, expr string, table_name string, for sub in subs { g.sql_stmt_line(sub, expr, or_expr) - g.writeln('array_push(&$last_ids_arr, _MOV((orm__Primitive[]){orm__Connection_name_table[${expr}._typ]._method_last_id(${expr}._object)}));') + g.writeln('array_push(&$last_ids_arr, _MOV((orm__Primitive[]){ orm__Connection_name_table[${expr}._typ]._method_last_id(${expr}._object)}));') } g.write('${result_name}_void $res = orm__Connection_name_table[${expr}._typ]._method_') diff --git a/vlib/v/gen/c/str.v b/vlib/v/gen/c/str.v index e301b2987..327060006 100644 --- a/vlib/v/gen/c/str.v +++ b/vlib/v/gen/c/str.v @@ -102,7 +102,7 @@ fn (mut g Gen) gen_expr_to_string(expr ast.Expr, etype ast.Type) { is_var_mut := expr.is_auto_deref_var() str_fn_name := g.get_str_fn(typ) if is_ptr && !is_var_mut { - g.write('str_intp(1, _MOV((StrIntpData[]){{_SLIT("&"), $si_s_code ,{.d_s = isnil(') + g.write('str_intp(1, _MOV((StrIntpData[]){{ _SLIT("&"), $si_s_code ,{.d_s = isnil(') g.expr(expr) g.write(') ? _SLIT("nil") : ') } diff --git a/vlib/v/gen/c/str_intp.v b/vlib/v/gen/c/str_intp.v index d88eddb94..5e960aa86 100644 --- a/vlib/v/gen/c/str_intp.v +++ b/vlib/v/gen/c/str_intp.v @@ -215,9 +215,9 @@ fn (mut g Gen) string_inter_literal(node ast.StringInterLiteral) { escaped_val := util.smart_quote(val, false) if escaped_val.len > 0 { - g.write('{_SLIT("$escaped_val"), ') + g.write('{ _SLIT("$escaped_val"), ') } else { - g.write('{_SLIT0, ') + g.write('{ _SLIT0, ') } if i >= node.exprs.len { diff --git a/vlib/v/gen/c/struct.v b/vlib/v/gen/c/struct.v index 505183e06..1fcb61d28 100644 --- a/vlib/v/gen/c/struct.v +++ b/vlib/v/gen/c/struct.v @@ -182,7 +182,7 @@ fn (mut g Gen) struct_init(node ast.StructInit) { } field_name := c_name(field.name) if field.typ.has_flag(.optional) || field.typ.has_flag(.result) { - g.write('.$field_name = {EMPTY_STRUCT_INITIALIZATION},') + g.write('.$field_name = { EMPTY_STRUCT_INITIALIZATION },') initialized = true continue } diff --git a/vlib/v/gen/js/auto_str_methods.v b/vlib/v/gen/js/auto_str_methods.v index ef551c96d..3c495a29d 100644 --- a/vlib/v/gen/js/auto_str_methods.v +++ b/vlib/v/gen/js/auto_str_methods.v @@ -812,18 +812,18 @@ fn struct_auto_str_func(mut g JsGen, sym &ast.TypeSymbol, field_type ast.Type, f // ptr int can be "nil", so this needs to be casted to a string if sym.kind == .f32 { return 'str_intp(1, _MOV((StrIntpData[]){ - {_SLIT0, $si_g32_code, {.d_f32 = *$method_str }} + { _SLIT0, $si_g32_code, {.d_f32 = *$method_str }} }))' } else if sym.kind == .f64 { return 'str_intp(1, _MOV((StrIntpData[]){ - {_SLIT0, $si_g64_code, {.d_f64 = *$method_str }} + { _SLIT0, $si_g64_code, {.d_f64 = *$method_str }} }))' } else if sym.kind == .u64 { fmt_type := StrIntpType.si_u64 - return 'str_intp(1, _MOV((StrIntpData[]){{_SLIT0, ${u32(fmt_type) | 0xfe00}, {.d_u64 = *$method_str }}}))' + return 'str_intp(1, _MOV((StrIntpData[]){{ _SLIT0, ${u32(fmt_type) | 0xfe00}, {.d_u64 = *$method_str }}}))' } fmt_type := StrIntpType.si_i32 - return 'str_intp(1, _MOV((StrIntpData[]){{_SLIT0, ${u32(fmt_type) | 0xfe00}, {.d_i32 = *$method_str }}}))' + return 'str_intp(1, _MOV((StrIntpData[]){{ _SLIT0, ${u32(fmt_type) | 0xfe00}, {.d_i32 = *$method_str }}}))' } return method_str } diff --git a/vlib/v/gen/js/fn.v b/vlib/v/gen/js/fn.v index a7346a8e7..b55287435 100644 --- a/vlib/v/gen/js/fn.v +++ b/vlib/v/gen/js/fn.v @@ -683,7 +683,7 @@ fn (mut g JsGen) gen_method_decl(it ast.FnDecl, typ FnGenType) { is_varg := i == args.len - 1 && it.is_variadic arg_name := g.js_name(arg.name) if is_varg { - g.writeln('$arg_name = new array(new array_buffer({arr: $arg_name,len: new int(${arg_name}.length),index_start: new int(0)}));') + g.writeln('$arg_name = new array(new array_buffer({ arr: $arg_name,len: new int(${arg_name}.length),index_start: new int(0)}));') } else { asym := g.table.sym(arg.typ) if asym.kind != .interface_ && asym.language != .js { diff --git a/vlib/v/gen/js/sourcemap/basic_test.v b/vlib/v/gen/js/sourcemap/basic_test.v index fc61b5574..37bdd4ab3 100644 --- a/vlib/v/gen/js/sourcemap/basic_test.v +++ b/vlib/v/gen/js/sourcemap/basic_test.v @@ -3,7 +3,7 @@ module sourcemap fn test_simple() { mut sg := generate_empty_map() mut sm := sg.add_map('hello.js', '/', true, 0, 0) - sm.set_source_content('hello.v', "fn main(){nprintln('Hello World! Helo \$a')\n}") + sm.set_source_content('hello.v', "fn main(){ nprintln('Hello World! Helo \$a')\n}") mlist := [ MappingInput{ @@ -132,7 +132,7 @@ fn test_simple() { json_data := sm.to_json() - expected := '{"version":3,"file":"hello.js","sourceRoot":"\\/","sources":["hello.v"],"sourcesContent":["fn main(){nprintln(\'Hello World! Helo \$a\')\\n}"],"names":["hello_name"],"mappings":"AAAA;AAAA,EAAA,OAAO,CAACA,GAAR,CAAY,aAAZ,CAAA,CAAA;AAAA"}' + expected := '{"version":3,"file":"hello.js","sourceRoot":"\\/","sources":["hello.v"],"sourcesContent":["fn main(){ nprintln(\'Hello World! Helo \$a\')\\n}"],"names":["hello_name"],"mappings":"AAAA;AAAA,EAAA,OAAO,CAACA,GAAR,CAAY,aAAZ,CAAA,CAAA;AAAA"}' assert json_data.str() == expected } diff --git a/vlib/v/scanner/scanner.v b/vlib/v/scanner/scanner.v index 6ca719bd3..c38a38f8b 100644 --- a/vlib/v/scanner/scanner.v +++ b/vlib/v/scanner/scanner.v @@ -802,9 +802,13 @@ fn (mut s Scanner) text_scan() token.Token { return s.new_token(.rsbr, '', 1) } `{` { - // Skip { in `${` in strings if s.is_inside_string { + // Handle new `hello {name}` string interpolation + if !s.text[s.pos + 1].is_space() && s.text[s.pos - 1] != `$` { + return s.new_token(.str_dollar, '', 1) + } if s.text[s.pos - 1] == `$` { + // Skip { in `${` in strings continue } else { s.inter_cbr_count++ @@ -1225,6 +1229,33 @@ fn (mut s Scanner) ident_string() string { s.pos -= 2 break } + // {var} (ignore in vfmt mode) (skip \{) + if c == `{` && util.is_name_char(s.text[s.pos + 1]) && prevc != `$` && !is_raw + && s.count_symbol_before(s.pos - 1, scanner.backslash) % 2 == 0 { + // Detect certain strings with "{" that are not interpolation: + // e.g. "{init: " (no "}" at the end) + mut is_valid_inter := true + for i := s.pos + 1; i < s.text.len; i++ { + if s.text[i] == `}` { + // No } in this string, so it's not a valid `{x}` interpolation + break + } + if s.text[i] in [`=`, `\n`, s.inter_quote] { + // We reached the end of the line or string without reaching "}". + // Also if there's "=", there's no way it's a valid interpolation expression: + // e.g. `println("{a.b = 42}")` + is_valid_inter = false + break + } + } + if is_valid_inter { + s.is_inside_string = true + s.is_enclosed_inter = true + // so that s.pos points to $ at the next step + s.pos -= 1 + break + } + } if c != scanner.backslash { backslash_count = 0 } diff --git a/vlib/v/token/pos.v b/vlib/v/token/pos.v index f9835bb02..0c2175391 100644 --- a/vlib/v/token/pos.v +++ b/vlib/v/token/pos.v @@ -18,7 +18,7 @@ pub fn (mut p Pos) free() { } pub fn (p Pos) line_str() string { - return '{l: ${p.line_nr + 1:5}, c: ${p.col:3}, p: ${p.pos:5}, ll: ${p.last_line + 1:5}}' + return '\{l: ${p.line_nr + 1:5}, c: ${p.col:3}, p: ${p.pos:5}, ll: ${p.last_line + 1:5}}' } pub fn (pos Pos) extend(end Pos) Pos { -- 2.30.2