rapidyaml  0.12.1
parse and emit YAML, and do it fast
error.def.hpp
Go to the documentation of this file.
1 #ifndef _C4_YML_ERROR_DEF_HPP_
2 #define _C4_YML_ERROR_DEF_HPP_
3 
4 /** @file error.def.hpp Definitions of error utilities used by ryml. */
5 
6 #ifndef _C4_YML_ERROR_HPP_
7 #include <c4/yml/error.hpp>
8 #endif
9 
10 // NOLINTBEGIN(bugprone-use-after-move,hicpp-invalid-access-moved)
11 
12 namespace c4 {
13 namespace yml {
14 
15 template<class DumpFn>
16 C4_NO_INLINE size_t location_format(DumpFn &&dumpfn, Location const& loc)
17 {
18  if(!loc)
19  return 0;
20  char buf_[32];
21  substr buf(buf_);
22  size_t count = 0;
23  if(!loc.name.empty())
24  {
25  std::forward<DumpFn>(dumpfn)(loc.name);
26  std::forward<DumpFn>(dumpfn)(":");
27  count += loc.name.len + 1;
28  }
29  if(loc.line != npos)
30  {
31  csubstr val = detail::_to_chars_limited(buf, loc.line);
32  if(loc.name.empty())
33  {
34  std::forward<DumpFn>(dumpfn)("line=");
35  std::forward<DumpFn>(dumpfn)(val);
36  if(loc.col == npos)
37  {
38  std::forward<DumpFn>(dumpfn)(":");
39  ++count;
40  }
41  count += val.len + 5;
42  }
43  else
44  {
45  std::forward<DumpFn>(dumpfn)(val);
46  std::forward<DumpFn>(dumpfn)(":");
47  count += val.len + 1;
48  }
49  }
50  if(loc.col != npos)
51  {
52  csubstr val = detail::_to_chars_limited(buf, loc.col);
53  if(loc.line != npos || !loc.name.empty())
54  {
55  std::forward<DumpFn>(dumpfn)(" ");
56  ++count;
57  }
58  std::forward<DumpFn>(dumpfn)("col=");
59  std::forward<DumpFn>(dumpfn)(val);
60  count += val.len + 4;
61  if(loc.offset == npos)
62  {
63  std::forward<DumpFn>(dumpfn)(":");
64  ++count;
65  }
66  }
67  if(loc.offset != npos)
68  {
69  csubstr val = detail::_to_chars_limited(buf, loc.offset);
70  if(loc.line != npos || loc.col != npos || !loc.name.empty())
71  {
72  std::forward<DumpFn>(dumpfn)(" ");
73  ++count;
74  }
75  std::forward<DumpFn>(dumpfn)("(");
76  std::forward<DumpFn>(dumpfn)(val);
77  std::forward<DumpFn>(dumpfn)("B):");
78  count += val.len + 5;
79  }
80  return count;
81 }
82 
83 template<class DumpFn>
84 C4_NO_INLINE void location_format_with_context(DumpFn &&dumpfn,
85  Location const &location,
86  csubstr source_buffer,
87  csubstr call,
88  size_t num_lines_before,
89  size_t num_lines_after,
90  size_t first_col_highlight,
91  size_t last_col_highlight,
92  size_t maxlen)
93 {
94  if(!location)
95  return;
96  char buf_[32];
97  substr buf(buf_);
98  auto pr = [&](csubstr s){ std::forward<DumpFn>(dumpfn)(s); };
99  auto prn = [&](csubstr s, size_t num_times){
100  for(size_t i = 0; i < num_times; ++i)
101  std::forward<DumpFn>(dumpfn)(s);
102  };
103  csubstr line = detail::_get_text_region(source_buffer, location.offset, 0, 0);
104  size_t target_col = location.col != npos ? location.col : (last_col_highlight > first_col_highlight ? first_col_highlight : npos);
105  size_t first_col_to_show = 0;
106  if(target_col != npos && target_col > maxlen)
107  first_col_to_show = target_col - maxlen + 1;
108  auto print_line_maybe_truncated = [&](csubstr contents){
109  if(contents.len <= maxlen)
110  {
111  if(first_col_to_show == 0)
112  {
113  pr(contents);
114  }
115  else if(first_col_to_show < contents.len)
116  {
117  csubstr show = contents.sub(first_col_to_show);
118  pr("[...]");
119  pr(show);
120  if(maxlen > show.len)
121  prn(" ", maxlen - show.len + 5);
122  pr(" (showing columns ");
123  pr(detail::_to_chars_limited(buf, first_col_to_show));
124  pr("-");
125  pr(detail::_to_chars_limited(buf, contents.len));
126  pr("/");
127  pr(detail::_to_chars_limited(buf, contents.len));
128  pr(")");
129  }
130  else
131  {
132  pr("[...]");
133  prn(" ", maxlen + 5);
134  pr(" (not showing, columns=");
135  pr(detail::_to_chars_limited(buf, contents.len));
136  pr(")");
137  }
138  }
139  else
140  {
141  if(first_col_to_show == 0)
142  {
143  csubstr show = contents.first(maxlen);
144  pr(show);
145  pr("[...] (showing columns 0-");
146  pr(detail::_to_chars_limited(buf, show.len));
147  pr("/");
148  pr(detail::_to_chars_limited(buf, contents.len));
149  pr(")");
150  }
151  else if(first_col_to_show < contents.len && first_col_to_show + maxlen <= contents.len)
152  {
153  csubstr show = contents.sub(first_col_to_show, maxlen);
154  pr("[...]");
155  pr(show);
156  pr("[...] (showing columns ");
157  pr(detail::_to_chars_limited(buf, first_col_to_show));
158  pr("-");
159  pr(detail::_to_chars_limited(buf, first_col_to_show + maxlen));
160  pr("/");
161  pr(detail::_to_chars_limited(buf, contents.len));
162  pr(")");
163  }
164  else if(first_col_to_show < contents.len)
165  {
166  csubstr show = contents.sub(first_col_to_show);
167  pr("[...]");
168  pr(show);
169  if(maxlen > show.len)
170  prn(" ", maxlen - show.len + 5);
171  pr(" (showing columns ");
172  pr(detail::_to_chars_limited(buf, first_col_to_show));
173  pr("-");
174  pr(detail::_to_chars_limited(buf, contents.len));
175  pr("/");
176  pr(detail::_to_chars_limited(buf, contents.len));
177  pr(")");
178  }
179  else
180  {
181  pr("[...]");
182  prn(" ", maxlen + 5);
183  pr(" (not showing, columns=");
184  pr(detail::_to_chars_limited(buf, contents.len));
185  pr(")");
186  }
187  }
188  };
189  // print the location, and compute how many cols it took
190  size_t locsize = location_format(pr, location);
191  // print line
192  if(locsize)
193  {
194  pr(" ");
195  //++locsize;
196  }
197  auto print_call = [&](csubstr after){
198  pr(call);
199  pr(":");
200  if(after.len)
201  pr(after);
202  };
203  size_t jump;
204  if(call.empty())
205  {
206  print_line_maybe_truncated(line);
207  pr("\n");
208  jump = locsize + location.col - first_col_to_show;
209  }
210  else
211  {
212  print_call("\n");
213  print_call("\n");
214  print_call(" ");
215  pr(" ");
216  print_line_maybe_truncated(line);
217  pr("\n");
218  jump = call.len + 2;
219  }
220  // when skipping to the first col, add 5 to adjust for the [...]
221  // leading the line as shown
222  const size_t first_col_jump = first_col_to_show == 0 ? 0 : 5;
223  // print a cursor pointing at the column on the previous printed line
224  auto print_cursor = [&](size_t nocall_jump){
225  if(location.offset == npos)
226  return;
227  if(call.empty())
228  {
229  if(nocall_jump != npos)
230  {
231  prn(" ", nocall_jump + first_col_jump);
232  pr("|\n");
233  prn(" ", nocall_jump + first_col_jump);
234  pr("(here)\n");
235  }
236  }
237  else if(location.col != npos)
238  {
239  print_call(" ");
240  pr(" ");
241  prn(" ", location.col - first_col_to_show + first_col_jump);
242  pr("|\n");
243  print_call(" ");
244  pr(" ");
245  prn(" ", location.col - first_col_to_show + first_col_jump);
246  pr("(here)\n");
247  }
248  };
249  // maybe highlighted zone
250  size_t firstcol = first_col_highlight < line.len ? first_col_highlight : line.len;
251  size_t lastcol = last_col_highlight < line.len ? last_col_highlight : line.len;
252  firstcol = firstcol < maxlen ? firstcol : maxlen;
253  lastcol = lastcol < maxlen ? lastcol : maxlen;
254  if(firstcol < lastcol)
255  {
256  if(!call.empty())
257  {
258  print_call(" ");
259  pr(" ");
260  }
261  else
262  {
263  for(size_t i = 0; i < locsize + firstcol; ++i)
264  pr(" ");
265  }
266  for(size_t i = locsize + firstcol; i < locsize + lastcol; ++i)
267  pr("~");
268  pr(" (cols ");
269  pr(detail::_to_chars_limited(buf, firstcol));
270  pr("-");
271  pr(detail::_to_chars_limited(buf, lastcol));
272  pr("/");
273  pr(detail::_to_chars_limited(buf, line.len));
274  pr(")\n");
275  }
276  if(location.col != npos)
277  {
278  print_cursor(jump);
279  }
280  // maybe print the region
281  if(num_lines_before || num_lines_after)
282  {
283  if(!call.empty())
284  {
285  print_call("\n");
286  print_call(" ");
287  pr("see region:\n");
288  print_call("\n");
289  }
290  else
291  {
292  if(location)
293  {
294  location_format(pr, location);
295  pr(" ");
296  }
297  pr("see region:\n");
298  }
299  csubstr region = detail::_get_text_region(source_buffer, location.offset, num_lines_before, num_lines_after);
300  for(csubstr contents : region.split('\n'))
301  {
302  if(!call.empty())
303  {
304  print_call(" ");
305  }
306  print_line_maybe_truncated(contents);
307  pr("\n");
308  }
309  assert(location.col == npos || location.col >= first_col_to_show);
310  print_cursor(location.col - first_col_to_show);
311  }
312 }
313 
314 
315 template<class DumpFn>
316 C4_NO_INLINE void err_basic_format(DumpFn &&dumpfn, csubstr msg, ErrorDataBasic const& errdata)
317 {
318  if(errdata.location)
319  {
320  location_format(dumpfn, errdata.location);
321  std::forward<DumpFn>(dumpfn)(" ");
322  }
323  std::forward<DumpFn>(dumpfn)("ERROR: [basic] ");
324  std::forward<DumpFn>(dumpfn)(msg);
325 }
326 
327 
328 template<class DumpFn>
329 C4_NO_INLINE void err_parse_format(DumpFn &&dumpfn, csubstr msg, ErrorDataParse const& errdata)
330 {
331  if(errdata.ymlloc)
332  {
333  location_format(std::forward<DumpFn>(dumpfn), errdata.ymlloc);
334  std::forward<DumpFn>(dumpfn)(" ");
335  }
336  std::forward<DumpFn>(dumpfn)("ERROR: [parse] ");
337  std::forward<DumpFn>(dumpfn)(msg);
338  if(errdata.cpploc)
339  {
340  std::forward<DumpFn>(dumpfn)("\n");
341  location_format(std::forward<DumpFn>(dumpfn), errdata.cpploc);
342  std::forward<DumpFn>(dumpfn)(" (detected here)");
343  }
344 }
345 
346 
347 template<class DumpFn>
348 C4_NO_INLINE void err_visit_format(DumpFn &&dumpfn, csubstr msg, ErrorDataVisit const& errdata)
349 {
350  char buf_[32];
351  substr buf(buf_);
352  if(errdata.cpploc)
353  {
354  location_format(dumpfn, errdata.cpploc);
355  std::forward<DumpFn>(dumpfn)(" ");
356  }
357  std::forward<DumpFn>(dumpfn)("ERROR: [visit] ");
358  std::forward<DumpFn>(dumpfn)(msg);
359  if(errdata.node != NONE && errdata.tree != nullptr)
360  {
361  if(errdata.cpploc)
362  {
363  std::forward<DumpFn>(dumpfn)("\n");
364  location_format(dumpfn, errdata.cpploc);
365  std::forward<DumpFn>(dumpfn)(" ");
366  }
367  std::forward<DumpFn>(dumpfn)("ERROR: (");
368  if(errdata.node != NONE)
369  {
370  std::forward<DumpFn>(dumpfn)("node=");
371  std::forward<DumpFn>(dumpfn)(detail::_to_chars_limited(buf, errdata.node));
372  if(errdata.tree != nullptr)
373  std::forward<DumpFn>(dumpfn)(" ");
374  }
375  if(errdata.tree != nullptr)
376  {
377  std::forward<DumpFn>(dumpfn)("tree=");
378  std::forward<DumpFn>(dumpfn)(detail::_to_chars_limited(buf, static_cast<void const*>(errdata.tree)));
379  }
380  std::forward<DumpFn>(dumpfn)(")");
381  }
382 }
383 
384 } // namespace yml
385 } // namespace c4
386 
387 // NOLINTEND(bugprone-use-after-move,hicpp-invalid-access-moved)
388 
389 #endif /* _C4_YML_ERROR_HPP_ */
Error utilities used by ryml.
size_t location_format(DumpFn &&dumpfn, Location const &loc)
generic formatting of a location
Definition: error.def.hpp:16
void err_visit_format(DumpFn &&dumpfn, csubstr msg, ErrorDataVisit const &errdata)
Given an error message and associated visit error data, format it fully as a visit error message.
Definition: error.def.hpp:348
void location_format_with_context(DumpFn &&dumpfn, Location const &location, csubstr source_buffer, csubstr call, size_t num_lines_before, size_t num_lines_after, size_t first_col_highlight, size_t last_col_highlight, size_t maxlen)
Generic formatting of a location, printing the source code buffer region around the location.
Definition: error.def.hpp:84
void err_basic_format(DumpFn &&dumpfn, csubstr msg, ErrorDataBasic const &errdata)
Given an error message and associated basic error data, format it fully as a basic error message.
Definition: error.def.hpp:316
void err_parse_format(DumpFn &&dumpfn, csubstr msg, ErrorDataParse const &errdata)
Given an error message and associated parse error data, format it fully as a parse error message.
Definition: error.def.hpp:329
csubstr _get_text_region(csubstr text, size_t pos, size_t num_lines_before, size_t num_lines_after)
Definition: common.cpp:283
@ npos
a null string position
Definition: common.hpp:258
@ NONE
an index to none
Definition: common.hpp:251
(Undefined by default) Use shorter error message from checks/asserts: do not show the check condition...
Definition: common.cpp:14
Data for a basic error.
Definition: common.hpp:312
Location location
location where the error was detected (may be from YAML or C++ source code)
Definition: common.hpp:313
Data for a parse error.
Definition: common.hpp:321
Location cpploc
location in the C++ source file where the error was detected.
Definition: common.hpp:322
Location ymlloc
location in the YAML source buffer where the error was detected.
Definition: common.hpp:323
Data for a visit error.
Definition: common.hpp:331
Location cpploc
location in the C++ source file where the error was detected.
Definition: common.hpp:332
Tree const * tree
tree where the error was detected
Definition: common.hpp:333
id_type node
node where the error was detected
Definition: common.hpp:334
holds a source or yaml file position, for example when an error is detected; See also location_format...
Definition: common.hpp:283
size_t col
column
Definition: common.hpp:286
size_t line
line
Definition: common.hpp:285
size_t offset
number of bytes from the beginning of the source buffer
Definition: common.hpp:284
csubstr name
name of the file
Definition: common.hpp:287