#!/usr/bin/env python3 """Check _PyTuple_FromArray's C89 declarations and preserve its order.""" 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"PyObject \*\n_PyTuple_FromArray\(PyObject \*const \*src, Py_ssize_t n\)\n\{(.*?)\n\}", source.read_text(), re.S, ) assert match, "_PyTuple_FromArray definition not found" body = match.group(1) assert re.match( r"\s*PyTupleObject \*tuple;\s*PyObject \*\*dst;\s*Py_ssize_t i;" r"\s*if \(n == 0\)", body ), ( "_PyTuple_FromArray: tuple, dst and i must be declared without initializers " "before the empty-tuple check; a loop declaration is not C89 compatible" ) expected = """ PyTupleObject *tuple; PyObject **dst; Py_ssize_t i; if (n == 0) { return tuple_get_empty(); } tuple = tuple_alloc(n); if (tuple == NULL) { return NULL; } dst = tuple->ob_item; for (i = 0; i < n; i++) { PyObject *item = src[i]; Py_INCREF(item); dst[i] = item; } _PyObject_GC_TRACK(tuple); return (PyObject *)tuple; """ assert re.sub(r"\s+", "", body) == re.sub(r"\s+", "", expected), ( "preserve early empty return before single allocation, NULL handling, " "dst assignment immediately after NULL check, i initialization/condition/increment, " "unchanged item declaration, " "INCREF/store, GC tracking and return order" ) print("_PyTuple_FromArray C89 declarations and evaluation/refcount/error order: PASS")