sammine-lang
Loading...
Searching...
No Matches
Utilities.h
Go to the documentation of this file.
1#pragma once
2#include "fmt/color.h"
3#include "fmt/core.h"
4#include <algorithm>
5#include <cassert>
6#include <cstdlib>
7#include <iostream>
8#include <filesystem>
9#include <source_location>
10#include <string>
11#include <string_view>
12#include <tuple>
13#include <unistd.h>
14#include <utility>
15#include <vector>
16#include <memory>
17
21
22namespace sammine_util {
23inline bool stderr_is_tty() {
24 static const bool is_tty = ::isatty(STDERR_FILENO);
25 return is_tty;
26}
27inline fmt::text_style styled(fmt::terminal_color c) {
28 return stderr_is_tty() ? fg(c) : fmt::text_style{};
29}
30
31
32auto get_string_from_file(const std::string &file_name) -> std::string;
33
34template <typename T>
35concept explicitly_bool_like = requires(T t) {
36 { static_cast<bool>(t) } -> std::same_as<bool>;
37};
38[[noreturn]] auto abort(const std::string &message = "<NO MESSAGE>") -> void;
39
40template <explicitly_bool_like T>
41void abort_on(const T &condition, const std::string &message = "<NO MESSAGE>") {
42 if (static_cast<bool>(condition)) {
43 abort(message);
44 }
45}
46
47template <explicitly_bool_like T>
48void abort_if_not(const T &condition,
49 const std::string &message = "<NO MESSAGE>") {
50 if (!static_cast<bool>(condition)) {
51 abort(message);
52 }
53}
54inline void log_diagnostics(const std::string &diagnostics) {
55 fmt::print(stderr, fg(fmt::terminal_color::green), "{}\n", diagnostics);
56}
57
58struct SourceInfo {
59 std::string file_name;
60 std::string source_text;
61};
62
65
70class Location {
71public:
72 // True location in original source code string
73 int64_t source_start, source_end;
74
75 // Source file info (nullptr = main file)
76 std::shared_ptr<SourceInfo> source_info;
77
78 // Default constructor
79 Location() : source_start(0), source_end(0) {}
80 static Location NonPrintable() { return Location(-1, -1); }
81 Location(int64_t source_start, int64_t source_end)
82 : source_start(source_start), source_end(source_end) {}
83
84 // Advance column position
85 inline void advance() { source_end++; }
86
87 // Move column position backwards
88 inline void devance() {
89 source_end--;
90 assert(source_end >= source_start);
91 }
92
93 // Handle newline
94 inline void newLine() { advance(); }
95
96 // Combine two locations — propagate non-null source_info
97 Location operator|(const Location &other) const {
98 Location result;
99 result.source_start = std::min(source_start, other.source_start);
100 result.source_end = std::max(source_end, other.source_end);
101 result.source_info = source_info ? source_info : other.source_info;
102 return result;
103 }
104
105 void operator|=(const Location &other) {
106 source_start = std::min(source_start, other.source_start);
107 source_end = std::max(source_end, other.source_end);
108 if (!source_info)
109 source_info = other.source_info;
110 }
111
112 std::pair<int64_t, int64_t> as_pair() const {
113 return std::make_pair(source_start, source_end);
114 }
115
116 // Stream output operator
117 friend std::ostream &operator<<(std::ostream &out, const Location &loc) {
118 out << loc.source_start << ":" << loc.source_end;
119
120 return out;
121 }
122
123 // Equality operator
124 bool operator==(const Location &other) const {
125 return source_start == other.source_start &&
126 source_end == other.source_end &&
127 source_info.get() == other.source_info.get();
128 }
129};
130class Reportee {
131public:
132 virtual ~Reportee() = default;
133 enum ReportKind {
134 error,
135 warn,
136 diag,
137 };
138 using Report = std::tuple<Location, std::vector<std::string>, ReportKind,
139 std::source_location>;
140
141 using iterator = std::vector<Report>::iterator;
142 using const_iterator = std::vector<Report>::const_iterator;
143
144 // Iterator methods
145 iterator begin() { return reports.begin(); }
146 iterator end() { return reports.end(); }
147 const_iterator begin() const { return reports.begin(); }
148 const_iterator end() const { return reports.end(); }
149 const_iterator cbegin() const { return reports.cbegin(); }
150 const_iterator cend() const { return reports.cend(); }
151 [[noreturn]] virtual void abort(const std::string &msg = "<NO MESSAGE>") {
152 sammine_util::abort(msg);
153 }
154 template <explicitly_bool_like T>
155 void abort_on(const T &condition,
156 const std::string &message = "<NO MESSAGE>") {
157 if (static_cast<bool>(condition)) {
158 this->abort(message);
159 }
160 }
161
162 template <explicitly_bool_like T>
163 void abort_if_not(const T &condition,
164 const std::string &message = "<NO MESSAGE>") {
165 if (!static_cast<bool>(condition)) {
166 this->abort(message);
167 }
168 }
169 void add_error(Location loc, std::string msg,
170 std::source_location src = std::source_location::current()) {
171 reports.push_back({loc, {std::move(msg)}, ReportKind::error, src});
172 error_count++;
173 }
174 void add_error(Location loc, std::vector<std::string> msgs,
175 std::source_location src = std::source_location::current()) {
176 reports.push_back({loc, std::move(msgs), ReportKind::error, src});
177 error_count++;
178 }
179 void add_warn(Location loc, std::string msg,
180 std::source_location src = std::source_location::current()) {
181 reports.push_back({loc, {std::move(msg)}, ReportKind::warn, src});
182 warn_count++;
183 }
184 void
185 add_diagnostics(Location loc, std::string msg,
186 std::source_location src = std::source_location::current()) {
187 reports.push_back({loc, {std::move(msg)}, ReportKind::diag, src});
188 diag_count++;
189 }
190
191 [[nodiscard]] virtual bool has_errors() const { return error_count > 0; }
192 [[nodiscard]] bool has_warn() const { return warn_count > 0; }
193 [[nodiscard]] bool has_message() const { return !reports.empty(); }
194
195 [[nodiscard]] bool has_diagnostics() const { return diag_count > 0; }
196
197 [[nodiscard]] int64_t get_error_count() const { return error_count; }
198
199 [[nodiscard]] int64_t get_warn_count() const { return warn_count; }
200 [[nodiscard]] int64_t get_diagnostic_count() const { return diag_count; }
201
202protected:
203 std::vector<Report> reports;
204 int64_t error_count = 0;
205 int64_t warn_count = 0;
206 int64_t diag_count = 0;
207};
208
209class Reporter {
210public:
211 using ReportKind = Reportee::ReportKind;
212 using IndexPair = std::pair<int64_t, int64_t>;
213 using DiagnosticData = std::vector<std::pair<std::int64_t, std::string_view>>;
214
215 static DiagnosticData get_diagnostic_data(std::string_view str);
216
217 inline static fmt::terminal_color LINE_COLOR =
218 fmt::terminal_color::bright_magenta;
219
220 static fmt::terminal_color get_color_from(ReportKind report_kind);
221
222 template <typename... T>
223 static void print_fmt(fmt::terminal_color ts,
224 fmt::format_string<T...> format_str, T &&...args) {
225 if (stderr_is_tty())
226 fmt::print(stderr, fg(ts), format_str, std::forward<T>(args)...);
227 else
228 fmt::print(stderr, format_str, std::forward<T>(args)...);
229 }
230 template <typename... T>
231 static void print_fmt(fmt::color ts, fmt::format_string<T...> format_str,
232 T &&...args) {
233 if (stderr_is_tty())
234 fmt::print(stderr, fg(ts), format_str, std::forward<T>(args)...);
235 else
236 fmt::print(stderr, format_str, std::forward<T>(args)...);
237 }
238 template <typename... T>
239 static void print_fmt(const ReportKind report_kind,
240 fmt::format_string<T...> format_str, T &&...args) {
241 if (stderr_is_tty())
242 fmt::print(stderr, fg(get_color_from(report_kind)), format_str,
243 std::forward<T>(args)...);
244 else
245 fmt::print(stderr, format_str, std::forward<T>(args)...);
246 }
247
248 static void print_data_singular_line(std::string_view msg, int64_t col_start,
249 int64_t col_end);
250
251private:
252 inline static fmt::terminal_color MSG_COLOR = fmt::terminal_color::blue;
253 std::string file_name;
254 std::string input;
255 std::vector<std::pair<std::int64_t, std::string_view>> diagnostic_data;
256 int64_t context_radius;
257 bool dev_mode = false;
258
259 void report_single_msg(const Location &loc,
260 const std::vector<std::string> &format_strs,
261 const ReportKind report_kind,
262 std::source_location src = std::source_location::current()) const;
263
264 void indicate_singular_line(ReportKind report_kind, int64_t col_start,
265 int64_t col_end) const;
266
267 static void report_singular_line(ReportKind report_kind,
268 const std::vector<std::string> &msgs,
269 int64_t col_start, int64_t col_end);
270
271public:
272 void report(const Reportee &reports) const;
273 void immediate_error(const std::string &str, Location l = Location(-1, -1),
274 std::source_location src = std::source_location::current()) {
275 if (l.source_start <= 0 && l.source_end <= 0) {
276 print_fmt(LINE_COLOR, " |");
277 print_fmt(fmt::terminal_color::blue, "In {}\n", file_name);
278 report_singular_line(ReportKind::error, {str}, 0, 0);
279
280 } else {
281 report_single_msg(l, {str}, ReportKind::error, src);
282 }
283 }
284 void immediate_diag(const std::string &str, Location l = Location(-1, -1),
285 std::source_location src = std::source_location::current()) {
286 if (l.source_start <= 0 && l.source_end <= 0) {
287 print_fmt(LINE_COLOR, " |");
288 print_fmt(fmt::terminal_color::blue, "In {}\n", file_name);
289 report_singular_line(ReportKind::diag, {str}, 0, 0);
290 } else {
291 report_single_msg(l, {str}, ReportKind::diag, src);
292 }
293 }
294 void immediate_warn(const std::string &str, Location l = Location(-1, -1),
295 std::source_location src = std::source_location::current()) {
296 if (l.source_start <= 0 && l.source_end <= 0) {
297 print_fmt(LINE_COLOR, " |");
298 print_fmt(fmt::terminal_color::blue, "In {}\n", file_name);
299 report_singular_line(ReportKind::warn, {str}, 0, 0);
300 } else {
301 report_single_msg(l, {str}, ReportKind::warn, src);
302 }
303 }
304 Reporter() {}
305 Reporter(std::string file_name, std::string input, int64_t context_radius,
306 bool dev_mode = false)
307 : file_name(file_name), input(input),
308 diagnostic_data(get_diagnostic_data(this->input)),
309 context_radius(context_radius), dev_mode(dev_mode) {}
310};
311} // namespace sammine_util
Definition Utilities.h:70
Definition Utilities.h:130
Definition Utilities.h:35
Definition Utilities.h:58