#!/usr/bin/env python3 """Keep type-spec doc locals C89-safe without moving their evaluations.""" import re from pathlib import Path source = Path("cpython/Objects/typeobject.c").read_text() match = re.search( r"\nPyObject \*\nPyType_FromModuleAndSpec\(PyObject \*module, PyType_Spec \*spec, PyObject \*bases\)\n" r"\{(.*?)\n\}", source, re.S, ) assert match, "PyType_FromModuleAndSpec definition missing" body = re.sub(r"/\*.*?\*/|//[^\n]*", "", match.group(1), flags=re.S) match = re.search( r"else if \(slot->slot == Py_tp_doc\) \{(.*?)\n \}" r"\s*else if \(slot->slot == Py_tp_members\)", body, re.S, ) assert match, "Py_tp_doc branch missing" branch = match.group(1) assert re.match(r"\s*size_t len;\s*char \*tp_doc;\s*if", branch), ( "len and tp_doc must be declared at the start of the Py_tp_doc block (C89)" ) expected = """ size_t len; char *tp_doc; if (slot->pfunc == NULL) { type->tp_doc = NULL; continue; } len = strlen(slot->pfunc)+1; tp_doc = PyObject_Malloc(len); if (tp_doc == NULL) { type->tp_doc = NULL; PyErr_NoMemory(); goto fail; } memcpy(tp_doc, slot->pfunc, len); type->tp_doc = tp_doc; """ assert branch.split() == expected.split(), ( "preserve NULL guard, length/allocation evaluation order, failure handling, and copy" ) print("PyType_FromModuleAndSpec doc locals C89 declarations and evaluation order: PASS")