ww: implement local vendor package semantics
This commit is contained in:
@@ -79,6 +79,31 @@ fn exportownermatches(buf: *u8, n: u64, path: *u8) bool = {
|
||||
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 importleaf(path: *u8) str = {
|
||||
let whole: str = pathstr(path);
|
||||
let (prefix, suffix) = strings.rcut(whole, ".");
|
||||
// rcut returns (whole, empty) when absent and (prefix, empty) for a
|
||||
// trailing delimiter. Preserve that distinction to match strrchr.
|
||||
if (suffix.len != 0 || prefix.len != whole.len) { return suffix; };
|
||||
return whole;
|
||||
};
|
||||
|
||||
export fn main(argc: i32, argv: **u8) i32 = {
|
||||
let src: *u8 = nil;
|
||||
let out: *u8 = nil;
|
||||
@@ -91,11 +116,41 @@ export fn main(argc: i32, argv: **u8) i32 = {
|
||||
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)!;
|
||||
let pathallocation: ([]*u8 | nomem) = allocimportptrs(argc);
|
||||
let fileallocation: ([]*u8 | nomem) = allocimportptrs(argc);
|
||||
let importpaths: []*u8;
|
||||
let importfiles: []*u8;
|
||||
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;
|
||||
let importfiles: []*u8 = alloc([], argc: u64)!;
|
||||
importfiles.len = argc;
|
||||
let nimports: 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) {
|
||||
@@ -144,6 +199,17 @@ export fn main(argc: i32, argv: **u8) i32 = {
|
||||
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);
|
||||
@@ -155,12 +221,12 @@ 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] [-c] [-I out.wwi] [--import path dep.wwi]... [-o out.s] file.ww\n";
|
||||
let m: str = "usage: w6c_ww [-T|--test-package] [--command-package] [--entry] [-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;
|
||||
};
|
||||
@@ -169,6 +235,11 @@ export fn main(argc: i32, argv: **u8) i32 = {
|
||||
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";
|
||||
@@ -195,6 +266,43 @@ export fn main(argc: i32, argv: **u8) i32 = {
|
||||
};
|
||||
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;
|
||||
};
|
||||
if (!syntax.streq(importleaf(importmaps[mapi].source),
|
||||
importleaf(importmaps[mapi].path))) {
|
||||
let m: str = "w6c: --import-map must preserve import leaf\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")))) {
|
||||
@@ -275,6 +383,31 @@ export fn main(argc: i32, argv: **u8) i32 = {
|
||||
// `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: *node = f.list;
|
||||
for (use != nil) {
|
||||
if (use.kind == syntax.nkind.N_USE && use.usepath.len != 0) {
|
||||
mapi = 0;
|
||||
for (mapi < nmaps) {
|
||||
if (syntax.streq(use.usepath,
|
||||
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;
|
||||
};
|
||||
if (importhead != nil) {
|
||||
importtail.next = f.list;
|
||||
f.list = importhead;
|
||||
|
||||
Reference in New Issue
Block a user