sammine-lang
Loading...
Searching...
No Matches
Utilities.h
Go to the documentation of this file.
1#pragma once
2#include "fmt/base.h"
3#include "fmt/color.h"
4#include "fmt/core.h"
5#include <algorithm>
6#include <cassert>
7#include <cstddef>
8#include <cstdlib>
9#include <iostream>
10#include <string>
11#include <string_view>
12#include <tuple>
13#include <utility>
14#include <vector>
15
19
20namespace sammine_util {
21auto get_string_from_file(const std::string &file_name) -> std::string;
22inline int64_t unique_ast_id = 0;
23
24template <typename T>
25concept explicitly_bool_like = requires(T t) {
26 { static_cast<bool>(t) } -> std::same_as<bool>;
27};
28[[noreturn]] auto abort(const std::string &message = "<NO MESSAGE>") -> void;
29
30template <explicitly_bool_like T>
31void abort_on(const T &condition, const std::string &message = "<NO MESSAGE>") {
32 if (static_cast<bool>(condition)) {
33 abort(message);
34 }
35}
36
37template <explicitly_bool_like T>
38void abort_if_not(const T &condition,
39 const std::string &message = "<NO MESSAGE>") {
40 if (!static_cast<bool>(condition)) {
41 abort(message);
42 }
43}
44inline void log_diagnostics(const std::string &diagnostics) {
45 fmt::print(stderr, fg(fmt::terminal_color::bright_green), "{}\n",
46 diagnostics);
47}
48
51
56class Location {
57public:
58 // True location in original source code string
59 int64_t source_start, source_end;
60
61 // Default constructor
62 Location() : source_start(0), source_end(0) {}
63 static Location NonPrintable() { return Location(-1, -1); }
64 Location(int64_t source_start, int64_t source_end)
65 : source_start(source_start), source_end(source_end) {}
66
67 // Advance column position
68 inline void advance() { source_end++; }
69
70 // Move column position backwards
71 inline void devance() {
72 source_end--;
73 assert(source_end >= source_start);
74 }
75
76 // Handle newline
77 inline void newLine() { advance(); }
78
79 // Combine two locations
80 Location operator|(const Location &other) const {
81 Location result;
82 result.source_start = std::min(source_start, other.source_start);
83 result.source_end = std::max(source_end, other.source_end);
84 return result;
85 }
86
87 void operator|=(const Location &other) {
88 source_start = std::min(source_start, other.source_start);
89 source_end = std::max(source_end, other.source_end);
90 }
91 operator std::pair<int64_t, int64_t>() const {
92 return std::make_pair(source_start, source_end);
93 }
94
95 // Stream output operator
96 friend std::ostream &operator<<(std::ostream &out, const Location &loc) {
97 out << loc.source_start << ":" << loc.source_end;
98
99 return out;
100 }
101
102 // Equality operator
103 bool operator==(const Location &other) const {
104 return source_start == other.source_start && source_end == other.source_end;
105 }
106};
107class Reportee {
108public:
109 enum ReportKind {
110 error,
111 warn,
112 diag,
113 };
114 using Report = std::tuple<Location, std::string, ReportKind>;
115
116 using iterator = std::vector<Report>::iterator;
117 using const_iterator = std::vector<Report>::const_iterator;
118
119 // Iterator methods
120 iterator begin() { return reports.begin(); }
121 iterator end() { return reports.end(); }
122 const_iterator begin() const { return reports.begin(); }
123 const_iterator end() const { return reports.end(); }
124 const_iterator cbegin() const { return reports.cbegin(); }
125 const_iterator cend() const { return reports.cend(); }
126 [[noreturn]] virtual void abort(const std::string &msg = "<NO MESSAGE>") {
127 sammine_util::abort(msg);
128 }
129 template <explicitly_bool_like T>
130 void abort_on(const T &condition,
131 const std::string &message = "<NO MESSAGE>") {
132 if (static_cast<bool>(condition)) {
133 this->abort(message);
134 }
135 }
136
137 template <explicitly_bool_like T>
138 void abort_if_not(const T &condition,
139 const std::string &message = "<NO MESSAGE>") {
140 if (!static_cast<bool>(condition)) {
141 this->abort(message);
142 }
143 }
144 void add_error(Location loc, std::string msg) {
145 reports.push_back({loc, msg, ReportKind::error});
146 error_count++;
147 }
148 void add_warn(Location loc, std::string msg) {
149 reports.push_back({loc, msg, ReportKind::warn});
150 warn_count++;
151 }
152 void add_diagnostics(Location loc, std::string msg) {
153 reports.push_back({loc, msg, ReportKind::diag});
154 diag_count++;
155 }
156
157 [[nodiscard]] virtual bool has_errors() const { return error_count > 0; }
158 [[nodiscard]] bool has_warn() const { return warn_count > 0; }
159 [[nodiscard]] bool has_message() const { return !reports.empty(); }
160
161 [[nodiscard]] bool has_diagnostics() const { return diag_count > 0; }
162
163 [[nodiscard]] int64_t get_error_count() const { return error_count; }
164
165 [[nodiscard]] int64_t get_warn_count() const { return warn_count; }
166 [[nodiscard]] int64_t get_diagnostic_count() const { return diag_count; }
167
168protected:
169 std::vector<Report> reports;
170 int64_t error_count = 0;
171 int64_t warn_count = 0;
172 int64_t diag_count = 0;
173};
174
175class Reporter {
176public:
177 using ReportKind = Reportee::ReportKind;
178 using IndexPair = std::pair<int64_t, int64_t>;
179 using DiagnosticData = std::vector<std::pair<std::int64_t, std::string_view>>;
180
181private:
182 static DiagnosticData get_diagnostic_data(std::string_view str);
183 inline static fmt::terminal_color LINE_COLOR =
184 fmt::terminal_color::bright_magenta;
185
186 inline static fmt::terminal_color MSG_COLOR =
187 fmt::terminal_color::bright_blue;
188 std::string file_name;
189 std::string input;
190 std::vector<std::pair<std::int64_t, std::string_view>> diagnostic_data;
191 int64_t context_radius;
192 static fmt::terminal_color get_color_from(ReportKind report_kind);
193
194 void report_single_msg(std::pair<int64_t, int64_t> index_pair,
195 const std::string &format_str,
196 const ReportKind report_kind) const;
197
198 template <typename... T>
199 static void print_fmt(fmt::terminal_color ts,
200 fmt::format_string<T...> format_str, T &&...args) {
201 fmt::print(stderr, fg(ts), format_str, std::forward<T>(args)...);
202 }
203 template <typename... T>
204 static void print_fmt(fmt::color ts, fmt::format_string<T...> format_str,
205 T &&...args) {
206 fmt::print(stderr, fg(ts), format_str, std::forward<T>(args)...);
207 }
208 template <typename... T>
209 static void print_fmt(const ReportKind report_kind,
210 fmt::format_string<T...> format_str, T &&...args) {
211 fmt::print(stderr, fg(get_color_from(report_kind)), format_str,
212 std::forward<T>(args)...);
213 }
214
215 void indicate_singular_line(ReportKind report_kind, int64_t col_start,
216 int64_t col_end) const;
217
218 static void report_singular_line(ReportKind report_kind,
219 const std::string &msg, int64_t col_start,
220 int64_t col_end);
221
222 void print_data_singular_line(std::string_view msg, int64_t col_start,
223 int64_t col_end) const;
224
225public:
226 void report(const Reportee &reports) const;
227 void immediate_error(const std::string &str, Location l = Location(-1, -1)) {
228 if (l.source_start <= 0 && l.source_end <= 0) {
229 print_fmt(LINE_COLOR, " |");
230 print_fmt(fmt::terminal_color::bright_blue, "In {}\n", file_name);
231 report_singular_line(ReportKind::error, str, 0, 0);
232
233 } else {
234 report_single_msg(l, str, ReportKind::error);
235 }
236 }
237 void immediate_diag(const std::string &str, Location l = Location(-1, -1)) {
238 if (l.source_start <= 0 && l.source_end <= 0) {
239 print_fmt(LINE_COLOR, " |");
240 print_fmt(fmt::terminal_color::bright_blue, "In {}\n", file_name);
241 report_singular_line(ReportKind::diag, str, 0, 0);
242 } else {
243 report_single_msg(l, str, ReportKind::diag);
244 }
245 }
246 Reporter() {}
247 Reporter(std::string file_name, std::string input, int64_t context_radius)
248 : file_name(file_name), input(input),
249 diagnostic_data(get_diagnostic_data(this->input)),
250 context_radius(context_radius) {}
251};
252} // namespace sammine_util
Definition Utilities.h:56
Definition Utilities.h:107
Definition Utilities.h:25