@@ 13,6 13,9 @@ enum DataTag
DataAst,
DataByteCode,
DataValueStack,
+ DataCallStack,
+ DataFunction,
+ DataLocalList,
DataMax,
};
@@ 172,6 175,8 @@ enum AstTag
AstLater, /* parse at runtime */
};
+typedef struct ByteCode ByteCode;
+
typedef struct Ast Ast;
struct Ast
{
@@ 206,7 211,6 @@ enum Nameclass
NameclassFunc, /* Function value */
};
-typedef struct ByteCode ByteCode;
struct ByteCode
{
uvlong count;
@@ 221,10 225,13 @@ enum Instr
IStrand,
IMonadic,
IDyadic,
+ ICall,
IClear,
IParse,
IDone,
- IJump,
+ IReturn,
+ IAssign,
+ ILocal,
};
typedef struct ValueStack ValueStack;
@@ 232,4 239,45 @@ struct ValueStack
{
uvlong count;
void **values;
+};
+
+typedef struct Local Local;
+struct Local
+{
+ uvlong id;
+ void *value;
+};
+
+typedef struct LocalList LocalList;
+struct LocalList
+{
+ uvlong count;
+ Local *list;
+};
+
+typedef struct CallFrame CallFrame;
+struct CallFrame
+{
+ /* Values stored when the frame is pushed */
+ ByteCode *code;
+ uvlong offset;
+
+ /* Old values of symbols before they were localised */
+ LocalList *locals;
+};
+
+typedef struct CallStack CallStack;
+struct CallStack
+{
+ uvlong count;
+ CallFrame *frames;
+};
+
+typedef struct Function Function;
+struct Function
+{
+ Ast *ast;
+ uvlong symbol;
+ ByteCode *code;
+ int prim;
};=
\ No newline at end of file
@@ 39,6 39,21 @@ emitptr(ByteCode *c, void *p)
}
static void
+emitlocal(ByteCode *c, Symtab *s, Ast *a, int assign)
+{
+ if(a == nil)
+ return;
+
+ uvlong id = sym(s, a->name);
+ emitbyte(c, ILocal);
+ emituvlong(c, id);
+ if(assign){
+ emitbyte(c, IAssign);
+ emituvlong(c, id);
+ }
+}
+
+static void
codegensub(Session *s, Module *m, ByteCode *c, Ast *a)
{
char *err;
@@ 53,6 68,39 @@ codegensub(Session *s, Module *m, ByteCode *c, Ast *a)
}
emitbyte(c, IDone);
break;
+ case AstFunc:
+ /* Emit bytecode for the function body */
+ {
+ Function *fn = alloc(DataFunction);
+ fn->ast = a;
+ fn->symbol = sym(m->symtab, a->funcname->name);
+ fn->code = alloc(DataByteCode);
+ emitbyte(fn->code, IPushConst);
+ emitptr(fn->code, fn);
+ emitlocal(fn->code, m->symtab, fn->ast->funcname, 1);
+ emitlocal(fn->code, m->symtab, fn->ast->funcresult, 0);
+ emitlocal(fn->code, m->symtab, fn->ast->funcleftarg, 1);
+ emitlocal(fn->code, m->symtab, fn->ast->funcrightarg, 1);
+ for(i = 0; i < fn->ast->funclocals->childcount; i++)
+ emitlocal(fn->code, m->symtab, fn->ast->funclocals->children[i], 0);
+ for(i = 0; i < a->childcount; i++){
+ if(i != 0)
+ emitbyte(fn->code, IClear);
+ codegensub(s, m, fn->code, a->children[i]);
+ }
+ emitbyte(fn->code, IReturn);
+
+ emitbyte(c, IPushConst);
+ emitptr(c, fn);
+
+ /* push the value twice so defining a function yields a function value.. */
+ emitbyte(c, IPushConst);
+ emitptr(c, fn);
+
+ emitbyte(c, IAssign);
+ emituvlong(c, fn->symbol);
+ }
+ break;
case AstName:
emitbyte(c, ILookup);
emituvlong(c, sym(m->symtab, a->name));
@@ 71,13 119,19 @@ codegensub(Session *s, Module *m, ByteCode *c, Ast *a)
case AstMonadic:
codegensub(s, m, c, a->right);
codegensub(s, m, c, a->func);
- emitbyte(c, IMonadic);
+ if(a->func->tag == AstPrim)
+ emitbyte(c, IMonadic);
+ else
+ emitbyte(c, ICall);
break;
case AstDyadic:
codegensub(s, m, c, a->right);
codegensub(s, m, c, a->left);
codegensub(s, m, c, a->func);
- emitbyte(c, IDyadic);
+ if(a->func->tag == AstPrim)
+ emitbyte(c, IDyadic);
+ else
+ emitbyte(c, ICall);
break;
case AstPrim:
emitbyte(c, IPushPrim);
@@ 107,7 161,7 @@ codegen(Session *s, Module *m, Ast *a)
static void
pushval(ValueStack *s, void *v)
{
- s->count += 1;
+ s->count++;
s->values = allocextra(s, s->count * sizeof(v));
s->values[s->count-1] = v;
}
@@ 121,15 175,57 @@ popval(ValueStack *s)
return s->values[s->count];
}
+static void
+pushcall(CallStack *s, ByteCode *c, uvlong o)
+{
+ s->count++;
+ s->frames = allocextra(s, s->count * sizeof(CallFrame));
+ s->frames[s->count-1].code = c;
+ s->frames[s->count-1].offset = o;
+ s->frames[s->count-1].locals = alloc(DataLocalList);
+}
+
+static void
+popcall(CallStack *s, Symtab *t, ByteCode **c, uvlong *o)
+{
+ if(s->count == 0)
+ sysfatal("popcall on empty call stack");
+ s->count--; /* no realloc */
+ *c = s->frames[s->count].code;
+ *o = s->frames[s->count].offset;
+
+ LocalList *locals = s->frames[s->count].locals;
+ for(uvlong i = 0; i < locals->count; i++)
+ symset(t, locals->list[i].id, locals->list[i].value);
+}
+
+static void
+pushlocal(CallStack *c, Symtab *s, uvlong id)
+{
+ CallFrame f = c->frames[s->count-1];
+
+ f.locals->count++;
+ f.locals->list = allocextra(f.locals, sizeof(Local) * f.locals->count);
+ f.locals->list[f.locals->count-1].id = id;
+ f.locals->list[f.locals->count-1].value = symval(s, id);
+
+ symset(s, id, nil);
+}
+
static void *
evalbc(Session *s, Module *m, ByteCode *c)
{
ValueStack *values;
+ CallStack *calls;
+
+ ByteCode *newcode;
uvlong o, v;
- int prim = 0;
+ Function *func;
void *r;
values = alloc(DataValueStack);
+ calls = alloc(DataCallStack);
+
debugbc(c);
o = 0;
@@ 144,7 240,11 @@ evalbc(Session *s, Module *m, ByteCode *c)
break;
case IPushPrim:
o += getuvlong(c->instrs+o, &v);
- prim = v;
+ {
+ Function *f = alloc(DataFunction);
+ f->prim = v;
+ pushval(values, f);
+ }
break;
case ILookup:
o += getuvlong(c->instrs+o, &v);
@@ 165,11 265,20 @@ evalbc(Session *s, Module *m, ByteCode *c)
appendlog(s, "NOTE: monadic call acts like ⊢\n");
break;
case IDyadic:
- USED(prim);
- appendlog(s, "NOTE: dyadic call acts like ⊣\n");
+ appendlog(s, "NOTE: dyadic call acts like ⊢\n");
popval(values);
break;
- case IClear:
+ case ICall:
+ func = popval(values);
+ newcode = func->code;
+call:
+ pushcall(calls, c, o);
+ c = newcode;
+ o = 0;
+ print("CALLED:\n");
+ debugbc(c);
+ break;
+ case IClear: /* TODO: get rid of this instruction. It shouldn't be there, and it is wrong */
while(values->count > 0)
popval(values);
break;
@@ 186,24 295,28 @@ evalbc(Session *s, Module *m, ByteCode *c)
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);
+ newcode = alloc(DataByteCode);
+ codegensub(s, m, newcode, a);
+ emitbyte(newcode, IReturn);
+ goto call;
}
}
break;
case IDone:
goto done;
break;
- case IJump:
- getuvlong(c->instrs+o, &v);
- o = v;
+ case IReturn:
+ popcall(calls, m->symtab, &c, &o);
+ print("RETURNED TO (%ulld)\n", o);
+ debugbc(c);
+ break;
+ case IAssign:
+ o += getuvlong(c->instrs+o, &v);
+ symset(m->symtab, v, popval(values));
+ break;
+ case ILocal:
+ o += getuvlong(c->instrs+o, &v);
+ pushlocal(calls, m->symtab, v);
break;
default:
appendlog(s, "unknown instruction in evalbc\n");
@@ 213,6 326,8 @@ evalbc(Session *s, Module *m, ByteCode *c)
done:
r = nil;
+ print("Final value stack size: %ulld\n", values->count);
+ print("Final call stack size: %ulld\n", calls->count);
if(values->count != 0)
r = popval(values);
return r;