# Step 5 — Open arrays, copy, strings, I/O, NIL trap (uncommitted) 99/99 tests green (74 regressions + 15 run + 10 rejection), mc64 suite green. ## Goal Phase 4, first half: 1D open arrays (`ARRAY OF T`, `HIGH`, VAR + value, fixed actuals only), whole array/record copy (`copy_block`), fixed `CHAR`-array `=`/`#`/`<`/`<=`/`>`/`>=` (`string_comp`), `WriteInt` / `WriteString` (SYSTEM 1 + print helper), NIL-trap (VM Fatal, no static check). Deferred to step 6: single-file modules, VAR tails (`233`), value composites (`230`), open-to-open (`233`). ## What was built - `SymTab`: `NewOpen`/`IsOpen` (`tOpen` flag), open params take 2 slots (`EnterParam`: addr+len, `parCnt+=2`, `Leave` drops slots, arity still counts formals). - `MGen`: open actuals (`ActValue`: addr + `ArrayLen` const → 2 temps; `ActEnd`: reload len then addr so addr lands at base), `PushAddr` treats open value params as indirect, `PrintNum`/`CallPrint` (print helper), `SysCall` (`0C3`), `Swap`/`LoadByte`/`StoreByte` already from step 4. - `M2c.atg`: `ArrayType` allows `ARRAY OF` (no index → `NewOpen`; LL(1) via `OF` lookahead), record fields reject open (`230`), `HIGH(...)` builtin (fixed `ArrayHi`, open `len-1` via `LoadLocal` or display `FrameAddr+LoadIndir`; non-array `217`), whole copy (`pushedDst` for all whole Array/Record vars + `pushedFld` fields: string `Str→Array` with length check `210`, else `Assignable`? copy : `210`; no more `230` for same-type copy), fixed `CHAR`-array compare (`StrComp` + `Or`/`Not`/`Swap`/`Drop`, no `RealEq` cmp), `WriteInt` (`IsIntFamily`? `CallPrint` : `210`), `WriteString` (`Str` or `Array-of-CHAR`? `PushInt(1)` + `SysCall` : `210`). - `mc64/Interpreter`: `string_comp` gt/lt swap fix + src-NUL length fix (`dst` non-NUL → `gt`); NIL trap on `41H/51H/60H-6FH/70H-7FH` (`p=0` → Fatal, exit 1). `mkdtest` field_mask 252 unchanged (exclusive VM kept; M2c ranges inclusive via hi+1 from step 4). ## Tests — 99/99 (74 + 15 + 10) 15 run: `o_open` 150 (VAR open+HIGH), `c_copy` 18 (whole array), `s_streq` 21 (`=/#/<`), `o_val` 14 (value open), `o_high` 14 (`HIGH` fixed 5+9), `c_rec` 17 (whole record), `w_io` hi42 (`WriteString`+`WriteInt`), `o_open2` 286 (two lengths, runtime HIGH), `c_copy2` 9 (CHAR copy), `s_cmp2` 10 (`>/>=/<=`), `r_copy2` 15 (nested record copy), `a_subopen` 66 (2D subarray actual), `w_str2` ok8 (WriteString var), `p_newarr` 66 (NEW array + `p^[i]`), `o_char` 4 (open CHAR+HIGH). 10 rejections, each exactly one error: `o_bad_open` 233 (open-to-open), `o_bad_high` 217, `c_bad_len` 210, `s_bad_cmp` 213, `v_bad_var` 233 (VAR `a[i]`), `w_bad_int` 210, `w_bad_str` 210, `r_bad_open` 230, `p_bad_dispose` 219, `s_bad_op` 211. ## Bugs found and fixed 1. `string_comp` gt/lt swapped (`src>dst` gave `gt`, should be `lt`) + src-NUL ignored longer `dst` (gave equal, should be `gt`). 2. String `=`/`#` used `RealEq`/`RealNe` (extra `OPrCmp` on gt/lt — reinterprets bits as REAL) — use `Or`/`Not`/`Swap`/`Drop` only. 3. Whole `a:=x` (array:=int) gave `230` hiding `210` — check `Assignable` before `230` (same for records/fields). 4. `t_bad_array` (`a:=b` same-type) became valid after whole-copy lift — repurposed to open-var `230`, added `c_copy` run (18). 5. Empty `""` lexed as CHAR (len 2 ≤ 3 → `CharOrd('"')`=34) — CHAR iff len = 3; len 2/≥4 is Str (empty via `EmitString` NUL only). 6. Single-slot `[1..1]` CHAR arrays took scalar `StoreFinish` (stored pointer, no length check) — `pushedDst` for any Array-CHAR (not just slots>1); `s_bad_long` (`"abcdefghij"` → 11 > 8) now 210. 7. `Design` unreachable after WITH lift (Coco error, step 4 loop) — removed dead `Design` (step-4 build already fixed; kept). ## Known limits (deferred with rejection tests) Open-to-open actuals `233`, VAR designators with tails (`a[i]`/`p^`/ fields as VAR) `233`, value composite params/returns `230` (`a_bad_val` kept), open string compare `213`→`230`? (currently `213` via Array/Record guard; open CHAR `=` gives `213` — acceptable, no test), `HIGH` on open needs same/descendant frame (display walk implemented, untested beyond one level), `WriteInt` prints unsigned (like `ExitCode`; negatives wrap), modules single-file untouched (step 6).