#!/usr/bin/env python3 """Check PyTuple_Pack's C89 declaration and evaluation/refcount/error 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 \*\nPyTuple_Pack\(Py_ssize_t n, \.\.\.\)\n\{(.*?)\n\}", source.read_text(), re.S, ) assert match, "PyTuple_Pack definition not found" body = match.group(1) assert re.match( r"\s*Py_ssize_t i;\s*PyObject \*o;\s*PyObject \*\*items;" r"\s*va_list vargs;\s*PyTupleObject \*result;", body ), ( "PyTuple_Pack: result must be declared without initializer before the empty " "tuple check; declaration after statement is not C89 compatible" ) expected = """ Py_ssize_t i; PyObject *o; PyObject **items; va_list vargs; PyTupleObject *result; if (n == 0) { return tuple_get_empty(); } va_start(vargs, n); result = tuple_alloc(n); if (result == NULL) { va_end(vargs); return NULL; } items = result->ob_item; for (i = 0; i < n; i++) { o = va_arg(vargs, PyObject *); Py_INCREF(o); items[i] = o; } va_end(vargs); _PyObject_GC_TRACK(result); return (PyObject *)result; """ assert re.sub(r"\s+", "", body) == re.sub(r"\s+", "", expected), ( "preserve empty-tuple return, va_start before single allocation, failure " "va_end/NULL return, item extraction/INCREF/store, final va_end, GC tracking, " "and return order" ) print("PyTuple_Pack C89 declaration and evaluation/refcount/error order: PASS")