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

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

View File

@ -68,6 +68,8 @@ int main()
- [TOML literal](#toml-literal)
- [Conversion between toml value and arbitrary types](#conversion-between-toml-value-and-arbitrary-types)
- [Formatting user-defined error messages](#formatting-user-defined-error-messages)
- [Obtaining location information](#obtaining-location-information)
- [Exceptions](#exceptions)
- [Serializing TOML data](#serializing-toml-data)
- [Underlying types](#underlying-types)
- [Unreleased TOML features](#unreleased-toml-features)
@ -351,6 +353,7 @@ The above code works with the following toml file.
# NOT {"physical": {"color": "orange"}}.
```
## Casting a toml value
### `toml::get`
@ -1258,7 +1261,7 @@ you will get an error message like this.
| ~~ maximum number here
```
### Obtaining location information
## Obtaining location information
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();
```
## 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
toml11 enables you to serialize data into toml format.

View File

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

View File

@ -31,7 +31,8 @@ parse_boolean(location<Container>& loc)
{
throw internal_error(format_underline(
"[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
@ -58,7 +59,8 @@ parse_binary_integer(location<Container>& loc)
{
throw internal_error(format_underline(
"[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()));
@ -378,7 +380,8 @@ parse_ml_basic_string(location<Container>& loc)
{
throw internal_error(format_underline("[error] "
"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)
/* 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] "
"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);
}
@ -433,7 +437,8 @@ parse_basic_string(location<Container>& loc)
if(!quot)
{
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;
@ -455,7 +460,8 @@ parse_basic_string(location<Container>& loc)
{
throw internal_error(format_underline("[error] "
"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);
}
@ -484,7 +490,8 @@ parse_ml_literal_string(location<Container>& loc)
{
throw internal_error(format_underline("[error] "
"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)
/* 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] "
"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(
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] "
"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);
@ -535,7 +544,8 @@ parse_literal_string(location<Container>& loc)
{
throw internal_error(format_underline("[error] "
"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(
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]: "
"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();
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]: "
"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();
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]: "
"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(
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]: "
"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();
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]: "
"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();
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]: "
"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(
from_string<int>(h.unwrap().str(), 0),
@ -695,7 +711,8 @@ parse_local_time(location<Container>& loc)
{
throw internal_error(format_underline("[error]: "
"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()));
@ -721,14 +738,16 @@ parse_local_datetime(location<Container>& loc)
{
throw internal_error(format_underline("[error]: "
"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());
if(delim != 'T' && delim != 't' && delim != ' ')
{
throw internal_error(format_underline("[error]: "
"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();
const auto time = parse_local_time(inner_loc);
@ -736,7 +755,8 @@ parse_local_datetime(location<Container>& loc)
{
throw internal_error(format_underline("[error]: "
"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(
local_datetime(date.unwrap().first, time.unwrap().first),
@ -763,7 +783,8 @@ parse_offset_datetime(location<Container>& loc)
{
throw internal_error(format_underline("[error]: "
"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);
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]: "
"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),
token.unwrap()));
@ -842,7 +864,8 @@ parse_key(location<Container>& loc)
{
throw internal_error(format_underline("[error] "
"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);
@ -858,7 +881,8 @@ parse_key(location<Container>& loc)
{
throw internal_error(format_underline("[error] toml::parse_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));
@ -1396,7 +1420,8 @@ parse_inline_table(location<Container>& loc)
if(!inserted)
{
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<','>>;
@ -1640,7 +1665,8 @@ parse_table_key(location<Container>& loc)
{
throw internal_error(format_underline("[error] "
"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 ]
// ^----------- this whitespace
@ -1650,7 +1676,8 @@ parse_table_key(location<Container>& loc)
{
throw internal_error(format_underline("[error] "
"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 ]
// ^-- this whitespace
@ -1660,7 +1687,8 @@ parse_table_key(location<Container>& loc)
{
throw internal_error(format_underline("[error] "
"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.
@ -1699,7 +1727,8 @@ parse_array_table_key(location<Container>& loc)
{
throw internal_error(format_underline("[error] "
"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);
const auto keys = parse_key(inner_loc);
@ -1707,7 +1736,8 @@ parse_array_table_key(location<Container>& loc)
{
throw internal_error(format_underline("[error] "
"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);
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] "
"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.