112/112 tests green (99 regressions + 5 run + 8 rejection), mc64 boot + example green.
Harden the step-6 WIP (single-file local MODULEs, no nesting, no bodies):
exported VARs, CONSTs and parameterless proper procedures, used as
M.x / M.P(). Fix the bugs found by probing, lock behavior in with
rejection tests, keep every old suite green.
SymTab: ExpQual now qualifies KindConst as well as KindVar
("M.x"); ExitModule became a BOOLEAN function — TRUE iff every
EXPORT name was declared (ghost exports report FALSE).M2c.atg: ModuleDecl gained an enterOk flag (failed EnterModule
skips export recording and ExitModule, killing the duplicate-module
cascade); END reports SemError(201) on ghost exports; header comment
documents local-module support and limits.run_tests.sh: new Step-6 sections (5 run + 8 rejection).5 run: m_mod 12 (exported var + Inc() twice), m_multi 7 (two
modules), m_arr 42 (exported array + M.arr[2]), m_outer 11 (module
proc touches outer global), m_const 7 (exported CONST).
8 rejections, each exactly one error: m_bad_priv 201 (private M.secret),
m_bad_nest 230 (module in procedure), m_bad_dup 200 (duplicate module),
m_bad_exp 200 (duplicate export), m_bad_ghost 201 (EXPORT ghost),
m_bad_param 233 (M.Add(5)), m_bad_func 233 (M.Get() in expression),
m_bad_end 202 (END N mismatch).
CONST read back 0: ExpQual returned an empty name for
non-Var kinds, so GlobalAddr("") hit a temp slot. Qualifying
KindConst fixes the load (M.C → 7) with no ATG change (address +
LoadIndir path is shared with vars).EXPORT silently accepted: ExitModule dropped undeclared names.
Now returns FALSE and the ATG reports 201 at END.EXPORT, since
ModuleAddExp ran with no module context). enterOk guard → 1 error.Module procedures take no parameters (M.Add(5) → 233), module functions
are statement-only (M.Get() in an expression → 233), no type exports
(M.T → 221 + 230 via QualIdent), no DEFINITION/IMPLEMENTATION
split, no module BEGIN bodies, NoteSfx/NoteIdx VAR-tail helpers still
unwired (a[i]/p^/fields as VAR actuals → 233), max 8 modules /
32 exports per module / 128 exports total.
No new machinery needed for simple output — step-5 builtins cover it:
WriteString("...") / WriteString(charArrayVar) emits raw bytes via
SYSTEM service 1 (no newline); WriteInt(n) emits unsigned decimal + CRLF
via the embedded EmitPrint helper; a declared ExitCode global is printed
the same way at program end. Demo verified under mcint:
WriteString("Hello"); WriteString(" world"); WriteInt(42);
→ Hello world42\r\n. Limits: no WriteLn, single-CHAR literals rejected
(210 — "A" lexes as CHAR, not a string), WriteInt wraps negatives, one
value per call. A WriteLn/WriteChar would be a small isolated addition
(new ATG builtin + MGen emitter + tests).