/* * Secret Labs' Regular Expression Engine * * regular expression matching engine * * partial history: * 1999-10-24 fl created (based on existing template matcher code) * 2000-03-06 fl first alpha, sort of * 2000-08-01 fl fixes for 1.6b1 * 2000-08-07 fl use PyOS_CheckStack() if available * 2000-09-20 fl added expand method * 2001-03-20 fl lots of fixes for 2.1b2 * 2001-04-15 fl export copyright as Python attribute, not global * 2001-04-28 fl added __copy__ methods (work in progress) * 2001-05-14 fl fixes for 1.5.2 compatibility * 2001-07-01 fl added BIGCHARSET support (from Martin von Loewis) * 2001-10-18 fl fixed group reset issue (from Matthew Mueller) * 2001-10-20 fl added split primitive; re-enable unicode for 1.6/2.0/2.1 * 2001-10-21 fl added sub/subn primitive * 2001-10-24 fl added finditer primitive (for 2.2 only) * 2001-12-07 fl fixed memory leak in sub/subn (Guido van Rossum) * 2002-11-09 fl fixed empty sub/subn return type * 2003-04-18 mvl fully support 4-byte codes * 2003-10-17 gn implemented non recursive scheme * 2013-02-04 mrab added fullmatch primitive * * Copyright (c) 1997-2001 by Secret Labs AB. All rights reserved. * * This version of the SRE library can be redistributed under CNRI's * Python 1.6 license. For any other use, please contact Secret Labs * AB ([email protected]). * * Portions of this engine have been developed in cooperation with * CNRI. Hewlett-Packard provided funding for 1.6 integration and * other compatibility work. */ static const char copyright[] = …; #include "Python.h" #include "pycore_critical_section.h" // Py_BEGIN_CRITICAL_SECTION #include "pycore_dict.h" // _PyDict_Next() #include "pycore_long.h" // _PyLong_GetZero() #include "pycore_moduleobject.h" // _PyModule_GetState() #include "sre.h" // SRE_CODE #include <ctype.h> // tolower(), toupper(), isalnum() #define SRE_CODE_BITS … // On macOS, use the wide character ctype API using btowc() #if defined(__APPLE__) #define USE_CTYPE_WINT_T #endif static int sre_isalnum(unsigned int ch) { … } static unsigned int sre_tolower(unsigned int ch) { … } static unsigned int sre_toupper(unsigned int ch) { … } /* Defining this one controls tracing: * 0 -- disabled * 1 -- only if the DEBUG flag set * 2 -- always */ #ifndef VERBOSE #define VERBOSE … #endif /* -------------------------------------------------------------------- */ #if defined(_MSC_VER) #pragma optimize("agtw", on) /* doesn't seem to make much difference... */ #pragma warning(disable: 4710) /* who cares if functions are not inlined ;-) */ /* fastest possible local call under MSVC */ #define LOCAL … #else #define LOCAL(type) … #endif /* error codes */ #define SRE_ERROR_ILLEGAL … #define SRE_ERROR_STATE … #define SRE_ERROR_RECURSION_LIMIT … #define SRE_ERROR_MEMORY … #define SRE_ERROR_INTERRUPTED … #if VERBOSE == 0 #define INIT_TRACE(state) … #define DO_TRACE … #define TRACE(v) … #elif VERBOSE == 1 #define INIT_TRACE … #define DO_TRACE … #define TRACE … #elif VERBOSE == 2 #define INIT_TRACE … #define DO_TRACE … #define TRACE … #else # error VERBOSE must be 0, 1 or 2 #endif /* -------------------------------------------------------------------- */ /* search engine state */ #define SRE_IS_DIGIT(ch) … #define SRE_IS_SPACE(ch) … #define SRE_IS_LINEBREAK(ch) … #define SRE_IS_WORD(ch) … static unsigned int sre_lower_ascii(unsigned int ch) { … } /* locale-specific character predicates */ /* !(c & ~N) == (c < N+1) for any unsigned c, this avoids * warnings when c's type supports only numbers < N+1 */ #define SRE_LOC_IS_ALNUM(ch) … #define SRE_LOC_IS_WORD(ch) … static unsigned int sre_lower_locale(unsigned int ch) { … } static unsigned int sre_upper_locale(unsigned int ch) { … } /* unicode-specific character predicates */ #define SRE_UNI_IS_DIGIT(ch) … #define SRE_UNI_IS_SPACE(ch) … #define SRE_UNI_IS_LINEBREAK(ch) … #define SRE_UNI_IS_ALNUM(ch) … #define SRE_UNI_IS_WORD(ch) … static unsigned int sre_lower_unicode(unsigned int ch) { … } static unsigned int sre_upper_unicode(unsigned int ch) { … } LOCAL(int) sre_category(SRE_CODE category, unsigned int ch) { … } LOCAL(int) char_loc_ignore(SRE_CODE pattern, SRE_CODE ch) { … } /* helpers */ static void data_stack_dealloc(SRE_STATE* state) { … } static int data_stack_grow(SRE_STATE* state, Py_ssize_t size) { … } /* memory pool functions for SRE_REPEAT, this can avoid memory leak when SRE(match) function terminates abruptly. state->repeat_pool_used is a doubly-linked list, so that we can remove a SRE_REPEAT node from it. state->repeat_pool_unused is a singly-linked list, we put/get node at the head. */ static SRE_REPEAT * repeat_pool_malloc(SRE_STATE *state) { … } static void repeat_pool_free(SRE_STATE *state, SRE_REPEAT *repeat) { … } static void repeat_pool_clear(SRE_STATE *state) { … } /* generate 8-bit version */ #define SRE_CHAR … #define SIZEOF_SRE_CHAR … #define SRE … #include "sre_lib.h" /* generate 16-bit unicode version */ #define SRE_CHAR … #define SIZEOF_SRE_CHAR … #define SRE … #include "sre_lib.h" /* generate 32-bit unicode version */ #define SRE_CHAR … #define SIZEOF_SRE_CHAR … #define SRE … #include "sre_lib.h" /* -------------------------------------------------------------------- */ /* factories and destructors */ /* module state */ _sremodulestate; static _sremodulestate * get_sre_module_state(PyObject *m) { … } static struct PyModuleDef sremodule; #define get_sre_module_state_by_class(cls) … /* see sre.h for object declarations */ static PyObject*pattern_new_match(_sremodulestate *, PatternObject*, SRE_STATE*, Py_ssize_t); static PyObject *pattern_scanner(_sremodulestate *, PatternObject *, PyObject *, Py_ssize_t, Py_ssize_t); /*[clinic input] module _sre class _sre.SRE_Pattern "PatternObject *" "get_sre_module_state_by_class(tp)->Pattern_Type" class _sre.SRE_Match "MatchObject *" "get_sre_module_state_by_class(tp)->Match_Type" class _sre.SRE_Scanner "ScannerObject *" "get_sre_module_state_by_class(tp)->Scanner_Type" [clinic start generated code]*/ /*[clinic end generated code: output=da39a3ee5e6b4b0d input=fe2966e32b66a231]*/ /*[clinic input] _sre.getcodesize -> int [clinic start generated code]*/ static int _sre_getcodesize_impl(PyObject *module) /*[clinic end generated code: output=e0db7ce34a6dd7b1 input=bd6f6ecf4916bb2b]*/ { … } /*[clinic input] _sre.ascii_iscased -> bool character: int / [clinic start generated code]*/ static int _sre_ascii_iscased_impl(PyObject *module, int character) /*[clinic end generated code: output=4f454b630fbd19a2 input=9f0bd952812c7ed3]*/ { … } /*[clinic input] _sre.unicode_iscased -> bool character: int / [clinic start generated code]*/ static int _sre_unicode_iscased_impl(PyObject *module, int character) /*[clinic end generated code: output=9c5ddee0dc2bc258 input=51e42c3b8dddb78e]*/ { … } /*[clinic input] _sre.ascii_tolower -> int character: int / [clinic start generated code]*/ static int _sre_ascii_tolower_impl(PyObject *module, int character) /*[clinic end generated code: output=228294ed6ff2a612 input=272c609b5b61f136]*/ { … } /*[clinic input] _sre.unicode_tolower -> int character: int / [clinic start generated code]*/ static int _sre_unicode_tolower_impl(PyObject *module, int character) /*[clinic end generated code: output=6422272d7d7fee65 input=91d708c5f3c2045a]*/ { … } LOCAL(void) state_reset(SRE_STATE* state) { … } static const void* getstring(PyObject* string, Py_ssize_t* p_length, int* p_isbytes, int* p_charsize, Py_buffer *view) { … } LOCAL(PyObject*) state_init(SRE_STATE* state, PatternObject* pattern, PyObject* string, Py_ssize_t start, Py_ssize_t end) { … } LOCAL(void) state_fini(SRE_STATE* state) { … } /* calculate offset from start of string */ #define STATE_OFFSET(state, member) … LOCAL(PyObject*) getslice(int isbytes, const void *ptr, PyObject* string, Py_ssize_t start, Py_ssize_t end) { … } LOCAL(PyObject*) state_getslice(SRE_STATE* state, Py_ssize_t index, PyObject* string, int empty) { … } static void pattern_error(Py_ssize_t status) { … } static int pattern_traverse(PatternObject *self, visitproc visit, void *arg) { … } static int pattern_clear(PatternObject *self) { … } static void pattern_dealloc(PatternObject* self) { … } LOCAL(Py_ssize_t) sre_match(SRE_STATE* state, SRE_CODE* pattern) { … } LOCAL(Py_ssize_t) sre_search(SRE_STATE* state, SRE_CODE* pattern) { … } /*[clinic input] _sre.SRE_Pattern.match cls: defining_class / string: object pos: Py_ssize_t = 0 endpos: Py_ssize_t(c_default="PY_SSIZE_T_MAX") = sys.maxsize Matches zero or more characters at the beginning of the string. [clinic start generated code]*/ static PyObject * _sre_SRE_Pattern_match_impl(PatternObject *self, PyTypeObject *cls, PyObject *string, Py_ssize_t pos, Py_ssize_t endpos) /*[clinic end generated code: output=ec6208ea58a0cca0 input=4bdb9c3e564d13ac]*/ { … } /*[clinic input] _sre.SRE_Pattern.fullmatch cls: defining_class / string: object pos: Py_ssize_t = 0 endpos: Py_ssize_t(c_default="PY_SSIZE_T_MAX") = sys.maxsize Matches against all of the string. [clinic start generated code]*/ static PyObject * _sre_SRE_Pattern_fullmatch_impl(PatternObject *self, PyTypeObject *cls, PyObject *string, Py_ssize_t pos, Py_ssize_t endpos) /*[clinic end generated code: output=625b75b027ef94da input=50981172ab0fcfdd]*/ { … } /*[clinic input] _sre.SRE_Pattern.search cls: defining_class / string: object pos: Py_ssize_t = 0 endpos: Py_ssize_t(c_default="PY_SSIZE_T_MAX") = sys.maxsize Scan through string looking for a match, and return a corresponding match object instance. Return None if no position in the string matches. [clinic start generated code]*/ static PyObject * _sre_SRE_Pattern_search_impl(PatternObject *self, PyTypeObject *cls, PyObject *string, Py_ssize_t pos, Py_ssize_t endpos) /*[clinic end generated code: output=bd7f2d9d583e1463 input=afa9afb66a74a4b3]*/ { … } /*[clinic input] _sre.SRE_Pattern.findall string: object pos: Py_ssize_t = 0 endpos: Py_ssize_t(c_default="PY_SSIZE_T_MAX") = sys.maxsize Return a list of all non-overlapping matches of pattern in string. [clinic start generated code]*/ static PyObject * _sre_SRE_Pattern_findall_impl(PatternObject *self, PyObject *string, Py_ssize_t pos, Py_ssize_t endpos) /*[clinic end generated code: output=f4966baceea60aca input=5b6a4ee799741563]*/ { … } /*[clinic input] _sre.SRE_Pattern.finditer cls: defining_class / string: object pos: Py_ssize_t = 0 endpos: Py_ssize_t(c_default="PY_SSIZE_T_MAX") = sys.maxsize Return an iterator over all non-overlapping matches for the RE pattern in string. For each match, the iterator returns a match object. [clinic start generated code]*/ static PyObject * _sre_SRE_Pattern_finditer_impl(PatternObject *self, PyTypeObject *cls, PyObject *string, Py_ssize_t pos, Py_ssize_t endpos) /*[clinic end generated code: output=1791dbf3618ade56 input=812e332a4848cbaf]*/ { … } /*[clinic input] _sre.SRE_Pattern.scanner cls: defining_class / string: object pos: Py_ssize_t = 0 endpos: Py_ssize_t(c_default="PY_SSIZE_T_MAX") = sys.maxsize [clinic start generated code]*/ static PyObject * _sre_SRE_Pattern_scanner_impl(PatternObject *self, PyTypeObject *cls, PyObject *string, Py_ssize_t pos, Py_ssize_t endpos) /*[clinic end generated code: output=f70cd506112f1bd9 input=2e487e5151bcee4c]*/ { … } /*[clinic input] _sre.SRE_Pattern.split string: object maxsplit: Py_ssize_t = 0 Split string by the occurrences of pattern. [clinic start generated code]*/ static PyObject * _sre_SRE_Pattern_split_impl(PatternObject *self, PyObject *string, Py_ssize_t maxsplit) /*[clinic end generated code: output=7ac66f381c45e0be input=1eeeb10dafc9947a]*/ { … } static PyObject * compile_template(_sremodulestate *module_state, PatternObject *pattern, PyObject *template) { … } static PyObject *expand_template(TemplateObject *, MatchObject *); /* Forward */ static PyObject* pattern_subx(_sremodulestate* module_state, PatternObject* self, PyObject* ptemplate, PyObject* string, Py_ssize_t count, Py_ssize_t subn) { … } /*[clinic input] _sre.SRE_Pattern.sub cls: defining_class / repl: object string: object count: Py_ssize_t = 0 Return the string obtained by replacing the leftmost non-overlapping occurrences of pattern in string by the replacement repl. [clinic start generated code]*/ static PyObject * _sre_SRE_Pattern_sub_impl(PatternObject *self, PyTypeObject *cls, PyObject *repl, PyObject *string, Py_ssize_t count) /*[clinic end generated code: output=4be141ab04bca60d input=d8d1d4ac2311a07c]*/ { … } /*[clinic input] _sre.SRE_Pattern.subn cls: defining_class / repl: object string: object count: Py_ssize_t = 0 Return the tuple (new_string, number_of_subs_made) found by replacing the leftmost non-overlapping occurrences of pattern with the replacement repl. [clinic start generated code]*/ static PyObject * _sre_SRE_Pattern_subn_impl(PatternObject *self, PyTypeObject *cls, PyObject *repl, PyObject *string, Py_ssize_t count) /*[clinic end generated code: output=da02fd85258b1e1f input=8b78a65b8302e58d]*/ { … } /*[clinic input] _sre.SRE_Pattern.__copy__ [clinic start generated code]*/ static PyObject * _sre_SRE_Pattern___copy___impl(PatternObject *self) /*[clinic end generated code: output=85dedc2db1bd8694 input=a730a59d863bc9f5]*/ { … } /*[clinic input] _sre.SRE_Pattern.__deepcopy__ memo: object / [clinic start generated code]*/ static PyObject * _sre_SRE_Pattern___deepcopy__(PatternObject *self, PyObject *memo) /*[clinic end generated code: output=2ad25679c1f1204a input=a465b1602f997bed]*/ { … } #ifdef Py_DEBUG /*[clinic input] _sre.SRE_Pattern._fail_after count: int exception: object / For debugging. [clinic start generated code]*/ static PyObject * _sre_SRE_Pattern__fail_after_impl(PatternObject *self, int count, PyObject *exception) /*[clinic end generated code: output=9a6bf12135ac50c2 input=ef80a45c66c5499d]*/ { self->fail_after_count = count; Py_INCREF(exception); Py_XSETREF(self->fail_after_exc, exception); Py_RETURN_NONE; } #endif /* Py_DEBUG */ static PyObject * pattern_repr(PatternObject *obj) { … } PyDoc_STRVAR(pattern_doc, "Compiled regular expression object."); /* PatternObject's 'groupindex' method. */ static PyObject * pattern_groupindex(PatternObject *self, void *Py_UNUSED(ignored)) { … } static int _validate(PatternObject *self); /* Forward */ /*[clinic input] _sre.compile pattern: object flags: int code: object(subclass_of='&PyList_Type') groups: Py_ssize_t groupindex: object(subclass_of='&PyDict_Type') indexgroup: object(subclass_of='&PyTuple_Type') [clinic start generated code]*/ static PyObject * _sre_compile_impl(PyObject *module, PyObject *pattern, int flags, PyObject *code, Py_ssize_t groups, PyObject *groupindex, PyObject *indexgroup) /*[clinic end generated code: output=ef9c2b3693776404 input=0a68476dbbe5db30]*/ { … } /*[clinic input] _sre.template pattern: object template: object(subclass_of="&PyList_Type") A list containing interleaved literal strings (str or bytes) and group indices (int), as returned by re._parser.parse_template(): [literal1, group1, ..., literalN, groupN] / [clinic start generated code]*/ static PyObject * _sre_template_impl(PyObject *module, PyObject *pattern, PyObject *template) /*[clinic end generated code: output=d51290e596ebca86 input=af55380b27f02942]*/ { … } /* -------------------------------------------------------------------- */ /* Code validation */ /* To learn more about this code, have a look at the _compile() function in Lib/sre_compile.py. The validation functions below checks the code array for conformance with the code patterns generated there. The nice thing about the generated code is that it is position-independent: all jumps are relative jumps forward. Also, jumps don't cross each other: the target of a later jump is always earlier than the target of an earlier jump. IOW, this is okay: J---------J-------T--------T \ \_____/ / \______________________/ but this is not: J---------J-------T--------T \_________\_____/ / \____________/ It also helps that SRE_CODE is always an unsigned type. */ /* Defining this one enables tracing of the validator */ #undef VVERBOSE /* Trace macro for the validator */ #if defined(VVERBOSE) #define VTRACE … #else #define VTRACE(v) … #endif /* Report failure */ #define FAIL … /* Extract opcode, argument, or skip count from code array */ #define GET_OP … #define GET_ARG … #define GET_SKIP_ADJ(adj) … #define GET_SKIP … static int _validate_charset(SRE_CODE *code, SRE_CODE *end) { … } /* Returns 0 on success, -1 on failure, and 1 if the last op is JUMP. */ static int _validate_inner(SRE_CODE *code, SRE_CODE *end, Py_ssize_t groups) { … } static int _validate_outer(SRE_CODE *code, SRE_CODE *end, Py_ssize_t groups) { … } static int _validate(PatternObject *self) { … } /* -------------------------------------------------------------------- */ /* match methods */ static int match_traverse(MatchObject *self, visitproc visit, void *arg) { … } static int match_clear(MatchObject *self) { … } static void match_dealloc(MatchObject* self) { … } static PyObject* match_getslice_by_index(MatchObject* self, Py_ssize_t index, PyObject* def) { … } static Py_ssize_t match_getindex(MatchObject* self, PyObject* index) { … } static PyObject* match_getslice(MatchObject* self, PyObject* index, PyObject* def) { … } /*[clinic input] _sre.SRE_Match.expand template: object Return the string obtained by doing backslash substitution on the string template, as done by the sub() method. [clinic start generated code]*/ static PyObject * _sre_SRE_Match_expand_impl(MatchObject *self, PyObject *template) /*[clinic end generated code: output=931b58ccc323c3a1 input=4bfdb22c2f8b146a]*/ { … } static PyObject* match_group(MatchObject* self, PyObject* args) { … } static PyObject* match_getitem(MatchObject* self, PyObject* name) { … } /*[clinic input] _sre.SRE_Match.groups default: object = None Is used for groups that did not participate in the match. Return a tuple containing all the subgroups of the match, from 1. [clinic start generated code]*/ static PyObject * _sre_SRE_Match_groups_impl(MatchObject *self, PyObject *default_value) /*[clinic end generated code: output=daf8e2641537238a input=bb069ef55dabca91]*/ { … } /*[clinic input] _sre.SRE_Match.groupdict default: object = None Is used for groups that did not participate in the match. Return a dictionary containing all the named subgroups of the match, keyed by the subgroup name. [clinic start generated code]*/ static PyObject * _sre_SRE_Match_groupdict_impl(MatchObject *self, PyObject *default_value) /*[clinic end generated code: output=29917c9073e41757 input=0ded7960b23780aa]*/ { … } /*[clinic input] _sre.SRE_Match.start -> Py_ssize_t group: object(c_default="NULL") = 0 / Return index of the start of the substring matched by group. [clinic start generated code]*/ static Py_ssize_t _sre_SRE_Match_start_impl(MatchObject *self, PyObject *group) /*[clinic end generated code: output=3f6e7f9df2fb5201 input=ced8e4ed4b33ee6c]*/ { … } /*[clinic input] _sre.SRE_Match.end -> Py_ssize_t group: object(c_default="NULL") = 0 / Return index of the end of the substring matched by group. [clinic start generated code]*/ static Py_ssize_t _sre_SRE_Match_end_impl(MatchObject *self, PyObject *group) /*[clinic end generated code: output=f4240b09911f7692 input=1b799560c7f3d7e6]*/ { … } LOCAL(PyObject*) _pair(Py_ssize_t i1, Py_ssize_t i2) { … } /*[clinic input] _sre.SRE_Match.span group: object(c_default="NULL") = 0 / For match object m, return the 2-tuple (m.start(group), m.end(group)). [clinic start generated code]*/ static PyObject * _sre_SRE_Match_span_impl(MatchObject *self, PyObject *group) /*[clinic end generated code: output=f02ae40594d14fe6 input=8fa6014e982d71d4]*/ { … } static PyObject* match_regs(MatchObject* self) { … } /*[clinic input] _sre.SRE_Match.__copy__ [clinic start generated code]*/ static PyObject * _sre_SRE_Match___copy___impl(MatchObject *self) /*[clinic end generated code: output=a779c5fc8b5b4eb4 input=3bb4d30b6baddb5b]*/ { … } /*[clinic input] _sre.SRE_Match.__deepcopy__ memo: object / [clinic start generated code]*/ static PyObject * _sre_SRE_Match___deepcopy__(MatchObject *self, PyObject *memo) /*[clinic end generated code: output=ba7cb46d655e4ee2 input=779d12a31c2c325e]*/ { … } PyDoc_STRVAR(match_doc, "The result of re.match() and re.search().\n\ Match objects always have a boolean value of True."); PyDoc_STRVAR(match_group_doc, "group([group1, ...]) -> str or tuple.\n\ Return subgroup(s) of the match by indices or names.\n\ For 0 returns the entire match."); static PyObject * match_lastindex_get(MatchObject *self, void *Py_UNUSED(ignored)) { … } static PyObject * match_lastgroup_get(MatchObject *self, void *Py_UNUSED(ignored)) { … } static PyObject * match_regs_get(MatchObject *self, void *Py_UNUSED(ignored)) { … } static PyObject * match_repr(MatchObject *self) { … } static PyObject* pattern_new_match(_sremodulestate* module_state, PatternObject* pattern, SRE_STATE* state, Py_ssize_t status) { … } /* -------------------------------------------------------------------- */ /* scanner methods (experimental) */ static int scanner_traverse(ScannerObject *self, visitproc visit, void *arg) { … } static int scanner_clear(ScannerObject *self) { … } static void scanner_dealloc(ScannerObject* self) { … } static int scanner_begin(ScannerObject* self) { … } static void scanner_end(ScannerObject* self) { … } /*[clinic input] _sre.SRE_Scanner.match cls: defining_class / [clinic start generated code]*/ static PyObject * _sre_SRE_Scanner_match_impl(ScannerObject *self, PyTypeObject *cls) /*[clinic end generated code: output=6e22c149dc0f0325 input=b5146e1f30278cb7]*/ { … } /*[clinic input] _sre.SRE_Scanner.search cls: defining_class / [clinic start generated code]*/ static PyObject * _sre_SRE_Scanner_search_impl(ScannerObject *self, PyTypeObject *cls) /*[clinic end generated code: output=23e8fc78013f9161 input=056c2d37171d0bf2]*/ { … } static PyObject * pattern_scanner(_sremodulestate *module_state, PatternObject *self, PyObject *string, Py_ssize_t pos, Py_ssize_t endpos) { … } /* -------------------------------------------------------------------- */ /* template methods */ static int template_traverse(TemplateObject *self, visitproc visit, void *arg) { … } static int template_clear(TemplateObject *self) { … } static void template_dealloc(TemplateObject *self) { … } static PyObject * expand_template(TemplateObject *self, MatchObject *match) { … } static Py_hash_t pattern_hash(PatternObject *self) { … } static PyObject* pattern_richcompare(PyObject *lefto, PyObject *righto, int op) { … } #include "clinic/sre.c.h" static PyMethodDef pattern_methods[] = …; static PyGetSetDef pattern_getset[] = …; #define PAT_OFF(x) … static PyMemberDef pattern_members[] = …; static PyType_Slot pattern_slots[] = …; static PyType_Spec pattern_spec = …; static PyMethodDef match_methods[] = …; static PyGetSetDef match_getset[] = …; #define MATCH_OFF(x) … static PyMemberDef match_members[] = …; /* FIXME: implement setattr("string", None) as a special case (to detach the associated string, if any */ static PyType_Slot match_slots[] = …; static PyType_Spec match_spec = …; static PyMethodDef scanner_methods[] = …; #define SCAN_OFF(x) … static PyMemberDef scanner_members[] = …; static PyType_Slot scanner_slots[] = …; static PyType_Spec scanner_spec = …; static PyType_Slot template_slots[] = …; static PyType_Spec template_spec = …; static PyMethodDef _functions[] = …; static int sre_traverse(PyObject *module, visitproc visit, void *arg) { … } static int sre_clear(PyObject *module) { … } static void sre_free(void *module) { … } #define CREATE_TYPE(m, type, spec) … #define ADD_ULONG_CONSTANT(module, name, value) … static int sre_exec(PyObject *m) { … } static PyModuleDef_Slot sre_slots[] = …; static struct PyModuleDef sremodule = …; PyMODINIT_FUNC PyInit__sre(void) { … } /* vim:ts=4:sw=4:et */