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:
2026-08-08 23:14:03 +09:00
parent 83f5956df2
commit 62b9d20383
60 changed files with 232 additions and 1045 deletions

View File

@@ -1,11 +1,6 @@
/*
* ww — the user-facing driver. Plan 9 cc(1) / Hare hare(1) analogue.
*
* Pipeline:
* ww build foo.ww → w6c foo.ww > foo.s ; w6a foo.s > foo.o ;
* w6l -o foo foo.o <runtime.o>
* ww run foo.ww → build then exec ./foo
*
* Tool paths default to siblings of $0 (so a fresh build runs out of
* out/bin/), and can be overridden with WW_W6C / WW_W6A / WW_W6L.
*/
@@ -35,7 +30,7 @@ static const char *usage =
" lib/... every package under lib, recursively (test only)\n"
" . build the cwd's <basename>.ww\n";
static char *self_dir; /* directory containing this binary */
static char *self_dir;
static const char *
toolpath(const char *envvar, const char *name)
@@ -125,8 +120,7 @@ exec_package_tests(int argc, char **argv, const char *target,
return 1;
}
/* Set of imported module paths, kept on the heap. Used to break
* cycles in `use` resolution. Linear because typical imports are
/* Breaks cycles in `use` resolution. Linear because typical imports are
* a handful per build. */
struct ImportSet {
char **paths;
@@ -151,8 +145,7 @@ import_add(struct ImportSet *s, const char *path)
s->paths[s->n++] = strdup(path);
}
/* Translate dots in an `import` name to slashes for path lookup.
* `encoding.utf8` → `encoding/utf8`. Mirrors Hare hare(1)'s
/* `encoding.utf8` → `encoding/utf8`. Mirrors Hare hare(1)'s
* use-path → fs-path mapping (ref/hare/hare/module/srcs.ha:78
* builds the same shape via path::push per ident part). */
static void
@@ -164,12 +157,11 @@ import_path_form(const char *name, char *out, size_t outsz)
out[i] = '\0';
}
/* try <dir>/<path>/ as a directory (want_dir), else <dir>/<path>.ww as
* a file. Sets *is_dir on hit. Symmetric with wwstage locatein for
* byte-id driver output (rule 10). The legacy <dir>/<name>/<name>.ww
* form was dropped in task #22 — directory-as-module enumeration
* replaces it, mirroring ref/hare/hare/module/srcs.ha (Hare has no
* fallback matching `foo/foo.ha`; a module IS the directory). */
/* Symmetric with wwstage locatein for byte-id driver output (rule 10).
* The legacy <dir>/<name>/<name>.ww form was dropped in task #22 —
* directory-as-module enumeration replaces it, mirroring
* ref/hare/hare/module/srcs.ha (Hare has no fallback matching
* `foo/foo.ha`; a module IS the directory). */
static int
locate_import_in(const char *dir, const char *path_form, char *out,
size_t outsz, int *is_dir, int want_dir)
@@ -191,10 +183,7 @@ locate_import_in(const char *dir, const char *path_form, char *out,
return 0;
}
/* Walk a colon-separated dirlist trying to resolve `path_form`. Returns
* 1 on the first hit and writes the concrete path + dir/file marker.
*
* #98: "a module IS the directory" — a directory-package on ANY entry
/* #98: "a module IS the directory" — a directory-package on ANY entry
* wins over a same-named sibling FILE on an EARLIER entry. The driver
* builds the searchpath srcd-first; a co-located `lib/<mod>/<x>_test.ww`
* entry makes srcd = lib/<mod>, so a self-named `import <mod>` would
@@ -231,10 +220,10 @@ locate_import(const char *dirs, const char *path_form, char *out,
return 0;
}
/* memcmp-based string compare for qsort. Byte-wise total order is
* locale-independent; rule-10 byte-id requires the two stages sort
* the same way. (strcmp would work today but Hare-fidelity points
* at memcmp via ref/hare/sort/cmp/cmp.ha:9.) */
/* Byte-wise total order is locale-independent; rule-10 byte-id requires
* the two stages sort the same way. strcmp diverges from Hare's memcmp
* (ref/hare/sort/cmp/cmp.ha:9); the order is identical for NUL-free
* filenames. */
static int
strs_cmp(const void *a, const void *b)
{
@@ -266,11 +255,9 @@ file_has_line_test(const char *path)
return found;
}
/* enumerate_dir_ww — collect production *.ww paths in `dirpath`, excluding
* *_test.ww test sources, then sort byte-wise. A line-leading @test in
* any other source is diagnosed here and returns -2. This is the sole
* directory-membership discovery path; the owning seppkg retains the
* returned list. */
/* A line-leading @test in a production source is diagnosed here and
* returns -2. This is the sole directory-membership discovery path; the
* owning seppkg retains the returned list. */
static int
enumerate_dir_ww(const char *dirpath, char ***out_files)
{
@@ -310,9 +297,8 @@ enumerate_dir_ww(const char *dirpath, char ***out_files)
return n;
}
/* ====================================================================
* ww build — separate-compilation driver (task #46/c3).
* ====================================================================
/* ww build — separate-compilation driver (task #46/c3).
*
* This is the SOLE build path (E3-C1 flip, task #87): the legacy
* single-file amalgamator is gone. Each imported
* package's `.wwi` interface is materialized and every package is
@@ -357,7 +343,6 @@ struct sepgraph {
int n;
};
/* Find a package by dotted path, or add it. Returns its index, -1 full. */
static int
sep_find_or_add(struct sepgraph *g, const char *path, const char *entry,
int is_dir)
@@ -395,8 +380,7 @@ sep_graph_free(struct sepgraph *g)
free(g);
}
/* Sanitize a package's dotted path into a scratch-file basename. Dots
* stay (legal in filenames); the root's empty path becomes "__root". */
/* Dots stay (legal in filenames); the root's empty path becomes "__root". */
static void
sep_fname(const struct sepgraph *g, int pi, const char *scratch,
const char *suffix, char *out, size_t outsz)
@@ -451,9 +435,8 @@ sep_ident_continue(int c)
return sep_ident_start(c) || (c >= '0' && c <= '9');
}
/* Skip the whitespace and comments accepted before and within the leading
* package clause. This is deliberately only the loader's small header
* grammar, not a second compiler lexer. */
/* Deliberately only the loader's small header grammar for the leading
* package clause, not a second compiler lexer. */
static int
sep_skip_space(const char *src, size_t n, size_t *off)
{
@@ -481,7 +464,6 @@ sep_skip_space(const char *src, size_t n, size_t *off)
return 0;
}
/* Parse exactly the leading loader grammar `package ident;`. */
static int
sep_package_clause(const char *src, size_t n, char *name, size_t namesz)
{
@@ -509,9 +491,7 @@ sep_package_clause(const char *src, size_t n, char *name, size_t namesz)
return 0;
}
/* Scan one source file's already-selected bytes for its leading package
* clause (when it is an owned directory source) and top-level imports. A
* DIRECTORY import is a package boundary: add it as a direct dep of pkg
/* A DIRECTORY import is a package boundary: add it as a direct dep of pkg
* `pi`. A FILE import is an intra-package split — fold its imports into
* `pi` (its bytes join pi's body at emit time). Collects package PATHS
* rather than concatenating bytes the way the legacy amalgamator did
@@ -715,7 +695,6 @@ sep_topo_visit(struct sepgraph *g, int pi, int *order, int *no,
return 0;
}
/* Mark pi's transitive deps (excluding pi) in inset[]. */
static void
sep_mark_deps(struct sepgraph *g, int pi, char *inset)
{
@@ -881,9 +860,9 @@ archive_o(const char *objpath, const char *apath)
return 0;
}
/* ---- -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
/* -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
* composed unit byte-equals the committed unit AND the tool copies
* recorded in the dir byte-equal the live tools — every decision is
@@ -997,7 +976,6 @@ build_one_sep_impl(const char *src, int entry_is_dir, const char *out,
else if (access("lib", 0) == 0) srcdir = "lib";
else srcdir = libdir;
}
/* search path: source-dir, then -I dirs, then srcdir. */
char srcd[1024];
if (entry_is_dir) {
snprintf(srcd, sizeof srcd, "%s", src);
@@ -1110,7 +1088,6 @@ build_one_sep_impl(const char *src, int entry_is_dir, const char *out,
}
free(stack);
/* producer loop — dep-first, one `w6c -c -I` pass per package. */
for (int oi = 0; oi < norder; oi++) {
int pi = order[oi];
char unitf[1024], wwi[1024], asmf[1024], obj[1024], apath[1024];
@@ -1250,7 +1227,6 @@ build_one_sep_impl(const char *src, int entry_is_dir, const char *out,
char objs[8192] = {0};
for (int oi = norder - 1; oi >= 0; oi--) {
char path[1024];
/* root: positional `.o` (force-load); deps: `.a` (selective). */
sep_fname(g, order[oi], scratch,
order[oi] == root ? ".o" : ".a", path, sizeof path);
size_t n = strlen(objs);
@@ -1345,7 +1321,6 @@ search_path(const char *extra, char *buf, size_t bufsz)
return buf;
}
/* basename_no_ext: last path segment with any trailing ".ww" stripped. */
static void
basename_no_ext(const char *path, char *out, size_t outsz)
{
@@ -1356,13 +1331,6 @@ basename_no_ext(const char *path, char *out, size_t outsz)
if (dot && strcmp(dot, ".ww") == 0) *dot = '\0';
}
/* resolve_module: turn a name into a concrete entry path.
* foo.ww → use as-is if it exists
* <existing dir> → returns the dir path (caller dir-enumerates)
* . → cwd as a directory
* foo (bare) → walk cwd:incs:WW_LIB; first hit is dir or file.
* Sets *is_dir on hit. Dir resolution drives directory-as-module
* enumeration in build_one_sep. */
static int
resolve_module(const char *name, const char *incs, char *out, size_t outsz,
int *is_dir)
@@ -1387,12 +1355,11 @@ resolve_module(const char *name, const char *incs, char *out, size_t outsz,
return locate_import(sp, path_form, out, outsz, is_dir);
}
/* Parse the standard -I/-L/-l/-o flags into incs/libdirs/libs/outpath. The
* first non-flag positional becomes *src_out. Returns the index past the last
* arg consumed for positionals (so callers can pick up trailing args), or -1
* if a flag is missing its argument (diagnostic already emitted). `cmd` names
* the subcommand for the diagnostic, byte-identical to the wwstage twin's
* per-subcommand wording (selfhost/cmd/ww/main.ww dobuild/dorun). */
/* Returns the index past the last arg consumed for positionals (so callers
* can pick up trailing args), or -1 if a flag is missing its argument
* (diagnostic already emitted). `cmd` names the subcommand for the
* diagnostic, byte-identical to the wwstage twin's per-subcommand wording
* (selfhost/cmd/ww/main.ww dobuild/dorun). */
static int
parse_build_flags(const char *cmd, int argc, char **argv,
char *incs, size_t incsz,
@@ -1504,7 +1471,7 @@ do_build(int argc, char **argv)
outflag, sizeof outflag, workdir, sizeof workdir,
&src, &emit_asm) < 0)
return 2;
if (src == NULL) src = "."; /* default: build cwd */
if (src == NULL) src = ".";
char resolved[1024];
int is_dir = 0;
if (!resolve_module(src, incs, resolved, sizeof resolved, &is_dir)) {
@@ -1568,7 +1535,6 @@ do_run(int argc, char **argv)
fputs("ww: cannot remove temporary directory\n", stderr);
return 1;
}
/* exec the built binary with any trailing argv as its argv. */
pid_t pid = fork();
if (pid < 0) {
perror("ww: fork");
@@ -1823,7 +1789,6 @@ do_test(int argc, char **argv)
"ww test: package options need a directory\n");
return 2;
}
/* single .ww file — build, then run unless -c (compile-only). */
char tmpdir[1024] = {0}, tmp[1024];
const char *outp;
int owntmp = !outstem[0] && !workdir[0];