added missing operator<< for parse_error

also:
- fixed printing bug in operator << for source_position
- improved quality of error messages for boolean and inf/nan parsing
- documentation fixes
This commit is contained in:
Mark Gillard 2020-02-25 23:11:40 +02:00
parent 94f2f5a771
commit 44e5b1b1e2
15 changed files with 184 additions and 68 deletions

View File

@ -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

View File

@ -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)
<br>

View File

@ -17,3 +17,4 @@ HTML_EXTRA_FILES = tomlplusplus.js \
##! <a target="_blank" href="https://github.com/marzer/tomlplusplus/issues">Report an issue</a> \
##! <br><br>Documentation generated using <a href="https://mcss.mosra.cz/">m.css</a>
##! M_HTML_HEADER = <script src="tomlplusplus.js"></script>
##! M_FAVICON = favicon.ico

BIN
docs/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -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;

View File

@ -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;
}

View File

@ -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.
///
/// <blockquote>
/// <h3>On Linkers and the One-Definition-Rule</h3>
/// <p>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.</p>
/// <p>`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.</p>
/// </blockquote>
/// 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 <iostream>
/// #include <sstream>
/// #include <toml++/toml.h>
/// 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 <mark@notarealwebsite.com>"]
/// 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.
///

View File

@ -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 <typename CHAR>
friend std::basic_ostream<CHAR>& operator << (std::basic_ostream<CHAR>& lhs, const parse_error& rhs)
TOML_MAY_THROW;
};
#else
@ -633,6 +660,10 @@ TOML_START
{
return source_;
}
template <typename CHAR>
friend std::basic_ostream<CHAR>& operator << (std::basic_ostream<CHAR>& lhs, const parse_error& rhs)
TOML_MAY_THROW;
};
#endif

View File

@ -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 <strong>This type only exists when exceptions are disabled.</strong>
/// 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))

View File

@ -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 <typename CHAR>
std::basic_ostream<CHAR>& operator << (std::basic_ostream<CHAR>& 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

View File

@ -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

View File

@ -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']

View File

@ -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 <typename CHAR>
friend std::basic_ostream<CHAR>& operator << (std::basic_ostream<CHAR>& lhs, const parse_error& rhs)
TOML_MAY_THROW;
};
#else
@ -571,6 +575,10 @@ TOML_START
{
return source_;
}
template <typename CHAR>
friend std::basic_ostream<CHAR>& operator << (std::basic_ostream<CHAR>& 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 <typename CHAR>
std::basic_ostream<CHAR>& operator << (std::basic_ostream<CHAR>& 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))

View File

@ -75,6 +75,7 @@
</ItemGroup>
<ItemGroup>
<None Include="..\.editorconfig" />
<None Include="..\CONTRIBUTING.md" />
<None Include="..\docs\Doxyfile" />
<None Include="..\docs\Doxyfile-mcss" />
<None Include="..\docs\tomlplusplus.css" />

View File

@ -77,6 +77,7 @@
<None Include="..\docs\tomlplusplus.js">
<Filter>doc</Filter>
</None>
<None Include="..\CONTRIBUTING.md" />
</ItemGroup>
<ItemGroup>
<Filter Include="include">