compiler: support package test runtime aliases
This commit is contained in:
@@ -66,6 +66,7 @@ export fn main(argc: i32, argv: **u8) i32 = {
|
||||
let src: *u8 = nil;
|
||||
let out: *u8 = nil;
|
||||
let wwiout: *u8 = nil; // -I <out.wwi>: M2 export-data producer
|
||||
let testsupport: *u8 = nil;
|
||||
let testmode: i32 = 0i32; // #15: `-T` test-mode
|
||||
let sepmode: i32 = 0i32; // -c: #22 M3 separate-compile / primary-
|
||||
// only codegen (emit imported==0 decls
|
||||
@@ -92,6 +93,14 @@ export fn main(argc: i32, argv: **u8) i32 = {
|
||||
wwiout = argv[i];
|
||||
} else { if (cstreq(a, "-T")) {
|
||||
testmode = 1i32;
|
||||
} else { if (cstreq(a, "--test-support-module")) {
|
||||
i += 1;
|
||||
if (i >= argc) {
|
||||
let m: str = "w6c: --test-support-module requires arg\n";
|
||||
os.write(2, m.ptr, m.len: u64);
|
||||
return 2;
|
||||
};
|
||||
testsupport = argv[i];
|
||||
} else { if (cstreq(a, "-c")) {
|
||||
sepmode = 1i32;
|
||||
} else { if (a[0u64] == 45u8) {
|
||||
@@ -105,7 +114,7 @@ export fn main(argc: i32, argv: **u8) i32 = {
|
||||
return 2;
|
||||
};
|
||||
src = a;
|
||||
}; }; }; }; };
|
||||
}; }; }; }; }; };
|
||||
i += 1;
|
||||
};
|
||||
|
||||
@@ -114,6 +123,13 @@ export fn main(argc: i32, argv: **u8) i32 = {
|
||||
os.write(2, m.ptr, m.len: u64);
|
||||
return 2;
|
||||
};
|
||||
if (testsupport != nil && (sepmode == 0
|
||||
|| (!cstreq(testsupport, "test")
|
||||
&& !cstreq(testsupport, "__wwtest")))) {
|
||||
let m: str = "w6c: invalid --test-support-module\n";
|
||||
os.write(2, m.ptr, m.len: u64);
|
||||
return 2;
|
||||
};
|
||||
|
||||
let buf: *u8;
|
||||
let blen: u64;
|
||||
@@ -155,6 +171,7 @@ export fn main(argc: i32, argv: **u8) i32 = {
|
||||
|
||||
let ps: parser;
|
||||
parserinit(&ps, &l);
|
||||
if (testsupport != nil) { ps.testmodule = pathstr(testsupport); };
|
||||
let f: *node = parsefile(&ps);
|
||||
// Gate cgen on parse-stage errors. Mirrors cmd/w6c/main.c's
|
||||
// `if (l.errs || p.errs) return 1;` — broken AST otherwise reaches
|
||||
@@ -172,6 +189,7 @@ export fn main(argc: i32, argv: **u8) i32 = {
|
||||
let ck: checker;
|
||||
checkinit(&ck, &tc);
|
||||
ck.istest = testmode;
|
||||
if (testsupport != nil) { ck.testmodule = pathstr(testsupport); };
|
||||
ck.sepmode = sepmode;
|
||||
checkfile(&ck, f);
|
||||
if (ck.errs > 0) { return 1; };
|
||||
|
||||
@@ -20,9 +20,10 @@ type checker = struct {
|
||||
// twin (c->matcharms)
|
||||
istest: i32, // #15: `w6c_ww -T` — collect @test fns +
|
||||
// synth the entry; loud-reject a user main.
|
||||
testmodule: str, // generated dispatcher support qualifier
|
||||
sepmode: i32, // -c package compilation: imported interfaces are
|
||||
// present, so absent members are hard export errors.
|
||||
synthtestrun: *syntax.node, // exact generated test.run DOT; its
|
||||
synthtestrun: *syntax.node, // exact generated support.run DOT; its
|
||||
// unresolved external hook is intentional
|
||||
verbose: i32, // when non-zero, log each unresolved name
|
||||
fnret: *syntax.node, // enclosing fn's return type AST (for `?`)
|
||||
@@ -361,7 +362,7 @@ fn packageaccesserr(c: *checker, e: *syntax.node, pkg: str, member: str,
|
||||
c.errs += 1;
|
||||
};
|
||||
|
||||
// A bare `w6c -T` leaves the compiler-generated test.run hook external;
|
||||
// A bare `w6c -T` leaves the compiler-generated support.run hook external;
|
||||
// the ordinary driver supplies lib/test. No user-written missing member is
|
||||
// exempt from package export checking.
|
||||
fn synthesizedtestrun(c: *checker, e: *syntax.node) bool = {
|
||||
@@ -7480,6 +7481,7 @@ export fn checkinit(c: *checker, tc: *syntax.tctx) void = {
|
||||
c.nunresolved = 0;
|
||||
c.errs = 0;
|
||||
c.istest = 0i32; // #15: caller (w6c main) sets it after init
|
||||
c.testmodule = "test";
|
||||
c.sepmode = 0i32; // caller (w6c main) sets it from -c
|
||||
c.synthtestrun = nil;
|
||||
c.verbose = 0;
|
||||
@@ -7496,20 +7498,19 @@ export fn checkfile(c: *checker, file: *syntax.node) void = {
|
||||
if (file.kind != syntax.nkind.N_FILE) { return; };
|
||||
c.file = file;
|
||||
|
||||
// #80: under -T, PREPEND the synth `use test;` BEFORE Pass 1 so declmod
|
||||
// (called per-decl during install) sees a matching `use test` when it
|
||||
// keys lib/test's `run` — keying it under mod="test", not "". This is a
|
||||
// Under -T, prepend the dispatcher support import before Pass 1 so
|
||||
// declmod keys the runner under the selected support module. This is a
|
||||
// pure ORDER fix: the synth N_USE was appended AFTER install (below),
|
||||
// too late for declmod, so `run` keyed under "" — leaving the synth
|
||||
// `test.run` ty_err (the E1 bridge) and colliding with a user root
|
||||
// too late for declmod, so `run` keyed under "" — leaving the qualified
|
||||
// call ty_err (the E1 bridge) and colliding with a user root
|
||||
// `fn run` (also mod=""). Decoupled from cgen: the symbol mangle keys
|
||||
// off d.module (the //ww:module directive, cgen mod_collect), NOT this
|
||||
// scope keying — cgen already emits the correct CALL test.run. Twin of
|
||||
// scope keying — cgen already emits the qualified call. Twin of
|
||||
// cstage cmd/wcc/check.c.
|
||||
if (c.istest != 0) {
|
||||
let usenode: *syntax.node = syntax.newnode(syntax.nkind.N_USE, file.file, file.line, file.col);
|
||||
usenode.str = "test";
|
||||
usenode.usepath = "test";
|
||||
usenode.str = c.testmodule;
|
||||
usenode.usepath = c.testmodule;
|
||||
usenode.next = file.list;
|
||||
file.list = usenode;
|
||||
};
|
||||
@@ -7719,16 +7720,14 @@ export fn checkfile(c: *checker, file: *syntax.node) void = {
|
||||
let arg: *syntax.node = syntax.newnode(syntax.nkind.N_IDENT, pf, pl, pc);
|
||||
arg.str = "__wwtests";
|
||||
let call: *syntax.node = syntax.newnode(syntax.nkind.N_CALL, pf, pl, pc);
|
||||
// QUALIFIED test.run (N_DOT base ident `test`, member `run`):
|
||||
// the sep producer sees lib/test as a real imported package,
|
||||
// so the call must carry the module qualifier; the combined
|
||||
// path tags auto-bundled lib/test `//ww:module test` too, so
|
||||
// it resolves+mangles identically (test.run). Cstage twin:
|
||||
// cmd/wcc/check.c synth. The base ident binds through the
|
||||
// synth N_USE below.
|
||||
// Qualified support.run (N_DOT base ident + member `run`):
|
||||
// the sep producer sees the toolchain test runtime as a real
|
||||
// imported package. Its selected module is normally `test`, or
|
||||
// the reserved alias when user source owns that identity. The
|
||||
// base ident binds through the synthetic N_USE.
|
||||
let dot: *syntax.node = syntax.newnode(syntax.nkind.N_DOT, pf, pl, pc);
|
||||
let did: *syntax.node = syntax.newnode(syntax.nkind.N_IDENT, pf, pl, pc);
|
||||
did.str = "test";
|
||||
did.str = c.testmodule;
|
||||
dot.lhs = did;
|
||||
dot.str = "run";
|
||||
c.synthtestrun = dot;
|
||||
@@ -7737,11 +7736,9 @@ export fn checkfile(c: *checker, file: *syntax.node) void = {
|
||||
let ret: *syntax.node = syntax.newnode(syntax.nkind.N_RETURN, pf, pl, pc);
|
||||
ret.lhs = call;
|
||||
body.list = ret;
|
||||
// #80: the synth `use test;` (the N_DOT base qualifier + the
|
||||
// usepathfor source mapping `test`→its path) is now PREPENDED
|
||||
// before Pass 1 at the top of checkfile, so declmod keys
|
||||
// lib/test's `run` under "test" and the synth `test.run`
|
||||
// type-resolves. It is installed (SK_USE) by Pass 1's N_USE arm.
|
||||
// The synthetic support use is prepended before Pass 1, so
|
||||
// declmod keys the runtime's `run` under the selected module and
|
||||
// the synthesized call type-resolves. Pass 1 installs the use.
|
||||
};
|
||||
let m: *syntax.node = syntax.newnode(syntax.nkind.N_FNDECL, pf, pl, pc);
|
||||
m.str = "main";
|
||||
|
||||
Reference in New Issue
Block a user