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         // silence MSVC warning C4512: assignment operator could not be generated
122         BOOST_DELETED_FUNCTION(literal_string& operator= (literal_string const&))
123     };
124 
125     template <typename String, bool no_attribute>
126     struct no_case_literal_string
127       : primitive_parser<no_case_literal_string<String, no_attribute> >
128     {
129         typedef typename
130             remove_const<typename traits::char_type_of<String>::type>::type
131         char_type;
132         typedef std::basic_string<char_type> string_type;
133 
134         template <typename CharEncoding>
no_case_literal_stringboost::spirit::qi::no_case_literal_string135         no_case_literal_string(char_type const* in, CharEncoding encoding)
136           : str_lo(in)
137           , str_hi(in)
138         {
139 #if BOOST_WORKAROUND(BOOST_MSVC, BOOST_TESTED_AT(1600))
140             encoding; // suppresses warning: C4100: 'encoding' : unreferenced formal parameter
141 #endif
142             typename string_type::iterator loi = str_lo.begin();
143             typename string_type::iterator hii = str_hi.begin();
144 
145             for (; loi != str_lo.end(); ++loi, ++hii, ++in)
146             {
147                 typedef typename CharEncoding::char_type encoded_char_type;
148 
149                 *loi = static_cast<char_type>(encoding.tolower(encoded_char_type(*loi)));
150                 *hii = static_cast<char_type>(encoding.toupper(encoded_char_type(*hii)));
151             }
152         }
153 
154         template <typename Context, typename Iterator>
155         struct attribute
156         {
157             typedef typename mpl::if_c<
158                 no_attribute, unused_type, string_type>::type
159             type;
160         };
161 
162         template <typename Iterator, typename Context
163           , typename Skipper, typename Attribute>
parseboost::spirit::qi::no_case_literal_string164         bool parse(Iterator& first, Iterator const& last
165           , Context& /*context*/, Skipper const& skipper, Attribute& attr_) const
166         {
167             qi::skip_over(first, last, skipper);
168             return detail::string_parse(str_lo, str_hi, first, last, attr_);
169         }
170 
171         template <typename Context>
whatboost::spirit::qi::no_case_literal_string172         info what(Context& /*context*/) const
173         {
174             return info("no-case-literal-string", str_lo);
175         }
176 
177         string_type str_lo, str_hi;
178     };
179 
180     ///////////////////////////////////////////////////////////////////////////
181     // Parser generators: make_xxx function (objects)
182     ///////////////////////////////////////////////////////////////////////////
183     template <typename T, typename Modifiers>
184     struct make_primitive<T, Modifiers
185       , typename enable_if<traits::is_string<T> >::type>
186     {
187         typedef has_modifier<Modifiers, tag::char_code_base<tag::no_case> > no_case;
188 
189         typedef typename add_const<T>::type const_string;
190         typedef typename mpl::if_<
191             no_case
192           , no_case_literal_string<const_string, true>
193           , literal_string<const_string, true> >::type
194         result_type;
195 
operator ()boost::spirit::qi::make_primitive196         result_type operator()(
197             typename add_reference<const_string>::type str, unused_type) const
198         {
199             return op(str, no_case());
200         }
201 
202         template <typename String>
opboost::spirit::qi::make_primitive203         result_type op(String const& str, mpl::false_) const
204         {
205             return result_type(str);
206         }
207 
208         template <typename String>
opboost::spirit::qi::make_primitive209         result_type op(String const& str, mpl::true_) const
210         {
211             typename spirit::detail::get_encoding<Modifiers,
212                 spirit::char_encoding::standard>::type encoding;
213             return result_type(traits::get_c_string(str), encoding);
214         }
215     };
216 
217     // lit("...")
218     template <typename Modifiers, typename A0>
219     struct make_primitive<
220         terminal_ex<tag::lit, fusion::vector1<A0> >
221       , Modifiers
222       , typename enable_if<traits::is_string<A0> >::type>
223     {
224         typedef has_modifier<Modifiers, tag::char_code_base<tag::no_case> > no_case;
225 
226         typedef typename add_const<A0>::type const_string;
227         typedef typename mpl::if_<
228             no_case
229           , no_case_literal_string<const_string, true>
230           , literal_string<const_string, true> >::type
231         result_type;
232 
233         template <typename Terminal>
operator ()boost::spirit::qi::make_primitive234         result_type operator()(Terminal const& term, unused_type) const
235         {
236             return op(fusion::at_c<0>(term.args), no_case());
237         }
238 
239         template <typename String>
opboost::spirit::qi::make_primitive240         result_type op(String const& str, mpl::false_) const
241         {
242             return result_type(str);
243         }
244 
245         template <typename String>
opboost::spirit::qi::make_primitive246         result_type op(String const& str, mpl::true_) const
247         {
248             typedef typename traits::char_encoding_from_char<
249                 typename traits::char_type_of<A0>::type>::type encoding_type;
250             typename spirit::detail::get_encoding<Modifiers,
251                 encoding_type>::type encoding;
252             return result_type(traits::get_c_string(str), encoding);
253         }
254     };
255 
256     ///////////////////////////////////////////////////////////////////////////
257     // string("...")
258     template <typename CharEncoding, typename Modifiers, typename A0>
259     struct make_primitive<
260         terminal_ex<
261             tag::char_code<tag::string, CharEncoding>
262           , fusion::vector1<A0> >
263       , Modifiers>
264     {
265         typedef CharEncoding encoding;
266         typedef has_modifier<Modifiers, tag::char_code_base<tag::no_case> > no_case;
267 
268         typedef typename add_const<A0>::type const_string;
269         typedef typename mpl::if_<
270             no_case
271           , no_case_literal_string<const_string, false>
272           , literal_string<const_string, false> >::type
273         result_type;
274 
275         template <typename Terminal>
operator ()boost::spirit::qi::make_primitive276         result_type operator()(Terminal const& term, unused_type) const
277         {
278             return op(fusion::at_c<0>(term.args), no_case());
279         }
280 
281         template <typename String>
opboost::spirit::qi::make_primitive282         result_type op(String const& str, mpl::false_) const
283         {
284             return result_type(str);
285         }
286 
287         template <typename String>
opboost::spirit::qi::make_primitive288         result_type op(String const& str, mpl::true_) const
289         {
290             return result_type(traits::get_c_string(str), encoding());
291         }
292     };
293 }}}
294 
295 namespace boost { namespace spirit { namespace traits
296 {
297     ///////////////////////////////////////////////////////////////////////////
298     template <typename String, bool no_attribute, typename Attribute
299       ,typename Context, typename Iterator>
300     struct handles_container<qi::literal_string<String, no_attribute>
301       , Attribute, Context, Iterator>
302       : mpl::true_ {};
303 
304     template <typename String, bool no_attribute, typename Attribute
305       , typename Context, typename Iterator>
306     struct handles_container<qi::no_case_literal_string<String, no_attribute>
307       , Attribute, Context, Iterator>
308       : mpl::true_ {};
309 }}}
310 
311 #endif
312