@@@ -20,126 -18,23 +21,127 @@@ struct RException
};
#define mrb_exc_ptr(v) ((struct RException*)mrb_ptr(v))
+ #define MRB_EXC_MESG_STRING_FLAG 0x100
-void mrb_sys_fail(mrb_state *mrb, const char *mesg);
-mrb_value mrb_exc_new_str(mrb_state *mrb, struct RClass* c, mrb_value str);
-#define mrb_exc_new_str_lit(mrb, c, lit) mrb_exc_new_str(mrb, c, mrb_str_new_lit(mrb, lit))
-mrb_value mrb_make_exception(mrb_state *mrb, int argc, const mrb_value *argv);
-void mrb_exc_print(mrb_state *mrb, struct RObject *exc);
-void mrb_print_backtrace(mrb_state *mrb);
+MRB_API void mrb_sys_fail(mrb_state *mrb, const char *mesg);
+MRB_API mrb_value mrb_exc_new_str(mrb_state *mrb, struct RClass* c, mrb_value str);
+#define mrb_exc_new_lit(mrb, c, lit) mrb_exc_new_str(mrb, c, mrb_str_new_lit(mrb, lit))
+#define mrb_exc_new_str_lit(mrb, c, lit) mrb_exc_new_lit(mrb, c, lit)
+MRB_API mrb_value mrb_make_exception(mrb_state *mrb, mrb_int argc, const mrb_value *argv);
mrb_value mrb_exc_backtrace(mrb_state *mrb, mrb_value exc);
mrb_value mrb_get_backtrace(mrb_state *mrb);
-mrb_noreturn void mrb_no_method_error(mrb_state *mrb, mrb_sym id, mrb_int argc, const mrb_value *argv, const char *fmt, ...);
-/* declaration for fail method */
-mrb_value mrb_f_raise(mrb_state*, mrb_value);
+MRB_API mrb_noreturn void mrb_no_method_error(mrb_state *mrb, mrb_sym id, mrb_value args, const char *fmt, ...);
+
+/* declaration for `fail` method */
+MRB_API mrb_value mrb_f_raise(mrb_state*, mrb_value);
+
+#if defined(MRB_64BIT) || defined(MRB_USE_FLOAT32) || defined(MRB_NAN_BOXING) || defined(MRB_WORD_BOXING)
+struct RBreak {
+ MRB_OBJECT_HEADER;
+ const struct RProc *proc;
+ mrb_value val;
+};
+#define mrb_break_value_get(brk) ((brk)->val)
+#define mrb_break_value_set(brk, v) ((brk)->val = v)
+#else
+struct RBreak {
+ MRB_OBJECT_HEADER;
+ const struct RProc *proc;
+ union mrb_value_union value;
+};
+#define RBREAK_VALUE_TT_MASK ((1 << 8) - 1)
+static inline mrb_value
+mrb_break_value_get(struct RBreak *brk)
+{
+ mrb_value val;
+ val.value = brk->value;
+ val.tt = (enum mrb_vtype)(brk->flags & RBREAK_VALUE_TT_MASK);
+ return val;
+}
+static inline void
+mrb_break_value_set(struct RBreak *brk, mrb_value val)
+{
+ brk->value = val.value;
+ brk->flags &= ~RBREAK_VALUE_TT_MASK;
+ brk->flags |= val.tt;
+}
+#endif /* MRB_64BIT || MRB_USE_FLOAT32 || MRB_NAN_BOXING || MRB_WORD_BOXING */
+#define mrb_break_proc_get(brk) ((brk)->proc)
+#define mrb_break_proc_set(brk, p) ((brk)->proc = p)
+
+#define RBREAK_TAG_FOREACH(f) \
+ f(RBREAK_TAG_BREAK, 0) \
+ f(RBREAK_TAG_BREAK_UPPER, 1) \
+ f(RBREAK_TAG_BREAK_INTARGET, 2) \
+ f(RBREAK_TAG_RETURN_BLOCK, 3) \
+ f(RBREAK_TAG_RETURN, 4) \
+ f(RBREAK_TAG_RETURN_TOPLEVEL, 5) \
+ f(RBREAK_TAG_JUMP, 6) \
+ f(RBREAK_TAG_STOP, 7)
+
+#define RBREAK_TAG_DEFINE(tag, i) tag = i,
+enum {
+ RBREAK_TAG_FOREACH(RBREAK_TAG_DEFINE)
+};
+#undef RBREAK_TAG_DEFINE
+
+#define RBREAK_TAG_BIT 3
+#define RBREAK_TAG_BIT_OFF 8
+#define RBREAK_TAG_MASK (~(~UINT32_C(0) << RBREAK_TAG_BIT))
+
+static inline uint32_t
+mrb_break_tag_get(struct RBreak *brk)
+{
+ return (brk->flags >> RBREAK_TAG_BIT_OFF) & RBREAK_TAG_MASK;
+}
+
+static inline void
+mrb_break_tag_set(struct RBreak *brk, uint32_t tag)
+{
+ brk->flags &= ~(RBREAK_TAG_MASK << RBREAK_TAG_BIT_OFF);
+ brk->flags |= (tag & RBREAK_TAG_MASK) << RBREAK_TAG_BIT_OFF;
+}
+
+/**
+ * Protect
+ *
+ */
+typedef mrb_value mrb_protect_error_func(mrb_state *mrb, void *userdata);
+MRB_API mrb_value mrb_protect_error(mrb_state *mrb, mrb_protect_error_func *body, void *userdata, mrb_bool *error);
+
+/**
+ * Protect (takes mrb_value for body argument)
+ *
+ * Implemented in the mruby-error mrbgem
+ */
+MRB_API mrb_value mrb_protect(mrb_state *mrb, mrb_func_t body, mrb_value data, mrb_bool *state);
+
+/**
+ * Ensure
+ *
+ * Implemented in the mruby-error mrbgem
+ */
+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);
+
+/**
+ * Rescue
+ *
+ * Implemented in the mruby-error mrbgem
+ */
+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);
+
+/**
+ * Rescue exception
+ *
+ * Implemented in the mruby-error mrbgem
+ */
+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_int len, struct RClass **classes);
-#if defined(__cplusplus)
-} /* extern "C" { */
-#endif
+MRB_END_DECL
#endif /* MRUBY_ERROR_H */
*/
#include <errno.h>
-#include <stdarg.h>
#include <stdlib.h>
-#include "mruby.h"
-#include "mruby/array.h"
-#include "mruby/irep.h"
-#include "mruby/proc.h"
-#include "mruby/string.h"
-#include "mruby/variable.h"
-#include "mruby/debug.h"
-#include "mruby/error.h"
-#include "mruby/class.h"
-#include "mrb_throw.h"
+#include <mruby.h>
+#include <mruby/array.h>
+#include <mruby/irep.h>
+#include <mruby/proc.h>
+#include <mruby/string.h>
+#include <mruby/variable.h>
+#include <mruby/error.h>
+#include <mruby/class.h>
+#include <mruby/throw.h>
+#include <mruby/presym.h>
-mrb_value
-mrb_exc_new(mrb_state *mrb, struct RClass *c, const char *ptr, long len)
+ static void
+ exc_mesg_set(mrb_state *mrb, struct RException *exc, mrb_value mesg)
+ {
+ if (mrb_string_p(mesg)) {
+ exc->flags |= MRB_EXC_MESG_STRING_FLAG;
+ exc->mesg = RSTRING(mesg);
+ mrb_field_write_barrier_value(mrb, (struct RBasic*)exc, mesg);
+ }
+ else if (!mrb_nil_p(mesg)) {
+ exc->flags &= ~MRB_EXC_MESG_STRING_FLAG;
+ mrb_obj_iv_set(mrb, (struct RObject*)exc, mrb_intern_lit(mrb, "mesg"), mesg);
+ }
+ }
+
+ static mrb_value
+ exc_mesg_get(mrb_state *mrb, struct RException *exc)
+ {
+ return (exc->flags & MRB_EXC_MESG_STRING_FLAG) != 0
+ ? mrb_obj_value(exc->mesg) : mrb_obj_iv_get(mrb, (struct RObject*)exc, mrb_intern_lit(mrb, "mesg"));
+ }
+
+MRB_API mrb_value
+mrb_exc_new_str(mrb_state *mrb, struct RClass* c, mrb_value str)
{
- mrb_value arg = mrb_str_new(mrb, ptr, len);
- return mrb_obj_new(mrb, c, 1, &arg);
+ mrb_ensure_string_type(mrb, str);
+
+ struct RBasic* e = mrb_obj_alloc(mrb, MRB_TT_EXCEPTION, c);
+ mrb_value exc = mrb_obj_value(e);
+ mrb_iv_set(mrb, exc, MRB_SYM(mesg), str);
+ return exc;
}
-mrb_value
-mrb_exc_new_str(mrb_state *mrb, struct RClass* c, mrb_value str)
+MRB_API mrb_value
+mrb_exc_new(mrb_state *mrb, struct RClass *c, const char *ptr, size_t len)
{
- str = mrb_str_to_str(mrb, str);
- return mrb_obj_new(mrb, c, 1, &str);
+ return mrb_exc_new_str(mrb, c, mrb_str_new(mrb, ptr, len));
}
/*
@@@ -130,60 -151,75 +151,60 @@@ exc_message(mrb_state *mrb, mrb_value e
* returns message and class name.
*/
-static mrb_value
-exc_inspect(mrb_state *mrb, mrb_value exc)
+mrb_value
+mrb_exc_inspect(mrb_state *mrb, mrb_value exc)
{
- mrb_value mesg = mrb_attr_get(mrb, exc, MRB_SYM(mesg));
- mrb_value str, mesg, file, line;
- mrb_bool append_mesg;
-
- mesg = exc_mesg_get(mrb, mrb_exc_ptr(exc));
- file = mrb_attr_get(mrb, exc, mrb_intern_lit(mrb, "file"));
- line = mrb_attr_get(mrb, exc, mrb_intern_lit(mrb, "line"));
++ mrb_value mesg = exc_mesg_get(mrb, mrb_exc_ptr(exc));
+ mrb_value cname = mrb_mod_to_s(mrb, mrb_obj_value(mrb_obj_class(mrb, exc)));
+ mesg = mrb_obj_as_string(mrb, mesg);
+ return RSTRING_LEN(mesg) == 0 ? cname : mrb_format(mrb, "%v (%v)", mesg, cname);
+}
- append_mesg = !mrb_nil_p(mesg);
- if (append_mesg) {
- mesg = mrb_obj_as_string(mrb, mesg);
- append_mesg = RSTRING_LEN(mesg) > 0;
- }
+void mrb_keep_backtrace(mrb_state *mrb, mrb_value exc);
- if (!mrb_nil_p(file) && !mrb_nil_p(line)) {
- str = mrb_str_dup(mrb, file);
- mrb_str_cat_lit(mrb, str, ":");
- mrb_str_append(mrb, str, line);
- mrb_str_cat_lit(mrb, str, ": ");
- if (append_mesg) {
- mrb_str_append(mrb, str, mesg);
- mrb_str_cat_lit(mrb, str, " (");
- }
- mrb_str_cat_cstr(mrb, str, mrb_obj_classname(mrb, exc));
- if (append_mesg) {
- mrb_str_cat_lit(mrb, str, ")");
- }
+static void
+set_backtrace(mrb_state *mrb, mrb_value exc, mrb_value backtrace)
+{
+ if (!mrb_array_p(backtrace)) {
+ type_err:
+ mrb_raise(mrb, E_TYPE_ERROR, "backtrace must be Array of String");
}
else {
- const char *cname = mrb_obj_classname(mrb, exc);
- str = mrb_str_new_cstr(mrb, cname);
- mrb_str_cat_lit(mrb, str, ": ");
- if (append_mesg) {
- mrb_str_append(mrb, str, mesg);
- }
- else {
- mrb_str_cat_cstr(mrb, str, cname);
+ const mrb_value *p = RARRAY_PTR(backtrace);
+ const mrb_value *pend = p + RARRAY_LEN(backtrace);
+
+ while (p < pend) {
+ if (!mrb_string_p(*p)) goto type_err;
+ p++;
}
}
- return str;
+ mrb_iv_set(mrb, exc, MRB_SYM(backtrace), backtrace);
}
-
-static void
-exc_debug_info(mrb_state *mrb, struct RObject *exc)
+static mrb_value
+exc_set_backtrace(mrb_state *mrb, mrb_value exc)
{
- mrb_callinfo *ci = mrb->c->ci;
- mrb_code *pc = ci->pc;
+ mrb_value backtrace = mrb_get_arg1(mrb);
- mrb_obj_iv_set(mrb, exc, mrb_intern_lit(mrb, "ciidx"), mrb_fixnum_value((mrb_int)(ci - mrb->c->cibase)));
- while (ci >= mrb->c->cibase) {
- mrb_code *err = ci->err;
-
- if (!err && pc) err = pc - 1;
- if (err && ci->proc && !MRB_PROC_CFUNC_P(ci->proc)) {
- mrb_irep *irep = ci->proc->body.irep;
+ set_backtrace(mrb, exc, backtrace);
+ return backtrace;
+}
- int32_t const line = mrb_debug_get_line(irep, (uint32_t)(err - irep->iseq));
- char const* file = mrb_debug_get_filename(irep, (uint32_t)(err - irep->iseq));
- if (line != -1 && file) {
- mrb_obj_iv_set(mrb, exc, mrb_intern_lit(mrb, "file"), mrb_str_new_cstr(mrb, file));
- mrb_obj_iv_set(mrb, exc, mrb_intern_lit(mrb, "line"), mrb_fixnum_value(line));
- return;
- }
+void
+mrb_exc_set(mrb_state *mrb, mrb_value exc)
+{
+ if (mrb_nil_p(exc)) {
+ mrb->exc = 0;
+ }
+ else {
+ mrb->exc = mrb_obj_ptr(exc);
+ if (mrb->gc.arena_idx > 0 &&
+ (struct RBasic*)mrb->exc == mrb->gc.arena[mrb->gc.arena_idx-1]) {
+ mrb->gc.arena_idx--;
+ }
+ if (!mrb->gc.out_of_memory && !mrb_frozen_p(mrb->exc)) {
+ mrb_keep_backtrace(mrb, exc);
}
- pc = ci->pc;
- ci--;
}
}