summary_step5.6.md 2.2 KB

V3 step 5.6 — module-qualified symbols + real qualified access (done 2026-09-22)

Removes both separate-compilation limitations from step 5.4/5.5. Suite 97/97 (54 run — incl. 4 trap-aborts, 7 sessions, 3 session-output, 2 session-input, 1 unit — + 43 reject). LL(1)-clean, zero gm2 warnings.

1. Module-qualified globals

Module-level VAR/CONST data now emits as $<mod>_<name> (previously $<name>), so two modules with a global of the same name no longer collide at link time. QbeGen.SetModule (called by each unit's Begin*) supplies the module; DeclVar/DeclConst prefix it. Real-const startup flushes and the ExitCode load use the same qualified name.

2. Real per-module qualified access

L.x / L.P no longer flatten-clone under the plain name (which let one library's export shadow another's). New SymTab.MaterializeAlias(mod, name, alias) clones under a per-module key <mod>$<name> ($ can't appear in identifiers), and the symbol node keeps:

  • sym — the base symbol name (for QBE mangling/global names), and
  • mod — the defining module.

SymBase and GlobalRef read those back; QbeGen.Mangled now mangles via SymBase (drops any alias prefix) and SymRef builds $<mod>_<sym> for data access. All other lookups (type/kind/uid/params/result/external/depth) work unchanged because they only need Find(alias).

Tests

  • ClashProg → 60: two modules ClashA/ClashB each with a global count and a procedure Get; the program uses both qualified. Image shows $ClashA_count/$ClashB_count and Get_0/Get_1.
  • MixProg → prints 7: TextIO.WriteInt (console) and Files.WriteInt (file) in one program — the exact case that failed before this pass.
  • Full prior suite unchanged (95 → 97).

Remaining known edge

FROM A IMPORT x followed by FROM B IMPORT x is still first-wins (Materialize returns the existing node) — genuinely ambiguous by name; callers should use qualified access or distinct names. Qualified access is fully per-module.

Unblocks

Storage/SYSTEM (ADDRESS, generic pointers) and the step-7 syslib port: SYSTEM/Storage/Trap can now be ordinary modules whose internals bind externals without symbol collisions.