Merge branch 'add-src-loc-to-exception' #87

This commit is contained in:
ToruNiina
2019-11-02 13:42:14 +09:00
3 changed files with 105 additions and 42 deletions

View File

@@ -68,6 +68,8 @@ int main()
- [TOML literal](#toml-literal) - [TOML literal](#toml-literal)
- [Conversion between toml value and arbitrary types](#conversion-between-toml-value-and-arbitrary-types) - [Conversion between toml value and arbitrary types](#conversion-between-toml-value-and-arbitrary-types)
- [Formatting user-defined error messages](#formatting-user-defined-error-messages) - [Formatting user-defined error messages](#formatting-user-defined-error-messages)
- [Obtaining location information](#obtaining-location-information)
- [Exceptions](#exceptions)
- [Serializing TOML data](#serializing-toml-data) - [Serializing TOML data](#serializing-toml-data)
- [Underlying types](#underlying-types) - [Underlying types](#underlying-types)
- [Unreleased TOML features](#unreleased-toml-features) - [Unreleased TOML features](#unreleased-toml-features)
@@ -351,6 +353,7 @@ The above code works with the following toml file.
# NOT {"physical": {"color": "orange"}}. # NOT {"physical": {"color": "orange"}}.
``` ```
## Casting a toml value ## Casting a toml value
### `toml::get` ### `toml::get`
@@ -1258,7 +1261,7 @@ you will get an error message like this.
| ~~ maximum number here | ~~ maximum number here
``` ```
### Obtaining location information ## Obtaining location information
You can also format error messages in your own way by using `source_location`. You can also format error messages in your own way by using `source_location`.
@@ -1283,6 +1286,35 @@ const toml::value v = /*...*/;
const toml::source_location loc = v.location(); const toml::source_location loc = v.location();
``` ```
## Exceptions
All the exceptions thrown by toml11 inherits `toml::exception` that inherits
`std::exception`.
```cpp
namespace toml {
struct exception : public std::exception {/**/};
struct syntax_error : public toml::exception {/**/};
struct type_error : public toml::exception {/**/};
struct internal_error : public toml::exception {/**/};
} // toml
```
`toml::exception` has `toml::exception::location()` member function that returns
`toml::source_location`, in addition to `what()`.
```cpp
namespace toml {
struct exception : public std::exception
{
// ...
source_location const& location() const noexcept;
};
} // toml
```
It represents where the error occurs.
## Serializing TOML data ## Serializing TOML data
toml11 enables you to serialize data into toml format. toml11 enables you to serialize data into toml format.

View File

@@ -12,50 +12,50 @@ namespace toml
struct exception : public std::exception struct exception : public std::exception
{ {
public: public:
exception(const source_location& loc): loc_(loc) {}
virtual ~exception() noexcept override = default; virtual ~exception() noexcept override = default;
virtual const char* what() const noexcept override {return "";} virtual const char* what() const noexcept override {return "";}
virtual source_location const& location() const noexcept {return loc_;}
protected:
source_location loc_;
}; };
struct syntax_error : public toml::exception struct syntax_error : public toml::exception
{ {
public: public:
explicit syntax_error(const std::string& what_arg, const source_location& loc) explicit syntax_error(const std::string& what_arg, const source_location& loc)
: what_(what_arg), loc_(loc) : exception(loc), what_(what_arg)
{} {}
virtual ~syntax_error() noexcept override = default; virtual ~syntax_error() noexcept override = default;
virtual const char* what() const noexcept override {return what_.c_str();} virtual const char* what() const noexcept override {return what_.c_str();}
source_location const& location() const noexcept {return loc_;}
protected: protected:
std::string what_; std::string what_;
source_location loc_;
}; };
struct type_error : public toml::exception struct type_error : public toml::exception
{ {
public: public:
explicit type_error(const std::string& what_arg, const source_location& loc) explicit type_error(const std::string& what_arg, const source_location& loc)
: what_(what_arg), loc_(loc) : exception(loc), what_(what_arg)
{} {}
virtual ~type_error() noexcept override = default; virtual ~type_error() noexcept override = default;
virtual const char* what() const noexcept override {return what_.c_str();} virtual const char* what() const noexcept override {return what_.c_str();}
source_location const& location() const noexcept {return loc_;}
protected: protected:
std::string what_; std::string what_;
source_location loc_;
}; };
struct internal_error : public toml::exception struct internal_error : public toml::exception
{ {
public: public:
explicit internal_error(const std::string& what_arg) explicit internal_error(const std::string& what_arg, const source_location& loc)
: what_(what_arg) : exception(loc), what_(what_arg)
{} {}
virtual ~internal_error() noexcept override = default; virtual ~internal_error() noexcept override = default;
virtual const char* what() const noexcept override {return what_.c_str();} virtual const char* what() const noexcept override {return what_.c_str();}
protected: protected:
std::string what_; std::string what_;
}; };

View File

@@ -31,7 +31,8 @@ parse_boolean(location<Container>& loc)
{ {
throw internal_error(format_underline( throw internal_error(format_underline(
"[error] toml::parse_boolean: internal error", "[error] toml::parse_boolean: internal error",
{{std::addressof(reg), "invalid token"}})); {{std::addressof(reg), "invalid token"}}),
source_location(std::addressof(reg)));
} }
} }
loc.reset(first); //rollback loc.reset(first); //rollback
@@ -58,7 +59,8 @@ parse_binary_integer(location<Container>& loc)
{ {
throw internal_error(format_underline( throw internal_error(format_underline(
"[error] toml::parse_integer: internal error", "[error] toml::parse_integer: internal error",
{{std::addressof(token.unwrap()), "invalid token"}})); {{std::addressof(token.unwrap()), "invalid token"}}),
source_location(std::addressof(loc)));
} }
} }
return ok(std::make_pair(retval, token.unwrap())); return ok(std::make_pair(retval, token.unwrap()));
@@ -378,7 +380,8 @@ parse_ml_basic_string(location<Container>& loc)
{ {
throw internal_error(format_underline("[error] " throw internal_error(format_underline("[error] "
"parse_ml_basic_string: invalid token", "parse_ml_basic_string: invalid token",
{{std::addressof(inner_loc), "should be \"\"\""}})); {{std::addressof(inner_loc), "should be \"\"\""}}),
source_location(std::addressof(inner_loc)));
} }
// immediate newline is ignored (if exists) // immediate newline is ignored (if exists)
/* discard return value */ lex_newline::invoke(inner_loc); /* discard return value */ lex_newline::invoke(inner_loc);
@@ -404,7 +407,8 @@ parse_ml_basic_string(location<Container>& loc)
{ {
throw internal_error(format_underline("[error] " throw internal_error(format_underline("[error] "
"parse_ml_basic_string: unexpected end of region", "parse_ml_basic_string: unexpected end of region",
{{std::addressof(inner_loc), "not sufficient token"}})); {{std::addressof(inner_loc), "not sufficient token"}}),
source_location(std::addressof(inner_loc)));
} }
delim = lex_ml_basic_string_delim::invoke(inner_loc); delim = lex_ml_basic_string_delim::invoke(inner_loc);
} }
@@ -433,7 +437,8 @@ parse_basic_string(location<Container>& loc)
if(!quot) if(!quot)
{ {
throw internal_error(format_underline("[error] parse_basic_string: " throw internal_error(format_underline("[error] parse_basic_string: "
"invalid token", {{std::addressof(inner_loc), "should be \""}})); "invalid token", {{std::addressof(inner_loc), "should be \""}}),
source_location(std::addressof(inner_loc)));
} }
std::string retval; std::string retval;
@@ -455,7 +460,8 @@ parse_basic_string(location<Container>& loc)
{ {
throw internal_error(format_underline("[error] " throw internal_error(format_underline("[error] "
"parse_basic_string: unexpected end of region", "parse_basic_string: unexpected end of region",
{{std::addressof(inner_loc), "not sufficient token"}})); {{std::addressof(inner_loc), "not sufficient token"}}),
source_location(std::addressof(inner_loc)));
} }
quot = lex_quotation_mark::invoke(inner_loc); quot = lex_quotation_mark::invoke(inner_loc);
} }
@@ -484,7 +490,8 @@ parse_ml_literal_string(location<Container>& loc)
{ {
throw internal_error(format_underline("[error] " throw internal_error(format_underline("[error] "
"parse_ml_literal_string: invalid token", "parse_ml_literal_string: invalid token",
{{std::addressof(inner_loc), "should be '''"}})); {{std::addressof(inner_loc), "should be '''"}}),
source_location(std::addressof(inner_loc)));
} }
// immediate newline is ignored (if exists) // immediate newline is ignored (if exists)
/* discard return value */ lex_newline::invoke(inner_loc); /* discard return value */ lex_newline::invoke(inner_loc);
@@ -496,7 +503,8 @@ parse_ml_literal_string(location<Container>& loc)
{ {
throw internal_error(format_underline("[error] " throw internal_error(format_underline("[error] "
"parse_ml_literal_string: invalid token", "parse_ml_literal_string: invalid token",
{{std::addressof(inner_loc), "should be '''"}})); {{std::addressof(inner_loc), "should be '''"}}),
source_location(std::addressof(inner_loc)));
} }
return ok(std::make_pair( return ok(std::make_pair(
toml::string(body.unwrap().str(), toml::string_t::literal), toml::string(body.unwrap().str(), toml::string_t::literal),
@@ -525,7 +533,8 @@ parse_literal_string(location<Container>& loc)
{ {
throw internal_error(format_underline("[error] " throw internal_error(format_underline("[error] "
"parse_literal_string: invalid token", "parse_literal_string: invalid token",
{{std::addressof(inner_loc), "should be '"}})); {{std::addressof(inner_loc), "should be '"}}),
source_location(std::addressof(inner_loc)));
} }
const auto body = repeat<lex_literal_char, unlimited>::invoke(inner_loc); const auto body = repeat<lex_literal_char, unlimited>::invoke(inner_loc);
@@ -535,7 +544,8 @@ parse_literal_string(location<Container>& loc)
{ {
throw internal_error(format_underline("[error] " throw internal_error(format_underline("[error] "
"parse_literal_string: invalid token", "parse_literal_string: invalid token",
{{std::addressof(inner_loc), "should be '"}})); {{std::addressof(inner_loc), "should be '"}}),
source_location(std::addressof(inner_loc)));
} }
return ok(std::make_pair( return ok(std::make_pair(
toml::string(body.unwrap().str(), toml::string_t::literal), toml::string(body.unwrap().str(), toml::string_t::literal),
@@ -596,7 +606,8 @@ parse_local_date(location<Container>& loc)
{ {
throw internal_error(format_underline("[error]: " throw internal_error(format_underline("[error]: "
"toml::parse_inner_local_date: invalid year format", "toml::parse_inner_local_date: invalid year format",
{{std::addressof(inner_loc), "should be `-`"}})); {{std::addressof(inner_loc), "should be `-`"}}),
source_location(std::addressof(inner_loc)));
} }
inner_loc.advance(); inner_loc.advance();
const auto m = lex_date_month::invoke(inner_loc); const auto m = lex_date_month::invoke(inner_loc);
@@ -604,7 +615,8 @@ parse_local_date(location<Container>& loc)
{ {
throw internal_error(format_underline("[error]: " throw internal_error(format_underline("[error]: "
"toml::parse_local_date: invalid month format", "toml::parse_local_date: invalid month format",
{{std::addressof(inner_loc), "should be `-`"}})); {{std::addressof(inner_loc), "should be `-`"}}),
source_location(std::addressof(inner_loc)));
} }
inner_loc.advance(); inner_loc.advance();
const auto d = lex_date_mday::invoke(inner_loc); const auto d = lex_date_mday::invoke(inner_loc);
@@ -612,7 +624,8 @@ parse_local_date(location<Container>& loc)
{ {
throw internal_error(format_underline("[error]: " throw internal_error(format_underline("[error]: "
"toml::parse_local_date: invalid day format", "toml::parse_local_date: invalid day format",
{{std::addressof(inner_loc), "here"}})); {{std::addressof(inner_loc), "here"}}),
source_location(std::addressof(inner_loc)));
} }
return ok(std::make_pair(local_date( return ok(std::make_pair(local_date(
static_cast<std::int16_t>(from_string<int>(y.unwrap().str(), 0)), static_cast<std::int16_t>(from_string<int>(y.unwrap().str(), 0)),
@@ -643,7 +656,8 @@ parse_local_time(location<Container>& loc)
{ {
throw internal_error(format_underline("[error]: " throw internal_error(format_underline("[error]: "
"toml::parse_local_time: invalid year format", "toml::parse_local_time: invalid year format",
{{std::addressof(inner_loc), "should be `:`"}})); {{std::addressof(inner_loc), "should be `:`"}}),
source_location(std::addressof(inner_loc)));
} }
inner_loc.advance(); inner_loc.advance();
const auto m = lex_time_minute::invoke(inner_loc); const auto m = lex_time_minute::invoke(inner_loc);
@@ -651,7 +665,8 @@ parse_local_time(location<Container>& loc)
{ {
throw internal_error(format_underline("[error]: " throw internal_error(format_underline("[error]: "
"toml::parse_local_time: invalid month format", "toml::parse_local_time: invalid month format",
{{std::addressof(inner_loc), "should be `:`"}})); {{std::addressof(inner_loc), "should be `:`"}}),
source_location(std::addressof(inner_loc)));
} }
inner_loc.advance(); inner_loc.advance();
const auto s = lex_time_second::invoke(inner_loc); const auto s = lex_time_second::invoke(inner_loc);
@@ -659,7 +674,8 @@ parse_local_time(location<Container>& loc)
{ {
throw internal_error(format_underline("[error]: " throw internal_error(format_underline("[error]: "
"toml::parse_local_time: invalid second format", "toml::parse_local_time: invalid second format",
{{std::addressof(inner_loc), "here"}})); {{std::addressof(inner_loc), "here"}}),
source_location(std::addressof(inner_loc)));
} }
local_time time( local_time time(
from_string<int>(h.unwrap().str(), 0), from_string<int>(h.unwrap().str(), 0),
@@ -695,7 +711,8 @@ parse_local_time(location<Container>& loc)
{ {
throw internal_error(format_underline("[error]: " throw internal_error(format_underline("[error]: "
"toml::parse_local_time: invalid subsecond format", "toml::parse_local_time: invalid subsecond format",
{{std::addressof(inner_loc), "here"}})); {{std::addressof(inner_loc), "here"}}),
source_location(std::addressof(inner_loc)));
} }
} }
return ok(std::make_pair(time, token.unwrap())); return ok(std::make_pair(time, token.unwrap()));
@@ -721,14 +738,16 @@ parse_local_datetime(location<Container>& loc)
{ {
throw internal_error(format_underline("[error]: " throw internal_error(format_underline("[error]: "
"toml::parse_local_datetime: invalid datetime format", "toml::parse_local_datetime: invalid datetime format",
{{std::addressof(inner_loc), "date, not datetime"}})); {{std::addressof(inner_loc), "date, not datetime"}}),
source_location(std::addressof(inner_loc)));
} }
const char delim = *(inner_loc.iter()); const char delim = *(inner_loc.iter());
if(delim != 'T' && delim != 't' && delim != ' ') if(delim != 'T' && delim != 't' && delim != ' ')
{ {
throw internal_error(format_underline("[error]: " throw internal_error(format_underline("[error]: "
"toml::parse_local_datetime: invalid datetime format", "toml::parse_local_datetime: invalid datetime format",
{{std::addressof(inner_loc), "should be `T` or ` ` (space)"}})); {{std::addressof(inner_loc), "should be `T` or ` ` (space)"}}),
source_location(std::addressof(inner_loc)));
} }
inner_loc.advance(); inner_loc.advance();
const auto time = parse_local_time(inner_loc); const auto time = parse_local_time(inner_loc);
@@ -736,7 +755,8 @@ parse_local_datetime(location<Container>& loc)
{ {
throw internal_error(format_underline("[error]: " throw internal_error(format_underline("[error]: "
"toml::parse_local_datetime: invalid datetime format", "toml::parse_local_datetime: invalid datetime format",
{{std::addressof(inner_loc), "invalid time fomrat"}})); {{std::addressof(inner_loc), "invalid time fomrat"}}),
source_location(std::addressof(inner_loc)));
} }
return ok(std::make_pair( return ok(std::make_pair(
local_datetime(date.unwrap().first, time.unwrap().first), local_datetime(date.unwrap().first, time.unwrap().first),
@@ -763,7 +783,8 @@ parse_offset_datetime(location<Container>& loc)
{ {
throw internal_error(format_underline("[error]: " throw internal_error(format_underline("[error]: "
"toml::parse_offset_datetime: invalid datetime format", "toml::parse_offset_datetime: invalid datetime format",
{{std::addressof(inner_loc), "date, not datetime"}})); {{std::addressof(inner_loc), "date, not datetime"}}),
source_location(std::addressof(inner_loc)));
} }
time_offset offset(0, 0); time_offset offset(0, 0);
if(const auto ofs = lex_time_numoffset::invoke(inner_loc)) if(const auto ofs = lex_time_numoffset::invoke(inner_loc))
@@ -784,7 +805,8 @@ parse_offset_datetime(location<Container>& loc)
{ {
throw internal_error(format_underline("[error]: " throw internal_error(format_underline("[error]: "
"toml::parse_offset_datetime: invalid datetime format", "toml::parse_offset_datetime: invalid datetime format",
{{std::addressof(inner_loc), "should be `Z` or `+HH:MM`"}})); {{std::addressof(inner_loc), "should be `Z` or `+HH:MM`"}}),
source_location(std::addressof(inner_loc)));
} }
return ok(std::make_pair(offset_datetime(datetime.unwrap().first, offset), return ok(std::make_pair(offset_datetime(datetime.unwrap().first, offset),
token.unwrap())); token.unwrap()));
@@ -842,7 +864,8 @@ parse_key(location<Container>& loc)
{ {
throw internal_error(format_underline("[error] " throw internal_error(format_underline("[error] "
"toml::detail::parse_key: dotted key contains invalid key", "toml::detail::parse_key: dotted key contains invalid key",
{{std::addressof(inner_loc), k.unwrap_err()}})); {{std::addressof(inner_loc), k.unwrap_err()}}),
source_location(std::addressof(inner_loc)));
} }
lex_ws::invoke(inner_loc); lex_ws::invoke(inner_loc);
@@ -858,7 +881,8 @@ parse_key(location<Container>& loc)
{ {
throw internal_error(format_underline("[error] toml::parse_key: " throw internal_error(format_underline("[error] toml::parse_key: "
"dotted key contains invalid key ", "dotted key contains invalid key ",
{{std::addressof(inner_loc), "should be `.`"}})); {{std::addressof(inner_loc), "should be `.`"}}),
source_location(std::addressof(inner_loc)));
} }
} }
return ok(std::make_pair(keys, reg)); return ok(std::make_pair(keys, reg));
@@ -1396,7 +1420,8 @@ parse_inline_table(location<Container>& loc)
if(!inserted) if(!inserted)
{ {
throw internal_error("[error] toml::parse_inline_table: " throw internal_error("[error] toml::parse_inline_table: "
"failed to insert value into table: " + inserted.unwrap_err()); "failed to insert value into table: " + inserted.unwrap_err(),
source_location(std::addressof(loc)));
} }
using lex_table_separator = sequence<maybe<lex_ws>, character<','>>; using lex_table_separator = sequence<maybe<lex_ws>, character<','>>;
@@ -1640,7 +1665,8 @@ parse_table_key(location<Container>& loc)
{ {
throw internal_error(format_underline("[error] " throw internal_error(format_underline("[error] "
"toml::parse_table_key: no `[`", "toml::parse_table_key: no `[`",
{{std::addressof(inner_loc), "should be `[`"}})); {{std::addressof(inner_loc), "should be `[`"}}),
source_location(std::addressof(inner_loc)));
} }
// to skip [ a . b . c ] // to skip [ a . b . c ]
// ^----------- this whitespace // ^----------- this whitespace
@@ -1650,7 +1676,8 @@ parse_table_key(location<Container>& loc)
{ {
throw internal_error(format_underline("[error] " throw internal_error(format_underline("[error] "
"toml::parse_table_key: invalid key", "toml::parse_table_key: invalid key",
{{std::addressof(inner_loc), "not key"}})); {{std::addressof(inner_loc), "not key"}}),
source_location(std::addressof(inner_loc)));
} }
// to skip [ a . b . c ] // to skip [ a . b . c ]
// ^-- this whitespace // ^-- this whitespace
@@ -1660,7 +1687,8 @@ parse_table_key(location<Container>& loc)
{ {
throw internal_error(format_underline("[error] " throw internal_error(format_underline("[error] "
"toml::parse_table_key: no `]`", "toml::parse_table_key: no `]`",
{{std::addressof(inner_loc), "should be `]`"}})); {{std::addressof(inner_loc), "should be `]`"}}),
source_location(std::addressof(inner_loc)));
} }
// after [table.key], newline or EOF(empty table) requried. // after [table.key], newline or EOF(empty table) requried.
@@ -1699,7 +1727,8 @@ parse_array_table_key(location<Container>& loc)
{ {
throw internal_error(format_underline("[error] " throw internal_error(format_underline("[error] "
"toml::parse_array_table_key: no `[[`", "toml::parse_array_table_key: no `[[`",
{{std::addressof(inner_loc), "should be `[[`"}})); {{std::addressof(inner_loc), "should be `[[`"}}),
source_location(std::addressof(inner_loc)));
} }
lex_ws::invoke(inner_loc); lex_ws::invoke(inner_loc);
const auto keys = parse_key(inner_loc); const auto keys = parse_key(inner_loc);
@@ -1707,7 +1736,8 @@ parse_array_table_key(location<Container>& loc)
{ {
throw internal_error(format_underline("[error] " throw internal_error(format_underline("[error] "
"toml::parse_array_table_key: invalid key", "toml::parse_array_table_key: invalid key",
{{std::addressof(inner_loc), "not a key"}})); {{std::addressof(inner_loc), "not a key"}}),
source_location(std::addressof(inner_loc)));
} }
lex_ws::invoke(inner_loc); lex_ws::invoke(inner_loc);
const auto close = lex_array_table_close::invoke(inner_loc); const auto close = lex_array_table_close::invoke(inner_loc);
@@ -1715,7 +1745,8 @@ parse_array_table_key(location<Container>& loc)
{ {
throw internal_error(format_underline("[error] " throw internal_error(format_underline("[error] "
"toml::parse_table_key: no `]]`", "toml::parse_table_key: no `]]`",
{{std::addressof(inner_loc), "should be `]]`"}})); {{std::addressof(inner_loc), "should be `]]`"}}),
source_location(std::addressof(inner_loc)));
} }
// after [[table.key]], newline or EOF(empty table) requried. // after [[table.key]], newline or EOF(empty table) requried.