/*============================================================================= 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 #include #include #include #include #include #include #include #include #include #include #include #include namespace boost { namespace spirit { namespace x3 { namespace detail { template struct saver_visitor; // save to associative fusion container where Key is simple type template struct save_to_assoc_attr { template static void call(const Key, Value& value, Attribute& attr) { traits::move_to(value, fusion::at_key(attr)); } }; /* $$$ clang reports: warning: class template partial specialization contains * a template parameter that can not be deduced; this partial specialization * will never be used $$$ * // save to associative fusion container where Key // is variant over possible keys template struct save_to_assoc_attr > { typedef variant variant_t; template static void call(const variant_t key, Value& value, Attribute& attr) { apply_visitor(saver_visitor(attr, value), key); } }; */ template struct saver_visitor : boost::static_visitor { saver_visitor(Attribute& attr, Value& value) : attr(attr), value(value) {}; Attribute& attr; Value& value; template void operator()(Key) const { save_to_assoc_attr::call(Key(), value,attr); } }; template struct parser_accepts_container : traits::is_substitute< typename traits::attribute_of::type , Container > {}; template struct parse_into_container_base_impl { private: // Parser has attribute (synthesize; Attribute is a container) template 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 typedef typename traits::container_value::type value_type; value_type val = traits::value_initialize::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 container) template 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 static bool call_synthesize( Parser const& parser , Iterator& first, Iterator const& last , Context const& context, RContext& rcontext, Attribute& attr) { typedef parser_accepts_container 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 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::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 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::type; static_assert(traits::has_size::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::type>::type; attribute_type attr_; if (!parser.parse(first, last, context, rcontext, attr_)) return false; save_to_assoc_attr::call(fusion::front(attr_), fusion::back(attr_), attr); return true; } template 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()); } template 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 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()); } // Parser has no attribute (pass unused) template 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 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_::value>()); } }; template struct parse_into_container_impl : parse_into_container_base_impl {}; template struct parser_attr_is_substitute_for_container_value : traits::is_substitute< typename traits::attribute_of::type , typename traits::container_value::type > {}; template struct parse_into_container_impl>::type> { template 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::call( parser, first, last, context, rcontext, attr); } template static bool call( Parser const& parser , Iterator& first, Iterator const& last , Context const& context, RContext& rcontext, Attribute& attr, mpl::true_) { if (attr.empty()) return parser.parse(first, last, context, rcontext, attr); Attribute rest; bool r = parser.parse(first, last, context, rcontext, rest); if (r) attr.insert(attr.end(), rest.begin(), rest.end()); return r; } template 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, Attribute, Context> parser_attr_is_substitute_for_container_value; typedef mpl::or_< parser_accepts_container , mpl::not_> pass_attibute_as_is; return call(parser, first, last, context, rcontext, attr, pass_attibute_as_is()); } }; template bool parse_into_container( Parser const& parser , Iterator& first, Iterator const& last, Context const& context , RContext& rcontext, Attribute& attr) { return parse_into_container_impl::call( parser, first, last, context, rcontext, attr); } }}}} #endif