ww: unify directory package-test products
This commit is contained in:
@@ -373,7 +373,7 @@ main(int argc, char **argv)
|
|||||||
const char *out = NULL;
|
const char *out = NULL;
|
||||||
const char *wwiout = NULL; /* -I <out.wwi>: M2 export-data producer */
|
const char *wwiout = NULL; /* -I <out.wwi>: M2 export-data producer */
|
||||||
const char *testsupport = NULL;
|
const char *testsupport = NULL;
|
||||||
const char *testtarget = NULL;
|
const char **testtargets = calloc((size_t)argc, sizeof *testtargets);
|
||||||
const char *packageinit = NULL;
|
const char *packageinit = NULL;
|
||||||
const char *initdispatch = NULL;
|
const char *initdispatch = NULL;
|
||||||
int testmode = 0;
|
int testmode = 0;
|
||||||
@@ -385,14 +385,16 @@ main(int argc, char **argv)
|
|||||||
* only; treat `.wwi` deps as external) */
|
* only; treat `.wwi` deps as external) */
|
||||||
struct importin *imports = calloc((size_t)argc, sizeof *imports);
|
struct importin *imports = calloc((size_t)argc, sizeof *imports);
|
||||||
struct importmap *maps = calloc((size_t)argc, sizeof *maps);
|
struct importmap *maps = calloc((size_t)argc, sizeof *maps);
|
||||||
if (imports == NULL || maps == NULL) {
|
if (imports == NULL || maps == NULL || testtargets == NULL) {
|
||||||
fputs("w6c: out of memory\n", stderr);
|
fputs("w6c: out of memory\n", stderr);
|
||||||
|
free(testtargets);
|
||||||
free(maps);
|
free(maps);
|
||||||
free(imports);
|
free(imports);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
int nimports = 0;
|
int nimports = 0;
|
||||||
int nmaps = 0;
|
int nmaps = 0;
|
||||||
|
int ntesttargets = 0;
|
||||||
for (int i = 1; i < argc; i++) {
|
for (int i = 1; i < argc; i++) {
|
||||||
const char *a = argv[i];
|
const char *a = argv[i];
|
||||||
if (strcmp(a, "-o") == 0 && i + 1 < argc) {
|
if (strcmp(a, "-o") == 0 && i + 1 < argc) {
|
||||||
@@ -430,7 +432,7 @@ main(int argc, char **argv)
|
|||||||
fputs("w6c: --test-target-package requires arg\n", stderr);
|
fputs("w6c: --test-target-package requires arg\n", stderr);
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
testtarget = argv[++i];
|
testtargets[ntesttargets++] = argv[++i];
|
||||||
} else if (strcmp(a, "-c") == 0) {
|
} else if (strcmp(a, "-c") == 0) {
|
||||||
sepmode = 1;
|
sepmode = 1;
|
||||||
} else if (strcmp(a, "--import") == 0) {
|
} else if (strcmp(a, "--import") == 0) {
|
||||||
@@ -535,12 +537,17 @@ main(int argc, char **argv)
|
|||||||
fputs("w6c: invalid --test-support-module\n", stderr);
|
fputs("w6c: invalid --test-support-module\n", stderr);
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
if (testtarget != NULL && (!sepmode || !testmode
|
for (int ti = 0; ti < ntesttargets; ti++) {
|
||||||
|| testtarget[0] == '\0')) {
|
const char *testtarget = testtargets[ti];
|
||||||
|
if (!sepmode || !testmode || testtarget[0] == '\0') {
|
||||||
fputs("w6c: invalid --test-target-package\n", stderr);
|
fputs("w6c: invalid --test-target-package\n", stderr);
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
if (testtarget != NULL) {
|
if (ti > 0 && strcmp(testtargets[ti - 1], testtarget) >= 0) {
|
||||||
|
fputs("w6c: --test-target-package paths must be sorted and unique\n",
|
||||||
|
stderr);
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
int direct = 0;
|
int direct = 0;
|
||||||
for (int i = 0; i < nimports; i++)
|
for (int i = 0; i < nimports; i++)
|
||||||
if (strcmp(imports[i].path, testtarget) == 0)
|
if (strcmp(imports[i].path, testtarget) == 0)
|
||||||
@@ -621,11 +628,11 @@ main(int argc, char **argv)
|
|||||||
if (bind_import_names(file->list, imports, nimports, file,
|
if (bind_import_names(file->list, imports, nimports, file,
|
||||||
testsupport) < 0)
|
testsupport) < 0)
|
||||||
return 1;
|
return 1;
|
||||||
if (testtarget != NULL) {
|
for (int ti = 0; ti < ntesttargets; ti++) {
|
||||||
int seen = 0;
|
int seen = 0;
|
||||||
for (Node *u = file->list; u; u = u->next) {
|
for (Node *u = file->list; u; u = u->next) {
|
||||||
if (u->kind != N_USE || u->imported || u->usepath == NULL
|
if (u->kind != N_USE || u->imported || u->usepath == NULL
|
||||||
|| strcmp(u->usepath, testtarget) != 0)
|
|| strcmp(u->usepath, testtargets[ti]) != 0)
|
||||||
continue;
|
continue;
|
||||||
u->str = u->usepath;
|
u->str = u->usepath;
|
||||||
u->strlen = strlen(u->usepath);
|
u->strlen = strlen(u->usepath);
|
||||||
@@ -646,7 +653,8 @@ main(int argc, char **argv)
|
|||||||
c.is_test = testmode;
|
c.is_test = testmode;
|
||||||
c.is_test_package = testpackage;
|
c.is_test_package = testpackage;
|
||||||
if (testsupport != NULL) c.test_module = testsupport;
|
if (testsupport != NULL) c.test_module = testsupport;
|
||||||
c.test_target = testtarget;
|
c.test_targets = testtargets;
|
||||||
|
c.n_test_targets = ntesttargets;
|
||||||
c.sep_mode = sepmode;
|
c.sep_mode = sepmode;
|
||||||
c.package_init_symbol = packageinit;
|
c.package_init_symbol = packageinit;
|
||||||
check_file(&c, file);
|
check_file(&c, file);
|
||||||
|
|||||||
@@ -2869,7 +2869,8 @@ check_init(Checker *c, Arena *a)
|
|||||||
c->is_test = 0; /* #15: caller (w6c main) sets it after init */
|
c->is_test = 0; /* #15: caller (w6c main) sets it after init */
|
||||||
c->is_test_package = 0;
|
c->is_test_package = 0;
|
||||||
c->test_module = "test";
|
c->test_module = "test";
|
||||||
c->test_target = NULL;
|
c->test_targets = NULL;
|
||||||
|
c->n_test_targets = 0;
|
||||||
typesinit(a);
|
typesinit(a);
|
||||||
c->top = newscope(a, NULL);
|
c->top = newscope(a, NULL);
|
||||||
c->cur = c->top;
|
c->cur = c->top;
|
||||||
@@ -3995,6 +3996,15 @@ check_import_usage_and_collisions(Checker *c, Node *file)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
check_test_target(const Checker *c, const char *path)
|
||||||
|
{
|
||||||
|
if (path == NULL) return 0;
|
||||||
|
for (int i = 0; i < c->n_test_targets; i++)
|
||||||
|
if (strcmp(c->test_targets[i], path) == 0) return 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
check_file(Checker *c, Node *file)
|
check_file(Checker *c, Node *file)
|
||||||
{
|
{
|
||||||
@@ -4018,8 +4028,7 @@ check_file(Checker *c, Node *file)
|
|||||||
&& !u->imported && u->sourceid == file->sourceid
|
&& !u->imported && u->sourceid == file->sourceid
|
||||||
&& u->usepath
|
&& u->usepath
|
||||||
&& (strcmp(u->usepath, c->test_module) == 0
|
&& (strcmp(u->usepath, c->test_module) == 0
|
||||||
|| (c->test_target != NULL
|
|| check_test_target(c, u->usepath)))
|
||||||
&& strcmp(u->usepath, c->test_target) == 0)))
|
|
||||||
u->used = 1;
|
u->used = 1;
|
||||||
if (u->kind == N_USE && !u->imported
|
if (u->kind == N_USE && !u->imported
|
||||||
&& u->sourceid == file->sourceid
|
&& u->sourceid == file->sourceid
|
||||||
@@ -4383,9 +4392,8 @@ check_file(Checker *c, Node *file)
|
|||||||
* package as `main`: that would collide with its own entry.
|
* package as `main`: that would collide with its own entry.
|
||||||
* This is a compiler-owned binding, never source alias syntax;
|
* This is a compiler-owned binding, never source alias syntax;
|
||||||
* use the canonical target path as its private qualifier. */
|
* use the canonical target path as its private qualifier. */
|
||||||
if (c->test_target != NULL
|
if (check_test_target(c, d->module))
|
||||||
&& strcmp(d->module, c->test_target) == 0)
|
alias = d->module;
|
||||||
alias = c->test_target;
|
|
||||||
id = newnode(c->a, N_DOT, fp);
|
id = newnode(c->a, N_DOT, fp);
|
||||||
id->lhs = newnode(c->a, N_IDENT, fp);
|
id->lhs = newnode(c->a, N_IDENT, fp);
|
||||||
id->lhs->str = alias;
|
id->lhs->str = alias;
|
||||||
|
|||||||
@@ -613,8 +613,8 @@ struct Checker {
|
|||||||
* bodies and export compiler-private metadata,
|
* bodies and export compiler-private metadata,
|
||||||
* but do not synthesize an entry. */
|
* but do not synthesize an entry. */
|
||||||
const char *test_module; /* generated dispatcher support qualifier */
|
const char *test_module; /* generated dispatcher support qualifier */
|
||||||
const char *test_target; /* canonical target path used only as the
|
const char **test_targets; /* canonical generated-main target paths */
|
||||||
* compiler-owned generated-main qualifier */
|
int n_test_targets;
|
||||||
int sep_mode; /* -c package compilation: imported interfaces are
|
int sep_mode; /* -c package compilation: imported interfaces are
|
||||||
* present, so absent members are hard export errors. */
|
* present, so absent members are hard export errors. */
|
||||||
Node *synth_test_run; /* exact compiler-generated support.run DOT;
|
Node *synth_test_run; /* exact compiler-generated support.run DOT;
|
||||||
|
|||||||
684
cmd/ww/main.c
684
cmd/ww/main.c
File diff suppressed because it is too large
Load Diff
@@ -24,7 +24,12 @@ type pkgfolder = struct {
|
|||||||
type pkggroup = struct {
|
type pkggroup = struct {
|
||||||
dir: str,
|
dir: str,
|
||||||
pkg: str,
|
pkg: str,
|
||||||
external: bool,
|
prodpkg: str,
|
||||||
|
samepkg: str,
|
||||||
|
externalpkg: str,
|
||||||
|
hassame: bool,
|
||||||
|
hasexternal: bool,
|
||||||
|
notests: bool,
|
||||||
production: bool,
|
production: bool,
|
||||||
plan: i32,
|
plan: i32,
|
||||||
root: str,
|
root: str,
|
||||||
@@ -1299,8 +1304,6 @@ fn pkglabel(g: *pkggroup) void = {
|
|||||||
pkgput(os.STDOUT_FILENO, g.dir);
|
pkgput(os.STDOUT_FILENO, g.dir);
|
||||||
pkgput(os.STDOUT_FILENO, " [");
|
pkgput(os.STDOUT_FILENO, " [");
|
||||||
pkgput(os.STDOUT_FILENO, g.pkg);
|
pkgput(os.STDOUT_FILENO, g.pkg);
|
||||||
if (g.external) { pkgput(os.STDOUT_FILENO, ", external"); }
|
|
||||||
else { pkgput(os.STDOUT_FILENO, ", same-package"); };
|
|
||||||
pkgput(os.STDOUT_FILENO, "]");
|
pkgput(os.STDOUT_FILENO, "]");
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1331,11 +1334,11 @@ fn pkgstartbuild(p: *pkgplan, groups: []pkggroup, builder: str, includes: []str,
|
|||||||
libdirs: []str, libs: []str, h: *exec.process) bool = {
|
libdirs: []str, libs: []str, h: *exec.process) bool = {
|
||||||
let nproducts: i32 = p.end - p.start;
|
let nproducts: i32 = p.end - p.start;
|
||||||
let capacity: i32 = 16;
|
let capacity: i32 = 16;
|
||||||
if (nproducts < 0 || nproducts > (PKG_COUNT_MAX - capacity) / 6) {
|
if (nproducts < 0 || nproducts > (PKG_COUNT_MAX - capacity) / 9) {
|
||||||
pkgputln(os.STDERR_FILENO, "wwtest package: package graph is too large");
|
pkgputln(os.STDERR_FILENO, "wwtest package: package graph is too large");
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
capacity += nproducts * 6;
|
capacity += nproducts * 9;
|
||||||
if (includes.len > (PKG_COUNT_MAX - capacity) / 2) {
|
if (includes.len > (PKG_COUNT_MAX - capacity) / 2) {
|
||||||
pkgputln(os.STDERR_FILENO, "wwtest package: package graph is too large");
|
pkgputln(os.STDERR_FILENO, "wwtest package: package graph is too large");
|
||||||
return false;
|
return false;
|
||||||
@@ -1379,11 +1382,15 @@ fn pkgstartbuild(p: *pkgplan, groups: []pkggroup, builder: str, includes: []str,
|
|||||||
for (i < p.end) {
|
for (i < p.end) {
|
||||||
let g: *pkggroup = &groups[i];
|
let g: *pkggroup = &groups[i];
|
||||||
append(ba, "--ww-package-test");
|
append(ba, "--ww-package-test");
|
||||||
if (g.production) { append(ba, "production"); }
|
if (p.buildonly) { append(ba, "build"); }
|
||||||
else { if (g.external) { append(ba, "external"); }
|
else { append(ba, "test"); };
|
||||||
else { append(ba, "same"); };
|
|
||||||
};
|
|
||||||
append(ba, g.pkg);
|
append(ba, g.pkg);
|
||||||
|
if (g.prodpkg.len != 0) { append(ba, g.prodpkg); }
|
||||||
|
else { append(ba, "-"); };
|
||||||
|
if (g.hassame) { append(ba, g.samepkg); }
|
||||||
|
else { append(ba, "-"); };
|
||||||
|
if (g.hasexternal) { append(ba, g.externalpkg); }
|
||||||
|
else { append(ba, "-"); };
|
||||||
append(ba, g.dir);
|
append(ba, g.dir);
|
||||||
append(ba, g.bin);
|
append(ba, g.bin);
|
||||||
append(ba, g.buildok);
|
append(ba, g.buildok);
|
||||||
@@ -1469,7 +1476,7 @@ fn pkgstartrun(g: *pkggroup, filters: []str, timeoutarg: str,
|
|||||||
};
|
};
|
||||||
|
|
||||||
fn pkgproductbuilt(g: *pkggroup, buildonly: bool) bool = {
|
fn pkgproductbuilt(g: *pkggroup, buildonly: bool) bool = {
|
||||||
if (buildonly) { return pkgisreg(g.buildok); };
|
if (buildonly || g.notests) { return pkgisreg(g.buildok); };
|
||||||
return pkgisreg(g.buildok) && pkgisreg(g.bin);
|
return pkgisreg(g.buildok) && pkgisreg(g.bin);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1480,6 +1487,12 @@ fn pkgrunok(g: *pkggroup) bool = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
fn pkgemitgroup(g: *pkggroup, compileonly: bool) bool = {
|
fn pkgemitgroup(g: *pkggroup, compileonly: bool) bool = {
|
||||||
|
if (g.notests) {
|
||||||
|
pkgput(os.STDOUT_FILENO, "? ");
|
||||||
|
pkgput(os.STDOUT_FILENO, g.dir);
|
||||||
|
pkgputln(os.STDOUT_FILENO, " [no tests]");
|
||||||
|
return true;
|
||||||
|
};
|
||||||
if (compileonly) {
|
if (compileonly) {
|
||||||
pkgput(os.STDOUT_FILENO, "built ");
|
pkgput(os.STDOUT_FILENO, "built ");
|
||||||
pkglabel(g);
|
pkglabel(g);
|
||||||
@@ -1494,15 +1507,6 @@ fn pkgemitgroup(g: *pkggroup, compileonly: bool) bool = {
|
|||||||
pkgfailpath(g.root, "cannot read test capture");
|
pkgfailpath(g.root, "cannot read test capture");
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
// The compiler-owned dispatcher is the authority on whether a variant
|
|
||||||
// contains runnable tests. With an empty generated table, test.run returns
|
|
||||||
// zero without output; no coordinator-side source scan is involved.
|
|
||||||
if (pkgrunok(g) && runstdout.len == 0 && runstderr.len == 0) {
|
|
||||||
pkgput(os.STDOUT_FILENO, "? ");
|
|
||||||
pkgput(os.STDOUT_FILENO, g.dir);
|
|
||||||
pkgputln(os.STDOUT_FILENO, " [no tests]");
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
pkgput(os.STDOUT_FILENO, runstdout);
|
pkgput(os.STDOUT_FILENO, runstdout);
|
||||||
pkgput(os.STDERR_FILENO, runstderr);
|
pkgput(os.STDERR_FILENO, runstderr);
|
||||||
if (!pkgrunok(g)) {
|
if (!pkgrunok(g)) {
|
||||||
@@ -1888,17 +1892,23 @@ export fn packagecommand(args: []str) int = {
|
|||||||
};
|
};
|
||||||
i = 0;
|
i = 0;
|
||||||
for (i < ds.paths.len) {
|
for (i < ds.paths.len) {
|
||||||
|
let s: pkgsource;
|
||||||
|
s.path = ds.paths[i];
|
||||||
|
if (!pkgstring(&s.dir, pkgdirname(ds.paths[i]))) { return 1; };
|
||||||
|
s.test = strings.hassuffix(pkgbase(ds.paths[i]), "_test.ww");
|
||||||
|
if (buildonly && s.test) {
|
||||||
|
s.pkg = "";
|
||||||
|
append(srcs, s);
|
||||||
|
i += 1;
|
||||||
|
continue;
|
||||||
|
};
|
||||||
let body: str;
|
let body: str;
|
||||||
let pn: str;
|
let pn: str;
|
||||||
if (!pkgread(ds.paths[i], &body) || !pkgclause(body, &pn)) {
|
if (!pkgread(ds.paths[i], &body) || !pkgclause(body, &pn)) {
|
||||||
pkgfailpath(ds.paths[i], "invalid or missing package clause");
|
pkgfailpath(ds.paths[i], "invalid or missing package clause");
|
||||||
return 1;
|
return 1;
|
||||||
};
|
};
|
||||||
let s: pkgsource;
|
if (!pkgstring(&s.pkg, pn)) { return 1; };
|
||||||
s.path = ds.paths[i];
|
|
||||||
if (!pkgstring(&s.dir, pkgdirname(ds.paths[i]))
|
|
||||||
|| !pkgstring(&s.pkg, pn)) { return 1; };
|
|
||||||
s.test = strings.hassuffix(pkgbase(ds.paths[i]), "_test.ww");
|
|
||||||
append(srcs, s);
|
append(srcs, s);
|
||||||
i += 1;
|
i += 1;
|
||||||
};
|
};
|
||||||
@@ -1948,7 +1958,12 @@ export fn packagecommand(args: []str) int = {
|
|||||||
let g: pkggroup;
|
let g: pkggroup;
|
||||||
g.dir = f.path;
|
g.dir = f.path;
|
||||||
g.pkg = f.prodpkg;
|
g.pkg = f.prodpkg;
|
||||||
g.external = false;
|
g.prodpkg = f.prodpkg;
|
||||||
|
g.samepkg = "";
|
||||||
|
g.externalpkg = "";
|
||||||
|
g.hassame = false;
|
||||||
|
g.hasexternal = false;
|
||||||
|
g.notests = false;
|
||||||
g.production = true;
|
g.production = true;
|
||||||
append(groups, g);
|
append(groups, g);
|
||||||
} else {
|
} else {
|
||||||
@@ -1970,64 +1985,110 @@ export fn packagecommand(args: []str) int = {
|
|||||||
i += 1;
|
i += 1;
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
|
let family: str = f.prodpkg;
|
||||||
|
let samepkg: str = "";
|
||||||
let externalpkg: str = "";
|
let externalpkg: str = "";
|
||||||
if (f.prodpkg.len != 0) {
|
let hassame: bool = false;
|
||||||
if (!pkgstring(&externalpkg, f.prodpkg, "_test")) { return 1; };
|
let hasexternal: bool = false;
|
||||||
};
|
|
||||||
let standalonepkg: str = "";
|
|
||||||
let sawtestfile: bool = false;
|
let sawtestfile: bool = false;
|
||||||
|
if (f.prodpkg.len != 0) {
|
||||||
|
let expectedexternal: str;
|
||||||
|
if (!pkgstring(&expectedexternal, f.prodpkg, "_test")) {
|
||||||
|
return 1;
|
||||||
|
};
|
||||||
let j: i32 = f.start;
|
let j: i32 = f.start;
|
||||||
for (j < f.end) {
|
for (j < f.end) {
|
||||||
if (srcs[j].test) {
|
if (srcs[j].test) {
|
||||||
sawtestfile = true;
|
sawtestfile = true;
|
||||||
if (f.prodpkg.len != 0
|
if (strings.compare(srcs[j].pkg, f.prodpkg) == 0) {
|
||||||
&& strings.compare(srcs[j].pkg, f.prodpkg) != 0
|
hassame = true;
|
||||||
&& strings.compare(srcs[j].pkg, externalpkg) != 0) {
|
samepkg = srcs[j].pkg;
|
||||||
|
} else if (strings.compare(srcs[j].pkg,
|
||||||
|
expectedexternal) == 0) {
|
||||||
|
hasexternal = true;
|
||||||
|
externalpkg = srcs[j].pkg;
|
||||||
|
} else {
|
||||||
pkgfailpath(srcs[j].path,
|
pkgfailpath(srcs[j].path,
|
||||||
"test package must match production package or <package>_test");
|
"test package must match production package or <package>_test");
|
||||||
return 1;
|
return 1;
|
||||||
};
|
};
|
||||||
if (f.prodpkg.len == 0) {
|
};
|
||||||
if (standalonepkg.len == 0) {
|
j += 1;
|
||||||
standalonepkg = srcs[j].pkg;
|
};
|
||||||
} else if (strings.compare(standalonepkg,
|
} else {
|
||||||
srcs[j].pkg) != 0) {
|
let firstpkg: str = "";
|
||||||
pkgfailpath(f.path,
|
let secondpkg: str = "";
|
||||||
"test-only directory declares conflicting packages");
|
let j: i32 = f.start;
|
||||||
|
for (j < f.end) {
|
||||||
|
if (srcs[j].test) {
|
||||||
|
sawtestfile = true;
|
||||||
|
if (firstpkg.len == 0) {
|
||||||
|
firstpkg = srcs[j].pkg;
|
||||||
|
} else if (strings.compare(srcs[j].pkg, firstpkg) != 0
|
||||||
|
&& secondpkg.len == 0) {
|
||||||
|
secondpkg = srcs[j].pkg;
|
||||||
|
} else if (strings.compare(srcs[j].pkg, firstpkg) != 0
|
||||||
|
&& strings.compare(srcs[j].pkg, secondpkg) != 0) {
|
||||||
|
pkgfailpath(srcs[j].path,
|
||||||
|
"test package must match production package or <package>_test");
|
||||||
return 1;
|
return 1;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
let found: bool = false;
|
|
||||||
let k: i32 = 0;
|
|
||||||
for (k < groups.len) {
|
|
||||||
if (strings.compare(groups[k].dir, f.path) == 0
|
|
||||||
&& strings.compare(groups[k].pkg, srcs[j].pkg) == 0) {
|
|
||||||
found = true;
|
|
||||||
break;
|
|
||||||
};
|
|
||||||
k += 1;
|
|
||||||
};
|
|
||||||
if (!found) {
|
|
||||||
let g: pkggroup;
|
|
||||||
g.dir = f.path;
|
|
||||||
g.pkg = srcs[j].pkg;
|
|
||||||
g.external = f.prodpkg.len != 0
|
|
||||||
&& strings.compare(f.prodpkg, g.pkg) != 0;
|
|
||||||
g.production = false;
|
|
||||||
append(groups, g);
|
|
||||||
};
|
|
||||||
};
|
|
||||||
j += 1;
|
j += 1;
|
||||||
};
|
};
|
||||||
if (!sawtestfile) {
|
if (secondpkg.len == 0) {
|
||||||
|
if (strings.hassuffix(firstpkg, "_test")) {
|
||||||
|
family = firstpkg[0:(firstpkg.len - 5)];
|
||||||
|
if (family.len == 0) {
|
||||||
|
pkgfailpath(f.path,
|
||||||
|
"external test package has empty base name");
|
||||||
|
return 1;
|
||||||
|
};
|
||||||
|
hasexternal = true;
|
||||||
|
externalpkg = firstpkg;
|
||||||
|
} else {
|
||||||
|
family = firstpkg;
|
||||||
|
hassame = true;
|
||||||
|
samepkg = firstpkg;
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
let firstexternal: str;
|
||||||
|
let secondexternal: str;
|
||||||
|
if (!pkgstring(&firstexternal, firstpkg, "_test")
|
||||||
|
|| !pkgstring(&secondexternal, secondpkg, "_test")) {
|
||||||
|
return 1;
|
||||||
|
};
|
||||||
|
if (strings.compare(secondpkg, firstexternal) == 0) {
|
||||||
|
family = firstpkg;
|
||||||
|
hassame = true;
|
||||||
|
samepkg = firstpkg;
|
||||||
|
hasexternal = true;
|
||||||
|
externalpkg = secondpkg;
|
||||||
|
} else if (strings.compare(firstpkg, secondexternal) == 0) {
|
||||||
|
family = secondpkg;
|
||||||
|
hassame = true;
|
||||||
|
samepkg = secondpkg;
|
||||||
|
hasexternal = true;
|
||||||
|
externalpkg = firstpkg;
|
||||||
|
} else {
|
||||||
|
pkgfailpath(f.path,
|
||||||
|
"test package must match production package or <package>_test");
|
||||||
|
return 1;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
let g: pkggroup;
|
let g: pkggroup;
|
||||||
g.dir = f.path;
|
g.dir = f.path;
|
||||||
g.pkg = f.prodpkg;
|
g.pkg = family;
|
||||||
if (g.pkg.len == 0) { g.pkg = srcs[f.start].pkg; };
|
if (g.pkg.len == 0) { g.pkg = srcs[f.start].pkg; };
|
||||||
g.external = false;
|
g.prodpkg = f.prodpkg;
|
||||||
g.production = true;
|
g.samepkg = samepkg;
|
||||||
|
g.externalpkg = externalpkg;
|
||||||
|
g.hassame = hassame;
|
||||||
|
g.hasexternal = hasexternal;
|
||||||
|
g.notests = !sawtestfile;
|
||||||
|
g.production = f.prodpkg.len != 0;
|
||||||
append(groups, g);
|
append(groups, g);
|
||||||
};
|
|
||||||
i += 1;
|
i += 1;
|
||||||
};
|
};
|
||||||
if (groups.len == 0) {
|
if (groups.len == 0) {
|
||||||
@@ -2225,6 +2286,9 @@ export fn packagecommand(args: []str) int = {
|
|||||||
if (!pkgproductbuilt(g, buildonly)) {
|
if (!pkgproductbuilt(g, buildonly)) {
|
||||||
g.state = PKGDONE;
|
g.state = PKGDONE;
|
||||||
productcompleted += 1;
|
productcompleted += 1;
|
||||||
|
} else if (g.notests) {
|
||||||
|
g.state = PKGDONE;
|
||||||
|
productcompleted += 1;
|
||||||
} else {
|
} else {
|
||||||
if (!pkgstartrun(g, filters, timeoutarg, list,
|
if (!pkgstartrun(g, filters, timeoutarg, list,
|
||||||
&runhandles[gi])) {
|
&runhandles[gi])) {
|
||||||
|
|||||||
@@ -327,6 +327,11 @@ fn allocimportptrs(count: i32) ([]*u8 | nomem) = {
|
|||||||
return value;
|
return value;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
fn allocimportstrs(count: i32) ([]str | nomem) = {
|
||||||
|
let value: []str = alloc([], count: u64)?;
|
||||||
|
return value;
|
||||||
|
};
|
||||||
|
|
||||||
fn allocnodeptrs(count: i32) ([]*syntax.node | nomem) = {
|
fn allocnodeptrs(count: i32) ([]*syntax.node | nomem) = {
|
||||||
let value: []*syntax.node = alloc([], count: u64)?;
|
let value: []*syntax.node = alloc([], count: u64)?;
|
||||||
return value;
|
return value;
|
||||||
@@ -457,7 +462,6 @@ export fn main(argc: i32, argv: **u8) i32 = {
|
|||||||
let out: *u8 = nil;
|
let out: *u8 = nil;
|
||||||
let wwiout: *u8 = nil; // -I <out.wwi>: M2 export-data producer
|
let wwiout: *u8 = nil; // -I <out.wwi>: M2 export-data producer
|
||||||
let testsupport: *u8 = nil;
|
let testsupport: *u8 = nil;
|
||||||
let testtarget: *u8 = nil;
|
|
||||||
let testmode: i32 = 0i32; // #15: `-T` test-mode
|
let testmode: i32 = 0i32; // #15: `-T` test-mode
|
||||||
let testpackage: i32 = 0i32;
|
let testpackage: i32 = 0i32;
|
||||||
let commandpackage: i32 = 0i32;
|
let commandpackage: i32 = 0i32;
|
||||||
@@ -469,8 +473,10 @@ export fn main(argc: i32, argv: **u8) i32 = {
|
|||||||
// only; treat `.wwi` deps as external)
|
// only; treat `.wwi` deps as external)
|
||||||
let pathallocation: ([]*u8 | nomem) = allocimportptrs(argc);
|
let pathallocation: ([]*u8 | nomem) = allocimportptrs(argc);
|
||||||
let fileallocation: ([]*u8 | nomem) = allocimportptrs(argc);
|
let fileallocation: ([]*u8 | nomem) = allocimportptrs(argc);
|
||||||
|
let targetallocation: ([]str | nomem) = allocimportstrs(argc);
|
||||||
let importpaths: []*u8;
|
let importpaths: []*u8;
|
||||||
let importfiles: []*u8;
|
let importfiles: []*u8;
|
||||||
|
let testtargets: []str;
|
||||||
let astallocation: ([]*syntax.node | nomem) = allocnodeptrs(argc);
|
let astallocation: ([]*syntax.node | nomem) = allocnodeptrs(argc);
|
||||||
let importasts: []*syntax.node;
|
let importasts: []*syntax.node;
|
||||||
match (pathallocation) {
|
match (pathallocation) {
|
||||||
@@ -491,6 +497,15 @@ export fn main(argc: i32, argv: **u8) i32 = {
|
|||||||
};
|
};
|
||||||
importpaths.len = argc;
|
importpaths.len = argc;
|
||||||
importfiles.len = argc;
|
importfiles.len = argc;
|
||||||
|
match (targetallocation) {
|
||||||
|
case let value: []str => testtargets = value;
|
||||||
|
case nomem => {
|
||||||
|
let m: str = "w6c: out of memory\n";
|
||||||
|
os.write(2, m.ptr, m.len: u64);
|
||||||
|
return 1;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
testtargets.len = argc;
|
||||||
match (astallocation) {
|
match (astallocation) {
|
||||||
case let value: []*syntax.node => importasts = value;
|
case let value: []*syntax.node => importasts = value;
|
||||||
case nomem => {
|
case nomem => {
|
||||||
@@ -501,6 +516,7 @@ export fn main(argc: i32, argv: **u8) i32 = {
|
|||||||
};
|
};
|
||||||
importasts.len = argc;
|
importasts.len = argc;
|
||||||
let nimports: i32 = 0;
|
let nimports: i32 = 0;
|
||||||
|
let ntesttargets: i32 = 0;
|
||||||
let mapallocation: ([]importmap | nomem) = allocimportmaps(argc);
|
let mapallocation: ([]importmap | nomem) = allocimportmaps(argc);
|
||||||
let importmaps: []importmap;
|
let importmaps: []importmap;
|
||||||
match (mapallocation) {
|
match (mapallocation) {
|
||||||
@@ -572,7 +588,8 @@ export fn main(argc: i32, argv: **u8) i32 = {
|
|||||||
os.write(2, m.ptr, m.len: u64);
|
os.write(2, m.ptr, m.len: u64);
|
||||||
return 2;
|
return 2;
|
||||||
};
|
};
|
||||||
testtarget = argv[i];
|
testtargets[ntesttargets] = pathstr(argv[i]);
|
||||||
|
ntesttargets += 1;
|
||||||
} else { if (cstreq(a, "-c")) {
|
} else { if (cstreq(a, "-c")) {
|
||||||
sepmode = 1i32;
|
sepmode = 1i32;
|
||||||
} else { if (cstreq(a, "--import")) {
|
} else { if (cstreq(a, "--import")) {
|
||||||
@@ -711,17 +728,24 @@ export fn main(argc: i32, argv: **u8) i32 = {
|
|||||||
os.write(2, m.ptr, m.len: u64);
|
os.write(2, m.ptr, m.len: u64);
|
||||||
return 2;
|
return 2;
|
||||||
};
|
};
|
||||||
if (testtarget != nil && (sepmode == 0 || testmode == 0
|
let targeti: i32 = 0;
|
||||||
|| testtarget[0u64] == 0u8)) {
|
for (targeti < ntesttargets) {
|
||||||
|
let testtarget: str = testtargets[targeti];
|
||||||
|
if (sepmode == 0 || testmode == 0 || testtarget.len == 0) {
|
||||||
let m: str = "w6c: invalid --test-target-package\n";
|
let m: str = "w6c: invalid --test-target-package\n";
|
||||||
os.write(2, m.ptr, m.len: u64);
|
os.write(2, m.ptr, m.len: u64);
|
||||||
return 2;
|
return 2;
|
||||||
};
|
};
|
||||||
if (testtarget != nil) {
|
if (targeti > 0
|
||||||
|
&& strings.compare(testtargets[targeti - 1], testtarget) >= 0) {
|
||||||
|
let m: str = "w6c: --test-target-package paths must be sorted and unique\n";
|
||||||
|
os.write(2, m.ptr, m.len: u64);
|
||||||
|
return 2;
|
||||||
|
};
|
||||||
let direct: bool = false;
|
let direct: bool = false;
|
||||||
importi = 0;
|
importi = 0;
|
||||||
for (importi < nimports) {
|
for (importi < nimports) {
|
||||||
if (cstreq(importpaths[importi], pathstr(testtarget))) {
|
if (syntax.streq(pathstr(importpaths[importi]), testtarget)) {
|
||||||
direct = true;
|
direct = true;
|
||||||
};
|
};
|
||||||
importi += 1;
|
importi += 1;
|
||||||
@@ -731,6 +755,7 @@ export fn main(argc: i32, argv: **u8) i32 = {
|
|||||||
os.write(2, m.ptr, m.len: u64);
|
os.write(2, m.ptr, m.len: u64);
|
||||||
return 2;
|
return 2;
|
||||||
};
|
};
|
||||||
|
targeti += 1;
|
||||||
};
|
};
|
||||||
|
|
||||||
let importhead: *syntax.node = nil;
|
let importhead: *syntax.node = nil;
|
||||||
@@ -848,13 +873,14 @@ export fn main(argc: i32, argv: **u8) i32 = {
|
|||||||
testsupport)) {
|
testsupport)) {
|
||||||
return 1;
|
return 1;
|
||||||
};
|
};
|
||||||
if (testtarget != nil) {
|
targeti = 0;
|
||||||
|
for (targeti < ntesttargets) {
|
||||||
let seen: i32 = 0;
|
let seen: i32 = 0;
|
||||||
let targetuse: *syntax.node = f.list;
|
let targetuse: *syntax.node = f.list;
|
||||||
for (targetuse != nil) {
|
for (targetuse != nil) {
|
||||||
if (targetuse.kind == syntax.nkind.N_USE
|
if (targetuse.kind == syntax.nkind.N_USE
|
||||||
&& targetuse.imported == 0
|
&& targetuse.imported == 0
|
||||||
&& syntax.streq(targetuse.usepath, pathstr(testtarget))) {
|
&& syntax.streq(targetuse.usepath, testtargets[targeti])) {
|
||||||
targetuse.str = targetuse.usepath;
|
targetuse.str = targetuse.usepath;
|
||||||
seen += 1;
|
seen += 1;
|
||||||
};
|
};
|
||||||
@@ -865,6 +891,7 @@ export fn main(argc: i32, argv: **u8) i32 = {
|
|||||||
os.write(2, m.ptr, m.len: u64);
|
os.write(2, m.ptr, m.len: u64);
|
||||||
return 2;
|
return 2;
|
||||||
};
|
};
|
||||||
|
targeti += 1;
|
||||||
};
|
};
|
||||||
if (importhead != nil) {
|
if (importhead != nil) {
|
||||||
importtail.next = f.list;
|
importtail.next = f.list;
|
||||||
@@ -896,8 +923,7 @@ export fn main(argc: i32, argv: **u8) i32 = {
|
|||||||
|
|
||||||
let testmodule: str;
|
let testmodule: str;
|
||||||
if (testsupport != nil) { testmodule = pathstr(testsupport); };
|
if (testsupport != nil) { testmodule = pathstr(testsupport); };
|
||||||
let testtargetmodule: str;
|
testtargets.len = ntesttargets;
|
||||||
if (testtarget != nil) { testtargetmodule = pathstr(testtarget); };
|
|
||||||
let packageinitsymbol: str;
|
let packageinitsymbol: str;
|
||||||
if (packageinit != nil) { packageinitsymbol = pathstr(packageinit); };
|
if (packageinit != nil) { packageinitsymbol = pathstr(packageinit); };
|
||||||
let initdispatchsymbol: str;
|
let initdispatchsymbol: str;
|
||||||
@@ -905,7 +931,7 @@ export fn main(argc: i32, argv: **u8) i32 = {
|
|||||||
let haswwi: i32 = 0;
|
let haswwi: i32 = 0;
|
||||||
if (wwiout != nil) { haswwi = 1; };
|
if (wwiout != nil) { haswwi = 1; };
|
||||||
let compilerc: i32 = wcc.compilefile(f, testmode, testpackage, testmodule,
|
let compilerc: i32 = wcc.compilefile(f, testmode, testpackage, testmodule,
|
||||||
testtargetmodule, sepmode, wwifd, haswwi, entrymode,
|
testtargets, sepmode, wwifd, haswwi, entrymode,
|
||||||
packageinitsymbol, initdispatchsymbol);
|
packageinitsymbol, initdispatchsymbol);
|
||||||
if (out != nil) { os.close(1i32); };
|
if (out != nil) { os.close(1i32); };
|
||||||
if (compilerc != 0) {
|
if (compilerc != 0) {
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ package wcc;
|
|||||||
import syntax;
|
import syntax;
|
||||||
|
|
||||||
export fn compilefile(file: *syntax.node, testmode: i32, testpackage: i32,
|
export fn compilefile(file: *syntax.node, testmode: i32, testpackage: i32,
|
||||||
testmodule: str, testtarget: str, sepmode: i32, wwifd: i32,
|
testmodule: str, testtargets: []str, sepmode: i32, wwifd: i32,
|
||||||
haswwi: i32,
|
haswwi: i32,
|
||||||
entrymode: i32, packageinitsymbol: str, initdispatchsymbol: str) i32 = {
|
entrymode: i32, packageinitsymbol: str, initdispatchsymbol: str) i32 = {
|
||||||
let tc: syntax.tctx;
|
let tc: syntax.tctx;
|
||||||
@@ -13,7 +13,7 @@ export fn compilefile(file: *syntax.node, testmode: i32, testpackage: i32,
|
|||||||
ck.istest = testmode;
|
ck.istest = testmode;
|
||||||
ck.istestpackage = testpackage;
|
ck.istestpackage = testpackage;
|
||||||
if (testmodule.len > 0) { ck.testmodule = testmodule; };
|
if (testmodule.len > 0) { ck.testmodule = testmodule; };
|
||||||
ck.testtarget = testtarget;
|
ck.testtargets = testtargets;
|
||||||
ck.sepmode = sepmode;
|
ck.sepmode = sepmode;
|
||||||
ck.packageinitsymbol = packageinitsymbol;
|
ck.packageinitsymbol = packageinitsymbol;
|
||||||
checkfile(&ck, file);
|
checkfile(&ck, file);
|
||||||
|
|||||||
@@ -23,8 +23,8 @@ type checker = struct {
|
|||||||
istestpackage: i32, // validate/retain package-owned @test bodies and
|
istestpackage: i32, // validate/retain package-owned @test bodies and
|
||||||
// export compiler-private metadata; no entry synth
|
// export compiler-private metadata; no entry synth
|
||||||
testmodule: str, // generated dispatcher support qualifier
|
testmodule: str, // generated dispatcher support qualifier
|
||||||
testtarget: str, // canonical target path used only as the
|
testtargets: []str, // canonical generated-main target paths used only as
|
||||||
// compiler-owned generated-main qualifier
|
// compiler-owned generated-main qualifiers
|
||||||
sepmode: i32, // -c package compilation: imported interfaces are
|
sepmode: i32, // -c package compilation: imported interfaces are
|
||||||
// present, so absent members are hard export errors.
|
// present, so absent members are hard export errors.
|
||||||
synthtestrun: *syntax.node, // exact generated support.run DOT; its
|
synthtestrun: *syntax.node, // exact generated support.run DOT; its
|
||||||
@@ -8507,8 +8507,8 @@ fn checkinit(c: *checker, tc: *syntax.tctx) void = {
|
|||||||
c.istest = 0i32; // #15: caller (w6c main) sets it after init
|
c.istest = 0i32; // #15: caller (w6c main) sets it after init
|
||||||
c.istestpackage = 0i32;
|
c.istestpackage = 0i32;
|
||||||
c.testmodule = "test";
|
c.testmodule = "test";
|
||||||
let emptytesttarget: str;
|
let emptytesttargets: []str;
|
||||||
c.testtarget = emptytesttarget;
|
c.testtargets = emptytesttargets;
|
||||||
c.sepmode = 0i32; // caller (w6c main) sets it from -c
|
c.sepmode = 0i32; // caller (w6c main) sets it from -c
|
||||||
c.synthtestrun = nil;
|
c.synthtestrun = nil;
|
||||||
c.verbose = 0;
|
c.verbose = 0;
|
||||||
@@ -8524,6 +8524,15 @@ fn checkinit(c: *checker, tc: *syntax.tctx) void = {
|
|||||||
seedprimitives(c);
|
seedprimitives(c);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
fn checktesttarget(c: *checker, path: str) bool = {
|
||||||
|
let i: i32 = 0;
|
||||||
|
for (i < c.testtargets.len) {
|
||||||
|
if (syntax.streq(c.testtargets[i], path)) { return true; };
|
||||||
|
i += 1;
|
||||||
|
};
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
fn checkfile(c: *checker, file: *syntax.node) void = {
|
fn checkfile(c: *checker, file: *syntax.node) void = {
|
||||||
if (file == nil) { return; };
|
if (file == nil) { return; };
|
||||||
if (file.kind != syntax.nkind.N_FILE) { return; };
|
if (file.kind != syntax.nkind.N_FILE) { return; };
|
||||||
@@ -8547,8 +8556,7 @@ fn checkfile(c: *checker, file: *syntax.node) void = {
|
|||||||
if (su.kind == syntax.nkind.N_USE
|
if (su.kind == syntax.nkind.N_USE
|
||||||
&& su.imported == 0 && su.sourceid == file.sourceid
|
&& su.imported == 0 && su.sourceid == file.sourceid
|
||||||
&& (syntax.streq(su.usepath, c.testmodule)
|
&& (syntax.streq(su.usepath, c.testmodule)
|
||||||
|| (c.testtarget.len > 0
|
|| checktesttarget(c, su.usepath))) {
|
||||||
&& syntax.streq(su.usepath, c.testtarget)))) {
|
|
||||||
su.used = 1i32;
|
su.used = 1i32;
|
||||||
};
|
};
|
||||||
if (su.kind == syntax.nkind.N_USE && su.imported == 0
|
if (su.kind == syntax.nkind.N_USE && su.imported == 0
|
||||||
@@ -8719,9 +8727,8 @@ fn checkfile(c: *checker, file: *syntax.node) void = {
|
|||||||
if (t.imported != 0 && t.nmod.len > 0) {
|
if (t.imported != 0 && t.nmod.len > 0) {
|
||||||
let alias: str = t.pkgname;
|
let alias: str = t.pkgname;
|
||||||
if (alias.len == 0) { alias = t.nmod; };
|
if (alias.len == 0) { alias = t.nmod; };
|
||||||
if (c.testtarget.len > 0
|
if (checktesttarget(c, t.nmod)) {
|
||||||
&& syntax.streq(t.nmod, c.testtarget)) {
|
alias = t.nmod;
|
||||||
alias = c.testtarget;
|
|
||||||
};
|
};
|
||||||
id = syntax.newnode(syntax.nkind.N_DOT, pf, pl, pc);
|
id = syntax.newnode(syntax.nkind.N_DOT, pf, pl, pc);
|
||||||
id.lhs = syntax.newnode(syntax.nkind.N_IDENT, pf, pl, pc);
|
id.lhs = syntax.newnode(syntax.nkind.N_IDENT, pf, pl, pc);
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -148,7 +148,8 @@ export fn main(argc: i32, argv: **u8) i32 = {
|
|||||||
// silently). Mirrors w6c main.ww:162 / cmd/w6c/main.c.
|
// silently). Mirrors w6c main.ww:162 / cmd/w6c/main.c.
|
||||||
if (l.errs > 0 || ps.errs > 0) { return 1; };
|
if (l.errs > 0 || ps.errs > 0) { return 1; };
|
||||||
let empty: str;
|
let empty: str;
|
||||||
if (wcc.compilefile(f, 0, 0, empty, empty, 0, -1, 0, 0,
|
let emptytargets: []str;
|
||||||
|
if (wcc.compilefile(f, 0, 0, empty, emptytargets, 0, -1, 0, 0,
|
||||||
empty, empty) != 0) { return 1; };
|
empty, empty) != 0) { return 1; };
|
||||||
};};};};
|
};};};};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user