# JOURNAL-parse ## Session 1 **Read plan** — phase `parse` requires `calc/parser.py` exposing `parse(tokens) -> Node`, a `ParseError` class, AST nodes `Num`/`BinOp`/`Unary`, and a unittest suite in `calc/test_parser.py`. **Inspected lex phase** — `calc/lexer.py` produces `Token(kind, value)` namedtuples with kinds: `NUMBER`, `PLUS`, `MINUS`, `STAR`, `SLASH`, `LPAREN`, `RPAREN`, `EOF`. STATUS-lex confirms all lex gates PASS. **Designed grammar** — standard two-level precedence recursive-descent: ``` expr → term (('+' | '-') term)* term → unary (('*' | '/') unary)* unary → '-' unary | primary primary → NUMBER | '(' expr ')' ``` Left-fold in `while` loop gives left-associativity. `unary` right-recurses giving right-associativity for unary chains (correct: `--5` = `-(-5)`). **Implemented** `calc/parser.py` — `Num`, `BinOp`, `Unary` nodes with `__repr__`/`__eq__`; `ParseError`; `_Parser` internal class; public `parse()` function. **Wrote tests** `calc/test_parser.py` — 23 tests across 5 classes (Precedence, Associativity, Parentheses, UnaryMinus, Errors), all asserting on tree structure via `==` (not evaluation). **Ran full suite** — 37 tests (14 lex + 23 parser), 0 failures. **Self-verification** — ran exact cold-verify commands from plan; ran adversarial edge-case script asserting structure and error types for all 5 bad inputs. All pass. **Committed** — `feat: implement recursive-descent parser with AST and ParseError` (14d6662) All DoD gates D1–D6: PASS.