From 944b83642a614debdf52196a36f261cfdd9fcdb7 Mon Sep 17 00:00:00 2001 From: ToruNiina Date: Sat, 2 Mar 2019 17:52:00 +0900 Subject: [PATCH] feat: make location to inherit region_base To generate error message, it is better to have the same interface. Also, location can be considered as a region having only one character. --- toml/region.hpp | 259 +++++++++++++++++++++++++++++++++--------------- 1 file changed, 178 insertions(+), 81 deletions(-) diff --git a/toml/region.hpp b/toml/region.hpp index 7a0acba..62a28e1 100644 --- a/toml/region.hpp +++ b/toml/region.hpp @@ -28,44 +28,6 @@ inline std::string make_string(std::size_t len, char c) return std::string(len, c); } -// location in a container, normally in a file content. -// shared_ptr points the resource that the iter points. -// it can be used not only for resource handling, but also error message. -template -struct location -{ - static_assert(std::is_same::value,""); - using const_iterator = typename Container::const_iterator; - using source_ptr = std::shared_ptr; - - location(std::string name, Container cont) - : source_(std::make_shared(std::move(cont))), - source_name_(std::move(name)), iter_(source_->cbegin()) - {} - location(const location&) = default; - location(location&&) = default; - location& operator=(const location&) = default; - location& operator=(location&&) = default; - ~location() = default; - - const_iterator& iter() noexcept {return iter_;} - const_iterator iter() const noexcept {return iter_;} - - const_iterator begin() const noexcept {return source_->cbegin();} - const_iterator end() const noexcept {return source_->cend();} - - source_ptr const& source() const& noexcept {return source_;} - source_ptr&& source() && noexcept {return std::move(source_);} - - std::string const& name() const noexcept {return source_name_;} - - private: - - source_ptr source_; - std::string source_name_; - const_iterator iter_; -}; - // region in a container, normally in a file content. // shared_ptr points the resource that the iter points. // combinators returns this. @@ -86,12 +48,89 @@ struct region_base virtual std::string line() const {return std::string("unknown line");} virtual std::string line_num() const {return std::string("?");} - virtual std::size_t before() const noexcept {return 0;} virtual std::size_t size() const noexcept {return 0;} virtual std::size_t after() const noexcept {return 0;} }; +// location in a container, normally in a file content. +// shared_ptr points the resource that the iter points. +// it can be used not only for resource handling, but also error message. +// +// it can be considered as a region that contains only one character. +template +struct location final : public region_base +{ + static_assert(std::is_same::value,""); + using const_iterator = typename Container::const_iterator; + using source_ptr = std::shared_ptr; + + location(std::string name, Container cont) + : source_(std::make_shared(std::move(cont))), + source_name_(std::move(name)), iter_(source_->cbegin()) + {} + location(const location&) = default; + location(location&&) = default; + location& operator=(const location&) = default; + location& operator=(location&&) = default; + ~location() = default; + + bool is_ok() const noexcept override {return static_cast(source_);} + + const_iterator& iter() noexcept {return iter_;} + const_iterator iter() const noexcept {return iter_;} + + const_iterator begin() const noexcept {return source_->cbegin();} + const_iterator end() const noexcept {return source_->cend();} + + std::string str() const override {return make_string(1, *this->iter());} + std::string name() const override {return source_name_;} + + std::string line_num() const override + { + return std::to_string(1+std::count(this->begin(), this->iter(), '\n')); + } + + std::string line() const override + { + return make_string(this->line_begin(), this->line_end()); + } + + const_iterator line_begin() const noexcept + { + using reverse_iterator = std::reverse_iterator; + return std::find(reverse_iterator(this->iter()), + reverse_iterator(this->begin()), '\n').base(); + } + const_iterator line_end() const noexcept + { + return std::find(this->iter(), this->end(), '\n'); + } + + // location is always points a character. so the size is 1. + std::size_t size() const noexcept override + { + return 1u; + } + std::size_t before() const noexcept override + { + return std::distance(this->line_begin(), this->iter()); + } + std::size_t after() const noexcept override + { + return std::distance(this->iter(), this->line_end()); + } + + source_ptr const& source() const& noexcept {return source_;} + source_ptr&& source() && noexcept {return std::move(source_);} + + private: + + source_ptr source_; + std::string source_name_; + const_iterator iter_; +}; + template struct region final : public region_base { @@ -225,7 +264,19 @@ inline std::string format_underline(const std::string& message, retval += make_string(line_number.size() + 1, ' '); retval += " | "; retval += make_string(reg.before(), ' '); - retval += make_string(reg.size(), '~'); + if(reg.size() == 1) + { + // invalid + // ^------ + retval += '^'; + retval += make_string(reg.after(), '-'); + } + else + { + // invalid + // ~~~~~~~ + retval += make_string(reg.size(), '~'); + } retval += ' '; retval += comment_for_underline; if(helps.size() != 0) @@ -270,7 +321,19 @@ inline std::string format_underline(const std::string& message, retval << make_string(line_num_width + 1, ' '); retval << " | "; retval << make_string(reg1.before(), ' '); - retval << make_string(reg1.size(), '~'); + if(reg1.size() == 1) + { + // invalid + // ^------ + retval << '^'; + retval << make_string(reg1.after(), '-'); + } + else + { + // invalid + // ~~~~~~~ + retval << make_string(reg1.size(), '~'); + } retval << ' '; retval << comment_for_underline1 << newline; // --------------------------------------- @@ -287,7 +350,19 @@ inline std::string format_underline(const std::string& message, retval << make_string(line_num_width + 1, ' '); retval << " | "; retval << make_string(reg2.before(), ' '); - retval << make_string(reg2.size(), '~'); + if(reg2.size() == 1) + { + // invalid + // ^------ + retval << '^'; + retval << make_string(reg2.after(), '-'); + } + else + { + // invalid + // ~~~~~~~ + retval << make_string(reg2.size(), '~'); + } retval << ' '; retval << comment_for_underline2; if(helps.size() != 0) @@ -305,62 +380,84 @@ inline std::string format_underline(const std::string& message, return retval.str(); } - // to show a better error message. -template -std::string -format_underline(const std::string& message, const location& loc, - const std::string& comment_for_underline, - std::vector helps = {}) +inline std::string format_underline(const std::string& message, + std::vector> reg_com, + std::vector helps = {}) { + assert(!reg_com.empty()); + #ifdef _WIN32 const auto newline = "\r\n"; #else const char newline = '\n'; #endif - using const_iterator = typename location::const_iterator; - using reverse_iterator = std::reverse_iterator; - const auto line_begin = std::find(reverse_iterator(loc.iter()), - reverse_iterator(loc.begin()), - '\n').base(); - const auto line_end = std::find(loc.iter(), loc.end(), '\n'); - const auto line_number = std::to_string( - 1 + std::count(loc.begin(), loc.iter(), '\n')); + const auto line_num_width = std::max_element(reg_com.begin(), reg_com.end(), + [](std::pair const& lhs, + std::pair const& rhs) + { + return lhs.first->line_num().size() < rhs.first->line_num().size(); + } + )->first->line_num().size(); + + std::ostringstream retval; + retval << message << newline; + + for(std::size_t i=0; iname() == reg_com.at(i).first->name()) + { + retval << " ..." << newline; + } + else + { + retval << " --> " << reg_com.at(i).first->name() << newline; + } + + const region_base* const reg = reg_com.at(i).first; + const std::string& comment = reg_com.at(i).second; + + + retval << ' ' << std::setw(line_num_width) << reg->line_num(); + retval << " | " << reg->line() << newline; + retval << make_string(line_num_width + 1, ' '); + retval << " | " << make_string(reg->before(), ' '); + + if(reg->size() == 1) + { + // invalid + // ^------ + retval << '^'; + retval << make_string(reg->after(), '-'); + } + else + { + // invalid + // ~~~~~~~ + retval << make_string(reg->size(), '~'); + } + + retval << ' '; + retval << comment << newline; + } - std::string retval; - retval += message; - retval += newline; - retval += " --> "; - retval += loc.name(); - retval += newline; - retval += ' '; - retval += line_number; - retval += " | "; - retval += make_string(line_begin, line_end); - retval += newline; - retval += make_string(line_number.size() + 1, ' '); - retval += " | "; - retval += make_string(std::distance(line_begin, loc.iter()),' '); - retval += '^'; - retval += make_string(std::distance(loc.iter(), line_end), '-'); - retval += ' '; - retval += comment_for_underline; if(helps.size() != 0) { - retval += newline; - retval += make_string(line_number.size() + 1, ' '); - retval += " | "; + retval << newline; + retval << make_string(line_num_width + 1, ' '); + retval << " | "; for(const auto help : helps) { - retval += newline; - retval += "Hint: "; - retval += help; + retval << newline; + retval << "Hint: "; + retval << help; } } - return retval; + return retval.str(); } + } // detail } // toml #endif// TOML11_REGION_H