Rcpp Version 1.0.0
exceptions.h
Go to the documentation of this file.
1 // -*- mode: C++; c-indent-level: 4; c-basic-offset: 4; indent-tabs-mode: nil; -*-
2 //
3 // exceptions.h: Rcpp R/C++ interface class library -- exceptions
4 //
5 // Copyright (C) 2010 - 2017 Dirk Eddelbuettel and Romain Francois
6 //
7 // This file is part of Rcpp.
8 //
9 // Rcpp is free software: you can redistribute it and/or modify it
10 // under the terms of the GNU General Public License as published by
11 // the Free Software Foundation, either version 2 of the License, or
12 // (at your option) any later version.
13 //
14 // Rcpp is distributed in the hope that it will be useful, but
15 // WITHOUT ANY WARRANTY; without even the implied warranty of
16 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 // GNU General Public License for more details.
18 //
19 // You should have received a copy of the GNU General Public License
20 // along with Rcpp. If not, see <http://www.gnu.org/licenses/>.
21 
22 #ifndef Rcpp__exceptions__h
23 #define Rcpp__exceptions__h
24 
25 #include <Rversion.h>
26 
27 #ifndef RCPP_DEFAULT_INCLUDE_CALL
28 #define RCPP_DEFAULT_INCLUDE_CALL true
29 #endif
30 
31 #define GET_STACKTRACE() stack_trace( __FILE__, __LINE__ )
32 
33 namespace Rcpp {
34 
35  class exception : public std::exception {
36  public:
37  explicit exception(const char* message_, bool include_call = RCPP_DEFAULT_INCLUDE_CALL) : // #nocov start
38  message(message_),
41  }
42  exception(const char* message_, const char*, int, bool include_call = RCPP_DEFAULT_INCLUDE_CALL) :
43  message(message_),
46  }
47  bool include_call() const {
48  return include_call_;
49  }
50  virtual ~exception() throw() {}
51  virtual const char* what() const throw() {
52  return message.c_str(); // #nocov end
53  }
54  private:
55  std::string message;
57  };
58 
59  // simple helper
60  static std::string toString(const int i) { // #nocov start
61  std::ostringstream ostr;
62  ostr << i;
63  return ostr.str(); // #nocov end
64  }
65 
66  class no_such_env : public std::exception {
67  public:
68  no_such_env(const std::string& name) throw() :
69  message(std::string("no such environment: '") + name + "'") {};
70  no_such_env(int pos) throw() :
71  message("no environment in given position '" + toString(pos) + "'") {};
72  virtual ~no_such_env() throw() {};
73  virtual const char* what() const throw() { return message.c_str(); };
74  private:
75  std::string message;
76  };
77 
78  class file_io_error : public std::exception {
79  public:
80  file_io_error(const std::string& file) throw() : // #nocov start
81  message(std::string("file io error: '") + file + "'"), file(file) {};
82  file_io_error(int code, const std::string& file) throw() :
83  message("file io error " + toString(code) + ": '" + file + "'"), file(file) {};
84  file_io_error(const std::string& msg, const std::string& file) throw() :
85  message(msg + ": '" + file + "'"), file(file) {};
86  virtual ~file_io_error() throw() {};
87  virtual const char* what() const throw() { return message.c_str(); };
88  std::string filePath() const throw() { return file; }; // #nocov end
89  private:
90  std::string message;
91  std::string file;
92  } ;
93 
94  class file_not_found : public file_io_error { // #nocov start
95  public:
96  file_not_found(const std::string& file) throw() :
97  file_io_error("file not found", file) {} // #nocov end
98  };
99 
100  class file_exists : public file_io_error { // #nocov start
101  public:
102  file_exists(const std::string& file) throw() :
103  file_io_error("file already exists", file) {} // #nocov end
104  };
105 
106  // Variadic / code generated version of the warning and stop functions
107  // can be found within the respective C++11 or C++98 exceptions.h
108  // included below
109  inline void warning(const std::string& message) { // #nocov start
110  Rf_warning(message.c_str());
111  } // #nocov end
112 
113  inline void NORET stop(const std::string& message) { // #nocov start
114  throw Rcpp::exception(message.c_str());
115  } // #nocov end
116 
117 } // namespace Rcpp
118 
119 
120 namespace Rcpp { namespace internal {
121 
122 inline SEXP longjumpSentinel(SEXP token) {
123  SEXP sentinel = PROTECT(Rf_allocVector(VECSXP, 1));
124  SET_VECTOR_ELT(sentinel, 0, token);
125 
126  SEXP sentinelClass = PROTECT(Rf_mkString("Rcpp:longjumpSentinel"));
127  Rf_setAttrib(sentinel, R_ClassSymbol, sentinelClass) ;
128 
129  UNPROTECT(2);
130  return sentinel;
131 }
132 
133 inline bool isLongjumpSentinel(SEXP x) {
134  return
135  Rf_inherits(x, "Rcpp:longjumpSentinel") &&
136  TYPEOF(x) == VECSXP &&
137  Rf_length(x) == 1;
138 }
139 
140 inline SEXP getLongjumpToken(SEXP sentinel) {
141  return VECTOR_ELT(sentinel, 0);
142 }
143 
144 inline void resumeJump(SEXP token) {
145  if (isLongjumpSentinel(token)) {
146  token = getLongjumpToken(token);
147  }
148  ::R_ReleaseObject(token);
149 #if (defined(R_VERSION) && R_VERSION >= R_Version(3, 5, 0))
150  ::R_ContinueUnwind(token);
151 #endif
152  Rf_error("Internal error: Rcpp longjump failed to resume");
153 }
154 
155 }} // namespace Rcpp::internal
156 
157 
158 namespace Rcpp {
159 
161  SEXP token;
162  LongjumpException(SEXP token_) : token(token_) {
163  if (internal::isLongjumpSentinel(token)) {
164  token = internal::getLongjumpToken(token);
165  }
166  }
167 };
168 
169 } // namespace Rcpp
170 
171 
172 // Determine whether to use variadic templated RCPP_ADVANCED_EXCEPTION_CLASS,
173 // warning, and stop exception functions or to use the generated argument macro
174 // based on whether the compiler supports c++11 or not.
175 #if __cplusplus >= 201103L
177 #else
179 #endif
180 
181 namespace Rcpp {
182 
183  #define RCPP_EXCEPTION_CLASS(__CLASS__,__WHAT__) \
184  class __CLASS__ : public std::exception{ \
185  public: \
186  __CLASS__( ) throw() : message( std::string(__WHAT__) + "." ){} ; \
187  __CLASS__( const std::string& message ) throw() : \
188  message( std::string(__WHAT__) + ": " + message + "." ){} ; \
189  virtual ~__CLASS__() throw(){} ; \
190  virtual const char* what() const throw() { return message.c_str() ; } \
191  private: \
192  std::string message ; \
193  } ;
194 
195  #define RCPP_SIMPLE_EXCEPTION_CLASS(__CLASS__,__MESSAGE__) \
196  class __CLASS__ : public std::exception{ \
197  public: \
198  __CLASS__() throw() {} ; \
199  virtual ~__CLASS__() throw(){} ; \
200  virtual const char* what() const throw() { return __MESSAGE__ ; } \
201  } ;
202 
203  RCPP_SIMPLE_EXCEPTION_CLASS(not_a_matrix, "Not a matrix.") // #nocov start
204  RCPP_SIMPLE_EXCEPTION_CLASS(parse_error, "Parse error.")
205  RCPP_SIMPLE_EXCEPTION_CLASS(not_s4, "Not an S4 object.")
206  RCPP_SIMPLE_EXCEPTION_CLASS(not_reference, "Not an S4 object of a reference class.")
207  RCPP_SIMPLE_EXCEPTION_CLASS(not_initialized, "C++ object not initialized. (Missing default constructor?)")
208  RCPP_SIMPLE_EXCEPTION_CLASS(no_such_field, "No such field.") // not used internally
209  RCPP_SIMPLE_EXCEPTION_CLASS(no_such_function, "No such function.")
210  RCPP_SIMPLE_EXCEPTION_CLASS(unevaluated_promise, "Promise not yet evaluated.")
211  RCPP_SIMPLE_EXCEPTION_CLASS(embedded_nul_in_string, "Embedded NUL in string.")
212 
213  // Promoted
214  RCPP_EXCEPTION_CLASS(no_such_slot, "No such slot")
215  RCPP_EXCEPTION_CLASS(not_a_closure, "Not a closure")
216 
217  RCPP_EXCEPTION_CLASS(S4_creation_error, "Error creating object of S4 class")
218  RCPP_EXCEPTION_CLASS(reference_creation_error, "Error creating object of reference class") // not used internally
219  RCPP_EXCEPTION_CLASS(no_such_binding, "No such binding")
220  RCPP_EXCEPTION_CLASS(binding_not_found, "Binding not found")
221  RCPP_EXCEPTION_CLASS(binding_is_locked, "Binding is locked")
222  RCPP_EXCEPTION_CLASS(no_such_namespace, "No such namespace")
223  RCPP_EXCEPTION_CLASS(function_not_exported, "Function not exported")
224  RCPP_EXCEPTION_CLASS(eval_error, "Evaluation error") // #nocov end
225 
226  // Promoted
227  RCPP_ADVANCED_EXCEPTION_CLASS(not_compatible, "Not compatible" )
228  RCPP_ADVANCED_EXCEPTION_CLASS(index_out_of_bounds, "Index is out of bounds")
229 
230  #undef RCPP_SIMPLE_EXCEPTION_CLASS
231  #undef RCPP_EXCEPTION_CLASS
232  #undef RCPP_ADVANCED_EXCEPTION_CLASS
233 
234 
235 namespace internal {
236 
237  inline SEXP nth(SEXP s, int n) { // #nocov start
238  return Rf_length(s) > n ? (n == 0 ? CAR(s) : CAR(Rf_nthcdr(s, n))) : R_NilValue;
239  }
240 
241  // We want the call just prior to the call from Rcpp_eval
242  // This conditional matches
243  // tryCatch(evalq(sys.calls(), .GlobalEnv), error = identity, interrupt = identity)
244  inline bool is_Rcpp_eval_call(SEXP expr) {
245  SEXP sys_calls_symbol = Rf_install("sys.calls");
246  SEXP identity_symbol = Rf_install("identity");
247  Shield<SEXP> identity_fun(Rf_findFun(identity_symbol, R_BaseEnv));
248  SEXP tryCatch_symbol = Rf_install("tryCatch");
249  SEXP evalq_symbol = Rf_install("evalq");
250 
251  return TYPEOF(expr) == LANGSXP &&
252  Rf_length(expr) == 4 &&
253  nth(expr, 0) == tryCatch_symbol &&
254  CAR(nth(expr, 1)) == evalq_symbol &&
255  CAR(nth(nth(expr, 1), 1)) == sys_calls_symbol &&
256  nth(nth(expr, 1), 2) == R_GlobalEnv &&
257  nth(expr, 2) == identity_fun &&
258  nth(expr, 3) == identity_fun;
259  }
260 } // namespace internal
261 
262 } // namespace Rcpp
263 
264 inline SEXP get_last_call(){
265  SEXP sys_calls_symbol = Rf_install("sys.calls");
266 
267  Rcpp::Shield<SEXP> sys_calls_expr(Rf_lang1(sys_calls_symbol));
268  Rcpp::Shield<SEXP> calls(Rcpp_fast_eval(sys_calls_expr, R_GlobalEnv));
269 
270  SEXP cur, prev;
271  prev = cur = calls;
272  while(CDR(cur) != R_NilValue) {
273  SEXP expr = CAR(cur);
274 
276  break;
277  }
278  prev = cur;
279  cur = CDR(cur);
280  }
281  return CAR(prev);
282 }
283 
284 inline SEXP get_exception_classes( const std::string& ex_class) {
285  Rcpp::Shield<SEXP> res( Rf_allocVector( STRSXP, 4 ) );
286 
287  #ifndef RCPP_USING_UTF8_ERROR_STRING
288  SET_STRING_ELT( res, 0, Rf_mkChar( ex_class.c_str() ) ) ;
289  #else
290  SET_STRING_ELT( res, 0, Rf_mkCharLenCE( ex_class.c_str(), ex_class.size(), CE_UTF8 ) );
291  #endif
292  SET_STRING_ELT( res, 1, Rf_mkChar( "C++Error" ) ) ;
293  SET_STRING_ELT( res, 2, Rf_mkChar( "error" ) ) ;
294  SET_STRING_ELT( res, 3, Rf_mkChar( "condition" ) ) ;
295  return res;
296 }
297 
298 inline SEXP make_condition(const std::string& ex_msg, SEXP call, SEXP cppstack, SEXP classes){
299  Rcpp::Shield<SEXP> res( Rf_allocVector( VECSXP, 3 ) ) ;
300  #ifndef RCPP_USING_UTF8_ERROR_STRING
301  SET_VECTOR_ELT( res, 0, Rf_mkString( ex_msg.c_str() ) ) ;
302  #else
303  Rcpp::Shield<SEXP> ex_msg_rstring( Rf_allocVector( STRSXP, 1 ) ) ;
304  SET_STRING_ELT( ex_msg_rstring, 0, Rf_mkCharLenCE( ex_msg.c_str(), ex_msg.size(), CE_UTF8 ) );
305  SET_VECTOR_ELT( res, 0, ex_msg_rstring ) ;
306  #endif
307  SET_VECTOR_ELT( res, 1, call ) ;
308  SET_VECTOR_ELT( res, 2, cppstack ) ;
309 
310  Rcpp::Shield<SEXP> names( Rf_allocVector( STRSXP, 3 ) );
311  SET_STRING_ELT( names, 0, Rf_mkChar( "message" ) ) ;
312  SET_STRING_ELT( names, 1, Rf_mkChar( "call" ) ) ;
313  SET_STRING_ELT( names, 2, Rf_mkChar( "cppstack" ) ) ;
314  Rf_setAttrib( res, R_NamesSymbol, names ) ;
315  Rf_setAttrib( res, R_ClassSymbol, classes ) ;
316  return res ;
317 }
318 
319 template <typename Exception>
320 inline SEXP exception_to_condition_template( const Exception& ex, bool include_call) {
321  std::string ex_class = demangle( typeid(ex).name() ) ;
322  std::string ex_msg = ex.what() ;
323 
324  Rcpp::Shelter<SEXP> shelter;
325  SEXP call, cppstack;
326  if (include_call) {
327  call = shelter(get_last_call());
328  cppstack = shelter(rcpp_get_stack_trace());
329  } else {
330  call = R_NilValue;
331  cppstack = R_NilValue;
332  }
333  SEXP classes = shelter( get_exception_classes(ex_class) );
334  SEXP condition = shelter( make_condition( ex_msg, call, cppstack, classes) );
335  rcpp_set_stack_trace( R_NilValue ) ;
336  return condition ;
337 }
338 
341 }
342 
343 inline SEXP exception_to_r_condition( const std::exception& ex){
345 }
346 
347 inline SEXP string_to_try_error( const std::string& str){
348  using namespace Rcpp;
349 
350  #ifndef RCPP_USING_UTF8_ERROR_STRING
351  Rcpp::Shield<SEXP> txt(Rf_mkString(str.c_str()));
352  Rcpp::Shield<SEXP> simpleErrorExpr(Rf_lang2(::Rf_install("simpleError"), txt));
353  Rcpp::Shield<SEXP> tryError( Rf_mkString( str.c_str() ) );
354  #else
355  Rcpp::Shield<SEXP> tryError( Rf_allocVector( STRSXP, 1 ) ) ;
356  SET_STRING_ELT( tryError, 0, Rf_mkCharLenCE( str.c_str(), str.size(), CE_UTF8 ) );
357  Rcpp::Shield<SEXP> simpleErrorExpr( Rf_lang2(::Rf_install("simpleError"), tryError ));
358  #endif
359 
360  Rcpp::Shield<SEXP> simpleError( Rf_eval(simpleErrorExpr, R_GlobalEnv) );
361  Rf_setAttrib( tryError, R_ClassSymbol, Rf_mkString("try-error") ) ;
362  Rf_setAttrib( tryError, Rf_install( "condition") , simpleError ) ;
363 
364  return tryError; // #nocov end
365 }
366 
367 inline SEXP exception_to_try_error( const std::exception& ex){
368  return string_to_try_error(ex.what());
369 }
370 
371 std::string demangle( const std::string& name) ;
372 #define DEMANGLE(__TYPE__) demangle( typeid(__TYPE__).name() ).c_str()
373 
374 inline void forward_exception_to_r(const std::exception& ex){
375  SEXP stop_sym = Rf_install( "stop" ) ;
377  Rcpp::Shield<SEXP> expr( Rf_lang2( stop_sym , condition ) ) ;
378  Rf_eval( expr, R_GlobalEnv ) ;
379 }
380 
382  SEXP stop_sym = Rf_install( "stop" ) ;
384  Rcpp::Shield<SEXP> expr( Rf_lang2( stop_sym , condition ) ) ;
385  Rf_eval( expr, R_GlobalEnv ) ;
386 }
387 
388 
389 #endif
SEXP getLongjumpToken(SEXP sentinel)
Definition: exceptions.h:140
file_io_error(const std::string &msg, const std::string &file)
Definition: exceptions.h:84
RCPP_SIMPLE_EXCEPTION_CLASS(not_a_matrix, "Not a matrix.") RCPP_SIMPLE_EXCEPTION_CLASS(no_such_field
S4_Impl< PreserveStorage > S4
Definition: S4.h:75
self & field(const char *name_, T Class::*ptr, const char *docstring=0)
Definition: Module_Field.h:68
no_such_env(const std::string &name)
Definition: exceptions.h:68
LongjumpException(SEXP token_)
Definition: exceptions.h:162
file_io_error(const std::string &file)
Definition: exceptions.h:80
virtual ~no_such_env()
Definition: exceptions.h:72
#define RCPP_DEFAULT_INCLUDE_CALL
Definition: exceptions.h:28
#define RCPP_ADVANCED_EXCEPTION_CLASS(__CLASS__, __WHAT__)
Definition: exceptions.h:30
SEXP Rcpp_fast_eval(SEXP expr, SEXP env)
Definition: Rcpp_eval.h:68
attribute_hidden SEXP stack_trace(const char *file="", int line=-1)
Definition: routines.h:160
std::string demangle(const std::string &name)
Definition: routines.h:148
SEXP exception_to_r_condition(const std::exception &ex)
Definition: exceptions.h:343
Function_Impl< PreserveStorage > Function
Definition: Function.h:114
bool include_call() const
Definition: exceptions.h:47
SEXP exception_to_condition_template(const Exception &ex, bool include_call)
Definition: exceptions.h:320
void forward_exception_to_r(const std::exception &ex)
Definition: exceptions.h:374
bool include_call_
Definition: exceptions.h:56
virtual const char * what() const
Definition: exceptions.h:51
std::string message
Definition: exceptions.h:88
LogicalVector in(const VectorBase< RTYPE, NA, T > &x, const VectorBase< RTYPE, RHS_NA, RHS_T > &table)
Definition: unique.h:77
bool is_Rcpp_eval_call(SEXP expr)
Definition: exceptions.h:244
void resumeJump(SEXP token)
Definition: exceptions.h:144
bool isLongjumpSentinel(SEXP x)
Definition: exceptions.h:133
virtual const char * what() const
Definition: exceptions.h:87
attribute_hidden SEXP rcpp_set_stack_trace(SEXP e)
Definition: routines.h:142
exception(const char *message_, const char *, int, bool include_call=RCPP_DEFAULT_INCLUDE_CALL)
Definition: exceptions.h:42
SEXP get_exception_classes(const std::string &ex_class)
Definition: exceptions.h:284
SEXP exception_to_try_error(const std::exception &ex)
Definition: exceptions.h:367
no_such_env(int pos)
Definition: exceptions.h:70
SEXP rcpp_exception_to_r_condition(const Rcpp::exception &ex)
Definition: exceptions.h:339
void NORET stop(const char *fmt, Args &&... args)
Definition: exceptions.h:51
bool is(SEXP x)
Definition: is.h:53
virtual ~exception()
Definition: exceptions.h:50
std::string message
Definition: exceptions.h:55
SEXP nth(SEXP s, int n)
Definition: exceptions.h:237
static std::string toString(const int i)
Definition: exceptions.h:60
void warning(const char *fmt, Args &&... args)
Definition: exceptions.h:46
#define NORET
Definition: headers.h:75
SEXP get_last_call()
Definition: exceptions.h:264
void forward_rcpp_exception_to_r(const Rcpp::exception &ex)
Definition: exceptions.h:381
attribute_hidden SEXP rcpp_get_stack_trace()
Definition: routines.h:136
file_io_error(int code, const std::string &file)
Definition: exceptions.h:82
Rcpp API.
Definition: algo.h:28
virtual ~file_io_error()
Definition: exceptions.h:86
SEXP longjumpSentinel(SEXP token)
Definition: exceptions.h:122
virtual const char * what() const
Definition: exceptions.h:73
No such field RCPP_EXCEPTION_CLASS(reference_creation_error, "Error creating object of reference class") RCPP_EXCEPTION_CLASS(eval_error
exception(const char *message_, bool include_call=RCPP_DEFAULT_INCLUDE_CALL)
Definition: exceptions.h:37
SEXP make_condition(const std::string &ex_msg, SEXP call, SEXP cppstack, SEXP classes)
Definition: exceptions.h:298
SEXP string_to_try_error(const std::string &str)
Definition: exceptions.h:347
file_exists(const std::string &file)
Definition: exceptions.h:102
std::string file
Definition: exceptions.h:91
Promise_Impl< PreserveStorage > Promise
Definition: Promise.h:76
file_not_found(const std::string &file)
Definition: exceptions.h:96