diff --git a/README.md b/README.md index 359bc13e..642f5084 100644 --- a/README.md +++ b/README.md @@ -117,7 +117,7 @@ Picrin is a lightweight scheme implementation intended to comply with full R7RS | 6.8 Vectors | yes | | | 6.9 Bytevectors | yes | | | 6.10 Control features | yes | | -| 6.11 Exceptions | yes | | +| 6.11 Exceptions | yes | `raise-continuable` is not supported | | 6.12 Environments and evaluation | N/A | | | 6.13.1 Ports | yes | | | 6.13.2 Input | incomplete | TODO: binary input | diff --git a/include/picrin.h b/include/picrin.h index 34953544..0d250f7b 100644 --- a/include/picrin.h +++ b/include/picrin.h @@ -77,9 +77,6 @@ typedef struct { pic_code *ip; - struct pic_proc **rescue; - size_t ridx, rlen; - pic_sym sDEFINE, sLAMBDA, sIF, sBEGIN, sQUOTE, sSETBANG; pic_sym sQUASIQUOTE, sUNQUOTE, sUNQUOTE_SPLICING; pic_sym sDEFINE_SYNTAX, sDEFINE_MACRO; @@ -124,7 +121,7 @@ struct pic_object *pic_obj_alloc_unsafe(pic_state *, size_t, enum pic_tt); void pic_free(pic_state *, void *); void pic_gc_run(pic_state *); -void pic_gc_protect(pic_state *, pic_value); +pic_value pic_gc_protect(pic_state *, pic_value); int pic_gc_arena_preserve(pic_state *); void pic_gc_arena_restore(pic_state *, int); @@ -180,11 +177,15 @@ void pic_import(pic_state *, pic_value); void pic_export(pic_state *, pic_sym); noreturn void pic_abort(pic_state *, const char *); -noreturn void pic_raise(pic_state *, struct pic_error *); -noreturn void pic_error(pic_state *, const char *); /* obsoleted */ noreturn void pic_errorf(pic_state *, const char *, ...); void pic_warn(pic_state *, const char *); +/* obsoleted */ +noreturn static inline void pic_error(pic_state *pic, const char *msg) +{ + pic_errorf(pic, msg); +} + const char *pic_errmsg(pic_state *); pic_value pic_write(pic_state *, pic_value); /* returns given obj */ diff --git a/include/picrin/cont.h b/include/picrin/cont.h index 38cfc131..15ea1c3f 100644 --- a/include/picrin/cont.h +++ b/include/picrin/cont.h @@ -26,9 +26,6 @@ struct pic_cont { pic_code *ip; - struct pic_proc **rescue; - size_t ridx, rlen; - struct pic_object *arena[PIC_ARENA_SIZE]; int arena_idx; diff --git a/include/picrin/error.h b/include/picrin/error.h index a4caf63a..cebc85e1 100644 --- a/include/picrin/error.h +++ b/include/picrin/error.h @@ -15,6 +15,8 @@ struct pic_jmpbuf { struct pic_jmpbuf *prev; }; +/* do not return from try block! */ + #define pic_try \ pic_push_try(pic); \ if (setjmp(*pic->jmp) == 0) \ @@ -27,6 +29,8 @@ struct pic_jmpbuf { void pic_push_try(pic_state *); void pic_pop_try(pic_state *); +noreturn void pic_throw(pic_state *, struct pic_error *); + struct pic_error { PIC_OBJECT_HEADER enum pic_error_kind { @@ -42,8 +46,6 @@ struct pic_error { #define pic_error_p(v) (pic_type(v) == PIC_TT_ERROR) #define pic_error_ptr(v) ((struct pic_error *)pic_ptr(v)) -pic_value pic_raise_continuable(pic_state *, pic_value); - #if defined(__cplusplus) } #endif diff --git a/src/cont.c b/src/cont.c index 389e8a7b..9d0379d9 100644 --- a/src/cont.c +++ b/src/cont.c @@ -119,11 +119,6 @@ save_cont(pic_state *pic, struct pic_cont **c) cont->ip = pic->ip; - cont->ridx = pic->ridx; - cont->rlen = pic->rlen; - cont->rescue = (struct pic_proc **)pic_alloc(pic, sizeof(struct pic_proc *) * cont->rlen); - memcpy(cont->rescue, pic->rescue, sizeof(struct pic_proc *) * cont->rlen); - cont->arena_idx = pic->arena_idx; memcpy(cont->arena, pic->arena, sizeof(struct pic_object *) * PIC_ARENA_SIZE); @@ -168,11 +163,6 @@ restore_cont(pic_state *pic, struct pic_cont *cont) pic->ip = cont->ip; - pic->rescue = (struct pic_proc **)pic_realloc(pic, pic->rescue, sizeof(struct pic_proc *) * cont->rlen); - memcpy(pic->rescue, cont->rescue, sizeof(struct pic_object *) * cont->rlen); - pic->ridx = cont->ridx; - pic->rlen = cont->rlen; - memcpy(pic->arena, cont->arena, sizeof(struct pic_object *) * PIC_ARENA_SIZE); pic->arena_idx = cont->arena_idx; diff --git a/src/error.c b/src/error.c index d3798f21..f5c3d24f 100644 --- a/src/error.c +++ b/src/error.c @@ -11,6 +11,24 @@ #include "picrin/string.h" #include "picrin/error.h" +void +pic_abort(pic_state *pic, const char *msg) +{ + UNUSED(pic); + + fprintf(stderr, "abort: %s\n", msg); + fflush(stderr); + abort(); +} + +void +pic_warn(pic_state *pic, const char *msg) +{ + UNUSED(pic); + + fprintf(stderr, "warn: %s\n", msg); +} + void pic_push_try(pic_state *pic) { @@ -39,16 +57,8 @@ pic_pop_try(pic_state *pic) pic->try_jmps = prev; } -const char * -pic_errmsg(pic_state *pic) -{ - assert(pic->err != NULL); - - return pic_str_cstr(pic->err->msg); -} - -noreturn static void -raise(pic_state *pic, struct pic_error *e) +noreturn void +pic_throw(pic_state *pic, struct pic_error *e) { pic->err = e; if (! pic->jmp) { @@ -58,23 +68,12 @@ raise(pic_state *pic, struct pic_error *e) longjmp(*pic->jmp, 1); } -noreturn static void -error(pic_state *pic, pic_str *msg, pic_value irrs) +const char * +pic_errmsg(pic_state *pic) { - struct pic_error *e; + assert(pic->err != NULL); - e = (struct pic_error *)pic_obj_alloc(pic, sizeof(struct pic_error), PIC_TT_ERROR); - e->type = PIC_ERROR_OTHER; - e->msg = msg; - e->irrs = irrs; - - raise(pic, e); -} - -void -pic_error(pic_state *pic, const char *msg) -{ - pic_errorf(pic, msg); + return pic_str_cstr(pic->err->msg); } void @@ -82,64 +81,18 @@ pic_errorf(pic_state *pic, const char *fmt, ...) { va_list ap; pic_value err_line; + struct pic_error *e; va_start(ap, fmt); err_line = pic_vformat(pic, fmt, ap); va_end(ap); - error(pic, pic_str_ptr(pic_car(pic, err_line)), pic_cdr(pic, err_line)); -} + e = (struct pic_error *)pic_obj_alloc(pic, sizeof(struct pic_error), PIC_TT_ERROR); + e->type = PIC_ERROR_OTHER; + e->msg = pic_str_ptr(pic_car(pic, err_line)); + e->irrs = pic_cdr(pic, err_line); -void -pic_abort(pic_state *pic, const char *msg) -{ - UNUSED(pic); - - fprintf(stderr, "abort: %s\n", msg); - fflush(stderr); - abort(); -} - -void -pic_warn(pic_state *pic, const char *msg) -{ - UNUSED(pic); - - fprintf(stderr, "warn: %s\n", msg); -} - -void -pic_raise(pic_state *pic, struct pic_error *e) -{ - pic_value a; - struct pic_proc *handler; - - if (pic->ridx == 0) { - raise(pic, e); - } - - handler = pic->rescue[--pic->ridx]; - pic_gc_protect(pic, pic_obj_value(handler)); - - a = pic_apply_argv(pic, handler, 1, pic_obj_value(e)); - /* when the handler returns */ - pic_errorf(pic, "handler returned", 2, pic_obj_value(handler), a); -} - -pic_value -pic_raise_continuable(pic_state *pic, pic_value obj) -{ - struct pic_proc *handler; - - if (pic->ridx == 0) { - pic_abort(pic, "logic flaw: no exception handler remains"); - } - - handler = pic->rescue[--pic->ridx]; - obj = pic_apply_argv(pic, handler, 1, obj); - pic->rescue[pic->ridx++] = handler; - - return obj; + pic_throw(pic, e); } static pic_value @@ -150,19 +103,16 @@ pic_error_with_exception_handler(pic_state *pic) pic_get_args(pic, "ll", &handler, &thunk); - if (pic->ridx >= pic->rlen) { - -#if DEBUG - puts("rescue realloced"); -#endif - - pic->rlen *= 2; - pic->rescue = (struct pic_proc **)pic_realloc(pic, pic->rescue, sizeof(struct pic_proc *) * pic->rlen); + pic_try { + v = pic_apply_argv(pic, thunk, 0); } - pic->rescue[pic->ridx++] = handler; + pic_catch { + struct pic_error *e = pic->err; - v = pic_apply_argv(pic, thunk, 0); - pic->ridx--; + pic->err = NULL; + v = pic_apply_argv(pic, handler, 1, pic_obj_value(e)); + pic_errorf(pic, "error handler returned ~s, by error ~s", v, pic_obj_value(e)); + } return v; } @@ -179,17 +129,7 @@ pic_error_raise(pic_state *pic) e->msg = pic_str_new_cstr(pic, "raised"); e->irrs = pic_list1(pic, v); - pic_raise(pic, e); -} - -static pic_value -pic_error_raise_continuable(pic_state *pic) -{ - pic_value obj; - - pic_get_args(pic, "o", &obj); - - return pic_raise_continuable(pic, obj); + pic_throw(pic, e); } noreturn static pic_value @@ -207,7 +147,7 @@ pic_error_error(pic_state *pic) e->msg = str; e->irrs = pic_list_by_array(pic, argc, argv); - pic_raise(pic, e); + pic_throw(pic, e); } static pic_value @@ -277,7 +217,6 @@ pic_init_error(pic_state *pic) { pic_defun(pic, "with-exception-handler", pic_error_with_exception_handler); pic_defun(pic, "raise", pic_error_raise); - pic_defun(pic, "raise-continuable", pic_error_raise_continuable); pic_defun(pic, "error", pic_error_error); pic_defun(pic, "error-object?", pic_error_error_object_p); pic_defun(pic, "error-object-message", pic_error_error_object_message); diff --git a/src/gc.c b/src/gc.c index 807574c2..2d42ade6 100644 --- a/src/gc.c +++ b/src/gc.c @@ -183,17 +183,19 @@ gc_protect(pic_state *pic, struct pic_object *obj) pic->arena[pic->arena_idx++] = obj; } -void +pic_value pic_gc_protect(pic_state *pic, pic_value v) { struct pic_object *obj; if (pic_vtype(v) != PIC_VTYPE_HEAP) { - return; + return v; } obj = pic_obj_ptr(v); gc_protect(pic, obj); + + return v; } int @@ -406,8 +408,7 @@ gc_mark_object(pic_state *pic, struct pic_object *obj) struct pic_cont *cont = (struct pic_cont *)obj; pic_value *stack; pic_callinfo *ci; - size_t i; - int j; + int i; /* block */ gc_mark_block(pic, cont->blk); @@ -424,14 +425,9 @@ gc_mark_object(pic_state *pic, struct pic_object *obj) } } - /* exception handlers */ - for (i = 0; i < cont->ridx; ++i) { - gc_mark_object(pic, (struct pic_object *)cont->rescue[i]); - } - /* arena */ - for (j = 0; j < cont->arena_idx; ++j) { - gc_mark_object(pic, cont->arena[j]); + for (i = 0; i < cont->arena_idx; ++i) { + gc_mark_object(pic, cont->arena[i]); } /* result values */ @@ -537,11 +533,6 @@ gc_mark_phase(pic_state *pic) } } - /* exception handlers */ - for (i = 0; i < pic->ridx; ++i) { - gc_mark_object(pic, (struct pic_object *)pic->rescue[i]); - } - /* error object */ if (pic->err) { gc_mark_object(pic, (struct pic_object *)pic->err); @@ -608,7 +599,6 @@ gc_finalize_object(pic_state *pic, struct pic_object *obj) pic_free(pic, cont->stk_ptr); pic_free(pic, cont->st_ptr); pic_free(pic, cont->ci_ptr); - pic_free(pic, cont->rescue); PIC_BLK_DECREF(pic, cont->blk); break; } diff --git a/src/macro.c b/src/macro.c index 4af43ae6..e6f5db1d 100644 --- a/src/macro.c +++ b/src/macro.c @@ -224,17 +224,10 @@ macroexpand(pic_state *pic, pic_value expr, struct pic_senv *senv) pic_in_library(pic, pic_cadr(pic, expr)); pic_for_each (v, pic_cddr(pic, expr)) { - struct pic_proc *proc; int ai = pic_gc_arena_preserve(pic); - proc = pic_compile(pic, v); - if (proc == NULL) { - abort(); - } - pic_apply_argv(pic, proc, 0); - if (pic_undef_p(v)) { - abort(); - } + pic_eval(pic, v); + pic_gc_arena_restore(pic, ai); } @@ -243,7 +236,7 @@ macroexpand(pic_state *pic, pic_value expr, struct pic_senv *senv) pic_catch { /* restores pic->lib even if an error occurs */ pic_in_library(pic, prev->name); - longjmp(*pic->jmp, 1); + pic_throw(pic, pic->err); } return pic_none_value(); @@ -271,7 +264,6 @@ macroexpand(pic_state *pic, pic_value expr, struct pic_senv *senv) else if (tag == pic->sDEFINE_SYNTAX) { pic_value var, val; - struct pic_proc *proc; pic_sym uniq; struct pic_macro *mac; @@ -290,17 +282,16 @@ macroexpand(pic_state *pic, pic_value expr, struct pic_senv *senv) xh_put_int(senv->name, pic_sym(var), uniq); val = pic_cadr(pic, pic_cdr(pic, expr)); - proc = pic_compile(pic, val); - if (pic->err) { - printf("macroexpand error: %s\n", pic_errmsg(pic)); - abort(); - } - v = pic_apply(pic, proc, pic_nil_value()); - if (pic->err) { - printf("macroexpand error: %s\n", pic_errmsg(pic)); - abort(); - } - assert(pic_proc_p(v)); + + pic_try { + v = pic_eval(pic, val); + } pic_catch { + pic_errorf(pic, "macroexpand error: %s", pic_errmsg(pic)); + } + + if (! pic_proc_p(v)) { + pic_errorf(pic, "macro definition \"~s\" evaluates to non-procedure object", var); + } mac = macro_new(pic, pic_proc_ptr(v), senv); xh_put_int(pic->macros, uniq, (long)mac); @@ -311,7 +302,6 @@ macroexpand(pic_state *pic, pic_value expr, struct pic_senv *senv) else if (tag == pic->sDEFINE_MACRO) { pic_value var, val; - struct pic_proc *proc; pic_sym uniq; struct pic_macro *mac; @@ -339,17 +329,15 @@ macroexpand(pic_state *pic, pic_value expr, struct pic_senv *senv) uniq = pic_gensym(pic, pic_sym(var)); xh_put_int(senv->name, pic_sym(var), uniq); - proc = pic_compile(pic, val); - if (pic->err) { - printf("macroexpand error: %s\n", pic_errmsg(pic)); - abort(); - } - v = pic_apply(pic, proc, pic_nil_value()); - if (pic->err) { - printf("macroexpand error: %s\n", pic_errmsg(pic)); - abort(); - } - assert(pic_proc_p(v)); + pic_try { + v = pic_eval(pic, val); + } pic_catch { + pic_errorf(pic, "macroexpand error: %s", pic_errmsg(pic)); + } + + if (! pic_proc_p(v)) { + pic_errorf(pic, "macro definition \"~s\" evaluates to non-procedure object", var); + } mac = macro_new(pic, pic_proc_ptr(v), NULL); xh_put_int(pic->macros, uniq, (long)mac); @@ -441,7 +429,7 @@ macroexpand(pic_state *pic, pic_value expr, struct pic_senv *senv) /* macro */ if ((e = xh_get_int(pic->macros, tag)) != NULL) { - pic_value v; + pic_value v, args; struct pic_macro *mac; #if DEBUG @@ -452,19 +440,17 @@ macroexpand(pic_state *pic, pic_value expr, struct pic_senv *senv) mac = (struct pic_macro *)e->val; if (mac->senv == NULL) { /* legacy macro */ - v = pic_apply(pic, mac->proc, pic_cdr(pic, expr)); - if (pic->err) { - printf("macroexpand error: %s\n", pic_errmsg(pic)); - abort(); - } - } - else { - v = pic_apply_argv(pic, mac->proc, 3, expr, pic_obj_value(senv), pic_obj_value(mac->senv)); - if (pic->err) { - printf("macroexpand error: %s\n", pic_errmsg(pic)); - abort(); - } - } + args = pic_cdr(pic, expr); + } + else { + args = pic_list3(pic, expr, pic_obj_value(senv), pic_obj_value(mac->senv)); + } + + pic_try { + v = pic_apply(pic, mac->proc, args); + } pic_catch { + pic_errorf(pic, "macroexpand error: %s", pic_errmsg(pic)); + } pic_gc_arena_restore(pic, ai); pic_gc_protect(pic, v); @@ -508,8 +494,7 @@ macroexpand(pic_state *pic, pic_value expr, struct pic_senv *senv) pic_error(pic, "unexpected value type"); return pic_undef_value(); /* unreachable */ } - /* suppress warnings, never be called */ - abort(); + UNREACHABLE(); } static pic_value diff --git a/src/state.c b/src/state.c index c0a511eb..4875193e 100644 --- a/src/state.c +++ b/src/state.c @@ -42,11 +42,6 @@ pic_open(int argc, char *argv[], char **envp) pic->cibase = pic->ci = (pic_callinfo *)calloc(PIC_STACK_SIZE, sizeof(pic_callinfo)); pic->ciend = pic->cibase + PIC_STACK_SIZE; - /* exception handlers */ - pic->rescue = (struct pic_proc **)calloc(PIC_RESCUE_SIZE, sizeof(struct pic_proc *)); - pic->ridx = 0; - pic->rlen = PIC_RESCUE_SIZE; - /* memory heap */ pic->heap = pic_heap_open(); @@ -136,7 +131,6 @@ pic_close(pic_state *pic) /* clear out root objects */ pic->sp = pic->stbase; pic->ci = pic->cibase; - pic->ridx = 0; pic->arena_idx = 0; pic->err = NULL; pic->glen = 0; @@ -152,7 +146,6 @@ pic_close(pic_state *pic) /* free runtime context */ free(pic->stbase); free(pic->cibase); - free(pic->rescue); /* free global stacks */ free(pic->globals); diff --git a/src/vm.c b/src/vm.c index 51e1787a..4cefff0b 100644 --- a/src/vm.c +++ b/src/vm.c @@ -18,6 +18,7 @@ #include "picrin/var.h" #include "picrin/lib.h" #include "picrin/macro.h" +#include "picrin/error.h" #define GET_OPERAND(pic,n) ((pic)->ci->fp[(n)]) @@ -499,7 +500,6 @@ pic_apply(pic_state *pic, struct pic_proc *proc, pic_value argv) { pic_code c; int ai = pic_gc_arena_preserve(pic); - jmp_buf jmp, *prev_jmp = pic->jmp; size_t argc, i; pic_code boot[2]; @@ -515,13 +515,6 @@ pic_apply(pic_state *pic, struct pic_proc *proc, pic_value argv) }; #endif - if (setjmp(jmp) == 0) { - pic->jmp = &jmp; - } - else { - goto L_RAISE; - } - if (! pic_list_p(argv)) { pic_error(pic, "argv must be a proper list"); } @@ -773,12 +766,6 @@ pic_apply(pic_state *pic, struct pic_proc *proc, pic_value argv) pic_value *retv; pic_callinfo *ci; - if (pic->err) { - - L_RAISE: - goto L_STOP; - } - if (pic->ci->env != NULL) { vm_tear_off(pic); } @@ -918,7 +905,6 @@ pic_apply(pic_state *pic, struct pic_proc *proc, pic_value argv) } \ else { \ pic_error(pic, #op " got non-number operands"); \ - goto L_RAISE; \ } \ NEXT; \ } @@ -928,21 +914,12 @@ pic_apply(pic_state *pic, struct pic_proc *proc, pic_value argv) DEFINE_COMP_OP(OP_LE, <=); CASE(OP_STOP) { - pic_value val; - - L_STOP: - val = POP(); - - pic->jmp = prev_jmp; - if (pic->err) { - longjmp(*pic->jmp, 1); - } #if VM_DEBUG puts("**VM END STATE**"); printf("stbase\t= %p\nsp\t= %p\n", (void *)stbase, (void *)pic->sp); printf("cibase\t= %p\nci\t= %p\n", (void *)cibase, (void *)pic->ci); - if (stbase < pic->sp) { + if (stbase < pic->sp - 1) { pic_value *sp; printf("* stack trace:"); for (sp = stbase; pic->sp != sp; ++sp) { @@ -950,14 +927,12 @@ pic_apply(pic_state *pic, struct pic_proc *proc, pic_value argv) puts(""); } } - if (stbase > pic->sp) { + if (stbase > pic->sp - 1) { puts("*** stack underflow!"); } #endif - pic_gc_protect(pic, val); - - return val; + return pic_gc_protect(pic, POP()); } } VM_LOOP_END; }