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 generateboost::spirit::karma::any_string106 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> generateboost::spirit::karma::any_string123 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> whatboost::spirit::karma::any_string135 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 literal_stringboost::spirit::karma::literal_string159 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> generateboost::spirit::karma::literal_string169 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> generateboost::spirit::karma::literal_string193 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> whatboost::spirit::karma::literal_string201 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 operator ()boost::spirit::karma::make_primitive230 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 operator ()boost::spirit::karma::make_primitive256 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> operator ()boost::spirit::karma::detail::make_string_direct285 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