add ErrorInfo to BaseError

This commit is contained in:
Ben Burdette 2020-04-21 13:25:41 -06:00
parent 15e9564fd1
commit d3052197fe
6 changed files with 192 additions and 186 deletions

View file

@ -1,4 +1,4 @@
#include "error.hh" #include "types.hh"
#include <iostream> #include <iostream>
#include <optional> #include <optional>

View file

@ -1,122 +0,0 @@
#ifndef error_hh
#define error_hh
#include "ansicolor.hh"
#include <string>
#include <optional>
#include <iostream>
#include "types.hh"
namespace nix
{
typedef enum {
lvlError = 0,
lvlWarn,
lvlInfo,
lvlTalkative,
lvlChatty,
lvlDebug,
lvlVomit
} Verbosity;
struct ErrPos
{
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)
{
*this = p;
}
};
struct NixCode
{
ErrPos errPos;
std::optional<string> prevLineOfCode;
string errLineOfCode;
std::optional<string> nextLineOfCode;
};
// ----------------------------------------------------------------
// format function for hints. same as fmt, except templated values
// are always in yellow.
template <class T>
struct yellowify
{
yellowify(T &s) : value(s) {}
T &value;
};
template <class T>
std::ostream& operator<<(std::ostream &out, const yellowify<T> &y)
{
return out << ANSI_YELLOW << y.value << ANSI_NORMAL;
}
class hintformat
{
public:
hintformat(string format) :fmt(format)
{
fmt.exceptions(boost::io::all_error_bits ^ boost::io::too_many_args_bit);
}
template<class T>
hintformat& operator%(const T &value)
{
fmt % yellowify(value);
return *this;
}
std::string str() const
{
return fmt.str();
}
template <typename U>
friend class AddHint;
private:
format fmt;
};
std::ostream& operator<<(std::ostream &os, const hintformat &hf);
template<typename... Args>
inline hintformat hintfmt(const std::string & fs, const Args & ... args)
{
hintformat f(fs);
formatHelper(f, args...);
return f;
}
// -------------------------------------------------
// ErrorInfo.
struct ErrorInfo
{
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);
}
#endif

127
src/libutil/fmt.hh Normal file
View file

@ -0,0 +1,127 @@
#pragma once
#include <boost/format.hpp>
#include <string>
#include "ansicolor.hh"
namespace nix {
/* Inherit some names from other namespaces for convenience. */
using std::string;
using boost::format;
/* A variadic template that does nothing. Useful to call a function
for all variadic arguments but ignoring the result. */
struct nop { template<typename... T> nop(T...) {} };
struct FormatOrString
{
string s;
FormatOrString(const string & s) : s(s) { };
template<class F>
FormatOrString(const F & f) : s(f.str()) { };
FormatOrString(const char * s) : s(s) { };
};
/* A helper for formatting strings. fmt(format, a_0, ..., a_n) is
equivalent to boost::format(format) % a_0 % ... %
... a_n. However, fmt(s) is equivalent to s (so no %-expansion
takes place). */
template<class F>
inline void formatHelper(F & f)
{
}
template<class F, typename T, typename... Args>
inline void formatHelper(F & f, const T & x, const Args & ... args)
{
formatHelper(f % x, args...);
}
inline std::string fmt(const std::string & s)
{
return s;
}
inline std::string fmt(const char * s)
{
return s;
}
inline std::string fmt(const FormatOrString & fs)
{
return fs.s;
}
template<typename... Args>
inline std::string fmt(const std::string & fs, const Args & ... args)
{
boost::format f(fs);
f.exceptions(boost::io::all_error_bits ^ boost::io::too_many_args_bit);
formatHelper(f, args...);
return f.str();
}
// -----------------------------------------------------------------------------
// format function for hints in errors. same as fmt, except templated values
// are always in yellow.
template <class T>
struct yellowify
{
yellowify(T &s) : value(s) {}
T &value;
};
template <class T>
std::ostream& operator<<(std::ostream &out, const yellowify<T> &y)
{
return out << ANSI_YELLOW << y.value << ANSI_NORMAL;
}
class hintformat
{
public:
hintformat(const string &format) :fmt(format)
{
fmt.exceptions(boost::io::all_error_bits ^ boost::io::too_many_args_bit);
}
template<class T>
hintformat& operator%(const T &value)
{
fmt % yellowify(value);
return *this;
}
hintformat(const hintformat &hf)
: fmt(hf.fmt)
{}
std::string str() const
{
return fmt.str();
}
template <typename U>
friend class AddHint;
private:
format fmt;
};
std::ostream& operator<<(std::ostream &os, const hintformat &hf);
template<typename... Args>
inline hintformat hintfmt(const std::string & fs, const Args & ... args)
{
hintformat f(fs);
formatHelper(f, args...);
return f;
}
}

View file

