ww: add file-scoped import aliases
This commit is contained in:
@@ -99,26 +99,52 @@ fn allocnodeptrs(count: i32) ([]*syntax.node | nomem) = {
|
||||
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,
|
||||
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 (name.len > 0 && !syntax.streq(name, p.pkgname)) {
|
||||
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;
|
||||
};
|
||||
name = p.pkgname;
|
||||
} else { name = p.pkgname; }; };
|
||||
};
|
||||
p = p.next;
|
||||
};
|
||||
@@ -129,19 +155,22 @@ fn importpkgname(asts: []*syntax.node, nasts: i32, path: str,
|
||||
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)) {
|
||||
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;
|
||||
};
|
||||
name = p.pkgname;
|
||||
} else { name = p.pkgname; }; };
|
||||
};
|
||||
p = p.next;
|
||||
};
|
||||
if (name.len == 0) { name = placeholder; };
|
||||
return name;
|
||||
};
|
||||
|
||||
fn bindimportnames(list: *syntax.node, asts: []*syntax.node, nasts: i32,
|
||||
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) {
|
||||
@@ -151,7 +180,7 @@ fn bindimportnames(list: *syntax.node, asts: []*syntax.node, nasts: i32,
|
||||
&& syntax.streq(u.usepath, "__wwtest");
|
||||
if (!reserved) {
|
||||
let conflict: bool = false;
|
||||
let name: str = importpkgname(asts, nasts, u.usepath,
|
||||
let name: str = importpkgname(asts, paths, nasts, u.usepath,
|
||||
primary, &conflict);
|
||||
if (conflict) {
|
||||
let pre: str = "w6c: package ";
|
||||
@@ -162,7 +191,9 @@ fn bindimportnames(list: *syntax.node, asts: []*syntax.node, nasts: i32,
|
||||
return false;
|
||||
};
|
||||
if (name.len > 0) {
|
||||
u.str = name;
|
||||
u.usepkgname = name;
|
||||
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";
|
||||
@@ -174,7 +205,8 @@ fn bindimportnames(list: *syntax.node, asts: []*syntax.node, nasts: i32,
|
||||
// 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;
|
||||
if (u.usealias.len > 0) { u.str = u.usealias; }
|
||||
else { u.str = u.usepath; };
|
||||
}; };
|
||||
};
|
||||
};
|
||||
@@ -425,8 +457,8 @@ export fn main(argc: i32, argv: **u8) i32 = {
|
||||
};
|
||||
};
|
||||
|
||||
let importhead: *node = nil;
|
||||
let importtail: *node = nil;
|
||||
let importhead: *syntax.node = nil;
|
||||
let importtail: *syntax.node = nil;
|
||||
importi = 0;
|
||||
for (importi < nimports) {
|
||||
let ibuf: *u8;
|
||||
@@ -456,20 +488,20 @@ export fn main(argc: i32, argv: **u8) i32 = {
|
||||
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 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: *node = parsefile(&ips);
|
||||
let imported: *syntax.node = syntax.parsefile(&ips);
|
||||
if (il.errs > 0 || ips.errs > 0) { return 1; };
|
||||
importasts[importi] = imported;
|
||||
if (!bindimportnames(imported.list, importasts, importi + 1,
|
||||
if (!bindimportnames(imported.list, importasts, importpaths, importi + 1,
|
||||
nil, testsupport)) { return 1; };
|
||||
let d: *node = imported.list;
|
||||
let d: *syntax.node = imported.list;
|
||||
if (d != nil) {
|
||||
if (importhead == nil) { importhead = d; }
|
||||
else { importtail.next = d; };
|
||||
@@ -487,25 +519,27 @@ export fn main(argc: i32, argv: **u8) i32 = {
|
||||
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);
|
||||
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: *node = parsefile(&ps);
|
||||
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: *node = f.list;
|
||||
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(use.usepath,
|
||||
if (syntax.streq(source,
|
||||
pathstr(importmaps[mapi].source))) {
|
||||
use.usepath = pathstr(importmaps[mapi].path);
|
||||
importmaps[mapi].seen = true;
|
||||
@@ -529,11 +563,13 @@ export fn main(argc: i32, argv: **u8) i32 = {
|
||||
// by an earlier interface, so bind once more against the complete set.
|
||||
importi = 0;
|
||||
for (importi < nimports) {
|
||||
if (!bindimportnames(importasts[importi].list, importasts, nimports,
|
||||
if (!bindimportnames(importasts[importi].list, importasts, importpaths,
|
||||
nimports,
|
||||
nil, testsupport)) { return 1; };
|
||||
importi += 1;
|
||||
};
|
||||
if (!bindimportnames(f.list, importasts, nimports, f, testsupport)) {
|
||||
if (!bindimportnames(f.list, importasts, importpaths, nimports, f,
|
||||
testsupport)) {
|
||||
return 1;
|
||||
};
|
||||
if (testtarget != nil) {
|
||||
|
||||
Reference in New Issue
Block a user