aboutsummaryrefslogtreecommitdiff
path: root/src/toml11/toml/source_location.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/toml11/toml/source_location.hpp')
-rw-r--r--src/toml11/toml/source_location.hpp233
1 files changed, 233 insertions, 0 deletions
diff --git a/src/toml11/toml/source_location.hpp b/src/toml11/toml/source_location.hpp
new file mode 100644
index 000000000..fa175b5b4
--- /dev/null
+++ b/src/toml11/toml/source_location.hpp
@@ -0,0 +1,233 @@
+// Copyright Toru Niina 2019.
+// Distributed under the MIT License.
+#ifndef TOML11_SOURCE_LOCATION_HPP
+#define TOML11_SOURCE_LOCATION_HPP
+#include <cstdint>
+#include <sstream>
+
+#include "region.hpp"
+
+namespace toml
+{
+
+// A struct to contain location in a toml file.
+// The interface imitates std::experimental::source_location,
+// but not completely the same.
+//
+// It would be constructed by toml::value. It can be used to generate
+// user-defined error messages.
+//
+// - std::uint_least32_t line() const noexcept
+// - returns the line number where the region is on.
+// - std::uint_least32_t column() const noexcept
+// - returns the column number where the region starts.
+// - std::uint_least32_t region() const noexcept
+// - returns the size of the region.
+//
+// +-- line() +-- region of interest (region() == 9)
+// v .---+---.
+// 12 | value = "foo bar"
+// ^
+// +-- column()
+//
+// - std::string const& file_name() const noexcept;
+// - name of the file.
+// - std::string const& line_str() const noexcept;
+// - the whole line that contains the region of interest.
+//
+struct source_location
+{
+ public:
+
+ source_location()
+ : line_num_(1), column_num_(1), region_size_(1),
+ file_name_("unknown file"), line_str_("")
+ {}
+
+ explicit source_location(const detail::region_base* reg)
+ : line_num_(1), column_num_(1), region_size_(1),
+ file_name_("unknown file"), line_str_("")
+ {
+ if(reg)
+ {
+ if(reg->line_num() != detail::region_base().line_num())
+ {
+ line_num_ = static_cast<std::uint_least32_t>(
+ std::stoul(reg->line_num()));
+ }
+ column_num_ = static_cast<std::uint_least32_t>(reg->before() + 1);
+ region_size_ = static_cast<std::uint_least32_t>(reg->size());
+ file_name_ = reg->name();
+ line_str_ = reg->line();
+ }
+ }
+
+ explicit source_location(const detail::region& reg)
+ : line_num_(static_cast<std::uint_least32_t>(std::stoul(reg.line_num()))),
+ column_num_(static_cast<std::uint_least32_t>(reg.before() + 1)),
+ region_size_(static_cast<std::uint_least32_t>(reg.size())),
+ file_name_(reg.name()),
+ line_str_ (reg.line())
+ {}
+ explicit source_location(const detail::location& loc)
+ : line_num_(static_cast<std::uint_least32_t>(std::stoul(loc.line_num()))),
+ column_num_(static_cast<std::uint_least32_t>(loc.before() + 1)),
+ region_size_(static_cast<std::uint_least32_t>(loc.size())),
+ file_name_(loc.name()),
+ line_str_ (loc.line())
+ {}
+
+ ~source_location() = default;
+ source_location(source_location const&) = default;
+ source_location(source_location &&) = default;
+ source_location& operator=(source_location const&) = default;
+ source_location& operator=(source_location &&) = default;
+
+ std::uint_least32_t line() const noexcept {return line_num_;}
+ std::uint_least32_t column() const noexcept {return column_num_;}
+ std::uint_least32_t region() const noexcept {return region_size_;}
+
+ std::string const& file_name() const noexcept {return file_name_;}
+ std::string const& line_str() const noexcept {return line_str_;}
+
+ private:
+
+ std::uint_least32_t line_num_;
+ std::uint_least32_t column_num_;
+ std::uint_least32_t region_size_;
+ std::string file_name_;
+ std::string line_str_;
+};
+
+namespace detail
+{
+
+// internal error message generation.
+inline std::string format_underline(const std::string& message,
+ const std::vector<std::pair<source_location, std::string>>& loc_com,
+ const std::vector<std::string>& helps = {},
+ const bool colorize = TOML11_ERROR_MESSAGE_COLORIZED)
+{
+ std::size_t line_num_width = 0;
+ for(const auto& lc : loc_com)
+ {
+ std::uint_least32_t line = lc.first.line();
+ std::size_t digit = 0;
+ while(line != 0)
+ {
+ line /= 10;
+ digit += 1;
+ }
+ line_num_width = (std::max)(line_num_width, digit);
+ }
+ // 1 is the minimum width
+ line_num_width = std::max<std::size_t>(line_num_width, 1);
+
+ std::ostringstream retval;
+
+ if(colorize)
+ {
+ retval << color::colorize; // turn on ANSI color
+ }
+
+ // XXX
+ // Here, before `colorize` support, it does not output `[error]` prefix
+ // automatically. So some user may output it manually and this change may
+ // duplicate the prefix. To avoid it, check the first 7 characters and
+ // if it is "[error]", it removes that part from the message shown.
+ if(message.size() > 7 && message.substr(0, 7) == "[error]")
+ {
+ retval << color::bold << color::red << "[error]" << color::reset
+ << color::bold << message.substr(7) << color::reset << '\n';
+ }
+ else
+ {
+ retval << color::bold << color::red << "[error] " << color::reset
+ << color::bold << message << color::reset << '\n';
+ }
+
+ const auto format_one_location = [line_num_width]
+ (std::ostringstream& oss,
+ const source_location& loc, const std::string& comment) -> void
+ {
+ oss << ' ' << color::bold << color::blue
+ << std::setw(static_cast<int>(line_num_width))
+ << std::right << loc.line() << " | " << color::reset
+ << loc.line_str() << '\n';
+
+ oss << make_string(line_num_width + 1, ' ')
+ << color::bold << color::blue << " | " << color::reset
+ << make_string(loc.column()-1 /*1-origin*/, ' ');
+
+ if(loc.region() == 1)
+ {
+ // invalid
+ // ^------
+ oss << color::bold << color::red << "^---" << color::reset;
+ }
+ else
+ {
+ // invalid
+ // ~~~~~~~
+ const auto underline_len = (std::min)(
+ static_cast<std::size_t>(loc.region()), loc.line_str().size());
+ oss << color::bold << color::red
+ << make_string(underline_len, '~') << color::reset;
+ }
+ oss << ' ';
+ oss << comment;
+ return;
+ };
+
+ assert(!loc_com.empty());
+
+ // --> example.toml
+ // |
+ retval << color::bold << color::blue << " --> " << color::reset
+ << loc_com.front().first.file_name() << '\n';
+ retval << make_string(line_num_width + 1, ' ')
+ << color::bold << color::blue << " |\n" << color::reset;
+ // 1 | key value
+ // | ^--- missing =
+ format_one_location(retval, loc_com.front().first, loc_com.front().second);
+
+ // process the rest of the locations
+ for(std::size_t i=1; i<loc_com.size(); ++i)
+ {
+ const auto& prev = loc_com.at(i-1);
+ const auto& curr = loc_com.at(i);
+
+ retval << '\n';
+ // if the filenames are the same, print "..."
+ if(prev.first.file_name() == curr.first.file_name())
+ {
+ retval << color::bold << color::blue << " ...\n" << color::reset;
+ }
+ else // if filename differs, print " --> filename.toml" again
+ {
+ retval << color::bold << color::blue << " --> " << color::reset
+ << curr.first.file_name() << '\n';
+ retval << make_string(line_num_width + 1, ' ')
+ << color::bold << color::blue << " |\n" << color::reset;
+ }
+
+ format_one_location(retval, curr.first, curr.second);
+ }
+
+ if(!helps.empty())
+ {
+ retval << '\n';
+ retval << make_string(line_num_width + 1, ' ');
+ retval << color::bold << color::blue << " |" << color::reset;
+ for(const auto& help : helps)
+ {
+ retval << color::bold << "\nHint: " << color::reset;
+ retval << help;
+ }
+ }
+ return retval.str();
+}
+
+} // detail
+} // toml
+#endif// TOML11_SOURCE_LOCATION_HPP