ww: separate package identity from declared name
This commit is contained in:
@@ -3,7 +3,6 @@
|
||||
package main;
|
||||
|
||||
import os;
|
||||
import rt;
|
||||
import strings;
|
||||
import syntax;
|
||||
import wcc;
|
||||
@@ -95,13 +94,93 @@ fn allocimportptrs(count: i32) ([]*u8 | nomem) = {
|
||||
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;
|
||||
fn allocnodeptrs(count: i32) ([]*syntax.node | nomem) = {
|
||||
let value: []*syntax.node = alloc([], count: u64)?;
|
||||
return value;
|
||||
};
|
||||
|
||||
// Export data carries canonical owner and declared name independently. Each
|
||||
// direct interface's package-clause markers also describe its reachable fact
|
||||
// closure, so search all parsed interfaces for a canonical owner.
|
||||
fn importpkgname(asts: []*syntax.node, nasts: i32, path: str,
|
||||
primary: *syntax.node, conflict: *bool) str = {
|
||||
let name: str;
|
||||
let i: i32 = 0;
|
||||
for (i < nasts) {
|
||||
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 (name.len > 0 && !syntax.streq(name, p.pkgname)) {
|
||||
*conflict = true;
|
||||
let empty: str;
|
||||
return empty;
|
||||
};
|
||||
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 (name.len > 0 && !syntax.streq(name, p.pkgname)) {
|
||||
*conflict = true;
|
||||
let empty: str;
|
||||
return empty;
|
||||
};
|
||||
name = p.pkgname;
|
||||
};
|
||||
p = p.next;
|
||||
};
|
||||
return name;
|
||||
};
|
||||
|
||||
fn bindimportnames(list: *syntax.node, asts: []*syntax.node, 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, 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.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.
|
||||
u.str = u.usepath;
|
||||
}; };
|
||||
};
|
||||
};
|
||||
u = u.next;
|
||||
};
|
||||
return true;
|
||||
};
|
||||
|
||||
export fn main(argc: i32, argv: **u8) i32 = {
|
||||
@@ -109,6 +188,7 @@ export fn main(argc: i32, argv: **u8) i32 = {
|
||||
let out: *u8 = nil;
|
||||
let wwiout: *u8 = nil; // -I <out.wwi>: M2 export-data producer
|
||||
let testsupport: *u8 = nil;
|
||||
let testtarget: *u8 = nil;
|
||||
let testmode: i32 = 0i32; // #15: `-T` test-mode
|
||||
let testpackage: i32 = 0i32;
|
||||
let commandpackage: i32 = 0i32;
|
||||
@@ -120,6 +200,8 @@ export fn main(argc: i32, argv: **u8) i32 = {
|
||||
let fileallocation: ([]*u8 | nomem) = allocimportptrs(argc);
|
||||
let importpaths: []*u8;
|
||||
let importfiles: []*u8;
|
||||
let astallocation: ([]*syntax.node | nomem) = allocnodeptrs(argc);
|
||||
let importasts: []*syntax.node;
|
||||
match (pathallocation) {
|
||||
case let value: []*u8 => importpaths = value;
|
||||
case nomem => {
|
||||
@@ -138,6 +220,15 @@ export fn main(argc: i32, argv: **u8) i32 = {
|
||||
};
|
||||
importpaths.len = argc;
|
||||
importfiles.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 mapallocation: ([]importmap | nomem) = allocimportmaps(argc);
|
||||
let importmaps: []importmap;
|
||||
@@ -187,6 +278,14 @@ export fn main(argc: i32, argv: **u8) i32 = {
|
||||
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;
|
||||
};
|
||||
testtarget = argv[i];
|
||||
} else { if (cstreq(a, "-c")) {
|
||||
sepmode = 1i32;
|
||||
} else { if (cstreq(a, "--import")) {
|
||||
@@ -221,12 +320,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]... [--import-map source path]... [-o out.s] file.ww\n";
|
||||
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";
|
||||
os.write(2, m.ptr, m.len: u64);
|
||||
return 2;
|
||||
};
|
||||
@@ -280,12 +379,6 @@ export fn main(argc: i32, argv: **u8) i32 = {
|
||||
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) {
|
||||
@@ -310,6 +403,27 @@ export fn main(argc: i32, argv: **u8) i32 = {
|
||||
os.write(2, m.ptr, m.len: u64);
|
||||
return 2;
|
||||
};
|
||||
if (testtarget != nil && (sepmode == 0 || testmode == 0
|
||||
|| testtarget[0u64] == 0u8)) {
|
||||
let m: str = "w6c: invalid --test-target-package\n";
|
||||
os.write(2, m.ptr, m.len: u64);
|
||||
return 2;
|
||||
};
|
||||
if (testtarget != nil) {
|
||||
let direct: bool = false;
|
||||
importi = 0;
|
||||
for (importi < nimports) {
|
||||
if (cstreq(importpaths[importi], pathstr(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;
|
||||
};
|
||||
};
|
||||
|
||||
let importhead: *node = nil;
|
||||
let importtail: *node = nil;
|
||||
@@ -352,6 +466,9 @@ export fn main(argc: i32, argv: **u8) i32 = {
|
||||
if (testsupport != nil) { ips.testmodule = pathstr(testsupport); };
|
||||
let imported: *node = parsefile(&ips);
|
||||
if (il.errs > 0 || ips.errs > 0) { return 1; };
|
||||
importasts[importi] = imported;
|
||||
if (!bindimportnames(imported.list, importasts, importi + 1,
|
||||
nil, testsupport)) { return 1; };
|
||||
let d: *node = imported.list;
|
||||
if (d != nil) {
|
||||
if (importhead == nil) { importhead = d; }
|
||||
@@ -408,6 +525,35 @@ export fn main(argc: i32, argv: **u8) i32 = {
|
||||
};
|
||||
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, nimports,
|
||||
nil, testsupport)) { return 1; };
|
||||
importi += 1;
|
||||
};
|
||||
if (!bindimportnames(f.list, importasts, nimports, f, testsupport)) {
|
||||
return 1;
|
||||
};
|
||||
if (testtarget != nil) {
|
||||
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, pathstr(testtarget))) {
|
||||
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;
|
||||
};
|
||||
};
|
||||
if (importhead != nil) {
|
||||
importtail.next = f.list;
|
||||
f.list = importhead;
|
||||
@@ -433,8 +579,10 @@ export fn main(argc: i32, argv: **u8) i32 = {
|
||||
|
||||
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, sepmode,
|
||||
interfaceout, entrymode);
|
||||
return wcc.compilefile(f, testmode, testpackage, testmodule,
|
||||
testtargetmodule, sepmode, interfaceout, entrymode);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user