add pic_closure_ref, pic_closure_set, and pic_lambda

This commit is contained in:
Yuichi Nishiwaki 2016-02-14 22:23:14 +09:00
parent 8814469eac
commit f70dd4d376
12 changed files with 105 additions and 99 deletions

View File

@ -218,14 +218,13 @@ restore_cont(pic_state *pic, struct pic_fullcont *cont)
PIC_NORETURN static pic_value PIC_NORETURN static pic_value
cont_call(pic_state *pic) cont_call(pic_state *pic)
{ {
struct pic_proc *self;
int argc; int argc;
pic_value *argv; pic_value *argv;
struct pic_fullcont *cont; struct pic_fullcont *cont;
pic_get_args(pic, "&*", &self, &argc, &argv); pic_get_args(pic, "*", &argc, &argv);
cont = pic_data_ptr(pic_proc_env_ref(pic, self, "cont"))->data; cont = pic_data_ptr(pic_closure_ref(pic, 0))->data;
cont->results = pic_list_by_array(pic, argc, argv); cont->results = pic_list_by_array(pic, argc, argv);
/* execute guard handlers */ /* execute guard handlers */
@ -245,14 +244,9 @@ pic_callcc_full(pic_state *pic, struct pic_proc *proc)
} }
else { else {
struct pic_proc *c; struct pic_proc *c;
struct pic_data *dat;
c = pic_make_proc(pic, cont_call);
dat = pic_data_alloc(pic, &cont_type, cont);
/* save the continuation object in proc */ /* save the continuation object in proc */
pic_proc_env_set(pic, c, "cont", pic_obj_value(dat)); c = pic_lambda(pic, cont_call, 1, pic_obj_value(pic_data_alloc(pic, &cont_type, cont)));
return pic_call(pic, proc, 1, pic_obj_value(c)); return pic_call(pic, proc, 1, pic_obj_value(c));
} }
@ -272,15 +266,10 @@ pic_callcc_callcc(pic_state *pic)
} }
else { else {
struct pic_proc *c; struct pic_proc *c;
struct pic_data *dat;
pic_value args[1]; pic_value args[1];
c = pic_make_proc(pic, cont_call);
dat = pic_data_alloc(pic, &cont_type, cont);
/* save the continuation object in proc */ /* save the continuation object in proc */
pic_proc_env_set(pic, c, "cont", pic_obj_value(dat)); c = pic_lambda(pic, cont_call, 1, pic_obj_value(pic_data_alloc(pic, &cont_type, cont)));
args[0] = pic_obj_value(c); args[0] = pic_obj_value(c);
return pic_applyk(pic, proc, 1, args); return pic_applyk(pic, proc, 1, args);
@ -288,7 +277,7 @@ pic_callcc_callcc(pic_state *pic)
} }
#define pic_redefun(pic, lib, name, func) \ #define pic_redefun(pic, lib, name, func) \
pic_set(pic, lib, name, pic_obj_value(pic_make_proc(pic, func))) pic_set(pic, lib, name, pic_obj_value(pic_make_proc(pic, func, 0, NULL)))
void void
pic_init_callcc(pic_state *pic) pic_init_callcc(pic_state *pic)

View File

