rapidyaml 0.16.0
parse and emit YAML, and do it fast
Loading...
Searching...
No Matches
Errors and error handlers

Functions

void sample_error_handler ()
 set custom error handlers
void sample_error_basic ()
 handler for basic errors, and obtain a full error message with basic context
void sample_error_parse ()
 handler for parse errors, and obtain a full error message with parse context
void sample_error_visit ()
 handler for visit errors, and obtain a full error message with visit context
void sample_error_visit_location ()
 obtaining the YAML location from a visit error

Detailed Description

Function Documentation

◆ sample_error_handler()

void sample_error_handler ( )

set custom error handlers

demonstrates how to set a custom error handler for ryml

Definition at line 6439 of file quickstart.cpp.

6440{
6441 ErrorHandlerExample errh; // browse the implementation of this
6442 // class to understand more details
6443 errh.check_disabled();
6444 // set the global error handlers. Note the error callbacks must
6445 // never return: they must either throw an exception, use setjmp()
6446 // and longjmp(), or abort. Otherwise, the parser will enter into
6447 // an infinite loop, or the program may crash.
6449 errh.check_enabled();
6450 CHECK(errh.check_error_occurs([&]{
6451 ryml::Tree tree = ryml::parse_in_arena("errorhandler.yml", "[a: b\n}");
6452 }));
6453 ryml::set_callbacks(errh.original_callbacks); // restore defaults.
6454 errh.check_disabled();
6455}
void set_callbacks(Callbacks const &c)
set the global callbacks for the library; after a call to this function, these callbacks will be used...
Definition common.cpp:89
bool check_error_occurs(Fn &&fn)
checking that an error occurs while calling fn
void check_disabled() const
test that this handler is currently not set
#define CHECK(predicate)
a testing assertion, used only in this quickstart
ryml::Callbacks callbacks()
a helper to create the Callbacks object for the custom error handler
void check_enabled() const
test that this handler is currently set
an error handler used by some of the quickstart examples.
ryml::Callbacks original_callbacks

Referenced by main().

◆ sample_error_basic()

void sample_error_basic ( )

handler for basic errors, and obtain a full error message with basic context

Definition at line 6460 of file quickstart.cpp.

6461{
6462 auto cause_basic_error = []{
6463 ryml::Tree t;
6464 ryml::csubstr tag_handle = {}, tag_prefix = {}; // invalid, not filled
6465 t.add_tag_directive(tag_handle, tag_prefix, 0);
6466 };
6467 {
6468 ScopedErrorHandlerExample errh; // set the example callbacks (scoped)
6469 CHECK(errh.check_error_occurs(cause_basic_error));
6470 }
6471#ifdef RYML_WITH_EXCEPTIONS_
6472 bool gotit = false;
6473 try
6474 {
6475 cause_basic_error();
6476 }
6477 catch(ryml::ExceptionBasic const& exc)
6478 {
6479 gotit = true;
6480 ryml::csubstr msg = ryml::to_csubstr(exc.what());
6482 CHECK(!msg.empty());
6483 }
6484 CHECK(gotit);
6485#endif
6486}
void add_tag_directive(csubstr handle, csubstr prefix, id_type id)
Definition tree.cpp:1444
csubstr to_csubstr(const char(&s)[N]) noexcept
Definition substr.hpp:2380
basic_substring< const char > csubstr
an immutable string view
Definition substr.hpp:2356
Shows how to create a scoped error handler.
bool empty() const noexcept
Definition substr.hpp:356
Location location
location where the error was detected (may be from YAML or C++ source code)
Definition common.hpp:261
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
csubstr name
name of the file
Definition common.hpp:233

Referenced by main().

◆ sample_error_parse()

void sample_error_parse ( )

handler for parse errors, and obtain a full error message with parse context

Definition at line 6489 of file quickstart.cpp.

