Looking at the source code for raise in Ruby the rb_raise is an alias for sprintf, or format! for us, and then pass the exception object on to be raised.
/* rb_raise is a sprintf formatter to exception raiser */
void
rb_raise(VALUE exc, const char *fmt, ...)
{
va_list args;
VALUE mesg;
va_start(args, fmt);
mesg = rb_vsprintf(fmt, args);
va_end(args);
rb_exc_raise(rb_exc_new3(exc, mesg));
}
/*
#define rb_exc_new3 rb_exc_new_str
*/
VALUE
rb_exc_new_str(VALUE etype, VALUE str)
{
StringValue(str);
return rb_class_new_instance(1, &str, etype);
}
/*!
* Raises an exception in the current thread.
* \param[in] mesg an Exception class or an \c Exception object.
* \exception always raises an instance of the given exception class or
* the given \c Exception object.
* \ingroup exception
*/
void
rb_exc_raise(VALUE mesg)
{
if (!NIL_P(mesg)) {
mesg = make_exception(1, &mesg, FALSE);
}
rb_longjmp(GET_EC(), TAG_RAISE, mesg, Qundef);
}
NORETURN(static void rb_longjmp(rb_execution_context_t *, int, volatile VALUE, VALUE));
static void
rb_longjmp(rb_execution_context_t *ec, int tag, volatile VALUE mesg, VALUE cause)
{
mesg = exc_setup_message(ec, mesg, &cause);
setup_exception(ec, tag, mesg, cause);
rb_ec_raised_clear(ec);
EC_JUMP_TAG(ec, tag);
}
/*
#define EC_JUMP_TAG(ec, st) rb_ec_tag_jump(ec, st)
*/
NORETURN(static inline void rb_ec_tag_jump(const rb_execution_context_t *ec, enum ruby_tag_type st));
static inline void
rb_ec_tag_jump(const rb_execution_context_t *ec, enum ruby_tag_type st)
{
ec->tag->state = st;
ruby_longjmp(ec->tag->buf, 1);
}
/*
#define ruby_longjmp(env,val) RUBY_LONGJMP((env),(val))
#define RUBY_LONGJMP(env,val) longjmp(env,val)
*/
Looking into longjmp that seems to be defined by the C language itself: “longjump(jmp_buf buf, i) : Go back to place buf is pointing to and return i”
My proposal for the raise! macro is to re-implement the sprintf behavior and the appropriate C code references to raise the exception back in Ruby.
I think this could work. It needs to be tested out first to verify we can do this.
Looking at the source code for raise in Ruby the
rb_raise
is an alias forsprintf
, orformat!
for us, and then pass the exception object on to be raised.Looking into
longjmp
that seems to be defined by the C language itself: “longjump(jmp_buf buf, i) : Go back to place buf is pointing to and return i”My proposal for the
raise!
macro is to re-implement thesprintf
behavior and the appropriate C code references to raise the exception back in Ruby.I think this could work. It needs to be tested out first to verify we can do this.