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