/Src/Dependencies/Boost/boost/spirit/repository/home/karma/nonterminal/subrule.hpp

http://hadesmem.googlecode.com/ · C++ Header · 560 lines · 424 code · 73 blank · 63 comment · 0 complexity · 4e384e22db7db17352b00fe3ad5272f7 MD5 · raw file

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