#!/usr/bin/env python3 """Check initialize_structseq_dict's C89 declarations and operation 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 int\ninitialize_structseq_dict\(.*?\) \{(.*?)\n\}", source.read_text(), re.S, ) assert match, "initialize_structseq_dict definition not found" body = match.group(1) assert re.match( r"\s*PyObject \*v;\s*Py_ssize_t i, k;\s*PyObject\* keys;", body ), "i, k, and uninitialized keys must precede all statements for C89" assert re.search( r"for \(i = k = 0; i < desc->n_in_sequence; \+\+i\) \{" r"\s*PyObject\* new_member;\s*if", body ), "uninitialized new_member must precede the loop's unnamed-field check for C89" expected = r""" PyObject *v; Py_ssize_t i, k; PyObject* keys; #define SET_DICT_FROM_SIZE(key, value) \ do { \ v = PyLong_FromSsize_t(value); \ if (v == NULL) { \ return -1; \ } \ if (PyDict_SetItemString(dict, key, v) < 0) { \ Py_DECREF(v); \ return -1; \ } \ Py_DECREF(v); \ } while (0) SET_DICT_FROM_SIZE(visible_length_key, desc->n_in_sequence); SET_DICT_FROM_SIZE(real_length_key, n_members); SET_DICT_FROM_SIZE(unnamed_fields_key, n_unnamed_members); // Prepare and set __match_args__ keys = PyTuple_New(desc->n_in_sequence); if (keys == NULL) { return -1; } for (i = k = 0; i < desc->n_in_sequence; ++i) { PyObject* new_member; if (desc->fields[i].name == PyStructSequence_UnnamedField) { continue; } new_member = PyUnicode_FromString(desc->fields[i].name); if (new_member == NULL) { goto error; } PyTuple_SET_ITEM(keys, k, new_member); k++; } if (_PyTuple_Resize(&keys, k) == -1) { goto error; } if (PyDict_SetItemString(dict, match_args_key, keys) < 0) { goto error; } Py_DECREF(keys); return 0; error: Py_DECREF(keys); return -1; """ assert re.sub(r"\s+", "", body) == re.sub(r"\s+", "", expected), ( "preserve metadata writes and early returns before tuple allocation, skip " "unnamed fields before Unicode allocation, and preserve insertion, resize, " "match-args write, refcount, and cleanup order" ) print("initialize_structseq_dict C89 declarations and operation order: PASS")