Files
agent-orchestrator-benchmark/calculators/builder-solo/run-01/machine-docs/STATUS-parse.md

4.0 KiB

STATUS — phase parse

AST Node Shapes

Num(value: int|float)
BinOp(op: str, left: Node, right: Node)   -- op in {'+','-','*','/'}
Unary(op: str, operand: Node)             -- op == '-'

All nodes are dataclasses with __repr__ returning the form above.

Exact Shape Assertions (for re-verification)

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('(1+2)*3')))"
# Expected: BinOp('*', BinOp('+', Num(1), Num(2)), Num(3))

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

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

Gates

D1 — precedence

What: * and / bind tighter than + and -. 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)))

Also verified: 2*3+4BinOp('+', BinOp('*', Num(2), Num(3)), Num(4)) ✓ Also verified: 10-6/2BinOp('-', Num(10), BinOp('/', Num(6), Num(2)))

D2 — left associativity

What: Same-precedence operators associate left. Command: python -c "... print(parse(tokenize('8-3-2')))" Expected: BinOp('-', BinOp('-', Num(8), Num(3)), Num(2)) Observed: BinOp('-', BinOp('-', Num(8), Num(3)), Num(2))

Also verified: 8/4/2BinOp('/', BinOp('/', Num(8), Num(4)), Num(2)) ✓ Also verified: 1+2+3BinOp('+', BinOp('+', Num(1), Num(2)), Num(3))

D3 — parentheses

What: Parens override precedence. Command: python -c "... print(parse(tokenize('(1+2)*3')))" Expected: BinOp('*', BinOp('+', Num(1), Num(2)), Num(3)) Observed: BinOp('*', BinOp('+', Num(1), Num(2)), Num(3))

Also verified: ((2+3))BinOp('+', Num(2), Num(3)) ✓ Also verified: 1*(2+3)*4BinOp('*', BinOp('*', Num(1), BinOp('+', Num(2), Num(3))), Num(4))

D4 — unary minus

What: Leading and nested unary minus parses. Commands and observations:

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

D5 — errors

What: Malformed input raises ParseError (not any other exception). Command:

from calc.lexer import tokenize
from calc.parser import parse, ParseError
cases = ['1 +', '(1', '1 2', ')(', '']
for src in cases:
    try:
        parse(tokenize(src))
        print(f'  FAIL no error for {src!r}')
    except ParseError as e:
        print(f'  PASS ParseError for {src!r}: {e}')

Observed:

  PASS ParseError for '1 +': unexpected end of input
  PASS ParseError for '(1': expected 'RPAREN' but got 'EOF' (None)
  PASS ParseError for '1 2': unexpected token 'NUMBER' (2) after expression
  PASS ParseError for ')(': unexpected token 'RPAREN' (')')
  PASS ParseError for '': empty input

D6 — tests green

Command: python -m unittest -q Expected: 0 failures Observed:

----------------------------------------------------------------------
Ran 32 tests in 0.001s

OK

✓ (19 parser tests + 13 lexer tests)

DONE