Files
agent-orchestrator-benchmark/calculators/builder-adversary-deferred/run-04/machine-docs/STATUS-parse.md

4.2 KiB
Raw Blame History

STATUS — parse phase

DONE

All DoD gates D1D6 implemented and self-certified (BUILD phase — DEFERRED review protocol).


What was built

  • calc/parser.pyParseError, Num, BinOp, Unary, parse(tokens) -> Node
  • calc/test_parser.py — 24 unittest cases covering D1D5 (D6 = all pass)

AST shape (stable contract for the evaluator)

Num(value)              .value  — int or float
BinOp(op, left, right)  .op     — one of '+', '-', '*', '/'
                        .left   — any Node
                        .right  — any Node
Unary(op, operand)      .op     — '-'
                        .operand — any Node

All nodes implement __repr__ and __eq__.


D1 — Precedence ✓

1+2*3 parses as BinOp('+', Num(1), BinOp('*', Num(2), Num(3)))* tighter than +.

Verify:

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)))

D2 — Left associativity ✓

8-3-2BinOp('-', BinOp('-', Num(8), Num(3)), Num(2)) 8/4/2BinOp('/', BinOp('/', Num(8), Num(4)), Num(2))

Verify:

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 ✓

(1+2)*3BinOp('*', BinOp('+', Num(1), Num(2)), Num(3))+ is child of *.

Verify:

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 ✓

-5        → Unary('-', Num(5))
-(1+2)    → Unary('-', BinOp('+', Num(1), Num(2)))
3 * -2    → BinOp('*', Num(3), Unary('-', Num(2)))

Verify:

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 of the following raises ParseError (not any other exception):

Input ParseError message
'1 +' Unexpected end of input
'(1' Expected RPAREN, got 'EOF' (None)
'1 2' Unexpected token after expression: 'NUMBER' (2)
')(' Unexpected token 'RPAREN' (')')
'' Empty input

Verify:

python -c "from calc.lexer import tokenize; from calc.parser import parse; parse(tokenize('1 +'))"
# Expected: raises ParseError: Unexpected end of input

python -c "from calc.lexer import tokenize; from calc.parser import parse; parse(tokenize('(1'))"
# Expected: raises ParseError: Expected RPAREN...

python -c "from calc.lexer import tokenize; from calc.parser import parse; parse(tokenize('1 2'))"
# Expected: raises ParseError: Unexpected token after expression...

python -c "from calc.lexer import tokenize; from calc.parser import parse; parse(tokenize(')('))"
# Expected: raises ParseError: Unexpected token 'RPAREN'...

python -c "from calc.lexer import tokenize; from calc.parser import parse; parse(tokenize(''))"
# Expected: raises ParseError: Empty input

D6 — Tests green ✓

44 total tests (20 lex + 24 parser), 0 failures.

Verify:

python -m unittest -q
# Expected: Ran 44 tests in 0.00xs / OK

Plan verify commands (from parse.md)

python -m unittest -q
# → Ran 44 tests in 0.001s / OK

python -c "from calc.lexer import tokenize; from calc.parser import parse; print(parse(tokenize('1+2*3')))"
# → BinOp('+', Num(1), BinOp('*', Num(2), Num(3)))

python -c "from calc.lexer import tokenize; from calc.parser import parse; parse(tokenize('1 +'))"
# → ParseError: Unexpected end of input