# STATUS-parse.md ## AST Node Shapes ``` Num(value) — numeric literal (int or float) Unary('-', operand) — unary negation; operand is any Node BinOp(op, left, right) — binary operation; op in {'+', '-', '*', '/'} ``` All nodes are Python dataclasses with `__repr__` and structural equality via `__eq__`. ## Gate Verification ### D1 — Precedence (`*`/`/` bind tighter than `+`/`-`) **Command:** ```bash python -c "from calc.lexer import tokenize; from calc.parser import parse; print(parse(tokenize('1+2*3')))" ``` **Expected:** `BinOp('+', Num(1), BinOp('*', Num(2), Num(3)))` **Observed:** `BinOp('+', Num(1), BinOp('*', Num(2), Num(3)))` ✓ **Status: PASS** --- ### D2 — Left Associativity (same-precedence operators associate left) **Commands:** ```bash python -c "from calc.lexer import tokenize; from calc.parser import parse; print(parse(tokenize('8-3-2')))" python -c "from calc.lexer import tokenize; from calc.parser import parse; print(parse(tokenize('8/4/2')))" ``` **Expected:** - `8-3-2` → `BinOp('-', BinOp('-', Num(8), Num(3)), Num(2))` - `8/4/2` → `BinOp('/', BinOp('/', Num(8), Num(4)), Num(2))` **Observed:** - `BinOp('-', BinOp('-', Num(8), Num(3)), Num(2))` ✓ - `BinOp('/', BinOp('/', Num(8), Num(4)), Num(2))` ✓ **Status: PASS** --- ### D3 — Parentheses override precedence **Command:** ```bash python -c "from calc.lexer import tokenize; from calc.parser import parse; print(parse(tokenize('(1+2)*3')))" ``` **Expected:** `BinOp('*', BinOp('+', Num(1), Num(2)), Num(3))` **Observed:** `BinOp('*', BinOp('+', Num(1), Num(2)), Num(3))` ✓ **Status: PASS** --- ### D4 — Unary minus (leading and nested) **Commands:** ```bash python -c "from calc.lexer import tokenize; from calc.parser import parse; print(parse(tokenize('-5')))" python -c "from calc.lexer import tokenize; from calc.parser import parse; print(parse(tokenize('-(1+2)')))" python -c "from calc.lexer import tokenize; from calc.parser import parse; print(parse(tokenize('3 * -2')))" ``` **Expected:** - `-5` → `Unary('-', Num(5))` - `-(1+2)` → `Unary('-', BinOp('+', Num(1), Num(2)))` - `3 * -2` → `BinOp('*', Num(3), Unary('-', Num(2)))` **Observed:** - `Unary('-', Num(5))` ✓ - `Unary('-', BinOp('+', Num(1), Num(2)))` ✓ - `BinOp('*', Num(3), Unary('-', Num(2)))` ✓ **Status: PASS** --- ### D5 — Malformed input raises ParseError **Commands:** `parse(tokenize(x))` for each bad input x | Input | Expected | Observed | |---------|--------------------|--------------------------------------------------| | `"1 +"` | ParseError | `ParseError: unexpected end of input` ✓ | | `"(1"` | ParseError | `ParseError: expected ')' but got 'EOF'` ✓ | | `"1 2"` | ParseError | `ParseError: unexpected token 'NUMBER' (2)...` ✓| | `")("` | ParseError | `ParseError: unexpected token 'RPAREN' (')')` ✓ | | `""` | ParseError | `ParseError: empty input` ✓ | **Status: PASS** --- ### D6 — Tests green **Command:** ```bash python -m unittest -q ``` **Expected:** 0 failures **Observed:** ``` Ran 46 tests in 0.001s OK ``` **Status: PASS** --- ## Exact Shape Assertion (for cold verification) ```python from calc.lexer import tokenize from calc.parser import parse, BinOp, Num, Unary # D1 assert parse(tokenize('1+2*3')) == BinOp('+', Num(1), BinOp('*', Num(2), Num(3))) # D2 assert parse(tokenize('8-3-2')) == BinOp('-', BinOp('-', Num(8), Num(3)), Num(2)) assert parse(tokenize('8/4/2')) == BinOp('/', BinOp('/', Num(8), Num(4)), Num(2)) # D3 assert parse(tokenize('(1+2)*3')) == BinOp('*', BinOp('+', Num(1), Num(2)), Num(3)) # D4 assert parse(tokenize('-5')) == Unary('-', Num(5)) assert parse(tokenize('-(1+2)')) == Unary('-', BinOp('+', Num(1), Num(2))) assert parse(tokenize('3 * -2')) == BinOp('*', Num(3), Unary('-', Num(2))) ``` ## DONE