ww: implement package initialization
This commit is contained in:
@@ -113,7 +113,7 @@ export fn main(argc: i32, argv: **u8) i32 = {
|
||||
view.ptr = src;
|
||||
view.len = nlen: i32;
|
||||
let fname: str = strings.dup(view);
|
||||
init(&s, fname, buf, blen);
|
||||
parserinit(&s, fname, buf, blen);
|
||||
|
||||
if (parse(&s) != 0) { return 1; };
|
||||
if (encode(&s) != 0) { return 1; };
|
||||
|
||||
@@ -136,7 +136,7 @@ fn reglookup(p: *u8, n: u64) i32 = {
|
||||
return D_NONE;
|
||||
};
|
||||
|
||||
export fn init(a: *asm_, file: str, src: *u8, len: u64) void = {
|
||||
export fn parserinit(a: *asm_, file: str, src: *u8, len: u64) void = {
|
||||
a.file = file;
|
||||
a.src = src;
|
||||
a.srclen = len;
|
||||
|
||||
@@ -3,10 +3,204 @@
|
||||
package main;
|
||||
|
||||
import os;
|
||||
import strconv;
|
||||
import strings;
|
||||
import syntax;
|
||||
import wcc;
|
||||
|
||||
type publication = struct {
|
||||
dst: *u8,
|
||||
stage: str,
|
||||
backup: str,
|
||||
hadold: bool,
|
||||
installed: bool,
|
||||
};
|
||||
|
||||
fn publicationpath(dst: *u8, kind: str) str = {
|
||||
return strings.concat(pathstr(dst), ".w6c.",
|
||||
strconv.i32tos(os.getpid(), strconv.base.DEC), ".", kind);
|
||||
};
|
||||
|
||||
// Open a destination-adjacent file and immediately unlink its name. Cgen's
|
||||
// fatal exit then leaves only a kernel-owned fd, never a partial destination
|
||||
// or named staging artifact.
|
||||
fn anonymousfd(dst: *u8, kind: str) i32 = {
|
||||
let path: str = publicationpath(dst, kind);
|
||||
let fd: i32 = os.open(path,
|
||||
os.flag.RDWR | os.flag.CREATE | os.flag.EXCL, 384i32);
|
||||
if (fd < 0) {
|
||||
os.write(2, "w6c: cannot create anonymous output\n".ptr,
|
||||
"w6c: cannot create anonymous output\n".len: u64);
|
||||
return -1;
|
||||
};
|
||||
if (os.remove(path) != 0) {
|
||||
os.close(fd);
|
||||
os.write(2, "w6c: cannot unlink anonymous output\n".ptr,
|
||||
"w6c: cannot unlink anonymous output\n".len: u64);
|
||||
return -1;
|
||||
};
|
||||
return fd;
|
||||
};
|
||||
|
||||
fn copystream(src: i32, dst: i32) bool = {
|
||||
if (os.lseek(src, 0i64, os.whence.SET) < 0) { return false; };
|
||||
let buf: [65536]u8;
|
||||
for (true) {
|
||||
let n: i64 = os.read(src, buf.ptr, 65536u64);
|
||||
if (n < 0) { return false; };
|
||||
if (n == 0) { return true; };
|
||||
let wr: (i64 | os.oserror) = os.writeall(dst, buf.ptr, n: u64);
|
||||
match (wr) {
|
||||
case let wrote: i64 => { if (wrote != n) { return false; }; };
|
||||
case let e: os.oserror => return false;
|
||||
};
|
||||
};
|
||||
return false;
|
||||
};
|
||||
|
||||
fn materializestream(src: i32, dst: *u8, p: *publication) bool = {
|
||||
p.dst = dst;
|
||||
p.stage = publicationpath(dst, "new");
|
||||
p.backup = publicationpath(dst, "old");
|
||||
p.hadold = false;
|
||||
p.installed = false;
|
||||
let fd: i32 = os.open(p.stage,
|
||||
os.flag.WRONLY | os.flag.CREATE | os.flag.EXCL, 420i32);
|
||||
if (fd < 0) { return false; };
|
||||
let ok: bool = copystream(src, fd);
|
||||
if (os.close(fd) != 0) { ok = false; };
|
||||
if (!ok) { os.remove(p.stage); };
|
||||
return ok;
|
||||
};
|
||||
|
||||
// A publication rollback name is occupied by any terminal directory entry,
|
||||
// including a dangling symlink. Never follow it while deciding whether the
|
||||
// compiler may park an existing destination there.
|
||||
fn pathexistsnofollow(path: str) i32 = {
|
||||
let fi: os.filestat;
|
||||
match (os.lstat(&fi, path)) {
|
||||
case void => return 1;
|
||||
case let e: os.oserror => {
|
||||
if ((e: i64) == -2i64) { return 0; };
|
||||
return -1;
|
||||
};
|
||||
};
|
||||
return -1;
|
||||
};
|
||||
|
||||
fn pathisregularnofollow(path: str) bool = {
|
||||
let fi: os.filestat;
|
||||
match (os.lstat(&fi, path)) {
|
||||
case void => {
|
||||
return (((fi.mode: u32) & 61440u32) == (os.mode.REG: u32));
|
||||
};
|
||||
case let e: os.oserror => return false;
|
||||
};
|
||||
return false;
|
||||
};
|
||||
|
||||
fn publishdiag(prefix: str, dst: *u8) void = {
|
||||
os.write(2, prefix.ptr, prefix.len: u64);
|
||||
let path: str = pathstr(dst);
|
||||
os.write(2, path.ptr, path.len: u64);
|
||||
os.write(2, "\n".ptr, 1u64);
|
||||
};
|
||||
|
||||
fn publishall(p: *publication, n: i32) bool = {
|
||||
let i: i32 = 0;
|
||||
let ok: bool = true;
|
||||
for (i < n) {
|
||||
if (!pathisregularnofollow(p[i].stage)) {
|
||||
publishdiag("w6c: publication stage is not a regular file for ",
|
||||
p[i].dst);
|
||||
ok = false;
|
||||
break;
|
||||
};
|
||||
let fi: os.filestat;
|
||||
match (os.lstat(&fi, pathstr(p[i].dst))) {
|
||||
case void => {
|
||||
if (((fi.mode: u32) & 61440u32) != (os.mode.REG: u32)) {
|
||||
publishdiag(
|
||||
"w6c: publication destination is not a regular file: ",
|
||||
p[i].dst);
|
||||
ok = false;
|
||||
};
|
||||
};
|
||||
case let e: os.oserror => {
|
||||
if ((e: i64) != -2i64) {
|
||||
publishdiag("w6c: cannot inspect publication destination ",
|
||||
p[i].dst);
|
||||
ok = false;
|
||||
};
|
||||
};
|
||||
};
|
||||
if (!ok) { break; };
|
||||
i += 1;
|
||||
};
|
||||
if (ok) {
|
||||
i = 0;
|
||||
for (i < n) {
|
||||
let exists: i32 = pathexistsnofollow(p[i].backup);
|
||||
if (exists != 0) {
|
||||
if (exists < 0) {
|
||||
publishdiag("w6c: cannot inspect publication backup for ",
|
||||
p[i].dst);
|
||||
} else {
|
||||
publishdiag("w6c: publication backup exists for ", p[i].dst);
|
||||
};
|
||||
ok = false;
|
||||
break;
|
||||
};
|
||||
i += 1;
|
||||
};
|
||||
};
|
||||
if (ok) {
|
||||
i = 0;
|
||||
for (i < n) {
|
||||
let rc: i32 = os.rename(pathstr(p[i].dst), p[i].backup);
|
||||
if (rc == 0) { p[i].hadold = true; }
|
||||
else { if (rc != -2) {
|
||||
publishdiag("w6c: cannot preserve ", p[i].dst);
|
||||
ok = false;
|
||||
break;
|
||||
}; };
|
||||
i += 1;
|
||||
};
|
||||
};
|
||||
if (ok) {
|
||||
i = 0;
|
||||
for (i < n) {
|
||||
if (os.rename(p[i].stage, pathstr(p[i].dst)) != 0) {
|
||||
publishdiag("w6c: cannot publish ", p[i].dst);
|
||||
ok = false;
|
||||
break;
|
||||
};
|
||||
p[i].installed = true;
|
||||
i += 1;
|
||||
};
|
||||
if (ok) {
|
||||
// Installation is the commit point. Backup cleanup cannot
|
||||
// truthfully turn a completely installed pair into rejection.
|
||||
i = 0;
|
||||
for (i < n) {
|
||||
if (p[i].hadold && os.remove(p[i].backup) != 0) {
|
||||
publishdiag("w6c: cannot remove backup for ", p[i].dst);
|
||||
};
|
||||
i += 1;
|
||||
};
|
||||
return true;
|
||||
};
|
||||
};
|
||||
i = n - 1;
|
||||
for (i >= 0) {
|
||||
if (p[i].installed) { os.remove(pathstr(p[i].dst)); };
|
||||
if (p[i].hadold) { os.rename(p[i].backup, pathstr(p[i].dst)); };
|
||||
if (p[i].stage.len != 0) { os.remove(p[i].stage); };
|
||||
i -= 1;
|
||||
};
|
||||
return false;
|
||||
};
|
||||
|
||||
fn cstreq(a: *u8, lit: str) bool = {
|
||||
let n: u64 = lit.len: u64;
|
||||
let i: u64 = 0u64;
|
||||
@@ -192,8 +386,10 @@ fn bindimportnames(list: *syntax.node, asts: []*syntax.node, paths: []*u8,
|
||||
};
|
||||
if (name.len > 0) {
|
||||
u.usepkgname = name;
|
||||
if (u.usealias.len > 0) { u.str = u.usealias; }
|
||||
else { u.str = name; };
|
||||
if (u.useblank == 0) {
|
||||
if (u.usealias.len > 0) { u.str = u.usealias; }
|
||||
else { u.str = name; };
|
||||
};
|
||||
} else { if (u.imported == 0) {
|
||||
let pre: str = "w6c: import ";
|
||||
let post: str = " has no declared package name in direct export data\n";
|
||||
@@ -205,8 +401,10 @@ fn bindimportnames(list: *syntax.node, asts: []*syntax.node, paths: []*u8,
|
||||
// A closure-only import may have no declarations in this
|
||||
// interface. Its canonical path must never become a leaf
|
||||
// qualifier by fallback.
|
||||
if (u.usealias.len > 0) { u.str = u.usealias; }
|
||||
else { u.str = u.usepath; };
|
||||
if (u.useblank == 0) {
|
||||
if (u.usealias.len > 0) { u.str = u.usealias; }
|
||||
else { u.str = u.usepath; };
|
||||
};
|
||||
}; };
|
||||
};
|
||||
};
|
||||
@@ -225,6 +423,8 @@ export fn main(argc: i32, argv: **u8) i32 = {
|
||||
let testpackage: i32 = 0i32;
|
||||
let commandpackage: i32 = 0i32;
|
||||
let entrymode: i32 = 0i32;
|
||||
let packageinit: *u8 = nil;
|
||||
let initdispatch: *u8 = nil;
|
||||
let sepmode: i32 = 0i32; // -c: #22 M3 separate-compile / primary-
|
||||
// only codegen (emit imported==0 decls
|
||||
// only; treat `.wwi` deps as external)
|
||||
@@ -302,6 +502,22 @@ export fn main(argc: i32, argv: **u8) i32 = {
|
||||
commandpackage = 1i32;
|
||||
} else { if (cstreq(a, "--entry")) {
|
||||
entrymode = 1i32;
|
||||
} else { if (cstreq(a, "--package-init-symbol")) {
|
||||
i += 1;
|
||||
if (i >= argc) {
|
||||
let m: str = "w6c: --package-init-symbol requires arg\n";
|
||||
os.write(2, m.ptr, m.len: u64);
|
||||
return 2;
|
||||
};
|
||||
packageinit = argv[i];
|
||||
} else { if (cstreq(a, "--init-dispatch-symbol")) {
|
||||
i += 1;
|
||||
if (i >= argc) {
|
||||
let m: str = "w6c: --init-dispatch-symbol requires arg\n";
|
||||
os.write(2, m.ptr, m.len: u64);
|
||||
return 2;
|
||||
};
|
||||
initdispatch = argv[i];
|
||||
} else { if (cstreq(a, "--test-support-module")) {
|
||||
i += 1;
|
||||
if (i >= argc) {
|
||||
@@ -352,12 +568,17 @@ export fn main(argc: i32, argv: **u8) i32 = {
|
||||
return 2;
|
||||
};
|
||||
src = a;
|
||||
}; }; }; }; }; }; }; }; }; }; }; };
|
||||
}; }; }; }; }; }; }; }; }; }; }; }; }; };
|
||||
i += 1;
|
||||
};
|
||||
|
||||
if (src == nil) {
|
||||
let m: str = "usage: w6c_ww [-T|--test-package] [--command-package] [--entry] [--test-target-package path] [-c] [-I out.wwi] [--import path dep.wwi]... [--import-map source path]... [-o out.s] file.ww\n";
|
||||
let m: str = "usage: w6c_ww [-T|--test-package] [--command-package] [--entry] [--package-init-symbol symbol] [--init-dispatch-symbol symbol] [--test-target-package path] [-c] [-I out.wwi] [--import path dep.wwi]... [--import-map source path]... [-o out.s] file.ww\n";
|
||||
os.write(2, m.ptr, m.len: u64);
|
||||
return 2;
|
||||
};
|
||||
if (out != nil && wwiout != nil && cstreq(out, pathstr(wwiout))) {
|
||||
let m: str = "w6c: assembly and interface outputs must be distinct\n";
|
||||
os.write(2, m.ptr, m.len: u64);
|
||||
return 2;
|
||||
};
|
||||
@@ -377,6 +598,22 @@ export fn main(argc: i32, argv: **u8) i32 = {
|
||||
os.write(2, m.ptr, m.len: u64);
|
||||
return 2;
|
||||
};
|
||||
if ((packageinit != nil || initdispatch != nil) && sepmode == 0) {
|
||||
let m: str = "w6c: package initialization symbols require -c\n";
|
||||
os.write(2, m.ptr, m.len: u64);
|
||||
return 2;
|
||||
};
|
||||
if (packageinit != nil && packageinit[0u64] == 0u8) {
|
||||
let m: str = "w6c: --package-init-symbol is empty\n";
|
||||
os.write(2, m.ptr, m.len: u64);
|
||||
return 2;
|
||||
};
|
||||
if (initdispatch != nil
|
||||
&& (initdispatch[0u64] == 0u8 || entrymode == 0)) {
|
||||
let m: str = "w6c: --init-dispatch-symbol requires --entry and a non-empty symbol\n";
|
||||
os.write(2, m.ptr, m.len: u64);
|
||||
return 2;
|
||||
};
|
||||
if (testmode != 0 && testpackage != 0) {
|
||||
let m: str = "w6c: -T and --test-package are mutually exclusive\n";
|
||||
os.write(2, m.ptr, m.len: u64);
|
||||
@@ -595,30 +832,82 @@ export fn main(argc: i32, argv: **u8) i32 = {
|
||||
f.list = importhead;
|
||||
};
|
||||
|
||||
// cgen writes directly to fd 1; dup2 keeps that implementation private.
|
||||
let wwifd: i32 = -1;
|
||||
if (wwiout != nil) {
|
||||
wwifd = anonymousfd(wwiout, "anon.wwi");
|
||||
if (wwifd < 0) { return 1; };
|
||||
};
|
||||
// cgen writes directly to fd 1. Redirect it only to an already-unlinked
|
||||
// anonymous file, never to the named destination.
|
||||
let asmfd: i32 = -1;
|
||||
if (out != nil) {
|
||||
let ofd: i32 = os.open(pathstr(out),
|
||||
os.flag.WRONLY | os.flag.CREATE | os.flag.TRUNC, 420i32); // 0o644
|
||||
if (ofd < 0) {
|
||||
let m: str = "w6c: cannot open output\n";
|
||||
os.write(2, m.ptr, m.len: u64);
|
||||
asmfd = anonymousfd(out, "anon.asm");
|
||||
if (asmfd < 0) {
|
||||
if (wwifd >= 0) { os.close(wwifd); };
|
||||
return 1;
|
||||
};
|
||||
if (os.dup2(ofd, 1i32) < 0) {
|
||||
if (os.dup2(asmfd, 1i32) < 0) {
|
||||
let m: str = "w6c: dup2 failed\n";
|
||||
os.write(2, m.ptr, m.len: u64);
|
||||
os.close(ofd);
|
||||
os.close(asmfd);
|
||||
if (wwifd >= 0) { os.close(wwifd); };
|
||||
return 1;
|
||||
};
|
||||
os.close(ofd);
|
||||
};
|
||||
|
||||
let testmodule: str;
|
||||
if (testsupport != nil) { testmodule = pathstr(testsupport); };
|
||||
let testtargetmodule: str;
|
||||
if (testtarget != nil) { testtargetmodule = pathstr(testtarget); };
|
||||
let interfaceout: str;
|
||||
if (wwiout != nil) { interfaceout = pathstr(wwiout); };
|
||||
return wcc.compilefile(f, testmode, testpackage, testmodule,
|
||||
testtargetmodule, sepmode, interfaceout, entrymode);
|
||||
let packageinitsymbol: str;
|
||||
if (packageinit != nil) { packageinitsymbol = pathstr(packageinit); };
|
||||
let initdispatchsymbol: str;
|
||||
if (initdispatch != nil) { initdispatchsymbol = pathstr(initdispatch); };
|
||||
let haswwi: i32 = 0;
|
||||
if (wwiout != nil) { haswwi = 1; };
|
||||
let compilerc: i32 = wcc.compilefile(f, testmode, testpackage, testmodule,
|
||||
testtargetmodule, sepmode, wwifd, haswwi, entrymode,
|
||||
packageinitsymbol, initdispatchsymbol);
|
||||
if (out != nil) { os.close(1i32); };
|
||||
if (compilerc != 0) {
|
||||
if (asmfd >= 0) { os.close(asmfd); };
|
||||
if (wwifd >= 0) { os.close(wwifd); };
|
||||
return compilerc;
|
||||
};
|
||||
let pubs: [2]publication;
|
||||
let pi: i32 = 0;
|
||||
for (pi < 2) {
|
||||
pubs[pi].dst = nil;
|
||||
pubs[pi].stage = "";
|
||||
pubs[pi].backup = "";
|
||||
pubs[pi].hadold = false;
|
||||
pubs[pi].installed = false;
|
||||
pi += 1;
|
||||
};
|
||||
let npub: i32 = 0;
|
||||
let stagedok: bool = true;
|
||||
if (wwiout != nil) {
|
||||
stagedok = materializestream(wwifd, wwiout, &pubs[npub]);
|
||||
if (stagedok) { npub += 1; };
|
||||
};
|
||||
if (stagedok && out != nil) {
|
||||
stagedok = materializestream(asmfd, out, &pubs[npub]);
|
||||
if (stagedok) { npub += 1; };
|
||||
};
|
||||
if (asmfd >= 0) { os.close(asmfd); };
|
||||
if (wwifd >= 0) { os.close(wwifd); };
|
||||
if (!stagedok) {
|
||||
pi = 0;
|
||||
for (pi < 2) {
|
||||
if (pubs[pi].stage.len != 0) { os.remove(pubs[pi].stage); };
|
||||
pi += 1;
|
||||
};
|
||||
let m: str = "w6c: cannot stage compiler output\n";
|
||||
os.write(2, m.ptr, m.len: u64);
|
||||
return 1;
|
||||
};
|
||||
if (!publishall(&pubs[0], npub)) {
|
||||
return 1;
|
||||
};
|
||||
return 0;
|
||||
};
|
||||
|
||||
@@ -3,8 +3,9 @@ package wcc;
|
||||
import syntax;
|
||||
|
||||
export fn compilefile(file: *syntax.node, testmode: i32, testpackage: i32,
|
||||
testmodule: str, testtarget: str, sepmode: i32, wwiout: str,
|
||||
entrymode: i32) i32 = {
|
||||
testmodule: str, testtarget: str, sepmode: i32, wwifd: i32,
|
||||
haswwi: i32,
|
||||
entrymode: i32, packageinitsymbol: str, initdispatchsymbol: str) i32 = {
|
||||
let tc: syntax.tctx;
|
||||
syntax.typesinit(&tc);
|
||||
let ck: checker;
|
||||
@@ -14,18 +15,19 @@ export fn compilefile(file: *syntax.node, testmode: i32, testpackage: i32,
|
||||
if (testmodule.len > 0) { ck.testmodule = testmodule; };
|
||||
ck.testtarget = testtarget;
|
||||
ck.sepmode = sepmode;
|
||||
ck.packageinitsymbol = packageinitsymbol;
|
||||
checkfile(&ck, file);
|
||||
if (ck.errs > 0) { return 1; };
|
||||
if (wwiout.len > 0) {
|
||||
if (wwiemit(&ck, file, wwiout) != 0) { return 1; };
|
||||
if (haswwi != 0) {
|
||||
if (wwiemitfd(&ck, file, wwifd) != 0) { return 1; };
|
||||
};
|
||||
|
||||
let cg: cgen;
|
||||
cgeninit(&cg);
|
||||
cg.sepmode = sepmode;
|
||||
if (wwiout.len > 0 && entrymode == 0) { cg.sepisdep = 1i32; };
|
||||
cgfile(&cg, file);
|
||||
return 0;
|
||||
if (haswwi != 0 && entrymode == 0) { cg.sepisdep = 1i32; };
|
||||
cg.initdispatchsymbol = initdispatchsymbol;
|
||||
return cgfile(&cg, file);
|
||||
};
|
||||
|
||||
export fn resolvefile(file: *syntax.node, verbose: i32,
|
||||
|
||||
@@ -509,6 +509,7 @@ type cgen = struct {
|
||||
// root entry stays bare. Like sepmode, NOT reset by cgeninit (per-fn).
|
||||
// Symmetric with cstage Cg.sep_isdep.
|
||||
sepisdep: i32,
|
||||
initdispatchsymbol: str, // root-owned complete package-init schedule
|
||||
};
|
||||
|
||||
// Top-level mutable `let` registry. Mirrors cmd/w6c/cgen.c LetVar.
|
||||
@@ -741,6 +742,17 @@ fn localfind(c: *cgen, name: str) i32 = {
|
||||
let cgoutstream: memio.stream;
|
||||
let cgoutmode: i32 = 0;
|
||||
let cgoutinit: i32 = 0;
|
||||
let cgwritefailed: i32 = 0;
|
||||
|
||||
fn cgwrite(p: *u8, n: u64) void = {
|
||||
if (cgwritefailed != 0) { return; };
|
||||
match (os.writeall(1i32, p, n)) {
|
||||
case let wrote: i64 => {
|
||||
if (wrote < 0 || (wrote: u64) != n) { cgwritefailed = 1; };
|
||||
};
|
||||
case let e: os.oserror => cgwritefailed = 1;
|
||||
};
|
||||
};
|
||||
|
||||
fn cgout_enable() void = {
|
||||
if (cgoutinit == 0) {
|
||||
@@ -754,7 +766,7 @@ fn cgout_disable() void = { cgoutmode = 0; };
|
||||
|
||||
fn cgout_flush() void = {
|
||||
if (cgoutstream.pos > 0) {
|
||||
os.write(1, cgoutstream.ptr, cgoutstream.pos: u64);
|
||||
cgwrite(cgoutstream.ptr, cgoutstream.pos: u64);
|
||||
memio.reset(&cgoutstream);
|
||||
};
|
||||
};
|
||||
@@ -769,7 +781,7 @@ fn emitbytes(p: *u8, n: u64) void = {
|
||||
// lib/log/log.ww stdprintln. #94 fold-eFinal.
|
||||
io.write(&cgoutstream.vt, buf);
|
||||
} else {
|
||||
os.write(1, p, n);
|
||||
cgwrite(p, n);
|
||||
};
|
||||
};
|
||||
|
||||
@@ -2894,6 +2906,35 @@ fn emittupledata(c: *cgen, name: str, module: str, tt: *syntax.node, rhs: *synta
|
||||
return true;
|
||||
};
|
||||
|
||||
fn emitinitbackings(n: *syntax.node) void = {
|
||||
for (n != nil) {
|
||||
if (n.kind == syntax.nkind.N_ARRLIT && n.linksym.len > 0) {
|
||||
let u: *syntax.tinfo = tichase(n.type_: *syntax.tinfo);
|
||||
if (u == nil || u.kind != syntax.tykind.TY_ARRAY) {
|
||||
let msg: str = "runtime package slice backing has no array type\n";
|
||||
os.write(2, msg.ptr, msg.len: u64);
|
||||
os.exit(1);
|
||||
};
|
||||
emitline("DATAW ");
|
||||
emitbytes(n.linksym.ptr, n.linksym.len: u64);
|
||||
emitline("(SB),\"");
|
||||
let count: u64 = u.size;
|
||||
if (count == 0u64) { count = 1u64; };
|
||||
let i: u64 = 0u64;
|
||||
for (i < count) { emitdatawbyte(0u8); i += 1u64; };
|
||||
emitline("\"\n");
|
||||
};
|
||||
emitinitbackings(n.attr);
|
||||
emitinitbackings(n.lhs);
|
||||
emitinitbackings(n.rhs);
|
||||
emitinitbackings(n.cond);
|
||||
emitinitbackings(n.body);
|
||||
emitinitbackings(n.els);
|
||||
emitinitbackings(n.list);
|
||||
n = n.next;
|
||||
};
|
||||
};
|
||||
|
||||
fn emitletdataw(c: *cgen, file: *syntax.node) void = {
|
||||
let savedmod: str = c.curmod;
|
||||
let savedsource: i32 = c.cursource;
|
||||
@@ -3458,6 +3499,10 @@ fn collectfnrets(c: *cgen, file: *syntax.node) void = {
|
||||
let d: *syntax.node = file.list;
|
||||
for (d != nil) {
|
||||
if (d.kind == syntax.nkind.N_FNDECL) {
|
||||
if (d.initfn != 0 || d.initsynthetic != 0) {
|
||||
d = d.next;
|
||||
continue;
|
||||
};
|
||||
let f: *fnret = alloc(fnret{fname=d.str, fmod=d.nmod, rtype=d.lhs, params=d.list, frnext=c.fnrets})!;
|
||||
c.fnrets = f;
|
||||
};
|
||||
@@ -3788,12 +3833,16 @@ fn collectmods(c: *cgen, file: *syntax.node) void = {
|
||||
let d: *syntax.node = file.list;
|
||||
for (d != nil) {
|
||||
// M1 #22: record alias→path for the qualified-ref hint.
|
||||
if (d.kind == syntax.nkind.N_USE) {
|
||||
if (d.kind == syntax.nkind.N_USE && d.useblank == 0) {
|
||||
if (d.usepath.len > 0) {
|
||||
let um: *modent = alloc(modent{mname=d.str, nmod=d.usepath, omod=d.nmod, sourceid=d.sourceid, mnext=c.uses})!;
|
||||
c.uses = um;
|
||||
};
|
||||
};
|
||||
if (d.initfn != 0 || d.initsynthetic != 0) {
|
||||
d = d.next;
|
||||
continue;
|
||||
};
|
||||
// Mirror collectfnrets' shape exactly (plain prepend in one
|
||||
// branch). Earlier nested-if/early-return variants tickled a
|
||||
// wwstage cgen bug that dropped most prepends.
|
||||
@@ -3988,6 +4037,10 @@ fn fficollect(c: *cgen, file: *syntax.node) void = {
|
||||
let d: *syntax.node = file.list;
|
||||
for (d != nil) {
|
||||
if (d.kind == syntax.nkind.N_FNDECL) {
|
||||
if (d.initfn != 0 || d.initsynthetic != 0) {
|
||||
d = d.next;
|
||||
continue;
|
||||
};
|
||||
let a: *syntax.node = d.attr;
|
||||
for (a != nil) {
|
||||
if (a.kind == syntax.nkind.N_ATTR) {
|
||||
|
||||
@@ -544,6 +544,12 @@ fn cgfn(c: *cgen, fn_: *syntax.node) void = {
|
||||
};
|
||||
|
||||
cgfnparams(c, fn_.list);
|
||||
if (c.initdispatchsymbol.len > 0 && syntax.streq(fn_.str, "main")
|
||||
&& fn_.imported == 0 && c.sepisdep == 0) {
|
||||
emitline("\tCALL\t");
|
||||
emitbytes(c.initdispatchsymbol.ptr, c.initdispatchsymbol.len: u64);
|
||||
emitline("(SB)\n");
|
||||
};
|
||||
c.lastwasreturn = 0;
|
||||
// Iterate the fn body's statements directly rather than dispatching
|
||||
// the outermost N_BLOCK through cgstmt — cgblock now save/restores
|
||||
@@ -594,11 +600,13 @@ fn cgfn(c: *cgen, fn_: *syntax.node) void = {
|
||||
// (path-carrying `//ww:module-reset`, #57); only the root/link-entry
|
||||
// unit (wwiout==nil, #69) keeps the bare label.
|
||||
emitline("TEXT ");
|
||||
if (syntax.streq(fn_.str, "main") && fn_.imported == 0 && c.sepisdep == 0) {
|
||||
if (fn_.linksym.len > 0) {
|
||||
emitbytes(fn_.linksym.ptr, fn_.linksym.len: u64);
|
||||
} else { if (syntax.streq(fn_.str, "main") && fn_.imported == 0 && c.sepisdep == 0) {
|
||||
emitbytes(fn_.str.ptr, fn_.str.len: u64);
|
||||
} else {
|
||||
emitfnname(c, fn_.str, fn_.nmod);
|
||||
};
|
||||
}; };
|
||||
emitline(",$");
|
||||
emitint(frame: i64);
|
||||
emitline("\n");
|
||||
@@ -612,8 +620,9 @@ fn cgfn(c: *cgen, fn_: *syntax.node) void = {
|
||||
cgout_flush();
|
||||
};
|
||||
|
||||
fn cgfile(c: *cgen, file: *syntax.node) void = {
|
||||
if (file == nil) { return; };
|
||||
fn cgfile(c: *cgen, file: *syntax.node) i32 = {
|
||||
cgwritefailed = 0;
|
||||
if (file == nil) { return 0; };
|
||||
c.strlits = nil;
|
||||
c.strlitseq = 0;
|
||||
collectaliases(c, file);
|
||||
@@ -647,5 +656,7 @@ fn cgfile(c: *cgen, file: *syntax.node) void = {
|
||||
letpreintern(c, file);
|
||||
emitdatasection(c);
|
||||
emitdefconstants(c, file);
|
||||
emitinitbackings(file.list);
|
||||
emitletdataw(c, file);
|
||||
return cgwritefailed;
|
||||
};
|
||||
|
||||
@@ -8698,7 +8698,11 @@ fn cgcall(c: *cgen, n: *syntax.node) void = {
|
||||
emitline("\tCALL\tAX\n");
|
||||
} else {
|
||||
emitline("\tCALL\t");
|
||||
if (callee != nil) {
|
||||
if (callee != nil && callee.refdecl != nil
|
||||
&& callee.refdecl.linksym.len > 0) {
|
||||
emitbytes(callee.refdecl.linksym.ptr,
|
||||
callee.refdecl.linksym.len: u64);
|
||||
} else { if (callee != nil) {
|
||||
if (callee.kind == syntax.nkind.N_IDENT) {
|
||||
// Bare `f()` — same-module by ww's resolver,
|
||||
// so c.curmod is the disambiguation hint.
|
||||
@@ -8718,7 +8722,7 @@ fn cgcall(c: *cgen, n: *syntax.node) void = {
|
||||
};
|
||||
emitfnname(c, calleename, hint);
|
||||
};};
|
||||
};
|
||||
}; };
|
||||
emitline("(SB)\n");
|
||||
};
|
||||
// Caller cleanup for stack-passed args (args 7+, or any
|
||||
|
||||
@@ -2173,6 +2173,284 @@ fn cgarrlitfillbp(c: *cgen, arrtn: *syntax.node, rhs: *syntax.node, off: i32) vo
|
||||
};
|
||||
};
|
||||
|
||||
// Compiler-generated package-variable helpers need a memory-directed literal
|
||||
// path. It bypasses the finite tuple cursor, recursively fills nested
|
||||
// aggregates, and moves runtime slice-literal backing into canonical writable
|
||||
// package storage before the helper returns. The hook is gated solely by the
|
||||
// checker-owned N_LET.initsynthetic bit, so ordinary locals are unchanged.
|
||||
fn cginitfatal(msg: str) void = {
|
||||
os.write(2, msg.ptr, msg.len: u64);
|
||||
os.write(2, "\n".ptr, 1u64);
|
||||
os.exit(1);
|
||||
};
|
||||
|
||||
fn cginitzerobp(c: *cgen, off: i32, sz: i32) void = {
|
||||
emitline("\tXORQ\tAX, AX\n");
|
||||
let k: i32 = 0;
|
||||
for (k + 8 <= sz) {
|
||||
emitline("\tMOVQ\tAX, "); emitoff((off + k): i64);
|
||||
emitline("(BP)\n"); k += 8;
|
||||
};
|
||||
if (k + 4 <= sz) {
|
||||
emitline("\tMOVL\tAX, "); emitoff((off + k): i64);
|
||||
emitline("(BP)\n"); k += 4;
|
||||
};
|
||||
if (k + 2 <= sz) {
|
||||
emitline("\tMOVW\tAX, "); emitoff((off + k): i64);
|
||||
emitline("(BP)\n"); k += 2;
|
||||
};
|
||||
if (k + 1 <= sz) {
|
||||
emitline("\tMOVB\tAX, "); emitoff((off + k): i64);
|
||||
emitline("(BP)\n");
|
||||
};
|
||||
};
|
||||
|
||||
fn cginitcopybp(c: *cgen, src: i32, dst: i32, sz: i32) void = {
|
||||
emitline("\tLEAQ\t"); emitoff(src: i64); emitline("(BP), SI\n");
|
||||
emitline("\tLEAQ\t"); emitoff(dst: i64); emitline("(BP), BX\n");
|
||||
aggcopy(c, sz);
|
||||
};
|
||||
|
||||
fn cginitstripcast(n: *syntax.node) *syntax.node = {
|
||||
for (n != nil && n.kind == syntax.nkind.N_CAST) { n = n.lhs; };
|
||||
return n;
|
||||
};
|
||||
|
||||
fn cginitfield(u: *syntax.tinfo, name: str) *syntax.tfield = {
|
||||
let f: *syntax.tfield = nil;
|
||||
if (u != nil) { f = u.fields; };
|
||||
for (f != nil) {
|
||||
if (syntax.streq(name, f.name)) { return f; };
|
||||
f = f.tnext;
|
||||
};
|
||||
return nil;
|
||||
};
|
||||
|
||||
fn cginitarraybp(c: *cgen, u: *syntax.tinfo, lit: *syntax.node,
|
||||
off: i32) void = {
|
||||
let et: *syntax.tinfo = u.sub;
|
||||
let eu: *syntax.tinfo = tichase(et);
|
||||
let esz: i32 = 1;
|
||||
if (eu != nil) { esz = eu.size: i32; };
|
||||
let total: i32 = u.alen: i32;
|
||||
cginitzerobp(c, off, u.size: i32);
|
||||
let idx: i32 = 0;
|
||||
let lastoff: i32 = 0;
|
||||
let e: *syntax.node = lit.list;
|
||||
for (e != nil) {
|
||||
if (e.kind == syntax.nkind.N_FIELD
|
||||
&& syntax.streq(e.str, "...")) {
|
||||
if (idx == 0) {
|
||||
cginitfatal("package initializer array repeat has no value");
|
||||
};
|
||||
for (idx < total) {
|
||||
cginitcopybp(c, lastoff, off + idx * esz, esz);
|
||||
idx += 1;
|
||||
};
|
||||
return;
|
||||
};
|
||||
if (idx >= total) {
|
||||
cginitfatal("package initializer array literal exceeds destination");
|
||||
};
|
||||
lastoff = off + idx * esz;
|
||||
cginitvaluebp(c, et, e, lastoff);
|
||||
idx += 1;
|
||||
e = e.next;
|
||||
};
|
||||
};
|
||||
|
||||
fn cginitstructbp(c: *cgen, u: *syntax.tinfo, lit: *syntax.node,
|
||||
off: i32) void = {
|
||||
cginitzerobp(c, off, u.size: i32);
|
||||
let e: *syntax.node = lit.list;
|
||||
for (e != nil) {
|
||||
let f: *syntax.tfield = cginitfield(u, e.str);
|
||||
if (f != nil) {
|
||||
cginitvaluebp(c, f.type_, e.lhs, off + (f.offset: i32));
|
||||
};
|
||||
e = e.next;
|
||||
};
|
||||
};
|
||||
|
||||
fn cginittuplebp(c: *cgen, u: *syntax.tinfo, lit: *syntax.node,
|
||||
off: i32) void = {
|
||||
cginitzerobp(c, off, u.size: i32);
|
||||
let te: *syntax.ttupleelem = u.tupleelems;
|
||||
let e: *syntax.node = lit.list;
|
||||
for (te != nil && e != nil) {
|
||||
cginitvaluebp(c, te.type_, e, off + (te.offset: i32));
|
||||
te = te.tnext;
|
||||
e = e.next;
|
||||
};
|
||||
};
|
||||
|
||||
fn cginitslicebp(c: *cgen, u: *syntax.tinfo, lit: *syntax.node,
|
||||
off: i32) void = {
|
||||
if (lit.linksym.len == 0) {
|
||||
cginitfatal("runtime package slice literal has no canonical backing");
|
||||
};
|
||||
let at: *syntax.tinfo = tichase(lit.type_: *syntax.tinfo);
|
||||
if (at == nil || at.kind != syntax.tykind.TY_ARRAY || at.sub == nil) {
|
||||
cginitfatal("runtime package slice literal has no backing type");
|
||||
};
|
||||
let count: i32 = at.alen: i32;
|
||||
let bsz: i32 = at.size: i32;
|
||||
if (bsz != 0) {
|
||||
let scr: i32 = localalloc(c, "@initbacking", bsz, nil);
|
||||
cginitarraybp(c, at, lit, scr);
|
||||
emitline("\tLEAQ\t"); emitoff(scr: i64); emitline("(BP), SI\n");
|
||||
emitline("\tLEAQ\t"); emitbytes(lit.linksym.ptr,
|
||||
lit.linksym.len: u64); emitline("(SB), BX\n");
|
||||
aggcopy(c, bsz);
|
||||
};
|
||||
emitline("\tLEAQ\t"); emitbytes(lit.linksym.ptr,
|
||||
lit.linksym.len: u64); emitline("(SB), AX\n");
|
||||
emitline("\tMOVQ\tAX, "); emitoff(off: i64); emitline("(BP)\n");
|
||||
emitline("\tMOVQ\t$"); emitint(count: i64); emitline(", ");
|
||||
emitoff((off + 8): i64); emitline("(BP)\n");
|
||||
emitline("\tMOVQ\t$"); emitint(count: i64); emitline(", ");
|
||||
emitoff((off + 16): i64); emitline("(BP)\n");
|
||||
};
|
||||
|
||||
fn cginitcursorstore(c: *cgen, ti: *syntax.tinfo, gpcur: i32,
|
||||
ssecur: i32, off: i32) void = {
|
||||
let eslot: i32 = tupeslot(ti);
|
||||
if (eslot == 0) { return; };
|
||||
if (eslot > 8) {
|
||||
let k: i32 = 0;
|
||||
for (k < eslot / 8) {
|
||||
emitline("\tMOVQ\t"); emitline(tupreg(gpcur + k));
|
||||
emitline(", "); emitoff((off + k * 8): i64);
|
||||
emitline("(BP)\n"); k += 1;
|
||||
};
|
||||
return;
|
||||
};
|
||||
if (syntax.typeisfloat(ti)) {
|
||||
let op: str = "MOVSD";
|
||||
if (syntax.typeisf32(ti)) { op = "MOVSS"; };
|
||||
emitline("\t"); emitline(op); emitline("\t");
|
||||
emitline(tupsse(ssecur)); emitline(", ");
|
||||
emitoff(off: i64); emitline("(BP)\n");
|
||||
return;
|
||||
};
|
||||
emitline("\tMOVQ\t"); emitline(tupreg(gpcur)); emitline(", ");
|
||||
emitoff(off: i64); emitline("(BP)\n");
|
||||
};
|
||||
|
||||
fn cginitaggregatebp(c: *cgen, ti: *syntax.tinfo, u: *syntax.tinfo,
|
||||
expr: *syntax.node, off: i32) void = {
|
||||
let sz: i32 = u.size: i32;
|
||||
if (expr.kind == syntax.nkind.N_CALL && sretretsizetn(c, ti) > 0) {
|
||||
c.sretdestoff = off;
|
||||
cgexpr(c, expr);
|
||||
c.sretdestoff = 0;
|
||||
return;
|
||||
};
|
||||
if (u.kind == syntax.tykind.TY_TUPLE && sretretsizetn(c, ti) == 0) {
|
||||
cgexpr(c, expr);
|
||||
let gpcur: i32 = 0;
|
||||
let ssecur: i32 = 0;
|
||||
let te: *syntax.ttupleelem = u.tupleelems;
|
||||
for (te != nil) {
|
||||
cginitcursorstore(c, te.type_, gpcur, ssecur,
|
||||
off + (te.offset: i32));
|
||||
if (syntax.typeisfloat(te.type_)) { ssecur += 1; }
|
||||
else { gpcur += tupeslot(te.type_) / 8; };
|
||||
te = te.tnext;
|
||||
};
|
||||
return;
|
||||
};
|
||||
if (expr.kind == syntax.nkind.N_CALL
|
||||
&& u.kind == syntax.tykind.TY_STRUCT) {
|
||||
let fc: i32 = structfloatclassti(u);
|
||||
if (fc != 0) {
|
||||
cgexpr(c, expr);
|
||||
let nb: i32 = fc & 15;
|
||||
let gp: i32 = 0;
|
||||
let sse: i32 = 0;
|
||||
let i: i32 = 0;
|
||||
for (i < nb) {
|
||||
let issse: bool = false;
|
||||
if (i == 0 && (fc & 16) != 0) { issse = true; };
|
||||
if (i == 1 && (fc & 32) != 0) { issse = true; };
|
||||
if (issse) {
|
||||
emitline("\tMOVSD\t"); emitline(tupsse(sse));
|
||||
emitline(", "); sse += 1;
|
||||
} else {
|
||||
emitline("\tMOVQ\t"); emitline(tupreg(gp));
|
||||
emitline(", "); gp += 1;
|
||||
};
|
||||
emitoff((off + i * 8): i64); emitline("(BP)\n");
|
||||
i += 1;
|
||||
};
|
||||
return;
|
||||
};
|
||||
};
|
||||
if (expr.kind == syntax.nkind.N_CALL && sz <= 24) {
|
||||
cgexpr(c, expr);
|
||||
cgaggregstore(c, "BP", off, sz, true);
|
||||
return;
|
||||
};
|
||||
if (aggargsrcaddr(c, expr, "SI")) {
|
||||
emitline("\tLEAQ\t"); emitoff(off: i64); emitline("(BP), BX\n");
|
||||
aggcopy(c, sz);
|
||||
return;
|
||||
};
|
||||
cginitfatal("package initializer aggregate expression shape unsupported");
|
||||
};
|
||||
|
||||
fn cginitvaluebp(c: *cgen, ti: *syntax.tinfo, expr: *syntax.node,
|
||||
off: i32) void = {
|
||||
let u: *syntax.tinfo = tichase(ti);
|
||||
let r: *syntax.node = cginitstripcast(expr);
|
||||
if (u == nil || r == nil) {
|
||||
cginitfatal("package initializer value has no type or expression");
|
||||
};
|
||||
if (u.kind == syntax.tykind.TY_ARRAY
|
||||
&& r.kind == syntax.nkind.N_ARRLIT) {
|
||||
cginitarraybp(c, u, r, off); return;
|
||||
};
|
||||
if (u.kind == syntax.tykind.TY_STRUCT
|
||||
&& r.kind == syntax.nkind.N_STRUCTLIT) {
|
||||
cginitstructbp(c, u, r, off); return;
|
||||
};
|
||||
if (u.kind == syntax.tykind.TY_TUPLE
|
||||
&& r.kind == syntax.nkind.N_TUPLE) {
|
||||
cginittuplebp(c, u, r, off); return;
|
||||
};
|
||||
if (u.kind == syntax.tykind.TY_SLICE
|
||||
&& r.kind == syntax.nkind.N_ARRLIT) {
|
||||
cginitslicebp(c, u, r, off); return;
|
||||
};
|
||||
if (u.kind == syntax.tykind.TY_TAGGED) {
|
||||
cgwidentaggedstore(c, u, expr, "BP", off, u.size: i32);
|
||||
return;
|
||||
};
|
||||
if (syntax.typeisstr(ti) || u.kind == syntax.tykind.TY_SLICE) {
|
||||
cgexpr(c, expr);
|
||||
emitline("\tMOVQ\tAX, "); emitoff(off: i64); emitline("(BP)\n");
|
||||
emitline("\tMOVQ\tBX, "); emitoff((off + 8): i64); emitline("(BP)\n");
|
||||
emitline("\tMOVQ\tCX, "); emitoff((off + 16): i64); emitline("(BP)\n");
|
||||
return;
|
||||
};
|
||||
if (u.kind == syntax.tykind.TY_ARRAY
|
||||
|| u.kind == syntax.tykind.TY_STRUCT
|
||||
|| u.kind == syntax.tykind.TY_TUPLE) {
|
||||
cginitaggregatebp(c, ti, u, r, off); return;
|
||||
};
|
||||
cgexpr(c, expr);
|
||||
if (syntax.typeisfloat(ti)) {
|
||||
let op: str = "MOVSD";
|
||||
if (syntax.typeisf32(ti)) { op = "MOVSS"; };
|
||||
emitline("\t"); emitline(op); emitline("\tX0, ");
|
||||
emitoff(off: i64); emitline("(BP)\n"); return;
|
||||
};
|
||||
let sz: i32 = u.size: i32;
|
||||
if (sz != 1 && sz != 2 && sz != 4) { sz = 8; };
|
||||
emitline("\t"); emitline(storeopsz(sz)); emitline("\tAX, ");
|
||||
emitoff(off: i64); emitline("(BP)\n");
|
||||
};
|
||||
|
||||
// #152: reserve the let's frame slot, emit its initializer against the
|
||||
// PRE-binding locals chain, then link the binding. A self-shadowing init
|
||||
// (`let x = f(x)`) resolves x in the OUTER scope because nm is not yet in
|
||||
@@ -2205,6 +2483,20 @@ fn cgletbody(c: *cgen, n: *syntax.node, off: i32) void = {
|
||||
if (tn == nil) { tn = inferletcalltype(c, n.rhs); };
|
||||
if (n.rhs != nil) {
|
||||
let rhs: *syntax.node = n.rhs;
|
||||
let initlit: *syntax.node = cginitstripcast(rhs);
|
||||
if (n.initsynthetic != 0 && initlit != nil
|
||||
&& (initlit.kind == syntax.nkind.N_ARRLIT
|
||||
|| initlit.kind == syntax.nkind.N_STRUCTLIT
|
||||
|| initlit.kind == syntax.nkind.N_TUPLE)) {
|
||||
let iti: *syntax.tinfo = nil;
|
||||
if (tn != nil) { iti = tn.type_: *syntax.tinfo; };
|
||||
if (iti == nil && n.type_ != nil) {
|
||||
iti = n.type_: *syntax.tinfo;
|
||||
};
|
||||
cginitvaluebp(c, iti, rhs, off);
|
||||
c.lastwasreturn = 0;
|
||||
return;
|
||||
};
|
||||
// `let s: []T = alloc([], n)!;` / `?` shortcut (#32, #45).
|
||||
// Mirror of cstage cgen.c N_LET arrlit-empty branch: allocate
|
||||
// n*esz bytes via rt_malloc, then build the {ptr, 0, n} slice
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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;
|
||||
};
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -148,7 +148,8 @@ export fn main(argc: i32, argv: **u8) i32 = {
|
||||
// silently). Mirrors w6c main.ww:162 / cmd/w6c/main.c.
|
||||
if (l.errs > 0 || ps.errs > 0) { return 1; };
|
||||
let empty: str;
|
||||
if (wcc.compilefile(f, 0, 0, empty, empty, 0, empty, 0) != 0) { return 1; };
|
||||
if (wcc.compilefile(f, 0, 0, empty, empty, 0, -1, 0, 0,
|
||||
empty, empty) != 0) { return 1; };
|
||||
};};};};
|
||||
|
||||
if (l.errs > 0) { return 1; };
|
||||
|
||||
Reference in New Issue
Block a user