1 // Copyright (c) 2001-2011 Hartmut Kaiser
2 // Copyright (c) 2010 Bryce Lelbach
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)
7 #if !defined(BOOST_SPIRIT_KARMA_LIT_FEB_22_2007_0534PM)
8 #define BOOST_SPIRIT_KARMA_LIT_FEB_22_2007_0534PM
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>
40 ///////////////////////////////////////////////////////////////////////////////
41 namespace boost { namespace spirit
43 ///////////////////////////////////////////////////////////////////////////
45 ///////////////////////////////////////////////////////////////////////////
46 template <typename CharEncoding>
47 struct use_terminal<karma::domain
48 , tag::char_code<tag::string, CharEncoding> > // enables string
52 struct use_terminal<karma::domain, T
53 , typename enable_if<traits::is_string<T> >::type> // enables string literals
56 template <typename CharEncoding, typename A0>
57 struct use_terminal<karma::domain
59 tag::char_code<tag::string, CharEncoding> // enables string(str)
60 , fusion::vector1<A0> >
61 > : traits::is_string<A0> {};
63 template <typename CharEncoding> // enables string(f)
64 struct use_lazy_terminal<
66 , tag::char_code<tag::string, CharEncoding>
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>
78 ///////////////////////////////////////////////////////////////////////////////
79 namespace boost { namespace spirit { namespace karma
81 #ifndef BOOST_SPIRIT_NO_PREDEFINED_TERMINALS
84 using spirit::lit_type;
86 ///////////////////////////////////////////////////////////////////////////
87 // generate literal strings from a given parameter
88 ///////////////////////////////////////////////////////////////////////////
89 template <typename CharEncoding, typename Tag>
91 : primitive_generator<any_string<CharEncoding, Tag> >
93 typedef typename CharEncoding::char_type char_type;
94 typedef CharEncoding char_encoding;
96 template <typename Context, typename Unused = unused_type>
99 typedef std::basic_string<char_type> type;
102 // lit has an attached attribute
103 template <typename OutputIterator, typename Context, typename Delimiter
104 , typename Attribute>
106 generate(OutputIterator& sink, Context& context, Delimiter const& d,
107 Attribute const& attr)
109 if (!traits::has_optional_value(attr))
112 typedef typename attribute<Context>::type attribute_type;
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
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>
123 static bool generate(OutputIterator&, Context&, Delimiter const&,
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, ());
134 template <typename Context>
135 static info what(Context const& /*context*/)
137 return info("any-string");
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> >
148 typedef CharEncoding char_encoding;
150 remove_const<typename traits::char_type_of<String>::type>::type
152 typedef std::basic_string<char_type> string_type;
154 template <typename Context, typename Unused = unused_type>
156 : mpl::if_c<no_attribute, unused_type, string_type>
159 literal_string(typename add_reference<String>::type str)
163 // A string("...") which additionally has an associated attribute emits
164 // its immediate literal only if it matches the attribute, otherwise
167 typename OutputIterator, typename Context, typename Delimiter
168 , typename Attribute>
169 bool generate(OutputIterator& sink, Context& context
170 , Delimiter const& d, Attribute const& attr) const
172 if (!traits::has_optional_value(attr))
175 // fail if attribute isn't matched by immediate literal
176 typedef typename attribute<Context>::type attribute_type;
178 using spirit::traits::get_c_string;
179 if (!detail::string_compare(
181 traits::extract_from<attribute_type>(attr, context))
182 , get_c_string(str_), char_encoding(), Tag()))
186 return detail::string_generate(sink, str_, char_encoding(), Tag()) &&
187 karma::delimit_out(sink, d); // always do post-delimiting
190 // A string("...") without any associated attribute just emits its
192 template <typename OutputIterator, typename Context, typename Delimiter>
193 bool generate(OutputIterator& sink, Context&, Delimiter const& d
196 return detail::string_generate(sink, str_, char_encoding(), Tag()) &&
197 karma::delimit_out(sink, d); // always do post-delimiting
200 template <typename Context>
201 info what(Context const& /*context*/) const
203 return info("literal-string", str_);
209 ///////////////////////////////////////////////////////////////////////////
210 // Generator generators: make_xxx function (objects)
211 ///////////////////////////////////////////////////////////////////////////
214 template <typename CharEncoding, typename Modifiers>
215 struct make_primitive<
216 tag::char_code<tag::string, CharEncoding>
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;
225 typename spirit::detail::get_encoding_with_case<
226 Modifiers, CharEncoding, lower || upper>::type
227 , typename detail::get_casetag<Modifiers, lower || upper>::type
230 result_type operator()(unused_type, unused_type) const
232 return result_type();
237 template <typename T, typename Modifiers>
238 struct make_primitive<T, Modifiers
239 , typename enable_if<traits::is_string<T> >::type>
241 static bool const lower =
242 has_modifier<Modifiers, tag::char_code_base<tag::lower> >::value;
244 static bool const upper =
245 has_modifier<Modifiers, tag::char_code_base<tag::upper> >::value;
247 typedef typename add_const<T>::type const_string;
248 typedef literal_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
256 result_type operator()(
257 typename add_reference<const_string>::type str, unused_type) const
259 return result_type(str);
263 ///////////////////////////////////////////////////////////////////////////
266 template <typename CharEncoding, typename Modifiers, typename A0
268 struct make_string_direct
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;
275 typedef typename add_const<A0>::type const_string;
276 typedef literal_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
284 template <typename Terminal>
285 result_type operator()(Terminal const& term, unused_type) const
287 return result_type(fusion::at_c<0>(term.args));
292 // string("..."), lit("...")
293 template <typename CharEncoding, typename Modifiers, typename A0>
294 struct make_primitive<
296 tag::char_code<tag::string, CharEncoding>
297 , fusion::vector1<A0> >
299 : detail::make_string_direct<CharEncoding, Modifiers, A0, false>
302 template <typename Modifiers, typename A0>
303 struct make_primitive<
304 terminal_ex<tag::lit, fusion::vector1<A0> >
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>
312 }}} // namespace boost::spirit::karma
314 namespace boost { namespace spirit { namespace traits
316 ///////////////////////////////////////////////////////////////////////////
317 template <typename CharEncoding, typename Tag, typename Attribute
318 , typename Context, typename Iterator>
319 struct handles_container<karma::any_string<CharEncoding, Tag>, Attribute
323 template <typename String, typename CharEncoding, typename Tag
324 , bool no_attribute, typename Attribute, typename Context
326 struct handles_container<karma::literal_string<String, CharEncoding, Tag
327 , no_attribute>, Attribute, Context, Iterator>