"""Tiny S-expression parser used by tests for round-trip validation. Not a full KiCad reader — just enough to confirm our writer output is syntactically valid Lisp-flavored S-expr (balanced parens, quoted strings, numbers, symbols). """ from __future__ import annotations from typing import Iterator def tokens(src: str) -> Iterator[str]: i, n = 0, len(src) while i < n: c = src[i] if c.isspace(): i += 1 continue if c == "(": yield "(" i += 1 continue if c == ")": yield ")" i += 1 continue if c == '"': j = i + 1 buf = [] while j < n: ch = src[j] if ch == "\\" and j + 1 < n: nxt = src[j + 1] buf.append({"\\": "\\", '"': '"', "n": "\n", "t": "\t"}.get(nxt, nxt)) j += 2 continue if ch == '"': break buf.append(ch) j += 1 if j >= n: raise SyntaxError("unterminated string") yield '"' + "".join(buf) + '"' i = j + 1 continue # bare token until whitespace or paren j = i while j < n and not src[j].isspace() and src[j] not in "()": j += 1 yield src[i:j] i = j def parse(src: str): it = iter(tokens(src)) def _read(tok): if tok == "(": out = [] while True: try: nxt = next(it) except StopIteration: raise SyntaxError("unterminated list") if nxt == ")": return out out.append(_read(nxt)) if tok == ")": raise SyntaxError("unexpected )") if tok.startswith('"') and tok.endswith('"'): return tok[1:-1] try: return int(tok) except ValueError: try: return float(tok) except ValueError: return tok # symbol try: first = next(it) except StopIteration: raise SyntaxError("empty input") val = _read(first) # Expect EOF for extra in it: raise SyntaxError(f"unexpected trailing token: {extra!r}") return val