ww: separate package identity from declared name
This commit is contained in:
287
cmd/w6c/wwi.c
287
cmd/w6c/wwi.c
@@ -54,17 +54,11 @@ wwi_mod_eq(const char *a, const char *b)
|
||||
* flat in the parser, so consulting every N_USE without this owner filter
|
||||
* would let one dependency accidentally resolve another dependency's alias. */
|
||||
static const char *
|
||||
wwi_use_path(Checker *c, const char *owner, const char *alias)
|
||||
wwi_use_path(Checker *c, const char *owner, int source, const char *alias)
|
||||
{
|
||||
if (owner && alias) {
|
||||
const char *dot = strrchr(owner, '.');
|
||||
const char *leaf = dot ? dot + 1 : owner;
|
||||
if (strcmp(alias, leaf) == 0)
|
||||
return owner;
|
||||
}
|
||||
for (Node *u = c->file->list; u; u = u->next) {
|
||||
if (u->kind != N_USE || u->str == NULL
|
||||
|| strcmp(u->str, alias) != 0)
|
||||
|| u->sourceid != source || strcmp(u->str, alias) != 0)
|
||||
continue;
|
||||
int same = owner == NULL ? u->imported == 0
|
||||
: u->imported != 0 && wwi_mod_eq(u->module, owner);
|
||||
@@ -75,17 +69,22 @@ wwi_use_path(Checker *c, const char *owner, const char *alias)
|
||||
}
|
||||
|
||||
static int
|
||||
wwi_direct_mod_visible(Checker *c, const char *owner, const char *mod)
|
||||
wwi_direct_mod_visible(Checker *c, const char *owner, int source,
|
||||
const char *mod)
|
||||
{
|
||||
if (mod == NULL || mod[0] == '\0') return 0;
|
||||
const char *dot = strrchr(mod, '.');
|
||||
const char *alias = dot ? dot + 1 : mod;
|
||||
const char *path = wwi_use_path(c, owner, alias);
|
||||
return path != NULL && strcmp(path, mod) == 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;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static Sym *
|
||||
wwi_typesym(Checker *c, const char *owner, const char *nm)
|
||||
wwi_typesym(Checker *c, const char *owner, int source, const char *nm)
|
||||
{
|
||||
if (nm == NULL) return NULL;
|
||||
const char *dot = strrchr(nm, '.');
|
||||
@@ -96,7 +95,7 @@ wwi_typesym(Checker *c, const char *owner, const char *nm)
|
||||
if (alias == NULL) fatal("wwi: out of memory");
|
||||
memcpy(alias, nm, n);
|
||||
alias[n] = '\0';
|
||||
const char *mod = wwi_use_path(c, owner, alias);
|
||||
const char *mod = wwi_use_path(c, owner, source, alias);
|
||||
if (mod)
|
||||
s = scope_lookup_in_module(c->cur, mod, dot + 1);
|
||||
free(alias);
|
||||
@@ -107,7 +106,8 @@ wwi_typesym(Checker *c, const char *owner, const char *nm)
|
||||
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, b->mod)) {
|
||||
&& wwi_direct_mod_visible(c, owner, source,
|
||||
b->mod)) {
|
||||
s = b;
|
||||
break;
|
||||
}
|
||||
@@ -563,6 +563,8 @@ factcmp(const void *a, const void *b)
|
||||
const struct factent *x = a, *y = b;
|
||||
int r = strcmp(x->mod, y->mod);
|
||||
if (r != 0) return r;
|
||||
if (x->d->sourceid != y->d->sourceid)
|
||||
return x->d->sourceid - y->d->sourceid;
|
||||
int xr = x->d->kind == N_TYPEDECL ? 0 : 1;
|
||||
int yr = y->d->kind == N_TYPEDECL ? 0 : 1;
|
||||
if (xr != yr) return xr - yr;
|
||||
@@ -607,7 +609,7 @@ wwi_fact_grow(struct factent **v, int *cap, int need)
|
||||
}
|
||||
|
||||
static Sym *
|
||||
wwi_valuesym(Checker *c, const char *owner, const char *name)
|
||||
wwi_valuesym(Checker *c, const char *owner, int source, const char *name)
|
||||
{
|
||||
for (Scope *p = c->top; p; p = p->parent)
|
||||
for (Sym *s = p->first; s; s = s->next)
|
||||
@@ -617,25 +619,26 @@ wwi_valuesym(Checker *c, const char *owner, const char *name)
|
||||
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, s->mod))
|
||||
return s;
|
||||
&& wwi_direct_mod_visible(c, owner, source, s->mod))
|
||||
return s;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void wwi_collect_decl(struct factset*, const char*, Node*);
|
||||
static void wwi_collect_type(struct factset*, const char*, Node*);
|
||||
static void wwi_collect_type(struct factset*, const char*, int, Node*);
|
||||
|
||||
static void
|
||||
wwi_collect_expr(struct factset *fs, const char *owner, Node *e)
|
||||
wwi_collect_expr(struct factset *fs, const char *owner, int source, Node *e)
|
||||
{
|
||||
if (e == NULL) return;
|
||||
Sym *s = NULL;
|
||||
if (e->kind == N_IDENT) {
|
||||
s = wwi_valuesym(fs->c, owner, e->str);
|
||||
s = wwi_valuesym(fs->c, owner, source, e->str);
|
||||
} else if (e->kind == N_DOT && e->lhs
|
||||
&& e->lhs->kind == N_IDENT) {
|
||||
const char *mod = wwi_use_path(fs->c, owner, e->lhs->str);
|
||||
if (mod) s = wwi_valuesym(fs->c, mod, e->str);
|
||||
const char *mod = wwi_use_path(fs->c, owner, source,
|
||||
e->lhs->str);
|
||||
if (mod) s = wwi_valuesym(fs->c, mod, source, e->str);
|
||||
}
|
||||
if (s && s->decl && s->decl->kind == N_DEF) {
|
||||
if (!s->decl->export) {
|
||||
@@ -648,23 +651,23 @@ wwi_collect_expr(struct factset *fs, const char *owner, Node *e)
|
||||
return;
|
||||
}
|
||||
if (e->kind == N_BIN) {
|
||||
wwi_collect_expr(fs, owner, e->lhs);
|
||||
wwi_collect_expr(fs, owner, e->rhs);
|
||||
wwi_collect_expr(fs, owner, source, e->lhs);
|
||||
wwi_collect_expr(fs, owner, source, e->rhs);
|
||||
} else if (e->kind == N_UN) {
|
||||
wwi_collect_expr(fs, owner, e->lhs);
|
||||
wwi_collect_expr(fs, owner, source, e->lhs);
|
||||
} else if (e->kind == N_CAST) {
|
||||
wwi_collect_expr(fs, owner, e->lhs);
|
||||
wwi_collect_type(fs, owner, e->rhs);
|
||||
wwi_collect_expr(fs, owner, source, e->lhs);
|
||||
wwi_collect_type(fs, owner, source, e->rhs);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
wwi_collect_type(struct factset *fs, const char *owner, Node *t)
|
||||
wwi_collect_type(struct factset *fs, const char *owner, int source, Node *t)
|
||||
{
|
||||
if (t == NULL) return;
|
||||
switch (t->kind) {
|
||||
case N_TNAME: {
|
||||
Sym *s = wwi_typesym(fs->c, owner, t->str);
|
||||
Sym *s = wwi_typesym(fs->c, owner, source, t->str);
|
||||
if (s && s->decl && s->decl->kind == N_TYPEDECL)
|
||||
wwi_collect_decl(fs, s->mod, s->decl);
|
||||
break;
|
||||
@@ -673,7 +676,7 @@ wwi_collect_type(struct factset *fs, const char *owner, Node *t)
|
||||
case N_TSLICE:
|
||||
case N_TBANG:
|
||||
case N_TCHAN:
|
||||
wwi_collect_type(fs, owner, t->lhs);
|
||||
wwi_collect_type(fs, owner, source, t->lhs);
|
||||
break;
|
||||
case N_TARRAY:
|
||||
/* Array length is part of the resolved type identity, not a source
|
||||
@@ -681,7 +684,7 @@ wwi_collect_type(struct factset *fs, const char *owner, Node *t)
|
||||
* and a consumer never needs an implementation def to size the type. */
|
||||
if (t->rhs != NULL && t->rhs->kind != N_INTLIT) {
|
||||
u64 len;
|
||||
if (!check_eval_const(fs->c, t->rhs, owner, &len)) {
|
||||
if (!check_eval_const(fs->c, t->rhs, owner, source, &len)) {
|
||||
errorf(t->pos, "cannot encode array dimension");
|
||||
fs->bad = 1;
|
||||
} else {
|
||||
@@ -692,24 +695,24 @@ wwi_collect_type(struct factset *fs, const char *owner, Node *t)
|
||||
e->lhs = e->rhs = e->list = NULL;
|
||||
}
|
||||
}
|
||||
wwi_collect_type(fs, owner, t->lhs);
|
||||
wwi_collect_type(fs, owner, source, t->lhs);
|
||||
break;
|
||||
case N_TFN:
|
||||
for (Node *p = t->list; p; p = p->next)
|
||||
wwi_collect_type(fs, owner, p->lhs);
|
||||
wwi_collect_type(fs, owner, t->lhs);
|
||||
wwi_collect_type(fs, owner, source, p->lhs);
|
||||
wwi_collect_type(fs, owner, source, t->lhs);
|
||||
break;
|
||||
case N_TSTRUCT:
|
||||
for (Node *f = t->list; f; f = f->next)
|
||||
wwi_collect_type(fs, owner, f->lhs);
|
||||
wwi_collect_type(fs, owner, source, f->lhs);
|
||||
break;
|
||||
case N_TTAGGED:
|
||||
case N_TTUPLE:
|
||||
for (Node *e = t->list; e; e = e->next)
|
||||
wwi_collect_type(fs, owner, e);
|
||||
wwi_collect_type(fs, owner, source, e);
|
||||
break;
|
||||
case N_TENUM:
|
||||
wwi_collect_type(fs, owner, t->lhs);
|
||||
wwi_collect_type(fs, owner, source, t->lhs);
|
||||
/* Member identifiers are enum-local prior-sibling references, not
|
||||
* package defs; the complete member list already carries their facts. */
|
||||
break;
|
||||
@@ -756,18 +759,18 @@ wwi_collect_decl(struct factset *fs, const char *owner, Node *d)
|
||||
switch (d->kind) {
|
||||
case N_FNDECL:
|
||||
for (Node *p = d->list; p; p = p->next)
|
||||
wwi_collect_type(fs, owner, p->lhs);
|
||||
wwi_collect_type(fs, owner, d->lhs);
|
||||
wwi_collect_type(fs, owner, d->sourceid, p->lhs);
|
||||
wwi_collect_type(fs, owner, d->sourceid, d->lhs);
|
||||
break;
|
||||
case N_TYPEDECL:
|
||||
wwi_collect_type(fs, owner, d->lhs);
|
||||
wwi_collect_type(fs, owner, d->sourceid, d->lhs);
|
||||
break;
|
||||
case N_DEF:
|
||||
wwi_collect_type(fs, owner, d->lhs);
|
||||
wwi_collect_expr(fs, owner, d->rhs);
|
||||
wwi_collect_type(fs, owner, d->sourceid, d->lhs);
|
||||
wwi_collect_expr(fs, owner, d->sourceid, d->rhs);
|
||||
break;
|
||||
case N_LET:
|
||||
wwi_collect_type(fs, owner, d->lhs);
|
||||
wwi_collect_type(fs, owner, d->sourceid, d->lhs);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@@ -775,24 +778,32 @@ wwi_collect_decl(struct factset *fs, const char *owner, Node *d)
|
||||
}
|
||||
|
||||
static int
|
||||
wwi_use_owned(Node *u, const char *owner)
|
||||
wwi_use_owned(Node *u, const char *owner, int source)
|
||||
{
|
||||
return u->kind == N_USE && u->imported != 0
|
||||
&& wwi_mod_eq(u->module, owner);
|
||||
&& u->sourceid == source && wwi_mod_eq(u->module, owner);
|
||||
}
|
||||
|
||||
static void
|
||||
wwi_emit_fact_imports(FILE *of, Node *file, const char *owner)
|
||||
wwi_emit_imports(FILE *of, Node *file, const char *owner, int source,
|
||||
int imported)
|
||||
{
|
||||
int nuse = 0;
|
||||
for (Node *u = file->list; u; u = u->next)
|
||||
if (wwi_use_owned(u, owner)) nuse++;
|
||||
for (Node *u = file->list; u; u = u->next) {
|
||||
int owned = imported ? wwi_use_owned(u, owner, source)
|
||||
: u->kind == N_USE && u->imported == 0
|
||||
&& u->sourceid == source;
|
||||
if (owned) nuse++;
|
||||
}
|
||||
if (nuse == 0) return;
|
||||
struct useent *us = malloc((size_t)nuse * sizeof *us);
|
||||
if (us == NULL) fatal("wwi: out of memory");
|
||||
int k = 0;
|
||||
for (Node *u = file->list; u; u = u->next) {
|
||||
if (!wwi_use_owned(u, owner)) continue;
|
||||
int owned = imported ? wwi_use_owned(u, owner, source)
|
||||
: u->kind == N_USE && u->imported == 0
|
||||
&& u->sourceid == source;
|
||||
if (!owned) continue;
|
||||
us[k].path = u->usepath ? u->usepath : u->str;
|
||||
us[k].idx = k;
|
||||
k++;
|
||||
@@ -807,6 +818,65 @@ wwi_emit_fact_imports(FILE *of, Node *file, const char *owner)
|
||||
free(us);
|
||||
}
|
||||
|
||||
static int
|
||||
wwi_primary_section_has(Checker *c, Node *file, struct factset *fs,
|
||||
struct declent *exports, int nexports, int source)
|
||||
{
|
||||
for (Node *u = file->list; u; u = u->next)
|
||||
if (u->kind == N_USE && u->imported == 0
|
||||
&& u->sourceid == source)
|
||||
return 1;
|
||||
for (int i = 0; i < fs->nprivate; i++)
|
||||
if (fs->privatefacts[i].d->sourceid == source) return 1;
|
||||
for (int i = 0; i < nexports; i++)
|
||||
if (exports[i].d->sourceid == source) return 1;
|
||||
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"))
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
wwi_first_primary_source(Node *file)
|
||||
{
|
||||
int found = 0;
|
||||
int source = 0;
|
||||
for (Node *d = file->list; d; d = d->next) {
|
||||
if (!wwi_primary(d)) continue;
|
||||
if (!found || d->sourceid < source) {
|
||||
source = d->sourceid;
|
||||
found = 1;
|
||||
}
|
||||
}
|
||||
return found ? source : file->sourceid;
|
||||
}
|
||||
|
||||
static void
|
||||
wwi_emit_primary_section(Checker *c, FILE *of, Node *file,
|
||||
struct factset *fs, struct declent *exports, int nexports,
|
||||
const char *owner, const char *pkg, int source)
|
||||
{
|
||||
if (owner != NULL && owner[0] != '\0')
|
||||
fprintf(of, "//ww:module %s\n", owner);
|
||||
fprintf(of, "package %s;\n", pkg && pkg[0] ? pkg : "main");
|
||||
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);
|
||||
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);
|
||||
for (int i = 0; i < nexports; i++)
|
||||
if (exports[i].d->sourceid == source)
|
||||
wwi_decl(of, exports[i].d);
|
||||
}
|
||||
|
||||
int
|
||||
wwi_emit(Checker *c, FILE *of, Node *file)
|
||||
{
|
||||
@@ -841,83 +911,15 @@ wwi_emit(Checker *c, FILE *of, Node *file)
|
||||
if (fs.nfacts > 1)
|
||||
qsort(fs.facts, (size_t)fs.nfacts, sizeof *fs.facts, factcmp);
|
||||
|
||||
/* package line: leaf of the first primary decl's module tag. */
|
||||
const char *pkg = "main";
|
||||
int found = 0;
|
||||
for (Node *d = file->list; d; d = d->next) {
|
||||
if (wwi_primary(d) && d->module && d->module[0]) {
|
||||
const char *dot = strrchr(d->module, '.');
|
||||
pkg = dot ? dot + 1 : d->module;
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* #11: a decl-less / export-less primary body carries no
|
||||
* module-tagged decl, so the scan above finds nothing; fall back to
|
||||
* the primary module identity stamped on the N_FILE node at parse
|
||||
* time. A raw single-file `package main` root arrives via a bare reset
|
||||
* and leaves file->module NULL, so it stays "main". The detector is
|
||||
* scan-miss (`!found`), NOT pkg=="main": a body whose first tagged
|
||||
* decl legitimately leafs to "main" must keep that, and must match
|
||||
* selfhost's `found` flag byte-for-byte (rule 10). */
|
||||
if (!found && file->module && file->module[0]) {
|
||||
const char *dot = strrchr(file->module, '.');
|
||||
pkg = dot ? dot + 1 : file->module;
|
||||
}
|
||||
if (file->module != NULL && file->module[0] != '\0')
|
||||
fprintf(of, "//ww:module %s\n", file->module);
|
||||
fprintf(of, "package %s;\n", pkg);
|
||||
|
||||
/* imports — primary N_USE, byte-sorted by import path. */
|
||||
int nuse = 0;
|
||||
for (Node *u = file->list; u; u = u->next)
|
||||
if (u->kind == N_USE && wwi_primary(u))
|
||||
nuse++;
|
||||
if (nuse > 0) {
|
||||
struct useent *us = malloc((size_t)nuse * sizeof *us);
|
||||
int k = 0;
|
||||
for (Node *u = file->list; u; u = u->next) {
|
||||
if (u->kind != N_USE || !wwi_primary(u))
|
||||
continue;
|
||||
us[k].path = u->usepath ? u->usepath : u->str;
|
||||
us[k].idx = k;
|
||||
k++;
|
||||
}
|
||||
qsort(us, (size_t)nuse, sizeof *us, usecmp);
|
||||
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);
|
||||
previous = us[i].path;
|
||||
}
|
||||
free(us);
|
||||
}
|
||||
|
||||
/* Compiler-private primary nominal facts precede the public declarations.
|
||||
* They are parseable within this package export but lack `export`, so a
|
||||
* source qualifier cannot name them. */
|
||||
for (int i = 0; i < fs.nprivate; i++)
|
||||
wwi_decl(of, fs.privatefacts[i].d);
|
||||
|
||||
/* Package-test metadata is private, deterministic, and owned by the test
|
||||
* variant. A distinct generated-main compile consumes it through --import. */
|
||||
if (c->is_test_package) {
|
||||
/* Unit source paths and declarations are already deterministically
|
||||
* ordered; preserve that order as the test runner's user-facing order. */
|
||||
for (Node *d = file->list; d; d = d->next)
|
||||
if (wwi_primary(d) && d->kind == N_FNDECL
|
||||
&& !d->export && wwi_has_attr(d, "test"))
|
||||
wwi_decl(of, d);
|
||||
}
|
||||
|
||||
/* decls — exported primary, byte-sorted by symbol name. */
|
||||
/* Exported declarations are sorted within their source-file sections. */
|
||||
int ndecl = 0;
|
||||
for (Node *d = file->list; d; d = d->next)
|
||||
if (wwi_primary(d) && d->export && wwi_is_decl(d))
|
||||
ndecl++;
|
||||
struct declent *ds = NULL;
|
||||
if (ndecl > 0) {
|
||||
struct declent *ds = malloc((size_t)ndecl * sizeof *ds);
|
||||
ds = malloc((size_t)ndecl * sizeof *ds);
|
||||
if (ds == NULL) fatal("wwi: out of memory");
|
||||
int k = 0;
|
||||
for (Node *d = file->list; d; d = d->next) {
|
||||
if (!wwi_primary(d) || !d->export || !wwi_is_decl(d))
|
||||
@@ -927,24 +929,49 @@ wwi_emit(Checker *c, FILE *of, Node *file)
|
||||
k++;
|
||||
}
|
||||
qsort(ds, (size_t)ndecl, sizeof *ds, declcmp);
|
||||
for (int i = 0; i < ndecl; i++)
|
||||
wwi_decl(of, ds[i].d);
|
||||
free(ds);
|
||||
}
|
||||
|
||||
/* Canonical ownership, declared name, and lexical source scope are three
|
||||
* independent export facts. Repeated owner sections preserve the file that
|
||||
* owns each binding while keeping every symbol/action keyed by OWNER. */
|
||||
int nsection = 0;
|
||||
for (Node *p = file->body; p; p = p->next) {
|
||||
if (p->imported || !wwi_primary_section_has(c, file, &fs, ds,
|
||||
ndecl, p->sourceid))
|
||||
continue;
|
||||
const char *owner = p->module && p->module[0]
|
||||
? p->module : file->module;
|
||||
const char *pkg = p->pkgname && p->pkgname[0]
|
||||
? p->pkgname : file->pkgname;
|
||||
wwi_emit_primary_section(c, of, file, &fs, ds, ndecl, owner,
|
||||
pkg, p->sourceid);
|
||||
nsection++;
|
||||
}
|
||||
if (nsection == 0) {
|
||||
const char *pkg = file->pkgname && file->pkgname[0]
|
||||
? file->pkgname : "main";
|
||||
wwi_emit_primary_section(c, of, file, &fs, ds, ndecl,
|
||||
file->module, pkg, wwi_first_primary_source(file));
|
||||
}
|
||||
free(ds);
|
||||
|
||||
/* Compiler-owned public fact closure. A module marker changes semantic
|
||||
* ownership without making the namespace a source import of the eventual
|
||||
* consumer; direct visibility continues to come solely from its own N_USE. */
|
||||
const char *lastmod = NULL;
|
||||
int lastsource = -1;
|
||||
for (int i = 0; i < fs.nfacts; i++) {
|
||||
struct factent *f = &fs.facts[i];
|
||||
if (lastmod == NULL || strcmp(lastmod, f->mod) != 0) {
|
||||
if (lastmod == NULL || strcmp(lastmod, f->mod) != 0
|
||||
|| lastsource != f->d->sourceid) {
|
||||
const char *dot = strrchr(f->mod, '.');
|
||||
const char *leaf = dot ? dot + 1 : 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", leaf);
|
||||
wwi_emit_fact_imports(of, file, f->mod);
|
||||
fprintf(of, "package %s;\n", factpkg);
|
||||
wwi_emit_imports(of, file, f->mod, f->d->sourceid, 1);
|
||||
lastmod = f->mod;
|
||||
lastsource = f->d->sourceid;
|
||||
}
|
||||
wwi_decl(of, f->d);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user