#!/usr/bin/env python3 """Check mro_hierarchy's n/i declarations and guarded subclass loop timing.""" import re from pathlib import Path source = Path("cpython/Objects/typeobject.c").read_text() match = re.search( r"\nstatic int\nmro_hierarchy\(PyTypeObject \*type, PyObject \*temp\)\n\{(.*?)\n\}", source, re.S, ) assert match, "mro_hierarchy definition missing" body = re.sub(r"/\*.*?\*/|//[^\n]*", "", match.group(1), flags=re.S) assert re.match( r"\s*PyObject \*old_mro;\s*PyObject \*new_mro;\s*PyObject \*tuple;" r"\s*Py_ssize_t n;\s*Py_ssize_t i;\s*int res = mro_internal\(", body ), "mro_hierarchy: n and i must be uninitialized opening function declarations" for name in ("n", "i"): assert len(re.findall(rf"\bPy_ssize_t\s+{name}\b", body)) == 1, ( f"mro_hierarchy: declare {name} exactly once" ) assert len(re.findall(rf"\b{name}\s*=(?!=)", body)) == 1, ( f"mro_hierarchy: initialize {name} exactly once at its original point" ) expected = """ if (type->tp_subclasses != NULL) { PyObject *subclasses = _PyType_GetSubclasses(type); if (subclasses == NULL) { return -1; } n = PyList_GET_SIZE(subclasses); for (i = 0; i < n; i++) { PyTypeObject *subclass = _PyType_CAST(PyList_GET_ITEM(subclasses, i)); res = mro_hierarchy(subclass, temp); if (res < 0) { break; } } Py_DECREF(subclasses); } return res; """ tail = body[body.index("if (type->tp_subclasses != NULL)"):] assert tail.split() == expected.split(), ( "mro_hierarchy: preserve NULL guard, size read, loop, cleanup, and return" ) print("mro_hierarchy n/i C89 declarations and guarded subclass loop timing: PASS")