123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312 |
- /*=============================================================================
- 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_PARSE_INTO_CONTAINER_JAN_15_2013_0957PM)
- #define BOOST_SPIRIT_X3_PARSE_INTO_CONTAINER_JAN_15_2013_0957PM
- #include <type_traits>
- #include <boost/spirit/home/x3/support/traits/container_traits.hpp>
- #include <boost/spirit/home/x3/support/traits/value_traits.hpp>
- #include <boost/spirit/home/x3/support/traits/attribute_of.hpp>
- #include <boost/spirit/home/x3/support/traits/pseudo_attribute.hpp>
- #include <boost/spirit/home/x3/support/traits/handles_container.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/move_to.hpp>
- #include <boost/mpl/and.hpp>
- #include <boost/fusion/include/at_key.hpp>
- #include <boost/fusion/include/front.hpp>
- #include <boost/fusion/include/back.hpp>
- #include <boost/variant/apply_visitor.hpp>
- #include <iterator> // for std::make_move_iterator
- namespace boost { namespace spirit { namespace x3 { namespace detail
- {
- template <typename Attribute, typename Value>
- struct saver_visitor;
- // save to associative fusion container where Key is simple type
- template <typename Key, typename Enable = void>
- struct save_to_assoc_attr
- {
- template <typename Value, typename Attribute>
- static void call(const Key, Value& value, Attribute& attr)
- {
- traits::move_to(value, fusion::at_key<Key>(attr));
- }
- };
- // save to associative fusion container where Key
- // is variant over possible keys
- template <typename ...T>
- struct save_to_assoc_attr<variant<T...> >
- {
- typedef variant<T...> variant_t;
- template <typename Value, typename Attribute>
- static void call(const variant_t key, Value& value, Attribute& attr)
- {
- apply_visitor(saver_visitor<Attribute, Value>(attr, value), key);
- }
- };
- template <typename Attribute, typename Value>
- struct saver_visitor : boost::static_visitor<void>
- {
- saver_visitor(Attribute& attr, Value& value)
- : attr(attr), value(value) {};
- Attribute& attr;
- Value& value;
- template <typename Key>
- void operator()(Key) const
- {
- save_to_assoc_attr<Key>::call(Key(), value,attr);
- }
- };
- template <typename Parser, typename Container, typename Context>
- struct parser_accepts_container
- : traits::is_substitute<
- typename traits::attribute_of<Parser, Context>::type
- , Container
- >
- {};
- template <typename Parser>
- struct parse_into_container_base_impl
- {
- private:
- // Parser has attribute (synthesize; Attribute is a container)
- template <typename Iterator, typename Context
- , typename RContext, typename Attribute>
- static bool call_synthesize_x(
- Parser const& parser
- , Iterator& first, Iterator const& last
- , Context const& context, RContext& rcontext, Attribute& attr, mpl::false_)
- {
- // synthesized attribute needs to be value initialized
- using value_type = typename traits::container_value<Attribute>::type;
- using pseudo = traits::pseudo_attribute<Context, value_type, Iterator>;
- typename pseudo::type val = pseudo::call(
- first, last, traits::value_initialize<value_type>::call());
- if (!parser.parse(first, last, context, rcontext, val))
- return false;
- // push the parsed value into our attribute
- traits::push_back(attr, static_cast<value_type&&>(val));
- return true;
- }
- // Parser has attribute (synthesize; Attribute is a container)
- template <typename Iterator, typename Context
- , typename RContext, typename Attribute>
- static bool call_synthesize_x(
- Parser const& parser
- , Iterator& first, Iterator const& last
- , Context const& context, RContext& rcontext, Attribute& attr, mpl::true_)
- {
- return parser.parse(first, last, context, rcontext, attr);
- }
- // Parser has attribute (synthesize; Attribute is a container)
- template <typename Iterator, typename Context
- , typename RContext, typename Attribute>
- static bool call_synthesize(
- Parser const& parser
- , Iterator& first, Iterator const& last
- , Context const& context, RContext& rcontext, Attribute& attr)
- {
- typedef
- parser_accepts_container<Parser, Attribute, Context>
- parser_accepts_container;
- return call_synthesize_x(parser, first, last, context, rcontext, attr
- , parser_accepts_container());
- }
- // Parser has attribute (synthesize; Attribute is a single element fusion sequence)
- template <typename Iterator, typename Context
- , typename RContext, typename Attribute>
- static bool call_synthesize_into_fusion_seq(Parser const& parser
- , Iterator& first, Iterator const& last, Context const& context
- , RContext& rcontext, Attribute& attr, mpl::false_ /* is_associative */)
- {
- static_assert(traits::has_size<Attribute, 1>::value,
- "Expecting a single element fusion sequence");
- return call_synthesize(parser, first, last, context, rcontext,
- fusion::front(attr));
- }
- // Parser has attribute (synthesize; Attribute is fusion map sequence)
- template <typename Iterator, typename Context, typename RContext, typename Attribute>
- static bool call_synthesize_into_fusion_seq(
- Parser const& parser
- , Iterator& first, Iterator const& last, Context const& context
- , RContext& rcontext, Attribute& attr, mpl::true_ /*is_associative*/)
- {
- using attribute_type = typename traits::attribute_of<Parser, Context>::type;
- static_assert(traits::has_size<attribute_type, 2>::value,
- "To parse directly into fusion map parser must produce 2 element attr");
- // use type of first element of attribute as key
- using key = typename std::remove_reference<
- typename fusion::result_of::front<attribute_type>::type>::type;
- attribute_type attr_;
- if (!parser.parse(first, last, context, rcontext, attr_))
- return false;
- save_to_assoc_attr<key>::call(fusion::front(attr_), fusion::back(attr_), attr);
- return true;
- }
- template <typename Iterator, typename Context, typename RContext, typename Attribute>
- static bool call_synthesize_dispatch_by_seq(Parser const& parser
- , Iterator& first, Iterator const& last, Context const& context
- , RContext& rcontext, Attribute& attr, mpl::true_ /*is_sequence*/)
- {
- return call_synthesize_into_fusion_seq(
- parser, first, last, context, rcontext, attr
- , fusion::traits::is_associative<Attribute>());
- }
- template <typename Iterator, typename Context, typename RContext, typename Attribute>
- static bool call_synthesize_dispatch_by_seq(Parser const& parser
- , Iterator& first, Iterator const& last, Context const& context
- , RContext& rcontext, Attribute& attr, mpl::false_ /*is_sequence*/)
- {
- return call_synthesize(parser, first, last, context, rcontext, attr);
- }
- // Parser has attribute (synthesize)
- template <typename Iterator, typename Context, typename RContext, typename Attribute>
- static bool call(Parser const& parser
- , Iterator& first, Iterator const& last, Context const& context
- , RContext& rcontext, Attribute& attr, mpl::true_)
- {
- return call_synthesize_dispatch_by_seq(parser, first, last, context, rcontext, attr
- , fusion::traits::is_sequence<Attribute>());
- }
- // Parser has no attribute (pass unused)
- template <typename Iterator, typename Context, typename RContext, typename Attribute>
- static bool call(
- Parser const& parser
- , Iterator& first, Iterator const& last, Context const& context
- , RContext& rcontext, Attribute& /* attr */, mpl::false_)
- {
- return parser.parse(first, last, context, rcontext, unused);
- }
- public:
- template <typename Iterator, typename Context, typename RContext, typename Attribute>
- static bool call(Parser const& parser
- , Iterator& first, Iterator const& last, Context const& context
- , RContext& rcontext, Attribute& attr)
- {
- return call(parser, first, last, context, rcontext, attr
- , mpl::bool_<traits::has_attribute<Parser, Context>::value>());
- }
- };
- template <typename Parser, typename Context, typename RContext, typename Enable = void>
- struct parse_into_container_impl : parse_into_container_base_impl<Parser> {};
- template <typename Parser, typename Iterator, typename Container, typename Context>
- struct parser_attr_is_substitute_for_container_value
- : traits::is_substitute<
- typename traits::pseudo_attribute<
- Context
- , typename traits::attribute_of<Parser, Context>::type
- , Iterator
- >::type
- , typename traits::container_value<Container>::type
- >
- {};
- template <typename Parser, typename Context, typename RContext>
- struct parse_into_container_impl<Parser, Context, RContext,
- typename enable_if<traits::handles_container<Parser, Context>>::type>
- {
- template <typename Iterator, typename Attribute>
- static bool call(
- Parser const& parser
- , Iterator& first, Iterator const& last
- , Context const& context, RContext& rcontext, Attribute& attr, mpl::false_)
- {
- return parse_into_container_base_impl<Parser>::call(
- parser, first, last, context, rcontext, attr);
- }
- template <typename Iterator>
- static bool call(
- Parser const& parser
- , Iterator& first, Iterator const& last
- , Context const& context, RContext& rcontext, unused_type attr, mpl::true_)
- {
- return parser.parse(first, last, context, rcontext, attr);
- }
- template <typename Iterator, typename Attribute>
- static bool call(
- Parser const& parser
- , Iterator& first, Iterator const& last
- , Context const& context, RContext& rcontext, Attribute& attr, mpl::true_)
- {
- if (traits::is_empty(attr))
- return parser.parse(first, last, context, rcontext, attr);
- Attribute rest;
- bool r = parser.parse(first, last, context, rcontext, rest);
- if (r)
- traits::append(attr, std::make_move_iterator(rest.begin()),
- std::make_move_iterator(rest.end()));
- return r;
- }
- template <typename Iterator, typename Attribute>
- static bool call(Parser const& parser
- , Iterator& first, Iterator const& last
- , Context const& context, RContext& rcontext, Attribute& attr)
- {
- typedef parser_accepts_container<
- Parser, Attribute, Context>
- parser_accepts_container;
- typedef parser_attr_is_substitute_for_container_value<
- Parser, Iterator, Attribute, Context>
- parser_attr_is_substitute_for_container_value;
- typedef mpl::or_<
- parser_accepts_container
- , mpl::not_<parser_attr_is_substitute_for_container_value>>
- pass_attibute_as_is;
- return call(parser, first, last, context, rcontext, attr,
- pass_attibute_as_is());
- }
- };
- template <typename Parser, typename Iterator, typename Context
- , typename RContext, typename Attribute>
- bool parse_into_container(
- Parser const& parser
- , Iterator& first, Iterator const& last, Context const& context
- , RContext& rcontext, Attribute& attr)
- {
- return parse_into_container_impl<Parser, Context, RContext>::call(
- parser, first, last, context, rcontext, attr);
- }
- }}}}
- #endif
|