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