# STATUS-parse Phase: parse ## AST Shape Nodes are dataclasses from `calc.parser`: - `Num(value)` — leaf; value is int or float - repr: `Num(value=42)` - `BinOp(op, left, right)` — binary operation; op in ('+', '-', '*', '/') - repr: `BinOp(op='+', left=Num(value=1), right=BinOp(op='*', left=Num(value=2), right=Num(value=3)))` - `Unary(op, operand)` — unary minus; op is '-' - repr: `Unary(op='-', operand=Num(value=5))` ## Gate Results ### D1 — precedence **Check:** `1+2*3` parses as `1+(2*3)`, not `(1+2)*3` **Command:** ```bash python -c "from calc.lexer import tokenize; from calc.parser import parse; print(parse(tokenize('1+2*3')))" ``` **Expected:** `BinOp(op='+', left=Num(value=1), right=BinOp(op='*', left=Num(value=2), right=Num(value=3)))` **Observed:** `BinOp(op='+', left=Num(value=1), right=BinOp(op='*', left=Num(value=2), right=Num(value=3)))` ✓ **Result: PASS** --- ### D2 — left associativity **Check:** `8-3-2` parses as `(8-3)-2`; `8/4/2` as `(8/4)/2` **Command:** ```bash python -c "from calc.lexer import tokenize; from calc.parser import parse; print(parse(tokenize('8-3-2'))); print(parse(tokenize('8/4/2')))" ``` **Expected:** - `BinOp(op='-', left=BinOp(op='-', left=Num(value=8), right=Num(value=3)), right=Num(value=2))` - `BinOp(op='/', left=BinOp(op='/', left=Num(value=8), right=Num(value=4)), right=Num(value=2))` **Observed:** ``` BinOp(op='-', left=BinOp(op='-', left=Num(value=8), right=Num(value=3)), right=Num(value=2)) BinOp(op='/', left=BinOp(op='/', left=Num(value=8), right=Num(value=4)), right=Num(value=2)) ``` ✓ **Result: PASS** --- ### D3 — parentheses **Check:** `(1+2)*3` parses with `+` under `*` **Command:** ```bash python -c "from calc.lexer import tokenize; from calc.parser import parse; print(parse(tokenize('(1+2)*3')))" ``` **Expected:** `BinOp(op='*', left=BinOp(op='+', left=Num(value=1), right=Num(value=2)), right=Num(value=3))` **Observed:** `BinOp(op='*', left=BinOp(op='+', left=Num(value=1), right=Num(value=2)), right=Num(value=3))` ✓ **Result: PASS** --- ### D4 — unary minus **Check:** `-5`, `-(1+2)`, `3 * -2` all parse correctly **Command:** ```bash python -c "from calc.lexer import tokenize; from calc.parser import parse; print(parse(tokenize('-5'))); print(parse(tokenize('-(1+2)'))); print(parse(tokenize('3 * -2')))" ``` **Expected:** - `Unary(op='-', operand=Num(value=5))` - `Unary(op='-', operand=BinOp(op='+', left=Num(value=1), right=Num(value=2)))` - `BinOp(op='*', left=Num(value=3), right=Unary(op='-', operand=Num(value=2)))` **Observed:** ``` Unary(op='-', operand=Num(value=5)) Unary(op='-', operand=BinOp(op='+', left=Num(value=1), right=Num(value=2))) BinOp(op='*', left=Num(value=3), right=Unary(op='-', operand=Num(value=2))) ``` ✓ **Result: PASS** --- ### D5 — errors **Check:** `"1 +"`, `"(1"`, `"1 2"`, `")("`, `""` each raise `ParseError` **Command:** ```bash python -c " from calc.lexer import tokenize from calc.parser import parse, ParseError cases = ['1 +', '(1', '1 2', ')(', ''] for src in cases: try: parse(tokenize(src)) print(f'FAIL: {src!r} did not raise ParseError') except ParseError as e: print(f'PASS: {src!r} -> ParseError: {e}') except Exception as e: print(f'FAIL: {src!r} raised wrong exception {type(e).__name__}: {e}') " ``` **Expected:** All 5 cases print PASS **Observed:** ``` PASS: '1 +' -> ParseError: Unexpected end of input PASS: '(1' -> ParseError: Expected RPAREN but got 'EOF' PASS: '1 2' -> ParseError: Unexpected token NUMBER(2) PASS: ')(' -> ParseError: Unexpected token RPAREN(')') PASS: '' -> ParseError: Unexpected end of input ``` ✓ **Result: PASS** --- ### D6 — tests green **Command:** ```bash python -m unittest -q ``` **Expected:** 0 failures **Observed:** ``` ---------------------------------------------------------------------- Ran 40 tests in 0.001s OK ``` ✓ (40 = 18 from lex + 22 from parser) **Result: PASS** --- ## Cold-verify commands (for independent re-run) ```bash python -m unittest -q # Expected: Ran 40 tests ... OK python -c "from calc.lexer import tokenize; from calc.parser import parse; print(parse(tokenize('1+2*3')))" # Expected: BinOp(op='+', left=Num(value=1), right=BinOp(op='*', left=Num(value=2), right=Num(value=3))) python -c "from calc.lexer import tokenize; from calc.parser import parse; parse(tokenize('1 +'))" # Expected: ParseError: Unexpected end of input ``` ## DONE