from __future__ import annotations
import re
import sys
from pathlib import Path
ASSERT_MACRO = re.compile(r"(?<![\w!])(?:debug_)?assert(?:_eq|_ne)?!\s*\(")
ENGINE_CONTROL = Path("hegel-c/src/control.rs")
PANIC_MACRO = re.compile(r"(?<![\w!])panic!\s*\(")
def main() -> int:
roots = [Path("src"), Path("hegel-c/src")]
offences: list[str] = []
for root in roots:
for path in sorted(root.rglob("*.rs")):
for lineno, line in enumerate(path.read_text().splitlines(), start=1):
if line.lstrip().startswith("//"):
continue
if ASSERT_MACRO.search(line):
offences.append(f" {path}:{lineno}: {line.strip()}")
panic_offences: list[str] = []
for lineno, line in enumerate(ENGINE_CONTROL.read_text().splitlines(), start=1):
if line.lstrip().startswith("//"):
continue
if PANIC_MACRO.search(line):
panic_offences.append(f" {ENGINE_CONTROL}:{lineno}: {line.strip()}")
if offences:
print("std assertion macros are not allowed in src/ or hegel-c/src/.")
print("Use hegel_internal_assert! (internal invariants) or")
print("invalid_argument! / EngineError::InvalidArgument (user-facing")
print("argument validation) instead:")
print()
print("\n".join(offences))
if panic_offences:
print("hegel-c's internal-error funnel must return Err, not panic.")
print("hegel_internal_assert! and friends expand to")
print("`return Err(InternalError::new(...).into())`; do not")
print("reintroduce a panic! into hegel-c/src/control.rs:")
print()
print("\n".join(panic_offences))
if offences or panic_offences:
return 1
print("check-internal-asserts: OK")
return 0
if __name__ == "__main__":
sys.exit(main())