diff options
Diffstat (limited to 'Python/ast.c')
-rw-r--r-- | Python/ast.c | 90 |
1 files changed, 46 insertions, 44 deletions
diff --git a/Python/ast.c b/Python/ast.c index 6259827..7ffdf4a 100644 --- a/Python/ast.c +++ b/Python/ast.c @@ -5006,10 +5006,16 @@ fstring_parse(const char **str, const char *end, int raw, int recurse_lvl, closing brace doesn't match an opening paren, for example. It doesn't need to error on all invalid expressions, just correctly find the end of all valid ones. Any errors inside the expression - will be caught when we parse it later. */ + will be caught when we parse it later. + + *expression is set to the expression. For an '=' "debug" expression, + *expr_text is set to the debug text (the original text of the expression, + *including the '=' and any whitespace around it, as a string object). If + *not a debug expression, *expr_text set to NULL. */ static int fstring_find_expr(const char **str, const char *end, int raw, int recurse_lvl, - expr_ty *expression, struct compiling *c, const node *n) + PyObject **expr_text, expr_ty *expression, + struct compiling *c, const node *n) { /* Return -1 on error, else 0. */ @@ -5020,9 +5026,6 @@ fstring_find_expr(const char **str, const char *end, int raw, int recurse_lvl, int conversion = -1; /* The conversion char. Use default if not specified, or !r if using = and no format spec. */ - int equal_flag = 0; /* Are we using the = feature? */ - PyObject *expr_text = NULL; /* The text of the expression, used for =. */ - const char *expr_text_end; /* 0 if we're not in a string, else the quote char we're trying to match (single or double quote). */ @@ -5198,7 +5201,6 @@ fstring_find_expr(const char **str, const char *end, int raw, int recurse_lvl, expr_text. */ if (**str == '=') { *str += 1; - equal_flag = 1; /* Skip over ASCII whitespace. No need to test for end of string here, since we know there's at least a trailing quote somewhere @@ -5206,7 +5208,14 @@ fstring_find_expr(const char **str, const char *end, int raw, int recurse_lvl, while (Py_ISSPACE(**str)) { *str += 1; } - expr_text_end = *str; + + /* Set *expr_text to the text of the expression. */ + *expr_text = PyUnicode_FromStringAndSize(expr_start, *str-expr_start); + if (!*expr_text) { + goto error; + } + } else { + *expr_text = NULL; } /* Check for a conversion char, if present. */ @@ -5227,17 +5236,6 @@ fstring_find_expr(const char **str, const char *end, int raw, int recurse_lvl, } } - if (equal_flag) { - Py_ssize_t len = expr_text_end - expr_start; - expr_text = PyUnicode_FromStringAndSize(expr_start, len); - if (!expr_text) { - goto error; - } - if (PyArena_AddPyObject(c->c_arena, expr_text) < 0) { - Py_DECREF(expr_text); - goto error; - } - } /* Check for the format spec, if present. */ if (*str >= end) @@ -5261,16 +5259,16 @@ fstring_find_expr(const char **str, const char *end, int raw, int recurse_lvl, assert(**str == '}'); *str += 1; - /* If we're in = mode, and have no format spec and no explict conversion, - set the conversion to 'r'. */ - if (equal_flag && format_spec == NULL && conversion == -1) { + /* If we're in = mode (detected by non-NULL expr_text), and have no format + spec and no explict conversion, set the conversion to 'r'. */ + if (*expr_text && format_spec == NULL && conversion == -1) { conversion = 'r'; } /* And now create the FormattedValue node that represents this entire expression with the conversion and format spec. */ *expression = FormattedValue(simple_expression, conversion, - format_spec, expr_text, LINENO(n), + format_spec, LINENO(n), n->n_col_offset, n->n_end_lineno, n->n_end_col_offset, c->c_arena); if (!*expression) @@ -5313,7 +5311,7 @@ error: static int fstring_find_literal_and_expr(const char **str, const char *end, int raw, int recurse_lvl, PyObject **literal, - expr_ty *expression, + PyObject **expr_text, expr_ty *expression, struct compiling *c, const node *n) { int result; @@ -5341,7 +5339,8 @@ fstring_find_literal_and_expr(const char **str, const char *end, int raw, /* We must now be the start of an expression, on a '{'. */ assert(**str == '{'); - if (fstring_find_expr(str, end, raw, recurse_lvl, expression, c, n) < 0) + if (fstring_find_expr(str, end, raw, recurse_lvl, expr_text, + expression, c, n) < 0) goto error; return 0; @@ -5604,7 +5603,7 @@ FstringParser_ConcatFstring(FstringParser *state, const char **str, /* Parse the f-string. */ while (1) { - PyObject *literal = NULL; + PyObject *literal[2] = {NULL, NULL}; expr_ty expression = NULL; /* If there's a zero length literal in front of the @@ -5612,31 +5611,34 @@ FstringParser_ConcatFstring(FstringParser *state, const char **str, the f-string, expression will be NULL (unless result == 1, see below). */ int result = fstring_find_literal_and_expr(str, end, raw, recurse_lvl, - &literal, &expression, - c, n); + &literal[0], &literal[1], + &expression, c, n); if (result < 0) return -1; - /* Add the literal, if any. */ - if (!literal) { - /* Do nothing. Just leave last_str alone (and possibly - NULL). */ - } else if (!state->last_str) { - /* Note that the literal can be zero length, if the - input string is "\\\n" or "\\\r", among others. */ - state->last_str = literal; - literal = NULL; - } else { - /* We have a literal, concatenate it. */ - assert(PyUnicode_GET_LENGTH(literal) != 0); - if (FstringParser_ConcatAndDel(state, literal) < 0) - return -1; - literal = NULL; + /* Add the literals, if any. */ + for (int i = 0; i < 2; i++) { + if (!literal[i]) { + /* Do nothing. Just leave last_str alone (and possibly + NULL). */ + } else if (!state->last_str) { + /* Note that the literal can be zero length, if the + input string is "\\\n" or "\\\r", among others. */ + state->last_str = literal[i]; + literal[i] = NULL; + } else { + /* We have a literal, concatenate it. */ + assert(PyUnicode_GET_LENGTH(literal[i]) != 0); + if (FstringParser_ConcatAndDel(state, literal[i]) < 0) + return -1; + literal[i] = NULL; + } } - /* We've dealt with the literal now. It can't be leaked on further + /* We've dealt with the literals now. They can't be leaked on further errors. */ - assert(literal == NULL); + assert(literal[0] == NULL); + assert(literal[1] == NULL); /* See if we should just loop around to get the next literal and expression, while ignoring the expression this |