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