rapidyaml 0.15.2
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 6355 of file quickstart.cpp.

6356{
6357 ErrorHandlerExample errh; // browse the implementation of this
6358 // class to understand more details
6359 errh.check_disabled();
6360 // set the global error handlers. Note the error callbacks must
6361 // never return: they must either throw an exception, use setjmp()
6362 // and longjmp(), or abort. Otherwise, the parser will enter into
6363 // an infinite loop, or the program may crash.
6365 errh.check_enabled();
6366 CHECK(errh.check_error_occurs([&]{
6367 ryml::Tree tree = ryml::parse_in_arena("errorhandler.yml", "[a: b\n}");
6368 }));
6369 ryml::set_callbacks(errh.original_callbacks); // restore defaults.
6370 errh.check_disabled();
6371}
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 6376 of file quickstart.cpp.

6377{
6378 auto cause_basic_error = []{
6379 ryml::Tree t;
6380 ryml::csubstr tag_handle = {}, tag_prefix = {}; // invalid, not filled
6381 t.add_tag_directive(tag_handle, tag_prefix, 0);
6382 };
6383 {
6384 ScopedErrorHandlerExample errh; // set the example callbacks (scoped)
6385 CHECK(errh.check_error_occurs(cause_basic_error));
6386 }
6387#ifdef RYML_WITH_EXCEPTIONS_
6388 bool gotit = false;
6389 try
6390 {
6391 cause_basic_error();
6392 }
6393 catch(ryml::ExceptionBasic const& exc)
6394 {
6395 gotit = true;
6396 ryml::csubstr msg = ryml::to_csubstr(exc.what());
6398 CHECK(!msg.empty());
6399 }
6400 CHECK(gotit);
6401#endif
6402}
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 6405 of file quickstart.cpp.

