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/stackctrl.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_STACK_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 : 132 : static mp_obj_t re_exec(bool is_anchored, uint n_args, const mp_obj_t *args) {
198 : 132 : (void)n_args;
199 : 132 : mp_obj_re_t *self;
200 [ + + + + ]: 132 : if (mp_obj_is_type(args[0], (mp_obj_type_t *)&re_type)) {
201 : : self = MP_OBJ_TO_PTR(args[0]);
202 : : } else {
203 : 104 : self = MP_OBJ_TO_PTR(mod_re_compile(1, args));
204 : : }
205 : 128 : Subject subj;
206 : 128 : size_t len;
207 : 128 : subj.begin_line = subj.begin = mp_obj_str_get_data(args[1], &len);
208 : 128 : subj.end = subj.begin + len;
209 : 128 : int caps_num = (self->re.sub + 1) * 2;
210 : 128 : mp_obj_match_t *match = m_new_obj_var(mp_obj_match_t, caps, char *, caps_num);
211 : : // 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
212 : 128 : memset((char *)match->caps, 0, caps_num * sizeof(char *));
213 : 128 : int res = re1_5_recursiveloopprog(&self->re, &subj, match->caps, caps_num, is_anchored);
214 [ + + ]: 126 : if (res == 0) {
215 : 16 : m_del_var(mp_obj_match_t, caps, char *, caps_num, match);
216 : 16 : return mp_const_none;
217 : : }
218 : :
219 : 110 : match->base.type = (mp_obj_type_t *)&match_type;
220 : 110 : match->num_matches = caps_num / 2; // caps_num counts start and end pointers
221 : 110 : match->str = args[1];
222 : 110 : return MP_OBJ_FROM_PTR(match);
223 : : }
224 : :
225 : 112 : static mp_obj_t re_match(size_t n_args, const mp_obj_t *args) {
226 : 112 : return re_exec(true, n_args, args);
227 : : }
228 : : MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(re_match_obj, 2, 4, re_match);
229 : :
230 : 20 : static mp_obj_t re_search(size_t n_args, const mp_obj_t *args) {
231 : 20 : return re_exec(false, n_args, args);
232 : : }
233 : : MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(re_search_obj, 2, 4, re_search);
234 : :
235 : 34 : static mp_obj_t re_split(size_t n_args, const mp_obj_t *args) {
236 : 34 : mp_obj_re_t *self = MP_OBJ_TO_PTR(args[0]);
237 : 34 : Subject subj;
238 : 34 : size_t len;
239 : 34 : const mp_obj_type_t *str_type = mp_obj_get_type(args[1]);
240 : 34 : subj.begin_line = subj.begin = mp_obj_str_get_data(args[1], &len);
241 : 34 : subj.end = subj.begin + len;
242 : 34 : int caps_num = (self->re.sub + 1) * 2;
243 : :
244 : 34 : int maxsplit = 0;
245 [ + + ]: 34 : if (n_args > 2) {
246 : 4 : maxsplit = mp_obj_get_int(args[2]);
247 : : }
248 : :
249 : 34 : mp_obj_t retval = mp_obj_new_list(0, NULL);
250 : 34 : const char **caps = mp_local_alloc(caps_num * sizeof(char *));
251 : 80 : while (true) {
252 : : // 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
253 : 80 : memset((char **)caps, 0, caps_num * sizeof(char *));
254 : 80 : int res = re1_5_recursiveloopprog(&self->re, &subj, caps, caps_num, false);
255 : :
256 : : // if we didn't have a match, or had an empty match, it's time to stop
257 [ + + + + ]: 80 : if (!res || caps[0] == caps[1]) {
258 : : break;
259 : : }
260 : :
261 : 52 : mp_obj_t s = mp_obj_new_str_of_type(str_type, (const byte *)subj.begin, caps[0] - subj.begin);
262 : 52 : mp_obj_list_append(retval, s);
263 [ + + ]: 52 : if (self->re.sub > 0) {
264 : 2 : mp_raise_NotImplementedError(MP_ERROR_TEXT("splitting with sub-captures"));
265 : : }
266 : 50 : subj.begin = caps[1];
267 [ + + + + ]: 50 : if (maxsplit > 0 && --maxsplit == 0) {
268 : : break;
269 : : }
270 : : }
271 : : // cast is a workaround for a bug in msvc (see above)
272 : 32 : mp_local_free((char **)caps);
273 : :
274 : 32 : mp_obj_t s = mp_obj_new_str_of_type(str_type, (const byte *)subj.begin, subj.end - subj.begin);
275 : 32 : mp_obj_list_append(retval, s);
276 : 32 : return retval;
277 : : }
278 : : MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(re_split_obj, 2, 3, re_split);
279 : :
280 : : #if MICROPY_PY_RE_SUB
281 : :
282 : 36 : static mp_obj_t re_sub_helper(size_t n_args, const mp_obj_t *args) {
283 : 36 : mp_obj_re_t *self;
284 [ + + + + ]: 36 : if (mp_obj_is_type(args[0], (mp_obj_type_t *)&re_type)) {
285 : : self = MP_OBJ_TO_PTR(args[0]);
286 : : } else {
287 : 32 : self = MP_OBJ_TO_PTR(mod_re_compile(1, args));
288 : : }
289 : 34 : mp_obj_t replace = args[1];
290 : 34 : mp_obj_t where = args[2];
291 : 34 : mp_int_t count = 0;
292 [ + + ]: 34 : if (n_args > 3) {
293 : 2 : count = mp_obj_get_int(args[3]);
294 : : // Note: flags are currently ignored
295 : : }
296 : :
297 : 34 : size_t where_len;
298 : 34 : const char *where_str = mp_obj_str_get_data(where, &where_len);
299 : 34 : Subject subj;
300 : 34 : subj.begin_line = subj.begin = where_str;
301 : 34 : subj.end = subj.begin + where_len;
302 : 34 : int caps_num = (self->re.sub + 1) * 2;
303 : :
304 : 34 : vstr_t vstr_return;
305 : 34 : vstr_return.buf = NULL; // We'll init the vstr after the first match
306 : 34 : mp_obj_match_t *match = mp_local_alloc(sizeof(mp_obj_match_t) + caps_num * sizeof(char *));
307 : 34 : match->base.type = (mp_obj_type_t *)&match_type;
308 : 34 : match->num_matches = caps_num / 2; // caps_num counts start and end pointers
309 : 34 : match->str = where;
310 : :
311 : 88 : for (;;) {
312 : : // 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
313 : 88 : memset((char *)match->caps, 0, caps_num * sizeof(char *));
314 : 88 : int res = re1_5_recursiveloopprog(&self->re, &subj, match->caps, caps_num, false);
315 : :
316 : : // If we didn't have a match, or had an empty match, it's time to stop
317 [ + + + - ]: 88 : if (!res || match->caps[0] == match->caps[1]) {
318 : : break;
319 : : }
320 : :
321 : : // Initialise the vstr if it's not already
322 [ + + ]: 60 : if (vstr_return.buf == NULL) {
323 : 32 : vstr_init(&vstr_return, match->caps[0] - subj.begin);
324 : : }
325 : :
326 : : // Add pre-match string
327 : 60 : vstr_add_strn(&vstr_return, subj.begin, match->caps[0] - subj.begin);
328 : :
329 : : // Get replacement string
330 [ + + ]: 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));
331 : :
332 : : // Append replacement string to result, substituting any regex groups
333 [ + + ]: 446 : while (*repl != '\0') {
334 [ + + ]: 390 : if (*repl == '\\') {
335 : 28 : ++repl;
336 : 28 : bool is_g_format = false;
337 [ + + + - ]: 28 : if (*repl == 'g' && repl[1] == '<') {
338 : : // Group specified with syntax "\g<number>"
339 : 8 : repl += 2;
340 : 8 : is_g_format = true;
341 : : }
342 : :
343 [ + + ]: 28 : if ('0' <= *repl && *repl <= '9') {
344 : : // Group specified with syntax "\g<number>" or "\number"
345 : : unsigned int match_no = 0;
346 : 102 : do {
347 : 102 : match_no = match_no * 10 + (*repl++ - '0');
348 [ + + ]: 102 : } while ('0' <= *repl && *repl <= '9');
349 [ + + + - ]: 26 : if (is_g_format && *repl == '>') {
350 : 8 : ++repl;
351 : : }
352 : :
353 [ + + ]: 26 : if (match_no >= (unsigned int)match->num_matches) {
354 : 4 : mp_raise_type_arg(&mp_type_IndexError, MP_OBJ_NEW_SMALL_INT(match_no));
355 : : }
356 : :
357 : 22 : const char *start_match = match->caps[match_no * 2];
358 [ + + ]: 22 : if (start_match != NULL) {
359 : : // Add the substring matched by group
360 : 20 : const char *end_match = match->caps[match_no * 2 + 1];
361 : 20 : vstr_add_strn(&vstr_return, start_match, end_match - start_match);
362 : : }
363 [ + - ]: 2 : } else if (*repl == '\\') {
364 : : // Add the \ character
365 : 2 : vstr_add_byte(&vstr_return, *repl++);
366 : : }
367 : : } else {
368 : : // Just add the current byte from the replacement string
369 : 362 : vstr_add_byte(&vstr_return, *repl++);
370 : : }
371 : : }
372 : :
373 : : // Move start pointer to end of last match
374 : 56 : subj.begin = match->caps[1];
375 : :
376 : : // Stop substitutions if count was given and gets to 0
377 [ + + + + ]: 56 : if (count > 0 && --count == 0) {
378 : : break;
379 : : }
380 : : }
381 : :
382 : 30 : mp_local_free(match);
383 : :
384 [ + + ]: 30 : if (vstr_return.buf == NULL) {
385 : : // Optimisation for case of no substitutions
386 : : return where;
387 : : }
388 : :
389 : : // Add post-match string
390 : 28 : vstr_add_strn(&vstr_return, subj.begin, subj.end - subj.begin);
391 : :
392 [ + + ]: 28 : if (mp_obj_get_type(where) == &mp_type_str) {
393 : 26 : return mp_obj_new_str_from_utf8_vstr(&vstr_return);
394 : : } else {
395 : 2 : return mp_obj_new_bytes_from_vstr(&vstr_return);
396 : : }
397 : : }
398 : :
399 : : MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(re_sub_obj, 3, 5, re_sub_helper);
400 : :
401 : : #endif
402 : :
403 : : #if !MICROPY_ENABLE_DYNRUNTIME
404 : : static const mp_rom_map_elem_t re_locals_dict_table[] = {
405 : : { MP_ROM_QSTR(MP_QSTR_match), MP_ROM_PTR(&re_match_obj) },
406 : : { MP_ROM_QSTR(MP_QSTR_search), MP_ROM_PTR(&re_search_obj) },
407 : : { MP_ROM_QSTR(MP_QSTR_split), MP_ROM_PTR(&re_split_obj) },
408 : : #if MICROPY_PY_RE_SUB
409 : : { MP_ROM_QSTR(MP_QSTR_sub), MP_ROM_PTR(&re_sub_obj) },
410 : : #endif
411 : : };
412 : :
413 : : static MP_DEFINE_CONST_DICT(re_locals_dict, re_locals_dict_table);
414 : :
415 : : static MP_DEFINE_CONST_OBJ_TYPE(
416 : : re_type,
417 : : MP_QSTR_re,
418 : : MP_TYPE_FLAG_NONE,
419 : : print, re_print,
420 : : locals_dict, &re_locals_dict
421 : : );
422 : : #endif
423 : :
424 : 224 : static mp_obj_t mod_re_compile(size_t n_args, const mp_obj_t *args) {
425 : 224 : (void)n_args;
426 : 224 : const char *re_str = mp_obj_str_get_str(args[0]);
427 : 218 : int size = re1_5_sizecode(re_str);
428 [ + + ]: 218 : if (size == -1) {
429 : 30 : goto error;
430 : : }
431 : 188 : mp_obj_re_t *o = mp_obj_malloc_var(mp_obj_re_t, re.insts, char, size, (mp_obj_type_t *)&re_type);
432 : : #if MICROPY_PY_RE_DEBUG
433 : 188 : int flags = 0;
434 [ + + ]: 188 : if (n_args > 1) {
435 : 2 : flags = mp_obj_get_int(args[1]);
436 : : }
437 : : #endif
438 : 188 : int error = re1_5_compilecode(&o->re, re_str);
439 [ + + ]: 188 : if (error != 0) {
440 : 2 : error:
441 : 32 : mp_raise_ValueError(MP_ERROR_TEXT("error in regex"));
442 : : }
443 : : #if MICROPY_PY_RE_DEBUG
444 [ + + ]: 186 : if (flags & FLAG_DEBUG) {
445 : 2 : re1_5_dumpcode(&o->re);
446 : : }
447 : : #endif
448 : 186 : return MP_OBJ_FROM_PTR(o);
449 : : }
450 : : MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_re_compile_obj, 1, 2, mod_re_compile);
451 : :
452 : : #if !MICROPY_ENABLE_DYNRUNTIME
453 : : static const mp_rom_map_elem_t mp_module_re_globals_table[] = {
454 : : { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_re) },
455 : : { MP_ROM_QSTR(MP_QSTR_compile), MP_ROM_PTR(&mod_re_compile_obj) },
456 : : { MP_ROM_QSTR(MP_QSTR_match), MP_ROM_PTR(&re_match_obj) },
457 : : { MP_ROM_QSTR(MP_QSTR_search), MP_ROM_PTR(&re_search_obj) },
458 : : #if MICROPY_PY_RE_SUB
459 : : { MP_ROM_QSTR(MP_QSTR_sub), MP_ROM_PTR(&re_sub_obj) },
460 : : #endif
461 : : #if MICROPY_PY_RE_DEBUG
462 : : { MP_ROM_QSTR(MP_QSTR_DEBUG), MP_ROM_INT(FLAG_DEBUG) },
463 : : #endif
464 : : };
465 : :
466 : : static MP_DEFINE_CONST_DICT(mp_module_re_globals, mp_module_re_globals_table);
467 : :
468 : : const mp_obj_module_t mp_module_re = {
469 : : .base = { &mp_type_module },
470 : : .globals = (mp_obj_dict_t *)&mp_module_re_globals,
471 : : };
472 : :
473 : : MP_REGISTER_EXTENSIBLE_MODULE(MP_QSTR_re, mp_module_re);
474 : : #endif
475 : :
476 : : // Source files #include'd here to make sure they're compiled in
477 : : // only if module is enabled by config setting.
478 : :
479 : : #define re1_5_fatal(x) assert(!x)
480 : :
481 : : #include "lib/re1.5/compilecode.c"
482 : : #include "lib/re1.5/recursiveloop.c"
483 : : #include "lib/re1.5/charclass.c"
484 : :
485 : : #if MICROPY_PY_RE_DEBUG
486 : : // Make sure the output print statements go to the same output as other Python output.
487 : : #define printf(...) mp_printf(&mp_plat_print, __VA_ARGS__)
488 : : #include "lib/re1.5/dumpcode.c"
489 : : #undef printf
490 : : #endif
491 : :
492 : : #endif // MICROPY_PY_RE
|