File: exceptions.h

package info (click to toggle)
rcpp 0.11.3-1
  • links: PTS
  • area: main
  • in suites: jessie, jessie-kfreebsd
  • size: 9,948 kB
  • ctags: 16,427
  • sloc: ansic: 42,692; cpp: 34,078; makefile: 32; sh: 21
file content (208 lines) | stat: -rw-r--r-- 9,074 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
// -*- mode: C++; c-indent-level: 4; c-basic-offset: 4; tab-width: 8 -*-
//
// exceptions.h: Rcpp R/C++ interface class library -- exceptions
//
// Copyright (C) 2010 - 2013 Dirk Eddelbuettel and Romain Francois
//
// This file is part of Rcpp.
//
// Rcpp is free software: you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 2 of the License, or
// (at your option) any later version.
//
// Rcpp is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Rcpp.  If not, see <http://www.gnu.org/licenses/>.

#ifndef Rcpp__exceptions__h
#define Rcpp__exceptions__h

#define GET_STACKTRACE() stack_trace( __FILE__, __LINE__ )

namespace Rcpp{

    class exception : public std::exception {
    public:
        explicit exception(const char* message_) : message(message_){}
        exception(const char* message_, const char* file, int line ) : message(message_){
            rcpp_set_stack_trace( stack_trace(file,line) ) ;
        }
        virtual ~exception() throw(){}
        virtual const char* what() const throw() {
            return message.c_str() ;
        }
    private:
        std::string message ;
    } ;

    // simple helper
    static std::string toString(const int i) {
        std::ostringstream ostr;
        ostr << i;
        return ostr.str();
    }

    class no_such_env : public std::exception{
    public:
        no_such_env( const std::string& name ) throw() : message( std::string("no such environment: '") + name + "'" ){} ;
        no_such_env( int pos ) throw() : message( "no environment in given position '" + toString(pos) + "'") {} ;
        virtual ~no_such_env() throw(){} ;
        virtual const char* what() const throw(){ return message.c_str() ; } ;
    private:
        std::string message ;
    } ;

    class file_io_error : public std::exception {
    public:
        file_io_error(const std::string& file) throw() : message( std::string("file io error: '") + file + "'" ), file(file) {} ;
        file_io_error(int code, const std::string& file) throw() : message( "file io error " + toString(code) + ": '" + file + "'"), file(file) {} ;
        file_io_error(const std::string& msg, const std::string& file) throw() : message( msg + ": '" + file + "'"), file(file) {} ;
        virtual ~file_io_error() throw(){} ;
        virtual const char* what() const throw(){ return message.c_str() ; } ;
        std::string filePath() const throw(){ return file ; } ;
    private:
        std::string message ;
        std::string file;
    } ;

    class file_not_found : public file_io_error {
    public:
        file_not_found(const std::string& file) throw() : file_io_error("file not found", file) {}
    };

    class file_exists : public file_io_error {
    public:
        file_exists(const std::string& file) throw() : file_io_error("file already exists", file) {}
    };

    #define RCPP_EXCEPTION_CLASS(__CLASS__,__WHAT__)                               \
    class __CLASS__ : public std::exception{                                       \
    public:                                                                        \
        __CLASS__( const std::string& message ) throw() : message( __WHAT__ ){} ;  \
        virtual ~__CLASS__() throw(){} ;                                           \
        virtual const char* what() const throw() { return message.c_str() ; }      \
    private:                                                                       \
        std::string message ;                                                      \
    } ;

    #define RCPP_SIMPLE_EXCEPTION_CLASS(__CLASS__,__MESSAGE__)                     \
    class __CLASS__ : public std::exception{                                       \
    public:                                                                        \
        __CLASS__() throw() {} ;                                                   \
        virtual ~__CLASS__() throw(){} ;                                           \
        virtual const char* what() const throw() { return __MESSAGE__ ; }          \
    } ;

    RCPP_SIMPLE_EXCEPTION_CLASS(not_a_matrix, "not a matrix")
    RCPP_SIMPLE_EXCEPTION_CLASS(index_out_of_bounds, "index out of bounds")
    RCPP_SIMPLE_EXCEPTION_CLASS(parse_error, "parse error")
    RCPP_SIMPLE_EXCEPTION_CLASS(not_s4, "not an S4 object")
    RCPP_SIMPLE_EXCEPTION_CLASS(not_reference, "not an S4 object of a reference class")
    RCPP_SIMPLE_EXCEPTION_CLASS(not_initialized, "C++ object not initialized (missing default constructor?)")
    RCPP_SIMPLE_EXCEPTION_CLASS(no_such_slot, "no such slot")
    RCPP_SIMPLE_EXCEPTION_CLASS(no_such_field, "no such field")
    RCPP_SIMPLE_EXCEPTION_CLASS(not_a_closure, "not a closure")
    RCPP_SIMPLE_EXCEPTION_CLASS(no_such_function, "no such function")
    RCPP_SIMPLE_EXCEPTION_CLASS(unevaluated_promise, "promise not yet evaluated")