6406{
6407 ryml::csubstr ymlsrc = ""
6408 "{" "\n"
6409 " a: b" "\n"
6410 " [" "\n"
6411 "";
6412 ryml::csubstr ymlfile = "file.yml";
6413 auto cause_parse_error = [&]{
6414 return ryml::parse_in_arena(ymlfile, ymlsrc);
6415 };
6416 // the YAML in ymlsrc must cause a parse error while it is being
6417 // parsed. We use our error handler to catch that error, and save
6418 // the error info:
6420 {
6422 CHECK(errh.check_error_occurs(cause_parse_error));
6423 // the handler in errh saves the error info in itself. Let's
6424 // use that to see the messages we get.
6425 //
6426 // this message is the short message passed into the parse
6427 // error handler:
6428 CHECK(errh.saved_msg_short == "invalid character: '['");
6429 // this message was created inside the handler, by calling
6430 // ryml::err_parse_format():
6431 CHECK(ryml::to_csubstr(errh.saved_msg_full).begins_with("file.yml:3: col=4 (12B): ERROR: [parse] invalid character: '['"));
6432 // If you keep the YAML source buffer around, you can also use
6433 // it to create/print a larger error message showing the
6434 // YAML source code context which causes the error:
6435 std::string msg_ctx = errh.saved_msg_full + "\n";
6437 msg_ctx.append(s.str, s.len);
6438 }, errh.saved_parse_loc, ymlsrc, "err");
6439 CHECK(ryml::to_csubstr(msg_ctx).begins_with("file.yml:3: col=4 (12B): ERROR: [parse] invalid character: '['"));
6440 CHECK(ryml::to_csubstr(msg_ctx).ends_with(
6441 "file.yml:3: col=4 (12B): err:" "\n"
6442 "err:" "\n"
6443 "err: [" "\n"
6444 "err: |" "\n"
6445 "err: (here)" "\n"
6446 "err:" "\n"
6447 "err: see region:" "\n"
6448 "err:" "\n"
6449 "err: {" "\n"
6450 "err: a: b" "\n"
6451 "err: [" "\n"
6452 "err: |" "\n"
6453 "err: (here)" "\n"
6454 ""));
6455 //
6456 // Let's now check the location (see the message above):
6457 CHECK(errh.saved_parse_loc.name == ymlfile);
6458 CHECK(errh.saved_parse_loc.line == 3);
6459 CHECK(errh.saved_parse_loc.col == 4);
6460 CHECK(errh.saved_parse_loc.offset == 12);
6461 CHECK(errh.saved_parse_loc.offset <= ymlsrc.len);
6462 // ... and this is the location in the ryml source code file where
6463 // this error was found:
6465 CHECK(errh.saved_basic_loc.line > 0);
6466 CHECK(errh.saved_basic_loc.col > 0);
6467 CHECK(errh.saved_basic_loc.offset > 0);
6469 }
6470 // A parse error is also a basic error. If no parse error handler
6471 // is set, then ryml falls back to a basic error:
6472 {
6473 ryml::Callbacks cb = errh.callbacks();
6474 cb.m_error_parse = nullptr;
6476 CHECK(ryml::get_callbacks().m_error_parse == nullptr);
6477 CHECK(errh.check_error_occurs(cause_parse_error));
6478 // we got a basic error instead of a parse error:
6479 CHECK(errh.saved_msg_short == "invalid character: '['");
6480 // notice that the full message now displays this as a basic
6481 // error:
6482 CHECK(errh.saved_msg_full == "file.yml:3: col=4 (12B): ERROR: [basic] invalid character: '['");
6483 // the yml location is now in the location saved from the basic error
6484 CHECK(errh.saved_basic_loc.name == ymlfile);
6485 CHECK(errh.saved_basic_loc.line == 3);
6486 CHECK(errh.saved_basic_loc.col == 4);
6487 CHECK(errh.saved_basic_loc.offset == 12);
6488 CHECK(errh.saved_basic_loc.offset <= ymlsrc.len);
6494 }
6495#ifdef RYML_WITH_EXCEPTIONS_
6496 bool gotit = false;
6497 try
6498 {
6499 cause_parse_error();
6500 }
6501 catch(ryml::ExceptionParse const& exc)
6502 {
6503 gotit = true;
6504 ryml::csubstr msg = ryml::to_csubstr(exc.what());
6505 CHECK(exc.errdata_parse.ymlloc.name == ymlfile);
6506 CHECK(exc.errdata_parse.ymlloc.line == 3);
6507 CHECK(exc.errdata_parse.ymlloc.col == 4);
6508 CHECK(exc.errdata_parse.ymlloc.offset == 12);
6509 CHECK(exc.errdata_parse.ymlloc.offset <= ymlsrc.len);
6510 // the message saved in the exception is just the concrete error description:
6511 CHECK(msg == "invalid character: '['");
6512 // to print richer error messages, ryml provides helpers to
6513 // format that description into a complete error message,
6514 // containing location and source context indication:
6515 std::string full;
6516 auto dumpfn = [&full](ryml::csubstr s) { full.append(s.str, s.len); };
6517 ryml::err_parse_format(dumpfn, msg, exc.errdata_parse);
6518 full += '\n';
6519 ryml::location_format_with_context(dumpfn, exc.errdata_parse.ymlloc, ymlsrc, "err", 3);
6520 CHECK(ryml::to_csubstr(full).begins_with("file.yml:3: col=4 (12B): ERROR: [parse] invalid character: '['"));
6521 CHECK(ryml::to_csubstr(full).ends_with(
6522 "file.yml:3: col=4 (12B): err:" "\n"
6523 "err:" "\n"
6524 "err: [" "\n"
6525 "err: |" "\n"
6526 "err: (here)" "\n"
6527 "err:" "\n"
6528 "err: see region:" "\n"
6529 "err:" "\n"
6530 "err: {" "\n"
6531 "err: a: b" "\n"
6532 "err: [" "\n"
6533 "err: |" "\n"
6534 "err: (here)" "\n"
6535 ""));
6536 }
6537 CHECK(gotit);
6538 gotit = false;
6539 try
6540 {
6541 cause_parse_error();
6542 }
6543 catch(ryml::ExceptionBasic const& exc) // use references! don't slice the exception
6544 {
6545 gotit = true;
6546 ryml::csubstr msg = ryml::to_csubstr(exc.what());
6548 CHECK(!msg.empty());
6549 }
6550 CHECK(gotit);
6551#endif
6552}
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 6557 of file quickstart.cpp.

