1 //  Copyright (c) 2001-2011 Hartmut Kaiser
2 //
3 //  Distributed under the Boost Software License, Version 1.0. (See accompanying
4 //  file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
5 
6 #if !defined(BOOST_SPIRIT_LEX_PLAIN_TOKENID_NOV_26_2010_0944AM)
7 #define BOOST_SPIRIT_LEX_PLAIN_TOKENID_NOV_26_2010_0944AM
8 
9 #if defined(_MSC_VER)
10 #pragma once
11 #endif
12 
13 #include <boost/spirit/home/support/info.hpp>
14 #include <boost/spirit/home/qi/detail/attributes.hpp>
15 #include <boost/spirit/home/support/common_terminals.hpp>
16 #include <boost/spirit/home/support/handles_container.hpp>
17 #include <boost/spirit/home/qi/skip_over.hpp>
18 #include <boost/spirit/home/qi/domain.hpp>
19 #include <boost/spirit/home/qi/parser.hpp>
20 #include <boost/spirit/home/qi/meta_compiler.hpp>
21 #include <boost/spirit/home/qi/detail/assign_to.hpp>
22 #include <boost/range/iterator_range.hpp>
23 #include <boost/fusion/include/vector.hpp>
24 #include <boost/fusion/include/at.hpp>
25 #include <boost/mpl/or.hpp>
26 #include <boost/mpl/and.hpp>
27 #include <boost/type_traits/is_integral.hpp>
28 #include <boost/type_traits/is_enum.hpp>
29 #include <boost/lexical_cast.hpp>
30 #include <iterator> // for std::iterator_traits
31 
32 namespace boost { namespace spirit
33 {
34     ///////////////////////////////////////////////////////////////////////////
35     // Enablers
36     ///////////////////////////////////////////////////////////////////////////
37 
38     // enables tokenid
39     template <>
40     struct use_terminal<qi::domain, tag::tokenid>
41       : mpl::true_ {};
42 
43     // enables tokenid(id)
44     template <typename A0>
45     struct use_terminal<qi::domain
46       , terminal_ex<tag::tokenid, fusion::vector1<A0> >
47     > : mpl::or_<is_integral<A0>, is_enum<A0> > {};
48 
49     // enables tokenid(idmin, idmax)
50     template <typename A0, typename A1>
51     struct use_terminal<qi::domain
52       , terminal_ex<tag::tokenid, fusion::vector2<A0, A1> >
53     > : mpl::and_<
54             mpl::or_<is_integral<A0>, is_enum<A0> >
55           , mpl::or_<is_integral<A1>, is_enum<A1> >
56         > {};
57 
58     // enables *lazy* tokenid(id)
59     template <>
60     struct use_lazy_terminal<
61         qi::domain, tag::tokenid, 1
62     > : mpl::true_ {};
63 
64     // enables *lazy* tokenid(idmin, idmax)
65     template <>
66     struct use_lazy_terminal<
67         qi::domain, tag::tokenid, 2
68     > : mpl::true_ {};
69 }}
70 
71 namespace boost { namespace spirit { namespace qi
72 {
73 #ifndef BOOST_SPIRIT_NO_PREDEFINED_TERMINALS
74     using spirit::tokenid;
75 #endif
76     using spirit::tokenid_type;
77 
78     ///////////////////////////////////////////////////////////////////////////
79     // The plain_tokenid represents a simple token defined by the lexer inside
80     // a Qi grammar. The difference to plain_token is that it exposes the
81     // matched token id instead of the iterator_range of the matched input.
82     template <typename TokenId>
83     struct plain_tokenid
84       : primitive_parser<plain_tokenid<TokenId> >
85     {
86         template <typename Context, typename Iterator>
87         struct attribute
88         {
89             typedef TokenId type;
90         };
91 
plain_tokenidboost::spirit::qi::plain_tokenid92         plain_tokenid(TokenId const& id)
93           : id(id) {}
94 
95         template <typename Iterator, typename Context
96           , typename Skipper, typename Attribute>
parseboost::spirit::qi::plain_tokenid97         bool parse(Iterator& first, Iterator const& last
98           , Context& /*context*/, Skipper const& skipper
99           , Attribute& attr) const
100         {
101             qi::skip_over(first, last, skipper);   // always do a pre-skip
102 
103             if (first != last) {
104                 // simply match the token id with the id this component has
105                 // been initialized with
106 
107                 typedef typename
108                     std::iterator_traits<Iterator>::value_type
109                 token_type;
110                 typedef typename token_type::id_type id_type;
111 
112                 token_type const& t = *first;
113                 if (id_type(~0) == id_type(id) || id_type(id) == t.id()) {
114                     spirit::traits::assign_to(id, attr);
115                     ++first;
116                     return true;
117                 }
118             }
119             return false;
120         }
121 
122         template <typename Context>
whatboost::spirit::qi::plain_tokenid123         info what(Context& /*context*/) const
124         {
125             return info("tokenid",
126                 "tokenid(" + boost::lexical_cast<utf8_string>(id) + ")");
127         }
128 
129         TokenId id;
130     };
131 
132     ///////////////////////////////////////////////////////////////////////////
133     template <typename TokenId>
134     struct plain_tokenid_range
135       : primitive_parser<plain_tokenid_range<TokenId> >
136     {
137         template <typename Context, typename Iterator>
138         struct attribute
139         {
140             typedef TokenId type;
141         };
142 
plain_tokenid_rangeboost::spirit::qi::plain_tokenid_range143         plain_tokenid_range(TokenId const& idmin, TokenId const& idmax)
144           : idmin(idmin), idmax(idmax) {}
145 
146         template <typename Iterator, typename Context
147           , typename Skipper, typename Attribute>
parseboost::spirit::qi::plain_tokenid_range148         bool parse(Iterator& first, Iterator const& last
149           , Context& /*context*/, Skipper const& skipper
150           , Attribute& attr) const
151         {
152             qi::skip_over(first, last, skipper);   // always do a pre-skip
153 
154             if (first != last) {
155                 // simply match the token id with the id this component has
156                 // been initialized with
157 
158                 typedef typename
159                     std::iterator_traits<Iterator>::value_type
160                 token_type;
161                 typedef typename token_type::id_type id_type;
162 
163                 token_type const& t = *first;
164                 if (id_type(idmin) >= t.id() && id_type(idmin) <= t.id())
165                 {
166                     spirit::traits::assign_to(t.id(), attr);
167                     ++first;
168                     return true;
169                 }
170             }
171             return false;
172         }
173 
174         template <typename Context>
whatboost::spirit::qi::plain_tokenid_range175         info what(Context& /*context*/) const
176         {
177             return info("tokenid_range"
178               , "token(" +
179                     boost::lexical_cast<utf8_string>(idmin) + ", " +
180                     boost::lexical_cast<utf8_string>(idmax) + ")"
181             );
182         }
183 
184         TokenId idmin, idmax;
185     };
186 
187     ///////////////////////////////////////////////////////////////////////////
188     // Parser generators: make_xxx function (objects)
189     ///////////////////////////////////////////////////////////////////////////
190     template <typename Modifiers>
191     struct make_primitive<tag::tokenid, Modifiers>
192     {
193         typedef plain_tokenid<std::size_t> result_type;
194 
operator ()boost::spirit::qi::make_primitive195         result_type operator()(unused_type, unused_type) const
196         {
197             return result_type(std::size_t(~0));
198         }
199     };
200 
201     template <typename Modifiers, typename TokenId>
202     struct make_primitive<terminal_ex<tag::tokenid, fusion::vector1<TokenId> >
203       , Modifiers>
204     {
205         typedef plain_tokenid<TokenId> result_type;
206 
207         template <typename Terminal>
operator ()boost::spirit::qi::make_primitive208         result_type operator()(Terminal const& term, unused_type) const
209         {
210             return result_type(fusion::at_c<0>(term.args));
211         }
212     };
213 
214     template <typename Modifiers, typename TokenId>
215     struct make_primitive<terminal_ex<tag::tokenid, fusion::vector2<TokenId, TokenId> >
216       , Modifiers>
217     {
218         typedef plain_tokenid_range<TokenId> result_type;
219 
220         template <typename Terminal>
operator ()boost::spirit::qi::make_primitive221         result_type operator()(Terminal const& term, unused_type) const
222         {
223             return result_type(fusion::at_c<0>(term.args)
224               , fusion::at_c<1>(term.args));
225         }
226     };
227 }}}
228 
229 namespace boost { namespace spirit { namespace traits
230 {
231     ///////////////////////////////////////////////////////////////////////////
232     template<typename Idtype, typename Attr, typename Context, typename Iterator>
233     struct handles_container<qi::plain_tokenid<Idtype>, Attr, Context, Iterator>
234       : mpl::true_
235     {};
236 
237     template<typename Idtype, typename Attr, typename Context, typename Iterator>
238     struct handles_container<qi::plain_tokenid_range<Idtype>, Attr, Context, Iterator>
239       : mpl::true_
240     {};
241 }}}
242 
243 #endif
244