#include <utility> #include <memory> // For std::unique_ptr #include "DiagnosticsHolder.hpp" #include "ErrorMessages-EN-US.cpp" using namespace Porygon::Diagnostics; vector<Diagnostic> DiagnosticsHolder::GetDiagnostics() { return _diagnostics; } void DiagnosticsHolder::Log(DiagnosticSeverity severity, DiagnosticCode code, unsigned int start, unsigned int length, std::vector<string> arguments) { _diagnostics.emplace_back(severity, code, start, length, arguments); if (severity >= DiagnosticSeverity::Error){ _hasErrors = true; } } void DiagnosticsHolder::LogError(DiagnosticCode code, unsigned int start, unsigned int length, std::vector<string> arguments) { Log(DiagnosticSeverity::Error, code, start, length, std::move(arguments)); } void DiagnosticsHolder::LogWarning(DiagnosticCode code, unsigned int start, unsigned int length, std::vector<string> arguments) { Log(DiagnosticSeverity::Warning, code, start, length, std::move(arguments)); } void DiagnosticsHolder::LogInfo(DiagnosticCode code, unsigned int start, unsigned int length, std::vector<string> arguments) { Log(DiagnosticSeverity::Info, code, start, length, std::move(arguments)); } bool DiagnosticsHolder::HasErrors() { return _hasErrors; } int DiagnosticsHolder::DiagnosticsCount() { return _diagnostics.size(); } Diagnostic *DiagnosticsHolder::GetDiagnosticAt(int position) { return &_diagnostics[position]; } size_t DiagnosticsHolder::GetLineFromPosition(size_t i) { size_t topLimit = _lineStarts.size() - 1; size_t bottomLimit = 0; while (true){ if (bottomLimit == topLimit){ return bottomLimit; } size_t half = (topLimit - bottomLimit) / 2; size_t pos = _lineStarts[half]; size_t length = _lineLength[half]; if (pos < i && pos + length > i){ return half; } if (pos > i){ bottomLimit = half; } else if (pos < i){ topLimit = half; } else{ return half; } } } std::string SeverityToString(DiagnosticSeverity s){ switch (s){ case DiagnosticSeverity::Info: return "Info"; case DiagnosticSeverity::Warning: return "Warning"; case DiagnosticSeverity::Error: return "Error"; } } void findAndReplaceAll(std::string & data, const std::string& toSearch, const std::string& replaceStr) { // Get the first occurrence size_t pos = data.find(toSearch); // Repeat till end is reached while( pos != std::string::npos) { // Replace this occurrence of Sub String data.replace(pos, toSearch.size(), replaceStr); // Get the next occurrence from the current position pos =data.find(toSearch, pos + replaceStr.size()); } } const string PrettyDiagnostic ( const char * format, vector<string> arguments) { string result = string(format); for (int i = 0; i < arguments.size(); i++){ auto keyToReplace = "{" + to_string(i) + "}"; auto argument = arguments[i]; findAndReplaceAll(result, keyToReplace, argument); } return result; } std::string DiagnosticsHolder::GetFullDiagnostic(Diagnostic* diagnostic) { stringstream stream; stream << "[" << SeverityToString(diagnostic->GetSeverity()) << "] "; auto startPos = diagnostic->GetStartPosition(); auto line = this -> GetLineFromPosition(startPos); auto linePos = startPos - this ->GetStartPositionForLine(line); stream << " (" << line + 1 << ", " << linePos + 1 << ") "; auto unformatted = ErrorMessages.find(diagnostic->GetCode()); if (unformatted != ErrorMessages.end()){ stream << PrettyDiagnostic(unformatted->second, diagnostic->GetArguments()); } return stream.str(); } extern "C" { int GetDiagnosticsCount (DiagnosticsHolder* diagnostics){ return diagnostics->DiagnosticsCount(); } Diagnostic* GetDiagnosticAt(DiagnosticsHolder* diagnostics, int position){ return diagnostics->GetDiagnosticAt(position); } const char* GetFullDiagnostic(DiagnosticsHolder* diagnostics, Diagnostic* diag){ return diagnostics ->GetFullDiagnostic(diag).c_str(); } }