ww: add file-scoped import aliases
This commit is contained in:
164
cmd/w6c/wwi.c
164
cmd/w6c/wwi.c
@@ -68,19 +68,41 @@ wwi_use_path(Checker *c, const char *owner, int source, const char *alias)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int
|
||||
wwi_direct_mod_visible(Checker *c, const char *owner, int source,
|
||||
const char *mod)
|
||||
/* Export spelling is derived only from canonical identity. The bytewise hex
|
||||
* encoding is injective, source-identifier-safe, and independent of a local
|
||||
* alias or the dependency's declared package name. */
|
||||
static void
|
||||
wwi_canonical_alias(FILE *of, const char *path)
|
||||
{
|
||||
if (mod == NULL || mod[0] == '\0') return 0;
|
||||
for (Node *u = c->file->list; u; u = u->next) {
|
||||
if (u->kind != N_USE || u->sourceid != source) continue;
|
||||
int same = owner == NULL ? u->imported == 0
|
||||
: u->imported != 0 && wwi_mod_eq(u->module, owner);
|
||||
const char *path = u->usepath ? u->usepath : u->str;
|
||||
if (same && path != NULL && strcmp(path, mod) == 0) return 1;
|
||||
static const char hex[] = "0123456789abcdef";
|
||||
fputs("__wwi_", of);
|
||||
for (const unsigned char *p = (const unsigned char *)path; *p; p++) {
|
||||
fputc(hex[*p >> 4], of);
|
||||
fputc(hex[*p & 15], of);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
wwi_name(Checker *c, FILE *of, const char *owner, int source,
|
||||
const char *name)
|
||||
{
|
||||
if (name == NULL) return;
|
||||
const char *dot = strrchr(name, '.');
|
||||
if (dot != NULL) {
|
||||
size_t n = (size_t)(dot - name);
|
||||
char *alias = malloc(n + 1);
|
||||
if (alias == NULL) fatal("wwi: out of memory");
|
||||
memcpy(alias, name, n);
|
||||
alias[n] = '\0';
|
||||
const char *path = wwi_use_path(c, owner, source, alias);
|
||||
free(alias);
|
||||
if (path != NULL) {
|
||||
wwi_canonical_alias(of, path);
|
||||
fputs(dot, of);
|
||||
return;
|
||||
}
|
||||
}
|
||||
fputs(name, of);
|
||||
}
|
||||
|
||||
static Sym *
|
||||
@@ -101,20 +123,6 @@ wwi_typesym(Checker *c, const char *owner, int source, const char *nm)
|
||||
free(alias);
|
||||
} else {
|
||||
s = scope_lookup_type(c->cur, owner, nm);
|
||||
if (s == NULL) {
|
||||
for (Scope *p = c->cur; p; p = p->parent) {
|
||||
for (Sym *b = p->first; b; b = b->next) {
|
||||
if (b->kind == SK_TYPE
|
||||
&& strcmp(b->name, nm) == 0
|
||||
&& wwi_direct_mod_visible(c, owner, source,
|
||||
b->mod)) {
|
||||
s = b;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (s != NULL) break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (s && s->kind == SK_TYPE)
|
||||
return s;
|
||||
@@ -197,8 +205,8 @@ wwi_check_decl(Checker *c, Node *d)
|
||||
|
||||
/* type-expr unparse per rob §2.2; const-expr per rob §2.4. */
|
||||
|
||||
static void wwi_expr(FILE *of, Node *e);
|
||||
static void wwi_type(FILE *of, Node *t);
|
||||
static void wwi_expr(Checker*, FILE*, const char*, int, Node*);
|
||||
static void wwi_type(Checker*, FILE*, const char*, int, Node*);
|
||||
|
||||
static void
|
||||
wwi_quote(FILE *of, const char *s, u64 n)
|
||||
@@ -248,7 +256,7 @@ wwi_rune(FILE *of, u64 cp)
|
||||
}
|
||||
|
||||
static void
|
||||
wwi_param(FILE *of, Node *p)
|
||||
wwi_param(Checker *c, FILE *of, const char *owner, int source, Node *p)
|
||||
{
|
||||
if (p->str && strcmp(p->str, "...") == 0) { /* C-style FFI `...` */
|
||||
fputs("...", of);
|
||||
@@ -258,13 +266,13 @@ wwi_param(FILE *of, Node *p)
|
||||
fputs(p->str, of);
|
||||
fputs(": ", of);
|
||||
}
|
||||
wwi_type(of, p->lhs);
|
||||
wwi_type(c, of, owner, source, p->lhs);
|
||||
if (p->op == TK_ELLIPSIS) /* Hare `T...` variadic */
|
||||
fputs("...", of);
|
||||
}
|
||||
|
||||
static void
|
||||
wwi_type(FILE *of, Node *t)
|
||||
wwi_type(Checker *c, FILE *of, const char *owner, int source, Node *t)
|
||||
{
|
||||
if (t == NULL) { /* absent return type spells void */
|
||||
fputs("void", of);
|
||||
@@ -272,39 +280,40 @@ wwi_type(FILE *of, Node *t)
|
||||
}
|
||||
switch (t->kind) {
|
||||
case N_TNAME:
|
||||
fputs(t->str ? t->str : "void", of);
|
||||
if (t->str) wwi_name(c, of, owner, source, t->str);
|
||||
else fputs("void", of);
|
||||
break;
|
||||
case N_TPTR:
|
||||
fputc('*', of);
|
||||
wwi_type(of, t->lhs);
|
||||
wwi_type(c, of, owner, source, t->lhs);
|
||||
break;
|
||||
case N_TSLICE:
|
||||
fputs("[]", of);
|
||||
wwi_type(of, t->lhs);
|
||||
wwi_type(c, of, owner, source, t->lhs);
|
||||
break;
|
||||
case N_TARRAY:
|
||||
fputc('[', of);
|
||||
if (t->rhs) wwi_expr(of, t->rhs);
|
||||
if (t->rhs) wwi_expr(c, of, owner, source, t->rhs);
|
||||
else fputc('_', of);
|
||||
fputc(']', of);
|
||||
wwi_type(of, t->lhs);
|
||||
wwi_type(c, of, owner, source, t->lhs);
|
||||
break;
|
||||
case N_TBANG:
|
||||
fputc('!', of);
|
||||
wwi_type(of, t->lhs);
|
||||
wwi_type(c, of, owner, source, t->lhs);
|
||||
break;
|
||||
case N_TCHAN:
|
||||
fputs("chan ", of);
|
||||
wwi_type(of, t->lhs);
|
||||
wwi_type(c, of, owner, source, t->lhs);
|
||||
break;
|
||||
case N_TFN:
|
||||
fputs("fn(", of);
|
||||
for (Node *p = t->list; p; p = p->next) {
|
||||
if (p != t->list) fputs(", ", of);
|
||||
wwi_param(of, p);
|
||||
wwi_param(c, of, owner, source, p);
|
||||
}
|
||||
fputs(") ", of);
|
||||
wwi_type(of, t->lhs);
|
||||
wwi_type(c, of, owner, source, t->lhs);
|
||||
break;
|
||||
case N_TSTRUCT:
|
||||
/* re-emit the `@packed` attr so the flag round-trips
|
||||
@@ -316,7 +325,7 @@ wwi_type(FILE *of, Node *t)
|
||||
fputs(f->str, of);
|
||||
fputs(": ", of);
|
||||
}
|
||||
wwi_type(of, f->lhs);
|
||||
wwi_type(c, of, owner, source, f->lhs);
|
||||
}
|
||||
fputs(" }", of);
|
||||
break;
|
||||
@@ -324,7 +333,7 @@ wwi_type(FILE *of, Node *t)
|
||||
fputc('(', of);
|
||||
for (Node *e = t->list; e; e = e->next) {
|
||||
if (e != t->list) fputs(", ", of);
|
||||
wwi_type(of, e);
|
||||
wwi_type(c, of, owner, source, e);
|
||||
}
|
||||
fputc(')', of);
|
||||
break;
|
||||
@@ -337,14 +346,14 @@ wwi_type(FILE *of, Node *t)
|
||||
* unparse/type.ha:290-300). */
|
||||
if (e->op == TK_ELLIPSIS)
|
||||
fputs("...", of);
|
||||
wwi_type(of, e);
|
||||
wwi_type(c, of, owner, source, e);
|
||||
}
|
||||
fputc(')', of);
|
||||
break;
|
||||
case N_TENUM:
|
||||
fputs("enum ", of);
|
||||
if (t->lhs) {
|
||||
wwi_type(of, t->lhs);
|
||||
wwi_type(c, of, owner, source, t->lhs);
|
||||
fputc(' ', of);
|
||||
}
|
||||
fputs("{ ", of);
|
||||
@@ -353,7 +362,7 @@ wwi_type(FILE *of, Node *t)
|
||||
fputs(m->str, of);
|
||||
if (m->lhs) {
|
||||
fputs(" = ", of);
|
||||
wwi_expr(of, m->lhs);
|
||||
wwi_expr(c, of, owner, source, m->lhs);
|
||||
}
|
||||
}
|
||||
fputs(" }", of);
|
||||
@@ -364,7 +373,7 @@ wwi_type(FILE *of, Node *t)
|
||||
}
|
||||
|
||||
static void
|
||||
wwi_expr(FILE *of, Node *e)
|
||||
wwi_expr(Checker *c, FILE *of, const char *owner, int source, Node *e)
|
||||
{
|
||||
if (e == NULL)
|
||||
return;
|
||||
@@ -375,10 +384,17 @@ wwi_expr(FILE *of, Node *e)
|
||||
break;
|
||||
case N_IDENT:
|
||||
case N_TNAME:
|
||||
fputs(e->str, of);
|
||||
wwi_name(c, of, owner, source, e->str);
|
||||
break;
|
||||
case N_DOT:
|
||||
wwi_expr(of, e->lhs);
|
||||
if (e->lhs && e->lhs->kind == N_IDENT) {
|
||||
const char *path = wwi_use_path(c, owner, source,
|
||||
e->lhs->str);
|
||||
if (path != NULL) wwi_canonical_alias(of, path);
|
||||
else wwi_expr(c, of, owner, source, e->lhs);
|
||||
} else {
|
||||
wwi_expr(c, of, owner, source, e->lhs);
|
||||
}
|
||||
fputc('.', of);
|
||||
fputs(e->str, of);
|
||||
break;
|
||||
@@ -393,20 +409,20 @@ wwi_expr(FILE *of, Node *e)
|
||||
case N_RUNELIT: wwi_rune(of, e->uval); break;
|
||||
case N_BIN:
|
||||
fputc('(', of);
|
||||
wwi_expr(of, e->lhs);
|
||||
wwi_expr(c, of, owner, source, e->lhs);
|
||||
fprintf(of, " %s ", tokname(e->op));
|
||||
wwi_expr(of, e->rhs);
|
||||
wwi_expr(c, of, owner, source, e->rhs);
|
||||
fputc(')', of);
|
||||
break;
|
||||
case N_UN:
|
||||
fputs(tokname(e->op), of);
|
||||
wwi_expr(of, e->lhs);
|
||||
wwi_expr(c, of, owner, source, e->lhs);
|
||||
break;
|
||||
case N_CAST:
|
||||
fputc('(', of);
|
||||
wwi_expr(of, e->lhs);
|
||||
wwi_expr(c, of, owner, source, e->lhs);
|
||||
fputs(": ", of);
|
||||
wwi_type(of, e->rhs);
|
||||
wwi_type(c, of, owner, source, e->rhs);
|
||||
fputc(')', of);
|
||||
break;
|
||||
default:
|
||||
@@ -428,7 +444,7 @@ wwi_attr_relevant(const char *nm)
|
||||
}
|
||||
|
||||
static void
|
||||
wwi_attrs(FILE *of, Node *d)
|
||||
wwi_attrs(Checker *c, FILE *of, const char *owner, Node *d)
|
||||
{
|
||||
for (Node *a = d->attr; a; a = a->next) {
|
||||
if (a->kind != N_ATTR || !wwi_attr_relevant(a->str))
|
||||
@@ -439,7 +455,7 @@ wwi_attrs(FILE *of, Node *d)
|
||||
fputc('(', of);
|
||||
for (Node *arg = a->list; arg; arg = arg->next) {
|
||||
if (arg != a->list) fputs(", ", of);
|
||||
wwi_expr(of, arg);
|
||||
wwi_expr(c, of, owner, d->sourceid, arg);
|
||||
}
|
||||
fputc(')', of);
|
||||
}
|
||||
@@ -448,34 +464,34 @@ wwi_attrs(FILE *of, Node *d)
|
||||
}
|
||||
|
||||
static void
|
||||
wwi_decl(FILE *of, Node *d)
|
||||
wwi_decl(Checker *c, FILE *of, const char *owner, Node *d)
|
||||
{
|
||||
switch (d->kind) {
|
||||
case N_FNDECL:
|
||||
wwi_attrs(of, d);
|
||||
wwi_attrs(c, of, owner, d);
|
||||
fputs(d->export ? "export fn " : "fn ", of);
|
||||
fputs(d->str, of);
|
||||
fputc('(', of);
|
||||
for (Node *p = d->list; p; p = p->next) {
|
||||
if (p != d->list) fputs(", ", of);
|
||||
wwi_param(of, p);
|
||||
wwi_param(c, of, owner, d->sourceid, p);
|
||||
}
|
||||
fputs(") ", of);
|
||||
wwi_type(of, d->lhs);
|
||||
wwi_type(c, of, owner, d->sourceid, d->lhs);
|
||||
fputs(";\n", of);
|
||||
break;
|
||||
case N_TYPEDECL:
|
||||
fputs(d->export ? "export type " : "type ", of);
|
||||
fputs(d->str, of);
|
||||
fputs(" = ", of);
|
||||
wwi_type(of, d->lhs);
|
||||
wwi_type(c, of, owner, d->sourceid, d->lhs);
|
||||
fputs(";\n", of);
|
||||
break;
|
||||
case N_DEF:
|
||||
fputs(d->export ? "export def " : "def ", of);
|
||||
fputs(d->str, of);
|
||||
fputs(": ", of);
|
||||
wwi_type(of, d->lhs);
|
||||
wwi_type(c, of, owner, d->sourceid, d->lhs);
|
||||
/* An aggregate initializer (N_STRUCTLIT/N_ARRLIT) is a DATA-
|
||||
* global (#52): emit a value-LESS prototype `export def X: T;`.
|
||||
* The defining package's own .o emits the struct/array DATA; the
|
||||
@@ -491,7 +507,7 @@ wwi_decl(FILE *of, Node *d)
|
||||
fputs(";\n", of);
|
||||
} else {
|
||||
fputs(" = ", of);
|
||||
wwi_expr(of, d->rhs);
|
||||
wwi_expr(c, of, owner, d->sourceid, d->rhs);
|
||||
fputs(";\n", of);
|
||||
}
|
||||
break;
|
||||
@@ -502,7 +518,7 @@ wwi_decl(FILE *of, Node *d)
|
||||
if (d->lhs == NULL)
|
||||
fatal("wwi: exported let '%s' has no declared type",
|
||||
d->str);
|
||||
wwi_type(of, d->lhs);
|
||||
wwi_type(c, of, owner, d->sourceid, d->lhs);
|
||||
fputs(";\n", of);
|
||||
break;
|
||||
default:
|
||||
@@ -616,11 +632,6 @@ wwi_valuesym(Checker *c, const char *owner, int source, const char *name)
|
||||
if (s->kind == SK_DEF && strcmp(s->name, name) == 0
|
||||
&& wwi_mod_eq(s->mod, owner))
|
||||
return s;
|
||||
for (Scope *p = c->top; p; p = p->parent)
|
||||
for (Sym *s = p->first; s; s = s->next)
|
||||
if (s->kind == SK_DEF && strcmp(s->name, name) == 0
|
||||
&& wwi_direct_mod_visible(c, owner, source, s->mod))
|
||||
return s;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -812,7 +823,9 @@ wwi_emit_imports(FILE *of, Node *file, const char *owner, int source,
|
||||
const char *previous = NULL;
|
||||
for (int i = 0; i < nuse; i++) {
|
||||
if (previous && strcmp(previous, us[i].path) == 0) continue;
|
||||
fprintf(of, "import %s;\n", us[i].path);
|
||||
fputs("import ", of);
|
||||
wwi_canonical_alias(of, us[i].path);
|
||||
fprintf(of, " %s;\n", us[i].path);
|
||||
previous = us[i].path;
|
||||
}
|
||||
free(us);
|
||||
@@ -865,16 +878,16 @@ wwi_emit_primary_section(Checker *c, FILE *of, Node *file,
|
||||
wwi_emit_imports(of, file, owner, source, 0);
|
||||
for (int i = 0; i < fs->nprivate; i++)
|
||||
if (fs->privatefacts[i].d->sourceid == source)
|
||||
wwi_decl(of, fs->privatefacts[i].d);
|
||||
wwi_decl(c, of, NULL, fs->privatefacts[i].d);
|
||||
if (c->is_test_package)
|
||||
for (Node *d = file->list; d; d = d->next)
|
||||
if (wwi_primary(d) && d->sourceid == source
|
||||
&& d->kind == N_FNDECL && !d->export
|
||||
&& wwi_has_attr(d, "test"))
|
||||
wwi_decl(of, d);
|
||||
wwi_decl(c, of, NULL, d);
|
||||
for (int i = 0; i < nexports; i++)
|
||||
if (exports[i].d->sourceid == source)
|
||||
wwi_decl(of, exports[i].d);
|
||||
wwi_decl(c, of, NULL, exports[i].d);
|
||||
}
|
||||
|
||||
int
|
||||
@@ -964,16 +977,15 @@ wwi_emit(Checker *c, FILE *of, Node *file)
|
||||
struct factent *f = &fs.facts[i];
|
||||
if (lastmod == NULL || strcmp(lastmod, f->mod) != 0
|
||||
|| lastsource != f->d->sourceid) {
|
||||
const char *dot = strrchr(f->mod, '.');
|
||||
const char *factpkg = f->d->pkgname && f->d->pkgname[0]
|
||||
? f->d->pkgname : (dot ? dot + 1 : f->mod);
|
||||
fprintf(of, "//ww:module %s\n", f->mod);
|
||||
fprintf(of, "package %s;\n", factpkg);
|
||||
fputs("package ", of);
|
||||
wwi_canonical_alias(of, f->mod);
|
||||
fputs(";\n", of);
|
||||
wwi_emit_imports(of, file, f->mod, f->d->sourceid, 1);
|
||||
lastmod = f->mod;
|
||||
lastsource = f->d->sourceid;
|
||||
}
|
||||
wwi_decl(of, f->d);
|
||||
wwi_decl(c, of, f->mod, f->d);
|
||||
}
|
||||
free(fs.privatefacts);
|
||||
free(fs.facts);
|
||||
|
||||
Reference in New Issue
Block a user