diff --git a/spot/parsetl/fmterror.cc b/spot/parsetl/fmterror.cc index 61df55125..574ba2837 100644 --- a/spot/parsetl/fmterror.cc +++ b/spot/parsetl/fmterror.cc @@ -1,5 +1,5 @@ // -*- coding: utf-8 -*- -// Copyright (C) 2010, 2012, 2013, 2015 Laboratoire de Recherche et +// Copyright (C) 2010, 2012, 2013, 2015, 2016 Laboratoire de Recherche et // Développement de l'Epita (LRDE). // Copyright (C) 2003, 2004, 2005 Laboratoire d'Informatique de Paris // 6 (LIP6), département Systèmes Répartis Coopératifs (SRC), @@ -66,10 +66,11 @@ namespace spot namespace { - bool + static bool format_parse_errors_aux(std::ostream& os, const std::string& ltl_string, - const parse_error_list& error_list) + const parse_error_list& error_list, + unsigned shift) { bool printed = false; for (auto it: error_list) @@ -78,12 +79,12 @@ namespace spot const location& l = it.first; unsigned n = 1; - for (; n < 4 + l.begin.column; ++n) + for (; n < 4 + l.begin.column + shift; ++n) os << ' '; // Write at least one '^', even if begin==end. os << '^'; ++n; - for (; n < 4 + l.end.column; ++n) + for (; n < 4 + l.end.column + shift; ++n) os << '^'; os << '\n' << it.second << "\n\n"; printed = true; @@ -93,17 +94,27 @@ namespace spot } bool - parsed_formula::format_errors(std::ostream& os) + parsed_formula::format_errors(std::ostream& os, + const std::string& real_input, + unsigned shift) { if (utf8::is_valid(input.begin(), input.end())) { parse_error_list fixed = errors; fix_utf8_locations(input, fixed); - return format_parse_errors_aux(os, input, fixed); + return format_parse_errors_aux(os, real_input, fixed, shift); } else { - return format_parse_errors_aux(os, input, errors); + return format_parse_errors_aux(os, real_input, errors, shift); } } + + bool + parsed_formula::format_errors(std::ostream& os) + { + return format_errors(os, input, 0); + } + + } diff --git a/spot/tl/parse.hh b/spot/tl/parse.hh index b1bb4601e..4fdd21ff1 100644 --- a/spot/tl/parse.hh +++ b/spot/tl/parse.hh @@ -74,6 +74,28 @@ namespace spot /// \param os Where diagnostics should be output. /// \return \c true iff any diagnostic was output. bool format_errors(std::ostream& os); + + /// \brief Format shifted diagnostics. + /// + /// If the user input was something like "formula = a U b;" but you + /// only passed "a U b" to the parser, it might be convenient to + /// display the diagnostic in the context of "formula = a U b;". + /// + /// So pass the real input as \a input, and specify the number + /// of character to skip before the actual text passed to the + /// parser starts. + /// + /// This procedure assumes that the text passed to the parser + /// appears as-is in the input string. If you had to un-escape it + /// in any way, the error locations will be wrong. + /// + /// \param os Where diagnostics should be output. + /// \param input the real input string + /// \param shift how many characters to add to the error locations + /// \return \c true iff any diagnostic was output. + bool format_errors(std::ostream& os, + const std::string& input, + unsigned shift); }; diff --git a/spot/twaalgos/word.cc b/spot/twaalgos/word.cc index 7a8087153..b81a509d2 100644 --- a/spot/twaalgos/word.cc +++ b/spot/twaalgos/word.cc @@ -117,15 +117,10 @@ namespace spot namespace { static void word_parse_error(const std::string& word, - size_t i, parse_error_list pel) + size_t i, parsed_formula pf) { - for (auto& err: pel) - { - err.first.begin.column += i; - err.first.end.column += i; - } std::ostringstream os; - format_parse_errors(os, word, pel); + pf.format_errors(os, word, i); throw parse_error(os.str()); } @@ -166,7 +161,6 @@ namespace spot twa_word_ptr parse_word(const std::string& word, const bdd_dict_ptr& dict) { atomic_prop_set aps; - parse_error_list pel; tl_simplifier tls(dict); twa_word_ptr tw = make_twa_word(dict); size_t i = 0; @@ -176,11 +170,11 @@ namespace spot [&](typename twa_word::seq_t& seq) { auto sub = word.substr(i, ind - i); - formula f = spot::parse_infix_boolean(sub, pel); - if (!pel.empty()) - word_parse_error(word, i, pel); - atomic_prop_collect(f, &aps); - seq.push_back(tls.as_bdd(f)); + auto pf = spot::parse_infix_boolean(sub); + if (!pf.errors.empty()) + word_parse_error(word, i, pf); + atomic_prop_collect(pf.f, &aps); + seq.push_back(tls.as_bdd(pf.f)); if (word[ind] == '}') return true; // Skip blanks after semi-colon