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