build: omit named test source operands

This commit is contained in:
2026-08-22 21:53:10 +09:00
parent 3922f1c34e
commit 2e5451a601
13 changed files with 1666 additions and 21 deletions

View File

@@ -991,6 +991,102 @@ fn slurp(pathcs: *u8) (*u8, u64) = {
return buf.ptr, nu;
};
// Named source recognition accepts every existing non-directory Stat result.
// Read to EOF without seeking so a finite FIFO follows the same package-header
// loading path as a regular file.
fn sourceheaderslurp(pathcs: *u8) (*u8, u64, u64) = {
let fd: i32 = os.open(pathstr(pathcs), os.flag.RDONLY, 0i32);
if (fd < 0) { return nil, 0u64, 0u64; };
let cap: i32 = 4096;
let allocation: ([]u8 | nomem) = sepallocbytes(cap);
let buf: []u8;
match (allocation) {
case let value: []u8 => buf = value;
case nomem => {
sepfailnomem();
os.close(fd);
return nil, 0u64, 0u64;
};
};
let used: u64 = 0u64;
for (true) {
if (used == cap: u64) {
if (cap == SEP_COUNT_MAX) {
sepfailsize();
os.close(fd);
os.free(buf.ptr: *void, cap: u64);
return nil, 0u64, 0u64;
};
let nextcap: i32 = cap;
if (cap > SEP_COUNT_MAX / 2) { nextcap = SEP_COUNT_MAX; }
else { nextcap = cap * 2; };
let nextallocation: ([]u8 | nomem) = sepallocbytes(nextcap);
let next: []u8;
match (nextallocation) {
case let value: []u8 => next = value;
case nomem => {
sepfailnomem();
os.close(fd);
os.free(buf.ptr: *void, cap: u64);
return nil, 0u64, 0u64;
};
};
bytecpy(next.ptr, buf.ptr, used);
os.free(buf.ptr: *void, cap: u64);
buf = next;
cap = nextcap;
};
let got: i64 = os.read(fd, buf.ptr + used,
(cap: u64) - used);
if (got == -(os.EINTR: i32): i64) { continue; };
if (got < 0i64) {
os.close(fd);
os.free(buf.ptr: *void, cap: u64);
return nil, 0u64, 0u64;
};
if (got == 0i64) { break; };
used += got: u64;
};
if (os.close(fd) != 0) {
os.free(buf.ptr: *void, cap: u64);
return nil, 0u64, 0u64;
};
buf[used] = 0u8;
return buf.ptr, used, cap: u64;
};
// Validate only the package/import header. The returned syntax is deliberately
// discarded: an ordinary build creates no package or import graph for this
// test-only named source.
fn sourcebuildheader(path: *u8) bool = {
let view: str = pathstr(path);
let bufp: *u8;
let blen: u64;
let bcap: u64;
bufp, blen, bcap = sourceheaderslurp(path);
if (bufp == nil) {
cerrpath("ww: cannot read ", path, "\n");
return false;
};
let l: syntax.lex;
syntax.lexinit(&l, view, bufp, blen);
let ps: syntax.parser;
syntax.parserinit(&ps, &l);
let header: *syntax.node = syntax.parsepackageheader(&ps);
if (l.errs > 0 || ps.errs > 0) {
os.free(bufp: *void, bcap);
return false;
};
if (header.nmod.len == 0) {
cerrpos(view, 1, 1);
cerr(": error: invalid or missing package clause\n");
os.free(bufp: *void, bcap);
return false;
};
os.free(bufp: *void, bcap);
return true;
};
fn makestem(stem: *u8, src: *u8) void = {
let n: u64 = cstrlen(src);
let stop: u64 = n;
@@ -8943,15 +9039,35 @@ fn dobuild(selfdir: *u8, argv: **u8, argc: i32, start: i32) i32 = {
nil, nil, false, true);
};
let requestedliteral: bool = false;
let requestednondirectory: bool = false;
let requestedstat: os.filestat;
match (os.stat(&requestedstat, pathstr(src))) {
case void => requestedliteral = true;
case void => {
requestedliteral = true;
let typ: u32 = (requestedstat.mode: u32) & 61440u32;
requestednondirectory = typ != os.mode.DIR: u32;
};
case let e: os.oserror => void;
};
if (sourceoperandignored(src)) {
sourceoperandnosources(src);
return 1;
};
let requestedlen: u64 = cstrlen(src);
let requestedbase: u64 = basenameoff(src, requestedlen);
if (requestednondirectory && requestedlen - requestedbase >= 8u64
&& cstrendswithlit(src, "_test.ww")) {
if (!sourcebuildheader(src)) { return 1; };
if (outflag == nil || cstreqlit(outflag, "/dev/null")) {
return 0;
};
if (buildoutputdir(outflag)) {
cerr("ww: no main packages to build\n");
} else {
cerr("ww: no packages to build\n");
};
return 1;
};
let isdir: i32 = 0;
let resolved: *u8 = resolvemodule(selfdir, src, incs.ptr, &isdir);
if (resolved == nil) {