From c38b9b7dc7ad60fde51fb9fbe6dfcce172728264 Mon Sep 17 00:00:00 2001 From: ToruNiina Date: Sun, 2 Dec 2018 20:52:04 +0900 Subject: [PATCH] add region and location to represent tokens location is almost same as an Iterator, but having shared_ptr that points the content. region is almost same as a range. by adding pointer to the content source, utility function to show the error message can be implemented easier. it is expected that this also makes easy to show error messages after parse (e.g., in the case of bad_get) --- toml/region.hpp | 136 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 136 insertions(+) create mode 100644 toml/region.hpp diff --git a/toml/region.hpp b/toml/region.hpp new file mode 100644 index 0000000..e9ced53 --- /dev/null +++ b/toml/region.hpp @@ -0,0 +1,136 @@ +#ifndef TOML11_REGION_H +#define TOML11_REGION_H +#include +#include +#include +#include + +namespace toml +{ +namespace detail +{ + +// 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 +{ + using const_iterator = typename Container::const_iterator; + + location(Container cont) + : source(std::make_shared(std::move(cont))), + iter(source->begin()) + {} + location(const location&) = default; + location(location&&) = default; + location& operator=(const location&) = default; + location& operator=(location&&) = default; + ~location() = default; + + std::shared_ptr source; + const_iterator iter; +}; + +// region in a container, normally in a file content. +// shared_ptr points the resource that the iter points. +// combinators returns this. +// it can be used not only for resource handling, but also error message. +template +struct region +{ + using const_iterator = typename Container::const_iterator; + + region(const location& loc) + : first(loc.iter), last(loc.iter), source(loc.source) + {} + region(location&& loc) + : first(loc.iter), last(loc.iter), source(std::move(loc.source)) + {} + + region(const region&) = default; + region(region&&) = default; + region& operator=(const region&) = default; + region& operator=(region&&) = default; + ~region() = default; + + const_iterator first, last; + std::shared_ptr source; +}; + +// to show a better error message. +template +std::string +format_underline(const region& reg, const std::string& msg) +{ + using const_iterator = typename region::const_iterator; + using reverse_iterator = std::reverse_iterator; + const auto line_begin = std::find( + reverse_iterator(reg.first), + reverse_iterator(reg.source->cbegin()), + '\n').base(); + const auto line_end = std::find(reg.last, reg.source->cend(), '\n'); + + const auto line_number = std::to_string( + 1 + std::count(reg.source->cbegin(), reg.first, '\n')); + + std::string retval; + retval += ' '; + retval += line_number; + retval += " | "; + retval += std::string(line_begin, line_end); + retval += '\n'; + retval += std::string(line_number.size() + 1, ' '); + retval += " | "; + retval += std::string(std::distance(line_begin, reg.first), ' '); + retval += std::string(std::distance(reg.first, reg.last), '~'); + retval += ' '; + retval += msg; + return retval; +} + +// to show a better error message. +template +std::string format_underline(const region& reg, + typename Container::const_iterator pos, + const std::string& msg) +{ + using const_iterator = typename region::const_iterator; + using reverse_iterator = std::reverse_iterator; + const auto line_begin = std::find( + reverse_iterator(reg.first), + reverse_iterator(reg.source->cbegin()), + '\n').base(); + const auto line_end = std::find(reg.last, reg.source->cend(), '\n'); + + const auto line_number = std::to_string( + 1 + std::count(reg.source->cbegin(), reg.first, '\n')); + + std::string retval; + retval += ' '; + retval += line_number; + retval += " | "; + retval += std::string(line_begin, line_end); + retval += '\n'; + retval += std::string(line_number.size() + 1, ' '); + retval += " | "; + retval += std::string(std::distance(line_begin, reg.first), ' '); + + if(std::distance(reg.first, std::prev(pos)) > 0) + { + retval += std::string(std::distance(reg.first, std::prev(pos)), '-'); + } + retval += '^'; + if(std::distance(pos, reg.last) > 0) + { + retval += std::string(std::distance(std::next(pos), reg.last), '-'); + } + + retval += ' '; + retval += msg; + return retval; +} + +} // detail +} // toml +#endif// TOML11_REGION_H