6558{
6559 ryml::csubstr ymlfile = "file.yml";
6560 ryml::csubstr ymlsrc = "float: 123.456";
6562 {
6564 ryml::Tree tree = ryml::parse_in_arena(ymlfile, ymlsrc);
6565 CHECK(errh.check_error_occurs([&]{
6566 int intval = 0;
6567 tree["float"].load(&intval); // cannot deserialize 123.456 to int
6568 }));
6569 // the handler in errh saves the error info in itself. Let's
6570 // use that to see the messages we get.
6571 //
6572 // this message is the short message passed into the visit error
6573 CHECK(errh.saved_msg_short == "could not deserialize node");
6574 // this message was created inside the handler, by calling
6575 // ryml::err_visit_format():
6576 CHECK(ryml::csubstr::npos != ryml::to_csubstr(errh.saved_msg_full).find("ERROR: [visit] could not deserialize node"));
6577 // The location of the visit error is of the C++ source file where
6578 // the error was detected -- NOT of the YAML source file:
6579 CHECK(errh.saved_basic_loc.name != ymlfile);
6580 // However, note that the tree and node id are available:
6581 CHECK(errh.saved_visit_tree == &tree);
6582 CHECK(errh.saved_visit_id == tree["float"].id());
6583 // see sample_error_visit_location() for an example on how
6584 // to extract the location.
6585 }
6586 // visit errors also fall back to basic errors when the visit
6587 // handler is not set (similar to the behavior of ExceptionVisit):
6588 {
6589 ryml::Callbacks cb = errh.callbacks();
6590 cb.m_error_visit = nullptr;
6592 CHECK(ryml::get_callbacks().m_error_visit == nullptr);
6593 ryml::Tree tree = ryml::parse_in_arena(ymlfile, ymlsrc);
6594 CHECK(errh.check_error_occurs([&]{
6595 int intval = 0;
6596 tree["float"].load(&intval); // cannot deserialize 123.456 to int
6597 }));
6598 // we got a basic error instead of a visit error:
6599 CHECK(errh.saved_msg_short == "could not deserialize node");
6600 // notice that the full message now displays this as a basic
6601 // error:
6602 CHECK(ryml::csubstr::npos != ryml::to_csubstr(errh.saved_msg_full).find("ERROR: [basic] could not deserialize node"));
6603 // the tree and id are not set, because this was called as a basic error
6604 CHECK(errh.saved_visit_tree == nullptr);
6607 }
6608#ifdef RYML_WITH_EXCEPTIONS_
6609 // when using the default ryml callbacks (see
6610 // RYML_NO_DEFAULT_CALLBACKS), and
6611 // RYML_DEFAULT_CALLBACK_USES_EXCEPTIONS is defined, the ryml
6612 // parse handler throws an exception of type ryml::ExceptionVisit,
6613 // which is derived from ryml::ExceptionBasic.
6614 {
6615 const ryml::Tree tree = ryml::parse_in_arena(ymlfile, ymlsrc);
6616 bool gotit = false;
6617 try
6618 {
6619 int intval = 0;
6620 tree["float"].load(&intval); // cannot deserialize 123.456 to int
6621 }
6622 catch(ryml::ExceptionVisit const& exc)
6623 {
6624 gotit = true;
6625 ryml::csubstr msg = ryml::to_csubstr(exc.what());
6627 CHECK(exc.errdata_visit.tree == &tree);
6628 CHECK(exc.errdata_visit.node == tree["float"].id());
6629 CHECK(!msg.empty());
6630 }
6631 CHECK(gotit);
6632 }
6633 // you can also catch the exception as its base,
6634 // ryml::ExceptionBasic:
6635 {
6636 const ryml::Tree tree = ryml::parse_in_arena(ymlfile, ymlsrc);
6637 bool gotit = false;
6638 try
6639 {
6640 int intval = 0;
6641 tree["float"].load(&intval); // cannot deserialize 123.456 to int
6642 }
6643 catch(ryml::ExceptionBasic const& exc) // use references! don't slice the exception
6644 {
6645 gotit = true;
6646 ryml::csubstr msg = ryml::to_csubstr(exc.what());
6648 CHECK(!msg.empty());
6649 }
6650 CHECK(gotit);
6651 }
6652#endif
6653}
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 6661 of file quickstart.cpp.

