LCOV - code coverage report
Current view: top level - extmod - modre.c (source / functions) Hit Total Coverage
Test: unix_coverage_v1.24.0-7-g548babf8a.info Lines: 187 187 100.0 %
Date: 2024-10-30 09:06:48 Functions: 14 14 100.0 %
Branches: 86 94 91.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) 2014 Paul Sokolovsky
       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 <stdio.h>
      28                 :            : #include <assert.h>
      29                 :            : #include <string.h>
      30                 :            : 
      31                 :            : #include "py/runtime.h"
      32                 :            : #include "py/binary.h"
      33                 :            : #include "py/objstr.h"
      34                 :            : #include "py/cstack.h"
      35                 :            : 
      36                 :            : #if MICROPY_PY_BUILTINS_STR_UNICODE
      37                 :            : #include "py/unicode.h"
      38                 :            : #endif
      39                 :            : 
      40                 :            : #if MICROPY_PY_RE
      41                 :            : 
      42                 :            : #define re1_5_stack_chk() mp_cstack_check()
      43                 :            : 
      44                 :            : #include "lib/re1.5/re1.5.h"
      45                 :            : 
      46                 :            : #define FLAG_DEBUG 0x1000
      47                 :            : 
      48                 :            : typedef struct _mp_obj_re_t {
      49                 :            :     mp_obj_base_t base;
      50                 :            :     ByteProg re;
      51                 :            : } mp_obj_re_t;
      52                 :            : 
      53                 :            : typedef struct _mp_obj_match_t {
      54                 :            :     mp_obj_base_t base;
      55                 :            :     int num_matches;
      56                 :            :     mp_obj_t str;
      57                 :            :     const char *caps[0];
      58                 :            : } mp_obj_match_t;
      59                 :            : 
      60                 :            : static mp_obj_t mod_re_compile(size_t n_args, const mp_obj_t *args);
      61                 :            : #if !MICROPY_ENABLE_DYNRUNTIME
      62                 :            : static const mp_obj_type_t re_type;
      63                 :            : #endif
      64                 :            : 
      65                 :          2 : static void match_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
      66                 :          2 :     (void)kind;
      67                 :          2 :     mp_obj_match_t *self = MP_OBJ_TO_PTR(self_in);
      68                 :          2 :     mp_printf(print, "<match num=%d>", self->num_matches);
      69                 :          2 : }
      70                 :            : 
      71                 :        208 : static mp_obj_t match_group(mp_obj_t self_in, mp_obj_t no_in) {
      72                 :        208 :     mp_obj_match_t *self = MP_OBJ_TO_PTR(self_in);
      73                 :        208 :     mp_int_t no = mp_obj_get_int(no_in);
      74   [ +  -  +  + ]:        208 :     if (no < 0 || no >= self->num_matches) {
      75                 :         28 :         mp_raise_type_arg(&mp_type_IndexError, no_in);
      76                 :            :     }
      77                 :            : 
      78                 :        180 :     const char *start = self->caps[no * 2];
      79         [ +  + ]:        180 :     if (start == NULL) {
      80                 :            :         // no match for this group
      81                 :            :         return mp_const_none;
      82                 :            :     }
      83                 :        176 :     return mp_obj_new_str_of_type(mp_obj_get_type(self->str),
      84                 :        176 :         (const byte *)start, self->caps[no * 2 + 1] - start);
      85                 :            : }
      86                 :            : MP_DEFINE_CONST_FUN_OBJ_2(match_group_obj, match_group);
      87                 :            : 
      88                 :            : #if MICROPY_PY_RE_MATCH_GROUPS
      89                 :            : 
      90                 :         10 : static mp_obj_t match_groups(mp_obj_t self_in) {
      91                 :         10 :     mp_obj_match_t *self = MP_OBJ_TO_PTR(self_in);
      92         [ +  + ]:         10 :     if (self->num_matches <= 1) {
      93                 :            :         return mp_const_empty_tuple;
      94                 :            :     }
      95                 :          8 :     mp_obj_tuple_t *groups = MP_OBJ_TO_PTR(mp_obj_new_tuple(self->num_matches - 1, NULL));
      96         [ +  + ]:         30 :     for (int i = 1; i < self->num_matches; ++i) {
      97                 :         22 :         groups->items[i - 1] = match_group(self_in, MP_OBJ_NEW_SMALL_INT(i));
      98                 :            :     }
      99                 :            :     return MP_OBJ_FROM_PTR(groups);
     100                 :            : }
     101                 :            : MP_DEFINE_CONST_FUN_OBJ_1(match_groups_obj, match_groups);
     102                 :            : 
     103                 :            : #endif
     104                 :            : 
     105                 :            : #if MICROPY_PY_RE_MATCH_SPAN_START_END
     106                 :            : 
     107                 :        130 : static void match_span_helper(size_t n_args, const mp_obj_t *args, mp_obj_t span[2]) {
     108                 :        130 :     mp_obj_match_t *self = MP_OBJ_TO_PTR(args[0]);
     109                 :            : 
     110                 :        130 :     mp_int_t no = 0;
     111         [ +  - ]:        130 :     if (n_args == 2) {
     112                 :        130 :         no = mp_obj_get_int(args[1]);
     113   [ +  -  +  + ]:        130 :         if (no < 0 || no >= self->num_matches) {
     114                 :         10 :             mp_raise_type_arg(&mp_type_IndexError, args[1]);
     115                 :            :         }
     116                 :            :     }
     117                 :            : 
     118                 :        120 :     mp_int_t s = -1;
     119                 :        120 :     mp_int_t e = -1;
     120                 :        120 :     const char *start = self->caps[no * 2];
     121         [ +  + ]:        120 :     if (start != NULL) {
     122                 :            :         // have a match for this group
     123                 :        114 :         const char *begin = mp_obj_str_get_str(self->str);
     124                 :        114 :         s = start - begin;
     125                 :        114 :         e = self->caps[no * 2 + 1] - begin;
     126                 :            :     }
     127                 :            : 
     128                 :            :     #if MICROPY_PY_BUILTINS_STR_UNICODE
     129         [ +  - ]:        120 :     if (mp_obj_get_type(self->str) == &mp_type_str) {
     130                 :        120 :         const byte *begin = (const byte *)mp_obj_str_get_str(self->str);
     131         [ +  + ]:        120 :         if (s != -1) {
     132                 :        114 :             s = utf8_ptr_to_index(begin, begin + s);
     133                 :            :         }
     134         [ +  + ]:        120 :         if (e != -1) {
     135                 :        114 :             e = utf8_ptr_to_index(begin, begin + e);
     136                 :            :         }
     137                 :            :     }
     138                 :            :     #endif
     139                 :            : 
     140                 :        120 :     span[0] = mp_obj_new_int(s);
     141                 :        120 :     span[1] = mp_obj_new_int(e);
     142                 :        120 : }
     143                 :            : 
     144                 :         50 : static mp_obj_t match_span(size_t n_args, const mp_obj_t *args) {
     145                 :         50 :     mp_obj_t span[2];
     146                 :         50 :     match_span_helper(n_args, args, span);
     147                 :         40 :     return mp_obj_new_tuple(2, span);
     148                 :            : }
     149                 :            : MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(match_span_obj, 1, 2, match_span);
     150                 :            : 
     151                 :         40 : static mp_obj_t match_start(size_t n_args, const mp_obj_t *args) {
     152                 :         40 :     mp_obj_t span[2];
     153                 :         40 :     match_span_helper(n_args, args, span);
     154                 :         40 :     return span[0];
     155                 :            : }
     156                 :            : MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(match_start_obj, 1, 2, match_start);
     157                 :            : 
     158                 :         40 : static mp_obj_t match_end(size_t n_args, const mp_obj_t *args) {
     159                 :         40 :     mp_obj_t span[2];
     160                 :         40 :     match_span_helper(n_args, args, span);
     161                 :         40 :     return span[1];
     162                 :            : }
     163                 :            : MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(match_end_obj, 1, 2, match_end);
     164                 :            : 
     165                 :            : #endif
     166                 :            : 
     167                 :            : #if !MICROPY_ENABLE_DYNRUNTIME
     168                 :            : static const mp_rom_map_elem_t match_locals_dict_table[] = {
     169                 :            :     { MP_ROM_QSTR(MP_QSTR_group), MP_ROM_PTR(&match_group_obj) },
     170                 :            :     #if MICROPY_PY_RE_MATCH_GROUPS
     171                 :            :     { MP_ROM_QSTR(MP_QSTR_groups), MP_ROM_PTR(&match_groups_obj) },
     172                 :            :     #endif
     173                 :            :     #if MICROPY_PY_RE_MATCH_SPAN_START_END
     174                 :            :     { MP_ROM_QSTR(MP_QSTR_span), MP_ROM_PTR(&match_span_obj) },
     175                 :            :     { MP_ROM_QSTR(MP_QSTR_start), MP_ROM_PTR(&match_start_obj) },
     176                 :            :     { MP_ROM_QSTR(MP_QSTR_end), MP_ROM_PTR(&match_end_obj) },
     177                 :            :     #endif
     178                 :            : };
     179                 :            : 
     180                 :            : static MP_DEFINE_CONST_DICT(match_locals_dict, match_locals_dict_table);
     181                 :            : 
     182                 :            : static MP_DEFINE_CONST_OBJ_TYPE(
     183                 :            :     match_type,
     184                 :            :     MP_QSTR_match,
     185                 :            :     MP_TYPE_FLAG_NONE,
     186                 :            :     print, match_print,
     187                 :            :     locals_dict, &match_locals_dict
     188                 :            :     );
     189                 :            : #endif
     190                 :            : 
     191                 :          2 : static void re_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
     192                 :          2 :     (void)kind;
     193                 :          2 :     mp_obj_re_t *self = MP_OBJ_TO_PTR(self_in);
     194                 :          2 :     mp_printf(print, "<re %p>", self);
     195                 :          2 : }
     196                 :            : 
     197                 :            : // Note: this function can't be named re_exec because it may clash with system headers, eg on FreeBSD
     198                 :        132 : static mp_obj_t re_exec_helper(bool is_anchored, uint n_args, const mp_obj_t *args) {
     199                 :        132 :     (void)n_args;
     200                 :        132 :     mp_obj_re_t *self;
     201   [ +  +  +  + ]:        132 :     if (mp_obj_is_type(args[0], (mp_obj_type_t *)&re_type)) {
     202                 :            :         self = MP_OBJ_TO_PTR(args[0]);
     203                 :            :     } else {
     204                 :        104 :         self = MP_OBJ_TO_PTR(mod_re_compile(1, args));
     205                 :            :     }
     206                 :        128 :     Subject subj;
     207                 :        128 :     size_t len;
     208                 :        128 :     subj.begin_line = subj.begin = mp_obj_str_get_data(args[1], &len);
     209                 :        128 :     subj.end = subj.begin + len;
     210                 :        128 :     int caps_num = (self->re.sub + 1) * 2;
     211                 :        128 :     mp_obj_match_t *match = m_new_obj_var(mp_obj_match_t, caps, char *, caps_num);
     212                 :            :     // cast is a workaround for a bug in msvc: it treats const char** as a const pointer instead of a pointer to pointer to const char
     213                 :        128 :     memset((char *)match->caps, 0, caps_num * sizeof(char *));
     214                 :        128 :     int res = re1_5_recursiveloopprog(&self->re, &subj, match->caps, caps_num, is_anchored);
     215         [ +  + ]:        126 :     if (res == 0) {
     216                 :         16 :         m_del_var(mp_obj_match_t, caps, char *, caps_num, match);
     217                 :         16 :         return mp_const_none;
     218                 :            :     }
     219                 :            : 
     220                 :        110 :     match->base.type = (mp_obj_type_t *)&match_type;
     221                 :        110 :     match->num_matches = caps_num / 2; // caps_num counts start and end pointers
     222                 :        110 :     match->str = args[1];
     223                 :        110 :     return MP_OBJ_FROM_PTR(match);
     224                 :            : }
     225                 :            : 
     226                 :        112 : static mp_obj_t re_match(size_t n_args, const mp_obj_t *args) {
     227                 :        112 :     return re_exec_helper(true, n_args, args);
     228                 :            : }
     229                 :            : MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(re_match_obj, 2, 4, re_match);
     230                 :            : 
     231                 :         20 : static mp_obj_t re_search(size_t n_args, const mp_obj_t *args) {
     232                 :         20 :     return re_exec_helper(false, n_args, args);
     233                 :            : }
     234                 :            : MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(re_search_obj, 2, 4, re_search);
     235                 :            : 
     236                 :         34 : static mp_obj_t re_split(size_t n_args, const mp_obj_t *args) {
     237                 :         34 :     mp_obj_re_t *self = MP_OBJ_TO_PTR(args[0]);
     238                 :         34 :     Subject subj;
     239                 :         34 :     size_t len;
     240                 :         34 :     const mp_obj_type_t *str_type = mp_obj_get_type(args[1]);
     241                 :         34 :     subj.begin_line = subj.begin = mp_obj_str_get_data(args[1], &len);
     242                 :         34 :     subj.end = subj.begin + len;
     243                 :         34 :     int caps_num = (self->re.sub + 1) * 2;
     244                 :            : 
     245                 :         34 :     int maxsplit = 0;
     246         [ +  + ]:         34 :     if (n_args > 2) {
     247                 :          4 :         maxsplit = mp_obj_get_int(args[2]);
     248                 :            :     }
     249                 :            : 
     250                 :         34 :     mp_obj_t retval = mp_obj_new_list(0, NULL);
     251                 :         34 :     const char **caps = mp_local_alloc(caps_num * sizeof(char *));
     252                 :         80 :     while (true) {
     253                 :            :         // cast is a workaround for a bug in msvc: it treats const char** as a const pointer instead of a pointer to pointer to const char
     254                 :         80 :         memset((char **)caps, 0, caps_num * sizeof(char *));
     255                 :         80 :         int res = re1_5_recursiveloopprog(&self->re, &subj, caps, caps_num, false);
     256                 :            : 
     257                 :            :         // if we didn't have a match, or had an empty match, it's time to stop
     258   [ +  +  +  + ]:         80 :         if (!res || caps[0] == caps[1]) {
     259                 :            :             break;
     260                 :            :         }
     261                 :            : 
     262                 :         52 :         mp_obj_t s = mp_obj_new_str_of_type(str_type, (const byte *)subj.begin, caps[0] - subj.begin);
     263                 :         52 :         mp_obj_list_append(retval, s);
     264         [ +  + ]:         52 :         if (self->re.sub > 0) {
     265                 :          2 :             mp_raise_NotImplementedError(MP_ERROR_TEXT("splitting with sub-captures"));
     266                 :            :         }
     267                 :         50 :         subj.begin = caps[1];
     268   [ +  +  +  + ]:         50 :         if (maxsplit > 0 && --maxsplit == 0) {
     269                 :            :             break;
     270                 :            :         }
     271                 :            :     }
     272                 :            :     // cast is a workaround for a bug in msvc (see above)
     273                 :         32 :     mp_local_free((char **)caps);
     274                 :            : 
     275                 :         32 :     mp_obj_t s = mp_obj_new_str_of_type(str_type, (const byte *)subj.begin, subj.end - subj.begin);
     276                 :         32 :     mp_obj_list_append(retval, s);
     277                 :         32 :     return retval;
     278                 :            : }
     279                 :            : MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(re_split_obj, 2, 3, re_split);
     280                 :            : 
     281                 :            : #if MICROPY_PY_RE_SUB
     282                 :            : 
     283                 :         36 : static mp_obj_t re_sub_helper(size_t n_args, const mp_obj_t *args) {
     284                 :         36 :     mp_obj_re_t *self;
     285   [ +  +  +  + ]:         36 :     if (mp_obj_is_type(args[0], (mp_obj_type_t *)&re_type)) {
     286                 :            :         self = MP_OBJ_TO_PTR(args[0]);
     287                 :            :     } else {
     288                 :         32 :         self = MP_OBJ_TO_PTR(mod_re_compile(1, args));
     289                 :            :     }
     290                 :         34 :     mp_obj_t replace = args[1];
     291                 :         34 :     mp_obj_t where = args[2];
     292                 :         34 :     mp_int_t count = 0;
     293         [ +  + ]:         34 :     if (n_args > 3) {
     294                 :          2 :         count = mp_obj_get_int(args[3]);
     295                 :            :         // Note: flags are currently ignored
     296                 :            :     }
     297                 :            : 
     298                 :         34 :     size_t where_len;
     299                 :         34 :     const char *where_str = mp_obj_str_get_data(where, &where_len);
     300                 :         34 :     Subject subj;
     301                 :         34 :     subj.begin_line = subj.begin = where_str;
     302                 :         34 :     subj.end = subj.begin + where_len;
     303                 :         34 :     int caps_num = (self->re.sub + 1) * 2;
     304                 :            : 
     305                 :         34 :     vstr_t vstr_return;
     306                 :         34 :     vstr_return.buf = NULL; // We'll init the vstr after the first match
     307                 :         34 :     mp_obj_match_t *match = mp_local_alloc(sizeof(mp_obj_match_t) + caps_num * sizeof(char *));
     308                 :         34 :     match->base.type = (mp_obj_type_t *)&match_type;
     309                 :         34 :     match->num_matches = caps_num / 2; // caps_num counts start and end pointers
     310                 :         34 :     match->str = where;
     311                 :            : 
     312                 :         88 :     for (;;) {
     313                 :            :         // cast is a workaround for a bug in msvc: it treats const char** as a const pointer instead of a pointer to pointer to const char
     314                 :         88 :         memset((char *)match->caps, 0, caps_num * sizeof(char *));
     315                 :         88 :         int res = re1_5_recursiveloopprog(&self->re, &subj, match->caps, caps_num, false);
     316                 :            : 
     317                 :            :         // If we didn't have a match, or had an empty match, it's time to stop
     318   [ +  +  +  - ]:         88 :         if (!res || match->caps[0] == match->caps[1]) {
     319                 :            :             break;
     320                 :            :         }
     321                 :            : 
     322                 :            :         // Initialise the vstr if it's not already
     323         [ +  + ]:         60 :         if (vstr_return.buf == NULL) {
     324                 :         32 :             vstr_init(&vstr_return, match->caps[0] - subj.begin);
     325                 :            :         }
     326                 :            : 
     327                 :            :         // Add pre-match string
     328                 :         60 :         vstr_add_strn(&vstr_return, subj.begin, match->caps[0] - subj.begin);
     329                 :            : 
     330                 :            :         // Get replacement string
     331         [ +  + ]:         60 :         const char *repl = mp_obj_str_get_str((mp_obj_is_callable(replace) ? mp_call_function_1(replace, MP_OBJ_FROM_PTR(match)) : replace));
     332                 :            : 
     333                 :            :         // Append replacement string to result, substituting any regex groups
     334         [ +  + ]:        446 :         while (*repl != '\0') {
     335         [ +  + ]:        390 :             if (*repl == '\\') {
     336                 :         28 :                 ++repl;
     337                 :         28 :                 bool is_g_format = false;
     338   [ +  +  +  - ]:         28 :                 if (*repl == 'g' && repl[1] == '<') {
     339                 :            :                     // Group specified with syntax "\g<number>"
     340                 :          8 :                     repl += 2;
     341                 :          8 :                     is_g_format = true;
     342                 :            :                 }
     343                 :            : 
     344         [ +  + ]:         28 :                 if ('0' <= *repl && *repl <= '9') {
     345                 :            :                     // Group specified with syntax "\g<number>" or "\number"
     346                 :            :                     unsigned int match_no = 0;
     347                 :        102 :                     do {
     348                 :        102 :                         match_no = match_no * 10 + (*repl++ - '0');
     349         [ +  + ]:        102 :                     } while ('0' <= *repl && *repl <= '9');
     350   [ +  +  +  - ]:         26 :                     if (is_g_format && *repl == '>') {
     351                 :          8 :                         ++repl;
     352                 :            :                     }
     353                 :            : 
     354         [ +  + ]:         26 :                     if (match_no >= (unsigned int)match->num_matches) {
     355                 :          4 :                         mp_raise_type_arg(&mp_type_IndexError, MP_OBJ_NEW_SMALL_INT(match_no));
     356                 :            :                     }
     357                 :            : 
     358                 :         22 :                     const char *start_match = match->caps[match_no * 2];
     359         [ +  + ]:         22 :                     if (start_match != NULL) {
     360                 :            :                         // Add the substring matched by group
     361                 :         20 :                         const char *end_match = match->caps[match_no * 2 + 1];
     362                 :         20 :                         vstr_add_strn(&vstr_return, start_match, end_match - start_match);
     363                 :            :                     }
     364         [ +  - ]:          2 :                 } else if (*repl == '\\') {
     365                 :            :                     // Add the \ character
     366                 :          2 :                     vstr_add_byte(&vstr_return, *repl++);
     367                 :            :                 }
     368                 :            :             } else {
     369                 :            :                 // Just add the current byte from the replacement string
     370                 :        362 :                 vstr_add_byte(&vstr_return, *repl++);
     371                 :            :             }
     372                 :            :         }
     373                 :            : 
     374                 :            :         // Move start pointer to end of last match
     375                 :         56 :         subj.begin = match->caps[1];
     376                 :            : 
     377                 :            :         // Stop substitutions if count was given and gets to 0
     378   [ +  +  +  + ]:         56 :         if (count > 0 && --count == 0) {
     379                 :            :             break;
     380                 :            :         }
     381                 :            :     }
     382                 :            : 
     383                 :         30 :     mp_local_free(match);
     384                 :            : 
     385         [ +  + ]:         30 :     if (vstr_return.buf == NULL) {
     386                 :            :         // Optimisation for case of no substitutions
     387                 :            :         return where;
     388                 :            :     }
     389                 :            : 
     390                 :            :     // Add post-match string
     391                 :         28 :     vstr_add_strn(&vstr_return, subj.begin, subj.end - subj.begin);
     392                 :            : 
     393         [ +  + ]:         28 :     if (mp_obj_get_type(where) == &mp_type_str) {
     394                 :         26 :         return mp_obj_new_str_from_utf8_vstr(&vstr_return);
     395                 :            :     } else {
     396                 :          2 :         return mp_obj_new_bytes_from_vstr(&vstr_return);
     397                 :            :     }
     398                 :            : }
     399                 :            : 
     400                 :            : MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(re_sub_obj, 3, 5, re_sub_helper);
     401                 :            : 
     402                 :            : #endif
     403                 :            : 
     404                 :            : #if !MICROPY_ENABLE_DYNRUNTIME
     405                 :            : static const mp_rom_map_elem_t re_locals_dict_table[] = {
     406                 :            :     { MP_ROM_QSTR(MP_QSTR_match), MP_ROM_PTR(&re_match_obj) },
     407                 :            :     { MP_ROM_QSTR(MP_QSTR_search), MP_ROM_PTR(&re_search_obj) },
     408                 :            :     { MP_ROM_QSTR(MP_QSTR_split), MP_ROM_PTR(&re_split_obj) },
     409                 :            :     #if MICROPY_PY_RE_SUB
     410                 :            :     { MP_ROM_QSTR(MP_QSTR_sub), MP_ROM_PTR(&re_sub_obj) },
     411                 :            :     #endif
     412                 :            : };
     413                 :            : 
     414                 :            : static MP_DEFINE_CONST_DICT(re_locals_dict, re_locals_dict_table);
     415                 :            : 
     416                 :            : static MP_DEFINE_CONST_OBJ_TYPE(
     417                 :            :     re_type,
     418                 :            :     MP_QSTR_re,
     419                 :            :     MP_TYPE_FLAG_NONE,
     420                 :            :     print, re_print,
     421                 :            :     locals_dict, &re_locals_dict
     422                 :            :     );
     423                 :            : #endif
     424                 :            : 
     425                 :        224 : static mp_obj_t mod_re_compile(size_t n_args, const mp_obj_t *args) {
     426                 :        224 :     (void)n_args;
     427                 :        224 :     const char *re_str = mp_obj_str_get_str(args[0]);
     428                 :        218 :     int size = re1_5_sizecode(re_str);
     429         [ +  + ]:        218 :     if (size == -1) {
     430                 :         30 :         goto error;
     431                 :            :     }
     432                 :        188 :     mp_obj_re_t *o = mp_obj_malloc_var(mp_obj_re_t, re.insts, char, size, (mp_obj_type_t *)&re_type);
     433                 :            :     #if MICROPY_PY_RE_DEBUG
     434                 :        188 :     int flags = 0;
     435         [ +  + ]:        188 :     if (n_args > 1) {
     436                 :          2 :         flags = mp_obj_get_int(args[1]);
     437                 :            :     }
     438                 :            :     #endif
     439                 :        188 :     int error = re1_5_compilecode(&o->re, re_str);
     440         [ +  + ]:        188 :     if (error != 0) {
     441                 :          2 :     error:
     442                 :         32 :         mp_raise_ValueError(MP_ERROR_TEXT("error in regex"));
     443                 :            :     }
     444                 :            :     #if MICROPY_PY_RE_DEBUG
     445         [ +  + ]:        186 :     if (flags & FLAG_DEBUG) {
     446                 :          2 :         re1_5_dumpcode(&o->re);
     447                 :            :     }
     448                 :            :     #endif
     449                 :        186 :     return MP_OBJ_FROM_PTR(o);
     450                 :            : }
     451                 :            : MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_re_compile_obj, 1, 2, mod_re_compile);
     452                 :            : 
     453                 :            : #if !MICROPY_ENABLE_DYNRUNTIME
     454                 :            : static const mp_rom_map_elem_t mp_module_re_globals_table[] = {
     455                 :            :     { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_re) },
     456                 :            :     { MP_ROM_QSTR(MP_QSTR_compile), MP_ROM_PTR(&mod_re_compile_obj) },
     457                 :            :     { MP_ROM_QSTR(MP_QSTR_match), MP_ROM_PTR(&re_match_obj) },
     458                 :            :     { MP_ROM_QSTR(MP_QSTR_search), MP_ROM_PTR(&re_search_obj) },
     459                 :            :     #if MICROPY_PY_RE_SUB
     460                 :            :     { MP_ROM_QSTR(MP_QSTR_sub), MP_ROM_PTR(&re_sub_obj) },
     461                 :            :     #endif
     462                 :            :     #if MICROPY_PY_RE_DEBUG
     463                 :            :     { MP_ROM_QSTR(MP_QSTR_DEBUG), MP_ROM_INT(FLAG_DEBUG) },
     464                 :            :     #endif
     465                 :            : };
     466                 :            : 
     467                 :            : static MP_DEFINE_CONST_DICT(mp_module_re_globals, mp_module_re_globals_table);
     468                 :            : 
     469                 :            : const mp_obj_module_t mp_module_re = {
     470                 :            :     .base = { &mp_type_module },
     471                 :            :     .globals = (mp_obj_dict_t *)&mp_module_re_globals,
     472                 :            : };
     473                 :            : 
     474                 :            : MP_REGISTER_EXTENSIBLE_MODULE(MP_QSTR_re, mp_module_re);
     475                 :            : #endif
     476                 :            : 
     477                 :            : // Source files #include'd here to make sure they're compiled in
     478                 :            : // only if module is enabled by config setting.
     479                 :            : 
     480                 :            : #define re1_5_fatal(x) assert(!x)
     481                 :            : 
     482                 :            : #include "lib/re1.5/compilecode.c"
     483                 :            : #include "lib/re1.5/recursiveloop.c"
     484                 :            : #include "lib/re1.5/charclass.c"
     485                 :            : 
     486                 :            : #if MICROPY_PY_RE_DEBUG
     487                 :            : // Make sure the output print statements go to the same output as other Python output.
     488                 :            : #define printf(...) mp_printf(&mp_plat_print, __VA_ARGS__)
     489                 :            : #include "lib/re1.5/dumpcode.c"
     490                 :            : #undef printf
     491                 :            : #endif
     492                 :            : 
     493                 :            : #endif // MICROPY_PY_RE

Generated by: LCOV version 1.15-5-g462f71d