rule.hpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371
  1. /*=============================================================================
  2. Copyright (c) 2001-2014 Joel de Guzman
  3. Copyright (c) 2017 wanghan02
  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_DETAIL_RULE_JAN_08_2012_0326PM)
  9. #define BOOST_SPIRIT_X3_DETAIL_RULE_JAN_08_2012_0326PM
  10. #include <boost/core/ignore_unused.hpp>
  11. #include <boost/spirit/home/x3/auxiliary/guard.hpp>
  12. #include <boost/spirit/home/x3/core/parser.hpp>
  13. #include <boost/spirit/home/x3/core/skip_over.hpp>
  14. #include <boost/spirit/home/x3/support/expectation.hpp>
  15. #include <boost/spirit/home/x3/directive/expect.hpp>
  16. #include <boost/spirit/home/x3/nonterminal/detail/transform_attribute.hpp>
  17. #include <boost/utility/addressof.hpp>
  18. #if defined(BOOST_SPIRIT_X3_DEBUG)
  19. #include <boost/spirit/home/x3/nonterminal/simple_trace.hpp>
  20. #endif
  21. #include <type_traits>
  22. namespace boost { namespace spirit { namespace x3
  23. {
  24. template <typename ID>
  25. struct identity;
  26. template <typename ID, typename Attribute = unused_type, bool force_attribute = false>
  27. struct rule;
  28. struct parse_pass_context_tag;
  29. namespace detail
  30. {
  31. template <typename ID>
  32. struct rule_id {};
  33. // we use this so we can detect if the default parse_rule
  34. // is the being called.
  35. struct default_parse_rule_result
  36. {
  37. default_parse_rule_result(bool r)
  38. : r(r) {}
  39. operator bool() const { return r; }
  40. bool r;
  41. };
  42. }
  43. // default parse_rule implementation
  44. template <typename ID, typename Iterator
  45. , typename Context, typename ActualAttribute>
  46. inline detail::default_parse_rule_result
  47. parse_rule(
  48. detail::rule_id<ID>
  49. , Iterator& first, Iterator const& last
  50. , Context const& context, ActualAttribute& attr);
  51. }}}
  52. namespace boost { namespace spirit { namespace x3 { namespace detail
  53. {
  54. #if defined(BOOST_SPIRIT_X3_DEBUG)
  55. template <typename Iterator, typename Attribute>
  56. struct context_debug
  57. {
  58. context_debug(
  59. char const* rule_name
  60. , Iterator const& first, Iterator const& last
  61. , Attribute const& attr
  62. , bool const& ok_parse //was parse successful?
  63. )
  64. : ok_parse(ok_parse), rule_name(rule_name)
  65. , first(first), last(last)
  66. , attr(attr)
  67. , f(detail::get_simple_trace())
  68. {
  69. f(first, last, attr, pre_parse, rule_name);
  70. }
  71. ~context_debug()
  72. {
  73. auto status = ok_parse ? successful_parse : failed_parse ;
  74. f(first, last, attr, status, rule_name);
  75. }
  76. bool const& ok_parse;
  77. char const* rule_name;
  78. Iterator const& first;
  79. Iterator const& last;
  80. Attribute const& attr;
  81. detail::simple_trace_type& f;
  82. };
  83. #endif
  84. template <typename ID, typename Iterator, typename Context, typename Enable = void>
  85. struct has_on_error : mpl::false_ {};
  86. template <typename ID, typename Iterator, typename Context>
  87. struct has_on_error<ID, Iterator, Context,
  88. decltype(void(
  89. std::declval<ID>().on_error(
  90. std::declval<Iterator&>()
  91. , std::declval<Iterator>()
  92. , std::declval<expectation_failure<Iterator>>()
  93. , std::declval<Context>()
  94. )
  95. ))
  96. >
  97. : mpl::true_
  98. {};
  99. template <typename ID, typename Iterator, typename Attribute, typename Context, typename Enable = void>
  100. struct has_on_success : mpl::false_ {};
  101. template <typename ID, typename Iterator, typename Attribute, typename Context>
  102. struct has_on_success<ID, Iterator, Context, Attribute,
  103. decltype(void(
  104. std::declval<ID>().on_success(
  105. std::declval<Iterator&>()
  106. , std::declval<Iterator&>()
  107. , std::declval<Attribute&>()
  108. , std::declval<Context>()
  109. )
  110. ))
  111. >
  112. : mpl::true_
  113. {};
  114. template <typename ID>
  115. struct make_id
  116. {
  117. typedef identity<ID> type;
  118. };
  119. template <typename ID>
  120. struct make_id<identity<ID>>
  121. {
  122. typedef identity<ID> type;
  123. };
  124. template <typename ID, typename RHS, typename Context>
  125. Context const&
  126. make_rule_context(RHS const& /* rhs */, Context const& context
  127. , mpl::false_ /* is_default_parse_rule */)
  128. {
  129. return context;
  130. }
  131. template <typename ID, typename RHS, typename Context>
  132. auto make_rule_context(RHS const& rhs, Context const& context
  133. , mpl::true_ /* is_default_parse_rule */ )
  134. {
  135. return make_unique_context<ID>(rhs, context);
  136. }
  137. template <typename Attribute, typename ID, bool skip_definition_injection = false>
  138. struct rule_parser
  139. {
  140. template <typename Iterator, typename Context, typename ActualAttribute>
  141. static bool call_on_success(
  142. Iterator& /* before */, Iterator& /* after */
  143. , Context const& /* context */, ActualAttribute& /* attr */
  144. , mpl::false_ /* No on_success handler */ )
  145. {
  146. return true;
  147. }
  148. template <typename Iterator, typename Context, typename ActualAttribute>
  149. static bool call_on_success(
  150. Iterator& before, Iterator& after
  151. , Context const& context, ActualAttribute& attr
  152. , mpl::true_ /* Has on_success handler */)
  153. {
  154. x3::skip_over(before, after, context);
  155. bool pass = true;
  156. ID().on_success(
  157. before
  158. , after
  159. , attr
  160. , make_context<parse_pass_context_tag>(pass, context)
  161. );
  162. return pass;
  163. }
  164. template <typename RHS, typename Iterator, typename Context
  165. , typename RContext, typename ActualAttribute>
  166. static bool parse_rhs_main(
  167. RHS const& rhs
  168. , Iterator& first, Iterator const& last
  169. , Context const& context, RContext& rcontext, ActualAttribute& attr
  170. , mpl::false_)
  171. {
  172. // see if the user has a BOOST_SPIRIT_DEFINE for this rule
  173. typedef
  174. decltype(parse_rule(
  175. detail::rule_id<ID>{}, first, last
  176. , make_unique_context<ID>(rhs, context), std::declval<Attribute&>()))
  177. parse_rule_result;
  178. // If there is no BOOST_SPIRIT_DEFINE for this rule,
  179. // we'll make a context for this rule tagged by its ID
  180. // so we can extract the rule later on in the default
  181. // (generic) parse_rule function.
  182. typedef
  183. is_same<parse_rule_result, default_parse_rule_result>
  184. is_default_parse_rule;
  185. Iterator start = first;
  186. bool r = rhs.parse(
  187. first
  188. , last
  189. , make_rule_context<ID>(rhs, context, std::conditional_t<skip_definition_injection, mpl::false_, is_default_parse_rule>())
  190. , rcontext
  191. , attr
  192. );
  193. if (r)
  194. {
  195. r = call_on_success(start, first, context, attr
  196. , has_on_success<ID, Iterator, Context, ActualAttribute>());
  197. }
  198. return r;
  199. }
  200. template <typename RHS, typename Iterator, typename Context
  201. , typename RContext, typename ActualAttribute>
  202. static bool parse_rhs_main(
  203. RHS const& rhs
  204. , Iterator& first, Iterator const& last
  205. , Context const& context, RContext& rcontext, ActualAttribute& attr
  206. , mpl::true_ /* on_error is found */)
  207. {
  208. for (;;)
  209. {
  210. #if BOOST_SPIRIT_X3_THROW_EXPECTATION_FAILURE
  211. try
  212. #endif
  213. {
  214. if (parse_rhs_main(
  215. rhs, first, last, context, rcontext, attr, mpl::false_()))
  216. {
  217. return true;
  218. }
  219. }
  220. #if BOOST_SPIRIT_X3_THROW_EXPECTATION_FAILURE
  221. catch (expectation_failure<Iterator> const& x) {
  222. #else
  223. if (has_expectation_failure(context)) {
  224. auto& x = get_expectation_failure(context);
  225. #endif
  226. // X3 developer note: don't forget to sync this implementation with x3::guard
  227. switch (ID().on_error(first, last, x, context))
  228. {
  229. case error_handler_result::fail:
  230. clear_expectation_failure(context);
  231. return false;
  232. case error_handler_result::retry:
  233. continue;
  234. case error_handler_result::accept:
  235. return true;
  236. case error_handler_result::rethrow:
  237. #if BOOST_SPIRIT_X3_THROW_EXPECTATION_FAILURE
  238. throw;
  239. #else
  240. return false; // TODO: design decision required
  241. #endif
  242. }
  243. }
  244. return false;
  245. }
  246. }
  247. template <typename RHS, typename Iterator
  248. , typename Context, typename RContext, typename ActualAttribute>
  249. static bool parse_rhs_main(
  250. RHS const& rhs
  251. , Iterator& first, Iterator const& last
  252. , Context const& context, RContext& rcontext, ActualAttribute& attr)
  253. {
  254. return parse_rhs_main(
  255. rhs, first, last, context, rcontext, attr
  256. , has_on_error<ID, Iterator, Context>()
  257. );
  258. }
  259. template <typename RHS, typename Iterator
  260. , typename Context, typename RContext, typename ActualAttribute>
  261. static bool parse_rhs(
  262. RHS const& rhs
  263. , Iterator& first, Iterator const& last
  264. , Context const& context, RContext& rcontext, ActualAttribute& attr
  265. , mpl::false_)
  266. {
  267. return parse_rhs_main(rhs, first, last, context, rcontext, attr);
  268. }
  269. template <typename RHS, typename Iterator
  270. , typename Context, typename RContext, typename ActualAttribute>
  271. static bool parse_rhs(
  272. RHS const& rhs
  273. , Iterator& first, Iterator const& last
  274. , Context const& context, RContext& rcontext, ActualAttribute& /* attr */
  275. , mpl::true_)
  276. {
  277. return parse_rhs_main(rhs, first, last, context, rcontext, unused);
  278. }
  279. template <typename RHS, typename Iterator, typename Context
  280. , typename ActualAttribute, typename ExplicitAttrPropagation>
  281. static bool call_rule_definition(
  282. RHS const& rhs
  283. , char const* rule_name
  284. , Iterator& first, Iterator const& last
  285. , Context const& context, ActualAttribute& attr
  286. , ExplicitAttrPropagation)
  287. {
  288. boost::ignore_unused(rule_name);
  289. // do down-stream transformation, provides attribute for
  290. // rhs parser
  291. typedef traits::transform_attribute<
  292. ActualAttribute, Attribute, parser_id>
  293. transform;
  294. typedef typename transform::type transform_attr;
  295. transform_attr attr_ = transform::pre(attr);
  296. bool ok_parse
  297. //Creates a place to hold the result of parse_rhs
  298. //called inside the following scope.
  299. ;
  300. {
  301. // Create a scope to cause the dbg variable below (within
  302. // the #if...#endif) to call it's DTOR before any
  303. // modifications are made to the attribute, attr_ passed
  304. // to parse_rhs (such as might be done in
  305. // transform::post when, for example,
  306. // ActualAttribute is a recursive variant).
  307. #if defined(BOOST_SPIRIT_X3_DEBUG)
  308. context_debug<Iterator, transform_attr>
  309. dbg(rule_name, first, last, attr_, ok_parse);
  310. #endif
  311. ok_parse = parse_rhs(rhs, first, last, context, attr_, attr_
  312. , mpl::bool_
  313. < ( RHS::has_action
  314. && !ExplicitAttrPropagation::value
  315. )
  316. >()
  317. );
  318. }
  319. if (ok_parse)
  320. {
  321. // do up-stream transformation, this integrates the results
  322. // back into the original attribute value, if appropriate
  323. transform::post(attr, std::forward<transform_attr>(attr_));
  324. }
  325. return ok_parse;
  326. }
  327. };
  328. }}}}
  329. #endif