#include "parsecontext.h" #include "assert.h" #include #include #include ParseContext::ParseContext() { applicationDir = std::string(); } unsigned ParseContext::addFile(const std::string& fileName, const std::string& source) { fileMap.push_back(SourceFile(fileName, source)); return fileMap.size(); } SourceFile& ParseContext::getFile(unsigned fileId) { return fileMap[fileId-1]; } struct pad { char ch; int count; pad(char ch, int count) : ch(ch), count(count) {} }; std::ostream& operator<<(std::ostream& stream, const pad& p) { for (int i = 0; i < p.count; i++) { stream << p.ch; } return stream; } #define ATLAS_ASSERT(x) \ do {} while(0) void ParseContext::formatError(const SourceError& sourceError, std::ostream& stream, const std::string& ErrorOrWarning) { ATLAS_ASSERT(sourceError.span.lo.col != 0 && sourceError.span.hi.col != 0); SourceFile sourceFile = getFile(sourceError.span.lo.fileId); stream << ErrorOrWarning << sourceError.message << std::endl; Span span = sourceError.span; // figure out how much padding is required for line numbers in front of // printed source code int numberPad = 0; while (true) { numberPad = std::max(numberPad, static_cast(ceil(log10(span.hi.line))) + 1); break; } span = sourceError.span; // print all spans while (true) { SourceFile sourceFile = getFile(span.lo.fileId); // check if the span spans across multiple lines or even files bool complex = span.lo.fileId != span.hi.fileId || span.lo.line != span.hi.line; stream << pad(' ', numberPad) << " -> " << sourceFile.getFileName() << ":" << span.lo.line << ":" << span.lo.col << std::endl; stream << pad(' ', numberPad) << " |" << std::endl << std::right << std::setw(numberPad) << span.lo.line << " | " << sourceFile.getLine(span.lo.line) << std::endl << pad(' ', numberPad) << " | "; for (unsigned i = 0; i < span.lo.col - 1; i++) { stream << ' '; } if (complex) { // just point to the beginning of the span stream << '^'; } else { // underline the entire span for (unsigned i = 0; i < span.hi.col - span.lo.col; i++) { stream << '^'; } } stream << std::endl; break; } stream << std::endl; } SourceFile::SourceFile(std::string fileName, std::string source) : fileName(std::move(fileName)), source(std::move(source)) { lineOffsets.push_back(0); } const std::string& SourceFile::getFileName() const { return fileName; } const std::string SourceFile::getLine(unsigned line) const { auto lineOffset = lineOffsets[line-1]; auto nextLF = source.find('\n', lineOffset); auto nextCR = source.find('\r', lineOffset); auto nl = std::min(nextCR, nextLF); return source.substr(lineOffset, nl - lineOffset); } void SourceFile::addLineOffset(unsigned offset) { lineOffsets.push_back(offset); }