#include "limbo.h"#include "y.tab.h" Node **labstack;int labdep;static Node* inexcept;static Decl* fndec; void checkraises(Node *n); static voidincrefs(Decl *id){ for( ; id != nil; id = id->link) id->refs++;} static intfninline(Decl *d){ Node *n, *left, *right; left = right = nil; n = d->init; if(dontinline || d->caninline < 0 || d->locals != nil || ispoly(d) || n->ty->tof->kind == Tnone || nodes(n) >= 100) return 0; n = n->right; if(n->op == Oseq && n->right == nil) n = n->left; /* * inline * (a) return e; * (b) if(c) return e1; else return e2; * (c) if(c) return e1; return e2; */ switch(n->op){ case Oret: break; case Oif: right = n->right; if(right->right == nil || right->left->op != Oret || right->right->op != Oret || !tequal(right->left->left->ty, right->right->left->ty)) return 0; break; case Oseq: left = n->left; right = n->right; if(left->op != Oif || left->right->right != nil || left->right->left->op != Oret || right->op != Oseq || right->right != nil || right->left->op != Oret || !tequal(left->right->left->left->ty, right->left->left->ty)) return 0; break; default: return 0; } if(occurs(d, n) || hasasgns(n)) return 0; if(n->op == Oseq){ left->right->right = right->left; n = left; right = n->right; d->init->right->right = nil; } if(n->op == Oif){ n->ty = right->ty = right->left->left->ty; right->left = right->left->left; right->right = right->right->left; d->init->right->left = mkunary(Oret, n); } return 1;} static intisfnrefty(Type *t){ return t->kind == Tref && t->tof->kind == Tfn;} static intisfnref(Decl *d){ switch(d->store){ case Dglobal: case Darg: case Dlocal: case Dfield: case Dimport: return isfnrefty(d->ty); } return 0;} intargncompat(Node *n, Decl *f, Node *a){ for(; a != nil; a = a->right){ if(f == nil){ nerror(n, "%V: too many function arguments", n->left); return 0; } f = f->next; } if(f != nil){ nerror(n, "%V: too few function arguments", n->left); return 0; } return 1;} static voidrewind(Node *n){ Node *r, *nn; r = n; nn = n->left; for(n = n->right; n != nil; n = n->right){ if(n->right == nil){ r->left = nn; r->right = n->left; } else nn = mkbin(Oindex, nn, n->left); }} static voidckmod(Node *n, Decl *id){ Type *t; Decl *d, *idc; Node *mod; if(id == nil) fatal("can't find function: %n", n); idc = nil; mod = nil; if(n->op == Oname){ idc = id; mod = id->eimport; } else if(n->op == Omdot) mod = n->left; else if(n->op == Odot){ idc = id->dot; t = n->left->ty; if(t->kind == Tref) t = t->tof; if(t->kind == Tadtpick) t = t->decl->dot->ty; d = t->decl; while(d != nil && d->link != nil) d = d->link; if(d != nil && d->timport != nil) mod = d->timport->eimport; n->right->left = mod; } if(mod != nil && mod->ty->kind != Tmodule){ nerror(n, "cannot use %V as a function reference", n); return; } if(mod != nil){ if(valistype(mod)){ nerror(n, "cannot use %V as a function reference because %V is a module interface", n, mod); return; } }else if(idc != nil && idc->dot != nil && !isimpmod(idc->dot->sym)){ nerror(n, "cannot use %V without importing %s from a variable", n, idc->sym->name); return; } if(mod != nil) modrefable(n->ty);} static voidaddref(Node *n){ Node *nn; nn = mkn(0, nil, nil); *nn = *n; n->op = Oref; n->left = nn; n->right = nil; n->decl = nil; n->ty = usetype(mktype(&n->src.start, &n->src.stop, Tref, nn->ty, nil));} static voidfnref(Node *n, Decl *id){ id->caninline = -1; ckmod(n, id); addref(n); while(id->link != nil) id = id->link; if(ispoly(id) && encpolys(id) != nil) nerror(n, "cannot have a polymorphic adt function reference %s", id->sym->name);} Decl*typecheck(int checkimp){ Decl *entry, *m, *d; Sym *s; int i; if(errors) return nil; /* * generate the set of all functions * compile one function at a time */ gdecl(tree); gbind(tree); fns = allocmem(nfns * sizeof(Decl)); i = gcheck(tree, fns, 0); if(i != nfns) fatal("wrong number of functions found in gcheck"); maxlabdep = 0; for(i = 0; i < nfns; i++){ d = fns[i]; if(d != nil) fndec = d; if(d != nil) fncheck(d); fndec = nil; } if(errors) return nil; entry = nil; if(checkimp){ Decl *im; Dlist *dm; if(impmods == nil){ yyerror("no implementation module"); return nil; } for(im = impmods; im != nil; im = im->next){ for(dm = impdecls; dm != nil; dm = dm->next) if(dm->d->sym == im->sym) break; if(dm == nil || dm->d->ty == nil){ yyerror("no definition for implementation module %s", im->sym->name); return nil; } } /* * can't check the module spec until all types and imports are determined, * which happens in scheck */ for(dm = impdecls; dm != nil; dm = dm->next){ im = dm->d; im->refs++; im->ty = usetype(im->ty); if(im->store != Dtype || im->ty->kind != Tmodule){ error(im->src.start, "cannot implement %K", im); return nil; } } /* now check any multiple implementations */ impdecl = modimp(impdecls, impmods); s = enter("init", 0); entry = nil; for(dm = impdecls; dm != nil; dm = dm->next){ im = dm->d; for(m = im->ty->ids; m != nil; m = m->next){ m->ty = usetype(m->ty); m->refs++; if(m->sym == s && m->ty->kind == Tfn && entry == nil) entry = m; if(m->store == Dglobal || m->store == Dfn) modrefable(m->ty); if(m->store == Dtype && m->ty->kind == Tadt){ for(d = m->ty->ids; d != nil; d = d->next){ d->ty = usetype(d->ty); modrefable(d->ty); d->refs++; } } } checkrefs(im->ty->ids); } } if(errors) return nil; gsort(tree); tree = nil; return entry;} /* * introduce all global declarations * also adds all fields to adts and modules * note the complications due to nested Odas expressions */voidgdecl(Node *n){ for(;;){ if(n == nil) return; if(n->op != Oseq) break; gdecl(n->left); n = n->right; } switch(n->op){ case Oimport: importdecled(n); gdasdecl(n->right); break; case Oadtdecl: adtdecled(n); break; case Ocondecl: condecled(n); gdasdecl(n->right); break; case Oexdecl: exdecled(n); break; case Omoddecl: moddecled(n); break; case Otypedecl: typedecled(n); break; case Ovardecl: vardecled(n); break; case Ovardecli: vardecled(n->left); gdasdecl(n->right); break; case Ofunc: fndecled(n); break; case Oas: case Odas: case Onothing: gdasdecl(n); break; default: fatal("can't deal with %O in gdecl", n->op); }} /* * bind all global type ids, * including those nested inside modules * this needs to be done, since we may use such * a type later in a nested scope, so if we bound * the type ids then, the type could get bound * to a nested declaration */voidgbind(Node *n){ Decl *d, *ids; for(;;){ if(n == nil) return; if(n->op != Oseq) break; gbind(n->left); n = n->right; } switch(n->op){ case Oas: case Ocondecl: case Odas: case Oexdecl: case Ofunc: case Oimport: case Onothing: case Ovardecl: case Ovardecli: break; case Ofielddecl: bindtypes(n->decl->ty); break; case Otypedecl: bindtypes(n->decl->ty); if(n->left != nil) gbind(n->left); break; case Opickdecl: gbind(n->left); d = n->right->left->decl; bindtypes(d->ty); repushids(d->ty->ids); gbind(n->right->right); /* get new ids for undefined types; propagate outwards */ ids = popids(d->ty->ids); if(ids != nil) installids(Dundef, ids); break; case Oadtdecl: case Omoddecl: bindtypes(n->ty); if(n->ty->polys != nil) repushids(n->ty->polys); repushids(n->ty->ids); gbind(n->left); /* get new ids for undefined types; propagate outwards */ ids = popids(n->ty->ids); if(ids != nil) installids(Dundef, ids); if(n->ty->polys != nil) popids(n->ty->polys); break; default: fatal("can't deal with %O in gbind", n->op); }} /* * check all of the > declarations * bind all type ids referred to within types at the global level * record decls for defined functions */intgcheck(Node *n, Decl **fns, int nfns){ Ok rok; Decl *d; for(;;){ if(n == nil) return nfns; if(n->op != Oseq) break; nfns = gcheck(n->left, fns, nfns); n = n->right; } switch(n->op){ case Ofielddecl: if(n->decl->ty->u.eraises) raisescheck(n->decl->ty); break; case Onothing: case Opickdecl: break; case Otypedecl: tcycle(n->ty); break; case Oadtdecl: case Omoddecl: if(n->ty->polys != nil) repushids(n->ty->polys); repushids(n->ty->ids); if(gcheck(n->left, nil, 0)) fatal("gcheck fn decls nested in modules or adts"); if(popids(n->ty->ids) != nil) fatal("gcheck installs new ids in a module or adt"); if(n->ty->polys != nil) popids(n->ty->polys); break; case Ovardecl: varcheck(n, 1); break; case Ocondecl: concheck(n, 1); break; case Oexdecl: excheck(n, 1); break; case Oimport: importcheck(n, 1); break; case Ovardecli: varcheck(n->left, 1); rok = echeck(n->right, 0, 1, nil); if(rok.ok){ if(rok.allok) n->right = fold(n->right); globalas(n->right->left, n->right->right, rok.allok); } break; case Oas: case Odas: rok = echeck(n, 0, 1, nil); if(rok.ok){ if(rok.allok) n = fold(n); globalas(n->left, n->right, rok.allok); } break;Lines 1–500 of 3635. Load more
#include "limbo.h" #include "y.tab.h" Node **labstack; int labdep; static Node* inexcept; static Decl* fndec; void checkraises(Node *n); static void increfs(Decl *id) { for( ; id != nil; id = id->link) id->refs++; } static int fninline(Decl *d) { Node *n, *left, *right; left = right = nil; n = d->init; if(dontinline || d->caninline < 0 || d->locals != nil || ispoly(d) || n->ty->tof->kind == Tnone || nodes(n) >= 100) return 0; n = n->right; if(n->op == Oseq && n->right == nil) n = n->left; /* * inline * (a) return e; * (b) if(c) return e1; else return e2; * (c) if(c) return e1; return e2; */ switch(n->op){ case Oret: break; case Oif: right = n->right; if(right->right == nil || right->left->op != Oret || right->right->op != Oret || !tequal(right->left->left->ty, right->right->left->ty)) return 0; break; case Oseq: left = n->left; right = n->right; if(left->op != Oif || left->right->right != nil || left->right->left->op != Oret || right->op != Oseq || right->right != nil || right->left->op != Oret || !tequal(left->right->left->left->ty, right->left->left->ty)) return 0; break; default: return 0; } if(occurs(d, n) || hasasgns(n)) return 0; if(n->op == Oseq){ left->right->right = right->left; n = left; right = n->right; d->init->right->right = nil; } if(n->op == Oif){ n->ty = right->ty = right->left->left->ty; right->left = right->left->left; right->right = right->right->left; d->init->right->left = mkunary(Oret, n); } return 1; } static int isfnrefty(Type *t) { return t->kind == Tref && t->tof->kind == Tfn; } static int isfnref(Decl *d) { switch(d->store){ case Dglobal: case Darg: case Dlocal: case Dfield: case Dimport: return isfnrefty(d->ty); } return 0; } int argncompat(Node *n, Decl *f, Node *a) { for(; a != nil; a = a->right){ if(f == nil){ nerror(n, "%V: too many function arguments", n->left); return 0; } f = f->next; } if(f != nil){ nerror(n, "%V: too few function arguments", n->left); return 0; } return 1; } static void rewind(Node *n) { Node *r, *nn; r = n; nn = n->left; for(n = n->right; n != nil; n = n->right){ if(n->right == nil){ r->left = nn; r->right = n->left; } else nn = mkbin(Oindex, nn, n->left); } } static void ckmod(Node *n, Decl *id) { Type *t; Decl *d, *idc; Node *mod; if(id == nil) fatal("can't find function: %n", n); idc = nil; mod = nil; if(n->op == Oname){ idc = id; mod = id->eimport; } else if(n->op == Omdot) mod = n->left; else if(n->op == Odot){ idc = id->dot; t = n->left->ty; if(t->kind == Tref) t = t->tof; if(t->kind == Tadtpick) t = t->decl->dot->ty; d = t->decl; while(d != nil && d->link != nil) d = d->link; if(d != nil && d->timport != nil) mod = d->timport->eimport; n->right->left = mod; } if(mod != nil && mod->ty->kind != Tmodule){ nerror(n, "cannot use %V as a function reference", n); return; } if(mod != nil){ if(valistype(mod)){ nerror(n, "cannot use %V as a function reference because %V is a module interface", n, mod); return; } }else if(idc != nil && idc->dot != nil && !isimpmod(idc->dot->sym)){ nerror(n, "cannot use %V without importing %s from a variable", n, idc->sym->name); return; } if(mod != nil) modrefable(n->ty); } static void addref(Node *n) { Node *nn; nn = mkn(0, nil, nil); *nn = *n; n->op = Oref; n->left = nn; n->right = nil; n->decl = nil; n->ty = usetype(mktype(&n->src.start, &n->src.stop, Tref, nn->ty, nil)); } static void fnref(Node *n, Decl *id) { id->caninline = -1; ckmod(n, id); addref(n); while(id->link != nil) id = id->link; if(ispoly(id) && encpolys(id) != nil) nerror(n, "cannot have a polymorphic adt function reference %s", id->sym->name); } Decl* typecheck(int checkimp) { Decl *entry, *m, *d; Sym *s; int i; if(errors) return nil; /* * generate the set of all functions * compile one function at a time */ gdecl(tree); gbind(tree); fns = allocmem(nfns * sizeof(Decl)); i = gcheck(tree, fns, 0); if(i != nfns) fatal("wrong number of functions found in gcheck"); maxlabdep = 0; for(i = 0; i < nfns; i++){ d = fns[i]; if(d != nil) fndec = d; if(d != nil) fncheck(d); fndec = nil; } if(errors) return nil; entry = nil; if(checkimp){ Decl *im; Dlist *dm; if(impmods == nil){ yyerror("no implementation module"); return nil; } for(im = impmods; im != nil; im = im->next){ for(dm = impdecls; dm != nil; dm = dm->next) if(dm->d->sym == im->sym) break; if(dm == nil || dm->d->ty == nil){ yyerror("no definition for implementation module %s", im->sym->name); return nil; } } /* * can't check the module spec until all types and imports are determined, * which happens in scheck */ for(dm = impdecls; dm != nil; dm = dm->next){ im = dm->d; im->refs++; im->ty = usetype(im->ty); if(im->store != Dtype || im->ty->kind != Tmodule){ error(im->src.start, "cannot implement %K", im); return nil; } } /* now check any multiple implementations */ impdecl = modimp(impdecls, impmods); s = enter("init", 0); entry = nil; for(dm = impdecls; dm != nil; dm = dm->next){ im = dm->d; for(m = im->ty->ids; m != nil; m = m->next){ m->ty = usetype(m->ty); m->refs++; if(m->sym == s && m->ty->kind == Tfn && entry == nil) entry = m; if(m->store == Dglobal || m->store == Dfn) modrefable(m->ty); if(m->store == Dtype && m->ty->kind == Tadt){ for(d = m->ty->ids; d != nil; d = d->next){ d->ty = usetype(d->ty); modrefable(d->ty); d->refs++; } } } checkrefs(im->ty->ids); } } if(errors) return nil; gsort(tree); tree = nil; return entry; } /* * introduce all global declarations * also adds all fields to adts and modules * note the complications due to nested Odas expressions */ void gdecl(Node *n) { for(;;){ if(n == nil) return; if(n->op != Oseq) break; gdecl(n->left); n = n->right; } switch(n->op){ case Oimport: importdecled(n); gdasdecl(n->right); break; case Oadtdecl: adtdecled(n); break; case Ocondecl: condecled(n); gdasdecl(n->right); break; case Oexdecl: exdecled(n); break; case Omoddecl: moddecled(n); break; case Otypedecl: typedecled(n); break; case Ovardecl: vardecled(n); break; case Ovardecli: vardecled(n->left); gdasdecl(n->right); break; case Ofunc: fndecled(n); break; case Oas: case Odas: case Onothing: gdasdecl(n); break; default: fatal("can't deal with %O in gdecl", n->op); } } /* * bind all global type ids, * including those nested inside modules * this needs to be done, since we may use such * a type later in a nested scope, so if we bound * the type ids then, the type could get bound * to a nested declaration */ void gbind(Node *n) { Decl *d, *ids; for(;;){ if(n == nil) return; if(n->op != Oseq) break; gbind(n->left); n = n->right; } switch(n->op){ case Oas: case Ocondecl: case Odas: case Oexdecl: case Ofunc: case Oimport: case Onothing: case Ovardecl: case Ovardecli: break; case Ofielddecl: bindtypes(n->decl->ty); break; case Otypedecl: bindtypes(n->decl->ty); if(n->left != nil) gbind(n->left); break; case Opickdecl: gbind(n->left); d = n->right->left->decl; bindtypes(d->ty); repushids(d->ty->ids); gbind(n->right->right); /* get new ids for undefined types; propagate outwards */ ids = popids(d->ty->ids); if(ids != nil) installids(Dundef, ids); break; case Oadtdecl: case Omoddecl: bindtypes(n->ty); if(n->ty->polys != nil) repushids(n->ty->polys); repushids(n->ty->ids); gbind(n->left); /* get new ids for undefined types; propagate outwards */ ids = popids(n->ty->ids); if(ids != nil) installids(Dundef, ids); if(n->ty->polys != nil) popids(n->ty->polys); break; default: fatal("can't deal with %O in gbind", n->op); } } /* * check all of the > declarations * bind all type ids referred to within types at the global level * record decls for defined functions */ int gcheck(Node *n, Decl **fns, int nfns) { Ok rok; Decl *d; for(;;){ if(n == nil) return nfns; if(n->op != Oseq) break; nfns = gcheck(n->left, fns, nfns); n = n->right; } switch(n->op){ case Ofielddecl: if(n->decl->ty->u.eraises) raisescheck(n->decl->ty); break; case Onothing: case Opickdecl: break; case Otypedecl: tcycle(n->ty); break; case Oadtdecl: case Omoddecl: if(n->ty->polys != nil) repushids(n->ty->polys); repushids(n->ty->ids); if(gcheck(n->left, nil, 0)) fatal("gcheck fn decls nested in modules or adts"); if(popids(n->ty->ids) != nil) fatal("gcheck installs new ids in a module or adt"); if(n->ty->polys != nil) popids(n->ty->polys); break; case Ovardecl: varcheck(n, 1); break; case Ocondecl: concheck(n, 1); break; case Oexdecl: excheck(n, 1); break; case Oimport: importcheck(n, 1); break; case Ovardecli: varcheck(n->left, 1); rok = echeck(n->right, 0, 1, nil); if(rok.ok){ if(rok.allok) n->right = fold(n->right); globalas(n->right->left, n->right->right, rok.allok); } break; case Oas: case Odas: rok = echeck(n, 0, 1, nil); if(rok.ok){ if(rok.allok) n = fold(n); globalas(n->left, n->right, rok.allok); } break;