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

3.7 KiB
Raw Blame History

STATUS — phase parse

DONE

All DoD gates self-certified (BUILD phase — deferred review).

Gates

Gate Status
D1 — precedence PASS (self-certified)
D2 — left associativity PASS (self-certified)
D3 — parentheses PASS (self-certified)
D4 — unary minus PASS (self-certified)
D5 — errors PASS (self-certified)
D6 — tests green PASS (self-certified)

Verify commands (Adversary cold-verify)

# D6 — all tests green (19 lex + 25 parser = 44 total)
python -m unittest -q
# Expected: Ran 44 tests in 0.001s OK

# D1 — precedence: 1+2*3 must parse as 1+(2*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)))

# D2 — left associativity: 8-3-2 must parse as (8-3)-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 associativity: 8/4/2 must parse as (8/4)/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 has + under *
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
python -c "from calc.lexer import tokenize; from calc.parser import parse; print(parse(tokenize('-5')))"
# Expected: Unary('-', Num(5))

# D4 — unary in multiply: 3 * -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)))

# D4 — unary with paren: -(1+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)))

# D5 — error: 1 + (EOF after operator)
python -c "from calc.lexer import tokenize; from calc.parser import parse; parse(tokenize('1 +'))" 2>&1
# Expected: calc.parser.ParseError raised

# D5 — error: (1 (unclosed paren)
python -c "from calc.lexer import tokenize; from calc.parser import parse; parse(tokenize('(1'))" 2>&1
# Expected: calc.parser.ParseError raised

# D5 — error: 1 2 (two consecutive numbers)
python -c "from calc.lexer import tokenize; from calc.parser import parse; parse(tokenize('1 2'))" 2>&1
# Expected: calc.parser.ParseError raised

# D5 — error: )( (wrong-order parens)
python -c "from calc.lexer import tokenize; from calc.parser import parse; parse(tokenize(')('))" 2>&1
# Expected: calc.parser.ParseError raised

# D5 — error: empty string
python -c "from calc.lexer import tokenize; from calc.parser import parse; parse(tokenize(''))" 2>&1
# Expected: calc.parser.ParseError raised

AST shape (for Adversary to re-derive)

Nodes are Python dataclasses with custom __repr__:

  • Num(value) — leaf node, value is int or float
  • BinOp(op, left, right) — binary operator; op is the literal char '+', '-', '*', '/'
  • Unary(op, operand) — unary operator; op is '-'

WHAT is claimed

  • calc/parser.pyparse(tokens) -> Node using recursive descent
  • Grammar: expr → term ((+|-) term)*, term → unary ((*|/) unary)*, unary → - unary | primary, primary → NUMBER | ( expr )
  • ParseError defined in calc.parser (plain Exception subclass)
  • All 44 tests pass (python -m unittest -q)
  • Parser asserts on tree structure (not evaluation) in tests

Artifacts

  • calc/parser.py — ParseError, Num, BinOp, Unary, parse()
  • calc/test_parser.py — 25 unittest cases covering D1D5