LCOV - code coverage report
Current view: top level - Parser - pegen.c (source / functions) Hit Total Coverage
Test: CPython 3.12 LCOV report [commit acb105a7c1f] Lines: 409 472 86.7 %
Date: 2022-07-20 13:12:14 Functions: 38 39 97.4 %
Branches: 236 296 79.7 %

           Branch data     Line data    Source code
       1                 :            : #include <Python.h>
       2                 :            : #include "pycore_ast.h"           // _PyAST_Validate(),
       3                 :            : #include <errcode.h>
       4                 :            : 
       5                 :            : #include "tokenizer.h"
       6                 :            : #include "pegen.h"
       7                 :            : 
       8                 :            : // Internal parser functions
       9                 :            : 
      10                 :            : asdl_stmt_seq*
      11                 :         14 : _PyPegen_interactive_exit(Parser *p)
      12                 :            : {
      13         [ +  - ]:         14 :     if (p->errcode) {
      14                 :         14 :         *(p->errcode) = E_EOF;
      15                 :            :     }
      16                 :         14 :     return NULL;
      17                 :            : }
      18                 :            : 
      19                 :            : Py_ssize_t
      20                 :       3877 : _PyPegen_byte_offset_to_character_offset(PyObject *line, Py_ssize_t col_offset)
      21                 :            : {
      22                 :       3877 :     const char *str = PyUnicode_AsUTF8(line);
      23         [ -  + ]:       3877 :     if (!str) {
      24                 :          0 :         return -1;
      25                 :            :     }
      26                 :       3877 :     Py_ssize_t len = strlen(str);
      27         [ +  + ]:       3877 :     if (col_offset > len + 1) {
      28                 :          8 :         col_offset = len + 1;
      29                 :            :     }
      30                 :            :     assert(col_offset >= 0);
      31                 :       3877 :     PyObject *text = PyUnicode_DecodeUTF8(str, col_offset, "replace");
      32         [ -  + ]:       3877 :     if (!text) {
      33                 :          0 :         return -1;
      34                 :            :     }
      35                 :       3877 :     Py_ssize_t size = PyUnicode_GET_LENGTH(text);
      36                 :       3877 :     Py_DECREF(text);
      37                 :       3877 :     return size;
      38                 :            : }
      39                 :            : 
      40                 :            : // Here, mark is the start of the node, while p->mark is the end.
      41                 :            : // If node==NULL, they should be the same.
      42                 :            : int
      43                 :  194514777 : _PyPegen_insert_memo(Parser *p, int mark, int type, void *node)
      44                 :            : {
      45                 :            :     // Insert in front
      46                 :  194514777 :     Memo *m = _PyArena_Malloc(p->arena, sizeof(Memo));
      47         [ -  + ]:  194514777 :     if (m == NULL) {
      48                 :          0 :         return -1;
      49                 :            :     }
      50                 :  194514777 :     m->type = type;
      51                 :  194514777 :     m->node = node;
      52                 :  194514777 :     m->mark = p->mark;
      53                 :  194514777 :     m->next = p->tokens[mark]->memo;
      54                 :  194514777 :     p->tokens[mark]->memo = m;
      55                 :  194514777 :     return 0;
      56                 :            : }
      57                 :            : 
      58                 :            : // Like _PyPegen_insert_memo(), but updates an existing node if found.
      59                 :            : int
      60                 :  170488319 : _PyPegen_update_memo(Parser *p, int mark, int type, void *node)
      61                 :            : {
      62         [ +  + ]:  853361249 :     for (Memo *m = p->tokens[mark]->memo; m != NULL; m = m->next) {
      63         [ +  + ]:  761854285 :         if (m->type == type) {
      64                 :            :             // Update existing node.
      65                 :   78981355 :             m->node = node;
      66                 :   78981355 :             m->mark = p->mark;
      67                 :   78981355 :             return 0;
      68                 :            :         }
      69                 :            :     }
      70                 :            :     // Insert new node.
      71                 :   91506964 :     return _PyPegen_insert_memo(p, mark, type, node);
      72                 :            : }
      73                 :            : 
      74                 :            : static int
      75                 :        589 : init_normalization(Parser *p)
      76                 :            : {
      77         [ +  + ]:        589 :     if (p->normalize) {
      78                 :        534 :         return 1;
      79                 :            :     }
      80                 :         55 :     p->normalize = _PyImport_GetModuleAttrString("unicodedata", "normalize");
      81         [ -  + ]:         55 :     if (!p->normalize)
      82                 :            :     {
      83                 :          0 :         return 0;
      84                 :            :     }
      85                 :         55 :     return 1;
      86                 :            : }
      87                 :            : 
      88                 :            : static int
      89                 :     222224 : growable_comment_array_init(growable_comment_array *arr, size_t initial_size) {
      90                 :            :     assert(initial_size > 0);
      91                 :     222224 :     arr->items = PyMem_Malloc(initial_size * sizeof(*arr->items));
      92                 :     222224 :     arr->size = initial_size;
      93                 :     222224 :     arr->num_items = 0;
      94                 :            : 
      95                 :     222224 :     return arr->items != NULL;
      96                 :            : }
      97                 :            : 
      98                 :            : static int
      99                 :         74 : growable_comment_array_add(growable_comment_array *arr, int lineno, char *comment) {
     100         [ -  + ]:         74 :     if (arr->num_items >= arr->size) {
     101                 :          0 :         size_t new_size = arr->size * 2;
     102                 :          0 :         void *new_items_array = PyMem_Realloc(arr->items, new_size * sizeof(*arr->items));
     103         [ #  # ]:          0 :         if (!new_items_array) {
     104                 :          0 :             return 0;
     105                 :            :         }
     106                 :          0 :         arr->items = new_items_array;
     107                 :          0 :         arr->size = new_size;
     108                 :            :     }
     109                 :            : 
     110                 :         74 :     arr->items[arr->num_items].lineno = lineno;
     111                 :         74 :     arr->items[arr->num_items].comment = comment;  // Take ownership
     112                 :         74 :     arr->num_items++;
     113                 :         74 :     return 1;
     114                 :            : }
     115                 :            : 
     116                 :            : static void
     117                 :     222224 : growable_comment_array_deallocate(growable_comment_array *arr) {
     118         [ +  + ]:     222298 :     for (unsigned i = 0; i < arr->num_items; i++) {
     119                 :         74 :         PyMem_Free(arr->items[i].comment);
     120                 :            :     }
     121                 :     222224 :     PyMem_Free(arr->items);
     122                 :     222224 : }
     123                 :            : 
     124                 :            : static int
     125                 :   12380231 : _get_keyword_or_name_type(Parser *p, const char *name, int name_len)
     126                 :            : {
     127                 :            :     assert(name_len > 0);
     128         [ +  + ]:   12380231 :     if (name_len >= p->n_keyword_lists ||
     129         [ +  - ]:   10138034 :         p->keywords[name_len] == NULL ||
     130         [ +  + ]:   10138034 :         p->keywords[name_len]->type == -1) {
     131                 :    3937388 :         return NAME;
     132                 :            :     }
     133   [ +  -  +  + ]:   45096198 :     for (KeywordToken *k = p->keywords[name_len]; k != NULL && k->type != -1; k++) {
     134         [ +  + ]:   39141292 :         if (strncmp(k->str, name, name_len) == 0) {
     135                 :    2487937 :             return k->type;
     136                 :            :         }
     137                 :            :     }
     138                 :    5954906 :     return NAME;
     139                 :            : }
     140                 :            : 
     141                 :            : static int
     142                 :   39430438 : initialize_token(Parser *p, Token *token, const char *start, const char *end, int token_type) {
     143                 :            :     assert(token != NULL);
     144                 :            : 
     145         [ +  + ]:   39430438 :     token->type = (token_type == NAME) ? _get_keyword_or_name_type(p, start, (int)(end - start)) : token_type;
     146                 :   39430438 :     token->bytes = PyBytes_FromStringAndSize(start, end - start);
     147         [ -  + ]:   39430438 :     if (token->bytes == NULL) {
     148                 :          0 :         return -1;
     149                 :            :     }
     150                 :            : 
     151         [ -  + ]:   39430438 :     if (_PyArena_AddPyObject(p->arena, token->bytes) < 0) {
     152                 :          0 :         Py_DECREF(token->bytes);
     153                 :          0 :         return -1;
     154                 :            :     }
     155                 :            : 
     156                 :   39430438 :     token->level = p->tok->level;
     157                 :            : 
     158         [ +  + ]:   39430438 :     const char *line_start = token_type == STRING ? p->tok->multi_line_start : p->tok->line_start;
     159         [ +  + ]:   39430438 :     int lineno = token_type == STRING ? p->tok->first_lineno : p->tok->lineno;
     160                 :   39430438 :     int end_lineno = p->tok->lineno;
     161                 :            : 
     162   [ +  +  +  - ]:   39430438 :     int col_offset = (start != NULL && start >= line_start) ? (int)(start - line_start) : -1;
     163   [ +  +  +  - ]:   39430438 :     int end_col_offset = (end != NULL && end >= p->tok->line_start) ? (int)(end - p->tok->line_start) : -1;
     164                 :            : 
     165                 :   39430438 :     token->lineno = lineno;
     166         [ +  + ]:   39430438 :     token->col_offset = p->tok->lineno == p->starting_lineno ? p->starting_col_offset + col_offset : col_offset;
     167                 :   39430438 :     token->end_lineno = end_lineno;
     168         [ +  + ]:   39430438 :     token->end_col_offset = p->tok->lineno == p->starting_lineno ? p->starting_col_offset + end_col_offset : end_col_offset;
     169                 :            : 
     170                 :   39430438 :     p->fill += 1;
     171                 :            : 
     172   [ +  +  +  + ]:   39430438 :     if (token_type == ERRORTOKEN && p->tok->done == E_DECODE) {
     173                 :          7 :         return _Pypegen_raise_decode_error(p);
     174                 :            :     }
     175                 :            : 
     176         [ +  + ]:   39430431 :     return (token_type == ERRORTOKEN ? _Pypegen_tokenizer_error(p) : 0);
     177                 :            : }
     178                 :            : 
     179                 :            : static int
     180                 :     759469 : _resize_tokens_array(Parser *p) {
     181                 :     759469 :     int newsize = p->size * 2;
     182                 :     759469 :     Token **new_tokens = PyMem_Realloc(p->tokens, newsize * sizeof(Token *));
     183         [ -  + ]:     759469 :     if (new_tokens == NULL) {
     184                 :            :         PyErr_NoMemory();
     185                 :          0 :         return -1;
     186                 :            :     }
     187                 :     759469 :     p->tokens = new_tokens;
     188                 :            : 
     189         [ +  + ]:   57267623 :     for (int i = p->size; i < newsize; i++) {
     190                 :   56508154 :         p->tokens[i] = PyMem_Calloc(1, sizeof(Token));
     191         [ -  + ]:   56508154 :         if (p->tokens[i] == NULL) {
     192                 :          0 :             p->size = i; // Needed, in order to cleanup correctly after parser fails
     193                 :            :             PyErr_NoMemory();
     194                 :          0 :             return -1;
     195                 :            :         }
     196                 :            :     }
     197                 :     759469 :     p->size = newsize;
     198                 :     759469 :     return 0;
     199                 :            : }
     200                 :            : 
     201                 :            : int
     202                 :   39430438 : _PyPegen_fill_token(Parser *p)
     203                 :            : {
     204                 :            :     const char *start;
     205                 :            :     const char *end;
     206                 :   39430438 :     int type = _PyTokenizer_Get(p->tok, &start, &end);
     207                 :            : 
     208                 :            :     // Record and skip '# type: ignore' comments
     209         [ +  + ]:   39430512 :     while (type == TYPE_IGNORE) {
     210                 :         74 :         Py_ssize_t len = end - start;
     211                 :         74 :         char *tag = PyMem_Malloc(len + 1);
     212         [ -  + ]:         74 :         if (tag == NULL) {
     213                 :            :             PyErr_NoMemory();
     214                 :          0 :             return -1;
     215                 :            :         }
     216                 :         74 :         strncpy(tag, start, len);
     217                 :         74 :         tag[len] = '\0';
     218                 :            :         // Ownership of tag passes to the growable array
     219         [ -  + ]:         74 :         if (!growable_comment_array_add(&p->type_ignore_comments, p->tok->lineno, tag)) {
     220                 :            :             PyErr_NoMemory();
     221                 :          0 :             return -1;
     222                 :            :         }
     223                 :         74 :         type = _PyTokenizer_Get(p->tok, &start, &end);
     224                 :            :     }
     225                 :            : 
     226                 :            :     // If we have reached the end and we are in single input mode we need to insert a newline and reset the parsing
     227   [ +  +  +  +  :   39430438 :     if (p->start_rule == Py_single_input && type == ENDMARKER && p->parsing_started) {
                   +  + ]
     228                 :        809 :         type = NEWLINE; /* Add an extra newline */
     229                 :        809 :         p->parsing_started = 0;
     230                 :            : 
     231   [ +  +  +  + ]:        809 :         if (p->tok->indent && !(p->flags & PyPARSE_DONT_IMPLY_DEDENT)) {
     232                 :          9 :             p->tok->pendin = -p->tok->indent;
     233                 :          9 :             p->tok->indent = 0;
     234                 :            :         }
     235                 :            :     }
     236                 :            :     else {
     237                 :   39429629 :         p->parsing_started = 1;
     238                 :            :     }
     239                 :            : 
     240                 :            :     // Check if we are at the limit of the token array capacity and resize if needed
     241   [ +  +  -  + ]:   39430438 :     if ((p->fill == p->size) && (_resize_tokens_array(p) != 0)) {
     242                 :          0 :         return -1;
     243                 :            :     }
     244                 :            : 
     245                 :   39430438 :     Token *t = p->tokens[p->fill];
     246                 :   39430438 :     return initialize_token(p, t, start, end, type);
     247                 :            : }
     248                 :            : 
     249                 :            : #if defined(Py_DEBUG)
     250                 :            : // Instrumentation to count the effectiveness of memoization.
     251                 :            : // The array counts the number of tokens skipped by memoization,
     252                 :            : // indexed by type.
     253                 :            : 
     254                 :            : #define NSTATISTICS 2000
     255                 :            : static long memo_statistics[NSTATISTICS];
     256                 :            : 
     257                 :            : void
     258                 :            : _PyPegen_clear_memo_statistics()
     259                 :            : {
     260                 :            :     for (int i = 0; i < NSTATISTICS; i++) {
     261                 :            :         memo_statistics[i] = 0;
     262                 :            :     }
     263                 :            : }
     264                 :            : 
     265                 :            : PyObject *
     266                 :            : _PyPegen_get_memo_statistics()
     267                 :            : {
     268                 :            :     PyObject *ret = PyList_New(NSTATISTICS);
     269                 :            :     if (ret == NULL) {
     270                 :            :         return NULL;
     271                 :            :     }
     272                 :            :     for (int i = 0; i < NSTATISTICS; i++) {
     273                 :            :         PyObject *value = PyLong_FromLong(memo_statistics[i]);
     274                 :            :         if (value == NULL) {
     275                 :            :             Py_DECREF(ret);
     276                 :            :             return NULL;
     277                 :            :         }
     278                 :            :         // PyList_SetItem borrows a reference to value.
     279                 :            :         if (PyList_SetItem(ret, i, value) < 0) {
     280                 :            :             Py_DECREF(ret);
     281                 :            :             return NULL;
     282                 :            :         }
     283                 :            :     }
     284                 :            :     return ret;
     285                 :            : }
     286                 :            : #endif
     287                 :            : 
     288                 :            : int  // bool
     289                 :  746483324 : _PyPegen_is_memoized(Parser *p, int type, void *pres)
     290                 :            : {
     291         [ +  + ]:  746483324 :     if (p->mark == p->fill) {
     292         [ +  + ]:    3633016 :         if (_PyPegen_fill_token(p) < 0) {
     293                 :         40 :             p->error_indicator = 1;
     294                 :         40 :             return -1;
     295                 :            :         }
     296                 :            :     }
     297                 :            : 
     298                 :  746483284 :     Token *t = p->tokens[p->mark];
     299                 :            : 
     300         [ +  + ]: 2308675290 :     for (Memo *m = t->memo; m != NULL; m = m->next) {
     301         [ +  + ]: 2122950555 :         if (m->type == type) {
     302                 :            : #if defined(PY_DEBUG)
     303                 :            :             if (0 <= type && type < NSTATISTICS) {
     304                 :            :                 long count = m->mark - p->mark;
     305                 :            :                 // A memoized negative result counts for one.
     306                 :            :                 if (count <= 0) {
     307                 :            :                     count = 1;
     308                 :            :                 }
     309                 :            :                 memo_statistics[type] += count;
     310                 :            :             }
     311                 :            : #endif
     312                 :  560758549 :             p->mark = m->mark;
     313                 :  560758549 :             *(void **)(pres) = m->node;
     314                 :  560758549 :             return 1;
     315                 :            :         }
     316                 :            :     }
     317                 :  185724735 :     return 0;
     318                 :            : }
     319                 :            : 
     320                 :            : int
     321                 :          1 : _PyPegen_lookahead_with_name(int positive, expr_ty (func)(Parser *), Parser *p)
     322                 :            : {
     323                 :          1 :     int mark = p->mark;
     324                 :          1 :     void *res = func(p);
     325                 :          1 :     p->mark = mark;
     326                 :          1 :     return (res != NULL) == positive;
     327                 :            : }
     328                 :            : 
     329                 :            : int
     330                 :       3700 : _PyPegen_lookahead_with_string(int positive, expr_ty (func)(Parser *, const char*), Parser *p, const char* arg)
     331                 :            : {
     332                 :       3700 :     int mark = p->mark;
     333                 :       3700 :     void *res = func(p, arg);
     334                 :       3700 :     p->mark = mark;
     335                 :       3700 :     return (res != NULL) == positive;
     336                 :            : }
     337                 :            : 
     338                 :            : int
     339                 :   53692642 : _PyPegen_lookahead_with_int(int positive, Token *(func)(Parser *, int), Parser *p, int arg)
     340                 :            : {
     341                 :   53692642 :     int mark = p->mark;
     342                 :   53692642 :     void *res = func(p, arg);
     343                 :   53692642 :     p->mark = mark;
     344                 :   53692642 :     return (res != NULL) == positive;
     345                 :            : }
     346                 :            : 
     347                 :            : int
     348                 :   36472518 : _PyPegen_lookahead(int positive, void *(func)(Parser *), Parser *p)
     349                 :            : {
     350                 :   36472518 :     int mark = p->mark;
     351                 :   36472518 :     void *res = (void*)func(p);
     352                 :   36472518 :     p->mark = mark;
     353                 :   36472518 :     return (res != NULL) == positive;
     354                 :            : }
     355                 :            : 
     356                 :            : Token *
     357                 :  756782594 : _PyPegen_expect_token(Parser *p, int type)
     358                 :            : {
     359         [ +  + ]:  756782594 :     if (p->mark == p->fill) {
     360         [ +  + ]:   26717749 :         if (_PyPegen_fill_token(p) < 0) {
     361                 :        166 :             p->error_indicator = 1;
     362                 :        166 :             return NULL;
     363                 :            :         }
     364                 :            :     }
     365                 :  756782428 :     Token *t = p->tokens[p->mark];
     366         [ +  + ]:  756782428 :     if (t->type != type) {
     367                 :  660052471 :         return NULL;
     368                 :            :     }
     369                 :   96729957 :     p->mark += 1;
     370                 :   96729957 :     return t;
     371                 :            : }
     372                 :            : 
     373                 :            : void*
     374                 :          0 : _PyPegen_expect_forced_result(Parser *p, void* result, const char* expected) {
     375                 :            : 
     376         [ #  # ]:          0 :     if (p->error_indicator == 1) {
     377                 :          0 :         return NULL;
     378                 :            :     }
     379         [ #  # ]:          0 :     if (result == NULL) {
     380                 :          0 :         RAISE_SYNTAX_ERROR("expected (%s)", expected);
     381                 :          0 :         return NULL;
     382                 :            :     }
     383                 :          0 :     return result;
     384                 :            : }
     385                 :            : 
     386                 :            : Token *
     387                 :     847612 : _PyPegen_expect_forced_token(Parser *p, int type, const char* expected) {
     388                 :            : 
     389         [ -  + ]:     847612 :     if (p->error_indicator == 1) {
     390                 :          0 :         return NULL;
     391                 :            :     }
     392                 :            : 
     393         [ +  + ]:     847612 :     if (p->mark == p->fill) {
     394         [ -  + ]:     465257 :         if (_PyPegen_fill_token(p) < 0) {
     395                 :          0 :             p->error_indicator = 1;
     396                 :          0 :             return NULL;
     397                 :            :         }
     398                 :            :     }
     399                 :     847612 :     Token *t = p->tokens[p->mark];
     400         [ +  + ]:     847612 :     if (t->type != type) {
     401                 :         11 :         RAISE_SYNTAX_ERROR_KNOWN_LOCATION(t, "expected '%s'", expected);
     402                 :         11 :         return NULL;
     403                 :            :     }
     404                 :     847601 :     p->mark += 1;
     405                 :     847601 :     return t;
     406                 :            : }
     407                 :            : 
     408                 :            : expr_ty
     409                 :    3003077 : _PyPegen_expect_soft_keyword(Parser *p, const char *keyword)
     410                 :            : {
     411         [ +  + ]:    3003077 :     if (p->mark == p->fill) {
     412         [ -  + ]:       3431 :         if (_PyPegen_fill_token(p) < 0) {
     413                 :          0 :             p->error_indicator = 1;
     414                 :          0 :             return NULL;
     415                 :            :         }
     416                 :            :     }
     417                 :    3003077 :     Token *t = p->tokens[p->mark];
     418         [ +  + ]:    3003077 :     if (t->type != NAME) {
     419                 :    1632139 :         return NULL;
     420                 :            :     }
     421                 :    1370938 :     const char *s = PyBytes_AsString(t->bytes);
     422         [ -  + ]:    1370938 :     if (!s) {
     423                 :          0 :         p->error_indicator = 1;
     424                 :          0 :         return NULL;
     425                 :            :     }
     426         [ +  + ]:    1370938 :     if (strcmp(s, keyword) != 0) {
     427                 :    1366081 :         return NULL;
     428                 :            :     }
     429                 :       4857 :     return _PyPegen_name_token(p);
     430                 :            : }
     431                 :            : 
     432                 :            : Token *
     433                 :   19977442 : _PyPegen_get_last_nonnwhitespace_token(Parser *p)
     434                 :            : {
     435                 :            :     assert(p->mark >= 0);
     436                 :   19977442 :     Token *token = NULL;
     437         [ +  + ]:   22254360 :     for (int m = p->mark - 1; m >= 0; m--) {
     438                 :   22254358 :         token = p->tokens[m];
     439   [ +  -  +  +  :   22254358 :         if (token->type != ENDMARKER && (token->type < NEWLINE || token->type > DEDENT)) {
                   +  + ]
     440                 :            :             break;
     441                 :            :         }
     442                 :            :     }
     443                 :   19977442 :     return token;
     444                 :            : }
     445                 :            : 
     446                 :            : PyObject *
     447                 :   33919542 : _PyPegen_new_identifier(Parser *p, const char *n)
     448                 :            : {
     449                 :   33919542 :     PyObject *id = PyUnicode_DecodeUTF8(n, strlen(n), NULL);
     450         [ -  + ]:   33919542 :     if (!id) {
     451                 :          0 :         goto error;
     452                 :            :     }
     453                 :            :     /* PyUnicode_DecodeUTF8 should always return a ready string. */
     454                 :            :     assert(PyUnicode_IS_READY(id));
     455                 :            :     /* Check whether there are non-ASCII characters in the
     456                 :            :        identifier; if so, normalize to NFKC. */
     457         [ +  + ]:   33919542 :     if (!PyUnicode_IS_ASCII(id))
     458                 :            :     {
     459                 :            :         PyObject *id2;
     460         [ -  + ]:        589 :         if (!init_normalization(p))
     461                 :            :         {
     462                 :          0 :             Py_DECREF(id);
     463                 :          1 :             goto error;
     464                 :            :         }
     465                 :        589 :         PyObject *form = PyUnicode_InternFromString("NFKC");
     466         [ -  + ]:        589 :         if (form == NULL)
     467                 :            :         {
     468                 :          0 :             Py_DECREF(id);
     469                 :          0 :             goto error;
     470                 :            :         }
     471                 :        589 :         PyObject *args[2] = {form, id};
     472                 :        589 :         id2 = _PyObject_FastCall(p->normalize, args, 2);
     473                 :        589 :         Py_DECREF(id);
     474                 :        589 :         Py_DECREF(form);
     475         [ -  + ]:        589 :         if (!id2) {
     476                 :          0 :             goto error;
     477                 :            :         }
     478         [ +  + ]:        589 :         if (!PyUnicode_Check(id2))
     479                 :            :         {
     480                 :          1 :             PyErr_Format(PyExc_TypeError,
     481                 :            :                          "unicodedata.normalize() must return a string, not "
     482                 :            :                          "%.200s",
     483                 :            :                          _PyType_Name(Py_TYPE(id2)));
     484                 :          1 :             Py_DECREF(id2);
     485                 :          1 :             goto error;
     486                 :            :         }
     487                 :        588 :         id = id2;
     488                 :            :     }
     489                 :   33919541 :     PyUnicode_InternInPlace(&id);
     490         [ -  + ]:   33919541 :     if (_PyArena_AddPyObject(p->arena, id) < 0)
     491                 :            :     {
     492                 :          0 :         Py_DECREF(id);
     493                 :          0 :         goto error;
     494                 :            :     }
     495                 :   33919541 :     return id;
     496                 :            : 
     497                 :          1 : error:
     498                 :          1 :     p->error_indicator = 1;
     499                 :          1 :     return NULL;
     500                 :            : }
     501                 :            : 
     502                 :            : static expr_ty
     503                 :   68829944 : _PyPegen_name_from_token(Parser *p, Token* t)
     504                 :            : {
     505         [ +  + ]:   68829944 :     if (t == NULL) {
     506                 :   34914042 :         return NULL;
     507                 :            :     }
     508                 :   33915902 :     const char *s = PyBytes_AsString(t->bytes);
     509         [ -  + ]:   33915902 :     if (!s) {
     510                 :          0 :         p->error_indicator = 1;
     511                 :          0 :         return NULL;
     512                 :            :     }
     513                 :   33915902 :     PyObject *id = _PyPegen_new_identifier(p, s);
     514         [ +  + ]:   33915902 :     if (id == NULL) {
     515                 :          1 :         p->error_indicator = 1;
     516                 :          1 :         return NULL;
     517                 :            :     }
     518                 :   33915901 :     return _PyAST_Name(id, Load, t->lineno, t->col_offset, t->end_lineno,
     519                 :            :                        t->end_col_offset, p->arena);
     520                 :            : }
     521                 :            : 
     522                 :            : expr_ty
     523                 :   68829913 : _PyPegen_name_token(Parser *p)
     524                 :            : {
     525                 :   68829913 :     Token *t = _PyPegen_expect_token(p, NAME);
     526                 :   68829913 :     return _PyPegen_name_from_token(p, t);
     527                 :            : }
     528                 :            : 
     529                 :            : void *
     530                 :   17650755 : _PyPegen_string_token(Parser *p)
     531                 :            : {
     532                 :   17650755 :     return _PyPegen_expect_token(p, STRING);
     533                 :            : }
     534                 :            : 
     535                 :       2643 : expr_ty _PyPegen_soft_keyword_token(Parser *p) {
     536                 :       2643 :     Token *t = _PyPegen_expect_token(p, NAME);
     537         [ +  + ]:       2643 :     if (t == NULL) {
     538                 :       2002 :         return NULL;
     539                 :            :     }
     540                 :            :     char *the_token;
     541                 :            :     Py_ssize_t size;
     542                 :        641 :     PyBytes_AsStringAndSize(t->bytes, &the_token, &size);
     543         [ +  + ]:       2512 :     for (char **keyword = p->soft_keywords; *keyword != NULL; keyword++) {
     544         [ +  + ]:       1902 :         if (strncmp(*keyword, the_token, size) == 0) {
     545                 :         31 :             return _PyPegen_name_from_token(p, t);
     546                 :            :         }
     547                 :            :     }
     548                 :        610 :     return NULL;
     549                 :            : }
     550                 :            : 
     551                 :            : static PyObject *
     552                 :    5873696 : parsenumber_raw(const char *s)
     553                 :            : {
     554                 :            :     const char *end;
     555                 :            :     long x;
     556                 :            :     double dx;
     557                 :            :     Py_complex compl;
     558                 :            :     int imflag;
     559                 :            : 
     560                 :            :     assert(s != NULL);
     561                 :    5873696 :     errno = 0;
     562                 :    5873696 :     end = s + strlen(s) - 1;
     563   [ +  +  -  + ]:    5873696 :     imflag = *end == 'j' || *end == 'J';
     564         [ +  + ]:    5873696 :     if (s[0] == '0') {
     565                 :    1813334 :         x = (long)PyOS_strtoul(s, (char **)&end, 0);
     566   [ +  +  +  + ]:    1813334 :         if (x < 0 && errno == 0) {
     567                 :        279 :             return PyLong_FromString(s, (char **)0, 0);
     568                 :            :         }
     569                 :            :     }
     570                 :            :     else {
     571                 :    4060362 :         x = PyOS_strtol(s, (char **)&end, 0);
     572                 :            :     }
     573         [ +  + ]:    5873417 :     if (*end == '\0') {
     574         [ +  + ]:    5811636 :         if (errno != 0) {
     575                 :        892 :             return PyLong_FromString(s, (char **)0, 0);
     576                 :            :         }
     577                 :    5810744 :         return PyLong_FromLong(x);
     578                 :            :     }
     579                 :            :     /* XXX Huge floats may silently fail */
     580         [ +  + ]:      61781 :     if (imflag) {
     581                 :       4264 :         compl.real = 0.;
     582                 :       4264 :         compl.imag = PyOS_string_to_double(s, (char **)&end, NULL);
     583   [ -  +  -  - ]:       4264 :         if (compl.imag == -1.0 && PyErr_Occurred()) {
     584                 :          0 :             return NULL;
     585                 :            :         }
     586                 :       4264 :         return PyComplex_FromCComplex(compl);
     587                 :            :     }
     588                 :      57517 :     dx = PyOS_string_to_double(s, NULL, NULL);
     589   [ -  +  -  - ]:      57517 :     if (dx == -1.0 && PyErr_Occurred()) {
     590                 :          0 :         return NULL;
     591                 :            :     }
     592                 :      57517 :     return PyFloat_FromDouble(dx);
     593                 :            : }
     594                 :            : 
     595                 :            : static PyObject *
     596                 :    5873696 : parsenumber(const char *s)
     597                 :            : {
     598                 :            :     char *dup;
     599                 :            :     char *end;
     600                 :    5873696 :     PyObject *res = NULL;
     601                 :            : 
     602                 :            :     assert(s != NULL);
     603                 :            : 
     604         [ +  + ]:    5873696 :     if (strchr(s, '_') == NULL) {
     605                 :    5871879 :         return parsenumber_raw(s);
     606                 :            :     }
     607                 :            :     /* Create a duplicate without underscores. */
     608                 :       1817 :     dup = PyMem_Malloc(strlen(s) + 1);
     609         [ -  + ]:       1817 :     if (dup == NULL) {
     610                 :            :         return PyErr_NoMemory();
     611                 :            :     }
     612                 :       1817 :     end = dup;
     613         [ +  + ]:      39769 :     for (; *s; s++) {
     614         [ +  + ]:      37952 :         if (*s != '_') {
     615                 :      33546 :             *end++ = *s;
     616                 :            :         }
     617                 :            :     }
     618                 :       1817 :     *end = '\0';
     619                 :       1817 :     res = parsenumber_raw(dup);
     620                 :       1817 :     PyMem_Free(dup);
     621                 :       1817 :     return res;
     622                 :            : }
     623                 :            : 
     624                 :            : expr_ty
     625                 :   10965494 : _PyPegen_number_token(Parser *p)
     626                 :            : {
     627                 :   10965494 :     Token *t = _PyPegen_expect_token(p, NUMBER);
     628         [ +  + ]:   10965494 :     if (t == NULL) {
     629                 :    5091796 :         return NULL;
     630                 :            :     }
     631                 :            : 
     632                 :    5873698 :     const char *num_raw = PyBytes_AsString(t->bytes);
     633         [ -  + ]:    5873698 :     if (num_raw == NULL) {
     634                 :          0 :         p->error_indicator = 1;
     635                 :          0 :         return NULL;
     636                 :            :     }
     637                 :            : 
     638   [ +  +  +  + ]:    5873698 :     if (p->feature_version < 6 && strchr(num_raw, '_') != NULL) {
     639                 :          2 :         p->error_indicator = 1;
     640                 :          2 :         return RAISE_SYNTAX_ERROR("Underscores in numeric literals are only supported "
     641                 :            :                                   "in Python 3.6 and greater");
     642                 :            :     }
     643                 :            : 
     644                 :    5873696 :     PyObject *c = parsenumber(num_raw);
     645                 :            : 
     646         [ -  + ]:    5873696 :     if (c == NULL) {
     647                 :          0 :         p->error_indicator = 1;
     648                 :          0 :         return NULL;
     649                 :            :     }
     650                 :            : 
     651         [ -  + ]:    5873696 :     if (_PyArena_AddPyObject(p->arena, c) < 0) {
     652                 :          0 :         Py_DECREF(c);
     653                 :          0 :         p->error_indicator = 1;
     654                 :          0 :         return NULL;
     655                 :            :     }
     656                 :            : 
     657                 :    5873696 :     return _PyAST_Constant(c, NULL, t->lineno, t->col_offset, t->end_lineno,
     658                 :            :                            t->end_col_offset, p->arena);
     659                 :            : }
     660                 :            : 
     661                 :            : /* Check that the source for a single input statement really is a single
     662                 :            :    statement by looking at what is left in the buffer after parsing.
     663                 :            :    Trailing whitespace and comments are OK. */
     664                 :            : static int // bool
     665                 :       4160 : bad_single_statement(Parser *p)
     666                 :            : {
     667                 :       4160 :     char *cur = p->tok->cur;
     668                 :       4160 :     char c = *cur;
     669                 :            : 
     670                 :            :     for (;;) {
     671   [ +  +  -  +  :       4346 :         while (c == ' ' || c == '\t' || c == '\n' || c == '\014') {
             +  +  -  + ]
     672                 :        119 :             c = *++cur;
     673                 :            :         }
     674                 :            : 
     675         [ +  + ]:       4227 :         if (!c) {
     676                 :       4152 :             return 0;
     677                 :            :         }
     678                 :            : 
     679         [ +  + ]:         75 :         if (c != '#') {
     680                 :          8 :             return 1;
     681                 :            :         }
     682                 :            : 
     683                 :            :         /* Suck up comment. */
     684   [ +  -  +  + ]:       1551 :         while (c && c != '\n') {
     685                 :       1484 :             c = *++cur;
     686                 :            :         }
     687                 :            :     }
     688                 :            : }
     689                 :            : 
     690                 :            : static int
     691                 :     126156 : compute_parser_flags(PyCompilerFlags *flags)
     692                 :            : {
     693                 :     126156 :     int parser_flags = 0;
     694         [ +  + ]:     126156 :     if (!flags) {
     695                 :        181 :         return 0;
     696                 :            :     }
     697         [ +  + ]:     125975 :     if (flags->cf_flags & PyCF_DONT_IMPLY_DEDENT) {
     698                 :        359 :         parser_flags |= PyPARSE_DONT_IMPLY_DEDENT;
     699                 :            :     }
     700         [ +  + ]:     125975 :     if (flags->cf_flags & PyCF_IGNORE_COOKIE) {
     701                 :     113448 :         parser_flags |= PyPARSE_IGNORE_COOKIE;
     702                 :            :     }
     703         [ +  + ]:     125975 :     if (flags->cf_flags & CO_FUTURE_BARRY_AS_BDFL) {
     704                 :          3 :         parser_flags |= PyPARSE_BARRY_AS_BDFL;
     705                 :            :     }
     706         [ +  + ]:     125975 :     if (flags->cf_flags & PyCF_TYPE_COMMENTS) {
     707                 :        250 :         parser_flags |= PyPARSE_TYPE_COMMENTS;
     708                 :            :     }
     709   [ +  +  +  + ]:     125975 :     if ((flags->cf_flags & PyCF_ONLY_AST) && flags->cf_feature_version < 7) {
     710                 :         69 :         parser_flags |= PyPARSE_ASYNC_HACKS;
     711                 :            :     }
     712         [ +  + ]:     125975 :     if (flags->cf_flags & PyCF_ALLOW_INCOMPLETE_INPUT) {
     713                 :        320 :         parser_flags |= PyPARSE_ALLOW_INCOMPLETE_INPUT;
     714                 :            :     }
     715                 :     125975 :     return parser_flags;
     716                 :            : }
     717                 :            : 
     718                 :            : // Parser API
     719                 :            : 
     720                 :            : Parser *
     721                 :     222224 : _PyPegen_Parser_New(struct tok_state *tok, int start_rule, int flags,
     722                 :            :                     int feature_version, int *errcode, PyArena *arena)
     723                 :            : {
     724                 :     222224 :     Parser *p = PyMem_Malloc(sizeof(Parser));
     725         [ -  + ]:     222224 :     if (p == NULL) {
     726                 :            :         return (Parser *) PyErr_NoMemory();
     727                 :            :     }
     728                 :            :     assert(tok != NULL);
     729                 :     222224 :     tok->type_comments = (flags & PyPARSE_TYPE_COMMENTS) > 0;
     730                 :     222224 :     tok->async_hacks = (flags & PyPARSE_ASYNC_HACKS) > 0;
     731                 :     222224 :     p->tok = tok;
     732                 :     222224 :     p->keywords = NULL;
     733                 :     222224 :     p->n_keyword_lists = -1;
     734                 :     222224 :     p->soft_keywords = NULL;
     735                 :     222224 :     p->tokens = PyMem_Malloc(sizeof(Token *));
     736         [ -  + ]:     222224 :     if (!p->tokens) {
     737                 :          0 :         PyMem_Free(p);
     738                 :            :         return (Parser *) PyErr_NoMemory();
     739                 :            :     }
     740                 :     222224 :     p->tokens[0] = PyMem_Calloc(1, sizeof(Token));
     741         [ -  + ]:     222224 :     if (!p->tokens) {
     742                 :          0 :         PyMem_Free(p->tokens);
     743                 :          0 :         PyMem_Free(p);
     744                 :            :         return (Parser *) PyErr_NoMemory();
     745                 :            :     }
     746         [ -  + ]:     222224 :     if (!growable_comment_array_init(&p->type_ignore_comments, 10)) {
     747                 :          0 :         PyMem_Free(p->tokens[0]);
     748                 :          0 :         PyMem_Free(p->tokens);
     749                 :          0 :         PyMem_Free(p);
     750                 :            :         return (Parser *) PyErr_NoMemory();
     751                 :            :     }
     752                 :            : 
     753                 :     222224 :     p->mark = 0;
     754                 :     222224 :     p->fill = 0;
     755                 :     222224 :     p->size = 1;
     756                 :            : 
     757                 :     222224 :     p->errcode = errcode;
     758                 :     222224 :     p->arena = arena;
     759                 :     222224 :     p->start_rule = start_rule;
     760                 :     222224 :     p->parsing_started = 0;
     761                 :     222224 :     p->normalize = NULL;
     762                 :     222224 :     p->error_indicator = 0;
     763                 :            : 
     764                 :     222224 :     p->starting_lineno = 0;
     765                 :     222224 :     p->starting_col_offset = 0;
     766                 :     222224 :     p->flags = flags;
     767                 :     222224 :     p->feature_version = feature_version;
     768                 :     222224 :     p->known_err_token = NULL;
     769                 :     222224 :     p->level = 0;
     770                 :     222224 :     p->call_invalid_rules = 0;
     771                 :            : #ifdef Py_DEBUG
     772                 :            :     p->debug = _Py_GetConfig()->parser_debug;
     773                 :            : #endif
     774                 :     222224 :     return p;
     775                 :            : }
     776                 :            : 
     777                 :            : void
     778                 :     222224 : _PyPegen_Parser_Free(Parser *p)
     779                 :            : {
     780                 :     222224 :     Py_XDECREF(p->normalize);
     781         [ +  + ]:   56952602 :     for (int i = 0; i < p->size; i++) {
     782                 :   56730378 :         PyMem_Free(p->tokens[i]);
     783                 :            :     }
     784                 :     222224 :     PyMem_Free(p->tokens);
     785                 :     222224 :     growable_comment_array_deallocate(&p->type_ignore_comments);
     786                 :     222224 :     PyMem_Free(p);
     787                 :     222224 : }
     788                 :            : 
     789                 :            : static void
     790                 :       2002 : reset_parser_state_for_error_pass(Parser *p)
     791                 :            : {
     792         [ +  + ]:      10547 :     for (int i = 0; i < p->fill; i++) {
     793                 :       8545 :         p->tokens[i]->memo = NULL;
     794                 :            :     }
     795                 :       2002 :     p->mark = 0;
     796                 :       2002 :     p->call_invalid_rules = 1;
     797                 :            :     // Don't try to get extra tokens in interactive mode when trying to
     798                 :            :     // raise specialized errors in the second pass.
     799                 :       2002 :     p->tok->interactive_underflow = IUNDERFLOW_STOP;
     800                 :       2002 : }
     801                 :            : 
     802                 :            : static inline int
     803                 :        262 : _is_end_of_source(Parser *p) {
     804                 :        262 :     int err = p->tok->done;
     805   [ +  +  +  +  :        262 :     return err == E_EOF || err == E_EOFS || err == E_EOLS;
                   +  + ]
     806                 :            : }
     807                 :            : 
     808                 :            : void *
     809                 :     222224 : _PyPegen_run_parser(Parser *p)
     810                 :            : {
     811                 :     222224 :     void *res = _PyPegen_parse(p);
     812                 :            :     assert(p->level == 0);
     813         [ +  + ]:     222224 :     if (res == NULL) {
     814   [ +  +  +  + ]:       2219 :         if ((p->flags & PyPARSE_ALLOW_INCOMPLETE_INPUT) &&  _is_end_of_source(p)) {
     815                 :        213 :             PyErr_Clear();
     816                 :        213 :             return RAISE_SYNTAX_ERROR("incomplete input");
     817                 :            :         }
     818   [ +  +  +  + ]:       2006 :         if (PyErr_Occurred() && !PyErr_ExceptionMatches(PyExc_SyntaxError)) {
     819                 :          4 :             return NULL;
     820                 :            :         }
     821                 :            :        // Make a second parser pass. In this pass we activate heavier and slower checks
     822                 :            :         // to produce better error messages and more complete diagnostics. Extra "invalid_*"
     823                 :            :         // rules will be active during parsing.
     824                 :       2002 :         Token *last_token = p->tokens[p->fill - 1];
     825                 :       2002 :         reset_parser_state_for_error_pass(p);
     826                 :       2002 :         _PyPegen_parse(p);
     827                 :            : 
     828                 :            :         // Set SyntaxErrors accordingly depending on the parser/tokenizer status at the failure
     829                 :            :         // point.
     830                 :       2002 :         _Pypegen_set_syntax_error(p, last_token);
     831                 :       2002 :        return NULL;
     832                 :            :     }
     833                 :            : 
     834   [ +  +  +  + ]:     220005 :     if (p->start_rule == Py_single_input && bad_single_statement(p)) {
     835                 :          8 :         p->tok->done = E_BADSINGLE; // This is not necessary for now, but might be in the future
     836                 :          8 :         return RAISE_SYNTAX_ERROR("multiple statements found while compiling a single statement");
     837                 :            :     }
     838                 :            : 
     839                 :            :     // test_peg_generator defines _Py_TEST_PEGEN to not call PyAST_Validate()
     840                 :            : #if defined(Py_DEBUG) && !defined(_Py_TEST_PEGEN)
     841                 :            :     if (p->start_rule == Py_single_input ||
     842                 :            :         p->start_rule == Py_file_input ||
     843                 :            :         p->start_rule == Py_eval_input)
     844                 :            :     {
     845                 :            :         if (!_PyAST_Validate(res)) {
     846                 :            :             return NULL;
     847                 :            :         }
     848                 :            :     }
     849                 :            : #endif
     850                 :     219997 :     return res;
     851                 :            : }
     852                 :            : 
     853                 :            : mod_ty
     854                 :        358 : _PyPegen_run_parser_from_file_pointer(FILE *fp, int start_rule, PyObject *filename_ob,
     855                 :            :                              const char *enc, const char *ps1, const char *ps2,
     856                 :            :                              PyCompilerFlags *flags, int *errcode, PyArena *arena)
     857                 :            : {
     858                 :        358 :     struct tok_state *tok = _PyTokenizer_FromFile(fp, enc, ps1, ps2);
     859         [ -  + ]:        358 :     if (tok == NULL) {
     860         [ #  # ]:          0 :         if (PyErr_Occurred()) {
     861                 :          0 :             _PyPegen_raise_tokenizer_init_error(filename_ob);
     862                 :          0 :             return NULL;
     863                 :            :         }
     864                 :          0 :         return NULL;
     865                 :            :     }
     866   [ +  -  +  +  :        686 :     if (!tok->fp || ps1 != NULL || ps2 != NULL ||
             +  -  +  + ]
     867                 :        328 :         PyUnicode_CompareWithASCIIString(filename_ob, "<stdin>") == 0) {
     868                 :         43 :         tok->fp_interactive = 1;
     869                 :            :     }
     870                 :            :     // This transfers the ownership to the tokenizer
     871                 :        358 :     tok->filename = filename_ob;
     872                 :        358 :     Py_INCREF(filename_ob);
     873                 :            : 
     874                 :            :     // From here on we need to clean up even if there's an error
     875                 :        358 :     mod_ty result = NULL;
     876                 :            : 
     877                 :        358 :     int parser_flags = compute_parser_flags(flags);
     878                 :        358 :     Parser *p = _PyPegen_Parser_New(tok, start_rule, parser_flags, PY_MINOR_VERSION,
     879                 :            :                                     errcode, arena);
     880         [ -  + ]:        358 :     if (p == NULL) {
     881                 :          0 :         goto error;
     882                 :            :     }
     883                 :            : 
     884                 :        358 :     result = _PyPegen_run_parser(p);
     885                 :        358 :     _PyPegen_Parser_Free(p);
     886                 :            : 
     887                 :        358 : error:
     888                 :        358 :     _PyTokenizer_Free(tok);
     889                 :        358 :     return result;
     890                 :            : }
     891                 :            : 
     892                 :            : mod_ty
     893                 :     125824 : _PyPegen_run_parser_from_string(const char *str, int start_rule, PyObject *filename_ob,
     894                 :            :                        PyCompilerFlags *flags, PyArena *arena)
     895                 :            : {
     896                 :     125824 :     int exec_input = start_rule == Py_file_input;
     897                 :            : 
     898                 :            :     struct tok_state *tok;
     899   [ +  +  +  + ]:     125824 :     if (flags != NULL && flags->cf_flags & PyCF_IGNORE_COOKIE) {
     900                 :     113448 :         tok = _PyTokenizer_FromUTF8(str, exec_input);
     901                 :            :     } else {
     902                 :      12376 :         tok = _PyTokenizer_FromString(str, exec_input);
     903                 :            :     }
     904         [ +  + ]:     125824 :     if (tok == NULL) {
     905         [ +  - ]:         26 :         if (PyErr_Occurred()) {
     906                 :         26 :             _PyPegen_raise_tokenizer_init_error(filename_ob);
     907                 :            :         }
     908                 :         26 :         return NULL;
     909                 :            :     }
     910                 :            :     // This transfers the ownership to the tokenizer
     911                 :     125798 :     tok->filename = filename_ob;
     912                 :     125798 :     Py_INCREF(filename_ob);
     913                 :            : 
     914                 :            :     // We need to clear up from here on
     915                 :     125798 :     mod_ty result = NULL;
     916                 :            : 
     917                 :     125798 :     int parser_flags = compute_parser_flags(flags);
     918         [ +  + ]:     125617 :     int feature_version = flags && (flags->cf_flags & PyCF_ONLY_AST) ?
     919         [ +  + ]:     251415 :         flags->cf_feature_version : PY_MINOR_VERSION;
     920                 :     125798 :     Parser *p = _PyPegen_Parser_New(tok, start_rule, parser_flags, feature_version,
     921                 :            :                                     NULL, arena);
     922         [ -  + ]:     125798 :     if (p == NULL) {
     923                 :          0 :         goto error;
     924                 :            :     }
     925                 :            : 
     926                 :     125798 :     result = _PyPegen_run_parser(p);
     927                 :     125798 :     _PyPegen_Parser_Free(p);
     928                 :            : 
     929                 :     125798 : error:
     930                 :     125798 :     _PyTokenizer_Free(tok);
     931                 :     125798 :     return result;
     932                 :            : }

Generated by: LCOV version 1.14