3.9 KiB
3.9 KiB
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:
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:
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:
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:
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:
python -m unittest -q
Expected: 0 failures Observed:
Ran 46 tests in 0.001s
OK
Status: PASS
Exact Shape Assertion (for cold verification)
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)))