ww: implement local vendor package semantics
This commit is contained in:
@@ -41,6 +41,19 @@ struct importin {
|
||||
u64 len;
|
||||
};
|
||||
|
||||
struct importmap {
|
||||
const char *source;
|
||||
const char *path;
|
||||
int seen;
|
||||
};
|
||||
|
||||
static const char *
|
||||
importleaf(const char *path)
|
||||
{
|
||||
const char *dot = strrchr(path, '.');
|
||||
return dot != NULL ? dot + 1 : path;
|
||||
}
|
||||
|
||||
static Node *
|
||||
parseinput(Arena *a, const char *file, char *buf, u64 len,
|
||||
const char *mod, const char *testsupport, int commandpackage, int *bad)
|
||||
@@ -85,11 +98,15 @@ main(int argc, char **argv)
|
||||
* only codegen (emit imported==0 decls
|
||||
* only; treat `.wwi` deps as external) */
|
||||
struct importin *imports = calloc((size_t)argc, sizeof *imports);
|
||||
if (imports == NULL) {
|
||||
struct importmap *maps = calloc((size_t)argc, sizeof *maps);
|
||||
if (imports == NULL || maps == NULL) {
|
||||
fputs("w6c: out of memory\n", stderr);
|
||||
free(maps);
|
||||
free(imports);
|
||||
return 1;
|
||||
}
|
||||
int nimports = 0;
|
||||
int nmaps = 0;
|
||||
for (int i = 1; i < argc; i++) {
|
||||
const char *a = argv[i];
|
||||
if (strcmp(a, "-o") == 0 && i + 1 < argc) {
|
||||
@@ -120,6 +137,14 @@ main(int argc, char **argv)
|
||||
imports[nimports].path = argv[++i];
|
||||
imports[nimports].file = argv[++i];
|
||||
nimports++;
|
||||
} else if (strcmp(a, "--import-map") == 0) {
|
||||
if (i + 2 >= argc) {
|
||||
fputs("w6c: --import-map requires source and path\n", stderr);
|
||||
return 2;
|
||||
}
|
||||
maps[nmaps].source = argv[++i];
|
||||
maps[nmaps].path = argv[++i];
|
||||
nmaps++;
|
||||
} else if (a[0] == '-') {
|
||||
fprintf(stderr, "w6c: unknown flag %s\n", a);
|
||||
return 2;
|
||||
@@ -132,13 +157,17 @@ main(int argc, char **argv)
|
||||
}
|
||||
if (src == NULL) {
|
||||
fputs("usage: w6c [-T|--test-package] [--command-package] [--entry] [-c] [-I out.wwi] "
|
||||
"[--import path dep.wwi]... [-o out.s] file.ww\n", stderr);
|
||||
"[--import path dep.wwi]... [--import-map source path]... [-o out.s] file.ww\n", stderr);
|
||||
return 2;
|
||||
}
|
||||
if (nimports > 0 && !sepmode) {
|
||||
fputs("w6c: --import requires -c\n", stderr);
|
||||
return 2;
|
||||
}
|
||||
if (nmaps > 0 && !sepmode) {
|
||||
fputs("w6c: --import-map requires -c\n", stderr);
|
||||
return 2;
|
||||
}
|
||||
if ((entrymode || testpackage || commandpackage) && !sepmode) {
|
||||
fputs("w6c: --entry, --test-package, and --command-package require -c\n", stderr);
|
||||
return 2;
|
||||
@@ -157,6 +186,33 @@ main(int argc, char **argv)
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < nmaps; i++) {
|
||||
if (maps[i].source[0] == '\0' || maps[i].path[0] == '\0') {
|
||||
fputs("w6c: --import-map path is empty\n", stderr);
|
||||
return 2;
|
||||
}
|
||||
if (i > 0 && strcmp(maps[i-1].source, maps[i].source) >= 0) {
|
||||
fputs("w6c: --import-map sources must be sorted and unique\n",
|
||||
stderr);
|
||||
return 2;
|
||||
}
|
||||
if (strcmp(importleaf(maps[i].source),
|
||||
importleaf(maps[i].path)) != 0) {
|
||||
fputs("w6c: --import-map must preserve import leaf\n", stderr);
|
||||
return 2;
|
||||
}
|
||||
int direct = 0;
|
||||
for (int j = 0; j < nimports; j++)
|
||||
if (strcmp(maps[i].path, imports[j].path) == 0) {
|
||||
direct = 1;
|
||||
break;
|
||||
}
|
||||
if (!direct) {
|
||||
fputs("w6c: --import-map target is not a direct import\n",
|
||||
stderr);
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
if (testsupport != NULL && (!sepmode
|
||||
|| (strcmp(testsupport, "test") != 0
|
||||
&& strcmp(testsupport, "__wwtest") != 0))) {
|
||||
@@ -203,6 +259,23 @@ 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 leaf alias, while package
|
||||
* resolution supplies the expanded canonical owner. Rewrite only the
|
||||
* primary import key before imported interface nodes are prepended. */
|
||||
for (Node *u = file->list; u; u = u->next) {
|
||||
if (u->kind != N_USE || u->usepath == NULL) continue;
|
||||
for (int i = 0; i < nmaps; i++)
|
||||
if (strcmp(u->usepath, maps[i].source) == 0) {
|
||||
u->usepath = maps[i].path;
|
||||
maps[i].seen = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < nmaps; i++) {
|
||||
if (maps[i].seen) continue;
|
||||
fputs("w6c: --import-map source is not in primary input\n", stderr);
|
||||
return 2;
|
||||
}
|
||||
if (head != NULL) {
|
||||
tail->next = file->list;
|
||||
file->list = head;
|
||||
@@ -250,6 +323,7 @@ main(int argc, char **argv)
|
||||
freearena(a);
|
||||
for (int i = 0; i < nimports; i++) free(imports[i].buf);
|
||||
free(imports);
|
||||
free(maps);
|
||||
free(buf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user