#include <u.h>
#include <libc.h>
#include <bio.h>
#include <ctype.h>
#include <mach.h>
#define Extern extern
#include "acid.h"

Type*
srch(Type *t, char *s)
{
       Type *f;

       f = 0;
       while(t) {
               if(strcmp(t->tag->name, s) == 0) {
                       if(f == 0 || t->depth < f->depth)
                               f = t;
               }
               t = t->next;
       }
       return f;
}

void
odot(Node *n, Node *r)
{
       char *s;
       Type *t;
       Node res;
       uvlong addr;

       s = n->sym->name;
       if(s == 0)
               fatal("dodot: no tag");

       expr(n->left, &res);
       if(res.comt == 0)
               error("no type specified for (expr).%s", s);

       if(res.type != TINT)
               error("pointer must be integer for (expr).%s", s);

       t = srch(res.comt, s);
       if(t == 0)
               error("no tag for (expr).%s", s);

       /* Propagate types */
       if(t->type)
               r->comt = t->type->lt;

       addr = res.ival+t->offset;
       if(t->fmt == 'a') {
               r->op = OCONST;
               r->fmt = 'a';
               r->type = TINT;
               r->ival = addr;
       }
       else
               indir(cormap, addr, t->fmt, r);

}

static Type **tail;
static Lsym *base;

void
buildtype(Node *m, int d)
{
       Type *t;

       if(m == ZN)
               return;

       switch(m->op) {
       case OLIST:
               buildtype(m->left, d);
               buildtype(m->right, d);
               break;

       case OCTRUCT:
               buildtype(m->left, d+1);
               break;
       default:
               t = malloc(sizeof(Type));
               t->next = 0;
               t->depth = d;
               t->tag = m->sym;
               t->base = base;
               t->offset = m->ival;
               if(m->left) {
                       t->type = m->left->sym;
                       t->fmt = 'a';
               }
               else {
                       t->type = 0;
                       if(m->right)
                               t->type = m->right->sym;
                       t->fmt = m->fmt;
               }

               *tail = t;
               tail = &t->next;
       }
}

void
defcomplex(Node *tn, Node *m)
{
       tail = &tn->sym->lt;
       base = tn->sym;
       buildtype(m, 0);
}

void
decl(Node *n)
{
       Node *l;
       Value *v;
       Frtype *f;
       Lsym *type;

       type = n->sym;
       if(type->lt == 0)
               error("%s is not a complex type", type->name);

       l = n->left;
       if(l->op == ONAME) {
               v = l->sym->v;
               v->comt = type->lt;
               v->fmt = 'a';
               return;
       }

       /*
        * Frame declaration
        */
       for(f = l->sym->local; f; f = f->next) {
               if(f->var == l->left->sym) {
                       f->type = n->sym->lt;
                       return;
               }
       }
       f = malloc(sizeof(Frtype));
       if(f == 0)
               fatal("out of memory");

       f->type = type->lt;

       f->var = l->left->sym;
       f->next = l->sym->local;
       l->sym->local = f;
}