picrin/extlib/benz/vm.c

1031 lines
27 KiB
C
Raw Normal View History

2014-08-25 00:38:09 -04:00
/**
* See Copyright Notice in picrin.h
*/
#include "picrin.h"
2015-07-08 15:40:15 -04:00
#include "picrin/opcode.h"
2014-08-25 00:38:09 -04:00
#define GET_OPERAND(pic,n) ((pic)->ci->fp[(n)])
struct pic_proc *
pic_get_proc(pic_state *pic)
{
pic_value v = GET_OPERAND(pic,0);
if (! pic_proc_p(v)) {
2014-09-16 10:43:15 -04:00
pic_errorf(pic, "fatal error");
2014-08-25 00:38:09 -04:00
}
return pic_proc_ptr(v);
}
/**
2014-09-27 07:46:58 -04:00
* char type desc.
* ---- ---- ----
* o pic_value * object
* i int * int
* I int *, bool * int with exactness
* f double * float
* F double *, bool * float with exactness
2015-08-26 09:21:34 -04:00
* c char * char
2014-09-27 07:46:58 -04:00
* z char ** c string
2015-08-26 09:21:34 -04:00
* s pic_str ** string object
2015-01-20 02:02:28 -05:00
* m pic_sym ** symbol
2014-09-27 07:46:58 -04:00
* v pic_vec ** vector object
* b pic_blob ** bytevector object
* l struct pic_proc ** lambda object
* p struct pic_port ** port object
* d struct pic_dict ** dictionary object
* e struct pic_error ** error object
2014-08-25 00:38:09 -04:00
*
2014-09-27 07:46:58 -04:00
* | optional operator
2015-08-26 06:04:27 -04:00
* * int *, pic_value ** variable length operator
2014-08-25 00:38:09 -04:00
*/
int
pic_get_args(pic_state *pic, const char *format, ...)
{
char c;
2015-08-26 06:04:27 -04:00
int paramc, optc, min;
int i, argc = pic->ci->argc - 1;
2014-08-25 00:38:09 -04:00
va_list ap;
2015-02-03 11:57:39 -05:00
bool rest = false, opt = false;
/* paramc: required args count as scheme proc
optc: optional args count as scheme proc
argc: passed args count as scheme proc
vargc: args count passed to this function
*/
2014-08-25 00:38:09 -04:00
/* check nparams first */
2015-02-03 11:57:39 -05:00
for (paramc = 0, c = *format; c; c = format[++paramc]) {
if (c == '|') {
opt = true;
2014-08-25 00:38:09 -04:00
break;
}
2015-02-03 11:57:39 -05:00
else if (c == '*') {
rest = true;
2014-08-25 00:38:09 -04:00
break;
}
}
2015-02-03 11:57:39 -05:00
for (optc = 0; opt && c; c = format[paramc + opt + ++optc]) {
if (c == '*') {
rest = true;
2014-08-25 00:38:09 -04:00
break;
}
}
2014-08-25 00:38:09 -04:00
/* '|' should be followed by at least 1 char */
assert((opt ? 1 : 0) <= optc);
/* '*' should not be followed by any char */
2015-02-03 11:57:39 -05:00
assert(format[paramc + opt + optc + rest] == '\0');
2015-02-03 11:57:39 -05:00
/* check argc. */
if (argc < paramc || (paramc + optc < argc && ! rest)) {
2015-06-27 06:02:18 -04:00
pic_errorf(pic, "pic_get_args: wrong number of arguments (%d for %s%d)", argc, rest? "at least " : "", paramc);
}
2015-05-27 12:06:44 -04:00
/* start dispatching */
va_start(ap, format);
2015-02-03 12:19:17 -05:00
min = paramc + optc < argc ? paramc + optc : argc;
2015-05-27 12:06:44 -04:00
for (i = 1; i < min + 1; i++) {
2014-08-25 00:38:09 -04:00
2015-02-03 11:57:39 -05:00
c = *format++;
/* skip '|' if exists. This is always safe because of assert and argc check */
2015-02-03 11:57:39 -05:00
c = c == '|' ? *format++ : c;
2014-08-25 00:38:09 -04:00
switch (c) {
case 'o': {
pic_value *p;
p = va_arg(ap, pic_value*);
*p = GET_OPERAND(pic,i);
2014-08-25 00:38:09 -04:00
break;
}
2015-08-26 09:37:40 -04:00
#define NUM_CASE(c1, c2, ctype) \
case c1: case c2: { \
ctype *n; \
bool *e, dummy; \
pic_value v; \
\
n = va_arg(ap, ctype *); \
e = (c == c2 ? va_arg(ap, bool *) : &dummy); \
\
v = GET_OPERAND(pic, i); \
switch (pic_type(v)) { \
case PIC_TT_FLOAT: \
*n = pic_float(v); \
*e = false; \
break; \
case PIC_TT_INT: \
*n = pic_int(v); \
*e = true; \
break; \
default: \
pic_errorf(pic, "pic_get_args: expected float or int, but got ~s", v); \
} \
break; \
2014-08-25 00:38:09 -04:00
}
2015-08-26 09:37:40 -04:00
NUM_CASE('i', 'I', int)
NUM_CASE('f', 'F', double)
#define VAL_CASE(c, type, ctype, conv) \
2015-08-26 09:21:34 -04:00
case c: { \
ctype *ptr; \
pic_value v; \
\
ptr = va_arg(ap, ctype *); \
v = GET_OPERAND(pic, i); \
if (pic_## type ##_p(v)) { \
2015-08-26 09:37:40 -04:00
*ptr = conv; \
2015-08-26 09:21:34 -04:00
} \
else { \
pic_errorf(pic, "pic_get_args: expected " #type ", but got ~s", v); \
} \
break; \
}
2014-08-25 00:38:09 -04:00
2015-08-26 09:37:40 -04:00
VAL_CASE('c', char, char, pic_char(v))
VAL_CASE('z', str, const char *, pic_str_cstr(pic, pic_str_ptr(v)))
#define PTR_CASE(c, type, ctype) \
VAL_CASE(c, type, ctype, pic_## type ##_ptr(v))
2015-08-26 09:21:34 -04:00
PTR_CASE('s', str, pic_str *)
PTR_CASE('m', sym, pic_sym *)
PTR_CASE('v', vec, pic_vec *)
PTR_CASE('b', blob, pic_blob *)
PTR_CASE('l', proc, struct pic_proc *)
PTR_CASE('p', port, struct pic_port *)
PTR_CASE('d', dict, struct pic_dict *)
PTR_CASE('r', record, struct pic_record *)
PTR_CASE('e', error, struct pic_error *)
2014-08-25 00:38:09 -04:00
2015-02-03 12:19:17 -05:00
default:
pic_errorf(pic, "pic_get_args: invalid argument specifier '%c' given", c);
}
}
if (rest) {
2015-08-26 06:04:27 -04:00
int *n;
2015-02-03 11:57:39 -05:00
pic_value **argv;
2015-08-26 06:04:27 -04:00
n = va_arg(ap, int *);
2015-02-03 11:57:39 -05:00
argv = va_arg(ap, pic_value **);
2015-08-26 06:04:27 -04:00
*n = argc - (i - 1);
2015-02-03 12:19:17 -05:00
*argv = &GET_OPERAND(pic, i);
2015-05-27 12:06:44 -04:00
}
2014-08-25 00:38:09 -04:00
va_end(ap);
2015-02-03 11:57:39 -05:00
return argc;
2014-08-25 00:38:09 -04:00
}
2015-08-03 19:40:23 -04:00
struct pic_box *
2015-08-04 20:36:32 -04:00
pic_vm_gref_slot(pic_state *pic, pic_sym *uid) /* TODO: make this static */
2015-07-07 01:42:50 -04:00
{
2015-08-03 19:40:23 -04:00
struct pic_box *box;
2015-07-07 01:42:50 -04:00
2015-08-04 20:36:32 -04:00
if (pic_reg_has(pic, pic->globals, uid)) {
return pic_box_ptr(pic_reg_ref(pic, pic->globals, uid));
2015-07-07 01:42:50 -04:00
}
2015-08-03 19:40:23 -04:00
box = pic_box(pic, pic_invalid_value());
2015-08-04 20:36:32 -04:00
pic_reg_set(pic, pic->globals, uid, pic_obj_value(box));
2015-08-03 19:40:23 -04:00
return box;
2015-07-07 01:42:50 -04:00
}
static pic_value
2015-08-03 19:40:23 -04:00
vm_gref(pic_state *pic, struct pic_box *slot, pic_sym *uid)
2015-07-07 01:42:50 -04:00
{
2015-08-03 19:40:23 -04:00
if (pic_invalid_p(slot->value)) {
2015-08-04 20:03:38 -04:00
if (uid == NULL) {
uid = pic_reg_rev_ref(pic, pic->globals, pic_obj_value(slot));
2015-08-04 20:03:38 -04:00
}
pic_errorf(pic, "uninitialized global variable: %s", pic_symbol_name(pic, uid));
2015-07-07 01:42:50 -04:00
}
2015-08-03 19:40:23 -04:00
return slot->value;
2015-07-07 01:42:50 -04:00
}
static void
2015-08-03 19:40:23 -04:00
vm_gset(struct pic_box *slot, pic_value value)
2015-07-07 01:42:50 -04:00
{
2015-08-03 19:40:23 -04:00
slot->value = value;
2015-07-07 01:42:50 -04:00
}
2014-08-25 00:38:09 -04:00
static void
2015-05-30 09:34:51 -04:00
vm_push_cxt(pic_state *pic)
2014-08-25 00:38:09 -04:00
{
pic_callinfo *ci = pic->ci;
2015-08-26 06:04:27 -04:00
ci->cxt = (struct pic_context *)pic_obj_alloc(pic, sizeof(struct pic_context) + sizeof(pic_value) * ci->regc, PIC_TT_CXT);
2015-05-30 09:34:51 -04:00
ci->cxt->up = ci->up;
ci->cxt->regc = ci->regc;
ci->cxt->regs = ci->regs;
2014-08-25 00:38:09 -04:00
}
static void
vm_tear_off(pic_callinfo *ci)
{
2015-05-30 09:34:51 -04:00
struct pic_context *cxt;
2014-08-25 00:38:09 -04:00
int i;
2015-05-30 09:34:51 -04:00
assert(ci->cxt != NULL);
2014-08-25 00:38:09 -04:00
2015-05-30 09:34:51 -04:00
cxt = ci->cxt;
2014-08-25 00:38:09 -04:00
2015-05-30 09:34:51 -04:00
if (cxt->regs == cxt->storage) {
2014-08-25 00:38:09 -04:00
return; /* is torn off */
}
2015-05-30 09:34:51 -04:00
for (i = 0; i < cxt->regc; ++i) {
cxt->storage[i] = cxt->regs[i];
2014-08-25 00:38:09 -04:00
}
2015-05-30 09:34:51 -04:00
cxt->regs = cxt->storage;
2014-08-25 00:38:09 -04:00
}
void
pic_vm_tear_off(pic_state *pic)
{
pic_callinfo *ci;
for (ci = pic->ci; ci > pic->cibase; ci--) {
2015-05-30 09:34:51 -04:00
if (ci->cxt != NULL) {
2014-08-25 00:38:09 -04:00
vm_tear_off(ci);
}
}
}
#if VM_DEBUG
# define OPCODE_EXEC_HOOK pic_dump_code(c)
#else
# define OPCODE_EXEC_HOOK ((void)0)
#endif
#if PIC_DIRECT_THREADED_VM
# define VM_LOOP JUMP;
# define CASE(x) L_##x: OPCODE_EXEC_HOOK;
# define NEXT pic->ip++; JUMP;
# define JUMP c = *pic->ip; goto *oplabels[c.insn];
# define VM_LOOP_END
#else
# define VM_LOOP for (;;) { c = *pic->ip; switch (c.insn) {
# define CASE(x) case x:
# define NEXT pic->ip++; break
# define JUMP break
# define VM_LOOP_END } }
#endif
2014-09-26 04:36:27 -04:00
#define PUSH(v) (*pic->sp++ = (v))
2014-08-25 00:38:09 -04:00
#define POP() (*--pic->sp)
#define PUSHCI() (++pic->ci)
#define POPCI() (pic->ci--)
2014-09-14 09:59:29 -04:00
#if VM_DEBUG
# define VM_BOOT_PRINT \
do { \
puts("### booting VM... ###"); \
stbase = pic->sp; \
cibase = pic->ci; \
} while (0)
#else
# define VM_BOOT_PRINT
#endif
#if VM_DEBUG
# define VM_END_PRINT \
do { \
puts("**VM END STATE**"); \
printf("stbase\t= %p\nsp\t= %p\n", (void *)stbase, (void *)pic->sp); \
printf("cibase\t= %p\nci\t= %p\n", (void *)cibase, (void *)pic->ci); \
if (stbase < pic->sp - 1) { \
pic_value *sp; \
printf("* stack trace:"); \
for (sp = stbase; pic->sp != sp; ++sp) { \
pic_debug(pic, *sp); \
puts(""); \
} \
} \
if (stbase > pic->sp - 1) { \
puts("*** stack underflow!"); \
} \
} while (0)
#else
# define VM_END_PRINT
#endif
#if VM_DEBUG
# define VM_CALL_PRINT \
do { \
2015-01-26 09:55:28 -05:00
short i; \
2014-09-14 09:59:29 -04:00
puts("\n== calling proc..."); \
printf(" proc = "); \
pic_debug(pic, pic_obj_value(proc)); \
puts(""); \
printf(" argv = ("); \
2015-01-26 09:55:28 -05:00
for (i = 1; i < c.u.i; ++i) { \
2014-09-14 09:59:29 -04:00
if (i > 1) \
printf(" "); \
pic_debug(pic, pic->sp[-c.u.i + i]); \
} \
puts(")"); \
if (! pic_proc_func_p(proc)) { \
2015-05-31 07:19:07 -04:00
printf(" irep = %p\n", proc->u.i.irep); \
2014-09-14 09:59:29 -04:00
printf(" name = %s\n", pic_symbol_name(pic, pic_proc_name(proc))); \
2015-05-31 07:19:07 -04:00
pic_dump_irep(proc->u.i.irep); \
2014-09-14 09:59:29 -04:00
} \
else { \
2015-06-01 18:20:47 -04:00
printf(" cfunc = %p\n", (void *)proc->u.f.func); \
2014-09-14 09:59:29 -04:00
printf(" name = %s\n", pic_symbol_name(pic, pic_proc_name(proc))); \
} \
puts("== end\n"); \
} while (0)
#else
# define VM_CALL_PRINT
#endif
2014-08-25 00:38:09 -04:00
pic_value
pic_apply(pic_state *pic, struct pic_proc *proc, int argc, pic_value *argv)
2014-08-25 00:38:09 -04:00
{
pic_code c;
size_t ai = pic_gc_arena_preserve(pic);
pic_code boot[2];
int i;
2014-08-25 00:38:09 -04:00
#if PIC_DIRECT_THREADED_VM
static const void *oplabels[] = {
2015-06-09 03:34:45 -04:00
&&L_OP_NOP, &&L_OP_POP, &&L_OP_PUSHUNDEF, &&L_OP_PUSHNIL, &&L_OP_PUSHTRUE,
&&L_OP_PUSHFALSE, &&L_OP_PUSHINT, &&L_OP_PUSHCHAR, &&L_OP_PUSHCONST,
2014-08-25 00:38:09 -04:00
&&L_OP_GREF, &&L_OP_GSET, &&L_OP_LREF, &&L_OP_LSET, &&L_OP_CREF, &&L_OP_CSET,
&&L_OP_JMP, &&L_OP_JMPIF, &&L_OP_NOT, &&L_OP_CALL, &&L_OP_TAILCALL, &&L_OP_RET,
&&L_OP_LAMBDA, &&L_OP_CONS, &&L_OP_CAR, &&L_OP_CDR, &&L_OP_NILP,
2015-01-18 23:16:07 -05:00
&&L_OP_SYMBOLP, &&L_OP_PAIRP,
2015-07-03 10:12:28 -04:00
&&L_OP_ADD, &&L_OP_SUB, &&L_OP_MUL, &&L_OP_DIV,
2015-07-06 06:13:00 -04:00
&&L_OP_EQ, &&L_OP_LT, &&L_OP_LE, &&L_OP_GT, &&L_OP_GE, &&L_OP_STOP
2014-08-25 00:38:09 -04:00
};
#endif
2014-09-14 09:59:29 -04:00
#if VM_DEBUG
pic_value *stbase;
pic_callinfo *cibase;
#endif
PUSH(pic_obj_value(proc));
2014-08-25 00:38:09 -04:00
for (i = 0; i < argc; ++i) {
PUSH(argv[i]);
}
2014-08-25 00:38:09 -04:00
VM_BOOT_PRINT;
2014-08-25 00:38:09 -04:00
/* boot! */
boot[0].insn = OP_CALL;
boot[0].u.i = argc + 1;
boot[1].insn = OP_STOP;
pic->ip = boot;
2014-08-25 00:38:09 -04:00
VM_LOOP {
CASE(OP_NOP) {
NEXT;
}
CASE(OP_POP) {
(void)(POP());
2014-08-25 00:38:09 -04:00
NEXT;
}
2015-06-09 03:34:45 -04:00
CASE(OP_PUSHUNDEF) {
PUSH(pic_undef_value());
NEXT;
}
2014-08-25 00:38:09 -04:00
CASE(OP_PUSHNIL) {
PUSH(pic_nil_value());
NEXT;
}
CASE(OP_PUSHTRUE) {
PUSH(pic_true_value());
NEXT;
}
CASE(OP_PUSHFALSE) {
PUSH(pic_false_value());
NEXT;
}
CASE(OP_PUSHINT) {
PUSH(pic_int_value(c.u.i));
NEXT;
}
CASE(OP_PUSHCHAR) {
PUSH(pic_char_value(c.u.c));
NEXT;
}
CASE(OP_PUSHCONST) {
2015-07-04 01:30:46 -04:00
PUSH(pic->ci->irep->pool[c.u.i]);
2014-08-25 00:38:09 -04:00
NEXT;
}
CASE(OP_GREF) {
2015-08-04 20:03:38 -04:00
PUSH(vm_gref(pic, pic_box_ptr(pic->ci->irep->pool[c.u.i]), NULL)); /* FIXME */
2014-08-25 00:38:09 -04:00
NEXT;
}
CASE(OP_GSET) {
2015-08-03 19:40:23 -04:00
vm_gset(pic_box_ptr(pic->ci->irep->pool[c.u.i]), POP());
2015-07-01 16:59:54 -04:00
PUSH(pic_undef_value());
2014-08-25 00:38:09 -04:00
NEXT;
}
CASE(OP_LREF) {
pic_callinfo *ci = pic->ci;
2015-07-29 13:55:37 -04:00
struct pic_irep *irep = ci->irep;
if (ci->cxt != NULL && ci->cxt->regs == ci->cxt->storage) {
if (c.u.i >= irep->argc + irep->localc) {
PUSH(ci->cxt->regs[c.u.i - (ci->regs - ci->fp)]);
NEXT;
}
}
2014-08-25 00:38:09 -04:00
PUSH(pic->ci->fp[c.u.i]);
NEXT;
}
CASE(OP_LSET) {
pic_callinfo *ci = pic->ci;
2015-07-29 13:55:37 -04:00
struct pic_irep *irep = ci->irep;
if (ci->cxt != NULL && ci->cxt->regs == ci->cxt->storage) {
if (c.u.i >= irep->argc + irep->localc) {
ci->cxt->regs[c.u.i - (ci->regs - ci->fp)] = POP();
PUSH(pic_undef_value());
NEXT;
}
}
2014-08-25 00:38:09 -04:00
pic->ci->fp[c.u.i] = POP();
2015-07-01 16:59:54 -04:00
PUSH(pic_undef_value());
2014-08-25 00:38:09 -04:00
NEXT;
}
CASE(OP_CREF) {
int depth = c.u.r.depth;
2015-05-30 09:34:51 -04:00
struct pic_context *cxt;
2014-08-25 00:38:09 -04:00
2015-05-30 09:34:51 -04:00
cxt = pic->ci->up;
2014-08-25 00:38:09 -04:00
while (--depth) {
2015-05-30 09:34:51 -04:00
cxt = cxt->up;
2014-08-25 00:38:09 -04:00
}
2015-05-30 09:34:51 -04:00
PUSH(cxt->regs[c.u.r.idx]);
2014-08-25 00:38:09 -04:00
NEXT;
}
CASE(OP_CSET) {
int depth = c.u.r.depth;
2015-05-30 09:34:51 -04:00
struct pic_context *cxt;
2014-08-25 00:38:09 -04:00
2015-05-30 09:34:51 -04:00
cxt = pic->ci->up;
2014-08-25 00:38:09 -04:00
while (--depth) {
2015-05-30 09:34:51 -04:00
cxt = cxt->up;
2014-08-25 00:38:09 -04:00
}
2015-05-30 09:34:51 -04:00
cxt->regs[c.u.r.idx] = POP();
2015-07-01 16:59:54 -04:00
PUSH(pic_undef_value());
2014-08-25 00:38:09 -04:00
NEXT;
}
CASE(OP_JMP) {
pic->ip += c.u.i;
JUMP;
}
CASE(OP_JMPIF) {
pic_value v;
v = POP();
if (! pic_false_p(v)) {
pic->ip += c.u.i;
JUMP;
}
NEXT;
}
CASE(OP_CALL) {
pic_value x, v;
pic_callinfo *ci;
if (c.u.i == -1) {
pic->sp += pic->ci[1].retc - 1;
c.u.i = pic->ci[1].retc + 1;
}
L_CALL:
x = pic->sp[-c.u.i];
if (! pic_proc_p(x)) {
pic_errorf(pic, "invalid application: ~s", x);
}
proc = pic_proc_ptr(x);
2014-09-14 09:59:29 -04:00
VM_CALL_PRINT;
2014-08-25 00:38:09 -04:00
2014-09-26 04:36:27 -04:00
if (pic->sp >= pic->stend) {
pic_panic(pic, "VM stack overflow");
}
2014-08-25 00:38:09 -04:00
ci = PUSHCI();
ci->argc = c.u.i;
ci->retc = 1;
ci->ip = pic->ip;
ci->fp = pic->sp - c.u.i;
2015-07-04 01:30:46 -04:00
ci->irep = NULL;
2015-05-30 09:34:51 -04:00
ci->cxt = NULL;
2015-07-29 13:55:37 -04:00
if (pic_proc_func_p(proc)) {
2014-08-25 00:38:09 -04:00
/* invoke! */
2015-05-31 07:22:46 -04:00
v = proc->u.f.func(pic);
2014-08-25 00:38:09 -04:00
pic->sp[0] = v;
pic->sp += pic->ci->retc;
pic_gc_arena_restore(pic, ai);
goto L_RET;
}
else {
2015-05-31 07:19:07 -04:00
struct pic_irep *irep = proc->u.i.irep;
2014-08-25 00:38:09 -04:00
int i;
pic_value rest;
2015-07-04 01:30:46 -04:00
ci->irep = irep;
2014-08-25 00:38:09 -04:00
if (ci->argc != irep->argc) {
if (! (irep->varg && ci->argc >= irep->argc)) {
2015-01-26 01:25:40 -05:00
pic_errorf(pic, "wrong number of arguments (%d for %s%d)", ci->argc - 1, (irep->varg ? "at least " : ""), irep->argc - 1);
2014-08-25 00:38:09 -04:00
}
}
/* prepare rest args */
if (irep->varg) {
rest = pic_nil_value();
for (i = 0; i < ci->argc - irep->argc; ++i) {
pic_gc_protect(pic, v = POP());
rest = pic_cons(pic, v, rest);
}
PUSH(rest);
}
/* prepare local variable area */
if (irep->localc > 0) {
int l = irep->localc;
if (irep->varg) {
--l;
}
for (i = 0; i < l; ++i) {
PUSH(pic_undef_value());
}
}
2015-05-30 09:34:51 -04:00
/* prepare cxt */
2015-07-29 13:55:37 -04:00
ci->up = proc->u.i.cxt;
2014-08-25 00:38:09 -04:00
ci->regc = irep->capturec;
ci->regs = ci->fp + irep->argc + irep->localc;
pic->ip = irep->code;
pic_gc_arena_restore(pic, ai);
JUMP;
}
}
CASE(OP_TAILCALL) {
int i, argc;
pic_value *argv;
pic_callinfo *ci;
2015-05-30 09:34:51 -04:00
if (pic->ci->cxt != NULL) {
2014-08-25 00:38:09 -04:00
vm_tear_off(pic->ci);
}
if (c.u.i == -1) {
pic->sp += pic->ci[1].retc - 1;
c.u.i = pic->ci[1].retc + 1;
}
argc = c.u.i;
argv = pic->sp - argc;
for (i = 0; i < argc; ++i) {
pic->ci->fp[i] = argv[i];
}
ci = POPCI();
pic->sp = ci->fp + argc;
pic->ip = ci->ip;
/* c is not changed */
goto L_CALL;
}
CASE(OP_RET) {
int i, retc;
pic_value *retv;
pic_callinfo *ci;
2015-05-30 09:34:51 -04:00
if (pic->ci->cxt != NULL) {
2014-08-25 00:38:09 -04:00
vm_tear_off(pic->ci);
}
2015-07-04 01:02:29 -04:00
assert(pic->ci->retc == 1);
2014-08-25 00:38:09 -04:00
L_RET:
retc = pic->ci->retc;
retv = pic->sp - retc;
if (retc == 0) {
pic->ci->fp[0] = retv[0]; /* copy at least once */
}
for (i = 0; i < retc; ++i) {
pic->ci->fp[i] = retv[i];
}
ci = POPCI();
pic->sp = ci->fp + 1; /* advance only one! */
pic->ip = ci->ip;
NEXT;
}
CASE(OP_LAMBDA) {
2015-05-30 09:34:51 -04:00
if (pic->ci->cxt == NULL) {
vm_push_cxt(pic);
2014-08-25 00:38:09 -04:00
}
2015-07-04 01:30:46 -04:00
proc = pic_make_proc_irep(pic, pic->ci->irep->irep[c.u.i], pic->ci->cxt);
2014-08-25 00:38:09 -04:00
PUSH(pic_obj_value(proc));
pic_gc_arena_restore(pic, ai);
NEXT;
}
2015-07-03 09:09:14 -04:00
#define check_condition(name, n) do { \
2015-08-03 19:40:23 -04:00
if (! pic_eq_p(pic->p##name, pic->c##name->value)) \
goto L_CALL; \
if (c.u.i != n + 1) \
goto L_CALL; \
2015-07-03 10:20:53 -04:00
} while (0)
2014-08-25 00:38:09 -04:00
CASE(OP_CONS) {
pic_value a, b;
check_condition(CONS, 2);
2014-08-25 00:38:09 -04:00
pic_gc_protect(pic, b = POP());
pic_gc_protect(pic, a = POP());
(void)POP();
2014-08-25 00:38:09 -04:00
PUSH(pic_cons(pic, a, b));
pic_gc_arena_restore(pic, ai);
NEXT;
}
CASE(OP_CAR) {
pic_value p;
check_condition(CAR, 1);
2014-08-25 00:38:09 -04:00
p = POP();
(void)POP();
2014-08-25 00:38:09 -04:00
PUSH(pic_car(pic, p));
NEXT;
}
CASE(OP_CDR) {
pic_value p;
check_condition(CDR, 1);
2014-08-25 00:38:09 -04:00
p = POP();
(void)POP();
2014-08-25 00:38:09 -04:00
PUSH(pic_cdr(pic, p));
NEXT;
}
CASE(OP_NILP) {
pic_value p;
check_condition(NILP, 1);
2014-08-25 00:38:09 -04:00
p = POP();
(void)POP();
2014-08-25 00:38:09 -04:00
PUSH(pic_bool_value(pic_nil_p(p)));
NEXT;
}
2015-01-18 23:16:07 -05:00
CASE(OP_SYMBOLP) {
pic_value p;
check_condition(SYMBOLP, 1);
p = POP();
(void)POP();
PUSH(pic_bool_value(pic_sym_p(p)));
NEXT;
}
2015-01-18 23:16:07 -05:00
CASE(OP_PAIRP) {
pic_value p;
check_condition(PAIRP, 1);
p = POP();
(void)POP();
PUSH(pic_bool_value(pic_pair_p(p)));
NEXT;
}
2015-07-03 09:09:14 -04:00
CASE(OP_NOT) {
pic_value v;
check_condition(NOT, 1);
2015-07-03 09:09:14 -04:00
v = pic_false_p(POP()) ? pic_true_value() : pic_false_value();
(void)POP();
PUSH(v);
NEXT;
}
CASE(OP_ADD) {
pic_value a, b;
check_condition(ADD, 2);
b = POP();
a = POP();
(void)POP();
PUSH(pic_add(pic, a, b));
NEXT;
2014-08-25 00:38:09 -04:00
}
CASE(OP_SUB) {
pic_value a, b;
check_condition(SUB, 2);
b = POP();
a = POP();
(void)POP();
PUSH(pic_sub(pic, a, b));
NEXT;
}
CASE(OP_MUL) {
pic_value a, b;
check_condition(MUL, 2);
b = POP();
a = POP();
(void)POP();
PUSH(pic_mul(pic, a, b));
NEXT;
2014-08-25 00:38:09 -04:00
}
CASE(OP_DIV) {
pic_value a, b;
check_condition(DIV, 2);
b = POP();
a = POP();
(void)POP();
PUSH(pic_div(pic, a, b));
NEXT;
}
CASE(OP_EQ) {
pic_value a, b;
check_condition(EQ, 2);
b = POP();
a = POP();
(void)POP();
PUSH(pic_bool_value(pic_eq(pic, a, b)));
NEXT;
}
CASE(OP_LE) {
pic_value a, b;
check_condition(LT, 2);
b = POP();
a = POP();
(void)POP();
PUSH(pic_bool_value(pic_le(pic, a, b)));
NEXT;
}
CASE(OP_LT) {
pic_value a, b;
check_condition(LE, 2);
b = POP();
a = POP();
(void)POP();
PUSH(pic_bool_value(pic_lt(pic, a, b)));
NEXT;
}
2015-07-06 06:13:00 -04:00
CASE(OP_GE) {
pic_value a, b;
check_condition(LT, 2);
b = POP();
a = POP();
(void)POP();
PUSH(pic_bool_value(pic_ge(pic, a, b)));
NEXT;
}
CASE(OP_GT) {
pic_value a, b;
check_condition(LE, 2);
b = POP();
a = POP();
(void)POP();
PUSH(pic_bool_value(pic_gt(pic, a, b)));
NEXT;
}
2014-08-25 00:38:09 -04:00
CASE(OP_STOP) {
2014-09-14 09:59:29 -04:00
VM_END_PRINT;
2014-08-25 00:38:09 -04:00
return pic_gc_protect(pic, POP());
}
} VM_LOOP_END;
}
pic_value
pic_apply_list(pic_state *pic, struct pic_proc *proc, pic_value list)
{
int n, i = 0;
pic_vec *args;
pic_value x, it;
n = pic_length(pic, list);
args = pic_make_vec(pic, n);
pic_for_each (x, list, it) {
args->data[i++] = x;
}
return pic_apply(pic, proc, n, args->data);
}
2014-08-25 00:38:09 -04:00
pic_value
2015-08-26 06:04:27 -04:00
pic_apply_trampoline(pic_state *pic, struct pic_proc *proc, int argc, pic_value *args)
2014-08-25 00:38:09 -04:00
{
2015-07-04 05:01:30 -04:00
pic_value *sp;
2014-08-25 00:38:09 -04:00
pic_callinfo *ci;
2015-08-26 06:04:27 -04:00
int i;
2014-08-25 00:38:09 -04:00
PIC_INIT_CODE_I(pic->iseq[0], OP_NOP, 0);
PIC_INIT_CODE_I(pic->iseq[1], OP_TAILCALL, -1);
2015-01-27 10:46:51 -05:00
2014-08-25 00:38:09 -04:00
*pic->sp++ = pic_obj_value(proc);
sp = pic->sp;
2015-07-04 05:01:30 -04:00
for (i = 0; i < argc; ++i) {
*sp++ = args[i];
2014-08-25 00:38:09 -04:00
}
ci = PUSHCI();
ci->ip = pic->iseq;
2014-08-25 00:38:09 -04:00
ci->fp = pic->sp;
2015-07-04 05:01:30 -04:00
ci->retc = (int)argc;
2014-08-25 00:38:09 -04:00
if (ci->retc == 0) {
2015-06-09 03:34:45 -04:00
return pic_undef_value();
2014-08-25 00:38:09 -04:00
} else {
2015-07-04 05:01:30 -04:00
return args[0];
2014-08-25 00:38:09 -04:00
}
}
2015-06-19 08:21:04 -04:00
2015-07-04 05:01:30 -04:00
pic_value
pic_apply_trampoline_list(pic_state *pic, struct pic_proc *proc, pic_value args)
{
2015-08-26 06:04:27 -04:00
int i, argc = pic_length(pic, args);
2015-07-12 20:27:12 -04:00
pic_value val, it;
pic_vec *argv = pic_make_vec(pic, argc);
2015-07-04 05:01:30 -04:00
i = 0;
pic_for_each (val, args, it) {
2015-07-12 20:27:12 -04:00
argv->data[i++] = val;
2015-07-04 05:01:30 -04:00
}
2015-07-12 20:27:12 -04:00
return pic_apply_trampoline(pic, proc, argc, argv->data);
2015-07-04 05:01:30 -04:00
}
static pic_value
pic_va_apply(pic_state *pic, struct pic_proc *proc, int n, ...)
{
pic_vec *args = pic_make_vec(pic, n);
va_list ap;
int i = 0;
va_start(ap, n);
while (i < n) {
args->data[i++] = va_arg(ap, pic_value);
}
va_end(ap);
return pic_apply(pic, proc, n, args->data);
}
2015-06-19 08:21:04 -04:00
pic_value
pic_apply0(pic_state *pic, struct pic_proc *proc)
{
return pic_va_apply(pic, proc, 0);
2015-06-19 08:21:04 -04:00
}
pic_value
pic_apply1(pic_state *pic, struct pic_proc *proc, pic_value arg1)
{
return pic_va_apply(pic, proc, 1, arg1);
2015-06-19 08:21:04 -04:00
}
pic_value
pic_apply2(pic_state *pic, struct pic_proc *proc, pic_value arg1, pic_value arg2)
{
return pic_va_apply(pic, proc, 2, arg1, arg2);
2015-06-19 08:21:04 -04:00
}
pic_value
pic_apply3(pic_state *pic, struct pic_proc *proc, pic_value arg1, pic_value arg2, pic_value arg3)
{
return pic_va_apply(pic, proc, 3, arg1, arg2, arg3);
2015-06-19 08:21:04 -04:00
}
pic_value
pic_apply4(pic_state *pic, struct pic_proc *proc, pic_value arg1, pic_value arg2, pic_value arg3, pic_value arg4)
{
return pic_va_apply(pic, proc, 4, arg1, arg2, arg3, arg4);
2015-06-19 08:21:04 -04:00
}
pic_value
pic_apply5(pic_state *pic, struct pic_proc *proc, pic_value arg1, pic_value arg2, pic_value arg3, pic_value arg4, pic_value arg5)
{
return pic_va_apply(pic, proc, 5, arg1, arg2, arg3, arg4, arg5);
2015-06-19 08:21:04 -04:00
}
void
pic_define_(pic_state *pic, const char *name, pic_value val)
2015-06-19 08:21:04 -04:00
{
pic_sym *sym, *uid;
2015-07-12 19:16:04 -04:00
sym = pic_intern(pic, name);
2015-06-19 08:21:04 -04:00
if ((uid = pic_find_variable(pic, pic->lib->env, pic_obj_value(sym))) == NULL) {
uid = pic_add_variable(pic, pic->lib->env, pic_obj_value(sym));
} else {
2015-08-04 20:36:32 -04:00
if (pic_reg_has(pic, pic->globals, uid)) {
2015-07-01 17:17:27 -04:00
pic_warnf(pic, "redefining variable: ~s", pic_obj_value(uid));
}
2015-06-19 08:21:04 -04:00
}
2015-07-07 01:42:50 -04:00
pic_set(pic, pic->lib, name, val);
}
2015-06-19 08:21:04 -04:00
void
pic_define(pic_state *pic, const char *name, pic_value val)
{
pic_define_(pic, name, val);
2015-07-12 19:16:04 -04:00
pic_export(pic, pic_intern(pic, name));
}
void
pic_defun_(pic_state *pic, const char *name, pic_func_t cfunc)
{
2015-06-27 06:02:18 -04:00
pic_define_(pic, name, pic_obj_value(pic_make_proc(pic, cfunc)));
2015-06-19 08:21:04 -04:00
}
void
pic_defun(pic_state *pic, const char *name, pic_func_t cfunc)
{
pic_defun_(pic, name, cfunc);
2015-07-12 19:16:04 -04:00
pic_export(pic, pic_intern(pic, name));
}
void
pic_defvar_(pic_state *pic, const char *name, pic_value init, struct pic_proc *conv)
{
pic_define_(pic, name, pic_obj_value(pic_make_var(pic, init, conv)));
2015-06-19 08:21:04 -04:00
}
void
pic_defvar(pic_state *pic, const char *name, pic_value init, struct pic_proc *conv)
{
pic_defvar_(pic, name, init, conv);
2015-07-12 19:16:04 -04:00
pic_export(pic, pic_intern(pic, name));
2015-06-19 08:21:04 -04:00
}
pic_value
pic_ref(pic_state *pic, struct pic_lib *lib, const char *name)
{
pic_sym *sym, *uid;
2015-07-12 19:16:04 -04:00
sym = pic_intern(pic, name);
2015-06-19 08:21:04 -04:00
if ((uid = pic_find_variable(pic, lib->env, pic_obj_value(sym))) == NULL) {
pic_errorf(pic, "symbol \"%s\" not defined in library ~s", name, lib->name);
}
2015-08-03 19:40:23 -04:00
return vm_gref(pic, pic_vm_gref_slot(pic, uid), uid);
2015-06-19 08:21:04 -04:00
}
void
pic_set(pic_state *pic, struct pic_lib *lib, const char *name, pic_value val)
{
pic_sym *sym, *uid;
2015-07-12 19:16:04 -04:00
sym = pic_intern(pic, name);
2015-06-19 08:21:04 -04:00
if ((uid = pic_find_variable(pic, lib->env, pic_obj_value(sym))) == NULL) {
pic_errorf(pic, "symbol \"%s\" not defined in library ~s", name, lib->name);
}
2015-08-03 19:40:23 -04:00
vm_gset(pic_vm_gref_slot(pic, uid), val);
2015-06-19 08:21:04 -04:00
}
static struct pic_proc *
pic_ref_proc(pic_state *pic, struct pic_lib *lib, const char *name)
2015-06-19 08:21:04 -04:00
{
pic_value proc;
proc = pic_ref(pic, lib, name);
pic_assert_type(pic, proc, proc);
return pic_proc_ptr(proc);
}
pic_value
pic_funcall(pic_state *pic, struct pic_lib *lib, const char *name, pic_value args)
{
return pic_apply_list(pic, pic_ref_proc(pic, lib, name), args);
2015-06-19 08:21:04 -04:00
}
pic_value
pic_funcall0(pic_state *pic, struct pic_lib *lib, const char *name)
{
return pic_apply0(pic, pic_ref_proc(pic, lib, name));
2015-06-19 08:21:04 -04:00
}
pic_value
pic_funcall1(pic_state *pic, struct pic_lib *lib, const char *name, pic_value arg0)
{
return pic_apply1(pic, pic_ref_proc(pic, lib, name), arg0);
2015-06-19 08:21:04 -04:00
}
pic_value
pic_funcall2(pic_state *pic, struct pic_lib *lib, const char *name, pic_value arg0, pic_value arg1)
{
return pic_apply2(pic, pic_ref_proc(pic, lib, name), arg0, arg1);
2015-06-19 08:21:04 -04:00
}
pic_value
pic_funcall3(pic_state *pic, struct pic_lib *lib, const char *name, pic_value arg0, pic_value arg1, pic_value arg2)
{
return pic_apply3(pic, pic_ref_proc(pic, lib, name), arg0, arg1, arg2);
2015-06-19 08:21:04 -04:00
}