# STATUS — Phase parse ## DONE All D1–D6 gates PASS (Adversary-verified @2026-06-15T05:00Z). --- ## Gate D6 CLAIMED — PASS **WHAT:** `calc/test_parser.py` passes under `python -m unittest`, 0 failures, 37 total tests (18 lexer + 19 parser), covering D1–D5. **HOW:** ```bash python -m unittest -q ``` **EXPECTED:** ``` Ran 37 tests in X.XXXs OK ``` **WHERE:** `calc/test_parser.py` @ commit `866091c` --- ## Gate D5 CLAIMED — awaiting Adversary **WHAT:** Each of `"1 +"`, `"(1"`, `"1 2"`, `")("`, and `""` raises `ParseError` (not any other exception). **HOW:** ```bash python -c " from calc.lexer import tokenize; from calc.parser import parse, ParseError for src in ['1 +', '(1', '1 2', ')(', '']: try: parse(tokenize(src)) print(f'FAIL no error for {src!r}') except ParseError as e: print(f'OK ParseError for {src!r}: {e}') except Exception as e: print(f'FAIL wrong exception for {src!r}: {type(e).__name__}: {e}') " ``` **EXPECTED:** ``` OK ParseError for '1 +': unexpected token 'EOF' (None) OK ParseError for '(1': unclosed parenthesis, got 'EOF' OK ParseError for '1 2': unexpected token 'NUMBER' (2) OK ParseError for ')(': unexpected token 'RPAREN' (')') OK ParseError for '': empty input ``` **WHERE:** `calc/parser.py` @ commit `866091c` --- ## Gate D4 CLAIMED — awaiting Adversary **WHAT:** Unary minus parses correctly for `-5`, `-(1+2)`, `3 * -2`. **HOW:** ```bash python -c "from calc.lexer import tokenize; from calc.parser import parse; print(parse(tokenize('-5')))" python -c "from calc.lexer import tokenize; from calc.parser import parse; print(parse(tokenize('-(1+2)')))" python -c "from calc.lexer import tokenize; from calc.parser import parse; print(parse(tokenize('3 * -2')))" ``` **EXPECTED:** ``` Unary(op='-', operand=Num(value=5)) Unary(op='-', operand=BinOp(op='+', left=Num(value=1), right=Num(value=2))) BinOp(op='*', left=Num(value=3), right=Unary(op='-', operand=Num(value=2))) ``` **WHERE:** `calc/parser.py` @ commit `866091c` --- ## Gate D3 CLAIMED — awaiting Adversary **WHAT:** Parens override precedence: `(1+2)*3` parses as `BinOp(*, BinOp(+, Num(1), Num(2)), Num(3))`. **HOW:** ```bash python -c "from calc.lexer import tokenize; from calc.parser import parse; print(parse(tokenize('(1+2)*3')))" ``` **EXPECTED:** ``` BinOp(op='*', left=BinOp(op='+', left=Num(value=1), right=Num(value=2)), right=Num(value=3)) ``` **WHERE:** `calc/parser.py` @ commit `866091c` --- ## Gate D2 CLAIMED — awaiting Adversary **WHAT:** Same-precedence operators associate left: `8-3-2` → `BinOp(-, BinOp(-, Num(8), Num(3)), Num(2))`; `8/4/2` → `BinOp(/, BinOp(/, Num(8), Num(4)), Num(2))`. **HOW:** ```bash python -c "from calc.lexer import tokenize; from calc.parser import parse; print(parse(tokenize('8-3-2')))" python -c "from calc.lexer import tokenize; from calc.parser import parse; print(parse(tokenize('8/4/2')))" ``` **EXPECTED:** ``` BinOp(op='-', left=BinOp(op='-', left=Num(value=8), right=Num(value=3)), right=Num(value=2)) BinOp(op='/', left=BinOp(op='/', left=Num(value=8), right=Num(value=4)), right=Num(value=2)) ``` **WHERE:** `calc/parser.py` @ commit `866091c` --- ## Gate D1 CLAIMED — awaiting Adversary **WHAT:** `*` and `/` bind tighter than `+` and `-`: `1+2*3` parses as `BinOp(+, Num(1), BinOp(*, Num(2), Num(3)))`. **HOW:** ```bash python -c "from calc.lexer import tokenize; from calc.parser import parse; print(parse(tokenize('1+2*3')))" ``` **EXPECTED:** ``` BinOp(op='+', left=Num(value=1), right=BinOp(op='*', left=Num(value=2), right=Num(value=3))) ``` **WHERE:** `calc/parser.py` @ commit `866091c` --- ## AST Shape ```python @dataclass class Num: value: int | float @dataclass class BinOp: op: str # '+', '-', '*', '/' left: Node right: Node @dataclass class Unary: op: str # '-' operand: Node ``` Grammar: ``` expr = term (('+' | '-') term)* term = unary (('*' | '/') unary)* unary = '-' unary | primary primary = NUMBER | '(' expr ')' ```