summary_step7.md 3.1 KB

V3 step 7 — syslib port: analysis + enablers (partial, 2026-09-22)

Goal: remove gm2-only imports from the compiler sources (FileIO on SysIO/Storage). Attempting it exposed a fundamental bootstrap conflict; this step lands the enablers, the measuring gate, and the analysis that fixes the plan. Suite 102/102.

Delivered

  • Value open-array formals (PROCEDURE P(a : ARRAY OF T)). Previously 230; now supported (passed as a descriptor address, no copy — same representation as VAR). Needed because the compiler's own sources use value open arrays pervasively (WriteString(s : ARRAY OF CHAR), etc.). Assignable gained fixed-1D-array → open-formal compatibility. Tests: t_valopen → 15, t_openformal promoted to a run test.
  • syslib gate in run_tests.sh: fails if SymTab/QbeGen/ driver/parser/scanner import Environment, FileSysOp, TextIO, RawIO, WholeIO, IOChan, ProgramArgs. They do not. Only FileIO remains (excluded, pending).

The bootstrap conflict (why the port is not just mechanical)

FileIO is compiled twice, by two different compilers with two different ABIs:

  1. Stage 1 — gm2. gm2's ARRAY OF CHAR is a NUL-terminated C buffer; foreign procedures are declared DEFINITION MODULE FOR "C" … EXPORT UNQUALIFIED name; … (verified against the gm2 testsuite examples/callingC).
  2. Stage 2 — V3. ARRAY OF CHAR is our length-prefixed descriptor (LONGCARD count + bytes), and foreign procedures use PROCEDURE … ; EXTERNAL; (gm2 rejects that spelling).

So one FileIO source cannot pass strings to one shim: gm2 hands the shim a char* (NUL-terminated), V3 hands it a descriptor pointer. The runtime/syslib shim's string functions (m2write, m2puts, …) read the V3 descriptor layout, so they work for V3 programs but not for gm2-compiled FileIO.

Chosen resolution (for the next pass)

Make the foreign-call boundary NUL-terminated for both:

  • V3 codegen materialises a NUL-terminated copy when an ARRAY OF CHAR actual is passed to an EXTERNAL procedure (internal strings stay length-prefixed — only the boundary copy gets a NUL).
  • The shim's string functions switch to strlen-based (no count header), so gm2 and V3 both work.
  • A single runtime/syslib/SysShim.def (gm2 FOR "C" / UNQUALIFIED) binds the raw shim, and V3 gains support for DEFINITION MODULE FOR "C" + EXPORT UNQUALIFIED (its foreign dialect), so the same SysShim.def compiles under both.
  • Then FileIO is rewritten over SysShim (+ Storage), and the gate is extended to cover it.

Also identified

  • Corrected EXTERNAL FFI spelling for gm2 is DEFINITION MODULE FOR "C"; our PROCEDURE …; EXTERNAL; is V3-only. This is the concrete grammar addition V3 needs next.
  • Pointer-sized (l) handles, already the convention (step 5.4), apply to any host resource.

Files

compiler/src/M2.atg (value open arrays), compiler/src/SymTab.mod (assignability), compiler/run_tests.sh (gate), t_valopen, t_openformal. Build/FileIO unchanged (restored gm2-hosted).