/////////////////////////////////////////////////////////////////////////////// | |
// action_matcher.hpp | |
// | |
// Copyright 2008 Eric Niebler. | |
// Copyright 2008 David Jenkins. | |
// | |
// 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) | |
#ifndef BOOST_XPRESSIVE_DETAIL_CORE_MATCHER_ACTION_MATCHER_HPP_EAN_10_04_2005 | |
#define BOOST_XPRESSIVE_DETAIL_CORE_MATCHER_ACTION_MATCHER_HPP_EAN_10_04_2005 | |
// MS compatible compilers support #pragma once | |
#if defined(_MSC_VER) && (_MSC_VER >= 1020) | |
# pragma once | |
#endif | |
#include <boost/config.hpp> | |
#include <boost/version.hpp> | |
#include <boost/ref.hpp> | |
#include <boost/assert.hpp> | |
#include <boost/mpl/if.hpp> | |
#include <boost/throw_exception.hpp> | |
#include <boost/utility/result_of.hpp> | |
#include <boost/type_traits/is_const.hpp> | |
#include <boost/type_traits/remove_reference.hpp> | |
#include <boost/xpressive/detail/detail_fwd.hpp> | |
#include <boost/xpressive/detail/core/quant_style.hpp> | |
#include <boost/xpressive/detail/core/action.hpp> | |
#include <boost/xpressive/detail/core/state.hpp> | |
#include <boost/proto/core.hpp> | |
#include <boost/proto/context.hpp> | |
#include <boost/xpressive/match_results.hpp> // for type_info_less | |
#include <boost/xpressive/detail/static/transforms/as_action.hpp> // for 'read_attr' | |
#if BOOST_VERSION >= 103500 | |
# include <boost/proto/fusion.hpp> | |
# include <boost/fusion/include/transform_view.hpp> | |
# include <boost/fusion/include/invoke.hpp> | |
# include <boost/fusion/include/push_front.hpp> | |
# include <boost/fusion/include/pop_front.hpp> | |
#endif | |
#if BOOST_MSVC | |
#pragma warning(push) | |
#pragma warning(disable : 4510) // default constructor could not be generated | |
#pragma warning(disable : 4512) // assignment operator could not be generated | |
#pragma warning(disable : 4610) // can never be instantiated - user defined constructor required | |
#endif | |
namespace boost { namespace xpressive { namespace detail | |
{ | |
#if BOOST_VERSION >= 103500 | |
struct DataMember | |
: proto::mem_ptr<proto::_, proto::terminal<proto::_> > | |
{}; | |
template<typename Expr, long N> | |
struct child_ | |
: remove_reference< | |
typename proto::result_of::child_c<Expr &, N>::type | |
> | |
{}; | |
/////////////////////////////////////////////////////////////////////////////// | |
// mem_ptr_eval | |
// Rewrites expressions of the form x->*foo(a) into foo(x, a) and then | |
// evaluates them. | |
template<typename Expr, typename Context, bool IsDataMember = proto::matches<Expr, DataMember>::value> | |
struct mem_ptr_eval | |
{ | |
typedef typename child_<Expr, 0>::type left_type; | |
typedef typename child_<Expr, 1>::type right_type; | |
typedef | |
typename proto::result_of::value< | |
typename proto::result_of::child_c<right_type, 0>::type | |
>::type | |
function_type; | |
typedef | |
fusion::transform_view< | |
typename fusion::result_of::push_front< | |
typename fusion::result_of::pop_front<right_type>::type const | |
, reference_wrapper<left_type> | |
>::type const | |
, proto::eval_fun<Context> | |
> | |
evaluated_args; | |
typedef | |
typename fusion::result_of::invoke<function_type, evaluated_args>::type | |
result_type; | |
result_type operator()(Expr &expr, Context &ctx) const | |
{ | |
return fusion::invoke<function_type>( | |
proto::value(proto::child_c<0>(proto::right(expr))) | |
, evaluated_args( | |
fusion::push_front(fusion::pop_front(proto::right(expr)), boost::ref(proto::left(expr))) | |
, proto::eval_fun<Context>(ctx) | |
) | |
); | |
} | |
}; | |
/////////////////////////////////////////////////////////////////////////////// | |
// mem_ptr_eval | |
// Rewrites expressions of the form x->*foo into foo(x) and then | |
// evaluates them. | |
template<typename Expr, typename Context> | |
struct mem_ptr_eval<Expr, Context, true> | |
{ | |
typedef typename child_<Expr, 0>::type left_type; | |
typedef typename child_<Expr, 1>::type right_type; | |
typedef | |
typename proto::result_of::value<right_type>::type | |
function_type; | |
typedef typename boost::result_of< | |
function_type(typename proto::result_of::eval<left_type, Context>::type) | |
>::type result_type; | |
result_type operator()(Expr &expr, Context &ctx) const | |
{ | |
return proto::value(proto::right(expr))( | |
proto::eval(proto::left(expr), ctx) | |
); | |
} | |
}; | |
#endif | |
struct attr_with_default_tag | |
{}; | |
template<typename T> | |
struct opt; | |
/////////////////////////////////////////////////////////////////////////////// | |
// action_context | |
// | |
struct action_context | |
{ | |
explicit action_context(action_args_type *action_args) | |
: action_args_(action_args) | |
{} | |
action_args_type const &args() const | |
{ | |
return *this->action_args_; | |
} | |
// eval_terminal | |
template<typename Expr, typename Arg> | |
struct eval_terminal | |
: proto::default_eval<Expr, action_context const> | |
{}; | |
template<typename Expr, typename Arg> | |
struct eval_terminal<Expr, reference_wrapper<Arg> > | |
{ | |
typedef Arg &result_type; | |
result_type operator()(Expr &expr, action_context const &) const | |
{ | |
return proto::value(expr).get(); | |
} | |
}; | |
template<typename Expr, typename Arg> | |
struct eval_terminal<Expr, opt<Arg> > | |
{ | |
typedef Arg const &result_type; | |
result_type operator()(Expr &expr, action_context const &) const | |
{ | |
return proto::value(expr); | |
} | |
}; | |
template<typename Expr, typename Type, typename Int> | |
struct eval_terminal<Expr, action_arg<Type, Int> > | |
{ | |
typedef typename action_arg<Type, Int>::reference result_type; | |
result_type operator()(Expr &expr, action_context const &ctx) const | |
{ | |
action_args_type::const_iterator where_ = ctx.args().find(&typeid(proto::value(expr))); | |
if(where_ == ctx.args().end()) | |
{ | |
BOOST_THROW_EXCEPTION( | |
regex_error( | |
regex_constants::error_badarg | |
, "An argument to an action was unspecified" | |
) | |
); | |
} | |
return proto::value(expr).cast(where_->second); | |
} | |
}; | |
// eval | |
template<typename Expr, typename Tag = typename Expr::proto_tag> | |
struct eval | |
: proto::default_eval<Expr, action_context const> | |
{}; | |
template<typename Expr> | |
struct eval<Expr, proto::tag::terminal> | |
: eval_terminal<Expr, typename proto::result_of::value<Expr>::type> | |
{}; | |
// Evaluate attributes like a1|42 | |
template<typename Expr> | |
struct eval<Expr, attr_with_default_tag> | |
{ | |
typedef | |
typename proto::result_of::value< | |
typename proto::result_of::left< | |
typename proto::result_of::child< | |
Expr | |
>::type | |
>::type | |
>::type | |
temp_type; | |
typedef typename temp_type::type result_type; | |
result_type operator ()(Expr const &expr, action_context const &ctx) const | |
{ | |
return proto::value(proto::left(proto::child(expr))).t_ | |
? *proto::value(proto::left(proto::child(expr))).t_ | |
: proto::eval(proto::right(proto::child(expr)), ctx); | |
} | |
}; | |
#if BOOST_VERSION >= 103500 | |
template<typename Expr> | |
struct eval<Expr, proto::tag::mem_ptr> | |
: mem_ptr_eval<Expr, action_context const> | |
{}; | |
#endif | |
private: | |
action_args_type *action_args_; | |
}; | |
/////////////////////////////////////////////////////////////////////////////// | |
// action | |
// | |
template<typename Actor> | |
struct action | |
: actionable | |
{ | |
action(Actor const &actor) | |
: actionable() | |
, actor_(actor) | |
{ | |
} | |
virtual void execute(action_args_type *action_args) const | |
{ | |
action_context const ctx(action_args); | |
proto::eval(this->actor_, ctx); | |
} | |
private: | |
Actor actor_; | |
}; | |
/////////////////////////////////////////////////////////////////////////////// | |
// subreg_transform | |
// | |
struct subreg_transform : proto::transform<subreg_transform> | |
{ | |
template<typename Expr, typename State, typename Data> | |
struct impl : proto::transform_impl<Expr, State, Data> | |
{ | |
typedef typename impl::state state_type; | |
typedef | |
typename proto::terminal<sub_match<typename state_type::iterator> >::type | |
result_type; | |
result_type operator ()( | |
typename impl::expr_param | |
, typename impl::state_param state | |
, typename impl::data_param data | |
) const | |
{ | |
return result_type::make(state.sub_matches_[ data ]); | |
} | |
}; | |
}; | |
/////////////////////////////////////////////////////////////////////////////// | |
// mark_transform | |
// | |
struct mark_transform : proto::transform<mark_transform> | |
{ | |
template<typename Expr, typename State, typename Data> | |
struct impl : proto::transform_impl<Expr, State, Data> | |
{ | |
typedef typename impl::state state_type; | |
typedef | |
typename proto::terminal<sub_match<typename state_type::iterator> >::type | |
result_type; | |
result_type operator ()( | |
typename impl::expr_param expr | |
, typename impl::state_param state | |
, typename impl::data_param | |
) const | |
{ | |
return result_type::make(state.sub_matches_[ proto::value(expr).mark_number_ ]); | |
} | |
}; | |
}; | |
/////////////////////////////////////////////////////////////////////////////// | |
// opt | |
// | |
template<typename T> | |
struct opt | |
{ | |
typedef T type; | |
typedef T const &reference; | |
opt(T const *t) | |
: t_(t) | |
{} | |
operator reference() const | |
{ | |
BOOST_XPR_ENSURE_(0 != this->t_, regex_constants::error_badattr, "Use of uninitialized regex attribute"); | |
return *this->t_; | |
} | |
T const *t_; | |
}; | |
/////////////////////////////////////////////////////////////////////////////// | |
// attr_transform | |
// | |
struct attr_transform : proto::transform<attr_transform> | |
{ | |
template<typename Expr, typename State, typename Data> | |
struct impl : proto::transform_impl<Expr, State, Data> | |
{ | |
typedef typename impl::expr expr_type; | |
typedef | |
typename expr_type::proto_child0::matcher_type::value_type::second_type | |
attr_type; | |
typedef | |
typename proto::terminal<opt<attr_type> >::type | |
result_type; | |
result_type operator ()( | |
typename impl::expr_param | |
, typename impl::state_param state | |
, typename impl::data_param | |
) const | |
{ | |
int slot = typename expr_type::proto_child0::nbr_type(); | |
attr_type const *attr = static_cast<attr_type const *>(state.attr_context_.attr_slots_[slot-1]); | |
return result_type::make(opt<attr_type>(attr)); | |
} | |
}; | |
}; | |
/////////////////////////////////////////////////////////////////////////////// | |
// attr_with_default_transform | |
// | |
template<typename Grammar, typename Callable = proto::callable> | |
struct attr_with_default_transform : proto::transform<attr_with_default_transform<Grammar, Callable> > | |
{ | |
template<typename Expr, typename State, typename Data> | |
struct impl : proto::transform_impl<Expr, State, Data> | |
{ | |
typedef | |
typename proto::unary_expr< | |
attr_with_default_tag | |
, typename Grammar::template impl<Expr, State, Data>::result_type | |
>::type | |
result_type; | |
result_type operator ()( | |
typename impl::expr_param expr | |
, typename impl::state_param state | |
, typename impl::data_param data | |
) const | |
{ | |
result_type that = { | |
typename Grammar::template impl<Expr, State, Data>()(expr, state, data) | |
}; | |
return that; | |
} | |
}; | |
}; | |
/////////////////////////////////////////////////////////////////////////////// | |
// by_ref_transform | |
// | |
struct by_ref_transform : proto::transform<by_ref_transform> | |
{ | |
template<typename Expr, typename State, typename Data> | |
struct impl : proto::transform_impl<Expr, State, Data> | |
{ | |
typedef | |
typename proto::result_of::value<typename impl::expr_param>::type | |
reference; | |
typedef | |
typename proto::terminal<reference>::type | |
result_type; | |
result_type operator ()( | |
typename impl::expr_param expr | |
, typename impl::state_param | |
, typename impl::data_param | |
) const | |
{ | |
return result_type::make(proto::value(expr)); | |
} | |
}; | |
}; | |
/////////////////////////////////////////////////////////////////////////////// | |
// BindActionArgs | |
// | |
struct BindActionArgs | |
: proto::or_< | |
proto::when<proto::terminal<any_matcher>, subreg_transform> | |
, proto::when<proto::terminal<mark_placeholder>, mark_transform> | |
, proto::when<proto::terminal<read_attr<proto::_, proto::_> >, attr_transform> | |
, proto::when<proto::terminal<proto::_>, by_ref_transform> | |
, proto::when< | |
proto::bitwise_or<proto::terminal<read_attr<proto::_, proto::_> >, BindActionArgs> | |
, attr_with_default_transform<proto::bitwise_or<attr_transform, BindActionArgs> > | |
> | |
, proto::otherwise<proto::nary_expr<proto::_, proto::vararg<BindActionArgs> > > | |
> | |
{}; | |
/////////////////////////////////////////////////////////////////////////////// | |
// action_matcher | |
// | |
template<typename Actor> | |
struct action_matcher | |
: quant_style<quant_none, 0, false> | |
{ | |
int sub_; | |
Actor actor_; | |
action_matcher(Actor const &actor, int sub) | |
: sub_(sub) | |
, actor_(actor) | |
{ | |
} | |
template<typename BidiIter, typename Next> | |
bool match(match_state<BidiIter> &state, Next const &next) const | |
{ | |
// Bind the arguments | |
typedef | |
typename boost::result_of<BindActionArgs( | |
Actor const & | |
, match_state<BidiIter> & | |
, int const & | |
)>::type | |
action_type; | |
action<action_type> actor(BindActionArgs()(this->actor_, state, this->sub_)); | |
// Put the action in the action list | |
actionable const **action_list_tail = state.action_list_tail_; | |
*state.action_list_tail_ = &actor; | |
state.action_list_tail_ = &actor.next; | |
// Match the rest of the pattern | |
if(next.match(state)) | |
{ | |
return true; | |
} | |
BOOST_ASSERT(0 == actor.next); | |
// remove action from list | |
*action_list_tail = 0; | |
state.action_list_tail_ = action_list_tail; | |
return false; | |
} | |
}; | |
}}} | |
#if BOOST_MSVC | |
#pragma warning(pop) | |
#endif | |
#endif |