4.0 KiB
STATUS — phase: parse (Builder)
DONE
Gate: D1–D6 — ALL PASS (Adversary-verified @2026-06-15T01:42:00Z)
WHAT is claimed
All six gates D1–D6 are implemented and tested.
- D1 (precedence):
*//bind tighter than+/- - D2 (left associativity): Same-precedence ops associate left
- D3 (parentheses): Parens override precedence
- D4 (unary minus): Leading and nested unary minus
- D5 (errors): Five malformed inputs each raise
ParseError - D6 (tests green): 19 parser tests + 22 lexer tests = 41 total, 0 failures
HOW to verify (run from a fresh clone)
D6 — all tests green:
python -m unittest -q
Expected output: Ran 41 tests in 0.00xs / OK
D1 — precedence (structural check):
python -c "from calc.lexer import tokenize; from calc.parser import parse; print(parse(tokenize('1+2*3')))"
Expected: BinOp(PLUS, Num(1), BinOp(STAR, Num(2), Num(3)))
python -c "from calc.lexer import tokenize; from calc.parser import parse; print(parse(tokenize('6-4/2')))"
Expected: BinOp(MINUS, Num(6), BinOp(SLASH, Num(4), Num(2)))
D2 — left associativity:
python -c "from calc.lexer import tokenize; from calc.parser import parse; print(parse(tokenize('8-3-2')))"
Expected: BinOp(MINUS, BinOp(MINUS, 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(SLASH, BinOp(SLASH, Num(8), Num(4)), Num(2))
D3 — parentheses:
python -c "from calc.lexer import tokenize; from calc.parser import parse; print(parse(tokenize('(1+2)*3')))"
Expected: BinOp(STAR, BinOp(PLUS, Num(1), Num(2)), Num(3))
D4 — unary minus:
python -c "from calc.lexer import tokenize; from calc.parser import parse; print(parse(tokenize('-5')))"
Expected: Unary(MINUS, Num(5))
python -c "from calc.lexer import tokenize; from calc.parser import parse; print(parse(tokenize('-(1+2)')))"
Expected: Unary(MINUS, BinOp(PLUS, Num(1), Num(2)))
python -c "from calc.lexer import tokenize; from calc.parser import parse; print(parse(tokenize('3 * -2')))"
Expected: BinOp(STAR, Num(3), Unary(MINUS, Num(2)))
D5 — errors (each must raise ParseError, not a different exception):
python -c "from calc.lexer import tokenize; from calc.parser import parse; parse(tokenize('1 +'))"
# raises: ParseError: unexpected token 'EOF'
python -c "from calc.lexer import tokenize; from calc.parser import parse; parse(tokenize('(1'))"
# raises: ParseError: expected ')', got 'EOF'
python -c "from calc.lexer import tokenize; from calc.parser import parse; parse(tokenize('1 2'))"
# raises: ParseError: unexpected token 'NUMBER' after expression
python -c "from calc.lexer import tokenize; from calc.parser import parse; parse(tokenize(')('))"
# raises: ParseError: unexpected token 'RPAREN'
python -c "from calc.lexer import tokenize; from calc.parser import parse; parse(tokenize(''))"
# raises: ParseError: empty input
EXPECTED AST shapes (re-derivable from grammar)
AST node types:
Num(value)— numeric literal; value is int or floatBinOp(op, left, right)— op in{'PLUS','MINUS','STAR','SLASH'}Unary(op, operand)— op =='MINUS'
Grammar used (drives precedence + associativity):
expr : term (('+' | '-') term)* ← left-assoc, low precedence
term : unary (('*' | '/') unary)* ← left-assoc, high precedence
unary : '-' unary | primary ← right-assoc chain, prefix only
primary : NUMBER | '(' expr ')'
WHERE (commit sha)
23d0ae9 (claim(D1,D2,D3,D4,D5,D6): parser complete, all 41 tests green)
Files
calc/parser.py— ParseError, Num, BinOp, Unary, _Parser, parse()calc/test_parser.py— 19 unittest cases covering D1–D5
Gate checklist
- D1 (precedence): CLAIMED
- D2 (left associativity): CLAIMED
- D3 (parentheses): CLAIMED
- D4 (unary minus): CLAIMED
- D5 (errors): CLAIMED
- D6 (tests green): CLAIMED