@@ -21,6 +21,7 @@ limitations under the License.
2121#include < memory>
2222#include < set>
2323#include < string>
24+ #include < string_view>
2425
2526#include " desugarer.h"
2627#include " json.h"
@@ -52,6 +53,15 @@ using json = nlohmann::json;
5253
5354namespace {
5455
56+ // Custom exception type thrown by RapidYAML error handling callback.
57+ // Should be caught and converted to a runtime error.
58+ struct RapidYamlError {
59+ // Construct any way that std::string can be constructed.
60+ template <typename ... Args>
61+ explicit RapidYamlError (Args&&... args): msg_(std::forward<Args>(args)...) {}
62+ std::string msg_;
63+ };
64+
5565/* * Stack frames.
5666 *
5767 * Of these, FRAME_CALL is the most special, as it is the only frame the stack
@@ -1683,26 +1693,31 @@ class Interpreter {
16831693 const AST *builtinParseYaml (const LocationRange &loc, const std::vector<Value> &args)
16841694 {
16851695 validateBuiltinArgs (loc, " parseYaml" , args, {Value::STRING});
1686-
16871696 std::string value = encode_utf8 (static_cast <HeapString *>(args[0 ].v .h )->value );
1688-
1689- ryml::Tree tree = ryml::parse_in_arena (ryml::to_csubstr (value));
1690-
16911697 json j;
1692- if (tree.type (tree.root_id ()).is_notype ()) {
1693- scratch = makeNull ();
1694- return nullptr ;
1695- } else if (tree.is_stream (tree.root_id ())) {
1696- ryml::ConstNodeRef root = tree.crootref ();
1697- for (ryml::ConstNodeRef node : root.children ()) {
1698+ try {
1699+ // Use a custom EventHandler so we can attach error handling.
1700+ ryml::EventHandlerTree et{ryml::Callbacks{
1701+ nullptr , nullptr , nullptr , &Interpreter::handleRapidYamlError
1702+ }};
1703+ ryml::Parser pe (&et);
1704+ ryml::Tree tree = ryml::parse_in_arena (&pe, ryml::to_csubstr (value));
1705+
1706+ if (tree.type (tree.root_id ()).is_notype ()) {
1707+ // Nothing to do; `j` is already null!
1708+ } else if (tree.is_stream (tree.root_id ())) {
1709+ for (ryml::ConstNodeRef node : tree.crootref ().children ()) {
1710+ std::ostringstream jsonText;
1711+ jsonText << ryml::as_json (node);
1712+ j.push_back (json::parse (jsonText.str ()));
1713+ }
1714+ } else {
16981715 std::ostringstream jsonText;
1699- jsonText << ryml::as_json (node );
1700- j. push_back ( json::parse (jsonText.str () ));
1716+ jsonText << ryml::as_json (tree );
1717+ j = json::parse (jsonText.str ());
17011718 }
1702- } else {
1703- std::ostringstream jsonText;
1704- jsonText << ryml::as_json (tree);
1705- j = json::parse (jsonText.str ());
1719+ } catch (const RapidYamlError& exc) {
1720+ throw makeError (loc, exc.msg_ );
17061721 }
17071722 bool filled_unused;
17081723 otherJsonToHeap (j, filled_unused, scratch);
@@ -3407,6 +3422,19 @@ class Interpreter {
34073422 }
34083423 return r;
34093424 }
3425+
3426+ static void handleRapidYamlError (const char * inner_msg, size_t length, ryml::Location loc, void * /* unused: userdata */ )
3427+ {
3428+ std::ostringstream msg;
3429+ msg << " YAML error: " << loc.line << " :" ;
3430+ if (loc.col ) {
3431+ msg << loc.col << " :" ;
3432+ } else if (loc.offset ) {
3433+ msg << loc.offset << " :" ;
3434+ }
3435+ msg << " " << std::string_view (inner_msg, length);
3436+ throw RapidYamlError (std::move (msg.str ()));
3437+ }
34103438};
34113439
34123440} // namespace
0 commit comments