1 /*=============================================================================
2     Copyright (c) 2001-2011 Joel de Guzman
3     Copyright (c)      2011 Bryce Lelbach
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(BOOST_SPIRIT_INT_APR_17_2006_0830AM)
9 #define BOOST_SPIRIT_INT_APR_17_2006_0830AM
10 
11 #if defined(_MSC_VER)
12 #pragma once
13 #endif
14 
15 #include <boost/spirit/home/qi/skip_over.hpp>
16 #include <boost/spirit/home/qi/detail/enable_lit.hpp>
17 #include <boost/spirit/home/qi/numeric/numeric_utils.hpp>
18 #include <boost/spirit/home/qi/meta_compiler.hpp>
19 #include <boost/spirit/home/qi/parser.hpp>
20 #include <boost/spirit/home/support/common_terminals.hpp>
21 #include <boost/spirit/home/support/info.hpp>
22 #include <boost/spirit/home/support/detail/is_spirit_tag.hpp>
23 #include <boost/mpl/assert.hpp>
24 #include <boost/type_traits/is_same.hpp>
25 
26 namespace boost { namespace spirit
27 {
28     namespace tag
29     {
30         template <typename T, unsigned Radix, unsigned MinDigits
31                 , int MaxDigits>
32         struct int_parser
33         {
34             BOOST_SPIRIT_IS_TAG()
35         };
36     }
37 
38     namespace qi
39     {
40         ///////////////////////////////////////////////////////////////////////
41         // This one is the class that the user can instantiate directly in
42         // order to create a customized int parser
43         template <typename T = int, unsigned Radix = 10, unsigned MinDigits = 1
44                 , int MaxDigits = -1>
45         struct int_parser
46           : spirit::terminal<tag::int_parser<T, Radix, MinDigits, MaxDigits> >
47         {};
48     }
49 
50     ///////////////////////////////////////////////////////////////////////////
51     // Enablers
52     ///////////////////////////////////////////////////////////////////////////
53     //[primitive_parsers_enable_short
54     template <> // enables short_
55     struct use_terminal<qi::domain, tag::short_> : mpl::true_ {};
56     //]
57 
58     template <typename A0> // enables lit(n)
59     struct use_terminal<qi::domain
60         , terminal_ex<tag::lit, fusion::vector1<A0> >
61         , typename enable_if<is_same<A0, signed short> >::type>
62       : mpl::true_ {};
63 
64     template <typename A0> // enables short_(n)
65     struct use_terminal<qi::domain
66         , terminal_ex<tag::short_, fusion::vector1<A0> > >
67       : is_arithmetic<A0> {};
68 
69     template <> // enables *lazy* short_(n)
70     struct use_lazy_terminal<qi::domain, tag::short_, 1> : mpl::true_ {};
71 
72     ///////////////////////////////////////////////////////////////////////////
73     //[primitive_parsers_enable_int
74     template <> // enables int_
75     struct use_terminal<qi::domain, tag::int_> : mpl::true_ {};
76     //]
77 
78     template <typename A0> // enables lit(n)
79     struct use_terminal<qi::domain
80         , terminal_ex<tag::lit, fusion::vector1<A0> >
81         , typename enable_if<is_same<A0, signed> >::type>
82       : mpl::true_ {};
83 
84     template <typename A0> // enables int_(n)
85     struct use_terminal<qi::domain
86         , terminal_ex<tag::int_, fusion::vector1<A0> > >
87       : is_arithmetic<A0> {};
88 
89     template <> // enables *lazy* int_(n)
90     struct use_lazy_terminal<qi::domain, tag::int_, 1> : mpl::true_ {};
91 
92     ///////////////////////////////////////////////////////////////////////////
93     //[primitive_parsers_enable_long
94     template <> // enables long_
95     struct use_terminal<qi::domain, tag::long_> : mpl::true_ {};
96     //]
97 
98     template <typename A0> // enables lit(n)
99     struct use_terminal<qi::domain
100         , terminal_ex<tag::lit, fusion::vector1<A0> >
101         , typename enable_if<is_same<A0, signed long> >::type>
102       : mpl::true_ {};
103 
104     template <typename A0> // enables long_(n)
105     struct use_terminal<qi::domain
106         , terminal_ex<tag::long_, fusion::vector1<A0> > >
107       : is_arithmetic<A0> {};
108 
109     template <> // enables *lazy* long_(n)
110     struct use_lazy_terminal<qi::domain, tag::long_, 1> : mpl::true_ {};
111 
112     ///////////////////////////////////////////////////////////////////////////
113 #ifdef BOOST_HAS_LONG_LONG
114     //[primitive_parsers_enable_long_long
115     template <> // enables long_long
116     struct use_terminal<qi::domain, tag::long_long> : mpl::true_ {};
117     //]
118 
119     template <typename A0> // enables lit(n)
120     struct use_terminal<qi::domain
121         , terminal_ex<tag::lit, fusion::vector1<A0> >
122         , typename enable_if<is_same<A0, boost::long_long_type> >::type>
123       : mpl::true_ {};
124 
125     template <typename A0> // enables long_long(n)
126     struct use_terminal<qi::domain
127         , terminal_ex<tag::long_long, fusion::vector1<A0> > >
128       : is_arithmetic<A0> {};
129 
130     template <> // enables *lazy* long_long(n)
131     struct use_lazy_terminal<qi::domain, tag::long_long, 1> : mpl::true_ {};
132 #endif
133 
134     ///////////////////////////////////////////////////////////////////////////
135     // enables any custom int_parser
136     template <typename T, unsigned Radix, unsigned MinDigits
137             , int MaxDigits>
138     struct use_terminal<qi::domain
139         , tag::int_parser<T, Radix, MinDigits, MaxDigits> >
140       : mpl::true_ {};
141 
142     // enables any custom int_parser(n)
143     template <typename T, unsigned Radix, unsigned MinDigits
144             , int MaxDigits, typename A0>
145     struct use_terminal<qi::domain
146         , terminal_ex<tag::int_parser<T, Radix, MinDigits, MaxDigits>
147                   , fusion::vector1<A0> >
148     > : mpl::true_ {};
149 
150     // enables *lazy* custom int_parser(n)
151     template <typename T, unsigned Radix, unsigned MinDigits
152             , int MaxDigits>
153     struct use_lazy_terminal<qi::domain
154       , tag::int_parser<T, Radix, MinDigits, MaxDigits>, 1
155     > : mpl::true_ {};
156 }}
157 
158 namespace boost { namespace spirit { namespace qi
159 {
160 #ifndef BOOST_SPIRIT_NO_PREDEFINED_TERMINALS
161     using spirit::short_;
162     using spirit::int_;
163     using spirit::long_;
164 #ifdef BOOST_HAS_LONG_LONG
165     using spirit::long_long;
166 #endif
167     using spirit::lit;    // lit(1) is equivalent to 1
168 #endif
169     using spirit::short_type;
170     using spirit::int_type;
171     using spirit::long_type;
172     using spirit::lit_type;
173 #ifdef BOOST_HAS_LONG_LONG
174     using spirit::long_long_type;
175 #endif
176     using spirit::lit_type;
177 
178     ///////////////////////////////////////////////////////////////////////////
179     // This is the actual int parser
180     ///////////////////////////////////////////////////////////////////////////
181     //[primitive_parsers_int_parser
182     template <
183         typename T
184       , unsigned Radix = 10
185       , unsigned MinDigits = 1
186       , int MaxDigits = -1>
187     struct any_int_parser
188       : primitive_parser<any_int_parser<T, Radix, MinDigits, MaxDigits> >
189     {
190         // check template parameter 'Radix' for validity
191         BOOST_SPIRIT_ASSERT_MSG(
192             Radix == 2 || Radix == 8 || Radix == 10 || Radix == 16,
193             not_supported_radix, ());
194 
195         template <typename Context, typename Iterator>
196         struct attribute
197         {
198             typedef T type;
199         };
200 
201         template <typename Iterator, typename Context
202           , typename Skipper, typename Attribute>
parseboost::spirit::qi::any_int_parser203         bool parse(Iterator& first, Iterator const& last
204           , Context& /*context*/, Skipper const& skipper
205           , Attribute& attr_) const
206         {
207             typedef extract_int<T, Radix, MinDigits, MaxDigits> extract;
208             qi::skip_over(first, last, skipper);
209             return extract::call(first, last, attr_);
210         }
211 
212         template <typename Context>
whatboost::spirit::qi::any_int_parser213         info what(Context& /*context*/) const
214         {
215             return info("integer");
216         }
217     };
218     //]
219 
220     template <typename T, unsigned Radix = 10, unsigned MinDigits = 1
221             , int MaxDigits = -1, bool no_attribute = true>
222     struct literal_int_parser
223       : primitive_parser<literal_int_parser<T, Radix, MinDigits, MaxDigits
224         , no_attribute> >
225     {
226         // check template parameter 'Radix' for validity
227         BOOST_SPIRIT_ASSERT_MSG(
228             Radix == 2 || Radix == 8 || Radix == 10 || Radix == 16,
229             not_supported_radix, ());
230 
231         template <typename Value>
literal_int_parserboost::spirit::qi::literal_int_parser232         literal_int_parser(Value const& n) : n_(n) {}
233 
234         template <typename Context, typename Iterator>
235         struct attribute
236           : mpl::if_c<no_attribute, unused_type, T>
237         {};
238 
239         template <typename Iterator, typename Context
240           , typename Skipper, typename Attribute>
parseboost::spirit::qi::literal_int_parser241         bool parse(Iterator& first, Iterator const& last
242           , Context& /*context*/, Skipper const& skipper
243           , Attribute& attr_param) const
244         {
245             typedef extract_int<T, Radix, MinDigits, MaxDigits> extract;
246             qi::skip_over(first, last, skipper);
247 
248             Iterator save = first;
249             T attr_;
250 
251             if (extract::call(first, last, attr_) && (attr_ == n_))
252             {
253                 traits::assign_to(attr_, attr_param);
254                 return true;
255             }
256 
257             first = save;
258             return false;
259         }
260 
261         template <typename Context>
whatboost::spirit::qi::literal_int_parser262         info what(Context& /*context*/) const
263         {
264             return info("integer");
265         }
266 
267         T n_;
268     };
269 
270     ///////////////////////////////////////////////////////////////////////////
271     // Parser generators: make_xxx function (objects)
272     ///////////////////////////////////////////////////////////////////////////
273     //[primitive_parsers_make_int
274     template <
275         typename T
276       , unsigned Radix = 10
277       , unsigned MinDigits = 1
278       , int MaxDigits = -1>
279     struct make_int
280     {
281         typedef any_int_parser<T, Radix, MinDigits, MaxDigits> result_type;
operator ()boost::spirit::qi::make_int282         result_type operator()(unused_type, unused_type) const
283         {
284             return result_type();
285         }
286     };
287     //]
288 
289     template <typename T, unsigned Radix = 10, unsigned MinDigits = 1
290             , int MaxDigits = -1>
291     struct make_direct_int
292     {
293         typedef literal_int_parser<T, Radix, MinDigits, MaxDigits, false>
294             result_type;
295         template <typename Terminal>
operator ()boost::spirit::qi::make_direct_int296         result_type operator()(Terminal const& term, unused_type) const
297         {
298             return result_type(fusion::at_c<0>(term.args));
299         }
300     };
301 
302     template <typename T, unsigned Radix = 10, unsigned MinDigits = 1
303             , int MaxDigits = -1>
304     struct make_literal_int
305     {
306         typedef literal_int_parser<T, Radix, MinDigits, MaxDigits> result_type;
307         template <typename Terminal>
operator ()boost::spirit::qi::make_literal_int308         result_type operator()(Terminal const& term, unused_type) const
309         {
310             return result_type(fusion::at_c<0>(term.args));
311         }
312     };
313 
314     ///////////////////////////////////////////////////////////////////////////
315     template <typename Modifiers, typename A0>
316     struct make_primitive<
317           terminal_ex<tag::lit, fusion::vector1<A0> >
318         , Modifiers, typename enable_if<is_same<A0, signed short> >::type>
319       : make_literal_int<signed short> {};
320 
321     template <typename Modifiers, typename A0>
322     struct make_primitive<
323           terminal_ex<tag::lit, fusion::vector1<A0> >
324         , Modifiers, typename enable_if<is_same<A0, signed> >::type>
325       : make_literal_int<signed> {};
326 
327     template <typename Modifiers, typename A0>
328     struct make_primitive<
329           terminal_ex<tag::lit, fusion::vector1<A0> >
330         , Modifiers, typename enable_if<is_same<A0, signed long> >::type>
331       : make_literal_int<signed long> {};
332 
333 #ifdef BOOST_HAS_LONG_LONG
334     template <typename Modifiers, typename A0>
335     struct make_primitive<
336           terminal_ex<tag::lit, fusion::vector1<A0> >
337         , Modifiers, typename enable_if<is_same<A0, boost::long_long_type> >::type>
338       : make_literal_int<boost::long_long_type> {};
339 #endif
340 
341     ///////////////////////////////////////////////////////////////////////////
342     template <typename T, unsigned Radix, unsigned MinDigits, int MaxDigits
343             , typename Modifiers>
344     struct make_primitive<
345         tag::int_parser<T, Radix, MinDigits, MaxDigits>
346       , Modifiers>
347       : make_int<T, Radix, MinDigits, MaxDigits> {};
348 
349     template <typename T, unsigned Radix, unsigned MinDigits, int MaxDigits
350             , typename A0, typename Modifiers>
351     struct make_primitive<
352         terminal_ex<tag::int_parser<T, Radix, MinDigits, MaxDigits>
353       , fusion::vector1<A0> >, Modifiers>
354       : make_direct_int<T, Radix, MinDigits, MaxDigits> {};
355 
356     ///////////////////////////////////////////////////////////////////////////
357     //[primitive_parsers_short_primitive
358     template <typename Modifiers>
359     struct make_primitive<tag::short_, Modifiers>
360       : make_int<short> {};
361     //]
362 
363     template <typename Modifiers, typename A0>
364     struct make_primitive<
365         terminal_ex<tag::short_
366       , fusion::vector1<A0> > , Modifiers>
367       : make_direct_int<short> {};
368 
369     ///////////////////////////////////////////////////////////////////////////
370     //[primitive_parsers_int_primitive
371     template <typename Modifiers>
372     struct make_primitive<tag::int_, Modifiers>
373       : make_int<int> {};
374     //]
375 
376     template <typename Modifiers, typename A0>
377     struct make_primitive<
378         terminal_ex<tag::int_
379       , fusion::vector1<A0> > , Modifiers>
380       : make_direct_int<int> {};
381 
382     ///////////////////////////////////////////////////////////////////////////
383     //[primitive_parsers_long_primitive
384     template <typename Modifiers>
385     struct make_primitive<tag::long_, Modifiers>
386       : make_int<long> {};
387     //]
388 
389     template <typename Modifiers, typename A0>
390     struct make_primitive<
391         terminal_ex<tag::long_
392       , fusion::vector1<A0> > , Modifiers>
393       : make_direct_int<long> {};
394 
395     ///////////////////////////////////////////////////////////////////////////
396 #ifdef BOOST_HAS_LONG_LONG
397     //[primitive_parsers_long_long_primitive
398     template <typename Modifiers>
399     struct make_primitive<tag::long_long, Modifiers>
400       : make_int<boost::long_long_type> {};
401     //]
402 
403     template <typename Modifiers, typename A0>
404     struct make_primitive<
405         terminal_ex<tag::long_long
406       , fusion::vector1<A0> > , Modifiers>
407       : make_direct_int<boost::long_long_type> {};
408 #endif
409 }}}
410 
411 #endif
412