skip.hpp 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. /*=============================================================================
  2. Copyright (c) 2001-2014 Joel de Guzman
  3. Copyright (c) 2013 Agustin Berge
  4. Copyright (c) 2024 Nana Sakisaka
  5. Distributed under the Boost Software License, Version 1.0. (See accompanying
  6. file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  7. =============================================================================*/
  8. #if !defined(BOOST_SPIRIT_X3_SKIP_JANUARY_26_2008_0422PM)
  9. #define BOOST_SPIRIT_X3_SKIP_JANUARY_26_2008_0422PM
  10. #include <boost/spirit/home/x3/support/context.hpp>
  11. #include <boost/spirit/home/x3/support/unused.hpp>
  12. #include <boost/spirit/home/x3/support/expectation.hpp>
  13. #include <boost/spirit/home/x3/core/skip_over.hpp>
  14. #include <boost/spirit/home/x3/core/parser.hpp>
  15. #include <boost/utility/enable_if.hpp>
  16. namespace boost { namespace spirit { namespace x3
  17. {
  18. template <typename Subject>
  19. struct reskip_directive : unary_parser<Subject, reskip_directive<Subject>>
  20. {
  21. typedef unary_parser<Subject, reskip_directive<Subject>> base_type;
  22. static bool const is_pass_through_unary = true;
  23. static bool const handles_container = Subject::handles_container;
  24. constexpr reskip_directive(Subject const& subject)
  25. : base_type(subject) {}
  26. template <typename Iterator, typename Context
  27. , typename RContext, typename Attribute>
  28. typename disable_if<has_skipper<Context>, bool>::type
  29. parse(Iterator& first, Iterator const& last
  30. , Context& context, RContext& rcontext, Attribute& attr) const
  31. {
  32. auto const& skipper =
  33. detail::get_unused_skipper(x3::get<skipper_tag>(context));
  34. auto const local_ctx = make_context<skipper_tag>(skipper, context);
  35. bool const r = this->subject.parse(first, last, local_ctx, rcontext, attr);
  36. #if !BOOST_SPIRIT_X3_THROW_EXPECTATION_FAILURE
  37. if (has_expectation_failure(local_ctx))
  38. {
  39. set_expectation_failure(get_expectation_failure(local_ctx), context);
  40. }
  41. #endif
  42. return r;
  43. }
  44. template <typename Iterator, typename Context
  45. , typename RContext, typename Attribute>
  46. typename enable_if<has_skipper<Context>, bool>::type
  47. parse(Iterator& first, Iterator const& last
  48. , Context const& context, RContext& rcontext, Attribute& attr) const
  49. {
  50. return this->subject.parse(first, last, context, rcontext, attr);
  51. }
  52. };
  53. template <typename Subject, typename Skipper>
  54. struct skip_directive : unary_parser<Subject, skip_directive<Subject, Skipper>>
  55. {
  56. typedef unary_parser<Subject, skip_directive<Subject, Skipper>> base_type;
  57. static bool const is_pass_through_unary = true;
  58. static bool const handles_container = Subject::handles_container;
  59. constexpr skip_directive(Subject const& subject, Skipper const& skipper)
  60. : base_type(subject)
  61. , skipper(skipper)
  62. {}
  63. template <typename Iterator, typename RContext, typename Attribute>
  64. bool parse(Iterator& first, Iterator const& last
  65. , unused_type const&, RContext& rcontext, Attribute& attr) const
  66. {
  67. // It is perfectly fine to omit the expectation_failure context
  68. // even in non-throwing mode if and only if the skipper itself
  69. // is expectation-less.
  70. //
  71. // For example:
  72. // skip(a > b) [lit('foo')]
  73. // skip(c >> d)[lit('foo')]
  74. // `a > b` should require non-`unused_type` context, but
  75. // `c >> d` should NOT require non-`unused_type` context
  76. //
  77. // However, it's impossible right now to detect whether
  78. // `this->subject` actually is expectation-less, so we just
  79. // call the parse function to see what will happen. If the
  80. // subject turns out to lack the expectation context,
  81. // static_assert will be engaged in other locations.
  82. //
  83. // Anyways, we don't need to repack the expectation context
  84. // into our brand new skipper context, in contrast to the
  85. // repacking process done in `x3::skip_over`.
  86. return this->subject.parse(first, last,
  87. make_context<skipper_tag>(skipper), rcontext, attr);
  88. }
  89. template <typename Iterator, typename Context, typename RContext, typename Attribute>
  90. bool parse(Iterator& first, Iterator const& last
  91. , Context const& context, RContext& rcontext, Attribute& attr) const
  92. {
  93. #if BOOST_SPIRIT_X3_THROW_EXPECTATION_FAILURE
  94. return this->subject.parse(first, last, make_context<skipper_tag>(skipper, context), rcontext, attr);
  95. #else
  96. static_assert(
  97. !std::is_same_v<expectation_failure_t<Context>, unused_type>,
  98. "Context type was not specified for x3::expectation_failure_tag. "
  99. "You probably forgot: `x3::with<x3::expectation_failure_tag>(failure)[p]`. "
  100. "Note that you must also bind the context to your skipper.");
  101. // This logic is heavily related to the instantiation chain;
  102. // see `x3::skip_over` for details.
  103. auto const local_ctx = make_context<skipper_tag>(skipper, context);
  104. bool const r = this->subject.parse(first, last, local_ctx, rcontext, attr);
  105. if (has_expectation_failure(local_ctx))
  106. {
  107. set_expectation_failure(get_expectation_failure(local_ctx), context);
  108. }
  109. return r;
  110. #endif
  111. }
  112. Skipper const skipper;
  113. };
  114. struct reskip_gen
  115. {
  116. template <typename Skipper>
  117. struct skip_gen
  118. {
  119. constexpr skip_gen(Skipper const& skipper)
  120. : skipper_(skipper) {}
  121. template <typename Subject>
  122. constexpr skip_directive<typename extension::as_parser<Subject>::value_type, Skipper>
  123. operator[](Subject const& subject) const
  124. {
  125. return { as_parser(subject), skipper_ };
  126. }
  127. Skipper skipper_;
  128. };
  129. template <typename Skipper>
  130. constexpr skip_gen<Skipper> const operator()(Skipper const& skipper) const
  131. {
  132. return { skipper };
  133. }
  134. template <typename Subject>
  135. constexpr reskip_directive<typename extension::as_parser<Subject>::value_type>
  136. operator[](Subject const& subject) const
  137. {
  138. return { as_parser(subject) };
  139. }
  140. };
  141. constexpr auto skip = reskip_gen{};
  142. }}}
  143. #endif