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