ref: ee1ed56428b090dd694f50b49f4957c4d2e11bc2
dir: /eval.c/
#include <u.h> #include <libc.h> #include <thread.h> #include "dat.h" #include "fns.h" static ByteCode *codegen(Session *, Module *, Ast *); static void *evalbc(Session *, Module *, ByteCode *); void * eval(Session *s, Ast *a) { /* Evaluate some ast in module m in session s. */ Module *m = s->modules->modules[0]; /* TODO: this isn't nice */ ByteCode *code = codegen(s, m, a); return evalbc(s, m, code); } static void emitbyte(ByteCode *c, u8int i) { c->count += 1; c->instrs = allocextra(c, c->count); c->instrs[c->count-1] = i; } static void emituvlong(ByteCode *c, uvlong v) { for(int i = 0; i < sizeof(v); i++) emitbyte(c, (v>>(8*i)) & 0xFF); } static void emitptr(ByteCode *c, void *p) { emituvlong(c, (uvlong)p); } static void codegensub(Session *s, Module *m, ByteCode *c, Ast *a) { char *err; uvlong i; switch(a->tag){ case AstProg: for(i = 0; i < a->childcount; i++){ if(i != 0) emitbyte(c, IClear); codegensub(s, m, c, a->children[i]); } emitbyte(c, IDone); break; case AstName: emitbyte(c, ILookup); emituvlong(c, sym(m->symtab, a->name)); break; case AstConst: emitbyte(c, IPushConst); emitptr(c, a->val); /* TODO: better to have consts array and emit index? */ break; case AstStrand: /* right to left */ for(i = a->childcount; i > 0; i--) codegensub(s, m, c, a->children[i-1]); emitbyte(c, IStrand); emituvlong(c, a->childcount); break; case AstMonadic: codegensub(s, m, c, a->right); codegensub(s, m, c, a->func); emitbyte(c, IMonadic); break; case AstDyadic: codegensub(s, m, c, a->right); codegensub(s, m, c, a->left); codegensub(s, m, c, a->func); emitbyte(c, IDyadic); break; case AstPrim: emitbyte(c, IPushPrim); emituvlong(c, a->prim); /* TODO: waste of space */ break; case AstLater: emitbyte(c, IParse); emitptr(c, a->tokens); break; default: err = smprint("Don't know how to do codegen for ast type %d\n", a->tag); appendlog(s, err); free(err); break; } } static ByteCode * codegen(Session *s, Module *m, Ast *a) { ByteCode *c = alloc(DataByteCode); codegensub(s, m, c, a); return c; } static void pushval(ValueStack *s, void *v) { s->count += 1; s->values = allocextra(s, s->count * sizeof(v)); s->values[s->count-1] = v; } static void * popval(ValueStack *s) { if(s->count == 0) sysfatal("popval on empty value stack"); s->count--; /* no realloc */ return s->values[s->count]; } static void * evalbc(Session *s, Module *m, ByteCode *c) { ValueStack *values; uvlong o, v; int prim = 0; void *r; values = alloc(DataValueStack); debugbc(c); o = 0; while(o < c->count){ int instr = c->instrs[o]; o++; switch(instr){ case IPushConst: o += getuvlong(c->instrs+o, &v); pushval(values, (void*)v); break; case IPushPrim: o += getuvlong(c->instrs+o, &v); prim = v; break; case ILookup: o += getuvlong(c->instrs+o, &v); pushval(values, symval(m->symtab, v)); /* TODO: value error? */ break; case IStrand: o += getuvlong(c->instrs+o, &v); { Array *x = allocarray(TypeArray, 1, v); setshape(x, 0, v); for(uvlong i = 0; i < v; i++) setarray(x, i, popval(values)); x = simplifyarray(x); pushval(values, x); } break; case IMonadic: appendlog(s, "NOTE: monadic call acts like ⊢\n"); break; case IDyadic: USED(prim); appendlog(s, "NOTE: dyadic call acts like ⊣\n"); popval(values); break; case IClear: while(values->count > 0) popval(values); break; case IParse: /* parse at runtime and emit code */ o += getuvlong(c->instrs+o, &v); { char *err; TokenList *t = (TokenList *)v; Ast *a = parse(t, m->symtab, &err); if(!a){ appendlog(s, "RUNTIME PARSE: "); appendlog(s, err); appendlog(s, "\n"); return nil; }else{ uvlong next = o; uvlong start = c->count; codegensub(s, m, c, a); emitbyte(c, IJump); emituvlong(c, next); o = start; /* jump to new code */ /* TODO: this adds code every time the instruction is run */ print("updated bytecode:\n"); debugbc(c); } } break; case IDone: goto done; break; case IJump: getuvlong(c->instrs+o, &v); o = v; break; default: appendlog(s, "unknown instruction in evalbc\n"); return nil; } } done: r = nil; if(values->count != 0) r = popval(values); return r; }