# Procedure types + indirect calls (step 3) Tag `v3-proctypes`. Main suite 109/109 (new `t_proctype`). ## What works - **Procedure types**: `TYPE Op = PROCEDURE (a, b : INTEGER) : INTEGER;` and anonymous ones in declarations (`VAR Error : PROCEDURE (nr, line, col : INTEGER; pos : INT32);`). - **Type-only parameter form** (GNU shorthand used by the Coco/R scanner frame): `PROCEDURE (INT32) : CHAR`, `PROCEDURE (INTEGER, INTEGER, INTEGER, INT32)`. - **Procedure-typed variables** (module-level and local), stored as pointer-sized (`l`) code pointers, zero-initialised. - **Assigning a procedure to a procedure variable**: `f := Add;` emits the procedure's code address (`storel $Mod_Add_N, $Mod_f`). - **Indirect calls**: `f(40, 2)` emits `%r =w call %t(l 0, w 40, w 2)` (the leading `l 0` is the static link). - **Qualified proc-typed variables**: `M2S.Error(...)`, `Error := Err;`. ## Implementation - **SymTab**: new descriptor form `FProc` (result in `tref`) with parameters in flat arrays (`procp`/`procvis`, per-type `procstart`/`procn`); builder `NewProcType` + `ProcTypeAdd` + `SetProcTypeRes`; accessors `ProcTypeNPar/ParamType/ParamIsVar/Res`; `ProcTypeOf(name)` builds the type of a named procedure; `ClassOf` → `ClProc`; `SizeOf` 8; `Assignable` compares procedure types structurally (`ProcTypesOk`). Max 1024 param slots. - **QbeGen**: `ProcAddr` (a procedure's code address as a value); `ClProc` handled in `DeclVar`/`AllocLocal`/`ResClass`/ `LoadDesignator`/`ResClass`; `CallBeginInd` + `CallEnd` emit `call %(...)`. - **Grammar**: `ProcType` in `Type`; `ProcTypeSection` accepts named (`a, b : T`) and type-only (`T`) parameter lists; `Fact` yields a procedure's code address when a procedure name is used as a value (not followed by `(`); `ArgList`/`ActParam` gained a proc-type + callee path for indirect calls (used from both statement and expression calls). ## Limitations / follow-ups - **Nested procedure values** are not supported: only the code address is stored, so the static link passed to an indirect call is always `0` (fine for top-level procedures). The Coco/R driver's `Error := StoreError` (StoreError nested in `ListHandler`) will need this, or a source-level restructuring. - **Type-only parameters that are composite** (`PROCEDURE (ARRAY OF CHAR)`) are not parsed; only identifier type names are. ## M2S status after this step `M2S` compiled under V3 drops from 30 errors to **3**, none procedure-type related: 1. `M2S.mod:111` — `LENGTH(s)` (GNU builtin; V3 has `LEN`). 2. `M2S.mod:201` — empty `ELSE` in a CASE (`ELSE END`). 3. `M2S.mod:206` — `&` used for AND (in CR's *generated* scanner tables, not our `scanner.frm`). These are small language-compatibility items (aliases / empty branches), separate from procedure types. ## Files `compiler/src/{SymTab.def,SymTab.mod,QbeGen.def,QbeGen.mod,M2.atg}`, `compiler/tests/t_proctype.mod`, `compiler/run_tests.sh`.