Compare commits

...

40 Commits

Author SHA1 Message Date
Toru Niina
9eb4008d6d Merge pull request #37 from ToruNiina/to-toml-deprecated
feat: mark to_toml as deprecated
2019-03-15 17:12:45 +09:00
ToruNiina
a04544637b feat: mark to_toml as deprecated
because the constructor of `toml::value()` supports all the stuff that
are supported by `to_toml`.
2019-03-15 14:29:32 +09:00
Toru Niina
4c7dc17b78 Merge pull request #36 from ToruNiina/refactor-format-underline
refactor: remove redundant function overload
2019-03-15 13:41:16 +09:00
ToruNiina
59aaaab436 test: add test to check format_error compiles 2019-03-15 12:40:01 +09:00
ToruNiina
61dfa4a2dc feat: format any number of values into an err msg
```cpp
toml::format_error("[error] message", v1, "v1", v2, "v2", ...);
```
2019-03-15 12:38:37 +09:00
ToruNiina
ca337a1110 chore: merge branch 'master' into travis-ci 2019-03-14 23:02:04 +09:00
ToruNiina
510e10de95 ci: test numerous compilers on CI 2019-03-14 22:58:44 +09:00
ToruNiina
0babe8d589 fix: use format_underline for N regions everywhere 2019-03-14 00:59:10 +09:00
ToruNiina
5b2ce26721 refactor: remove redundant function
since N region format_underline() has been implemented, overloads for 1
and 2 region(s) are not needed.
2019-03-14 00:56:35 +09:00
Toru Niina
db4d99cd4f Merge pull request #35 from ToruNiina/suppress-warning
fix: suppress warning about sign-unsign comparison
2019-03-13 15:01:51 +09:00
ToruNiina
74ceceef73 fix: suppress warning about sign-unsign comparison
The solution is not ideal, but it's okay at the line
2019-03-13 14:03:04 +09:00
Toru Niina
360e890cc0 Merge pull request #34 from ToruNiina/consider-locale
fix: use snprintf instead of stringstream
2019-03-13 09:56:32 +09:00
ToruNiina
46b35870c5 style: remove needless type casting 2019-03-13 01:17:27 +09:00
ToruNiina
dddcecb034 fix: use snprintf instead of stringstream
to avoid the effect of locale
2019-03-12 23:37:46 +09:00
ToruNiina
084e82a8a9 chore: update README 2019-03-07 14:09:02 +09:00
Toru Niina
f5079a7892 Merge pull request #32 from ToruNiina/allow-deeper-table-before
Allow deeper table before
2019-03-06 12:03:14 +09:00
ToruNiina
d90ffb63c6 Merge branch 'master' into allow-deeper-table-before 2019-03-05 23:27:11 +09:00
ToruNiina
b0ed122214 fix: allow deeper table appeared before
allow the following toml file.
```toml
[a.b.c]
d = 10
[a]
e = 2.718
```
2019-03-05 23:25:25 +09:00
ToruNiina
d88521d63c feat: enable to change region of value
To allow the following toml file, we need to replace the region after
the more precise region is found.
```toml
[a.b.c]
d = 42
[a]
e = 2.71
```
If the precise region (here, [a]) is found, the region of `a` should be
`[a]`, not `[a.b.c]`. After `[a]` is defined, toml does not allow to
write `[a]` twice. To check it, we need to replace the region of values
to the precise one.
2019-03-04 15:01:28 +09:00
ToruNiina
2accc9d22c fix: diagnose, but not throw for unicode error
in 2.0.x and 2.1.0, README says "it shows warning" for invalid unicode
codepoints. So far, this library just show an error message in stderr
for this case. It is not good to change the behavior fatal in the next
minor release, 2.1.1, that includes patches and improved error msgs.
I will make it throw syntax_error after 2.2.0 for invalid unicode
codepoints. For now, I will keep it to be "warning".
2019-03-03 18:56:45 +09:00
Toru Niina
363927f489 Merge pull request #31 from ToruNiina/err-msg-inhomogenous-array
improve error messages for invalid arrays
2019-03-02 23:07:29 +09:00
ToruNiina
ae793fb631 feat: improve error message for invalid array 2019-03-02 17:56:16 +09:00
ToruNiina
944b83642a feat: make location to inherit region_base
To generate error message, it is better to have the same interface.
Also, location can be considered as a region having only one character.
2019-03-02 17:52:00 +09:00
Toru Niina
5a8e5dee73 Merge pull request #30 from ToruNiina/hotfix
small patches for parser
2019-03-02 16:11:31 +09:00
ToruNiina
7f870d5861 fix: diagnose invalid UTF-8 codepoints 2019-03-02 01:57:05 +09:00
ToruNiina
536b23dc84 fix: allow empty table in the middle of a file 2019-03-01 22:53:16 +09:00
ToruNiina
0c9806e99f fix: diagnose key after [table.key] pattern
the following is not a valid toml format.
```
[table] key = "value"
```
this commit enables to diagnose that pattern.
2019-03-01 22:37:52 +09:00
ToruNiina
5a92932019 fix: disallow invalid escape sequence 2019-03-01 22:13:32 +09:00
ToruNiina
e929d2f00f fix: allow empty input file (to be an empty table) 2019-02-27 12:30:57 +09:00
Toru Niina
1e1e4c06e8 Merge pull request #29 from ToruNiina/err-msg-dotted-key
Error message for getting values corresponds to dotted keys
2019-02-27 12:21:03 +09:00
ToruNiina
d0726db473 chore: merge branch master into err-msg-dotted-key 2019-02-27 01:26:36 +09:00
Toru Niina
4cdc15a824 Merge pull request #28 from xaxousis/master
Add location to error string in parse_* functions
2019-02-27 01:25:52 +09:00
ToruNiina
b36fdf2f54 refactor: remove internal fn not needed any more
The function was needed to copy region information from value to value,
for a useful error message. Because of the last few commits, the region
information about keys are passed to insert_nested_keys that requires
the function which is removed. And it turned out that the function is no
longer required. It is originally a workaround, so I removed it.
2019-02-27 01:07:00 +09:00
ToruNiina
73ba6b385f feat: use key-region to represent table
use x.y.z = 42
    ~~~ here as the region of the table `x.y`
