LCOV - code coverage report
Current view: top level - py - parse.c (source / functions) Hit Total Coverage
Test: unix_coverage_v1.22.0-335-g9c7f0659e.info Lines: 555 559 99.3 %
Date: 2024-04-24 08:31:58 Functions: 28 28 100.0 %
Branches: 384 429 89.5 %

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :  * This file is part of the MicroPython project, http://micropython.org/
       3                 :            :  *
       4                 :            :  * The MIT License (MIT)
       5                 :            :  *
       6                 :            :  * Copyright (c) 2013-2017 Damien P. George
       7                 :            :  *
       8                 :            :  * Permission is hereby granted, free of charge, to any person obtaining a copy
       9                 :            :  * of this software and associated documentation files (the "Software"), to deal
      10                 :            :  * in the Software without restriction, including without limitation the rights
      11                 :            :  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
      12                 :            :  * copies of the Software, and to permit persons to whom the Software is
      13                 :            :  * furnished to do so, subject to the following conditions:
      14                 :            :  *
      15                 :            :  * The above copyright notice and this permission notice shall be included in
      16                 :            :  * all copies or substantial portions of the Software.
      17                 :            :  *
      18                 :            :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
      19                 :            :  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      20                 :            :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
      21                 :            :  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      22                 :            :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
      23                 :            :  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
      24                 :            :  * THE SOFTWARE.
      25                 :            :  */
      26                 :            : 
      27                 :            : #include <stdbool.h>
      28                 :            : #include <stdint.h>
      29                 :            : #include <stdio.h>
      30                 :            : #include <unistd.h> // for ssize_t
      31                 :            : #include <assert.h>
      32                 :            : #include <string.h>
      33                 :            : 
      34                 :            : #include "py/lexer.h"
      35                 :            : #include "py/parse.h"
      36                 :            : #include "py/parsenum.h"
      37                 :            : #include "py/runtime.h"
      38                 :            : #include "py/objint.h"
      39                 :            : #include "py/objstr.h"
      40                 :            : #include "py/builtin.h"
      41                 :            : 
      42                 :            : #if MICROPY_ENABLE_COMPILER
      43                 :            : 
      44                 :            : #define RULE_ACT_ARG_MASK       (0x0f)
      45                 :            : #define RULE_ACT_KIND_MASK      (0x30)
      46                 :            : #define RULE_ACT_ALLOW_IDENT    (0x40)
      47                 :            : #define RULE_ACT_ADD_BLANK      (0x80)
      48                 :            : #define RULE_ACT_OR             (0x10)
      49                 :            : #define RULE_ACT_AND            (0x20)
      50                 :            : #define RULE_ACT_LIST           (0x30)
      51                 :            : 
      52                 :            : #define RULE_ARG_KIND_MASK      (0xf000)
      53                 :            : #define RULE_ARG_ARG_MASK       (0x0fff)
      54                 :            : #define RULE_ARG_TOK            (0x1000)
      55                 :            : #define RULE_ARG_RULE           (0x2000)
      56                 :            : #define RULE_ARG_OPT_RULE       (0x3000)
      57                 :            : 
      58                 :            : // *FORMAT-OFF*
      59                 :            : 
      60                 :            : enum {
      61                 :            : // define rules with a compile function
      62                 :            : #define DEF_RULE(rule, comp, kind, ...) RULE_##rule,
      63                 :            : #define DEF_RULE_NC(rule, kind, ...)
      64                 :            : #include "py/grammar.h"
      65                 :            : #undef DEF_RULE
      66                 :            : #undef DEF_RULE_NC
      67                 :            :     RULE_const_object, // special node for a constant, generic Python object
      68                 :            : 
      69                 :            : // define rules without a compile function
      70                 :            : #define DEF_RULE(rule, comp, kind, ...)
      71                 :            : #define DEF_RULE_NC(rule, kind, ...) RULE_##rule,
      72                 :            : #include "py/grammar.h"
      73                 :            : #undef DEF_RULE
      74                 :            : #undef DEF_RULE_NC
      75                 :            : };
      76                 :            : 
      77                 :            : // Define an array of actions corresponding to each rule
      78                 :            : static const uint8_t rule_act_table[] = {
      79                 :            : #define or(n)                   (RULE_ACT_OR | n)
      80                 :            : #define and(n)                  (RULE_ACT_AND | n)
      81                 :            : #define and_ident(n)            (RULE_ACT_AND | n | RULE_ACT_ALLOW_IDENT)
      82                 :            : #define and_blank(n)            (RULE_ACT_AND | n | RULE_ACT_ADD_BLANK)
      83                 :            : #define one_or_more             (RULE_ACT_LIST | 2)
      84                 :            : #define list                    (RULE_ACT_LIST | 1)
      85                 :            : #define list_with_end           (RULE_ACT_LIST | 3)
      86                 :            : 
      87                 :            : #define DEF_RULE(rule, comp, kind, ...) kind,
      88                 :            : #define DEF_RULE_NC(rule, kind, ...)
      89                 :            : #include "py/grammar.h"
      90                 :            : #undef DEF_RULE
      91                 :            : #undef DEF_RULE_NC
      92                 :            : 
      93                 :            :     0, // RULE_const_object
      94                 :            : 
      95                 :            : #define DEF_RULE(rule, comp, kind, ...)
      96                 :            : #define DEF_RULE_NC(rule, kind, ...) kind,
      97                 :            : #include "py/grammar.h"
      98                 :            : #undef DEF_RULE
      99                 :            : #undef DEF_RULE_NC
     100                 :            : 
     101                 :            : #undef or
     102                 :            : #undef and
     103                 :            : #undef and_ident
     104                 :            : #undef and_blank
     105                 :            : #undef one_or_more
     106                 :            : #undef list
     107                 :            : #undef list_with_end
     108                 :            : };
     109                 :            : 
     110                 :            : // Define the argument data for each rule, as a combined array
     111                 :            : static const uint16_t rule_arg_combined_table[] = {
     112                 :            : #define tok(t)                  (RULE_ARG_TOK | MP_TOKEN_##t)
     113                 :            : #define rule(r)                 (RULE_ARG_RULE | RULE_##r)
     114                 :            : #define opt_rule(r)             (RULE_ARG_OPT_RULE | RULE_##r)
     115                 :            : 
     116                 :            : #define DEF_RULE(rule, comp, kind, ...) __VA_ARGS__,
     117                 :            : #define DEF_RULE_NC(rule, kind, ...)
     118                 :            : #include "py/grammar.h"
     119                 :            : #undef DEF_RULE
     120                 :            : #undef DEF_RULE_NC
     121                 :            : 
     122                 :            : #define DEF_RULE(rule, comp, kind, ...)
     123                 :            : #define DEF_RULE_NC(rule, kind, ...)  __VA_ARGS__,
     124                 :            : #include "py/grammar.h"
     125                 :            : #undef DEF_RULE
     126                 :            : #undef DEF_RULE_NC
     127                 :            : 
     128                 :            : #undef tok
     129                 :            : #undef rule
     130                 :            : #undef opt_rule
     131                 :            : };
     132                 :            : 
     133                 :            : // Macro to create a list of N identifiers where N is the number of variable arguments to the macro
     134                 :            : #define RULE_EXPAND(x) x
     135                 :            : #define RULE_PADDING(rule, ...) RULE_PADDING2(rule, __VA_ARGS__, RULE_PADDING_IDS(rule))
     136                 :            : #define RULE_PADDING2(rule, ...) RULE_EXPAND(RULE_PADDING3(rule, __VA_ARGS__))
     137                 :            : #define RULE_PADDING3(rule, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, ...) __VA_ARGS__
     138                 :            : #define RULE_PADDING_IDS(r) PAD13_##r, PAD12_##r, PAD11_##r, PAD10_##r, PAD9_##r, PAD8_##r, PAD7_##r, PAD6_##r, PAD5_##r, PAD4_##r, PAD3_##r, PAD2_##r, PAD1_##r,
     139                 :            : 
     140                 :            : // Use an enum to create constants specifying how much room a rule takes in rule_arg_combined_table
     141                 :            : enum {
     142                 :            : #define DEF_RULE(rule, comp, kind, ...) RULE_PADDING(rule, __VA_ARGS__)
     143                 :            : #define DEF_RULE_NC(rule, kind, ...)
     144                 :            : #include "py/grammar.h"
     145                 :            : #undef DEF_RULE
     146                 :            : #undef DEF_RULE_NC
     147                 :            : #define DEF_RULE(rule, comp, kind, ...)
     148                 :            : #define DEF_RULE_NC(rule, kind, ...) RULE_PADDING(rule, __VA_ARGS__)
     149                 :            : #include "py/grammar.h"
     150                 :            : #undef DEF_RULE
     151                 :            : #undef DEF_RULE_NC
     152                 :            : };
     153                 :            : 
     154                 :            : // Macro to compute the start of a rule in rule_arg_combined_table
     155                 :            : #define RULE_ARG_OFFSET(rule, ...) RULE_ARG_OFFSET2(rule, __VA_ARGS__, RULE_ARG_OFFSET_IDS(rule))
     156                 :            : #define RULE_ARG_OFFSET2(rule, ...) RULE_EXPAND(RULE_ARG_OFFSET3(rule, __VA_ARGS__))
     157                 :            : #define RULE_ARG_OFFSET3(rule, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, ...) _14
     158                 :            : #define RULE_ARG_OFFSET_IDS(r) PAD13_##r, PAD12_##r, PAD11_##r, PAD10_##r, PAD9_##r, PAD8_##r, PAD7_##r, PAD6_##r, PAD5_##r, PAD4_##r, PAD3_##r, PAD2_##r, PAD1_##r, PAD0_##r,
     159                 :            : 
     160                 :            : // Use the above enum values to create a table of offsets for each rule's arg
     161                 :            : // data, which indexes rule_arg_combined_table.  The offsets require 9 bits of
     162                 :            : // storage but only the lower 8 bits are stored here.  The 9th bit is computed
     163                 :            : // in get_rule_arg using the FIRST_RULE_WITH_OFFSET_ABOVE_255 constant.
     164                 :            : static const uint8_t rule_arg_offset_table[] = {
     165                 :            : #define DEF_RULE(rule, comp, kind, ...) RULE_ARG_OFFSET(rule, __VA_ARGS__) & 0xff,
     166                 :            : #define DEF_RULE_NC(rule, kind, ...)
     167                 :            : #include "py/grammar.h"
     168                 :            : #undef DEF_RULE
     169                 :            : #undef DEF_RULE_NC
     170                 :            :     0, // RULE_const_object
     171                 :            : #define DEF_RULE(rule, comp, kind, ...)
     172                 :            : #define DEF_RULE_NC(rule, kind, ...) RULE_ARG_OFFSET(rule, __VA_ARGS__) & 0xff,
     173                 :            : #include "py/grammar.h"
     174                 :            : #undef DEF_RULE
     175                 :            : #undef DEF_RULE_NC
     176                 :            : };
     177                 :            : 
     178                 :            : // Define a constant that's used to determine the 9th bit of the values in rule_arg_offset_table
     179                 :            : static const size_t FIRST_RULE_WITH_OFFSET_ABOVE_255 =
     180                 :            : #define DEF_RULE(rule, comp, kind, ...) RULE_ARG_OFFSET(rule, __VA_ARGS__) >= 0x100 ? RULE_##rule :
     181                 :            : #define DEF_RULE_NC(rule, kind, ...)
     182                 :            : #include "py/grammar.h"
     183                 :            : #undef DEF_RULE
     184                 :            : #undef DEF_RULE_NC
     185                 :            : #define DEF_RULE(rule, comp, kind, ...)
     186                 :            : #define DEF_RULE_NC(rule, kind, ...) RULE_ARG_OFFSET(rule, __VA_ARGS__) >= 0x100 ? RULE_##rule :
     187                 :            : #include "py/grammar.h"
     188                 :            : #undef DEF_RULE
     189                 :            : #undef DEF_RULE_NC
     190                 :            : 0;
     191                 :            : 
     192                 :            : #if MICROPY_DEBUG_PARSE_RULE_NAME
     193                 :            : // Define an array of rule names corresponding to each rule
     194                 :            : static const char *const rule_name_table[] = {
     195                 :            : #define DEF_RULE(rule, comp, kind, ...) #rule,
     196                 :            : #define DEF_RULE_NC(rule, kind, ...)
     197                 :            : #include "py/grammar.h"
     198                 :            : #undef DEF_RULE
     199                 :            : #undef DEF_RULE_NC
     200                 :            :     "", // RULE_const_object
     201                 :            : #define DEF_RULE(rule, comp, kind, ...)
     202                 :            : #define DEF_RULE_NC(rule, kind, ...) #rule,
     203                 :            : #include "py/grammar.h"
     204                 :            : #undef DEF_RULE
     205                 :            : #undef DEF_RULE_NC
     206                 :            : };
     207                 :            : #endif
     208                 :            : 
     209                 :            : // *FORMAT-ON*
     210                 :            : 
     211                 :            : typedef struct _rule_stack_t {
     212                 :            :     size_t src_line : (8 * sizeof(size_t) - 8); // maximum bits storing source line number
     213                 :            :     size_t rule_id : 8; // this must be large enough to fit largest rule number
     214                 :            :     size_t arg_i; // this dictates the maximum nodes in a "list" of things
     215                 :            : } rule_stack_t;
     216                 :            : 
     217                 :            : typedef struct _mp_parse_chunk_t {
     218                 :            :     size_t alloc;
     219                 :            :     union {
     220                 :            :         size_t used;
     221                 :            :         struct _mp_parse_chunk_t *next;
     222                 :            :     } union_;
     223                 :            :     byte data[];
     224                 :            : } mp_parse_chunk_t;
     225                 :            : 
     226                 :            : typedef struct _parser_t {
     227                 :            :     size_t rule_stack_alloc;
     228                 :            :     size_t rule_stack_top;
     229                 :            :     rule_stack_t *rule_stack;
     230                 :            : 
     231                 :            :     size_t result_stack_alloc;
     232                 :            :     size_t result_stack_top;
     233                 :            :     mp_parse_node_t *result_stack;
     234                 :            : 
     235                 :            :     mp_lexer_t *lexer;
     236                 :            : 
     237                 :            :     mp_parse_tree_t tree;
     238                 :            :     mp_parse_chunk_t *cur_chunk;
     239                 :            : 
     240                 :            :     #if MICROPY_COMP_CONST
     241                 :            :     mp_map_t consts;
     242                 :            :     #endif
     243                 :            : } parser_t;
     244                 :            : 
     245                 :            : static void push_result_rule(parser_t *parser, size_t src_line, uint8_t rule_id, size_t num_args);
     246                 :            : 
     247                 :   17730487 : static const uint16_t *get_rule_arg(uint8_t r_id) {
     248                 :   17730487 :     size_t off = rule_arg_offset_table[r_id];
     249         [ +  + ]:   17730487 :     if (r_id >= FIRST_RULE_WITH_OFFSET_ABOVE_255) {
     250                 :    6051612 :         off |= 0x100;
     251                 :            :     }
     252                 :   17730487 :     return &rule_arg_combined_table[off];
     253                 :            : }
     254                 :            : 
     255                 :     260698 : static void *parser_alloc(parser_t *parser, size_t num_bytes) {
     256                 :            :     // use a custom memory allocator to store parse nodes sequentially in large chunks
     257                 :            : 
     258                 :     260698 :     mp_parse_chunk_t *chunk = parser->cur_chunk;
     259                 :            : 
     260   [ +  +  +  + ]:     260698 :     if (chunk != NULL && chunk->union_.used + num_bytes > chunk->alloc) {
     261                 :            :         // not enough room at end of previously allocated chunk so try to grow
     262                 :     201041 :         mp_parse_chunk_t *new_data = (mp_parse_chunk_t *)m_renew_maybe(byte, chunk,
     263                 :            :             sizeof(mp_parse_chunk_t) + chunk->alloc,
     264                 :            :             sizeof(mp_parse_chunk_t) + chunk->alloc + num_bytes, false);
     265         [ +  + ]:     201041 :         if (new_data == NULL) {
     266                 :            :             // could not grow existing memory; shrink it to fit previous
     267                 :       8922 :             (void)m_renew_maybe(byte, chunk, sizeof(mp_parse_chunk_t) + chunk->alloc,
     268                 :            :                 sizeof(mp_parse_chunk_t) + chunk->union_.used, false);
     269                 :       8922 :             chunk->alloc = chunk->union_.used;
     270                 :       8922 :             chunk->union_.next = parser->tree.chunk;
     271                 :       8922 :             parser->tree.chunk = chunk;
     272                 :       8922 :             chunk = NULL;
     273                 :            :         } else {
     274                 :            :             // could grow existing memory
     275                 :     192119 :             chunk->alloc += num_bytes;
     276                 :            :         }
     277                 :            :     }
     278                 :            : 
     279                 :     201041 :     if (chunk == NULL) {
     280                 :            :         // no previous chunk, allocate a new chunk
     281                 :      12693 :         size_t alloc = MICROPY_ALLOC_PARSE_CHUNK_INIT;
     282         [ +  + ]:      12693 :         if (alloc < num_bytes) {
     283                 :         54 :             alloc = num_bytes;
     284                 :            :         }
     285                 :      12693 :         chunk = (mp_parse_chunk_t *)m_new(byte, sizeof(mp_parse_chunk_t) + alloc);
     286                 :      12693 :         chunk->alloc = alloc;
     287                 :      12693 :         chunk->union_.used = 0;
     288                 :      12693 :         parser->cur_chunk = chunk;
     289                 :            :     }
     290                 :            : 
     291                 :     260698 :     byte *ret = chunk->data + chunk->union_.used;
     292                 :     260698 :     chunk->union_.used += num_bytes;
     293                 :     260698 :     return ret;
     294                 :            : }
     295                 :            : 
     296                 :            : #if MICROPY_COMP_CONST_TUPLE
     297                 :        292 : static void parser_free_parse_node_struct(parser_t *parser, mp_parse_node_struct_t *pns) {
     298                 :        292 :     mp_parse_chunk_t *chunk = parser->cur_chunk;
     299   [ +  +  +  + ]:        292 :     if (chunk->data <= (byte *)pns && (byte *)pns < chunk->data + chunk->union_.used) {
     300                 :        252 :         size_t num_bytes = sizeof(mp_parse_node_struct_t) + sizeof(mp_parse_node_t) * MP_PARSE_NODE_STRUCT_NUM_NODES(pns);
     301                 :        252 :         chunk->union_.used -= num_bytes;
     302                 :            :     }
     303                 :        292 : }
     304                 :            : #endif
     305                 :            : 
     306                 :   17731403 : static void push_rule(parser_t *parser, size_t src_line, uint8_t rule_id, size_t arg_i) {
     307         [ +  + ]:   17731403 :     if (parser->rule_stack_top >= parser->rule_stack_alloc) {
     308                 :       1317 :         rule_stack_t *rs = m_renew(rule_stack_t, parser->rule_stack, parser->rule_stack_alloc, parser->rule_stack_alloc + MICROPY_ALLOC_PARSE_RULE_INC);
     309                 :       1317 :         parser->rule_stack = rs;
     310                 :       1317 :         parser->rule_stack_alloc += MICROPY_ALLOC_PARSE_RULE_INC;
     311                 :            :     }
     312                 :   17731403 :     rule_stack_t *rs = &parser->rule_stack[parser->rule_stack_top++];
     313                 :   17731403 :     rs->src_line = src_line;
     314                 :   17731403 :     rs->rule_id = rule_id;
     315                 :   17731403 :     rs->arg_i = arg_i;
     316                 :   17731403 : }
     317                 :            : 
     318                 :    9702046 : static void push_rule_from_arg(parser_t *parser, size_t arg) {
     319         [ -  + ]:    9702046 :     assert((arg & RULE_ARG_KIND_MASK) == RULE_ARG_RULE || (arg & RULE_ARG_KIND_MASK) == RULE_ARG_OPT_RULE);
     320                 :    9702046 :     size_t rule_id = arg & RULE_ARG_ARG_MASK;
     321                 :    9702046 :     push_rule(parser, parser->lexer->tok_line, rule_id, 0);
     322                 :    9702864 : }
     323                 :            : 
     324                 :   17731125 : static uint8_t pop_rule(parser_t *parser, size_t *arg_i, size_t *src_line) {
     325                 :   17731125 :     parser->rule_stack_top -= 1;
     326                 :   17731125 :     uint8_t rule_id = parser->rule_stack[parser->rule_stack_top].rule_id;
     327                 :   17731125 :     *arg_i = parser->rule_stack[parser->rule_stack_top].arg_i;
     328                 :   17731125 :     *src_line = parser->rule_stack[parser->rule_stack_top].src_line;
     329                 :   17731125 :     return rule_id;
     330                 :            : }
     331                 :            : 
     332                 :            : #if MICROPY_COMP_CONST_TUPLE
     333                 :       5315 : static uint8_t peek_rule(parser_t *parser, size_t n) {
     334         [ -  + ]:       5315 :     assert(parser->rule_stack_top > n);
     335                 :       5315 :     return parser->rule_stack[parser->rule_stack_top - 1 - n].rule_id;
     336                 :            : }
     337                 :            : #endif
     338                 :            : 
     339                 :       8493 : bool mp_parse_node_get_int_maybe(mp_parse_node_t pn, mp_obj_t *o) {
     340         [ +  + ]:       8493 :     if (MP_PARSE_NODE_IS_SMALL_INT(pn)) {
     341                 :       3551 :         *o = MP_OBJ_NEW_SMALL_INT(MP_PARSE_NODE_LEAF_SMALL_INT(pn));
     342                 :       3551 :         return true;
     343   [ +  -  +  +  :       4942 :     } else if (MP_PARSE_NODE_IS_STRUCT_KIND(pn, RULE_const_object)) {
                   +  + ]
     344                 :       1521 :         mp_parse_node_struct_t *pns = (mp_parse_node_struct_t *)pn;
     345         [ +  - ]:       1521 :         *o = mp_parse_node_extract_const_object(pns);
     346   [ +  -  +  -  :       2257 :         return mp_obj_is_int(*o);
                   +  + ]
     347                 :            :     } else {
     348                 :            :         return false;
     349                 :            :     }
     350                 :            : }
     351                 :            : 
     352                 :            : #if MICROPY_COMP_CONST_TUPLE || MICROPY_COMP_CONST
     353                 :      74974 : static bool mp_parse_node_is_const(mp_parse_node_t pn) {
     354         [ +  + ]:      74974 :     if (MP_PARSE_NODE_IS_SMALL_INT(pn)) {
     355                 :            :         // Small integer.
     356                 :            :         return true;
     357         [ +  + ]:      68395 :     } else if (MP_PARSE_NODE_IS_LEAF(pn)) {
     358                 :            :         // Possible str, or constant literal.
     359                 :      15420 :         uintptr_t kind = MP_PARSE_NODE_LEAF_KIND(pn);
     360         [ +  + ]:      15420 :         if (kind == MP_PARSE_NODE_STRING) {
     361                 :            :             return true;
     362         [ +  + ]:      14030 :         } else if (kind == MP_PARSE_NODE_TOKEN) {
     363                 :       6394 :             uintptr_t arg = MP_PARSE_NODE_LEAF_ARG(pn);
     364                 :       6394 :             return arg == MP_TOKEN_KW_NONE
     365                 :            :                    || arg == MP_TOKEN_KW_FALSE
     366                 :            :                    || arg == MP_TOKEN_KW_TRUE
     367                 :       6394 :                    || arg == MP_TOKEN_ELLIPSIS;
     368                 :            :         }
     369   [ +  -  +  + ]:      52975 :     } else if (MP_PARSE_NODE_IS_STRUCT_KIND(pn, RULE_const_object)) {
     370                 :            :         // Constant object.
     371                 :            :         return true;
     372         [ +  + ]:      51741 :     } else if (MP_PARSE_NODE_IS_STRUCT_KIND(pn, RULE_atom_paren)) {
     373                 :            :         // Possible empty tuple.
     374                 :        152 :         mp_parse_node_struct_t *pns = (mp_parse_node_struct_t *)pn;
     375                 :        152 :         return MP_PARSE_NODE_IS_NULL(pns->nodes[0]);
     376                 :            :     }
     377                 :            :     return false;
     378                 :            : }
     379                 :            : 
     380                 :       7581 : static mp_obj_t mp_parse_node_convert_to_obj(mp_parse_node_t pn) {
     381         [ -  + ]:       7581 :     assert(mp_parse_node_is_const(pn));
     382         [ +  + ]:       7581 :     if (MP_PARSE_NODE_IS_SMALL_INT(pn)) {
     383                 :       3205 :         mp_int_t arg = MP_PARSE_NODE_LEAF_SMALL_INT(pn);
     384                 :            :         #if MICROPY_DYNAMIC_COMPILER
     385                 :            :         mp_uint_t sign_mask = -((mp_uint_t)1 << (mp_dynamic_compiler.small_int_bits - 1));
     386                 :            :         if (!((arg & sign_mask) == 0 || (arg & sign_mask) == sign_mask)) {
     387                 :            :             // Integer doesn't fit in a small-int, so create a multi-precision int object.
     388                 :            :             return mp_obj_new_int_from_ll(arg);
     389                 :            :         }
     390                 :            :         #endif
     391                 :       3205 :         return MP_OBJ_NEW_SMALL_INT(arg);
     392         [ +  + ]:       4376 :     } else if (MP_PARSE_NODE_IS_LEAF(pn)) {
     393                 :       3800 :         uintptr_t kind = MP_PARSE_NODE_LEAF_KIND(pn);
     394                 :       3800 :         uintptr_t arg = MP_PARSE_NODE_LEAF_ARG(pn);
     395         [ +  + ]:       3800 :         if (kind == MP_PARSE_NODE_STRING) {
     396                 :        604 :             return MP_OBJ_NEW_QSTR(arg);
     397                 :            :         } else {
     398         [ -  + ]:       3196 :             assert(MP_PARSE_NODE_LEAF_KIND(pn) == MP_PARSE_NODE_TOKEN);
     399   [ +  +  +  + ]:       3196 :             switch (arg) {
     400                 :            :                 case MP_TOKEN_KW_NONE:
     401                 :            :                     return mp_const_none;
     402                 :        126 :                 case MP_TOKEN_KW_FALSE:
     403                 :        126 :                     return mp_const_false;
     404                 :       3060 :                 case MP_TOKEN_KW_TRUE:
     405                 :       3060 :                     return mp_const_true;
     406                 :          2 :                 default:
     407         [ -  + ]:          2 :                     assert(arg == MP_TOKEN_ELLIPSIS);
     408                 :            :                     return MP_OBJ_FROM_PTR(&mp_const_ellipsis_obj);
     409                 :            :             }
     410                 :            :         }
     411   [ +  -  +  + ]:        576 :     } else if (MP_PARSE_NODE_IS_STRUCT_KIND(pn, RULE_const_object)) {
     412                 :        552 :         mp_parse_node_struct_t *pns = (mp_parse_node_struct_t *)pn;
     413                 :        552 :         return mp_parse_node_extract_const_object(pns);
     414                 :            :     } else {
     415         [ -  + ]:         24 :         assert(MP_PARSE_NODE_IS_STRUCT_KIND(pn, RULE_atom_paren));
     416         [ -  + ]:         24 :         assert(MP_PARSE_NODE_IS_NULL(((mp_parse_node_struct_t *)pn)->nodes[0]));
     417                 :            :         return mp_const_empty_tuple;
     418                 :            :     }
     419                 :            : }
     420                 :            : #endif
     421                 :            : 
     422                 :      62230 : static bool parse_node_is_const_bool(mp_parse_node_t pn, bool value) {
     423                 :            :     // Returns true if 'pn' is a constant whose boolean value is equivalent to 'value'
     424                 :            :     #if MICROPY_COMP_CONST_TUPLE || MICROPY_COMP_CONST
     425   [ +  +  +  + ]:      62230 :     return mp_parse_node_is_const(pn) && mp_obj_is_true(mp_parse_node_convert_to_obj(pn)) == value;
     426                 :            :     #else
     427                 :            :     return MP_PARSE_NODE_IS_TOKEN_KIND(pn, value ? MP_TOKEN_KW_TRUE : MP_TOKEN_KW_FALSE)
     428                 :            :            || (MP_PARSE_NODE_IS_SMALL_INT(pn) && !!MP_PARSE_NODE_LEAF_SMALL_INT(pn) == value);
     429                 :            :     #endif
     430                 :            : }
     431                 :            : 
     432                 :      31241 : bool mp_parse_node_is_const_false(mp_parse_node_t pn) {
     433                 :      31241 :     return parse_node_is_const_bool(pn, false);
     434                 :            : }
     435                 :            : 
     436                 :      30989 : bool mp_parse_node_is_const_true(mp_parse_node_t pn) {
     437                 :      30989 :     return parse_node_is_const_bool(pn, true);
     438                 :            : }
     439                 :            : 
     440                 :     480933 : size_t mp_parse_node_extract_list(mp_parse_node_t *pn, size_t pn_kind, mp_parse_node_t **nodes) {
     441         [ +  + ]:     480933 :     if (MP_PARSE_NODE_IS_NULL(*pn)) {
     442                 :     246609 :         *nodes = NULL;
     443                 :     246609 :         return 0;
     444         [ +  + ]:     234324 :     } else if (MP_PARSE_NODE_IS_LEAF(*pn)) {
     445                 :      52527 :         *nodes = pn;
     446                 :      52527 :         return 1;
     447                 :            :     } else {
     448                 :     181797 :         mp_parse_node_struct_t *pns = (mp_parse_node_struct_t *)(*pn);
     449         [ +  + ]:     181797 :         if (MP_PARSE_NODE_STRUCT_KIND(pns) != pn_kind) {
     450                 :     143930 :             *nodes = pn;
     451                 :     143930 :             return 1;
     452                 :            :         } else {
     453                 :      37867 :             *nodes = pns->nodes;
     454                 :      37867 :             return MP_PARSE_NODE_STRUCT_NUM_NODES(pns);
     455                 :            :         }
     456                 :            :     }
     457                 :            : }
     458                 :            : 
     459                 :            : #if MICROPY_DEBUG_PRINTERS
     460                 :         78 : void mp_parse_node_print(const mp_print_t *print, mp_parse_node_t pn, size_t indent) {
     461   [ +  +  +  + ]:         78 :     if (MP_PARSE_NODE_IS_STRUCT(pn)) {
     462                 :         44 :         mp_printf(print, "[% 4d] ", (int)((mp_parse_node_struct_t *)pn)->source_line);
     463                 :            :     } else {
     464                 :         34 :         mp_printf(print, "       ");
     465                 :            :     }
     466         [ +  + ]:        410 :     for (size_t i = 0; i < indent; i++) {
     467                 :        332 :         mp_printf(print, " ");
     468                 :            :     }
     469         [ +  + ]:         78 :     if (MP_PARSE_NODE_IS_NULL(pn)) {
     470                 :          4 :         mp_printf(print, "NULL\n");
     471         [ +  + ]:         74 :     } else if (MP_PARSE_NODE_IS_SMALL_INT(pn)) {
     472                 :          2 :         mp_int_t arg = MP_PARSE_NODE_LEAF_SMALL_INT(pn);
     473                 :          2 :         mp_printf(print, "int(" INT_FMT ")\n", arg);
     474         [ +  + ]:         72 :     } else if (MP_PARSE_NODE_IS_LEAF(pn)) {
     475                 :         28 :         uintptr_t arg = MP_PARSE_NODE_LEAF_ARG(pn);
     476      [ +  +  + ]:         28 :         switch (MP_PARSE_NODE_LEAF_KIND(pn)) {
     477                 :         22 :             case MP_PARSE_NODE_ID:
     478                 :         22 :                 mp_printf(print, "id(%s)\n", qstr_str(arg));
     479                 :         22 :                 break;
     480                 :          2 :             case MP_PARSE_NODE_STRING:
     481                 :          2 :                 mp_printf(print, "str(%s)\n", qstr_str(arg));
     482                 :          2 :                 break;
     483                 :          4 :             default:
     484         [ -  + ]:          4 :                 assert(MP_PARSE_NODE_LEAF_KIND(pn) == MP_PARSE_NODE_TOKEN);
     485                 :          4 :                 mp_printf(print, "tok(%u)\n", (uint)arg);
     486                 :          4 :                 break;
     487                 :            :         }
     488                 :            :     } else {
     489                 :            :         // node must be a mp_parse_node_struct_t
     490                 :         44 :         mp_parse_node_struct_t *pns = (mp_parse_node_struct_t *)pn;
     491         [ +  + ]:         44 :         if (MP_PARSE_NODE_STRUCT_KIND(pns) == RULE_const_object) {
     492                 :         10 :             mp_obj_t obj = mp_parse_node_extract_const_object(pns);
     493                 :            :             #if MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_D
     494                 :            :             mp_printf(print, "literal const(%016llx)=", obj);
     495                 :            :             #else
     496                 :         10 :             mp_printf(print, "literal const(%p)=", obj);
     497                 :            :             #endif
     498                 :         10 :             mp_obj_print_helper(print, obj, PRINT_REPR);
     499                 :         10 :             mp_printf(print, "\n");
     500                 :            :         } else {
     501                 :         34 :             size_t n = MP_PARSE_NODE_STRUCT_NUM_NODES(pns);
     502                 :            :             #if MICROPY_DEBUG_PARSE_RULE_NAME
     503                 :         34 :             mp_printf(print, "%s(%u) (n=%u)\n", rule_name_table[MP_PARSE_NODE_STRUCT_KIND(pns)], (uint)MP_PARSE_NODE_STRUCT_KIND(pns), (uint)n);
     504                 :            :             #else
     505                 :            :             mp_printf(print, "rule(%u) (n=%u)\n", (uint)MP_PARSE_NODE_STRUCT_KIND(pns), (uint)n);
     506                 :            :             #endif
     507         [ +  + ]:        110 :             for (size_t i = 0; i < n; i++) {
     508                 :         76 :                 mp_parse_node_print(print, pns->nodes[i], indent + 2);
     509                 :            :             }
     510                 :            :         }
     511                 :            :     }
     512                 :         78 : }
     513                 :            : #endif // MICROPY_DEBUG_PRINTERS
     514                 :            : 
     515                 :            : /*
     516                 :            : static void result_stack_show(const mp_print_t *print, parser_t *parser) {
     517                 :            :     mp_printf(print, "result stack, most recent first\n");
     518                 :            :     for (ssize_t i = parser->result_stack_top - 1; i >= 0; i--) {
     519                 :            :         mp_parse_node_print(print, parser->result_stack[i], 0);
     520                 :            :     }
     521                 :            : }
     522                 :            : */
     523                 :            : 
     524                 :    1500867 : static mp_parse_node_t pop_result(parser_t *parser) {
     525         [ -  + ]:    1500867 :     assert(parser->result_stack_top > 0);
     526                 :    1500867 :     return parser->result_stack[--parser->result_stack_top];
     527                 :            : }
     528                 :            : 
     529                 :    1556923 : static mp_parse_node_t peek_result(parser_t *parser, size_t pos) {
     530         [ -  + ]:    1556923 :     assert(parser->result_stack_top > pos);
     531                 :    1556923 :     return parser->result_stack[parser->result_stack_top - 1 - pos];
     532                 :            : }
     533                 :            : 
     534                 :    1504834 : static void push_result_node(parser_t *parser, mp_parse_node_t pn) {
     535         [ +  + ]:    1504834 :     if (parser->result_stack_top >= parser->result_stack_alloc) {
     536                 :        678 :         mp_parse_node_t *stack = m_renew(mp_parse_node_t, parser->result_stack, parser->result_stack_alloc, parser->result_stack_alloc + MICROPY_ALLOC_PARSE_RESULT_INC);
     537                 :        678 :         parser->result_stack = stack;
     538                 :        678 :         parser->result_stack_alloc += MICROPY_ALLOC_PARSE_RESULT_INC;
     539                 :            :     }
     540                 :    1504834 :     parser->result_stack[parser->result_stack_top++] = pn;
     541                 :    1504834 : }
     542                 :            : 
     543                 :       8494 : static mp_parse_node_t make_node_const_object(parser_t *parser, size_t src_line, mp_obj_t obj) {
     544                 :       8494 :     mp_parse_node_struct_t *pn = parser_alloc(parser, sizeof(mp_parse_node_struct_t) + sizeof(mp_obj_t));
     545                 :       8494 :     pn->source_line = src_line;
     546                 :            :     #if MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_D
     547                 :            :     // nodes are 32-bit pointers, but need to store 64-bit object
     548                 :            :     pn->kind_num_nodes = RULE_const_object | (2 << 8);
     549                 :            :     pn->nodes[0] = (uint64_t)obj;
     550                 :            :     pn->nodes[1] = (uint64_t)obj >> 32;
     551                 :            :     #else
     552                 :       8494 :     pn->kind_num_nodes = RULE_const_object | (1 << 8);
     553                 :       8494 :     pn->nodes[0] = (uintptr_t)obj;
     554                 :            :     #endif
     555                 :       8494 :     return (mp_parse_node_t)pn;
     556                 :            : }
     557                 :            : 
     558                 :            : // Create a parse node representing a constant object, possibly optimising the case of
     559                 :            : // an integer, by putting the (small) integer value directly in the parse node itself.
     560                 :      29826 : static mp_parse_node_t make_node_const_object_optimised(parser_t *parser, size_t src_line, mp_obj_t obj) {
     561         [ +  + ]:      29826 :     if (mp_obj_is_small_int(obj)) {
     562                 :      28545 :         mp_int_t val = MP_OBJ_SMALL_INT_VALUE(obj);
     563                 :            :         #if MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_D
     564                 :            :         // A parse node is only 32-bits and the small-int value must fit in 31-bits
     565                 :            :         if (((val ^ (val << 1)) & 0xffffffff80000000) != 0) {
     566                 :            :             return make_node_const_object(parser, src_line, obj);
     567                 :            :         }
     568                 :            :         #endif
     569                 :            :         #if MICROPY_DYNAMIC_COMPILER
     570                 :            :         // Check that the integer value fits in target runtime's small-int
     571                 :            :         mp_uint_t sign_mask = -((mp_uint_t)1 << (mp_dynamic_compiler.small_int_bits - 1));
     572                 :            :         if (!((val & sign_mask) == 0 || (val & sign_mask) == sign_mask)) {
     573                 :            :             return make_node_const_object(parser, src_line, obj);
     574                 :            :         }
     575                 :            :         #endif
     576                 :      28545 :         return mp_parse_node_new_small_int(val);
     577                 :            :     } else {
     578                 :       1281 :         return make_node_const_object(parser, src_line, obj);
     579                 :            :     }
     580                 :            : }
     581                 :            : 
     582                 :     183006 : static void push_result_token(parser_t *parser, uint8_t rule_id) {
     583                 :     183006 :     mp_parse_node_t pn;
     584                 :     183006 :     mp_lexer_t *lex = parser->lexer;
     585   [ +  +  +  +  :     183006 :     if (lex->tok_kind == MP_TOKEN_NAME) {
                   +  + ]
     586                 :     121878 :         qstr id = qstr_from_strn(lex->vstr.buf, lex->vstr.len);
     587                 :            :         #if MICROPY_COMP_CONST
     588                 :            :         // if name is a standalone identifier, look it up in the table of dynamic constants
     589                 :     121867 :         mp_map_elem_t *elem;
     590         [ +  + ]:     121867 :         if (rule_id == RULE_atom
     591         [ +  + ]:      88842 :             && (elem = mp_map_lookup(&parser->consts, MP_OBJ_NEW_QSTR(id), MP_MAP_LOOKUP)) != NULL) {
     592                 :        201 :             pn = make_node_const_object_optimised(parser, lex->tok_line, elem->value);
     593                 :            :         } else {
     594                 :     121666 :             pn = mp_parse_node_new_leaf(MP_PARSE_NODE_ID, id);
     595                 :            :         }
     596                 :            :         #else
     597                 :            :         (void)rule_id;
     598                 :            :         pn = mp_parse_node_new_leaf(MP_PARSE_NODE_ID, id);
     599                 :            :         #endif
     600                 :            :     } else if (lex->tok_kind == MP_TOKEN_INTEGER) {
     601                 :      26406 :         mp_obj_t o = mp_parse_num_integer(lex->vstr.buf, lex->vstr.len, 0, lex);
     602                 :      26394 :         pn = make_node_const_object_optimised(parser, lex->tok_line, o);
     603                 :            :     } else if (lex->tok_kind == MP_TOKEN_FLOAT_OR_IMAG) {
     604                 :       1661 :         mp_obj_t o = mp_parse_num_float(lex->vstr.buf, lex->vstr.len, true, lex);
     605                 :       1661 :         pn = make_node_const_object(parser, lex->tok_line, o);
     606                 :            :     } else if (lex->tok_kind == MP_TOKEN_STRING) {
     607                 :            :         // Don't automatically intern all strings.  Doc strings (which are usually large)
     608                 :            :         // will be discarded by the compiler, and so we shouldn't intern them.
     609                 :      16042 :         qstr qst = MP_QSTRnull;
     610         [ +  + ]:      16042 :         if (lex->vstr.len <= MICROPY_ALLOC_PARSE_INTERN_STRING_LEN) {
     611                 :            :             // intern short strings
     612                 :      13203 :             qst = qstr_from_strn(lex->vstr.buf, lex->vstr.len);
     613                 :            :         } else {
     614                 :            :             // check if this string is already interned
     615                 :       2839 :             qst = qstr_find_strn(lex->vstr.buf, lex->vstr.len);
     616                 :            :         }
     617         [ +  + ]:      16042 :         if (qst != MP_QSTRnull) {
     618                 :            :             // qstr exists, make a leaf node
     619                 :      13610 :             pn = mp_parse_node_new_leaf(MP_PARSE_NODE_STRING, qst);
     620                 :            :         } else {
     621                 :            :             // not interned, make a node holding a pointer to the string object
     622                 :       2432 :             mp_obj_t o = mp_obj_new_str_copy(&mp_type_str, (const byte *)lex->vstr.buf, lex->vstr.len);
     623                 :       2432 :             pn = make_node_const_object(parser, lex->tok_line, o);
     624                 :            :         }
     625                 :            :     } else if (lex->tok_kind == MP_TOKEN_BYTES) {
     626                 :            :         // make a node holding a pointer to the bytes object
     627                 :       1926 :         mp_obj_t o = mp_obj_new_bytes((const byte *)lex->vstr.buf, lex->vstr.len);
     628                 :       1926 :         pn = make_node_const_object(parser, lex->tok_line, o);
     629                 :            :     } else {
     630                 :      15093 :         pn = mp_parse_node_new_leaf(MP_PARSE_NODE_TOKEN, lex->tok_kind);
     631                 :            :     }
     632                 :     182983 :     push_result_node(parser, pn);
     633                 :     182983 : }
     634                 :            : 
     635                 :            : #if MICROPY_COMP_CONST_FOLDING
     636                 :            : 
     637                 :            : #if MICROPY_COMP_MODULE_CONST
     638                 :            : static const mp_rom_map_elem_t mp_constants_table[] = {
     639                 :            :     #if MICROPY_PY_ERRNO
     640                 :            :     { MP_ROM_QSTR(MP_QSTR_errno), MP_ROM_PTR(&mp_module_errno) },
     641                 :            :     #endif
     642                 :            :     #if MICROPY_PY_UCTYPES
     643                 :            :     { MP_ROM_QSTR(MP_QSTR_uctypes), MP_ROM_PTR(&mp_module_uctypes) },
     644                 :            :     #endif
     645                 :            :     // Extra constants as defined by a port
     646                 :            :     MICROPY_PORT_CONSTANTS
     647                 :            : };
     648                 :            : static MP_DEFINE_CONST_MAP(mp_constants_map, mp_constants_table);
     649                 :            : #endif
     650                 :            : 
     651                 :            : #if MICROPY_COMP_CONST_FOLDING_COMPILER_WORKAROUND
     652                 :            : // Some versions of the xtensa-esp32-elf-gcc compiler generate wrong code if this
     653                 :            : // function is static, so provide a hook for them to work around this problem.
     654                 :            : MP_NOINLINE
     655                 :            : #endif
     656                 :     256802 : static bool fold_logical_constants(parser_t *parser, uint8_t rule_id, size_t *num_args) {
     657                 :     256802 :     if (rule_id == RULE_or_test
     658         [ +  + ]:     256802 :         || rule_id == RULE_and_test) {
     659                 :            :         // folding for binary logical ops: or and
     660                 :        518 :         size_t copy_to = *num_args;
     661         [ +  - ]:       1024 :         for (size_t i = copy_to; i > 0;) {
     662                 :       1024 :             mp_parse_node_t pn = peek_result(parser, --i);
     663                 :       1024 :             parser->result_stack[parser->result_stack_top - copy_to] = pn;
     664         [ +  + ]:       1024 :             if (i == 0) {
     665                 :            :                 // always need to keep the last value
     666                 :            :                 break;
     667                 :            :             }
     668         [ +  + ]:        528 :             if (rule_id == RULE_or_test) {
     669         [ +  + ]:        194 :                 if (mp_parse_node_is_const_true(pn)) {
     670                 :            :                     //
     671                 :            :                     break;
     672         [ +  + ]:        184 :                 } else if (!mp_parse_node_is_const_false(pn)) {
     673                 :        174 :                     copy_to -= 1;
     674                 :            :                 }
     675                 :            :             } else {
     676                 :            :                 // RULE_and_test
     677         [ +  + ]:        334 :                 if (mp_parse_node_is_const_false(pn)) {
     678                 :            :                     break;
     679         [ +  + ]:        322 :                 } else if (!mp_parse_node_is_const_true(pn)) {
     680                 :        312 :                     copy_to -= 1;
     681                 :            :                 }
     682                 :            :             }
     683                 :            :         }
     684                 :        518 :         copy_to -= 1; // copy_to now contains number of args to pop
     685                 :            : 
     686                 :            :         // pop and discard all the short-circuited expressions
     687         [ +  + ]:        560 :         for (size_t i = 0; i < copy_to; ++i) {
     688                 :         42 :             pop_result(parser);
     689                 :            :         }
     690                 :        518 :         *num_args -= copy_to;
     691                 :            : 
     692                 :            :         // we did a complete folding if there's only 1 arg left
     693                 :        518 :         return *num_args == 1;
     694                 :            : 
     695         [ +  + ]:     256284 :     } else if (rule_id == RULE_not_test_2) {
     696                 :            :         // folding for unary logical op: not
     697                 :        530 :         mp_parse_node_t pn = peek_result(parser, 0);
     698         [ +  + ]:        530 :         if (mp_parse_node_is_const_false(pn)) {
     699                 :            :             pn = mp_parse_node_new_leaf(MP_PARSE_NODE_TOKEN, MP_TOKEN_KW_TRUE);
     700         [ +  + ]:        496 :         } else if (mp_parse_node_is_const_true(pn)) {
     701                 :            :             pn = mp_parse_node_new_leaf(MP_PARSE_NODE_TOKEN, MP_TOKEN_KW_FALSE);
     702                 :            :         } else {
     703                 :            :             return false;
     704                 :            :         }
     705                 :         60 :         pop_result(parser);
     706                 :         60 :         push_result_node(parser, pn);
     707                 :         60 :         return true;
     708                 :            :     }
     709                 :            : 
     710                 :            :     return false;
     711                 :            : }
     712                 :            : 
     713                 :     256708 : static bool fold_constants(parser_t *parser, uint8_t rule_id, size_t num_args) {
     714                 :            :     // this code does folding of arbitrary integer expressions, eg 1 + 2 * 3 + 4
     715                 :            :     // it does not do partial folding, eg 1 + 2 + x -> 3 + x
     716                 :            : 
     717                 :     256708 :     mp_obj_t arg0;
     718                 :     256708 :     if (rule_id == RULE_expr
     719                 :            :         || rule_id == RULE_xor_expr
     720                 :     256708 :         || rule_id == RULE_and_expr
     721   [ +  +  +  +  :     256708 :         || rule_id == RULE_power) {
                   +  + ]
     722                 :            :         // folding for binary ops: | ^ & **
     723                 :       1331 :         mp_parse_node_t pn = peek_result(parser, num_args - 1);
     724         [ +  + ]:       1331 :         if (!mp_parse_node_get_int_maybe(pn, &arg0)) {
     725                 :            :             return false;
     726                 :            :         }
     727                 :        696 :         mp_binary_op_t op;
     728   [ +  +  +  + ]:        696 :         if (rule_id == RULE_expr) {
     729                 :            :             op = MP_BINARY_OP_OR;
     730                 :            :         } else if (rule_id == RULE_xor_expr) {
     731                 :            :             op = MP_BINARY_OP_XOR;
     732                 :            :         } else if (rule_id == RULE_and_expr) {
     733                 :            :             op = MP_BINARY_OP_AND;
     734                 :            :         } else {
     735                 :        696 :             op = MP_BINARY_OP_POWER;
     736                 :            :         }
     737         [ +  + ]:       1442 :         for (ssize_t i = num_args - 2; i >= 0; --i) {
     738                 :        776 :             pn = peek_result(parser, i);
     739                 :        776 :             mp_obj_t arg1;
     740         [ +  + ]:        776 :             if (!mp_parse_node_get_int_maybe(pn, &arg1)) {
     741                 :         30 :                 return false;
     742                 :            :             }
     743   [ +  +  +  + ]:        752 :             if (op == MP_BINARY_OP_POWER && mp_obj_int_sign(arg1) < 0) {
     744                 :            :                 // ** can't have negative rhs
     745                 :            :                 return false;
     746                 :            :             }
     747                 :        746 :             arg0 = mp_binary_op(op, arg0, arg1);
     748                 :            :         }
     749                 :            :     } else if (rule_id == RULE_shift_expr
     750                 :            :                || rule_id == RULE_arith_expr
     751                 :            :                || rule_id == RULE_term) {
     752                 :            :         // folding for binary ops: << >> + - * @ / % //
     753                 :       3260 :         mp_parse_node_t pn = peek_result(parser, num_args - 1);
     754         [ +  + ]:       3260 :         if (!mp_parse_node_get_int_maybe(pn, &arg0)) {
     755                 :            :             return false;
     756                 :            :         }
     757         [ +  + ]:       1224 :         for (ssize_t i = num_args - 2; i >= 1; i -= 2) {
     758                 :        754 :             pn = peek_result(parser, i - 1);
     759                 :        754 :             mp_obj_t arg1;
     760         [ +  + ]:        754 :             if (!mp_parse_node_get_int_maybe(pn, &arg1)) {
     761                 :        266 :                 return false;
     762                 :            :             }
     763                 :        544 :             mp_token_kind_t tok = MP_PARSE_NODE_LEAF_ARG(peek_result(parser, i));
     764         [ +  + ]:        544 :             if (tok == MP_TOKEN_OP_AT || tok == MP_TOKEN_OP_SLASH) {
     765                 :            :                 // Can't fold @ or /
     766                 :            :                 return false;
     767                 :            :             }
     768                 :        512 :             mp_binary_op_t op = MP_BINARY_OP_LSHIFT + (tok - MP_TOKEN_OP_DBL_LESS);
     769                 :        512 :             int rhs_sign = mp_obj_int_sign(arg1);
     770         [ +  + ]:        512 :             if (op <= MP_BINARY_OP_RSHIFT) {
     771                 :            :                 // << and >> can't have negative rhs
     772         [ +  + ]:        280 :                 if (rhs_sign < 0) {
     773                 :            :                     return false;
     774                 :            :                 }
     775         [ +  + ]:        232 :             } else if (op >= MP_BINARY_OP_FLOOR_DIVIDE) {
     776                 :            :                 // % and // can't have zero rhs
     777         [ +  + ]:         45 :                 if (rhs_sign == 0) {
     778                 :            :                     return false;
     779                 :            :                 }
     780                 :            :             }
     781                 :        488 :             arg0 = mp_binary_op(op, arg0, arg1);
     782                 :            :         }
     783                 :            :     } else if (rule_id == RULE_factor_2) {
     784                 :            :         // folding for unary ops: + - ~
     785                 :       2372 :         mp_parse_node_t pn = peek_result(parser, 0);
     786         [ +  + ]:       2372 :         if (!mp_parse_node_get_int_maybe(pn, &arg0)) {
     787                 :            :             return false;
     788                 :            :         }
     789                 :       1559 :         mp_token_kind_t tok = MP_PARSE_NODE_LEAF_ARG(peek_result(parser, 1));
     790                 :       1559 :         mp_unary_op_t op;
     791         [ +  + ]:       1559 :         if (tok == MP_TOKEN_OP_TILDE) {
     792                 :            :             op = MP_UNARY_OP_INVERT;
     793                 :            :         } else {
     794         [ -  + ]:       1537 :             assert(tok == MP_TOKEN_OP_PLUS || tok == MP_TOKEN_OP_MINUS); // should be
     795                 :            :             op = MP_UNARY_OP_POSITIVE + (tok - MP_TOKEN_OP_PLUS);
     796                 :            :         }
     797                 :       1559 :         arg0 = mp_unary_op(op, arg0);
     798                 :            : 
     799                 :            :     #if MICROPY_COMP_CONST
     800                 :            :     } else if (rule_id == RULE_expr_stmt) {
     801                 :      35621 :         mp_parse_node_t pn1 = peek_result(parser, 0);
     802         [ +  + ]:      35621 :         if (!MP_PARSE_NODE_IS_NULL(pn1)
     803   [ +  +  +  + ]:       9907 :             && !(MP_PARSE_NODE_IS_STRUCT_KIND(pn1, RULE_expr_stmt_augassign)
     804                 :            :                  || MP_PARSE_NODE_IS_STRUCT_KIND(pn1, RULE_expr_stmt_assign_list))) {
     805                 :            :             // this node is of the form <x> = <y>
     806                 :       9440 :             mp_parse_node_t pn0 = peek_result(parser, 1);
     807         [ +  + ]:       9440 :             if (MP_PARSE_NODE_IS_ID(pn0)
     808   [ +  +  +  + ]:       6852 :                 && MP_PARSE_NODE_IS_STRUCT_KIND(pn1, RULE_atom_expr_normal)
     809         [ +  + ]:       3307 :                 && MP_PARSE_NODE_IS_ID(((mp_parse_node_struct_t *)pn1)->nodes[0])
     810         [ +  + ]:       3285 :                 && MP_PARSE_NODE_LEAF_ARG(((mp_parse_node_struct_t *)pn1)->nodes[0]) == MP_QSTR_const
     811   [ +  -  +  -  :        109 :                 && MP_PARSE_NODE_IS_STRUCT_KIND(((mp_parse_node_struct_t *)pn1)->nodes[1], RULE_trailer_paren)
                   +  - ]
     812                 :            :                 ) {
     813                 :            :                 // code to assign dynamic constants: id = const(value)
     814                 :            : 
     815                 :            :                 // get the id
     816                 :        109 :                 qstr id = MP_PARSE_NODE_LEAF_ARG(pn0);
     817                 :            : 
     818                 :            :                 // get the value
     819                 :        109 :                 mp_parse_node_t pn_value = ((mp_parse_node_struct_t *)((mp_parse_node_struct_t *)pn1)->nodes[1])->nodes[0];
     820         [ +  + ]:        109 :                 if (!mp_parse_node_is_const(pn_value)) {
     821                 :         32 :                     mp_obj_t exc = mp_obj_new_exception_msg(&mp_type_SyntaxError,
     822                 :         32 :                         MP_ERROR_TEXT("not a constant"));
     823                 :         32 :                     mp_obj_exception_add_traceback(exc, parser->lexer->source_name,
     824                 :         32 :                         ((mp_parse_node_struct_t *)pn1)->source_line, MP_QSTRnull);
     825                 :         32 :                     nlr_raise(exc);
     826                 :            :                 }
     827                 :         77 :                 mp_obj_t value = mp_parse_node_convert_to_obj(pn_value);
     828                 :            : 
     829                 :            :                 // store the value in the table of dynamic constants
     830                 :         77 :                 mp_map_elem_t *elem = mp_map_lookup(&parser->consts, MP_OBJ_NEW_QSTR(id), MP_MAP_LOOKUP_ADD_IF_NOT_FOUND);
     831         [ -  + ]:         77 :                 assert(elem->value == MP_OBJ_NULL);
     832                 :         77 :                 elem->value = value;
     833                 :            : 
     834                 :            :                 // If the constant starts with an underscore then treat it as a private
     835                 :            :                 // variable and don't emit any code to store the value to the id.
     836         [ +  + ]:         77 :                 if (qstr_str(id)[0] == '_') {
     837                 :         46 :                     pop_result(parser); // pop const(value)
     838                 :         46 :                     pop_result(parser); // pop id
     839                 :         46 :                     push_result_rule(parser, 0, RULE_pass_stmt, 0); // replace with "pass"
     840                 :         46 :                     return true;
     841                 :            :                 }
     842                 :            : 
     843                 :            :                 // replace const(value) with value
     844                 :         31 :                 pop_result(parser);
     845                 :         31 :                 push_result_node(parser, pn_value);
     846                 :            : 
     847                 :            :                 // finished folding this assignment, but we still want it to be part of the tree
     848                 :         31 :                 return false;
     849                 :            :             }
     850                 :            :         }
     851                 :            :         return false;
     852                 :            :     #endif
     853                 :            : 
     854                 :            :     #if MICROPY_COMP_MODULE_CONST
     855                 :            :     } else if (rule_id == RULE_atom_expr_normal) {
     856                 :      51354 :         mp_parse_node_t pn0 = peek_result(parser, 1);
     857                 :      51354 :         mp_parse_node_t pn1 = peek_result(parser, 0);
     858   [ +  +  +  - ]:      51354 :         if (!(MP_PARSE_NODE_IS_ID(pn0)
     859   [ +  -  +  + ]:      49763 :               && MP_PARSE_NODE_IS_STRUCT_KIND(pn1, RULE_trailer_period))) {
     860                 :      50818 :             return false;
     861                 :            :         }
     862                 :            :         // id1.id2
     863                 :            :         // look it up in constant table, see if it can be replaced with an integer
     864                 :       5782 :         mp_parse_node_struct_t *pns1 = (mp_parse_node_struct_t *)pn1;
     865         [ -  + ]:       5782 :         assert(MP_PARSE_NODE_IS_ID(pns1->nodes[0]));
     866                 :       5782 :         qstr q_base = MP_PARSE_NODE_LEAF_ARG(pn0);
     867                 :       5782 :         qstr q_attr = MP_PARSE_NODE_LEAF_ARG(pns1->nodes[0]);
     868                 :       5782 :         mp_map_elem_t *elem = mp_map_lookup((mp_map_t *)&mp_constants_map, MP_OBJ_NEW_QSTR(q_base), MP_MAP_LOOKUP);
     869         [ +  + ]:       5782 :         if (elem == NULL) {
     870                 :            :             return false;
     871                 :            :         }
     872                 :        540 :         mp_obj_t dest[2];
     873                 :        540 :         mp_load_method_maybe(elem->value, q_attr, dest);
     874   [ +  -  +  +  :        540 :         if (!(dest[0] != MP_OBJ_NULL && mp_obj_is_int(dest[0]) && dest[1] == MP_OBJ_NULL)) {
          +  +  -  +  +  
                      - ]
     875                 :            :             return false;
     876                 :            :         }
     877                 :        536 :         arg0 = dest[0];
     878                 :            :     #endif
     879                 :            : 
     880                 :            :     } else {
     881                 :            :         return false;
     882                 :            :     }
     883                 :            : 
     884                 :            :     // success folding this rule
     885                 :            : 
     886         [ +  + ]:      10267 :     for (size_t i = num_args; i > 0; i--) {
     887                 :       7036 :         pop_result(parser);
     888                 :            :     }
     889                 :       3231 :     push_result_node(parser, make_node_const_object_optimised(parser, 0, arg0));
     890                 :            : 
     891                 :       3231 :     return true;
     892                 :            : }
     893                 :            : 
     894                 :            : #endif // MICROPY_COMP_CONST_FOLDING
     895                 :            : 
     896                 :            : #if MICROPY_COMP_CONST_TUPLE
     897                 :       2445 : static bool build_tuple_from_stack(parser_t *parser, size_t src_line, size_t num_args) {
     898         [ +  + ]:       6248 :     for (size_t i = num_args; i > 0;) {
     899                 :       5054 :         mp_parse_node_t pn = peek_result(parser, --i);
     900         [ +  + ]:       5054 :         if (!mp_parse_node_is_const(pn)) {
     901                 :            :             return false;
     902                 :            :         }
     903                 :            :     }
     904                 :       1194 :     mp_obj_tuple_t *tuple = MP_OBJ_TO_PTR(mp_obj_new_tuple(num_args, NULL));
     905         [ +  + ]:       4510 :     for (size_t i = num_args; i > 0;) {
     906                 :       3316 :         mp_parse_node_t pn = pop_result(parser);
     907                 :       3316 :         tuple->items[--i] = mp_parse_node_convert_to_obj(pn);
     908   [ +  -  +  + ]:       3316 :         if (MP_PARSE_NODE_IS_STRUCT(pn)) {
     909                 :        292 :             parser_free_parse_node_struct(parser, (mp_parse_node_struct_t *)pn);
     910                 :            :         }
     911                 :            :     }
     912                 :       1194 :     push_result_node(parser, make_node_const_object(parser, src_line, MP_OBJ_FROM_PTR(tuple)));
     913                 :       1194 :     return true;
     914                 :            : }
     915                 :            : 
     916                 :     253398 : static bool build_tuple(parser_t *parser, size_t src_line, uint8_t rule_id, size_t num_args) {
     917         [ +  + ]:     253398 :     if (rule_id == RULE_testlist_comp) {
     918         [ +  + ]:       1877 :         if (peek_rule(parser, 0) == RULE_atom_paren) {
     919                 :            :             // Tuple of the form "(a,)".
     920                 :       1395 :             return build_tuple_from_stack(parser, src_line, num_args);
     921                 :            :         }
     922                 :            :     }
     923         [ +  + ]:     252003 :     if (rule_id == RULE_testlist_comp_3c) {
     924         [ -  + ]:       1146 :         assert(peek_rule(parser, 0) == RULE_testlist_comp_3b);
     925         [ -  + ]:       1146 :         assert(peek_rule(parser, 1) == RULE_testlist_comp);
     926         [ +  + ]:       1146 :         if (peek_rule(parser, 2) == RULE_atom_paren) {
     927                 :            :             // Tuple of the form "(a, b)".
     928         [ +  + ]:        722 :             if (build_tuple_from_stack(parser, src_line, num_args)) {
     929                 :        410 :                 parser->rule_stack_top -= 2; // discard 2 rules
     930                 :        410 :                 return true;
     931                 :            :             }
     932                 :            :         }
     933                 :            :     }
     934                 :     251593 :     if (rule_id == RULE_testlist_star_expr
     935         [ +  + ]:     251593 :         || rule_id == RULE_testlist
     936                 :            :         || rule_id == RULE_subscriptlist) {
     937                 :            :         // Tuple of the form:
     938                 :            :         //  - x = a, b
     939                 :            :         //  - return a, b
     940                 :            :         //  - for x in a, b: pass
     941                 :            :         //  - x[a, b]
     942                 :        328 :         return build_tuple_from_stack(parser, src_line, num_args);
     943                 :            :     }
     944                 :            : 
     945                 :            :     return false;
     946                 :            : }
     947                 :            : #endif
     948                 :            : 
     949                 :     259465 : static void push_result_rule(parser_t *parser, size_t src_line, uint8_t rule_id, size_t num_args) {
     950                 :            :     // Simplify and optimise certain rules, to reduce memory usage and simplify the compiler.
     951         [ +  + ]:     259465 :     if (rule_id == RULE_atom_paren) {
     952                 :            :         // Remove parenthesis around a single expression if possible.
     953                 :            :         // This atom_paren rule always has a single argument, and after this
     954                 :            :         // optimisation that argument is either NULL or testlist_comp.
     955                 :       3125 :         mp_parse_node_t pn = peek_result(parser, 0);
     956         [ +  + ]:       3125 :         if (MP_PARSE_NODE_IS_NULL(pn)) {
     957                 :            :             // need to keep parenthesis for ()
     958   [ +  +  +  + ]:       2900 :         } else if (MP_PARSE_NODE_IS_STRUCT_KIND(pn, RULE_testlist_comp)) {
     959                 :            :             // need to keep parenthesis for (a, b, ...)
     960                 :            :         } else {
     961                 :            :             // parenthesis around a single expression, so it's just the expression
     962                 :            :             return;
     963                 :            :         }
     964         [ +  + ]:     256340 :     } else if (rule_id == RULE_testlist_comp) {
     965                 :            :         // The testlist_comp rule can be the sole argument to either atom_parent
     966                 :            :         // or atom_bracket, for (...) and [...] respectively.
     967         [ -  + ]:       2613 :         assert(num_args == 2);
     968                 :       2613 :         mp_parse_node_t pn = peek_result(parser, 0);
     969   [ +  -  +  + ]:       2613 :         if (MP_PARSE_NODE_IS_STRUCT(pn)) {
     970                 :       1470 :             mp_parse_node_struct_t *pns = (mp_parse_node_struct_t *)pn;
     971         [ +  + ]:       1470 :             if (MP_PARSE_NODE_STRUCT_KIND(pns) == RULE_testlist_comp_3b) {
     972                 :            :                 // tuple of one item, with trailing comma
     973                 :        247 :                 pop_result(parser);
     974                 :        247 :                 --num_args;
     975         [ +  + ]:       1223 :             } else if (MP_PARSE_NODE_STRUCT_KIND(pns) == RULE_testlist_comp_3c) {
     976                 :            :                 // tuple of many items, convert testlist_comp_3c to testlist_comp
     977                 :        736 :                 pop_result(parser);
     978         [ -  + ]:        736 :                 assert(pn == peek_result(parser, 0));
     979                 :        736 :                 pns->kind_num_nodes = rule_id | MP_PARSE_NODE_STRUCT_NUM_NODES(pns) << 8;
     980                 :        736 :                 return;
     981                 :            :             } else if (MP_PARSE_NODE_STRUCT_KIND(pns) == RULE_comp_for) {
     982                 :            :                 // generator expression
     983                 :            :             } else {
     984                 :            :                 // tuple with 2 items
     985                 :            :             }
     986                 :            :         } else {
     987                 :            :             // tuple with 2 items
     988                 :            :         }
     989         [ +  + ]:     253727 :     } else if (rule_id == RULE_testlist_comp_3c) {
     990                 :            :         // steal first arg of outer testlist_comp rule
     991                 :       1146 :         ++num_args;
     992                 :            :     }
     993                 :            : 
     994                 :            :     #if MICROPY_COMP_CONST_FOLDING
     995         [ +  + ]:     256802 :     if (fold_logical_constants(parser, rule_id, &num_args)) {
     996                 :            :         // we folded this rule so return straight away
     997                 :            :         return;
     998                 :            :     }
     999         [ +  + ]:     256708 :     if (fold_constants(parser, rule_id, num_args)) {
    1000                 :            :         // we folded this rule so return straight away
    1001                 :            :         return;
    1002                 :            :     }
    1003                 :            :     #endif
    1004                 :            : 
    1005                 :            :     #if MICROPY_COMP_CONST_TUPLE
    1006         [ +  + ]:     253398 :     if (build_tuple(parser, src_line, rule_id, num_args)) {
    1007                 :            :         // we built a tuple from this rule so return straight away
    1008                 :            :         return;
    1009                 :            :     }
    1010                 :            :     #endif
    1011                 :            : 
    1012                 :     252204 :     mp_parse_node_struct_t *pn = parser_alloc(parser, sizeof(mp_parse_node_struct_t) + sizeof(mp_parse_node_t) * num_args);
    1013                 :     252204 :     pn->source_line = src_line;
    1014                 :     252204 :     pn->kind_num_nodes = (rule_id & 0xff) | (num_args << 8);
    1015         [ +  + ]:     740380 :     for (size_t i = num_args; i > 0; i--) {
    1016                 :     488176 :         pn->nodes[i - 1] = pop_result(parser);
    1017                 :            :     }
    1018         [ +  + ]:     252204 :     if (rule_id == RULE_testlist_comp_3c) {
    1019                 :            :         // need to push something non-null to replace stolen first arg of testlist_comp
    1020                 :        736 :         push_result_node(parser, (mp_parse_node_t)pn);
    1021                 :            :     }
    1022                 :     252204 :     push_result_node(parser, (mp_parse_node_t)pn);
    1023                 :            : }
    1024                 :            : 
    1025                 :       3936 : mp_parse_tree_t mp_parse(mp_lexer_t *lex, mp_parse_input_kind_t input_kind) {
    1026                 :            :     // Set exception handler to free the lexer if an exception is raised.
    1027                 :       3936 :     MP_DEFINE_NLR_JUMP_CALLBACK_FUNCTION_1(ctx, mp_lexer_free, lex);
    1028                 :       3936 :     nlr_push_jump_callback(&ctx.callback, mp_call_function_1_from_nlr_jump_callback);
    1029                 :            : 
    1030                 :            :     // initialise parser and allocate memory for its stacks
    1031                 :            : 
    1032                 :       3936 :     parser_t parser;
    1033                 :            : 
    1034                 :       3936 :     parser.rule_stack_alloc = MICROPY_ALLOC_PARSE_RULE_INIT;
    1035                 :       3936 :     parser.rule_stack_top = 0;
    1036                 :       3936 :     parser.rule_stack = m_new(rule_stack_t, parser.rule_stack_alloc);
    1037                 :            : 
    1038                 :       3936 :     parser.result_stack_alloc = MICROPY_ALLOC_PARSE_RESULT_INIT;
    1039                 :       3936 :     parser.result_stack_top = 0;
    1040                 :       3936 :     parser.result_stack = m_new(mp_parse_node_t, parser.result_stack_alloc);
    1041                 :            : 
    1042                 :       3936 :     parser.lexer = lex;
    1043                 :            : 
    1044                 :       3936 :     parser.tree.chunk = NULL;
    1045                 :       3936 :     parser.cur_chunk = NULL;
    1046                 :            : 
    1047                 :            :     #if MICROPY_COMP_CONST
    1048                 :       3936 :     mp_map_init(&parser.consts, 0);
    1049                 :            :     #endif
    1050                 :            : 
    1051                 :            :     // work out the top-level rule to use, and push it on the stack
    1052                 :       3936 :     size_t top_level_rule;
    1053      [ +  +  + ]:       3936 :     switch (input_kind) {
    1054                 :            :         case MP_PARSE_SINGLE_INPUT:
    1055                 :            :             top_level_rule = RULE_single_input;
    1056                 :            :             break;
    1057                 :        378 :         case MP_PARSE_EVAL_INPUT:
    1058                 :        378 :             top_level_rule = RULE_eval_input;
    1059                 :        378 :             break;
    1060                 :       3335 :         default:
    1061                 :       3335 :             top_level_rule = RULE_file_input;
    1062                 :            :     }
    1063                 :       3936 :     push_rule(&parser, lex->tok_line, top_level_rule, 0);
    1064                 :            : 
    1065                 :            :     // parse!
    1066                 :            : 
    1067                 :       3936 :     bool backtrack = false;
    1068                 :            : 
    1069                 :    2878380 :     for (;;) {
    1070                 :   17735630 :     next_rule:
    1071         [ +  + ]:   17739566 :         if (parser.rule_stack_top == 0) {
    1072                 :            :             break;
    1073                 :            :         }
    1074                 :            : 
    1075                 :            :         // Pop the next rule to process it
    1076                 :   17735724 :         size_t i; // state for the current rule
    1077                 :   17735724 :         size_t rule_src_line; // source line for the first token matched by the current rule
    1078                 :   17735724 :         uint8_t rule_id = pop_rule(&parser, &i, &rule_src_line);
    1079                 :   17735399 :         uint8_t rule_act = rule_act_table[rule_id];
    1080                 :   17735399 :         const uint16_t *rule_arg = get_rule_arg(rule_id);
    1081                 :   17735399 :         size_t n = rule_act & RULE_ACT_ARG_MASK;
    1082                 :            : 
    1083                 :            :         #if 0
    1084                 :            :         // debugging
    1085                 :            :         printf("depth=" UINT_FMT " ", parser.rule_stack_top);
    1086                 :            :         for (int j = 0; j < parser.rule_stack_top; ++j) {
    1087                 :            :             printf(" ");
    1088                 :            :         }
    1089                 :            :         printf("%s n=" UINT_FMT " i=" UINT_FMT " bt=%d\n", rule_name_table[rule_id], n, i, backtrack);
    1090                 :            :         #endif
    1091                 :            : 
    1092      [ +  +  + ]:   17735399 :         switch (rule_act & RULE_ACT_KIND_MASK) {
    1093                 :    5901768 :             case RULE_ACT_OR:
    1094   [ +  +  +  + ]:    5901768 :                 if (i > 0 && !backtrack) {
    1095                 :     143840 :                     goto next_rule;
    1096                 :            :                 } else {
    1097                 :    9573234 :                     backtrack = false;
    1098                 :            :                 }
    1099         [ +  + ]:    9573234 :                 for (; i < n; ++i) {
    1100                 :    8926206 :                     uint16_t kind = rule_arg[i] & RULE_ARG_KIND_MASK;
    1101         [ +  + ]:    8926206 :                     if (kind == RULE_ARG_TOK) {
    1102         [ +  + ]:    3965287 :                         if (lex->tok_kind == (rule_arg[i] & RULE_ARG_ARG_MASK)) {
    1103                 :     149981 :                             push_result_token(&parser, rule_id);
    1104                 :     149958 :                             mp_lexer_to_next(lex);
    1105                 :     149957 :                             goto next_rule;
    1106                 :            :                         }
    1107                 :            :                     } else {
    1108         [ -  + ]:    4960919 :                         assert(kind == RULE_ARG_RULE);
    1109         [ +  + ]:    4960919 :                         if (i + 1 < n) {
    1110                 :    3286733 :                             push_rule(&parser, rule_src_line, rule_id, i + 1); // save this or-rule
    1111                 :            :                         }
    1112                 :    4960801 :                         push_rule_from_arg(&parser, rule_arg[i]); // push child of or-rule
    1113                 :    4960761 :                         goto next_rule;
    1114                 :            :                     }
    1115                 :            :                 }
    1116                 :            :                 backtrack = true;
    1117                 :            :                 break;
    1118                 :            : 
    1119                 :    6849479 :             case RULE_ACT_AND: {
    1120                 :            : 
    1121                 :            :                 // failed, backtrack if we can, else syntax error
    1122         [ +  + ]:    6849479 :                 if (backtrack) {
    1123         [ -  + ]:    1071856 :                     assert(i > 0);
    1124         [ +  + ]:    1071856 :                     if ((rule_arg[i - 1] & RULE_ARG_KIND_MASK) == RULE_ARG_OPT_RULE) {
    1125                 :            :                         // an optional rule that failed, so continue with next arg
    1126                 :     518655 :                         push_result_node(&parser, MP_PARSE_NODE_NULL);
    1127                 :     518655 :                         backtrack = false;
    1128                 :            :                     } else {
    1129                 :            :                         // a mandatory rule that failed, so propagate backtrack
    1130         [ +  + ]:     553201 :                         if (i > 1) {
    1131                 :            :                             // already eaten tokens so can't backtrack
    1132                 :         38 :                             goto syntax_error;
    1133                 :            :                         } else {
    1134                 :     553197 :                             goto next_rule;
    1135                 :            :                         }
    1136                 :            :                     }
    1137                 :            :                 }
    1138                 :            : 
    1139                 :            :                 // progress through the rule
    1140         [ +  + ]:    6664000 :                 for (; i < n; ++i) {
    1141         [ +  + ]:    5909409 :                     if ((rule_arg[i] & RULE_ARG_KIND_MASK) == RULE_ARG_TOK) {
    1142                 :            :                         // need to match a token
    1143                 :    4030118 :                         mp_token_kind_t tok_kind = rule_arg[i] & RULE_ARG_ARG_MASK;
    1144         [ +  + ]:    4030118 :                         if (lex->tok_kind == tok_kind) {
    1145                 :            :                             // matched token
    1146         [ +  + ]:     367168 :                             if (tok_kind == MP_TOKEN_NAME) {
    1147                 :      30144 :                                 push_result_token(&parser, rule_id);
    1148                 :            :                             }
    1149                 :     367168 :                             mp_lexer_to_next(lex);
    1150                 :            :                         } else {
    1151                 :            :                             // failed to match token
    1152         [ +  + ]:    3662950 :                             if (i > 0) {
    1153                 :            :                                 // already eaten tokens so can't backtrack
    1154                 :         30 :                                 goto syntax_error;
    1155                 :            :                             } else {
    1156                 :            :                                 // this rule failed, so backtrack
    1157                 :    3662920 :                                 backtrack = true;
    1158                 :    3662920 :                                 goto next_rule;
    1159                 :            :                             }
    1160                 :            :                         }
    1161                 :            :                     } else {
    1162                 :    1879291 :                         push_rule(&parser, rule_src_line, rule_id, i + 1); // save this and-rule
    1163                 :    1879242 :                         push_rule_from_arg(&parser, rule_arg[i]); // push child of and-rule
    1164                 :    1879217 :                         goto next_rule;
    1165                 :            :                     }
    1166                 :            :                 }
    1167                 :            : 
    1168         [ -  + ]:     754591 :                 assert(i == n);
    1169                 :            : 
    1170                 :            :                 // matched the rule, so now build the corresponding parse_node
    1171                 :            : 
    1172                 :            :                 #if !MICROPY_ENABLE_DOC_STRING
    1173                 :            :                 // this code discards lonely statements, such as doc strings
    1174   [ +  +  +  + ]:     754591 :                 if (input_kind != MP_PARSE_SINGLE_INPUT && rule_id == RULE_expr_stmt && peek_result(&parser, 0) == MP_PARSE_NODE_NULL) {
    1175                 :      25616 :                     mp_parse_node_t p = peek_result(&parser, 1);
    1176   [ +  +  +  + ]:      25616 :                     if ((MP_PARSE_NODE_IS_LEAF(p) && !MP_PARSE_NODE_IS_ID(p))
    1177   [ +  -  +  +  :      25594 :                         || MP_PARSE_NODE_IS_STRUCT_KIND(p, RULE_const_object)) {
                   -  + ]
    1178                 :         22 :                         pop_result(&parser); // MP_PARSE_NODE_NULL
    1179                 :         22 :                         pop_result(&parser); // const expression (leaf or RULE_const_object)
    1180                 :            :                         // Pushing the "pass" rule here will overwrite any RULE_const_object
    1181                 :            :                         // entry that was on the result stack, allowing the GC to reclaim
    1182                 :            :                         // the memory from the const object when needed.
    1183                 :         22 :                         push_result_rule(&parser, rule_src_line, RULE_pass_stmt, 0);
    1184                 :         22 :                         break;
    1185                 :            :                     }
    1186                 :            :                 }
    1187                 :            :                 #endif
    1188                 :            : 
    1189                 :            :                 // count number of arguments for the parse node
    1190                 :     754569 :                 i = 0;
    1191                 :     754569 :                 size_t num_not_nil = 0;
    1192         [ +  + ]:    2445622 :                 for (size_t x = n; x > 0;) {
    1193                 :    1691050 :                     --x;
    1194         [ +  + ]:    1691050 :                     if ((rule_arg[x] & RULE_ARG_KIND_MASK) == RULE_ARG_TOK) {
    1195                 :     366684 :                         mp_token_kind_t tok_kind = rule_arg[x] & RULE_ARG_ARG_MASK;
    1196         [ +  + ]:     366684 :                         if (tok_kind == MP_TOKEN_NAME) {
    1197                 :            :                             // only tokens which were names are pushed to stack
    1198                 :      30140 :                             i += 1;
    1199                 :      30140 :                             num_not_nil += 1;
    1200                 :            :                         }
    1201                 :            :                     } else {
    1202                 :            :                         // rules are always pushed
    1203         [ +  + ]:    1324366 :                         if (peek_result(&parser, i) != MP_PARSE_NODE_NULL) {
    1204                 :     805753 :                             num_not_nil += 1;
    1205                 :            :                         }
    1206                 :    1324369 :                         i += 1;
    1207                 :            :                     }
    1208                 :            :                 }
    1209                 :            : 
    1210   [ +  +  +  + ]:    1294479 :                 if (num_not_nil == 1 && (rule_act & RULE_ACT_ALLOW_IDENT)) {
    1211                 :            :                     // this rule has only 1 argument and should not be emitted
    1212                 :            :                     mp_parse_node_t pn = MP_PARSE_NODE_NULL;
    1213         [ +  + ]:    1540993 :                     for (size_t x = 0; x < i; ++x) {
    1214                 :    1001085 :                         mp_parse_node_t pn2 = pop_result(&parser);
    1215         [ +  + ]:    1001085 :                         if (pn2 != MP_PARSE_NODE_NULL) {
    1216                 :     539908 :                             pn = pn2;
    1217                 :            :                         }
    1218                 :            :                     }
    1219                 :     539908 :                     push_result_node(&parser, pn);
    1220                 :            :                 } else {
    1221                 :            :                     // this rule must be emitted
    1222                 :            : 
    1223         [ +  + ]:     214664 :                     if (rule_act & RULE_ACT_ADD_BLANK) {
    1224                 :            :                         // and add an extra blank node at the end (used by the compiler to store data)
    1225                 :       5846 :                         push_result_node(&parser, MP_PARSE_NODE_NULL);
    1226                 :       5846 :                         i += 1;
    1227                 :            :                     }
    1228                 :            : 
    1229                 :     214664 :                     push_result_rule(&parser, rule_src_line, rule_id, i);
    1230                 :            :                 }
    1231                 :            :                 break;
    1232                 :            :             }
    1233                 :            : 
    1234                 :    4984152 :             default: {
    1235         [ -  + ]:    4984152 :                 assert((rule_act & RULE_ACT_KIND_MASK) == RULE_ACT_LIST);
    1236                 :            : 
    1237                 :            :                 // n=2 is: item item*
    1238                 :            :                 // n=1 is: item (sep item)*
    1239                 :            :                 // n=3 is: item (sep item)* [sep]
    1240                 :    4984152 :                 bool had_trailing_sep;
    1241         [ +  + ]:    4984152 :                 if (backtrack) {
    1242                 :    1291996 :                 list_backtrack:
    1243                 :    2120287 :                     had_trailing_sep = false;
    1244         [ +  + ]:    2120287 :                     if (n == 2) {
    1245         [ +  + ]:     283000 :                         if (i == 1) {
    1246                 :            :                             // fail on item, first time round; propagate backtrack
    1247                 :     190699 :                             goto next_rule;
    1248                 :            :                         } else {
    1249                 :            :                             // fail on item, in later rounds; finish with this rule
    1250                 :            :                             backtrack = false;
    1251                 :            :                         }
    1252                 :            :                     } else {
    1253         [ +  + ]:    1837287 :                         if (i == 1) {
    1254                 :            :                             // fail on item, first time round; propagate backtrack
    1255                 :     452793 :                             goto next_rule;
    1256         [ +  + ]:    1384494 :                         } else if ((i & 1) == 1) {
    1257                 :            :                             // fail on item, in later rounds; have eaten tokens so can't backtrack
    1258         [ +  + ]:        397 :                             if (n == 3) {
    1259                 :            :                                 // list allows trailing separator; finish parsing list
    1260                 :            :                                 had_trailing_sep = true;
    1261                 :            :                                 backtrack = false;
    1262                 :            :                             } else {
    1263                 :            :                                 // list doesn't allowing trailing separator; fail
    1264                 :          4 :                                 goto syntax_error;
    1265                 :            :                             }
    1266                 :            :                         } else {
    1267                 :            :                             // fail on separator; finish parsing list
    1268                 :            :                             backtrack = false;
    1269                 :            :                         }
    1270                 :            :                     }
    1271                 :            :                 } else {
    1272                 :    3750484 :                     for (;;) {
    1273                 :    3721320 :                         size_t arg = rule_arg[i & 1 & n];
    1274         [ +  + ]:    3721320 :                         if ((arg & RULE_ARG_KIND_MASK) == RULE_ARG_TOK) {
    1275         [ +  + ]:     857361 :                             if (lex->tok_kind == (arg & RULE_ARG_ARG_MASK)) {
    1276         [ +  + ]:      29070 :                                 if (i & 1 & n) {
    1277                 :            :                                     // separators which are tokens are not pushed to result stack
    1278                 :            :                                 } else {
    1279                 :       2881 :                                     push_result_token(&parser, rule_id);
    1280                 :            :                                 }
    1281                 :      29070 :                                 mp_lexer_to_next(lex);
    1282                 :            :                                 // got element of list, so continue parsing list
    1283                 :      29164 :                                 i += 1;
    1284                 :            :                             } else {
    1285                 :            :                                 // couldn't get element of list
    1286                 :     828291 :                                 i += 1;
    1287                 :     828291 :                                 backtrack = true;
    1288                 :     828291 :                                 goto list_backtrack;
    1289                 :            :                             }
    1290                 :            :                         } else {
    1291         [ -  + ]:    2863959 :                             assert((arg & RULE_ARG_KIND_MASK) == RULE_ARG_RULE);
    1292                 :    2863959 :                             push_rule(&parser, rule_src_line, rule_id, i + 1); // save this list-rule
    1293                 :    2863908 :                             push_rule_from_arg(&parser, arg); // push child of list-rule
    1294                 :    2863866 :                             goto next_rule;
    1295                 :            :                         }
    1296                 :            :                     }
    1297                 :            :                 }
    1298         [ -  + ]:    1476791 :                 assert(i >= 1);
    1299                 :            : 
    1300                 :            :                 // compute number of elements in list, result in i
    1301                 :    1476791 :                 i -= 1;
    1302   [ +  +  +  + ]:    1476791 :                 if ((n & 1) && (rule_arg[1] & RULE_ARG_KIND_MASK) == RULE_ARG_TOK) {
    1303                 :            :                     // don't count separators when they are tokens
    1304                 :     828497 :                     i = (i + 1) / 2;
    1305                 :            :                 }
    1306                 :            : 
    1307         [ +  + ]:    1476791 :                 if (i == 1) {
    1308                 :            :                     // list matched single item
    1309         [ +  + ]:    1432236 :                     if (had_trailing_sep) {
    1310                 :            :                         // if there was a trailing separator, make a list of a single item
    1311                 :        177 :                         push_result_rule(&parser, rule_src_line, rule_id, i);
    1312                 :            :                     } else {
    1313                 :            :                         // just leave single item on stack (ie don't wrap in a list)
    1314                 :            :                     }
    1315                 :            :                 } else {
    1316                 :      44555 :                     push_result_rule(&parser, rule_src_line, rule_id, i);
    1317                 :            :                 }
    1318                 :            :                 break;
    1319                 :            :             }
    1320                 :            :         }
    1321                 :            :     }
    1322                 :            : 
    1323                 :            :     #if MICROPY_COMP_CONST
    1324                 :       3842 :     mp_map_deinit(&parser.consts);
    1325                 :            :     #endif
    1326                 :            : 
    1327                 :            :     // truncate final chunk and link into chain of chunks
    1328         [ +  + ]:       3842 :     if (parser.cur_chunk != NULL) {
    1329                 :       3709 :         (void)m_renew_maybe(byte, parser.cur_chunk,
    1330                 :            :             sizeof(mp_parse_chunk_t) + parser.cur_chunk->alloc,
    1331                 :            :             sizeof(mp_parse_chunk_t) + parser.cur_chunk->union_.used,
    1332                 :            :             false);
    1333                 :       3709 :         parser.cur_chunk->alloc = parser.cur_chunk->union_.used;
    1334                 :       3709 :         parser.cur_chunk->union_.next = parser.tree.chunk;
    1335                 :       3709 :         parser.tree.chunk = parser.cur_chunk;
    1336                 :            :     }
    1337                 :            : 
    1338                 :       3842 :     if (
    1339         [ +  + ]:       3842 :         lex->tok_kind != MP_TOKEN_END // check we are at the end of the token stream
    1340         [ +  + ]:       3796 :         || parser.result_stack_top == 0 // check that we got a node (can fail on empty input)
    1341                 :            :         ) {
    1342                 :         54 :     syntax_error:;
    1343                 :         92 :         mp_obj_t exc;
    1344         [ +  + ]:         92 :         if (lex->tok_kind == MP_TOKEN_INDENT) {
    1345                 :          4 :             exc = mp_obj_new_exception_msg(&mp_type_IndentationError,
    1346                 :          4 :                 MP_ERROR_TEXT("unexpected indent"));
    1347         [ +  + ]:         88 :         } else if (lex->tok_kind == MP_TOKEN_DEDENT_MISMATCH) {
    1348                 :          4 :             exc = mp_obj_new_exception_msg(&mp_type_IndentationError,
    1349                 :          4 :                 MP_ERROR_TEXT("unindent doesn't match any outer indent level"));
    1350                 :            :         #if MICROPY_PY_FSTRINGS
    1351         [ -  + ]:         84 :         } else if (lex->tok_kind == MP_TOKEN_MALFORMED_FSTRING) {
    1352                 :          0 :             exc = mp_obj_new_exception_msg(&mp_type_SyntaxError,
    1353                 :          0 :                 MP_ERROR_TEXT("malformed f-string"));
    1354         [ -  + ]:         84 :         } else if (lex->tok_kind == MP_TOKEN_FSTRING_RAW) {
    1355                 :          0 :             exc = mp_obj_new_exception_msg(&mp_type_SyntaxError,
    1356                 :          0 :                 MP_ERROR_TEXT("raw f-strings are not supported"));
    1357                 :            :         #endif
    1358                 :            :         } else {
    1359                 :         84 :             exc = mp_obj_new_exception_msg(&mp_type_SyntaxError,
    1360                 :         84 :                 MP_ERROR_TEXT("invalid syntax"));
    1361                 :            :         }
    1362                 :            :         // add traceback to give info about file name and location
    1363                 :            :         // we don't have a 'block' name, so just pass the NULL qstr to indicate this
    1364                 :         92 :         mp_obj_exception_add_traceback(exc, lex->source_name, lex->tok_line, MP_QSTRnull);
    1365                 :         92 :         nlr_raise(exc);
    1366                 :            :     }
    1367                 :            : 
    1368                 :            :     // get the root parse node that we created
    1369         [ -  + ]:       3788 :     assert(parser.result_stack_top == 1);
    1370                 :       3788 :     parser.tree.root = parser.result_stack[0];
    1371                 :            : 
    1372                 :            :     // free the memory that we don't need anymore
    1373                 :       3788 :     m_del(rule_stack_t, parser.rule_stack, parser.rule_stack_alloc);
    1374                 :       3788 :     m_del(mp_parse_node_t, parser.result_stack, parser.result_stack_alloc);
    1375                 :            : 
    1376                 :            :     // Deregister exception handler and free the lexer.
    1377                 :       3788 :     nlr_pop_jump_callback(true);
    1378                 :            : 
    1379                 :       3788 :     return parser.tree;
    1380                 :            : }
    1381                 :            : 
    1382                 :       3766 : void mp_parse_tree_clear(mp_parse_tree_t *tree) {
    1383                 :       3766 :     mp_parse_chunk_t *chunk = tree->chunk;
    1384         [ +  + ]:      16228 :     while (chunk != NULL) {
    1385                 :      12462 :         mp_parse_chunk_t *next = chunk->union_.next;
    1386                 :      12462 :         m_del(byte, chunk, sizeof(mp_parse_chunk_t) + chunk->alloc);
    1387                 :      12462 :         chunk = next;
    1388                 :            :     }
    1389                 :       3766 :     tree->chunk = NULL; // Avoid dangling pointer that may live on stack
    1390                 :       3766 : }
    1391                 :            : 
    1392                 :            : #endif // MICROPY_ENABLE_COMPILER

Generated by: LCOV version 1.15-5-g462f71d