"""
Validate .sr files (openUBMC CSR/PSR self-description records).
.sr files are JSON with C-style comments (JSONC). This hook strips
// line comments and /* */ block comments using a state machine that
respects string literals, then parses the result with json.loads.
Pure standard library only — no json5/jsonc dependencies.
Usage: check_sr.py <file1.sr> [file2.sr ...]
"""
import json
import sys
from typing import Sequence
_NORMAL = 0
_IN_STRING = 1
_IN_STRING_ESCAPE = 2
_IN_LINE_COMMENT = 3
_IN_BLOCK_COMMENT = 4
_IN_BLOCK_COMMENT_STAR = 5
def strip_comments(text: str) -> str:
"""
Strip // line comments and /* */ block comments from JSON-like text.
Uses a state machine to correctly skip comment markers that appear
inside string literals (e.g. "https://example.com" must be preserved).
Newlines are preserved even inside stripped comments so that json
error messages stay aligned with the original file's line numbers.
"""
out = []
state = _NORMAL
i = 0
n = len(text)
while i < n:
ch = text[i]
nxt = text[i + 1] if i + 1 < n else ""
if state == _NORMAL:
if ch == '"':
out.append(ch)
state = _IN_STRING
elif ch == "/" and nxt == "/":
state = _IN_LINE_COMMENT
i += 1
elif ch == "/" and nxt == "*":
state = _IN_BLOCK_COMMENT
i += 1
else:
out.append(ch)
elif state == _IN_STRING:
out.append(ch)
if ch == "\\":
state = _IN_STRING_ESCAPE
elif ch == '"':
state = _NORMAL
elif state == _IN_STRING_ESCAPE:
out.append(ch)
state = _IN_STRING
elif state == _IN_LINE_COMMENT:
if ch == "\n":
out.append("\n")
state = _NORMAL
elif state == _IN_BLOCK_COMMENT:
if ch == "*":
state = _IN_BLOCK_COMMENT_STAR
else:
if ch == "/":
state = _NORMAL
elif ch == "*":
pass
else:
state = _IN_BLOCK_COMMENT
i += 1
return "".join(out)
def main(argv: Sequence[str] | None = None) -> int:
if argv is None:
argv = sys.argv[1:]
if not argv:
return 0
retval = 0
for path in argv:
try:
with open(path, encoding="utf-8-sig") as f:
raw = f.read()
json.loads(strip_comments(raw))
except (OSError, ValueError) as e:
print(f"{path}: {e}")
retval = 1
return retval
if __name__ == "__main__":
raise SystemExit(main())