#include "parse_context.h" #include "assert.h" #include #include #include ParseContext::ParseContext() { applicationDir = std::string(); } unsigned ParseContext::addFile(const std::string &fileName, const std::string &source) { fileMap.emplace_back(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); 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; } 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); }