artifacts: add calculators/ — the 30 built calculators (5/variant) + machine-docs + git logs
This commit is contained in:
@ -0,0 +1,158 @@
|
||||
# STATUS — phase parse
|
||||
|
||||
## DONE
|
||||
|
||||
All gates D1–D6 Adversary-verified PASS @2026-06-15T04:22:33Z. No vetoes. Phase complete.
|
||||
|
||||
---
|
||||
|
||||
## Gates: D1–D6 CLAIMED, awaiting Adversary
|
||||
|
||||
All six gates implemented and locally verified. Claiming all simultaneously.
|
||||
|
||||
---
|
||||
|
||||
## AST node shapes (stable contract for evaluator)
|
||||
|
||||
- `Num(value)` — leaf; `value` is `int` or `float`
|
||||
- `BinOp(op, left, right)` — binary op; `op` is `'PLUS'|'MINUS'|'STAR'|'SLASH'`
|
||||
- `Unary(op, operand)` — unary minus; `op` is `'MINUS'`
|
||||
|
||||
All nodes are frozen `@dataclass`s with `__repr__` and `__eq__` derived from fields.
|
||||
Defined in `calc/parser.py`.
|
||||
|
||||
---
|
||||
|
||||
## D1 — precedence (CLAIMED)
|
||||
|
||||
**WHAT:** `*`/`/` bind tighter than `+`/`-`: `1+2*3` parses as `BinOp('PLUS', Num(1), BinOp('STAR', 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('PLUS', Num(1), BinOp('STAR', Num(2), Num(3)))
|
||||
```
|
||||
|
||||
**WHERE:** `calc/parser.py` — `expr()` loops over `+/-`, `term()` loops over `*//`.
|
||||
|
||||
---
|
||||
|
||||
## D2 — left associativity (CLAIMED)
|
||||
|
||||
**WHAT:** Same-precedence operators associate left.
|
||||
- `8-3-2` → `BinOp('MINUS', BinOp('MINUS', Num(8), Num(3)), Num(2))`
|
||||
- `8/4/2` → `BinOp('SLASH', BinOp('SLASH', 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('MINUS', BinOp('MINUS', Num(8), Num(3)), Num(2))
|
||||
BinOp('SLASH', BinOp('SLASH', Num(8), Num(4)), Num(2))
|
||||
```
|
||||
|
||||
**WHERE:** `calc/parser.py` — `while` loops in `expr()` and `term()` fold left.
|
||||
|
||||
---
|
||||
|
||||
## D3 — parentheses (CLAIMED)
|
||||
|
||||
**WHAT:** Parens override precedence: `(1+2)*3` → `BinOp('STAR', BinOp('PLUS', 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('STAR', BinOp('PLUS', Num(1), Num(2)), Num(3))
|
||||
```
|
||||
|
||||
**WHERE:** `calc/parser.py` — `primary()` handles `LPAREN … RPAREN`.
|
||||
|
||||
---
|
||||
|
||||
## D4 — unary minus (CLAIMED)
|
||||
|
||||
**WHAT:** Leading and nested unary minus works.
|
||||
- `-5` → `Unary('MINUS', Num(5))`
|
||||
- `-(1+2)` → `Unary('MINUS', BinOp('PLUS', Num(1), Num(2)))`
|
||||
- `3 * -2` → `BinOp('STAR', Num(3), Unary('MINUS', Num(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('MINUS', Num(5))
|
||||
Unary('MINUS', BinOp('PLUS', Num(1), Num(2)))
|
||||
BinOp('STAR', Num(3), Unary('MINUS', Num(2)))
|
||||
```
|
||||
|
||||
**WHERE:** `calc/parser.py` — `unary()` intercepts `MINUS` before `primary()`.
|
||||
|
||||
---
|
||||
|
||||
## D5 — errors (CLAIMED)
|
||||
|
||||
**WHAT:** Each malformed input raises `ParseError` (not any other exception).
|
||||
|
||||
**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('FAIL — no error for', repr(src))
|
||||
except ParseError as e:
|
||||
print('OK', repr(src), '->', e)
|
||||
"
|
||||
```
|
||||
|
||||
**EXPECTED (all OK lines):**
|
||||
```
|
||||
OK '1 +' -> unexpected token 'EOF'
|
||||
OK '(1' -> expected ')', got 'EOF'
|
||||
OK '1 2' -> unexpected token 'NUMBER' after expression
|
||||
OK ')(' -> unexpected token 'RPAREN'
|
||||
OK '' -> unexpected token 'EOF'
|
||||
```
|
||||
|
||||
**WHERE:** `calc/parser.py` — `primary()` raises on bad token; trailing-token check after `expr()`.
|
||||
|
||||
---
|
||||
|
||||
## D6 — tests green (CLAIMED)
|
||||
|
||||
**WHAT:** `python -m unittest -q` runs 39 tests (17 lex + 22 parser), 0 failures.
|
||||
|
||||
**HOW:**
|
||||
```bash
|
||||
python -m unittest -q
|
||||
```
|
||||
|
||||
**EXPECTED:**
|
||||
```
|
||||
----------------------------------------------------------------------
|
||||
Ran 39 tests in ...s
|
||||
|
||||
OK
|
||||
```
|
||||
|
||||
**WHERE:** `calc/test_parser.py` — 22 tests across 5 classes (TestPrecedence, TestLeftAssociativity, TestParentheses, TestUnaryMinus, TestErrors).
|
||||
Reference in New Issue
Block a user