mirror of
https://github.com/ToruNiina/toml11.git
synced 2025-12-16 03:08:52 +08:00
Merge branch 'master' into hotfix
This commit is contained in:
45
.circleci/config.yml
Normal file
45
.circleci/config.yml
Normal file
@@ -0,0 +1,45 @@
|
||||
version: 2.1
|
||||
|
||||
jobs:
|
||||
test:
|
||||
docker:
|
||||
- image: circleci/buildpack-deps:bionic
|
||||
steps:
|
||||
- checkout
|
||||
- run:
|
||||
command: |
|
||||
g++ --version
|
||||
cd tests/
|
||||
ls
|
||||
g++ -std=c++11 -O2 -Wall -Wextra -Werror -I../ check.cpp -o check
|
||||
git clone https://github.com/BurntSushi/toml-test.git
|
||||
cp check toml-test/tests/invalid
|
||||
cp check toml-test/tests/valid
|
||||
cd toml-test/tests/invalid
|
||||
for f in $(ls ./*.toml);
|
||||
do echo "==> ${f}";
|
||||
cat ${f};
|
||||
echo "---------------------------------------";
|
||||
./check ${f} invalid;
|
||||
if [ $? -ne 0 ] ; then
|
||||
exit 1
|
||||
fi
|
||||
echo "=======================================";
|
||||
done
|
||||
cd ../valid
|
||||
for f in $(ls ./*.toml);
|
||||
do echo "==> ${f}";
|
||||
cat ${f};
|
||||
echo "---------------------------------------";
|
||||
./check ${f} valid;
|
||||
if [ $? -ne 0 ] ; then
|
||||
exit 1
|
||||
fi
|
||||
echo "=======================================";
|
||||
done
|
||||
|
||||
workflows:
|
||||
version: 2.1
|
||||
test:
|
||||
jobs:
|
||||
- test
|
||||
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
|
||||
|
||||
181
README.md
181
README.md
@@ -7,7 +7,7 @@ toml11
|
||||
[](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)
|
||||
@@ -387,7 +387,31 @@ If it's not a `toml::table`, the same error as "invalid type" would be thrown.
|
||||
|
||||
### Checking value type
|
||||
|
||||
When you don't know the exact type of toml-value, you can get `enum` type from `toml::value`.
|
||||
You can check what type of value does `toml::value` contains by `is_*` function.
|
||||
|
||||
```cpp
|
||||
toml::value v = /* ... */;
|
||||
if(v.is_integer() && toml::get<int>(v) == 42)
|
||||
{
|
||||
std::cout << "value is 42" << std::endl;
|
||||
}
|
||||
```
|
||||
|
||||
The complete list of the functions is below.
|
||||
|
||||
- `bool toml::value::is_boolean() const noexcept;`
|
||||
- `bool toml::value::is_integer() const noexcept;`
|
||||
- `bool toml::value::is_float() const noexcept;`
|
||||
- `bool toml::value::is_string() const noexcept;`
|
||||
- `bool toml::value::is_offset_datetime() const noexcept;`
|
||||
- `bool toml::value::is_local_datetime() const noexcept;`
|
||||
- `bool toml::value::is_local_date() const noexcept;`
|
||||
- `bool toml::value::is_local_time() const noexcept;`
|
||||
- `bool toml::value::is_array() const noexcept;`
|
||||
- `bool toml::value::is_table() const noexcept;`
|
||||
- `bool toml::value::is_uninitialized() const noexcept;`
|
||||
|
||||
Also, you can get `enum class` value from `toml::value`.
|
||||
|
||||
```cpp
|
||||
switch(data.at("something").type())
|
||||
@@ -400,6 +424,16 @@ switch(data.at("something").type())
|
||||
}
|
||||
```
|
||||
|
||||
The complete list of the `enum`s can be found in the section
|
||||
[underlying types](#underlying-types).
|
||||
|
||||
The `enum`s can be used as a parameter of `toml::value::is` function like the following.
|
||||
|
||||
```cpp
|
||||
toml::value v = /* ... */;
|
||||
if(v.is(toml::value_t::Boolean)) // ...
|
||||
```
|
||||
|
||||
### Fill only the matched value
|
||||
|
||||
The more sophisticated way is using `toml::from_toml` and `std::tie`.
|
||||
@@ -423,6 +457,148 @@ int i = 0;
|
||||
toml::from_toml(i, data.at("something"));
|
||||
```
|
||||
|
||||
### Conversion between toml value and your class
|
||||
|
||||
You can also use `toml::get` and other related functions with the types you defined
|
||||
after you implement some stuff.
|
||||
|
||||
```cpp
|
||||
namespace ext
|
||||
{
|
||||
struct foo
|
||||
{
|
||||
int a;
|
||||
double b;
|
||||
std::string c;
|
||||
};
|
||||
} // ext
|
||||
|
||||
const auto data = toml::parse("example.toml");
|
||||
|
||||
const foo f = toml::get<ext::foo>(data.at("foo"));
|
||||
```
|
||||
|
||||
There are 2 ways to use `toml::get` with the types that you defined.
|
||||
|
||||
The first one is to implement `from_toml(const toml::value&)` member function.
|
||||
|
||||
```cpp
|
||||
namespace ext
|
||||
{
|
||||
struct foo
|
||||
{
|
||||
int a;
|
||||
double b;
|
||||
std::string c;
|
||||
|
||||
void from_toml(const toml::value& v)
|
||||
{
|
||||
this->a = toml::find<int >(v, "a");
|
||||
this->b = toml::find<double >(v, "b");
|
||||
this->c = toml::find<std::string>(v, "c");
|
||||
return;
|
||||
}
|
||||
};
|
||||
} // ext
|
||||
```
|
||||
|
||||
In this way, because `toml::get` first constructs `foo` without arguments,
|
||||
the type should be default-constructible.
|
||||
|
||||
The second is to implement specialization of `toml::from` for your type.
|
||||
|
||||
```cpp
|
||||
namespace ext
|
||||
{
|
||||
struct foo
|
||||
{
|
||||
int a;
|
||||
double b;
|
||||
std::string c;
|
||||
};
|
||||
} // ext
|
||||
|
||||
namespace toml
|
||||
{
|
||||
template<>
|
||||
struct from<ext::foo>
|
||||
{
|
||||
ext::foo from_toml(const toml::value& v)
|
||||
{
|
||||
ext::foo f;
|
||||
f.a = toml::find<int >(v, "a");
|
||||
f.b = toml::find<double >(v, "b");
|
||||
f.c = toml::find<std::string>(v, "c");
|
||||
return f;
|
||||
}
|
||||
};
|
||||
} // toml
|
||||
```
|
||||
|
||||
In this way, since the conversion function is introduced from out of the class,
|
||||
you can add conversion between `toml::value` and classes defined in another library.
|
||||
|
||||
Note that you cannot implement both of the functions because the overload
|
||||
resolution of `toml::get` become ambiguous.
|
||||
|
||||
----
|
||||
|
||||
The opposite direction is also supported in a similar way. You can directly
|
||||
pass your type to `toml::value`'s constructor by introducing `into_iter` or
|
||||
`toml::into<T>`.
|
||||
|
||||
```cpp
|
||||
namespace ext
|
||||
{
|
||||
struct foo
|
||||
{
|
||||
int a;
|
||||
double b;
|
||||
std::string c;
|
||||
|
||||
toml::table into_toml() const // you need to mark it const.
|
||||
{
|
||||
return toml::table{{"a", this->a}, {"b", this->b}, {"c", this->c}};
|
||||
}
|
||||
};
|
||||
} // ext
|
||||
|
||||
ext::foo f{42, 3.14, "foobar"};
|
||||
toml::value v(f);
|
||||
```
|
||||
|
||||
The definition of `toml::into<ext::foo>` is similar to `from_toml()`.
|
||||
|
||||
```cpp
|
||||
namespace ext
|
||||
{
|
||||
struct foo
|
||||
{
|
||||
int a;
|
||||
double b;
|
||||
std::string c;
|
||||
};
|
||||
} // ext
|
||||
|
||||
namespace toml
|
||||
{
|
||||
template<>
|
||||
struct into<ext::foo>
|
||||
{
|
||||
toml::table into_toml(const ext::foo& v)
|
||||
{
|
||||
return toml::table{{"a", this->a}, {"b", this->b}, {"c", this->c}};
|
||||
}
|
||||
};
|
||||
} // toml
|
||||
|
||||
ext::foo f{42, 3.14, "foobar"};
|
||||
toml::value v(f);
|
||||
```
|
||||
|
||||
Any type that can be converted to `toml::value`, e.g. `toml::table`, `toml::array`,
|
||||
is okay to return from `into_toml`.
|
||||
|
||||
### visiting toml::value
|
||||
|
||||
TOML v2.1.0+ provides `toml::visit` to apply a function to `toml::value` in the
|
||||
@@ -642,6 +818,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
|
||||
|
||||
|
||||
@@ -22,12 +22,13 @@ set(TEST_NAMES
|
||||
test_parse_table_key
|
||||
test_get
|
||||
test_get_related_func
|
||||
test_to_toml
|
||||
test_from_toml
|
||||
test_parse_file
|
||||
test_serialize_file
|
||||
test_parse_unicode
|
||||
test_error_detection
|
||||
test_format_error
|
||||
test_extended_conversions
|
||||
)
|
||||
|
||||
CHECK_CXX_COMPILER_FLAG("-Wall" COMPILER_SUPPORTS_WALL)
|
||||
|
||||
41
tests/check.cpp
Normal file
41
tests/check.cpp
Normal file
@@ -0,0 +1,41 @@
|
||||
#include "toml.hpp"
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
if(argc != 3)
|
||||
{
|
||||
std::cerr << "usage: ./check [filename] [valid|invalid]" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
const std::string file_kind(argv[2]);
|
||||
|
||||
try
|
||||
{
|
||||
const auto data = toml::parse(argv[1]);
|
||||
std::cout << std::setprecision(16) << std::setw(80) << data;
|
||||
if(file_kind == "valid")
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
catch(const toml::syntax_error& err)
|
||||
{
|
||||
std::cout << "what(): " << err.what() << std::endl;
|
||||
if(file_kind == "invalid")
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 127;
|
||||
}
|
||||
116
tests/test_extended_conversions.cpp
Normal file
116
tests/test_extended_conversions.cpp
Normal file
@@ -0,0 +1,116 @@
|
||||
#define BOOST_TEST_MODULE "test_extended_conversions"
|
||||
#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>
|
||||
|
||||
namespace extlib
|
||||
{
|
||||
struct foo
|
||||
{
|
||||
int a;
|
||||
std::string b;
|
||||
};
|
||||
struct bar
|
||||
{
|
||||
int a;
|
||||
std::string b;
|
||||
|
||||
void from_toml(const toml::value& v)
|
||||
{
|
||||
this->a = toml::find<int>(v, "a");
|
||||
this->b = toml::find<std::string>(v, "b");
|
||||
return ;
|
||||
}
|
||||
|
||||
toml::table into_toml() const
|
||||
{
|
||||
return toml::table{{"a", this->a}, {"b", this->b}};
|
||||
}
|
||||
};
|
||||
} // extlib
|
||||
|
||||
namespace toml
|
||||
{
|
||||
template<>
|
||||
struct from<extlib::foo>
|
||||
{
|
||||
static extlib::foo from_toml(const toml::value& v)
|
||||
{
|
||||
return extlib::foo{toml::find<int>(v, "a"), toml::find<std::string>(v, "b")};
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct into<extlib::foo>
|
||||
{
|
||||
static toml::table into_toml(const extlib::foo& f)
|
||||
{
|
||||
return toml::table{{"a", f.a}, {"b", f.b}};
|
||||
}
|
||||
};
|
||||
} // toml
|
||||
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_conversion_by_member_methods)
|
||||
{
|
||||
const toml::value v{{"a", 42}, {"b", "baz"}};
|
||||
|
||||
const auto foo = toml::get<extlib::foo>(v);
|
||||
BOOST_CHECK_EQUAL(foo.a, 42);
|
||||
BOOST_CHECK_EQUAL(foo.b, "baz");
|
||||
|
||||
const toml::value v2(foo);
|
||||
|
||||
BOOST_CHECK_EQUAL(v, v2);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_conversion_by_specialization)
|
||||
{
|
||||
const toml::value v{{"a", 42}, {"b", "baz"}};
|
||||
|
||||
const auto bar = toml::get<extlib::bar>(v);
|
||||
BOOST_CHECK_EQUAL(bar.a, 42);
|
||||
BOOST_CHECK_EQUAL(bar.b, "baz");
|
||||
|
||||
const toml::value v2(bar);
|
||||
|
||||
BOOST_CHECK_EQUAL(v, v2);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_recursive_conversion)
|
||||
{
|
||||
const toml::value v{
|
||||
toml::table{{"a", 42}, {"b", "baz"}},
|
||||
toml::table{{"a", 43}, {"b", "qux"}},
|
||||
toml::table{{"a", 44}, {"b", "quux"}},
|
||||
toml::table{{"a", 45}, {"b", "foobar"}},
|
||||
};
|
||||
|
||||
const auto foos = toml::get<std::vector<extlib::foo>>(v);
|
||||
BOOST_CHECK_EQUAL(foos.size() , 4ul);
|
||||
BOOST_CHECK_EQUAL(foos.at(0).a , 42);
|
||||
BOOST_CHECK_EQUAL(foos.at(1).a , 43);
|
||||
BOOST_CHECK_EQUAL(foos.at(2).a , 44);
|
||||
BOOST_CHECK_EQUAL(foos.at(3).a , 45);
|
||||
|
||||
BOOST_CHECK_EQUAL(foos.at(0).b , "baz");
|
||||
BOOST_CHECK_EQUAL(foos.at(1).b , "qux");
|
||||
BOOST_CHECK_EQUAL(foos.at(2).b , "quux");
|
||||
BOOST_CHECK_EQUAL(foos.at(3).b , "foobar");
|
||||
|
||||
const auto bars = toml::get<std::vector<extlib::bar>>(v);
|
||||
BOOST_CHECK_EQUAL(bars.size() , 4ul);
|
||||
BOOST_CHECK_EQUAL(bars.at(0).a , 42);
|
||||
BOOST_CHECK_EQUAL(bars.at(1).a , 43);
|
||||
BOOST_CHECK_EQUAL(bars.at(2).a , 44);
|
||||
BOOST_CHECK_EQUAL(bars.at(3).a , 45);
|
||||
|
||||
BOOST_CHECK_EQUAL(bars.at(0).b , "baz");
|
||||
BOOST_CHECK_EQUAL(bars.at(1).b , "qux");
|
||||
BOOST_CHECK_EQUAL(bars.at(2).b , "quux");
|
||||
BOOST_CHECK_EQUAL(bars.at(3).b , "foobar");
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -1,189 +0,0 @@
|
||||
#define BOOST_TEST_MODULE "test_to_toml"
|
||||
#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>
|
||||
#include <map>
|
||||
#include <list>
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_value_boolean)
|
||||
{
|
||||
toml::value v1 = toml::to_toml(true);
|
||||
toml::value v2 = toml::to_toml(false);
|
||||
|
||||
BOOST_CHECK_EQUAL(v1.type(), toml::value_t::Boolean);
|
||||
BOOST_CHECK_EQUAL(v2.type(), toml::value_t::Boolean);
|
||||
BOOST_CHECK(v1.is(toml::value_t::Boolean));
|
||||
BOOST_CHECK(v2.is(toml::value_t::Boolean));
|
||||
BOOST_CHECK(v1.is<toml::Boolean>());
|
||||
BOOST_CHECK(v2.is<toml::Boolean>());
|
||||
|
||||
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::Boolean>(), true);
|
||||
BOOST_CHECK_EQUAL(v2.cast<toml::value_t::Boolean>(), false);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_value_integer)
|
||||
{
|
||||
toml::value v1 = toml::to_toml(-42);
|
||||
toml::value v2 = toml::to_toml(42u);
|
||||
|
||||
BOOST_CHECK_EQUAL(v1.type(), toml::value_t::Integer);
|
||||
BOOST_CHECK_EQUAL(v2.type(), toml::value_t::Integer);
|
||||
BOOST_CHECK(v1.is(toml::value_t::Integer));
|
||||
BOOST_CHECK(v2.is(toml::value_t::Integer));
|
||||
BOOST_CHECK(v1.is<toml::Integer>());
|
||||
BOOST_CHECK(v2.is<toml::Integer>());
|
||||
|
||||
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::Integer>(), -42);
|
||||
BOOST_CHECK_EQUAL(v2.cast<toml::value_t::Integer>(), 42u);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_value_float)
|
||||
{
|
||||
toml::value v1 = toml::to_toml(3.14);
|
||||
toml::value v2 = toml::to_toml(3.14f);
|
||||
|
||||
BOOST_CHECK_EQUAL(v1.type(), toml::value_t::Float);
|
||||
BOOST_CHECK_EQUAL(v2.type(), toml::value_t::Float);
|
||||
BOOST_CHECK(v1.is(toml::value_t::Float));
|
||||
BOOST_CHECK(v2.is(toml::value_t::Float));
|
||||
BOOST_CHECK(v1.is<toml::Float>());
|
||||
BOOST_CHECK(v2.is<toml::Float>());
|
||||
|
||||
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::Float>(), 3.14);
|
||||
BOOST_CHECK_CLOSE_FRACTION(v2.cast<toml::value_t::Float>(), 3.14, 1e-2);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_value_string)
|
||||
{
|
||||
toml::value v1 = toml::to_toml(std::string("foo"));
|
||||
toml::value v2 = toml::to_toml(std::string("foo"), toml::string_t::literal);
|
||||
toml::value v3 = toml::to_toml("foo");
|
||||
|
||||
BOOST_CHECK_EQUAL(v1.type(), toml::value_t::String);
|
||||
BOOST_CHECK_EQUAL(v2.type(), toml::value_t::String);
|
||||
BOOST_CHECK_EQUAL(v3.type(), toml::value_t::String);
|
||||
BOOST_CHECK(v1.is(toml::value_t::String));
|
||||
BOOST_CHECK(v2.is(toml::value_t::String));
|
||||
BOOST_CHECK(v3.is(toml::value_t::String));
|
||||
BOOST_CHECK(v1.is<toml::String>());
|
||||
BOOST_CHECK(v2.is<toml::String>());
|
||||
BOOST_CHECK(v3.is<toml::String>());
|
||||
|
||||
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::String>(), "foo");
|
||||
BOOST_CHECK_EQUAL(v2.cast<toml::value_t::String>(), "foo");
|
||||
BOOST_CHECK_EQUAL(v3.cast<toml::value_t::String>(), "foo");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_value_local_date)
|
||||
{
|
||||
toml::value v1 = toml::to_toml(toml::local_date(2018, toml::month_t::Jan, 31));
|
||||
|
||||
BOOST_CHECK_EQUAL(v1.type(), toml::value_t::LocalDate);
|
||||
BOOST_CHECK(v1.is(toml::value_t::LocalDate));
|
||||
BOOST_CHECK(v1.is<toml::LocalDate>());
|
||||
|
||||
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::LocalDate>(),
|
||||
toml::local_date(2018, toml::month_t::Jan, 31));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_value_local_time)
|
||||
{
|
||||
toml::value v1 = toml::to_toml(toml::local_time(12, 30, 45));
|
||||
toml::value v2 = toml::to_toml(std::chrono::hours(12) + std::chrono::minutes(30) +
|
||||
std::chrono::seconds(45));
|
||||
|
||||
BOOST_CHECK_EQUAL(v1.type(), toml::value_t::LocalTime);
|
||||
BOOST_CHECK_EQUAL(v2.type(), toml::value_t::LocalTime);
|
||||
BOOST_CHECK(v1.is(toml::value_t::LocalTime));
|
||||
BOOST_CHECK(v2.is(toml::value_t::LocalTime));
|
||||
BOOST_CHECK(v1.is<toml::LocalTime>());
|
||||
BOOST_CHECK(v2.is<toml::LocalTime>());
|
||||
|
||||
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::LocalTime>(),
|
||||
toml::local_time(12, 30, 45));
|
||||
BOOST_CHECK_EQUAL(v2.cast<toml::value_t::LocalTime>(),
|
||||
toml::local_time(12, 30, 45));
|
||||
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::LocalTime>(),
|
||||
v2.cast<toml::value_t::LocalTime>());
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_value_local_datetime)
|
||||
{
|
||||
toml::value v1 = toml::to_toml(toml::local_datetime(
|
||||
toml::local_date(2018, toml::month_t::Jan, 31),
|
||||
toml::local_time(12, 30, 45)
|
||||
));
|
||||
|
||||
BOOST_CHECK_EQUAL(v1.type(), toml::value_t::LocalDatetime);
|
||||
BOOST_CHECK(v1.is(toml::value_t::LocalDatetime));
|
||||
BOOST_CHECK(v1.is<toml::LocalDatetime>());
|
||||
|
||||
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::LocalDatetime>(),
|
||||
toml::local_datetime(
|
||||
toml::local_date(2018, toml::month_t::Jan, 31),
|
||||
toml::local_time(12, 30, 45)));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_value_offset_datetime)
|
||||
{
|
||||
toml::value v1 = toml::to_toml(toml::offset_datetime(
|
||||
toml::local_date(2018, toml::month_t::Jan, 31),
|
||||
toml::local_time(12, 30, 45),
|
||||
toml::time_offset(9, 0)
|
||||
));
|
||||
|
||||
BOOST_CHECK_EQUAL(v1.type(), toml::value_t::OffsetDatetime);
|
||||
BOOST_CHECK(v1.is(toml::value_t::OffsetDatetime));
|
||||
BOOST_CHECK(v1.is<toml::OffsetDatetime>());
|
||||
|
||||
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::OffsetDatetime>(),
|
||||
toml::offset_datetime(
|
||||
toml::local_date(2018, toml::month_t::Jan, 31),
|
||||
toml::local_time(12, 30, 45),
|
||||
toml::time_offset(9, 0)
|
||||
));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_value_array)
|
||||
{
|
||||
std::vector<int> v{1,2,3,4,5};
|
||||
toml::value v1 = toml::to_toml(v);
|
||||
toml::value v2 = toml::to_toml(6,7,8,9,0);
|
||||
|
||||
BOOST_CHECK_EQUAL(v1.type(), toml::value_t::Array);
|
||||
BOOST_CHECK(v1.is(toml::value_t::Array));
|
||||
BOOST_CHECK(v1.is<toml::Array>());
|
||||
|
||||
BOOST_CHECK_EQUAL(v2.type(), toml::value_t::Array);
|
||||
BOOST_CHECK(v2.is(toml::value_t::Array));
|
||||
BOOST_CHECK(v2.is<toml::Array>());
|
||||
|
||||
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::Array>().at(0).cast<toml::value_t::Integer>(), 1);
|
||||
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::Array>().at(1).cast<toml::value_t::Integer>(), 2);
|
||||
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::Array>().at(2).cast<toml::value_t::Integer>(), 3);
|
||||
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::Array>().at(3).cast<toml::value_t::Integer>(), 4);
|
||||
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::Array>().at(4).cast<toml::value_t::Integer>(), 5);
|
||||
|
||||
BOOST_CHECK_EQUAL(v2.cast<toml::value_t::Array>().at(0).cast<toml::value_t::Integer>(), 6);
|
||||
BOOST_CHECK_EQUAL(v2.cast<toml::value_t::Array>().at(1).cast<toml::value_t::Integer>(), 7);
|
||||
BOOST_CHECK_EQUAL(v2.cast<toml::value_t::Array>().at(2).cast<toml::value_t::Integer>(), 8);
|
||||
BOOST_CHECK_EQUAL(v2.cast<toml::value_t::Array>().at(3).cast<toml::value_t::Integer>(), 9);
|
||||
BOOST_CHECK_EQUAL(v2.cast<toml::value_t::Array>().at(4).cast<toml::value_t::Integer>(), 0);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_value_table)
|
||||
{
|
||||
toml::value v1 = toml::to_toml({{"foo", 42}, {"bar", 3.14}, {"baz", "qux"}});
|
||||
|
||||
BOOST_CHECK_EQUAL(v1.type(), toml::value_t::Table);
|
||||
BOOST_CHECK(v1.is(toml::value_t::Table));
|
||||
BOOST_CHECK(v1.is<toml::Table>());
|
||||
|
||||
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::Table>().at("foo").cast<toml::value_t::Integer>(), 42);
|
||||
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::Table>().at("bar").cast<toml::value_t::Float>(), 3.14);
|
||||
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::Table>().at("baz").cast<toml::value_t::String>().str, "qux");
|
||||
}
|
||||
@@ -20,6 +20,8 @@ BOOST_AUTO_TEST_CASE(test_value_boolean)
|
||||
BOOST_CHECK(v2.is(toml::value_t::Boolean));
|
||||
BOOST_CHECK(v1.is<toml::Boolean>());
|
||||
BOOST_CHECK(v2.is<toml::Boolean>());
|
||||
BOOST_CHECK(v1.is_boolean());
|
||||
BOOST_CHECK(v2.is_boolean());
|
||||
|
||||
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::Boolean>(), true);
|
||||
BOOST_CHECK_EQUAL(v2.cast<toml::value_t::Boolean>(), false);
|
||||
@@ -33,6 +35,8 @@ BOOST_AUTO_TEST_CASE(test_value_boolean)
|
||||
BOOST_CHECK(v2.is(toml::value_t::Boolean));
|
||||
BOOST_CHECK(v1.is<toml::Boolean>());
|
||||
BOOST_CHECK(v2.is<toml::Boolean>());
|
||||
BOOST_CHECK(v1.is_boolean());
|
||||
BOOST_CHECK(v2.is_boolean());
|
||||
|
||||
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::Boolean>(), false);
|
||||
BOOST_CHECK_EQUAL(v2.cast<toml::value_t::Boolean>(), true);
|
||||
@@ -48,6 +52,8 @@ BOOST_AUTO_TEST_CASE(test_value_boolean)
|
||||
BOOST_CHECK(v4.is(toml::value_t::Boolean));
|
||||
BOOST_CHECK(v3.is<toml::Boolean>());
|
||||
BOOST_CHECK(v4.is<toml::Boolean>());
|
||||
BOOST_CHECK(v3.is_boolean());
|
||||
BOOST_CHECK(v4.is_boolean());
|
||||
|
||||
BOOST_CHECK_EQUAL(v3.cast<toml::value_t::Boolean>(), false);
|
||||
BOOST_CHECK_EQUAL(v4.cast<toml::value_t::Boolean>(), true);
|
||||
@@ -61,6 +67,8 @@ BOOST_AUTO_TEST_CASE(test_value_boolean)
|
||||
BOOST_CHECK(v6.is(toml::value_t::Boolean));
|
||||
BOOST_CHECK(v5.is<toml::Boolean>());
|
||||
BOOST_CHECK(v6.is<toml::Boolean>());
|
||||
BOOST_CHECK(v3.is_boolean());
|
||||
BOOST_CHECK(v4.is_boolean());
|
||||
|
||||
BOOST_CHECK_EQUAL(v5.cast<toml::value_t::Boolean>(), false);
|
||||
BOOST_CHECK_EQUAL(v6.cast<toml::value_t::Boolean>(), true);
|
||||
@@ -74,6 +82,8 @@ BOOST_AUTO_TEST_CASE(test_value_boolean)
|
||||
BOOST_CHECK(v2.is(toml::value_t::Float));
|
||||
BOOST_CHECK(v1.is<toml::Integer>());
|
||||
BOOST_CHECK(v2.is<toml::Float>());
|
||||
BOOST_CHECK(v1.is_integer());
|
||||
BOOST_CHECK(v2.is_float());
|
||||
|
||||
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::Integer>(), 42);
|
||||
BOOST_CHECK_EQUAL(v2.cast<toml::value_t::Float>(), 3.14);
|
||||
@@ -90,6 +100,8 @@ BOOST_AUTO_TEST_CASE(test_value_integer)
|
||||
BOOST_CHECK(v2.is(toml::value_t::Integer));
|
||||
BOOST_CHECK(v1.is<toml::Integer>());
|
||||
BOOST_CHECK(v2.is<toml::Integer>());
|
||||
BOOST_CHECK(v1.is_integer());
|
||||
BOOST_CHECK(v2.is_integer());
|
||||
|
||||
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::Integer>(), -42);
|
||||
BOOST_CHECK_EQUAL(v2.cast<toml::value_t::Integer>(), 42u);
|
||||
@@ -103,6 +115,8 @@ BOOST_AUTO_TEST_CASE(test_value_integer)
|
||||
BOOST_CHECK(v2.is(toml::value_t::Integer));
|
||||
BOOST_CHECK(v1.is<toml::Integer>());
|
||||
BOOST_CHECK(v2.is<toml::Integer>());
|
||||
BOOST_CHECK(v1.is_integer());
|
||||
BOOST_CHECK(v2.is_integer());
|
||||
|
||||
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::Integer>(), 54);
|
||||
BOOST_CHECK_EQUAL(v2.cast<toml::value_t::Integer>(), -54);
|
||||
@@ -118,6 +132,8 @@ BOOST_AUTO_TEST_CASE(test_value_integer)
|
||||
BOOST_CHECK(v4.is(toml::value_t::Integer));
|
||||
BOOST_CHECK(v3.is<toml::Integer>());
|
||||
BOOST_CHECK(v4.is<toml::Integer>());
|
||||
BOOST_CHECK(v3.is_integer());
|
||||
BOOST_CHECK(v4.is_integer());
|
||||
|
||||
BOOST_CHECK_EQUAL(v3.cast<toml::value_t::Integer>(), 54);
|
||||
BOOST_CHECK_EQUAL(v4.cast<toml::value_t::Integer>(), -54);
|
||||
@@ -131,6 +147,8 @@ BOOST_AUTO_TEST_CASE(test_value_integer)
|
||||
BOOST_CHECK(v6.is(toml::value_t::Integer));
|
||||
BOOST_CHECK(v5.is<toml::Integer>());
|
||||
BOOST_CHECK(v6.is<toml::Integer>());
|
||||
BOOST_CHECK(v5.is_integer());
|
||||
BOOST_CHECK(v6.is_integer());
|
||||
|
||||
BOOST_CHECK_EQUAL(v5.cast<toml::value_t::Integer>(), 54);
|
||||
BOOST_CHECK_EQUAL(v6.cast<toml::value_t::Integer>(), -54);
|
||||
@@ -144,6 +162,8 @@ BOOST_AUTO_TEST_CASE(test_value_integer)
|
||||
BOOST_CHECK(v2.is(toml::value_t::Boolean));
|
||||
BOOST_CHECK(v1.is<toml::Boolean>());
|
||||
BOOST_CHECK(v2.is<toml::Boolean>());
|
||||
BOOST_CHECK(v1.is_boolean());
|
||||
BOOST_CHECK(v2.is_boolean());
|
||||
|
||||
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::Boolean>(), true);
|
||||
BOOST_CHECK_EQUAL(v2.cast<toml::value_t::Boolean>(), false);
|
||||
@@ -160,6 +180,8 @@ BOOST_AUTO_TEST_CASE(test_value_float)
|
||||
BOOST_CHECK(v2.is(toml::value_t::Float));
|
||||
BOOST_CHECK(v1.is<toml::Float>());
|
||||
BOOST_CHECK(v2.is<toml::Float>());
|
||||
BOOST_CHECK(v1.is_float());
|
||||
BOOST_CHECK(v2.is_float());
|
||||
|
||||
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::Float>(), 3.14);
|
||||
BOOST_CHECK_CLOSE_FRACTION(v2.cast<toml::value_t::Float>(), 3.14, 1e-2);
|
||||
@@ -173,6 +195,8 @@ BOOST_AUTO_TEST_CASE(test_value_float)
|
||||
BOOST_CHECK(v2.is(toml::value_t::Float));
|
||||
BOOST_CHECK(v1.is<toml::Float>());
|
||||
BOOST_CHECK(v2.is<toml::Float>());
|
||||
BOOST_CHECK(v1.is_float());
|
||||
BOOST_CHECK(v2.is_float());
|
||||
|
||||
BOOST_CHECK_CLOSE_FRACTION(v1.cast<toml::value_t::Float>(), 2.718, 1e-3);
|
||||
BOOST_CHECK_EQUAL(v2.cast<toml::value_t::Float>(), 2.718);
|
||||
@@ -188,6 +212,8 @@ BOOST_AUTO_TEST_CASE(test_value_float)
|
||||
BOOST_CHECK(v4.is(toml::value_t::Float));
|
||||
BOOST_CHECK(v3.is<toml::Float>());
|
||||
BOOST_CHECK(v4.is<toml::Float>());
|
||||
BOOST_CHECK(v3.is_float());
|
||||
BOOST_CHECK(v4.is_float());
|
||||
|
||||
BOOST_CHECK_CLOSE_FRACTION(v3.cast<toml::value_t::Float>(), 2.718, 1e-3);
|
||||
BOOST_CHECK_EQUAL(v4.cast<toml::value_t::Float>(), 2.718);
|
||||
@@ -201,6 +227,8 @@ BOOST_AUTO_TEST_CASE(test_value_float)
|
||||
BOOST_CHECK(v6.is(toml::value_t::Float));
|
||||
BOOST_CHECK(v5.is<toml::Float>());
|
||||
BOOST_CHECK(v6.is<toml::Float>());
|
||||
BOOST_CHECK(v5.is_float());
|
||||
BOOST_CHECK(v6.is_float());
|
||||
|
||||
BOOST_CHECK_CLOSE_FRACTION(v5.cast<toml::value_t::Float>(), 2.718, 1e-3);
|
||||
BOOST_CHECK_EQUAL(v6.cast<toml::value_t::Float>(), 2.718);
|
||||
@@ -214,6 +242,8 @@ BOOST_AUTO_TEST_CASE(test_value_float)
|
||||
BOOST_CHECK(v2.is(toml::value_t::Boolean));
|
||||
BOOST_CHECK(v1.is<toml::Boolean>());
|
||||
BOOST_CHECK(v2.is<toml::Boolean>());
|
||||
BOOST_CHECK(v1.is_boolean());
|
||||
BOOST_CHECK(v2.is_boolean());
|
||||
|
||||
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::Boolean>(), true);
|
||||
BOOST_CHECK_EQUAL(v2.cast<toml::value_t::Boolean>(), false);
|
||||
@@ -234,6 +264,9 @@ BOOST_AUTO_TEST_CASE(test_value_string)
|
||||
BOOST_CHECK(v1.is<toml::String>());
|
||||
BOOST_CHECK(v2.is<toml::String>());
|
||||
BOOST_CHECK(v3.is<toml::String>());
|
||||
BOOST_CHECK(v1.is_string());
|
||||
BOOST_CHECK(v2.is_string());
|
||||
BOOST_CHECK(v3.is_string());
|
||||
|
||||
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::String>(), "foo");
|
||||
BOOST_CHECK_EQUAL(v2.cast<toml::value_t::String>(), "foo");
|
||||
@@ -249,9 +282,9 @@ BOOST_AUTO_TEST_CASE(test_value_string)
|
||||
BOOST_CHECK(v1.is(toml::value_t::String));
|
||||
BOOST_CHECK(v2.is(toml::value_t::String));
|
||||
BOOST_CHECK(v3.is(toml::value_t::String));
|
||||
BOOST_CHECK(v1.is<toml::String>());
|
||||
BOOST_CHECK(v2.is<toml::String>());
|
||||
BOOST_CHECK(v3.is<toml::String>());
|
||||
BOOST_CHECK(v1.is_string());
|
||||
BOOST_CHECK(v2.is_string());
|
||||
BOOST_CHECK(v3.is_string());
|
||||
|
||||
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::String>(), "bar");
|
||||
BOOST_CHECK_EQUAL(v2.cast<toml::value_t::String>(), "bar");
|
||||
@@ -273,6 +306,9 @@ BOOST_AUTO_TEST_CASE(test_value_string)
|
||||
BOOST_CHECK(v4.is<toml::String>());
|
||||
BOOST_CHECK(v5.is<toml::String>());
|
||||
BOOST_CHECK(v6.is<toml::String>());
|
||||
BOOST_CHECK(v4.is_string());
|
||||
BOOST_CHECK(v5.is_string());
|
||||
BOOST_CHECK(v6.is_string());
|
||||
|
||||
BOOST_CHECK_EQUAL(v4.cast<toml::value_t::String>(), "bar");
|
||||
BOOST_CHECK_EQUAL(v5.cast<toml::value_t::String>(), "bar");
|
||||
@@ -291,6 +327,9 @@ BOOST_AUTO_TEST_CASE(test_value_string)
|
||||
BOOST_CHECK(v4.is<toml::String>());
|
||||
BOOST_CHECK(v5.is<toml::String>());
|
||||
BOOST_CHECK(v6.is<toml::String>());
|
||||
BOOST_CHECK(v4.is_string());
|
||||
BOOST_CHECK(v5.is_string());
|
||||
BOOST_CHECK(v6.is_string());
|
||||
|
||||
BOOST_CHECK_EQUAL(v4.cast<toml::value_t::String>(), "baz");
|
||||
BOOST_CHECK_EQUAL(v5.cast<toml::value_t::String>(), "baz");
|
||||
@@ -309,6 +348,9 @@ BOOST_AUTO_TEST_CASE(test_value_string)
|
||||
BOOST_CHECK(v1.is<toml::Boolean>());
|
||||
BOOST_CHECK(v2.is<toml::Boolean>());
|
||||
BOOST_CHECK(v3.is<toml::Boolean>());
|
||||
BOOST_CHECK(v1.is_boolean());
|
||||
BOOST_CHECK(v2.is_boolean());
|
||||
BOOST_CHECK(v3.is_boolean());
|
||||
|
||||
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::Boolean>(), true);
|
||||
BOOST_CHECK_EQUAL(v2.cast<toml::value_t::Boolean>(), true);
|
||||
@@ -322,6 +364,7 @@ BOOST_AUTO_TEST_CASE(test_value_local_date)
|
||||
BOOST_CHECK_EQUAL(v1.type(), toml::value_t::LocalDate);
|
||||
BOOST_CHECK(v1.is(toml::value_t::LocalDate));
|
||||
BOOST_CHECK(v1.is<toml::LocalDate>());
|
||||
BOOST_CHECK(v1.is_local_date());
|
||||
|
||||
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::LocalDate>(),
|
||||
toml::local_date(2018, toml::month_t::Jan, 31));
|
||||
@@ -331,6 +374,7 @@ BOOST_AUTO_TEST_CASE(test_value_local_date)
|
||||
BOOST_CHECK_EQUAL(v1.type(), toml::value_t::LocalDate);
|
||||
BOOST_CHECK(v1.is(toml::value_t::LocalDate));
|
||||
BOOST_CHECK(v1.is<toml::LocalDate>());
|
||||
BOOST_CHECK(v1.is_local_date());
|
||||
|
||||
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::LocalDate>(),
|
||||
toml::local_date(2018, toml::month_t::Apr, 1));
|
||||
@@ -341,6 +385,7 @@ BOOST_AUTO_TEST_CASE(test_value_local_date)
|
||||
BOOST_CHECK_EQUAL(v2.type(), toml::value_t::LocalDate);
|
||||
BOOST_CHECK(v2.is(toml::value_t::LocalDate));
|
||||
BOOST_CHECK(v2.is<toml::LocalDate>());
|
||||
BOOST_CHECK(v2.is_local_date());
|
||||
|
||||
BOOST_CHECK_EQUAL(v2.cast<toml::value_t::LocalDate>(),
|
||||
toml::local_date(2018, toml::month_t::Apr, 1));
|
||||
@@ -349,6 +394,7 @@ BOOST_AUTO_TEST_CASE(test_value_local_date)
|
||||
BOOST_CHECK_EQUAL(v1.type(), toml::value_t::Boolean);
|
||||
BOOST_CHECK(v1.is(toml::value_t::Boolean));
|
||||
BOOST_CHECK(v1.is<toml::Boolean>());
|
||||
BOOST_CHECK(v1.is_boolean());
|
||||
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::Boolean>(), true);
|
||||
}
|
||||
|
||||
@@ -364,6 +410,8 @@ BOOST_AUTO_TEST_CASE(test_value_local_time)
|
||||
BOOST_CHECK(v2.is(toml::value_t::LocalTime));
|
||||
BOOST_CHECK(v1.is<toml::LocalTime>());
|
||||
BOOST_CHECK(v2.is<toml::LocalTime>());
|
||||
BOOST_CHECK(v1.is_local_time());
|
||||
BOOST_CHECK(v2.is_local_time());
|
||||
|
||||
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::LocalTime>(),
|
||||
toml::local_time(12, 30, 45));
|
||||
@@ -377,6 +425,7 @@ BOOST_AUTO_TEST_CASE(test_value_local_time)
|
||||
BOOST_CHECK_EQUAL(v1.type(), toml::value_t::LocalTime);
|
||||
BOOST_CHECK(v1.is(toml::value_t::LocalTime));
|
||||
BOOST_CHECK(v1.is<toml::LocalTime>());
|
||||
BOOST_CHECK(v1.is_local_time());
|
||||
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::LocalTime>(),
|
||||
toml::local_time(1, 30, 0, 100, 0));
|
||||
|
||||
@@ -386,6 +435,7 @@ BOOST_AUTO_TEST_CASE(test_value_local_time)
|
||||
BOOST_CHECK_EQUAL(v3.type(), toml::value_t::LocalTime);
|
||||
BOOST_CHECK(v3.is(toml::value_t::LocalTime));
|
||||
BOOST_CHECK(v3.is<toml::LocalTime>());
|
||||
BOOST_CHECK(v3.is_local_time());
|
||||
|
||||
BOOST_CHECK_EQUAL(v3.cast<toml::value_t::LocalTime>(),
|
||||
toml::local_time(1, 30, 0, 100, 0));
|
||||
@@ -394,6 +444,7 @@ BOOST_AUTO_TEST_CASE(test_value_local_time)
|
||||
BOOST_CHECK_EQUAL(v1.type(), toml::value_t::Boolean);
|
||||
BOOST_CHECK(v1.is(toml::value_t::Boolean));
|
||||
BOOST_CHECK(v1.is<toml::Boolean>());
|
||||
BOOST_CHECK(v1.is_boolean());
|
||||
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::Boolean>(), true);
|
||||
}
|
||||
|
||||
@@ -407,6 +458,7 @@ BOOST_AUTO_TEST_CASE(test_value_local_datetime)
|
||||
BOOST_CHECK_EQUAL(v1.type(), toml::value_t::LocalDatetime);
|
||||
BOOST_CHECK(v1.is(toml::value_t::LocalDatetime));
|
||||
BOOST_CHECK(v1.is<toml::LocalDatetime>());
|
||||
BOOST_CHECK(v1.is_local_datetime());
|
||||
|
||||
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::LocalDatetime>(),
|
||||
toml::local_datetime(
|
||||
@@ -420,6 +472,7 @@ BOOST_AUTO_TEST_CASE(test_value_local_datetime)
|
||||
BOOST_CHECK_EQUAL(v1.type(), toml::value_t::LocalDatetime);
|
||||
BOOST_CHECK(v1.is(toml::value_t::LocalDatetime));
|
||||
BOOST_CHECK(v1.is<toml::LocalDatetime>());
|
||||
BOOST_CHECK(v1.is_local_datetime());
|
||||
|
||||
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::LocalDatetime>(),
|
||||
toml::local_datetime(
|
||||
@@ -432,6 +485,7 @@ BOOST_AUTO_TEST_CASE(test_value_local_datetime)
|
||||
BOOST_CHECK_EQUAL(v2.type(), toml::value_t::LocalDatetime);
|
||||
BOOST_CHECK(v2.is(toml::value_t::LocalDatetime));
|
||||
BOOST_CHECK(v2.is<toml::LocalDatetime>());
|
||||
BOOST_CHECK(v2.is_local_datetime());
|
||||
|
||||
BOOST_CHECK_EQUAL(v2.cast<toml::value_t::LocalDatetime>(),
|
||||
toml::local_datetime(
|
||||
@@ -442,6 +496,7 @@ BOOST_AUTO_TEST_CASE(test_value_local_datetime)
|
||||
BOOST_CHECK_EQUAL(v1.type(), toml::value_t::Boolean);
|
||||
BOOST_CHECK(v1.is(toml::value_t::Boolean));
|
||||
BOOST_CHECK(v1.is<toml::Boolean>());
|
||||
BOOST_CHECK(v1.is_boolean());
|
||||
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::Boolean>(), true);
|
||||
}
|
||||
|
||||
@@ -456,6 +511,7 @@ BOOST_AUTO_TEST_CASE(test_value_offset_datetime)
|
||||
BOOST_CHECK_EQUAL(v1.type(), toml::value_t::OffsetDatetime);
|
||||
BOOST_CHECK(v1.is(toml::value_t::OffsetDatetime));
|
||||
BOOST_CHECK(v1.is<toml::OffsetDatetime>());
|
||||
BOOST_CHECK(v1.is_offset_datetime());
|
||||
|
||||
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::OffsetDatetime>(),
|
||||
toml::offset_datetime(
|
||||
@@ -472,6 +528,7 @@ BOOST_AUTO_TEST_CASE(test_value_offset_datetime)
|
||||
BOOST_CHECK_EQUAL(v1.type(), toml::value_t::OffsetDatetime);
|
||||
BOOST_CHECK(v1.is(toml::value_t::OffsetDatetime));
|
||||
BOOST_CHECK(v1.is<toml::OffsetDatetime>());
|
||||
BOOST_CHECK(v1.is_offset_datetime());
|
||||
|
||||
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::OffsetDatetime>(),
|
||||
toml::offset_datetime(
|
||||
@@ -485,6 +542,7 @@ BOOST_AUTO_TEST_CASE(test_value_offset_datetime)
|
||||
BOOST_CHECK_EQUAL(v2.type(), toml::value_t::OffsetDatetime);
|
||||
BOOST_CHECK(v2.is(toml::value_t::OffsetDatetime));
|
||||
BOOST_CHECK(v2.is<toml::OffsetDatetime>());
|
||||
BOOST_CHECK(v2.is_offset_datetime());
|
||||
|
||||
BOOST_CHECK_EQUAL(v2.cast<toml::value_t::OffsetDatetime>(),
|
||||
toml::offset_datetime(
|
||||
@@ -495,6 +553,7 @@ BOOST_AUTO_TEST_CASE(test_value_offset_datetime)
|
||||
BOOST_CHECK_EQUAL(v1.type(), toml::value_t::Boolean);
|
||||
BOOST_CHECK(v1.is(toml::value_t::Boolean));
|
||||
BOOST_CHECK(v1.is<toml::Boolean>());
|
||||
BOOST_CHECK(v1.is_boolean());
|
||||
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::Boolean>(), true);
|
||||
}
|
||||
|
||||
@@ -507,10 +566,12 @@ BOOST_AUTO_TEST_CASE(test_value_array)
|
||||
BOOST_CHECK_EQUAL(v1.type(), toml::value_t::Array);
|
||||
BOOST_CHECK(v1.is(toml::value_t::Array));
|
||||
BOOST_CHECK(v1.is<toml::Array>());
|
||||
BOOST_CHECK(v1.is_array());
|
||||
|
||||
BOOST_CHECK_EQUAL(v2.type(), toml::value_t::Array);
|
||||
BOOST_CHECK(v2.is(toml::value_t::Array));
|
||||
BOOST_CHECK(v2.is<toml::Array>());
|
||||
BOOST_CHECK(v2.is_array());
|
||||
|
||||
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::Array>().at(0).cast<toml::value_t::Integer>(), 1);
|
||||
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::Array>().at(1).cast<toml::value_t::Integer>(), 2);
|
||||
@@ -530,10 +591,12 @@ BOOST_AUTO_TEST_CASE(test_value_array)
|
||||
BOOST_CHECK_EQUAL(v1.type(), toml::value_t::Array);
|
||||
BOOST_CHECK(v1.is(toml::value_t::Array));
|
||||
BOOST_CHECK(v1.is<toml::Array>());
|
||||
BOOST_CHECK(v1.is_array());
|
||||
|
||||
BOOST_CHECK_EQUAL(v2.type(), toml::value_t::Array);
|
||||
BOOST_CHECK(v2.is(toml::value_t::Array));
|
||||
BOOST_CHECK(v2.is<toml::Array>());
|
||||
BOOST_CHECK(v2.is_array());
|
||||
|
||||
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::Array>().at(0).cast<toml::value_t::Integer>(), 6);
|
||||
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::Array>().at(1).cast<toml::value_t::Integer>(), 7);
|
||||
@@ -553,6 +616,7 @@ BOOST_AUTO_TEST_CASE(test_value_array)
|
||||
BOOST_CHECK_EQUAL(v3.type(), toml::value_t::Array);
|
||||
BOOST_CHECK(v3.is(toml::value_t::Array));
|
||||
BOOST_CHECK(v3.is<toml::Array>());
|
||||
BOOST_CHECK(v3.is_array());
|
||||
|
||||
BOOST_CHECK_EQUAL(v3.cast<toml::value_t::Array>().at(0).cast<toml::value_t::Integer>(), 6);
|
||||
BOOST_CHECK_EQUAL(v3.cast<toml::value_t::Array>().at(1).cast<toml::value_t::Integer>(), 7);
|
||||
@@ -564,6 +628,7 @@ BOOST_AUTO_TEST_CASE(test_value_array)
|
||||
BOOST_CHECK_EQUAL(v1.type(), toml::value_t::Boolean);
|
||||
BOOST_CHECK(v1.is(toml::value_t::Boolean));
|
||||
BOOST_CHECK(v1.is<toml::Boolean>());
|
||||
BOOST_CHECK(v1.is_boolean());
|
||||
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::Boolean>(), true);
|
||||
}
|
||||
|
||||
@@ -574,6 +639,7 @@ BOOST_AUTO_TEST_CASE(test_value_table)
|
||||
BOOST_CHECK_EQUAL(v1.type(), toml::value_t::Table);
|
||||
BOOST_CHECK(v1.is(toml::value_t::Table));
|
||||
BOOST_CHECK(v1.is<toml::Table>());
|
||||
BOOST_CHECK(v1.is_table());
|
||||
|
||||
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::Table>().at("foo").cast<toml::value_t::Integer>(), 42);
|
||||
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::Table>().at("bar").cast<toml::value_t::Float>(), 3.14);
|
||||
@@ -584,6 +650,7 @@ BOOST_AUTO_TEST_CASE(test_value_table)
|
||||
BOOST_CHECK_EQUAL(v1.type(), toml::value_t::Table);
|
||||
BOOST_CHECK(v1.is(toml::value_t::Table));
|
||||
BOOST_CHECK(v1.is<toml::Table>());
|
||||
BOOST_CHECK(v1.is_table());
|
||||
|
||||
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::Table>().at("foo").cast<toml::value_t::Float>(), 2.71);
|
||||
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::Table>().at("bar").cast<toml::value_t::Integer>(), 54);
|
||||
@@ -595,6 +662,7 @@ BOOST_AUTO_TEST_CASE(test_value_table)
|
||||
BOOST_CHECK_EQUAL(v3.type(), toml::value_t::Table);
|
||||
BOOST_CHECK(v3.is(toml::value_t::Table));
|
||||
BOOST_CHECK(v3.is<toml::Table>());
|
||||
BOOST_CHECK(v3.is_table());
|
||||
|
||||
BOOST_CHECK_EQUAL(v3.cast<toml::value_t::Table>().at("foo").cast<toml::value_t::Float>(), 2.71);
|
||||
BOOST_CHECK_EQUAL(v3.cast<toml::value_t::Table>().at("bar").cast<toml::value_t::Integer>(), 54);
|
||||
@@ -604,5 +672,13 @@ BOOST_AUTO_TEST_CASE(test_value_table)
|
||||
BOOST_CHECK_EQUAL(v1.type(), toml::value_t::Boolean);
|
||||
BOOST_CHECK(v1.is(toml::value_t::Boolean));
|
||||
BOOST_CHECK(v1.is<toml::Boolean>());
|
||||
BOOST_CHECK(v1.is_boolean());
|
||||
BOOST_CHECK_EQUAL(v1.cast<toml::value_t::Boolean>(), true);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_value_empty)
|
||||
{
|
||||
toml::value v1;
|
||||
BOOST_CHECK(v1.is_uninitialized());
|
||||
BOOST_CHECK(v1.is(toml::value_t::Empty));
|
||||
}
|
||||
|
||||
1
toml.hpp
1
toml.hpp
@@ -35,7 +35,6 @@
|
||||
|
||||
#include "toml/parser.hpp"
|
||||
#include "toml/serializer.hpp"
|
||||
#include "toml/to_toml.hpp"
|
||||
#include "toml/from_toml.hpp"
|
||||
#include "toml/get.hpp"
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Copyright Toru Niina 2017.
|
||||
// Distributed under the MIT License.
|
||||
#ifndef TOML11_DATETIME
|
||||
#define TOML11_DATETIME
|
||||
#ifndef TOML11_DATETIME_HPP
|
||||
#define TOML11_DATETIME_HPP
|
||||
#include <chrono>
|
||||
#include <tuple>
|
||||
#include <array>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Copyright Toru Niina 2017.
|
||||
// Distributed under the MIT License.
|
||||
#ifndef TOML11_EXCEPTION
|
||||
#define TOML11_EXCEPTION
|
||||
#ifndef TOML11_EXCEPTION_HPP
|
||||
#define TOML11_EXCEPTION_HPP
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
|
||||
|
||||
20
toml/from.hpp
Normal file
20
toml/from.hpp
Normal file
@@ -0,0 +1,20 @@
|
||||
// Copyright Toru Niina 2019.
|
||||
// Distributed under the MIT License.
|
||||
#ifndef TOML11_FROM_HPP
|
||||
#define TOML11_FROM_HPP
|
||||
#include "traits.hpp"
|
||||
|
||||
namespace toml
|
||||
{
|
||||
|
||||
template<typename T>
|
||||
struct from;
|
||||
// {
|
||||
// static T from_toml(const toml::value& v)
|
||||
// {
|
||||
// // User-defined conversions ...
|
||||
// }
|
||||
// };
|
||||
|
||||
} // toml
|
||||
#endif // TOML11_FROM_HPP
|
||||
@@ -1,7 +1,7 @@
|
||||
// Copyright Toru Niina 2017.
|
||||
// Distributed under the MIT License.
|
||||
#ifndef TOML11_FROM_TOML
|
||||
#define TOML11_FROM_TOML
|
||||
#ifndef TOML11_FROM_TOML_HPP
|
||||
#define TOML11_FROM_TOML_HPP
|
||||
#include "get.hpp"
|
||||
|
||||
namespace toml
|
||||
|
||||
70
toml/get.hpp
70
toml/get.hpp
@@ -1,7 +1,8 @@
|
||||
// Copyright Toru Niina 2017.
|
||||
// Distributed under the MIT License.
|
||||
#ifndef TOML11_GET
|
||||
#define TOML11_GET
|
||||
#ifndef TOML11_GET_HPP
|
||||
#define TOML11_GET_HPP
|
||||
#include "from.hpp"
|
||||
#include "result.hpp"
|
||||
#include "value.hpp"
|
||||
#include <algorithm>
|
||||
@@ -173,6 +174,20 @@ template<typename T, typename std::enable_if<detail::conjunction<
|
||||
>::value, std::nullptr_t>::type = nullptr>
|
||||
T get(const toml::value& v);
|
||||
|
||||
template<typename T, typename std::enable_if<detail::conjunction<
|
||||
detail::negation<detail::is_exact_toml_type<T>>, // not a toml::value
|
||||
detail::has_from_toml_method<T>, // but has from_toml(toml::value) memfn
|
||||
std::is_default_constructible<T> // and default constructible
|
||||
>::value, std::nullptr_t>::type = nullptr>
|
||||
T get(const toml::value& v);
|
||||
|
||||
template<typename T, typename std::enable_if<detail::conjunction<
|
||||
detail::negation<detail::is_exact_toml_type<T>> // not a toml::value
|
||||
>::value, std::nullptr_t>::type = nullptr,
|
||||
std::size_t = sizeof(::toml::from<T>) // and has from<T> specialization
|
||||
>
|
||||
T get(const toml::value& v);
|
||||
|
||||
// ============================================================================
|
||||
// array-like types; most likely STL container, like std::vector, etc.
|
||||
|
||||
@@ -210,8 +225,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 +249,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 +282,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>{});
|
||||
@@ -292,6 +312,29 @@ T get(const toml::value& v)
|
||||
return map;
|
||||
}
|
||||
|
||||
|
||||
// ============================================================================
|
||||
// user-defined, but compatible types.
|
||||
|
||||
template<typename T, typename std::enable_if<detail::conjunction<
|
||||
detail::negation<detail::is_exact_toml_type<T>>, // not a toml::value
|
||||
detail::has_from_toml_method<T>, // but has from_toml(toml::value) memfn
|
||||
std::is_default_constructible<T> // and default constructible
|
||||
>::value, std::nullptr_t>::type>
|
||||
T get(const toml::value& v)
|
||||
{
|
||||
T ud;
|
||||
ud.from_toml(v);
|
||||
return ud;
|
||||
}
|
||||
template<typename T, typename std::enable_if<detail::conjunction<
|
||||
detail::negation<detail::is_exact_toml_type<T>> // not a toml::value
|
||||
>::value, std::nullptr_t>::type, std::size_t> // and has from<T>
|
||||
T get(const toml::value& v)
|
||||
{
|
||||
return ::toml::from<T>::from_toml(v);
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// find and get
|
||||
|
||||
@@ -340,8 +383,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 +397,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 +411,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]));
|
||||
}
|
||||
|
||||
20
toml/into.hpp
Normal file
20
toml/into.hpp
Normal file
@@ -0,0 +1,20 @@
|
||||
// Copyright Toru Niina 2019.
|
||||
// Distributed under the MIT License.
|
||||
#ifndef TOML11_INTO_HPP
|
||||
#define TOML11_INTO_HPP
|
||||
#include "traits.hpp"
|
||||
|
||||
namespace toml
|
||||
{
|
||||
|
||||
template<typename T>
|
||||
struct into;
|
||||
// {
|
||||
// static toml::value into_toml(const T& user_defined_type)
|
||||
// {
|
||||
// // User-defined conversions ...
|
||||
// }
|
||||
// };
|
||||
|
||||
} // toml
|
||||
#endif // TOML11_INTO_HPP
|
||||
457
toml/parser.hpp
457
toml/parser.hpp
@@ -29,13 +29,13 @@ parse_boolean(location<Container>& loc)
|
||||
else // internal error.
|
||||
{
|
||||
throw toml::internal_error(format_underline(
|
||||
"[error] toml::parse_boolean: internal error", reg,
|
||||
"invalid token"));
|
||||
"[error] toml::parse_boolean: internal error",
|
||||
{{std::addressof(reg), "invalid token"}}));
|
||||
}
|
||||
}
|
||||
loc.iter() = first; //rollback
|
||||
return err(format_underline("[error] toml::parse_boolean: ", loc,
|
||||
"the next token is not a boolean"));
|
||||
return err(format_underline("[error] toml::parse_boolean: ",
|
||||
{{std::addressof(loc), "the next token is not a boolean"}}));
|
||||
}
|
||||
|
||||
template<typename Container>
|
||||
@@ -57,14 +57,14 @@ parse_binary_integer(location<Container>& loc)
|
||||
{
|
||||
throw toml::internal_error(format_underline(
|
||||
"[error] toml::parse_integer: internal error",
|
||||
token.unwrap(), "invalid token"));
|
||||
{{std::addressof(token.unwrap()), "invalid token"}}));
|
||||
}
|
||||
}
|
||||
return ok(std::make_pair(retval, token.unwrap()));
|
||||
}
|
||||
loc.iter() = first;
|
||||
return err(format_underline("[error] toml::parse_binary_integer:", loc,
|
||||
"the next token is not an integer"));
|
||||
return err(format_underline("[error] toml::parse_binary_integer:",
|
||||
{{std::addressof(loc), "the next token is not an integer"}}));
|
||||
}
|
||||
|
||||
template<typename Container>
|
||||
@@ -84,8 +84,8 @@ parse_octal_integer(location<Container>& loc)
|
||||
return ok(std::make_pair(retval, token.unwrap()));
|
||||
}
|
||||
loc.iter() = first;
|
||||
return err(format_underline("[error] toml::parse_octal_integer:", loc,
|
||||
"the next token is not an integer"));
|
||||
return err(format_underline("[error] toml::parse_octal_integer:",
|
||||
{{std::addressof(loc), "the next token is not an integer"}}));
|
||||
}
|
||||
|
||||
template<typename Container>
|
||||
@@ -105,8 +105,8 @@ parse_hexadecimal_integer(location<Container>& loc)
|
||||
return ok(std::make_pair(retval, token.unwrap()));
|
||||
}
|
||||
loc.iter() = first;
|
||||
return err(format_underline("[error] toml::parse_hexadecimal_integer", loc,
|
||||
"the next token is not an integer"));
|
||||
return err(format_underline("[error] toml::parse_hexadecimal_integer",
|
||||
{{std::addressof(loc), "the next token is not an integer"}}));
|
||||
}
|
||||
|
||||
template<typename Container>
|
||||
@@ -133,8 +133,8 @@ parse_integer(location<Container>& loc)
|
||||
return ok(std::make_pair(retval, token.unwrap()));
|
||||
}
|
||||
loc.iter() = first;
|
||||
return err(format_underline("[error] toml::parse_integer: ", loc,
|
||||
"the next token is not an integer"));
|
||||
return err(format_underline("[error] toml::parse_integer: ",
|
||||
{{std::addressof(loc), "the next token is not an integer"}}));
|
||||
}
|
||||
|
||||
template<typename Container>
|
||||
@@ -222,8 +222,8 @@ parse_floating(location<Container>& loc)
|
||||
return ok(std::make_pair(v, token.unwrap()));
|
||||
}
|
||||
loc.iter() = first;
|
||||
return err(format_underline("[error] toml::parse_floating: ", loc,
|
||||
"the next token is not a float"));
|
||||
return err(format_underline("[error] toml::parse_floating: ",
|
||||
{{std::addressof(loc), "the next token is not a float"}}));
|
||||
}
|
||||
|
||||
template<typename Container, typename Container2>
|
||||
@@ -252,8 +252,9 @@ std::string read_utf8_codepoint(const region<Container>& reg,
|
||||
{
|
||||
throw syntax_error(format_underline("[error] "
|
||||
"toml::read_utf8_codepoint: codepoints in the range "
|
||||
"[0xD800, 0xDFFF] are not valid UTF-8.",
|
||||
loc, "not a valid UTF-8 codepoint"));
|
||||
"[0xD800, 0xDFFF] are not valid UTF-8.", {{
|
||||
std::addressof(loc), "not a valid UTF-8 codepoint"
|
||||
}}));
|
||||
}
|
||||
assert(codepoint < 0xD800 || 0xDFFF < codepoint);
|
||||
// 1110yyyy 10yxxxxx 10xxxxxx
|
||||
@@ -261,15 +262,8 @@ std::string read_utf8_codepoint(const region<Container>& reg,
|
||||
character += static_cast<unsigned char>(0x80|(codepoint >> 6 & 0x3F));
|
||||
character += static_cast<unsigned char>(0x80|(codepoint & 0x3F));
|
||||
}
|
||||
else if(codepoint < 0x200000) // U+010000 ... U+1FFFFF
|
||||
else if(codepoint < 0x110000) // U+010000 ... U+10FFFF
|
||||
{
|
||||
if(0x10FFFF < codepoint) // out of Unicode region
|
||||
{
|
||||
throw syntax_error(format_underline("[error] "
|
||||
"toml::read_utf8_codepoint: input codepoint is too large to "
|
||||
"decode as a unicode character.", loc,
|
||||
"should be in [0x00..0x10FFFF]"));
|
||||
}
|
||||
// 11110yyy 10yyxxxx 10xxxxxx 10xxxxxx
|
||||
character += static_cast<unsigned char>(0xF0| codepoint >> 18);
|
||||
character += static_cast<unsigned char>(0x80|(codepoint >> 12 & 0x3F));
|
||||
@@ -278,9 +272,9 @@ std::string read_utf8_codepoint(const region<Container>& reg,
|
||||
}
|
||||
else // out of UTF-8 region
|
||||
{
|
||||
throw std::range_error(format_underline(concat_to_string("[error] "
|
||||
"input codepoint (", str, ") is too large to encode as utf-8."),
|
||||
reg, "should be in [0x00..0x10FFFF]"));
|
||||
throw syntax_error(format_underline("[error] toml::read_utf8_codepoint:"
|
||||
" input codepoint is too large.",
|
||||
{{std::addressof(loc), "should be in [0x00..0x10FFFF]"}}));
|
||||
}
|
||||
return character;
|
||||
}
|
||||
@@ -291,8 +285,8 @@ result<std::string, std::string> parse_escape_sequence(location<Container>& loc)
|
||||
const auto first = loc.iter();
|
||||
if(first == loc.end() || *first != '\\')
|
||||
{
|
||||
return err(format_underline("[error]: toml::parse_escape_sequence: ", loc,
|
||||
"the next token is not an escape sequence \"\\\""));
|
||||
return err(format_underline("[error]: toml::parse_escape_sequence: ", {{
|
||||
std::addressof(loc), "the next token is not a backslash \"\\\""}}));
|
||||
}
|
||||
++loc.iter();
|
||||
switch(*loc.iter())
|
||||
@@ -314,7 +308,7 @@ result<std::string, std::string> parse_escape_sequence(location<Container>& loc)
|
||||
{
|
||||
return err(format_underline("[error] parse_escape_sequence: "
|
||||
"invalid token found in UTF-8 codepoint uXXXX.",
|
||||
loc, token.unwrap_err()));
|
||||
{{std::addressof(loc), token.unwrap_err()}}));
|
||||
}
|
||||
}
|
||||
case 'U':
|
||||
@@ -327,16 +321,16 @@ result<std::string, std::string> parse_escape_sequence(location<Container>& loc)
|
||||
{
|
||||
return err(format_underline("[error] parse_escape_sequence: "
|
||||
"invalid token found in UTF-8 codepoint Uxxxxxxxx",
|
||||
loc, token.unwrap_err()));
|
||||
{{std::addressof(loc), token.unwrap_err()}}));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const auto msg = format_underline("[error] parse_escape_sequence: "
|
||||
"unknown escape sequence appeared.", loc, "escape sequence is one of"
|
||||
" \\, \", b, t, n, f, r, uxxxx, Uxxxxxxxx", {"if you want to write "
|
||||
"backslash as just one backslash, use literal string like:",
|
||||
"regex = '<\\i\\c*\\s*>'"});
|
||||
"unknown escape sequence appeared.", {{std::addressof(loc),
|
||||
"escape sequence is one of \\, \", b, t, n, f, r, uxxxx, Uxxxxxxxx"}},
|
||||
/* Hints = */{"if you want to write backslash as just one backslash, "
|
||||
"use literal string like: regex = '<\\i\\c*\\s*>'"});
|
||||
loc.iter() = first;
|
||||
return err(msg);
|
||||
}
|
||||
@@ -359,7 +353,7 @@ parse_ml_basic_string(location<Container>& loc)
|
||||
{
|
||||
throw internal_error(format_underline("[error] "
|
||||
"parse_ml_basic_string: invalid token",
|
||||
inner_loc, "should be \"\"\""));
|
||||
{{std::addressof(inner_loc), "should be \"\"\""}}));
|
||||
}
|
||||
// immediate newline is ignored (if exists)
|
||||
/* discard return value */ lex_newline::invoke(inner_loc);
|
||||
@@ -385,7 +379,7 @@ parse_ml_basic_string(location<Container>& loc)
|
||||
{
|
||||
throw internal_error(format_underline("[error] "
|
||||
"parse_ml_basic_string: unexpected end of region",
|
||||
inner_loc, "not sufficient token"));
|
||||
{{std::addressof(inner_loc), "not sufficient token"}}));
|
||||
}
|
||||
delim = lex_ml_basic_string_delim::invoke(inner_loc);
|
||||
}
|
||||
@@ -412,7 +406,7 @@ parse_basic_string(location<Container>& loc)
|
||||
if(!quot)
|
||||
{
|
||||
throw internal_error(format_underline("[error] parse_basic_string: "
|
||||
"invalid token", inner_loc, "should be \""));
|
||||
"invalid token", {{std::addressof(inner_loc), "should be \""}}));
|
||||
}
|
||||
|
||||
std::string retval;
|
||||
@@ -434,7 +428,7 @@ parse_basic_string(location<Container>& loc)
|
||||
{
|
||||
throw internal_error(format_underline("[error] "
|
||||
"parse_ml_basic_string: unexpected end of region",
|
||||
inner_loc, "not sufficient token"));
|
||||
{{std::addressof(inner_loc), "not sufficient token"}}));
|
||||
}
|
||||
quot = lex_quotation_mark::invoke(inner_loc);
|
||||
}
|
||||
@@ -461,7 +455,7 @@ parse_ml_literal_string(location<Container>& loc)
|
||||
{
|
||||
throw internal_error(format_underline("[error] "
|
||||
"parse_ml_literal_string: invalid token",
|
||||
inner_loc, "should be '''"));
|
||||
{{std::addressof(inner_loc), "should be '''"}}));
|
||||
}
|
||||
// immediate newline is ignored (if exists)
|
||||
/* discard return value */ lex_newline::invoke(inner_loc);
|
||||
@@ -473,7 +467,7 @@ parse_ml_literal_string(location<Container>& loc)
|
||||
{
|
||||
throw internal_error(format_underline("[error] "
|
||||
"parse_ml_literal_string: invalid token",
|
||||
inner_loc, "should be '''"));
|
||||
{{std::addressof(inner_loc), "should be '''"}}));
|
||||
}
|
||||
return ok(std::make_pair(
|
||||
toml::string(body.unwrap().str(), toml::string_t::literal),
|
||||
@@ -500,7 +494,7 @@ parse_literal_string(location<Container>& loc)
|
||||
{
|
||||
throw internal_error(format_underline("[error] "
|
||||
"parse_literal_string: invalid token",
|
||||
inner_loc, "should be '"));
|
||||
{{std::addressof(inner_loc), "should be '"}}));
|
||||
}
|
||||
|
||||
const auto body = repeat<lex_literal_char, unlimited>::invoke(inner_loc);
|
||||
@@ -510,7 +504,7 @@ parse_literal_string(location<Container>& loc)
|
||||
{
|
||||
throw internal_error(format_underline("[error] "
|
||||
"parse_literal_string: invalid token",
|
||||
inner_loc, "should be '"));
|
||||
{{std::addressof(inner_loc), "should be '"}}));
|
||||
}
|
||||
return ok(std::make_pair(
|
||||
toml::string(body.unwrap().str(), toml::string_t::literal),
|
||||
@@ -531,8 +525,8 @@ parse_string(location<Container>& loc)
|
||||
if(const auto rslt = parse_ml_literal_string(loc)) {return rslt;}
|
||||
if(const auto rslt = parse_basic_string(loc)) {return rslt;}
|
||||
if(const auto rslt = parse_literal_string(loc)) {return rslt;}
|
||||
return err(format_underline("[error] toml::parse_string: ", loc,
|
||||
"the next token is not a string"));
|
||||
return err(format_underline("[error] toml::parse_string: ",
|
||||
{{std::addressof(loc), "the next token is not a string"}}));
|
||||
}
|
||||
|
||||
template<typename Container>
|
||||
@@ -547,21 +541,23 @@ parse_local_date(location<Container>& loc)
|
||||
const auto y = lex_date_fullyear::invoke(inner_loc);
|
||||
if(!y || inner_loc.iter() == inner_loc.end() || *inner_loc.iter() != '-')
|
||||
{
|
||||
const std::string msg = y.map_err_or_else(
|
||||
[](const std::string& msg) {return msg;}, "should be `-`");
|
||||
|
||||
throw internal_error(format_underline("[error]: "
|
||||
"toml::parse_inner_local_date: invalid year format",
|
||||
inner_loc, y.map_err_or_else([](const std::string& msg) {
|
||||
return msg;
|
||||
}, "should be `-`")));
|
||||
{{std::addressof(inner_loc), msg}}));
|
||||
}
|
||||
++inner_loc.iter();
|
||||
const auto m = lex_date_month::invoke(inner_loc);
|
||||
if(!m || inner_loc.iter() == inner_loc.end() || *inner_loc.iter() != '-')
|
||||
{
|
||||
const std::string msg = m.map_err_or_else(
|
||||
[](const std::string& msg) {return msg;}, "should be `-`");
|
||||
|
||||
throw internal_error(format_underline("[error]: "
|
||||
"toml::parse_local_date: invalid month format",
|
||||
inner_loc, m.map_err_or_else([](const std::string& msg) {
|
||||
return msg;
|
||||
}, "should be `-`")));
|
||||
{{std::addressof(inner_loc), msg}}));
|
||||
}
|
||||
++inner_loc.iter();
|
||||
const auto d = lex_date_mday::invoke(inner_loc);
|
||||
@@ -569,7 +565,7 @@ parse_local_date(location<Container>& loc)
|
||||
{
|
||||
throw internal_error(format_underline("[error]: "
|
||||
"toml::parse_local_date: invalid day format",
|
||||
inner_loc, d.unwrap_err()));
|
||||
{{std::addressof(inner_loc), d.unwrap_err()}}));
|
||||
}
|
||||
return ok(std::make_pair(local_date(
|
||||
static_cast<std::int16_t>(from_string<int>(y.unwrap().str(), 0)),
|
||||
@@ -581,8 +577,8 @@ parse_local_date(location<Container>& loc)
|
||||
else
|
||||
{
|
||||
loc.iter() = first;
|
||||
return err(format_underline("[error]: toml::parse_local_date: ", loc,
|
||||
"the next token is not a local_date"));
|
||||
return err(format_underline("[error]: toml::parse_local_date: ",
|
||||
{{std::addressof(loc), "the next token is not a local_date"}}));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -598,21 +594,23 @@ parse_local_time(location<Container>& loc)
|
||||
const auto h = lex_time_hour::invoke(inner_loc);
|
||||
if(!h || inner_loc.iter() == inner_loc.end() || *inner_loc.iter() != ':')
|
||||
{
|
||||
const std::string msg = h.map_err_or_else(
|
||||
[](const std::string& msg) {return msg;}, "should be `:`");
|
||||
|
||||
throw internal_error(format_underline("[error]: "
|
||||
"toml::parse_local_time: invalid year format",
|
||||
inner_loc, h.map_err_or_else([](const std::string& msg) {
|
||||
return msg;
|
||||
}, "should be `:`")));
|
||||
{{std::addressof(inner_loc), msg}}));
|
||||
}
|
||||
++inner_loc.iter();
|
||||
const auto m = lex_time_minute::invoke(inner_loc);
|
||||
if(!m || inner_loc.iter() == inner_loc.end() || *inner_loc.iter() != ':')
|
||||
{
|
||||
const std::string msg = m.map_err_or_else(
|
||||
[](const std::string& msg) {return msg;}, "should be `:`");
|
||||
|
||||
throw internal_error(format_underline("[error]: "
|
||||
"toml::parse_local_time: invalid month format",
|
||||
inner_loc, m.map_err_or_else([](const std::string& msg) {
|
||||
return msg;
|
||||
}, "should be `:`")));
|
||||
{{std::addressof(inner_loc), msg}}));
|
||||
}
|
||||
++inner_loc.iter();
|
||||
const auto s = lex_time_second::invoke(inner_loc);
|
||||
@@ -620,7 +618,7 @@ parse_local_time(location<Container>& loc)
|
||||
{
|
||||
throw internal_error(format_underline("[error]: "
|
||||
"toml::parse_local_time: invalid second format",
|
||||
inner_loc, s.unwrap_err()));
|
||||
{{std::addressof(inner_loc), s.unwrap_err()}}));
|
||||
}
|
||||
local_time time(
|
||||
static_cast<std::int8_t>(from_string<int>(h.unwrap().str(), 0)),
|
||||
@@ -656,7 +654,7 @@ parse_local_time(location<Container>& loc)
|
||||
{
|
||||
throw internal_error(format_underline("[error]: "
|
||||
"toml::parse_local_time: invalid subsecond format",
|
||||
inner_loc, secfrac.unwrap_err()));
|
||||
{{std::addressof(inner_loc), secfrac.unwrap_err()}}));
|
||||
}
|
||||
}
|
||||
return ok(std::make_pair(time, token.unwrap()));
|
||||
@@ -664,8 +662,8 @@ parse_local_time(location<Container>& loc)
|
||||
else
|
||||
{
|
||||
loc.iter() = first;
|
||||
return err(format_underline("[error]: toml::parse_local_time: ", loc,
|
||||
"the next token is not a local_time"));
|
||||
return err(format_underline("[error]: toml::parse_local_time: ",
|
||||
{{std::addressof(loc), "the next token is not a local_time"}}));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -680,25 +678,26 @@ parse_local_datetime(location<Container>& loc)
|
||||
const auto date = parse_local_date(inner_loc);
|
||||
if(!date || inner_loc.iter() == inner_loc.end())
|
||||
{
|
||||
const std::string msg = date.map_err_or_else(
|
||||
[](const std::string& msg) {return msg;}, "date, not datetime");
|
||||
|
||||
throw internal_error(format_underline("[error]: "
|
||||
"toml::parse_local_datetime: invalid datetime format",
|
||||
inner_loc, date.map_err_or_else([](const std::string& msg){
|
||||
return msg;
|
||||
}, "date, not datetime")));
|
||||
{{std::addressof(inner_loc), msg}}));
|
||||
}
|
||||
const char delim = *(inner_loc.iter()++);
|
||||
if(delim != 'T' && delim != 't' && delim != ' ')
|
||||
{
|
||||
throw internal_error(format_underline("[error]: "
|
||||
"toml::parse_local_datetime: invalid datetime format",
|
||||
inner_loc, "should be `T` or ` ` (space)"));
|
||||
{{std::addressof(inner_loc), "should be `T` or ` ` (space)"}}));
|
||||
}
|
||||
const auto time = parse_local_time(inner_loc);
|
||||
if(!time)
|
||||
{
|
||||
throw internal_error(format_underline("[error]: "
|
||||
"toml::parse_local_datetime: invalid datetime format",
|
||||
inner_loc, "invalid time fomrat"));
|
||||
{{std::addressof(inner_loc), "invalid time fomrat"}}));
|
||||
}
|
||||
return ok(std::make_pair(
|
||||
local_datetime(date.unwrap().first, time.unwrap().first),
|
||||
@@ -707,8 +706,8 @@ parse_local_datetime(location<Container>& loc)
|
||||
else
|
||||
{
|
||||
loc.iter() = first;
|
||||
return err(format_underline("[error]: toml::parse_local_datetime: ", loc,
|
||||
"the next token is not a local_datetime"));
|
||||
return err(format_underline("[error]: toml::parse_local_datetime: ",
|
||||
{{std::addressof(loc), "the next token is not a local_datetime"}}));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -723,11 +722,12 @@ parse_offset_datetime(location<Container>& loc)
|
||||
const auto datetime = parse_local_datetime(inner_loc);
|
||||
if(!datetime || inner_loc.iter() == inner_loc.end())
|
||||
{
|
||||
const std::string msg = datetime.map_err_or_else(
|
||||
[](const std::string& msg){return msg;}, "date, not datetime");
|
||||
|
||||
throw internal_error(format_underline("[error]: "
|
||||
"toml::parse_offset_datetime: invalid datetime format",
|
||||
inner_loc, datetime.map_err_or_else([](const std::string& msg){
|
||||
return msg;
|
||||
}, "date, not datetime")));
|
||||
{{std::addressof(inner_loc), msg}}));
|
||||
}
|
||||
time_offset offset(0, 0);
|
||||
if(const auto ofs = lex_time_numoffset::invoke(inner_loc))
|
||||
@@ -748,7 +748,7 @@ parse_offset_datetime(location<Container>& loc)
|
||||
{
|
||||
throw internal_error(format_underline("[error]: "
|
||||
"toml::parse_offset_datetime: invalid datetime format",
|
||||
inner_loc, "should be `Z` or `+HH:MM`"));
|
||||
{{std::addressof(inner_loc), "should be `Z` or `+HH:MM`"}}));
|
||||
}
|
||||
return ok(std::make_pair(offset_datetime(datetime.unwrap().first, offset),
|
||||
token.unwrap()));
|
||||
@@ -756,8 +756,8 @@ parse_offset_datetime(location<Container>& loc)
|
||||
else
|
||||
{
|
||||
loc.iter() = first;
|
||||
return err(format_underline("[error]: toml::parse_offset_datetime: ", loc,
|
||||
"the next token is not a local_datetime"));
|
||||
return err(format_underline("[error]: toml::parse_offset_datetime: ",
|
||||
{{std::addressof(loc), "the next token is not a local_datetime"}}));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -778,8 +778,8 @@ parse_simple_key(location<Container>& loc)
|
||||
const auto reg = bare.unwrap();
|
||||
return ok(std::make_pair(reg.str(), reg));
|
||||
}
|
||||
return err(format_underline("[error] toml::parse_simple_key: ", loc,
|
||||
"the next token is not a simple key"));
|
||||
return err(format_underline("[error] toml::parse_simple_key: ",
|
||||
{{std::addressof(loc), "the next token is not a simple key"}}));
|
||||
}
|
||||
|
||||
// dotted key become vector of keys
|
||||
@@ -806,7 +806,7 @@ parse_key(location<Container>& loc)
|
||||
{
|
||||
throw internal_error(format_underline("[error] "
|
||||
"toml::detail::parse_key: dotted key contains invalid key",
|
||||
inner_loc, k.unwrap_err()));
|
||||
{{std::addressof(inner_loc), k.unwrap_err()}}));
|
||||
}
|
||||
|
||||
lex_ws::invoke(inner_loc);
|
||||
@@ -821,8 +821,8 @@ parse_key(location<Container>& loc)
|
||||
else
|
||||
{
|
||||
throw internal_error(format_underline("[error] toml::parse_key: "
|
||||
"dotted key contains invalid key ", inner_loc,
|
||||
"should be `.`"));
|
||||
"dotted key contains invalid key ",
|
||||
{{std::addressof(inner_loc), "should be `.`"}}));
|
||||
}
|
||||
}
|
||||
return ok(std::make_pair(keys, reg));
|
||||
@@ -835,7 +835,8 @@ parse_key(location<Container>& loc)
|
||||
return ok(std::make_pair(std::vector<key>(1, smpl.unwrap().first),
|
||||
smpl.unwrap().second));
|
||||
}
|
||||
return err(format_underline("[error] toml::parse_key: ", loc, "is not a valid key"));
|
||||
return err(format_underline("[error] toml::parse_key: ",
|
||||
{{std::addressof(loc), "is not a valid key"}}));
|
||||
}
|
||||
|
||||
// forward-decl to implement parse_array and parse_table
|
||||
@@ -876,16 +877,34 @@ parse_array(location<Container>& loc)
|
||||
{
|
||||
if(!retval.empty() && retval.front().type() != val.as_ok().type())
|
||||
{
|
||||
throw syntax_error(format_underline(
|
||||
"[error] toml::parse_array: type of elements should be the "
|
||||
"same each other.", region<Container>(loc, first, loc.iter()),
|
||||
"inhomogeneous types"));
|
||||
auto array_start_loc = loc;
|
||||
array_start_loc.iter() = first;
|
||||
|
||||
throw syntax_error(format_underline("[error] toml::parse_array: "
|
||||
"type of elements should be the same each other.", {
|
||||
{std::addressof(array_start_loc), "array starts here"},
|
||||
{
|
||||
std::addressof(get_region(retval.front())),
|
||||
"value has type " + stringize(retval.front().type())
|
||||
},
|
||||
{
|
||||
std::addressof(get_region(val.unwrap())),
|
||||
"value has different type, " + stringize(val.unwrap().type())
|
||||
}
|
||||
}));
|
||||
}
|
||||
retval.push_back(std::move(val.unwrap()));
|
||||
}
|
||||
else
|
||||
{
|
||||
return err(val.unwrap_err());
|
||||
auto array_start_loc = loc;
|
||||
array_start_loc.iter() = first;
|
||||
|
||||
throw syntax_error(format_underline("[error] toml::parse_array: "
|
||||
"value having invalid format appeared in an array", {
|
||||
{std::addressof(array_start_loc), "array starts here"},
|
||||
{std::addressof(loc), "it is not a valid value."}
|
||||
}));
|
||||
}
|
||||
|
||||
using lex_array_separator = sequence<maybe<lex_ws>, character<','>>;
|
||||
@@ -901,14 +920,21 @@ parse_array(location<Container>& loc)
|
||||
}
|
||||
else
|
||||
{
|
||||
auto array_start_loc = loc;
|
||||
array_start_loc.iter() = first;
|
||||
|
||||
throw syntax_error(format_underline("[error] toml::parse_array:"
|
||||
" missing array separator `,`", loc, "should be `,`"));
|
||||
" missing array separator `,` after a value", {
|
||||
{std::addressof(array_start_loc), "array starts here"},
|
||||
{std::addressof(loc), "should be `,`"}
|
||||
}));
|
||||
}
|
||||
}
|
||||
}
|
||||
loc.iter() = first;
|
||||
throw syntax_error(format_underline("[error] toml::parse_array: "
|
||||
"array did not closed by `]`", loc, "should be closed"));
|
||||
"array did not closed by `]`",
|
||||
{{std::addressof(loc), "should be closed"}}));
|
||||
}
|
||||
|
||||
template<typename Container>
|
||||
@@ -926,7 +952,8 @@ parse_key_value_pair(location<Container>& loc)
|
||||
{
|
||||
loc.iter() = first;
|
||||
msg = format_underline("[error] toml::parse_key_value_pair: "
|
||||
"empty key is not allowed.", loc, "key expected before '='");
|
||||
"empty key is not allowed.",
|
||||
{{std::addressof(loc), "key expected before '='"}});
|
||||
}
|
||||
return err(std::move(msg));
|
||||
}
|
||||
@@ -941,14 +968,16 @@ parse_key_value_pair(location<Container>& loc)
|
||||
if(std::find(loc.iter(), line_end, '=') != line_end)
|
||||
{
|
||||
msg = format_underline("[error] toml::parse_key_value_pair: "
|
||||
"invalid format for key", loc, "invalid character in key", {
|
||||
"Did you forget '.' to separate dotted-key?",
|
||||
"invalid format for key",
|
||||
{{std::addressof(loc), "invalid character in key"}},
|
||||
{"Did you forget '.' to separate dotted-key?",
|
||||
"Allowed characters for bare key are [0-9a-zA-Z_-]."});
|
||||
}
|
||||
else // if not, the error is lack of key-value separator.
|
||||
{
|
||||
msg = format_underline("[error] toml::parse_key_value_pair: "
|
||||
"missing key-value separator `=`", loc, "should be `=`");
|
||||
"missing key-value separator `=`",
|
||||
{{std::addressof(loc), "should be `=`"}});
|
||||
}
|
||||
loc.iter() = first;
|
||||
return err(std::move(msg));
|
||||
@@ -960,17 +989,17 @@ parse_key_value_pair(location<Container>& loc)
|
||||
{
|
||||
std::string msg;
|
||||
loc.iter() = after_kvsp;
|
||||
// check there is something not a comment/whitespace after `=`
|
||||
if(sequence<maybe<lex_ws>, maybe<lex_comment>, lex_newline>::invoke(loc))
|
||||
{
|
||||
loc.iter() = after_kvsp;
|
||||
msg = format_underline("[error] toml::parse_key_value_pair: "
|
||||
"missing value after key-value separator '='", loc,
|
||||
"expected value, but got nothing");
|
||||
"missing value after key-value separator '='",
|
||||
{{std::addressof(loc), "expected value, but got nothing"}});
|
||||
}
|
||||
else
|
||||
else // there is something not a comment/whitespace, so invalid format.
|
||||
{
|
||||
msg = format_underline("[error] toml::parse_key_value_pair: "
|
||||
"invalid value format", loc, val.unwrap_err());
|
||||
msg = std::move(val.unwrap_err());
|
||||
}
|
||||
loc.iter() = first;
|
||||
return err(msg);
|
||||
@@ -995,6 +1024,75 @@ std::string format_dotted_keys(InputIterator first, const InputIterator last)
|
||||
return retval;
|
||||
}
|
||||
|
||||
// forward decl for is_valid_forward_table_definition
|
||||
template<typename Container>
|
||||
result<std::pair<std::vector<key>, region<Container>>, std::string>
|
||||
parse_table_key(location<Container>& loc);
|
||||
// The following toml file is allowed.
|
||||
// ```toml
|
||||
// [a.b.c] # here, table `a` has element `b`.
|
||||
// foo = "bar"
|
||||
// [a] # merge a = {baz = "qux"} to a = {b = {...}}
|
||||
// baz = "qux"
|
||||
// ```
|
||||
// But the following is not allowed.
|
||||
// ```toml
|
||||
// [a]
|
||||
// b.c.foo = "bar"
|
||||
// [a] # error! the same table [a] defined!
|
||||
// baz = "qux"
|
||||
// ```
|
||||
// The following is neither allowed.
|
||||
// ```toml
|
||||
// a = { b.c.foo = "bar"}
|
||||
// [a] # error! the same table [a] defined!
|
||||
// baz = "qux"
|
||||
// ```
|
||||
// Here, it parses region of `tab->at(k)` as a table key and check the depth
|
||||
// of the key. If the key region points deeper node, it would be allowed.
|
||||
// Otherwise, the key points the same node. It would be rejected.
|
||||
template<typename Iterator>
|
||||
bool is_valid_forward_table_definition(const value& fwd,
|
||||
Iterator key_first, Iterator key_curr, Iterator key_last)
|
||||
{
|
||||
location<std::string> def("internal", detail::get_region(fwd).str());
|
||||
if(const auto tabkeys = parse_table_key(def))
|
||||
{
|
||||
// table keys always contains all the nodes from the root.
|
||||
const auto& tks = tabkeys.unwrap().first;
|
||||
if(std::size_t(std::distance(key_first, key_last)) == tks.size() &&
|
||||
std::equal(tks.begin(), tks.end(), key_first))
|
||||
{
|
||||
// the keys are equivalent. it is not allowed.
|
||||
return false;
|
||||
}
|
||||
// the keys are not equivalent. it is allowed.
|
||||
return true;
|
||||
}
|
||||
if(const auto dotkeys = parse_key(def))
|
||||
{
|
||||
// consider the following case.
|
||||
// [a]
|
||||
// b.c = {d = 42}
|
||||
// [a.b.c]
|
||||
// e = 2.71
|
||||
// this defines the table [a.b.c] twice. no?
|
||||
|
||||
// a dotted key starts from the node representing a table in which the
|
||||
// dotted key belongs to.
|
||||
const auto& dks = dotkeys.unwrap().first;
|
||||
if(std::size_t(std::distance(key_curr, key_last)) == dks.size() &&
|
||||
std::equal(dks.begin(), dks.end(), key_curr))
|
||||
{
|
||||
// the keys are equivalent. it is not allowed.
|
||||
return false;
|
||||
}
|
||||
// the keys are not equivalent. it is allowed.
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
template<typename InputIterator, typename Container>
|
||||
result<bool, std::string>
|
||||
insert_nested_key(table& root, const toml::value& v,
|
||||
@@ -1026,19 +1124,26 @@ insert_nested_key(table& root, const toml::value& v,
|
||||
// show special err msg for conflicting table
|
||||
throw syntax_error(format_underline(concat_to_string(
|
||||
"[error] toml::insert_value: array of table (\"",
|
||||
format_dotted_keys(first, last), "\") cannot insert"
|
||||
"ed"), get_region(tab->at(k)), "table already defined",
|
||||
get_region(v), "this conflicts with the previous table"));
|
||||
format_dotted_keys(first, last),
|
||||
"\") cannot be defined"), {
|
||||
{std::addressof(get_region(tab->at(k))),
|
||||
"table already defined"},
|
||||
{std::addressof(get_region(v)),
|
||||
"this conflicts with the previous table"}
|
||||
}));
|
||||
}
|
||||
else if(!(tab->at(k).is(value_t::Array)))
|
||||
{
|
||||
throw syntax_error(format_underline(concat_to_string(
|
||||
"[error] toml::insert_value: array of table (\"",
|
||||
format_dotted_keys(first, last), "\") collides with"
|
||||
" existing value"), get_region(tab->at(k)),
|
||||
concat_to_string("this ", tab->at(k).type(),
|
||||
" value already exists"), get_region(v),
|
||||
"while inserting this array-of-tables"));
|
||||
" existing value"), {
|
||||
{std::addressof(get_region(tab->at(k))),
|
||||
concat_to_string("this ", tab->at(k).type(),
|
||||
" value already exists")},
|
||||
{std::addressof(get_region(v)),
|
||||
"while inserting this array-of-tables"}
|
||||
}));
|
||||
}
|
||||
array& a = tab->at(k).template cast<toml::value_t::Array>();
|
||||
if(!(a.front().is(value_t::Table)))
|
||||
@@ -1046,10 +1151,13 @@ insert_nested_key(table& root, const toml::value& v,
|
||||
throw syntax_error(format_underline(concat_to_string(
|
||||
"[error] toml::insert_value: array of table (\"",
|
||||
format_dotted_keys(first, last), "\") collides with"
|
||||
" existing value"), get_region(tab->at(k)),
|
||||
concat_to_string("this ", tab->at(k).type(),
|
||||
" value already exists"), get_region(v),
|
||||
"while inserting this array-of-tables"));
|
||||
" existing value"), {
|
||||
{std::addressof(get_region(tab->at(k))),
|
||||
concat_to_string("this ", tab->at(k).type(),
|
||||
" value already exists")},
|
||||
{std::addressof(get_region(v)),
|
||||
"while inserting this array-of-tables"}
|
||||
}));
|
||||
}
|
||||
// avoid conflicting array of table like the following.
|
||||
// ```toml
|
||||
@@ -1071,10 +1179,13 @@ insert_nested_key(table& root, const toml::value& v,
|
||||
throw syntax_error(format_underline(concat_to_string(
|
||||
"[error] toml::insert_value: array of table (\"",
|
||||
format_dotted_keys(first, last), "\") collides with"
|
||||
" existing array-of-tables"), get_region(tab->at(k)),
|
||||
concat_to_string("this ", tab->at(k).type(),
|
||||
" value has static size"), get_region(v),
|
||||
"appending this to the statically sized array"));
|
||||
" existing array-of-tables"), {
|
||||
{std::addressof(get_region(tab->at(k))),
|
||||
concat_to_string("this ", tab->at(k).type(),
|
||||
" value has static size")},
|
||||
{std::addressof(get_region(v)),
|
||||
"appending it to the statically sized array"}
|
||||
}));
|
||||
}
|
||||
a.push_back(v);
|
||||
return ok(true);
|
||||
@@ -1085,16 +1196,37 @@ insert_nested_key(table& root, const toml::value& v,
|
||||
tab->insert(std::make_pair(k, aot));
|
||||
return ok(true);
|
||||
}
|
||||
}
|
||||
} // end if(array of table)
|
||||
|
||||
if(tab->count(k) == 1)
|
||||
{
|
||||
if(tab->at(k).is(value_t::Table) && v.is(value_t::Table))
|
||||
{
|
||||
throw syntax_error(format_underline(concat_to_string(
|
||||
"[error] toml::insert_value: table (\"",
|
||||
format_dotted_keys(first, last), "\") already exists."),
|
||||
get_region(tab->at(k)), "table already exists here",
|
||||
get_region(v), "table defined twice"));
|
||||
if(!is_valid_forward_table_definition(
|
||||
tab->at(k), first, iter, last))
|
||||
{
|
||||
throw syntax_error(format_underline(concat_to_string(
|
||||
"[error] toml::insert_value: table (\"",
|
||||
format_dotted_keys(first, last),
|
||||
"\") already exists."), {
|
||||
{std::addressof(get_region(tab->at(k))),
|
||||
"table already exists here"},
|
||||
{std::addressof(get_region(v)),
|
||||
"table defined twice"}
|
||||
}));
|
||||
}
|
||||
// to allow the following toml file.
|
||||
// [a.b.c]
|
||||
// d = 42
|
||||
// [a]
|
||||
// e = 2.71
|
||||
auto& t = tab->at(k).cast<value_t::Table>();
|
||||
for(const auto& kv : v.cast<value_t::Table>())
|
||||
{
|
||||
t[kv.first] = kv.second;
|
||||
}
|
||||
detail::change_region(tab->at(k), key_reg);
|
||||
return ok(true);
|
||||
}
|
||||
else if(v.is(value_t::Table) &&
|
||||
tab->at(k).is(value_t::Array) &&
|
||||
@@ -1103,18 +1235,23 @@ insert_nested_key(table& root, const toml::value& v,
|
||||
{
|
||||
throw syntax_error(format_underline(concat_to_string(
|
||||
"[error] toml::insert_value: array of tables (\"",
|
||||
format_dotted_keys(first, last), "\") already exists."),
|
||||
get_region(tab->at(k)), "array of tables defined here",
|
||||
get_region(v), "table conflicts with the previous array"
|
||||
" of table"));
|
||||
format_dotted_keys(first, last), "\") already exists."), {
|
||||
{std::addressof(get_region(tab->at(k))),
|
||||
"array of tables defined here"},
|
||||
{std::addressof(get_region(v)),
|
||||
"table conflicts with the previous array of table"}
|
||||
}));
|
||||
}
|
||||
else
|
||||
{
|
||||
throw syntax_error(format_underline(concat_to_string(
|
||||
"[error] toml::insert_value: value (\"",
|
||||
format_dotted_keys(first, last), "\") already exists."),
|
||||
get_region(tab->at(k)), "value already exists here",
|
||||
get_region(v), "value inserted twice"));
|
||||
format_dotted_keys(first, last), "\") already exists."), {
|
||||
{std::addressof(get_region(tab->at(k))),
|
||||
"value already exists here"},
|
||||
{std::addressof(get_region(v)),
|
||||
"value defined twice"}
|
||||
}));
|
||||
}
|
||||
}
|
||||
tab->insert(std::make_pair(k, v));
|
||||
@@ -1146,9 +1283,11 @@ insert_nested_key(table& root, const toml::value& v,
|
||||
throw syntax_error(format_underline(concat_to_string(
|
||||
"[error] toml::insert_value: target (",
|
||||
format_dotted_keys(first, std::next(iter)),
|
||||
") is neither table nor an array of tables"),
|
||||
get_region(a.back()), concat_to_string("actual type is ",
|
||||
a.back().type()), get_region(v), "inserting this"));
|
||||
") is neither table nor an array of tables"), {
|
||||
{std::addressof(get_region(a.back())),
|
||||
concat_to_string("actual type is ", a.back().type())},
|
||||
{std::addressof(get_region(v)), "inserting this"}
|
||||
}));
|
||||
}
|
||||
tab = std::addressof(a.back().template cast<value_t::Table>());
|
||||
}
|
||||
@@ -1157,9 +1296,11 @@ insert_nested_key(table& root, const toml::value& v,
|
||||
throw syntax_error(format_underline(concat_to_string(
|
||||
"[error] toml::insert_value: target (",
|
||||
format_dotted_keys(first, std::next(iter)),
|
||||
") is neither table nor an array of tables"),
|
||||
get_region(tab->at(k)), concat_to_string("actual type is ",
|
||||
tab->at(k).type()), get_region(v), "inserting this"));
|
||||
") is neither table nor an array of tables"), {
|
||||
{std::addressof(get_region(tab->at(k))),
|
||||
concat_to_string("actual type is ", tab->at(k).type())},
|
||||
{std::addressof(get_region(v)), "inserting this"}
|
||||
}));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1174,8 +1315,8 @@ parse_inline_table(location<Container>& loc)
|
||||
table retval;
|
||||
if(!(loc.iter() != loc.end() && *loc.iter() == '{'))
|
||||
{
|
||||
return err(format_underline("[error] toml::parse_inline_table: ", loc,
|
||||
"the next token is not an inline table"));
|
||||
return err(format_underline("[error] toml::parse_inline_table: ",
|
||||
{{std::addressof(loc), "the next token is not an inline table"}}));
|
||||
}
|
||||
++loc.iter();
|
||||
// it starts from "{". it should be formatted as inline-table
|
||||
@@ -1221,13 +1362,14 @@ parse_inline_table(location<Container>& loc)
|
||||
{
|
||||
throw syntax_error(format_underline("[error] "
|
||||
"toml:::parse_inline_table: missing table separator `,` ",
|
||||
loc, "should be `,`"));
|
||||
{{std::addressof(loc), "should be `,`"}}));
|
||||
}
|
||||
}
|
||||
}
|
||||
loc.iter() = first;
|
||||
throw syntax_error(format_underline("[error] toml::parse_inline_table: "
|
||||
"inline table did not closed by `}`", loc, "should be closed"));
|
||||
"inline table did not closed by `}`",
|
||||
{{std::addressof(loc), "should be closed"}}));
|
||||
}
|
||||
|
||||
template<typename Container>
|
||||
@@ -1236,7 +1378,8 @@ result<value, std::string> parse_value(location<Container>& loc)
|
||||
const auto first = loc.iter();
|
||||
if(first == loc.end())
|
||||
{
|
||||
return err(format_underline("[error] toml::parse_value: input is empty", loc, ""));
|
||||
return err(format_underline("[error] toml::parse_value: input is empty",
|
||||
{{std::addressof(loc), ""}}));
|
||||
}
|
||||
if(auto r = parse_string (loc))
|
||||
{return ok(value(std::move(r.unwrap().first), std::move(r.unwrap().second)));}
|
||||
@@ -1260,7 +1403,7 @@ result<value, std::string> parse_value(location<Container>& loc)
|
||||
{return ok(value(std::move(r.unwrap().first), std::move(r.unwrap().second)));}
|
||||
|
||||
const auto msg = format_underline("[error] toml::parse_value: "
|
||||
"unknown token appeared", loc, "unknown");
|
||||
"unknown token appeared", {{std::addressof(loc), "unknown"}});
|
||||
loc.iter() = first;
|
||||
return err(msg);
|
||||
}
|
||||
@@ -1277,7 +1420,8 @@ parse_table_key(location<Container>& loc)
|
||||
if(!open || inner_loc.iter() == inner_loc.end())
|
||||
{
|
||||
throw internal_error(format_underline("[error] "
|
||||
"toml::parse_table_key: no `[`", inner_loc, "should be `[`"));
|
||||
"toml::parse_table_key: no `[`",
|
||||
{{std::addressof(inner_loc), "should be `[`"}}));
|
||||
}
|
||||
// to skip [ a . b . c ]
|
||||
// ^----------- this whitespace
|
||||
@@ -1286,7 +1430,8 @@ parse_table_key(location<Container>& loc)
|
||||
if(!keys)
|
||||
{
|
||||
throw internal_error(format_underline("[error] "
|
||||
"toml::parse_table_key: invalid key", inner_loc, "not key"));
|
||||
"toml::parse_table_key: invalid key",
|
||||
{{std::addressof(inner_loc), "not key"}}));
|
||||
}
|
||||
// to skip [ a . b . c ]
|
||||
// ^-- this whitespace
|
||||
@@ -1295,7 +1440,8 @@ parse_table_key(location<Container>& loc)
|
||||
if(!close)
|
||||
{
|
||||
throw internal_error(format_underline("[error] "
|
||||
"toml::parse_table_key: no `]`", inner_loc, "should be `]`"));
|
||||
"toml::parse_table_key: no `]`",
|
||||
{{std::addressof(inner_loc), "should be `]`"}}));
|
||||
}
|
||||
|
||||
// after [table.key], newline or EOF(empty table) requried.
|
||||
@@ -1308,7 +1454,7 @@ parse_table_key(location<Container>& loc)
|
||||
{
|
||||
throw syntax_error(format_underline("[error] "
|
||||
"toml::parse_table_key: newline required after [table.key]",
|
||||
loc, "expected newline"));
|
||||
{{std::addressof(loc), "expected newline"}}));
|
||||
}
|
||||
}
|
||||
return ok(std::make_pair(keys.unwrap().first, token.unwrap()));
|
||||
@@ -1331,23 +1477,24 @@ parse_array_table_key(location<Container>& loc)
|
||||
if(!open || inner_loc.iter() == inner_loc.end())
|
||||
{
|
||||
throw internal_error(format_underline("[error] "
|
||||
"toml::parse_array_table_key: no `[[`", inner_loc,
|
||||
"should be `[[`"));
|
||||
"toml::parse_array_table_key: no `[[`",
|
||||
{{std::addressof(inner_loc), "should be `[[`"}}));
|
||||
}
|
||||
lex_ws::invoke(inner_loc);
|
||||
const auto keys = parse_key(inner_loc);
|
||||
if(!keys)
|
||||
{
|
||||
throw internal_error(format_underline("[error] "
|
||||
"toml::parse_array_table_key: invalid key", inner_loc,
|
||||
"not key"));
|
||||
"toml::parse_array_table_key: invalid key",
|
||||
{{std::addressof(inner_loc), "not a key"}}));
|
||||
}
|
||||
lex_ws::invoke(inner_loc);
|
||||
const auto close = lex_array_table_close::invoke(inner_loc);
|
||||
if(!close)
|
||||
{
|
||||
throw internal_error(format_underline("[error] "
|
||||
"toml::parse_table_key: no `]]`", inner_loc, "should be `]]`"));
|
||||
"toml::parse_table_key: no `]]`",
|
||||
{{std::addressof(inner_loc), "should be `]]`"}}));
|
||||
}
|
||||
|
||||
// after [[table.key]], newline or EOF(empty table) requried.
|
||||
@@ -1358,9 +1505,9 @@ parse_array_table_key(location<Container>& loc)
|
||||
const auto nl = lex_newline_after_table_key::invoke(loc);
|
||||
if(!nl)
|
||||
{
|
||||
throw syntax_error(format_underline("[error] "
|
||||
"toml::parse_array_table_key: newline required after "
|
||||
"[[table.key]]", loc, "expected newline"));
|
||||
throw syntax_error(format_underline("[error] toml::"
|
||||
"parse_array_table_key: newline required after [[table.key]]",
|
||||
{{std::addressof(loc), "expected newline"}}));
|
||||
}
|
||||
}
|
||||
return ok(std::make_pair(keys.unwrap().first, token.unwrap()));
|
||||
@@ -1436,8 +1583,8 @@ result<table, std::string> parse_ml_table(location<Container>& loc)
|
||||
const auto before = loc.iter();
|
||||
lex_ws::invoke(loc); // skip whitespace
|
||||
const auto msg = format_underline("[error] toml::parse_table: "
|
||||
"invalid line format", loc, concat_to_string(
|
||||
"expected newline, but got '", show_char(*loc.iter()), "'."));
|
||||
"invalid line format", {{std::addressof(loc), concat_to_string(
|
||||
"expected newline, but got '", show_char(*loc.iter()), "'.")}});
|
||||
loc.iter() = before;
|
||||
return err(msg);
|
||||
}
|
||||
@@ -1507,7 +1654,7 @@ result<table, std::string> parse_toml_file(location<Container>& loc)
|
||||
continue;
|
||||
}
|
||||
return err(format_underline("[error]: toml::parse_toml_file: "
|
||||
"unknown line appeared", loc, "unknown format"));
|
||||
"unknown line appeared", {{std::addressof(loc), "unknown format"}}));
|
||||
}
|
||||
return ok(data);
|
||||
}
|
||||
|
||||
298
toml/region.hpp
298
toml/region.hpp
@@ -1,7 +1,7 @@
|
||||
// Copyright Toru Niina 2017.
|
||||
// Distributed under the MIT License.
|
||||
#ifndef TOML11_REGION_H
|
||||
#define TOML11_REGION_H
|
||||
#ifndef TOML11_REGION_HPP
|
||||
#define TOML11_REGION_HPP
|
||||
#include "exception.hpp"
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
@@ -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
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Copyright Toru Niina 2017.
|
||||
// Distributed under the MIT License.
|
||||
#ifndef TOML11_RESULT_H
|
||||
#define TOML11_RESULT_H
|
||||
#ifndef TOML11_RESULT_HPP
|
||||
#define TOML11_RESULT_HPP
|
||||
#include "traits.hpp"
|
||||
#include <type_traits>
|
||||
#include <stdexcept>
|
||||
|
||||
@@ -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(), std::prev(buf.end()));
|
||||
if(token.back() == '.') // 1. => 1.0
|
||||
{
|
||||
token += '0';
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Copyright Toru Niina 2017.
|
||||
// Distributed under the MIT License.
|
||||
#ifndef TOML11_STRING_H
|
||||
#define TOML11_STRING_H
|
||||
#ifndef TOML11_STRING_HPP
|
||||
#define TOML11_STRING_HPP
|
||||
#include <string>
|
||||
#include <cstdint>
|
||||
|
||||
|
||||
@@ -1,43 +0,0 @@
|
||||
// Copyright Toru Niina 2017.
|
||||
// Distributed under the MIT License.
|
||||
#ifndef TOML11_TO_TOML
|
||||
#define TOML11_TO_TOML
|
||||
#include "value.hpp"
|
||||
|
||||
namespace toml
|
||||
{
|
||||
|
||||
template<typename T>
|
||||
inline value to_toml(T&& x)
|
||||
{
|
||||
return value(std::forward<T>(x));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline value to_toml(T&& x, string_t kind)
|
||||
{
|
||||
return value(std::forward<T>(x), kind);
|
||||
}
|
||||
|
||||
inline value to_toml(local_date d, local_time t)
|
||||
{
|
||||
return value(local_datetime(d, t));
|
||||
}
|
||||
inline value to_toml(local_date d, local_time t, time_offset ofs)
|
||||
{
|
||||
return value(offset_datetime(d, t, ofs));
|
||||
}
|
||||
|
||||
template<typename ... Ts>
|
||||
inline value to_toml(Ts&& ... xs)
|
||||
{
|
||||
return value(toml::array{toml::value(std::forward<Ts>(xs)) ... });
|
||||
}
|
||||
|
||||
inline value to_toml(std::initializer_list<std::pair<std::string, toml::value>> xs)
|
||||
{
|
||||
return value(toml::table(xs.begin(), xs.end()));
|
||||
}
|
||||
|
||||
} // toml
|
||||
#endif // TOML11_TO_TOML
|
||||
@@ -1,7 +1,7 @@
|
||||
// Copyright Toru Niina 2017.
|
||||
// Distributed under the MIT License.
|
||||
#ifndef TOML11_TRAITS
|
||||
#define TOML11_TRAITS
|
||||
#ifndef TOML11_TRAITS_HPP
|
||||
#define TOML11_TRAITS_HPP
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <chrono>
|
||||
@@ -9,6 +9,9 @@
|
||||
|
||||
namespace toml
|
||||
{
|
||||
|
||||
class value; // forward decl
|
||||
|
||||
namespace detail
|
||||
{
|
||||
|
||||
@@ -45,6 +48,22 @@ struct has_resize_method_impl
|
||||
template<typename T> static std::false_type check(...);
|
||||
};
|
||||
|
||||
struct has_from_toml_method_impl
|
||||
{
|
||||
template<typename T>
|
||||
static std::true_type check(
|
||||
decltype(std::declval<T>().from_toml(std::declval<::toml::value>()))*);
|
||||
template<typename T>
|
||||
static std::false_type check(...);
|
||||
};
|
||||
struct has_into_toml_method_impl
|
||||
{
|
||||
template<typename T>
|
||||
static std::true_type check(decltype(std::declval<T>().into_toml())*);
|
||||
template<typename T>
|
||||
static std::false_type check(...);
|
||||
};
|
||||
|
||||
/// Intel C++ compiler can not use decltype in parent class declaration, here
|
||||
/// is a hack to work around it. https://stackoverflow.com/a/23953090/4692076
|
||||
#ifdef __INTEL_COMPILER
|
||||
@@ -62,6 +81,14 @@ struct has_mapped_type : decltype(has_mapped_type_impl::check<T>(nullptr)){};
|
||||
template<typename T>
|
||||
struct has_resize_method : decltype(has_resize_method_impl::check<T>(nullptr)){};
|
||||
|
||||
|
||||
template<typename T>
|
||||
struct has_from_toml_method
|
||||
: decltype(has_from_toml_method_impl::check<T>(nullptr)){};
|
||||
template<typename T>
|
||||
struct has_into_toml_method
|
||||
: decltype(has_into_toml_method_impl::check<T>(nullptr)){};
|
||||
|
||||
#ifdef __INTEL_COMPILER
|
||||
#undef decltype(...)
|
||||
#endif
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Copyright Toru Niina 2017.
|
||||
// Distributed under the MIT License.
|
||||
#ifndef TOML11_TYPES_H
|
||||
#define TOML11_TYPES_H
|
||||
#ifndef TOML11_TYPES_HPP
|
||||
#define TOML11_TYPES_HPP
|
||||
#include "datetime.hpp"
|
||||
#include "string.hpp"
|
||||
#include "traits.hpp"
|
||||
|
||||
@@ -1,12 +1,22 @@
|
||||
// Copyright Toru Niina 2017.
|
||||
// Distributed under the MIT License.
|
||||
#ifndef TOML11_UTILITY
|
||||
#define TOML11_UTILITY
|
||||
#ifndef TOML11_UTILITY_HPP
|
||||
#define TOML11_UTILITY_HPP
|
||||
#include "traits.hpp"
|
||||
#include <utility>
|
||||
#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
|
||||
{
|
||||
|
||||
|
||||
140
toml/value.hpp
140
toml/value.hpp
@@ -1,8 +1,9 @@
|
||||
// Copyright Toru Niina 2017.
|
||||
// Distributed under the MIT License.
|
||||
#ifndef TOML11_VALUE
|
||||
#define TOML11_VALUE
|
||||
#ifndef TOML11_VALUE_HPP
|
||||
#define TOML11_VALUE_HPP
|
||||
#include "traits.hpp"
|
||||
#include "into.hpp"
|
||||
#include "utility.hpp"
|
||||
#include "exception.hpp"
|
||||
#include "storage.hpp"
|
||||
@@ -21,6 +22,8 @@ namespace detail
|
||||
{
|
||||
// to show error messages. not recommended for users.
|
||||
region_base const& get_region(const value&);
|
||||
template<typename Region>
|
||||
void change_region(value&, Region&&);
|
||||
}// detail
|
||||
|
||||
template<typename T>
|
||||
@@ -531,10 +534,62 @@ class value
|
||||
return *this;
|
||||
}
|
||||
|
||||
// user-defined =========================================================
|
||||
|
||||
// convert using into_toml() method -------------------------------------
|
||||
|
||||
template<typename T, typename std::enable_if<detail::conjunction<
|
||||
detail::negation<detail::is_exact_toml_type<T>>, // not a toml::value
|
||||
detail::has_into_toml_method<T> // but has `into_toml` method
|
||||
>::value, std::nullptr_t>::type = nullptr>
|
||||
value(const T& ud): value(ud.into_toml()) {}
|
||||
|
||||
template<typename T, typename std::enable_if<detail::conjunction<
|
||||
detail::negation<detail::is_exact_toml_type<T>>, // not a toml::value
|
||||
detail::has_into_toml_method<T> // but has `into_toml` method
|
||||
>::value, std::nullptr_t>::type = nullptr>
|
||||
value& operator=(const T& ud)
|
||||
{
|
||||
*this = ud.into_toml();
|
||||
return *this;
|
||||
}
|
||||
|
||||
// convert using into<T> struct -----------------------------------------
|
||||
|
||||
template<typename T, typename std::enable_if<
|
||||
detail::negation<detail::is_exact_toml_type<T>>::value,
|
||||
std::nullptr_t>::type = nullptr,
|
||||
std::size_t S = sizeof(::toml::into<T>)>
|
||||
value(const T& ud): value(::toml::into<T>::into_toml(ud)) {}
|
||||
|
||||
template<typename T, typename std::enable_if<
|
||||
detail::negation<detail::is_exact_toml_type<T>>::value,
|
||||
std::nullptr_t>::type = nullptr,
|
||||
std::size_t S = sizeof(::toml::into<T>)>
|
||||
value& operator=(const T& ud)
|
||||
{
|
||||
*this = ::toml::into<T>::into_toml(ud);
|
||||
return *this;
|
||||
}
|
||||
|
||||
// type checking and casting ============================================
|
||||
|
||||
template<typename T>
|
||||
bool is() const noexcept {return value_traits<T>::type_index == this->type_;}
|
||||
bool is(value_t t) const noexcept {return t == this->type_;}
|
||||
|
||||
bool is_uninitialized() const noexcept {return this->is(value_t::Empty );}
|
||||
bool is_boolean() const noexcept {return this->is(value_t::Boolean );}
|
||||
bool is_integer() const noexcept {return this->is(value_t::Integer );}
|
||||
bool is_float() const noexcept {return this->is(value_t::Float );}
|
||||
bool is_string() const noexcept {return this->is(value_t::String );}
|
||||
bool is_offset_datetime() const noexcept {return this->is(value_t::OffsetDatetime);}
|
||||
bool is_local_datetime() const noexcept {return this->is(value_t::LocalDatetime );}
|
||||
bool is_local_date() const noexcept {return this->is(value_t::LocalDate );}
|
||||
bool is_local_time() const noexcept {return this->is(value_t::LocalTime );}
|
||||
bool is_array() const noexcept {return this->is(value_t::Array );}
|
||||
bool is_table() const noexcept {return this->is(value_t::Table );}
|
||||
|
||||
value_t type() const {return type_;}
|
||||
|
||||
template<value_t T>
|
||||
@@ -560,6 +615,9 @@ class value
|
||||
// for error messages
|
||||
friend region_base const& detail::get_region(const value&);
|
||||
|
||||
template<typename Region>
|
||||
friend void detail::change_region(value&, Region&&);
|
||||
|
||||
template<value_t T>
|
||||
struct switch_cast;
|
||||
|
||||
@@ -594,6 +652,20 @@ inline region_base const& get_region(const value& v)
|
||||
{
|
||||
return *(v.region_info_);
|
||||
}
|
||||
|
||||
template<typename Region>
|
||||
void change_region(value& v, Region&& reg)
|
||||
{
|
||||
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
|
||||
|
||||
template<> struct value::switch_cast<value_t::Boolean>
|
||||
@@ -662,9 +734,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);
|
||||
}
|
||||
@@ -673,9 +747,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);
|
||||
}
|
||||
@@ -684,9 +760,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));
|
||||
}
|
||||
@@ -769,22 +847,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