mirror of
https://github.com/ToruNiina/toml11.git
synced 2025-12-16 03:08:52 +08:00
Compare commits
22 Commits
try-get
...
add-error-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0df1dd6fea | ||
|
|
a9fb557d70 | ||
|
|
746abd73db | ||
|
|
7a6cb02293 | ||
|
|
00d6124f59 | ||
|
|
3a14cb5083 | ||
|
|
edbea2f483 | ||
|
|
973ecee32d | ||
|
|
b9b2ee02ff | ||
|
|
d77caa94d0 | ||
|
|
65e722da43 | ||
|
|
37d0391b9d | ||
|
|
d4742334ce | ||
|
|
ccd941dc5b | ||
|
|
fc493afb4e | ||
|
|
1d3abc9718 | ||
|
|
9f59c591f0 | ||
|
|
de092e5457 | ||
|
|
bcd8a6d1e4 | ||
|
|
5b0ea5e95c | ||
|
|
d00c0c1b15 | ||
|
|
5d23f4b8a8 |
2
.github/workflows/main.yml
vendored
2
.github/workflows/main.yml
vendored
@@ -53,7 +53,7 @@ jobs:
|
||||
sudo apt-get install clang-${{ matrix.compiler }}
|
||||
- name: Configure
|
||||
run: |
|
||||
cmake -B build/ -DCMAKE_VERBOSE_MAKEFILE=1 -DCMAKE_CXX_COMPILER=clang++-${{ matrix.compiler }} -DCMAKE_CXX_STANDARD=${{ matrix.standard }} -DTOML11_BUILD_TESTS=ON -DTOML11_PRECOMPILE=${{ matrix.precompile }}
|
||||
cmake -B build/ -DCMAKE_CXX_COMPILER=clang++-${{ matrix.compiler }} -DCMAKE_CXX_STANDARD=${{ matrix.standard }} -DTOML11_BUILD_TESTS=ON -DTOML11_PRECOMPILE=${{ matrix.precompile }}
|
||||
- name: Build
|
||||
run: |
|
||||
cmake --build build/
|
||||
|
||||
10
README.md
10
README.md
@@ -8,7 +8,7 @@
|
||||
|
||||
[日本語版](https://github.com/ToruNiina/toml11/blob/main/README_ja.md)
|
||||
|
||||
toml11 is a feature-rich TOML language library for C++.
|
||||
toml11 is a feature-rich TOML language library for C++11/14/17/20.
|
||||
|
||||
- It complies with [the latest TOML language specification](https://toml.io/en/v1.0.0).
|
||||
- It passes all the standard TOML language [test cases](https://github.com/toml-lang/toml-test).
|
||||
@@ -124,6 +124,14 @@ $ cmake -B ./build/ -DTOML11_PRECOMPILE=ON -DCMAKE_CXX_STANDARD=11/14/17/20
|
||||
$ cmake --build ./build/
|
||||
```
|
||||
|
||||
When linking the library, use `target_link_libraries` in CMake
|
||||
|
||||
```cmake
|
||||
target_link_libraries(your_target PUBLIC toml11::toml11)
|
||||
```
|
||||
|
||||
or pass `-DTOML11_COMPILE_SOURCES` to the compiler.
|
||||
|
||||
### Building Example
|
||||
|
||||
To compile the examples in the `examples/` directory, set `-DTOML11_BUILD_EXAMPLES=ON`.
|
||||
|
||||
10
README_ja.md
10
README_ja.md
@@ -5,7 +5,7 @@
|
||||
[](LICENSE)
|
||||
[](https://doi.org/10.5281/zenodo.1209136)
|
||||
|
||||
toml11は、C++のための豊富な機能を持つTOML言語ライブラリです。
|
||||
toml11は、C++11,14,17,20のための豊富な機能を持つTOML言語ライブラリです。
|
||||
|
||||
- [TOML言語の最新規格](https://toml.io/ja/v1.0.0)に準拠しています。
|
||||
- TOML言語標準のテストケースすべてにパスしています。
|
||||
@@ -122,6 +122,14 @@ $ cmake -B ./build/ -DTOML11_PRECOMPILE=ON -DCMAKE_CXX_STANDARD=11/14/17/20
|
||||
$ cmake --build ./build/
|
||||
```
|
||||
|
||||
ライブラリをリンクする場合は、CMakeで
|
||||
|
||||
```cmake
|
||||
target_link_libraries(your_target PUBLIC toml11::toml11)
|
||||
```
|
||||
|
||||
とするか、コンパイラに`-DTOML11_COMPILE_SOURCES`を渡してください。
|
||||
|
||||
### Building example
|
||||
|
||||
`-DTOML11_BUILD_EXAMPLES=ON`とすることで、`examples/`をコンパイルできます。
|
||||
|
||||
@@ -42,10 +42,18 @@ int main()
|
||||
}
|
||||
```
|
||||
|
||||
#### Specifying a File with `std::filesystem::path`
|
||||
|
||||
[`toml::parse`]({{< ref "docs/reference/parser#parse" >}}) can accept a `std::filesystem::path`.
|
||||
|
||||
This requires C++17 or later, as it relies on the `<filesystem>` support.
|
||||
|
||||
#### Specifying an Input Stream with `std::istream`
|
||||
|
||||
[`toml::parse`]({{< ref "docs/reference/parser#parse" >}}) can also accept an `std::istream`.
|
||||
|
||||
Open a stream in binary mode by passing `std::ios::binary` to avoid inconsistency between the file size and the number of characters due to automatic conversion of newline characters by the standard library.
|
||||
|
||||
Without the filename information, error messages will display `"unknown file"`. To avoid this, you can pass the filename as a `std::string` in the second argument when using `std::istream`.
|
||||
|
||||
You can use streams other than `std::ifstream`, such as `std::istringstream`. Note that the entire content is readable at the time of the call.
|
||||
@@ -64,16 +72,12 @@ int main()
|
||||
}
|
||||
```
|
||||
|
||||
#### Specifying a File with `std::filesystem::path`
|
||||
|
||||
[`toml::parse`]({{< ref "docs/reference/parser#parse" >}}) can accept a `std::filesystem::path`.
|
||||
|
||||
This requires C++17 or later, as it relies on the `<filesystem>` support.
|
||||
|
||||
#### Specifying a File with `FILE*`
|
||||
|
||||
[`toml::parse`]({{< ref "docs/reference/parser#parse" >}}) can also accept a `FILE*`.
|
||||
|
||||
Open a stream in binary mode by passing `"rb"` to avoid inconsistency between the file size and the number of characters due to automatic conversion of newline characters by the standard library.
|
||||
|
||||
As with `std::istream`, you need to provide the filename as a string in the second argument.
|
||||
|
||||
When passing a `FILE*`, if the file read fails, `errno` will be reported.
|
||||
|
||||
@@ -54,6 +54,14 @@ By defining `-DTOML11_PRECOMPILE=ON` when running cmake, you can precompile some
|
||||
$ cmake -B ./build/ -DTOML11_PRECOMPILE=ON
|
||||
```
|
||||
|
||||
When linking the library, use `target_link_libraries` in CMake
|
||||
|
||||
```cmake
|
||||
target_link_libraries(your_target PUBLIC toml11::toml11)
|
||||
```
|
||||
|
||||
or pass `-DTOML11_COMPILE_SOURCES` to the compiler to suppress header-only features.
|
||||
|
||||
However, since toml11 supports multiple C++ versions and may switch types based on the value of `__cplusplus`,
|
||||
there is a possibility of link failures if the version used during build differs from the version used during usage.
|
||||
If you encounter issues, set the required version using `CMAKE_CXX_STANDARD` during compilation.
|
||||
|
||||
@@ -17,23 +17,6 @@ In case of failure, `toml::syntax_error` is thrown.
|
||||
|
||||
The type information of `basic_value` is provided by a `template`, and the TOML language version is specified by `toml::spec`.
|
||||
|
||||
### `parse(std::istream&, std::string filename, toml::spec)`
|
||||
|
||||
```cpp
|
||||
namespace toml
|
||||
{
|
||||
template<typename TC = type_config>
|
||||
basic_value<TC>
|
||||
parse(std::istream& is,
|
||||
std::string fname = "unknown file",
|
||||
spec s = spec::default_version());
|
||||
}
|
||||
```
|
||||
|
||||
Parses the content of the given `std::istream&`.
|
||||
|
||||
The filename information is taken as the third argument. If the filename is not provided, it defaults to `"unknown file"`.
|
||||
|
||||
### `parse(std::string filename, toml::spec)`
|
||||
|
||||
```cpp
|
||||
@@ -90,6 +73,25 @@ If reading the file fails, `toml::file_io_error` is thrown.
|
||||
|
||||
If parsing fails, `toml::syntax_error` is thrown.
|
||||
|
||||
### `parse(std::istream&, std::string filename, toml::spec)`
|
||||
|
||||
```cpp
|
||||
namespace toml
|
||||
{
|
||||
template<typename TC = type_config>
|
||||
basic_value<TC>
|
||||
parse(std::istream& is,
|
||||
std::string fname = "unknown file",
|
||||
spec s = spec::default_version());
|
||||
}
|
||||
```
|
||||
|
||||
Parses the content of the given `std::istream&`.
|
||||
|
||||
Open a stream in binary mode by passing `std::ios::binary` to avoid inconsistency between the file size and the number of characters due to automatic conversion of newline characters by the standard library.
|
||||
|
||||
The filename information is taken as the third argument. If the filename is not provided, it defaults to `"unknown file"`.
|
||||
|
||||
### `parse(FILE*, std::string filename, toml::spec)`
|
||||
|
||||
```cpp
|
||||
@@ -105,6 +107,8 @@ parse(FILE* fp,
|
||||
|
||||
Parses the content of the file pointed to by `FILE*`.
|
||||
|
||||
Open a stream in binary mode by passing `"rb"` to avoid inconsistency between the file size and the number of characters due to automatic conversion of newline characters by the standard library.
|
||||
|
||||
If reading the file fails, `file_io_error` containing `errno` is thrown.
|
||||
|
||||
If parsing fails, `syntax_error` is thrown.
|
||||
@@ -166,27 +170,6 @@ For instance, errors occurring internally within `std::ifstream` or memory exhau
|
||||
|
||||
{{< /hint >}}
|
||||
|
||||
### `try_parse(std::istream&, std::string filename, toml::spec)`
|
||||
|
||||
```cpp
|
||||
namespace toml
|
||||
{
|
||||
template<typename TC = type_config>
|
||||
result<basic_value<TC>, std::vector<error_info>>
|
||||
try_parse(std::istream& is,
|
||||
std::string fname = "unknown file",
|
||||
spec s = spec::default_version());
|
||||
}
|
||||
```
|
||||
|
||||
Takes a `std::istream&` and parses its content.
|
||||
|
||||
The file name information is taken as the second argument. If a file name is not provided, it defaults to `"unknown file"`.
|
||||
|
||||
If parsing fails, a `result` holding the error type `std::vector<error_info>` is returned.
|
||||
|
||||
If successful, a `result` holding a `basic_value` is returned.
|
||||
|
||||
### `try_parse(std::string filename, toml::spec)`
|
||||
|
||||
```cpp
|
||||
@@ -241,6 +224,29 @@ If parsing fails, a `result` holding the error type `std::vector<error_info>` is
|
||||
|
||||
If successful, a `result` holding a `basic_value` is returned.
|
||||
|
||||
### `try_parse(std::istream&, std::string filename, toml::spec)`
|
||||
|
||||
```cpp
|
||||
namespace toml
|
||||
{
|
||||
template<typename TC = type_config>
|
||||
result<basic_value<TC>, std::vector<error_info>>
|
||||
try_parse(std::istream& is,
|
||||
std::string fname = "unknown file",
|
||||
spec s = spec::default_version());
|
||||
}
|
||||
```
|
||||
|
||||
Takes a `std::istream&` and parses its content.
|
||||
|
||||
Open a stream in binary mode by passing `std::ios::binary` to avoid inconsistency between the file size and the number of characters due to automatic conversion of newline characters by the standard library.
|
||||
|
||||
The file name information is taken as the second argument. If a file name is not provided, it defaults to `"unknown file"`.
|
||||
|
||||
If parsing fails, a `result` holding the error type `std::vector<error_info>` is returned.
|
||||
|
||||
If successful, a `result` holding a `basic_value` is returned.
|
||||
|
||||
### `try_parse(FILE*, std::string filename, toml::spec)`
|
||||
|
||||
```cpp
|
||||
@@ -256,6 +262,8 @@ try_parse(FILE* fp,
|
||||
|
||||
Takes a `FILE*` and parses its content.
|
||||
|
||||
Open a stream in binary mode by passing `"rb"` to avoid inconsistency between the file size and the number of characters due to automatic conversion of newline characters by the standard library.
|
||||
|
||||
If parsing fails, a `result` holding the error type `std::vector<error_info>` is returned.
|
||||
|
||||
If successful, a `result` holding a `basic_value` is returned.
|
||||
|
||||
@@ -44,11 +44,21 @@ int main()
|
||||
}
|
||||
```
|
||||
|
||||
#### `std::filesystem::path`でファイルを指定する
|
||||
|
||||
[`toml::parse`]({{< ref "docs/reference/parser#parse" >}})
|
||||
には、`std::filesystem::path`を渡すことも可能です。
|
||||
|
||||
当然ですが、`<filesystem>`がサポートされるC++17以降でなければ使用できません。
|
||||
|
||||
#### `std::istream`で入力ストリームを指定する
|
||||
|
||||
[`toml::parse`]({{< ref "docs/reference/parser#parse" >}})
|
||||
には、`std::istream`を渡すことも可能です。
|
||||
|
||||
標準ライブラリが改行文字を自動変換することによるファイルサイズと文字数との不整合を避けるため、
|
||||
`std::ios::binary`を使ってバイナリモードで開いてください。
|
||||
|
||||
その際、ファイル名の情報がなくなるため、エラーメッセージ中では `"unknown file"` となります。
|
||||
|
||||
これを避けるため、 `std::istream` を取る場合は第二引数に `std::string` でファイル名を取ることもできます。
|
||||
@@ -70,18 +80,14 @@ int main()
|
||||
}
|
||||
```
|
||||
|
||||
#### `std::filesystem::path`でファイルを指定する
|
||||
|
||||
[`toml::parse`]({{< ref "docs/reference/parser#parse" >}})
|
||||
には、`std::filesystem::path`を渡すことも可能です。
|
||||
|
||||
当然ですが、`<filesystem>`がサポートされるC++17以降でなければ使用できません。
|
||||
|
||||
#### `FILE*`でファイルを指定する
|
||||
|
||||
[`toml::parse`]({{< ref "docs/reference/parser#parse" >}})
|
||||
には、`FILE*`を渡すことも可能です。
|
||||
|
||||
標準ライブラリによる改行文字の自動変換によるファイルサイズと文字数との不整合を避けるため、
|
||||
`fopen("example.toml", "rb")`のようにしてバイナリモードで開いてください。
|
||||
|
||||
この場合も、`std::istream`のときと同様に、第二引数に文字列でファイル名を与える必要があります。
|
||||
|
||||
`FILE*`を渡した場合、ファイルの読み込みに失敗した際には`errno`が報告されます。
|
||||
|
||||
@@ -54,6 +54,14 @@ target_link_libraries(main PRIVATE toml11::toml11)
|
||||
$ cmake -B ./build/ -DTOML11_PRECOMPILE=ON
|
||||
```
|
||||
|
||||
ライブラリをリンクする場合は、CMakeで
|
||||
|
||||
```cmake
|
||||
target_link_libraries(your_target PUBLIC toml11::toml11)
|
||||
```
|
||||
|
||||
とするか、ヘッダ内の関数の`inline`化を避けるためにコンパイラに`-DTOML11_COMPILE_SOURCES`を渡してください。
|
||||
|
||||
ただし、toml11は複数のC++バージョンに対応するため、`__cplusplus`の値などによって型を切り替えることがあります。
|
||||
そのため、ビルドした際のバージョンと使用時のバージョンが異なる場合、リンクに失敗する可能性があります。
|
||||
問題が生じた場合は`CMAKE_CXX_STANDARD`によって必要なバージョンを設定してコンパイルしてください。
|
||||
|
||||
@@ -17,23 +17,6 @@ type = "docs"
|
||||
|
||||
`basic_value`の持つ型情報は`template`で、TOML言語のバージョンは`toml::spec`で指定します。
|
||||
|
||||
### `parse(std::istream&, std::string filename, toml::spec)`
|
||||
|
||||
```cpp
|
||||
namespace toml
|
||||
{
|
||||
template<typename TC = type_config>
|
||||
basic_value<TC>
|
||||
parse(std::istream& is,
|
||||
std::string fname = "unknown file",
|
||||
spec s = spec::default_version());
|
||||
}
|
||||
```
|
||||
|
||||
`std::istream&`を受け取ってその内容をパースします。
|
||||
|
||||
ファイル名の情報は第三引数で受け取ります。ファイル名が渡されなかった場合、`"unknown file"`になります。
|
||||
|
||||
### `parse(std::string filename, toml::spec)`
|
||||
|
||||
```cpp
|
||||
@@ -90,6 +73,25 @@ parse(const std::filesystem::path& fpath,
|
||||
|
||||
パースに失敗した場合、`syntax_error`が送出されます。
|
||||
|
||||
### `parse(std::istream&, std::string filename, toml::spec)`
|
||||
|
||||
```cpp
|
||||
namespace toml
|
||||
{
|
||||
template<typename TC = type_config>
|
||||
basic_value<TC>
|
||||
parse(std::istream& is,
|
||||
std::string fname = "unknown file",
|
||||
spec s = spec::default_version());
|
||||
}
|
||||
```
|
||||
|
||||
`std::istream&`を受け取ってその内容をパースします。
|
||||
|
||||
標準ライブラリが改行文字を自動変換することによるファイルサイズと文字数との不整合を避けるため、
|
||||
`std::ios::binary`を使ってバイナリモードで開いてください。
|
||||
|
||||
ファイル名の情報は第三引数で受け取ります。ファイル名が渡されなかった場合、`"unknown file"`になります。
|
||||
|
||||
### `parse(FILE*, std::string filename, toml::spec)`
|
||||
|
||||
@@ -106,6 +108,9 @@ parse(FILE* fp,
|
||||
|
||||
`FILE*`が指すファイルを読み込んでパースします。
|
||||
|
||||
標準ライブラリが改行文字を自動変換することによるファイルサイズと文字数との不整合を避けるため、
|
||||
`fopen`には`"rb"`などを渡してバイナリモードで開いてください。
|
||||
|
||||
ファイルの読み込みに失敗した場合、`errno`が含まれた`file_io_error`が送出されます。
|
||||
|
||||
パースに失敗した場合、`syntax_error`が送出されます。
|
||||
@@ -167,28 +172,6 @@ parse_str(std::string content,
|
||||
|
||||
{{< /hint >}}
|
||||
|
||||
|
||||
### `try_parse(std::istream&, std::string filename, toml::spec)`
|
||||
|
||||
```cpp
|
||||
namespace toml
|
||||
{
|
||||
template<typename TC = type_config>
|
||||
result<basic_value<TC>, std::vector<error_info>>
|
||||
try_parse(std::istream& is,
|
||||
std::string fname = "unknown file",
|
||||
spec s = spec::default_version());
|
||||
}
|
||||
```
|
||||
|
||||
`std::istream&`を受け取ってその内容をパースします。
|
||||
|
||||
ファイル名の情報は第二引数で受け取ります。ファイル名が渡されなかった場合、`"unknown file"`になります。
|
||||
|
||||
パースに失敗した場合、エラー型である`std::vector<error_info>`を持つ`result`が返されます。
|
||||
|
||||
成功した場合、`basic_value`を持つ`result`が返されます。
|
||||
|
||||
### `try_parse(std::string filename, toml::spec)`
|
||||
|
||||
```cpp
|
||||
@@ -244,6 +227,30 @@ try_parse(const std::filesystem::path& fpath,
|
||||
|
||||
成功した場合、`basic_value`を持つ`result`が返されます。
|
||||
|
||||
### `try_parse(std::istream&, std::string filename, toml::spec)`
|
||||
|
||||
```cpp
|
||||
namespace toml
|
||||
{
|
||||
template<typename TC = type_config>
|
||||
result<basic_value<TC>, std::vector<error_info>>
|
||||
try_parse(std::istream& is,
|
||||
std::string fname = "unknown file",
|
||||
spec s = spec::default_version());
|
||||
}
|
||||
```
|
||||
|
||||
`std::istream&`を受け取ってその内容をパースします。
|
||||
|
||||
標準ライブラリが改行文字を自動変換することによるファイルサイズと文字数との不整合を避けるため、
|
||||
`std::ios::binary`を使ってバイナリモードで開いてください。
|
||||
|
||||
ファイル名の情報は第二引数で受け取ります。ファイル名が渡されなかった場合、`"unknown file"`になります。
|
||||
|
||||
パースに失敗した場合、エラー型である`std::vector<error_info>`を持つ`result`が返されます。
|
||||
|
||||
成功した場合、`basic_value`を持つ`result`が返されます。
|
||||
|
||||
### `try_parse(FILE*, std::string filename, toml::spec)`
|
||||
|
||||
```cpp
|
||||
@@ -259,6 +266,9 @@ try_parse(FILE* fp,
|
||||
|
||||
`FILE*`を受け取って、そのファイルの内容をパースします。
|
||||
|
||||
標準ライブラリが改行文字を自動変換することによるファイルサイズと文字数との不整合を避けるため、
|
||||
`fopen`には`"rb"`などを渡してバイナリモードで開いてください。
|
||||
|
||||
パースに失敗した場合、エラー型である`std::vector<error_info>`を持つ`result`が返されます。
|
||||
|
||||
成功した場合、`basic_value`を持つ`result`が返されます。
|
||||
|
||||
@@ -7,19 +7,47 @@
|
||||
namespace toml
|
||||
{
|
||||
|
||||
enum class error_kind : std::uint8_t
|
||||
{
|
||||
runtime_error,
|
||||
out_of_range,
|
||||
type_error,
|
||||
syntax_error,
|
||||
file_io_error,
|
||||
serialization_error
|
||||
};
|
||||
|
||||
// error info returned from parser.
|
||||
struct error_info
|
||||
{
|
||||
error_info(std::string t, source_location l, std::string m, std::string s = "")
|
||||
: title_(std::move(t)), locations_{std::make_pair(std::move(l), std::move(m))},
|
||||
: kind_(error_kind::runtime_error), title_(std::move(t)),
|
||||
locations_{std::make_pair(std::move(l), std::move(m))},
|
||||
suffix_(std::move(s))
|
||||
{}
|
||||
|
||||
error_info(std::string t, std::vector<std::pair<source_location, std::string>> l,
|
||||
std::string s = "")
|
||||
: title_(std::move(t)), locations_(std::move(l)), suffix_(std::move(s))
|
||||
: kind_(error_kind::runtime_error), title_(std::move(t)),
|
||||
locations_(std::move(l)), suffix_(std::move(s))
|
||||
{}
|
||||
|
||||
error_info(error_kind k, std::string t, source_location l, std::string m, std::string s = "")
|
||||
: kind_(k), title_(std::move(t)),
|
||||
locations_{std::make_pair(std::move(l), std::move(m))},
|
||||
suffix_(std::move(s))
|
||||
{}
|
||||
|
||||
error_info(error_kind k, std::string t,
|
||||
std::vector<std::pair<source_location, std::string>> l,
|
||||
std::string s = "")
|
||||
: kind_(k), title_(std::move(t)),
|
||||
locations_(std::move(l)), suffix_(std::move(s))
|
||||
{}
|
||||
|
||||
error_kind& kind() noexcept {return kind_;}
|
||||
error_kind kind() const noexcept {return kind_;}
|
||||
|
||||
std::string const& title() const noexcept {return title_;}
|
||||
std::string & title() noexcept {return title_;}
|
||||
|
||||
@@ -36,11 +64,16 @@ struct error_info
|
||||
|
||||
private:
|
||||
|
||||
error_kind kind_;
|
||||
std::string title_;
|
||||
std::vector<std::pair<source_location, std::string>> locations_;
|
||||
std::string suffix_; // hint or something like that
|
||||
};
|
||||
|
||||
// forward decl
|
||||
template<typename TypeConfig>
|
||||
class basic_value;
|
||||
|
||||
namespace detail
|
||||
{
|
||||
inline error_info make_error_info_rec(error_info e)
|
||||
@@ -53,6 +86,10 @@ inline error_info make_error_info_rec(error_info e, std::string s)
|
||||
return e;
|
||||
}
|
||||
|
||||
template<typename TC, typename ... Ts>
|
||||
error_info make_error_info_rec(error_info e,
|
||||
const basic_value<TC>& v, std::string msg, Ts&& ... tail);
|
||||
|
||||
template<typename ... Ts>
|
||||
error_info make_error_info_rec(error_info e,
|
||||
source_location loc, std::string msg, Ts&& ... tail)
|
||||
@@ -67,7 +104,14 @@ template<typename ... Ts>
|
||||
error_info make_error_info(
|
||||
std::string title, source_location loc, std::string msg, Ts&& ... tail)
|
||||
{
|
||||
error_info ei(std::move(title), std::move(loc), std::move(msg));
|
||||
error_info ei(error_kind::runtime_error, std::move(title), std::move(loc), std::move(msg));
|
||||
return detail::make_error_info_rec(ei, std::forward<Ts>(tail) ... );
|
||||
}
|
||||
template<typename ... Ts>
|
||||
error_info make_error_info(error_kind k,
|
||||
std::string title, source_location loc, std::string msg, Ts&& ... tail)
|
||||
{
|
||||
error_info ei(k, std::move(title), std::move(loc), std::move(msg));
|
||||
return detail::make_error_info_rec(ei, std::forward<Ts>(tail) ... );
|
||||
}
|
||||
|
||||
|
||||
@@ -84,7 +84,7 @@ error_info make_syntax_error(std::string title,
|
||||
{
|
||||
auto msg = std::string("expected ") + scanner.expected_chars(loc);
|
||||
auto src = source_location(region(loc));
|
||||
return make_error_info(
|
||||
return make_error_info(error_kind::syntax_error,
|
||||
std::move(title), std::move(src), std::move(msg), std::move(suffix));
|
||||
}
|
||||
|
||||
@@ -116,8 +116,8 @@ parse_comment_line(location& loc, context<TC>& ctx)
|
||||
loc.advance();
|
||||
if(loc.current() == '\n') { /*skip LF*/ loc.advance(); break; }
|
||||
}
|
||||
return err(make_error_info("toml::parse_comment_line: "
|
||||
"newline (LF / CRLF) or EOF is expected",
|
||||
return err(make_error_info(error_kind::syntax_error,
|
||||
"toml::parse_comment_line: newline (LF / CRLF) or EOF is expected",
|
||||
source_location(region(loc)), "but got this",
|
||||
"Hint: most of the control characters are not allowed in comments"));
|
||||
}
|
||||
@@ -383,7 +383,7 @@ parse_dec_integer(location& loc, const context<TC>& ctx)
|
||||
if( ! sfx_reg.is_ok())
|
||||
{
|
||||
loc = first;
|
||||
return err(make_error_info("toml::parse_dec_integer: "
|
||||
return err(make_error_info(error_kind::syntax_error, "toml::parse_dec_integer: "
|
||||
"invalid suffix: should be `_ non-digit-graph (graph | _graph)`",
|
||||
source_location(region(loc)), "here"));
|
||||
}
|
||||
@@ -433,7 +433,7 @@ parse_integer(location& loc, const context<TC>& ctx)
|
||||
if(std::isdigit(prefix))
|
||||
{
|
||||
auto src = source_location(region(loc));
|
||||
return err(make_error_info("toml::parse_integer: "
|
||||
return err(make_error_info(error_kind::syntax_error, "toml::parse_integer: "
|
||||
"leading zero in an decimal integer is not allowed",
|
||||
std::move(src), "leading zero"));
|
||||
}
|
||||
@@ -526,7 +526,7 @@ parse_floating(location& loc, const context<TC>& ctx)
|
||||
}
|
||||
else
|
||||
{
|
||||
return err(make_error_info("toml::parse_floating: inf value found"
|
||||
return err(make_error_info(error_kind::syntax_error, "toml::parse_floating: inf value found"
|
||||
" but the current environment does not support inf. Please"
|
||||
" make sure that the floating-point implementation conforms"
|
||||
" IEEE 754/ISO 60559 international standard.",
|
||||
@@ -542,7 +542,7 @@ parse_floating(location& loc, const context<TC>& ctx)
|
||||
}
|
||||
else
|
||||
{
|
||||
return err(make_error_info("toml::parse_floating: inf value found"
|
||||
return err(make_error_info(error_kind::syntax_error, "toml::parse_floating: inf value found"
|
||||
" but the current environment does not support inf. Please"
|
||||
" make sure that the floating-point implementation conforms"
|
||||
" IEEE 754/ISO 60559 international standard.",
|
||||
@@ -562,7 +562,7 @@ parse_floating(location& loc, const context<TC>& ctx)
|
||||
}
|
||||
else
|
||||
{
|
||||
return err(make_error_info("toml::parse_floating: NaN value found"
|
||||
return err(make_error_info(error_kind::syntax_error, "toml::parse_floating: NaN value found"
|
||||
" but the current environment does not support NaN. Please"
|
||||
" make sure that the floating-point implementation conforms"
|
||||
" IEEE 754/ISO 60559 international standard.",
|
||||
@@ -583,7 +583,7 @@ parse_floating(location& loc, const context<TC>& ctx)
|
||||
}
|
||||
else
|
||||
{
|
||||
return err(make_error_info("toml::parse_floating: NaN value found"
|
||||
return err(make_error_info(error_kind::syntax_error, "toml::parse_floating: NaN value found"
|
||||
" but the current environment does not support NaN. Please"
|
||||
" make sure that the floating-point implementation conforms"
|
||||
" IEEE 754/ISO 60559 international standard.",
|
||||
@@ -648,7 +648,7 @@ parse_floating(location& loc, const context<TC>& ctx)
|
||||
{
|
||||
auto src = source_location(region(loc));
|
||||
loc = first;
|
||||
return err(make_error_info("toml::parse_floating: "
|
||||
return err(make_error_info(error_kind::syntax_error, "toml::parse_floating: "
|
||||
"invalid suffix: should be `_ non-digit-graph (graph | _graph)`",
|
||||
std::move(src), "here"));
|
||||
}
|
||||
@@ -702,21 +702,21 @@ parse_local_date_only(location& loc, const context<TC>& ctx)
|
||||
if(year_r.is_err())
|
||||
{
|
||||
auto src = source_location(region(first));
|
||||
return err(make_error_info("toml::parse_local_date: "
|
||||
return err(make_error_info(error_kind::syntax_error, "toml::parse_local_date: "
|
||||
"failed to read year `" + str.substr(0, 4) + "`",
|
||||
std::move(src), "here"));
|
||||
}
|
||||
if(month_r.is_err())
|
||||
{
|
||||
auto src = source_location(region(first));
|
||||
return err(make_error_info("toml::parse_local_date: "
|
||||
return err(make_error_info(error_kind::syntax_error, "toml::parse_local_date: "
|
||||
"failed to read month `" + str.substr(5, 2) + "`",
|
||||
std::move(src), "here"));
|
||||
}
|
||||
if(day_r.is_err())
|
||||
{
|
||||
auto src = source_location(region(first));
|
||||
return err(make_error_info("toml::parse_local_date: "
|
||||
return err(make_error_info(error_kind::syntax_error, "toml::parse_local_date: "
|
||||
"failed to read day `" + str.substr(8, 2) + "`",
|
||||
std::move(src), "here"));
|
||||
}
|
||||
@@ -751,7 +751,7 @@ parse_local_date_only(location& loc, const context<TC>& ctx)
|
||||
if((month < 1 || 12 < month) || (day < 1 || max_day < day))
|
||||
{
|
||||
auto src = source_location(region(first));
|
||||
return err(make_error_info("toml::parse_local_date: invalid date.",
|
||||
return err(make_error_info(error_kind::syntax_error, "toml::parse_local_date: invalid date.",
|
||||
std::move(src), "month must be 01-12, day must be any of "
|
||||
"01-28,29,30,31 depending on the month/year."));
|
||||
}
|
||||
@@ -822,14 +822,14 @@ parse_local_time_only(location& loc, const context<TC>& ctx)
|
||||
if(hour_r.is_err())
|
||||
{
|
||||
auto src = source_location(region(first));
|
||||
return err(make_error_info("toml::parse_local_time: "
|
||||
return err(make_error_info(error_kind::syntax_error, "toml::parse_local_time: "
|
||||
"failed to read hour `" + str.substr(0, 2) + "`",
|
||||
std::move(src), "here"));
|
||||
}
|
||||
if(minute_r.is_err())
|
||||
{
|
||||
auto src = source_location(region(first));
|
||||
return err(make_error_info("toml::parse_local_time: "
|
||||
return err(make_error_info(error_kind::syntax_error, "toml::parse_local_time: "
|
||||
"failed to read minute `" + str.substr(3, 2) + "`",
|
||||
std::move(src), "here"));
|
||||
}
|
||||
@@ -840,7 +840,7 @@ parse_local_time_only(location& loc, const context<TC>& ctx)
|
||||
if((hour < 0 || 24 <= hour) || (minute < 0 || 60 <= minute))
|
||||
{
|
||||
auto src = source_location(region(first));
|
||||
return err(make_error_info("toml::parse_local_time: invalid time.",
|
||||
return err(make_error_info(error_kind::syntax_error, "toml::parse_local_time: invalid time.",
|
||||
std::move(src), "hour must be 00-23, minute must be 00-59."));
|
||||
}
|
||||
|
||||
@@ -866,7 +866,7 @@ parse_local_time_only(location& loc, const context<TC>& ctx)
|
||||
if(sec_r.is_err())
|
||||
{
|
||||
auto src = source_location(region(first));
|
||||
return err(make_error_info("toml::parse_local_time: "
|
||||
return err(make_error_info(error_kind::syntax_error, "toml::parse_local_time: "
|
||||
"failed to read second `" + str.substr(6, 2) + "`",
|
||||
std::move(src), "here"));
|
||||
}
|
||||
@@ -875,7 +875,7 @@ parse_local_time_only(location& loc, const context<TC>& ctx)
|
||||
if(sec < 0 || 60 < sec) // :60 is allowed
|
||||
{
|
||||
auto src = source_location(region(first));
|
||||
return err(make_error_info("toml::parse_local_time: invalid time.",
|
||||
return err(make_error_info(error_kind::syntax_error, "toml::parse_local_time: invalid time.",
|
||||
std::move(src), "second must be 00-60."));
|
||||
}
|
||||
|
||||
@@ -905,21 +905,21 @@ parse_local_time_only(location& loc, const context<TC>& ctx)
|
||||
if(ms_r.is_err())
|
||||
{
|
||||
auto src = source_location(region(first));
|
||||
return err(make_error_info("toml::parse_local_time: "
|
||||
return err(make_error_info(error_kind::syntax_error, "toml::parse_local_time: "
|
||||
"failed to read milliseconds `" + secfrac.substr(0, 3) + "`",
|
||||
std::move(src), "here"));
|
||||
}
|
||||
if(us_r.is_err())
|
||||
{
|
||||
auto src = source_location(region(first));
|
||||
return err(make_error_info("toml::parse_local_time: "
|
||||
return err(make_error_info(error_kind::syntax_error, "toml::parse_local_time: "
|
||||
"failed to read microseconds`" + str.substr(3, 3) + "`",
|
||||
std::move(src), "here"));
|
||||
}
|
||||
if(ns_r.is_err())
|
||||
{
|
||||
auto src = source_location(region(first));
|
||||
return err(make_error_info("toml::parse_local_time: "
|
||||
return err(make_error_info(error_kind::syntax_error, "toml::parse_local_time: "
|
||||
"failed to read nanoseconds`" + str.substr(6, 3) + "`",
|
||||
std::move(src), "here"));
|
||||
}
|
||||
@@ -985,7 +985,7 @@ parse_local_datetime(location& loc, const context<TC>& ctx)
|
||||
else
|
||||
{
|
||||
auto src = source_location(region(loc));
|
||||
return err(make_error_info("toml::parse_local_datetime: "
|
||||
return err(make_error_info(error_kind::syntax_error, "toml::parse_local_datetime: "
|
||||
"expect date-time delimiter `T`, `t` or ` `(space).",
|
||||
std::move(src), "here"));
|
||||
}
|
||||
@@ -1049,7 +1049,7 @@ parse_offset_datetime(location& loc, const context<TC>& ctx)
|
||||
else
|
||||
{
|
||||
auto src = source_location(region(loc));
|
||||
return err(make_error_info("toml::parse_offset_datetime: "
|
||||
return err(make_error_info(error_kind::syntax_error, "toml::parse_offset_datetime: "
|
||||
"expect date-time delimiter `T` or ` `(space).", std::move(src), "here"
|
||||
));
|
||||
}
|
||||
@@ -1090,13 +1090,13 @@ parse_offset_datetime(location& loc, const context<TC>& ctx)
|
||||
if(hour_r.is_err())
|
||||
{
|
||||
auto src = source_location(region(loc));
|
||||
return err(make_error_info("toml::parse_offset_datetime: "
|
||||
return err(make_error_info(error_kind::syntax_error, "toml::parse_offset_datetime: "
|
||||
"Failed to read offset hour part", std::move(src), "here"));
|
||||
}
|
||||
if(minute_r.is_err())
|
||||
{
|
||||
auto src = source_location(region(loc));
|
||||
return err(make_error_info("toml::parse_offset_datetime: "
|
||||
return err(make_error_info(error_kind::syntax_error, "toml::parse_offset_datetime: "
|
||||
"Failed to read offset minute part", std::move(src), "here"));
|
||||
}
|
||||
const auto hour = hour_r.unwrap();
|
||||
@@ -1119,7 +1119,7 @@ parse_offset_datetime(location& loc, const context<TC>& ctx)
|
||||
if (offset.hour < -24 || 24 < offset.hour ||
|
||||
offset.minute < -60 || 60 < offset.minute)
|
||||
{
|
||||
return err(make_error_info("toml::parse_offset_datetime: "
|
||||
return err(make_error_info(error_kind::syntax_error, "toml::parse_offset_datetime: "
|
||||
"too large offset: |hour| <= 24, |minute| <= 60",
|
||||
source_location(region(first, loc)), "here"));
|
||||
}
|
||||
@@ -1181,7 +1181,7 @@ parse_utf8_codepoint(const region& reg)
|
||||
if(0xD800 <= codepoint && codepoint <= 0xDFFF)
|
||||
{
|
||||
auto src = source_location(reg);
|
||||
return err(make_error_info("toml::parse_utf8_codepoint: "
|
||||
return err(make_error_info(error_kind::syntax_error, "toml::parse_utf8_codepoint: "
|
||||
"[0xD800, 0xDFFF] is not a valid UTF-8",
|
||||
std::move(src), "here"));
|
||||
}
|
||||
@@ -1202,7 +1202,7 @@ parse_utf8_codepoint(const region& reg)
|
||||
else // out of UTF-8 region
|
||||
{
|
||||
auto src = source_location(reg);
|
||||
return err(make_error_info("toml::parse_utf8_codepoint: "
|
||||
return err(make_error_info(error_kind::syntax_error, "toml::parse_utf8_codepoint: "
|
||||
"input codepoint is too large.",
|
||||
std::move(src), "must be in range [0x00, 0x10FFFF]"));
|
||||
}
|
||||
@@ -1243,7 +1243,7 @@ parse_escape_sequence(location& loc, const context<TC>& ctx)
|
||||
if( ! reg.is_ok())
|
||||
{
|
||||
auto src = source_location(region(loc));
|
||||
return err(make_error_info("toml::parse_escape_sequence: "
|
||||
return err(make_error_info(error_kind::syntax_error, "toml::parse_escape_sequence: "
|
||||
"invalid token found in UTF-8 codepoint \\xhh",
|
||||
std::move(src), "here"));
|
||||
}
|
||||
@@ -1261,7 +1261,7 @@ parse_escape_sequence(location& loc, const context<TC>& ctx)
|
||||
if( ! reg.is_ok())
|
||||
{
|
||||
auto src = source_location(region(loc));
|
||||
return err(make_error_info("toml::parse_escape_sequence: "
|
||||
return err(make_error_info(error_kind::syntax_error, "toml::parse_escape_sequence: "
|
||||
"invalid token found in UTF-8 codepoint \\uhhhh",
|
||||
std::move(src), "here"));
|
||||
}
|
||||
@@ -1279,7 +1279,7 @@ parse_escape_sequence(location& loc, const context<TC>& ctx)
|
||||
if( ! reg.is_ok())
|
||||
{
|
||||
auto src = source_location(region(loc));
|
||||
return err(make_error_info("toml::parse_escape_sequence: "
|
||||
return err(make_error_info(error_kind::syntax_error, "toml::parse_escape_sequence: "
|
||||
"invalid token found in UTF-8 codepoint \\Uhhhhhhhh",
|
||||
std::move(src), "here"));
|
||||
}
|
||||
@@ -1304,7 +1304,7 @@ parse_escape_sequence(location& loc, const context<TC>& ctx)
|
||||
}
|
||||
escape_seqs += ", \\uhhhh, or \\Uhhhhhhhh";
|
||||
|
||||
return err(make_error_info("toml::parse_escape_sequence: "
|
||||
return err(make_error_info(error_kind::syntax_error, "toml::parse_escape_sequence: "
|
||||
"unknown escape sequence.", std::move(src), escape_seqs));
|
||||
}
|
||||
return ok(retval);
|
||||
@@ -1612,7 +1612,7 @@ parse_string(location& loc, const context<TC>& ctx)
|
||||
else
|
||||
{
|
||||
auto src = source_location(region(loc));
|
||||
return err(make_error_info("toml::parse_string: "
|
||||
return err(make_error_info(error_kind::syntax_error, "toml::parse_string: "
|
||||
"not a string", std::move(src), "here"));
|
||||
}
|
||||
}
|
||||
@@ -1624,7 +1624,7 @@ parse_null(location& loc, const context<TC>& ctx)
|
||||
const auto& spec = ctx.toml_spec();
|
||||
if( ! spec.ext_null_value)
|
||||
{
|
||||
return err(make_error_info("toml::parse_null: "
|
||||
return err(make_error_info(error_kind::syntax_error, "toml::parse_null: "
|
||||
"invalid spec: spec.ext_null_value must be true.",
|
||||
source_location(region(loc)), "here"));
|
||||
}
|
||||
@@ -1754,7 +1754,7 @@ parse_key(location& loc, const context<TC>& ctx)
|
||||
if(keys.empty())
|
||||
{
|
||||
auto src = source_location(region(first));
|
||||
return err(make_error_info("toml::parse_key: expected a new key, "
|
||||
return err(make_error_info(error_kind::syntax_error, "toml::parse_key: expected a new key, "
|
||||
"but got nothing", std::move(src), "reached EOF"));
|
||||
}
|
||||
|
||||
@@ -1906,7 +1906,7 @@ parse_array(location& loc, context<TC>& ctx)
|
||||
if(loc.eof() || loc.current() != '[')
|
||||
{
|
||||
auto src = source_location(region(loc));
|
||||
return err(make_error_info("toml::parse_array: "
|
||||
return err(make_error_info(error_kind::syntax_error, "toml::parse_array: "
|
||||
"The next token is not an array", std::move(src), "here"));
|
||||
}
|
||||
loc.advance();
|
||||
@@ -1940,7 +1940,7 @@ parse_array(location& loc, context<TC>& ctx)
|
||||
if( ! comma_found)
|
||||
{
|
||||
auto src = source_location(region(loc));
|
||||
return err(make_error_info("toml::parse_array: "
|
||||
return err(make_error_info(error_kind::syntax_error, "toml::parse_array: "
|
||||
"expected value-separator `,` or closing `]`",
|
||||
std::move(src), "here"));
|
||||
}
|
||||
@@ -2033,7 +2033,7 @@ parse_array(location& loc, context<TC>& ctx)
|
||||
if(loc.current() != ']')
|
||||
{
|
||||
auto src = source_location(region(loc));
|
||||
return err(make_error_info("toml::parse_array: missing closing bracket `]`",
|
||||
return err(make_error_info(error_kind::syntax_error, "toml::parse_array: missing closing bracket `]`",
|
||||
std::move(src), "expected `]`, reached EOF"));
|
||||
}
|
||||
else
|
||||
@@ -2216,7 +2216,7 @@ insert_value(const inserting_value_kind kind,
|
||||
if(fmt == table_format::oneline || fmt == table_format::multiline_oneline)
|
||||
{
|
||||
// foo = {bar = "baz"} or foo = { \n bar = "baz" \n }
|
||||
return err(make_error_info("toml::insert_value: "
|
||||
return err(make_error_info(error_kind::syntax_error, "toml::insert_value: "
|
||||
"failed to insert a value: inline table is immutable",
|
||||
key_loc, "inserting this",
|
||||
found->second.location(), "to this table"));
|
||||
@@ -2224,7 +2224,7 @@ insert_value(const inserting_value_kind kind,
|
||||
// dotted key cannot reopen a table.
|
||||
if(kind ==inserting_value_kind::dotted_keys && fmt != table_format::dotted)
|
||||
{
|
||||
return err(make_error_info("toml::insert_value: "
|
||||
return err(make_error_info(error_kind::syntax_error, "toml::insert_value: "
|
||||
"reopening a table using dotted keys",
|
||||
key_loc, "dotted key cannot reopen a table",
|
||||
found->second.location(), "this table is already closed"));
|
||||
@@ -2237,7 +2237,7 @@ insert_value(const inserting_value_kind kind,
|
||||
// aot = [{this = "type", of = "aot"}] # cannot be reopened
|
||||
if(found->second.as_array_fmt().fmt != array_format::array_of_tables)
|
||||
{
|
||||
return err(make_error_info("toml::insert_value:"
|
||||
return err(make_error_info(error_kind::syntax_error, "toml::insert_value:"
|
||||
"inline array of tables are immutable",
|
||||
key_loc, "inserting this",
|
||||
found->second.location(), "inline array of tables"));
|
||||
@@ -2249,7 +2249,7 @@ insert_value(const inserting_value_kind kind,
|
||||
// [[array.of.tables]]
|
||||
// [array.of] # reopening supertable is okay
|
||||
// tables.x = "foo" # appending `x` to the first table
|
||||
return err(make_error_info("toml::insert_value:"
|
||||
return err(make_error_info(error_kind::syntax_error, "toml::insert_value:"
|
||||
"dotted key cannot reopen an array-of-tables",
|
||||
key_loc, "inserting this",
|
||||
found->second.location(), "to this array-of-tables."));
|
||||
@@ -2269,7 +2269,7 @@ insert_value(const inserting_value_kind kind,
|
||||
}
|
||||
else
|
||||
{
|
||||
return err(make_error_info("toml::insert_value: "
|
||||
return err(make_error_info(error_kind::syntax_error, "toml::insert_value: "
|
||||
"failed to insert a value, value already exists",
|
||||
key_loc, "while inserting this",
|
||||
found->second.location(), "non-table value already exists"));
|
||||
@@ -2283,7 +2283,7 @@ insert_value(const inserting_value_kind kind,
|
||||
{
|
||||
if(current_table.find(key) != current_table.end())
|
||||
{
|
||||
return err(make_error_info("toml::insert_value: "
|
||||
return err(make_error_info(error_kind::syntax_error, "toml::insert_value: "
|
||||
"failed to insert a value, value already exists",
|
||||
key_loc, "inserting this",
|
||||
current_table.at(key).location(), "but value already exists"));
|
||||
@@ -2307,7 +2307,7 @@ insert_value(const inserting_value_kind kind,
|
||||
if( ! target.is_table() || // could be an array-of-tables
|
||||
target.as_table_fmt().fmt != table_format::implicit)
|
||||
{
|
||||
return err(make_error_info("toml::insert_value: "
|
||||
return err(make_error_info(error_kind::syntax_error, "toml::insert_value: "
|
||||
"failed to insert a table, table already defined",
|
||||
key_loc, "inserting this",
|
||||
target.location(), "this table is explicitly defined"));
|
||||
@@ -2322,7 +2322,7 @@ insert_value(const inserting_value_kind kind,
|
||||
// w = "foo"
|
||||
// [x]
|
||||
// y = "bar"
|
||||
return err(make_error_info("toml::insert_value: "
|
||||
return err(make_error_info(error_kind::syntax_error, "toml::insert_value: "
|
||||
"failed to insert a table, table keys conflict to each other",
|
||||
key_loc, "inserting this table",
|
||||
kv.second.location(), "having this value",
|
||||
@@ -2362,14 +2362,14 @@ insert_value(const inserting_value_kind kind,
|
||||
{
|
||||
if( ! found->second.is_array_of_tables())
|
||||
{
|
||||
return err(make_error_info("toml::insert_value: "
|
||||
return err(make_error_info(error_kind::syntax_error, "toml::insert_value: "
|
||||
"failed to insert an array of tables, value already exists",
|
||||
key_loc, "while inserting this",
|
||||
found->second.location(), "non-table value already exists"));
|
||||
}
|
||||
if(found->second.as_array_fmt().fmt != array_format::array_of_tables)
|
||||
{
|
||||
return err(make_error_info("toml::insert_value: "
|
||||
return err(make_error_info(error_kind::syntax_error, "toml::insert_value: "
|
||||
"failed to insert a table, inline array of tables is immutable",
|
||||
key_loc, "while inserting this",
|
||||
found->second.location(), "this is inline array-of-tables"));
|
||||
@@ -2383,7 +2383,7 @@ insert_value(const inserting_value_kind kind,
|
||||
}
|
||||
}
|
||||
}
|
||||
return err(make_error_info("toml::insert_key: no keys found",
|
||||
return err(make_error_info(error_kind::syntax_error, "toml::insert_key: no keys found",
|
||||
std::move(key_loc), "here"));
|
||||
}
|
||||
|
||||
@@ -2403,7 +2403,7 @@ parse_inline_table(location& loc, context<TC>& ctx)
|
||||
if(loc.eof() || loc.current() != '{')
|
||||
{
|
||||
auto src = source_location(region(loc));
|
||||
return err(make_error_info("toml::parse_inline_table: "
|
||||
return err(make_error_info(error_kind::syntax_error, "toml::parse_inline_table: "
|
||||
"The next token is not an inline table", std::move(src), "here"));
|
||||
}
|
||||
loc.advance();
|
||||
@@ -2438,7 +2438,7 @@ parse_inline_table(location& loc, context<TC>& ctx)
|
||||
if(comma_found && ! spec.v1_1_0_allow_trailing_comma_in_inline_tables)
|
||||
{
|
||||
auto src = source_location(region(loc));
|
||||
return err(make_error_info("toml::parse_inline_table: trailing "
|
||||
return err(make_error_info(error_kind::syntax_error, "toml::parse_inline_table: trailing "
|
||||
"comma is not allowed in TOML-v1.0.0)", std::move(src), "here"));
|
||||
}
|
||||
|
||||
@@ -2458,7 +2458,7 @@ parse_inline_table(location& loc, context<TC>& ctx)
|
||||
if( ! comma_found && ! still_empty)
|
||||
{
|
||||
auto src = source_location(region(loc));
|
||||
return err(make_error_info("toml::parse_inline_table: "
|
||||
return err(make_error_info(error_kind::syntax_error, "toml::parse_inline_table: "
|
||||
"expected value-separator `,` or closing `}`",
|
||||
std::move(src), "here"));
|
||||
}
|
||||
@@ -2586,7 +2586,7 @@ parse_inline_table(location& loc, context<TC>& ctx)
|
||||
if(loc.current() != '}')
|
||||
{
|
||||
auto src = source_location(region(loc));
|
||||
return err(make_error_info("toml::parse_inline_table: "
|
||||
return err(make_error_info(error_kind::syntax_error, "toml::parse_inline_table: "
|
||||
"missing closing bracket `}`",
|
||||
std::move(src), "expected `}`, reached line end"));
|
||||
}
|
||||
@@ -2702,7 +2702,7 @@ guess_number_type(const location& first, const context<TC>& ctx)
|
||||
return ok(value_t::floating);
|
||||
}
|
||||
auto src = source_location(region(loc));
|
||||
return err(make_error_info(
|
||||
return err(make_error_info(error_kind::syntax_error,
|
||||
"bad float: `_` must be surrounded by digits",
|
||||
std::move(src), "invalid underscore",
|
||||
"Hint: valid : +1.0, -2e-2, 3.141_592_653_589, inf, nan\n"
|
||||
@@ -2723,7 +2723,7 @@ guess_number_type(const location& first, const context<TC>& ctx)
|
||||
return ok(value_t::floating);
|
||||
}
|
||||
auto src = source_location(region(loc));
|
||||
return err(make_error_info(
|
||||
return err(make_error_info(error_kind::syntax_error,
|
||||
"bad float: `_` must be surrounded by digits",
|
||||
std::move(src), "invalid underscore",
|
||||
"Hint: valid : +1.0, -2e-2, 3.141_592_653_589, inf, nan\n"
|
||||
@@ -2750,7 +2750,7 @@ guess_number_type(const location& first, const context<TC>& ctx)
|
||||
int_reg.as_string() == "-0" || int_reg.as_string() == "+0"))
|
||||
{
|
||||
auto src = source_location(region(loc));
|
||||
return err(make_error_info(
|
||||
return err(make_error_info(error_kind::syntax_error,
|
||||
"bad integer: leading zero is not allowed in decimal int",
|
||||
std::move(src), "leading zero",
|
||||
"Hint: valid : -42, 1_000, 1_2_3_4_5, 0xC0FFEE, 0b0010, 0o755\n"
|
||||
@@ -2759,7 +2759,7 @@ guess_number_type(const location& first, const context<TC>& ctx)
|
||||
else
|
||||
{
|
||||
auto src = source_location(region(loc));
|
||||
return err(make_error_info(
|
||||
return err(make_error_info(error_kind::syntax_error,
|
||||
"bad integer: `_` must be surrounded by digits",
|
||||
std::move(src), "invalid underscore",
|
||||
"Hint: valid : -42, 1_000, 1_2_3_4_5, 0xC0FFEE, 0b0010, 0o755\n"
|
||||
@@ -2771,7 +2771,7 @@ guess_number_type(const location& first, const context<TC>& ctx)
|
||||
if(loc.current() == '0')
|
||||
{
|
||||
loc.retrace();
|
||||
return err(make_error_info(
|
||||
return err(make_error_info(error_kind::syntax_error,
|
||||
"bad integer: leading zero",
|
||||
source_location(region(loc)), "leading zero is not allowed",
|
||||
std::string("Hint: valid : -42, 1_000, 1_2_3_4_5, 0xC0FFEE, 0b0010, 0o755\n"
|
||||
@@ -2780,7 +2780,7 @@ guess_number_type(const location& first, const context<TC>& ctx)
|
||||
}
|
||||
else // invalid digits, especially in oct/bin ints.
|
||||
{
|
||||
return err(make_error_info(
|
||||
return err(make_error_info(error_kind::syntax_error,
|
||||
"bad integer: invalid digit after an integer",
|
||||
source_location(region(loc)), "this digit is not allowed",
|
||||
std::string("Hint: valid : -42, 1_000, 1_2_3_4_5, 0xC0FFEE, 0b0010, 0o755\n"
|
||||
@@ -2791,7 +2791,7 @@ guess_number_type(const location& first, const context<TC>& ctx)
|
||||
if(c == ':' || c == '-')
|
||||
{
|
||||
auto src = source_location(region(loc));
|
||||
return err(make_error_info("bad datetime: invalid format",
|
||||
return err(make_error_info(error_kind::syntax_error, "bad datetime: invalid format",
|
||||
std::move(src), "here",
|
||||
std::string("Hint: valid : 1979-05-27T07:32:00-07:00, 1979-05-27 07:32:00.999999Z\n"
|
||||
"Hint: invalid: 1979-05-27T7:32:00-7:00, 1979-05-27 7:32-00:30")
|
||||
@@ -2800,7 +2800,7 @@ guess_number_type(const location& first, const context<TC>& ctx)
|
||||
if(c == '.' || c == 'e' || c == 'E')
|
||||
{
|
||||
auto src = source_location(region(loc));
|
||||
return err(make_error_info("bad float: invalid format",
|
||||
return err(make_error_info(error_kind::syntax_error, "bad float: invalid format",
|
||||
std::move(src), "here", std::string(
|
||||
"Hint: valid : +1.0, -2e-2, 3.141_592_653_589, inf, nan\n"
|
||||
"Hint: invalid: .0, 1., _1.0, 1.0_, 1_.0, 1.0__0\n")));
|
||||
@@ -2811,7 +2811,7 @@ guess_number_type(const location& first, const context<TC>& ctx)
|
||||
if( ! loc.eof() && loc.current() == '.')
|
||||
{
|
||||
auto src = source_location(region(loc));
|
||||
return err(make_error_info("bad float: integer part is required before decimal point",
|
||||
return err(make_error_info(error_kind::syntax_error, "bad float: integer part is required before decimal point",
|
||||
std::move(src), "missing integer part", std::string(
|
||||
"Hint: valid : +1.0, -2e-2, 3.141_592_653_589, inf, nan\n"
|
||||
"Hint: invalid: .0, 1., _1.0, 1.0_, 1_.0, 1.0__0\n")
|
||||
@@ -2820,7 +2820,7 @@ guess_number_type(const location& first, const context<TC>& ctx)
|
||||
if( ! loc.eof() && loc.current() == '_')
|
||||
{
|
||||
auto src = source_location(region(loc));
|
||||
return err(make_error_info("bad number: `_` must be surrounded by digits",
|
||||
return err(make_error_info(error_kind::syntax_error, "bad number: `_` must be surrounded by digits",
|
||||
std::move(src), "digits required before `_`", std::string(
|
||||
"Hint: valid : -42, 1_000, 1_2_3_4_5, 0xC0FFEE, 0b0010, 0o755\n"
|
||||
"Hint: invalid: _42, 1__000, 0123\n")
|
||||
@@ -2828,7 +2828,7 @@ guess_number_type(const location& first, const context<TC>& ctx)
|
||||
}
|
||||
|
||||
auto src = source_location(region(loc));
|
||||
return err(make_error_info("bad format: unknown value appeared",
|
||||
return err(make_error_info(error_kind::syntax_error, "bad format: unknown value appeared",
|
||||
std::move(src), "here"));
|
||||
}
|
||||
|
||||
@@ -2968,7 +2968,7 @@ parse_value(location& loc, context<TC>& ctx)
|
||||
else
|
||||
{
|
||||
auto src = source_location(region(loc));
|
||||
return err(make_error_info("toml::parse_value: unknown value appeared",
|
||||
return err(make_error_info(error_kind::syntax_error, "toml::parse_value: unknown value appeared",
|
||||
std::move(src), "here"));
|
||||
}
|
||||
}
|
||||
@@ -2985,7 +2985,7 @@ parse_value(location& loc, context<TC>& ctx)
|
||||
default:
|
||||
{
|
||||
auto src = source_location(region(loc));
|
||||
return err(make_error_info("toml::parse_value: unknown value appeared",
|
||||
return err(make_error_info(error_kind::syntax_error, "toml::parse_value: unknown value appeared",
|
||||
std::move(src), "here"));
|
||||
}
|
||||
}
|
||||
@@ -3097,7 +3097,7 @@ parse_table(location& loc, context<TC>& ctx, basic_value<TC>& table)
|
||||
newline_found = newline_found || (sp.has_value() && sp.value().newline_found);
|
||||
if( ! newline_found)
|
||||
{
|
||||
return err(make_error_info("toml::parse_table: "
|
||||
return err(make_error_info(error_kind::syntax_error, "toml::parse_table: "
|
||||
"newline (LF / CRLF) or EOF is expected",
|
||||
source_location(region(loc)), "here"));
|
||||
}
|
||||
@@ -3524,7 +3524,7 @@ try_parse(std::istream& is, std::string fname = "unknown file", spec s = spec::d
|
||||
|
||||
// read whole file as a sequence of char
|
||||
assert(fsize >= 0);
|
||||
std::vector<detail::location::char_type> letters(static_cast<std::size_t>(fsize));
|
||||
std::vector<detail::location::char_type> letters(static_cast<std::size_t>(fsize), '\0');
|
||||
is.read(reinterpret_cast<char*>(letters.data()), fsize);
|
||||
|
||||
return detail::parse_impl<TC>(std::move(letters), std::move(fname), std::move(s));
|
||||
@@ -3560,7 +3560,8 @@ try_parse(std::string fname, spec s = spec::default_version())
|
||||
if(!ifs.good())
|
||||
{
|
||||
std::vector<error_info> e;
|
||||
e.push_back(error_info("toml::parse: Error opening file \"" + fname + "\"", {}));
|
||||
e.push_back(error_info(error_kind::file_io_error,
|
||||
"toml::parse: Error opening file \"" + fname + "\"", {}));
|
||||
return err(std::move(e));
|
||||
}
|
||||
ifs.exceptions(std::ifstream::failbit | std::ifstream::badbit);
|
||||
@@ -3641,7 +3642,8 @@ try_parse(const FSPATH& fpath, spec s = spec::default_version())
|
||||
if(!ifs.good())
|
||||
{
|
||||
std::vector<error_info> e;
|
||||
e.push_back(error_info("toml::parse: Error opening file \"" + fpath.string() + "\"", {}));
|
||||
e.push_back(error_info(error_kind::file_io_error,
|
||||
"toml::parse: Error opening file \"" + fpath.string() + "\"", {}));
|
||||
return err(std::move(e));
|
||||
}
|
||||
ifs.exceptions(std::ifstream::failbit | std::ifstream::badbit);
|
||||
@@ -3675,7 +3677,7 @@ try_parse(FILE* fp, std::string filename, spec s = spec::default_version())
|
||||
const long beg = std::ftell(fp);
|
||||
if (beg == -1L)
|
||||
{
|
||||
return err(std::vector<error_info>{error_info(
|
||||
return err(std::vector<error_info>{error_info(error_kind::file_io_error,
|
||||
std::string("Failed to access: \"") + filename +
|
||||
"\", errno = " + std::to_string(errno), {}
|
||||
)});
|
||||
@@ -3684,7 +3686,7 @@ try_parse(FILE* fp, std::string filename, spec s = spec::default_version())
|
||||
const int res_seekend = std::fseek(fp, 0, SEEK_END);
|
||||
if (res_seekend != 0)
|
||||
{
|
||||
return err(std::vector<error_info>{error_info(
|
||||
return err(std::vector<error_info>{error_info(error_kind::file_io_error,
|
||||
std::string("Failed to seek: \"") + filename +
|
||||
"\", errno = " + std::to_string(errno), {}
|
||||
)});
|
||||
@@ -3693,7 +3695,7 @@ try_parse(FILE* fp, std::string filename, spec s = spec::default_version())
|
||||
const long end = std::ftell(fp);
|
||||
if (end == -1L)
|
||||
{
|
||||
return err(std::vector<error_info>{error_info(
|
||||
return err(std::vector<error_info>{error_info(error_kind::file_io_error,
|
||||
std::string("Failed to access: \"") + filename +
|
||||
"\", errno = " + std::to_string(errno), {}
|
||||
)});
|
||||
@@ -3704,7 +3706,7 @@ try_parse(FILE* fp, std::string filename, spec s = spec::default_version())
|
||||
const auto res_seekbeg = std::fseek(fp, beg, SEEK_SET);
|
||||
if (res_seekbeg != 0)
|
||||
{
|
||||
return err(std::vector<error_info>{error_info(
|
||||
return err(std::vector<error_info>{error_info(error_kind::file_io_error,
|
||||
std::string("Failed to seek: \"") + filename +
|
||||
"\", errno = " + std::to_string(errno), {}
|
||||
)});
|
||||
@@ -3714,7 +3716,15 @@ try_parse(FILE* fp, std::string filename, spec s = spec::default_version())
|
||||
// read whole file as a sequence of char
|
||||
assert(fsize >= 0);
|
||||
std::vector<detail::location::char_type> letters(static_cast<std::size_t>(fsize));
|
||||
std::fread(letters.data(), sizeof(char), static_cast<std::size_t>(fsize), fp);
|
||||
const auto actual = std::fread(letters.data(), sizeof(char), static_cast<std::size_t>(fsize), fp);
|
||||
if(actual != static_cast<std::size_t>(fsize))
|
||||
{
|
||||
return err(std::vector<error_info>{error_info(error_kind::file_io_error,
|
||||
std::string("File size changed: \"") + filename +
|
||||
std::string("\" make sure that FILE* is in binary mode "
|
||||
"to avoid LF <-> CRLF conversion"), {}
|
||||
)});
|
||||
}
|
||||
|
||||
return detail::parse_impl<TC>(std::move(letters), std::move(filename), std::move(s));
|
||||
}
|
||||
@@ -3752,7 +3762,12 @@ parse(FILE* fp, std::string filename, spec s = spec::default_version())
|
||||
// read whole file as a sequence of char
|
||||
assert(fsize >= 0);
|
||||
std::vector<detail::location::char_type> letters(static_cast<std::size_t>(fsize));
|
||||
std::fread(letters.data(), sizeof(char), static_cast<std::size_t>(fsize), fp);
|
||||
const auto actual = std::fread(letters.data(), sizeof(char), static_cast<std::size_t>(fsize), fp);
|
||||
if(actual != static_cast<std::size_t>(fsize))
|
||||
{
|
||||
throw file_io_error(errno, "File size changed; make sure that "
|
||||
"FILE* is in binary mode to avoid LF <-> CRLF conversion", filename);
|
||||
}
|
||||
|
||||
auto res = detail::parse_impl<TC>(std::move(letters), std::move(filename), std::move(s));
|
||||
if(res.is_ok())
|
||||
|
||||
@@ -217,7 +217,7 @@ try_get(const basic_value<TC>& v) noexcept
|
||||
default:
|
||||
{
|
||||
const auto loc = v.location();
|
||||
return err(make_error_info("toml::try_get(): bad_cast to "
|
||||
return err(make_error_info(error_kind::type_error, "toml::try_get(): bad_cast to "
|
||||
"std::chrono::system_clock::time_point", loc,
|
||||
"the actual type is " + to_string(v.type())));
|
||||
}
|
||||
@@ -280,7 +280,7 @@ try_get(const basic_value<TC>& v) noexcept
|
||||
if(a.size() != container.size())
|
||||
{
|
||||
const auto loc = v.location();
|
||||
return err(make_error_info("toml::try_get: while converting to an array: "
|
||||
return err(make_error_info(error_kind::out_of_range, "toml::try_get: while converting to an array: "
|
||||
" array size is " + std::to_string(container.size()) +
|
||||
" but there are " + std::to_string(a.size()) + " elements in toml array.",
|
||||
loc, "here"));
|
||||
@@ -344,7 +344,7 @@ try_get(const basic_value<TC>& v) noexcept
|
||||
if(ar.size() != 2)
|
||||
{
|
||||
const auto loc = v.location();
|
||||
return err(make_error_info("toml::try_get: while converting std::pair: "
|
||||
return err(make_error_info(error_kind::out_of_range, "toml::try_get: while converting std::pair: "
|
||||
" but there are " + std::to_string(ar.size()) +
|
||||
" > 2 elements in toml array.",
|
||||
loc, "here"));
|
||||
@@ -411,7 +411,8 @@ try_get(const basic_value<TC>& v) noexcept
|
||||
if(ar.size() != std::tuple_size<T>::value)
|
||||
{
|
||||
const auto loc = v.location();
|
||||
return err(make_error_info("toml::try_get: while converting std::tuple: "
|
||||
return err(make_error_info(error_kind::out_of_range,
|
||||
"toml::try_get: while converting std::tuple: "
|
||||
" there are " + std::to_string(ar.size()) + " > " +
|
||||
std::to_string(std::tuple_size<T>::value) + " elements in toml array.",
|
||||
loc, "here"));
|
||||
|
||||
@@ -44,7 +44,7 @@ read_dec_int(const std::string& str, const source_location src)
|
||||
iss >> val;
|
||||
if(iss.fail())
|
||||
{
|
||||
return err(make_error_info("toml::parse_dec_integer: "
|
||||
return err(make_error_info(error_kind::syntax_error, "toml::parse_dec_integer: "
|
||||
"too large integer: current max digits = 2^" + std::to_string(max_digits),
|
||||
std::move(src), "must be < 2^" + std::to_string(max_digits)));
|
||||
}
|
||||
@@ -63,7 +63,7 @@ read_hex_int(const std::string& str, const source_location src)
|
||||
iss >> std::hex >> val;
|
||||
if(iss.fail())
|
||||
{
|
||||
return err(make_error_info("toml::parse_hex_integer: "
|
||||
return err(make_error_info(error_kind::syntax_error, "toml::parse_hex_integer: "
|
||||
"too large integer: current max value = 2^" + std::to_string(max_digits),
|
||||
std::move(src), "must be < 2^" + std::to_string(max_digits)));
|
||||
}
|
||||
@@ -82,7 +82,7 @@ read_oct_int(const std::string& str, const source_location src)
|
||||
iss >> std::oct >> val;
|
||||
if(iss.fail())
|
||||
{
|
||||
return err(make_error_info("toml::parse_oct_integer: "
|
||||
return err(make_error_info(error_kind::syntax_error, "toml::parse_oct_integer: "
|
||||
"too large integer: current max value = 2^" + std::to_string(max_digits),
|
||||
std::move(src), "must be < 2^" + std::to_string(max_digits)));
|
||||
}
|
||||
@@ -131,7 +131,7 @@ read_bin_int(const std::string& str, const source_location src)
|
||||
}
|
||||
if(base == 0)
|
||||
{
|
||||
return err(make_error_info("toml::parse_bin_integer: "
|
||||
return err(make_error_info(error_kind::syntax_error, "toml::parse_bin_integer: "
|
||||
"too large integer: current max value = 2^" + std::to_string(max_digits),
|
||||
std::move(src), "must be < 2^" + std::to_string(max_digits)));
|
||||
}
|
||||
@@ -166,7 +166,7 @@ read_hex_float(const std::string& str, const source_location src, float val)
|
||||
#endif
|
||||
if(res != 1)
|
||||
{
|
||||
return err(make_error_info("toml::parse_floating: "
|
||||
return err(make_error_info(error_kind::syntax_error, "toml::parse_floating: "
|
||||
"failed to read hexadecimal floating point value ",
|
||||
std::move(src), "here"));
|
||||
}
|
||||
@@ -182,7 +182,7 @@ read_hex_float(const std::string& str, const source_location src, double val)
|
||||
#endif
|
||||
if(res != 1)
|
||||
{
|
||||
return err(make_error_info("toml::parse_floating: "
|
||||
return err(make_error_info(error_kind::syntax_error, "toml::parse_floating: "
|
||||
"failed to read hexadecimal floating point value ",
|
||||
std::move(src), "here"));
|
||||
}
|
||||
@@ -195,7 +195,7 @@ cxx::enable_if_t<cxx::conjunction<
|
||||
>::value, result<T, error_info>>
|
||||
read_hex_float(const std::string&, const source_location src, T)
|
||||
{
|
||||
return err(make_error_info("toml::parse_floating: failed to read "
|
||||
return err(make_error_info(error_kind::syntax_error, "toml::parse_floating: failed to read "
|
||||
"floating point value because of unknown type in type_config",
|
||||
std::move(src), "here"));
|
||||
}
|
||||
@@ -209,7 +209,7 @@ read_dec_float(const std::string& str, const source_location src)
|
||||
iss >> val;
|
||||
if(iss.fail())
|
||||
{
|
||||
return err(make_error_info("toml::parse_floating: "
|
||||
return err(make_error_info(error_kind::syntax_error, "toml::parse_floating: "
|
||||
"failed to read floating point value from stream",
|
||||
std::move(src), "here"));
|
||||
}
|
||||
|
||||
@@ -2102,12 +2102,16 @@ operator>=(const basic_value<TC>& lhs, const basic_value<TC>& rhs)
|
||||
}
|
||||
|
||||
// error_info helper
|
||||
namespace detail
|
||||
{
|
||||
template<typename TC, typename ... Ts>
|
||||
error_info make_error_info_rec(error_info e,
|
||||
const basic_value<TC>& v, std::string msg, Ts&& ... tail)
|
||||
{
|
||||
return make_error_info_rec(std::move(e), v.location(), std::move(msg), std::forward<Ts>(tail)...);
|
||||
}
|
||||
} // detail
|
||||
|
||||
template<typename TC, typename ... Ts>
|
||||
error_info make_error_info(
|
||||
std::string title, const basic_value<TC>& v, std::string msg, Ts&& ... tail)
|
||||
@@ -2116,6 +2120,13 @@ error_info make_error_info(
|
||||
v.location(), std::move(msg), std::forward<Ts>(tail)...);
|
||||
}
|
||||
template<typename TC, typename ... Ts>
|
||||
error_info make_error_info(error_kind k,
|
||||
std::string title, const basic_value<TC>& v, std::string msg, Ts&& ... tail)
|
||||
{
|
||||
return make_error_info(k, std::move(title),
|
||||
v.location(), std::move(msg), std::forward<Ts>(tail)...);
|
||||
}
|
||||
template<typename TC, typename ... Ts>
|
||||
std::string format_error(std::string title,
|
||||
const basic_value<TC>& v, std::string msg, Ts&& ... tail)
|
||||
{
|
||||
@@ -2129,7 +2140,8 @@ namespace detail
|
||||
template<typename TC>
|
||||
error_info make_type_error(const basic_value<TC>& v, const std::string& fname, const value_t ty)
|
||||
{
|
||||
return make_error_info(fname + ": bad_cast to " + to_string(ty),
|
||||
return make_error_info(error_kind::type_error,
|
||||
fname + ": bad_cast to " + to_string(ty),
|
||||
v.location(), "the actual type is " + to_string(v.type()));
|
||||
}
|
||||
template<typename TC>
|
||||
@@ -2141,7 +2153,7 @@ error_info make_not_found_error(const basic_value<TC>& v, const std::string& fna
|
||||
std::vector<std::pair<source_location, std::string>> locs;
|
||||
if( ! loc.is_ok())
|
||||
{
|
||||
return error_info(title, locs);
|
||||
return error_info(error_kind::out_of_range, title, locs);
|
||||
}
|
||||
|
||||
if(loc.first_line_number() == 1 && loc.first_column_number() == 1 && loc.length() == 1)
|
||||
@@ -2166,7 +2178,7 @@ error_info make_not_found_error(const basic_value<TC>& v, const std::string& fna
|
||||
{
|
||||
locs.emplace_back(v.location(), "in this table");
|
||||
}
|
||||
return error_info(title, locs);
|
||||
return error_info(error_kind::out_of_range, title, locs);
|
||||
}
|
||||
template<typename TC>
|
||||
error_info make_not_found_error(const basic_value<TC>& v, const std::string& fname, const std::size_t idx)
|
||||
@@ -2178,7 +2190,8 @@ error_info make_not_found_error(const basic_value<TC>& v, const std::string& fna
|
||||
std::ostringstream oss;
|
||||
oss << "actual length (" << v.as_array(std::nothrow).size()
|
||||
<< ") is shorter than the specified index (" << idx << ").";
|
||||
return make_error_info(fname + ": no element corresponding to the index",
|
||||
return make_error_info(error_kind::out_of_range,
|
||||
fname + ": no element corresponding to the index",
|
||||
v, oss.str());
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
#define TOML11_VERSION_MAJOR 4
|
||||
#define TOML11_VERSION_MINOR 0
|
||||
#define TOML11_VERSION_PATCH 1
|
||||
#define TOML11_VERSION_PATCH 2
|
||||
|
||||
#ifndef __cplusplus
|
||||
# error "__cplusplus is not defined"
|
||||
|
||||
@@ -52,8 +52,7 @@ struct local_time_format_info;
|
||||
struct array_format_info;
|
||||
struct table_format_info;
|
||||
|
||||
template<typename Key, typename Val, typename Cmp = std::equal_to<Key>,
|
||||
typename Allocator = std::allocator<std::pair<Key, Val>>>
|
||||
template<typename Key, typename Val, typename Cmp, typename Allocator>
|
||||
class ordered_map;
|
||||
|
||||
struct syntax_error;
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
#define TOML11_VERSION_MAJOR 4
|
||||
#define TOML11_VERSION_MINOR 0
|
||||
#define TOML11_VERSION_PATCH 1
|
||||
#define TOML11_VERSION_PATCH 2
|
||||
|
||||
#ifndef __cplusplus
|
||||
# error "__cplusplus is not defined"
|
||||
@@ -3584,7 +3584,7 @@ struct has_specialized_into_impl
|
||||
template<typename T>
|
||||
static std::false_type check(...);
|
||||
template<typename T, std::size_t S = sizeof(::toml::into<T>)>
|
||||
static std::true_type check(::toml::from<T>*);
|
||||
static std::true_type check(::toml::into<T>*);
|
||||
};
|
||||
|
||||
|
||||
@@ -5447,6 +5447,10 @@ struct error_info
|
||||
std::string suffix_; // hint or something like that
|
||||
};
|
||||
|
||||
// forward decl
|
||||
template<typename TypeConfig>
|
||||
class basic_value;
|
||||
|
||||
namespace detail
|
||||
{
|
||||
inline error_info make_error_info_rec(error_info e)
|
||||
@@ -5459,6 +5463,10 @@ inline error_info make_error_info_rec(error_info e, std::string s)
|
||||
return e;
|
||||
}
|
||||
|
||||
template<typename TC, typename ... Ts>
|
||||
error_info make_error_info_rec(error_info e,
|
||||
const basic_value<TC>& v, std::string msg, Ts&& ... tail);
|
||||
|
||||
template<typename ... Ts>
|
||||
error_info make_error_info_rec(error_info e,
|
||||
source_location loc, std::string msg, Ts&& ... tail)
|
||||
@@ -7588,12 +7596,16 @@ operator>=(const basic_value<TC>& lhs, const basic_value<TC>& rhs)
|
||||
}
|
||||
|
||||
// error_info helper
|
||||
namespace detail
|
||||
{
|
||||
template<typename TC, typename ... Ts>
|
||||
error_info make_error_info_rec(error_info e,
|
||||
const basic_value<TC>& v, std::string msg, Ts&& ... tail)
|
||||
{
|
||||
return make_error_info_rec(std::move(e), v.location(), std::move(msg), std::forward<Ts>(tail)...);
|
||||
}
|
||||
} // detail
|
||||
|
||||
template<typename TC, typename ... Ts>
|
||||
error_info make_error_info(
|
||||
std::string title, const basic_value<TC>& v, std::string msg, Ts&& ... tail)
|
||||
@@ -15063,7 +15075,7 @@ try_parse(std::istream& is, std::string fname = "unknown file", spec s = spec::d
|
||||
|
||||
// read whole file as a sequence of char
|
||||
assert(fsize >= 0);
|
||||
std::vector<detail::location::char_type> letters(static_cast<std::size_t>(fsize));
|
||||
std::vector<detail::location::char_type> letters(static_cast<std::size_t>(fsize), '\0');
|
||||
is.read(reinterpret_cast<char*>(letters.data()), fsize);
|
||||
|
||||
return detail::parse_impl<TC>(std::move(letters), std::move(fname), std::move(s));
|
||||
@@ -15253,7 +15265,15 @@ try_parse(FILE* fp, std::string filename, spec s = spec::default_version())
|
||||
// read whole file as a sequence of char
|
||||
assert(fsize >= 0);
|
||||
std::vector<detail::location::char_type> letters(static_cast<std::size_t>(fsize));
|
||||
std::fread(letters.data(), sizeof(char), static_cast<std::size_t>(fsize), fp);
|
||||
const auto actual = std::fread(letters.data(), sizeof(char), static_cast<std::size_t>(fsize), fp);
|
||||
if(actual != static_cast<std::size_t>(fsize))
|
||||
{
|
||||
return err(std::vector<error_info>{error_info(
|
||||
std::string("File size changed: \"") + filename +
|
||||
std::string("\" make sure that FILE* is in binary mode "
|
||||
"to avoid LF <-> CRLF conversion"), {}
|
||||
)});
|
||||
}
|
||||
|
||||
return detail::parse_impl<TC>(std::move(letters), std::move(filename), std::move(s));
|
||||
}
|
||||
@@ -15291,7 +15311,12 @@ parse(FILE* fp, std::string filename, spec s = spec::default_version())
|
||||
// read whole file as a sequence of char
|
||||
assert(fsize >= 0);
|
||||
std::vector<detail::location::char_type> letters(static_cast<std::size_t>(fsize));
|
||||
std::fread(letters.data(), sizeof(char), static_cast<std::size_t>(fsize), fp);
|
||||
const auto actual = std::fread(letters.data(), sizeof(char), static_cast<std::size_t>(fsize), fp);
|
||||
if(actual != static_cast<std::size_t>(fsize))
|
||||
{
|
||||
throw file_io_error(errno, "File size changed; make sure that "
|
||||
"FILE* is in binary mode to avoid LF <-> CRLF conversion", filename);
|
||||
}
|
||||
|
||||
auto res = detail::parse_impl<TC>(std::move(letters), std::move(filename), std::move(s));
|
||||
if(res.is_ok())
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
set(TOML11_TEST_NAMES
|
||||
test_comments
|
||||
test_datetime
|
||||
test_error_message
|
||||
test_find
|
||||
test_try_find
|
||||
test_find_or
|
||||
@@ -24,6 +25,7 @@ set(TOML11_TEST_NAMES
|
||||
test_parse_table
|
||||
test_result
|
||||
test_scanner
|
||||
test_serialize
|
||||
test_syntax_boolean
|
||||
test_syntax_integer
|
||||
test_syntax_floating
|
||||
|
||||
79
tests/test_error_message.cpp
Normal file
79
tests/test_error_message.cpp
Normal file
@@ -0,0 +1,79 @@
|
||||
#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN
|
||||
#include "doctest.h"
|
||||
|
||||
#include <toml.hpp>
|
||||
|
||||
TEST_CASE("testing custom error message using source_location")
|
||||
{
|
||||
const toml::value root = toml::parse_str(R"(
|
||||
range = [0, 42]
|
||||
val = 54
|
||||
)");
|
||||
|
||||
const auto& lower = root.at("range").at(0);
|
||||
const auto& upper = root.at("range").at(1);
|
||||
const auto& val = root.at("val");
|
||||
|
||||
const auto err = toml::make_error_info("val not in range",
|
||||
lower.location(), "lower limit is defined here",
|
||||
upper.location(), "upper limit is defined here",
|
||||
val.location(), "this is not in the range",
|
||||
"Hint: upper limit is inclusive"
|
||||
);
|
||||
|
||||
CHECK_EQ(err.title(), "val not in range");
|
||||
CHECK_EQ(err.locations().size(), 3);
|
||||
CHECK_EQ(err.locations().at(0).second, "lower limit is defined here");
|
||||
CHECK_EQ(err.locations().at(1).second, "upper limit is defined here");
|
||||
CHECK_EQ(err.locations().at(2).second, "this is not in the range" );
|
||||
}
|
||||
|
||||
TEST_CASE("testing custom error message using value")
|
||||
{
|
||||
const toml::value root = toml::parse_str(R"(
|
||||
range = [0, 42]
|
||||
val = 54
|
||||
)");
|
||||
|
||||
const auto& lower = root.at("range").at(0);
|
||||
const auto& upper = root.at("range").at(1);
|
||||
const auto& val = root.at("val");
|
||||
|
||||
const auto err = toml::make_error_info("val not in range",
|
||||
lower, "lower limit is defined here",
|
||||
upper, "upper limit is defined here",
|
||||
val, "this is not in the range",
|
||||
"Hint: upper limit is inclusive"
|
||||
);
|
||||
|
||||
CHECK_EQ(err.title(), "val not in range");
|
||||
CHECK_EQ(err.locations().size(), 3);
|
||||
CHECK_EQ(err.locations().at(0).second, "lower limit is defined here");
|
||||
CHECK_EQ(err.locations().at(1).second, "upper limit is defined here");
|
||||
CHECK_EQ(err.locations().at(2).second, "this is not in the range" );
|
||||
}
|
||||
|
||||
TEST_CASE("testing custom error message using source_location and value")
|
||||
{
|
||||
const toml::value root = toml::parse_str(R"(
|
||||
range = [0, 42]
|
||||
val = 54
|
||||
)");
|
||||
|
||||
const auto& lower = root.at("range").at(0);
|
||||
const auto& upper = root.at("range").at(1);
|
||||
const auto& val = root.at("val");
|
||||
|
||||
const auto err = toml::make_error_info("val not in range",
|
||||
lower, "lower limit is defined here",
|
||||
upper, "upper limit is defined here",
|
||||
val.location(), "this is not in the range",
|
||||
"Hint: upper limit is inclusive"
|
||||
);
|
||||
|
||||
CHECK_EQ(err.title(), "val not in range");
|
||||
CHECK_EQ(err.locations().size(), 3);
|
||||
CHECK_EQ(err.locations().at(0).second, "lower limit is defined here");
|
||||
CHECK_EQ(err.locations().at(1).second, "upper limit is defined here");
|
||||
CHECK_EQ(err.locations().at(2).second, "this is not in the range" );
|
||||
}
|
||||
150
tests/test_serialize.cpp
Normal file
150
tests/test_serialize.cpp
Normal file
@@ -0,0 +1,150 @@
|
||||
#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN
|
||||
#include "doctest.h"
|
||||
|
||||
#include <toml.hpp>
|
||||
|
||||
#include <clocale>
|
||||
|
||||
TEST_CASE("testing serialization")
|
||||
{
|
||||
using namespace toml::literals::toml_literals;
|
||||
|
||||
const auto spec_example = R"(# This is a TOML document
|
||||
|
||||
title = "TOML Example"
|
||||
|
||||
[owner]
|
||||
name = "Tom Preston-Werner"
|
||||
dob = 1979-05-27T07:32:00-08:00
|
||||
|
||||
[database]
|
||||
enabled = true
|
||||
ports = [ 8000, 8001, 8002 ]
|
||||
data = [ ["delta", "phi"], [3.14] ]
|
||||
temp_targets = { cpu = 79.5, case = 72.0 }
|
||||
|
||||
[servers]
|
||||
|
||||
[servers.alpha]
|
||||
ip = "10.0.0.1"
|
||||
role = "frontend"
|
||||
|
||||
[servers.beta]
|
||||
ip = "10.0.0.2"
|
||||
role = "backend")"_toml;
|
||||
|
||||
// format and parse
|
||||
const auto v = toml::parse_str(toml::format(spec_example));
|
||||
|
||||
CHECK_EQ(v, spec_example);
|
||||
}
|
||||
|
||||
TEST_CASE("testing serialization with complicated keys")
|
||||
{
|
||||
using namespace toml::literals::toml_literals;
|
||||
|
||||
const auto spec_example = R"(
|
||||
[keys]
|
||||
|
||||
key = "value"
|
||||
bare_key = "value"
|
||||
bare-key = "value"
|
||||
1234 = "value"
|
||||
|
||||
"127.0.0.1" = "value"
|
||||
"character encoding" = "value"
|
||||
"ʎǝʞ" = "value"
|
||||
'key2' = "value"
|
||||
'quoted "value"' = "value"
|
||||
|
||||
"" = "blank"
|
||||
|
||||
fruits.apple.skin = "thin"
|
||||
fruits.apple.color = "red"
|
||||
|
||||
fruits.orange.skin = "thick"
|
||||
fruits.orange.color = "orange"
|
||||
|
||||
site."google.com" = true
|
||||
3.14159 = "pi"
|
||||
)"_toml;
|
||||
|
||||
// format and parse
|
||||
const auto v = toml::parse_str(toml::format(spec_example));
|
||||
|
||||
CHECK_EQ(v, spec_example);
|
||||
}
|
||||
|
||||
TEST_CASE("testing serialization with array of tables")
|
||||
{
|
||||
using namespace toml::literals::toml_literals;
|
||||
|
||||
const auto spec_example = R"(
|
||||
points = [ { x = 1, y = 2, z = 3 },
|
||||
{ x = 7, y = 8, z = 9 },
|
||||
{ x = 2, y = 4, z = 8 } ]
|
||||
|
||||
[[products]]
|
||||
name = "Hammer"
|
||||
sku = 738594937
|
||||
|
||||
[[products]] # empty table within the array
|
||||
|
||||
[[products]]
|
||||
name = "Nail"
|
||||
sku = 284758393
|
||||
|
||||
color = "gray"
|
||||
|
||||
[[fruits]]
|
||||
name = "apple"
|
||||
|
||||
[fruits.physical] # subtable
|
||||
color = "red"
|
||||
shape = "round"
|
||||
|
||||
[[fruits.varieties]] # nested array of tables
|
||||
name = "red delicious"
|
||||
|
||||
[[fruits.varieties]]
|
||||
name = "granny smith"
|
||||
|
||||
[[fruits]]
|
||||
name = "banana"
|
||||
|
||||
[[fruits.varieties]]
|
||||
name = "plantain"
|
||||
)"_toml;
|
||||
|
||||
// format and parse
|
||||
const auto v = toml::parse_str(toml::format(spec_example));
|
||||
|
||||
CHECK_EQ(v, spec_example);
|
||||
}
|
||||
|
||||
TEST_CASE("testing serialization with locale")
|
||||
{
|
||||
std::string current_locale = std::setlocale(LC_ALL, nullptr);
|
||||
|
||||
// fr_FR is a one of locales that uses `,` as a decimal separator.
|
||||
if(const char* try_hyphen = std::setlocale(LC_ALL, "fr_FR.UTF-8"))
|
||||
{
|
||||
current_locale = std::string(try_hyphen);
|
||||
}
|
||||
else if(const char* try_nohyphen = std::setlocale(LC_ALL, "fr_FR.utf8"))
|
||||
{
|
||||
current_locale = std::string(try_nohyphen);
|
||||
}
|
||||
|
||||
MESSAGE("current_locale = ", current_locale);
|
||||
|
||||
const auto v1 = toml::parse_str(R"(
|
||||
pi = 3.1415_9265
|
||||
large_int = 123_456_789
|
||||
)");
|
||||
const auto v2 = toml::parse_str(toml::format(v1));
|
||||
|
||||
// actually, it checkl if v1 is serialized correctly under FR locale
|
||||
// where 3.1415 -> 3,1415
|
||||
CHECK_EQ(v1, v2);
|
||||
}
|
||||
Reference in New Issue
Block a user