v.scanner: fix escaped backslash after string interpolation (#11118)
parent
0ed7b000ec
commit
2ae77c1998
|
@ -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
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
fn test_escaped_backslash_after_string_interpolation() {
|
||||||
|
test := 'test'
|
||||||
|
a := "\\\"$test\\\""
|
||||||
|
assert a == '\\"test\\"'
|
||||||
|
}
|
Loading…
Reference in New Issue