Back to home page

EIC code displayed by LXR

 
 

    


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

0001 // Copyright (C) 2024 T. Zachary Laine
0002 //
0003 // Distributed under the Boost Software License, Version 1.0. (See
0004 // accompanying file LICENSE_1_0.txt or copy at
0005 // http://www.boost.org/LICENSE_1_0.txt)
0006 #ifndef BOOST_PARSER_PARSER_HPP
0007 #define BOOST_PARSER_PARSER_HPP
0008 
0009 #include <boost/parser/parser_fwd.hpp>
0010 #include <boost/parser/concepts.hpp>
0011 #include <boost/parser/error_handling.hpp>
0012 #include <boost/parser/tuple.hpp>
0013 #include <boost/parser/detail/hl.hpp>
0014 #include <boost/parser/detail/numeric.hpp>
0015 #include <boost/parser/detail/case_fold.hpp>
0016 #include <boost/parser/detail/unicode_char_sets.hpp>
0017 #include <boost/parser/detail/pp_for_each.hpp>
0018 #include <boost/parser/detail/printing.hpp>
0019 
0020 #include <boost/parser/detail/text/algorithm.hpp>
0021 #include <boost/parser/detail/text/trie_map.hpp>
0022 #include <boost/parser/detail/text/unpack.hpp>
0023 
0024 #include <type_traits>
0025 #include <variant>
0026 #include <vector>
0027 
0028 
0029 namespace boost { namespace parser {
0030 
0031     /** A placeholder type used to represent the absence of information,
0032         value, etc., inside semantic actions.  For instance, calling
0033         `_locals(ctx)` in a semantic action associated with a parser that has
0034         no locals will yield a `none`. */
0035     struct none;
0036 
0037 #if defined(BOOST_PARSER_NO_RUNTIME_ASSERTIONS)
0038     struct none
0039     {};
0040 #else
0041     struct none
0042     {
0043         none() = default;
0044 
0045         // Constructible from, assignable from, and implicitly convertible to,
0046         // anything.
0047         template<typename T>
0048         none(T const &)
0049         {
0050             fail();
0051         }
0052         template<typename T>
0053         none & operator=(T const &)
0054         {
0055             fail();
0056             return *this;
0057         }
0058         template<typename T>
0059         operator T() const
0060         {
0061             fail();
0062             return T{};
0063         }
0064 
0065         // unary operators
0066         none operator+() const
0067         {
0068             fail();
0069             return none{};
0070         }
0071         none operator-() const
0072         {
0073             fail();
0074             return none{};
0075         }
0076         none operator*() const
0077         {
0078             fail();
0079             return none{};
0080         }
0081         none operator~() const
0082         {
0083             fail();
0084             return none{};
0085         }
0086         none operator&() const
0087         {
0088             fail();
0089             return none{};
0090         }
0091         none operator!() const
0092         {
0093             fail();
0094             return none{};
0095         }
0096         none operator++()
0097         {
0098             fail();
0099             return none{};
0100         }
0101         none & operator++(int)
0102         {
0103             fail();
0104             return *this;
0105         }
0106         none operator--()
0107         {
0108             fail();
0109             return none{};
0110         }
0111         none operator--(int)
0112         {
0113             fail();
0114             return *this;
0115         }
0116 
0117         // binary operators
0118         template<typename T>
0119         none operator<<(T const &) const
0120         {
0121             fail();
0122             return none{};
0123         }
0124         template<typename T>
0125         none operator>>(T const &) const
0126         {
0127             fail();
0128             return none{};
0129         }
0130         template<typename T>
0131         none operator*(T const &) const
0132         {
0133             fail();
0134             return none{};
0135         }
0136         template<typename T>
0137         none operator/(T const &) const
0138         {
0139             fail();
0140             return none{};
0141         }
0142         template<typename T>
0143         none operator%(T const &) const
0144         {
0145             fail();
0146             return none{};
0147         }
0148         template<typename T>
0149         none operator+(T const &) const
0150         {
0151             fail();
0152             return none{};
0153         }
0154         template<typename T>
0155         none operator-(T const &) const
0156         {
0157             fail();
0158             return none{};
0159         }
0160         template<typename T>
0161         none operator<(T const &) const
0162         {
0163             fail();
0164             return none{};
0165         }
0166         template<typename T>
0167         none operator>(T const &) const
0168         {
0169             fail();
0170             return none{};
0171         }
0172         template<typename T>
0173         none operator<=(T const &) const
0174         {
0175             fail();
0176             return none{};
0177         }
0178         template<typename T>
0179         none operator>=(T const &) const
0180         {
0181             fail();
0182             return none{};
0183         }
0184         template<typename T>
0185         none operator==(T const &) const
0186         {
0187             fail();
0188             return none{};
0189         }
0190         template<typename T>
0191         none operator!=(T const &) const
0192         {
0193             fail();
0194             return none{};
0195         }
0196         template<typename T>
0197         none operator||(T const &) const
0198         {
0199             fail();
0200             return none{};
0201         }
0202         template<typename T>
0203         none operator&&(T const &) const
0204         {
0205             fail();
0206             return none{};
0207         }
0208         template<typename T>
0209         none operator&(T const &) const
0210         {
0211             fail();
0212             return none{};
0213         }
0214         template<typename T>
0215         none operator|(T const &) const
0216         {
0217             fail();
0218             return none{};
0219         }
0220         template<typename T>
0221         none operator^(T const &) const
0222         {
0223             fail();
0224             return none{};
0225         }
0226         template<typename T>
0227         none operator,(T const &) const
0228         {
0229             fail();
0230             return none{};
0231         }
0232         template<typename T>
0233         none operator->*(T const &) const
0234         {
0235             fail();
0236             return none{};
0237         }
0238         template<typename T>
0239         none operator<<=(T const &)
0240         {
0241             fail();
0242             return none{};
0243         }
0244         template<typename T>
0245         none operator>>=(T const &)
0246         {
0247             fail();
0248             return none{};
0249         }
0250         template<typename T>
0251         none operator*=(T const &)
0252         {
0253             fail();
0254             return none{};
0255         }
0256         template<typename T>
0257         none operator/=(T const &)
0258         {
0259             fail();
0260             return none{};
0261         }
0262         template<typename T>
0263         none operator%=(T const &)
0264         {
0265             fail();
0266             return none{};
0267         }
0268         template<typename T>
0269         none operator+=(T const &)
0270         {
0271             fail();
0272             return none{};
0273         }
0274         template<typename T>
0275         none operator-=(T const &)
0276         {
0277             fail();
0278             return none{};
0279         }
0280         template<typename T>
0281         none operator&=(T const &)
0282         {
0283             fail();
0284             return none{};
0285         }
0286         template<typename T>
0287         none operator|=(T const &)
0288         {
0289             fail();
0290             return none{};
0291         }
0292         template<typename T>
0293         none operator^=(T const &)
0294         {
0295             fail();
0296             return none{};
0297         }
0298         template<typename T>
0299         none operator[](T const &) const
0300         {
0301             fail();
0302             return none{};
0303         }
0304 
0305         // n-ary operators
0306         template<typename... Args>
0307         none operator()(Args const &...) const
0308         {
0309             fail();
0310             return none{};
0311         }
0312 
0313         void fail() const
0314         {
0315             // If you're seeing this, you've probably gotten a `none` out of
0316             // the parse context, and are trying to use it because you think
0317             // it's something else.  For instance, if your parser produces an
0318             // int attribute, the semantic ation `[](auto & ctx) { _attr(ctx)
0319             // = 0; }` may be fine.  If you attach that same semantic action
0320             // to `eps`, you end up here, because `eps` has no attribute, and
0321             // so `_attr(ctx)` produces a `none`.
0322             BOOST_PARSER_DEBUG_ASSERT(false);
0323         }
0324     };
0325 #endif
0326 
0327     namespace detail {
0328         // Follows boost/mpl/print.hpp.
0329 #if defined(_MSC_VER)
0330 #pragma warning(push, 3)
0331 #pragma warning(disable : 4307)
0332 #endif
0333 #if defined(__EDG_VERSION__)
0334         namespace print_aux {
0335             template<typename T>
0336             struct dependent_unsigned
0337             {
0338                 static const unsigned int value = 1;
0339             };
0340         }
0341 #endif
0342         template<typename T>
0343         struct identity_t
0344         {
0345             using type = T;
0346         };
0347         template<typename T>
0348         struct print_t : identity_t<T>
0349         {
0350 #if defined(__clang__)
0351 #pragma clang diagnostic push
0352 #pragma clang diagnostic ignored "-Wc++11-extensions"
0353             const int x_ = 1 / (sizeof(T) - sizeof(T));
0354 #pragma clang diagnostic pop
0355 #elif defined(_MSC_VER)
0356             enum { n = sizeof(T) + -1 };
0357 #elif defined(__MWERKS__)
0358             void f(int);
0359 #else
0360             enum {
0361                 n =
0362 #if defined(__EDG_VERSION__)
0363                     print_aux::dependent_unsigned<T>::value > -1
0364 #else
0365                     sizeof(T) > -1
0366 #endif
0367             };
0368 #endif
0369         };
0370 #if defined(_MSC_VER)
0371 #pragma warning(pop)
0372 #endif
0373 
0374         template<typename T>
0375         using print_type = typename print_t<T>::type;
0376 
0377         template<typename R, typename Parser>
0378         struct attribute_impl;
0379 
0380         // Utility types.
0381 
0382         struct nope
0383         {
0384             template<typename T>
0385             constexpr nope & operator=(T const &)
0386             {
0387                 return *this;
0388             }
0389 
0390             operator std::nullopt_t() const noexcept { return std::nullopt; }
0391 
0392             template<typename Context>
0393             constexpr bool operator()(Context const &) const noexcept
0394             {
0395                 return true;
0396             }
0397 
0398             constexpr nope operator*() const noexcept { return nope{}; }
0399 
0400             friend constexpr bool operator==(nope, nope) { return true; }
0401             friend constexpr bool operator!=(nope, nope) { return false; }
0402 
0403             template<typename T>
0404             friend constexpr bool operator==(T, nope)
0405             {
0406                 return false;
0407             }
0408             template<typename T>
0409             friend constexpr bool operator!=(T, nope)
0410             {
0411                 return false;
0412             }
0413         };
0414 
0415         inline nope global_nope;
0416 
0417         template<typename T>
0418         using parser_interface_tag_expr =
0419             typename T::parser_interface_derivation_tag;
0420         template<typename T>
0421         constexpr bool derived_from_parser_interface_v =
0422             is_detected_v<parser_interface_tag_expr, T>;
0423 
0424         template<typename T, bool AlwaysConst = false>
0425         using nope_or_pointer_t = std::conditional_t<
0426             std::is_same_v<std::remove_const_t<T>, nope>,
0427             nope,
0428             std::conditional_t<AlwaysConst, T const *, T *>>;
0429 
0430         template<
0431             bool DoTrace,
0432             bool UseCallbacks,
0433             typename I,
0434             typename S,
0435             typename ErrorHandler,
0436             typename GlobalState = nope,
0437             typename Callbacks = nope,
0438             typename Attr = nope,
0439             typename Val = nope,
0440             typename RuleTag = void,
0441             typename RuleLocals = nope,
0442             typename RuleParams = nope,
0443             typename Where = nope>
0444         struct parse_context
0445         {
0446             parse_context() = default;
0447             parse_context(parse_context const &) = default;
0448             parse_context & operator=(parse_context const &) = default;
0449 
0450             using rule_tag = RuleTag;
0451 
0452             static constexpr bool do_trace = DoTrace;
0453             static constexpr bool use_callbacks = UseCallbacks;
0454 
0455             I first_;
0456             S last_;
0457             bool * pass_ = nullptr;
0458             int * trace_indent_ = nullptr;
0459             symbol_table_tries_t * symbol_table_tries_ = nullptr;
0460             pending_symbol_table_operations_t *
0461                 pending_symbol_table_operations_ = nullptr;
0462             ErrorHandler const * error_handler_ = nullptr;
0463             nope_or_pointer_t<GlobalState> globals_{};
0464             nope_or_pointer_t<Callbacks, true> callbacks_{};
0465             nope_or_pointer_t<Attr> attr_{};
0466             nope_or_pointer_t<Val> val_{};
0467             nope_or_pointer_t<RuleLocals> locals_{};
0468             nope_or_pointer_t<RuleParams, true> params_{};
0469             nope_or_pointer_t<Where, true> where_{};
0470             int no_case_depth_ = 0;
0471 
0472             template<typename T>
0473             static auto nope_or_address(T & x)
0474             {
0475                 if constexpr (std::is_same_v<std::remove_const_t<T>, nope>)
0476                     return nope{};
0477                 else
0478                     return std::addressof(x);
0479             }
0480 
0481             template<typename T, typename U>
0482             static auto other_or_address(T other, U & x)
0483             {
0484                 if constexpr (std::is_same_v<std::remove_const_t<U>, nope>)
0485                     return other;
0486                 else
0487                     return std::addressof(x);
0488             }
0489 
0490             parse_context(
0491                 std::bool_constant<DoTrace>,
0492                 std::bool_constant<UseCallbacks>,
0493                 I & first,
0494                 S last,
0495                 bool & success,
0496                 int & indent,
0497                 ErrorHandler const & error_handler,
0498                 GlobalState & globals,
0499                 symbol_table_tries_t & symbol_table_tries,
0500                 pending_symbol_table_operations_t &
0501                     pending_symbol_table_operations) :
0502                 first_(first),
0503                 last_(last),
0504                 pass_(std::addressof(success)),
0505                 trace_indent_(std::addressof(indent)),
0506                 symbol_table_tries_(std::addressof(symbol_table_tries)),
0507                 pending_symbol_table_operations_(
0508                     std::addressof(pending_symbol_table_operations)),
0509                 error_handler_(std::addressof(error_handler)),
0510                 globals_(nope_or_address(globals))
0511             {}
0512 
0513             // With callbacks.
0514             parse_context(
0515                 std::bool_constant<DoTrace>,
0516                 std::bool_constant<UseCallbacks>,
0517                 I & first,
0518                 S last,
0519                 bool & success,
0520                 int & indent,
0521                 ErrorHandler const & error_handler,
0522                 Callbacks const & callbacks,
0523                 GlobalState & globals,
0524                 symbol_table_tries_t & symbol_table_tries,
0525                 pending_symbol_table_operations_t &
0526                     pending_symbol_table_operations) :
0527                 first_(first),
0528                 last_(last),
0529                 pass_(std::addressof(success)),
0530                 trace_indent_(std::addressof(indent)),
0531                 symbol_table_tries_(std::addressof(symbol_table_tries)),
0532                 pending_symbol_table_operations_(
0533                     std::addressof(pending_symbol_table_operations)),
0534                 error_handler_(std::addressof(error_handler)),
0535                 globals_(nope_or_address(globals)),
0536                 callbacks_(std::addressof(callbacks))
0537             {}
0538 
0539             // For making rule contexts.
0540             template<
0541                 typename OldVal,
0542                 typename OldRuleTag,
0543                 typename OldRuleLocals,
0544                 typename OldRuleParams,
0545                 typename NewVal,
0546                 typename NewRuleTag,
0547                 typename NewRuleLocals,
0548                 typename NewRuleParams>
0549             parse_context(
0550                 parse_context<
0551                     DoTrace,
0552                     UseCallbacks,
0553                     I,
0554                     S,
0555                     ErrorHandler,
0556                     GlobalState,
0557                     Callbacks,
0558                     Attr,
0559                     OldVal,
0560                     OldRuleTag,
0561                     OldRuleLocals,
0562                     OldRuleParams> const & other,
0563                 NewRuleTag * tag_ptr,
0564                 NewVal & value,
0565                 NewRuleLocals & locals,
0566                 NewRuleParams const & params) :
0567                 first_(other.first_),
0568                 last_(other.last_),
0569                 pass_(other.pass_),
0570                 trace_indent_(other.trace_indent_),
0571                 symbol_table_tries_(other.symbol_table_tries_),
0572                 pending_symbol_table_operations_(
0573                     other.pending_symbol_table_operations_),
0574                 error_handler_(other.error_handler_),
0575                 globals_(other.globals_),
0576                 callbacks_(other.callbacks_),
0577                 attr_(other.attr_),
0578                 no_case_depth_(other.no_case_depth_)
0579             {
0580                 if constexpr (
0581                     std::is_same_v<OldRuleTag, NewRuleTag> &&
0582                     !std::is_same_v<OldRuleTag, void>) {
0583                     val_ = other.val_;
0584                     locals_ = other.locals_;
0585                     params_ = other.params_;
0586                 } else {
0587                     val_ = other_or_address(other.val_, value);
0588                     locals_ = other_or_address(other.locals_, locals);
0589                     params_ = other_or_address(other.params_, params);
0590                 }
0591             }
0592 
0593             // For making action contexts.
0594             template<typename OldAttr, typename OldWhere>
0595             parse_context(
0596                 parse_context<
0597                     DoTrace,
0598                     UseCallbacks,
0599                     I,
0600                     S,
0601                     ErrorHandler,
0602                     GlobalState,
0603                     Callbacks,
0604                     OldAttr,
0605                     Val,
0606                     RuleTag,
0607                     RuleLocals,
0608                     RuleParams,
0609                     OldWhere> const & other,
0610                 Attr & attr,
0611                 Where const & where) :
0612                 first_(other.first_),
0613                 last_(other.last_),
0614                 pass_(other.pass_),
0615                 trace_indent_(other.trace_indent_),
0616                 symbol_table_tries_(other.symbol_table_tries_),
0617                 pending_symbol_table_operations_(
0618                     other.pending_symbol_table_operations_),
0619                 error_handler_(other.error_handler_),
0620                 globals_(other.globals_),
0621                 callbacks_(other.callbacks_),
0622                 attr_(nope_or_address(attr)),
0623                 val_(other.val_),
0624                 locals_(other.locals_),
0625                 params_(other.params_),
0626                 where_(nope_or_address(where)),
0627                 no_case_depth_(other.no_case_depth_)
0628             {}
0629         };
0630 
0631         template<
0632             bool DoTrace,
0633             bool UseCallbacks,
0634             typename I,
0635             typename S,
0636             typename ErrorHandler,
0637             typename GlobalState,
0638             typename Callbacks,
0639             typename Val,
0640             typename RuleTag,
0641             typename RuleLocals,
0642             typename RuleParams,
0643             typename Attr,
0644             typename Where,
0645             typename OldAttr>
0646         auto make_action_context(
0647             parse_context<
0648                 DoTrace,
0649                 UseCallbacks,
0650                 I,
0651                 S,
0652                 ErrorHandler,
0653                 GlobalState,
0654                 Callbacks,
0655                 OldAttr,
0656                 Val,
0657                 RuleTag,
0658                 RuleLocals,
0659                 RuleParams> const & context,
0660             Attr & attr,
0661             Where const & where)
0662         {
0663             using result_type = parse_context<
0664                 DoTrace,
0665                 UseCallbacks,
0666                 I,
0667                 S,
0668                 ErrorHandler,
0669                 GlobalState,
0670                 Callbacks,
0671                 Attr,
0672                 Val,
0673                 RuleTag,
0674                 RuleLocals,
0675                 RuleParams,
0676                 Where>;
0677             return result_type(context, attr, where);
0678         }
0679 
0680         template<
0681             bool DoTrace,
0682             bool UseCallbacks,
0683             typename I,
0684             typename S,
0685             typename ErrorHandler,
0686             typename GlobalState,
0687             typename Callbacks,
0688             typename Attr,
0689             typename Val,
0690             typename RuleTag,
0691             typename RuleLocals,
0692             typename RuleParams,
0693             typename NewVal,
0694             typename NewRuleTag,
0695             typename NewRuleLocals,
0696             typename NewRuleParams>
0697         auto make_rule_context(
0698             parse_context<
0699                 DoTrace,
0700                 UseCallbacks,
0701                 I,
0702                 S,
0703                 ErrorHandler,
0704                 GlobalState,
0705                 Callbacks,
0706                 Attr,
0707                 Val,
0708                 RuleTag,
0709                 RuleLocals,
0710                 RuleParams> const & context,
0711             NewRuleTag * tag_ptr,
0712             NewVal & value,
0713             NewRuleLocals & locals,
0714             NewRuleParams const & params)
0715         {
0716             using result_type = parse_context<
0717                 DoTrace,
0718                 UseCallbacks,
0719                 I,
0720                 S,
0721                 ErrorHandler,
0722                 GlobalState,
0723                 Callbacks,
0724                 Attr,
0725                 std::conditional_t<std::is_same_v<NewVal, nope>, Val, NewVal>,
0726                 NewRuleTag,
0727                 std::conditional_t<
0728                     std::is_same_v<NewRuleLocals, nope>,
0729                     RuleLocals,
0730                     NewRuleLocals>,
0731                 std::conditional_t<
0732                     std::is_same_v<NewRuleParams, nope>,
0733                     RuleParams,
0734                     NewRuleParams>>;
0735             return result_type(context, tag_ptr, value, locals, params);
0736         }
0737 
0738         template<
0739             bool DoTrace,
0740             bool UseCallbacks,
0741             typename Iter,
0742             typename Sentinel,
0743             typename ErrorHandler>
0744         auto make_context(
0745             Iter first,
0746             Sentinel last,
0747             bool & success,
0748             int & indent,
0749             ErrorHandler const & error_handler,
0750             nope & n,
0751             symbol_table_tries_t & symbol_table_tries,
0752             pending_symbol_table_operations_t &
0753                 pending_symbol_table_operations) noexcept
0754         {
0755             return parse_context(
0756                 std::bool_constant<DoTrace>{},
0757                 std::bool_constant<UseCallbacks>{},
0758                 first,
0759                 last,
0760                 success,
0761                 indent,
0762                 error_handler,
0763                 n,
0764                 symbol_table_tries,
0765                 pending_symbol_table_operations);
0766         }
0767 
0768         template<
0769             bool DoTrace,
0770             bool UseCallbacks,
0771             typename Iter,
0772             typename Sentinel,
0773             typename ErrorHandler,
0774             typename GlobalState>
0775         auto make_context(
0776             Iter first,
0777             Sentinel last,
0778             bool & success,
0779             int & indent,
0780             ErrorHandler const & error_handler,
0781             GlobalState & globals,
0782             symbol_table_tries_t & symbol_table_tries,
0783             pending_symbol_table_operations_t &
0784                 pending_symbol_table_operations) noexcept
0785         {
0786             return parse_context(
0787                 std::bool_constant<DoTrace>{},
0788                 std::bool_constant<UseCallbacks>{},
0789                 first,
0790                 last,
0791                 success,
0792                 indent,
0793                 error_handler,
0794                 globals,
0795                 symbol_table_tries,
0796                 pending_symbol_table_operations);
0797         }
0798 
0799         template<
0800             bool DoTrace,
0801             bool UseCallbacks,
0802             typename Iter,
0803             typename Sentinel,
0804             typename ErrorHandler,
0805             typename Callbacks>
0806         auto make_context(
0807             Iter first,
0808             Sentinel last,
0809             bool & success,
0810             int & indent,
0811             ErrorHandler const & error_handler,
0812             Callbacks const & callbacks,
0813             nope & n,
0814             symbol_table_tries_t & symbol_table_tries,
0815             pending_symbol_table_operations_t &
0816                 pending_symbol_table_operations) noexcept
0817         {
0818             return parse_context(
0819                 std::bool_constant<DoTrace>{},
0820                 std::bool_constant<UseCallbacks>{},
0821                 first,
0822                 last,
0823                 success,
0824                 indent,
0825                 error_handler,
0826                 callbacks,
0827                 n,
0828                 symbol_table_tries,
0829                 pending_symbol_table_operations);
0830         }
0831 
0832         template<
0833             bool DoTrace,
0834             bool UseCallbacks,
0835             typename Iter,
0836             typename Sentinel,
0837             typename ErrorHandler,
0838             typename Callbacks,
0839             typename GlobalState>
0840         auto make_context(
0841             Iter first,
0842             Sentinel last,
0843             bool & success,
0844             int & indent,
0845             ErrorHandler const & error_handler,
0846             Callbacks const & callbacks,
0847             GlobalState & globals,
0848             symbol_table_tries_t & symbol_table_tries,
0849             pending_symbol_table_operations_t &
0850                 pending_symbol_table_operations) noexcept
0851         {
0852             return parse_context(
0853                 std::bool_constant<DoTrace>{},
0854                 std::bool_constant<UseCallbacks>{},
0855                 first,
0856                 last,
0857                 success,
0858                 indent,
0859                 error_handler,
0860                 callbacks,
0861                 globals,
0862                 symbol_table_tries,
0863                 pending_symbol_table_operations);
0864         }
0865 
0866 
0867         template<unsigned int I>
0868         struct param_t
0869         {
0870             template<typename Context>
0871             decltype(auto) operator()(Context const & context) const
0872             {
0873                 return parser::get(parser::_params(context), llong<I>{});
0874             }
0875         };
0876 
0877 
0878         template<typename T, typename... Args>
0879         using callable = decltype(std::declval<T>()(std::declval<Args>()...));
0880 
0881         template<
0882             typename Context,
0883             typename T,
0884             bool Callable = is_detected_v<callable, T const &, Context const &>>
0885         struct resolve_impl
0886         {
0887             static auto call(Context const &, T const & x) { return x; }
0888         };
0889 
0890         template<typename Context, typename T>
0891         struct resolve_impl<Context, T, true>
0892         {
0893             static auto call(Context const & context, T const & x)
0894             {
0895                 return x(context);
0896             }
0897         };
0898 
0899         template<typename Context, typename T>
0900         auto resolve(Context const & context, T const & x)
0901         {
0902             return resolve_impl<Context, T>::call(context, x);
0903         }
0904 
0905         template<typename Context>
0906         auto resolve(Context const &, nope n)
0907         {
0908             return n;
0909         }
0910 
0911 
0912         template<typename Context, typename ParamsTuple>
0913         auto
0914         resolve_rule_params(Context const & context, ParamsTuple const & params)
0915         {
0916             return detail::hl::transform(params, [&](auto const & x) {
0917                 return detail::resolve(context, x);
0918             });
0919         }
0920 
0921         template<typename Context>
0922         nope resolve_rule_params(Context const & context, nope)
0923         {
0924             return {};
0925         }
0926 
0927         template<typename LocalsType, typename Context>
0928         LocalsType make_locals_impl(Context const & context, std::true_type)
0929         {
0930             return LocalsType(context);
0931         }
0932 
0933         template<typename LocalsType, typename Context>
0934         LocalsType make_locals_impl(Context const & context, std::false_type)
0935         {
0936             return LocalsType();
0937         }
0938 
0939         template<typename LocalsType, typename Context>
0940         LocalsType make_locals(Context const & context)
0941         {
0942             return detail::make_locals_impl<LocalsType>(
0943                 context,
0944                 typename std::is_convertible<Context const &, LocalsType>::
0945                     type{});
0946         }
0947 
0948 
0949         template<typename Context>
0950         decltype(auto) _indent(Context const & context)
0951         {
0952             return *context.trace_indent_;
0953         }
0954 
0955         template<typename Context>
0956         decltype(auto) _callbacks(Context const & context)
0957         {
0958             return *context.callbacks_;
0959         }
0960 
0961 
0962         // Type traits.
0963 
0964         template<typename T>
0965         using remove_cv_ref_t = typename std::remove_cv<
0966             typename std::remove_reference<T>::type>::type;
0967 
0968         template<typename T, typename U>
0969         using comparison = decltype(std::declval<T>() == std::declval<U>());
0970 
0971         template<typename T, typename U>
0972         constexpr bool is_equality_comparable_with_v =
0973             is_detected_v<comparison, T, U>;
0974 
0975         template<typename T>
0976         struct is_nope : std::false_type
0977         {};
0978         template<>
0979         struct is_nope<nope> : std::true_type
0980         {};
0981         template<typename T>
0982         constexpr bool is_nope_v = is_nope<remove_cv_ref_t<T>>::value;
0983 
0984         template<typename T>
0985         struct is_eps_p : std::false_type
0986         {};
0987         template<typename T>
0988         struct is_eps_p<eps_parser<T>> : std::true_type
0989         {};
0990 
0991         template<typename T>
0992         struct is_unconditional_eps : std::false_type
0993         {};
0994         template<>
0995         struct is_unconditional_eps<eps_parser<nope>> : std::true_type
0996         {};
0997         template<typename T>
0998         constexpr bool is_unconditional_eps_v =
0999             is_unconditional_eps<remove_cv_ref_t<T>>::value;
1000 
1001         template<typename T>
1002         struct is_zero_plus_p : std::false_type
1003         {};
1004         template<typename T>
1005         struct is_zero_plus_p<zero_plus_parser<T>> : std::true_type
1006         {};
1007 
1008         template<typename T>
1009         struct is_or_p : std::false_type
1010         {};
1011         template<typename T>
1012         struct is_or_p<or_parser<T>> : std::true_type
1013         {};
1014 
1015         template<typename T>
1016         struct is_perm_p : std::false_type
1017         {};
1018         template<typename T, typename DelimiterParser>
1019         struct is_perm_p<perm_parser<T, DelimiterParser>> : std::true_type
1020         {};
1021 
1022         template<typename T>
1023         struct is_seq_p : std::false_type
1024         {};
1025         template<typename T, typename U, typename V>
1026         struct is_seq_p<seq_parser<T, U, V>> : std::true_type
1027         {};
1028 
1029         template<typename T>
1030         struct is_one_plus_p : std::false_type
1031         {};
1032         template<typename T>
1033         struct is_one_plus_p<one_plus_parser<T>> : std::true_type
1034         {};
1035 
1036         template<typename T>
1037         struct is_utf8_view : std::false_type
1038         {};
1039         template<typename V>
1040         struct is_utf8_view<text::utf8_view<V>> : std::true_type
1041         {};
1042 
1043         template<typename T>
1044         using optional_type = remove_cv_ref_t<decltype(*std::declval<T &>())>;
1045 
1046         template<typename F, typename... Args>
1047         constexpr bool is_invocable_v = is_detected_v<callable, F, Args...>;
1048 
1049         template<typename T>
1050         using has_begin =
1051             decltype(*detail::text::detail::begin(std::declval<T &>()));
1052         template<typename T>
1053         using has_end =
1054             decltype(detail::text::detail::end(std::declval<T &>()));
1055 
1056         template<typename T>
1057         constexpr bool is_range =
1058             is_detected_v<has_begin, T> && is_detected_v<has_end, T>;
1059 
1060         template<typename T>
1061         using has_push_back =
1062             decltype(std::declval<T &>().push_back(*std::declval<T>().begin()));
1063 
1064 #if BOOST_PARSER_USE_CONCEPTS
1065 
1066         template<typename T>
1067         using iterator_t = std::ranges::iterator_t<T>;
1068         template<typename T>
1069         using sentinel_t = std::ranges::sentinel_t<T>;
1070         template<typename T>
1071         using iter_value_t = std::iter_value_t<T>;
1072         template<typename T>
1073         using iter_reference_t = std::iter_reference_t<T>;
1074         template<typename T>
1075         using range_value_t = std::ranges::range_value_t<T>;
1076         template<typename T>
1077         using range_reference_t = std::ranges::range_reference_t<T>;
1078         template<typename T>
1079         using range_rvalue_reference_t =
1080             std::ranges::range_rvalue_reference_t<T>;
1081 
1082         template<typename T>
1083         constexpr bool is_parsable_code_unit_v = code_unit<T>;
1084 
1085 #else
1086 
1087         template<typename T>
1088         using iterator_t =
1089             decltype(detail::text::detail::begin(std::declval<T &>()));
1090         template<typename Range>
1091         using sentinel_t =
1092             decltype(detail::text::detail::end(std::declval<Range &>()));
1093         template<typename T>
1094         using iter_value_t = typename std::iterator_traits<T>::value_type;
1095         template<typename T>
1096         using iter_reference_t = decltype(*std::declval<T &>());
1097         template<typename T>
1098         using iter_rvalue_reference_t =
1099             decltype(std::move(*std::declval<T &>()));
1100         template<typename T>
1101         using range_value_t = iter_value_t<iterator_t<T>>;
1102         template<typename T>
1103         using range_reference_t = iter_reference_t<iterator_t<T>>;
1104         template<typename T>
1105         using range_rvalue_reference_t = iter_rvalue_reference_t<iterator_t<T>>;
1106 
1107         template<typename T>
1108         using has_insert = decltype(std::declval<T &>().insert(
1109             std::declval<T>().begin(), *std::declval<T>().begin()));
1110         template<typename T>
1111         using has_range_insert = decltype(std::declval<T &>().insert(
1112             std::declval<T>().begin(),
1113             std::declval<T>().begin(),
1114             std::declval<T>().end()));
1115 
1116         template<typename T>
1117         constexpr bool is_container_v = is_detected_v<has_insert, T>;
1118 
1119         template<typename T, typename U>
1120         constexpr bool container_and_value_type =
1121             is_container_v<T> &&
1122             (std::is_same_v<detected_t<range_value_t, T>, U> ||
1123              (std::is_same_v<T, std::string> && std::is_same_v<U, char32_t>));
1124 
1125         template<typename T>
1126         constexpr bool is_parsable_code_unit_impl =
1127             std::is_same_v<T, char> || std::is_same_v<T, wchar_t> ||
1128 #if defined(__cpp_char8_t)
1129             std::is_same_v<T, char8_t> ||
1130 #endif
1131             std::is_same_v<T, char16_t> || std::is_same_v<T, char32_t>;
1132 
1133         template<typename T>
1134         constexpr bool is_parsable_code_unit_v =
1135             is_parsable_code_unit_impl<std::remove_cv_t<T>>;
1136 
1137         template<typename T>
1138         constexpr bool is_parsable_iter_v = is_parsable_code_unit_v<
1139             remove_cv_ref_t<detected_t<iter_value_t, T>>>;
1140 
1141         template<typename T>
1142         constexpr bool is_parsable_range_v = is_parsable_code_unit_v<
1143             remove_cv_ref_t<detected_t<has_begin, T>>> &&
1144             is_detected_v<has_end, T>;
1145 
1146         template<typename T>
1147         constexpr bool is_parsable_pointer_v =
1148             std::is_pointer_v<remove_cv_ref_t<T>> && is_parsable_code_unit_v<
1149                 std::remove_pointer_t<remove_cv_ref_t<T>>>;
1150 
1151         template<typename T>
1152         constexpr bool is_parsable_range_like_v =
1153             is_parsable_range_v<T> || is_parsable_pointer_v<T>;
1154     }
1155 
1156     template<typename T>
1157     constexpr bool container = detail::is_container_v<T>;
1158 
1159     namespace detail {
1160 #endif
1161 
1162         template<typename T, bool = std::is_pointer_v<T>>
1163         constexpr bool is_code_unit_pointer_v = false;
1164         template<typename T>
1165         constexpr bool is_code_unit_pointer_v<T, true> =
1166             is_parsable_code_unit_v<std::remove_pointer_t<T>>;
1167 
1168         template<typename T>
1169         constexpr bool is_range_like = is_range<T> || is_code_unit_pointer_v<T>;
1170 
1171         template<typename I>
1172         constexpr bool is_char8_iter_v =
1173 #if defined(__cpp_char8_t)
1174             std::is_same_v<iter_value_t<I>, char8_t>
1175 #else
1176             false
1177 #endif
1178             ;
1179 
1180         // Metafunctions.
1181 
1182         template<bool WrapInOptional, typename Tuple>
1183         struct to_hana_tuple_or_type_impl;
1184 
1185         template<typename... T>
1186         struct to_hana_tuple_or_type_impl<true, tuple<T...>>
1187         {
1188             using type = std::optional<std::variant<T...>>;
1189         };
1190 
1191         template<typename... T>
1192         struct to_hana_tuple_or_type_impl<false, tuple<T...>>
1193         {
1194             using type = std::variant<T...>;
1195         };
1196 
1197         template<typename T>
1198         struct to_hana_tuple_or_type_impl<true, tuple<T>>
1199         {
1200             // The reason this is not two separate specializations, one
1201             // for tuple<t> and on for tuple<optional<T>>, is because
1202             // MSVC.
1203             using type =
1204                 std::conditional_t<is_optional_v<T>, T, std::optional<T>>;
1205         };
1206 
1207         template<typename T>
1208         struct to_hana_tuple_or_type_impl<false, tuple<T>>
1209         {
1210             using type = T;
1211         };
1212 
1213         template<>
1214         struct to_hana_tuple_or_type_impl<true, tuple<>>
1215         {
1216             using type = nope;
1217         };
1218 
1219         template<>
1220         struct to_hana_tuple_or_type_impl<false, tuple<>>
1221         {
1222             using type = nope;
1223         };
1224 
1225         template<typename Pair>
1226         struct to_hana_tuple_or_type;
1227 
1228         template<typename Tuple, typename TrueFalse>
1229         struct to_hana_tuple_or_type<tuple<Tuple, TrueFalse>>
1230         {
1231             // This has to be done in two steps like this because MSVC.
1232             using type =
1233                 typename to_hana_tuple_or_type_impl<TrueFalse::value, Tuple>::
1234                     type;
1235         };
1236 
1237         template<typename T>
1238         using to_hana_tuple_or_type_t = typename to_hana_tuple_or_type<T>::type;
1239 
1240         template<typename T>
1241         auto make_sequence_of()
1242         {
1243             if constexpr (
1244                 std::is_same_v<T, char> || std::is_same_v<T, char32_t>) {
1245                 return std::string{};
1246             } else if constexpr (std::is_same_v<T, nope>) {
1247                 return nope{};
1248             } else {
1249                 return std::vector<T>{};
1250             }
1251         }
1252 
1253         template<typename T>
1254         constexpr bool is_char_type_v =
1255             std::is_same_v<T, char> || std::is_same_v<T, char32_t>;
1256 
1257         template<typename T>
1258         struct optional_of_impl
1259         {
1260             using type = std::optional<T>;
1261         };
1262 
1263         template<typename T>
1264         struct optional_of_impl<std::optional<T>>
1265         {
1266             using type = std::optional<T>;
1267         };
1268 
1269         template<>
1270         struct optional_of_impl<nope>
1271         {
1272             using type = nope;
1273         };
1274 
1275         template<typename T>
1276         using optional_of = typename optional_of_impl<T>::type;
1277 
1278         template<typename T>
1279         struct unwrapped_optional
1280         {
1281             using type = T;
1282         };
1283         template<typename T>
1284         struct unwrapped_optional<std::optional<T>>
1285         {
1286             using type = T;
1287         };
1288         template<typename T>
1289         using unwrapped_optional_t = typename unwrapped_optional<T>::type;
1290 
1291 
1292 
1293         // Etc.
1294 
1295         template<typename T>
1296         struct wrapper
1297         {
1298             using type = T;
1299 
1300             constexpr bool operator==(wrapper) const { return true; }
1301         };
1302 
1303         struct wrap
1304         {
1305             template<typename T>
1306             constexpr auto operator()(T type) const
1307             {
1308                 return wrapper<T>{};
1309             }
1310         };
1311 
1312         struct unwrap
1313         {
1314             template<typename T>
1315             constexpr auto operator()(T wrapped_type) const
1316             {
1317                 return typename T::type{};
1318             }
1319         };
1320 
1321         template<typename Container, typename T>
1322         void insert(Container & c, T && x)
1323         {
1324             if constexpr (is_detected_v<has_push_back, Container>) {
1325                 c.push_back((T &&) x);
1326             } else {
1327                 c.insert((T &&) x);
1328             }
1329         }
1330 
1331         template<typename Container, typename I>
1332         void insert(Container & c, I first, I last)
1333         {
1334             std::for_each(first, last, [&](auto && x) {
1335                 using type = decltype(x);
1336                 insert(c, (type &&) x);
1337             });
1338         }
1339 
1340         template<typename Container, typename T>
1341         constexpr bool needs_transcoding_to_utf8 =
1342             (std::is_same_v<range_value_t<remove_cv_ref_t<Container>>, char>
1343 #if defined(__cpp_char8_t)
1344              || std::is_same_v<range_value_t<remove_cv_ref_t<Container>>, char8_t>
1345 #endif
1346                 ) && (std::is_same_v<remove_cv_ref_t<T>, char32_t>
1347 #if !defined(_MSC_VER)
1348              || std::is_same_v<remove_cv_ref_t<T>, wchar_t>
1349 #endif
1350              );
1351 
1352         template<typename Container, typename T>
1353         void append(Container & c, T && x, bool gen_attrs)
1354         {
1355             if (!gen_attrs)
1356                 return;
1357             if constexpr (needs_transcoding_to_utf8<Container, T>) {
1358                 char32_t cps[1] = {(char32_t)x};
1359                 auto const r = cps | text::as_utf8;
1360                 c.insert(c.end(), r.begin(), r.end());
1361             } else {
1362                 detail::insert(c, std::move(x));
1363             }
1364         }
1365 
1366         template<typename Container, typename T>
1367         void append(std::optional<Container> & c, T && x, bool gen_attrs)
1368         {
1369             if (!gen_attrs)
1370                 return;
1371             if (!c)
1372                 c = Container();
1373             return detail::append(*c, (T &&) x, gen_attrs);
1374         }
1375 
1376         template<typename Container>
1377         void append(Container & c, nope &&, bool)
1378         {}
1379 
1380         template<typename T>
1381         void append(nope &, T &&, bool)
1382         {}
1383 
1384         inline void append(nope &, nope &&, bool) {}
1385 
1386         template<typename Container, typename Iter, typename Sentinel>
1387         void append(Container & c, Iter first, Sentinel last, bool gen_attrs)
1388         {
1389             if (!gen_attrs)
1390                 return;
1391             if constexpr (needs_transcoding_to_utf8<
1392                               Container,
1393                               iter_value_t<Iter>>) {
1394                 auto const r =
1395                     BOOST_PARSER_SUBRANGE(first, last) | text::as_utf8;
1396                 c.insert(c.end(), r.begin(), r.end());
1397             } else {
1398                 detail::insert(c, first, last);
1399             }
1400         }
1401 
1402         template<typename Container, typename Iter, typename Sentinel>
1403         void append(
1404             std::optional<Container> & c,
1405             Iter first,
1406             Sentinel last,
1407             bool gen_attrs)
1408         {
1409             if (!gen_attrs)
1410                 return;
1411             if (!c)
1412                 c = Container();
1413             return detail::append(*c, first, last, gen_attrs);
1414         }
1415 
1416         template<typename Iter, typename Sentinel>
1417         void append(nope &, Iter first, Sentinel last, bool gen_attrs)
1418         {}
1419 
1420         constexpr inline flags default_flags()
1421         {
1422             return flags(
1423                 uint32_t(flags::gen_attrs) | uint32_t(flags::use_skip));
1424         }
1425         constexpr inline flags enable_skip(flags f)
1426         {
1427             return flags(uint32_t(f) | uint32_t(flags::use_skip));
1428         }
1429         constexpr inline flags disable_skip(flags f)
1430         {
1431             return flags(uint32_t(f) & ~uint32_t(flags::use_skip));
1432         }
1433         constexpr inline flags enable_attrs(flags f)
1434         {
1435             return flags(uint32_t(f) | uint32_t(flags::gen_attrs));
1436         }
1437         constexpr inline flags disable_attrs(flags f)
1438         {
1439             return flags(uint32_t(f) & ~uint32_t(flags::gen_attrs));
1440         }
1441         constexpr inline flags enable_trace(flags f)
1442         {
1443             return flags(uint32_t(f) | uint32_t(flags::trace));
1444         }
1445         constexpr inline flags disable_trace(flags f)
1446         {
1447             return flags(uint32_t(f) & ~uint32_t(flags::trace));
1448         }
1449         constexpr inline flags set_in_apply_parser(flags f)
1450         {
1451             return flags(uint32_t(f) | uint32_t(flags::in_apply_parser));
1452         }
1453         constexpr inline bool gen_attrs(flags f)
1454         {
1455             return (uint32_t(f) & uint32_t(flags::gen_attrs)) ==
1456                    uint32_t(flags::gen_attrs);
1457         }
1458         constexpr inline bool use_skip(flags f)
1459         {
1460             return (uint32_t(f) & uint32_t(flags::use_skip)) ==
1461                    uint32_t(flags::use_skip);
1462         }
1463         constexpr inline bool in_apply_parser(flags f)
1464         {
1465             return (uint32_t(f) & uint32_t(flags::in_apply_parser)) ==
1466                    uint32_t(flags::in_apply_parser);
1467         }
1468 
1469         struct null_parser
1470         {};
1471 
1472         struct skip_skipper
1473         {
1474             template<
1475                 typename Iter,
1476                 typename Sentinel,
1477                 typename Context,
1478                 typename SkipParser>
1479             nope operator()(
1480                 Iter & first,
1481                 Sentinel last,
1482                 Context const & context,
1483                 SkipParser const & skip,
1484                 flags flags,
1485                 bool & success) const noexcept
1486             {
1487                 return {};
1488             }
1489 
1490             template<
1491                 typename Iter,
1492                 typename Sentinel,
1493                 typename Context,
1494                 typename SkipParser,
1495                 typename Attribute>
1496             void operator()(
1497                 Iter & first,
1498                 Sentinel last,
1499                 Context const & context,
1500                 SkipParser const & skip,
1501                 flags flags,
1502                 bool & success,
1503                 Attribute & retval) const
1504             {}
1505         };
1506 
1507         template<typename Iter, typename Sentinel>
1508         void
1509         skip(Iter & first, Sentinel last, null_parser const & skip_, flags f)
1510         {}
1511 
1512         template<typename Iter, typename Sentinel, typename SkipParser>
1513         void
1514         skip(Iter & first, Sentinel last, SkipParser const & skip_, flags f)
1515         {
1516             if (!detail::use_skip(f))
1517                 return;
1518             bool success = true;
1519             int indent = 0;
1520             rethrow_error_handler eh;
1521             nope n;
1522             symbol_table_tries_t symbol_table_tries;
1523             pending_symbol_table_operations_t pending_symbol_table_operations;
1524             auto const context = detail::make_context<false, false>(
1525                 first,
1526                 last,
1527                 success,
1528                 indent,
1529                 eh,
1530                 n,
1531                 symbol_table_tries,
1532                 pending_symbol_table_operations);
1533             while (success) {
1534                 skip_(
1535                     first,
1536                     last,
1537                     context,
1538                     skip_skipper{},
1539                     detail::disable_trace(detail::disable_skip(f)),
1540                     success);
1541             }
1542         }
1543 
1544         enum : int64_t { unbounded = -1 };
1545 
1546         template<typename T>
1547         std::optional<T> make_parse_result(T & x, bool success)
1548         {
1549             std::optional<T> retval;
1550             if (success)
1551                 retval = x;
1552             return retval;
1553         }
1554 
1555         inline bool make_parse_result(nope &, bool success) { return success; }
1556         inline bool make_parse_result(none &, bool success) { return success; }
1557 
1558         template<typename LoType, typename HiType>
1559         struct char_pair
1560         {
1561             LoType lo_;
1562             HiType hi_;
1563         };
1564 
1565         using case_fold_array_t = std::array<char32_t, detail::longest_mapping>;
1566 
1567         template<typename I, typename S>
1568         struct no_case_iter : stl_interfaces::proxy_iterator_interface<
1569                                   no_case_iter<I, S>,
1570                                   std::forward_iterator_tag,
1571                                   char32_t>
1572         {
1573             no_case_iter() : it_(), last_(), idx_(0), last_idx_() {}
1574             no_case_iter(I it, S last) :
1575                 it_(it), last_(last), idx_(0), last_idx_(0)
1576             {
1577                 fold();
1578             }
1579 
1580             char32_t operator*() const { return folded_[idx_]; }
1581             no_case_iter & operator++()
1582             {
1583                 ++idx_;
1584                 if (last_idx_ <= idx_) {
1585                     ++it_;
1586                     fold();
1587                 }
1588                 return *this;
1589             }
1590             I base() const { return it_; }
1591             friend bool operator==(no_case_iter lhs, S rhs) noexcept
1592             {
1593                 return lhs.it_ == rhs;
1594             }
1595             friend bool operator==(no_case_iter lhs, no_case_iter rhs) noexcept
1596             {
1597                 return lhs.it_ == rhs.it_ && lhs.idx_ == rhs.idx_;
1598             }
1599 
1600             using base_type = stl_interfaces::proxy_iterator_interface<
1601                 no_case_iter<I, S>,
1602                 std::forward_iterator_tag,
1603                 char32_t>;
1604             using base_type::operator++;
1605 
1606         private:
1607             void fold()
1608             {
1609                 idx_ = 0;
1610                 if (it_ == last_) {
1611                     folded_[0] = 0;
1612                     last_idx_ = 1;
1613                     return;
1614                 }
1615                 auto const folded_last =
1616                     detail::case_fold(*it_, folded_.begin());
1617                 last_idx_ = int(folded_last - folded_.begin());
1618             }
1619 
1620             case_fold_array_t folded_;
1621             I it_;
1622             [[no_unique_address]] S last_;
1623             int idx_;
1624             int last_idx_;
1625         };
1626 
1627         template<typename V>
1628         struct case_fold_view
1629         {
1630             using iterator =
1631                 no_case_iter<detail::iterator_t<V>, detail::sentinel_t<V>>;
1632 
1633             case_fold_view(V base) : base_(std::move(base)) {}
1634 
1635             iterator begin() const
1636             {
1637                 return iterator(
1638                     text::detail::begin(base_), text::detail::end(base_));
1639             }
1640             auto end() const { return text::detail::end(base_); }
1641 
1642         private:
1643             V base_;
1644         };
1645 
1646         enum class symbol_table_op { insert, erase, clear };
1647 
1648         template<typename T>
1649         struct symbol_table_operation
1650         {
1651             std::string key_;
1652             std::optional<T> value_;
1653             symbol_table_op kind_;
1654         };
1655 
1656         template<typename T>
1657         void apply_symbol_table_operations(
1658             std::vector<std::pair<std::string, T>> & initial_elements,
1659             std::vector<symbol_table_operation<T>> & pending_operations)
1660         {
1661             auto lower_bound = [&initial_elements](std::string const & str) {
1662                 return std::lower_bound(
1663                     initial_elements.begin(),
1664                     initial_elements.end(),
1665                     str,
1666                     [](auto const & a, auto b) {
1667                         return a.first < b;
1668                     });
1669             };
1670 
1671             for (auto & op : pending_operations) {
1672                 if (op.kind_ == symbol_table_op::insert) {
1673                     auto it = lower_bound(op.key_);
1674                     if (it == initial_elements.end() ||
1675                         it->first != op.key_) {
1676                         initial_elements.insert(
1677                             it,
1678                             std::pair<std::string, T>(
1679                                 std::move(op.key_), std::move(*op.value_)));
1680                     } else {
1681                         it->second = std::move(*op.value_);
1682                     }
1683                 } else if (op.kind_ == symbol_table_op::erase) {
1684                     auto it = lower_bound(op.key_);
1685                     if (it != initial_elements.end() && it->first == op.key_)
1686                         initial_elements.erase(it);
1687                 } else {
1688                     initial_elements.clear();
1689                 }
1690             }
1691 
1692             pending_operations.clear();
1693         }
1694 
1695         template<typename Context, typename T>
1696         auto get_trie(
1697             Context const & context, symbol_parser<T> const & sym_parser)
1698         {
1699             using trie_t = text::trie_map<std::vector<char32_t>, T>;
1700             using result_type = std::pair<trie_t &, bool>;
1701             symbol_table_tries_t & symbol_table_tries =
1702                 *context.symbol_table_tries_;
1703 
1704             auto & [any, has_case_folded] =
1705                 symbol_table_tries[(void *)&sym_parser.ref()];
1706 
1707             bool const needs_case_folded = context.no_case_depth_;
1708 
1709             if (!any.has_value()) {
1710                 any = trie_t{};
1711                 has_case_folded = false;
1712                 trie_t & trie = *std::any_cast<trie_t>(&any);
1713                 for (auto const & e : sym_parser.initial_elements()) {
1714                     trie.insert(e.first | text::as_utf32, e.second);
1715                     if (needs_case_folded) {
1716                         trie.insert(
1717                             case_fold_view(e.first | text::as_utf32), e.second);
1718                         has_case_folded = true;
1719                     }
1720                 }
1721                 return result_type(trie, has_case_folded);
1722             } else {
1723                 trie_t & trie = *std::any_cast<trie_t>(&any);
1724                 if (needs_case_folded && !has_case_folded) {
1725                     trie_t new_trie = trie;
1726                     for (auto && [key, value] : trie) {
1727                         new_trie.insert(
1728                             case_fold_view(key | text::as_utf32), value);
1729                     }
1730                     std::swap(new_trie, trie);
1731                 }
1732                 return result_type(trie, has_case_folded);
1733              }
1734         }
1735 
1736         template<typename Context, typename T>
1737         decltype(auto) get_pending_symtab_ops(
1738             Context const & context, symbol_parser<T> const & sym_parser)
1739         {
1740             void const * ptr = static_cast<void const *>(&sym_parser);
1741             auto & entry = (*context.pending_symbol_table_operations_)[ptr];
1742             std::vector<detail::symbol_table_operation<T>> * retval = nullptr;
1743             if (entry.visit_) {
1744                 retval = std::any_cast<
1745                     std::vector<detail::symbol_table_operation<T>>>(
1746                     &entry.ops_);
1747             } else {
1748                 entry.ops_ = std::vector<detail::symbol_table_operation<T>>{};
1749                 retval = std::any_cast<
1750                     std::vector<detail::symbol_table_operation<T>>>(
1751                     &entry.ops_);
1752                 entry.visit_ = [&sym_parser, ops_ptr = retval] {
1753                     detail::apply_symbol_table_operations(
1754                         sym_parser.initial_elements_, *ops_ptr);
1755                 };
1756             }
1757             return *retval;
1758         }
1759 
1760         template<>
1761         struct char_subranges<hex_digit_subranges>
1762         {
1763             static constexpr char_subrange ranges[] = {
1764                 {U'0', U'9'},
1765                 {U'A', U'F'},
1766                 {U'a', U'f'},
1767                 {U'\uff10', U'\uff19'},
1768                 {U'\uff21', U'\uff26'},
1769                 {U'\uff41', U'\uff46'}};
1770         };
1771 
1772         template<>
1773         struct char_subranges<control_subranges>
1774         {
1775             static constexpr char_subrange ranges[] = {
1776                 {U'\u0000', U'\u001f'}, {U'\u007f', U'\u009f'}};
1777         };
1778 
1779         template<typename Iter, typename Sentinel, bool SortedUTF32>
1780         struct char_range
1781         {
1782             template<typename T, typename Context>
1783             bool contains(T c_, Context const & context) const
1784             {
1785                 if constexpr (SortedUTF32) {
1786                     return std::binary_search(chars_.begin(), chars_.end(), c_);
1787                 }
1788 
1789                 if (context.no_case_depth_) {
1790                     case_fold_array_t folded;
1791                     auto folded_last = detail::case_fold(c_, folded.begin());
1792                     if constexpr (std::is_same_v<T, char32_t>) {
1793                         auto const cps = chars_ | text::as_utf32;
1794                         auto chars_first = no_case_iter(cps.begin(), cps.end());
1795                         auto chars_last = cps.end();
1796                         auto result = text::search(
1797                             chars_first,
1798                             chars_last,
1799                             folded.begin(),
1800                             folded_last);
1801                         return !result.empty();
1802                     } else {
1803                         auto chars_first =
1804                             no_case_iter(chars_.begin(), chars_.end());
1805                         auto chars_last = chars_.end();
1806                         auto result = text::search(
1807                             chars_first,
1808                             chars_last,
1809                             folded.begin(),
1810                             folded_last);
1811                         return !result.empty();
1812                     }
1813                 } else {
1814                     if constexpr (std::is_same_v<T, char32_t>) {
1815                         auto const cps = chars_ | text::as_utf32;
1816                         return text::find(cps.begin(), cps.end(), c_) !=
1817                                cps.end();
1818                     } else {
1819                         using element_type =
1820                             remove_cv_ref_t<decltype(*chars_.begin())>;
1821                         element_type const c = c_;
1822                         return text::find(chars_.begin(), chars_.end(), c) !=
1823                                chars_.end();
1824                     }
1825                 }
1826             }
1827 
1828             BOOST_PARSER_SUBRANGE<Iter, Sentinel> chars_;
1829         };
1830 
1831         template<bool SortedUTF32, typename Iter, typename Sentinel>
1832         constexpr auto make_char_range(Iter first, Sentinel last)
1833         {
1834             return char_range<Iter, Sentinel, SortedUTF32>{
1835                 BOOST_PARSER_SUBRANGE<Iter, Sentinel>{first, last}};
1836         }
1837 
1838         template<bool SortedUTF32, typename R>
1839         constexpr auto make_char_range(R && r) noexcept
1840         {
1841             if constexpr (std::is_pointer_v<remove_cv_ref_t<R>>) {
1842                 return detail::make_char_range<SortedUTF32>(
1843                     r, text::null_sentinel);
1844             } else {
1845                 return detail::make_char_range<SortedUTF32>(
1846                     text::detail::begin(r), text::detail::end(r));
1847             }
1848         }
1849 
1850         template<bool Equal, typename Context>
1851         auto no_case_aware_compare(Context const & context)
1852         {
1853             return [no_case = context.no_case_depth_](char32_t a, char32_t b) {
1854                 if (no_case) {
1855                     case_fold_array_t folded_a = {0, 0, 0};
1856                     detail::case_fold(a, folded_a.begin());
1857                     case_fold_array_t folded_b = {0, 0, 0};
1858                     detail::case_fold(b, folded_b.begin());
1859                     return Equal ? folded_a == folded_b : folded_a < folded_b;
1860                 } else {
1861                     return Equal ? a == b : a < b;
1862                 }
1863             };
1864         }
1865 
1866         template<typename T, typename U>
1867         constexpr bool both_character_types =
1868             is_parsable_code_unit_v<T> && is_parsable_code_unit_v<U>;
1869 
1870         template<typename T, typename U>
1871         using eq_comparable =
1872             decltype(std::declval<T &>() == std::declval<U &>());
1873 
1874         template<
1875             typename Context,
1876             typename CharType,
1877             typename Expected,
1878             bool BothCharacters = both_character_types<CharType, Expected>>
1879         struct unequal_impl
1880         {
1881             static bool
1882             call(Context const & context, CharType c, Expected const & expected)
1883             {
1884                 auto resolved = detail::resolve(context, expected);
1885                 if constexpr (is_detected_v<
1886                                   eq_comparable,
1887                                   CharType,
1888                                   decltype(resolved)>) {
1889                     auto const compare =
1890                         detail::no_case_aware_compare<true>(context);
1891                     return !compare(c, resolved);
1892                 } else {
1893                     return !resolved.contains(c, context);
1894                 }
1895             }
1896         };
1897 
1898         template<typename Context, typename CharType, typename Expected>
1899         struct unequal_impl<Context, CharType, Expected, true>
1900         {
1901             static bool
1902             call(Context const & context, CharType c, Expected expected)
1903             {
1904 
1905                 return !detail::no_case_aware_compare<true>(context)(
1906                     c, expected);
1907             }
1908         };
1909 
1910         template<typename Context, typename CharType, typename Expected>
1911         bool unequal(Context const & context, CharType c, Expected expected)
1912         {
1913             return unequal_impl<Context, CharType, Expected>::call(
1914                 context, c, expected);
1915         }
1916 
1917         template<
1918             typename Context,
1919             typename CharType,
1920             typename LoType,
1921             typename HiType>
1922         bool unequal(
1923             Context const & context,
1924             CharType c,
1925             char_pair<LoType, HiType> const & expected)
1926         {
1927             auto const less = detail::no_case_aware_compare<false>(context);
1928             {
1929                 auto lo = detail::resolve(context, expected.lo_);
1930                 if (less(c, lo))
1931                     return true;
1932             }
1933             {
1934                 auto hi = detail::resolve(context, expected.hi_);
1935                 if (less(hi, c))
1936                     return true;
1937             }
1938             return false;
1939         }
1940 
1941         template<typename Context, typename CharType>
1942         bool unequal(Context const &, CharType, nope)
1943         {
1944             return false;
1945         }
1946 
1947         template<typename Container, typename T>
1948         using insertable = decltype(std::declval<Container &>().insert(
1949             std::declval<Container &>().end(), std::declval<T>()));
1950 
1951         template<typename T, typename Tuple, int... Is>
1952         auto
1953         make_from_tuple_impl(Tuple && tup, std::integer_sequence<int, Is...>)
1954             -> decltype(T(parser::get(std::move(tup), llong<Is>{})...))
1955         {
1956             return T(parser::get(std::move(tup), llong<Is>{})...);
1957         }
1958 
1959         template<typename T, typename... Args>
1960         auto make_from_tuple(tuple<Args...> && tup)
1961             -> decltype(detail::make_from_tuple_impl<T>(
1962                 std::move(tup),
1963                 std::make_integer_sequence<int, tuple_size_<tuple<Args...>>>()))
1964         {
1965             return detail::make_from_tuple_impl<T>(
1966                 std::move(tup),
1967                 std::make_integer_sequence<int, tuple_size_<tuple<Args...>>>());
1968         }
1969 
1970         template<typename T, typename Tuple>
1971         using constructible_from_tuple_expr =
1972             decltype(detail::make_from_tuple<T>(std::declval<Tuple>()));
1973 
1974         template<typename T, typename Tuple, bool = is_tuple<Tuple>{}>
1975         constexpr bool is_constructible_from_tuple_v = false;
1976         template<typename T, typename Tuple>
1977         constexpr bool is_constructible_from_tuple_v<T, Tuple, true> =
1978             is_detected_v<constructible_from_tuple_expr, T, Tuple>;
1979 
1980         template<typename Container, typename U>
1981         constexpr void move_back_impl(Container & c, U && x)
1982         {
1983             using just_t = range_value_t<Container>;
1984             using just_u = remove_cv_ref_t<U>;
1985             if constexpr (needs_transcoding_to_utf8<Container, U>) {
1986                 char32_t cps[1] = {(char32_t)x};
1987                 auto const r = cps | text::as_utf8;
1988                 c.insert(c.end(), r.begin(), r.end());
1989             } else if constexpr (std::is_convertible_v<just_u &&, just_t>) {
1990                 detail::insert(c, std::move(x));
1991             } else if constexpr (
1992                 !is_tuple<just_t>::value && is_tuple<just_u>::value &&
1993                 std::is_aggregate_v<just_t> &&
1994                 !is_detected_v<insertable, Container, just_u &&> &&
1995                 is_struct_assignable_v<just_t, just_u>) {
1996                 auto int_seq =
1997                     std::make_integer_sequence<int, tuple_size_<just_u>>();
1998                 detail::insert(
1999                     c,
2000                     detail::tuple_to_aggregate<just_t>(std::move(x), int_seq));
2001             } else if constexpr (
2002                 is_tuple<just_t>::value && !is_tuple<just_u>::value &&
2003                 std::is_aggregate_v<just_u> &&
2004                 !is_detected_v<insertable, Container, just_u &&> &&
2005                 is_tuple_assignable_v<just_t, just_u>) {
2006                 just_t t;
2007                 auto tie = detail::tie_aggregate(x);
2008                 detail::aggregate_to_tuple(
2009                     t,
2010                     tie,
2011                     std::make_integer_sequence<int, tuple_size_<just_t>>());
2012                 detail::insert(c, std::move(t));
2013             } else if constexpr (is_constructible_from_tuple_v<
2014                                      just_t,
2015                                      just_u>) {
2016                 detail::insert(
2017                     c, detail::make_from_tuple<just_t>(std::move(x)));
2018             } else {
2019                 static_assert(
2020                     sizeof(U) && false,
2021                     "Could not insert value into container, by: just inserting "
2022                     "it; doing tuple -> aggregate or aggregate -> tuple "
2023                     "conversions; or tuple -> class type construction.");
2024             }
2025         }
2026 
2027         template<typename Container, typename T>
2028         constexpr void move_back(Container & c, T && x, bool gen_attrs)
2029         {
2030             if (!gen_attrs)
2031                 return;
2032             detail::move_back_impl(c, std::move(x));
2033         }
2034 
2035         template<typename Container>
2036         constexpr void move_back(Container & c, Container & x, bool gen_attrs)
2037         {
2038             if (!gen_attrs)
2039                 return;
2040             c.insert(c.end(), x.begin(), x.end());
2041         }
2042 
2043         template<typename Container>
2044         constexpr void
2045         move_back(Container & c, std::optional<Container> && x, bool gen_attrs)
2046         {
2047             if (!gen_attrs || !x)
2048                 return;
2049             c.insert(c.end(), x->begin(), x->end());
2050         }
2051 
2052         template<typename Container, typename T>
2053         constexpr void
2054         move_back(Container & c, std::optional<T> & x, bool gen_attrs)
2055         {
2056             if (!gen_attrs || !x)
2057                 return;
2058             detail::move_back_impl(c, std::move(*x));
2059         }
2060 
2061         template<
2062             typename Container,
2063             typename T,
2064             typename Enable = std::enable_if_t<!std::is_same_v<Container, T>>>
2065         constexpr void
2066         move_back(Container & c, std::optional<T> && x, bool gen_attrs)
2067         {
2068             if (!gen_attrs || !x)
2069                 return;
2070             detail::move_back_impl(c, std::move(*x));
2071         }
2072 
2073         constexpr void move_back(nope, nope, bool gen_attrs) {}
2074 
2075         template<typename Container>
2076         constexpr void move_back(Container & c, nope, bool gen_attrs)
2077         {}
2078 
2079         template<typename From, typename To>
2080         using move_assignable_expr =
2081             decltype(std::declval<To &>() = std::declval<From &&>());
2082         template<typename From, typename To>
2083         constexpr bool is_move_assignable_v =
2084             is_detected_v<move_assignable_expr, From, To>;
2085 
2086         template<typename T, typename U>
2087         constexpr void assign(T & t, U && u)
2088         {
2089             using just_t = remove_cv_ref_t<T>;
2090             using just_u = remove_cv_ref_t<U>;
2091             if constexpr (is_move_assignable_v<just_u, just_t>) {
2092                 static_assert(
2093                     (!std::is_same_v<just_t, std::string> ||
2094                      !std::is_arithmetic_v<just_u>),
2095                     "std::string is assignable from a char.  Due to implicit "
2096                     "conversions among arithmetic types, any arithmetic type "
2097                     "(like int or double) is assignable to std::string.  This "
2098                     "is almost certainly not what you meant to write, so "
2099                     "Boost.Parser disallows it.  If you want to do this, write "
2100                     "a semantic action and do it explicitly.");
2101                 t = std::move(u);
2102             } else if constexpr (
2103                 !is_tuple<just_t>::value && is_tuple<just_u>::value &&
2104                 std::is_aggregate_v<just_t> &&
2105                 !std::is_convertible_v<just_u &&, just_t> &&
2106                 is_struct_assignable_v<just_t, just_u>) {
2107                 auto int_seq =
2108                     std::make_integer_sequence<int, tuple_size_<just_u>>();
2109                 t = detail::tuple_to_aggregate<just_t>(std::move(u), int_seq);
2110             } else if constexpr (
2111                 is_tuple<just_t>::value && !is_tuple<just_u>::value &&
2112                 std::is_aggregate_v<just_u> &&
2113                 !std::is_convertible_v<just_u &&, just_t> &&
2114                 is_tuple_assignable_v<just_t, just_u>) {
2115                 auto tie = detail::tie_aggregate(u);
2116                 detail::aggregate_to_tuple(
2117                     t,
2118                     tie,
2119                     std::make_integer_sequence<int, tuple_size_<just_t>>());
2120             } else if constexpr (is_constructible_from_tuple_v<
2121                                      just_t,
2122                                      just_u>) {
2123                 t = detail::make_from_tuple<just_t>(std::move(u));
2124             } else {
2125                 static_assert(
2126                     sizeof(T) && false,
2127                     "Could not assign value, by: just assigning it; doing tuple "
2128                     "-> aggregate or aggregate -> tuple conversions; or tuple "
2129                     "-> class type construction.");
2130             }
2131         }
2132 
2133         template<typename T>
2134         constexpr void assign(T &, nope)
2135         {}
2136 
2137         template<typename T, typename U>
2138         constexpr void assign_copy(T & t, U const & u)
2139         {
2140             t = u;
2141         }
2142 
2143         template<typename T>
2144         constexpr void assign_copy(T &, nope)
2145         {}
2146 
2147         template<
2148             typename Parser,
2149             typename Iter,
2150             typename Sentinel,
2151             typename Context,
2152             typename SkipParser,
2153             typename... T>
2154         void apply_parser(
2155             Parser const & parser,
2156             Iter & first,
2157             Sentinel last,
2158             Context const & context,
2159             SkipParser const & skip,
2160             flags flags,
2161             bool & success,
2162             std::optional<std::variant<T...>> & retval)
2163         {
2164             using attr_t = decltype(parser.call(
2165                 first, last, context, skip, flags, success));
2166             if constexpr (std::is_same<
2167                               attr_t,
2168                               std::optional<std::variant<T...>>>{}) {
2169                 parser.call(first, last, context, skip, flags, success, retval);
2170             } else if constexpr (is_nope_v<attr_t>) {
2171                 parser.call(first, last, context, skip, flags, success);
2172             } else {
2173                 auto attr =
2174                     parser.call(first, last, context, skip, flags, success);
2175                 if (success)
2176                     detail::assign(retval, std::variant<T...>(std::move(attr)));
2177             }
2178         }
2179 
2180         template<
2181             typename Parser,
2182             typename Iter,
2183             typename Sentinel,
2184             typename Context,
2185             typename SkipParser,
2186             typename... T>
2187         void apply_parser(
2188             Parser const & parser,
2189             Iter & first,
2190             Sentinel last,
2191             Context const & context,
2192             SkipParser const & skip,
2193             flags flags,
2194             bool & success,
2195             std::variant<T...> & retval)
2196         {
2197             auto attr = parser.call(first, last, context, skip, flags, success);
2198             if (success)
2199                 detail::assign(retval, std::move(attr));
2200         }
2201 
2202         template<
2203             typename Parser,
2204             typename Iter,
2205             typename Sentinel,
2206             typename Context,
2207             typename SkipParser,
2208             typename T>
2209         void apply_parser(
2210             Parser const & parser,
2211             Iter & first,
2212             Sentinel last,
2213             Context const & context,
2214             SkipParser const & skip,
2215             flags flags,
2216             bool & success,
2217             std::optional<T> & retval)
2218         {
2219             auto attr = parser.call(first, last, context, skip, flags, success);
2220             if (success)
2221                 detail::assign(retval, std::move(attr));
2222         }
2223 
2224         template<
2225             typename Parser,
2226             typename Iter,
2227             typename Sentinel,
2228             typename Context,
2229             typename SkipParser,
2230             typename Attribute>
2231         void apply_parser(
2232             Parser const & parser,
2233             Iter & first,
2234             Sentinel last,
2235             Context const & context,
2236             SkipParser const & skip,
2237             flags flags,
2238             bool & success,
2239             Attribute & retval)
2240         {
2241             parser.call(first, last, context, skip, flags, success, retval);
2242         }
2243 
2244 
2245 
2246         // API implementations
2247 
2248         template<typename Iter, typename Sentinel, typename Parser>
2249         auto has_attribute(Iter first, Sentinel last, Parser parser);
2250 
2251         template<typename BaseIter, typename Iter>
2252         struct scoped_base_assign
2253         {
2254             scoped_base_assign(BaseIter & base, Iter & it) :
2255                 base_(base), it_(it)
2256             {}
2257             ~scoped_base_assign() { base_ = it_.base(); }
2258 
2259             BaseIter & base_;
2260             Iter & it_;
2261         };
2262 
2263         template<typename Parser>
2264         using has_parser_data_member_expr =
2265             decltype(std::declval<Parser>().parser_);
2266         template<typename Parser>
2267         constexpr bool has_parser_data_member_v =
2268             is_detected_v<has_parser_data_member_expr, Parser>;
2269 
2270         template<typename Parser>
2271         using has_parsers_data_member_expr =
2272             decltype(std::declval<Parser>().parsers_);
2273         template<typename Parser>
2274         constexpr bool has_parsers_data_member_v =
2275             is_detected_v<has_parsers_data_member_expr, Parser>;
2276 
2277         struct scoped_apply_pending_symbol_table_operations
2278         {
2279             scoped_apply_pending_symbol_table_operations(
2280                 pending_symbol_table_operations_t & pending_ops) :
2281                 pending_ops_(pending_ops)
2282             {}
2283 
2284             ~scoped_apply_pending_symbol_table_operations()
2285             {
2286                 for (auto & [_, entry] : pending_ops_) {
2287                     entry.visit_();
2288                 }
2289             }
2290 
2291             pending_symbol_table_operations_t & pending_ops_;
2292         };
2293 
2294         template<
2295             bool Debug,
2296             typename Iter,
2297             typename Sentinel,
2298             typename Parser,
2299             typename Attr,
2300             typename ErrorHandler>
2301         bool parse_impl(
2302             Iter & first,
2303             Sentinel last,
2304             Parser const & parser,
2305             ErrorHandler const & error_handler,
2306             Attr & attr)
2307         {
2308             auto const initial_first = first;
2309             bool success = true;
2310             int trace_indent = 0;
2311             detail::symbol_table_tries_t symbol_table_tries;
2312             pending_symbol_table_operations_t pending_symbol_table_operations;
2313             scoped_apply_pending_symbol_table_operations apply_pending(
2314                 pending_symbol_table_operations);
2315             auto context = detail::make_context<Debug, false>(
2316                 first,
2317                 last,
2318                 success,
2319                 trace_indent,
2320                 error_handler,
2321                 parser.globals_,
2322                 symbol_table_tries,
2323                 pending_symbol_table_operations);
2324             auto const flags =
2325                 Debug ? detail::enable_trace(detail::flags::gen_attrs)
2326                       : detail::flags::gen_attrs;
2327             try {
2328                 parser(
2329                     first,
2330                     last,
2331                     context,
2332                     detail::null_parser{},
2333                     flags,
2334                     success,
2335                     attr);
2336                 if (Debug)
2337                     detail::final_trace(context, flags, attr);
2338                 return success;
2339             } catch (parse_error<Iter> const & e) {
2340                 if (error_handler(initial_first, last, e) ==
2341                     error_handler_result::rethrow) {
2342                     throw;
2343                 }
2344                 return false;
2345             }
2346         }
2347 
2348         template<
2349             bool Debug,
2350             typename Iter,
2351             typename Sentinel,
2352             typename Parser,
2353             typename ErrorHandler>
2354         auto parse_impl(
2355             Iter & first,
2356             Sentinel last,
2357             Parser const & parser,
2358             ErrorHandler const & error_handler)
2359         {
2360             auto const initial_first = first;
2361             bool success = true;
2362             int trace_indent = 0;
2363             detail::symbol_table_tries_t symbol_table_tries;
2364             pending_symbol_table_operations_t pending_symbol_table_operations;
2365             scoped_apply_pending_symbol_table_operations apply_pending(
2366                 pending_symbol_table_operations);
2367             auto context = detail::make_context<Debug, false>(
2368                 first,
2369                 last,
2370                 success,
2371                 trace_indent,
2372                 error_handler,
2373                 parser.globals_,
2374                 symbol_table_tries,
2375                 pending_symbol_table_operations);
2376             auto const flags =
2377                 Debug ? detail::enable_trace(detail::flags::gen_attrs)
2378                       : detail::flags::gen_attrs;
2379             using attr_t = typename detail::attribute_impl<
2380                 BOOST_PARSER_SUBRANGE<std::remove_const_t<Iter>, Sentinel>,
2381                 Parser>::type;
2382             try {
2383                 attr_t attr_ = parser(
2384                     first,
2385                     last,
2386                     context,
2387                     detail::null_parser{},
2388                     flags,
2389                     success);
2390                 if (Debug)
2391                     detail::final_trace(context, flags, nope{});
2392                 return detail::make_parse_result(attr_, success);
2393             } catch (parse_error<Iter> const & e) {
2394                 if (error_handler(initial_first, last, e) ==
2395                     error_handler_result::rethrow) {
2396                     throw;
2397                 }
2398                 attr_t attr_{};
2399                 return detail::make_parse_result(attr_, false);
2400             }
2401         }
2402 
2403         template<
2404             bool Debug,
2405             typename Iter,
2406             typename Sentinel,
2407             typename Parser,
2408             typename ErrorHandler,
2409             typename Callbacks>
2410         bool callback_parse_impl(
2411             Iter & first,
2412             Sentinel last,
2413             Parser const & parser,
2414             ErrorHandler const & error_handler,
2415             Callbacks const & callbacks)
2416         {
2417             auto const initial_first = first;
2418             bool success = true;
2419             int trace_indent = 0;
2420             detail::symbol_table_tries_t symbol_table_tries;
2421             pending_symbol_table_operations_t pending_symbol_table_operations;
2422             scoped_apply_pending_symbol_table_operations apply_pending(
2423                 pending_symbol_table_operations);
2424             auto context = detail::make_context<Debug, true>(
2425                 first,
2426                 last,
2427                 success,
2428                 trace_indent,
2429                 error_handler,
2430                 callbacks,
2431                 parser.globals_,
2432                 symbol_table_tries,
2433                 pending_symbol_table_operations);
2434             auto const flags =
2435                 Debug ? detail::enable_trace(detail::flags::gen_attrs)
2436                       : detail::flags::gen_attrs;
2437             try {
2438                 parser(
2439                     first,
2440                     last,
2441                     context,
2442                     detail::null_parser{},
2443                     flags,
2444                     success);
2445                 if (Debug)
2446                     detail::final_trace(context, flags, nope{});
2447                 return success;
2448             } catch (parse_error<Iter> const & e) {
2449                 if (error_handler(initial_first, last, e) ==
2450                     error_handler_result::rethrow) {
2451                     throw;
2452                 }
2453                 return false;
2454             }
2455         }
2456 
2457         template<
2458             bool Debug,
2459             typename Iter,
2460             typename Sentinel,
2461             typename Parser,
2462             typename SkipParser,
2463             typename Attr,
2464             typename ErrorHandler>
2465         bool skip_parse_impl(
2466             Iter & first,
2467             Sentinel last,
2468             Parser const & parser,
2469             SkipParser const & skip,
2470             ErrorHandler const & error_handler,
2471             Attr & attr)
2472         {
2473             auto const initial_first = first;
2474             bool success = true;
2475             int trace_indent = 0;
2476             detail::symbol_table_tries_t symbol_table_tries;
2477             pending_symbol_table_operations_t pending_symbol_table_operations;
2478             scoped_apply_pending_symbol_table_operations apply_pending(
2479                 pending_symbol_table_operations);
2480             auto context = detail::make_context<Debug, false>(
2481                 first,
2482                 last,
2483                 success,
2484                 trace_indent,
2485                 error_handler,
2486                 parser.globals_,
2487                 symbol_table_tries,
2488                 pending_symbol_table_operations);
2489             auto const flags =
2490                 Debug ? detail::enable_trace(detail::default_flags())
2491                       : detail::default_flags();
2492             detail::skip(first, last, skip, flags);
2493             try {
2494                 parser(first, last, context, skip, flags, success, attr);
2495                 detail::skip(first, last, skip, flags);
2496                 if (Debug)
2497                     detail::final_trace(context, flags, attr);
2498                 return success;
2499             } catch (parse_error<Iter> const & e) {
2500                 if (error_handler(initial_first, last, e) ==
2501                     error_handler_result::rethrow) {
2502                     throw;
2503                 }
2504                 return false;
2505             }
2506         }
2507 
2508         template<
2509             bool Debug,
2510             typename Iter,
2511             typename Sentinel,
2512             typename Parser,
2513             typename SkipParser,
2514             typename ErrorHandler>
2515         auto skip_parse_impl(
2516             Iter & first,
2517             Sentinel last,
2518             Parser const & parser,
2519             SkipParser const & skip,
2520             ErrorHandler const & error_handler)
2521         {
2522             auto const initial_first = first;
2523             bool success = true;
2524             int trace_indent = 0;
2525             detail::symbol_table_tries_t symbol_table_tries;
2526             pending_symbol_table_operations_t pending_symbol_table_operations;
2527             scoped_apply_pending_symbol_table_operations apply_pending(
2528                 pending_symbol_table_operations);
2529             auto context = detail::make_context<Debug, false>(
2530                 first,
2531                 last,
2532                 success,
2533                 trace_indent,
2534                 error_handler,
2535                 parser.globals_,
2536                 symbol_table_tries,
2537                 pending_symbol_table_operations);
2538             auto const flags =
2539                 Debug ? detail::enable_trace(detail::default_flags())
2540                       : detail::default_flags();
2541             detail::skip(first, last, skip, flags);
2542             using attr_t = typename detail::attribute_impl<
2543                 BOOST_PARSER_SUBRANGE<std::remove_const_t<Iter>, Sentinel>,
2544                 Parser>::type;
2545             try {
2546                 attr_t attr_ =
2547                     parser(first, last, context, skip, flags, success);
2548                 detail::skip(first, last, skip, flags);
2549                 if (Debug)
2550                     detail::final_trace(context, flags, nope{});
2551                 return detail::make_parse_result(attr_, success);
2552             } catch (parse_error<Iter> const & e) {
2553                 if (error_handler(initial_first, last, e) ==
2554                     error_handler_result::rethrow) {
2555                     throw;
2556                 }
2557                 attr_t attr_{};
2558                 return detail::make_parse_result(attr_, false);
2559             }
2560         }
2561 
2562         template<
2563             bool Debug,
2564             typename Iter,
2565             typename Sentinel,
2566             typename Parser,
2567             typename SkipParser,
2568             typename ErrorHandler,
2569             typename Callbacks>
2570         bool callback_skip_parse_impl(
2571             Iter & first,
2572             Sentinel last,
2573             Parser const & parser,
2574             SkipParser const & skip,
2575             ErrorHandler const & error_handler,
2576             Callbacks const & callbacks)
2577         {
2578             auto const initial_first = first;
2579             bool success = true;
2580             int trace_indent = 0;
2581             detail::symbol_table_tries_t symbol_table_tries;
2582             pending_symbol_table_operations_t pending_symbol_table_operations;
2583             scoped_apply_pending_symbol_table_operations apply_pending(
2584                 pending_symbol_table_operations);
2585             auto context = detail::make_context<Debug, true>(
2586                 first,
2587                 last,
2588                 success,
2589                 trace_indent,
2590                 error_handler,
2591                 callbacks,
2592                 parser.globals_,
2593                 symbol_table_tries,
2594                 pending_symbol_table_operations);
2595             auto const flags =
2596                 Debug ? detail::enable_trace(detail::default_flags())
2597                       : detail::default_flags();
2598             detail::skip(first, last, skip, flags);
2599             try {
2600                 parser(first, last, context, skip, flags, success);
2601                 detail::skip(first, last, skip, flags);
2602                 if (Debug)
2603                     detail::final_trace(context, flags, nope{});
2604                 return success;
2605             } catch (parse_error<Iter> const & e) {
2606                 if (error_handler(initial_first, last, e) ==
2607                     error_handler_result::rethrow) {
2608                     throw;
2609                 }
2610                 return false;
2611             }
2612         }
2613 
2614         template<typename R>
2615         constexpr auto make_input_subrange(R && r) noexcept
2616         {
2617             using r_t = remove_cv_ref_t<R>;
2618             if constexpr (std::is_pointer_v<r_t>) {
2619                 using value_type = iter_value_t<r_t>;
2620                 if constexpr (std::is_same_v<value_type, char>) {
2621                     return BOOST_PARSER_SUBRANGE(r, text::null_sentinel);
2622                 } else {
2623                     return r | text::as_utf32;
2624                 }
2625             } else {
2626                 using value_type = range_value_t<r_t>;
2627                 if constexpr (text::detail::is_bounded_array_v<r_t>) {
2628                     if constexpr (std::is_same_v<value_type, char>) {
2629                         auto first = detail::text::detail::begin(r);
2630                         auto last = detail::text::detail::end(r);
2631                         if (first != last && !*std::prev(last))
2632                             --last;
2633                         return BOOST_PARSER_SUBRANGE(first, last);
2634                     } else {
2635                         return r | text::as_utf32;
2636                     }
2637                 } else {
2638                     if constexpr (
2639                         std::is_same_v<value_type, char> &&
2640                         !is_utf8_view<r_t>::value) {
2641                         return BOOST_PARSER_SUBRANGE(
2642                             detail::text::detail::begin(r),
2643                             detail::text::detail::end(r));
2644                     } else {
2645                         return r | text::as_utf32;
2646                     }
2647                 }
2648             }
2649         }
2650 
2651         template<typename R>
2652         constexpr auto make_view_begin(R & r) noexcept
2653         {
2654             if constexpr (std::is_pointer_v<std::decay_t<R>>) {
2655                 return r;
2656             } else {
2657                 return detail::text::detail::begin(r);
2658             }
2659         }
2660 
2661         template<typename R>
2662         constexpr auto make_view_end(R & r) noexcept
2663         {
2664             if constexpr (std::is_pointer_v<std::decay_t<R>>) {
2665                 return text::null_sentinel;
2666             } else {
2667                 return detail::text::detail::end(r);
2668             }
2669         }
2670 
2671         template<
2672             typename Iter1,
2673             typename Sentinel1,
2674             typename Iter2,
2675             typename Sentinel2,
2676             typename Pred>
2677         std::pair<Iter1, Iter2> mismatch(
2678             Iter1 first1,
2679             Sentinel1 last1,
2680             Iter2 first2,
2681             Sentinel2 last2,
2682             Pred pred)
2683         {
2684             std::pair<Iter1, Iter2> retval{first1, first2};
2685             while (retval.first != last1 && retval.second != last2 &&
2686                    pred(*retval.first, *retval.second)) {
2687                 ++retval.first;
2688                 ++retval.second;
2689             }
2690             return retval;
2691         }
2692 
2693         template<
2694             typename Iter1,
2695             typename Sentinel1,
2696             typename Iter2,
2697             typename Sentinel2>
2698         std::pair<Iter1, Iter2> no_case_aware_string_mismatch(
2699             Iter1 first1,
2700             Sentinel1 last1,
2701             Iter2 first2,
2702             Sentinel2 last2,
2703             bool no_case)
2704         {
2705             if (no_case) {
2706                 auto it1 = no_case_iter(first1, last1);
2707                 auto it2 = no_case_iter(first2, last2);
2708                 auto const mismatch = detail::mismatch(
2709                     it1, last1, it2, last2, std::equal_to<char32_t>{});
2710                 return std::pair<Iter1, Iter2>{
2711                     mismatch.first.base(), mismatch.second.base()};
2712             } else {
2713                 return detail::mismatch(
2714                     first1, last1, first2, last2, std::equal_to<char32_t>{});
2715             }
2716         }
2717 
2718         template<typename I, typename S, typename T>
2719         std::optional<T>
2720         if_full_parse(I & first, S last, std::optional<T> retval)
2721         {
2722             if (first != last)
2723                 retval = std::nullopt;
2724             return retval;
2725         }
2726         template<typename I, typename S>
2727         bool if_full_parse(I & first, S last, bool retval)
2728         {
2729             if (first != last)
2730                 retval = false;
2731             return retval;
2732         }
2733 
2734         // The notion of comaptibility is that, given a parser with the
2735         // Attribute Tuple, we can parse into Struct instead.
2736         template<typename Struct, typename Tuple>
2737         constexpr auto is_struct_compatible();
2738 
2739         struct element_compatibility
2740         {
2741             template<typename T, typename U>
2742             constexpr auto operator()(T result, U x) const
2743             {
2744                 using struct_elem =
2745                     remove_cv_ref_t<decltype(parser::get(x, llong<0>{}))>;
2746                 using tuple_elem =
2747                     remove_cv_ref_t<decltype(parser::get(x, llong<1>{}))>;
2748                 if constexpr (!T::value) {
2749                     return std::false_type{};
2750                 } else if constexpr (
2751                     is_optional_v<struct_elem> && is_optional_v<tuple_elem>) {
2752                     using struct_opt_type = optional_type<struct_elem>;
2753                     using tuple_opt_type = optional_type<tuple_elem>;
2754                     using retval_t = decltype((*this)(
2755                         result,
2756                         detail::hl::make_tuple(
2757                             std::declval<struct_opt_type &>(),
2758                             std::declval<tuple_opt_type &>())));
2759                     return retval_t{};
2760                 } else if constexpr (std::is_convertible_v<
2761                                          tuple_elem &&,
2762                                          struct_elem>) {
2763                     return std::true_type{};
2764                 } else if constexpr (
2765                     container<struct_elem> && container<tuple_elem>) {
2766                     return detail::is_struct_compatible<
2767                         range_value_t<struct_elem>,
2768                         range_value_t<tuple_elem>>();
2769                 } else {
2770                     return std::bool_constant<detail::is_struct_compatible<
2771                         struct_elem,
2772                         tuple_elem>()>{};
2773                 }
2774             }
2775         };
2776 
2777         template<typename T, typename U>
2778         constexpr auto is_struct_compatible()
2779         {
2780             if constexpr (
2781                 !std::is_aggregate_v<T> ||
2782                 struct_arity_v<T> != tuple_size_<U>) {
2783                 return std::false_type{};
2784             } else {
2785                 using result_t = decltype(detail::hl::fold_left(
2786                     detail::hl::zip(
2787                         detail::tie_aggregate(std::declval<T &>()),
2788                         std::declval<U &>()),
2789                     std::true_type{},
2790                     element_compatibility{}));
2791                 return result_t{};
2792             }
2793         }
2794 
2795         template<typename Struct, typename Tuple>
2796         constexpr bool is_struct_compatible_v =
2797             detail::is_struct_compatible<Struct, Tuple>();
2798 
2799         template<typename ParserAttr, typename GivenContainerAttr>
2800         constexpr auto parser_attr_or_container_value_type()
2801         {
2802             if constexpr (is_nope_v<ParserAttr>) {
2803                 return nope{};
2804             } else {
2805                 using value_type = range_value_t<GivenContainerAttr>;
2806                 return std::conditional_t<
2807                     std::is_convertible_v<ParserAttr, value_type>,
2808                     ParserAttr,
2809                     value_type>{};
2810             }
2811         }
2812         template<typename ParserAttr, typename GivenContainerAttr>
2813         using parser_attr_or_container_value_type_v =
2814             decltype(parser_attr_or_container_value_type<
2815                      ParserAttr,
2816                      GivenContainerAttr>());
2817 
2818         template<typename T>
2819         constexpr auto tuple_or_struct_size(T && x)
2820         {
2821             if constexpr (is_tuple<remove_cv_ref_t<T>>{}) {
2822                 return hl::size(x);
2823             } else {
2824                 return llong<struct_arity_v<remove_cv_ref_t<T>>>{};
2825             }
2826         }
2827 
2828         template<typename T>
2829         struct attr_reset
2830         {
2831             attr_reset(T & x) : x_(std::addressof(x)) {}
2832             attr_reset(attr_reset const &) = delete;
2833             attr_reset(attr_reset &&) = delete;
2834             attr_reset & operator=(attr_reset const &) = delete;
2835             attr_reset & operator=(attr_reset &&) = delete;
2836             ~attr_reset()
2837             {
2838                 if (x_)
2839                     *x_ = T();
2840             }
2841 
2842             bool operator=(bool b)
2843             {
2844                 if (b)
2845                     x_ = nullptr;
2846                 return b;
2847             }
2848 
2849         private:
2850             T * x_;
2851         };
2852     }
2853 
2854 #ifndef BOOST_PARSER_DOXYGEN
2855 
2856     // This constraint is only here to allow the alternate-call semantic
2857     // action metaprogramming logic to function on MSVC.
2858     template<typename Context>
2859     auto _val(Context const & context) -> std::conditional_t<
2860         detail::is_nope_v<decltype(*context.val_)>,
2861         none,
2862         decltype(*context.val_)>
2863     {
2864         if constexpr (detail::is_nope_v<decltype(*context.val_)>)
2865             return none{};
2866         else
2867             return *context.val_;
2868     }
2869 
2870     template<typename Context>
2871     decltype(auto) _attr(Context const & context)
2872     {
2873         if constexpr (detail::is_nope_v<decltype(*context.attr_)>)
2874             return none{};
2875         else
2876             return *context.attr_;
2877     }
2878 
2879     template<typename Context>
2880     decltype(auto) _where(Context const & context)
2881     {
2882         return *context.where_;
2883     }
2884 
2885     template<typename Context>
2886     decltype(auto) _begin(Context const & context)
2887     {
2888         return context.first_;
2889     }
2890 
2891     template<typename Context>
2892     decltype(auto) _end(Context const & context)
2893     {
2894         return context.last_;
2895     }
2896 
2897     template<typename Context>
2898     decltype(auto) _pass(Context const & context)
2899     {
2900         return *context.pass_;
2901     }
2902 
2903     template<typename Context>
2904     decltype(auto) _locals(Context const & context)
2905     {
2906         if constexpr (detail::is_nope_v<decltype(*context.locals_)>)
2907             return none{};
2908         else
2909             return *context.locals_;
2910     }
2911 
2912     template<typename Context>
2913     decltype(auto) _params(Context const & context)
2914     {
2915         if constexpr (detail::is_nope_v<decltype(*context.params_)>)
2916             return none{};
2917         else
2918             return *context.params_;
2919     }
2920 
2921     template<typename Context>
2922     decltype(auto) _globals(Context const & context)
2923     {
2924         if constexpr (detail::is_nope_v<decltype(*context.globals_)>)
2925             return none{};
2926         else
2927             return *context.globals_;
2928     }
2929 
2930     template<typename Context>
2931     decltype(auto) _no_case(Context const & context)
2932     {
2933         return context.no_case_depth_;
2934     }
2935 
2936     template<typename Context>
2937     decltype(auto) _error_handler(Context const & context)
2938     {
2939         return *context.error_handler_;
2940     }
2941 
2942 #if BOOST_PARSER_USE_CONCEPTS
2943     template<std::forward_iterator I, typename Context>
2944 #else
2945     template<typename I, typename Context>
2946 #endif
2947     void
2948     _report_error(Context const & context, std::string_view message, I location)
2949     {
2950         return context.error_handler_->diagnose(
2951             diagnostic_kind::error, message, context, location);
2952     }
2953 
2954     template<typename Context>
2955     void _report_error(Context const & context, std::string_view message)
2956     {
2957         return context.error_handler_->diagnose(
2958             diagnostic_kind::error, message, context);
2959     }
2960 
2961 #if BOOST_PARSER_USE_CONCEPTS
2962     template<std::forward_iterator I, typename Context>
2963 #else
2964     template<typename I, typename Context>
2965 #endif
2966     void _report_warning(
2967         Context const & context, std::string_view message, I location)
2968     {
2969         return context.error_handler_->diagnose(
2970             diagnostic_kind::warning, message, context, location);
2971     }
2972 
2973     template<typename Context>
2974     void _report_warning(Context const & context, std::string_view message)
2975     {
2976         return context.error_handler_->diagnose(
2977             diagnostic_kind::warning, message, context);
2978     }
2979 
2980 #endif
2981 
2982     /** An invocable that returns the `I`th parameter to the bottommost rule.
2983         This is useful for forwarding parameters to sub-rules. */
2984     template<unsigned int I>
2985     inline constexpr detail::param_t<I> _p = {};
2986 
2987 
2988 
2989     // Second order parsers.
2990 
2991     /** A very large sentinel value used to represent pseudo-infinity. */
2992     int64_t const Inf = detail::unbounded;
2993 
2994 #ifndef BOOST_PARSER_DOXYGEN
2995     template<
2996         typename Parser,
2997         typename DelimiterParser,
2998         typename MinType,
2999         typename MaxType>
3000     struct repeat_parser
3001     {
3002         constexpr repeat_parser(
3003             Parser parser,
3004             MinType _min,
3005             MaxType _max,
3006             DelimiterParser delimiter_parser = DelimiterParser{}) :
3007             parser_(parser),
3008             delimiter_parser_(delimiter_parser),
3009             min_(_min),
3010             max_(_max)
3011         {}
3012 
3013         template<
3014             typename Iter,
3015             typename Sentinel,
3016             typename Context,
3017             typename SkipParser>
3018         auto call(
3019             Iter & first,
3020             Sentinel last,
3021             Context const & context,
3022             SkipParser const & skip,
3023             detail::flags flags,
3024             bool & success) const
3025         {
3026             using attr_t = decltype(parser_.call(
3027                 first, last, context, skip, flags, success));
3028             auto retval = detail::make_sequence_of<attr_t>();
3029             call(first, last, context, skip, flags, success, retval);
3030             return retval;
3031         }
3032 
3033         template<
3034             typename Iter,
3035             typename Sentinel,
3036             typename Context,
3037             typename SkipParser,
3038             typename Attribute>
3039         void call(
3040             Iter & first,
3041             Sentinel last,
3042             Context const & context,
3043             SkipParser const & skip,
3044             detail::flags flags,
3045             bool & success,
3046             Attribute & retval) const
3047         {
3048             [[maybe_unused]] auto _ = detail::scoped_trace(
3049                 *this,
3050                 first,
3051                 last,
3052                 context,
3053                 detail::in_apply_parser(flags) ? detail::disable_trace(flags)
3054                                                : flags,
3055                 retval);
3056 
3057             if constexpr (detail::is_optional_v<Attribute>) {
3058                 detail::optional_type<Attribute> attr;
3059                 detail::apply_parser(
3060                     *this,
3061                     first,
3062                     last,
3063                     context,
3064                     skip,
3065                     detail::set_in_apply_parser(flags),
3066                     success,
3067                     attr);
3068                 if (success)
3069                     retval = std::move(attr);
3070             } else { // Otherwise, Attribute must be a container or a nope.
3071                 using attr_t = detail::parser_attr_or_container_value_type_v<
3072                     decltype(parser_.call(
3073                         first, last, context, skip, flags, success)),
3074                     Attribute>;
3075 
3076                 int64_t count = 0;
3077 
3078                 for (int64_t end = detail::resolve(context, min_); count != end;
3079                      ++count) {
3080                     detail::skip(first, last, skip, flags);
3081                     attr_t attr{};
3082                     parser_.call(
3083                         first, last, context, skip, flags, success, attr);
3084                     if (!success) {
3085                         detail::assign(retval, Attribute());
3086                         return;
3087                     }
3088                     detail::move_back(
3089                         retval, std::move(attr), detail::gen_attrs(flags));
3090                 }
3091 
3092                 int64_t const end = detail::resolve(context, max_);
3093 
3094                 // It looks like you've created a repeated epsilon parser, by
3095                 // writing "*eps", "+eps", "repeat(2, Inf)[eps]", or similar.
3096                 BOOST_PARSER_DEBUG_ASSERT(
3097                     !detail::is_unconditional_eps<Parser>{} || end < Inf);
3098 
3099                 for (; count != end; ++count) {
3100                     auto const prev_first = first;
3101                     // This is only ever used in delimited_parser, which
3102                     // always has a min=1; we therefore know we're after a
3103                     // previous element when this executes.
3104                     if constexpr (!detail::is_nope_v<DelimiterParser>) {
3105                         detail::skip(first, last, skip, flags);
3106                         delimiter_parser_.call(
3107                             first,
3108                             last,
3109                             context,
3110                             skip,
3111                             detail::disable_attrs(flags),
3112                             success);
3113                         if (!success) {
3114                             success = true;
3115                             first = prev_first;
3116                             break;
3117                         }
3118                     }
3119 
3120                     detail::skip(first, last, skip, flags);
3121                     attr_t attr{};
3122                     parser_.call(
3123                         first, last, context, skip, flags, success, attr);
3124                     if (!success) {
3125                         success = true;
3126                         first = prev_first;
3127                         break;
3128                     }
3129                     detail::move_back(
3130                         retval, std::move(attr), detail::gen_attrs(flags));
3131                 }
3132             }
3133         }
3134 
3135         Parser parser_;
3136         DelimiterParser delimiter_parser_;
3137         MinType min_;
3138         MaxType max_;
3139     };
3140 #endif
3141 
3142     template<typename Parser>
3143     struct zero_plus_parser : repeat_parser<Parser>
3144     {
3145         constexpr zero_plus_parser(Parser parser) :
3146             repeat_parser<Parser>(parser, 0, Inf)
3147         {}
3148     };
3149 
3150     template<typename Parser>
3151     struct one_plus_parser : repeat_parser<Parser>
3152     {
3153         constexpr one_plus_parser(Parser parser) :
3154             repeat_parser<Parser>(parser, 1, Inf)
3155         {}
3156     };
3157 
3158     template<typename Parser, typename DelimiterParser>
3159     struct delimited_seq_parser : repeat_parser<Parser, DelimiterParser>
3160     {
3161         constexpr delimited_seq_parser(
3162             Parser parser, DelimiterParser delimiter_parser) :
3163             repeat_parser<Parser, DelimiterParser>(
3164                 parser, 1, Inf, delimiter_parser)
3165         {}
3166     };
3167 
3168     //[ opt_parser_beginning
3169     template<typename Parser>
3170     struct opt_parser
3171     {
3172         //]
3173         //[ opt_parser_attr_call
3174         template<
3175             typename Iter,
3176             typename Sentinel,
3177             typename Context,
3178             typename SkipParser>
3179         auto call(
3180             Iter & first,
3181             Sentinel last,
3182             Context const & context,
3183             SkipParser const & skip,
3184             detail::flags flags,
3185             bool & success) const
3186         {
3187             using attr_t = decltype(parser_.call(
3188                 first, last, context, skip, flags, success));
3189             detail::optional_of<attr_t> retval;
3190             call(first, last, context, skip, flags, success, retval);
3191             return retval;
3192         }
3193         //]
3194 
3195         //[ opt_parser_out_param_call
3196         template<
3197             typename Iter,
3198             typename Sentinel,
3199             typename Context,
3200             typename SkipParser,
3201             typename Attribute>
3202         void call(
3203             Iter & first,
3204             Sentinel last,
3205             Context const & context,
3206             SkipParser const & skip,
3207             detail::flags flags,
3208             bool & success,
3209             Attribute & retval) const
3210         {
3211             //[ opt_parser_trace
3212             [[maybe_unused]] auto _ = detail::scoped_trace(
3213                 *this, first, last, context, flags, retval);
3214             //]
3215 
3216             //[ opt_parser_skip
3217             detail::skip(first, last, skip, flags);
3218             //]
3219 
3220             //[ opt_parser_no_gen_attr_path
3221             if (!detail::gen_attrs(flags)) {
3222                 parser_.call(first, last, context, skip, flags, success);
3223                 success = true;
3224                 return;
3225             }
3226             //]
3227 
3228             //[ opt_parser_gen_attr_path
3229             parser_.call(first, last, context, skip, flags, success, retval);
3230             success = true;
3231             //]
3232         }
3233         //]
3234 
3235         //[ opt_parser_end
3236         Parser parser_;
3237     };
3238     //]
3239 
3240     template<typename ParserTuple>
3241     struct or_parser
3242     {
3243         constexpr or_parser(ParserTuple parsers) : parsers_(parsers) {}
3244 
3245 #ifndef BOOST_PARSER_DOXYGEN
3246 
3247         template<
3248             typename Iter,
3249             typename Sentinel,
3250             typename Context,
3251             typename SkipParser>
3252         struct use_parser_t
3253         {
3254             template<typename Parser>
3255             auto operator()(Parser const & parser) const
3256             {
3257                 detail::skip(first_, last_, skip_, flags_);
3258                 success_ = true; // In case someone earlier already failed...
3259                 return parser.call(
3260                     first_,
3261                     last_,
3262                     context_,
3263                     skip_,
3264                     flags_,
3265                     success_);
3266             }
3267 
3268             template<typename Parser, typename Attribute>
3269             void operator()(Parser const & parser, Attribute & retval) const
3270             {
3271                 detail::skip(first_, last_, skip_, flags_);
3272                 success_ = true; // In case someone earlier already failed...
3273 
3274                 detail::apply_parser(
3275                     parser,
3276                     first_,
3277                     last_,
3278                     context_,
3279                     skip_,
3280                     flags_,
3281                     success_,
3282                     retval);
3283             }
3284 
3285             Iter & first_;
3286             Sentinel last_;
3287             Context const & context_;
3288             SkipParser const & skip_;
3289             detail::flags flags_;
3290             bool & success_;
3291         };
3292 
3293 #endif
3294 
3295         template<
3296             typename Iter,
3297             typename Sentinel,
3298             typename Context,
3299             typename SkipParser>
3300         auto call(
3301             Iter & first,
3302             Sentinel last,
3303             Context const & context,
3304             SkipParser const & skip,
3305             detail::flags flags,
3306             bool & success) const
3307         {
3308             use_parser_t<Iter, Sentinel, Context, SkipParser> const use_parser{
3309                 first, last, context, skip, flags, success};
3310 
3311             // A result type for each of the parsers in parsers_.
3312             using all_types =
3313                 decltype(detail::hl::transform(parsers_, use_parser));
3314 
3315             // Same as above, wrapped in detail::wrapper.
3316             using all_types_wrapped =
3317                 decltype(detail::hl::transform(all_types{}, detail::wrap{}));
3318 
3319             // Returns a tuple<> containing two things: 1) A tuple of only the
3320             // unique wrapped types from above, without nopes; this may be
3321             // empty. 2) std::true_type or std::false_type indicating whether
3322             // nopes were found; if so, the final result is an optional.
3323             auto append_unique = [](auto result, auto x) {
3324                 using x_type = typename decltype(x)::type;
3325                 if constexpr (detail::is_nope_v<x_type>) {
3326                     return detail::hl::make_pair(
3327                         detail::hl::first(result), std::true_type{});
3328                 } else if constexpr (detail::hl::contains(
3329                                          detail::hl::first(result), x)) {
3330                     return result;
3331                 } else {
3332                     return detail::hl::make_pair(
3333                         detail::hl::append(detail::hl::first(result), x),
3334                         detail::hl::second(result));
3335                 }
3336             };
3337             using wrapped_unique_types = decltype(detail::hl::fold_left(
3338                 all_types_wrapped{},
3339                 detail::hl::make_pair(tuple<>{}, std::false_type{}),
3340                 append_unique));
3341 
3342             // Same as above, with the tuple types unwrapped.
3343             using unwrapped_types = decltype(detail::hl::make_pair(
3344                 detail::hl::transform(
3345                     detail::hl::first(wrapped_unique_types{}),
3346                     detail::unwrap{}),
3347                 detail::hl::second(wrapped_unique_types{})));
3348 
3349             // Types above converted to a "variant", which may actually be a
3350             // non-variant type T if that is the only unique non-nope type, or a
3351             // nope if unwrapped_types is empty.
3352             using result_t = detail::to_hana_tuple_or_type_t<unwrapped_types>;
3353 
3354             result_t retval{};
3355             call(first, last, context, skip, flags, success, retval);
3356             return retval;
3357         }
3358 
3359         template<
3360             typename Iter,
3361             typename Sentinel,
3362             typename Context,
3363             typename SkipParser,
3364             typename Attribute>
3365         void call(
3366             Iter & first,
3367             Sentinel last,
3368             Context const & context,
3369             SkipParser const & skip,
3370             detail::flags flags,
3371             bool & success,
3372             Attribute & retval) const
3373         {
3374             [[maybe_unused]] auto _ = detail::scoped_trace(
3375                 *this, first, last, context, flags, retval);
3376 
3377             use_parser_t<Iter, Sentinel, Context, SkipParser> const use_parser{
3378                 first, last, context, skip, flags, success};
3379 
3380             bool done = false;
3381             auto try_parser = [prev_first = first,
3382                                use_parser,
3383                                &success,
3384                                flags,
3385                                &retval,
3386                                &done](auto const & parser) {
3387                 if (done)
3388                     return;
3389                 if (detail::gen_attrs(flags))
3390                     use_parser(parser, retval);
3391                 else
3392                     use_parser(parser);
3393                 if (success)
3394                     done = true;
3395                 else
3396                     use_parser.first_ = prev_first;
3397             };
3398             detail::hl::for_each(parsers_, try_parser); // TODO: -> fold-expr
3399 
3400             if (!done)
3401                 success = false;
3402         }
3403 
3404 #ifndef BOOST_PARSER_DOXYGEN
3405 
3406         template<typename Parser>
3407         constexpr auto prepend(parser_interface<Parser> parser) const noexcept;
3408         template<typename Parser>
3409         constexpr auto append(parser_interface<Parser> parser) const noexcept;
3410 
3411 #endif
3412 
3413         ParserTuple parsers_;
3414     };
3415 
3416     template<typename ParserTuple, typename DelimiterParser>
3417     struct perm_parser
3418     {
3419         constexpr perm_parser(ParserTuple parsers) : parsers_(parsers) {}
3420         constexpr perm_parser(
3421             ParserTuple parsers, DelimiterParser delimiter_parser) :
3422             parsers_(parsers), delimiter_parser_(delimiter_parser)
3423         {}
3424 
3425 #ifndef BOOST_PARSER_DOXYGEN
3426 
3427         template<
3428             typename Iter,
3429             typename Sentinel,
3430             typename Context,
3431             typename SkipParser>
3432         struct use_parser_t
3433         {
3434             template<typename Parser>
3435             auto operator()(Parser const & parser) const
3436             {
3437                 detail::skip(first_, last_, skip_, flags_);
3438                 success_ = true; // In case someone earlier already failed...
3439                 return parser.call(
3440                     first_,
3441                     last_,
3442                     context_,
3443                     skip_,
3444                     flags_,
3445                     success_);
3446             }
3447 
3448             template<typename Parser, typename Attribute>
3449             void operator()(Parser const & parser, Attribute & retval) const
3450             {
3451                 detail::skip(first_, last_, skip_, flags_);
3452                 success_ = true; // In case someone earlier already failed...
3453 
3454                 detail::apply_parser(
3455                     parser,
3456                     first_,
3457                     last_,
3458                     context_,
3459                     skip_,
3460                     flags_,
3461                     success_,
3462                     retval);
3463             }
3464 
3465             Iter & first_;
3466             Sentinel last_;
3467             Context const & context_;
3468             SkipParser const & skip_;
3469             detail::flags flags_;
3470             bool & success_;
3471         };
3472 
3473 #endif
3474 
3475         template<
3476             typename Iter,
3477             typename Sentinel,
3478             typename Context,
3479             typename SkipParser>
3480         auto call(
3481             Iter & first_,
3482             Sentinel last,
3483             Context const & context,
3484             SkipParser const & skip,
3485             detail::flags flags,
3486             bool & success) const
3487         {
3488             Iter first = first_;
3489 
3490             use_parser_t<Iter, Sentinel, Context, SkipParser> const use_parser{
3491                 first, last, context, skip, flags, success};
3492             using result_t =
3493                 decltype(detail::hl::transform(parsers_, use_parser));
3494             result_t retval{};
3495 
3496             [[maybe_unused]] auto _ = detail::scoped_trace(
3497                 *this, first_, last, context, flags, retval);
3498 
3499             call_impl(
3500                 first,
3501                 last,
3502                 context,
3503                 skip,
3504                 flags,
3505                 success,
3506                 retval,
3507                 std::make_integer_sequence<
3508                     int,
3509                     detail::tuple_size_<ParserTuple>>{});
3510 
3511             if (success)
3512                 first_ = first;
3513 
3514             return retval;
3515         }
3516 
3517         template<
3518             typename Iter,
3519             typename Sentinel,
3520             typename Context,
3521             typename SkipParser,
3522             typename Attribute>
3523         void call(
3524             Iter & first_,
3525             Sentinel last,
3526             Context const & context,
3527             SkipParser const & skip,
3528             detail::flags flags,
3529             bool & success,
3530             Attribute & retval) const
3531         {
3532             [[maybe_unused]] auto _ = detail::scoped_trace(
3533                 *this, first_, last, context, flags, retval);
3534 
3535             Iter first = first_;
3536             use_parser_t<Iter, Sentinel, Context, SkipParser> const use_parser{
3537                 first, last, context, skip, flags, success};
3538             using result_t =
3539                 decltype(detail::hl::transform(parsers_, use_parser));
3540 
3541             constexpr auto indices = std::
3542                 make_integer_sequence<int, detail::tuple_size_<ParserTuple>>{};
3543 
3544             if constexpr (detail::is_optional_v<Attribute>) {
3545                 typename Attribute::value_type attr;
3546                 call(first, last, context, skip, flags, success, attr);
3547                 if (success)
3548                     detail::assign(retval, std::move(attr));
3549             } else if constexpr (
3550                 detail::is_tuple<Attribute>{} ||
3551                 detail::is_struct_compatible_v<Attribute, result_t>) {
3552                 call_impl(
3553                     first,
3554                     last,
3555                     context,
3556                     skip,
3557                     flags,
3558                     success,
3559                     retval,
3560                     indices);
3561 
3562                 if (!success)
3563                     detail::assign(retval, Attribute());
3564             } else if constexpr (detail::is_constructible_from_tuple_v<
3565                                      Attribute,
3566                                      result_t>) {
3567                 result_t temp_retval{};
3568                 call_impl(
3569                     first,
3570                     last,
3571                     context,
3572                     skip,
3573                     flags,
3574                     success,
3575                     temp_retval,
3576                     indices);
3577 
3578                 if (success && detail::gen_attrs(flags)) {
3579                     detail::assign(
3580                         retval,
3581                         detail::make_from_tuple<Attribute>(
3582                             std::move(temp_retval)));
3583                 }
3584             } else {
3585 #if 0 // TODO Seems incompatible with this parser.
3586                 // call_impl requires a tuple, so we must wrap this scalar.
3587                 tuple<Attribute> temp_retval{};
3588                 call_impl(
3589                     first,
3590                     last,
3591                     context,
3592                     skip,
3593                     flags,
3594                     success,
3595                     temp_retval,
3596                     indices);
3597 
3598                 if (success && detail::gen_attrs(flags)) {
3599                     detail::assign(
3600                         retval, std::move(detail::hl::front(temp_retval)));
3601                 }
3602 #else
3603                 static_assert(
3604                     std::is_same_v<Attribute, void> && false,
3605                     "It looks like you passed an attribute to this permutation "
3606                     "parser that is not capable of taking the number, or the "
3607                     "types of values compatible with the ones it produces.");
3608 #endif
3609             }
3610 
3611             if (success)
3612                 first_ = first;
3613         }
3614 
3615         template<
3616             typename Iter,
3617             typename Sentinel,
3618             typename Context,
3619             typename SkipParser,
3620             typename... Ts,
3621             int... Is>
3622         void call_impl(
3623             Iter & first,
3624             Sentinel last,
3625             Context const & context,
3626             SkipParser const & skip,
3627             detail::flags flags,
3628             bool & success,
3629             tuple<Ts...> & retval,
3630             std::integer_sequence<int, Is...>) const
3631         {
3632             std::array<bool, sizeof...(Ts)> used_parsers = {{}};
3633 
3634             // Use "parser" to fill in attribute "x", unless "parser" has
3635             // previously been used.
3636             auto parse_into = [&](int i, auto const & parser, auto & x) {
3637                 if (used_parsers[i])
3638                     return false;
3639                 detail::skip(first, last, skip, flags);
3640                 parser.call(first, last, context, skip, flags, success, x);
3641                 if (success) {
3642                     used_parsers[i] = true;
3643                     return true;
3644                 }
3645                 success = true;
3646                 return false;
3647             };
3648             // Use one of the previously-unused parsers to parse one
3649             // alternative.
3650             bool first_iteration = true;
3651             auto parsed_one = [&](auto) {
3652                 if constexpr (!detail::is_nope_v<DelimiterParser>) {
3653                     if (!first_iteration) {
3654                         detail::skip(first, last, skip, flags);
3655                         bool local_success = true;
3656                         delimiter_parser_.call(
3657                             first, last, context, skip, flags, local_success);
3658                         if (!local_success)
3659                             return false;
3660                     }
3661                     first_iteration = false;
3662                 }
3663                 return (
3664                     parse_into(
3665                         Is,
3666                         parser::get(parsers_, llong<Is>{}),
3667                         parser::get(retval, llong<Is>{})) ||
3668                     ...);
3669             };
3670             success = (parsed_one(Is) && ...);
3671 
3672             if (!success)
3673                 retval = tuple<Ts...>{};
3674         }
3675 
3676 #ifndef BOOST_PARSER_DOXYGEN
3677 
3678         template<typename Parser>
3679         constexpr auto prepend(parser_interface<Parser> parser) const noexcept;
3680         template<typename Parser>
3681         constexpr auto append(parser_interface<Parser> parser) const noexcept;
3682 
3683 #endif
3684 
3685         ParserTuple parsers_;
3686         DelimiterParser delimiter_parser_;
3687     };
3688 
3689     namespace detail {
3690         template<int N, int... I>
3691         constexpr auto
3692         make_default_combining_impl(std::integer_sequence<int, I...>)
3693         {
3694             return hl::make_tuple(((void)I, llong<N>{})...);
3695         }
3696         template<template<class...> class Tuple, typename... Args>
3697         constexpr auto make_default_combining(Tuple<Args...>)
3698         {
3699             return detail::make_default_combining_impl<0>(
3700                 std::make_integer_sequence<int, sizeof...(Args)>());
3701         }
3702         template<typename ParserTuple>
3703         using default_combining_t = decltype(detail::make_default_combining(
3704             std::declval<ParserTuple>()));
3705 
3706         struct merge_t
3707         {};
3708         struct separate_t
3709         {};
3710 
3711         template<
3712             typename Iter,
3713             typename Sentinel,
3714             typename Context,
3715             typename SkipParser>
3716         struct dummy_use_parser_t
3717         {
3718             dummy_use_parser_t(
3719                 Iter & first,
3720                 Sentinel last,
3721                 Context const & context,
3722                 SkipParser const & skip,
3723                 detail::flags flags,
3724                 bool & success) :
3725                 first_(first),
3726                 last_(last),
3727                 context_(context),
3728                 skip_(skip),
3729                 flags_(flags),
3730                 success_(success)
3731             {}
3732             template<typename Parser>
3733             auto operator()(Parser const & parser) const
3734             {
3735                 return parser.call(
3736                     first_,
3737                     last_,
3738                     context_,
3739                     skip_,
3740                     flags_,
3741                     success_);
3742             }
3743             Iter & first_;
3744             Sentinel last_;
3745             Context const & context_;
3746             SkipParser const & skip_;
3747             detail::flags flags_;
3748             bool & success_;
3749         };
3750 
3751         template<typename... Args>
3752         constexpr void static_assert_merge_attributes(tuple<Args...> parsers);
3753 
3754         // Combining groups are: 0, which is default merge behavior, as in
3755         // seq_parser::combine; -1, which is don't merge with anything, ever;
3756         // and N>0, which is merge with other members of group N.
3757         template<typename CombiningGroups, typename... Args>
3758         constexpr auto make_combining(tuple<Args...> parsers)
3759         {
3760             if constexpr (std::is_same_v<CombiningGroups, merge_t>) {
3761                 detail::static_assert_merge_attributes(parsers);
3762                 return detail::make_default_combining_impl<1>(
3763                     std::make_integer_sequence<int, sizeof...(Args)>());
3764             } else if constexpr (std::is_same_v<CombiningGroups, separate_t>) {
3765                 return detail::make_default_combining_impl<-1>(
3766                     std::make_integer_sequence<int, sizeof...(Args)>());
3767             } else {
3768                 return CombiningGroups{};
3769             }
3770         }
3771         template<typename ParserTuple, typename CombiningGroups>
3772         using combining_t = decltype(detail::make_combining<CombiningGroups>(
3773             std::declval<ParserTuple>()));
3774 
3775         struct max_
3776         {
3777             template<typename T, typename U>
3778             constexpr auto operator()(T x, U y) const
3779             {
3780                 if constexpr (T::value < U::value)
3781                     return y;
3782                 else
3783                     return x;
3784             }
3785         };
3786         template<int MaxGroupIdx>
3787         struct adjust_combining_groups
3788         {
3789             template<typename T, typename U>
3790             constexpr auto operator()(T result, U x) const
3791             {
3792                 if constexpr (U::value <= 0)
3793                     return hl::append(result, x);
3794                 else
3795                     return hl::append(result, llong<MaxGroupIdx + U::value>{});
3796             }
3797         };
3798         template<typename Tuple1, typename Tuple2>
3799         constexpr auto make_combined_combining(Tuple1 lhs, Tuple2 rhs)
3800         {
3801             auto max_group_idx = detail::hl::fold_left(lhs, llong<0>{}, max_{});
3802             auto rhs_adjusted = detail::hl::fold_left(
3803                 rhs,
3804                 tuple<>{},
3805                 adjust_combining_groups<decltype(max_group_idx)::value>{});
3806             return hl::concat(lhs, rhs_adjusted);
3807         }
3808         template<typename CombiningGroups1, typename CombiningGroups2>
3809         using combined_combining_t = decltype(detail::make_combined_combining(
3810             std::declval<CombiningGroups1>(),
3811             std::declval<CombiningGroups2>()));
3812 
3813         enum class merge_kind { second_pass_detect, singleton, merged, group };
3814 
3815         template<merge_kind Kind>
3816         struct merge_kind_t
3817         {
3818             static constexpr merge_kind kind = Kind;
3819         };
3820 
3821         template<merge_kind Kind>
3822         static constexpr auto merge_wrap = merge_kind_t<Kind>{};
3823     }
3824 
3825 #ifndef BOOST_PARSER_DOXYGEN
3826 
3827     template<
3828         typename ParserTuple,
3829         typename BacktrackingTuple,
3830         typename CombiningGroups>
3831     struct seq_parser
3832     {
3833         using backtracking = BacktrackingTuple;
3834         using combining_groups = CombiningGroups;
3835 
3836         constexpr seq_parser(ParserTuple parsers) : parsers_(parsers) {}
3837 
3838         static constexpr auto true_ = std::true_type{};
3839         static constexpr auto false_ = std::false_type{};
3840 
3841         struct combine
3842         {
3843             template<typename T, typename U>
3844             auto operator()(
3845                 T result_merging_indices_and_prev_group, U x_and_group) const
3846             {
3847                 using namespace literals;
3848                 using detail::merge_wrap;
3849                 using detail::merge_kind;
3850 
3851                 auto x = parser::get(x_and_group, 0_c);
3852                 auto group = parser::get(x_and_group, 1_c);
3853 
3854                 auto result =
3855                     parser::get(result_merging_indices_and_prev_group, 0_c);
3856                 using result_back_type =
3857                     typename std::decay_t<decltype(detail::hl::back(
3858                         result))>::type;
3859                 using unwrapped_optional_result_back_type =
3860                     detail::unwrapped_optional_t<result_back_type>;
3861 
3862                 auto merging =
3863                     parser::get(result_merging_indices_and_prev_group, 1_c);
3864                 auto indices =
3865                     parser::get(result_merging_indices_and_prev_group, 2_c);
3866                 auto prev_group =
3867                     parser::get(result_merging_indices_and_prev_group, 3_c);
3868 
3869                 using x_type = typename decltype(x)::type;
3870                 using unwrapped_optional_x_type =
3871                     detail::unwrapped_optional_t<x_type>;
3872 
3873                 if constexpr (detail::is_nope_v<x_type>) {
3874                     if constexpr (
3875                         !detail::is_nope_v<result_back_type> &&
3876                         0 < decltype(group)::value &&
3877                         decltype(group)::value != decltype(prev_group)::value) {
3878                         // T >> merge[nope >> ...] -> nope
3879                         // This is a very special case.  If we see a nope at
3880                         // the begining of a group, and there's a non-nope
3881                         // before it, we put the nope in place in the result
3882                         // tuple temporarily, knowing that a non-nope will
3883                         // come along later in the group to replace it.
3884                         return detail::hl::make_tuple(
3885                             detail::hl::append(result, x),
3886                             detail::hl::append(
3887                                 merging,
3888                                 merge_wrap<merge_kind::second_pass_detect>),
3889                             detail::hl::append(
3890                                 indices, detail::hl::size(result)),
3891                             group);
3892                     } else {
3893                         // T >> nope -> T
3894                         return detail::hl::make_tuple(
3895                             result,
3896                             detail::hl::append(
3897                                 merging,
3898                                 merge_wrap<merge_kind::second_pass_detect>),
3899                             detail::hl::append(
3900                                 indices, detail::hl::size_minus_one(result)),
3901                             prev_group);
3902                     }
3903                 } else if constexpr (detail::is_nope_v<result_back_type>) {
3904                     // tuple<nope> >> T -> tuple<T>
3905                     constexpr auto merge =
3906                         0 < decltype(group)::value
3907                             ? merge_kind::group
3908                             : (decltype(group)::value == -1
3909                                    ? merge_kind::singleton
3910                                    : merge_kind::second_pass_detect);
3911                     return detail::hl::make_tuple(
3912                         detail::hl::append(detail::hl::drop_back(result), x),
3913                         detail::hl::append(merging, merge_wrap<merge>),
3914                         detail::hl::append(
3915                             indices, detail::hl::size_minus_one(result)),
3916                         group);
3917                 } else if constexpr (0 < decltype(group)::value) {
3918                     if constexpr (
3919                         decltype(prev_group)::value == decltype(group)::value) {
3920                         return detail::hl::make_tuple(
3921                             result,
3922                             detail::hl::append(
3923                                 merging, merge_wrap<merge_kind::group>),
3924                             detail::hl::append(
3925                                 indices, detail::hl::size_minus_one(result)),
3926                             group);
3927                     } else {
3928                         return detail::hl::make_tuple(
3929                             detail::hl::append(result, x),
3930                             detail::hl::append(
3931                                 merging, merge_wrap<merge_kind::group>),
3932                             detail::hl::append(
3933                                 indices, detail::hl::size(result)),
3934                             group);
3935                     }
3936                 } else if constexpr (
3937                     decltype(group)::value == -1 ||
3938                     decltype(group)::value != decltype(prev_group)::value) {
3939                     constexpr auto merge = decltype(group)::value == -1
3940                                                ? merge_kind::singleton
3941                                                : merge_kind::second_pass_detect;
3942                     return detail::hl::make_tuple(
3943                         detail::hl::append(result, x),
3944                         detail::hl::append(merging, merge_wrap<merge>),
3945                         detail::hl::append(indices, detail::hl::size(result)),
3946                         group);
3947                 } else if constexpr (
3948                     detail::is_char_type_v<result_back_type> &&
3949                     (detail::is_char_type_v<x_type> ||
3950                      detail::is_char_type_v<unwrapped_optional_x_type>)) {
3951                     // CHAR >> CHAR -> string
3952                     return detail::hl::make_tuple(
3953                         detail::hl::append(
3954                             detail::hl::drop_back(result),
3955                             detail::wrapper<std::string>{}),
3956                         detail::hl::append(
3957                             detail::hl::append(
3958                                 detail::hl::drop_front(merging),
3959                                 merge_wrap<merge_kind::second_pass_detect>),
3960                             merge_wrap<merge_kind::second_pass_detect>),
3961                         detail::hl::append(
3962                             indices, detail::hl::size_minus_one(result)),
3963                         group);
3964                 } else if constexpr (
3965                     detail::
3966                         container_and_value_type<result_back_type, x_type> ||
3967                     detail::container_and_value_type<
3968                         result_back_type,
3969                         unwrapped_optional_x_type>) {
3970                     // C<T> >> T -> C<T>
3971                     // C<T> >> optional<T> -> C<T>
3972                     return detail::hl::make_tuple(
3973                         result,
3974                         detail::hl::append(
3975                             merging,
3976                             merge_wrap<merge_kind::second_pass_detect>),
3977                         detail::hl::append(
3978                             indices, detail::hl::size_minus_one(result)),
3979                         group);
3980                 } else if constexpr (
3981                     detail::
3982                         container_and_value_type<x_type, result_back_type> ||
3983                     detail::container_and_value_type<
3984                         x_type,
3985                         unwrapped_optional_result_back_type>) {
3986                     // T >> C<T> -> C<T>
3987                     // optional<T> >> C<T> -> C<T>
3988                     return detail::hl::make_tuple(
3989                         detail::hl::append(detail::hl::drop_back(result), x),
3990                         detail::hl::append(
3991                             detail::hl::append(
3992                                 detail::hl::drop_front(merging),
3993                                 merge_wrap<merge_kind::second_pass_detect>),
3994                             merge_wrap<merge_kind::second_pass_detect>),
3995                         detail::hl::append(
3996                             indices, detail::hl::size_minus_one(result)),
3997                         group);
3998                 } else {
3999                     // tuple<Ts...> >> T -> tuple<Ts..., T>
4000                     return detail::hl::make_tuple(
4001                         detail::hl::append(result, x),
4002                         detail::hl::append(
4003                             merging, merge_wrap<merge_kind::second_pass_detect>),
4004                         detail::hl::append(indices, detail::hl::size(result)),
4005                         group);
4006                 }
4007             }
4008         };
4009 
4010         struct find_merged
4011         {
4012             template<typename T, typename U>
4013             auto operator()(
4014                 T final_types_and_result, U x_index_and_prev_merged) const
4015             {
4016                 using namespace literals;
4017                 using detail::merge_wrap;
4018                 using detail::merge_kind;
4019 
4020                 auto final_types = parser::get(final_types_and_result, 0_c);
4021                 auto result = parser::get(final_types_and_result, 1_c);
4022 
4023                 auto x_type_wrapper = parser::get(x_index_and_prev_merged, 0_c);
4024                 auto index = parser::get(x_index_and_prev_merged, 1_c);
4025                 auto prev_merged = parser::get(x_index_and_prev_merged, 2_c);
4026 
4027                 auto type_at_index_wrapper = parser::get(final_types, index);
4028                 using x_type = typename decltype(x_type_wrapper)::type;
4029                 using type_at_index =
4030                     typename decltype(type_at_index_wrapper)::type;
4031                 if constexpr (
4032                     decltype(prev_merged)::kind ==
4033                     merge_kind::second_pass_detect) {
4034                     if constexpr (
4035                         !std::is_same_v<x_type, type_at_index> &&
4036                         container<type_at_index>) {
4037                         return detail::hl::make_tuple(
4038                             final_types,
4039                             detail::hl::append(
4040                                 result, merge_wrap<merge_kind::merged>));
4041                     } else {
4042                         return detail::hl::make_tuple(
4043                             final_types,
4044                             detail::hl::append(
4045                                 result, merge_wrap<merge_kind::singleton>));
4046                     }
4047                 } else {
4048                     return detail::hl::make_tuple(
4049                         final_types, detail::hl::append(result, prev_merged));
4050                 }
4051             }
4052         };
4053 
4054         template<long long I>
4055         static constexpr auto
4056         merging_from_group(integral_constant<long long, I>)
4057         {
4058             using detail::merge_wrap;
4059             using detail::merge_kind;
4060             if constexpr (0 < I)
4061                 return merge_wrap<merge_kind::group>;
4062             else if constexpr (I == -1)
4063                 return merge_wrap<merge_kind::singleton>;
4064             else
4065                 return merge_wrap<merge_kind::second_pass_detect>;
4066         }
4067 
4068         // Returns the tuple of values produced by this parser, and the
4069         // indices into that tuple that each parser should use in turn.  The
4070         // case where the tuple only has one element is handled elsewhere.
4071         template<
4072             typename Iter,
4073             typename Sentinel,
4074             typename Context,
4075             typename SkipParser>
4076         auto make_temp_result(
4077             Iter & first,
4078             Sentinel last,
4079             Context const & context,
4080             SkipParser const & skip,
4081             detail::flags flags,
4082             bool & success) const
4083         {
4084             using namespace literals;
4085 
4086             detail::
4087                 dummy_use_parser_t<Iter, Sentinel, Context, SkipParser> const
4088                     dummy_use_parser(
4089                         first, last, context, skip, flags, success);
4090 
4091             // A result type for each of the parsers in parsers_.
4092             using all_types =
4093                 decltype(detail::hl::transform(parsers_, dummy_use_parser));
4094 
4095             // Same as above, wrapped in detail::wrapper.
4096             using all_types_wrapped =
4097                 decltype(detail::hl::transform(all_types{}, detail::wrap{}));
4098 
4099             using combining_groups =
4100                 detail::combining_t<ParserTuple, CombiningGroups>;
4101             constexpr auto first_group = detail::hl::front(combining_groups{});
4102 
4103             // Generate a tuple of outputs; the index that each parser should
4104             // use to write into its output; and whether the attribute for
4105             // each parser was merged into an adjacent container-attribute.
4106             constexpr auto combine_start = detail::hl::make_tuple(
4107                 detail::hl::make_tuple(detail::hl::front(all_types_wrapped{})),
4108                 detail::hl::make_tuple(merging_from_group(first_group)),
4109                 tuple<llong<0>>{},
4110                 first_group);
4111             using combined_types = decltype(detail::hl::fold_left(
4112                 detail::hl::zip(
4113                     detail::hl::drop_front(all_types_wrapped{}),
4114                     detail::hl::drop_front(combining_groups{})),
4115                 combine_start,
4116                 combine{}));
4117 
4118             // Unwrap the result tuple's types.
4119             constexpr auto result_type_wrapped =
4120                 parser::get(combined_types{}, 0_c);
4121             using result_type = decltype(detail::hl::transform(
4122                 result_type_wrapped, detail::unwrap{}));
4123 
4124             using indices = decltype(parser::get(combined_types{}, 2_c));
4125             using first_pass_merged =
4126                 decltype(parser::get(combined_types{}, 1_c));
4127 
4128             constexpr auto find_merged_start =
4129                 detail::hl::make_tuple(result_type_wrapped, tuple<>{});
4130             using merged = decltype(detail::hl::fold_left(
4131                 detail::hl::zip(
4132                     all_types_wrapped{}, indices{}, first_pass_merged{}),
4133                 find_merged_start,
4134                 find_merged{}));
4135 
4136             return detail::hl::make_tuple(
4137                 result_type{}, indices{}, parser::get(merged{}, 1_c));
4138         }
4139 
4140         template<
4141             typename Iter,
4142             typename Sentinel,
4143             typename Context,
4144             typename SkipParser>
4145         auto call(
4146             Iter & first_,
4147             Sentinel last,
4148             Context const & context,
4149             SkipParser const & skip,
4150             detail::flags flags,
4151             bool & success) const
4152         {
4153             Iter first = first_;
4154 
4155             auto temp_result =
4156                 make_temp_result(first, last, context, skip, flags, success);
4157 
4158             std::decay_t<decltype(parser::get(temp_result, llong<0>{}))>
4159                 retval{};
4160 
4161             [[maybe_unused]] auto _ = detail::scoped_trace(
4162                 *this,
4163                 first_,
4164                 last,
4165                 context,
4166                 detail::in_apply_parser(flags) ? detail::disable_trace(flags)
4167                                                : flags,
4168                 retval);
4169 
4170             std::decay_t<decltype(parser::get(temp_result, llong<1>{}))>
4171                 indices;
4172             std::decay_t<decltype(parser::get(temp_result, llong<2>{}))>
4173                 merged;
4174             call_impl(
4175                 first,
4176                 last,
4177                 context,
4178                 skip,
4179                 flags,
4180                 success,
4181                 retval,
4182                 indices,
4183                 merged);
4184 
4185             if (success)
4186                 first_ = first;
4187 
4188             // A 1-tuple is converted to a scalar.
4189             if constexpr (detail::hl::size(retval) == llong<1>{}) {
4190                 using namespace literals;
4191                 return parser::get(retval, 0_c);
4192             } else {
4193                 return retval;
4194             }
4195         }
4196 
4197         template<
4198             typename Iter,
4199             typename Sentinel,
4200             typename Context,
4201             typename SkipParser,
4202             typename Attribute>
4203         void call(
4204             Iter & first_,
4205             Sentinel last,
4206             Context const & context,
4207             SkipParser const & skip,
4208             detail::flags flags,
4209             bool & success,
4210             Attribute & retval) const
4211         {
4212             [[maybe_unused]] auto _ = detail::scoped_trace(
4213                 *this,
4214                 first_,
4215                 last,
4216                 context,
4217                 detail::in_apply_parser(flags) ? detail::disable_trace(flags)
4218                                                : flags,
4219                 retval);
4220 
4221             Iter first = first_;
4222 
4223             auto temp_result =
4224                 make_temp_result(first, last, context, skip, flags, success);
4225             using temp_result_attr_t =
4226                 std::decay_t<decltype(parser::get(temp_result, llong<0>{}))>;
4227             std::decay_t<decltype(parser::get(temp_result, llong<1>{}))>
4228                 indices;
4229             std::decay_t<decltype(parser::get(temp_result, llong<2>{}))> merged;
4230 
4231             auto max_ = [](auto result, auto x) {
4232                 if constexpr (decltype(result)::value < decltype(x)::value) {
4233                     return x;
4234                 } else {
4235                     return result;
4236                 }
4237             };
4238             using max_index_t =
4239                 decltype(detail::hl::fold_left(indices, llong<0>{}, max_));
4240 
4241             if constexpr (detail::is_optional_v<Attribute>) {
4242                 typename Attribute::value_type attr;
4243                 call(first, last, context, skip, flags, success, attr);
4244                 if (success)
4245                     detail::assign(retval, std::move(attr));
4246             } else if constexpr (
4247                 detail::is_tuple<Attribute>{} ||
4248                 detail::is_struct_compatible_v<Attribute, temp_result_attr_t>) {
4249                 call_impl(
4250                     first,
4251                     last,
4252                     context,
4253                     skip,
4254                     flags,
4255                     success,
4256                     retval,
4257                     indices,
4258                     merged);
4259 
4260                 if (!success)
4261                     detail::assign(retval, Attribute());
4262             } else if constexpr (
4263                 0 < max_index_t::value && detail::is_constructible_from_tuple_v<
4264                                               Attribute,
4265                                               temp_result_attr_t>) {
4266                 temp_result_attr_t temp_retval{};
4267                 call_impl(
4268                     first,
4269                     last,
4270                     context,
4271                     skip,
4272                     flags,
4273                     success,
4274                     temp_retval,
4275                     indices,
4276                     merged);
4277 
4278                 if (success && detail::gen_attrs(flags)) {
4279                     detail::assign(
4280                         retval,
4281                         detail::make_from_tuple<Attribute>(
4282                             std::move(temp_retval)));
4283                 }
4284             } else {
4285                 // call_impl requires a tuple, so we must wrap this scalar.
4286                 tuple<Attribute> temp_retval{};
4287                 call_impl(
4288                     first,
4289                     last,
4290                     context,
4291                     skip,
4292                     flags,
4293                     success,
4294                     temp_retval,
4295                     indices,
4296                     merged);
4297 
4298                 if (success && detail::gen_attrs(flags)) {
4299                     detail::assign(
4300                         retval, std::move(detail::hl::front(temp_retval)));
4301                 }
4302             }
4303 
4304             if (success)
4305                 first_ = first;
4306         }
4307 
4308         // Invokes each parser, placing the resulting values (if any) into
4309         // retval, using the index mapping in indices.  The case of a tuple
4310         // containing only a single value is handled elsewhere.
4311         template<
4312             typename Iter,
4313             typename Sentinel,
4314             typename Context,
4315             typename SkipParser,
4316             typename Attribute,
4317             typename Indices,
4318             typename Merged>
4319         void call_impl(
4320             Iter & first,
4321             Sentinel last,
4322             Context const & context,
4323             SkipParser const & skip,
4324             detail::flags flags,
4325             bool & success,
4326             Attribute & retval,
4327             Indices const & indices,
4328             Merged const & merged) const
4329         {
4330             using detail::merge_wrap;
4331             using detail::merge_kind;
4332 
4333             static_assert(
4334                 detail::is_tuple<Attribute>{} || std::is_aggregate_v<Attribute>,
4335                 "");
4336 
4337             auto use_parser = [&first,
4338                                last,
4339                                &context,
4340                                &skip,
4341                                flags_ = flags,
4342                                &success,
4343                                &retval](auto const &
4344                                             parser_index_merged_and_backtrack) {
4345                 auto flags = flags_;
4346                 using namespace literals;
4347                 detail::skip(first, last, skip, flags);
4348                 if (!success) // Someone earlier already failed...
4349                     return;
4350 
4351                 auto const & parser =
4352                     parser::get(parser_index_merged_and_backtrack, 0_c);
4353                 auto merge_kind_t_ =
4354                     parser::get(parser_index_merged_and_backtrack, 2_c);
4355                 constexpr bool was_merged_into_adjacent_container =
4356                     decltype(merge_kind_t_)::kind == merge_kind::merged;
4357                 constexpr bool is_in_a_group =
4358                     decltype(merge_kind_t_)::kind == merge_kind::group;
4359                 bool const can_backtrack =
4360                     parser::get(parser_index_merged_and_backtrack, 3_c);
4361 
4362                 if (!detail::gen_attrs(flags)) {
4363                     parser.call(first, last, context, skip, flags, success);
4364                     if (!success && !can_backtrack) {
4365                         std::stringstream oss;
4366                         detail::print_parser(context, parser, oss);
4367                         throw parse_error<Iter>(first, oss.str());
4368                     }
4369                     return;
4370                 }
4371 
4372                 auto const tuple_idx =
4373                     parser::get(parser_index_merged_and_backtrack, 1_c);
4374                 auto const tuple_size = detail::tuple_or_struct_size(retval);
4375                 static_assert(
4376                     decltype(tuple_idx)::value < decltype(tuple_size)::value,
4377                     "Looks like you're trying to write some attribute into an "
4378                     "out-of-bounds position in a tuple/struct.  In other "
4379                     "words, the attribute you're parsing into does not match "
4380                     "the default attribute used by this parser.  This may be "
4381                     "because you passed an out-param to parse() at the top "
4382                     "level that is not compatible with the attribute type "
4383                     "generated by the parser you passed to parse().");
4384                 if constexpr (!(decltype(tuple_idx)::value <
4385                                 decltype(tuple_size)::value)) {
4386                     [[maybe_unused]] detail::print_type<Attribute> _;
4387                 }
4388                 auto & out = parser::get(retval, tuple_idx);
4389 
4390                 using attr_t = decltype(parser.call(
4391                     first, last, context, skip, flags, success));
4392                 constexpr bool out_container =
4393                     container<std::decay_t<decltype(out)>>;
4394                 constexpr bool attr_container = container<attr_t>;
4395 
4396                 if constexpr (
4397                     (out_container == attr_container &&
4398                      !was_merged_into_adjacent_container) ||
4399                     is_in_a_group) {
4400                     parser.call(
4401                         first, last, context, skip, flags, success, out);
4402                     if (!success) {
4403                         if (!can_backtrack) {
4404                             std::stringstream oss;
4405                             detail::print_parser(context, parser, oss);
4406                             throw parse_error<Iter>(first, oss.str());
4407                         }
4408                         out = std::decay_t<decltype(out)>();
4409                         return;
4410                     }
4411                 } else {
4412                     attr_t x =
4413                         parser.call(first, last, context, skip, flags, success);
4414                     if (!success) {
4415                         if (!can_backtrack) {
4416                             std::stringstream oss;
4417                             detail::print_parser(context, parser, oss);
4418                             throw parse_error<Iter>(first, oss.str());
4419                         }
4420                         return;
4421                     }
4422                     using just_x = attr_t;
4423                     using just_out = detail::remove_cv_ref_t<decltype(out)>;
4424                     if constexpr (
4425                         (!out_container ||
4426                          !std::is_same_v<just_x, just_out>) &&
4427                         std::is_assignable_v<just_out &, just_x &&> &&
4428                         (!std::is_same_v<just_out, std::string> ||
4429                          !std::is_integral_v<just_x>)) {
4430                         detail::assign(out, std::move(x));
4431                     } else {
4432                         detail::move_back(
4433                             out, std::move(x), detail::gen_attrs(flags));
4434                     }
4435                 }
4436             };
4437 
4438             auto const parsers_and_indices =
4439                 detail::hl::zip(parsers_, indices, merged, backtracking{});
4440             detail::hl::for_each(parsers_and_indices, use_parser);
4441         }
4442 
4443         template<bool AllowBacktracking, typename Parser>
4444         constexpr auto prepend(parser_interface<Parser> parser) const noexcept;
4445         template<bool AllowBacktracking, typename Parser>
4446         constexpr auto append(parser_interface<Parser> parser) const noexcept;
4447 
4448         ParserTuple parsers_;
4449     };
4450 
4451 #endif
4452 
4453     namespace detail {
4454         template<typename Action, typename Attribute>
4455         using action_direct_call_expr =
4456             decltype(std::declval<Action>()(std::declval<Attribute>()));
4457         template<typename Action, typename Attribute>
4458         using action_apply_call_expr = decltype(hl::apply(
4459             std::declval<Action>(), std::declval<Attribute>()));
4460         template<typename Action, typename Attribute, typename Context>
4461         using action_assignable_to_val_direct_expr =
4462             decltype(_val(std::declval<Context>()) = std::declval<Action>()(std::declval<Attribute>()));
4463         template<typename Action, typename Attribute, typename Context>
4464         using action_assignable_to_val_apply_expr =
4465             decltype(_val(std::declval<Context>()) = hl::apply(std::declval<Action>(), std::declval<Attribute>()));
4466 
4467         template<typename Action, typename Attribute, typename Context>
4468         constexpr auto action_assignable_to_val_direct()
4469         {
4470             if constexpr (is_nope_v<decltype(*std::declval<Context>().val_)>) {
4471                 return false;
4472             } else if constexpr (!is_detected_v<
4473                                      action_direct_call_expr,
4474                                      Action,
4475                                      Attribute>) {
4476                 return false;
4477             } else if constexpr (std::is_same_v<
4478                                      action_direct_call_expr<Action, Attribute>,
4479                                      void>) {
4480                 return false;
4481             } else {
4482                 return is_detected_v<
4483                     action_assignable_to_val_direct_expr,
4484                     Action,
4485                     Attribute,
4486                     Context>;
4487             }
4488         }
4489 
4490         template<typename Action, typename Attribute, typename Context>
4491         constexpr auto action_assignable_to_val_apply()
4492         {
4493             if constexpr (is_nope_v<decltype(*std::declval<Context>().val_)>) {
4494                 return false;
4495             } else if constexpr (!is_tuple<remove_cv_ref_t<Attribute>>{}) {
4496                 return false;
4497             } else if constexpr (tuple_size_<remove_cv_ref_t<Attribute>> < 2) {
4498                 return false;
4499             } else if constexpr (!is_detected_v<
4500                                      action_apply_call_expr,
4501                                      Action,
4502                                      Attribute>) {
4503                 return false;
4504             } else if constexpr (std::is_same_v<
4505                                      action_apply_call_expr<Action, Attribute>,
4506                                      void>) {
4507                 return false;
4508             } else {
4509                 return is_detected_v<
4510                     action_assignable_to_val_apply_expr,
4511                     Action,
4512                     Attribute,
4513                     Context>;
4514             }
4515         }
4516 
4517         template<typename Context, typename TagType>
4518         constexpr bool in_recursion =
4519             std::is_same_v<typename Context::rule_tag, TagType> &&
4520             !std::is_same_v<typename Context::rule_tag, void>;
4521     }
4522 
4523 #ifndef BOOST_PARSER_DOXYGEN
4524 
4525     template<typename Parser, typename Action>
4526     struct action_parser
4527     {
4528         template<
4529             typename Iter,
4530             typename Sentinel,
4531             typename Context,
4532             typename SkipParser>
4533         detail::nope call(
4534             Iter & first,
4535             Sentinel last,
4536             Context const & context,
4537             SkipParser const & skip,
4538             detail::flags flags,
4539             bool & success) const
4540         {
4541             detail::nope retval;
4542             call(first, last, context, skip, flags, success, retval);
4543             return retval;
4544         }
4545 
4546         template<
4547             typename Iter,
4548             typename Sentinel,
4549             typename Context,
4550             typename SkipParser,
4551             typename Attribute>
4552         void call(
4553             Iter & first,
4554             Sentinel last,
4555             Context const & context,
4556             SkipParser const & skip,
4557             detail::flags flags,
4558             bool & success,
4559             Attribute & retval) const
4560         {
4561             [[maybe_unused]] auto _ = detail::scoped_trace(
4562                 *this, first, last, context, flags, retval);
4563 
4564             auto const initial_first = first;
4565             auto attr = parser_.call(
4566                 first,
4567                 last,
4568                 context,
4569                 skip,
4570                 detail::enable_attrs(flags),
4571                 success);
4572 
4573             if (!success)
4574                 return;
4575 
4576             if constexpr (detail::action_assignable_to_val_apply<
4577                               decltype(action_) &,
4578                               decltype(attr),
4579                               decltype(context)>()) {
4580                 _val(context) = detail::hl::apply(action_, std::move(attr));
4581             } else {
4582                 BOOST_PARSER_SUBRANGE const where(initial_first, first);
4583                 auto const action_context =
4584                     detail::make_action_context(context, attr, where);
4585                 if constexpr (detail::action_assignable_to_val_direct<
4586                                   decltype(action_) &,
4587                                   decltype(action_context) &,
4588                                   decltype(action_context) &>()) {
4589                     _val(action_context) = action_(action_context);
4590                 } else if constexpr (std::is_same_v<
4591                                          decltype(action_(action_context)),
4592                                          void>) {
4593                     action_(action_context);
4594                 } else {
4595                     // If you see an error here, it's because you are using an
4596                     // invocable for a semantic action that returns a non-void
4597                     // type Ret, but values fo type Ret is not assignable to
4598                     // _val(ctx).  To fix this, only use this invocable within
4599                     // a rule whose attribute type is assignable from Ret, or
4600                     // remove the non-void return statement(s) from your
4601                     // invocable.
4602                     [[maybe_unused]] none n = action_(action_context);
4603                 }
4604             }
4605         }
4606 
4607         Parser parser_;
4608         Action action_;
4609     };
4610 
4611     template<typename Parser, typename F>
4612     struct transform_parser
4613     {
4614         template<
4615             typename Iter,
4616             typename Sentinel,
4617             typename Context,
4618             typename SkipParser>
4619         auto call(
4620             Iter & first,
4621             Sentinel last,
4622             Context const & context,
4623             SkipParser const & skip,
4624             detail::flags flags,
4625             bool & success) const
4626         {
4627             [[maybe_unused]] auto _ = detail::scoped_trace(
4628                 *this, first, last, context, flags, detail::global_nope);
4629             auto attr =
4630                 parser_.call(first, last, context, skip, flags, success);
4631             if (success && detail::gen_attrs(flags))
4632                 return f_(std::move(attr));
4633             else
4634                 return decltype(f_(std::move(attr))){};
4635         }
4636 
4637         template<
4638             typename Iter,
4639             typename Sentinel,
4640             typename Context,
4641             typename SkipParser,
4642             typename Attribute>
4643         void call(
4644             Iter & first,
4645             Sentinel last,
4646             Context const & context,
4647             SkipParser const & skip,
4648             detail::flags flags,
4649             bool & success,
4650             Attribute & retval) const
4651         {
4652             [[maybe_unused]] auto _ = detail::scoped_trace(
4653                 *this, first, last, context, flags, retval);
4654             auto attr =
4655                 parser_.call(first, last, context, skip, flags, success);
4656             if (success && detail::gen_attrs(flags))
4657                 detail::assign(retval, f_(std::move(attr)));
4658         }
4659 
4660         Parser parser_;
4661         F f_;
4662     };
4663 
4664     template<typename Parser>
4665     struct omit_parser
4666     {
4667         template<
4668             typename Iter,
4669             typename Sentinel,
4670             typename Context,
4671             typename SkipParser>
4672         detail::nope call(
4673             Iter & first,
4674             Sentinel last,
4675             Context const & context,
4676             SkipParser const & skip,
4677             detail::flags flags,
4678             bool & success) const
4679         {
4680             [[maybe_unused]] auto _ = detail::scoped_trace(
4681                 *this, first, last, context, flags, detail::global_nope);
4682 
4683             parser_.call(
4684                 first,
4685                 last,
4686                 context,
4687                 skip,
4688                 detail::disable_attrs(flags),
4689                 success);
4690             return {};
4691         }
4692 
4693         template<
4694             typename Iter,
4695             typename Sentinel,
4696             typename Context,
4697             typename SkipParser,
4698             typename Attribute>
4699         void call(
4700             Iter & first,
4701             Sentinel last,
4702             Context const & context,
4703             SkipParser const & skip,
4704             detail::flags flags,
4705             bool & success,
4706             Attribute & retval) const
4707         {
4708             [[maybe_unused]] auto _ = detail::scoped_trace(
4709                 *this, first, last, context, flags, retval);
4710 
4711             parser_.call(
4712                 first,
4713                 last,
4714                 context,
4715                 skip,
4716                 detail::disable_attrs(flags),
4717                 success);
4718         }
4719 
4720         Parser parser_;
4721     };
4722 
4723     template<typename Parser>
4724     struct raw_parser
4725     {
4726         template<
4727             typename Iter,
4728             typename Sentinel,
4729             typename Context,
4730             typename SkipParser>
4731         BOOST_PARSER_SUBRANGE<Iter> call(
4732             Iter & first,
4733             Sentinel last,
4734             Context const & context,
4735             SkipParser const & skip,
4736             detail::flags flags,
4737             bool & success) const
4738         {
4739             BOOST_PARSER_SUBRANGE<Iter> retval;
4740             call(first, last, context, skip, flags, success, retval);
4741             return retval;
4742         }
4743 
4744         template<
4745             typename Iter,
4746             typename Sentinel,
4747             typename Context,
4748             typename SkipParser,
4749             typename Attribute>
4750         void call(
4751             Iter & first,
4752             Sentinel last,
4753             Context const & context,
4754             SkipParser const & skip,
4755             detail::flags flags,
4756             bool & success,
4757             Attribute & retval) const
4758         {
4759             [[maybe_unused]] auto _ = detail::scoped_trace(
4760                 *this, first, last, context, flags, retval);
4761 
4762             auto const initial_first = first;
4763             parser_.call(
4764                 first,
4765                 last,
4766                 context,
4767                 skip,
4768                 detail::disable_attrs(flags),
4769                 success);
4770             if (success && detail::gen_attrs(flags))
4771                 detail::assign(
4772                     retval, BOOST_PARSER_SUBRANGE<Iter>(initial_first, first));
4773         }
4774 
4775         Parser parser_;
4776     };
4777 
4778 #if BOOST_PARSER_USE_CONCEPTS
4779     template<typename Parser>
4780     struct string_view_parser
4781     {
4782         template<
4783             typename Iter,
4784             typename Sentinel,
4785             typename Context,
4786             typename SkipParser>
4787         auto call(
4788             Iter & first,
4789             Sentinel last,
4790             Context const & context,
4791             SkipParser const & skip,
4792             detail::flags flags,
4793             bool & success) const
4794         {
4795             auto r =
4796                 parser::detail::text::unpack_iterator_and_sentinel(first, last);
4797             static_assert(
4798                 std::contiguous_iterator<decltype(r.first)>,
4799                 "string_view_parser and the string_view[] directive that uses "
4800                 "it requires that the underlying char sequence being parsed be "
4801                 "a contiguous range.  If you're seeing this static_assert, you "
4802                 "have not met this contract.");
4803             using char_type = detail::remove_cv_ref_t<decltype(*r.first)>;
4804             std::basic_string_view<char_type> retval;
4805             call(first, last, context, skip, flags, success, retval);
4806             return retval;
4807         }
4808 
4809         template<
4810             typename Iter,
4811             typename Sentinel,
4812             typename Context,
4813             typename SkipParser,
4814             typename Attribute>
4815         void call(
4816             Iter & first,
4817             Sentinel last,
4818             Context const & context,
4819             SkipParser const & skip,
4820             detail::flags flags,
4821             bool & success,
4822             Attribute & retval) const
4823         {
4824             [[maybe_unused]] auto _ = detail::scoped_trace(
4825                 *this, first, last, context, flags, retval);
4826 
4827             auto const initial_first = first;
4828             parser_.call(
4829                 first,
4830                 last,
4831                 context,
4832                 skip,
4833                 detail::disable_attrs(flags),
4834                 success);
4835 
4836             if (!success || !detail::gen_attrs(flags))
4837                 return;
4838 
4839             auto r = parser::detail::text::unpack_iterator_and_sentinel(
4840                 initial_first, first);
4841             static_assert(
4842                 std::contiguous_iterator<decltype(r.first)>,
4843                 "string_view_parser and the string_view[] directive that uses "
4844                 "it requires that the underlying char sequence being parsed be "
4845                 "a contiguous range.  If you're seeing this static_assert, you "
4846                 "have not met this contract.");
4847             using char_type = detail::remove_cv_ref_t<decltype(*r.first)>;
4848             if (initial_first == first) {
4849                 detail::assign(retval, std::basic_string_view<char_type>{});
4850             } else {
4851                 detail::assign(
4852                     retval,
4853                     std::basic_string_view<char_type>{
4854                         &*r.first, std::size_t(r.last - r.first)});
4855             }
4856         }
4857 
4858         Parser parser_;
4859     };
4860 #endif
4861 
4862     template<typename Parser>
4863     struct lexeme_parser
4864     {
4865         template<
4866             typename Iter,
4867             typename Sentinel,
4868             typename Context,
4869             typename SkipParser>
4870         auto call(
4871             Iter & first,
4872             Sentinel last,
4873             Context const & context,
4874             SkipParser const & skip,
4875             detail::flags flags,
4876             bool & success) const
4877         {
4878             using attr_t = decltype(parser_.call(
4879                 first, last, context, skip, flags, success));
4880             attr_t retval{};
4881             call(first, last, context, skip, flags, success, retval);
4882             return retval;
4883         }
4884 
4885         template<
4886             typename Iter,
4887             typename Sentinel,
4888             typename Context,
4889             typename SkipParser,
4890             typename Attribute>
4891         void call(
4892             Iter & first,
4893             Sentinel last,
4894             Context const & context,
4895             SkipParser const & skip,
4896             detail::flags flags,
4897             bool & success,
4898             Attribute & retval) const
4899         {
4900             [[maybe_unused]] auto _ = detail::scoped_trace(
4901                 *this, first, last, context, flags, retval);
4902 
4903             parser_.call(
4904                 first,
4905                 last,
4906                 context,
4907                 skip,
4908                 detail::disable_skip(flags),
4909                 success,
4910                 retval);
4911         }
4912 
4913         Parser parser_;
4914     };
4915 
4916     template<typename Parser>
4917     struct no_case_parser
4918     {
4919         template<
4920             typename Iter,
4921             typename Sentinel,
4922             typename Context,
4923             typename SkipParser>
4924         auto call(
4925             Iter & first,
4926             Sentinel last,
4927             Context const & context_,
4928             SkipParser const & skip,
4929             detail::flags flags,
4930             bool & success) const
4931         {
4932             auto context = context_;
4933             ++context.no_case_depth_;
4934 
4935             using attr_t = decltype(parser_.call(
4936                 first, last, context, skip, flags, success));
4937             attr_t retval{};
4938             call(first, last, context, skip, flags, success, retval);
4939             return retval;
4940         }
4941 
4942         template<
4943             typename Iter,
4944             typename Sentinel,
4945             typename Context,
4946             typename SkipParser,
4947             typename Attribute>
4948         void call(
4949             Iter & first,
4950             Sentinel last,
4951             Context const & context_,
4952             SkipParser const & skip,
4953             detail::flags flags,
4954             bool & success,
4955             Attribute & retval) const
4956         {
4957             auto context = context_;
4958             ++context.no_case_depth_;
4959 
4960             [[maybe_unused]] auto _ = detail::scoped_trace(
4961                 *this, first, last, context, flags, retval);
4962 
4963             parser_.call(first, last, context, skip, flags, success, retval);
4964         }
4965 
4966         Parser parser_;
4967     };
4968 
4969     template<typename Parser, typename SkipParser>
4970     struct skip_parser
4971     {
4972         template<
4973             typename Iter,
4974             typename Sentinel,
4975             typename Context,
4976             typename SkipParser_>
4977         auto call(
4978             Iter & first,
4979             Sentinel last,
4980             Context const & context,
4981             SkipParser_ const & skip,
4982             detail::flags flags,
4983             bool & success) const
4984         {
4985             using attr_t = decltype(parser_.call(
4986                 first, last, context, skip, flags, success));
4987             attr_t retval{};
4988             call(first, last, context, skip, flags, success, retval);
4989             return retval;
4990         }
4991 
4992         template<
4993             typename Iter,
4994             typename Sentinel,
4995             typename Context,
4996             typename SkipParser_,
4997             typename Attribute>
4998         void call(
4999             Iter & first,
5000             Sentinel last,
5001             Context const & context,
5002             SkipParser_ const & skip,
5003             detail::flags flags,
5004             bool & success,
5005             Attribute & retval) const
5006         {
5007             [[maybe_unused]] auto _ = detail::scoped_trace(
5008                 *this, first, last, context, flags, retval);
5009 
5010             if constexpr (detail::is_nope_v<SkipParser>) {
5011                 parser_.call(
5012                     first,
5013                     last,
5014                     context,
5015                     skip,
5016                     detail::enable_skip(flags),
5017                     success,
5018                     retval);
5019             } else {
5020                 parser_.call(
5021                     first,
5022                     last,
5023                     context,
5024                     skip_parser_,
5025                     detail::enable_skip(flags),
5026                     success,
5027                     retval);
5028             }
5029         }
5030 
5031         Parser parser_;
5032         SkipParser skip_parser_;
5033     };
5034 
5035     template<typename Parser, bool FailOnMatch>
5036     struct expect_parser
5037     {
5038         template<
5039             typename Iter,
5040             typename Sentinel,
5041             typename Context,
5042             typename SkipParser>
5043         detail::nope call(
5044             Iter & first,
5045             Sentinel last,
5046             Context const & context,
5047             SkipParser const & skip,
5048             detail::flags flags,
5049             bool & success) const
5050         {
5051             detail::nope retval;
5052             call(first, last, context, skip, flags, success, retval);
5053             return retval;
5054         }
5055 
5056         template<
5057             typename Iter,
5058             typename Sentinel,
5059             typename Context,
5060             typename SkipParser,
5061             typename Attribute>
5062         void call(
5063             Iter & first,
5064             Sentinel last,
5065             Context const & context,
5066             SkipParser const & skip,
5067             detail::flags flags,
5068             bool & success,
5069             Attribute & retval) const
5070         {
5071             [[maybe_unused]] auto _ = detail::scoped_trace(
5072                 *this, first, last, context, flags, retval);
5073 
5074             auto first_copy = first;
5075             parser_.call(
5076                 first_copy,
5077                 last,
5078                 context,
5079                 skip,
5080                 detail::disable_attrs(flags),
5081                 success);
5082             if (FailOnMatch)
5083                 success = !success;
5084         }
5085 
5086         Parser parser_;
5087     };
5088 
5089     template<typename T>
5090     struct symbol_parser
5091     {
5092         symbol_parser() : copied_from_(nullptr) {}
5093         explicit symbol_parser(std::string_view diagnostic_text) :
5094             copied_from_(nullptr), diagnostic_text_(diagnostic_text)
5095         {}
5096         symbol_parser(symbol_parser const & other) :
5097             initial_elements_(other.initial_elements_),
5098             copied_from_(other.copied_from_ ? other.copied_from_ : &other),
5099             diagnostic_text_(other.diagnostic_text_)
5100         {}
5101         symbol_parser(symbol_parser && other) :
5102             initial_elements_(std::move(other.initial_elements_)),
5103             copied_from_(other.copied_from_),
5104             diagnostic_text_(other.diagnostic_text_)
5105         {}
5106 
5107         /** Inserts an entry consisting of a UTF-8 string `str` to match, and
5108             an associated attribute `x`, to `*this`.  The entry is added for
5109             use in all subsequent top-level parses.  Subsequent lookups during
5110             the current top-level parse will not necessarily match `str`. */
5111         template<typename Context>
5112         void insert_for_next_parse(
5113             Context const & context, std::string_view str, T x)
5114         {
5115             auto & pending_ops =
5116                 detail::get_pending_symtab_ops(context, ref());
5117             pending_ops.push_back(detail::symbol_table_operation<T>{
5118                 std::string(str),
5119                 std::move(x),
5120                 detail::symbol_table_op::insert});
5121         }
5122 
5123         /** Erases the entry whose UTF-8 match string is `str`, from `*this`.
5124             The entry will no longer be available for use in all subsequent
5125             top-level parses.  `str` will not be removed from the symbols
5126             matched in the current top-level parse. */
5127         template<typename Context>
5128         void erase_for_next_parse(Context const & context, std::string_view str)
5129         {
5130             auto & pending_ops =
5131                 detail::get_pending_symtab_ops(context, ref());
5132             pending_ops.push_back(detail::symbol_table_operation<T>{
5133                 std::string(str),
5134                 std::nullopt,
5135                 detail::symbol_table_op::erase});
5136         }
5137 
5138         /** Erases all the entries from the copy of the symbol table inside
5139             the parse context `context`. */
5140         template<typename Context>
5141         void clear_for_next_parse(Context const & context)
5142         {
5143             auto & pending_ops =
5144                 detail::get_pending_symtab_ops(context, ref());
5145             pending_ops.push_back(detail::symbol_table_operation<T>{
5146                 {}, std::nullopt, detail::symbol_table_op::clear});
5147         }
5148 
5149         /** Uses UTF-8 string `str` to look up an attribute in the table
5150             during parsing, returning it as an optional reference.  The lookup
5151             is done on the copy of the symbol table inside the parse context
5152             `context`. */
5153         template<typename Context>
5154         parser::detail::text::optional_ref<T>
5155         find(Context const & context, std::string_view str) const
5156         {
5157             auto [trie, has_case_folded] = detail::get_trie(context, ref());
5158             if (context.no_case_depth_) {
5159                 return trie[detail::case_fold_view(
5160                     str | detail::text::as_utf32)];
5161             } else {
5162                 return trie[str | detail::text::as_utf32];
5163             }
5164         }
5165 
5166         /** Inserts an entry consisting of a UTF-8 string `str` to match, and
5167             an associtated attribute `x`, to the copy of the symbol table
5168             inside the parse context `context`. */
5169         template<typename Context>
5170         void insert(Context const & context, std::string_view str, T && x) const
5171         {
5172             auto [trie, has_case_folded] = detail::get_trie(context, ref());
5173             if (context.no_case_depth_) {
5174                 trie.insert(
5175                     detail::case_fold_view(str | detail::text::as_utf32),
5176                     std::move(x));
5177             } else {
5178                 trie.insert(str | detail::text::as_utf32, std::move(x));
5179             }
5180         }
5181 
5182         /** Erases the entry whose UTF-8 match string is `str` from the copy
5183             of the symbol table inside the parse context `context`. */
5184         template<typename Context>
5185         void erase(Context const & context, std::string_view str) const
5186         {
5187             auto [trie, has_case_folded] = detail::get_trie(context, ref());
5188             if (context.no_case_depth_) {
5189                 trie.erase(
5190                     detail::case_fold_view(str | detail::text::as_utf32));
5191             } else {
5192                 trie.erase(str | detail::text::as_utf32);
5193             }
5194         }
5195 
5196         /** Erases the entry whose UTF-8 match string is `str` from the copy
5197             of the symbol table inside the parse context `context`. */
5198         template<typename Context>
5199         void clear(Context const & context) const
5200         {
5201             auto [trie, _] = detail::get_trie(context, ref());
5202             trie.clear();
5203         }
5204 
5205         template<
5206             typename Iter,
5207             typename Sentinel,
5208             typename Context,
5209             typename SkipParser>
5210         T call(
5211             Iter & first,
5212             Sentinel last,
5213             Context const & context,
5214             SkipParser const & skip,
5215             detail::flags flags,
5216             bool & success) const
5217         {
5218             T retval{};
5219             call(first, last, context, skip, flags, success, retval);
5220             return retval;
5221         }
5222 
5223         template<
5224             typename Iter,
5225             typename Sentinel,
5226             typename Context,
5227             typename SkipParser,
5228             typename Attribute>
5229         void call(
5230             Iter & first,
5231             Sentinel last,
5232             Context const & context,
5233             SkipParser const & skip,
5234             detail::flags flags,
5235             bool & success,
5236             Attribute & retval) const
5237         {
5238             [[maybe_unused]] auto _ = detail::scoped_trace(
5239                 *this, first, last, context, flags, retval);
5240 
5241             auto [trie, _0] = detail::get_trie(context, ref());
5242             auto const lookup = context.no_case_depth_
5243                                     ? trie.longest_match(detail::case_fold_view(
5244                                           BOOST_PARSER_SUBRANGE(first, last)))
5245                                     : trie.longest_match(first, last);
5246             if (lookup.match) {
5247                 std::advance(first, lookup.size);
5248                 detail::assign(retval, T{*trie[lookup]});
5249             } else {
5250                 success = false;
5251             }
5252         }
5253 
5254         mutable std::vector<std::pair<std::string, T>> initial_elements_;
5255         symbol_parser const * copied_from_;
5256 
5257         symbol_parser const & ref() const noexcept
5258         {
5259             if (copied_from_)
5260                 return *copied_from_;
5261             return *this;
5262         }
5263         std::vector<std::pair<std::string, T>> &
5264         initial_elements() const noexcept
5265         {
5266             return ref().initial_elements_;
5267         }
5268 
5269         std::string_view diagnostic_text_;
5270     };
5271 
5272     template<
5273         bool CanUseCallbacks,
5274         typename TagType,
5275         typename Attribute,
5276         typename LocalState,
5277         typename ParamsTuple>
5278     struct rule_parser
5279     {
5280         using tag_type = TagType;
5281         using attr_type = Attribute;
5282         using locals_type = LocalState;
5283 
5284         template<
5285             typename Iter,
5286             typename Sentinel,
5287             typename Context,
5288             typename SkipParser>
5289         std::conditional_t<
5290             detail::in_recursion<Context, tag_type>,
5291             detail::nope,
5292             attr_type>
5293         call(
5294             Iter & first,
5295             Sentinel last,
5296             Context const & context,
5297             SkipParser const & skip,
5298             detail::flags flags,
5299             bool & success) const
5300         {
5301             constexpr bool in_recursion =
5302                 detail::in_recursion<Context, tag_type>;
5303 
5304             if constexpr (in_recursion)
5305                 flags = detail::disable_attrs(flags);
5306 
5307             attr_type retval{};
5308             locals_type locals = detail::make_locals<locals_type>(context);
5309             auto params = detail::resolve_rule_params(context, params_);
5310             tag_type * const tag_ptr = nullptr;
5311             auto const rule_context = detail::make_rule_context(
5312                 context, tag_ptr, retval, locals, params);
5313             [[maybe_unused]] auto _ = detail::scoped_trace(
5314                 *this, first, last, rule_context, flags, retval);
5315 
5316             bool dont_assign = false;
5317             if constexpr (in_recursion) {
5318                 // We have to use this out-arg overload for iterations >= 1 in
5319                 // recursive rules, since every iteration past the first is
5320                 // defined to return nope.
5321                 parse_rule(
5322                     tag_ptr,
5323                     first,
5324                     last,
5325                     rule_context,
5326                     skip,
5327                     flags,
5328                     success,
5329                     dont_assign,
5330                     retval);
5331             } else {
5332                 auto attr = parse_rule(
5333                     tag_ptr,
5334                     first,
5335                     last,
5336                     rule_context,
5337                     skip,
5338                     flags,
5339                     success,
5340                     dont_assign);
5341                 if (success && !dont_assign) {
5342                     if constexpr (!detail::is_nope_v<decltype(attr)>)
5343                         detail::assign(retval, attr);
5344                 }
5345             }
5346 
5347             if constexpr (
5348                 CanUseCallbacks && Context::use_callbacks && !in_recursion) {
5349                 if (!success)
5350                     return attr_type{};
5351 
5352                 auto const & callbacks = _callbacks(context);
5353 
5354                 if constexpr (detail::is_nope_v<attr_type>) {
5355                     static_assert(
5356                         detail::is_invocable_v<decltype(callbacks), tag_type>,
5357                         "For rules without attributes, Callbacks must be a "
5358                         "struct with overloads of the form void(tag_type).  If "
5359                         "you're seeing an error here, you probably have not "
5360                         "met this contract.");
5361                     callbacks(tag_type{});
5362                 } else {
5363                     static_assert(
5364                         detail::is_invocable_v<
5365                             decltype(callbacks),
5366                             tag_type,
5367                             decltype(std::move(retval))>,
5368                         "For rules with attributes, Callbacks must be a struct "
5369                         "with overloads of the form void(tag_type, attr_type). "
5370                         "If you're seeing an error here, you probably have not "
5371                         "met this contract.");
5372                     callbacks(tag_type{}, std::move(retval));
5373                 }
5374 
5375                 return attr_type{};
5376             } else {
5377                 if (!success && !in_recursion)
5378                     detail::assign(retval, attr_type());
5379                 if constexpr (in_recursion)
5380                     return detail::nope{};
5381                 else
5382                     return retval;
5383             }
5384         }
5385 
5386         template<
5387             typename Iter,
5388             typename Sentinel,
5389             typename Context,
5390             typename SkipParser,
5391             typename Attribute_>
5392         void call(
5393             Iter & first,
5394             Sentinel last,
5395             Context const & context,
5396             SkipParser const & skip,
5397             detail::flags flags,
5398             bool & success,
5399             Attribute_ & retval) const
5400         {
5401             if constexpr (CanUseCallbacks && Context::use_callbacks) {
5402                 call(first, last, context, skip, flags, success);
5403             } else {
5404                 auto attr = call(first, last, context, skip, flags, success);
5405                 if (success)
5406                     detail::assign(retval, std::move(attr));
5407             }
5408         }
5409 
5410         std::string_view diagnostic_text_;
5411         ParamsTuple params_;
5412     };
5413 
5414 #endif
5415 
5416     // Parser interface.
5417 
5418     template<typename Parser, typename GlobalState, typename ErrorHandler>
5419     struct parser_interface
5420     {
5421         using parser_type = Parser;
5422         using global_state_type = GlobalState;
5423         using error_handler_type = ErrorHandler;
5424 
5425         constexpr parser_interface() : parser_() {}
5426         constexpr parser_interface(parser_type p) : parser_(std::move(p)) {}
5427         constexpr parser_interface(
5428             parser_type p, global_state_type gs, error_handler_type eh) :
5429             parser_(p), globals_(gs), error_handler_(eh)
5430         {}
5431 
5432         /** Returns a `parser_interface` containing a parser equivalent to an
5433             `expect_parser` containing `parser_`, with `FailOnMatch ==
5434             true`. */
5435         constexpr auto operator!() const noexcept
5436         {
5437             return parser::parser_interface{
5438                 expect_parser<parser_type, true>{parser_}};
5439         }
5440 
5441         /** Returns a `parser_interface` containing a parser equivalent to an
5442             `expect_parser` containing `parser_`, with `FailOnMatch ==
5443             false`. */
5444         constexpr auto operator&() const noexcept
5445         {
5446             return parser::parser_interface{
5447                 expect_parser<parser_type, false>{parser_}};
5448         }
5449 
5450         /** Returns a `parser_interface` containing a parser equivalent to a
5451             `zero_plus_parser` containing `parser_`. */
5452         constexpr auto operator*() const noexcept
5453         {
5454             if constexpr (detail::is_zero_plus_p<parser_type>{}) {
5455                 return *this;
5456             } else if constexpr (detail::is_one_plus_p<parser_type>{}) {
5457                 using inner_parser = decltype(parser_type::parser_);
5458                 return parser::parser_interface{
5459                     zero_plus_parser<inner_parser>(parser_.parser_)};
5460             } else {
5461                 return parser::parser_interface{
5462                     zero_plus_parser<parser_type>(parser_)};
5463             }
5464         }
5465 
5466         /** Returns a `parser_interface` containing a parser equivalent to a
5467             `one_plus_parser` containing `parser_`. */
5468         constexpr auto operator+() const noexcept
5469         {
5470             if constexpr (detail::is_zero_plus_p<parser_type>{}) {
5471                 using inner_parser = decltype(parser_type::parser_);
5472                 return parser::parser_interface{
5473                     zero_plus_parser<inner_parser>(parser_.parser_)};
5474             } else if constexpr (detail::is_one_plus_p<parser_type>{}) {
5475                 return *this;
5476             } else {
5477                 return parser::parser_interface{
5478                     one_plus_parser<parser_type>(parser_)};
5479             }
5480         }
5481 
5482         /** Returns a `parser_interface` containing a parser equivalent to a
5483             `opt_parser` containing `parser_`. */
5484         constexpr auto operator-() const noexcept
5485         {
5486             return parser::parser_interface{opt_parser<parser_type>{parser_}};
5487         }
5488 
5489         /** Returns a `parser_interface` containing a parser equivalent to a
5490             `seq_parser` containing `parser_` followed by `rhs.parser_`. */
5491         template<typename ParserType2>
5492         constexpr auto
5493         operator>>(parser_interface<ParserType2> rhs) const noexcept
5494         {
5495             if constexpr (detail::is_seq_p<parser_type>{}) {
5496                 return parser_.template append<true>(rhs);
5497             } else if constexpr (detail::is_seq_p<ParserType2>{}) {
5498                 return rhs.parser_.template prepend<true>(*this);
5499             } else {
5500                 using parser_t = seq_parser<
5501                     tuple<parser_type, ParserType2>,
5502                     tuple<std::true_type, std::true_type>,
5503                     tuple<llong<0>, llong<0>>>;
5504                 return parser::parser_interface{parser_t{
5505                     tuple<parser_type, ParserType2>{parser_, rhs.parser_}}};
5506             }
5507         }
5508 
5509         /** Returns a `parser_interface` containing a parser equivalent to a
5510             `seq_parser` containing `parser_` followed by `lit(rhs)`. */
5511         constexpr auto operator>>(char rhs) const noexcept;
5512 
5513         /** Returns a `parser_interface` containing a parser equivalent to a
5514             `seq_parser` containing `parser_` followed by `lit(rhs)`. */
5515         constexpr auto operator>>(char32_t rhs) const noexcept;
5516 
5517         /** Returns a `parser_interface` containing a parser equivalent to a
5518             `seq_parser` containing `parser_` followed by `lit(rhs)`. */
5519 #if BOOST_PARSER_USE_CONCEPTS
5520         template<parsable_range_like R>
5521 #else
5522         template<
5523             typename R,
5524             typename Enable =
5525                 std::enable_if_t<detail::is_parsable_range_like_v<R>>>
5526 #endif
5527         constexpr auto operator>>(R && r) const noexcept;
5528 
5529         /** Returns a `parser_interface` containing a parser equivalent to a
5530             `seq_parser` containing `parser_` followed by `rhs.parser_`.  No
5531             back-tracking is allowed after `parser_` succeeds; if
5532             `rhs.parser_` fails after `parser_` succeeds, the top-level parse
5533             fails. */
5534         template<typename ParserType2>
5535         constexpr auto
5536         operator>(parser_interface<ParserType2> rhs) const noexcept
5537         {
5538             if constexpr (detail::is_seq_p<parser_type>{}) {
5539                 return parser_.template append<false>(rhs);
5540             } else if constexpr (detail::is_seq_p<ParserType2>{}) {
5541                 return rhs.parser_.template prepend<false>(*this);
5542             } else {
5543                 using parser_t = seq_parser<
5544                     tuple<parser_type, ParserType2>,
5545                     tuple<std::true_type, std::false_type>,
5546                     tuple<llong<0>, llong<0>>>;
5547                 return parser::parser_interface{parser_t{
5548                     tuple<parser_type, ParserType2>{parser_, rhs.parser_}}};
5549             }
5550         }
5551 
5552         /** Returns a `parser_interface` containing a parser equivalent to a
5553             `seq_parser` containing `parser_` followed by `lit(rhs)`.  No
5554             back-tracking is allowed after `parser_` succeeds; if `lit(rhs)`
5555             fails after `parser_` succeeds, the top-level parse fails. */
5556         constexpr auto operator>(char rhs) const noexcept;
5557 
5558         /** Returns a `parser_interface` containing a parser equivalent to a
5559             `seq_parser` containing `parser_` followed by `lit(rhs)`.  No
5560             back-tracking is allowed after `parser_` succeeds; if `lit(rhs)`
5561             fails after `parser_` succeeds, the top-level parse fails. */
5562         constexpr auto operator>(char32_t rhs) const noexcept;
5563 
5564         /** Returns a `parser_interface` containing a parser equivalent to a
5565             `seq_parser` containing `parser_` followed by `lit(rhs)`.  No
5566             back-tracking is allowed after `parser_` succeeds; if `lit(rhs)`
5567             fails after `parser_` succeeds, the top-level parse fails. */
5568 #if BOOST_PARSER_USE_CONCEPTS
5569         template<parsable_range_like R>
5570 #else
5571         template<
5572             typename R,
5573             typename Enable =
5574                 std::enable_if_t<detail::is_parsable_range_like_v<R>>>
5575 #endif
5576         constexpr auto operator>(R && r) const noexcept;
5577 
5578         /** Returns a `parser_interface` containing a parser equivalent to an
5579             `or_parser` containing `parser_` followed by `rhs.parser_`. */
5580         template<typename ParserType2>
5581         constexpr auto
5582         operator|(parser_interface<ParserType2> rhs) const noexcept
5583         {
5584             if constexpr (detail::is_or_p<parser_type>{}) {
5585                 return parser_.append(rhs);
5586             } else if constexpr (detail::is_or_p<ParserType2>{}) {
5587                 return rhs.parser_.prepend(*this);
5588             } else {
5589                 // If you're seeing this as a compile- or run-time failure,
5590                 // you've tried to put an eps parser at the beginning of an
5591                 // alternative-parser, such as "eps | int_".  This is not what
5592                 // you meant.  Since eps always matches any input, "eps |
5593                 // int_" is just an awkward spelling for "eps".  To fix this
5594                 // this, put the eps as the last alternative, so the other
5595                 // alternatives get a chance.  Possibly, you may have meant to
5596                 // add a condition to the eps, like "eps(condition) | int_",
5597                 // which also is meaningful, and so is allowed.
5598                 BOOST_PARSER_ASSERT(
5599                     !detail::is_unconditional_eps<parser_type>{});
5600                 return parser::parser_interface{
5601                     or_parser<tuple<parser_type, ParserType2>>{
5602                         tuple<parser_type, ParserType2>{parser_, rhs.parser_}}};
5603             }
5604         }
5605 
5606         /** Returns a `parser_interface` containing a parser equivalent to a
5607             `perm_parser` containing `parser_` followed by `rhs.parser_`.  It
5608             is an error to use `eps` (conditional or not) with this
5609             operator. */
5610         template<typename ParserType2>
5611         constexpr auto
5612         operator||(parser_interface<ParserType2> rhs) const noexcept
5613         {
5614             // If you're seeing this as a compile- or run-time failure, you've
5615             // tried to put an eps parser in a permutation-parser, such as
5616             // "eps || int_".
5617             BOOST_PARSER_ASSERT(!detail::is_eps_p<parser_type>{});
5618             BOOST_PARSER_ASSERT(!detail::is_eps_p<ParserType2>{});
5619             if constexpr (detail::is_perm_p<parser_type>{}) {
5620                 return parser_.append(rhs);
5621             } else if constexpr (detail::is_perm_p<ParserType2>{}) {
5622                 return rhs.parser_.prepend(*this);
5623             } else {
5624                 return parser::parser_interface{
5625                     perm_parser<tuple<parser_type, ParserType2>, detail::nope>{
5626                         tuple<parser_type, ParserType2>{parser_, rhs.parser_}}};
5627             }
5628         }
5629 
5630         /** Returns a `parser_interface` containing a parser equivalent to an
5631             `or_parser` containing `parser_` followed by `lit(rhs)`. */
5632         constexpr auto operator|(char rhs) const noexcept;
5633 
5634         /** Returns a `parser_interface` containing a parser equivalent to an
5635             `or_parser` containing `parser_` followed by `lit(rhs)`. */
5636         constexpr auto operator|(char32_t rhs) const noexcept;
5637 
5638         /** Returns a `parser_interface` containing a parser equivalent to an
5639             `or_parser` containing `parser_` followed by `lit(rhs)`. */
5640 #if BOOST_PARSER_USE_CONCEPTS
5641         template<parsable_range_like R>
5642 #else
5643         template<
5644             typename R,
5645             typename Enable =
5646                 std::enable_if_t<detail::is_parsable_range_like_v<R>>>
5647 #endif
5648         constexpr auto operator|(R && r) const noexcept;
5649 
5650         /** Returns a `parser_interface` containing a parser equivalent to
5651             `!rhs >> *this`. */
5652         template<typename ParserType2>
5653         constexpr auto
5654         operator-(parser_interface<ParserType2> rhs) const noexcept
5655         {
5656             return !rhs >> *this;
5657         }
5658 
5659         /** Returns a `parser_interface` containing a parser equivalent to
5660             `!lit(rhs) >> *this`. */
5661         constexpr auto operator-(char rhs) const noexcept;
5662 
5663         /** Returns a `parser_interface` containing a parser equivalent to
5664             `!lit(rhs) >> *this`. */
5665         constexpr auto operator-(char32_t rhs) const noexcept;
5666 
5667         /** Returns a `parser_interface` containing a parser equivalent to
5668             `!lit(rhs) >> *this`. */
5669 #if BOOST_PARSER_USE_CONCEPTS
5670         template<parsable_range_like R>
5671 #else
5672         template<
5673             typename R,
5674             typename Enable =
5675                 std::enable_if_t<detail::is_parsable_range_like_v<R>>>
5676 #endif
5677         constexpr auto operator-(R && r) const noexcept;
5678 
5679         /** Returns a `parser_interface` containing a parser equivalent to an
5680            `delimited_seq_parser` containing `parser_` and `rhs.parser_`. */
5681         template<typename ParserType2>
5682         constexpr auto
5683         operator%(parser_interface<ParserType2> rhs) const noexcept
5684         {
5685             return parser::parser_interface{
5686                 delimited_seq_parser<parser_type, ParserType2>(
5687                     parser_, rhs.parser_)};
5688         }
5689 
5690         /** Returns a `parser_interface` containing a parser equivalent to an
5691            `delimited_seq_parser` containing `parser_` and `lit(rhs)`. */
5692         constexpr auto operator%(char rhs) const noexcept;
5693 
5694         /** Returns a `parser_interface` containing a parser equivalent to an
5695            `delimited_seq_parser` containing `parser_` and `lit(rhs)`. */
5696         constexpr auto operator%(char32_t rhs) const noexcept;
5697 
5698         /** Returns a `parser_interface` containing a parser equivalent to an
5699            `delimited_seq_parser` containing `parser_` and `lit(rhs)`. */
5700 #if BOOST_PARSER_USE_CONCEPTS
5701         template<parsable_range_like R>
5702 #else
5703         template<
5704             typename R,
5705             typename Enable =
5706                 std::enable_if_t<detail::is_parsable_range_like_v<R>>>
5707 #endif
5708         constexpr auto operator%(R && r) const noexcept;
5709 
5710         /** Returns a `parser_interface` containing a parser equivalent to an
5711            `action_parser` containing `parser_`, with semantic action
5712            `action`. */
5713         template<typename Action>
5714         constexpr auto operator[](Action action) const
5715         {
5716             using action_parser_t = action_parser<parser_type, Action>;
5717             return parser::parser_interface{action_parser_t{parser_, action}};
5718         }
5719 
5720         /** Returns `parser_((Arg &&)arg, (Args &&)args...)`.  This is useful
5721             for those parsers that have `operator()` overloads,
5722             e.g. `char_('x')`.  By convention, parsers' `operator()`s return
5723             `parser_interface`s.
5724 
5725             This function does not participate in overload resolution unless
5726             `parser_((Arg &&)arg, (Args &&)args...)` is well-formed. */
5727         template<typename Arg, typename... Args>
5728         constexpr auto operator()(Arg && arg, Args &&... args) const noexcept
5729             -> decltype(std::declval<parser_type const &>()(
5730                 (Arg &&) arg, (Args &&) args...))
5731         {
5732             return parser_((Arg &&) arg, (Args &&) args...);
5733         }
5734 
5735 #ifndef BOOST_PARSER_DOXYGEN
5736 
5737         /** Applies `parser_`, returning the parsed attribute, if any, unless
5738             the attribute is reported via callback. */
5739         template<
5740             typename Iter,
5741             typename Sentinel,
5742             typename Context,
5743             typename SkipParserType>
5744         auto operator()(
5745             Iter & first,
5746             Sentinel last,
5747             Context const & context,
5748             SkipParserType const & skip,
5749             detail::flags flags,
5750             bool & success) const
5751         {
5752             return parser_.call(first, last, context, skip, flags, success);
5753         }
5754 
5755         /** Applies `parser_`, assiging the parsed attribute, if any, to
5756             `attr`, unless the attribute is reported via callback. */
5757         template<
5758             typename Iter,
5759             typename Sentinel,
5760             typename Context,
5761             typename SkipParserType,
5762             typename Attribute>
5763         void operator()(
5764             Iter & first,
5765             Sentinel last,
5766             Context const & context,
5767             SkipParserType const & skip,
5768             detail::flags flags,
5769             bool & success,
5770             Attribute & attr) const
5771         {
5772             parser_.call(first, last, context, skip, flags, success, attr);
5773         }
5774 
5775         parser_type parser_;
5776         global_state_type globals_;
5777         error_handler_type error_handler_;
5778 
5779 #endif
5780 
5781         using parser_interface_derivation_tag = int;
5782     };
5783 
5784     /** Returns a `parser_interface` with the same parser and error handler,
5785         with `globals` added.  The resut of passing any non-top-level parser
5786         for the `parser` argument is undefined. */
5787     template<typename Parser, typename GlobalState, typename ErrorHandler>
5788     auto with_globals(
5789         parser_interface<Parser, detail::nope, ErrorHandler> const & parser,
5790         GlobalState & globals)
5791     {
5792         return parser_interface<Parser, GlobalState &, ErrorHandler>{
5793             parser.parser_, globals, parser.error_handler_};
5794     }
5795 
5796     /** Returns a `parser_interface` with the same parser and globals, with
5797         `error_handler` added.  The resut of passing any non-top-level parser
5798         for the `parser` argument is undefined. */
5799     template<typename Parser, typename GlobalState, typename ErrorHandler>
5800     auto with_error_handler(
5801         parser_interface<Parser, GlobalState, default_error_handler> const &
5802             parser,
5803         ErrorHandler & error_handler)
5804     {
5805         return parser_interface<Parser, GlobalState, ErrorHandler &>{
5806             parser.parser_, parser.globals_, error_handler};
5807     }
5808 
5809 
5810     /** A `symbols<T>` represents the initial state of a symbol table parser
5811         that produces attributes of type `T`.  The entries in the symbol table
5812         can be changed during parsing, but those mutations to not affect the
5813         `symbols<T>` object itself; all mutations happen to a copy of the
5814         symbol table in the parse context.  For table entries that should be
5815         used during every parse, add entries via `add()` or `operator()`.  For
5816         mid-parse mutations, use `insert()` and `erase()`. */
5817     template<typename T>
5818     struct symbols : parser_interface<symbol_parser<T>>
5819     {
5820         symbols() {}
5821         symbols(char const * diagnostic_text) :
5822             parser_interface<symbol_parser<T>>(
5823                 symbol_parser<T>(diagnostic_text))
5824         {}
5825         symbols(std::initializer_list<std::pair<std::string_view, T>> il)
5826         {
5827             this->parser_.initial_elements_.resize(il.size());
5828             std::copy(il.begin(), il.end(),
5829                       this->parser_.initial_elements_.begin());
5830         }
5831         symbols(
5832             char const * diagnostic_text,
5833             std::initializer_list<std::pair<std::string_view, T>> il) :
5834             parser_interface<symbol_parser<T>>(
5835                 symbol_parser<T>(diagnostic_text))
5836         {
5837             this->parser_.initial_elements_.resize(il.size());
5838             std::copy(il.begin(), il.end(),
5839                       this->parser_.initial_elements_.begin());
5840         }
5841 
5842         /** Inserts an entry consisting of a UTF-8 string `str` to match, and
5843             an associated attribute `x`, to `*this`.  The entry is added for
5844             use in all subsequent top-level parses.  Subsequent lookups during
5845             the current top-level parse will not necessarily match `str`. */
5846         void insert_for_next_parse(std::string_view str, T x)
5847         {
5848             this->parser_.initial_elements_.push_back(
5849                 std::pair(std::string(str), std::move(x)));
5850         }
5851 
5852         /** Erases the entry whose UTF-8 match string is `str`, from `*this`.
5853             The entry will no longer be available for use in all subsequent
5854             top-level parses.  `str` will not be removed from the symbols
5855             matched in the current top-level parse. */
5856         void erase_for_next_parse(std::string_view str)
5857         {
5858             auto it = std::find_if(
5859                 this->parser_.initial_elements_.begin(),
5860                 this->parser_.initial_elements_.end(),
5861                 [str](auto const & x) { return x.first == str; });
5862             this->parser_.initial_elements_.erase(it);
5863         }
5864 
5865         /** Erases all the entries from the copy of the symbol table inside
5866             the parse context `context`. */
5867         void clear_for_next_parse() { this->parser_.initial_elements_.clear(); }
5868 
5869         /** Inserts an entry consisting of a UTF-8 string `str` to match, and
5870             an associated attribute `x`, to `*this`.  The entry is added for
5871             use in all subsequent top-level parses.  Subsequent lookups during
5872             the current top-level parse will not necessarily match `str`. */
5873         template<typename Context>
5874         void insert_for_next_parse(
5875             Context const & context, std::string_view str, T x)
5876         {
5877             this->parser_.insert_for_next_parse(context, str, std::move(x));
5878         }
5879 
5880         /** Erases the entry whose UTF-8 match string is `str`, from `*this`.
5881             The entry will no longer be available for use in all subsequent
5882             top-level parses.  `str` will not be removed from the symbols
5883             matched in the current top-level parse. */
5884         template<typename Context>
5885         void erase_for_next_parse(Context const & context, std::string_view str)
5886         {
5887             this->parser_.erase_for_next_parse(context, str);
5888         }
5889 
5890         /** Erases all the entries from the copy of the symbol table inside
5891             the parse context `context`. */
5892         template<typename Context>
5893         void clear_for_next_parse(Context const & context)
5894         {
5895             this->parser_.clear_for_next_parse(context);
5896         }
5897 
5898         /** Uses UTF-8 string `str` to look up an attribute in the table
5899             during parsing, returning it as an optional reference.  The lookup
5900             is done on the copy of the symbol table inside the parse context
5901             `context`, not `*this`. */
5902         template<typename Context>
5903         parser::detail::text::optional_ref<T>
5904         find(Context const & context, std::string_view str) const
5905         {
5906             return this->parser_.find(context, str);
5907         }
5908 
5909         /** Inserts an entry consisting of a UTF-8 string to match `str`, and
5910             an associtated attribute `x`, to the copy of the symbol table
5911             inside the parse context `context`. */
5912         template<typename Context>
5913         void insert(Context const & context, std::string_view str, T x) const
5914         {
5915             this->parser_.insert(context, str, std::move(x));
5916         }
5917 
5918         /** Erases the entry whose UTF-8 match string is `str` from the copy
5919             of the symbol table inside the parse context `context`. */
5920         template<typename Context>
5921         void erase(Context const & context, std::string_view str) const
5922         {
5923             this->parser_.erase(context, str);
5924         }
5925 
5926         /** Erases all the entries from the copy of the symbol table inside
5927             the parse context `context`. */
5928         template<typename Context>
5929         void clear(Context const & context) const
5930         {
5931             this->parser_.clear(context);
5932         }
5933    };
5934 
5935 #ifndef BOOST_PARSER_DOXYGEN
5936 
5937     template<
5938         typename TagType,
5939         typename Attribute,
5940         typename LocalState,
5941         typename ParamsTuple>
5942     struct rule
5943         : parser_interface<
5944               rule_parser<false, TagType, Attribute, LocalState, ParamsTuple>>
5945     {
5946         static_assert(
5947             !std::is_same_v<TagType, void>,
5948             "void is not a valid tag type for a rule.");
5949 
5950         constexpr rule(char const * diagnostic_text)
5951         {
5952             this->parser_.diagnostic_text_ = diagnostic_text;
5953         }
5954 
5955         template<typename T, typename... Ts>
5956         constexpr auto with(T && x, Ts &&... xs) const
5957         {
5958             BOOST_PARSER_ASSERT(
5959                 (detail::is_nope_v<ParamsTuple> &&
5960                  "If you're seeing this, you tried to chain calls on a rule, "
5961                  "like 'rule.with(foo).with(bar)'.  Quit it!'"));
5962             using params_tuple_type = decltype(detail::hl::make_tuple(
5963                 static_cast<T &&>(x), static_cast<Ts &&>(xs)...));
5964             using rule_parser_type = rule_parser<
5965                 false,
5966                 TagType,
5967                 Attribute,
5968                 LocalState,
5969                 params_tuple_type>;
5970             using result_type = parser_interface<rule_parser_type>;
5971             return result_type{rule_parser_type{
5972                 this->parser_.diagnostic_text_,
5973                 detail::hl::make_tuple(
5974                     static_cast<T &&>(x), static_cast<Ts &&>(xs)...)}};
5975         }
5976     };
5977 
5978     template<
5979         typename TagType,
5980         typename Attribute,
5981         typename LocalState,
5982         typename ParamsTuple>
5983     struct callback_rule
5984         : parser_interface<
5985               rule_parser<true, TagType, Attribute, LocalState, ParamsTuple>>
5986     {
5987         constexpr callback_rule(char const * diagnostic_text)
5988         {
5989             this->parser_.diagnostic_text_ = diagnostic_text;
5990         }
5991 
5992         template<typename T, typename... Ts>
5993         constexpr auto with(T && x, Ts &&... xs) const
5994         {
5995             BOOST_PARSER_ASSERT(
5996                 (detail::is_nope_v<ParamsTuple> &&
5997                  "If you're seeing this, you tried to chain calls on a "
5998                  "callback_rule, like 'rule.with(foo).with(bar)'.  Quit it!'"));
5999             using params_tuple_type = decltype(detail::hl::make_tuple(
6000                 static_cast<T &&>(x), static_cast<Ts &&>(xs)...));
6001             using rule_parser_type = rule_parser<
6002                 true,
6003                 TagType,
6004                 Attribute,
6005                 LocalState,
6006                 params_tuple_type>;
6007             using result_type = parser_interface<rule_parser_type>;
6008             return result_type{rule_parser_type{
6009                 this->parser_.diagnostic_text_,
6010                 detail::hl::make_tuple(
6011                     static_cast<T &&>(x), static_cast<Ts &&>(xs)...)}};
6012         }
6013     };
6014 
6015 //[ define_rule_definition
6016 #define BOOST_PARSER_DEFINE_IMPL(_, rule_name_)                                \
6017     template<                                                                  \
6018         typename Iter,                                                         \
6019         typename Sentinel,                                                     \
6020         typename Context,                                                      \
6021         typename SkipParser>                                                   \
6022     decltype(rule_name_)::parser_type::attr_type parse_rule(                   \
6023         decltype(rule_name_)::parser_type::tag_type *,                         \
6024         Iter & first,                                                          \
6025         Sentinel last,                                                         \
6026         Context const & context,                                               \
6027         SkipParser const & skip,                                               \
6028         boost::parser::detail::flags flags,                                    \
6029         bool & success,                                                        \
6030         bool & dont_assign)                                                    \
6031     {                                                                          \
6032         auto const & parser = BOOST_PARSER_PP_CAT(rule_name_, _def);           \
6033         using attr_t =                                                         \
6034             decltype(parser(first, last, context, skip, flags, success));      \
6035         using attr_type = decltype(rule_name_)::parser_type::attr_type;        \
6036         if constexpr (boost::parser::detail::is_nope_v<attr_t>) {              \
6037             dont_assign = true;                                                \
6038             parser(first, last, context, skip, flags, success);                \
6039             return {};                                                         \
6040         } else if constexpr (std::is_same_v<attr_type, attr_t>) {              \
6041             return parser(first, last, context, skip, flags, success);         \
6042         } else if constexpr (std::is_constructible_v<attr_type, attr_t>) {     \
6043             return attr_type(                                                  \
6044                 parser(first, last, context, skip, flags, success));           \
6045         } else {                                                               \
6046             attr_type attr{};                                                  \
6047             parser(first, last, context, skip, flags, success, attr);          \
6048             return attr;                                                       \
6049         }                                                                      \
6050     }                                                                          \
6051                                                                                \
6052     template<                                                                  \
6053         typename Iter,                                                         \
6054         typename Sentinel,                                                     \
6055         typename Context,                                                      \
6056         typename SkipParser,                                                   \
6057         typename Attribute>                                                    \
6058     void parse_rule(                                                           \
6059         decltype(rule_name_)::parser_type::tag_type *,                         \
6060         Iter & first,                                                          \
6061         Sentinel last,                                                         \
6062         Context const & context,                                               \
6063         SkipParser const & skip,                                               \
6064         boost::parser::detail::flags flags,                                    \
6065         bool & success,                                                        \
6066         bool & dont_assign,                                                    \
6067         Attribute & retval)                                                    \
6068     {                                                                          \
6069         auto const & parser = BOOST_PARSER_PP_CAT(rule_name_, _def);           \
6070         using attr_t =                                                         \
6071             decltype(parser(first, last, context, skip, flags, success));      \
6072         if constexpr (boost::parser::detail::is_nope_v<attr_t>) {              \
6073             parser(first, last, context, skip, flags, success);                \
6074         } else {                                                               \
6075             parser(first, last, context, skip, flags, success, retval);        \
6076         }                                                                      \
6077     }
6078     //]
6079 
6080 #endif
6081 
6082         /** For each given token `t`, defines a pair of `parse_rule()`
6083            overloads, used internally within Boost.Parser.  Each such pair
6084            implements the parsing behavior rule `t`, using the parser `t_def`.
6085            This implementation is in the form of a pair of function templates.
6086            You should therefore write this macro only at namespace scope. */
6087 #define BOOST_PARSER_DEFINE_RULES(...)                                         \
6088     BOOST_PARSER_PP_FOR_EACH(BOOST_PARSER_DEFINE_IMPL, _, __VA_ARGS__)
6089 
6090 
6091 #ifndef BOOST_PARSER_DOXYGEN
6092 
6093     template<typename ParserTuple>
6094     template<typename Parser>
6095     constexpr auto or_parser<ParserTuple>::prepend(
6096         parser_interface<Parser> parser) const noexcept
6097     {
6098         // If you're seeing this as a compile- or run-time failure, you've
6099         // tried to put an eps parser at the beginning of an
6100         // alternative-parser, such as "eps | (int_ | double_)".  This is not
6101         // what you meant.  Since eps always matches any input, "eps | (int_ |
6102         // double_)" is just an awkward spelling for "eps".  To fix this this,
6103         // put the eps as the last alternative, so the other alternatives get
6104         // a chance.  Possibly, you may have meant to add a condition to the
6105         // eps, like "eps(condition) | (int_ | double_)", which also is
6106         // meaningful, and so is allowed.
6107         BOOST_PARSER_ASSERT(!detail::is_unconditional_eps<Parser>{});
6108         return parser_interface{
6109             or_parser<decltype(detail::hl::prepend(parsers_, parser.parser_))>{
6110                 detail::hl::prepend(parsers_, parser.parser_)}};
6111     }
6112 
6113     template<typename ParserTuple>
6114     template<typename Parser>
6115     constexpr auto or_parser<ParserTuple>::append(
6116         parser_interface<Parser> parser) const noexcept
6117     {
6118         // If you're seeing this as a compile- or run-time failure, you've
6119         // tried to put an eps parser in the middle of an alternative-parser,
6120         // such as "int_ | eps | double_".  This is not what you meant.  Since
6121         // eps always matches any input, "int_ | eps | double_" is just an
6122         // awkward spelling for "int_ | eps".  To fix this this, put the eps
6123         // as the last alternative, so the other alternatives get a chance.
6124         // Possibly, you may have meant to add a condition to the eps, like
6125         // "int_ | eps(condition) | double_", which also is meaningful, and so
6126         // is allowed.
6127         BOOST_PARSER_ASSERT(!detail::is_unconditional_eps_v<decltype(
6128                                 detail::hl::back(parsers_))>);
6129         if constexpr (detail::is_or_p<Parser>{}) {
6130             return parser_interface{or_parser<decltype(
6131                 detail::hl::concat(parsers_, parser.parser_.parsers_))>{
6132                 detail::hl::concat(parsers_, parser.parser_.parsers_)}};
6133         } else {
6134             return parser_interface{or_parser<decltype(
6135                 detail::hl::append(parsers_, parser.parser_))>{
6136                 detail::hl::append(parsers_, parser.parser_)}};
6137         }
6138     }
6139 
6140     template<typename ParserTuple, typename DelimiterParser>
6141     template<typename Parser>
6142     constexpr auto perm_parser<ParserTuple, DelimiterParser>::prepend(
6143         parser_interface<Parser> parser) const noexcept
6144     {
6145         // If you're seeing this as a compile- or run-time failure, you've
6146         // tried to put an eps parser in a permutation-parser, such as "eps ||
6147         // int_".
6148         BOOST_PARSER_ASSERT(!detail::is_eps_p<Parser>{});
6149         return parser_interface{perm_parser<
6150             decltype(detail::hl::prepend(parsers_, parser.parser_)),
6151             detail::nope>{detail::hl::prepend(parsers_, parser.parser_)}};
6152     }
6153 
6154     template<typename ParserTuple, typename DelimiterParser>
6155     template<typename Parser>
6156     constexpr auto perm_parser<ParserTuple, DelimiterParser>::append(
6157         parser_interface<Parser> parser) const noexcept
6158     {
6159         // If you're seeing this as a compile- or run-time failure, you've
6160         // tried to put an eps parser in a permutation-parser, such as "int_
6161         // || eps".
6162         BOOST_PARSER_ASSERT(!detail::is_eps_p<Parser>{});
6163         if constexpr (detail::is_perm_p<Parser>{}) {
6164             return parser_interface{perm_parser<
6165                 decltype(detail::hl::concat(parsers_, parser.parser_.parsers_)),
6166                 detail::nope>{
6167                 detail::hl::concat(parsers_, parser.parser_.parsers_)}};
6168         } else {
6169             return parser_interface{perm_parser<
6170                 decltype(detail::hl::append(parsers_, parser.parser_)),
6171                 detail::nope>{detail::hl::append(parsers_, parser.parser_)}};
6172         }
6173     }
6174 
6175     template<
6176         typename ParserTuple,
6177         typename BacktrackingTuple,
6178         typename CombiningGroups>
6179     template<bool AllowBacktracking, typename Parser>
6180     constexpr auto
6181     seq_parser<ParserTuple, BacktrackingTuple, CombiningGroups>::prepend(
6182         parser_interface<Parser> parser) const noexcept
6183     {
6184         using combining_groups =
6185             detail::combining_t<ParserTuple, CombiningGroups>;
6186         using final_combining_groups =
6187             decltype(detail::hl::prepend(combining_groups{}, llong<0>{}));
6188         using backtracking = decltype(detail::hl::prepend(
6189             detail::hl::prepend(
6190                 detail::hl::drop_front(BacktrackingTuple{}),
6191                 std::bool_constant<AllowBacktracking>{}),
6192             std::true_type{}));
6193         using parser_t = seq_parser<
6194             decltype(detail::hl::prepend(parsers_, parser.parser_)),
6195             backtracking,
6196             final_combining_groups>;
6197         return parser_interface{
6198             parser_t{detail::hl::prepend(parsers_, parser.parser_)}};
6199     }
6200 
6201     template<
6202         typename ParserTuple,
6203         typename BacktrackingTuple,
6204         typename CombiningGroups>
6205     template<bool AllowBacktracking, typename Parser>
6206     constexpr auto
6207     seq_parser<ParserTuple, BacktrackingTuple, CombiningGroups>::append(
6208         parser_interface<Parser> parser) const noexcept
6209     {
6210         using combining_groups =
6211             detail::combining_t<ParserTuple, CombiningGroups>;
6212         if constexpr (detail::is_seq_p<Parser>{}) {
6213             using parser_combining_groups = detail::combining_t<
6214                 decltype(parser.parser_.parsers_),
6215                 typename Parser::combining_groups>;
6216             using final_combining_groups = detail::
6217                 combined_combining_t<combining_groups, parser_combining_groups>;
6218             using rhs_backtracking = decltype(detail::hl::prepend(
6219                 detail::hl::drop_front(typename Parser::backtracking{}),
6220                 std::bool_constant<AllowBacktracking>{}));
6221             using backtracking = decltype(detail::hl::concat(
6222                 BacktrackingTuple{}, rhs_backtracking{}));
6223             using parser_t = seq_parser<
6224                 decltype(detail::hl::concat(parsers_, parser.parser_.parsers_)),
6225                 backtracking,
6226                 final_combining_groups>;
6227             return parser_interface{parser_t{
6228                 detail::hl::concat(parsers_, parser.parser_.parsers_)}};
6229         } else {
6230             using final_combining_groups =
6231                 decltype(detail::hl::append(combining_groups{}, llong<0>{}));
6232             using backtracking = decltype(detail::hl::append(
6233                 BacktrackingTuple{}, std::bool_constant<AllowBacktracking>{}));
6234             using parser_t = seq_parser<
6235                 decltype(detail::hl::append(parsers_, parser.parser_)),
6236                 backtracking,
6237                 final_combining_groups>;
6238             return parser_interface{
6239                 parser_t{detail::hl::append(parsers_, parser.parser_)}};
6240         }
6241     }
6242 
6243 #endif
6244 
6245 
6246 
6247     // Directives.
6248 
6249     /** Represents a unparameterized higher-order parser (e.g. `omit_parser`)
6250         as a directive (e.g. `omit[other_parser]`). */
6251     template<template<class> class Parser>
6252     struct directive
6253     {
6254         template<typename Parser2>
6255         constexpr auto operator[](parser_interface<Parser2> rhs) const noexcept
6256         {
6257             return parser_interface{Parser<Parser2>{rhs.parser_}};
6258         }
6259     };
6260 
6261     /** The `omit` directive, whose `operator[]` returns a
6262         `parser_interface<omit_parser<P>>` from a given parser of type
6263         `parser_interface<P>`. */
6264     inline constexpr directive<omit_parser> omit;
6265 
6266     /** The `raw` directive, whose `operator[]` returns a
6267         `parser_interface<raw_parser<P>>` from a given parser of type
6268         `parser_interface<P>`. */
6269     inline constexpr directive<raw_parser> raw;
6270 
6271 #if defined(BOOST_PARSER_DOXYGEN) || BOOST_PARSER_USE_CONCEPTS
6272     /** The `string_view` directive, whose `operator[]` returns a
6273         `parser_interface<string_view_parser<P>>` from a given parser of type
6274         `parser_interface<P>`.  This is only available in C++20 and later. */
6275     inline constexpr directive<string_view_parser> string_view;
6276 #endif
6277 
6278     /** The `lexeme` directive, whose `operator[]` returns a
6279         `parser_interface<lexeme_parser<P>>` from a given parser of type
6280         `parser_interface<P>`. */
6281     inline constexpr directive<lexeme_parser> lexeme;
6282 
6283     /** The `no_case` directive, whose `operator[]` returns a
6284         `parser_interface<no_case_parser<P>>` from a given parser of type
6285         `parser_interface<P>`. */
6286     inline constexpr directive<no_case_parser> no_case;
6287 
6288     /** Represents a `repeat_parser` as a directive
6289         (e.g. `repeat[other_parser]`). */
6290     template<typename MinType, typename MaxType>
6291     struct repeat_directive
6292     {
6293         template<typename Parser2>
6294         constexpr auto operator[](parser_interface<Parser2> rhs) const noexcept
6295         {
6296             using repeat_parser_type =
6297                 repeat_parser<Parser2, detail::nope, MinType, MaxType>;
6298             return parser_interface{
6299                 repeat_parser_type{rhs.parser_, min_, max_}};
6300         }
6301 
6302         MinType min_;
6303         MaxType max_;
6304     };
6305 
6306     /** Returns a `repeat_directive` that repeats exactly `n` times, and whose
6307         `operator[]` returns a `parser_interface<repeat_parser<P>>` from a
6308         given parser of type `parser_interface<P>`. */
6309     template<typename T>
6310     constexpr repeat_directive<T, T> repeat(T n) noexcept
6311     {
6312         return repeat_directive<T, T>{n, n};
6313     }
6314 
6315     /** Returns a `repeat_directive` that repeats between `min_` and `max_`
6316         times, inclusive, and whose `operator[]` returns a
6317         `parser_interface<repeat_parser<P>>` from a given parser of type
6318         `parser_interface<P>`. */
6319     template<typename MinType, typename MaxType>
6320     constexpr repeat_directive<MinType, MaxType>
6321     repeat(MinType min_, MaxType max_) noexcept
6322     {
6323         return repeat_directive<MinType, MaxType>{min_, max_};
6324     }
6325 
6326     /** A directive that represents a `perm_parser`, where the items parsed
6327         are delimited by `DelimiterParser`,
6328         (e.g. `delimiter(delimter_parser)[some_perm_parser]`).  This directive
6329         only applies to `perm_parser`s. */
6330     template<typename DelimiterParser>
6331     struct delimiter_directive
6332     {
6333         template<typename ParserTuple, typename DelimiterParser2>
6334         constexpr auto operator[](
6335             parser_interface<perm_parser<ParserTuple, DelimiterParser2>> rhs)
6336             const noexcept
6337         {
6338             using parser_type = perm_parser<ParserTuple, DelimiterParser>;
6339             return parser_interface{
6340                 parser_type{rhs.parser_.parsers_, delimiter_parser_}};
6341         }
6342 
6343         DelimiterParser delimiter_parser_;
6344     };
6345 
6346     /** Returns a `delimiter_directive` whose `operator[]` returns a
6347         `perm_parser`, where the items parsed are delimited by
6348         `delimiter_parser`. */
6349     template<typename DelimiterParser>
6350     constexpr delimiter_directive<DelimiterParser>
6351     delimiter(parser_interface<DelimiterParser> delimiter_parser) noexcept
6352     {
6353         return delimiter_directive<DelimiterParser>{delimiter_parser.parser_};
6354     }
6355 
6356     /** Represents a skip parser as a directive.  When used without a skip
6357         parser, e.g. `skip[parser_in_which_to_do_skipping]`, the skipper for
6358         the entire parse is used.  When given another parser, e.g.
6359         `skip(skip_parser)[parser_in_which_to_do_skipping]`, that other parser
6360         is used as the skipper within the directive. */
6361     template<typename SkipParser = detail::nope>
6362     struct skip_directive
6363     {
6364         template<typename Parser>
6365         constexpr auto operator[](parser_interface<Parser> rhs) const noexcept
6366         {
6367             return parser_interface{
6368                 skip_parser<Parser, SkipParser>{rhs.parser_, skip_parser_}};
6369         }
6370 
6371         /** Returns a `skip_directive` with `skip_parser` as its skipper. */
6372         template<typename SkipParser2>
6373         constexpr auto
6374         operator()(parser_interface<SkipParser2> skip_parser) const noexcept
6375         {
6376             BOOST_PARSER_ASSERT(
6377                 (detail::is_nope_v<SkipParser> &&
6378                  "If you're seeing this, you tried to chain calls on skip, "
6379                  "like 'skip(foo)(bar)'.  Quit it!'"));
6380             return skip_directive<parser_interface<SkipParser2>>{skip_parser};
6381         }
6382 
6383         SkipParser skip_parser_;
6384     };
6385 
6386     /** The `skip_directive`, whose `operator[]` returns a
6387         `parser_interface<skip_parser<P>>` from a given parser of type
6388         `parser_interface<P>`. */
6389     inline constexpr skip_directive<> skip;
6390 
6391     /** A directive type that can only be used on sequence parsers, that
6392         forces the merge of all the sequence_parser's subparser's attributes
6393         into a single attribute. */
6394     struct merge_directive
6395     {
6396         template<
6397             typename ParserTuple,
6398             typename BacktrackingTuple,
6399             typename CombiningGroups>
6400         constexpr auto
6401         operator[](parser_interface<
6402                    seq_parser<ParserTuple, BacktrackingTuple, CombiningGroups>>
6403                        rhs) const noexcept
6404         {
6405             return parser_interface{
6406                 seq_parser<ParserTuple, BacktrackingTuple, detail::merge_t>{
6407                     rhs.parser_.parsers_}};
6408         }
6409     };
6410 
6411     /** The `merge_directive`, whose `operator[]` returns a
6412         `parser_interface<P2>`, from a given parser of type
6413         `parser_interface<P>`, where `P` is a `seq_parser`.  `P2` is the same
6414         as `P`, except that its `CombiningGroups` template parameter is
6415         replaced with a tag type that causes the subparser's attributes to be
6416         merged into a single attribute. */
6417     inline constexpr merge_directive merge;
6418 
6419     /** A directive type that can only be used on sequence parsers, that
6420         prevents each of the sequence_parser's subparser's attributes from
6421         merging with any other subparser's attribute. */
6422     struct separate_directive
6423     {
6424         template<
6425             typename ParserTuple,
6426             typename BacktrackingTuple,
6427             typename CombiningGroups>
6428         constexpr auto
6429         operator[](parser_interface<
6430                    seq_parser<ParserTuple, BacktrackingTuple, CombiningGroups>>
6431                        rhs) const noexcept
6432         {
6433             return parser_interface{
6434                 seq_parser<ParserTuple, BacktrackingTuple, detail::separate_t>{
6435                     rhs.parser_.parsers_}};
6436         }
6437     };
6438 
6439     /** The `separate_directive`, whose `operator[]` returns a
6440         `parser_interface<P2>`, from a given parser of type
6441         `parser_interface<P>`, where `P` is a `seq_parser`.  `P2` is the same
6442         as `P`, except that its `CombiningGroups` template parameter is
6443         replaced with a tag type that prevents each subparser's attribute from
6444         merging with any other subparser's attribute. */
6445     inline constexpr separate_directive separate;
6446 
6447     /** A directive that transforms the attribute generated by a parser.
6448         `operator[]` returns a `parser_interface<transform_parser<Parser,
6449         F>>`. */
6450     template<typename F>
6451     struct transform_directive
6452     {
6453         template<typename Parser>
6454         constexpr auto operator[](parser_interface<Parser> rhs) const noexcept
6455         {
6456             return parser_interface{
6457                 transform_parser<Parser, F>{rhs.parser_, f_}};
6458         }
6459 
6460         F f_;
6461     };
6462 
6463     /** Returns a `transform_directive` that uses invocable `F` to do its
6464         work. */
6465     template<typename F>
6466     auto transform(F f)
6467     {
6468         return transform_directive<F>{std::move(f)};
6469     }
6470 
6471 
6472     // First order parsers.
6473 
6474 #ifndef BOOST_PARSER_DOXYGEN
6475 
6476     template<typename Predicate>
6477     struct eps_parser
6478     {
6479         template<
6480             typename Iter,
6481             typename Sentinel,
6482             typename Context,
6483             typename SkipParser>
6484         detail::nope call(
6485             Iter & first,
6486             Sentinel last,
6487             Context const & context,
6488             SkipParser const & skip,
6489             detail::flags flags,
6490             bool & success) const noexcept
6491         {
6492             [[maybe_unused]] auto _ = detail::scoped_trace(
6493                 *this, first, last, context, flags, detail::global_nope);
6494             BOOST_PARSER_SUBRANGE const where(first, first);
6495             auto const predicate_context = detail::make_action_context(
6496                 context, detail::global_nope, where);
6497             // Predicate must be a parse predicate.  If you see an error here,
6498             // you have not met this contract.  See the terminology section of
6499             // the online docs if you don't know what that a parse predicate
6500             // is.
6501             success = pred_(predicate_context);
6502             return {};
6503         }
6504 
6505         template<
6506             typename Iter,
6507             typename Sentinel,
6508             typename Context,
6509             typename SkipParser,
6510             typename Attribute>
6511         void call(
6512             Iter & first,
6513             Sentinel last,
6514             Context const & context,
6515             SkipParser const & skip,
6516             detail::flags flags,
6517             bool & success,
6518             Attribute & retval) const
6519         {
6520             [[maybe_unused]] auto _ = detail::scoped_trace(
6521                 *this, first, last, context, flags, retval);
6522             BOOST_PARSER_SUBRANGE const where(first, first);
6523             auto const predicate_context = detail::make_action_context(
6524                 context, detail::global_nope, where);
6525             // Predicate must be a parse predicate.  If you see an error here,
6526             // you have not met this contract.  See the terminology section of
6527             // the online docs if you don't know what that a parse predicate
6528             // is.
6529             success = pred_(predicate_context);
6530         }
6531 
6532         /** Returns a `parser_interface` containing an `eps_parser` that will
6533             fail if `pred` evaluates to false. */
6534         template<typename Predicate2>
6535         constexpr auto operator()(Predicate2 pred) const noexcept
6536         {
6537             BOOST_PARSER_ASSERT(
6538                 (detail::is_nope_v<Predicate> &&
6539                  "If you're seeing this, you tried to chain calls on eps, "
6540                  "like 'eps(foo)(bar)'.  Quit it!'"));
6541             return parser_interface{eps_parser<Predicate2>{std::move(pred)}};
6542         }
6543 
6544         Predicate pred_;
6545     };
6546 
6547 #endif
6548 
6549     /** The epsilon parser.  This matches anything, and consumes no input.  If
6550         used with an optional predicate, like `eps(pred)`, it matches iff
6551         `pred(ctx)` evaluates to true, where `ctx` is the parser context. */
6552     inline constexpr parser_interface<eps_parser<detail::nope>> eps;
6553 
6554 #ifndef BOOST_PARSER_DOXYGEN
6555 
6556     struct eoi_parser
6557     {
6558         template<
6559             typename Iter,
6560             typename Sentinel,
6561             typename Context,
6562             typename SkipParser>
6563         detail::nope call(
6564             Iter & first,
6565             Sentinel last,
6566             Context const & context,
6567             SkipParser const & skip,
6568             detail::flags flags,
6569             bool & success) const
6570         {
6571             [[maybe_unused]] auto _ = detail::scoped_trace(
6572                 *this, first, last, context, flags, detail::global_nope);
6573             if (first != last)
6574                 success = false;
6575             return {};
6576         }
6577 
6578         template<
6579             typename Iter,
6580             typename Sentinel,
6581             typename Context,
6582             typename SkipParser,
6583             typename Attribute>
6584         void call(
6585             Iter & first,
6586             Sentinel last,
6587             Context const & context,
6588             SkipParser const & skip,
6589             detail::flags flags,
6590             bool & success,
6591             Attribute & retval) const
6592         {
6593             [[maybe_unused]] auto _ = detail::scoped_trace(
6594                 *this, first, last, context, flags, retval);
6595             if (first != last)
6596                 success = false;
6597         }
6598     };
6599 
6600 #endif
6601 
6602     /** The end-of-input parser.  It matches only the end of input. */
6603     inline constexpr parser_interface<eoi_parser> eoi;
6604 
6605 #ifndef BOOST_PARSER_DOXYGEN
6606 
6607     template<typename Attribute>
6608     struct attr_parser
6609     {
6610         template<
6611             typename Iter,
6612             typename Sentinel,
6613             typename Context,
6614             typename SkipParser>
6615         auto call(
6616             Iter & first,
6617             Sentinel last,
6618             Context const & context,
6619             SkipParser const &,
6620             detail::flags flags,
6621             bool &) const
6622         {
6623             [[maybe_unused]] auto _ = detail::scoped_trace(
6624                 *this, first, last, context, flags, detail::global_nope);
6625             return detail::resolve(context, attr_);
6626         }
6627 
6628         template<
6629             typename Iter,
6630             typename Sentinel,
6631             typename Context,
6632             typename SkipParser,
6633             typename Attribute_>
6634         void call(
6635             Iter & first,
6636             Sentinel last,
6637             Context const & context,
6638             SkipParser const & skip,
6639             detail::flags flags,
6640             bool & success,
6641             Attribute_ & retval) const
6642         {
6643             [[maybe_unused]] auto _ = detail::scoped_trace(
6644                 *this, first, last, context, flags, retval);
6645             if (detail::gen_attrs(flags))
6646                 detail::assign_copy(retval, detail::resolve(context, attr_));
6647         }
6648 
6649         Attribute attr_;
6650     };
6651 
6652 #endif
6653 
6654     /** Returns an `attr_parser` which matches anything, and consumes no
6655         input, and which produces `a` as its attribute. */
6656     template<typename Attribute>
6657     constexpr auto attr(Attribute a) noexcept
6658     {
6659         return parser_interface{attr_parser<Attribute>{std::move(a)}};
6660     }
6661 
6662 #ifndef BOOST_PARSER_DOXYGEN
6663 
6664     template<typename Expected, typename AttributeType>
6665     struct char_parser
6666     {
6667         constexpr char_parser() {}
6668         constexpr char_parser(Expected expected) : expected_(expected) {}
6669 
6670         template<typename T>
6671         using attribute_type = std::conditional_t<
6672             std::is_same_v<AttributeType, void>,
6673             std::decay_t<T>,
6674             AttributeType>;
6675 
6676         template<
6677             typename Iter,
6678             typename Sentinel,
6679             typename Context,
6680             typename SkipParser>
6681         auto call(
6682             Iter & first,
6683             Sentinel last,
6684             Context const & context,
6685             SkipParser const & skip,
6686             detail::flags flags,
6687             bool & success) const -> attribute_type<decltype(*first)>
6688         {
6689             attribute_type<decltype(*first)> retval{};
6690             call(first, last, context, skip, flags, success, retval);
6691             return retval;
6692         }
6693 
6694         template<
6695             typename Iter,
6696             typename Sentinel,
6697             typename Context,
6698             typename SkipParser,
6699             typename Attribute>
6700         void call(
6701             Iter & first,
6702             Sentinel last,
6703             Context const & context,
6704             SkipParser const & skip,
6705             detail::flags flags,
6706             bool & success,
6707             Attribute & retval) const
6708         {
6709             [[maybe_unused]] auto _ = detail::scoped_trace(
6710                 *this, first, last, context, flags, retval);
6711 
6712             if (first == last) {
6713                 success = false;
6714                 return;
6715             }
6716             attribute_type<decltype(*first)> const x = *first;
6717             if (detail::unequal(context, x, expected_)) {
6718                 success = false;
6719                 return;
6720             }
6721             detail::assign(retval, x);
6722             ++first;
6723         }
6724 
6725         /** Returns a `parser_interface` containing a `char_parser` that
6726             matches `x`.
6727 
6728             \tparam T Constrained by `!parsable_range_like<T>`. */
6729 #if BOOST_PARSER_USE_CONCEPTS
6730         template<typename T>
6731             requires(!parsable_range_like<T>)
6732 #else
6733         template<
6734             typename T,
6735             typename Enable =
6736                 std::enable_if_t<!detail::is_parsable_range_like_v<T>>>
6737 #endif
6738         constexpr auto operator()(T x) const noexcept
6739         {
6740             BOOST_PARSER_ASSERT(
6741                 (detail::is_nope_v<Expected> &&
6742                  "If you're seeing this, you tried to chain calls on char_, "
6743                  "like 'char_('a')('b')'.  Quit it!'"));
6744             return parser_interface{
6745                 char_parser<T, AttributeType>{std::move(x)}};
6746         }
6747 
6748         /** Returns a `parser_interface` containing a `char_parser` that
6749             matches any value in `[lo, hi]`. */
6750         template<typename LoType, typename HiType>
6751         constexpr auto operator()(LoType lo, HiType hi) const noexcept
6752         {
6753             BOOST_PARSER_ASSERT(
6754                 (detail::is_nope_v<Expected> &&
6755                  "If you're seeing this, you tried to chain calls on char_, "
6756                  "like 'char_('a', 'b')('c', 'd')'.  Quit it!'"));
6757             using char_pair_t = detail::char_pair<LoType, HiType>;
6758             using char_parser_t = char_parser<char_pair_t, AttributeType>;
6759             return parser_interface(
6760                 char_parser_t(char_pair_t{std::move(lo), std::move(hi)}));
6761         }
6762 
6763         /** Returns a `parser_interface` containing a `char_parser` that
6764             matches one of the values in `r`.  If the character being matched
6765             during the parse is a `char32_t` value, the elements of `r` are
6766             transcoded from their presumed encoding to UTF-32 during the
6767             comparison.  Otherwise, the character begin matched is directly
6768             compared to the elements of `r`. */
6769 #if BOOST_PARSER_USE_CONCEPTS
6770         template<parsable_range_like R>
6771 #else
6772         template<
6773             typename R,
6774             typename Enable =
6775                 std::enable_if_t<detail::is_parsable_range_like_v<R>>>
6776 #endif
6777         constexpr auto operator()(R && r) const noexcept
6778         {
6779             BOOST_PARSER_ASSERT(
6780                 ((!std::is_rvalue_reference_v<R &&> ||
6781                   !detail::is_range<detail::remove_cv_ref_t<R>>) &&
6782                      "It looks like you tried to pass an rvalue range to "
6783                      "char_().  Don't do that, or you'll end up with dangling "
6784                      "references."));
6785             BOOST_PARSER_ASSERT(
6786                 (detail::is_nope_v<Expected> &&
6787                  "If you're seeing this, you tried to chain calls on char_, "
6788                  "like 'char_(char-set)(char-set)'.  Quit it!'"));
6789             auto chars = detail::make_char_range<false>(r);
6790             using char_range_t = decltype(chars);
6791             using char_parser_t = char_parser<char_range_t, AttributeType>;
6792             return parser_interface(char_parser_t(chars));
6793         }
6794 
6795         /** Returns a `parser_interface` containing a `char_parser` that
6796             matches one of the values in `r`.  `r` must be a sorted,
6797             random-access sequence of `char32_t`.  The character begin matched
6798             is directly compared to the elements of `r`.  The match is found
6799             via binary search.  No case folding is performed.
6800 
6801             \tparam R Additionally constrained by
6802             `std::same_as<std::ranges::range_value_t<R>, char32_t>`. */
6803 #if BOOST_PARSER_USE_CONCEPTS
6804         template<parsable_range_like R>
6805             requires std::same_as<std::ranges::range_value_t<R>, char32_t>
6806 #else
6807         template<
6808             typename R,
6809             typename Enable = std::enable_if_t<
6810                 detail::is_parsable_range_like_v<R> &&
6811                 std::is_same_v<detail::range_value_t<R>, char32_t>>>
6812 #endif
6813         constexpr auto operator()(sorted_t, R && r) const noexcept
6814         {
6815             BOOST_PARSER_ASSERT(
6816                 ((!std::is_rvalue_reference_v<R &&> ||
6817                   !detail::is_range<detail::remove_cv_ref_t<R>>) &&
6818                  "It looks like you tried to pass an rvalue range to "
6819                  "char_().  Don't do that, or you'll end up with dangling "
6820                  "references."));
6821             BOOST_PARSER_ASSERT(
6822                 (detail::is_nope_v<Expected> &&
6823                  "If you're seeing this, you tried to chain calls on char_, "
6824                  "like 'char_(char-set)(char-set)'.  Quit it!'"));
6825             auto chars = detail::make_char_range<true>(r);
6826             using char_range_t = decltype(chars);
6827             using char_parser_t = char_parser<char_range_t, AttributeType>;
6828             return parser_interface(char_parser_t(chars));
6829         }
6830 
6831         Expected expected_;
6832     };
6833 
6834     struct digit_parser
6835     {
6836         constexpr digit_parser() {}
6837 
6838         template<typename T>
6839         using attribute_type = std::decay_t<T>;
6840 
6841         template<
6842             typename Iter,
6843             typename Sentinel,
6844             typename Context,
6845             typename SkipParser>
6846         auto call(
6847             Iter & first,
6848             Sentinel last,
6849             Context const & context,
6850             SkipParser const & skip,
6851             detail::flags flags,
6852             bool & success) const -> attribute_type<decltype(*first)>
6853         {
6854             attribute_type<decltype(*first)> retval{};
6855             call(first, last, context, skip, flags, success, retval);
6856             return retval;
6857         }
6858 
6859         template<
6860             typename Iter,
6861             typename Sentinel,
6862             typename Context,
6863             typename SkipParser,
6864             typename Attribute>
6865         void call(
6866             Iter & first,
6867             Sentinel last,
6868             Context const & context,
6869             SkipParser const & skip,
6870             detail::flags flags,
6871             bool & success,
6872             Attribute & retval) const
6873         {
6874             [[maybe_unused]] auto _ = detail::scoped_trace(
6875                 *this, first, last, context, flags, retval);
6876 
6877             if (first == last) {
6878                 success = false;
6879                 return;
6880             }
6881             attribute_type<decltype(*first)> const x = *first;
6882             char32_t const x_cmp = x;
6883             if (x_cmp < U'\x0100' && (x_cmp < U'0' || U'9' < x_cmp)) {
6884                 success = false;
6885                 return;
6886             }
6887             char32_t const * it = std::upper_bound(
6888                 std::begin(zero_cps) + 1, std::end(zero_cps), x_cmp);
6889             if (it == std::begin(zero_cps) || x_cmp < *(it - 1) ||
6890                 *(it - 1) + 9 < x_cmp) {
6891                 success = false;
6892                 return;
6893             }
6894             detail::assign(retval, x);
6895             ++first;
6896         }
6897 
6898         // Produced from
6899         // https://util.unicode.org/UnicodeJsps/list-unicodeset.jsp, using
6900         // "[:nt=De:]" for the Input field.
6901         static constexpr char32_t zero_cps[] = {
6902             U'\u0030',     // U+0030 DIGIT ZERO
6903             U'\u0660',     // U+0660 ARABIC-INDIC DIGIT ZERO
6904             U'\u06F0',     // U+06F0 EXTENDED ARABIC-INDIC DIGIT ZERO
6905             U'\u07C0',     // U+07C0 NKO DIGIT ZERO
6906             U'\u0966',     // U+0966 DEVANAGARI DIGIT ZERO
6907             U'\u09E6',     // U+09E6 BENGALI DIGIT ZERO
6908             U'\u0A66',     // U+0A66 GURMUKHI DIGIT ZERO
6909             U'\u0AE6',     // U+0AE6 GUJARATI DIGIT ZERO
6910             U'\u0B66',     // U+0B66 ORIYA DIGIT ZERO
6911             U'\u0BE6',     // U+0BE6 TAMIL DIGIT ZERO
6912             U'\u0C66',     // U+0C66 TELUGU DIGIT ZERO
6913             U'\u0CE6',     // U+0CE6 KANNADA DIGIT ZERO
6914             U'\u0D66',     // U+0D66 MALAYALAM DIGIT ZERO
6915             U'\u0DE6',     // U+0DE6 SINHALA LITH DIGIT ZERO
6916             U'\u0E50',     // U+0E50 THAI DIGIT ZERO
6917             U'\u0ED0',     // U+0ED0 LAO DIGIT ZERO
6918             U'\u0F20',     // U+0F20 TIBETAN DIGIT ZERO
6919             U'\u1040',     // U+1040 MYANMAR DIGIT ZERO
6920             U'\u1090',     // U+1090 MYANMAR SHAN DIGIT ZERO
6921             U'\u17E0',     // U+17E0 KHMER DIGIT ZERO
6922             U'\u1810',     // U+1810 MONGOLIAN DIGIT ZERO
6923             U'\u1946',     // U+1946 LIMBU DIGIT ZERO
6924             U'\u19D0',     // U+19D0 NEW TAI LUE DIGIT ZERO
6925             U'\u1A80',     // U+1A80 TAI THAM HORA DIGIT ZERO
6926             U'\u1A90',     // U+1A90 TAI THAM THAM DIGIT ZERO
6927             U'\u1B50',     // U+1B50 BALINESE DIGIT ZERO
6928             U'\u1BB0',     // U+1BB0 SUNDANESE DIGIT ZERO
6929             U'\u1C40',     // U+1C40 LEPCHA DIGIT ZERO
6930             U'\u1C50',     // U+1C50 OL CHIKI DIGIT ZERO
6931             U'\uA620',     // U+A620 VAI DIGIT ZERO
6932             U'\uA8D0',     // U+A8D0 SAURASHTRA DIGIT ZERO
6933             U'\uA900',     // U+A900 KAYAH LI DIGIT ZERO
6934             U'\uA9D0',     // U+A9D0 JAVANESE DIGIT ZERO
6935             U'\uA9F0',     // U+A9F0 MYANMAR TAI LAING DIGIT ZERO
6936             U'\uAA50',     // U+AA50 CHAM DIGIT ZERO
6937             U'\uABF0',     // U+ABF0 MEETEI MAYEK DIGIT ZERO
6938             U'\uFF10',     // U+FF10 FULLWIDTH DIGIT ZERO
6939             U'\U000104A0', // U+104A0 OSMANYA DIGIT ZERO
6940             U'\U00010D30', // U+10D30 HANIFI ROHINGYA DIGIT ZERO
6941             U'\U00011066', // U+11066 BRAHMI DIGIT ZERO
6942             U'\U000110F0', // U+110F0 SORA SOMPENG DIGIT ZERO
6943             U'\U00011136', // U+11136 CHAKMA DIGIT ZERO
6944             U'\U000111D0', // U+111D0 SHARADA DIGIT ZERO
6945             U'\U000112F0', // U+112F0 KHUDAWADI DIGIT ZERO
6946             U'\U00011450', // U+11450 NEWA DIGIT ZERO
6947             U'\U000114D0', // U+114D0 TIRHUTA DIGIT ZERO
6948             U'\U00011650', // U+11650 MODI DIGIT ZERO
6949             U'\U000116C0', // U+116C0 TAKRI DIGIT ZERO
6950             U'\U00011730', // U+11730 AHOM DIGIT ZERO
6951             U'\U000118E0', // U+118E0 WARANG CITI DIGIT ZERO
6952             U'\U00011950', // U+11950 DIVES AKURU DIGIT ZERO
6953             U'\U00011C50', // U+11C50 BHAIKSUKI DIGIT ZERO
6954             U'\U00011D50', // U+11D50 MASARAM GONDI DIGIT ZERO
6955             U'\U00011DA0', // U+11DA0 GUNJALA GONDI DIGIT ZERO
6956             U'\U00011F50', // U+11F50 KAWI DIGIT ZERO
6957             U'\U00016A60', // U+16A60 MRO DIGIT ZERO
6958             U'\U00016AC0', // U+16AC0 TANGSA DIGIT ZERO
6959             U'\U00016B50', // U+16B50 PAHAWH HMONG DIGIT ZERO
6960             U'\U0001D7CE', // U+1D7CE MATHEMATICAL BOLD DIGIT ZERO
6961             U'\U0001D7D8', // U+1D7D8 MATHEMATICAL DOUBLE-STRUCK DIGIT ZERO
6962             U'\U0001D7E2', // U+1D7E2 MATHEMATICAL SANS-SERIF DIGIT ZERO
6963             U'\U0001D7EC', // U+1D7EC MATHEMATICAL SANS-SERIF BOLD DIGIT ZERO
6964             U'\U0001D7F6', // U+1D7F6 MATHEMATICAL MONOSPACE DIGIT ZERO
6965             U'\U0001E140', // U+1E140 NYIAKENG PUACHUE HMONG DIGIT ZERO
6966             U'\U0001E2F0', // U+1E2F0 WANCHO DIGIT ZERO
6967             U'\U0001E4F0', // U+1E4F0 NAG MUNDARI DIGIT ZERO
6968             U'\U0001E950', // U+1E950 ADLAM DIGIT ZERO
6969             U'\U0001FBF0'  // U+1FBF0 SEGMENTED DIGIT ZERO
6970         };
6971     };
6972 
6973     template<typename Tag>
6974     struct char_set_parser
6975     {
6976         BOOST_PARSER_ALGO_CONSTEXPR char_set_parser()
6977         {
6978             auto const & chars = detail::char_set<Tag>::chars;
6979             auto const first = std::begin(chars);
6980             auto const last = std::end(chars);
6981             auto it = std::upper_bound(first, last, 0x100, [](auto x, auto y){
6982                 using common_t = std::common_type_t<decltype(x), decltype(x)>;
6983                 return (common_t)x < (common_t)y;
6984             });
6985             if (it != last)
6986                 one_byte_offset_ = int(it - first);
6987         }
6988 
6989         template<typename T>
6990         using attribute_type = std::decay_t<T>;
6991 
6992         template<
6993             typename Iter,
6994             typename Sentinel,
6995             typename Context,
6996             typename SkipParser>
6997         auto call(
6998             Iter & first,
6999             Sentinel last,
7000             Context const & context,
7001             SkipParser const & skip,
7002             detail::flags flags,
7003             bool & success) const -> attribute_type<decltype(*first)>
7004         {
7005             attribute_type<decltype(*first)> retval{};
7006             call(first, last, context, skip, flags, success, retval);
7007             return retval;
7008         }
7009 
7010         template<
7011             typename Iter,
7012             typename Sentinel,
7013             typename Context,
7014             typename SkipParser,
7015             typename Attribute>
7016         void call(
7017             Iter & first,
7018             Sentinel last,
7019             Context const & context,
7020             SkipParser const & skip,
7021             detail::flags flags,
7022             bool & success,
7023             Attribute & retval) const
7024         {
7025             [[maybe_unused]] auto _ = detail::scoped_trace(
7026                 *this, first, last, context, flags, retval);
7027 
7028             if (first == last) {
7029                 success = false;
7030                 return;
7031             }
7032 
7033             auto const & chars = detail::char_set<Tag>::chars;
7034             attribute_type<decltype(*first)> const x = *first;
7035             uint32_t const x_cmp = x;
7036             if (x_cmp < U'\x0100') {
7037                 uint32_t const * it = std::lower_bound(
7038                     std::begin(chars),
7039                     std::begin(chars) + one_byte_offset_,
7040                     x_cmp);
7041                 if (it != std::end(chars) && *it == x_cmp) {
7042                     detail::assign(retval, x_cmp);
7043                     ++first;
7044                 } else {
7045                     success = false;
7046                 }
7047                 return;
7048             }
7049 
7050             uint32_t const * it = std::lower_bound(
7051                 std::begin(chars) + one_byte_offset_, std::end(chars), x_cmp);
7052             if (it != std::end(chars) && *it == x_cmp) {
7053                 detail::assign(retval, x_cmp);
7054                 ++first;
7055                 return;
7056             }
7057 
7058             success = false;
7059         }
7060 
7061         int one_byte_offset_ = 0;
7062     };
7063 
7064     template<typename Tag>
7065     struct char_subrange_parser
7066     {
7067         constexpr char_subrange_parser() {}
7068 
7069         template<typename T>
7070         using attribute_type = std::decay_t<T>;
7071 
7072         template<
7073             typename Iter,
7074             typename Sentinel,
7075             typename Context,
7076             typename SkipParser>
7077         auto call(
7078             Iter & first,
7079             Sentinel last,
7080             Context const & context,
7081             SkipParser const & skip,
7082             detail::flags flags,
7083             bool & success) const -> attribute_type<decltype(*first)>
7084         {
7085             attribute_type<decltype(*first)> retval{};
7086             call(first, last, context, skip, flags, success, retval);
7087             return retval;
7088         }
7089 
7090         template<
7091             typename Iter,
7092             typename Sentinel,
7093             typename Context,
7094             typename SkipParser,
7095             typename Attribute>
7096         void call(
7097             Iter & first,
7098             Sentinel last,
7099             Context const & context,
7100             SkipParser const & skip,
7101             detail::flags flags,
7102             bool & success,
7103             Attribute & retval) const
7104         {
7105             [[maybe_unused]] auto _ = detail::scoped_trace(
7106                 *this, first, last, context, flags, retval);
7107 
7108             if (first == last) {
7109                 success = false;
7110                 return;
7111             }
7112             attribute_type<decltype(*first)> const x = *first;
7113             char32_t const x_cmp = x;
7114             success = false;
7115             for (auto subrange : detail::char_subranges<Tag>::ranges) {
7116                 if (subrange.lo_ <= x_cmp && x_cmp <= subrange.hi_) {
7117                     success = true;
7118                     detail::assign(retval, x);
7119                     ++first;
7120                     return;
7121                 }
7122             }
7123         }
7124     };
7125 
7126 #endif
7127 
7128     /** The single-character parser.  The produced attribute is the type of
7129         the matched code point (`char` or `char32_t`).  Used as-is, `char_`
7130         matches any code point.  `char_` can also can be used to create code
7131         point parsers that match one or more specific code point values, by
7132         calling it with: a single value comparable to a code point; a closed
7133         range of code point values `[lo, hi]`, or a set of code point values
7134         passed as a range.  When calling with a range, only the iterators that
7135         bound the range are stored.  Make sure the range you pass outlives the
7136         use of the resulting parser.  Note that a string literal is a range,
7137         and that it outlives any parser it is used to construct. */
7138     inline constexpr parser_interface<char_parser<detail::nope>> char_;
7139 
7140     /** The code point parser.  It produces a `char32_t` attribute.  Used
7141         as-is, `cp` matches any code point.  `cp` can also can be used to
7142         create code point parsers that match one or more specific code point
7143         values, by calling it with: a single value comparable to a code point;
7144         a closed range of code point values `[lo, hi]`, or a set of code point
7145         values passed as a range.  When calling with a range, only the
7146         iterators that bound the range are stored.  Make sure the range you
7147         pass outlives the use of the resulting parser.  Note that a string
7148         literal is a range, and that it outlives any parser it is used to
7149         construct. */
7150     inline constexpr parser_interface<char_parser<detail::nope, char32_t>> cp;
7151 
7152     /** The code unit parser.  It produces a `char` attribute.  Used as-is,
7153         `cu` matches any code point.  `cu` can also can be used to create code
7154         point parsers that match one or more specific code point values, by
7155         calling it with: a single value comparable to a code point; a closed
7156         range of code point values `[lo, hi]`, or a set of code point values
7157         passed as a range.  When calling with a range, only the iterators that
7158         bound the range are stored.  Make sure the range you pass outlives the
7159         use of the resulting parser.  Note that a string literal is a range,
7160         and that it outlives any parser it is used to construct. */
7161     inline constexpr parser_interface<char_parser<detail::nope, char>> cu;
7162 
7163     /** Returns a literal code point parser that produces no attribute. */
7164     inline constexpr auto lit(char c) noexcept { return omit[char_(c)]; }
7165 
7166 #if defined(__cpp_char8_t) || defined(BOOST_PARSER_DOXYGEN)
7167     /** Returns a literal code point parser that produces no attribute. */
7168     inline constexpr auto lit(char8_t c) noexcept { return omit[char_(c)]; }
7169 #endif
7170 
7171     /** Returns a literal code point parser that produces no attribute. */
7172     inline constexpr auto lit(char32_t c) noexcept { return omit[char_(c)]; }
7173 
7174 #ifndef BOOST_PARSER_DOXYGEN
7175 
7176     template<typename StrIter, typename StrSentinel>
7177     struct string_parser
7178     {
7179         constexpr string_parser() : expected_first_(), expected_last_() {}
7180 
7181 #if BOOST_PARSER_USE_CONCEPTS
7182         template<parsable_range_like R>
7183 #else
7184         template<
7185             typename R,
7186             typename Enable =
7187                 std::enable_if_t<detail::is_parsable_range_like_v<R>>>
7188 #endif
7189         constexpr string_parser(R && r) :
7190             expected_first_(detail::make_view_begin(r)),
7191             expected_last_(detail::make_view_end(r))
7192         {}
7193 
7194         template<
7195             typename Iter,
7196             typename Sentinel,
7197             typename Context,
7198             typename SkipParser>
7199         std::string call(
7200             Iter & first,
7201             Sentinel last,
7202             Context const & context,
7203             SkipParser const & skip,
7204             detail::flags flags,
7205             bool & success) const
7206         {
7207             std::string retval;
7208             call(first, last, context, skip, flags, success, retval);
7209             return retval;
7210         }
7211 
7212         template<
7213             typename Iter,
7214             typename Sentinel,
7215             typename Context,
7216             typename SkipParser,
7217             typename Attribute>
7218         void call(
7219             Iter & first,
7220             Sentinel last,
7221             Context const & context,
7222             SkipParser const & skip,
7223             detail::flags flags,
7224             bool & success,
7225             Attribute & retval) const
7226         {
7227             [[maybe_unused]] auto _ = detail::scoped_trace(
7228                 *this, first, last, context, flags, retval);
7229 
7230             if (first == last) {
7231                 success = false;
7232                 return;
7233             }
7234 
7235             if constexpr (std::is_same_v<
7236                               detail::remove_cv_ref_t<decltype(*first)>,
7237                               char32_t>) {
7238                 auto const cps =
7239                     BOOST_PARSER_SUBRANGE(expected_first_, expected_last_) |
7240                     detail::text::as_utf32;
7241 
7242                 auto const mismatch = detail::no_case_aware_string_mismatch(
7243                     first,
7244                     last,
7245                     cps.begin(),
7246                     cps.end(),
7247                     context.no_case_depth_);
7248                 if (mismatch.second != cps.end()) {
7249                     success = false;
7250                     return;
7251                 }
7252 
7253                 detail::append(
7254                     retval, first, mismatch.first, detail::gen_attrs(flags));
7255 
7256                 first = mismatch.first;
7257             } else {
7258                 auto const mismatch = detail::no_case_aware_string_mismatch(
7259                     first,
7260                     last,
7261                     expected_first_,
7262                     expected_last_,
7263                     context.no_case_depth_);
7264                 if (mismatch.second != expected_last_) {
7265                     success = false;
7266                     return;
7267                 }
7268 
7269                 detail::append(
7270                     retval, first, mismatch.first, detail::gen_attrs(flags));
7271 
7272                 first = mismatch.first;
7273             }
7274         }
7275 
7276         StrIter expected_first_;
7277         StrSentinel expected_last_;
7278     };
7279 
7280 #if BOOST_PARSER_USE_CONCEPTS
7281     template<parsable_range_like R>
7282 #else
7283     template<typename R>
7284 #endif
7285     string_parser(R r) -> string_parser<
7286         decltype(detail::make_view_begin(r)),
7287         decltype(detail::make_view_end(r))>;
7288 
7289 #endif
7290 
7291     /** Returns a parser that matches `str` that produces the matched string
7292         as its attribute. */
7293 #if BOOST_PARSER_USE_CONCEPTS
7294     template<parsable_range_like R>
7295 #else
7296     template<typename R>
7297 #endif
7298     constexpr auto string(R && str) noexcept
7299     {
7300         return parser_interface{string_parser(str)};
7301     }
7302 
7303     template<typename Quotes, typename Escapes, typename CharParser>
7304     struct quoted_string_parser
7305     {
7306         constexpr quoted_string_parser() : chs_(), ch_('"') {}
7307 
7308 #if BOOST_PARSER_USE_CONCEPTS
7309         template<parsable_range_like R>
7310 #else
7311         template<
7312             typename R,
7313             typename Enable =
7314                 std::enable_if_t<detail::is_parsable_range_like_v<R>>>
7315 #endif
7316         constexpr quoted_string_parser(
7317             R && r,
7318             parser_interface<CharParser> char_p =
7319                 parser_interface{CharParser()}) :
7320             chs_((R &&)r), char_p_(char_p), ch_(0)
7321         {
7322             BOOST_PARSER_DEBUG_ASSERT(r.begin() != r.end());
7323         }
7324 
7325 #if BOOST_PARSER_USE_CONCEPTS
7326         template<parsable_range_like R>
7327 #else
7328         template<
7329             typename R,
7330             typename Enable =
7331                 std::enable_if_t<detail::is_parsable_range_like_v<R>>>
7332 #endif
7333         constexpr quoted_string_parser(
7334             R && r,
7335             Escapes escapes,
7336             parser_interface<CharParser> char_p =
7337                 parser_interface{CharParser()}) :
7338             chs_((R &&)r), escapes_(escapes), char_p_(char_p), ch_(0)
7339         {
7340             BOOST_PARSER_DEBUG_ASSERT(r.begin() != r.end());
7341         }
7342 
7343         constexpr quoted_string_parser(
7344             char32_t cp,
7345             parser_interface<CharParser> char_p =
7346                 parser_interface{CharParser()}) :
7347             chs_(), char_p_(char_p), ch_(cp)
7348         {}
7349 
7350         constexpr quoted_string_parser(
7351             char32_t cp,
7352             Escapes escapes,
7353             parser_interface<CharParser> char_p =
7354                 parser_interface{CharParser()}) :
7355             chs_(), escapes_(escapes), char_p_(char_p), ch_(cp)
7356         {}
7357 
7358         template<
7359             typename Iter,
7360             typename Sentinel,
7361             typename Context,
7362             typename SkipParser>
7363         std::string call(
7364             Iter & first,
7365             Sentinel last,
7366             Context const & context,
7367             SkipParser const & skip,
7368             detail::flags flags,
7369             bool & success) const
7370         {
7371             std::string retval;
7372             call(first, last, context, skip, flags, success, retval);
7373             return retval;
7374         }
7375 
7376         template<
7377             typename Iter,
7378             typename Sentinel,
7379             typename Context,
7380             typename SkipParser,
7381             typename Attribute>
7382         void call(
7383             Iter & first,
7384             Sentinel last,
7385             Context const & context,
7386             SkipParser const & skip,
7387             detail::flags flags,
7388             bool & success,
7389             Attribute & retval) const
7390         {
7391             [[maybe_unused]] auto _ = detail::scoped_trace(
7392                 *this, first, last, context, flags, retval);
7393 
7394             if (first == last) {
7395                 success = false;
7396                 return;
7397             }
7398 
7399             auto const prev_first = first;
7400 
7401             auto append = [&retval,
7402                            gen_attrs = detail::gen_attrs(flags)](auto & ctx) {
7403                 detail::move_back(retval, _attr(ctx), gen_attrs);
7404             };
7405 
7406             auto quote_ch = [&]() {
7407                 if constexpr (detail::is_nope_v<Quotes>) {
7408                     detail::remove_cv_ref_t<decltype(*first)> curr = *first;
7409                     if ((char32_t)curr == ch_)
7410                         ++first;
7411                     else
7412                         success = false;
7413                     return ch_;
7414                 } else {
7415                     detail::remove_cv_ref_t<decltype(*first)> const ch = *first;
7416                     bool found = false;
7417                     if constexpr (std::
7418                                       is_same_v<decltype(ch), char32_t const>) {
7419                         auto r = chs_ | detail::text::as_utf32;
7420                         found = detail::text::find(r.begin(), r.end(), ch) !=
7421                                 r.end();
7422                     } else {
7423                         found = detail::text::find(
7424                                     chs_.begin(), chs_.end(), ch) != chs_.end();
7425                     }
7426                     if (found)
7427                         ++first;
7428                     else
7429                         success = false;
7430                     return ch;
7431                 }
7432             };
7433 
7434             auto const ch = quote_ch();
7435             if (!success)
7436                 return;
7437 
7438             decltype(ch) const backslash_and_delim[] = {'\\', ch};
7439             auto const back_delim = char_(backslash_and_delim);
7440 
7441             auto make_parser = [&]() {
7442                 if constexpr (detail::is_nope_v<Escapes>) {
7443                     return *((lit('\\') >> back_delim) |
7444                              (char_p_ - back_delim))[append] > ch;
7445                 } else {
7446                     return *((lit('\\') >> back_delim)[append] |
7447                              (lit('\\') >> parser_interface(escapes_))[append] |
7448                              (char_p_ - back_delim)[append]) > ch;
7449                 }
7450             };
7451 
7452             auto const p = make_parser();
7453             p.parser_.call(
7454                 first,
7455                 last,
7456                 context,
7457                 skip,
7458                 detail::disable_skip(flags),
7459                 success);
7460 
7461             if (!success) {
7462                 retval = Attribute();
7463                 first = prev_first;
7464             }
7465         }
7466 
7467         /** Returns a `parser_interface` containing a `quoted_string_parser`
7468             that uses `x` as its quotation marks. */
7469 #if BOOST_PARSER_USE_CONCEPTS
7470         template<typename T, typename Parser = char_parser<detail::nope>>
7471             requires(!parsable_range_like<T>)
7472 #else
7473         template<
7474             typename T,
7475             typename Parser = char_parser<detail::nope>,
7476             typename Enable =
7477                 std::enable_if_t<!detail::is_parsable_range_like_v<T>>>
7478 #endif
7479         constexpr auto
7480         operator()(T x, parser_interface<Parser> char_p = char_) const noexcept
7481         {
7482             if constexpr (!detail::is_nope_v<Quotes>) {
7483                 BOOST_PARSER_ASSERT(
7484                     (chs_.empty() && ch_ == '"' &&
7485                      "If you're seeing this, you tried to chain calls on "
7486                      "quoted_string, like 'quoted_string('\"')('\\'')'.  Quit "
7487                      "it!'"));
7488             }
7489             return parser_interface(
7490                 quoted_string_parser<detail::nope, detail::nope, Parser>(
7491                     std::move(x), char_p));
7492         }
7493 
7494         /** Returns a `parser_interface` containing a `quoted_string_parser`
7495             that accepts any of the values in `r` as its quotation marks.  If
7496             the input being matched during the parse is a a sequence of
7497             `char32_t`, the elements of `r` are transcoded from their presumed
7498             encoding to UTF-32 during the comparison.  Otherwise, the
7499             character begin matched is directly compared to the elements of
7500             `r`. */
7501 #if BOOST_PARSER_USE_CONCEPTS
7502         template<
7503             parsable_range_like R,
7504             typename Parser = char_parser<detail::nope>>
7505 #else
7506         template<
7507             typename R,
7508             typename Parser = char_parser<detail::nope>,
7509             typename Enable =
7510                 std::enable_if_t<detail::is_parsable_range_like_v<R>>>
7511 #endif
7512         constexpr auto operator()(
7513             R && r, parser_interface<Parser> char_p = char_) const noexcept
7514         {
7515             BOOST_PARSER_ASSERT(((
7516                 !std::is_rvalue_reference_v<R &&> ||
7517                 !detail::is_range<detail::remove_cv_ref_t<
7518                     R>>)&&"It looks like you tried to pass an rvalue range to "
7519                           "quoted_string().  Don't do that, or you'll end up "
7520                           "with dangling references."));
7521             if constexpr (!detail::is_nope_v<Quotes>) {
7522                 BOOST_PARSER_ASSERT(
7523                     (chs_.empty() && ch_ == '"' &&
7524                      "If you're seeing this, you tried to chain calls on "
7525                      "quoted_string, like "
7526                      "'quoted_string(char-range)(char-range)'.  Quit it!'"));
7527             }
7528             return parser_interface(
7529                 quoted_string_parser<
7530                     decltype(BOOST_PARSER_SUBRANGE(
7531                         detail::make_view_begin(r), detail::make_view_end(r))),
7532                     detail::nope,
7533                     Parser>(
7534                     BOOST_PARSER_SUBRANGE(
7535                         detail::make_view_begin(r), detail::make_view_end(r)),
7536                     char_p));
7537         }
7538 
7539         /** Returns a `parser_interface` containing a `quoted_string_parser`
7540             that uses `x` as its quotation marks.  `symbols` provides a list
7541             of strings that may appear after a backslash to form an escape
7542             sequence, and what character(s) each escape sequence represents.
7543             Note that `"\\"` and `"\ch"` are always valid escape sequences. */
7544 #if BOOST_PARSER_USE_CONCEPTS
7545         template<
7546             typename T,
7547             typename U,
7548             typename Parser = char_parser<detail::nope>>
7549             requires(!parsable_range_like<T>)
7550 #else
7551         template<
7552             typename T,
7553             typename U,
7554             typename Parser = char_parser<detail::nope>,
7555             typename Enable =
7556                 std::enable_if_t<!detail::is_parsable_range_like_v<T>>>
7557 #endif
7558         auto operator()(
7559             T x,
7560             symbols<U> const & escapes,
7561             parser_interface<Parser> char_p = char_) const noexcept
7562         {
7563             if constexpr (!detail::is_nope_v<Quotes>) {
7564                 BOOST_PARSER_ASSERT(
7565                     (chs_.empty() && ch_ == '"' &&
7566                      "If you're seeing this, you tried to chain calls on "
7567                      "quoted_string, like 'quoted_string('\"')('\\'')'.  Quit "
7568                      "it!'"));
7569             }
7570             auto symbols = symbol_parser(escapes.parser_);
7571             auto parser =
7572                 quoted_string_parser<detail::nope, decltype(symbols), Parser>(
7573                     char32_t(x), symbols, char_p);
7574             return parser_interface(parser);
7575         }
7576 
7577         /** Returns a `parser_interface` containing a `quoted_string_parser`
7578             that accepts any of the values in `r` as its quotation marks.  If
7579             the input being matched during the parse is a a sequence of
7580             `char32_t`, the elements of `r` are transcoded from their presumed
7581             encoding to UTF-32 during the comparison.  Otherwise, the
7582             character begin matched is directly compared to the elements of
7583             `r`.  `symbols` provides a list of strings that may appear after a
7584             backslash to form an escape sequence, and what character(s) each
7585             escape sequence represents.  Note that `"\\"` and `"\ch"` are
7586             always valid escape sequences. */
7587 #if BOOST_PARSER_USE_CONCEPTS
7588         template<
7589             parsable_range_like R,
7590             typename T,
7591             typename Parser = char_parser<detail::nope>>
7592 #else
7593         template<
7594             typename R,
7595             typename T,
7596             typename Parser = char_parser<detail::nope>,
7597             typename Enable =
7598                 std::enable_if_t<detail::is_parsable_range_like_v<R>>>
7599 #endif
7600         auto operator()(
7601             R && r,
7602             symbols<T> const & escapes,
7603             parser_interface<Parser> char_p = char_) const noexcept
7604         {
7605             BOOST_PARSER_ASSERT(((
7606                 !std::is_rvalue_reference_v<R &&> ||
7607                 !detail::is_range<detail::remove_cv_ref_t<
7608                     R>>)&&"It looks like you tried to pass an rvalue range to "
7609                           "quoted_string().  Don't do that, or you'll end up "
7610                           "with dangling references."));
7611             if constexpr (!detail::is_nope_v<Quotes>) {
7612                 BOOST_PARSER_ASSERT(
7613                     (chs_.empty() && ch_ == '"' &&
7614                      "If you're seeing this, you tried to chain calls on "
7615                      "quoted_string, like "
7616                      "'quoted_string(char-range)(char-range)'.  Quit it!'"));
7617             }
7618             auto symbols = symbol_parser(escapes.parser_);
7619             auto quotes = BOOST_PARSER_SUBRANGE(
7620                 detail::make_view_begin(r), detail::make_view_end(r));
7621             auto parser = quoted_string_parser<
7622                 decltype(quotes),
7623                 decltype(symbols),
7624                 Parser>(quotes, symbols, char_p);
7625             return parser_interface(parser);
7626         }
7627 
7628         Quotes chs_;
7629         Escapes escapes_;
7630         parser_interface<CharParser> char_p_;
7631         char32_t ch_;
7632     };
7633 
7634     /** Parses a string delimited by quotation marks.  This parser can be used
7635         to create parsers that accept one or more specific quotation mark
7636         characters.  By default, the quotation marks are `'"'`; an alternate
7637         quotation mark can be specified by calling this parser with a single
7638         character, or a range of characters.  If a range is specified, the
7639         opening quote must be one of the characters specified, and the closing
7640         quote must match the opening quote.  Quotation marks may appear within
7641         the string if escaped with a backslash, and a pair of backslashes is
7642         treated as a single escaped backslash; all other backslashes cause the
7643         parse to fail, unless a symbol table is in use.  A symbol table can be
7644         provided as a second parameter after the single character or range
7645         described above.  The symbol table is used to recognize escape
7646         sequences.  Each escape sequence is a backslash followed by a value in
7647         the symbol table.  When using a symbol table, any backslash that is
7648         not followed by another backslash, the opening quote character, or a
7649         symbol from the symbol table will cause the parse to fail.  Skipping
7650         is disabled during parsing of the entire quoted string, including the
7651         quotation marks.  There is an expectation point before the closing
7652         quotation mark.  Produces a `std::string` attribute. */
7653     inline constexpr parser_interface<quoted_string_parser<>> quoted_string;
7654 
7655     /** Returns a parser that matches `str` that produces no attribute. */
7656 #if BOOST_PARSER_USE_CONCEPTS
7657     template<parsable_range_like R>
7658 #else
7659     template<typename R>
7660 #endif
7661     constexpr auto lit(R && str) noexcept
7662     {
7663         return omit[parser::string(str)];
7664     }
7665 
7666 #ifndef BOOST_PARSER_DOXYGEN
7667 
7668     template<bool NewlinesOnly, bool NoNewlines>
7669     struct ws_parser
7670     {
7671         constexpr ws_parser() {}
7672 
7673         static_assert(!NewlinesOnly || !NoNewlines);
7674 
7675         template<
7676             typename Iter,
7677             typename Sentinel,
7678             typename Context,
7679             typename SkipParser>
7680         detail::nope call(
7681             Iter & first,
7682             Sentinel last,
7683             Context const & context,
7684             SkipParser const & skip,
7685             detail::flags flags,
7686             bool & success) const
7687         {
7688             detail::nope nope;
7689             call(first, last, context, skip, flags, success, nope);
7690             return {};
7691         }
7692 
7693         template<
7694             typename Iter,
7695             typename Sentinel,
7696             typename Context,
7697             typename SkipParser,
7698             typename Attribute>
7699         void call(
7700             Iter & first,
7701             Sentinel last,
7702             Context const & context,
7703             SkipParser const & skip,
7704             detail::flags flags,
7705             bool & success,
7706             Attribute & retval) const
7707         {
7708             [[maybe_unused]] auto _ = detail::scoped_trace(
7709                 *this, first, last, context, flags, retval);
7710 
7711             if (first == last) {
7712                 success = false;
7713                 return;
7714             }
7715             int const x = *first;
7716             if constexpr (NewlinesOnly) {
7717                 if (x == 0x000a) { // lf
7718                     ++first;
7719                     return;
7720                 }
7721                 if (x == 0x000d) { // cr
7722                     ++first;
7723                     if (first != last && *first == 0x000a) // lf
7724                         ++first;
7725                     return;
7726                 }
7727                 if (0x000b == x || x == 0x000c || x == 0x0085 || x == 0x2028 ||
7728                     x == 0x2029) {
7729                     ++first;
7730                     return;
7731                 }
7732                 success = false;
7733             } else if constexpr (NoNewlines) {
7734                 if (x == 0x0020) { // space
7735                     ++first;
7736                     return;
7737                 }
7738                 if (x == 0x0009) { // tab
7739                     ++first;
7740                     return;
7741                 }
7742                 if (x == 0x00a0 || x == 0x1680 ||
7743                     (0x2000 <= x && x <= 0x200a) || x == 0x202F ||
7744                     x == 0x205F || x == 0x3000) {
7745                     ++first;
7746                     return;
7747                 }
7748                 success = false;
7749             } else {
7750                 if (x == 0x0020 || x == 0x000a) { // space, lf
7751                     ++first;
7752                     return;
7753                 }
7754                 if (x == 0x000d) { // cr
7755                     ++first;
7756                     if (first != last && *first == 0x000a) // lf
7757                         ++first;
7758                     return;
7759                 }
7760                 if (0x0009 <= x && x <= 0x000c) { // tab through cr
7761                     ++first;
7762                     return;
7763                 }
7764                 if (x == 0x0085 || x == 0x00a0 || x == 0x1680 ||
7765                     (0x2000 <= x && x <= 0x200a) || x == 0x2028 ||
7766                     x == 0x2029 || x == 0x202F || x == 0x205F || x == 0x3000) {
7767                     ++first;
7768                     return;
7769                 }
7770                 success = false;
7771             }
7772         }
7773     };
7774 
7775 #endif
7776 
7777     /** The end-of-line parser.  This matches "\r\n", or any one of the line
7778         break code points from the Unicode Line Break Algorithm, described in
7779         https://unicode.org/reports/tr14.  Produces no attribute. */
7780     inline constexpr parser_interface<ws_parser<true, false>> eol;
7781 
7782     /** The whitespace parser.  This matches "\r\n", or any one of the Unicode
7783         code points with the White_Space property, as defined in
7784         https://www.unicode.org/Public/UCD/latest/ucd/PropList.txt.  Produces
7785         no attribute. */
7786     inline constexpr parser_interface<ws_parser<false, false>> ws;
7787 
7788     /** The whitespace parser that does not match end-of-line.  This matches
7789         any one of the Unicode code points with the White_Space property, as
7790         defined in https://www.unicode.org/Public/UCD/latest/ucd/PropList.txt,
7791         except for the ones matched by `eol`.  Produces no attribute. */
7792     inline constexpr parser_interface<ws_parser<false, true>> blank;
7793 
7794     /** The decimal digit parser.  Matches the full set of Unicode decimal
7795         digits; in other words, all Unicode code points with the "Nd"
7796         character property.  Note that this covers all Unicode scripts, only a
7797         few of which are Latin. */
7798     inline constexpr parser_interface<digit_parser> digit;
7799 
7800     /** The hexidecimal digit parser.  Matches the full set of Unicode
7801         hexidecimal digits (upper or lower case); in other words, all Unicode
7802         code points with the "Hex_Digit" character property. */
7803     inline constexpr parser_interface<
7804         char_subrange_parser<detail::hex_digit_subranges>>
7805         hex_digit;
7806 
7807     /** The control character parser.  Matches the all Unicode code points
7808         with the "Cc" ("control character") character property. */
7809     inline constexpr parser_interface<
7810         char_subrange_parser<detail::control_subranges>>
7811         control;
7812 
7813     /** The punctuation character parser.  Matches the full set of Unicode
7814         punctuation classes (specifically, "Pc", "Pd", "Pe", "Pf", "Pi", "Ps",
7815         and "Po"). */
7816     inline BOOST_PARSER_ALGO_CONSTEXPR
7817         parser_interface<char_set_parser<detail::punct_chars>>
7818             punct;
7819 
7820     /** The symbol character parser.  Matches the full set of Unicode
7821         symbol classes (specifically, "Sc", "Sk", "Sm", and "So"). */
7822     inline BOOST_PARSER_ALGO_CONSTEXPR
7823         parser_interface<char_set_parser<detail::symb_chars>>
7824             symb;
7825 
7826     /** The lower case character parser.  Matches the full set of Unicode
7827         lower case code points (class "Ll"). */
7828     inline BOOST_PARSER_ALGO_CONSTEXPR
7829         parser_interface<char_set_parser<detail::lower_case_chars>>
7830             lower;
7831 
7832     /** The lower case character parser.  Matches the full set of Unicode
7833         lower case code points (class "Lu"). */
7834     inline BOOST_PARSER_ALGO_CONSTEXPR
7835         parser_interface<char_set_parser<detail::upper_case_chars>>
7836             upper;
7837 
7838 #ifndef BOOST_PARSER_DOXYGEN
7839 
7840     struct bool_parser
7841     {
7842         template<
7843             typename Iter,
7844             typename Sentinel,
7845             typename Context,
7846             typename SkipParser>
7847         bool call(
7848             Iter & first,
7849             Sentinel last,
7850             Context const & context,
7851             SkipParser const & skip,
7852             detail::flags flags,
7853             bool & success) const
7854         {
7855             bool retval{};
7856             call(first, last, context, skip, flags, success, retval);
7857             return retval;
7858         }
7859 
7860         template<
7861             typename Iter,
7862             typename Sentinel,
7863             typename Context,
7864             typename SkipParser,
7865             typename Attribute>
7866         void call(
7867             Iter & first,
7868             Sentinel last,
7869             Context const & context,
7870             SkipParser const & skip,
7871             detail::flags flags,
7872             bool & success,
7873             Attribute & retval) const
7874         {
7875             [[maybe_unused]] auto _ = detail::scoped_trace(
7876                 *this, first, last, context, flags, retval);
7877 
7878             auto compare =
7879                 [no_case = context.no_case_depth_](char32_t a, char32_t b) {
7880                     if (no_case && 0x41 <= b && b < 0x5b)
7881                         b += 0x20;
7882                     return a == b;
7883                 };
7884 
7885             // The lambda quiets a signed/unsigned mismatch warning when
7886             // comparing the chars here to code points.
7887             char const t[] = "true";
7888             if (detail::mismatch(t, t + 4, first, last, compare).first ==
7889                 t + 4) {
7890                 std::advance(first, 4);
7891                 detail::assign(retval, true);
7892                 return;
7893             }
7894             char const f[] = "false";
7895             if (detail::mismatch(f, f + 5, first, last, compare).first ==
7896                 f + 5) {
7897                 std::advance(first, 5);
7898                 detail::assign(retval, false);
7899                 return;
7900             }
7901             success = false;
7902         }
7903     };
7904 
7905 #endif
7906 
7907     /** The Boolean parser.  Parses "true" and "false", producing attributes
7908         `true` and `false`, respectively, and fails on any other input. */
7909     inline constexpr parser_interface<bool_parser> bool_;
7910 
7911 #ifndef BOOST_PARSER_DOXYGEN
7912 
7913     template<
7914         typename T,
7915         int Radix,
7916         int MinDigits,
7917         int MaxDigits,
7918         typename Expected>
7919     struct uint_parser
7920     {
7921         static_assert(2 <= Radix && Radix <= 36, "Unsupported radix.");
7922 
7923         constexpr uint_parser() {}
7924         explicit constexpr uint_parser(Expected expected) : expected_(expected)
7925         {}
7926 
7927         template<
7928             typename Iter,
7929             typename Sentinel,
7930             typename Context,
7931             typename SkipParser>
7932         T call(
7933             Iter & first,
7934             Sentinel last,
7935             Context const & context,
7936             SkipParser const & skip,
7937             detail::flags flags,
7938             bool & success) const
7939         {
7940             T retval{};
7941             call(first, last, context, skip, flags, success, retval);
7942             return retval;
7943         }
7944 
7945         template<
7946             typename Iter,
7947             typename Sentinel,
7948             typename Context,
7949             typename SkipParser,
7950             typename Attribute>
7951         void call(
7952             Iter & first,
7953             Sentinel last,
7954             Context const & context,
7955             SkipParser const & skip,
7956             detail::flags flags,
7957             bool & success,
7958             Attribute & retval) const
7959         {
7960             [[maybe_unused]] auto _ = detail::scoped_trace(
7961                 *this, first, last, context, flags, retval);
7962             T attr = 0;
7963             auto const initial = first;
7964             success =
7965                 detail::numeric::parse_int<false, Radix, MinDigits, MaxDigits>(
7966                     first, last, attr);
7967             if (first == initial || attr != detail::resolve(context, expected_))
7968                 success = false;
7969             if (success)
7970                 detail::assign(retval, attr);
7971         }
7972 
7973         /** Returns a `parser_interface` containing a `uint_parser` that
7974             matches the exact value `expected`. */
7975         template<typename Expected2>
7976         constexpr auto operator()(Expected2 expected) const noexcept
7977         {
7978             BOOST_PARSER_ASSERT(
7979                 (detail::is_nope_v<Expected> &&
7980                  "If you're seeing this, you tried to chain calls on this "
7981                  "parser, like 'uint_(2)(3)'.  Quit it!'"));
7982             using parser_t =
7983                 uint_parser<T, Radix, MinDigits, MaxDigits, Expected2>;
7984             return parser_interface{parser_t{expected}};
7985         }
7986 
7987         Expected expected_;
7988     };
7989 
7990 #endif
7991 
7992     /** The binary unsigned integer parser.  Produces an `unsigned int`
7993         attribute.  To parse a particular value `x`, use `bin(x)`. */
7994     inline constexpr parser_interface<uint_parser<unsigned int, 2>> bin;
7995 
7996     /** The octal unsigned integer parser.  Produces an `unsigned int`
7997         attribute.  To parse a particular value `x`, use `oct(x)`. */
7998     inline constexpr parser_interface<uint_parser<unsigned int, 8>> oct;
7999 
8000     /** The hexadecimal unsigned integer parser.  Produces an `unsigned int`
8001         attribute.  To parse a particular value `x`, use `hex(x)`. */
8002     inline constexpr parser_interface<uint_parser<unsigned int, 16>> hex;
8003 
8004     /** The `unsigned short` parser.  Produces an `unsigned short` attribute.
8005         To parse a particular value `x`, use `ushort_(x)`. */
8006     inline constexpr parser_interface<uint_parser<unsigned short>> ushort_;
8007 
8008     /** The `unsigned int` parser.  Produces an `unsigned int` attribute.  To
8009         parse a particular value `x`, use `uint_(x)`. */
8010     inline constexpr parser_interface<uint_parser<unsigned int>> uint_;
8011 
8012     /** The `unsigned long` parser.  Produces an `unsigned long` attribute.
8013         To parse a particular value `x`, use `ulong_(x)`. */
8014     inline constexpr parser_interface<uint_parser<unsigned long>> ulong_;
8015 
8016     /** The `unsigned long long` parser.  Produces an `unsigned long long`
8017         attribute.  To parse a particular value `x`, use `ulong_long(x)`. */
8018     inline constexpr parser_interface<uint_parser<unsigned long long>>
8019         ulong_long;
8020 
8021 #ifndef BOOST_PARSER_DOXYGEN
8022 
8023     template<
8024         typename T,
8025         int Radix,
8026         int MinDigits,
8027         int MaxDigits,
8028         typename Expected>
8029     struct int_parser
8030     {
8031         static_assert(
8032             Radix == 2 || Radix == 8 || Radix == 10 || Radix == 16,
8033             "Unsupported radix.");
8034 
8035         constexpr int_parser() {}
8036         explicit constexpr int_parser(Expected expected) : expected_(expected)
8037         {}
8038 
8039         template<
8040             typename Iter,
8041             typename Sentinel,
8042             typename Context,
8043             typename SkipParser>
8044         T call(
8045             Iter & first,
8046             Sentinel last,
8047             Context const & context,
8048             SkipParser const & skip,
8049             detail::flags flags,
8050             bool & success) const
8051         {
8052             T retval{};
8053             call(first, last, context, skip, flags, success, retval);
8054             return retval;
8055         }
8056 
8057         template<
8058             typename Iter,
8059             typename Sentinel,
8060             typename Context,
8061             typename SkipParser,
8062             typename Attribute>
8063         void call(
8064             Iter & first,
8065             Sentinel last,
8066             Context const & context,
8067             SkipParser const & skip,
8068             detail::flags flags,
8069             bool & success,
8070             Attribute & retval) const
8071         {
8072             [[maybe_unused]] auto _ = detail::scoped_trace(
8073                 *this, first, last, context, flags, retval);
8074             T attr = 0;
8075             auto const initial = first;
8076             success =
8077                 detail::numeric::parse_int<true, Radix, MinDigits, MaxDigits>(
8078                     first, last, attr);
8079             if (first == initial || attr != detail::resolve(context, expected_))
8080                 success = false;
8081             if (success)
8082                 detail::assign(retval, attr);
8083         }
8084 
8085         /** Returns a `parser_interface` containing an `int_parser` that
8086             matches the exact value `expected`. */
8087         template<typename Expected2>
8088         constexpr auto operator()(Expected2 expected) const noexcept
8089         {
8090             BOOST_PARSER_ASSERT(
8091                 (detail::is_nope_v<Expected> &&
8092                  "If you're seeing this, you tried to chain calls on this "
8093                  "parser, like 'int_(2)(3)'.  Quit it!'"));
8094             using parser_t =
8095                 int_parser<T, Radix, MinDigits, MaxDigits, Expected2>;
8096             return parser_interface{parser_t{expected}};
8097         }
8098 
8099         Expected expected_;
8100     };
8101 
8102 #endif
8103 
8104     /** The `short` parser.  Produces a `short` attribute.  To parse a
8105         particular value `x`, use `short_(x)`. */
8106     inline constexpr parser_interface<int_parser<short>> short_;
8107 
8108     /** The `int` parser.  Produces an `int` attribute.  To parse a particular
8109         value `x`, use `int_(x)`. */
8110     inline constexpr parser_interface<int_parser<int>> int_;
8111 
8112     /** The `long` parser.  Produces a `long` attribute.  To parse a particular
8113         value `x`, use `long_(x)`. */
8114     inline constexpr parser_interface<int_parser<long>> long_;
8115 
8116     /** The `long long` parser.  Produces a `long long` attribute.  To parse a
8117         particular value `x`, use `long_long(x)`. */
8118     inline constexpr parser_interface<int_parser<long long>> long_long;
8119 
8120 #ifndef BOOST_PARSER_DOXYGEN
8121 
8122     template<typename T>
8123     struct float_parser
8124     {
8125         constexpr float_parser() {}
8126 
8127         template<
8128             typename Iter,
8129             typename Sentinel,
8130             typename Context,
8131             typename SkipParser>
8132         T call(
8133             Iter & first,
8134             Sentinel last,
8135             Context const & context,
8136             SkipParser const & skip,
8137             detail::flags flags,
8138             bool & success) const
8139         {
8140             T retval = 0;
8141             call(first, last, context, skip, flags, success, retval);
8142             return retval;
8143         }
8144 
8145         template<
8146             typename Iter,
8147             typename Sentinel,
8148             typename Context,
8149             typename SkipParser,
8150             typename Attribute>
8151         void call(
8152             Iter & first,
8153             Sentinel last,
8154             Context const & context,
8155             SkipParser const & skip,
8156             detail::flags flags,
8157             bool & success,
8158             Attribute & retval) const
8159         {
8160             [[maybe_unused]] auto _ = detail::scoped_trace(
8161                 *this, first, last, context, flags, retval);
8162             T attr = 0;
8163             auto const initial = first;
8164             success = detail::numeric::parse_real(first, last, attr);
8165             if (first == initial)
8166                 success = false;
8167             if (success)
8168                 detail::assign(retval, attr);
8169         }
8170     };
8171 
8172 #endif
8173 
8174     /** The `float` parser.  Produces a `float` attribute. */
8175     inline constexpr parser_interface<float_parser<float>> float_;
8176 
8177     /** The `double` parser.  Produces a `double` attribute. */
8178     inline constexpr parser_interface<float_parser<double>> double_;
8179 
8180 
8181     /** Represents a sequence parser, the first parser of which is an
8182         `epsilon_parser` with predicate, as a directive
8183         (e.g. `if_(pred)[p]`). */
8184     template<typename Predicate>
8185     struct if_directive
8186     {
8187         template<typename Parser2>
8188         constexpr auto operator[](parser_interface<Parser2> rhs) const noexcept
8189         {
8190             return eps(pred_) >> rhs;
8191         }
8192 
8193         Predicate pred_;
8194     };
8195 
8196     /** Returns an `if_directive` that fails if the given predicate `pred` is
8197         `false`, and otherwise, applies another parser.  For instance, in
8198         `if_(pred)[p]`, `p` is only applied if `pred` is true. */
8199     template<typename Predicate>
8200     constexpr auto if_(Predicate pred) noexcept
8201     {
8202         return if_directive<Predicate>{pred};
8203     }
8204 
8205     namespace detail {
8206         template<typename SwitchValue, typename Value>
8207         struct switch_parser_equal
8208         {
8209             template<typename Context>
8210             bool operator()(Context & context) const
8211             {
8212                 auto const switch_value =
8213                     detail::resolve(context, switch_value_);
8214                 auto const value = detail::resolve(context, value_);
8215                 return value == switch_value;
8216             }
8217             SwitchValue switch_value_;
8218             Value value_;
8219         };
8220     }
8221 
8222 #ifndef BOOST_PARSER_DOXYGEN
8223 
8224     template<typename SwitchValue, typename OrParser>
8225     struct switch_parser
8226     {
8227         switch_parser() {}
8228         switch_parser(SwitchValue switch_value) : switch_value_(switch_value) {}
8229         switch_parser(SwitchValue switch_value, OrParser or_parser) :
8230             switch_value_(switch_value), or_parser_(or_parser)
8231         {}
8232 
8233         template<
8234             typename Iter,
8235             typename Sentinel,
8236             typename Context,
8237             typename SkipParser>
8238         auto call(
8239             Iter & first,
8240             Sentinel last,
8241             Context const & context,
8242             SkipParser const & skip,
8243             detail::flags flags,
8244             bool & success) const
8245         {
8246             BOOST_PARSER_ASSERT(
8247                 (!detail::is_nope_v<OrParser> &&
8248                  "It looks like you tried to write switch_(val).  You need at "
8249                  "least one alternative, like: switch_(val)(value_1, "
8250                  "parser_1)(value_2, parser_2)..."));
8251             using attr_t = decltype(or_parser_.call(
8252                 first, last, context, skip, flags, success));
8253             attr_t attr{};
8254             [[maybe_unused]] auto _ =
8255                 detail::scoped_trace(*this, first, last, context, flags, attr);
8256             attr = or_parser_.call(first, last, context, skip, flags, success);
8257             return attr;
8258         }
8259 
8260         template<
8261             typename Iter,
8262             typename Sentinel,
8263             typename Context,
8264             typename SkipParser,
8265             typename Attribute>
8266         void call(
8267             Iter & first,
8268             Sentinel last,
8269             Context const & context,
8270             SkipParser const & skip,
8271             detail::flags flags,
8272             bool & success,
8273             Attribute & retval) const
8274         {
8275             BOOST_PARSER_ASSERT(
8276                 (!detail::is_nope_v<OrParser> &&
8277                  "It looks like you tried to write switch_(val).  You need at "
8278                  "least one alternative, like: switch_(val)(value_1, "
8279                  "parser_1)(value_2, parser_2)..."));
8280             [[maybe_unused]] auto _ = detail::scoped_trace(
8281                 *this, first, last, context, flags, retval);
8282             or_parser_.call(first, last, context, skip, flags, success, retval);
8283         }
8284 
8285         /** Returns a `parser_interface` containing a `switch_parser`, with
8286             the case `value_`,`rhs` appended to its `or_parser_`. */
8287         template<typename Value, typename Parser2>
8288         constexpr auto
8289         operator()(Value value_, parser_interface<Parser2> rhs) const noexcept
8290         {
8291             auto const match = detail::switch_parser_equal<SwitchValue, Value>{
8292                 switch_value_, value_};
8293             auto or_parser = make_or_parser(or_parser_, eps(match) >> rhs);
8294             using switch_parser_type =
8295                 switch_parser<SwitchValue, decltype(or_parser)>;
8296             return parser_interface{
8297                 switch_parser_type{switch_value_, or_parser}};
8298         }
8299 
8300 #ifndef BOOST_PARSER_DOXYGEN
8301 
8302         template<typename Parser1, typename Parser2>
8303         static constexpr auto
8304         make_or_parser(Parser1 parser1, parser_interface<Parser2> parser2)
8305         {
8306             return (parser_interface{parser1} | parser2).parser_;
8307         }
8308 
8309         template<typename Parser>
8310         static constexpr auto
8311         make_or_parser(detail::nope, parser_interface<Parser> parser)
8312         {
8313             return parser.parser_;
8314         }
8315 
8316 #endif
8317 
8318         SwitchValue switch_value_;
8319         OrParser or_parser_;
8320     };
8321 
8322 #endif
8323 
8324     /** Returns a `switch`-like parser.  The resulting parser uses the given
8325         value `x` to select one of the following value/parser pairs, and to
8326         apply the selected parser.  `x` may be a value to be used directly, or
8327         a unary invocable that takes a reference to the parse context, and
8328         returns the value to use.  You can add more value/parser cases to the
8329         returned parser, using its call operator, e.g. `switch_(x)(y1, p1)(y2,
8330         p2)`.  As with the `x` passed to this function, each `yN` value can be
8331         a value or a unary invocable. */
8332     template<typename T>
8333     constexpr auto switch_(T x) noexcept
8334     {
8335         return switch_parser<T>{x};
8336     }
8337 
8338 
8339 #ifndef BOOST_PARSER_DOXYGEN
8340 
8341     template<typename Parser, typename GlobalState, typename ErrorHandler>
8342     constexpr auto
8343     parser_interface<Parser, GlobalState, ErrorHandler>::operator>>(
8344         char rhs) const noexcept
8345     {
8346         return *this >> parser::lit(rhs);
8347     }
8348 
8349     template<typename Parser, typename GlobalState, typename ErrorHandler>
8350     constexpr auto
8351     parser_interface<Parser, GlobalState, ErrorHandler>::operator>>(
8352         char32_t rhs) const noexcept
8353     {
8354         return *this >> parser::lit(rhs);
8355     }
8356 
8357     template<typename Parser, typename GlobalState, typename ErrorHandler>
8358 #if BOOST_PARSER_USE_CONCEPTS
8359     template<parsable_range_like R>
8360 #else
8361     template<typename R, typename>
8362 #endif
8363     constexpr auto
8364     parser_interface<Parser, GlobalState, ErrorHandler>::operator>>(
8365         R && r) const noexcept
8366     {
8367         return *this >> parser::lit(r);
8368     }
8369 
8370 #endif
8371 
8372     /** Returns a parser equivalent to `lit(c) >> rhs`. */
8373     template<typename Parser>
8374     constexpr auto operator>>(char c, parser_interface<Parser> rhs) noexcept
8375     {
8376         if constexpr (detail::is_seq_p<Parser>{}) {
8377             return rhs.parser_.template prepend<true>(parser::lit(c));
8378         } else {
8379             return parser::lit(c) >> rhs;
8380         }
8381     }
8382 
8383     /** Returns a parser equivalent to `lit(c) >> rhs`. */
8384     template<typename Parser>
8385     constexpr auto operator>>(char32_t c, parser_interface<Parser> rhs) noexcept
8386     {
8387         if constexpr (detail::is_seq_p<Parser>{}) {
8388             return rhs.parser_.template prepend<true>(parser::lit(c));
8389         } else {
8390             return parser::lit(c) >> rhs;
8391         }
8392     }
8393 
8394     /** Returns a parser equivalent to `lit(str) >> rhs`. */
8395 #if BOOST_PARSER_USE_CONCEPTS
8396     template<parsable_range_like R, typename Parser>
8397 #else
8398     template<
8399         typename R,
8400         typename Parser,
8401         typename Enable = std::enable_if_t<detail::is_parsable_range_like_v<R>>>
8402 #endif
8403     constexpr auto operator>>(R && r, parser_interface<Parser> rhs) noexcept
8404     {
8405         if constexpr (detail::is_seq_p<Parser>{}) {
8406             return rhs.parser_.template prepend<true>(parser::lit(r));
8407         } else {
8408             return parser::lit(r) >> rhs;
8409         }
8410     }
8411 
8412 #ifndef BOOST_PARSER_DOXYGEN
8413 
8414     template<typename Parser, typename GlobalState, typename ErrorHandler>
8415     constexpr auto
8416     parser_interface<Parser, GlobalState, ErrorHandler>::operator>(
8417         char rhs) const noexcept
8418     {
8419         return *this > parser::lit(rhs);
8420     }
8421 
8422     template<typename Parser, typename GlobalState, typename ErrorHandler>
8423     constexpr auto
8424     parser_interface<Parser, GlobalState, ErrorHandler>::operator>(
8425         char32_t rhs) const noexcept
8426     {
8427         return *this > parser::lit(rhs);
8428     }
8429 
8430     template<typename Parser, typename GlobalState, typename ErrorHandler>
8431 #if BOOST_PARSER_USE_CONCEPTS
8432     template<parsable_range_like R>
8433 #else
8434     template<typename R, typename>
8435 #endif
8436     constexpr auto
8437     parser_interface<Parser, GlobalState, ErrorHandler>::operator>(
8438         R && r) const noexcept
8439     {
8440         return *this > parser::lit(r);
8441     }
8442 
8443 #endif
8444 
8445     /** Returns a parser equivalent to `lit(c) > rhs`. */
8446     template<typename Parser>
8447     constexpr auto operator>(char c, parser_interface<Parser> rhs) noexcept
8448     {
8449         if constexpr (detail::is_seq_p<Parser>{}) {
8450             return rhs.parser_.template prepend<false>(parser::lit(c));
8451         } else {
8452             return parser::lit(c) > rhs;
8453         }
8454     }
8455 
8456     /** Returns a parser equivalent to `lit(c) > rhs`. */
8457     template<typename Parser>
8458     constexpr auto operator>(char32_t c, parser_interface<Parser> rhs) noexcept
8459     {
8460         if constexpr (detail::is_seq_p<Parser>{}) {
8461             return rhs.parser_.template prepend<false>(parser::lit(c));
8462         } else {
8463             return parser::lit(c) > rhs;
8464         }
8465     }
8466 
8467     /** Returns a parser equivalent to `lit(str) > rhs`. */
8468 #if BOOST_PARSER_USE_CONCEPTS
8469     template<parsable_range_like R, typename Parser>
8470 #else
8471     template<
8472         typename R,
8473         typename Parser,
8474         typename Enable = std::enable_if_t<detail::is_parsable_range_like_v<R>>>
8475 #endif
8476     constexpr auto operator>(R && r, parser_interface<Parser> rhs) noexcept
8477     {
8478         if constexpr (detail::is_seq_p<Parser>{}) {
8479             return rhs.parser_.template prepend<false>(parser::lit(r));
8480         } else {
8481             return parser::lit(r) > rhs;
8482         }
8483     }
8484 
8485 #ifndef BOOST_PARSER_DOXYGEN
8486 
8487     template<typename Parser, typename GlobalState, typename ErrorHandler>
8488     constexpr auto
8489     parser_interface<Parser, GlobalState, ErrorHandler>::operator|(
8490         char rhs) const noexcept
8491     {
8492         return *this | parser::lit(rhs);
8493     }
8494 
8495     template<typename Parser, typename GlobalState, typename ErrorHandler>
8496     constexpr auto
8497     parser_interface<Parser, GlobalState, ErrorHandler>::operator|(
8498         char32_t rhs) const noexcept
8499     {
8500         return *this | parser::lit(rhs);
8501     }
8502 
8503     template<typename Parser, typename GlobalState, typename ErrorHandler>
8504 #if BOOST_PARSER_USE_CONCEPTS
8505     template<parsable_range_like R>
8506 #else
8507     template<typename R, typename>
8508 #endif
8509     constexpr auto
8510     parser_interface<Parser, GlobalState, ErrorHandler>::operator|(
8511         R && r) const noexcept
8512     {
8513         return *this | parser::lit(r);
8514     }
8515 
8516 #endif
8517 
8518     /** Returns a parser equivalent to `lit(c) | rhs`. */
8519     template<typename Parser>
8520     constexpr auto operator|(char c, parser_interface<Parser> rhs) noexcept
8521     {
8522         if constexpr (detail::is_or_p<Parser>{}) {
8523             return rhs.parser_.prepend(parser::lit(c));
8524         } else {
8525             return parser::lit(c) | rhs;
8526         }
8527     }
8528 
8529     /** Returns a parser equivalent to `lit(c) | rhs`. */
8530     template<typename Parser>
8531     constexpr auto operator|(char32_t c, parser_interface<Parser> rhs) noexcept
8532     {
8533         if constexpr (detail::is_or_p<Parser>{}) {
8534             return rhs.parser_.prepend(parser::lit(c));
8535         } else {
8536             return parser::lit(c) | rhs;
8537         }
8538     }
8539 
8540     /** Returns a parser equivalent to `lit(str) | rhs`. */
8541 #if BOOST_PARSER_USE_CONCEPTS
8542     template<parsable_range_like R, typename Parser>
8543 #else
8544     template<
8545         typename R,
8546         typename Parser,
8547         typename Enable = std::enable_if_t<detail::is_parsable_range_like_v<R>>>
8548 #endif
8549     constexpr auto operator|(R && r, parser_interface<Parser> rhs) noexcept
8550     {
8551         if constexpr (detail::is_or_p<Parser>{}) {
8552             return rhs.parser_.prepend(parser::lit(r));
8553         } else {
8554             return parser::lit(r) | rhs;
8555         }
8556     }
8557 
8558 #ifndef BOOST_PARSER_DOXYGEN
8559 
8560     template<typename Parser, typename GlobalState, typename ErrorHandler>
8561     constexpr auto
8562     parser_interface<Parser, GlobalState, ErrorHandler>::operator-(
8563         char rhs) const noexcept
8564     {
8565         return !parser::lit(rhs) >> *this;
8566     }
8567 
8568     template<typename Parser, typename GlobalState, typename ErrorHandler>
8569     constexpr auto
8570     parser_interface<Parser, GlobalState, ErrorHandler>::operator-(
8571         char32_t rhs) const noexcept
8572     {
8573         return !parser::lit(rhs) >> *this;
8574     }
8575 
8576     template<typename Parser, typename GlobalState, typename ErrorHandler>
8577 #if BOOST_PARSER_USE_CONCEPTS
8578     template<parsable_range_like R>
8579 #else
8580     template<typename R, typename>
8581 #endif
8582     constexpr auto
8583     parser_interface<Parser, GlobalState, ErrorHandler>::operator-(
8584         R && r) const noexcept
8585     {
8586         return !parser::lit(r) >> *this;
8587     }
8588 
8589 #endif
8590 
8591     /** Returns a parser equivalent to `!rhs >> lit(c)`. */
8592     template<typename Parser>
8593     constexpr auto operator-(char c, parser_interface<Parser> rhs) noexcept
8594     {
8595         return !rhs >> parser::lit(c);
8596     }
8597 
8598     /** Returns a parser equivalent to `!rhs >> lit(c)`. */
8599     template<typename Parser>
8600     constexpr auto operator-(char32_t c, parser_interface<Parser> rhs) noexcept
8601     {
8602         return !rhs >> parser::lit(c);
8603     }
8604 
8605     /** Returns a parser equivalent to `!rhs >> lit(str)`. */
8606 #if BOOST_PARSER_USE_CONCEPTS
8607     template<parsable_range_like R, typename Parser>
8608 #else
8609     template<
8610         typename R,
8611         typename Parser,
8612         typename Enable = std::enable_if_t<detail::is_parsable_range_like_v<R>>>
8613 #endif
8614     constexpr auto operator-(R && r, parser_interface<Parser> rhs) noexcept
8615     {
8616         return !rhs >> parser::lit(r);
8617     }
8618 
8619 #ifndef BOOST_PARSER_DOXYGEN
8620 
8621     template<typename Parser, typename GlobalState, typename ErrorHandler>
8622     constexpr auto
8623     parser_interface<Parser, GlobalState, ErrorHandler>::operator%(
8624         char rhs) const noexcept
8625     {
8626         return *this % parser::lit(rhs);
8627     }
8628 
8629     template<typename Parser, typename GlobalState, typename ErrorHandler>
8630     constexpr auto
8631     parser_interface<Parser, GlobalState, ErrorHandler>::operator%(
8632         char32_t rhs) const noexcept
8633     {
8634         return *this % parser::lit(rhs);
8635     }
8636 
8637     template<typename Parser, typename GlobalState, typename ErrorHandler>
8638 #if BOOST_PARSER_USE_CONCEPTS
8639     template<parsable_range_like R>
8640 #else
8641     template<typename R, typename>
8642 #endif
8643     constexpr auto
8644     parser_interface<Parser, GlobalState, ErrorHandler>::operator%(
8645         R && r) const noexcept
8646     {
8647         return *this % parser::lit(r);
8648     }
8649 
8650 #endif
8651 
8652     /** Returns a parser equivalent to `lit(c) % rhs`. */
8653     template<typename Parser>
8654     constexpr auto operator%(char c, parser_interface<Parser> rhs) noexcept
8655     {
8656         return parser::lit(c) % rhs;
8657     }
8658 
8659     /** Returns a parser equivalent to `lit(c) % rhs`. */
8660     template<typename Parser>
8661     constexpr auto operator%(char32_t c, parser_interface<Parser> rhs) noexcept
8662     {
8663         return parser::lit(c) % rhs;
8664     }
8665 
8666     /** Returns a parser equivalent to `lit(str) % rhs`. */
8667 #if BOOST_PARSER_USE_CONCEPTS
8668     template<parsable_range_like R, typename Parser>
8669 #else
8670     template<
8671         typename R,
8672         typename Parser,
8673         typename Enable = std::enable_if_t<detail::is_parsable_range_like_v<R>>>
8674 #endif
8675     constexpr auto operator%(R && r, parser_interface<Parser> rhs) noexcept
8676     {
8677         return parser::lit(r) % rhs;
8678     }
8679 
8680 }}
8681 
8682 #include <boost/parser/detail/printing_impl.hpp>
8683 
8684 namespace boost { namespace parser {
8685 
8686     /** An enumeration used for parameters to enable and disable trace in the
8687         `*parse()` functions. */
8688     enum class trace { off, on };
8689 
8690     // Parse API.
8691 
8692     /** Parses `[first, last)` using `parser`, and returns whether the parse
8693         was successful.  On success, `attr` will be assigned the value of the
8694         attribute produced by `parser`.  If `trace_mode == trace::on`, a
8695         verbose trace of the parse will be streamed to `std::cout`.
8696 
8697         \tparam Attr Constrained by
8698         `!detail::derived_from_parser_interface_v<std::remove_cvref_t<Attr>`. */
8699 #if BOOST_PARSER_USE_CONCEPTS
8700     template<
8701         parsable_iter I,
8702         std::sentinel_for<I> S,
8703         typename Parser,
8704         typename GlobalState,
8705         error_handler<I, S, GlobalState> ErrorHandler,
8706         typename Attr>
8707 #else
8708     template<
8709         typename I,
8710         typename S,
8711         typename Parser,
8712         typename GlobalState,
8713         typename ErrorHandler,
8714         typename Attr,
8715         typename Enable = std::enable_if_t<
8716             detail::is_parsable_iter_v<I> &&
8717             detail::is_equality_comparable_with_v<I, S> &&
8718             !detail::derived_from_parser_interface_v<
8719                 detail::remove_cv_ref_t<Attr>>>>
8720 #endif
8721     bool prefix_parse(
8722         I & first,
8723         S last,
8724         parser_interface<Parser, GlobalState, ErrorHandler> const & parser,
8725         Attr & attr,
8726         trace trace_mode = trace::off)
8727 #if BOOST_PARSER_USE_CONCEPTS
8728         requires(
8729             !detail::derived_from_parser_interface_v<std::remove_cvref_t<Attr>>)
8730 #endif
8731     {
8732         detail::attr_reset reset(attr);
8733         if constexpr (!detail::is_char8_iter_v<I>) {
8734             static_assert(
8735                 decltype(detail::has_attribute(first, last, parser)){},
8736                 "If you're seeing this error, you're trying to get parse() to "
8737                 "fill in attr above, using the attribute generated by parser. "
8738                 "However, parser does not generate an attribute.");
8739             if (trace_mode == trace::on) {
8740                 return reset = detail::parse_impl<true>(
8741                            first, last, parser, parser.error_handler_, attr);
8742             } else {
8743                 return reset = detail::parse_impl<false>(
8744                            first, last, parser, parser.error_handler_, attr);
8745             }
8746         } else {
8747             auto r =
8748                 BOOST_PARSER_SUBRANGE(first, last) | detail::text::as_utf32;
8749             auto f = r.begin();
8750             auto const l = r.end();
8751             auto _ = detail::scoped_base_assign(first, f);
8752             static_assert(
8753                 decltype(detail::has_attribute(f, l, parser)){},
8754                 "If you're seeing this error, you're trying to get parse() to "
8755                 "fill in attr above, using the attribute generated by parser. "
8756                 "However, parser does not generate an attribute.");
8757             if (trace_mode == trace::on) {
8758                 return reset = detail::parse_impl<true>(
8759                            f, l, parser, parser.error_handler_, attr);
8760             } else {
8761                 return reset = detail::parse_impl<false>(
8762                            f, l, parser, parser.error_handler_, attr);
8763             }
8764         }
8765     }
8766 
8767     /** Parses `r` using `parser`, and returns whether the parse was
8768         successful.  The entire input range `r` must be consumed for the parse
8769         to be considered successful.  On success, `attr` will be assigned the
8770         value of the attribute produced by `parser`.  If `trace_mode ==
8771         trace::on`, a verbose trace of the parse will be streamed to
8772         `std::cout`.
8773 
8774         \tparam ErrorHandler Constrained by `error_handler<ErrorHandler,std::ranges::iterator_t<decltype(subrange_of(r))>, std::ranges::sentinel_t<decltype(subrange_of(r))>, GlobalState>`,
8775             where `subrange_of` is an implementation detail that: creates
8776             subranges out of pointers; trims trailing zeros off of bounded
8777             arrays (such as string literals); and transcodes to UTF-32 if the
8778             input is non-`char`.
8779         \tparam Attr Constrained by
8780         `!detail::derived_from_parser_interface_v<std::remove_cvref_t<Attr>`. */
8781 #if BOOST_PARSER_USE_CONCEPTS
8782     template<
8783         parsable_range R,
8784         typename Parser,
8785         typename GlobalState,
8786         typename ErrorHandler,
8787         typename Attr>
8788 #else
8789     template<
8790         typename R,
8791         typename Parser,
8792         typename GlobalState,
8793         typename ErrorHandler,
8794         typename Attr,
8795         typename Enable = std::enable_if_t<
8796             detail::is_parsable_range_v<R> &&
8797             !detail::derived_from_parser_interface_v<
8798                 detail::remove_cv_ref_t<Attr>>>>
8799 #endif
8800     bool parse(
8801         R const & r,
8802         parser_interface<Parser, GlobalState, ErrorHandler> const & parser,
8803         Attr & attr,
8804         trace trace_mode = trace::off)
8805 #if BOOST_PARSER_USE_CONCEPTS
8806         // clang-format off
8807         requires error_handler<
8808             ErrorHandler,
8809             std::ranges::iterator_t<decltype(detail::make_input_subrange(r))>,
8810             std::ranges::sentinel_t<decltype(detail::make_input_subrange(r))>,
8811             GlobalState> &&
8812         (!detail::derived_from_parser_interface_v<std::remove_cvref_t<Attr>>)
8813     // clang-format on
8814 #endif
8815     {
8816         detail::attr_reset reset(attr);
8817         auto r_ = detail::make_input_subrange(r);
8818         auto first = r_.begin();
8819         auto const last = r_.end();
8820         return reset = detail::if_full_parse(
8821                    first,
8822                    last,
8823                    parser::prefix_parse(first, last, parser, attr, trace_mode));
8824     }
8825 
8826     /** Parses `[first, last)` using `parser`.  Returns a `std::optional`
8827         containing the attribute produced by `parser` on parse success, and
8828         `std::nullopt` on parse failure.  If `trace_mode == trace::on`, a
8829         verbose trace of the parse will be streamed to `std::cout`.
8830 
8831         \tparam Attr Constrained by
8832         `!detail::derived_from_parser_interface_v<std::remove_cvref_t<Attr>`. */
8833 #if BOOST_PARSER_USE_CONCEPTS
8834     template<
8835         parsable_iter I,
8836         std::sentinel_for<I> S,
8837         typename Parser,
8838         typename GlobalState,
8839         error_handler<I, S, GlobalState> ErrorHandler>
8840 #else
8841     template<
8842         typename I,
8843         typename S,
8844         typename Parser,
8845         typename GlobalState,
8846         typename ErrorHandler,
8847         typename Enable = std::enable_if_t<
8848             detail::is_parsable_iter_v<I> &&
8849             detail::is_equality_comparable_with_v<I, S>>>
8850 #endif
8851     auto prefix_parse(
8852         I & first,
8853         S last,
8854         parser_interface<Parser, GlobalState, ErrorHandler> const & parser,
8855         trace trace_mode = trace::off)
8856     {
8857         if constexpr (!detail::is_char8_iter_v<I>) {
8858             if (trace_mode == trace::on) {
8859                 return detail::parse_impl<true>(
8860                     first, last, parser, parser.error_handler_);
8861             } else {
8862                 return detail::parse_impl<false>(
8863                     first, last, parser, parser.error_handler_);
8864             }
8865         } else {
8866             auto r =
8867                 BOOST_PARSER_SUBRANGE(first, last) | detail::text::as_utf32;
8868             auto f = r.begin();
8869             auto const l = r.end();
8870             auto _ = detail::scoped_base_assign(first, f);
8871             if (trace_mode == trace::on) {
8872                 return detail::parse_impl<true>(
8873                     f, l, parser, parser.error_handler_);
8874             } else {
8875                 return detail::parse_impl<false>(
8876                     f, l, parser, parser.error_handler_);
8877             }
8878         }
8879     }
8880 
8881     /** Parses `r` using `parser`.  Returns a `std::optional` containing the
8882         attribute produced by `parser` on parse success, and `std::nullopt` on
8883         parse failure.  The entire input range `r` must be consumed for the
8884         parse to be considered successful.  If `trace_mode == trace::on`, a
8885         verbose trace of the parse will be streamed to `std::cout`.
8886 
8887         \tparam ErrorHandler Constrained by `error_handler<ErrorHandler,std::ranges::iterator_t<decltype(subrange_of(r))>, std::ranges::sentinel_t<decltype(subrange_of(r))>, GlobalState>`,
8888             where `subrange_of` is an implementation detail that: creates
8889             subranges out of pointers; trims trailing zeros off of bounded
8890             arrays (such as string literals); and transcodes to UTF-32 if the
8891             input is non-`char`.
8892         \tparam Attr Constrained by
8893         `!detail::derived_from_parser_interface_v<std::remove_cvref_t<Attr>`. */
8894 #if BOOST_PARSER_USE_CONCEPTS
8895     template<
8896         parsable_range R,
8897         typename Parser,
8898         typename GlobalState,
8899         typename ErrorHandler>
8900 #else
8901     template<
8902         typename R,
8903         typename Parser,
8904         typename GlobalState,
8905         typename ErrorHandler,
8906         typename Enable = std::enable_if_t<detail::is_parsable_range_v<R>>>
8907 #endif
8908     auto parse(
8909         R const & r,
8910         parser_interface<Parser, GlobalState, ErrorHandler> const & parser,
8911         trace trace_mode = trace::off)
8912 #if BOOST_PARSER_USE_CONCEPTS
8913         // clang-format off
8914         requires error_handler<
8915             ErrorHandler,
8916             std::ranges::iterator_t<decltype(detail::make_input_subrange(r))>,
8917             std::ranges::sentinel_t<decltype(detail::make_input_subrange(r))>,
8918             GlobalState>
8919     // clang-format on
8920 #endif
8921     {
8922         auto r_ = detail::make_input_subrange(r);
8923         auto first = r_.begin();
8924         auto const last = r_.end();
8925         return detail::if_full_parse(
8926             first, last, parser::prefix_parse(first, last, parser, trace_mode));
8927     }
8928 
8929     /** Parses `[first, last)` using `parser`, skipping all input recognized
8930         by `skip` between the application of any two parsers, and returns
8931         whether the parse was successful.  On success, `attr` will be assigned
8932         the value of the attribute produced by `parser`.  If `trace_mode ==
8933         trace::on`, a verbose trace of the parse will be streamed to
8934         `std::cout`. */
8935 #if BOOST_PARSER_USE_CONCEPTS
8936     template<
8937         parsable_iter I,
8938         std::sentinel_for<I> S,
8939         typename Parser,
8940         typename GlobalState,
8941         error_handler<I, S, GlobalState> ErrorHandler,
8942         typename SkipParser,
8943         typename Attr>
8944 #else
8945     template<
8946         typename I,
8947         typename S,
8948         typename Parser,
8949         typename GlobalState,
8950         typename ErrorHandler,
8951         typename SkipParser,
8952         typename Attr,
8953         typename Enable = std::enable_if_t<
8954             detail::is_parsable_iter_v<I> &&
8955             detail::is_equality_comparable_with_v<I, S>>>
8956 #endif
8957     bool prefix_parse(
8958         I & first,
8959         S last,
8960         parser_interface<Parser, GlobalState, ErrorHandler> const & parser,
8961         parser_interface<SkipParser> const & skip,
8962         Attr & attr,
8963         trace trace_mode = trace::off)
8964     {
8965         detail::attr_reset reset(attr);
8966         if constexpr (!detail::is_char8_iter_v<I>) {
8967             static_assert(
8968                 decltype(detail::has_attribute(first, last, parser)){},
8969                 "If you're seeing this error, you're trying to get parse() to "
8970                 "fill in attr above, using the attribute generated by parser. "
8971                 "However, parser does not generate an attribute.");
8972             if (trace_mode == trace::on) {
8973                 return reset = detail::skip_parse_impl<true>(
8974                            first,
8975                            last,
8976                            parser,
8977                            skip,
8978                            parser.error_handler_,
8979                            attr);
8980             } else {
8981                 return reset = detail::skip_parse_impl<false>(
8982                            first,
8983                            last,
8984                            parser,
8985                            skip,
8986                            parser.error_handler_,
8987                            attr);
8988             }
8989         } else {
8990             auto r =
8991                 BOOST_PARSER_SUBRANGE(first, last) | detail::text::as_utf32;
8992             auto f = r.begin();
8993             auto const l = r.end();
8994             auto _ = detail::scoped_base_assign(first, f);
8995             static_assert(
8996                 decltype(detail::has_attribute(f, l, parser)){},
8997                 "If you're seeing this error, you're trying to get parse() to "
8998                 "fill in attr above, using the attribute generated by parser. "
8999                 "However, parser does not generate an attribute.");
9000             if (trace_mode == trace::on) {
9001                 return reset = detail::skip_parse_impl<true>(
9002                            f, l, parser, skip, parser.error_handler_, attr);
9003             } else {
9004                 return reset = detail::skip_parse_impl<false>(
9005                            f, l, parser, skip, parser.error_handler_, attr);
9006             }
9007         }
9008     }
9009 
9010     /** Parses `r` using `parser`, skipping all input recognized by `skip`
9011         between the application of any two parsers, and returns whether the
9012         parse was successful.  The entire input range `r` must be consumed for
9013         the parse to be considered successful.  On success, `attr` will be
9014         assigned the value of the attribute produced by `parser`.  If
9015         `trace_mode == trace::on`, a verbose trace of the parse will be
9016         streamed to `std::cout`.
9017 
9018         \tparam ErrorHandler Constrained by `error_handler<ErrorHandler,std::ranges::iterator_t<decltype(subrange_of(r))>, std::ranges::sentinel_t<decltype(subrange_of(r))>, GlobalState>`,
9019             where `subrange_of` is an implementation detail that: creates
9020             subranges out of pointers; trims trailing zeros off of bounded
9021             arrays (such as string literals); and transcodes to UTF-32 if the
9022             input is non-`char`. */
9023 #if BOOST_PARSER_USE_CONCEPTS
9024     template<
9025         parsable_range R,
9026         typename Parser,
9027         typename GlobalState,
9028         typename ErrorHandler,
9029         typename SkipParser,
9030         typename Attr>
9031 #else
9032     template<
9033         typename R,
9034         typename Parser,
9035         typename GlobalState,
9036         typename ErrorHandler,
9037         typename SkipParser,
9038         typename Attr,
9039         typename Enable = std::enable_if_t<detail::is_parsable_range_v<R>>>
9040 #endif
9041     bool parse(
9042         R const & r,
9043         parser_interface<Parser, GlobalState, ErrorHandler> const & parser,
9044         parser_interface<SkipParser> const & skip,
9045         Attr & attr,
9046         trace trace_mode = trace::off)
9047 #if BOOST_PARSER_USE_CONCEPTS
9048         // clang-format off
9049         requires error_handler<
9050             ErrorHandler,
9051             std::ranges::iterator_t<decltype(detail::make_input_subrange(r))>,
9052             std::ranges::sentinel_t<decltype(detail::make_input_subrange(r))>,
9053             GlobalState>
9054     // clang-format on
9055 #endif
9056     {
9057         detail::attr_reset reset(attr);
9058         auto r_ = detail::make_input_subrange(r);
9059         auto first = r_.begin();
9060         auto const last = r_.end();
9061         return reset = detail::if_full_parse(
9062                    first,
9063                    last,
9064                    parser::prefix_parse(
9065                        first, last, parser, skip, attr, trace_mode));
9066     }
9067 
9068     /** Parses `[first, last)` using `parser`, skipping all input recognized
9069         by `skip` between the application of any two parsers.  Returns a
9070         `std::optional` containing the attribute produced by `parser` on parse
9071         success, and `std::nullopt` on parse failure.  If `trace_mode ==
9072         trace::on`, a verbose trace of the parse will be streamed to
9073         `std::cout`. */
9074 #if BOOST_PARSER_USE_CONCEPTS
9075     template<
9076         parsable_iter I,
9077         std::sentinel_for<I> S,
9078         typename Parser,
9079         typename GlobalState,
9080         error_handler<I, S, GlobalState> ErrorHandler,
9081         typename SkipParser>
9082 #else
9083     template<
9084         typename I,
9085         typename S,
9086         typename Parser,
9087         typename GlobalState,
9088         typename ErrorHandler,
9089         typename SkipParser,
9090         typename Enable = std::enable_if_t<
9091             detail::is_parsable_iter_v<I> &&
9092             detail::is_equality_comparable_with_v<I, S>>>
9093 #endif
9094     auto prefix_parse(
9095         I & first,
9096         S last,
9097         parser_interface<Parser, GlobalState, ErrorHandler> const & parser,
9098         parser_interface<SkipParser> const & skip,
9099         trace trace_mode = trace::off)
9100     {
9101         if constexpr (!detail::is_char8_iter_v<I>) {
9102             if (trace_mode == trace::on) {
9103                 return detail::skip_parse_impl<true>(
9104                     first, last, parser, skip, parser.error_handler_);
9105             } else {
9106                 return detail::skip_parse_impl<false>(
9107                     first, last, parser, skip, parser.error_handler_);
9108             }
9109         } else {
9110             auto r =
9111                 BOOST_PARSER_SUBRANGE(first, last) | detail::text::as_utf32;
9112             auto f = r.begin();
9113             auto const l = r.end();
9114             auto _ = detail::scoped_base_assign(first, f);
9115             if (trace_mode == trace::on) {
9116                 return detail::skip_parse_impl<true>(
9117                     f, l, parser, skip, parser.error_handler_);
9118             } else {
9119                 return detail::skip_parse_impl<false>(
9120                     f, l, parser, skip, parser.error_handler_);
9121             }
9122         }
9123     }
9124 
9125     /** Parses `r` using `parser`, skipping all input recognized by `skip`
9126         between the application of any two parsers.  Returns a `std::optional`
9127         containing the attribute produced by `parser` on parse success, and
9128         `std::nullopt` on parse failure.  The entire input range `r` must be
9129         consumed for the parse to be considered successful.  If `trace_mode ==
9130         trace::on`, a verbose trace of the parse will be streamed to
9131         `std::cout`.
9132 
9133         \tparam ErrorHandler Constrained by `error_handler<ErrorHandler,std::ranges::iterator_t<decltype(subrange_of(r))>, std::ranges::sentinel_t<decltype(subrange_of(r))>, GlobalState>`,
9134             where `subrange_of` is an implementation detail that: creates
9135             subranges out of pointers; trims trailing zeros off of bounded
9136             arrays (such as string literals); and transcodes to UTF-32 if the
9137             input is non-`char`. */
9138 #if BOOST_PARSER_USE_CONCEPTS
9139     template<
9140         parsable_range R,
9141         typename Parser,
9142         typename GlobalState,
9143         typename ErrorHandler,
9144         typename SkipParser>
9145 #else
9146     template<
9147         typename R,
9148         typename Parser,
9149         typename GlobalState,
9150         typename ErrorHandler,
9151         typename SkipParser,
9152         typename Enable = std::enable_if_t<detail::is_parsable_range_v<R>>>
9153 #endif
9154     auto parse(
9155         R const & r,
9156         parser_interface<Parser, GlobalState, ErrorHandler> const & parser,
9157         parser_interface<SkipParser> const & skip,
9158         trace trace_mode = trace::off)
9159 #if BOOST_PARSER_USE_CONCEPTS
9160         // clang-format off
9161         requires error_handler<
9162             ErrorHandler,
9163             std::ranges::iterator_t<decltype(detail::make_input_subrange(r))>,
9164             std::ranges::sentinel_t<decltype(detail::make_input_subrange(r))>,
9165             GlobalState>
9166     // clang-format on
9167 #endif
9168     {
9169         auto r_ = detail::make_input_subrange(r);
9170         auto first = r_.begin();
9171         auto const last = r_.end();
9172         return detail::if_full_parse(
9173             first,
9174             last,
9175             parser::prefix_parse(first, last, parser, skip, trace_mode));
9176     }
9177 
9178     /** Parses `[first, last)` using `parser`, and returns whether the parse
9179         was successful.  When a callback rule `r` is successful during the
9180         parse, one of two things happens: 1) if `r` has an attribute,
9181         `callbacks(tag, x)` will be called (where `tag` is
9182         `decltype(r)::tag_type{}`, and `x` is the attribute produced by `r`);
9183         or 2) if `r` has no attribute, `callbacks(tag)` will be called.
9184         `Callbacks` is expected to be an invocable with the correct overloads
9185         required to support all successful rule parses that might occur.  If
9186         `trace_mode == trace::on`, a verbose trace of the parse will be
9187         streamed to `std::cout`. */
9188 #if BOOST_PARSER_USE_CONCEPTS
9189     template<
9190         parsable_iter I,
9191         std::sentinel_for<I> S,
9192         typename Parser,
9193         typename GlobalState,
9194         error_handler<I, S, GlobalState> ErrorHandler,
9195         typename Callbacks>
9196 #else
9197     template<
9198         typename I,
9199         typename S,
9200         typename Parser,
9201         typename GlobalState,
9202         typename ErrorHandler,
9203         typename Callbacks,
9204         typename Enable = std::enable_if_t<
9205             detail::is_parsable_iter_v<I> &&
9206             detail::is_equality_comparable_with_v<I, S>>>
9207 #endif
9208     bool callback_prefix_parse(
9209         I & first,
9210         S last,
9211         parser_interface<Parser, GlobalState, ErrorHandler> const & parser,
9212         Callbacks const & callbacks,
9213         trace trace_mode = trace::off)
9214     {
9215         if constexpr (!detail::is_char8_iter_v<I>) {
9216             if (trace_mode == trace::on) {
9217                 return detail::callback_parse_impl<true>(
9218                     first, last, parser, parser.error_handler_, callbacks);
9219             } else {
9220                 return detail::callback_parse_impl<false>(
9221                     first, last, parser, parser.error_handler_, callbacks);
9222             }
9223         } else {
9224             auto r =
9225                 BOOST_PARSER_SUBRANGE(first, last) | detail::text::as_utf32;
9226             auto f = r.begin();
9227             auto const l = r.end();
9228             auto _ = detail::scoped_base_assign(first, f);
9229             if (trace_mode == trace::on) {
9230                 return detail::callback_parse_impl<true>(
9231                     f, l, parser, parser.error_handler_, callbacks);
9232             } else {
9233                 return detail::callback_parse_impl<false>(
9234                     f, l, parser, parser.error_handler_, callbacks);
9235             }
9236         }
9237     }
9238 
9239     /** Parses `r` using `parser`, and returns whether the parse was
9240         successful.  The entire input range `r` must be consumed for the parse
9241         to be considered successful.  When a callback rule `r` is successful
9242         during the parse, one of two things happens: 1) if `r` has an
9243         attribute, `callbacks(tag, x)` will be called (where `tag` is
9244         `decltype(r)::tag_type{}`, and `x` is the attribute produced by `r`);
9245         or 2) if `r` has no attribute, `callbacks(tag)` will be called.
9246         `Callbacks` is expected to be an invocable with the correct overloads
9247         required to support all successful rule parses that might occur.  If
9248         `trace_mode == trace::on`, a verbose trace of the parse will be
9249         streamed to `std::cout`.
9250 
9251         \tparam ErrorHandler Constrained by `error_handler<ErrorHandler,std::ranges::iterator_t<decltype(subrange_of(r))>, std::ranges::sentinel_t<decltype(subrange_of(r))>, GlobalState>`,
9252             where `subrange_of` is an implementation detail that: creates
9253             subranges out of pointers; trims trailing zeros off of bounded
9254             arrays (such as string literals); and transcodes to UTF-32 if the
9255             input is non-`char`. */
9256 #if BOOST_PARSER_USE_CONCEPTS
9257     template<
9258         parsable_range R,
9259         typename Parser,
9260         typename GlobalState,
9261         typename ErrorHandler,
9262         typename Callbacks>
9263 #else
9264     template<
9265         typename R,
9266         typename Parser,
9267         typename GlobalState,
9268         typename ErrorHandler,
9269         typename Callbacks,
9270         typename Enable = std::enable_if_t<detail::is_parsable_range_v<R>>>
9271 #endif
9272     bool callback_parse(
9273         R const & r,
9274         parser_interface<Parser, GlobalState, ErrorHandler> const & parser,
9275         Callbacks const & callbacks,
9276         trace trace_mode = trace::off)
9277 #if BOOST_PARSER_USE_CONCEPTS
9278         // clang-format off
9279         requires error_handler<
9280             ErrorHandler,
9281             std::ranges::iterator_t<decltype(detail::make_input_subrange(r))>,
9282             std::ranges::sentinel_t<decltype(detail::make_input_subrange(r))>,
9283             GlobalState>
9284     // clang-format on
9285 #endif
9286     {
9287         auto r_ = detail::make_input_subrange(r);
9288         auto first = r_.begin();
9289         auto const last = r_.end();
9290         return detail::if_full_parse(
9291             first,
9292             last,
9293             parser::callback_prefix_parse(first, last, parser, callbacks));
9294     }
9295 
9296     /** Parses `[first, last)` using `parser`, skipping all input recognized
9297         by `skip` between the application of any two parsers, and returns
9298         whether the parse was successful.  When a callback rule `r` is
9299         successful during the parse, one of two things happens: 1) if `r` has
9300         an attribute, `callbacks(tag, x)` will be called (where `tag` is
9301         `decltype(r)::tag_type{}`, and `x` is the attribute produced by `r`);
9302         or 2) if `r` has no attribute, `callbacks(tag)` will be called.
9303         `Callbacks` is expected to be an invocable with the correct overloads
9304         required to support all successful rule parses that might occur.  If
9305         `trace_mode == trace::on`, a verbose trace of the parse will be
9306         streamed to `std::cout`. */
9307 #if BOOST_PARSER_USE_CONCEPTS
9308     template<
9309         parsable_iter I,
9310         std::sentinel_for<I> S,
9311         typename Parser,
9312         typename GlobalState,
9313         error_handler<I, S, GlobalState> ErrorHandler,
9314         typename SkipParser,
9315         typename Callbacks>
9316 #else
9317     template<
9318         typename I,
9319         typename S,
9320         typename Parser,
9321         typename GlobalState,
9322         typename ErrorHandler,
9323         typename SkipParser,
9324         typename Callbacks,
9325         typename Enable = std::enable_if_t<
9326             detail::is_parsable_iter_v<I> &&
9327             detail::is_equality_comparable_with_v<I, S>>>
9328 #endif
9329     bool callback_prefix_parse(
9330         I & first,
9331         S last,
9332         parser_interface<Parser, GlobalState, ErrorHandler> const & parser,
9333         parser_interface<SkipParser> const & skip,
9334         Callbacks const & callbacks,
9335         trace trace_mode = trace::off)
9336     {
9337         if constexpr (!detail::is_char8_iter_v<I>) {
9338             if (trace_mode == trace::on) {
9339                 return detail::callback_skip_parse_impl<true>(
9340                     first,
9341                     last,
9342                     parser,
9343                     skip,
9344                     parser.error_handler_,
9345                     callbacks);
9346             } else {
9347                 return detail::callback_skip_parse_impl<false>(
9348                     first,
9349                     last,
9350                     parser,
9351                     skip,
9352                     parser.error_handler_,
9353                     callbacks);
9354             }
9355         } else {
9356             auto r =
9357                 BOOST_PARSER_SUBRANGE(first, last) | detail::text::as_utf32;
9358             auto f = r.begin();
9359             auto const l = r.end();
9360             auto _ = detail::scoped_base_assign(first, f);
9361             if (trace_mode == trace::on) {
9362                 return detail::callback_skip_parse_impl<true>(
9363                     f, l, parser, skip, parser.error_handler_, callbacks);
9364             } else {
9365                 return detail::callback_skip_parse_impl<false>(
9366                     f, l, parser, skip, parser.error_handler_, callbacks);
9367             }
9368         }
9369     }
9370 
9371     /** Parses `r` using `parser`, skipping all input recognized by `skip`
9372         between the application of any two parsers, and returns whether the
9373         parse was successful.  The entire input range `r` must be consumed for
9374         the parse to be considered successful.  When a callback rule `r` is
9375         successful during the parse, one of two things happens: 1) if `r` has
9376         an attribute, `callbacks(tag, x)` will be called (where `tag` is
9377         `decltype(r)::tag_type{}`, and `x` is the attribute produced by `r`);
9378         or 2) if `r` has no attribute, `callbacks(tag)` will be called.
9379         `Callbacks` is expected to be an invocable with the correct overloads
9380         required to support all successful rule parses that might occur.  If
9381         `trace_mode == trace::on`, a verbose trace of the parse will be
9382         streamed to `std::cout`.
9383 
9384         \tparam ErrorHandler Constrained by `error_handler<ErrorHandler,std::ranges::iterator_t<decltype(subrange_of(r))>, std::ranges::sentinel_t<decltype(subrange_of(r))>, GlobalState>`,
9385             where `subrange_of` is an implementation detail that: creates
9386             subranges out of pointers; trims trailing zeros off of bounded
9387             arrays (such as string literals); and transcodes to UTF-32 if the
9388             input is non-`char`. */
9389 #if BOOST_PARSER_USE_CONCEPTS
9390     template<
9391         parsable_range R,
9392         typename Parser,
9393         typename GlobalState,
9394         typename ErrorHandler,
9395         typename SkipParser,
9396         typename Callbacks>
9397 #else
9398     template<
9399         typename R,
9400         typename Parser,
9401         typename GlobalState,
9402         typename ErrorHandler,
9403         typename SkipParser,
9404         typename Callbacks,
9405         typename Enable = std::enable_if_t<detail::is_parsable_range_v<R>>>
9406 #endif
9407     bool callback_parse(
9408         R const & r,
9409         parser_interface<Parser, GlobalState, ErrorHandler> const & parser,
9410         parser_interface<SkipParser> const & skip,
9411         Callbacks const & callbacks,
9412         trace trace_mode = trace::off)
9413 #if BOOST_PARSER_USE_CONCEPTS
9414         // clang-format off
9415         requires error_handler<
9416             ErrorHandler,
9417             std::ranges::iterator_t<decltype(detail::make_input_subrange(r))>,
9418             std::ranges::sentinel_t<decltype(detail::make_input_subrange(r))>,
9419             GlobalState>
9420     // clang-format on
9421 #endif
9422     {
9423         auto r_ = detail::make_input_subrange(r);
9424         auto first = r_.begin();
9425         auto const last = r_.end();
9426         return detail::if_full_parse(
9427             first,
9428             last,
9429             parser::callback_prefix_parse(
9430                 first, last, parser, skip, callbacks, trace_mode));
9431     }
9432 
9433     namespace literals {
9434         /** Returns a literal parser equivalent to `lit(c)`. */
9435         constexpr auto operator""_l(char c) { return parser::lit(c); }
9436 #if defined(__cpp_char8_t) || defined(BOOST_PARSER_DOXYGEN)
9437         /** Returns a literal parser equivalent to `lit(c)`. */
9438         constexpr auto operator""_l(char8_t c) { return parser::lit(c); }
9439 #endif
9440         /** Returns a literal parser equivalent to `lit(c)`. */
9441         constexpr auto operator""_l(char32_t c) { return parser::lit(c); }
9442         /** Returns a literal parser equivalent to `lit(str)`. */
9443         constexpr auto operator""_l(char const * str, std::size_t)
9444         {
9445             return parser::lit(str);
9446         }
9447 #if defined(__cpp_char8_t) || defined(BOOST_PARSER_DOXYGEN)
9448         /** Returns a literal parser equivalent to `lit(str)`. */
9449         constexpr auto operator""_l(char8_t const * str, std::size_t)
9450         {
9451             return parser::lit(str);
9452         }
9453 #endif
9454         /** Returns a literal parser equivalent to `lit(str)`. */
9455         constexpr auto operator""_l(char32_t const * str, std::size_t)
9456         {
9457             return parser::lit(str);
9458         }
9459 
9460         /** Returns a character parser equivalent to `char_(c)`. */
9461         constexpr auto operator""_p(char c) { return char_(c); }
9462 #if defined(__cpp_char8_t) || defined(BOOST_PARSER_DOXYGEN)
9463         /** Returns a character parser equivalent to `char_(c)`. */
9464         constexpr auto operator""_p(char8_t c) { return char_(c); }
9465 #endif
9466         /** Returns a character parser equivalent to `char_(c)`. */
9467         constexpr auto operator""_p(char32_t c) { return char_(c); }
9468         /** Returns a string parser equivalent to `string(str)`. */
9469         constexpr auto operator""_p(char const * str, std::size_t)
9470         {
9471             return parser::string(str);
9472         }
9473 #if defined(__cpp_char8_t) || defined(BOOST_PARSER_DOXYGEN)
9474         /** Returns a string parser equivalent to `string(str)`. */
9475         constexpr auto operator""_p(char8_t const * str, std::size_t)
9476         {
9477             return parser::string(str);
9478         }
9479 #endif
9480         /** Returns a string parser equivalent to `string(str)`. */
9481         constexpr auto operator""_p(char32_t const * str, std::size_t)
9482         {
9483             return parser::string(str);
9484         }
9485     }
9486 
9487     namespace detail {
9488         template<typename R, typename Parser>
9489         struct attribute_impl
9490         {
9491             using parser_type = typename Parser::parser_type;
9492             using global_state_type = typename Parser::global_state_type;
9493             using error_handler_type = typename Parser::error_handler_type;
9494 
9495             using iterator = detail::iterator_t<R>;
9496             using sentinel = detail::sentinel_t<R>;
9497 
9498             using context = decltype(detail::make_context<false, false>(
9499                 std::declval<iterator>(),
9500                 std::declval<sentinel>(),
9501                 std::declval<bool &>(),
9502                 std::declval<int &>(),
9503                 std::declval<error_handler_type>(),
9504                 std::declval<global_state_type &>(),
9505                 std::declval<detail::symbol_table_tries_t &>(),
9506                 std::declval<detail::pending_symbol_table_operations_t &>()));
9507             using type = decltype(std::declval<Parser>()(
9508                 std::declval<iterator &>(),
9509                 std::declval<sentinel>(),
9510                 std::declval<context>(),
9511                 detail::null_parser{},
9512                 detail::flags::gen_attrs,
9513                 std::declval<bool &>()));
9514         };
9515 
9516         template<typename Iter, typename Sentinel, typename Parser>
9517         auto has_attribute(Iter first, Sentinel last, Parser parser)
9518         {
9519             using attr_t = typename attribute_impl<
9520                 BOOST_PARSER_SUBRANGE<Iter, Sentinel>,
9521                 Parser>::type;
9522             return std::integral_constant<bool, !is_nope_v<attr_t>>{};
9523         }
9524 
9525         template<typename T>
9526         constexpr wrapper<T> attr_wrapped_final;
9527         template<>
9528         inline constexpr wrapper<none> attr_wrapped_final<nope>;
9529     }
9530 
9531     template<typename R, typename Parser>
9532     struct attribute
9533     {
9534         using initial_type = typename detail::attribute_impl<
9535             decltype(detail::make_input_subrange(std::declval<R>())),
9536             Parser>::type;
9537         using type =
9538             typename decltype(detail::attr_wrapped_final<initial_type>)::type;
9539     };
9540 
9541 
9542     namespace detail {
9543         template<typename... Args>
9544         constexpr void static_assert_merge_attributes(tuple<Args...> parsers)
9545         {
9546             using context_t = parse_context<
9547                 false,
9548                 false,
9549                 char const *,
9550                 char const *,
9551                 default_error_handler>;
9552             using skipper_t = parser_interface<ws_parser<false, false>>;
9553             using use_parser_t = dummy_use_parser_t<
9554                 char const *,
9555                 char const *,
9556                 context_t,
9557                 skipper_t> const;
9558             using all_types =
9559                 decltype(hl::transform(parsers, std::declval<use_parser_t>()));
9560             auto all_types_wrapped = hl::transform(all_types{}, detail::wrap{});
9561             auto first_non_nope = hl::fold_left(
9562                 all_types_wrapped,
9563                 wrapper<nope>{},
9564                 [=](auto result, auto type) {
9565                     if constexpr (is_nope_v<typename decltype(result)::type>) {
9566                         return type;
9567                     } else {
9568                         return result;
9569                     }
9570                 });
9571             using first_t = typename decltype(first_non_nope)::type;
9572             static_assert(
9573                 !is_nope_v<first_t>,
9574                 "It looks like you wrote merge[p1 >> p2 >> ... pn], and none "
9575                 "of the parsers p1, p2, ... pn produces an attribute.  Please "
9576                 "fix.");
9577             if constexpr (is_nope_v<first_t>) {
9578                 [[maybe_unused]] detail::print_type<tuple<Args...>> tuple_types;
9579                 [[maybe_unused]] detail::print_type<all_types> attribute_types;
9580             }
9581             hl::for_each(all_types_wrapped, [=](auto type) {
9582                 using t = typename decltype(type)::type;
9583                 if constexpr (!is_nope_v<t>) {
9584                     static_assert(
9585                         std::is_same_v<t, first_t>,
9586                         "If you see an error here, you wrote merge[p1 >> "
9587                         "p2 >> ... pn] where at least one of the types in "
9588                         "ATTR(p1), ATTR(p2), ... ATTR(pn) is not the same "
9589                         "type as one of the others.");
9590                     if constexpr (!std::is_same_v<t, first_t>) {
9591                         [[maybe_unused]] detail::print_type<tuple<Args...>>
9592                             tuple_types(parsers);
9593                         [[maybe_unused]] detail::print_type<all_types>
9594                             attribute_types;
9595                         [[maybe_unused]] detail::print_type<first_t> first_type;
9596                         [[maybe_unused]] detail::print_type<t> this_type;
9597                     }
9598                 }
9599             });
9600         }
9601     }
9602 }}
9603 
9604 #endif