ww: lift introspection files to lib/ww/ (ast, lex, tok, parse, typ, sym)

This commit is contained in:
2026-05-11 16:17:23 +09:00
parent 3f8d64e01b
commit 177862fb29
16 changed files with 80 additions and 74 deletions

View File

@@ -101,39 +101,42 @@ $(OBJ)/w6l/%.o: cmd/w6l/%.c cmd/w6l/l.h | $(OBJ)/w6l
$(CC) $(CFLAGS) -Icmd/w6l -c -o $@ $<
# ---- ww-side wwdump (the lexer port, exercised by 990_selfhost) --------
# Built via the user-facing ww driver, with -I selfhost/cmd/wcc so it
# can find the lex/tok/mem ports. Output named wwdump_ww to avoid
# colliding with the C-side wwdump in $(BIN).
# Built via the user-facing ww driver. The introspection ports (lex,
# tok, ast, parse, typ, sym) live in lib/ww/; the compiler-only bits
# (mem, check, cgen*) stay in selfhost/cmd/wcc/. Output named wwdump_ww
# to avoid colliding with the C-side wwdump in $(BIN).
$(BIN)/wwdump_ww: selfhost/cmd/wwdump/main.ww \
selfhost/cmd/wcc/lex.ww selfhost/cmd/wcc/tok.ww \
selfhost/cmd/wcc/mem.ww selfhost/cmd/wcc/ast.ww \
selfhost/cmd/wcc/parse.ww selfhost/cmd/wcc/typ.ww \
selfhost/cmd/wcc/sym.ww selfhost/cmd/wcc/check.ww \
lib/ww/lex.ww lib/ww/tok.ww lib/ww/ast.ww \
lib/ww/parse.ww lib/ww/typ.ww lib/ww/sym.ww \
selfhost/cmd/wcc/mem.ww selfhost/cmd/wcc/check.ww \
selfhost/cmd/wcc/cgen.ww selfhost/cmd/wcc/cgen_expr.ww \
selfhost/cmd/wcc/cgen_stmt.ww selfhost/cmd/wcc/cgen_util.ww \
selfhost/cmd/wcc/cgen_decl.ww \
lib/os/os.ww lib/strconv/strconv.ww \
$(BIN)/ww $(BIN)/w6c $(BIN)/w6a $(BIN)/w6l \
$(LIB)/libwwrt.a | $(BIN)
cd $(BIN) && ./ww build -I $$PWD/../../selfhost/cmd/wcc \
cd $(BIN) && ./ww build \
-I $$PWD/../../lib/ww \
-I $$PWD/../../selfhost/cmd/wcc \
$$PWD/../../selfhost/cmd/wwdump/main.ww
mv $(BIN)/main $@
# ---- ww-side w6c (compiler port, exercised by 994_w6c_ww) -------------
# Thin driver: parse + cgen, both already living in selfhost/cmd/wcc.
# Build through `ww build` like the other wwstage tools.
# Thin driver: parse + cgen. The frontend (lex/parse/ast/...) lives in
# lib/ww/; cgen + check live in selfhost/cmd/wcc/.
$(BIN)/w6c_ww: selfhost/cmd/w6c/main.ww \
selfhost/cmd/wcc/lex.ww selfhost/cmd/wcc/tok.ww \
selfhost/cmd/wcc/mem.ww selfhost/cmd/wcc/ast.ww \
selfhost/cmd/wcc/parse.ww selfhost/cmd/wcc/typ.ww \
selfhost/cmd/wcc/sym.ww selfhost/cmd/wcc/check.ww \
lib/ww/lex.ww lib/ww/tok.ww lib/ww/ast.ww \
lib/ww/parse.ww lib/ww/typ.ww lib/ww/sym.ww \
selfhost/cmd/wcc/mem.ww selfhost/cmd/wcc/check.ww \
selfhost/cmd/wcc/cgen.ww selfhost/cmd/wcc/cgen_expr.ww \
selfhost/cmd/wcc/cgen_stmt.ww selfhost/cmd/wcc/cgen_util.ww \
selfhost/cmd/wcc/cgen_decl.ww \
lib/os/os.ww \
$(BIN)/ww $(BIN)/w6c $(BIN)/w6a $(BIN)/w6l \
$(LIB)/libwwrt.a | $(BIN)
cd $(BIN) && ./ww build -I $$PWD/../../selfhost/cmd/wcc \
cd $(BIN) && ./ww build \
-I $$PWD/../../lib/ww \
-I $$PWD/../../selfhost/cmd/wcc \
$$PWD/../../selfhost/cmd/w6c/main.ww
mv $(BIN)/main $@
@@ -392,7 +395,9 @@ nocc:
@# The driver's default lib path is $self_dir/../../lib — under
@# $(NOCC_BIN) that resolves to $(NOCC_OUT)/lib (libwwrt only).
@# Pass -I $(CURDIR)/lib so `use os` etc. resolve to source.
@cd $(NOCC_BIN) && ./ww build -I $(CURDIR)/selfhost/cmd/wcc \
@cd $(NOCC_BIN) && ./ww build \
-I $(CURDIR)/lib/ww \
-I $(CURDIR)/selfhost/cmd/wcc \
-I $(CURDIR)/lib $(CURDIR)/selfhost/cmd/w6c/main.ww && mv main w6c_ww1
@cd $(NOCC_BIN) && ./ww build -I $(CURDIR)/selfhost/cmd/w6a \
-I $(CURDIR)/selfhost/cmd/wcc -I $(CURDIR)/lib \

