| 1 | /////////////////////////////////////////////////////////////////////////////// |
| 2 | /// \file when.hpp |
| 3 | /// Definition of when transform. |
| 4 | // |
| 5 | // Copyright 2008 Eric Niebler. Distributed under the Boost |
| 6 | // Software License, Version 1.0. (See accompanying file |
| 7 | // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) |
| 8 | |
| 9 | #ifndef BOOST_PROTO_TRANSFORM_WHEN_HPP_EAN_10_29_2007 |
| 10 | #define BOOST_PROTO_TRANSFORM_WHEN_HPP_EAN_10_29_2007 |
| 11 | |
| 12 | #include <boost/preprocessor/cat.hpp> |
| 13 | #include <boost/preprocessor/repetition/enum_params.hpp> |
| 14 | #include <boost/preprocessor/repetition/enum_trailing_params.hpp> |
| 15 | #include <boost/preprocessor/iteration/iterate.hpp> |
| 16 | #include <boost/mpl/at.hpp> |
| 17 | #include <boost/mpl/if.hpp> |
| 18 | #include <boost/mpl/map.hpp> |
| 19 | #include <boost/mpl/eval_if.hpp> |
| 20 | #include <boost/proto/proto_fwd.hpp> |
| 21 | #include <boost/proto/traits.hpp> |
| 22 | #include <boost/proto/transform/call.hpp> |
| 23 | #include <boost/proto/transform/make.hpp> |
| 24 | #include <boost/proto/transform/impl.hpp> |
| 25 | #include <boost/proto/transform/env.hpp> |
| 26 | |
| 27 | #if defined(_MSC_VER) |
| 28 | # pragma warning(push) |
| 29 | # pragma warning(disable : 4714) // function 'xxx' marked as __forceinline not inlined |
| 30 | #endif |
| 31 | |
| 32 | namespace boost { namespace proto |
| 33 | { |
| 34 | namespace detail |
| 35 | { |
| 36 | template<typename Grammar, typename R, typename Fun> |
| 37 | struct when_impl |
| 38 | : transform<when<Grammar, Fun> > |
| 39 | { |
| 40 | typedef Grammar first; |
| 41 | typedef Fun second; |
| 42 | typedef typename Grammar::proto_grammar proto_grammar; |
| 43 | |
| 44 | // Note: do not evaluate is_callable<R> in this scope. |
| 45 | // R may be an incomplete type at this point. |
| 46 | |
| 47 | template<typename Expr, typename State, typename Data> |
| 48 | struct impl : transform_impl<Expr, State, Data> |
| 49 | { |
| 50 | // OK to evaluate is_callable<R> here. R should be compete by now. |
| 51 | typedef |
| 52 | typename mpl::if_c< |
| 53 | is_callable<R>::value |
| 54 | , proto::call<Fun> // "R" is a function to call |
| 55 | , proto::make<Fun> // "R" is an object to construct |
| 56 | >::type |
| 57 | which; |
| 58 | |
| 59 | typedef typename which::template impl<Expr, State, Data>::result_type result_type; |
| 60 | |
| 61 | /// Evaluate <tt>R(A0,A1,...)</tt> as a transform either with |
| 62 | /// <tt>call\<\></tt> or with <tt>make\<\></tt> depending on |
| 63 | /// whether <tt>is_callable\<R\>::value</tt> is \c true or |
| 64 | /// \c false. |
| 65 | /// |
| 66 | /// \param e The current expression |
| 67 | /// \param s The current state |
| 68 | /// \param d An arbitrary data |
| 69 | /// \pre <tt>matches\<Expr, Grammar\>::value</tt> is \c true |
| 70 | /// \return <tt>which()(e, s, d)</tt> |
| 71 | BOOST_FORCEINLINE |
| 72 | result_type operator ()( |
| 73 | typename impl::expr_param e |
| 74 | , typename impl::state_param s |
| 75 | , typename impl::data_param d |
| 76 | ) const |
| 77 | { |
| 78 | return typename which::template impl<Expr, State, Data>()(e, s, d); |
| 79 | } |
| 80 | }; |
| 81 | }; |
| 82 | } |
| 83 | |
| 84 | /// \brief A grammar element and a PrimitiveTransform that associates |
| 85 | /// a transform with the grammar. |
| 86 | /// |
| 87 | /// Use <tt>when\<\></tt> to override a grammar's default transform |
| 88 | /// with a custom transform. It is for used when composing larger |
| 89 | /// transforms by associating smaller transforms with individual |
| 90 | /// rules in your grammar, as in the following transform which |
| 91 | /// counts the number of terminals in an expression. |
| 92 | /// |
| 93 | /// \code |
| 94 | /// // Count the terminals in an expression tree. |
| 95 | /// // Must be invoked with initial state == mpl::int_<0>(). |
| 96 | /// struct CountLeaves |
| 97 | /// : or_< |
| 98 | /// when<terminal<_>, mpl::next<_state>()> |
| 99 | /// , otherwise<fold<_, _state, CountLeaves> > |
| 100 | /// > |
| 101 | /// {}; |
| 102 | /// \endcode |
| 103 | /// |
| 104 | /// In <tt>when\<G, T\></tt>, when \c T is a class type it is a |
| 105 | /// PrimitiveTransform and the following equivalencies hold: |
| 106 | /// |
| 107 | /// <tt>boost::result_of\<when\<G,T\>(E,S,V)\>::type</tt> is the same as |
| 108 | /// <tt>boost::result_of\<T(E,S,V)\>::type</tt>. |
| 109 | /// |
| 110 | /// <tt>when\<G,T\>()(e,s,d)</tt> is the same as |
| 111 | /// <tt>T()(e,s,d)</tt>. |
| 112 | template<typename Grammar, typename PrimitiveTransform /*= Grammar*/> |
| 113 | struct when |
| 114 | : PrimitiveTransform |
| 115 | { |
| 116 | typedef Grammar first; |
| 117 | typedef PrimitiveTransform second; |
| 118 | typedef typename Grammar::proto_grammar proto_grammar; |
| 119 | }; |
| 120 | |
| 121 | /// \brief A specialization that treats function pointer Transforms as |
| 122 | /// if they were function type Transforms. |
| 123 | /// |
| 124 | /// This specialization requires that \c Fun is actually a function type. |
| 125 | /// |
| 126 | /// This specialization is required for nested transforms such as |
| 127 | /// <tt>when\<G, T0(T1(_))\></tt>. In C++, functions that are used as |
| 128 | /// parameters to other functions automatically decay to funtion |
| 129 | /// pointer types. In other words, the type <tt>T0(T1(_))</tt> is |
| 130 | /// indistinguishable from <tt>T0(T1(*)(_))</tt>. This specialization |
| 131 | /// is required to handle these nested function pointer type transforms |
| 132 | /// properly. |
| 133 | template<typename Grammar, typename Fun> |
| 134 | struct when<Grammar, Fun *> |
| 135 | : when<Grammar, Fun> |
| 136 | {}; |
| 137 | |
| 138 | /// \brief Syntactic sugar for <tt>when\<_, Fun\></tt>, for use |
| 139 | /// in grammars to handle all the cases not yet handled. |
| 140 | /// |
| 141 | /// Use <tt>otherwise\<T\></tt> in your grammars as a synonym for |
| 142 | /// <tt>when\<_, T\></tt> as in the following transform which |
| 143 | /// counts the number of terminals in an expression. |
| 144 | /// |
| 145 | /// \code |
| 146 | /// // Count the terminals in an expression tree. |
| 147 | /// // Must be invoked with initial state == mpl::int_<0>(). |
| 148 | /// struct CountLeaves |
| 149 | /// : or_< |
| 150 | /// when<terminal<_>, mpl::next<_state>()> |
| 151 | /// , otherwise<fold<_, _state, CountLeaves> > |
| 152 | /// > |
| 153 | /// {}; |
| 154 | /// \endcode |
| 155 | template<typename Fun> |
| 156 | struct otherwise |
| 157 | : when<_, Fun> |
| 158 | {}; |
| 159 | |
| 160 | namespace envns_ |
| 161 | { |
| 162 | // Define the transforms global |
| 163 | BOOST_PROTO_DEFINE_ENV_VAR(transforms_type, transforms); |
| 164 | } |
| 165 | |
| 166 | using envns_::transforms; |
| 167 | |
| 168 | /// \brief This specialization uses the Data parameter as a collection |
| 169 | /// of transforms that can be indexed by the specified rule. |
| 170 | /// |
| 171 | /// Use <tt>when\<T, external_transform\></tt> in your code when you would like |
| 172 | /// to define a grammar once and use it to evaluate expressions with |
| 173 | /// many different sets of transforms. The transforms are found by |
| 174 | /// using the Data parameter as a map from rules to transforms. |
| 175 | /// |
| 176 | /// See \c action_map for an example. |
| 177 | template<typename Grammar> |
| 178 | struct when<Grammar, external_transform> |
| 179 | : proto::transform<when<Grammar, external_transform> > |
| 180 | { |
| 181 | typedef Grammar first; |
| 182 | typedef external_transform second; |
| 183 | typedef typename Grammar::proto_grammar proto_grammar; |
| 184 | |
| 185 | template<typename Expr, typename State, typename Data> |
| 186 | struct impl |
| 187 | : remove_reference< |
| 188 | typename mpl::eval_if_c< |
| 189 | proto::result_of::has_env_var<Data, transforms_type>::value |
| 190 | , proto::result_of::env_var<Data, transforms_type> |
| 191 | , proto::result_of::env_var<Data, data_type> |
| 192 | >::type |
| 193 | >::type::template when<Grammar>::template impl<Expr, State, Data> |
| 194 | {}; |
| 195 | }; |
| 196 | |
| 197 | /// \brief For defining a map of Rule/Transform pairs for use with |
| 198 | /// <tt>when\<T, external_transform\></tt> to make transforms external to the grammar |
| 199 | /// |
| 200 | /// The following code defines a grammar with a couple of external transforms. |
| 201 | /// It also defines an action_map that maps from rules to transforms. It then |
| 202 | /// passes that transforms map at the Data parameter to the grammar. In this way, |
| 203 | /// the behavior of the grammar can be modified post-hoc by passing a different |
| 204 | /// action_map. |
| 205 | /// |
| 206 | /// \code |
| 207 | /// struct int_terminal |
| 208 | /// : proto::terminal<int> |
| 209 | /// {}; |
| 210 | /// |
| 211 | /// struct char_terminal |
| 212 | /// : proto::terminal<char> |
| 213 | /// {}; |
| 214 | /// |
| 215 | /// struct my_grammar |
| 216 | /// : proto::or_< |
| 217 | /// proto::when< int_terminal, proto::external_transform > |
| 218 | /// , proto::when< char_terminal, proto::external_transform > |
| 219 | /// , proto::when< |
| 220 | /// proto::plus< my_grammar, my_grammar > |
| 221 | /// , proto::fold< _, int(), my_grammar > |
| 222 | /// > |
| 223 | /// > |
| 224 | /// {}; |
| 225 | /// |
| 226 | /// struct my_transforms |
| 227 | /// : proto::external_transforms< |
| 228 | /// proto::when<int_terminal, print(proto::_value)> |
| 229 | /// , proto::when<char_terminal, print(proto::_value)> |
| 230 | /// > |
| 231 | /// {}; |
| 232 | /// |
| 233 | /// proto::literal<int> i(1); |
| 234 | /// proto::literal<char> c('a'); |
| 235 | /// my_transforms trx; |
| 236 | /// |
| 237 | /// // Evaluate "i+c" using my_grammar with the specified transforms: |
| 238 | /// my_grammar()(i + c, 0, trx); |
| 239 | /// \endcode |
| 240 | template<BOOST_PP_ENUM_PARAMS_WITH_A_DEFAULT(BOOST_MPL_LIMIT_MAP_SIZE, typename T, mpl::na)> |
| 241 | struct external_transforms |
| 242 | { |
| 243 | typedef mpl::map<BOOST_PP_ENUM_PARAMS(BOOST_MPL_LIMIT_MAP_SIZE, T)> map_type; |
| 244 | |
| 245 | template<typename Rule> |
| 246 | struct when |
| 247 | : proto::when<_, typename mpl::at<map_type, Rule>::type> |
| 248 | {}; |
| 249 | }; |
| 250 | |
| 251 | // Other specializations of proto::when are generated by the preprocessor... |
| 252 | #include <boost/proto/transform/detail/when.hpp> |
| 253 | |
| 254 | /// INTERNAL ONLY |
| 255 | /// |
| 256 | template<typename Grammar, typename Transform> |
| 257 | struct is_callable<when<Grammar, Transform> > |
| 258 | : mpl::true_ |
| 259 | {}; |
| 260 | |
| 261 | }} // namespace boost::proto |
| 262 | |
| 263 | #if defined(_MSC_VER) |
| 264 | # pragma warning(pop) |
| 265 | #endif |
| 266 | |
| 267 | #endif |
| 268 | |