#!/usr/bin/env python3 """Keep PyType_GetModuleByDef's loop index in opening C89 locals.""" import re from pathlib import Path source = Path("cpython/Objects/typeobject.c").read_text() match = re.search( r"\nPyObject \*\nPyType_GetModuleByDef\(PyTypeObject \*type, PyModuleDef \*def\)\n" r"\{(.*?)\n\}", source, re.S, ) assert match, "PyType_GetModuleByDef definition missing" body = re.sub(r"/\*.*?\*/|//[^\n]*", "", match.group(1), flags=re.S) assert re.match(r"\s*PyObject \*mro;\s*Py_ssize_t n;\s*Py_ssize_t i;\s*PyHeapTypeObject \*ht;\s*PyObject \*module;\s*assert\(", body), ( "PyType_GetModuleByDef: i must be declared in the opening declaration block (C89)" ) assert len(re.findall(r"\bPy_ssize_t\s+i\b", body)) == 1, ( "PyType_GetModuleByDef: declare i exactly once" ) expected = """ PyObject *mro; Py_ssize_t n; Py_ssize_t i; PyHeapTypeObject *ht; PyObject *module; assert(PyType_Check(type)); mro = type->tp_mro; assert(mro != NULL); assert(PyTuple_Check(mro)); assert(PyTuple_GET_SIZE(mro) >= 1); n = PyTuple_GET_SIZE(mro); for (i = 0; i < n; i++) { PyObject *super = PyTuple_GET_ITEM(mro, i); if(!_PyType_HasFeature((PyTypeObject *)super, Py_TPFLAGS_HEAPTYPE)) { continue; } ht = (PyHeapTypeObject*)super; module = ht->ht_module; if (module && _PyModule_GetDef(module) == def) { return module; } } PyErr_Format( PyExc_TypeError, "PyType_GetModuleByDef: No superclass of '%s' has the given module", type->tp_name); return NULL; """ assert body.split() == expected.split(), ( "PyType_GetModuleByDef: preserve loop initialization, bound, increment, body, and surrounding " "loop, module lookup, and error handling" ) print("PyType_GetModuleByDef C89 loop index and preserved loop semantics: PASS")