mirror of
https://github.com/ToruNiina/toml11.git
synced 2025-12-16 03:08:52 +08:00
Compare commits
40 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9eb4008d6d | ||
|
|
a04544637b | ||
|
|
4c7dc17b78 | ||
|
|
59aaaab436 | ||
|
|
61dfa4a2dc | ||
|
|
ca337a1110 | ||
|
|
510e10de95 | ||
|
|
0babe8d589 | ||
|
|
5b2ce26721 | ||
|
|
db4d99cd4f | ||
|
|
74ceceef73 | ||
|
|
360e890cc0 | ||
|
|
46b35870c5 | ||
|
|
dddcecb034 | ||
|
|
084e82a8a9 | ||
|
|
f5079a7892 | ||
|
|
d90ffb63c6 | ||
|
|
b0ed122214 | ||
|
|
d88521d63c | ||
|
|
2accc9d22c | ||
|
|
363927f489 | ||
|
|
ae793fb631 | ||
|
|
944b83642a | ||
|
|
5a8e5dee73 | ||
|
|
7f870d5861 | ||
|
|
536b23dc84 | ||
|
|
0c9806e99f | ||
|
|
5a92932019 | ||
|
|
e929d2f00f | ||
|
|
1e1e4c06e8 | ||
|
|
d0726db473 | ||
|
|
4cdc15a824 | ||
|
|
b36fdf2f54 | ||
|
|
73ba6b385f | ||
|
|
30d1639aa4 | ||
|
|
d82814fc86 | ||
|
|
2220efd682 | ||
|
|
679b365cf7 | ||
|
|
83bf83b6dd | ||
|
|
321364c7c2 |
97
.travis.yml
97
.travis.yml
@@ -12,8 +12,39 @@ matrix:
|
||||
- ubuntu-toolchain-r-test
|
||||
packages:
|
||||
- g++-5
|
||||
- build-essential
|
||||
- cmake
|
||||
- libboost-all-dev
|
||||
- os: linux
|
||||
language: cpp
|
||||
compiler: gcc
|
||||
env: COMPILER="g++-6"
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
packages:
|
||||
- g++-6
|
||||
- libboost-all-dev
|
||||
- os: linux
|
||||
language: cpp
|
||||
compiler: gcc
|
||||
env: COMPILER="g++-7"
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
packages:
|
||||
- g++-7
|
||||
- libboost-all-dev
|
||||
- os: linux
|
||||
language: cpp
|
||||
compiler: gcc
|
||||
env: COMPILER="g++-8"
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
packages:
|
||||
- g++-8
|
||||
- libboost-all-dev
|
||||
- os: linux
|
||||
language: cpp
|
||||
@@ -26,8 +57,66 @@ matrix:
|
||||
- llvm-toolchain-precise-3.7
|
||||
packages:
|
||||
- clang-3.7
|
||||
- build-essential
|
||||
- cmake
|
||||
- libboost-all-dev
|
||||
- os: linux
|
||||
language: cpp
|
||||
compiler: clang
|
||||
env: COMPILER="clang++-4.0"
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
- llvm-toolchain-trusty-4.0
|
||||
packages:
|
||||
- clang-4.0
|
||||
- libboost-all-dev
|
||||
- os: linux
|
||||
language: cpp
|
||||
compiler: clang
|
||||
env: COMPILER="clang++-5.0"
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
- llvm-toolchain-trusty-5.0
|
||||
packages:
|
||||
- clang-5.0
|
||||
- libboost-all-dev
|
||||
- os: linux
|
||||
language: cpp
|
||||
compiler: clang
|
||||
env: COMPILER="clang++-6.0"
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
- llvm-toolchain-trusty-6.0
|
||||
packages:
|
||||
- clang-6.0
|
||||
- libboost-all-dev
|
||||
- os: linux
|
||||
language: cpp
|
||||
compiler: clang
|
||||
env: COMPILER="clang++-7"
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
- llvm-toolchain-trusty-7
|
||||
packages:
|
||||
- clang-7
|
||||
- libboost-all-dev
|
||||
- os: linux
|
||||
language: cpp
|
||||
compiler: clang
|
||||
env: COMPILER="clang++-8"
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
- llvm-toolchain-trusty-8
|
||||
packages:
|
||||
- clang-8
|
||||
- libboost-all-dev
|
||||
- os: osx
|
||||
language: cpp
|
||||
|
||||
@@ -2,12 +2,12 @@ toml11
|
||||
======
|
||||
|
||||
[](https://travis-ci.org/ToruNiina/toml11)
|
||||
[](https://ci.appveyor.com/project/ToruNiina/toml11)
|
||||
[](https://ci.appveyor.com/project/ToruNiina/toml11/branch/master)
|
||||
[](https://github.com/ToruNiina/toml11/releases)
|
||||
[](LICENSE)
|
||||
[](https://doi.org/10.5281/zenodo.1209136)
|
||||
|
||||
C++11 header-only toml parser depending only on C++ standard library.
|
||||
C++11 header-only toml parser/encoder depending only on C++ standard library.
|
||||
|
||||
compatible to the latest version of
|
||||
[TOML v0.5.0](https://github.com/toml-lang/toml/blob/master/versions/en/toml-v0.5.0.md)
|
||||
@@ -642,6 +642,7 @@ I thank the contributor for providing great feature to this repository.
|
||||
- Intel Compiler support
|
||||
- Quentin Khan (@xaxousis)
|
||||
- Found & Fixed a bug around ODR
|
||||
- Improved error message to show the location where the parser fails
|
||||
|
||||
## Licensing terms
|
||||
|
||||
|
||||
@@ -28,6 +28,7 @@ set(TEST_NAMES
|
||||
test_serialize_file
|
||||
test_parse_unicode
|
||||
test_error_detection
|
||||
test_format_error
|
||||
)
|
||||
|
||||
CHECK_CXX_COMPILER_FLAG("-Wall" COMPILER_SUPPORTS_WALL)
|
||||
|
||||
75
tests/test_format_error.cpp
Normal file
75
tests/test_format_error.cpp
Normal file
@@ -0,0 +1,75 @@
|
||||
#define BOOST_TEST_MODULE "test_value"
|
||||
#ifdef UNITTEST_FRAMEWORK_LIBRARY_EXIST
|
||||
#include <boost/test/unit_test.hpp>
|
||||
#else
|
||||
#define BOOST_TEST_NO_LIB
|
||||
#include <boost/test/included/unit_test.hpp>
|
||||
#endif
|
||||
#include <toml.hpp>
|
||||
|
||||
// to check it successfully compiles. it does not check the formatted string.
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_1_value)
|
||||
{
|
||||
toml::value val(42);
|
||||
|
||||
{
|
||||
const std::string pretty_error =
|
||||
toml::format_error("[error] test error", val, "this is a value");
|
||||
std::cout << pretty_error << std::endl;
|
||||
}
|
||||
|
||||
{
|
||||
const std::string pretty_error =
|
||||
toml::format_error("[error] test error", val, "this is a value",
|
||||
std::vector<std::string>{"this is a hint"});
|
||||
std::cout << pretty_error << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_2_values)
|
||||
{
|
||||
toml::value v1(42);
|
||||
toml::value v2(3.14);
|
||||
{
|
||||
const std::string pretty_error =
|
||||
toml::format_error("[error] test error with two values",
|
||||
v1, "this is the answer",
|
||||
v2, "this is the pi");
|
||||
std::cout << pretty_error << std::endl;
|
||||
}
|
||||
|
||||
{
|
||||
const std::string pretty_error =
|
||||
toml::format_error("[error] test error with two values",
|
||||
v1, "this is the answer",
|
||||
v2, "this is the pi",
|
||||
std::vector<std::string>{"hint"});
|
||||
std::cout << pretty_error << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_3_values)
|
||||
{
|
||||
toml::value v1(42);
|
||||
toml::value v2(3.14);
|
||||
toml::value v3("foo");
|
||||
{
|
||||
const std::string pretty_error =
|
||||
toml::format_error("[error] test error with two values",
|
||||
v1, "this is the answer",
|
||||
v2, "this is the pi",
|
||||
v3, "this is a meta-syntactic variable");
|
||||
std::cout << pretty_error << std::endl;
|
||||
}
|
||||
|
||||
{
|
||||
const std::string pretty_error =
|
||||
toml::format_error("[error] test error with two values",
|
||||
v1, "this is the answer",
|
||||
v2, "this is the pi",
|
||||
v3, "this is a meta-syntactic variable",
|
||||
std::vector<std::string>{"hint 1", "hint 2"});
|
||||
std::cout << pretty_error << std::endl;
|
||||
}
|
||||
}
|
||||
@@ -13,23 +13,23 @@ using namespace detail;
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_bare_key)
|
||||
{
|
||||
TOML11_TEST_PARSE_EQUAL_VALUE(parse_key, "barekey", std::vector<key>(1, "barekey"));
|
||||
TOML11_TEST_PARSE_EQUAL_VALUE(parse_key, "bare-key", std::vector<key>(1, "bare-key"));
|
||||
TOML11_TEST_PARSE_EQUAL_VALUE(parse_key, "bare_key", std::vector<key>(1, "bare_key"));
|
||||
TOML11_TEST_PARSE_EQUAL_VALUE(parse_key, "1234", std::vector<key>(1, "1234"));
|
||||
TOML11_TEST_PARSE_EQUAL(parse_key, "barekey", std::vector<key>(1, "barekey"));
|
||||
TOML11_TEST_PARSE_EQUAL(parse_key, "bare-key", std::vector<key>(1, "bare-key"));
|
||||
TOML11_TEST_PARSE_EQUAL(parse_key, "bare_key", std::vector<key>(1, "bare_key"));
|
||||
TOML11_TEST_PARSE_EQUAL(parse_key, "1234", std::vector<key>(1, "1234"));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_quoted_key)
|
||||
{
|
||||
TOML11_TEST_PARSE_EQUAL_VALUE(parse_key, "\"127.0.0.1\"", std::vector<key>(1, "127.0.0.1" ));
|
||||
TOML11_TEST_PARSE_EQUAL_VALUE(parse_key, "\"character encoding\"", std::vector<key>(1, "character encoding"));
|
||||
TOML11_TEST_PARSE_EQUAL(parse_key, "\"127.0.0.1\"", std::vector<key>(1, "127.0.0.1" ));
|
||||
TOML11_TEST_PARSE_EQUAL(parse_key, "\"character encoding\"", std::vector<key>(1, "character encoding"));
|
||||
#if defined(_MSC_VER) || defined(__INTEL_COMPILER)
|
||||
TOML11_TEST_PARSE_EQUAL_VALUE(parse_key, "\"\xCA\x8E\xC7\x9D\xCA\x9E\"", std::vector<key>(1, "\xCA\x8E\xC7\x9D\xCA\x9E"));
|
||||
TOML11_TEST_PARSE_EQUAL(parse_key, "\"\xCA\x8E\xC7\x9D\xCA\x9E\"", std::vector<key>(1, "\xCA\x8E\xC7\x9D\xCA\x9E"));
|
||||
#else
|
||||
TOML11_TEST_PARSE_EQUAL_VALUE(parse_key, "\"ʎǝʞ\"", std::vector<key>(1, "ʎǝʞ" ));
|
||||
TOML11_TEST_PARSE_EQUAL(parse_key, "\"ʎǝʞ\"", std::vector<key>(1, "ʎǝʞ" ));
|
||||
#endif
|
||||
TOML11_TEST_PARSE_EQUAL_VALUE(parse_key, "'key2'", std::vector<key>(1, "key2" ));
|
||||
TOML11_TEST_PARSE_EQUAL_VALUE(parse_key, "'quoted \"value\"'", std::vector<key>(1, "quoted \"value\"" ));
|
||||
TOML11_TEST_PARSE_EQUAL(parse_key, "'key2'", std::vector<key>(1, "key2" ));
|
||||
TOML11_TEST_PARSE_EQUAL(parse_key, "'quoted \"value\"'", std::vector<key>(1, "quoted \"value\"" ));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_dotted_key)
|
||||
@@ -38,13 +38,13 @@ BOOST_AUTO_TEST_CASE(test_dotted_key)
|
||||
std::vector<key> keys(2);
|
||||
keys[0] = "physical";
|
||||
keys[1] = "color";
|
||||
TOML11_TEST_PARSE_EQUAL_VALUE(parse_key, "physical.color", keys);
|
||||
TOML11_TEST_PARSE_EQUAL(parse_key, "physical.color", keys);
|
||||
}
|
||||
{
|
||||
std::vector<key> keys(2);
|
||||
keys[0] = "physical";
|
||||
keys[1] = "shape";
|
||||
TOML11_TEST_PARSE_EQUAL_VALUE(parse_key, "physical.shape", keys);
|
||||
TOML11_TEST_PARSE_EQUAL(parse_key, "physical.shape", keys);
|
||||
}
|
||||
{
|
||||
std::vector<key> keys(4);
|
||||
@@ -52,12 +52,12 @@ BOOST_AUTO_TEST_CASE(test_dotted_key)
|
||||
keys[1] = "y";
|
||||
keys[2] = "z";
|
||||
keys[3] = "w";
|
||||
TOML11_TEST_PARSE_EQUAL_VALUE(parse_key, "x.y.z.w", keys);
|
||||
TOML11_TEST_PARSE_EQUAL(parse_key, "x.y.z.w", keys);
|
||||
}
|
||||
{
|
||||
std::vector<key> keys(2);
|
||||
keys[0] = "site";
|
||||
keys[1] = "google.com";
|
||||
TOML11_TEST_PARSE_EQUAL_VALUE(parse_key, "site.\"google.com\"", keys);
|
||||
TOML11_TEST_PARSE_EQUAL(parse_key, "site.\"google.com\"", keys);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,7 +39,7 @@ inline std::string show_char(const char c)
|
||||
else
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << std::hex << std::setfill('0') << std::setw(2) << "0x"
|
||||
oss << "0x" << std::hex << std::setfill('0') << std::setw(2)
|
||||
<< static_cast<int>(c);
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
28
toml/get.hpp
28
toml/get.hpp
@@ -210,8 +210,9 @@ T get(const value& v)
|
||||
{
|
||||
throw std::out_of_range(detail::format_underline(concat_to_string(
|
||||
"[erorr] toml::get specified container size is ", container.size(),
|
||||
" but there are ", ar.size(), " elements in toml array."),
|
||||
detail::get_region(v), "here"));
|
||||
" but there are ", ar.size(), " elements in toml array."), {
|
||||
{std::addressof(detail::get_region(v)), "here"}
|
||||
}));
|
||||
}
|
||||
std::transform(ar.cbegin(), ar.cend(), container.begin(),
|
||||
[](const value& x){return ::toml::get<value_type>(x);});
|
||||
@@ -233,7 +234,9 @@ T get(const value& v)
|
||||
{
|
||||
throw std::out_of_range(detail::format_underline(concat_to_string(
|
||||
"[erorr] toml::get specified std::pair but there are ", ar.size(),
|
||||
" elements in toml array."), detail::get_region(v), "here"));
|
||||
" elements in toml array."), {
|
||||
{std::addressof(detail::get_region(v)), "here"}
|
||||
}));
|
||||
}
|
||||
return std::make_pair(::toml::get<first_type >(ar.at(0)),
|
||||
::toml::get<second_type>(ar.at(1)));
|
||||
@@ -264,7 +267,9 @@ T get(const value& v)
|
||||
throw std::out_of_range(detail::format_underline(concat_to_string(
|
||||
"[erorr] toml::get specified std::tuple with ",
|
||||
std::tuple_size<T>::value, "elements, but there are ", ar.size(),
|
||||
" elements in toml array."), detail::get_region(v), "here"));
|
||||
" elements in toml array."), {
|
||||
{std::addressof(detail::get_region(v)), "here"}
|
||||
}));
|
||||
}
|
||||
return detail::get_tuple_impl<T>(ar,
|
||||
detail::make_index_sequence<std::tuple_size<T>::value>{});
|
||||
@@ -340,8 +345,9 @@ find(const toml::value& v, const toml::key& ky)
|
||||
if(tab.count(ky) == 0)
|
||||
{
|
||||
throw std::out_of_range(detail::format_underline(concat_to_string(
|
||||
"[error] key \"", ky, "\" not found"), detail::get_region(v),
|
||||
"in this table"));
|
||||
"[error] key \"", ky, "\" not found"), {
|
||||
{std::addressof(detail::get_region(v)), "in this table"}
|
||||
}));
|
||||
}
|
||||
return ::toml::get<T>(tab.at(ky));
|
||||
}
|
||||
@@ -353,8 +359,9 @@ find(toml::value& v, const toml::key& ky)
|
||||
if(tab.count(ky) == 0)
|
||||
{
|
||||
throw std::out_of_range(detail::format_underline(concat_to_string(
|
||||
"[error] key \"", ky, "\" not found"), detail::get_region(v),
|
||||
"in this table"));
|
||||
"[error] key \"", ky, "\" not found"), {
|
||||
{std::addressof(detail::get_region(v)), "in this table"}
|
||||
}));
|
||||
}
|
||||
return ::toml::get<T>(tab.at(ky));
|
||||
}
|
||||
@@ -366,8 +373,9 @@ find(toml::value&& v, const toml::key& ky)
|
||||
if(tab.count(ky) == 0)
|
||||
{
|
||||
throw std::out_of_range(detail::format_underline(concat_to_string(
|
||||
"[error] key \"", ky, "\" not found"), detail::get_region(v),
|
||||
"in this table"));
|
||||
"[error] key \"", ky, "\" not found"), {
|
||||
{std::addressof(detail::get_region(v)), "in this table"}
|
||||
}));
|
||||
}
|
||||
return ::toml::get<T>(std::move(tab[ky]));
|
||||
}
|
||||
|
||||
@@ -124,9 +124,9 @@ using lex_escape_unicode_short = sequence<character<'u'>,
|
||||
using lex_escape_unicode_long = sequence<character<'U'>,
|
||||
repeat<lex_hex_dig, exactly<8>>>;
|
||||
using lex_escape_seq_char = either<character<'"'>, character<'\\'>,
|
||||
character<'/'>, character<'b'>,
|
||||
character<'f'>, character<'n'>,
|
||||
character<'r'>, character<'t'>,
|
||||
character<'b'>, character<'f'>,
|
||||
character<'n'>, character<'r'>,
|
||||
character<'t'>,
|
||||
lex_escape_unicode_short,
|
||||
lex_escape_unicode_long
|
||||
>;
|
||||
|
||||
566
toml/parser.hpp
566
toml/parser.hpp
File diff suppressed because it is too large
Load Diff
294
toml/region.hpp
294
toml/region.hpp
@@ -28,44 +28,6 @@ inline std::string make_string(std::size_t len, char c)
|
||||
return std::string(len, c);
|
||||
}
|
||||
|
||||
// location in a container, normally in a file content.
|
||||
// shared_ptr points the resource that the iter points.
|
||||
// it can be used not only for resource handling, but also error message.
|
||||
template<typename Container>
|
||||
struct location
|
||||
{
|
||||
static_assert(std::is_same<char, typename Container::value_type>::value,"");
|
||||
using const_iterator = typename Container::const_iterator;
|
||||
using source_ptr = std::shared_ptr<const Container>;
|
||||
|
||||
location(std::string name, Container cont)
|
||||
: source_(std::make_shared<Container>(std::move(cont))),
|
||||
source_name_(std::move(name)), iter_(source_->cbegin())
|
||||
{}
|
||||
location(const location&) = default;
|
||||
location(location&&) = default;
|
||||
location& operator=(const location&) = default;
|
||||
location& operator=(location&&) = default;
|
||||
~location() = default;
|
||||
|
||||
const_iterator& iter() noexcept {return iter_;}
|
||||
const_iterator iter() const noexcept {return iter_;}
|
||||
|
||||
const_iterator begin() const noexcept {return source_->cbegin();}
|
||||
const_iterator end() const noexcept {return source_->cend();}
|
||||
|
||||
source_ptr const& source() const& noexcept {return source_;}
|
||||
source_ptr&& source() && noexcept {return std::move(source_);}
|
||||
|
||||
std::string const& name() const noexcept {return source_name_;}
|
||||
|
||||
private:
|
||||
|
||||
source_ptr source_;
|
||||
std::string source_name_;
|
||||
const_iterator iter_;
|
||||
};
|
||||
|
||||
// region in a container, normally in a file content.
|
||||
// shared_ptr points the resource that the iter points.
|
||||
// combinators returns this.
|
||||
@@ -86,12 +48,89 @@ struct region_base
|
||||
virtual std::string line() const {return std::string("unknown line");}
|
||||
virtual std::string line_num() const {return std::string("?");}
|
||||
|
||||
|
||||
virtual std::size_t before() const noexcept {return 0;}
|
||||
virtual std::size_t size() const noexcept {return 0;}
|
||||
virtual std::size_t after() const noexcept {return 0;}
|
||||
};
|
||||
|
||||
// location in a container, normally in a file content.
|
||||
// shared_ptr points the resource that the iter points.
|
||||
// it can be used not only for resource handling, but also error message.
|
||||
//
|
||||
// it can be considered as a region that contains only one character.
|
||||
template<typename Container>
|
||||
struct location final : public region_base
|
||||
{
|
||||
static_assert(std::is_same<char, typename Container::value_type>::value,"");
|
||||
using const_iterator = typename Container::const_iterator;
|
||||
using source_ptr = std::shared_ptr<const Container>;
|
||||
|
||||
location(std::string name, Container cont)
|
||||
: source_(std::make_shared<Container>(std::move(cont))),
|
||||
source_name_(std::move(name)), iter_(source_->cbegin())
|
||||
{}
|
||||
location(const location&) = default;
|
||||
location(location&&) = default;
|
||||
location& operator=(const location&) = default;
|
||||
location& operator=(location&&) = default;
|
||||
~location() = default;
|
||||
|
||||
bool is_ok() const noexcept override {return static_cast<bool>(source_);}
|
||||
|
||||
const_iterator& iter() noexcept {return iter_;}
|
||||
const_iterator iter() const noexcept {return iter_;}
|
||||
|
||||
const_iterator begin() const noexcept {return source_->cbegin();}
|
||||
const_iterator end() const noexcept {return source_->cend();}
|
||||
|
||||
std::string str() const override {return make_string(1, *this->iter());}
|
||||
std::string name() const override {return source_name_;}
|
||||
|
||||
std::string line_num() const override
|
||||
{
|
||||
return std::to_string(1+std::count(this->begin(), this->iter(), '\n'));
|
||||
}
|
||||
|
||||
std::string line() const override
|
||||
{
|
||||
return make_string(this->line_begin(), this->line_end());
|
||||
}
|
||||
|
||||
const_iterator line_begin() const noexcept
|
||||
{
|
||||
using reverse_iterator = std::reverse_iterator<const_iterator>;
|
||||
return std::find(reverse_iterator(this->iter()),
|
||||
reverse_iterator(this->begin()), '\n').base();
|
||||
}
|
||||
const_iterator line_end() const noexcept
|
||||
{
|
||||
return std::find(this->iter(), this->end(), '\n');
|
||||
}
|
||||
|
||||
// location is always points a character. so the size is 1.
|
||||
std::size_t size() const noexcept override
|
||||
{
|
||||
return 1u;
|
||||
}
|
||||
std::size_t before() const noexcept override
|
||||
{
|
||||
return std::distance(this->line_begin(), this->iter());
|
||||
}
|
||||
std::size_t after() const noexcept override
|
||||
{
|
||||
return std::distance(this->iter(), this->line_end());
|
||||
}
|
||||
|
||||
source_ptr const& source() const& noexcept {return source_;}
|
||||
source_ptr&& source() && noexcept {return std::move(source_);}
|
||||
|
||||
private:
|
||||
|
||||
source_ptr source_;
|
||||
std::string source_name_;
|
||||
const_iterator iter_;
|
||||
};
|
||||
|
||||
template<typename Container>
|
||||
struct region final : public region_base
|
||||
{
|
||||
@@ -200,96 +239,67 @@ struct region final : public region_base
|
||||
|
||||
// to show a better error message.
|
||||
inline std::string format_underline(const std::string& message,
|
||||
const region_base& reg, const std::string& comment_for_underline,
|
||||
std::vector<std::pair<region_base const*, std::string>> reg_com,
|
||||
std::vector<std::string> helps = {})
|
||||
{
|
||||
assert(!reg_com.empty());
|
||||
|
||||
#ifdef _WIN32
|
||||
const auto newline = "\r\n";
|
||||
#else
|
||||
const char newline = '\n';
|
||||
#endif
|
||||
const auto line = reg.line();
|
||||
const auto line_number = reg.line_num();
|
||||
|
||||
std::string retval;
|
||||
retval += message;
|
||||
retval += newline;
|
||||
retval += " --> ";
|
||||
retval += reg.name();
|
||||
retval += newline;
|
||||
retval += ' ';
|
||||
retval += line_number;
|
||||
retval += " | ";
|
||||
retval += line;
|
||||
retval += newline;
|
||||
retval += make_string(line_number.size() + 1, ' ');
|
||||
retval += " | ";
|
||||
retval += make_string(reg.before(), ' ');
|
||||
retval += make_string(reg.size(), '~');
|
||||
retval += ' ';
|
||||
retval += comment_for_underline;
|
||||
if(helps.size() != 0)
|
||||
{
|
||||
retval += newline;
|
||||
retval += make_string(line_number.size() + 1, ' ');
|
||||
retval += " | ";
|
||||
for(const auto help : helps)
|
||||
const auto line_num_width = std::max_element(reg_com.begin(), reg_com.end(),
|
||||
[](std::pair<region_base const*, std::string> const& lhs,
|
||||
std::pair<region_base const*, std::string> const& rhs)
|
||||
{
|
||||
retval += newline;
|
||||
retval += "Hint: ";
|
||||
retval += help;
|
||||
return lhs.first->line_num().size() < rhs.first->line_num().size();
|
||||
}
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
// to show a better error message.
|
||||
inline std::string format_underline(const std::string& message,
|
||||
const region_base& reg1, const std::string& comment_for_underline1,
|
||||
const region_base& reg2, const std::string& comment_for_underline2,
|
||||
std::vector<std::string> helps = {})
|
||||
{
|
||||
#ifdef _WIN32
|
||||
const auto newline = "\r\n";
|
||||
#else
|
||||
const char newline = '\n';
|
||||
#endif
|
||||
const auto line1 = reg1.line();
|
||||
const auto line_number1 = reg1.line_num();
|
||||
const auto line2 = reg2.line();
|
||||
const auto line_number2 = reg2.line_num();
|
||||
const auto line_num_width =
|
||||
std::max(line_number1.size(), line_number2.size());
|
||||
)->first->line_num().size();
|
||||
|
||||
std::ostringstream retval;
|
||||
retval << message << newline;
|
||||
retval << " --> " << reg1.name() << newline;
|
||||
// ---------------------------------------
|
||||
retval << ' ' << std::setw(line_num_width) << line_number1;
|
||||
retval << " | " << line1 << newline;
|
||||
retval << make_string(line_num_width + 1, ' ');
|
||||
retval << " | ";
|
||||
retval << make_string(reg1.before(), ' ');
|
||||
retval << make_string(reg1.size(), '~');
|
||||
retval << ' ';
|
||||
retval << comment_for_underline1 << newline;
|
||||
// ---------------------------------------
|
||||
if(reg2.name() != reg1.name())
|
||||
|
||||
for(std::size_t i=0; i<reg_com.size(); ++i)
|
||||
{
|
||||
retval << " --> " << reg2.name() << newline;
|
||||
if(i!=0 && reg_com.at(i-1).first->name() == reg_com.at(i).first->name())
|
||||
{
|
||||
retval << newline << " ..." << newline;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(i != 0) {retval << newline;}
|
||||
retval << " --> " << reg_com.at(i).first->name() << newline;
|
||||
}
|
||||
|
||||
const region_base* const reg = reg_com.at(i).first;
|
||||
const std::string& comment = reg_com.at(i).second;
|
||||
|
||||
|
||||
retval << ' ' << std::setw(line_num_width) << reg->line_num();
|
||||
retval << " | " << reg->line() << newline;
|
||||
retval << make_string(line_num_width + 1, ' ');
|
||||
retval << " | " << make_string(reg->before(), ' ');
|
||||
|
||||
if(reg->size() == 1)
|
||||
{
|
||||
// invalid
|
||||
// ^------
|
||||
retval << '^';
|
||||
retval << make_string(reg->after(), '-');
|
||||
}
|
||||
else
|
||||
{
|
||||
// invalid
|
||||
// ~~~~~~~
|
||||
retval << make_string(reg->size(), '~');
|
||||
}
|
||||
|
||||
retval << ' ';
|
||||
retval << comment;
|
||||
}
|
||||
else
|
||||
{
|
||||
retval << " ..." << newline;
|
||||
}
|
||||
retval << ' ' << std::setw(line_num_width) << line_number2;
|
||||
retval << " | " << line2 << newline;
|
||||
retval << make_string(line_num_width + 1, ' ');
|
||||
retval << " | ";
|
||||
retval << make_string(reg2.before(), ' ');
|
||||
retval << make_string(reg2.size(), '~');
|
||||
retval << ' ';
|
||||
retval << comment_for_underline2;
|
||||
|
||||
if(helps.size() != 0)
|
||||
{
|
||||
retval << newline;
|
||||
@@ -305,62 +315,6 @@ inline std::string format_underline(const std::string& message,
|
||||
return retval.str();
|
||||
}
|
||||
|
||||
|
||||
// to show a better error message.
|
||||
template<typename Container>
|
||||
std::string
|
||||
format_underline(const std::string& message, const location<Container>& loc,
|
||||
const std::string& comment_for_underline,
|
||||
std::vector<std::string> helps = {})
|
||||
{
|
||||
#ifdef _WIN32
|
||||
const auto newline = "\r\n";
|
||||
#else
|
||||
const char newline = '\n';
|
||||
#endif
|
||||
using const_iterator = typename location<Container>::const_iterator;
|
||||
using reverse_iterator = std::reverse_iterator<const_iterator>;
|
||||
const auto line_begin = std::find(reverse_iterator(loc.iter()),
|
||||
reverse_iterator(loc.begin()),
|
||||
'\n').base();
|
||||
const auto line_end = std::find(loc.iter(), loc.end(), '\n');
|
||||
|
||||
const auto line_number = std::to_string(
|
||||
1 + std::count(loc.begin(), loc.iter(), '\n'));
|
||||
|
||||
std::string retval;
|
||||
retval += message;
|
||||
retval += newline;
|
||||
retval += " --> ";
|
||||
retval += loc.name();
|
||||
retval += newline;
|
||||
retval += ' ';
|
||||
retval += line_number;
|
||||
retval += " | ";
|
||||
retval += make_string(line_begin, line_end);
|
||||
retval += newline;
|
||||
retval += make_string(line_number.size() + 1, ' ');
|
||||
retval += " | ";
|
||||
retval += make_string(std::distance(line_begin, loc.iter()),' ');
|
||||
retval += '^';
|
||||
retval += make_string(std::distance(loc.iter(), line_end), '-');
|
||||
retval += ' ';
|
||||
retval += comment_for_underline;
|
||||
if(helps.size() != 0)
|
||||
{
|
||||
retval += newline;
|
||||
retval += make_string(line_number.size() + 1, ' ');
|
||||
retval += " | ";
|
||||
for(const auto help : helps)
|
||||
{
|
||||
retval += newline;
|
||||
retval += "Hint: ";
|
||||
retval += help;
|
||||
}
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
} // detail
|
||||
} // toml
|
||||
#endif// TOML11_REGION_H
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include "value.hpp"
|
||||
#include "lexer.hpp"
|
||||
#include <limits>
|
||||
#include <cstdio>
|
||||
|
||||
namespace toml
|
||||
{
|
||||
@@ -30,13 +31,12 @@ struct serializer
|
||||
}
|
||||
std::string operator()(const toml::floating f) const
|
||||
{
|
||||
std::string token = [=] {
|
||||
// every float value needs decimal point (or exponent).
|
||||
std::ostringstream oss;
|
||||
oss << std::setprecision(float_prec_) << std::showpoint << f;
|
||||
return oss.str();
|
||||
}();
|
||||
const auto fmt = "%.*g";
|
||||
const auto bsz = std::snprintf(nullptr, 0, fmt, this->float_prec_, f);
|
||||
std::vector<char> buf(bsz + 1, '\0'); // +1 for null character(\0)
|
||||
std::snprintf(buf.data(), buf.size(), fmt, this->float_prec_, f);
|
||||
|
||||
std::string token(buf.begin(), buf.end());
|
||||
if(token.back() == '.') // 1. => 1.0
|
||||
{
|
||||
token += '0';
|
||||
|
||||
@@ -8,32 +8,38 @@ namespace toml
|
||||
{
|
||||
|
||||
template<typename T>
|
||||
TOML11_MARK_AS_DEPRECATED
|
||||
inline value to_toml(T&& x)
|
||||
{
|
||||
return value(std::forward<T>(x));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
TOML11_MARK_AS_DEPRECATED
|
||||
inline value to_toml(T&& x, string_t kind)
|
||||
{
|
||||
return value(std::forward<T>(x), kind);
|
||||
}
|
||||
|
||||
TOML11_MARK_AS_DEPRECATED
|
||||
inline value to_toml(local_date d, local_time t)
|
||||
{
|
||||
return value(local_datetime(d, t));
|
||||
}
|
||||
TOML11_MARK_AS_DEPRECATED
|
||||
inline value to_toml(local_date d, local_time t, time_offset ofs)
|
||||
{
|
||||
return value(offset_datetime(d, t, ofs));
|
||||
}
|
||||
|
||||
template<typename ... Ts>
|
||||
TOML11_MARK_AS_DEPRECATED
|
||||
inline value to_toml(Ts&& ... xs)
|
||||
{
|
||||
return value(toml::array{toml::value(std::forward<Ts>(xs)) ... });
|
||||
}
|
||||
|
||||
TOML11_MARK_AS_DEPRECATED
|
||||
inline value to_toml(std::initializer_list<std::pair<std::string, toml::value>> xs)
|
||||
{
|
||||
return value(toml::table(xs.begin(), xs.end()));
|
||||
|
||||
@@ -7,6 +7,16 @@
|
||||
#include <memory>
|
||||
#include <sstream>
|
||||
|
||||
#if __cplusplus >= 201402L
|
||||
# define TOML11_MARK_AS_DEPRECATED [[deprecated]]
|
||||
#elif defined(__GNUC__)
|
||||
# define TOML11_MARK_AS_DEPRECATED __attribute__((deprecated))
|
||||
#elif defined(_MSC_VER)
|
||||
# define TOML11_MARK_AS_DEPRECATED __declspec(deprecated)
|
||||
#else
|
||||
# define TOML11_MARK_AS_DEPRECATED
|
||||
#endif
|
||||
|
||||
namespace toml
|
||||
{
|
||||
|
||||
@@ -29,8 +39,9 @@ inline void resize_impl(T& container, std::size_t N, std::true_type)
|
||||
template<typename T>
|
||||
inline void resize_impl(T& container, std::size_t N, std::false_type)
|
||||
{
|
||||
if(container.size() >= N) return;
|
||||
else throw std::invalid_argument("not resizable type");
|
||||
if(container.size() >= N) {return;}
|
||||
|
||||
throw std::invalid_argument("not resizable type");
|
||||
}
|
||||
|
||||
} // detail
|
||||
@@ -38,8 +49,9 @@ inline void resize_impl(T& container, std::size_t N, std::false_type)
|
||||
template<typename T>
|
||||
inline void resize(T& container, std::size_t N)
|
||||
{
|
||||
if(container.size() == N) return;
|
||||
else return detail::resize_impl(container, N, detail::has_resize_method<T>());
|
||||
if(container.size() == N) {return;}
|
||||
|
||||
return detail::resize_impl(container, N, detail::has_resize_method<T>());
|
||||
}
|
||||
|
||||
namespace detail
|
||||
@@ -73,7 +85,5 @@ T from_string(const std::string& str, U&& opt)
|
||||
return v;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}// toml
|
||||
#endif // TOML11_UTILITY
|
||||
|
||||
108
toml/value.hpp
108
toml/value.hpp
@@ -21,8 +21,8 @@ namespace detail
|
||||
{
|
||||
// to show error messages. not recommended for users.
|
||||
region_base const& get_region(const value&);
|
||||
// ditto.
|
||||
void assign_keeping_region(value&, value);
|
||||
template<typename Region>
|
||||
void change_region(value&, Region&&);
|
||||
}// detail
|
||||
|
||||
template<typename T>
|
||||
@@ -562,8 +562,8 @@ class value
|
||||
// for error messages
|
||||
friend region_base const& detail::get_region(const value&);
|
||||
|
||||
// to see why it's here, see detail::insert_nested_key.
|
||||
friend void detail::assign_keeping_region(value&, value);
|
||||
template<typename Region>
|
||||
friend void detail::change_region(value&, Region&&);
|
||||
|
||||
template<value_t T>
|
||||
struct switch_cast;
|
||||
@@ -599,35 +599,21 @@ inline region_base const& get_region(const value& v)
|
||||
{
|
||||
return *(v.region_info_);
|
||||
}
|
||||
// If we keep region information after assigning another toml::* types, the
|
||||
// error message become different from the actual value contained.
|
||||
// To avoid this kind of confusing phenomena, the default assigners clear the
|
||||
// old region_info_. But this functionality is actually needed deep inside of
|
||||
// parser, so if you want to see the usecase, see toml::detail::insert_nested_key
|
||||
// defined in toml/parser.hpp.
|
||||
inline void assign_keeping_region(value& v, value other)
|
||||
|
||||
template<typename Region>
|
||||
void change_region(value& v, Region&& reg)
|
||||
{
|
||||
v.cleanup(); // this keeps region info
|
||||
// keep region_info_ intact
|
||||
v.type_ = other.type();
|
||||
switch(v.type())
|
||||
{
|
||||
case value_t::Boolean : ::toml::value::assigner(v.boolean_ , other.boolean_ ); break;
|
||||
case value_t::Integer : ::toml::value::assigner(v.integer_ , other.integer_ ); break;
|
||||
case value_t::Float : ::toml::value::assigner(v.floating_ , other.floating_ ); break;
|
||||
case value_t::String : ::toml::value::assigner(v.string_ , other.string_ ); break;
|
||||
case value_t::OffsetDatetime: ::toml::value::assigner(v.offset_datetime_, other.offset_datetime_); break;
|
||||
case value_t::LocalDatetime : ::toml::value::assigner(v.local_datetime_ , other.local_datetime_ ); break;
|
||||
case value_t::LocalDate : ::toml::value::assigner(v.local_date_ , other.local_date_ ); break;
|
||||
case value_t::LocalTime : ::toml::value::assigner(v.local_time_ , other.local_time_ ); break;
|
||||
case value_t::Array : ::toml::value::assigner(v.array_ , other.array_ ); break;
|
||||
case value_t::Table : ::toml::value::assigner(v.table_ , other.table_ ); break;
|
||||
default: break;
|
||||
}
|
||||
using region_type = typename std::remove_reference<
|
||||
typename std::remove_cv<Region>::type
|
||||
>::type;
|
||||
|
||||
std::shared_ptr<region_base> new_reg =
|
||||
std::make_shared<region_type>(std::forward<region_type>(reg));
|
||||
v.region_info_ = new_reg;
|
||||
return;
|
||||
}
|
||||
}// detail
|
||||
|
||||
}// detail
|
||||
|
||||
template<> struct value::switch_cast<value_t::Boolean>
|
||||
{
|
||||
@@ -695,9 +681,11 @@ typename detail::toml_default_type<T>::type& value::cast() &
|
||||
{
|
||||
if(T != this->type_)
|
||||
{
|
||||
throw type_error(format_underline(concat_to_string(
|
||||
"[error] toml::value bad_cast to ", T), *region_info_,
|
||||
concat_to_string("the actual type is ", this->type_)));
|
||||
throw type_error(detail::format_underline(concat_to_string(
|
||||
"[error] toml::value bad_cast to ", T), {
|
||||
{this->region_info_.get(),
|
||||
concat_to_string("the actual type is ", this->type_)}
|
||||
}));
|
||||
}
|
||||
return switch_cast<T>::invoke(*this);
|
||||
}
|
||||
@@ -706,9 +694,11 @@ typename detail::toml_default_type<T>::type const& value::cast() const&
|
||||
{
|
||||
if(T != this->type_)
|
||||
{
|
||||
throw type_error(format_underline(concat_to_string(
|
||||
"[error] toml::value bad_cast to ", T), *region_info_,
|
||||
concat_to_string("the actual type is ", this->type_)));
|
||||
throw type_error(detail::format_underline(concat_to_string(
|
||||
"[error] toml::value bad_cast to ", T), {
|
||||
{this->region_info_.get(),
|
||||
concat_to_string("the actual type is ", this->type_)}
|
||||
}));
|
||||
}
|
||||
return switch_cast<T>::invoke(*this);
|
||||
}
|
||||
@@ -717,9 +707,11 @@ typename detail::toml_default_type<T>::type&& value::cast() &&
|
||||
{
|
||||
if(T != this->type_)
|
||||
{
|
||||
throw type_error(format_underline(concat_to_string(
|
||||
"[error] toml::value bad_cast to ", T), *region_info_,
|
||||
concat_to_string("the actual type is ", this->type_)));
|
||||
throw type_error(detail::format_underline(concat_to_string(
|
||||
"[error] toml::value bad_cast to ", T), {
|
||||
{this->region_info_.get(),
|
||||
concat_to_string("the actual type is ", this->type_)}
|
||||
}));
|
||||
}
|
||||
return switch_cast<T>::invoke(std::move(*this));
|
||||
}
|
||||
@@ -802,22 +794,38 @@ inline bool operator>=(const toml::value& lhs, const toml::value& rhs)
|
||||
return !(lhs < rhs);
|
||||
}
|
||||
|
||||
inline std::string format_error(const std::string& err_msg,
|
||||
const toml::value& v, const std::string& comment,
|
||||
std::vector<std::string> hints = {})
|
||||
namespace detail
|
||||
{
|
||||
return detail::format_underline(err_msg, detail::get_region(v), comment,
|
||||
std::move(hints));
|
||||
inline std::string format_error_impl(const std::string& err_msg,
|
||||
std::vector<std::pair<region_base const*, std::string>> val,
|
||||
std::vector<std::string> hints)
|
||||
{
|
||||
return format_underline(err_msg, std::move(val), std::move(hints));
|
||||
}
|
||||
inline std::string format_error_impl(const std::string& err_msg,
|
||||
std::vector<std::pair<region_base const*, std::string>> val)
|
||||
{
|
||||
return format_underline(err_msg, std::move(val));
|
||||
}
|
||||
|
||||
inline std::string format_error(const std::string& err_msg,
|
||||
const toml::value& v1, const std::string& comment1,
|
||||
const toml::value& v2, const std::string& comment2,
|
||||
std::vector<std::string> hints = {})
|
||||
template<typename ... Ts>
|
||||
std::string format_error_impl(const std::string& err_msg,
|
||||
std::vector<std::pair<region_base const*, std::string>> val,
|
||||
const toml::value& v, const std::string& comment,
|
||||
Ts&& ... args)
|
||||
{
|
||||
return detail::format_underline(err_msg, detail::get_region(v1), comment1,
|
||||
detail::get_region(v2), comment2,
|
||||
std::move(hints));
|
||||
val.push_back(std::make_pair(std::addressof(get_region(v)), comment));
|
||||
return format_error_impl(err_msg, std::move(val), std::forward<Ts>(args)...);
|
||||
}
|
||||
} // detail
|
||||
|
||||
template<typename ... Ts>
|
||||
std::string format_error(const std::string& err_msg, Ts&& ... args)
|
||||
{
|
||||
std::vector<std::pair<detail::region_base const*, std::string>> val;
|
||||
val.reserve(sizeof...(args) / 2);
|
||||
return detail::format_error_impl(err_msg, std::move(val),
|
||||
std::forward<Ts>(args)...);
|
||||
}
|
||||
|
||||
template<typename Visitor>
|
||||
|
||||
Reference in New Issue
Block a user