Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-09-13 08:51:46

0001 /*=============================================================================
0002     Copyright (c) 2017 wanghan02
0003     Copyright (c) 2024 Nana Sakisaka
0004 
0005     Distributed under the Boost Software License, Version 1.0. (See accompanying
0006     file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
0007 =============================================================================*/
0008 #if !defined(BOOST_SPIRIT_X3_SUPPORT_EXPECTATION_HPP)
0009 #define BOOST_SPIRIT_X3_SUPPORT_EXPECTATION_HPP
0010 
0011 #if !defined(BOOST_SPIRIT_X3_THROW_EXPECTATION_FAILURE)
0012 # define BOOST_SPIRIT_X3_THROW_EXPECTATION_FAILURE 1
0013 #endif
0014 
0015 #include <boost/config.hpp> // for BOOST_SYMBOL_VISIBLE, BOOST_ATTRIBUTE_NODISCARD
0016 #include <boost/core/ignore_unused.hpp>
0017 #include <boost/spirit/home/x3/support/unused.hpp>
0018 #include <boost/spirit/home/x3/support/context.hpp>
0019 
0020 // We utilize `x3::traits::build_optional<...>` for customization point
0021 // instead of directly wrapping `expectation_failure` with `boost::optional`.
0022 // This would make it possible for the user to eliminate the usages of
0023 // `boost::optional<T>`, and use `std::optional<T>` everywhere.
0024 //
0025 // Note that we are intentionally including this header regardless of
0026 // the value of BOOST_SPIRIT_X3_THROW_EXPECTATION_FAILURE, since the
0027 // helper types defined in non-throwing version might still be required
0028 // when the users benchmark their application just by switching the
0029 // macro while keeping their implementation unmodified.
0030 //
0031 // This will make it possible for the users to unconditionally
0032 // inject `x3::expectation_failure_optional<Iterator>` into their parser,
0033 // safely assuming that the value is no-op in throwing mode.
0034 #include <boost/spirit/home/x3/support/traits/optional_traits.hpp>
0035 
0036 // This is required for partial specialization of relevant helpers.
0037 // TODO: Add a macro to discard all #includes of <boost/optional.hpp>.
0038 //       (this is TODO because it requires changes in `optional_traits.hpp`.)
0039 #include <boost/optional.hpp>
0040 #include <optional>
0041 
0042 #if BOOST_SPIRIT_X3_THROW_EXPECTATION_FAILURE // throwing mode
0043 # define BOOST_SPIRIT_X3_EXPECTATION_FAILURE_API BOOST_SYMBOL_VISIBLE
0044 # define BOOST_SPIRIT_X3_EXPECTATION_FAILURE_BASE : std::runtime_error
0045 # define BOOST_SPIRIT_X3_EXPECTATION_FAILURE_NS throwing
0046 # include <boost/throw_exception.hpp>
0047 # include <stdexcept>
0048 
0049 #else // non-throwing mode
0050 # define BOOST_SPIRIT_X3_EXPECTATION_FAILURE_API
0051 # define BOOST_SPIRIT_X3_EXPECTATION_FAILURE_BASE
0052 # define BOOST_SPIRIT_X3_EXPECTATION_FAILURE_NS non_throwing
0053 #endif
0054 
0055 #include <string>
0056 #include <type_traits>
0057 
0058 
0059 namespace boost { namespace spirit { namespace x3
0060 {
0061     struct expectation_failure_tag;
0062 
0063     inline namespace BOOST_SPIRIT_X3_EXPECTATION_FAILURE_NS
0064     {
0065         template <typename Iterator>
0066         struct BOOST_SPIRIT_X3_EXPECTATION_FAILURE_API
0067             expectation_failure BOOST_SPIRIT_X3_EXPECTATION_FAILURE_BASE
0068         {
0069         public:
0070             expectation_failure(Iterator where, std::string const& which)
0071             #if BOOST_SPIRIT_X3_THROW_EXPECTATION_FAILURE
0072                 : std::runtime_error("boost::spirit::x3::expectation_failure"),
0073             #else
0074                 :
0075             #endif
0076                 where_(where), which_(which)
0077             {}
0078 
0079             BOOST_ATTRIBUTE_NODISCARD
0080             constexpr Iterator const& where() const noexcept { return where_; }
0081 
0082             BOOST_ATTRIBUTE_NODISCARD
0083             constexpr std::string const& which() const noexcept { return which_; }
0084 
0085         private:
0086             Iterator where_;
0087             std::string which_;
0088         };
0089 
0090 
0091         template <typename Context>
0092         using expectation_failure_t = std::remove_cv_t<std::remove_reference_t<
0093             decltype(x3::get<expectation_failure_tag>(std::declval<Context>()))>>;
0094 
0095         template <typename Iterator>
0096         using expectation_failure_optional =
0097             typename traits::build_optional<expectation_failure<Iterator>>::type;
0098 
0099 
0100         // x3::where(x), x3::which(x)
0101         // Convenient accessors for absorbing the variation of
0102         // optional/reference_wrapper interfaces.
0103 
0104         // beware ADL - we should avoid overgeneralization here.
0105 
0106         namespace expectation_failure_helpers
0107         {
0108             // bare type
0109             template <typename Iterator>
0110             BOOST_ATTRIBUTE_NODISCARD
0111             constexpr decltype(auto) where(expectation_failure<Iterator> const& failure) noexcept { return failure.where(); }
0112 
0113             template <typename Iterator>
0114             BOOST_ATTRIBUTE_NODISCARD
0115             constexpr decltype(auto) which(expectation_failure<Iterator> const& failure) noexcept { return failure.which(); }
0116 
0117             // std::optional
0118             template <typename Iterator>
0119             BOOST_ATTRIBUTE_NODISCARD
0120             constexpr decltype(auto) where(std::optional<expectation_failure<Iterator>> const& failure) noexcept { return failure->where(); }
0121 
0122             template <typename Iterator>
0123             BOOST_ATTRIBUTE_NODISCARD
0124             constexpr decltype(auto) which(std::optional<expectation_failure<Iterator>> const& failure) noexcept { return failure->which(); }
0125 
0126             // boost::optional
0127             template <typename Iterator>
0128             BOOST_ATTRIBUTE_NODISCARD
0129             constexpr decltype(auto) where(boost::optional<expectation_failure<Iterator>> const& failure) noexcept { return failure->where(); }
0130 
0131             template <typename Iterator>
0132             BOOST_ATTRIBUTE_NODISCARD
0133             constexpr decltype(auto) which(boost::optional<expectation_failure<Iterator>> const& failure) noexcept { return failure->which(); }
0134 
0135             // std::optional + std::reference_wrapper
0136             template <typename Iterator>
0137             BOOST_ATTRIBUTE_NODISCARD
0138             constexpr decltype(auto) where(std::reference_wrapper<std::optional<expectation_failure<Iterator>>> const& failure) noexcept { return failure.get()->where(); }
0139 
0140             template <typename Iterator>
0141             BOOST_ATTRIBUTE_NODISCARD
0142             constexpr decltype(auto) which(std::reference_wrapper<std::optional<expectation_failure<Iterator>>> const& failure) noexcept { return failure.get()->which(); }
0143 
0144             // boost::optional + std::reference_wrapper
0145             template <typename Iterator>
0146             BOOST_ATTRIBUTE_NODISCARD
0147             constexpr decltype(auto) where(std::reference_wrapper<boost::optional<expectation_failure<Iterator>>> const& failure) noexcept { return failure.get()->where(); }
0148 
0149             template <typename Iterator>
0150             BOOST_ATTRIBUTE_NODISCARD
0151             constexpr decltype(auto) which(std::reference_wrapper<boost::optional<expectation_failure<Iterator>>> const& failure) noexcept { return failure.get()->which(); }
0152         } // expectation_failure_helpers
0153 
0154         using expectation_failure_helpers::where;
0155         using expectation_failure_helpers::which;
0156 
0157     } // inline namespace BOOST_SPIRIT_X3_EXPECTATION_FAILURE_NS
0158 
0159     #if !BOOST_SPIRIT_X3_THROW_EXPECTATION_FAILURE
0160     namespace detail {
0161         inline namespace BOOST_SPIRIT_X3_EXPECTATION_FAILURE_NS
0162         {
0163             inline constexpr bool has_expectation_failure_impl(unused_type const&) noexcept = delete;
0164 
0165             inline constexpr bool has_expectation_failure_impl(bool& failure) noexcept {
0166                 return failure;
0167             }
0168 
0169             template <typename Iterator>
0170             constexpr bool has_expectation_failure_impl(std::optional<expectation_failure<Iterator>> const& failure) noexcept
0171             {
0172                 return failure.has_value();
0173             }
0174 
0175             template <typename Iterator>
0176             constexpr bool has_expectation_failure_impl(boost::optional<expectation_failure<Iterator>> const& failure) noexcept
0177             {
0178                 return failure.has_value();
0179             }
0180 
0181             template <typename T>
0182             constexpr bool has_expectation_failure_impl(std::reference_wrapper<T> const& ref) noexcept
0183             {
0184                 return has_expectation_failure_impl(ref.get());
0185             }
0186 
0187 
0188             template <typename Iterator, typename T>
0189             constexpr void set_expectation_failure_impl(bool& failure, T&& value)
0190             {
0191                 failure = std::forward<T>(value);
0192             }
0193 
0194             template <typename Iterator, typename T>
0195             constexpr void set_expectation_failure_impl(std::optional<expectation_failure<Iterator>>& failure, T&& value)
0196             {
0197                 failure = std::forward<T>(value);
0198             }
0199 
0200             template <typename Iterator, typename T>
0201             constexpr void set_expectation_failure_impl(boost::optional<expectation_failure<Iterator>>& failure, T&& value)
0202             {
0203                 failure = std::forward<T>(value);
0204             }
0205 
0206             template <typename AnyExpectationFailure, typename T>
0207             constexpr void set_expectation_failure_impl(std::reference_wrapper<AnyExpectationFailure>& failure, T&& value)
0208             {
0209                 set_expectation_failure_impl(failure.get(), std::forward<T>(value));
0210             }
0211 
0212 
0213             template <typename Iterator>
0214             constexpr void clear_expectation_failure_impl(unused_type const&) noexcept = delete;
0215 
0216             template <typename Iterator>
0217             constexpr void clear_expectation_failure_impl(bool& failure) noexcept
0218             {
0219                 failure = false;
0220             }
0221 
0222             template <typename Iterator>
0223             constexpr void clear_expectation_failure_impl(std::optional<expectation_failure<Iterator>>& failure) noexcept
0224             {
0225                 failure.reset();
0226             }
0227 
0228             template <typename Iterator>
0229             constexpr void clear_expectation_failure_impl(boost::optional<expectation_failure<Iterator>>& failure) noexcept
0230             {
0231                 failure.reset();
0232             }
0233 
0234             template <typename T>
0235             constexpr void clear_expectation_failure_impl(std::reference_wrapper<T>& ref) noexcept
0236             {
0237                 return clear_expectation_failure_impl(ref.get());
0238             }
0239         } // inline namespace BOOST_SPIRIT_X3_EXPECTATION_FAILURE_NS
0240     } // detail
0241     #endif
0242 
0243     inline namespace BOOST_SPIRIT_X3_EXPECTATION_FAILURE_NS
0244     {
0245         template <typename Context>
0246         BOOST_ATTRIBUTE_NODISCARD
0247         constexpr bool has_expectation_failure(Context const& context) noexcept {
0248         #if BOOST_SPIRIT_X3_THROW_EXPECTATION_FAILURE
0249             boost::ignore_unused(context);
0250             return false;
0251         #else
0252             using T = expectation_failure_t<Context>;
0253             static_assert(
0254                 !std::is_same_v<unused_type, T>,
0255                 "Context type was not specified for x3::expectation_failure_tag. "
0256                 "You probably forgot: `x3::with<x3::expectation_failure_tag>(failure)[p]`. "
0257                 "Note that you must also bind the context to your skipper."
0258             );
0259             return detail::has_expectation_failure_impl(
0260                 x3::get<expectation_failure_tag>(context));
0261         #endif
0262         }
0263 
0264         //
0265         // Creation of a brand new expectation_failure instance.
0266         // This is the primary overload.
0267         //
0268         template <typename Iterator, typename Subject, typename Context>
0269         constexpr void set_expectation_failure(
0270             Iterator const& where,
0271             Subject const& subject,
0272             Context const& context
0273         ) {
0274         #if BOOST_SPIRIT_X3_THROW_EXPECTATION_FAILURE
0275             boost::ignore_unused(where, subject, context);
0276 
0277         #else
0278             using T = expectation_failure_t<Context>;
0279             static_assert(
0280                 !std::is_same_v<unused_type, T>,
0281                 "Context type was not specified for x3::expectation_failure_tag. "
0282                 "You probably forgot: `x3::with<x3::expectation_failure_tag>(failure)[p]`. "
0283                 "Note that you must also bind the context to your skipper."
0284             );
0285 
0286             if constexpr (std::is_same_v<T, bool>)
0287             {
0288                 boost::ignore_unused(where, subject);
0289                 detail::set_expectation_failure_impl(
0290                     x3::get<expectation_failure_tag>(context),
0291                     true);
0292             }
0293             else
0294             {
0295                 detail::set_expectation_failure_impl(
0296                     x3::get<expectation_failure_tag>(context),
0297                     expectation_failure<Iterator>(where, what(subject)));
0298             }
0299         #endif
0300         }
0301 
0302         //
0303         // Copy-assignment of existing expectation_failure instance.
0304         //
0305         // When you're in the situation where this functionality is
0306         // *really* needed, it essentially means that you have
0307         // multiple valid exceptions at the same time.
0308         //
0309         // There are only two decent situations that I can think of:
0310         //
0311         //   (a) When you are writing a custom parser procedure with very specific characteristics:
0312         //       1. You're forking a context.
0313         //       2. Your parser class has delegated some process to child parser(s).
0314         //       3. The child parser(s) have raised an exceptation_failure.
0315         //       4. You need to propagate the failure back to the parent context.
0316         //
0317         //   (b) When you truly need a nested exception.
0318         //       That is, you're trying to preserve a nested exception structure
0319         //       raised by nested directive: e.g. `x3::expect[x3::expect[p]]`.
0320         //       Note that all builtin primitives just save the first error,
0321         //       so this structure does not exist in core (as of now).
0322         //
0323         template <typename AnyExpectationFailure, typename Context>
0324         constexpr void set_expectation_failure(
0325             AnyExpectationFailure const& existing_failure,
0326             Context const& context
0327         ) {
0328         #if BOOST_SPIRIT_X3_THROW_EXPECTATION_FAILURE
0329             boost::ignore_unused(existing_failure, context);
0330 
0331         #else
0332             using T = expectation_failure_t<Context>;
0333             static_assert(
0334                 !std::is_same_v<T, unused_type>,
0335                 "Context type was not specified for x3::expectation_failure_tag. "
0336                 "You probably forgot: `x3::with<x3::expectation_failure_tag>(failure)[p]`. "
0337                 "Note that you must also bind the context to your skipper."
0338             );
0339 
0340             static_assert(
0341                 std::is_assignable_v<T, AnyExpectationFailure const&>,
0342                 "previous/current expectation failure types should be compatible"
0343             );
0344 
0345             detail::set_expectation_failure_impl(
0346                 x3::get<expectation_failure_tag>(context), existing_failure);
0347         #endif
0348         }
0349 
0350     #if BOOST_SPIRIT_X3_THROW_EXPECTATION_FAILURE
0351         template <typename Context>
0352         constexpr decltype(auto) get_expectation_failure(Context const&) = delete;
0353 
0354     #else
0355         template <typename Context>
0356         BOOST_ATTRIBUTE_NODISCARD
0357         constexpr decltype(auto) get_expectation_failure(Context const& context)
0358         {
0359             using T = expectation_failure_t<Context>;
0360             static_assert(
0361                 !std::is_same_v<T, unused_type>,
0362                 "Context type was not specified for x3::expectation_failure_tag. "
0363                 "You probably forgot: `x3::with<x3::expectation_failure_tag>(failure)[p]`. "
0364                 "Note that you must also bind the context to your skipper."
0365             );
0366 
0367             return x3::get<expectation_failure_tag>(context);
0368         }
0369     #endif
0370 
0371         template <typename Context>
0372         constexpr void clear_expectation_failure(Context const& context) noexcept
0373         {
0374         #if BOOST_SPIRIT_X3_THROW_EXPECTATION_FAILURE
0375             boost::ignore_unused(context);
0376         #else
0377             using T = expectation_failure_t<Context>;
0378             static_assert(
0379                 !std::is_same_v<T, unused_type>,
0380                 "Context type was not specified for x3::expectation_failure_tag. "
0381                 "You probably forgot: `x3::with<x3::expectation_failure_tag>(failure)[p]`. "
0382                 "Note that you must also bind the context to your skipper."
0383             );
0384             detail::clear_expectation_failure_impl(
0385                 x3::get<expectation_failure_tag>(context));
0386         #endif
0387         }
0388 
0389     } // inline namespace BOOST_SPIRIT_X3_EXPECTATION_FAILURE_NS
0390 }}}
0391 
0392 #endif