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

4.2 KiB
Raw Blame History

STATUS-parse — Builder

DONE

All gates D1D6 verified PASS by Adversary @2026-06-15T00:50Z. See REVIEW-parse.md.


Gate: D1D6 CLAIMED → PASS

All six gates are implemented and verified locally.


Files

File Description
calc/parser.py Recursive-descent parser exposing parse(tokens) -> Node
calc/test_parser.py unittest suite covering D1D6

AST Node Types (stable shape for evaluator)

@dataclass
class Num:
    value: Any          # int or float from lexer

@dataclass
class BinOp:
    op: str             # '+', '-', '*', '/'
    left: Any           # Node
    right: Any          # Node

@dataclass
class Unary:
    op: str             # '-'
    operand: Any        # Node

All three are dataclasses with __repr__ — equality comparison works via ==.


Verification commands (cold-runnable from any clone)

# D6 — all tests green
python -m unittest -q

# D1 — precedence: 1+2*3 => BinOp('+', Num(1), BinOp('*', Num(2), Num(3)))
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)))

# D1 — precedence: 2*3+1 => BinOp('+', BinOp('*', Num(2), Num(3)), Num(1))
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 assoc subtraction: 8-3-2 => BinOp('-', BinOp('-', Num(8), Num(3)), Num(2))
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))

# D2 — left assoc division: 8/4/2 => BinOp('/', BinOp('/', Num(8), Num(4)), 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 — parens override: (1+2)*3 => BinOp('*', BinOp('+', Num(1), Num(2)), Num(3))
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))
python -c "from calc.lexer import tokenize; from calc.parser import parse; print(parse(tokenize('-5')))"
# expected: Unary('-', Num(5))

# D4 — unary in paren: -(1+2) => Unary('-', BinOp('+', Num(1), Num(2)))
python -c "from calc.lexer import tokenize; from calc.parser import parse; print(parse(tokenize('-(1+2)')))"
# expected: Unary('-', BinOp('+', Num(1), Num(2)))

# D4 — unary in mul: 3 * -2 => BinOp('*', Num(3), Unary('-', 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 — each raises ParseError (must NOT raise any other exception)
python -c "from calc.lexer import tokenize; from calc.parser import parse, ParseError
for s in ['1 +', '(1', '1 2', ')(', '']:
    try: parse(tokenize(s)); print(f'FAIL no error for {s!r}')
    except ParseError as e: print(f'OK {s!r} => ParseError: {e}')
    except Exception as e: print(f'FAIL wrong exc for {s!r}: {type(e).__name__}: {e}')
"
# expected: 5 lines each starting "OK"

Expected outputs (exact)

Gate Expression Expected repr
D1 1+2*3 BinOp('+', Num(1), BinOp('*', Num(2), Num(3)))
D1 2*3+1 BinOp('+', BinOp('*', Num(2), Num(3)), Num(1))
D2 8-3-2 BinOp('-', BinOp('-', Num(8), Num(3)), Num(2))
D2 8/4/2 BinOp('/', BinOp('/', Num(8), Num(4)), Num(2))
D3 (1+2)*3 BinOp('*', BinOp('+', Num(1), Num(2)), Num(3))
D4 -5 Unary('-', Num(5))
D4 -(1+2) Unary('-', BinOp('+', Num(1), Num(2)))
D4 3 * -2 BinOp('*', Num(3), Unary('-', Num(2)))
D5 1 + ParseError: unexpected token 'EOF' (None)
D5 (1 ParseError: expected RPAREN, got 'EOF' (None)
D5 1 2 ParseError: unexpected token 'NUMBER' (2) after expression
D5 )( ParseError: unexpected token 'RPAREN' (')')
D5 `` ParseError: empty expression
D6 python -m unittest -q Ran 46 tests in …s OK