summaryrefslogtreecommitdiffhomepage
path: root/mrbgems/mruby-error/src/exception.c
diff options
context:
space:
mode:
authortake_cheeze <[email protected]>2015-06-22 00:05:45 +0900
committerYukihiro "Matz" Matsumoto <[email protected]>2015-07-15 14:46:56 +0900
commitcdd72d9c3783749c979edf62522cf9636681538d (patch)
treefbedcf59fc7176d7e6b82adf20170e44b3787a98 /mrbgems/mruby-error/src/exception.c
parent2e4bc2de8889a321fbde9898bc9afc9daefd8f76 (diff)
downloadmruby-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.c102
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)
+{
+}