// Port of cmd/w6c/main.c. 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, passthrough: bool, }; fn publicationpath(dst: *u8, kind: str) str = { return strings.concat(pathstr(dst), ".w6c.", strconv.i32tos(os.getpid(), strconv.base.DEC), ".", kind); }; fn pathischardevice(path: *u8) bool = { let fi: os.filestat; match (os.lstat(&fi, pathstr(path))) { case void => { return (((fi.mode: u32) & 61440u32) == (os.mode.CHR: u32)); }; case let e: os.oserror => return false; }; return false; }; // 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 && pathischardevice(dst)) { path = strings.concat("/tmp/ww-w6c.", strconv.i32tos(os.getpid(), strconv.base.DEC), ".", kind); fd = 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.passthrough = false; let fi: os.filestat; match (os.lstat(&fi, pathstr(dst))) { case void => { if (((fi.mode: u32) & 61440u32) == (os.mode.CHR: u32)) { let sink: i32 = os.open(pathstr(dst), os.flag.WRONLY, 0i32); if (sink < 0) { return false; }; let sinkok: bool = copystream(src, sink); if (os.close(sink) != 0) { sinkok = false; }; if (sinkok) { p.passthrough = true; }; return sinkok; }; }; case let e: os.oserror => void; }; 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 (p[i].passthrough) { i += 1; continue; }; 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) { if (p[i].passthrough) { i += 1; continue; }; 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) { if (p[i].passthrough) { i += 1; continue; }; 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 (p[i].passthrough) { i += 1; continue; }; 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].passthrough && 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].passthrough) { i -= 1; continue; }; 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; for (i < n) { let li: i32 = i: i32; if (a[i] != lit[li]) { return false; }; i += 1u64; }; if (a[i] != 0u8) { return false; }; return true; }; fn cstrlen(p: *u8) u64 = { let n: u64 = 0u64; for (p[n] != 0u8) { n += 1u64; }; return n; }; // pathstr — view a NUL-terminated *u8 as a str. lib/os entrypoints // take str post-task-#23; this bridges call sites that still hold // C-string paths (argv entries, arena-allocated buffers). fn pathstr(p: *u8) str = { let r: str; r.ptr = p; r.len = cstrlen(p): i32; return r; }; fn slurp(path: *u8) (*u8, u64) = { let fd: i32 = os.open(pathstr(path), os.flag.RDONLY, 0i32); if (fd < 0) { return nil, 0u64; }; let szr: (i64 | os.oserror) = os.filesize(fd); let n: i64 = 0i64; match (szr) { case let v: i64 => n = v; case let e: os.oserror => { os.close(fd); return nil, 0u64; }; }; let nz: u64 = n: u64; let buf: []u8 = alloc([], nz + 1u64)!; buf.len = (nz + 1u64): i32; let rr: (i64 | os.oserror) = os.readall(fd, buf.ptr, nz); os.close(fd); let got: i64 = 0i64; match (rr) { case let v: i64 => got = v; case let e: os.oserror => return nil, 0u64; }; if (got != n) { return nil, 0u64; }; buf[nz] = 0u8; return buf.ptr, nz; }; fn exportownermatches(buf: *u8, n: u64, path: *u8) bool = { let prefix: str = "//ww:module "; let pn: u64 = cstrlen(path); let poff: u64 = prefix.len: u64; let need: u64 = poff + pn + 1u64; if (n < need) { return false; }; let i: u64 = 0u64; for (i < poff) { if (buf[i] != prefix.ptr[i]) { return false; }; i += 1u64; }; i = 0u64; for (i < pn) { if (buf[poff + i] != path[i]) { return false; }; i += 1u64; }; return buf[need - 1u64] == 10u8; }; type importmap = struct { source: *u8, path: *u8, seen: bool, }; fn allocimportmaps(count: i32) ([]importmap | nomem) = { let value: []importmap = alloc([], count: u64)?; return value; }; fn allocimportptrs(count: i32) ([]*u8 | nomem) = { let value: []*u8 = alloc([], count: u64)?; return value; }; fn allocimportstrs(count: i32) ([]str | nomem) = { let value: []str = alloc([], count: u64)?; return value; }; fn allocnodeptrs(count: i32) ([]*syntax.node | nomem) = { let value: []*syntax.node = alloc([], count: u64)?; return value; }; fn canonicalpkgname(path: str, name: str) bool = { let prefix: str = "__wwi_"; if (name.len != prefix.len + path.len * 2) { return false; }; let i: i32 = 0; for (i < prefix.len) { if (name[i] != prefix[i]) { return false; }; i += 1; }; i = 0; for (i < path.len) { let hi: u8 = path[i] >> 4u8; let lo: u8 = path[i] & 15u8; let hib: u8 = hi + 48u8; let lob: u8 = lo + 48u8; if (hi >= 10u8) { hib = hi - 10u8 + 97u8; }; if (lo >= 10u8) { lob = lo - 10u8 + 97u8; }; if (name[prefix.len + i * 2] != hib || name[prefix.len + i * 2 + 1] != lob) { return false; }; i += 1; }; return true; }; // A paired interface owns PATH's declared name. Compiler-private names keep // transitive fact sections semantic and are ignored when a real name exists. fn importpkgname(asts: []*syntax.node, paths: []*u8, nasts: i32, path: str, primary: *syntax.node, conflict: *bool) str = { let name: str; let placeholder: str; let i: i32 = 0; for (i < nasts) { if (!cstreq(paths[i], path)) { i += 1; continue; }; let f: *syntax.node = asts[i]; let p: *syntax.node = nil; if (f != nil) { p = f.body; }; for (p != nil) { if (p.nmod.len > 0 && p.pkgname.len > 0 && syntax.streq(p.nmod, path)) { if (canonicalpkgname(path, p.pkgname)) { placeholder = p.pkgname; } else { if (name.len > 0 && !syntax.streq(name, p.pkgname)) { *conflict = true; let empty: str; return empty; } else { name = p.pkgname; }; }; }; p = p.next; }; i += 1; }; let p: *syntax.node = nil; if (primary != nil) { p = primary.body; }; for (p != nil) { if (p.nmod.len > 0 && p.pkgname.len > 0 && syntax.streq(p.nmod, path)) { if (canonicalpkgname(path, p.pkgname)) { placeholder = p.pkgname; } else { if (name.len > 0 && !syntax.streq(name, p.pkgname)) { *conflict = true; let empty: str; return empty; } else { name = p.pkgname; }; }; }; p = p.next; }; if (name.len == 0) { name = placeholder; }; return name; }; fn bindimportnames(list: *syntax.node, asts: []*syntax.node, paths: []*u8, nasts: i32, primary: *syntax.node, testsupport: *u8) bool = { let u: *syntax.node = list; for (u != nil) { if (u.kind == syntax.nkind.N_USE && u.usepath.len > 0) { let reserved: bool = testsupport != nil && cstreq(testsupport, "__wwtest") && syntax.streq(u.usepath, "__wwtest"); if (!reserved) { let conflict: bool = false; let name: str = importpkgname(asts, paths, nasts, u.usepath, primary, &conflict); if (conflict) { let pre: str = "w6c: package "; let post: str = " has conflicting declared names in export data\n"; os.write(2, pre.ptr, pre.len: u64); os.write(2, u.usepath.ptr, u.usepath.len: u64); os.write(2, post.ptr, post.len: u64); return false; }; if (name.len > 0) { u.usepkgname = 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"; os.write(2, pre.ptr, pre.len: u64); os.write(2, u.usepath.ptr, u.usepath.len: u64); os.write(2, post.ptr, post.len: u64); return false; } else { // A closure-only import may have no declarations in this // interface. Its canonical path must never become a leaf // qualifier by fallback. if (u.useblank == 0) { if (u.usealias.len > 0) { u.str = u.usealias; } else { u.str = u.usepath; }; }; }; }; }; }; u = u.next; }; return true; }; export fn main(argc: i32, argv: **u8) i32 = { let src: *u8 = nil; let out: *u8 = nil; let wwiout: *u8 = nil; // -I : M2 export-data producer let testsupport: *u8 = nil; let testmode: i32 = 0i32; // #15: `-T` test-mode 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) let pathallocation: ([]*u8 | nomem) = allocimportptrs(argc); let fileallocation: ([]*u8 | nomem) = allocimportptrs(argc); let targetallocation: ([]str | nomem) = allocimportstrs(argc); let importpaths: []*u8; let importfiles: []*u8; let testtargets: []str; let astallocation: ([]*syntax.node | nomem) = allocnodeptrs(argc); let importasts: []*syntax.node; match (pathallocation) { case let value: []*u8 => importpaths = value; case nomem => { let m: str = "w6c: out of memory\n"; os.write(2, m.ptr, m.len: u64); return 1; }; }; match (fileallocation) { case let value: []*u8 => importfiles = value; case nomem => { let m: str = "w6c: out of memory\n"; os.write(2, m.ptr, m.len: u64); return 1; }; }; importpaths.len = argc; importfiles.len = argc; match (targetallocation) { case let value: []str => testtargets = value; case nomem => { let m: str = "w6c: out of memory\n"; os.write(2, m.ptr, m.len: u64); return 1; }; }; testtargets.len = argc; match (astallocation) { case let value: []*syntax.node => importasts = value; case nomem => { let m: str = "w6c: out of memory\n"; os.write(2, m.ptr, m.len: u64); return 1; }; }; importasts.len = argc; let nimports: i32 = 0; let ntesttargets: i32 = 0; let mapallocation: ([]importmap | nomem) = allocimportmaps(argc); let importmaps: []importmap; match (mapallocation) { case let value: []importmap => importmaps = value; case nomem => { let m: str = "w6c: out of memory\n"; os.write(2, m.ptr, m.len: u64); return 1; }; }; importmaps.len = argc; let nmaps: i32 = 0; let i: i32 = 1; for (i < argc) { let a: *u8 = argv[i]; if (cstreq(a, "-o")) { i += 1; if (i >= argc) { let m: str = "w6c: -o requires arg\n"; os.write(2, m.ptr, m.len: u64); return 2; }; out = argv[i]; } else { if (cstreq(a, "-I")) { i += 1; if (i >= argc) { let m: str = "w6c: -I requires arg\n"; os.write(2, m.ptr, m.len: u64); return 2; }; wwiout = argv[i]; } else { if (cstreq(a, "-T")) { testmode = 1i32; } else { if (cstreq(a, "--test-package")) { testpackage = 1i32; } else { if (cstreq(a, "--command-package")) { 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) { let m: str = "w6c: --test-support-module requires arg\n"; os.write(2, m.ptr, m.len: u64); return 2; }; testsupport = argv[i]; } else { if (cstreq(a, "--test-target-package")) { i += 1; if (i >= argc) { let m: str = "w6c: --test-target-package requires arg\n"; os.write(2, m.ptr, m.len: u64); return 2; }; testtargets[ntesttargets] = pathstr(argv[i]); ntesttargets += 1; } else { if (cstreq(a, "-c")) { sepmode = 1i32; } else { if (cstreq(a, "--import")) { if (i + 2 >= argc) { let m: str = "w6c: --import requires path and file\n"; os.write(2, m.ptr, m.len: u64); return 2; }; importpaths[nimports] = argv[i + 1]; importfiles[nimports] = argv[i + 2]; nimports += 1; i += 2; } else { if (cstreq(a, "--import-map")) { if (i + 2 >= argc) { let m: str = "w6c: --import-map requires source and path\n"; os.write(2, m.ptr, m.len: u64); return 2; }; importmaps[nmaps].source = argv[i + 1]; importmaps[nmaps].path = argv[i + 2]; importmaps[nmaps].seen = false; nmaps += 1; i += 2; } else { if (a[0u64] == 45u8) { let m: str = "w6c: unknown flag\n"; os.write(2, m.ptr, m.len: u64); return 2; } else { if (src != nil) { let m: str = "w6c: only one input\n"; os.write(2, m.ptr, m.len: u64); return 2; }; src = a; }; }; }; }; }; }; }; }; }; }; }; }; }; }; i += 1; }; if (src == nil) { 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; }; if (nimports > 0 && sepmode == 0) { let m: str = "w6c: --import requires -c\n"; os.write(2, m.ptr, m.len: u64); return 2; }; if (nmaps > 0 && sepmode == 0) { let m: str = "w6c: --import-map requires -c\n"; os.write(2, m.ptr, m.len: u64); return 2; }; if ((entrymode != 0 || testpackage != 0 || commandpackage != 0) && sepmode == 0) { let m: str = "w6c: --entry, --test-package, and --command-package require -c\n"; 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); return 2; }; let importi: i32 = 0; for (importi < nimports) { if (importpaths[importi][0u64] == 0u8) { let m: str = "w6c: --import path is empty\n"; os.write(2, m.ptr, m.len: u64); return 2; }; if (importi > 0 && strings.compare(pathstr(importpaths[importi - 1]), pathstr(importpaths[importi])) >= 0) { let m: str = "w6c: --import paths must be sorted and unique\n"; os.write(2, m.ptr, m.len: u64); return 2; }; importi += 1; }; let mapi: i32 = 0; for (mapi < nmaps) { if (importmaps[mapi].source[0u64] == 0u8 || importmaps[mapi].path[0u64] == 0u8) { let m: str = "w6c: --import-map path is empty\n"; os.write(2, m.ptr, m.len: u64); return 2; }; if (mapi > 0 && strings.compare(pathstr(importmaps[mapi - 1].source), pathstr(importmaps[mapi].source)) >= 0) { let m: str = "w6c: --import-map sources must be sorted and unique\n"; os.write(2, m.ptr, m.len: u64); return 2; }; let direct: bool = false; let directi: i32 = 0; for (directi < nimports) { if (cstreq(importmaps[mapi].path, pathstr(importpaths[directi]))) { direct = true; break; }; directi += 1; }; if (!direct) { let m: str = "w6c: --import-map target is not a direct import\n"; os.write(2, m.ptr, m.len: u64); return 2; }; mapi += 1; }; if (testsupport != nil && (sepmode == 0 || (!cstreq(testsupport, "test") && !cstreq(testsupport, "__wwtest")))) { let m: str = "w6c: invalid --test-support-module\n"; os.write(2, m.ptr, m.len: u64); return 2; }; let targeti: i32 = 0; for (targeti < ntesttargets) { let testtarget: str = testtargets[targeti]; if (sepmode == 0 || testmode == 0 || testtarget.len == 0) { let m: str = "w6c: invalid --test-target-package\n"; os.write(2, m.ptr, m.len: u64); return 2; }; if (targeti > 0 && strings.compare(testtargets[targeti - 1], testtarget) >= 0) { let m: str = "w6c: --test-target-package paths must be sorted and unique\n"; os.write(2, m.ptr, m.len: u64); return 2; }; let direct: bool = false; importi = 0; for (importi < nimports) { if (syntax.streq(pathstr(importpaths[importi]), testtarget)) { direct = true; }; importi += 1; }; if (!direct) { let m: str = "w6c: --test-target-package is not a direct import\n"; os.write(2, m.ptr, m.len: u64); return 2; }; targeti += 1; }; let importhead: *syntax.node = nil; let importtail: *syntax.node = nil; importi = 0; for (importi < nimports) { let ibuf: *u8; let ilen: u64; ibuf, ilen = slurp(importfiles[importi]); if (ibuf == nil) { let pre: str = "w6c: import "; let mid: str = ": cannot read "; let nl: str = "\n"; let ipath: str = pathstr(importpaths[importi]); let ifile: str = pathstr(importfiles[importi]); os.write(2, pre.ptr, pre.len: u64); os.write(2, ipath.ptr, ipath.len: u64); os.write(2, mid.ptr, mid.len: u64); os.write(2, ifile.ptr, ifile.len: u64); os.write(2, nl.ptr, nl.len: u64); return 1; }; if (!exportownermatches(ibuf, ilen, importpaths[importi])) { let pre: str = "w6c: import "; let mid: str = ": export owner mismatch in "; let nl: str = "\n"; os.write(2, pre.ptr, pre.len: u64); os.write(2, importpaths[importi], cstrlen(importpaths[importi])); os.write(2, mid.ptr, mid.len: u64); os.write(2, importfiles[importi], cstrlen(importfiles[importi])); os.write(2, nl.ptr, nl.len: u64); return 1; }; let il: syntax.lex; syntax.lexinit(&il, strings.dup(pathstr(importfiles[importi])), ibuf, ilen); let ips: syntax.parser; syntax.parserinit(&ips, &il); let imod: str = pathstr(importpaths[importi]); ips.pathmod = imod; ips.curmod = imod; if (testsupport != nil) { ips.testmodule = pathstr(testsupport); }; let imported: *syntax.node = syntax.parsefile(&ips); if (il.errs > 0 || ips.errs > 0) { return 1; }; importasts[importi] = imported; if (!bindimportnames(imported.list, importasts, importpaths, importi + 1, nil, testsupport)) { return 1; }; let d: *syntax.node = imported.list; if (d != nil) { if (importhead == nil) { importhead = d; } else { importtail.next = d; }; for (d.next != nil) { d = d.next; }; importtail = d; }; importi += 1; }; let buf: *u8; let blen: u64; buf, blen = slurp(src); if (buf == nil) { let m: str = "w6c: cannot read input\n"; os.write(2, m.ptr, m.len: u64); return 1; }; let l: syntax.lex; syntax.lexinit(&l, strings.dup(pathstr(src)), buf, blen); let ps: syntax.parser; syntax.parserinit(&ps, &l); if (testsupport != nil) { ps.testmodule = pathstr(testsupport); }; // Entry compilation classifies an ordinary command package. The explicit // marker carries only that parser fact for non-entry command test variants. ps.commandpackage = commandpackage != 0 || entrymode != 0; let f: *syntax.node = syntax.parsefile(&ps); // Gate cgen on parse-stage errors. Mirrors cmd/w6c/main.c's // `if (l.errs || p.errs) return 1;` — broken AST otherwise reaches // cgen and emits junk asm with a zero exit (silent miscompile). if (l.errs > 0 || ps.errs > 0) { return 1; }; let use: *syntax.node = f.list; for (use != nil) { if (use.kind == syntax.nkind.N_USE && use.usepath.len != 0) { let source: str = use.usesource; if (source.len == 0) { source = use.usepath; }; mapi = 0; for (mapi < nmaps) { if (syntax.streq(source, pathstr(importmaps[mapi].source))) { use.usepath = pathstr(importmaps[mapi].path); importmaps[mapi].seen = true; break; }; mapi += 1; }; }; use = use.next; }; mapi = 0; for (mapi < nmaps) { if (!importmaps[mapi].seen) { let m: str = "w6c: --import-map source is not in primary input\n"; os.write(2, m.ptr, m.len: u64); return 2; }; mapi += 1; }; // A later direct interface may supply metadata for an origin section used // by an earlier interface, so bind once more against the complete set. importi = 0; for (importi < nimports) { if (!bindimportnames(importasts[importi].list, importasts, importpaths, nimports, nil, testsupport)) { return 1; }; importi += 1; }; if (!bindimportnames(f.list, importasts, importpaths, nimports, f, testsupport)) { return 1; }; targeti = 0; for (targeti < ntesttargets) { let seen: i32 = 0; let targetuse: *syntax.node = f.list; for (targetuse != nil) { if (targetuse.kind == syntax.nkind.N_USE && targetuse.imported == 0 && syntax.streq(targetuse.usepath, testtargets[targeti])) { targetuse.str = targetuse.usepath; seen += 1; }; targetuse = targetuse.next; }; if (seen != 1) { let m: str = "w6c: generated test target import is not unique\n"; os.write(2, m.ptr, m.len: u64); return 2; }; targeti += 1; }; if (importhead != nil) { importtail.next = f.list; f.list = importhead; }; 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) { asmfd = anonymousfd(out, "anon.asm"); if (asmfd < 0) { if (wwifd >= 0) { os.close(wwifd); }; return 1; }; if (os.dup2(asmfd, 1i32) < 0) { let m: str = "w6c: dup2 failed\n"; os.write(2, m.ptr, m.len: u64); os.close(asmfd); if (wwifd >= 0) { os.close(wwifd); }; return 1; }; }; let testmodule: str; if (testsupport != nil) { testmodule = pathstr(testsupport); }; testtargets.len = ntesttargets; 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, testtargets, 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; pubs[pi].passthrough = 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; };