ref: 80f1e8ed2ff1a49b39ad424f388f10d434766e43
dir: /parse/use.c/
#include <stdlib.h> #include <stdio.h> #include <stdarg.h> #include <inttypes.h> #include <ctype.h> #include <string.h> #include <assert.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #include "util.h" #include "parse.h" static void wrtype(FILE *fd, Type *val); static void rdtype(FILE *fd, Type **dest); static void wrstab(FILE *fd, Stab *val); static Stab *rdstab(FILE *fd, int isfunc); static void wrsym(FILE *fd, Node *val); static Node *rdsym(FILE *fd, Trait *ctx); static void pickle(FILE *fd, Node *n); static Node *unpickle(FILE *fd); /* type fixup list */ static Htab *tydeduptab; /* map from name -> type, contains all Tynames loaded ever */ static Htab *tidmap; /* map from tid -> type */ static Htab *trmap; /* map from trait id -> trait */ static Htab *initmap; /* map from init name -> int */ #define Builtinmask (1 << 30) static Type ***typefixdest; /* list of types we need to replace */ static size_t ntypefixdest; /* size of replacement list */ static intptr_t *typefixid; /* list of types we need to replace */ static size_t ntypefixid; /* size of replacement list */ static Trait ***traitfixdest; /* list of traits we need to replace */ static size_t ntraitfixdest; /* size of replacement list */ static Type **traitfixtype; /* list of types we need to set the trait on */ static size_t ntraitfixtype; /* size of replacement list */ static intptr_t *traitfixid; /* list of traits we need to replace */ static size_t ntraitfixid; /* size of replacement list */ static Node **implfix; /* list of impls we need to fix up */ static size_t nimplfix; /* size of replacement list */ void addextlibs(Node *file, char **libs, size_t nlibs) { size_t i, j; for (i = 0; i < nlibs; i++) { for (j = 0; j < file->file.nextlibs; j++) if (!strcmp(file->file.extlibs[j], libs[i])) continue; lappend(&file->file.extlibs, &file->file.nextlibs, libs[i]); } } /* Outputs a symbol table to file in a way that can be * read back usefully. Only writes declarations, types * and sub-namespaces. Captured variables are ommitted. */ static void wrstab(FILE *fd, Stab *val) { size_t n, i; void **keys; wrstr(fd, val->name); /* write decls */ keys = htkeys(val->dcl, &n); wrint(fd, n); for (i = 0; i < n; i++) wrsym(fd, getdcl(val, keys[i])); free(keys); /* write types */ keys = htkeys(val->ty, &n); wrint(fd, n); for (i = 0; i < n; i++) { pickle(fd, keys[i]); /* name */ wrtype(fd, gettype(val, keys[i])); /* type */ } free(keys); } /* Reads a symbol table from file. The converse * of wrstab. */ static Stab *rdstab(FILE *fd, int isfunc) { Stab *st; Type *ty; Node *nm; int n; int i; /* read dcls */ st = mkstab(isfunc); st->name = rdstr(fd); n = rdint(fd); for (i = 0; i < n; i++) putdcl(st, rdsym(fd, NULL)); /* read types */ n = rdint(fd); for (i = 0; i < n; i++) { nm = unpickle(fd); rdtype(fd, &ty); puttype(st, nm, ty); } return st; } static void wrucon(FILE *fd, Ucon *uc) { wrint(fd, uc->loc.line); wrint(fd, uc->id); wrbool(fd, uc->synth); pickle(fd, uc->name); wrbool(fd, uc->etype != NULL); if (uc->etype) wrtype(fd, uc->etype); } static Ucon *rducon(FILE *fd, Type *ut) { Type *et; Node *name; Ucon *uc; size_t id; int line; int synth; et = NULL; line = rdint(fd); id = rdint(fd); synth = rdbool(fd); name = unpickle(fd); uc = mkucon(Zloc, name, ut, et); uc->loc.line = line; uc->loc.file = file->file.nfiles - 1; if (rdbool(fd)) rdtype(fd, &uc->etype); uc->id = id; uc->synth = synth; return uc; } /* Writes the name and type of a variable, * but only writes its intializer for things * we want to inline cross-file (currently, * the only cross-file inline is generics) */ static void wrsym(FILE *fd, Node *val) { /* sym */ wrint(fd, val->loc.line); pickle(fd, val->decl.name); wrtype(fd, val->decl.type); /* symflags */ wrint(fd, val->decl.vis); wrbool(fd, val->decl.isconst); wrbool(fd, val->decl.isgeneric); wrbool(fd, val->decl.isextern); wrbool(fd, val->decl.ispkglocal); wrbool(fd, val->decl.isnoret); wrbool(fd, val->decl.isexportinit); wrbool(fd, val->decl.isinit); if (val->decl.isexportinit) pickle(fd, val->decl.init); } static Node *rdsym(FILE *fd, Trait *ctx) { int line; Node *name; Node *n; line = rdint(fd); name = unpickle(fd); n = mkdecl(Zloc, name, NULL); n->loc.line = line; n->loc.file = file->file.nfiles - 1; rdtype(fd, &n->decl.type); if (rdint(fd) == Vishidden) n->decl.ishidden = 1; n->decl.trait = ctx; n->decl.isconst = rdbool(fd); n->decl.isgeneric = rdbool(fd); n->decl.isextern = rdbool(fd); n->decl.ispkglocal = rdbool(fd); n->decl.isnoret = rdbool(fd); n->decl.isimport = 1; n->decl.isexportinit = rdbool(fd); n->decl.isinit = rdbool(fd); if (n->decl.isexportinit) n->decl.init = unpickle(fd); return n; } /* Writes types to a file. Errors on * internal only types like Tyvar that * will not be meaningful in another file*/ static void typickle(FILE *fd, Type *ty) { size_t i; if (!ty) { die("trying to pickle null type\n"); return; } wrbyte(fd, ty->type); wrbyte(fd, ty->vis); /* tid is generated; don't write */ /* FIXME: since we only support hardcoded traits, we just write * out the set of them. we should write out the trait list as * well */ if (!ty->traits) { wrint(fd, 0); } else { wrint(fd, bscount(ty->traits)); for (i = 0; bsiter(ty->traits, &i); i++) { if (i < Ntraits) wrint(fd, i | Builtinmask); else wrint(fd, i); } } wrint(fd, ty->nsub); switch (ty->type) { case Tyunres: pickle(fd, ty->name); break; case Typaram: wrstr(fd, ty->pname); break; case Tystruct: wrint(fd, ty->nmemb); for (i = 0; i < ty->nmemb; i++) pickle(fd, ty->sdecls[i]); break; case Tyunion: wrint(fd, ty->nmemb); for (i = 0; i < ty->nmemb; i++) wrucon(fd, ty->udecls[i]); break; case Tyarray: wrtype(fd, ty->sub[0]); pickle(fd, ty->asize); break; case Tyslice: wrtype(fd, ty->sub[0]); break; case Tyvar: die("Attempting to pickle %s. This will not work.\n", tystr(ty)); break; case Tyname: pickle(fd, ty->name); wrbool(fd, ty->issynth); wrint(fd, ty->narg); for (i = 0; i < ty->narg; i++) wrtype(fd, ty->arg[i]); wrtype(fd, ty->sub[0]); break; case Tygeneric: pickle(fd, ty->name); wrbool(fd, ty->issynth); wrint(fd, ty->ngparam); for (i = 0; i < ty->ngparam; i++) wrtype(fd, ty->gparam[i]); wrtype(fd, ty->sub[0]); break; default: for (i = 0; i < ty->nsub; i++) wrtype(fd, ty->sub[i]); break; } } static void traitpickle(FILE *fd, Trait *tr) { size_t i; wrint(fd, tr->uid); wrint(fd, tr->vis); pickle(fd, tr->name); typickle(fd, tr->param); wrint(fd, tr->naux); for (i = 0; i < tr->naux; i++) wrtype(fd, tr->aux[i]); wrint(fd, tr->nmemb); for (i = 0; i < tr->nmemb; i++) wrsym(fd, tr->memb[i]); wrint(fd, tr->nfuncs); for (i = 0; i < tr->nfuncs; i++) wrsym(fd, tr->funcs[i]); } static void wrtype(FILE *fd, Type *ty) { if (ty->tid >= Builtinmask) die("Type id %d for %s too big", ty->tid, tystr(ty)); if (ty->vis == Visbuiltin) wrint(fd, ty->type | Builtinmask); else wrint(fd, ty->tid); } static void rdtype(FILE *fd, Type **dest) { uintptr_t tid; tid = rdint(fd); if (tid & Builtinmask) { *dest = mktype(Zloc, tid & ~Builtinmask); } else { lappend(&typefixdest, &ntypefixdest, dest); lappend(&typefixid, &ntypefixid, itop(tid)); } } static void rdtrait(FILE *fd, Trait **dest, Type *ty) { uintptr_t tid; tid = rdint(fd); if (tid & Builtinmask) { if (dest) *dest = traittab[tid & ~Builtinmask]; if (ty) settrait(ty, traittab[tid & ~Builtinmask]); } else { lappend(&traitfixdest, &ntraitfixdest, dest); lappend(&traitfixtype, &ntraitfixtype, ty); lappend(&traitfixid, &ntraitfixid, itop(tid)); } } /* Writes types to a file. Errors on * internal only types like Tyvar that * will not be meaningful in another file */ static Type *tyunpickle(FILE *fd) { size_t i, n; Type *ty; Ty t; t = rdbyte(fd); ty = mktype(Zloc, t); ty->isimport = 1; if (rdbyte(fd) == Vishidden) ty->ishidden = 1; /* tid is generated; don't write */ n = rdint(fd); for (i = 0; i < n; i++) rdtrait(fd, NULL, ty); ty->nsub = rdint(fd); if (ty->nsub > 0) ty->sub = zalloc(ty->nsub * sizeof(Type *)); switch (ty->type) { case Tyunres: ty->name = unpickle(fd); break; case Typaram: ty->pname = rdstr(fd); break; case Tystruct: ty->nmemb = rdint(fd); ty->sdecls = zalloc(ty->nmemb * sizeof(Node *)); for (i = 0; i < ty->nmemb; i++) ty->sdecls[i] = unpickle(fd); break; case Tyunion: ty->nmemb = rdint(fd); ty->udecls = zalloc(ty->nmemb * sizeof(Node *)); for (i = 0; i < ty->nmemb; i++) ty->udecls[i] = rducon(fd, ty); break; case Tyarray: rdtype(fd, &ty->sub[0]); ty->asize = unpickle(fd); break; case Tyslice: rdtype(fd, &ty->sub[0]); break; case Tyname: ty->name = unpickle(fd); ty->issynth = rdbool(fd); ty->narg = rdint(fd); ty->arg = zalloc(ty->narg * sizeof(Type *)); for (i = 0; i < ty->narg; i++) rdtype(fd, &ty->arg[i]); rdtype(fd, &ty->sub[0]); break; case Tygeneric: ty->name = unpickle(fd); ty->issynth = rdbool(fd); ty->ngparam = rdint(fd); ty->gparam = zalloc(ty->ngparam * sizeof(Type *)); for (i = 0; i < ty->ngparam; i++) rdtype(fd, &ty->gparam[i]); rdtype(fd, &ty->sub[0]); break; default: for (i = 0; i < ty->nsub; i++) rdtype(fd, &ty->sub[i]); break; } return ty; } Trait *traitunpickle(FILE *fd) { Trait *tr; Node *fn; size_t i, n; intptr_t uid; /* create an empty trait */ tr = mktrait(Zloc, NULL, NULL, NULL, 0, NULL, 0, NULL, 0, 0); uid = rdint(fd); if (rdint(fd) == Vishidden) tr->ishidden = 1; tr->name = unpickle(fd); tr->param = tyunpickle(fd); tr->naux = rdint(fd); tr->aux = zalloc(tr->naux * sizeof(Type*)); tr->isimport = 1; for (i = 0; i < tr->naux; i++) rdtype(fd, &tr->aux[i]); n = rdint(fd); for (i = 0; i < n; i++) lappend(&tr->memb, &tr->nmemb, rdsym(fd, tr)); n = rdint(fd); for (i = 0; i < n; i++) { fn = rdsym(fd, tr); fn->decl.impls = mkht(tyhash, tyeq); lappend(&tr->funcs, &tr->nfuncs, fn); } htput(trmap, itop(uid), tr); return tr; } /* Pickles a node to a file. The format * is more or less equivalen to to * simplest serialization of the * in-memory representation. Minimal * checking is done, so a bad type can * crash the compiler */ static void pickle(FILE *fd, Node *n) { size_t i; if (!n) { wrbyte(fd, Nnone); return; } wrbyte(fd, n->type); wrint(fd, n->loc.line); switch (n->type) { case Nfile: wrstr(fd, n->file.files[0]); wrint(fd, n->file.nuses); for (i = 0; i < n->file.nuses; i++) pickle(fd, n->file.uses[i]); wrint(fd, n->file.nstmts); for (i = 0; i < n->file.nstmts; i++) pickle(fd, n->file.stmts[i]); wrstab(fd, n->file.globls); break; case Nexpr: wrbyte(fd, n->expr.op); wrtype(fd, n->expr.type); wrbool(fd, n->expr.isconst); pickle(fd, n->expr.idx); wrint(fd, n->expr.nargs); for (i = 0; i < n->expr.nargs; i++) pickle(fd, n->expr.args[i]); break; case Nname: wrbool(fd, n->name.ns != NULL); if (n->name.ns) { wrstr(fd, n->name.ns); } wrstr(fd, n->name.name); break; case Nuse: wrbool(fd, n->use.islocal); wrstr(fd, n->use.name); break; case Nlit: wrbyte(fd, n->lit.littype); wrtype(fd, n->lit.type); wrint(fd, n->lit.nelt); switch (n->lit.littype) { case Lvoid: break; case Lchr: wrint(fd, n->lit.chrval); break; case Lint: wrint(fd, n->lit.intval); break; case Lflt: wrflt(fd, n->lit.fltval); break; case Lstr: wrlenstr(fd, n->lit.strval); break; case Llbl: wrstr(fd, n->lit.lblval); break; case Lbool: wrbool(fd, n->lit.boolval); break; case Lfunc: pickle(fd, n->lit.fnval); break; } break; case Nloopstmt: pickle(fd, n->loopstmt.init); pickle(fd, n->loopstmt.cond); pickle(fd, n->loopstmt.step); pickle(fd, n->loopstmt.body); break; case Niterstmt: pickle(fd, n->iterstmt.elt); pickle(fd, n->iterstmt.seq); pickle(fd, n->iterstmt.body); break; case Nmatchstmt: pickle(fd, n->matchstmt.val); wrint(fd, n->matchstmt.nmatches); for (i = 0; i < n->matchstmt.nmatches; i++) pickle(fd, n->matchstmt.matches[i]); break; case Nmatch: pickle(fd, n->match.pat); pickle(fd, n->match.block); break; case Nifstmt: pickle(fd, n->ifstmt.cond); pickle(fd, n->ifstmt.iftrue); pickle(fd, n->ifstmt.iffalse); break; case Nblock: wrstab(fd, n->block.scope); wrint(fd, n->block.nstmts); for (i = 0; i < n->block.nstmts; i++) pickle(fd, n->block.stmts[i]); break; case Ndecl: /* sym */ pickle(fd, n->decl.name); wrtype(fd, n->decl.type); /* symflags */ wrbool(fd, n->decl.isconst); wrbool(fd, n->decl.isgeneric); wrbool(fd, n->decl.isextern); wrbool(fd, n->decl.isnoret); wrbool(fd, n->decl.ispkglocal); /* init */ pickle(fd, n->decl.init); break; case Nfunc: wrtype(fd, n->func.type); wrstab(fd, n->func.scope); wrint(fd, n->func.nargs); for (i = 0; i < n->func.nargs; i++) pickle(fd, n->func.args[i]); pickle(fd, n->func.body); break; case Nimpl: pickle(fd, n->impl.traitname); wrint(fd, n->impl.trait->uid); wrtype(fd, n->impl.type); wrint(fd, n->impl.naux); for (i = 0; i < n->impl.naux; i++) wrtype(fd, n->impl.aux[i]); wrint(fd, n->impl.ndecls); for (i = 0; i < n->impl.ndecls; i++) wrsym(fd, n->impl.decls[i]); break; case Nnone: die("Nnone should not be seen as node type!"); break; } } /* Unpickles a node from a file. Minimal checking * is done. Specifically, no checks are done for * sane arities, a bad file can crash the compiler */ static Node *unpickle(FILE *fd) { size_t i; Ntype type; Node *n; type = rdbyte(fd); if (type == Nnone) return NULL; n = mknode(Zloc, type); n->loc.line = rdint(fd); n->loc.file = file->file.nfiles - 1; switch (n->type) { case Nfile: lappend(&n->file.files, &n->file.nfiles, rdstr(fd)); n->file.nuses = rdint(fd); n->file.uses = zalloc(sizeof(Node *) * n->file.nuses); for (i = 0; i < n->file.nuses; i++) n->file.uses[i] = unpickle(fd); n->file.nstmts = rdint(fd); n->file.stmts = zalloc(sizeof(Node *) * n->file.nstmts); for (i = 0; i < n->file.nstmts; i++) n->file.stmts[i] = unpickle(fd); n->file.globls = rdstab(fd, 0); break; case Nexpr: n->expr.op = rdbyte(fd); rdtype(fd, &n->expr.type); n->expr.isconst = rdbool(fd); n->expr.idx = unpickle(fd); n->expr.nargs = rdint(fd); n->expr.args = zalloc(sizeof(Node *) * n->expr.nargs); for (i = 0; i < n->expr.nargs; i++) n->expr.args[i] = unpickle(fd); break; case Nname: if (rdbool(fd)) n->name.ns = rdstr(fd); n->name.name = rdstr(fd); break; case Nuse: n->use.islocal = rdbool(fd); n->use.name = rdstr(fd); break; case Nlit: n->lit.littype = rdbyte(fd); rdtype(fd, &n->lit.type); n->lit.nelt = rdint(fd); switch (n->lit.littype) { case Lvoid: break; case Lchr: n->lit.chrval = rdint(fd); break; case Lint: n->lit.intval = rdint(fd); break; case Lflt: n->lit.fltval = rdflt(fd); break; case Lstr: rdlenstr(fd, &n->lit.strval); break; case Llbl: n->lit.lblval = rdstr(fd); break; case Lbool: n->lit.boolval = rdbool(fd); break; case Lfunc: n->lit.fnval = unpickle(fd); break; } break; case Nloopstmt: n->loopstmt.init = unpickle(fd); n->loopstmt.cond = unpickle(fd); n->loopstmt.step = unpickle(fd); n->loopstmt.body = unpickle(fd); break; case Niterstmt: n->iterstmt.elt = unpickle(fd); n->iterstmt.seq = unpickle(fd); n->iterstmt.body = unpickle(fd); break; case Nmatchstmt: n->matchstmt.val = unpickle(fd); n->matchstmt.nmatches = rdint(fd); n->matchstmt.matches = zalloc(sizeof(Node *) * n->matchstmt.nmatches); for (i = 0; i < n->matchstmt.nmatches; i++) n->matchstmt.matches[i] = unpickle(fd); break; case Nmatch: n->match.pat = unpickle(fd); n->match.block = unpickle(fd); break; case Nifstmt: n->ifstmt.cond = unpickle(fd); n->ifstmt.iftrue = unpickle(fd); n->ifstmt.iffalse = unpickle(fd); break; case Nblock: n->block.scope = rdstab(fd, 0); n->block.nstmts = rdint(fd); n->block.stmts = zalloc(sizeof(Node *) * n->block.nstmts); n->block.scope->super = curstab(); pushstab(n->func.scope->super); for (i = 0; i < n->block.nstmts; i++) n->block.stmts[i] = unpickle(fd); popstab(); break; case Ndecl: n->decl.did = ndecls; /* unique within file */ /* sym */ n->decl.name = unpickle(fd); rdtype(fd, &n->decl.type); /* symflags */ n->decl.isconst = rdbool(fd); n->decl.isgeneric = rdbool(fd); n->decl.isextern = rdbool(fd); n->decl.isnoret = rdbool(fd); n->decl.ispkglocal = rdbool(fd); /* init */ n->decl.init = unpickle(fd); lappend(&decls, &ndecls, n); break; case Nfunc: rdtype(fd, &n->func.type); n->func.scope = rdstab(fd, 1); n->func.nargs = rdint(fd); n->func.args = zalloc(sizeof(Node *) * n->func.nargs); n->func.scope->super = curstab(); pushstab(n->func.scope->super); for (i = 0; i < n->func.nargs; i++) n->func.args[i] = unpickle(fd); n->func.body = unpickle(fd); popstab(); break; case Nimpl: n->impl.traitname = unpickle(fd); rdtrait(fd, &n->impl.trait, NULL); rdtype(fd, &n->impl.type); n->impl.naux = rdint(fd); n->impl.aux = zalloc(sizeof(Node *) * n->impl.naux); for (i = 0; i < n->impl.naux; i++) rdtype(fd, &n->impl.aux[i]); n->impl.ndecls = rdint(fd); n->impl.decls = zalloc(sizeof(Node *) * n->impl.ndecls); for (i = 0; i < n->impl.ndecls; i++) n->impl.decls[i] = rdsym(fd, n->impl.trait); lappend(&impltab, &nimpltab, n); lappend(&implfix, &nimplfix, n); break; case Nnone: die("Nnone should not be seen as node type!"); break; } return n; } static Stab *findstab(Stab *st, char *pkg) { Stab *s; if (!pkg) { if (!st->name) return st; else return NULL; } s = getns(file, pkg); if (!s) { s = mkstab(0); s->name = strdup(pkg); putns(file, s); } return s; } static int isspecialization(Type *t1, Type *t2) { if ((t1->type != Tygeneric || t2->type != Tyname) && (t1->type != Tyname || t2->type != Tygeneric) && (t1->type != Tyname || t2->type != Tyname)) return 0; /* FIXME: this should be done better */ return nameeq(t1->name, t2->name); } static void fixtypemappings(Stab *st) { size_t i; Type *t, *u, *old; /* * merge duplicate definitions. * This allows us to compare named types by id, instead * of doing a deep walk through the type. This ability is * depended on when we do type inference. */ for (i = 0; i < ntypefixdest; i++) { t = htget(tidmap, itop(typefixid[i])); if (!t) die("Unable to find type for id %zd\n", typefixid[i]); *typefixdest[i] = t; } for (i = 0; i < ntypefixdest; i++) { old = *typefixdest[i]; if (old->type == Tyname || old->type == Tygeneric) { t = htget(tydeduptab, old); if (!t) { t = old; htput(tydeduptab, old, old); } u = tydedup(old); assert(tyeq(t, u)); *typefixdest[i] = t; } } /* check for duplicate type definitions */ for (i = 0; i < ntypefixdest; i++) { t = htget(tidmap, itop(typefixid[i])); if ((t->type != Tyname && t->type != Tygeneric) || t->issynth) continue; old = htget(tydeduptab, t); if (old && !tyeq(t, old) && !isspecialization(t, old)) lfatal(t->loc, "Duplicate definition of type %s on %s:%d", tystr(old), file->file.files[old->loc.file], old->loc.line); } for (i = 0; i < ntypefixdest; i++) lfree(&typefixdest, &ntypefixdest); lfree(&typefixid, &ntypefixid); } static void fixtraitmappings(Stab *st) { size_t i; Trait *t; /* * merge duplicate definitions. * This allows us to compare named types by id, instead * of doing a deep walk through the type. This ability is * depended on when we do type inference. */ for (i = 0; i < ntraitfixdest; i++) { t = htget(trmap, itop(traitfixid[i])); if (!t) die("Unable to find trait for id %zd\n", traitfixid[i]); if (traitfixdest[i]) *traitfixdest[i] = t; if (traitfixtype[i]) settrait(traitfixtype[i], t); } lfree(&traitfixdest, &ntraitfixdest); lfree(&traitfixid, &ntraitfixid); } static void protomap(Trait *tr, Type *ty, Node *dcl) { size_t i, len; char *protoname, *dclname, *p; Node *proto; dclname = declname(dcl); for (i = 0; i < tr->nfuncs; i++) { proto = tr->funcs[i]; protoname = declname(proto); len = strlen(protoname); p = strstr(dclname, protoname); if (!p || p[len] != '$') continue; if (hthas(proto->decl.impls, ty)) continue; htput(proto->decl.impls, ty, dcl); if (ty->type == Tygeneric || hasparams(ty)) { lappend(&proto->decl.gimpl, &proto->decl.ngimpl, dcl); lappend(&proto->decl.gtype, &proto->decl.ngtype, ty); } } } static void fiximplmappings(Stab *st) { Node *impl; Trait *tr; size_t i, j; for (i = 0; i < nimplfix; i++) { impl = implfix[i]; tr = impl->impl.trait; /* FIXME: handle duplicate impls properly */ if (getimpl(st, impl)) continue; putimpl(st, impl); settrait(impl->impl.type, tr); for (j = 0; j < impl->impl.ndecls; j++) { putdcl(file->file.globls, impl->impl.decls[j]); protomap(tr, impl->impl.type, impl->impl.decls[j]); } } } /* Usefile format: * U<pkgname> * T<pickled-type> * R<picled-trait> * I<pickled-impl> * D<picled-decl> * G<pickled-decl><pickled-initializer> */ int loaduse(char *path, FILE *f, Stab *st, Vis vis) { intptr_t tid; size_t i; int v; char *pkg; Node *dcl, *impl, *init; Stab *s; Type *ty; Trait *tr; char *lib; int c; pushstab(file->file.globls); if (!tydeduptab) tydeduptab = mkht(tyhash, tyeq); if (fgetc(f) != 'U') return 0; v = rdint(f); if (v != Abiversion) { fprintf(stderr, "%s: abi version %d, expected %d\n", path, v, Abiversion); return 0; } pkg = rdstr(f); /* if the package names match up, or the usefile has no declared * package, then we simply add to the current stab. Otherwise, * we add a new stab under the current one */ if (st->name) { if (pkg && !strcmp(pkg, st->name)) { s = st; } else { s = findstab(st, pkg); } } else { if (pkg) { s = findstab(st, pkg); } else { s = st; } } if (!streq(st->name, pkg)) vis = Visintern; if (!s) { printf("could not find matching package for merge: %s in %s\n", st->name, path); exit(1); } tidmap = mkht(ptrhash, ptreq); trmap = mkht(ptrhash, ptreq); if (!initmap) initmap = mkht(namehash, nameeq); /* builtin traits */ for (i = 0; i < Ntraits; i++) htput(trmap, itop(i), traittab[i]); while ((c = fgetc(f)) != EOF) { switch (c) { case 'L': lib = rdstr(f); for (i = 0; i < file->file.nlibdeps; i++) if (!strcmp(file->file.libdeps[i], lib)) /* break out of both loop and switch */ goto foundlib; lappend(&file->file.libdeps, &file->file.nlibdeps, lib); foundlib: break; case 'X': lib = rdstr(f); for (i = 0; i < file->file.nextlibs; i++) if (!strcmp(file->file.extlibs[i], lib)) /* break out of both loop and switch */ goto foundextlib; lappend(&file->file.extlibs, &file->file.nextlibs, lib); foundextlib: break; case 'F': lappend(&file->file.files, &file->file.nfiles, rdstr(f)); break; case 'G': case 'D': dcl = rdsym(f, NULL); dcl->decl.vis = vis; dcl->decl.isglobl = 1; putdcl(s, dcl); break; case 'S': init = unpickle(f); if (!hthas(initmap, init)) { htput(initmap, init, init); lappend(&file->file.init, &file->file.ninit, init); } break; case 'R': tr = traitunpickle(f); tr->vis = vis; if (!tr->ishidden) { puttrait(s, tr->name, tr); for (i = 0; i < tr->nfuncs; i++) { putdcl(s, tr->funcs[i]); } } break; case 'T': tid = rdint(f); ty = tyunpickle(f); if (!ty->ishidden) ty->vis = vis; htput(tidmap, itop(tid), ty); /* fix up types */ if (ty->type == Tyname || ty->type == Tygeneric) { if (ty->issynth) break; if (!streq(s->name, ty->name->name.ns)) ty->ishidden = 1; if (!gettype(s, ty->name) && !ty->ishidden) puttype(s, ty->name, ty); } else if (ty->type == Tyunion) { for (i = 0; i < ty->nmemb; i++) if (!getucon(s, ty->udecls[i]->name) && !ty->udecls[i]->synth) putucon(s, ty->udecls[i]); } break; case 'I': impl = unpickle(f); impl->impl.isextern = 1; impl->impl.vis = vis; /* specialized declarations always go into the global stab */ for (i = 0; i < impl->impl.ndecls; i++) { impl->impl.decls[i]->decl.isglobl = 1; putdcl(file->file.globls, impl->impl.decls[i]); } break; case EOF: break; } } fixtypemappings(s); fixtraitmappings(s); fiximplmappings(s); htfree(tidmap); popstab(); return 1; } int hassuffix(char *str, char *suff) { size_t nstr, nsuff; nstr = strlen(str); nsuff = strlen(suff); if (nstr < nsuff) return 0; return !strcmp(str + nstr - nsuff, suff); } void readuse(Node *use, Stab *st, Vis vis) { size_t i; FILE *fd; char *t, *p; char buf[512]; /* local (quoted) uses are always relative to the cwd */ fd = NULL; p = NULL; if (use->use.islocal) { if (hassuffix(use->use.name, ".use")) snprintf(buf, sizeof buf, "%s", use->use.name); else snprintf(buf,sizeof buf, "%s.use", use->use.name); p = strdup(buf); fd = fopen(p, "r"); /* nonlocal (barename) uses are always searched on the include path */ } else { for (i = 0; i < nincpaths; i++) { snprintf(buf, sizeof buf, "lib%s.use", use->use.name); t = strjoin(incpaths[i], "/"); p = strjoin(t, buf); fd = fopen(p, "r"); if (fd) { free(t); break; } free(p); t = strjoin(incpaths[i], "/"); p = strjoin(t, use->use.name); fd = fopen(p, "r"); if (fd) { free(t); break; } free(p); } } if (!fd) { fprintf(stderr, "could not open usefile %s in search path:\n", use->use.name); for (i = 0; i < nincpaths; i++) fprintf(stderr, "\t%s\n", incpaths[i]); exit(1); } if (!loaduse(p, fd, st, vis)) die("Could not load usefile %s from %s", use->use.name, p); free(p); } /* Usefile format: * U<pkgname> * L<liblist> * I<initlist> * T<pickled-type> * D<picled-decl> * G<pickled-decl><pickled-initializer> * Z */ void writeuse(FILE *f, Node *file) { Stab *st; void **k; Node *s, *u; size_t i, n; assert(file->type == Nfile); st = file->file.globls; /* usefile name */ wrbyte(f, 'U'); wrint(f, Abiversion); /* use version */ if (st->name) wrstr(f, st->name); else wrstr(f, NULL); /* library deps */ for (i = 0; i < file->file.nuses; i++) { u = file->file.uses[i]; if (!u->use.islocal) { wrbyte(f, 'L'); wrstr(f, u->use.name); } } for (i = 0; i < file->file.nlibdeps; i++) { wrbyte(f, 'L'); wrstr(f, file->file.libdeps[i]); } for (i = 0; i < file->file.nextlibs; i++) { wrbyte(f, 'X'); wrstr(f, file->file.extlibs[i]); } /* source file name */ wrbyte(f, 'F'); wrstr(f, file->file.files[0]); for (i = 0; i < ntypes; i++) { if (types[i]->vis == Visexport || types[i]->vis == Vishidden) { wrbyte(f, 'T'); wrint(f, types[i]->tid); typickle(f, types[i]); } } for (i = 0; i < ntraittab; i++) { if (i < Ntraits) continue; if (traittab[i]->vis == Visexport || traittab[i]->vis == Vishidden) { wrbyte(f, 'R'); traitpickle(f, traittab[i]); } } k = htkeys(st->impl, &n); for (i = 0; i < n; i++) { /* merging during inference should remove all protos */ s = getimpl(st, k[i]); assert(!s->impl.isproto); if (s->impl.vis == Visexport || s->impl.vis == Vishidden) { wrbyte(f, 'I'); pickle(f, s); } } free(k); k = htkeys(st->dcl, &n); for (i = 0; i < n; i++) { s = getdcl(st, k[i]); assert(s != NULL); if (s->decl.vis == Visintern || s->decl.vis == Visbuiltin) continue; /* trait functions get written out with their traits */ if (s->decl.trait || s->decl.isinit) continue; else if (s->decl.isgeneric) wrbyte(f, 'G'); else wrbyte(f, 'D'); wrsym(f, s); } for (i = 0; i < file->file.ninit; i++) { wrbyte(f, 'S'); pickle(f, file->file.init[i]); } if (file->file.localinit) { wrbyte(f, 'S'); pickle(f, file->file.localinit->decl.name); } free(k); }