1 /*=============================================================================
2     Copyright (c) 2001-2011 Joel de Guzman
3     Copyright (c) 2011 Bryce Lelbach
4     Copyright (c) 2011 Jan Frederick Eick
5 
6     Distributed under the Boost Software License, Version 1.0. (See accompanying
7     file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
8 ==============================================================================*/
9 #if !defined(SPIRIT_UINT_APR_17_2006_0901AM)
10 #define SPIRIT_UINT_APR_17_2006_0901AM
11 
12 #if defined(_MSC_VER)
13 #pragma once
14 #endif
15 
16 #include <boost/spirit/home/qi/skip_over.hpp>
17 #include <boost/spirit/home/qi/detail/enable_lit.hpp>
18 #include <boost/spirit/home/qi/numeric/numeric_utils.hpp>
19 #include <boost/spirit/home/qi/meta_compiler.hpp>
20 #include <boost/spirit/home/qi/parser.hpp>
21 #include <boost/spirit/home/support/common_terminals.hpp>
22 #include <boost/spirit/home/support/info.hpp>
23 #include <boost/spirit/home/support/detail/is_spirit_tag.hpp>
24 #include <boost/mpl/assert.hpp>
25 #include <boost/type_traits/is_same.hpp>
26 
27 namespace boost { namespace spirit
28 {
29     namespace tag
30     {
31         template <typename T, unsigned Radix, unsigned MinDigits
32                 , int MaxDigits>
33         struct uint_parser
34         {
35             BOOST_SPIRIT_IS_TAG()
36         };
37     }
38 
39     namespace qi
40     {
41         ///////////////////////////////////////////////////////////////////////
42         // This one is the class that the user can instantiate directly in
43         // order to create a customized int parser
44         template <typename T = int, unsigned Radix = 10, unsigned MinDigits = 1
45                 , int MaxDigits = -1>
46         struct uint_parser
47           : spirit::terminal<tag::uint_parser<T, Radix, MinDigits, MaxDigits> >
48         {};
49     }
50 
51     ///////////////////////////////////////////////////////////////////////////
52     // Enablers
53     ///////////////////////////////////////////////////////////////////////////
54     template <> // enables ushort_
55     struct use_terminal<qi::domain, tag::ushort_> : mpl::true_ {};
56 
57     template <typename A0> // enables lit(n)
58     struct use_terminal<qi::domain
59         , terminal_ex<tag::lit, fusion::vector1<A0> >
60         , typename enable_if<is_same<A0, unsigned short> >::type>
61       : mpl::true_ {};
62 
63     template <typename A0> // enables ushort_(n)
64     struct use_terminal<qi::domain
65         , terminal_ex<tag::ushort_, fusion::vector1<A0> > >
66       : is_arithmetic<A0> {};
67 
68     template <> // enables *lazy* ushort_(n)
69     struct use_lazy_terminal<qi::domain, tag::ushort_, 1> : mpl::true_ {};
70 
71     ///////////////////////////////////////////////////////////////////////////
72     template <> // enables uint_
73     struct use_terminal<qi::domain, tag::uint_> : mpl::true_ {};
74 
75     template <typename A0> // enables lit(n)
76     struct use_terminal<qi::domain
77         , terminal_ex<tag::lit, fusion::vector1<A0> >
78         , typename enable_if<is_same<A0, unsigned> >::type>
79       : mpl::true_ {};
80 
81     template <typename A0> // enables uint_(n)
82     struct use_terminal<qi::domain
83         , terminal_ex<tag::uint_, fusion::vector1<A0> > >
84       : is_arithmetic<A0> {};
85 
86     template <> // enables *lazy* uint_(n)
87     struct use_lazy_terminal<qi::domain, tag::uint_, 1> : mpl::true_ {};
88 
89     ///////////////////////////////////////////////////////////////////////////
90     template <> // enables ulong_
91     struct use_terminal<qi::domain, tag::ulong_> : mpl::true_ {};
92 
93     template <typename A0> // enables lit(n)
94     struct use_terminal<qi::domain
95         , terminal_ex<tag::lit, fusion::vector1<A0> >
96         , typename enable_if<is_same<A0, unsigned long> >::type>
97       : mpl::true_ {};
98 
99     template <typename A0> // enables ulong_(n)
100     struct use_terminal<qi::domain
101         , terminal_ex<tag::ulong_, fusion::vector1<A0> > >
102       : is_arithmetic<A0> {};
103 
104     template <> // enables *lazy* ulong_(n)
105     struct use_lazy_terminal<qi::domain, tag::ulong_, 1> : mpl::true_ {};
106 
107     ///////////////////////////////////////////////////////////////////////////
108 #ifdef BOOST_HAS_LONG_LONG
109     template <> // enables ulong_long
110     struct use_terminal<qi::domain, tag::ulong_long> : mpl::true_ {};
111 
112     template <typename A0> // enables lit(n)
113     struct use_terminal<qi::domain
114         , terminal_ex<tag::lit, fusion::vector1<A0> >
115         , typename enable_if<is_same<A0, boost::ulong_long_type> >::type>
116       : mpl::true_ {};
117 
118     template <typename A0> // enables ulong_long(n)
119     struct use_terminal<qi::domain
120         , terminal_ex<tag::ulong_long, fusion::vector1<A0> > >
121       : is_arithmetic<A0> {};
122 
123     template <> // enables *lazy* ulong_long(n)
124     struct use_lazy_terminal<qi::domain, tag::ulong_long, 1> : mpl::true_ {};
125 #endif
126 
127     ///////////////////////////////////////////////////////////////////////////
128     template <> // enables bin
129     struct use_terminal<qi::domain, tag::bin> : mpl::true_ {};
130 
131     template <typename A0> // enables bin(n)
132     struct use_terminal<qi::domain
133         , terminal_ex<tag::bin, fusion::vector1<A0> > >
134       : is_arithmetic<A0> {};
135 
136     template <> // enables *lazy* bin(n)
137     struct use_lazy_terminal<qi::domain, tag::bin, 1> : mpl::true_ {};
138 
139     ///////////////////////////////////////////////////////////////////////////
140     template <> // enables oct
141     struct use_terminal<qi::domain, tag::oct> : mpl::true_ {};
142 
143     template <typename A0> // enables oct(n)
144     struct use_terminal<qi::domain
145         , terminal_ex<tag::oct, fusion::vector1<A0> > >
146       : is_arithmetic<A0> {};
147 
148     template <> // enables *lazy* oct(n)
149     struct use_lazy_terminal<qi::domain, tag::oct, 1> : mpl::true_ {};
150 
151     ///////////////////////////////////////////////////////////////////////////
152     template <> // enables hex
153     struct use_terminal<qi::domain, tag::hex> : mpl::true_ {};
154 
155     template <typename A0> // enables hex(n)
156     struct use_terminal<qi::domain
157         , terminal_ex<tag::hex, fusion::vector1<A0> > >
158       : is_arithmetic<A0> {};
159 
160     template <> // enables *lazy* hex(n)
161     struct use_lazy_terminal<qi::domain, tag::hex, 1> : mpl::true_ {};
162 
163     ///////////////////////////////////////////////////////////////////////////
164     // enables any custom uint_parser
165     template <typename T, unsigned Radix, unsigned MinDigits
166             , int MaxDigits>
167     struct use_terminal<qi::domain
168         , tag::uint_parser<T, Radix, MinDigits, MaxDigits> >
169       : mpl::true_ {};
170 
171     // enables any custom uint_parser(n)
172     template <typename T, unsigned Radix, unsigned MinDigits
173             , int MaxDigits, typename A0>
174     struct use_terminal<qi::domain
175         , terminal_ex<tag::uint_parser<T, Radix, MinDigits, MaxDigits>
176                   , fusion::vector1<A0> >
177     > : mpl::true_ {};
178 
179     // enables *lazy* custom uint_parser(n)
180     template <typename T, unsigned Radix, unsigned MinDigits
181             , int MaxDigits>
182     struct use_lazy_terminal<qi::domain
183       , tag::uint_parser<T, Radix, MinDigits, MaxDigits>, 1
184     > : mpl::true_ {};
185 }}
186 
187 namespace boost { namespace spirit { namespace qi
188 {
189 #ifndef BOOST_SPIRIT_NO_PREDEFINED_TERMINALS
190     using spirit::bin;
191     using spirit::oct;
192     using spirit::hex;
193 
194     using spirit::ushort_;
195     using spirit::uint_;
196     using spirit::ulong_;
197 #ifdef BOOST_HAS_LONG_LONG
198     using spirit::ulong_long;
199 #endif
200     using spirit::lit; // lit(1) is equivalent to 1
201 #endif
202 
203     using spirit::bin_type;
204     using spirit::oct_type;
205     using spirit::hex_type;
206 
207     using spirit::ushort_type;
208     using spirit::uint_type;
209     using spirit::ulong_type;
210 #ifdef BOOST_HAS_LONG_LONG
211     using spirit::ulong_long_type;
212 #endif
213     using spirit::lit_type;
214 
215     ///////////////////////////////////////////////////////////////////////////
216     // This is the actual uint parser
217     ///////////////////////////////////////////////////////////////////////////
218     template <typename T, unsigned Radix = 10, unsigned MinDigits = 1
219             , int MaxDigits = -1>
220     struct any_uint_parser
221       : primitive_parser<any_uint_parser<T, Radix, MinDigits, MaxDigits> >
222     {
223         // check template parameter 'Radix' for validity
224         BOOST_SPIRIT_ASSERT_MSG(
225             Radix >= 2 && Radix <= 36,
226             not_supported_radix, ());
227 
228         template <typename Context, typename Iterator>
229         struct attribute
230         {
231             typedef T type;
232         };
233 
234         template <typename Iterator, typename Context
235           , typename Skipper, typename Attribute>
parseboost::spirit::qi::any_uint_parser236         bool parse(Iterator& first, Iterator const& last
237           , Context& /*context*/, Skipper const& skipper
238           , Attribute& attr_) const
239         {
240             typedef extract_uint<T, Radix, MinDigits, MaxDigits> extract;
241             qi::skip_over(first, last, skipper);
242             return extract::call(first, last, attr_);
243         }
244 
245         template <typename Context>
whatboost::spirit::qi::any_uint_parser246         info what(Context& /*context*/) const
247         {
248             return info("unsigned-integer");
249         }
250     };
251     //]
252 
253     template <typename T, unsigned Radix = 10, unsigned MinDigits = 1
254             , int MaxDigits = -1, bool no_attribute = true>
255     struct literal_uint_parser
256       : primitive_parser<literal_uint_parser<T, Radix, MinDigits, MaxDigits
257         , no_attribute> >
258     {
259         // check template parameter 'Radix' for validity
260         BOOST_SPIRIT_ASSERT_MSG(
261             Radix == 2 || Radix == 8 || Radix == 10 || Radix == 16,
262             not_supported_radix, ());
263 
264         template <typename Value>
literal_uint_parserboost::spirit::qi::literal_uint_parser265         literal_uint_parser(Value const& n) : n_(n) {}
266 
267         template <typename Context, typename Iterator>
268         struct attribute
269           : mpl::if_c<no_attribute, unused_type, T>
270         {};
271 
272         template <typename Iterator, typename Context
273           , typename Skipper, typename Attribute>
parseboost::spirit::qi::literal_uint_parser274         bool parse(Iterator& first, Iterator const& last
275           , Context& /*context*/, Skipper const& skipper
276           , Attribute& attr_param) const
277         {
278             typedef extract_uint<T, Radix, MinDigits, MaxDigits> extract;
279             qi::skip_over(first, last, skipper);
280 
281             Iterator save = first;
282             T attr_;
283 
284             if (extract::call(first, last, attr_) && (attr_ == n_))
285             {
286                 traits::assign_to(attr_, attr_param);
287                 return true;
288             }
289 
290             first = save;
291             return false;
292         }
293 
294         template <typename Context>
whatboost::spirit::qi::literal_uint_parser295         info what(Context& /*context*/) const
296         {
297             return info("unsigned-integer");
298         }
299 
300         T n_;
301     };
302 
303     ///////////////////////////////////////////////////////////////////////////
304     // Parser generators: make_xxx function (objects)
305     ///////////////////////////////////////////////////////////////////////////
306     template <typename T, unsigned Radix = 10, unsigned MinDigits = 1
307             , int MaxDigits = -1>
308     struct make_uint
309     {
310         typedef any_uint_parser<T, Radix, MinDigits, MaxDigits> result_type;
operator ()boost::spirit::qi::make_uint311         result_type operator()(unused_type, unused_type) const
312         {
313             return result_type();
314         }
315     };
316 
317     template <typename T, unsigned Radix = 10, unsigned MinDigits = 1
318             , int MaxDigits = -1>
319     struct make_direct_uint
320     {
321         typedef literal_uint_parser<T, Radix, MinDigits, MaxDigits, false>
322             result_type;
323         template <typename Terminal>
operator ()boost::spirit::qi::make_direct_uint324         result_type operator()(Terminal const& term, unused_type) const
325         {
326             return result_type(fusion::at_c<0>(term.args));
327         }
328     };
329 
330     template <typename T, unsigned Radix = 10, unsigned MinDigits = 1
331             , int MaxDigits = -1>
332     struct make_literal_uint
333     {
334         typedef literal_uint_parser<T, Radix, MinDigits, MaxDigits> result_type;
335         template <typename Terminal>
operator ()boost::spirit::qi::make_literal_uint336         result_type operator()(Terminal const& term, unused_type) const
337         {
338             return result_type(fusion::at_c<0>(term.args));
339         }
340     };
341 
342     ///////////////////////////////////////////////////////////////////////////
343     template <typename Modifiers, typename A0>
344     struct make_primitive<
345           terminal_ex<tag::lit, fusion::vector1<A0> >
346         , Modifiers, typename enable_if<is_same<A0, unsigned short> >::type>
347       : make_literal_uint<unsigned short> {};
348 
349     template <typename Modifiers, typename A0>
350     struct make_primitive<
351           terminal_ex<tag::lit, fusion::vector1<A0> >
352         , Modifiers, typename enable_if<is_same<A0, unsigned> >::type>
353       : make_literal_uint<unsigned> {};
354 
355     template <typename Modifiers, typename A0>
356     struct make_primitive<
357           terminal_ex<tag::lit, fusion::vector1<A0> >
358         , Modifiers, typename enable_if<is_same<A0, unsigned long> >::type>
359       : make_literal_uint<unsigned long> {};
360 
361 #ifdef BOOST_HAS_LONG_LONG
362     template <typename Modifiers, typename A0>
363     struct make_primitive<
364           terminal_ex<tag::lit, fusion::vector1<A0> >
365         , Modifiers, typename enable_if<is_same<A0, boost::ulong_long_type> >::type>
366       : make_literal_uint<boost::ulong_long_type> {};
367 #endif
368 
369     ///////////////////////////////////////////////////////////////////////////
370     template <typename T, unsigned Radix, unsigned MinDigits, int MaxDigits
371             , typename Modifiers>
372     struct make_primitive<
373         tag::uint_parser<T, Radix, MinDigits, MaxDigits>
374       , Modifiers>
375       : make_uint<T, Radix, MinDigits, MaxDigits> {};
376 
377     template <typename T, unsigned Radix, unsigned MinDigits, int MaxDigits
378             , typename A0, typename Modifiers>
379     struct make_primitive<
380         terminal_ex<tag::uint_parser<T, Radix, MinDigits, MaxDigits>
381       , fusion::vector1<A0> >, Modifiers>
382       : make_direct_uint<T, Radix, MinDigits, MaxDigits> {};
383 
384     ///////////////////////////////////////////////////////////////////////////
385     template <typename Modifiers>
386     struct make_primitive<tag::bin, Modifiers>
387       : make_uint<unsigned, 2> {};
388 
389     template <typename Modifiers, typename A0>
390     struct make_primitive<
391         terminal_ex<tag::bin
392       , fusion::vector1<A0> > , Modifiers>
393       : make_direct_uint<unsigned, 2> {};
394 
395     ///////////////////////////////////////////////////////////////////////////
396     template <typename Modifiers>
397     struct make_primitive<tag::oct, Modifiers>
398       : make_uint<unsigned, 8> {};
399 
400     template <typename Modifiers, typename A0>
401     struct make_primitive<
402         terminal_ex<tag::oct
403       , fusion::vector1<A0> > , Modifiers>
404       : make_direct_uint<unsigned, 8> {};
405 
406     ///////////////////////////////////////////////////////////////////////////
407     template <typename Modifiers>
408     struct make_primitive<tag::hex, Modifiers>
409       : make_uint<unsigned, 16> {};
410 
411     template <typename Modifiers, typename A0>
412     struct make_primitive<
413         terminal_ex<tag::hex
414       , fusion::vector1<A0> > , Modifiers>
415       : make_direct_uint<unsigned, 16> {};
416 
417     ///////////////////////////////////////////////////////////////////////////
418     template <typename Modifiers>
419     struct make_primitive<tag::ushort_, Modifiers>
420       : make_uint<unsigned short> {};
421 
422     template <typename Modifiers, typename A0>
423     struct make_primitive<
424         terminal_ex<tag::ushort_
425       , fusion::vector1<A0> > , Modifiers>
426       : make_direct_uint<unsigned short> {};
427 
428     ///////////////////////////////////////////////////////////////////////////
429     template <typename Modifiers>
430     struct make_primitive<tag::uint_, Modifiers>
431       : make_uint<unsigned> {};
432 
433     template <typename Modifiers, typename A0>
434     struct make_primitive<
435         terminal_ex<tag::uint_
436       , fusion::vector1<A0> > , Modifiers>
437       : make_direct_uint<unsigned> {};
438 
439     ///////////////////////////////////////////////////////////////////////////
440     template <typename Modifiers>
441     struct make_primitive<tag::ulong_, Modifiers>
442       : make_uint<unsigned long> {};
443 
444     template <typename Modifiers, typename A0>
445     struct make_primitive<
446         terminal_ex<tag::ulong_
447       , fusion::vector1<A0> > , Modifiers>
448       : make_direct_uint<unsigned long> {};
449 
450     ///////////////////////////////////////////////////////////////////////////
451 #ifdef BOOST_HAS_LONG_LONG
452     template <typename Modifiers>
453     struct make_primitive<tag::ulong_long, Modifiers>
454       : make_uint<boost::ulong_long_type> {};
455 
456     template <typename Modifiers, typename A0>
457     struct make_primitive<
458         terminal_ex<tag::ulong_long
459       , fusion::vector1<A0> > , Modifiers>
460       : make_direct_uint<boost::ulong_long_type> {};
461 #endif
462 }}}
463 
464 #endif
465