@ -1,7 +1,6 @@
#pragma once #pragma once
#include "types.hh" #include "types.hh"
#include "error.hh"
namespace nix { namespace nix {

View file

@ -3,13 +3,13 @@
#include "ref.hh" #include "ref.hh"
#include <string>
#include <list> #include <list>
#include <set> #include <set>
#include <memory> #include <memory>
#include <map> #include <map>
#include <optional>
#include <boost/format.hpp> #include "fmt.hh"
/* Before 4.7, gcc's std::exception uses empty throw() specifiers for /* 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 * its (virtual) destructor and what() in c++11 mode, in violation of spec
@ -20,73 +20,66 @@
#endif #endif
#endif #endif
namespace nix { namespace nix {
/* Inherit some names from other namespaces for convenience. */
using std::string;
using std::list; using std::list;
using std::set; using std::set;
using std::vector; using std::vector;
using boost::format;
typedef enum {
lvlError = 0,
lvlWarn,
lvlInfo,
lvlTalkative,
lvlChatty,
lvlDebug,
lvlVomit
} Verbosity;
/* A variadic template that does nothing. Useful to call a function struct ErrPos
for all variadic arguments but ignoring the result. */
struct nop { template<typename... T> nop(T...) {} };
struct FormatOrString
{ {
string s; int line;
FormatOrString(const string & s) : s(s) { }; int column;
template<class F> string file;
FormatOrString(const F & f) : s(f.str()) { };
FormatOrString(const char * s) : s(s) { }; 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)
{
*this = p;
}
}; };
struct NixCode
/* A helper for formatting strings. fmt(format, a_0, ..., a_n) is
equivalent to boost::format(format) % a_0 % ... %
... a_n. However, fmt(s) is equivalent to s (so no %-expansion
takes place). */
template<class F>
inline void formatHelper(F & f)
{ {
} ErrPos errPos;
std::optional<string> prevLineOfCode;
string errLineOfCode;
std::optional<string> nextLineOfCode;
};
template<class F, typename T, typename... Args> // -------------------------------------------------
inline void formatHelper(F & f, const T & x, const Args & ... args) // ErrorInfo.
struct ErrorInfo
{ {
formatHelper(f % x, args...); Verbosity level;
} string name;
string description;
std::optional<hintformat> hint;
std::optional<NixCode> nixCode;
inline std::string fmt(const std::string & s) static std::optional<string> programName;
{ };
return s;
}
inline std::string fmt(const char * s)
{
return s;
}
inline std::string fmt(const FormatOrString & fs)
{
return fs.s;
}
template<typename... Args>
inline std::string fmt(const std::string & fs, const Args & ... args)
{
boost::format f(fs);
f.exceptions(boost::io::all_error_bits ^ boost::io::too_many_args_bit);
formatHelper(f, args...);
return f.str();
}
std::ostream& operator<<(std::ostream &out, const ErrorInfo &einfo);
/* BaseError should generally not be caught, as it has Interrupted as /* BaseError should generally not be caught, as it has Interrupted as
a subclass. Catch Error instead. */ a subclass. Catch Error instead. */
@ -94,33 +87,42 @@ class BaseError : public std::exception
{ {
protected: protected:
string prefix_; // used for location traces etc. string prefix_; // used for location traces etc.
string err; ErrorInfo err;
public: public:
unsigned int status = 1; // exit status unsigned int status = 1; // exit status
template<typename... Args> template<typename... Args>
BaseError(unsigned int status, const Args & ... args) BaseError(unsigned int status, const Args & ... args)
: err(fmt(args...)) : err(hintfmt(args...))
, status(status) , status(status)
{ {
} }
template<typename... Args> template<typename... Args>
BaseError(const Args & ... args) BaseError(const Args & ... args)
: err(fmt(args...)) : err { .level = lvlError,
.hint = hintfmt(args...)
}
{
}
BaseError(ErrorInfo e)
: err(e)
{ {
} }
#ifdef EXCEPTION_NEEDS_THROW_SPEC #ifdef EXCEPTION_NEEDS_THROW_SPEC
~BaseError() throw () { }; ~BaseError() throw () { };
const char * what() const throw () { return err.c_str(); } const char * what() const throw () { return err.description.c_str(); }
#else #else
const char * what() const noexcept { return err.c_str(); } const char * what() const noexcept { return err.description.c_str(); }
#endif #endif
const string & msg() const { return err; } const string & msg() const { return err.description; }
const string & prefix() const { return prefix_; } const string & prefix() const { return prefix_; }
BaseError & addPrefix(const FormatOrString & fs); BaseError & addPrefix(const FormatOrString & fs);
const ErrorInfo & info() const { return err; }
}; };
#define MakeError(newClass, superClass) \ #define MakeError(newClass, superClass) \
@ -139,7 +141,8 @@ public:
template<typename... Args> template<typename... Args>
SysError(const Args & ... args) SysError(const Args & ... args)
: Error(addErrno(fmt(args...))) : Error(args...) // TODO addErrNo for hintfmt
// : Error(addErrno(hintfmt(args...)))
{ } { }
private: private:

View file

@ -3,7 +3,6 @@
#include "types.hh" #include "types.hh"
#include "logging.hh" #include "logging.hh"
#include "ansicolor.hh" #include "ansicolor.hh"
#include "error.hh"
#include <sys/types.h> #include <sys/types.h>
#include <sys/stat.h> #include <sys/stat.h>