picrin/lib/cont.c

172 lines
3.7 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"
2014-08-25 00:38:09 -04:00
2017-04-14 12:33:18 -04:00
#if PIC_USE_CALLCC
static pic_value
cont_call(pic_state *pic)
{
int argc;
pic_value *argv;
struct context *cxt, *c;
int i;
pic_get_args(pic, "*", &argc, &argv);
cxt = pic_data(pic, pic_closure_ref(pic, 0));
/* check if continuation is alive */
for (c = pic->cxt; c != NULL; c = c->prev) {
if (c == cxt) {
break;
}
}
if (c == NULL) {
pic_error(pic, "calling dead escape continuation", 0);
}
#define MKCALLK(argc) \
(cxt->tmpcode[0] = OP_CALL, cxt->tmpcode[1] = (argc), cxt->tmpcode)
cxt->pc = MKCALLK(argc);
cxt->sp = pic_make_frame_unsafe(pic, argc + 2);
cxt->sp->regs[0] = pic_closure_ref(pic, 1); /* cont. */
for (i = 0; i < argc; ++i) {
cxt->sp->regs[i + 1] = argv[i];
}
pic->cxt = cxt;
PIC_LONGJMP(cxt->jmp, 1);
PIC_UNREACHABLE();
}
pic_value
pic_make_cont(pic_state *pic, struct context *cxt, pic_value k)
{
static const pic_data_type cxt_type = { "cxt", NULL };
return pic_lambda(pic, cont_call, 2, pic_data_value(pic, cxt, &cxt_type), k);
}
static pic_value
pic_cont_callcc(pic_state *pic)
{
pic_value f, args[1];
pic_get_args(pic, "l", &f);
args[0] = pic_make_cont(pic, pic->cxt, pic->cxt->fp->regs[1]);
return pic_applyk(pic, f, 1, args);
}
#endif /* PIC_USE_CALCC */
2015-01-07 16:11:48 -05:00
static pic_value
2017-04-14 10:40:07 -04:00
applyk(pic_state *pic, pic_value proc, pic_value cont, int argc, pic_value *argv)
2014-09-19 03:41:49 -04:00
{
2017-04-14 10:40:07 -04:00
int i;
2014-09-19 03:41:49 -04:00
2017-04-14 10:40:07 -04:00
#define MKCALL(argc) \
(pic->cxt->tmpcode[0] = OP_CALL, pic->cxt->tmpcode[1] = (argc), pic->cxt->tmpcode)
2016-02-20 09:55:40 -05:00
2017-04-14 10:40:07 -04:00
pic->cxt->pc = MKCALL(argc + 1);
pic->cxt->sp = pic_make_frame_unsafe(pic, argc + 3);
pic->cxt->sp->regs[0] = proc;
pic->cxt->sp->regs[1] = cont;
for (i = 0; i < argc; ++i) {
pic->cxt->sp->regs[i + 2] = argv[i];
}
2017-04-14 10:40:07 -04:00
return pic_invalid_value(pic);
2014-09-24 01:57:49 -04:00
}
2017-03-30 08:53:49 -04:00
static pic_value
valuesk(pic_state *pic, int argc, pic_value *argv)
2017-03-30 08:53:49 -04:00
{
int i;
2017-04-14 10:40:07 -04:00
pic->cxt->pc = MKCALL(argc);
pic->cxt->sp = pic_make_frame_unsafe(pic, argc + 2);
pic->cxt->sp->regs[0] = pic->cxt->fp->regs[1];
2017-03-30 08:53:49 -04:00
for (i = 0; i < argc; ++i) {
2017-04-14 10:40:07 -04:00
pic->cxt->sp->regs[i + 1] = argv[i];
2014-09-19 03:41:49 -04:00
}
2017-04-14 10:40:07 -04:00
return pic_invalid_value(pic);
2014-09-19 03:41:49 -04:00
}
2016-02-19 03:38:49 -05:00
pic_value
2017-03-30 08:53:49 -04:00
pic_values(pic_state *pic, int n, ...)
2015-06-28 15:25:47 -04:00
{
va_list ap;
2016-02-19 03:38:49 -05:00
pic_value ret;
2015-06-28 15:25:47 -04:00
va_start(ap, n);
2017-03-30 08:53:49 -04:00
ret = pic_vvalues(pic, n, ap);
2015-06-28 15:25:47 -04:00
va_end(ap);
2016-02-19 03:38:49 -05:00
return ret;
2014-08-25 00:38:09 -04:00
}
pic_value
2017-03-30 08:53:49 -04:00
pic_vvalues(pic_state *pic, int n, va_list ap)
2014-08-25 00:38:09 -04:00
{
2016-02-19 03:38:49 -05:00
pic_value *retv = pic_alloca(pic, sizeof(pic_value) * n);
int i;
2014-08-25 00:38:09 -04:00
2016-02-19 03:38:49 -05:00
for (i = 0; i < n; ++i) {
retv[i] = va_arg(ap, pic_value);
}
return valuesk(pic, n, retv);
2014-08-25 00:38:09 -04:00
}
static pic_value
pic_cont_values(pic_state *pic)
{
2015-08-26 06:04:27 -04:00
int argc;
2014-08-25 00:38:09 -04:00
pic_value *argv;
pic_get_args(pic, "*", &argc, &argv);
return valuesk(pic, argc, argv);
2014-08-25 00:38:09 -04:00
}
2017-04-14 10:40:07 -04:00
static pic_value
receive_call(pic_state *pic)
{
int argc = pic->cxt->pc[1];
pic_value *args = &pic->cxt->fp->regs[1], consumer, cont;
/* receive_call is an inhabitant in the continuation side.
You can not use pic_get_args since it implicitly consumes the first argument. */
consumer = pic_closure_ref(pic, 0);
cont = pic_closure_ref(pic, 1);
return applyk(pic, consumer, cont, argc, args);
}
2014-08-25 00:38:09 -04:00
static pic_value
pic_cont_call_with_values(pic_state *pic)
{
2017-04-14 10:40:07 -04:00
pic_value producer, consumer, k;
2014-08-25 00:38:09 -04:00
pic_get_args(pic, "ll", &producer, &consumer);
2017-04-14 10:40:07 -04:00
k = pic_lambda(pic, receive_call, 2, consumer, pic->cxt->fp->regs[1]);
2014-08-25 00:38:09 -04:00
2017-04-14 10:40:07 -04:00
return applyk(pic, producer, k, 0, NULL);
2014-08-25 00:38:09 -04:00
}
void
pic_init_cont(pic_state *pic)
{
2017-04-14 12:33:18 -04:00
#if PIC_USE_CALLCC
2014-08-25 00:38:09 -04:00
pic_defun(pic, "call-with-current-continuation", pic_cont_callcc);
2014-09-08 06:38:33 -04:00
pic_defun(pic, "call/cc", pic_cont_callcc);
2017-04-14 12:33:18 -04:00
#endif
2015-07-01 17:17:27 -04:00
pic_defun(pic, "values", pic_cont_values);
pic_defun(pic, "call-with-values", pic_cont_call_with_values);
2014-08-25 00:38:09 -04:00
}