diff --git a/toml/exception.hpp b/toml/exception.hpp index 1a3cd0c..08541b0 100644 --- a/toml/exception.hpp +++ b/toml/exception.hpp @@ -2,6 +2,7 @@ // Distributed under the MIT License. #ifndef TOML11_EXCEPTION_HPP #define TOML11_EXCEPTION_HPP +#include "source_location.hpp" #include #include @@ -18,32 +19,41 @@ struct exception : public std::exception struct syntax_error : public toml::exception { public: - explicit syntax_error(const std::string& what_arg) : what_(what_arg){} - explicit syntax_error(const char* what_arg) : what_(what_arg){} + explicit syntax_error(const std::string& what_arg, const source_location& loc) + : what_(what_arg), loc_(loc) + {} 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) : what_(what_arg){} - explicit type_error(const char* what_arg) : what_(what_arg){} + explicit type_error(const std::string& what_arg, const source_location& loc) + : what_(what_arg), loc_(loc) + {} 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 char* what_arg) : what_(what_arg){} + explicit internal_error(const std::string& what_arg) + : what_(what_arg) + {} virtual ~internal_error() noexcept override = default; virtual const char* what() const noexcept override {return what_.c_str();} protected: diff --git a/toml/get.hpp b/toml/get.hpp index 7445ff0..2973e35 100644 --- a/toml/get.hpp +++ b/toml/get.hpp @@ -190,7 +190,7 @@ get(const basic_value& v) "bad_cast to std::chrono::system_clock::time_point", { {std::addressof(detail::get_region(v)), concat_to_string("the actual type is ", v.type())} - })); + }), v.location()); } } } diff --git a/toml/literal.hpp b/toml/literal.hpp index 783d309..14b6883 100644 --- a/toml/literal.hpp +++ b/toml/literal.hpp @@ -76,7 +76,8 @@ inline ::toml::value operator"" _toml(const char* str, std::size_t len) } else // none of them. { - throw ::toml::syntax_error(data.unwrap_err()); + throw ::toml::syntax_error(data.unwrap_err(), + source_location(std::addressof(loc))); } } diff --git a/toml/parser.hpp b/toml/parser.hpp index 2805d80..6d89866 100644 --- a/toml/parser.hpp +++ b/toml/parser.hpp @@ -278,7 +278,7 @@ std::string read_utf8_codepoint(const region& reg, "toml::read_utf8_codepoint: codepoints in the range " "[0xD800, 0xDFFF] are not valid UTF-8.", {{ std::addressof(loc), "not a valid UTF-8 codepoint" - }})); + }}), source_location(std::addressof(loc))); } assert(codepoint < 0xD800 || 0xDFFF < codepoint); // 1110yyyy 10yxxxxx 10xxxxxx @@ -298,7 +298,8 @@ std::string read_utf8_codepoint(const region& reg, { throw syntax_error(format_underline("[error] toml::read_utf8_codepoint:" " input codepoint is too large.", - {{std::addressof(loc), "should be in [0x00..0x10FFFF]"}})); + {{std::addressof(loc), "should be in [0x00..0x10FFFF]"}}), + source_location(std::addressof(loc))); } return character; } @@ -929,7 +930,7 @@ parse_array(location& loc) std::addressof(get_region(val.unwrap())), "value has different type, " + stringize(val.unwrap().type()) } - })); + }), source_location(std::addressof(loc))); } retval.push_back(std::move(val.unwrap())); } @@ -942,7 +943,7 @@ parse_array(location& loc) "value having invalid format appeared in an array", { {std::addressof(array_start_loc), "array starts here"}, {std::addressof(loc), "it is not a valid value."} - })); + }), source_location(std::addressof(loc))); } using lex_array_separator = sequence, character<','>>; @@ -965,14 +966,15 @@ parse_array(location& loc) " missing array separator `,` after a value", { {std::addressof(array_start_loc), "array starts here"}, {std::addressof(loc), "should be `,`"} - })); + }), source_location(std::addressof(loc))); } } } loc.reset(first); throw syntax_error(format_underline("[error] toml::parse_array: " "array did not closed by `]`", - {{std::addressof(loc), "should be closed"}})); + {{std::addressof(loc), "should be closed"}}), + source_location(std::addressof(loc))); } template @@ -1175,7 +1177,7 @@ insert_nested_key(typename Value::table_type& root, const Value& v, "table already defined"}, {std::addressof(get_region(v)), "this conflicts with the previous table"} - })); + }), v.location()); } else if(!(tab->at(k).is_array())) { @@ -1188,7 +1190,7 @@ insert_nested_key(typename Value::table_type& root, const Value& v, " value already exists")}, {std::addressof(get_region(v)), "while inserting this array-of-tables"} - })); + }), v.location()); } // the above if-else-if checks tab->at(k) is an array auto& a = tab->at(k).as_array(); @@ -1203,7 +1205,7 @@ insert_nested_key(typename Value::table_type& root, const Value& v, " value already exists")}, {std::addressof(get_region(v)), "while inserting this array-of-tables"} - })); + }), v.location()); } // avoid conflicting array of table like the following. // ```toml @@ -1231,7 +1233,7 @@ insert_nested_key(typename Value::table_type& root, const Value& v, " value has static size")}, {std::addressof(get_region(v)), "appending it to the statically sized array"} - })); + }), v.location()); } a.push_back(v); return ok(true); @@ -1259,7 +1261,7 @@ insert_nested_key(typename Value::table_type& root, const Value& v, "table already exists here"}, {std::addressof(get_region(v)), "table defined twice"} - })); + }), v.location()); } // to allow the following toml file. // [a.b.c] @@ -1286,7 +1288,7 @@ insert_nested_key(typename Value::table_type& root, const Value& v, "array of tables defined here"}, {std::addressof(get_region(v)), "table conflicts with the previous array of table"} - })); + }), v.location()); } else { @@ -1297,7 +1299,7 @@ insert_nested_key(typename Value::table_type& root, const Value& v, "value already exists here"}, {std::addressof(get_region(v)), "value defined twice"} - })); + }), v.location()); } } tab->insert(std::make_pair(k, v)); @@ -1333,7 +1335,7 @@ insert_nested_key(typename Value::table_type& root, const Value& v, {std::addressof(get_region(a.back())), concat_to_string("actual type is ", a.back().type())}, {std::addressof(get_region(v)), "inserting this"} - })); + }), v.location()); } tab = std::addressof(a.back().as_table()); } @@ -1346,7 +1348,7 @@ insert_nested_key(typename Value::table_type& root, const Value& v, {std::addressof(get_region(tab->at(k))), concat_to_string("actual type is ", tab->at(k).type())}, {std::addressof(get_region(v)), "inserting this"} - })); + }), v.location()); } } } @@ -1412,20 +1414,23 @@ parse_inline_table(location& loc) { throw syntax_error(format_underline("[error] " "toml::parse_inline_table: missing curly brace `}`", - {{std::addressof(loc), "should be `}`"}})); + {{std::addressof(loc), "should be `}`"}}), + source_location(std::addressof(loc))); } else { throw syntax_error(format_underline("[error] " "toml::parse_inline_table: missing table separator `,` ", - {{std::addressof(loc), "should be `,`"}})); + {{std::addressof(loc), "should be `,`"}}), + source_location(std::addressof(loc))); } } } loc.reset(first); throw syntax_error(format_underline("[error] toml::parse_inline_table: " "inline table did not closed by `}`", - {{std::addressof(loc), "should be closed"}})); + {{std::addressof(loc), "should be closed"}}), + source_location(std::addressof(loc))); } template @@ -1668,7 +1673,8 @@ parse_table_key(location& loc) { throw syntax_error(format_underline("[error] " "toml::parse_table_key: newline required after [table.key]", - {{std::addressof(loc), "expected newline"}})); + {{std::addressof(loc), "expected newline"}}), + source_location(std::addressof(loc))); } } return ok(std::make_pair(keys.unwrap().first, token.unwrap())); @@ -1722,7 +1728,8 @@ parse_array_table_key(location& loc) { throw syntax_error(format_underline("[error] toml::" "parse_array_table_key: newline required after [[table.key]]", - {{std::addressof(loc), "expected newline"}})); + {{std::addressof(loc), "expected newline"}}), + source_location(std::addressof(loc))); } } return ok(std::make_pair(keys.unwrap().first, token.unwrap())); @@ -1976,7 +1983,7 @@ parse(std::istream& is, const std::string& fname = "unknown file") const auto data = detail::parse_toml_file(loc); if(!data) { - throw syntax_error(data.unwrap_err()); + throw syntax_error(data.unwrap_err(), source_location(std::addressof(loc))); } return data.unwrap(); } diff --git a/toml/region.hpp b/toml/region.hpp index e5ed659..de6d04b 100644 --- a/toml/region.hpp +++ b/toml/region.hpp @@ -2,7 +2,6 @@ // Distributed under the MIT License. #ifndef TOML11_REGION_HPP #define TOML11_REGION_HPP -#include "exception.hpp" #include #include #include @@ -231,11 +230,10 @@ struct region final : public region_base region& operator+=(const region& other) { - if(this->begin() != other.begin() || this->end() != other.end() || - this->last_ != other.first_) - { - throw internal_error("invalid region concatenation"); - } + // different regions cannot be concatenated + assert(this->begin() == other.begin() && this->end() == other.end() && + this->last_ == other.first_); + this->last_ = other.last_; return *this; } diff --git a/toml/source_location.hpp b/toml/source_location.hpp index 051f4e5..f85c51e 100644 --- a/toml/source_location.hpp +++ b/toml/source_location.hpp @@ -48,7 +48,11 @@ struct source_location { if(reg) { - line_num_ = static_cast(std::stoul(reg->line_num())); + if(reg->line_num() != detail::region_base().line_num()) + { + line_num_ = static_cast( + std::stoul(reg->line_num())); + } column_num_ = static_cast(reg->before() + 1); region_size_ = static_cast(reg->size()); file_name_ = reg->name(); diff --git a/toml/value.hpp b/toml/value.hpp index cdb9506..e2f5cf8 100644 --- a/toml/value.hpp +++ b/toml/value.hpp @@ -35,7 +35,7 @@ throw_bad_cast(value_t actual, const ::toml::basic_value& v) "[error] toml::value bad_cast to ", Expected), { {std::addressof(get_region(v)), concat_to_string("the actual type is ", actual)} - })); + }), v.location()); } // switch by `value_t` and call the corresponding `value::as_xxx()`. {{{