ww: implement package initialization

This commit is contained in:
2026-08-14 19:02:35 +09:00
parent 72e890d5aa
commit c6bec0914d
24 changed files with 5279 additions and 1009 deletions

View File

@@ -24,14 +24,26 @@ import os;
import syntax;
import strconv;
let wwiwritefailed: i32 = 0;
fn wwrite(fd: i32, p: *u8, n: u64) void = {
if (wwiwritefailed != 0) { return; };
match (os.writeall(fd, p, n)) {
case let wrote: i64 => {
if (wrote < 0 || (wrote: u64) != n) { wwiwritefailed = 1; };
};
case let e: os.oserror => wwiwritefailed = 1;
};
};
fn wputs(fd: i32, s: str) void = {
os.write(fd, s.ptr, s.len: u64);
wwrite(fd, s.ptr, s.len: u64);
};
fn wputb(fd: i32, b: u8) void = {
let buf: [1]u8;
buf[0] = b;
os.write(fd, buf.ptr, 1u64);
wwrite(fd, buf.ptr, 1u64);
};
fn wquote(fd: i32, s: str) void = {
@@ -59,7 +71,7 @@ fn wquote(fd: i32, s: str) void = {
buf[1] = 120u8;
buf[2] = h;
buf[3] = l;
os.write(fd, buf.ptr, 4u64);
wwrite(fd, buf.ptr, 4u64);
} else {
wputb(fd, c);
};};};};};
@@ -85,7 +97,8 @@ fn wwimodeq(a: str, b: str) bool = {
fn wwiusepath(c: *checker, owner: str, source: i32, alias: str) str = {
let u: *syntax.node = c.file.list;
for (u != nil) {
if (u.kind == syntax.nkind.N_USE && u.sourceid == source
if (u.kind == syntax.nkind.N_USE && u.useblank == 0
&& u.sourceid == source
&& syntax.streq(u.str, alias)) {
let same: bool = false;
if (owner.len == 0) {
@@ -301,7 +314,7 @@ fn wwirune(fd: i32, cp: u64) void = {
buf[1] = 120u8;
buf[2] = h;
buf[3] = l;
os.write(fd, buf.ptr, 4u64);
wwrite(fd, buf.ptr, 4u64);
} else {
wputb(fd, c);
};};};};};
@@ -591,6 +604,7 @@ fn wwiprimary(n: *syntax.node) bool = {
};
fn wwiisdecl(d: *syntax.node) bool = {
if (d.initfn != 0 || d.initsynthetic != 0) { return false; };
return d.kind == syntax.nkind.N_FNDECL || d.kind == syntax.nkind.N_TYPEDECL ||
d.kind == syntax.nkind.N_DEF || d.kind == syntax.nkind.N_LET;
};
@@ -887,7 +901,7 @@ fn wwisortfacts(fs: *wwifactset) void = {
};
fn wwiowneduse(u: *syntax.node, owner: str, source: i32) bool = {
return u.kind == syntax.nkind.N_USE && u.imported != 0
return u.kind == syntax.nkind.N_USE && u.useblank == 0 && u.imported != 0
&& u.sourceid == source && wwimodeq(u.nmod, owner);
};
@@ -900,7 +914,8 @@ fn wwiemitimports(fd: i32, file: *syntax.node, owner: str, source: i32,
if (imported) {
owned = wwiowneduse(u, owner, source);
} else {
owned = u.kind == syntax.nkind.N_USE && u.imported == 0
owned = u.kind == syntax.nkind.N_USE && u.useblank == 0
&& u.imported == 0
&& u.sourceid == source;
};
if (owned) { nuse += 1; };
@@ -916,7 +931,8 @@ fn wwiemitimports(fd: i32, file: *syntax.node, owner: str, source: i32,
if (imported) {
owned = wwiowneduse(u, owner, source);
} else {
owned = u.kind == syntax.nkind.N_USE && u.imported == 0
owned = u.kind == syntax.nkind.N_USE && u.useblank == 0
&& u.imported == 0
&& u.sourceid == source;
};
if (owned) {
@@ -944,7 +960,7 @@ fn wwiprimarysectionhas(c: *checker, file: *syntax.node,
source: i32) bool = {
let u: *syntax.node = file.list;
for (u != nil) {
if (u.kind == syntax.nkind.N_USE && u.imported == 0
if (u.kind == syntax.nkind.N_USE && u.useblank == 0 && u.imported == 0
&& u.sourceid == source) { return true; };
u = u.next;
};
@@ -1025,7 +1041,8 @@ fn wwiemitprimarysection(c: *checker, fd: i32, file: *syntax.node,
};
};
fn wwiemit(c: *checker, file: *syntax.node, path: str) i32 = {
fn wwiemitfd(c: *checker, file: *syntax.node, fd: i32) i32 = {
wwiwritefailed = 0;
// §5: check_exported_type FIRST, before any byte — a producer
// without it can emit a dangling `.wwi`.
let bad: i32 = 0;
@@ -1101,15 +1118,6 @@ fn wwiemit(c: *checker, file: *syntax.node, path: str) i32 = {
wwisortdecls(dkeys, dnodes, ndecl);
};
let fd: i32 = os.open(path,
os.flag.WRONLY | os.flag.CREATE | os.flag.TRUNC, 420i32); // 0o644
if (fd < 0) {
wputs(2, "w6c: cannot open ");
wputs(2, path);
wputs(2, "\n");
return 1i32;
};
// Canonical ownership, declared name, and lexical source scope are
// independent export facts. Repeated owner sections preserve the file
// that owns each binding while every symbol/action remains keyed by owner.
@@ -1154,6 +1162,5 @@ fn wwiemit(c: *checker, file: *syntax.node, path: str) i32 = {
fi += 1;
};
os.close(fd);
return 0i32;
return wwiwritefailed;
};