• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #ifndef BOOST_SPIRIT_QI_DIRECTIVE_REPEAT_HPP
9 #define BOOST_SPIRIT_QI_DIRECTIVE_REPEAT_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/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         // silence MSVC warning C4512: assignment operator could not be generated
95         BOOST_DELETED_FUNCTION(exact_iterator& operator= (exact_iterator const&))
96     };
97 
98     template <typename T>
99     struct finite_iterator // handles repeat(min, max)[p]
100     {
finite_iteratorboost::spirit::qi::finite_iterator101         finite_iterator(T const min_, T const max_)
102           : min BOOST_PREVENT_MACRO_SUBSTITUTION (min_)
103           , max BOOST_PREVENT_MACRO_SUBSTITUTION (max_) {}
104 
105         typedef T type;
startboost::spirit::qi::finite_iterator106         T start() const { return 0; }
got_maxboost::spirit::qi::finite_iterator107         bool got_max(T i) const { return i >= max; }
got_minboost::spirit::qi::finite_iterator108         bool got_min(T i) const { return i >= min; }
109 
110         T const min;
111         T const max;
112 
113         // silence MSVC warning C4512: assignment operator could not be generated
114         BOOST_DELETED_FUNCTION(finite_iterator& operator= (finite_iterator const&))
115     };
116 
117     template <typename T>
118     struct infinite_iterator // handles repeat(min, inf)[p]
119     {
infinite_iteratorboost::spirit::qi::infinite_iterator120         infinite_iterator(T const min_)
121           : min BOOST_PREVENT_MACRO_SUBSTITUTION (min_) {}
122 
123         typedef T type;
startboost::spirit::qi::infinite_iterator124         T start() const { return 0; }
got_maxboost::spirit::qi::infinite_iterator125         bool got_max(T /*i*/) const { return false; }
got_minboost::spirit::qi::infinite_iterator126         bool got_min(T i) const { return i >= min; }
127 
128         T const min;
129 
130         // silence MSVC warning C4512: assignment operator could not be generated
131         BOOST_DELETED_FUNCTION(infinite_iterator& operator= (infinite_iterator const&))
132     };
133 
134     template <typename Subject, typename LoopIter>
135     struct repeat_parser : unary_parser<repeat_parser<Subject, LoopIter> >
136     {
137         typedef Subject subject_type;
138 
139         template <typename Context, typename Iterator>
140         struct attribute
141         {
142             // Build a std::vector from the subject's attribute. Note
143             // that build_std_vector may return unused_type if the
144             // subject's attribute is an unused_type.
145             typedef typename
146                 traits::build_std_vector<
147                     typename traits::attribute_of<
148                         Subject, Context, Iterator>::type
149                 >::type
150             type;
151         };
152 
repeat_parserboost::spirit::qi::repeat_parser153         repeat_parser(Subject const& subject_, LoopIter const& iter_)
154           : subject(subject_), iter(iter_) {}
155 
156         template <typename F>
parse_containerboost::spirit::qi::repeat_parser157         bool parse_container(F f) const
158         {
159             typename LoopIter::type i = iter.start();
160             for (/**/; !iter.got_min(i); ++i)
161             {
162                 if (f (subject))
163                     return false;
164             }
165 
166             // parse some more up to the maximum specified
167             typename F::iterator_type save = f.f.first;
168             for (/**/; !iter.got_max(i); ++i)
169             {
170                 if (f (subject))
171                     break;
172                 save = f.f.first;
173             }
174 
175             f.f.first = save;
176             return true;
177         }
178 
179         template <typename Iterator, typename Context
180           , typename Skipper, typename Attribute>
parseboost::spirit::qi::repeat_parser181         bool parse(Iterator& first, Iterator const& last
182           , Context& context, Skipper const& skipper
183           , Attribute& attr_) const
184         {
185             typedef detail::fail_function<Iterator, Context, Skipper>
186                 fail_function;
187 
188             // ensure the attribute is actually a container type
189             traits::make_container(attr_);
190 
191             Iterator iter_local = first;
192             fail_function f(iter_local, last, context, skipper);
193             if (!parse_container(detail::make_pass_container(f, attr_)))
194                 return false;
195 
196             first = f.first;
197             return true;
198         }
199 
200         template <typename Context>
whatboost::spirit::qi::repeat_parser201         info what(Context& context) const
202         {
203             return info("repeat", subject.what(context));
204         }
205 
206         Subject subject;
207         LoopIter iter;
208 
209         // silence MSVC warning C4512: assignment operator could not be generated
210         BOOST_DELETED_FUNCTION(repeat_parser& operator= (repeat_parser const&))
211     };
212 
213     ///////////////////////////////////////////////////////////////////////////
214     // Parser generators: make_xxx function (objects)
215     ///////////////////////////////////////////////////////////////////////////
216     template <typename Subject, typename Modifiers>
217     struct make_directive<tag::repeat, Subject, Modifiers>
218     {
219         typedef kleene<Subject> result_type;
operator ()boost::spirit::qi::make_directive220         result_type operator()(unused_type, Subject const& subject, unused_type) const
221         {
222             return result_type(subject);
223         }
224     };
225 
226     template <typename T, typename Subject, typename Modifiers>
227     struct make_directive<
228         terminal_ex<tag::repeat, fusion::vector1<T> >, Subject, Modifiers>
229     {
230         typedef exact_iterator<T> iterator_type;
231         typedef repeat_parser<Subject, iterator_type> result_type;
232 
233         template <typename Terminal>
operator ()boost::spirit::qi::make_directive234         result_type operator()(
235             Terminal const& term, Subject const& subject, unused_type) const
236         {
237             return result_type(subject, fusion::at_c<0>(term.args));
238         }
239     };
240 
241     template <typename T, typename Subject, typename Modifiers>
242     struct make_directive<
243         terminal_ex<tag::repeat, fusion::vector2<T, T> >, Subject, Modifiers>
244     {
245         typedef finite_iterator<T> iterator_type;
246         typedef repeat_parser<Subject, iterator_type> result_type;
247 
248         template <typename Terminal>
operator ()boost::spirit::qi::make_directive249         result_type operator()(
250             Terminal const& term, Subject const& subject, unused_type) const
251         {
252             return result_type(subject,
253                 iterator_type(
254                     fusion::at_c<0>(term.args)
255                   , fusion::at_c<1>(term.args)
256                 )
257             );
258         }
259     };
260 
261     template <typename T, typename Subject, typename Modifiers>
262     struct make_directive<
263         terminal_ex<tag::repeat
264         , fusion::vector2<T, inf_type> >, Subject, Modifiers>
265     {
266         typedef infinite_iterator<T> iterator_type;
267         typedef repeat_parser<Subject, iterator_type> result_type;
268 
269         template <typename Terminal>
operator ()boost::spirit::qi::make_directive270         result_type operator()(
271             Terminal const& term, Subject const& subject, unused_type) const
272         {
273             return result_type(subject, fusion::at_c<0>(term.args));
274         }
275     };
276 }}}
277 
278 namespace boost { namespace spirit { namespace traits
279 {
280     ///////////////////////////////////////////////////////////////////////////
281     template <typename Subject, typename LoopIter>
282     struct has_semantic_action<qi::repeat_parser<Subject, LoopIter> >
283       : unary_has_semantic_action<Subject> {};
284 
285     ///////////////////////////////////////////////////////////////////////////
286     template <typename Subject, typename LoopIter, typename Attribute
287       , typename Context, typename Iterator>
288     struct handles_container<qi::repeat_parser<Subject, LoopIter>
289           , Attribute, Context, Iterator>
290       : mpl::true_ {};
291 }}}
292 
293 #endif
294