6490{
6491 ryml::csubstr ymlsrc = ""
6492 "{" "\n"
6493 " a: b" "\n"
6494 " [" "\n"
6495 "";
6496 ryml::csubstr ymlfile = "file.yml";
6497 auto cause_parse_error = [&]{
6498 return ryml::parse_in_arena(ymlfile, ymlsrc);
6499 };
6500 // the YAML in ymlsrc must cause a parse error while it is being
6501 // parsed. We use our error handler to catch that error, and save
6502 // the error info:
6504 {
6506 CHECK(errh.check_error_occurs(cause_parse_error));
6507 // the handler in errh saves the error info in itself. Let's
6508 // use that to see the messages we get.
6509 //
6510 // this message is the short message passed into the parse
6511 // error handler:
6512 CHECK(errh.saved_msg_short == "invalid character: '['");
6513 // this message was created inside the handler, by calling
6514 // ryml::err_parse_format():
6515 CHECK(ryml::to_csubstr(errh.saved_msg_full).begins_with("file.yml:3: col=4 (12B): ERROR: [parse] invalid character: '['"));
6516 // If you keep the YAML source buffer around, you can also use
6517 // it to create/print a larger error message showing the
6518 // YAML source code context which causes the error:
6519 std::string msg_ctx = errh.saved_msg_full + "\n";
6521 msg_ctx.append(s.str, s.len);
6522 }, errh.saved_parse_loc, ymlsrc, "err");
6523 CHECK(ryml::to_csubstr(msg_ctx).begins_with("file.yml:3: col=4 (12B): ERROR: [parse] invalid character: '['"));
6524 CHECK(ryml::to_csubstr(msg_ctx).ends_with(
6525 "file.yml:3: col=4 (12B): err:" "\n"
6526 "err:" "\n"
6527 "err: [" "\n"
6528 "err: |" "\n"
6529 "err: (here)" "\n"
6530 "err:" "\n"
6531 "err: see region:" "\n"
6532 "err:" "\n"
6533 "err: {" "\n"
6534 "err: a: b" "\n"
6535 "err: [" "\n"
6536 "err: |" "\n"
6537 "err: (here)" "\n"
6538 ""));
6539 //
6540 // Let's now check the location (see the message above):
6541 CHECK(errh.saved_parse_loc.name == ymlfile);
6542 CHECK(errh.saved_parse_loc.line == 3);
6543 CHECK(errh.saved_parse_loc.col == 4);
6544 CHECK(errh.saved_parse_loc.offset == 12);
6545 CHECK(errh.saved_parse_loc.offset <= ymlsrc.len);
6546 // ... and this is the location in the ryml source code file where
6547 // this error was found:
6549 CHECK(errh.saved_basic_loc.line > 0);
6550 CHECK(errh.saved_basic_loc.col > 0);
6551 CHECK(errh.saved_basic_loc.offset > 0);
6553 }
6554 // A parse error is also a basic error. If no parse error handler
6555 // is set, then ryml falls back to a basic error:
6556 {
6557 ryml::Callbacks cb = errh.callbacks();
6558 cb.m_error_parse = nullptr;
6560 CHECK(ryml::get_callbacks().m_error_parse == nullptr);
6561 CHECK(errh.check_error_occurs(cause_parse_error));
6562 // we got a basic error instead of a parse error:
6563 CHECK(errh.saved_msg_short == "invalid character: '['");
6564 // notice that the full message now displays this as a basic
6565 // error:
6566 CHECK(errh.saved_msg_full == "file.yml:3: col=4 (12B): ERROR: [basic] invalid character: '['");
6567 // the yml location is now in the location saved from the basic error
6568 CHECK(errh.saved_basic_loc.name == ymlfile);
6569 CHECK(errh.saved_basic_loc.line == 3);
6570 CHECK(errh.saved_basic_loc.col == 4);
6571 CHECK(errh.saved_basic_loc.offset == 12);
6572 CHECK(errh.saved_basic_loc.offset <= ymlsrc.len);
6578 }
6579#ifdef RYML_WITH_EXCEPTIONS_
6580 bool gotit = false;
6581 try
6582 {
6583 cause_parse_error();
6584 }
6585 catch(ryml::ExceptionParse const& exc)
6586 {
6587 gotit = true;
6588 ryml::csubstr msg = ryml::to_csubstr(exc.what());
6589 CHECK(exc.errdata_parse.ymlloc.name == ymlfile);
6590 CHECK(exc.errdata_parse.ymlloc.line == 3);
6591 CHECK(exc.errdata_parse.ymlloc.col == 4);
6592 CHECK(exc.errdata_parse.ymlloc.offset == 12);
6593 CHECK(exc.errdata_parse.ymlloc.offset <= ymlsrc.len);
6594 // the message saved in the exception is just the concrete error description:
6595 CHECK(msg == "invalid character: '['");
6596 // to print richer error messages, ryml provides helpers to
6597 // format that description into a complete error message,
6598 // containing location and source context indication:
6599 std::string full;
6600 auto dumpfn = [&full](ryml::csubstr s) { full.append(s.str, s.len); };
6601 ryml::err_parse_format(dumpfn, msg, exc.errdata_parse);
6602 full += '\n';
6603 ryml::location_format_with_context(dumpfn, exc.errdata_parse.ymlloc, ymlsrc, "err", 3);
6604 CHECK(ryml::to_csubstr(full).begins_with("file.yml:3: col=4 (12B): ERROR: [parse] invalid character: '['"));
6605 CHECK(ryml::to_csubstr(full).ends_with(
6606 "file.yml:3: col=4 (12B): err:" "\n"
6607 "err:" "\n"
6608 "err: [" "\n"
6609 "err: |" "\n"
6610 "err: (here)" "\n"
6611 "err:" "\n"
6612 "err: see region:" "\n"
6613 "err:" "\n"
6614 "err: {" "\n"
6615 "err: a: b" "\n"
6616 "err: [" "\n"
6617 "err: |" "\n"
6618 "err: (here)" "\n"
6619 ""));
6620 }
6621 CHECK(gotit);
6622 gotit = false;
6623 try
6624 {
6625 cause_parse_error();
6626 }
6627 catch(ryml::ExceptionBasic const& exc) // use references! don't slice the exception
6628 {
6629 gotit = true;
6630 ryml::csubstr msg = ryml::to_csubstr(exc.what());
6632 CHECK(!msg.empty());
6633 }
6634 CHECK(gotit);
6635#endif
6636}
Callbacks const & get_callbacks()
get the global callbacks
Definition common.cpp:94
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_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 parse_in_arena(Parser *parser, csubstr filename, csubstr yaml, Tree *tree, id_type node_id)
(1) parse YAML into an existing tree node. The filename will be used in any error messages arising du...
Definition parse.cpp:209
ryml::Location saved_basic_loc
std::string saved_msg_full
std::string saved_msg_short
ryml::Location saved_parse_loc
size_t len
the length of the substring
Definition substr.hpp:218
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_parse m_error_parse
a pointer to a parse error handler function
Definition common.hpp:379
Location ymlloc
location in the YAML source buffer where the error was detected.
Definition common.hpp:271
Exception thrown by the default parse error implementation.
Definition error.hpp:494
ErrorDataParse errdata_parse
Definition error.hpp:496
size_t col
column
Definition common.hpp:232
size_t line
line
Definition common.hpp:231
size_t offset
number of bytes from the beginning of the source buffer
Definition common.hpp:230

