diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 7107ae6..ff227d2 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -13,14 +13,14 @@ If you wish to submit a PR, please be aware that: others, add an include directive to `include/toml++/toml.h` 3. Run `python/generate_single_header.py` -### Building and testing +### Building and running the tests Testing is done using [Catch2], included in the respository as a submodule under `extern/Catch2`. The first time you want to begin testing you'll need to ensure submodules have been fetched: ```bash git submodule update --init --recursive extern/Catch2 ``` -#### Windows +#### Testing on Windows with Visual Studio Install [Visual Studio 2019] and [Test Adapter for Catch2], then open `vs/toml++.sln` and build the projects in the `tests` solution folder. Visual Studio's Test Explorer should pick these up and @@ -29,7 +29,7 @@ allow you to run the tests directly. If test discovery fails you can usually fix it by clicking enabling `Auto Detect runsettings Files` (settings gear icon > `Configure Run Settings`). -#### Linux +#### Testing on Linux (and WSL) Install [meson] and [ninja] if necessary, then test with both gcc and clang: ```bash CXX=g++ meson build-gcc diff --git a/README.md b/README.md index 727eedd..dc51540 100644 --- a/README.md +++ b/README.md @@ -12,6 +12,7 @@ - Works with or without exceptions - Doesn't require RTTI - First-class support for serializing to JSON + - Tested on Clang and GCC and MSVC (VS2019)
diff --git a/docs/Doxyfile-mcss b/docs/Doxyfile-mcss index a2b25d9..485e011 100644 --- a/docs/Doxyfile-mcss +++ b/docs/Doxyfile-mcss @@ -17,3 +17,4 @@ HTML_EXTRA_FILES = tomlplusplus.js \ ##! Report an issue \ ##!

Documentation generated using m.css ##! M_HTML_HEADER = +##! M_FAVICON = favicon.ico diff --git a/docs/favicon.ico b/docs/favicon.ico new file mode 100644 index 0000000..518213d Binary files /dev/null and b/docs/favicon.ico differ diff --git a/examples/parse_file.cpp b/examples/parse_file.cpp index f288241..67206f2 100644 --- a/examples/parse_file.cpp +++ b/examples/parse_file.cpp @@ -27,12 +27,7 @@ int main(int argc, char** argv) } catch (const toml::parse_error& err) { - std::cerr - << "Error parsing file '"sv << *err.source().path - << "':\n"sv << err.description() - << "\n ("sv << err.source().begin << ")"sv - << std::endl; - + std::cerr << "Error parsing file:\n"sv << err << std::endl; return 1; } return 0; diff --git a/examples/toml_to_json_transcoder.cpp b/examples/toml_to_json_transcoder.cpp index 6111b5a..5b460f2 100644 --- a/examples/toml_to_json_transcoder.cpp +++ b/examples/toml_to_json_transcoder.cpp @@ -29,13 +29,9 @@ int main(int argc, char** argv) const auto table = toml::parse(file, std::move(path)); std::cout << toml::json_formatter{ table } << std::endl; } - catch (const toml::parse_error & err) + catch (const toml::parse_error& err) { - std::cerr - << "Error parsing file '"sv << *err.source().path - << "':\n"sv << err.description() - << "\n ("sv << err.source().begin << ")"sv - << std::endl; + std::cerr << "Error parsing file:\n"sv << err << std::endl; return 1; } @@ -51,10 +47,7 @@ int main(int argc, char** argv) } catch (const toml::parse_error& err) { - std::cerr - << "Error parsing stdin:\n"sv << err.description() - << "\n ("sv << err.source().begin << ")"sv - << std::endl; + std::cerr << "Error parsing stdin:\n"sv << err << std::endl; return 1; } diff --git a/include/toml++/toml.h b/include/toml++/toml.h index ae64f80..325a9d0 100644 --- a/include/toml++/toml.h +++ b/include/toml++/toml.h @@ -78,7 +78,8 @@ /// - Proper UTF-8 handling (incl. BOM) /// - Works with or without exceptions /// - Doesn't require RTTI -/// - First-class support for serializing to JSON +/// - First-class support for serializing to JSON +/// - Tested on Clang and GCC and MSVC (VS2019) /// /////////////////////////////////////////////////////////////////////// /// @@ -88,14 +89,15 @@ /// There's some minor configuration you can do to customize some basic library functionality, but that's totally /// optional. See the [README](https://github.com/marzer/tomlplusplus/blob/master/README.md) for more info. /// -///
-///