View File

@@ -115,7 +115,7 @@ locate_import(const char *dirs, const char *name, char *out, size_t outsz)
/* module_of — pick the source's containing-directory basename.
* lib/os/os.ww -> "os"
* selfhost/cmd/wcc/sym.ww -> "wcc"
* lib/ww/sym.ww -> "ww"
* bare "main.ww" -> "main"
* Writes into dst (size ≥ 1); always NUL-terminates. */
static void

View File

@@ -1,4 +1,4 @@
// selfhost/cmd/wcc/ast.ww — port of cmd/wcc/ast.c (Node defs + printer).
// lib/ww/ast.ww — port of cmd/wcc/ast.c (Node defs + printer).
//
// Status: AST printer is fully ported. Constructor `newnode` is here.
// The parser (parse.ww) is currently minimal — see its file header.

View File

@@ -1,4 +1,4 @@
// selfhost/cmd/wcc/lex.ww — port of cmd/wcc/lex.c.
// lib/ww/lex.ww — port of cmd/wcc/lex.c.
//
// The DFA, the helpers, and the order of decisions all mirror the C
// version exactly. The 990_selfhost test diffs the resulting token

View File

@@ -1,4 +1,4 @@
// selfhost/cmd/wcc/parse.ww — port of cmd/wcc/parse.c.
// lib/ww/parse.ww — port of cmd/wcc/parse.c.
//
// Status: GROWING stub. Currently handles top-level `use IDENT;`,
// `def NAME: TYPE = LIT;`, `type NAME = TYPE;`, and `fn NAME(params)

View File

@@ -1,4 +1,4 @@
// selfhost/cmd/wcc/sym.ww — port of cmd/wcc/sym.c.
// lib/ww/sym.ww — port of cmd/wcc/sym.c.
//
// Per-scope hashtable, chained to the parent. Lookup walks up.
// Plan 9 / Hare flavoured. Duplicate definitions in the same scope

View File

@@ -1,4 +1,4 @@
// selfhost/cmd/wcc/tok.ww — port of cmd/wcc/tok.c plus the Tkind /
// lib/ww/tok.ww — port of cmd/wcc/tok.c plus the Tkind /
// Tok / Pos shapes from cmd/wcc/ww.h.
//
// Token kind values must stay numerically equal to the C side: the

View File

@@ -1,4 +1,4 @@
// selfhost/cmd/wcc/type.ww — port of cmd/wcc/type.c.
// lib/ww/typ.ww — port of cmd/wcc/type.c.
//
// Status: full structural port. The C version uses module-globals for
// the primitive types (tyvoid, tyi32, …); ww doesn't have writable

View File

