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 = `_`
b_lf = 10
b_cr = 13
backslash = `\\`
)
pub struct Scanner {
@ -1111,7 +1112,7 @@ fn (mut s Scanner) ident_string() string {
}
s.is_inside_string = false
mut u_escapes_pos := []int{} // pos list of \uXXXX
slash := `\\`
mut backslash_count := if start_char == scanner.backslash { 1 } else { 0 }
for {
s.pos++
if s.pos >= s.text.len {
@ -1120,10 +1121,12 @@ fn (mut s Scanner) ident_string() string {
}
c := s.text[s.pos]
prevc := s.text[s.pos - 1]
if c == scanner.backslash {
backslash_count++
}
// end of string
if c == s.quote
&& (is_raw || prevc != slash || (prevc == slash && s.text[s.pos - 2] == slash)) {
// handle '123\\' slash at the end
if c == s.quote && (is_raw || backslash_count % 2 == 0) {
// handle '123\\' backslash at the end
break
}
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()
}
// 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())
|| 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 {
s.error(r'cannot use `\0` (NULL character) in the string literal')
}
}
// Don't allow \x00
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 {
s.error(r'cannot use `\x00` (NULL character) in the string literal')
}
}
// 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`
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')
@ -1168,7 +1171,8 @@ 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 {
if prevc == `$` && c == `{` && !is_raw
&& s.count_symbol_before(s.pos - 2, scanner.backslash) % 2 == 0 {
s.is_inside_string = true
s.is_enclosed_inter = true
// so that s.pos points to $ at the next step
@ -1177,12 +1181,15 @@ fn (mut s Scanner) ident_string() string {
}
// $var
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_inter_start = true
s.pos -= 2
break
}
if c != scanner.backslash {
backslash_count = 0
}
}
mut lit := ''
mut end := s.pos

View File

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