-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathlogging.cpp
More file actions
135 lines (109 loc) · 3.78 KB
/
Copy pathlogging.cpp
File metadata and controls
135 lines (109 loc) · 3.78 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
#include "logging.hpp"
#include <iomanip>
#include <ios>
#include <string>
#include <unordered_map>
#include <fstream>
#include <iostream>
#include <cctype>
#include <cstring>
static std::string to_string(Errors error) {
switch (error) {
case Errors::Syntax: return "syntax";
case Errors::Type : return "type";
default: return "unkown";
}
}
void ConsoleLogger::log(Errors error, const std::string& message, TextSpan span) {
LANG_ASSERT(span.start.pos <= span.end.pos);
LANG_ASSERT(span.start.line <= span.end.line);
LANG_ASSERT(span.start.column <= span.end.column);
messages.emplace_back(
LogMessage{
.error = error,
.message = message,
.span = span,
}
);
}
bool ConsoleLogger::is_error() {
return messages.size() > 0;
}
void ConsoleLogger::commit(const FileManager& file_manager) {
std::unordered_map<int, std::vector<LogMessage*>> file_to_messages;
for (auto& m : messages) {
if (file_to_messages.find(m.span.src_id) == file_to_messages.end())
file_to_messages[m.span.src_id] = std::vector<LogMessage*>{};
file_to_messages[m.span.src_id].push_back(&m);
}
std::string line_buf;
for (auto& [src_id, msgs] : file_to_messages) {
auto path = file_manager.get_path(src_id);
std::ifstream file;
for (auto m_ptr : msgs) {
auto& span = m_ptr->span;
auto& error = m_ptr->error;
auto& message = m_ptr->message;
if (path != "")
std::cout << path << ":" << to_string(span.start) << ": ";
std::cout << to_string(error) << ": " << message << "\n";
if (path == "" || span.start.pos < 0)
continue;
if (file.bad())
file.close();
else if (file.eof() || file.fail())
file.clear();
if (!file.is_open() || file.bad())
file.open(path);
if (file) {
file.seekg(span.start.pos);
int line = span.start.line;
// go to beginning of line
while(file.tellg() != 0 && file.unget() && file.peek() != '\n') {}
if (file.peek() == '\n') {
// go back an extra line if possible
while(file.tellg() != 0 && file.unget()) {
line = span.start.line - 1;
if (file.peek() == '\n')
break;
}
// consume \n from previous line
file.get();
}
int left_pad = std::to_string(span.end.line + 1).length() + 1;
for (; line <= span.end.line + 1; ++line) {
std::getline(file, line_buf);
std::cout << std::setfill(' ') << std::setw(left_pad) << std::right << line;
std::cout << " | " << line_buf << "\n";
if (line >= span.start.line && line <= span.end.line) {
std::cout << std::string(left_pad + 3, ' ');
for (int col = 1; col <= line_buf.length(); ++col) {
char c = line_buf[col - 1];
if (isspace(c))
std::cout << c;
else if (line == span.start.line && col < span.start.column)
std::cout << ' ';
else if (line == span.end.line && col > span.end.column)
std::cout << ' ';
else
std::cout << '^';
}
std::cout << "\n";
}
}
}
}
}
messages.clear();
}
static void dummy_trace([[maybe_unused]] const char *inFMT, ...) {
LANG_ASSERT(false);
};
TraceFunction trace = dummy_trace;
#ifdef LANG_ENABLE_ASSERTS
static bool dummy_assert_failed(const char *inExpression, const char *inMessage, const char *inFile, int inLine) {
std::cerr << "Assert failed \"" << inExpression << "\" at " << inFile << ":" << inLine << " " << inMessage << std::endl;
return true; // Trigger breakpoint
};
AssertFailedFunction assert_failed = dummy_assert_failed;
#endif // LANG_ENABLE_ASSERTS