toolchain: banner purge + WHY-only comment sweep (rule 8)
selfhost/, cmd/, internal/ join the tree-wide sweep: every section banner dies (91 selfhost + the cmd C-style dividers -> 0); narration and stale contracts deleted (pre-#22 bundler notes, retired single-PT_LOAD and no-archive claims, superseded ABI tables); every ref/harec/qbe cite, task cite, encoding/ELF contract, and rule-10 twin pointer kept; lost lifetime/rationale lines restored where the sweep over-cut (elf_globals ownership, kwtab linear-scan). Comment- only proven: all five wwstage tool binaries byte-identical across the sweep; test-commit, test-byteid (161+1399, 0 pinned-divergent), and test-bootstrap (fixed point + 991-995 byte-id) all exit 0. The read-through banked 66 latent-bug leads (checkpoint).
This commit is contained in:
@@ -24,9 +24,8 @@ import strings;
|
||||
// the cgen #127 mod-mangle attribution bug consumer per rule-7.
|
||||
def CMD_MAX: u64 = 8192u64;
|
||||
|
||||
// cerr — bare stderr fragment writer for the driver's piecewise
|
||||
// diagnostics. Tool-local (NOT a lib wrapper): messages are built from
|
||||
// many fragments and we route through os.write to avoid libc stdio.
|
||||
// Tool-local (NOT a lib wrapper): messages are built from many
|
||||
// fragments and we route through os.write to avoid libc stdio.
|
||||
// .len replaces the error-prone hand-counted byte literals these sites
|
||||
// carried. Lives here (the selfhost ww-driver build is a single main.ww;
|
||||
// err.c's bare-message path is not ported into this tree).
|
||||
@@ -34,17 +33,14 @@ fn cerr(m: str) void = {
|
||||
os.write(2, m.ptr, m.len: u64);
|
||||
};
|
||||
|
||||
// ---- C-string helpers --------------------------------------------------
|
||||
|
||||
fn cstrlen(p: *u8) u64 = {
|
||||
let n: u64 = 0u64;
|
||||
for (p[n] != 0u8) { n += 1u64; };
|
||||
return n;
|
||||
};
|
||||
|
||||
// pathstr — view a NUL-terminated *u8 as a str. Bridges the
|
||||
// driver's argv-style *u8 paths to lib/os entrypoints (str
|
||||
// post-task-#23).
|
||||
// Bridges the driver's argv-style *u8 paths to lib/os entrypoints
|
||||
// (str post-task-#23).
|
||||
fn pathstr(p: *u8) str = {
|
||||
let r: str;
|
||||
r.ptr = p;
|
||||
@@ -56,12 +52,10 @@ fn cstreq(a: *u8, b: *u8) bool = {
|
||||
return strings.compare(pathstr(a), pathstr(b)) == 0;
|
||||
};
|
||||
|
||||
// cstreqlit — compare a NUL-terminated *u8 to a ww string literal.
|
||||
fn cstreqlit(a: *u8, lit: str) bool = {
|
||||
return strings.compare(pathstr(a), lit) == 0;
|
||||
};
|
||||
|
||||
// memcpy
|
||||
fn bytecpy(dst: *u8, src: *u8, n: u64) void = {
|
||||
let i: u64 = 0u64;
|
||||
for (i < n) {
|
||||
@@ -70,8 +64,6 @@ fn bytecpy(dst: *u8, src: *u8, n: u64) void = {
|
||||
};
|
||||
};
|
||||
|
||||
// Copy a NUL-terminated *u8 into dst starting at off; return the new
|
||||
// offset (without writing a NUL).
|
||||
fn cstrinto(dst: *u8, off: u64, src: *u8) u64 = {
|
||||
let i: u64 = 0u64;
|
||||
for (src[i] != 0u8) {
|
||||
@@ -81,7 +73,6 @@ fn cstrinto(dst: *u8, off: u64, src: *u8) u64 = {
|
||||
return off + i;
|
||||
};
|
||||
|
||||
// Same, but for a ww `str` (no NUL on the source side; we copy len bytes).
|
||||
fn strinto(dst: *u8, off: u64, src: str) u64 = {
|
||||
let n: i32 = src.len;
|
||||
let i: i32 = 0;
|
||||
@@ -94,22 +85,15 @@ fn strinto(dst: *u8, off: u64, src: str) u64 = {
|
||||
return off + nu;
|
||||
};
|
||||
|
||||
// Write a single byte, return new offset.
|
||||
fn byteinto(dst: *u8, off: u64, c: u8) u64 = {
|
||||
dst[off] = c;
|
||||
return off + 1u64;
|
||||
};
|
||||
|
||||
// NUL-terminate at off and return the same off (handy when passing the
|
||||
// buffer to a syscall that expects a C-string).
|
||||
fn cstrseal(dst: *u8, off: u64) void = {
|
||||
dst[off] = 0u8;
|
||||
};
|
||||
|
||||
// ---- Tool-path resolution ---------------------------------------------
|
||||
|
||||
// dirname-equivalent: copy argv[0] up to (but not including) the last
|
||||
// '/' into dst, NUL-terminated. If no slash, write ".".
|
||||
fn selfdirinto(dst: *u8, dstsz: u64, argv0: *u8) void = {
|
||||
let n: u64 = cstrlen(argv0);
|
||||
let cut: u64 = 0u64;
|
||||
@@ -128,7 +112,6 @@ fn selfdirinto(dst: *u8, dstsz: u64, argv0: *u8) void = {
|
||||
dst[cut] = 0u8;
|
||||
};
|
||||
|
||||
// Build "$dir/$name" (NUL-terminated) into a fresh page-sized buffer.
|
||||
fn joinpath(dir: *u8, name: *u8) *u8 = {
|
||||
let buf: []u8 = alloc([], (os.PATH_MAX: u64))!;
|
||||
buf.len = os.PATH_MAX;
|
||||
@@ -139,7 +122,6 @@ fn joinpath(dir: *u8, name: *u8) *u8 = {
|
||||
return buf.ptr;
|
||||
};
|
||||
|
||||
// Same, but the second component is a ww `str` literal.
|
||||
fn joinpathlit(dir: *u8, name: str) *u8 = {
|
||||
let buf: []u8 = alloc([], (os.PATH_MAX: u64))!;
|
||||
buf.len = os.PATH_MAX;
|
||||
@@ -208,8 +190,6 @@ fn execpackagetests(selfdir: *u8, argv: **u8, argc: i32, start: i32,
|
||||
return 1;
|
||||
};
|
||||
|
||||
// ---- import resolution + visited-set -----------------------------------
|
||||
//
|
||||
// The separate-compilation producer scans each unit's top-of-file
|
||||
// `import IDENT;` lines and resolves them via the colon-separated `dirs`
|
||||
// search path. A per-scan visited set (linear; typical builds visit a
|
||||
@@ -409,10 +389,9 @@ fn dirfileclass(dirpath: *u8, name: *u8, nlen: u64) i32 = {
|
||||
return 1;
|
||||
};
|
||||
|
||||
// Byte-wise memcmp returning < 0, 0, > 0. Rule-10 byte-id requires
|
||||
// cstage and wwstage sort the same way; memcmp is the
|
||||
// locale-independent total order (mirrors ref/hare/sort/cmp/cmp.ha
|
||||
// strs).
|
||||
// Rule-10 byte-id requires cstage and wwstage sort the same way;
|
||||
// memcmp is the locale-independent total order (mirrors
|
||||
// ref/hare/sort/cmp/cmp.ha strs).
|
||||
fn bytecmp(a: *u8, alen: u64, b: *u8, blen: u64) i32 = {
|
||||
let n: u64 = alen;
|
||||
if (blen < n) { n = blen; };
|
||||
@@ -526,8 +505,6 @@ fn enumeratedir(dirpath: *u8) (**u8, i32) = {
|
||||
return exact.ptr, n;
|
||||
};
|
||||
|
||||
// ---- file slurp -------------------------------------------------------
|
||||
|
||||
fn slurp(pathcs: *u8) (*u8, u64) = {
|
||||
let fd: i32 = os.open(pathstr(pathcs), os.flag.RDONLY, 0i32);
|
||||
if (fd < 0) { return nil, 0u64; };
|
||||
@@ -566,7 +543,6 @@ fn isidentbyte(c: u8) bool = {
|
||||
// caller passes a slice of the source: src points at the line start.
|
||||
fn scanuse(src: *u8, len: u64) (*u8, u64) = {
|
||||
let i: u64 = 0u64;
|
||||
// skip leading whitespace
|
||||
for (i < len) {
|
||||
if (src[i] != 32u8) { if (src[i] != 9u8) { break; }; };
|
||||
i += 1u64;
|
||||
@@ -595,11 +571,6 @@ fn scanuse(src: *u8, len: u64) (*u8, u64) = {
|
||||
return src + idstart, idlen;
|
||||
};
|
||||
|
||||
// ---- Build pipeline ---------------------------------------------------
|
||||
|
||||
// Strip the trailing ".ww" off `src` (a NUL-terminated path) into
|
||||
// `stem`, NUL-terminated. If there's no .ww, the stem is the whole
|
||||
// path.
|
||||
fn makestem(stem: *u8, src: *u8) void = {
|
||||
let n: u64 = cstrlen(src);
|
||||
let stop: u64 = n;
|
||||
@@ -617,7 +588,6 @@ fn makestem(stem: *u8, src: *u8) void = {
|
||||
stem[stop] = 0u8;
|
||||
};
|
||||
|
||||
// Append a literal suffix to `stem` (which already lives in a buffer).
|
||||
fn appendlit(stem: *u8, suffix: str) *u8 = {
|
||||
let buf: []u8 = alloc([], (os.PATH_MAX: u64))!;
|
||||
buf.len = os.PATH_MAX;
|
||||
@@ -638,8 +608,6 @@ type lflags = struct {
|
||||
nlibs: i32,
|
||||
};
|
||||
|
||||
// ---- separate-compilation driver -------------------------------------
|
||||
//
|
||||
// Port of cmd/ww/main.c build_one_sep (task #46/c3). The build path
|
||||
// materializes each imported package's `.wwi` interface and compiles
|
||||
// every package on its own (`w6c -c`), then flat-links the `.o` set.
|
||||
@@ -677,7 +645,6 @@ type sepgraph = struct {
|
||||
n: i32,
|
||||
};
|
||||
|
||||
// Find a package by dotted path, or add it. Returns index, -1 if full.
|
||||
fn sepfindoradd(g: *sepgraph, path: *u8, entry: *u8, isdir: i32) i32 = {
|
||||
let i: i32 = 0;
|
||||
for (i < g.n) {
|
||||
@@ -1060,8 +1027,6 @@ fn seploadpkg(g: *sepgraph, pi: i32, searchpath: *u8) i32 = {
|
||||
return 0;
|
||||
};
|
||||
|
||||
// Print one cycle-chain node: a package path, or "(root)" for the
|
||||
// empty root path.
|
||||
fn sepcyclenode(p: *u8) void = {
|
||||
if (p[0] == 0u8) { cerr("(root)"); } else { cerr(pathstr(p)); };
|
||||
};
|
||||
@@ -1103,7 +1068,6 @@ fn septopovisit(g: *sepgraph, pi: i32, order: []i32, no: *i32,
|
||||
return 0;
|
||||
};
|
||||
|
||||
// Mark pi's transitive deps (excluding pi) in inset[].
|
||||
fn sepmarkdeps(g: *sepgraph, pi: i32, inset: []u8) void = {
|
||||
let k: i32 = 0;
|
||||
for (k < g.pkg[pi].ndeps) {
|
||||
@@ -1306,7 +1270,7 @@ fn archiveo(objpath: *u8, apath: *u8) i32 = {
|
||||
// reverse-topo `w6l` of the root `.o` + dependency `.a` set + libwwrt.a.
|
||||
// Side files land in a cold `<stem>.sepwork` scratch dir. Twin of cstage
|
||||
// build_one_sep.
|
||||
// ---- -w workdir freshness ----------------------------------------------
|
||||
|
||||
// A `-w DIR` workdir is a caller-owned persistent package-artifact tree
|
||||
// that replaces the fresh `.sepwork` scratch. Staleness is pure content
|
||||
// identity, never mtime: a package is reused only when its freshly
|
||||
@@ -1478,7 +1442,6 @@ fn buildonesepimpl(selfdir: *u8, src: *u8, entryisdir: i32, out: *u8,
|
||||
let a6: *u8 = joinpathlit(selfdir, "w6a_ww");
|
||||
let l6: *u8 = joinpathlit(selfdir, "w6l_ww");
|
||||
|
||||
// Default lib search path: <selfdir>/../../lib
|
||||
let dotdotlib: []u8 = alloc([], (os.PATH_MAX: u64))!;
|
||||
dotdotlib.len = os.PATH_MAX;
|
||||
{
|
||||
@@ -1487,7 +1450,6 @@ fn buildonesepimpl(selfdir: *u8, src: *u8, entryisdir: i32, out: *u8,
|
||||
cstrseal(dotdotlib.ptr, off);
|
||||
};
|
||||
|
||||
// Source directory.
|
||||
let srcd: []u8 = alloc([], (os.PATH_MAX: u64))!;
|
||||
srcd.len = os.PATH_MAX;
|
||||
if (entryisdir != 0) {
|
||||
@@ -1532,7 +1494,6 @@ fn buildonesepimpl(selfdir: *u8, src: *u8, entryisdir: i32, out: *u8,
|
||||
cstrseal(searchpath.ptr, off);
|
||||
};
|
||||
|
||||
// Stem for the scratch dir.
|
||||
let stem: []u8 = alloc([], (os.PATH_MAX: u64))!;
|
||||
stem.len = os.PATH_MAX;
|
||||
if (entryisdir != 0) {
|
||||
@@ -1606,7 +1567,6 @@ fn buildonesepimpl(selfdir: *u8, src: *u8, entryisdir: i32, out: *u8,
|
||||
};
|
||||
};
|
||||
|
||||
// libwwrt.a path: <selfdir>/../lib/libwwrt.a
|
||||
let libwwrt: []u8 = alloc([], (os.PATH_MAX: u64))!;
|
||||
libwwrt.len = os.PATH_MAX;
|
||||
{
|
||||
@@ -1615,7 +1575,6 @@ fn buildonesepimpl(selfdir: *u8, src: *u8, entryisdir: i32, out: *u8,
|
||||
cstrseal(libwwrt.ptr, off);
|
||||
};
|
||||
|
||||
// Discover.
|
||||
let pkgslot: []seppkg = alloc([], SEP_MAXPKG: u64)!;
|
||||
pkgslot.len = SEP_MAXPKG;
|
||||
let g: *sepgraph = alloc(sepgraph{pkg = pkgslot, n = 0})!;
|
||||
@@ -1649,7 +1608,6 @@ fn buildonesepimpl(selfdir: *u8, src: *u8, entryisdir: i32, out: *u8,
|
||||
};
|
||||
if (seploadpkg(g, root, searchpath.ptr) < 0) { return 1; };
|
||||
|
||||
// Reset colors, reverse-topo.
|
||||
let ci: i32 = 0;
|
||||
for (ci < g.n) { g.pkg[ci].color = 0; ci += 1; };
|
||||
let order: []i32 = alloc([], g.n: u64)!;
|
||||
@@ -1659,7 +1617,6 @@ fn buildonesepimpl(selfdir: *u8, src: *u8, entryisdir: i32, out: *u8,
|
||||
let norder: i32 = 0;
|
||||
if (septopovisit(g, root, order, &norder, stack, 0) < 0) { return 1; };
|
||||
|
||||
// Producer loop — dep-first, one `w6c -c -I` per package.
|
||||
let oi: i32 = 0;
|
||||
for (oi < norder) {
|
||||
let pi: i32 = order[oi];
|
||||
@@ -1961,22 +1918,10 @@ fn buildonesep(selfdir: *u8, src: *u8, entryisdir: i32, out: *u8,
|
||||
return r;
|
||||
};
|
||||
|
||||
// ---- Module-by-name resolution ----------------------------------------
|
||||
//
|
||||
// Mirrors cmd/ww/main.c:resolvemodule. Maps a name like "foo", "lib/foo",
|
||||
// "foo.ww", or "." to a concrete .ww file path:
|
||||
// 1. literal <name>.ww that exists → use as-is
|
||||
// 2. "." → <cwd>/<basename(cwd)>.ww → that, if it exists
|
||||
// 3. <name>/<basename(name)>.ww → that, if it exists
|
||||
// 4. walk search path (cwd:incs:<selfdir>/../../lib):
|
||||
// <dir>/<name>.ww or <dir>/<name>/<name>.ww
|
||||
|
||||
fn cstrendswithlit(p: *u8, lit: str) bool = {
|
||||
return strings.hassuffix(pathstr(p), lit);
|
||||
};
|
||||
|
||||
// basenameoff — return the offset of the last path segment within `p`
|
||||
// (i.e. one past the final '/'). Returns 0 if there's no slash.
|
||||
fn basenameoff(p: *u8, plen: u64) u64 = {
|
||||
let start: u64 = 0u64;
|
||||
let i: u64 = 0u64;
|
||||
@@ -1987,8 +1932,6 @@ fn basenameoff(p: *u8, plen: u64) u64 = {
|
||||
return start;
|
||||
};
|
||||
|
||||
// arenadupcstr — copy `plen` bytes from `src` into a fresh NUL-sealed
|
||||
// heap buffer.
|
||||
fn arenadupcstr(src: *u8, plen: u64) *u8 = {
|
||||
let buf: []u8 = alloc([], plen + 1u64)!;
|
||||
let i: u64 = 0u64;
|
||||
@@ -1997,8 +1940,7 @@ fn arenadupcstr(src: *u8, plen: u64) *u8 = {
|
||||
return buf.ptr;
|
||||
};
|
||||
|
||||
// buildsearchpath — compose the colon-separated lookup path used by
|
||||
// resolvemodule's case (4). Order: "." : <incs> : <selfdir>/../../lib
|
||||
// resolvemodule search-path order: "." : <incs> : <selfdir>/../../lib
|
||||
fn buildsearchpath(selfdir: *u8, incs: *u8) *u8 = {
|
||||
let buf: []u8 = alloc([], (os.PATH_MAX: u64) * 2u64)!;
|
||||
let off: u64 = 0u64;
|
||||
@@ -2016,13 +1958,11 @@ fn buildsearchpath(selfdir: *u8, incs: *u8) *u8 = {
|
||||
return buf.ptr;
|
||||
};
|
||||
|
||||
// resolvemodule — map a name like "foo", "lib/foo", "foo.ww", or
|
||||
// "." to a concrete entry path. Sets *isdir when the entry is a
|
||||
// Mirrors cmd/ww/main.c:resolvemodule. Sets *isdir when the entry is a
|
||||
// module directory (caller will dir-enumerate).
|
||||
fn resolvemodule(selfdir: *u8, name: *u8, incs: *u8, isdir: *i32) *u8 = {
|
||||
let nlen: u64 = cstrlen(name);
|
||||
|
||||
// (1) Literal file that exists → use as-is.
|
||||
if (cstrendswithlit(name, ".ww")) {
|
||||
if (os.access(pathstr(name), 0i32) == 0) {
|
||||
*isdir = 0;
|
||||
@@ -2030,7 +1970,6 @@ fn resolvemodule(selfdir: *u8, name: *u8, incs: *u8, isdir: *i32) *u8 = {
|
||||
};
|
||||
};
|
||||
|
||||
// (2) Existing path → use as-is, dir vs file via stat.
|
||||
let fi: os.filestat;
|
||||
let sr: (void | os.oserror) = os.stat(&fi, pathstr(name));
|
||||
let found: bool = false;
|
||||
@@ -2048,13 +1987,10 @@ fn resolvemodule(selfdir: *u8, name: *u8, incs: *u8, isdir: *i32) *u8 = {
|
||||
return arenadupcstr(name, nlen);
|
||||
};
|
||||
|
||||
// (3) Search-path lookup with dot-to-slash path translation.
|
||||
let search: *u8 = buildsearchpath(selfdir, incs);
|
||||
return locateimport(search, name, nlen, isdir);
|
||||
};
|
||||
|
||||
// ---- Subcommand handlers ----------------------------------------------
|
||||
|
||||
fn writeusage(fd: i32) void = {
|
||||
let s: str = "usage: ww [-V] <subcommand> [args...]\n -V print version and exit\n build [-S] [-w DIR] [-o FILE] [path] compile module; -S stops after package asm\n run [path] ... build then exec, passing extra args to the program\n test [-S -o STEM] [-w DIR] [options] [path] build/run tests; -S emits package asm\n version print version and exit\n\n path forms:\n foo.ww literal file\n foo search cwd, -I dirs, then $WW_LIB-equiv for foo.ww or foo/foo.ww\n lib/foo directory: build lib/foo/foo.ww\n lib/... every package under lib, recursively (test only)\n . build the cwd's <basename>.ww\n";
|
||||
os.write(fd, s.ptr, s.len: u64);
|
||||
@@ -2065,8 +2001,6 @@ fn doversion() i32 = {
|
||||
return 0;
|
||||
};
|
||||
|
||||
// Compute the basename of src (without trailing ".ww") into a fresh
|
||||
// buffer. Used as the default output path for `ww build`.
|
||||
fn defaultoutpath(src: *u8) *u8 = {
|
||||
let n: u64 = cstrlen(src);
|
||||
let start: u64 = 0u64;
|
||||
@@ -2084,7 +2018,6 @@ fn defaultoutpath(src: *u8) *u8 = {
|
||||
off += 1u64;
|
||||
j += 1u64;
|
||||
};
|
||||
// Strip ".ww" if present.
|
||||
if (off >= 3u64) {
|
||||
if (out[off - 3u64] == 46u8) {
|
||||
if (out[off - 2u64] == 119u8) {
|
||||
@@ -2209,7 +2142,6 @@ fn dobuild(selfdir: *u8, argv: **u8, argc: i32, start: i32) i32 = {
|
||||
};
|
||||
|
||||
if (src == nil) {
|
||||
// default to cwd module
|
||||
let dot: [2]u8 = ['.': u8, 0u8];
|
||||
src = &dot[0];
|
||||
};
|
||||
@@ -2264,7 +2196,6 @@ fn makedrivertmp(buf: *u8, prefix: str) void = {
|
||||
pk += 1;
|
||||
};
|
||||
let pid: i32 = os.getpid();
|
||||
// itoa for non-negative pid
|
||||
let dig: [16]u8;
|
||||
let n: i32 = 0;
|
||||
if (pid <= 0) {
|
||||
@@ -2383,7 +2314,7 @@ fn dorun(selfdir: *u8, argv: **u8, argc: i32, start: i32) i32 = {
|
||||
src = p;
|
||||
i += 1;
|
||||
} else {
|
||||
passstart = i; // remaining args go to the program
|
||||
passstart = i;
|
||||
};
|
||||
};
|
||||
};
|
||||
@@ -2426,8 +2357,8 @@ fn dorun(selfdir: *u8, argv: **u8, argc: i32, start: i32) i32 = {
|
||||
return 1;
|
||||
};
|
||||
|
||||
// Execute with [tmp, argv[passstart..argc)). The standard process
|
||||
// facility inherits stdio and waits only for this user program.
|
||||
// The standard process facility inherits stdio and waits only for
|
||||
// this user program.
|
||||
let nextra: i32 = 0;
|
||||
if (passstart >= 0) { nextra = argc - passstart; };
|
||||
let execargv: []str = alloc([], (nextra + 1): u64)!;
|
||||
@@ -2464,8 +2395,6 @@ fn dorun(selfdir: *u8, argv: **u8, argc: i32, start: i32) i32 = {
|
||||
return rc;
|
||||
};
|
||||
|
||||
// ---- ww test ----------------------------------------------------------
|
||||
//
|
||||
// Mirrors cmd/ww/main.c:dotest. Explicit regular files retain the bootstrap
|
||||
// compatibility route; directory/default requests delegate to wwtest.
|
||||
|
||||
@@ -2762,15 +2691,12 @@ fn dotest(selfdir: *u8, argv: **u8, argc: i32, start: i32) i32 = {
|
||||
replacement, targetindex < 0);
|
||||
};
|
||||
|
||||
// ---- Entry -------------------------------------------------------------
|
||||
|
||||
export fn main(argc: i32, argv: **u8) i32 = {
|
||||
if (argc < 1) {
|
||||
writeusage(2);
|
||||
return 2;
|
||||
};
|
||||
|
||||
// selfdir = dirname(argv[0])
|
||||
let selfdir: []u8 = alloc([], (os.PATH_MAX: u64))!;
|
||||
selfdir.len = os.PATH_MAX;
|
||||
selfdirinto(selfdir.ptr, (os.PATH_MAX: u64), argv[0]);
|
||||
|
||||
Reference in New Issue
Block a user