1 /*=============================================================================
2 Copyright (c) 2001-2011 Joel de Guzman
3 Copyright (c) 2001-2011 Hartmut Kaiser
4 Copyright (c) 2010 Bryce Lelbach
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_CHAR_APRIL_16_2006_1051AM)
10 #define BOOST_SPIRIT_CHAR_APRIL_16_2006_1051AM
16 #include <boost/spirit/home/support/common_terminals.hpp>
17 #include <boost/spirit/home/support/string_traits.hpp>
18 #include <boost/spirit/home/support/info.hpp>
19 #include <boost/spirit/home/support/detail/get_encoding.hpp>
20 #include <boost/spirit/home/support/char_set/basic_chset.hpp>
21 #include <boost/spirit/home/qi/char/char_parser.hpp>
22 #include <boost/spirit/home/qi/char/char_class.hpp>
23 #include <boost/spirit/home/qi/meta_compiler.hpp>
24 #include <boost/spirit/home/qi/auxiliary/lazy.hpp>
25 #include <boost/spirit/home/qi/detail/enable_lit.hpp>
26 #include <boost/fusion/include/at.hpp>
27 #include <boost/mpl/if.hpp>
28 #include <boost/mpl/assert.hpp>
29 #include <boost/mpl/identity.hpp>
30 #include <boost/utility/enable_if.hpp>
31 #include <boost/type_traits/remove_const.hpp>
38 namespace boost { namespace spirit
40 ///////////////////////////////////////////////////////////////////////////
42 ///////////////////////////////////////////////////////////////////////////
43 template <typename CharEncoding>
44 struct use_terminal<qi::domain
46 tag::char_code<tag::char_, CharEncoding> // enables char_
50 template <typename CharEncoding, typename A0>
51 struct use_terminal<qi::domain
53 tag::char_code<tag::char_, CharEncoding> // enables char_('x'), char_("x")
54 , fusion::vector1<A0> // and char_("a-z0-9")
58 template <typename CharEncoding, typename A0, typename A1>
59 struct use_terminal<qi::domain
61 tag::char_code<tag::char_, CharEncoding> // enables char_('a','z')
62 , fusion::vector2<A0, A1>
66 template <typename CharEncoding> // enables *lazy* char_('x'), char_("x")
67 struct use_lazy_terminal< // and char_("a-z0-9")
69 , tag::char_code<tag::char_, CharEncoding>
73 template <typename CharEncoding> // enables *lazy* char_('a','z')
74 struct use_lazy_terminal<
76 , tag::char_code<tag::char_, CharEncoding>
81 struct use_terminal<qi::domain, char> // enables 'x'
85 struct use_terminal<qi::domain, char[2]> // enables "x"
89 struct use_terminal<qi::domain, wchar_t> // enables wchar_t
93 struct use_terminal<qi::domain, wchar_t[2]> // enables L"x"
97 template <typename A0>
98 struct use_terminal<qi::domain
99 , terminal_ex<tag::lit, fusion::vector1<A0> >
100 , typename enable_if<traits::is_char<A0> >::type>
104 namespace boost { namespace spirit { namespace qi
106 #ifndef BOOST_SPIRIT_NO_PREDEFINED_TERMINALS
107 using spirit::lit; // lit('x') is equivalent to 'x'
109 using spirit::lit_type;
111 ///////////////////////////////////////////////////////////////////////////
112 // Parser for a single character
113 ///////////////////////////////////////////////////////////////////////////
114 template <typename CharEncoding, bool no_attribute, bool no_case = false>
117 literal_char<CharEncoding, no_attribute, false>
118 , typename CharEncoding::char_type
119 , typename mpl::if_c<no_attribute, unused_type
120 , typename CharEncoding::char_type>::type>
122 typedef typename CharEncoding::char_type char_type;
123 typedef CharEncoding char_encoding;
125 template <typename Char>
126 literal_char(Char ch_)
127 : ch(static_cast<char_type>(ch_)) {}
129 template <typename Context, typename Iterator>
132 typedef typename mpl::if_c<
133 no_attribute, unused_type, char_type>::type
137 template <typename CharParam, typename Context>
138 bool test(CharParam ch_, Context&) const
140 return traits::ischar<CharParam, char_encoding>::call(ch_) &&
141 ch == char_type(ch_);
144 template <typename Context>
145 info what(Context& /*context*/) const
147 return info("literal-char", char_encoding::toucs4(ch));
153 template <typename CharEncoding, bool no_attribute>
154 struct literal_char<CharEncoding, no_attribute, true> // case insensitive
156 literal_char<CharEncoding, no_attribute, true>
157 , typename mpl::if_c<no_attribute, unused_type
158 , typename CharEncoding::char_type>::type>
160 typedef typename CharEncoding::char_type char_type;
161 typedef CharEncoding char_encoding;
163 literal_char(char_type ch)
164 : lo(static_cast<char_type>(char_encoding::tolower(ch)))
165 , hi(static_cast<char_type>(char_encoding::toupper(ch))) {}
167 template <typename Context, typename Iterator>
170 typedef typename mpl::if_c<
171 no_attribute, unused_type, char_type>::type
175 template <typename CharParam, typename Context>
176 bool test(CharParam ch_, Context&) const
178 if (!traits::ischar<CharParam, char_encoding>::call(ch_))
181 char_type ch = char_type(ch_); // optimize for token based parsing
182 return this->lo == ch || this->hi == ch;
185 template <typename Context>
186 info what(Context& /*context*/) const
188 return info("no-case-literal-char", char_encoding::toucs4(lo));
194 ///////////////////////////////////////////////////////////////////////////
195 // Parser for a character range
196 ///////////////////////////////////////////////////////////////////////////
197 template <typename CharEncoding, bool no_case = false>
199 : char_parser<char_range<CharEncoding, false>, typename CharEncoding::char_type>
201 typedef typename CharEncoding::char_type char_type;
202 typedef CharEncoding char_encoding;
204 char_range(char_type from_, char_type to_)
205 : from(from_), to(to_) {}
207 template <typename CharParam, typename Context>
208 bool test(CharParam ch_, Context&) const
210 if (!traits::ischar<CharParam, char_encoding>::call(ch_))
213 char_type ch = char_type(ch_); // optimize for token based parsing
214 return !(ch < from) && !(to < ch);
217 template <typename Context>
218 info what(Context& /*context*/) const
220 info result("char-range", char_encoding::toucs4(from));
221 boost::get<std::string>(result.value) += '-';
222 boost::get<std::string>(result.value) += to_utf8(char_encoding::toucs4(to));
229 template <typename CharEncoding>
230 struct char_range<CharEncoding, true> // case insensitive
231 : char_parser<char_range<CharEncoding, true>, typename CharEncoding::char_type>
233 typedef typename CharEncoding::char_type char_type;
234 typedef CharEncoding char_encoding;
236 char_range(char_type from, char_type to)
237 : from_lo(static_cast<char_type>(char_encoding::tolower(from)))
238 , to_lo(static_cast<char_type>(char_encoding::tolower(to)))
239 , from_hi(static_cast<char_type>(char_encoding::toupper(from)))
240 , to_hi(static_cast<char_type>(char_encoding::toupper(to)))
243 template <typename CharParam, typename Context>
244 bool test(CharParam ch_, Context&) const
246 if (!traits::ischar<CharParam, char_encoding>::call(ch_))
249 char_type ch = char_type(ch_); // optimize for token based parsing
250 return (!(ch < from_lo) && !(to_lo < ch))
251 || (!(ch < from_hi) && !(to_hi < ch))
255 template <typename Context>
256 info what(Context& /*context*/) const
258 info result("no-case-char-range", char_encoding::toucs4(from_lo));
259 boost::get<std::string>(result.value) += '-';
260 boost::get<std::string>(result.value) += to_utf8(char_encoding::toucs4(to_lo));
264 char_type from_lo, to_lo, from_hi, to_hi;
267 ///////////////////////////////////////////////////////////////////////////
268 // Parser for a character set
269 ///////////////////////////////////////////////////////////////////////////
270 template <typename CharEncoding, bool no_attribute, bool no_case = false>
272 : char_parser<char_set<CharEncoding, no_attribute, false>
273 , typename mpl::if_c<no_attribute, unused_type
274 , typename CharEncoding::char_type>::type>
276 typedef typename CharEncoding::char_type char_type;
277 typedef CharEncoding char_encoding;
279 template <typename String>
280 char_set(String const& str)
282 using spirit::detail::cast_char;
286 typename traits::char_type_of<String>::type
290 BOOST_SPIRIT_ASSERT_MSG((
291 (sizeof(char_type) >= sizeof(in_type))
292 ), cannot_convert_string, (String));
294 in_type const* definition =
295 (in_type const*)traits::get_c_string(str);
296 in_type ch = *definition++;
299 in_type next = *definition++;
302 next = *definition++;
305 chset.set(cast_char<char_type>(ch));
310 cast_char<char_type>(ch),
311 cast_char<char_type>(next)
316 chset.set(cast_char<char_type>(ch));
322 template <typename CharParam, typename Context>
323 bool test(CharParam ch, Context&) const
325 return traits::ischar<CharParam, char_encoding>::call(ch) &&
326 chset.test(char_type(ch));
329 template <typename Context>
330 info what(Context& /*context*/) const
332 return info("char-set");
335 support::detail::basic_chset<char_type> chset;
338 template <typename CharEncoding, bool no_attribute>
339 struct char_set<CharEncoding, no_attribute, true> // case insensitive
340 : char_parser<char_set<CharEncoding, no_attribute, true>
341 , typename mpl::if_c<no_attribute, unused_type
342 , typename CharEncoding::char_type>::type>
344 typedef typename CharEncoding::char_type char_type;
345 typedef CharEncoding char_encoding;
347 template <typename String>
348 char_set(String const& str)
350 typedef typename traits::char_type_of<String>::type in_type;
352 BOOST_SPIRIT_ASSERT_MSG((
353 (sizeof(char_type) == sizeof(in_type))
354 ), cannot_convert_string, (String));
356 char_type const* definition =
357 (char_type const*)traits::get_c_string(str);
358 char_type ch = *definition++;
361 char_type next = *definition++;
364 next = *definition++;
367 chset.set(static_cast<char_type>(CharEncoding::tolower(ch)));
368 chset.set(static_cast<char_type>(CharEncoding::toupper(ch)));
372 chset.set(static_cast<char_type>(CharEncoding::tolower(ch))
373 , static_cast<char_type>(CharEncoding::tolower(next)));
374 chset.set(static_cast<char_type>(CharEncoding::toupper(ch))
375 , static_cast<char_type>(CharEncoding::toupper(next)));
379 chset.set(static_cast<char_type>(CharEncoding::tolower(ch)));
380 chset.set(static_cast<char_type>(CharEncoding::toupper(ch)));
386 template <typename CharParam, typename Context>
387 bool test(CharParam ch, Context&) const
389 return traits::ischar<CharParam, char_encoding>::call(ch) &&
390 chset.test(char_type(ch));
393 template <typename Context>
394 info what(Context& /*context*/) const
396 return info("no-case-char-set");
399 support::detail::basic_chset<char_type> chset;
402 ///////////////////////////////////////////////////////////////////////////
403 // Parser generators: make_xxx function (objects)
404 ///////////////////////////////////////////////////////////////////////////
407 template <typename Modifiers, typename Encoding>
410 static bool const no_case =
413 , tag::char_code_base<tag::no_case>
416 static bool const no_attr =
422 typedef literal_char<
423 typename spirit::detail::get_encoding_with_case<
424 Modifiers, Encoding, no_case>::type
429 template <typename Char>
430 result_type operator()(Char ch, unused_type) const
432 return result_type(ch);
435 template <typename Char>
436 result_type operator()(Char const* str, unused_type) const
438 return result_type(str[0]);
443 template <typename Modifiers>
444 struct make_primitive<char, Modifiers>
445 : detail::basic_literal<Modifiers, char_encoding::standard> {};
447 template <typename Modifiers>
448 struct make_primitive<char const(&)[2], Modifiers>
449 : detail::basic_literal<Modifiers, char_encoding::standard> {};
451 template <typename Modifiers>
452 struct make_primitive<wchar_t, Modifiers>
453 : detail::basic_literal<Modifiers, char_encoding::standard_wide> {};
455 template <typename Modifiers>
456 struct make_primitive<wchar_t const(&)[2], Modifiers>
457 : detail::basic_literal<Modifiers, char_encoding::standard_wide> {};
459 template <typename CharEncoding, typename Modifiers>
460 struct make_primitive<
461 terminal<tag::char_code<tag::char_, CharEncoding> >, Modifiers>
464 spirit::detail::get_encoding<Modifiers, CharEncoding>::type
467 typedef tag::char_code<tag::char_, char_encoding> tag;
468 typedef char_class<tag> result_type;
469 result_type operator()(unused_type, unused_type) const
471 return result_type();
475 ///////////////////////////////////////////////////////////////////////////
477 template <typename CharEncoding, typename Modifiers, typename A0>
478 struct make_primitive<
480 tag::char_code<tag::char_, CharEncoding>
481 , fusion::vector1<A0> >
484 static bool const no_case =
485 has_modifier<Modifiers, tag::char_code_base<tag::no_case> >::value;
488 spirit::detail::get_encoding<Modifiers, CharEncoding>::type
493 traits::is_string<A0>
494 , char_set<char_encoding, false, no_case>
495 , literal_char<char_encoding, false, no_case>
499 template <typename Terminal>
500 result_type operator()(Terminal const& term, unused_type) const
502 return result_type(fusion::at_c<0>(term.args));
507 template <typename Modifiers, typename A0>
508 struct make_primitive<
509 terminal_ex<tag::lit, fusion::vector1<A0> >
511 , typename enable_if<traits::is_char<A0> >::type>
513 static bool const no_case =
516 , tag::char_code_base<tag::no_case>
519 typedef typename traits::char_encoding_from_char<
520 typename traits::char_type_of<A0>::type>::type encoding;
522 typedef literal_char<
523 typename spirit::detail::get_encoding_with_case<
524 Modifiers, encoding, no_case>::type
528 template <typename Terminal>
529 result_type operator()(Terminal const& term, unused_type) const
531 return result_type(fusion::at_c<0>(term.args));
535 ///////////////////////////////////////////////////////////////////////////
536 template <typename CharEncoding, typename Modifiers, typename Char>
537 struct make_primitive<
539 tag::char_code<tag::char_, CharEncoding>
540 , fusion::vector1<Char(&)[2]> // For single char strings
544 static bool const no_case =
545 has_modifier<Modifiers, tag::char_code_base<tag::no_case> >::value;
548 spirit::detail::get_encoding<Modifiers, CharEncoding>::type
551 typedef literal_char<char_encoding, false, no_case> result_type;
553 template <typename Terminal>
554 result_type operator()(Terminal const& term, unused_type) const
556 return result_type(fusion::at_c<0>(term.args)[0]);
560 template <typename CharEncoding, typename Modifiers, typename A0, typename A1>
561 struct make_primitive<
563 tag::char_code<tag::char_, CharEncoding>
564 , fusion::vector2<A0, A1>
568 static bool const no_case =
569 has_modifier<Modifiers, tag::char_code_base<tag::no_case> >::value;
572 spirit::detail::get_encoding<Modifiers, CharEncoding>::type
575 typedef char_range<char_encoding, no_case> result_type;
577 template <typename Terminal>
578 result_type operator()(Terminal const& term, unused_type) const
581 fusion::at_c<0>(term.args)
582 , fusion::at_c<1>(term.args)
587 template <typename CharEncoding, typename Modifiers, typename Char>
588 struct make_primitive<
590 tag::char_code<tag::char_, CharEncoding>
591 , fusion::vector2<Char(&)[2], Char(&)[2]> // For single char strings
595 static bool const no_case =
596 has_modifier<Modifiers, tag::char_code_base<tag::no_case> >::value;
599 spirit::detail::get_encoding<Modifiers, CharEncoding>::type
602 typedef char_range<char_encoding, no_case> result_type;
604 template <typename Terminal>
605 result_type operator()(Terminal const& term, unused_type) const
608 fusion::at_c<0>(term.args)[0]
609 , fusion::at_c<1>(term.args)[0]