ww: add file-scoped import aliases
This commit is contained in:
@@ -67,38 +67,63 @@ parseinput(Arena *a, const char *file, char *buf, u64 len,
|
||||
return f;
|
||||
}
|
||||
|
||||
/* Export data carries canonical owner and declared package name separately.
|
||||
* Search every direct interface's package-clause markers because its
|
||||
* self-contained fact closure can also name a transitive owner. */
|
||||
static int
|
||||
canonical_pkgname(const char *path, const char *name)
|
||||
{
|
||||
static const char hex[] = "0123456789abcdef";
|
||||
const char *prefix = "__wwi_";
|
||||
for (int i = 0; prefix[i]; i++)
|
||||
if (*name++ != prefix[i]) return 0;
|
||||
for (const unsigned char *p = (const unsigned char *)path; *p; p++) {
|
||||
if (*name++ != hex[*p >> 4] || *name++ != hex[*p & 15])
|
||||
return 0;
|
||||
}
|
||||
return *name == '\0';
|
||||
}
|
||||
|
||||
static void
|
||||
consider_pkgname(const char *path, const char *candidate,
|
||||
const char **name, const char **placeholder, int *conflict)
|
||||
{
|
||||
if (canonical_pkgname(path, candidate)) {
|
||||
*placeholder = candidate;
|
||||
return;
|
||||
}
|
||||
if (*name != NULL && strcmp(*name, candidate) != 0) {
|
||||
*conflict = 1;
|
||||
return;
|
||||
}
|
||||
*name = candidate;
|
||||
}
|
||||
|
||||
/* A paired interface owns PATH's declared name. Compiler-private names keep
|
||||
* transitive fact sections semantic and are ignored when a real name exists. */
|
||||
static const char *
|
||||
import_pkgname(struct importin *imports, int nimports, const char *path,
|
||||
Node *primary, int *conflict)
|
||||
{
|
||||
const char *name = NULL;
|
||||
const char *placeholder = NULL;
|
||||
for (int i = 0; i < nimports; i++) {
|
||||
if (strcmp(imports[i].path, path) != 0) continue;
|
||||
Node *file = imports[i].ast;
|
||||
for (Node *p = file ? file->body : NULL; p; p = p->next) {
|
||||
if (p->module == NULL || p->pkgname == NULL
|
||||
|| strcmp(p->module, path) != 0)
|
||||
continue;
|
||||
if (name != NULL && strcmp(name, p->pkgname) != 0) {
|
||||
*conflict = 1;
|
||||
return NULL;
|
||||
}
|
||||
name = p->pkgname;
|
||||
consider_pkgname(path, p->pkgname, &name, &placeholder,
|
||||
conflict);
|
||||
if (*conflict) return NULL;
|
||||
}
|
||||
}
|
||||
for (Node *p = primary ? primary->body : NULL; p; p = p->next) {
|
||||
if (p->module == NULL || p->pkgname == NULL
|
||||
|| strcmp(p->module, path) != 0)
|
||||
continue;
|
||||
if (name != NULL && strcmp(name, p->pkgname) != 0) {
|
||||
*conflict = 1;
|
||||
return NULL;
|
||||
}
|
||||
name = p->pkgname;
|
||||
consider_pkgname(path, p->pkgname, &name, &placeholder, conflict);
|
||||
if (*conflict) return NULL;
|
||||
}
|
||||
return name;
|
||||
return name ? name : placeholder;
|
||||
}
|
||||
|
||||
static int
|
||||
@@ -122,8 +147,9 @@ bind_import_names(Node *list, struct importin *imports, int nimports,
|
||||
return -1;
|
||||
}
|
||||
if (name != NULL) {
|
||||
u->str = name;
|
||||
u->strlen = strlen(name);
|
||||
u->usepkgname = name;
|
||||
u->str = u->usealias ? u->usealias : name;
|
||||
u->strlen = strlen(u->str);
|
||||
} else if (!u->imported) {
|
||||
fprintf(stderr,
|
||||
"w6c: import %s has no declared package name in direct export data\n",
|
||||
@@ -133,8 +159,8 @@ bind_import_names(Node *list, struct importin *imports, int nimports,
|
||||
/* A closure-only import need not contribute declarations to this
|
||||
* interface. Keep it canonical-path keyed without reinstalling
|
||||
* the historical path-leaf qualifier. */
|
||||
u->str = u->usepath;
|
||||
u->strlen = strlen(u->usepath);
|
||||
u->str = u->usealias ? u->usealias : u->usepath;
|
||||
u->strlen = strlen(u->str);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
@@ -348,13 +374,13 @@ main(int argc, char **argv)
|
||||
Node *file = parseinput(a, src, buf, len, NULL, testsupport,
|
||||
commandpackage || entrymode, &bad);
|
||||
if (bad) return 1;
|
||||
/* Source keeps its effective spelling and position, while package
|
||||
* resolution supplies the expanded canonical owner. Rewrite only the
|
||||
* primary import key before imported interface nodes are prepended. */
|
||||
/* Vendor expansion changes only canonical identity. Source spelling and
|
||||
* an optional file-local alias remain independent facts. */
|
||||
for (Node *u = file->list; u; u = u->next) {
|
||||
if (u->kind != N_USE || u->usepath == NULL) continue;
|
||||
const char *source = u->usesource ? u->usesource : u->usepath;
|
||||
for (int i = 0; i < nmaps; i++)
|
||||
if (strcmp(u->usepath, maps[i].source) == 0) {
|
||||
if (strcmp(source, maps[i].source) == 0) {
|
||||
u->usepath = maps[i].path;
|
||||
maps[i].seen = 1;
|
||||
break;
|
||||
|
||||
Reference in New Issue
Block a user