ww: separate package identity from declared name
This commit is contained in:
@@ -1327,9 +1327,9 @@ parseuse(Parser *p)
|
||||
Pos pp = p->cur.pos;
|
||||
expect(p, TK_USE);
|
||||
Node *n = newnode(p->a, N_USE, pp);
|
||||
/* M1 #22: accumulate the full dotted import path (n->module) so the
|
||||
* checker can match decl identity on the path, while n->str stays the
|
||||
* leaf alias the user writes (`utf8.x`). */
|
||||
/* M1 #22: accumulate the full dotted import path in usepath. `str`
|
||||
* starts as its leaf; direct export metadata later installs the imported
|
||||
* declaration's default name without changing canonical identity. */
|
||||
const char *leaf = expectident(p);
|
||||
const char *path = leaf;
|
||||
while (accept(p, TK_DOT)) {
|
||||
@@ -1358,19 +1358,23 @@ parseimports(Parser *p)
|
||||
* the following package clause and imports. */
|
||||
if (p->cur.kind == TK_MODPATH) {
|
||||
sawpackage = 0;
|
||||
p->sourceid++;
|
||||
p->pathmod = p->cur.text;
|
||||
p->curmod = p->cur.text;
|
||||
p->resetmod = NULL;
|
||||
p->curpkg = NULL;
|
||||
advance(p);
|
||||
continue;
|
||||
}
|
||||
if (p->cur.kind == TK_MODRESET) {
|
||||
const char *rp = p->cur.text;
|
||||
sawpackage = 0;
|
||||
p->sourceid++;
|
||||
advance(p);
|
||||
p->pathmod = NULL;
|
||||
p->curmod = rp;
|
||||
p->resetmod = rp;
|
||||
p->curpkg = NULL;
|
||||
continue;
|
||||
}
|
||||
if (p->cur.kind == TK_MODULE) {
|
||||
@@ -1385,9 +1389,13 @@ parseimports(Parser *p)
|
||||
}
|
||||
const char *name = expectident(p);
|
||||
expect(p, TK_SEMI);
|
||||
p->curmod = name;
|
||||
p->curpkg = name;
|
||||
if (p->pathmod == NULL && p->resetmod == NULL)
|
||||
p->curmod = name;
|
||||
Node *package = newnode(p->a, N_FILE, pp);
|
||||
package->module = name;
|
||||
package->module = p->curmod;
|
||||
package->pkgname = name;
|
||||
package->sourceid = p->sourceid;
|
||||
if (packages == NULL)
|
||||
packages = package;
|
||||
else
|
||||
@@ -1395,6 +1403,8 @@ parseimports(Parser *p)
|
||||
packagetail = package;
|
||||
if (!sawpackage) {
|
||||
file->module = name;
|
||||
file->pkgname = name;
|
||||
file->sourceid = p->sourceid;
|
||||
file->pos = pp;
|
||||
sawpackage = 1;
|
||||
}
|
||||
@@ -1408,6 +1418,8 @@ parseimports(Parser *p)
|
||||
if (p->cur.kind == TK_USE) {
|
||||
Node *d = parseuse(p);
|
||||
d->module = p->curmod;
|
||||
d->pkgname = p->curpkg;
|
||||
d->sourceid = p->sourceid;
|
||||
if (head == NULL)
|
||||
head = d;
|
||||
else
|
||||
@@ -1424,6 +1436,8 @@ parseimports(Parser *p)
|
||||
p->errs++;
|
||||
Node *d = parseuse(p);
|
||||
d->module = p->curmod;
|
||||
d->pkgname = p->curpkg;
|
||||
d->sourceid = p->sourceid;
|
||||
if (head == NULL)
|
||||
head = d;
|
||||
else
|
||||
@@ -1441,6 +1455,8 @@ parseimports(Parser *p)
|
||||
p->errs++;
|
||||
Node *d = parseuse(p);
|
||||
d->module = p->curmod;
|
||||
d->pkgname = p->curpkg;
|
||||
d->sourceid = p->sourceid;
|
||||
if (head == NULL)
|
||||
head = d;
|
||||
else
|
||||
@@ -1546,6 +1562,7 @@ parsefile(Parser *p)
|
||||
Pos pp = { p->l->file, 1, 1 };
|
||||
Node *file = newnode(p->a, N_FILE, pp);
|
||||
Node *head = NULL, *tail = NULL;
|
||||
Node *packages = NULL, *packagetail = NULL;
|
||||
int sawpackage = 0;
|
||||
while (p->cur.kind != TK_EOF) {
|
||||
/* `package foo;` — directory-as-module declaration. Every
|
||||
@@ -1555,58 +1572,41 @@ parsefile(Parser *p)
|
||||
* sep primary-reset (resetmod) regions carry identity
|
||||
* out-of-band and are exempt. */
|
||||
if (p->cur.kind == TK_MODULE) {
|
||||
Pos packagepos = p->cur.pos;
|
||||
sawpackage = 1;
|
||||
advance(p);
|
||||
const char *name = expectident(p);
|
||||
expect(p, TK_SEMI);
|
||||
if (p->pathmod != NULL || p->resetmod != NULL) {
|
||||
/* 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 the
|
||||
* authoritative identity, the clause asserts. */
|
||||
const char *active =
|
||||
p->pathmod ? p->pathmod : p->resetmod;
|
||||
const char *dot = strrchr(active, '.');
|
||||
const char *last = dot ? dot + 1 : active;
|
||||
int testsupport = p->testmodule != NULL
|
||||
&& strcmp(p->testmodule, "__wwtest") == 0
|
||||
&& strcmp(active, "__wwtest") == 0
|
||||
&& strcmp(name, "test") == 0;
|
||||
int commandpackage = p->commandpackage
|
||||
&& p->pathmod == NULL && p->resetmod != NULL
|
||||
&& (strcmp(name, "main") == 0
|
||||
|| strcmp(name, "main_test") == 0);
|
||||
if (strcmp(name, last) != 0 && !testsupport
|
||||
&& !commandpackage) {
|
||||
errorf(p->cur.pos,
|
||||
"package %s does not match import path %s",
|
||||
name, active);
|
||||
p->errs++;
|
||||
}
|
||||
} else {
|
||||
p->curpkg = name;
|
||||
if (p->pathmod == NULL && p->resetmod == NULL) {
|
||||
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 (file->module == NULL)
|
||||
file->module = name;
|
||||
}
|
||||
Node *package = newnode(p->a, N_FILE, packagepos);
|
||||
package->module = p->curmod;
|
||||
package->pkgname = name;
|
||||
package->sourceid = p->sourceid;
|
||||
package->imported = p->pathmod != NULL;
|
||||
if (packages == NULL) packages = package;
|
||||
else packagetail->next = package;
|
||||
packagetail = package;
|
||||
if (file->pkgname == NULL) {
|
||||
file->pkgname = name;
|
||||
file->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->cur.kind == TK_MODPATH) {
|
||||
sawpackage = 0;
|
||||
p->sourceid++;
|
||||
p->pathmod = p->cur.text;
|
||||
p->curmod = p->cur.text;
|
||||
p->resetmod = NULL;
|
||||
p->curpkg = NULL;
|
||||
if (file->module == NULL) file->module = p->cur.text;
|
||||
advance(p);
|
||||
continue;
|
||||
}
|
||||
@@ -1620,6 +1620,7 @@ parsefile(Parser *p)
|
||||
* decls to bare — that usage is deliberate-only. */
|
||||
if (p->cur.kind == TK_MODRESET) {
|
||||
sawpackage = 0;
|
||||
p->sourceid++;
|
||||
/* #57: a path-carrying reset (sep primary body) mangles
|
||||
* decls on the dotted path so definer == importer, but
|
||||
* leaves imported==0 (curmod set, pathmod NULL) so -c
|
||||
@@ -1630,6 +1631,7 @@ parsefile(Parser *p)
|
||||
const char *rp = p->cur.text;
|
||||
advance(p);
|
||||
p->pathmod = NULL;
|
||||
p->curpkg = NULL;
|
||||
if (rp != NULL) {
|
||||
p->curmod = rp;
|
||||
p->resetmod = rp;
|
||||
@@ -1679,14 +1681,17 @@ parsefile(Parser *p)
|
||||
advance(p);
|
||||
continue;
|
||||
}
|
||||
if (d != NULL) {
|
||||
d->module = p->curmod;
|
||||
d->imported = (p->pathmod != NULL);
|
||||
if (d != NULL) {
|
||||
d->module = p->curmod;
|
||||
d->pkgname = p->curpkg;
|
||||
d->sourceid = p->sourceid;
|
||||
d->imported = (p->pathmod != NULL);
|
||||
}
|
||||
if (head == NULL) head = d;
|
||||
else tail->next = d;
|
||||
tail = d;
|
||||
}
|
||||
file->list = head;
|
||||
file->body = packages;
|
||||
return file;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user