Rcpp Version 0.12.12
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 #define GET_STACKTRACE() stack_trace( __FILE__, __LINE__ )
26 
27 namespace Rcpp {
28 
29  class exception : public std::exception {
30  public:
31  explicit exception(const char* message_, bool include_call = true) : // #nocov start
32  message(message_),
35  }
36  exception(const char* message_, const char*, int, bool include_call = true) :
37  message(message_),
40  }
41  bool include_call() const {
42  return include_call_;
43  }
44  virtual ~exception() throw() {}
45  virtual const char* what() const throw() {
46  return message.c_str(); // #nocov end
47  }
48  private:
49  std::string message;
51  };
52 
53  // simple helper
54  static std::string toString(const int i) { // #nocov start
55  std::ostringstream ostr;
56  ostr << i;
57  return ostr.str(); // #nocov end
58  }
59 
60  class no_such_env : public std::exception {
61  public:
62  no_such_env(const std::string& name) throw() :
63  message(std::string("no such environment: '") + name + "'") {};
64  no_such_env(int pos) throw() :
65  message("no environment in given position '" + toString(pos) + "'") {};
66  virtual ~no_such_env() throw() {};
67  virtual const char* what() const throw() { return message.c_str(); };
68  private:
69  std::string message;
70  };
71 
72  class file_io_error : public std::exception {
73  public:
74  file_io_error(const std::string& file) throw() : // #nocov start
75  message(std::string("file io error: '") + file + "'"), file(file) {};
76  file_io_error(int code, const std::string& file) throw() :
77  message("file io error " + toString(code) + ": '" + file + "'"), file(file) {};
78  file_io_error(const std::string& msg, const std::string& file) throw() :
79  message(msg + ": '" + file + "'"), file(file) {};
80  virtual ~file_io_error() throw() {};
81  virtual const char* what() const throw() { return message.c_str(); };
82  std::string filePath() const throw() { return file; }; // #nocov end
83  private:
84  std::string message;
85  std::string file;
86  } ;
87 
88  class file_not_found : public file_io_error { // #nocov start
89  public:
90  file_not_found(const std::string& file) throw() :
91  file_io_error("file not found", file) {} // #nocov end
92  };
93 
94  class file_exists : public file_io_error { // #nocov start
95  public:
96  file_exists(const std::string& file) throw() :
97  file_io_error("file already exists", file) {} // #nocov end
98  };
99 
100  // Variadic / code generated version of the warning and stop functions
101  // can be found within the respective C++11 or C++98 exceptions.h
102  // included below
103  inline void warning(const std::string& message) { // #nocov start
104  Rf_warning(message.c_str());
105  } // #nocov end
106 
107  inline void NORET stop(const std::string& message) { // #nocov start
108  throw Rcpp::exception(message.c_str());
109  } // #nocov end
110 
111 } // namespace Rcpp
112 
113 
114 // Determine whether to use variadic templated RCPP_ADVANCED_EXCEPTION_CLASS,
115 // warning, and stop exception functions or to use the generated argument macro
116 // based on whether the compiler supports c++11 or not.
117 #if __cplusplus >= 201103L
119 #else
121 #endif
122 
123 namespace Rcpp {
124 
125  #define RCPP_EXCEPTION_CLASS(__CLASS__,__WHAT__) \
126  class __CLASS__ : public std::exception{ \
127  public: \
128  __CLASS__( ) throw() : message( std::string(__WHAT__) + "." ){} ; \
129  __CLASS__( const std::string& message ) throw() : \
130  message( std::string(__WHAT__) + ": " + message + "." ){} ; \
131  virtual ~__CLASS__() throw(){} ; \
132  virtual const char* what() const throw() { return message.c_str() ; } \
133  private: \
134  std::string message ; \
135  } ;
136 
137  #define RCPP_SIMPLE_EXCEPTION_CLASS(__CLASS__,__MESSAGE__) \
138  class __CLASS__ : public std::exception{ \
139  public: \
140  __CLASS__() throw() {} ; \
141  virtual ~__CLASS__() throw(){} ; \
142  virtual const char* what() const throw() { return __MESSAGE__ ; } \
143  } ;
144 
145  RCPP_SIMPLE_EXCEPTION_CLASS(not_a_matrix, "Not a matrix.") // #nocov start
146  RCPP_SIMPLE_EXCEPTION_CLASS(parse_error, "Parse error.")
147  RCPP_SIMPLE_EXCEPTION_CLASS(not_s4, "Not an S4 object.")
148  RCPP_SIMPLE_EXCEPTION_CLASS(not_reference, "Not an S4 object of a reference class.")
149  RCPP_SIMPLE_EXCEPTION_CLASS(not_initialized, "C++ object not initialized. (Missing default constructor?)")
150  RCPP_SIMPLE_EXCEPTION_CLASS(no_such_field, "No such field.") // not used internally
151  RCPP_SIMPLE_EXCEPTION_CLASS(no_such_function, "No such function.")
152  RCPP_SIMPLE_EXCEPTION_CLASS(unevaluated_promise, "Promise not yet evaluated.")
153 
154  // Promoted
155  RCPP_EXCEPTION_CLASS(no_such_slot, "No such slot")
156  RCPP_EXCEPTION_CLASS(not_a_closure, "Not a closure")
157 
158  RCPP_EXCEPTION_CLASS(S4_creation_error, "Error creating object of S4 class")
159  RCPP_EXCEPTION_CLASS(reference_creation_error, "Error creating object of reference class") // not used internally
160  RCPP_EXCEPTION_CLASS(no_such_binding, "No such binding")
161  RCPP_EXCEPTION_CLASS(binding_not_found, "Binding not found")
162  RCPP_EXCEPTION_CLASS(binding_is_locked, "Binding is locked")
163  RCPP_EXCEPTION_CLASS(no_such_namespace, "No such namespace")
164  RCPP_EXCEPTION_CLASS(function_not_exported, "Function not exported")
165  RCPP_EXCEPTION_CLASS(eval_error, "Evaluation error") // #nocov end
166 
167  // Promoted
168  RCPP_ADVANCED_EXCEPTION_CLASS(not_compatible, "Not compatible" )
169  RCPP_ADVANCED_EXCEPTION_CLASS(index_out_of_bounds, "Index is out of bounds")
170 
171  #undef RCPP_SIMPLE_EXCEPTION_CLASS
172  #undef RCPP_EXCEPTION_CLASS
173  #undef RCPP_ADVANCED_EXCEPTION_CLASS
174 
175 
176 namespace internal {
177 
178  inline SEXP nth(SEXP s, int n) { // #nocov start
179  return Rf_length(s) > n ? (n == 0 ? CAR(s) : CAR(Rf_nthcdr(s, n))) : R_NilValue;
180  }
181 
182  // We want the call just prior to the call from Rcpp_eval
183  // This conditional matches
184  // tryCatch(evalq(sys.calls(), .GlobalEnv), error = identity, interrupt = identity)
185  inline bool is_Rcpp_eval_call(SEXP expr) {
186  SEXP sys_calls_symbol = Rf_install("sys.calls");
187  SEXP identity_symbol = Rf_install("identity");
188  SEXP identity_fun = Rf_findFun(identity_symbol, R_BaseEnv);
189  SEXP tryCatch_symbol = Rf_install("tryCatch");
190  SEXP evalq_symbol = Rf_install("evalq");
191 
192  return TYPEOF(expr) == LANGSXP &&
193  Rf_length(expr) == 4 &&
194  nth(expr, 0) == tryCatch_symbol &&
195  CAR(nth(expr, 1)) == evalq_symbol &&
196  CAR(nth(nth(expr, 1), 1)) == sys_calls_symbol &&
197  nth(nth(expr, 1), 2) == R_GlobalEnv &&
198  nth(expr, 2) == identity_fun &&
199  nth(expr, 3) == identity_fun;
200  }
201 } // namespace internal
202 
203 } // namespace Rcpp
204 
205 inline SEXP get_last_call(){
206  SEXP sys_calls_symbol = Rf_install("sys.calls");
207 
208  Rcpp::Shield<SEXP> sys_calls_expr(Rf_lang1(sys_calls_symbol));
209  Rcpp::Shield<SEXP> calls(Rcpp_eval(sys_calls_expr, R_GlobalEnv));
210 
211  SEXP cur, prev;
212  prev = cur = calls;
213  while(CDR(cur) != R_NilValue) {
214  SEXP expr = CAR(cur);
215 
217  break;
218  }
219  prev = cur;
220  cur = CDR(cur);
221  }
222  return CAR(prev);
223 }
224 
225 inline SEXP get_exception_classes( const std::string& ex_class) {
226  Rcpp::Shield<SEXP> res( Rf_allocVector( STRSXP, 4 ) );
227 
228  #ifndef RCPP_USING_UTF8_ERROR_STRING
229  SET_STRING_ELT( res, 0, Rf_mkChar( ex_class.c_str() ) ) ;
230  #else
231  SET_STRING_ELT( res, 0, Rf_mkCharLenCE( ex_class.c_str(), ex_class.size(), CE_UTF8 ) );
232  #endif
233  SET_STRING_ELT( res, 1, Rf_mkChar( "C++Error" ) ) ;
234  SET_STRING_ELT( res, 2, Rf_mkChar( "error" ) ) ;
235  SET_STRING_ELT( res, 3, Rf_mkChar( "condition" ) ) ;
236  return res;
237 }
238 
239 inline SEXP make_condition(const std::string& ex_msg, SEXP call, SEXP cppstack, SEXP classes){
240  Rcpp::Shield<SEXP> res( Rf_allocVector( VECSXP, 3 ) ) ;
241  #ifndef RCPP_USING_UTF8_ERROR_STRING
242  SET_VECTOR_ELT( res, 0, Rf_mkString( ex_msg.c_str() ) ) ;
243  #else
244  Rcpp::Shield<SEXP> ex_msg_rstring( Rf_allocVector( STRSXP, 1 ) ) ;
245  SET_STRING_ELT( ex_msg_rstring, 0, Rf_mkCharLenCE( ex_msg.c_str(), ex_msg.size(), CE_UTF8 ) );
246  SET_VECTOR_ELT( res, 0, ex_msg_rstring ) ;
247  #endif
248  SET_VECTOR_ELT( res, 1, call ) ;
249  SET_VECTOR_ELT( res, 2, cppstack ) ;
250 
251  Rcpp::Shield<SEXP> names( Rf_allocVector( STRSXP, 3 ) );
252  SET_STRING_ELT( names, 0, Rf_mkChar( "message" ) ) ;
253  SET_STRING_ELT( names, 1, Rf_mkChar( "call" ) ) ;
254  SET_STRING_ELT( names, 2, Rf_mkChar( "cppstack" ) ) ;
255  Rf_setAttrib( res, R_NamesSymbol, names ) ;
256  Rf_setAttrib( res, R_ClassSymbol, classes ) ;
257  return res ;
258 }
259 
261  std::string ex_class = demangle( typeid(ex).name() ) ;
262  std::string ex_msg = ex.what() ;
263 
264  SEXP call, cppstack;
265  if (ex.include_call()) {
268  } else {
269  call = R_NilValue;
270  cppstack = R_NilValue;
271  }
272  Rcpp::Shield<SEXP> classes( get_exception_classes(ex_class) );
273  Rcpp::Shield<SEXP> condition( make_condition( ex_msg, call, cppstack, classes) );
274  rcpp_set_stack_trace( R_NilValue ) ;
275  return condition ;
276 }
277 
278 inline SEXP exception_to_r_condition( const std::exception& ex){
279  std::string ex_class = demangle( typeid(ex).name() ) ;
280  std::string ex_msg = ex.what() ;
281 
284  Rcpp::Shield<SEXP> classes( get_exception_classes(ex_class) );
285  Rcpp::Shield<SEXP> condition( make_condition( ex_msg, call, cppstack, classes) );
286  rcpp_set_stack_trace( R_NilValue ) ;
287  return condition ;
288 }
289 
290 inline SEXP string_to_try_error( const std::string& str){
291  using namespace Rcpp;
292 
293  #ifndef RCPP_USING_UTF8_ERROR_STRING
294  Rcpp::Shield<SEXP> txt(Rf_mkString(str.c_str()));
295  Rcpp::Shield<SEXP> simpleErrorExpr(Rf_lang2(::Rf_install("simpleError"), txt));
296  Rcpp::Shield<SEXP> tryError( Rf_mkString( str.c_str() ) );
297  #else
298  Rcpp::Shield<SEXP> tryError( Rf_allocVector( STRSXP, 1 ) ) ;
299  SET_STRING_ELT( tryError, 0, Rf_mkCharLenCE( str.c_str(), str.size(), CE_UTF8 ) );
300  Rcpp::Shield<SEXP> simpleErrorExpr( Rf_lang2(::Rf_install("simpleError"), tryError ));
301  #endif
302 
303  Rcpp::Shield<SEXP> simpleError( Rf_eval(simpleErrorExpr, R_GlobalEnv) );
304  Rf_setAttrib( tryError, R_ClassSymbol, Rf_mkString("try-error") ) ;
305  Rf_setAttrib( tryError, Rf_install( "condition") , simpleError ) ;
306 
307  return tryError; // #nocov end
308 }
309 
310 inline SEXP exception_to_try_error( const std::exception& ex){
311  return string_to_try_error(ex.what());
312 }
313 
314 std::string demangle( const std::string& name) ;
315 #define DEMANGLE(__TYPE__) demangle( typeid(__TYPE__).name() ).c_str()
316 
317 inline void forward_exception_to_r(const std::exception& ex){
318  SEXP stop_sym = Rf_install( "stop" ) ;
320  Rcpp::Shield<SEXP> expr( Rf_lang2( stop_sym , condition ) ) ;
321  Rf_eval( expr, R_GlobalEnv ) ;
322 }
323 
325  SEXP stop_sym = Rf_install( "stop" ) ;
327  Rcpp::Shield<SEXP> expr( Rf_lang2( stop_sym , condition ) ) ;
328  Rf_eval( expr, R_GlobalEnv ) ;
329 }
330 
331 
332 #endif
file_io_error(const std::string &msg, const std::string &file)
Definition: exceptions.h:78
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:62
file_io_error(const std::string &file)
Definition: exceptions.h:74
virtual ~no_such_env()
Definition: exceptions.h:66
#define RCPP_ADVANCED_EXCEPTION_CLASS(__CLASS__, __WHAT__)
Definition: exceptions.h:30
attribute_hidden SEXP stack_trace(const char *file="", int line=-1)
Definition: routines.h:146
exception(const char *message_, bool include_call=true)
Definition: exceptions.h:31
virtual const char * what() const
Definition: exceptions.h:45
virtual const char * what() const
Definition: exceptions.h:67
void warning(const char *fmt, Args &&...args)
Definition: exceptions.h:46
std::string demangle(const std::string &name)
Definition: routines.h:134
SEXP exception_to_r_condition(const std::exception &ex)
Definition: exceptions.h:278
Function_Impl< PreserveStorage > Function
Definition: Function.h:114
void forward_exception_to_r(const std::exception &ex)
Definition: exceptions.h:317
bool include_call_
Definition: exceptions.h:50
SEXP Rcpp_eval(SEXP expr, SEXP env)
Definition: Rcpp_eval.h:25
std::string message
Definition: exceptions.h:82
bool is_Rcpp_eval_call(SEXP expr)
Definition: exceptions.h:185
attribute_hidden SEXP rcpp_set_stack_trace(SEXP e)
Definition: routines.h:128
SEXP get_exception_classes(const std::string &ex_class)
Definition: exceptions.h:225
SEXP exception_to_try_error(const std::exception &ex)
Definition: exceptions.h:310
no_such_env(int pos)
Definition: exceptions.h:64
SEXP rcpp_exception_to_r_condition(const Rcpp::exception &ex)
Definition: exceptions.h:260
bool is(SEXP x)
Definition: is.h:53
virtual ~exception()
Definition: exceptions.h:44
std::string message
Definition: exceptions.h:49
virtual const char * what() const
Definition: exceptions.h:81
SEXP nth(SEXP s, int n)
Definition: exceptions.h:178
static std::string toString(const int i)
Definition: exceptions.h:54
#define NORET
Definition: headers.h:64
void NORET stop(const char *fmt, Args &&...args)
Definition: exceptions.h:51
SEXP get_last_call()
Definition: exceptions.h:205
exception(const char *message_, const char *, int, bool include_call=true)
Definition: exceptions.h:36
void forward_rcpp_exception_to_r(const Rcpp::exception &ex)
Definition: exceptions.h:324
attribute_hidden SEXP rcpp_get_stack_trace()
Definition: routines.h:122
file_io_error(int code, const std::string &file)
Definition: exceptions.h:76
Rcpp API.
Definition: algo.h:28
virtual ~file_io_error()
Definition: exceptions.h:80
RCPP_SIMPLE_EXCEPTION_CLASS(not_a_matrix,"Not a matrix.") RCPP_SIMPLE_EXCEPTION_CLASS(no_such_field
SEXP make_condition(const std::string &ex_msg, SEXP call, SEXP cppstack, SEXP classes)
Definition: exceptions.h:239
SEXP string_to_try_error(const std::string &str)
Definition: exceptions.h:290
file_exists(const std::string &file)
Definition: exceptions.h:96
std::string file
Definition: exceptions.h:85
No such field RCPP_EXCEPTION_CLASS(reference_creation_error,"Error creating object of reference class") RCPP_EXCEPTION_CLASS(eval_error
bool include_call() const
Definition: exceptions.h:41
Promise_Impl< PreserveStorage > Promise
Definition: Promise.h:76
file_not_found(const std::string &file)
Definition: exceptions.h:90