artifacts: add calculators/ — the 30 built calculators (5/variant) + machine-docs + git logs
This commit is contained in:
@ -0,0 +1,211 @@
|
||||
# STATUS — phase parse
|
||||
|
||||
_Role: Builder owns this file._
|
||||
|
||||
## DONE
|
||||
|
||||
All gates PASSED by Adversary (2026-06-15T05:14:00Z). Advisory F1 corrected post-PASS.
|
||||
|
||||
| Gate | Status |
|
||||
|------|--------|
|
||||
| D1 | PASS (Adversary verified 2026-06-15T05:12:00Z) |
|
||||
| D2 | PASS (Adversary verified 2026-06-15T05:12:30Z) |
|
||||
| D3 | PASS (Adversary verified 2026-06-15T05:13:00Z) |
|
||||
| D4 | PASS (Adversary verified 2026-06-15T05:13:30Z) |
|
||||
| D5 | PASS (Adversary verified 2026-06-15T05:13:45Z) |
|
||||
| D6 | PASS (Adversary verified 2026-06-15T05:14:00Z) |
|
||||
|
||||
Post-DONE fix: Advisory F1 resolved — corrected test count from "50 (25+25)" to "48 (23+25)" in D6 gate entry.
|
||||
|
||||
---
|
||||
|
||||
## AST node shapes (stable interface)
|
||||
|
||||
`calc/parser.py` exports three node types and one exception:
|
||||
|
||||
```python
|
||||
@dataclass
|
||||
class Num:
|
||||
value: Union[int, float]
|
||||
# repr: Num(42) or Num(3.14)
|
||||
|
||||
@dataclass
|
||||
class BinOp:
|
||||
op: str # one of '+', '-', '*', '/'
|
||||
left: Node
|
||||
right: Node
|
||||
# repr: BinOp('+', Num(1), Num(2))
|
||||
|
||||
@dataclass
|
||||
class Unary:
|
||||
op: str # '-'
|
||||
operand: Node
|
||||
# repr: Unary('-', Num(5))
|
||||
|
||||
class ParseError(Exception): ...
|
||||
```
|
||||
|
||||
`parse(tokens) -> Node` consumes a token list from `calc.lexer.tokenize()`.
|
||||
|
||||
---
|
||||
|
||||
## Gate D1 — Precedence
|
||||
|
||||
**WHAT:** `*` and `/` bind tighter than `+` and `-`. `1+2*3` parses as `1+(2*3)`, not `(1+2)*3`.
|
||||
|
||||
**HOW to verify:**
|
||||
```bash
|
||||
python -c "
|
||||
from calc.lexer import tokenize; from calc.parser import parse
|
||||
r = repr(parse(tokenize('1+2*3')))
|
||||
assert r == \"BinOp('+', Num(1), BinOp('*', Num(2), Num(3)))\", r
|
||||
print('D1 OK:', r)
|
||||
"
|
||||
python -c "
|
||||
from calc.lexer import tokenize; from calc.parser import parse
|
||||
r = repr(parse(tokenize('2*3+1')))
|
||||
assert r == \"BinOp('+', BinOp('*', Num(2), Num(3)), Num(1))\", r
|
||||
print('D1b OK:', r)
|
||||
"
|
||||
```
|
||||
|
||||
**EXPECTED:**
|
||||
```
|
||||
D1 OK: BinOp('+', Num(1), BinOp('*', Num(2), Num(3)))
|
||||
D1b OK: BinOp('+', BinOp('*', Num(2), Num(3)), Num(1))
|
||||
```
|
||||
|
||||
**WHERE:** `calc/parser.py` (current HEAD)
|
||||
|
||||
---
|
||||
|
||||
## Gate D2 — Left Associativity
|
||||
|
||||
**WHAT:** Same-precedence operators associate left. `8-3-2` → `(8-3)-2`; `8/4/2` → `(8/4)/2`.
|
||||
|
||||
**HOW to verify:**
|
||||
```bash
|
||||
python -c "
|
||||
from calc.lexer import tokenize; from calc.parser import parse
|
||||
r = repr(parse(tokenize('8-3-2')))
|
||||
assert r == \"BinOp('-', BinOp('-', Num(8), Num(3)), Num(2))\", r
|
||||
print('D2 sub OK:', r)
|
||||
"
|
||||
python -c "
|
||||
from calc.lexer import tokenize; from calc.parser import parse
|
||||
r = repr(parse(tokenize('8/4/2')))
|
||||
assert r == \"BinOp('/', BinOp('/', Num(8), Num(4)), Num(2))\", r
|
||||
print('D2 div OK:', r)
|
||||
"
|
||||
```
|
||||
|
||||
**EXPECTED:**
|
||||
```
|
||||
D2 sub OK: BinOp('-', BinOp('-', Num(8), Num(3)), Num(2))
|
||||
D2 div OK: BinOp('/', BinOp('/', Num(8), Num(4)), Num(2))
|
||||
```
|
||||
|
||||
**WHERE:** `calc/parser.py` (current HEAD)
|
||||
|
||||
---
|
||||
|
||||
## Gate D3 — Parentheses
|
||||
|
||||
**WHAT:** Parens override precedence. `(1+2)*3` parses with `+` under `*`.
|
||||
|
||||
**HOW to verify:**
|
||||
```bash
|
||||
python -c "
|
||||
from calc.lexer import tokenize; from calc.parser import parse
|
||||
r = repr(parse(tokenize('(1+2)*3')))
|
||||
assert r == \"BinOp('*', BinOp('+', Num(1), Num(2)), Num(3))\", r
|
||||
print('D3 OK:', r)
|
||||
"
|
||||
python -c "
|
||||
from calc.lexer import tokenize; from calc.parser import parse
|
||||
r = repr(parse(tokenize('8/(2+2)')))
|
||||
assert r == \"BinOp('/', Num(8), BinOp('+', Num(2), Num(2)))\", r
|
||||
print('D3b OK:', r)
|
||||
"
|
||||
```
|
||||
|
||||
**EXPECTED:**
|
||||
```
|
||||
D3 OK: BinOp('*', BinOp('+', Num(1), Num(2)), Num(3))
|
||||
D3b OK: BinOp('/', Num(8), BinOp('+', Num(2), Num(2)))
|
||||
```
|
||||
|
||||
**WHERE:** `calc/parser.py` (current HEAD)
|
||||
|
||||
---
|
||||
|
||||
## Gate D4 — Unary Minus
|
||||
|
||||
**WHAT:** Leading and nested unary minus parses correctly.
|
||||
|
||||
**HOW to verify:**
|
||||
```bash
|
||||
python -c "
|
||||
from calc.lexer import tokenize; from calc.parser import parse
|
||||
r = repr(parse(tokenize('-5')))
|
||||
assert r == \"Unary('-', Num(5))\", r
|
||||
print('D4a OK:', r)
|
||||
r = repr(parse(tokenize('-(1+2)')))
|
||||
assert r == \"Unary('-', BinOp('+', Num(1), Num(2)))\", r
|
||||
print('D4b OK:', r)
|
||||
r = repr(parse(tokenize('3 * -2')))
|
||||
assert r == \"BinOp('*', Num(3), Unary('-', Num(2)))\", r
|
||||
print('D4c OK:', r)
|
||||
"
|
||||
```
|
||||
|
||||
**EXPECTED:**
|
||||
```
|
||||
D4a OK: Unary('-', Num(5))
|
||||
D4b OK: Unary('-', BinOp('+', Num(1), Num(2)))
|
||||
D4c OK: BinOp('*', Num(3), Unary('-', Num(2)))
|
||||
```
|
||||
|
||||
**WHERE:** `calc/parser.py` (current HEAD)
|
||||
|
||||
---
|
||||
|
||||
## Gate D5 — Errors
|
||||
|
||||
**WHAT:** Malformed inputs raise `ParseError`. Mandated cases: `"1 +"`, `"(1"`, `"1 2"`, `")("`, `""`.
|
||||
|
||||
**HOW to verify:**
|
||||
```bash
|
||||
python -c "
|
||||
from calc.lexer import tokenize
|
||||
from calc.parser import parse, ParseError
|
||||
bad_cases = ['1 +', '(1', '1 2', ')(', '']
|
||||
for src in bad_cases:
|
||||
try:
|
||||
parse(tokenize(src))
|
||||
print('FAIL: no exception for', repr(src))
|
||||
except ParseError as e:
|
||||
print('OK ParseError for', repr(src), ':', e)
|
||||
except Exception as e:
|
||||
print('FAIL: wrong exception', type(e).__name__, 'for', repr(src), ':', e)
|
||||
"
|
||||
```
|
||||
|
||||
**EXPECTED:** Five lines all starting with `OK ParseError for`.
|
||||
|
||||
**WHERE:** `calc/parser.py` (current HEAD)
|
||||
|
||||
---
|
||||
|
||||
## Gate D6 — Tests Green
|
||||
|
||||
**WHAT:** `calc/test_parser.py` (unittest) passes under `python -m unittest`, 0 failures, covering D1–D5.
|
||||
|
||||
**HOW to verify:**
|
||||
```bash
|
||||
python -m unittest -q
|
||||
```
|
||||
|
||||
**EXPECTED:** `Ran 48 tests in 0.00Xs OK` (23 lexer + 25 parser)
|
||||
|
||||
**WHERE:** `calc/test_parser.py` and `calc/parser.py` (current HEAD)
|
||||
Reference in New Issue
Block a user