From 08ff84627cfbcce47d9a053f8ed8cc919053a114 Mon Sep 17 00:00:00 2001 From: shove Date: Fri, 29 Dec 2023 20:25:11 +0800 Subject: [PATCH] scanner: fix escape character handling in character/rune literals (fix #20301) (#20304) --- vlib/v/scanner/scanner.v | 26 ++++++++++++++----- .../tests/invalid_character_literal_err_1.out | 7 +++++ .../tests/invalid_character_literal_err_1.vv | 1 + .../tests/invalid_character_literal_err_2.out | 7 +++++ .../tests/invalid_character_literal_err_2.vv | 1 + 5 files changed, 36 insertions(+), 6 deletions(-) create mode 100644 vlib/v/scanner/tests/invalid_character_literal_err_1.out create mode 100644 vlib/v/scanner/tests/invalid_character_literal_err_1.vv create mode 100644 vlib/v/scanner/tests/invalid_character_literal_err_2.out create mode 100644 vlib/v/scanner/tests/invalid_character_literal_err_2.vv diff --git a/vlib/v/scanner/scanner.v b/vlib/v/scanner/scanner.v index 9402ba73f..e8b97526d 100644 --- a/vlib/v/scanner/scanner.v +++ b/vlib/v/scanner/scanner.v @@ -1537,11 +1537,14 @@ pub fn (mut s Scanner) ident_char() string { mut len := 0 // set flags for advanced escapes first - escaped_hex := s.expect('\\x', start + 1) - escaped_unicode_16 := s.expect('\\u', start + 1) - escaped_unicode_32 := s.expect('\\U', start + 1) + escaped_hex := s.expect('\\x', start + 1) && s.text.len > start + 3 + && s.text[start + 3].is_hex_digit() + escaped_unicode_16 := s.expect('\\u', start + 1) && s.text.len > start + 3 + && s.text[start + 3].is_hex_digit() + escaped_unicode_32 := s.expect('\\U', start + 1) && s.text.len > start + 3 + && s.text[start + 3].is_hex_digit() escaped_octal := !escaped_hex && !escaped_unicode_16 && !escaped_unicode_32 - && s.expect('\\', start + 1) + && s.expect('\\', start + 1) && s.text.len > start + 2 && s.text[start + 2].is_oct_digit() // walk the string to get characters up to the next backtick for { @@ -1599,8 +1602,19 @@ pub fn (mut s Scanner) ident_char() string { u := c.runes() if u.len != 1 { + mut err_info := []string{cap: u.len} + mut i := 0 + for i < u.len { + if u[i] != `\\` || i == u.len - 1 { + err_info << '`${u[i]}`' + i++ + continue + } + err_info << '`\\${u[i + 1]}`' + i += 2 + } if escaped_hex || escaped_unicode_16 || escaped_unicode_32 { - s.error_with_pos('invalid character literal `${orig}` => `${c}` (${u}) (escape sequence did not refer to a singular rune)', + s.error_with_pos('invalid character literal `${orig}` => `${c}` ([${err_info.join(', ')}]) (escape sequence did not refer to a singular rune)', lspos) } else if u.len == 0 { 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 { } else { s.add_error_detail_with_pos('use quotes for strings, backticks for characters', lspos) - s.error_with_pos('invalid character literal `${orig}` => `${c}` (${u}) (more than one character)', + s.error_with_pos('invalid character literal `${orig}` => `${c}` ([${err_info.join(', ')}]) (more than one character)', lspos) } } diff --git a/vlib/v/scanner/tests/invalid_character_literal_err_1.out b/vlib/v/scanner/tests/invalid_character_literal_err_1.out new file mode 100644 index 000000000..5d2fe747b --- /dev/null +++ b/vlib/v/scanner/tests/invalid_character_literal_err_1.out @@ -0,0 +1,7 @@ +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) + 1 | a := `\n\t` + | ^ +Details: +vlib/v/scanner/tests/invalid_character_literal_err_1.vv:1:6: details: use quotes for strings, backticks for characters + 1 | a := `\n\t` + | ^ diff --git a/vlib/v/scanner/tests/invalid_character_literal_err_1.vv b/vlib/v/scanner/tests/invalid_character_literal_err_1.vv new file mode 100644 index 000000000..28f6b6aa4 --- /dev/null +++ b/vlib/v/scanner/tests/invalid_character_literal_err_1.vv @@ -0,0 +1 @@ +a := `\n\t` diff --git a/vlib/v/scanner/tests/invalid_character_literal_err_2.out b/vlib/v/scanner/tests/invalid_character_literal_err_2.out new file mode 100644 index 000000000..c89fda852 --- /dev/null +++ b/vlib/v/scanner/tests/invalid_character_literal_err_2.out @@ -0,0 +1,7 @@ +vlib/v/scanner/tests/invalid_character_literal_err_2.vv:1:6: error: invalid character literal `\nb` => `\nb` ([`\n`, `b`]) (more than one character) + 1 | a := `\nb` + | ^ +Details: +vlib/v/scanner/tests/invalid_character_literal_err_2.vv:1:6: details: use quotes for strings, backticks for characters + 1 | a := `\nb` + | ^ diff --git a/vlib/v/scanner/tests/invalid_character_literal_err_2.vv b/vlib/v/scanner/tests/invalid_character_literal_err_2.vv new file mode 100644 index 000000000..56abba72b --- /dev/null +++ b/vlib/v/scanner/tests/invalid_character_literal_err_2.vv @@ -0,0 +1 @@ +a := `\nb` -- 2.39.5