LCOV - code coverage report
Current view: top level - Parser - string_parser.c (source / functions) Hit Total Coverage
Test: CPython 3.12 LCOV report [commit acb105a7c1f] Lines: 464 514 90.3 %
Date: 2022-07-20 13:12:14 Functions: 21 21 100.0 %
Branches: 405 460 88.0 %

           Branch data     Line data    Source code
       1                 :            : #include <stdbool.h>
       2                 :            : 
       3                 :            : #include <Python.h>
       4                 :            : 
       5                 :            : #include "tokenizer.h"
       6                 :            : #include "pegen.h"
       7                 :            : #include "string_parser.h"
       8                 :            : 
       9                 :            : //// STRING HANDLING FUNCTIONS ////
      10                 :            : 
      11                 :            : static int
      12                 :        732 : warn_invalid_escape_sequence(Parser *p, const char *first_invalid_escape, Token *t)
      13                 :            : {
      14                 :        732 :     unsigned char c = *first_invalid_escape;
      15   [ +  +  +  + ]:        732 :     int octal = ('4' <= c && c <= '7');
      16                 :        732 :     PyObject *msg =
      17                 :            :         octal
      18                 :        516 :         ? PyUnicode_FromFormat("invalid octal escape sequence '\\%.3s'",
      19                 :            :                                first_invalid_escape)
      20         [ +  + ]:        732 :         : PyUnicode_FromFormat("invalid escape sequence '\\%c'", c);
      21         [ -  + ]:        732 :     if (msg == NULL) {
      22                 :          0 :         return -1;
      23                 :            :     }
      24         [ +  + ]:        732 :     if (PyErr_WarnExplicitObject(PyExc_DeprecationWarning, msg, p->tok->filename,
      25                 :            :                                  t->lineno, NULL, NULL) < 0) {
      26         [ +  - ]:          5 :         if (PyErr_ExceptionMatches(PyExc_DeprecationWarning)) {
      27                 :            :             /* Replace the DeprecationWarning exception with a SyntaxError
      28                 :            :                to get a more accurate error report */
      29                 :          5 :             PyErr_Clear();
      30                 :            : 
      31                 :            :             /* This is needed, in order for the SyntaxError to point to the token t,
      32                 :            :                since _PyPegen_raise_error uses p->tokens[p->fill - 1] for the
      33                 :            :                error location, if p->known_err_token is not set. */
      34                 :          5 :             p->known_err_token = t;
      35         [ +  + ]:          5 :             if (octal) {
      36                 :          2 :                 RAISE_SYNTAX_ERROR("invalid octal escape sequence '\\%.3s'",
      37                 :            :                                    first_invalid_escape);
      38                 :            :             }
      39                 :            :             else {
      40                 :          3 :                 RAISE_SYNTAX_ERROR("invalid escape sequence '\\%c'", c);
      41                 :            :             }
      42                 :            :         }
      43                 :          5 :         Py_DECREF(msg);
      44                 :          5 :         return -1;
      45                 :            :     }
      46                 :        727 :     Py_DECREF(msg);
      47                 :        727 :     return 0;
      48                 :            : }
      49                 :            : 
      50                 :            : static PyObject *
      51                 :      22168 : decode_utf8(const char **sPtr, const char *end)
      52                 :            : {
      53                 :            :     const char *s;
      54                 :            :     const char *t;
      55                 :      22168 :     t = s = *sPtr;
      56   [ +  +  +  + ]:     152655 :     while (s < end && (*s & 0x80)) {
      57                 :     130487 :         s++;
      58                 :            :     }
      59                 :      22168 :     *sPtr = s;
      60                 :      22168 :     return PyUnicode_DecodeUTF8(t, s - t, NULL);
      61                 :            : }
      62                 :            : 
      63                 :            : static PyObject *
      64                 :     239777 : decode_unicode_with_escapes(Parser *parser, const char *s, size_t len, Token *t)
      65                 :            : {
      66                 :            :     PyObject *v;
      67                 :            :     PyObject *u;
      68                 :            :     char *buf;
      69                 :            :     char *p;
      70                 :            :     const char *end;
      71                 :            : 
      72                 :            :     /* check for integer overflow */
      73         [ -  + ]:     239777 :     if (len > SIZE_MAX / 6) {
      74                 :          0 :         return NULL;
      75                 :            :     }
      76                 :            :     /* "ä" (2 bytes) may become "\U000000E4" (10 bytes), or 1:5
      77                 :            :        "\ä" (3 bytes) may become "\u005c\U000000E4" (16 bytes), or ~1:6 */
      78                 :     239777 :     u = PyBytes_FromStringAndSize((char *)NULL, len * 6);
      79         [ -  + ]:     239777 :     if (u == NULL) {
      80                 :          0 :         return NULL;
      81                 :            :     }
      82                 :     239777 :     p = buf = PyBytes_AsString(u);
      83         [ -  + ]:     239777 :     if (p == NULL) {
      84                 :          0 :         return NULL;
      85                 :            :     }
      86                 :     239777 :     end = s + len;
      87         [ +  + ]:    4364519 :     while (s < end) {
      88         [ +  + ]:    4124743 :         if (*s == '\\') {
      89                 :     228116 :             *p++ = *s++;
      90   [ +  +  +  + ]:     228116 :             if (s >= end || *s & 0x80) {
      91                 :          5 :                 strcpy(p, "u005c");
      92                 :          5 :                 p += 5;
      93         [ +  + ]:          5 :                 if (s >= end) {
      94                 :          1 :                     break;
      95                 :            :                 }
      96                 :            :             }
      97                 :            :         }
      98         [ +  + ]:    4124742 :         if (*s & 0x80) {
      99                 :            :             PyObject *w;
     100                 :            :             int kind;
     101                 :            :             const void *data;
     102                 :            :             Py_ssize_t w_len;
     103                 :            :             Py_ssize_t i;
     104                 :      22168 :             w = decode_utf8(&s, end);
     105         [ -  + ]:      22168 :             if (w == NULL) {
     106                 :          0 :                 Py_DECREF(u);
     107                 :          0 :                 return NULL;
     108                 :            :             }
     109                 :      22168 :             kind = PyUnicode_KIND(w);
     110                 :      22168 :             data = PyUnicode_DATA(w);
     111                 :      22168 :             w_len = PyUnicode_GET_LENGTH(w);
     112         [ +  + ]:      60555 :             for (i = 0; i < w_len; i++) {
     113                 :      38387 :                 Py_UCS4 chr = PyUnicode_READ(kind, data, i);
     114                 :      38387 :                 sprintf(p, "\\U%08x", chr);
     115                 :      38387 :                 p += 10;
     116                 :            :             }
     117                 :            :             /* Should be impossible to overflow */
     118                 :            :             assert(p - buf <= PyBytes_GET_SIZE(u));
     119                 :      22168 :             Py_DECREF(w);
     120                 :            :         }
     121                 :            :         else {
     122                 :    4102574 :             *p++ = *s++;
     123                 :            :         }
     124                 :            :     }
     125                 :     239777 :     len = p - buf;
     126                 :     239777 :     s = buf;
     127                 :            : 
     128                 :            :     const char *first_invalid_escape;
     129                 :     239777 :     v = _PyUnicode_DecodeUnicodeEscapeInternal(s, len, NULL, NULL, &first_invalid_escape);
     130                 :            : 
     131   [ +  +  +  + ]:     239777 :     if (v != NULL && first_invalid_escape != NULL) {
     132         [ +  + ]:        365 :         if (warn_invalid_escape_sequence(parser, first_invalid_escape, t) < 0) {
     133                 :            :             /* We have not decref u before because first_invalid_escape points
     134                 :            :                inside u. */
     135                 :          3 :             Py_XDECREF(u);
     136                 :          3 :             Py_DECREF(v);
     137                 :          3 :             return NULL;
     138                 :            :         }
     139                 :            :     }
     140                 :     239774 :     Py_XDECREF(u);
     141                 :     239774 :     return v;
     142                 :            : }
     143                 :            : 
     144                 :            : static PyObject *
     145                 :      19133 : decode_bytes_with_escapes(Parser *p, const char *s, Py_ssize_t len, Token *t)
     146                 :            : {
     147                 :            :     const char *first_invalid_escape;
     148                 :      19133 :     PyObject *result = _PyBytes_DecodeEscape(s, len, NULL, &first_invalid_escape);
     149         [ +  + ]:      19133 :     if (result == NULL) {
     150                 :          2 :         return NULL;
     151                 :            :     }
     152                 :            : 
     153         [ +  + ]:      19131 :     if (first_invalid_escape != NULL) {
     154         [ +  + ]:        366 :         if (warn_invalid_escape_sequence(p, first_invalid_escape, t) < 0) {
     155                 :          2 :             Py_DECREF(result);
     156                 :          2 :             return NULL;
     157                 :            :         }
     158                 :            :     }
     159                 :      19129 :     return result;
     160                 :            : }
     161                 :            : 
     162                 :            : /* s must include the bracketing quote characters, and r, b, u,
     163                 :            :    &/or f prefixes (if any), and embedded escape sequences (if any).
     164                 :            :    _PyPegen_parsestr parses it, and sets *result to decoded Python string object.
     165                 :            :    If the string is an f-string, set *fstr and *fstrlen to the unparsed
     166                 :            :    string object.  Return 0 if no errors occurred.  */
     167                 :            : int
     168                 :    1685857 : _PyPegen_parsestr(Parser *p, int *bytesmode, int *rawmode, PyObject **result,
     169                 :            :                   const char **fstr, Py_ssize_t *fstrlen, Token *t)
     170                 :            : {
     171                 :    1685857 :     const char *s = PyBytes_AsString(t->bytes);
     172         [ -  + ]:    1685857 :     if (s == NULL) {
     173                 :          0 :         return -1;
     174                 :            :     }
     175                 :            : 
     176                 :            :     size_t len;
     177                 :    1685857 :     int quote = Py_CHARMASK(*s);
     178                 :    1685857 :     int fmode = 0;
     179                 :    1685857 :     *bytesmode = 0;
     180                 :    1685857 :     *rawmode = 0;
     181                 :    1685857 :     *result = NULL;
     182                 :    1685857 :     *fstr = NULL;
     183         [ +  + ]:    1685857 :     if (Py_ISALPHA(quote)) {
     184   [ +  +  +  + ]:     182029 :         while (!*bytesmode || !*rawmode) {
     185   [ +  +  -  + ]:     181268 :             if (quote == 'b' || quote == 'B') {
     186                 :      52115 :                 quote =(unsigned char)*++s;
     187                 :      52115 :                 *bytesmode = 1;
     188                 :            :             }
     189   [ +  +  +  + ]:     129153 :             else if (quote == 'u' || quote == 'U') {
     190                 :        909 :                 quote = (unsigned char)*++s;
     191                 :            :             }
     192   [ +  +  +  + ]:     128244 :             else if (quote == 'r' || quote == 'R') {
     193                 :      16198 :                 quote = (unsigned char)*++s;
     194                 :      16198 :                 *rawmode = 1;
     195                 :            :             }
     196   [ +  +  -  + ]:     112046 :             else if (quote == 'f' || quote == 'F') {
     197                 :      22227 :                 quote = (unsigned char)*++s;
     198                 :      22227 :                 fmode = 1;
     199                 :            :             }
     200                 :            :             else {
     201                 :            :                 break;
     202                 :            :             }
     203                 :            :         }
     204                 :            :     }
     205                 :            : 
     206                 :            :     /* fstrings are only allowed in Python 3.6 and greater */
     207   [ +  +  +  + ]:    1685857 :     if (fmode && p->feature_version < 6) {
     208                 :          2 :         p->error_indicator = 1;
     209                 :          2 :         RAISE_SYNTAX_ERROR("Format strings are only supported in Python 3.6 and greater");
     210                 :          2 :         return -1;
     211                 :            :     }
     212                 :            : 
     213   [ +  +  -  + ]:    1685855 :     if (fmode && *bytesmode) {
     214                 :          0 :         PyErr_BadInternalCall();
     215                 :          0 :         return -1;
     216                 :            :     }
     217   [ +  +  -  + ]:    1685855 :     if (quote != '\'' && quote != '\"') {
     218                 :          0 :         PyErr_BadInternalCall();
     219                 :          0 :         return -1;
     220                 :            :     }
     221                 :            :     /* Skip the leading quote char. */
     222                 :    1685855 :     s++;
     223                 :    1685855 :     len = strlen(s);
     224         [ -  + ]:    1685855 :     if (len > INT_MAX) {
     225                 :          0 :         PyErr_SetString(PyExc_OverflowError, "string to parse is too long");
     226                 :          0 :         return -1;
     227                 :            :     }
     228         [ -  + ]:    1685855 :     if (s[--len] != quote) {
     229                 :            :         /* Last quote char must match the first. */
     230                 :          0 :         PyErr_BadInternalCall();
     231                 :          0 :         return -1;
     232                 :            :     }
     233   [ +  +  +  +  :    1685855 :     if (len >= 4 && s[0] == quote && s[1] == quote) {
                   +  - ]
     234                 :            :         /* A triple quoted string. We've already skipped one quote at
     235                 :            :            the start and one at the end of the string. Now skip the
     236                 :            :            two at the start. */
     237                 :     120518 :         s += 2;
     238                 :     120518 :         len -= 2;
     239                 :            :         /* And check that the last two match. */
     240   [ +  -  -  + ]:     120518 :         if (s[--len] != quote || s[--len] != quote) {
     241                 :          0 :             PyErr_BadInternalCall();
     242                 :          0 :             return -1;
     243                 :            :         }
     244                 :            :     }
     245                 :            : 
     246         [ +  + ]:    1685855 :     if (fmode) {
     247                 :            :         /* Just return the bytes. The caller will parse the resulting
     248                 :            :            string. */
     249                 :      22225 :         *fstr = s;
     250                 :      22225 :         *fstrlen = len;
     251                 :      22225 :         return 0;
     252                 :            :     }
     253                 :            : 
     254                 :            :     /* Not an f-string. */
     255                 :            :     /* Avoid invoking escape decoding routines if possible. */
     256   [ +  +  +  + ]:    1663630 :     *rawmode = *rawmode || strchr(s, '\\') == NULL;
     257         [ +  + ]:    1663630 :     if (*bytesmode) {
     258                 :            :         /* Disallow non-ASCII characters. */
     259                 :            :         const char *ch;
     260         [ +  + ]:     738050 :         for (ch = s; *ch; ch++) {
     261         [ +  + ]:     686073 :             if (Py_CHARMASK(*ch) >= 0x80) {
     262                 :        138 :                 RAISE_SYNTAX_ERROR(
     263                 :            :                                    "bytes can only contain ASCII "
     264                 :            :                                    "literal characters");
     265                 :        138 :                 return -1;
     266                 :            :             }
     267                 :            :         }
     268         [ +  + ]:      51977 :         if (*rawmode) {
     269                 :      32844 :             *result = PyBytes_FromStringAndSize(s, len);
     270                 :            :         }
     271                 :            :         else {
     272                 :      19133 :             *result = decode_bytes_with_escapes(p, s, len, t);
     273                 :            :         }
     274                 :            :     }
     275                 :            :     else {
     276         [ +  + ]:    1611515 :         if (*rawmode) {
     277                 :    1472738 :             *result = PyUnicode_DecodeUTF8Stateful(s, len, NULL, NULL);
     278                 :            :         }
     279                 :            :         else {
     280                 :     138777 :             *result = decode_unicode_with_escapes(p, s, len, t);
     281                 :            :         }
     282                 :            :     }
     283         [ +  + ]:    1663492 :     return *result == NULL ? -1 : 0;
     284                 :            : }
     285                 :            : 
     286                 :            : 
     287                 :            : 
     288                 :            : // FSTRING STUFF
     289                 :            : 
     290                 :            : /* Fix locations for the given node and its children.
     291                 :            : 
     292                 :            :    `parent` is the enclosing node.
     293                 :            :    `expr_start` is the starting position of the expression (pointing to the open brace).
     294                 :            :    `n` is the node which locations are going to be fixed relative to parent.
     295                 :            :    `expr_str` is the child node's string representation, including braces.
     296                 :            : */
     297                 :            : static bool
     298                 :      96068 : fstring_find_expr_location(Token *parent, const char* expr_start, char *expr_str, int *p_lines, int *p_cols)
     299                 :            : {
     300                 :      96068 :     *p_lines = 0;
     301                 :      96068 :     *p_cols = 0;
     302                 :            :     assert(expr_start != NULL && *expr_start == '{');
     303   [ +  -  +  - ]:      96068 :     if (parent && parent->bytes) {
     304                 :      96068 :         const char *parent_str = PyBytes_AsString(parent->bytes);
     305         [ -  + ]:      96068 :         if (!parent_str) {
     306                 :          0 :             return false;
     307                 :            :         }
     308                 :            :         // The following is needed, in order to correctly shift the column
     309                 :            :         // offset, in the case that (disregarding any whitespace) a newline
     310                 :            :         // immediately follows the opening curly brace of the fstring expression.
     311                 :      96068 :         bool newline_after_brace = 1;
     312                 :      96068 :         const char *start = expr_start + 1;
     313   [ +  -  +  -  :      96110 :         while (start && *start != '}' && *start != '\n') {
                   +  + ]
     314   [ +  +  +  -  :      96103 :             if (*start != ' ' && *start != '\t' && *start != '\f') {
                   +  - ]
     315                 :      96061 :                 newline_after_brace = 0;
     316                 :      96061 :                 break;
     317                 :            :             }
     318                 :         42 :             start++;
     319                 :            :         }
     320                 :            : 
     321                 :            :         // Account for the characters from the last newline character to our
     322                 :            :         // left until the beginning of expr_start.
     323         [ +  + ]:      96068 :         if (!newline_after_brace) {
     324                 :      96061 :             start = expr_start;
     325   [ +  +  +  + ]:   36137786 :             while (start > parent_str && *start != '\n') {
     326                 :   36041725 :                 start--;
     327                 :            :             }
     328                 :      96061 :             *p_cols += (int)(expr_start - start);
     329         [ +  + ]:      96061 :             if (*start == '\n') {
     330                 :        489 :                 *p_cols -= 1;
     331                 :            :             }
     332                 :            :         }
     333                 :            :         /* adjust the start based on the number of newlines encountered
     334                 :            :            before the f-string expression */
     335         [ +  + ]:   36263462 :         for (const char *p = parent_str; p < expr_start; p++) {
     336         [ +  + ]:   36167394 :             if (*p == '\n') {
     337                 :       4707 :                 (*p_lines)++;
     338                 :            :             }
     339                 :            :         }
     340                 :            :     }
     341                 :      96068 :     return true;
     342                 :            : }
     343                 :            : 
     344                 :            : 
     345                 :            : /* Compile this expression in to an expr_ty.  Add parens around the
     346                 :            :    expression, in order to allow leading spaces in the expression. */
     347                 :            : static expr_ty
     348                 :      96097 : fstring_compile_expr(Parser *p, const char *expr_start, const char *expr_end,
     349                 :            :                      Token *t)
     350                 :            : {
     351                 :      96097 :     expr_ty expr = NULL;
     352                 :            :     char *str;
     353                 :            :     Py_ssize_t len;
     354                 :            :     const char *s;
     355                 :      96097 :     expr_ty result = NULL;
     356                 :            : 
     357                 :            :     assert(expr_end >= expr_start);
     358                 :            :     assert(*(expr_start-1) == '{');
     359                 :            :     assert(*expr_end == '}' || *expr_end == '!' || *expr_end == ':' ||
     360                 :            :            *expr_end == '=');
     361                 :            : 
     362                 :            :     /* If the substring is all whitespace, it's an error.  We need to catch this
     363                 :            :        here, and not when we call PyParser_SimpleParseStringFlagsFilename,
     364                 :            :        because turning the expression '' in to '()' would go from being invalid
     365                 :            :        to valid. */
     366         [ +  + ]:      96219 :     for (s = expr_start; s != expr_end; s++) {
     367                 :      96190 :         char c = *s;
     368                 :            :         /* The Python parser ignores only the following whitespace
     369                 :            :            characters (\r already is converted to \n). */
     370   [ +  +  +  +  :      96190 :         if (!(c == ' ' || c == '\t' || c == '\n' || c == '\f')) {
             +  +  +  + ]
     371                 :      96068 :             break;
     372                 :            :         }
     373                 :            :     }
     374                 :            : 
     375         [ +  + ]:      96097 :     if (s == expr_end) {
     376   [ +  +  +  +  :         29 :         if (*expr_end == '!' || *expr_end == ':' || *expr_end == '=') {
                   +  + ]
     377                 :         23 :             RAISE_SYNTAX_ERROR("f-string: expression required before '%c'", *expr_end);
     378                 :         23 :             return NULL;
     379                 :            :         }
     380                 :          6 :         RAISE_SYNTAX_ERROR("f-string: empty expression not allowed");
     381                 :          6 :         return NULL;
     382                 :            :     }
     383                 :            : 
     384                 :      96068 :     len = expr_end - expr_start;
     385                 :            :     /* Allocate 3 extra bytes: open paren, close paren, null byte. */
     386                 :      96068 :     str = PyMem_Calloc(len + 3, sizeof(char));
     387         [ -  + ]:      96068 :     if (str == NULL) {
     388                 :            :         PyErr_NoMemory();
     389                 :          0 :         return NULL;
     390                 :            :     }
     391                 :            : 
     392                 :            :     // The call to fstring_find_expr_location is responsible for finding the column offset
     393                 :            :     // the generated AST nodes need to be shifted to the right, which is equal to the number
     394                 :            :     // of the f-string characters before the expression starts.
     395                 :      96068 :     memcpy(str+1, expr_start, len);
     396                 :            :     int lines, cols;
     397         [ -  + ]:      96068 :     if (!fstring_find_expr_location(t, expr_start-1, str+1, &lines, &cols)) {
     398                 :          0 :         PyMem_Free(str);
     399                 :          0 :         return NULL;
     400                 :            :     }
     401                 :            : 
     402                 :            :     // The parentheses are needed in order to allow for leading whitespace within
     403                 :            :     // the f-string expression. This consequently gets parsed as a group (see the
     404                 :            :     // group rule in python.gram).
     405                 :      96068 :     str[0] = '(';
     406                 :      96068 :     str[len+1] = ')';
     407                 :            : 
     408                 :      96068 :     struct tok_state* tok = _PyTokenizer_FromString(str, 1);
     409         [ -  + ]:      96068 :     if (tok == NULL) {
     410                 :          0 :         PyMem_Free(str);
     411                 :          0 :         return NULL;
     412                 :            :     }
     413                 :      96068 :     Py_INCREF(p->tok->filename);
     414                 :            : 
     415                 :      96068 :     tok->filename = p->tok->filename;
     416                 :      96068 :     tok->lineno = t->lineno + lines - 1;
     417                 :            : 
     418                 :      96068 :     Parser *p2 = _PyPegen_Parser_New(tok, Py_fstring_input, p->flags, p->feature_version,
     419                 :            :                                      NULL, p->arena);
     420                 :            : 
     421                 :      96068 :     p2->starting_lineno = t->lineno + lines;
     422         [ +  + ]:      96068 :     p2->starting_col_offset = lines != 0 ? cols : t->col_offset + cols;
     423                 :            : 
     424                 :      96068 :     expr = _PyPegen_run_parser(p2);
     425                 :            : 
     426         [ +  + ]:      96068 :     if (expr == NULL) {
     427                 :         16 :         goto exit;
     428                 :            :     }
     429                 :      96052 :     result = expr;
     430                 :            : 
     431                 :      96068 : exit:
     432                 :      96068 :     PyMem_Free(str);
     433                 :      96068 :     _PyPegen_Parser_Free(p2);
     434                 :      96068 :     _PyTokenizer_Free(tok);
     435                 :      96068 :     return result;
     436                 :            : }
     437                 :            : 
     438                 :            : /* Return -1 on error.
     439                 :            : 
     440                 :            :    Return 0 if we reached the end of the literal.
     441                 :            : 
     442                 :            :    Return 1 if we haven't reached the end of the literal, but we want
     443                 :            :    the caller to process the literal up to this point. Used for
     444                 :            :    doubled braces.
     445                 :            : */
     446                 :            : static int
     447                 :     119721 : fstring_find_literal(Parser *p, const char **str, const char *end, int raw,
     448                 :            :                      PyObject **literal, int recurse_lvl, Token *t)
     449                 :            : {
     450                 :            :     /* Get any literal string. It ends when we hit an un-doubled left
     451                 :            :        brace (which isn't part of a unicode name escape such as
     452                 :            :        "\N{EULER CONSTANT}"), or the end of the string. */
     453                 :            : 
     454                 :     119721 :     const char *s = *str;
     455                 :     119721 :     const char *literal_start = s;
     456                 :     119721 :     int result = 0;
     457                 :            : 
     458                 :            :     assert(*literal == NULL);
     459         [ +  + ]:     671363 :     while (s < end) {
     460                 :     649256 :         char ch = *s++;
     461   [ +  +  +  +  :     649256 :         if (!raw && ch == '\\' && s < end) {
                   +  - ]
     462                 :       3149 :             ch = *s++;
     463         [ +  + ]:       3149 :             if (ch == 'N') {
     464                 :            :                 /* We need to look at and skip matching braces for "\N{name}"
     465                 :            :                    sequences because otherwise we'll think the opening '{'
     466                 :            :                    starts an expression, which is not the case with "\N".
     467                 :            :                    Keep looking for either a matched '{' '}' pair, or the end
     468                 :            :                    of the string. */
     469                 :            : 
     470   [ +  +  +  + ]:         27 :                 if (s < end && *s++ == '{') {
     471   [ +  +  +  + ]:        524 :                     while (s < end && *s++ != '}') {
     472                 :            :                     }
     473                 :         24 :                     continue;
     474                 :            :                 }
     475                 :            : 
     476                 :            :                 /* This is an invalid "\N" sequence, since it's a "\N" not
     477                 :            :                    followed by a "{".  Just keep parsing this literal.  This
     478                 :            :                    error will be caught later by
     479                 :            :                    decode_unicode_with_escapes(). */
     480                 :          3 :                 continue;
     481                 :            :             }
     482   [ +  +  -  + ]:       3122 :             if (ch == '{' && warn_invalid_escape_sequence(p, s-1, t) < 0) {
     483                 :          0 :                 return -1;
     484                 :            :             }
     485                 :            :         }
     486   [ +  +  +  + ]:     649229 :         if (ch == '{' || ch == '}') {
     487                 :            :             /* Check for doubled braces, but only at the top level. If
     488                 :            :                we checked at every level, then f'{0:{3}}' would fail
     489                 :            :                with the two closing braces. */
     490         [ +  + ]:      97614 :             if (recurse_lvl == 0) {
     491   [ +  +  +  + ]:      96502 :                 if (s < end && *s == ch) {
     492                 :            :                     /* We're going to tell the caller that the literal ends
     493                 :            :                        here, but that they should continue scanning. But also
     494                 :            :                        skip over the second brace when we resume scanning. */
     495                 :        509 :                     *str = s + 1;
     496                 :        509 :                     result = 1;
     497                 :        509 :                     goto done;
     498                 :            :                 }
     499                 :            : 
     500                 :            :                 /* Where a single '{' is the start of a new expression, a
     501                 :            :                    single '}' is not allowed. */
     502         [ +  + ]:      95993 :                 if (ch == '}') {
     503                 :          8 :                     *str = s - 1;
     504                 :          8 :                     RAISE_SYNTAX_ERROR("f-string: single '}' is not allowed");
     505                 :          8 :                     return -1;
     506                 :            :                 }
     507                 :            :             }
     508                 :            :             /* We're either at a '{', which means we're starting another
     509                 :            :                expression; or a '}', which means we're at the end of this
     510                 :            :                f-string (for a nested format_spec). */
     511                 :      97097 :             s--;
     512                 :      97097 :             break;
     513                 :            :         }
     514                 :            :     }
     515                 :     119204 :     *str = s;
     516                 :            :     assert(s <= end);
     517                 :            :     assert(s == end || *s == '{' || *s == '}');
     518                 :     119713 : done:
     519         [ +  + ]:     119713 :     if (literal_start != s) {
     520         [ +  + ]:     101358 :         if (raw) {
     521                 :        358 :             *literal = PyUnicode_DecodeUTF8Stateful(literal_start,
     522                 :            :                                                     s - literal_start,
     523                 :            :                                                     NULL, NULL);
     524                 :            :         }
     525                 :            :         else {
     526                 :     101000 :             *literal = decode_unicode_with_escapes(p, literal_start,
     527                 :     101000 :                                                    s - literal_start, t);
     528                 :            :         }
     529         [ +  + ]:     101358 :         if (!*literal) {
     530                 :          5 :             return -1;
     531                 :            :         }
     532                 :            :     }
     533                 :     119708 :     return result;
     534                 :            : }
     535                 :            : 
     536                 :            : /* Forward declaration because parsing is recursive. */
     537                 :            : static expr_ty
     538                 :            : fstring_parse(Parser *p, const char **str, const char *end, int raw, int recurse_lvl,
     539                 :            :               Token *first_token, Token* t, Token *last_token);
     540                 :            : 
     541                 :            : /* Parse the f-string at *str, ending at end.  We know *str starts an
     542                 :            :    expression (so it must be a '{'). Returns the FormattedValue node, which
     543                 :            :    includes the expression, conversion character, format_spec expression, and
     544                 :            :    optionally the text of the expression (if = is used).
     545                 :            : 
     546                 :            :    Note that I don't do a perfect job here: I don't make sure that a
     547                 :            :    closing brace doesn't match an opening paren, for example. It
     548                 :            :    doesn't need to error on all invalid expressions, just correctly
     549                 :            :    find the end of all valid ones. Any errors inside the expression
     550                 :            :    will be caught when we parse it later.
     551                 :            : 
     552                 :            :    *expression is set to the expression.  For an '=' "debug" expression,
     553                 :            :    *expr_text is set to the debug text (the original text of the expression,
     554                 :            :    including the '=' and any whitespace around it, as a string object).  If
     555                 :            :    not a debug expression, *expr_text set to NULL. */
     556                 :            : static int
     557                 :      96132 : fstring_find_expr(Parser *p, const char **str, const char *end, int raw, int recurse_lvl,
     558                 :            :                   PyObject **expr_text, expr_ty *expression, Token *first_token,
     559                 :            :                   Token *t, Token *last_token)
     560                 :            : {
     561                 :            :     /* Return -1 on error, else 0. */
     562                 :            : 
     563                 :            :     const char *expr_start;
     564                 :            :     const char *expr_end;
     565                 :            :     expr_ty simple_expression;
     566                 :      96132 :     expr_ty format_spec = NULL; /* Optional format specifier. */
     567                 :      96132 :     int conversion = -1; /* The conversion char.  Use default if not
     568                 :            :                             specified, or !r if using = and no format
     569                 :            :                             spec. */
     570                 :            : 
     571                 :            :     /* 0 if we're not in a string, else the quote char we're trying to
     572                 :            :        match (single or double quote). */
     573                 :      96132 :     char quote_char = 0;
     574                 :            : 
     575                 :            :     /* If we're inside a string, 1=normal, 3=triple-quoted. */
     576                 :      96132 :     int string_type = 0;
     577                 :            : 
     578                 :            :     /* Keep track of nesting level for braces/parens/brackets in
     579                 :            :        expressions. */
     580                 :      96132 :     Py_ssize_t nested_depth = 0;
     581                 :            :     char parenstack[MAXLEVEL];
     582                 :            : 
     583                 :      96132 :     *expr_text = NULL;
     584                 :            : 
     585                 :            :     /* Can only nest one level deep. */
     586         [ +  + ]:      96132 :     if (recurse_lvl >= 2) {
     587                 :          1 :         RAISE_SYNTAX_ERROR("f-string: expressions nested too deeply");
     588                 :          1 :         goto error;
     589                 :            :     }
     590                 :            : 
     591                 :            :     /* The first char must be a left brace, or we wouldn't have gotten
     592                 :            :        here. Skip over it. */
     593                 :            :     assert(**str == '{');
     594                 :      96131 :     *str += 1;
     595                 :            : 
     596                 :      96131 :     expr_start = *str;
     597         [ +  + ]:     427806 :     for (; *str < end; (*str)++) {
     598                 :            :         char ch;
     599                 :            : 
     600                 :            :         /* Loop invariants. */
     601                 :            :         assert(nested_depth >= 0);
     602                 :            :         assert(*str >= expr_start && *str < end);
     603                 :            :         if (quote_char) {
     604                 :            :             assert(string_type == 1 || string_type == 3);
     605                 :            :         } else {
     606                 :            :             assert(string_type == 0);
     607                 :            :         }
     608                 :            : 
     609                 :     427791 :         ch = **str;
     610                 :            :         /* Nowhere inside an expression is a backslash allowed. */
     611         [ +  + ]:     427791 :         if (ch == '\\') {
     612                 :            :             /* Error: can't include a backslash character, inside
     613                 :            :                parens or strings or not. */
     614                 :          8 :             RAISE_SYNTAX_ERROR(
     615                 :            :                       "f-string expression part "
     616                 :            :                       "cannot include a backslash");
     617                 :          8 :             goto error;
     618                 :            :         }
     619         [ +  + ]:     427783 :         if (quote_char) {
     620                 :            :             /* We're inside a string. See if we're at the end. */
     621                 :            :             /* This code needs to implement the same non-error logic
     622                 :            :                as tok_get from tokenizer.c, at the letter_quote
     623                 :            :                label. To actually share that code would be a
     624                 :            :                nightmare. But, it's unlikely to change and is small,
     625                 :            :                so duplicate it here. Note we don't need to catch all
     626                 :            :                of the errors, since they'll be caught when parsing the
     627                 :            :                expression. We just need to match the non-error
     628                 :            :                cases. Thus we can ignore \n in single-quoted strings,
     629                 :            :                for example. Or non-terminated strings. */
     630         [ +  + ]:       3337 :             if (ch == quote_char) {
     631                 :            :                 /* Does this match the string_type (single or triple
     632                 :            :                    quoted)? */
     633         [ +  + ]:        927 :                 if (string_type == 3) {
     634   [ +  -  +  +  :         62 :                     if (*str+2 < end && *(*str+1) == ch && *(*str+2) == ch) {
                   +  - ]
     635                 :            :                         /* We're at the end of a triple quoted string. */
     636                 :         38 :                         *str += 2;
     637                 :         38 :                         string_type = 0;
     638                 :         38 :                         quote_char = 0;
     639                 :         38 :                         continue;
     640                 :            :                     }
     641                 :            :                 } else {
     642                 :            :                     /* We're at the end of a normal string. */
     643                 :        865 :                     quote_char = 0;
     644                 :        865 :                     string_type = 0;
     645                 :        865 :                     continue;
     646                 :            :                 }
     647                 :            :             }
     648   [ +  +  +  + ]:     424446 :         } else if (ch == '\'' || ch == '"') {
     649                 :            :             /* Is this a triple quoted string? */
     650   [ +  +  +  +  :        908 :             if (*str+2 < end && *(*str+1) == ch && *(*str+2) == ch) {
                   +  + ]
     651                 :         38 :                 string_type = 3;
     652                 :         38 :                 *str += 2;
     653                 :            :             } else {
     654                 :            :                 /* Start of a normal string. */
     655                 :        870 :                 string_type = 1;
     656                 :            :             }
     657                 :            :             /* Start looking for the end of the string. */
     658                 :        908 :             quote_char = ch;
     659   [ +  +  +  +  :     423538 :         } else if (ch == '[' || ch == '{' || ch == '(') {
                   +  + ]
     660         [ +  + ]:       3621 :             if (nested_depth >= MAXLEVEL) {
     661                 :          1 :                 RAISE_SYNTAX_ERROR("f-string: too many nested parenthesis");
     662                 :          1 :                 goto error;
     663                 :            :             }
     664                 :       3620 :             parenstack[nested_depth] = ch;
     665                 :       3620 :             nested_depth++;
     666         [ +  + ]:     419917 :         } else if (ch == '#') {
     667                 :            :             /* Error: can't include a comment character, inside parens
     668                 :            :                or not. */
     669                 :          3 :             RAISE_SYNTAX_ERROR("f-string expression part cannot include '#'");
     670                 :          3 :             goto error;
     671   [ +  +  +  + ]:     419914 :         } else if (nested_depth == 0 &&
     672   [ +  +  +  +  :     390371 :                    (ch == '!' || ch == ':' || ch == '}' ||
                   +  + ]
     673   [ +  +  +  + ]:     301148 :                     ch == '=' || ch == '>' || ch == '<')) {
     674                 :            :             /* See if there's a next character. */
     675         [ +  + ]:      96210 :             if (*str+1 < end) {
     676                 :      89432 :                 char next = *(*str+1);
     677                 :            : 
     678                 :            :                 /* For "!=". since '=' is not an allowed conversion character,
     679                 :            :                    nothing is lost in this test. */
     680   [ +  +  +  +  :      89432 :                 if ((ch == '!' && next == '=') ||   /* != */
                   +  + ]
     681   [ +  +  +  + ]:      89414 :                     (ch == '=' && next == '=') ||   /* == */
     682   [ -  +  +  + ]:      89407 :                     (ch == '<' && next == '=') ||   /* <= */
     683         [ +  + ]:         83 :                     (ch == '>' && next == '=')      /* >= */
     684                 :            :                     ) {
     685                 :         31 :                     *str += 1;
     686                 :         31 :                     continue;
     687                 :            :                 }
     688                 :            :             }
     689                 :            :             /* Don't get out of the loop for these, if they're single
     690                 :            :                chars (not part of 2-char tokens). If by themselves, they
     691                 :            :                don't end an expression (unlike say '!'). */
     692   [ +  +  +  + ]:      96179 :             if (ch == '>' || ch == '<') {
     693                 :         82 :                 continue;
     694                 :            :             }
     695                 :            : 
     696                 :            :             /* Normal way out of this loop. */
     697                 :      96097 :             break;
     698   [ +  +  +  +  :     323704 :         } else if (ch == ']' || ch == '}' || ch == ')') {
                   +  + ]
     699         [ +  + ]:       3418 :             if (!nested_depth) {
     700                 :          2 :                 RAISE_SYNTAX_ERROR("f-string: unmatched '%c'", ch);
     701                 :          2 :                 goto error;
     702                 :            :             }
     703                 :       3416 :             nested_depth--;
     704                 :       3416 :             int opening = (unsigned char)parenstack[nested_depth];
     705   [ +  +  +  +  :       3418 :             if (!((opening == '(' && ch == ')') ||
             +  +  +  + ]
     706         [ +  + ]:        890 :                   (opening == '[' && ch == ']') ||
     707         [ -  + ]:         23 :                   (opening == '{' && ch == '}')))
     708                 :            :             {
     709                 :          5 :                 RAISE_SYNTAX_ERROR(
     710                 :            :                           "f-string: closing parenthesis '%c' "
     711                 :            :                           "does not match opening parenthesis '%c'",
     712                 :            :                           ch, opening);
     713                 :          5 :                 goto error;
     714                 :            :             }
     715                 :            :         } else {
     716                 :            :             /* Just consume this char and loop around. */
     717                 :            :         }
     718                 :            :     }
     719                 :      96112 :     expr_end = *str;
     720                 :            :     /* If we leave the above loop in a string or with mismatched parens, we
     721                 :            :        don't really care. We'll get a syntax error when compiling the
     722                 :            :        expression. But, we can produce a better error message, so let's just
     723                 :            :        do that.*/
     724         [ +  + ]:      96112 :     if (quote_char) {
     725                 :          4 :         RAISE_SYNTAX_ERROR("f-string: unterminated string");
     726                 :          4 :         goto error;
     727                 :            :     }
     728         [ -  + ]:      96108 :     if (nested_depth) {
     729                 :          0 :         int opening = (unsigned char)parenstack[nested_depth - 1];
     730                 :          0 :         RAISE_SYNTAX_ERROR("f-string: unmatched '%c'", opening);
     731                 :          0 :         goto error;
     732                 :            :     }
     733                 :            : 
     734         [ +  + ]:      96108 :     if (*str >= end) {
     735                 :         11 :         goto unexpected_end_of_string;
     736                 :            :     }
     737                 :            : 
     738                 :            :     /* Compile the expression as soon as possible, so we show errors
     739                 :            :        related to the expression before errors related to the
     740                 :            :        conversion or format_spec. */
     741                 :      96097 :     simple_expression = fstring_compile_expr(p, expr_start, expr_end, t);
     742         [ +  + ]:      96097 :     if (!simple_expression) {
     743                 :         45 :         goto error;
     744                 :            :     }
     745                 :            : 
     746                 :            :     /* Check for =, which puts the text value of the expression in
     747                 :            :        expr_text. */
     748         [ +  + ]:      96052 :     if (**str == '=') {
     749         [ +  + ]:        169 :         if (p->feature_version < 8) {
     750                 :          1 :             RAISE_SYNTAX_ERROR("f-string: self documenting expressions are "
     751                 :            :                                "only supported in Python 3.8 and greater");
     752                 :          1 :             goto error;
     753                 :            :         }
     754                 :        168 :         *str += 1;
     755                 :            : 
     756                 :            :         /* Skip over ASCII whitespace.  No need to test for end of string
     757                 :            :            here, since we know there's at least a trailing quote somewhere
     758                 :            :            ahead. */
     759         [ +  + ]:        178 :         while (Py_ISSPACE(**str)) {
     760                 :         10 :             *str += 1;
     761                 :            :         }
     762         [ +  + ]:        168 :         if (*str >= end) {
     763                 :          1 :             goto unexpected_end_of_string;
     764                 :            :         }
     765                 :            :         /* Set *expr_text to the text of the expression. */
     766                 :        167 :         *expr_text = PyUnicode_FromStringAndSize(expr_start, *str-expr_start);
     767         [ -  + ]:        167 :         if (!*expr_text) {
     768                 :          0 :             goto error;
     769                 :            :         }
     770                 :            :     }
     771                 :            : 
     772                 :            :     /* Check for a conversion char, if present. */
     773         [ +  + ]:      96050 :     if (**str == '!') {
     774                 :       6921 :         *str += 1;
     775                 :       6921 :         const char *conv_start = *str;
     776                 :            :         while (1) {
     777         [ +  + ]:      13852 :             if (*str >= end) {
     778                 :          5 :                 goto unexpected_end_of_string;
     779                 :            :             }
     780   [ +  +  +  + ]:      13847 :             if (**str == '}' || **str == ':') {
     781                 :            :                 break;
     782                 :            :             }
     783                 :       6931 :             *str += 1;
     784                 :            :         }
     785         [ +  + ]:       6916 :         if (*str == conv_start) {
     786                 :          3 :             RAISE_SYNTAX_ERROR(
     787                 :            :                       "f-string: missed conversion character");
     788                 :          3 :             goto error;
     789                 :            :         }
     790                 :            : 
     791                 :       6913 :         conversion = (unsigned char)*conv_start;
     792                 :            :         /* Validate the conversion. */
     793   [ +  +  +  + ]:       6913 :         if ((*str != conv_start + 1) ||
     794   [ +  +  +  + ]:       6816 :             !(conversion == 's' || conversion == 'r' || conversion == 'a'))
     795                 :            :         {
     796                 :         16 :             PyObject *conv_obj = PyUnicode_FromStringAndSize(conv_start,
     797                 :         16 :                                                              *str-conv_start);
     798         [ +  - ]:         16 :             if (conv_obj) {
     799                 :         16 :                 RAISE_SYNTAX_ERROR(
     800                 :            :                         "f-string: invalid conversion character %R: "
     801                 :            :                         "expected 's', 'r', or 'a'",
     802                 :            :                         conv_obj);
     803                 :         16 :                 Py_DECREF(conv_obj);
     804                 :            :             }
     805                 :         16 :             goto error;
     806                 :            :         }
     807                 :            : 
     808                 :            :     }
     809                 :            : 
     810                 :            :     /* Check for the format spec, if present. */
     811                 :            :     assert(*str < end);
     812         [ +  + ]:      96026 :     if (**str == ':') {
     813                 :        974 :         *str += 1;
     814         [ +  + ]:        974 :         if (*str >= end) {
     815                 :          2 :             goto unexpected_end_of_string;
     816                 :            :         }
     817                 :            : 
     818                 :            :         /* Parse the format spec. */
     819                 :        972 :         format_spec = fstring_parse(p, str, end, raw, recurse_lvl+1,
     820                 :            :                                     first_token, t, last_token);
     821         [ +  + ]:        972 :         if (!format_spec) {
     822                 :          7 :             goto error;
     823                 :            :         }
     824                 :            :     }
     825                 :            : 
     826   [ +  -  +  + ]:      96017 :     if (*str >= end || **str != '}') {
     827                 :          1 :         goto unexpected_end_of_string;
     828                 :            :     }
     829                 :            : 
     830                 :            :     /* We're at a right brace. Consume it. */
     831                 :            :     assert(*str < end);
     832                 :            :     assert(**str == '}');
     833                 :      96016 :     *str += 1;
     834                 :            : 
     835                 :            :     /* If we're in = mode (detected by non-NULL expr_text), and have no format
     836                 :            :        spec and no explicit conversion, set the conversion to 'r'. */
     837   [ +  +  +  +  :      96016 :     if (*expr_text && format_spec == NULL && conversion == -1) {
                   +  + ]
     838                 :         62 :         conversion = 'r';
     839                 :            :     }
     840                 :            : 
     841                 :            :     /* And now create the FormattedValue node that represents this
     842                 :            :        entire expression with the conversion and format spec. */
     843                 :            :     //TODO: Fix this
     844                 :      96016 :     *expression = _PyAST_FormattedValue(simple_expression, conversion,
     845                 :            :                                         format_spec, first_token->lineno,
     846                 :            :                                         first_token->col_offset,
     847                 :            :                                         last_token->end_lineno,
     848                 :            :                                         last_token->end_col_offset, p->arena);
     849         [ -  + ]:      96016 :     if (!*expression) {
     850                 :          0 :         goto error;
     851                 :            :     }
     852                 :            : 
     853                 :      96016 :     return 0;
     854                 :            : 
     855                 :         20 : unexpected_end_of_string:
     856                 :         20 :     RAISE_SYNTAX_ERROR("f-string: expecting '}'");
     857                 :            :     /* Falls through to error. */
     858                 :            : 
     859                 :        116 : error:
     860                 :        116 :     Py_XDECREF(*expr_text);
     861                 :        116 :     return -1;
     862                 :            : 
     863                 :            : }
     864                 :            : 
     865                 :            : /* Return -1 on error.
     866                 :            : 
     867                 :            :    Return 0 if we have a literal (possible zero length) and an
     868                 :            :    expression (zero length if at the end of the string.
     869                 :            : 
     870                 :            :    Return 1 if we have a literal, but no expression, and we want the
     871                 :            :    caller to call us again. This is used to deal with doubled
     872                 :            :    braces.
     873                 :            : 
     874                 :            :    When called multiple times on the string 'a{{b{0}c', this function
     875                 :            :    will return:
     876                 :            : 
     877                 :            :    1. the literal 'a{' with no expression, and a return value
     878                 :            :       of 1. Despite the fact that there's no expression, the return
     879                 :            :       value of 1 means we're not finished yet.
     880                 :            : 
     881                 :            :    2. the literal 'b' and the expression '0', with a return value of
     882                 :            :       0. The fact that there's an expression means we're not finished.
     883                 :            : 
     884                 :            :    3. literal 'c' with no expression and a return value of 0. The
     885                 :            :       combination of the return value of 0 with no expression means
     886                 :            :       we're finished.
     887                 :            : */
     888                 :            : static int
     889                 :     119721 : fstring_find_literal_and_expr(Parser *p, const char **str, const char *end, int raw,
     890                 :            :                               int recurse_lvl, PyObject **literal,
     891                 :            :                               PyObject **expr_text, expr_ty *expression,
     892                 :            :                               Token *first_token, Token *t, Token *last_token)
     893                 :            : {
     894                 :            :     int result;
     895                 :            : 
     896                 :            :     assert(*literal == NULL && *expression == NULL);
     897                 :            : 
     898                 :            :     /* Get any literal string. */
     899                 :     119721 :     result = fstring_find_literal(p, str, end, raw, literal, recurse_lvl, t);
     900         [ +  + ]:     119721 :     if (result < 0) {
     901                 :         13 :         goto error;
     902                 :            :     }
     903                 :            : 
     904                 :            :     assert(result == 0 || result == 1);
     905                 :            : 
     906         [ +  + ]:     119708 :     if (result == 1) {
     907                 :            :         /* We have a literal, but don't look at the expression. */
     908                 :        509 :         return 1;
     909                 :            :     }
     910                 :            : 
     911   [ +  +  +  + ]:     119199 :     if (*str >= end || **str == '}') {
     912                 :            :         /* We're at the end of the string or the end of a nested
     913                 :            :            f-string: no expression. The top-level error case where we
     914                 :            :            expect to be at the end of the string but we're at a '}' is
     915                 :            :            handled later. */
     916                 :      23067 :         return 0;
     917                 :            :     }
     918                 :            : 
     919                 :            :     /* We must now be the start of an expression, on a '{'. */
     920                 :            :     assert(**str == '{');
     921                 :            : 
     922         [ +  + ]:      96132 :     if (fstring_find_expr(p, str, end, raw, recurse_lvl, expr_text,
     923                 :            :                           expression, first_token, t, last_token) < 0) {
     924                 :        116 :         goto error;
     925                 :            :     }
     926                 :            : 
     927                 :      96016 :     return 0;
     928                 :            : 
     929                 :        129 : error:
     930         [ +  + ]:        129 :     Py_CLEAR(*literal);
     931                 :        129 :     return -1;
     932                 :            : }
     933                 :            : 
     934                 :            : #ifdef NDEBUG
     935                 :            : #define ExprList_check_invariants(l)
     936                 :            : #else
     937                 :            : static void
     938                 :            : ExprList_check_invariants(ExprList *l)
     939                 :            : {
     940                 :            :     /* Check our invariants. Make sure this object is "live", and
     941                 :            :        hasn't been deallocated. */
     942                 :            :     assert(l->size >= 0);
     943                 :            :     assert(l->p != NULL);
     944                 :            :     if (l->size <= EXPRLIST_N_CACHED) {
     945                 :            :         assert(l->data == l->p);
     946                 :            :     }
     947                 :            : }
     948                 :            : #endif
     949                 :            : 
     950                 :            : static void
     951                 :    1601789 : ExprList_Init(ExprList *l)
     952                 :            : {
     953                 :    1601789 :     l->allocated = EXPRLIST_N_CACHED;
     954                 :    1601789 :     l->size = 0;
     955                 :            : 
     956                 :            :     /* Until we start allocating dynamically, p points to data. */
     957                 :    1601789 :     l->p = l->data;
     958                 :            : 
     959                 :            :     ExprList_check_invariants(l);
     960                 :    1601789 : }
     961                 :            : 
     962                 :            : static int
     963                 :     196172 : ExprList_Append(ExprList *l, expr_ty exp)
     964                 :            : {
     965                 :            :     ExprList_check_invariants(l);
     966         [ +  + ]:     196172 :     if (l->size >= l->allocated) {
     967                 :            :         /* We need to alloc (or realloc) the memory. */
     968                 :         58 :         Py_ssize_t new_size = l->allocated * 2;
     969                 :            : 
     970                 :            :         /* See if we've ever allocated anything dynamically. */
     971         [ +  + ]:         58 :         if (l->p == l->data) {
     972                 :            :             Py_ssize_t i;
     973                 :            :             /* We're still using the cached data. Switch to
     974                 :            :                alloc-ing. */
     975                 :         15 :             l->p = PyMem_Malloc(sizeof(expr_ty) * new_size);
     976         [ -  + ]:         15 :             if (!l->p) {
     977                 :          0 :                 return -1;
     978                 :            :             }
     979                 :            :             /* Copy the cached data into the new buffer. */
     980         [ +  + ]:        975 :             for (i = 0; i < l->size; i++) {
     981                 :        960 :                 l->p[i] = l->data[i];
     982                 :            :             }
     983                 :            :         } else {
     984                 :            :             /* Just realloc. */
     985                 :         43 :             expr_ty *tmp = PyMem_Realloc(l->p, sizeof(expr_ty) * new_size);
     986         [ -  + ]:         43 :             if (!tmp) {
     987                 :          0 :                 PyMem_Free(l->p);
     988                 :          0 :                 l->p = NULL;
     989                 :          0 :                 return -1;
     990                 :            :             }
     991                 :         43 :             l->p = tmp;
     992                 :            :         }
     993                 :            : 
     994                 :         58 :         l->allocated = new_size;
     995                 :            :         assert(l->allocated == 2 * l->size);
     996                 :            :     }
     997                 :            : 
     998                 :     196172 :     l->p[l->size++] = exp;
     999                 :            : 
    1000                 :            :     ExprList_check_invariants(l);
    1001                 :     196172 :     return 0;
    1002                 :            : }
    1003                 :            : 
    1004                 :            : static void
    1005                 :      20110 : ExprList_Dealloc(ExprList *l)
    1006                 :            : {
    1007                 :            :     ExprList_check_invariants(l);
    1008                 :            : 
    1009                 :            :     /* If there's been an error, or we've never dynamically allocated,
    1010                 :            :        do nothing. */
    1011   [ +  -  +  + ]:      20110 :     if (!l->p || l->p == l->data) {
    1012                 :            :         /* Do nothing. */
    1013                 :            :     } else {
    1014                 :            :         /* We have dynamically allocated. Free the memory. */
    1015                 :         15 :         PyMem_Free(l->p);
    1016                 :            :     }
    1017                 :      20110 :     l->p = NULL;
    1018                 :      20110 :     l->size = -1;
    1019                 :      20110 : }
    1020                 :            : 
    1021                 :            : static asdl_expr_seq *
    1022                 :      19336 : ExprList_Finish(ExprList *l, PyArena *arena)
    1023                 :            : {
    1024                 :            :     asdl_expr_seq *seq;
    1025                 :            : 
    1026                 :            :     ExprList_check_invariants(l);
    1027                 :            : 
    1028                 :            :     /* Allocate the asdl_seq and copy the expressions in to it. */
    1029                 :      19336 :     seq = _Py_asdl_expr_seq_new(l->size, arena);
    1030         [ +  - ]:      19336 :     if (seq) {
    1031                 :            :         Py_ssize_t i;
    1032         [ +  + ]:     215506 :         for (i = 0; i < l->size; i++) {
    1033                 :     196170 :             asdl_seq_SET(seq, i, l->p[i]);
    1034                 :            :         }
    1035                 :            :     }
    1036                 :      19336 :     ExprList_Dealloc(l);
    1037                 :      19336 :     return seq;
    1038                 :            : }
    1039                 :            : 
    1040                 :            : #ifdef NDEBUG
    1041                 :            : #define FstringParser_check_invariants(state)
    1042                 :            : #else
    1043                 :            : static void
    1044                 :            : FstringParser_check_invariants(FstringParser *state)
    1045                 :            : {
    1046                 :            :     if (state->last_str) {
    1047                 :            :         assert(PyUnicode_CheckExact(state->last_str));
    1048                 :            :     }
    1049                 :            :     ExprList_check_invariants(&state->expr_list);
    1050                 :            : }
    1051                 :            : #endif
    1052                 :            : 
    1053                 :            : void
    1054                 :    1601789 : _PyPegen_FstringParser_Init(FstringParser *state)
    1055                 :            : {
    1056                 :    1601789 :     state->last_str = NULL;
    1057                 :    1601789 :     state->fmode = 0;
    1058                 :    1601789 :     ExprList_Init(&state->expr_list);
    1059                 :            :     FstringParser_check_invariants(state);
    1060                 :    1601789 : }
    1061                 :            : 
    1062                 :            : void
    1063                 :        774 : _PyPegen_FstringParser_Dealloc(FstringParser *state)
    1064                 :            : {
    1065                 :            :     FstringParser_check_invariants(state);
    1066                 :            : 
    1067                 :        774 :     Py_XDECREF(state->last_str);
    1068                 :        774 :     ExprList_Dealloc(&state->expr_list);
    1069                 :        774 : }
    1070                 :            : 
    1071                 :            : /* Make a Constant node, but decref the PyUnicode object being added. */
    1072                 :            : static expr_ty
    1073                 :    1633428 : make_str_node_and_del(Parser *p, PyObject **str, Token* first_token, Token *last_token)
    1074                 :            : {
    1075                 :    1633428 :     PyObject *s = *str;
    1076                 :    1633428 :     PyObject *kind = NULL;
    1077                 :    1633428 :     *str = NULL;
    1078                 :            :     assert(PyUnicode_CheckExact(s));
    1079         [ -  + ]:    1633428 :     if (_PyArena_AddPyObject(p->arena, s) < 0) {
    1080                 :          0 :         Py_DECREF(s);
    1081                 :          0 :         return NULL;
    1082                 :            :     }
    1083                 :    1633428 :     const char* the_str = PyBytes_AsString(first_token->bytes);
    1084   [ +  -  +  + ]:    1633428 :     if (the_str && the_str[0] == 'u') {
    1085                 :        844 :         kind = _PyPegen_new_identifier(p, "u");
    1086                 :            :     }
    1087                 :            : 
    1088   [ +  +  -  + ]:    1633428 :     if (kind == NULL && PyErr_Occurred()) {
    1089                 :          0 :         return NULL;
    1090                 :            :     }
    1091                 :            : 
    1092                 :    1633428 :     return _PyAST_Constant(s, kind, first_token->lineno, first_token->col_offset,
    1093                 :            :                            last_token->end_lineno, last_token->end_col_offset,
    1094                 :            :                            p->arena);
    1095                 :            : 
    1096                 :            : }
    1097                 :            : 
    1098                 :            : 
    1099                 :            : /* Add a non-f-string (that is, a regular literal string). str is
    1100                 :            :    decref'd. */
    1101                 :            : int
    1102                 :    1712527 : _PyPegen_FstringParser_ConcatAndDel(FstringParser *state, PyObject *str)
    1103                 :            : {
    1104                 :            :     FstringParser_check_invariants(state);
    1105                 :            : 
    1106                 :            :     assert(PyUnicode_CheckExact(str));
    1107                 :            : 
    1108         [ +  + ]:    1712527 :     if (PyUnicode_GET_LENGTH(str) == 0) {
    1109                 :     100534 :         Py_DECREF(str);
    1110                 :     100534 :         return 0;
    1111                 :            :     }
    1112                 :            : 
    1113         [ +  + ]:    1611993 :     if (!state->last_str) {
    1114                 :            :         /* We didn't have a string before, so just remember this one. */
    1115                 :    1532956 :         state->last_str = str;
    1116                 :            :     } else {
    1117                 :            :         /* Concatenate this with the previous string. */
    1118                 :      79037 :         PyUnicode_AppendAndDel(&state->last_str, str);
    1119         [ -  + ]:      79037 :         if (!state->last_str) {
    1120                 :          0 :             return -1;
    1121                 :            :         }
    1122                 :            :     }
    1123                 :            :     FstringParser_check_invariants(state);
    1124                 :    1611993 :     return 0;
    1125                 :            : }
    1126                 :            : 
    1127                 :            : /* Parse an f-string. The f-string is in *str to end, with no
    1128                 :            :    'f' or quotes. */
    1129                 :            : int
    1130                 :      23196 : _PyPegen_FstringParser_ConcatFstring(Parser *p, FstringParser *state, const char **str,
    1131                 :            :                             const char *end, int raw, int recurse_lvl,
    1132                 :            :                             Token *first_token, Token* t, Token *last_token)
    1133                 :            : {
    1134                 :            :     FstringParser_check_invariants(state);
    1135                 :      23196 :     state->fmode = 1;
    1136                 :            : 
    1137                 :            :     /* Parse the f-string. */
    1138                 :      96525 :     while (1) {
    1139                 :     119721 :         PyObject *literal = NULL;
    1140                 :     119721 :         PyObject *expr_text = NULL;
    1141                 :     119721 :         expr_ty expression = NULL;
    1142                 :            : 
    1143                 :            :         /* If there's a zero length literal in front of the
    1144                 :            :            expression, literal will be NULL. If we're at the end of
    1145                 :            :            the f-string, expression will be NULL (unless result == 1,
    1146                 :            :            see below). */
    1147                 :     119721 :         int result = fstring_find_literal_and_expr(p, str, end, raw, recurse_lvl,
    1148                 :            :                                                    &literal, &expr_text,
    1149                 :            :                                                    &expression, first_token, t, last_token);
    1150         [ +  + ]:     119721 :         if (result < 0) {
    1151                 :        129 :             return -1;
    1152                 :            :         }
    1153                 :            : 
    1154                 :            :         /* Add the literal, if any. */
    1155   [ +  +  -  + ]:     119592 :         if (literal && _PyPegen_FstringParser_ConcatAndDel(state, literal) < 0) {
    1156                 :          0 :             Py_XDECREF(expr_text);
    1157                 :          0 :             return -1;
    1158                 :            :         }
    1159                 :            :         /* Add the expr_text, if any. */
    1160   [ +  +  -  + ]:     119592 :         if (expr_text && _PyPegen_FstringParser_ConcatAndDel(state, expr_text) < 0) {
    1161                 :          0 :             return -1;
    1162                 :            :         }
    1163                 :            : 
    1164                 :            :         /* We've dealt with the literal and expr_text, their ownership has
    1165                 :            :            been transferred to the state object.  Don't look at them again. */
    1166                 :            : 
    1167                 :            :         /* See if we should just loop around to get the next literal
    1168                 :            :            and expression, while ignoring the expression this
    1169                 :            :            time. This is used for un-doubling braces, as an
    1170                 :            :            optimization. */
    1171         [ +  + ]:     119592 :         if (result == 1) {
    1172                 :        509 :             continue;
    1173                 :            :         }
    1174                 :            : 
    1175         [ +  + ]:     119083 :         if (!expression) {
    1176                 :            :             /* We're done with this f-string. */
    1177                 :      23067 :             break;
    1178                 :            :         }
    1179                 :            : 
    1180                 :            :         /* We know we have an expression. Convert any existing string
    1181                 :            :            to a Constant node. */
    1182         [ +  + ]:      96016 :         if (state->last_str) {
    1183                 :            :             /* Convert the existing last_str literal to a Constant node. */
    1184                 :      89559 :             expr_ty last_str = make_str_node_and_del(p, &state->last_str, first_token, last_token);
    1185   [ +  -  -  + ]:      89559 :             if (!last_str || ExprList_Append(&state->expr_list, last_str) < 0) {
    1186                 :          0 :                 return -1;
    1187                 :            :             }
    1188                 :            :         }
    1189                 :            : 
    1190         [ -  + ]:      96016 :         if (ExprList_Append(&state->expr_list, expression) < 0) {
    1191                 :          0 :             return -1;
    1192                 :            :         }
    1193                 :            :     }
    1194                 :            : 
    1195                 :            :     /* If recurse_lvl is zero, then we must be at the end of the
    1196                 :            :        string. Otherwise, we must be at a right brace. */
    1197                 :            : 
    1198   [ +  +  -  + ]:      23067 :     if (recurse_lvl == 0 && *str < end-1) {
    1199                 :          0 :         RAISE_SYNTAX_ERROR("f-string: unexpected end of string");
    1200                 :          0 :         return -1;
    1201                 :            :     }
    1202   [ +  +  +  + ]:      23067 :     if (recurse_lvl != 0 && **str != '}') {
    1203                 :          2 :         RAISE_SYNTAX_ERROR("f-string: expecting '}'");
    1204                 :          2 :         return -1;
    1205                 :            :     }
    1206                 :            : 
    1207                 :            :     FstringParser_check_invariants(state);
    1208                 :      23065 :     return 0;
    1209                 :            : }
    1210                 :            : 
    1211                 :            : /* Convert the partial state reflected in last_str and expr_list to an
    1212                 :            :    expr_ty. The expr_ty can be a Constant, or a JoinedStr. */
    1213                 :            : expr_ty
    1214                 :    1552608 : _PyPegen_FstringParser_Finish(Parser *p, FstringParser *state, Token* first_token,
    1215                 :            :                      Token *last_token)
    1216                 :            : {
    1217                 :            :     asdl_expr_seq *seq;
    1218                 :            : 
    1219                 :            :     FstringParser_check_invariants(state);
    1220                 :            : 
    1221                 :            :     /* If we're just a constant string with no expressions, return
    1222                 :            :        that. */
    1223         [ +  + ]:    1552608 :     if (!state->fmode) {
    1224                 :            :         assert(!state->expr_list.size);
    1225         [ +  + ]:    1533272 :         if (!state->last_str) {
    1226                 :            :             /* Create a zero length string. */
    1227                 :     100478 :             state->last_str = PyUnicode_FromStringAndSize(NULL, 0);
    1228         [ -  + ]:     100478 :             if (!state->last_str) {
    1229                 :          0 :                 goto error;
    1230                 :            :             }
    1231                 :            :         }
    1232                 :    1533272 :         return make_str_node_and_del(p, &state->last_str, first_token, last_token);
    1233                 :            :     }
    1234                 :            : 
    1235                 :            :     /* Create a Constant node out of last_str, if needed. It will be the
    1236                 :            :        last node in our expression list. */
    1237         [ +  + ]:      19336 :     if (state->last_str) {
    1238                 :      10597 :         expr_ty str = make_str_node_and_del(p, &state->last_str, first_token, last_token);
    1239   [ +  -  -  + ]:      10597 :         if (!str || ExprList_Append(&state->expr_list, str) < 0) {
    1240                 :          0 :             goto error;
    1241                 :            :         }
    1242                 :            :     }
    1243                 :            :     /* This has already been freed. */
    1244                 :            :     assert(state->last_str == NULL);
    1245                 :            : 
    1246                 :      19336 :     seq = ExprList_Finish(&state->expr_list, p->arena);
    1247         [ -  + ]:      19336 :     if (!seq) {
    1248                 :          0 :         goto error;
    1249                 :            :     }
    1250                 :            : 
    1251                 :      19336 :     return _PyAST_JoinedStr(seq, first_token->lineno, first_token->col_offset,
    1252                 :            :                             last_token->end_lineno, last_token->end_col_offset,
    1253                 :            :                             p->arena);
    1254                 :            : 
    1255                 :          0 : error:
    1256                 :          0 :     _PyPegen_FstringParser_Dealloc(state);
    1257                 :          0 :     return NULL;
    1258                 :            : }
    1259                 :            : 
    1260                 :            : /* Given an f-string (with no 'f' or quotes) that's in *str and ends
    1261                 :            :    at end, parse it into an expr_ty.  Return NULL on error.  Adjust
    1262                 :            :    str to point past the parsed portion. */
    1263                 :            : static expr_ty
    1264                 :        972 : fstring_parse(Parser *p, const char **str, const char *end, int raw,
    1265                 :            :               int recurse_lvl, Token *first_token, Token* t, Token *last_token)
    1266                 :            : {
    1267                 :            :     FstringParser state;
    1268                 :            : 
    1269                 :        972 :     _PyPegen_FstringParser_Init(&state);
    1270         [ +  + ]:        972 :     if (_PyPegen_FstringParser_ConcatFstring(p, &state, str, end, raw, recurse_lvl,
    1271                 :            :                                     first_token, t, last_token) < 0) {
    1272                 :          7 :         _PyPegen_FstringParser_Dealloc(&state);
    1273                 :          7 :         return NULL;
    1274                 :            :     }
    1275                 :            : 
    1276                 :        965 :     return _PyPegen_FstringParser_Finish(p, &state, t, t);
    1277                 :            : }

Generated by: LCOV version 1.14