1 /*============================================================================= 2 Copyright (c) 2001-2011 Joel de Guzman 3 Copyright (c) 2001-2011 Hartmut Kaiser 4 Copyright (c) 2010-2011 Bryce Lelbach 5 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_OUTPUT_UTREE_TRAITS_APR_16_2010_0655AM) 10 #define BOOST_SPIRIT_OUTPUT_UTREE_TRAITS_APR_16_2010_0655AM 11 12 #include <boost/spirit/home/support/attributes.hpp> 13 #include <boost/spirit/home/support/container.hpp> 14 #include <boost/spirit/home/support/utree.hpp> 15 #include <boost/spirit/home/qi/domain.hpp> 16 #include <boost/spirit/home/karma/domain.hpp> 17 #include <boost/spirit/home/qi/nonterminal/nonterminal_fwd.hpp> 18 #include <boost/spirit/home/karma/nonterminal/nonterminal_fwd.hpp> 19 20 #include <string> 21 22 #include <boost/cstdint.hpp> 23 #include <boost/variant.hpp> 24 #include <boost/range/iterator_range.hpp> 25 #include <boost/mpl/bool.hpp> 26 #include <boost/mpl/identity.hpp> 27 #include <boost/mpl/or.hpp> 28 #include <boost/type_traits/is_same.hpp> 29 #include <boost/utility/enable_if.hpp> 30 31 /////////////////////////////////////////////////////////////////////////////// 32 namespace boost 33 { 34 template <typename T> get(boost::spirit::utree const & x)35 inline T get(boost::spirit::utree const& x) 36 { 37 return x.get<T>(); 38 } 39 } 40 41 /////////////////////////////////////////////////////////////////////////////// 42 namespace boost { namespace spirit { namespace traits 43 { 44 namespace detail 45 { is_list(utree const & ut)46 inline bool is_list(utree const& ut) 47 { 48 switch (traits::which(ut)) 49 { 50 case utree_type::reference_type: 51 return is_list(ut.deref()); 52 53 case utree_type::list_type: 54 case utree_type::range_type: 55 return true; 56 57 default: 58 break; 59 } 60 return false; 61 } 62 is_uninitialized(utree const & ut)63 inline bool is_uninitialized(utree const& ut) 64 { 65 return traits::which(ut) == utree_type::invalid_type; 66 } 67 } 68 69 // this specialization tells Spirit how to extract the type of the value 70 // stored in the given utree node 71 template <> 72 struct variant_which<utree> 73 { callboost::spirit::traits::variant_which74 static int call(utree const& u) { return u.which(); } 75 }; 76 77 template <> 78 struct variant_which<utree::list_type> 79 { callboost::spirit::traits::variant_which80 static int call(utree::list_type const& u) { return u.which(); } 81 }; 82 83 /////////////////////////////////////////////////////////////////////////// 84 // Make sure all components of an alternative expose utree, even if they 85 // actually expose a utree::list_type 86 template <typename Domain> 87 struct alternative_attribute_transform<utree::list_type, Domain> 88 : mpl::identity<utree> 89 {}; 90 91 /////////////////////////////////////////////////////////////////////////// 92 // Make sure all components of a sequence expose utree, even if they 93 // actually expose a utree::list_type 94 template <typename Domain> 95 struct sequence_attribute_transform<utree::list_type, Domain> 96 : mpl::identity<utree> 97 {}; 98 99 /////////////////////////////////////////////////////////////////////////// 100 // this specialization lets Spirit know that typed basic_strings 101 // are strings 102 template <typename Base, utree_type::info I> 103 struct is_string<spirit::basic_string<Base, I> > 104 : mpl::true_ 105 {}; 106 107 /////////////////////////////////////////////////////////////////////////// 108 // these specializations extract the character type of a utree typed string 109 template <typename T, utree_type::info I> 110 struct char_type_of<spirit::basic_string<iterator_range<T>, I> > 111 : char_type_of<T> 112 {}; 113 114 template <utree_type::info I> 115 struct char_type_of<spirit::basic_string<std::string, I> > 116 : mpl::identity<char> 117 {}; 118 119 /////////////////////////////////////////////////////////////////////////// 120 // these specializations extract a c string from a utree typed string 121 template <typename String> 122 struct extract_c_string; 123 124 template <typename T, utree_type::info I> 125 struct extract_c_string< 126 spirit::basic_string<iterator_range<T const*>, I> 127 > { 128 typedef T char_type; 129 130 typedef spirit::basic_string<iterator_range<T const*>, I> string; 131 callboost::spirit::traits::extract_c_string132 static T const* call (string& s) 133 { 134 return s.begin(); 135 } 136 callboost::spirit::traits::extract_c_string137 static T const* call (string const& s) 138 { 139 return s.begin(); 140 } 141 }; 142 143 template <utree_type::info I> 144 struct extract_c_string<spirit::basic_string<std::string, I> > 145 { 146 typedef char char_type; 147 148 typedef spirit::basic_string<std::string, I> string; 149 callboost::spirit::traits::extract_c_string150 static char const* call (string& s) 151 { 152 return s.c_str(); 153 } 154 callboost::spirit::traits::extract_c_string155 static char const* call (string const& s) 156 { 157 return s.c_str(); 158 } 159 }; 160 161 /////////////////////////////////////////////////////////////////////////// 162 // these specializations are needed because utree::value_type == utree 163 template <> 164 struct is_substitute<utree, utree> 165 : mpl::true_ 166 {}; 167 168 template <> 169 struct is_weak_substitute<utree, utree> 170 : mpl::true_ 171 {}; 172 173 template <> 174 struct is_substitute<utree::list_type, utree::list_type> 175 : mpl::true_ 176 {}; 177 178 template <> 179 struct is_weak_substitute<utree::list_type, utree::list_type> 180 : mpl::true_ 181 {}; 182 183 /////////////////////////////////////////////////////////////////////////// 184 // this specialization tells Spirit.Qi to allow assignment to an utree from 185 // a variant 186 namespace detail 187 { 188 struct assign_to_utree_visitor : static_visitor<> 189 { assign_to_utree_visitorboost::spirit::traits::detail::assign_to_utree_visitor190 assign_to_utree_visitor(utree& ut) : ut_(ut) {} 191 192 template <typename T> operator ()boost::spirit::traits::detail::assign_to_utree_visitor193 void operator()(T& val) const 194 { 195 ut_ = val; 196 } 197 198 utree& ut_; 199 }; 200 } 201 202 template <BOOST_VARIANT_ENUM_PARAMS(typename T)> 203 struct assign_to_container_from_value< 204 utree, variant<BOOST_VARIANT_ENUM_PARAMS(T)> > 205 { 206 static void callboost::spirit::traits::assign_to_container_from_value207 call(variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& val, utree& attr) 208 { 209 apply_visitor(detail::assign_to_utree_visitor(attr), val); 210 } 211 }; 212 213 /////////////////////////////////////////////////////////////////////////// 214 // this specialization tells Spirit.Qi to allow assignment to an utree from 215 // a STL container 216 template <typename Attribute> 217 struct assign_to_container_from_value<utree, Attribute> 218 { 219 // any non-container type will be either directly assigned or appended callboost::spirit::traits::assign_to_container_from_value220 static void call(Attribute const& val, utree& attr, mpl::false_) 221 { 222 if (attr.empty()) 223 attr = val; 224 else 225 push_back(attr, val); 226 } 227 228 // any container type will be converted into a list_type utree callboost::spirit::traits::assign_to_container_from_value229 static void call(Attribute const& val, utree& attr, mpl::true_) 230 { 231 typedef typename traits::container_iterator<Attribute const>::type 232 iterator_type; 233 234 // make sure the attribute is a list, at least an empty one 235 if (attr.empty()) 236 attr = empty_list; 237 238 iterator_type end = traits::end(val); 239 for (iterator_type i = traits::begin(val); i != end; traits::next(i)) 240 push_back(attr, traits::deref(i)); 241 } 242 callboost::spirit::traits::assign_to_container_from_value243 static void call(Attribute const& val, utree& attr) 244 { 245 call(val, attr, is_container<Attribute>()); 246 } 247 }; 248 249 /////////////////////////////////////////////////////////////////////////// 250 // this specialization is required to disambiguate the specializations 251 // related to utree 252 template <> 253 struct assign_to_container_from_value<utree, utree> 254 { callboost::spirit::traits::assign_to_container_from_value255 static void call(utree const& val, utree& attr) 256 { 257 if (attr.empty()) { 258 attr = val; 259 } 260 else if (detail::is_list(val)) { 261 typedef utree::const_iterator iterator_type; 262 263 iterator_type end = traits::end(val); 264 for (iterator_type i = traits::begin(val); i != end; traits::next(i)) 265 push_back(attr, traits::deref(i)); 266 } 267 else { 268 push_back(attr, val); 269 } 270 } 271 }; 272 273 template <> 274 struct assign_to_container_from_value<utree, utree::list_type> 275 : assign_to_container_from_value<utree, utree> 276 {}; 277 278 // If the destination is a utree_list, we need to force the right hand side 279 // value into a new sub-node, always, no questions asked. 280 template <> 281 struct assign_to_container_from_value<utree::list_type, utree> 282 { callboost::spirit::traits::assign_to_container_from_value283 static void call(utree const& val, utree& attr) 284 { 285 push_back(attr, val); 286 } 287 }; 288 289 // If both, the right hand side and the left hand side are utree_lists 290 // we have a lhs rule which has a single rule exposing a utree_list as its 291 // rhs (optionally wrapped into a directive or other unary parser). In this 292 // case we do not create a new sub-node. 293 template <> 294 struct assign_to_container_from_value<utree::list_type, utree::list_type> 295 : assign_to_container_from_value<utree, utree> 296 {}; 297 298 /////////////////////////////////////////////////////////////////////////// 299 // this specialization makes sure strings get assigned as a whole and are 300 // not converted into a utree list 301 template <> 302 struct assign_to_container_from_value<utree, utf8_string_type> 303 { callboost::spirit::traits::assign_to_container_from_value304 static void call(utf8_string_type const& val, utree& attr) 305 { 306 if (attr.empty()) 307 attr = val; 308 else 309 push_back(attr, val); 310 } 311 }; 312 313 // this specialization keeps symbols from being transformed into strings 314 template<> 315 struct assign_to_container_from_value<utree, utf8_symbol_type> 316 { callboost::spirit::traits::assign_to_container_from_value317 static void call (utf8_symbol_type const& val, utree& attr) 318 { 319 if (attr.empty()) 320 attr = val; 321 else 322 push_back(attr, val); 323 } 324 }; 325 326 template <> 327 struct assign_to_container_from_value<utree, binary_string_type> 328 { callboost::spirit::traits::assign_to_container_from_value329 static void call(binary_string_type const& val, utree& attr) 330 { 331 if (attr.empty()) 332 attr = val; 333 else 334 push_back(attr, val); 335 } 336 }; 337 338 template<> 339 struct assign_to_container_from_value<utree, utf8_symbol_range_type> 340 { callboost::spirit::traits::assign_to_container_from_value341 static void call (utf8_symbol_range_type const& val, utree& attr) 342 { 343 if (attr.empty()) 344 attr = val; 345 else 346 push_back(attr, val); 347 } 348 }; 349 350 template <> 351 struct assign_to_container_from_value<utree, binary_range_type> 352 { callboost::spirit::traits::assign_to_container_from_value353 static void call(binary_range_type const& val, utree& attr) 354 { 355 if (attr.empty()) 356 attr = val; 357 else 358 push_back(attr, val); 359 } 360 }; 361 362 template <> 363 struct assign_to_container_from_value<utree, std::string> 364 { callboost::spirit::traits::assign_to_container_from_value365 static void call(std::string const& val, utree& attr) 366 { 367 if (attr.empty()) 368 attr = val; 369 else 370 push_back(attr, val); 371 } 372 }; 373 374 /////////////////////////////////////////////////////////////////////////// 375 // this specialization tells Spirit.Qi to allow assignment to an utree from 376 // generic iterators 377 template <typename Iterator> 378 struct assign_to_attribute_from_iterators<utree, Iterator> 379 { 380 static void callboost::spirit::traits::assign_to_attribute_from_iterators381 call(Iterator const& first, Iterator const& last, utree& attr) 382 { 383 if (attr.empty()) 384 attr.assign(first, last); 385 else { 386 for (Iterator i = first; i != last; ++i) 387 push_back(attr, traits::deref(i)); 388 } 389 } 390 }; 391 392 /////////////////////////////////////////////////////////////////////////// 393 // Karma only: convert utree node to string 394 namespace detail 395 { 396 struct attribute_as_string_type 397 { 398 typedef utf8_string_range_type type; 399 callboost::spirit::traits::detail::attribute_as_string_type400 static type call(utree const& attr) 401 { 402 return boost::get<utf8_string_range_type>(attr); 403 } 404 is_validboost::spirit::traits::detail::attribute_as_string_type405 static bool is_valid(utree const& attr) 406 { 407 switch (traits::which(attr)) 408 { 409 case utree_type::reference_type: 410 return is_valid(attr.deref()); 411 412 case utree_type::string_range_type: 413 case utree_type::string_type: 414 return true; 415 416 default: 417 return false; 418 } 419 } 420 }; 421 } 422 423 template <> 424 struct attribute_as<std::string, utree> 425 : detail::attribute_as_string_type 426 {}; 427 428 template <> 429 struct attribute_as<utf8_string_type, utree> 430 : detail::attribute_as_string_type 431 {}; 432 433 template <> 434 struct attribute_as<utf8_string_range_type, utree> 435 : detail::attribute_as_string_type 436 {}; 437 438 /////////////////////////////////////////////////////////////////////////// 439 namespace detail 440 { 441 struct attribute_as_symbol_type 442 { 443 typedef utf8_symbol_range_type type; 444 callboost::spirit::traits::detail::attribute_as_symbol_type445 static type call(utree const& attr) 446 { 447 return boost::get<utf8_symbol_range_type>(attr); 448 } 449 is_validboost::spirit::traits::detail::attribute_as_symbol_type450 static bool is_valid(utree const& attr) 451 { 452 switch (traits::which(attr)) 453 { 454 case utree_type::reference_type: 455 return is_valid(attr.deref()); 456 457 case utree_type::symbol_type: 458 return true; 459 460 default: 461 return false; 462 } 463 } 464 }; 465 } 466 467 template <> 468 struct attribute_as<utf8_symbol_type, utree> 469 : detail::attribute_as_symbol_type 470 {}; 471 472 template <> 473 struct attribute_as<utf8_symbol_range_type, utree> 474 : detail::attribute_as_symbol_type 475 {}; 476 477 template <typename Attribute> 478 struct attribute_as<Attribute, utree::list_type> 479 : attribute_as<Attribute, utree> 480 {}; 481 482 /////////////////////////////////////////////////////////////////////////// 483 namespace detail 484 { 485 struct attribute_as_binary_string_type 486 { 487 typedef binary_range_type type; 488 callboost::spirit::traits::detail::attribute_as_binary_string_type489 static type call(utree const& attr) 490 { 491 return boost::get<binary_range_type>(attr); 492 } 493 is_validboost::spirit::traits::detail::attribute_as_binary_string_type494 static bool is_valid(utree const& attr) 495 { 496 switch (traits::which(attr)) 497 { 498 case utree_type::reference_type: 499 return is_valid(attr.deref()); 500 501 case utree_type::binary_type: 502 return true; 503 504 default: 505 return false; 506 } 507 } 508 }; 509 } 510 511 template <> 512 struct attribute_as<binary_string_type, utree> 513 : detail::attribute_as_binary_string_type 514 {}; 515 516 template <> 517 struct attribute_as<binary_range_type, utree> 518 : detail::attribute_as_binary_string_type 519 {}; 520 521 /////////////////////////////////////////////////////////////////////////// 522 // push_back support for utree 523 template <typename T> 524 struct push_back_container<utree, T> 525 { callboost::spirit::traits::push_back_container526 static bool call(utree& c, T const& val) 527 { 528 switch (traits::which(c)) 529 { 530 case utree_type::invalid_type: 531 case utree_type::nil_type: 532 case utree_type::list_type: 533 c.push_back(val); 534 break; 535 536 default: 537 { 538 utree ut; 539 ut.push_back(c); 540 ut.push_back(val); 541 c.swap(ut); 542 } 543 break; 544 } 545 return true; 546 } 547 }; 548 549 template <typename T> 550 struct push_back_container<utree::list_type, T> 551 : push_back_container<utree, T> 552 {}; 553 554 /////////////////////////////////////////////////////////////////////////// 555 // ensure the utree attribute is an empty list 556 template <> 557 struct make_container_attribute<utree> 558 { callboost::spirit::traits::make_container_attribute559 static void call(utree& ut) 560 { 561 if (!detail::is_list(ut)) { 562 if (detail::is_uninitialized(ut)) 563 ut = empty_list; 564 else { 565 utree retval (empty_list); 566 retval.push_back(ut); 567 ut.swap(retval); 568 } 569 } 570 } 571 }; 572 573 template <> 574 struct make_container_attribute<utree::list_type> 575 : make_container_attribute<utree> 576 {}; 577 578 /////////////////////////////////////////////////////////////////////////// 579 // an utree is a container on its own 580 template <> 581 struct build_std_vector<utree> 582 { 583 typedef utree type; 584 }; 585 586 template <> 587 struct build_std_vector<utree::list_type> 588 { 589 typedef utree::list_type type; 590 }; 591 592 /////////////////////////////////////////////////////////////////////////// 593 // debug support for utree 594 template <typename Out> 595 struct print_attribute_debug<Out, utree> 596 { callboost::spirit::traits::print_attribute_debug597 static void call(Out& out, utree const& val) 598 { 599 out << val; 600 } 601 }; 602 603 /////////////////////////////////////////////////////////////////////////// 604 // force utree list attribute in a sequence to be dereferenced if a rule 605 // or a grammar exposes an utree as it's attribute 606 namespace detail 607 { 608 // Checks whether the exposed Attribute allows to handle utree or 609 // utree::list_type directly. Returning mpl::false_ from this meta 610 // function will force a new utree instance to be created for each 611 // invocation of the embedded parser. 612 613 // The purpose of using utree::list_type as an attribute is to force a 614 // new sub-node in the result. 615 template <typename Attribute, typename Enable = void> 616 struct handles_utree_list_container 617 : mpl::and_< 618 mpl::not_<is_same<utree::list_type, Attribute> >, 619 traits::is_container<Attribute> > 620 {}; 621 622 // The following specializations make sure that the actual handling of 623 // an utree (or utree::list_type) attribute is deferred to the embedded 624 // parsers of a sequence, alternative or optional component. 625 template <typename Attribute> 626 struct handles_utree_list_container<Attribute 627 , typename enable_if<fusion::traits::is_sequence<Attribute> >::type> 628 : mpl::true_ 629 {}; 630 631 template <typename Attribute> 632 struct handles_utree_list_container<boost::optional<Attribute> > 633 : mpl::true_ 634 {}; 635 636 template <BOOST_VARIANT_ENUM_PARAMS(typename T)> 637 struct handles_utree_list_container< 638 boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> > 639 : mpl::true_ 640 {}; 641 } 642 643 template < 644 typename IteratorA, typename IteratorB, typename Context 645 , typename T1, typename T2, typename T3, typename T4> 646 struct handles_container<qi::rule<IteratorA, T1, T2, T3, T4> 647 , utree, Context, IteratorB> 648 : detail::handles_utree_list_container<typename attribute_of< 649 qi::rule<IteratorA, T1, T2, T3, T4>, Context, IteratorB 650 >::type> 651 {}; 652 653 template < 654 typename IteratorA, typename IteratorB, typename Context 655 , typename T1, typename T2, typename T3, typename T4> 656 struct handles_container<qi::grammar<IteratorA, T1, T2, T3, T4> 657 , utree, Context, IteratorB> 658 : detail::handles_utree_list_container<typename attribute_of< 659 qi::grammar<IteratorA, T1, T2, T3, T4>, Context, IteratorB 660 >::type> 661 {}; 662 663 template < 664 typename IteratorA, typename IteratorB, typename Context 665 , typename T1, typename T2, typename T3, typename T4> 666 struct handles_container<qi::rule<IteratorA, T1, T2, T3, T4> 667 , utree::list_type, Context, IteratorB> 668 : detail::handles_utree_list_container<typename attribute_of< 669 qi::rule<IteratorA, T1, T2, T3, T4>, Context, IteratorB 670 >::type> 671 {}; 672 673 template < 674 typename IteratorA, typename IteratorB, typename Context 675 , typename T1, typename T2, typename T3, typename T4> 676 struct handles_container<qi::grammar<IteratorA, T1, T2, T3, T4> 677 , utree::list_type, Context, IteratorB> 678 : detail::handles_utree_list_container<typename attribute_of< 679 qi::grammar<IteratorA, T1, T2, T3, T4>, Context, IteratorB 680 >::type> 681 {}; 682 683 /////////////////////////////////////////////////////////////////////////// 684 template <typename Attribute, typename Sequence> 685 struct pass_through_container< 686 utree, utree, Attribute, Sequence, qi::domain> 687 : detail::handles_utree_list_container<Attribute> 688 {}; 689 690 template <typename Attribute, typename Sequence> 691 struct pass_through_container< 692 utree::list_type, utree, Attribute, Sequence, qi::domain> 693 : detail::handles_utree_list_container<Attribute> 694 {}; 695 696 /////////////////////////////////////////////////////////////////////////// 697 namespace detail 698 { 699 // Checks whether the exposed Attribute allows to handle utree or 700 // utree::list_type directly. Returning mpl::false_ from this meta 701 // function will force a new utree instance to be created for each 702 // invocation of the embedded parser. 703 704 // The purpose of using utree::list_type as an attribute is to force a 705 // new sub-node in the result. 706 template <typename Attribute, typename Enable = void> 707 struct handles_utree_container 708 : mpl::and_< 709 mpl::not_<is_same<utree, Attribute> >, 710 traits::is_container<Attribute> > 711 {}; 712 713 // The following specializations make sure that the actual handling of 714 // an utree (or utree::list_type) attribute is deferred to the embedded 715 // parsers of a sequence, alternative or optional component. 716 template <typename Attribute> 717 struct handles_utree_container<Attribute 718 , typename enable_if<fusion::traits::is_sequence<Attribute> >::type> 719 : mpl::true_ 720 {}; 721 722 template <typename Attribute> 723 struct handles_utree_container<boost::optional<Attribute> > 724 : mpl::true_ 725 {}; 726 727 template <BOOST_VARIANT_ENUM_PARAMS(typename T)> 728 struct handles_utree_container< 729 boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> > 730 : mpl::true_ 731 {}; 732 } 733 734 template < 735 typename IteratorA, typename IteratorB, typename Context 736 , typename T1, typename T2, typename T3, typename T4> 737 struct handles_container<karma::rule<IteratorA, T1, T2, T3, T4> 738 , utree, Context, IteratorB> 739 : detail::handles_utree_container<typename attribute_of< 740 karma::rule<IteratorA, T1, T2, T3, T4>, Context, IteratorB 741 >::type> 742 {}; 743 744 template < 745 typename IteratorA, typename IteratorB, typename Context 746 , typename T1, typename T2, typename T3, typename T4> 747 struct handles_container<karma::grammar<IteratorA, T1, T2, T3, T4> 748 , utree, Context, IteratorB> 749 : detail::handles_utree_container<typename attribute_of< 750 karma::grammar<IteratorA, T1, T2, T3, T4>, Context, IteratorB 751 >::type> 752 {}; 753 754 /////////////////////////////////////////////////////////////////////////// 755 template <typename Attribute, typename Sequence> 756 struct pass_through_container< 757 utree, utree, Attribute, Sequence, karma::domain> 758 : detail::handles_utree_container<Attribute> 759 {}; 760 761 /////////////////////////////////////////////////////////////////////////// 762 // the specialization below tells Spirit how to handle utree if it is used 763 // with an optional component 764 template <> 765 struct optional_attribute<utree> 766 { 767 typedef utree const& type; 768 callboost::spirit::traits::optional_attribute769 static type call(utree const& val) 770 { 771 return val; 772 } 773 774 // only 'invalid_type' utree nodes are not valid is_validboost::spirit::traits::optional_attribute775 static bool is_valid(utree const& val) 776 { 777 return !detail::is_uninitialized(val); 778 } 779 }; 780 781 template <> 782 struct build_optional<utree> 783 { 784 typedef utree type; 785 }; 786 787 template <> 788 struct build_optional<utree::list_type> 789 { 790 typedef utree::list_type type; 791 }; 792 793 // an utree is an optional (in any domain) 794 template <> 795 struct not_is_optional<utree, qi::domain> 796 : mpl::false_ 797 {}; 798 799 template <> 800 struct not_is_optional<utree::list_type, qi::domain> 801 : mpl::false_ 802 {}; 803 804 template <> 805 struct not_is_optional<utree, karma::domain> 806 : mpl::false_ 807 {}; 808 809 template <> 810 struct not_is_optional<utree::list_type, karma::domain> 811 : mpl::false_ 812 {}; 813 814 /////////////////////////////////////////////////////////////////////////// 815 // the specialization below tells Spirit to handle utree as if it 816 // where a 'real' variant (in the context of karma) 817 template <> 818 struct not_is_variant<utree, karma::domain> 819 : mpl::false_ 820 {}; 821 822 template <> 823 struct not_is_variant<utree::list_type, karma::domain> 824 : mpl::false_ 825 {}; 826 827 // The specializations below tell Spirit to verify whether an attribute 828 // type is compatible with a given variant type 829 template <> 830 struct compute_compatible_component_variant< 831 utree, iterator_range<utree::iterator> > 832 : mpl::true_ 833 { 834 typedef iterator_range<utree::iterator> compatible_type; 835 is_compatibleboost::spirit::traits::compute_compatible_component_variant836 static bool is_compatible(int d) 837 { 838 return d == utree_type::list_type; 839 } 840 }; 841 842 template <> 843 struct compute_compatible_component_variant< 844 utree, iterator_range<utree::const_iterator> > 845 : mpl::true_ 846 { 847 typedef iterator_range<utree::const_iterator> compatible_type; 848 is_compatibleboost::spirit::traits::compute_compatible_component_variant849 static bool is_compatible(int d) 850 { 851 return d == utree_type::list_type; 852 } 853 }; 854 855 template <> 856 struct compute_compatible_component_variant<utree, utree::invalid_type> 857 : mpl::true_ 858 { 859 typedef utree::invalid_type compatible_type; 860 is_compatibleboost::spirit::traits::compute_compatible_component_variant861 static bool is_compatible(int d) 862 { 863 return d == utree_type::invalid_type; 864 } 865 }; 866 867 template <> 868 struct compute_compatible_component_variant<utree, utree::nil_type> 869 : mpl::true_ 870 { 871 typedef utree::nil_type compatible_type; 872 is_compatibleboost::spirit::traits::compute_compatible_component_variant873 static bool is_compatible(int d) 874 { 875 return d == utree_type::nil_type; 876 } 877 }; 878 879 template <> 880 struct compute_compatible_component_variant<utree, bool> 881 : mpl::true_ 882 { 883 typedef bool compatible_type; 884 is_compatibleboost::spirit::traits::compute_compatible_component_variant885 static bool is_compatible(int d) 886 { 887 return d == utree_type::bool_type; 888 } 889 }; 890 891 template <> 892 struct compute_compatible_component_variant<utree, int> 893 : mpl::true_ 894 { 895 typedef int compatible_type; 896 is_compatibleboost::spirit::traits::compute_compatible_component_variant897 static bool is_compatible(int d) 898 { 899 return d == utree_type::int_type; 900 } 901 }; 902 903 template <> 904 struct compute_compatible_component_variant<utree, double> 905 : mpl::true_ 906 { 907 typedef double compatible_type; 908 is_compatibleboost::spirit::traits::compute_compatible_component_variant909 static bool is_compatible(int d) 910 { 911 return d == utree_type::double_type; 912 } 913 }; 914 915 template <> 916 struct compute_compatible_component_variant< 917 utree, utf8_string_range_type> 918 : mpl::true_ 919 { 920 typedef utf8_string_range_type compatible_type; 921 is_compatibleboost::spirit::traits::compute_compatible_component_variant922 static bool is_compatible(int d) 923 { 924 return d == utree_type::string_type; 925 } 926 }; 927 928 template <> 929 struct compute_compatible_component_variant< 930 utree, utf8_string_type> 931 : mpl::true_ 932 { 933 typedef utf8_string_type compatible_type; 934 is_compatibleboost::spirit::traits::compute_compatible_component_variant935 static bool is_compatible(int d) 936 { 937 return d == utree_type::string_type; 938 } 939 }; 940 941 template <> 942 struct compute_compatible_component_variant< 943 utree, utf8_symbol_range_type> 944 : mpl::true_ 945 { 946 typedef utf8_symbol_range_type compatible_type; 947 is_compatibleboost::spirit::traits::compute_compatible_component_variant948 static bool is_compatible(int d) 949 { 950 return d == utree_type::symbol_type; 951 } 952 }; 953 954 template <> 955 struct compute_compatible_component_variant< 956 utree, utf8_symbol_type> 957 : mpl::true_ 958 { 959 typedef utf8_symbol_type compatible_type; 960 is_compatibleboost::spirit::traits::compute_compatible_component_variant961 static bool is_compatible(int d) 962 { 963 return d == utree_type::symbol_type; 964 } 965 }; 966 967 template <> 968 struct compute_compatible_component_variant< 969 utree, binary_range_type> 970 : mpl::true_ 971 { 972 typedef binary_range_type compatible_type; 973 is_compatibleboost::spirit::traits::compute_compatible_component_variant974 static bool is_compatible(int d) 975 { 976 return d == utree_type::binary_type; 977 } 978 }; 979 980 template <> 981 struct compute_compatible_component_variant< 982 utree, binary_string_type> 983 : mpl::true_ 984 { 985 typedef binary_string_type compatible_type; 986 is_compatibleboost::spirit::traits::compute_compatible_component_variant987 static bool is_compatible(int d) 988 { 989 return d == utree_type::binary_type; 990 } 991 }; 992 993 template <> 994 struct compute_compatible_component_variant<utree, utree> 995 : mpl::true_ 996 { 997 typedef utree compatible_type; 998 is_compatibleboost::spirit::traits::compute_compatible_component_variant999 static bool is_compatible(int d) 1000 { 1001 return d >= utree_type::invalid_type && 1002 d <= utree_type::reference_type; 1003 } 1004 }; 1005 1006 template <> 1007 struct compute_compatible_component_variant< 1008 utree, std::vector<utree> > 1009 : mpl::true_ 1010 { 1011 typedef utree compatible_type; 1012 is_compatibleboost::spirit::traits::compute_compatible_component_variant1013 static bool is_compatible(int d) 1014 { 1015 return d >= utree_type::invalid_type && 1016 d <= utree_type::reference_type; 1017 } 1018 }; 1019 1020 template <typename Sequence> 1021 struct compute_compatible_component_variant<utree, Sequence 1022 , mpl::false_ 1023 , typename enable_if<fusion::traits::is_sequence<Sequence> >::type> 1024 : mpl::true_ 1025 { 1026 typedef iterator_range<utree::const_iterator> compatible_type; 1027 is_compatibleboost::spirit::traits::compute_compatible_component_variant1028 static bool is_compatible(int d) 1029 { 1030 return d == utree_type::list_type; 1031 } 1032 }; 1033 1034 template <typename Attribute> 1035 struct compute_compatible_component_variant<utree::list_type, Attribute> 1036 : compute_compatible_component_variant<utree, Attribute> 1037 {}; 1038 1039 /////////////////////////////////////////////////////////////////////////// 1040 template <> 1041 struct symbols_lookup<utree, utf8_symbol_type> 1042 { 1043 typedef std::string type; 1044 callboost::spirit::traits::symbols_lookup1045 static type call(utree const& t) 1046 { 1047 utf8_symbol_range_type r = boost::get<utf8_symbol_range_type>(t); 1048 return std::string(traits::begin(r), traits::end(r)); 1049 } 1050 }; 1051 1052 template <> 1053 struct symbols_lookup<utf8_symbol_type, utf8_symbol_type> 1054 { 1055 typedef std::string type; 1056 callboost::spirit::traits::symbols_lookup1057 static type call(utf8_symbol_type const& t) 1058 { 1059 return t; 1060 } 1061 }; 1062 1063 /////////////////////////////////////////////////////////////////////////// 1064 namespace detail 1065 { 1066 template <typename T> get_or_deref(utree const & t)1067 inline T get_or_deref(utree const& t) 1068 { 1069 if (detail::is_list(t)) 1070 return boost::get<T>(t.front()); 1071 return boost::get<T>(t); 1072 } 1073 } 1074 1075 template <> 1076 struct extract_from_container<utree, utree::nil_type> 1077 { 1078 typedef utree::nil_type type; 1079 1080 template <typename Context> callboost::spirit::traits::extract_from_container1081 static type call(utree const&, Context&) 1082 { 1083 return nil; 1084 } 1085 }; 1086 1087 template <> 1088 struct extract_from_container<utree, char> 1089 { 1090 typedef char type; 1091 1092 template <typename Context> callboost::spirit::traits::extract_from_container1093 static type call(utree const& t, Context&) 1094 { 1095 utf8_symbol_range_type r = detail::get_or_deref<utf8_symbol_range_type>(t); 1096 return r.front(); 1097 } 1098 }; 1099 1100 template <> 1101 struct extract_from_container<utree, bool> 1102 { 1103 typedef bool type; 1104 1105 template <typename Context> callboost::spirit::traits::extract_from_container1106 static type call(utree const& t, Context&) 1107 { 1108 return detail::get_or_deref<bool>(t); 1109 } 1110 }; 1111 1112 template <> 1113 struct extract_from_container<utree, int> 1114 { 1115 typedef int type; 1116 1117 template <typename Context> callboost::spirit::traits::extract_from_container1118 static type call(utree const& t, Context&) 1119 { 1120 return detail::get_or_deref<int>(t); 1121 } 1122 }; 1123 1124 template <> 1125 struct extract_from_container<utree, double> 1126 { 1127 typedef double type; 1128 1129 template <typename Context> callboost::spirit::traits::extract_from_container1130 static type call(utree const& t, Context&) 1131 { 1132 return detail::get_or_deref<double>(t); 1133 } 1134 }; 1135 1136 template <typename Traits, typename Alloc> 1137 struct extract_from_container<utree, std::basic_string<char, Traits, Alloc> > 1138 { 1139 typedef std::basic_string<char, Traits, Alloc> type; 1140 1141 template <typename Context> callboost::spirit::traits::extract_from_container1142 static type call(utree const& t, Context&) 1143 { 1144 utf8_string_range_type r = detail::get_or_deref<utf8_string_range_type>(t); 1145 return type(traits::begin(r), traits::end(r)); 1146 } 1147 }; 1148 1149 template <> 1150 struct extract_from_container<utree, utf8_symbol_type> 1151 { 1152 typedef utf8_symbol_type type; 1153 1154 template <typename Context> callboost::spirit::traits::extract_from_container1155 static type call(utree const& t, Context&) 1156 { 1157 utf8_symbol_range_type r = detail::get_or_deref<utf8_symbol_range_type>(t); 1158 return type(traits::begin(r), traits::end(r)); 1159 } 1160 }; 1161 1162 template <> 1163 struct extract_from_container<utree, utf8_string_type> 1164 { 1165 typedef utf8_string_type type; 1166 1167 template <typename Context> callboost::spirit::traits::extract_from_container1168 static type call(utree const& t, Context&) 1169 { 1170 utf8_string_range_type r = detail::get_or_deref<utf8_string_range_type>(t); 1171 return type(traits::begin(r), traits::end(r)); 1172 } 1173 }; 1174 1175 /////////////////////////////////////////////////////////////////////////// 1176 template <> 1177 struct transform_attribute<utree const, utree::nil_type, karma::domain> 1178 { 1179 typedef utree::nil_type type; 1180 preboost::spirit::traits::transform_attribute1181 static type pre(utree const&) 1182 { 1183 return nil; 1184 } 1185 }; 1186 1187 template <> 1188 struct transform_attribute<utree const, char, karma::domain> 1189 { 1190 typedef char type; 1191 preboost::spirit::traits::transform_attribute1192 static type pre(utree const& t) 1193 { 1194 utf8_string_range_type r = detail::get_or_deref<utf8_string_range_type>(t); 1195 return r.front(); 1196 } 1197 }; 1198 1199 template <> 1200 struct transform_attribute<utree const, bool, karma::domain> 1201 { 1202 typedef bool type; 1203 preboost::spirit::traits::transform_attribute1204 static type pre(utree const& t) 1205 { 1206 return detail::get_or_deref<bool>(t); 1207 } 1208 }; 1209 1210 template <> 1211 struct transform_attribute<utree const, int, karma::domain> 1212 { 1213 typedef int type; 1214 preboost::spirit::traits::transform_attribute1215 static type pre(utree const& t) 1216 { 1217 return detail::get_or_deref<int>(t); 1218 } 1219 }; 1220 1221 template <> 1222 struct transform_attribute<utree const, double, karma::domain> 1223 { 1224 typedef double type; 1225 preboost::spirit::traits::transform_attribute1226 static type pre(utree const& t) 1227 { 1228 return detail::get_or_deref<double>(t); 1229 } 1230 }; 1231 1232 template <typename Traits, typename Alloc> 1233 struct transform_attribute< 1234 utree const, std::basic_string<char, Traits, Alloc>, karma::domain> 1235 { 1236 typedef std::basic_string<char, Traits, Alloc> type; 1237 preboost::spirit::traits::transform_attribute1238 static type pre(utree const& t) 1239 { 1240 utf8_string_range_type r = detail::get_or_deref<utf8_string_range_type>(t); 1241 return type(traits::begin(r), traits::end(r)); 1242 } 1243 }; 1244 1245 // this specialization is used whenever a utree is passed to a rule as part 1246 // of a sequence 1247 template <typename Iterator> 1248 struct transform_attribute< 1249 iterator_range<Iterator> const, utree, karma::domain> 1250 { 1251 typedef utree type; 1252 preboost::spirit::traits::karma::domain1253 static type pre(iterator_range<Iterator> const& t) 1254 { 1255 // return utree the begin iterator points to 1256 Iterator it = boost::begin(t); 1257 utree result(boost::ref(*it)); 1258 ++it; 1259 return result; 1260 } 1261 }; 1262 1263 /////////////////////////////////////////////////////////////////////////// 1264 template <> 1265 struct transform_attribute<utree const, utf8_string_type, karma::domain> 1266 { 1267 typedef utf8_string_type type; 1268 preboost::spirit::traits::transform_attribute1269 static type pre(utree const& t) 1270 { 1271 utf8_string_range_type r = detail::get_or_deref<utf8_string_range_type>(t); 1272 return type(traits::begin(r), traits::end(r)); 1273 } 1274 }; 1275 1276 template <> 1277 struct transform_attribute<utree const, utf8_symbol_type, karma::domain> 1278 { 1279 typedef utf8_symbol_type type; 1280 preboost::spirit::traits::transform_attribute1281 static type pre(utree const& t) 1282 { 1283 utf8_symbol_range_type r = detail::get_or_deref<utf8_symbol_range_type>(t); 1284 return type(traits::begin(r), traits::end(r)); 1285 } 1286 }; 1287 1288 template <typename Attribute> 1289 struct transform_attribute<utree::list_type const, Attribute, karma::domain> 1290 : transform_attribute<utree const, Attribute, karma::domain> 1291 {}; 1292 }}} 1293 1294 #endif 1295