Aleph-w 3.0
A C++ Library for Data Structures and Algorithms
Loading...
Searching...
No Matches
ah-diagnostics.H
Go to the documentation of this file.
1/*
2 Aleph_w
3
4 Data structures & Algorithms
5 version 2.0.0b
6 https://github.com/lrleon/Aleph-w
7
8 This file is part of Aleph-w library
9
10 Copyright (c) 2002-2026 Leandro Rabindranath Leon
11
12 Permission is hereby granted, free of charge, to any person obtaining a copy
13 of this software and associated documentation files (the "Software"), to deal
14 in the Software without restriction, including without limitation the rights
15 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
16 copies of the Software, and to permit persons to whom the Software is
17 furnished to do so, subject to the following conditions:
18
19 The above copyright notice and this permission notice shall be included in all
20 copies or substantial portions of the Software.
21
22 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
25 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
28 SOFTWARE.
29*/
30
31
46# ifndef AH_DIAGNOSTICS_H
47# define AH_DIAGNOSTICS_H
48
49# include <ostream>
50# include <sstream>
51# include <string>
52
53# include <ah-source.H>
54# include <tpl_dynArray.H>
55
56namespace Aleph
57{
60 {
61 Note,
62 Warning,
63 Error,
64 Fatal
65 };
66
69 {
70 Primary,
72 };
73
85
100
101 class Diagnostic_Engine;
102
105 {
107 size_t diag_index = 0;
108
109 Diagnostic & diag();
110
111 public:
114 : engine(&engine), diag_index(index)
115 {}
116
118 Diagnostic_Builder & code(const std::string & value);
119
126 const std::string & msg = "");
127
130 const std::string & msg);
131
133 Diagnostic_Builder & note(const std::string & msg);
134
136 Diagnostic_Builder & help(const std::string & msg);
137
140 {
141 return diag_index;
142 }
143 };
144
152 {
153 const Source_Manager * sources = nullptr;
155 size_t errors = 0;
156 size_t warnings = 0;
157
158 static const char * severity_string(const Diagnostic_Severity severity)
159 {
160 switch (severity)
161 {
162 case Diagnostic_Severity::Note: return "note";
163 case Diagnostic_Severity::Warning: return "warning";
164 case Diagnostic_Severity::Error: return "error";
165 case Diagnostic_Severity::Fatal: return "fatal";
166 }
167
168 return "diagnostic";
169 }
170
172 const Source_Span & span,
173 const std::string & msg)
174 {
175 Diagnostic diag;
176 diag.severity = severity;
177 diag.message = msg;
178 if (span.is_valid())
179 diag.labels.append({span, Diagnostic_Label_Kind::Primary, ""});
180
181 diags.append(std::move(diag));
182 if (severity == Diagnostic_Severity::Warning)
183 ++warnings;
184 else if (severity == Diagnostic_Severity::Error
185 or severity == Diagnostic_Severity::Fatal)
186 ++errors;
187
188 return diags.size() - 1;
189 }
190
191 const Diagnostic_Label *
192 first_primary_label(const Diagnostic & diag) const noexcept
193 {
194 for (size_t i = 0; i < diag.labels.size(); ++i)
195 {
196 const auto & label = diag.labels.access(i);
197 if (label.kind == Diagnostic_Label_Kind::Primary and label.span.is_valid())
198 return &label;
199 }
200
201 for (size_t i = 0; i < diag.labels.size(); ++i)
202 {
203 const auto & label = diag.labels.access(i);
204 if (label.span.is_valid())
205 return &label;
206 }
207
208 return nullptr;
209 }
210
211 void render_label_snippet(std::ostream & out,
212 const Diagnostic_Label & label) const
213 {
214 if (not label.span.is_valid())
215 return;
216
217 const auto pos = sources->begin_position(label.span);
218 const auto snip = sources->snippet(label.span);
219
220 out << " --> " << pos.to_string() << '\n';
221
222 std::ostringstream ln;
223 ln << snip.line;
224 const std::string line_no = ln.str();
225
226 out << " " << line_no << " | " << snip.line_text << '\n';
227 out << " " << std::string(line_no.size(), ' ') << " | ";
228 out << std::string(snip.highlight_column > 1 ? snip.highlight_column - 1 : 0, ' ');
229 out << '^';
230 for (size_t i = 1; i < snip.highlight_width; ++i)
231 out << '~';
232 if (not label.message.empty())
233 out << " " << label.message;
234 out << '\n';
235 }
236
237 void render_secondary_labels(std::ostream & out,
238 const Diagnostic & diag) const
239 {
240 for (size_t i = 0; i < diag.labels.size(); ++i)
241 {
242 const auto & label = diag.labels.access(i);
243 if (label.kind != Diagnostic_Label_Kind::Secondary)
244 continue;
245
246 out << " = related";
247 if (label.span.is_valid())
248 out << ": " << sources->begin_position(label.span).to_string();
249 if (not label.message.empty())
250 out << ": " << label.message;
251 out << '\n';
252 }
253 }
254
255 public:
258 : sources(&sm)
259 {}
260
262 Diagnostic_Builder error(const Source_Span & span, const std::string & msg)
263 {
264 return Diagnostic_Builder(*this,
266 span, msg));
267 }
268
270 Diagnostic_Builder warning(const Source_Span & span, const std::string & msg)
271 {
272 return Diagnostic_Builder(*this,
274 span, msg));
275 }
276
278 Diagnostic_Builder fatal(const Source_Span & span, const std::string & msg)
279 {
280 return Diagnostic_Builder(*this,
282 span, msg));
283 }
284
286 Diagnostic_Builder note(const Source_Span & span, const std::string & msg)
287 {
288 return Diagnostic_Builder(*this,
290 span, msg));
291 }
292
294 const Diagnostic & get(const size_t i) const
295 {
297 << "Diagnostic_Engine::get(): invalid index " << i;
298 return diags.access(i);
299 }
300
303 {
304 return diags.size();
305 }
306
309 {
310 return errors;
311 }
312
315 {
316 return warnings;
317 }
318
321 {
322 return errors > 0;
323 }
324
327 {
328 diags.clear();
329 errors = 0;
330 warnings = 0;
331 }
332
334 void render_plain(std::ostream & out) const
335 {
336 for (size_t i = 0; i < diags.size(); ++i)
337 {
338 const auto & diag = diags.access(i);
339 out << severity_string(diag.severity);
340 if (not diag.code.empty())
341 out << "[" << diag.code << "]";
342 out << ": " << diag.message << '\n';
343
344 if (const auto * primary = first_primary_label(diag);
345 primary != nullptr)
346 render_label_snippet(out, *primary);
347
349
350 for (size_t j = 0; j < diag.notes.size(); ++j)
351 out << " = note: " << diag.notes.access(j) << '\n';
352
353 for (size_t j = 0; j < diag.help.size(); ++j)
354 out << " = help: " << diag.help.access(j) << '\n';
355
356 if (i + 1 < diags.size())
357 out << '\n';
358 }
359 }
360
361 friend class Diagnostic_Builder;
362 };
363
364 inline Diagnostic &
366 {
368 << "Diagnostic_Builder: detached builder";
369 return engine->diags.access(diag_index);
370 }
371
372 inline Diagnostic_Builder &
373 Diagnostic_Builder::code(const std::string & value)
374 {
375 diag().code = value;
376 return *this;
377 }
378
379 inline Diagnostic_Builder &
380 Diagnostic_Builder::primary(const Source_Span & span, const std::string & msg)
381 {
382 diag().labels.append({span, Diagnostic_Label_Kind::Primary, msg});
383 return *this;
384 }
385
386 inline Diagnostic_Builder &
387 Diagnostic_Builder::secondary(const Source_Span & span, const std::string & msg)
388 {
389 diag().labels.append({span, Diagnostic_Label_Kind::Secondary, msg});
390 return *this;
391 }
392
393 inline Diagnostic_Builder &
394 Diagnostic_Builder::note(const std::string & msg)
395 {
396 diag().notes.append(msg);
397 return *this;
398 }
399
400 inline Diagnostic_Builder &
401 Diagnostic_Builder::help(const std::string & msg)
402 {
403 diag().help.append(msg);
404 return *this;
405 }
406}
407
408# endif // AH_DIAGNOSTICS_H
#define ah_runtime_error_unless(C)
Throws std::runtime_error if condition does NOT hold.
Definition ah-errors.H:255
#define ah_out_of_range_error_unless(C)
Throws std::out_of_range if condition does NOT hold.
Definition ah-errors.H:600
Source file and span management utilities for compiler-style tooling.
size_t size_t int32_t value
Definition ca-c-api.h:116
size_t size_t int32_t * out
Definition ca-c-api.h:120
Fluent builder used to enrich a just-created diagnostic.
Diagnostic_Engine * engine
Diagnostic_Builder & code(const std::string &value)
Sets the stable diagnostic code.
Diagnostic_Builder(Diagnostic_Engine &engine, const size_t index) noexcept
Constructs a builder bound to engine[index].
size_t emit() const noexcept
Finalizes the builder and returns the diagnostic index.
Diagnostic_Builder & help(const std::string &msg)
Appends a help line.
Diagnostic_Builder & secondary(const Source_Span &span, const std::string &msg)
Adds a secondary label.
Diagnostic_Builder & primary(const Source_Span &span, const std::string &msg="")
Adds a primary label.
Diagnostic_Builder & note(const std::string &msg)
Appends a note line.
Diagnostic accumulator and renderer.
size_t warning_count() const noexcept
Returns the number of warnings.
void clear() noexcept
Removes all accumulated diagnostics and resets counters.
size_t append_diagnostic(const Diagnostic_Severity severity, const Source_Span &span, const std::string &msg)
Diagnostic_Engine(const Source_Manager &sm) noexcept
Constructs an engine bound to sm.
void render_plain(std::ostream &out) const
Renders all diagnostics as deterministic plain text.
bool has_errors() const noexcept
Returns whether any error or fatal diagnostic was emitted.
const Diagnostic_Label * first_primary_label(const Diagnostic &diag) const noexcept
const Source_Manager * sources
Diagnostic_Builder fatal(const Source_Span &span, const std::string &msg)
Starts a fatal diagnostic.
Diagnostic_Builder warning(const Source_Span &span, const std::string &msg)
Starts a warning diagnostic.
DynArray< Diagnostic > diags
const Diagnostic & get(const size_t i) const
Returns diagnostic i.
size_t error_count() const noexcept
Returns the number of error and fatal diagnostics.
Diagnostic_Builder note(const Source_Span &span, const std::string &msg)
Starts a note diagnostic.
void render_secondary_labels(std::ostream &out, const Diagnostic &diag) const
Diagnostic_Builder error(const Source_Span &span, const std::string &msg)
Starts an error diagnostic.
void render_label_snippet(std::ostream &out, const Diagnostic_Label &label) const
size_t size() const noexcept
Returns the number of stored diagnostics.
static const char * severity_string(const Diagnostic_Severity severity)
T & append()
Allocate a new entry to the end of array.
Stores source files and resolves offsets into human-readable data.
Definition ah-source.H:184
Source_Snippet snippet(const Source_Span &span) const
Builds a single-line diagnostic snippet from span.
Definition ah-source.H:383
Source_Position begin_position(const Source_Span &span) const
Resolves the begin of span to a concrete source position.
Definition ah-source.H:347
size_t blossom_maximum_cardinality_matching(const GT &g, DynDlist< typename GT::Arc * > &matching, SA sa=SA())
Alias of compute_maximum_cardinality_general_matching().
Definition Blossom.H:466
Main namespace for Aleph-w library functions.
Definition ah-arena.H:89
and
Check uniqueness with explicit hash + equality functors.
Diagnostic_Label_Kind
Kind of source label attached to a diagnostic.
Diagnostic_Severity
Severity level of a diagnostic message.
Span annotation attached to a diagnostic.
Diagnostic_Label_Kind kind
Label role.
Source_Span span
Highlighted region.
std::string message
Optional label-specific message.
Fully accumulated diagnostic.
std::string code
Optional stable code such as E001.
DynArray< Diagnostic_Label > labels
Source annotations.
Diagnostic_Severity severity
Severity level.
std::string message
Main headline message.
DynArray< std::string > help
Suggested next actions.
DynArray< std::string > notes
Additional notes.
std::string to_string() const
Formats the position as file:line:column or line:column.
Definition ah-source.H:84
size_t line
1-based line number.
Definition ah-source.H:166
Half-open byte range inside a source file.
Definition ah-source.H:100
bool is_valid() const noexcept
Returns whether the span belongs to a registered file.
Definition ah-source.H:106
Lazy and scalable dynamic array implementation.