From 2f7e5964a6e06f6b6738e2372786d36e96d5f206 Mon Sep 17 00:00:00 2001 From: Zach Laine Date: Tue, 10 Dec 2024 01:39:45 -0600 Subject: [PATCH] Apply the same sort of change as the previous two commits, but to all the parsers not already modified. Generalize with_parser_mods(). Remove omit_parser, since it is now moot. See #160. --- include/boost/parser/detail/printing.hpp | 337 +-- include/boost/parser/detail/printing_impl.hpp | 446 ++-- include/boost/parser/parser.hpp | 1956 +++++++++++------ include/boost/parser/parser_fwd.hpp | 80 +- include/boost/parser/replace.hpp | 17 +- include/boost/parser/search.hpp | 29 +- include/boost/parser/split.hpp | 22 +- include/boost/parser/transform_replace.hpp | 21 +- test/tracing.cpp | 2 + 9 files changed, 1830 insertions(+), 1080 deletions(-) diff --git a/include/boost/parser/detail/printing.hpp b/include/boost/parser/detail/printing.hpp index 52722a67..b30f0fe6 100644 --- a/include/boost/parser/detail/printing.hpp +++ b/include/boost/parser/detail/printing.hpp @@ -52,110 +52,125 @@ namespace boost { namespace parser { namespace detail { typename Parser, typename DelimiterParser, typename MinType, - typename MaxType> - void print_parser( + typename MaxType, + typename ParserMods> + void print_parser_impl( Context const & context, - repeat_parser const & parser, + repeat_parser< + Parser, + DelimiterParser, + MinType, + MaxType, + ParserMods> const & parser, std::ostream & os, - int components = 0); + int components); - template - void print_parser( + template + void print_parser_impl( Context const & context, - opt_parser const & parser, + opt_parser const & parser, std::ostream & os, - int components = 0); + int components); - template - void print_parser( + template + void print_parser_impl( Context const & context, - or_parser const & parser, + or_parser const & parser, std::ostream & os, - int components = 0); + int components); - template - void print_parser( + template + void print_parser_impl( Context const & context, - perm_parser const & parser, + perm_parser const & parser, std::ostream & os, - int components = 0); + int components); 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( + typename CombiningGroups, + typename ParserMods> + void print_parser_impl( Context const & context, - action_parser const & parser, + seq_parser< + ParserTuple, + BacktrackingTuple, + CombiningGroups, + ParserMods> const & parser, std::ostream & os, - int components = 0); + int components); - template - void print_parser( + template< + typename Context, + typename Parser, + typename Action, + typename ParserMods> + void print_parser_impl( Context const & context, - transform_parser const & parser, + action_parser const & parser, std::ostream & os, - int components = 0); + int components); - template - void print_parser( + template + void print_parser_impl( Context const & context, - omit_parser const & parser, + transform_parser const & parser, std::ostream & os, - int components = 0); + int components); - template - void print_parser( + template + void print_parser_impl( Context const & context, - raw_parser const & parser, + raw_parser const & parser, std::ostream & os, - int components = 0); + int components); #if defined(BOOST_PARSER_DOXYGEN) || BOOST_PARSER_USE_CONCEPTS - template - void print_parser( + template + void print_parser_impl( Context const & context, - string_view_parser const & parser, + string_view_parser const & parser, std::ostream & os, - int components = 0); + int components); #endif - template - void print_parser( + template + void print_parser_impl( Context const & context, - lexeme_parser const & parser, + lexeme_parser const & parser, std::ostream & os, - int components = 0); + int components); - template - void print_parser( + template + void print_parser_impl( Context const & context, - no_case_parser const & parser, + no_case_parser const & parser, std::ostream & os, - int components = 0); + int components); - template - void print_parser( + template< + typename Context, + typename Parser, + typename SkipParser, + typename ParserMods> + void print_parser_impl( Context const & context, - skip_parser const & parser, + skip_parser const & parser, std::ostream & os, - int components = 0); + int components); - template - void print_parser( + template< + typename Context, + typename Parser, + bool FailOnMatch, + typename ParserMods> + void print_parser_impl( Context const & context, - expect_parser const & parser, + expect_parser const & parser, std::ostream & os, - int components = 0); + int components); template< typename Context, @@ -163,137 +178,147 @@ namespace boost { namespace parser { namespace detail { typename Parser, typename Attribute, typename LocalState, - typename ParamsTuple> - void print_parser( + typename ParamsTuple, + typename ParserMods> + void print_parser_impl( Context const & context, rule_parser< UseCallbacks, Parser, Attribute, LocalState, - ParamsTuple> const & parser, + ParamsTuple, + ParserMods> const & parser, std::ostream & os, - int components = 0); + int components); - template - void print_parser( + template + void print_parser_impl( Context const & context, - symbol_parser const & parser, + symbol_parser const & parser, std::ostream & os, - int components = 0); + int components); - template - void print_parser( + template + void print_parser_impl( Context const & context, - eps_parser const & parser, + eps_parser const & parser, std::ostream & os, - int components = 0); + int components); - template - void print_parser( + template + void print_parser_impl( Context const & context, - eps_parser const & parser, + eps_parser const & parser, std::ostream & os, - int components = 0); + int components); - template - void print_parser( + template + void print_parser_impl( Context const & context, - eoi_parser const & parser, + eoi_parser const & parser, std::ostream & os, - int components = 0); + int components); - template - void print_parser( + template + void print_parser_impl( Context const & context, - attr_parser const & parser, + attr_parser const & parser, std::ostream & os, - int components = 0); + int components); template< typename Context, typename Expected, typename AttributeType, typename ParserMods> - void print_parser( + void print_parser_impl( Context const & context, char_parser const & parser, std::ostream & os, - int components = 0); + int components); - template - void print_parser( + template + void print_parser_impl( Context const & context, - digit_parser const & parser, + digit_parser const & parser, std::ostream & os, - int components = 0); + int components); - template - void print_parser( + template + void print_parser_impl( Context const & context, - char_subrange_parser const & parser, + char_subrange_parser const & parser, std::ostream & os, - int components = 0); + int components); - template - void print_parser( + template + void print_parser_impl( Context const & context, - char_subrange_parser const & parser, + char_subrange_parser const & parser, std::ostream & os, - int components = 0); + int components); - template - void print_parser( + template + void print_parser_impl( Context const & context, - char_set_parser const & parser, + char_set_parser const & parser, std::ostream & os, - int components = 0); + int components); - template - void print_parser( + template + void print_parser_impl( Context const & context, - char_set_parser const & parser, + char_set_parser const & parser, std::ostream & os, - int components = 0); + int components); - template - void print_parser( + template + void print_parser_impl( Context const & context, - char_set_parser const & parser, + char_set_parser const & parser, std::ostream & os, - int components = 0); + int components); template< typename Context, typename StrIter, typename StrSentinel, typename ParserMods> - void print_parser( + void print_parser_impl( Context const & context, string_parser const & parser, std::ostream & os, - int components = 0); + int components); - template - void print_parser( + template< + typename Context, + typename Quotes, + typename Escapes, + typename ParserMods> + void print_parser_impl( Context const & context, - quoted_string_parser const & parser, + quoted_string_parser const & parser, std::ostream & os, - int components = 0); + int components); - template - void print_parser( + template< + typename Context, + bool NewlinesOnly, + bool NoNewlines, + typename ParserMods> + void print_parser_impl( Context const & context, - ws_parser const & parser, + ws_parser const & parser, std::ostream & os, - int components = 0); + int components); - template - void print_parser( + template + void print_parser_impl( Context const & context, - bool_parser const & parser, + bool_parser const & parser, std::ostream & os, - int components = 0); + int components); template< typename Context, @@ -301,12 +326,19 @@ namespace boost { namespace parser { namespace detail { int Radix, int MinDigits, int MaxDigits, - typename Expected> - void print_parser( + typename Expected, + typename ParserMods> + void print_parser_impl( Context const & context, - uint_parser const & parser, + uint_parser< + T, + Radix, + MinDigits, + MaxDigits, + Expected, + ParserMods> const & parser, std::ostream & os, - int components = 0); + int components); template< typename Context, @@ -314,38 +346,51 @@ namespace boost { namespace parser { namespace detail { int Radix, int MinDigits, int MaxDigits, - typename Expected> - void print_parser( + typename Expected, + typename ParserMods> + void print_parser_impl( Context const & context, - int_parser const & parser, + int_parser const & + parser, std::ostream & os, - int components = 0); + int components); - template - void print_parser( + template + void print_parser_impl( Context const & context, - float_parser const & parser, + float_parser const & parser, std::ostream & os, - int components = 0); + int components); - template - void print_parser( + template + void print_parser_impl( Context const & context, - float_parser const & parser, + float_parser const & parser, std::ostream & os, - int components = 0); + int components); - template - void print_parser( + template + void print_parser_impl( Context const & context, - float_parser const & parser, + float_parser const & parser, std::ostream & os, - int components = 0); + int components); - template + template< + typename Context, + typename SwitchValue, + typename OrParser, + typename ParserMods> + void print_parser_impl( + Context const & context, + switch_parser const & parser, + std::ostream & os, + int components); + + template void print_parser( Context const & context, - switch_parser const & parser, + Parser const & parser, std::ostream & os, int components = 0); diff --git a/include/boost/parser/detail/printing_impl.hpp b/include/boost/parser/detail/printing_impl.hpp index 0c8ac699..51b6920f 100644 --- a/include/boost/parser/detail/printing_impl.hpp +++ b/include/boost/parser/detail/printing_impl.hpp @@ -43,36 +43,44 @@ namespace boost { namespace parser { namespace detail { typename Parser, typename DelimiterParser, typename MinType, - typename MaxType> + typename MaxType, + typename ParserMods> struct n_aray_parser< - repeat_parser> + repeat_parser> : std::true_type {}; - template - struct n_aray_parser> + template< + typename Parser, + typename MinType, + typename MaxType, + typename ParserMods> + struct n_aray_parser< + repeat_parser> : std::false_type {}; - template - struct n_aray_parser> + template + struct n_aray_parser< + delimited_seq_parser> : std::true_type {}; - template - struct n_aray_parser> : std::true_type + template + struct n_aray_parser> : std::true_type {}; - template - struct n_aray_parser> : std::true_type + template + struct n_aray_parser> : std::true_type {}; template< typename ParserTuple, typename BacktrackingTuple, - typename CombiningGroups> + typename CombiningGroups, + typename ParserMods> struct n_aray_parser< - seq_parser> + seq_parser> : std::true_type {}; @@ -101,10 +109,16 @@ namespace boost { namespace parser { namespace detail { typename Parser, typename DelimiterParser, typename MinType, - typename MaxType> - void print_parser( + typename MaxType, + typename ParserMods> + void print_parser_impl( Context const & context, - repeat_parser const & parser, + repeat_parser< + Parser, + DelimiterParser, + MinType, + MaxType, + ParserMods> const & parser, std::ostream & os, int components) { @@ -116,7 +130,7 @@ namespace boost { namespace parser { namespace detail { os << "*"; if (n_ary_child) os << "("; - detail::print_parser( + detail::print_parser_impl( context, parser.parser_, os, components + 1); if (n_ary_child) os << ")"; @@ -124,7 +138,7 @@ namespace boost { namespace parser { namespace detail { os << "+"; if (n_ary_child) os << "("; - detail::print_parser( + detail::print_parser_impl( context, parser.parser_, os, components + 1); if (n_ary_child) os << ")"; @@ -141,22 +155,22 @@ namespace boost { namespace parser { namespace detail { detail::print(os, max_); os << ")["; } - detail::print_parser( + detail::print_parser_impl( context, parser.parser_, os, components + 1); os << "]"; } } else { - detail::print_parser(context, parser.parser_, os, components + 1); + detail::print_parser_impl(context, parser.parser_, os, components + 1); os << " % "; - detail::print_parser( + detail::print_parser_impl( context, parser.delimiter_parser_, os, components + 2); } } - template - void print_parser( + template + void print_parser_impl( Context const & context, - opt_parser const & parser, + opt_parser const & parser, std::ostream & os, int components) { @@ -164,7 +178,7 @@ namespace boost { namespace parser { namespace detail { constexpr bool n_ary_child = n_aray_parser_v; if (n_ary_child) os << "("; - detail::print_parser(context, parser.parser_, os, components + 1); + detail::print_parser_impl(context, parser.parser_, os, components + 1); if (n_ary_child) os << ")"; } @@ -189,16 +203,16 @@ namespace boost { namespace parser { namespace detail { } if (i) os << ws_or; - detail::print_parser(context, parser, os, components); + detail::print_parser_impl(context, parser, os, components); ++components; ++i; }); } - template - void print_parser( + template + void print_parser_impl( Context const & context, - or_parser const & parser, + or_parser const & parser, std::ostream & os, int components) { @@ -206,10 +220,10 @@ namespace boost { namespace parser { namespace detail { context, parser, os, components, " | ...", " | "); } - template - void print_parser( + template + void print_parser_impl( Context const & context, - perm_parser const & parser, + perm_parser const & parser, std::ostream & os, int components) { @@ -221,11 +235,15 @@ namespace boost { namespace parser { namespace detail { typename Context, typename ParserTuple, typename BacktrackingTuple, - typename CombiningGroups> - void print_parser( + typename CombiningGroups, + typename ParserMods> + void print_parser_impl( Context const & context, - seq_parser const & - parser, + seq_parser< + ParserTuple, + BacktrackingTuple, + CombiningGroups, + ParserMods> const & parser, std::ostream & os, int components) { @@ -255,7 +273,7 @@ namespace boost { namespace parser { namespace detail { os << (backtrack ? " >> " : " > "); if (group != prev_group && group) os << (group == -1 ? "separate[" : "merge["); - detail::print_parser(context, parser, os, components); + detail::print_parser_impl(context, parser, os, components); ++components; ++i; prev_group = (int)group; @@ -264,14 +282,18 @@ namespace boost { namespace parser { namespace detail { os << ']'; } - template - void print_parser( + template< + typename Context, + typename Parser, + typename Action, + typename ParserMods> + void print_parser_impl( Context const & context, - action_parser const & parser, + action_parser const & parser, std::ostream & os, int components) { - detail::print_parser(context, parser.parser_, os, components); + detail::print_parser_impl(context, parser.parser_, os, components); os << "[<>]"; } @@ -287,14 +309,14 @@ namespace boost { namespace parser { namespace detail { if (++components == parser_component_limit) os << "..."; else - detail::print_parser(context, parser, os, components + 1); + detail::print_parser_impl(context, parser, os, components + 1); os << "]"; } - template - void print_parser( + template + void print_parser_impl( Context const & context, - transform_parser const & parser, + transform_parser const & parser, std::ostream & os, int components) { @@ -302,21 +324,10 @@ namespace boost { namespace parser { namespace detail { context, "transform(<>)", parser.parser_, os, components); } - template - void print_parser( + template + void print_parser_impl( Context const & context, - omit_parser const & parser, - std::ostream & os, - int components) - { - detail::print_directive( - context, "omit", parser.parser_, os, components); - } - - template - void print_parser( - Context const & context, - raw_parser const & parser, + raw_parser const & parser, std::ostream & os, int components) { @@ -324,10 +335,10 @@ namespace boost { namespace parser { namespace detail { } #if defined(BOOST_PARSER_DOXYGEN) || BOOST_PARSER_USE_CONCEPTS - template - void print_parser( + template + void print_parser_impl( Context const & context, - string_view_parser const & parser, + string_view_parser const & parser, std::ostream & os, int components) { @@ -336,10 +347,10 @@ namespace boost { namespace parser { namespace detail { } #endif - template - void print_parser( + template + void print_parser_impl( Context const & context, - lexeme_parser const & parser, + lexeme_parser const & parser, std::ostream & os, int components) { @@ -347,10 +358,10 @@ namespace boost { namespace parser { namespace detail { context, "lexeme", parser.parser_, os, components); } - template - void print_parser( + template + void print_parser_impl( Context const & context, - no_case_parser const & parser, + no_case_parser const & parser, std::ostream & os, int components) { @@ -358,10 +369,14 @@ namespace boost { namespace parser { namespace detail { context, "no_case", parser.parser_, os, components); } - template - void print_parser( + template< + typename Context, + typename Parser, + typename SkipParser, + typename ParserMods> + void print_parser_impl( Context const & context, - skip_parser const & parser, + skip_parser const & parser, std::ostream & os, int components) { @@ -370,7 +385,7 @@ namespace boost { namespace parser { namespace detail { context, "skip", parser.parser_, os, components); } else { os << "skip("; - detail::print_parser( + detail::print_parser_impl( context, parser.skip_parser_.parser_, os, components); os << ")"; detail::print_directive( @@ -378,10 +393,14 @@ namespace boost { namespace parser { namespace detail { } } - template - void print_parser( + template< + typename Context, + typename Parser, + bool FailOnMatch, + typename ParserMods> + void print_parser_impl( Context const & context, - expect_parser const & parser, + expect_parser const & parser, std::ostream & os, int components) { @@ -392,7 +411,7 @@ namespace boost { namespace parser { namespace detail { constexpr bool n_ary_child = n_aray_parser_v; if (n_ary_child) os << "("; - detail::print_parser(context, parser.parser_, os, components + 1); + detail::print_parser_impl(context, parser.parser_, os, components + 1); if (n_ary_child) os << ")"; } @@ -403,15 +422,17 @@ namespace boost { namespace parser { namespace detail { typename Parser, typename Attribute, typename LocalState, - typename ParamsTuple> - void print_parser( + typename ParamsTuple, + typename ParserMods> + void print_parser_impl( Context const & context, rule_parser< UseCallbacks, Parser, Attribute, LocalState, - ParamsTuple> const & parser, + ParamsTuple, + ParserMods> const & parser, std::ostream & os, int components) { @@ -428,10 +449,10 @@ namespace boost { namespace parser { namespace detail { } } - template - void print_parser( + template + void print_parser_impl( Context const & context, - symbol_parser const & parser, + symbol_parser const & parser, std::ostream & os, int components) { @@ -441,40 +462,40 @@ namespace boost { namespace parser { namespace detail { os << parser.diagnostic_text_; } - template - void print_parser( + template + void print_parser_impl( Context const & context, - eps_parser const & parser, + eps_parser const & parser, std::ostream & os, int components) { os << "eps(<>)"; } - template - void print_parser( + template + void print_parser_impl( Context const & context, - eps_parser const & parser, + eps_parser const & parser, std::ostream & os, int components) { os << "eps"; } - template - void print_parser( + template + void print_parser_impl( Context const & context, - eoi_parser const & parser, + eoi_parser const & parser, std::ostream & os, int components) { os << "eoi"; } - template - void print_parser( + template + void print_parser_impl( Context const & context, - attr_parser const & parser, + attr_parser const & parser, std::ostream & os, int components) { @@ -527,7 +548,7 @@ namespace boost { namespace parser { namespace detail { } template - struct char_print_parser_impl + struct char_print_parser_impl_impl { static void call(Context const & context, std::ostream & os, T expected) { @@ -536,7 +557,7 @@ namespace boost { namespace parser { namespace detail { }; template - struct char_print_parser_impl> + struct char_print_parser_impl_impl> { static void call( Context const & context, @@ -550,7 +571,7 @@ namespace boost { namespace parser { namespace detail { }; template - struct char_print_parser_impl> + struct char_print_parser_impl_impl> { static void call( Context const & context, @@ -571,7 +592,7 @@ namespace boost { namespace parser { namespace detail { typename Expected, typename AttributeType, typename ParserMods> - void print_parser( + void print_parser_impl( Context const & context, char_parser const & parser, std::ostream & os, @@ -579,9 +600,9 @@ namespace boost { namespace parser { namespace detail { { if constexpr (parser.mods_.omit_attr) { if constexpr (is_nope_v) { - os << "omit[char_]"; + os << "char_"; } else { - char_print_parser_impl::call( + char_print_parser_impl_impl::call( context, os, parser.expected_); } } else { @@ -593,67 +614,67 @@ namespace boost { namespace parser { namespace detail { os << "char_"; if constexpr (!is_nope_v) { os << "("; - char_print_parser_impl::call( + char_print_parser_impl_impl::call( context, os, parser.expected_); os << ")"; } } } - template - void print_parser( + template + void print_parser_impl( Context const & context, - digit_parser const & parser, + digit_parser const & parser, std::ostream & os, int components) { os << "digit"; } - template - void print_parser( + template + void print_parser_impl( Context const & context, - char_subrange_parser const & parser, + char_subrange_parser const & parser, std::ostream & os, int components) { os << "hex_digit"; } - template - void print_parser( + template + void print_parser_impl( Context const & context, - char_subrange_parser const & parser, + char_subrange_parser const & parser, std::ostream & os, int components) { os << "control"; } - template - void print_parser( + template + void print_parser_impl( Context const & context, - char_set_parser const & parser, + char_set_parser const & parser, std::ostream & os, int components) { os << "punct"; } - template - void print_parser( + template + void print_parser_impl( Context const & context, - char_set_parser const & parser, + char_set_parser const & parser, std::ostream & os, int components) { os << "lower"; } - template - void print_parser( + template + void print_parser_impl( Context const & context, - char_set_parser const & parser, + char_set_parser const & parser, std::ostream & os, int components) { @@ -665,7 +686,7 @@ namespace boost { namespace parser { namespace detail { typename StrIter, typename StrSentinel, typename ParserMods> - void print_parser( + void print_parser_impl( Context const & context, string_parser const & parser, std::ostream & os, @@ -686,10 +707,14 @@ namespace boost { namespace parser { namespace detail { } } - template - void print_parser( + template< + typename Context, + typename Quotes, + typename Escapes, + typename ParserMods> + void print_parser_impl( Context const & context, - quoted_string_parser const & parser, + quoted_string_parser const & parser, std::ostream & os, int components) { @@ -707,10 +732,14 @@ namespace boost { namespace parser { namespace detail { os << ')'; } - template - void print_parser( + template< + typename Context, + bool NewlinesOnly, + bool NoNewlines, + typename ParserMods> + void print_parser_impl( Context const & context, - ws_parser const & parser, + ws_parser const & parser, std::ostream & os, int components) { @@ -722,10 +751,10 @@ namespace boost { namespace parser { namespace detail { os << "ws"; } - template - void print_parser( + template + void print_parser_impl( Context const & context, - bool_parser const & parser, + bool_parser const & parser, std::ostream & os, int components) { @@ -738,10 +767,17 @@ namespace boost { namespace parser { namespace detail { int Radix, int MinDigits, int MaxDigits, - typename Expected> - void print_parser( + typename Expected, + typename ParserMods> + void print_parser_impl( Context const & context, - uint_parser const & parser, + uint_parser< + T, + Radix, + MinDigits, + MaxDigits, + Expected, + ParserMods> const & parser, std::ostream & os, int components) { @@ -782,27 +818,29 @@ namespace boost { namespace parser { namespace detail { int Radix, int MinDigits, int MaxDigits, - typename Expected> - void print_parser( + typename Expected, + typename ParserMods> + void print_parser_impl( Context const & context, - int_parser const & parser, + int_parser const & + parser, std::ostream & os, int components) { if (Radix == 10 && MinDigits == 1 && MaxDigits == -1) { - if (std::is_same_v) { + if constexpr (std::is_same_v) { os << "short_"; detail::print_expected(context, os, parser.expected_); return; - } else if (std::is_same_v) { + } else if constexpr (std::is_same_v) { os << "int_"; detail::print_expected(context, os, parser.expected_); return; - } else if (std::is_same_v) { + } else if constexpr (std::is_same_v) { os << "long_"; detail::print_expected(context, os, parser.expected_); return; - } else if (std::is_same_v) { + } else if constexpr (std::is_same_v) { os << "long_long"; detail::print_expected(context, os, parser.expected_); return; @@ -812,61 +850,31 @@ namespace boost { namespace parser { namespace detail { << MinDigits << ", " << MaxDigits << ">"; detail::print_expected(context, os, parser.expected_); } - - template - void print_parser( - Context const & context, - int_parser const & parser, - std::ostream & os, - int components) - { - os << "short_"; - } - - template - void print_parser( - Context const & context, - int_parser const & parser, - std::ostream & os, - int components) - { - os << "long_"; - } - - template - void print_parser( - Context const & context, - int_parser const & parser, - std::ostream & os, - int components) - { - os << "long_long"; - } - - template - void print_parser( + + template + void print_parser_impl( Context const & context, - float_parser const & parser, + float_parser const & parser, std::ostream & os, int components) { os << "float<" << detail::type_name() << ">"; } - template - void print_parser( + template + void print_parser_impl( Context const & context, - float_parser const & parser, + float_parser const & parser, std::ostream & os, int components) { os << "float_"; } - template - void print_parser( + template + void print_parser_impl( Context const & context, - float_parser const & parser, + float_parser const & parser, std::ostream & os, int components) { @@ -877,10 +885,11 @@ namespace boost { namespace parser { namespace detail { typename Context, typename ParserTuple, typename BacktrackingTuple, - typename CombiningGroups> + typename CombiningGroups, + typename ParserMods> void print_switch_matchers( Context const & context, - seq_parser const & + seq_parser const & parser, std::ostream & os, int components) @@ -892,15 +901,15 @@ namespace boost { namespace parser { namespace detail { detail::resolve( context, parser::get(parser.parsers_, 0_c).pred_.value_)); os << ", "; - detail::print_parser( + detail::print_parser_impl( context, parser::get(parser.parsers_, 1_c), os, components); os << ")"; } - template + template void print_switch_matchers( Context const & context, - or_parser const & parser, + or_parser const & parser, std::ostream & os, int components) { @@ -919,10 +928,14 @@ namespace boost { namespace parser { namespace detail { }); } - template - void print_parser( + template< + typename Context, + typename SwitchValue, + typename OrParser, + typename ParserMods> + void print_parser_impl( Context const & context, - switch_parser const & parser, + switch_parser const & parser, std::ostream & os, int components) { @@ -933,6 +946,67 @@ namespace boost { namespace parser { namespace detail { context, parser.or_parser_, os, components); } + template + struct scoped_print_parser_mods + { + template + scoped_print_parser_mods(std::ostream & os, Parser const & parser) : + os_(os), mods_(parser.mods_) + { + if constexpr (ParserMods::omit_attr) { + skip_omit_ = skip_omit(parser); + if (!skip_omit_) + os_ << "omit["; + } + } + ~scoped_print_parser_mods() + { + if constexpr (ParserMods::omit_attr) { + if (!skip_omit_) + os_ << "]"; + } + } + + template + static bool skip_omit(T const &) + { + return false; + } + template< + typename Expected, + typename AttributeType, + typename ParserMods2> + static bool + skip_omit(char_parser const &) + { + return !std::is_same_v; + } + template + static bool + skip_omit(string_parser const &) + { + return true; + } + + std::ostream & os_; + ParserMods const & mods_; + bool skip_omit_ = false; + }; + + // TODO: Document how 'omit[]' will reappear for subparsers sometimes, as + // in omt[*omit[char_]] (see test/tracing.cpp). + template + void print_parser( + Context const & context, + Parser const & parser, + std::ostream & os, + int components) + { + scoped_print_parser_mods> _( + os, parser); + detail::print_parser_impl(context, parser, os, components); + } + }}} #endif diff --git a/include/boost/parser/parser.hpp b/include/boost/parser/parser.hpp index 74faba22..32fe8afa 100644 --- a/include/boost/parser/parser.hpp +++ b/include/boost/parser/parser.hpp @@ -387,7 +387,11 @@ namespace boost { namespace parser { return *this; } - operator std::nullopt_t() const noexcept { return std::nullopt; } + template + operator T() const noexcept + { + return {}; + } template constexpr bool operator()(Context const &) const noexcept @@ -984,15 +988,16 @@ namespace boost { namespace parser { template struct is_eps_p : std::false_type {}; - template - struct is_eps_p> : std::true_type + template + struct is_eps_p> : std::true_type {}; template struct is_unconditional_eps : std::false_type {}; - template<> - struct is_unconditional_eps> : std::true_type + template + struct is_unconditional_eps> + : std::true_type {}; template constexpr bool is_unconditional_eps_v = @@ -1001,36 +1006,36 @@ namespace boost { namespace parser { template struct is_zero_plus_p : std::false_type {}; - template - struct is_zero_plus_p> : std::true_type + template + struct is_zero_plus_p> : std::true_type {}; template struct is_or_p : std::false_type {}; - template - struct is_or_p> : std::true_type + template + struct is_or_p> : std::true_type {}; template struct is_perm_p : std::false_type {}; - template - struct is_perm_p> : std::true_type + template + struct is_perm_p> : std::true_type {}; template struct is_seq_p : std::false_type {}; - template - struct is_seq_p> : std::true_type + template + struct is_seq_p> : std::true_type {}; template struct is_one_plus_p : std::false_type {}; - template - struct is_one_plus_p> : std::true_type + template + struct is_one_plus_p> : std::true_type {}; template @@ -1349,11 +1354,15 @@ namespace boost { namespace parser { #endif ); + template + constexpr auto gen_attrs() + { + return std::bool_constant{}; + } + template - void append(Container & c, T && x, bool gen_attrs) + void append(Container & c, T && x) { - if (!gen_attrs) - return; if constexpr (needs_transcoding_to_utf8) { char32_t cps[1] = {(char32_t)x}; auto const r = cps | text::as_utf8; @@ -1364,30 +1373,26 @@ namespace boost { namespace parser { } template - void append(std::optional & c, T && x, bool gen_attrs) + void append(std::optional & c, T && x) { - if (!gen_attrs) - return; if (!c) c = Container(); - return detail::append(*c, (T &&) x, gen_attrs); + detail::append(*c, (T &&)x, gen_attrs); } template - void append(Container & c, nope &&, bool) + void append(Container & c, nope &&) {} template - void append(nope &, T &&, bool) + void append(nope &, T &&) {} - inline void append(nope &, nope &&, bool) {} + inline void append(nope &, nope &&) {} template - void append(Container & c, Iter first, Sentinel last, bool gen_attrs) + void append(Container & c, Iter first, Sentinel last) { - if (!gen_attrs) - return; if constexpr (needs_transcoding_to_utf8< Container, iter_value_t>) { @@ -1400,21 +1405,15 @@ namespace boost { namespace parser { } template - void append( - std::optional & c, - Iter first, - Sentinel last, - bool gen_attrs) + void append(std::optional & c, Iter first, Sentinel last) { - if (!gen_attrs) - return; if (!c) c = Container(); - return detail::append(*c, first, last, gen_attrs); + detail::append(*c, first, last); } template - void append(nope &, Iter first, Sentinel last, bool gen_attrs) + void append(nope &, Iter first, Sentinel last) {} constexpr inline flags default_flags() @@ -1450,11 +1449,6 @@ namespace boost { namespace parser { { return flags(uint32_t(f) | uint32_t(flags::in_apply_parser)); } - constexpr inline bool gen_attrs(flags f) - { - return (uint32_t(f) & uint32_t(flags::gen_attrs)) == - uint32_t(flags::gen_attrs); - } constexpr inline bool use_skip(flags f) { return (uint32_t(f) & uint32_t(flags::use_skip)) == @@ -1643,6 +1637,9 @@ namespace boost { namespace parser { V base_; }; + template + struct symbol_parser_impl; + enum class symbol_table_op { insert, erase, clear }; template @@ -1694,7 +1691,7 @@ namespace boost { namespace parser { template auto get_trie( - Context const & context, symbol_parser const & sym_parser) + Context const & context, symbol_parser_impl const & sym_parser) { using trie_t = text::trie_map, T>; using result_type = std::pair; @@ -1735,7 +1732,7 @@ namespace boost { namespace parser { template decltype(auto) get_pending_symtab_ops( - Context const & context, symbol_parser const & sym_parser) + Context const & context, symbol_parser_impl const & sym_parser) { void const * ptr = static_cast(&sym_parser); auto & entry = (*context.pending_symbol_table_operations_)[ptr]; @@ -1757,6 +1754,121 @@ namespace boost { namespace parser { return *retval; } + template + struct symbol_parser_impl + { + symbol_parser_impl() : copied_from_(nullptr) {} + explicit symbol_parser_impl(std::string_view diagnostic_text) : + copied_from_(nullptr), diagnostic_text_(diagnostic_text) + {} + symbol_parser_impl(symbol_parser_impl const & other) : + initial_elements_(other.initial_elements_), + copied_from_(other.copied_from_ ? other.copied_from_ : &other), + diagnostic_text_(other.diagnostic_text_) + {} + symbol_parser_impl(symbol_parser_impl && other) : + initial_elements_(std::move(other.initial_elements_)), + copied_from_(other.copied_from_), + diagnostic_text_(other.diagnostic_text_) + {} + + template + void insert_for_next_parse( + Context const & context, std::string_view str, T x) + { + auto & pending_ops = + detail::get_pending_symtab_ops(context, ref()); + pending_ops.push_back(detail::symbol_table_operation{ + std::string(str), + std::move(x), + detail::symbol_table_op::insert}); + } + + template + void + erase_for_next_parse(Context const & context, std::string_view str) + { + auto & pending_ops = + detail::get_pending_symtab_ops(context, ref()); + pending_ops.push_back(detail::symbol_table_operation{ + std::string(str), + std::nullopt, + detail::symbol_table_op::erase}); + } + + template + void clear_for_next_parse(Context const & context) + { + auto & pending_ops = + detail::get_pending_symtab_ops(context, ref()); + pending_ops.push_back(detail::symbol_table_operation{ + {}, std::nullopt, detail::symbol_table_op::clear}); + } + + template + parser::detail::text::optional_ref + find(Context const & context, std::string_view str) const + { + auto [trie, has_case_folded] = detail::get_trie(context, ref()); + if (context.no_case_depth_) { + return trie[detail::case_fold_view( + str | detail::text::as_utf32)]; + } else { + return trie[str | detail::text::as_utf32]; + } + } + + template + void + insert(Context const & context, std::string_view str, T && x) const + { + auto [trie, has_case_folded] = detail::get_trie(context, ref()); + if (context.no_case_depth_) { + trie.insert( + detail::case_fold_view(str | detail::text::as_utf32), + std::move(x)); + } else { + trie.insert(str | detail::text::as_utf32, std::move(x)); + } + } + + template + void erase(Context const & context, std::string_view str) const + { + auto [trie, has_case_folded] = detail::get_trie(context, ref()); + if (context.no_case_depth_) { + trie.erase( + detail::case_fold_view(str | detail::text::as_utf32)); + } else { + trie.erase(str | detail::text::as_utf32); + } + } + + template + void clear(Context const & context) const + { + auto [trie, _] = detail::get_trie(context, ref()); + trie.clear(); + } + + mutable std::vector> initial_elements_; + symbol_parser_impl const * copied_from_; + + symbol_parser_impl const & ref() const noexcept + { + if (copied_from_) + return *copied_from_; + return *this; + } + std::vector> & + initial_elements() const noexcept + { + return ref().initial_elements_; + } + + std::string_view diagnostic_text_; + }; + template<> struct char_subranges { @@ -2025,35 +2137,29 @@ namespace boost { namespace parser { } template - constexpr void move_back(Container & c, T && x, bool gen_attrs) + constexpr void move_back(Container & c, T && x) { - if (!gen_attrs) - return; detail::move_back_impl(c, std::move(x)); } template - constexpr void move_back(Container & c, Container & x, bool gen_attrs) + constexpr void move_back(Container & c, Container & x) { - if (!gen_attrs) - return; c.insert(c.end(), x.begin(), x.end()); } template - constexpr void - move_back(Container & c, std::optional && x, bool gen_attrs) + constexpr void move_back(Container & c, std::optional && x) { - if (!gen_attrs || !x) + if (!x) return; c.insert(c.end(), x->begin(), x->end()); } template - constexpr void - move_back(Container & c, std::optional & x, bool gen_attrs) + constexpr void move_back(Container & c, std::optional & x) { - if (!gen_attrs || !x) + if (!x) return; detail::move_back_impl(c, std::move(*x)); } @@ -2062,18 +2168,17 @@ namespace boost { namespace parser { typename Container, typename T, typename Enable = std::enable_if_t>> - constexpr void - move_back(Container & c, std::optional && x, bool gen_attrs) + constexpr void move_back(Container & c, std::optional && x) { - if (!gen_attrs || !x) + if (!x) return; detail::move_back_impl(c, std::move(*x)); } - constexpr void move_back(nope, nope, bool gen_attrs) {} + inline constexpr void move_back(nope, nope) {} template - constexpr void move_back(Container & c, nope, bool gen_attrs) + constexpr void move_back(Container & c, nope) {} template @@ -2850,11 +2955,38 @@ namespace boost { namespace parser { T * x_; }; - template - constexpr auto omit_attr(ParserMods const &) + template + auto modify_parsers_impl( + F f, Parsers parsers, std::integer_sequence) { - return ParserMods::omit_attr; + return hl::make_tuple( + parser::get(parsers, llong{}).with_parser_mods(f)...); } + template + auto modify_parsers(F f, tuple parsers) + { + return modify_parsers_impl( + f, + parsers, + std::make_integer_sequence{}); + } + + inline constexpr struct omit_attr_t + { + template + constexpr auto operator()(parser_modifiers const &) const + { + return parser_modifiers{}; + } + } omit_attr; + + template + using final_attribute_type_impl = + std::conditional_t; + + template + using final_attribute_type = + final_attribute_type_impl; } #ifndef BOOST_PARSER_DOXYGEN @@ -3002,7 +3134,8 @@ namespace boost { namespace parser { typename Parser, typename DelimiterParser, typename MinType, - typename MaxType> + typename MaxType, + typename ParserMods> struct repeat_parser { constexpr repeat_parser( @@ -3016,7 +3149,20 @@ namespace boost { namespace parser { max_(_max) {} - template< + constexpr repeat_parser( + Parser parser, + DelimiterParser delimiter_parser, + MinType _min, + MaxType _max, + ParserMods mods) : + parser_(parser), + delimiter_parser_(delimiter_parser), + min_(_min), + max_(_max), + mods_(std::move(mods)) + {} + + template< typename Iter, typename Sentinel, typename Context, @@ -3033,7 +3179,10 @@ namespace boost { namespace parser { first, last, context, skip, flags, success)); auto retval = detail::make_sequence_of(); call(first, last, context, skip, flags, success, retval); - return retval; + if constexpr (detail::gen_attrs()) + return retval; + else + return detail::nope{}; } template< @@ -3071,8 +3220,10 @@ namespace boost { namespace parser { detail::set_in_apply_parser(flags), success, attr); - if (success) - retval = std::move(attr); + if constexpr (detail::gen_attrs()) { + if (success) + retval = std::move(attr); + } } else { // Otherwise, Attribute must be a container or a nope. using attr_t = detail::parser_attr_or_container_value_type_v< decltype(parser_.call( @@ -3088,11 +3239,12 @@ namespace boost { namespace parser { parser_.call( first, last, context, skip, flags, success, attr); if (!success) { - detail::assign(retval, Attribute()); + if constexpr (detail::gen_attrs()) + detail::assign(retval, Attribute()); return; } - detail::move_back( - retval, std::move(attr), detail::gen_attrs(flags)); + if constexpr (detail::gen_attrs()) + detail::move_back(retval, std::move(attr)); } int64_t const end = detail::resolve(context, max_); @@ -3132,50 +3284,116 @@ namespace boost { namespace parser { first = prev_first; break; } - detail::move_back( - retval, std::move(attr), detail::gen_attrs(flags)); + if constexpr (detail::gen_attrs()) + detail::move_back(retval, std::move(attr)); } } } + template + constexpr auto with_parser_mods(F f) const + { + if constexpr (std::is_same_v) { + return parser::repeat_parser( + parser_.with_parser_mods(f), + detail::nope{}, + min_, + max_, + f(mods_)); + } else { + return parser::repeat_parser( + parser_.with_parser_mods(f), + delimiter_parser_.with_parser_mods(f), + min_, + max_, + f(mods_)); + } + } + Parser parser_; DelimiterParser delimiter_parser_; MinType min_; MaxType max_; + [[no_unique_address]] ParserMods mods_; }; #endif - template - struct zero_plus_parser : repeat_parser + template + struct zero_plus_parser + : repeat_parser { - constexpr zero_plus_parser(Parser parser) : - repeat_parser(parser, 0, Inf) + using base_type = + repeat_parser; + + constexpr zero_plus_parser(Parser parser) : base_type(parser, 0, Inf) {} + constexpr zero_plus_parser(Parser parser, ParserMods mods) : + base_type(parser, detail::nope{}, 0, Inf, mods) {} + + template + constexpr auto with_parser_mods(F f) const + { + return parser::zero_plus_parser( + this->parser_.with_parser_mods(f), f(this->mods_)); + } }; - template - struct one_plus_parser : repeat_parser + template + struct one_plus_parser + : repeat_parser { - constexpr one_plus_parser(Parser parser) : - repeat_parser(parser, 1, Inf) + using base_type = + repeat_parser; + + constexpr one_plus_parser(Parser parser) : base_type(parser, 1, Inf) {} + constexpr one_plus_parser(Parser parser, ParserMods mods) : + base_type(parser, detail::nope{}, 1, Inf, mods) {} + + template + constexpr auto with_parser_mods(F f) const + { + return parser::one_plus_parser( + this->parser_.with_parser_mods(f), f(this->mods_)); + } }; - template - struct delimited_seq_parser : repeat_parser + template + struct delimited_seq_parser + : repeat_parser { + using base_type = + repeat_parser; + constexpr delimited_seq_parser( Parser parser, DelimiterParser delimiter_parser) : - repeat_parser( - parser, 1, Inf, delimiter_parser) + base_type(parser, 1, Inf, delimiter_parser) + {} + constexpr delimited_seq_parser( + Parser parser, DelimiterParser delimiter_parser, ParserMods mods) : + base_type(parser, delimiter_parser, 1, Inf, mods) {} + + template + constexpr auto with_parser_mods(F f) const + { + return parser::delimited_seq_parser( + this->parser_.with_parser_mods(f), + this->delimiter_parser_.with_parser_mods(f), + f(this->mods_)); + } }; //[ opt_parser_beginning - template + template struct opt_parser { //] + constexpr opt_parser(Parser parser) : parser_(parser) {} + constexpr opt_parser(Parser parser, ParserMods mods) : + parser_(parser), mods_(std::move(mods)) + {} + //[ opt_parser_attr_call template< typename Iter, @@ -3192,7 +3410,9 @@ namespace boost { namespace parser { { using attr_t = decltype(parser_.call( first, last, context, skip, flags, success)); - detail::optional_of retval; + detail:: + final_attribute_type, ParserMods> + retval; call(first, last, context, skip, flags, success, retval); return retval; } @@ -3224,7 +3444,7 @@ namespace boost { namespace parser { //] //[ opt_parser_no_gen_attr_path - if (!detail::gen_attrs(flags)) { + if (!detail::gen_attrs()) { parser_.call(first, last, context, skip, flags, success); success = true; return; @@ -3238,15 +3458,25 @@ namespace boost { namespace parser { } //] + template + constexpr auto with_parser_mods(F f) const + { + return parser::opt_parser(parser_.with_parser_mods(f), f(mods_)); + } + //[ opt_parser_end Parser parser_; + [[no_unique_address]] ParserMods mods_; }; //] - template + template struct or_parser { constexpr or_parser(ParserTuple parsers) : parsers_(parsers) {} + constexpr or_parser(ParserTuple parsers, ParserMods mods) : + parsers_(parsers), mods_(std::move(mods)) + {} #ifndef BOOST_PARSER_DOXYGEN @@ -3359,7 +3589,10 @@ namespace boost { namespace parser { result_t retval{}; call(first, last, context, skip, flags, success, retval); - return retval; + if constexpr (detail::gen_attrs()) + return retval; + else + return detail::nope{}; } template< @@ -3392,7 +3625,7 @@ namespace boost { namespace parser { &done](auto const & parser) { if (done) return; - if (detail::gen_attrs(flags)) + if constexpr (detail::gen_attrs()) use_parser(parser, retval); else use_parser(parser); @@ -3416,13 +3649,24 @@ namespace boost { namespace parser { #endif + template + constexpr auto with_parser_mods(F f) const + { + return parser::or_parser( + detail::modify_parsers(f, parsers_), f(mods_)); + } + ParserTuple parsers_; + [[no_unique_address]] ParserMods mods_; }; - template + template struct perm_parser { constexpr perm_parser(ParserTuple parsers) : parsers_(parsers) {} + constexpr perm_parser(ParserTuple parsers, ParserMods mods) : + parsers_(parsers), mods_(std::move(mods)) + {} #ifndef BOOST_PARSER_DOXYGEN @@ -3513,7 +3757,10 @@ namespace boost { namespace parser { if (success) first_ = first; - return retval; + if constexpr (detail::gen_attrs()) + return retval; + else + return detail::nope{}; } template< @@ -3546,8 +3793,10 @@ namespace boost { namespace parser { if constexpr (detail::is_optional_v) { typename Attribute::value_type attr; call(first, last, context, skip, flags, success, attr); - if (success) - detail::assign(retval, std::move(attr)); + if constexpr (detail::gen_attrs()) { + if (success) + detail::assign(retval, std::move(attr)); + } } else if constexpr ( detail::is_tuple{} || detail::is_struct_compatible_v) { @@ -3561,8 +3810,10 @@ namespace boost { namespace parser { retval, indices); - if (!success) - detail::assign(retval, Attribute()); + if constexpr (detail::gen_attrs()) { + if (!success) + detail::assign(retval, Attribute()); + } } else if constexpr (detail::is_constructible_from_tuple_v< Attribute, result_t>) { @@ -3577,11 +3828,13 @@ namespace boost { namespace parser { temp_retval, indices); - if (success && detail::gen_attrs(flags)) { - detail::assign( - retval, - detail::make_from_tuple( - std::move(temp_retval))); + if constexpr (detail::gen_attrs()) { + if (success) { + detail::assign( + retval, + detail::make_from_tuple( + std::move(temp_retval))); + } } } else { #if 0 // TODO Seems incompatible with this parser. @@ -3597,9 +3850,11 @@ namespace boost { namespace parser { temp_retval, indices); - if (success && detail::gen_attrs(flags)) { - detail::assign( - retval, std::move(detail::hl::front(temp_retval))); + if constexpr (detail::gen_attrs()) { + if (success) { + detail::assign( + retval, std::move(detail::hl::front(temp_retval))); + } } #else static_assert( @@ -3672,7 +3927,15 @@ namespace boost { namespace parser { #endif + template + constexpr auto with_parser_mods(F f) const + { + return parser::perm_parser( + detail::modify_parsers(f, parsers_), f(mods_)); + } + ParserTuple parsers_; + [[no_unique_address]] ParserMods mods_; }; namespace detail { @@ -3816,13 +4079,17 @@ namespace boost { namespace parser { template< typename ParserTuple, typename BacktrackingTuple, - typename CombiningGroups> + typename CombiningGroups, + typename ParserMods> struct seq_parser { using backtracking = BacktrackingTuple; using combining_groups = CombiningGroups; constexpr seq_parser(ParserTuple parsers) : parsers_(parsers) {} + constexpr seq_parser(ParserTuple parsers, ParserMods mods) : + parsers_(parsers), mods_(std::move(mods)) + {} static constexpr auto true_ = std::true_type{}; static constexpr auto false_ = std::false_type{}; @@ -4175,11 +4442,15 @@ namespace boost { namespace parser { first_ = first; // A 1-tuple is converted to a scalar. - if constexpr (detail::hl::size(retval) == llong<1>{}) { - using namespace literals; - return parser::get(retval, 0_c); + if constexpr (detail::gen_attrs()) { + if constexpr (detail::hl::size(retval) == llong<1>{}) { + using namespace literals; + return parser::get(retval, 0_c); + } else { + return retval; + } } else { - return retval; + return detail::nope{}; } } @@ -4230,8 +4501,10 @@ namespace boost { namespace parser { if constexpr (detail::is_optional_v) { typename Attribute::value_type attr; call(first, last, context, skip, flags, success, attr); - if (success) - detail::assign(retval, std::move(attr)); + if constexpr (detail::gen_attrs()) { + if (success) + detail::assign(retval, std::move(attr)); + } } else if constexpr ( detail::is_tuple{} || detail::is_struct_compatible_v) { @@ -4246,8 +4519,10 @@ namespace boost { namespace parser { indices, merged); - if (!success) - detail::assign(retval, Attribute()); + if constexpr (detail::gen_attrs()) { + if (!success) + detail::assign(retval, Attribute()); + } } else if constexpr ( 0 < max_index_t::value && detail::is_constructible_from_tuple_v< Attribute, @@ -4264,11 +4539,13 @@ namespace boost { namespace parser { indices, merged); - if (success && detail::gen_attrs(flags)) { - detail::assign( - retval, - detail::make_from_tuple( - std::move(temp_retval))); + if constexpr (detail::gen_attrs()) { + if (success) { + detail::assign( + retval, + detail::make_from_tuple( + std::move(temp_retval))); + } } } else { // call_impl requires a tuple, so we must wrap this scalar. @@ -4284,9 +4561,11 @@ namespace boost { namespace parser { indices, merged); - if (success && detail::gen_attrs(flags)) { - detail::assign( - retval, std::move(detail::hl::front(temp_retval))); + if constexpr (detail::gen_attrs()) { + if (success) { + detail::assign( + retval, std::move(detail::hl::front(temp_retval))); + } } } @@ -4348,7 +4627,7 @@ namespace boost { namespace parser { bool const can_backtrack = parser::get(parser_index_merged_and_backtrack, 3_c); - if (!detail::gen_attrs(flags)) { + if constexpr (!detail::gen_attrs()) { parser.call(first, last, context, skip, flags, success); if (!success && !can_backtrack) { std::stringstream oss; @@ -4418,8 +4697,7 @@ namespace boost { namespace parser { !std::is_integral_v)) { detail::assign(out, std::move(x)); } else { - detail::move_back( - out, std::move(x), detail::gen_attrs(flags)); + detail::move_back(out, std::move(x)); } } }; @@ -4434,7 +4712,20 @@ namespace boost { namespace parser { template constexpr auto append(parser_interface parser) const noexcept; + template + constexpr auto with_parser_mods(F f) const + { + auto parsers = detail::modify_parsers(f, parsers_); + auto mods = f(mods_); + return seq_parser< + decltype(parsers), + BacktrackingTuple, + CombiningGroups, + decltype(mods)>(std::move(parsers), std::move(mods)); + } + ParserTuple parsers_; + [[no_unique_address]] ParserMods mods_; }; #endif @@ -4511,9 +4802,17 @@ namespace boost { namespace parser { #ifndef BOOST_PARSER_DOXYGEN - template + // TODO: Consider turning the action into a mod data member. + template struct action_parser { + constexpr action_parser(Parser parser, Action action) : + parser_(parser), action_(action) + {} + constexpr action_parser(Parser parser, Action action, ParserMods mods) : + parser_(parser), action_(action), mods_(std::move(mods)) + {} + template< typename Iter, typename Sentinel, @@ -4593,13 +4892,29 @@ namespace boost { namespace parser { } } + template + constexpr auto with_parser_mods(F f) const + { + return parser::action_parser( + parser_.with_parser_mods(f), action_, f(mods_)); + } + Parser parser_; Action action_; + [[no_unique_address]] ParserMods mods_; }; - template + // TODO: Consider turning this into a mod data member, same with raw_- and + // string_view_parser. + template struct transform_parser { + constexpr transform_parser(Parser parser, F f) : parser_(parser), f_(f) + {} + constexpr transform_parser(Parser parser, F f, ParserMods mods) : + parser_(parser), f_(f), mods_(std::move(mods)) + {} + template< typename Iter, typename Sentinel, @@ -4617,10 +4932,14 @@ namespace boost { namespace parser { *this, first, last, context, flags, detail::global_nope); auto attr = parser_.call(first, last, context, skip, flags, success); - if (success && detail::gen_attrs(flags)) - return f_(std::move(attr)); - else - return decltype(f_(std::move(attr))){}; + if constexpr (detail::gen_attrs()) { + if (success) + return f_(std::move(attr)); + else + return decltype(f_(std::move(attr))){}; + } else { + return detail::nope{}; + } } template< @@ -4642,41 +4961,52 @@ namespace boost { namespace parser { *this, first, last, context, flags, retval); auto attr = parser_.call(first, last, context, skip, flags, success); - if (success && detail::gen_attrs(flags)) - detail::assign(retval, f_(std::move(attr))); + if constexpr (detail::gen_attrs()) { + if (success) + detail::assign(retval, f_(std::move(attr))); + } + } + + template + constexpr auto with_parser_mods(F2 f) const + { + return parser::transform_parser( + parser_.with_parser_mods(f), f_, f(mods_)); } Parser parser_; F f_; + [[no_unique_address]] ParserMods mods_; }; - template - struct omit_parser + template + struct raw_parser { + constexpr raw_parser(Parser parser) : parser_(parser) {} + constexpr raw_parser(Parser parser, ParserMods mods) : + parser_(parser), mods_(std::move(mods)) + {} + template< typename Iter, typename Sentinel, typename Context, typename SkipParser> - detail::nope call( + auto call( Iter & first, Sentinel last, Context const & context, SkipParser const & skip, detail::flags flags, bool & success) const + -> detail:: + final_attribute_type, ParserMods> { - [[maybe_unused]] auto _ = detail::scoped_trace( - *this, first, last, context, flags, detail::global_nope); - - parser_.call( - first, - last, - context, - skip, - detail::disable_attrs(flags), - success); - return {}; + detail:: + final_attribute_type, ParserMods> + retval; + call(first, last, context, skip, flags, success, retval); + return retval; } template< @@ -4697,6 +5027,7 @@ namespace boost { namespace parser { [[maybe_unused]] auto _ = detail::scoped_trace( *this, first, last, context, flags, retval); + auto const initial_first = first; parser_.call( first, last, @@ -4704,20 +5035,40 @@ namespace boost { namespace parser { skip, detail::disable_attrs(flags), success); + if constexpr (detail::gen_attrs()) { + if (success) { + detail::assign( + retval, + BOOST_PARSER_SUBRANGE(initial_first, first)); + } + } + } + + template + constexpr auto with_parser_mods(F f) const + { + return parser::raw_parser(parser_.with_parser_mods(f), f(mods_)); } Parser parser_; + [[no_unique_address]] ParserMods mods_; }; - template - struct raw_parser +#if BOOST_PARSER_USE_CONCEPTS + template + struct string_view_parser { + constexpr string_view_parser(Parser parser) : parser_(parser) {} + constexpr string_view_parser(Parser parser, ParserMods mods) : + parser_(parser), mods_(std::move(mods)) + {} + template< typename Iter, typename Sentinel, typename Context, typename SkipParser> - BOOST_PARSER_SUBRANGE call( + auto call( Iter & first, Sentinel last, Context const & context, @@ -4725,7 +5076,19 @@ namespace boost { namespace parser { detail::flags flags, bool & success) const { - BOOST_PARSER_SUBRANGE retval; + auto r = + parser::detail::text::unpack_iterator_and_sentinel(first, last); + static_assert( + std::contiguous_iterator, + "string_view_parser and the string_view[] directive that uses " + "it requires that the underlying char sequence being parsed be " + "a contiguous range. If you're seeing this static_assert, you " + "have not met this contract."); + using char_type = detail::remove_cv_ref_t; + detail::final_attribute_type< + std::basic_string_view, + ParserMods> + retval; call(first, last, context, skip, flags, success, retval); return retval; } @@ -4756,101 +5119,52 @@ namespace boost { namespace parser { skip, detail::disable_attrs(flags), success); - if (success && detail::gen_attrs(flags)) - detail::assign( - retval, BOOST_PARSER_SUBRANGE(initial_first, first)); - } - Parser parser_; - }; + if (!success || !detail::gen_attrs()) + return; -#if BOOST_PARSER_USE_CONCEPTS - template - struct string_view_parser - { - template< - typename Iter, - typename Sentinel, - typename Context, - typename SkipParser> - auto call( - Iter & first, - Sentinel last, - Context const & context, - SkipParser const & skip, - detail::flags flags, - bool & success) const - { - auto r = - parser::detail::text::unpack_iterator_and_sentinel(first, last); - static_assert( - std::contiguous_iterator, - "string_view_parser and the string_view[] directive that uses " - "it requires that the underlying char sequence being parsed be " - "a contiguous range. If you're seeing this static_assert, you " - "have not met this contract."); - using char_type = detail::remove_cv_ref_t; - std::basic_string_view retval; - call(first, last, context, skip, flags, success, retval); - return retval; + if constexpr (detail::gen_attrs()) { + auto r = parser::detail::text::unpack_iterator_and_sentinel( + initial_first, first); + static_assert( + std::contiguous_iterator, + "string_view_parser and the string_view[] directive that " + "uses it requires that the underlying char sequence being " + "parsed be a contiguous range. If you're seeing this " + "static_assert, you have not met this contract."); + using char_type = detail::remove_cv_ref_t; + if (initial_first == first) { + detail::assign(retval, std::basic_string_view{}); + } else { + detail::assign( + retval, + std::basic_string_view{ + &*r.first, std::size_t(r.last - r.first)}); + } + } } - template< - typename Iter, - typename Sentinel, - typename Context, - typename SkipParser, - typename Attribute> - void call( - Iter & first, - Sentinel last, - Context const & context, - SkipParser const & skip, - detail::flags flags, - bool & success, - Attribute & retval) const + template + constexpr auto with_parser_mods(F f) const { - [[maybe_unused]] auto _ = detail::scoped_trace( - *this, first, last, context, flags, retval); - - auto const initial_first = first; - parser_.call( - first, - last, - context, - skip, - detail::disable_attrs(flags), - success); - - if (!success || !detail::gen_attrs(flags)) - return; - - auto r = parser::detail::text::unpack_iterator_and_sentinel( - initial_first, first); - static_assert( - std::contiguous_iterator, - "string_view_parser and the string_view[] directive that uses " - "it requires that the underlying char sequence being parsed be " - "a contiguous range. If you're seeing this static_assert, you " - "have not met this contract."); - using char_type = detail::remove_cv_ref_t; - if (initial_first == first) { - detail::assign(retval, std::basic_string_view{}); - } else { - detail::assign( - retval, - std::basic_string_view{ - &*r.first, std::size_t(r.last - r.first)}); - } + return parser::string_view_parser( + parser_.with_parser_mods(f), f(mods_)); } Parser parser_; + [[no_unique_address]] ParserMods mods_; }; #endif - template + // TODO: -> mod + template struct lexeme_parser { + constexpr lexeme_parser(Parser parser) : parser_(parser) {} + constexpr lexeme_parser(Parser parser, ParserMods mods) : + parser_(parser), mods_(std::move(mods)) + {} + template< typename Iter, typename Sentinel, @@ -4866,7 +5180,7 @@ namespace boost { namespace parser { { using attr_t = decltype(parser_.call( first, last, context, skip, flags, success)); - attr_t retval{}; + detail::final_attribute_type retval{}; call(first, last, context, skip, flags, success, retval); return retval; } @@ -4899,12 +5213,25 @@ namespace boost { namespace parser { retval); } + template + constexpr auto with_parser_mods(F f) const + { + return parser::lexeme_parser(parser_.with_parser_mods(f), f(mods_)); + } + Parser parser_; + [[no_unique_address]] ParserMods mods_; }; - template + // TODO: -> mod + template struct no_case_parser { + constexpr no_case_parser(Parser parser) : parser_(parser) {} + constexpr no_case_parser(Parser parser, ParserMods mods) : + parser_(parser), mods_(std::move(mods)) + {} + template< typename Iter, typename Sentinel, @@ -4923,7 +5250,7 @@ namespace boost { namespace parser { using attr_t = decltype(parser_.call( first, last, context, skip, flags, success)); - attr_t retval{}; + detail::final_attribute_type retval{}; call(first, last, context, skip, flags, success, retval); return retval; } @@ -4952,12 +5279,27 @@ namespace boost { namespace parser { parser_.call(first, last, context, skip, flags, success, retval); } + template + constexpr auto with_parser_mods(F f) const + { + return parser::no_case_parser( + parser_.with_parser_mods(f), f(mods_)); + } + Parser parser_; + [[no_unique_address]] ParserMods mods_; }; - template + template struct skip_parser { + constexpr skip_parser(Parser parser, SkipParser skip) : + parser_(parser), skip_parser_(skip) + {} + constexpr skip_parser(Parser parser, SkipParser skip, ParserMods mods) : + parser_(parser), skip_parser_(skip), mods_(std::move(mods)) + {} + template< typename Iter, typename Sentinel, @@ -4973,7 +5315,7 @@ namespace boost { namespace parser { { using attr_t = decltype(parser_.call( first, last, context, skip, flags, success)); - attr_t retval{}; + detail::final_attribute_type retval{}; call(first, last, context, skip, flags, success, retval); return retval; } @@ -5017,13 +5359,30 @@ namespace boost { namespace parser { } } + template + constexpr auto with_parser_mods(F f) const + { + return parser::skip_parser( + parser_.with_parser_mods(f), + skip_parser_.with_parser_mods(f), + f(mods_)); + } + Parser parser_; SkipParser skip_parser_; + [[no_unique_address]] ParserMods mods_; }; - template + // TODO: Consider adding expactation (pass/fail) as a mod property, and + // adding pre and post expectation parsers to the mod properties. + template struct expect_parser { + constexpr expect_parser(Parser parser) : parser_(parser) {} + constexpr expect_parser(Parser parser, ParserMods mods) : + parser_(parser), mods_(std::move(mods)) + {} + template< typename Iter, typename Sentinel, @@ -5072,68 +5431,67 @@ namespace boost { namespace parser { success = !success; } + template + constexpr auto with_parser_mods(F f) const + { + auto mods = f(mods_); + return expect_parser< + decltype(parser_.with_parser_mods(f)), + FailOnMatch, + decltype(mods)>{parser_.with_parser_mods(f), std::move(mods)}; + } + Parser parser_; + [[no_unique_address]] ParserMods mods_; }; - template - struct symbol_parser + template + struct symbol_parser : detail::symbol_parser_impl { - symbol_parser() : copied_from_(nullptr) {} + symbol_parser() : detail::symbol_parser_impl() {} explicit symbol_parser(std::string_view diagnostic_text) : - copied_from_(nullptr), diagnostic_text_(diagnostic_text) + detail::symbol_parser_impl(diagnostic_text) {} symbol_parser(symbol_parser const & other) : - initial_elements_(other.initial_elements_), - copied_from_(other.copied_from_ ? other.copied_from_ : &other), - diagnostic_text_(other.diagnostic_text_) + detail::symbol_parser_impl(other) {} symbol_parser(symbol_parser && other) : - initial_elements_(std::move(other.initial_elements_)), - copied_from_(other.copied_from_), - diagnostic_text_(other.diagnostic_text_) + detail::symbol_parser_impl(std::move(other)) + {} + template + symbol_parser( + symbol_parser const & other, ParserMods mods) : + detail::symbol_parser_impl(other), mods_(std::move(mods)) + {} + template + symbol_parser( + symbol_parser && other, ParserMods mods) : + detail::symbol_parser_impl(std::move(other)), + mods_(std::move(mods)) {} +#ifdef BOOST_PARSER_DOXYGEN + /** Inserts an entry consisting of a UTF-8 string `str` to match, and an associated attribute `x`, to `*this`. The entry is added for use in all subsequent top-level parses. Subsequent lookups during the current top-level parse will not necessarily match `str`. */ template void insert_for_next_parse( - Context const & context, std::string_view str, T x) - { - auto & pending_ops = - detail::get_pending_symtab_ops(context, ref()); - pending_ops.push_back(detail::symbol_table_operation{ - std::string(str), - std::move(x), - detail::symbol_table_op::insert}); - } + Context const & context, std::string_view str, T x); /** Erases the entry whose UTF-8 match string is `str`, from `*this`. The entry will no longer be available for use in all subsequent top-level parses. `str` will not be removed from the symbols matched in the current top-level parse. */ template - void erase_for_next_parse(Context const & context, std::string_view str) - { - auto & pending_ops = - detail::get_pending_symtab_ops(context, ref()); - pending_ops.push_back(detail::symbol_table_operation{ - std::string(str), - std::nullopt, - detail::symbol_table_op::erase}); - } + void + erase_for_next_parse(Context const & context, std::string_view str); /** Erases all the entries from the copy of the symbol table inside the parse context `context`. */ template - void clear_for_next_parse(Context const & context) - { - auto & pending_ops = - detail::get_pending_symtab_ops(context, ref()); - pending_ops.push_back(detail::symbol_table_operation{ - {}, std::nullopt, detail::symbol_table_op::clear}); - } + void clear_for_next_parse(Context const & context); /** Uses UTF-8 string `str` to look up an attribute in the table during parsing, returning it as an optional reference. The lookup @@ -5141,70 +5499,40 @@ namespace boost { namespace parser { `context`. */ template parser::detail::text::optional_ref - find(Context const & context, std::string_view str) const - { - auto [trie, has_case_folded] = detail::get_trie(context, ref()); - if (context.no_case_depth_) { - return trie[detail::case_fold_view( - str | detail::text::as_utf32)]; - } else { - return trie[str | detail::text::as_utf32]; - } - } + find(Context const & context, std::string_view str) const; /** Inserts an entry consisting of a UTF-8 string `str` to match, and an associtated attribute `x`, to the copy of the symbol table inside the parse context `context`. */ template - void insert(Context const & context, std::string_view str, T && x) const - { - auto [trie, has_case_folded] = detail::get_trie(context, ref()); - if (context.no_case_depth_) { - trie.insert( - detail::case_fold_view(str | detail::text::as_utf32), - std::move(x)); - } else { - trie.insert(str | detail::text::as_utf32, std::move(x)); - } - } + void insert(Context const & context, std::string_view str, T && x) const; /** Erases the entry whose UTF-8 match string is `str` from the copy of the symbol table inside the parse context `context`. */ template - void erase(Context const & context, std::string_view str) const - { - auto [trie, has_case_folded] = detail::get_trie(context, ref()); - if (context.no_case_depth_) { - trie.erase( - detail::case_fold_view(str | detail::text::as_utf32)); - } else { - trie.erase(str | detail::text::as_utf32); - } - } + void erase(Context const & context, std::string_view str) const; /** Erases the entry whose UTF-8 match string is `str` from the copy of the symbol table inside the parse context `context`. */ template - void clear(Context const & context) const - { - auto [trie, _] = detail::get_trie(context, ref()); - trie.clear(); - } + void clear(Context const & context) const; + +#endif template< typename Iter, typename Sentinel, typename Context, typename SkipParser> - T call( + auto call( Iter & first, Sentinel last, Context const & context, SkipParser const & skip, detail::flags flags, - bool & success) const + bool & success) const -> detail::final_attribute_type { - T retval{}; + detail::final_attribute_type retval{}; call(first, last, context, skip, flags, success, retval); return retval; } @@ -5227,35 +5555,35 @@ namespace boost { namespace parser { [[maybe_unused]] auto _ = detail::scoped_trace( *this, first, last, context, flags, retval); - auto [trie, _0] = detail::get_trie(context, ref()); + auto [trie, _0] = detail::get_trie(context, this->ref()); auto const lookup = context.no_case_depth_ ? trie.longest_match(detail::case_fold_view( BOOST_PARSER_SUBRANGE(first, last))) : trie.longest_match(first, last); if (lookup.match) { std::advance(first, lookup.size); - detail::assign(retval, T{*trie[lookup]}); + if constexpr (detail::gen_attrs()) + detail::assign(retval, T{*trie[lookup]}); } else { success = false; } } - mutable std::vector> initial_elements_; - symbol_parser const * copied_from_; - - symbol_parser const & ref() const noexcept + template + constexpr auto with_parser_mods(F f) const & { - if (copied_from_) - return *copied_from_; - return *this; + auto mods = f(mods_); + return symbol_parser(*this, std::move(mods)); } - std::vector> & - initial_elements() const noexcept + template + constexpr auto with_parser_mods(F f) const && { - return ref().initial_elements_; + auto mods = f(mods_); + return symbol_parser( + std::move(*this), std::move(mods)); } - std::string_view diagnostic_text_; + [[no_unique_address]] ParserMods mods_; }; template< @@ -5263,20 +5591,36 @@ namespace boost { namespace parser { typename TagType, typename Attribute, typename LocalState, - typename ParamsTuple> + typename ParamsTuple, + typename ParserMods> struct rule_parser { using tag_type = TagType; using attr_type = Attribute; using locals_type = LocalState; + constexpr rule_parser() {} + constexpr rule_parser( + std::string_view diagnostic_text, ParamsTuple params) : + diagnostic_text_(diagnostic_text), params_(params) + {} + constexpr rule_parser( + std::string_view diagnostic_text, + ParamsTuple params, + ParserMods mods) : + diagnostic_text_(diagnostic_text), + params_(params), + mods_(std::move(mods)) + {} + template< typename Iter, typename Sentinel, typename Context, typename SkipParser> std::conditional_t< - detail::in_recursion, + detail::in_recursion || + !detail::gen_attrs(), detail::nope, attr_type> call( @@ -5328,7 +5672,7 @@ namespace boost { namespace parser { success, dont_assign); if (success && !dont_assign) { - if constexpr (!detail::is_nope_v) + if constexpr (detail::gen_attrs()) detail::assign(retval, attr); } } @@ -5336,7 +5680,7 @@ namespace boost { namespace parser { if constexpr ( CanUseCallbacks && Context::use_callbacks && !in_recursion) { if (!success) - return attr_type{}; + return {}; auto const & callbacks = _callbacks(context); @@ -5361,10 +5705,12 @@ namespace boost { namespace parser { callbacks(tag_type{}, std::move(retval)); } - return attr_type{}; + return {}; } else { - if (!success && !in_recursion) - detail::assign(retval, attr_type()); + if constexpr (detail::gen_attrs()) { + if (!success && !in_recursion) + detail::assign(retval, attr_type()); + } if constexpr (in_recursion) return detail::nope{}; else @@ -5391,13 +5737,29 @@ namespace boost { namespace parser { call(first, last, context, skip, flags, success); } else { auto attr = call(first, last, context, skip, flags, success); - if (success) - detail::assign(retval, std::move(attr)); + if constexpr (detail::gen_attrs()) { + if (success) + detail::assign(retval, std::move(attr)); + } } } + template + constexpr auto with_parser_mods(F f) const + { + auto mods = f(mods_); + return rule_parser< + CanUseCallbacks, + TagType, + Attribute, + LocalState, + ParamsTuple, + decltype(mods)>(diagnostic_text_, params_, std::move(mods)); + } + std::string_view diagnostic_text_; ParamsTuple params_; + [[no_unique_address]] ParserMods mods_; }; #endif @@ -5424,7 +5786,7 @@ namespace boost { namespace parser { constexpr auto operator!() const noexcept { return parser::parser_interface{ - expect_parser{parser_}}; + expect_parser>{parser_}}; } /** Returns a `parser_interface` containing a parser equivalent to an @@ -5433,7 +5795,7 @@ namespace boost { namespace parser { constexpr auto operator&() const noexcept { return parser::parser_interface{ - expect_parser{parser_}}; + expect_parser>{parser_}}; } /** Returns a `parser_interface` containing a parser equivalent to a @@ -5445,10 +5807,11 @@ namespace boost { namespace parser { } else if constexpr (detail::is_one_plus_p{}) { using inner_parser = decltype(parser_type::parser_); return parser::parser_interface{ - zero_plus_parser(parser_.parser_)}; + zero_plus_parser>( + parser_.parser_)}; } else { return parser::parser_interface{ - zero_plus_parser(parser_)}; + zero_plus_parser>(parser_)}; } } @@ -5459,12 +5822,13 @@ namespace boost { namespace parser { if constexpr (detail::is_zero_plus_p{}) { using inner_parser = decltype(parser_type::parser_); return parser::parser_interface{ - zero_plus_parser(parser_.parser_)}; + zero_plus_parser>( + parser_.parser_)}; } else if constexpr (detail::is_one_plus_p{}) { return *this; } else { return parser::parser_interface{ - one_plus_parser(parser_)}; + one_plus_parser>(parser_)}; } } @@ -5472,7 +5836,8 @@ namespace boost { namespace parser { `opt_parser` containing `parser_`. */ constexpr auto operator-() const noexcept { - return parser::parser_interface{opt_parser{parser_}}; + return parser::parser_interface{ + opt_parser>{parser_}}; } /** Returns a `parser_interface` containing a parser equivalent to a @@ -5489,7 +5854,8 @@ namespace boost { namespace parser { using parser_t = seq_parser< tuple, tuple, - tuple, llong<0>>>; + tuple, llong<0>>, + parser_modifiers<>>; return parser::parser_interface{parser_t{ tuple{parser_, rhs.parser_}}}; } @@ -5532,7 +5898,8 @@ namespace boost { namespace parser { using parser_t = seq_parser< tuple, tuple, - tuple, llong<0>>>; + tuple, llong<0>>, + parser_modifiers<>>; return parser::parser_interface{parser_t{ tuple{parser_, rhs.parser_}}}; } @@ -5586,9 +5953,10 @@ namespace boost { namespace parser { // which also is meaningful, and so is allowed. BOOST_PARSER_ASSERT( !detail::is_unconditional_eps{}); - return parser::parser_interface{ - or_parser>{ - tuple{parser_, rhs.parser_}}}; + return parser::parser_interface{or_parser< + tuple, + parser_modifiers<>>{ + tuple{parser_, rhs.parser_}}}; } } @@ -5610,9 +5978,10 @@ namespace boost { namespace parser { } else if constexpr (detail::is_perm_p{}) { return rhs.parser_.prepend(*this); } else { - return parser::parser_interface{ - perm_parser>{ - tuple{parser_, rhs.parser_}}}; + return parser::parser_interface{perm_parser< + tuple, + parser_modifiers<>>{ + tuple{parser_, rhs.parser_}}}; } } @@ -5671,9 +6040,10 @@ namespace boost { namespace parser { constexpr auto operator%(parser_interface rhs) const noexcept { - return parser::parser_interface{ - delimited_seq_parser( - parser_, rhs.parser_)}; + return parser::parser_interface{delimited_seq_parser< + parser_type, + ParserType2, + parser_modifiers<>>(parser_, rhs.parser_)}; } /** Returns a `parser_interface` containing a parser equivalent to an @@ -5702,7 +6072,8 @@ namespace boost { namespace parser { template constexpr auto operator[](Action action) const { - using action_parser_t = action_parser; + using action_parser_t = + action_parser>; return parser::parser_interface{action_parser_t{parser_, action}}; } @@ -5803,13 +6174,13 @@ namespace boost { namespace parser { symbol table in the parse context. For table entries that should be used during every parse, add entries via `add()` or `operator()`. For mid-parse mutations, use `insert()` and `erase()`. */ - template - struct symbols : parser_interface> + template> + struct symbols : parser_interface> { symbols() {} symbols(char const * diagnostic_text) : - parser_interface>( - symbol_parser(diagnostic_text)) + parser_interface>( + symbol_parser(diagnostic_text)) {} symbols(std::initializer_list> il) { @@ -5820,8 +6191,8 @@ namespace boost { namespace parser { symbols( char const * diagnostic_text, std::initializer_list> il) : - parser_interface>( - symbol_parser(diagnostic_text)) + parser_interface>( + symbol_parser(diagnostic_text)) { this->parser_.initial_elements_.resize(il.size()); std::copy(il.begin(), il.end(), @@ -5923,83 +6294,93 @@ namespace boost { namespace parser { #ifndef BOOST_PARSER_DOXYGEN - template< - typename TagType, - typename Attribute, - typename LocalState, - typename ParamsTuple> - struct rule - : parser_interface< - rule_parser> - { - static_assert( - !std::is_same_v, - "void is not a valid tag type for a rule."); - - constexpr rule(char const * diagnostic_text) - { - this->parser_.diagnostic_text_ = diagnostic_text; - } - - template - constexpr auto with(T && x, Ts &&... xs) const - { - BOOST_PARSER_ASSERT( - (detail::is_nope_v && - "If you're seeing this, you tried to chain calls on a rule, " - "like 'rule.with(foo).with(bar)'. Quit it!'")); - using params_tuple_type = decltype(detail::hl::make_tuple( - static_cast(x), static_cast(xs)...)); - using rule_parser_type = rule_parser< - false, - TagType, - Attribute, - LocalState, - params_tuple_type>; - using result_type = parser_interface; - return result_type{rule_parser_type{ - this->parser_.diagnostic_text_, - detail::hl::make_tuple( - static_cast(x), static_cast(xs)...)}}; - } - }; - - template< - typename TagType, - typename Attribute, - typename LocalState, - typename ParamsTuple> - struct callback_rule - : parser_interface< - rule_parser> - { - constexpr callback_rule(char const * diagnostic_text) - { - this->parser_.diagnostic_text_ = diagnostic_text; - } + template< + typename TagType, + typename Attribute, + typename LocalState, + typename ParamsTuple> + struct rule : parser_interface>> + { + static_assert( + !std::is_same_v, + "void is not a valid tag type for a rule."); + + constexpr rule(char const * diagnostic_text) + { + this->parser_.diagnostic_text_ = diagnostic_text; + } + + template + constexpr auto with(T && x, Ts &&... xs) const + { + BOOST_PARSER_ASSERT( + (detail::is_nope_v && + "If you're seeing this, you tried to chain calls on a rule, " + "like 'rule.with(foo).with(bar)'. Quit it!'")); + using params_tuple_type = decltype(detail::hl::make_tuple( + static_cast(x), static_cast(xs)...)); + using rule_parser_type = rule_parser< + false, + TagType, + Attribute, + LocalState, + params_tuple_type, + parser_modifiers<>>; + using result_type = parser_interface; + return result_type{rule_parser_type{ + this->parser_.diagnostic_text_, + detail::hl::make_tuple( + static_cast(x), static_cast(xs)...)}}; + } + }; - template - constexpr auto with(T && x, Ts &&... xs) const - { - BOOST_PARSER_ASSERT( - (detail::is_nope_v && - "If you're seeing this, you tried to chain calls on a " - "callback_rule, like 'rule.with(foo).with(bar)'. Quit it!'")); - using params_tuple_type = decltype(detail::hl::make_tuple( - static_cast(x), static_cast(xs)...)); - using rule_parser_type = rule_parser< - true, - TagType, - Attribute, - LocalState, - params_tuple_type>; - using result_type = parser_interface; - return result_type{rule_parser_type{ - this->parser_.diagnostic_text_, - detail::hl::make_tuple( - static_cast(x), static_cast(xs)...)}}; - } - }; + template< + typename TagType, + typename Attribute, + typename LocalState, + typename ParamsTuple> + struct callback_rule : parser_interface>> + { + constexpr callback_rule(char const * diagnostic_text) + { + this->parser_.diagnostic_text_ = diagnostic_text; + } + + template + constexpr auto with(T && x, Ts &&... xs) const + { + BOOST_PARSER_ASSERT( + (detail::is_nope_v && + "If you're seeing this, you tried to chain calls on a " + "callback_rule, like 'rule.with(foo).with(bar)'. Quit it!'")); + using params_tuple_type = decltype(detail::hl::make_tuple( + static_cast(x), static_cast(xs)...)); + using rule_parser_type = rule_parser< + true, + TagType, + Attribute, + LocalState, + params_tuple_type, + parser_modifiers<>>; + using result_type = parser_interface; + return result_type{rule_parser_type{ + this->parser_.diagnostic_text_, + detail::hl::make_tuple( + static_cast(x), static_cast(xs)...)}}; + } + }; //[ define_rule_definition #define BOOST_PARSER_DEFINE_IMPL(_, rule_name_) \ @@ -6079,9 +6460,9 @@ namespace boost { namespace parser { #ifndef BOOST_PARSER_DOXYGEN - template + template template - constexpr auto or_parser::prepend( + constexpr auto or_parser::prepend( parser_interface parser) const noexcept { // If you're seeing this as a compile- or run-time failure, you've @@ -6094,14 +6475,14 @@ namespace boost { namespace parser { // eps, like "eps(condition) | (int_ | double_)", which also is // meaningful, and so is allowed. BOOST_PARSER_ASSERT(!detail::is_unconditional_eps{}); - return parser_interface{ - or_parser{ - detail::hl::prepend(parsers_, parser.parser_)}}; + return parser_interface{or_parser< + decltype(detail::hl::prepend(parsers_, parser.parser_)), + ParserMods>{detail::hl::prepend(parsers_, parser.parser_), mods_}}; } - template + template template - constexpr auto or_parser::append( + constexpr auto or_parser::append( parser_interface parser) const noexcept { // If you're seeing this as a compile- or run-time failure, you've @@ -6116,33 +6497,35 @@ namespace boost { namespace parser { BOOST_PARSER_ASSERT(!detail::is_unconditional_eps_v); if constexpr (detail::is_or_p{}) { - return parser_interface{or_parser{ - detail::hl::concat(parsers_, parser.parser_.parsers_)}}; + return parser_interface{or_parser< + decltype(detail::hl::concat(parsers_, parser.parser_.parsers_)), + ParserMods>{ + detail::hl::concat(parsers_, parser.parser_.parsers_), mods_}}; } else { - return parser_interface{or_parser{ - detail::hl::append(parsers_, parser.parser_)}}; + return parser_interface{or_parser< + decltype(detail::hl::append(parsers_, parser.parser_)), + ParserMods>{ + detail::hl::append(parsers_, parser.parser_), mods_}}; } } - template + template template - constexpr auto perm_parser::prepend( + constexpr auto perm_parser::prepend( parser_interface parser) const noexcept { // If you're seeing this as a compile- or run-time failure, you've // tried to put an eps parser in a permutation-parser, such as "eps || // int_". BOOST_PARSER_ASSERT(!detail::is_eps_p{}); - return parser_interface{perm_parser{ - detail::hl::prepend(parsers_, parser.parser_)}}; + return parser_interface{perm_parser< + decltype(detail::hl::prepend(parsers_, parser.parser_)), + ParserMods>{detail::hl::prepend(parsers_, parser.parser_), mods_}}; } - template + template template - constexpr auto perm_parser::append( + constexpr auto perm_parser::append( parser_interface parser) const noexcept { // If you're seeing this as a compile- or run-time failure, you've @@ -6150,24 +6533,27 @@ namespace boost { namespace parser { // || eps". BOOST_PARSER_ASSERT(!detail::is_eps_p{}); if constexpr (detail::is_perm_p{}) { - return parser_interface{perm_parser{ - detail::hl::concat(parsers_, parser.parser_.parsers_)}}; + return parser_interface{perm_parser< + decltype(detail::hl::concat(parsers_, parser.parser_.parsers_)), + ParserMods>{ + detail::hl::concat(parsers_, parser.parser_.parsers_), mods_}}; } else { - return parser_interface{perm_parser{ - detail::hl::append(parsers_, parser.parser_)}}; + return parser_interface{perm_parser< + decltype(detail::hl::append(parsers_, parser.parser_)), + ParserMods>{ + detail::hl::append(parsers_, parser.parser_), mods_}}; } } template< typename ParserTuple, typename BacktrackingTuple, - typename CombiningGroups> + typename CombiningGroups, + typename ParserMods> template constexpr auto - seq_parser::prepend( - parser_interface parser) const noexcept + seq_parser:: + prepend(parser_interface parser) const noexcept { using combining_groups = detail::combining_t; @@ -6181,19 +6567,21 @@ namespace boost { namespace parser { using parser_t = seq_parser< decltype(detail::hl::prepend(parsers_, parser.parser_)), backtracking, - final_combining_groups>; + final_combining_groups, + ParserMods>; return parser_interface{ - parser_t{detail::hl::prepend(parsers_, parser.parser_)}}; + parser_t{detail::hl::prepend(parsers_, parser.parser_), mods_}}; } template< typename ParserTuple, typename BacktrackingTuple, - typename CombiningGroups> + typename CombiningGroups, + typename ParserMods> template constexpr auto - seq_parser::append( - parser_interface parser) const noexcept + seq_parser:: + append(parser_interface parser) const noexcept { using combining_groups = detail::combining_t; @@ -6211,9 +6599,10 @@ namespace boost { namespace parser { using parser_t = seq_parser< decltype(detail::hl::concat(parsers_, parser.parser_.parsers_)), backtracking, - final_combining_groups>; + final_combining_groups, + ParserMods>; return parser_interface{parser_t{ - detail::hl::concat(parsers_, parser.parser_.parsers_)}}; + detail::hl::concat(parsers_, parser.parser_.parsers_), mods_}}; } else { using final_combining_groups = decltype(detail::hl::append(combining_groups{}, llong<0>{})); @@ -6222,34 +6611,47 @@ namespace boost { namespace parser { using parser_t = seq_parser< decltype(detail::hl::append(parsers_, parser.parser_)), backtracking, - final_combining_groups>; + final_combining_groups, + ParserMods>; return parser_interface{ - parser_t{detail::hl::append(parsers_, parser.parser_)}}; + parser_t{detail::hl::append(parsers_, parser.parser_), mods_}}; } } #endif - // Directives. - /** Represents a unparameterized higher-order parser (e.g. `omit_parser`) - as a directive (e.g. `omit[other_parser]`). */ - template class Parser> + /** Represents a unparameterized higher-order parser (e.g. `raw_parser`) + as a directive (e.g. `raw[other_parser]`). */ + template class Parser> struct directive { template constexpr auto operator[](parser_interface rhs) const noexcept { - return parser_interface{Parser{rhs.parser_}}; + return parser_interface{ + Parser>{rhs.parser_}}; } }; - /** The `omit` directive, whose `operator[]` returns a - `parser_interface>` from a given parser of type - `parser_interface

