EVOLUTION-MANAGER
Edit File: sequence.hpp
/*============================================================================= Copyright (c) 2001-2014 Joel de Guzman Distributed under the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) =============================================================================*/ #if !defined(BOOST_SPIRIT_X3_SEQUENCE_DETAIL_JAN_06_2013_1015AM) #define BOOST_SPIRIT_X3_SEQUENCE_DETAIL_JAN_06_2013_1015AM #include <boost/spirit/home/x3/support/traits/attribute_of.hpp> #include <boost/spirit/home/x3/support/traits/attribute_category.hpp> #include <boost/spirit/home/x3/support/traits/has_attribute.hpp> #include <boost/spirit/home/x3/support/traits/is_substitute.hpp> #include <boost/spirit/home/x3/support/traits/container_traits.hpp> #include <boost/spirit/home/x3/support/traits/tuple_traits.hpp> #include <boost/spirit/home/x3/core/detail/parse_into_container.hpp> #include <boost/fusion/include/begin.hpp> #include <boost/fusion/include/end.hpp> #include <boost/fusion/include/advance.hpp> #include <boost/fusion/include/deref.hpp> #include <boost/fusion/include/empty.hpp> #include <boost/fusion/include/front.hpp> #include <boost/fusion/include/iterator_range.hpp> #include <boost/fusion/include/as_deque.hpp> #include <boost/fusion/include/mpl.hpp> #include <boost/mpl/copy_if.hpp> #include <boost/mpl/not.hpp> #include <boost/mpl/if.hpp> #include <boost/mpl/insert_range.hpp> #include <boost/mpl/eval_if.hpp> #include <boost/mpl/vector.hpp> #include <boost/mpl/identity.hpp> #include <boost/type_traits/add_reference.hpp> #include <boost/type_traits/is_same.hpp> #include <iterator> // for std::make_move_iterator namespace boost { namespace spirit { namespace x3 { template <typename Left, typename Right> struct sequence; }}} namespace boost { namespace spirit { namespace x3 { namespace detail { template <typename Parser, typename Context, typename Enable = void> struct sequence_size { static int const value = traits::has_attribute<Parser, Context>::value; }; template <typename Parser, typename Context> struct sequence_size_subject : sequence_size<typename Parser::subject_type, Context> {}; template <typename Parser, typename Context> struct sequence_size<Parser, Context , typename enable_if_c<(Parser::is_pass_through_unary)>::type> : sequence_size_subject<Parser, Context> {}; template <typename L, typename R, typename Context> struct sequence_size<sequence<L, R>, Context> { static int const value = sequence_size<L, Context>::value + sequence_size<R, Context>::value; }; struct pass_sequence_attribute_unused { typedef unused_type type; template <typename T> static unused_type call(T&) { return unused_type(); } }; template <typename Attribute> struct pass_sequence_attribute_size_one_view { typedef typename fusion::result_of::deref< typename fusion::result_of::begin<Attribute>::type >::type type; static type call(Attribute& attr) { return fusion::deref(fusion::begin(attr)); } }; template <typename Attribute> struct pass_through_sequence_attribute { typedef Attribute& type; template <typename Attribute_> static Attribute_& call(Attribute_& attr) { return attr; } }; template <typename Parser, typename Attribute, typename Enable = void> struct pass_sequence_attribute : mpl::if_< traits::is_size_one_view<Attribute> , pass_sequence_attribute_size_one_view<Attribute> , pass_through_sequence_attribute<Attribute>>::type {}; template <typename L, typename R, typename Attribute> struct pass_sequence_attribute<sequence<L, R>, Attribute> : pass_through_sequence_attribute<Attribute> {}; template <typename Parser, typename Attribute> struct pass_sequence_attribute_subject : pass_sequence_attribute<typename Parser::subject_type, Attribute> {}; template <typename Parser, typename Attribute> struct pass_sequence_attribute<Parser, Attribute , typename enable_if_c<(Parser::is_pass_through_unary)>::type> : pass_sequence_attribute_subject<Parser, Attribute> {}; template <typename L, typename R, typename Attribute, typename Context , typename Enable = void> struct partition_attribute { using attr_category = typename traits::attribute_category<Attribute>::type; static_assert(is_same<traits::tuple_attribute, attr_category>::value, "The parser expects tuple-like attribute type"); static int const l_size = sequence_size<L, Context>::value; static int const r_size = sequence_size<R, Context>::value; static int constexpr actual_size = fusion::result_of::size<Attribute>::value; static int constexpr expected_size = l_size + r_size; // If you got an error here, then you are trying to pass // a fusion sequence with the wrong number of elements // as that expected by the (sequence) parser. static_assert( actual_size >= expected_size , "Size of the passed attribute is less than expected." ); static_assert( actual_size <= expected_size , "Size of the passed attribute is bigger than expected." ); typedef typename fusion::result_of::begin<Attribute>::type l_begin; typedef typename fusion::result_of::advance_c<l_begin, l_size>::type l_end; typedef typename fusion::result_of::end<Attribute>::type r_end; typedef fusion::iterator_range<l_begin, l_end> l_part; typedef fusion::iterator_range<l_end, r_end> r_part; typedef pass_sequence_attribute<L, l_part> l_pass; typedef pass_sequence_attribute<R, r_part> r_pass; static l_part left(Attribute& s) { auto i = fusion::begin(s); return l_part(i, fusion::advance_c<l_size>(i)); } static r_part right(Attribute& s) { return r_part( fusion::advance_c<l_size>(fusion::begin(s)) , fusion::end(s)); } }; template <typename L, typename R, typename Attribute, typename Context> struct partition_attribute<L, R, Attribute, Context, typename enable_if_c<(!traits::has_attribute<L, Context>::value && traits::has_attribute<R, Context>::value)>::type> { typedef unused_type l_part; typedef Attribute& r_part; typedef pass_sequence_attribute_unused l_pass; typedef pass_sequence_attribute<R, Attribute> r_pass; static unused_type left(Attribute&) { return unused; } static Attribute& right(Attribute& s) { return s; } }; template <typename L, typename R, typename Attribute, typename Context> struct partition_attribute<L, R, Attribute, Context, typename enable_if_c<(traits::has_attribute<L, Context>::value && !traits::has_attribute<R, Context>::value)>::type> { typedef Attribute& l_part; typedef unused_type r_part; typedef pass_sequence_attribute<L, Attribute> l_pass; typedef pass_sequence_attribute_unused r_pass; static Attribute& left(Attribute& s) { return s; } static unused_type right(Attribute&) { return unused; } }; template <typename L, typename R, typename Attribute, typename Context> struct partition_attribute<L, R, Attribute, Context, typename enable_if_c<(!traits::has_attribute<L, Context>::value && !traits::has_attribute<R, Context>::value)>::type> { typedef unused_type l_part; typedef unused_type r_part; typedef pass_sequence_attribute_unused l_pass; typedef pass_sequence_attribute_unused r_pass; static unused_type left(Attribute&) { return unused; } static unused_type right(Attribute&) { return unused; } }; template <typename L, typename R, typename C> struct get_sequence_types { typedef mpl::vector< typename traits::attribute_of<L, C>::type , typename traits::attribute_of<R, C>::type > type; }; template <typename LL, typename LR, typename R, typename C> struct get_sequence_types<sequence<LL, LR>, R, C> : mpl::push_back< typename get_sequence_types<LL, LR, C>::type , typename traits::attribute_of<R, C>::type> {}; template <typename L, typename RL, typename RR, typename C> struct get_sequence_types<L, sequence<RL, RR>, C> : mpl::push_front< typename get_sequence_types<RL, RR, C>::type , typename traits::attribute_of<L, C>::type> {}; template <typename LL, typename LR, typename RL, typename RR, typename C> struct get_sequence_types<sequence<LL, LR>, sequence<RL, RR>, C> { typedef typename get_sequence_types<LL, LR, C>::type left; typedef typename get_sequence_types<RL, RR, C>::type right; typedef typename mpl::insert_range<left, typename mpl::end<left>::type, right>::type type; }; template <typename L, typename R, typename C> struct attribute_of_sequence { // Get all sequence attribute types typedef typename get_sequence_types<L, R, C>::type all_types; // Filter all unused_types typedef typename mpl::copy_if< all_types , mpl::not_<is_same<mpl::_1, unused_type>> , mpl::back_inserter<mpl::vector<>> >::type filtered_types; // Build a fusion::deque if filtered_types is not empty, // else just return unused_type typedef typename mpl::eval_if< mpl::empty<filtered_types> , mpl::identity<unused_type> , mpl::if_<mpl::equal_to<mpl::size<filtered_types>, mpl::int_<1> >, typename mpl::front<filtered_types>::type , typename fusion::result_of::as_deque<filtered_types>::type > >::type type; }; template <typename Parser, typename Iterator, typename Context , typename RContext, typename Attribute, typename AttributeCategory> bool parse_sequence( Parser const& parser, Iterator& first, Iterator const& last , Context const& context, RContext& rcontext, Attribute& attr , AttributeCategory) { using Left = typename Parser::left_type; using Right = typename Parser::right_type; using partition = partition_attribute<Left, Right, Attribute, Context>; using l_pass = typename partition::l_pass; using r_pass = typename partition::r_pass; typename partition::l_part l_part = partition::left(attr); typename partition::r_part r_part = partition::right(attr); typename l_pass::type l_attr = l_pass::call(l_part); typename r_pass::type r_attr = r_pass::call(r_part); Iterator save = first; if (parser.left.parse(first, last, context, rcontext, l_attr) && parser.right.parse(first, last, context, rcontext, r_attr)) return true; first = save; return false; } template <typename Parser, typename Context> constexpr bool pass_sequence_container_attribute = sequence_size<Parser, Context>::value > 1; template <typename Parser, typename Iterator, typename Context , typename RContext, typename Attribute> 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) { return parser.parse(first, last, context, rcontext, attr); } template <typename Parser, typename Iterator, typename Context , typename RContext, typename Attribute> 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) { return parse_into_container(parser, first, last, context, rcontext, attr); } template <typename Parser, typename Iterator, typename Context , typename RContext, typename Attribute> bool parse_sequence( Parser const& parser , Iterator& first, Iterator const& last , Context const& context, RContext& rcontext, Attribute& attr , traits::container_attribute) { Iterator save = first; if (parse_sequence_container(parser.left, first, last, context, rcontext, attr) && parse_sequence_container(parser.right, first, last, context, rcontext, attr)) return true; first = save; return false; } template <typename Parser, typename Iterator, typename Context , typename RContext, typename Attribute> bool parse_sequence_assoc( Parser const& parser , Iterator& first, Iterator const& last , Context const& context, RContext& rcontext, Attribute& attr, mpl::false_ /*should_split*/) { return parse_into_container(parser, first, last, context, rcontext, attr); } template <typename Parser, typename Iterator, typename Context , typename RContext, typename Attribute> bool parse_sequence_assoc( Parser const& parser , Iterator& first, Iterator const& last , Context const& context, RContext& rcontext, Attribute& attr, mpl::true_ /*should_split*/) { Iterator save = first; if (parser.left.parse( first, last, context, rcontext, attr) && parser.right.parse(first, last, context, rcontext, attr)) return true; first = save; return false; } template <typename Parser, typename Iterator, typename Context , typename RContext, typename Attribute> bool parse_sequence( Parser const& parser, Iterator& first, Iterator const& last , Context const& context, RContext& rcontext, Attribute& attr , traits::associative_attribute) { // we can come here in 2 cases: // - when sequence is key >> value and therefore must // be parsed with tuple synthesized attribute and then // that tuple is used to save into associative attribute provided here. // Example: key >> value; // // - when either this->left or this->right provides full key-value // pair (like in case 1) and another one provides nothing. // Example: eps >> rule<class x; fusion::map<...> > // // first case must be parsed as whole, and second one should // be parsed separately for left and right. typedef typename traits::attribute_of< decltype(parser.left), Context>::type l_attr_type; typedef typename traits::attribute_of< decltype(parser.right), Context>::type r_attr_type; typedef typename mpl::or_< is_same<l_attr_type, unused_type> , is_same<r_attr_type, unused_type> > should_split; return parse_sequence_assoc(parser, first, last, context, rcontext, attr , should_split()); } template <typename Left, typename Right, typename Context, typename RContext> struct parse_into_container_impl<sequence<Left, Right>, Context, RContext> { typedef sequence<Left, Right> parser_type; template <typename Iterator, typename Attribute> static bool call( parser_type const& parser , Iterator& first, Iterator const& last , Context const& context, RContext& rcontext, Attribute& attr, mpl::false_) { // inform user what went wrong if we jumped here in attempt to // parse incompatible sequence into fusion::map static_assert(!is_same< typename traits::attribute_category<Attribute>::type, traits::associative_attribute>::value, "To parse directly into fusion::map sequence must produce tuple attribute " "where type of first element is existing key in fusion::map and second element " "is value to be stored under that key"); Attribute attr_; if (!parse_sequence(parser , first, last, context, rcontext, attr_, traits::container_attribute())) { return false; } traits::append(attr, std::make_move_iterator(traits::begin(attr_)), std::make_move_iterator(traits::end(attr_))); return true; } template <typename Iterator, typename Attribute> static bool call( parser_type const& parser , Iterator& first, Iterator const& last , Context const& context, RContext& rcontext, Attribute& attr, mpl::true_) { return parse_into_container_base_impl<parser_type>::call( parser, first, last, context, rcontext, attr); } template <typename Iterator, typename Attribute> static bool call( parser_type const& parser , Iterator& first, Iterator const& last , Context const& context, RContext& rcontext, Attribute& attr) { typedef typename traits::attribute_of<parser_type, Context>::type attribute_type; typedef typename traits::container_value<Attribute>::type value_type; return call(parser, first, last, context, rcontext, attr , typename traits::is_substitute<attribute_type, value_type>::type()); } }; }}}} #endif