Error integration: error::Flag as subclass of State. Wrapped throw
This commit is contained in:
parent
acd0671390
commit
90d311dc1d
5 changed files with 134 additions and 69 deletions
|
|
@ -192,7 +192,6 @@ namespace backend {
|
|||
lumiera_thread_join (thread_);
|
||||
thread_ = 0;
|
||||
|
||||
TODO("check this, is error::State approbiate or do we want Runtime as thrown by throwOnError()");
|
||||
if (errorInOtherThread)
|
||||
throw lumiera::error::State ("Thread terminated with error:", errorInOtherThread);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
ERROR.hpp - Lumiera Exception Interface
|
||||
|
||||
Copyright (C) Lumiera.org
|
||||
2008, Hermann Vosseler <Ichthyostega@web.de>
|
||||
2008-2010 Hermann Vosseler <Ichthyostega@web.de>
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License as
|
||||
|
|
@ -33,32 +33,32 @@
|
|||
namespace lumiera {
|
||||
|
||||
using std::string;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/** error-ID for unspecified exceptions */
|
||||
LUMIERA_ERROR_DECLARE(EXCEPTION);
|
||||
|
||||
/**
|
||||
* Interface and Base class of all Exceptions thrown
|
||||
* Interface and Base class of all Exceptions thrown
|
||||
* from within Lumiera (C++) code. Common operations
|
||||
* for getting an diagnostic message and for obtaining
|
||||
* the root cause, i.e. the first exception encountered
|
||||
* in a chain of exceptions.
|
||||
* in a chain of exceptions.
|
||||
*/
|
||||
class Error : public std::exception
|
||||
{
|
||||
public:
|
||||
Error (string description="", const char* id=LUMIERA_ERROR_EXCEPTION) throw();
|
||||
Error (string description="", const char* const id=LUMIERA_ERROR_EXCEPTION) throw();
|
||||
Error (std::exception const& cause,
|
||||
string description="", const char* id=LUMIERA_ERROR_EXCEPTION) throw();
|
||||
string description="", const char* const id=LUMIERA_ERROR_EXCEPTION) throw();
|
||||
|
||||
Error (const Error&) throw();
|
||||
virtual ~Error () throw() {};
|
||||
|
||||
/** yield a diagnostic message characterising the problem */
|
||||
virtual const char* what () const throw();
|
||||
|
||||
|
||||
/** the internal Lumiera-error-ID (was set as C-errorstate in ctor) */
|
||||
const char* getID () const throw() { return this->id_; }
|
||||
|
||||
|
|
@ -72,10 +72,10 @@ namespace lumiera {
|
|||
* @return the description string, maybe empty (if there is no known root cause)
|
||||
*/
|
||||
const string& rootCause () const throw() { return this->cause_; }
|
||||
|
||||
|
||||
/** replace the previous or default friendly message for the user. To be localised. */
|
||||
Error& setUsermsg (const string& newMsg) throw() { this->msg_ = newMsg; return *this; }
|
||||
|
||||
|
||||
/** give additional developer info. Typically used at intermediate handlers to add context. */
|
||||
Error& prependInfo (const string& text) throw() { this->desc_.insert (0,text); return *this; }
|
||||
|
||||
|
|
@ -86,19 +86,18 @@ namespace lumiera {
|
|||
string desc_; ///< detailed description of the error situation for the developers
|
||||
mutable string what_; ///< buffer for generating the detailed description on demand
|
||||
const string cause_; ///< description of first exception encountered in the chain
|
||||
|
||||
|
||||
static const string extractCauseMsg (std::exception const&) throw();
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/* === Exception Sub-categories === */
|
||||
|
||||
namespace error
|
||||
{
|
||||
|
||||
namespace error {
|
||||
|
||||
/** global function for handling unknown exceptions
|
||||
* encountered at functions declaring not to throw
|
||||
|
|
@ -107,28 +106,28 @@ namespace lumiera {
|
|||
* add some diagnostics prior to halting.
|
||||
*/
|
||||
void lumiera_unexpectedException () throw();
|
||||
|
||||
|
||||
/** throw an error::Fatal indicating "assertion failure" */
|
||||
void assertion_terminate (const string& location);
|
||||
|
||||
|
||||
|
||||
/* constants to be used as error IDs */
|
||||
LUMIERA_ERROR_DECLARE (LOGIC ); ///< contradiction to internal logic assumptions detected
|
||||
LUMIERA_ERROR_DECLARE (FATAL ); ///< unable to cope with, internal logic floundered
|
||||
LUMIERA_ERROR_DECLARE (LOGIC ); ///< contradiction to internal logic assumptions detected
|
||||
LUMIERA_ERROR_DECLARE (FATAL ); ///< unable to cope with, internal logic floundered
|
||||
LUMIERA_ERROR_DECLARE (CONFIG ); ///< execution aborted due to misconfiguration
|
||||
LUMIERA_ERROR_DECLARE (STATE ); ///< unforeseen internal state
|
||||
LUMIERA_ERROR_DECLARE (FLAG ); ///< non-cleared lumiera errorstate from C code
|
||||
LUMIERA_ERROR_DECLARE (INVALID ); ///< invalid input or parameters encountered
|
||||
LUMIERA_ERROR_DECLARE (EXTERNAL ); ///< failure in external service the application relies on
|
||||
LUMIERA_ERROR_DECLARE (ASSERTION); ///< assertion failure
|
||||
|
||||
/* generic error situations */
|
||||
LUMIERA_ERROR_DECLARE (WRONG_TYPE); ///< runtime type mismatch
|
||||
LUMIERA_ERROR_DECLARE (ITER_EXHAUST); ///< end of sequence reached
|
||||
LUMIERA_ERROR_DECLARE (BOTTOM_VALUE); ///< invalid or NIL value
|
||||
LUMIERA_ERROR_DECLARE (RUNTIME); ///< generic runtime error, will be overridden by id
|
||||
|
||||
LUMIERA_ERROR_DECLARE (WRONG_TYPE); ///< runtime type mismatch
|
||||
LUMIERA_ERROR_DECLARE (ITER_EXHAUST); ///< end of sequence reached
|
||||
LUMIERA_ERROR_DECLARE (BOTTOM_VALUE); ///< invalid or NIL value
|
||||
|
||||
/** Macro for creating derived exception classes properly
|
||||
|
||||
/** Macro for creating derived exception classes properly
|
||||
* integrated into Lumiera's exception hierarchy. Using
|
||||
* this macro assures that the new class will get the full
|
||||
* set of constructors and behaviour common to all exception
|
||||
|
|
@ -143,44 +142,73 @@ namespace lumiera {
|
|||
const char* id=_ID_) throw() \
|
||||
: PARENT (description, id) {} \
|
||||
\
|
||||
CLASS (std::exception& cause, \
|
||||
CLASS (std::exception const& cause, \
|
||||
std::string description="", \
|
||||
const char* id=_ID_) throw() \
|
||||
: PARENT (cause, description, id) {} \
|
||||
};
|
||||
|
||||
|
||||
//-------------------------CLASS-----PARENT--ID----------------------
|
||||
LUMIERA_EXCEPTION_DECLARE (Logic, Error, LUMIERA_ERROR_LOGIC);
|
||||
LUMIERA_EXCEPTION_DECLARE (Fatal, Logic, LUMIERA_ERROR_FATAL);
|
||||
LUMIERA_EXCEPTION_DECLARE (Config, Error, LUMIERA_ERROR_CONFIG);
|
||||
LUMIERA_EXCEPTION_DECLARE (State, Error, LUMIERA_ERROR_STATE);
|
||||
LUMIERA_EXCEPTION_DECLARE (Flag, State, LUMIERA_ERROR_FLAG);
|
||||
LUMIERA_EXCEPTION_DECLARE (Invalid, Error, LUMIERA_ERROR_INVALID);
|
||||
LUMIERA_EXCEPTION_DECLARE (External, Error, LUMIERA_ERROR_EXTERNAL);
|
||||
LUMIERA_EXCEPTION_DECLARE (Runtime, Error, LUMIERA_ERROR_RUNTIME);
|
||||
|
||||
|
||||
/** install our own handler for undeclared exceptions. Will be
|
||||
* called automatically ON_BASIC_INIT when linking exception.cpp */
|
||||
void install_unexpectedException_handler ();
|
||||
|
||||
/** @return error detail-info if currently set, a default message else */
|
||||
const char* detailInfo ();
|
||||
|
||||
} // namespace error
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Throw a 'Runtime' error which wraps an existing lumiera error
|
||||
* no-op when no error is pending. Does not clear the error state.
|
||||
* Check the lumiera error state, which maybe was set by C-code.
|
||||
* @throw Errorflag exception to signal an detected lumiera error
|
||||
* @note specific error code and information is enclosed in
|
||||
* the raised exception; the error state is \em not cleared.
|
||||
*/
|
||||
static inline void throwOnError()
|
||||
inline void
|
||||
throwOnError()
|
||||
{
|
||||
lumiera_err err = lumiera_error_peek();
|
||||
if (err)
|
||||
if (lumiera_err errorFlag =lumiera_error())
|
||||
{
|
||||
const char* extra = lumiera_error_extra();
|
||||
throw error::Runtime(extra?extra:"", err);
|
||||
}
|
||||
throw error::Flag( error::detailInfo()
|
||||
, errorFlag);
|
||||
} } //causes the error state to be set
|
||||
|
||||
/** Check the lumiera error state and throw a specific exception
|
||||
* in case a non-cleared errorflag is detected. No-op else.
|
||||
* @throw instance of the lumiera::Error subclass provided as
|
||||
* template parameter, containing an lumiera::error::Flag
|
||||
* as root cause to denote the detected error-flag state.
|
||||
*/
|
||||
template<class EX>
|
||||
inline void
|
||||
maybeThrow(string description)
|
||||
{
|
||||
if (lumiera_err errorFlag =lumiera_error())
|
||||
{
|
||||
throw EX (error::Flag( error::detailInfo()
|
||||
, errorFlag)
|
||||
,description);
|
||||
} }
|
||||
|
||||
template<class EX>
|
||||
inline void
|
||||
maybeThrow()
|
||||
{
|
||||
maybeThrow<EX>("");
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
} // namespace lumiera
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -34,6 +34,11 @@ using std::exception;
|
|||
|
||||
|
||||
namespace lumiera {
|
||||
|
||||
typedef const char* CStr;
|
||||
typedef const char* const CCStr;
|
||||
|
||||
|
||||
namespace error {
|
||||
|
||||
/** the message shown to the user per default
|
||||
|
|
@ -48,37 +53,46 @@ namespace lumiera {
|
|||
+ typeid(*exception_obj).name() + ")";
|
||||
}
|
||||
|
||||
inline const char*
|
||||
default_or_given (const char* id)
|
||||
inline CStr
|
||||
default_or_given (CCStr id)
|
||||
{
|
||||
return id? id : LUMIERA_ERROR_STATE;
|
||||
}
|
||||
|
||||
CStr
|
||||
detailInfo ()
|
||||
{
|
||||
CCStr detailinfo = lumiera_error_extra();
|
||||
return isnil (detailinfo)? "Lumiera errorstate detected"
|
||||
: detailinfo;
|
||||
}
|
||||
|
||||
|
||||
/* constants to be used as error IDs */
|
||||
LUMIERA_ERROR_DEFINE (LOGIC , "internal logic broken");
|
||||
LUMIERA_ERROR_DEFINE (FATAL , "floundered");
|
||||
LUMIERA_ERROR_DEFINE (CONFIG , "misconfiguration");
|
||||
LUMIERA_ERROR_DEFINE (STATE , "unforeseen state");
|
||||
LUMIERA_ERROR_DEFINE (INVALID , "invalid input or parameters");
|
||||
LUMIERA_ERROR_DEFINE (EXTERNAL , "failure in external service");
|
||||
LUMIERA_ERROR_DEFINE (LOGIC , "internal logic broken");
|
||||
LUMIERA_ERROR_DEFINE (FATAL , "floundered");
|
||||
LUMIERA_ERROR_DEFINE (CONFIG , "misconfiguration");
|
||||
LUMIERA_ERROR_DEFINE (STATE , "unforeseen state");
|
||||
LUMIERA_ERROR_DEFINE (FLAG , "non-cleared lumiera errorstate");
|
||||
LUMIERA_ERROR_DEFINE (INVALID , "invalid input or parameters");
|
||||
LUMIERA_ERROR_DEFINE (EXTERNAL , "failure in external service");
|
||||
LUMIERA_ERROR_DEFINE (ASSERTION, "assertion failure");
|
||||
|
||||
|
||||
/* some further generic error situations */
|
||||
LUMIERA_ERROR_DEFINE (WRONG_TYPE, "runtime type mismatch");
|
||||
LUMIERA_ERROR_DEFINE (WRONG_TYPE, "runtime type mismatch");
|
||||
LUMIERA_ERROR_DEFINE (ITER_EXHAUST, "end of sequence reached");
|
||||
LUMIERA_ERROR_DEFINE (BOTTOM_VALUE, "invalid or NIL value");
|
||||
LUMIERA_ERROR_DEFINE (BOTTOM_VALUE, "invalid or NIL value");
|
||||
|
||||
|
||||
} // namespace error
|
||||
|
||||
LUMIERA_ERROR_DEFINE (EXCEPTION, "generic Lumiera exception");
|
||||
LUMIERA_ERROR_DEFINE (EXCEPTION, "generic Lumiera exception");
|
||||
|
||||
|
||||
|
||||
|
||||
/** @note we set the C-style errorstate as a side effect */
|
||||
Error::Error (string description, const char* id) throw()
|
||||
Error::Error (string description, CCStr id) throw()
|
||||
: std::exception (),
|
||||
id_ (error::default_or_given (id)),
|
||||
msg_ (error::default_usermsg (this)),
|
||||
|
|
@ -90,7 +104,7 @@ namespace lumiera {
|
|||
|
||||
|
||||
Error::Error (std::exception const& cause,
|
||||
string description, const char* id) throw()
|
||||
string description, CCStr id) throw()
|
||||
: std::exception (),
|
||||
id_ (error::default_or_given (id)),
|
||||
msg_ (error::default_usermsg (this)),
|
||||
|
|
@ -117,7 +131,7 @@ namespace lumiera {
|
|||
* If a root cause can be obtained, this will be included in the
|
||||
* generated output as well.
|
||||
*/
|
||||
const char*
|
||||
CStr
|
||||
Error::what() const throw()
|
||||
{
|
||||
if (isnil (this->what_))
|
||||
|
|
@ -160,13 +174,13 @@ namespace lumiera {
|
|||
|
||||
void lumiera_unexpectedException () throw()
|
||||
{
|
||||
const char* is_halted
|
||||
CCStr is_halted
|
||||
= "### Lumiera halted due to an unexpected Error ###";
|
||||
|
||||
std::cerr << "\n" << is_halted << "\n\n";
|
||||
ERROR (NOBUG_ON, "%s", is_halted);
|
||||
|
||||
if (const char * errorstate = lumiera_error ())
|
||||
if (CCStr errorstate = lumiera_error ())
|
||||
ERROR (NOBUG_ON, "last registered error was....\n%s", errorstate);
|
||||
|
||||
std::terminate();
|
||||
|
|
@ -176,20 +190,20 @@ namespace lumiera {
|
|||
{
|
||||
throw Fatal (location, LUMIERA_ERROR_ASSERTION)
|
||||
.setUsermsg("Program terminated because of violating "
|
||||
"an internal consistency check.");
|
||||
"an internal consistency check.");
|
||||
}
|
||||
|
||||
|
||||
void install_unexpectedException_handler ()
|
||||
{
|
||||
std::set_unexpected (lumiera_unexpectedException);
|
||||
std::set_unexpected (lumiera_unexpectedException);
|
||||
}
|
||||
|
||||
namespace {
|
||||
LifecycleHook schedule_ (ON_BASIC_INIT, &install_unexpectedException_handler);
|
||||
LifecycleHook schedule_ (ON_BASIC_INIT, &install_unexpectedException_handler);
|
||||
}
|
||||
|
||||
|
||||
} // namespace error
|
||||
|
||||
|
||||
} // namespace error
|
||||
|
||||
} // namespace lumiera
|
||||
|
|
|
|||
|
|
@ -205,7 +205,9 @@ out: intermediate handler caught: LUMIERA_ERROR_EXTERNAL:failure in external ser
|
|||
out: caught lumiera::Error: LUMIERA_ERROR_STATE:unforeseen state -- caused by: LUMIERA_ERROR_EXTERNAL:failure in external service \(test-7\).
|
||||
out: intermediate handler caught: LUMIERA_ERROR_EXTERNAL:failure in external service \(test-8\).....will rethrow as error::State
|
||||
out: 2nd intermediate handler caught: LUMIERA_ERROR_STATE:unforeseen state -- caused by: LUMIERA_ERROR_EXTERNAL:failure in external service \(test-8\).....will rethrow as error::Config
|
||||
out: caught lumiera::Error: LUMIERA_ERROR_CONFIG:misconfiguration -- caused by: LUMIERA_ERROR_EXTERNAL:failure in external service \(test-8\).
|
||||
out: caught lumiera::Error: LUMIERA_ERROR_CONFIG:misconfiguration -- caused by: LUMIERA_ERROR_EXTERNAL:failure in external service \(test-8\)\.
|
||||
out: caught lumiera::Error: LUMIERA_ERROR_LIFE_AND_UNIVERSE:and everything\? \(what is the answer\?\)\.
|
||||
out: caught error::Logic: LUMIERA_ERROR_LOGIC:internal logic broken \(the big bang\). -- caused by: LUMIERA_ERROR_LIFE_AND_UNIVERSE:and everything\? \(what is the answer\?\)\.
|
||||
END
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -83,6 +83,7 @@ namespace lumiera {
|
|||
catcher (&test::doubleNestedTh,"test-8");
|
||||
|
||||
checkErrorIntegration();
|
||||
checkErrorFlagPropagation();
|
||||
checkRootCauseChaining();
|
||||
}
|
||||
|
||||
|
|
@ -153,6 +154,27 @@ namespace lumiera {
|
|||
ASSERT (!lumiera_error ());
|
||||
}
|
||||
|
||||
|
||||
void detectErrorflag (string) { throwOnError(); }
|
||||
void detectErrorflagChained (string msg) { maybeThrow<error::Logic>(msg); }
|
||||
|
||||
|
||||
/** @test verify throwing of Exceptions
|
||||
* based on a non-cleared C error flag
|
||||
*/
|
||||
void checkErrorFlagPropagation()
|
||||
{
|
||||
lumiera_error_set(LUMIERA_ERROR_LIFE_AND_UNIVERSE, "what is the answer?");
|
||||
ASSERT (lumiera_error_peek());
|
||||
|
||||
catcher (&test::detectErrorflag, "");
|
||||
ASSERT (LUMIERA_ERROR_LIFE_AND_UNIVERSE == lumiera_error_peek());
|
||||
|
||||
catcher (&test::detectErrorflagChained, "the big bang");
|
||||
ASSERT (LUMIERA_ERROR_LIFE_AND_UNIVERSE == lumiera_error());
|
||||
}
|
||||
|
||||
|
||||
/** @test the chaining of lumiera::Exception objects
|
||||
* and the retrieval of the original root cause.
|
||||
*/
|
||||
|
|
|
|||
Loading…
Reference in a new issue