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_CHAR_FEB_21_2007_0543PM)
8 #define BOOST_SPIRIT_KARMA_CHAR_FEB_21_2007_0543PM
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/detail/get_encoding.hpp>
19 #include <boost/spirit/home/support/char_set/basic_chset.hpp>
20 #include <boost/spirit/home/karma/domain.hpp>
21 #include <boost/spirit/home/karma/meta_compiler.hpp>
22 #include <boost/spirit/home/karma/delimit_out.hpp>
23 #include <boost/spirit/home/karma/char/char_generator.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/generate_to.hpp>
27 #include <boost/spirit/home/karma/detail/enable_lit.hpp>
28 #include <boost/fusion/include/at.hpp>
29 #include <boost/fusion/include/vector.hpp>
30 #include <boost/fusion/include/cons.hpp>
31 #include <boost/mpl/if.hpp>
32 #include <boost/mpl/assert.hpp>
33 #include <boost/mpl/bool.hpp>
34 #include <boost/utility/enable_if.hpp>
37 ///////////////////////////////////////////////////////////////////////////////
38 namespace boost { namespace spirit
40 ///////////////////////////////////////////////////////////////////////////
42 ///////////////////////////////////////////////////////////////////////////
43 template <typename CharEncoding>
44 struct use_terminal<karma::domain
45 , tag::char_code<tag::char_, CharEncoding> // enables char_
48 template <typename CharEncoding, typename A0>
49 struct use_terminal<karma::domain
51 tag::char_code<tag::char_, CharEncoding> // enables char_('x'), char_("x")
56 template <typename A0>
57 struct use_terminal<karma::domain
58 , terminal_ex<tag::lit, fusion::vector1<A0> > // enables lit('x')
59 , typename enable_if<traits::is_char<A0> >::type>
62 template <typename CharEncoding, typename A0, typename A1>
63 struct use_terminal<karma::domain
65 tag::char_code<tag::char_, CharEncoding> // enables char_('a','z')
66 , fusion::vector2<A0, A1>
70 template <typename CharEncoding> // enables *lazy* char_('x'), char_("x")
71 struct use_lazy_terminal<
73 , tag::char_code<tag::char_, CharEncoding>
78 struct use_terminal<karma::domain, char> // enables 'x'
82 struct use_terminal<karma::domain, char[2]> // enables "x"
86 struct use_terminal<karma::domain, wchar_t> // enables L'x'
90 struct use_terminal<karma::domain, wchar_t[2]> // enables L"x"
94 ///////////////////////////////////////////////////////////////////////////////
95 namespace boost { namespace spirit { namespace karma
97 #ifndef BOOST_SPIRIT_NO_PREDEFINED_TERMINALS
98 using spirit::lit; // lit('x') is equivalent to 'x'
100 using spirit::lit_type;
102 ///////////////////////////////////////////////////////////////////////////
105 // generates a single character from the associated attribute
107 // Note: this generator has to have an associated attribute
109 ///////////////////////////////////////////////////////////////////////////
110 template <typename CharEncoding, typename Tag>
112 : char_generator<any_char<CharEncoding, Tag>, CharEncoding, Tag>
114 typedef typename CharEncoding::char_type char_type;
115 typedef CharEncoding char_encoding;
117 template <typename Context, typename Unused>
120 typedef char_type type;
123 // any_char has an attached parameter
124 template <typename Attribute, typename CharParam, typename Context>
125 bool test(Attribute const& attr, CharParam& ch, Context&) const
127 ch = CharParam(attr);
131 // any_char has no attribute attached, it needs to have been
132 // initialized from a direct literal
133 template <typename CharParam, typename Context>
134 bool test(unused_type, CharParam&, Context&) const
136 // It is not possible (doesn't make sense) to use char_ without
137 // providing any attribute, as the generator doesn't 'know' what
138 // character to output. The following assertion fires if this
139 // situation is detected in your code.
140 BOOST_SPIRIT_ASSERT_FAIL(CharParam, char_not_usable_without_attribute, ());
144 template <typename Context>
145 static info what(Context const& /*context*/)
147 return info("any-char");
151 ///////////////////////////////////////////////////////////////////////////
154 // generates a single character given by a literal it was initialized
157 ///////////////////////////////////////////////////////////////////////////
158 template <typename CharEncoding, typename Tag, bool no_attribute>
160 : char_generator<literal_char<CharEncoding, Tag, no_attribute>
163 typedef typename CharEncoding::char_type char_type;
164 typedef CharEncoding char_encoding;
166 literal_char(char_type ch)
167 : ch (spirit::char_class::convert<char_encoding>::to(Tag(), ch))
170 template <typename Context, typename Unused>
172 : mpl::if_c<no_attribute, unused_type, char_type>
175 // A char_('x') which additionally has an associated attribute emits
176 // its immediate literal only if it matches the attribute, otherwise
178 // any_char has an attached parameter
179 template <typename Attribute, typename CharParam, typename Context>
180 bool test(Attribute const& attr, CharParam& ch_, Context&) const
182 // fail if attribute isn't matched my immediate literal
187 // A char_('x') without any associated attribute just emits its
189 template <typename CharParam, typename Context>
190 bool test(unused_type, CharParam& ch_, Context&) const
196 template <typename Context>
197 info what(Context const& /*context*/) const
199 return info("literal-char", char_encoding::toucs4(ch));
205 ///////////////////////////////////////////////////////////////////////////
206 // char range generator
207 template <typename CharEncoding, typename Tag>
209 : char_generator<char_range<CharEncoding, Tag>, CharEncoding, Tag>
211 typedef typename CharEncoding::char_type char_type;
212 typedef CharEncoding char_encoding;
214 char_range(char_type from, char_type to)
215 : from(spirit::char_class::convert<char_encoding>::to(Tag(), from))
216 , to(spirit::char_class::convert<char_encoding>::to(Tag(), to))
219 // A char_('a', 'z') which has an associated attribute emits it only if
220 // it matches the character range, otherwise it fails.
221 template <typename Attribute, typename CharParam, typename Context>
222 bool test(Attribute const& attr, CharParam& ch, Context&) const
224 // fail if attribute doesn't belong to character range
226 return (from <= char_type(attr)) && (char_type(attr) <= to);
229 // A char_('a', 'z') without any associated attribute fails compiling
230 template <typename CharParam, typename Context>
231 bool test(unused_type, CharParam&, Context&) const
233 // It is not possible (doesn't make sense) to use char_ generators
234 // without providing any attribute, as the generator doesn't 'know'
235 // what to output. The following assertion fires if this situation
236 // is detected in your code.
237 BOOST_SPIRIT_ASSERT_FAIL(CharParam
238 , char_range_not_usable_without_attribute, ());
242 template <typename Context>
243 info what(Context& /*context*/) const
245 info result("char-range", char_encoding::toucs4(from));
246 boost::get<std::string>(result.value) += '-';
247 boost::get<std::string>(result.value) += to_utf8(char_encoding::toucs4(to));
254 ///////////////////////////////////////////////////////////////////////////
255 // character set generator
256 template <typename CharEncoding, typename Tag, bool no_attribute>
258 : char_generator<char_set<CharEncoding, Tag, no_attribute>
261 typedef typename CharEncoding::char_type char_type;
262 typedef CharEncoding char_encoding;
264 template <typename Context, typename Unused>
266 : mpl::if_c<no_attribute, unused_type, char_type>
269 template <typename String>
270 char_set(String const& str)
272 typedef typename traits::char_type_of<String>::type in_type;
274 BOOST_SPIRIT_ASSERT_MSG((
275 (sizeof(char_type) == sizeof(in_type))
276 ), cannot_convert_string, (String));
278 typedef spirit::char_class::convert<char_encoding> convert_type;
280 char_type const* definition =
281 (char_type const*)traits::get_c_string(str);
282 char_type ch = convert_type::to(Tag(), *definition++);
285 char_type next = convert_type::to(Tag(), *definition++);
288 next = convert_type::to(Tag(), *definition++);
305 // A char_("a-z") which has an associated attribute emits it only if
306 // it matches the character set, otherwise it fails.
307 template <typename Attribute, typename CharParam, typename Context>
308 bool test(Attribute const& attr, CharParam& ch, Context&) const
310 // fail if attribute doesn't belong to character set
312 return chset.test(char_type(attr));
315 // A char_("a-z") without any associated attribute fails compiling
316 template <typename CharParam, typename Context>
317 bool test(unused_type, CharParam&, Context&) const
319 // It is not possible (doesn't make sense) to use char_ generators
320 // without providing any attribute, as the generator doesn't 'know'
321 // what to output. The following assertion fires if this situation
322 // is detected in your code.
323 BOOST_SPIRIT_ASSERT_FAIL(CharParam
324 , char_set_not_usable_without_attribute, ());
328 template <typename Context>
329 info what(Context& /*context*/) const
331 return info("char-set");
334 support::detail::basic_chset<char_type> chset;
337 ///////////////////////////////////////////////////////////////////////////
338 // Generator generators: make_xxx function (objects)
339 ///////////////////////////////////////////////////////////////////////////
342 template <typename Modifiers, typename Encoding>
345 static bool const lower =
346 has_modifier<Modifiers, tag::char_code_base<tag::lower> >::value;
347 static bool const upper =
348 has_modifier<Modifiers, tag::char_code_base<tag::upper> >::value;
350 typedef literal_char<
351 typename spirit::detail::get_encoding_with_case<
352 Modifiers, Encoding, lower || upper>::type
353 , typename get_casetag<Modifiers, lower || upper>::type
357 template <typename Char>
358 result_type operator()(Char ch, unused_type) const
360 return result_type(ch);
363 template <typename Char>
364 result_type operator()(Char const* str, unused_type) const
366 return result_type(str[0]);
371 // literals: 'x', "x"
372 template <typename Modifiers>
373 struct make_primitive<char, Modifiers>
374 : detail::basic_literal<Modifiers, char_encoding::standard> {};
376 template <typename Modifiers>
377 struct make_primitive<char const(&)[2], Modifiers>
378 : detail::basic_literal<Modifiers, char_encoding::standard> {};
380 // literals: L'x', L"x"
381 template <typename Modifiers>
382 struct make_primitive<wchar_t, Modifiers>
383 : detail::basic_literal<Modifiers, char_encoding::standard_wide> {};
385 template <typename Modifiers>
386 struct make_primitive<wchar_t const(&)[2], Modifiers>
387 : detail::basic_literal<Modifiers, char_encoding::standard_wide> {};
390 template <typename CharEncoding, typename Modifiers>
391 struct make_primitive<tag::char_code<tag::char_, CharEncoding>, Modifiers>
393 static bool const lower =
394 has_modifier<Modifiers, tag::char_code_base<tag::lower> >::value;
395 static bool const upper =
396 has_modifier<Modifiers, tag::char_code_base<tag::upper> >::value;
399 typename spirit::detail::get_encoding_with_case<
400 Modifiers, CharEncoding, lower || upper>::type
401 , typename detail::get_casetag<Modifiers, lower || upper>::type
404 result_type operator()(unused_type, unused_type) const
406 return result_type();
410 ///////////////////////////////////////////////////////////////////////////
413 template <typename CharEncoding, typename Modifiers, typename A0
415 struct make_char_direct
417 static bool const lower =
418 has_modifier<Modifiers, tag::char_code_base<tag::lower> >::value;
419 static bool const upper =
420 has_modifier<Modifiers, tag::char_code_base<tag::upper> >::value;
422 typedef typename spirit::detail::get_encoding_with_case<
423 Modifiers, CharEncoding, lower || upper>::type encoding;
424 typedef typename detail::get_casetag<
425 Modifiers, lower || upper>::type tag;
427 typedef typename mpl::if_<
428 traits::is_string<A0>
429 , char_set<encoding, tag, no_attribute>
430 , literal_char<encoding, tag, no_attribute>
433 template <typename Terminal>
434 result_type operator()(Terminal const& term, unused_type) const
436 return result_type(fusion::at_c<0>(term.args));
441 // char_(...), lit(...)
442 template <typename CharEncoding, typename Modifiers, typename A0>
443 struct make_primitive<
445 tag::char_code<tag::char_, CharEncoding>
446 , fusion::vector1<A0> >
448 : detail::make_char_direct<CharEncoding, Modifiers, A0, false>
451 template <typename Modifiers, typename A0>
452 struct make_primitive<
453 terminal_ex<tag::lit, fusion::vector1<A0> >
455 , typename enable_if<traits::is_char<A0> >::type>
456 : detail::make_char_direct<
457 typename traits::char_encoding_from_char<
458 typename traits::char_type_of<A0>::type>::type
459 , Modifiers, A0, true>
462 ///////////////////////////////////////////////////////////////////////////
464 template <typename CharEncoding, typename Modifiers, typename Char>
465 struct make_primitive<
467 tag::char_code<tag::char_, CharEncoding>
468 , fusion::vector1<Char(&)[2]> > // For single char strings
471 static bool const lower =
472 has_modifier<Modifiers, tag::char_code_base<tag::lower> >::value;
473 static bool const upper =
474 has_modifier<Modifiers, tag::char_code_base<tag::upper> >::value;
476 typedef literal_char<
477 typename spirit::detail::get_encoding_with_case<
478 Modifiers, CharEncoding, lower || upper>::type
479 , typename detail::get_casetag<Modifiers, lower || upper>::type
483 template <typename Terminal>
484 result_type operator()(Terminal const& term, unused_type) const
486 return result_type(fusion::at_c<0>(term.args)[0]);
490 ///////////////////////////////////////////////////////////////////////////
492 template <typename CharEncoding, typename Modifiers, typename A0, typename A1>
493 struct make_primitive<
495 tag::char_code<tag::char_, CharEncoding>
496 , fusion::vector2<A0, A1>
500 static bool const lower =
501 has_modifier<Modifiers, tag::char_code_base<tag::lower> >::value;
502 static bool const upper =
503 has_modifier<Modifiers, tag::char_code_base<tag::upper> >::value;
506 typename spirit::detail::get_encoding_with_case<
507 Modifiers, CharEncoding, lower || upper>::type
508 , typename detail::get_casetag<Modifiers, lower || upper>::type
511 template <typename Terminal>
512 result_type operator()(Terminal const& term, unused_type) const
514 return result_type(fusion::at_c<0>(term.args)
515 , fusion::at_c<1>(term.args));
519 template <typename CharEncoding, typename Modifiers, typename Char>
520 struct make_primitive<
522 tag::char_code<tag::char_, CharEncoding>
523 , fusion::vector2<Char(&)[2], Char(&)[2]> // For single char strings
527 static bool const lower =
528 has_modifier<Modifiers, tag::char_code_base<tag::lower> >::value;
529 static bool const upper =
530 has_modifier<Modifiers, tag::char_code_base<tag::upper> >::value;
533 typename spirit::detail::get_encoding_with_case<
534 Modifiers, CharEncoding, lower || upper>::type
535 , typename detail::get_casetag<Modifiers, lower || upper>::type
538 template <typename Terminal>
539 result_type operator()(Terminal const& term, unused_type) const
541 return result_type(fusion::at_c<0>(term.args)[0]
542 , fusion::at_c<1>(term.args)[0]);
545 }}} // namespace boost::spirit::karma