1 /*============================================================================= 2 Copyright (c) 2001-2014 Joel de Guzman 3 4 Distributed under the Boost Software License, Version 1.0. (See accompanying 5 file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 6 =============================================================================*/ 7 #if !defined(SPIRIT_ALTERNATIVE_DETAIL_JAN_07_2013_1245PM) 8 #define SPIRIT_ALTERNATIVE_DETAIL_JAN_07_2013_1245PM 9 10 #include <boost/spirit/home/x3/support/traits/attribute_of.hpp> 11 #include <boost/spirit/home/x3/support/traits/is_variant.hpp> 12 #include <boost/spirit/home/x3/support/traits/tuple_traits.hpp> 13 #include <boost/spirit/home/x3/support/traits/move_to.hpp> 14 #include <boost/spirit/home/x3/support/traits/variant_has_substitute.hpp> 15 #include <boost/spirit/home/x3/support/traits/variant_find_substitute.hpp> 16 #include <boost/spirit/home/x3/core/detail/parse_into_container.hpp> 17 #include <boost/variant/variant.hpp> 18 19 #include <boost/mpl/copy_if.hpp> 20 #include <boost/mpl/not.hpp> 21 #include <boost/mpl/if.hpp> 22 #include <boost/mpl/insert_range.hpp> 23 #include <boost/mpl/eval_if.hpp> 24 #include <boost/mpl/vector.hpp> 25 26 #include <boost/fusion/include/front.hpp> 27 28 #include <boost/type_traits/is_same.hpp> 29 30 namespace boost { namespace spirit { namespace x3 31 { 32 template <typename Left, typename Right> 33 struct alternative; 34 }}} 35 36 namespace boost { namespace spirit { namespace x3 { namespace detail 37 { 38 struct pass_variant_unused 39 { 40 typedef unused_type type; 41 42 template <typename T> 43 static unused_type callboost::spirit::x3::detail::pass_variant_unused44 call(T&) 45 { 46 return unused_type(); 47 } 48 }; 49 50 template <typename Attribute> 51 struct pass_variant_used 52 { 53 typedef Attribute& type; 54 55 static Attribute& callboost::spirit::x3::detail::pass_variant_used56 call(Attribute& v) 57 { 58 return v; 59 } 60 }; 61 62 template <> 63 struct pass_variant_used<unused_type> : pass_variant_unused {}; 64 65 template <typename Parser, typename Attribute, typename Context 66 , typename Enable = void> 67 struct pass_parser_attribute 68 { 69 typedef typename 70 traits::attribute_of<Parser, Context>::type 71 attribute_type; 72 typedef typename 73 traits::variant_find_substitute<Attribute, attribute_type>::type 74 substitute_type; 75 76 typedef typename 77 mpl::if_< 78 is_same<Attribute, substitute_type> 79 , Attribute& 80 , substitute_type 81 >::type 82 type; 83 84 template <typename Attribute_> 85 static Attribute_& callboost::spirit::x3::detail::pass_parser_attribute86 call(Attribute_& attr, mpl::true_) 87 { 88 return attr; 89 } 90 91 template <typename Attribute_> 92 static type callboost::spirit::x3::detail::pass_parser_attribute93 call(Attribute_&, mpl::false_) 94 { 95 return type(); 96 } 97 98 template <typename Attribute_> 99 static type callboost::spirit::x3::detail::pass_parser_attribute100 call(Attribute_& attr) 101 { 102 return call(attr, is_same<Attribute_, typename remove_reference<type>::type>()); 103 } 104 }; 105 106 // Pass non-variant attributes as-is 107 template <typename Parser, typename Attribute, typename Context 108 , typename Enable = void> 109 struct pass_non_variant_attribute 110 { 111 typedef Attribute& type; 112 113 static Attribute& callboost::spirit::x3::detail::pass_non_variant_attribute114 call(Attribute& attr) 115 { 116 return attr; 117 } 118 }; 119 120 // Unwrap single element sequences 121 template <typename Parser, typename Attribute, typename Context> 122 struct pass_non_variant_attribute<Parser, Attribute, Context, 123 typename enable_if<traits::is_size_one_sequence<Attribute>>::type> 124 { 125 typedef typename remove_reference< 126 typename fusion::result_of::front<Attribute>::type>::type 127 attr_type; 128 129 typedef pass_parser_attribute<Parser, attr_type, Context> pass; 130 typedef typename pass::type type; 131 132 template <typename Attribute_> 133 static type callboost::spirit::x3::detail::pass_non_variant_attribute134 call(Attribute_& attr) 135 { 136 return pass::call(fusion::front(attr)); 137 } 138 }; 139 140 template <typename Parser, typename Attribute, typename Context> 141 struct pass_parser_attribute<Parser, Attribute, Context, 142 typename enable_if_c<(!traits::is_variant<Attribute>::value)>::type> 143 : pass_non_variant_attribute<Parser, Attribute, Context> 144 {}; 145 146 template <typename Parser, typename Context> 147 struct pass_parser_attribute<Parser, unused_type, Context> 148 : pass_variant_unused {}; 149 150 template <typename Parser, typename Attribute, typename Context> 151 struct pass_variant_attribute : 152 mpl::if_c<traits::has_attribute<Parser, Context>::value 153 , pass_parser_attribute<Parser, Attribute, Context> 154 , pass_variant_unused>::type 155 { 156 typedef typename mpl::false_ is_alternative; 157 }; 158 159 template <typename L, typename R, typename Attribute, typename Context> 160 struct pass_variant_attribute<alternative<L, R>, Attribute, Context> : 161 mpl::if_c<traits::has_attribute<alternative<L, R>, Context>::value 162 , pass_variant_used<Attribute> 163 , pass_variant_unused>::type 164 { 165 typedef typename mpl::true_ is_alternative; 166 }; 167 168 template <typename L, typename R, typename C> 169 struct get_alternative_types 170 { 171 typedef 172 mpl::vector< 173 typename traits::attribute_of<L, C>::type 174 , typename traits::attribute_of<R, C>::type 175 > 176 type; 177 }; 178 179 template <typename LL, typename LR, typename R, typename C> 180 struct get_alternative_types<alternative<LL, LR>, R, C> 181 : mpl::push_back< typename get_alternative_types<LL, LR, C>::type 182 , typename traits::attribute_of<R, C>::type> {}; 183 184 template <typename L, typename RL, typename RR, typename C> 185 struct get_alternative_types<L, alternative<RL, RR>, C> 186 : mpl::push_front< typename get_alternative_types<RL, RR, C>::type 187 , typename traits::attribute_of<L, C>::type> {}; 188 189 template <typename LL, typename LR, typename RL, typename RR, typename C> 190 struct get_alternative_types<alternative<LL, LR>, alternative<RL, RR>, C> 191 { 192 typedef typename get_alternative_types<LL, LR, C>::type left; 193 typedef typename get_alternative_types<RL, RR, C>::type right; 194 typedef typename 195 mpl::insert_range<left, typename mpl::end<left>::type, right>::type 196 type; 197 }; 198 199 template <typename L, typename R, typename C> 200 struct attribute_of_alternative 201 { 202 // Get all alternative attribute types 203 typedef typename get_alternative_types<L, R, C>::type all_types; 204 205 // Filter all unused_types 206 typedef typename 207 mpl::copy_if< 208 all_types 209 , mpl::not_<is_same<mpl::_1, unused_type>> 210 , mpl::back_inserter<mpl::vector<>> 211 >::type 212 filtered_types; 213 214 // Build a variant if filtered_types is not empty, 215 // else just return unused_type 216 typedef typename 217 mpl::eval_if< 218 mpl::empty<filtered_types> 219 , mpl::identity<unused_type> 220 , make_variant_over<filtered_types> 221 >::type 222 type; 223 }; 224 225 template <typename IsAlternative> 226 struct move_if_not_alternative 227 { 228 template<typename T1, typename T2> callboost::spirit::x3::detail::move_if_not_alternative229 static void call(T1& attr_, T2& attr) {} 230 }; 231 232 template <> 233 struct move_if_not_alternative<mpl::false_ /*is alternative*/> 234 { 235 template<typename T1, typename T2> callboost::spirit::x3::detail::move_if_not_alternative236 static void call(T1& attr_, T2& attr) 237 { 238 traits::move_to(attr_, attr); 239 } 240 }; 241 242 template <typename Parser, typename Iterator, typename Context 243 , typename RContext, typename Attribute> parse_alternative(Parser const & p,Iterator & first,Iterator const & last,Context const & context,RContext & rcontext,Attribute & attr)244 bool parse_alternative(Parser const& p, Iterator& first, Iterator const& last 245 , Context const& context, RContext& rcontext, Attribute& attr) 246 { 247 typedef detail::pass_variant_attribute<Parser, Attribute, Context> pass; 248 249 typename pass::type attr_ = pass::call(attr); 250 if (p.parse(first, last, context, rcontext, attr_)) 251 { 252 move_if_not_alternative<typename pass::is_alternative>::call(attr_, attr); 253 return true; 254 } 255 return false; 256 } 257 258 259 template <typename Left, typename Right, typename Context, typename RContext> 260 struct parse_into_container_impl<alternative<Left, Right>, Context, RContext> 261 { 262 typedef alternative<Left, Right> parser_type; 263 264 template <typename Iterator, typename Attribute> callboost::spirit::x3::detail::parse_into_container_impl265 static bool call( 266 parser_type const& parser 267 , Iterator& first, Iterator const& last 268 , Context const& context, RContext& rcontext, Attribute& attr, mpl::true_) 269 { 270 return parse_alternative(parser, first, last, context, rcontext, attr); 271 } 272 273 template <typename Iterator, typename Attribute> callboost::spirit::x3::detail::parse_into_container_impl274 static bool call( 275 parser_type const& parser 276 , Iterator& first, Iterator const& last 277 , Context const& context, RContext& rcontext, Attribute& attr, mpl::false_) 278 { 279 return parse_into_container_base_impl<parser_type>::call( 280 parser, first, last, context, rcontext, attr); 281 } 282 283 template <typename Iterator, typename Attribute> callboost::spirit::x3::detail::parse_into_container_impl284 static bool call( 285 parser_type const& parser 286 , Iterator& first, Iterator const& last 287 , Context const& context, RContext& rcontext, Attribute& attr) 288 { 289 typedef typename 290 traits::attribute_of<parser_type, Context>::type 291 attribute_type; 292 293 return call(parser, first, last, context, rcontext, attr 294 , traits::variant_has_substitute<attribute_type, Attribute>()); 295 } 296 }; 297 298 }}}} 299 300 #endif 301