From cdd72d9c3783749c979edf62522cf9636681538d Mon Sep 17 00:00:00 2001 From: take_cheeze Date: Mon, 22 Jun 2015 00:05:45 +0900 Subject: Implement `mrb_protect`, `mrb_ensure`, `mrb_rescue`, `mrb_rescue_exceptions`. (`mrb_rescue_exceptions` is mruby implementation of `rb_rescue2`.) Closes #2844, closes #2837. --- mrbgems/mruby-error/src/exception.c | 102 ++++++++++++++++++++++++++++++++++++ 1 file changed, 102 insertions(+) create mode 100644 mrbgems/mruby-error/src/exception.c (limited to 'mrbgems/mruby-error/src') 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 +#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) +{ +} -- cgit v1.2.3 From f6b5a829729479d4ae557effc15656605ca71781 Mon Sep 17 00:00:00 2001 From: take_cheeze Date: Mon, 22 Jun 2015 10:49:37 +0900 Subject: Use class array instead of variadic. --- include/mruby/error.h | 3 ++- mrbgems/mruby-error/src/exception.c | 14 ++++++-------- mrbgems/mruby-error/test/exception.c | 4 +++- 3 files changed, 11 insertions(+), 10 deletions(-) (limited to 'mrbgems/mruby-error/src') diff --git a/include/mruby/error.h b/include/mruby/error.h index 3a985236a..d02e9166c 100644 --- a/include/mruby/error.h +++ b/include/mruby/error.h @@ -35,7 +35,8 @@ MRB_API mrb_value mrb_ensure(mrb_state *mrb, mrb_func_t body, mrb_value b_data, 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); 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, ...); + mrb_func_t rescue, mrb_value r_data, + mrb_int len, struct RClass **classes); #if defined(__cplusplus) } /* extern "C" { */ diff --git a/mrbgems/mruby-error/src/exception.c b/mrbgems/mruby-error/src/exception.c index abd03bc29..7199e0801 100644 --- a/mrbgems/mruby-error/src/exception.c +++ b/mrbgems/mruby-error/src/exception.c @@ -1,4 +1,3 @@ -#include #include "mruby.h" #include "mruby/throw.h" #include "mruby/error.h" @@ -52,18 +51,19 @@ 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); + return mrb_rescue_exceptions(mrb, body, b_data, rescue, r_data, 1, &mrb->eStandardError_class); } 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, ...) +mrb_rescue_exceptions(mrb_state *mrb, mrb_func_t body, mrb_value b_data, mrb_func_t rescue, mrb_value r_data, + mrb_int len, struct RClass **classes) { 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_int i; MRB_TRY(&c_jmp) { mrb->jmp = &c_jmp; @@ -72,14 +72,12 @@ mrb_rescue_exceptions(mrb_state *mrb, mrb_func_t body, mrb_value b_data, mrb_fun } 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)) { + for (i = 0; i < len; ++i) { + if (mrb_obj_is_kind_of(mrb, mrb_obj_value(mrb->exc), classes[i])) { error_matched = TRUE; break; } } - va_end(excs); if (!error_matched) { MRB_THROW(mrb->jmp); } diff --git a/mrbgems/mruby-error/test/exception.c b/mrbgems/mruby-error/test/exception.c index 7c15fb457..2a943aaae 100644 --- a/mrbgems/mruby-error/test/exception.c +++ b/mrbgems/mruby-error/test/exception.c @@ -40,8 +40,10 @@ static mrb_value run_rescue_exceptions(mrb_state *mrb, mrb_value self) { mrb_value b, r; + struct RClass *cls[1]; mrb_get_args(mrb, "oo", &b, &r); - return mrb_rescue_exceptions(mrb, protect_cb, b, protect_cb, r, E_TYPE_ERROR, NULL); + cls[0] = E_TYPE_ERROR; + return mrb_rescue_exceptions(mrb, protect_cb, b, protect_cb, r, 1, cls); } void -- cgit v1.2.3 From c0bf76d0a1ef631813c01d785500c1544d18a506 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Wed, 15 Jul 2015 14:43:34 +0900 Subject: remove unused variable declaration --- mrbgems/mruby-error/src/exception.c | 1 - 1 file changed, 1 deletion(-) (limited to 'mrbgems/mruby-error/src') diff --git a/mrbgems/mruby-error/src/exception.c b/mrbgems/mruby-error/src/exception.c index 7199e0801..9d77c6adf 100644 --- a/mrbgems/mruby-error/src/exception.c +++ b/mrbgems/mruby-error/src/exception.c @@ -61,7 +61,6 @@ mrb_rescue_exceptions(mrb_state *mrb, mrb_func_t body, mrb_value b_data, mrb_fun struct mrb_jmpbuf *prev_jmp = mrb->jmp; struct mrb_jmpbuf c_jmp; mrb_value result; - struct RClass *cls; mrb_bool error_matched = FALSE; mrb_int i; -- cgit v1.2.3 From 207577f0af72874d9d643f2c46b881a9159d42d7 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Wed, 15 Jul 2015 14:45:32 +0900 Subject: mrb_protect() to return the exception raised (with the state of true) --- mrbgems/mruby-error/src/exception.c | 1 + mrbgems/mruby-error/test/exception.rb | 8 +++++--- 2 files changed, 6 insertions(+), 3 deletions(-) (limited to 'mrbgems/mruby-error/src') diff --git a/mrbgems/mruby-error/src/exception.c b/mrbgems/mruby-error/src/exception.c index 9d77c6adf..911fde0be 100644 --- a/mrbgems/mruby-error/src/exception.c +++ b/mrbgems/mruby-error/src/exception.c @@ -17,6 +17,7 @@ mrb_protect(mrb_state *mrb, mrb_func_t body, mrb_value data, mrb_bool *state) mrb->jmp = prev_jmp; } MRB_CATCH(&c_jmp) { mrb->jmp = prev_jmp; + result = mrb_obj_value(mrb->exc); mrb->exc = NULL; if (state) { *state = TRUE; } } MRB_END_EXC(&c_jmp); diff --git a/mrbgems/mruby-error/test/exception.rb b/mrbgems/mruby-error/test/exception.rb index b5ea719a2..0bbc2a0e7 100644 --- a/mrbgems/mruby-error/test/exception.rb +++ b/mrbgems/mruby-error/test/exception.rb @@ -1,10 +1,12 @@ assert 'mrb_protect' do + # no failure in protect returns [result, false] assert_equal ['test', false] do ExceptionTest.mrb_protect { 'test' } end - assert_equal [nil, true] do - ExceptionTest.mrb_protect { raise 'test' } - end + # failure in protect returns [exception, true] + result = ExceptionTest.mrb_protect { raise 'test' } + assert_kind_of RuntimeError, result[0] + assert_true result[1] end assert 'mrb_ensure' do -- cgit v1.2.3