ww: separate package identity from declared name
This commit is contained in:
@@ -82,24 +82,11 @@ fn wwimodeq(a: str, b: str) bool = {
|
||||
// Map an import alias in the source package that owns the reference. The
|
||||
// flattened parser file contains every imported interface's N_USE nodes, so
|
||||
// this owner filter is what prevents cross-package alias capture.
|
||||
fn wwiusepath(c: *checker, owner: str, alias: str) str = {
|
||||
if (owner.len > 0) {
|
||||
let dotidx: i32 = -1;
|
||||
let i: i32 = 0;
|
||||
for (i < owner.len) {
|
||||
if (owner[i] == 46u8) { dotidx = i; };
|
||||
i += 1;
|
||||
};
|
||||
let leaf: str = owner;
|
||||
if (dotidx >= 0) {
|
||||
leaf.ptr = owner.ptr + ((dotidx + 1): u64);
|
||||
leaf.len = owner.len - dotidx - 1;
|
||||
};
|
||||
if (syntax.streq(alias, leaf)) { return owner; };
|
||||
};
|
||||
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 && syntax.streq(u.str, alias)) {
|
||||
if (u.kind == syntax.nkind.N_USE && u.sourceid == source
|
||||
&& syntax.streq(u.str, alias)) {
|
||||
let same: bool = false;
|
||||
if (owner.len == 0) {
|
||||
same = u.imported == 0;
|
||||
@@ -117,24 +104,27 @@ fn wwiusepath(c: *checker, owner: str, alias: str) str = {
|
||||
return empty;
|
||||
};
|
||||
|
||||
fn wwidirectmodvisible(c: *checker, owner: str, mod: str) bool = {
|
||||
fn wwidirectmodvisible(c: *checker, owner: str, source: i32, mod: str) bool = {
|
||||
if (mod.len == 0) { return false; };
|
||||
let dotidx: i32 = -1;
|
||||
let i: i32 = 0;
|
||||
for (i < mod.len) {
|
||||
if (mod[i] == 46u8) { dotidx = i; };
|
||||
i += 1;
|
||||
let u: *syntax.node = c.file.list;
|
||||
for (u != nil) {
|
||||
if (u.kind == syntax.nkind.N_USE && u.sourceid == source) {
|
||||
let same: bool = false;
|
||||
if (owner.len == 0) {
|
||||
same = u.imported == 0;
|
||||
} else {
|
||||
same = u.imported != 0 && wwimodeq(u.nmod, owner);
|
||||
};
|
||||
let path: str = u.str;
|
||||
if (u.usepath.len > 0) { path = u.usepath; };
|
||||
if (same && syntax.streq(path, mod)) { return true; };
|
||||
};
|
||||
u = u.next;
|
||||
};
|
||||
let alias: str = mod;
|
||||
if (dotidx >= 0) {
|
||||
alias.ptr = mod.ptr + ((dotidx + 1): u64);
|
||||
alias.len = mod.len - dotidx - 1;
|
||||
};
|
||||
let path: str = wwiusepath(c, owner, alias);
|
||||
return path.len > 0 && syntax.streq(path, mod);
|
||||
return false;
|
||||
};
|
||||
|
||||
fn wwitypesym(c: *checker, owner: str, nm: str) *syntax.sym = {
|
||||
fn wwitypesym(c: *checker, owner: str, source: i32, nm: str) *syntax.sym = {
|
||||
let dotidx: i32 = -1;
|
||||
let i: i32 = 0;
|
||||
for (i < nm.len) {
|
||||
@@ -149,7 +139,7 @@ fn wwitypesym(c: *checker, owner: str, nm: str) *syntax.sym = {
|
||||
let leaf: str;
|
||||
leaf.ptr = nm.ptr + ((dotidx + 1): u64);
|
||||
leaf.len = nm.len - dotidx - 1;
|
||||
let mod: str = wwiusepath(c, owner, head);
|
||||
let mod: str = wwiusepath(c, owner, source, head);
|
||||
if (mod.len > 0) {
|
||||
s = syntax.scopelookupinmodule(c.cur, mod, leaf);
|
||||
};
|
||||
@@ -162,7 +152,7 @@ fn wwitypesym(c: *checker, owner: str, nm: str) *syntax.sym = {
|
||||
for (b != nil) {
|
||||
if (b.skind == syntax.skind.SK_TYPE
|
||||
&& syntax.streq(b.name, nm)
|
||||
&& wwidirectmodvisible(c, owner, b.mod)) {
|
||||
&& wwidirectmodvisible(c, owner, source, b.mod)) {
|
||||
s = b;
|
||||
break;
|
||||
};
|
||||
@@ -669,7 +659,8 @@ fn wwifactsame(mod: str, rank: i32, d: *syntax.node,
|
||||
return rank == srank && wwimodeq(mod, smod) && syntax.streq(d.str, sd.str);
|
||||
};
|
||||
|
||||
fn wwifactvaluesym(c: *checker, owner: str, name: str) *syntax.sym = {
|
||||
fn wwifactvaluesym(c: *checker, owner: str, source: i32,
|
||||
name: str) *syntax.sym = {
|
||||
let p: *syntax.scope = c.top;
|
||||
for (p != nil) {
|
||||
let s: *syntax.sym = p.first;
|
||||
@@ -685,7 +676,7 @@ fn wwifactvaluesym(c: *checker, owner: str, name: str) *syntax.sym = {
|
||||
let s: *syntax.sym = p.first;
|
||||
for (s != nil) {
|
||||
if (s.skind == syntax.skind.SK_DEF && syntax.streq(s.name, name)
|
||||
&& wwidirectmodvisible(c, owner, s.mod)) { return s; };
|
||||
&& wwidirectmodvisible(c, owner, source, s.mod)) { return s; };
|
||||
s = s.snext;
|
||||
};
|
||||
p = p.parent;
|
||||
@@ -757,27 +748,30 @@ fn wwicollectdecl(fs: *wwifactset, owner: str, d: *syntax.node) void = {
|
||||
|
||||
if (d.kind == syntax.nkind.N_FNDECL) {
|
||||
let p: *syntax.node = d.list;
|
||||
for (p != nil) { wwicollecttype(fs, owner, p.lhs); p = p.next; };
|
||||
wwicollecttype(fs, owner, d.lhs);
|
||||
for (p != nil) { wwicollecttype(fs, owner, d.sourceid, p.lhs); p = p.next; };
|
||||
wwicollecttype(fs, owner, d.sourceid, d.lhs);
|
||||
} else { if (d.kind == syntax.nkind.N_TYPEDECL) {
|
||||
wwicollecttype(fs, owner, d.lhs);
|
||||
wwicollecttype(fs, owner, d.sourceid, d.lhs);
|
||||
} else { if (d.kind == syntax.nkind.N_DEF) {
|
||||
wwicollecttype(fs, owner, d.lhs);
|
||||
wwicollectexpr(fs, owner, d.rhs);
|
||||
wwicollecttype(fs, owner, d.sourceid, d.lhs);
|
||||
wwicollectexpr(fs, owner, d.sourceid, d.rhs);
|
||||
} else { if (d.kind == syntax.nkind.N_LET) {
|
||||
wwicollecttype(fs, owner, d.lhs);
|
||||
wwicollecttype(fs, owner, d.sourceid, d.lhs);
|
||||
};};};};
|
||||
};
|
||||
|
||||
fn wwicollectexpr(fs: *wwifactset, owner: str, e: *syntax.node) void = {
|
||||
fn wwicollectexpr(fs: *wwifactset, owner: str, source: i32,
|
||||
e: *syntax.node) void = {
|
||||
if (e == nil) { return; };
|
||||
let s: *syntax.sym = nil;
|
||||
if (e.kind == syntax.nkind.N_IDENT) {
|
||||
s = wwifactvaluesym(fs.c, owner, e.str);
|
||||
s = wwifactvaluesym(fs.c, owner, source, e.str);
|
||||
} else { if (e.kind == syntax.nkind.N_DOT && e.lhs != nil) {
|
||||
if (e.lhs.kind == syntax.nkind.N_IDENT) {
|
||||
let mod: str = wwiusepath(fs.c, owner, e.lhs.str);
|
||||
if (mod.len > 0) { s = wwifactvaluesym(fs.c, mod, e.str); };
|
||||
let mod: str = wwiusepath(fs.c, owner, source, e.lhs.str);
|
||||
if (mod.len > 0) {
|
||||
s = wwifactvaluesym(fs.c, mod, source, e.str);
|
||||
};
|
||||
};
|
||||
}; };
|
||||
if (s != nil && s.decl != nil) {
|
||||
@@ -790,30 +784,37 @@ fn wwicollectexpr(fs: *wwifactset, owner: str, e: *syntax.node) void = {
|
||||
return;
|
||||
};
|
||||
if (e.kind == syntax.nkind.N_BIN) {
|
||||
wwicollectexpr(fs, owner, e.lhs);
|
||||
wwicollectexpr(fs, owner, e.rhs);
|
||||
wwicollectexpr(fs, owner, source, e.lhs);
|
||||
wwicollectexpr(fs, owner, source, e.rhs);
|
||||
} else { if (e.kind == syntax.nkind.N_UN) {
|
||||
wwicollectexpr(fs, owner, e.lhs);
|
||||
wwicollectexpr(fs, owner, source, e.lhs);
|
||||
} else { if (e.kind == syntax.nkind.N_CAST) {
|
||||
wwicollectexpr(fs, owner, e.lhs);
|
||||
wwicollecttype(fs, owner, e.rhs);
|
||||
wwicollectexpr(fs, owner, source, e.lhs);
|
||||
wwicollecttype(fs, owner, source, e.rhs);
|
||||
}; }; };
|
||||
};
|
||||
|
||||
fn wwievalconst(fs: *wwifactset, owner: str, e: *syntax.node,
|
||||
fn wwievalconst(fs: *wwifactset, owner: str, source: i32, e: *syntax.node,
|
||||
out: *u64) bool = {
|
||||
let saved: str = fs.c.curmod;
|
||||
let savesource: i32 = fs.c.cursource;
|
||||
fs.c.curmod = owner;
|
||||
fs.c.cursource = source;
|
||||
let ok: bool = evaldefconst(fs.c, e, out, 0);
|
||||
fs.c.curmod = saved;
|
||||
fs.c.cursource = savesource;
|
||||
return ok;
|
||||
};
|
||||
|
||||
fn wwicollecttype(fs: *wwifactset, owner: str, t: *syntax.node) void = {
|
||||
fn wwicollecttype(fs: *wwifactset, owner: str, source: i32,
|
||||
t: *syntax.node) void = {
|
||||
if (t == nil) { return; };
|
||||
if (t.kind == syntax.nkind.N_TPARAM) { wwicollecttype(fs, owner, t.lhs); return; };
|
||||
if (t.kind == syntax.nkind.N_TPARAM) {
|
||||
wwicollecttype(fs, owner, source, t.lhs);
|
||||
return;
|
||||
};
|
||||
if (t.kind == syntax.nkind.N_TNAME) {
|
||||
let s: *syntax.sym = wwitypesym(fs.c, owner, t.str);
|
||||
let s: *syntax.sym = wwitypesym(fs.c, owner, source, t.str);
|
||||
if (s != nil && s.decl != nil) {
|
||||
if (s.decl.kind == syntax.nkind.N_TYPEDECL) {
|
||||
wwicollectdecl(fs, s.mod, s.decl);
|
||||
@@ -823,14 +824,14 @@ fn wwicollecttype(fs: *wwifactset, owner: str, t: *syntax.node) void = {
|
||||
t.kind == syntax.nkind.N_TPTR || t.kind == syntax.nkind.N_TSLICE ||
|
||||
t.kind == syntax.nkind.N_TBANG || t.kind == syntax.nkind.N_TCHAN
|
||||
) {
|
||||
wwicollecttype(fs, owner, t.lhs);
|
||||
wwicollecttype(fs, owner, source, t.lhs);
|
||||
} else { if (t.kind == syntax.nkind.N_TARRAY) {
|
||||
// Array length is resolved type identity, not a source name
|
||||
// dependency. Canonicalize it so private constants stay private
|
||||
// and consumers never need implementation defs merely for layout.
|
||||
if (t.rhs != nil && t.rhs.kind != syntax.nkind.N_INTLIT) {
|
||||
let len: u64 = 0u64;
|
||||
if (!wwievalconst(fs, owner, t.rhs, &len)) {
|
||||
if (!wwievalconst(fs, owner, source, t.rhs, &len)) {
|
||||
wwiencodearrayreject(t);
|
||||
fs.bad = 1;
|
||||
} else {
|
||||
@@ -841,19 +842,19 @@ fn wwicollecttype(fs: *wwifactset, owner: str, t: *syntax.node) void = {
|
||||
let empty: str; e.tsuffix = empty;
|
||||
};
|
||||
};
|
||||
wwicollecttype(fs, owner, t.lhs);
|
||||
wwicollecttype(fs, owner, source, t.lhs);
|
||||
} else { if (t.kind == syntax.nkind.N_TFN) {
|
||||
let p: *syntax.node = t.list;
|
||||
for (p != nil) { wwicollecttype(fs, owner, p.lhs); p = p.next; };
|
||||
wwicollecttype(fs, owner, t.lhs);
|
||||
for (p != nil) { wwicollecttype(fs, owner, source, p.lhs); p = p.next; };
|
||||
wwicollecttype(fs, owner, source, t.lhs);
|
||||
} else { if (t.kind == syntax.nkind.N_TSTRUCT) {
|
||||
let f: *syntax.node = t.list;
|
||||
for (f != nil) { wwicollecttype(fs, owner, f.lhs); f = f.next; };
|
||||
for (f != nil) { wwicollecttype(fs, owner, source, f.lhs); f = f.next; };
|
||||
} else { if (t.kind == syntax.nkind.N_TTAGGED || t.kind == syntax.nkind.N_TTUPLE) {
|
||||
let e: *syntax.node = t.list;
|
||||
for (e != nil) { wwicollecttype(fs, owner, e); e = e.next; };
|
||||
for (e != nil) { wwicollecttype(fs, owner, source, e); e = e.next; };
|
||||
} else { if (t.kind == syntax.nkind.N_TENUM) {
|
||||
wwicollecttype(fs, owner, t.lhs);
|
||||
wwicollecttype(fs, owner, source, t.lhs);
|
||||
// Member identifiers refer to prior siblings in this enum, not
|
||||
// package defs; the declaration already carries the whole list.
|
||||
};};};};};};};
|
||||
@@ -866,6 +867,9 @@ fn wwisortfacts(fs: *wwifactset) void = {
|
||||
let j: i32 = i + 1;
|
||||
for (j < fs.nfacts) {
|
||||
let r: i32 = wwistrcmp(fs.factmods[j], fs.factmods[best]);
|
||||
if (r == 0) {
|
||||
r = fs.factnodes[j].sourceid - fs.factnodes[best].sourceid;
|
||||
};
|
||||
if (r == 0) { r = fs.factranks[j] - fs.factranks[best]; };
|
||||
if (r == 0) { r = wwistrcmp(fs.factnodes[j].str, fs.factnodes[best].str); };
|
||||
if (r < 0) { best = j; };
|
||||
@@ -880,22 +884,40 @@ fn wwisortfacts(fs: *wwifactset) void = {
|
||||
};
|
||||
};
|
||||
|
||||
fn wwiowneduse(u: *syntax.node, owner: str) bool = {
|
||||
fn wwiowneduse(u: *syntax.node, owner: str, source: i32) bool = {
|
||||
return u.kind == syntax.nkind.N_USE && u.imported != 0
|
||||
&& syntax.streq(u.nmod, owner);
|
||||
&& u.sourceid == source && wwimodeq(u.nmod, owner);
|
||||
};
|
||||
|
||||
fn wwiemitfactimports(fd: i32, file: *syntax.node, owner: str) void = {
|
||||
fn wwiemitimports(fd: i32, file: *syntax.node, owner: str, source: i32,
|
||||
imported: bool) void = {
|
||||
let nuse: i32 = 0;
|
||||
let u: *syntax.node = file.list;
|
||||
for (u != nil) { if (wwiowneduse(u, owner)) { nuse += 1; }; u = u.next; };
|
||||
for (u != nil) {
|
||||
let owned: bool = false;
|
||||
if (imported) {
|
||||
owned = wwiowneduse(u, owner, source);
|
||||
} else {
|
||||
owned = u.kind == syntax.nkind.N_USE && u.imported == 0
|
||||
&& u.sourceid == source;
|
||||
};
|
||||
if (owned) { nuse += 1; };
|
||||
u = u.next;
|
||||
};
|
||||
if (nuse == 0) { return; };
|
||||
let paths: []str = alloc([], nuse: u64)!; paths.len = nuse;
|
||||
let nodes: []*syntax.node = alloc([], nuse: u64)!; nodes.len = nuse;
|
||||
let k: i32 = 0;
|
||||
u = file.list;
|
||||
for (u != nil) {
|
||||
if (wwiowneduse(u, owner)) {
|
||||
let owned: bool = false;
|
||||
if (imported) {
|
||||
owned = wwiowneduse(u, owner, source);
|
||||
} else {
|
||||
owned = u.kind == syntax.nkind.N_USE && u.imported == 0
|
||||
&& u.sourceid == source;
|
||||
};
|
||||
if (owned) {
|
||||
if (u.usepath.len > 0) { paths[k] = u.usepath; } else { paths[k] = u.str; };
|
||||
nodes[k] = u;
|
||||
k += 1;
|
||||
@@ -914,6 +936,85 @@ fn wwiemitfactimports(fd: i32, file: *syntax.node, owner: str) void = {
|
||||
};
|
||||
};
|
||||
|
||||
fn wwiprimarysectionhas(c: *checker, file: *syntax.node,
|
||||
fs: *wwifactset, exports: []*syntax.node, nexports: i32,
|
||||
source: i32) bool = {
|
||||
let u: *syntax.node = file.list;
|
||||
for (u != nil) {
|
||||
if (u.kind == syntax.nkind.N_USE && u.imported == 0
|
||||
&& u.sourceid == source) { return true; };
|
||||
u = u.next;
|
||||
};
|
||||
let i: i32 = 0;
|
||||
for (i < fs.nprivate) {
|
||||
if (fs.privatenodes[i].sourceid == source) { return true; };
|
||||
i += 1;
|
||||
};
|
||||
i = 0;
|
||||
for (i < nexports) {
|
||||
if (exports[i].sourceid == source) { return true; };
|
||||
i += 1;
|
||||
};
|
||||
if (c.istestpackage != 0) {
|
||||
let d: *syntax.node = file.list;
|
||||
for (d != nil) {
|
||||
if (wwiprimary(d) && d.sourceid == source
|
||||
&& d.kind == syntax.nkind.N_FNDECL && d.exported == 0
|
||||
&& wwihasattr(d, "test")) { return true; };
|
||||
d = d.next;
|
||||
};
|
||||
};
|
||||
return false;
|
||||
};
|
||||
|
||||
fn wwifirstprimarysource(file: *syntax.node) i32 = {
|
||||
let found: bool = false;
|
||||
let source: i32 = 0;
|
||||
let d: *syntax.node = file.list;
|
||||
for (d != nil) {
|
||||
if (wwiprimary(d) && (!found || d.sourceid < source)) {
|
||||
source = d.sourceid;
|
||||
found = true;
|
||||
};
|
||||
d = d.next;
|
||||
};
|
||||
if (found) { return source; };
|
||||
return file.sourceid;
|
||||
};
|
||||
|
||||
fn wwiemitprimarysection(c: *checker, fd: i32, file: *syntax.node,
|
||||
fs: *wwifactset, exports: []*syntax.node, nexports: i32,
|
||||
owner: str, pkgname: str, source: i32) void = {
|
||||
if (owner.len > 0) {
|
||||
wputs(fd, "//ww:module "); wputs(fd, owner); wputs(fd, "\n");
|
||||
};
|
||||
let pkg: str = pkgname;
|
||||
if (pkg.len == 0) { pkg = "main"; };
|
||||
wputs(fd, "package "); wputs(fd, pkg); wputs(fd, ";\n");
|
||||
wwiemitimports(fd, file, owner, source, false);
|
||||
let i: i32 = 0;
|
||||
for (i < fs.nprivate) {
|
||||
if (fs.privatenodes[i].sourceid == source) {
|
||||
wwidecl(fd, fs.privatenodes[i]);
|
||||
};
|
||||
i += 1;
|
||||
};
|
||||
if (c.istestpackage != 0) {
|
||||
let d: *syntax.node = file.list;
|
||||
for (d != nil) {
|
||||
if (wwiprimary(d) && d.sourceid == source
|
||||
&& d.kind == syntax.nkind.N_FNDECL && d.exported == 0
|
||||
&& wwihasattr(d, "test")) { wwidecl(fd, d); };
|
||||
d = d.next;
|
||||
};
|
||||
};
|
||||
i = 0;
|
||||
for (i < nexports) {
|
||||
if (exports[i].sourceid == source) { wwidecl(fd, exports[i]); };
|
||||
i += 1;
|
||||
};
|
||||
};
|
||||
|
||||
fn wwiemit(c: *checker, file: *syntax.node, path: str) i32 = {
|
||||
// §5: check_exported_type FIRST, before any byte — a producer
|
||||
// without it can emit a dangling `.wwi`.
|
||||
@@ -959,140 +1060,24 @@ fn wwiemit(c: *checker, file: *syntax.node, path: str) i32 = {
|
||||
wwisortdecls(fs.privatekeys, fs.privatenodes, fs.nprivate);
|
||||
wwisortfacts(&fs);
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
// package line: leaf of the first primary decl's module tag.
|
||||
let pkg: str = "main";
|
||||
let found: i32 = 0;
|
||||
let pd: *syntax.node = file.list;
|
||||
for (pd != nil) {
|
||||
if (wwiprimary(pd) && pd.nmod.len > 0) {
|
||||
let dotidx: i32 = -1;
|
||||
let i: i32 = 0;
|
||||
for (i < pd.nmod.len) {
|
||||
if (pd.nmod[i] == 46u8) { dotidx = i; };
|
||||
i += 1;
|
||||
};
|
||||
if (dotidx >= 0) {
|
||||
let leaf: str;
|
||||
leaf.ptr = pd.nmod.ptr + ((dotidx + 1): u64);
|
||||
leaf.len = pd.nmod.len - dotidx - 1;
|
||||
pkg = leaf;
|
||||
} else {
|
||||
pkg = pd.nmod;
|
||||
};
|
||||
found = 1;
|
||||
pd = nil;
|
||||
} else {
|
||||
pd = pd.next;
|
||||
};
|
||||
};
|
||||
// #11: a decl-less / export-less primary body carries no
|
||||
// module-tagged decl, so the scan above finds nothing; fall back to
|
||||
// the primary module identity stamped on the N_FILE node at parse
|
||||
// time. A raw single-file `package main` root arrives via a bare reset
|
||||
// and leaves file.nmod empty, so it stays "main". The detector is
|
||||
// scan-miss (found==0), NOT pkg=="main", to match cstage byte-for-
|
||||
// byte (rule 10) when a tagged decl legitimately leafs to "main".
|
||||
if (found == 0 && file.nmod.len > 0) {
|
||||
let dotidx: i32 = -1;
|
||||
let i: i32 = 0;
|
||||
for (i < file.nmod.len) {
|
||||
if (file.nmod[i] == 46u8) { dotidx = i; };
|
||||
i += 1;
|
||||
};
|
||||
if (dotidx >= 0) {
|
||||
let leaf: str;
|
||||
leaf.ptr = file.nmod.ptr + ((dotidx + 1): u64);
|
||||
leaf.len = file.nmod.len - dotidx - 1;
|
||||
pkg = leaf;
|
||||
} else {
|
||||
pkg = file.nmod;
|
||||
};
|
||||
};
|
||||
if (file.nmod.len > 0) {
|
||||
wputs(fd, "//ww:module "); wputs(fd, file.nmod); wputs(fd, "\n");
|
||||
};
|
||||
wputs(fd, "package ");
|
||||
wputs(fd, pkg);
|
||||
wputs(fd, ";\n");
|
||||
|
||||
// imports — primary N_USE, byte-sorted by import path.
|
||||
let nuse: i32 = 0;
|
||||
let u: *syntax.node = file.list;
|
||||
for (u != nil) {
|
||||
if (u.kind == syntax.nkind.N_USE && wwiprimary(u)) { nuse += 1; };
|
||||
u = u.next;
|
||||
};
|
||||
if (nuse > 0) {
|
||||
let upaths: []str = alloc([], nuse: u64)!;
|
||||
upaths.len = nuse;
|
||||
let unodes: []*syntax.node = alloc([], nuse: u64)!;
|
||||
unodes.len = nuse;
|
||||
let k: i32 = 0;
|
||||
u = file.list;
|
||||
for (u != nil) {
|
||||
if (u.kind == syntax.nkind.N_USE && wwiprimary(u)) {
|
||||
if (u.usepath.len > 0) { upaths[k] = u.usepath; } else { upaths[k] = u.str; };
|
||||
unodes[k] = u;
|
||||
k += 1;
|
||||
};
|
||||
u = u.next;
|
||||
};
|
||||
wwisortdecls(upaths, unodes, nuse);
|
||||
let i: i32 = 0;
|
||||
let previous: str = "";
|
||||
for (i < nuse) {
|
||||
if (previous.len == 0 || !syntax.streq(previous, upaths[i])) {
|
||||
wputs(fd, "import ");
|
||||
wputs(fd, upaths[i]);
|
||||
wputs(fd, ";\n");
|
||||
previous = upaths[i];
|
||||
};
|
||||
i += 1;
|
||||
};
|
||||
};
|
||||
|
||||
// Compiler-private owner nominals precede public declarations. They are
|
||||
// available to export decoding but remain absent from source visibility.
|
||||
let pri: i32 = 0;
|
||||
for (pri < fs.nprivate) {
|
||||
wwidecl(fd, fs.privatenodes[pri]);
|
||||
pri += 1;
|
||||
};
|
||||
|
||||
// Package-test metadata is private and deterministic. Only the distinct
|
||||
// generated-main package consumes these declarations through --import.
|
||||
if (c.istestpackage != 0) {
|
||||
d = file.list;
|
||||
for (d != nil) {
|
||||
if (wwiprimary(d) && d.kind == syntax.nkind.N_FNDECL
|
||||
&& d.exported == 0 && wwihasattr(d, "test")) {
|
||||
wwidecl(fd, d);
|
||||
};
|
||||
d = d.next;
|
||||
};
|
||||
};
|
||||
|
||||
// decls — exported primary, byte-sorted by symbol name.
|
||||
// Exported declarations are sorted within their source-file sections.
|
||||
let ndecl: i32 = 0;
|
||||
d = file.list;
|
||||
for (d != nil) {
|
||||
if (wwiprimary(d) && d.exported != 0 && wwiisdecl(d)) { ndecl += 1; };
|
||||
if (wwiprimary(d) && d.exported != 0 && wwiisdecl(d)) {
|
||||
ndecl += 1;
|
||||
};
|
||||
d = d.next;
|
||||
};
|
||||
let dkeys: []str;
|
||||
let dnodes: []*syntax.node;
|
||||
if (ndecl > 0) {
|
||||
let dkeys: []str = alloc([], ndecl: u64)!;
|
||||
dkeys.len = ndecl;
|
||||
let dnodes: []*syntax.node = alloc([], ndecl: u64)!;
|
||||
dnodes.len = ndecl;
|
||||
let keys: []str = alloc([], ndecl: u64)!;
|
||||
keys.len = ndecl;
|
||||
dkeys = keys;
|
||||
let nodes: []*syntax.node = alloc([], ndecl: u64)!;
|
||||
nodes.len = ndecl;
|
||||
dnodes = nodes;
|
||||
let k: i32 = 0;
|
||||
d = file.list;
|
||||
for (d != nil) {
|
||||
@@ -1104,32 +1089,66 @@ fn wwiemit(c: *checker, file: *syntax.node, path: str) i32 = {
|
||||
d = d.next;
|
||||
};
|
||||
wwisortdecls(dkeys, dnodes, ndecl);
|
||||
let i: i32 = 0;
|
||||
for (i < ndecl) {
|
||||
wwidecl(fd, dnodes[i]);
|
||||
i += 1;
|
||||
};
|
||||
|
||||
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.
|
||||
let nsection: i32 = 0;
|
||||
let p: *syntax.node = file.body;
|
||||
for (p != nil) {
|
||||
if (p.imported == 0 && wwiprimarysectionhas(c, file, &fs,
|
||||
dnodes, ndecl, p.sourceid)) {
|
||||
let owner: str = p.nmod;
|
||||
if (owner.len == 0) { owner = file.nmod; };
|
||||
let pkg: str = p.pkgname;
|
||||
if (pkg.len == 0) { pkg = file.pkgname; };
|
||||
wwiemitprimarysection(c, fd, file, &fs, dnodes, ndecl,
|
||||
owner, pkg, p.sourceid);
|
||||
nsection += 1;
|
||||
};
|
||||
p = p.next;
|
||||
};
|
||||
if (nsection == 0) {
|
||||
wwiemitprimarysection(c, fd, file, &fs, dnodes, ndecl,
|
||||
file.nmod, file.pkgname, wwifirstprimarysource(file));
|
||||
};
|
||||
|
||||
// Compiler-owned public fact closure. Origin markers preserve nominal
|
||||
// ownership but do not create source imports in the eventual consumer.
|
||||
let lastmod: str;
|
||||
let lastsource: i32 = -1;
|
||||
let fi: i32 = 0;
|
||||
for (fi < fs.nfacts) {
|
||||
let mod: str = fs.factmods[fi];
|
||||
if (lastmod.len == 0 || !syntax.streq(lastmod, mod)) {
|
||||
let source: i32 = fs.factnodes[fi].sourceid;
|
||||
if (lastmod.len == 0 || !syntax.streq(lastmod, mod)
|
||||
|| lastsource != source) {
|
||||
wputs(fd, "//ww:module "); wputs(fd, mod); wputs(fd, "\n");
|
||||
let dotidx: i32 = -1;
|
||||
let mi: i32 = 0;
|
||||
for (mi < mod.len) { if (mod[mi] == 46u8) { dotidx = mi; }; mi += 1; };
|
||||
let leaf: str = mod;
|
||||
if (dotidx >= 0) {
|
||||
leaf.ptr = mod.ptr + ((dotidx + 1): u64);
|
||||
leaf.len = mod.len - dotidx - 1;
|
||||
let factpkg: str = fs.factnodes[fi].pkgname;
|
||||
if (factpkg.len == 0) {
|
||||
let dotidx: i32 = -1;
|
||||
let mi: i32 = 0;
|
||||
for (mi < mod.len) { if (mod[mi] == 46u8) { dotidx = mi; }; mi += 1; };
|
||||
factpkg = mod;
|
||||
if (dotidx >= 0) {
|
||||
factpkg.ptr = mod.ptr + ((dotidx + 1): u64);
|
||||
factpkg.len = mod.len - dotidx - 1;
|
||||
};
|
||||
};
|
||||
wputs(fd, "package "); wputs(fd, leaf); wputs(fd, ";\n");
|
||||
wwiemitfactimports(fd, file, mod);
|
||||
wputs(fd, "package "); wputs(fd, factpkg); wputs(fd, ";\n");
|
||||
wwiemitimports(fd, file, mod, source, true);
|
||||
lastmod = mod;
|
||||
lastsource = source;
|
||||
};
|
||||
wwidecl(fd, fs.factnodes[fi]);
|
||||
fi += 1;
|
||||
|
||||
Reference in New Issue
Block a user