2014-01-17 06:58:31 -05:00
|
|
|
/**
|
|
|
|
* See Copyright Notice in picrin.h
|
|
|
|
*/
|
|
|
|
|
2013-10-12 05:48:35 -04:00
|
|
|
#include <stdio.h>
|
2013-11-22 09:37:57 -05:00
|
|
|
#include <stdlib.h>
|
2013-10-15 06:19:34 -04:00
|
|
|
#include <stdarg.h>
|
2013-10-28 08:26:39 -04:00
|
|
|
#include <limits.h>
|
2013-11-09 02:32:13 -05:00
|
|
|
#include <math.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"
|
2014-01-12 10:48:00 -05:00
|
|
|
#include "picrin/port.h"
|
2013-10-20 04:06:47 -04:00
|
|
|
#include "picrin/irep.h"
|
2013-11-04 22:58:16 -05:00
|
|
|
#include "picrin/blob.h"
|
2014-01-12 02:09:27 -05:00
|
|
|
#include "picrin/var.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
|
|
|
|
2013-11-09 00:12:59 -05:00
|
|
|
struct pic_proc *
|
|
|
|
pic_get_proc(pic_state *pic)
|
|
|
|
{
|
|
|
|
pic_value v = GET_OPERAND(pic,0);
|
|
|
|
|
|
|
|
if (! pic_proc_p(v)) {
|
|
|
|
pic_error(pic, "fatal error");
|
|
|
|
}
|
|
|
|
return pic_proc_ptr(v);
|
|
|
|
}
|
|
|
|
|
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-11-15 08:53:41 -05:00
|
|
|
case '*':
|
|
|
|
break;
|
2013-10-21 00:57:02 -04:00
|
|
|
}
|
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-11-15 08:53:41 -05:00
|
|
|
if (c == '*')
|
|
|
|
break;
|
|
|
|
|
2013-10-21 00:57:02 -04:00
|
|
|
switch (c) {
|
|
|
|
case '|':
|
|
|
|
opt = true;
|
|
|
|
break;
|
2014-01-16 23:16:55 -05:00
|
|
|
case 'o': {
|
|
|
|
pic_value *p;
|
|
|
|
|
|
|
|
p = va_arg(ap, pic_value*);
|
|
|
|
if (i < argc) {
|
|
|
|
*p = GET_OPERAND(pic,i);
|
|
|
|
i++;
|
2013-10-15 06:19:34 -04:00
|
|
|
}
|
|
|
|
break;
|
2014-01-16 23:16:55 -05:00
|
|
|
}
|
|
|
|
case 'f': {
|
|
|
|
double *f;
|
|
|
|
|
|
|
|
f = va_arg(ap, double *);
|
|
|
|
if (i < argc) {
|
|
|
|
pic_value v;
|
|
|
|
|
|
|
|
v = GET_OPERAND(pic, i);
|
|
|
|
switch (pic_type(v)) {
|
|
|
|
case PIC_TT_FLOAT:
|
|
|
|
*f = pic_float(v);
|
|
|
|
break;
|
|
|
|
case PIC_TT_INT:
|
|
|
|
*f = pic_int(v);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
pic_error(pic, "pic_get_args: expected float or int");
|
|
|
|
}
|
|
|
|
i++;
|
2013-10-20 22:42:21 -04:00
|
|
|
}
|
|
|
|
break;
|
2014-01-16 23:16:55 -05:00
|
|
|
}
|
|
|
|
case 'F': {
|
|
|
|
double *f;
|
|
|
|
bool *e;
|
|
|
|
|
|
|
|
f = va_arg(ap, double *);
|
|
|
|
e = va_arg(ap, bool *);
|
|
|
|
if (i < argc) {
|
|
|
|
pic_value v;
|
|
|
|
|
|
|
|
v = GET_OPERAND(pic, i);
|
|
|
|
switch (pic_type(v)) {
|
|
|
|
case PIC_TT_FLOAT:
|
|
|
|
*f = pic_float(v);
|
|
|
|
*e = false;
|
|
|
|
break;
|
|
|
|
case PIC_TT_INT:
|
|
|
|
*f = pic_int(v);
|
|
|
|
*e = true;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
pic_error(pic, "pic_get_args: expected float or int");
|
|
|
|
}
|
|
|
|
i++;
|
2013-10-27 11:21:24 -04:00
|
|
|
}
|
|
|
|
break;
|
2014-01-16 23:16:55 -05:00
|
|
|
}
|
|
|
|
case 'I': {
|
|
|
|
int *k;
|
|
|
|
bool *e;
|
|
|
|
|
|
|
|
k = va_arg(ap, int *);
|
|
|
|
e = va_arg(ap, bool *);
|
|
|
|
if (i < argc) {
|
|
|
|
pic_value v;
|
|
|
|
|
|
|
|
v = GET_OPERAND(pic, i);
|
|
|
|
switch (pic_type(v)) {
|
|
|
|
case PIC_TT_FLOAT:
|
|
|
|
*k = (int)pic_float(v);
|
|
|
|
*e = false;
|
|
|
|
break;
|
|
|
|
case PIC_TT_INT:
|
|
|
|
*k = pic_int(v);
|
|
|
|
*e = true;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
pic_error(pic, "pic_get_args: expected float or int");
|
|
|
|
}
|
|
|
|
i++;
|
2013-10-27 11:24:51 -04:00
|
|
|
}
|
|
|
|
break;
|
2014-01-16 23:16:55 -05:00
|
|
|
}
|
|
|
|
case 'i': {
|
|
|
|
int *k;
|
|
|
|
|
|
|
|
k = va_arg(ap, int *);
|
|
|
|
if (i < argc) {
|
|
|
|
pic_value v;
|
|
|
|
|
|
|
|
v = GET_OPERAND(pic, i);
|
|
|
|
switch (pic_type(v)) {
|
|
|
|
case PIC_TT_FLOAT:
|
|
|
|
*k = (int)pic_float(v);
|
|
|
|
break;
|
|
|
|
case PIC_TT_INT:
|
|
|
|
*k = pic_int(v);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
pic_error(pic, "pic_get_args: expected int");
|
|
|
|
}
|
|
|
|
i++;
|
2013-11-04 20:53:33 -05:00
|
|
|
}
|
|
|
|
break;
|
2014-01-16 23:16:55 -05:00
|
|
|
}
|
|
|
|
case 's': {
|
|
|
|
pic_value str;
|
|
|
|
char **cstr;
|
|
|
|
size_t *len;
|
|
|
|
|
|
|
|
cstr = va_arg(ap, char **);
|
|
|
|
len = va_arg(ap, size_t *);
|
|
|
|
if (i < argc) {
|
|
|
|
str = GET_OPERAND(pic,i);
|
|
|
|
if (! pic_str_p(str)) {
|
|
|
|
pic_error(pic, "pic_get_args: expected string");
|
|
|
|
}
|
|
|
|
*cstr = pic_str_ptr(str)->str;
|
|
|
|
*len = pic_str_ptr(str)->len;
|
|
|
|
i++;
|
2013-10-15 10:25:07 -04:00
|
|
|
}
|
|
|
|
break;
|
2014-01-16 23:16:55 -05:00
|
|
|
}
|
|
|
|
case 'm': {
|
|
|
|
pic_sym *m;
|
|
|
|
pic_value v;
|
|
|
|
|
|
|
|
m = va_arg(ap, pic_sym *);
|
|
|
|
if (i < argc) {
|
|
|
|
v = GET_OPERAND(pic,i);
|
2014-01-30 13:03:36 -05:00
|
|
|
if (pic_sym_p(v)) {
|
2014-01-16 23:16:55 -05:00
|
|
|
*m = pic_sym(v);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
pic_error(pic, "pic_get_args: expected symbol");
|
|
|
|
}
|
|
|
|
i++;
|
2014-01-09 02:33:38 -05:00
|
|
|
}
|
2014-01-16 23:16:55 -05:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
case 'v': {
|
|
|
|
struct pic_vector **vec;
|
|
|
|
pic_value v;
|
|
|
|
|
|
|
|
vec = va_arg(ap, struct pic_vector **);
|
|
|
|
if (i < argc) {
|
|
|
|
v = GET_OPERAND(pic,i);
|
|
|
|
if (pic_vec_p(v)) {
|
|
|
|
*vec = pic_vec_ptr(v);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
pic_error(pic, "pic_get_args: expected vector");
|
|
|
|
}
|
|
|
|
i++;
|
2013-11-04 20:53:33 -05:00
|
|
|
}
|
|
|
|
break;
|
2014-01-16 23:16:55 -05:00
|
|
|
}
|
|
|
|
case 'b': {
|
|
|
|
struct pic_blob **b;
|
|
|
|
pic_value v;
|
|
|
|
|
|
|
|
b = va_arg(ap, struct pic_blob **);
|
|
|
|
if (i < argc) {
|
|
|
|
v = GET_OPERAND(pic,i);
|
|
|
|
if (pic_blob_p(v)) {
|
|
|
|
*b = pic_blob_ptr(v);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
pic_error(pic, "pic_get_args: expected bytevector");
|
|
|
|
}
|
|
|
|
i++;
|
2013-11-04 22:58:16 -05:00
|
|
|
}
|
|
|
|
break;
|
2014-01-16 23:16:55 -05:00
|
|
|
}
|
|
|
|
case 'c': {
|
|
|
|
char *c;
|
|
|
|
pic_value v;
|
|
|
|
|
|
|
|
c = va_arg(ap, char *);
|
|
|
|
if (i < argc) {
|
|
|
|
v = GET_OPERAND(pic,i);
|
|
|
|
if (pic_char_p(v)) {
|
|
|
|
*c = pic_char(v);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
pic_error(pic, "pic_get_args: expected char");
|
|
|
|
}
|
|
|
|
i++;
|
2013-11-14 06:41:22 -05:00
|
|
|
}
|
|
|
|
break;
|
2014-01-16 23:16:55 -05:00
|
|
|
}
|
|
|
|
case 'l': {
|
|
|
|
struct pic_proc **l;
|
|
|
|
pic_value v;
|
|
|
|
|
|
|
|
l = va_arg(ap, struct pic_proc **);
|
|
|
|
if (i < argc) {
|
|
|
|
v = GET_OPERAND(pic,i);
|
|
|
|
if (pic_proc_p(v)) {
|
|
|
|
*l = pic_proc_ptr(v);
|
2014-01-08 06:53:28 -05:00
|
|
|
}
|
2014-01-16 23:16:55 -05:00
|
|
|
else {
|
|
|
|
pic_error(pic, "pic_get_args, expected procedure");
|
|
|
|
}
|
|
|
|
i++;
|
2014-01-08 06:53:28 -05:00
|
|
|
}
|
2014-01-16 23:16:55 -05:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
case 'p': {
|
|
|
|
struct pic_port **p;
|
|
|
|
pic_value v;
|
|
|
|
|
|
|
|
p = va_arg(ap, struct pic_port **);
|
|
|
|
if (i < argc) {
|
|
|
|
v = GET_OPERAND(pic,i);
|
|
|
|
if (pic_port_p(v)) {
|
|
|
|
*p = pic_port_ptr(v);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
pic_error(pic, "pic_get_args, expected port");
|
2014-01-12 10:48:00 -05:00
|
|
|
}
|
2014-01-16 23:16:55 -05:00
|
|
|
i++;
|
2014-01-12 10:48:00 -05:00
|
|
|
}
|
2014-01-16 23:16:55 -05:00
|
|
|
break;
|
|
|
|
}
|
2013-10-22 04:44:47 -04:00
|
|
|
default:
|
2014-01-16 23:16:55 -05:00
|
|
|
pic_error(pic, "pic_get_args: invalid argument specifier given");
|
2013-10-15 06:19:34 -04:00
|
|
|
}
|
|
|
|
}
|
2013-11-15 08:53:41 -05:00
|
|
|
if ('*' == c) {
|
2013-11-17 11:07:51 -05:00
|
|
|
size_t *n;
|
2013-11-15 08:53:41 -05:00
|
|
|
pic_value **argv;
|
|
|
|
|
2013-11-17 11:07:51 -05:00
|
|
|
n = va_arg(ap, size_t *);
|
2013-11-15 08:53:41 -05:00
|
|
|
argv = va_arg(ap, pic_value **);
|
|
|
|
if (i <= argc) {
|
|
|
|
*n = argc - i;
|
|
|
|
*argv = &GET_OPERAND(pic, i);
|
|
|
|
i = argc;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (argc > i) {
|
2013-10-21 00:57:02 -04:00
|
|
|
pic_error(pic, "wrong number of arguments");
|
|
|
|
}
|
|
|
|
va_end(ap);
|
2014-02-01 00:23:21 -05:00
|
|
|
return i - 1;
|
2013-10-15 06:19:34 -04:00
|
|
|
}
|
|
|
|
|
2014-01-12 02:09:19 -05:00
|
|
|
void
|
|
|
|
pic_defun(pic_state *pic, const char *name, pic_func_t cfunc)
|
|
|
|
{
|
|
|
|
struct pic_proc *proc;
|
|
|
|
|
|
|
|
proc = pic_proc_new(pic, cfunc);
|
2014-01-12 10:45:49 -05:00
|
|
|
pic_define(pic, name, pic_obj_value(proc));
|
2014-01-12 02:09:19 -05:00
|
|
|
}
|
|
|
|
|
2014-01-12 02:09:27 -05:00
|
|
|
void
|
|
|
|
pic_defvar(pic_state *pic, const char *name, pic_value init)
|
|
|
|
{
|
|
|
|
struct pic_var *var;
|
|
|
|
|
|
|
|
var = pic_var_new(pic, init, NULL);
|
2014-01-12 10:45:49 -05:00
|
|
|
pic_define(pic, name, pic_obj_value(pic_wrap_var(pic, var)));
|
2014-01-12 02:09:27 -05:00
|
|
|
}
|
|
|
|
|
2013-11-09 00:13:14 -05:00
|
|
|
pic_value
|
|
|
|
pic_apply_argv(pic_state *pic, struct pic_proc *proc, size_t argc, ...)
|
|
|
|
{
|
|
|
|
va_list ap;
|
|
|
|
pic_value v;
|
|
|
|
|
|
|
|
va_start(ap, argc);
|
|
|
|
|
|
|
|
v = pic_nil_value();
|
|
|
|
while (argc--) {
|
|
|
|
v = pic_cons(pic, va_arg(ap, pic_value), v);
|
|
|
|
}
|
2013-11-27 01:55:54 -05:00
|
|
|
v = pic_reverse(pic, v);
|
2013-11-09 00:13:14 -05:00
|
|
|
|
|
|
|
va_end(ap);
|
|
|
|
return pic_apply(pic, proc, v);
|
|
|
|
}
|
|
|
|
|
2013-12-10 04:47:45 -05:00
|
|
|
void print_code(pic_state *, struct pic_code);
|
|
|
|
|
2013-11-01 06:02:46 -04:00
|
|
|
#if VM_DEBUG
|
2013-12-10 04:47:45 -05:00
|
|
|
# define OPCODE_EXEC_HOOK print_code(pic, c)
|
2013-11-01 06:02:46 -04:00
|
|
|
#else
|
|
|
|
# define OPCODE_EXEC_HOOK ((void)0)
|
|
|
|
#endif
|
|
|
|
|
2013-10-17 00:54:48 -04:00
|
|
|
#if PIC_DIRECT_THREADED_VM
|
|
|
|
# define VM_LOOP JUMP;
|
2013-11-01 06:02:46 -04:00
|
|
|
# define CASE(x) L_##x: OPCODE_EXEC_HOOK;
|
2014-02-03 20:40:03 -05:00
|
|
|
# define NEXT pic->ip++; JUMP;
|
|
|
|
# define JUMP c = *pic->ip; goto *oplabels[c.insn];
|
2013-10-17 00:54:48 -04:00
|
|
|
# define VM_LOOP_END
|
|
|
|
#else
|
2014-02-03 20:40:03 -05:00
|
|
|
# define VM_LOOP for (;;) { c = *pic->ip; switch (c.insn) {
|
2013-10-17 00:54:48 -04:00
|
|
|
# define CASE(x) case x:
|
2014-02-03 20:40:03 -05:00
|
|
|
# define NEXT pic->ip++; break
|
2013-10-17 00:54:48 -04:00
|
|
|
# define JUMP break
|
|
|
|
# define VM_LOOP_END } }
|
|
|
|
#endif
|
2013-10-12 05:48:35 -04:00
|
|
|
|
2013-11-22 09:37:57 -05:00
|
|
|
#define PUSH(v) ((pic->sp >= pic->stend) ? abort() : (*pic->sp++ = (v)))
|
2013-10-23 02:55:42 -04:00
|
|
|
#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
|
2013-10-28 04:45:13 -04:00
|
|
|
pic_apply(pic_state *pic, struct pic_proc *proc, pic_value argv)
|
2013-10-12 00:06:02 -04:00
|
|
|
{
|
2014-02-03 20:40:03 -05:00
|
|
|
struct pic_code c;
|
2013-10-13 04:29:21 -04:00
|
|
|
int ai = pic_gc_arena_preserve(pic);
|
2013-11-14 05:25:03 -05:00
|
|
|
jmp_buf jmp, *prev_jmp = pic->jmp;
|
2013-10-28 04:45:13 -04:00
|
|
|
size_t argc, i;
|
2013-10-30 02:36:28 -04:00
|
|
|
struct pic_code boot[2];
|
2013-10-12 00:06:02 -04:00
|
|
|
|
2013-10-17 00:54:48 -04:00
|
|
|
#if PIC_DIRECT_THREADED_VM
|
|
|
|
static void *oplabels[] = {
|
2014-01-30 13:11:28 -05:00
|
|
|
&&L_OP_POP, &&L_OP_PUSHNIL, &&L_OP_PUSHTRUE, &&L_OP_PUSHFALSE,
|
2013-11-04 21:37:18 -05:00
|
|
|
&&L_OP_PUSHINT, &&L_OP_PUSHCHAR, &&L_OP_PUSHCONST,
|
|
|
|
&&L_OP_GREF, &&L_OP_GSET, &&L_OP_LREF, &&L_OP_LSET, &&L_OP_CREF, &&L_OP_CSET,
|
2014-02-02 00:54:47 -05:00
|
|
|
&&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,
|
2013-11-06 22:17:37 -05:00
|
|
|
&&L_OP_ADD, &&L_OP_SUB, &&L_OP_MUL, &&L_OP_DIV, &&L_OP_MINUS,
|
2013-10-24 08:10:13 -04:00
|
|
|
&&L_OP_EQ, &&L_OP_LT, &&L_OP_LE, &&L_OP_STOP
|
2013-10-17 00:54:48 -04:00
|
|
|
};
|
|
|
|
#endif
|
|
|
|
|
2013-10-20 10:30:01 -04:00
|
|
|
if (setjmp(jmp) == 0) {
|
|
|
|
pic->jmp = &jmp;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
goto L_RAISE;
|
|
|
|
}
|
|
|
|
|
2013-11-10 18:01:08 -05:00
|
|
|
if (! pic_list_p(pic, argv)) {
|
|
|
|
pic_error(pic, "argv must be a proper list");
|
|
|
|
}
|
|
|
|
|
2013-10-28 04:45:13 -04:00
|
|
|
argc = pic_length(pic, argv) + 1;
|
|
|
|
|
2013-11-01 06:02:46 -04:00
|
|
|
#if VM_DEBUG
|
|
|
|
puts("== booting VM...");
|
|
|
|
printf(" proc = ");
|
|
|
|
pic_debug(pic, pic_obj_value(proc));
|
|
|
|
puts("");
|
|
|
|
printf(" argv = ");
|
|
|
|
pic_debug(pic, argv);
|
|
|
|
puts("");
|
2013-11-09 00:12:36 -05:00
|
|
|
if (! proc->cfunc_p) {
|
|
|
|
printf(" irep = ");
|
2014-01-18 02:23:12 -05:00
|
|
|
pic_dump_irep(pic, proc->u.irep);
|
2013-11-09 00:12:36 -05:00
|
|
|
}
|
|
|
|
else {
|
2014-01-05 04:10:33 -05:00
|
|
|
printf(" cfunc = %p\n", (void *)proc->u.cfunc);
|
2013-11-09 00:12:36 -05:00
|
|
|
}
|
2013-11-01 06:02:46 -04:00
|
|
|
puts("\nLet's go!");
|
|
|
|
#endif
|
|
|
|
|
2013-10-28 04:45:13 -04:00
|
|
|
PUSH(pic_obj_value(proc));
|
|
|
|
for (i = 1; i < argc; ++i) {
|
|
|
|
PUSH(pic_car(pic, argv));
|
|
|
|
argv = pic_cdr(pic, argv);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* boot! */
|
2013-10-30 02:36:28 -04:00
|
|
|
boot[0].insn = OP_CALL;
|
|
|
|
boot[0].u.i = argc;
|
|
|
|
boot[1].insn = OP_STOP;
|
2014-02-03 20:40:03 -05:00
|
|
|
pic->ip = boot;
|
|
|
|
c = *pic->ip;
|
2013-10-28 04:45:13 -04:00
|
|
|
goto L_CALL;
|
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-27 11:21:24 -04:00
|
|
|
CASE(OP_PUSHINT) {
|
2013-11-01 01:44:26 -04:00
|
|
|
PUSH(pic_int_value(c.u.i));
|
2013-10-27 11:21:24 -04:00
|
|
|
NEXT;
|
|
|
|
}
|
2013-11-04 21:37:18 -05:00
|
|
|
CASE(OP_PUSHCHAR) {
|
|
|
|
PUSH(pic_char_value(c.u.c));
|
|
|
|
NEXT;
|
|
|
|
}
|
2013-10-20 20:29:56 -04:00
|
|
|
CASE(OP_PUSHCONST) {
|
2014-01-18 08:32:41 -05:00
|
|
|
pic_value self;
|
|
|
|
struct pic_irep *irep;
|
|
|
|
|
|
|
|
self = pic->ci->fp[0];
|
|
|
|
if (! pic_proc_p(self)) {
|
|
|
|
pic_error(pic, "logic flaw");
|
|
|
|
}
|
|
|
|
irep = pic_proc_ptr(self)->u.irep;
|
|
|
|
if (pic_proc_cfunc_p(self)) {
|
|
|
|
pic_error(pic, "logic flaw");
|
|
|
|
}
|
|
|
|
PUSH(irep->pool[c.u.i]);
|
2013-10-20 20:29:56 -04:00
|
|
|
NEXT;
|
|
|
|
}
|
2013-10-12 05:48:35 -04:00
|
|
|
CASE(OP_GREF) {
|
2013-11-01 01:44:26 -04:00
|
|
|
PUSH(pic->globals[c.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-11-01 01:44:26 -04:00
|
|
|
pic->globals[c.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-11-01 01:44:26 -04:00
|
|
|
PUSH(pic->ci->fp[c.u.i]);
|
2013-10-16 04:20:53 -04:00
|
|
|
NEXT;
|
|
|
|
}
|
2013-10-23 14:14:32 -04:00
|
|
|
CASE(OP_LSET) {
|
2013-11-01 01:44:26 -04:00
|
|
|
pic->ci->fp[c.u.i] = POP();
|
2013-10-23 14:14:32 -04:00
|
|
|
NEXT;
|
|
|
|
}
|
2013-10-23 13:04:49 -04:00
|
|
|
CASE(OP_CREF) {
|
2013-11-04 21:32:09 -05:00
|
|
|
int depth = c.u.r.depth;
|
2013-10-23 13:04:49 -04:00
|
|
|
struct pic_env *env;
|
|
|
|
|
2013-10-28 21:16:56 -04:00
|
|
|
env = pic->ci->env;
|
2013-10-23 13:04:49 -04:00
|
|
|
while (depth--) {
|
|
|
|
env = env->up;
|
|
|
|
}
|
2013-11-04 21:32:09 -05:00
|
|
|
PUSH(env->values[c.u.r.idx]);
|
2013-10-23 13:04:49 -04:00
|
|
|
NEXT;
|
|
|
|
}
|
2013-10-23 14:14:32 -04:00
|
|
|
CASE(OP_CSET) {
|
2013-11-04 21:32:09 -05:00
|
|
|
int depth = c.u.r.depth;
|
2013-10-23 14:14:32 -04:00
|
|
|
struct pic_env *env;
|
|
|
|
|
2013-10-28 21:16:56 -04:00
|
|
|
env = pic->ci->env;
|
2013-10-23 14:14:32 -04:00
|
|
|
while (depth--) {
|
|
|
|
env = env->up;
|
|
|
|
}
|
2013-11-04 21:32:09 -05:00
|
|
|
env->values[c.u.r.idx] = POP();
|
2013-10-23 14:14:32 -04:00
|
|
|
NEXT;
|
|
|
|
}
|
2013-10-16 04:42:47 -04:00
|
|
|
CASE(OP_JMP) {
|
2014-02-03 20:40:03 -05:00
|
|
|
pic->ip += c.u.i;
|
2013-10-16 04:42:47 -04:00
|
|
|
JUMP;
|
|
|
|
}
|
|
|
|
CASE(OP_JMPIF) {
|
|
|
|
pic_value v;
|
|
|
|
|
|
|
|
v = POP();
|
|
|
|
if (! pic_false_p(v)) {
|
2014-02-03 20:40:03 -05:00
|
|
|
pic->ip += c.u.i;
|
2013-10-16 04:42:47 -04:00
|
|
|
JUMP;
|
|
|
|
}
|
|
|
|
NEXT;
|
|
|
|
}
|
2014-02-02 00:54:47 -05:00
|
|
|
CASE(OP_NOT) {
|
|
|
|
pic_value v;
|
|
|
|
|
|
|
|
v = pic_false_p(POP()) ? pic_true_value() : pic_false_value();
|
|
|
|
PUSH(v);
|
|
|
|
NEXT;
|
|
|
|
}
|
2013-10-15 06:18:33 -04:00
|
|
|
CASE(OP_CALL) {
|
2013-11-01 01:44:26 -04:00
|
|
|
pic_value x, 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-28 04:45:13 -04:00
|
|
|
L_CALL:
|
2013-11-01 01:44:26 -04:00
|
|
|
x = pic->sp[-c.u.i];
|
|
|
|
if (! pic_proc_p(x)) {
|
2013-11-14 02:52:49 -05:00
|
|
|
#if DEBUG
|
|
|
|
pic_debug(pic, x);
|
|
|
|
#endif
|
2013-10-23 14:38:29 -04:00
|
|
|
pic->errmsg = "invalid application";
|
|
|
|
goto L_RAISE;
|
|
|
|
}
|
2013-11-01 01:44:26 -04:00
|
|
|
proc = pic_proc_ptr(x);
|
2013-10-23 02:55:42 -04:00
|
|
|
|
2013-11-16 23:12:59 -05:00
|
|
|
#if VM_DEBUG
|
|
|
|
puts("== calling proc...");
|
|
|
|
printf(" proc = ");
|
|
|
|
pic_debug(pic, pic_obj_value(proc));
|
|
|
|
puts("");
|
|
|
|
printf(" argv = ");
|
|
|
|
pic_debug(pic, argv);
|
|
|
|
puts("");
|
|
|
|
if (! proc->cfunc_p) {
|
|
|
|
printf(" irep = ");
|
2014-01-18 02:23:12 -05:00
|
|
|
pic_dump_irep(pic, proc->u.irep);
|
2013-11-16 23:12:59 -05:00
|
|
|
}
|
|
|
|
else {
|
2014-01-05 04:10:33 -05:00
|
|
|
printf(" cfunc = %p\n", (void *)proc->u.cfunc);
|
2013-11-16 23:12:59 -05:00
|
|
|
}
|
|
|
|
puts("");
|
|
|
|
#endif
|
|
|
|
|
2013-10-15 10:29:34 -04:00
|
|
|
ci = PUSHCI();
|
2013-11-01 01:44:26 -04:00
|
|
|
ci->argc = c.u.i;
|
2014-02-03 20:46:36 -05:00
|
|
|
ci->ip = pic->ip;
|
2013-11-01 01:44:26 -04:00
|
|
|
ci->fp = pic->sp - c.u.i;
|
2013-10-29 03:39:57 -04:00
|
|
|
ci->env = NULL;
|
2013-11-01 01:44:26 -04:00
|
|
|
if (pic_proc_cfunc_p(x)) {
|
2013-10-16 00:24:19 -04:00
|
|
|
v = proc->u.cfunc(pic);
|
2014-02-03 20:40:16 -05:00
|
|
|
ci = POPCI();
|
2014-02-03 20:46:36 -05:00
|
|
|
pic->ip = ci->ip;
|
2013-10-23 02:55:42 -04:00
|
|
|
pic->sp = ci->fp;
|
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-27 05:13:36 -04:00
|
|
|
pic_value rest;
|
2013-10-23 13:51:02 -04:00
|
|
|
|
2013-10-23 11:09:40 -04:00
|
|
|
if (ci->argc != proc->u.irep->argc) {
|
2013-10-27 05:13:36 -04:00
|
|
|
if (! (proc->u.irep->varg && ci->argc >= proc->u.irep->argc)) {
|
|
|
|
pic->errmsg = "wrong number of arguments";
|
|
|
|
goto L_RAISE;
|
|
|
|
}
|
2013-11-01 02:09:20 -04:00
|
|
|
}
|
|
|
|
/* prepare rest args */
|
|
|
|
if (proc->u.irep->varg) {
|
2013-10-27 05:13:36 -04:00
|
|
|
rest = pic_nil_value();
|
|
|
|
for (i = 0; i < ci->argc - proc->u.irep->argc; ++i) {
|
|
|
|
pic_gc_protect(pic, v = POP());
|
|
|
|
rest = pic_cons(pic, v, rest);
|
|
|
|
}
|
|
|
|
PUSH(rest);
|
2013-10-23 11:09:40 -04:00
|
|
|
}
|
2013-11-17 03:24:37 -05:00
|
|
|
/* prepare local variable area */
|
|
|
|
if (proc->u.irep->localc > 0) {
|
|
|
|
int l = proc->u.irep->localc;
|
|
|
|
if (proc->u.irep->varg) {
|
|
|
|
--l;
|
|
|
|
}
|
|
|
|
for (i = 0; i < l; ++i) {
|
|
|
|
PUSH(pic_undef_value());
|
|
|
|
}
|
|
|
|
}
|
2013-10-28 21:16:56 -04:00
|
|
|
|
|
|
|
/* prepare env */
|
2014-01-27 08:24:12 -05:00
|
|
|
ci->env = (struct pic_env *)pic_obj_alloc(pic, sizeof(struct pic_env), PIC_TT_ENV);
|
|
|
|
ci->env->up = proc->env;
|
|
|
|
ci->env->valuec = proc->u.irep->cv_num;
|
|
|
|
ci->env->values = (pic_value *)pic_calloc(pic, ci->env->valuec, sizeof(pic_value));
|
|
|
|
for (i = 0; i < ci->env->valuec; ++i) {
|
|
|
|
ci->env->values[i] = ci->fp[proc->u.irep->cv_tbl[i]];
|
|
|
|
}
|
2013-10-28 21:16:56 -04:00
|
|
|
|
2014-02-03 20:40:03 -05:00
|
|
|
pic->ip = proc->u.irep->code;
|
2013-10-16 02:30:52 -04:00
|
|
|
pic_gc_arena_restore(pic, ai);
|
|
|
|
JUMP;
|
2013-10-15 22:28:57 -04:00
|
|
|
}
|
2013-10-16 02:30:52 -04:00
|
|
|
}
|
2013-10-29 21:03:46 -04:00
|
|
|
CASE(OP_TAILCALL) {
|
2014-01-30 04:14:33 -05:00
|
|
|
int i, argc;
|
2013-10-29 21:03:46 -04:00
|
|
|
pic_value *argv;
|
|
|
|
|
2013-11-01 01:44:26 -04:00
|
|
|
argc = c.u.i;
|
2013-10-29 21:03:46 -04:00
|
|
|
argv = pic->sp - argc;
|
|
|
|
for (i = 0; i < argc; ++i) {
|
|
|
|
pic->ci->fp[i] = argv[i];
|
|
|
|
}
|
|
|
|
pic->sp = pic->ci->fp + argc;
|
2014-02-03 20:46:36 -05:00
|
|
|
pic->ip = POPCI()->ip;
|
2013-10-29 21:03:46 -04:00
|
|
|
|
2013-11-01 02:09:20 -04:00
|
|
|
/* c is not changed */
|
2013-10-29 21:03:46 -04:00
|
|
|
goto L_CALL;
|
|
|
|
}
|
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();
|
2014-02-03 20:46:36 -05:00
|
|
|
pic->ip = ci->ip;
|
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) {
|
2014-01-18 07:48:50 -05:00
|
|
|
pic_value self;
|
|
|
|
struct pic_irep *irep;
|
2013-10-15 22:32:30 -04:00
|
|
|
struct pic_proc *proc;
|
2013-10-23 13:02:07 -04:00
|
|
|
|
2014-01-18 07:48:50 -05:00
|
|
|
self = pic->ci->fp[0];
|
|
|
|
if (! pic_proc_p(self)) {
|
|
|
|
pic_error(pic, "logic flaw");
|
|
|
|
}
|
|
|
|
irep = pic_proc_ptr(self)->u.irep;
|
|
|
|
if (pic_proc_cfunc_p(self)) {
|
|
|
|
pic_error(pic, "logic flaw");
|
|
|
|
}
|
|
|
|
proc = pic_proc_new_irep(pic, irep->irep[c.u.i], pic->ci->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-27 11:21:24 -04:00
|
|
|
|
2013-11-09 02:32:13 -05:00
|
|
|
#define DEFINE_ARITH_OP(opcode, op, guard) \
|
2013-10-27 11:21:24 -04:00
|
|
|
CASE(opcode) { \
|
|
|
|
pic_value a, b; \
|
|
|
|
b = POP(); \
|
|
|
|
a = POP(); \
|
|
|
|
if (pic_int_p(a) && pic_int_p(b)) { \
|
2013-10-28 08:26:39 -04:00
|
|
|
double f = (double)pic_int(a) op (double)pic_int(b); \
|
2013-11-09 02:32:13 -05:00
|
|
|
if (INT_MIN <= f && f <= INT_MAX && (guard)) { \
|
2013-10-28 08:26:39 -04:00
|
|
|
PUSH(pic_int_value((int)f)); \
|
|
|
|
} \
|
|
|
|
else { \
|
|
|
|
PUSH(pic_float_value(f)); \
|
|
|
|
} \
|
2013-10-27 11:21:24 -04:00
|
|
|
} \
|
|
|
|
else if (pic_float_p(a) && pic_float_p(b)) { \
|
|
|
|
PUSH(pic_float_value(pic_float(a) op pic_float(b))); \
|
|
|
|
} \
|
|
|
|
else if (pic_int_p(a) && pic_float_p(b)) { \
|
|
|
|
PUSH(pic_float_value(pic_int(a) op pic_float(b))); \
|
|
|
|
} \
|
|
|
|
else if (pic_float_p(a) && pic_int_p(b)) { \
|
|
|
|
PUSH(pic_float_value(pic_float(a) op pic_int(b))); \
|
|
|
|
} \
|
|
|
|
else { \
|
|
|
|
pic->errmsg = #op " got non-number operands"; \
|
|
|
|
goto L_RAISE; \
|
|
|
|
} \
|
|
|
|
NEXT; \
|
2013-10-15 08:29:07 -04:00
|
|
|
}
|
2013-10-27 11:21:24 -04:00
|
|
|
|
2013-11-09 02:32:13 -05:00
|
|
|
DEFINE_ARITH_OP(OP_ADD, +, true);
|
|
|
|
DEFINE_ARITH_OP(OP_SUB, -, true);
|
|
|
|
DEFINE_ARITH_OP(OP_MUL, *, true);
|
|
|
|
DEFINE_ARITH_OP(OP_DIV, /, f == round(f));
|
2013-10-27 11:21:24 -04:00
|
|
|
|
2013-11-06 22:17:37 -05:00
|
|
|
CASE(OP_MINUS) {
|
|
|
|
pic_value n;
|
|
|
|
n = POP();
|
|
|
|
if (pic_int_p(n)) {
|
|
|
|
PUSH(pic_int_value(-pic_int(n)));
|
|
|
|
}
|
|
|
|
else if (pic_float_p(n)) {
|
|
|
|
PUSH(pic_float_value(-pic_float(n)));
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
pic->errmsg = "unary - got a non-number operand";
|
|
|
|
}
|
|
|
|
NEXT;
|
|
|
|
}
|
|
|
|
|
2013-10-27 11:21:24 -04:00
|
|
|
#define DEFINE_COMP_OP(opcode, op) \
|
|
|
|
CASE(opcode) { \
|
|
|
|
pic_value a, b; \
|
|
|
|
b = POP(); \
|
|
|
|
a = POP(); \
|
|
|
|
if (pic_int_p(a) && pic_int_p(b)) { \
|
|
|
|
PUSH(pic_bool_value(pic_int(a) op pic_int(b))); \
|
|
|
|
} \
|
|
|
|
else if (pic_float_p(a) && pic_float_p(b)) { \
|
|
|
|
PUSH(pic_bool_value(pic_float(a) op pic_float(b))); \
|
|
|
|
} \
|
2013-11-13 03:40:31 -05:00
|
|
|
else if (pic_int_p(a) && pic_float_p(b)) { \
|
2013-10-27 11:21:24 -04:00
|
|
|
PUSH(pic_bool_value(pic_int(a) op pic_float(b))); \
|
|
|
|
} \
|
|
|
|
else if (pic_float_p(a) && pic_int_p(b)) { \
|
|
|
|
PUSH(pic_bool_value(pic_float(a) op pic_int(b))); \
|
|
|
|
} \
|
|
|
|
else { \
|
|
|
|
pic->errmsg = #op " got non-number operands"; \
|
|
|
|
goto L_RAISE; \
|
|
|
|
} \
|
|
|
|
NEXT; \
|
2013-10-24 08:10:13 -04:00
|
|
|
}
|
2013-10-27 11:21:24 -04:00
|
|
|
|
|
|
|
DEFINE_COMP_OP(OP_EQ, ==);
|
|
|
|
DEFINE_COMP_OP(OP_LT, <);
|
|
|
|
DEFINE_COMP_OP(OP_LE, <=);
|
|
|
|
|
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-23 02:55:42 -04:00
|
|
|
|
2013-11-14 05:25:03 -05:00
|
|
|
pic->jmp = prev_jmp;
|
2013-10-20 10:30:01 -04:00
|
|
|
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**");
|
2014-01-05 04:10:33 -05:00
|
|
|
printf("stbase\t= %p\nsp\t= %p\n", (void *)pic->stbase, (void *)pic->sp);
|
|
|
|
printf("cibase\t= %p\nci\t= %p\n", (void *)pic->cibase, (void *)pic->ci);
|
2013-10-29 21:05:21 -04:00
|
|
|
if (pic->stbase < pic->sp) {
|
2013-10-20 04:26:18 -04:00
|
|
|
pic_value *sp;
|
|
|
|
printf("* stack trace:");
|
|
|
|
for (sp = pic->stbase; pic->sp != sp; ++sp) {
|
|
|
|
pic_debug(pic, *sp);
|
|
|
|
puts("");
|
|
|
|
}
|
|
|
|
}
|
2013-10-29 21:05:21 -04:00
|
|
|
if (pic->stbase > pic->sp) {
|
|
|
|
puts("*** stack underflow!");
|
|
|
|
}
|
2013-10-16 02:30:52 -04:00
|
|
|
#endif
|
|
|
|
|
2013-11-01 05:56:17 -04:00
|
|
|
pic_gc_protect(pic, val);
|
|
|
|
|
2013-10-20 04:26:18 -04:00
|
|
|
return val;
|
|
|
|
}
|
|
|
|
} VM_LOOP_END;
|
2013-10-12 01:40:27 -04:00
|
|
|
}
|