lix/src/libutil/error.hh

173 lines
3.6 KiB
C++
Raw Normal View History

2020-04-26 20:47:41 +00:00
#pragma once
#include "ref.hh"
#include <list>
#include <memory>
#include <map>
#include <optional>
#include "fmt.hh"
/* Before 4.7, gcc's std::exception uses empty throw() specifiers for
* its (virtual) destructor and what() in c++11 mode, in violation of spec
*/
#ifdef __GNUC__
#if __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 7)
#define EXCEPTION_NEEDS_THROW_SPEC
#endif
#endif
namespace nix {
using std::list;
using std::vector;
2020-04-29 03:06:08 +00:00
typedef enum {
2020-04-26 20:47:41 +00:00
lvlError = 0,
lvlWarn,
lvlInfo,
lvlTalkative,
lvlChatty,
lvlDebug,
lvlVomit
} Verbosity;
2020-04-29 03:06:08 +00:00
struct ErrPos {
2020-04-26 20:47:41 +00:00
int line;
int column;
string file;
template <class P>
ErrPos& operator=(const P &pos)
{
line = pos.line;
column = pos.column;
file = pos.file;
return *this;
}
template <class P>
ErrPos(const P &p)
{
2020-04-27 21:15:08 +00:00
*this = p;
2020-04-26 20:47:41 +00:00
}
};
2020-04-29 03:06:08 +00:00
struct NixCode {
2020-04-26 20:47:41 +00:00
ErrPos errPos;
std::optional<string> prevLineOfCode;
string errLineOfCode;
std::optional<string> nextLineOfCode;
};
// -------------------------------------------------
// ErrorInfo.
2020-04-29 03:06:08 +00:00
struct ErrorInfo {
2020-04-26 20:47:41 +00:00
Verbosity level;
string name;
string description;
std::optional<hintformat> hint;
std::optional<NixCode> nixCode;
static std::optional<string> programName;
};
std::ostream& operator<<(std::ostream &out, const ErrorInfo &einfo);
/* BaseError should generally not be caught, as it has Interrupted as
a subclass. Catch Error instead. */
class BaseError : public std::exception
{
protected:
string prefix_; // used for location traces etc.
ErrorInfo err;
2020-04-30 00:57:05 +00:00
2020-04-29 03:06:08 +00:00
std::optional<string> what_;
const string& calcWhat()
2020-04-26 20:47:41 +00:00
{
2020-04-29 03:06:08 +00:00
if (what_.has_value())
return *what_;
else {
err.name = sname();
std::ostringstream oss;
oss << err;
what_ = oss.str();
return *what_;
}
2020-04-26 20:47:41 +00:00
}
public:
unsigned int status = 1; // exit status
template<typename... Args>
BaseError(unsigned int status, const Args & ... args)
: err { .level = lvlError,
.hint = hintfmt(args...)
}
, status(status)
2020-04-30 00:57:05 +00:00
{ }
2020-04-26 20:47:41 +00:00
template<typename... Args>
BaseError(const Args & ... args)
2020-04-27 21:15:08 +00:00
: err { .level = lvlError,
2020-04-26 20:47:41 +00:00
.hint = hintfmt(args...)
}
2020-04-30 00:57:05 +00:00
{ }
2020-04-26 20:47:41 +00:00
BaseError(hintformat hint)
: err { .level = lvlError,
.hint = hint
}
{ }
2020-04-26 20:47:41 +00:00
BaseError(ErrorInfo e)
: err(e)
2020-04-30 00:57:05 +00:00
{ }
2020-04-29 03:06:08 +00:00
virtual const char* sname() const { return "BaseError"; }
2020-04-26 20:47:41 +00:00
#ifdef EXCEPTION_NEEDS_THROW_SPEC
~BaseError() throw () { };
2020-04-29 03:06:08 +00:00
const char * what() throw () { return calcWhat().c_str(); }
2020-04-26 20:47:41 +00:00
#else
2020-04-29 03:06:08 +00:00
const char * what() noexcept { return calcWhat().c_str(); }
2020-04-26 20:47:41 +00:00
#endif
2020-04-29 03:06:08 +00:00
const string & msg() { return calcWhat(); }
2020-04-26 20:47:41 +00:00
const string & prefix() const { return prefix_; }
BaseError & addPrefix(const FormatOrString & fs);
2020-04-29 03:06:08 +00:00
const ErrorInfo & info() { calcWhat(); return err; }
2020-04-26 20:47:41 +00:00
};
#define MakeError(newClass, superClass) \
class newClass : public superClass \
{ \
public: \
using superClass::superClass; \
2020-04-29 03:06:08 +00:00
virtual const char* sname() const override { return #newClass; } \
2020-04-26 20:47:41 +00:00
}
MakeError(Error, BaseError);
class SysError : public Error
{
public:
int errNo;
template<typename... Args>
SysError(const Args & ... args)
: Error(args...) // TODO addErrNo for hintfmt
2020-04-27 21:15:08 +00:00
// : Error(addErrno(hintfmt(args...)))
2020-04-26 20:47:41 +00:00
{ }
private:
std::string addErrno(const std::string & s);
};
}