1 /*============================================================================= 2 Copyright (c) 2001-2014 Joel de Guzman 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(SPIRIT_SEQUENCE_DETAIL_JAN_06_2013_1015AM) 8 #define SPIRIT_SEQUENCE_DETAIL_JAN_06_2013_1015AM 9 10 #include <boost/spirit/home/x3/support/traits/attribute_of.hpp> 11 #include <boost/spirit/home/x3/support/traits/attribute_category.hpp> 12 #include <boost/spirit/home/x3/support/traits/make_attribute.hpp> 13 #include <boost/spirit/home/x3/support/traits/has_attribute.hpp> 14 #include <boost/spirit/home/x3/support/traits/is_substitute.hpp> 15 #include <boost/spirit/home/x3/support/traits/container_traits.hpp> 16 #include <boost/spirit/home/x3/core/detail/parse_into_container.hpp> 17 18 #include <boost/fusion/include/begin.hpp> 19 #include <boost/fusion/include/end.hpp> 20 #include <boost/fusion/include/advance.hpp> 21 #include <boost/fusion/include/empty.hpp> 22 #include <boost/fusion/include/front.hpp> 23 #include <boost/fusion/include/iterator_range.hpp> 24 #include <boost/fusion/include/as_deque.hpp> 25 #include <boost/fusion/include/mpl.hpp> 26 27 #include <boost/mpl/copy_if.hpp> 28 #include <boost/mpl/not.hpp> 29 #include <boost/mpl/if.hpp> 30 #include <boost/mpl/insert_range.hpp> 31 #include <boost/mpl/eval_if.hpp> 32 #include <boost/mpl/vector.hpp> 33 #include <boost/mpl/identity.hpp> 34 35 #include <boost/type_traits/add_reference.hpp> 36 #include <boost/type_traits/is_same.hpp> 37 38 namespace boost { namespace spirit { namespace x3 39 { 40 template <typename Left, typename Right> 41 struct sequence; 42 }}} 43 44 namespace boost { namespace spirit { namespace x3 { namespace detail 45 { 46 template <typename Parser, typename Context, typename Enable = void> 47 struct sequence_size 48 { 49 static int const value = traits::has_attribute<Parser, Context>::value; 50 }; 51 52 template <typename Parser, typename Context> 53 struct sequence_size_subject 54 : sequence_size<typename Parser::subject_type, Context> {}; 55 56 template <typename Parser, typename Context> 57 struct sequence_size<Parser, Context 58 , typename enable_if_c<(Parser::is_pass_through_unary)>::type> 59 : sequence_size_subject<Parser, Context> {}; 60 61 template <typename L, typename R, typename Context> 62 struct sequence_size<sequence<L, R>, Context> 63 { 64 static int const value = 65 sequence_size<L, Context>::value + 66 sequence_size<R, Context>::value; 67 }; 68 69 struct pass_sequence_attribute_unused 70 { 71 typedef unused_type type; 72 73 template <typename T> 74 static unused_type callboost::spirit::x3::detail::pass_sequence_attribute_unused75 call(T&) 76 { 77 return unused_type(); 78 } 79 }; 80 81 template <typename Attribute> 82 struct pass_sequence_attribute_front 83 { 84 typedef typename fusion::result_of::front<Attribute>::type type; 85 86 static typename add_reference<type>::type callboost::spirit::x3::detail::pass_sequence_attribute_front87 call(Attribute& attr) 88 { 89 return fusion::front(attr); 90 } 91 }; 92 93 template <typename Attribute> 94 struct pass_through_sequence_attribute 95 { 96 typedef Attribute& type; 97 98 template <typename Attribute_> 99 static Attribute_& callboost::spirit::x3::detail::pass_through_sequence_attribute100 call(Attribute_& attr) 101 { 102 return attr; 103 } 104 }; 105 106 template <typename Parser, typename Attribute> 107 struct pass_sequence_attribute_used : 108 mpl::if_< 109 traits::is_size_one_sequence<Attribute> 110 , pass_sequence_attribute_front<Attribute> 111 , pass_through_sequence_attribute<Attribute>>::type {}; 112 113 template <typename Parser, typename Attribute, typename Enable = void> 114 struct pass_sequence_attribute : 115 mpl::if_< 116 fusion::result_of::empty<Attribute> 117 , pass_sequence_attribute_unused 118 , pass_sequence_attribute_used<Parser, Attribute>>::type {}; 119 120 template <typename L, typename R, typename Attribute> 121 struct pass_sequence_attribute<sequence<L, R>, Attribute> 122 : pass_through_sequence_attribute<Attribute> {}; 123 124 template <typename Parser, typename Attribute> 125 struct pass_sequence_attribute_subject : 126 pass_sequence_attribute<typename Parser::subject_type, Attribute> {}; 127 128 template <typename Parser, typename Attribute> 129 struct pass_sequence_attribute<Parser, Attribute 130 , typename enable_if_c<(Parser::is_pass_through_unary)>::type> 131 : pass_sequence_attribute_subject<Parser, Attribute> {}; 132 133 template <typename L, typename R, typename Attribute, typename Context 134 , typename Enable = void> 135 struct partition_attribute 136 { 137 static int const l_size = sequence_size<L, Context>::value; 138 static int const r_size = sequence_size<R, Context>::value; 139 140 // If you got an error here, then you are trying to pass 141 // a fusion sequence with the wrong number of elements 142 // as that expected by the (sequence) parser. 143 static_assert( 144 fusion::result_of::size<Attribute>::value == (l_size + r_size) 145 , "Attribute does not have the expected size." 146 ); 147 148 typedef typename fusion::result_of::begin<Attribute>::type l_begin; 149 typedef typename fusion::result_of::advance_c<l_begin, l_size>::type l_end; 150 typedef typename fusion::result_of::end<Attribute>::type r_end; 151 typedef fusion::iterator_range<l_begin, l_end> l_part; 152 typedef fusion::iterator_range<l_end, r_end> r_part; 153 typedef pass_sequence_attribute<L, l_part> l_pass; 154 typedef pass_sequence_attribute<R, r_part> r_pass; 155 leftboost::spirit::x3::detail::partition_attribute156 static l_part left(Attribute& s) 157 { 158 auto i = fusion::begin(s); 159 return l_part(i, fusion::advance_c<l_size>(i)); 160 } 161 rightboost::spirit::x3::detail::partition_attribute162 static r_part right(Attribute& s) 163 { 164 return r_part( 165 fusion::advance_c<l_size>(fusion::begin(s)) 166 , fusion::end(s)); 167 } 168 }; 169 170 template <typename L, typename R, typename Attribute, typename Context> 171 struct partition_attribute<L, R, Attribute, Context, 172 typename enable_if_c<(!traits::has_attribute<L, Context>::value && 173 traits::has_attribute<R, Context>::value)>::type> 174 { 175 typedef unused_type l_part; 176 typedef Attribute& r_part; 177 typedef pass_sequence_attribute_unused l_pass; 178 typedef pass_sequence_attribute<R, Attribute> r_pass; 179 leftboost::spirit::x3::detail::partition_attribute180 static unused_type left(Attribute&) 181 { 182 return unused; 183 } 184 rightboost::spirit::x3::detail::partition_attribute185 static Attribute& right(Attribute& s) 186 { 187 return s; 188 } 189 }; 190 191 template <typename L, typename R, typename Attribute, typename Context> 192 struct partition_attribute<L, R, Attribute, Context, 193 typename enable_if_c<(traits::has_attribute<L, Context>::value && 194 !traits::has_attribute<R, Context>::value)>::type> 195 { 196 typedef Attribute& l_part; 197 typedef unused_type r_part; 198 typedef pass_sequence_attribute<L, Attribute> l_pass; 199 typedef pass_sequence_attribute_unused r_pass; 200 leftboost::spirit::x3::detail::partition_attribute201 static Attribute& left(Attribute& s) 202 { 203 return s; 204 } 205 rightboost::spirit::x3::detail::partition_attribute206 static unused_type right(Attribute&) 207 { 208 return unused; 209 } 210 }; 211 212 template <typename L, typename R, typename Attribute, typename Context> 213 struct partition_attribute<L, R, Attribute, Context, 214 typename enable_if_c<(!traits::has_attribute<L, Context>::value && 215 !traits::has_attribute<R, Context>::value)>::type> 216 { 217 typedef unused_type l_part; 218 typedef unused_type r_part; 219 typedef pass_sequence_attribute_unused l_pass; 220 typedef pass_sequence_attribute_unused r_pass; 221 leftboost::spirit::x3::detail::partition_attribute222 static unused_type left(Attribute&) 223 { 224 return unused; 225 } 226 rightboost::spirit::x3::detail::partition_attribute227 static unused_type right(Attribute&) 228 { 229 return unused; 230 } 231 }; 232 233 template <typename L, typename R, typename C> 234 struct get_sequence_types 235 { 236 typedef 237 mpl::vector< 238 typename traits::attribute_of<L, C>::type 239 , typename traits::attribute_of<R, C>::type 240 > 241 type; 242 }; 243 244 template <typename LL, typename LR, typename R, typename C> 245 struct get_sequence_types<sequence<LL, LR>, R, C> 246 : mpl::push_back< typename get_sequence_types<LL, LR, C>::type 247 , typename traits::attribute_of<R, C>::type> {}; 248 249 template <typename L, typename RL, typename RR, typename C> 250 struct get_sequence_types<L, sequence<RL, RR>, C> 251 : mpl::push_front< typename get_sequence_types<RL, RR, C>::type 252 , typename traits::attribute_of<L, C>::type> {}; 253 254 template <typename LL, typename LR, typename RL, typename RR, typename C> 255 struct get_sequence_types<sequence<LL, LR>, sequence<RL, RR>, C> 256 { 257 typedef typename get_sequence_types<LL, LR, C>::type left; 258 typedef typename get_sequence_types<RL, RR, C>::type right; 259 typedef typename 260 mpl::insert_range<left, typename mpl::end<left>::type, right>::type 261 type; 262 }; 263 264 template <typename L, typename R, typename C> 265 struct attribute_of_sequence 266 { 267 // Get all sequence attribute types 268 typedef typename get_sequence_types<L, R, C>::type all_types; 269 270 // Filter all unused_types 271 typedef typename 272 mpl::copy_if< 273 all_types 274 , mpl::not_<is_same<mpl::_1, unused_type>> 275 , mpl::back_inserter<mpl::vector<>> 276 >::type 277 filtered_types; 278 279 // Build a fusion::deque if filtered_types is not empty, 280 // else just return unused_type 281 typedef typename 282 mpl::eval_if< 283 mpl::empty<filtered_types> 284 , mpl::identity<unused_type> 285 , mpl::if_<mpl::equal_to<mpl::size<filtered_types>, mpl::int_<1> >, 286 typename mpl::front<filtered_types>::type 287 , typename fusion::result_of::as_deque<filtered_types>::type > 288 >::type 289 type; 290 }; 291 292 template <typename Parser, typename Iterator, typename Context 293 , typename RContext, typename Attribute> parse_sequence(Parser const & parser,Iterator & first,Iterator const & last,Context const & context,RContext & rcontext,Attribute & attr,traits::tuple_attribute)294 bool parse_sequence( 295 Parser const& parser, Iterator& first, Iterator const& last 296 , Context const& context, RContext& rcontext, Attribute& attr 297 , traits::tuple_attribute) 298 { 299 typedef typename Parser::left_type Left; 300 typedef typename Parser::right_type Right; 301 typedef partition_attribute<Left, Right, Attribute, Context> partition; 302 typedef typename partition::l_pass l_pass; 303 typedef typename partition::r_pass r_pass; 304 305 typename partition::l_part l_part = partition::left(attr); 306 typename partition::r_part r_part = partition::right(attr); 307 typename l_pass::type l_attr = l_pass::call(l_part); 308 typename r_pass::type r_attr = r_pass::call(r_part); 309 310 Iterator save = first; 311 if (parser.left.parse(first, last, context, rcontext, l_attr) 312 && parser.right.parse(first, last, context, rcontext, r_attr)) 313 return true; 314 first = save; 315 return false; 316 } 317 318 template <typename Parser, typename Iterator, typename Context 319 , typename RContext, typename Attribute> parse_sequence_plain(Parser const & parser,Iterator & first,Iterator const & last,Context const & context,RContext & rcontext,Attribute & attr)320 bool parse_sequence_plain( 321 Parser const& parser, Iterator& first, Iterator const& last 322 , Context const& context, RContext& rcontext, Attribute& attr) 323 { 324 typedef typename Parser::left_type Left; 325 typedef typename Parser::right_type Right; 326 typedef typename traits::attribute_of<Left, Context>::type l_attr_type; 327 typedef typename traits::attribute_of<Right, Context>::type r_attr_type; 328 typedef traits::make_attribute<l_attr_type, Attribute> l_make_attribute; 329 typedef traits::make_attribute<r_attr_type, Attribute> r_make_attribute; 330 331 typename l_make_attribute::type l_attr = l_make_attribute::call(attr); 332 typename r_make_attribute::type r_attr = r_make_attribute::call(attr); 333 334 Iterator save = first; 335 if (parser.left.parse(first, last, context, rcontext, l_attr) 336 && parser.right.parse(first, last, context, rcontext, r_attr)) 337 return true; 338 first = save; 339 return false; 340 } 341 342 template <typename Parser, typename Iterator, typename Context 343 , typename RContext, typename Attribute> parse_sequence(Parser const & parser,Iterator & first,Iterator const & last,Context const & context,RContext & rcontext,Attribute & attr,traits::plain_attribute)344 bool parse_sequence( 345 Parser const& parser, Iterator& first, Iterator const& last 346 , Context const& context, RContext& rcontext, Attribute& attr 347 , traits::plain_attribute) 348 { 349 return parse_sequence_plain(parser, first, last, context, rcontext, attr); 350 } 351 352 template <typename Parser, typename Iterator, typename Context 353 , typename RContext, typename Attribute> parse_sequence(Parser const & parser,Iterator & first,Iterator const & last,Context const & context,RContext & rcontext,Attribute & attr,traits::variant_attribute)354 bool parse_sequence( 355 Parser const& parser, Iterator& first, Iterator const& last 356 , Context const& context, RContext& rcontext, Attribute& attr 357 , traits::variant_attribute) 358 { 359 return parse_sequence_plain(parser, first, last, context, rcontext, attr); 360 } 361 362 template <typename Left, typename Right, typename Iterator 363 , typename Context, typename RContext, typename Attribute> 364 bool parse_sequence( 365 Left const& left, Right const& right 366 , Iterator& first, Iterator const& last 367 , Context const& context, RContext& rcontext, Attribute& attr 368 , traits::container_attribute); 369 370 template <typename Parser, typename Iterator, typename Context 371 , typename RContext, typename Attribute> parse_sequence(Parser const & parser,Iterator & first,Iterator const & last,Context const & context,RContext & rcontext,Attribute & attr,traits::container_attribute)372 bool parse_sequence( 373 Parser const& parser , Iterator& first, Iterator const& last 374 , Context const& context, RContext& rcontext, Attribute& attr 375 , traits::container_attribute) 376 { 377 Iterator save = first; 378 if (parse_into_container(parser.left, first, last, context, rcontext, attr) 379 && parse_into_container(parser.right, first, last, context, rcontext, attr)) 380 return true; 381 first = save; 382 return false; 383 } 384 385 template <typename Parser, typename Iterator, typename Context 386 , typename RContext, typename Attribute> parse_sequence_assoc(Parser const & parser,Iterator & first,Iterator const & last,Context const & context,RContext & rcontext,Attribute & attr,mpl::false_)387 bool parse_sequence_assoc( 388 Parser const& parser , Iterator& first, Iterator const& last 389 , Context const& context, RContext& rcontext, Attribute& attr, mpl::false_ /*should_split*/) 390 { 391 return parse_into_container(parser, first, last, context, rcontext, attr); 392 } 393 394 template <typename Parser, typename Iterator, typename Context 395 , typename RContext, typename Attribute> parse_sequence_assoc(Parser const & parser,Iterator & first,Iterator const & last,Context const & context,RContext & rcontext,Attribute & attr,mpl::true_)396 bool parse_sequence_assoc( 397 Parser const& parser , Iterator& first, Iterator const& last 398 , Context const& context, RContext& rcontext, Attribute& attr, mpl::true_ /*should_split*/) 399 { 400 Iterator save = first; 401 if (parser.left.parse( first, last, context, rcontext, attr) 402 && parser.right.parse(first, last, context, rcontext, attr)) 403 return true; 404 first = save; 405 return false; 406 } 407 408 template <typename Parser, typename Iterator, typename Context 409 , typename RContext, typename Attribute> parse_sequence(Parser const & parser,Iterator & first,Iterator const & last,Context const & context,RContext & rcontext,Attribute & attr,traits::associative_attribute)410 bool parse_sequence( 411 Parser const& parser, Iterator& first, Iterator const& last 412 , Context const& context, RContext& rcontext, Attribute& attr 413 , traits::associative_attribute) 414 { 415 // we can come here in 2 cases: 416 // - when sequence is key >> value and therefore must 417 // be parsed with tuple synthesized attribute and then 418 // that tuple is used to save into associative attribute provided here. 419 // Example: key >> value; 420 // 421 // - when either this->left or this->right provides full key-value 422 // pair (like in case 1) and another one provides nothing. 423 // Example: eps >> rule<class x; fusion::map<...> > 424 // 425 // first case must be parsed as whole, and second one should 426 // be parsed separately for left and right. 427 428 typedef typename traits::attribute_of< 429 decltype(parser.left), Context>::type l_attr_type; 430 typedef typename traits::attribute_of< 431 decltype(parser.right), Context>::type r_attr_type; 432 433 typedef typename 434 mpl::or_< 435 is_same<l_attr_type, unused_type> 436 , is_same<r_attr_type, unused_type> > 437 should_split; 438 439 return parse_sequence_assoc(parser, first, last, context, rcontext, attr 440 , should_split()); 441 } 442 443 template <typename Left, typename Right, typename Context, typename RContext> 444 struct parse_into_container_impl<sequence<Left, Right>, Context, RContext> 445 { 446 typedef sequence<Left, Right> parser_type; 447 448 template <typename Iterator, typename Attribute> callboost::spirit::x3::detail::parse_into_container_impl449 static bool call( 450 parser_type const& parser 451 , Iterator& first, Iterator const& last 452 , Context const& context, RContext& rcontext, Attribute& attr, mpl::false_) 453 { 454 // inform user what went wrong if we jumped here in attempt to 455 // parse incompatible sequence into fusion::map 456 static_assert(!is_same< typename traits::attribute_category<Attribute>::type, 457 traits::associative_attribute>::value, 458 "To parse directly into fusion::map sequence must produce tuple attribute " 459 "where type of first element is existing key in fusion::map and second element " 460 "is value to be stored under that key"); 461 462 Attribute attr_; 463 if (!parse_sequence(parser 464 , first, last, context, rcontext, attr_, traits::container_attribute())) 465 { 466 return false; 467 } 468 traits::append(attr, traits::begin(attr_), traits::end(attr_)); 469 return true; 470 } 471 472 template <typename Iterator, typename Attribute> callboost::spirit::x3::detail::parse_into_container_impl473 static bool call( 474 parser_type const& parser 475 , Iterator& first, Iterator const& last 476 , Context const& context, RContext& rcontext, Attribute& attr, mpl::true_) 477 { 478 return parse_into_container_base_impl<parser_type>::call( 479 parser, first, last, context, rcontext, attr); 480 } 481 482 template <typename Iterator, typename Attribute> callboost::spirit::x3::detail::parse_into_container_impl483 static bool call( 484 parser_type const& parser 485 , Iterator& first, Iterator const& last 486 , Context const& context, RContext& rcontext, Attribute& attr) 487 { 488 typedef typename 489 traits::attribute_of<parser_type, Context>::type 490 attribute_type; 491 492 typedef typename 493 traits::container_value<Attribute>::type 494 value_type; 495 496 return call(parser, first, last, context, rcontext, attr 497 , typename traits::is_substitute<attribute_type, value_type>::type()); 498 } 499 }; 500 501 }}}} 502 503 #endif 504