diff options
author | Pablo Galindo Salgado <Pablogsal@gmail.com> | 2021-08-12 17:46:35 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-08-12 17:46:35 (GMT) |
commit | 4b86c9c5146c339c689830619be9d29b8f7bf417 (patch) | |
tree | 922ade83b3de3ffa5280687c19a323bff62466bf /Parser | |
parent | f7635f0e542c916bfd62542e7b60ee23ff681d0d (diff) | |
download | cpython-4b86c9c5146c339c689830619be9d29b8f7bf417.zip cpython-4b86c9c5146c339c689830619be9d29b8f7bf417.tar.gz cpython-4b86c9c5146c339c689830619be9d29b8f7bf417.tar.bz2 |
[3.9] bpo-44885: Correct the ast locations of f-strings with format specs and repeated expressions (GH-27729) (GH-27744)
(cherry picked from commit 8e832fb2a2cb54d7262148b6ec15563dffb48d63)
Co-authored-by: Pablo Galindo Salgado <Pablogsal@gmail.com>
Diffstat (limited to 'Parser')
-rw-r--r-- | Parser/pegen/parse_string.c | 70 |
1 files changed, 31 insertions, 39 deletions
diff --git a/Parser/pegen/parse_string.c b/Parser/pegen/parse_string.c index c852e5b..41fdc2d 100644 --- a/Parser/pegen/parse_string.c +++ b/Parser/pegen/parse_string.c @@ -284,49 +284,48 @@ _PyPegen_parsestr(Parser *p, int *bytesmode, int *rawmode, PyObject **result, /* Fix locations for the given node and its children. `parent` is the enclosing node. + `expr_start` is the starting position of the expression (pointing to the open brace). `n` is the node which locations are going to be fixed relative to parent. `expr_str` is the child node's string representation, including braces. */ static bool -fstring_find_expr_location(Token *parent, char *expr_str, int *p_lines, int *p_cols) +fstring_find_expr_location(Token *parent, const char* expr_start, char *expr_str, int *p_lines, int *p_cols) { *p_lines = 0; *p_cols = 0; + assert(expr_start != NULL && *expr_start == '{'); if (parent && parent->bytes) { char *parent_str = PyBytes_AsString(parent->bytes); if (!parent_str) { return false; } - char *substr = strstr(parent_str, expr_str); - if (substr) { - // The following is needed, in order to correctly shift the column - // offset, in the case that (disregarding any whitespace) a newline - // immediately follows the opening curly brace of the fstring expression. - bool newline_after_brace = 1; - char *start = substr + 1; - while (start && *start != '}' && *start != '\n') { - if (*start != ' ' && *start != '\t' && *start != '\f') { - newline_after_brace = 0; - break; - } - start++; + // The following is needed, in order to correctly shift the column + // offset, in the case that (disregarding any whitespace) a newline + // immediately follows the opening curly brace of the fstring expression. + bool newline_after_brace = 1; + const char *start = expr_start + 1; + while (start && *start != '}' && *start != '\n') { + if (*start != ' ' && *start != '\t' && *start != '\f') { + newline_after_brace = 0; + break; } + start++; + } - // Account for the characters from the last newline character to our - // left until the beginning of substr. - if (!newline_after_brace) { - start = substr; - while (start > parent_str && *start != '\n') { - start--; - } - *p_cols += (int)(substr - start); + // Account for the characters from the last newline character to our + // left until the beginning of expr_start. + if (!newline_after_brace) { + start = expr_start; + while (start > parent_str && *start != '\n') { + start--; } - /* adjust the start based on the number of newlines encountered - before the f-string expression */ - for (char* p = parent_str; p < substr; p++) { - if (*p == '\n') { - (*p_lines)++; - } + *p_cols += (int)(expr_start - start); + } + /* adjust the start based on the number of newlines encountered + before the f-string expression */ + for (const char *p = parent_str; p < expr_start; p++) { + if (*p == '\n') { + (*p_lines)++; } } } @@ -370,7 +369,7 @@ fstring_compile_expr(Parser *p, const char *expr_start, const char *expr_end, len = expr_end - expr_start; /* Allocate 3 extra bytes: open paren, close paren, null byte. */ - str = PyMem_Malloc(len + 3); + str = PyMem_Calloc(len + 3, sizeof(char)); if (str == NULL) { PyErr_NoMemory(); return NULL; @@ -378,18 +377,11 @@ fstring_compile_expr(Parser *p, const char *expr_start, const char *expr_end, // The call to fstring_find_expr_location is responsible for finding the column offset // the generated AST nodes need to be shifted to the right, which is equal to the number - // of the f-string characters before the expression starts. In order to correctly compute - // this offset, strstr gets called in fstring_find_expr_location which only succeeds - // if curly braces appear before and after the f-string expression (exactly like they do - // in the f-string itself), hence the following lines. - str[0] = '{'; + // of the f-string characters before the expression starts. memcpy(str+1, expr_start, len); - str[len+1] = '}'; - str[len+2] = 0; - int lines, cols; - if (!fstring_find_expr_location(t, str, &lines, &cols)) { - PyMem_FREE(str); + if (!fstring_find_expr_location(t, expr_start-1, str+1, &lines, &cols)) { + PyMem_Free(str); return NULL; } |