mirror of
https://github.com/ToruNiina/toml11.git
synced 2025-01-10 01:20:06 +00:00
Merge branch 'master' into find-idx
This commit is contained in:
commit
827b433389
@ -12,7 +12,7 @@ jobs:
|
||||
command: |
|
||||
g++ --version
|
||||
cd tests/
|
||||
g++ -std=c++11 -O2 -Wall -Wextra -Werror -I../ check_toml_test.cpp -o check_toml_test
|
||||
g++ -std=c++11 -O2 -Wall -Wextra -Werror -DTOML11_COLORIZE_ERROR_MESSAGE -I../ check_toml_test.cpp -o check_toml_test
|
||||
go get github.com/BurntSushi/toml-test
|
||||
$GOPATH/bin/toml-test ./check_toml_test
|
||||
test_serialization:
|
||||
@ -24,7 +24,7 @@ jobs:
|
||||
command: |
|
||||
g++ --version
|
||||
cd tests/
|
||||
g++ -std=c++11 -O2 -Wall -Wextra -Wpedantic -Werror -I../ check_serialization.cpp -o check_serialization
|
||||
g++ -std=c++11 -O2 -Wall -Wextra -Wpedantic -Werror -DTOML11_COLORIZE_ERROR_MESSAGE -I../ check_serialization.cpp -o check_serialization
|
||||
git clone https://github.com/BurntSushi/toml-test.git
|
||||
cp check_serialization toml-test/tests/valid
|
||||
cd toml-test/tests/valid
|
||||
@ -47,7 +47,7 @@ jobs:
|
||||
command: |
|
||||
g++ --version
|
||||
cd tests/
|
||||
g++ -std=c++11 -O2 -Wall -Wextra -Wpedantic -Werror -I../ check.cpp -o check
|
||||
g++ -std=c++11 -O2 -Wall -Wextra -Wpedantic -Werror -DTOML11_COLORIZE_ERROR_MESSAGE -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
|
||||
|
72
.travis.yml
72
.travis.yml
@ -9,7 +9,7 @@ matrix:
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
- sourceline: 'ppa:ubuntu-toolchain-r/test'
|
||||
- sourceline: 'ppa:mhier/libboost-latest'
|
||||
packages:
|
||||
- g++-5
|
||||
@ -21,7 +21,7 @@ matrix:
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
- sourceline: 'ppa:ubuntu-toolchain-r/test'
|
||||
- sourceline: 'ppa:mhier/libboost-latest'
|
||||
packages:
|
||||
- g++-6
|
||||
@ -33,7 +33,7 @@ matrix:
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
- sourceline: 'ppa:ubuntu-toolchain-r/test'
|
||||
- sourceline: 'ppa:mhier/libboost-latest'
|
||||
packages:
|
||||
- g++-7
|
||||
@ -45,7 +45,7 @@ matrix:
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
- sourceline: 'ppa:ubuntu-toolchain-r/test'
|
||||
- sourceline: 'ppa:mhier/libboost-latest'
|
||||
packages:
|
||||
- g++-8
|
||||
@ -57,7 +57,7 @@ matrix:
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
- sourceline: 'ppa:ubuntu-toolchain-r/test'
|
||||
- sourceline: 'ppa:mhier/libboost-latest'
|
||||
packages:
|
||||
- g++-8
|
||||
@ -69,7 +69,7 @@ matrix:
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
- sourceline: 'ppa:ubuntu-toolchain-r/test'
|
||||
- sourceline: 'ppa:mhier/libboost-latest'
|
||||
packages:
|
||||
- g++-8
|
||||
@ -81,7 +81,7 @@ matrix:
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
- sourceline: 'ppa:ubuntu-toolchain-r/test'
|
||||
- sourceline: 'ppa:mhier/libboost-latest'
|
||||
packages:
|
||||
- g++-8
|
||||
@ -89,16 +89,16 @@ matrix:
|
||||
- os: linux
|
||||
language: cpp
|
||||
compiler: clang
|
||||
env: COMPILER="clang++-3.7" CXX_STANDARD=11 TOML_HEAD=OFF
|
||||
env: COMPILER="clang++-3.9" CXX_STANDARD=11 TOML_HEAD=OFF
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
- llvm-toolchain-precise-3.7
|
||||
- sourceline: 'ppa:ubuntu-toolchain-r/test'
|
||||
- sourceline: 'ppa:mhier/libboost-latest'
|
||||
- llvm-toolchain-trusty-3.9
|
||||
packages:
|
||||
- g++-8
|
||||
- clang-3.7
|
||||
- clang-3.9
|
||||
- boost1.70
|
||||
- os: linux
|
||||
language: cpp
|
||||
@ -107,9 +107,9 @@ matrix:
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
- llvm-toolchain-trusty-4.0
|
||||
- sourceline: 'ppa:ubuntu-toolchain-r/test'
|
||||
- sourceline: 'ppa:mhier/libboost-latest'
|
||||
- llvm-toolchain-trusty-4.0
|
||||
packages:
|
||||
- g++-8
|
||||
- clang-4.0
|
||||
@ -121,9 +121,9 @@ matrix:
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
- llvm-toolchain-trusty-5.0
|
||||
- sourceline: 'ppa:ubuntu-toolchain-r/test'
|
||||
- sourceline: 'ppa:mhier/libboost-latest'
|
||||
- llvm-toolchain-trusty-5.0
|
||||
packages:
|
||||
- g++-8
|
||||
- clang-5.0
|
||||
@ -135,9 +135,9 @@ matrix:
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
- llvm-toolchain-trusty-6.0
|
||||
- sourceline: 'ppa:ubuntu-toolchain-r/test'
|
||||
- sourceline: 'ppa:mhier/libboost-latest'
|
||||
- llvm-toolchain-trusty-6.0
|
||||
packages:
|
||||
- g++-8
|
||||
- clang-6.0
|
||||
@ -149,9 +149,9 @@ matrix:
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
- llvm-toolchain-trusty-7
|
||||
- sourceline: 'ppa:ubuntu-toolchain-r/test'
|
||||
- sourceline: 'ppa:mhier/libboost-latest'
|
||||
- llvm-toolchain-trusty-7
|
||||
packages:
|
||||
- g++-8
|
||||
- clang-7
|
||||
@ -163,9 +163,9 @@ matrix:
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
- llvm-toolchain-trusty-8
|
||||
- sourceline: 'ppa:ubuntu-toolchain-r/test'
|
||||
- sourceline: 'ppa:mhier/libboost-latest'
|
||||
- llvm-toolchain-trusty-8
|
||||
packages:
|
||||
- g++-8
|
||||
- clang-8
|
||||
@ -177,9 +177,9 @@ matrix:
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
- llvm-toolchain-trusty-8
|
||||
- sourceline: 'ppa:ubuntu-toolchain-r/test'
|
||||
- sourceline: 'ppa:mhier/libboost-latest'
|
||||
- llvm-toolchain-trusty-8
|
||||
packages:
|
||||
- g++-8
|
||||
- clang-8
|
||||
@ -191,9 +191,9 @@ matrix:
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
- llvm-toolchain-trusty-8
|
||||
- sourceline: 'ppa:ubuntu-toolchain-r/test'
|
||||
- sourceline: 'ppa:mhier/libboost-latest'
|
||||
- llvm-toolchain-trusty-8
|
||||
packages:
|
||||
- clang-8
|
||||
- g++-8
|
||||
@ -205,9 +205,9 @@ matrix:
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
- llvm-toolchain-trusty-8
|
||||
- sourceline: 'ppa:ubuntu-toolchain-r/test'
|
||||
- sourceline: 'ppa:mhier/libboost-latest'
|
||||
- llvm-toolchain-trusty-8
|
||||
packages:
|
||||
- clang-8
|
||||
- g++-8
|
||||
@ -216,6 +216,15 @@ matrix:
|
||||
language: cpp
|
||||
compiler: clang
|
||||
env: CXX_STANDARD=11
|
||||
cache:
|
||||
directories:
|
||||
- $HOME/Library/Caches/Homebrew
|
||||
addons:
|
||||
homebrew:
|
||||
update: true
|
||||
packages:
|
||||
- cmake
|
||||
- boost
|
||||
|
||||
script:
|
||||
- |
|
||||
@ -224,8 +233,6 @@ script:
|
||||
travis_retry wget "https://github.com/Kitware/CMake/releases/download/v3.14.5/cmake-3.14.5-Linux-x86_64.tar.gz"
|
||||
tar xf cmake-3.14.5-Linux-x86_64.tar.gz -C cmake --strip-components=1
|
||||
export PATH=${TRAVIS_BUILD_DIR}/cmake/bin:${PATH}
|
||||
else
|
||||
brew upgrade cmake boost
|
||||
fi
|
||||
- cmake --version
|
||||
- mkdir build
|
||||
@ -234,3 +241,10 @@ script:
|
||||
- cmake -DCMAKE_CXX_COMPILER=$COMPILER -DCMAKE_CXX_STANDARD=$CXX_STANDARD -DTOML11_USE_UNRELEASED_TOML_FEATURES=${TOML_HEAD} ..
|
||||
- make
|
||||
- ctest --output-on-failure
|
||||
|
||||
# https://stackoverflow.com/a/53331571
|
||||
before_cache:
|
||||
- |
|
||||
if [[ "${TRAVIS_OS_NAME}" == "osx" ]]; then
|
||||
brew cleanup
|
||||
fi
|
||||
|
@ -4,8 +4,8 @@ enable_testing()
|
||||
project(toml11)
|
||||
|
||||
set(toml11_VERSION_MAYOR 3)
|
||||
set(toml11_VERSION_MINOR 0)
|
||||
set(toml11_VERSION_PATCH 1)
|
||||
set(toml11_VERSION_MINOR 2)
|
||||
set(toml11_VERSION_PATCH 0)
|
||||
set(toml11_VERSION
|
||||
"${toml11_VERSION_MAYOR}.${toml11_VERSION_MINOR}.${toml11_VERSION_PATCH}"
|
||||
)
|
||||
|
235
README.md
235
README.md
@ -68,6 +68,9 @@ int main()
|
||||
- [TOML literal](#toml-literal)
|
||||
- [Conversion between toml value and arbitrary types](#conversion-between-toml-value-and-arbitrary-types)
|
||||
- [Formatting user-defined error messages](#formatting-user-defined-error-messages)
|
||||
- [Obtaining location information](#obtaining-location-information)
|
||||
- [Exceptions](#exceptions)
|
||||
- [Colorize Error Messages](#colorize-error-messages)
|
||||
- [Serializing TOML data](#serializing-toml-data)
|
||||
- [Underlying types](#underlying-types)
|
||||
- [Unreleased TOML features](#unreleased-toml-features)
|
||||
@ -351,6 +354,7 @@ The above code works with the following toml file.
|
||||
# NOT {"physical": {"color": "orange"}}.
|
||||
```
|
||||
|
||||
|
||||
## Casting a toml value
|
||||
|
||||
### `toml::get`
|
||||
@ -470,6 +474,44 @@ If an invalid key (integer for a table, string for an array), it throws
|
||||
`toml::type_error` for the conversion. If the provided key is out-of-range,
|
||||
it throws `std::out_of_range`.
|
||||
|
||||
Note that, although `std::string` has `at()` member function, `toml::value::at`
|
||||
throws if the contained type is a string. Because `std::string` does not
|
||||
contain `toml::value`.
|
||||
|
||||
### `operator[]`
|
||||
|
||||
You can also access to the element of a table and an array by
|
||||
`toml::basic_value::operator[]`.
|
||||
|
||||
```cpp
|
||||
const toml::value v{1,2,3,4,5};
|
||||
std::cout << v[2].as_integer() << std::endl; // 3
|
||||
|
||||
const toml::value v{{"foo", 42}, {"bar", 3.14}};
|
||||
std::cout << v["foo"].as_integer() << std::endl; // 42
|
||||
```
|
||||
|
||||
When you access to a `toml::value` that is not initialized yet via
|
||||
`operator[](const std::string&)`, the `toml::value` will be a table,
|
||||
just like the `std::map`.
|
||||
|
||||
```cpp
|
||||
toml::value v; // not initialized as a table.
|
||||
v["foo"] = 42; // OK. `v` will be a table.
|
||||
```
|
||||
|
||||
Contrary, if you access to a `toml::value` that contains an array via `operator[]`,
|
||||
it does not check anything. It converts `toml::value` without type check and then
|
||||
access to the n-th element without boundary check, just like the `std::vector::operator[]`.
|
||||
|
||||
```cpp
|
||||
toml::value v; // not initialized as an array
|
||||
v[2] = 42; // error! UB
|
||||
```
|
||||
|
||||
Please make sure that the `toml::value` has an array inside when you access to
|
||||
its element via `operator[]`.
|
||||
|
||||
## Checking value type
|
||||
|
||||
You can check the type of a value by `is_xxx` function.
|
||||
@ -692,6 +734,7 @@ date information, but it can be converted to `std::chrono::duration` that
|
||||
represents a duration from the beginning of the day, `00:00:00.000`.
|
||||
|
||||
```toml
|
||||
# sample.toml
|
||||
date = 2018-12-23
|
||||
time = 12:30:00
|
||||
l_dt = 2018-12-23T12:30:00
|
||||
@ -708,8 +751,12 @@ const auto o_dt = toml::get<std::chrono::system_clock::time_point>(data.at("o_dt
|
||||
const auto time = toml::get<std::chrono::minutes>(data.at("time")); // 12 * 60 + 30 min
|
||||
```
|
||||
|
||||
toml11 defines its own datetime classes.
|
||||
You can see the definitions in [toml/datetime.hpp](toml/datetime.hpp).
|
||||
`local_date` and `local_datetime` are assumed to be in the local timezone when
|
||||
they are converted into `time_point`. On the other hand, `offset_datetime` only
|
||||
uses the offset part of the data and it does not take local timezone into account.
|
||||
|
||||
To contain datetime data, toml11 defines its own datetime types.
|
||||
For more detail, you can see the definitions in [toml/datetime.hpp](toml/datetime.hpp).
|
||||
|
||||
## Getting with a fallback
|
||||
|
||||
@ -1254,7 +1301,28 @@ you will get an error message like this.
|
||||
| ~~ maximum number here
|
||||
```
|
||||
|
||||
### Obtaining location information
|
||||
You can print hints at the end of the message.
|
||||
|
||||
```cpp
|
||||
std::vector<std::string> hints;
|
||||
hints.push_back("positive number means n >= 0.");
|
||||
hints.push_back("negative number is not positive.");
|
||||
std::cerr << toml::format_error("[error] value should be positive",
|
||||
data.at("num"), "positive number required", hints)
|
||||
<< std::endl;
|
||||
```
|
||||
|
||||
```console
|
||||
[error] value should be positive
|
||||
--> example.toml
|
||||
2 | num = 42
|
||||
| ~~ positive number required
|
||||
|
|
||||
Hint: positive number means n >= 0.
|
||||
Hint: negative number is not positive.
|
||||
```
|
||||
|
||||
## Obtaining location information
|
||||
|
||||
You can also format error messages in your own way by using `source_location`.
|
||||
|
||||
@ -1279,6 +1347,92 @@ const toml::value v = /*...*/;
|
||||
const toml::source_location loc = v.location();
|
||||
```
|
||||
|
||||
## Exceptions
|
||||
|
||||
All the exceptions thrown by toml11 inherits `toml::exception` that inherits
|
||||
`std::exception`.
|
||||
|
||||
```cpp
|
||||
namespace toml {
|
||||
struct exception : public std::exception {/**/};
|
||||
struct syntax_error : public toml::exception {/**/};
|
||||
struct type_error : public toml::exception {/**/};
|
||||
struct internal_error : public toml::exception {/**/};
|
||||
} // toml
|
||||
```
|
||||
|
||||
`toml::exception` has `toml::exception::location()` member function that returns
|
||||
`toml::source_location`, in addition to `what()`.
|
||||
|
||||
```cpp
|
||||
namespace toml {
|
||||
struct exception : public std::exception
|
||||
{
|
||||
// ...
|
||||
source_location const& location() const noexcept;
|
||||
};
|
||||
} // toml
|
||||
```
|
||||
|
||||
It represents where the error occurs.
|
||||
|
||||
## Colorize Error Messages
|
||||
|
||||
By defining `TOML11_COLORIZE_ERROR_MESSAGE`, the error messages from
|
||||
`toml::parse` and `toml::find|get` will be colorized. By default, this feature
|
||||
is turned off.
|
||||
|
||||
With the following toml file taken from `toml-lang/toml/tests/hard_example.toml`,
|
||||
|
||||
```toml
|
||||
[error]
|
||||
array = [
|
||||
"This might most likely happen in multiline arrays",
|
||||
Like here,
|
||||
"or here,
|
||||
and here"
|
||||
] End of array comment, forgot the #
|
||||
```
|
||||
|
||||
the error message would be like this.
|
||||
|
||||
![error-message-1](https://github.com/ToruNiina/toml11/blob/misc/misc/toml11-err-msg-1.png)
|
||||
|
||||
With the following,
|
||||
|
||||
```toml
|
||||
[error]
|
||||
# array = [
|
||||
# "This might most likely happen in multiline arrays",
|
||||
# Like here,
|
||||
# "or here,
|
||||
# and here"
|
||||
# ] End of array comment, forgot the #
|
||||
number = 3.14 pi <--again forgot the #
|
||||
```
|
||||
|
||||
the error message would be like this.
|
||||
|
||||
![error-message-2](https://github.com/ToruNiina/toml11/blob/misc/misc/toml11-err-msg-2.png)
|
||||
|
||||
The message would be messy when it is written to a file, not a terminal because
|
||||
it uses [ANSI escape code](https://en.wikipedia.org/wiki/ANSI_escape_code).
|
||||
|
||||
Without `TOML11_COLORIZE_ERROR_MESSAGE`, you can still colorize user-defined
|
||||
error message by passing `true` to the `toml::format_error` function.
|
||||
If you define `TOML11_COLORIZE_ERROR_MESSAGE`, the value is `true` by default.
|
||||
If not, the defalut value would be `false`.
|
||||
|
||||
```cpp
|
||||
std::cerr << toml::format_error("[error] value should be positive",
|
||||
data.at("num"), "positive number required",
|
||||
hints, /*colorize = */ true) << std::endl;
|
||||
```
|
||||
|
||||
Note: It colorize `[error]` in red. That means that it detects `[error]` prefix
|
||||
at the front of the error message. If there is no `[error]` prefix,
|
||||
`format_error` adds it to the error message.
|
||||
|
||||
## Serializing TOML data
|
||||
|
||||
toml11 enables you to serialize data into toml format.
|
||||
@ -1411,17 +1565,83 @@ This feature is introduced to make it easy to write a custom serializer.
|
||||
Because `std::chrono::system_clock::time_point` is a __time point__,
|
||||
not capable of representing a Local Time independent from a specific day.
|
||||
|
||||
It is recommended to get `datetime`s as `std::chrono` classes through `toml::get`.
|
||||
|
||||
## Unreleased TOML features
|
||||
|
||||
There are some unreleased features in toml-lang/toml:master.
|
||||
Currently, the following features are available after defining
|
||||
`TOML11_USE_UNRELEASED_TOML_FEATURES` macro flag.
|
||||
|
||||
To use those features, `#define` `TOML11_USE_UNRELEASED_TOML_FEATURES` before
|
||||
including `toml.hpp` or pass `-DTOML11_USE_UNRELEASED_TOML_FEATURES` to your
|
||||
compiler.
|
||||
|
||||
- Leading zeroes in exponent parts of floats are permitted.
|
||||
- e.g. `1.0e+01`, `5e+05`
|
||||
- [toml-lang/toml/PR/656](https://github.com/toml-lang/toml/pull/656)
|
||||
- Allow raw tab characters in basic strings and multi-line basic strings.
|
||||
- [toml-lang/toml/PR/627](https://github.com/toml-lang/toml/pull/627)
|
||||
- Allow heterogeneous arrays
|
||||
- [toml-lang/toml/PR/676](https://github.com/toml-lang/toml/pull/676)
|
||||
|
||||
### Note about heterogeneous arrays
|
||||
|
||||
Although `toml::parse` allows heterogeneous arrays, constructor of `toml::value`
|
||||
does not.
|
||||
|
||||
```cpp
|
||||
// this won't be compiled
|
||||
toml::value v{
|
||||
"foo", 3.14, 42, {1,2,3,4,5}, {{"key", "value"}}
|
||||
}
|
||||
```
|
||||
|
||||
There is a workaround for this issue. By explicitly converting values into
|
||||
`toml::value`, you can initialize `toml::value` with a heterogeneous array.
|
||||
|
||||
```cpp
|
||||
// OK!
|
||||
toml::value v{
|
||||
toml::value("foo"), toml::value(3.14), toml::value(42),
|
||||
toml::value{1,2,3,4,5}, toml::value{{"key", "value"}}
|
||||
}
|
||||
```
|
||||
|
||||
The reason why the first example is not allowed is the following.
|
||||
Let's assume that you are initializing a `toml::value` with a table.
|
||||
|
||||
```cpp
|
||||
// # expecting TOML table.
|
||||
toml::value v{ // [v]
|
||||
{"answer", 42}, // answer = 42
|
||||
{"pi", 3.14}, // pi = 3.14
|
||||
{"foo", "bar"} // foo = "bar"
|
||||
};
|
||||
```
|
||||
|
||||
This is indistinguishable from a (heterogeneous) TOML array definition.
|
||||
|
||||
```toml
|
||||
v = [
|
||||
["answer", 42],
|
||||
["pi", 3.14],
|
||||
["foo", "bar"],
|
||||
]
|
||||
```
|
||||
|
||||
This means that the above C++ code makes constructor's overload resolution
|
||||
ambiguous. So a constructor that allows both "table as an initializer-list" and
|
||||
"heterogeneous array as an initializer-list" cannot be implemented.
|
||||
|
||||
Thus, although it is painful, you need to explicitly cast values into
|
||||
`toml::value` when you initialize heterogeneous array in C++ code.
|
||||
|
||||
```cpp
|
||||
// You need to do this when you want to initialize hetero array.
|
||||
toml::value v{
|
||||
toml::value("foo"), toml::value(3.14), toml::value(42),
|
||||
toml::value{1,2,3,4,5}, toml::value{{"key", "value"}}
|
||||
}
|
||||
```
|
||||
|
||||
## Breaking Changes from v2
|
||||
|
||||
@ -1494,6 +1714,11 @@ I appreciate the help of the contributors who introduced the great feature to th
|
||||
- Added installation script to CMake
|
||||
- J.C. Moyer (@jcmoyer)
|
||||
- Fixed an example code in the documentation
|
||||
- Jt Freeman (@blockparty-sh)
|
||||
- Fixed feature test macro around `localtime_s`
|
||||
- Suppress warnings in Debug mode
|
||||
- OGAWA Kenichi (@kenichiice)
|
||||
- Suppress warnings on intel compiler
|
||||
|
||||
## Licensing terms
|
||||
|
||||
|
@ -80,10 +80,14 @@ BOOST_AUTO_TEST_CASE(test_detect_conflicting_value)
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_detect_inhomogeneous_array)
|
||||
{
|
||||
#ifdef TOML11_USE_UNRELEASED_TOML_FEATURES
|
||||
BOOST_TEST_MESSAGE("heterogeneous array will be allowed in the next release");
|
||||
#else
|
||||
std::istringstream stream(std::string(
|
||||
"a = [1, 1.0]\n"
|
||||
));
|
||||
BOOST_CHECK_THROW(toml::parse(stream), toml::syntax_error);
|
||||
#endif
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_detect_appending_array_of_table)
|
||||
|
@ -128,3 +128,47 @@ BOOST_AUTO_TEST_CASE(test_multiline_array_value)
|
||||
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>, "[\"foo\",#comment\n\"b#r\",#comment\n\"b#z\"#comment\n]", toml::value(a));
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_heterogeneous_array)
|
||||
{
|
||||
#ifndef TOML11_USE_UNRELEASED_TOML_FEATURES
|
||||
BOOST_TEST_MESSAGE("In strict TOML v0.5.0, heterogeneous arrays are not allowed.");
|
||||
#else
|
||||
{
|
||||
array a(5);
|
||||
a[0] = toml::value("foo");
|
||||
a[1] = toml::value(3.14);
|
||||
a[2] = toml::value(42);
|
||||
a[3] = toml::value{toml::value("array"), toml::value("of"), toml::value("hetero-array"), toml::value(1)};
|
||||
a[4] = toml::value{{"key", "value"}};
|
||||
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>, "[\"foo\", 3.14, 42, [\"array\", \"of\", \"hetero-array\", 1], {key = \"value\"}]", toml::value(a));
|
||||
}
|
||||
{
|
||||
array a(5);
|
||||
a[0] = toml::value("foo");
|
||||
a[1] = toml::value(3.14);
|
||||
a[2] = toml::value(42);
|
||||
a[3] = toml::value{toml::value("array"), toml::value("of"), toml::value("hetero-array"), toml::value(1)};
|
||||
a[4] = toml::value{{"key", "value"}};
|
||||
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>, "[\"foo\",\n 3.14,\n 42,\n [\"array\", \"of\", \"hetero-array\", 1],\n {key = \"value\"},\n]", toml::value(a));
|
||||
}
|
||||
{
|
||||
array a(5);
|
||||
a[0] = toml::value("foo");
|
||||
a[1] = toml::value(3.14);
|
||||
a[2] = toml::value(42);
|
||||
a[3] = toml::value{toml::value("array"), toml::value("of"), toml::value("hetero-array"), toml::value(1)};
|
||||
a[4] = toml::value{{"key", "value"}};
|
||||
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>, "[\"foo\",#comment\n 3.14,#comment\n 42,#comment\n [\"array\", \"of\", \"hetero-array\", 1],#comment\n {key = \"value\"},#comment\n]#comment", toml::value(a));
|
||||
}
|
||||
{
|
||||
array a(5);
|
||||
a[0] = toml::value("foo");
|
||||
a[1] = toml::value(3.14);
|
||||
a[2] = toml::value(42);
|
||||
a[3] = toml::value{toml::value("array"), toml::value("of"), toml::value("hetero-array"), toml::value(1)};
|
||||
a[4] = toml::value{{"key", "value"}};
|
||||
TOML11_TEST_PARSE_EQUAL_VALUE(parse_value<toml::value>, "[\"foo\",\n 3.14,\n 42,\n [\"array\",\n \"of\",\n \"hetero-array\",\n 1],\n {key = \"value\"},\n]", toml::value(a));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
@ -111,3 +111,44 @@ BOOST_AUTO_TEST_CASE(test_literal_ml_string)
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_string_add_assign)
|
||||
{
|
||||
// string literal
|
||||
{
|
||||
toml::string str("foo");
|
||||
str += "bar";
|
||||
BOOST_TEST(str.str == "foobar");
|
||||
}
|
||||
// std::string
|
||||
{
|
||||
toml::string str("foo");
|
||||
std::string str2("bar");
|
||||
str += str2;
|
||||
BOOST_TEST(str.str == "foobar");
|
||||
}
|
||||
// toml::string
|
||||
{
|
||||
toml::string str("foo");
|
||||
toml::string str2("bar");
|
||||
str += str2;
|
||||
BOOST_TEST(str.str == "foobar");
|
||||
}
|
||||
#if __cplusplus >= 201703L
|
||||
// std::string_view
|
||||
{
|
||||
toml::string str("foo");
|
||||
str += std::string_view("bar");
|
||||
BOOST_TEST(str == "foobar");
|
||||
}
|
||||
#endif
|
||||
// std::string += toml::string
|
||||
{
|
||||
std::string str("foo");
|
||||
toml::string str2("bar");
|
||||
str += str2;
|
||||
BOOST_TEST(str == "foobar");
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
@ -934,3 +934,35 @@ BOOST_AUTO_TEST_CASE(test_value_at)
|
||||
BOOST_CHECK_THROW(v1.at(5), std::out_of_range);
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_value_bracket)
|
||||
{
|
||||
{
|
||||
toml::value v1{{"foo", 42}, {"bar", 3.14}, {"baz", "qux"}};
|
||||
|
||||
BOOST_TEST(v1["foo"].as_integer() == 42);
|
||||
BOOST_TEST(v1["bar"].as_floating() == 3.14);
|
||||
BOOST_TEST(v1["baz"].as_string() == "qux");
|
||||
|
||||
v1["qux"] = 54;
|
||||
BOOST_TEST(v1["qux"].as_integer() == 54);
|
||||
}
|
||||
{
|
||||
toml::value v1;
|
||||
v1["foo"] = 42;
|
||||
|
||||
BOOST_TEST(v1.is_table());
|
||||
BOOST_TEST(v1["foo"].as_integer() == 42);
|
||||
}
|
||||
{
|
||||
toml::value v1{1,2,3,4,5};
|
||||
|
||||
BOOST_TEST(v1[0].as_integer() == 1);
|
||||
BOOST_TEST(v1[1].as_integer() == 2);
|
||||
BOOST_TEST(v1[2].as_integer() == 3);
|
||||
BOOST_TEST(v1[3].as_integer() == 4);
|
||||
BOOST_TEST(v1[4].as_integer() == 5);
|
||||
|
||||
BOOST_CHECK_THROW(v1["foo"], toml::type_error);
|
||||
}
|
||||
}
|
||||
|
64
toml/color.hpp
Normal file
64
toml/color.hpp
Normal file
@ -0,0 +1,64 @@
|
||||
#ifndef TOML11_COLOR_HPP
|
||||
#define TOML11_COLOR_HPP
|
||||
#include <ostream>
|
||||
#include <cstdint>
|
||||
|
||||
#ifdef TOML11_COLORIZE_ERROR_MESSAGE
|
||||
#define TOML11_ERROR_MESSAGE_COLORIZED true
|
||||
#else
|
||||
#define TOML11_ERROR_MESSAGE_COLORIZED false
|
||||
#endif
|
||||
|
||||
namespace toml
|
||||
{
|
||||
|
||||
// put ANSI escape sequence to ostream
|
||||
namespace color_ansi
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
inline int colorize_index()
|
||||
{
|
||||
static const int index = std::ios_base::xalloc();
|
||||
return index;
|
||||
}
|
||||
} // detail
|
||||
|
||||
inline std::ostream& colorize(std::ostream& os)
|
||||
{
|
||||
// by default, it is zero.
|
||||
os.iword(detail::colorize_index()) = 1;
|
||||
return os;
|
||||
}
|
||||
inline std::ostream& nocolorize(std::ostream& os)
|
||||
{
|
||||
os.iword(detail::colorize_index()) = 0;
|
||||
return os;
|
||||
}
|
||||
inline std::ostream& reset (std::ostream& os)
|
||||
{if(os.iword(detail::colorize_index()) == 1) {os << "\033[00m";} return os;}
|
||||
inline std::ostream& bold (std::ostream& os)
|
||||
{if(os.iword(detail::colorize_index()) == 1) {os << "\033[01m";} return os;}
|
||||
inline std::ostream& grey (std::ostream& os)
|
||||
{if(os.iword(detail::colorize_index()) == 1) {os << "\033[30m";} return os;}
|
||||
inline std::ostream& red (std::ostream& os)
|
||||
{if(os.iword(detail::colorize_index()) == 1) {os << "\033[31m";} return os;}
|
||||
inline std::ostream& green (std::ostream& os)
|
||||
{if(os.iword(detail::colorize_index()) == 1) {os << "\033[32m";} return os;}
|
||||
inline std::ostream& yellow (std::ostream& os)
|
||||
{if(os.iword(detail::colorize_index()) == 1) {os << "\033[33m";} return os;}
|
||||
inline std::ostream& blue (std::ostream& os)
|
||||
{if(os.iword(detail::colorize_index()) == 1) {os << "\033[34m";} return os;}
|
||||
inline std::ostream& magenta(std::ostream& os)
|
||||
{if(os.iword(detail::colorize_index()) == 1) {os << "\033[35m";} return os;}
|
||||
inline std::ostream& cyan (std::ostream& os)
|
||||
{if(os.iword(detail::colorize_index()) == 1) {os << "\033[36m";} return os;}
|
||||
inline std::ostream& white (std::ostream& os)
|
||||
{if(os.iword(detail::colorize_index()) == 1) {os << "\033[37m";} return os;}
|
||||
} // color_ansi
|
||||
|
||||
// ANSI escape sequence is the only and default colorization method currently
|
||||
namespace color = color_ansi;
|
||||
|
||||
} // toml
|
||||
#endif// TOML11_COLOR_HPP
|
@ -45,6 +45,7 @@ inline std::string show_char(const char c)
|
||||
buf.fill('\0');
|
||||
const auto r = std::snprintf(
|
||||
buf.data(), buf.size(), "0x%02x", static_cast<int>(c) & 0xFF);
|
||||
(void) r; // Unused variable warning
|
||||
assert(r == static_cast<int>(buf.size()) - 1);
|
||||
return std::string(buf.data());
|
||||
}
|
||||
|
@ -20,7 +20,7 @@ namespace toml
|
||||
namespace detail
|
||||
{
|
||||
// TODO: find more sophisticated way to handle this
|
||||
#if _POSIX_C_SOURCE >= 1 || _XOPEN_SOURCE || _BSD_SOURCE || _SVID_SOURCE || _POSIX_SOURCE
|
||||
#if _POSIX_C_SOURCE >= 1 || defined(_XOPEN_SOURCE) || defined(_BSD_SOURCE) || defined(_SVID_SOURCE) || defined(_POSIX_SOURCE)
|
||||
inline std::tm localtime_s(const std::time_t* src)
|
||||
{
|
||||
std::tm dst;
|
||||
@ -28,6 +28,13 @@ inline std::tm localtime_s(const std::time_t* src)
|
||||
if (!result) { throw std::runtime_error("localtime_r failed."); }
|
||||
return dst;
|
||||
}
|
||||
inline std::tm gmtime_s(const std::time_t* src)
|
||||
{
|
||||
std::tm dst;
|
||||
const auto result = ::gmtime_r(src, &dst);
|
||||
if (!result) { throw std::runtime_error("gmtime_r failed."); }
|
||||
return dst;
|
||||
}
|
||||
#elif _MSC_VER
|
||||
inline std::tm localtime_s(const std::time_t* src)
|
||||
{
|
||||
@ -36,13 +43,26 @@ inline std::tm localtime_s(const std::time_t* src)
|
||||
if (result) { throw std::runtime_error("localtime_s failed."); }
|
||||
return dst;
|
||||
}
|
||||
#else
|
||||
inline std::tm gmtime_s(const std::time_t* src)
|
||||
{
|
||||
std::tm dst;
|
||||
const auto result = ::gmtime_s(&dst, src);
|
||||
if (result) { throw std::runtime_error("gmtime_s failed."); }
|
||||
return dst;
|
||||
}
|
||||
#else // fallback. not threadsafe
|
||||
inline std::tm localtime_s(const std::time_t* src)
|
||||
{
|
||||
const auto result = std::localtime(src);
|
||||
if (!result) { throw std::runtime_error("localtime failed."); }
|
||||
return *result;
|
||||
}
|
||||
inline std::tm gmtime_s(const std::time_t* src)
|
||||
{
|
||||
const auto result = std::gmtime(src);
|
||||
if (!result) { throw std::runtime_error("gmtime failed."); }
|
||||
return *result;
|
||||
}
|
||||
#endif
|
||||
} // detail
|
||||
|
||||
@ -378,10 +398,31 @@ struct local_datetime
|
||||
{
|
||||
using internal_duration =
|
||||
typename std::chrono::system_clock::time_point::duration;
|
||||
|
||||
// Normally DST begins at A.M. 3 or 4. If we re-use conversion operator
|
||||
// of local_date and local_time independently, the conversion fails if
|
||||
// it is the day when DST begins or ends. Since local_date considers the
|
||||
// time is 00:00 A.M. and local_time does not consider DST because it
|
||||
// does not have any date information. We need to consider both date and
|
||||
// time information at the same time to convert it correctly.
|
||||
|
||||
std::tm t;
|
||||
t.tm_sec = static_cast<int>(this->time.second);
|
||||
t.tm_min = static_cast<int>(this->time.minute);
|
||||
t.tm_hour = static_cast<int>(this->time.hour);
|
||||
t.tm_mday = static_cast<int>(this->date.day);
|
||||
t.tm_mon = static_cast<int>(this->date.month);
|
||||
t.tm_year = static_cast<int>(this->date.year) - 1900;
|
||||
t.tm_wday = 0; // the value will be ignored
|
||||
t.tm_yday = 0; // the value will be ignored
|
||||
t.tm_isdst = -1;
|
||||
|
||||
// std::mktime returns date as local time zone. no conversion needed
|
||||
auto dt = std::chrono::system_clock::time_point(this->date);
|
||||
auto dt = std::chrono::system_clock::from_time_t(std::mktime(&t));
|
||||
dt += std::chrono::duration_cast<internal_duration>(
|
||||
std::chrono::nanoseconds(this->time));
|
||||
std::chrono::milliseconds(this->time.millisecond) +
|
||||
std::chrono::microseconds(this->time.microsecond) +
|
||||
std::chrono::nanoseconds (this->time.nanosecond));
|
||||
return dt;
|
||||
}
|
||||
|
||||
@ -447,40 +488,71 @@ struct offset_datetime
|
||||
: date(dt.date), time(dt.time), offset(o)
|
||||
{}
|
||||
explicit offset_datetime(const local_datetime& ld)
|
||||
: date(ld.date), time(ld.time), offset(get_local_offset())
|
||||
: date(ld.date), time(ld.time), offset(get_local_offset(nullptr))
|
||||
// use the current local timezone offset
|
||||
{}
|
||||
explicit offset_datetime(const std::chrono::system_clock::time_point& tp)
|
||||
: offset_datetime(local_datetime(tp))
|
||||
{}
|
||||
: offset(0, 0) // use gmtime
|
||||
{
|
||||
const auto timet = std::chrono::system_clock::to_time_t(tp);
|
||||
const auto tm = detail::gmtime_s(&timet);
|
||||
this->date = local_date(tm);
|
||||
this->time = local_time(tm);
|
||||
}
|
||||
explicit offset_datetime(const std::time_t& t)
|
||||
: offset_datetime(local_datetime(t))
|
||||
{}
|
||||
: offset(0, 0) // use gmtime
|
||||
{
|
||||
const auto tm = detail::gmtime_s(&t);
|
||||
this->date = local_date(tm);
|
||||
this->time = local_time(tm);
|
||||
}
|
||||
explicit offset_datetime(const std::tm& t)
|
||||
: offset_datetime(local_datetime(t))
|
||||
{}
|
||||
: offset(0, 0) // assume gmtime
|
||||
{
|
||||
this->date = local_date(t);
|
||||
this->time = local_time(t);
|
||||
}
|
||||
|
||||
operator std::chrono::system_clock::time_point() const
|
||||
{
|
||||
// get date-time
|
||||
using internal_duration =
|
||||
typename std::chrono::system_clock::time_point::duration;
|
||||
std::chrono::system_clock::time_point tp =
|
||||
std::chrono::system_clock::time_point(this->date) +
|
||||
std::chrono::duration_cast<internal_duration>(
|
||||
std::chrono::nanoseconds(this->time));
|
||||
|
||||
// get date-time in UTC. let's say we are in +09:00 (JPN).
|
||||
// writing 12:00:00 in +09:00 means 03:00:00Z. to represent
|
||||
// 12:00:00Z, first we need to add +09:00.
|
||||
const auto ofs = get_local_offset();
|
||||
// first, convert it to local date-time information in the same way as
|
||||
// local_datetime does. later we will use time_t to adjust time offset.
|
||||
std::tm t;
|
||||
t.tm_sec = static_cast<int>(this->time.second);
|
||||
t.tm_min = static_cast<int>(this->time.minute);
|
||||
t.tm_hour = static_cast<int>(this->time.hour);
|
||||
t.tm_mday = static_cast<int>(this->date.day);
|
||||
t.tm_mon = static_cast<int>(this->date.month);
|
||||
t.tm_year = static_cast<int>(this->date.year) - 1900;
|
||||
t.tm_wday = 0; // the value will be ignored
|
||||
t.tm_yday = 0; // the value will be ignored
|
||||
t.tm_isdst = -1;
|
||||
const std::time_t tp_loc = std::mktime(std::addressof(t));
|
||||
|
||||
auto tp = std::chrono::system_clock::from_time_t(tp_loc);
|
||||
tp += std::chrono::duration_cast<internal_duration>(
|
||||
std::chrono::milliseconds(this->time.millisecond) +
|
||||
std::chrono::microseconds(this->time.microsecond) +
|
||||
std::chrono::nanoseconds (this->time.nanosecond));
|
||||
|
||||
// Since mktime uses local time zone, it should be corrected.
|
||||
// `12:00:00+09:00` means `03:00:00Z`. So mktime returns `03:00:00Z` if
|
||||
// we are in `+09:00` timezone. To represent `12:00:00Z` there, we need
|
||||
// to add `+09:00` to `03:00:00Z`.
|
||||
// Here, it uses the time_t converted from date-time info to handle
|
||||
// daylight saving time.
|
||||
const auto ofs = get_local_offset(std::addressof(tp_loc));
|
||||
tp += std::chrono::hours (ofs.hour);
|
||||
tp += std::chrono::minutes(ofs.minute);
|
||||
|
||||
// here, tp represents 12:00:00 in UTC but we have offset information.
|
||||
// we need to subtract it. For example, let's say the input is
|
||||
// 12:00:00-08:00. now we have tp = 12:00:00Z as a result of the above
|
||||
// conversion. But the actual time we need to return is 20:00:00Z
|
||||
// because of -08:00.
|
||||
// We got `12:00:00Z` by correcting local timezone applied by mktime.
|
||||
// Then we will apply the offset. Let's say `12:00:00-08:00` is given.
|
||||
// And now, we have `12:00:00Z`. `12:00:00-08:00` means `20:00:00Z`.
|
||||
// So we need to subtract the offset.
|
||||
tp -= std::chrono::minutes(this->offset);
|
||||
return tp;
|
||||
}
|
||||
@ -500,11 +572,10 @@ struct offset_datetime
|
||||
|
||||
private:
|
||||
|
||||
static time_offset get_local_offset()
|
||||
static time_offset get_local_offset(const std::time_t* tp)
|
||||
{
|
||||
// get current timezone
|
||||
const auto tmp1 = std::time(nullptr);
|
||||
const auto t = detail::localtime_s(&tmp1);
|
||||
// get local timezone with the same date-time information as mktime
|
||||
const auto t = detail::localtime_s(tp);
|
||||
|
||||
std::array<char, 6> buf;
|
||||
const auto result = std::strftime(buf.data(), 6, "%z", &t); // +hhmm\0
|
||||
|
@ -2,6 +2,7 @@
|
||||
// Distributed under the MIT License.
|
||||
#ifndef TOML11_EXCEPTION_HPP
|
||||
#define TOML11_EXCEPTION_HPP
|
||||
#include "source_location.hpp"
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
|
||||
@ -11,15 +12,21 @@ namespace toml
|
||||
struct exception : public std::exception
|
||||
{
|
||||
public:
|
||||
exception(const source_location& loc): loc_(loc) {}
|
||||
virtual ~exception() noexcept override = default;
|
||||
virtual const char* what() const noexcept override {return "";}
|
||||
virtual source_location const& location() const noexcept {return loc_;}
|
||||
|
||||
protected:
|
||||
source_location loc_;
|
||||
};
|
||||
|
||||
struct syntax_error : public toml::exception
|
||||
{
|
||||
public:
|
||||
explicit syntax_error(const std::string& what_arg) : what_(what_arg){}
|
||||
explicit syntax_error(const char* what_arg) : what_(what_arg){}
|
||||
explicit syntax_error(const std::string& what_arg, const source_location& loc)
|
||||
: exception(loc), what_(what_arg)
|
||||
{}
|
||||
virtual ~syntax_error() noexcept override = default;
|
||||
virtual const char* what() const noexcept override {return what_.c_str();}
|
||||
|
||||
@ -30,8 +37,9 @@ struct syntax_error : public toml::exception
|
||||
struct type_error : public toml::exception
|
||||
{
|
||||
public:
|
||||
explicit type_error(const std::string& what_arg) : what_(what_arg){}
|
||||
explicit type_error(const char* what_arg) : what_(what_arg){}
|
||||
explicit type_error(const std::string& what_arg, const source_location& loc)
|
||||
: exception(loc), what_(what_arg)
|
||||
{}
|
||||
virtual ~type_error() noexcept override = default;
|
||||
virtual const char* what() const noexcept override {return what_.c_str();}
|
||||
|
||||
@ -42,10 +50,12 @@ struct type_error : public toml::exception
|
||||
struct internal_error : public toml::exception
|
||||
{
|
||||
public:
|
||||
explicit internal_error(const std::string& what_arg) : what_(what_arg){}
|
||||
explicit internal_error(const char* what_arg) : what_(what_arg){}
|
||||
explicit internal_error(const std::string& what_arg, const source_location& loc)
|
||||
: exception(loc), what_(what_arg)
|
||||
{}
|
||||
virtual ~internal_error() noexcept override = default;
|
||||
virtual const char* what() const noexcept override {return what_.c_str();}
|
||||
|
||||
protected:
|
||||
std::string what_;
|
||||
};
|
||||
|
24
toml/get.hpp
24
toml/get.hpp
@ -186,11 +186,11 @@ get(const basic_value<C, M, V>& v)
|
||||
}
|
||||
default:
|
||||
{
|
||||
throw type_error(detail::format_underline("[error] toml::value "
|
||||
throw type_error(detail::format_underline("toml::value: "
|
||||
"bad_cast to std::chrono::system_clock::time_point", {
|
||||
{std::addressof(detail::get_region(v)),
|
||||
concat_to_string("the actual type is ", v.type())}
|
||||
}));
|
||||
}), v.location());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -301,7 +301,7 @@ get(const basic_value<C, M, V>& v)
|
||||
if(ar.size() != container.size())
|
||||
{
|
||||
throw std::out_of_range(detail::format_underline(concat_to_string(
|
||||
"[erorr] toml::get specified container size is ", container.size(),
|
||||
"toml::get: specified container size is ", container.size(),
|
||||
" but there are ", ar.size(), " elements in toml array."), {
|
||||
{std::addressof(detail::get_region(v)), "here"}
|
||||
}));
|
||||
@ -326,7 +326,7 @@ get(const basic_value<C, M, V>& v)
|
||||
if(ar.size() != 2)
|
||||
{
|
||||
throw std::out_of_range(detail::format_underline(concat_to_string(
|
||||
"[erorr] toml::get specified std::pair but there are ", ar.size(),
|
||||
"toml::get: specified std::pair but there are ", ar.size(),
|
||||
" elements in toml array."), {
|
||||
{std::addressof(detail::get_region(v)), "here"}
|
||||
}));
|
||||
@ -357,8 +357,8 @@ get(const basic_value<C, M, V>& v)
|
||||
if(ar.size() != std::tuple_size<T>::value)
|
||||
{
|
||||
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(),
|
||||
"toml::get: specified std::tuple with ",
|
||||
std::tuple_size<T>::value, " elements, but there are ", ar.size(),
|
||||
" elements in toml array."), {
|
||||
{std::addressof(detail::get_region(v)), "here"}
|
||||
}));
|
||||
@ -430,7 +430,7 @@ basic_value<C, M, V> const& find(const basic_value<C, M, V>& v, const key& ky)
|
||||
if(tab.count(ky) == 0)
|
||||
{
|
||||
throw std::out_of_range(detail::format_underline(concat_to_string(
|
||||
"[error] key \"", ky, "\" not found"), {
|
||||
"key \"", ky, "\" not found"), {
|
||||
{std::addressof(detail::get_region(v)), "in this table"}
|
||||
}));
|
||||
}
|
||||
@ -444,7 +444,7 @@ basic_value<C, M, V>& find(basic_value<C, M, V>& v, const key& ky)
|
||||
if(tab.count(ky) == 0)
|
||||
{
|
||||
throw std::out_of_range(detail::format_underline(concat_to_string(
|
||||
"[error] key \"", ky, "\" not found"), {
|
||||
"key \"", ky, "\" not found"), {
|
||||
{std::addressof(detail::get_region(v)), "in this table"}
|
||||
}));
|
||||
}
|
||||
@ -458,7 +458,7 @@ basic_value<C, M, V> find(basic_value<C, M, V>&& v, const key& ky)
|
||||
if(tab.count(ky) == 0)
|
||||
{
|
||||
throw std::out_of_range(detail::format_underline(concat_to_string(
|
||||
"[error] key \"", ky, "\" not found"), {
|
||||
"key \"", ky, "\" not found"), {
|
||||
{std::addressof(detail::get_region(v)), "in this table"}
|
||||
}));
|
||||
}
|
||||
@ -523,7 +523,7 @@ find(const basic_value<C, M, V>& v, const key& ky)
|
||||
if(tab.count(ky) == 0)
|
||||
{
|
||||
throw std::out_of_range(detail::format_underline(concat_to_string(
|
||||
"[error] key \"", ky, "\" not found"), {
|
||||
"key \"", ky, "\" not found"), {
|
||||
{std::addressof(detail::get_region(v)), "in this table"}
|
||||
}));
|
||||
}
|
||||
@ -539,7 +539,7 @@ find(basic_value<C, M, V>& v, const key& ky)
|
||||
if(tab.count(ky) == 0)
|
||||
{
|
||||
throw std::out_of_range(detail::format_underline(concat_to_string(
|
||||
"[error] key \"", ky, "\" not found"), {
|
||||
"key \"", ky, "\" not found"), {
|
||||
{std::addressof(detail::get_region(v)), "in this table"}
|
||||
}));
|
||||
}
|
||||
@ -555,7 +555,7 @@ find(basic_value<C, M, V>&& v, const key& ky)
|
||||
if(tab.count(ky) == 0)
|
||||
{
|
||||
throw std::out_of_range(detail::format_underline(concat_to_string(
|
||||
"[error] key \"", ky, "\" not found"), {
|
||||
"key \"", ky, "\" not found"), {
|
||||
{std::addressof(detail::get_region(v)), "in this table"}
|
||||
}));
|
||||
}
|
||||
|
@ -76,7 +76,8 @@ inline ::toml::value operator"" _toml(const char* str, std::size_t len)
|
||||
}
|
||||
else // none of them.
|
||||
{
|
||||
throw ::toml::syntax_error(data.unwrap_err());
|
||||
throw ::toml::syntax_error(data.unwrap_err(),
|
||||
source_location(std::addressof(loc)));
|
||||
}
|
||||
}
|
||||
|
||||
|
391
toml/parser.hpp
391
toml/parser.hpp
File diff suppressed because it is too large
Load Diff
@ -2,7 +2,6 @@
|
||||
// Distributed under the MIT License.
|
||||
#ifndef TOML11_REGION_HPP
|
||||
#define TOML11_REGION_HPP
|
||||
#include "exception.hpp"
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
@ -10,6 +9,7 @@
|
||||
#include <iterator>
|
||||
#include <iomanip>
|
||||
#include <cassert>
|
||||
#include "color.hpp"
|
||||
|
||||
namespace toml
|
||||
{
|
||||
@ -231,11 +231,10 @@ struct region final : public region_base
|
||||
|
||||
region& operator+=(const region& other)
|
||||
{
|
||||
if(this->begin() != other.begin() || this->end() != other.end() ||
|
||||
this->last_ != other.first_)
|
||||
{
|
||||
throw internal_error("invalid region concatenation");
|
||||
}
|
||||
// different regions cannot be concatenated
|
||||
assert(this->begin() == other.begin() && this->end() == other.end() &&
|
||||
this->last_ == other.first_);
|
||||
|
||||
this->last_ = other.last_;
|
||||
return *this;
|
||||
}
|
||||
@ -420,7 +419,8 @@ struct region final : public region_base
|
||||
// to show a better error message.
|
||||
inline std::string format_underline(const std::string& message,
|
||||
const std::vector<std::pair<region_base const*, std::string>>& reg_com,
|
||||
const std::vector<std::string>& helps = {})
|
||||
const std::vector<std::string>& helps = {},
|
||||
const bool colorize = TOML11_ERROR_MESSAGE_COLORIZED)
|
||||
{
|
||||
assert(!reg_com.empty());
|
||||
|
||||
@ -434,7 +434,27 @@ inline std::string format_underline(const std::string& message,
|
||||
)->first->line_num().size());
|
||||
|
||||
std::ostringstream retval;
|
||||
retval << message << '\n';
|
||||
|
||||
if(colorize)
|
||||
{
|
||||
retval << color::colorize; // turn on ANSI color
|
||||
}
|
||||
|
||||
// XXX
|
||||
// Here, before `colorize` support, it does not output `[error]` prefix
|
||||
// automatically. So some user may output it manually and this change may
|
||||
// duplicate the prefix. To avoid it, check the first 7 characters and
|
||||
// if it is "[error]", it removes that part from the message shown.
|
||||
if(message.size() > 7 && message.substr(0, 7) == "[error]")
|
||||
{
|
||||
retval << color::bold << color::red << "[error]" << color::reset
|
||||
<< color::bold << message.substr(7) << color::reset << '\n';
|
||||
}
|
||||
else
|
||||
{
|
||||
retval << color::bold << color::red << "[error] " << color::reset
|
||||
<< color::bold << message << color::reset << '\n';
|
||||
}
|
||||
|
||||
for(auto iter = reg_com.begin(); iter != reg_com.end(); ++iter)
|
||||
{
|
||||
@ -442,34 +462,42 @@ inline std::string format_underline(const std::string& message,
|
||||
if(iter != reg_com.begin() &&
|
||||
std::prev(iter)->first->name() == iter->first->name())
|
||||
{
|
||||
retval << "\n ...\n";
|
||||
retval << color::bold << color::blue << "\n ...\n" << color::reset;
|
||||
}
|
||||
else // if filename differs, print " --> filename.toml"
|
||||
{
|
||||
if(iter != reg_com.begin()) {retval << '\n';}
|
||||
retval << " --> " << iter->first->name() << '\n';
|
||||
retval << color::bold << color::blue << " --> " << color::reset
|
||||
<< iter->first->name() << '\n';
|
||||
// add one almost-empty line for readability
|
||||
retval << make_string(static_cast<std::size_t>(line_num_width + 1), ' ')
|
||||
<< color::bold << color::blue << " | " << color::reset << '\n';
|
||||
}
|
||||
const region_base* const reg = iter->first;
|
||||
const std::string& comment = iter->second;
|
||||
|
||||
retval << ' ' << std::setw(line_num_width) << reg->line_num();
|
||||
retval << " | " << reg->line() << '\n';
|
||||
retval << make_string(static_cast<std::size_t>(line_num_width + 1), ' ');
|
||||
retval << " | " << make_string(reg->before(), ' ');
|
||||
retval << ' ' << color::bold << color::blue << std::setw(line_num_width)
|
||||
<< std::right << reg->line_num() << " | " << color::reset
|
||||
<< reg->line() << '\n';
|
||||
|
||||
retval << make_string(static_cast<std::size_t>(line_num_width + 1), ' ')
|
||||
<< color::bold << color::blue << " | " << color::reset
|
||||
<< make_string(reg->before(), ' ');
|
||||
|
||||
if(reg->size() == 1)
|
||||
{
|
||||
// invalid
|
||||
// ^------
|
||||
retval << '^';
|
||||
retval << make_string(reg->after(), '-');
|
||||
retval << color::bold << color::red
|
||||
<< '^' << make_string(reg->after(), '-') << color::reset;
|
||||
}
|
||||
else
|
||||
{
|
||||
// invalid
|
||||
// ~~~~~~~
|
||||
const auto underline_len = std::min(reg->size(), reg->line().size());
|
||||
retval << make_string(underline_len, '~');
|
||||
retval << color::bold << color::red
|
||||
<< make_string(underline_len, '~') << color::reset;
|
||||
}
|
||||
retval << ' ';
|
||||
retval << comment;
|
||||
@ -479,10 +507,10 @@ inline std::string format_underline(const std::string& message,
|
||||
{
|
||||
retval << '\n';
|
||||
retval << make_string(static_cast<std::size_t>(line_num_width + 1), ' ');
|
||||
retval << " | ";
|
||||
retval << color::bold << color::blue << " | " << color::reset;
|
||||
for(const auto help : helps)
|
||||
{
|
||||
retval << "\nHint: ";
|
||||
retval << color::bold << "\nHint: " << color::reset;
|
||||
retval << help;
|
||||
}
|
||||
}
|
||||
|
@ -118,8 +118,14 @@ struct serializer
|
||||
{
|
||||
return token; // there is no exponent part. just return it.
|
||||
}
|
||||
|
||||
// zero-prefix in an exponent is NOT allowed in TOML.
|
||||
#ifdef TOML11_USE_UNRELEASED_TOML_FEATURES
|
||||
// Although currently it is not released yet, TOML will allow
|
||||
// zero-prefix in an exponent part such as 1.234e+01.
|
||||
// The following code removes the zero prefixes.
|
||||
// If the feature is activated, the following codes can be skipped.
|
||||
return token;
|
||||
#endif
|
||||
// zero-prefix in an exponent is NOT allowed in TOML v0.5.0.
|
||||
// remove it if it exists.
|
||||
bool sign_exists = false;
|
||||
std::size_t zero_prefix = 0;
|
||||
|
@ -48,7 +48,11 @@ struct source_location
|
||||
{
|
||||
if(reg)
|
||||
{
|
||||
line_num_ = static_cast<std::uint_least32_t>(std::stoul(reg->line_num()));
|
||||
if(reg->line_num() != detail::region_base().line_num())
|
||||
{
|
||||
line_num_ = static_cast<std::uint_least32_t>(
|
||||
std::stoul(reg->line_num()));
|
||||
}
|
||||
column_num_ = static_cast<std::uint_least32_t>(reg->before() + 1);
|
||||
region_size_ = static_cast<std::uint_least32_t>(reg->size());
|
||||
file_name_ = reg->name();
|
||||
|
@ -2,6 +2,7 @@
|
||||
// Distributed under the MIT License.
|
||||
#ifndef TOML11_STRING_HPP
|
||||
#define TOML11_STRING_HPP
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
#include <cstdint>
|
||||
#if __cplusplus >= 201703L
|
||||
@ -45,6 +46,11 @@ struct string
|
||||
operator std::string const& () const& noexcept {return str;}
|
||||
operator std::string&& () && noexcept {return std::move(str);}
|
||||
|
||||
string& operator+=(const char* rhs) {str += rhs; return *this;}
|
||||
string& operator+=(const char rhs) {str += rhs; return *this;}
|
||||
string& operator+=(const std::string& rhs) {str += rhs; return *this;}
|
||||
string& operator+=(const string& rhs) {str += rhs.str; return *this;}
|
||||
|
||||
#if __cplusplus >= 201703L
|
||||
explicit string(std::string_view s): kind(string_t::basic), str(s){}
|
||||
string(std::string_view s, string_t k): kind(k), str(s){}
|
||||
@ -54,6 +60,8 @@ struct string
|
||||
|
||||
explicit operator std::string_view() const noexcept
|
||||
{return std::string_view(str);}
|
||||
|
||||
string& operator+=(const std::string_view& rhs) {str += rhs; return *this;}
|
||||
#endif
|
||||
|
||||
string_t kind;
|
||||
|
@ -105,7 +105,7 @@ struct has_into_toml_method
|
||||
: decltype(has_into_toml_method_impl::check<T>(nullptr)){};
|
||||
|
||||
#ifdef __INTEL_COMPILER
|
||||
#undef decltype(...)
|
||||
#undef decltype
|
||||
#endif
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
@ -32,10 +32,10 @@ template<value_t Expected,
|
||||
throw_bad_cast(value_t actual, const ::toml::basic_value<C, T, A>& v)
|
||||
{
|
||||
throw type_error(detail::format_underline(concat_to_string(
|
||||
"[error] toml::value bad_cast to ", Expected), {
|
||||
"toml::value: bad_cast to ", Expected), {
|
||||
{std::addressof(get_region(v)),
|
||||
concat_to_string("the actual type is ", actual)}
|
||||
}));
|
||||
}), v.location());
|
||||
}
|
||||
|
||||
// switch by `value_t` and call the corresponding `value::as_xxx()`. {{{
|
||||
@ -1579,6 +1579,14 @@ class basic_value
|
||||
{
|
||||
return this->as_table().at(k);
|
||||
}
|
||||
value_type& operator[](const key& k)
|
||||
{
|
||||
if(this->is_uninitialized())
|
||||
{
|
||||
*this = table_type{};
|
||||
}
|
||||
return this->as_table()[k];
|
||||
}
|
||||
|
||||
value_type& at(const std::size_t idx)
|
||||
{
|
||||
@ -1589,6 +1597,15 @@ class basic_value
|
||||
return this->as_array().at(idx);
|
||||
}
|
||||
|
||||
value_type& operator[](const std::size_t idx) noexcept
|
||||
{
|
||||
return this->as_array(std::nothrow)[idx];
|
||||
}
|
||||
value_type const& operator[](const std::size_t idx) const noexcept
|
||||
{
|
||||
return this->as_array(std::nothrow)[idx];
|
||||
}
|
||||
|
||||
source_location location() const
|
||||
{
|
||||
return source_location(this->region_info_.get());
|
||||
@ -1843,25 +1860,27 @@ operator>=(const basic_value<C, T, A>& lhs, const basic_value<C, T, A>& rhs)
|
||||
template<typename C, template<typename ...> class T, template<typename ...> class A>
|
||||
inline std::string format_error(const std::string& err_msg,
|
||||
const basic_value<C, T, A>& v, const std::string& comment,
|
||||
std::vector<std::string> hints = {})
|
||||
std::vector<std::string> hints = {},
|
||||
const bool colorize = TOML11_ERROR_MESSAGE_COLORIZED)
|
||||
{
|
||||
return detail::format_underline(err_msg,
|
||||
std::vector<std::pair<detail::region_base const*, std::string>>{
|
||||
{std::addressof(detail::get_region(v)), comment}
|
||||
}, std::move(hints));
|
||||
}, std::move(hints), colorize);
|
||||
}
|
||||
|
||||
template<typename C, template<typename ...> class T, template<typename ...> class A>
|
||||
inline std::string format_error(const std::string& err_msg,
|
||||
const toml::basic_value<C, T, A>& v1, const std::string& comment1,
|
||||
const toml::basic_value<C, T, A>& v2, const std::string& comment2,
|
||||
std::vector<std::string> hints = {})
|
||||
std::vector<std::string> hints = {},
|
||||
const bool colorize = TOML11_ERROR_MESSAGE_COLORIZED)
|
||||
{
|
||||
return detail::format_underline(err_msg,
|
||||
std::vector<std::pair<detail::region_base const*, std::string>>{
|
||||
{std::addressof(detail::get_region(v1)), comment1},
|
||||
{std::addressof(detail::get_region(v2)), comment2}
|
||||
}, std::move(hints));
|
||||
}, std::move(hints), colorize);
|
||||
}
|
||||
|
||||
template<typename C, template<typename ...> class T, template<typename ...> class A>
|
||||
@ -1869,14 +1888,15 @@ inline std::string format_error(const std::string& err_msg,
|
||||
const toml::basic_value<C, T, A>& v1, const std::string& comment1,
|
||||
const toml::basic_value<C, T, A>& v2, const std::string& comment2,
|
||||
const toml::basic_value<C, T, A>& v3, const std::string& comment3,
|
||||
std::vector<std::string> hints = {})
|
||||
std::vector<std::string> hints = {},
|
||||
const bool colorize = TOML11_ERROR_MESSAGE_COLORIZED)
|
||||
{
|
||||
return detail::format_underline(err_msg,
|
||||
std::vector<std::pair<detail::region_base const*, std::string>>{
|
||||
{std::addressof(detail::get_region(v1)), comment1},
|
||||
{std::addressof(detail::get_region(v2)), comment2},
|
||||
{std::addressof(detail::get_region(v3)), comment3}
|
||||
}, std::move(hints));
|
||||
}, std::move(hints), colorize);
|
||||
}
|
||||
|
||||
template<typename Visitor, typename C,
|
||||
|
Loading…
Reference in New Issue
Block a user