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