@@ -437,8 +437,8 @@ export fn parseu64(s: str) (u64 | str) = {
return v;
};
// MODULE: wcc
// selfhost/cmd/wcc/tok.ww — port of cmd/wcc/tok.c plus the Tkind /
// MODULE: ww
// lib/ww/tok.ww — port of cmd/wcc/tok.c plus the Tkind /
// Tok / Pos shapes from cmd/wcc/ww.h.
//
// Token kind values must stay numerically equal to the C side: the
@@ -927,8 +927,8 @@ export fn toupper(c: u8) u8 = {
return c;
};
// MODULE: wcc
// selfhost/cmd/wcc/lex.ww — port of cmd/wcc/lex.c.
// MODULE: ww
// lib/ww/lex.ww — port of cmd/wcc/lex.c.
//
// The DFA, the helpers, and the order of decisions all mirror the C
// version exactly. The 990_selfhost test diffs the resulting token
@@ -1616,8 +1616,8 @@ export fn lexnext(l: *lex, out: *tok) void = {
out.text = astrndup(l.a, one.ptr, 1u64);
};
// MODULE: wcc
// selfhost/cmd/wcc/ast.ww — port of cmd/wcc/ast.c (Node defs + printer).
// MODULE: ww
// lib/ww/ast.ww — port of cmd/wcc/ast.c (Node defs + printer).
//
// Status: AST printer is fully ported. Constructor `newnode` is here.
// The parser (parse.ww) is currently minimal — see its file header.
@@ -1954,8 +1954,8 @@ export fn astprint(fd: i32, n: *node) void = {
pr(fd, n, 0);
};
// MODULE: wcc
// selfhost/cmd/wcc/parse.ww — port of cmd/wcc/parse.c.
// MODULE: ww
// lib/ww/parse.ww — port of cmd/wcc/parse.c.
//
// Status: GROWING stub. Currently handles top-level `use IDENT;`,
// `def NAME: TYPE = LIT;`, `type NAME = TYPE;`, and `fn NAME(params)
@@ -2942,8 +2942,8 @@ export fn parsefile(p: *parser) *node = {
return f;
};
// MODULE: wcc
// selfhost/cmd/wcc/type.ww — port of cmd/wcc/type.c.
// MODULE: ww
// lib/ww/typ.ww — port of cmd/wcc/type.c.
//
// Status: full structural port. The C version uses module-globals for
// the primitive types (tyvoid, tyi32, …); ww doesn't have writable
@@ -3273,8 +3273,8 @@ export fn typeeq(a: *tinfo, b: *tinfo) bool = {
return true; // primitives match by kind alone
};
// MODULE: wcc
// selfhost/cmd/wcc/sym.ww — port of cmd/wcc/sym.c.
// MODULE: ww
// lib/ww/sym.ww — port of cmd/wcc/sym.c.
//
// Per-scope hashtable, chained to the parent. Lookup walks up.
// Plan 9 / Hare flavoured. Duplicate definitions in the same scope

View File

