ifndef Rice__ruby_try_catch__hpp_ define Rice__ruby_try_catch__hpp_

include “Exception_Base_defn.hpp” include “Jump_Tag.hpp” include “detail/ruby.hpp” include <stdexcept>

! \def RUBY_TRY
  \brief Start a block to catch Ruby exceptions and rethrow them.

// Goto is used here to avoid having to use a second try/catch block (we // can't rb_exc_raise directly out of the catch blocks below, since the // exceptions will not get properly cleaned up). // The labels are located before the try and not after it so the function can't // “fall through” into the exception-handling code accidentally. define RUBY_TRY \

VALUE Rice__ruby_exc = Qnil; \
int Rice__ruby_jump_tag = 0; \
\
goto start_of_RUBY_TRY; \
\
Rice__ruby_exception: \
  rb_exc_raise(Rice__ruby_exc); \
Rice__ruby_jump_tag: \
  rb_jump_tag(Rice__ruby_jump_tag); \
\
start_of_RUBY_TRY: \
try

! \def RUBY_RETHROW(ex)
  \brief Given a Ruby exception as a VALUE, safely raise the exception as a
         Ruby exception.  This should be used inside a RUBY_TRY/RUBY_CATCH
         block.
/

define RUBY_RETHROW(ex) \

Rice__ruby_exc = ex;  goto Rice__ruby_exception;

/*! def RUBY_CATCH

  \brief End a RUBY_TRY block.
/

define RUBY_CATCH \

catch(::Rice::Exception_Base const & ex) \
{ \
  RUBY_RETHROW(ex.value()); \
} \
catch(::Rice::Jump_Tag const & ex) \
{ \
  Rice__ruby_jump_tag = ex.tag; \
  goto Rice__ruby_jump_tag; \
} \
catch(std::bad_alloc const & ex) \
{ \
  /* This won't work quite right if the rb_exc_new2 fails; not       \
  /* much we can do about that, since Ruby doesn't give us access */ \
  /* to a pre-allocated NoMemoryError object                      */ \
  RUBY_RETHROW(rb_exc_new2(rb_eNoMemError, ex.what())); \
} \
catch(std::invalid_argument const & ex) \
{ \
  /* This can raise a NoMemoryError in VERY rare circumstances    */ \
  RUBY_RETHROW(rb_exc_new2(rb_eArgError, ex.what())); \
} \
catch(std::domain_error const & ex) \
{ \
  /* This can raise a NoMemoryError in VERY rare circumstances    */ \
  RUBY_RETHROW(rb_exc_new2(rb_eFloatDomainError, ex.what())); \
} \
catch(std::out_of_range const & ex) \
{ \
  /* This can raise a NoMemoryError in VERY rare circumstances    */ \
  RUBY_RETHROW(rb_exc_new2(rb_eRangeError, ex.what())); \
} \
catch(std::exception const & ex) \
{ \
  /* This can raise a NoMemoryError in VERY rare circumstances    */ \
  RUBY_RETHROW(rb_exc_new2(rb_eRuntimeError, ex.what())); \
} \
catch(...) \
{ \
  RUBY_RETHROW(rb_exc_new2(rb_eRuntimeError, "unknown C++ exception thrown")); \
} \

endif // Rice__ruby_try_catch__hpp_