compiler: support package test runtime aliases
This commit is contained in:
@@ -28,6 +28,7 @@ main(int argc, char **argv)
|
||||
const char *src = NULL;
|
||||
const char *out = NULL;
|
||||
const char *wwiout = NULL; /* -I <out.wwi>: M2 export-data producer */
|
||||
const char *testsupport = NULL;
|
||||
int testmode = 0;
|
||||
int sepmode = 0; /* -c: #22 M3 separate-compile / primary-
|
||||
* only codegen (emit imported==0 decls
|
||||
@@ -40,6 +41,12 @@ main(int argc, char **argv)
|
||||
wwiout = argv[++i];
|
||||
} else if (strcmp(a, "-T") == 0) {
|
||||
testmode = 1;
|
||||
} else if (strcmp(a, "--test-support-module") == 0) {
|
||||
if (i + 1 >= argc) {
|
||||
fputs("w6c: --test-support-module requires arg\n", stderr);
|
||||
return 2;
|
||||
}
|
||||
testsupport = argv[++i];
|
||||
} else if (strcmp(a, "-c") == 0) {
|
||||
sepmode = 1;
|
||||
} else if (a[0] == '-') {
|
||||
@@ -56,6 +63,12 @@ main(int argc, char **argv)
|
||||
fputs("usage: w6c [-T] [-c] [-I out.wwi] [-o out.s] file.ww\n", stderr);
|
||||
return 2;
|
||||
}
|
||||
if (testsupport != NULL && (!sepmode
|
||||
|| (strcmp(testsupport, "test") != 0
|
||||
&& strcmp(testsupport, "__wwtest") != 0))) {
|
||||
fputs("w6c: invalid --test-support-module\n", stderr);
|
||||
return 2;
|
||||
}
|
||||
|
||||
char *buf;
|
||||
u64 len;
|
||||
@@ -72,11 +85,13 @@ main(int argc, char **argv)
|
||||
|
||||
lexinit(&l, a, src, buf, len);
|
||||
parserinit(&p, a, &l);
|
||||
p.testmodule = testsupport;
|
||||
Node *file = parsefile(&p);
|
||||
if (l.errs || p.errs) return 1;
|
||||
|
||||
check_init(&c, a);
|
||||
c.is_test = testmode;
|
||||
if (testsupport != NULL) c.test_module = testsupport;
|
||||
c.sep_mode = sepmode;
|
||||
check_file(&c, file);
|
||||
if (c.errs) return 1;
|
||||
|
||||
@@ -1483,7 +1483,7 @@ cexpr(Checker *c, Node *n)
|
||||
if (fs)
|
||||
return n->type = fs->type;
|
||||
/* A bare `w6c -T` intentionally leaves the
|
||||
* compiler-generated test.run hook external; the
|
||||
* compiler-generated support.run hook external; the
|
||||
* ordinary driver supplies lib/test. This is the only
|
||||
* missing direct member that is not a package export
|
||||
* error. */
|
||||
@@ -2843,6 +2843,7 @@ check_init(Checker *c, Arena *a)
|
||||
memset(c, 0, sizeof *c);
|
||||
c->a = a;
|
||||
c->is_test = 0; /* #15: caller (w6c main) sets it after init */
|
||||
c->test_module = "test";
|
||||
typesinit(a);
|
||||
c->top = newscope(a, NULL);
|
||||
c->cur = c->top;
|
||||
@@ -3120,20 +3121,19 @@ check_file(Checker *c, Node *file)
|
||||
if (file == NULL || file->kind != N_FILE) return;
|
||||
c->file = file;
|
||||
|
||||
/* #80: under -T, PREPEND the synth `use test;` BEFORE pass 1 so decl_mod
|
||||
* (called per-decl during install) sees a matching `use test` when it
|
||||
* keys lib/test's `run` — keying it under module="test", not "". A pure
|
||||
/* Under -T, prepend the dispatcher support import before pass 1 so
|
||||
* decl_mod keys the runner under the selected support module. A pure
|
||||
* ORDER fix: the synth N_USE was appended AFTER install (below), too late
|
||||
* for decl_mod, so `run` keyed under "" — leaving the synth `test.run`
|
||||
* for decl_mod, so `run` keyed under "" — leaving the qualified call
|
||||
* ty_err (the E1 bridge) and colliding with a user root `fn run` (also
|
||||
* module=""). Decoupled from cgen: the symbol mangle keys off d->module
|
||||
* (the //ww:module directive, mod_collect), NOT this scope keying — cgen
|
||||
* already emits the correct CALL test.run. wwstage twin in check.ww. */
|
||||
* already emits the qualified call. wwstage twin in check.ww. */
|
||||
if (c->is_test) {
|
||||
Node *usenode = newnode(c->a, N_USE, file->pos);
|
||||
usenode->str = "test";
|
||||
usenode->strlen = 4;
|
||||
usenode->usepath = "test";
|
||||
usenode->str = c->test_module;
|
||||
usenode->strlen = strlen(c->test_module);
|
||||
usenode->usepath = c->test_module;
|
||||
usenode->next = file->list;
|
||||
file->list = usenode;
|
||||
}
|
||||
@@ -3506,21 +3506,18 @@ check_file(Checker *c, Node *file)
|
||||
scope_define_in_module(c->cur, tab->str, NULL, SK_VAR,
|
||||
tt, tab);
|
||||
|
||||
/* return test.run(__wwtests);
|
||||
* QUALIFIED, not bare `run`: under the sep producer
|
||||
* lib/test is a real imported package, so the call must
|
||||
* carry the `test` module qualifier (N_DOT base ident
|
||||
* `test`, member `run`). The combined path tags the
|
||||
* auto-bundled lib/test `//ww:module test` too, so the
|
||||
* qualified form resolves+mangles identically there
|
||||
* (test.run either way) — byte-neutral. The base ident
|
||||
* resolves through a synthetic N_USE injected below. */
|
||||
/* Return support.run(__wwtests).
|
||||
* QUALIFIED, not bare `run`: under the sep producer the
|
||||
* toolchain test runtime is a real imported package. The
|
||||
* selected module is normally `test`, or the reserved alias
|
||||
* chosen by the package driver when user source owns `test`.
|
||||
* The base ident resolves through the synthetic N_USE. */
|
||||
Node *arg = newnode(c->a, N_IDENT, fp);
|
||||
arg->str = "__wwtests";
|
||||
Node *call = newnode(c->a, N_CALL, fp);
|
||||
Node *dot = newnode(c->a, N_DOT, fp);
|
||||
dot->lhs = newnode(c->a, N_IDENT, fp);
|
||||
dot->lhs->str = "test";
|
||||
dot->lhs->str = c->test_module;
|
||||
dot->str = "run";
|
||||
c->synth_test_run = dot;
|
||||
call->lhs = dot;
|
||||
@@ -3528,11 +3525,11 @@ check_file(Checker *c, Node *file)
|
||||
Node *ret = newnode(c->a, N_RETURN, fp);
|
||||
ret->lhs = call;
|
||||
body->list = ret;
|
||||
/* #80: the synth `use test;` (the N_DOT base qualifier +
|
||||
* the use_path source mapping `test`→its path) is now
|
||||
/* The synthetic support use (the N_DOT base qualifier plus
|
||||
* its use_path source mapping) is now
|
||||
* PREPENDED before pass 1 at the top of check_file, so
|
||||
* decl_mod keys lib/test's `run` under "test" and the synth
|
||||
* `test.run` type-resolves. Pass 1's N_USE arm installs it
|
||||
* decl_mod keys the runtime's `run` under the selected module
|
||||
* and the synthesized call type-resolves. Pass 1 installs it
|
||||
* (SK_USE). */
|
||||
}
|
||||
|
||||
|
||||
@@ -1571,7 +1571,11 @@ parsefile(Parser *p)
|
||||
p->pathmod ? p->pathmod : p->resetmod;
|
||||
const char *dot = strrchr(active, '.');
|
||||
const char *last = dot ? dot + 1 : active;
|
||||
if (strcmp(name, last) != 0) {
|
||||
int testsupport = p->testmodule != NULL
|
||||
&& strcmp(p->testmodule, "__wwtest") == 0
|
||||
&& strcmp(active, "__wwtest") == 0
|
||||
&& strcmp(name, "test") == 0;
|
||||
if (strcmp(name, last) != 0 && !testsupport) {
|
||||
errorf(p->cur.pos,
|
||||
"package %s does not match import path %s",
|
||||
name, active);
|
||||
|
||||
@@ -379,6 +379,8 @@ struct Parser {
|
||||
* bare-main rule stay intact), and the in-file
|
||||
* `package` clause asserts (leaf == last
|
||||
* component) instead of overwriting curmod. */
|
||||
const char *testmodule; /* hidden package-driver alias for toolchain
|
||||
* `package test`; NULL outside that compile */
|
||||
};
|
||||
|
||||
void parserinit(Parser*, Arena*, Lex*);
|
||||
@@ -588,9 +590,10 @@ struct Checker {
|
||||
int errs;
|
||||
int is_test; /* #15: `w6c -T` — collect @test fns + synth
|
||||
* the entry; loud-reject a user main. */
|
||||
const char *test_module; /* generated dispatcher support qualifier */
|
||||
int sep_mode; /* -c package compilation: imported interfaces are
|
||||
* present, so absent members are hard export errors. */
|
||||
Node *synth_test_run; /* exact compiler-generated test.run DOT;
|
||||
Node *synth_test_run; /* exact compiler-generated support.run DOT;
|
||||
* its unresolved external hook is intentional */
|
||||
Node *alloc_octx; /* #3/B': the one empty `alloc([], n)` call node
|
||||
* that has let-declared slice context this walk;
|
||||
|
||||
Reference in New Issue
Block a user