1 /////////////////////////////////////////////////////////////////////////////// 2 // action_matcher.hpp 3 // 4 // Copyright 2008 Eric Niebler. 5 // Copyright 2008 David Jenkins. 6 // 7 // Distributed under the Boost Software License, Version 1.0. (See 8 // accompanying file LICENSE_1_0.txt or copy at 9 // http://www.boost.org/LICENSE_1_0.txt) 10 11 #ifndef BOOST_XPRESSIVE_DETAIL_CORE_MATCHER_ACTION_MATCHER_HPP_EAN_10_04_2005 12 #define BOOST_XPRESSIVE_DETAIL_CORE_MATCHER_ACTION_MATCHER_HPP_EAN_10_04_2005 13 14 // MS compatible compilers support #pragma once 15 #if defined(_MSC_VER) 16 # pragma once 17 #endif 18 19 #include <boost/config.hpp> 20 #include <boost/version.hpp> 21 #include <boost/ref.hpp> 22 #include <boost/assert.hpp> 23 #include <boost/mpl/if.hpp> 24 #include <boost/throw_exception.hpp> 25 #include <boost/utility/result_of.hpp> 26 #include <boost/type_traits/is_const.hpp> 27 #include <boost/type_traits/remove_reference.hpp> 28 #include <boost/xpressive/detail/detail_fwd.hpp> 29 #include <boost/xpressive/detail/core/quant_style.hpp> 30 #include <boost/xpressive/detail/core/action.hpp> 31 #include <boost/xpressive/detail/core/state.hpp> 32 #include <boost/proto/core.hpp> 33 #include <boost/proto/context.hpp> 34 #include <boost/xpressive/match_results.hpp> // for type_info_less 35 #include <boost/xpressive/detail/static/transforms/as_action.hpp> // for 'read_attr' 36 #if BOOST_VERSION >= 103500 37 # include <boost/proto/fusion.hpp> 38 # include <boost/fusion/include/transform_view.hpp> 39 # include <boost/fusion/include/invoke.hpp> 40 # include <boost/fusion/include/push_front.hpp> 41 # include <boost/fusion/include/pop_front.hpp> 42 #endif 43 44 #if BOOST_MSVC 45 #pragma warning(push) 46 #pragma warning(disable : 4510) // default constructor could not be generated 47 #pragma warning(disable : 4512) // assignment operator could not be generated 48 #pragma warning(disable : 4610) // can never be instantiated - user defined constructor required 49 #endif 50 51 namespace boost { namespace xpressive { namespace detail 52 { 53 54 #if BOOST_VERSION >= 103500 55 struct DataMember 56 : proto::mem_ptr<proto::_, proto::terminal<proto::_> > 57 {}; 58 59 template<typename Expr, long N> 60 struct child_ 61 : remove_reference< 62 typename proto::result_of::child_c<Expr &, N>::type 63 > 64 {}; 65 66 /////////////////////////////////////////////////////////////////////////////// 67 // mem_ptr_eval 68 // Rewrites expressions of the form x->*foo(a) into foo(x, a) and then 69 // evaluates them. 70 template<typename Expr, typename Context, bool IsDataMember = proto::matches<Expr, DataMember>::value> 71 struct mem_ptr_eval 72 { 73 typedef typename child_<Expr, 0>::type left_type; 74 typedef typename child_<Expr, 1>::type right_type; 75 76 typedef 77 typename proto::result_of::value< 78 typename proto::result_of::child_c<right_type, 0>::type 79 >::type 80 function_type; 81 82 typedef 83 fusion::transform_view< 84 typename fusion::result_of::push_front< 85 typename fusion::result_of::pop_front<right_type>::type const 86 , reference_wrapper<left_type> 87 >::type const 88 , proto::eval_fun<Context> 89 > 90 evaluated_args; 91 92 typedef 93 typename fusion::result_of::invoke<function_type, evaluated_args>::type 94 result_type; 95 operator ()boost::xpressive::detail::mem_ptr_eval96 result_type operator()(Expr &expr, Context &ctx) const 97 { 98 return fusion::invoke<function_type>( 99 proto::value(proto::child_c<0>(proto::right(expr))) 100 , evaluated_args( 101 fusion::push_front(fusion::pop_front(proto::right(expr)), boost::ref(proto::left(expr))) 102 , proto::eval_fun<Context>(ctx) 103 ) 104 ); 105 } 106 }; 107 108 /////////////////////////////////////////////////////////////////////////////// 109 // mem_ptr_eval 110 // Rewrites expressions of the form x->*foo into foo(x) and then 111 // evaluates them. 112 template<typename Expr, typename Context> 113 struct mem_ptr_eval<Expr, Context, true> 114 { 115 typedef typename child_<Expr, 0>::type left_type; 116 typedef typename child_<Expr, 1>::type right_type; 117 118 typedef 119 typename proto::result_of::value<right_type>::type 120 function_type; 121 122 typedef typename boost::result_of< 123 function_type(typename proto::result_of::eval<left_type, Context>::type) 124 >::type result_type; 125 operator ()boost::xpressive::detail::mem_ptr_eval126 result_type operator()(Expr &expr, Context &ctx) const 127 { 128 return proto::value(proto::right(expr))( 129 proto::eval(proto::left(expr), ctx) 130 ); 131 } 132 }; 133 #endif 134 135 struct attr_with_default_tag 136 {}; 137 138 template<typename T> 139 struct opt; 140 141 /////////////////////////////////////////////////////////////////////////////// 142 // action_context 143 // 144 struct action_context 145 { action_contextboost::xpressive::detail::action_context146 explicit action_context(action_args_type *action_args) 147 : action_args_(action_args) 148 {} 149 argsboost::xpressive::detail::action_context150 action_args_type const &args() const 151 { 152 return *this->action_args_; 153 } 154 155 // eval_terminal 156 template<typename Expr, typename Arg> 157 struct eval_terminal 158 : proto::default_eval<Expr, action_context const> 159 {}; 160 161 template<typename Expr, typename Arg> 162 struct eval_terminal<Expr, reference_wrapper<Arg> > 163 { 164 typedef Arg &result_type; operator ()boost::xpressive::detail::action_context::eval_terminal165 result_type operator()(Expr &expr, action_context const &) const 166 { 167 return proto::value(expr).get(); 168 } 169 }; 170 171 template<typename Expr, typename Arg> 172 struct eval_terminal<Expr, opt<Arg> > 173 { 174 typedef Arg const &result_type; operator ()boost::xpressive::detail::action_context::eval_terminal175 result_type operator()(Expr &expr, action_context const &) const 176 { 177 return proto::value(expr); 178 } 179 }; 180 181 template<typename Expr, typename Type, typename Int> 182 struct eval_terminal<Expr, action_arg<Type, Int> > 183 { 184 typedef typename action_arg<Type, Int>::reference result_type; operator ()boost::xpressive::detail::action_context::eval_terminal185 result_type operator()(Expr &expr, action_context const &ctx) const 186 { 187 action_args_type::const_iterator where_ = ctx.args().find(&typeid(proto::value(expr))); 188 if(where_ == ctx.args().end()) 189 { 190 BOOST_THROW_EXCEPTION( 191 regex_error( 192 regex_constants::error_badarg 193 , "An argument to an action was unspecified" 194 ) 195 ); 196 } 197 return proto::value(expr).cast(where_->second); 198 } 199 }; 200 201 // eval 202 template<typename Expr, typename Tag = typename Expr::proto_tag> 203 struct eval 204 : proto::default_eval<Expr, action_context const> 205 {}; 206 207 template<typename Expr> 208 struct eval<Expr, proto::tag::terminal> 209 : eval_terminal<Expr, typename proto::result_of::value<Expr>::type> 210 {}; 211 212 // Evaluate attributes like a1|42 213 template<typename Expr> 214 struct eval<Expr, attr_with_default_tag> 215 { 216 typedef 217 typename proto::result_of::value< 218 typename proto::result_of::left< 219 typename proto::result_of::child< 220 Expr 221 >::type 222 >::type 223 >::type 224 temp_type; 225 226 typedef typename temp_type::type result_type; 227 operator ()boost::xpressive::detail::action_context::eval228 result_type operator ()(Expr const &expr, action_context const &ctx) const 229 { 230 return proto::value(proto::left(proto::child(expr))).t_ 231 ? *proto::value(proto::left(proto::child(expr))).t_ 232 : proto::eval(proto::right(proto::child(expr)), ctx); 233 } 234 }; 235 236 #if BOOST_VERSION >= 103500 237 template<typename Expr> 238 struct eval<Expr, proto::tag::mem_ptr> 239 : mem_ptr_eval<Expr, action_context const> 240 {}; 241 #endif 242 243 private: 244 action_args_type *action_args_; 245 }; 246 247 /////////////////////////////////////////////////////////////////////////////// 248 // action 249 // 250 template<typename Actor> 251 struct action 252 : actionable 253 { actionboost::xpressive::detail::action254 action(Actor const &actor) 255 : actionable() 256 , actor_(actor) 257 { 258 } 259 executeboost::xpressive::detail::action260 virtual void execute(action_args_type *action_args) const 261 { 262 action_context const ctx(action_args); 263 proto::eval(this->actor_, ctx); 264 } 265 266 private: 267 Actor actor_; 268 }; 269 270 /////////////////////////////////////////////////////////////////////////////// 271 // subreg_transform 272 // 273 struct subreg_transform : proto::transform<subreg_transform> 274 { 275 template<typename Expr, typename State, typename Data> 276 struct impl : proto::transform_impl<Expr, State, Data> 277 { 278 typedef typename impl::state state_type; 279 280 typedef 281 typename proto::terminal<sub_match<typename state_type::iterator> >::type 282 result_type; 283 operator ()boost::xpressive::detail::subreg_transform::impl284 result_type operator ()( 285 typename impl::expr_param 286 , typename impl::state_param state 287 , typename impl::data_param data 288 ) const 289 { 290 return result_type::make(state.sub_matches_[ data ]); 291 } 292 }; 293 }; 294 295 /////////////////////////////////////////////////////////////////////////////// 296 // mark_transform 297 // 298 struct mark_transform : proto::transform<mark_transform> 299 { 300 template<typename Expr, typename State, typename Data> 301 struct impl : proto::transform_impl<Expr, State, Data> 302 { 303 typedef typename impl::state state_type; 304 typedef 305 typename proto::terminal<sub_match<typename state_type::iterator> >::type 306 result_type; 307 operator ()boost::xpressive::detail::mark_transform::impl308 result_type operator ()( 309 typename impl::expr_param expr 310 , typename impl::state_param state 311 , typename impl::data_param 312 ) const 313 { 314 return result_type::make(state.sub_matches_[ proto::value(expr).mark_number_ ]); 315 } 316 }; 317 }; 318 319 /////////////////////////////////////////////////////////////////////////////// 320 // opt 321 // 322 template<typename T> 323 struct opt 324 { 325 typedef T type; 326 typedef T const &reference; 327 optboost::xpressive::detail::opt328 opt(T const *t) 329 : t_(t) 330 {} 331 operator referenceboost::xpressive::detail::opt332 operator reference() const 333 { 334 BOOST_XPR_ENSURE_(0 != this->t_, regex_constants::error_badattr, "Use of uninitialized regex attribute"); 335 return *this->t_; 336 } 337 338 T const *t_; 339 }; 340 341 /////////////////////////////////////////////////////////////////////////////// 342 // attr_transform 343 // 344 struct attr_transform : proto::transform<attr_transform> 345 { 346 template<typename Expr, typename State, typename Data> 347 struct impl : proto::transform_impl<Expr, State, Data> 348 { 349 typedef typename impl::expr expr_type; 350 351 typedef 352 typename expr_type::proto_child0::matcher_type::value_type::second_type 353 attr_type; 354 355 typedef 356 typename proto::terminal<opt<attr_type> >::type 357 result_type; 358 operator ()boost::xpressive::detail::attr_transform::impl359 result_type operator ()( 360 typename impl::expr_param 361 , typename impl::state_param state 362 , typename impl::data_param 363 ) const 364 { 365 int slot = typename expr_type::proto_child0::nbr_type(); 366 attr_type const *attr = static_cast<attr_type const *>(state.attr_context_.attr_slots_[slot-1]); 367 return result_type::make(opt<attr_type>(attr)); 368 } 369 }; 370 }; 371 372 /////////////////////////////////////////////////////////////////////////////// 373 // attr_with_default_transform 374 // 375 template<typename Grammar, typename Callable = proto::callable> 376 struct attr_with_default_transform : proto::transform<attr_with_default_transform<Grammar, Callable> > 377 { 378 template<typename Expr, typename State, typename Data> 379 struct impl : proto::transform_impl<Expr, State, Data> 380 { 381 typedef 382 typename proto::unary_expr< 383 attr_with_default_tag 384 , typename Grammar::template impl<Expr, State, Data>::result_type 385 >::type 386 result_type; 387 operator ()boost::xpressive::detail::attr_with_default_transform::impl388 result_type operator ()( 389 typename impl::expr_param expr 390 , typename impl::state_param state 391 , typename impl::data_param data 392 ) const 393 { 394 result_type that = { 395 typename Grammar::template impl<Expr, State, Data>()(expr, state, data) 396 }; 397 return that; 398 } 399 }; 400 }; 401 402 /////////////////////////////////////////////////////////////////////////////// 403 // by_ref_transform 404 // 405 struct by_ref_transform : proto::transform<by_ref_transform> 406 { 407 template<typename Expr, typename State, typename Data> 408 struct impl : proto::transform_impl<Expr, State, Data> 409 { 410 typedef 411 typename proto::result_of::value<typename impl::expr_param>::type 412 reference; 413 414 typedef 415 typename proto::terminal<reference>::type 416 result_type; 417 operator ()boost::xpressive::detail::by_ref_transform::impl418 result_type operator ()( 419 typename impl::expr_param expr 420 , typename impl::state_param 421 , typename impl::data_param 422 ) const 423 { 424 return result_type::make(proto::value(expr)); 425 } 426 }; 427 }; 428 429 /////////////////////////////////////////////////////////////////////////////// 430 // BindActionArgs 431 // 432 struct BindActionArgs 433 : proto::or_< 434 proto::when<proto::terminal<any_matcher>, subreg_transform> 435 , proto::when<proto::terminal<mark_placeholder>, mark_transform> 436 , proto::when<proto::terminal<read_attr<proto::_, proto::_> >, attr_transform> 437 , proto::when<proto::terminal<proto::_>, by_ref_transform> 438 , proto::when< 439 proto::bitwise_or<proto::terminal<read_attr<proto::_, proto::_> >, BindActionArgs> 440 , attr_with_default_transform<proto::bitwise_or<attr_transform, BindActionArgs> > 441 > 442 , proto::otherwise<proto::nary_expr<proto::_, proto::vararg<BindActionArgs> > > 443 > 444 {}; 445 446 /////////////////////////////////////////////////////////////////////////////// 447 // action_matcher 448 // 449 template<typename Actor> 450 struct action_matcher 451 : quant_style<quant_none, 0, false> 452 { 453 int sub_; 454 Actor actor_; 455 action_matcherboost::xpressive::detail::action_matcher456 action_matcher(Actor const &actor, int sub) 457 : sub_(sub) 458 , actor_(actor) 459 { 460 } 461 462 template<typename BidiIter, typename Next> matchboost::xpressive::detail::action_matcher463 bool match(match_state<BidiIter> &state, Next const &next) const 464 { 465 // Bind the arguments 466 typedef 467 typename boost::result_of<BindActionArgs( 468 Actor const & 469 , match_state<BidiIter> & 470 , int const & 471 )>::type 472 action_type; 473 474 action<action_type> actor(BindActionArgs()(this->actor_, state, this->sub_)); 475 476 // Put the action in the action list 477 actionable const **action_list_tail = state.action_list_tail_; 478 *state.action_list_tail_ = &actor; 479 state.action_list_tail_ = &actor.next; 480 481 // Match the rest of the pattern 482 if(next.match(state)) 483 { 484 return true; 485 } 486 487 BOOST_ASSERT(0 == actor.next); 488 // remove action from list 489 *action_list_tail = 0; 490 state.action_list_tail_ = action_list_tail; 491 return false; 492 } 493 }; 494 495 }}} 496 497 #if BOOST_MSVC 498 #pragma warning(pop) 499 #endif 500 501 #endif 502