1.5 KiB
1.5 KiB
JOURNAL — Phase eval
Implementation notes
evaluator.py
Built evaluate(node) -> int | float walking Num, BinOp, Unary nodes.
Num: returnsnode.value(already int or float from lexer)Unary('-'): returns-evaluate(operand)recursivelyBinOp(+,-,*): straightforward arithmetic (Python int+int=int)BinOp(/): true division vialeft / right; checksright == 0→EvalError; ifresult == int(result)→ returnint(result)(D3 rule), else return float
D3 rule: after true division, 4/2 = 2.0; 2.0 == int(2.0) is True, so return int(2.0) = 2. 7/2 = 3.5; 3.5 != 3, so return 3.5 (float).
calc.py
Top-level CLI at repo root. Imports from calc.*. Catches LexError, ParseError, EvalError → prints to stderr, exits 1. Traceback never escapes.
test_evaluator.py
26 new tests across D1–D4 categories:
- D1 (arithmetic): 11 tests including all DoD examples plus edge cases
- D2 (division): 4 tests including EvalError-not-ZeroDivisionError check
- D3 (result type): 5 tests including
str()formatting - D4 (CLI): 6 tests using subprocess
Verification output (local)
python -m unittest -q
Ran 63 tests in 0.228s
OK
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: division by zero (stderr, exit 1)
python calc.py "1 +" → error: unexpected token 'EOF' (None) (stderr, exit 1)