picrin/lib/proc.c

923 lines
22 KiB
C
Raw Normal View History

2014-08-25 00:38:09 -04:00
/**
* See Copyright Notice in picrin.h
*/
#include "picrin.h"
2017-03-28 10:09:40 -04:00
#include "object.h"
#include "state.h"
#include "vm.h"
2016-02-06 10:09:40 -05:00
2017-03-28 11:03:23 -04:00
pic_value
pic_lambda(pic_state *pic, pic_func_t f, int n, ...)
{
pic_value proc;
va_list ap;
va_start(ap, n);
proc = pic_vlambda(pic, f, n, ap);
va_end(ap);
return proc;
}
pic_value
pic_vlambda(pic_state *pic, pic_func_t f, int n, va_list ap)
{
pic_value *env = pic_alloca(pic, sizeof(pic_value) * n);
int i;
for (i = 0; i < n; ++i) {
env[i] = va_arg(ap, pic_value);
}
return pic_make_proc(pic, f, n, env);
}
2016-02-06 10:09:40 -05:00
2016-02-22 14:03:42 -05:00
PIC_NORETURN static void
arg_error(pic_state *pic, int actual, bool varg, int expected)
{
const char *msg;
2017-03-28 10:31:15 -04:00
msg = pic_str(pic, pic_strf_value(pic, "wrong number of arguments (%d for %s%d)", actual, (varg ? "at least " : ""), expected), NULL);
2016-02-22 14:03:42 -05:00
pic_error(pic, msg, 0);
}
2017-03-28 11:03:23 -04:00
#define GET_PROC(pic) (pic->ci->fp[0])
#define GET_ARG(pic,n) (pic->ci->fp[(n)+1])
2016-02-06 10:09:40 -05: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
* c char * char
* z char ** c string
2016-02-20 07:16:10 -05:00
* b unsigned char *, int * bytevector
* u void **, const pic_data_type * user data type
2016-02-20 01:31:14 -05:00
* m pic_value * symbol
2016-02-20 05:47:46 -05:00
* v pic_value * vector
* s pic_value * string
* l pic_value * lambda
* p pic_value * port
* d pic_value * dictionary
* r pic_value * record
2016-02-06 10:09:40 -05:00
*
2016-02-20 07:16:10 -05:00
* + aliasing operator
2016-02-06 10:09:40 -05:00
* | optional operator
2016-02-20 03:27:13 -05:00
* * int *, pic_value ** variable length operator
* ---- ---- ----
2016-02-06 10:09:40 -05:00
*/
int
pic_get_args(pic_state *pic, const char *format, ...)
{
char c;
2016-02-20 07:16:10 -05:00
const char *p = format;
int paramc = 0, optc = 0;
2017-03-28 11:03:23 -04:00
bool proc = 0, rest = 0, opt = 0;
2016-02-06 10:09:40 -05:00
int i, argc = pic->ci->argc - 1;
va_list ap;
/* parse format */
2016-02-20 07:16:10 -05:00
if ((c = *p) != '\0') {
if (c == '&') {
2016-02-20 07:16:10 -05:00
proc = 1;
p++;
2016-02-06 10:09:40 -05:00
}
2016-02-20 07:16:10 -05:00
while ((c = *p++) != '\0') {
if (c == '+')
continue;
if (c == '|') {
2016-02-20 07:16:10 -05:00
opt = 1; break;
} else if (c == '*') {
2016-02-20 07:16:10 -05:00
rest = 1; break;
}
2016-02-20 07:16:10 -05:00
paramc++;
2016-02-06 10:09:40 -05:00
}
2016-02-20 07:16:10 -05:00
if (opt) {
while ((c = *p++) != '\0') {
if (c == '+')
continue;
if (c == '*') {
rest = 1; break;
}
optc++;
}
2016-02-06 10:09:40 -05:00
}
2016-02-20 07:16:10 -05:00
if (rest) c = *p++;
assert(opt <= optc); /* at least 1 char after '|'? */
assert(c == '\0'); /* no extra chars? */
2016-02-06 10:09:40 -05:00
}
if (argc < paramc || (paramc + optc < argc && ! rest)) {
2016-02-22 14:03:42 -05:00
arg_error(pic, argc, rest, paramc);
2016-02-06 10:09:40 -05:00
}
va_start(ap, format);
/* dispatch */
if (proc) {
2016-02-19 10:03:16 -05:00
pic_value *proc;
2016-02-19 10:03:16 -05:00
proc = va_arg(ap, pic_value *);
2017-03-28 11:03:23 -04:00
*proc = GET_PROC(pic);
2016-02-20 07:16:10 -05:00
format++; /* skip '&' */
}
2017-03-28 18:11:27 -04:00
for (i = 0; i < argc && i < paramc + optc; ++i) {
2016-02-06 10:09:40 -05:00
c = *format++;
if (c == '|') {
c = *format++;
}
2016-02-06 10:09:40 -05:00
switch (c) {
case 'o': {
pic_value *p;
p = va_arg(ap, pic_value*);
2017-03-28 11:03:23 -04:00
*p = GET_ARG(pic, i);
2016-02-06 10:09:40 -05:00
break;
}
2016-02-20 07:16:10 -05:00
case 'u': {
void **data;
const pic_data_type *type;
pic_value v;
data = va_arg(ap, void **);
type = va_arg(ap, const pic_data_type *);
2017-03-28 11:03:23 -04:00
v = GET_ARG(pic, i);
2016-02-20 07:16:10 -05:00
if (pic_data_p(pic, v, type)) {
*data = pic_data(pic, v);
}
else {
2016-02-22 14:03:42 -05:00
const char *msg;
2017-03-28 10:31:15 -04:00
msg = pic_str(pic, pic_strf_value(pic, "pic_get_args: data type \"%s\" required", type->type_name), NULL);
2016-02-22 14:03:42 -05:00
pic_error(pic, msg, 1, v);
2016-02-20 07:16:10 -05:00
}
break;
}
case 'b': {
unsigned char **buf;
int *len;
pic_value v;
buf = va_arg(ap, unsigned char **);
len = va_arg(ap, int *);
2017-03-28 11:03:23 -04:00
v = GET_ARG(pic, i);
2016-02-20 07:16:10 -05:00
if (pic_blob_p(pic, v)) {
unsigned char *tmp = pic_blob(pic, v, len);
if (buf) *buf = tmp;
}
else {
2016-02-22 14:03:42 -05:00
pic_error(pic, "pic_get_args: bytevector required", 1, v);
2016-02-20 07:16:10 -05:00
}
break;
}
2016-02-06 10:09:40 -05: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); \
\
2017-03-28 11:03:23 -04:00
v = GET_ARG(pic, i); \
switch (pic_type(pic, v)) { \
2016-02-22 14:03:42 -05:00
case PIC_TYPE_FLOAT: \
*n = pic_float(pic, v); \
2016-02-06 10:09:40 -05:00
*e = false; \
break; \
2016-02-22 14:03:42 -05:00
case PIC_TYPE_INT: \
*n = pic_int(pic, v); \
2016-02-06 10:09:40 -05:00
*e = true; \
break; \
default: \
2016-02-22 14:03:42 -05:00
pic_error(pic, "pic_get_args: float or int required", 1, v); \
2016-02-06 10:09:40 -05:00
} \
break; \
}
NUM_CASE('i', 'I', int)
NUM_CASE('f', 'F', double)
#define VAL_CASE(c, type, ctype, conv) \
case c: { \
ctype *ptr; \
pic_value v; \
\
ptr = va_arg(ap, ctype *); \
2017-03-28 11:03:23 -04:00
v = GET_ARG(pic, i); \
if (pic_## type ##_p(pic, v)) { \
2016-02-06 10:09:40 -05:00
*ptr = conv; \
} \
else { \
2016-02-22 14:03:42 -05:00
pic_error(pic, "pic_get_args: " #type " required", 1, v); \
2016-02-06 10:09:40 -05:00
} \
break; \
}
VAL_CASE('c', char, char, pic_char(pic, v))
2017-03-28 10:31:15 -04:00
VAL_CASE('z', str, const char *, pic_str(pic, v, NULL))
2016-02-06 10:09:40 -05:00
2016-02-19 05:08:45 -05:00
#define OBJ_CASE(c, type) VAL_CASE(c, type, pic_value, v)
2016-02-20 01:31:14 -05:00
OBJ_CASE('m', sym)
2016-02-19 13:26:52 -05:00
OBJ_CASE('s', str)
2016-02-19 10:03:16 -05:00
OBJ_CASE('l', proc)
2016-02-19 07:56:45 -05:00
OBJ_CASE('v', vec)
2016-02-19 05:08:45 -05:00
OBJ_CASE('d', dict)
2017-03-28 18:11:27 -04:00
#define pic_port_p(pic,v) pic_port_p(pic,v,NULL)
2016-02-20 02:51:24 -05:00
OBJ_CASE('p', port)
2017-03-28 18:11:27 -04:00
#undef pic_port_p
2016-02-20 03:27:13 -05:00
OBJ_CASE('r', rec)
2016-02-19 05:08:45 -05:00
2016-02-06 10:09:40 -05:00
default:
2016-02-22 14:03:42 -05:00
pic_error(pic, "pic_get_args: invalid argument specifier given", 1, pic_char_value(pic, c));
2016-02-06 10:09:40 -05:00
}
2016-02-20 07:16:10 -05:00
2016-03-03 05:55:27 -05:00
if (*format == '+') {
2016-02-20 07:16:10 -05:00
pic_value *p;
2016-03-03 05:55:27 -05:00
format++;
2017-03-28 11:03:23 -04:00
p = va_arg(ap, pic_value *);
*p = GET_ARG(pic, i);
2016-02-20 07:16:10 -05:00
}
2016-02-06 10:09:40 -05:00
}
if (rest) {
int *n;
pic_value **argv;
2016-02-06 10:09:40 -05:00
n = va_arg(ap, int *);
argv = va_arg(ap, pic_value **);
2017-03-28 11:03:23 -04:00
*n = argc - i;
*argv = &GET_ARG(pic, i);
2016-02-06 10:09:40 -05:00
}
2016-02-06 10:09:40 -05:00
va_end(ap);
2016-02-06 10:09:40 -05:00
return argc;
}
2017-03-28 11:03:23 -04:00
pic_value
pic_closure_ref(pic_state *pic, int n)
2016-02-06 10:09:40 -05:00
{
2017-03-28 11:03:23 -04:00
pic_value self = GET_PROC(pic);
2016-02-20 01:31:14 -05:00
2017-03-28 11:03:23 -04:00
assert(pic_func_p(pic, self));
if (n < 0 || pic_proc_ptr(pic, self)->u.f.localc <= n) {
pic_error(pic, "pic_closure_ref: index out of range", 1, pic_int_value(pic, n));
2016-02-06 10:09:40 -05:00
}
2017-03-28 11:03:23 -04:00
return pic_proc_ptr(pic, self)->locals[n];
2016-02-06 10:09:40 -05:00
}
2017-03-28 11:03:23 -04:00
void
pic_closure_set(pic_state *pic, int n, pic_value v)
2016-02-06 10:09:40 -05:00
{
2017-03-28 11:03:23 -04:00
pic_value self = GET_PROC(pic);
assert(pic_func_p(pic, self));
if (n < 0 || pic_proc_ptr(pic, self)->u.f.localc <= n) {
pic_error(pic, "pic_closure_ref: index out of range", 1, pic_int_value(pic, n));
2016-02-20 03:27:13 -05:00
}
2017-03-28 11:03:23 -04:00
pic_proc_ptr(pic, self)->locals[n] = v;
2016-02-06 10:09:40 -05:00
}
static void
vm_push_cxt(pic_state *pic)
{
2016-02-21 06:32:00 -05:00
struct callinfo *ci = pic->ci;
2016-02-06 10:09:40 -05:00
2016-02-21 06:32:00 -05:00
ci->cxt = (struct context *)pic_obj_alloc(pic, offsetof(struct context, storage) + sizeof(pic_value) * ci->regc, PIC_TYPE_CXT);
2016-02-06 10:09:40 -05:00
ci->cxt->up = ci->up;
ci->cxt->regc = ci->regc;
ci->cxt->regs = ci->regs;
}
static void
2016-02-21 06:32:00 -05:00
vm_tear_off(struct callinfo *ci)
2016-02-06 10:09:40 -05:00
{
2016-02-21 06:32:00 -05:00
struct context *cxt;
2016-02-06 10:09:40 -05:00
int i;
assert(ci->cxt != NULL);
cxt = ci->cxt;
if (cxt->regs == cxt->storage) {
return; /* is torn off */
}
for (i = 0; i < cxt->regc; ++i) {
cxt->storage[i] = cxt->regs[i];
}
cxt->regs = cxt->storage;
}
void
pic_vm_tear_off(pic_state *pic)
{
2016-02-21 06:32:00 -05:00
struct callinfo *ci;
2016-02-06 10:09:40 -05:00
for (ci = pic->ci; ci > pic->cibase; ci--) {
if (ci->cxt != NULL) {
vm_tear_off(ci);
}
}
}
#if PIC_DIRECT_THREADED_VM
# define VM_LOOP JUMP;
2016-02-21 06:13:05 -05:00
# define CASE(x) L_##x:
2016-02-06 10:09:40 -05:00
# 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
#define PUSH(v) (*pic->sp++ = (v))
#define POP() (*--pic->sp)
#define PUSHCI() (++pic->ci)
#define POPCI() (pic->ci--)
/* for arithmetic instructions */
pic_value pic_add(pic_state *, pic_value, pic_value);
pic_value pic_sub(pic_state *, pic_value, pic_value);
pic_value pic_mul(pic_state *, pic_value, pic_value);
pic_value pic_div(pic_state *, pic_value, pic_value);
bool pic_eq(pic_state *, pic_value, pic_value);
bool pic_lt(pic_state *, pic_value, pic_value);
bool pic_le(pic_state *, pic_value, pic_value);
bool pic_gt(pic_state *, pic_value, pic_value);
bool pic_ge(pic_state *, pic_value, pic_value);
2016-02-06 10:09:40 -05:00
pic_value
2016-02-19 10:03:16 -05:00
pic_apply(pic_state *pic, pic_value proc, int argc, pic_value *argv)
2016-02-06 10:09:40 -05:00
{
2016-02-21 06:32:00 -05:00
struct code c;
2016-02-19 02:17:13 -05:00
size_t ai = pic_enter(pic);
2016-02-21 06:32:00 -05:00
struct code boot[2];
2016-02-06 10:09:40 -05:00
int i;
#if PIC_DIRECT_THREADED_VM
static const void *oplabels[] = {
&&L_OP_NOP, &&L_OP_POP, &&L_OP_PUSHUNDEF, &&L_OP_PUSHNIL, &&L_OP_PUSHTRUE,
&&L_OP_PUSHFALSE, &&L_OP_PUSHINT, &&L_OP_PUSHFLOAT,
&&L_OP_PUSHCHAR, &&L_OP_PUSHEOF, &&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_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,
&&L_OP_SYMBOLP, &&L_OP_PAIRP,
&&L_OP_ADD, &&L_OP_SUB, &&L_OP_MUL, &&L_OP_DIV,
&&L_OP_EQ, &&L_OP_LT, &&L_OP_LE, &&L_OP_GT, &&L_OP_GE, &&L_OP_STOP
};
#endif
2016-02-19 10:03:16 -05:00
PUSH(proc);
2016-02-06 10:09:40 -05:00
for (i = 0; i < argc; ++i) {
PUSH(argv[i]);
}
/* boot! */
boot[0].insn = OP_CALL;
boot[0].a = argc + 1;
boot[1].insn = OP_STOP;
pic->ip = boot;
VM_LOOP {
CASE(OP_NOP) {
NEXT;
}
CASE(OP_POP) {
(void)(POP());
NEXT;
}
CASE(OP_PUSHUNDEF) {
PUSH(pic_undef_value(pic));
2016-02-06 10:09:40 -05:00
NEXT;
}
CASE(OP_PUSHNIL) {
PUSH(pic_nil_value(pic));
2016-02-06 10:09:40 -05:00
NEXT;
}
CASE(OP_PUSHTRUE) {
PUSH(pic_true_value(pic));
2016-02-06 10:09:40 -05:00
NEXT;
}
CASE(OP_PUSHFALSE) {
PUSH(pic_false_value(pic));
2016-02-06 10:09:40 -05:00
NEXT;
}
CASE(OP_PUSHINT) {
PUSH(pic_int_value(pic, pic->ci->irep->ints[c.a]));
2016-02-06 10:09:40 -05:00
NEXT;
}
CASE(OP_PUSHFLOAT) {
PUSH(pic_float_value(pic, pic->ci->irep->nums[c.a]));
2016-02-06 10:09:40 -05:00
NEXT;
}
CASE(OP_PUSHCHAR) {
PUSH(pic_char_value(pic, pic->ci->irep->ints[c.a]));
2016-02-06 10:09:40 -05:00
NEXT;
}
CASE(OP_PUSHEOF) {
PUSH(pic_eof_object(pic));
2016-02-06 10:09:40 -05:00
NEXT;
}
CASE(OP_PUSHCONST) {
PUSH(obj_value(pic, pic->ci->irep->pool[c.a]));
2016-02-06 10:09:40 -05:00
NEXT;
}
CASE(OP_GREF) {
PUSH(pic_global_ref(pic, obj_value(pic, pic->ci->irep->pool[c.a])));
2016-02-06 10:09:40 -05:00
NEXT;
}
CASE(OP_GSET) {
pic_global_set(pic, obj_value(pic, pic->ci->irep->pool[c.a]), POP());
PUSH(pic_undef_value(pic));
2016-02-06 10:09:40 -05:00
NEXT;
}
CASE(OP_LREF) {
2016-02-21 06:32:00 -05:00
struct callinfo *ci = pic->ci;
struct irep *irep = ci->irep;
2016-02-06 10:09:40 -05:00
if (ci->cxt != NULL && ci->cxt->regs == ci->cxt->storage) {
if (c.a >= irep->argc + irep->localc) {
PUSH(ci->cxt->regs[c.a - (ci->regs - ci->fp)]);
NEXT;
}
}
PUSH(pic->ci->fp[c.a]);
NEXT;
}
CASE(OP_LSET) {
2016-02-21 06:32:00 -05:00
struct callinfo *ci = pic->ci;
struct irep *irep = ci->irep;
2016-02-06 10:09:40 -05:00
if (ci->cxt != NULL && ci->cxt->regs == ci->cxt->storage) {
if (c.a >= irep->argc + irep->localc) {
ci->cxt->regs[c.a - (ci->regs - ci->fp)] = POP();
PUSH(pic_undef_value(pic));
2016-02-06 10:09:40 -05:00
NEXT;
}
}
pic->ci->fp[c.a] = POP();
PUSH(pic_undef_value(pic));
2016-02-06 10:09:40 -05:00
NEXT;
}
CASE(OP_CREF) {
int depth = c.a;
2016-02-21 06:32:00 -05:00
struct context *cxt;
2016-02-06 10:09:40 -05:00
cxt = pic->ci->up;
while (--depth) {
cxt = cxt->up;
}
PUSH(cxt->regs[c.b]);
NEXT;
}
CASE(OP_CSET) {
int depth = c.a;
2016-02-21 06:32:00 -05:00
struct context *cxt;
2016-02-06 10:09:40 -05:00
cxt = pic->ci->up;
while (--depth) {
cxt = cxt->up;
}
cxt->regs[c.b] = POP();
PUSH(pic_undef_value(pic));
2016-02-06 10:09:40 -05:00
NEXT;
}
CASE(OP_JMP) {
pic->ip += c.a;
JUMP;
}
CASE(OP_JMPIF) {
pic_value v;
v = POP();
if (! pic_false_p(pic, v)) {
2016-02-06 10:09:40 -05:00
pic->ip += c.a;
JUMP;
}
NEXT;
}
CASE(OP_CALL) {
pic_value x, v;
2016-02-21 06:32:00 -05:00
struct callinfo *ci;
struct proc *proc;
2016-02-06 10:09:40 -05:00
if (c.a == -1) {
pic->sp += pic->ci[1].retc - 1;
c.a = pic->ci[1].retc + 1;
}
L_CALL:
x = pic->sp[-c.a];
if (! pic_proc_p(pic, x)) {
2016-02-22 14:03:42 -05:00
pic_error(pic, "invalid application", 1, x);
2016-02-06 10:09:40 -05:00
}
2016-02-19 10:03:16 -05:00
proc = pic_proc_ptr(pic, x);
2016-02-06 10:09:40 -05:00
if (pic->sp >= pic->stend) {
pic_panic(pic, "VM stack overflow");
}
ci = PUSHCI();
ci->argc = c.a;
ci->retc = 1;
ci->ip = pic->ip;
ci->fp = pic->sp - c.a;
ci->irep = NULL;
ci->cxt = NULL;
2016-02-21 06:42:41 -05:00
if (proc->tt == PIC_TYPE_FUNC) {
2016-02-06 10:09:40 -05:00
/* invoke! */
v = proc->u.f.func(pic);
pic->sp[0] = v;
pic->sp += pic->ci->retc;
2016-02-19 02:17:13 -05:00
pic_leave(pic, ai);
2016-02-06 10:09:40 -05:00
goto L_RET;
}
else {
2016-02-21 06:32:00 -05:00
struct irep *irep = proc->u.i.irep;
2016-02-06 10:09:40 -05:00
int i;
pic_value rest;
ci->irep = irep;
if (ci->argc != irep->argc) {
if (! (irep->varg && ci->argc >= irep->argc)) {
2016-02-22 14:03:42 -05:00
arg_error(pic, ci->argc - 1, irep->varg, irep->argc - 1);
2016-02-06 10:09:40 -05:00
}
}
/* prepare rest args */
if (irep->varg) {
rest = pic_nil_value(pic);
2016-02-06 10:09:40 -05:00
for (i = 0; i < ci->argc - irep->argc; ++i) {
2016-02-19 02:17:13 -05:00
pic_protect(pic, v = POP());
2016-02-06 10:09:40 -05:00
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(pic));
2016-02-06 10:09:40 -05:00
}
}
/* prepare cxt */
ci->up = proc->u.i.cxt;
ci->regc = irep->capturec;
ci->regs = ci->fp + irep->argc + irep->localc;
2016-02-07 23:51:41 -05:00
pic->ip = irep->code;
2016-02-19 02:17:13 -05:00
pic_leave(pic, ai);
2016-02-06 10:09:40 -05:00
JUMP;
}
}
CASE(OP_TAILCALL) {
int i, argc;
pic_value *argv;
2016-02-21 06:32:00 -05:00
struct callinfo *ci;
2016-02-06 10:09:40 -05:00
if (pic->ci->cxt != NULL) {
vm_tear_off(pic->ci);
}
if (c.a == -1) {
pic->sp += pic->ci[1].retc - 1;
c.a = pic->ci[1].retc + 1;
}
argc = c.a;
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;
2016-02-21 06:32:00 -05:00
struct callinfo *ci;
2016-02-06 10:09:40 -05:00
if (pic->ci->cxt != NULL) {
vm_tear_off(pic->ci);
}
assert(pic->ci->retc == 1);
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) {
if (pic->ci->cxt == NULL) {
vm_push_cxt(pic);
}
2016-02-19 10:03:16 -05:00
PUSH(pic_make_proc_irep(pic, pic->ci->irep->irep[c.a], pic->ci->cxt));
2016-02-19 02:17:13 -05:00
pic_leave(pic, ai);
2016-02-06 10:09:40 -05:00
NEXT;
}
CASE(OP_CONS) {
pic_value a, b;
2016-02-19 02:17:13 -05:00
pic_protect(pic, b = POP());
pic_protect(pic, a = POP());
2016-02-06 10:09:40 -05:00
PUSH(pic_cons(pic, a, b));
2016-02-19 02:17:13 -05:00
pic_leave(pic, ai);
2016-02-06 10:09:40 -05:00
NEXT;
}
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;
}
CASE(OP_NILP) {
pic_value p;
p = POP();
PUSH(pic_bool_value(pic, pic_nil_p(pic, p)));
2016-02-06 10:09:40 -05:00
NEXT;
}
CASE(OP_SYMBOLP) {
pic_value p;
p = POP();
PUSH(pic_bool_value(pic, pic_sym_p(pic, p)));
2016-02-06 10:09:40 -05:00
NEXT;
}
CASE(OP_PAIRP) {
pic_value p;
p = POP();
PUSH(pic_bool_value(pic, pic_pair_p(pic, p)));
2016-02-06 10:09:40 -05:00
NEXT;
}
CASE(OP_NOT) {
pic_value v;
v = pic_false_p(pic, POP()) ? pic_true_value(pic) : pic_false_value(pic);
2016-02-06 10:09:40 -05:00
PUSH(v);
NEXT;
}
CASE(OP_ADD) {
pic_value a, b;
b = POP();
a = POP();
PUSH(pic_add(pic, a, b));
NEXT;
}
CASE(OP_SUB) {
pic_value a, b;
b = POP();
a = POP();
PUSH(pic_sub(pic, a, b));
NEXT;
}
CASE(OP_MUL) {
pic_value a, b;
b = POP();
a = POP();
PUSH(pic_mul(pic, a, b));
NEXT;
}
CASE(OP_DIV) {
pic_value a, b;
b = POP();
a = POP();
PUSH(pic_div(pic, a, b));
NEXT;
}
CASE(OP_EQ) {
pic_value a, b;
b = POP();
a = POP();
PUSH(pic_bool_value(pic, pic_eq(pic, a, b)));
2016-02-06 10:09:40 -05:00
NEXT;
}
CASE(OP_LE) {
pic_value a, b;
b = POP();
a = POP();
PUSH(pic_bool_value(pic, pic_le(pic, a, b)));
2016-02-06 10:09:40 -05:00
NEXT;
}
CASE(OP_LT) {
pic_value a, b;
b = POP();
a = POP();
PUSH(pic_bool_value(pic, pic_lt(pic, a, b)));
2016-02-06 10:09:40 -05:00
NEXT;
}
CASE(OP_GE) {
pic_value a, b;
b = POP();
a = POP();
PUSH(pic_bool_value(pic, pic_ge(pic, a, b)));
2016-02-06 10:09:40 -05:00
NEXT;
}
CASE(OP_GT) {
pic_value a, b;
b = POP();
a = POP();
PUSH(pic_bool_value(pic, pic_gt(pic, a, b)));
2016-02-06 10:09:40 -05:00
NEXT;
}
CASE(OP_STOP) {
2016-02-19 02:17:13 -05:00
return pic_protect(pic, POP());
2016-02-06 10:09:40 -05:00
}
} VM_LOOP_END;
}
2016-02-13 23:33:15 -05:00
pic_value
2016-02-19 10:03:16 -05:00
pic_applyk(pic_state *pic, pic_value proc, int argc, pic_value *args)
2016-02-06 10:09:40 -05:00
{
2016-02-29 13:14:18 -05:00
static const struct code iseq[2] = { { OP_NOP, 0, 0 }, { OP_TAILCALL, -1, 0 } };
2016-02-06 10:09:40 -05:00
pic_value *sp;
2016-02-21 06:32:00 -05:00
struct callinfo *ci;
2016-02-06 10:09:40 -05:00
int i;
2016-02-19 10:03:16 -05:00
*pic->sp++ = proc;
2016-02-06 10:09:40 -05:00
sp = pic->sp;
for (i = 0; i < argc; ++i) {
*sp++ = args[i];
}
ci = PUSHCI();
2016-02-29 13:14:18 -05:00
ci->ip = iseq;
2016-02-06 10:09:40 -05:00
ci->fp = pic->sp;
ci->retc = (int)argc;
if (ci->retc == 0) {
return pic_undef_value(pic);
2016-02-06 10:09:40 -05:00
} else {
return args[0];
}
}
pic_value
2016-02-19 10:03:16 -05:00
pic_call(pic_state *pic, pic_value proc, int n, ...)
2016-02-06 10:09:40 -05:00
{
2016-02-14 03:14:33 -05:00
pic_value r;
va_list ap;
2016-02-06 10:09:40 -05:00
2016-02-14 03:14:33 -05:00
va_start(ap, n);
r = pic_vcall(pic, proc, n, ap);
va_end(ap);
return r;
}
2016-02-06 10:09:40 -05:00
2016-02-14 03:14:33 -05:00
pic_value
2016-02-19 10:03:16 -05:00
pic_vcall(pic_state *pic, pic_value proc, int n, va_list ap)
2016-02-14 03:14:33 -05:00
{
pic_value *args = pic_alloca(pic, sizeof(pic_value) * n);
int i;
for (i = 0; i < n; ++i) {
args[i] = va_arg(ap, pic_value);
}
return pic_apply(pic, proc, n, args);
2016-02-06 10:09:40 -05:00
}
2016-02-04 10:30:11 -05:00
void
2016-02-21 06:32:00 -05:00
pic_irep_incref(pic_state *PIC_UNUSED(pic), struct irep *irep)
2016-02-04 10:30:11 -05:00
{
irep->refc++;
}
void
2016-02-21 06:32:00 -05:00
pic_irep_decref(pic_state *pic, struct irep *irep)
2016-02-04 10:30:11 -05:00
{
2016-02-06 04:15:15 -05:00
size_t i;
2016-02-04 10:30:11 -05:00
if (--irep->refc == 0) {
2016-02-07 23:51:41 -05:00
pic_free(pic, irep->code);
pic_free(pic, irep->ints);
pic_free(pic, irep->nums);
2016-02-04 10:30:11 -05:00
pic_free(pic, irep->pool);
/* unchain before decref children ireps */
2016-03-06 18:23:05 -05:00
if (irep->list.prev) { /* && irep->list.next */
irep->list.prev->next = irep->list.next;
irep->list.next->prev = irep->list.prev;
}
2016-02-04 10:30:11 -05:00
2016-02-06 04:15:15 -05:00
for (i = 0; i < irep->nirep; ++i) {
2016-02-07 23:51:41 -05:00
pic_irep_decref(pic, irep->irep[i]);
2016-02-04 10:30:11 -05:00
}
2016-02-07 23:51:41 -05:00
pic_free(pic, irep->irep);
2016-02-04 10:30:11 -05:00
pic_free(pic, irep);
}
}
2016-02-19 10:03:16 -05:00
pic_value
pic_make_proc(pic_state *pic, pic_func_t func, int n, pic_value *env)
2014-08-25 00:38:09 -04:00
{
2016-02-21 06:32:00 -05:00
struct proc *proc;
int i;
2015-05-27 10:01:35 -04:00
2016-02-21 06:42:41 -05:00
proc = (struct proc *)pic_obj_alloc(pic, offsetof(struct proc, locals) + sizeof(pic_value) * n, PIC_TYPE_FUNC);
2015-05-31 07:22:46 -04:00
proc->u.f.func = func;
proc->u.f.localc = n;
for (i = 0; i < n; ++i) {
proc->locals[i] = env[i];
}
return obj_value(pic, proc);
2014-08-25 00:38:09 -04:00
}
2016-02-19 10:03:16 -05:00
pic_value
2016-02-21 06:32:00 -05:00
pic_make_proc_irep(pic_state *pic, struct irep *irep, struct context *cxt)
2014-08-25 00:38:09 -04:00
{
2016-02-21 06:32:00 -05:00
struct proc *proc;
2014-08-25 00:38:09 -04:00
2016-02-21 06:42:41 -05:00
proc = (struct proc *)pic_obj_alloc(pic, offsetof(struct proc, locals), PIC_TYPE_IREP);
2015-05-31 07:19:07 -04:00
proc->u.i.irep = irep;
proc->u.i.cxt = cxt;
2016-02-04 10:30:11 -05:00
pic_irep_incref(pic, irep);
return obj_value(pic, proc);
2014-08-25 00:38:09 -04:00
}
static pic_value
pic_proc_proc_p(pic_state *pic)
{
pic_value v;
pic_get_args(pic, "o", &v);
return pic_bool_value(pic, pic_proc_p(pic, v));
2014-08-25 00:38:09 -04:00
}
static pic_value
pic_proc_apply(pic_state *pic)
{
2016-02-19 10:03:16 -05:00
pic_value proc, *args, *arg_list;
2016-02-14 03:14:33 -05:00
int argc, n, i;
2014-08-25 00:38:09 -04:00
pic_get_args(pic, "l*", &proc, &argc, &args);
if (argc == 0) {
2016-02-22 14:03:42 -05:00
pic_error(pic, "apply: wrong number of arguments", 0);
2014-08-25 00:38:09 -04:00
}
2016-02-14 03:14:33 -05:00
n = argc - 1 + pic_length(pic, args[argc - 1]);
2014-08-25 00:38:09 -04:00
2016-02-14 03:14:33 -05:00
arg_list = pic_alloca(pic, sizeof(pic_value) * n);
for (i = 0; i < argc - 1; ++i) {
arg_list[i] = args[i];
}
while (i < n) {
arg_list[i] = pic_list_ref(pic, args[argc - 1], i - argc + 1);
i++;
}
return pic_applyk(pic, proc, n, arg_list);
2014-08-25 00:38:09 -04:00
}
void
pic_init_proc(pic_state *pic)
{
pic_defun(pic, "procedure?", pic_proc_proc_p);
pic_defun(pic, "apply", pic_proc_apply);
}