keywords.hpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437
  1. /*=============================================================================
  2. Copyright (c) 2001-2011 Joel de Guzman
  3. Copyright (c) 2011-2012 Thomas Bernard
  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(SPIRIT_KEYWORDS_OR_MARCH_13_2007_1145PM)
  8. #define SPIRIT_KEYWORDS_OR_MARCH_13_2007_1145PM
  9. #if defined(_MSC_VER)
  10. #pragma once
  11. #endif
  12. #include <boost/spirit/home/qi/meta_compiler.hpp>
  13. #include <boost/spirit/home/qi/domain.hpp>
  14. #include <boost/spirit/home/qi/detail/permute_function.hpp>
  15. #include <boost/spirit/home/qi/detail/attributes.hpp>
  16. #include <boost/spirit/home/support/detail/what_function.hpp>
  17. #include <boost/spirit/home/support/info.hpp>
  18. #include <boost/spirit/home/support/unused.hpp>
  19. #include <boost/fusion/include/iter_fold.hpp>
  20. #include <boost/fusion/include/at.hpp>
  21. #include <boost/fusion/include/value_at.hpp>
  22. #include <boost/fusion/include/mpl.hpp>
  23. #include <boost/optional.hpp>
  24. #include <boost/foreach.hpp>
  25. #include <boost/array.hpp>
  26. #include <boost/spirit/home/qi/string/symbols.hpp>
  27. #include <boost/spirit/home/qi/string/lit.hpp>
  28. #include <boost/spirit/home/qi/action/action.hpp>
  29. #include <boost/spirit/home/qi/directive/hold.hpp>
  30. #include <boost/mpl/count_if.hpp>
  31. #include <boost/mpl/greater.hpp>
  32. #include <boost/mpl/range_c.hpp>
  33. #include <boost/mpl/copy.hpp>
  34. #include <boost/mpl/size.hpp>
  35. #include <boost/mpl/equal_to.hpp>
  36. #include <boost/mpl/back_inserter.hpp>
  37. #include <boost/mpl/filter_view.hpp>
  38. #include <boost/fusion/include/zip_view.hpp>
  39. #include <boost/fusion/include/as_vector.hpp>
  40. #include <boost/variant/static_visitor.hpp>
  41. #include <boost/type_traits/remove_const.hpp>
  42. #include <boost/type_traits/is_same.hpp>
  43. #include <boost/spirit/repository/home/qi/operator/detail/keywords.hpp>
  44. #include <boost/fusion/include/any.hpp>
  45. namespace boost { namespace spirit
  46. {
  47. ///////////////////////////////////////////////////////////////////////////
  48. // Enablers
  49. ///////////////////////////////////////////////////////////////////////////
  50. template <>
  51. struct use_operator<qi::domain, proto::tag::divides > // enables /
  52. : mpl::true_ {};
  53. template <>
  54. struct flatten_tree<qi::domain, proto::tag::divides> // flattens /
  55. : mpl::true_ {};
  56. }}
  57. namespace boost { namespace spirit { namespace repository { namespace qi
  58. {
  59. // kwd directive parser type identification
  60. namespace detail
  61. {
  62. BOOST_MPL_HAS_XXX_TRAIT_DEF(kwd_parser_id)
  63. BOOST_MPL_HAS_XXX_TRAIT_DEF(complex_kwd_parser_id)
  64. }
  65. // kwd directive type query
  66. template <typename T>
  67. struct is_kwd_parser : detail::has_kwd_parser_id<T> {};
  68. template <typename Subject, typename Action>
  69. struct is_kwd_parser<spirit::qi::action<Subject,Action> > : detail::has_kwd_parser_id<Subject> {};
  70. template <typename Subject>
  71. struct is_kwd_parser<spirit::qi::hold_directive<Subject> > : detail::has_kwd_parser_id<Subject> {};
  72. template <typename T>
  73. struct is_complex_kwd_parser : detail::has_complex_kwd_parser_id<T> {};
  74. template <typename Subject, typename Action>
  75. struct is_complex_kwd_parser<spirit::qi::action<Subject,Action> > : detail::has_complex_kwd_parser_id<Subject> {};
  76. template <typename Subject>
  77. struct is_complex_kwd_parser<spirit::qi::hold_directive<Subject> > : detail::has_complex_kwd_parser_id<Subject> {};
  78. // Keywords operator
  79. template <typename Elements, typename Modifiers>
  80. struct keywords : spirit::qi::nary_parser<keywords<Elements,Modifiers> >
  81. {
  82. template <typename Context, typename Iterator>
  83. struct attribute
  84. {
  85. // Put all the element attributes in a tuple
  86. typedef typename traits::build_attribute_sequence<
  87. Elements, Context, traits::sequence_attribute_transform, Iterator, spirit::qi::domain >::type
  88. all_attributes;
  89. // Now, build a fusion vector over the attributes. Note
  90. // that build_fusion_vector 1) removes all unused attributes
  91. // and 2) may return unused_type if all elements have
  92. // unused_type(s).
  93. typedef typename
  94. traits::build_fusion_vector<all_attributes>::type
  95. type;
  96. };
  97. /// Make sure that all subjects are of the kwd type
  98. typedef typename mpl::count_if<
  99. Elements,
  100. mpl::not_<
  101. mpl::or_<
  102. is_kwd_parser<
  103. mpl::_1
  104. > ,
  105. is_complex_kwd_parser<
  106. mpl::_1
  107. >
  108. >
  109. >
  110. > non_kwd_subject_count;
  111. /// If the assertion fails here then you probably forgot to wrap a
  112. /// subject of the / operator in a kwd directive
  113. BOOST_MPL_ASSERT_RELATION( non_kwd_subject_count::value, ==, 0 );
  114. ///////////////////////////////////////////////////////////////////////////
  115. // build_parser_tags
  116. //
  117. // Builds a boost::variant from an mpl::range_c in order to "mark" every
  118. // parser of the fusion sequence. The integer constant is used in the parser
  119. // dispatcher functor in order to use the parser corresponding to the recognised
  120. // keyword.
  121. ///////////////////////////////////////////////////////////////////////////
  122. template <typename Sequence>
  123. struct build_parser_tags
  124. {
  125. // Get the sequence size
  126. typedef typename mpl::size< Sequence >::type sequence_size;
  127. // Create an integer_c constant for every parser in the sequence
  128. typedef typename mpl::range_c<int, 0, sequence_size::value>::type int_range;
  129. // Transform the range_c to an mpl vector in order to be able to transform it into a variant
  130. typedef typename mpl::copy<int_range, mpl::back_inserter<mpl::vector<> > >::type type;
  131. };
  132. // Build an index mpl vector
  133. typedef typename build_parser_tags< Elements >::type parser_index_vector;
  134. template <typename idx>
  135. struct is_complex_kwd_parser_filter : is_complex_kwd_parser< typename mpl::at<Elements, idx>::type >
  136. {};
  137. template <typename idx>
  138. struct is_kwd_parser_filter : is_kwd_parser< typename mpl::at<Elements, idx>::type >
  139. {};
  140. // filter out the string kwd directives
  141. typedef typename mpl::filter_view< Elements, is_kwd_parser<mpl::_> >::type string_keywords;
  142. typedef typename mpl::filter_view< parser_index_vector ,
  143. is_kwd_parser_filter< mpl::_ >
  144. >::type string_keyword_indexes;
  145. // filter out the complex keywords
  146. typedef typename mpl::filter_view< parser_index_vector ,
  147. is_complex_kwd_parser_filter< mpl::_ >
  148. >::type complex_keywords_indexes;
  149. //typedef typename fusion::filter_view< Elements, is_complex_kwd_parser< mpl::_ > > complex_keywords_view;
  150. typedef typename mpl::if_<
  151. typename mpl::empty<complex_keywords_indexes>::type,
  152. detail::empty_keywords_list,
  153. detail::complex_keywords< complex_keywords_indexes >
  154. >::type complex_keywords_type;
  155. // build a bool array and an integer array which will be used to
  156. // check that the repetition constraints of the kwd parsers are
  157. // met and bail out a soon as possible
  158. typedef boost::array<bool, fusion::result_of::size<Elements>::value> flags_type;
  159. typedef boost::array<int, fusion::result_of::size<Elements>::value> counters_type;
  160. typedef typename mpl::if_<
  161. typename mpl::empty<string_keyword_indexes>::type,
  162. detail::empty_keywords_list,
  163. detail::string_keywords<
  164. Elements,
  165. string_keywords,
  166. string_keyword_indexes,
  167. flags_type,
  168. Modifiers>
  169. >::type string_keywords_type;
  170. keywords(Elements const& elements_) :
  171. elements(elements_)
  172. , string_keywords_inst(elements,flags_init)
  173. , complex_keywords_inst(elements,flags_init)
  174. {
  175. }
  176. template <typename Iterator, typename Context
  177. , typename Skipper, typename Attribute>
  178. bool parse(Iterator& first, Iterator const& last
  179. , Context& context, Skipper const& skipper
  180. , Attribute& attr_) const
  181. {
  182. // Select which parse function to call
  183. // We need to handle the case where kwd / ikwd directives have been mixed
  184. // This is where we decide which function should be called.
  185. return parse_impl(first, last, context, skipper, attr_,
  186. typename string_keywords_type::requires_one_pass()
  187. );
  188. }
  189. template <typename Iterator, typename Context
  190. , typename Skipper, typename Attribute>
  191. bool parse_impl(Iterator& first, Iterator const& last
  192. , Context& context, Skipper const& skipper
  193. , Attribute& attr_,mpl::true_ /* one pass */) const
  194. {
  195. // wrap the attribute in a tuple if it is not a tuple
  196. typename traits::wrap_if_not_tuple<Attribute>::type attr(attr_);
  197. flags_type flags(flags_init);
  198. //flags.assign(false);
  199. counters_type counters;
  200. counters.assign(0);
  201. typedef repository::qi::detail::parse_dispatcher<Elements,Iterator, Context, Skipper
  202. , flags_type, counters_type
  203. , typename traits::wrap_if_not_tuple<Attribute>::type
  204. , mpl::false_ > parser_visitor_type;
  205. parser_visitor_type parse_visitor(elements, first, last
  206. , context, skipper, flags
  207. , counters, attr);
  208. typedef repository::qi::detail::complex_kwd_function< parser_visitor_type > complex_kwd_function_type;
  209. complex_kwd_function_type
  210. complex_function(first,last,context,skipper,parse_visitor);
  211. // We have a bool array 'flags' with one flag for each parser as well as a 'counter'
  212. // array.
  213. // The kwd directive sets and increments the counter when a successeful parse occurred
  214. // as well as the slot of the corresponding parser to true in the flags array as soon
  215. // the minimum repetition requirement is met and keeps that value to true as long as
  216. // the maximum repetition requirement is met.
  217. // The parsing takes place here in two steps:
  218. // 1) parse a keyword and fetch the parser index associated with that keyword
  219. // 2) call the associated parser and store the parsed value in the matching attribute.
  220. for(;;)
  221. {
  222. spirit::qi::skip_over(first, last, skipper);
  223. Iterator save = first;
  224. if (string_keywords_inst.parse(first, last,parse_visitor,skipper))
  225. {
  226. save = first;
  227. }
  228. else {
  229. // restore the position to the last successful keyword parse
  230. first = save;
  231. if(!complex_keywords_inst.parse(complex_function))
  232. {
  233. first = save;
  234. // Check that we are leaving the keywords parser in a successfull state
  235. BOOST_FOREACH(bool &valid,flags)
  236. {
  237. if(!valid)
  238. {
  239. return false;
  240. }
  241. }
  242. return true;
  243. }
  244. else
  245. save = first;
  246. }
  247. }
  248. return false;
  249. }
  250. // Handle the mixed kwd and ikwd case
  251. template <typename Iterator, typename Context
  252. , typename Skipper, typename Attribute>
  253. bool parse_impl(Iterator& first, Iterator const& last
  254. , Context& context, Skipper const& skipper
  255. , Attribute& attr_,mpl::false_ /* two passes */) const
  256. {
  257. // wrap the attribute in a tuple if it is not a tuple
  258. typename traits::wrap_if_not_tuple<Attribute>::type attr(attr_);
  259. flags_type flags(flags_init);
  260. //flags.assign(false);
  261. counters_type counters;
  262. counters.assign(0);
  263. typedef detail::parse_dispatcher<Elements, Iterator, Context, Skipper
  264. , flags_type, counters_type
  265. , typename traits::wrap_if_not_tuple<Attribute>::type
  266. , mpl::false_> parser_visitor_type;
  267. typedef detail::parse_dispatcher<Elements, Iterator, Context, Skipper
  268. , flags_type, counters_type
  269. , typename traits::wrap_if_not_tuple<Attribute>::type
  270. , mpl::true_> no_case_parser_visitor_type;
  271. parser_visitor_type parse_visitor(elements,first,last
  272. ,context,skipper,flags,counters,attr);
  273. no_case_parser_visitor_type no_case_parse_visitor(elements,first,last
  274. ,context,skipper,flags,counters,attr);
  275. typedef repository::qi::detail::complex_kwd_function< parser_visitor_type > complex_kwd_function_type;
  276. complex_kwd_function_type
  277. complex_function(first,last,context,skipper,parse_visitor);
  278. // We have a bool array 'flags' with one flag for each parser as well as a 'counter'
  279. // array.
  280. // The kwd directive sets and increments the counter when a successeful parse occurred
  281. // as well as the slot of the corresponding parser to true in the flags array as soon
  282. // the minimum repetition requirement is met and keeps that value to true as long as
  283. // the maximum repetition requirement is met.
  284. // The parsing takes place here in two steps:
  285. // 1) parse a keyword and fetch the parser index associated with that keyword
  286. // 2) call the associated parser and store the parsed value in the matching attribute.
  287. for(;;)
  288. {
  289. spirit::qi::skip_over(first, last, skipper);
  290. Iterator save = first;
  291. // String keywords pass
  292. if (string_keywords_inst.parse(first,last,parse_visitor,no_case_parse_visitor,skipper))
  293. {
  294. save = first;
  295. }
  296. else {
  297. first = save;
  298. if(!complex_keywords_inst.parse(complex_function))
  299. {
  300. first = save;
  301. // Check that we are leaving the keywords parser in a successfull state
  302. BOOST_FOREACH(bool &valid,flags)
  303. {
  304. if(!valid)
  305. {
  306. return false;
  307. }
  308. }
  309. return true;
  310. }
  311. else
  312. {
  313. save = first;
  314. }
  315. }
  316. }
  317. return false;
  318. }
  319. template <typename Context>
  320. info what(Context& context) const
  321. {
  322. info result("keywords");
  323. fusion::for_each(elements,
  324. spirit::detail::what_function<Context>(result, context));
  325. return result;
  326. }
  327. flags_type flags_init;
  328. Elements elements;
  329. string_keywords_type string_keywords_inst;
  330. complex_keywords_type complex_keywords_inst;
  331. };
  332. }}}}
  333. namespace boost { namespace spirit { namespace qi {
  334. ///////////////////////////////////////////////////////////////////////////
  335. // Parser generators: make_xxx function (objects)
  336. ///////////////////////////////////////////////////////////////////////////
  337. template <typename Elements, typename Modifiers >
  338. struct make_composite<proto::tag::divides, Elements, Modifiers >
  339. {
  340. typedef repository::qi::keywords<Elements,Modifiers> result_type;
  341. result_type operator()(Elements ref, unused_type) const
  342. {
  343. return result_type(ref);
  344. }
  345. };
  346. }}}
  347. namespace boost { namespace spirit { namespace traits
  348. {
  349. // We specialize this for keywords (see support/attributes.hpp).
  350. // For keywords, we only wrap the attribute in a tuple IFF
  351. // it is not already a fusion tuple.
  352. template <typename Elements, typename Modifiers,typename Attribute>
  353. struct pass_attribute<repository::qi::keywords<Elements,Modifiers>, Attribute>
  354. : wrap_if_not_tuple<Attribute> {};
  355. template <typename Elements, typename Modifiers>
  356. struct has_semantic_action<repository::qi::keywords<Elements, Modifiers> >
  357. : nary_has_semantic_action<Elements> {};
  358. template <typename Elements, typename Attribute, typename Context
  359. , typename Iterator, typename Modifiers>
  360. struct handles_container<repository::qi::keywords<Elements,Modifiers>, Attribute
  361. , Context, Iterator>
  362. : nary_handles_container<Elements, Attribute, Context, Iterator> {};
  363. }}}
  364. #endif