diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc index 2f1a41a64..7b80d76b9 100644 --- a/src/libexpr/primops.cc +++ b/src/libexpr/primops.cc @@ -239,13 +239,13 @@ void prim_exec(EvalState & state, const Pos & pos, Value * * args, Value & v) try { parsed = state.parseExprFromString(output, pos.file); } 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; } try { state.eval(parsed, v); } 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; } } diff --git a/src/libutil/error.cc b/src/libutil/error.cc index 07d9791ad..5f5b54251 100644 --- a/src/libutil/error.cc +++ b/src/libutil/error.cc @@ -18,6 +18,14 @@ BaseError & BaseError::addPrefix(const FormatOrString & fs) 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. // This stringifies the error and caches it for use by what(), or similarly by msg(). const string& BaseError::calcWhat() const @@ -58,7 +66,7 @@ string showErrPos(const ErrPos &errPos) void getCodeLines(NixCode &nixCode) { - if (nixCode.errPos.line <= 0) + if (nixCode.errPos.line <= 0) return; if (nixCode.errPos.origin == foFile) { @@ -72,13 +80,13 @@ void getCodeLines(NixCode &nixCode) int count = 0; string line; int pl = nixCode.errPos.line - 1; - do + do { line = readLine(fd.get()); ++count; - if (count < pl) + if (count < pl) { - ; + ; } else if (count == pl) { nixCode.prevLineOfCode = line; @@ -89,7 +97,7 @@ void getCodeLines(NixCode &nixCode) break; } } while (true); - } + } } catch (EndOfFile &eof) { ; @@ -97,20 +105,20 @@ void getCodeLines(NixCode &nixCode) catch (std::exception &e) { printError("error reading nix file: %s\n%s", nixCode.errPos.file, e.what()); } - } else { + } else { std::istringstream iss(nixCode.errPos.file); // count the newlines. int count = 0; string line; int pl = nixCode.errPos.line - 1; - do + do { std::getline(iss, line); ++count; - if (count < pl) + if (count < pl) { - ; + ; } else if (count == pl) { nixCode.prevLineOfCode = line; @@ -134,18 +142,18 @@ void printCodeLines(std::ostream &out, const string &prefix, const NixCode &nixC if (nixCode.prevLineOfCode.has_value()) { out << std::endl << fmt("%1% %|2$5d|| %3%", - prefix, - (nixCode.errPos.line - 1), - *nixCode.prevLineOfCode); + prefix, + (nixCode.errPos.line - 1), + *nixCode.prevLineOfCode); } if (nixCode.errLineOfCode.has_value()) { // line of code containing the error. out << std::endl << fmt("%1% %|2$5d|| %3%", - prefix, - (nixCode.errPos.line), - *nixCode.errLineOfCode); + prefix, + (nixCode.errPos.line), + *nixCode.errLineOfCode); // error arrows for the column range. if (nixCode.errPos.column > 0) { int start = nixCode.errPos.column; @@ -158,9 +166,9 @@ void printCodeLines(std::ostream &out, const string &prefix, const NixCode &nixC out << std::endl << fmt("%1% |%2%" ANSI_RED "%3%" ANSI_NORMAL, - prefix, - spaces, - arrows); + prefix, + spaces, + arrows); } } @@ -168,9 +176,9 @@ void printCodeLines(std::ostream &out, const string &prefix, const NixCode &nixC if (nixCode.nextLineOfCode.has_value()) { out << std::endl << fmt("%1% %|2$5d|| %3%", - prefix, - (nixCode.errPos.line + 1), - *nixCode.nextLineOfCode); + prefix, + (nixCode.errPos.line + 1), + *nixCode.nextLineOfCode); } } @@ -287,7 +295,7 @@ std::ostream& operator<<(std::ostream &out, const ErrorInfo &einfo) if (einfo.nixCode.has_value()) { NixCode nixcode = *einfo.nixCode; getCodeLines(nixcode); - + // lines of code. if (nixcode.errLineOfCode.has_value()) { if (nl) diff --git a/src/libutil/error.hh b/src/libutil/error.hh index 8494b9412..10bdeea1d 100644 --- a/src/libutil/error.hh +++ b/src/libutil/error.hh @@ -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 -happening in the logger rather than at the call site. + ErrorInfo provides a standard payload of error information, with conversion to string + happening in the logger rather than at the call site. -BaseError is the ancestor of nix specific exceptions (and Interrupted), and contains -an ErrorInfo. + BaseError is the ancestor of nix specific exceptions (and Interrupted), and contains + an ErrorInfo. -ErrorInfo structs are sent to the logger as part of an exception, or directly with the -logError or logWarning macros. + ErrorInfo structs are sent to the logger as part of an exception, or directly with the + logError or logWarning macros. -See the error-demo.cc program for usage examples. + See the error-demo.cc program for usage examples. -*/ + */ typedef enum { lvlError = 0, @@ -50,7 +50,7 @@ typedef enum { lvlVomit } Verbosity; -typedef enum { +typedef enum { foFile, foStdin, foString @@ -93,12 +93,18 @@ struct NixCode { std::optional nextLineOfCode; }; +struct Trace { + ErrPos pos; + hintformat hint; +}; + struct ErrorInfo { Verbosity level; string name; string description; std::optional hint; std::optional nixCode; + std::list traces; static std::optional programName; }; @@ -121,23 +127,23 @@ public: template BaseError(unsigned int status, const Args & ... args) - : err { .level = lvlError, - .hint = hintfmt(args...) - } + : err {.level = lvlError, + .hint = hintfmt(args...) + } , status(status) { } template BaseError(const std::string & fs, const Args & ... args) - : err { .level = lvlError, - .hint = hintfmt(fs, args...) - } + : err {.level = lvlError, + .hint = hintfmt(fs, args...) + } { } BaseError(hintformat hint) - : err { .level = lvlError, - .hint = hint - } + : err {.level = lvlError, + .hint = hint + } { } BaseError(ErrorInfo && e) @@ -160,6 +166,7 @@ public: const string & msg() const { return calcWhat(); } const string & prefix() const { return prefix_; } BaseError & addPrefix(const FormatOrString & fs); + BaseError & addTrace(ErrPos e, hintformat hint); const ErrorInfo & info() { calcWhat(); return err; } }; @@ -181,7 +188,7 @@ public: template SysError(const Args & ... args) - :Error("") + : Error("") { errNo = errno; auto hf = hintfmt(args...);