1 /*=============================================================================
2 Copyright (c) 2001-2011 Joel de Guzman
3 Copyright (c) 2011-2012 Thomas Bernard
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(SPIRIT_KEYWORDS_OR_MARCH_13_2007_1145PM)
9 #define SPIRIT_KEYWORDS_OR_MARCH_13_2007_1145PM
15 #include <boost/spirit/home/qi/meta_compiler.hpp>
16 #include <boost/spirit/home/qi/domain.hpp>
17 #include <boost/spirit/home/qi/detail/permute_function.hpp>
18 #include <boost/spirit/home/qi/detail/attributes.hpp>
19 #include <boost/spirit/home/support/detail/what_function.hpp>
20 #include <boost/spirit/home/support/info.hpp>
21 #include <boost/spirit/home/support/unused.hpp>
22 #include <boost/fusion/include/iter_fold.hpp>
23 #include <boost/fusion/include/at.hpp>
24 #include <boost/fusion/include/value_at.hpp>
25 #include <boost/fusion/include/mpl.hpp>
26 #include <boost/optional.hpp>
27 #include <boost/foreach.hpp>
28 #include <boost/array.hpp>
29 #include <boost/spirit/home/qi/string/symbols.hpp>
30 #include <boost/spirit/home/qi/string/lit.hpp>
31 #include <boost/spirit/home/qi/action/action.hpp>
32 #include <boost/spirit/home/qi/directive/hold.hpp>
33 #include <boost/mpl/count_if.hpp>
34 #include <boost/mpl/greater.hpp>
35 #include <boost/mpl/range_c.hpp>
36 #include <boost/mpl/copy.hpp>
37 #include <boost/mpl/size.hpp>
38 #include <boost/mpl/equal_to.hpp>
39 #include <boost/mpl/back_inserter.hpp>
40 #include <boost/mpl/filter_view.hpp>
41 #include <boost/fusion/include/zip_view.hpp>
42 #include <boost/fusion/include/as_vector.hpp>
43 #include <boost/variant/static_visitor.hpp>
44 #include <boost/type_traits/remove_const.hpp>
45 #include <boost/type_traits/is_same.hpp>
46 #include <boost/spirit/repository/home/qi/operator/detail/keywords.hpp>
47 #include <boost/fusion/include/any.hpp>
50 namespace boost { namespace spirit
52 ///////////////////////////////////////////////////////////////////////////
54 ///////////////////////////////////////////////////////////////////////////
56 struct use_operator<qi::domain, proto::tag::divides > // enables /
60 struct flatten_tree<qi::domain, proto::tag::divides> // flattens /
64 namespace boost { namespace spirit { namespace repository { namespace qi
67 // kwd directive parser type identification
70 BOOST_MPL_HAS_XXX_TRAIT_DEF(kwd_parser_id)
71 BOOST_MPL_HAS_XXX_TRAIT_DEF(complex_kwd_parser_id)
76 // kwd directive type query
78 struct is_kwd_parser : detail::has_kwd_parser_id<T> {};
80 template <typename Subject, typename Action>
81 struct is_kwd_parser<spirit::qi::action<Subject,Action> > : detail::has_kwd_parser_id<Subject> {};
83 template <typename Subject>
84 struct is_kwd_parser<spirit::qi::hold_directive<Subject> > : detail::has_kwd_parser_id<Subject> {};
87 struct is_complex_kwd_parser : detail::has_complex_kwd_parser_id<T> {};
89 template <typename Subject, typename Action>
90 struct is_complex_kwd_parser<spirit::qi::action<Subject,Action> > : detail::has_complex_kwd_parser_id<Subject> {};
92 template <typename Subject>
93 struct is_complex_kwd_parser<spirit::qi::hold_directive<Subject> > : detail::has_complex_kwd_parser_id<Subject> {};
97 template <typename Elements, typename Modifiers>
98 struct keywords : spirit::qi::nary_parser<keywords<Elements,Modifiers> >
100 template <typename Context, typename Iterator>
103 // Put all the element attributes in a tuple
104 typedef typename traits::build_attribute_sequence<
105 Elements, Context, traits::sequence_attribute_transform, Iterator, spirit::qi::domain >::type
108 // Now, build a fusion vector over the attributes. Note
109 // that build_fusion_vector 1) removes all unused attributes
110 // and 2) may return unused_type if all elements have
113 traits::build_fusion_vector<all_attributes>::type
117 /// Make sure that all subjects are of the kwd type
118 typedef typename mpl::count_if<
125 is_complex_kwd_parser<
130 > non_kwd_subject_count;
132 /// If the assertion fails here then you probably forgot to wrap a
133 /// subject of the / operator in a kwd directive
134 BOOST_MPL_ASSERT_RELATION( non_kwd_subject_count::value, ==, 0 );
136 ///////////////////////////////////////////////////////////////////////////
139 // Builds a boost::variant from an mpl::range_c in order to "mark" every
140 // parser of the fusion sequence. The integer constant is used in the parser
141 // dispatcher functor in order to use the parser corresponding to the recognised
143 ///////////////////////////////////////////////////////////////////////////
145 template <typename Sequence>
146 struct build_parser_tags
148 // Get the sequence size
149 typedef typename mpl::size< Sequence >::type sequence_size;
151 // Create an integer_c constant for every parser in the sequence
152 typedef typename mpl::range_c<int, 0, sequence_size::value>::type int_range;
154 // Transform the range_c to an mpl vector in order to be able to transform it into a variant
155 typedef typename mpl::copy<int_range, mpl::back_inserter<mpl::vector<> > >::type type;
158 // Build an index mpl vector
159 typedef typename build_parser_tags< Elements >::type parser_index_vector;
161 template <typename idx>
162 struct is_complex_kwd_parser_filter : is_complex_kwd_parser< typename mpl::at<Elements, idx>::type >
165 template <typename idx>
166 struct is_kwd_parser_filter : is_kwd_parser< typename mpl::at<Elements, idx>::type >
169 // filter out the string kwd directives
170 typedef typename mpl::filter_view< Elements, is_kwd_parser<mpl::_> >::type string_keywords;
172 typedef typename mpl::filter_view< parser_index_vector ,
173 is_kwd_parser_filter< mpl::_ >
174 >::type string_keyword_indexes;
175 // filter out the complex keywords
176 typedef typename mpl::filter_view< parser_index_vector ,
177 is_complex_kwd_parser_filter< mpl::_ >
178 >::type complex_keywords_indexes;
180 //typedef typename fusion::filter_view< Elements, is_complex_kwd_parser< mpl::_ > > complex_keywords_view;
182 typedef typename mpl::if_<
183 typename mpl::empty<complex_keywords_indexes>::type,
184 detail::empty_keywords_list,
185 detail::complex_keywords< complex_keywords_indexes >
186 >::type complex_keywords_type;
188 // build a bool array and an integer array which will be used to
189 // check that the repetition constraints of the kwd parsers are
190 // met and bail out a soon as possible
191 typedef boost::array<bool, fusion::result_of::size<Elements>::value> flags_type;
192 typedef boost::array<int, fusion::result_of::size<Elements>::value> counters_type;
194 typedef typename mpl::if_<
195 typename mpl::empty<string_keyword_indexes>::type,
196 detail::empty_keywords_list,
197 detail::string_keywords<
200 string_keyword_indexes,
203 >::type string_keywords_type;
205 keywords(Elements const& elements_) :
207 , string_keywords_inst(elements,flags_init)
208 , complex_keywords_inst(elements,flags_init)
212 template <typename Iterator, typename Context
213 , typename Skipper, typename Attribute>
214 bool parse(Iterator& first, Iterator const& last
215 , Context& context, Skipper const& skipper
216 , Attribute& attr_) const
218 // Select which parse function to call
219 // We need to handle the case where kwd / ikwd directives have been mixed
220 // This is where we decide which function should be called.
221 return parse_impl(first, last, context, skipper, attr_,
222 typename string_keywords_type::requires_one_pass()
226 template <typename Iterator, typename Context
227 , typename Skipper, typename Attribute>
228 bool parse_impl(Iterator& first, Iterator const& last
229 , Context& context, Skipper const& skipper
230 , Attribute& attr_,mpl::true_ /* one pass */) const
233 // wrap the attribute in a tuple if it is not a tuple
234 typename traits::wrap_if_not_tuple<Attribute>::type attr(attr_);
236 flags_type flags(flags_init);
237 //flags.assign(false);
239 counters_type counters;
242 typedef repository::qi::detail::parse_dispatcher<Elements,Iterator, Context, Skipper
243 , flags_type, counters_type
244 , typename traits::wrap_if_not_tuple<Attribute>::type
245 , mpl::false_ > parser_visitor_type;
247 parser_visitor_type parse_visitor(elements, first, last
248 , context, skipper, flags
251 typedef repository::qi::detail::complex_kwd_function< parser_visitor_type > complex_kwd_function_type;
253 complex_kwd_function_type
254 complex_function(first,last,context,skipper,parse_visitor);
256 // We have a bool array 'flags' with one flag for each parser as well as a 'counter'
258 // The kwd directive sets and increments the counter when a successeful parse occurred
259 // as well as the slot of the corresponding parser to true in the flags array as soon
260 // the minimum repetition requirement is met and keeps that value to true as long as
261 // the maximum repetition requirement is met.
262 // The parsing takes place here in two steps:
263 // 1) parse a keyword and fetch the parser index associated with that keyword
264 // 2) call the associated parser and store the parsed value in the matching attribute.
269 spirit::qi::skip_over(first, last, skipper);
270 Iterator save = first;
271 if (string_keywords_inst.parse(first, last,parse_visitor,skipper))
276 // restore the position to the last successful keyword parse
278 if(!complex_keywords_inst.parse(complex_function))
281 // Check that we are leaving the keywords parser in a successfull state
282 BOOST_FOREACH(bool &valid,flags)
298 // Handle the mixed kwd and ikwd case
299 template <typename Iterator, typename Context
300 , typename Skipper, typename Attribute>
301 bool parse_impl(Iterator& first, Iterator const& last
302 , Context& context, Skipper const& skipper
303 , Attribute& attr_,mpl::false_ /* two passes */) const
306 // wrap the attribute in a tuple if it is not a tuple
307 typename traits::wrap_if_not_tuple<Attribute>::type attr(attr_);
309 flags_type flags(flags_init);
310 //flags.assign(false);
312 counters_type counters;
315 typedef detail::parse_dispatcher<Elements, Iterator, Context, Skipper
316 , flags_type, counters_type
317 , typename traits::wrap_if_not_tuple<Attribute>::type
318 , mpl::false_> parser_visitor_type;
320 typedef detail::parse_dispatcher<Elements, Iterator, Context, Skipper
321 , flags_type, counters_type
322 , typename traits::wrap_if_not_tuple<Attribute>::type
323 , mpl::true_> no_case_parser_visitor_type;
326 parser_visitor_type parse_visitor(elements,first,last
327 ,context,skipper,flags,counters,attr);
328 no_case_parser_visitor_type no_case_parse_visitor(elements,first,last
329 ,context,skipper,flags,counters,attr);
331 typedef repository::qi::detail::complex_kwd_function< parser_visitor_type > complex_kwd_function_type;
333 complex_kwd_function_type
334 complex_function(first,last,context,skipper,parse_visitor);
337 // We have a bool array 'flags' with one flag for each parser as well as a 'counter'
339 // The kwd directive sets and increments the counter when a successeful parse occurred
340 // as well as the slot of the corresponding parser to true in the flags array as soon
341 // the minimum repetition requirement is met and keeps that value to true as long as
342 // the maximum repetition requirement is met.
343 // The parsing takes place here in two steps:
344 // 1) parse a keyword and fetch the parser index associated with that keyword
345 // 2) call the associated parser and store the parsed value in the matching attribute.
349 spirit::qi::skip_over(first, last, skipper);
350 Iterator save = first;
351 // String keywords pass
352 if (string_keywords_inst.parse(first,last,parse_visitor,no_case_parse_visitor,skipper))
359 if(!complex_keywords_inst.parse(complex_function))
362 // Check that we are leaving the keywords parser in a successfull state
363 BOOST_FOREACH(bool &valid,flags)
381 template <typename Context>
382 info what(Context& context) const
384 info result("keywords");
385 fusion::for_each(elements,
386 spirit::detail::what_function<Context>(result, context));
389 flags_type flags_init;
391 string_keywords_type string_keywords_inst;
392 complex_keywords_type complex_keywords_inst;
397 namespace boost { namespace spirit { namespace qi {
398 ///////////////////////////////////////////////////////////////////////////
399 // Parser generators: make_xxx function (objects)
400 ///////////////////////////////////////////////////////////////////////////
401 template <typename Elements, typename Modifiers >
402 struct make_composite<proto::tag::divides, Elements, Modifiers >
404 typedef repository::qi::keywords<Elements,Modifiers> result_type;
405 result_type operator()(Elements ref, unused_type) const
407 return result_type(ref);
414 namespace boost { namespace spirit { namespace traits
416 // We specialize this for keywords (see support/attributes.hpp).
417 // For keywords, we only wrap the attribute in a tuple IFF
418 // it is not already a fusion tuple.
419 template <typename Elements, typename Modifiers,typename Attribute>
420 struct pass_attribute<repository::qi::keywords<Elements,Modifiers>, Attribute>
421 : wrap_if_not_tuple<Attribute> {};
423 template <typename Elements, typename Modifiers>
424 struct has_semantic_action<repository::qi::keywords<Elements, Modifiers> >
425 : nary_has_semantic_action<Elements> {};
427 template <typename Elements, typename Attribute, typename Context
428 , typename Iterator, typename Modifiers>
429 struct handles_container<repository::qi::keywords<Elements,Modifiers>, Attribute
431 : nary_handles_container<Elements, Attribute, Context, Iterator> {};