LCOV - code coverage report
Current view: | top level - Parser - string_parser.c (source / functions) |  |  | Hit | Total | Coverage
Test: | CPython 3.12 LCOV report [commit 5e6661bce9] |  | Lines: | 323 | 517 | 62.5 %
Date: | 2023-03-20 08:15:36 |  | Functions: | 18 | 21 | 85.7 %
|  |  | Branches: | 274 | 462 | 59.3 %

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

Generated by: LCOV version 1.14