Imported Upstream version 1.72.0
[platform/upstream/boost.git] / boost / spirit / repository / home / qi / operator / keywords.hpp
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 #if !defined(SPIRIT_KEYWORDS_OR_MARCH_13_2007_1145PM)
9 #define SPIRIT_KEYWORDS_OR_MARCH_13_2007_1145PM
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/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>
48
49
50 namespace boost { namespace spirit
51 {
52     ///////////////////////////////////////////////////////////////////////////
53     // Enablers
54     ///////////////////////////////////////////////////////////////////////////
55     template <>
56     struct use_operator<qi::domain, proto::tag::divides > // enables /
57       : mpl::true_ {};
58
59     template <>
60     struct flatten_tree<qi::domain, proto::tag::divides> // flattens /
61       : mpl::true_ {};
62 }}
63
64 namespace boost { namespace spirit { namespace repository { namespace qi
65 {
66
67     // kwd directive parser type identification
68     namespace detail
69     {
70         BOOST_MPL_HAS_XXX_TRAIT_DEF(kwd_parser_id)
71         BOOST_MPL_HAS_XXX_TRAIT_DEF(complex_kwd_parser_id)
72
73
74     }
75
76     // kwd directive type query
77     template <typename T>
78     struct is_kwd_parser : detail::has_kwd_parser_id<T> {};
79
80     template <typename Subject, typename Action>
81     struct is_kwd_parser<spirit::qi::action<Subject,Action> > : detail::has_kwd_parser_id<Subject> {};
82
83     template <typename Subject>
84     struct is_kwd_parser<spirit::qi::hold_directive<Subject> > : detail::has_kwd_parser_id<Subject> {};
85
86     template <typename T>
87     struct is_complex_kwd_parser : detail::has_complex_kwd_parser_id<T> {};
88
89     template <typename Subject, typename Action>
90     struct is_complex_kwd_parser<spirit::qi::action<Subject,Action> > : detail::has_complex_kwd_parser_id<Subject> {};
91
92     template <typename Subject>
93     struct is_complex_kwd_parser<spirit::qi::hold_directive<Subject> > : detail::has_complex_kwd_parser_id<Subject> {};
94
95
96     // Keywords operator
97     template <typename Elements, typename Modifiers>
98     struct keywords : spirit::qi::nary_parser<keywords<Elements,Modifiers> >
99     {
100         template <typename Context, typename Iterator>
101         struct attribute
102         {
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
106             all_attributes;
107
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
111             // unused_type(s).
112             typedef typename
113                 traits::build_fusion_vector<all_attributes>::type
114             type;
115         };
116
117         /// Make sure that all subjects are of the kwd type
118         typedef typename mpl::count_if<
119                 Elements,
120                         mpl::not_<
121                            mpl::or_<
122                               is_kwd_parser<
123                                 mpl::_1
124                               > ,
125                               is_complex_kwd_parser<
126                                 mpl::_1
127                               >
128                           >
129                         >
130                 > non_kwd_subject_count;
131
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 );
135
136         ///////////////////////////////////////////////////////////////////////////
137         // build_parser_tags
138         //
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
142         // keyword.
143         ///////////////////////////////////////////////////////////////////////////
144
145         template <typename Sequence>
146         struct build_parser_tags
147         {
148             // Get the sequence size
149             typedef typename mpl::size< Sequence >::type sequence_size;
150
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;
153
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;
156
157         };
158         // Build an index mpl vector
159         typedef typename build_parser_tags< Elements >::type parser_index_vector;
160
161         template <typename idx>
162         struct is_complex_kwd_parser_filter : is_complex_kwd_parser< typename mpl::at<Elements, idx>::type >
163         {};
164
165         template <typename idx>
166         struct is_kwd_parser_filter : is_kwd_parser< typename mpl::at<Elements, idx>::type >
167         {};
168
169         // filter out the string kwd directives
170         typedef typename mpl::filter_view< Elements, is_kwd_parser<mpl::_> >::type string_keywords;
171
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;
179
180         //typedef typename fusion::filter_view< Elements, is_complex_kwd_parser< mpl::_ > > complex_keywords_view;
181
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;
187
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;
193
194         typedef typename mpl::if_<
195                         typename mpl::empty<string_keyword_indexes>::type,
196                         detail::empty_keywords_list,
197                         detail::string_keywords<
198                                 Elements,
199                                 string_keywords,
200                                 string_keyword_indexes,
201                                 flags_type,
202                                 Modifiers>
203                 >::type string_keywords_type;
204
205         keywords(Elements const& elements_) :
206               elements(elements_)
207             , string_keywords_inst(elements,flags_init)
208       , complex_keywords_inst(elements,flags_init)
209         {
210         }
211
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
217         {
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()
223                              );
224         }
225
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
231           {
232
233             // wrap the attribute in a tuple if it is not a tuple
234             typename traits::wrap_if_not_tuple<Attribute>::type attr(attr_);
235
236             flags_type flags(flags_init);
237             //flags.assign(false);
238
239             counters_type counters;
240             counters.assign(0);
241
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;
246
247             parser_visitor_type parse_visitor(elements, first, last
248                                              , context, skipper, flags
249                                              , counters, attr);
250
251             typedef repository::qi::detail::complex_kwd_function< parser_visitor_type > complex_kwd_function_type;
252
253             complex_kwd_function_type
254                      complex_function(first,last,context,skipper,parse_visitor);
255
256             // We have a bool array 'flags' with one flag for each parser as well as a 'counter'
257             // array.
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.
265
266             for(;;)
267             {
268
269                 spirit::qi::skip_over(first, last, skipper);
270                 Iterator save = first;
271                 if (string_keywords_inst.parse(first, last,parse_visitor,skipper))
272                 {
273                     save = first;
274                 }
275                 else {
276                   // restore the position to the last successful keyword parse
277                   first = save;
278                   if(!complex_keywords_inst.parse(complex_function))
279                   {
280                     first = save;
281                     // Check that we are leaving the keywords parser in a successfull state
282                     BOOST_FOREACH(bool &valid,flags)
283                     {
284                       if(!valid)
285                       {
286                         return false;
287                       }
288                     }
289                     return true;
290                   }
291                   else
292                     save = first;
293                 }
294             }
295             return false;
296           }
297
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
304           {
305
306             // wrap the attribute in a tuple if it is not a tuple
307             typename traits::wrap_if_not_tuple<Attribute>::type attr(attr_);
308
309             flags_type flags(flags_init);
310             //flags.assign(false);
311
312             counters_type counters;
313             counters.assign(0);
314
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;
319
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;
324
325
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);
330
331             typedef repository::qi::detail::complex_kwd_function< parser_visitor_type > complex_kwd_function_type;
332
333             complex_kwd_function_type
334                      complex_function(first,last,context,skipper,parse_visitor);
335
336
337             // We have a bool array 'flags' with one flag for each parser as well as a 'counter'
338             // array.
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.
346
347             for(;;)
348             {
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))
353                 {
354                     save = first;
355                 }
356                 else {
357                   first = save;
358
359                   if(!complex_keywords_inst.parse(complex_function))
360                   {
361                     first = save;
362                     // Check that we are leaving the keywords parser in a successfull state
363                     BOOST_FOREACH(bool &valid,flags)
364                     {
365                       if(!valid)
366                       {
367                         return false;
368                       }
369                     }
370                     return true;
371                   }
372                   else
373                   {
374                     save = first;
375                   }
376                 }
377             }
378             return false;
379           }
380
381         template <typename Context>
382         info what(Context& context) const
383         {
384             info result("keywords");
385             fusion::for_each(elements,
386                 spirit::detail::what_function<Context>(result, context));
387             return result;
388         }
389         flags_type flags_init;
390         Elements elements;
391         string_keywords_type string_keywords_inst;
392         complex_keywords_type complex_keywords_inst;
393
394     };
395 }}}}
396
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 >
403     {
404         typedef repository::qi::keywords<Elements,Modifiers> result_type;
405         result_type operator()(Elements ref, unused_type) const
406         {
407             return result_type(ref);
408         }
409     };
410
411
412 }}}
413
414 namespace boost { namespace spirit { namespace traits
415 {
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> {};
422
423     template <typename Elements, typename Modifiers>
424     struct has_semantic_action<repository::qi::keywords<Elements, Modifiers> >
425       : nary_has_semantic_action<Elements> {};
426
427     template <typename Elements, typename Attribute, typename Context
428         , typename Iterator, typename Modifiers>
429     struct handles_container<repository::qi::keywords<Elements,Modifiers>, Attribute
430         , Context, Iterator>
431       : nary_handles_container<Elements, Attribute, Context, Iterator> {};
432
433
434 }}}
435
436 #endif
437