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)
This commit is contained in:
ToruNiina 2018-12-02 20:52:04 +09:00
parent 4791088106
commit c38b9b7dc7

136
toml/region.hpp Normal file
View File

@ -0,0 +1,136 @@
#ifndef TOML11_REGION_H
#define TOML11_REGION_H
#include <memory>
#include <algorithm>
#include <iterator>
#include <string>
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<typename Container>
struct location
{
using const_iterator = typename Container::const_iterator;
location(Container cont)
: source(std::make_shared<Container>(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<Container> 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<typename Container>
struct region
{
using const_iterator = typename Container::const_iterator;
region(const location<Container>& loc)
: first(loc.iter), last(loc.iter), source(loc.source)
{}
region(location<Container>&& 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<Container> source;
};
// to show a better error message.
template<typename Container>
std::string
format_underline(const region<Container>& reg, const std::string& msg)
{
using const_iterator = typename region<Container>::const_iterator;
using reverse_iterator = std::reverse_iterator<const_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<typename Container>
std::string format_underline(const region<Container>& reg,
typename Container::const_iterator pos,
const std::string& msg)
{
using const_iterator = typename region<Container>::const_iterator;
using reverse_iterator = std::reverse_iterator<const_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