ww: separate package identity from declared name
This commit is contained in:
@@ -127,8 +127,11 @@ export type node = struct {
|
||||
type_: *void, // filled in by checker; type.ww treats it as *tinfo
|
||||
tsuffix: str, // typed numeric literal suffix ("i32", "u64", ...)
|
||||
nmod: str, // originating module from `// MODULE: foo`; "" if none
|
||||
usepath: str, // on an N_USE: full dotted IMPORT path vs leaf alias
|
||||
// in `str` (M1 #22); "" otherwise
|
||||
usepath: str, // on N_USE: full canonical import path; `str` becomes
|
||||
// the file-local declared default qualifier; "" otherwise
|
||||
pkgname: str, // declared package name; independent of canonical nmod
|
||||
sourceid: i32, // lexical source-file scope in an owner/export unit
|
||||
used: i32, // N_USE: checker observed this file-local binding
|
||||
imported: i32, // M1 #22: decl reached via `//ww:module <path>` import
|
||||
// boundary (vs root/primary); gates root-only bare main
|
||||
};
|
||||
@@ -137,7 +140,7 @@ export fn newnode(k: nkind, file: str, line: i32, col: i32) *node = {
|
||||
// fval cast-init: 990's wwdump TK_FLOAT diff requires this file
|
||||
// to tokenise identically through C and ww (lex.ww:382 has the
|
||||
// same workaround for the cstage %g-formats vs ww-skips divergence).
|
||||
let n: *node = alloc(node{kind=k, file=file, line=line, col=col, op=tkind.TK_NONE, str="", uval=0u64, fval=0: f64, lhs=nil, rhs=nil, cond=nil, body=nil, els=nil, list=nil, next=nil, attr=nil, exported=0, packed=0, type_=nil, tsuffix="", nmod="", usepath="", imported=0})!;
|
||||
let n: *node = alloc(node{kind=k, file=file, line=line, col=col, op=tkind.TK_NONE, str="", uval=0u64, fval=0: f64, lhs=nil, rhs=nil, cond=nil, body=nil, els=nil, list=nil, next=nil, attr=nil, exported=0, packed=0, type_=nil, tsuffix="", nmod="", usepath="", pkgname="", sourceid=0, used=0, imported=0})!;
|
||||
return n;
|
||||
};
|
||||
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
package syntax;
|
||||
|
||||
import os;
|
||||
import strings;
|
||||
|
||||
// `import encoding.utf8;` — the driver resolves the dotted path to
|
||||
@@ -18,8 +17,8 @@ fn parseuse(p: *parser) *node = {
|
||||
let n: *node = newnode(nkind.N_USE, pf, pl, pc);
|
||||
n.nmod = p.curmod;
|
||||
// M1 #22: accumulate the full dotted import path (n.usepath) for the
|
||||
// checker's path-keyed module match; n.str stays the leaf alias the
|
||||
// user writes (`utf8.x`).
|
||||
// checker's path-keyed module match. n.str is the provisional path leaf;
|
||||
// direct export metadata later replaces it with the declared default name.
|
||||
let leaf: str;
|
||||
expectident(p, &leaf);
|
||||
let path: str = leaf;
|
||||
|
||||
@@ -2,8 +2,6 @@
|
||||
|
||||
package syntax;
|
||||
|
||||
import os;
|
||||
|
||||
// Inlined to avoid a cross-module `use sym;` for one call site.
|
||||
fn streqlocal(a: str, b: str) bool = {
|
||||
if (a.len != b.len) { return false; };
|
||||
|
||||
@@ -41,11 +41,14 @@ export type parser = struct {
|
||||
// decls stamp nmod=pathmod and imported=1, and the in-file `package`
|
||||
// clause is an assertion. "" means inactive (root/primary).
|
||||
pathmod: str,
|
||||
// #57: active `//ww:module-reset <path>` dotted path. Mangles decls on
|
||||
// the path WITHOUT imported=1 (primary-ness for -c and the #32 bare-main
|
||||
// rule stay intact), and the in-file `package` clause asserts (leaf ==
|
||||
// last component) instead of overwriting curmod. "" means inactive.
|
||||
// #57: active `//ww:module-reset <path>` canonical identity. Decls
|
||||
// mangle on it without imported=1; the package clause independently
|
||||
// supplies the declared name. "" means inactive.
|
||||
resetmod: str,
|
||||
// Declared package name and file scope are deliberately orthogonal to
|
||||
// curmod/pathmod. Every driver module boundary advances sourceid.
|
||||
curpkg: str,
|
||||
sourceid: i32,
|
||||
// Hidden package-driver alias for the toolchain `package test` source.
|
||||
// Empty outside that one separate-compilation edge.
|
||||
testmodule: str,
|
||||
@@ -73,6 +76,8 @@ export fn parserinit(p: *parser, l: *lex) void = {
|
||||
p.nocast = 0;
|
||||
p.pathmod = "";
|
||||
p.resetmod = "";
|
||||
p.curpkg = "";
|
||||
p.sourceid = 0;
|
||||
p.testmodule = "";
|
||||
p.commandpackage = false;
|
||||
refill(p);
|
||||
@@ -498,19 +503,23 @@ export fn parseimports(p: *parser) *node = {
|
||||
// the following package clause and imports.
|
||||
if (p.curkind == tkind.TK_MODPATH) {
|
||||
sawpackage = false;
|
||||
p.sourceid += 1;
|
||||
p.pathmod = p.curtext;
|
||||
p.curmod = p.curtext;
|
||||
p.resetmod = "";
|
||||
p.curpkg = "";
|
||||
advance(p);
|
||||
continue;
|
||||
};
|
||||
if (p.curkind == tkind.TK_MODRESET) {
|
||||
let rp: str = p.curtext;
|
||||
sawpackage = false;
|
||||
p.sourceid += 1;
|
||||
advance(p);
|
||||
p.pathmod = "";
|
||||
p.curmod = rp;
|
||||
p.resetmod = rp;
|
||||
p.curpkg = "";
|
||||
continue;
|
||||
};
|
||||
if (p.curkind == tkind.TK_MODULE) {
|
||||
@@ -527,14 +536,21 @@ export fn parseimports(p: *parser) *node = {
|
||||
let name: str;
|
||||
expectident(p, &name);
|
||||
expecttok(p, tkind.TK_SEMI, "expected ';' after module name");
|
||||
p.curmod = name;
|
||||
p.curpkg = name;
|
||||
if (p.pathmod.len == 0 && p.resetmod.len == 0) {
|
||||
p.curmod = name;
|
||||
};
|
||||
let pm = newnode(nkind.N_FILE, pf, pl, pc);
|
||||
pm.nmod = name;
|
||||
pm.nmod = p.curmod;
|
||||
pm.pkgname = name;
|
||||
pm.sourceid = p.sourceid;
|
||||
if (packages == nil) { packages = pm; }
|
||||
else { packagetail.next = pm; };
|
||||
packagetail = pm;
|
||||
if (!sawpackage) {
|
||||
f.nmod = name;
|
||||
f.pkgname = name;
|
||||
f.sourceid = p.sourceid;
|
||||
f.file = pf;
|
||||
f.line = pl;
|
||||
f.col = pc;
|
||||
@@ -549,6 +565,8 @@ export fn parseimports(p: *parser) *node = {
|
||||
if (p.curkind == tkind.TK_USE) {
|
||||
let d: *node = parseuse(p);
|
||||
d.nmod = p.curmod;
|
||||
d.pkgname = p.curpkg;
|
||||
d.sourceid = p.sourceid;
|
||||
if (head == nil) { head = d; } else { tail.next = d; };
|
||||
tail = d;
|
||||
continue;
|
||||
@@ -560,6 +578,8 @@ export fn parseimports(p: *parser) *node = {
|
||||
errmsg(p, "import cannot be exported or attributed");
|
||||
let d: *node = parseuse(p);
|
||||
d.nmod = p.curmod;
|
||||
d.pkgname = p.curpkg;
|
||||
d.sourceid = p.sourceid;
|
||||
if (head == nil) { head = d; } else { tail.next = d; };
|
||||
tail = d;
|
||||
continue;
|
||||
@@ -573,6 +593,8 @@ export fn parseimports(p: *parser) *node = {
|
||||
errmsg(p, "import cannot be exported or attributed");
|
||||
let d: *node = parseuse(p);
|
||||
d.nmod = p.curmod;
|
||||
d.pkgname = p.curpkg;
|
||||
d.sourceid = p.sourceid;
|
||||
if (head == nil) { head = d; } else { tail.next = d; };
|
||||
tail = d;
|
||||
continue;
|
||||
@@ -593,6 +615,8 @@ export fn parsefile(p: *parser) *node = {
|
||||
let f = newnode(nkind.N_FILE, p.curfile, p.curline, p.curcol);
|
||||
let head: *node = nil;
|
||||
let tail: *node = nil;
|
||||
let packages: *node = nil;
|
||||
let packagetail: *node = nil;
|
||||
let sawpackage: i32 = 0;
|
||||
for (p.curkind != tkind.TK_EOF) {
|
||||
// `package foo;` — directory-as-module declaration. Every
|
||||
@@ -602,57 +626,44 @@ export fn parsefile(p: *parser) *node = {
|
||||
// sep primary-reset (resetmod) regions carry identity
|
||||
// out-of-band and are exempt.
|
||||
if (p.curkind == tkind.TK_MODULE) {
|
||||
let pf: str = p.curfile;
|
||||
let pl: i32 = p.curline;
|
||||
let pc: i32 = p.curcol;
|
||||
sawpackage = 1;
|
||||
advance(p);
|
||||
let name: str;
|
||||
expectident(p, &name);
|
||||
expecttok(p, tkind.TK_SEMI, "expected ';' after module name");
|
||||
if (p.pathmod.len != 0 || p.resetmod.len != 0) {
|
||||
// M1 #22: while an import path is active the in-file
|
||||
// `package` clause is an ASSERTION — its leaf must
|
||||
// equal the path's last component; it does NOT
|
||||
// overwrite the path-derived module. #57 extends this
|
||||
// to the sep primary-reset path (resetmod): the dotted
|
||||
// reset path is authoritative, the clause asserts.
|
||||
let active: str = p.pathmod;
|
||||
if (p.pathmod.len == 0) { active = p.resetmod; };
|
||||
let (pre, post) = strings.rcut(active, ".");
|
||||
let last: str = post;
|
||||
if (post.len == 0) { last = active; };
|
||||
let testsupport: bool = strings.compare(
|
||||
p.testmodule, "__wwtest") == 0
|
||||
&& strings.compare(active, "__wwtest") == 0
|
||||
&& strings.compare(name, "test") == 0;
|
||||
let commandpackage: bool = p.commandpackage
|
||||
&& p.pathmod.len == 0 && p.resetmod.len != 0
|
||||
&& (strings.compare(name, "main") == 0
|
||||
|| strings.compare(name, "main_test") == 0);
|
||||
if (strings.compare(name, last) != 0 && !testsupport
|
||||
&& !commandpackage) {
|
||||
errmsg(p, strings.concat(strings.concat(strings.concat(
|
||||
"package ", name),
|
||||
" does not match import path "), active));
|
||||
};
|
||||
} else {
|
||||
p.curpkg = name;
|
||||
if (p.pathmod.len == 0 && p.resetmod.len == 0) {
|
||||
p.curmod = name;
|
||||
// #11: stamp the primary module identity on the
|
||||
// N_FILE node so wwi_emit can derive the `package`
|
||||
// leaf even when the body carries zero module-tagged
|
||||
// decls. Primary identity only; never the imported
|
||||
// boundary (TK_MODPATH).
|
||||
if (f.nmod.len == 0) { f.nmod = name; };
|
||||
};
|
||||
let pm: *node = newnode(nkind.N_FILE, pf, pl, pc);
|
||||
pm.nmod = p.curmod;
|
||||
pm.pkgname = name;
|
||||
pm.sourceid = p.sourceid;
|
||||
if (p.pathmod.len != 0) { pm.imported = 1; };
|
||||
if (packages == nil) { packages = pm; }
|
||||
else { packagetail.next = pm; };
|
||||
packagetail = pm;
|
||||
if (f.pkgname.len == 0) {
|
||||
f.pkgname = name;
|
||||
f.sourceid = p.sourceid;
|
||||
};
|
||||
continue;
|
||||
};
|
||||
// `//ww:module <path>` — M1 #22 import boundary. The following
|
||||
// file's decls mangle on the full dotted import path, not the
|
||||
// leaf `package` clause, and are flagged imported (gates the
|
||||
// file's decls mangle on the full dotted import path independently
|
||||
// of its `package` clause, and are flagged imported (gates the
|
||||
// root-only bare-`main` rule, #32).
|
||||
if (p.curkind == tkind.TK_MODPATH) {
|
||||
sawpackage = 0;
|
||||
p.sourceid += 1;
|
||||
p.pathmod = p.curtext;
|
||||
p.curmod = p.curtext;
|
||||
p.resetmod = "";
|
||||
p.curpkg = "";
|
||||
if (f.nmod.len == 0) { f.nmod = p.curtext; };
|
||||
advance(p);
|
||||
continue;
|
||||
};
|
||||
@@ -666,6 +677,7 @@ export fn parsefile(p: *parser) *node = {
|
||||
// decls to bare — that usage is deliberate-only.
|
||||
if (p.curkind == tkind.TK_MODRESET) {
|
||||
sawpackage = 0;
|
||||
p.sourceid += 1;
|
||||
// #57: a path-carrying reset (sep primary body) mangles decls
|
||||
// on the dotted path so definer == importer, but leaves
|
||||
// imported==0 (curmod set, pathmod "") so -c primary-ness and
|
||||
@@ -675,6 +687,7 @@ export fn parsefile(p: *parser) *node = {
|
||||
let rp: str = p.curtext;
|
||||
advance(p);
|
||||
p.pathmod = "";
|
||||
p.curpkg = "";
|
||||
if (rp.len != 0) {
|
||||
p.curmod = rp;
|
||||
p.resetmod = rp;
|
||||
@@ -756,6 +769,9 @@ export fn parsefile(p: *parser) *node = {
|
||||
// M1 #22: flag decls reached via an import-path boundary
|
||||
// (gates the root-only bare-`main` rule, #32).
|
||||
if (p.pathmod.len != 0) { d.imported = 1; };
|
||||
d.nmod = p.curmod;
|
||||
d.pkgname = p.curpkg;
|
||||
d.sourceid = p.sourceid;
|
||||
if (head == nil) {
|
||||
head = d;
|
||||
tail = d;
|
||||
@@ -766,5 +782,6 @@ export fn parsefile(p: *parser) *node = {
|
||||
};
|
||||
};
|
||||
f.list = head;
|
||||
f.body = packages;
|
||||
return f;
|
||||
};
|
||||
|
||||
@@ -2,8 +2,6 @@
|
||||
|
||||
package syntax;
|
||||
|
||||
import os;
|
||||
|
||||
fn parseletlocal(p: *parser) *node = {
|
||||
let pf = p.curfile;
|
||||
let pl = p.curline;
|
||||
|
||||
@@ -115,8 +115,8 @@ export type tkind = enum i32 {
|
||||
// reset curmod to "" before a package-less file
|
||||
// (#16 option-B; cstage TK_MODRESET twin)
|
||||
TK_MODPATH = 88, // `//ww:module <dotted-path>` driver import
|
||||
// boundary; decls mangle on the path, not the
|
||||
// leaf `package` clause (M1 #22; cstage twin)
|
||||
// boundary; decls mangle on the path independently
|
||||
// of the `package` clause (M1 #22; cstage twin)
|
||||
TK_LAST = 89,
|
||||
};
|
||||
|
||||
|
||||
@@ -8,8 +8,6 @@
|
||||
|
||||
package syntax;
|
||||
|
||||
import os;
|
||||
|
||||
// Mirror of the C `TypeKind` enum in cmd/wcc/ww.h. Numeric values
|
||||
// are explicit and must stay in sync — the selfhost selfcheck and
|
||||
// typed-AST printers depend on matching numeric layout.
|
||||
|
||||
Reference in New Issue
Block a user