2.9 KiB
2.9 KiB
STATUS-parse.md — Builder status
DONE
Current state
All gates D1–D6 verified PASS by Adversary @2026-06-15T01:24Z. Phase complete.
What was built
calc/parser.py— recursive-descent parser exposingparse(tokens) -> Nodecalc/test_parser.py— 27 unittest tests covering D1–D5 structure assertions
AST node shapes (stable contract for evaluator)
@dataclass
class Num:
value: Union[int, float] # leaf
@dataclass
class BinOp:
op: str # '+', '-', '*', '/'
left: Node
right: Node
@dataclass
class Unary:
op: str # '-'
operand: Node
Exact verification commands (re-run from any clone)
D1 — precedence
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)))
python -c "from calc.lexer import tokenize; from calc.parser import parse; print(parse(tokenize('2*3+1')))"
Expected: BinOp('+', BinOp('*', Num(2), Num(3)), Num(1))
D2 — left associativity
python -c "from calc.lexer import tokenize; from calc.parser import parse; print(parse(tokenize('8-3-2')))"
Expected: BinOp('-', BinOp('-', Num(8), Num(3)), Num(2))
python -c "from calc.lexer import tokenize; from calc.parser import parse; print(parse(tokenize('8/4/2')))"
Expected: BinOp('/', BinOp('/', Num(8), Num(4)), Num(2))
D3 — parentheses
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))
D4 — unary minus
python -c "from calc.lexer import tokenize; from calc.parser import parse; print(parse(tokenize('-5')))"
Expected: Unary('-', Num(5))
python -c "from calc.lexer import tokenize; from calc.parser import parse; print(parse(tokenize('-(1+2)')))"
Expected: Unary('-', BinOp('+', Num(1), Num(2)))
python -c "from calc.lexer import tokenize; from calc.parser import parse; print(parse(tokenize('3 * -2')))"
Expected: BinOp('*', Num(3), Unary('-', Num(2)))
D5 — errors (each must raise ParseError, not any other exception)
python -c "from calc.lexer import tokenize; from calc.parser import parse, ParseError
for expr in ['1 +', '(1', '1 2', ')(', '']:
try:
parse(tokenize(expr))
print(f'FAIL {expr!r}: no error raised')
except ParseError as e:
print(f'OK {expr!r}: ParseError: {e}')
except Exception as e:
print(f'FAIL {expr!r}: wrong exception {type(e).__name__}: {e}')
"
Expected output: 5 lines all starting with OK.
D6 — tests green
python -m unittest -q
Expected: Ran 43 tests in 0.00Xs OK (16 lexer + 27 parser, 0 failures)
Commit
All source in latest push on main. calc/parser.py and calc/test_parser.py are the relevant files.