# V3 step 1.10 — Clarion classes: decl + inheritance + impl blocks (done 2026-09-19) Pre-step-3 grammar work from `docs/OOP.txt` (757-line Clarion CLASS spec + Table AVL example). Suite 33/33 (14 run + 19 reject). Grammar stays effectively LL(1)-clean (one benign Coco warning, see below). ## Locked decisions (interactive §5) - Classic identifiers stay: no underscores, so Table's `_Find` etc. remain lexically out of reach (noted, not solved). - Method separator `;` — the Table example overrules the sketch's `,`. - Construct now, lowering later (units/procs/nesting pattern). Full `Table.mod` needs steps 3+4+stdlib (pointers, calls, SIZE…). - `CLASS IMPLEMENTATION` + single `(Parent)` inheritance included now (parsed, scoped, 230); multiple parents → 230. ## Grammar (`compiler/src/M2.atg`) - One `ClassItem = "CLASS" ("IMPLEMENTATION" … | …)` in both the `TYPE` loop and `DeclSeq`: splitting decl/impl across the two loops needs 2-token lookahead (`CLASS ident` vs `CLASS IMPLEMENTATION`), which LL(1) cannot do. - `ClassRest`: name + optional parents + `;`, `{field ";"}`, `{method ";" + CloseProc}`, `END`-match, one 230. Fields reuse the record machinery (`FieldPending/FixPendingF`); `x = Name` constant form included. - `Parents`: first parent resolved (201 unknown, 230 non-class, stored via `SetParent`); extras consumed + 230 (single inheritance locked). - `MethodHeading = [VIRTUAL] ProcHeading` (+ `MarkVirtual`); bodies reuse `Block` (nested procedures inside methods work, as in Table's `Search`/`_Find`); impl-side existence check (`MethodExists`, else 201); `FORWARD` allowed in both. - `ClassImplRest`: class resolution (201/230), `PushClassMembers`, methods, optional `BEGIN` body, `END`-match, one 230. - Field *use* (`KindField` in Design) is now explicit 230 instead of silent `0` — no silent acceptance anywhere anymore. ## SymTab (additive) `FClass`/`ClClass` (=11); `NewClass`, `SetParent`, `PushClassScope` (records the body scope on the descriptor), `MethodExists`, `PushClassMembers` (fields only — see bug 1), `MarkVirtual` (`virt` node flag); `FieldPending`/`PushRecord` accept `FClass`; methods stay `KindProc` (class membership rides `node^.scope`). ## Bugs caught 1. **Member-copy collision**: first cut re-entered sibling methods into impl member scopes, so every method body heading hit `200 duplicate` (+ `232` cascade via cleared `curProc`). Fix: members push fields only; sibling calls honestly 201 until step 4. 2. **Coco's lingering TypeBlock warning** (`CLASS` start+successor): verified benign — the generated `WHILE`/`IF` decision is correct by inspection and by behavior on every input shape. Coco is strict about `FIRST ∩ FOLLOW` on that loop; the code it emits does the right thing. Documented, not "fixed". 3. **A phantom `t_class` failure** (`ident expected` at the impl line) appeared during development across many consistent runs, then vanished and never reproduced (deterministic 3/3 + full suite since, including from a clean rebuild). Token-stream dumps of failing vs working inputs were byte-identical through the failure point. No mechanism found; no code changed to "fix" it. If it ever recurs: clean-rebuild first, then suspect toolchain (CR codegen) rather than the grammar — the decision code reads correctly. Recorded here so nobody re-bisects it blind. ## Tests `t_classdef` (fields, `VIRTUAL`, empty/full formals, result → 2× 230: class + unit), `t_class` (inheritance + impl + body with `RETURN 0` → 4× 230, zero cascades), `t_bad_parent` (unknown parent → 201 + 230). Total 33 (14 run + 19 reject). Deferred: vtable/dispatch/`THIS`, multi-inheritance, opaque classes, `SHORTINT [-1..1]` postfix bounds, full Table (steps 3+4).