1 //  Copyright (c) 2001-2011 Hartmut Kaiser
2 //  Copyright (c)      2010 Bryce Lelbach
3 //
4 //  Distributed under the Boost Software License, Version 1.0. (See accompanying
5 //  file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6 
7 #if !defined(BOOST_SPIRIT_KARMA_LIT_FEB_22_2007_0534PM)
8 #define BOOST_SPIRIT_KARMA_LIT_FEB_22_2007_0534PM
9 
10 #if defined(_MSC_VER)
11 #pragma once
12 #endif
13 
14 #include <boost/spirit/home/support/common_terminals.hpp>
15 #include <boost/spirit/home/support/string_traits.hpp>
16 #include <boost/spirit/home/support/info.hpp>
17 #include <boost/spirit/home/support/char_class.hpp>
18 #include <boost/spirit/home/support/container.hpp>
19 #include <boost/spirit/home/support/handles_container.hpp>
20 #include <boost/spirit/home/support/detail/get_encoding.hpp>
21 #include <boost/spirit/home/karma/domain.hpp>
22 #include <boost/spirit/home/karma/meta_compiler.hpp>
23 #include <boost/spirit/home/karma/delimit_out.hpp>
24 #include <boost/spirit/home/karma/auxiliary/lazy.hpp>
25 #include <boost/spirit/home/karma/detail/get_casetag.hpp>
26 #include <boost/spirit/home/karma/detail/extract_from.hpp>
27 #include <boost/spirit/home/karma/detail/string_generate.hpp>
28 #include <boost/spirit/home/karma/detail/string_compare.hpp>
29 #include <boost/spirit/home/karma/detail/enable_lit.hpp>
30 #include <boost/fusion/include/at.hpp>
31 #include <boost/fusion/include/vector.hpp>
32 #include <boost/fusion/include/cons.hpp>
33 #include <boost/mpl/if.hpp>
34 #include <boost/mpl/or.hpp>
35 #include <boost/mpl/assert.hpp>
36 #include <boost/mpl/bool.hpp>
37 #include <boost/utility/enable_if.hpp>
38 #include <string>
39 
40 ///////////////////////////////////////////////////////////////////////////////
41 namespace boost { namespace spirit
42 {
43     ///////////////////////////////////////////////////////////////////////////
44     // Enablers
45     ///////////////////////////////////////////////////////////////////////////
46     template <typename CharEncoding>
47     struct use_terminal<karma::domain
48         , tag::char_code<tag::string, CharEncoding> >     // enables string
49       : mpl::true_ {};
50 
51     template <typename T>
52     struct use_terminal<karma::domain, T
53       , typename enable_if<traits::is_string<T> >::type>  // enables string literals
54       : mpl::true_ {};
55 
56     template <typename CharEncoding, typename A0>
57     struct use_terminal<karma::domain
58       , terminal_ex<
59             tag::char_code<tag::string, CharEncoding>     // enables string(str)
60           , fusion::vector1<A0> >
61     > : traits::is_string<A0> {};
62 
63     template <typename CharEncoding>                      // enables string(f)
64     struct use_lazy_terminal<
65         karma::domain
66       , tag::char_code<tag::string, CharEncoding>
67       , 1 /*arity*/
68     > : mpl::true_ {};
69 
70     // enables lit(str)
71     template <typename A0>
72     struct use_terminal<karma::domain
73           , terminal_ex<tag::lit, fusion::vector1<A0> >
74           , typename enable_if<traits::is_string<A0> >::type>
75       : mpl::true_ {};
76 }}
77 
78 ///////////////////////////////////////////////////////////////////////////////
79 namespace boost { namespace spirit { namespace karma
80 {
81 #ifndef BOOST_SPIRIT_NO_PREDEFINED_TERMINALS
82     using spirit::lit;
83 #endif
84     using spirit::lit_type;
85 
86     ///////////////////////////////////////////////////////////////////////////
87     // generate literal strings from a given parameter
88     ///////////////////////////////////////////////////////////////////////////
89     template <typename CharEncoding, typename Tag>
90     struct any_string
91       : primitive_generator<any_string<CharEncoding, Tag> >
92     {
93         typedef typename CharEncoding::char_type char_type;
94         typedef CharEncoding char_encoding;
95 
96         template <typename Context, typename Unused = unused_type>
97         struct attribute
98         {
99             typedef std::basic_string<char_type> type;
100         };
101 
102         // lit has an attached attribute
103         template <typename OutputIterator, typename Context, typename Delimiter
104           , typename Attribute>
105         static bool
generateboost::spirit::karma::any_string106         generate(OutputIterator& sink, Context& context, Delimiter const& d,
107             Attribute const& attr)
108         {
109             if (!traits::has_optional_value(attr))
110                 return false;
111 
112             typedef typename attribute<Context>::type attribute_type;
113             return
114                 karma::detail::string_generate(sink
115                   , traits::extract_from<attribute_type>(attr, context)
116                   , char_encoding(), Tag()) &&
117                 karma::delimit_out(sink, d);      // always do post-delimiting
118         }
119 
120         // this lit has no attribute attached, it needs to have been
121         // initialized from a direct literal
122         template <typename OutputIterator, typename Context, typename Delimiter>
generateboost::spirit::karma::any_string123         static bool generate(OutputIterator&, Context&, Delimiter const&,
124             unused_type const&)
125         {
126             // It is not possible (doesn't make sense) to use string without
127             // providing any attribute, as the generator doesn't 'know' what
128             // character to output. The following assertion fires if this
129             // situation is detected in your code.
130             BOOST_SPIRIT_ASSERT_FAIL(OutputIterator, string_not_usable_without_attribute, ());
131             return false;
132         }
133 
134         template <typename Context>
whatboost::spirit::karma::any_string135         static info what(Context const& /*context*/)
136         {
137             return info("any-string");
138         }
139     };
140 
141     ///////////////////////////////////////////////////////////////////////////
142     // generate literal strings
143     ///////////////////////////////////////////////////////////////////////////
144     template <typename String, typename CharEncoding, typename Tag, bool no_attribute>
145     struct literal_string
146       : primitive_generator<literal_string<String, CharEncoding, Tag, no_attribute> >
147     {
148         typedef CharEncoding char_encoding;
149         typedef typename
150             remove_const<typename traits::char_type_of<String>::type>::type
151         char_type;
152         typedef std::basic_string<char_type> string_type;
153 
154         template <typename Context, typename Unused = unused_type>
155         struct attribute
156           : mpl::if_c<no_attribute, unused_type, string_type>
157         {};
158 
literal_stringboost::spirit::karma::literal_string159         literal_string(typename add_reference<String>::type str)
160           : str_(str)
161         {}
162 
163         // A string("...") which additionally has an associated attribute emits
164         // its immediate literal only if it matches the attribute, otherwise
165         // it fails.
166         template <
167             typename OutputIterator, typename Context, typename Delimiter
168           , typename Attribute>
generateboost::spirit::karma::literal_string169         bool generate(OutputIterator& sink, Context& context
170           , Delimiter const& d, Attribute const& attr) const
171         {
172             if (!traits::has_optional_value(attr))
173                 return false;
174 
175             // fail if attribute isn't matched by immediate literal
176             typedef typename attribute<Context>::type attribute_type;
177 
178             using spirit::traits::get_c_string;
179             if (!detail::string_compare(
180                     get_c_string(
181                         traits::extract_from<attribute_type>(attr, context))
182                   , get_c_string(str_), char_encoding(), Tag()))
183             {
184                 return false;
185             }
186             return detail::string_generate(sink, str_, char_encoding(), Tag()) &&
187                    karma::delimit_out(sink, d);      // always do post-delimiting
188         }
189 
190         // A string("...") without any associated attribute just emits its
191         // immediate literal
192         template <typename OutputIterator, typename Context, typename Delimiter>
generateboost::spirit::karma::literal_string193         bool generate(OutputIterator& sink, Context&, Delimiter const& d
194           , unused_type) const
195         {
196             return detail::string_generate(sink, str_, char_encoding(), Tag()) &&
197                    karma::delimit_out(sink, d);      // always do post-delimiting
198         }
199 
200         template <typename Context>
whatboost::spirit::karma::literal_string201         info what(Context const& /*context*/) const
202         {
203             return info("literal-string", str_);
204         }
205 
206         string_type str_;
207     };
208 
209     ///////////////////////////////////////////////////////////////////////////
210     // Generator generators: make_xxx function (objects)
211     ///////////////////////////////////////////////////////////////////////////
212 
213     // string
214     template <typename CharEncoding, typename Modifiers>
215     struct make_primitive<
216         tag::char_code<tag::string, CharEncoding>
217       , Modifiers>
218     {
219         static bool const lower =
220             has_modifier<Modifiers, tag::char_code_base<tag::lower> >::value;
221         static bool const upper =
222             has_modifier<Modifiers, tag::char_code_base<tag::upper> >::value;
223 
224         typedef any_string<
225             typename spirit::detail::get_encoding_with_case<
226                 Modifiers, CharEncoding, lower || upper>::type
227           , typename detail::get_casetag<Modifiers, lower || upper>::type
228         > result_type;
229 
operator ()boost::spirit::karma::make_primitive230         result_type operator()(unused_type, unused_type) const
231         {
232             return result_type();
233         }
234     };
235 
236     // string literal
237     template <typename T, typename Modifiers>
238     struct make_primitive<T, Modifiers
239       , typename enable_if<traits::is_string<T> >::type>
240     {
241         static bool const lower =
242             has_modifier<Modifiers, tag::char_code_base<tag::lower> >::value;
243 
244         static bool const upper =
245             has_modifier<Modifiers, tag::char_code_base<tag::upper> >::value;
246 
247         typedef typename add_const<T>::type const_string;
248         typedef literal_string<
249             const_string
250           , typename spirit::detail::get_encoding_with_case<
251                 Modifiers, unused_type, lower || upper>::type
252           , typename detail::get_casetag<Modifiers, lower || upper>::type
253           , true
254         > result_type;
255 
operator ()boost::spirit::karma::make_primitive256         result_type operator()(
257             typename add_reference<const_string>::type str, unused_type) const
258         {
259             return result_type(str);
260         }
261     };
262 
263     ///////////////////////////////////////////////////////////////////////////
264     namespace detail
265     {
266         template <typename CharEncoding, typename Modifiers, typename A0
267           , bool no_attribute>
268         struct make_string_direct
269         {
270             static bool const lower =
271                 has_modifier<Modifiers, tag::char_code_base<tag::lower> >::value;
272             static bool const upper =
273                 has_modifier<Modifiers, tag::char_code_base<tag::upper> >::value;
274 
275             typedef typename add_const<A0>::type const_string;
276             typedef literal_string<
277                 const_string
278               , typename spirit::detail::get_encoding_with_case<
279                     Modifiers, unused_type, lower || upper>::type
280               , typename detail::get_casetag<Modifiers, lower || upper>::type
281               , no_attribute
282             > result_type;
283 
284             template <typename Terminal>
operator ()boost::spirit::karma::detail::make_string_direct285             result_type operator()(Terminal const& term, unused_type) const
286             {
287                 return result_type(fusion::at_c<0>(term.args));
288             }
289         };
290     }
291 
292     // string("..."), lit("...")
293     template <typename CharEncoding, typename Modifiers, typename A0>
294     struct make_primitive<
295             terminal_ex<
296                 tag::char_code<tag::string, CharEncoding>
297               , fusion::vector1<A0> >
298           , Modifiers>
299       : detail::make_string_direct<CharEncoding, Modifiers, A0, false>
300     {};
301 
302     template <typename Modifiers, typename A0>
303     struct make_primitive<
304             terminal_ex<tag::lit, fusion::vector1<A0> >
305           , Modifiers
306           , typename enable_if<traits::is_string<A0> >::type>
307       : detail::make_string_direct<
308             typename traits::char_encoding_from_char<
309                 typename traits::char_type_of<A0>::type>::type
310           , Modifiers, A0, true>
311     {};
312 }}}   // namespace boost::spirit::karma
313 
314 namespace boost { namespace spirit { namespace traits
315 {
316     ///////////////////////////////////////////////////////////////////////////
317     template <typename CharEncoding, typename Tag, typename Attribute
318             , typename Context, typename Iterator>
319     struct handles_container<karma::any_string<CharEncoding, Tag>, Attribute
320       , Context, Iterator>
321       : mpl::false_ {};
322 
323     template <typename String, typename CharEncoding, typename Tag
324             , bool no_attribute, typename Attribute, typename Context
325             , typename Iterator>
326     struct handles_container<karma::literal_string<String, CharEncoding, Tag
327       , no_attribute>, Attribute, Context, Iterator>
328       : mpl::false_ {};
329 }}}
330 
331 #endif
332