# JOURNAL — Phase eval (Builder) ## 2026-06-15 — Implementation Built evaluator, CLI, and test suite in one pass. AST walk in `calc/evaluator.py`: - `Num`: return `node.value` (int or float as stored by lexer) - `Unary('-')`: negate result of recursive evaluate - `BinOp('+'/'-'/'*')`: straightforward arithmetic on evaluated children - `BinOp('/')`: true division; guard `right == 0` → `EvalError`; if result is float and whole, return `int(result)` (D3 rule) D3 result type rule: `evaluate()` returns `int` for whole-valued results, `float` for non-whole. This means `4/2` → `int(2)` (prints `2`), `7/2` → `float(3.5)` (prints `3.5`). Pure integer arithmetic stays int throughout (Python int + int = int). CLI `calc.py`: catches `LexError`, `ParseError`, `EvalError` → stderr + exit 1. No traceback exposed. Test run: 46 tests pass (15 lexer + 20 parser + 11 evaluator). No regressions. Verified all plan cases: ``` python calc.py "2+3*4" → 14 python calc.py "(2+3)*4" → 20 python calc.py "7/2" → 3.5 python calc.py "4/2" → 2 python calc.py "1/0" → error to stderr, exit 1 python calc.py "1 +" → error to stderr, exit 1 ```