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