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 26 #include <boost/mpl/if.hpp> 27 28 #include <boost/type_traits/add_reference.hpp> 29 #include <boost/type_traits/is_same.hpp> 30 31 #include <iterator> // for std::make_move_iterator 32 33 namespace boost { namespace spirit { namespace x3 34 { 35 template <typename Left, typename Right> 36 struct sequence; 37 }}} 38 39 namespace boost { namespace spirit { namespace x3 { namespace detail 40 { 41 template <typename Parser, typename Context, typename Enable = void> 42 struct sequence_size 43 { 44 static int const value = traits::has_attribute<Parser, Context>::value; 45 }; 46 47 template <typename Parser, typename Context> 48 struct sequence_size_subject 49 : sequence_size<typename Parser::subject_type, Context> {}; 50 51 template <typename Parser, typename Context> 52 struct sequence_size<Parser, Context 53 , typename enable_if_c<(Parser::is_pass_through_unary)>::type> 54 : sequence_size_subject<Parser, Context> {}; 55 56 template <typename L, typename R, typename Context> 57 struct sequence_size<sequence<L, R>, Context> 58 { 59 static int const value = 60 sequence_size<L, Context>::value + 61 sequence_size<R, Context>::value; 62 }; 63 64 struct pass_sequence_attribute_unused 65 { 66 typedef unused_type type; 67 68 template <typename T> 69 static unused_type callboost::spirit::x3::detail::pass_sequence_attribute_unused70 call(T&) 71 { 72 return unused_type(); 73 } 74 }; 75 76 template <typename Attribute> 77 struct pass_sequence_attribute_size_one_view 78 { 79 typedef typename fusion::result_of::deref< 80 typename fusion::result_of::begin<Attribute>::type 81 >::type type; 82 callboost::spirit::x3::detail::pass_sequence_attribute_size_one_view83 static type call(Attribute& attribute) 84 { 85 return fusion::deref(fusion::begin(attribute)); 86 } 87 }; 88 89 template <typename Attribute> 90 struct pass_through_sequence_attribute 91 { 92 typedef Attribute& type; 93 94 template <typename Attribute_> 95 static Attribute_& callboost::spirit::x3::detail::pass_through_sequence_attribute96 call(Attribute_& attribute) 97 { 98 return attribute; 99 } 100 }; 101 102 template <typename Parser, typename Attribute, typename Enable = void> 103 struct pass_sequence_attribute : 104 mpl::if_< 105 traits::is_size_one_view<Attribute> 106 , pass_sequence_attribute_size_one_view<Attribute> 107 , pass_through_sequence_attribute<Attribute>>::type {}; 108 109 template <typename L, typename R, typename Attribute> 110 struct pass_sequence_attribute<sequence<L, R>, Attribute> 111 : pass_through_sequence_attribute<Attribute> {}; 112 113 template <typename Parser, typename Attribute> 114 struct pass_sequence_attribute_subject : 115 pass_sequence_attribute<typename Parser::subject_type, Attribute> {}; 116 117 template <typename Parser, typename Attribute> 118 struct pass_sequence_attribute<Parser, Attribute 119 , typename enable_if_c<(Parser::is_pass_through_unary)>::type> 120 : pass_sequence_attribute_subject<Parser, Attribute> {}; 121 122 template <typename L, typename R, typename Attribute, typename Context 123 , typename Enable = void> 124 struct partition_attribute 125 { 126 using attr_category = typename traits::attribute_category<Attribute>::type; 127 static_assert(is_same<traits::tuple_attribute, attr_category>::value, 128 "The parser expects tuple-like attribute type"); 129 130 static int const l_size = sequence_size<L, Context>::value; 131 static int const r_size = sequence_size<R, Context>::value; 132 133 static int constexpr actual_size = fusion::result_of::size<Attribute>::value; 134 static int constexpr expected_size = l_size + r_size; 135 136 // If you got an error here, then you are trying to pass 137 // a fusion sequence with the wrong number of elements 138 // as that expected by the (sequence) parser. 139 static_assert( 140 actual_size >= expected_size 141 , "Size of the passed attribute is less than expected." 142 ); 143 static_assert( 144 actual_size <= expected_size 145 , "Size of the passed attribute is bigger than expected." 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 Parser, typename Iterator, typename Context 234 , typename RContext, typename Attribute, typename AttributeCategory> parse_sequence(Parser const & parser,Iterator & first,Iterator const & last,Context const & context,RContext & rcontext,Attribute & attr,AttributeCategory)235 bool parse_sequence( 236 Parser const& parser, Iterator& first, Iterator const& last 237 , Context const& context, RContext& rcontext, Attribute& attr 238 , AttributeCategory) 239 { 240 using Left = typename Parser::left_type; 241 using Right = typename Parser::right_type; 242 using partition = partition_attribute<Left, Right, Attribute, Context>; 243 using l_pass = typename partition::l_pass; 244 using r_pass = typename partition::r_pass; 245 246 typename partition::l_part l_part = partition::left(attr); 247 typename partition::r_part r_part = partition::right(attr); 248 typename l_pass::type l_attr = l_pass::call(l_part); 249 typename r_pass::type r_attr = r_pass::call(r_part); 250 251 Iterator save = first; 252 if (parser.left.parse(first, last, context, rcontext, l_attr) 253 && parser.right.parse(first, last, context, rcontext, r_attr)) 254 return true; 255 first = save; 256 return false; 257 } 258 259 template <typename Parser, typename Context> 260 constexpr bool pass_sequence_container_attribute 261 = sequence_size<Parser, Context>::value > 1; 262 263 template <typename Parser, typename Iterator, typename Context 264 , typename RContext, typename Attribute> 265 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)266 parse_sequence_container( 267 Parser const& parser 268 , Iterator& first, Iterator const& last, Context const& context 269 , RContext& rcontext, Attribute& attr) 270 { 271 return parser.parse(first, last, context, rcontext, attr); 272 } 273 274 template <typename Parser, typename Iterator, typename Context 275 , typename RContext, typename Attribute> 276 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)277 parse_sequence_container( 278 Parser const& parser 279 , Iterator& first, Iterator const& last, Context const& context 280 , RContext& rcontext, Attribute& attr) 281 { 282 return parse_into_container(parser, first, last, context, rcontext, attr); 283 } 284 285 template <typename Parser, typename Iterator, typename Context 286 , typename RContext, typename Attribute> parse_sequence(Parser const & parser,Iterator & first,Iterator const & last,Context const & context,RContext & rcontext,Attribute & attr,traits::container_attribute)287 bool parse_sequence( 288 Parser const& parser , Iterator& first, Iterator const& last 289 , Context const& context, RContext& rcontext, Attribute& attr 290 , traits::container_attribute) 291 { 292 Iterator save = first; 293 if (parse_sequence_container(parser.left, first, last, context, rcontext, attr) 294 && parse_sequence_container(parser.right, first, last, context, rcontext, attr)) 295 return true; 296 first = save; 297 return false; 298 } 299 300 template <typename Parser, typename Iterator, typename Context 301 , typename RContext, typename Attribute> parse_sequence_assoc(Parser const & parser,Iterator & first,Iterator const & last,Context const & context,RContext & rcontext,Attribute & attr,mpl::false_)302 bool parse_sequence_assoc( 303 Parser const& parser , Iterator& first, Iterator const& last 304 , Context const& context, RContext& rcontext, Attribute& attr, mpl::false_ /*should_split*/) 305 { 306 return parse_into_container(parser, first, last, context, rcontext, attr); 307 } 308 309 template <typename Parser, typename Iterator, typename Context 310 , typename RContext, typename Attribute> parse_sequence_assoc(Parser const & parser,Iterator & first,Iterator const & last,Context const & context,RContext & rcontext,Attribute & attr,mpl::true_)311 bool parse_sequence_assoc( 312 Parser const& parser , Iterator& first, Iterator const& last 313 , Context const& context, RContext& rcontext, Attribute& attr, mpl::true_ /*should_split*/) 314 { 315 Iterator save = first; 316 if (parser.left.parse( first, last, context, rcontext, attr) 317 && parser.right.parse(first, last, context, rcontext, attr)) 318 return true; 319 first = save; 320 return false; 321 } 322 323 template <typename Parser, typename Iterator, typename Context 324 , typename RContext, typename Attribute> parse_sequence(Parser const & parser,Iterator & first,Iterator const & last,Context const & context,RContext & rcontext,Attribute & attr,traits::associative_attribute)325 bool parse_sequence( 326 Parser const& parser, Iterator& first, Iterator const& last 327 , Context const& context, RContext& rcontext, Attribute& attr 328 , traits::associative_attribute) 329 { 330 // we can come here in 2 cases: 331 // - when sequence is key >> value and therefore must 332 // be parsed with tuple synthesized attribute and then 333 // that tuple is used to save into associative attribute provided here. 334 // Example: key >> value; 335 // 336 // - when either this->left or this->right provides full key-value 337 // pair (like in case 1) and another one provides nothing. 338 // Example: eps >> rule<class x; fusion::map<...> > 339 // 340 // first case must be parsed as whole, and second one should 341 // be parsed separately for left and right. 342 343 typedef typename traits::attribute_of< 344 decltype(parser.left), Context>::type l_attr_type; 345 typedef typename traits::attribute_of< 346 decltype(parser.right), Context>::type r_attr_type; 347 348 typedef typename 349 mpl::or_< 350 is_same<l_attr_type, unused_type> 351 , is_same<r_attr_type, unused_type> > 352 should_split; 353 354 return parse_sequence_assoc(parser, first, last, context, rcontext, attr 355 , should_split()); 356 } 357 358 template <typename Left, typename Right, typename Context, typename RContext> 359 struct parse_into_container_impl<sequence<Left, Right>, Context, RContext> 360 { 361 typedef sequence<Left, Right> parser_type; 362 363 template <typename Iterator, typename Attribute> callboost::spirit::x3::detail::parse_into_container_impl364 static bool call( 365 parser_type const& parser 366 , Iterator& first, Iterator const& last 367 , Context const& context, RContext& rcontext, Attribute& attr, mpl::false_) 368 { 369 // inform user what went wrong if we jumped here in attempt to 370 // parse incompatible sequence into fusion::map 371 static_assert(!is_same< typename traits::attribute_category<Attribute>::type, 372 traits::associative_attribute>::value, 373 "To parse directly into fusion::map sequence must produce tuple attribute " 374 "where type of first element is existing key in fusion::map and second element " 375 "is value to be stored under that key"); 376 377 Attribute attr_{}; 378 if (!parse_sequence(parser 379 , first, last, context, rcontext, attr_, traits::container_attribute())) 380 { 381 return false; 382 } 383 traits::append(attr, std::make_move_iterator(traits::begin(attr_)), 384 std::make_move_iterator(traits::end(attr_))); 385 return true; 386 } 387 388 template <typename Iterator, typename Attribute> callboost::spirit::x3::detail::parse_into_container_impl389 static bool call( 390 parser_type const& parser 391 , Iterator& first, Iterator const& last 392 , Context const& context, RContext& rcontext, Attribute& attr, mpl::true_) 393 { 394 return parse_into_container_base_impl<parser_type>::call( 395 parser, first, last, context, rcontext, attr); 396 } 397 398 template <typename Iterator, typename Attribute> callboost::spirit::x3::detail::parse_into_container_impl399 static bool call( 400 parser_type const& parser 401 , Iterator& first, Iterator const& last 402 , Context const& context, RContext& rcontext, Attribute& attr) 403 { 404 typedef typename 405 traits::attribute_of<parser_type, Context>::type 406 attribute_type; 407 408 typedef typename 409 traits::container_value<Attribute>::type 410 value_type; 411 412 return call(parser, first, last, context, rcontext, attr 413 , typename traits::is_substitute<attribute_type, value_type>::type()); 414 } 415 }; 416 417 }}}} 418 419 #endif 420