@@ -279,49 +279,48 @@ _PyPegen_parsestr(Parser *p, int *bytesmode, int *rawmode, PyObject **result,
279
279
/* Fix locations for the given node and its children.
280
280
281
281
`parent` is the enclosing node.
282
+ `expr_start` is the starting position of the expression (pointing to the open brace).
282
283
`n` is the node which locations are going to be fixed relative to parent.
283
284
`expr_str` is the child node's string representation, including braces.
284
285
*/
285
286
static bool
286
- fstring_find_expr_location (Token * parent , char * expr_str , int * p_lines , int * p_cols )
287
+ fstring_find_expr_location (Token * parent , const char * expr_start , char * expr_str , int * p_lines , int * p_cols )
287
288
{
288
289
* p_lines = 0 ;
289
290
* p_cols = 0 ;
291
+ assert (expr_start != NULL && * expr_start == '{' );
290
292
if (parent && parent -> bytes ) {
291
293
const char * parent_str = PyBytes_AsString (parent -> bytes );
292
294
if (!parent_str ) {
293
295
return false;
294
296
}
295
- const char * substr = strstr (parent_str , expr_str );
296
- if (substr ) {
297
- // The following is needed, in order to correctly shift the column
298
- // offset, in the case that (disregarding any whitespace) a newline
299
- // immediately follows the opening curly brace of the fstring expression.
300
- bool newline_after_brace = 1 ;
301
- const char * start = substr + 1 ;
302
- while (start && * start != '}' && * start != '\n' ) {
303
- if (* start != ' ' && * start != '\t' && * start != '\f' ) {
304
- newline_after_brace = 0 ;
305
- break ;
306
- }
307
- start ++ ;
297
+ // The following is needed, in order to correctly shift the column
298
+ // offset, in the case that (disregarding any whitespace) a newline
299
+ // immediately follows the opening curly brace of the fstring expression.
300
+ bool newline_after_brace = 1 ;
301
+ const char * start = expr_start + 1 ;
302
+ while (start && * start != '}' && * start != '\n' ) {
303
+ if (* start != ' ' && * start != '\t' && * start != '\f' ) {
304
+ newline_after_brace = 0 ;
305
+ break ;
308
306
}
307
+ start ++ ;
308
+ }
309
309
310
- // Account for the characters from the last newline character to our
311
- // left until the beginning of substr.
312
- if (!newline_after_brace ) {
313
- start = substr ;
314
- while (start > parent_str && * start != '\n' ) {
315
- start -- ;
316
- }
317
- * p_cols += (int )(substr - start );
310
+ // Account for the characters from the last newline character to our
311
+ // left until the beginning of expr_start.
312
+ if (!newline_after_brace ) {
313
+ start = expr_start ;
314
+ while (start > parent_str && * start != '\n' ) {
315
+ start -- ;
318
316
}
319
- /* adjust the start based on the number of newlines encountered
320
- before the f-string expression */
321
- for (const char * p = parent_str ; p < substr ; p ++ ) {
322
- if (* p == '\n' ) {
323
- (* p_lines )++ ;
324
- }
317
+ * p_cols += (int )(expr_start - start );
318
+ }
319
+ /* adjust the start based on the number of newlines encountered
320
+ before the f-string expression */
321
+ for (const char * p = parent_str ; p < expr_start ; p ++ ) {
322
+ if (* p == '\n' ) {
323
+ (* p_lines )++ ;
325
324
}
326
325
}
327
326
}
@@ -365,25 +364,18 @@ fstring_compile_expr(Parser *p, const char *expr_start, const char *expr_end,
365
364
366
365
len = expr_end - expr_start ;
367
366
/* Allocate 3 extra bytes: open paren, close paren, null byte. */
368
- str = PyMem_Malloc (len + 3 );
367
+ str = PyMem_Calloc (len + 3 , sizeof ( char ) );
369
368
if (str == NULL ) {
370
369
PyErr_NoMemory ();
371
370
return NULL ;
372
371
}
373
372
374
373
// The call to fstring_find_expr_location is responsible for finding the column offset
375
374
// the generated AST nodes need to be shifted to the right, which is equal to the number
376
- // of the f-string characters before the expression starts. In order to correctly compute
377
- // this offset, strstr gets called in fstring_find_expr_location which only succeeds
378
- // if curly braces appear before and after the f-string expression (exactly like they do
379
- // in the f-string itself), hence the following lines.
380
- str [0 ] = '{' ;
375
+ // of the f-string characters before the expression starts.
381
376
memcpy (str + 1 , expr_start , len );
382
- str [len + 1 ] = '}' ;
383
- str [len + 2 ] = 0 ;
384
-
385
377
int lines , cols ;
386
- if (!fstring_find_expr_location (t , str , & lines , & cols )) {
378
+ if (!fstring_find_expr_location (t , expr_start - 1 , str + 1 , & lines , & cols )) {
387
379
PyMem_Free (str );
388
380
return NULL ;
389
381
}
0 commit comments