123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419 |
- /*=============================================================================
- 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/mpl/if.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& attribute)
- {
- return fusion::deref(fusion::begin(attribute));
- }
- };
- template <typename Attribute>
- struct pass_through_sequence_attribute
- {
- typedef Attribute& type;
- template <typename Attribute_>
- static Attribute_&
- call(Attribute_& attribute)
- {
- return attribute;
- }
- };
- 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 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
|