Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-09-17 08:40:31

0001 #ifndef BOOST_PARSER_ERROR_HANDLING_HPP
0002 #define BOOST_PARSER_ERROR_HANDLING_HPP
0003 
0004 #include <boost/parser/error_handling_fwd.hpp>
0005 #include <boost/parser/detail/printing.hpp>
0006 #ifdef _MSC_VER
0007 #include <boost/parser/detail/vs_output_stream.hpp>
0008 #endif
0009 
0010 #include <boost/parser/detail/text/algorithm.hpp>
0011 #include <boost/parser/detail/text/transcode_iterator.hpp>
0012 
0013 #include <algorithm>
0014 #include <array>
0015 #include <functional>
0016 #include <iostream>
0017 #include <sstream>
0018 
0019 
0020 namespace boost { namespace parser {
0021 
0022     namespace detail {
0023 
0024         // All the hard line break code points from the Unicode Line Break
0025         // Algorithm; see https://unicode.org/reports/tr14.
0026         inline constexpr std::array<int, 7> eol_cps = {
0027             {0x000a, 0x000b, 0x000c, 0x000d, 0x0085, 0x2028, 0x2029}};
0028 
0029         inline constexpr int eol_cp_mask =
0030             0x000a | 0x000b | 0x000c | 0x000d | 0x0085 | 0x2028 | 0x2029;
0031     }
0032 
0033     /** Returns the `line_position` for `it`, counting lines from the
0034         beginning of the input `first`. */
0035     template<typename Iter>
0036     line_position<Iter> find_line_position(Iter first, Iter it)
0037     {
0038         bool prev_cr = false;
0039         auto retval = line_position<Iter>{first, 0, 0};
0040         for (Iter pos = first; pos != it; ++pos) {
0041             auto const c = *pos;
0042             bool const found =
0043                 (c & detail::eol_cp_mask) == c &&
0044                 std::find(detail::eol_cps.begin(), detail::eol_cps.end(), c) !=
0045                     detail::eol_cps.end();
0046             if (found) {
0047                 retval.line_start = std::next(pos);
0048                 retval.column_number = 0;
0049             } else {
0050                 ++retval.column_number;
0051             }
0052             if (found && (!prev_cr || c != 0x000a))
0053                 ++retval.line_number;
0054             prev_cr = c == 0x000d;
0055         }
0056         return retval;
0057     }
0058 
0059     /** Returns the iterator to the end of the line in which `it` is
0060         found.  */
0061     template<typename Iter, typename Sentinel>
0062     Iter find_line_end(Iter it, Sentinel last)
0063     {
0064         return parser::detail::text::find_if(it, last, [](auto c) {
0065             return (c & detail::eol_cp_mask) == c &&
0066                    std::find(
0067                        detail::eol_cps.begin(), detail::eol_cps.end(), c) !=
0068                        detail::eol_cps.end();
0069         });
0070     }
0071 
0072     template<typename Iter, typename Sentinel>
0073     std::ostream & write_formatted_message(
0074         std::ostream & os,
0075         std::string_view filename,
0076         Iter first,
0077         Iter it,
0078         Sentinel last,
0079         std::string_view message,
0080         int64_t preferred_max_line_length,
0081         int64_t max_after_caret)
0082     {
0083         if (!filename.empty())
0084             os << filename << ':';
0085         auto const position = parser::find_line_position(first, it);
0086         os << (position.line_number + 1) << ':' << position.column_number
0087            << ": " << message << " here";
0088         if (it == last)
0089             os << " (end of input)";
0090         os << ":\n";
0091 
0092         std::string underlining(std::distance(position.line_start, it), ' ');
0093         detail::trace_input(os, position.line_start, it, false, 1u << 31);
0094         if (it == last) {
0095             os << '\n' << underlining << "^\n";
0096             os.rdbuf()->pubsync();
0097             return os;
0098         }
0099 
0100         underlining += '^';
0101 
0102         int64_t const limit = (std::max)(
0103             preferred_max_line_length,
0104             (int64_t)underlining.size() + max_after_caret);
0105 
0106         int64_t i = (int64_t)underlining.size();
0107         auto const line_end = parser::find_line_end(std::next(it), last);
0108         detail::trace_input(os, it, line_end, false, limit - i);
0109 
0110         os << '\n' << underlining << '\n';
0111         os.rdbuf()->pubsync();
0112 
0113         return os;
0114     }
0115 
0116 #if defined(_MSC_VER)
0117     template<typename Iter, typename Sentinel>
0118     std::ostream & write_formatted_message(
0119         std::ostream & os,
0120         std::wstring_view filename,
0121         Iter first,
0122         Iter it,
0123         Sentinel last,
0124         std::string_view message,
0125         int64_t preferred_max_line_length,
0126         int64_t max_after_caret)
0127     {
0128         auto const r = filename | parser::detail::text::as_utf8;
0129         std::string s(r.begin(), r.end());
0130         return parser::write_formatted_message(
0131             os,
0132             s,
0133             first,
0134             it,
0135             last,
0136             message,
0137             preferred_max_line_length,
0138             max_after_caret);
0139     }
0140 #endif
0141 
0142     template<typename Iter, typename Sentinel>
0143     std::ostream & write_formatted_expectation_failure_error_message(
0144         std::ostream & os,
0145         std::string_view filename,
0146         Iter first,
0147         Sentinel last,
0148         parse_error<Iter> const & e,
0149         int64_t preferred_max_line_length,
0150         int64_t max_after_caret)
0151     {
0152         std::string message = "error: Expected ";
0153         message += e.what();
0154         return parser::write_formatted_message(
0155             os,
0156             filename,
0157             first,
0158             e.iter,
0159             last,
0160             message,
0161             preferred_max_line_length,
0162             max_after_caret);
0163     }
0164 
0165 #if defined(_MSC_VER)
0166     template<typename Iter, typename Sentinel>
0167     std::ostream & write_formatted_expectation_failure_error_message(
0168         std::ostream & os,
0169         std::wstring_view filename,
0170         Iter first,
0171         Sentinel last,
0172         parse_error<Iter> const & e,
0173         int64_t preferred_max_line_length,
0174         int64_t max_after_caret)
0175     {
0176         auto const r = filename | parser::detail::text::as_utf8;
0177         std::string s(r.begin(), r.end());
0178         return parser::write_formatted_expectation_failure_error_message(
0179             os, s, first, last, e, preferred_max_line_length, max_after_caret);
0180     }
0181 #endif
0182 
0183     /** An error handler that allows users to supply callbacks to handle the
0184         reporting of warnings and errors.  The reporting of errors and/or
0185         warnings can be suppressed by supplying one or both
0186         default-constructed callbacks. */
0187     struct callback_error_handler
0188     {
0189         using callback_type = std::function<void(std::string const &)>;
0190 
0191         callback_error_handler() {}
0192         callback_error_handler(
0193             callback_type error, callback_type warning = callback_type()) :
0194             error_(error), warning_(warning)
0195         {}
0196         callback_error_handler(
0197             std::string_view filename,
0198             callback_type error,
0199             callback_type warning = callback_type()) :
0200             error_(error), warning_(warning), filename_(filename)
0201         {}
0202 #if defined(_MSC_VER) || defined(BOOST_PARSER_DOXYGEN)
0203         /** This overload is Windows-only. */
0204         callback_error_handler(
0205             std::wstring_view filename,
0206             callback_type error,
0207             callback_type warning = callback_type()) :
0208             error_(error), warning_(warning)
0209         {
0210             auto const r = filename | parser::detail::text::as_utf8;
0211             filename_.assign(r.begin(), r.end());
0212         }
0213 #endif
0214         template<typename Iter, typename Sentinel>
0215         error_handler_result
0216         operator()(Iter first, Sentinel last, parse_error<Iter> const & e) const
0217         {
0218             if (error_) {
0219                 std::stringstream ss;
0220                 parser::write_formatted_expectation_failure_error_message(
0221                     ss, filename_, first, last, e);
0222                 error_(ss.str());
0223             }
0224             return error_handler_result::fail;
0225         }
0226 
0227         template<typename Context, typename Iter>
0228         void diagnose(
0229             diagnostic_kind kind,
0230             std::string_view message,
0231             Context const & context,
0232             Iter it) const
0233         {
0234             callback_type const & cb =
0235                 kind == diagnostic_kind::error ? error_ : warning_;
0236             if (!cb)
0237                 return;
0238             std::stringstream ss;
0239             parser::write_formatted_message(
0240                 ss,
0241                 filename_,
0242                 parser::_begin(context),
0243                 it,
0244                 parser::_end(context),
0245                 message);
0246             cb(ss.str());
0247         }
0248 
0249         template<typename Context>
0250         void diagnose(
0251             diagnostic_kind kind,
0252             std::string_view message,
0253             Context const & context) const
0254         {
0255             diagnose(kind, message, context, parser::_where(context).begin());
0256         }
0257 
0258         callback_type error_;
0259         callback_type warning_;
0260         std::string filename_;
0261     };
0262 
0263     /** An error handler that just re-throws any exception generated by the
0264         parse. */
0265     struct rethrow_error_handler
0266     {
0267         template<typename Iter, typename Sentinel>
0268         error_handler_result
0269         operator()(Iter first, Sentinel last, parse_error<Iter> const & e) const
0270         {
0271             return error_handler_result::rethrow;
0272         }
0273 
0274         template<typename Context, typename Iter>
0275         void diagnose(
0276             diagnostic_kind kind,
0277             std::string_view message,
0278             Context const & context,
0279             Iter it) const
0280         {}
0281 
0282         template<typename Context>
0283         void diagnose(
0284             diagnostic_kind kind,
0285             std::string_view message,
0286             Context const & context) const
0287         {}
0288     };
0289 
0290 #if defined(_MSC_VER) || defined(BOOST_PARSER_DOXYGEN)
0291     /** An error handler that prints to the Visual Studio debugger via calls
0292         to `OutputDebugString()`. */
0293     struct vs_output_error_handler : stream_error_handler
0294     {
0295         vs_output_error_handler() :
0296             stream_error_handler{"", detail::vs_cout, detail::vs_cout}
0297         {}
0298 
0299         vs_output_error_handler(std::string_view filename) :
0300             stream_error_handler{filename, detail::vs_cout, detail::vs_cout}
0301         {}
0302 
0303         vs_output_error_handler(std::wstring_view filename) :
0304             stream_error_handler{filename, detail::vs_cout, detail::vs_cout}
0305         {}
0306     };
0307 #endif
0308 
0309 
0310     // implementations
0311 
0312     template<typename Iter, typename Sentinel>
0313     error_handler_result default_error_handler::operator()(
0314         Iter first, Sentinel last, parse_error<Iter> const & e) const
0315     {
0316         parser::write_formatted_expectation_failure_error_message(
0317             std::cerr, "", first, last, e);
0318         return error_handler_result::fail;
0319     }
0320 
0321     template<typename Context, typename Iter>
0322     void default_error_handler::diagnose(
0323         diagnostic_kind kind,
0324         std::string_view message,
0325         Context const & context,
0326         Iter it) const
0327     {
0328         parser::write_formatted_message(
0329             std::cerr,
0330             "",
0331             parser::_begin(context),
0332             it,
0333             parser::_end(context),
0334             message);
0335     }
0336 
0337     template<typename Context>
0338     void default_error_handler::diagnose(
0339         diagnostic_kind kind,
0340         std::string_view message,
0341         Context const & context) const
0342     {
0343         diagnose(kind, message, context, parser::_where(context).begin());
0344     }
0345 
0346     template<typename Iter, typename Sentinel>
0347     error_handler_result stream_error_handler::operator()(
0348         Iter first, Sentinel last, parse_error<Iter> const & e) const
0349     {
0350         std::ostream * os = err_os_;
0351         if (!os)
0352             os = &std::cerr;
0353         parser::write_formatted_expectation_failure_error_message(
0354             *os, filename_, first, last, e);
0355         return error_handler_result::fail;
0356     }
0357 
0358     template<typename Context, typename Iter>
0359     void stream_error_handler::diagnose(
0360         diagnostic_kind kind,
0361         std::string_view message,
0362         Context const & context,
0363         Iter it) const
0364     {
0365         std::ostream * os = kind == diagnostic_kind::error ? err_os_ : warn_os_;
0366         if (!os)
0367             os = &std::cerr;
0368         parser::write_formatted_message(
0369             *os,
0370             filename_,
0371             parser::_begin(context),
0372             it,
0373             parser::_end(context),
0374             message);
0375     }
0376 
0377     template<typename Context>
0378     void stream_error_handler::diagnose(
0379         diagnostic_kind kind,
0380         std::string_view message,
0381         Context const & context) const
0382     {
0383         diagnose(kind, message, context, parser::_where(context).begin());
0384     }
0385 
0386 }}
0387 
0388 #endif