v.scanner: fix escaped backslash after string interpolation (#11118)

pull/11133/head
Daniel Däschle 2021-08-10 16:04:42 +02:00 committed by GitHub
parent 0ed7b000ec
commit 2ae77c1998
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 22 additions and 10 deletions

View File

@ -19,6 +19,7 @@ const (
num_sep = `_` num_sep = `_`
b_lf = 10 b_lf = 10
b_cr = 13 b_cr = 13
backslash = `\\`
) )
pub struct Scanner { pub struct Scanner {
@ -1111,7 +1112,7 @@ fn (mut s Scanner) ident_string() string {
} }
s.is_inside_string = false s.is_inside_string = false
mut u_escapes_pos := []int{} // pos list of \uXXXX mut u_escapes_pos := []int{} // pos list of \uXXXX
slash := `\\` mut backslash_count := if start_char == scanner.backslash { 1 } else { 0 }
for { for {
s.pos++ s.pos++
if s.pos >= s.text.len { if s.pos >= s.text.len {
@ -1120,10 +1121,12 @@ fn (mut s Scanner) ident_string() string {
} }
c := s.text[s.pos] c := s.text[s.pos]
prevc := s.text[s.pos - 1] prevc := s.text[s.pos - 1]
if c == scanner.backslash {
backslash_count++
}
// end of string // end of string
if c == s.quote if c == s.quote && (is_raw || backslash_count % 2 == 0) {
&& (is_raw || prevc != slash || (prevc == slash && s.text[s.pos - 2] == slash)) { // handle '123\\' backslash at the end
// handle '123\\' slash at the end
break break
} }
if c == s.inter_quote && (s.is_inter_start || s.is_enclosed_inter) { if c == s.inter_quote && (s.is_inter_start || s.is_enclosed_inter) {
@ -1136,22 +1139,22 @@ fn (mut s Scanner) ident_string() string {
s.inc_line_number() s.inc_line_number()
} }
// Don't allow \0 // Don't allow \0
if c == `0` && s.pos > 2 && prevc == slash { if c == `0` && s.pos > 2 && prevc == scanner.backslash {
if (s.pos < s.text.len - 1 && s.text[s.pos + 1].is_digit()) if (s.pos < s.text.len - 1 && s.text[s.pos + 1].is_digit())
|| s.count_symbol_before(s.pos - 1, slash) % 2 == 0 { || s.count_symbol_before(s.pos - 1, scanner.backslash) % 2 == 0 {
} else if !is_cstr && !is_raw { } else if !is_cstr && !is_raw {
s.error(r'cannot use `\0` (NULL character) in the string literal') s.error(r'cannot use `\0` (NULL character) in the string literal')
} }
} }
// Don't allow \x00 // Don't allow \x00
if c == `0` && s.pos > 5 && s.expect('\\x0', s.pos - 3) { if c == `0` && s.pos > 5 && s.expect('\\x0', s.pos - 3) {
if s.count_symbol_before(s.pos - 3, slash) % 2 == 0 { if s.count_symbol_before(s.pos - 3, scanner.backslash) % 2 == 0 {
} else if !is_cstr && !is_raw { } else if !is_cstr && !is_raw {
s.error(r'cannot use `\x00` (NULL character) in the string literal') s.error(r'cannot use `\x00` (NULL character) in the string literal')
} }
} }
// Escape `\x` `\u` // Escape `\x` `\u`
if prevc == slash && !is_raw && !is_cstr && s.count_symbol_before(s.pos - 2, slash) % 2 == 0 { if backslash_count % 2 == 1 && !is_raw && !is_cstr {
// Escape `\x` // Escape `\x`
if c == `x` && (s.text[s.pos + 1] == s.quote || !s.text[s.pos + 1].is_hex_digit()) { if c == `x` && (s.text[s.pos + 1] == s.quote || !s.text[s.pos + 1].is_hex_digit()) {
s.error(r'`\x` used with no following hex digits') s.error(r'`\x` used with no following hex digits')
@ -1168,7 +1171,8 @@ fn (mut s Scanner) ident_string() string {
} }
} }
// ${var} (ignore in vfmt mode) (skip \$) // ${var} (ignore in vfmt mode) (skip \$)
if prevc == `$` && c == `{` && !is_raw && s.count_symbol_before(s.pos - 2, slash) % 2 == 0 { if prevc == `$` && c == `{` && !is_raw
&& s.count_symbol_before(s.pos - 2, scanner.backslash) % 2 == 0 {
s.is_inside_string = true s.is_inside_string = true
s.is_enclosed_inter = true s.is_enclosed_inter = true
// so that s.pos points to $ at the next step // so that s.pos points to $ at the next step
@ -1177,12 +1181,15 @@ fn (mut s Scanner) ident_string() string {
} }
// $var // $var
if prevc == `$` && util.is_name_char(c) && !is_raw if prevc == `$` && util.is_name_char(c) && !is_raw
&& s.count_symbol_before(s.pos - 2, slash) % 2 == 0 { && s.count_symbol_before(s.pos - 2, scanner.backslash) % 2 == 0 {
s.is_inside_string = true s.is_inside_string = true
s.is_inter_start = true s.is_inter_start = true
s.pos -= 2 s.pos -= 2
break break
} }
if c != scanner.backslash {
backslash_count = 0
}
} }
mut lit := '' mut lit := ''
mut end := s.pos mut end := s.pos

View File

@ -0,0 +1,5 @@
fn test_escaped_backslash_after_string_interpolation() {
test := 'test'
a := "\\\"$test\\\""
assert a == '\\"test\\"'
}