subrule.hpp 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610
  1. /*=============================================================================
  2. Copyright (c) 2009 Francois Barel
  3. Copyright (c) 2001-2011 Joel de Guzman
  4. Distributed under the Boost Software License, Version 1.0. (See accompanying
  5. file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  6. ==============================================================================*/
  7. #if !defined(BOOST_SPIRIT_REPOSITORY_QI_SUBRULE_AUGUST_06_2009_0239AM)
  8. #define BOOST_SPIRIT_REPOSITORY_QI_SUBRULE_AUGUST_06_2009_0239AM
  9. #if defined(_MSC_VER)
  10. #pragma once
  11. #endif
  12. #include <boost/spirit/home/qi/domain.hpp>
  13. #include <boost/spirit/home/qi/meta_compiler.hpp>
  14. #include <boost/spirit/home/qi/parser.hpp>
  15. #include <boost/spirit/home/qi/reference.hpp>
  16. #include <boost/spirit/home/qi/nonterminal/detail/parameterized.hpp>
  17. #include <boost/spirit/home/qi/nonterminal/detail/parser_binder.hpp>
  18. #include <boost/spirit/home/support/argument.hpp>
  19. #include <boost/spirit/home/support/assert_msg.hpp>
  20. #include <boost/spirit/home/qi/detail/attributes.hpp>
  21. #include <boost/spirit/home/support/info.hpp>
  22. #include <boost/spirit/home/support/unused.hpp>
  23. #include <boost/spirit/home/support/nonterminal/extract_param.hpp>
  24. #include <boost/spirit/home/support/nonterminal/locals.hpp>
  25. #include <boost/spirit/repository/home/support/subrule_context.hpp>
  26. #include <boost/static_assert.hpp>
  27. #include <boost/fusion/include/as_map.hpp>
  28. #include <boost/fusion/include/at_key.hpp>
  29. #include <boost/fusion/include/cons.hpp>
  30. #include <boost/fusion/include/front.hpp>
  31. #include <boost/fusion/include/has_key.hpp>
  32. #include <boost/fusion/include/join.hpp>
  33. #include <boost/fusion/include/make_map.hpp>
  34. #include <boost/fusion/include/make_vector.hpp>
  35. #include <boost/fusion/include/size.hpp>
  36. #include <boost/fusion/include/vector.hpp>
  37. #include <boost/mpl/bool.hpp>
  38. #include <boost/mpl/identity.hpp>
  39. #include <boost/mpl/int.hpp>
  40. #include <boost/mpl/vector.hpp>
  41. #include <boost/proto/extends.hpp>
  42. #include <boost/proto/traits.hpp>
  43. #include <boost/type_traits/is_reference.hpp>
  44. #include <boost/type_traits/is_same.hpp>
  45. #include <boost/type_traits/remove_reference.hpp>
  46. #if defined(BOOST_MSVC)
  47. # pragma warning(push)
  48. # pragma warning(disable: 4355) // 'this' : used in base member initializer list warning
  49. #endif
  50. ///////////////////////////////////////////////////////////////////////////////
  51. namespace boost { namespace spirit { namespace repository { namespace qi
  52. {
  53. ///////////////////////////////////////////////////////////////////////////
  54. // subrule_group_parser:
  55. // - parser representing a group of subrule definitions (one or more),
  56. // invokes first subrule on entry,
  57. ///////////////////////////////////////////////////////////////////////////
  58. template <typename Defs>
  59. struct subrule_group_parser
  60. : spirit::qi::parser<subrule_group_parser<Defs> >
  61. {
  62. // Fusion associative sequence, associating each subrule ID in this
  63. // group (as an MPL integral constant) with its definition
  64. typedef Defs defs_type;
  65. typedef subrule_group_parser<Defs> this_type;
  66. explicit subrule_group_parser(Defs const& defs)
  67. : defs(defs)
  68. {
  69. }
  70. // from a subrule ID, get the type of a reference to its definition
  71. template <int ID>
  72. struct def_type
  73. {
  74. typedef mpl::int_<ID> id_type;
  75. // If you are seeing a compilation error here, you are trying
  76. // to use a subrule which was not defined in this group.
  77. BOOST_SPIRIT_ASSERT_MSG(
  78. (fusion::result_of::has_key<
  79. defs_type const, id_type>::type::value)
  80. , subrule_used_without_being_defined, (mpl::int_<ID>));
  81. typedef typename
  82. fusion::result_of::at_key<defs_type const, id_type>::type
  83. type;
  84. };
  85. // from a subrule ID, get a reference to its definition
  86. template <int ID>
  87. typename def_type<ID>::type def() const
  88. {
  89. return fusion::at_key<mpl::int_<ID> >(defs);
  90. }
  91. template <typename Context, typename Iterator>
  92. struct attribute
  93. // Forward to first subrule.
  94. : mpl::identity<
  95. typename remove_reference<
  96. typename fusion::result_of::front<Defs>::type
  97. >::type::second_type::attr_type> {};
  98. template <typename Iterator, typename Context
  99. , typename Skipper, typename Attribute>
  100. bool parse(Iterator& first, Iterator const& last
  101. , Context& context, Skipper const& skipper
  102. , Attribute& attr) const
  103. {
  104. // Forward to first subrule.
  105. return parse_subrule(fusion::front(defs).second
  106. , first, last, context, skipper, attr);
  107. }
  108. template <typename Iterator, typename Context
  109. , typename Skipper, typename Attribute, typename Params>
  110. bool parse(Iterator& first, Iterator const& last
  111. , Context& context, Skipper const& skipper
  112. , Attribute& attr, Params const& params) const
  113. {
  114. // Forward to first subrule.
  115. return parse_subrule(fusion::front(defs).second
  116. , first, last, context, skipper, attr, params);
  117. }
  118. template <int ID, typename Iterator, typename Context
  119. , typename Skipper, typename Attribute>
  120. bool parse_subrule_id(Iterator& first, Iterator const& last
  121. , Context& context, Skipper const& skipper
  122. , Attribute& attr) const
  123. {
  124. return parse_subrule(def<ID>()
  125. , first, last, context, skipper, attr);
  126. }
  127. template <int ID, typename Iterator, typename Context
  128. , typename Skipper, typename Attribute, typename Params>
  129. bool parse_subrule_id(Iterator& first, Iterator const& last
  130. , Context& context, Skipper const& skipper
  131. , Attribute& attr, Params const& params) const
  132. {
  133. return parse_subrule(def<ID>()
  134. , first, last, context, skipper, attr, params);
  135. }
  136. template <typename Def
  137. , typename Iterator, typename Context
  138. , typename Skipper, typename Attribute>
  139. bool parse_subrule(Def const& def
  140. , Iterator& first, Iterator const& last
  141. , Context& /*caller_context*/, Skipper const& skipper
  142. , Attribute& attr) const
  143. {
  144. // compute context type for this subrule
  145. typedef typename Def::locals_type subrule_locals_type;
  146. typedef typename Def::attr_type subrule_attr_type;
  147. typedef typename Def::attr_reference_type subrule_attr_reference_type;
  148. typedef typename Def::parameter_types subrule_parameter_types;
  149. typedef
  150. subrule_context<
  151. this_type
  152. , fusion::cons<
  153. subrule_attr_reference_type, subrule_parameter_types>
  154. , subrule_locals_type
  155. >
  156. context_type;
  157. // do down-stream transformation, provides attribute for
  158. // rhs parser
  159. typedef traits::transform_attribute<
  160. Attribute, subrule_attr_type, spirit::qi::domain>
  161. transform;
  162. typename transform::type attr_ = transform::pre(attr);
  163. // If you are seeing a compilation error here, you are probably
  164. // trying to use a subrule which has inherited attributes,
  165. // without passing values for them.
  166. context_type context(*this, attr_);
  167. if (def.binder(first, last, context, skipper))
  168. {
  169. // do up-stream transformation, this integrates the results
  170. // back into the original attribute value, if appropriate
  171. transform::post(attr, attr_);
  172. return true;
  173. }
  174. // inform attribute transformation of failed rhs
  175. transform::fail(attr);
  176. return false;
  177. }
  178. template <typename Def
  179. , typename Iterator, typename Context
  180. , typename Skipper, typename Attribute, typename Params>
  181. bool parse_subrule(Def const& def
  182. , Iterator& first, Iterator const& last
  183. , Context& caller_context, Skipper const& skipper
  184. , Attribute& attr, Params const& params) const
  185. {
  186. // compute context type for this subrule
  187. typedef typename Def::locals_type subrule_locals_type;
  188. typedef typename Def::attr_type subrule_attr_type;
  189. typedef typename Def::attr_reference_type subrule_attr_reference_type;
  190. typedef typename Def::parameter_types subrule_parameter_types;
  191. typedef
  192. subrule_context<
  193. this_type
  194. , fusion::cons<
  195. subrule_attr_reference_type, subrule_parameter_types>
  196. , subrule_locals_type
  197. >
  198. context_type;
  199. // do down-stream transformation, provides attribute for
  200. // rhs parser
  201. typedef traits::transform_attribute<
  202. Attribute, subrule_attr_type, spirit::qi::domain>
  203. transform;
  204. typename transform::type attr_ = transform::pre(attr);
  205. // If you are seeing a compilation error here, you are probably
  206. // trying to use a subrule which has inherited attributes,
  207. // passing values of incompatible types for them.
  208. context_type context(*this, attr_, params, caller_context);
  209. if (def.binder(first, last, context, skipper))
  210. {
  211. // do up-stream transformation, this integrates the results
  212. // back into the original attribute value, if appropriate
  213. transform::post(attr, attr_);
  214. return true;
  215. }
  216. // inform attribute transformation of failed rhs
  217. transform::fail(attr);
  218. return false;
  219. }
  220. template <typename Context>
  221. info what(Context& context) const
  222. {
  223. // Forward to first subrule.
  224. return fusion::front(defs).second.binder.p.what(context);
  225. }
  226. Defs defs;
  227. };
  228. ///////////////////////////////////////////////////////////////////////////
  229. // subrule_group:
  230. // - a Proto terminal, so that a group behaves like any Spirit
  231. // expression.
  232. ///////////////////////////////////////////////////////////////////////////
  233. template <typename Defs>
  234. struct subrule_group
  235. : proto::extends<
  236. typename proto::terminal<
  237. subrule_group_parser<Defs>
  238. >::type
  239. , subrule_group<Defs>
  240. >
  241. {
  242. typedef subrule_group_parser<Defs> parser_type;
  243. typedef typename proto::terminal<parser_type>::type terminal;
  244. static size_t const params_size =
  245. // Forward to first subrule.
  246. remove_reference<
  247. typename fusion::result_of::front<Defs>::type
  248. >::type::second_type::params_size;
  249. explicit subrule_group(Defs const& defs)
  250. : subrule_group::proto_extends(terminal::make(parser_type(defs)))
  251. {
  252. }
  253. parser_type const& parser() const { return proto::value(*this); }
  254. Defs const& defs() const { return parser().defs; }
  255. template <typename Defs2>
  256. subrule_group<
  257. typename fusion::result_of::as_map<
  258. typename fusion::result_of::join<
  259. Defs const, Defs2 const>::type>::type>
  260. operator,(subrule_group<Defs2> const& other) const
  261. {
  262. typedef subrule_group<
  263. typename fusion::result_of::as_map<
  264. typename fusion::result_of::join<
  265. Defs const, Defs2 const>::type>::type> result_type;
  266. return result_type(fusion::as_map(fusion::join(defs(), other.defs())));
  267. }
  268. // non-const versions needed to suppress proto's comma op kicking in
  269. template <typename Defs2>
  270. friend subrule_group<
  271. typename fusion::result_of::as_map<
  272. typename fusion::result_of::join<
  273. Defs const, Defs2 const>::type>::type>
  274. #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
  275. operator,(subrule_group&& left, subrule_group<Defs2>&& other)
  276. #else
  277. operator,(subrule_group& left, subrule_group<Defs2>& other)
  278. #endif
  279. {
  280. return static_cast<subrule_group const&>(left)
  281. .operator,(static_cast<subrule_group<Defs2> const&>(other));
  282. }
  283. // bring in the operator() overloads
  284. parser_type const& get_parameterized_subject() const { return parser(); }
  285. typedef parser_type parameterized_subject_type;
  286. #include <boost/spirit/home/qi/nonterminal/detail/fcall.hpp>
  287. };
  288. ///////////////////////////////////////////////////////////////////////////
  289. // subrule_definition: holds one particular definition of a subrule
  290. ///////////////////////////////////////////////////////////////////////////
  291. template <
  292. int ID_
  293. , typename Locals
  294. , typename Attr
  295. , typename AttrRef
  296. , typename Parameters
  297. , size_t ParamsSize
  298. , typename Subject
  299. , bool Auto_
  300. >
  301. struct subrule_definition
  302. {
  303. typedef mpl::int_<ID_> id_type;
  304. BOOST_STATIC_CONSTANT(int, ID = ID_);
  305. typedef Locals locals_type;
  306. typedef Attr attr_type;
  307. typedef AttrRef attr_reference_type;
  308. typedef Parameters parameter_types;
  309. static size_t const params_size = ParamsSize;
  310. typedef Subject subject_type;
  311. typedef mpl::bool_<Auto_> auto_type;
  312. BOOST_STATIC_CONSTANT(bool, Auto = Auto_);
  313. typedef spirit::qi::detail::parser_binder<
  314. Subject, auto_type> binder_type;
  315. subrule_definition(Subject const& subject, std::string const& name)
  316. : binder(subject), name(name)
  317. {
  318. }
  319. binder_type const binder;
  320. std::string const name;
  321. };
  322. ///////////////////////////////////////////////////////////////////////////
  323. // subrule placeholder:
  324. // - on subrule definition: helper for creation of subrule_group,
  325. // - on subrule invocation: Proto terminal and parser.
  326. ///////////////////////////////////////////////////////////////////////////
  327. template <
  328. int ID_
  329. , typename T1 = unused_type
  330. , typename T2 = unused_type
  331. >
  332. struct subrule
  333. : proto::extends<
  334. typename proto::terminal<
  335. spirit::qi::reference<subrule<ID_, T1, T2> const>
  336. >::type
  337. , subrule<ID_, T1, T2>
  338. >
  339. , spirit::qi::parser<subrule<ID_, T1, T2> >
  340. {
  341. typedef mpl::int_<ID_> id_type;
  342. BOOST_STATIC_CONSTANT(int, ID = ID_);
  343. typedef subrule<ID_, T1, T2> this_type;
  344. typedef spirit::qi::reference<this_type const> reference_;
  345. typedef typename proto::terminal<reference_>::type terminal;
  346. typedef proto::extends<terminal, this_type> base_type;
  347. typedef mpl::vector<T1, T2> template_params;
  348. // The subrule's locals_type: a sequence of types to be used as local variables
  349. typedef typename
  350. spirit::detail::extract_locals<template_params>::type
  351. locals_type;
  352. // The subrule's encoding type
  353. typedef typename
  354. spirit::detail::extract_encoding<template_params>::type
  355. encoding_type;
  356. // The subrule's signature
  357. typedef typename
  358. spirit::detail::extract_sig<template_params, encoding_type
  359. , spirit::qi::domain>::type
  360. sig_type;
  361. // This is the subrule's attribute type
  362. typedef typename
  363. spirit::detail::attr_from_sig<sig_type>::type
  364. attr_type;
  365. BOOST_STATIC_ASSERT_MSG(
  366. !is_reference<attr_type>::value,
  367. "Reference qualifier on Qi subrule attribute type is meaningless");
  368. typedef attr_type& attr_reference_type;
  369. // parameter_types is a sequence of types passed as parameters to the subrule
  370. typedef typename
  371. spirit::detail::params_from_sig<sig_type>::type
  372. parameter_types;
  373. static size_t const params_size =
  374. fusion::result_of::size<parameter_types>::type::value;
  375. explicit subrule(std::string const& name_ = "unnamed-subrule")
  376. : base_type(terminal::make(reference_(*this)))
  377. , name_(name_)
  378. {
  379. }
  380. // compute type of this subrule's definition for expr type Expr
  381. template <typename Expr, bool Auto>
  382. struct def_type_helper
  383. {
  384. // Report invalid expression error as early as possible.
  385. // If you got an error_invalid_expression error message here,
  386. // then the expression (Expr) is not a valid spirit qi expression.
  387. BOOST_SPIRIT_ASSERT_MATCH(spirit::qi::domain, Expr);
  388. typedef typename result_of::compile<
  389. spirit::qi::domain, Expr>::type subject_type;
  390. typedef subrule_definition<
  391. ID_
  392. , locals_type
  393. , attr_type
  394. , attr_reference_type
  395. , parameter_types
  396. , params_size
  397. , subject_type
  398. , Auto
  399. > const type;
  400. };
  401. // compute type of subrule group containing only this
  402. // subrule's definition for expr type Expr
  403. template <typename Expr, bool Auto>
  404. struct group_type_helper
  405. {
  406. typedef typename def_type_helper<Expr, Auto>::type def_type;
  407. // create Defs map with only one entry: (ID -> def)
  408. typedef typename
  409. #ifndef BOOST_FUSION_HAS_VARIADIC_MAP
  410. fusion::result_of::make_map<id_type, def_type>::type
  411. #else
  412. fusion::result_of::make_map<id_type>::template apply<def_type>::type
  413. #endif
  414. defs_type;
  415. typedef subrule_group<defs_type> type;
  416. };
  417. template <typename Expr>
  418. typename group_type_helper<Expr, false>::type
  419. operator=(Expr const& expr) const
  420. {
  421. typedef group_type_helper<Expr, false> helper;
  422. typedef typename helper::def_type def_type;
  423. typedef typename helper::type result_type;
  424. return result_type(fusion::make_map<id_type>(
  425. def_type(compile<spirit::qi::domain>(expr), name_)));
  426. }
  427. #define BOOST_SPIRIT_SUBRULE_MODULUS_ASSIGN_OPERATOR(lhs_ref, rhs_ref) \
  428. template <typename Expr> \
  429. friend typename group_type_helper<Expr, true>::type \
  430. operator%=(subrule lhs_ref sr, Expr rhs_ref expr) \
  431. { \
  432. typedef group_type_helper<Expr, true> helper; \
  433. typedef typename helper::def_type def_type; \
  434. typedef typename helper::type result_type; \
  435. return result_type(fusion::make_map<id_type>( \
  436. def_type(compile<spirit::qi::domain>(expr), sr.name_))); \
  437. } \
  438. /**/
  439. // non-const versions needed to suppress proto's %= kicking in
  440. BOOST_SPIRIT_SUBRULE_MODULUS_ASSIGN_OPERATOR(const&, const&)
  441. #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
  442. BOOST_SPIRIT_SUBRULE_MODULUS_ASSIGN_OPERATOR(const&, &&)
  443. #else
  444. BOOST_SPIRIT_SUBRULE_MODULUS_ASSIGN_OPERATOR(const&, &)
  445. #endif
  446. BOOST_SPIRIT_SUBRULE_MODULUS_ASSIGN_OPERATOR(&, const&)
  447. #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
  448. BOOST_SPIRIT_SUBRULE_MODULUS_ASSIGN_OPERATOR(&, &&)
  449. #else
  450. BOOST_SPIRIT_SUBRULE_MODULUS_ASSIGN_OPERATOR(&, &)
  451. #endif
  452. #undef BOOST_SPIRIT_SUBRULE_MODULUS_ASSIGN_OPERATOR
  453. std::string const& name() const
  454. {
  455. return name_;
  456. }
  457. void name(std::string const& str)
  458. {
  459. name_ = str;
  460. }
  461. template <typename Context, typename Iterator>
  462. struct attribute
  463. {
  464. typedef attr_type type;
  465. };
  466. template <typename Iterator, typename Group
  467. , typename Attributes, typename Locals
  468. , typename Skipper, typename Attribute>
  469. bool parse(Iterator& first, Iterator const& last
  470. , subrule_context<Group, Attributes, Locals>& context
  471. , Skipper const& skipper, Attribute& attr) const
  472. {
  473. return context.group.template parse_subrule_id<ID_>(
  474. first, last, context, skipper, attr);
  475. }
  476. template <typename Iterator, typename Context
  477. , typename Skipper, typename Attribute>
  478. bool parse(Iterator& /*first*/, Iterator const& /*last*/
  479. , Context& /*context*/
  480. , Skipper const& /*skipper*/, Attribute& /*attr*/) const
  481. {
  482. // If you are seeing a compilation error here, you are trying
  483. // to use a subrule as a parser outside of a subrule group.
  484. BOOST_SPIRIT_ASSERT_FAIL(Iterator
  485. , subrule_used_outside_subrule_group, (id_type));
  486. return false;
  487. }
  488. template <typename Iterator, typename Group
  489. , typename Attributes, typename Locals
  490. , typename Skipper, typename Attribute
  491. , typename Params>
  492. bool parse(Iterator& first, Iterator const& last
  493. , subrule_context<Group, Attributes, Locals>& context
  494. , Skipper const& skipper, Attribute& attr
  495. , Params const& params) const
  496. {
  497. return context.group.template parse_subrule_id<ID_>(
  498. first, last, context, skipper, attr, params);
  499. }
  500. template <typename Iterator, typename Context
  501. , typename Skipper, typename Attribute
  502. , typename Params>
  503. bool parse(Iterator& /*first*/, Iterator const& /*last*/
  504. , Context& /*context*/
  505. , Skipper const& /*skipper*/, Attribute& /*attr*/
  506. , Params const& /*params*/) const
  507. {
  508. // If you are seeing a compilation error here, you are trying
  509. // to use a subrule as a parser outside of a subrule group.
  510. BOOST_SPIRIT_ASSERT_FAIL(Iterator
  511. , subrule_used_outside_subrule_group, (id_type));
  512. return false;
  513. }
  514. template <typename Context>
  515. info what(Context& /*context*/) const
  516. {
  517. return info(name_);
  518. }
  519. // bring in the operator() overloads
  520. this_type const& get_parameterized_subject() const { return *this; }
  521. typedef this_type parameterized_subject_type;
  522. #include <boost/spirit/home/qi/nonterminal/detail/fcall.hpp>
  523. std::string name_;
  524. };
  525. }}}}
  526. #if defined(BOOST_MSVC)
  527. # pragma warning(pop)
  528. #endif
  529. #endif