LCOV - code coverage report
Current view: top level - Parser - pegen.c (source / functions) Hit Total Coverage
Test: CPython lcov report Lines: 425 514 82.7 %
Date: 2022-07-07 18:19:46 Functions: 38 41 92.7 %

          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        3963 : _PyPegen_byte_offset_to_character_offset(PyObject *line, Py_ssize_t col_offset)
      21             : {
      22        3963 :     const char *str = PyUnicode_AsUTF8(line);
      23        3963 :     if (!str) {
      24           0 :         return -1;
      25             :     }
      26        3963 :     Py_ssize_t len = strlen(str);
      27        3963 :     if (col_offset > len + 1) {
      28          10 :         col_offset = len + 1;
      29             :     }
      30        3963 :     assert(col_offset >= 0);
      31        3963 :     PyObject *text = PyUnicode_DecodeUTF8(str, col_offset, "replace");
      32        3963 :     if (!text) {
      33           0 :         return -1;
      34             :     }
      35        3963 :     Py_ssize_t size = PyUnicode_GET_LENGTH(text);
      36        3963 :     Py_DECREF(text);
      37        3963 :     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   195276000 : _PyPegen_insert_memo(Parser *p, int mark, int type, void *node)
      44             : {
      45             :     // Insert in front
      46   195276000 :     Memo *m = _PyArena_Malloc(p->arena, sizeof(Memo));
      47   195276000 :     if (m == NULL) {
      48           0 :         return -1;
      49             :     }
      50   195276000 :     m->type = type;
      51   195276000 :     m->node = node;
      52   195276000 :     m->mark = p->mark;
      53   195276000 :     m->next = p->tokens[mark]->memo;
      54   195276000 :     p->tokens[mark]->memo = m;
      55   195276000 :     return 0;
      56             : }
      57             : 
      58             : // Like _PyPegen_insert_memo(), but updates an existing node if found.
      59             : int
      60   171061000 : _PyPegen_update_memo(Parser *p, int mark, int type, void *node)
      61             : {
      62   856401000 :     for (Memo *m = p->tokens[mark]->memo; m != NULL; m = m->next) {
      63   764557000 :         if (m->type == type) {
      64             :             // Update existing node.
      65    79216800 :             m->node = node;
      66    79216800 :             m->mark = p->mark;
      67    79216800 :             return 0;
      68             :         }
      69             :     }
      70             :     // Insert new node.
      71    91843900 :     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      223947 : growable_comment_array_init(growable_comment_array *arr, size_t initial_size) {
      90      223947 :     assert(initial_size > 0);
      91      223947 :     arr->items = PyMem_Malloc(initial_size * sizeof(*arr->items));
      92      223947 :     arr->size = initial_size;
      93      223947 :     arr->num_items = 0;
      94             : 
      95      223947 :     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      223947 : growable_comment_array_deallocate(growable_comment_array *arr) {
     118      224021 :     for (unsigned i = 0; i < arr->num_items; i++) {
     119          74 :         PyMem_Free(arr->items[i].comment);
     120             :     }
     121      223947 :     PyMem_Free(arr->items);
     122      223947 : }
     123             : 
     124             : static int
     125    12437000 : _get_keyword_or_name_type(Parser *p, const char *name, int name_len)
     126             : {
     127    12437000 :     assert(name_len > 0);
     128    12437000 :     if (name_len >= p->n_keyword_lists ||
     129    10186300 :         p->keywords[name_len] == NULL ||
     130    10186300 :         p->keywords[name_len]->type == -1) {
     131     3946410 :         return NAME;
     132             :     }
     133    45341500 :     for (KeywordToken *k = p->keywords[name_len]; k != NULL && k->type != -1; k++) {
     134    39354900 :         if (strncmp(k->str, name, name_len) == 0) {
     135     2504030 :             return k->type;
     136             :         }
     137             :     }
     138     5986600 :     return NAME;
     139             : }
     140             : 
     141             : static int
     142    39577500 : initialize_token(Parser *p, Token *token, const char *start, const char *end, int token_type) {
     143    39577500 :     assert(token != NULL);
     144             : 
     145    39577500 :     token->type = (token_type == NAME) ? _get_keyword_or_name_type(p, start, (int)(end - start)) : token_type;
     146    39577500 :     token->bytes = PyBytes_FromStringAndSize(start, end - start);
     147    39577500 :     if (token->bytes == NULL) {
     148           0 :         return -1;
     149             :     }
     150             : 
     151    39577500 :     if (_PyArena_AddPyObject(p->arena, token->bytes) < 0) {
     152           0 :         Py_DECREF(token->bytes);
     153           0 :         return -1;
     154             :     }
     155             : 
     156    39577500 :     token->level = p->tok->level;
     157             : 
     158    39577500 :     const char *line_start = token_type == STRING ? p->tok->multi_line_start : p->tok->line_start;
     159    39577500 :     int lineno = token_type == STRING ? p->tok->first_lineno : p->tok->lineno;
     160    39577500 :     int end_lineno = p->tok->lineno;
     161             : 
     162    39577500 :     int col_offset = (start != NULL && start >= line_start) ? (int)(start - line_start) : -1;
     163    39577500 :     int end_col_offset = (end != NULL && end >= p->tok->line_start) ? (int)(end - p->tok->line_start) : -1;
     164             : 
     165    39577500 :     token->lineno = lineno;
     166    39577500 :     token->col_offset = p->tok->lineno == p->starting_lineno ? p->starting_col_offset + col_offset : col_offset;
     167    39577500 :     token->end_lineno = end_lineno;
     168    39577500 :     token->end_col_offset = p->tok->lineno == p->starting_lineno ? p->starting_col_offset + end_col_offset : end_col_offset;
     169             : 
     170    39577500 :     p->fill += 1;
     171             : 
     172    39577500 :     if (token_type == ERRORTOKEN && p->tok->done == E_DECODE) {
     173           7 :         return _Pypegen_raise_decode_error(p);
     174             :     }
     175             : 
     176    39577500 :     return (token_type == ERRORTOKEN ? _Pypegen_tokenizer_error(p) : 0);
     177             : }
     178             : 
     179             : static int
     180      763916 : _resize_tokens_array(Parser *p) {
     181      763916 :     int newsize = p->size * 2;
     182      763916 :     Token **new_tokens = PyMem_Realloc(p->tokens, newsize * sizeof(Token *));
     183      763916 :     if (new_tokens == NULL) {
     184           0 :         PyErr_NoMemory();
     185           0 :         return -1;
     186             :     }
     187      763916 :     p->tokens = new_tokens;
     188             : 
     189    57520500 :     for (int i = p->size; i < newsize; i++) {
     190    56756600 :         p->tokens[i] = PyMem_Calloc(1, sizeof(Token));
     191    56756600 :         if (p->tokens[i] == NULL) {
     192           0 :             p->size = i; // Needed, in order to cleanup correctly after parser fails
     193           0 :             PyErr_NoMemory();
     194           0 :             return -1;
     195             :         }
     196             :     }
     197      763916 :     p->size = newsize;
     198      763916 :     return 0;
     199             : }
     200             : 
     201             : int
     202    39577500 : _PyPegen_fill_token(Parser *p)
     203             : {
     204             :     const char *start;
     205             :     const char *end;
     206    39577500 :     int type = _PyTokenizer_Get(p->tok, &start, &end);
     207             : 
     208             :     // Record and skip '# type: ignore' comments
     209    39577600 :     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           0 :             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           0 :             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    39577500 :     if (p->start_rule == Py_single_input && type == ENDMARKER && p->parsing_started) {
     228         812 :         type = NEWLINE; /* Add an extra newline */
     229         812 :         p->parsing_started = 0;
     230             : 
     231         812 :         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    39576700 :         p->parsing_started = 1;
     238             :     }
     239             : 
     240             :     // Check if we are at the limit of the token array capacity and resize if needed
     241    39577500 :     if ((p->fill == p->size) && (_resize_tokens_array(p) != 0)) {
     242           0 :         return -1;
     243             :     }
     244             : 
     245    39577500 :     Token *t = p->tokens[p->fill];
     246    39577500 :     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           0 : _PyPegen_clear_memo_statistics()
     259             : {
     260           0 :     for (int i = 0; i < NSTATISTICS; i++) {
     261           0 :         memo_statistics[i] = 0;
     262             :     }
     263           0 : }
     264             : 
     265             : PyObject *
     266           0 : _PyPegen_get_memo_statistics()
     267             : {
     268           0 :     PyObject *ret = PyList_New(NSTATISTICS);
     269           0 :     if (ret == NULL) {
     270           0 :         return NULL;
     271             :     }
     272           0 :     for (int i = 0; i < NSTATISTICS; i++) {
     273           0 :         PyObject *value = PyLong_FromLong(memo_statistics[i]);
     274           0 :         if (value == NULL) {
     275           0 :             Py_DECREF(ret);
     276           0 :             return NULL;
     277             :         }
     278             :         // PyList_SetItem borrows a reference to value.
     279           0 :         if (PyList_SetItem(ret, i, value) < 0) {
     280           0 :             Py_DECREF(ret);
     281           0 :             return NULL;
     282             :         }
     283             :     }
     284           0 :     return ret;
     285             : }
     286             : #endif
     287             : 
     288             : int  // bool
     289   749151000 : _PyPegen_is_memoized(Parser *p, int type, void *pres)
     290             : {
     291   749151000 :     if (p->mark == p->fill) {
     292     3642320 :         if (_PyPegen_fill_token(p) < 0) {
     293          40 :             p->error_indicator = 1;
     294          40 :             return -1;
     295             :         }
     296             :     }
     297             : 
     298   749151000 :     Token *t = p->tokens[p->mark];
     299             : 
     300  2316980000 :     for (Memo *m = t->memo; m != NULL; m = m->next) {
     301  2130550000 :         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   562715000 :             p->mark = m->mark;
     313   562715000 :             *(void **)(pres) = m->node;
     314   562715000 :             return 1;
     315             :         }
     316             :     }
     317   186436000 :     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        3682 : _PyPegen_lookahead_with_string(int positive, expr_ty (func)(Parser *, const char*), Parser *p, const char* arg)
     331             : {
     332        3682 :     int mark = p->mark;
     333        3682 :     void *res = func(p, arg);
     334        3682 :     p->mark = mark;
     335        3682 :     return (res != NULL) == positive;
     336             : }
     337             : 
     338             : int
     339    53979700 : _PyPegen_lookahead_with_int(int positive, Token *(func)(Parser *, int), Parser *p, int arg)
     340             : {
     341    53979700 :     int mark = p->mark;
     342    53979700 :     void *res = func(p, arg);
     343    53979700 :     p->mark = mark;
     344    53979700 :     return (res != NULL) == positive;
     345             : }
     346             : 
     347             : int
     348    36644100 : _PyPegen_lookahead(int positive, void *(func)(Parser *), Parser *p)
     349             : {
     350    36644100 :     int mark = p->mark;
     351    36644100 :     void *res = (void*)func(p);
     352    36644100 :     p->mark = mark;
     353    36644100 :     return (res != NULL) == positive;
     354             : }
     355             : 
     356             : Token *
     357   759672000 : _PyPegen_expect_token(Parser *p, int type)
     358             : {
     359   759672000 :     if (p->mark == p->fill) {
     360    26819300 :         if (_PyPegen_fill_token(p) < 0) {
     361         166 :             p->error_indicator = 1;
     362         166 :             return NULL;
     363             :         }
     364             :     }
     365   759672000 :     Token *t = p->tokens[p->mark];
     366   759672000 :     if (t->type != type) {
     367   662567000 :         return NULL;
     368             :     }
     369    97105000 :     p->mark += 1;
     370    97105000 :     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      853883 : _PyPegen_expect_forced_token(Parser *p, int type, const char* expected) {
     388             : 
     389      853883 :     if (p->error_indicator == 1) {
     390           0 :         return NULL;
     391             :     }
     392             : 
     393      853883 :     if (p->mark == p->fill) {
     394      468732 :         if (_PyPegen_fill_token(p) < 0) {
     395           0 :             p->error_indicator = 1;
     396           0 :             return NULL;
     397             :         }
     398             :     }
     399      853883 :     Token *t = p->tokens[p->mark];
     400      853883 :     if (t->type != type) {
     401          11 :         RAISE_SYNTAX_ERROR_KNOWN_LOCATION(t, "expected '%s'", expected);
     402          11 :         return NULL;
     403             :     }
     404      853872 :     p->mark += 1;
     405      853872 :     return t;
     406             : }
     407             : 
     408             : expr_ty
     409     3022660 : _PyPegen_expect_soft_keyword(Parser *p, const char *keyword)
     410             : {
     411     3022660 :     if (p->mark == p->fill) {
     412        3416 :         if (_PyPegen_fill_token(p) < 0) {
     413           0 :             p->error_indicator = 1;
     414           0 :             return NULL;
     415             :         }
     416             :     }
     417     3022660 :     Token *t = p->tokens[p->mark];
     418     3022660 :     if (t->type != NAME) {
     419     1645110 :         return NULL;
     420             :     }
     421     1377550 :     const char *s = PyBytes_AsString(t->bytes);
     422     1377550 :     if (!s) {
     423           0 :         p->error_indicator = 1;
     424           0 :         return NULL;
     425             :     }
     426     1377550 :     if (strcmp(s, keyword) != 0) {
     427     1372710 :         return NULL;
     428             :     }
     429        4842 :     return _PyPegen_name_token(p);
     430             : }
     431             : 
     432             : Token *
     433    20074800 : _PyPegen_get_last_nonnwhitespace_token(Parser *p)
     434             : {
     435    20074800 :     assert(p->mark >= 0);
     436    20074800 :     Token *token = NULL;
     437    22365500 :     for (int m = p->mark - 1; m >= 0; m--) {
     438    22365500 :         token = p->tokens[m];
     439    22365500 :         if (token->type != ENDMARKER && (token->type < NEWLINE || token->type > DEDENT)) {
     440             :             break;
     441             :         }
     442             :     }
     443    20074800 :     return token;
     444             : }
     445             : 
     446             : PyObject *
     447    34074200 : _PyPegen_new_identifier(Parser *p, const char *n)
     448             : {
     449    34074200 :     PyObject *id = PyUnicode_DecodeUTF8(n, strlen(n), NULL);
     450    34074200 :     if (!id) {
     451           0 :         goto error;
     452             :     }
     453             :     /* PyUnicode_DecodeUTF8 should always return a ready string. */
     454    34074200 :     assert(PyUnicode_IS_READY(id));
     455             :     /* Check whether there are non-ASCII characters in the
     456             :        identifier; if so, normalize to NFKC. */
     457    34074200 :     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    34074200 :     PyUnicode_InternInPlace(&id);
     490    34074200 :     if (_PyArena_AddPyObject(p->arena, id) < 0)
     491             :     {
     492           0 :         Py_DECREF(id);
     493           0 :         goto error;
     494             :     }
     495    34074200 :     return id;
     496             : 
     497           1 : error:
     498           1 :     p->error_indicator = 1;
     499           1 :     return NULL;
     500             : }
     501             : 
     502             : static expr_ty
     503    69126700 : _PyPegen_name_from_token(Parser *p, Token* t)
     504             : {
     505    69126700 :     if (t == NULL) {
     506    35056200 :         return NULL;
     507             :     }
     508    34070500 :     const char *s = PyBytes_AsString(t->bytes);
     509    34070500 :     if (!s) {
     510           0 :         p->error_indicator = 1;
     511           0 :         return NULL;
     512             :     }
     513    34070500 :     PyObject *id = _PyPegen_new_identifier(p, s);
     514    34070500 :     if (id == NULL) {
     515           1 :         p->error_indicator = 1;
     516           1 :         return NULL;
     517             :     }
     518    34070500 :     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    69126700 : _PyPegen_name_token(Parser *p)
     524             : {
     525    69126700 :     Token *t = _PyPegen_expect_token(p, NAME);
     526    69126700 :     return _PyPegen_name_from_token(p, t);
     527             : }
     528             : 
     529             : void *
     530    17709100 : _PyPegen_string_token(Parser *p)
     531             : {
     532    17709100 :     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     5874740 : 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     5874740 :     assert(s != NULL);
     561     5874740 :     errno = 0;
     562     5874740 :     end = s + strlen(s) - 1;
     563     5874740 :     imflag = *end == 'j' || *end == 'J';
     564     5874740 :     if (s[0] == '0') {
     565     1814730 :         x = (long)PyOS_strtoul(s, (char **)&end, 0);
     566     1814730 :         if (x < 0 && errno == 0) {
     567         277 :             return PyLong_FromString(s, (char **)0, 0);
     568             :         }
     569             :     }
     570             :     else {
     571     4060010 :         x = PyOS_strtol(s, (char **)&end, 0);
     572             :     }
     573     5874470 :     if (*end == '\0') {
     574     5813940 :         if (errno != 0) {
     575         892 :             return PyLong_FromString(s, (char **)0, 0);
     576             :         }
     577     5813050 :         return PyLong_FromLong(x);
     578             :     }
     579             :     /* XXX Huge floats may silently fail */
     580       60523 :     if (imflag) {
     581        4262 :         compl.real = 0.;
     582        4262 :         compl.imag = PyOS_string_to_double(s, (char **)&end, NULL);
     583        4262 :         if (compl.imag == -1.0 && PyErr_Occurred()) {
     584           0 :             return NULL;
     585             :         }
     586        4262 :         return PyComplex_FromCComplex(compl);
     587             :     }
     588       56261 :     dx = PyOS_string_to_double(s, NULL, NULL);
     589       56261 :     if (dx == -1.0 && PyErr_Occurred()) {
     590           0 :         return NULL;
     591             :     }
     592       56261 :     return PyFloat_FromDouble(dx);
     593             : }
     594             : 
     595             : static PyObject *
     596     5874740 : parsenumber(const char *s)
     597             : {
     598             :     char *dup;
     599             :     char *end;
     600     5874740 :     PyObject *res = NULL;
     601             : 
     602     5874740 :     assert(s != NULL);
     603             : 
     604     5874740 :     if (strchr(s, '_') == NULL) {
     605     5873040 :         return parsenumber_raw(s);
     606             :     }
     607             :     /* Create a duplicate without underscores. */
     608        1703 :     dup = PyMem_Malloc(strlen(s) + 1);
     609        1703 :     if (dup == NULL) {
     610           0 :         return PyErr_NoMemory();
     611             :     }
     612        1703 :     end = dup;
     613       38803 :     for (; *s; s++) {
     614       37100 :         if (*s != '_') {
     615       32836 :             *end++ = *s;
     616             :         }
     617             :     }
     618        1703 :     *end = '\0';
     619        1703 :     res = parsenumber_raw(dup);
     620        1703 :     PyMem_Free(dup);
     621        1703 :     return res;
     622             : }
     623             : 
     624             : expr_ty
     625    10995100 : _PyPegen_number_token(Parser *p)
     626             : {
     627    10995100 :     Token *t = _PyPegen_expect_token(p, NUMBER);
     628    10995100 :     if (t == NULL) {
     629     5120390 :         return NULL;
     630             :     }
     631             : 
     632     5874740 :     const char *num_raw = PyBytes_AsString(t->bytes);
     633     5874740 :     if (num_raw == NULL) {
     634           0 :         p->error_indicator = 1;
     635           0 :         return NULL;
     636             :     }
     637             : 
     638     5874740 :     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     5874740 :     PyObject *c = parsenumber(num_raw);
     645             : 
     646     5874740 :     if (c == NULL) {
     647           0 :         p->error_indicator = 1;
     648           0 :         return NULL;
     649             :     }
     650             : 
     651     5874740 :     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     5874740 :     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        4163 : bad_single_statement(Parser *p)
     666             : {
     667        4163 :     char *cur = p->tok->cur;
     668        4163 :     char c = *cur;
     669             : 
     670             :     for (;;) {
     671        4349 :         while (c == ' ' || c == '\t' || c == '\n' || c == '\014') {
     672         119 :             c = *++cur;
     673             :         }
     674             : 
     675        4230 :         if (!c) {
     676        4155 :             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      127837 : compute_parser_flags(PyCompilerFlags *flags)
     692             : {
     693      127837 :     int parser_flags = 0;
     694      127837 :     if (!flags) {
     695         181 :         return 0;
     696             :     }
     697      127656 :     if (flags->cf_flags & PyCF_DONT_IMPLY_DEDENT) {
     698         362 :         parser_flags |= PyPARSE_DONT_IMPLY_DEDENT;
     699             :     }
     700      127656 :     if (flags->cf_flags & PyCF_IGNORE_COOKIE) {
     701      115007 :         parser_flags |= PyPARSE_IGNORE_COOKIE;
     702             :     }
     703      127656 :     if (flags->cf_flags & CO_FUTURE_BARRY_AS_BDFL) {
     704           3 :         parser_flags |= PyPARSE_BARRY_AS_BDFL;
     705             :     }
     706      127656 :     if (flags->cf_flags & PyCF_TYPE_COMMENTS) {
     707         250 :         parser_flags |= PyPARSE_TYPE_COMMENTS;
     708             :     }
     709      127656 :     if ((flags->cf_flags & PyCF_ONLY_AST) && flags->cf_feature_version < 7) {
     710          69 :         parser_flags |= PyPARSE_ASYNC_HACKS;
     711             :     }
     712      127656 :     if (flags->cf_flags & PyCF_ALLOW_INCOMPLETE_INPUT) {
     713         323 :         parser_flags |= PyPARSE_ALLOW_INCOMPLETE_INPUT;
     714             :     }
     715      127656 :     return parser_flags;
     716             : }
     717             : 
     718             : // Parser API
     719             : 
     720             : Parser *
     721      223947 : _PyPegen_Parser_New(struct tok_state *tok, int start_rule, int flags,
     722             :                     int feature_version, int *errcode, PyArena *arena)
     723             : {
     724      223947 :     Parser *p = PyMem_Malloc(sizeof(Parser));
     725      223947 :     if (p == NULL) {
     726           0 :         return (Parser *) PyErr_NoMemory();
     727             :     }
     728      223947 :     assert(tok != NULL);
     729      223947 :     tok->type_comments = (flags & PyPARSE_TYPE_COMMENTS) > 0;
     730      223947 :     tok->async_hacks = (flags & PyPARSE_ASYNC_HACKS) > 0;
     731      223947 :     p->tok = tok;
     732      223947 :     p->keywords = NULL;
     733      223947 :     p->n_keyword_lists = -1;
     734      223947 :     p->soft_keywords = NULL;
     735      223947 :     p->tokens = PyMem_Malloc(sizeof(Token *));
     736      223947 :     if (!p->tokens) {
     737           0 :         PyMem_Free(p);
     738           0 :         return (Parser *) PyErr_NoMemory();
     739             :     }
     740      223947 :     p->tokens[0] = PyMem_Calloc(1, sizeof(Token));
     741      223947 :     if (!p->tokens) {
     742           0 :         PyMem_Free(p->tokens);
     743           0 :         PyMem_Free(p);
     744           0 :         return (Parser *) PyErr_NoMemory();
     745             :     }
     746      223947 :     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           0 :         return (Parser *) PyErr_NoMemory();
     751             :     }
     752             : 
     753      223947 :     p->mark = 0;
     754      223947 :     p->fill = 0;
     755      223947 :     p->size = 1;
     756             : 
     757      223947 :     p->errcode = errcode;
     758      223947 :     p->arena = arena;
     759      223947 :     p->start_rule = start_rule;
     760      223947 :     p->parsing_started = 0;
     761      223947 :     p->normalize = NULL;
     762      223947 :     p->error_indicator = 0;
     763             : 
     764      223947 :     p->starting_lineno = 0;
     765      223947 :     p->starting_col_offset = 0;
     766      223947 :     p->flags = flags;
     767      223947 :     p->feature_version = feature_version;
     768      223947 :     p->known_err_token = NULL;
     769      223947 :     p->level = 0;
     770      223947 :     p->call_invalid_rules = 0;
     771             : #ifdef Py_DEBUG
     772      223947 :     p->debug = _Py_GetConfig()->parser_debug;
     773             : #endif
     774      223947 :     return p;
     775             : }
     776             : 
     777             : void
     778      223947 : _PyPegen_Parser_Free(Parser *p)
     779             : {
     780      223947 :     Py_XDECREF(p->normalize);
     781    57204500 :     for (int i = 0; i < p->size; i++) {
     782    56980500 :         PyMem_Free(p->tokens[i]);
     783             :     }
     784      223947 :     PyMem_Free(p->tokens);
     785      223947 :     growable_comment_array_deallocate(&p->type_ignore_comments);
     786      223947 :     PyMem_Free(p);
     787      223947 : }
     788             : 
     789             : static void
     790        2000 : reset_parser_state_for_error_pass(Parser *p)
     791             : {
     792       10529 :     for (int i = 0; i < p->fill; i++) {
     793        8529 :         p->tokens[i]->memo = NULL;
     794             :     }
     795        2000 :     p->mark = 0;
     796        2000 :     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        2000 :     p->tok->interactive_underflow = IUNDERFLOW_STOP;
     800        2000 : }
     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      223947 : _PyPegen_run_parser(Parser *p)
     810             : {
     811      223947 :     void *res = _PyPegen_parse(p);
     812      223947 :     assert(p->level == 0);
     813      223947 :     if (res == NULL) {
     814        2217 :         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        2004 :         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        2000 :         Token *last_token = p->tokens[p->fill - 1];
     825        2000 :         reset_parser_state_for_error_pass(p);
     826        2000 :         _PyPegen_parse(p);
     827             : 
     828             :         // Set SyntaxErrors accordingly depending on the parser/tokenizer status at the failure
     829             :         // point.
     830        2000 :         _Pypegen_set_syntax_error(p, last_token);
     831        2000 :        return NULL;
     832             :     }
     833             : 
     834      221730 :     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      221722 :     if (p->start_rule == Py_single_input ||
     842      217567 :         p->start_rule == Py_file_input ||
     843      169363 :         p->start_rule == Py_eval_input)
     844             :     {
     845      125616 :         if (!_PyAST_Validate(res)) {
     846           8 :             return NULL;
     847             :         }
     848             :     }
     849             : #endif
     850      221714 :     return res;
     851             : }
     852             : 
     853             : mod_ty
     854         354 : _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         354 :     struct tok_state *tok = _PyTokenizer_FromFile(fp, enc, ps1, ps2);
     859         354 :     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         678 :     if (!tok->fp || ps1 != NULL || ps2 != NULL ||
     867         324 :         PyUnicode_CompareWithASCIIString(filename_ob, "<stdin>") == 0) {
     868          43 :         tok->fp_interactive = 1;
     869             :     }
     870             :     // This transfers the ownership to the tokenizer
     871         354 :     tok->filename = filename_ob;
     872         354 :     Py_INCREF(filename_ob);
     873             : 
     874             :     // From here on we need to clean up even if there's an error
     875         354 :     mod_ty result = NULL;
     876             : 
     877         354 :     int parser_flags = compute_parser_flags(flags);
     878         354 :     Parser *p = _PyPegen_Parser_New(tok, start_rule, parser_flags, PY_MINOR_VERSION,
     879             :                                     errcode, arena);
     880         354 :     if (p == NULL) {
     881           0 :         goto error;
     882             :     }
     883             : 
     884         354 :     result = _PyPegen_run_parser(p);
     885         354 :     _PyPegen_Parser_Free(p);
     886             : 
     887         354 : error:
     888         354 :     _PyTokenizer_Free(tok);
     889         354 :     return result;
     890             : }
     891             : 
     892             : mod_ty
     893      127509 : _PyPegen_run_parser_from_string(const char *str, int start_rule, PyObject *filename_ob,
     894             :                        PyCompilerFlags *flags, PyArena *arena)
     895             : {
     896      127509 :     int exec_input = start_rule == Py_file_input;
     897             : 
     898             :     struct tok_state *tok;
     899      127509 :     if (flags != NULL && flags->cf_flags & PyCF_IGNORE_COOKIE) {
     900      115007 :         tok = _PyTokenizer_FromUTF8(str, exec_input);
     901             :     } else {
     902       12502 :         tok = _PyTokenizer_FromString(str, exec_input);
     903             :     }
     904      127509 :     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      127483 :     tok->filename = filename_ob;
     912      127483 :     Py_INCREF(filename_ob);
     913             : 
     914             :     // We need to clear up from here on
     915      127483 :     mod_ty result = NULL;
     916             : 
     917      127483 :     int parser_flags = compute_parser_flags(flags);
     918      127302 :     int feature_version = flags && (flags->cf_flags & PyCF_ONLY_AST) ?
     919      254785 :         flags->cf_feature_version : PY_MINOR_VERSION;
     920      127483 :     Parser *p = _PyPegen_Parser_New(tok, start_rule, parser_flags, feature_version,
     921             :                                     NULL, arena);
     922      127483 :     if (p == NULL) {
     923           0 :         goto error;
     924             :     }
     925             : 
     926      127483 :     result = _PyPegen_run_parser(p);
     927      127483 :     _PyPegen_Parser_Free(p);
     928             : 
     929      127483 : error:
     930      127483 :     _PyTokenizer_Free(tok);
     931      127483 :     return result;
     932             : }

Generated by: LCOV version 1.14