artifacts: add calculators/ — the 30 built calculators (5/variant) + machine-docs + git logs
This commit is contained in:
@ -0,0 +1,114 @@
|
||||
# STATUS-parse — Builder
|
||||
|
||||
## DONE
|
||||
|
||||
All gates D1–D6 verified PASS by Adversary @2026-06-15T00:50Z. See REVIEW-parse.md.
|
||||
|
||||
---
|
||||
|
||||
## Gate: D1–D6 CLAIMED → PASS
|
||||
|
||||
All six gates are implemented and verified locally.
|
||||
|
||||
---
|
||||
|
||||
## Files
|
||||
|
||||
| File | Description |
|
||||
|---|---|
|
||||
| `calc/parser.py` | Recursive-descent parser exposing `parse(tokens) -> Node` |
|
||||
| `calc/test_parser.py` | unittest suite covering D1–D6 |
|
||||
|
||||
---
|
||||
|
||||
## AST Node Types (stable shape for evaluator)
|
||||
|
||||
```python
|
||||
@dataclass
|
||||
class Num:
|
||||
value: Any # int or float from lexer
|
||||
|
||||
@dataclass
|
||||
class BinOp:
|
||||
op: str # '+', '-', '*', '/'
|
||||
left: Any # Node
|
||||
right: Any # Node
|
||||
|
||||
@dataclass
|
||||
class Unary:
|
||||
op: str # '-'
|
||||
operand: Any # Node
|
||||
```
|
||||
|
||||
All three are dataclasses with `__repr__` — equality comparison works via `==`.
|
||||
|
||||
---
|
||||
|
||||
## Verification commands (cold-runnable from any clone)
|
||||
|
||||
```bash
|
||||
# D6 — all tests green
|
||||
python -m unittest -q
|
||||
|
||||
# D1 — precedence: 1+2*3 => 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('+', Num(1), BinOp('*', Num(2), Num(3)))
|
||||
|
||||
# D1 — precedence: 2*3+1 => BinOp('+', BinOp('*', Num(2), Num(3)), Num(1))
|
||||
python -c "from calc.lexer import tokenize; from calc.parser import parse; print(parse(tokenize('2*3+1')))"
|
||||
# expected: BinOp('+', BinOp('*', Num(2), Num(3)), Num(1))
|
||||
|
||||
# D2 — left assoc subtraction: 8-3-2 => BinOp('-', BinOp('-', Num(8), Num(3)), Num(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 assoc division: 8/4/2 => BinOp('/', BinOp('/', Num(8), Num(4)), 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))
|
||||
|
||||
# D3 — parens override: (1+2)*3 => BinOp('*', BinOp('+', Num(1), 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))
|
||||
|
||||
# D4 — unary minus: -5 => Unary('-', Num(5))
|
||||
python -c "from calc.lexer import tokenize; from calc.parser import parse; print(parse(tokenize('-5')))"
|
||||
# expected: Unary('-', Num(5))
|
||||
|
||||
# D4 — unary in paren: -(1+2) => Unary('-', BinOp('+', Num(1), Num(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)))
|
||||
|
||||
# D4 — unary in mul: 3 * -2 => BinOp('*', Num(3), Unary('-', 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)))
|
||||
|
||||
# D5 — each raises ParseError (must NOT raise any other exception)
|
||||
python -c "from calc.lexer import tokenize; from calc.parser import parse, ParseError
|
||||
for s in ['1 +', '(1', '1 2', ')(', '']:
|
||||
try: parse(tokenize(s)); print(f'FAIL no error for {s!r}')
|
||||
except ParseError as e: print(f'OK {s!r} => ParseError: {e}')
|
||||
except Exception as e: print(f'FAIL wrong exc for {s!r}: {type(e).__name__}: {e}')
|
||||
"
|
||||
# expected: 5 lines each starting "OK"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Expected outputs (exact)
|
||||
|
||||
| Gate | Expression | Expected repr |
|
||||
|---|---|---|
|
||||
| D1 | `1+2*3` | `BinOp('+', Num(1), BinOp('*', Num(2), Num(3)))` |
|
||||
| D1 | `2*3+1` | `BinOp('+', BinOp('*', Num(2), Num(3)), Num(1))` |
|
||||
| D2 | `8-3-2` | `BinOp('-', BinOp('-', Num(8), Num(3)), Num(2))` |
|
||||
| D2 | `8/4/2` | `BinOp('/', BinOp('/', Num(8), Num(4)), Num(2))` |
|
||||
| D3 | `(1+2)*3` | `BinOp('*', BinOp('+', Num(1), Num(2)), Num(3))` |
|
||||
| D4 | `-5` | `Unary('-', Num(5))` |
|
||||
| D4 | `-(1+2)` | `Unary('-', BinOp('+', Num(1), Num(2)))` |
|
||||
| D4 | `3 * -2` | `BinOp('*', Num(3), Unary('-', Num(2)))` |
|
||||
| D5 | `1 +` | `ParseError: unexpected token 'EOF' (None)` |
|
||||
| D5 | `(1` | `ParseError: expected RPAREN, got 'EOF' (None)` |
|
||||
| D5 | `1 2` | `ParseError: unexpected token 'NUMBER' (2) after expression` |
|
||||
| D5 | `)(` | `ParseError: unexpected token 'RPAREN' (')')` |
|
||||
| D5 | `` | `ParseError: empty expression` |
|
||||
| D6 | `python -m unittest -q` | `Ran 46 tests in …s OK` |
|
||||
Reference in New Issue
Block a user