picrin/src/vm.c

225 lines
4.7 KiB
C
Raw Normal View History

2013-10-11 11:16:19 -04:00
#include <stdlib.h>
2013-10-12 05:48:35 -04:00
#include <stdio.h>
2013-10-11 11:16:19 -04:00
#include "picrin.h"
2013-10-13 06:00:39 -04:00
#include "picrin/irep.h"
2013-10-11 11:16:19 -04:00
2013-10-12 01:40:55 -04:00
static pic_value
pic_assq(pic_state *pic, pic_value key, pic_value assoc)
{
pic_value cell;
enter:
if (pic_nil_p(assoc))
return assoc;
cell = pic_car(pic, assoc);
if (pic_eq_p(pic, key, pic_car(pic, cell)))
return cell;
assoc = pic_cdr(pic, assoc);
goto enter;
}
static struct pic_pair *
pic_env_lookup(pic_state *pic, pic_value sym, struct pic_env *env)
{
pic_value v;
enter:
v = pic_assq(pic, sym, env->assoc);
if (! pic_nil_p(v)) {
return pic_pair_ptr(v);
}
if (env->parent) {
env = env->parent;
goto enter;
}
return NULL;
}
static struct pic_pair *
pic_env_define(pic_state *pic, pic_value sym, struct pic_env *env)
{
pic_value cell;
cell = pic_cons(pic, sym, pic_undef_value());
env->assoc = pic_cons(pic, cell, env->assoc);
return pic_pair_ptr(cell);
}
2013-10-12 00:06:02 -04:00
static void
2013-10-11 23:53:54 -04:00
pic_gen(pic_state *pic, struct pic_irep *irep, pic_value obj, struct pic_env *env)
{
2013-10-12 01:40:55 -04:00
pic_value sDEFINE, sCONS, sADD;
2013-10-11 23:53:54 -04:00
sDEFINE = pic->sDEFINE;
sCONS = pic->sCONS;
sADD = pic->sADD;
2013-10-11 23:53:54 -04:00
switch (pic_type(obj)) {
case PIC_TT_SYMBOL: {
2013-10-12 01:40:55 -04:00
struct pic_pair *gvar;
gvar = pic_env_lookup(pic, obj, env);
if (! gvar) {
pic_raise(pic, "unbound variable");
}
irep->code[irep->clen].insn = OP_GREF;
irep->code[irep->clen].u.gvar = gvar;
irep->clen++;
2013-10-11 23:53:54 -04:00
break;
}
case PIC_TT_PAIR: {
pic_value proc;
proc = pic_car(pic, obj);
2013-10-12 01:40:55 -04:00
if (pic_eq_p(pic, proc, sDEFINE)) {
struct pic_pair *gvar;
pic_gen(pic, irep, pic_car(pic, pic_cdr(pic, pic_cdr(pic, obj))), env);
gvar = pic_env_define(pic, pic_car(pic, pic_cdr(pic, obj)), env);
irep->code[irep->clen].insn = OP_GSET;
irep->code[irep->clen].u.gvar = gvar;
irep->clen++;
irep->code[irep->clen].insn = OP_PUSHUNDEF;
irep->clen++;
break;
}
else if (pic_eq_p(pic, proc, sCONS)) {
2013-10-11 23:53:54 -04:00
/* generate args in reverse order*/
pic_gen(pic, irep, pic_car(pic, pic_cdr(pic, pic_cdr(pic, obj))), env);
pic_gen(pic, irep, pic_car(pic, pic_cdr(pic, obj)), env);
irep->code[irep->clen].insn = OP_CONS;
irep->clen++;
break;
}
else if (pic_eq_p(pic, proc, sADD)) {
/* generate args in reverse order*/
pic_gen(pic, irep, pic_car(pic, pic_cdr(pic, pic_cdr(pic, obj))), env);
pic_gen(pic, irep, pic_car(pic, pic_cdr(pic, obj)), env);
irep->code[irep->clen].insn = OP_ADD;
irep->clen++;
break;
}
else {
/* not implemented */
break;
}
}
case PIC_TT_INT: {
irep->code[irep->clen].insn = OP_PUSHI;
irep->code[irep->clen].u.i = pic_int(obj);
irep->clen++;
break;
}
case PIC_TT_NIL: {
irep->code[irep->clen].insn = OP_PUSHNIL;
irep->clen++;
break;
}
2013-10-12 05:48:35 -04:00
case PIC_TT_UNDEF: {
irep->code[irep->clen].insn = OP_PUSHUNDEF;
irep->clen++;
break;
}
2013-10-11 23:53:54 -04:00
}
}
struct pic_proc *
pic_codegen(pic_state *pic, pic_value obj, struct pic_env *env)
{
struct pic_proc *proc;
struct pic_irep *irep;
struct pic_code *code;
2013-10-13 03:55:07 -04:00
proc = (struct pic_proc *)pic_obj_alloc(pic, sizeof(struct pic_proc), PIC_TT_PROC);
2013-10-11 23:53:54 -04:00
proc->u.irep = irep = (struct pic_irep *)pic_alloc(pic, sizeof(struct pic_irep));
irep->code = code = (struct pic_code *)pic_alloc(pic, sizeof(struct pic_code) * 1024);
2013-10-11 23:53:54 -04:00
irep->clen = 0;
irep->ccapa = 1024;
pic_gen(pic, irep, obj, env);
irep->code[irep->clen].insn = OP_STOP;
irep->clen++;
return proc;
}
2013-10-12 00:06:02 -04:00
2013-10-12 05:48:35 -04:00
#define VM_LOOP for (;;) { switch (pc->insn) {
#define CASE(x) case x:
#define NEXT pc++; break
#define JUMP break
#define VM_LOOP_END } }
#define PUSH(v) (*++sp = (v))
#define POP() (*sp--)
2013-10-12 00:06:02 -04:00
pic_value
pic_run(pic_state *pic, struct pic_proc *proc, pic_value args)
{
struct pic_code *pc;
pic_value *sp;
2013-10-13 04:29:21 -04:00
int ai = pic_gc_arena_preserve(pic);
2013-10-12 00:06:02 -04:00
pc = proc->u.irep->code;
sp = pic->sp;
2013-10-12 05:48:35 -04:00
VM_LOOP {
CASE(OP_PUSHNIL) {
PUSH(pic_nil_value());
2013-10-12 05:48:35 -04:00
NEXT;
2013-10-12 00:06:02 -04:00
}
2013-10-12 05:48:35 -04:00
CASE(OP_PUSHI) {
PUSH(pic_int_value(pc->u.i));
2013-10-12 05:48:35 -04:00
NEXT;
2013-10-12 00:06:02 -04:00
}
2013-10-12 05:48:35 -04:00
CASE(OP_PUSHUNDEF) {
PUSH(pic_undef_value());
2013-10-12 05:48:35 -04:00
NEXT;
2013-10-12 01:40:01 -04:00
}
2013-10-12 05:48:35 -04:00
CASE(OP_GREF) {
PUSH(pc->u.gvar->cdr);
2013-10-12 05:48:35 -04:00
NEXT;
2013-10-12 01:40:55 -04:00
}
2013-10-12 05:48:35 -04:00
CASE(OP_GSET) {
pc->u.gvar->cdr = POP();
2013-10-12 05:48:35 -04:00
NEXT;
2013-10-12 01:40:55 -04:00
}
2013-10-12 05:48:35 -04:00
CASE(OP_CONS) {
2013-10-12 00:06:02 -04:00
pic_value a, b;
2013-10-13 04:29:21 -04:00
pic_gc_protect(pic, a = POP());
pic_gc_protect(pic, b = POP());
PUSH(pic_cons(pic, a, b));
2013-10-13 04:29:21 -04:00
pic_gc_arena_restore(pic, ai);
2013-10-12 05:48:35 -04:00
NEXT;
2013-10-12 00:06:02 -04:00
}
2013-10-12 05:48:35 -04:00
CASE(OP_ADD) {
2013-10-12 00:06:02 -04:00
pic_value a, b;
a = POP();
b = POP();
PUSH(pic_int_value(pic_int(a) + pic_int(b)));
2013-10-12 05:48:35 -04:00
NEXT;
2013-10-12 00:06:02 -04:00
}
2013-10-12 05:48:35 -04:00
CASE(OP_STOP) {
2013-10-12 00:06:02 -04:00
goto STOP;
}
2013-10-12 05:48:35 -04:00
} VM_LOOP_END;
2013-10-12 00:06:02 -04:00
STOP:
return POP();
2013-10-12 00:06:02 -04:00
}
2013-10-12 01:40:27 -04:00
void
pic_raise(pic_state *pic, const char *str)
{
puts(str);
abort();
}