Files
Python3-Win9x/scripts/vc6-typeobject-find-name-in-mro-c89.test.py

77 lines
2.2 KiB
Python

#!/usr/bin/env python3
"""Keep find_name_in_mro mro/res C89-safe without changing lookup timing."""
import re
from pathlib import Path
source = Path("cpython/Objects/typeobject.c").read_text()
match = re.search(
r"\nfind_name_in_mro\(PyTypeObject \*type, PyObject \*name, int \*error\)\n"
r"\{(.*?)\n\}", source, re.S,
)
assert match, "find_name_in_mro definition missing"
body = re.sub(r"/\*.*?\*/|//[^\n]*", "", match.group(1), flags=re.S)
assert re.match(r"\s*Py_hash_t hash;\s*PyObject \*mro;\s*PyObject \*res;\s*Py_ssize_t n;\s*(?:Py_ssize_t i;\s*)?if", body), (
"find_name_in_mro: mro and res must be declared at function entry (C89)"
)
assert not re.search(r"for\s*\(\s*Py_ssize_t\s+i\b", body), (
"find_name_in_mro: i remains declared in the for initializer (C89)"
)
expected = """
Py_hash_t hash;
PyObject *mro;
PyObject *res;
Py_ssize_t n;
Py_ssize_t i;
if (!PyUnicode_CheckExact(name) ||
(hash = _PyASCIIObject_CAST(name)->hash) == -1)
{
hash = PyObject_Hash(name);
if (hash == -1) {
*error = -1;
return NULL;
}
}
mro = type->tp_mro;
if (mro == NULL) {
if ((type->tp_flags & Py_TPFLAGS_READYING) == 0) {
if (PyType_Ready(type) < 0) {
*error = -1;
return NULL;
}
mro = type->tp_mro;
}
if (mro == NULL) {
*error = 1;
return NULL;
}
}
res = NULL;
Py_INCREF(mro);
n = PyTuple_GET_SIZE(mro);
for (i = 0; i < n; i++) {
PyObject *base = PyTuple_GET_ITEM(mro, i);
PyObject *dict = _PyType_CAST(base)->tp_dict;
assert(dict && PyDict_Check(dict));
res = _PyDict_GetItem_KnownHash(dict, name, hash);
if (res != NULL) {
break;
}
if (PyErr_Occurred()) {
*error = -1;
goto done;
}
}
*error = 0;
done:
Py_DECREF(mro);
return res;"""
assert body.split() == expected.split(), (
"find_name_in_mro: preserve hash/readiness checks, mro/res assignment timing, "
"reference handling, lookup, errors, and opening n/i declarations"
)
print("find_name_in_mro mro/res C89 declarations and same-point assignments: PASS")