    RCPP_EXCEPTION_CLASS(not_compatible, message )
    RCPP_EXCEPTION_CLASS(S4_creation_error, std::string("error creating object of S4 class : ") + message )
    RCPP_EXCEPTION_CLASS(reference_creation_error, std::string("error creating object of reference class : ") + message )
    RCPP_EXCEPTION_CLASS(no_such_binding, std::string("no such binding : '") + message + "'" )
    RCPP_EXCEPTION_CLASS(binding_not_found, std::string("binding not found: '") + message + "'" )
    RCPP_EXCEPTION_CLASS(binding_is_locked, std::string("binding is locked: '") + message + "'" )
    RCPP_EXCEPTION_CLASS(no_such_namespace, std::string("no such namespace: '") + message + "'" )
    RCPP_EXCEPTION_CLASS(function_not_exported, std::string("function not exported: ") + message)
    RCPP_EXCEPTION_CLASS(eval_error, message )

    #undef RCPP_EXCEPTION_CLASS
    #undef RCPP_SIMPLE_EXCEPTION_CLASS


} // namespace Rcpp

inline SEXP get_last_call(){
    SEXP sys_calls_symbol = Rf_install( "sys.calls" ) ;
    Rcpp::Shield<SEXP> sys_calls_expr( Rf_lang1(sys_calls_symbol) );
    Rcpp::Shield<SEXP> calls( Rf_eval( sys_calls_expr, R_GlobalEnv ) );
    SEXP res = calls ;
    while( !Rf_isNull(CDR(res)) ) res = CDR(res);
    return CAR(res) ;
}

inline SEXP get_exception_classes( const std::string& ex_class) {
    Rcpp::Shield<SEXP> res( Rf_allocVector( STRSXP, 4 ) );
    SET_STRING_ELT( res, 0, Rf_mkChar( ex_class.c_str() ) ) ;
    SET_STRING_ELT( res, 1, Rf_mkChar( "C++Error" ) ) ;
    SET_STRING_ELT( res, 2, Rf_mkChar( "error" ) ) ;
    SET_STRING_ELT( res, 3, Rf_mkChar( "condition" ) ) ;
    return res;
}

inline SEXP make_condition(const std::string& ex_msg, SEXP call, SEXP cppstack, SEXP classes){
    Rcpp::Shield<SEXP> res( Rf_allocVector( VECSXP, 3 ) ) ;

    SET_VECTOR_ELT( res, 0, Rf_mkString( ex_msg.c_str() ) ) ;
    SET_VECTOR_ELT( res, 1, call ) ;
    SET_VECTOR_ELT( res, 2, cppstack ) ;

    Rcpp::Shield<SEXP> names( Rf_allocVector( STRSXP, 3 ) );
    SET_STRING_ELT( names, 0, Rf_mkChar( "message" ) ) ;
    SET_STRING_ELT( names, 1, Rf_mkChar( "call" ) ) ;
    SET_STRING_ELT( names, 2, Rf_mkChar( "cppstack" ) ) ;
    Rf_setAttrib( res, R_NamesSymbol, names ) ;
    Rf_setAttrib( res, R_ClassSymbol, classes ) ;
    return res ;
}

inline SEXP exception_to_r_condition( const std::exception& ex){
    std::string ex_class = demangle( typeid(ex).name() ) ;
    std::string ex_msg   = ex.what() ;

    Rcpp::Shield<SEXP> cppstack( rcpp_get_stack_trace() );
    Rcpp::Shield<SEXP> call( get_last_call() );
    Rcpp::Shield<SEXP> classes( get_exception_classes(ex_class) );
    Rcpp::Shield<SEXP> condition( make_condition( ex_msg, call, cppstack, classes) );
    rcpp_set_stack_trace( R_NilValue ) ;
    return condition ;
}

inline SEXP string_to_try_error( const std::string& str){
    using namespace Rcpp;

    Rcpp::Shield<SEXP> simpleErrorExpr( Rf_lang2(::Rf_install("simpleError"), Rf_mkString(str.c_str())) );
    Rcpp::Shield<SEXP> simpleError( Rf_eval(simpleErrorExpr, R_GlobalEnv) );
    Rcpp::Shield<SEXP> tryError( Rf_mkString( str.c_str() ) );
    Rf_setAttrib( tryError, R_ClassSymbol, Rf_mkString("try-error") ) ;
    Rf_setAttrib( tryError, Rf_install( "condition") , simpleError ) ;

    return tryError;
}

inline SEXP exception_to_try_error( const std::exception& ex){
    return string_to_try_error(ex.what());
}

std::string demangle( const std::string& name) ;
#define DEMANGLE(__TYPE__) demangle( typeid(__TYPE__).name() ).c_str()

namespace Rcpp{
    inline void stop(const std::string& message) {
        throw Rcpp::exception(message.c_str());
    }
}

inline void forward_exception_to_r( const std::exception& ex){
    SEXP stop_sym  = Rf_install( "stop" ) ;
    Rcpp::Shield<SEXP> condition( exception_to_r_condition(ex) );
    Rcpp::Shield<SEXP> expr( Rf_lang2( stop_sym , condition ) ) ;
    Rf_eval( expr, R_GlobalEnv ) ;
}


#endif