1 /*=============================================================================
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 =============================================================================*/
8 #if !defined(SPIRIT_REPEAT_NOVEMBER_14_2008_1148AM)
9 #define SPIRIT_REPEAT_NOVEMBER_14_2008_1148AM
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/parser.hpp>
17 #include <boost/spirit/home/qi/auxiliary/lazy.hpp>
18 #include <boost/spirit/home/qi/operator/kleene.hpp>
19 #include <boost/spirit/home/support/container.hpp>
20 #include <boost/spirit/home/support/common_terminals.hpp>
21 #include <boost/spirit/home/qi/detail/attributes.hpp>
22 #include <boost/spirit/home/qi/detail/fail_function.hpp>
23 #include <boost/spirit/home/qi/detail/pass_container.hpp>
24 #include <boost/spirit/home/support/info.hpp>
25 #include <boost/spirit/home/support/has_semantic_action.hpp>
26 #include <boost/spirit/home/support/handles_container.hpp>
27 #include <boost/fusion/include/at.hpp>
28 #include <vector>
29 
30 namespace boost { namespace spirit
31 {
32     ///////////////////////////////////////////////////////////////////////////
33     // Enablers
34     ///////////////////////////////////////////////////////////////////////////
35     template <>
36     struct use_directive<qi::domain, tag::repeat>   // enables repeat[p]
37       : mpl::true_ {};
38 
39     template <typename T>
40     struct use_directive<qi::domain
41       , terminal_ex<tag::repeat                     // enables repeat(exact)[p]
42         , fusion::vector1<T> >
43     > : mpl::true_ {};
44 
45     template <typename T>
46     struct use_directive<qi::domain
47       , terminal_ex<tag::repeat                     // enables repeat(min, max)[p]
48         , fusion::vector2<T, T> >
49     > : mpl::true_ {};
50 
51     template <typename T>
52     struct use_directive<qi::domain
53       , terminal_ex<tag::repeat                     // enables repeat(min, inf)[p]
54         , fusion::vector2<T, inf_type> >
55     > : mpl::true_ {};
56 
57     template <>                                     // enables *lazy* repeat(exact)[p]
58     struct use_lazy_directive<
59         qi::domain
60       , tag::repeat
61       , 1 // arity
62     > : mpl::true_ {};
63 
64     template <>                                     // enables *lazy* repeat(min, max)[p]
65     struct use_lazy_directive<                      // and repeat(min, inf)[p]
66         qi::domain
67       , tag::repeat
68       , 2 // arity
69     > : mpl::true_ {};
70 }}
71 
72 namespace boost { namespace spirit { namespace qi
73 {
74 #ifndef BOOST_SPIRIT_NO_PREDEFINED_TERMINALS
75     using spirit::repeat;
76     using spirit::inf;
77 #endif
78     using spirit::repeat_type;
79     using spirit::inf_type;
80 
81     template <typename T>
82     struct exact_iterator // handles repeat(exact)[p]
83     {
exact_iteratorboost::spirit::qi::exact_iterator84         exact_iterator(T const exact_)
85           : exact(exact_) {}
86 
87         typedef T type;
startboost::spirit::qi::exact_iterator88         T start() const { return 0; }
got_maxboost::spirit::qi::exact_iterator89         bool got_max(T i) const { return i >= exact; }
got_minboost::spirit::qi::exact_iterator90         bool got_min(T i) const { return i >= exact; }
91 
92         T const exact;
93 
94     private:
95         // silence MSVC warning C4512: assignment operator could not be generated
96         exact_iterator& operator= (exact_iterator const&);
97     };
98 
99     template <typename T>
100     struct finite_iterator // handles repeat(min, max)[p]
101     {
finite_iteratorboost::spirit::qi::finite_iterator102         finite_iterator(T const min_, T const max_)
103           : min BOOST_PREVENT_MACRO_SUBSTITUTION (min_)
104           , max BOOST_PREVENT_MACRO_SUBSTITUTION (max_) {}
105 
106         typedef T type;
startboost::spirit::qi::finite_iterator107         T start() const { return 0; }
got_maxboost::spirit::qi::finite_iterator108         bool got_max(T i) const { return i >= max; }
got_minboost::spirit::qi::finite_iterator109         bool got_min(T i) const { return i >= min; }
110 
111         T const min;
112         T const max;
113 
114     private:
115         // silence MSVC warning C4512: assignment operator could not be generated
116         finite_iterator& operator= (finite_iterator const&);
117     };
118 
119     template <typename T>
120     struct infinite_iterator // handles repeat(min, inf)[p]
121     {
infinite_iteratorboost::spirit::qi::infinite_iterator122         infinite_iterator(T const min_)
123           : min BOOST_PREVENT_MACRO_SUBSTITUTION (min_) {}
124 
125         typedef T type;
startboost::spirit::qi::infinite_iterator126         T start() const { return 0; }
got_maxboost::spirit::qi::infinite_iterator127         bool got_max(T /*i*/) const { return false; }
got_minboost::spirit::qi::infinite_iterator128         bool got_min(T i) const { return i >= min; }
129 
130         T const min;
131 
132     private:
133         // silence MSVC warning C4512: assignment operator could not be generated
134         infinite_iterator& operator= (infinite_iterator const&);
135     };
136 
137     template <typename Subject, typename LoopIter>
138     struct repeat_parser : unary_parser<repeat_parser<Subject, LoopIter> >
139     {
140         typedef Subject subject_type;
141 
142         template <typename Context, typename Iterator>
143         struct attribute
144         {
145             // Build a std::vector from the subject's attribute. Note
146             // that build_std_vector may return unused_type if the
147             // subject's attribute is an unused_type.
148             typedef typename
149                 traits::build_std_vector<
150                     typename traits::attribute_of<
151                         Subject, Context, Iterator>::type
152                 >::type
153             type;
154         };
155 
repeat_parserboost::spirit::qi::repeat_parser156         repeat_parser(Subject const& subject_, LoopIter const& iter_)
157           : subject(subject_), iter(iter_) {}
158 
159         template <typename F>
parse_containerboost::spirit::qi::repeat_parser160         bool parse_container(F f) const
161         {
162             typename LoopIter::type i = iter.start();
163             for (/**/; !iter.got_min(i); ++i)
164             {
165                 if (f (subject))
166                     return false;
167             }
168 
169             // parse some more up to the maximum specified
170             typename F::iterator_type save = f.f.first;
171             for (/**/; !iter.got_max(i); ++i)
172             {
173                 if (f (subject))
174                     break;
175                 save = f.f.first;
176             }
177 
178             f.f.first = save;
179             return true;
180         }
181 
182         template <typename Iterator, typename Context
183           , typename Skipper, typename Attribute>
parseboost::spirit::qi::repeat_parser184         bool parse(Iterator& first, Iterator const& last
185           , Context& context, Skipper const& skipper
186           , Attribute& attr_) const
187         {
188             typedef detail::fail_function<Iterator, Context, Skipper>
189                 fail_function;
190 
191             // ensure the attribute is actually a container type
192             traits::make_container(attr_);
193 
194             Iterator iter_local = first;
195             fail_function f(iter_local, last, context, skipper);
196             if (!parse_container(detail::make_pass_container(f, attr_)))
197                 return false;
198 
199             first = f.first;
200             return true;
201         }
202 
203         template <typename Context>
whatboost::spirit::qi::repeat_parser204         info what(Context& context) const
205         {
206             return info("repeat", subject.what(context));
207         }
208 
209         Subject subject;
210         LoopIter iter;
211 
212     private:
213         // silence MSVC warning C4512: assignment operator could not be generated
214         repeat_parser& operator= (repeat_parser const&);
215     };
216 
217     ///////////////////////////////////////////////////////////////////////////
218     // Parser generators: make_xxx function (objects)
219     ///////////////////////////////////////////////////////////////////////////
220     template <typename Subject, typename Modifiers>
221     struct make_directive<tag::repeat, Subject, Modifiers>
222     {
223         typedef kleene<Subject> result_type;
operator ()boost::spirit::qi::make_directive224         result_type operator()(unused_type, Subject const& subject, unused_type) const
225         {
226             return result_type(subject);
227         }
228     };
229 
230     template <typename T, typename Subject, typename Modifiers>
231     struct make_directive<
232         terminal_ex<tag::repeat, fusion::vector1<T> >, Subject, Modifiers>
233     {
234         typedef exact_iterator<T> iterator_type;
235         typedef repeat_parser<Subject, iterator_type> result_type;
236 
237         template <typename Terminal>
operator ()boost::spirit::qi::make_directive238         result_type operator()(
239             Terminal const& term, Subject const& subject, unused_type) const
240         {
241             return result_type(subject, fusion::at_c<0>(term.args));
242         }
243     };
244 
245     template <typename T, typename Subject, typename Modifiers>
246     struct make_directive<
247         terminal_ex<tag::repeat, fusion::vector2<T, T> >, Subject, Modifiers>
248     {
249         typedef finite_iterator<T> iterator_type;
250         typedef repeat_parser<Subject, iterator_type> result_type;
251 
252         template <typename Terminal>
operator ()boost::spirit::qi::make_directive253         result_type operator()(
254             Terminal const& term, Subject const& subject, unused_type) const
255         {
256             return result_type(subject,
257                 iterator_type(
258                     fusion::at_c<0>(term.args)
259                   , fusion::at_c<1>(term.args)
260                 )
261             );
262         }
263     };
264 
265     template <typename T, typename Subject, typename Modifiers>
266     struct make_directive<
267         terminal_ex<tag::repeat
268         , fusion::vector2<T, inf_type> >, Subject, Modifiers>
269     {
270         typedef infinite_iterator<T> iterator_type;
271         typedef repeat_parser<Subject, iterator_type> result_type;
272 
273         template <typename Terminal>
operator ()boost::spirit::qi::make_directive274         result_type operator()(
275             Terminal const& term, Subject const& subject, unused_type) const
276         {
277             return result_type(subject, fusion::at_c<0>(term.args));
278         }
279     };
280 }}}
281 
282 namespace boost { namespace spirit { namespace traits
283 {
284     ///////////////////////////////////////////////////////////////////////////
285     template <typename Subject, typename LoopIter>
286     struct has_semantic_action<qi::repeat_parser<Subject, LoopIter> >
287       : unary_has_semantic_action<Subject> {};
288 
289     ///////////////////////////////////////////////////////////////////////////
290     template <typename Subject, typename LoopIter, typename Attribute
291       , typename Context, typename Iterator>
292     struct handles_container<qi::repeat_parser<Subject, LoopIter>
293           , Attribute, Context, Iterator>
294       : mpl::true_ {};
295 }}}
296 
297 #endif
298