119 lines
3.2 KiB
C++
119 lines
3.2 KiB
C++
#include "parse_context.h"
|
|
#include "assert.h"
|
|
|
|
#include <iostream>
|
|
#include <iomanip>
|
|
#include <cmath>
|
|
|
|
|
|
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<int>(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);
|
|
}
|