2013-10-12 05:48:35 -04:00
|
|
|
#include <stdio.h>
|
2013-10-15 06:19:34 -04:00
|
|
|
#include <stdarg.h>
|
2013-10-11 11:16:19 -04:00
|
|
|
|
|
|
|
#include "picrin.h"
|
2013-10-19 23:34:57 -04:00
|
|
|
#include "picrin/pair.h"
|
2013-10-20 04:06:47 -04:00
|
|
|
#include "picrin/proc.h"
|
|
|
|
#include "picrin/irep.h"
|
2013-10-15 06:19:34 -04:00
|
|
|
|
2013-10-23 02:55:42 -04:00
|
|
|
#define GET_OPERAND(pic,n) ((pic)->ci->fp[(n)])
|
2013-10-21 00:57:02 -04:00
|
|
|
|
|
|
|
int
|
2013-10-15 06:19:34 -04:00
|
|
|
pic_get_args(pic_state *pic, const char *format, ...)
|
|
|
|
{
|
|
|
|
char c;
|
2013-10-23 02:55:42 -04:00
|
|
|
int i = 1, argc = pic->ci->argc;
|
2013-10-15 06:19:34 -04:00
|
|
|
va_list ap;
|
2013-10-21 00:57:02 -04:00
|
|
|
bool opt = false;
|
2013-10-15 06:19:34 -04:00
|
|
|
|
|
|
|
va_start(ap, format);
|
|
|
|
while ((c = *format++)) {
|
|
|
|
switch (c) {
|
2013-10-21 00:57:02 -04:00
|
|
|
default:
|
|
|
|
if (argc <= i && ! opt) {
|
|
|
|
pic_error(pic, "wrong number of arguments");
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case '|':
|
|
|
|
break;
|
|
|
|
}
|
2013-10-22 04:23:21 -04:00
|
|
|
|
|
|
|
/* in order to run out of all arguments passed to this function
|
|
|
|
(i.e. do va_arg for each argument), optional argument existence
|
|
|
|
check is done in every case closure */
|
|
|
|
|
2013-10-21 00:57:02 -04:00
|
|
|
switch (c) {
|
|
|
|
case '|':
|
|
|
|
opt = true;
|
|
|
|
break;
|
2013-10-15 06:19:34 -04:00
|
|
|
case 'o':
|
|
|
|
{
|
|
|
|
pic_value *p;
|
|
|
|
|
|
|
|
p = va_arg(ap, pic_value*);
|
2013-10-22 04:23:21 -04:00
|
|
|
if (i < argc) {
|
|
|
|
*p = GET_OPERAND(pic,i);
|
|
|
|
i++;
|
|
|
|
}
|
2013-10-15 06:19:34 -04:00
|
|
|
}
|
|
|
|
break;
|
2013-10-15 10:25:07 -04:00
|
|
|
case 'f':
|
|
|
|
{
|
|
|
|
double *f;
|
|
|
|
|
|
|
|
f = va_arg(ap, double *);
|
2013-10-22 04:23:21 -04:00
|
|
|
if (i < argc) {
|
|
|
|
*f = pic_float(GET_OPERAND(pic,i));
|
|
|
|
i++;
|
|
|
|
}
|
2013-10-20 22:42:21 -04:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 's':
|
|
|
|
{
|
|
|
|
pic_value str;
|
|
|
|
char **cstr;
|
|
|
|
size_t *len;
|
|
|
|
|
|
|
|
cstr = va_arg(ap, char **);
|
|
|
|
len = va_arg(ap, size_t *);
|
2013-10-22 04:23:21 -04:00
|
|
|
if (i < argc) {
|
|
|
|
str = GET_OPERAND(pic,i);
|
|
|
|
*cstr = pic_str_ptr(str)->str;
|
|
|
|
*len = pic_str_ptr(str)->len;
|
|
|
|
i++;
|
|
|
|
}
|
2013-10-15 10:25:07 -04:00
|
|
|
}
|
|
|
|
break;
|
2013-10-22 04:44:47 -04:00
|
|
|
default:
|
|
|
|
{
|
|
|
|
pic_error(pic, "pic_get_args: invalid argument specifier given");
|
|
|
|
}
|
2013-10-15 06:19:34 -04:00
|
|
|
}
|
|
|
|
}
|
2013-10-21 00:57:02 -04:00
|
|
|
if (argc > i) {
|
|
|
|
pic_error(pic, "wrong number of arguments");
|
|
|
|
}
|
|
|
|
va_end(ap);
|
|
|
|
return i;
|
2013-10-15 06:19:34 -04:00
|
|
|
}
|
|
|
|
|
2013-10-17 00:54:48 -04:00
|
|
|
#if PIC_DIRECT_THREADED_VM
|
|
|
|
# define VM_LOOP JUMP;
|
|
|
|
# define CASE(x) L_##x:
|
|
|
|
# define NEXT ++pc; JUMP;
|
|
|
|
# define JUMP goto *oplabels[pc->insn];
|
|
|
|
# define VM_LOOP_END
|
|
|
|
#else
|
|
|
|
# define VM_LOOP for (;;) { switch (pc->insn) {
|
|
|
|
# define CASE(x) case x:
|
|
|
|
# define NEXT pc++; break
|
|
|
|
# define JUMP break
|
|
|
|
# define VM_LOOP_END } }
|
|
|
|
#endif
|
2013-10-12 05:48:35 -04:00
|
|
|
|
2013-10-23 02:55:42 -04:00
|
|
|
#define PUSH(v) (*pic->sp++ = (v))
|
|
|
|
#define POP() (*--pic->sp)
|
|
|
|
#define POPN(i) (pic->sp -= (i))
|
2013-10-13 04:27:44 -04:00
|
|
|
|
2013-10-17 10:29:18 -04:00
|
|
|
#define PUSHCI() (++pic->ci)
|
|
|
|
#define POPCI() (pic->ci--)
|
2013-10-15 10:29:34 -04:00
|
|
|
|
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;
|
2013-10-13 04:29:21 -04:00
|
|
|
int ai = pic_gc_arena_preserve(pic);
|
2013-10-20 10:30:01 -04:00
|
|
|
jmp_buf jmp;
|
2013-10-12 00:06:02 -04:00
|
|
|
|
2013-10-17 00:54:48 -04:00
|
|
|
#if PIC_DIRECT_THREADED_VM
|
|
|
|
static void *oplabels[] = {
|
2013-10-17 13:29:11 -04:00
|
|
|
&&L_OP_POP, &&L_OP_PUSHNIL, &&L_OP_PUSHTRUE, &&L_OP_PUSHFALSE, &&L_OP_PUSHNUM,
|
2013-10-23 14:14:32 -04:00
|
|
|
&&L_OP_PUSHCONST, &&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_CALL, &&L_OP_RET,
|
|
|
|
&&L_OP_LAMBDA, &&L_OP_CONS, &&L_OP_CAR, &&L_OP_CDR, &&L_OP_NILP,
|
|
|
|
&&L_OP_ADD, &&L_OP_SUB, &&L_OP_MUL, &&L_OP_DIV, &&L_OP_STOP
|
2013-10-17 00:54:48 -04:00
|
|
|
};
|
|
|
|
#endif
|
|
|
|
|
2013-10-12 00:06:02 -04:00
|
|
|
pc = proc->u.irep->code;
|
2013-10-15 20:28:58 -04:00
|
|
|
|
2013-10-20 10:30:01 -04:00
|
|
|
if (setjmp(jmp) == 0) {
|
|
|
|
pic->jmp = &jmp;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
goto L_RAISE;
|
|
|
|
}
|
|
|
|
|
2013-10-17 10:29:18 -04:00
|
|
|
/* adjust call frame */
|
|
|
|
pic->sp[0] = pic_obj_value(proc);
|
2013-10-17 12:30:35 -04:00
|
|
|
pic->ci->argc = 1;
|
2013-10-17 10:29:18 -04:00
|
|
|
pic->ci->pc = NULL;
|
2013-10-23 02:55:42 -04:00
|
|
|
pic->ci->fp = pic->sp;
|
|
|
|
pic->sp++;
|
2013-10-12 00:06:02 -04:00
|
|
|
|
2013-10-12 05:48:35 -04:00
|
|
|
VM_LOOP {
|
2013-10-17 13:29:11 -04:00
|
|
|
CASE(OP_POP) {
|
2013-10-19 14:05:42 -04:00
|
|
|
POPN(1);
|
2013-10-17 13:29:11 -04:00
|
|
|
NEXT;
|
|
|
|
}
|
2013-10-12 05:48:35 -04:00
|
|
|
CASE(OP_PUSHNIL) {
|
2013-10-13 04:27:44 -04:00
|
|
|
PUSH(pic_nil_value());
|
2013-10-16 00:17:01 -04:00
|
|
|
NEXT;
|
|
|
|
}
|
|
|
|
CASE(OP_PUSHTRUE) {
|
|
|
|
PUSH(pic_true_value());
|
|
|
|
NEXT;
|
|
|
|
}
|
|
|
|
CASE(OP_PUSHFALSE) {
|
|
|
|
PUSH(pic_false_value());
|
2013-10-12 05:48:35 -04:00
|
|
|
NEXT;
|
2013-10-12 00:06:02 -04:00
|
|
|
}
|
2013-10-15 07:05:12 -04:00
|
|
|
CASE(OP_PUSHNUM) {
|
|
|
|
PUSH(pic_float_value(pc->u.f));
|
2013-10-12 05:48:35 -04:00
|
|
|
NEXT;
|
2013-10-12 00:06:02 -04:00
|
|
|
}
|
2013-10-20 20:29:56 -04:00
|
|
|
CASE(OP_PUSHCONST) {
|
|
|
|
PUSH(pic->pool[pc->u.i]);
|
|
|
|
NEXT;
|
|
|
|
}
|
2013-10-12 05:48:35 -04:00
|
|
|
CASE(OP_GREF) {
|
2013-10-17 11:15:15 -04:00
|
|
|
PUSH(pic->globals[pc->u.i]);
|
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) {
|
2013-10-17 11:15:15 -04:00
|
|
|
pic->globals[pc->u.i] = POP();
|
2013-10-12 05:48:35 -04:00
|
|
|
NEXT;
|
2013-10-12 01:40:55 -04:00
|
|
|
}
|
2013-10-16 04:20:53 -04:00
|
|
|
CASE(OP_LREF) {
|
2013-10-23 02:55:42 -04:00
|
|
|
PUSH(pic->ci->fp[pc->u.i]);
|
2013-10-16 04:20:53 -04:00
|
|
|
NEXT;
|
|
|
|
}
|
2013-10-23 14:14:32 -04:00
|
|
|
CASE(OP_LSET) {
|
|
|
|
pic->ci->fp[pc->u.i] = POP();
|
|
|
|
NEXT;
|
|
|
|
}
|
2013-10-23 13:04:49 -04:00
|
|
|
CASE(OP_CREF) {
|
|
|
|
int depth = pc->u.c.depth;
|
|
|
|
struct pic_env *env;
|
|
|
|
|
|
|
|
env = pic_proc_ptr(*pic->ci->fp)->env;
|
|
|
|
while (depth--) {
|
|
|
|
env = env->up;
|
|
|
|
}
|
|
|
|
PUSH(env->values[pc->u.c.idx]);
|
|
|
|
NEXT;
|
|
|
|
}
|
2013-10-23 14:14:32 -04:00
|
|
|
CASE(OP_CSET) {
|
|
|
|
int depth = pc->u.c.depth;
|
|
|
|
struct pic_env *env;
|
|
|
|
|
|
|
|
env = pic_proc_ptr(*pic->ci->fp)->env;
|
|
|
|
while (depth--) {
|
|
|
|
env = env->up;
|
|
|
|
}
|
|
|
|
env->values[pc->u.c.idx] = POP();
|
|
|
|
NEXT;
|
|
|
|
}
|
2013-10-16 04:42:47 -04:00
|
|
|
CASE(OP_JMP) {
|
|
|
|
pc += pc->u.i;
|
|
|
|
JUMP;
|
|
|
|
}
|
|
|
|
CASE(OP_JMPIF) {
|
|
|
|
pic_value v;
|
|
|
|
|
|
|
|
v = POP();
|
|
|
|
if (! pic_false_p(v)) {
|
|
|
|
pc += pc->u.i;
|
|
|
|
JUMP;
|
|
|
|
}
|
|
|
|
NEXT;
|
|
|
|
}
|
2013-10-15 06:18:33 -04:00
|
|
|
CASE(OP_CALL) {
|
2013-10-16 00:24:19 -04:00
|
|
|
pic_value c, v;
|
2013-10-17 10:29:18 -04:00
|
|
|
pic_callinfo *ci;
|
2013-10-15 06:18:33 -04:00
|
|
|
struct pic_proc *proc;
|
|
|
|
|
2013-10-23 02:55:42 -04:00
|
|
|
c = pic->sp[-pc->u.i];
|
2013-10-23 14:38:29 -04:00
|
|
|
if (! pic_proc_p(c)) {
|
|
|
|
pic->errmsg = "invalid application";
|
|
|
|
goto L_RAISE;
|
|
|
|
}
|
2013-10-15 06:18:33 -04:00
|
|
|
proc = pic_proc_ptr(c);
|
2013-10-23 02:55:42 -04:00
|
|
|
|
2013-10-15 10:29:34 -04:00
|
|
|
ci = PUSHCI();
|
|
|
|
ci->argc = pc->u.i;
|
2013-10-16 02:30:52 -04:00
|
|
|
ci->pc = pc;
|
2013-10-23 02:55:42 -04:00
|
|
|
ci->fp = pic->sp - pc->u.i;
|
2013-10-15 22:28:57 -04:00
|
|
|
if (pic_proc_cfunc_p(c)) {
|
2013-10-16 00:24:19 -04:00
|
|
|
v = proc->u.cfunc(pic);
|
2013-10-23 02:55:42 -04:00
|
|
|
pic->sp = ci->fp;
|
2013-10-15 22:28:57 -04:00
|
|
|
POPCI();
|
2013-10-16 00:24:19 -04:00
|
|
|
PUSH(v);
|
2013-10-16 02:30:52 -04:00
|
|
|
pic_gc_arena_restore(pic, ai);
|
|
|
|
NEXT;
|
2013-10-15 22:28:57 -04:00
|
|
|
}
|
|
|
|
else {
|
2013-10-23 13:51:02 -04:00
|
|
|
int i;
|
|
|
|
|
2013-10-23 11:09:40 -04:00
|
|
|
if (ci->argc != proc->u.irep->argc) {
|
|
|
|
pic->errmsg = "wrong number of arguments";
|
|
|
|
goto L_RAISE;
|
|
|
|
}
|
2013-10-23 13:51:02 -04:00
|
|
|
for (i = 0; i < proc->u.irep->argc; ++i) {
|
|
|
|
proc->env->values[i] = ci->fp[i];
|
|
|
|
}
|
2013-10-16 02:30:52 -04:00
|
|
|
pc = proc->u.irep->code;
|
|
|
|
pic_gc_arena_restore(pic, ai);
|
|
|
|
JUMP;
|
2013-10-15 22:28:57 -04:00
|
|
|
}
|
2013-10-16 02:30:52 -04:00
|
|
|
}
|
|
|
|
CASE(OP_RET) {
|
|
|
|
pic_value v;
|
2013-10-17 10:29:18 -04:00
|
|
|
pic_callinfo *ci;
|
2013-10-16 02:30:52 -04:00
|
|
|
|
2013-10-20 10:30:01 -04:00
|
|
|
if (pic->errmsg) {
|
2013-10-20 20:29:56 -04:00
|
|
|
|
|
|
|
L_RAISE:
|
2013-10-20 10:30:01 -04:00
|
|
|
goto L_STOP;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
v = POP();
|
|
|
|
ci = POPCI();
|
|
|
|
pc = ci->pc;
|
2013-10-23 02:55:42 -04:00
|
|
|
pic->sp = ci->fp;
|
2013-10-20 10:30:01 -04:00
|
|
|
PUSH(v);
|
|
|
|
}
|
2013-10-15 22:32:30 -04:00
|
|
|
NEXT;
|
|
|
|
}
|
|
|
|
CASE(OP_LAMBDA) {
|
|
|
|
struct pic_proc *proc;
|
2013-10-23 13:02:07 -04:00
|
|
|
struct pic_env *env;
|
2013-10-15 22:32:30 -04:00
|
|
|
|
2013-10-23 13:02:07 -04:00
|
|
|
env = (struct pic_env *)pic_obj_alloc(pic, sizeof(struct pic_env), PIC_TT_ENV);
|
2013-10-23 13:51:02 -04:00
|
|
|
env->numcv = pic->irep[pc->u.i]->argc;
|
|
|
|
env->values = (pic_value *)pic_alloc(pic, sizeof(pic_value) * env->numcv);
|
2013-10-23 13:02:07 -04:00
|
|
|
env->up = pic_proc_ptr(*pic->ci->fp)->env;
|
|
|
|
|
|
|
|
proc = pic_proc_new(pic, pic->irep[pc->u.i], env);
|
2013-10-15 22:32:30 -04:00
|
|
|
PUSH(pic_obj_value(proc));
|
|
|
|
pic_gc_arena_restore(pic, ai);
|
2013-10-15 06:18:33 -04:00
|
|
|
NEXT;
|
|
|
|
}
|
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, b = POP());
|
2013-10-23 02:55:42 -04:00
|
|
|
pic_gc_protect(pic, a = POP());
|
2013-10-13 04:27:44 -04:00
|
|
|
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-19 14:48:06 -04:00
|
|
|
CASE(OP_CAR) {
|
|
|
|
pic_value p;
|
|
|
|
p = POP();
|
|
|
|
PUSH(pic_car(pic, p));
|
|
|
|
NEXT;
|
|
|
|
}
|
|
|
|
CASE(OP_CDR) {
|
|
|
|
pic_value p;
|
|
|
|
p = POP();
|
|
|
|
PUSH(pic_cdr(pic, p));
|
|
|
|
NEXT;
|
|
|
|
}
|
2013-10-19 14:53:02 -04:00
|
|
|
CASE(OP_NILP) {
|
|
|
|
pic_value p;
|
|
|
|
p = POP();
|
|
|
|
PUSH(pic_bool_value(pic_nil_p(p)));
|
|
|
|
NEXT;
|
|
|
|
}
|
2013-10-12 05:48:35 -04:00
|
|
|
CASE(OP_ADD) {
|
2013-10-12 00:06:02 -04:00
|
|
|
pic_value a, b;
|
2013-10-13 04:27:44 -04:00
|
|
|
b = POP();
|
2013-10-23 02:55:42 -04:00
|
|
|
a = POP();
|
2013-10-15 07:05:12 -04:00
|
|
|
PUSH(pic_float_value(pic_float(a) + pic_float(b)));
|
2013-10-12 05:48:35 -04:00
|
|
|
NEXT;
|
2013-10-12 00:06:02 -04:00
|
|
|
}
|
2013-10-15 08:29:07 -04:00
|
|
|
CASE(OP_SUB) {
|
|
|
|
pic_value a, b;
|
|
|
|
b = POP();
|
2013-10-23 02:55:42 -04:00
|
|
|
a = POP();
|
2013-10-15 08:29:07 -04:00
|
|
|
PUSH(pic_float_value(pic_float(a) - pic_float(b)));
|
|
|
|
NEXT;
|
|
|
|
}
|
|
|
|
CASE(OP_MUL) {
|
|
|
|
pic_value a, b;
|
|
|
|
b = POP();
|
2013-10-23 02:55:42 -04:00
|
|
|
a = POP();
|
2013-10-15 08:29:07 -04:00
|
|
|
PUSH(pic_float_value(pic_float(a) * pic_float(b)));
|
|
|
|
NEXT;
|
|
|
|
}
|
|
|
|
CASE(OP_DIV) {
|
|
|
|
pic_value a, b;
|
|
|
|
b = POP();
|
2013-10-23 02:55:42 -04:00
|
|
|
a = POP();
|
2013-10-15 08:29:07 -04:00
|
|
|
PUSH(pic_float_value(pic_float(a) / pic_float(b)));
|
|
|
|
NEXT;
|
|
|
|
}
|
2013-10-12 05:48:35 -04:00
|
|
|
CASE(OP_STOP) {
|
2013-10-20 04:26:18 -04:00
|
|
|
pic_value val;
|
2013-10-12 00:06:02 -04:00
|
|
|
|
2013-10-20 10:30:01 -04:00
|
|
|
L_STOP:
|
2013-10-20 04:26:18 -04:00
|
|
|
val = POP();
|
2013-10-16 02:30:52 -04:00
|
|
|
|
2013-10-23 02:55:42 -04:00
|
|
|
/* pop the first procedure */
|
|
|
|
POPN(1);
|
|
|
|
|
2013-10-20 10:30:01 -04:00
|
|
|
pic->jmp = NULL;
|
|
|
|
if (pic->errmsg) {
|
|
|
|
return pic_undef_value();
|
|
|
|
}
|
|
|
|
|
2013-10-20 00:07:14 -04:00
|
|
|
#if VM_DEBUG
|
2013-10-20 04:26:18 -04:00
|
|
|
puts("**VM END STATE**");
|
2013-10-23 02:52:14 -04:00
|
|
|
printf("stbase\t= %p\nsp\t= %p\n", pic->stbase, pic->sp);
|
|
|
|
printf("cibase\t= %p\nci\t= %p\n", pic->cibase, pic->ci);
|
2013-10-20 04:26:18 -04:00
|
|
|
if (pic->stbase != pic->sp) {
|
|
|
|
pic_value *sp;
|
|
|
|
printf("* stack trace:");
|
|
|
|
for (sp = pic->stbase; pic->sp != sp; ++sp) {
|
|
|
|
pic_debug(pic, *sp);
|
|
|
|
puts("");
|
|
|
|
}
|
|
|
|
}
|
2013-10-16 02:30:52 -04:00
|
|
|
#endif
|
|
|
|
|
2013-10-20 04:26:18 -04:00
|
|
|
return val;
|
|
|
|
}
|
|
|
|
} VM_LOOP_END;
|
2013-10-12 01:40:27 -04:00
|
|
|
}
|