#ifndef BOOST_PARSER_DETAIL_PRINTING_HPP #define BOOST_PARSER_DETAIL_PRINTING_HPP #include #include #include #include #include #if defined(_MSC_VER) && defined(BOOST_PARSER_TRACE_TO_VS_OUTPUT) #include #endif #include #include #include #include #include #include #include #include namespace boost { namespace parser { namespace detail { template decltype(auto) _indent(Context const & context); template std::ostream & print_char(std::ostream & os, Char c) { if constexpr ( #if defined(__cpp_char8_t) std::is_same_v< char8_t, std::remove_cv_t>> #else false #endif ) { os << char(c); } else { os << c; } return os; } enum { parser_component_limit = 4 }; template< typename Context, typename Parser, typename DelimiterParser, typename MinType, typename MaxType> void print_parser( Context const & context, repeat_parser const & parser, std::ostream & os, int components = 0); template void print_parser( Context const & context, opt_parser const & parser, std::ostream & os, int components = 0); template void print_parser( Context const & context, or_parser const & parser, std::ostream & os, int components = 0); template void print_parser( Context const & context, perm_parser const & parser, std::ostream & os, int components = 0); template< typename Context, typename ParserTuple, typename BacktrackingTuple, typename CombiningGroups> void print_parser( Context const & context, seq_parser const & parser, std::ostream & os, int components = 0); template void print_parser( Context const & context, action_parser const & parser, std::ostream & os, int components = 0); template void print_parser( Context const & context, transform_parser const & parser, std::ostream & os, int components = 0); template void print_parser( Context const & context, omit_parser const & parser, std::ostream & os, int components = 0); template void print_parser( Context const & context, raw_parser const & parser, std::ostream & os, int components = 0); #if defined(BOOST_PARSER_DOXYGEN) || BOOST_PARSER_USE_CONCEPTS template void print_parser( Context const & context, string_view_parser const & parser, std::ostream & os, int components = 0); #endif template void print_parser( Context const & context, lexeme_parser const & parser, std::ostream & os, int components = 0); template void print_parser( Context const & context, no_case_parser const & parser, std::ostream & os, int components = 0); template void print_parser( Context const & context, skip_parser const & parser, std::ostream & os, int components = 0); template void print_parser( Context const & context, expect_parser const & parser, std::ostream & os, int components = 0); template< typename Context, bool UseCallbacks, typename Parser, typename Attribute, typename LocalState, typename ParamsTuple> void print_parser( Context const & context, rule_parser< UseCallbacks, Parser, Attribute, LocalState, ParamsTuple> const & parser, std::ostream & os, int components = 0); template void print_parser( Context const & context, symbol_parser const & parser, std::ostream & os, int components = 0); template void print_parser( Context const & context, eps_parser const & parser, std::ostream & os, int components = 0); template void print_parser( Context const & context, eps_parser const & parser, std::ostream & os, int components = 0); template void print_parser( Context const & context, eoi_parser const & parser, std::ostream & os, int components = 0); template void print_parser( Context const & context, attr_parser const & parser, std::ostream & os, int components = 0); template void print_parser( Context const & context, char_parser const & parser, std::ostream & os, int components = 0); template void print_parser( Context const & context, digit_parser const & parser, std::ostream & os, int components = 0); template void print_parser( Context const & context, char_subrange_parser const & parser, std::ostream & os, int components = 0); template void print_parser( Context const & context, char_subrange_parser const & parser, std::ostream & os, int components = 0); template void print_parser( Context const & context, char_set_parser const & parser, std::ostream & os, int components = 0); template void print_parser( Context const & context, char_set_parser const & parser, std::ostream & os, int components = 0); template void print_parser( Context const & context, char_set_parser const & parser, std::ostream & os, int components = 0); template void print_parser( Context const & context, char_set_parser const & parser, std::ostream & os, int components = 0); template void print_parser( Context const & context, omit_parser> const & parser, std::ostream & os, int components = 0); template void print_parser( Context const & context, string_parser const & parser, std::ostream & os, int components = 0); template void print_parser( Context const & context, omit_parser> const & parser, std::ostream & os, int components = 0); template< typename Context, typename Quotes, typename Escapes, typename CharParser> void print_parser( Context const & context, quoted_string_parser const & parser, std::ostream & os, int components = 0); template void print_parser( Context const & context, ws_parser const & parser, std::ostream & os, int components = 0); template void print_parser( Context const & context, bool_parser const & parser, std::ostream & os, int components = 0); template< typename Context, typename T, int Radix, int MinDigits, int MaxDigits, typename Expected> void print_parser( Context const & context, uint_parser const & parser, std::ostream & os, int components = 0); template< typename Context, typename T, int Radix, int MinDigits, int MaxDigits, typename Expected> void print_parser( Context const & context, int_parser const & parser, std::ostream & os, int components = 0); template void print_parser( Context const & context, float_parser const & parser, std::ostream & os, int components = 0); template void print_parser( Context const & context, float_parser const & parser, std::ostream & os, int components = 0); template void print_parser( Context const & context, float_parser const & parser, std::ostream & os, int components = 0); template void print_parser( Context const & context, switch_parser const & parser, std::ostream & os, int components = 0); enum { trace_indent_factor = 2 }; inline void trace_indent(std::ostream & os, int indent) { for (int i = 0, end = trace_indent_factor * indent; i != end; ++i) { os << ' '; } } template struct trace_input_impl { static void call( std::ostream & os, Iter first_, Sentinel last_, bool quote, int64_t trace_input_cps) { auto utf8 = BOOST_PARSER_DETAIL_TEXT_SUBRANGE(first_, last_) | text::as_utf8; auto first = utf8.begin(); auto last = utf8.end(); if (quote) os << '"'; for (int64_t i = 0; i < trace_input_cps && first != last; ++i, ++first) { detail::print_char(os, *first); } if (quote) os << '"'; } }; template struct trace_input_impl { static void call( std::ostream & os, Iter first_, Sentinel last_, bool quote, int64_t trace_input_cps) { auto r = BOOST_PARSER_DETAIL_TEXT_SUBRANGE(first_, last_); auto r_unpacked = detail::text::unpack_iterator_and_sentinel(first_, last_); auto utf32 = r | text::as_utf32; auto first = utf32.begin(); auto const last = utf32.end(); for (int64_t i = 0; i < trace_input_cps && first != last; ++i) { ++first; } if (quote) os << '"'; auto first_repacked = r_unpacked.repack(first.base()); for (Iter it = first_, end = first_repacked; it != end; ++it) { detail::print_char(os, *it); } if (quote) os << '"'; } }; template inline void trace_input( std::ostream & os, Iter first, Sentinel last, bool quote = true, int64_t trace_input_cps = 8) { trace_input_impl::call( os, first, last, quote, trace_input_cps); } template inline void trace_begin_match( std::ostream & os, Iter first, Sentinel last, int indent, std::string_view name) { detail::trace_indent(os, indent); os << "[begin " << name << "; input="; detail::trace_input(os, first, last); os << "]" << std::endl; } template inline void trace_end_match( std::ostream & os, Iter first, Sentinel last, int indent, std::string_view name) { detail::trace_indent(os, indent); os << "[end " << name << "; input="; detail::trace_input(os, first, last); os << "]" << std::endl; } template void trace_prefix( std::ostream & os, Iter first, Sentinel last, Context const & context, std::string_view name) { int & indent = detail::_indent(context); detail::trace_begin_match(os, first, last, indent, name); ++indent; } template void trace_suffix( std::ostream & os, Iter first, Sentinel last, Context const & context, std::string_view name) { int & indent = detail::_indent(context); --indent; detail::trace_end_match(os, first, last, indent, name); } template using streamable = decltype(std::declval() << std::declval()); template> struct printer { std::ostream & operator()(std::ostream & os, T const &) { return os << "<>"; } }; template void print_printable(std::ostream & os, T const & x) { os << x; } inline void print_printable(std::ostream & os, char c) { if (std::isprint(c)) { os << "'" << c << "'"; } else { unsigned char c_ = c; os << "'\\x" << std::hex << std::setfill('0') << (uint32_t)c_ << "'"; } } inline void print_printable(std::ostream & os, char32_t c) { if (c < 256) { os << "U"; detail::print_printable(os, (char)c); } else { os << "U'\\U" << std::hex << std::setfill('0') << (int32_t)c << "'"; } } template struct printer { std::ostream & operator()(std::ostream & os, T const & x) { detail::print_printable(os, x); return os; } }; template constexpr bool is_variant_v = enable_variant; template inline void print(std::ostream & os, Attribute const & attr) { using just_attribute = std::remove_cv_t>; if constexpr (is_tuple{}) { os << "("; bool first = true; hl::for_each(attr, [&](auto const & a) { if (!first) os << ", "; detail::print(os, a); first = false; }); os << ")"; } else if constexpr (is_optional_v) { if (!attr) os << "<>"; else detail::print(os, *attr); } else if constexpr (is_variant_v) { os << "<>"; } else { printer{}(os, attr); } } template inline void print_attribute(std::ostream & os, Attribute const & attr, int indent) { detail::trace_indent(os, indent); os << "attribute: "; detail::print(os, attr); os << "\n"; } inline void print_attribute(std::ostream &, nope const &, int) {} constexpr inline bool do_trace(flags f) { return (uint32_t(f) & uint32_t(flags::trace)) == uint32_t(flags::trace); } template auto resolve(Context const & context, T const & x); template auto resolve(Context const &, nope n); template< bool DoTrace, typename Iter, typename Sentinel, typename Context, typename Attribute> struct scoped_trace_t { scoped_trace_t( std::ostream & os, Iter & first, Sentinel last, Context const & context, flags f, Attribute const & attr, std::string name) : os_(os), initial_first_(first), first_(first), last_(last), context_(context), flags_(f), attr_(attr), name_(std::move(name)) { if (!detail::do_trace(flags_)) return; detail::trace_prefix(os, first_, last_, context_, name_); } ~scoped_trace_t() { if (!detail::do_trace(flags_)) return; detail::trace_indent(os_, detail::_indent(context_)); if (*context_.pass_) { os_ << "matched "; detail::trace_input(os_, initial_first_, first_); os_ << "\n"; detail::print_attribute( os_, detail::resolve(context_, attr_), detail::_indent(context_)); } else { os_ << "no match\n"; } detail::trace_suffix(os_, first_, last_, context_, name_); } std::ostream & os_; Iter initial_first_; Iter & first_; Sentinel last_; Context const & context_; flags flags_; Attribute const & attr_; std::string name_; }; template< typename Iter, typename Sentinel, typename Context, typename Attribute> struct scoped_trace_t { scoped_trace_t() {} }; template< typename Parser, typename Iter, typename Sentinel, typename Context, typename Attribute> auto scoped_trace( Parser const & parser, Iter & first, Sentinel last, Context const & context, flags f, Attribute const & attr) { if constexpr (Context::do_trace) { std::stringstream oss; detail::print_parser(context, parser, oss); std::ostream & os = BOOST_PARSER_TRACE_OSTREAM; return scoped_trace_t( os, first, last, context, f, attr, oss.str()); } else { return scoped_trace_t{}; } } template auto final_trace(Context const & context, flags f, Attribute const & attr) { if (!detail::do_trace(f)) return; std::ostream & os = BOOST_PARSER_TRACE_OSTREAM; os << "--------------------\n"; if (*context.pass_) { os << "parse succeeded\n"; detail::print_attribute(os, detail::resolve(context, attr), 0); } else { os << "parse failed\n"; } os << "--------------------" << std::endl; } }}} #endif