468 lines
7.5 KiB
C
468 lines
7.5 KiB
C
#include "yo.h"
|
|
|
|
void assertexpr(Node *n);
|
|
|
|
Decl *fndecls;
|
|
Node **labstk;
|
|
int loopdep;
|
|
int maxloopdep;
|
|
|
|
static void
|
|
pushloop(void)
|
|
{
|
|
if(loopdep >= maxloopdep)
|
|
maxloopdep += MaxScope;
|
|
loopdep += 1;
|
|
}
|
|
|
|
static Type*
|
|
typeofslice(Type *t)
|
|
{
|
|
Type *p = t;
|
|
while(p && p->kind == Tslice)
|
|
p = p->tof;
|
|
assert(p && p->kind == Tarray);
|
|
return p;
|
|
}
|
|
|
|
void
|
|
elemfields(Node *n)
|
|
{
|
|
Decl *d = nil;
|
|
Type *t = n->ty;
|
|
Node *e = nil;
|
|
|
|
switch(t->kind){
|
|
case Tstruct:
|
|
d = t->ids;
|
|
for(e = n->l; e != nil; e = e->r){
|
|
e->l->ty = d->ty;
|
|
assertexpr(e->l);
|
|
d = d->next;
|
|
}
|
|
break;
|
|
case Tarray:
|
|
for(e = n->l; e != nil; e = e->r){
|
|
e->l->ty = t->tof;
|
|
assertexpr(e->l);
|
|
}
|
|
break;
|
|
default:
|
|
assert(0);
|
|
}
|
|
}
|
|
|
|
Decl*
|
|
tupfields(Node *n)
|
|
{
|
|
Decl *h = nil;
|
|
Decl *d = h;
|
|
Decl **last = &h;
|
|
for(; n; n=n->r){
|
|
d = mkdecl(Dfield, n->l->ty);
|
|
*last = d;
|
|
last = &d->next;
|
|
}
|
|
return h;
|
|
}
|
|
|
|
void
|
|
dasinfer(Node *n, Type *t)
|
|
{
|
|
switch(n->op){
|
|
case Otup:
|
|
n->ty = t;
|
|
n = n->l;
|
|
Decl *p = t->ids;
|
|
for(; p&&n; p=p->next){
|
|
if(p->store != Dfield)
|
|
continue;
|
|
dasinfer(n->l, p->ty);
|
|
n = n->r;
|
|
}
|
|
for(;p; p=p->next){
|
|
if(p->store == Dfield)
|
|
break;
|
|
}
|
|
assert(n==nil && p==nil);
|
|
return;
|
|
case Oname:
|
|
n->decl->ty = t;
|
|
n->ty = t;
|
|
sharelocal(n->decl);
|
|
return;
|
|
default:
|
|
assert(0);
|
|
}
|
|
}
|
|
|
|
void
|
|
assertexpr(Node *n)
|
|
{
|
|
if(n == nil)
|
|
return;
|
|
if(n->op == Oseq){
|
|
for(; n && n->op==Oseq; n=n->r){
|
|
assertexpr(n->l);
|
|
n->ty = tnone;
|
|
}
|
|
if(n == nil)
|
|
return;
|
|
}
|
|
|
|
Type *t = nil;
|
|
Decl *d = nil;
|
|
Node * l = n->l, *r = n->r;
|
|
if(n->op != Odas)
|
|
assertexpr(l);
|
|
if(n->op != Ocall &&n->op != Odas && n->op != Odot && n->op != Oindex && n->op != Oindex)
|
|
assertexpr(r);
|
|
switch(n->op){
|
|
case Opkg: break;
|
|
case Oseq: n->ty = tnone; break;
|
|
case Ostruct:
|
|
case Oarray:
|
|
n->ty = isvalidty(n->ty);
|
|
break;
|
|
case Ooror: case Oandand:
|
|
assert(l->ty == tbool);
|
|
assert(r->ty == tbool);
|
|
case Oeq: case Oneq: case Olt:
|
|
case Oleq: case Ogt: case Ogeq:
|
|
n->ty = tbool;
|
|
break;
|
|
case Oconst:
|
|
assert(n->ty != nil);
|
|
break;
|
|
case Omul: case Oadd: case Osub:
|
|
/* TODO : match type or can addable */
|
|
assertexpr(l);
|
|
assertexpr(r);
|
|
assert(eqtype(l->ty, r->ty));
|
|
n->ty = l->ty;
|
|
break;
|
|
case Olen:
|
|
l->ty = isvalidty(l->ty);
|
|
assert(l->ty->kind==Tarray||l->ty->kind==Tslice);
|
|
n->ty = tint;
|
|
break;
|
|
case Oas:
|
|
if(r->op == Oname)
|
|
assert(r->decl->store != Dtype);
|
|
assert(eqtype(l->ty, r->ty));
|
|
n->ty = l->ty = r->ty;
|
|
break;
|
|
case Odas:
|
|
assertexpr(r);
|
|
dasdecl(l);
|
|
dasinfer(l, r->ty);
|
|
assert(eqtype(l->ty, r->ty));
|
|
n->ty = l->ty = r->ty;
|
|
usetype(n->ty);
|
|
if(r->op == Oname)
|
|
assert(r->decl->store != Dtype);
|
|
break;
|
|
case Oxref:
|
|
t = l->ty;
|
|
assert(t->kind == Tptr);
|
|
n->ty = usetype(t->tof);
|
|
break;
|
|
case Oref:
|
|
t = l->ty;
|
|
assert(l->op == Oname);
|
|
n->ty = usetype(mktype(Tref, IBY2WD, t, nil));
|
|
break;
|
|
case Odot:
|
|
t = l->ty;
|
|
switch(t->kind){
|
|
case Tpkg:
|
|
assert(r->op == Oname);
|
|
d = isinpkg(t->ids, r->decl->sym);
|
|
assert(d != nil);
|
|
r->decl = d;
|
|
r->ty = n->ty = d->ty;
|
|
break;
|
|
case Tstruct:
|
|
d = isinids(t->ids, r->decl->sym);
|
|
assert(d != nil);
|
|
d->ty = usetype(isvalidty(d->ty));
|
|
r->decl = d;
|
|
n->ty = d->ty;
|
|
break;
|
|
default:
|
|
assert(0);
|
|
}
|
|
break;
|
|
case Oname:
|
|
assert((d = n->decl) != nil);
|
|
if(d->store == Dunbound){
|
|
Sym *s = d->sym;
|
|
assert((d = s->decl) != nil);
|
|
s->unbound = nil;
|
|
n->decl = d;
|
|
}
|
|
assert(n->ty = d->ty = usetype(d->ty));
|
|
switch(d->store){
|
|
case Darg: case Dfn: case Dlocal: case Dfield:
|
|
case Dtype: case Dglobal: case Dpkg:
|
|
break;
|
|
default:
|
|
assert(0);
|
|
}
|
|
break;
|
|
case Oslice:
|
|
t = usetype(l->ty);
|
|
if(t->kind == Tslice)
|
|
t = typeofslice(t);
|
|
assert(t->kind == Tarray);
|
|
n->ty = mktype(Tslice, ArrHead, t, nil);
|
|
break;
|
|
case Oindex:
|
|
t = l->ty;
|
|
if(t->kind == Tslice)
|
|
t = t->tof;
|
|
assert(t->kind == Tarray || t->kind == Tslice);
|
|
assertexpr(r);
|
|
if(r->op == Oconst)
|
|
assert(r->val < t->len);
|
|
n->ty = t->tof;
|
|
break;
|
|
case Otup:
|
|
d = tupfields(l);
|
|
n->ty = usetype(mktype(Ttup, 0, nil, d));
|
|
break;
|
|
case Ocall:
|
|
assertexpr(r);
|
|
t = l->ty;
|
|
if(l->op==Opkg)
|
|
return;
|
|
usetype(t);
|
|
n->ty = t->tof;
|
|
break;
|
|
default:
|
|
assert(0);
|
|
}
|
|
}
|
|
|
|
void
|
|
assertvar(Node *n)
|
|
{
|
|
Type *t = isvalidty(n->ty);
|
|
Decl *last = n->l->decl;
|
|
for(Decl *d = n->decl; d != last->next; d=d->next){
|
|
assert(d->store != Dtype);
|
|
d->ty = t;
|
|
}
|
|
}
|
|
|
|
Node*
|
|
assertstmt(Type *ret, Node *n)
|
|
{
|
|
Decl *d = nil;
|
|
Node *top = n, *last = nil, *l = nil, *r=nil;
|
|
|
|
for(; n; n=n->r){
|
|
l = n->l;
|
|
r = n->r;
|
|
switch(n->op){
|
|
case Oseq:
|
|
n->l = assertstmt(ret, l);
|
|
break;
|
|
case Ovardecl:
|
|
vardecled(n);
|
|
assertvar(n);
|
|
return top;
|
|
case Oret:
|
|
assertexpr(l);
|
|
if(l == nil)
|
|
assert(ret == tnone);
|
|
else if(ret == tnone)
|
|
assert(l->ty == tnone);
|
|
else
|
|
assert(eqtype(ret, l->ty));
|
|
return top;
|
|
case Oif:
|
|
n->l = l = assertstmt(ret, l);
|
|
assert(l->ty == tbool);
|
|
r->l = assertstmt(ret, r->l);
|
|
n = r;
|
|
break;
|
|
case Ofor:
|
|
assertexpr(l);
|
|
assert(l->ty == tbool);
|
|
pushloop();
|
|
r->r = assertstmt(ret, r->r);
|
|
r->l = assertstmt(ret, r->l);
|
|
loopdep -= 1;
|
|
return top;
|
|
case Oscope:
|
|
pushscope(n, Sother);
|
|
assertstmt(ret, n->l);
|
|
n->r = assertstmt(ret, n->r);
|
|
d = popscope();
|
|
fndecls = concatdecl(fndecls,d);
|
|
return top;
|
|
default:
|
|
assertexpr(n);
|
|
if(last == nil)
|
|
return n;
|
|
last->r = n;
|
|
return top;
|
|
}
|
|
last = n;
|
|
}
|
|
return top;
|
|
}
|
|
|
|
Decl*
|
|
assertfndecl(Node* n)
|
|
{
|
|
Decl *d = n->l->decl;
|
|
d->store = Dfn;
|
|
d->init = n;
|
|
Type *t = n->ty;
|
|
t = isvalidty(t);
|
|
n->ty = d->ty = t = usetype(t);
|
|
d->offset = idoffsets(t->ids, 56, IBY2WD);
|
|
d->locals = nil;
|
|
n->decl = d;
|
|
return d;
|
|
}
|
|
|
|
void
|
|
assertfn(Decl *d)
|
|
{
|
|
Node *n = d->init;
|
|
fndecls = nil;
|
|
repushids(d->ty->ids);
|
|
n->r = assertstmt(n->ty->tof, n->r);
|
|
d->locals = concatdecl(popids(d->ty->ids), fndecls);
|
|
fndecls = nil;
|
|
}
|
|
|
|
void
|
|
gdecl(Node *n)
|
|
{
|
|
for(;;n=n->r){
|
|
if(n==nil)
|
|
return;
|
|
if(n->op != Oseq)
|
|
break;
|
|
gdecl(n->l);
|
|
}
|
|
switch(n->op){
|
|
case Oexport:
|
|
gdecl(n->l);
|
|
nexport += 1;
|
|
break;
|
|
case Ovardecl:
|
|
vardecled(n);
|
|
nvar += 1;
|
|
break;
|
|
case Ostrdecl:
|
|
structdecled(n);
|
|
ntype += 1;
|
|
break;
|
|
case Ofn:
|
|
fndecled(n);
|
|
nfn += 1;
|
|
break;
|
|
default:
|
|
assert(0);
|
|
}
|
|
}
|
|
|
|
void
|
|
varassert(Node *n)
|
|
{
|
|
Type *t = isvalidty(n->ty);
|
|
Decl *last = n->l->decl;
|
|
for(Decl *ids = n->decl; ids != last->next; ids=ids->next){
|
|
ids->ty = t;
|
|
}
|
|
}
|
|
|
|
void
|
|
gassert(Node *n)
|
|
{
|
|
for(; ; n=n->r){
|
|
if(n==nil)
|
|
return;
|
|
if(n->op != Oseq)
|
|
break;
|
|
gassert(n->l);
|
|
}
|
|
switch(n->op){
|
|
case Oexport:
|
|
gassert(n->l);
|
|
break;
|
|
case Ostrdecl:
|
|
repushids(n->ty->ids);
|
|
gassert(n->l);
|
|
assert(popids(n->ty->ids) == nil);
|
|
break;
|
|
case Ofn:
|
|
assertexpr(n->l);
|
|
assertfndecl(n);
|
|
break;
|
|
case Ovardecl:
|
|
varassert(n);
|
|
bindsize(n->ty);
|
|
break;
|
|
case Ofielddecl:
|
|
bindsize(n->ty);
|
|
break;
|
|
default:
|
|
assert(0);
|
|
}
|
|
return;
|
|
}
|
|
|
|
void
|
|
gentry(Node *tree)
|
|
{
|
|
static int ivar = 0;
|
|
static int ifn = 0;
|
|
static int iexport = 0;
|
|
static int itype = 0;
|
|
|
|
for(; tree; tree=tree->r){
|
|
assert(tree->op == Oseq);
|
|
Node *n = tree->l;
|
|
Decl *d = nil;
|
|
int exp = 0;
|
|
redo:
|
|
switch(n->op){
|
|
case Oexport:
|
|
n = n->l;
|
|
exp = 1;
|
|
goto redo;
|
|
break;
|
|
case Ostrdecl:
|
|
types[itype++]=d=n->ty->decl;
|
|
break;
|
|
case Ofn:
|
|
fns[ifn++]=d=n->decl;
|
|
break;
|
|
case Ovardecl:
|
|
vars[ivar++]=d=n->decl;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
if(exp)
|
|
exports[iexport++] = d;
|
|
}
|
|
}
|
|
|
|
Sym*
|
|
assertpkgdecl(Node **trees, int n)
|
|
{
|
|
Sym *s = trees[0]->l->decl->sym;
|
|
for(int i = 1; i < n; ++i){
|
|
Sym *ss = trees[i]->l->decl->sym;
|
|
assert(s->len == ss->len);
|
|
assert(memcmp(s->name, ss->name, s->len)==0);
|
|
}
|
|
return s;
|
|
} |