wcc+ww: //ww:module-reset boundary directive; package-less files keep module "" (#16 PREP-main)
Driver twins emit the line-comment directive only before package-less files (peekpackage==nil); both lexers tokenize it (TK_MODRESET, appended =87 so existing token values hold) and both parsers reset curmod — a package-less file's decls get module "" instead of inheriting the last bundled package (the sticky-curmod leak, task #11). Withdrawn alternative: injecting 'package main' flips non-entry symbols bare->main-prefixed (FFI-visible, broke 764). Codegen-neutral by proof: bare symbols preserved, both stages emit byte-identical asm for a directive-bearing combined. Transitional until strict-package rejects package-less files outright. Includes 737 bad-deep pin for the PREP-peek >2048 edge + 904/toktest rows for the new token.
This commit is contained in:
@@ -6441,7 +6441,10 @@ type tkind = enum i32 {
|
||||
TK_YIELD = 84,
|
||||
TK_ENUM = 85,
|
||||
TK_MODULE = 86, // `module foo;` — directory-as-module decl
|
||||
TK_LAST = 87,
|
||||
TK_MODRESET = 87, // `//ww:module-reset` driver bundle boundary:
|
||||
// reset curmod to "" before a package-less file
|
||||
// (#16 option-B; cstage TK_MODRESET twin)
|
||||
TK_LAST = 88,
|
||||
};
|
||||
|
||||
// ---- Pos / Tok --------------------------------------------------------
|
||||
@@ -6563,6 +6566,7 @@ export fn tokname(k: tkind) str = {
|
||||
case tkind.TK_UNDER: return "_";
|
||||
case tkind.TK_ENUM: return "enum";
|
||||
case tkind.TK_MODULE: return "package";
|
||||
case tkind.TK_MODRESET: return "//ww:module-reset";
|
||||
|
||||
case tkind.TK_LPAREN: return "(";
|
||||
case tkind.TK_RPAREN: return ")";
|
||||
@@ -6775,6 +6779,9 @@ type lex = struct {
|
||||
line: i32,
|
||||
col: i32,
|
||||
errs: i32,
|
||||
// a `//ww:module-reset` directive was seen in the last skipped run;
|
||||
// lexnext emits TK_MODRESET before the next real token (#16 opt-B).
|
||||
modreset: i32,
|
||||
};
|
||||
|
||||
export fn lexinit(l: *lex, file: str, src: *u8, len: u64) void = {
|
||||
@@ -6785,6 +6792,7 @@ export fn lexinit(l: *lex, file: str, src: *u8, len: u64) void = {
|
||||
l.line = 1;
|
||||
l.col = 1;
|
||||
l.errs = 0;
|
||||
l.modreset = 0;
|
||||
};
|
||||
|
||||
// srcb — byte at offset; helper that lifts the cast out of indexing.
|
||||
@@ -6846,6 +6854,26 @@ fn skipws(l: *lex) bool = {
|
||||
let c2: i32 = lpeek(l, 1u64);
|
||||
if (c2 == '/') {
|
||||
lget(l); lget(l); // consume '//'
|
||||
// #16 opt-B: recognize the driver's curmod-reset
|
||||
// boundary directive `//ww:module-reset` (whole
|
||||
// line) and flag it; lexnext emits TK_MODRESET.
|
||||
// The body is then skipped like any comment.
|
||||
// Mirrors cstage lex.c skipws. Compare via lpeek
|
||||
// (no consume) so the skip loop below is unchanged.
|
||||
let dir: str = "ww:module-reset";
|
||||
let di: i32 = 0;
|
||||
let matched: bool = true;
|
||||
for (di < dir.len) {
|
||||
if (lpeek(l, di: u64) != dir[di]: i32) {
|
||||
matched = false; break;
|
||||
};
|
||||
di += 1;
|
||||
};
|
||||
if (matched) {
|
||||
let nx: i32 = lpeek(l, dir.len: u64);
|
||||
if (nx == '\n') { l.modreset = 1; }
|
||||
else { if (nx < 0) { l.modreset = 1; }; };
|
||||
};
|
||||
for (true) {
|
||||
let cx: i32 = lpeek(l, 0u64);
|
||||
if (cx < 0) { return false; };
|
||||
@@ -7348,12 +7376,19 @@ export fn lexnext(l: *lex, out: *tok) void = {
|
||||
out.text = empty;
|
||||
out.tsuffix = empty;
|
||||
|
||||
if (!skipws(l)) {
|
||||
let p: pos; curpos(l, &p);
|
||||
emitsimple(&p, tkind.TK_EOF, out);
|
||||
let more: bool = skipws(l);
|
||||
let start: pos; curpos(l, &start);
|
||||
// A `//ww:module-reset` seen in the skipped run surfaces as its own
|
||||
// token before the next real one (#16 opt-B boundary reset).
|
||||
if (l.modreset != 0) {
|
||||
l.modreset = 0;
|
||||
emitsimple(&start, tkind.TK_MODRESET, out);
|
||||
return;
|
||||
};
|
||||
if (!more) {
|
||||
emitsimple(&start, tkind.TK_EOF, out);
|
||||
return;
|
||||
};
|
||||
let start: pos; curpos(l, &start);
|
||||
let c: i32 = lpeek(l, 0u64);
|
||||
|
||||
if (c >= 0) {
|
||||
@@ -8913,6 +8948,22 @@ export fn parsefile(p: *parser) *node = {
|
||||
p.curmod = name;
|
||||
continue;
|
||||
};
|
||||
// `//ww:module-reset` — bundle boundary before a package-less
|
||||
// file. Reset curmod to "" so the file's decls (and its own
|
||||
// `import os;`) are attributed to the primary module, not the
|
||||
// preceding bundled package. Codegen-neutral: "" curmod keeps
|
||||
// bare symbols. (#16 option-B; closes task #11.)
|
||||
// Driver-emitted ONLY before package-less files; a hand-placed
|
||||
// directive after a mid-file `package` would strip subsequent
|
||||
// decls to bare — that usage is deliberate-only.
|
||||
if (p.curkind == tkind.TK_MODRESET) {
|
||||
advance(p);
|
||||
let empty: str;
|
||||
empty.ptr = nil;
|
||||
empty.len = 0;
|
||||
p.curmod = empty;
|
||||
continue;
|
||||
};
|
||||
let attrs = parseattrs(p);
|
||||
let exported: i32 = 0;
|
||||
if (p.curkind == tkind.TK_EXPORT) { exported = 1; advance(p); };
|
||||
|
||||
@@ -3315,6 +3315,19 @@ fn expand(c: *expctx, pathcs: *u8) void = {
|
||||
i = j + 1u64;
|
||||
};
|
||||
|
||||
// #16 option-B: a package-less file's decls would otherwise inherit
|
||||
// the preceding bundled module's sticky curmod (parser parse.ww). Emit
|
||||
// a curmod-reset boundary directive so the lexer/parser attribute the
|
||||
// file to the primary module ("") — fixes the self-import false-fire
|
||||
// and the leaked-prefix bug, codegen-neutral (bare symbols kept; not
|
||||
// `package main`, which would main-prefix them). A packaged file's own
|
||||
// `package` decl already sets curmod, so it needs nothing — keeping
|
||||
// the directive out of every tracked combined.ww. (Task #11.)
|
||||
if (peekpackage(pathcs) == nil) {
|
||||
let d: str = "//ww:module-reset\n";
|
||||
os.writeall(c.out, d.ptr, d.len: u64);
|
||||
};
|
||||
|
||||
os.writeall(c.out, bufp, blen);
|
||||
os.writeall(c.out, "\n".ptr, 1u64);
|
||||
};
|
||||
|
||||
@@ -529,6 +529,19 @@ fn expand(c: *expctx, pathcs: *u8) void = {
|
||||
i = j + 1u64;
|
||||
};
|
||||
|
||||
// #16 option-B: a package-less file's decls would otherwise inherit
|
||||
// the preceding bundled module's sticky curmod (parser parse.ww). Emit
|
||||
// a curmod-reset boundary directive so the lexer/parser attribute the
|
||||
// file to the primary module ("") — fixes the self-import false-fire
|
||||
// and the leaked-prefix bug, codegen-neutral (bare symbols kept; not
|
||||
// `package main`, which would main-prefix them). A packaged file's own
|
||||
// `package` decl already sets curmod, so it needs nothing — keeping
|
||||
// the directive out of every tracked combined.ww. (Task #11.)
|
||||
if (peekpackage(pathcs) == nil) {
|
||||
let d: str = "//ww:module-reset\n";
|
||||
os.writeall(c.out, d.ptr, d.len: u64);
|
||||
};
|
||||
|
||||
os.writeall(c.out, bufp, blen);
|
||||
os.writeall(c.out, "\n".ptr, 1u64);
|
||||
};
|
||||
|
||||
@@ -6441,7 +6441,10 @@ type tkind = enum i32 {
|
||||
TK_YIELD = 84,
|
||||
TK_ENUM = 85,
|
||||
TK_MODULE = 86, // `module foo;` — directory-as-module decl
|
||||
TK_LAST = 87,
|
||||
TK_MODRESET = 87, // `//ww:module-reset` driver bundle boundary:
|
||||
// reset curmod to "" before a package-less file
|
||||
// (#16 option-B; cstage TK_MODRESET twin)
|
||||
TK_LAST = 88,
|
||||
};
|
||||
|
||||
// ---- Pos / Tok --------------------------------------------------------
|
||||
@@ -6563,6 +6566,7 @@ export fn tokname(k: tkind) str = {
|
||||
case tkind.TK_UNDER: return "_";
|
||||
case tkind.TK_ENUM: return "enum";
|
||||
case tkind.TK_MODULE: return "package";
|
||||
case tkind.TK_MODRESET: return "//ww:module-reset";
|
||||
|
||||
case tkind.TK_LPAREN: return "(";
|
||||
case tkind.TK_RPAREN: return ")";
|
||||
@@ -6775,6 +6779,9 @@ type lex = struct {
|
||||
line: i32,
|
||||
col: i32,
|
||||
errs: i32,
|
||||
// a `//ww:module-reset` directive was seen in the last skipped run;
|
||||
// lexnext emits TK_MODRESET before the next real token (#16 opt-B).
|
||||
modreset: i32,
|
||||
};
|
||||
|
||||
export fn lexinit(l: *lex, file: str, src: *u8, len: u64) void = {
|
||||
@@ -6785,6 +6792,7 @@ export fn lexinit(l: *lex, file: str, src: *u8, len: u64) void = {
|
||||
l.line = 1;
|
||||
l.col = 1;
|
||||
l.errs = 0;
|
||||
l.modreset = 0;
|
||||
};
|
||||
|
||||
// srcb — byte at offset; helper that lifts the cast out of indexing.
|
||||
@@ -6846,6 +6854,26 @@ fn skipws(l: *lex) bool = {
|
||||
let c2: i32 = lpeek(l, 1u64);
|
||||
if (c2 == '/') {
|
||||
lget(l); lget(l); // consume '//'
|
||||
// #16 opt-B: recognize the driver's curmod-reset
|
||||
// boundary directive `//ww:module-reset` (whole
|
||||
// line) and flag it; lexnext emits TK_MODRESET.
|
||||
// The body is then skipped like any comment.
|
||||
// Mirrors cstage lex.c skipws. Compare via lpeek
|
||||
// (no consume) so the skip loop below is unchanged.
|
||||
let dir: str = "ww:module-reset";
|
||||
let di: i32 = 0;
|
||||
let matched: bool = true;
|
||||
for (di < dir.len) {
|
||||
if (lpeek(l, di: u64) != dir[di]: i32) {
|
||||
matched = false; break;
|
||||
};
|
||||
di += 1;
|
||||
};
|
||||
if (matched) {
|
||||
let nx: i32 = lpeek(l, dir.len: u64);
|
||||
if (nx == '\n') { l.modreset = 1; }
|
||||
else { if (nx < 0) { l.modreset = 1; }; };
|
||||
};
|
||||
for (true) {
|
||||
let cx: i32 = lpeek(l, 0u64);
|
||||
if (cx < 0) { return false; };
|
||||
@@ -7348,12 +7376,19 @@ export fn lexnext(l: *lex, out: *tok) void = {
|
||||
out.text = empty;
|
||||
out.tsuffix = empty;
|
||||
|
||||
if (!skipws(l)) {
|
||||
let p: pos; curpos(l, &p);
|
||||
emitsimple(&p, tkind.TK_EOF, out);
|
||||
let more: bool = skipws(l);
|
||||
let start: pos; curpos(l, &start);
|
||||
// A `//ww:module-reset` seen in the skipped run surfaces as its own
|
||||
// token before the next real one (#16 opt-B boundary reset).
|
||||
if (l.modreset != 0) {
|
||||
l.modreset = 0;
|
||||
emitsimple(&start, tkind.TK_MODRESET, out);
|
||||
return;
|
||||
};
|
||||
if (!more) {
|
||||
emitsimple(&start, tkind.TK_EOF, out);
|
||||
return;
|
||||
};
|
||||
let start: pos; curpos(l, &start);
|
||||
let c: i32 = lpeek(l, 0u64);
|
||||
|
||||
if (c >= 0) {
|
||||
@@ -8913,6 +8948,22 @@ export fn parsefile(p: *parser) *node = {
|
||||
p.curmod = name;
|
||||
continue;
|
||||
};
|
||||
// `//ww:module-reset` — bundle boundary before a package-less
|
||||
// file. Reset curmod to "" so the file's decls (and its own
|
||||
// `import os;`) are attributed to the primary module, not the
|
||||
// preceding bundled package. Codegen-neutral: "" curmod keeps
|
||||
// bare symbols. (#16 option-B; closes task #11.)
|
||||
// Driver-emitted ONLY before package-less files; a hand-placed
|
||||
// directive after a mid-file `package` would strip subsequent
|
||||
// decls to bare — that usage is deliberate-only.
|
||||
if (p.curkind == tkind.TK_MODRESET) {
|
||||
advance(p);
|
||||
let empty: str;
|
||||
empty.ptr = nil;
|
||||
empty.len = 0;
|
||||
p.curmod = empty;
|
||||
continue;
|
||||
};
|
||||
let attrs = parseattrs(p);
|
||||
let exported: i32 = 0;
|
||||
if (p.curkind == tkind.TK_EXPORT) { exported = 1; advance(p); };
|
||||
|
||||
Reference in New Issue
Block a user