Files
Python3-Win9x/scripts/vc6-iterobject-c89.test.py

99 lines
4.3 KiB
Python

#!/usr/bin/env python3
"""Guard C89 declaration placement and reference order in iterobject.c."""
import sys
from pathlib import Path
from typing import NoReturn
def fail(message: str) -> NoReturn:
print(message, file=sys.stderr)
raise SystemExit(1)
def extract_function(source: str, signature: str) -> str:
start = source.find(signature)
if start < 0:
fail(f"missing function signature: {signature}")
brace = source.find("{", start + len(signature))
if brace < 0:
fail("missing function body")
depth = 0
for end in range(brace, len(source)):
if source[end] == "{":
depth += 1
elif source[end] == "}":
depth -= 1
if depth == 0:
return source[brace + 1:end]
fail("unterminated function body")
def ordered(body: str, tokens: tuple[str, ...], message: str) -> None:
positions = [body.find(token) for token in tokens]
if any(position < 0 for position in positions) or positions != sorted(positions):
fail(message)
source = Path(sys.argv[1]).read_text(encoding="utf-8")
getiter = extract_function(source, "anextawaitable_getiter(anextawaitableobject *obj)")
for declaration in ("PyObject *awaitable;", "unaryfunc getter;", "PyObject *new_awaitable;"):
if declaration not in getiter:
fail("anextawaitable_getiter local must be declared before use: " + declaration)
for late in ("PyObject *awaitable =", "unaryfunc getter =", "PyObject *new_awaitable ="):
if late in getiter:
fail("anextawaitable_getiter must not initialize a local in a late declaration: " + late)
branch = getiter.split("if (Py_TYPE(awaitable)->tp_iternext == NULL) {", 1)[1]
if branch.find("unaryfunc getter;") > branch.find("getter = Py_TYPE(awaitable)->tp_as_async->am_await;"):
fail("anextawaitable_getiter branch locals must be declared before statements")
if branch.find("PyObject *new_awaitable;") > branch.find("getter = Py_TYPE(awaitable)->tp_as_async->am_await;"):
fail("anextawaitable_getiter branch locals must be declared before statements")
ordered(getiter, (
"assert(obj->wrapped != NULL);",
"awaitable = _PyCoro_GetAwaitableIter(obj->wrapped);",
"if (awaitable == NULL)",
"if (Py_TYPE(awaitable)->tp_iternext == NULL)",
"getter = Py_TYPE(awaitable)->tp_as_async->am_await;",
"new_awaitable = getter(awaitable);",
"if (new_awaitable == NULL)",
"Py_SETREF(awaitable, new_awaitable);",
"if (!PyIter_Check(awaitable))",
"return awaitable;",
), "anextawaitable_getiter must preserve awaitable conversion and cleanup order")
iternext = extract_function(source, "anextawaitable_iternext(anextawaitableobject *obj)")
for declaration in ("PyObject *awaitable;", "PyObject *result;"):
if declaration not in iternext:
fail("anextawaitable_iternext local must be declared at function entry: " + declaration)
if "PyObject *result =" in iternext:
fail("anextawaitable_iternext result must not be declared after the NULL guard")
ordered(iternext, (
"awaitable = anextawaitable_getiter(obj);",
"if (awaitable == NULL)",
"result = (*Py_TYPE(awaitable)->tp_iternext)(awaitable);",
"Py_DECREF(awaitable);",
"if (result != NULL)",
"if (PyErr_ExceptionMatches(PyExc_StopAsyncIteration))",
"_PyGen_SetStopIterationValue(obj->default_value);",
"\n return NULL;",
), "anextawaitable_iternext must preserve call, decref, and StopAsyncIteration handling order")
proxy = extract_function(source, "anextawaitable_proxy(anextawaitableobject *obj, char *meth, PyObject *arg)")
for declaration in ("PyObject *awaitable;", "PyObject *ret;"):
if declaration not in proxy:
fail("anextawaitable_proxy local must be declared at function entry: " + declaration)
if "PyObject *ret =" in proxy:
fail("anextawaitable_proxy result must not be declared after the NULL guard")
ordered(proxy, (
"awaitable = anextawaitable_getiter(obj);",
"if (awaitable == NULL)",
"ret = PyObject_CallMethod(awaitable, meth, \"O\", arg);",
"Py_DECREF(awaitable);",
"if (ret != NULL)",
"if (PyErr_ExceptionMatches(PyExc_StopAsyncIteration))",
"_PyGen_SetStopIterationValue(obj->default_value);",
"\n return NULL;",
), "anextawaitable_proxy must preserve call, decref, and exception handling order")
print("iterobject anextawaitable C89 declarations and reference order: PASS")