rapidyaml 0.14.0
parse and emit YAML, and do it fast
Loading...
Searching...
No Matches
error.hpp
Go to the documentation of this file.
1#ifndef _C4_YML_ERROR_HPP_
2#define _C4_YML_ERROR_HPP_
3
4/** @file error.hpp Error utilities used by ryml. */
5
6#ifndef _C4_YML_COMMON_HPP_
7#include <c4/yml/common.hpp>
8#endif
9
10#include <cstdlib>
11
12/// @cond dev
13#if (defined(C4_EXCEPTIONS) && (!defined(RYML_NO_DEFAULT_CALLBACKS) && defined(RYML_DEFAULT_CALLBACK_USES_EXCEPTIONS))) || defined(__DOXYGEN__)
14#define _RYML_WITH_EXCEPTIONS
15#endif
16#if defined(RYML_DBG) && !defined(NDEBUG) && !defined(C4_NO_DEBUG_BREAK)
17# define RYML_DEBUG_BREAK() \
18 do { \
19 if(c4::get_error_flags() & c4::ON_ERROR_DEBUGBREAK) \
20 { \
21 C4_DEBUG_BREAK(); \
22 } \
23 } while(false)
24#else
25# define RYML_DEBUG_BREAK()
26#endif
27/// @endcond
28
29#ifdef _RYML_WITH_EXCEPTIONS
30#include <exception>
31#endif
32
33
34namespace c4 {
35namespace yml {
36
37
38/// @cond dev
39
40namespace detail {
41struct _SubstrWriter
42{
43 substr buf;
44 size_t pos;
45 _SubstrWriter(substr buf_, size_t pos_=0) : buf(buf_), pos(pos_) { C4_ASSERT(buf.str); }
46 void append(csubstr s)
47 {
48 C4_ASSERT(!s.overlaps(buf));
49 C4_ASSERT(s.str || !s.len);
50 if(s.len && pos + s.len <= buf.len)
51 {
52 C4_ASSERT(s.str);
53 memcpy(buf.str + pos, s.str, s.len);
54 }
55 pos += s.len;
56 }
57 void append(char c)
58 {
59 C4_ASSERT(buf.str);
60 if(pos < buf.len)
61 buf.str[pos] = c;
62 ++pos;
63 }
64 void append_n(char c, size_t numtimes)
65 {
66 C4_ASSERT(buf.str);
67 if(numtimes && pos + numtimes < buf.len)
68 memset(buf.str + pos, c, numtimes);
69 pos += numtimes;
70 }
71 size_t slack() const { return pos <= buf.len ? buf.len - pos : 0; }
72 size_t excess() const { return pos > buf.len ? pos - buf.len : 0; }
73 //! get the part written so far
74 csubstr curr() const { return pos <= buf.len ? buf.first(pos) : buf; }
75 //! get the part that is still free to write to (the remainder)
76 substr rem() const { return pos < buf.len ? buf.sub(pos) : buf.last(0); }
77
78 size_t advance(size_t more) { pos += more; return pos; }
79};
80
81
82// truncate the result to the buffer, adding ellipsis if it
83// doesn't fit
84inline C4_NO_INLINE csubstr _maybe_add_ellipsis(substr buf, size_t len)
85{
86 if(C4_UNLIKELY(len > buf.len))
87 {
88 const size_t numdots = (buf.len > 3) ? 3 : buf.len;
89 buf.last(numdots).fill('.');
90 len = buf.len;
91 }
92 return buf.first(len);
93}
94
95
96// std::remove_cvref appeared in c++20
97template<class T>
98struct _remove_cvref
99{
100 using type = typename std::remove_cv<typename std::remove_reference<T>::type>::type;
101};
102template<class T>
103struct _dump_directly : public c4::is_string<typename _remove_cvref<T>::type>
104{
105};
106
107
108#if C4_CPP >= 17
109template<class T> using _remove_cvref_t = typename _remove_cvref<T>::type;
110template<class T> using _dump_directly_v = typename _dump_directly<T>::value;
111template<class T>
112C4_NO_INLINE csubstr _to_chars_limited(substr buf, T &&var)
113{
114 if constexpr (_dump_directly<T>::value)
115 {
116 (void)buf;
117 return to_csubstr(std::forward<T>(var)); // no need to convert to buf
118 }
119 else
120 {
121 size_t len = to_chars(buf, std::forward<T>(var));
122 return _maybe_add_ellipsis(buf, len);
123 }
124}
125#else
126template<class T>
127C4_NO_INLINE auto _to_chars_limited(substr, T &&var)
128 -> typename std::enable_if<_dump_directly<T>::value, csubstr>::type
129{
130 return to_csubstr(std::forward<T>(var)); // no need to convert to buf
131}
132template<class T>
133C4_NO_INLINE auto _to_chars_limited(substr buf, T &&var)
134 -> typename std::enable_if< ! _dump_directly<T>::value, csubstr>::type
135{
136 size_t len = to_chars(buf, std::forward<T>(var));
137 return _maybe_add_ellipsis(buf, len);
138}
139#endif
140
141
142// dumpfn is a function abstracting prints to terminal (or to string).
143template<class DumpFn>
144C4_NO_INLINE void _dump(DumpFn &&dumpfn, substr, csubstr fmt)
145{
146 std::forward<DumpFn>(dumpfn)(fmt);
147}
148template<class DumpFn, class Arg, class ...Args>
149C4_NO_INLINE void _dump(DumpFn &&dumpfn, substr argbuf, csubstr fmt, Arg const& arg, Args const& ...more)
150{
151 size_t pos = fmt.find("{}");
152 if(pos == csubstr::npos)
153 return std::forward<DumpFn>(dumpfn)(fmt); // NOLINT // LCOV_EXCL_LINE
154 std::forward<DumpFn>(dumpfn)(fmt.first(pos)); // NOLINT
155 std::forward<DumpFn>(dumpfn)(_to_chars_limited(argbuf, arg)); // NOLINT
156 _dump(std::forward<DumpFn>(dumpfn), argbuf, fmt.sub(pos + 2), more...); // NOLINT
157}
158
159
160template<class ...Args>
161C4_NO_INLINE csubstr _mk_err_msg(substr buf, csubstr fmt, Args const& ...args)
162{
163 detail::_SubstrWriter writer(buf);
164 auto dumpfn = [&writer](csubstr s){ writer.append(s); };
165 char writebuf[RYML_LOGBUF_SIZE];
166 _dump(dumpfn, writebuf, fmt, args...);
167 return _maybe_add_ellipsis(buf, writer.pos);
168}
169
170RYML_EXPORT csubstr _get_text_region(csubstr text, size_t pos, size_t num_lines_before, size_t num_lines_after);
171
172} // namespace detail
173
174/// @endcond
175
176
177//-----------------------------------------------------------------------------
178//-----------------------------------------------------------------------------
179//-----------------------------------------------------------------------------
180
181/** @addtogroup doc_error_handling
182 *
183 * @{ */
184
185
186/** generic formatting of a location
187 *
188 * @param dumpfn function taking a csubstr and abstracting a string
189 * concatenation operation, such as appending to a std::string or
190 * printing to terminal.
191 * @param loc the location to be formatted
192 *
193 * For example:
194 *
195 * ```c++
196 * /// to output to std::cerr:
197 * location_format([&s](csubstr s){
198 * std::cerr.write(s.str, s.len);
199 * }, loc);
200 *
201 * /// to build a string:
202 * std::string msg;
203 * location_format([&s](csubstr s){
204 * msg.append(s.str, s.len);
205 * }, loc);
206 * ```
207 */
208template<class DumpFn>
209C4_NO_INLINE size_t location_format(DumpFn &&dumpfn, Location const& loc);
210
211
212/** Generic formatting of a location, printing the source code buffer
213 * region around the location.
214 *
215 * @param dumpfn function taking a csubstr and abstracting a string
216 * concatenation operation, such as appending to a std::string or
217 * printing to terminal.
218 * @param location the location
219 * @param source_buffer the source buffer
220 * @param call a string with a call of attention to print in the
221 * message (see examples below)
222 * @param num_lines_before how many source buffer lines to print
223 * before the location line
224 * @param num_lines_after how many source buffer lines to print
225 * after the location line
226 * @param first_col_highlight the first column to highlight
227 * around the location line
228 * @param last_col_highlight the last column to highlight
229 * around the location line
230 * @param maxlen the maximum number of columns to show in the error
231 * message; source buffer lines will have at most this number
232 * of columns shown; if the line is longer than this, the line
233 * will be trimmed as needed at the end and/or beginning, and
234 * only the relevant columns *around* the location are shown
235 *
236 * For example:
237 *
238 * ```c++
239 * std::string out;
240 * auto dumpfn = [&out](csubstr s){ out.append(s.str, s.len); };
241 * format_location_with_context(dumpfn, location, source, "error");
242 * ```
243 *
244 * will result in this string:
245 *
246 * ```
247 * file.yaml:3: col=3 (11B): error:
248 * error:
249 * error: ccc
250 * error: |
251 * error: (here)
252 * error:
253 * error: see region:
254 * error:
255 * error: aaa
256 * error: bbb
257 * error: ccc
258 * error: |
259 * error: (here)
260 * ```
261 *
262 * If an empty string is passed for the call of attention,
263 *
264 * ```c++
265 * format_location_with_context(dumpfn, location, source);
266 * ```
267 *
268 * the returned string becomes:
269 *
270 * ```
271 * file.yaml:3: col=3 (11B): ccc
272 * |
273 * (here)
274 * file.yaml:3: col=3 (11B): see region:
275 * aaa
276 * bbb
277 * ccc
278 * |
279 * (here)
280 * ```
281 */
282template<class DumpFn>
283C4_NO_INLINE void location_format_with_context(DumpFn &&dumpfn,
284 Location const &location,
285 csubstr source_buffer,
286 csubstr call = "",
287 size_t num_lines_before = 3,
288 size_t num_lines_after = 0,
289 size_t first_col_highlight = 0,
290 size_t last_col_highlight = 0,
291 size_t maxlen = 80u);
292
293
294//-----------------------------------------------------------------------------
295
296/** Given an error message and associated basic error data, format it fully as a basic error message.
297 *
298 * @param dumpfn function taking a csubstr and abstracting a string
299 * concatenation operation, such as appending to a std::string or
300 * printing to terminal.
301 * @param msg the error message
302 * @param errdata the error data
303 *
304 * For example:
305 *
306 * ```c++
307 * /// to output to cerr:
308 * err_basic_format([](csubstr s){
309 * std::cerr.write(s.str, s.len);
310 * }, errmsg, errdata);
311 *
312 * /// to build a string:
313 * std::string msg;
314 * error_basic_format([&msg](csubstr s){
315 * msg.append(s.str, s.len);
316 * }, errmsg, errdata);
317 * ```
318 */
319template<class DumpFn>
320C4_NO_INLINE void err_basic_format(DumpFn &&dumpfn, csubstr msg, ErrorDataBasic const& errdata);
321
322/** trigger a basic error to its respective handler, with a non-formatted error message. */
323C4_NORETURN RYML_EXPORT C4_NO_INLINE void err_basic(Callbacks const& callbacks, ErrorDataBasic const& errdata, const char* msg_);
324/** trigger a basic error to its respective handler, with a non-formatted error message. Like (1), but use the current global callbacks. */
325C4_NORETURN RYML_EXPORT C4_NO_INLINE void err_basic(ErrorDataBasic const& errdata, const char* msg);
326/** trigger a basic error to its respective handler, with a formatted error message. */
327template<class ...Args>
328C4_NORETURN C4_NO_INLINE void err_basic(Callbacks const& callbacks, ErrorDataBasic const& errdata, const char *fmt, Args const& ...args)
329{
330 char errbuf[RYML_ERRMSG_SIZE];
331 csubstr msg = detail::_mk_err_msg(errbuf, to_csubstr(fmt), args...);
332 callbacks.m_error_basic(msg, errdata, callbacks.m_user_data);
333 std::abort(); // the call above should not return, but force it here in case it does // LCOV_EXCL_LINE
334 C4_UNREACHABLE_AFTER_ERR();
335}
336/** trigger a basic error to its respective handler, with a formatted error message. Like (1), but use the current global callbacks. */
337template<class ...Args>
338C4_NORETURN C4_NO_INLINE void err_basic(ErrorDataBasic const& errdata, const char *fmt, Args const& ...args)
339{
340 err_basic(get_callbacks(), errdata, fmt, args...);
341 C4_UNREACHABLE_AFTER_ERR();
342}
343
344
345/** Given an error message and associated parse error data, format it fully as a parse error message.
346 *
347 * @param dumpfn function taking a csubstr and abstracting a string
348 * concatenation operation, such as appending to a std::string or
349 * printing to terminal.
350 * @param msg the error message
351 * @param errdata the error data
352 *
353 * For example:
354 *
355 * ```c++
356 * /// to output to cerr:
357 * /// this is what err_parse_print() does
358 * err_parse_format([](csubstr s){
359 * std::cerr.write(s.str, s.len);
360 * }, errmsg, errdata);
361 *
362 * /// to build a string:
363 * std::string msg;
364 * err_parse_format([](csubstr s){
365 * s.append(s.str, s.len);
366 * }, errmsg, errdata);
367 * ```
368 *
369 * @note if the (preferably original) source buffer is kept, @ref
370 * location_format_with_context() can be used to also an additional
371 * rich error message showing the YAML source buffer region around
372 * that location.
373 */
374template<class DumpFn>
375C4_NO_INLINE void err_parse_format(DumpFn &&dumpfn, csubstr msg, ErrorDataParse const& errdata);
376
377/** trigger a parse error to its respective handler, with a non-formatted error message */
378C4_NORETURN RYML_EXPORT C4_NO_INLINE void err_parse(Callbacks const& callbacks, ErrorDataParse const& errdata, const char *msg);
379/** trigger a parse error to its respective handler, with a non-formatted error message. Like (1), but use the current global callbacks. */
380C4_NORETURN RYML_EXPORT C4_NO_INLINE void err_parse(ErrorDataParse const& errdata, const char *msg);
381/** trigger a parse error to its respective handler, with a formatted error message */
382template<class ...Args>
383C4_NORETURN C4_NO_INLINE void err_parse(Callbacks const& callbacks, ErrorDataParse const& errdata, const char *fmt, Args const& ...args)
384{
385 char errbuf[RYML_ERRMSG_SIZE];
386 csubstr msg = detail::_mk_err_msg(errbuf, to_csubstr(fmt), args...);
387 if(callbacks.m_error_parse)
388 callbacks.m_error_parse(msg, errdata, callbacks.m_user_data);
389 // fall to basic error if there is no parse handler set, but use errdata.ymlloc instead of errdata.cpploc
390 else if(callbacks.m_error_basic)
391 callbacks.m_error_basic(msg, errdata.ymlloc, callbacks.m_user_data);
392 std::abort(); // the call above should not return, so force it here in case it does // LCOV_EXCL_LINE
393 C4_UNREACHABLE_AFTER_ERR();
394}
395/** trigger a parse error to its respective handler, with a formatted error message. Like (1), but use the current global callbacks. */
396template<class ...Args>
397C4_NORETURN C4_NO_INLINE void err_parse(ErrorDataParse const& errdata, const char *fmt, Args const& ...args)
398{
399 err_parse(get_callbacks(), errdata, fmt, args...);
400 C4_UNREACHABLE_AFTER_ERR();
401}
402
403
404/** Given an error message and associated visit error data, format it
405 * fully as a visit error message.
406 *
407 * @param dumpfn function taking a csubstr and abstracting a string
408 * concatenation operation, such as appending to a std::string or
409 * printing to terminal.
410 * @param msg the error message
411 * @param errdata the error data
412 *
413 * For example:
414 *
415 * ```c++
416 * /// to output to cerr:
417 * err_visit_format([](csubstr s){
418 * std::cerr.write(s.str, s.len);
419 * }, errmsg, errdata);
420 *
421 * /// to build a string:
422 * std::string msg;
423 * err_visit_format([&msg](csubstr s){
424 * msg.append(s.str, s.len);
425 * }, errmsg, errdata);
426 *
427 * @note under certain conditions, it is possible to obtain an
428 * associated location, and subsequently use @ref
429 * location_format_with_context() to also create a rich error message
430 * showing the YAML source buffer region around that location. This is
431 * possible if the (preferably original) source buffer is kept, and
432 * the node location can be retrieved from the parser.
433 * ```
434 */
435template<class DumpFn>
436C4_NO_INLINE void err_visit_format(DumpFn &&dumpfn, csubstr msg, ErrorDataVisit const& errdata);
437
438
439/** trigger a visit error to its respective handler, with a non-formatted error message */
440C4_NORETURN RYML_EXPORT C4_NO_INLINE void err_visit(Callbacks const& callbacks, ErrorDataVisit const& errdata, const char *msg);
441/** trigger a visit error to its respective handler, with a non-formatted error message. Like (1), but uses the current global callbacks. */
442C4_NORETURN RYML_EXPORT C4_NO_INLINE void err_visit(ErrorDataVisit const& errdata, const char *msg);
443/** trigger a visit error to its respective handler, with a formatted error message */
444template<class ...Args>
445C4_NORETURN C4_NO_INLINE void err_visit(Callbacks const& callbacks, ErrorDataVisit const& errdata, const char *fmt, Args const& ...args)
446{
447 char errbuf[RYML_ERRMSG_SIZE];
448 csubstr msg = detail::_mk_err_msg(errbuf, to_csubstr(fmt), args...);
449 if(callbacks.m_error_visit)
450 callbacks.m_error_visit(msg, errdata, callbacks.m_user_data);
451 // fall to basic error if there is no visit handler set
452 else if(callbacks.m_error_basic)
453 callbacks.m_error_basic(msg, errdata.cpploc, callbacks.m_user_data);
454 std::abort(); // the call above should not return, so force it here in case it does // LCOV_EXCL_LINE
455 C4_UNREACHABLE_AFTER_ERR();
456}
457/** trigger a visit error to its respective handler, with a formatted error message. Like (1), but use the current global callbacks. */
458template<class ...Args>
459C4_NORETURN C4_NO_INLINE void err_visit(ErrorDataVisit const& errdata, const char *fmt, Args const& ...args)
460{
461 err_visit(get_callbacks(), errdata, fmt, args...);
462 C4_UNREACHABLE_AFTER_ERR();
463}
464
465
466//-----------------------------------------------------------------------------
467
468#if defined(_RYML_WITH_EXCEPTIONS) || defined(__DOXYGEN__)
469
470/** Exception thrown by the default basic error implementation. To
471 * obtain the full error message, use @ref err_basic_format(), or the
472 * helper @ref format_exc().
473 *
474 * @note Available only if @ref
475 * RYML_DEFAULT_CALLBACK_USES_EXCEPTIONS is defined, and @ref
476 * RYML_NO_DEFAULT_CALLBACKS is NOT defined. */
477struct RYML_EXPORT ExceptionBasic : public std::exception
478{
479 ExceptionBasic(csubstr msg, ErrorDataBasic const& errdata_) noexcept;
480 const char* what() const noexcept override { return msg; }
482 char msg[RYML_ERRMSG_SIZE]; ///< the reported error message, without location indication.
483};
484
485
486/** Exception thrown by the default parse error implementation. To
487 * obtain the full error message containing context, use @ref
488 * err_parse_format(), or the helper @ref format_exc().
489 *
490 * @note This exception derives from @ref ExceptionBasic and can be
491 * catched using either type.
492 *
493 * @note Available only if @ref
494 * RYML_DEFAULT_CALLBACK_USES_EXCEPTIONS is defined, and @ref
495 * RYML_NO_DEFAULT_CALLBACKS is NOT defined. */
501
502
503/** Exception thrown by the default visit error implementation. To
504 * obtain the full error message containing context, use @ref
505 * err_visit_format(), or the helper @ref format_exc().
506 *
507 * @note This exception derives from @ref ExceptionBasic and can be
508 * catched using either type.
509 *
510 * @note Available only if @ref
511 * RYML_DEFAULT_CALLBACK_USES_EXCEPTIONS is defined, and @ref
512 * RYML_NO_DEFAULT_CALLBACKS is NOT defined. */
518
519
520/** Format a basic exception to an existing char container
521 *
522 * @note Available only if @ref
523 * RYML_DEFAULT_CALLBACK_USES_EXCEPTIONS is defined, and @ref
524 * RYML_NO_DEFAULT_CALLBACKS is NOT defined. */
525template<class CharContainer>
526void format_exc(CharContainer *out, ExceptionBasic const& exc)
527{
528 out->clear();
529 err_basic_format([out](csubstr s){
530 out->append(s.str, s.len);
531 }, csubstr{exc.msg, strlen(exc.msg)}, exc.errdata_basic);
532}
533/** Format a parse exception to an existing char container
534 *
535 * @note Available only if @ref
536 * RYML_DEFAULT_CALLBACK_USES_EXCEPTIONS is defined, and @ref
537 * RYML_NO_DEFAULT_CALLBACKS is NOT defined. */
538template<class CharContainer>
539void format_exc(CharContainer *out, ExceptionParse const& exc)
540{
541 out->clear();
542 err_parse_format([out](csubstr s){
543 out->append(s.str, s.len);
544 }, csubstr{exc.msg, strlen(exc.msg)}, exc.errdata_parse);
545}
546/** Format a visit exception to an existing char container
547 *
548 * @note Available only if @ref
549 * RYML_DEFAULT_CALLBACK_USES_EXCEPTIONS is defined, and @ref
550 * RYML_NO_DEFAULT_CALLBACKS is NOT defined. */
551template<class CharContainer>
552void format_exc(CharContainer *out, ExceptionVisit const& exc)
553{
554 out->clear();
555 err_visit_format([out](csubstr s){
556 out->append(s.str, s.len);
557 }, csubstr{exc.msg, strlen(exc.msg)}, exc.errdata_visit);
558}
559/** Format a parse exception, and return a newly-created char
560 * container
561 *
562 * @note Available only if @ref
563 * RYML_DEFAULT_CALLBACK_USES_EXCEPTIONS is defined, and @ref
564 * RYML_NO_DEFAULT_CALLBACKS is NOT defined. */
565template<class CharContainer, class ExceptionT>
566CharContainer format_exc(ExceptionT const& exc)
567{
568 CharContainer str;
569 format_exc(&str, exc);
570 return str;
571}
572
573#endif // _RYML_WITH_EXCEPTIONS
574
575/** @} */
576
577
578//-----------------------------------------------------------------------------
579//-----------------------------------------------------------------------------
580//-----------------------------------------------------------------------------
581
582/// @cond dev
583
584
585#if RYML_USE_ASSERT
586# define _RYML_ASSERT_BASIC(cond) _RYML_CHECK_BASIC(cond)
587# define _RYML_ASSERT_BASIC_(cb, cond) _RYML_CHECK_BASIC_((cb), cond)
588# define _RYML_ASSERT_BASIC_MSG(cond, ...) _RYML_CHECK_BASIC_MSG(cond, __VA_ARGS__)
589# define _RYML_ASSERT_BASIC_MSG_(cb, cond, ...) _RYML_CHECK_BASIC_MSG_((cb), cond, __VA_ARGS__)
590# define _RYML_ASSERT_PARSE(cond, ymlloc) _RYML_CHECK_PARSE(cond, (ymlloc))
591# define _RYML_ASSERT_PARSE_(cb, cond, ymlloc) _RYML_CHECK_PARSE_((cb), cond, (ymlloc))
592# define _RYML_ASSERT_PARSE_MSG(cond, ymlloc, ...) _RYML_CHECK_PARSE_MSG(cond, (ymlloc), __VA_ARGS__)
593# define _RYML_ASSERT_PARSE_MSG_(cb, cond, ymlloc, ...) _RYML_CHECK_PARSE_MSG_((cb), cond, (ymlloc), __VA_ARGS__)
594# define _RYML_ASSERT_VISIT(cond, tree, node) _RYML_CHECK_VISIT(cond, (tree), (node))
595# define _RYML_ASSERT_VISIT_(cb, cond, tree, node) _RYML_CHECK_VISIT_((cb), cond, (tree), (node))
596# define _RYML_ASSERT_VISIT_MSG(cond, tree, node, ...) _RYML_CHECK_VISIT_MSG(cond, (tree), (node), __VA_ARGS__)
597# define _RYML_ASSERT_VISIT_MSG_(cb, cond, tree, node, ...) _RYML_CHECK_VISIT_MSG_((cb), cond, (tree), (node), __VA_ARGS__)
598#else
599# define _RYML_ASSERT_BASIC(cond)
600# define _RYML_ASSERT_BASIC_(cb, cond)
601# define _RYML_ASSERT_BASIC_MSG(cond, ...)
602# define _RYML_ASSERT_BASIC_MSG_(cb, cond, ...)
603# define _RYML_ASSERT_PARSE(cond, ymlloc)
604# define _RYML_ASSERT_PARSE_(cb, cond, ymlloc)
605# define _RYML_ASSERT_PARSE_MSG(cond, ymlloc, ...)
606# define _RYML_ASSERT_PARSE_MSG_(cb, cond, ymlloc, ...)
607# define _RYML_ASSERT_VISIT(cont, tree, node)
608# define _RYML_ASSERT_VISIT_(cb, cont, tree, node)
609# define _RYML_ASSERT_VISIT_MSG(cont, tree, node, ...)
610# define _RYML_ASSERT_VISIT_MSG_(cb, cont, tree, node, ...)
611#endif
612
613#define _RYML_ERR_BASIC(...) \
614 do \
615 { \
616 RYML_DEBUG_BREAK(); \
617 ::c4::yml::err_basic((::c4::yml::ErrorDataBasic{RYML_LOC_HERE()}), __VA_ARGS__); \
618 C4_UNREACHABLE_AFTER_ERR(); \
619 } while(false)
620#define _RYML_ERR_PARSE(ymlloc, ...) \
621 do \
622 { \
623 RYML_DEBUG_BREAK(); \
624 ::c4::yml::err_parse((::c4::yml::ErrorDataParse{RYML_LOC_HERE(), ymlloc}), __VA_ARGS__); \
625 C4_UNREACHABLE_AFTER_ERR(); \
626 } while(false)
627#define _RYML_ERR_VISIT(tree, node, ...) \
628 do \
629 { \
630 RYML_DEBUG_BREAK(); \
631 ::c4::yml::err_visit((::c4::yml::ErrorDataVisit{RYML_LOC_HERE(), tree, node}), __VA_ARGS__); \
632 C4_UNREACHABLE_AFTER_ERR(); \
633 } while(false)
634
635
636#define _RYML_ERR_BASIC_(cb, ...) \
637 do \
638 { \
639 RYML_DEBUG_BREAK(); \
640 ::c4::yml::err_basic((cb), (::c4::yml::ErrorDataBasic{RYML_LOC_HERE()}), __VA_ARGS__); \
641 C4_UNREACHABLE_AFTER_ERR(); \
642 } while(false)
643#define _RYML_ERR_PARSE_(cb, ymlloc, ...) \
644 do \
645 { \
646 RYML_DEBUG_BREAK(); \
647 ::c4::yml::err_parse((cb), (::c4::yml::ErrorDataParse{RYML_LOC_HERE(), ymlloc}), __VA_ARGS__); \
648 C4_UNREACHABLE_AFTER_ERR(); \
649 } while(false)
650#define _RYML_ERR_VISIT_(cb, tree, node, ...) \
651 do \
652 { \
653 RYML_DEBUG_BREAK(); \
654 ::c4::yml::err_visit((cb), (::c4::yml::ErrorDataVisit{RYML_LOC_HERE(), tree, node}), __VA_ARGS__); \
655 C4_UNREACHABLE_AFTER_ERR(); \
656 } while(false)
657
658
659#ifndef RYML_SHORT_CHECK_MSG
660#define _RYML_MAYBE_MSG(cond) ": " #cond
661#define _RYML_MAYBE_MSG_(cond) ": " #cond ": "
662#else
663#define _RYML_MAYBE_MSG(cond)
664#define _RYML_MAYBE_MSG_(cond) ": "
665#endif
666
667#define _RYML_CHECK_BASIC(cond) \
668 do { \
669 if(C4_UNLIKELY(!(cond))) \
670 { \
671 RYML_DEBUG_BREAK(); \
672 ::c4::yml::err_basic((::c4::yml::ErrorDataBasic{RYML_LOC_HERE()}), "check failed" _RYML_MAYBE_MSG(cond)); \
673 C4_UNREACHABLE_AFTER_ERR(); \
674 } \
675 } while(false)
676#define _RYML_CHECK_PARSE(cond, ymlloc) \
677 do { \
678 if(C4_UNLIKELY(!(cond))) \
679 { \
680 RYML_DEBUG_BREAK(); \
681 ::c4::yml::err_parse((::c4::yml::ErrorDataParse{RYML_LOC_HERE(), ymlloc}), "check failed" _RYML_MAYBE_MSG(cond)); \
682 C4_UNREACHABLE_AFTER_ERR(); \
683 } \
684 } while(false)
685#define _RYML_CHECK_VISIT(cond, tree, node) \
686 do { \
687 if(C4_UNLIKELY(!(cond))) \
688 { \
689 RYML_DEBUG_BREAK(); \
690 ::c4::yml::err_visit((::c4::yml::ErrorDataVisit{RYML_LOC_HERE(), tree, node}), "check failed" _RYML_MAYBE_MSG(cond)); \
691 C4_UNREACHABLE_AFTER_ERR(); \
692 } \
693 } while(false)
694
695
696#define _RYML_CHECK_BASIC_(cb, cond) \
697 do { \
698 if(C4_UNLIKELY(!(cond))) \
699 { \
700 RYML_DEBUG_BREAK(); \
701 ::c4::yml::err_basic((cb), (::c4::yml::ErrorDataBasic{RYML_LOC_HERE()}), "check failed" _RYML_MAYBE_MSG(cond)); \
702 C4_UNREACHABLE_AFTER_ERR(); \
703 } \
704 } while(false)
705#define _RYML_CHECK_PARSE_(cb, cond, ymlloc) \
706 do { \
707 if(C4_UNLIKELY(!(cond))) \
708 { \
709 RYML_DEBUG_BREAK(); \
710 ::c4::yml::err_parse((cb), (::c4::yml::ErrorDataParse{RYML_LOC_HERE(), ymlloc}), "check failed" _RYML_MAYBE_MSG(cond)); \
711 C4_UNREACHABLE_AFTER_ERR(); \
712 } \
713 } while(false)
714#define _RYML_CHECK_VISIT_(cb, cond, tree, node) \
715 do { \
716 if(C4_UNLIKELY(!(cond))) \
717 { \
718 RYML_DEBUG_BREAK(); \
719 ::c4::yml::err_visit((cb), (::c4::yml::ErrorDataVisit{RYML_LOC_HERE(), tree, node}), "check failed" _RYML_MAYBE_MSG(cond)); \
720 C4_UNREACHABLE_AFTER_ERR(); \
721 } \
722 } while(false)
723
724
725#define _RYML_CHECK_BASIC_MSG(cond, ...) \
726 do { \
727 if(C4_UNLIKELY(!(cond))) \
728 { \
729 RYML_DEBUG_BREAK(); \
730 ::c4::yml::err_basic((::c4::yml::ErrorDataBasic{RYML_LOC_HERE()}), "check failed" _RYML_MAYBE_MSG_(cond) __VA_ARGS__); \
731 C4_UNREACHABLE_AFTER_ERR(); \
732 } \
733 } while(false)
734#define _RYML_CHECK_PARSE_MSG(cond, ymlloc, ...) \
735 do { \
736 if(C4_UNLIKELY(!(cond))) \
737 { \
738 RYML_DEBUG_BREAK(); \
739 ::c4::yml::err_parse((::c4::yml::ErrorDataParse{RYML_LOC_HERE(), ymlloc}), "check failed" _RYML_MAYBE_MSG_(cond) __VA_ARGS__); \
740 C4_UNREACHABLE_AFTER_ERR(); \
741 } \
742 } while(false)
743#define _RYML_CHECK_VISIT_MSG(cond, tree, node, ...) \
744 do { \
745 if(C4_UNLIKELY(!(cond))) \
746 { \
747 RYML_DEBUG_BREAK(); \
748 ::c4::yml::err_visit((::c4::yml::ErrorDataVisit{RYML_LOC_HERE(), tree, node}), "check failed" _RYML_MAYBE_MSG_(cond) __VA_ARGS__); \
749 C4_UNREACHABLE_AFTER_ERR(); \
750 } \
751 } while(false)
752
753
754#define _RYML_CHECK_BASIC_MSG_(cb, cond, ...) \
755 do { \
756 if(C4_UNLIKELY(!(cond))) \
757 { \
758 RYML_DEBUG_BREAK(); \
759 ::c4::yml::err_basic((cb), (::c4::yml::ErrorDataBasic{RYML_LOC_HERE()}), "check failed" _RYML_MAYBE_MSG_(cond) __VA_ARGS__); \
760 C4_UNREACHABLE_AFTER_ERR(); \
761 } \
762 } while(false)
763#define _RYML_CHECK_PARSE_MSG_(cb, cond, ymlloc, ...) \
764 do { \
765 if(C4_UNLIKELY(!(cond))) \
766 { \
767 RYML_DEBUG_BREAK(); \
768 ::c4::yml::err_parse((cb), (::c4::yml::ErrorDataParse{RYML_LOC_HERE(), ymlloc}), "check failed" _RYML_MAYBE_MSG_(cond) __VA_ARGS__); \
769 C4_UNREACHABLE_AFTER_ERR(); \
770 } \
771 } while(false)
772#define _RYML_CHECK_VISIT_MSG_(cb, cond, tree, node, ...) \
773 do { \
774 if(C4_UNLIKELY(!(cond))) \
775 { \
776 RYML_DEBUG_BREAK(); \
777 ::c4::yml::err_visit((cb), (::c4::yml::ErrorDataVisit{RYML_LOC_HERE(), tree, node}), "check failed" _RYML_MAYBE_MSG_(cond) __VA_ARGS__); \
778 C4_UNREACHABLE_AFTER_ERR(); \
779 } \
780 } while(false)
781
782/// @endcond
783
784} // namespace yml
785} // namespace c4
786
787#endif /* _C4_YML_ERROR_HPP_ */
Common utilities and infrastructure used by ryml.
#define RYML_ERRMSG_SIZE
size for the error message buffer
Definition common.hpp:34
#define RYML_LOGBUF_SIZE
size for the buffer used to format individual values to string while preparing an error message....
Definition common.hpp:44
#define RYML_EXPORT
Definition export.hpp:18
Callbacks const & get_callbacks()
get the global callbacks
Definition common.cpp:94
size_t location_format(DumpFn &&dumpfn, Location const &loc)
generic formatting of a location
Definition error.def.hpp:18
void err_visit(ErrorDataVisit const &errdata, const char *msg)
trigger a visit error to its respective handler, with a non-formatted error message.
Definition common.cpp:228
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.
void err_basic(ErrorDataBasic const &errdata, const char *msg)
trigger a basic error to its respective handler, with a non-formatted error message.
Definition common.cpp:196
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.
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.
void format_exc(CharContainer *out, ExceptionBasic const &exc)
Format a basic exception to an existing char container.
Definition error.hpp:526
void err_parse(ErrorDataParse const &errdata, const char *msg)
trigger a parse error to its respective handler, with a non-formatted error message.
Definition common.cpp:210
csubstr to_csubstr(const char(&s)[N]) noexcept
Definition substr.hpp:2381
basic_substring< char > substr
a mutable string view
Definition substr.hpp:2356
basic_substring< const char > csubstr
an immutable string view
Definition substr.hpp:2357
a CRTP base providing read-only methods for ConstNodeRef and NodeRef
Definition common.cpp:282
csubstr _get_text_region(csubstr text, size_t pos, size_t num_lines_before, size_t num_lines_after)
Definition common.cpp:283
size_t to_chars(substr buf, escaped_scalar e)
formatting implementation to escape a scalar with escape_scalar()
(Undefined by default) Use shorter error message from checks/asserts: do not show the check condition...
Definition common.cpp:14
size_t len
the length of the substring
Definition substr.hpp:218
size_t find(const C c, size_t start_pos=0) const
Definition substr.hpp:714
basic_substring first(size_t num) const noexcept
return the first num elements: [0,num[
Definition substr.hpp:530
C * str
a restricted pointer to the first character of the substring
Definition substr.hpp:216
A c-style callbacks class to customize behavior on errors or allocation.
Definition common.hpp:546
pfn_error_basic m_error_basic
a pointer to a basic error handler function
Definition common.hpp:550
pfn_error_parse m_error_parse
a pointer to a parse error handler function
Definition common.hpp:551
void * m_user_data
data to be forwarded in every call to a callback
Definition common.hpp:547
pfn_error_visit m_error_visit
a pointer to a visit error handler function
Definition common.hpp:552
Data for a basic error.
Definition common.hpp:320
Data for a parse error.
Definition common.hpp:329
Location ymlloc
location in the YAML source buffer where the error was detected.
Definition common.hpp:331
Data for a visit error.
Definition common.hpp:339
Location cpploc
location in the C++ source file where the error was detected.
Definition common.hpp:340
Exception thrown by the default basic error implementation.
Definition error.hpp:478
const char * what() const noexcept override
Definition error.hpp:480
ErrorDataBasic errdata_basic
error data
Definition error.hpp:481
ExceptionBasic(csubstr msg, ErrorDataBasic const &errdata_) noexcept
char msg[RYML_ERRMSG_SIZE]
the reported error message, without location indication.
Definition error.hpp:482
Exception thrown by the default parse error implementation.
Definition error.hpp:497
ExceptionParse(csubstr msg, ErrorDataParse const &errdata_) noexcept
ErrorDataParse errdata_parse
Definition error.hpp:499
Exception thrown by the default visit error implementation.
Definition error.hpp:514
ErrorDataVisit errdata_visit
Definition error.hpp:516
ExceptionVisit(csubstr msg, ErrorDataVisit const &errdata_) noexcept
holds a source or yaml file position, for example when an error is detected; See also location_format...
Definition common.hpp:289