Skip to content

Commit 08ff846

Browse files
authored
scanner: fix escape character handling in character/rune literals (fix #20301) (#20304)
1 parent 452666f commit 08ff846

File tree

5 files changed

+36
-6
lines changed

5 files changed

+36
-6
lines changed

vlib/v/scanner/scanner.v

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1537,11 +1537,14 @@ pub fn (mut s Scanner) ident_char() string {
15371537
mut len := 0
15381538

15391539
// set flags for advanced escapes first
1540-
escaped_hex := s.expect('\\x', start + 1)
1541-
escaped_unicode_16 := s.expect('\\u', start + 1)
1542-
escaped_unicode_32 := s.expect('\\U', start + 1)
1540+
escaped_hex := s.expect('\\x', start + 1) && s.text.len > start + 3
1541+
&& s.text[start + 3].is_hex_digit()
1542+
escaped_unicode_16 := s.expect('\\u', start + 1) && s.text.len > start + 3
1543+
&& s.text[start + 3].is_hex_digit()
1544+
escaped_unicode_32 := s.expect('\\U', start + 1) && s.text.len > start + 3
1545+
&& s.text[start + 3].is_hex_digit()
15431546
escaped_octal := !escaped_hex && !escaped_unicode_16 && !escaped_unicode_32
1544-
&& s.expect('\\', start + 1)
1547+
&& s.expect('\\', start + 1) && s.text.len > start + 2 && s.text[start + 2].is_oct_digit()
15451548

15461549
// walk the string to get characters up to the next backtick
15471550
for {
@@ -1599,8 +1602,19 @@ pub fn (mut s Scanner) ident_char() string {
15991602

16001603
u := c.runes()
16011604
if u.len != 1 {
1605+
mut err_info := []string{cap: u.len}
1606+
mut i := 0
1607+
for i < u.len {
1608+
if u[i] != `\\` || i == u.len - 1 {
1609+
err_info << '`${u[i]}`'
1610+
i++
1611+
continue
1612+
}
1613+
err_info << '`\\${u[i + 1]}`'
1614+
i += 2
1615+
}
16021616
if escaped_hex || escaped_unicode_16 || escaped_unicode_32 {
1603-
s.error_with_pos('invalid character literal `${orig}` => `${c}` (${u}) (escape sequence did not refer to a singular rune)',
1617+
s.error_with_pos('invalid character literal `${orig}` => `${c}` ([${err_info.join(', ')}]) (escape sequence did not refer to a singular rune)',
16041618
lspos)
16051619
} else if u.len == 0 {
16061620
s.add_error_detail_with_pos('use quotes for strings, backticks for characters',
@@ -1609,7 +1623,7 @@ pub fn (mut s Scanner) ident_char() string {
16091623
} else {
16101624
s.add_error_detail_with_pos('use quotes for strings, backticks for characters',
16111625
lspos)
1612-
s.error_with_pos('invalid character literal `${orig}` => `${c}` (${u}) (more than one character)',
1626+
s.error_with_pos('invalid character literal `${orig}` => `${c}` ([${err_info.join(', ')}]) (more than one character)',
16131627
lspos)
16141628
}
16151629
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
vlib/v/scanner/tests/invalid_character_literal_err_1.vv:1:6: error: invalid character literal `\n\t` => `\n\t` ([`\n`, `\t`]) (more than one character)
2+
1 | a := `\n\t`
3+
| ^
4+
Details:
5+
vlib/v/scanner/tests/invalid_character_literal_err_1.vv:1:6: details: use quotes for strings, backticks for characters
6+
1 | a := `\n\t`
7+
| ^
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
a := `\n\t`
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
vlib/v/scanner/tests/invalid_character_literal_err_2.vv:1:6: error: invalid character literal `\nb` => `\nb` ([`\n`, `b`]) (more than one character)
2+
1 | a := `\nb`
3+
| ^
4+
Details:
5+
vlib/v/scanner/tests/invalid_character_literal_err_2.vv:1:6: details: use quotes for strings, backticks for characters
6+
1 | a := `\nb`
7+
| ^
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
a := `\nb`

0 commit comments

Comments
 (0)