diff options
| author | take_cheeze <[email protected]> | 2015-06-22 00:05:45 +0900 |
|---|---|---|
| committer | Yukihiro "Matz" Matsumoto <[email protected]> | 2015-07-15 14:46:56 +0900 |
| commit | cdd72d9c3783749c979edf62522cf9636681538d (patch) | |
| tree | fbedcf59fc7176d7e6b82adf20170e44b3787a98 /mrbgems/mruby-error/src/exception.c | |
| parent | 2e4bc2de8889a321fbde9898bc9afc9daefd8f76 (diff) | |
| download | mruby-cdd72d9c3783749c979edf62522cf9636681538d.tar.gz mruby-cdd72d9c3783749c979edf62522cf9636681538d.zip | |
Implement `mrb_protect`, `mrb_ensure`, `mrb_rescue`, `mrb_rescue_exceptions`.
(`mrb_rescue_exceptions` is mruby implementation of `rb_rescue2`.)
Closes #2844, closes #2837.
Diffstat (limited to 'mrbgems/mruby-error/src/exception.c')
| -rw-r--r-- | mrbgems/mruby-error/src/exception.c | 102 |
1 files changed, 102 insertions, 0 deletions
diff --git a/mrbgems/mruby-error/src/exception.c b/mrbgems/mruby-error/src/exception.c new file mode 100644 index 000000000..abd03bc29 --- /dev/null +++ b/mrbgems/mruby-error/src/exception.c @@ -0,0 +1,102 @@ +#include <stdarg.h> +#include "mruby.h" +#include "mruby/throw.h" +#include "mruby/error.h" + +MRB_API mrb_value +mrb_protect(mrb_state *mrb, mrb_func_t body, mrb_value data, mrb_bool *state) +{ + struct mrb_jmpbuf *prev_jmp = mrb->jmp; + struct mrb_jmpbuf c_jmp; + mrb_value result = mrb_nil_value(); + + if (state) { *state = FALSE; } + + MRB_TRY(&c_jmp) { + mrb->jmp = &c_jmp; + result = body(mrb, data); + mrb->jmp = prev_jmp; + } MRB_CATCH(&c_jmp) { + mrb->jmp = prev_jmp; + mrb->exc = NULL; + if (state) { *state = TRUE; } + } MRB_END_EXC(&c_jmp); + + mrb_gc_protect(mrb, result); + return result; +} + +MRB_API mrb_value +mrb_ensure(mrb_state *mrb, mrb_func_t body, mrb_value b_data, mrb_func_t ensure, mrb_value e_data) +{ + struct mrb_jmpbuf *prev_jmp = mrb->jmp; + struct mrb_jmpbuf c_jmp; + mrb_value result; + + MRB_TRY(&c_jmp) { + mrb->jmp = &c_jmp; + result = body(mrb, b_data); + mrb->jmp = prev_jmp; + } MRB_CATCH(&c_jmp) { + mrb->jmp = prev_jmp; + ensure(mrb, e_data); + MRB_THROW(mrb->jmp); /* rethrow catched exceptions */ + } MRB_END_EXC(&c_jmp); + + ensure(mrb, e_data); + mrb_gc_protect(mrb, result); + return result; +} + +MRB_API mrb_value +mrb_rescue(mrb_state *mrb, mrb_func_t body, mrb_value b_data, + mrb_func_t rescue, mrb_value r_data) +{ + return mrb_rescue_exceptions(mrb, body, b_data, rescue, r_data, mrb->eStandardError_class, NULL); +} + +MRB_API mrb_value +mrb_rescue_exceptions(mrb_state *mrb, mrb_func_t body, mrb_value b_data, mrb_func_t rescue, mrb_value r_data, ...) +{ + struct mrb_jmpbuf *prev_jmp = mrb->jmp; + struct mrb_jmpbuf c_jmp; + mrb_value result; + va_list excs; + struct RClass *cls; + mrb_bool error_matched = FALSE; + + MRB_TRY(&c_jmp) { + mrb->jmp = &c_jmp; + result = body(mrb, b_data); + mrb->jmp = prev_jmp; + } MRB_CATCH(&c_jmp) { + mrb->jmp = prev_jmp; + + va_start(excs, r_data); + while((cls = va_arg(excs, struct RClass*))) { + if (mrb_obj_is_kind_of(mrb, mrb_obj_value(mrb->exc), cls)) { + error_matched = TRUE; + break; + } + } + va_end(excs); + + if (!error_matched) { MRB_THROW(mrb->jmp); } + + mrb->exc = NULL; + result = rescue(mrb, r_data); + } MRB_END_EXC(&c_jmp); + + mrb_gc_protect(mrb, result); + return result; +} + +void +mrb_mruby_error_gem_init(mrb_state *mrb) +{ +} + +void +mrb_mruby_error_gem_final(mrb_state *mrb) +{ +} |
