artifacts: add calculators/ — the 30 built calculators (5/variant) + machine-docs + git logs
This commit is contained in:
@ -0,0 +1,157 @@
|
||||
# STATUS — Phase parse (Builder)
|
||||
|
||||
## DONE
|
||||
|
||||
All gates D1–D6 Adversary-verified PASS @2026-06-15T06:32:30Z. Phase parse complete.
|
||||
|
||||
## Current State
|
||||
|
||||
Gates D1 through D6 implemented, claimed, and Adversary-verified. Phase complete.
|
||||
|
||||
---
|
||||
|
||||
## Gate D1 — precedence — CLAIMED, awaiting Adversary
|
||||
|
||||
**WHAT:** `*` and `/` bind tighter than `+` and `-`. `1+2*3` parses as `BinOp('+', Num(1), BinOp('*', Num(2), Num(3)))`, not `BinOp('+', BinOp('+',…))`.
|
||||
|
||||
**HOW:**
|
||||
```bash
|
||||
python -c "from calc.lexer import tokenize; from calc.parser import parse; print(parse(tokenize('1+2*3')))"
|
||||
python -c "from calc.lexer import tokenize; from calc.parser import parse; print(parse(tokenize('2*3+4')))"
|
||||
```
|
||||
|
||||
**EXPECTED:**
|
||||
```
|
||||
BinOp('+', Num(1), BinOp('*', Num(2), Num(3)))
|
||||
BinOp('+', BinOp('*', Num(2), Num(3)), Num(4))
|
||||
```
|
||||
|
||||
**WHERE:** `calc/parser.py` — commit 64d0252
|
||||
|
||||
---
|
||||
|
||||
## Gate D2 — left associativity — CLAIMED, awaiting Adversary
|
||||
|
||||
**WHAT:** Same-precedence operators associate left. `8-3-2` → `(8-3)-2`; `8/4/2` → `(8/4)/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('-', BinOp('-', Num(8), Num(3)), Num(2))
|
||||
BinOp('/', BinOp('/', Num(8), Num(4)), Num(2))
|
||||
```
|
||||
|
||||
**WHERE:** `calc/parser.py` — commit 64d0252
|
||||
|
||||
---
|
||||
|
||||
## Gate D3 — parentheses — CLAIMED, awaiting Adversary
|
||||
|
||||
**WHAT:** Parens override precedence. `(1+2)*3` parses with `+` under `*`.
|
||||
|
||||
**HOW:**
|
||||
```bash
|
||||
python -c "from calc.lexer import tokenize; from calc.parser import parse; print(parse(tokenize('(1+2)*3')))"
|
||||
python -c "from calc.lexer import tokenize; from calc.parser import parse; print(parse(tokenize('((2+3))')))"
|
||||
```
|
||||
|
||||
**EXPECTED:**
|
||||
```
|
||||
BinOp('*', BinOp('+', Num(1), Num(2)), Num(3))
|
||||
BinOp('+', Num(2), Num(3))
|
||||
```
|
||||
|
||||
**WHERE:** `calc/parser.py` `_primary()` method — commit 64d0252
|
||||
|
||||
---
|
||||
|
||||
## Gate D4 — unary minus — CLAIMED, awaiting Adversary
|
||||
|
||||
**WHAT:** Leading and nested unary minus parses correctly: `-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')))"
|
||||
python -c "from calc.lexer import tokenize; from calc.parser import parse; print(parse(tokenize('--5')))"
|
||||
```
|
||||
|
||||
**EXPECTED:**
|
||||
```
|
||||
Unary('-', Num(5))
|
||||
Unary('-', BinOp('+', Num(1), Num(2)))
|
||||
BinOp('*', Num(3), Unary('-', Num(2)))
|
||||
Unary('-', Unary('-', Num(5)))
|
||||
```
|
||||
|
||||
**WHERE:** `calc/parser.py` `_unary()` method — commit 64d0252
|
||||
|
||||
---
|
||||
|
||||
## Gate D5 — errors — CLAIMED, awaiting Adversary
|
||||
|
||||
**WHAT:** Malformed input raises `ParseError` (not any other exception) for all five plan cases.
|
||||
|
||||
**HOW:**
|
||||
```bash
|
||||
python -c "
|
||||
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: {src!r} did not raise')
|
||||
except ParseError as e:
|
||||
print(f'OK ParseError: {src!r} -> {e}')
|
||||
except Exception as e:
|
||||
print(f'FAIL wrong exc: {src!r} -> {type(e).__name__}: {e}')
|
||||
"
|
||||
```
|
||||
|
||||
**EXPECTED:**
|
||||
```
|
||||
OK ParseError: '1 +' -> unexpected end of expression
|
||||
OK ParseError: '(1' -> expected ')' but got 'EOF' ('')
|
||||
OK ParseError: '1 2' -> unexpected token 'NUMBER' (2)
|
||||
OK ParseError: ')(' -> unexpected token 'RPAREN' (')')
|
||||
OK ParseError: '' -> empty expression
|
||||
```
|
||||
|
||||
**WHERE:** `calc/parser.py` `parse()`, `_primary()`, `_expr()` — commit 64d0252
|
||||
|
||||
---
|
||||
|
||||
## Gate D6 — tests green — CLAIMED, awaiting Adversary
|
||||
|
||||
**WHAT:** `calc/test_parser.py` (unittest) passes with 0 failures, covering D1–D5. Total 35 tests pass (15 lexer + 20 parser).
|
||||
|
||||
**HOW:**
|
||||
```bash
|
||||
python -m unittest -q
|
||||
```
|
||||
|
||||
**EXPECTED:**
|
||||
```
|
||||
Ran 35 tests in 0.00Xs
|
||||
|
||||
OK
|
||||
```
|
||||
|
||||
Test coverage in `calc/test_parser.py`:
|
||||
- `TestPrecedence` (4 tests): D1 — `1+2*3`, `2*3+4`, `6-2*3`, `1+6/2`
|
||||
- `TestAssociativity` (4 tests): D2 — `8-3-2`, `8/4/2`, `1+2+3`, `2*3*4`
|
||||
- `TestParentheses` (3 tests): D3 — `(1+2)*3`, `((2+3))`, `3*(2+1)`
|
||||
- `TestUnaryMinus` (4 tests): D4 — `-5`, `-(1+2)`, `3 * -2`, `--5`
|
||||
- `TestErrors` (5 tests): D5 — `1 +`, `(1`, `1 2`, `)(`, `""`
|
||||
|
||||
All tests assert on tree structure via `assertEqual` on dataclass instances (not on evaluation).
|
||||
|
||||
**WHERE:** `calc/test_parser.py`, `calc/parser.py` — commit 64d0252
|
||||
Reference in New Issue
Block a user