diff --git a/cmd/tools/vtest-cleancode.v b/cmd/tools/vtest-cleancode.v index fb4f1c4772..a0e4e0ffbc 100644 --- a/cmd/tools/vtest-cleancode.v +++ b/cmd/tools/vtest-cleancode.v @@ -47,6 +47,7 @@ const verify_known_failing_exceptions = [ 'vlib/builtin/int_test.v' /* special number formatting that should be tested */, // TODOs and unfixed vfmt bugs 'vlib/v/gen/js/tests/js.v', /* local `hello` fn, gets replaced with module `hello` aliased as `hl` */ + 'vlib/v/tests/inout/string_interpolation_inner_expr_cbr.vv', /* for new string interpolation, prevent resolving to nested interpolation */ 'vlib/v/tests/string_new_interpolation_test.v', /* new string interpolation */ ] diff --git a/vlib/v/scanner/scanner.v b/vlib/v/scanner/scanner.v index 966186bc01..e5acbbeb83 100644 --- a/vlib/v/scanner/scanner.v +++ b/vlib/v/scanner/scanner.v @@ -37,6 +37,7 @@ pub mut: is_inter_start bool // for hacky string interpolation TODO simplify is_inter_end bool is_enclosed_inter bool + is_inside_interpolation bool // avoid nesting interpolation line_comment string last_lt int = -1 // position of latest < is_started bool @@ -677,6 +678,7 @@ fn (mut s Scanner) text_scan() token.Token { s.is_inter_end = true s.is_inter_start = false s.is_inside_string = false + s.is_inside_interpolation = false } } // end of `$expr` @@ -692,6 +694,7 @@ fn (mut s Scanner) text_scan() token.Token { } else if s.is_inter_start && next_char != `.` { s.is_inter_end = true s.is_inter_start = false + s.is_inside_interpolation = false } return s.new_token(.name, name, name.len) } else if c.is_digit() || (c == `.` && nextc.is_digit()) { @@ -720,6 +723,7 @@ fn (mut s Scanner) text_scan() token.Token { s.is_inter_start = false if next_char == s.quote { s.is_inside_string = false + s.is_inside_interpolation = false } return s.new_token(.rpar, '', 1) } @@ -806,10 +810,12 @@ fn (mut s Scanner) text_scan() token.Token { prev_char := s.text[s.pos - 1] next_char := s.text[s.pos + 1] // Handle new `hello {name}` string interpolation - if !next_char.is_space() && next_char != `}` && prev_char !in [`$`, `{`] { + if !s.is_inside_interpolation && !next_char.is_space() && next_char != `}` + && prev_char !in [`$`, `{`] { + s.is_inside_interpolation = true return s.new_token(.str_dollar, '', 1) } - if prev_char == `$` { + if s.is_inside_interpolation && prev_char == `$` { // Skip { in `${` in strings continue } else { @@ -820,6 +826,7 @@ fn (mut s Scanner) text_scan() token.Token { } `$` { if s.is_inside_string { + s.is_inside_interpolation = true return s.new_token(.str_dollar, '', 1) } else { return s.new_token(.dollar, '', 1) @@ -837,9 +844,11 @@ fn (mut s Scanner) text_scan() token.Token { if s.text[s.pos] == s.quote { s.is_inside_string = false s.is_enclosed_inter = false + s.is_inside_interpolation = false return s.new_token(.string, '', 1) } s.is_enclosed_inter = false + s.is_inside_interpolation = false ident_string := s.ident_string() return s.new_token(.string, ident_string, ident_string.len + 2) // + two quotes } else { @@ -1219,6 +1228,7 @@ fn (mut s Scanner) ident_string() string { && s.count_symbol_before(s.pos - 2, scanner.backslash) % 2 == 0 { s.is_inside_string = true s.is_enclosed_inter = true + s.is_inside_interpolation = true // so that s.pos points to $ at the next step s.pos -= 2 break @@ -1228,6 +1238,7 @@ fn (mut s Scanner) ident_string() string { && s.count_symbol_before(s.pos - 2, scanner.backslash) % 2 == 0 { s.is_inside_string = true s.is_inter_start = true + s.is_inside_interpolation = true s.pos -= 2 break } diff --git a/vlib/v/tests/inout/string_interpolation_inner_expr_cbr.out b/vlib/v/tests/inout/string_interpolation_inner_expr_cbr.out new file mode 100644 index 0000000000..41f0b6d769 --- /dev/null +++ b/vlib/v/tests/inout/string_interpolation_inner_expr_cbr.out @@ -0,0 +1,2 @@ +Foo = def +Foo = def diff --git a/vlib/v/tests/inout/string_interpolation_inner_expr_cbr.vv b/vlib/v/tests/inout/string_interpolation_inner_expr_cbr.vv new file mode 100644 index 0000000000..0cab1b2273 --- /dev/null +++ b/vlib/v/tests/inout/string_interpolation_inner_expr_cbr.vv @@ -0,0 +1,9 @@ +enum Foo { + abc + def +} + +fn main() { + println('Foo = {Foo.def}') + println('Foo = {unsafe{Foo(1)}}') +}