1 // Copyright David Abrahams 2001.
2 // Distributed under the Boost Software License, Version 1.0. (See
3 // accompanying file LICENSE_1_0.txt or copy at
4 // http://www.boost.org/LICENSE_1_0.txt)
5
6 #ifndef BOOST_PYTHON_SOURCE
7 # define BOOST_PYTHON_SOURCE
8 #endif
9
10 #include <boost/python/errors.hpp>
11 #include <boost/cast.hpp>
12 #include <boost/python/detail/exception_handler.hpp>
13
14 namespace boost { namespace python {
15
~error_already_set()16 error_already_set::~error_already_set() {}
17
18 // IMPORTANT: this function may only be called from within a catch block!
handle_exception_impl(function0<void> f)19 BOOST_PYTHON_DECL bool handle_exception_impl(function0<void> f)
20 {
21 try
22 {
23 if (detail::exception_handler::chain)
24 return detail::exception_handler::chain->handle(f);
25 f();
26 return false;
27 }
28 catch(const boost::python::error_already_set&)
29 {
30 // The python error reporting has already been handled.
31 }
32 catch(const std::bad_alloc&)
33 {
34 PyErr_NoMemory();
35 }
36 catch(const bad_numeric_cast& x)
37 {
38 PyErr_SetString(PyExc_OverflowError, x.what());
39 }
40 catch(const std::out_of_range& x)
41 {
42 PyErr_SetString(PyExc_IndexError, x.what());
43 }
44 catch(const std::invalid_argument& x)
45 {
46 PyErr_SetString(PyExc_ValueError, x.what());
47 }
48 catch(const std::exception& x)
49 {
50 PyErr_SetString(PyExc_RuntimeError, x.what());
51 }
52 catch(...)
53 {
54 PyErr_SetString(PyExc_RuntimeError, "unidentifiable C++ exception");
55 }
56 return true;
57 }
58
throw_error_already_set()59 void BOOST_PYTHON_DECL throw_error_already_set()
60 {
61 throw error_already_set();
62 }
63
64 namespace detail {
65
operator ()(function0<void> const & f) const66 bool exception_handler::operator()(function0<void> const& f) const
67 {
68 if (m_next)
69 {
70 return m_next->handle(f);
71 }
72 else
73 {
74 f();
75 return false;
76 }
77 }
78
exception_handler(handler_function const & impl)79 exception_handler::exception_handler(handler_function const& impl)
80 : m_impl(impl)
81 , m_next(0)
82 {
83 if (chain != 0)
84 tail->m_next = this;
85 else
86 chain = this;
87 tail = this;
88 }
89
90 exception_handler* exception_handler::chain;
91 exception_handler* exception_handler::tail;
92
register_exception_handler(handler_function const & f)93 BOOST_PYTHON_DECL void register_exception_handler(handler_function const& f)
94 {
95 // the constructor links the new object into a handler chain, so
96 // this object isn't actaully leaked (until, of course, the
97 // interpreter exits).
98 new exception_handler(f);
99 }
100
101 } // namespace boost::python::detail
102
103 }} // namespace boost::python
104
105
106