@ -399,7 +399,7 @@ pic_socket_call_with_socket(pic_state *pic)
void void
pic_init_srfi_106(pic_state *pic) pic_init_srfi_106(pic_state *pic)
{ {
#define pic_defun_(pic, name, f) pic_define(pic, pic->lib, name, pic_obj_value(pic_make_proc(pic, f))) #define pic_defun_(pic, name, f) pic_define(pic, pic->lib, name, pic_obj_value(pic_make_proc(pic, f, 0, NULL)))
#define pic_define_(pic, name, v) pic_define(pic, pic->lib, name, v) #define pic_define_(pic, name, v) pic_define(pic, pic->lib, name, v)
pic_deflibrary (pic, "(srfi 106)") { pic_deflibrary (pic, "(srfi 106)") {

View File

@ -82,18 +82,20 @@ pic_load_point(pic_state *pic, struct pic_cont *cont)
pic->cc = cont->prev; pic->cc = cont->prev;
} }
#define CV_ID 0
#define CV_ESCAPE 1
static pic_value static pic_value
cont_call(pic_state *pic) cont_call(pic_state *pic)
{ {
struct pic_proc *self;
int argc; int argc;
pic_value *argv; pic_value *argv;
int id; int id;
struct pic_cont *cc, *cont; struct pic_cont *cc, *cont;
pic_get_args(pic, "&*", &self, &argc, &argv); pic_get_args(pic, "*", &argc, &argv);
id = pic_int(pic_proc_env_ref(pic, self, "id")); id = pic_int(pic_closure_ref(pic, CV_ID));
/* check if continuation is alive */ /* check if continuation is alive */
for (cc = pic->cc; cc != NULL; cc = cc->prev) { for (cc = pic->cc; cc != NULL; cc = cc->prev) {
@ -105,7 +107,7 @@ cont_call(pic_state *pic)
pic_errorf(pic, "calling dead escape continuation"); pic_errorf(pic, "calling dead escape continuation");
} }
cont = pic_data_ptr(pic_proc_env_ref(pic, self, "escape"))->data; cont = pic_data_ptr(pic_closure_ref(pic, CV_ESCAPE))->data;
cont->results = pic_list_by_array(pic, argc, argv); cont->results = pic_list_by_array(pic, argc, argv);
pic_load_point(pic, cont); pic_load_point(pic, cont);
@ -120,15 +122,9 @@ pic_make_cont(pic_state *pic, struct pic_cont *cont)
{ {
static const pic_data_type cont_type = { "cont", NULL, NULL }; static const pic_data_type cont_type = { "cont", NULL, NULL };
struct pic_proc *c; struct pic_proc *c;
struct pic_data *e;
c = pic_make_proc(pic, cont_call);
e = pic_data_alloc(pic, &cont_type, cont);
/* save the escape continuation in proc */ /* save the escape continuation in proc */
pic_proc_env_set(pic, c, "escape", pic_obj_value(e)); c = pic_lambda(pic, cont_call, 2, pic_int_value(cont->id), pic_obj_value(pic_data_alloc(pic, &cont_type, cont)));
pic_proc_env_set(pic, c, "id", pic_int_value(cont->id));
return c; return c;
} }

View File

@ -56,7 +56,7 @@ pic_native_exception_handler(pic_state *pic)
pic->err = err; pic->err = err;
cont = pic_proc_ptr(pic_proc_env_ref(pic, self, "cont")); cont = pic_proc_ptr(pic_closure_ref(pic, 0));
pic_call(pic, cont, 1, pic_false_value()); pic_call(pic, cont, 1, pic_false_value());

View File

@ -302,8 +302,9 @@ gc_mark_object(pic_state *pic, struct pic_object *obj)
LOOP(obj->u.proc.u.i.cxt); LOOP(obj->u.proc.u.i.cxt);
} }
} else { } else {
if (obj->u.proc.u.f.env) { int i;
LOOP(obj->u.proc.u.f.env); for (i = 0; i < obj->u.proc.u.f.localc; ++i) {
gc_mark(pic, obj->u.proc.locals[i]);
} }
} }
break; break;

View File