2019-02-27 01:02:39 +09:00
ToruNiina
30d1639aa4 refactor: return region info from parse_kvpair 2019-02-27 00:21:05 +09:00
Quentin Khan
d82814fc86 Add location to error string in parse_* functions 2019-02-26 14:56:58 +01:00
ToruNiina
2220efd682 chore: show appvayor status of master branch
other branches might be unstable, so they might fail. It is good to show
the status of the stable branch, rather than the experimental branches.
2019-02-26 00:26:04 +09:00
ToruNiina
679b365cf7 feat: get region info when parsing keys
Error messages related to dotted keys looks weird. like:
 1 | a.b.c = 42
   |         ~~ in this table
The underlined token is not a table. This should be like the following.
 1 | a.b.c = 42
   | ~~~ in this table
To implement this, the region information is needed when the keys are
read. This commit add this functionality, though currently the region
information is not used yet.
2019-02-26 00:17:28 +09:00
ToruNiina
83bf83b6dd style: add braces to if and remove additional else 2019-02-19 02:56:15 +09:00
ToruNiina
321364c7c2 fix: format char in an error message correctly 2019-02-19 02:46:48 +09:00
14 changed files with 797 additions and 453 deletions

View File

@@ -12,8 +12,39 @@ matrix:
- ubuntu-toolchain-r-test - ubuntu-toolchain-r-test
packages: packages:
- g++-5 - g++-5
- build-essential - libboost-all-dev
- cmake - 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 - libboost-all-dev
- os: linux - os: linux
language: cpp language: cpp
@@ -26,8 +57,66 @@ matrix:
- llvm-toolchain-precise-3.7 - llvm-toolchain-precise-3.7
packages: packages:
- clang-3.7 - clang-3.7
- build-essential - libboost-all-dev
- cmake - 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 - libboost-all-dev
- os: osx - os: osx
language: cpp language: cpp

