@@ -16,15 +16,19 @@ _PyLexer_set_ftstring_expr(struct tok_state* tok, struct token *token, char c) {
1616 if (!(tok_mode -> in_debug || tok_mode -> string_kind == TSTRING ) || token -> metadata ) {
1717 return 0 ;
1818 }
19+ const char * expression = tok_mode -> last_expr_start ;
20+ assert (expression != NULL );
21+ assert (expression <= tok -> start );
22+ Py_ssize_t expression_size = tok -> start - expression ;
1923 PyObject * res = NULL ;
2024
2125 // Look for a # character outside of string literals
2226 int hash_detected = 0 ;
2327 int in_string = 0 ;
2428 char quote_char = 0 ;
2529
26- for (Py_ssize_t i = 0 ; i < tok_mode -> last_expr_size - tok_mode -> last_expr_end ; i ++ ) {
27- char ch = tok_mode -> last_expr_buffer [i ];
30+ for (Py_ssize_t i = 0 ; i < expression_size ; i ++ ) {
31+ char ch = expression [i ];
2832
2933 // Skip escaped characters
3034 if (ch == '\\' ) {
@@ -60,7 +64,8 @@ _PyLexer_set_ftstring_expr(struct tok_state* tok, struct token *token, char c) {
6064 // If we found a # character in the expression, we need to handle comments
6165 if (hash_detected ) {
6266 // Allocate buffer for processed result
63- char * result = (char * )PyMem_Malloc ((tok_mode -> last_expr_size - tok_mode -> last_expr_end + 1 ) * sizeof (char ));
67+ char * result = (char * )PyMem_Malloc (
68+ (expression_size + 1 ) * sizeof (char ));
6469 if (!result ) {
6570 return -1 ;
6671 }
@@ -71,8 +76,8 @@ _PyLexer_set_ftstring_expr(struct tok_state* tok, struct token *token, char c) {
7176 quote_char = 0 ; // Current string quote char
7277
7378 // Process each character
74- while (i < tok_mode -> last_expr_size - tok_mode -> last_expr_end ) {
75- char ch = tok_mode -> last_expr_buffer [i ];
79+ while (i < expression_size ) {
80+ char ch = expression [i ];
7681
7782 // Handle string quotes
7883 if (ch == '"' || ch == '\'' ) {
@@ -87,11 +92,10 @@ _PyLexer_set_ftstring_expr(struct tok_state* tok, struct token *token, char c) {
8792 }
8893 // Skip comments
8994 else if (ch == '#' && !in_string ) {
90- while (i < tok_mode -> last_expr_size - tok_mode -> last_expr_end &&
91- tok_mode -> last_expr_buffer [i ] != '\n' ) {
95+ while (i < expression_size && expression [i ] != '\n' ) {
9296 i ++ ;
9397 }
94- if (i < tok_mode -> last_expr_size - tok_mode -> last_expr_end ) {
98+ if (i < expression_size ) {
9599 result [j ++ ] = '\n' ;
96100 }
97101 }
@@ -106,11 +110,7 @@ _PyLexer_set_ftstring_expr(struct tok_state* tok, struct token *token, char c) {
106110 res = PyUnicode_DecodeUTF8 (result , j , NULL );
107111 PyMem_Free (result );
108112 } else {
109- res = PyUnicode_DecodeUTF8 (
110- tok_mode -> last_expr_buffer ,
111- tok_mode -> last_expr_size - tok_mode -> last_expr_end ,
112- NULL
113- );
113+ res = PyUnicode_DecodeUTF8 (expression , expression_size , NULL );
114114 }
115115
116116 if (!res ) {
@@ -120,61 +120,6 @@ _PyLexer_set_ftstring_expr(struct tok_state* tok, struct token *token, char c) {
120120 return 0 ;
121121}
122122
123- int
124- _PyLexer_update_ftstring_expr (struct tok_state * tok , char cur )
125- {
126- assert (tok -> cur != NULL );
127-
128- Py_ssize_t size = strlen (tok -> cur );
129- tokenizer_mode * tok_mode = TOK_GET_MODE (tok );
130-
131- switch (cur ) {
132- case 0 :
133- if (!tok_mode -> last_expr_buffer || tok_mode -> last_expr_end >= 0 ) {
134- return 1 ;
135- }
136- char * new_buffer = PyMem_Realloc (
137- tok_mode -> last_expr_buffer ,
138- tok_mode -> last_expr_size + size
139- );
140- if (new_buffer == NULL ) {
141- PyMem_Free (tok_mode -> last_expr_buffer );
142- goto error ;
143- }
144- tok_mode -> last_expr_buffer = new_buffer ;
145- strncpy (tok_mode -> last_expr_buffer + tok_mode -> last_expr_size , tok -> cur , size );
146- tok_mode -> last_expr_size += size ;
147- break ;
148- case '{' :
149- if (tok_mode -> last_expr_buffer != NULL ) {
150- PyMem_Free (tok_mode -> last_expr_buffer );
151- }
152- tok_mode -> last_expr_buffer = PyMem_Malloc (size );
153- if (tok_mode -> last_expr_buffer == NULL ) {
154- goto error ;
155- }
156- tok_mode -> last_expr_size = size ;
157- tok_mode -> last_expr_end = -1 ;
158- strncpy (tok_mode -> last_expr_buffer , tok -> cur , size );
159- break ;
160- case '}' :
161- case '!' :
162- tok_mode -> last_expr_end = strlen (tok -> start );
163- break ;
164- case ':' :
165- if (tok_mode -> last_expr_end == -1 ) {
166- tok_mode -> last_expr_end = strlen (tok -> start );
167- }
168- break ;
169- default :
170- Py_UNREACHABLE ();
171- }
172- return 1 ;
173- error :
174- tok -> done = E_NOMEM ;
175- return 0 ;
176- }
177-
178123int
179124_PyLexer_check_string_prefixes (struct tok_state * tok ,
180125 int saw_b , int saw_r , int saw_u ,
@@ -268,9 +213,8 @@ _PyLexer_scan_fstring_start(struct tok_state *tok, struct token *token, int c)
268213 the_current_tok -> first_line = tok -> lineno ;
269214 the_current_tok -> start_offset = -1 ;
270215 the_current_tok -> multi_line_start_offset = -1 ;
271- the_current_tok -> last_expr_buffer = NULL ;
272- the_current_tok -> last_expr_size = 0 ;
273- the_current_tok -> last_expr_end = -1 ;
216+ the_current_tok -> last_expr_start = NULL ;
217+ the_current_tok -> last_expr_start_offset = -1 ;
274218 the_current_tok -> in_format_spec = 0 ;
275219 the_current_tok -> in_debug = 0 ;
276220
@@ -436,6 +380,9 @@ _PyLexer_get_fstring_mode(struct tok_state *tok, tokenizer_mode* current_tok, st
436380 if (start_char == '{' ) {
437381 int peek1 = tok_nextc (tok );
438382 tok_backup (tok , peek1 );
383+ if (peek1 != '{' ) {
384+ current_tok -> last_expr_start = tok -> cur ;
385+ }
439386 tok_backup (tok , start_char );
440387 if (peek1 != '{' ) {
441388 current_tok -> curly_bracket_expr_start_depth ++ ;
@@ -460,13 +407,6 @@ _PyLexer_get_fstring_mode(struct tok_state *tok, tokenizer_mode* current_tok, st
460407 }
461408 }
462409
463- if (current_tok -> last_expr_buffer != NULL ) {
464- PyMem_Free (current_tok -> last_expr_buffer );
465- current_tok -> last_expr_buffer = NULL ;
466- current_tok -> last_expr_size = 0 ;
467- current_tok -> last_expr_end = -1 ;
468- }
469-
470410 p_start = tok -> start ;
471411 p_end = tok -> cur ;
472412 tok -> tok_mode_stack_index -- ;
@@ -551,12 +491,10 @@ _PyLexer_get_fstring_mode(struct tok_state *tok, tokenizer_mode* current_tok, st
551491 }
552492
553493 if (c == '{' ) {
554- if (!_PyLexer_update_ftstring_expr (tok , c )) {
555- return MAKE_TOKEN (ENDMARKER );
556- }
557494 int peek = tok_nextc (tok );
558495 if (peek != '{' || in_format_spec ) {
559496 tok_backup (tok , peek );
497+ current_tok -> last_expr_start = tok -> cur ;
560498 tok_backup (tok , c );
561499 current_tok -> curly_bracket_expr_start_depth ++ ;
562500 if (current_tok -> curly_bracket_expr_start_depth >= MAX_EXPR_NESTING ) {
@@ -580,10 +518,10 @@ _PyLexer_get_fstring_mode(struct tok_state *tok, tokenizer_mode* current_tok, st
580518 }
581519 int peek = tok_nextc (tok );
582520
583- // The tokenizer can only be in the format spec if we have already completed the expression
584- // scanning (indicated by the end of the expression being set) and we are not at the top level
585- // of the bracket stack (-1 is the top level). Since format specifiers can't legally use double
586- // brackets, we can bypass it here.
521+ // The tokenizer can only be in the format spec if expression
522+ // scanning is complete and we are not at the top level of the
523+ // bracket stack (-1 is the top level). Since format specifiers
524+ // can't legally use double brackets, we can bypass it here.
587525 int cursor = current_tok -> curly_bracket_depth ;
588526 if (peek == '}' && !in_format_spec && cursor == 0 ) {
589527 p_start = tok -> start ;
0 commit comments