#include #include #include #include #include "paper.h" #include "impl.h" struct Rplace { Rplace* prev; jmp_buf rlab; Node* val; Lsym* local; Lsym** tail; }; static Rplace* ret; static Rplace* looplab; void pperror(char *fmt, ...) { char buf[2048]; va_list arg; ret = 0; va_start(arg, fmt); vseprint(buf, buf+sizeof(buf), fmt, arg); va_end(arg); werrstr("%L: (error) (fn:%s) %s", curfn == nil ? "no function" : curfn->name, buf); /* TODO: stack traces */ while(popio()) ; //fprint(2, "from %L\n"); longjmp(err, 1); } void unwind(void) { int i; Lsym *s; Value *v; for(i = 0; i < Hashsize; i++) { for(s = hash[i]; s; s = s->hash) { while(s->v->pop) { v = s->v->pop; free(s->v); s->v = v; } } } } void execrec(Node *n) { Value *v; Lsym *s; /* make node a root so it isn't collected! */ s = mkvar("_thiscmd"); v = gmalloc(sizeof(Value)); memset(v, 0, sizeof(Value)); v->store.type = TCODE; v->store.cc = n; v->pop = s->v; s->v = v; s->proc = n; gc(0); execute(n); s->proc = s->v->store.cc; s->v = v->pop; free(v); } int ppcall(char *fun, Node *args, Node *res) { Node name, func, xx; Lsym *sym; memset(&name, 0, sizeof(name)); memset(&func, 0, sizeof(func)); memset(&xx, 0, sizeof(xx)); if(res == nil) res = &xx; res->op = OCONST; /* Default return value */ res->store.type = TLIST; res->store.l = nil; if(setjmp(err)) { unwind(); return -1; } sym = look(fun); if(sym == nil) pperror("no function named %s", fun); name.op = ONAME; name.sym = sym; func.op = OCALL; func.left = &name; func.right = args; ppexpr(&func, res); /* Lsym *s; s = mkvar("_result"); s->v->set = 1; s->v->store = res->store; s->v->store.type = res->store.type; */ return 0; } enum { CONTINUE = 1, BREAK = 2, }; void execute(Node *n) { int rv; Value *v; Lsym *sl; Node *l, *r; vlong i, s, e; Node res, *tmp; Rplace loop; if(n == nil) return; l = n->left; r = n->right; switch(n->op) { default: ppexpr(n, &res); /* confusing */ /* if(ret || (res.store.type == TLIST && res.store.l == 0 && n->op != OADD)) break; prnt(&res); */ break; case OASGN: case OCALL: ppexpr(n, &res); break; case OLOCAL: for(n = n->left; n; n = n->left) { if(ret == nil) pperror("local not in function"); sl = n->sym; if(sl->v->ret == ret) pperror("%s declared twice", sl->name); v = gmalloc(sizeof(Value)); v->ret = ret; v->pop = sl->v; sl->v = v; v->scope = 0; *(ret->tail) = sl; ret->tail = &v->scope; v->set = 0; } break; case ORET: if(ret == 0) pperror("return not in function"); ppexpr(n->left, ret->val); longjmp(ret->rlab, 1); case OLIST: execute(n->left); execute(n->right); break; case OIF: ppexpr(l, &res); if(r && r->op == OELSE) { if(bool(&res)) execute(r->left); else execute(r->right); } else if(bool(&res)) execute(r); break; case OWHILE: loop.prev = looplab; looplab = &loop; for(;;) { ppexpr(l, &res); if(!bool(&res)) break; rv = setjmp(loop.rlab); if(rv == BREAK) break; else if(rv == CONTINUE) continue; execute(r); } looplab = loop.prev; break; case OFOR: ; // stupid c Node *init, *cond, *post; init = l->left; cond = l->right->left; post = l->right->right; loop.prev = looplab; looplab = &loop; for(init == nil ? (void)0 : ppexpr(init, &res); cond == nil ? 1 : (ppexpr(cond, &res), bool(&res)); post == nil ? (void)0 : ppexpr(post, &res)){ rv = setjmp(loop.rlab); if(rv == BREAK) break; else if(rv == CONTINUE) continue; execute(r); } looplab = loop.prev; break; case OBREAK: if(looplab == nil) pperror("break not in loop"); longjmp(looplab->rlab, BREAK); case OCONTINUE: if(looplab == nil) pperror("continue not in loop"); longjmp(looplab->rlab, CONTINUE); } } int bool(Node *n) { int true = 0; assert(n->op == OCONST); switch(n->store.type) { case TINT: if(n->store.ival != 0) true = 1; break; case TFLOAT: if(n->store.fval != 0.0) true = 1; break; case TSTRING: if(n->store.string->len) true = 1; break; case TLIST: if(n->store.l) true = 1; break; } return true; } void call(char *fn, Node *parameters, Node *local, Node *body, Node *retexp) { int np, na, i; Rplace rlab; Node *n, res; Value *v, *f; Lsym *s, *next; Node *avp[Maxarg], *ava[Maxarg]; rlab.local = 0; na = 0; flatten(avp, parameters, &na); np = na; na = 0; flatten(ava, local, &na); if(np != na) { if(np < na) pperror("%s: too few arguments", fn); pperror("%s: too many arguments", fn); } rlab.prev = ret; rlab.tail = &rlab.local; ret = &rlab; for(i = 0; i < np; i++) { n = ava[i]; switch(n->op) { default: pperror("%s: %d formal not a name", fn, i); case ONAME: ppexpr(avp[i], &res); s = n->sym; break; case OINDM: res.store.cc = avp[i]; res.store.type = TCODE; if(n->left->op != ONAME) pperror("%s: %d formal not a name", fn, i); s = n->left->sym; break; } if(s->v->ret == ret) pperror("%s already declared at this scope", s->name); v = gmalloc(sizeof(Value)); v->ret = ret; v->pop = s->v; s->v = v; v->scope = 0; *(rlab.tail) = s; rlab.tail = &v->scope; v->store = res.store; v->store.type = res.store.type; v->set = 1; } ret->val = retexp; switch(setjmp(rlab.rlab)){ case 0: execute(body); break; case 1: /* normal return */ break; case 2: /* error */ break; } for(s = rlab.local; s; s = next) { f = s->v; next = f->scope; s->v = f->pop; free(f); } ret = rlab.prev; } typedef struct Syncheck Syncheck; struct Syncheck { int breakok; }; static void _syncheck(Node *n, Syncheck *check) { Node *l, *r; if(n == nil) return; l = n->left; r = n->right; switch(n->op){ case OFOR: check->breakok = 1; break; case OBREAK: if(!check->breakok) pperror("saw break outside of for"); break; case OCONTINUE: if(!check->breakok) pperror("saw continue outside of for"); break; } _syncheck(l, check); _syncheck(r, check); } void syncheck(Node *n) { Syncheck syn; syn.breakok = 0; _syncheck(n, &syn); }