#!/usr/bin/env python3 """Keep tupleconcat's b declaration C89-safe and assignment after validation.""" import re import sys from pathlib import Path source = Path(sys.argv[1] if len(sys.argv) > 1 else 'cpython/Objects/tupleobject.c') match = re.search(r'tupleconcat\(PyTupleObject \*a, PyObject \*bb\)\n\{(.*?)\n\}', source.read_text(), re.S) assert match, 'tupleconcat definition missing' body = match.group(1) assert re.match(r'\s*Py_ssize_t size;\s*Py_ssize_t i;\s*PyObject \*\*src, \*\*dest;\s*PyTupleObject \*np;\s*PyTupleObject \*b;\s*if', body), 'tupleconcat: b must be declared in the opening declaration group' assert 'PyTupleObject *b =' not in body, 'tupleconcat: late initialized b declaration is not C89' validation = re.search(r'if \(!PyTuple_Check\(bb\)\) \{.*?return NULL;\s*\}\s*b = \(PyTupleObject \*\)bb;\s*if \(Py_SIZE\(b\) == 0 && PyTuple_CheckExact\(a\)\)', body, re.S) assert validation, 'tupleconcat: b assignment must follow type-check/error return and precede empty-b check' assert body.index('return bb;') < validation.start(), 'tupleconcat: empty-a exact-b fast return must remain first' assert body.count('b = (PyTupleObject *)bb;') == 1, 'tupleconcat: exactly one b assignment required' assert body.index('b = (PyTupleObject *)bb;') < body.index('np = tuple_alloc(size);') < body.index('src = b->ob_item;') < body.index('_PyObject_GC_TRACK(np);'), 'tupleconcat: cast/allocation/copy/GC order changed' print('tupleconcat b C89 declaration and validation/assignment order: PASS')