From 5fa1e403ecab64248067805066f3f3df8144c42c Mon Sep 17 00:00:00 2001 From: yuyi Date: Thu, 10 Dec 2020 02:58:27 +0800 Subject: [PATCH] scanner: fix interpolation with string args (#7214) --- vlib/v/scanner/scanner.v | 25 ++++++++++++++----- .../string_interpolation_string_args_test.v | 9 +++++++ 2 files changed, 28 insertions(+), 6 deletions(-) create mode 100644 vlib/v/tests/string_interpolation_string_args_test.v diff --git a/vlib/v/scanner/scanner.v b/vlib/v/scanner/scanner.v index f348e3ed4a..0316d417e3 100644 --- a/vlib/v/scanner/scanner.v +++ b/vlib/v/scanner/scanner.v @@ -26,6 +26,7 @@ pub mut: is_inside_string bool is_inter_start bool // for hacky string interpolation TODO simplify is_inter_end bool + is_enclosed_inter bool is_debug bool line_comment string // prev_tok TokenKind @@ -34,6 +35,7 @@ pub mut: is_print_colored_error bool is_print_rel_paths_on_error bool quote byte // which quote is used to denote current string: ' or " + inter_quote byte line_ends []int // the positions of source lines ends (i.e. \n signs) nr_lines int // total number of lines in the source file that were scanned is_vh bool // Keep newlines @@ -716,12 +718,14 @@ fn (mut s Scanner) text_scan() token.Token { `}` { // s = `hello $name !` // s = `hello ${name} !` - if s.is_inside_string { + if s.is_enclosed_inter { s.pos++ if s.text[s.pos] == s.quote { s.is_inside_string = false + s.is_enclosed_inter = false return s.new_token(.string, '', 1) } + s.is_enclosed_inter = false ident_string := s.ident_string() return s.new_token(.string, ident_string, ident_string.len + 2) // + two quotes } else { @@ -993,8 +997,12 @@ fn (mut s Scanner) ident_string() string { is_quote := q == single_quote || q == double_quote is_raw := is_quote && s.pos > 0 && s.text[s.pos - 1] == `r` is_cstr := is_quote && s.pos > 0 && s.text[s.pos - 1] == `c` - if is_quote && !s.is_inside_string { - s.quote = q + if is_quote { + if s.is_inside_string { + s.inter_quote = q + } else { + s.quote = q + } } // if s.file_path.contains('string_test') { // println('\nident_string() at char=${s.text[s.pos].str()}') @@ -1002,6 +1010,10 @@ fn (mut s Scanner) ident_string() string { // } mut n_cr_chars := 0 mut start := s.pos + if s.text[start] == s.quote || + (s.text[start] == s.inter_quote && (s.is_inter_start || s.is_enclosed_inter)) { + start++ + } s.is_inside_string = false slash := `\\` for { @@ -1016,6 +1028,9 @@ fn (mut s Scanner) ident_string() string { // handle '123\\' slash at the end break } + if c == s.inter_quote && (s.is_inter_start || s.is_enclosed_inter) { + break + } if c == `\r` { n_cr_chars++ } @@ -1054,6 +1069,7 @@ fn (mut s Scanner) ident_string() string { // ${var} (ignore in vfmt mode) (skip \$) if prevc == `$` && c == `{` && !is_raw && s.count_symbol_before(s.pos - 2, slash) % 2 == 0 { s.is_inside_string = true + s.is_enclosed_inter = true // so that s.pos points to $ at the next step s.pos -= 2 break @@ -1068,9 +1084,6 @@ fn (mut s Scanner) ident_string() string { } } mut lit := '' - if s.text[start] == s.quote { - start++ - } mut end := s.pos if s.is_inside_string { end++ diff --git a/vlib/v/tests/string_interpolation_string_args_test.v b/vlib/v/tests/string_interpolation_string_args_test.v new file mode 100644 index 0000000000..267d91be41 --- /dev/null +++ b/vlib/v/tests/string_interpolation_string_args_test.v @@ -0,0 +1,9 @@ +fn show_info(a string) string { + return a +} + +fn test_interpolation_string_args() { + assert '${show_info("abc")}' == 'abc' + assert '${show_info("bac")}' == 'bac' + assert '${"aaa"}' == 'aaa' +}