use call/cc in exception handler implementation
This commit is contained in:
parent
6a8a7d93e7
commit
46c1d0f2a7
88
error.c
88
error.c
|
@ -8,6 +8,8 @@
|
||||||
|
|
||||||
#include "picrin.h"
|
#include "picrin.h"
|
||||||
#include "picrin/pair.h"
|
#include "picrin/pair.h"
|
||||||
|
#include "picrin/proc.h"
|
||||||
|
#include "picrin/cont.h"
|
||||||
#include "picrin/string.h"
|
#include "picrin/string.h"
|
||||||
#include "picrin/error.h"
|
#include "picrin/error.h"
|
||||||
|
|
||||||
|
@ -66,42 +68,60 @@ pic_errmsg(pic_state *pic)
|
||||||
return pic_str_cstr(str);
|
return pic_str_cstr(str);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
static pic_value
|
||||||
pic_push_try(pic_state *pic, struct pic_proc *handler)
|
native_exception_handler(pic_state *pic)
|
||||||
{
|
{
|
||||||
|
pic_value err;
|
||||||
|
struct pic_proc *cont;
|
||||||
|
|
||||||
|
pic_get_args(pic, "o", &err);
|
||||||
|
|
||||||
|
pic->err = err;
|
||||||
|
|
||||||
|
cont = pic_proc_ptr(pic_attr_ref(pic, pic_get_proc(pic), "@@escape"));
|
||||||
|
|
||||||
|
pic_apply1(pic, cont, pic_false_value());
|
||||||
|
|
||||||
|
UNREACHABLE();
|
||||||
|
}
|
||||||
|
|
||||||
|
static pic_value
|
||||||
|
native_push_try(pic_state *pic)
|
||||||
|
{
|
||||||
|
struct pic_proc *cont, *handler;
|
||||||
struct pic_jmpbuf *try_jmp;
|
struct pic_jmpbuf *try_jmp;
|
||||||
|
|
||||||
|
pic_get_args(pic, "l", &cont);
|
||||||
|
|
||||||
|
handler = pic_make_proc(pic, native_exception_handler, "(native-exception-handler)");
|
||||||
|
|
||||||
|
pic_attr_set(pic, handler, "@@escape", pic_obj_value(cont));
|
||||||
|
|
||||||
if (pic->try_jmp_idx >= pic->try_jmp_size) {
|
if (pic->try_jmp_idx >= pic->try_jmp_size) {
|
||||||
pic->try_jmp_size *= 2;
|
pic->try_jmp_size *= 2;
|
||||||
pic->try_jmps = pic_realloc(pic, pic->try_jmps, sizeof(struct pic_jmpbuf) * pic->try_jmp_size);
|
pic->try_jmps = pic_realloc(pic, pic->try_jmps, sizeof(struct pic_jmpbuf) * pic->try_jmp_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
try_jmp = pic->try_jmps + pic->try_jmp_idx++;
|
try_jmp = pic->try_jmps + pic->try_jmp_idx++;
|
||||||
|
|
||||||
try_jmp->handler = handler;
|
try_jmp->handler = handler;
|
||||||
|
|
||||||
try_jmp->ci_offset = pic->ci - pic->cibase;
|
return pic_true_value();
|
||||||
try_jmp->sp_offset = pic->sp - pic->stbase;
|
}
|
||||||
try_jmp->ip = pic->ip;
|
|
||||||
|
|
||||||
try_jmp->prev_jmp = pic->jmp;
|
bool
|
||||||
pic->jmp = &try_jmp->here;
|
pic_push_try(pic_state *pic)
|
||||||
|
{
|
||||||
|
pic_value val;
|
||||||
|
|
||||||
|
val = pic_callcc(pic, pic_make_proc(pic, native_push_try, "(native-push-try)"));
|
||||||
|
|
||||||
|
return pic_test(val);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
pic_pop_try(pic_state *pic)
|
pic_pop_try(pic_state *pic)
|
||||||
{
|
{
|
||||||
struct pic_jmpbuf *try_jmp;
|
--pic->try_jmp_idx;
|
||||||
|
|
||||||
try_jmp = pic->try_jmps + --pic->try_jmp_idx;
|
|
||||||
|
|
||||||
/* assert(pic->jmp == &try_jmp->here); */
|
|
||||||
|
|
||||||
pic->ci = try_jmp->ci_offset + pic->cibase;
|
|
||||||
pic->sp = try_jmp->sp_offset + pic->stbase;
|
|
||||||
pic->ip = try_jmp->ip;
|
|
||||||
|
|
||||||
pic->jmp = try_jmp->prev_jmp;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct pic_error *
|
struct pic_error *
|
||||||
|
@ -124,28 +144,13 @@ pic_make_error(pic_state *pic, pic_sym type, const char *msg, pic_value irrs)
|
||||||
pic_value
|
pic_value
|
||||||
pic_raise_continuable(pic_state *pic, pic_value err)
|
pic_raise_continuable(pic_state *pic, pic_value err)
|
||||||
{
|
{
|
||||||
|
struct pic_proc *handler;
|
||||||
pic_value v;
|
pic_value v;
|
||||||
|
|
||||||
if (pic->try_jmp_idx == 0) {
|
if (pic->try_jmp_idx == 0) {
|
||||||
pic_errorf(pic, "no exception handler registered");
|
pic_panic(pic, "no exception handler registered");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pic->try_jmps[pic->try_jmp_idx - 1].handler == NULL) {
|
|
||||||
void pic_vm_tear_off(pic_state *);
|
|
||||||
|
|
||||||
pic_vm_tear_off(pic); /* tear off */
|
|
||||||
|
|
||||||
pic->err = err;
|
|
||||||
if (! pic->jmp) {
|
|
||||||
puts(pic_errmsg(pic));
|
|
||||||
pic_panic(pic, "no handler found on stack");
|
|
||||||
}
|
|
||||||
|
|
||||||
longjmp(*pic->jmp, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
struct pic_proc *handler;
|
|
||||||
|
|
||||||
handler = pic->try_jmps[pic->try_jmp_idx - 1].handler;
|
handler = pic->try_jmps[pic->try_jmp_idx - 1].handler;
|
||||||
|
|
||||||
pic_gc_protect(pic, pic_obj_value(handler));
|
pic_gc_protect(pic, pic_obj_value(handler));
|
||||||
|
@ -154,7 +159,7 @@ pic_raise_continuable(pic_state *pic, pic_value err)
|
||||||
|
|
||||||
v = pic_apply1(pic, pic->try_jmps[pic->try_jmp_idx].handler, err);
|
v = pic_apply1(pic, pic->try_jmps[pic->try_jmp_idx].handler, err);
|
||||||
|
|
||||||
pic->try_jmp_idx++;
|
pic->try_jmps[pic->try_jmp_idx++].handler = handler;
|
||||||
|
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
@ -195,11 +200,16 @@ pic_error_with_exception_handler(pic_state *pic)
|
||||||
|
|
||||||
pic_get_args(pic, "ll", &handler, &thunk);
|
pic_get_args(pic, "ll", &handler, &thunk);
|
||||||
|
|
||||||
pic_push_try(pic, handler);
|
if (pic->try_jmp_idx >= pic->try_jmp_size) {
|
||||||
|
pic->try_jmp_size *= 2;
|
||||||
|
pic->try_jmps = pic_realloc(pic, pic->try_jmps, sizeof(struct pic_jmpbuf) * pic->try_jmp_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
pic->try_jmps[pic->try_jmp_idx++].handler = handler;
|
||||||
|
|
||||||
val = pic_apply0(pic, thunk);
|
val = pic_apply0(pic, thunk);
|
||||||
|
|
||||||
pic_pop_try(pic);
|
pic->try_jmp_idx--;
|
||||||
|
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
|
@ -111,7 +111,6 @@ typedef struct {
|
||||||
|
|
||||||
struct pic_reader *reader;
|
struct pic_reader *reader;
|
||||||
|
|
||||||
jmp_buf *jmp;
|
|
||||||
pic_value err;
|
pic_value err;
|
||||||
struct pic_jmpbuf *try_jmps;
|
struct pic_jmpbuf *try_jmps;
|
||||||
size_t try_jmp_size, try_jmp_idx;
|
size_t try_jmp_size, try_jmp_idx;
|
||||||
|
|
|
@ -21,17 +21,14 @@ struct pic_jmpbuf {
|
||||||
/* do not return from try block! */
|
/* do not return from try block! */
|
||||||
|
|
||||||
#define pic_try \
|
#define pic_try \
|
||||||
pic_try_with_handler(NULL)
|
if (pic_push_try(pic)) \
|
||||||
#define pic_try_with_handler(handler) \
|
|
||||||
pic_push_try(pic, handler); \
|
|
||||||
if (setjmp(*pic->jmp) == 0) \
|
|
||||||
do
|
do
|
||||||
#define pic_catch \
|
#define pic_catch \
|
||||||
while (pic_pop_try(pic), 0); \
|
while (pic_pop_try(pic), 0); \
|
||||||
else \
|
else \
|
||||||
if (pic_pop_try(pic), 1)
|
if (pic_pop_try(pic), 1)
|
||||||
|
|
||||||
void pic_push_try(pic_state *, struct pic_proc *);
|
bool pic_push_try(pic_state *);
|
||||||
void pic_pop_try(pic_state *);
|
void pic_pop_try(pic_state *);
|
||||||
|
|
||||||
pic_value pic_raise_continuable(pic_state *, pic_value);
|
pic_value pic_raise_continuable(pic_state *, pic_value);
|
||||||
|
|
1
state.c
1
state.c
|
@ -71,7 +71,6 @@ pic_open(int argc, char *argv[], char **envp)
|
||||||
xh_init_int(&pic->reader->labels, sizeof(pic_value));
|
xh_init_int(&pic->reader->labels, sizeof(pic_value));
|
||||||
|
|
||||||
/* error handling */
|
/* error handling */
|
||||||
pic->jmp = NULL;
|
|
||||||
pic->err = pic_undef_value();
|
pic->err = pic_undef_value();
|
||||||
pic->try_jmps = calloc(PIC_RESCUE_SIZE, sizeof(struct pic_jmpbuf));
|
pic->try_jmps = calloc(PIC_RESCUE_SIZE, sizeof(struct pic_jmpbuf));
|
||||||
pic->try_jmp_idx = 0;
|
pic->try_jmp_idx = 0;
|
||||||
|
|
Loading…
Reference in New Issue