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

static List **tail;

List*
construct(Node *l)
{
       List *lh, **save;

       save = tail;
       lh = 0;
       tail = &lh;
       build(l);
       tail = save;

       return lh;
}

int
listlen(List *l)
{
       int len;

       len = 0;
       while(l) {
               len++;
               l = l->next;
       }
       return len;
}

void
build(Node *n)
{
       List *l;
       Node res;

       if(n == 0)
               return;

       switch(n->op) {
       case OLIST:
               build(n->left);
               build(n->right);
               return;
       default:
               expr(n, &res);
               l = al(res.type);
               l->Store = res.Store;
               *tail = l;
               tail = &l->next;
       }
}

List*
addlist(List *l, List *r)
{
       List *f;

       if(l == 0)
               return r;

       for(f = l; f->next; f = f->next)
               ;
       f->next = r;

       return l;
}

void
append(Node *r, Node *list, Node *val)
{
       List *l, *f;

       l = al(val->type);
       l->Store = val->Store;
       l->next = 0;

       r->op = OCONST;
       r->type = TLIST;

       if(list->l == 0) {
               list->l = l;
               r->l = l;
               return;
       }
       for(f = list->l; f->next; f = f->next)
               ;
       f->next = l;
       r->l = list->l;
}

int
listcmp(List *l, List *r)
{
       if(l == r)
               return 1;

       while(l) {
               if(r == 0)
                       return 0;
               if(l->type != r->type)
                       return 0;
               switch(l->type) {
               case TINT:
                       if(l->ival != r->ival)
                               return 0;
                       break;
               case TFLOAT:
                       if(l->fval != r->fval)
                               return 0;
                       break;
               case TSTRING:
                       if(scmp(l->string, r->string) == 0)
                               return 0;
                       break;
               case TLIST:
                       if(listcmp(l->l, r->l) == 0)
                               return 0;
                       break;
               }
               l = l->next;
               r = r->next;
       }
       if(l != r)
               return 0;
       return 1;
}

void
nthelem(List *l, int n, Node *res)
{
       if(n < 0)
               error("negative index in []");

       while(l && n--)
               l = l->next;

       res->op = OCONST;
       if(l == 0) {
               res->type = TLIST;
               res->l = 0;
               return;
       }
       res->type = l->type;
       res->Store = l->Store;
}

void
delete(List *l, int n, Node *res)
{
       List **tl;

       if(n < 0)
               error("negative index in delete");

       res->op = OCONST;
       res->type = TLIST;
       res->l = l;

       for(tl = &res->l; l && n--; l = l->next)
               tl = &l->next;

       if(l == 0)
               error("element beyond end of list");
       *tl = l->next;
}

List*
listvar(char *s, vlong v)
{
       List *l, *tl;

       tl = al(TLIST);

       l = al(TSTRING);
       tl->l = l;
       l->fmt = 's';
       l->string = strnode(s);
       l->next = al(TINT);
       l = l->next;
       l->fmt = 'A';
       l->ival = v;

       return tl;
}

static List*
listlocals(Map *map, Symbol *fn, uvlong fp)
{
       int i;
       uvlong val;
       Symbol s;
       List **tail, *l2;

       l2 = 0;
       tail = &l2;
       s = *fn;

       for(i = 0; localsym(&s, i); i++) {
               if(s.class != CAUTO)
                       continue;
               if(s.name[0] == '.')
                       continue;

               if(geta(map, fp-s.value, &val) > 0) {
                       *tail = listvar(s.name, val);
                       tail = &(*tail)->next;
               }
       }
       return l2;
}

static List*
listparams(Map *map, Symbol *fn, uvlong fp)
{
       int i;
       Symbol s;
       uvlong v;
       List **tail, *l2;

       l2 = 0;
       tail = &l2;
       fp += mach->szaddr;                     /* skip saved pc */
       s = *fn;
       for(i = 0; localsym(&s, i); i++) {
               if (s.class != CPARAM)
                       continue;

               if(geta(map, fp+s.value, &v) > 0) {
                       *tail = listvar(s.name, v);
                       tail = &(*tail)->next;
               }
       }
       return l2;
}

void
trlist(Map *map, uvlong pc, uvlong sp, Symbol *sym)
{
       List *q, *l;

       static List **tail;

       if (tracelist == 0) {           /* first time */
               tracelist = al(TLIST);
               tail = &tracelist;
       }

       q = al(TLIST);
       *tail = q;
       tail = &q->next;

       l = al(TINT);                   /* Function address */
       q->l = l;
       l->ival = sym->value;
       l->fmt = 'A';

       l->next = al(TINT);             /* called from address */
       l = l->next;
       l->ival = pc;
       l->fmt = 'Y';

       l->next = al(TLIST);            /* make list of params */
       l = l->next;
       l->l = listparams(map, sym, sp);

       l->next = al(TLIST);            /* make list of locals */
       l = l->next;
       l->l = listlocals(map, sym, sp);
}