@@ -656,7 +656,7 @@ fn scanuse(src: *u8, len: u64) (*u8, u64) = {
// Recursively expand `path` into c.out. Imported files are emitted
// before their importer; cycles are broken via the visited set.
// modulename — pick the source's containing-directory basename. So
// `lib/os/os.ww` → "os"; `selfhost/cmd/wcc/sym.ww` → "wcc". Falls back
// `lib/os/os.ww` → "os"; `lib/ww/sym.ww` → "ww". Falls back
// to the file's own basename (sans .ww) when there is no parent dir.
// Returns ("",0) if `path` ends in a '/' (degenerate).
fn modulename(path: *u8, plen: u64) (*u8, u64) = {

View File

@@ -337,7 +337,7 @@ fn scanuse(src: *u8, len: u64) (*u8, u64) = {
// Recursively expand `path` into c.out. Imported files are emitted
// before their importer; cycles are broken via the visited set.
// modulename — pick the source's containing-directory basename. So
// `lib/os/os.ww` → "os"; `selfhost/cmd/wcc/sym.ww` → "wcc". Falls back
// `lib/os/os.ww` → "os"; `lib/ww/sym.ww` → "ww". Falls back
// to the file's own basename (sans .ww) when there is no parent dir.
// Returns ("",0) if `path` ends in a '/' (degenerate).
fn modulename(path: *u8, plen: u64) (*u8, u64) = {

View File

@@ -437,8 +437,8 @@ export fn parseu64(s: str) (u64 | str) = {
return v;
};
// MODULE: wcc
// selfhost/cmd/wcc/tok.ww — port of cmd/wcc/tok.c plus the Tkind /
// MODULE: ww
// lib/ww/tok.ww — port of cmd/wcc/tok.c plus the Tkind /
// Tok / Pos shapes from cmd/wcc/ww.h.
//
// Token kind values must stay numerically equal to the C side: the
@@ -927,8 +927,8 @@ export fn toupper(c: u8) u8 = {
return c;
};
// MODULE: wcc
// selfhost/cmd/wcc/lex.ww — port of cmd/wcc/lex.c.
// MODULE: ww
// lib/ww/lex.ww — port of cmd/wcc/lex.c.
//
// The DFA, the helpers, and the order of decisions all mirror the C
// version exactly. The 990_selfhost test diffs the resulting token
@@ -1616,8 +1616,8 @@ export fn lexnext(l: *lex, out: *tok) void = {
out.text = astrndup(l.a, one.ptr, 1u64);
};
// MODULE: wcc
// selfhost/cmd/wcc/ast.ww — port of cmd/wcc/ast.c (Node defs + printer).
// MODULE: ww
// lib/ww/ast.ww — port of cmd/wcc/ast.c (Node defs + printer).
//
// Status: AST printer is fully ported. Constructor `newnode` is here.
// The parser (parse.ww) is currently minimal — see its file header.
@@ -1954,8 +1954,8 @@ export fn astprint(fd: i32, n: *node) void = {
pr(fd, n, 0);
};
// MODULE: wcc
// selfhost/cmd/wcc/parse.ww — port of cmd/wcc/parse.c.
// MODULE: ww
// lib/ww/parse.ww — port of cmd/wcc/parse.c.
//
// Status: GROWING stub. Currently handles top-level `use IDENT;`,
// `def NAME: TYPE = LIT;`, `type NAME = TYPE;`, and `fn NAME(params)
@@ -2942,8 +2942,8 @@ export fn parsefile(p: *parser) *node = {
return f;
};
// MODULE: wcc
// selfhost/cmd/wcc/type.ww — port of cmd/wcc/type.c.
// MODULE: ww
// lib/ww/typ.ww — port of cmd/wcc/type.c.
//
// Status: full structural port. The C version uses module-globals for
// the primitive types (tyvoid, tyi32, …); ww doesn't have writable
@@ -3273,8 +3273,8 @@ export fn typeeq(a: *tinfo, b: *tinfo) bool = {
return true; // primitives match by kind alone
};
// MODULE: wcc
// selfhost/cmd/wcc/sym.ww — port of cmd/wcc/sym.c.
// MODULE: ww
// lib/ww/sym.ww — port of cmd/wcc/sym.c.
//
// Per-scope hashtable, chained to the parent. Lookup walks up.
// Plan 9 / Hare flavoured. Duplicate definitions in the same scope

View File

@@ -3,7 +3,7 @@
// `type NAME = TYPE;` (alias + struct), top-level `let NAME: TYPE = LIT;`.
//
// Function declarations are still recovered past — the body parser
// is the next major chunk. See selfhost/cmd/wcc/parse.ww header.
// is the next major chunk. See lib/ww/parse.ww header.
use os;
use mem;

View File

@@ -171,10 +171,10 @@ probe_dump_diff(const char *bin)
const char *tok_inputs[] = {
"selfhost/cmd/wcc/mem.ww",
"selfhost/cmd/wcc/err.ww",
"selfhost/cmd/wcc/lex.ww",
"selfhost/cmd/wcc/tok.ww",
"selfhost/cmd/wcc/ast.ww",
"selfhost/cmd/wcc/parse.ww",
"lib/ww/lex.ww",
"lib/ww/tok.ww",
"lib/ww/ast.ww",
"lib/ww/parse.ww",
"selfhost/cmd/wwdump/main.ww",
"selfhost/test/smoke.ww",
NULL,
@@ -188,12 +188,12 @@ probe_dump_diff(const char *bin)
"selfhost/test/uses.ww",
"selfhost/cmd/wcc/err.ww",
"selfhost/cmd/wcc/mem.ww",
"selfhost/cmd/wcc/lex.ww",
"selfhost/cmd/wcc/tok.ww",
"selfhost/cmd/wcc/ast.ww",
"selfhost/cmd/wcc/parse.ww",
"selfhost/cmd/wcc/typ.ww",
"selfhost/cmd/wcc/sym.ww",
"lib/ww/lex.ww",
"lib/ww/tok.ww",
"lib/ww/ast.ww",
"lib/ww/parse.ww",
"lib/ww/typ.ww",
"lib/ww/sym.ww",
"selfhost/cmd/wcc/check.ww",
"selfhost/cmd/wcc/cgen.ww",
"selfhost/cmd/wwdump/main.ww",
@@ -435,7 +435,7 @@ probe_resolve(const char *bin)
const char *complete[] = {
"selfhost/cmd/wcc/err.ww",
"selfhost/cmd/wcc/mem.ww",
"selfhost/cmd/wcc/tok.ww",
"lib/ww/tok.ww",
"selfhost/test/smoke.ww",
NULL,
};
@@ -656,8 +656,8 @@ probe_ww_links(const char *bin)
runwait(cmd);
/* ww build to get the .combined.ww as a side effect. */
snprintf(cmd, sizeof cmd,
"cd %s && %s/ww build -I %s/selfhost/cmd/wcc %s >/dev/null 2>&1",
tmpdir, bin, cwd, tmpsrc);
"cd %s && %s/ww build -I %s/lib/ww -I %s/selfhost/cmd/wcc %s >/dev/null 2>&1",
tmpdir, bin, cwd, cwd, tmpsrc);
if (runwait(cmd) != 0) {
fprintf(stderr, "ww-links FAIL: ww build %s\n", fix);
fail++;
@@ -717,7 +717,7 @@ probe_cgen_match(const char *bin)
const char *files[] = {
"selfhost/cmd/wcc/mem.ww",
"selfhost/cmd/wcc/err.ww",
"selfhost/cmd/wcc/tok.ww",
"lib/ww/tok.ww",
"selfhost/test/smoke.ww",
NULL,
};

View File

@@ -152,8 +152,8 @@ main(void)
* regardless of the per-driver workdir. */
static char wwdump_src[2048], wwdump_inc_a[2048], wwdump_inc_b[2048];
snprintf(wwdump_src, sizeof wwdump_src, "%s/selfhost/cmd/wwdump/main.ww", cwd);
snprintf(wwdump_inc_a, sizeof wwdump_inc_a, "%s/selfhost/cmd/wcc", cwd);
wwdump_inc_b[0] = '\0';
snprintf(wwdump_inc_a, sizeof wwdump_inc_a, "%s/lib/ww", cwd);
snprintf(wwdump_inc_b, sizeof wwdump_inc_b, "%s/selfhost/cmd/wcc", cwd);
cases[1].src = wwdump_src;
cases[1].inc_a = wwdump_inc_a;
cases[1].inc_b = wwdump_inc_b;

View File

@@ -59,10 +59,11 @@ slurp_eq(const char *a, const char *b)
return rc;
}
/* Each tool builds via `ww_ww build -I <local> -I selfhost/cmd/wcc src`.
* Some tools have a local module dir (w6a, w6l with sibling .ww files);
* wwc-only tools (w6c, ww, wwdump) just need the wwc -I. inc_local is
* "" for those.
/* Each tool builds via `ww_ww build -I <local> -I lib/ww -I selfhost/cmd/wcc src`.
* lib/ww holds the language introspection (lex/tok/ast/parse/typ/sym);
* selfhost/cmd/wcc holds the compiler internals (mem/check/cgen*).
* Some tools have a local module dir (w6a, w6l with sibling .ww files).
* inc_local is "" for tools without one (w6c, ww, wwdump).
*/
static int
rebuild_one(const char *bin, const char *cwd, const char *tool,
@@ -76,14 +77,14 @@ rebuild_one(const char *bin, const char *cwd, const char *tool,
if (inc_local && inc_local[0]) {
snprintf(cmd, sizeof cmd,
"cd %s && %s/ww_ww build -I %s/%s -I %s/selfhost/cmd/wcc "
"cd %s && %s/ww_ww build -I %s/%s -I %s/lib/ww -I %s/selfhost/cmd/wcc "
"%s/%s >/dev/null 2>&1",
workdir, bin, cwd, inc_local, cwd, cwd, src_rel);
workdir, bin, cwd, inc_local, cwd, cwd, cwd, src_rel);
} else {
snprintf(cmd, sizeof cmd,
"cd %s && %s/ww_ww build -I %s/selfhost/cmd/wcc "
"cd %s && %s/ww_ww build -I %s/lib/ww -I %s/selfhost/cmd/wcc "
"%s/%s >/dev/null 2>&1",
workdir, bin, cwd, cwd, src_rel);
workdir, bin, cwd, cwd, cwd, src_rel);
}
if (runwait(cmd) != 0) {
fprintf(stderr, "self-rebuild FAIL: ww_ww build errored on %s\n", tool);