6662{
6664 // we will use locations to show the YAML source context of the
6665 // node where the visit error was triggered. This is a very
6666 // convenient feature to show detailed messages when deserializing
6667 // data read from a file (but do note this is opt-in, and it is
6668 // not mandatory). See sample_location_tracking() for more details
6669 // on location tracking.
6671 ryml::EventHandlerTree evt_handler{};
6672 ryml::Parser parser(&evt_handler, opts);
6673 ryml::csubstr ymlfile = "file.yml";
6674 ryml::csubstr ymlsrc = ""
6675 "foo: bar" "\n"
6676 "char: a" "\n"
6677 "int: a" "\n"
6678 "float: 123.456" "\n"
6679 "";
6680 const ryml::Tree tree = ryml::parse_in_arena(&parser, ymlfile, ymlsrc);
6681 // This function will cause a visit error when being called:
6682 auto cause_visit_error = [&]{
6683 int intval = 0;
6684 tree["float"].load(&intval); // cannot deserialize 123.456 to int
6685 };
6686 // Like with the parse error, we will use our error handler to
6687 // catch that visit error, and save the error info:
6688 CHECK(evt_handler.callbacks() == errh.callbacks());
6689 CHECK(parser.callbacks() == errh.callbacks());
6690 CHECK(tree.callbacks() == errh.callbacks());
6691 {
6692 CHECK(errh.check_error_occurs(cause_visit_error));
6693 // the handler in errh saves the error info in itself. Let's
6694 // use that to see the messages we get.
6695 //
6696 // this message is the short message passed into the visit error
6697 CHECK(errh.saved_msg_short == "could not deserialize node");
6698 // this message was created inside the handler, by calling
6699 // ryml::err_visit_format():
6700 CHECK(ryml::csubstr::npos != ryml::to_csubstr(errh.saved_msg_full).find("ERROR: [visit] could not deserialize node"));
6701 // The location of the visit error is of the C++ source file where
6702 // the error was detected -- NOT of the YAML source file:
6703 CHECK(errh.saved_basic_loc.name != ymlfile);
6704 // However, note that the tree and node id are available:
6705 CHECK(errh.saved_visit_tree == &tree);
6706 CHECK(errh.saved_visit_id == tree["float"].id());
6707 // ... which we can use to get the location in the YAML source
6708 // from the parser (but see @ref sample_location_tracking()):
6709 ryml::Location ymlloc = errh.saved_visit_tree->location(parser, errh.saved_visit_id);
6710 CHECK(ymlloc.name == ymlfile);
6711 // In turn, we can use format_location_context() to
6712 // print/create an error message pointing at the YAML source
6713 // code:
6714 std::string msg = errh.saved_msg_full;
6716 msg.append(s.str, s.len);
6717 }, ymlloc, ymlsrc, "err", /*number of lines to show before the error*/3);
6718 CHECK(ryml::to_csubstr(msg).ends_with(
6719 "file.yml:3: col=0 (24B): err:" "\n"
6720 "err:" "\n"
6721 "err: float: 123.456" "\n"
6722 "err: |" "\n"
6723 "err: (here)" "\n"
6724 "err:" "\n"
6725 "err: see region:" "\n"
6726 "err:" "\n"
6727 "err: foo: bar" "\n"
6728 "err: char: a" "\n"
6729 "err: int: a" "\n"
6730 "err: float: 123.456" "\n"
6731 "err: |" "\n"
6732 "err: (here)" "\n"
6733 ""));
6734 }
6735}
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().