diff --git a/src/error-demo/error-demo.cc b/src/error-demo/error-demo.cc index 8fb20d38c..a9ff6057c 100644 --- a/src/error-demo/error-demo.cc +++ b/src/error-demo/error-demo.cc @@ -11,77 +11,56 @@ int main() // In each program where errors occur, this has to be set. ErrorInfo::programName = std::optional("error-demo"); - // There are currently four error types: - // - // ProgramError, ProgramWarning, NixLangError, NixLangWarning. - // - // Each error type is created with a specific sequence of builder functions. - // Unlike with a constructor, each parameter is clearly named. - // If the sequence of function calls isn't followed, then there's a type - // error. This should make for a consistent look in the code when errors are - // created. + // Error in a program; no hint and no nix code. + printErrorInfo( + ErrorInfo { .level = elError, + .name = "name", + .description = "error description", + }); - // ProgramError takes name, description, and an optional hint. - printErrorInfo( ProgramError() - .name("name") - .description("error description") - .nohint() - ); + // Warning with name, description, and hint. + // The hintfmt function makes all the substituted text yellow. + printErrorInfo( + ErrorInfo { .level = elWarning, + .name = "name", + .description = "error description", + .hint = std::optional( + hintfmt("there was a %1%", "warning")), + }); - // ProgramWarning takes name, description, and an optional hint. - // The hint is in the form of a hintfmt class, which wraps boost::format(), - // and makes all the substituted text yellow. - printErrorInfo( ProgramWarning() - .name("warning name") - .description("warning description") - // the templated value, 'warning', is automatically colored yellow. - .hint(hintfmt("there was a %1%", "warning")) - ); - /* - // some invalid errors: - - // type error: no hint function. - ProgramError() - .name("name") - .description("error description"); - - // type error: description before name. - ProgramError() - .description("error description") - .name("name") - .nohint(); - - // type error: hint function with regular boost format, not special - hintfmt. ProgramError() .description("error description") .name("name") - .hint(format("there was a %1%") % "warning"); - */ - - // NixLangWarning adds nix file, line number, column range, and the lines of + // Warning with nix file, line number, column, and the lines of // code where a warning occurred. - SymbolTable testTable; - auto problem_symbol = testTable.create("problem"); + auto problem_file = testTable.create("myfile.nix"); - printErrorInfo(NixLangWarning() - .name("warning name") - .description("warning description") - .pos(Pos(problem_symbol, 40, 13)) - .linesOfCode(std::nullopt, - "this is the problem line of code", - std::nullopt) - .hint(hintfmt("this hint has %1% templated %2%!!", "yellow" , "values"))); + printErrorInfo( + ErrorInfo{ + .level = elWarning, + .name = "warning name", + .description = "warning description", + .hint = hintfmt("this hint has %1% templated %2%!!", "yellow", "values"), + .nixCode = NixCode { + .errPos = Pos(problem_file, 40, 13), + .prevLineOfCode = std::nullopt, + .errLineOfCode = "this is the problem line of code", + .nextLineOfCode = std::nullopt + }}); + + // Error with previous and next lines of code. + printErrorInfo( + ErrorInfo{ + .level = elError, + .name = "error name", + .description = "error description", + .hint = hintfmt("this hint has %1% templated %2%!!", "yellow", "values"), + .nixCode = NixCode { + .errPos = Pos(problem_file, 40, 13), + .prevLineOfCode = std::optional("previous line of code"), + .errLineOfCode = "this is the problem line of code", + .nextLineOfCode = std::optional("next line of code"), + }}); - // NixLangError is just the same as NixLangWarning, except for the Error - // flag. - printErrorInfo(NixLangError() - .name("error name") - .description("error description") - .pos(Pos(problem_symbol, 40, 13)) - .linesOfCode(std::optional("previous line of code"), - "this is the problem line of code", - std::optional("next line of code")) - .hint(hintfmt("this hint has %1% templated %2%!!", "yellow", "values"))); return 0; } diff --git a/src/libutil/error.cc b/src/libutil/error.cc index 106ea127e..40354cc87 100644 --- a/src/libutil/error.cc +++ b/src/libutil/error.cc @@ -8,68 +8,60 @@ namespace nix std::optional ErrorInfo::programName = std::nullopt; -string showErrLine(ErrLine &errLine) +string showErrPos(const ErrPos &errPos) { - if (errLine.column > 0) { - return fmt("(%1%:%2%)", errLine.lineNumber, errLine.column); + if (errPos.column > 0) { + return fmt("(%1%:%2%)", errPos.lineNumber, errPos.column); } else { - return fmt("(%1%)", errLine.lineNumber); + return fmt("(%1%)", errPos.lineNumber); }; } -void printCodeLines(string &prefix, NixCode &nixCode) +void printCodeLines(const string &prefix, const NixCode &nixCode) { - - if (nixCode.errLine.has_value()) { - // previous line of code. - if (nixCode.errLine->prevLineOfCode.has_value()) { - std::cout << fmt("%1% %|2$5d|| %3%", - prefix, - (nixCode.errLine->lineNumber - 1), - *nixCode.errLine->prevLineOfCode) - << std::endl; - } - - // line of code containing the error.%2$+5d% + // previous line of code. + if (nixCode.prevLineOfCode.has_value()) { std::cout << fmt("%1% %|2$5d|| %3%", prefix, - (nixCode.errLine->lineNumber), - nixCode.errLine->errLineOfCode) + (nixCode.errPos.lineNumber - 1), + *nixCode.prevLineOfCode) << std::endl; - - // error arrows for the column range. - if (nixCode.errLine->column > 0) { - int start = nixCode.errLine->column; - std::string spaces; - for (int i = 0; i < start; ++i) { - spaces.append(" "); - } - - // for now, length of 1. - std::string arrows("^"); - - std::cout << fmt("%1% |%2%" ANSI_RED "%3%" ANSI_NORMAL, - prefix, - spaces, - arrows) << std::endl; - } - - - - // next line of code. - if (nixCode.errLine->nextLineOfCode.has_value()) { - std::cout << fmt("%1% %|2$5d|| %3%", - prefix, - (nixCode.errLine->lineNumber + 1), - *nixCode.errLine->nextLineOfCode) - << std::endl; - } - } + // line of code containing the error.%2$+5d% + std::cout << fmt("%1% %|2$5d|| %3%", + prefix, + (nixCode.errPos.lineNumber), + nixCode.errLineOfCode) + << std::endl; + + // error arrows for the column range. + if (nixCode.errPos.column > 0) { + int start = nixCode.errPos.column; + std::string spaces; + for (int i = 0; i < start; ++i) { + spaces.append(" "); + } + + std::string arrows("^"); + + std::cout << fmt("%1% |%2%" ANSI_RED "%3%" ANSI_NORMAL, + prefix, + spaces, + arrows) << std::endl; + } + + // next line of code. + if (nixCode.nextLineOfCode.has_value()) { + std::cout << fmt("%1% %|2$5d|| %3%", + prefix, + (nixCode.errPos.lineNumber + 1), + *nixCode.nextLineOfCode) + << std::endl; + } } -void printErrorInfo(ErrorInfo &einfo) +void printErrorInfo(const ErrorInfo &einfo) { int errwidth = 80; string prefix = " "; @@ -102,24 +94,26 @@ void printErrorInfo(ErrorInfo &einfo) dashes.append("-"); // divider. - std::cout << fmt("%1%%2%" ANSI_BLUE " %3% %4% %5% %6%" ANSI_NORMAL - , prefix - , levelString - , "---" - , einfo.name - , dashes - , einfo.programName.value_or("")) + std::cout << fmt("%1%%2%" ANSI_BLUE " %3% %4% %5% %6%" ANSI_NORMAL, + prefix, + levelString, + "---", + einfo.name, + dashes, + einfo.programName.value_or("")) << std::endl; // filename. if (einfo.nixCode.has_value()) { - if (einfo.nixCode->nixFile.has_value()) { - string eline = einfo.nixCode->errLine.has_value() - ? string(" ") + showErrLine(*einfo.nixCode->errLine) + if (einfo.nixCode->errPos.nixFile != "") { + string eline = einfo.nixCode->errLineOfCode != "" + ? string(" ") + showErrPos(einfo.nixCode->errPos) : ""; - std::cout << fmt("%1%in file: " ANSI_BLUE "%2%%3%" ANSI_NORMAL - , prefix, *einfo.nixCode->nixFile, eline) << std::endl; + std::cout << fmt("%1%in file: " ANSI_BLUE "%2%%3%" ANSI_NORMAL, + prefix, + einfo.nixCode->errPos.nixFile, + eline) << std::endl; std::cout << prefix << std::endl; } else { std::cout << fmt("%1%from command line argument", prefix) << std::endl; @@ -132,7 +126,7 @@ void printErrorInfo(ErrorInfo &einfo) std::cout << prefix << std::endl; // lines of code. - if (einfo.nixCode.has_value()) { + if (einfo.nixCode->errLineOfCode != "") { printCodeLines(prefix, *einfo.nixCode); std::cout << prefix << std::endl; } diff --git a/src/libutil/error.hh b/src/libutil/error.hh index 664bfbb5a..8286eaab1 100644 --- a/src/libutil/error.hh +++ b/src/libutil/error.hh @@ -17,172 +17,40 @@ typedef enum { elError } ErrLevel; -class ErrorInfo; - -class ErrLine +class ErrPos { public: int lineNumber; int column; - std::optional prevLineOfCode; - string errLineOfCode; - std::optional nextLineOfCode; + string nixFile; + + template + ErrPos& operator=(const P &pos) + { + lineNumber = pos.line; + column = pos.column; + nixFile = pos.file; + return *this; + } + + template + ErrPos(const P &p) + { + *this = p; + } }; class NixCode { public: - std::optional nixFile; - std::optional errLine; - - ErrLine& ensureErrLine() - { - if (!this->errLine.has_value()) - this->errLine = std::optional(ErrLine()); - return *this->errLine; - } + ErrPos errPos; + std::optional prevLineOfCode; + string errLineOfCode; + std::optional nextLineOfCode; }; -// ------------------------------------------------- -// ErrorInfo. - -// Forward friend class declarations. "builder classes" -template -class AddName; - -template -class AddDescription; - -template -class AddPos; - -template -class AddLOC; - -// The error info class itself. -class ErrorInfo -{ -public: - ErrLevel level; - string name; - string description; - std::optional nixCode; - std::optional hint; - ErrorInfo& GetEI() - { - return *this; - } - - static std::optional programName; - - // give these access to the private constructor, - // when they are direct descendants (children but not grandchildren). - friend AddName; - friend AddDescription; - friend AddPos; - friend AddLOC; - - NixCode& ensureNixCode() - { - if (!this->nixCode.has_value()) - this->nixCode = std::optional(NixCode()); - return *this->nixCode; - } -protected: - // constructor is protected, so only the builder classes can create an ErrorInfo. - ErrorInfo(ErrLevel level) - { - this->level = level; - } -}; - -// Init as error -class EIError : public ErrorInfo -{ -protected: - EIError() : ErrorInfo(elError) {} -}; - -// Init as warning -class EIWarning : public ErrorInfo -{ -protected: - EIWarning() : ErrorInfo(elWarning) {} -}; - -// Builder class definitions. -template -class AddName : private T -{ -public: - T& name(const std::string &name) - { - GetEI().name = name; - return *this; - } -protected: - ErrorInfo& GetEI() - { - return T::GetEI(); - } -}; - -template -class AddDescription : private T -{ -public: - T& description(const std::string &description) - { - GetEI().description = description; - return *this; - } -protected: - ErrorInfo& GetEI() - { - return T::GetEI(); - } -}; - -template -class AddPos : private T -{ -public: - template - T& pos(const P &aPos) - { - GetEI().ensureNixCode().nixFile = aPos.file; - GetEI().ensureNixCode().ensureErrLine().lineNumber = aPos.line; - GetEI().ensureNixCode().ensureErrLine().column = aPos.column; - return *this; - } -protected: - ErrorInfo& GetEI() - { - return T::GetEI(); - } -}; - -template -class AddLOC : private T -{ -public: - T& linesOfCode(std::optional prevloc, string loc, std::optional nextloc) - { - GetEI().ensureNixCode().ensureErrLine().prevLineOfCode = prevloc; - GetEI().ensureNixCode().ensureErrLine().errLineOfCode = loc; - GetEI().ensureNixCode().ensureErrLine().nextLineOfCode = nextloc; - return *this; - } -protected: - ErrorInfo& GetEI() - { - return T::GetEI(); - } -}; - - // ---------------------------------------------------------------- -// format for hints. same as fmt, except templated values +// format function for hints. same as fmt, except templated values // are always in yellow. template @@ -222,9 +90,13 @@ public: friend class AddHint; private: format fmt; - }; +std::ostream& operator<<(std::ostream &os, const hintformat &hf) +{ + return os << hf.str(); +} + template inline hintformat hintfmt(const std::string & fs, const Args & ... args) { @@ -233,61 +105,27 @@ inline hintformat hintfmt(const std::string & fs, const Args & ... args) return f; } -// the template layer for adding a hint. -template -class AddHint : private T +// ------------------------------------------------- +// ErrorInfo. +class ErrorInfo { public: - T& hint(const hintformat &hf) - { - GetEI().hint = std::optional(hf.str()); - return *this; - } - T& nohint() - { - GetEI().hint = std::nullopt; - return *this; - } -protected: - ErrorInfo& GetEI() - { - return T::GetEI(); - } + ErrLevel level; + string name; + string description; + std::optional hint; + std::optional nixCode; + + static std::optional programName; + +private: }; -// -------------------------------------------------------- -// error types - -typedef AddName< - AddDescription< - AddHint< - EIError>>> ProgramError; - -typedef AddName< - AddDescription< - AddHint< - EIWarning>>> ProgramWarning; - -typedef AddName< - AddDescription< - AddPos< - AddLOC< - AddHint< - EIError>>>>> NixLangError; - -typedef AddName< - AddDescription< - AddPos< - AddLOC< - AddHint< - EIWarning>>>>> NixLangWarning; - - // -------------------------------------------------------- // error printing // just to cout for now. -void printErrorInfo(ErrorInfo &einfo); +void printErrorInfo(const ErrorInfo &einfo); }