char.hpp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547
  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. #if !defined(BOOST_SPIRIT_KARMA_CHAR_FEB_21_2007_0543PM)
  7. #define BOOST_SPIRIT_KARMA_CHAR_FEB_21_2007_0543PM
  8. #if defined(_MSC_VER)
  9. #pragma once
  10. #endif
  11. #include <boost/spirit/home/support/common_terminals.hpp>
  12. #include <boost/spirit/home/support/string_traits.hpp>
  13. #include <boost/spirit/home/support/info.hpp>
  14. #include <boost/spirit/home/support/char_class.hpp>
  15. #include <boost/spirit/home/support/detail/get_encoding.hpp>
  16. #include <boost/spirit/home/support/char_set/basic_chset.hpp>
  17. #include <boost/spirit/home/karma/domain.hpp>
  18. #include <boost/spirit/home/karma/meta_compiler.hpp>
  19. #include <boost/spirit/home/karma/delimit_out.hpp>
  20. #include <boost/spirit/home/karma/char/char_generator.hpp>
  21. #include <boost/spirit/home/karma/auxiliary/lazy.hpp>
  22. #include <boost/spirit/home/karma/detail/get_casetag.hpp>
  23. #include <boost/spirit/home/karma/detail/generate_to.hpp>
  24. #include <boost/spirit/home/karma/detail/enable_lit.hpp>
  25. #include <boost/fusion/include/at.hpp>
  26. #include <boost/fusion/include/vector.hpp>
  27. #include <boost/fusion/include/cons.hpp>
  28. #include <boost/mpl/if.hpp>
  29. #include <boost/mpl/assert.hpp>
  30. #include <boost/mpl/bool.hpp>
  31. #include <boost/utility/enable_if.hpp>
  32. #include <string>
  33. ///////////////////////////////////////////////////////////////////////////////
  34. namespace boost { namespace spirit
  35. {
  36. ///////////////////////////////////////////////////////////////////////////
  37. // Enablers
  38. ///////////////////////////////////////////////////////////////////////////
  39. template <typename CharEncoding>
  40. struct use_terminal<karma::domain
  41. , tag::char_code<tag::char_, CharEncoding> // enables char_
  42. > : mpl::true_ {};
  43. template <typename CharEncoding, typename A0>
  44. struct use_terminal<karma::domain
  45. , terminal_ex<
  46. tag::char_code<tag::char_, CharEncoding> // enables char_('x'), char_("x")
  47. , fusion::vector1<A0>
  48. >
  49. > : mpl::true_ {};
  50. template <typename A0>
  51. struct use_terminal<karma::domain
  52. , terminal_ex<tag::lit, fusion::vector1<A0> > // enables lit('x')
  53. , typename enable_if<traits::is_char<A0> >::type>
  54. : mpl::true_ {};
  55. template <typename CharEncoding, typename A0, typename A1>
  56. struct use_terminal<karma::domain
  57. , terminal_ex<
  58. tag::char_code<tag::char_, CharEncoding> // enables char_('a','z')
  59. , fusion::vector2<A0, A1>
  60. >
  61. > : mpl::true_ {};
  62. template <typename CharEncoding> // enables *lazy* char_('x'), char_("x")
  63. struct use_lazy_terminal<
  64. karma::domain
  65. , tag::char_code<tag::char_, CharEncoding>
  66. , 1 // arity
  67. > : mpl::true_ {};
  68. template <>
  69. struct use_terminal<karma::domain, char> // enables 'x'
  70. : mpl::true_ {};
  71. template <>
  72. struct use_terminal<karma::domain, char[2]> // enables "x"
  73. : mpl::true_ {};
  74. template <>
  75. struct use_terminal<karma::domain, wchar_t> // enables L'x'
  76. : mpl::true_ {};
  77. template <>
  78. struct use_terminal<karma::domain, wchar_t[2]> // enables L"x"
  79. : mpl::true_ {};
  80. }}
  81. ///////////////////////////////////////////////////////////////////////////////
  82. namespace boost { namespace spirit { namespace karma
  83. {
  84. #ifndef BOOST_SPIRIT_NO_PREDEFINED_TERMINALS
  85. using spirit::lit; // lit('x') is equivalent to 'x'
  86. #endif
  87. using spirit::lit_type;
  88. ///////////////////////////////////////////////////////////////////////////
  89. //
  90. // any_char
  91. // generates a single character from the associated attribute
  92. //
  93. // Note: this generator has to have an associated attribute
  94. //
  95. ///////////////////////////////////////////////////////////////////////////
  96. template <typename CharEncoding, typename Tag>
  97. struct any_char
  98. : char_generator<any_char<CharEncoding, Tag>, CharEncoding, Tag>
  99. {
  100. typedef typename CharEncoding::char_type char_type;
  101. typedef CharEncoding char_encoding;
  102. template <typename Context, typename Unused>
  103. struct attribute
  104. {
  105. typedef char_type type;
  106. };
  107. // any_char has an attached parameter
  108. template <typename Attribute, typename CharParam, typename Context>
  109. bool test(Attribute const& attr, CharParam& ch, Context&) const
  110. {
  111. ch = CharParam(attr);
  112. return true;
  113. }
  114. // any_char has no attribute attached, it needs to have been
  115. // initialized from a direct literal
  116. template <typename CharParam, typename Context>
  117. bool test(unused_type, CharParam&, Context&) const
  118. {
  119. // It is not possible (doesn't make sense) to use char_ without
  120. // providing any attribute, as the generator doesn't 'know' what
  121. // character to output. The following assertion fires if this
  122. // situation is detected in your code.
  123. BOOST_SPIRIT_ASSERT_FAIL(CharParam, char_not_usable_without_attribute, ());
  124. return false;
  125. }
  126. template <typename Context>
  127. static info what(Context const& /*context*/)
  128. {
  129. return info("any-char");
  130. }
  131. };
  132. ///////////////////////////////////////////////////////////////////////////
  133. //
  134. // literal_char
  135. // generates a single character given by a literal it was initialized
  136. // from
  137. //
  138. ///////////////////////////////////////////////////////////////////////////
  139. template <typename CharEncoding, typename Tag, bool no_attribute>
  140. struct literal_char
  141. : char_generator<literal_char<CharEncoding, Tag, no_attribute>
  142. , CharEncoding, Tag>
  143. {
  144. typedef typename CharEncoding::char_type char_type;
  145. typedef CharEncoding char_encoding;
  146. literal_char(char_type ch)
  147. : ch (spirit::char_class::convert<char_encoding>::to(Tag(), ch))
  148. {}
  149. template <typename Context, typename Unused>
  150. struct attribute
  151. : mpl::if_c<no_attribute, unused_type, char_type>
  152. {};
  153. // A char_('x') which additionally has an associated attribute emits
  154. // its immediate literal only if it matches the attribute, otherwise
  155. // it fails.
  156. // any_char has an attached parameter
  157. template <typename Attribute, typename CharParam, typename Context>
  158. bool test(Attribute const& attr, CharParam& ch_, Context&) const
  159. {
  160. // fail if attribute isn't matched my immediate literal
  161. ch_ = static_cast<char_type>(attr);
  162. return attr == ch;
  163. }
  164. // A char_('x') without any associated attribute just emits its
  165. // immediate literal
  166. template <typename CharParam, typename Context>
  167. bool test(unused_type, CharParam& ch_, Context&) const
  168. {
  169. ch_ = ch;
  170. return true;
  171. }
  172. template <typename Context>
  173. info what(Context const& /*context*/) const
  174. {
  175. return info("literal-char", char_encoding::toucs4(ch));
  176. }
  177. char_type ch;
  178. };
  179. ///////////////////////////////////////////////////////////////////////////
  180. // char range generator
  181. template <typename CharEncoding, typename Tag>
  182. struct char_range
  183. : char_generator<char_range<CharEncoding, Tag>, CharEncoding, Tag>
  184. {
  185. typedef typename CharEncoding::char_type char_type;
  186. typedef CharEncoding char_encoding;
  187. char_range(char_type from, char_type to)
  188. : from(spirit::char_class::convert<char_encoding>::to(Tag(), from))
  189. , to(spirit::char_class::convert<char_encoding>::to(Tag(), to))
  190. {}
  191. // A char_('a', 'z') which has an associated attribute emits it only if
  192. // it matches the character range, otherwise it fails.
  193. template <typename Attribute, typename CharParam, typename Context>
  194. bool test(Attribute const& attr, CharParam& ch, Context&) const
  195. {
  196. // fail if attribute doesn't belong to character range
  197. ch = attr;
  198. return (from <= char_type(attr)) && (char_type(attr) <= to);
  199. }
  200. // A char_('a', 'z') without any associated attribute fails compiling
  201. template <typename CharParam, typename Context>
  202. bool test(unused_type, CharParam&, Context&) const
  203. {
  204. // It is not possible (doesn't make sense) to use char_ generators
  205. // without providing any attribute, as the generator doesn't 'know'
  206. // what to output. The following assertion fires if this situation
  207. // is detected in your code.
  208. BOOST_SPIRIT_ASSERT_FAIL(CharParam
  209. , char_range_not_usable_without_attribute, ());
  210. return false;
  211. }
  212. template <typename Context>
  213. info what(Context& /*context*/) const
  214. {
  215. info result("char-range", char_encoding::toucs4(from));
  216. boost::get<std::string>(result.value) += '-';
  217. boost::get<std::string>(result.value) += to_utf8(char_encoding::toucs4(to));
  218. return result;
  219. }
  220. char_type from, to;
  221. };
  222. ///////////////////////////////////////////////////////////////////////////
  223. // character set generator
  224. template <typename CharEncoding, typename Tag, bool no_attribute>
  225. struct char_set
  226. : char_generator<char_set<CharEncoding, Tag, no_attribute>
  227. , CharEncoding, Tag>
  228. {
  229. typedef typename CharEncoding::char_type char_type;
  230. typedef CharEncoding char_encoding;
  231. template <typename Context, typename Unused>
  232. struct attribute
  233. : mpl::if_c<no_attribute, unused_type, char_type>
  234. {};
  235. template <typename String>
  236. char_set(String const& str)
  237. {
  238. typedef typename traits::char_type_of<String>::type in_type;
  239. BOOST_SPIRIT_ASSERT_MSG((
  240. (sizeof(char_type) == sizeof(in_type))
  241. ), cannot_convert_string, (String));
  242. typedef spirit::char_class::convert<char_encoding> convert_type;
  243. char_type const* definition =
  244. (char_type const*)traits::get_c_string(str);
  245. char_type ch = convert_type::to(Tag(), *definition++);
  246. while (ch)
  247. {
  248. char_type next = convert_type::to(Tag(), *definition++);
  249. if (next == '-')
  250. {
  251. next = convert_type::to(Tag(), *definition++);
  252. if (next == 0)
  253. {
  254. chset.set(ch);
  255. chset.set('-');
  256. break;
  257. }
  258. chset.set(ch, next);
  259. }
  260. else
  261. {
  262. chset.set(ch);
  263. }
  264. ch = next;
  265. }
  266. }
  267. // A char_("a-z") which has an associated attribute emits it only if
  268. // it matches the character set, otherwise it fails.
  269. template <typename Attribute, typename CharParam, typename Context>
  270. bool test(Attribute const& attr, CharParam& ch, Context&) const
  271. {
  272. // fail if attribute doesn't belong to character set
  273. ch = attr;
  274. return chset.test(char_type(attr));
  275. }
  276. // A char_("a-z") without any associated attribute fails compiling
  277. template <typename CharParam, typename Context>
  278. bool test(unused_type, CharParam&, Context&) const
  279. {
  280. // It is not possible (doesn't make sense) to use char_ generators
  281. // without providing any attribute, as the generator doesn't 'know'
  282. // what to output. The following assertion fires if this situation
  283. // is detected in your code.
  284. BOOST_SPIRIT_ASSERT_FAIL(CharParam
  285. , char_set_not_usable_without_attribute, ());
  286. return false;
  287. }
  288. template <typename Context>
  289. info what(Context& /*context*/) const
  290. {
  291. return info("char-set");
  292. }
  293. support::detail::basic_chset<char_type> chset;
  294. };
  295. ///////////////////////////////////////////////////////////////////////////
  296. // Generator generators: make_xxx function (objects)
  297. ///////////////////////////////////////////////////////////////////////////
  298. namespace detail
  299. {
  300. template <typename Modifiers, typename Encoding>
  301. struct basic_literal
  302. {
  303. static bool const lower =
  304. has_modifier<Modifiers, tag::char_code_base<tag::lower> >::value;
  305. static bool const upper =
  306. has_modifier<Modifiers, tag::char_code_base<tag::upper> >::value;
  307. typedef literal_char<
  308. typename spirit::detail::get_encoding_with_case<
  309. Modifiers, Encoding, lower || upper>::type
  310. , typename get_casetag<Modifiers, lower || upper>::type
  311. , true>
  312. result_type;
  313. template <typename Char>
  314. result_type operator()(Char ch, unused_type) const
  315. {
  316. return result_type(ch);
  317. }
  318. template <typename Char>
  319. result_type operator()(Char const* str, unused_type) const
  320. {
  321. return result_type(str[0]);
  322. }
  323. };
  324. }
  325. // literals: 'x', "x"
  326. template <typename Modifiers>
  327. struct make_primitive<char, Modifiers>
  328. : detail::basic_literal<Modifiers, char_encoding::standard> {};
  329. template <typename Modifiers>
  330. struct make_primitive<char const(&)[2], Modifiers>
  331. : detail::basic_literal<Modifiers, char_encoding::standard> {};
  332. // literals: L'x', L"x"
  333. template <typename Modifiers>
  334. struct make_primitive<wchar_t, Modifiers>
  335. : detail::basic_literal<Modifiers, char_encoding::standard_wide> {};
  336. template <typename Modifiers>
  337. struct make_primitive<wchar_t const(&)[2], Modifiers>
  338. : detail::basic_literal<Modifiers, char_encoding::standard_wide> {};
  339. // char_
  340. template <typename CharEncoding, typename Modifiers>
  341. struct make_primitive<tag::char_code<tag::char_, CharEncoding>, Modifiers>
  342. {
  343. static bool const lower =
  344. has_modifier<Modifiers, tag::char_code_base<tag::lower> >::value;
  345. static bool const upper =
  346. has_modifier<Modifiers, tag::char_code_base<tag::upper> >::value;
  347. typedef any_char<
  348. typename spirit::detail::get_encoding_with_case<
  349. Modifiers, CharEncoding, lower || upper>::type
  350. , typename detail::get_casetag<Modifiers, lower || upper>::type
  351. > result_type;
  352. result_type operator()(unused_type, unused_type) const
  353. {
  354. return result_type();
  355. }
  356. };
  357. ///////////////////////////////////////////////////////////////////////////
  358. namespace detail
  359. {
  360. template <typename CharEncoding, typename Modifiers, typename A0
  361. , bool no_attribute>
  362. struct make_char_direct
  363. {
  364. static bool const lower =
  365. has_modifier<Modifiers, tag::char_code_base<tag::lower> >::value;
  366. static bool const upper =
  367. has_modifier<Modifiers, tag::char_code_base<tag::upper> >::value;
  368. typedef typename spirit::detail::get_encoding_with_case<
  369. Modifiers, CharEncoding, lower || upper>::type encoding;
  370. typedef typename detail::get_casetag<
  371. Modifiers, lower || upper>::type tag;
  372. typedef typename mpl::if_<
  373. traits::is_string<A0>
  374. , char_set<encoding, tag, no_attribute>
  375. , literal_char<encoding, tag, no_attribute>
  376. >::type result_type;
  377. template <typename Terminal>
  378. result_type operator()(Terminal const& term, unused_type) const
  379. {
  380. return result_type(fusion::at_c<0>(term.args));
  381. }
  382. };
  383. }
  384. // char_(...), lit(...)
  385. template <typename CharEncoding, typename Modifiers, typename A0>
  386. struct make_primitive<
  387. terminal_ex<
  388. tag::char_code<tag::char_, CharEncoding>
  389. , fusion::vector1<A0> >
  390. , Modifiers>
  391. : detail::make_char_direct<CharEncoding, Modifiers, A0, false>
  392. {};
  393. template <typename Modifiers, typename A0>
  394. struct make_primitive<
  395. terminal_ex<tag::lit, fusion::vector1<A0> >
  396. , Modifiers
  397. , typename enable_if<traits::is_char<A0> >::type>
  398. : detail::make_char_direct<
  399. typename traits::char_encoding_from_char<
  400. typename traits::char_type_of<A0>::type>::type
  401. , Modifiers, A0, true>
  402. {};
  403. ///////////////////////////////////////////////////////////////////////////
  404. // char_("x")
  405. template <typename CharEncoding, typename Modifiers, typename Char>
  406. struct make_primitive<
  407. terminal_ex<
  408. tag::char_code<tag::char_, CharEncoding>
  409. , fusion::vector1<Char(&)[2]> > // For single char strings
  410. , Modifiers>
  411. {
  412. static bool const lower =
  413. has_modifier<Modifiers, tag::char_code_base<tag::lower> >::value;
  414. static bool const upper =
  415. has_modifier<Modifiers, tag::char_code_base<tag::upper> >::value;
  416. typedef literal_char<
  417. typename spirit::detail::get_encoding_with_case<
  418. Modifiers, CharEncoding, lower || upper>::type
  419. , typename detail::get_casetag<Modifiers, lower || upper>::type
  420. , false
  421. > result_type;
  422. template <typename Terminal>
  423. result_type operator()(Terminal const& term, unused_type) const
  424. {
  425. return result_type(fusion::at_c<0>(term.args)[0]);
  426. }
  427. };
  428. ///////////////////////////////////////////////////////////////////////////
  429. // char_('a', 'z')
  430. template <typename CharEncoding, typename Modifiers, typename A0, typename A1>
  431. struct make_primitive<
  432. terminal_ex<
  433. tag::char_code<tag::char_, CharEncoding>
  434. , fusion::vector2<A0, A1>
  435. >
  436. , Modifiers>
  437. {
  438. static bool const lower =
  439. has_modifier<Modifiers, tag::char_code_base<tag::lower> >::value;
  440. static bool const upper =
  441. has_modifier<Modifiers, tag::char_code_base<tag::upper> >::value;
  442. typedef char_range<
  443. typename spirit::detail::get_encoding_with_case<
  444. Modifiers, CharEncoding, lower || upper>::type
  445. , typename detail::get_casetag<Modifiers, lower || upper>::type
  446. > result_type;
  447. template <typename Terminal>
  448. result_type operator()(Terminal const& term, unused_type) const
  449. {
  450. return result_type(fusion::at_c<0>(term.args)
  451. , fusion::at_c<1>(term.args));
  452. }
  453. };
  454. template <typename CharEncoding, typename Modifiers, typename Char>
  455. struct make_primitive<
  456. terminal_ex<
  457. tag::char_code<tag::char_, CharEncoding>
  458. , fusion::vector2<Char(&)[2], Char(&)[2]> // For single char strings
  459. >
  460. , Modifiers>
  461. {
  462. static bool const lower =
  463. has_modifier<Modifiers, tag::char_code_base<tag::lower> >::value;
  464. static bool const upper =
  465. has_modifier<Modifiers, tag::char_code_base<tag::upper> >::value;
  466. typedef char_range<
  467. typename spirit::detail::get_encoding_with_case<
  468. Modifiers, CharEncoding, lower || upper>::type
  469. , typename detail::get_casetag<Modifiers, lower || upper>::type
  470. > result_type;
  471. template <typename Terminal>
  472. result_type operator()(Terminal const& term, unused_type) const
  473. {
  474. return result_type(fusion::at_c<0>(term.args)[0]
  475. , fusion::at_c<1>(term.args)[0]);
  476. }
  477. };
  478. }}} // namespace boost::spirit::karma
  479. #endif