artifacts: add calculators/ — the 30 built calculators (5/variant) + machine-docs + git logs
This commit is contained in:
@ -0,0 +1,93 @@
|
||||
# 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)
|
||||
|
||||
```bash
|
||||
# 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.py` — `parse(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 D1–D5
|
||||
Reference in New Issue
Block a user