This commit is contained in:
Ben Burdette 2020-06-18 15:25:26 -06:00
parent e6f93b94fc
commit 4d1a4f0217
3 changed files with 59 additions and 44 deletions

View file

@ -239,13 +239,13 @@ void prim_exec(EvalState & state, const Pos & pos, Value * * args, Value & v)
try { try {
parsed = state.parseExprFromString(output, pos.file); parsed = state.parseExprFromString(output, pos.file);
} catch (Error & e) { } catch (Error & e) {
e.addPrefix(fmt("While parsing the output from '%1%', at %2%\n", program, pos)); e.addTrace(pos, hintfmt("While parsing the output from '%1%'", program));
throw; throw;
} }
try { try {
state.eval(parsed, v); state.eval(parsed, v);
} catch (Error & e) { } catch (Error & e) {
e.addPrefix(fmt("While evaluating the output from '%1%', at %2%\n", program, pos)); e.addTrace(pos, hintfmt("While evaluating the output from '%1%'", program));
throw; throw;
} }
} }

View file

@ -18,6 +18,14 @@ BaseError & BaseError::addPrefix(const FormatOrString & fs)
return *this; return *this;
} }
// addPrefix is used for show-trace. Strings added with addPrefix
// will print ahead of the error itself.
BaseError & BaseError::addTrace(hintformat hint, ErrPos e)
{
err.traces.push_front(Trace { .pos = e, .hint = hint});
return *this;
}
// c++ std::exception descendants must have a 'const char* what()' function. // c++ std::exception descendants must have a 'const char* what()' function.
// This stringifies the error and caches it for use by what(), or similarly by msg(). // This stringifies the error and caches it for use by what(), or similarly by msg().
const string& BaseError::calcWhat() const const string& BaseError::calcWhat() const
@ -58,7 +66,7 @@ string showErrPos(const ErrPos &errPos)
void getCodeLines(NixCode &nixCode) void getCodeLines(NixCode &nixCode)
{ {
if (nixCode.errPos.line <= 0) if (nixCode.errPos.line <= 0)
return; return;
if (nixCode.errPos.origin == foFile) { if (nixCode.errPos.origin == foFile) {
@ -72,13 +80,13 @@ void getCodeLines(NixCode &nixCode)
int count = 0; int count = 0;
string line; string line;
int pl = nixCode.errPos.line - 1; int pl = nixCode.errPos.line - 1;
do do
{ {
line = readLine(fd.get()); line = readLine(fd.get());
++count; ++count;
if (count < pl) if (count < pl)
{ {
; ;
} }
else if (count == pl) { else if (count == pl) {
nixCode.prevLineOfCode = line; nixCode.prevLineOfCode = line;
@ -89,7 +97,7 @@ void getCodeLines(NixCode &nixCode)
break; break;
} }
} while (true); } while (true);
} }
} }
catch (EndOfFile &eof) { catch (EndOfFile &eof) {
; ;
@ -97,20 +105,20 @@ void getCodeLines(NixCode &nixCode)
catch (std::exception &e) { catch (std::exception &e) {
printError("error reading nix file: %s\n%s", nixCode.errPos.file, e.what()); printError("error reading nix file: %s\n%s", nixCode.errPos.file, e.what());
} }
} else { } else {
std::istringstream iss(nixCode.errPos.file); std::istringstream iss(nixCode.errPos.file);
// count the newlines. // count the newlines.
int count = 0; int count = 0;
string line; string line;
int pl = nixCode.errPos.line - 1; int pl = nixCode.errPos.line - 1;
do do
{ {
std::getline(iss, line); std::getline(iss, line);
++count; ++count;
if (count < pl) if (count < pl)
{ {
; ;
} }
else if (count == pl) { else if (count == pl) {
nixCode.prevLineOfCode = line; nixCode.prevLineOfCode = line;
@ -134,18 +142,18 @@ void printCodeLines(std::ostream &out, const string &prefix, const NixCode &nixC
if (nixCode.prevLineOfCode.has_value()) { if (nixCode.prevLineOfCode.has_value()) {
out << std::endl out << std::endl
<< fmt("%1% %|2$5d|| %3%", << fmt("%1% %|2$5d|| %3%",
prefix, prefix,
(nixCode.errPos.line - 1), (nixCode.errPos.line - 1),
*nixCode.prevLineOfCode); *nixCode.prevLineOfCode);
} }
if (nixCode.errLineOfCode.has_value()) { if (nixCode.errLineOfCode.has_value()) {
// line of code containing the error. // line of code containing the error.
out << std::endl out << std::endl
<< fmt("%1% %|2$5d|| %3%", << fmt("%1% %|2$5d|| %3%",
prefix, prefix,
(nixCode.errPos.line), (nixCode.errPos.line),
*nixCode.errLineOfCode); *nixCode.errLineOfCode);
// error arrows for the column range. // error arrows for the column range.
if (nixCode.errPos.column > 0) { if (nixCode.errPos.column > 0) {
int start = nixCode.errPos.column; int start = nixCode.errPos.column;
@ -158,9 +166,9 @@ void printCodeLines(std::ostream &out, const string &prefix, const NixCode &nixC
out << std::endl out << std::endl
<< fmt("%1% |%2%" ANSI_RED "%3%" ANSI_NORMAL, << fmt("%1% |%2%" ANSI_RED "%3%" ANSI_NORMAL,
prefix, prefix,
spaces, spaces,
arrows); arrows);
} }
} }
@ -168,9 +176,9 @@ void printCodeLines(std::ostream &out, const string &prefix, const NixCode &nixC
if (nixCode.nextLineOfCode.has_value()) { if (nixCode.nextLineOfCode.has_value()) {
out << std::endl out << std::endl
<< fmt("%1% %|2$5d|| %3%", << fmt("%1% %|2$5d|| %3%",
prefix, prefix,
(nixCode.errPos.line + 1), (nixCode.errPos.line + 1),
*nixCode.nextLineOfCode); *nixCode.nextLineOfCode);
} }
} }
@ -287,7 +295,7 @@ std::ostream& operator<<(std::ostream &out, const ErrorInfo &einfo)
if (einfo.nixCode.has_value()) { if (einfo.nixCode.has_value()) {
NixCode nixcode = *einfo.nixCode; NixCode nixcode = *einfo.nixCode;
getCodeLines(nixcode); getCodeLines(nixcode);
// lines of code. // lines of code.
if (nixcode.errLineOfCode.has_value()) { if (nixcode.errLineOfCode.has_value()) {
if (nl) if (nl)

View file

@ -25,20 +25,20 @@ namespace nix {
/* /*
This file defines two main structs/classes used in nix error handling. This file defines two main structs/classes used in nix error handling.
ErrorInfo provides a standard payload of error information, with conversion to string ErrorInfo provides a standard payload of error information, with conversion to string
happening in the logger rather than at the call site. happening in the logger rather than at the call site.
BaseError is the ancestor of nix specific exceptions (and Interrupted), and contains BaseError is the ancestor of nix specific exceptions (and Interrupted), and contains
an ErrorInfo. an ErrorInfo.
ErrorInfo structs are sent to the logger as part of an exception, or directly with the ErrorInfo structs are sent to the logger as part of an exception, or directly with the
logError or logWarning macros. logError or logWarning macros.
See the error-demo.cc program for usage examples. See the error-demo.cc program for usage examples.
*/ */
typedef enum { typedef enum {
lvlError = 0, lvlError = 0,
@ -50,7 +50,7 @@ typedef enum {
lvlVomit lvlVomit
} Verbosity; } Verbosity;
typedef enum { typedef enum {
foFile, foFile,
foStdin, foStdin,
foString foString
@ -93,12 +93,18 @@ struct NixCode {
std::optional<string> nextLineOfCode; std::optional<string> nextLineOfCode;
}; };
struct Trace {
ErrPos pos;
hintformat hint;
};
struct ErrorInfo { struct ErrorInfo {
Verbosity level; Verbosity level;
string name; string name;
string description; string description;
std::optional<hintformat> hint; std::optional<hintformat> hint;
std::optional<NixCode> nixCode; std::optional<NixCode> nixCode;
std::list<Trace> traces;
static std::optional<string> programName; static std::optional<string> programName;
}; };
@ -121,23 +127,23 @@ public:
template<typename... Args> template<typename... Args>
BaseError(unsigned int status, const Args & ... args) BaseError(unsigned int status, const Args & ... args)
: err { .level = lvlError, : err {.level = lvlError,
.hint = hintfmt(args...) .hint = hintfmt(args...)
} }
, status(status) , status(status)
{ } { }
template<typename... Args> template<typename... Args>
BaseError(const std::string & fs, const Args & ... args) BaseError(const std::string & fs, const Args & ... args)
: err { .level = lvlError, : err {.level = lvlError,
.hint = hintfmt(fs, args...) .hint = hintfmt(fs, args...)
} }
{ } { }
BaseError(hintformat hint) BaseError(hintformat hint)
: err { .level = lvlError, : err {.level = lvlError,
.hint = hint .hint = hint
} }
{ } { }
BaseError(ErrorInfo && e) BaseError(ErrorInfo && e)
@ -160,6 +166,7 @@ public:
const string & msg() const { return calcWhat(); } const string & msg() const { return calcWhat(); }
const string & prefix() const { return prefix_; } const string & prefix() const { return prefix_; }
BaseError & addPrefix(const FormatOrString & fs); BaseError & addPrefix(const FormatOrString & fs);
BaseError & addTrace(ErrPos e, hintformat hint);
const ErrorInfo & info() { calcWhat(); return err; } const ErrorInfo & info() { calcWhat(); return err; }
}; };
@ -181,7 +188,7 @@ public:
template<typename... Args> template<typename... Args>
SysError(const Args & ... args) SysError(const Args & ... args)
:Error("") : Error("")
{ {
errNo = errno; errNo = errno;
auto hf = hintfmt(args...); auto hf = hintfmt(args...);