46 lines
1.8 KiB
Python
46 lines
1.8 KiB
Python
#!/usr/bin/env python3
|
|
"""Keep the type-spec name pointer C89-safe and initialize it after flags."""
|
|
import re
|
|
from pathlib import Path
|
|
|
|
source = Path("cpython/Objects/typeobject.c").read_text()
|
|
match = re.search(
|
|
r"\nPyObject \*\nPyType_FromModuleAndSpec\(PyObject \*module, PyType_Spec \*spec, PyObject \*bases\)\n"
|
|
r"\{(.*?)\n\}", source, re.S,
|
|
)
|
|
assert match, "PyType_FromModuleAndSpec definition missing"
|
|
body = re.sub(r"/\*.*?\*/|//[^\n]*", "", match.group(1), flags=re.S)
|
|
opening = body[:body.index(" nmembers = weaklistoffset")]
|
|
assert re.search(r"\bconst char \*s;", opening), (
|
|
"s must be declared in the opening declaration block (C89), before statements"
|
|
)
|
|
assert len(re.findall(r"\bconst char\s*\*s\b", body)) == 1, "declare s exactly once"
|
|
name_setup = body[body.index(" type->tp_flags = spec->flags | Py_TPFLAGS_HEAPTYPE;"):]
|
|
name_setup = name_setup[:name_setup.index(" res->ht_name = PyUnicode_FromString(s);")]
|
|
assert len(re.findall(r"strrchr\(spec->name, '\.'\)", name_setup)) == 1, (
|
|
"evaluate name search exactly once in name setup"
|
|
)
|
|
expected = """
|
|
if (spec->name == NULL) {
|
|
PyErr_SetString(PyExc_SystemError,
|
|
"Type spec does not define the name field.");
|
|
goto fail;
|
|
}
|
|
type = &res->ht_type;
|
|
type->tp_flags = spec->flags | Py_TPFLAGS_HEAPTYPE;
|
|
s = strrchr(spec->name, '.');
|
|
if (s == NULL) {
|
|
s = spec->name;
|
|
}
|
|
else {
|
|
s++;
|
|
}
|
|
res->ht_name = PyUnicode_FromString(s);
|
|
"""
|
|
actual = body[body.index(" if (spec->name == NULL)"):
|
|
body.index(" if (!res->ht_name)")]
|
|
assert actual.split() == expected.split(), (
|
|
"preserve name validation, flags, search initialization timing, and name selection"
|
|
)
|
|
print("PyType_FromModuleAndSpec s C89 declaration and same-point initialization: PASS")
|