#include "limbo.h" char *storename[Dend]= { /* Dtype */ "type", /* Dfn */ "function", /* Dglobal */ "global", /* Darg */ "argument", /* Dlocal */ "local", /* Dconst */ "con", /* Dfield */ "field", /* Dtag */ "pick tag", /* Dimport */ "import", /* Dunbound */ "unbound", /* Dundef */ "undefined", /* Dwundef */ "undefined", }; char *storeart[Dend] = { /* Dtype */ "a ", /* Dfn */ "a ", /* Dglobal */ "a ", /* Darg */ "an ", /* Dlocal */ "a ", /* Dconst */ "a ", /* Dfield */ "a ", /* Dtag */ "a", /* Dimport */ "an ", /* Dunbound */ "", /* Dundef */ "", /* Dwundef */ "", }; int storespace[Dend] = { /* Dtype */ 0, /* Dfn */ 0, /* Dglobal */ 1, /* Darg */ 1, /* Dlocal */ 1, /* Dconst */ 0, /* Dfield */ 1, /* Dtag */ 0, /* Dimport */ 0, /* Dunbound */ 0, /* Dundef */ 0, /* Dwundef */ 0, }; static Decl *scopes[MaxScope]; static Decl *tails[MaxScope]; static Node *scopenode[MaxScope]; static uchar scopekind[MaxScope]; static void freeloc(Decl*); void popscopes(void) { Decl *d; Dlist *id; /* * clear out any decls left in syms */ while(scope >= ScopeBuiltin){ for(d = scopes[scope--]; d != nil; d = d->next){ if(d->sym != nil){ d->sym->decl = d->old; d->old = nil; } } } for(id = impdecls; id != nil; id = id->next){ for(d = id->d->ty->ids; d != nil; d = d->next){ d->sym->decl = nil; d->old = nil; } } impdecls = nil; scope = ScopeBuiltin; scopes[ScopeBuiltin] = nil; tails[ScopeBuiltin] = nil; } void declstart(void) { Decl *d; iota = mkids(&nosrc, enter("iota", 0), tint, nil); iota->init = mkconst(&nosrc, 0); scope = ScopeNils; scopes[ScopeNils] = nil; tails[ScopeNils] = nil; nildecl = mkdecl(&nosrc, Dglobal, tany); nildecl->sym = enter("nil", 0); installids(Dglobal, nildecl); d = mkdecl(&nosrc, Dglobal, tstring); d->sym = enter("", 0); installids(Dglobal, d); scope = ScopeGlobal; scopes[ScopeGlobal] = nil; tails[ScopeGlobal] = nil; } void redecl(Decl *d) { Decl *old; old = d->sym->decl; if(old->store == Dwundef) return; error(d->src.start, "redeclaration of %K, previously declared as %k on line %L", d, old, old->src.start); } void checkrefs(Decl *d) { Decl *id, *m; long refs; for(; d != nil; d = d->next){ if(d->das) d->refs--; switch(d->store){ case Dtype: refs = d->refs; if(d->ty->kind == Tadt){ for(id = d->ty->ids; id != nil; id = id->next){ d->refs += id->refs; if(id->store != Dfn) continue; if(id->init == nil && id->link == nil && d->importid == nil) error(d->src.start, "function %s.%s not defined", d->sym->name, id->sym->name); if(superwarn && !id->refs && d->importid == nil) warn(d->src.start, "function %s.%s not referenced", d->sym->name, id->sym->name); } } if(d->ty->kind == Tmodule){ for(id = d->ty->ids; id != nil; id = id->next){ refs += id->refs; if(id->iface != nil) id->iface->refs += id->refs; if(id->store == Dtype){ for(m = id->ty->ids; m != nil; m = m->next){ refs += m->refs; if(m->iface != nil) m->iface->refs += m->refs; } } } d->refs = refs; } if(superwarn && !refs && d->importid == nil) warn(d->src.start, "%K not referenced", d); break; case Dglobal: if(!superwarn) break; case Dlocal: case Darg: if(!d->refs && d->sym != nil && d->sym->name != nil && d->sym->name[0] != '.') warn(d->src.start, "%K not referenced", d); break; case Dconst: if(superwarn && !d->refs && d->sym != nil) warn(d->src.start, "%K not referenced", d); if(d->ty == tstring && d->init != nil) d->init->decl->refs += d->refs; break; case Dfn: if(d->init == nil && d->importid == nil) error(d->src.start, "%K not defined", d); if(superwarn && !d->refs) warn(d->src.start, "%K not referenced", d); break; case Dimport: if(superwarn && !d->refs) warn(d->src.start, "%K not referenced", d); break; } if(d->das) d->refs++; } } Node* vardecl(Decl *ids, Type *t) { Node *n; n = mkn(Ovardecl, mkn(Oseq, nil, nil), nil); n->decl = ids; n->ty = t; return n; } void vardecled(Node *n) { Decl *ids, *last; Type *t; int store; store = Dlocal; if(scope == ScopeGlobal) store = Dglobal; if(n->ty->kind == Texception && n->ty->cons){ store = Dconst; fatal("Texception in vardecled"); } ids = n->decl; installids(store, ids); t = n->ty; for(last = ids; ids != nil; ids = ids->next){ ids->ty = t; last = ids; } n->left->decl = last; } Node* condecl(Decl *ids, Node *init) { Node *n; n = mkn(Ocondecl, mkn(Oseq, nil, nil), init); n->decl = ids; return n; } void condecled(Node *n) { Decl *ids, *last; ids = n->decl; installids(Dconst, ids); for(last = ids; ids != nil; ids = ids->next){ ids->ty = tunknown; last = ids; } n->left->decl = last; } Node* exdecl(Decl *ids, Decl *tids) { Node *n; Type *t; t = mktype(&ids->src.start, &ids->src.stop, Texception, nil, tids); t->cons = 1; n = mkn(Oexdecl, mkn(Oseq, nil, nil), nil); n->decl = ids; n->ty = t; return n; } void exdecled(Node *n) { Decl *ids, *last; Type *t; ids = n->decl; installids(Dconst, ids); t = n->ty; for(last = ids; ids != nil; ids = ids->next){ ids->ty = t; last = ids; } n->left->decl = last; } Node* importdecl(Node *m, Decl *ids) { Node *n; n = mkn(Oimport, mkn(Oseq, nil, nil), m); n->decl = ids; return n; } void importdecled(Node *n) { Decl *ids, *last; ids = n->decl; installids(Dimport, ids); for(last = ids; ids != nil; ids = ids->next){ ids->ty = tunknown; last = ids; } n->left->decl = last; } Node* mkscope(Node *body) { Node *n; n = mkn(Oscope, nil, body); if(body != nil) n->src = body->src; return n; } Node* fndecl(Node *n, Type *t, Node *body) { n = mkbin(Ofunc, n, body); n->ty = t; return n; } void fndecled(Node *n) { Decl *d; Node *left; left = n->left; if(left->op == Oname){ d = left->decl->sym->decl; if(d == nil || d->store == Dimport){ d = mkids(&left->src, left->decl->sym, n->ty, nil); installids(Dfn, d); } left->decl = d; d->refs++; } if(left->op == Odot) pushscope(nil, Sother); if(n->ty->polys != nil){ pushscope(nil, Sother); installids(Dtype, n->ty->polys); } pushscope(nil, Sother); installids(Darg, n->ty->ids); n->ty->ids = popscope(); if(n->ty->val != nil) mergepolydecs(n->ty); if(n->ty->polys != nil) n->ty->polys = popscope(); if(left->op == Odot) popscope(); } /* * check the function declaration only * the body will be type checked later by fncheck */ Decl * fnchk(Node *n) { int bad; Decl *d, *inadt, *adtp; Type *t; bad = 0; d = n->left->decl; if(n->left->op == Odot) d = n->left->right->decl; if(d == nil) fatal("decl() fnchk nil"); n->left->decl = d; if(d->store == Dglobal || d->store == Dfield) d->store = Dfn; if(d->store != Dfn || d->init != nil){ nerror(n, "redeclaration of function %D, previously declared as %k on line %L", d, d, d->src.start); if(d->store == Dfn && d->init != nil) bad = 1; } d->init = n; t = n->ty; inadt = d->dot; if(inadt != nil && (inadt->store != Dtype || inadt->ty->kind != Tadt)) inadt = nil; if(n->left->op == Odot){ pushscope(nil, Sother); adtp = outerpolys(n->left); if(adtp != nil) installids(Dtype, adtp); if(!polyequal(adtp, n->decl)) nerror(n, "adt polymorphic type mismatch"); n->decl = nil; } t = validtype(t, inadt); if(n->left->op == Odot) popscope(); if(debug['d']) print("declare function %D ty %T newty %T\n", d, d->ty, t); t = usetype(t); if(!polyequal(d->ty->polys, t->polys)) nerror(n, "function polymorphic type mismatch"); if(!tcompat(d->ty, t, 0)) nerror(n, "type mismatch: %D defined as %T declared as %T on line %L", d, t, d->ty, d->src.start); else if(!raisescompat(d->ty->u.eraises, t->u.eraises)) nerror(n, "raises mismatch: %D", d); if(t->varargs != 0) nerror(n, "cannot define functions with a '*' argument, such as %D", d); t->u.eraises = d->ty->u.eraises; d->ty = t; d->offset = idoffsets(t->ids, MaxTemp, IBY2WD); d->src = n->src; d->locals = nil; n->ty = t; return bad ? nil: d; } Node* globalas(Node *dst, Node *v, int valok) { Node *tv; if(v == nil) return nil; if(v->op == Oas || v->op == Odas){ v = globalas(v->left, v->right, valok); if(v == nil) return nil; }else if(valok && !initable(dst, v, 0)) return nil; switch(dst->op){ case Oname: if(dst->decl->init != nil) nerror(dst, "duplicate assignment to %V, previously assigned on line %L", dst, dst->decl->init->src.start); if(valok) dst->decl->init = v; return v; case Otuple: if(valok && v->op != Otuple) fatal("can't deal with %n in tuple case of globalas", v); tv = v->left; for(dst = dst->left; dst != nil; dst = dst->right){ globalas(dst->left, tv->left, valok); if(valok) tv = tv->right; } return v; } fatal("can't deal with %n in globalas", dst); return nil; } int needsstore(Decl *d) { if(!d->refs) return 0; if(d->importid != nil) return 0; if(storespace[d->store]) return 1; return 0; } /* * return the list of all referenced storage variables */ Decl* vars(Decl *d) { Decl *v, *n; while(d != nil && !needsstore(d)) d = d->next; for(v = d; v != nil; v = v->next){ while(v->next != nil){ n = v->next; if(needsstore(n)) break; v->next = n->next; } } return d; } /* * declare variables from the left side of a := statement */ static int recdasdecl(Node *n, int store, int *nid) { Decl *d, *old; int ok; switch(n->op){ case Otuple: ok = 1; for(n = n->left; n != nil; n = n->right) ok &= recdasdecl(n->left, store, nid); return ok; case Oname: if(n->decl == nildecl){ *nid = -1; return 1; } d = mkids(&n->src, n->decl->sym, nil, nil); installids(store, d); old = d->old; if(old != nil && old->store != Dfn && old->store != Dwundef && old->store != Dundef) warn(d->src.start, "redeclaration of %K, previously declared as %k on line %L", d, old, old->src.start); n->decl = d; d->refs++; d->das = 1; if(*nid >= 0) (*nid)++; return 1; } return 0; } static int recmark(Node *n, int nid) { switch(n->op){ case Otuple: for(n = n->left; n != nil; n = n->right) nid = recmark(n->left, nid); break; case Oname: n->decl->nid = nid; nid = 0; break; } return nid; } int dasdecl(Node *n) { int store, ok, nid; nid = 0; if(scope == ScopeGlobal) store = Dglobal; else store = Dlocal; ok = recdasdecl(n, store, &nid); if(!ok) nerror(n, "illegal declaration expression %V", n); if(ok && store == Dlocal && nid > 1) recmark(n, nid); return ok; } /* * declare global variables in nested := expressions */ void gdasdecl(Node *n) { if(n == nil) return; if(n->op == Odas){ gdasdecl(n->right); dasdecl(n->left); }else{ gdasdecl(n->left); gdasdecl(n->right); } } Decl* undefed(Src *src, Sym *s) { Decl *d; d = mkids(src, s, tnone, nil); error(src->start, "%s is not declared", s->name); installids(Dwundef, d); return d; } /* int inloop() { int i; for (i = scope; i > 0; i--) if (scopekind[i] == Sloop) return 1; return 0; } */ int nested() { int i; for (i = scope; i > 0; i--) if (scopekind[i] == Sscope || scopekind[i] == Sloop) return 1; return 0; } void decltozero(Node *n) { Node *scp; if ((scp = scopenode[scope]) != nil) { /* can happen if we do * x[i] := ...... * which is an error */ if (n->right != nil && errors == 0) fatal("Ovardecl/Oname/Otuple has right field\n"); n->right = scp->left; scp->left = n; } } void pushscope(Node *scp, int kind) { if(scope >= MaxScope) fatal("scope too deep"); scope++; scopes[scope] = nil; tails[scope] = nil; scopenode[scope] = scp; scopekind[scope] = kind; } Decl* curscope(void) { return scopes[scope]; } /* * revert to old declarations for each symbol in the currect scope. * remove the effects of any imported adt types * whenever the adt is imported from a module, * we record in the type's decl the module to use * when calling members. the process is reversed here. */ Decl* popscope(void) { Decl *id; Type *t; if (debug['X']) print("popscope\n"); for(id = scopes[scope]; id != nil; id = id->next){ if(id->sym != nil){ if (debug['X']) print("%s : %s %d\n", id->sym->name, kindname[id->ty->kind], id->init != nil ? id->init->op : 0); id->sym->decl = id->old; id->old = nil; } if(id->importid != nil) id->importid->refs += id->refs; t = id->ty; if(id->store == Dtype && t->decl != nil && t->decl->timport == id) t->decl->timport = id->timport; if(id->store == Dlocal) freeloc(id); } return scopes[scope--]; } /* * make a new scope, * preinstalled with some previously installed identifiers * don't add the identifiers to the scope chain, * so they remain separate from any newly installed ids * * these routines assume no ids are imports */ void repushids(Decl *ids) { Sym *s; if(scope >= MaxScope) fatal("scope too deep"); scope++; scopes[scope] = nil; tails[scope] = nil; scopenode[scope] = nil; scopekind[scope] = Sother; for(; ids != nil; ids = ids->next){ if(ids->scope != scope && (ids->dot == nil || !isimpmod(ids->dot->sym) || ids->scope != ScopeGlobal || scope != ScopeGlobal + 1)) fatal("repushids scope mismatch"); s = ids->sym; if(s != nil && ids->store != Dtag){ if(s->decl != nil && s->decl->scope >= scope) ids->old = s->decl->old; else ids->old = s->decl; s->decl = ids; } } } /* * pop a scope which was started with repushids * return any newly installed ids */ Decl* popids(Decl *ids) { for(; ids != nil; ids = ids->next){ if(ids->sym != nil && ids->store != Dtag){ ids->sym->decl = ids->old; ids->old = nil; } } return popscope(); } void installids(int store, Decl *ids) { Decl *d, *last; Sym *s; last = nil; for(d = ids; d != nil; d = d->next){ d->scope = scope; if(d->store == Dundef) d->store = store; s = d->sym; if(s != nil){ if(s->decl != nil && s->decl->scope >= scope){ redecl(d); d->old = s->decl->old; }else d->old = s->decl; s->decl = d; } last = d; } if(ids != nil){ d = tails[scope]; if(d == nil) scopes[scope] = ids; else d->next = ids; tails[scope] = last; } } Decl* lookup(Sym *sym) { int s; Decl *d; for(s = scope; s >= ScopeBuiltin; s--){ for(d = scopes[s]; d != nil; d = d->next){ if(d->sym == sym) return d; } } return nil; } Decl* mkids(Src *src, Sym *s, Type *t, Decl *next) { Decl *d; d = mkdecl(src, Dundef, t); d->next = next; d->sym = s; return d; } Decl* mkdecl(Src *src, int store, Type *t) { Decl *d; static Decl z; d = allocmem(sizeof *d); *d = z; d->src = *src; d->store = store; d->ty = t; d->nid = 1; return d; } Decl* dupdecl(Decl *old) { Decl *d; d = allocmem(sizeof *d); *d = *old; d->next = nil; return d; } Decl* dupdecls(Decl *old) { Decl *d, *nd, *first, *last; first = last = nil; for(d = old; d != nil; d = d->next){ nd = dupdecl(d); if(first == nil) first = nd; else last->next = nd; last = nd; } return first; } Decl* appdecls(Decl *d, Decl *dd) { Decl *t; if(d == nil) return dd; for(t = d; t->next != nil; t = t->next) ; t->next = dd; return d; } Decl* revids(Decl *id) { Decl *d, *next; d = nil; for(; id != nil; id = next){ next = id->next; id->next = d; d = id; } return d; } long idoffsets(Decl *id, long offset, int al) { int a, algn; Decl *d; algn = 1; for(; id != nil; id = id->next){ if(storespace[id->store]){ usedty(id->ty); if(id->store == Dlocal && id->link != nil){ /* id->nid always 1 */ id->offset = id->link->offset; continue; } a = id->ty->align; if(id->nid > 1){ for(d = id->next; d != nil && d->nid == 0; d = d->next) if(d->ty->align > a) a = d->ty->align; algn = a; } offset = align(offset, a); id->offset = offset; offset += id->ty->size; if(id->nid == 0 && (id->next == nil || id->next->nid != 0)) offset = align(offset, algn); } } return align(offset, al); } long idindices(Decl *id) { int i; i = 0; for(; id != nil; id = id->next){ if(storespace[id->store]){ usedty(id->ty); id->offset = i++; } } return i; } int declconv(Fmt *f) { Decl *d; char buf[4096], *s; d = va_arg(f->args, Decl*); if(d->sym == nil) s = ""; else s = d->sym->name; seprint(buf, buf+sizeof(buf), "%s %s", storename[d->store], s); return fmtstrcpy(f, buf); } int storeconv(Fmt *f) { Decl *d; char buf[4096]; d = va_arg(f->args, Decl*); seprint(buf, buf+sizeof(buf), "%s%s", storeart[d->store], storename[d->store]); return fmtstrcpy(f, buf); } int dotconv(Fmt *f) { Decl *d; char buf[4096], *p, *s; d = va_arg(f->args, Decl*); buf[0] = 0; p = buf; if(d->dot != nil && !isimpmod(d->dot->sym)){ s = "."; if(d->dot->ty != nil && d->dot->ty->kind == Tmodule) s = "->"; p = seprint(buf, buf+sizeof(buf), "%D%s", d->dot, s); } seprint(p, buf+sizeof(buf), "%s", d->sym->name); return fmtstrcpy(f, buf); } /* * merge together two sorted lists, yielding a sorted list */ static Decl* namemerge(Decl *e, Decl *f) { Decl rock, *d; d = &rock; while(e != nil && f != nil){ if(strcmp(e->sym->name, f->sym->name) <= 0){ d->next = e; e = e->next; }else{ d->next = f; f = f->next; } d = d->next; } if(e != nil) d->next = e; else d->next = f; return rock.next; } /* * recursively split lists and remerge them after they are sorted */ static Decl* recnamesort(Decl *d, int n) { Decl *r, *dd; int i, m; if(n <= 1) return d; m = n / 2 - 1; dd = d; for(i = 0; i < m; i++) dd = dd->next; r = dd->next; dd->next = nil; return namemerge(recnamesort(d, n / 2), recnamesort(r, (n + 1) / 2)); } /* * sort the ids by name */ Decl* namesort(Decl *d) { Decl *dd; int n; n = 0; for(dd = d; dd != nil; dd = dd->next) n++; return recnamesort(d, n); } void printdecls(Decl *d) { for(; d != nil; d = d->next) print("%ld: %K %T ref %d\n", d->offset, d, d->ty, d->refs); } void mergepolydecs(Type *t) { Node *n, *nn; Decl *id, *ids, *ids1; for(n = t->val; n != nil; n = n->right){ nn = n->left; for(ids = nn->decl; ids != nil; ids = ids->next){ id = ids->sym->decl; if(id == nil){ undefed(&ids->src, ids->sym); break; } if(id->store != Dtype){ error(ids->src.start, "%K is not a type", id); break; } if(id->ty->kind != Tpoly){ error(ids->src.start, "%K is not a polymorphic type", id); break; } if(id->ty->ids != nil) error(ids->src.start, "%K redefined", id); pushscope(nil, Sother); fielddecled(nn->left); id->ty->ids = popscope(); for(ids1 = id->ty->ids; ids1 != nil; ids1 = ids1->next){ ids1->dot = id; bindtypes(ids1->ty); if(ids1->ty->kind != Tfn){ error(ids1->src.start, "only function types expected"); id->ty->ids = nil; } } } } t->val = nil; } static void adjfnptrs(Decl *d, Decl *polys1, Decl *polys2) { int n; Decl *id, *idt, *idf, *arg; if(debug['U']) print("adjnptrs %s\n", d->sym->name); n = 0; for(id = d->ty->ids; id != nil; id = id->next) n++; for(idt = polys1; idt != nil; idt = idt->next) for(idf = idt->ty->ids; idf != nil; idf = idf->next) n -= 2; for(idt = polys2; idt != nil; idt = idt->next) for(idf = idt->ty->ids; idf != nil; idf = idf->next) n -= 2; for(arg = d->ty->ids; --n >= 0; arg = arg->next) ; for(idt = polys1; idt != nil; idt = idt->next){ for(idf = idt->ty->ids; idf != nil; idf = idf->next){ idf->link = arg; arg = arg->next->next; } } for(idt = polys2; idt != nil; idt = idt->next){ for(idf = idt->ty->ids; idf != nil; idf = idf->next){ idf->link = arg; arg = arg->next->next; } } } static void addptrs(Decl *polys, Decl** fps, Decl **last, int link, Src *src) { Decl *idt, *idf, *fp; if(debug['U']) print("addptrs\n"); for(idt = polys; idt != nil; idt = idt->next){ for(idf = idt->ty->ids; idf != nil; idf = idf->next){ fp = mkdecl(src, Darg, tany); fp->sym = idf->sym; if(link) idf->link = fp; if(*fps == nil) *fps = fp; else (*last)->next = fp; *last = fp; fp = mkdecl(src, Darg, tint); fp->sym = idf->sym; (*last)->next = fp; *last = fp; } } } void addfnptrs(Decl *d, int link) { Decl *fps, *last, *polys; if(debug['U']) print("addfnptrs %s %d\n", d->sym->name, link); polys = encpolys(d); if(d->ty->flags&FULLARGS){ if(link) adjfnptrs(d, d->ty->polys, polys); if(0 && debug['U']){ for(d = d->ty->ids; d != nil; d = d->next) print("%s=%ld(%d) ", d->sym->name, d->offset, tattr[d->ty->kind].isptr); print("\n"); } return; } d->ty->flags |= FULLARGS; fps = last = nil; addptrs(d->ty->polys, &fps, &last, link, &d->src); addptrs(polys, &fps, &last, link, &d->src); for(last = d->ty->ids; last != nil && last->next != nil; last = last->next) ; if(last != nil) last->next = fps; else d->ty->ids = fps; d->offset = idoffsets(d->ty->ids, MaxTemp, IBY2WD); if(0 && debug['U']){ for(d = d->ty->ids; d != nil; d = d->next) print("%s=%ld(%d) ", d->sym->name, d->offset, tattr[d->ty->kind].isptr); print("\n"); } } void rmfnptrs(Decl *d) { int n; Decl *id, *idt, *idf; if(debug['U']) print("rmfnptrs %s\n", d->sym->name); if(!(d->ty->flags&FULLARGS)) return; d->ty->flags &= ~FULLARGS; n = 0; for(id = d->ty->ids; id != nil; id = id->next) n++; for(idt = d->ty->polys; idt != nil; idt = idt->next) for(idf = idt->ty->ids; idf != nil; idf = idf->next) n -= 2; for(idt = encpolys(d); idt != nil; idt = idt->next) for(idf = idt->ty->ids; idf != nil; idf = idf->next) n -= 2; if(n == 0){ d->ty->ids = nil; return; } for(id = d->ty->ids; --n > 0; id = id->next) ; id->next = nil; d->offset = idoffsets(d->ty->ids, MaxTemp, IBY2WD); } int local(Decl *d) { for(d = d->dot; d != nil; d = d->dot) if(d->store == Dtype && d->ty->kind == Tmodule) return 0; return 1; } Decl* module(Decl *d) { for(d = d->dot; d != nil; d = d->dot) if(d->store == Dtype && d->ty->kind == Tmodule) return d; return nil; } Decl* outerpolys(Node *n) { Decl *d; if(n->op == Odot){ d = n->right->decl; if(d == nil) fatal("decl() outeradt nil"); d = d->dot; if(d != nil && d->store == Dtype && d->ty->kind == Tadt) return d->ty->polys; } return nil; } Decl* encpolys(Decl *d) { if((d = d->dot) == nil) return nil; return d->ty->polys; } Decl* fnlookup(Sym *s, Type *t, Node **m) { Decl *id; Node *mod; id = nil; mod = nil; if(t->kind == Tpoly || t->kind == Tmodule) id = namedot(t->ids, s); else if(t->kind == Tref){ t = t->tof; if(t->kind == Tadt){ id = namedot(t->ids, s); if(t->decl != nil && t->decl->timport != nil) mod = t->decl->timport->eimport; } else if(t->kind == Tadtpick){ id = namedot(t->ids, s); if(t->decl != nil && t->decl->timport != nil) mod = t->decl->timport->eimport; t = t->decl->dot->ty; if(id == nil) id = namedot(t->ids, s); if(t->decl != nil && t->decl->timport != nil) mod = t->decl->timport->eimport; } } if(id == nil){ id = lookup(s); if(id != nil) mod = id->eimport; } if(m != nil) *m = mod; return id; } int isimpmod(Sym *s) { Decl *d; for(d = impmods; d != nil; d = d->next) if(d->sym == s) return 1; return 0; } int dequal(Decl *d1, Decl *d2, int full) { return d1->sym == d2->sym && d1->store == d2->store && d1->implicit == d2->implicit && d1->cyc == d2->cyc && (!full || tequal(d1->ty, d2->ty)) && (!full || d1->store == Dfn || sametree(d1->init, d2->init)); } static int tzero(Type *t) { return t->kind == Texception || tmustzero(t); } static int isptr(Type *t) { return t->kind == Texception || tattr[t->kind].isptr; } /* can d share the same stack location as another local ? */ void shareloc(Decl *d) { int z; Type *t, *tt; Decl *dd, *res; if(d->store != Dlocal || d->nid != 1) return; t = d->ty; res = nil; for(dd = fndecls; dd != nil; dd = dd->next){ if(d == dd) fatal("d==dd in shareloc"); if(dd->store != Dlocal || dd->nid != 1 || dd->link != nil || dd->tref != 0) continue; tt = dd->ty; if(t->size != tt->size || t->align != tt->align) continue; z = tzero(t)+tzero(tt); if(z > 0) continue; /* for now */ if(t == tt || tequal(t, tt)) res = dd; else{ if(z == 1) continue; if(z == 0 || isptr(t) || isptr(tt) || mktdesc(t) == mktdesc(tt)) res = dd; } if(res != nil){ /* print("%L %K share %L %K\n", d->src.start, d, res->src.start, res); */ d->link = res; res->tref = 1; return; } } return; } static void freeloc(Decl *d) { if(d->link != nil) d->link->tref = 0; }