// Port of cmd/w6c/main.c. package main; import os; import rt; import strings; import syntax; import wcc; 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; }; 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 sepmode: i32 = 0i32; // -c: #22 M3 separate-compile / primary- // only codegen (emit imported==0 decls // only; treat `.wwi` deps as external) let importpaths: []*u8 = alloc([], argc: u64)!; importpaths.len = argc; let importfiles: []*u8 = alloc([], argc: u64)!; importfiles.len = argc; let nimports: 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-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, "-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 (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] [-c] [-I out.wwi] [--import path dep.wwi]... [-o out.s] file.ww\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; }; 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; }; 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 importhead: *node = nil; let importtail: *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; }; let il: lex; lexinit(&il, strings.dup(pathstr(importfiles[importi])), ibuf, ilen); let ips: parser; parserinit(&ips, &il); let imod: str = pathstr(importpaths[importi]); ips.pathmod = imod; ips.curmod = imod; if (testsupport != nil) { ips.testmodule = pathstr(testsupport); }; let imported: *node = parsefile(&ips); if (il.errs > 0 || ips.errs > 0) { return 1; }; let d: *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: lex; lexinit(&l, strings.dup(pathstr(src)), buf, blen); let ps: parser; parserinit(&ps, &l); if (testsupport != nil) { ps.testmodule = pathstr(testsupport); }; let f: *node = 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; }; if (importhead != nil) { importtail.next = f.list; f.list = importhead; }; // cgen writes directly to fd 1; dup2 keeps that implementation private. 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); return 1; }; if (os.dup2(ofd, 1i32) < 0) { let m: str = "w6c: dup2 failed\n"; os.write(2, m.ptr, m.len: u64); os.close(ofd); return 1; }; os.close(ofd); }; let testmodule: str; if (testsupport != nil) { testmodule = pathstr(testsupport); }; let interfaceout: str; if (wwiout != nil) { interfaceout = pathstr(wwiout); }; return wcc.compilefile(f, testmode, testmodule, sepmode, interfaceout); };