1 /*============================================================================== 2 Copyright (c) 2001-2010 Joel de Guzman 3 Copyright (c) 2010 Thomas Heller 4 5 Distributed under the Boost Software License, Version 1.0. (See accompanying 6 file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 7 ==============================================================================*/ 8 #ifndef BOOST_PHOENIX_STATEMENT_SWITCH_HPP 9 #define BOOST_PHOENIX_STATEMENT_SWITCH_HPP 10 11 #include <boost/phoenix/core/limits.hpp> 12 #include <boost/fusion/iterator/advance.hpp> 13 #include <boost/phoenix/core/call.hpp> 14 #include <boost/phoenix/core/expression.hpp> 15 #include <boost/phoenix/core/meta_grammar.hpp> 16 #include <boost/phoenix/core/is_nullary.hpp> 17 #include <boost/phoenix/support/iterate.hpp> 18 #include <boost/proto/make_expr.hpp> 19 #include <boost/proto/fusion.hpp> 20 21 #ifdef _MSC_VER 22 #pragma warning(push) 23 #pragma warning(disable: 4065) // switch statement contains 'default' but no 'case' labels 24 #endif 25 26 BOOST_PHOENIX_DEFINE_EXPRESSION( 27 (boost)(phoenix)(switch_case) 28 , (proto::terminal<proto::_>) 29 (meta_grammar) 30 ) 31 32 BOOST_PHOENIX_DEFINE_EXPRESSION( 33 (boost)(phoenix)(switch_default_case) 34 , (meta_grammar) 35 ) 36 37 namespace boost { namespace phoenix 38 { 39 namespace detail 40 { 41 struct switch_case_grammar; 42 struct switch_case_with_default_grammar; 43 struct switch_grammar 44 : proto::or_< 45 proto::when< 46 detail::switch_case_grammar 47 , mpl::false_() 48 > 49 , proto::when< 50 detail::switch_case_with_default_grammar 51 , mpl::true_() 52 > 53 > 54 {}; 55 } 56 57 namespace detail 58 { 59 struct switch_case_is_nullary 60 : proto::or_< 61 proto::when< 62 proto::comma< 63 switch_case_is_nullary 64 , proto::or_<phoenix::rule::switch_default_case, phoenix::rule::switch_case> 65 > 66 , mpl::and_< 67 switch_case_is_nullary( 68 proto::_child_c<0> 69 , proto::_state 70 ) 71 , switch_case_is_nullary( 72 proto::_child_c<1> 73 , proto::_state 74 ) 75 >() 76 > 77 , proto::when< 78 proto::or_<phoenix::rule::switch_default_case, phoenix::rule::switch_case> 79 , evaluator(proto::_child_c<0>, proto::_state) 80 > 81 > 82 {}; 83 84 struct switch_case_grammar 85 : proto::or_< 86 proto::comma<switch_case_grammar, phoenix::rule::switch_case> 87 , proto::when<phoenix::rule::switch_case, proto::_> 88 > 89 {}; 90 91 struct switch_case_with_default_grammar 92 : proto::or_< 93 proto::comma<switch_case_grammar, phoenix::rule::switch_default_case> 94 , proto::when<phoenix::rule::switch_default_case, proto::_> 95 > 96 {}; 97 98 struct switch_size 99 : proto::or_< 100 proto::when< 101 proto::comma<switch_size, proto::_> 102 , mpl::next<switch_size(proto::_left)>() 103 > 104 , proto::when<proto::_, mpl::int_<1>()> 105 > 106 {}; 107 } 108 }} 109 110 BOOST_PHOENIX_DEFINE_EXPRESSION( 111 (boost)(phoenix)(switch_) 112 , (meta_grammar) // Cond 113 (detail::switch_grammar) // Cases 114 ) 115 116 namespace boost { namespace phoenix { 117 118 template <typename Dummy> 119 struct is_nullary::when<rule::switch_, Dummy> 120 : proto::and_< 121 evaluator(proto::_child_c<0>, _context) 122 , detail::switch_case_is_nullary(proto::_child_c<1>, _context) 123 > 124 {}; 125 126 struct switch_eval 127 { 128 typedef void result_type; 129 130 template <typename Context> 131 result_type operator ()boost::phoenix::switch_eval132 operator()(Context const &) const 133 { 134 } 135 136 template <typename Cond, typename Cases, typename Context> 137 result_type operator ()boost::phoenix::switch_eval138 operator()(Cond const & cond, Cases const & cases, Context const & ctx) const 139 { 140 this->evaluate( 141 ctx 142 , cond 143 , cases 144 , typename detail::switch_size::impl<Cases, int, proto::empty_env>::result_type() 145 , typename detail::switch_grammar::impl<Cases, int, proto::empty_env>::result_type() 146 ); 147 } 148 149 private: 150 template <typename Context, typename Cond, typename Cases> 151 result_type evaluateboost::phoenix::switch_eval152 evaluate( 153 Context const & ctx 154 , Cond const & cond 155 , Cases const & cases 156 , mpl::int_<1> 157 , mpl::false_ 158 ) const 159 { 160 typedef 161 typename proto::result_of::value< 162 typename proto::result_of::child_c< 163 Cases 164 , 0 165 >::type 166 >::type 167 case_label; 168 169 switch(boost::phoenix::eval(cond, ctx)) 170 { 171 case case_label::value: 172 boost::phoenix::eval(proto::child_c<1>(cases), ctx); 173 } 174 } 175 176 template <typename Context, typename Cond, typename Cases> 177 result_type evaluateboost::phoenix::switch_eval178 evaluate( 179 Context const & ctx 180 , Cond const & cond 181 , Cases const & cases 182 , mpl::int_<1> 183 , mpl::true_ 184 ) const 185 { 186 switch(boost::phoenix::eval(cond, ctx)) 187 { 188 default: 189 boost::phoenix::eval(proto::child_c<0>(cases), ctx); 190 } 191 } 192 193 // Bring in the evaluation functions 194 #include <boost/phoenix/statement/detail/switch.hpp> 195 }; 196 197 template <typename Dummy> 198 struct default_actions::when<rule::switch_, Dummy> 199 : call<switch_eval> 200 {}; 201 202 template <int N, typename A> 203 inline 204 typename proto::result_of::make_expr< 205 tag::switch_case 206 , proto::basic_default_domain 207 , mpl::int_<N> 208 , A 209 >::type const case_(A const & a)210 case_(A const & a) 211 { 212 return 213 proto::make_expr< 214 tag::switch_case 215 , proto::basic_default_domain 216 >( 217 mpl::int_<N>() 218 , a 219 ); 220 } 221 222 template <typename A> 223 inline 224 typename proto::result_of::make_expr< 225 tag::switch_default_case 226 , proto::basic_default_domain 227 , A 228 >::type const default_(A const & a)229 default_(A const& a) 230 { 231 return 232 proto::make_expr< 233 tag::switch_default_case 234 , proto::basic_default_domain 235 >(a); 236 } 237 238 template <typename Cond> 239 struct switch_gen 240 { switch_genboost::phoenix::switch_gen241 switch_gen(Cond const& cond_) : cond(cond_) {} 242 243 template <typename Cases> 244 typename expression::switch_< 245 Cond 246 , Cases 247 >::type operator []boost::phoenix::switch_gen248 operator[](Cases const& cases) const 249 { 250 return 251 this->generate( 252 cases 253 , proto::matches<Cases, detail::switch_grammar>() 254 ); 255 } 256 257 private: 258 Cond const& cond; 259 260 template <typename Cases> 261 typename expression::switch_< 262 Cond 263 , Cases 264 >::type generateboost::phoenix::switch_gen265 generate(Cases const & cases, mpl::true_) const 266 { 267 return expression::switch_<Cond, Cases>::make(cond, cases); 268 } 269 270 template <typename Cases> 271 typename expression::switch_< 272 Cond 273 , Cases 274 >::type generateboost::phoenix::switch_gen275 generate(Cases const &, mpl::false_) const 276 { 277 BOOST_MPL_ASSERT_MSG( 278 false 279 , INVALID_SWITCH_CASE_STATEMENT 280 , (Cases) 281 ); 282 } 283 }; 284 285 template <typename Cond> 286 inline 287 switch_gen<Cond> const switch_(Cond const & cond)288 switch_(Cond const& cond) 289 { 290 return switch_gen<Cond>(cond); 291 } 292 293 }} 294 295 #ifdef _MSC_VER 296 #pragma warning(pop) 297 #endif 298 299 #endif 300 301