/*============================================================================= 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_ALTERNATIVE_DETAIL_JAN_07_2013_1245PM) #define SPIRIT_ALTERNATIVE_DETAIL_JAN_07_2013_1245PM #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace boost { namespace spirit { namespace x3 { template struct alternative; }}} namespace boost { namespace spirit { namespace x3 { namespace detail { struct pass_variant_unused { typedef unused_type type; template static unused_type call(T&) { return unused_type(); } }; template struct pass_variant_used { typedef Attribute& type; static Attribute& call(Attribute& v) { return v; } }; template <> struct pass_variant_used : pass_variant_unused {}; template struct pass_parser_attribute { typedef typename traits::attribute_of::type attribute_type; typedef typename traits::variant_find_substitute::type substitute_type; typedef typename mpl::if_< is_same , Attribute& , substitute_type >::type type; template static Attribute_& call(Attribute_& attr, mpl::true_) { return attr; } template static type call(Attribute_&, mpl::false_) { return type(); } template static type call(Attribute_& attr) { return call(attr, is_same::type>()); } }; // Pass non-variant attributes as-is template struct pass_non_variant_attribute { typedef Attribute& type; static Attribute& call(Attribute& attr) { return attr; } }; // Unwrap single element sequences template struct pass_non_variant_attribute>::type> { typedef typename remove_reference< typename fusion::result_of::front::type>::type attr_type; typedef pass_parser_attribute pass; typedef typename pass::type type; template static type call(Attribute_& attr) { return pass::call(fusion::front(attr)); } }; template struct pass_parser_attribute::value)>::type> : pass_non_variant_attribute {}; template struct pass_parser_attribute : pass_variant_unused {}; template struct pass_variant_attribute : mpl::if_c::value , pass_parser_attribute , pass_variant_unused>::type { typedef typename mpl::false_ is_alternative; }; template struct pass_variant_attribute, Attribute, Context> : mpl::if_c, Context>::value , pass_variant_used , pass_variant_unused>::type { typedef typename mpl::true_ is_alternative; }; template struct get_alternative_types { typedef mpl::vector< typename traits::attribute_of::type , typename traits::attribute_of::type > type; }; template struct get_alternative_types, R, C> : mpl::push_back< typename get_alternative_types::type , typename traits::attribute_of::type> {}; template struct get_alternative_types, C> : mpl::push_front< typename get_alternative_types::type , typename traits::attribute_of::type> {}; template struct get_alternative_types, alternative, C> { typedef typename get_alternative_types::type left; typedef typename get_alternative_types::type right; typedef typename mpl::insert_range::type, right>::type type; }; template struct attribute_of_alternative { // Get all alternative attribute types typedef typename get_alternative_types::type all_types; // Filter all unused_types typedef typename mpl::copy_if< all_types , mpl::not_> , mpl::back_inserter> >::type filtered_types; // Build a variant if filtered_types is not empty, // else just return unused_type typedef typename mpl::eval_if< mpl::empty , mpl::identity , make_variant_over >::type type; }; template struct move_if_not_alternative { template static void call(T1& attr_, T2& attr) {} }; template <> struct move_if_not_alternative { template static void call(T1& attr_, T2& attr) { traits::move_to(attr_, attr); } }; template bool parse_alternative(Parser const& p, Iterator& first, Iterator const& last , Context const& context, RContext& rcontext, Attribute& attr) { typedef detail::pass_variant_attribute pass; typename pass::type attr_ = pass::call(attr); if (p.parse(first, last, context, rcontext, attr_)) { move_if_not_alternative::call(attr_, attr); return true; } return false; } template struct parse_into_container_impl, Context, RContext> { typedef alternative parser_type; template static bool call( parser_type const& parser , Iterator& first, Iterator const& last , Context const& context, RContext& rcontext, Attribute& attr, mpl::true_) { return parse_alternative(parser, first, last, context, rcontext, attr); } template static bool call( parser_type 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_type const& parser , Iterator& first, Iterator const& last , Context const& context, RContext& rcontext, Attribute& attr) { typedef typename traits::attribute_of::type attribute_type; return call(parser, first, last, context, rcontext, attr , traits::variant_has_substitute()); } }; }}}} #endif