# REVIEW-parse.md — Adversary verdicts ## Status All D1–D6 PASS. Phase complete. ## Verdicts ### parse/D1: PASS @2026-06-15T01:24Z Cold-ran: - `parse(tokenize('1+2*3'))` → `BinOp('+', Num(1), BinOp('*', Num(2), Num(3)))` ✓ - `parse(tokenize('2*3+1'))` → `BinOp('+', BinOp('*', Num(2), Num(3)), Num(1))` ✓ - Adversarial `1+2*3+4` → `BinOp('+', BinOp('+', Num(1), BinOp('*', Num(2), Num(3))), Num(4))` ✓ - Adversarial `1+2+3*4` → `BinOp('+', BinOp('+', Num(1), Num(2)), BinOp('*', Num(3), Num(4)))` ✓ - Adversarial `10-6/2` → `BinOp('-', Num(10), BinOp('/', Num(6), Num(2)))` (covered in test suite) ✓ Grammar hierarchy `_expr`→`_term`→`_unary`→`_primary` correctly implements `*`/`/` at higher precedence. ### parse/D2: PASS @2026-06-15T01:24Z Cold-ran: - `parse(tokenize('8-3-2'))` → `BinOp('-', BinOp('-', Num(8), Num(3)), Num(2))` ✓ - `parse(tokenize('8/4/2'))` → `BinOp('/', BinOp('/', Num(8), Num(4)), Num(2))` ✓ - Adversarial `10-3-2-1` → `BinOp('-', BinOp('-', BinOp('-', Num(10), Num(3)), Num(2)), Num(1))` ✓ - Adversarial `2*3*4` → `BinOp('*', BinOp('*', Num(2), Num(3)), Num(4))` ✓ `while` loops in `_expr`/`_term` accumulate left-to-right, enforcing left associativity correctly. ### parse/D3: PASS @2026-06-15T01:24Z Cold-ran: - `parse(tokenize('(1+2)*3'))` → `BinOp('*', BinOp('+', Num(1), Num(2)), Num(3))` ✓ - Adversarial `((1+2))` → `BinOp('+', Num(1), Num(2))` (double nesting stripped) ✓ - Adversarial `(42)` → `Num(42)` ✓ `_primary` correctly handles LPAREN by recursing into `_expr` then consuming RPAREN. ### parse/D4: PASS @2026-06-15T01:24Z Cold-ran: - `parse(tokenize('-5'))` → `Unary('-', Num(5))` ✓ - `parse(tokenize('-(1+2)'))` → `Unary('-', BinOp('+', Num(1), Num(2)))` ✓ - `parse(tokenize('3 * -2'))` → `BinOp('*', Num(3), Unary('-', Num(2)))` ✓ - Adversarial `--5` → `Unary('-', Unary('-', Num(5)))` ✓ (recursive unary) - Adversarial `-1*2` → `BinOp('*', Unary('-', Num(1)), Num(2))` ✓ (unary binds tighter than `*`) - Adversarial `-1+2` → `BinOp('+', Unary('-', Num(1)), Num(2))` ✓ ### parse/D5: PASS @2026-06-15T01:24Z Cold-ran all 5 required cases — all raise `ParseError`, not any other exception: - `'1 +'` → `ParseError: unexpected end of input` ✓ - `'(1'` → `ParseError: expected 'RPAREN' but got 'EOF' (value=None)` ✓ - `'1 2'` → `ParseError: unexpected token after expression: 'NUMBER' (value=2)` ✓ - `')('` → `ParseError: unexpected token 'RPAREN' (value=')')` ✓ - `''` → `ParseError: empty expression` ✓ Additional adversarial cases also raise `ParseError` correctly: - `'+5'` → `ParseError` (unary plus not in grammar) ✓ - `'()'` → `ParseError` ✓ - `'-'` (lone minus) → `ParseError` ✓ ### parse/D6: PASS @2026-06-15T01:24Z Cold-ran `python -m unittest -q` from repo root: ``` Ran 43 tests in 0.001s OK ``` 43 tests (16 lexer + 27 parser), 0 failures. Test suite uses `dataclass` structural equality (`assertEqual`), not string matching — verifies tree shape correctly. Coverage confirmed: 4 D1 tests, 4 D2 tests, 4 D3 tests, 5 D4 tests, 7 D5 tests (exceeds required 5). ## Adversary findings (none — no defects found)