@ -151,6 +151,8 @@ void pic_defvar(pic_state *, const char *, pic_value, struct pic_proc *);
void pic_define(pic_state *, struct pic_lib *, const char *, pic_value); void pic_define(pic_state *, struct pic_lib *, const char *, pic_value);
pic_value pic_ref(pic_state *, struct pic_lib *, const char *); pic_value pic_ref(pic_state *, struct pic_lib *, const char *);
void pic_set(pic_state *, struct pic_lib *, const char *, pic_value); void pic_set(pic_state *, struct pic_lib *, const char *, pic_value);
pic_value pic_closure_ref(pic_state *, int);
void pic_closure_set(pic_state *, int, pic_value);
pic_value pic_funcall(pic_state *pic, struct pic_lib *, const char *, int, ...); pic_value pic_funcall(pic_state *pic, struct pic_lib *, const char *, int, ...);
struct pic_lib *pic_make_library(pic_state *, pic_value); struct pic_lib *pic_make_library(pic_state *, pic_value);
@ -161,13 +163,13 @@ void pic_export(pic_state *, pic_sym *);
PIC_NORETURN void pic_panic(pic_state *, const char *); PIC_NORETURN void pic_panic(pic_state *, const char *);
PIC_NORETURN void pic_errorf(pic_state *, const char *, ...); PIC_NORETURN void pic_errorf(pic_state *, const char *, ...);
struct pic_proc *pic_lambda(pic_state *, pic_func_t, int, ...);
struct pic_proc *pic_vlambda(pic_state *, pic_func_t, int, va_list);
pic_value pic_call(pic_state *, struct pic_proc *, int, ...); pic_value pic_call(pic_state *, struct pic_proc *, int, ...);
pic_value pic_vcall(pic_state *, struct pic_proc *, int, va_list); pic_value pic_vcall(pic_state *, struct pic_proc *, int, va_list);
pic_value pic_apply(pic_state *, struct pic_proc *, int, pic_value *); pic_value pic_apply(pic_state *, struct pic_proc *, int, pic_value *);
pic_value pic_applyk(pic_state *, struct pic_proc *, int, pic_value *); pic_value pic_applyk(pic_state *, struct pic_proc *, int, pic_value *);
pic_value pic_eval(pic_state *, pic_value, struct pic_lib *);
bool pic_eq_p(pic_value, pic_value); bool pic_eq_p(pic_value, pic_value);
bool pic_eqv_p(pic_value, pic_value); bool pic_eqv_p(pic_value, pic_value);
bool pic_equal_p(pic_state *, pic_value, pic_value); bool pic_equal_p(pic_state *, pic_value, pic_value);
@ -208,6 +210,8 @@ pic_value pic_read_cstr(pic_state *, const char *);
void pic_load(pic_state *, struct pic_port *); void pic_load(pic_state *, struct pic_port *);
void pic_load_cstr(pic_state *, const char *); void pic_load_cstr(pic_state *, const char *);
pic_value pic_eval(pic_state *, pic_value, struct pic_lib *);
struct pic_proc *pic_make_var(pic_state *, pic_value, struct pic_proc *); struct pic_proc *pic_make_var(pic_state *, pic_value, struct pic_proc *);
#define pic_deflibrary(pic, spec) \ #define pic_deflibrary(pic, spec) \

View File

