@@ -284,49 +284,48 @@ _PyPegen_parsestr(Parser *p, int *bytesmode, int *rawmode, PyObject **result,
284284/* Fix locations for the given node and its children.
285285
286286 `parent` is the enclosing node.
287+ `expr_start` is the starting position of the expression (pointing to the open brace).
287288 `n` is the node which locations are going to be fixed relative to parent.
288289 `expr_str` is the child node's string representation, including braces.
289290*/
290291static bool
291- fstring_find_expr_location (Token * parent , char * expr_str , int * p_lines , int * p_cols )
292+ fstring_find_expr_location (Token * parent , const char * expr_start , char * expr_str , int * p_lines , int * p_cols )
292293{
293294 * p_lines = 0 ;
294295 * p_cols = 0 ;
296+ assert (expr_start != NULL && * expr_start == '{' );
295297 if (parent && parent -> bytes ) {
296298 char * parent_str = PyBytes_AsString (parent -> bytes );
297299 if (!parent_str ) {
298300 return false;
299301 }
300- char * substr = strstr (parent_str , expr_str );
301- if (substr ) {
302- // The following is needed, in order to correctly shift the column
303- // offset, in the case that (disregarding any whitespace) a newline
304- // immediately follows the opening curly brace of the fstring expression.
305- bool newline_after_brace = 1 ;
306- char * start = substr + 1 ;
307- while (start && * start != '}' && * start != '\n' ) {
308- if (* start != ' ' && * start != '\t' && * start != '\f' ) {
309- newline_after_brace = 0 ;
310- break ;
311- }
312- start ++ ;
302+ // The following is needed, in order to correctly shift the column
303+ // offset, in the case that (disregarding any whitespace) a newline
304+ // immediately follows the opening curly brace of the fstring expression.
305+ bool newline_after_brace = 1 ;
306+ const char * start = expr_start + 1 ;
307+ while (start && * start != '}' && * start != '\n' ) {
308+ if (* start != ' ' && * start != '\t' && * start != '\f' ) {
309+ newline_after_brace = 0 ;
310+ break ;
313311 }
312+ start ++ ;
313+ }
314314
315- // Account for the characters from the last newline character to our
316- // left until the beginning of substr.
317- if (!newline_after_brace ) {
318- start = substr ;
319- while (start > parent_str && * start != '\n' ) {
320- start -- ;
321- }
322- * p_cols += (int )(substr - start );
315+ // Account for the characters from the last newline character to our
316+ // left until the beginning of expr_start.
317+ if (!newline_after_brace ) {
318+ start = expr_start ;
319+ while (start > parent_str && * start != '\n' ) {
320+ start -- ;
323321 }
324- /* adjust the start based on the number of newlines encountered
325- before the f-string expression */
326- for (char * p = parent_str ; p < substr ; p ++ ) {
327- if (* p == '\n' ) {
328- (* p_lines )++ ;
329- }
322+ * p_cols += (int )(expr_start - start );
323+ }
324+ /* adjust the start based on the number of newlines encountered
325+ before the f-string expression */
326+ for (const char * p = parent_str ; p < expr_start ; p ++ ) {
327+ if (* p == '\n' ) {
328+ (* p_lines )++ ;
330329 }
331330 }
332331 }
@@ -370,26 +369,19 @@ fstring_compile_expr(Parser *p, const char *expr_start, const char *expr_end,
370369
371370 len = expr_end - expr_start ;
372371 /* Allocate 3 extra bytes: open paren, close paren, null byte. */
373- str = PyMem_Malloc (len + 3 );
372+ str = PyMem_Calloc (len + 3 , sizeof ( char ) );
374373 if (str == NULL ) {
375374 PyErr_NoMemory ();
376375 return NULL ;
377376 }
378377
379378 // The call to fstring_find_expr_location is responsible for finding the column offset
380379 // the generated AST nodes need to be shifted to the right, which is equal to the number
381- // of the f-string characters before the expression starts. In order to correctly compute
382- // this offset, strstr gets called in fstring_find_expr_location which only succeeds
383- // if curly braces appear before and after the f-string expression (exactly like they do
384- // in the f-string itself), hence the following lines.
385- str [0 ] = '{' ;
380+ // of the f-string characters before the expression starts.
386381 memcpy (str + 1 , expr_start , len );
387- str [len + 1 ] = '}' ;
388- str [len + 2 ] = 0 ;
389-
390382 int lines , cols ;
391- if (!fstring_find_expr_location (t , str , & lines , & cols )) {
392- PyMem_FREE (str );
383+ if (!fstring_find_expr_location (t , expr_start - 1 , str + 1 , & lines , & cols )) {
384+ PyMem_Free (str );
393385 return NULL ;
394386 }
395387
0 commit comments