45 lines
1.6 KiB
Python
45 lines
1.6 KiB
Python
#!/usr/bin/env python3
|
|
"""Guard the entry locals and evaluation order in _PyObject_FunctionStr."""
|
|
|
|
import re
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
source = Path(sys.argv[1]).read_text()
|
|
found = re.search(
|
|
r"\n_PyObject_FunctionStr\(PyObject \*x\)\s*\{(?P<body>.*?)\n\}",
|
|
source,
|
|
re.S,
|
|
)
|
|
assert found, "_PyObject_FunctionStr definition not found"
|
|
body = found.group("body")
|
|
for name in ("module", "result"):
|
|
declarations = re.findall(r"\bPyObject\s*\*\s*" + name + r"\b", body)
|
|
assert len(declarations) == 1, (
|
|
f"_PyObject_FunctionStr must declare {name} exactly once at entry; "
|
|
f"found {len(declarations)} declarations"
|
|
)
|
|
|
|
tokens = (
|
|
"PyObject *module;",
|
|
"PyObject *result;",
|
|
"int ret;",
|
|
"assert(!PyErr_Occurred());",
|
|
"ret = _PyObject_LookupAttr(x, &_Py_ID(__qualname__), &qualname);",
|
|
"if (qualname == NULL)",
|
|
"return PyObject_Str(x);",
|
|
"result = NULL;",
|
|
"ret = _PyObject_LookupAttr(x, &_Py_ID(__module__), &module);",
|
|
"ret = PyObject_RichCompareBool(module, &_Py_ID(builtins), Py_NE);",
|
|
'result = PyUnicode_FromFormat("%S.%S()", module, qualname);',
|
|
'result = PyUnicode_FromFormat("%S()", qualname);',
|
|
"Py_DECREF(qualname);",
|
|
"Py_XDECREF(module);",
|
|
"return result;",
|
|
)
|
|
positions = [body.find(token) for token in tokens]
|
|
assert all(position >= 0 for position in positions) and positions == sorted(positions), (
|
|
"_PyObject_FunctionStr must keep locals at entry and preserve evaluation/statement order"
|
|
)
|
|
print("object _PyObject_FunctionStr unique C89 locals and evaluation order: PASS")
|