lex: clear pending modpath on module-reset, fix empty-module stale-modpath miscompile (#9)

BUG-A #9: when an empty/export-less inlined module body produces `//ww:module <p>` immediately followed by `//ww:module-reset` in one skipws run, lexnext drained TK_MODRESET first then emitted the STALE TK_MODPATH past the reset boundary, re-binding pathmod=<p> so the root `package main` was validated against <p> -> wrong reject. Fix clears the pending modpath at the reset-RECOGNITION site in skipws (NOT lexnext drain): cstage l->modpath=NULL after both l->modreset=1 (cmd/wcc/lex.c); selfhost l.modpathset=0 after all three l.modreset=1 (lib/ww/syntax/lex.ww). Symmetric (rule-10): identical token streams, bootstrap byte-id holds. The normal RESET-then-PATH boundary is unaffected (clear is a no-op when no path is pending). Pin: test/wcc/989_modresetadj_run.c feeds the raw composed adjacency to w6c+w6c_ww (accept + byte-id), red-path-proven (reverting a clear reddens it). A separate wwi-producer defect surfaced (decl-less .wwi defaults to 'package main') filed as #11; not touched here.
This commit is contained in:
2026-06-22 19:49:57 +09:00
parent 99b98b9b1b
commit c0383274d1
4 changed files with 226 additions and 3 deletions

View File

@@ -172,8 +172,8 @@ fn skipws(l: *lex) bool = {
if (rm) {
let af: i32 = lpeek(l,
(pre.len + rest.len): u64);
if (af == '\n') { l.modreset = 1; }
else { if (af < 0) { l.modreset = 1; }
if (af == '\n') { l.modreset = 1; l.modpathset = 0; } // #9: reset supersedes pending path (empty module body)
else { if (af < 0) { l.modreset = 1; l.modpathset = 0; } // #9: see above
else { if (af == ' ' || af == '\t') {
// `//ww:module-reset <path>` — sep
// primary body tagged by its full
@@ -199,6 +199,7 @@ fn skipws(l: *lex) bool = {
k += 1u64;
};
l.modreset = 1;
l.modpathset = 0; // #9: see above — clear pending path
if (k > s0) {
let view: str;
view.ptr =