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
|