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