#!/usr/bin/env python3 """Check structseq_repr's value/repr declarations and ownership/order.""" import re import sys from pathlib import Path source = Path(sys.argv[1] if len(sys.argv) > 1 else "cpython/Objects/structseq.c") match = re.search( r"static PyObject \*\nstructseq_repr\(PyStructSequence \*obj\)\n\{(.*?)\n\}", source.read_text(), re.S, ) assert match, "structseq_repr definition not found" body = match.group(1) assert re.match( r"\s*PyTypeObject \*typ = Py_TYPE\(obj\);" r"\s*_PyUnicodeWriter writer;\s*Py_ssize_t i;" r"\s*PyObject \*value;\s*PyObject \*repr;", body, ), "structseq_repr: VC6 requires value and repr in the function entry declaration block" for variable in ("value", "repr"): assert len(re.findall(r"\bPyObject\s*\*" + variable + r"\b", body)) == 1, ( "declare " + variable + " exactly once" ) assert len(re.findall(r"\b" + variable + r"\s*=(?!=)", body)) == 1, ( "assign " + variable + " exactly once at its original evaluation point" ) expected = """ Py_DECREF(name); if (_PyUnicodeWriter_WriteChar(&writer, '=') < 0) { goto error; } value = PyStructSequence_GET_ITEM(obj, i); assert(value != NULL); repr = PyObject_Repr(value); if (repr == NULL) { goto error; } if (_PyUnicodeWriter_WriteStr(&writer, repr) < 0) { Py_DECREF(repr); goto error; } Py_DECREF(repr); } if (_PyUnicodeWriter_WriteChar(&writer, ')') < 0) { goto error; } return _PyUnicodeWriter_Finish(&writer); error: _PyUnicodeWriter_Dealloc(&writer); return NULL; """ assert re.sub(r"\s+", "", body).endswith(re.sub(r"\s+", "", expected)), ( "preserve name cleanup, '=' output, borrowed value lookup, repr creation, " "write/decref paths, and writer finish/error cleanup order" ) assert len(re.findall(r"\bvalue\b", body)) == 4, "preserve borrowed value ownership" assert len(re.findall(r"\brepr\b", re.sub(r"/\*.*?\*/", "", body, flags=re.S))) == 6, ( "preserve repr ownership and both decref paths" ) print("structseq_repr value/repr C89 declarations and ownership/order: PASS")