#!/usr/bin/env python3 """Check structseq_repr's name declaration and decoding/refcount 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.search( r"for \(i=0; i < VISIBLE_SIZE\(obj\); i\+\+\) \{" r"\s*const char \*name_utf8;\s*PyObject \*name;\s*if \(i > 0\)", body, ), "structseq_repr: VC6 requires name declared before loop-body statements" assert len(re.findall(r"\bPyObject\s*\*name\b", body)) == 1, ( "declare name exactly once without initialization" ) expected = ''' if (i > 0) { /* Write ", " */ if (_PyUnicodeWriter_WriteASCIIString(&writer, ", ", 2) < 0) { goto error; } } /* Write "name=repr" */ name_utf8 = typ->tp_members[i].name; if (name_utf8 == NULL) { PyErr_Format(PyExc_SystemError, "In structseq_repr(), member %zd name is NULL" " for type %.500s", i, typ->tp_name); goto error; } name = PyUnicode_DecodeUTF8(name_utf8, strlen(name_utf8), NULL); if (name == NULL) { goto error; } if (_PyUnicodeWriter_WriteStr(&writer, name) < 0) { Py_DECREF(name); goto error; } Py_DECREF(name); if (_PyUnicodeWriter_WriteChar(&writer, '=') < 0) { goto error; } value = PyStructSequence_GET_ITEM(obj, i); ''' assert re.sub(r"\s+", "", expected) in re.sub(r"\s+", "", body), ( "preserve separator, member lookup, NULL check, decoding, write/decref, " "error handling, and value lookup order" ) assert len(re.findall(r"^\s*name\s*=(?!=)", body, re.M)) == 1, "assign name exactly once" assert body.count("Py_DECREF(name)") == 2, "preserve both name decref paths" print("structseq_repr name C89 declaration and decoding/refcount order: PASS")