Files
Python3-Win9x/scripts/vc6-object-notimplemented-c89.test.py
T

76 lines
3.3 KiB
Python

#!/usr/bin/env python3
"""Check NotImplemented's positional number slots against the CPython header."""
import re
import sys
from pathlib import Path
source = Path(sys.argv[1]).read_text()
header = Path(sys.argv[2]).read_text()
layout = re.search(r"typedef struct \{([^{}]*)\} PyNumberMethods;", header, re.S)
assert layout, "PyNumberMethods definition not found"
fields = re.findall(r"\b(nb_\w+)\s*;", layout.group(1))
assert len(fields) == 36 and fields.index("nb_bool") == 9, (
"expected 36 PyNumberMethods slots with nb_bool in slot 10"
)
initializer = re.search(
r"static PyNumberMethods notimplemented_as_number\s*=\s*\{([^{}]*)\};",
source,
re.S,
)
assert initializer, "notimplemented_as_number initializer not found"
body = re.sub(r"/\*.*?\*/", "", initializer.group(1), flags=re.S)
assert not re.search(r"\.\s*\w+\s*=", body), (
"notimplemented_as_number must use a VC6-compatible positional initializer"
)
slots = [value.strip() for value in body.strip().rstrip(",").split(",")]
assert len(slots) == len(fields), "every PyNumberMethods slot must be explicit"
for field, value in zip(fields, slots):
expected = "notimplemented_bool" if field == "nb_bool" else "0"
assert value == expected, f"{field}: expected {expected}, got {value}"
print("object NotImplemented C89 positional initializer: PASS (36 slots; nb_bool slot 10)")
start = source.index("_PyTypes_InitTypes(PyInterpreterState *interp)\n{")
opening = source.index("{", start)
end = source.index("\n}\n", opening)
init_types = source[opening:end]
assert re.match(r"\{\s*size_t i;\s*if \(!_Py_IsMainInterpreter\(interp\)\)", init_types), (
"_PyTypes_InitTypes must declare size_t i before the interpreter guard"
)
assert len(re.findall(r"\bsize_t\s+i\b", init_types)) == 1, (
"_PyTypes_InitTypes must declare its loop counter exactly once"
)
assert "for (i=0; i < Py_ARRAY_LENGTH(static_types); i++) {" in init_types, (
"_PyTypes_InitTypes must use the C89 counter with unchanged loop bounds/traversal"
)
assert init_types.index("_Py_GenericAlias_InitTypes();") < init_types.index("for (i=0;"), (
"_PyTypes_InitTypes loop initialization must remain after VC6 type initialization"
)
print("object _PyTypes_InitTypes C89 loop counter declaration and initialization order: PASS")
start = source.index("_PyTypes_FiniTypes(PyInterpreterState *interp)\n{")
opening = source.index("{", start)
end = source.index("\n}\n", opening)
fini_types = source[opening:end]
assert re.match(r"\{\s*Py_ssize_t i;\s*if \(!_Py_IsMainInterpreter\(interp\)\)", fini_types), (
"_PyTypes_FiniTypes must declare Py_ssize_t i before the interpreter guard"
)
assert len(re.findall(r"\bPy_ssize_t\s+i\b", fini_types)) == 1, (
"_PyTypes_FiniTypes must declare its signed loop counter exactly once"
)
expected = '''{
Py_ssize_t i;
if (!_Py_IsMainInterpreter(interp)) {
return;
}
for (i=Py_ARRAY_LENGTH(static_types)-1; i>=0; i--) {
PyTypeObject *type = static_types[i];
_PyStaticType_Dealloc(type);
}
'''
assert re.sub(r"//[^\n]*", "", fini_types).split() == expected.split(), (
"_PyTypes_FiniTypes must preserve the interpreter guard, reverse loop bounds/traversal, "
"and block-opening type lookup before each deallocation"
)
print("object _PyTypes_FiniTypes C89 loop counter and reverse per-item deallocation order: PASS")