1 /*=============================================================================
2     Copyright (c) 2001-2011 Joel de Guzman
3     Copyright (c) 2001-2011 Hartmut Kaiser
4     Copyright (c)      2010 Bryce Lelbach
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(BOOST_SPIRIT_LIT_APR_18_2006_1125PM)
10 #define BOOST_SPIRIT_LIT_APR_18_2006_1125PM
11 
12 #if defined(_MSC_VER)
13 #pragma once
14 #endif
15 
16 #include <boost/spirit/home/qi/domain.hpp>
17 #include <boost/spirit/home/qi/skip_over.hpp>
18 #include <boost/spirit/home/qi/detail/string_parse.hpp>
19 #include <boost/spirit/home/qi/parser.hpp>
20 #include <boost/spirit/home/qi/meta_compiler.hpp>
21 #include <boost/spirit/home/qi/auxiliary/lazy.hpp>
22 #include <boost/spirit/home/qi/detail/enable_lit.hpp>
23 #include <boost/spirit/home/support/info.hpp>
24 #include <boost/spirit/home/support/char_class.hpp>
25 #include <boost/spirit/home/support/modify.hpp>
26 #include <boost/spirit/home/support/unused.hpp>
27 #include <boost/spirit/home/support/common_terminals.hpp>
28 #include <boost/spirit/home/support/string_traits.hpp>
29 #include <boost/spirit/home/support/detail/get_encoding.hpp>
30 #include <boost/spirit/home/support/handles_container.hpp>
31 #include <boost/fusion/include/at.hpp>
32 #include <boost/fusion/include/value_at.hpp>
33 #include <boost/type_traits/add_reference.hpp>
34 #include <boost/type_traits/add_const.hpp>
35 #include <boost/mpl/assert.hpp>
36 #include <boost/mpl/if.hpp>
37 #include <boost/detail/workaround.hpp>
38 #include <boost/utility/enable_if.hpp>
39 #include <string>
40 
41 namespace boost { namespace spirit
42 {
43     ///////////////////////////////////////////////////////////////////////////
44     // Enablers
45     ///////////////////////////////////////////////////////////////////////////
46     template <typename T>
47     struct use_terminal<qi::domain, T
48       , typename enable_if<traits::is_string<T> >::type> // enables strings
49       : mpl::true_ {};
50 
51     template <typename CharEncoding, typename A0>
52     struct use_terminal<qi::domain
53       , terminal_ex<
54             tag::char_code<tag::string, CharEncoding>   // enables string(str)
55           , fusion::vector1<A0> >
56     > : traits::is_string<A0> {};
57 
58     template <typename CharEncoding>                    // enables string(f)
59     struct use_lazy_terminal<
60         qi::domain
61       , tag::char_code<tag::string, CharEncoding>
62       , 1 /*arity*/
63     > : mpl::true_ {};
64 
65     // enables lit(...)
66     template <typename A0>
67     struct use_terminal<qi::domain
68           , terminal_ex<tag::lit, fusion::vector1<A0> >
69           , typename enable_if<traits::is_string<A0> >::type>
70       : mpl::true_ {};
71 }}
72 
73 namespace boost { namespace spirit { namespace qi
74 {
75 #ifndef BOOST_SPIRIT_NO_PREDEFINED_TERMINALS
76     using spirit::lit;
77 #endif
78     using spirit::lit_type;
79 
80     ///////////////////////////////////////////////////////////////////////////
81     // Parse for literal strings
82     ///////////////////////////////////////////////////////////////////////////
83     template <typename String, bool no_attribute>
84     struct literal_string
85       : primitive_parser<literal_string<String, no_attribute> >
86     {
87         typedef typename
88             remove_const<typename traits::char_type_of<String>::type>::type
89         char_type;
90         typedef std::basic_string<char_type> string_type;
91 
literal_stringboost::spirit::qi::literal_string92         literal_string(typename add_reference<String>::type str_)
93           : str(str_)
94         {}
95 
96         template <typename Context, typename Iterator>
97         struct attribute
98         {
99             typedef typename mpl::if_c<
100                 no_attribute, unused_type, string_type>::type
101             type;
102         };
103 
104         template <typename Iterator, typename Context
105           , typename Skipper, typename Attribute>
parseboost::spirit::qi::literal_string106         bool parse(Iterator& first, Iterator const& last
107           , Context& /*context*/, Skipper const& skipper, Attribute& attr_) const
108         {
109             qi::skip_over(first, last, skipper);
110             return detail::string_parse(str, first, last, attr_);
111         }
112 
113         template <typename Context>
whatboost::spirit::qi::literal_string114         info what(Context& /*context*/) const
115         {
116             return info("literal-string", str);
117         }
118 
119         String str;
120 
121     private:
122         // silence MSVC warning C4512: assignment operator could not be generated
123         literal_string& operator= (literal_string const&);
124     };
125 
126     template <typename String, bool no_attribute>
127     struct no_case_literal_string
128       : primitive_parser<no_case_literal_string<String, no_attribute> >
129     {
130         typedef typename
131             remove_const<typename traits::char_type_of<String>::type>::type
132         char_type;
133         typedef std::basic_string<char_type> string_type;
134 
135         template <typename CharEncoding>
no_case_literal_stringboost::spirit::qi::no_case_literal_string136         no_case_literal_string(char_type const* in, CharEncoding encoding)
137           : str_lo(in)
138           , str_hi(in)
139         {
140 #if BOOST_WORKAROUND(BOOST_MSVC, BOOST_TESTED_AT(1600))
141             encoding; // suppresses warning: C4100: 'encoding' : unreferenced formal parameter
142 #endif
143             typename string_type::iterator loi = str_lo.begin();
144             typename string_type::iterator hii = str_hi.begin();
145 
146             for (; loi != str_lo.end(); ++loi, ++hii, ++in)
147             {
148                 typedef typename CharEncoding::char_type encoded_char_type;
149 
150                 *loi = static_cast<char_type>(encoding.tolower(encoded_char_type(*loi)));
151                 *hii = static_cast<char_type>(encoding.toupper(encoded_char_type(*hii)));
152             }
153         }
154 
155         template <typename Context, typename Iterator>
156         struct attribute
157         {
158             typedef typename mpl::if_c<
159                 no_attribute, unused_type, string_type>::type
160             type;
161         };
162 
163         template <typename Iterator, typename Context
164           , typename Skipper, typename Attribute>
parseboost::spirit::qi::no_case_literal_string165         bool parse(Iterator& first, Iterator const& last
166           , Context& /*context*/, Skipper const& skipper, Attribute& attr_) const
167         {
168             qi::skip_over(first, last, skipper);
169             return detail::string_parse(str_lo, str_hi, first, last, attr_);
170         }
171 
172         template <typename Context>
whatboost::spirit::qi::no_case_literal_string173         info what(Context& /*context*/) const
174         {
175             return info("no-case-literal-string", str_lo);
176         }
177 
178         string_type str_lo, str_hi;
179     };
180 
181     ///////////////////////////////////////////////////////////////////////////
182     // Parser generators: make_xxx function (objects)
183     ///////////////////////////////////////////////////////////////////////////
184     template <typename T, typename Modifiers>
185     struct make_primitive<T, Modifiers
186       , typename enable_if<traits::is_string<T> >::type>
187     {
188         typedef has_modifier<Modifiers, tag::char_code_base<tag::no_case> > no_case;
189 
190         typedef typename add_const<T>::type const_string;
191         typedef typename mpl::if_<
192             no_case
193           , no_case_literal_string<const_string, true>
194           , literal_string<const_string, true> >::type
195         result_type;
196 
operator ()boost::spirit::qi::make_primitive197         result_type operator()(
198             typename add_reference<const_string>::type str, unused_type) const
199         {
200             return op(str, no_case());
201         }
202 
203         template <typename String>
opboost::spirit::qi::make_primitive204         result_type op(String const& str, mpl::false_) const
205         {
206             return result_type(str);
207         }
208 
209         template <typename String>
opboost::spirit::qi::make_primitive210         result_type op(String const& str, mpl::true_) const
211         {
212             typename spirit::detail::get_encoding<Modifiers,
213                 spirit::char_encoding::standard>::type encoding;
214             return result_type(traits::get_c_string(str), encoding);
215         }
216     };
217 
218     // lit("...")
219     template <typename Modifiers, typename A0>
220     struct make_primitive<
221         terminal_ex<tag::lit, fusion::vector1<A0> >
222       , Modifiers
223       , typename enable_if<traits::is_string<A0> >::type>
224     {
225         typedef has_modifier<Modifiers, tag::char_code_base<tag::no_case> > no_case;
226 
227         typedef typename add_const<A0>::type const_string;
228         typedef typename mpl::if_<
229             no_case
230           , no_case_literal_string<const_string, true>
231           , literal_string<const_string, true> >::type
232         result_type;
233 
234         template <typename Terminal>
operator ()boost::spirit::qi::make_primitive235         result_type operator()(Terminal const& term, unused_type) const
236         {
237             return op(fusion::at_c<0>(term.args), no_case());
238         }
239 
240         template <typename String>
opboost::spirit::qi::make_primitive241         result_type op(String const& str, mpl::false_) const
242         {
243             return result_type(str);
244         }
245 
246         template <typename String>
opboost::spirit::qi::make_primitive247         result_type op(String const& str, mpl::true_) const
248         {
249             typedef typename traits::char_encoding_from_char<
250                 typename traits::char_type_of<A0>::type>::type encoding_type;
251             typename spirit::detail::get_encoding<Modifiers,
252                 encoding_type>::type encoding;
253             return result_type(traits::get_c_string(str), encoding);
254         }
255     };
256 
257     ///////////////////////////////////////////////////////////////////////////
258     // string("...")
259     template <typename CharEncoding, typename Modifiers, typename A0>
260     struct make_primitive<
261         terminal_ex<
262             tag::char_code<tag::string, CharEncoding>
263           , fusion::vector1<A0> >
264       , Modifiers>
265     {
266         typedef CharEncoding encoding;
267         typedef has_modifier<Modifiers, tag::char_code_base<tag::no_case> > no_case;
268 
269         typedef typename add_const<A0>::type const_string;
270         typedef typename mpl::if_<
271             no_case
272           , no_case_literal_string<const_string, false>
273           , literal_string<const_string, false> >::type
274         result_type;
275 
276         template <typename Terminal>
operator ()boost::spirit::qi::make_primitive277         result_type operator()(Terminal const& term, unused_type) const
278         {
279             return op(fusion::at_c<0>(term.args), no_case());
280         }
281 
282         template <typename String>
opboost::spirit::qi::make_primitive283         result_type op(String const& str, mpl::false_) const
284         {
285             return result_type(str);
286         }
287 
288         template <typename String>
opboost::spirit::qi::make_primitive289         result_type op(String const& str, mpl::true_) const
290         {
291             return result_type(traits::get_c_string(str), encoding());
292         }
293     };
294 }}}
295 
296 namespace boost { namespace spirit { namespace traits
297 {
298     ///////////////////////////////////////////////////////////////////////////
299     template <typename String, bool no_attribute, typename Attribute
300       ,typename Context, typename Iterator>
301     struct handles_container<qi::literal_string<String, no_attribute>
302       , Attribute, Context, Iterator>
303       : mpl::true_ {};
304 
305     template <typename String, bool no_attribute, typename Attribute
306       , typename Context, typename Iterator>
307     struct handles_container<qi::no_case_literal_string<String, no_attribute>
308       , Attribute, Context, Iterator>
309       : mpl::true_ {};
310 }}}
311 
312 #endif
313