mirror of
https://github.com/astral-sh/ruff.git
synced 2025-09-26 11:59:35 +00:00
Consume the escaped Windows newline (\r\n
) for FStringMiddle
(#7722)
## Summary This PR fixes a bug where if a Windows newline (`\r\n`) character was escaped, then only the `\r` was consumed and not `\n` leading to an unterminated string error. ## Test Plan Add new test cases to check the newline escapes. fixes: #7632
This commit is contained in:
parent
e72d617f4b
commit
e91ffe3e93
4 changed files with 101 additions and 2 deletions
|
@ -584,7 +584,7 @@ impl<'source> Lexer<'source> {
|
||||||
location: self.offset(),
|
location: self.offset(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
'\n' if !fstring.is_triple_quoted() => {
|
'\n' | '\r' if !fstring.is_triple_quoted() => {
|
||||||
return Err(LexicalError {
|
return Err(LexicalError {
|
||||||
error: LexicalErrorType::FStringError(FStringErrorType::UnterminatedString),
|
error: LexicalErrorType::FStringError(FStringErrorType::UnterminatedString),
|
||||||
location: self.offset(),
|
location: self.offset(),
|
||||||
|
@ -603,8 +603,12 @@ impl<'source> Lexer<'source> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Consume the escaped character.
|
// Consume the escaped character.
|
||||||
|
if self.cursor.eat_char('\r') {
|
||||||
|
self.cursor.eat_char('\n');
|
||||||
|
} else {
|
||||||
self.cursor.bump();
|
self.cursor.bump();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
quote @ ('\'' | '"') if quote == fstring.quote_char() => {
|
quote @ ('\'' | '"') if quote == fstring.quote_char() => {
|
||||||
if let Some(triple_quotes) = fstring.triple_quotes() {
|
if let Some(triple_quotes) = fstring.triple_quotes() {
|
||||||
if self.cursor.rest().starts_with(triple_quotes) {
|
if self.cursor.rest().starts_with(triple_quotes) {
|
||||||
|
@ -1983,6 +1987,26 @@ def f(arg=%timeit a = b):
|
||||||
assert_debug_snapshot!(lex_source(source));
|
assert_debug_snapshot!(lex_source(source));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn fstring_single_quote_escape_eol(eol: &str) -> Vec<Spanned> {
|
||||||
|
let source = format!(r"f'text \{eol} more text'");
|
||||||
|
lex_source(&source)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_fstring_single_quote_escape_unix_eol() {
|
||||||
|
assert_debug_snapshot!(fstring_single_quote_escape_eol(UNIX_EOL));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_fstring_single_quote_escape_mac_eol() {
|
||||||
|
assert_debug_snapshot!(fstring_single_quote_escape_eol(MAC_EOL));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_fstring_single_quote_escape_windows_eol() {
|
||||||
|
assert_debug_snapshot!(fstring_single_quote_escape_eol(WINDOWS_EOL));
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_fstring_escape() {
|
fn test_fstring_escape() {
|
||||||
let source = r#"f"\{x:\"\{x}} \"\"\
|
let source = r#"f"\{x:\"\{x}} \"\"\
|
||||||
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
---
|
||||||
|
source: crates/ruff_python_parser/src/lexer.rs
|
||||||
|
expression: fstring_single_quote_escape_eol(MAC_EOL)
|
||||||
|
---
|
||||||
|
[
|
||||||
|
(
|
||||||
|
FStringStart,
|
||||||
|
0..2,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
FStringMiddle {
|
||||||
|
value: "text \\\r more text",
|
||||||
|
is_raw: false,
|
||||||
|
},
|
||||||
|
2..19,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
FStringEnd,
|
||||||
|
19..20,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
Newline,
|
||||||
|
20..20,
|
||||||
|
),
|
||||||
|
]
|
|
@ -0,0 +1,25 @@
|
||||||
|
---
|
||||||
|
source: crates/ruff_python_parser/src/lexer.rs
|
||||||
|
expression: fstring_single_quote_escape_eol(UNIX_EOL)
|
||||||
|
---
|
||||||
|
[
|
||||||
|
(
|
||||||
|
FStringStart,
|
||||||
|
0..2,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
FStringMiddle {
|
||||||
|
value: "text \\\n more text",
|
||||||
|
is_raw: false,
|
||||||
|
},
|
||||||
|
2..19,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
FStringEnd,
|
||||||
|
19..20,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
Newline,
|
||||||
|
20..20,
|
||||||
|
),
|
||||||
|
]
|
|
@ -0,0 +1,25 @@
|
||||||
|
---
|
||||||
|
source: crates/ruff_python_parser/src/lexer.rs
|
||||||
|
expression: fstring_single_quote_escape_eol(WINDOWS_EOL)
|
||||||
|
---
|
||||||
|
[
|
||||||
|
(
|
||||||
|
FStringStart,
|
||||||
|
0..2,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
FStringMiddle {
|
||||||
|
value: "text \\\r\n more text",
|
||||||
|
is_raw: false,
|
||||||
|
},
|
||||||
|
2..20,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
FStringEnd,
|
||||||
|
20..21,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
Newline,
|
||||||
|
21..21,
|
||||||
|
),
|
||||||
|
]
|
Loading…
Add table
Add a link
Reference in a new issue