From: <geo...@us...> - 2012-03-25 21:06:30
|
Revision: 4746 http://freeorion.svn.sourceforge.net/freeorion/revision/?rev=4746&view=rev Author: geoffthemedio Date: 2012-03-25 21:06:23 +0000 (Sun, 25 Mar 2012) Log Message: ----------- Added preceding and following lines around log error output of parsing problem indication of location in parsed file. Modified Paths: -------------- trunk/FreeOrion/parse/ReportParseError.cpp trunk/FreeOrion/parse/ReportParseError.h Modified: trunk/FreeOrion/parse/ReportParseError.cpp =================================================================== --- trunk/FreeOrion/parse/ReportParseError.cpp 2012-03-24 21:23:26 UTC (rev 4745) +++ trunk/FreeOrion/parse/ReportParseError.cpp 2012-03-25 21:06:23 UTC (rev 4746) @@ -11,14 +11,12 @@ m_indent(indent) {} -void parse::detail::info_visitor::indent() const -{ +void parse::detail::info_visitor::indent() const { if (m_indent) m_os << std::string(m_indent, ' '); } -std::string parse::detail::info_visitor::prepare(const string& s) const -{ +std::string parse::detail::info_visitor::prepare(const string& s) const { std::string str = s; if (str == parse::lexer::bool_regex) str = "boolean (true or false)"; @@ -36,14 +34,12 @@ void parse::detail::info_visitor::print(const string& str) const { m_os << prepare(str); } -void parse::detail::info_visitor::operator()(boost::spirit::info::nil) const -{ +void parse::detail::info_visitor::operator()(boost::spirit::info::nil) const { indent(); print(m_tag); } -void parse::detail::info_visitor::operator()(const string& str) const -{ +void parse::detail::info_visitor::operator()(const string& str) const { indent(); print(str); } @@ -51,8 +47,7 @@ void parse::detail::info_visitor::operator()(const boost::spirit::info& what) const { boost::apply_visitor(info_visitor(m_os, what.tag, m_indent), what.value); } -void parse::detail::info_visitor::operator()(const std::pair<boost::spirit::info, boost::spirit::info>& pair) const -{ +void parse::detail::info_visitor::operator()(const std::pair<boost::spirit::info, boost::spirit::info>& pair) const { const boost::spirit::info* infos = &pair.first; multi_info(infos, infos + 2); } @@ -61,7 +56,7 @@ { multi_info(l.begin(), l.end()); } template <typename Iter> -void parse::detail::info_visitor::multi_info(Iter first, const Iter last) const +void parse::detail::info_visitor::multi_info(Iter first, const Iter last) const { if (m_tag == "sequence" || m_tag == "expect") { if (first->tag.find(" =") == first->tag.size() - 2) @@ -85,8 +80,7 @@ } } -void parse::detail::pretty_print(std::ostream& os, boost::spirit::info const& what) -{ +void parse::detail::pretty_print(std::ostream& os, boost::spirit::info const& what) { info_visitor v(os, what.tag, 1); boost::apply_visitor(v, what.value); } @@ -102,43 +96,136 @@ boost::function<void (const std::string&)> parse::report_error_::send_error_string = &detail::default_send_error_string; -std::pair<parse::text_iterator, unsigned int> parse::report_error_::line_start_and_line_number(text_iterator error_position) const -{ - unsigned int line = 1; - text_iterator it = detail::s_begin; - text_iterator line_start = detail::s_begin; - while (it != error_position) { - bool eol = false; - if (it != error_position && *it == '\r') { - eol = true; - line_start = ++it; +namespace { + std::vector<parse::text_iterator> LineStarts() { + //Logger().debugStream() << "line starts start"; + using namespace parse; + + std::vector<text_iterator> retval; + + text_iterator it = detail::s_begin; + retval.push_back(it); // first line + + // find subsequent lines + while (it != detail::s_end) { + bool eol = false; + text_iterator temp; + + // if line-ending char is found, store iterator to point after it + if (*it == '\r') { + eol = true; + temp = ++it; + } + if (it != detail::s_end && *it == '\n') { + eol = true; + temp = ++it; + } + + if (eol && temp != detail::s_end) + retval.push_back(temp); + else if (it != detail::s_end) + ++it; } - if (it != error_position && *it == '\n') { - eol = true; - line_start = ++it; + + //Logger().debugStream() << "line starts end. num lines: " << retval.size(); + //for (unsigned int i = 0; i < retval.size(); ++i) { + // text_iterator line_end = retval[i]; + // while (line_end != detail::s_end && *line_end != '\r' && *line_end != '\n') + // ++line_end; + // Logger().debugStream() << " line " << i+1 << ": " << std::string(retval[i], line_end); + //} + return retval; + } +} + +std::pair<parse::text_iterator, unsigned int> parse::report_error_::line_start_and_line_number(text_iterator error_position) const { + //Logger().debugStream() << "line_start_and_line_number start ... looking for: " << std::string(error_position, error_position + 20); + if (error_position == detail::s_begin) + return std::make_pair(detail::s_begin, 1); + + std::vector<parse::text_iterator> line_starts = LineStarts(); + + // search for the first line where the iterator to the start of the line is + // at or past the error position + for (unsigned int index = 0; index < line_starts.size(); ++index) { + if (std::distance(line_starts[index], error_position) < 0 && index > 0) { + //Logger().debugStream() << "line_start_and_line_number early end"; + return std::make_pair(line_starts[index-1], index); // return start of previous line, which contained the error_position text } - if (eol) - ++line; - else - ++it; + //Logger().debugStream() << "line: " << index + 1 << " distance: " << std::distance(line_starts[index], error_position) << " : " << get_line(line_starts[index]); } - return std::pair<text_iterator, unsigned int>(line_start, line); + + //Logger().debugStream() << "line_start_and_line_number end"; + return std::make_pair(detail::s_begin, 1); } -std::string parse::report_error_::get_line(text_iterator line_start) const -{ +std::string parse::report_error_::get_line(text_iterator line_start) const { text_iterator line_end = line_start; - while (line_end != detail::s_end && *line_end != '\r' && *line_end != '\n') { + while (line_end != detail::s_end && *line_end != '\r' && *line_end != '\n') ++line_end; - } return std::string(line_start, line_end); } +std::string parse::report_error_::get_lines_before(text_iterator line_start) const { + //Logger().debugStream() << "get_lines_before start"; + + std::vector<parse::text_iterator> all_line_starts = LineStarts(); + unsigned int target_line = 1; + for (unsigned int line_minus_one = 0; line_minus_one < all_line_starts.size(); ++line_minus_one) { + if (std::distance(all_line_starts[line_minus_one], line_start) < 0) { + target_line = line_minus_one; // want line before line that starts past the requested line_start + break; + } + } + if (target_line <= 1) { + //Logger().debugStream() << "get_lines_before early end"; + return ""; + } + //Logger().debugStream() << "get_lines_before line " << target_line; + + const unsigned int NUM_LINES = 5; + unsigned int retval_first_line = 1; + unsigned int retval_last_line = target_line - 1; + if (retval_last_line > NUM_LINES) + retval_first_line = retval_last_line - NUM_LINES; + + //Logger().debugStream() << "get_lines_before showing lines " << retval_first_line << " to " << retval_last_line; + return std::string(all_line_starts[retval_first_line-1], all_line_starts[retval_last_line-1]); +} + +std::string parse::report_error_::get_lines_after(text_iterator line_start) const { + //Logger().debugStream() << "get_lines_after start"; + + std::vector<parse::text_iterator> all_line_starts = LineStarts(); + unsigned int target_line = 1; + for (unsigned int line_minus_one = 0; line_minus_one < all_line_starts.size(); ++line_minus_one) { + if (std::distance(all_line_starts[line_minus_one], line_start) < 0) { + target_line = line_minus_one; // want line before line that starts past the requested line_start + break; + } + } + if (target_line >= all_line_starts.size()) { + //Logger().debugStream() << "get_lines_after early end"; + return ""; + } + //Logger().debugStream() << "get_lines_after line " << target_line; + + const unsigned int NUM_LINES = 5; + unsigned int retval_first_line = target_line + 1; + unsigned int retval_last_line = all_line_starts.size(); + if (retval_first_line + NUM_LINES < all_line_starts.size()) + retval_last_line = retval_first_line + NUM_LINES; + + //Logger().debugStream() << "get_lines_after showing lines " << retval_first_line << " to " << retval_last_line; + return std::string(all_line_starts[retval_first_line-1], all_line_starts[retval_last_line-1]); +} + void parse::report_error_::generate_error_string(const token_iterator& first, const token_iterator& it, const boost::spirit::info& rule_name, std::string& str) const { + //Logger().debugStream() << "generate_error_string"; std::stringstream is; text_iterator line_start; @@ -161,6 +248,7 @@ boost::tie(line_start, line_number) = line_start_and_line_number(text_it); std::size_t column_number = std::distance(line_start, text_it); + //Logger().debugStream() << "generate_error_string found line number: " << line_number << " column number: " << column_number; is << detail::s_filename << ":" << line_number << ":" << column_number << ": " << "Parse error. Expected"; @@ -176,9 +264,11 @@ if (text_it == detail::s_end) { is << " before end of input.\n"; } else { - is << " here:\n" - << " " << get_line(line_start) << "\n" - << " " << std::string(column_number, ' ') << '^' << std::endl; + is << " here:\n"; + is << get_lines_before(line_start); + is << get_line(line_start) << "\n"; + is << std::string(column_number, ' ') << '^' << std::endl; + is << get_lines_after(line_start); } str = is.str(); Modified: trunk/FreeOrion/parse/ReportParseError.h =================================================================== --- trunk/FreeOrion/parse/ReportParseError.h 2012-03-24 21:23:26 UTC (rev 4745) +++ trunk/FreeOrion/parse/ReportParseError.h 2012-03-25 21:06:23 UTC (rev 4746) @@ -9,11 +9,8 @@ namespace parse { - namespace detail { - - struct info_visitor - { + struct info_visitor { typedef void result_type; typedef boost::spirit::utf8_string string; @@ -39,15 +36,13 @@ void default_send_error_string(const std::string& str); - extern const char* s_filename; - extern text_iterator* s_text_it; - extern text_iterator s_begin; - extern text_iterator s_end; - + extern const char* s_filename; + extern text_iterator* s_text_it; + extern text_iterator s_begin; + extern text_iterator s_end; } - struct report_error_ - { + struct report_error_ { template <typename Arg1, typename Arg2, typename Arg3, typename Arg4> struct result { typedef void type; }; @@ -65,6 +60,8 @@ private: std::pair<text_iterator, unsigned int> line_start_and_line_number(text_iterator error_position) const; std::string get_line(text_iterator line_start) const; + std::string get_lines_before(text_iterator line_start) const; + std::string get_lines_after(text_iterator line_start) const; void generate_error_string(const token_iterator& first, const token_iterator& it, const boost::spirit::info& rule_name, @@ -72,7 +69,6 @@ }; extern const boost::phoenix::function<report_error_> report_error; - } #endif |