LCOV - code coverage report
Current view: | top level - Parser - pegen.c (source / functions) |  |  | Hit | Total | Coverage
Test: | CPython 3.12 LCOV report [commit 5e6661bce9] |  | Lines: | 290 | 485 | 59.8 %
Date: | 2023-03-20 08:15:36 |  | Functions: | 30 | 39 | 76.9 %
|  |  | Branches: | 149 | 288 | 51.7 %

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

Generated by: LCOV version 1.14