report_error.hpp
Go to the documentation of this file.
1 // Copyright (C) 2020-2023 Jonathan Müller and lexy contributors
2 // SPDX-License-Identifier: BSL-1.0
3 
4 #ifndef LEXY_EXT_REPORT_ERROR_HPP_INCLUDED
5 #define LEXY_EXT_REPORT_ERROR_HPP_INCLUDED
6 
7 #include <cstdio>
9 #include <lexy/error.hpp>
10 #include <lexy/input_location.hpp>
11 #include <lexy/visualize.hpp>
12 
13 namespace lexy_ext
14 {
16 enum class diagnostic_kind
17 {
18  error,
19  warning,
20  note,
21  info,
22  debug,
23  fixit,
24  help,
25 };
26 
28 enum class annotation_kind
29 {
30  // foo
31  // ^^^ primary annotation
32  primary,
33  // bar
34  // ~~~ secondary annotation
35  secondary,
36 };
37 
39 template <typename Input>
41 {
42 public:
43  explicit diagnostic_writer(const Input& input, lexy::visualization_options opts = {})
44  : _input(&input), _opts(opts)
45  {}
46 
47  //=== writers ===//
51  template <typename OutputIt, typename Writer>
52  OutputIt write_message(OutputIt out, diagnostic_kind kind, const Writer& message) const
53  {
54  using namespace lexy::_detail;
55  using lexy::_detail::color; // clang-cl bug
56 
57  switch (kind)
58  {
60  out = write_color<color::red, color::bold>(out, _opts);
61  out = write_str(out, "error: ");
62  break;
64  out = write_color<color::yellow, color::bold>(out, _opts);
65  out = write_str(out, " warn: ");
66  break;
68  out = write_color<color::bold>(out, _opts);
69  out = write_str(out, " note: ");
70  break;
72  out = write_color<color::bold>(out, _opts);
73  out = write_str(out, " info: ");
74  break;
76  out = write_color<color::bold>(out, _opts);
77  out = write_str(out, "debug: ");
78  break;
80  out = write_color<color::bold>(out, _opts);
81  out = write_str(out, "fixit: ");
82  break;
84  out = write_color<color::bold>(out, _opts);
85  out = write_str(out, " help: ");
86  break;
87  }
88  out = write_color<color::reset>(out, _opts);
89 
90  out = message(out, _opts);
91  *out++ = '\n';
92 
93  return out;
94  }
95 
97  template <typename OutputIt>
98  OutputIt write_path(OutputIt out, const char* path) const
99  {
100  using namespace lexy::_detail;
101  using lexy::_detail::color; // clang-cl bug
102 
103  out = write_color<color::blue>(out, _opts);
104  out = write_str(out, path);
105  out = write_color<color::reset>(out, _opts);
106  *out++ = '\n';
107  return out;
108  }
109 
113  template <typename OutputIt>
114  OutputIt write_empty_annotation(OutputIt out) const
115  {
116  using namespace lexy::_detail;
117  using lexy::_detail::color; // clang-cl bug
118 
119  out = write_str(out, " ");
120  out = write_str(out, column());
121  *out++ = '\n';
122  return out;
123  }
124 
129  template <typename OutputIt, typename Location, typename IteratorOrSize, typename Writer>
130  OutputIt write_annotation(OutputIt out, annotation_kind kind, const Location& begin_location,
131  IteratorOrSize end, const Writer& message) const
132  {
133  using namespace lexy::_detail;
134  using lexy::_detail::color; // clang-cl bug
135 
136  auto line = lexy::get_input_line_annotation(*_input, begin_location, end);
137  // If we had to truncate the annotation but don't include the newline,
138  // this is a "multiline" annotation in the last line.
139  auto annotate_eof = line.truncated_multiline && !line.annotated_newline;
140 
141  //=== Line with file contents ===//
142  // Location column.
143  out = write_color<color::blue>(out, _opts);
144  out = write_format(out, "%4zd ", begin_location.line_nr());
145  out = write_color<color::reset>(out, _opts);
146  out = write_str(out, column());
147  *out++ = ' ';
148 
149  // Print before underlined normally.
150  out = lexy::visualize_to(out, line.before, _opts);
151 
152  // Print underlined colored.
153  out = colorize_underline(out, kind);
154  out = lexy::visualize_to(out, line.annotated, _opts.reset(lexy::visualize_use_color));
155  out = write_color<color::reset>(out, _opts);
156 
157  // Print after underlined normally.
158  out = lexy::visualize_to(out, line.after, _opts);
159  *out++ = '\n';
160 
161  //=== Line with annotation ===//
162  // Initial column.
163  out = write_str(out, " ");
164  out = write_str(out, column());
165  *out++ = ' ';
166 
167  // Indent until the underline.
168  auto indent_count = lexy::visualization_display_width(line.before, _opts);
169  for (auto i = 0u; i != indent_count; ++i)
170  *out++ = ' ';
171 
172  // Colorize.
173  out = colorize_underline(out, kind);
174 
175  // Then underline.
176  auto underline_count = lexy::visualization_display_width(line.annotated, _opts);
177  for (auto i = 0u; i != underline_count; ++i)
178  out = write_str(out, underline(kind));
179  if (underline_count == 0 || annotate_eof)
180  out = write_str(out, underline(kind));
181  *out++ = ' ';
182 
183  // Print the message.
184  out = message(out, _opts.reset(lexy::visualize_use_color));
185  *out++ = '\n';
186 
187  return write_color<color::reset>(out, _opts);
188  }
189 
190 private:
191  const auto* column() const
192  {
194  return u8"│";
195  else
196  return u8"|";
197  }
198 
199  template <typename OutputIt>
200  OutputIt colorize_underline(OutputIt out, annotation_kind kind) const
201  {
202  using namespace lexy::_detail;
203  using lexy::_detail::color; // clang-cl bug
204 
205  switch (kind)
206  {
208  return write_color<color::red, color::bold>(out, _opts);
210  return write_color<color::yellow>(out, _opts);
211  }
212 
213  return out;
214  }
215 
216  const auto* underline(annotation_kind kind) const
217  {
218  switch (kind)
219  {
221  return "^";
223  return "~";
224  }
225 
226  return "";
227  }
228 
229  const Input* _input;
231 };
232 } // namespace lexy_ext
233 
235 {
236 template <typename OutputIt, typename Input, typename Reader, typename Tag>
237 OutputIt write_error(OutputIt out, const lexy::error_context<Input>& context,
239  const char* path)
240 {
241  diagnostic_writer<Input> writer(context.input(), opts);
242 
243  // Convert the context location and error location into line/column information.
244  auto context_location = lexy::get_input_location(context.input(), context.position());
245  auto location
246  = lexy::get_input_location(context.input(), error.position(), context_location.anchor());
247 
248  // Write the main error headline.
249  out = writer.write_message(out, diagnostic_kind::error,
250  [&](OutputIt out, lexy::visualization_options) {
251  out = lexy::_detail::write_str(out, "while parsing ");
252  out = lexy::_detail::write_str(out, context.production());
253  return out;
254  });
255  if (path != nullptr)
256  out = writer.write_path(out, path);
257  out = writer.write_empty_annotation(out);
258 
259  // Write an annotation for the context.
260  if (location.line_nr() != context_location.line_nr())
261  {
262  out = writer.write_annotation(out, annotation_kind::secondary, context_location,
263  lexy::_detail::next(context.position()),
264  [&](OutputIt out, lexy::visualization_options) {
265  return lexy::_detail::write_str(out, "beginning here");
266  });
267  out = writer.write_empty_annotation(out);
268  }
269 
270  // Write the main annotation.
271  if constexpr (std::is_same_v<Tag, lexy::expected_literal>)
272  {
273  auto string = lexy::_detail::make_literal_lexeme<typename Reader::encoding>(error.string(),
274  error.length());
275 
276  out = writer.write_annotation(out, annotation_kind::primary, location, error.index() + 1,
277  [&](OutputIt out, lexy::visualization_options opts) {
278  out = lexy::_detail::write_str(out, "expected '");
279  out = lexy::visualize_to(out, string, opts);
280  out = lexy::_detail::write_str(out, "'");
281  return out;
282  });
283  }
284  else if constexpr (std::is_same_v<Tag, lexy::expected_keyword>)
285  {
286  auto string = lexy::_detail::make_literal_lexeme<typename Reader::encoding>(error.string(),
287  error.length());
288 
289  out = writer.write_annotation(out, annotation_kind::primary, location, error.end(),
290  [&](OutputIt out, lexy::visualization_options opts) {
291  out = lexy::_detail::write_str(out, "expected keyword '");
292  out = lexy::visualize_to(out, string, opts);
293  out = lexy::_detail::write_str(out, "'");
294  return out;
295  });
296  }
297  else if constexpr (std::is_same_v<Tag, lexy::expected_char_class>)
298  {
299  out = writer.write_annotation(out, annotation_kind::primary, location, 1u,
300  [&](OutputIt out, lexy::visualization_options) {
301  out = lexy::_detail::write_str(out, "expected ");
302  out = lexy::_detail::write_str(out, error.name());
303  return out;
304  });
305  }
306  else
307  {
308  out = writer.write_annotation(out, annotation_kind::primary, location, error.end(),
309  [&](OutputIt out, lexy::visualization_options) {
310  return lexy::_detail::write_str(out, error.message());
311  });
312  }
313 
314  return out;
315 }
316 } // namespace lexy_ext::_detail
317 
318 namespace lexy_ext
319 {
320 template <typename OutputIterator = int>
322 {
323  OutputIterator _iter;
325  const char* _path;
326 
327  struct _sink
328  {
329  OutputIterator _iter;
331  const char* _path;
332  std::size_t _count;
333 
334  using return_type = std::size_t;
335 
336  template <typename Input, typename Reader, typename Tag>
338  const lexy::error<Reader, Tag>& error)
339  {
340  if constexpr (std::is_same_v<OutputIterator, int>)
342  _path);
343  else
344  _iter = _detail::write_error(_iter, context, error, _opts, _path);
345  ++_count;
346  }
347 
348  std::size_t finish() &&
349  {
350  if (_count != 0)
351  std::fputs("\n", stderr);
352  return _count;
353  }
354  };
355  constexpr auto sink() const
356  {
357  return _sink{_iter, _opts, _path, 0};
358  }
359 
361  constexpr _report_error path(const char* path) const
362  {
363  return {_iter, _opts, path};
364  }
365 
367  template <typename OI>
368  constexpr _report_error<OI> to(OI out) const
369  {
370  return {out, _opts, _path};
371  }
372 
375  {
376  return {_iter, opts, _path};
377  }
378 };
379 
381 constexpr auto report_error = _report_error<>{};
382 } // namespace lexy_ext
383 
384 #endif // LEXY_EXT_REPORT_ERROR_HPP_INCLUDED
385 
lexy::_detail::color
color
Definition: visualize.hpp:120
lexy_ext::_detail
Definition: report_error.hpp:234
lexy::error_context::position
constexpr auto position() const noexcept
The starting position of the production.
Definition: error.hpp:222
lexy_ext::_report_error
Definition: report_error.hpp:321
lexy_ext::_report_error::_opts
lexy::visualization_options _opts
Definition: report_error.hpp:324
lexy::visualize_use_color
@ visualize_use_color
Visualization can use ANSI color escape sequences.
Definition: visualize.hpp:23
lexy::_detail::write_format
constexpr OutIt write_format(OutIt out, const char *fmt, const Args &... args)
Definition: visualize.hpp:109
lexy_ext::diagnostic_writer::write_annotation
OutputIt write_annotation(OutputIt out, annotation_kind kind, const Location &begin_location, IteratorOrSize end, const Writer &message) const
Definition: report_error.hpp:130
lexy::visualization_display_width
std::size_t visualization_display_width(const T &obj, visualization_options opts={})
Definition: visualize.hpp:637
lexy_ext::_report_error::_sink::_opts
lexy::visualization_options _opts
Definition: report_error.hpp:330
lexy_ext::_report_error::_iter
OutputIterator _iter
Definition: report_error.hpp:323
lexy::_detail::write_str
constexpr OutIt write_str(OutIt out, const char *str)
Definition: visualize.hpp:94
lexy_ext::diagnostic_kind
diagnostic_kind
The kind of diagnostic message.
Definition: report_error.hpp:16
lexy_ext::diagnostic_kind::warning
@ warning
lexy_ext::_report_error::_sink::_count
std::size_t _count
Definition: report_error.hpp:332
lexy_ext::diagnostic_kind::help
@ help
lexy_ext::diagnostic_writer::diagnostic_writer
diagnostic_writer(const Input &input, lexy::visualization_options opts={})
Definition: report_error.hpp:43
lexy_ext
Definition: compiler_explorer.hpp:12
lexy::visualization_options
Options that control visualization.
Definition: visualize.hpp:40
lexy_ext::_report_error::sink
constexpr auto sink() const
Definition: report_error.hpp:355
lexy::visualization_options::is_set
constexpr bool is_set(visualization_flags f) const noexcept
Definition: visualize.hpp:57
lexy::_detail::next
constexpr Iterator next(Iterator iter)
Definition: iterator.hpp:38
lexy_ext::_detail::write_error
OutputIt write_error(OutputIt out, const lexy::error_context< Input > &context, const lexy::error< Reader, Tag > &error, lexy::visualization_options opts, const char *path)
Definition: report_error.hpp:237
lexy::visualization_options::reset
constexpr visualization_options reset(visualization_flags f) const noexcept
Definition: visualize.hpp:62
lexy_ext::annotation_kind::primary
@ primary
lexy_ext::_report_error::opts
constexpr _report_error opts(lexy::visualization_options opts) const
Overrides visualization options.
Definition: report_error.hpp:374
lexy_ext::diagnostic_writer::_opts
lexy::visualization_options _opts
Definition: report_error.hpp:230
lexy::get_input_location
constexpr auto get_input_location(const Input &input, typename lexy::input_reader< Input >::iterator position, input_location_anchor< Input > anchor) -> input_location< Input, Counting >
The location for a position in the input; search starts at the anchor.
Definition: input_location.hpp:198
lexy::cfile_output_iterator
Definition: visualize.hpp:603
lexy::error_context
Contains information about the context of an error, production is type-erased.
Definition: error.hpp:198
lexy_ext::annotation_kind::secondary
@ secondary
lexy::error_context::production
const char * production() const noexcept
The name of the production where the error occurred.
Definition: error.hpp:216
lexy_ext::_report_error::_path
const char * _path
Definition: report_error.hpp:325
cx::end
constexpr auto end(const C &c) -> decltype(c.end())
Definition: wildcards.hpp:686
lexy_ext::diagnostic_writer::colorize_underline
OutputIt colorize_underline(OutputIt out, annotation_kind kind) const
Definition: report_error.hpp:200
lexy_ext::_report_error::_sink::_path
const char * _path
Definition: report_error.hpp:331
lexy::error
Generic failure.
Definition: error.hpp:14
lexy::visualize_to
OutputIt visualize_to(OutputIt out, lexy::code_point cp, visualization_options opts={})
Definition: visualize.hpp:194
lexy_ext::diagnostic_writer::write_message
OutputIt write_message(OutputIt out, diagnostic_kind kind, const Writer &message) const
Definition: report_error.hpp:52
input_location.hpp
lexy_ext::diagnostic_writer::column
const auto * column() const
Definition: report_error.hpp:191
lexy::get_input_line_annotation
constexpr auto get_input_line_annotation(const Input &input, const input_location< Input, Counting > &begin_location, typename lexy::input_reader< Input >::iterator end) -> input_line_annotation< Input >
Definition: input_location.hpp:395
lexy_ext::_report_error::_sink::return_type
std::size_t return_type
Definition: report_error.hpp:334
visualize.hpp
lexy_ext::diagnostic_writer::_input
const Input * _input
Definition: report_error.hpp:229
lexy_ext::diagnostic_kind::error
@ error
lexy_ext::_report_error::_sink
Definition: report_error.hpp:327
lexy_ext::_report_error::path
constexpr _report_error path(const char *path) const
Specifies a path that will be printed alongside the diagnostic.
Definition: report_error.hpp:361
lexy_ext::diagnostic_kind::info
@ info
assert.hpp
lexy_ext::_report_error::_sink::_iter
OutputIterator _iter
Definition: report_error.hpp:329
lexy_ext::report_error
constexpr auto report_error
An error callback that uses diagnostic_writer to print to stderr (by default).
Definition: report_error.hpp:381
lexy_ext::diagnostic_kind::fixit
@ fixit
lexy_ext::diagnostic_writer::write_path
OutputIt write_path(OutputIt out, const char *path) const
Writes a path.
Definition: report_error.hpp:98
lexy::_detail
Definition: any_ref.hpp:12
lexy_ext::diagnostic_writer::write_empty_annotation
OutputIt write_empty_annotation(OutputIt out) const
Definition: report_error.hpp:114
lexy_ext::diagnostic_writer
Formats and writes diagnostic messages.
Definition: report_error.hpp:40
lexy_ext::annotation_kind
annotation_kind
Classifies a source code annotation.
Definition: report_error.hpp:28
lexy::_detail::error
constexpr bool error
Definition: config.hpp:39
lexy::error_context::input
constexpr const auto & input() const noexcept
The input.
Definition: error.hpp:207
lexy_ext::_report_error::to
constexpr _report_error< OI > to(OI out) const
Specifies an output iterator where the errors are written to.
Definition: report_error.hpp:368
lexy::visualize_use_unicode
@ visualize_use_unicode
Visualization can use unicode characters.
Definition: visualize.hpp:21
lexy_ext::diagnostic_writer::underline
const auto * underline(annotation_kind kind) const
Definition: report_error.hpp:216
lexy_ext::_report_error::_sink::operator()
void operator()(const lexy::error_context< Input > &context, const lexy::error< Reader, Tag > &error)
Definition: report_error.hpp:337
lexy_ext::_report_error::_sink::finish
std::size_t finish() &&
Definition: report_error.hpp:348
lexy_ext::diagnostic_kind::debug
@ debug
lexy_ext::diagnostic_kind::note
@ note
error.hpp


behaviortree_cpp_v4
Author(s): Davide Faconti
autogenerated on Fri Jun 28 2024 02:20:08