From 9d27429527bd00c1fe90b1e280e0ba512e96425d Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Mon, 5 Mar 2018 16:46:35 +0100 Subject: [PATCH] :hammer: added error messages to SAX interface --- include/nlohmann/detail/input/json_sax.hpp | 5 ++- include/nlohmann/detail/input/parser.hpp | 35 ++++++++++++------- single_include/nlohmann/json.hpp | 40 +++++++++++++++------- test/src/unit-class_parser.cpp | 4 +-- test/src/unit-deserialization.cpp | 2 +- 5 files changed, 57 insertions(+), 29 deletions(-) diff --git a/include/nlohmann/detail/input/json_sax.hpp b/include/nlohmann/detail/input/json_sax.hpp index 87f2119f..af2e7f24 100644 --- a/include/nlohmann/detail/input/json_sax.hpp +++ b/include/nlohmann/detail/input/json_sax.hpp @@ -113,9 +113,12 @@ struct json_sax @brief a parse error occurred @param[in] position the position in the input where the error occurs @param[in] last_token the last read token + @param[in] error_msg a detailed error message @return whether parsing should proceed */ - virtual bool parse_error(std::size_t position, const std::string& last_token) = 0; + virtual bool parse_error(std::size_t position, + const std::string& last_token, + const std::string& error_msg) = 0; virtual ~json_sax() = default; }; diff --git a/include/nlohmann/detail/input/parser.hpp b/include/nlohmann/detail/input/parser.hpp index 8fc29981..ece475bb 100644 --- a/include/nlohmann/detail/input/parser.hpp +++ b/include/nlohmann/detail/input/parser.hpp @@ -562,7 +562,8 @@ class parser if (JSON_UNLIKELY(last_token != token_type::value_string)) { return sax->parse_error(m_lexer.get_position(), - m_lexer.get_token_string()); + m_lexer.get_token_string(), + exception_message(token_type::value_string)); } else { @@ -577,7 +578,8 @@ class parser if (JSON_UNLIKELY(last_token != token_type::name_separator)) { return sax->parse_error(m_lexer.get_position(), - m_lexer.get_token_string()); + m_lexer.get_token_string(), + exception_message(token_type::name_separator)); } // parse value @@ -603,7 +605,8 @@ class parser else { return sax->parse_error(m_lexer.get_position(), - m_lexer.get_token_string()); + m_lexer.get_token_string(), + exception_message(token_type::end_object)); } } } @@ -649,7 +652,8 @@ class parser else { return sax->parse_error(m_lexer.get_position(), - m_lexer.get_token_string()); + m_lexer.get_token_string(), + exception_message(token_type::end_array)); } } } @@ -661,7 +665,8 @@ class parser if (JSON_UNLIKELY(not std::isfinite(res))) { return sax->parse_error(m_lexer.get_position(), - m_lexer.get_token_string()); + m_lexer.get_token_string(), + "number overflow"); } else { @@ -699,10 +704,19 @@ class parser return sax->number_unsigned(m_lexer.get_number_unsigned()); } + case token_type::parse_error: + { + // using "uninitialized" to avoid "expected" message + return sax->parse_error(m_lexer.get_position(), + m_lexer.get_token_string(), + exception_message(token_type::uninitialized)); + } + default: // the last token was unexpected { return sax->parse_error(m_lexer.get_position(), - m_lexer.get_token_string()); + m_lexer.get_token_string(), + exception_message(token_type::literal_or_value)); } } } @@ -721,10 +735,9 @@ class parser if (JSON_UNLIKELY(t != last_token)) { errored = true; - expected = t; if (allow_exceptions) { - throw_exception(); + JSON_THROW(parse_error::create(101, m_lexer.get_position(), exception_message(t))); } else { @@ -735,7 +748,7 @@ class parser return true; } - [[noreturn]] void throw_exception() const + std::string exception_message(const token_type expected) { std::string error_msg = "syntax error - "; if (last_token == token_type::parse_error) @@ -753,7 +766,7 @@ class parser error_msg += "; expected " + std::string(lexer_t::token_type_name(expected)); } - JSON_THROW(parse_error::create(101, m_lexer.get_position(), error_msg)); + return error_msg; } private: @@ -767,8 +780,6 @@ class parser lexer_t m_lexer; /// whether a syntax error occurred bool errored = false; - /// possible reason for the syntax error - token_type expected = token_type::uninitialized; /// whether to throw exceptions in case of errors const bool allow_exceptions = true; /// associated SAX parse event receiver diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index 656afa10..6138d33a 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -3247,9 +3247,12 @@ struct json_sax @brief a parse error occurred @param[in] position the position in the input where the error occurs @param[in] last_token the last read token + @param[in] error_msg a detailed error message @return whether parsing should proceed */ - virtual bool parse_error(std::size_t position, const std::string& last_token) = 0; + virtual bool parse_error(std::size_t position, + const std::string& last_token, + const std::string& error_msg) = 0; virtual ~json_sax() = default; }; @@ -3809,7 +3812,8 @@ class parser if (JSON_UNLIKELY(last_token != token_type::value_string)) { return sax->parse_error(m_lexer.get_position(), - m_lexer.get_token_string()); + m_lexer.get_token_string(), + exception_message(token_type::value_string)); } else { @@ -3824,7 +3828,8 @@ class parser if (JSON_UNLIKELY(last_token != token_type::name_separator)) { return sax->parse_error(m_lexer.get_position(), - m_lexer.get_token_string()); + m_lexer.get_token_string(), + exception_message(token_type::name_separator)); } // parse value @@ -3850,7 +3855,8 @@ class parser else { return sax->parse_error(m_lexer.get_position(), - m_lexer.get_token_string()); + m_lexer.get_token_string(), + exception_message(token_type::end_object)); } } } @@ -3896,7 +3902,8 @@ class parser else { return sax->parse_error(m_lexer.get_position(), - m_lexer.get_token_string()); + m_lexer.get_token_string(), + exception_message(token_type::end_array)); } } } @@ -3908,7 +3915,8 @@ class parser if (JSON_UNLIKELY(not std::isfinite(res))) { return sax->parse_error(m_lexer.get_position(), - m_lexer.get_token_string()); + m_lexer.get_token_string(), + "number overflow"); } else { @@ -3946,10 +3954,19 @@ class parser return sax->number_unsigned(m_lexer.get_number_unsigned()); } + case token_type::parse_error: + { + // using "uninitialized" to avoid "expected" message + return sax->parse_error(m_lexer.get_position(), + m_lexer.get_token_string(), + exception_message(token_type::uninitialized)); + } + default: // the last token was unexpected { return sax->parse_error(m_lexer.get_position(), - m_lexer.get_token_string()); + m_lexer.get_token_string(), + exception_message(token_type::literal_or_value)); } } } @@ -3968,10 +3985,9 @@ class parser if (JSON_UNLIKELY(t != last_token)) { errored = true; - expected = t; if (allow_exceptions) { - throw_exception(); + JSON_THROW(parse_error::create(101, m_lexer.get_position(), exception_message(t))); } else { @@ -3982,7 +3998,7 @@ class parser return true; } - [[noreturn]] void throw_exception() const + std::string exception_message(const token_type expected) { std::string error_msg = "syntax error - "; if (last_token == token_type::parse_error) @@ -4000,7 +4016,7 @@ class parser error_msg += "; expected " + std::string(lexer_t::token_type_name(expected)); } - JSON_THROW(parse_error::create(101, m_lexer.get_position(), error_msg)); + return error_msg; } private: @@ -4014,8 +4030,6 @@ class parser lexer_t m_lexer; /// whether a syntax error occurred bool errored = false; - /// possible reason for the syntax error - token_type expected = token_type::uninitialized; /// whether to throw exceptions in case of errors const bool allow_exceptions = true; /// associated SAX parse event receiver diff --git a/test/src/unit-class_parser.cpp b/test/src/unit-class_parser.cpp index bbf10589..9d40bfeb 100644 --- a/test/src/unit-class_parser.cpp +++ b/test/src/unit-class_parser.cpp @@ -123,7 +123,7 @@ class SaxEventLogger : public nlohmann::json::json_sax_t return true; } - bool parse_error(std::size_t position, const std::string&) override + bool parse_error(std::size_t position, const std::string&, const std::string&) override { errored = true; events.push_back("parse_error(" + std::to_string(position) + ")"); @@ -208,7 +208,7 @@ class SaxDomParser : public nlohmann::json::json_sax_t return true; } - bool parse_error(std::size_t position, const std::string&) override + bool parse_error(std::size_t position, const std::string&, const std::string&) override { return false; } diff --git a/test/src/unit-deserialization.cpp b/test/src/unit-deserialization.cpp index d50e6924..cd87dfdb 100644 --- a/test/src/unit-deserialization.cpp +++ b/test/src/unit-deserialization.cpp @@ -122,7 +122,7 @@ struct SaxEventLogger : public nlohmann::json::json_sax_t return true; } - bool parse_error(std::size_t position, const std::string&) override + bool parse_error(std::size_t position, const std::string&, const std::string&) override { events.push_back("parse_error(" + std::to_string(position) + ")"); return false;