From ff7f7316326a19749c5d79f9e44acdbe7d54ac4e Mon Sep 17 00:00:00 2001 From: Pablo Galindo Salgado Date: Sat, 20 May 2023 14:07:05 +0100 Subject: [PATCH] gh-104658: Fix location of unclosed quote error for multiline f-strings (#104660) --- Lib/test/test_fstring.py | 16 +++++++++++++++- Parser/tokenizer.c | 7 +++++-- Parser/tokenizer.h | 1 + 3 files changed, 21 insertions(+), 3 deletions(-) diff --git a/Lib/test/test_fstring.py b/Lib/test/test_fstring.py index 58e2550715c..fcb12d25ff9 100644 --- a/Lib/test/test_fstring.py +++ b/Lib/test/test_fstring.py @@ -1558,7 +1558,21 @@ x = ( self.assertAllRaise(SyntaxError, "unterminated f-string literal", ['f"', "f'"]) self.assertAllRaise(SyntaxError, "unterminated triple-quoted f-string literal", ['f"""', "f'''"]) - + # Ensure that the errors are reported at the correct line number. + data = '''\ +x = 1 + 1 +y = 2 + 2 +z = f""" +sdfjnsdfjsdf +sdfsdfs{1+ +2} dfigdf {3+ +4}sdufsd"" +''' + try: + compile(data, "?", "exec") + except SyntaxError as e: + self.assertEqual(e.text, 'z = f"""') + self.assertEqual(e.lineno, 3) def test_syntax_error_after_debug(self): self.assertAllRaise(SyntaxError, "f-string: expecting a valid expression after '{'", [ diff --git a/Parser/tokenizer.c b/Parser/tokenizer.c index 91ffabac56c..c5dc9e706fe 100644 --- a/Parser/tokenizer.c +++ b/Parser/tokenizer.c @@ -1124,7 +1124,7 @@ tok_underflow_interactive(struct tok_state *tok) { static int tok_underflow_file(struct tok_state *tok) { - if (tok->start == NULL) { + if (tok->start == NULL && !INSIDE_FSTRING(tok)) { tok->cur = tok->inp = tok->buf; } if (tok->decoding_state == STATE_INIT) { @@ -2250,6 +2250,7 @@ tok_get_normal_mode(struct tok_state *tok, tokenizer_mode* current_tok, struct t the_current_tok->f_string_quote_size = quote_size; the_current_tok->f_string_start = tok->start; the_current_tok->f_string_multi_line_start = tok->line_start; + the_current_tok->f_string_line_start = tok->lineno; the_current_tok->f_string_start_offset = -1; the_current_tok->f_string_multi_line_start_offset = -1; the_current_tok->last_expr_buffer = NULL; @@ -2580,7 +2581,9 @@ f_string_middle: tok->cur++; tok->line_start = current_tok->f_string_multi_line_start; int start = tok->lineno; - tok->lineno = tok->first_lineno; + + tokenizer_mode *the_current_tok = TOK_GET_MODE(tok); + tok->lineno = the_current_tok->f_string_line_start; if (current_tok->f_string_quote_size == 3) { return MAKE_TOKEN(syntaxerror(tok, diff --git a/Parser/tokenizer.h b/Parser/tokenizer.h index 5e2171885ac..fd169cf3d1b 100644 --- a/Parser/tokenizer.h +++ b/Parser/tokenizer.h @@ -53,6 +53,7 @@ typedef struct _tokenizer_mode { int f_string_raw; const char* f_string_start; const char* f_string_multi_line_start; + int f_string_line_start; Py_ssize_t f_string_start_offset; Py_ssize_t f_string_multi_line_start_offset;