# V3 step 3.1 — arrays: bounded/open, strings, whole assign (done 2026-09-20) First of four phased composite substeps (arrays → records → sets → pointers). Suite 42/42 (16 run — incl. 2 trap-aborts — + 26 reject), LL(1)-clean (only the known-benign TypeBlock warning). ## Type syntax (`M2.atg`) - `Type` gains `allowOpen` and `ArrayType`: `"ARRAY" "OF" Type` (open formal; 230 elsewhere incl. named open aliases) and `"ARRAY" "[" bounds "]" "OF" Type` (multi-index sugar nests inside-out via `NestArray`). Bounds are folded int/char literals (`ConstInt`, inverted → 230); bare-type indices wait for enum ordinals; `VarDecl` takes full `Type` (anonymous arrays in `VAR`); formals take `Type`; composite function results are 230 (V2 parity). - Coco/R V1.53 cannot parse dotted types (`SymTab.BoundsArr`) in *attribute* declarations (generates garbage), so bounds accumulate SymTab-side (`BoundBegin/BoundAdd/NestArray`, max 8). - `Design` grows index suffixes (`[i, j]` descends nested levels; 217/218) plus an `sfx` out-flag; `Fact` loads indexed elements (`ElemLoad`) and lowers string literals to descriptors (1-char stays CHAR, `''` works); `Assign` copies whole arrays (`CopyArray`) or stores elements (`ElemStore`, with `ConvIR` for `r[i] := 3`); array/string `=` is 213 (strict Wirth; done in `EqCheck`, so CASE labels agree). ## Layout (locked rule, now real) `DeclArr` emits `data $a = { l n, … }` with CHAR→b, int/bool/enum→w, REAL→d, nested/pointer→l, all zero; nested levels are separate `$a_i` objects linked by address (probes proved `l $sym` in data, `copy $sym` addressing, `loadub`, `blit`-class ops). Indexes widen to LONGCARD (`extsw`), check `lo..hi` (static, or `0..count-1` for open via `OpenHi`), trap via `call $abort()` + `hlt` (rc=134; interim until `runtime/syslib/Trap`). ## Backend lessons (all probed, not guessed) - QBE `blit` needs a *constant* length → whole copies use `call $memcpy(l dst, l src, l n)` (runtime length, uniform for fixed/open/nested; nested recurses through a runtime loop). - QBE `call` needs per-argument classes (`call $f(l a, …)`); bare `$abort()` is fine. - Single-letter `%p` temporaries mislink — always `%tN` (already the convention; now recorded). - String `data` must be top-level: literals buffer during the body and flush at `EndModule` (a `data` line mid-function is a QBE syntax error — found the hard way). ## SymTab (additive) Bounded/open descriptors (`NewArrayB/OpenArray`, `alo/ahi`), `IsOpenArray/ArrayLo/Hi/Len/Depth`, `ConstInt` reuse; `Assignable` tightened (array↔array by `SameType`, string→1-D-CHAR-array only); `EqCheck` rejects array/string `=`. ## Tests `t_array` → 108 (named + anonymous arrays, nested `m[i,j]`, whole + nested copies, strings, char compare); `t_bad_index` (218), `t_bad_bounds` (inverted → 230), `t_openformal`/`t_bad_open` (open rules); new `expect_trap` harness (rc=134): index breach and `"abcd"`-into-3 count mismatch. Deferred: `HIGH`/`LEN` (need calls, step 4), string `=`/`+`, string CONSTs, enum/char-subrange bounds as index *types*, `CHAR`-bound subtleties, open-formal *reads* (parse-only now).