ww: preserve command package identities
This commit is contained in:
@@ -31,13 +31,14 @@ struct importin {
|
||||
|
||||
static Node *
|
||||
parseinput(Arena *a, const char *file, char *buf, u64 len,
|
||||
const char *mod, const char *testsupport, int *bad)
|
||||
const char *mod, const char *testsupport, int commandpackage, int *bad)
|
||||
{
|
||||
Lex l;
|
||||
Parser p;
|
||||
lexinit(&l, a, file, buf, len);
|
||||
parserinit(&p, a, &l);
|
||||
p.testmodule = testsupport;
|
||||
p.commandpackage = commandpackage;
|
||||
if (mod != NULL) {
|
||||
p.pathmod = mod;
|
||||
p.curmod = mod;
|
||||
@@ -66,6 +67,7 @@ main(int argc, char **argv)
|
||||
const char *testsupport = NULL;
|
||||
int testmode = 0;
|
||||
int testpackage = 0;
|
||||
int commandpackage = 0;
|
||||
int entrymode = 0;
|
||||
int sepmode = 0; /* -c: #22 M3 separate-compile / primary-
|
||||
* only codegen (emit imported==0 decls
|
||||
@@ -86,6 +88,8 @@ main(int argc, char **argv)
|
||||
testmode = 1;
|
||||
} else if (strcmp(a, "--test-package") == 0) {
|
||||
testpackage = 1;
|
||||
} else if (strcmp(a, "--command-package") == 0) {
|
||||
commandpackage = 1;
|
||||
} else if (strcmp(a, "--entry") == 0) {
|
||||
entrymode = 1;
|
||||
} else if (strcmp(a, "--test-support-module") == 0) {
|
||||
@@ -115,7 +119,7 @@ main(int argc, char **argv)
|
||||
}
|
||||
}
|
||||
if (src == NULL) {
|
||||
fputs("usage: w6c [-T|--test-package] [--entry] [-c] [-I out.wwi] "
|
||||
fputs("usage: w6c [-T|--test-package] [--command-package] [--entry] [-c] [-I out.wwi] "
|
||||
"[--import path dep.wwi]... [-o out.s] file.ww\n", stderr);
|
||||
return 2;
|
||||
}
|
||||
@@ -123,8 +127,8 @@ main(int argc, char **argv)
|
||||
fputs("w6c: --import requires -c\n", stderr);
|
||||
return 2;
|
||||
}
|
||||
if ((entrymode || testpackage) && !sepmode) {
|
||||
fputs("w6c: --entry and --test-package require -c\n", stderr);
|
||||
if ((entrymode || testpackage || commandpackage) && !sepmode) {
|
||||
fputs("w6c: --entry, --test-package, and --command-package require -c\n", stderr);
|
||||
return 2;
|
||||
}
|
||||
if (testmode && testpackage) {
|
||||
@@ -162,7 +166,7 @@ main(int argc, char **argv)
|
||||
}
|
||||
int bad = 0;
|
||||
Node *f = parseinput(a, imports[i].file, imports[i].buf,
|
||||
imports[i].len, imports[i].path, testsupport, &bad);
|
||||
imports[i].len, imports[i].path, testsupport, 0, &bad);
|
||||
if (bad) return 1;
|
||||
appendnodes(&head, &tail, f->list);
|
||||
}
|
||||
@@ -174,7 +178,11 @@ main(int argc, char **argv)
|
||||
return 1;
|
||||
}
|
||||
int bad = 0;
|
||||
Node *file = parseinput(a, src, buf, len, NULL, testsupport, &bad);
|
||||
/* --entry classifies an ordinary selected command. The separate
|
||||
* --command-package marker carries the same parser-only fact for command
|
||||
* test variants whose code generation must not expose bare main. */
|
||||
Node *file = parseinput(a, src, buf, len, NULL, testsupport,
|
||||
commandpackage || entrymode, &bad);
|
||||
if (bad) return 1;
|
||||
if (head != NULL) {
|
||||
tail->next = file->list;
|
||||
|
||||
@@ -1575,7 +1575,12 @@ parsefile(Parser *p)
|
||||
&& strcmp(p->testmodule, "__wwtest") == 0
|
||||
&& strcmp(active, "__wwtest") == 0
|
||||
&& strcmp(name, "test") == 0;
|
||||
if (strcmp(name, last) != 0 && !testsupport) {
|
||||
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);
|
||||
|
||||
@@ -381,6 +381,8 @@ struct Parser {
|
||||
* component) instead of overwriting curmod. */
|
||||
const char *testmodule; /* hidden package-driver alias for toolchain
|
||||
* `package test`; NULL outside that compile */
|
||||
int commandpackage; /* selected command family: package main/main_test
|
||||
* validates kind without replacing resetmod identity */
|
||||
};
|
||||
|
||||
void parserinit(Parser*, Arena*, Lex*);
|
||||
|
||||
@@ -638,6 +638,37 @@ sep_import_base_valid(const char *path)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Go command packages retain their canonical import identity while declaring
|
||||
* package main. An external command-test variant declares main_test. These
|
||||
* declarations classify package kind but never participate in interning. */
|
||||
static int
|
||||
sep_command_declared_name(const struct seppkg *p)
|
||||
{
|
||||
return p->variant == SEP_VARIANT_EXTERNAL
|
||||
? strcmp(p->name, "main_test") == 0
|
||||
: strcmp(p->name, "main") == 0;
|
||||
}
|
||||
static int
|
||||
sep_forbidden_command_import(const struct sepgraph *g, int importer, int dep)
|
||||
{
|
||||
const struct seppkg *from = &g->pkg[importer];
|
||||
const struct seppkg *to = &g->pkg[dep];
|
||||
if (strcmp(to->name, "main") != 0 || to->role != SEP_ROLE_NORMAL)
|
||||
return 0;
|
||||
/* An external test's exact import of its colocated command production is
|
||||
* test-variant wiring, not a general source-importable command edge. */
|
||||
return !(from->variant == SEP_VARIANT_EXTERNAL
|
||||
&& sep_command_declared_name(from)
|
||||
&& strcmp(from->canon, to->canon) == 0);
|
||||
}
|
||||
|
||||
static int
|
||||
sep_command_compiler_marker(const struct sepgraph *g, int pi)
|
||||
{
|
||||
return sep_command_declared_name(&g->pkg[pi])
|
||||
&& !g->pkg[pi].link_entry;
|
||||
}
|
||||
|
||||
/* Bind the canonical ordinary import identity of one provisional directory
|
||||
* action. The action's compiler path is derived from that base and its semantic
|
||||
* variant; neither requested-root state nor artifact naming participates. */
|
||||
@@ -1223,7 +1254,9 @@ sep_scan_file(struct sepgraph *g, int pi, const char *file,
|
||||
}
|
||||
int self = strcmp(canon, g->pkg[pi].canon) == 0;
|
||||
free(canon);
|
||||
if (self && sep_external_production_name(&g->pkg[pi], name, 1))
|
||||
if (self
|
||||
&& (sep_external_production_name(&g->pkg[pi], name, 1)
|
||||
|| sep_command_declared_name(&g->pkg[pi])))
|
||||
external_production = 1;
|
||||
if (self && !external_production) {
|
||||
const char *owner = g->pkg[pi].path[0]
|
||||
@@ -1409,7 +1442,8 @@ sep_load_pkg(struct sepgraph *g, int pi, int context)
|
||||
&& !g->pkg[pi].test_support) {
|
||||
const char *dot = strrchr(g->pkg[pi].path, '.');
|
||||
const char *leaf = dot ? dot + 1 : g->pkg[pi].path;
|
||||
if (strcmp(g->pkg[pi].name, leaf) != 0) {
|
||||
if (strcmp(g->pkg[pi].name, leaf) != 0
|
||||
&& !sep_command_declared_name(&g->pkg[pi])) {
|
||||
fprintf(stderr,
|
||||
"ww: package %s does not match import path %s\n",
|
||||
g->pkg[pi].name, g->pkg[pi].path);
|
||||
@@ -1461,11 +1495,20 @@ sep_load_pkg(struct sepgraph *g, int pi, int context)
|
||||
/* Mark before recursion so a source cycle terminates here; topo emits the
|
||||
* stable cycle diagnostic after all direct bindings are known. */
|
||||
g->pkg[pi].context_state[context] = 2;
|
||||
for (int k = 0; k < g->pkg[pi].ndeps; k++)
|
||||
if (sep_load_pkg(g, g->pkg[pi].deps[k], context) < 0) {
|
||||
for (int k = 0; k < g->pkg[pi].ndeps; k++) {
|
||||
int dep = g->pkg[pi].deps[k];
|
||||
if (sep_load_pkg(g, dep, context) < 0) {
|
||||
g->pkg[pi].failed = 1;
|
||||
return -1;
|
||||
}
|
||||
if (dep != pi && sep_forbidden_command_import(g, pi, dep)) {
|
||||
fprintf(stderr,
|
||||
"ww: package %s is a program, not an importable package\n",
|
||||
g->pkg[dep].path[0] ? g->pkg[dep].path : g->pkg[dep].canon);
|
||||
g->pkg[pi].failed = 1;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1677,7 +1720,8 @@ sep_finalize_directory_identities(struct sepgraph *g)
|
||||
int support_alias = p->role == SEP_ROLE_TEST_SUPPORT
|
||||
&& strcmp(p->path, SEP_TEST_SUPPORT_MODULE) == 0
|
||||
&& strcmp(p->name, "test") == 0;
|
||||
if (!support_alias && strcmp(p->name, leaf) != 0) {
|
||||
if (!support_alias && strcmp(p->name, leaf) != 0
|
||||
&& !sep_command_declared_name(p)) {
|
||||
fprintf(stderr, "ww: package %s does not match import path %s\n",
|
||||
p->name, p->path);
|
||||
return -1;
|
||||
@@ -2437,6 +2481,8 @@ build_one_sep_impl(const char *src, int entry_is_dir,
|
||||
if (g->pkg[pi].variant == SEP_VARIANT_SAME_TEST
|
||||
|| g->pkg[pi].variant == SEP_VARIANT_EXTERNAL)
|
||||
cargv[cpos++] = "--test-package";
|
||||
if (sep_command_compiler_marker(g, pi))
|
||||
cargv[cpos++] = "--command-package";
|
||||
if (g->pkg[pi].link_entry)
|
||||
cargv[cpos++] = "--entry";
|
||||
if (g->pkg[pi].test_support) {
|
||||
|
||||
Reference in New Issue
Block a user