diff options
| author | Charles.Forsyth <devnull@localhost> | 2006-12-22 17:07:39 +0000 |
|---|---|---|
| committer | Charles.Forsyth <devnull@localhost> | 2006-12-22 17:07:39 +0000 |
| commit | 37da2899f40661e3e9631e497da8dc59b971cbd0 (patch) | |
| tree | cbc6d4680e347d906f5fa7fca73214418741df72 /limbo/decls.c | |
| parent | 54bc8ff236ac10b3eaa928fd6bcfc0cdb2ba46ae (diff) | |
20060303a
Diffstat (limited to 'limbo/decls.c')
| -rw-r--r-- | limbo/decls.c | 1367 |
1 files changed, 1367 insertions, 0 deletions
diff --git a/limbo/decls.c b/limbo/decls.c new file mode 100644 index 00000000..4edab461 --- /dev/null +++ b/limbo/decls.c @@ -0,0 +1,1367 @@ +#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 Decl zdecl; + +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; +} |