View File

@@ -2,12 +2,12 @@ toml11
====== ======
[![Build Status](https://travis-ci.org/ToruNiina/toml11.svg?branch=master)](https://travis-ci.org/ToruNiina/toml11) [![Build Status](https://travis-ci.org/ToruNiina/toml11.svg?branch=master)](https://travis-ci.org/ToruNiina/toml11)
[![Build status](https://ci.appveyor.com/api/projects/status/m2n08a926asvg5mg?svg=true)](https://ci.appveyor.com/project/ToruNiina/toml11) [![Build status](https://ci.appveyor.com/api/projects/status/m2n08a926asvg5mg/branch/master?svg=true)](https://ci.appveyor.com/project/ToruNiina/toml11/branch/master)
[![Version](https://img.shields.io/github/release/ToruNiina/toml11.svg?style=flat)](https://github.com/ToruNiina/toml11/releases) [![Version](https://img.shields.io/github/release/ToruNiina/toml11.svg?style=flat)](https://github.com/ToruNiina/toml11/releases)
[![License](https://img.shields.io/github/license/ToruNiina/toml11.svg?style=flat)](LICENSE) [![License](https://img.shields.io/github/license/ToruNiina/toml11.svg?style=flat)](LICENSE)
[![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.1209136.svg)](https://doi.org/10.5281/zenodo.1209136) [![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.1209136.svg)](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 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) [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 - Intel Compiler support
- Quentin Khan (@xaxousis) - Quentin Khan (@xaxousis)
- Found & Fixed a bug around ODR - Found & Fixed a bug around ODR
- Improved error message to show the location where the parser fails
## Licensing terms ## Licensing terms

View File

@@ -28,6 +28,7 @@ set(TEST_NAMES
test_serialize_file test_serialize_file
test_parse_unicode test_parse_unicode
test_error_detection test_error_detection
test_format_error
) )
CHECK_CXX_COMPILER_FLAG("-Wall" COMPILER_SUPPORTS_WALL) CHECK_CXX_COMPILER_FLAG("-Wall" COMPILER_SUPPORTS_WALL)

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

View File

@@ -13,23 +13,23 @@ using namespace detail;
BOOST_AUTO_TEST_CASE(test_bare_key) BOOST_AUTO_TEST_CASE(test_bare_key)
{ {
TOML11_TEST_PARSE_EQUAL_VALUE(parse_key, "barekey", std::vector<key>(1, "barekey")); TOML11_TEST_PARSE_EQUAL(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(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(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, "1234", std::vector<key>(1, "1234"));
} }
BOOST_AUTO_TEST_CASE(test_quoted_key) 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(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, "\"character encoding\"", std::vector<key>(1, "character encoding"));
#if defined(_MSC_VER) || defined(__INTEL_COMPILER) #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 #else
TOML11_TEST_PARSE_EQUAL_VALUE(parse_key, "\"ʎǝʞ\"", std::vector<key>(1, "ʎǝʞ" )); TOML11_TEST_PARSE_EQUAL(parse_key, "\"ʎǝʞ\"", std::vector<key>(1, "ʎǝʞ" ));
#endif #endif
TOML11_TEST_PARSE_EQUAL_VALUE(parse_key, "'key2'", std::vector<key>(1, "key2" )); TOML11_TEST_PARSE_EQUAL(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, "'quoted \"value\"'", std::vector<key>(1, "quoted \"value\"" ));
} }
BOOST_AUTO_TEST_CASE(test_dotted_key) BOOST_AUTO_TEST_CASE(test_dotted_key)
@@ -38,13 +38,13 @@ BOOST_AUTO_TEST_CASE(test_dotted_key)
std::vector<key> keys(2); std::vector<key> keys(2);
keys[0] = "physical"; keys[0] = "physical";
keys[1] = "color"; 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); std::vector<key> keys(2);
keys[0] = "physical"; keys[0] = "physical";
keys[1] = "shape"; 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); std::vector<key> keys(4);
@@ -52,12 +52,12 @@ BOOST_AUTO_TEST_CASE(test_dotted_key)
keys[1] = "y"; keys[1] = "y";
keys[2] = "z"; keys[2] = "z";
keys[3] = "w"; 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); std::vector<key> keys(2);
keys[0] = "site"; keys[0] = "site";
keys[1] = "google.com"; 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);
} }
} }

