#pragma once #include "ref.hh" #include #include #include #include #include #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::set; using std::vector; typedef enum { lvlError = 0, lvlWarn, lvlInfo, lvlTalkative, lvlChatty, lvlDebug, lvlVomit } Verbosity; struct ErrPos { int line; int column; string file; template ErrPos& operator=(const P &pos) { line = pos.line; column = pos.column; file = pos.file; return *this; } template ErrPos(const P &p) { *this = p; } }; struct NixCode { ErrPos errPos; std::optional prevLineOfCode; string errLineOfCode; std::optional nextLineOfCode; }; // ------------------------------------------------- // ErrorInfo. struct ErrorInfo { Verbosity level; string name; string description; std::optional hint; std::optional nixCode; static std::optional 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; public: unsigned int status = 1; // exit status template BaseError(unsigned int status, const Args & ... args) : err(hintfmt(args...)) , status(status) { } template BaseError(const Args & ... args) : err { .level = lvlError, .hint = hintfmt(args...) } { } BaseError(ErrorInfo e) : err(e) { } #ifdef EXCEPTION_NEEDS_THROW_SPEC ~BaseError() throw () { }; const char * what() const throw () { return err.description.c_str(); } #else const char * what() const noexcept { return err.description.c_str(); } #endif const string & msg() const { return err.description; } const string & prefix() const { return prefix_; } BaseError & addPrefix(const FormatOrString & fs); const ErrorInfo & info() const { return err; } }; #define MakeError(newClass, superClass) \ class newClass : public superClass \ { \ public: \ using superClass::superClass; \ } MakeError(Error, BaseError); class SysError : public Error { public: int errNo; template SysError(const Args & ... args) : Error(args...) // TODO addErrNo for hintfmt // : Error(addErrno(hintfmt(args...))) { } private: std::string addErrno(const std::string & s); }; typedef list Strings; typedef set StringSet; typedef std::map StringMap; /* Paths are just strings. */ typedef string Path; typedef list Paths; typedef set PathSet; }