Referenced by main().

◆ sample_error_visit()

void sample_error_visit ( )

handler for visit errors, and obtain a full error message with visit context

Visit errors happen when an error is triggered while reading from a node.

Definition at line 6641 of file quickstart.cpp.

6642{
6643 ryml::csubstr ymlfile = "file.yml";
6644 ryml::csubstr ymlsrc = "float: 123.456";
6646 {
6648 ryml::Tree tree = ryml::parse_in_arena(ymlfile, ymlsrc);
6649 CHECK(errh.check_error_occurs([&]{
6650 int intval = 0;
6651 tree["float"].load(&intval); // cannot deserialize 123.456 to int
6652 }));
6653 // the handler in errh saves the error info in itself. Let's
6654 // use that to see the messages we get.
6655 //
6656 // this message is the short message passed into the visit error
6657 CHECK(errh.saved_msg_short == "could not deserialize node");
6658 // this message was created inside the handler, by calling
6659 // ryml::err_visit_format():
6660 CHECK(ryml::csubstr::npos != ryml::to_csubstr(errh.saved_msg_full).find("ERROR: [visit] could not deserialize node"));
6661 // The location of the visit error is of the C++ source file where
6662 // the error was detected -- NOT of the YAML source file:
6663 CHECK(errh.saved_basic_loc.name != ymlfile);
6664 // However, note that the tree and node id are available:
6665 CHECK(errh.saved_visit_tree == &tree);
6666 CHECK(errh.saved_visit_id == tree["float"].id());
6667 // see sample_error_visit_location() for an example on how
6668 // to extract the location.
6669 }
6670 // visit errors also fall back to basic errors when the visit
6671 // handler is not set (similar to the behavior of ExceptionVisit):
6672 {
6673 ryml::Callbacks cb = errh.callbacks();
6674 cb.m_error_visit = nullptr;
6676 CHECK(ryml::get_callbacks().m_error_visit == nullptr);
6677 ryml::Tree tree = ryml::parse_in_arena(ymlfile, ymlsrc);
6678 CHECK(errh.check_error_occurs([&]{
6679 int intval = 0;
6680 tree["float"].load(&intval); // cannot deserialize 123.456 to int
6681 }));
6682 // we got a basic error instead of a visit error:
6683 CHECK(errh.saved_msg_short == "could not deserialize node");
6684 // notice that the full message now displays this as a basic
6685 // error:
6686 CHECK(ryml::csubstr::npos != ryml::to_csubstr(errh.saved_msg_full).find("ERROR: [basic] could not deserialize node"));
6687 // the tree and id are not set, because this was called as a basic error
6688 CHECK(errh.saved_visit_tree == nullptr);
6691 }
6692#ifdef RYML_WITH_EXCEPTIONS_
6693 // when using the default ryml callbacks (see
6694 // RYML_NO_DEFAULT_CALLBACKS), and
6695 // RYML_DEFAULT_CALLBACK_USES_EXCEPTIONS is defined, the ryml
6696 // parse handler throws an exception of type ryml::ExceptionVisit,
6697 // which is derived from ryml::ExceptionBasic.
6698 {
6699 const ryml::Tree tree = ryml::parse_in_arena(ymlfile, ymlsrc);
6700 bool gotit = false;
6701 try
6702 {
6703 int intval = 0;
6704 tree["float"].load(&intval); // cannot deserialize 123.456 to int
6705 }
6706 catch(ryml::ExceptionVisit const& exc)
6707 {
6708 gotit = true;
6709 ryml::csubstr msg = ryml::to_csubstr(exc.what());
6711 CHECK(exc.errdata_visit.tree == &tree);
6712 CHECK(exc.errdata_visit.node == tree["float"].id());
6713 CHECK(!msg.empty());
6714 }
6715 CHECK(gotit);
6716 }
6717 // you can also catch the exception as its base,
6718 // ryml::ExceptionBasic:
6719 {
6720 const ryml::Tree tree = ryml::parse_in_arena(ymlfile, ymlsrc);
6721 bool gotit = false;
6722 try
6723 {
6724 int intval = 0;
6725 tree["float"].load(&intval); // cannot deserialize 123.456 to int
6726 }
6727 catch(ryml::ExceptionBasic const& exc) // use references! don't slice the exception
6728 {
6729 gotit = true;
6730 ryml::csubstr msg = ryml::to_csubstr(exc.what());
6732 CHECK(!msg.empty());
6733 }
6734 CHECK(gotit);
6735 }
6736#endif
6737}
void load(id_type node, T *v, bool check_readable=true) const
(1) deserialize the node's contents (val or container) to the given variable, forwarding to the user-...
Definition tree.hpp:871
@ NONE
an index to none
Definition common.hpp:131
ryml::id_type saved_visit_id
ryml::Tree const * saved_visit_tree
pfn_error_visit m_error_visit
a pointer to a visit error handler function
Definition common.hpp:380
Location cpploc
location in the C++ source file where the error was detected.
Definition common.hpp:280
Tree const * tree
tree where the error was detected
Definition common.hpp:281
id_type node
node where the error was detected
Definition common.hpp:282
Exception thrown by the default visit error implementation.
Definition error.hpp:511
ErrorDataVisit errdata_visit
Definition error.hpp:513