`. */ - inline constexpr directive omit; + /** Transforms the attribute type of the given parser to `none`, as in + (e.g. `omit[other_parser]`). */ + struct omit_directive + { + template + constexpr auto operator[](parser_interface rhs) const noexcept + { + return parser_interface{ + rhs.parser_.with_parser_mods(detail::omit_attr)}; + } + }; + + /** The global `omit_directive` object, whose `operator[]` returns a new + `parser_interface

` that does not generate an attribute, from a + given parser of type `parser_interface

`. */ + inline constexpr omit_directive omit; /** The `raw` directive, whose `operator[]` returns a `parser_interface>` from a given parser of type @@ -6281,8 +6683,12 @@ namespace boost { namespace parser { template constexpr auto operator[](parser_interface rhs) const noexcept { - using repeat_parser_type = - repeat_parser; + using repeat_parser_type = repeat_parser< + Parser2, + detail::nope, + MinType, + MaxType, + parser_modifiers<>>; return parser_interface{ repeat_parser_type{rhs.parser_, min_, max_}}; } @@ -6323,7 +6729,8 @@ namespace boost { namespace parser { constexpr auto operator[](parser_interface rhs) const noexcept { return parser_interface{ - skip_parser{rhs.parser_, skip_parser_}}; + skip_parser>{ + rhs.parser_, skip_parser_}}; } /** Returns a `skip_directive` with `skip_parser` as its skipper. */ @@ -6354,15 +6761,19 @@ namespace boost { namespace parser { template< typename ParserTuple, typename BacktrackingTuple, - typename CombiningGroups> - constexpr auto - operator[](parser_interface< - seq_parser> - rhs) const noexcept - { - return parser_interface{ - seq_parser{ - rhs.parser_.parsers_}}; + typename CombiningGroups, + typename ParserMods> + constexpr auto operator[](parser_interface> rhs) const noexcept + { + return parser_interface{seq_parser< + ParserTuple, + BacktrackingTuple, + detail::merge_t, + ParserMods>{rhs.parser_.parsers_, rhs.parser_.mods_}}; } }; @@ -6382,15 +6793,19 @@ namespace boost { namespace parser { template< typename ParserTuple, typename BacktrackingTuple, - typename CombiningGroups> - constexpr auto - operator[](parser_interface< - seq_parser> - rhs) const noexcept - { - return parser_interface{ - seq_parser{ - rhs.parser_.parsers_}}; + typename CombiningGroups, + typename ParserMods> + constexpr auto operator[](parser_interface> rhs) const noexcept + { + return parser_interface{seq_parser< + ParserTuple, + BacktrackingTuple, + detail::separate_t, + ParserMods>{rhs.parser_.parsers_, rhs.parser_.mods_}}; } }; @@ -6412,7 +6827,8 @@ namespace boost { namespace parser { constexpr auto operator[](parser_interface rhs) const noexcept { return parser_interface{ - transform_parser{rhs.parser_, f_}}; + transform_parser>{ + rhs.parser_, f_}}; } F f_; @@ -6431,9 +6847,15 @@ namespace boost { namespace parser { #ifndef BOOST_PARSER_DOXYGEN - template + template struct eps_parser { + constexpr eps_parser() {} + constexpr eps_parser(Predicate pred) : pred_(pred) {} + constexpr eps_parser(Predicate pred, ParserMods mods) : + pred_(pred), mods_(std::move(mods)) + {} + template< typename Iter, typename Sentinel, @@ -6496,10 +6918,18 @@ namespace boost { namespace parser { (detail::is_nope_v && "If you're seeing this, you tried to chain calls on eps, " "like 'eps(foo)(bar)'. Quit it!'")); - return parser_interface{eps_parser{std::move(pred)}}; + return parser_interface{ + eps_parser{std::move(pred), mods_}}; + } + + template + constexpr auto with_parser_mods(F f) const + { + return parser::eps_parser(pred_, f(mods_)); } Predicate pred_; + [[no_unique_address]] ParserMods mods_; }; #endif @@ -6507,12 +6937,19 @@ namespace boost { namespace parser { /** The epsilon parser. This matches anything, and consumes no input. If used with an optional predicate, like `eps(pred)`, it matches iff `pred(ctx)` evaluates to true, where `ctx` is the parser context. */ - inline constexpr parser_interface> eps; + inline constexpr parser_interface< + eps_parser>> + eps; #ifndef BOOST_PARSER_DOXYGEN + template struct eoi_parser { + constexpr eoi_parser() {} + constexpr explicit eoi_parser(ParserMods mods) : mods_(std::move(mods)) + {} + template< typename Iter, typename Sentinel, @@ -6553,18 +6990,31 @@ namespace boost { namespace parser { if (first != last) success = false; } + + template + constexpr auto with_parser_mods(F f) const + { + return parser::eoi_parser(f(mods_)); + } + + [[no_unique_address]] ParserMods mods_; }; #endif /** The end-of-input parser. It matches only the end of input. */ - inline constexpr parser_interface eoi; + inline constexpr parser_interface>> eoi; #ifndef BOOST_PARSER_DOXYGEN - template + template struct attr_parser { + constexpr attr_parser(Attribute attr) : attr_(attr) {} + constexpr attr_parser(Attribute attr, ParserMods mods) : + attr_(std::move(attr)), mods_(std::move(mods)) + {} + template< typename Iter, typename Sentinel, @@ -6580,7 +7030,10 @@ namespace boost { namespace parser { { [[maybe_unused]] auto _ = detail::scoped_trace( *this, first, last, context, flags, detail::global_nope); - return detail::resolve(context, attr_); + if constexpr (detail::gen_attrs()) + return detail::resolve(context, attr_); + else + return detail::nope{}; } template< @@ -6600,11 +7053,23 @@ namespace boost { namespace parser { { [[maybe_unused]] auto _ = detail::scoped_trace( *this, first, last, context, flags, retval); - if (detail::gen_attrs(flags)) + if constexpr (detail::gen_attrs()) detail::assign_copy(retval, detail::resolve(context, attr_)); } + template + constexpr auto with_parser_mods(F f) const & + { + return parser::attr_parser(attr_, f(mods_)); + } + template + constexpr auto with_parser_mods(F f) const && + { + return parser::attr_parser(std::move(attr_), f(mods_)); + } + Attribute attr_; + [[no_unique_address]] ParserMods mods_; }; #endif @@ -6614,7 +7079,8 @@ namespace boost { namespace parser { template constexpr auto attr(Attribute a) noexcept { - return parser_interface{attr_parser{std::move(a)}}; + return parser_interface{ + attr_parser>{std::move(a)}}; } #ifndef BOOST_PARSER_DOXYGEN @@ -6624,7 +7090,7 @@ namespace boost { namespace parser { { constexpr char_parser() {} constexpr char_parser(Expected expected, ParserMods mods) : - expected_(expected), mods_(mods) + expected_(expected), mods_(std::move(mods)) {} template @@ -6633,10 +7099,6 @@ namespace boost { namespace parser { std::decay_t, AttributeType>; - template - using attribute_type = std:: - conditional_t>; - template< typename Iter, typename Sentinel, @@ -6648,9 +7110,13 @@ namespace boost { namespace parser { Context const & context, SkipParser const & skip, detail::flags flags, - bool & success) const -> attribute_type + bool & success) const + -> detail:: + final_attribute_type, ParserMods> { - attribute_type retval{}; + detail:: + final_attribute_type, ParserMods> + retval{}; call(first, last, context, skip, flags, success, retval); return retval; } @@ -6796,23 +7262,23 @@ namespace boost { namespace parser { return parser_interface(char_parser_t(chars, mods_)); } - template - constexpr auto with_parser_mods(ParserMods2 mods) + template + constexpr auto with_parser_mods(F f) const { - return char_parser{ - expected_, std::move(mods)}; + return parser::char_parser(expected_, f(mods_)); } Expected expected_; [[no_unique_address]] ParserMods mods_; }; + template struct digit_parser { constexpr digit_parser() {} - - template - using attribute_type = std::decay_t; + constexpr explicit digit_parser(ParserMods mods) : + mods_(std::move(mods)) + {} template< typename Iter, @@ -6825,9 +7291,12 @@ namespace boost { namespace parser { Context const & context, SkipParser const & skip, detail::flags flags, - bool & success) const -> attribute_type + bool & success) const + -> detail:: + final_attribute_type, ParserMods> { - attribute_type retval{}; + detail::final_attribute_type, ParserMods> + retval{}; call(first, last, context, skip, flags, success, retval); return retval; } @@ -6854,7 +7323,7 @@ namespace boost { namespace parser { success = false; return; } - attribute_type const x = *first; + detail::iter_value_t const x = *first; char32_t const x_cmp = x; if (x_cmp < U'\x0100' && (x_cmp < U'0' || U'9' < x_cmp)) { success = false; @@ -6867,7 +7336,8 @@ namespace boost { namespace parser { success = false; return; } - detail::assign(retval, x); + if constexpr (detail::gen_attrs()) + detail::assign(retval, x); ++first; } @@ -6944,9 +7414,17 @@ namespace boost { namespace parser { U'\U0001E950', // U+1E950 ADLAM DIGIT ZERO U'\U0001FBF0' // U+1FBF0 SEGMENTED DIGIT ZERO }; + + template + constexpr auto with_parser_mods(F f) const + { + return parser::digit_parser(f(mods_)); + } + + [[no_unique_address]] ParserMods mods_; }; - template + template struct char_set_parser { BOOST_PARSER_ALGO_CONSTEXPR char_set_parser() @@ -6961,9 +7439,10 @@ namespace boost { namespace parser { if (it != last) one_byte_offset_ = int(it - first); } - - template - using attribute_type = std::decay_t; + BOOST_PARSER_ALGO_CONSTEXPR + char_set_parser(int offset, ParserMods mods) : + one_byte_offset_(offset), mods_(std::move(mods)) + {} template< typename Iter, @@ -6976,9 +7455,12 @@ namespace boost { namespace parser { Context const & context, SkipParser const & skip, detail::flags flags, - bool & success) const -> attribute_type + bool & success) const + -> detail:: + final_attribute_type, ParserMods> { - attribute_type retval{}; + detail::final_attribute_type, ParserMods> + retval{}; call(first, last, context, skip, flags, success, retval); return retval; } @@ -7007,7 +7489,7 @@ namespace boost { namespace parser { } auto const & chars = detail::char_set::chars; - attribute_type const x = *first; + detail::iter_value_t const x = *first; uint32_t const x_cmp = x; if (x_cmp < U'\x0100') { uint32_t const * it = std::lower_bound( @@ -7015,7 +7497,8 @@ namespace boost { namespace parser { std::begin(chars) + one_byte_offset_, x_cmp); if (it != std::end(chars) && *it == x_cmp) { - detail::assign(retval, x_cmp); + if constexpr (detail::gen_attrs()) + detail::assign(retval, x_cmp); ++first; } else { success = false; @@ -7026,7 +7509,8 @@ namespace boost { namespace parser { uint32_t const * it = std::lower_bound( std::begin(chars) + one_byte_offset_, std::end(chars), x_cmp); if (it != std::end(chars) && *it == x_cmp) { - detail::assign(retval, x_cmp); + if constexpr (detail::gen_attrs()) + detail::assign(retval, x_cmp); ++first; return; } @@ -7034,16 +7518,25 @@ namespace boost { namespace parser { success = false; } + template + constexpr auto with_parser_mods(F f) const + { + auto mods = f(mods_); + return char_set_parser{ + one_byte_offset_, std::move(mods)}; + } + int one_byte_offset_ = 0; + [[no_unique_address]] ParserMods mods_; }; - template + template struct char_subrange_parser { constexpr char_subrange_parser() {} - - template - using attribute_type = std::decay_t; + constexpr explicit char_subrange_parser(ParserMods mods) : + mods_(std::move(mods)) + {} template< typename Iter, @@ -7056,9 +7549,12 @@ namespace boost { namespace parser { Context const & context, SkipParser const & skip, detail::flags flags, - bool & success) const -> attribute_type + bool & success) const + -> detail:: + final_attribute_type, ParserMods> { - attribute_type retval{}; + detail::final_attribute_type, ParserMods> + retval{}; call(first, last, context, skip, flags, success, retval); return retval; } @@ -7085,18 +7581,28 @@ namespace boost { namespace parser { success = false; return; } - attribute_type const x = *first; + detail::iter_value_t const x = *first; char32_t const x_cmp = x; success = false; for (auto subrange : detail::char_subranges::ranges) { if (subrange.lo_ <= x_cmp && x_cmp <= subrange.hi_) { success = true; - detail::assign(retval, x); + if constexpr (detail::gen_attrs()) + detail::assign(retval, x); ++first; return; } } } + + template + constexpr auto with_parser_mods(F f) const + { + auto mods = f(mods_); + return char_subrange_parser(std::move(mods)); + } + + [[no_unique_address]] ParserMods mods_; }; #endif @@ -7164,9 +7670,6 @@ namespace boost { namespace parser { template struct string_parser { - using attribute_type = std:: - conditional_t; - constexpr string_parser() = default; #if BOOST_PARSER_USE_CONCEPTS @@ -7183,7 +7686,7 @@ namespace boost { namespace parser { {} constexpr string_parser(StrIter f, StrSentinel l, ParserMods mods) : - expected_first_(f), expected_last_(l), mods_(mods) + expected_first_(f), expected_last_(l), mods_(std::move(mods)) {} template< @@ -7191,15 +7694,16 @@ namespace boost { namespace parser { typename Sentinel, typename Context, typename SkipParser> - attribute_type call( + auto call( Iter & first, Sentinel last, Context const & context, SkipParser const & skip, detail::flags flags, bool & success) const + -> detail::final_attribute_type { - attribute_type retval; + detail::final_attribute_type retval; call(first, last, context, skip, flags, success, retval); return retval; } @@ -7227,6 +7731,8 @@ namespace boost { namespace parser { return; } + constexpr auto gen_attrs = detail::gen_attrs(); + if constexpr (std::is_same_v< detail::remove_cv_ref_t, char32_t>) { @@ -7245,13 +7751,8 @@ namespace boost { namespace parser { return; } - if constexpr (!ParserMods::omit_attr) { - detail::append( - retval, - first, - mismatch.first, - detail::gen_attrs(flags)); - } + if constexpr (gen_attrs.value) + detail::append(retval, first, mismatch.first); first = mismatch.first; } else { @@ -7266,23 +7767,19 @@ namespace boost { namespace parser { return; } - if constexpr (!ParserMods::omit_attr) { - detail::append( - retval, - first, - mismatch.first, - detail::gen_attrs(flags)); - } + if constexpr (gen_attrs.value) + detail::append(retval, first, mismatch.first); first = mismatch.first; } } - template - constexpr auto with_parser_mods(ParserMods2 mods) + template + constexpr auto with_parser_mods(F f) const { - return string_parser{ - expected_first_, expected_last_, std::move(mods)}; + auto mods = f(mods_); + return string_parser( + expected_first_, expected_last_, std::move(mods)); } StrIter expected_first_; @@ -7314,58 +7811,31 @@ namespace boost { namespace parser { return parser_interface{string_parser(str)}; } - template + template struct quoted_string_parser { constexpr quoted_string_parser() : chs_(), ch_('"') {} - -#if BOOST_PARSER_USE_CONCEPTS - template -#else - template< - typename R, - typename Enable = - std::enable_if_t>> -#endif - constexpr quoted_string_parser(R && r) : chs_((R &&) r), ch_(0) - { - BOOST_PARSER_DEBUG_ASSERT(r.begin() != r.end()); - } - -#if BOOST_PARSER_USE_CONCEPTS - template -#else - template< - typename R, - typename Enable = - std::enable_if_t>> -#endif - constexpr quoted_string_parser(R && r, Escapes escapes) : - chs_((R &&) r), escapes_(escapes), ch_(0) - { - BOOST_PARSER_DEBUG_ASSERT(r.begin() != r.end()); - } - - constexpr quoted_string_parser(char32_t cp) : chs_(), ch_(cp) {} - - constexpr quoted_string_parser(char32_t cp, Escapes escapes) : - chs_(), escapes_(escapes), ch_(cp) + constexpr quoted_string_parser( + Quotes chs, Escapes escapes, char32_t ch, ParserMods mods) : + chs_(chs), escapes_(escapes), ch_(ch), mods_(std::move(mods)) {} + constexpr quoted_string_parser(char32_t cp) : chs_(), ch_(cp) {} template< typename Iter, typename Sentinel, typename Context, typename SkipParser> - std::string call( + auto call( Iter & first, Sentinel last, Context const & context, SkipParser const & skip, detail::flags flags, bool & success) const + -> detail::final_attribute_type { - std::string retval; + detail::final_attribute_type retval; call(first, last, context, skip, flags, success, retval); return retval; } @@ -7395,9 +7865,9 @@ namespace boost { namespace parser { auto const prev_first = first; - auto append = [&retval, - gen_attrs = detail::gen_attrs(flags)](auto & ctx) { - detail::move_back(retval, _attr(ctx), gen_attrs); + auto append = [&retval](auto & ctx) { + if constexpr (detail::gen_attrs()) + detail::move_back(retval, _attr(ctx)); }; auto quote_ch = [&]() { @@ -7456,7 +7926,8 @@ namespace boost { namespace parser { success); if (!success) { - retval = Attribute(); + if constexpr (detail::gen_attrs()) + retval = Attribute(); first = prev_first; } } @@ -7515,10 +7986,16 @@ namespace boost { namespace parser { "'quoted_string(char-range)(char-range)'. Quit it!'")); } return parser_interface( - quoted_string_parser( + quoted_string_parser< + decltype(BOOST_PARSER_SUBRANGE( + detail::make_view_begin(r), detail::make_view_end(r))), + detail::nope, + ParserMods>( BOOST_PARSER_SUBRANGE( - detail::make_view_begin(r), detail::make_view_end(r)))); + detail::make_view_begin(r), detail::make_view_end(r)), + escapes_, + ch_, + mods_)); } /** Returns a `parser_interface` containing a `quoted_string_parser` @@ -7546,8 +8023,10 @@ namespace boost { namespace parser { "it!'")); } auto symbols = symbol_parser(escapes.parser_); - auto parser = quoted_string_parser( - char32_t(x), symbols); + auto parser = quoted_string_parser< + detail::nope, + decltype(symbols), + ParserMods>(chs_, symbols, char32_t(x), mods_); return parser_interface(parser); } @@ -7588,15 +8067,23 @@ namespace boost { namespace parser { auto symbols = symbol_parser(escapes.parser_); auto quotes = BOOST_PARSER_SUBRANGE( detail::make_view_begin(r), detail::make_view_end(r)); - auto parser = - quoted_string_parser( - quotes, symbols); + auto parser = quoted_string_parser< + decltype(quotes), + decltype(symbols), + ParserMods>(quotes, symbols, ch_, mods_); return parser_interface(parser); } + template + constexpr auto with_parser_mods(F f) const + { + return parser::quoted_string_parser(chs_, escapes_, ch_, f(mods_)); + } + Quotes chs_; Escapes escapes_; char32_t ch_; + [[no_unique_address]] ParserMods mods_; }; /** Parses a string delimited by quotation marks. This parser can be used @@ -7628,16 +8115,18 @@ namespace boost { namespace parser { #endif constexpr auto lit(R && str) noexcept { - return parser_interface{parser::string(str).parser_.with_parser_mods( - parser_modifiers{})}; + return parser_interface{ + parser::string(str).parser_.with_parser_mods(detail::omit_attr)}; } #ifndef BOOST_PARSER_DOXYGEN - template + template struct ws_parser { constexpr ws_parser() {} + constexpr explicit ws_parser(ParserMods mods) : mods_(std::move(mods)) + {} static_assert(!NewlinesOnly || !NoNewlines); @@ -7739,6 +8228,16 @@ namespace boost { namespace parser { success = false; } } + + template + constexpr auto with_parser_mods(F f) const + { + auto mods = f(mods_); + return ws_parser( + std::move(mods)); + } + + [[no_unique_address]] ParserMods mods_; }; #endif @@ -7746,76 +8245,88 @@ namespace boost { namespace parser { /** The end-of-line parser. This matches "\r\n", or any one of the line break code points from the Unicode Line Break Algorithm, described in https://unicode.org/reports/tr14. Produces no attribute. */ - inline constexpr parser_interface> eol; + inline constexpr parser_interface< + ws_parser>> + eol; /** The whitespace parser. This matches "\r\n", or any one of the Unicode code points with the White_Space property, as defined in https://www.unicode.org/Public/UCD/latest/ucd/PropList.txt. Produces no attribute. */ - inline constexpr parser_interface> ws; + inline constexpr parser_interface< + ws_parser>> + ws; /** The whitespace parser that does not match end-of-line. This matches any one of the Unicode code points with the White_Space property, as defined in https://www.unicode.org/Public/UCD/latest/ucd/PropList.txt, except for the ones matched by `eol`. Produces no attribute. */ - inline constexpr parser_interface> blank; + inline constexpr parser_interface< + ws_parser>> + blank; /** The decimal digit parser. Matches the full set of Unicode decimal digits; in other words, all Unicode code points with the "Nd" character property. Note that this covers all Unicode scripts, only a few of which are Latin. */ - inline constexpr parser_interface digit; + inline constexpr parser_interface>> digit; /** The hexidecimal digit parser. Matches the full set of Unicode hexidecimal digits (upper or lower case); in other words, all Unicode code points with the "Hex_Digit" character property. */ inline constexpr parser_interface< - char_subrange_parser> + char_subrange_parser>> hex_digit; /** The control character parser. Matches the all Unicode code points with the "Cc" ("control character") character property. */ inline constexpr parser_interface< - char_subrange_parser> + char_subrange_parser>> control; /** The punctuation character parser. Matches the full set of Unicode punctuation clases (specifically, "Pc", "Pd", "Pe", "Pf", "Pi", "Ps", and "Po"). */ - inline BOOST_PARSER_ALGO_CONSTEXPR - parser_interface> - punct; + inline BOOST_PARSER_ALGO_CONSTEXPR parser_interface< + char_set_parser>> + punct; /** The lower case character parser. Matches the full set of Unicode lower case code points (class "Ll"). */ - inline BOOST_PARSER_ALGO_CONSTEXPR - parser_interface> - lower; + inline BOOST_PARSER_ALGO_CONSTEXPR parser_interface< + char_set_parser>> + lower; /** The lower case character parser. Matches the full set of Unicode lower case code points (class "Lu"). */ - inline BOOST_PARSER_ALGO_CONSTEXPR - parser_interface> - upper; + inline BOOST_PARSER_ALGO_CONSTEXPR parser_interface< + char_set_parser>> + upper; #ifndef BOOST_PARSER_DOXYGEN + template struct bool_parser { + constexpr bool_parser() {} + constexpr explicit bool_parser(ParserMods mods) : mods_(std::move(mods)) + {} + template< typename Iter, typename Sentinel, typename Context, typename SkipParser> - bool call( + auto call( Iter & first, Sentinel last, Context const & context, SkipParser const & skip, detail::flags flags, bool & success) const + -> detail::final_attribute_type { - bool retval{}; + detail::final_attribute_type retval{}; call(first, last, context, skip, flags, success, retval); return retval; } @@ -7851,25 +8362,35 @@ namespace boost { namespace parser { if (detail::mismatch(t, t + 4, first, last, compare).first == t + 4) { std::advance(first, 4); - detail::assign(retval, true); + if constexpr (detail::gen_attrs()) + detail::assign(retval, true); return; } char const f[] = "false"; if (detail::mismatch(f, f + 5, first, last, compare).first == f + 5) { std::advance(first, 5); - detail::assign(retval, false); + if constexpr (detail::gen_attrs()) + detail::assign(retval, false); return; } success = false; } + + template + constexpr auto with_parser_mods(F f) const + { + return parser::bool_parser(f(mods_)); + } + + [[no_unique_address]] ParserMods mods_; }; #endif /** The Boolean parser. Parses "true" and "false", producing attributes `true` and `false`, respectively, and fails on any other input. */ - inline constexpr parser_interface bool_; + inline constexpr parser_interface>> bool_; #ifndef BOOST_PARSER_DOXYGEN @@ -7878,7 +8399,8 @@ namespace boost { namespace parser { int Radix, int MinDigits, int MaxDigits, - typename Expected> + typename Expected, + typename ParserMods> struct uint_parser { static_assert(2 <= Radix && Radix <= 36, "Unsupported radix."); @@ -7886,21 +8408,24 @@ namespace boost { namespace parser { constexpr uint_parser() {} explicit constexpr uint_parser(Expected expected) : expected_(expected) {} + constexpr uint_parser(Expected expected, ParserMods mods) : + expected_(expected), mods_(std::move(mods)) + {} template< typename Iter, typename Sentinel, typename Context, typename SkipParser> - T call( + auto call( Iter & first, Sentinel last, Context const & context, SkipParser const & skip, detail::flags flags, - bool & success) const + bool & success) const -> detail::final_attribute_type { - T retval{}; + detail::final_attribute_type retval{}; call(first, last, context, skip, flags, success, retval); return retval; } @@ -7929,8 +8454,10 @@ namespace boost { namespace parser { first, last, attr); if (first == initial || attr != detail::resolve(context, expected_)) success = false; - if (success) - detail::assign(retval, attr); + if constexpr (detail::gen_attrs()) { + if (success) + detail::assign(retval, attr); + } } /** Returns a `parser_interface` containing a `uint_parser` that @@ -7942,12 +8469,31 @@ namespace boost { namespace parser { (detail::is_nope_v && "If you're seeing this, you tried to chain calls on this " "parser, like 'uint_(2)(3)'. Quit it!'")); - using parser_t = - uint_parser; - return parser_interface{parser_t{expected}}; + using parser_t = uint_parser< + T, + Radix, + MinDigits, + MaxDigits, + Expected2, + ParserMods>; + return parser_interface{parser_t{expected, mods_}}; + } + + template + constexpr auto with_parser_mods(F f) const + { + auto mods = f(mods_); + return uint_parser< + T, + Radix, + MinDigits, + MaxDigits, + Expected, + decltype(mods)>{expected_, std::move(mods)}; } Expected expected_; + [[no_unique_address]] ParserMods mods_; }; #endif @@ -7988,7 +8534,8 @@ namespace boost { namespace parser { int Radix, int MinDigits, int MaxDigits, - typename Expected> + typename Expected, + typename ParserMods> struct int_parser { static_assert( @@ -7998,21 +8545,24 @@ namespace boost { namespace parser { constexpr int_parser() {} explicit constexpr int_parser(Expected expected) : expected_(expected) {} + constexpr int_parser(Expected expected, ParserMods mods) : + expected_(expected), mods_(std::move(mods)) + {} template< typename Iter, typename Sentinel, typename Context, typename SkipParser> - T call( + auto call( Iter & first, Sentinel last, Context const & context, SkipParser const & skip, detail::flags flags, - bool & success) const + bool & success) const -> detail::final_attribute_type { - T retval{}; + detail::final_attribute_type retval{}; call(first, last, context, skip, flags, success, retval); return retval; } @@ -8041,8 +8591,10 @@ namespace boost { namespace parser { first, last, attr); if (first == initial || attr != detail::resolve(context, expected_)) success = false; - if (success) - detail::assign(retval, attr); + if constexpr (detail::gen_attrs()) { + if (success) + detail::assign(retval, attr); + } } /** Returns a `parser_interface` containing an `int_parser` that @@ -8054,12 +8606,31 @@ namespace boost { namespace parser { (detail::is_nope_v && "If you're seeing this, you tried to chain calls on this " "parser, like 'int_(2)(3)'. Quit it!'")); - using parser_t = - int_parser; - return parser_interface{parser_t{expected}}; + using parser_t = int_parser< + T, + Radix, + MinDigits, + MaxDigits, + Expected2, + ParserMods>; + return parser_interface{parser_t{expected, mods_}}; + } + + template + constexpr auto with_parser_mods(F f) const + { + auto mods = f(mods_); + return int_parser< + T, + Radix, + MinDigits, + MaxDigits, + Expected, + decltype(mods)>{expected_, std::move(mods)}; } Expected expected_; + [[no_unique_address]] ParserMods mods_; }; #endif @@ -8082,25 +8653,28 @@ namespace boost { namespace parser { #ifndef BOOST_PARSER_DOXYGEN - template + template struct float_parser { constexpr float_parser() {} + explicit constexpr float_parser(ParserMods mods) : + mods_(std::move(mods)) + {} template< typename Iter, typename Sentinel, typename Context, typename SkipParser> - T call( + auto call( Iter & first, Sentinel last, Context const & context, SkipParser const & skip, detail::flags flags, - bool & success) const + bool & success) const -> detail::final_attribute_type { - T retval = 0; + detail::final_attribute_type retval{}; call(first, last, context, skip, flags, success, retval); return retval; } @@ -8127,18 +8701,31 @@ namespace boost { namespace parser { success = detail::numeric::parse_real(first, last, attr); if (first == initial) success = false; - if (success) - detail::assign(retval, attr); + if constexpr (detail::gen_attrs()) { + if (success) + detail::assign(retval, attr); + } } + + template + constexpr auto with_parser_mods(F f) const + { + auto mods = f(mods_); + return float_parser(std::move(mods)); + } + + [[no_unique_address]] ParserMods mods_; }; #endif /** The `float` parser. Produces a `float` attribute. */ - inline constexpr parser_interface> float_; + inline constexpr parser_interface>> + float_; /** The `double` parser. Produces a `double` attribute. */ - inline constexpr parser_interface> double_; + inline constexpr parser_interface>> + double_; /** Represents a sequence parser, the first parser of which is an @@ -8184,7 +8771,7 @@ namespace boost { namespace parser { #ifndef BOOST_PARSER_DOXYGEN - template + template struct switch_parser { switch_parser() {} @@ -8192,6 +8779,12 @@ namespace boost { namespace parser { switch_parser(SwitchValue switch_value, OrParser or_parser) : switch_value_(switch_value), or_parser_(or_parser) {} + switch_parser( + SwitchValue switch_value, OrParser or_parser, ParserMods mods) : + switch_value_(switch_value), + or_parser_(or_parser), + mods_(std::move(mods)) + {} template< typename Iter, @@ -8211,9 +8804,11 @@ namespace boost { namespace parser { "It looks like you tried to write switch_(val). You need at " "least one alternative, like: switch_(val)(value_1, " "parser_1)(value_2, parser_2)...")); - using attr_t = decltype(or_parser_.call( - first, last, context, skip, flags, success)); - attr_t attr{}; + detail::final_attribute_type< + decltype(or_parser_.call( + first, last, context, skip, flags, success)), + ParserMods> + attr{}; [[maybe_unused]] auto _ = detail::scoped_trace(*this, first, last, context, flags, attr); attr = or_parser_.call(first, last, context, skip, flags, success); @@ -8255,9 +8850,9 @@ namespace boost { namespace parser { switch_value_, value_}; auto or_parser = make_or_parser(or_parser_, eps(match) >> rhs); using switch_parser_type = - switch_parser; + switch_parser; return parser_interface{ - switch_parser_type{switch_value_, or_parser}}; + switch_parser_type{switch_value_, or_parser, mods_}}; } #ifndef BOOST_PARSER_DOXYGEN @@ -8278,8 +8873,16 @@ namespace boost { namespace parser { #endif + template + constexpr auto with_parser_mods(F f) const + { + return parser::switch_parser( + switch_value_, or_parser_with_parser_mods(f), f(mods_)); + } + SwitchValue switch_value_; OrParser or_parser_; + [[no_unique_address]] ParserMods mods_; }; #endif @@ -9515,7 +10118,8 @@ namespace boost { namespace parser { char const *, char const *, default_error_handler>; - using skipper_t = parser_interface>; + using skipper_t = + parser_interface>>; using use_parser_t = dummy_use_parser_t< char const *, char const *, diff --git a/include/boost/parser/parser_fwd.hpp b/include/boost/parser/parser_fwd.hpp index 6bc7ffa6..fe0aa024 100644 --- a/include/boost/parser/parser_fwd.hpp +++ b/include/boost/parser/parser_fwd.hpp @@ -165,20 +165,21 @@ namespace boost { namespace parser { typename Parser, typename DelimiterParser = detail::nope, typename MinType = int64_t, - typename MaxType = int64_t> + typename MaxType = int64_t, + typename ParserMods = parser_modifiers<>> struct repeat_parser; /** Repeats the application of another parser `p` of type `Parser`, `[0, Inf)` times. The parse always succeeds. The attribute produced is a sequence of the type of attribute produced by `Parser`. */ - template + template struct zero_plus_parser; /** Repeats the application of another parser `p` of type `Parser`, `[1, Inf)` times. The parse succeeds iff `p` succeeds at least once. The attribute produced is a sequence of the type of attribute produced by `Parser`. */ - template + template struct one_plus_parser; /** Repeats the application of another parser `p` of type `Parser`, `[1, @@ -187,14 +188,14 @@ namespace boost { namespace parser { succeeds at least once, and `d` succeeds each time it is applied. The attribute produced is a sequence of the type of attribute produced by `Parser`. */ - template + template struct delimited_seq_parser; /** Repeats the application of another parser of type `Parser`, `[0, 1]` times. The parse always succeeds. The attribute produced is a `std::optional`, where `T` is the type of attribute produced by `Parser`. */ - template + template struct opt_parser; /** Applies each parser in `ParserTuple`, in order, stopping after the @@ -202,7 +203,7 @@ namespace boost { namespace parser { one of the sub-parsers succeeds. The attribute produced is a `std::variant` over the types of attribute produced by the parsers in `ParserTuple`. */ - template + template struct or_parser; /** Applies each parsers in `ParserTuple`, an any order, stopping after @@ -213,7 +214,7 @@ namespace boost { namespace parser { `ParserTuple`, not the order of the parsers' matches. It is an error to specialize `perm_parser` with a `ParserTuple` template parameter that includes an `eps_parser`. */ - template + template struct perm_parser; /** Applies each parser in `ParserTuple`, in order. The parse succeeds @@ -226,14 +227,15 @@ namespace boost { namespace parser { template< typename ParserTuple, typename BacktrackingTuple, - typename CombiningGroups> + typename CombiningGroups, + typename ParserMods> struct seq_parser; /** Applies the given parser `p` of type `Parser` and an invocable `a` of type `Action`. `Action` shall model `semantic_action`, and `a` will only be invoked if `p` succeeds. The parse succeeds iff `p` succeeds. Produces no attribute. */ - template + template struct action_parser; /** Applies the given parser `p` of type `Parser`. The attribute produced @@ -241,21 +243,14 @@ namespace boost { namespace parser { only be invoked if `p` succeeds and sttributes are currently being generated. The parse succeeds iff `p` succeeds. The attribute produced is the the result of the call to `f`. */ - template + template struct transform_parser; - /** Applies the given parser `p` of type `Parser`. This parser produces - no attribute, and suppresses the production of any attributes that - would otherwise be produced by `p`. The parse succeeds iff `p` - succeeds. */ - template - struct omit_parser; - /** Applies the given parser `p` of type `Parser`; regardless of the attribute produced by `Parser`, this parser's attribute is equivalent to `_where(ctx)` within a semantic action on `p`. The parse succeeds iff `p` succeeds. */ - template + template struct raw_parser; #if defined(BOOST_PARSER_DOXYGEN) || BOOST_PARSER_USE_CONCEPTS @@ -268,34 +263,37 @@ namespace boost { namespace parser { non-contiguous, code using `string_view_parser` is ill-formed. The parse succeeds iff `p` succeeds. This parser is only available in C++20 and later. */ - template + template struct string_view_parser; #endif /** Applies the given parser `p` of type `Parser`, disabling the current skipper in use, if any. The parse succeeds iff `p` succeeds. The attribute produced is the type of attribute produced by `Parser`. */ - template + template struct lexeme_parser; /** Applies the given parser `p` of type `Parser`, enabling case-insensitive matching, based on Unicode case folding. The parse succeeds iff `p` succeeds. The attribute produced is the type of attribute produced by `Parser`. */ - template + template struct no_case_parser; /** Applies the given parser `p` of type `Parser`, using a parser of type `SkipParser` as the skipper. The parse succeeds iff `p` succeeds. The attribute produced is the type of attribute produced by `Parser`. */ - template + template< + typename Parser, + typename SkipParser = detail::nope, + typename ParserMods = parser_modifiers<>> struct skip_parser; /** Applies the given parser `p` of type `Parser`, producing no attributes and consuming no input. The parse succeeds iff `p`'s success is unequal to `FailOnMatch`. */ - template + template struct expect_parser; /** Matches one of a set S of possible inputs, each of which is associated @@ -304,7 +302,7 @@ namespace boost { namespace parser { from S dynamically, during parsing; any such changes are reverted at the end of parsing. The parse succeeds iff an element of S is matched. \see `symbols` */ - template + template struct symbol_parser; /** Applies another parser `p`, associated with this parser via `TagType`. @@ -323,22 +321,24 @@ namespace boost { namespace parser { typename TagType, typename Attribute, typename LocalState, - typename ParamsTuple> + typename ParamsTuple, + typename ParserMods> struct rule_parser; /** Matches anything, and consumes no input. If `Predicate` is anything other than `detail::nope` (which it is by default), and `pred_(ctx)` evaluates to false, where `ctx` is the parser context, the parse fails. */ - template + template struct eps_parser; /** Matches only the end of input. Produces no attribute. */ + template struct eoi_parser; /** Matches anything, consumes no input, and produces an attribute of type `RESOLVE(Attribute)`. */ - template + template struct attr_parser; /** A tag type that can be passed as the first parameter to `char_()` when @@ -366,7 +366,7 @@ namespace boost { namespace parser { characters for matching Unicode character classes like punctuation or lower case. Attribute type is the attribute type of the character being matched. */ - template + template struct char_set_parser; /** Matches a single code point that falls into one of the subranges of @@ -374,12 +374,13 @@ namespace boost { namespace parser { sets of characters for matching Unicode character classes like hex digits or control characters. Attribute type is the attribute type of the character being matched. */ - template + template struct char_subrange_parser; /** Matches a single decimal digit code point, using the Unicode character class Hex_Digit. Attribute type is the attribute type of the character being matched. */ + template struct digit_parser; /** Matches a particular string, delimited by an iterator sentinel pair; @@ -389,7 +390,10 @@ namespace boost { namespace parser { /** Matches a string delimited by quotation marks; produces a `std::string` attribute. */ - template + template< + typename Quotes = detail::nope, + typename Escapes = detail::nope, + typename ParserMods = parser_modifiers<>> struct quoted_string_parser; /** Matches an end-of-line (`NewlinesOnly == true`), whitespace @@ -397,11 +401,12 @@ namespace boost { namespace parser { but not newline) code point, based on the Unicode definitions of each (also matches the two code points `"\r\n"`). Produces no attribute. */ - template + template struct ws_parser; /** Matches the strings "true" and "false", producing an attribute of `true` or `false`, respectively, and fails on any other input. */ + template struct bool_parser; /** Matches an unsigned number of radix `Radix`, of at least `MinDigits` @@ -415,7 +420,8 @@ namespace boost { namespace parser { int Radix = 10, int MinDigits = 1, int MaxDigits = -1, - typename Expected = detail::nope> + typename Expected = detail::nope, + typename ParserMods = parser_modifiers<>> struct uint_parser; /** Matches a signed number of radix `Radix`, of at least `MinDigits` and @@ -429,12 +435,13 @@ namespace boost { namespace parser { int Radix = 10, int MinDigits = 1, int MaxDigits = -1, - typename Expected = detail::nope> + typename Expected = detail::nope, + typename ParserMods = parser_modifiers<>> struct int_parser; /** Matches a floating point number, producing an attribute of type `T`. */ - template + template struct float_parser; /** Applies at most one of the parsers in `OrParser`. If `switch_value_` @@ -442,7 +449,10 @@ namespace boost { namespace parser { first such parser is applied, and the success or failure and attribute of the parse are those of the applied parser. Otherwise, the parse fails. */ - template + template< + typename SwitchValue, + typename OrParser = detail::nope, + typename ParserMods = parser_modifiers<>> struct switch_parser; /** A wrapper for parsers that provides the operations that must be diff --git a/include/boost/parser/replace.hpp b/include/boost/parser/replace.hpp index 58bcf916..fc43b648 100644 --- a/include/boost/parser/replace.hpp +++ b/include/boost/parser/replace.hpp @@ -451,7 +451,7 @@ namespace boost::parser { Parser, GlobalState, ErrorHandler, - parser_interface>>; + parser_interface>>>; template< typename V, @@ -469,7 +469,7 @@ namespace boost::parser { Parser, GlobalState, ErrorHandler, - parser_interface>>; + parser_interface>>>; namespace detail { template< @@ -571,7 +571,8 @@ namespace boost::parser { Parser, GlobalState, ErrorHandler, - parser_interface>> + parser_interface< + eps_parser>>> [[nodiscard]] constexpr auto operator()( R && r, parser_interface const & @@ -582,7 +583,8 @@ namespace boost::parser { return (*this)( (R &&)r, parser, - parser_interface>{}, + parser_interface< + eps_parser>>{}, (ReplacementR &&)replacement, trace_mode); } @@ -623,10 +625,11 @@ namespace boost::parser { std::is_same_v) { // (r, parser, replacement, trace) case return impl( - (R &&) r, + (R &&)r, parser, - parser_interface>{}, - (SkipParser &&) skip, + parser_interface< + eps_parser>>{}, + (SkipParser &&)skip, replacement); } else { static_assert( diff --git a/include/boost/parser/search.hpp b/include/boost/parser/search.hpp index ef54c945..933af5a2 100644 --- a/include/boost/parser/search.hpp +++ b/include/boost/parser/search.hpp @@ -116,7 +116,9 @@ namespace boost::parser { return BOOST_PARSER_SUBRANGE(first, first); auto const search_parser = omit[*(char_ - parser)] >> -raw[parser]; - if constexpr (std::is_same_v>) { + if constexpr (std::is_same_v< + SkipParser, + eps_parser>>) { auto result = parser::prefix_parse( first, last, search_parser, trace_mode); if (*result) @@ -255,9 +257,9 @@ namespace boost::parser { trace trace_mode = trace::off) { return parser::search( - (R &&) r, + (R &&)r, parser, - parser_interface>{}, + parser_interface>>{}, trace_mode); } @@ -292,7 +294,7 @@ namespace boost::parser { return parser::search( BOOST_PARSER_SUBRANGE(first, last), parser, - parser_interface>{}, + parser_interface>>{}, trace_mode); } @@ -483,7 +485,7 @@ namespace boost::parser { Parser, GlobalState, ErrorHandler, - parser_interface>>; + parser_interface>>>; template< typename V, @@ -496,7 +498,7 @@ namespace boost::parser { Parser, GlobalState, ErrorHandler, - parser_interface>>; + parser_interface>>>; namespace detail { template< @@ -569,7 +571,8 @@ namespace boost::parser { Parser, GlobalState, ErrorHandler, - parser_interface>> + parser_interface< + eps_parser>>> [[nodiscard]] constexpr auto operator()( R && r, parser_interface const & @@ -579,7 +582,8 @@ namespace boost::parser { return (*this)( (R &&)r, parser, - parser_interface>{}, + parser_interface< + eps_parser>>{}, trace_mode); } @@ -590,8 +594,8 @@ namespace boost::parser { typename Parser, typename GlobalState, typename ErrorHandler, - typename SkipParser = - parser_interface>, + typename SkipParser = parser_interface< + eps_parser>>, typename Trace = trace, typename Enable = std::enable_if_t>> [[nodiscard]] constexpr auto operator()( @@ -607,9 +611,10 @@ namespace boost::parser { std::is_same_v) { // (r, parser, trace) case return impl( - (R &&) r, + (R &&)r, parser, - parser_interface>{}, + parser_interface< + eps_parser>>{}, skip); } else if constexpr ( detail::is_parser_iface && diff --git a/include/boost/parser/split.hpp b/include/boost/parser/split.hpp index 6b554763..25b1d733 100644 --- a/include/boost/parser/split.hpp +++ b/include/boost/parser/split.hpp @@ -193,14 +193,13 @@ namespace boost::parser { typename Parser, typename GlobalState, typename ErrorHandler> - split_view( - V &&, parser_interface, trace) + split_view(V &&, parser_interface, trace) -> split_view< detail::text::detail::all_t, Parser, GlobalState, ErrorHandler, - parser_interface>>; + parser_interface>>>; template< typename V, @@ -213,7 +212,7 @@ namespace boost::parser { Parser, GlobalState, ErrorHandler, - parser_interface>>; + parser_interface>>>; namespace detail { template< @@ -286,7 +285,8 @@ namespace boost::parser { Parser, GlobalState, ErrorHandler, - parser_interface>> + parser_interface< + eps_parser>>> [[nodiscard]] constexpr auto operator()( R && r, parser_interface const & @@ -296,7 +296,8 @@ namespace boost::parser { return (*this)( (R &&)r, parser, - parser_interface>{}, + parser_interface< + eps_parser>>{}, trace_mode); } @@ -307,8 +308,8 @@ namespace boost::parser { typename Parser, typename GlobalState, typename ErrorHandler, - typename SkipParser = - parser_interface>, + typename SkipParser = parser_interface< + eps_parser>>, typename Trace = trace, typename Enable = std::enable_if_t>> [[nodiscard]] constexpr auto operator()( @@ -324,9 +325,10 @@ namespace boost::parser { std::is_same_v) { // (r, parser, trace) case return impl( - (R &&) r, + (R &&)r, parser, - parser_interface>{}, + parser_interface< + eps_parser>>{}, skip); } else if constexpr ( detail::is_parser_iface && diff --git a/include/boost/parser/transform_replace.hpp b/include/boost/parser/transform_replace.hpp index 51e2d6b3..2c72e74c 100644 --- a/include/boost/parser/transform_replace.hpp +++ b/include/boost/parser/transform_replace.hpp @@ -254,7 +254,9 @@ namespace boost::parser { BOOST_PARSER_SUBRANGE(first, first), parse_result{}); } - if constexpr (std::is_same_v>) { + if constexpr (std::is_same_v< + SkipParser, + eps_parser>>) { auto result = parser::prefix_parse( first, last, search_parser, trace_mode); if (*result) { @@ -578,7 +580,7 @@ namespace boost::parser { Parser, GlobalState, ErrorHandler, - parser_interface>>; + parser_interface>>>; template< typename V, @@ -594,7 +596,7 @@ namespace boost::parser { Parser, GlobalState, ErrorHandler, - parser_interface>>; + parser_interface>>>; namespace detail { template< @@ -697,7 +699,8 @@ namespace boost::parser { Parser, GlobalState, ErrorHandler, - parser_interface>> + parser_interface< + eps_parser>>> [[nodiscard]] constexpr auto operator()( R && r, parser_interface const & @@ -708,7 +711,8 @@ namespace boost::parser { return (*this)( (R &&)r, parser, - parser_interface>{}, + parser_interface< + eps_parser>>{}, (F &&)f, trace_mode); } @@ -753,10 +757,11 @@ namespace boost::parser { std::is_same_v) { // (r, parser, f, trace) case return impl( - to_range::call((R &&) r), + to_range::call((R &&)r), parser, - parser_interface>{}, - (SkipParser &&) skip, + parser_interface< + eps_parser>>{}, + (SkipParser &&)skip, f); } else { static_assert( diff --git a/test/tracing.cpp b/test/tracing.cpp index 1d94fb53..50a15b3d 100644 --- a/test/tracing.cpp +++ b/test/tracing.cpp @@ -156,6 +156,8 @@ int main() << "----------------------------------------\n"; PARSE(omit[char_]); + PARSE(omit[omit[char_]]); + PARSE(omit[*omit[char_]]); std::cout << "\n\n" << "----------------------------------------\n"