/////////////////////////////////////////////////////////////////////////////// /// \file regex_actions.hpp /// Defines the syntax elements of xpressive's action expressions. // // Copyright 2008 Eric Niebler. 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_ACTIONS_HPP_EAN_03_22_2007 #define BOOST_XPRESSIVE_ACTIONS_HPP_EAN_03_22_2007 // MS compatible compilers support #pragma once #if defined(_MSC_VER) && (_MSC_VER >= 1020) # pragma once #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // These are very often needed by client code. #include #include // Doxygen can't handle proto :-( #ifndef BOOST_XPRESSIVE_DOXYGEN_INVOKED # include # include # include #endif /// INTERNAL ONLY /// #define UNREF(x) typename remove_reference::type /// INTERNAL ONLY /// #define UNCVREF(x) typename remove_cv::type>::type #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 { template struct action_arg { typedef T type; typedef typename add_reference::type reference; reference cast(void *pv) const { return *static_cast(pv); } }; template struct value_wrapper : private noncopyable { value_wrapper() : value() {} value_wrapper(T const &t) : value(t) {} T value; }; struct check_tag {}; struct BindArg { BOOST_PROTO_CALLABLE() template struct result; template struct result { typedef Expr type; }; template Expr const & operator ()(MatchResults &what, Expr const &expr) const { what.let(expr); return expr; } }; struct let_tag {}; // let(_a = b, _c = d) struct BindArgs : proto::function< proto::terminal , proto::vararg< proto::when< proto::assign , proto::call > > > {}; struct let_domain : boost::proto::domain > {}; template struct let_ { BOOST_PROTO_BASIC_EXTENDS(Expr, let_, let_domain) BOOST_PROTO_EXTENDS_FUNCTION() }; template void bind_args(let_ const &args, match_results &what) { BindArgs()(args, 0, what); } typedef boost::proto::functional::make_expr make_function; } namespace op { struct at { BOOST_PROTO_CALLABLE() template struct result; template struct result : result { }; template struct result { typedef typename Cont::reference type; }; template struct result { typedef typename Cont::const_reference type; }; template typename Cont::reference operator()(Cont &c, Idx idx BOOST_PROTO_DISABLE_IF_IS_CONST(Cont)) const { return c[idx]; } template typename Cont::const_reference operator()(Cont const &c, Idx idx) const { return c[idx]; } }; struct push { BOOST_PROTO_CALLABLE() typedef void result_type; template void operator()(Sequence &seq, Value const &val) const { seq.push(val); } }; struct push_back { BOOST_PROTO_CALLABLE() typedef void result_type; template void operator()(Sequence &seq, Value const &val) const { seq.push_back(val); } }; struct push_front { BOOST_PROTO_CALLABLE() typedef void result_type; template void operator()(Sequence &seq, Value const &val) const { seq.push_front(val); } }; struct pop { BOOST_PROTO_CALLABLE() typedef void result_type; template void operator()(Sequence &seq) const { seq.pop(); } }; struct pop_back { BOOST_PROTO_CALLABLE() typedef void result_type; template void operator()(Sequence &seq) const { seq.pop_back(); } }; struct pop_front { BOOST_PROTO_CALLABLE() typedef void result_type; template void operator()(Sequence &seq) const { seq.pop_front(); } }; struct front { BOOST_PROTO_CALLABLE() template struct result {}; template struct result { typedef UNREF(Sequence) sequence_type; typedef typename mpl::if_c< is_const::value , typename sequence_type::const_reference , typename sequence_type::reference >::type type; }; template typename result::type operator()(Sequence &seq) const { return seq.front(); } }; struct back { BOOST_PROTO_CALLABLE() template struct result {}; template struct result { typedef UNREF(Sequence) sequence_type; typedef typename mpl::if_c< is_const::value , typename sequence_type::const_reference , typename sequence_type::reference >::type type; }; template typename result::type operator()(Sequence &seq) const { return seq.back(); } }; struct top { BOOST_PROTO_CALLABLE() template struct result {}; template struct result { typedef UNREF(Sequence) sequence_type; typedef typename mpl::if_c< is_const::value , typename sequence_type::value_type const & , typename sequence_type::value_type & >::type type; }; template typename result::type operator()(Sequence &seq) const { return seq.top(); } }; struct first { BOOST_PROTO_CALLABLE() template struct result {}; template struct result { typedef UNREF(Pair)::first_type type; }; template typename Pair::first_type operator()(Pair const &p) const { return p.first; } }; struct second { BOOST_PROTO_CALLABLE() template struct result {}; template struct result { typedef UNREF(Pair)::second_type type; }; template typename Pair::second_type operator()(Pair const &p) const { return p.second; } }; struct matched { BOOST_PROTO_CALLABLE() typedef bool result_type; template bool operator()(Sub const &sub) const { return sub.matched; } }; struct length { BOOST_PROTO_CALLABLE() template struct result {}; template struct result { typedef UNREF(Sub)::difference_type type; }; template typename Sub::difference_type operator()(Sub const &sub) const { return sub.length(); } }; struct str { BOOST_PROTO_CALLABLE() template struct result {}; template struct result { typedef UNREF(Sub)::string_type type; }; template typename Sub::string_type operator()(Sub const &sub) const { return sub.str(); } }; // This codifies the return types of the various insert member // functions found in sequence containers, the 2 flavors of // associative containers, and strings. struct insert { BOOST_PROTO_CALLABLE() template struct result {}; // assoc containers template struct result { typedef UNREF(Cont) cont_type; typedef UNREF(Value) value_type; static cont_type &scont_; static value_type &svalue_; typedef char yes_type; typedef char (&no_type)[2]; static yes_type check_insert_return(typename cont_type::iterator); static no_type check_insert_return(std::pair); BOOST_STATIC_CONSTANT(bool, is_iterator = (sizeof(yes_type) == sizeof(check_insert_return(scont_.insert(svalue_))))); typedef typename mpl::if_c< is_iterator , typename cont_type::iterator , std::pair >::type type; }; // sequence containers, assoc containers, strings template struct result, is_same > >::type> { typedef UNREF(Cont)::iterator type; }; // strings template struct result >::type> { typedef UNREF(Cont) &type; }; // assoc containers template struct result { typedef void type; }; // sequence containers, strings template struct result >::type> { typedef void type; }; // strings template struct result >::type> { typedef UNREF(Cont) &type; }; /// operator() /// template typename result::type operator()(Cont &cont, A0 const &a0) const { return cont.insert(a0); } /// \overload /// template typename result::type operator()(Cont &cont, A0 const &a0, A1 const &a1) const { return cont.insert(a0, a1); } /// \overload /// template typename result::type operator()(Cont &cont, A0 const &a0, A1 const &a1, A2 const &a2) const { return cont.insert(a0, a1, a2); } }; struct make_pair { BOOST_PROTO_CALLABLE() template struct result {}; template struct result { typedef std::pair type; }; template std::pair operator()(First const &first, Second const &second) const { return std::make_pair(first, second); } }; template struct as { BOOST_PROTO_CALLABLE() typedef T result_type; template T operator()(Value const &val) const { return boost::lexical_cast(val); } // Hack around some limitations in boost::lexical_cast T operator()(csub_match const &val) const { return val.matched ? boost::lexical_cast(boost::make_iterator_range(val.first, val.second)) : boost::lexical_cast(""); } #ifndef BOOST_XPRESSIVE_NO_WREGEX T operator()(wcsub_match const &val) const { return val.matched ? boost::lexical_cast(boost::make_iterator_range(val.first, val.second)) : boost::lexical_cast(""); } #endif template T operator()(sub_match const &val) const { // If this assert fires, you're trying to coerce a sequences of non-characters // to some other type. Xpressive doesn't know how to do that. typedef typename iterator_value::type char_type; BOOST_MPL_ASSERT_MSG( (xpressive::detail::is_char::value) , CAN_ONLY_CONVERT_FROM_CHARACTER_SEQUENCES , (char_type) ); return this->impl(val, xpressive::detail::is_string_iterator()); } private: template T impl(sub_match const &val, mpl::true_) const { return val.matched ? boost::lexical_cast(boost::make_iterator_range(&*val.first, &*val.first + (val.second - val.first))) : boost::lexical_cast(""); } template T impl(sub_match const &val, mpl::false_) const { return boost::lexical_cast(val.str()); } }; template struct static_cast_ { BOOST_PROTO_CALLABLE() typedef T result_type; template T operator()(Value const &val) const { return static_cast(val); } }; template struct dynamic_cast_ { BOOST_PROTO_CALLABLE() typedef T result_type; template T operator()(Value const &val) const { return dynamic_cast(val); } }; template struct const_cast_ { BOOST_PROTO_CALLABLE() typedef T result_type; template T operator()(Value const &val) const { return const_cast(val); } }; template struct construct { BOOST_PROTO_CALLABLE() typedef T result_type; T operator()() const { return T(); } template T operator()(A0 const &a0) const { return T(a0); } template T operator()(A0 const &a0, A1 const &a1) const { return T(a0, a1); } template T operator()(A0 const &a0, A1 const &a1, A2 const &a2) const { return T(a0, a1, a2); } }; template struct throw_ { BOOST_PROTO_CALLABLE() typedef void result_type; void operator()() const { BOOST_THROW_EXCEPTION(Except()); } template void operator()(A0 const &a0) const { BOOST_THROW_EXCEPTION(Except(a0)); } template void operator()(A0 const &a0, A1 const &a1) const { BOOST_THROW_EXCEPTION(Except(a0, a1)); } template void operator()(A0 const &a0, A1 const &a1, A2 const &a2) const { BOOST_THROW_EXCEPTION(Except(a0, a1, a2)); } }; struct unwrap_reference { BOOST_PROTO_CALLABLE() template struct result; template struct result { typedef typename boost::unwrap_reference::type &type; }; template struct result { typedef typename boost::unwrap_reference::type &type; }; template T &operator()(boost::reference_wrapper r) const { return static_cast(r); } }; } template struct function { typedef typename proto::terminal::type type; }; function::type const at = {{}}; function::type const push = {{}}; function::type const push_back = {{}}; function::type const push_front = {{}}; function::type const pop = {{}}; function::type const pop_back = {{}}; function::type const pop_front = {{}}; function::type const top = {{}}; function::type const back = {{}}; function::type const front = {{}}; function::type const first = {{}}; function::type const second = {{}}; function::type const matched = {{}}; function::type const length = {{}}; function::type const str = {{}}; function::type const insert = {{}}; function::type const make_pair = {{}}; function::type const unwrap_reference = {{}}; template struct value : proto::extends::type, value > { typedef proto::extends::type, value > base_type; value() : base_type() {} explicit value(T const &t) : base_type(base_type::proto_base_expr::make(t)) {} using base_type::operator =; T &get() { return proto::value(*this); } T const &get() const { return proto::value(*this); } }; template struct reference : proto::extends >::type, reference > { typedef proto::extends >::type, reference > base_type; explicit reference(T &t) : base_type(base_type::proto_base_expr::make(boost::ref(t))) {} using base_type::operator =; T &get() const { return proto::value(*this).get(); } }; template struct local : detail::value_wrapper , proto::terminal >::type { typedef typename proto::terminal >::type base_type; local() : detail::value_wrapper() , base_type(base_type::make(boost::ref(detail::value_wrapper::value))) {} explicit local(T const &t) : detail::value_wrapper(t) , base_type(base_type::make(boost::ref(detail::value_wrapper::value))) {} using base_type::operator =; T &get() { return proto::value(*this); } T const &get() const { return proto::value(*this); } }; /// as (a.k.a., lexical_cast) /// template typename detail::make_function::impl const, A0 const &>::result_type const as(A0 const &a0) { return detail::make_function::impl const, A0 const &>()((op::as()), a0); } /// static_cast_ /// template typename detail::make_function::impl const, A0 const &>::result_type const static_cast_(A0 const &a0) { return detail::make_function::impl const, A0 const &>()((op::static_cast_()), a0); } /// dynamic_cast_ /// template typename detail::make_function::impl const, A0 const &>::result_type const dynamic_cast_(A0 const &a0) { return detail::make_function::impl const, A0 const &>()((op::dynamic_cast_()), a0); } /// const_cast_ /// template typename detail::make_function::impl const, A0 const &>::result_type const const_cast_(A0 const &a0) { return detail::make_function::impl const, A0 const &>()((op::const_cast_()), a0); } /// val() /// template value const val(T const &t) { return value(t); } /// ref() /// template reference const ref(T &t) { return reference(t); } /// cref() /// template reference const cref(T const &t) { return reference(t); } /// check(), for testing custom assertions /// proto::terminal::type const check = {{}}; /// let(), for binding references to non-local variables /// detail::let_::type> const let = {{{}}}; /// placeholder, for defining a placeholder to stand in fo /// a variable of type T in a semantic action. /// template struct placeholder { typedef placeholder this_type; typedef typename proto::terminal > >::type action_arg_type; BOOST_PROTO_EXTENDS(action_arg_type, this_type, proto::default_domain) }; /// Usage: construct\(arg1, arg2) /// /// Usage: throw_\(arg1, arg2) /// #define BOOST_PROTO_LOCAL_MACRO(N, typename_A, A_const_ref, A_const_ref_a, a)\ \ template\ typename detail::make_function::impl const BOOST_PP_COMMA_IF(N) A_const_ref(N)>::result_type const\ construct(A_const_ref_a(N))\ {\ return detail::make_function::impl const BOOST_PP_COMMA_IF(N) A_const_ref(N)>()((op::construct()) BOOST_PP_COMMA_IF(N) a(N));\ }\ \ template\ typename detail::make_function::impl const BOOST_PP_COMMA_IF(N) A_const_ref(N)>::result_type const\ throw_(A_const_ref_a(N))\ {\ return detail::make_function::impl const BOOST_PP_COMMA_IF(N) A_const_ref(N)>()((op::throw_()) BOOST_PP_COMMA_IF(N) a(N));\ }\ /**/ #define BOOST_PROTO_LOCAL_a BOOST_PROTO_a #define BOOST_PROTO_LOCAL_LIMITS (0, BOOST_PP_DEC(BOOST_PROTO_MAX_ARITY)) #include BOOST_PROTO_LOCAL_ITERATE() namespace detail { inline void ignore_unused_regex_actions() { detail::ignore_unused(xpressive::at); detail::ignore_unused(xpressive::push); detail::ignore_unused(xpressive::push_back); detail::ignore_unused(xpressive::push_front); detail::ignore_unused(xpressive::pop); detail::ignore_unused(xpressive::pop_back); detail::ignore_unused(xpressive::pop_front); detail::ignore_unused(xpressive::top); detail::ignore_unused(xpressive::back); detail::ignore_unused(xpressive::front); detail::ignore_unused(xpressive::first); detail::ignore_unused(xpressive::second); detail::ignore_unused(xpressive::matched); detail::ignore_unused(xpressive::length); detail::ignore_unused(xpressive::str); detail::ignore_unused(xpressive::insert); detail::ignore_unused(xpressive::make_pair); detail::ignore_unused(xpressive::unwrap_reference); detail::ignore_unused(xpressive::check); detail::ignore_unused(xpressive::let); } struct mark_nbr { BOOST_PROTO_CALLABLE() typedef int result_type; int operator()(mark_placeholder m) const { return m.mark_number_; } }; struct ReplaceAlgo : proto::or_< proto::when< proto::terminal , op::at(proto::_data, proto::call) > , proto::when< proto::terminal , op::at(proto::_data, proto::size_t<0>) > , proto::when< proto::terminal > , op::unwrap_reference(proto::_value) > , proto::_default > {}; } }} #undef UNREF #undef UNCVREF #if BOOST_MSVC #pragma warning(pop) #endif #endif // BOOST_XPRESSIVE_ACTIONS_HPP_EAN_03_22_2007