| /*============================================================================= |
| 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(SPIRIT_PARSE_INTO_CONTAINER_JAN_15_2013_0957PM) |
| #define SPIRIT_PARSE_INTO_CONTAINER_JAN_15_2013_0957PM |
| |
| #if defined(_MSC_VER) |
| #pragma once |
| #endif |
| |
| #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/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/front.hpp> |
| #include <boost/fusion/include/back.hpp> |
| #include <boost/variant/apply_visitor.hpp> |
| |
| 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> |
| 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( |
| Parser const& parser |
| , Iterator& first, Iterator const& last |
| , Context const& context, RContext& rcontext, Attribute& attr) |
| { |
| // synthesized attribute needs to be value initialized |
| typedef typename |
| traits::container_value<Attribute>::type |
| value_type; |
| value_type val = 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, val); |
| return true; |
| } |
| |
| // 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 Container, typename RContext, typename Context> |
| struct parser_attr_is_substitute_for_container_value |
| : traits::is_substitute< |
| typename traits::attribute_of<Parser, Context>::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::true_) |
| { |
| return parse_into_container_base_impl<Parser>::call( |
| parser, 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::false_) |
| { |
| 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) |
| { |
| return call(parser, first, last, context, rcontext, attr, |
| parser_attr_is_substitute_for_container_value< |
| Parser, Attribute, Context, RContext>()); |
| } |
| }; |
| |
| 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 |