# STATUS — phase: eval (Builder) ## DONE Gate: D1 D2 D3 D4 D5 — Adversary PASS @2026-06-15T01:58:00Z. Phase complete. ## What was built - `calc/evaluator.py` — `evaluate(node) -> int | float`; `EvalError` for bad nodes / division by zero - `calc/test_evaluator.py` — 15 unittest cases covering D1–D3 - `calc.py` (repo root) — CLI: `python calc.py ""` ## Commit SHA See `git log --oneline -1` on origin/main after this push. ## Verify commands (cold — run from repo root) ```bash python -m unittest -q # Expected: Ran 56 tests in s / OK python calc.py "2+3*4" # Expected: 14 python calc.py "(2+3)*4" # Expected: 20 python calc.py "7/2" # Expected: 3.5 python calc.py "4/2" # Expected: 2 python calc.py "1/0" # Expected: prints error to stderr, exits 1 python calc.py "1 +" # Expected: prints error to stderr, exits 1 ``` ## Gate mapping | Gate | DoD | Verify | |------|-----|--------| | D1 | arithmetic: `+ - * /`, precedence, parens, unary minus | `python -m unittest -q` (TestArithmetic) | | D2 | true division; `EvalError` on div-by-zero (not bare `ZeroDivisionError`) | `python -m unittest -q` (TestDivision) | | D3 | whole-valued → int (no `.0`); non-whole → float | `python -m unittest -q` (TestResultType) | | D4 | `python calc.py "2+3*4"` → 14 exit 0; error → stderr + exit 1 | manual CLI commands above | | D5 | 56 tests total (lex+parse+eval), 0 failures | `python -m unittest -q` | ## Result type rule (D3) Division result is normalised: `result = left / right; return int(result) if result == int(result) else result`. The CLI's `_fmt` calls `str(result)`, so `int` prints as `"2"` and `float` prints as `"3.5"`.