@ -35,8 +35,7 @@ struct pic_error *pic_make_error(pic_state *, pic_sym *, const char *, pic_value
if (PIC_SETJMP(pic, cont.jmp) == 0) { \ if (PIC_SETJMP(pic, cont.jmp) == 0) { \
extern pic_value pic_native_exception_handler(pic_state *); \ extern pic_value pic_native_exception_handler(pic_state *); \
struct pic_proc *handler; \ struct pic_proc *handler; \
handler = pic_make_proc(pic, pic_native_exception_handler); \ handler = pic_lambda(pic, pic_native_exception_handler, 1, pic_obj_value(pic_make_cont(pic, &cont))); \
pic_proc_env_set(pic, handler, "cont", pic_obj_value(pic_make_cont(pic, &cont))); \
do { \ do { \
pic_push_handler(pic, handler); pic_push_handler(pic, handler);
#define pic_catch_(label) \ #define pic_catch_(label) \

View File

@ -26,13 +26,14 @@ struct pic_proc {
union { union {
struct { struct {
pic_func_t func; pic_func_t func;
struct pic_dict *env; int localc;
} f; } f;
struct { struct {
struct pic_irep *irep; struct pic_irep *irep;
struct pic_context *cxt; struct pic_context *cxt;
} i; } i;
} u; } u;
pic_value locals[1];
}; };
#define pic_proc_func_p(proc) ((proc)->tag == PIC_PROC_TAG_FUNC) #define pic_proc_func_p(proc) ((proc)->tag == PIC_PROC_TAG_FUNC)
@ -44,14 +45,9 @@ struct pic_proc {
#define pic_context_p(o) (pic_type(o) == PIC_TT_CXT) #define pic_context_p(o) (pic_type(o) == PIC_TT_CXT)
#define pic_context_ptr(o) ((struct pic_context *)pic_ptr(o)) #define pic_context_ptr(o) ((struct pic_context *)pic_ptr(o))
struct pic_proc *pic_make_proc(pic_state *, pic_func_t); struct pic_proc *pic_make_proc(pic_state *, pic_func_t, int, pic_value *);
struct pic_proc *pic_make_proc_irep(pic_state *, struct pic_irep *, struct pic_context *); struct pic_proc *pic_make_proc_irep(pic_state *, struct pic_irep *, struct pic_context *);
struct pic_dict *pic_proc_env(pic_state *, struct pic_proc *);
bool pic_proc_env_has(pic_state *, struct pic_proc *, const char *);
pic_value pic_proc_env_ref(pic_state *, struct pic_proc *, const char *);
void pic_proc_env_set(pic_state *, struct pic_proc *, const char *, pic_value);
#if defined(__cplusplus) #if defined(__cplusplus)
} }
#endif #endif

View File

@ -163,7 +163,7 @@ pic_define_standard_port(pic_state *pic, const char *name, xFILE *file, int dir)
port->file = file; port->file = file;
port->flags = dir | PIC_PORT_TEXT | PIC_PORT_OPEN; port->flags = dir | PIC_PORT_TEXT | PIC_PORT_OPEN;
pic_defvar(pic, name, pic_obj_value(port), pic_make_proc(pic, pic_assert_port)); pic_defvar(pic, name, pic_obj_value(port), pic_make_proc(pic, pic_assert_port, 0, NULL));
} }
#define DEFINE_STANDARD_PORT_ACCESSOR(name, var) \ #define DEFINE_STANDARD_PORT_ACCESSOR(name, var) \

View File

@ -200,7 +200,7 @@ vm_push_cxt(pic_state *pic)
{ {
pic_callinfo *ci = pic->ci; pic_callinfo *ci = pic->ci;
ci->cxt = (struct pic_context *)pic_obj_alloc(pic, sizeof(struct pic_context) + sizeof(pic_value) * ci->regc, PIC_TT_CXT); ci->cxt = (struct pic_context *)pic_obj_alloc(pic, offsetof(struct pic_context, storage) + sizeof(pic_value) * ci->regc, PIC_TT_CXT);
ci->cxt->up = ci->up; ci->cxt->up = ci->up;
ci->cxt->regc = ci->regc; ci->cxt->regc = ci->regc;
ci->cxt->regs = ci->regs; ci->cxt->regs = ci->regs;
@ -836,6 +836,30 @@ pic_vcall(pic_state *pic, struct pic_proc *proc, int n, va_list ap)
return pic_apply(pic, proc, n, args); return pic_apply(pic, proc, n, args);
} }
struct pic_proc *
pic_lambda(pic_state *pic, pic_func_t f, int n, ...)
{
struct pic_proc *proc;
va_list ap;
va_start(ap, n);
proc = pic_vlambda(pic, f, n, ap);
va_end(ap);
return proc;
}
struct pic_proc *
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);
}
void void
pic_define(pic_state *pic, struct pic_lib *lib, const char *name, pic_value val) pic_define(pic_state *pic, struct pic_lib *lib, const char *name, pic_value val)
{ {
@ -855,9 +879,9 @@ pic_define(pic_state *pic, struct pic_lib *lib, const char *name, pic_value val)
} }
void void
pic_defun(pic_state *pic, const char *name, pic_func_t cfunc) pic_defun(pic_state *pic, const char *name, pic_func_t f)
{ {
pic_define(pic, pic->lib, name, pic_obj_value(pic_make_proc(pic, cfunc))); pic_define(pic, pic->lib, name, pic_obj_value(pic_make_proc(pic, f, 0, NULL)));
pic_export(pic, pic_intern_cstr(pic, name)); pic_export(pic, pic_intern_cstr(pic, name));
} }
@ -896,6 +920,36 @@ pic_set(pic_state *pic, struct pic_lib *lib, const char *name, pic_value val)
vm_gset(pic, uid, val); vm_gset(pic, uid, val);
} }
pic_value
pic_closure_ref(pic_state *pic, int n)
{
struct pic_proc *self;
self = pic_proc_ptr(GET_OPERAND(pic, 0));
assert(pic_proc_func_p(self));
if (n < 0 || self->u.f.localc <= n) {
pic_errorf(pic, "pic_closure_ref: index out of range (%d)", n);
}
return pic_proc_ptr(GET_OPERAND(pic, 0))->locals[n];
}
void
pic_closure_set(pic_state *pic, int n, pic_value v)
{
struct pic_proc *self;
self = pic_proc_ptr(GET_OPERAND(pic, 0));
assert(pic_proc_func_p(self));
if (n < 0 || self->u.f.localc <= n) {
pic_errorf(pic, "pic_closure_ref: index out of range (%d)", n);
}
pic_proc_ptr(GET_OPERAND(pic, 0))->locals[n] = v;
}
pic_value pic_value
pic_funcall(pic_state *pic, struct pic_lib *lib, const char *name, int n, ...) pic_funcall(pic_state *pic, struct pic_lib *lib, const char *name, int n, ...)
{ {
@ -943,14 +997,18 @@ pic_irep_decref(pic_state *pic, struct pic_irep *irep)
} }
struct pic_proc * struct pic_proc *
pic_make_proc(pic_state *pic, pic_func_t func) pic_make_proc(pic_state *pic, pic_func_t func, int n, pic_value *env)
{ {
struct pic_proc *proc; struct pic_proc *proc;
int i;
proc = (struct pic_proc *)pic_obj_alloc(pic, sizeof(struct pic_proc), PIC_TT_PROC); proc = (struct pic_proc *)pic_obj_alloc(pic, offsetof(struct pic_proc, locals) + sizeof(pic_value) * n, PIC_TT_PROC);
proc->tag = PIC_PROC_TAG_FUNC; proc->tag = PIC_PROC_TAG_FUNC;
proc->u.f.func = func; proc->u.f.func = func;
proc->u.f.env = NULL; proc->u.f.localc = n;
for (i = 0; i < n; ++i) {
proc->locals[i] = env[i];
}
return proc; return proc;
} }
@ -959,7 +1017,7 @@ pic_make_proc_irep(pic_state *pic, struct pic_irep *irep, struct pic_context *cx
{ {
struct pic_proc *proc; struct pic_proc *proc;
proc = (struct pic_proc *)pic_obj_alloc(pic, sizeof(struct pic_proc), PIC_TT_PROC); proc = (struct pic_proc *)pic_obj_alloc(pic, offsetof(struct pic_proc, locals), PIC_TT_PROC);
proc->tag = PIC_PROC_TAG_IREP; proc->tag = PIC_PROC_TAG_IREP;
proc->u.i.irep = irep; proc->u.i.irep = irep;
proc->u.i.cxt = cxt; proc->u.i.cxt = cxt;
@ -967,35 +1025,6 @@ pic_make_proc_irep(pic_state *pic, struct pic_irep *irep, struct pic_context *cx
return proc; return proc;
} }
struct pic_dict *
pic_proc_env(pic_state *pic, struct pic_proc *proc)
{
assert(pic_proc_func_p(proc));
if (! proc->u.f.env) {
proc->u.f.env = pic_make_dict(pic);
}
return proc->u.f.env;
}
bool
pic_proc_env_has(pic_state *pic, struct pic_proc *proc, const char *key)
{
return pic_dict_has(pic, pic_proc_env(pic, proc), pic_intern_cstr(pic, key));
}
pic_value
pic_proc_env_ref(pic_state *pic, struct pic_proc *proc, const char *key)
{
return pic_dict_ref(pic, pic_proc_env(pic, proc), pic_intern_cstr(pic, key));
}
void
pic_proc_env_set(pic_state *pic, struct pic_proc *proc, const char *key, pic_value val)
{
pic_dict_set(pic, pic_proc_env(pic, proc), pic_intern_cstr(pic, key), val);
}
static pic_value static pic_value
pic_proc_proc_p(pic_state *pic) pic_proc_proc_p(pic_state *pic)
{ {

View File

@ -4,15 +4,6 @@
#include "picrin.h" #include "picrin.h"
static pic_value
var_conv(pic_state *pic, struct pic_proc *var, pic_value val)
{
if (pic_proc_env_has(pic, var, "conv") != 0) {
return pic_call(pic, pic_proc_ptr(pic_proc_env_ref(pic, var, "conv")), 1, val);
}
return val;
}
static pic_value static pic_value
var_get(pic_state *pic, struct pic_proc *var) var_get(pic_state *pic, struct pic_proc *var)
{ {
@ -52,7 +43,13 @@ var_call(pic_state *pic)
if (n == 0) { if (n == 0) {
return var_get(pic, self); return var_get(pic, self);
} else { } else {
return var_set(pic, self, var_conv(pic, self, val)); pic_value conv;
conv = pic_closure_ref(pic, 0);
if (! pic_false_p(conv)) {
val = pic_call(pic, pic_proc_ptr(conv), 1, val);
}
return var_set(pic, self, val);
} }
} }
@ -60,12 +57,12 @@ struct pic_proc *
pic_make_var(pic_state *pic, pic_value init, struct pic_proc *conv) pic_make_var(pic_state *pic, pic_value init, struct pic_proc *conv)
{ {
struct pic_proc *var; struct pic_proc *var;
pic_value c = pic_false_value();
var = pic_make_proc(pic, var_call);
if (conv != NULL) { if (conv != NULL) {
pic_proc_env_set(pic, var, "conv", pic_obj_value(conv)); c = pic_obj_value(conv);
} }
var = pic_lambda(pic, var_call, 1, c);
pic_call(pic, var, 1, init); pic_call(pic, var, 1, init);

View File

@ -115,7 +115,7 @@ weak_call(pic_state *pic)
pic_errorf(pic, "attempted to set a non-object key '~s' in an ephemeron", key); pic_errorf(pic, "attempted to set a non-object key '~s' in an ephemeron", key);
} }
weak = pic_weak_ptr(pic_proc_env_ref(pic, self, "weak")); weak = pic_weak_ptr(pic_closure_ref(pic, 0));
if (n == 1) { if (n == 1) {
return weak_get(pic, weak, pic_obj_ptr(key)); return weak_get(pic, weak, pic_obj_ptr(key));
@ -127,16 +127,11 @@ weak_call(pic_state *pic)
static pic_value static pic_value
pic_weak_make_ephemeron(pic_state *pic) pic_weak_make_ephemeron(pic_state *pic)
{ {
struct pic_weak *weak;
struct pic_proc *proc; struct pic_proc *proc;
pic_get_args(pic, ""); pic_get_args(pic, "");
weak = pic_make_weak(pic); proc = pic_lambda(pic, weak_call, 1, pic_obj_value(pic_make_weak(pic)));
proc = pic_make_proc(pic, weak_call);
pic_proc_env_set(pic, proc, "weak", pic_obj_value(weak));
return pic_obj_value(proc); return pic_obj_value(proc);
} }