File indexing completed on 2025-09-17 08:40:28
0001 #ifndef BOOST_PARSER_DETAIL_PRINTING_HPP
0002 #define BOOST_PARSER_DETAIL_PRINTING_HPP
0003
0004 #include <boost/parser/parser_fwd.hpp>
0005 #include <boost/parser/tuple.hpp>
0006 #include <boost/parser/detail/detection.hpp>
0007 #include <boost/parser/detail/hl.hpp>
0008 #include <boost/parser/detail/text/unpack.hpp>
0009 #if defined(_MSC_VER) && defined(BOOST_PARSER_TRACE_TO_VS_OUTPUT)
0010 #include <boost/parser/detail/vs_output_stream.hpp>
0011 #endif
0012 #include <boost/parser/detail/text/transcode_view.hpp>
0013
0014 #include <iomanip>
0015 #include <iostream>
0016 #include <optional>
0017 #include <sstream>
0018 #include <string>
0019 #include <variant>
0020
0021 #include <cctype>
0022
0023
0024 namespace boost { namespace parser { namespace detail {
0025
0026 template<typename Context>
0027 decltype(auto) _indent(Context const & context);
0028
0029 template<typename Char>
0030 std::ostream & print_char(std::ostream & os, Char c)
0031 {
0032 if constexpr (
0033 #if defined(__cpp_char8_t)
0034 std::is_same_v<
0035 char8_t,
0036 std::remove_cv_t<std::remove_reference_t<Char>>>
0037 #else
0038 false
0039 #endif
0040 ) {
0041 os << char(c);
0042 } else {
0043 os << c;
0044 }
0045 return os;
0046 }
0047
0048 enum { parser_component_limit = 4 };
0049
0050 template<
0051 typename Context,
0052 typename Parser,
0053 typename DelimiterParser,
0054 typename MinType,
0055 typename MaxType>
0056 void print_parser(
0057 Context const & context,
0058 repeat_parser<Parser, DelimiterParser, MinType, MaxType> const & parser,
0059 std::ostream & os,
0060 int components = 0);
0061
0062 template<typename Context, typename Parser>
0063 void print_parser(
0064 Context const & context,
0065 opt_parser<Parser> const & parser,
0066 std::ostream & os,
0067 int components = 0);
0068
0069 template<typename Context, typename ParserTuple>
0070 void print_parser(
0071 Context const & context,
0072 or_parser<ParserTuple> const & parser,
0073 std::ostream & os,
0074 int components = 0);
0075
0076 template<typename Context, typename ParserTuple, typename DelimiterParser>
0077 void print_parser(
0078 Context const & context,
0079 perm_parser<ParserTuple, DelimiterParser> const & parser,
0080 std::ostream & os,
0081 int components = 0);
0082
0083 template<
0084 typename Context,
0085 typename ParserTuple,
0086 typename BacktrackingTuple,
0087 typename CombiningGroups>
0088 void print_parser(
0089 Context const & context,
0090 seq_parser<ParserTuple, BacktrackingTuple, CombiningGroups> const &
0091 parser,
0092 std::ostream & os,
0093 int components = 0);
0094
0095 template<typename Context, typename Parser, typename Action>
0096 void print_parser(
0097 Context const & context,
0098 action_parser<Parser, Action> const & parser,
0099 std::ostream & os,
0100 int components = 0);
0101
0102 template<typename Context, typename Parser, typename F>
0103 void print_parser(
0104 Context const & context,
0105 transform_parser<Parser, F> const & parser,
0106 std::ostream & os,
0107 int components = 0);
0108
0109 template<typename Context, typename Parser>
0110 void print_parser(
0111 Context const & context,
0112 omit_parser<Parser> const & parser,
0113 std::ostream & os,
0114 int components = 0);
0115
0116 template<typename Context, typename Parser>
0117 void print_parser(
0118 Context const & context,
0119 raw_parser<Parser> const & parser,
0120 std::ostream & os,
0121 int components = 0);
0122
0123 #if defined(BOOST_PARSER_DOXYGEN) || BOOST_PARSER_USE_CONCEPTS
0124 template<typename Context, typename Parser>
0125 void print_parser(
0126 Context const & context,
0127 string_view_parser<Parser> const & parser,
0128 std::ostream & os,
0129 int components = 0);
0130 #endif
0131
0132 template<typename Context, typename Parser>
0133 void print_parser(
0134 Context const & context,
0135 lexeme_parser<Parser> const & parser,
0136 std::ostream & os,
0137 int components = 0);
0138
0139 template<typename Context, typename Parser>
0140 void print_parser(
0141 Context const & context,
0142 no_case_parser<Parser> const & parser,
0143 std::ostream & os,
0144 int components = 0);
0145
0146 template<typename Context, typename Parser, typename SkipParser>
0147 void print_parser(
0148 Context const & context,
0149 skip_parser<Parser, SkipParser> const & parser,
0150 std::ostream & os,
0151 int components = 0);
0152
0153 template<typename Context, typename Parser, bool FailOnMatch>
0154 void print_parser(
0155 Context const & context,
0156 expect_parser<Parser, FailOnMatch> const & parser,
0157 std::ostream & os,
0158 int components = 0);
0159
0160 template<
0161 typename Context,
0162 bool UseCallbacks,
0163 typename Parser,
0164 typename Attribute,
0165 typename LocalState,
0166 typename ParamsTuple>
0167 void print_parser(
0168 Context const & context,
0169 rule_parser<
0170 UseCallbacks,
0171 Parser,
0172 Attribute,
0173 LocalState,
0174 ParamsTuple> const & parser,
0175 std::ostream & os,
0176 int components = 0);
0177
0178 template<typename Context, typename T>
0179 void print_parser(
0180 Context const & context,
0181 symbol_parser<T> const & parser,
0182 std::ostream & os,
0183 int components = 0);
0184
0185 template<typename Context, typename Predicate>
0186 void print_parser(
0187 Context const & context,
0188 eps_parser<Predicate> const & parser,
0189 std::ostream & os,
0190 int components = 0);
0191
0192 template<typename Context>
0193 void print_parser(
0194 Context const & context,
0195 eps_parser<nope> const & parser,
0196 std::ostream & os,
0197 int components = 0);
0198
0199 template<typename Context>
0200 void print_parser(
0201 Context const & context,
0202 eoi_parser const & parser,
0203 std::ostream & os,
0204 int components = 0);
0205
0206 template<typename Context, typename Atribute>
0207 void print_parser(
0208 Context const & context,
0209 attr_parser<Atribute> const & parser,
0210 std::ostream & os,
0211 int components = 0);
0212
0213 template<typename Context, typename Expected, typename AttributeType>
0214 void print_parser(
0215 Context const & context,
0216 char_parser<Expected, AttributeType> const & parser,
0217 std::ostream & os,
0218 int components = 0);
0219
0220 template<typename Context>
0221 void print_parser(
0222 Context const & context,
0223 digit_parser const & parser,
0224 std::ostream & os,
0225 int components = 0);
0226
0227 template<typename Context>
0228 void print_parser(
0229 Context const & context,
0230 char_subrange_parser<hex_digit_subranges> const & parser,
0231 std::ostream & os,
0232 int components = 0);
0233
0234 template<typename Context>
0235 void print_parser(
0236 Context const & context,
0237 char_subrange_parser<control_subranges> const & parser,
0238 std::ostream & os,
0239 int components = 0);
0240
0241 template<typename Context>
0242 void print_parser(
0243 Context const & context,
0244 char_set_parser<punct_chars> const & parser,
0245 std::ostream & os,
0246 int components = 0);
0247
0248 template<typename Context>
0249 void print_parser(
0250 Context const & context,
0251 char_set_parser<symb_chars> const & parser,
0252 std::ostream & os,
0253 int components = 0);
0254
0255 template<typename Context>
0256 void print_parser(
0257 Context const & context,
0258 char_set_parser<lower_case_chars> const & parser,
0259 std::ostream & os,
0260 int components = 0);
0261
0262 template<typename Context>
0263 void print_parser(
0264 Context const & context,
0265 char_set_parser<upper_case_chars> const & parser,
0266 std::ostream & os,
0267 int components = 0);
0268
0269 template<typename Context, typename Expected, typename AttributeType>
0270 void print_parser(
0271 Context const & context,
0272 omit_parser<char_parser<Expected, AttributeType>> const & parser,
0273 std::ostream & os,
0274 int components = 0);
0275
0276 template<typename Context, typename StrIter, typename StrSentinel>
0277 void print_parser(
0278 Context const & context,
0279 string_parser<StrIter, StrSentinel> const & parser,
0280 std::ostream & os,
0281 int components = 0);
0282
0283 template<typename Context, typename StrIter, typename StrSentinel>
0284 void print_parser(
0285 Context const & context,
0286 omit_parser<string_parser<StrIter, StrSentinel>> const & parser,
0287 std::ostream & os,
0288 int components = 0);
0289
0290 template<
0291 typename Context,
0292 typename Quotes,
0293 typename Escapes,
0294 typename CharParser>
0295 void print_parser(
0296 Context const & context,
0297 quoted_string_parser<Quotes, Escapes, CharParser> const & parser,
0298 std::ostream & os,
0299 int components = 0);
0300
0301 template<typename Context, bool NewlinesOnly, bool NoNewlines>
0302 void print_parser(
0303 Context const & context,
0304 ws_parser<NewlinesOnly, NoNewlines> const & parser,
0305 std::ostream & os,
0306 int components = 0);
0307
0308 template<typename Context>
0309 void print_parser(
0310 Context const & context,
0311 bool_parser const & parser,
0312 std::ostream & os,
0313 int components = 0);
0314
0315 template<
0316 typename Context,
0317 typename T,
0318 int Radix,
0319 int MinDigits,
0320 int MaxDigits,
0321 typename Expected>
0322 void print_parser(
0323 Context const & context,
0324 uint_parser<T, Radix, MinDigits, MaxDigits, Expected> const & parser,
0325 std::ostream & os,
0326 int components = 0);
0327
0328 template<
0329 typename Context,
0330 typename T,
0331 int Radix,
0332 int MinDigits,
0333 int MaxDigits,
0334 typename Expected>
0335 void print_parser(
0336 Context const & context,
0337 int_parser<T, Radix, MinDigits, MaxDigits, Expected> const & parser,
0338 std::ostream & os,
0339 int components = 0);
0340
0341 template<typename Context, typename T>
0342 void print_parser(
0343 Context const & context,
0344 float_parser<T> const & parser,
0345 std::ostream & os,
0346 int components = 0);
0347
0348 template<typename Context>
0349 void print_parser(
0350 Context const & context,
0351 float_parser<float> const & parser,
0352 std::ostream & os,
0353 int components = 0);
0354
0355 template<typename Context>
0356 void print_parser(
0357 Context const & context,
0358 float_parser<double> const & parser,
0359 std::ostream & os,
0360 int components = 0);
0361
0362 template<typename Context, typename SwitchValue, typename OrParser>
0363 void print_parser(
0364 Context const & context,
0365 switch_parser<SwitchValue, OrParser> const & parser,
0366 std::ostream & os,
0367 int components = 0);
0368
0369 enum { trace_indent_factor = 2 };
0370
0371 inline void trace_indent(std::ostream & os, int indent)
0372 {
0373 for (int i = 0, end = trace_indent_factor * indent; i != end; ++i) {
0374 os << ' ';
0375 }
0376 }
0377
0378 template<typename Iter, typename Sentinel, int SizeofValueType>
0379 struct trace_input_impl
0380 {
0381 static void call(
0382 std::ostream & os,
0383 Iter first_,
0384 Sentinel last_,
0385 bool quote,
0386 int64_t trace_input_cps)
0387 {
0388 auto utf8 = BOOST_PARSER_DETAIL_TEXT_SUBRANGE(first_, last_) | text::as_utf8;
0389 auto first = utf8.begin();
0390 auto last = utf8.end();
0391 if (quote)
0392 os << '"';
0393 for (int64_t i = 0; i < trace_input_cps && first != last;
0394 ++i, ++first) {
0395 detail::print_char(os, *first);
0396 }
0397 if (quote)
0398 os << '"';
0399 }
0400 };
0401
0402 template<typename Iter, typename Sentinel>
0403 struct trace_input_impl<Iter, Sentinel, 1>
0404 {
0405 static void call(
0406 std::ostream & os,
0407 Iter first_,
0408 Sentinel last_,
0409 bool quote,
0410 int64_t trace_input_cps)
0411 {
0412 auto r = BOOST_PARSER_DETAIL_TEXT_SUBRANGE(first_, last_);
0413 auto r_unpacked =
0414 detail::text::unpack_iterator_and_sentinel(first_, last_);
0415 auto utf32 = r | text::as_utf32;
0416 auto first = utf32.begin();
0417 auto const last = utf32.end();
0418 for (int64_t i = 0; i < trace_input_cps && first != last; ++i) {
0419 ++first;
0420 }
0421 if (quote)
0422 os << '"';
0423 auto first_repacked = r_unpacked.repack(first.base());
0424 for (Iter it = first_, end = first_repacked; it != end; ++it) {
0425 detail::print_char(os, *it);
0426 }
0427 if (quote)
0428 os << '"';
0429 }
0430 };
0431
0432 template<typename Iter, typename Sentinel>
0433 inline void trace_input(
0434 std::ostream & os,
0435 Iter first,
0436 Sentinel last,
0437 bool quote = true,
0438 int64_t trace_input_cps = 8)
0439 {
0440 trace_input_impl<Iter, Sentinel, sizeof(*first)>::call(
0441 os, first, last, quote, trace_input_cps);
0442 }
0443
0444 template<typename Iter, typename Sentinel>
0445 inline void trace_begin_match(
0446 std::ostream & os,
0447 Iter first,
0448 Sentinel last,
0449 int indent,
0450 std::string_view name)
0451 {
0452 detail::trace_indent(os, indent);
0453 os << "[begin " << name << "; input=";
0454 detail::trace_input(os, first, last);
0455 os << "]" << std::endl;
0456 }
0457
0458 template<typename Iter, typename Sentinel>
0459 inline void trace_end_match(
0460 std::ostream & os,
0461 Iter first,
0462 Sentinel last,
0463 int indent,
0464 std::string_view name)
0465 {
0466 detail::trace_indent(os, indent);
0467 os << "[end " << name << "; input=";
0468 detail::trace_input(os, first, last);
0469 os << "]" << std::endl;
0470 }
0471
0472 template<typename Iter, typename Sentinel, typename Context>
0473 void trace_prefix(
0474 std::ostream & os,
0475 Iter first,
0476 Sentinel last,
0477 Context const & context,
0478 std::string_view name)
0479 {
0480 int & indent = detail::_indent(context);
0481 detail::trace_begin_match(os, first, last, indent, name);
0482 ++indent;
0483 }
0484
0485 template<typename Iter, typename Sentinel, typename Context>
0486 void trace_suffix(
0487 std::ostream & os,
0488 Iter first,
0489 Sentinel last,
0490 Context const & context,
0491 std::string_view name)
0492 {
0493 int & indent = detail::_indent(context);
0494 --indent;
0495 detail::trace_end_match(os, first, last, indent, name);
0496 }
0497
0498 template<typename T>
0499 using streamable =
0500 decltype(std::declval<std::ostream &>() << std::declval<T const &>());
0501
0502 template<typename T, bool Streamable = is_detected_v<streamable, T>>
0503 struct printer
0504 {
0505 std::ostream & operator()(std::ostream & os, T const &)
0506 {
0507 return os << "<<unprintable-value>>";
0508 }
0509 };
0510
0511 template<typename T>
0512 void print_printable(std::ostream & os, T const & x)
0513 {
0514 os << x;
0515 }
0516
0517 inline void print_printable(std::ostream & os, char c)
0518 {
0519 if (std::isprint(c)) {
0520 os << "'" << c << "'";
0521 } else {
0522 unsigned char c_ = c;
0523 os << "'\\x" << std::hex << std::setfill('0') << (uint32_t)c_
0524 << "'";
0525 }
0526 }
0527
0528 inline void print_printable(std::ostream & os, char32_t c)
0529 {
0530 if (c < 256) {
0531 os << "U";
0532 detail::print_printable(os, (char)c);
0533 } else {
0534 os << "U'\\U" << std::hex << std::setfill('0') << (int32_t)c << "'";
0535 }
0536 }
0537
0538 template<typename T>
0539 struct printer<T, true>
0540 {
0541 std::ostream & operator()(std::ostream & os, T const & x)
0542 {
0543 detail::print_printable(os, x);
0544 return os;
0545 }
0546 };
0547
0548 template<typename T>
0549 constexpr bool is_variant_v = enable_variant<T>;
0550
0551 template<typename Attribute>
0552 inline void print(std::ostream & os, Attribute const & attr)
0553 {
0554 using just_attribute =
0555 std::remove_cv_t<std::remove_reference_t<Attribute>>;
0556 if constexpr (is_tuple<just_attribute>{}) {
0557 os << "(";
0558 bool first = true;
0559 hl::for_each(attr, [&](auto const & a) {
0560 if (!first)
0561 os << ", ";
0562 detail::print(os, a);
0563 first = false;
0564 });
0565 os << ")";
0566 } else if constexpr (is_optional_v<just_attribute>) {
0567 if (!attr)
0568 os << "<<empty>>";
0569 else
0570 detail::print(os, *attr);
0571 } else if constexpr (is_variant_v<just_attribute>) {
0572 os << "<<variant>>";
0573 } else {
0574 printer<just_attribute>{}(os, attr);
0575 }
0576 }
0577
0578 template<typename Attribute>
0579 inline void
0580 print_attribute(std::ostream & os, Attribute const & attr, int indent)
0581 {
0582 detail::trace_indent(os, indent);
0583 os << "attribute: ";
0584 detail::print(os, attr);
0585 os << "\n";
0586 }
0587
0588 inline void print_attribute(std::ostream &, nope const &, int) {}
0589
0590 constexpr inline bool do_trace(flags f)
0591 {
0592 return (uint32_t(f) & uint32_t(flags::trace)) == uint32_t(flags::trace);
0593 }
0594
0595 template<typename Context, typename T>
0596 auto resolve(Context const & context, T const & x);
0597
0598 template<typename Context>
0599 auto resolve(Context const &, nope n);
0600
0601 template<
0602 bool DoTrace,
0603 typename Iter,
0604 typename Sentinel,
0605 typename Context,
0606 typename Attribute>
0607 struct scoped_trace_t
0608 {
0609 scoped_trace_t(
0610 std::ostream & os,
0611 Iter & first,
0612 Sentinel last,
0613 Context const & context,
0614 flags f,
0615 Attribute const & attr,
0616 std::string name) :
0617 os_(os),
0618 initial_first_(first),
0619 first_(first),
0620 last_(last),
0621 context_(context),
0622 flags_(f),
0623 attr_(attr),
0624 name_(std::move(name))
0625 {
0626 if (!detail::do_trace(flags_))
0627 return;
0628 detail::trace_prefix(os, first_, last_, context_, name_);
0629 }
0630
0631 ~scoped_trace_t()
0632 {
0633 if (!detail::do_trace(flags_))
0634 return;
0635 detail::trace_indent(os_, detail::_indent(context_));
0636 if (*context_.pass_) {
0637 os_ << "matched ";
0638 detail::trace_input(os_, initial_first_, first_);
0639 os_ << "\n";
0640 detail::print_attribute(
0641 os_,
0642 detail::resolve(context_, attr_),
0643 detail::_indent(context_));
0644 } else {
0645 os_ << "no match\n";
0646 }
0647 detail::trace_suffix(os_, first_, last_, context_, name_);
0648 }
0649
0650 std::ostream & os_;
0651 Iter initial_first_;
0652 Iter & first_;
0653 Sentinel last_;
0654 Context const & context_;
0655 flags flags_;
0656 Attribute const & attr_;
0657 std::string name_;
0658 };
0659
0660 template<
0661 typename Iter,
0662 typename Sentinel,
0663 typename Context,
0664 typename Attribute>
0665 struct scoped_trace_t<false, Iter, Sentinel, Context, Attribute>
0666 {
0667 scoped_trace_t() {}
0668 };
0669
0670 template<
0671 typename Parser,
0672 typename Iter,
0673 typename Sentinel,
0674 typename Context,
0675 typename Attribute>
0676 auto scoped_trace(
0677 Parser const & parser,
0678 Iter & first,
0679 Sentinel last,
0680 Context const & context,
0681 flags f,
0682 Attribute const & attr)
0683 {
0684 if constexpr (Context::do_trace) {
0685 std::stringstream oss;
0686 detail::print_parser(context, parser, oss);
0687 std::ostream & os = BOOST_PARSER_TRACE_OSTREAM;
0688 return scoped_trace_t<true, Iter, Sentinel, Context, Attribute>(
0689 os, first, last, context, f, attr, oss.str());
0690 } else {
0691 return scoped_trace_t<false, Iter, Sentinel, Context, Attribute>{};
0692 }
0693 }
0694
0695 template<typename Context, typename Attribute>
0696 auto final_trace(Context const & context, flags f, Attribute const & attr)
0697 {
0698 if (!detail::do_trace(f))
0699 return;
0700
0701 std::ostream & os = BOOST_PARSER_TRACE_OSTREAM;
0702 os << "--------------------\n";
0703 if (*context.pass_) {
0704 os << "parse succeeded\n";
0705 detail::print_attribute(os, detail::resolve(context, attr), 0);
0706 } else {
0707 os << "parse failed\n";
0708 }
0709 os << "--------------------" << std::endl;
0710 }
0711
0712 }}}
0713
0714 #endif