View File

@@ -39,7 +39,7 @@ inline std::string show_char(const char c)
else else
{ {
std::ostringstream oss; 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); << static_cast<int>(c);
return oss.str(); return oss.str();
} }

View File

@@ -210,8 +210,9 @@ T get(const value& v)
{ {
throw std::out_of_range(detail::format_underline(concat_to_string( throw std::out_of_range(detail::format_underline(concat_to_string(
"[erorr] toml::get specified container size is ", container.size(), "[erorr] toml::get specified container size is ", container.size(),
" but there are ", ar.size(), " elements in toml array."), " but there are ", ar.size(), " elements in toml array."), {
detail::get_region(v), "here")); {std::addressof(detail::get_region(v)), "here"}
}));
} }
std::transform(ar.cbegin(), ar.cend(), container.begin(), std::transform(ar.cbegin(), ar.cend(), container.begin(),
[](const value& x){return ::toml::get<value_type>(x);}); [](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( throw std::out_of_range(detail::format_underline(concat_to_string(
"[erorr] toml::get specified std::pair but there are ", ar.size(), "[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)), return std::make_pair(::toml::get<first_type >(ar.at(0)),
::toml::get<second_type>(ar.at(1))); ::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( throw std::out_of_range(detail::format_underline(concat_to_string(
"[erorr] toml::get specified std::tuple with ", "[erorr] toml::get specified std::tuple with ",
std::tuple_size<T>::value, "elements, but there are ", ar.size(), 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, return detail::get_tuple_impl<T>(ar,
detail::make_index_sequence<std::tuple_size<T>::value>{}); 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) if(tab.count(ky) == 0)
{ {
throw std::out_of_range(detail::format_underline(concat_to_string( throw std::out_of_range(detail::format_underline(concat_to_string(
"[error] key \"", ky, "\" not found"), detail::get_region(v), "[error] key \"", ky, "\" not found"), {
"in this table")); {std::addressof(detail::get_region(v)), "in this table"}
}));
} }
return ::toml::get<T>(tab.at(ky)); return ::toml::get<T>(tab.at(ky));
} }
@@ -353,8 +359,9 @@ find(toml::value& v, const toml::key& ky)
if(tab.count(ky) == 0) if(tab.count(ky) == 0)
{ {
throw std::out_of_range(detail::format_underline(concat_to_string( throw std::out_of_range(detail::format_underline(concat_to_string(
"[error] key \"", ky, "\" not found"), detail::get_region(v), "[error] key \"", ky, "\" not found"), {
"in this table")); {std::addressof(detail::get_region(v)), "in this table"}
}));
} }
return ::toml::get<T>(tab.at(ky)); return ::toml::get<T>(tab.at(ky));
} }
@@ -366,8 +373,9 @@ find(toml::value&& v, const toml::key& ky)
if(tab.count(ky) == 0) if(tab.count(ky) == 0)
{ {
throw std::out_of_range(detail::format_underline(concat_to_string( throw std::out_of_range(detail::format_underline(concat_to_string(
"[error] key \"", ky, "\" not found"), detail::get_region(v), "[error] key \"", ky, "\" not found"), {
"in this table")); {std::addressof(detail::get_region(v)), "in this table"}
}));
} }
return ::toml::get<T>(std::move(tab[ky])); return ::toml::get<T>(std::move(tab[ky]));
} }

View File

@@ -124,9 +124,9 @@ using lex_escape_unicode_short = sequence<character<'u'>,
using lex_escape_unicode_long = sequence<character<'U'>, using lex_escape_unicode_long = sequence<character<'U'>,
repeat<lex_hex_dig, exactly<8>>>; repeat<lex_hex_dig, exactly<8>>>;
using lex_escape_seq_char = either<character<'"'>, character<'\\'>, using lex_escape_seq_char = either<character<'"'>, character<'\\'>,
character<'/'>, character<'b'>, character<'b'>, character<'f'>,
character<'f'>, character<'n'>, character<'n'>, character<'r'>,
character<'r'>, character<'t'>, character<'t'>,
lex_escape_unicode_short, lex_escape_unicode_short,
lex_escape_unicode_long lex_escape_unicode_long
>; >;

File diff suppressed because it is too large Load Diff

View File

@@ -28,44 +28,6 @@ inline std::string make_string(std::size_t len, char c)
return std::string(len, 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. // region in a container, normally in a file content.
// shared_ptr points the resource that the iter points. // shared_ptr points the resource that the iter points.
// combinators returns this. // combinators returns this.
@@ -86,12 +48,89 @@ struct region_base
virtual std::string line() const {return std::string("unknown line");} virtual std::string line() const {return std::string("unknown line");}
virtual std::string line_num() const {return std::string("?");} virtual std::string line_num() const {return std::string("?");}
virtual std::size_t before() const noexcept {return 0;} virtual std::size_t before() const noexcept {return 0;}
virtual std::size_t size() const noexcept {return 0;} virtual std::size_t size() const noexcept {return 0;}
virtual std::size_t after() 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> template<typename Container>
struct region final : public region_base struct region final : public region_base
{ {
@@ -200,96 +239,67 @@ struct region final : public region_base
// to show a better error message. // to show a better error message.
inline std::string format_underline(const std::string& 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 = {}) std::vector<std::string> helps = {})
{ {
assert(!reg_com.empty());
#ifdef _WIN32 #ifdef _WIN32
const auto newline = "\r\n"; const auto newline = "\r\n";
#else #else
const char newline = '\n'; const char newline = '\n';
#endif #endif
const auto line = reg.line();
const auto line_number = reg.line_num();
std::string retval; const auto line_num_width = std::max_element(reg_com.begin(), reg_com.end(),
retval += message; [](std::pair<region_base const*, std::string> const& lhs,
retval += newline; std::pair<region_base const*, std::string> const& rhs)
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)
{ {
retval += newline; return lhs.first->line_num().size() < rhs.first->line_num().size();
retval += "Hint: ";
retval += help;
} }
} )->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());
std::ostringstream retval; std::ostringstream retval;
retval << message << newline; retval << message << newline;
retval << " --> " << reg1.name() << newline;
// --------------------------------------- for(std::size_t i=0; i<reg_com.size(); ++i)
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())
{ {
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) if(helps.size() != 0)
{ {
retval << newline; retval << newline;
@@ -305,62 +315,6 @@ inline std::string format_underline(const std::string& message,
return retval.str(); 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 } // detail
} // toml } // toml
#endif// TOML11_REGION_H #endif// TOML11_REGION_H

View File

@@ -5,6 +5,7 @@
#include "value.hpp" #include "value.hpp"
#include "lexer.hpp" #include "lexer.hpp"
#include <limits> #include <limits>
#include <cstdio>
namespace toml namespace toml
{ {
@@ -30,13 +31,12 @@ struct serializer
} }
std::string operator()(const toml::floating f) const std::string operator()(const toml::floating f) const
{ {
std::string token = [=] { const auto fmt = "%.*g";
// every float value needs decimal point (or exponent). const auto bsz = std::snprintf(nullptr, 0, fmt, this->float_prec_, f);
std::ostringstream oss; std::vector<char> buf(bsz + 1, '\0'); // +1 for null character(\0)
oss << std::setprecision(float_prec_) << std::showpoint << f; std::snprintf(buf.data(), buf.size(), fmt, this->float_prec_, f);
return oss.str();
}();
std::string token(buf.begin(), buf.end());
if(token.back() == '.') // 1. => 1.0 if(token.back() == '.') // 1. => 1.0
{ {
token += '0'; token += '0';

View File

@@ -8,32 +8,38 @@ namespace toml
{ {
template<typename T> template<typename T>
TOML11_MARK_AS_DEPRECATED
inline value to_toml(T&& x) inline value to_toml(T&& x)
{ {
return value(std::forward<T>(x)); return value(std::forward<T>(x));
} }
template<typename T> template<typename T>
TOML11_MARK_AS_DEPRECATED
inline value to_toml(T&& x, string_t kind) inline value to_toml(T&& x, string_t kind)
{ {
return value(std::forward<T>(x), kind); return value(std::forward<T>(x), kind);
} }
TOML11_MARK_AS_DEPRECATED
inline value to_toml(local_date d, local_time t) inline value to_toml(local_date d, local_time t)
{ {
return value(local_datetime(d, t)); return value(local_datetime(d, t));
} }
TOML11_MARK_AS_DEPRECATED
inline value to_toml(local_date d, local_time t, time_offset ofs) inline value to_toml(local_date d, local_time t, time_offset ofs)
{ {
return value(offset_datetime(d, t, ofs)); return value(offset_datetime(d, t, ofs));
} }
template<typename ... Ts> template<typename ... Ts>
TOML11_MARK_AS_DEPRECATED
inline value to_toml(Ts&& ... xs) inline value to_toml(Ts&& ... xs)
{ {
return value(toml::array{toml::value(std::forward<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) inline value to_toml(std::initializer_list<std::pair<std::string, toml::value>> xs)
{ {
return value(toml::table(xs.begin(), xs.end())); return value(toml::table(xs.begin(), xs.end()));

View File

@@ -7,6 +7,16 @@
#include <memory> #include <memory>
#include <sstream> #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 namespace toml
{ {
@@ -29,8 +39,9 @@ inline void resize_impl(T& container, std::size_t N, std::true_type)
template<typename T> template<typename T>
inline void resize_impl(T& container, std::size_t N, std::false_type) inline void resize_impl(T& container, std::size_t N, std::false_type)
{ {
if(container.size() >= N) return; if(container.size() >= N) {return;}
else throw std::invalid_argument("not resizable type");
throw std::invalid_argument("not resizable type");
} }
} // detail } // detail
@@ -38,8 +49,9 @@ inline void resize_impl(T& container, std::size_t N, std::false_type)
template<typename T> template<typename T>
inline void resize(T& container, std::size_t N) inline void resize(T& container, std::size_t N)
{ {
if(container.size() == N) return; if(container.size() == N) {return;}
else return detail::resize_impl(container, N, detail::has_resize_method<T>());
return detail::resize_impl(container, N, detail::has_resize_method<T>());
} }
namespace detail namespace detail
@@ -73,7 +85,5 @@ T from_string(const std::string& str, U&& opt)
return v; return v;
} }
}// toml }// toml
#endif // TOML11_UTILITY #endif // TOML11_UTILITY

View File

@@ -21,8 +21,8 @@ namespace detail
{ {
// to show error messages. not recommended for users. // to show error messages. not recommended for users.
region_base const& get_region(const value&); region_base const& get_region(const value&);
// ditto. template<typename Region>
void assign_keeping_region(value&, value); void change_region(value&, Region&&);
}// detail }// detail
template<typename T> template<typename T>
@@ -562,8 +562,8 @@ class value
// for error messages // for error messages
friend region_base const& detail::get_region(const value&); friend region_base const& detail::get_region(const value&);
// to see why it's here, see detail::insert_nested_key. template<typename Region>
friend void detail::assign_keeping_region(value&, value); friend void detail::change_region(value&, Region&&);
template<value_t T> template<value_t T>
struct switch_cast; struct switch_cast;
@@ -599,35 +599,21 @@ inline region_base const& get_region(const value& v)
{ {
return *(v.region_info_); return *(v.region_info_);
} }
// If we keep region information after assigning another toml::* types, the
// error message become different from the actual value contained. template<typename Region>
// To avoid this kind of confusing phenomena, the default assigners clear the void change_region(value& v, Region&& reg)
// 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)
{ {
v.cleanup(); // this keeps region info using region_type = typename std::remove_reference<
// keep region_info_ intact typename std::remove_cv<Region>::type
v.type_ = other.type(); >::type;
switch(v.type())
{ std::shared_ptr<region_base> new_reg =
case value_t::Boolean : ::toml::value::assigner(v.boolean_ , other.boolean_ ); break; std::make_shared<region_type>(std::forward<region_type>(reg));
case value_t::Integer : ::toml::value::assigner(v.integer_ , other.integer_ ); break; v.region_info_ = new_reg;
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;
}
return; return;
} }
}// detail
}// detail
template<> struct value::switch_cast<value_t::Boolean> 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_) if(T != this->type_)
{ {
throw type_error(format_underline(concat_to_string( throw type_error(detail::format_underline(concat_to_string(
"[error] toml::value bad_cast to ", T), *region_info_, "[error] toml::value bad_cast to ", T), {
concat_to_string("the actual type is ", this->type_))); {this->region_info_.get(),
concat_to_string("the actual type is ", this->type_)}
}));
} }
return switch_cast<T>::invoke(*this); 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_) if(T != this->type_)
{ {
throw type_error(format_underline(concat_to_string( throw type_error(detail::format_underline(concat_to_string(
"[error] toml::value bad_cast to ", T), *region_info_, "[error] toml::value bad_cast to ", T), {
concat_to_string("the actual type is ", this->type_))); {this->region_info_.get(),
concat_to_string("the actual type is ", this->type_)}
}));
} }
return switch_cast<T>::invoke(*this); return switch_cast<T>::invoke(*this);
} }
@@ -717,9 +707,11 @@ typename detail::toml_default_type<T>::type&& value::cast() &&
{ {
if(T != this->type_) if(T != this->type_)
{ {
throw type_error(format_underline(concat_to_string( throw type_error(detail::format_underline(concat_to_string(
"[error] toml::value bad_cast to ", T), *region_info_, "[error] toml::value bad_cast to ", T), {
concat_to_string("the actual type is ", this->type_))); {this->region_info_.get(),
concat_to_string("the actual type is ", this->type_)}
}));
} }
return switch_cast<T>::invoke(std::move(*this)); 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); return !(lhs < rhs);
} }
inline std::string format_error(const std::string& err_msg, namespace detail
const toml::value& v, const std::string& comment,
std::vector<std::string> hints = {})
{ {
return detail::format_underline(err_msg, detail::get_region(v), comment, inline std::string format_error_impl(const std::string& err_msg,
std::move(hints)); 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, template<typename ... Ts>
const toml::value& v1, const std::string& comment1, std::string format_error_impl(const std::string& err_msg,
const toml::value& v2, const std::string& comment2, std::vector<std::pair<region_base const*, std::string>> val,
std::vector<std::string> hints = {}) const toml::value& v, const std::string& comment,
Ts&& ... args)
{ {
return detail::format_underline(err_msg, detail::get_region(v1), comment1, val.push_back(std::make_pair(std::addressof(get_region(v)), comment));
detail::get_region(v2), comment2, return format_error_impl(err_msg, std::move(val), std::forward<Ts>(args)...);
std::move(hints)); }
} // 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> template<typename Visitor>