Referenced by main().

◆ sample_error_visit_location()

void sample_error_visit_location ( )

obtaining the YAML location from a visit error

It is possible to obtain the YAML location from a visit error: when the tree is obtained from parsing YAML, the messages may be enriched by using a parser set to track the locations.

See sample_location_tracking() for more details on how to use locations.

Definition at line 6745 of file quickstart.cpp.

6746{
6748 // we will use locations to show the YAML source context of the
6749 // node where the visit error was triggered. This is a very
6750 // convenient feature to show detailed messages when deserializing
6751 // data read from a file (but do note this is opt-in, and it is
6752 // not mandatory). See sample_location_tracking() for more details
6753 // on location tracking.
6755 ryml::EventHandlerTree evt_handler{};
6756 ryml::Parser parser(&evt_handler, opts);
6757 ryml::csubstr ymlfile = "file.yml";
6758 ryml::csubstr ymlsrc = ""
6759 "foo: bar" "\n"
6760 "char: a" "\n"
6761 "int: a" "\n"
6762 "float: 123.456" "\n"
6763 "";
6764 const ryml::Tree tree = ryml::parse_in_arena(&parser, ymlfile, ymlsrc);
6765 // This function will cause a visit error when being called:
6766 auto cause_visit_error = [&]{
6767 int intval = 0;
6768 tree["float"].load(&intval); // cannot deserialize 123.456 to int
6769 };
6770 // Like with the parse error, we will use our error handler to
6771 // catch that visit error, and save the error info:
6772 CHECK(evt_handler.callbacks() == errh.callbacks());
6773 CHECK(parser.callbacks() == errh.callbacks());
6774 CHECK(tree.callbacks() == errh.callbacks());
6775 {
6776 CHECK(errh.check_error_occurs(cause_visit_error));
6777 // the handler in errh saves the error info in itself. Let's
6778 // use that to see the messages we get.
6779 //
6780 // this message is the short message passed into the visit error
6781 CHECK(errh.saved_msg_short == "could not deserialize node");
6782 // this message was created inside the handler, by calling
6783 // ryml::err_visit_format():
6784 CHECK(ryml::csubstr::npos != ryml::to_csubstr(errh.saved_msg_full).find("ERROR: [visit] could not deserialize node"));
6785 // The location of the visit error is of the C++ source file where
6786 // the error was detected -- NOT of the YAML source file:
6787 CHECK(errh.saved_basic_loc.name != ymlfile);
6788 // However, note that the tree and node id are available:
6789 CHECK(errh.saved_visit_tree == &tree);
6790 CHECK(errh.saved_visit_id == tree["float"].id());
6791 // ... which we can use to get the location in the YAML source
6792 // from the parser (but see @ref sample_location_tracking()):
6793 ryml::Location ymlloc = errh.saved_visit_tree->location(parser, errh.saved_visit_id);
6794 CHECK(ymlloc.name == ymlfile);
6795 // In turn, we can use format_location_context() to
6796 // print/create an error message pointing at the YAML source
6797 // code:
6798 std::string msg = errh.saved_msg_full;
6800 msg.append(s.str, s.len);
6801 }, ymlloc, ymlsrc, "err", /*number of lines to show before the error*/3);
6802 CHECK(ryml::to_csubstr(msg).ends_with(
6803 "file.yml:3: col=0 (24B): err:" "\n"
6804 "err:" "\n"
6805 "err: float: 123.456" "\n"
6806 "err: |" "\n"
6807 "err: (here)" "\n"
6808 "err:" "\n"
6809 "err: see region:" "\n"
6810 "err:" "\n"
6811 "err: foo: bar" "\n"
6812 "err: char: a" "\n"
6813 "err: int: a" "\n"
6814 "err: float: 123.456" "\n"
6815 "err: |" "\n"
6816 "err: (here)" "\n"
6817 ""));
6818 }
6819}
Callbacks const & callbacks() const
Definition tree.hpp:349
Location location(Parser const &p, id_type node) const
Get the location of a node from the parse used to parse this tree.
Definition tree.cpp:1913
ParseEngine< EventHandlerTree > Parser
This is the main ryml parser, where the parser events are handled to create a ryml tree (see Event Ha...
Definition fwd.hpp:19
The event handler to create a ryml Tree.
Callbacks const & callbacks() const
holds a source or yaml file position, for example when an error is detected; See also location_format...
Definition common.hpp:229
Options to give to the ParseEngine to control its behavior.
ParserOptions & locations(bool enabled) noexcept
enable/disable source location tracking.

Referenced by main().