#pragma once #include "types.hh" #include #include #include using std::string; using std::optional; namespace nix { enum ErrLevel { elWarning , elError }; class ColumnRange { public: unsigned int start; unsigned int len; }; class ErrorInfo; class ErrLine { public: int lineNumber; optional columnRange; optional prevLineOfCode; string errLineOfCode; optional nextLineOfCode; }; class NixCode { public: optional nixFile; optional errLine; ErrLine& ensureErrLine() { if (!this->errLine.has_value()) this->errLine = optional(ErrLine()); return *this->errLine; } }; // ------------------------------------------------- // ErrorInfo. // Forward friend class declarations. "builder classes" template class AddName; template class AddDescription; template class AddNixCode; template class AddNixFile; template class AddErrLine; template class AddLineNumber; template class AddColumnRange; template class AddLOC; // The error info class itself. class ErrorInfo { public: ErrLevel level; string name; string description; string program; optional nixCode; string hint; ErrorInfo& GetEI() { return *this; } // give these access to the private constructor, // when they are direct descendants. friend AddName; friend AddDescription; friend AddNixCode; friend AddNixFile; friend AddErrLine; friend AddLineNumber; friend AddColumnRange; friend AddLOC; NixCode& ensureNixCode() { if (!this->nixCode.has_value()) this->nixCode = optional(NixCode()); return *this->nixCode; } protected: // constructor is protected, so only the builder classes can create an ErrorInfo. ErrorInfo(ErrLevel level) { this->level = level; } }; class EIError : public ErrorInfo { protected: EIError() : ErrorInfo(elError) {} }; class EIWarning : public ErrorInfo { protected: EIWarning() : ErrorInfo(elWarning) {} }; 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 AddNixFile : public T { public: T& nixFile(string filename) { GetEI().ensureNixCode().nixFile = filename; return *this; } protected: ErrorInfo& GetEI() { return T::GetEI(); } }; template class AddLineNumber : public T { public: T& lineNumber(int lineNumber) { GetEI().ensureNixCode().ensureErrLine().lineNumber = lineNumber; return *this; } protected: ErrorInfo& GetEI() { return T::GetEI(); } }; template class AddColumnRange : public T { public: T& columnRange(unsigned int start, unsigned int len) { GetEI().ensureNixCode().ensureErrLine().columnRange = { start, len }; return *this; } protected: ErrorInfo& GetEI() { return T::GetEI(); } }; template class AddLOC : public T { public: T& linesOfCode(optional prevloc, string loc, 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(); } }; typedef AddNixFile> MkNixCode; typedef AddName> StandardError; typedef AddName> StandardWarning; typedef AddName< AddDescription< AddNixFile< AddLineNumber< AddColumnRange< AddLOC>>>>> MkNixError; typedef AddName< AddDescription< AddNixFile< AddLineNumber< AddColumnRange< AddLOC>>>>> MkNixWarning; string showErrLine(ErrLine &errLine); void print_code_lines(string &prefix, NixCode &nix_code); void print_error(ErrorInfo &einfo); }