Compare commits

...

22 Commits

Author SHA1 Message Date
ToruNiina
0df1dd6fea refactor: remove extraneous whitespaces 2024-07-04 02:57:22 +09:00
ToruNiina
a9fb557d70 feat: add error_kind to error_infos 2024-07-04 02:56:52 +09:00
ToruNiina
746abd73db feat: enable to get error_kind from error_info
and add serialization_error for future update
2024-07-04 02:55:47 +09:00
ToruNiina
7a6cb02293 feat: add error_kind to distinguish error_info 2024-07-04 00:57:50 +09:00
ToruNiina
00d6124f59 Merge branch 'v4_1_0' into try-get 2024-07-03 01:59:52 +09:00
ToruNiina
3a14cb5083 Merge branch 'main' into v4_1_0 2024-07-03 01:59:11 +09:00
ToruNiina
edbea2f483 Merge branch 'add-test-case' 2024-07-03 01:58:17 +09:00
ToruNiina
973ecee32d fix: add missing include file 2024-07-03 00:24:45 +09:00
ToruNiina
b9b2ee02ff feat [skip ci]: update single_include 2024-07-02 15:23:57 +00:00
ToruNiina
d77caa94d0 chore: Merge 'fix-make-error-info' 2024-07-03 00:22:55 +09:00
ToruNiina
65e722da43 test: add minimum cases of serializer 2024-07-03 00:00:50 +09:00
ToruNiina
37d0391b9d test: add test to make error_info
check if it compiles
2024-07-02 23:35:16 +09:00
ToruNiina
d4742334ce fix: add detail::make_error_info_rec overload
that converts basic_value to location
2024-07-02 23:34:49 +09:00
ToruNiina
ccd941dc5b fix: remove default arg from fwd decl 2024-07-02 00:03:10 +09:00
ToruNiina
fc493afb4e chore: update version 4.0.2 2024-06-30 23:59:23 +09:00
ToruNiina
1d3abc9718 ci: remove verbose message from ci build 2024-06-30 17:40:40 +09:00
ToruNiina
9f59c591f0 feat [skip ci]: update single_include 2024-06-29 15:56:19 +00:00
ToruNiina
de092e5457 fix: cast fsize to avoid sign-conv 2024-06-30 00:55:45 +09:00
ToruNiina
bcd8a6d1e4 doc: update notice about open mode
in overload of toml::parse that takes file stream or FILE* itself
2024-06-30 00:47:44 +09:00
ToruNiina
5b0ea5e95c fix #249: make sure all the file content is read 2024-06-30 00:29:34 +09:00
ToruNiina
d00c0c1b15 doc: explain a macro to link pre-built lib 2024-06-28 23:52:58 +09:00
ToruNiina
5d23f4b8a8 feat [skip ci]: update single_include 2024-06-27 15:08:22 +00:00
20 changed files with 585 additions and 197 deletions

View File

@@ -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/

View File

@@ -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`.

View File

@@ -5,7 +5,7 @@
[![License](https://img.shields.io/github/license/ToruNiina/toml11.svg?style=flat)](LICENSE)
[![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.1209136.svg)](https://doi.org/10.5281/zenodo.1209136)
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/`をコンパイルできます。

View File

@@ -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.

View File

@@ -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.

View File

@@ -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.

View File

@@ -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`が報告されます。

View File

@@ -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`によって必要なバージョンを設定してコンパイルしてください。

View File

@@ -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`が返されます。

View File

@@ -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) ... );
}

View File

@@ -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())

View File

@@ -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"));

View File

@@ -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"));
}

View File

@@ -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());
}

View File

@@ -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"

View File

@@ -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;

View File

@@ -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())

View File

@@ -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

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