summary_step1.10.md 3.7 KB

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).