On Linkers and the One-Definition-Rule

-///

Header-only libraries are great for minimal setup, but can cause ODR violations and complex linker errors +/// \remark +/// \parblock +/// Header-only libraries are great for minimal setup, but can cause ODR violations and complex linker errors /// in situations where multiple modules include them separately, each with different versions, configuration options, -/// exception handling modes, et cetera.

-///

`toml++` attempts to combat this problem by nesting everything inside an additional inline namespace that -/// changes according to the library's major version and the compiler's exception-handling mode.

-///
+/// exception handling modes, et cetera. +/// +/// `toml++` attempts to combat this problem by nesting everything inside an additional inline namespace that +/// changes according to the library's major version and the compiler's exception-handling mode. +/// \endparblock /// /////////////////////////////////////////////////////////////////////// /// @@ -173,23 +175,47 @@ /// } /// \ecpp /// +/// Instances of toml::parse_error can be printed directly to streams: +/// \cpp +/// try +/// { +/// auto tbl = toml::parse("enabled = trUe"sv); //fails; TOML booleans are case-sensitive +/// } +/// catch (const toml::parse_error & err) +/// { +/// std::cerr << "Parsing failed:\n"sv << err << std::endl; +/// return 1; +/// } +/// \ecpp +/// +/// \out +/// Parsing failed: +/// Encountered unexpected character while parsing boolean; expected 'true', saw 'trU' +/// (error occurred at line 1, column 13) +/// \eout +/// +/// If the default error formatting is not be suitable for your use-case you can access the error's +/// toml::source_region and description directly from the error object (as in the examples above). +/// /// \see /// - toml::parse_file() /// - toml::parse_result -/// - toml::parse_error +/// - toml::parse_error +/// - toml::source_region +/// - toml::source_position /// /////////////////////////////////// /// -/// \subsection mainpage-example-parsing-strings Parsing TOML directly from strings -/// +/// \subsection mainpage-example-parsing-strings Parsing TOML directly from strings and streams +/// Strings and std::istreams can be read directly using toml::parse(): /// \cpp /// #include +/// #include /// #include /// using namespace std::string_view_literals; /// /// int main() /// { -/// // parse error handling omitted for brevity. /// static constexpr auto source = R"( /// [library] /// name = "toml++" @@ -199,8 +225,20 @@ /// [dependencies] /// cpp = 17 /// )"sv; -/// auto tbl = toml::parse(source); -/// std::cout << tbl << std::endl; +/// +/// // parse directly from a string view: +/// { +/// auto tbl = toml::parse(source); +/// std::cout << tbl << std::endl; +/// } +/// +/// // parse from a string stream: +/// { +/// std::stringstream ss{ std::string{ source } }; +/// auto tbl = toml::parse(ss); +/// std::cout << tbl << std::endl; +/// } +/// /// return 0; /// } /// \ecpp @@ -213,7 +251,10 @@ /// authors = ["Mark Gillard "] /// name = "toml++" /// version = "0.1.0" +/// +/// ... exactly as above, but twice /// \eout +/// /// \see toml::parse() /// /////////////////////////////////// @@ -353,7 +394,9 @@ /////////////////////////////////////////////////////////////////////// /// /// \section mainpage-contributing Contributing -/// See the [Contributing](https://github.com/marzer/tomlplusplus/blob/master/README.md#contributing) section of the repository README. +/// Contributions are very welcome! Either by [reporting issues](https://github.com/marzer/tomlplusplus/issues) or submitting pull requests. +/// If you wish to submit a pull request, please see [CONTRIBUTING](https://github.com/marzer/tomlplusplus/blob/master/CONTRIBUTING.md) +/// for all the details you need to get going. /// /////////////////////////////////////////////////////////////////////// /// @@ -366,6 +409,6 @@ /// 'Flexible and Economical UTF - 8 Decoder', which is also subject to the terms of the MIT license - see /// [LICENSE-utf8-decoder](https://github.com/marzer/tomlplusplus/blob/master/LICENSE-utf8-decoder). /// -/// \remark Note that if you're using the single-header version of the library you don't need to distribute these files; +/// \remark If you're using the single-header version of the library you don't need to distribute these files; /// their contents is included in the preamble at the top of the file. /// diff --git a/include/toml++/toml_common.h b/include/toml++/toml_common.h index 777ef7f..c858907 100644 --- a/include/toml++/toml_common.h +++ b/include/toml++/toml_common.h @@ -594,6 +594,33 @@ TOML_START { return source_; } + + /// \brief Prints a parse_error to a stream. + /// + /// \detail \cpp + /// try + /// { + /// auto tbl = toml::parse("enabled = trUe"sv); + /// } + /// catch (const toml::parse_error & err) + /// { + /// std::cerr << "Parsing failed:\n"sv << err << std::endl; + /// } + /// \ecpp + /// + /// \out + /// Parsing failed: + /// Encountered unexpected character while parsing boolean; expected 'true', saw 'trU' + /// (error occurred at line 1, column 13) + /// \eout + /// + /// \param lhs The stream. + /// \param rhs The parse_error. + /// + /// \returns The input stream. + template + friend std::basic_ostream& operator << (std::basic_ostream& lhs, const parse_error& rhs) + TOML_MAY_THROW; }; #else @@ -633,6 +660,10 @@ TOML_START { return source_; } + + template + friend std::basic_ostream& operator << (std::basic_ostream& lhs, const parse_error& rhs) + TOML_MAY_THROW; }; #endif diff --git a/include/toml++/toml_parser.h b/include/toml++/toml_parser.h index f5b4d81..ff1abc6 100644 --- a/include/toml++/toml_parser.h +++ b/include/toml++/toml_parser.h @@ -9,6 +9,26 @@ TOML_START #if TOML_DOXYGEN || !TOML_EXCEPTIONS /// \brief The result of a parsing operation. + /// + /// \detail A parse_result is effectively a discriminated union containing either a toml::table + /// or a toml::parse_error. Most member functions assume a particular one of these two states, + /// and calling them when in the wrong state will cause errors (e.g. attempting to access the + /// error object when parsing was successful). \cpp + /// parse_result result = toml::parse_file("config.toml"); + /// if (result) + /// do_stuff_with_a_table(result); //implicitly converts to table& + /// else + /// std::cerr << "Parse failed:\n"sv << result.error() << std::endl; + /// + /// \ecpp + /// + /// \out + /// example output: + /// + /// Parse failed: + /// Encountered unexpected character while parsing boolean; expected 'true', saw 'trU' + /// (error occurred at line 1, column 13 of 'config.toml') + /// \eout /// /// \warning This type only exists when exceptions are disabled. /// Otherwise parse_result is just an alias for toml::table: \cpp @@ -26,22 +46,6 @@ TOML_START /// /// #endif /// \ecpp - /// - /// \detail A parse_result is effectively a discriminated union containing either a toml::table - /// or a toml::parse_error. Most member functions assume a particular one of these two states, - /// and calling them when in the wrong state will cause errors (e.g. attempting to access the - /// error object when parsing was successful). \cpp - /// parse_result result = toml::parse_file("config.toml"); - /// if (result) - /// do_stuff_with_a_table(result); //implicitly converts to table& - /// else - /// std::cerr - /// << "Error parsing file '"sv << *result.error().source().path - /// << "':\n"sv << result.error().description() - /// << "\n ("sv << result.error().source().begin << ")"sv - /// << std::endl; - /// - /// \ecpp class parse_result final { private: @@ -971,6 +975,7 @@ TOML_IMPL_START TOML_ERROR_CHECK({}); TOML_ASSERT(cp && (*cp == U't' || *cp == U'f')); + start_recording(true); auto result = *cp == U't'; if (!consume_expected_sequence(result ? U"true"sv : U"false"sv)) { @@ -979,9 +984,10 @@ TOML_IMPL_START else abort_with_error( "Encountered unexpected character while parsing "sv, node_type::boolean, - "; expected 'true' or 'false', saw '"sv, *cp, '\'' + "; expected '"sv, result ? "true"sv : "false"sv, "', saw '"sv, recording_buffer, '\'' ); } + stop_recording(); TOML_ERROR_CHECK({}); if (cp && !is_value_terminator(*cp)) @@ -1008,6 +1014,7 @@ TOML_IMPL_START abort_with_error("Encountered EOF while parsing "sv, node_type::floating_point); }; + start_recording(true); const int sign = *cp == U'-' ? -1 : 1; if (*cp == U'+' || *cp == U'-') { @@ -1022,9 +1029,10 @@ TOML_IMPL_START eof_check(); abort_with_error( "Encountered unexpected character while parsing "sv, node_type::floating_point, - "; expected '"sv, inf ? "inf"sv : "nan"sv, "', saw '"sv, *cp, '\'' + "; expected '"sv, inf ? "inf"sv : "nan"sv, "', saw '"sv, recording_buffer, '\'' ); } + stop_recording(); TOML_ERROR_CHECK({}); if (cp && !is_value_terminator(*cp)) diff --git a/include/toml++/toml_print_to_stream.h b/include/toml++/toml_print_to_stream.h index 1327be9..01ef94e 100644 --- a/include/toml++/toml_print_to_stream.h +++ b/include/toml++/toml_print_to_stream.h @@ -302,7 +302,7 @@ TOML_START ); impl::print_to_stream("line "sv, lhs); impl::print_to_stream(rhs.line, lhs); - impl::print_to_stream(", column ", lhs); + impl::print_to_stream(", column "sv, lhs); impl::print_to_stream(rhs.column, lhs); return lhs; } @@ -324,5 +324,16 @@ TOML_START } return lhs; } + + template + std::basic_ostream& operator << (std::basic_ostream& lhs, const parse_error& rhs) + TOML_MAY_THROW + { + impl::print_to_stream(rhs.description(), lhs); + impl::print_to_stream("\n\t(error occurred at "sv, lhs); + lhs << rhs.source(); + impl::print_to_stream(")"sv, lhs); + return lhs; + } } TOML_END diff --git a/include/toml++/toml_version.h b/include/toml++/toml_version.h index 63f8d8d..202c65e 100644 --- a/include/toml++/toml_version.h +++ b/include/toml++/toml_version.h @@ -2,7 +2,7 @@ #define TOML_LIB_MAJOR 0 #define TOML_LIB_MINOR 2 -#define TOML_LIB_PATCH 0 +#define TOML_LIB_PATCH 1 #define TOML_LANG_MAJOR 0 #define TOML_LANG_MINOR 5 diff --git a/python/generate_documentation.py b/python/generate_documentation.py index 3443608..896f126 100644 --- a/python/generate_documentation.py +++ b/python/generate_documentation.py @@ -517,9 +517,16 @@ class InlineNamespaceFix3(InlineNamespaceFixBase): # adds some additional colouring to the syntax highlighting in code blocks. class SyntaxHighlightingFix(object): - __missing_keywords = [ + __keywords = [ 'constexpr', - 'if' + 'if', + 'else', + 'true', + 'false', + 'const', + 'noexcept', + 'template', + 'typename' ] def __call__(self, file, doc): @@ -570,11 +577,12 @@ class SyntaxHighlightingFix(object): changed = True # misidentifed keywords - nfs = code_block('span', class_='nf') - for nf in nfs: - if (nf.string is not None and nf.string in self.__missing_keywords): - nf['class'] = 'k' - changed = True + for keywordClass in ['nf', 'nb']: + kws = code_block('span', class_=keywordClass) + for kw in kws: + if (kw.string is not None and kw.string in self.__keywords): + kw['class'] = 'k' + changed = True return changed @@ -677,7 +685,7 @@ class ExtDocLinksFix(object): # toml-specific (r'toml::values?', 'classtoml_1_1value.html'), (r'(toml::)?date_times?', 'structtoml_1_1date__time.html'), - (r'(toml::)?times?', 'structtoml_1_1time.html'), + (r'(toml::)?time', 'structtoml_1_1time.html'), (r'(toml::)?dates?', 'structtoml_1_1date.html') ] __allowedNames = ['dd', 'p', 'dt', 'h3', 'td'] diff --git a/toml.hpp b/toml.hpp index 1c2151e..12a44ee 100644 --- a/toml.hpp +++ b/toml.hpp @@ -1,6 +1,6 @@ //---------------------------------------------------------------------------------------------------------------------- // -// toml++ v0.2.0 +// toml++ v0.2.1 // https://github.com/marzer/tomlplusplus // SPDX-License-Identifier: MIT // @@ -295,7 +295,7 @@ #define TOML_LIB_MAJOR 0 #define TOML_LIB_MINOR 2 -#define TOML_LIB_PATCH 0 +#define TOML_LIB_PATCH 1 #define TOML_LANG_MAJOR 0 #define TOML_LANG_MINOR 5 @@ -532,6 +532,10 @@ TOML_START { return source_; } + + template + friend std::basic_ostream& operator << (std::basic_ostream& lhs, const parse_error& rhs) + TOML_MAY_THROW; }; #else @@ -571,6 +575,10 @@ TOML_START { return source_; } + + template + friend std::basic_ostream& operator << (std::basic_ostream& lhs, const parse_error& rhs) + TOML_MAY_THROW; }; #endif @@ -1308,7 +1316,7 @@ TOML_START ); impl::print_to_stream("line "sv, lhs); impl::print_to_stream(rhs.line, lhs); - impl::print_to_stream(", column ", lhs); + impl::print_to_stream(", column "sv, lhs); impl::print_to_stream(rhs.column, lhs); return lhs; } @@ -1330,6 +1338,17 @@ TOML_START } return lhs; } + + template + std::basic_ostream& operator << (std::basic_ostream& lhs, const parse_error& rhs) + TOML_MAY_THROW + { + impl::print_to_stream(rhs.description(), lhs); + impl::print_to_stream("\n\t(error occurred at "sv, lhs); + lhs << rhs.source(); + impl::print_to_stream(")"sv, lhs); + return lhs; + } } TOML_END @@ -5590,6 +5609,7 @@ TOML_IMPL_START TOML_ERROR_CHECK({}); TOML_ASSERT(cp && (*cp == U't' || *cp == U'f')); + start_recording(true); auto result = *cp == U't'; if (!consume_expected_sequence(result ? U"true"sv : U"false"sv)) { @@ -5598,9 +5618,10 @@ TOML_IMPL_START else abort_with_error( "Encountered unexpected character while parsing "sv, node_type::boolean, - "; expected 'true' or 'false', saw '"sv, *cp, '\'' + "; expected '"sv, result ? "true"sv : "false"sv, "', saw '"sv, recording_buffer, '\'' ); } + stop_recording(); TOML_ERROR_CHECK({}); if (cp && !is_value_terminator(*cp)) @@ -5627,6 +5648,7 @@ TOML_IMPL_START abort_with_error("Encountered EOF while parsing "sv, node_type::floating_point); }; + start_recording(true); const int sign = *cp == U'-' ? -1 : 1; if (*cp == U'+' || *cp == U'-') { @@ -5641,9 +5663,10 @@ TOML_IMPL_START eof_check(); abort_with_error( "Encountered unexpected character while parsing "sv, node_type::floating_point, - "; expected '"sv, inf ? "inf"sv : "nan"sv, "', saw '"sv, *cp, '\'' + "; expected '"sv, inf ? "inf"sv : "nan"sv, "', saw '"sv, recording_buffer, '\'' ); } + stop_recording(); TOML_ERROR_CHECK({}); if (cp && !is_value_terminator(*cp)) diff --git a/vs/toml++.vcxproj b/vs/toml++.vcxproj index dc6be77..6360905 100644 --- a/vs/toml++.vcxproj +++ b/vs/toml++.vcxproj @@ -75,6 +75,7 @@ + diff --git a/vs/toml++.vcxproj.filters b/vs/toml++.vcxproj.filters index 087c99e..812176d 100644 --- a/vs/toml++.vcxproj.filters +++ b/vs/toml++.vcxproj.filters @@ -77,6 +77,7 @@ doc +