lit.hpp 12 KB

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