254 lines
6.8 KiB
Plaintext
254 lines
6.8 KiB
Plaintext
// 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 <out.wwi>: 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);
|
|
};
|