#ifndef BOOST_PP_IS_ITERATING /////////////////////////////////////////////////////////////////////////////// /// \file when.hpp /// Definition of when transform. // // 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_PROTO_TRANSFORM_WHEN_HPP_EAN_10_29_2007 #define BOOST_PROTO_TRANSFORM_WHEN_HPP_EAN_10_29_2007 #include #include #include #include #include #include #include #include #include #include #include namespace boost { namespace proto { namespace transform { /// \brief A grammar element and a PrimitiveTransform that associates /// a transform with the grammar. /// /// Use when\<\> to override a grammar's default transform /// with a custom transform. It is for used when composing larger /// transforms by associating smaller transforms with individual /// rules in your grammar, as in the following transform which /// counts the number of terminals in an expression. /// /// \code /// // Count the terminals in an expression tree. /// // Must be invoked with initial state == mpl::int_<0>(). /// struct CountLeaves /// : or_< /// when, mpl::next<_state>()> /// , otherwise > /// > /// {}; /// \endcode /// /// In when\, when \c T is a class type it is a /// PrimitiveTransform and the following equivalencies hold: /// /// when\::::result\::::type is the same as /// T::result\::::type. /// /// when\()(e,s,v) is the same as /// T()(e,s,v). template struct when : PrimitiveTransform { typedef typename Grammar::proto_base_expr proto_base_expr; }; /// \brief A specialization that treats function pointer Transforms as /// if they were function type Transforms. /// /// This specialization requires that \c Fun is actually a function type. /// /// This specialization is required for nested transforms such as /// when\. In C++, functions that are used as /// parameters to other functions automatically decay to funtion /// pointer types. In other words, the type T0(T1(_)) is /// indistinguishable from T0(T1(*)(_)). This specialization /// is required to handle these nested function pointer type transforms /// properly. template struct when : when {}; /// \brief Syntactic sugar for when\<_, Fun\>, for use /// in grammars to handle all the cases not yet handled. /// /// Use otherwise\ in your grammars as a synonym for /// when\<_, T\> as in the following transform which /// counts the number of terminals in an expression. /// /// \code /// // Count the terminals in an expression tree. /// // Must be invoked with initial state == mpl::int_<0>(). /// struct CountLeaves /// : or_< /// when, mpl::next<_state>()> /// , otherwise > /// > /// {}; /// \endcode template struct otherwise : when<_, Fun> {}; #define BOOST_PP_ITERATION_PARAMS_1 (3, (0, BOOST_PROTO_MAX_ARITY, )) #include BOOST_PP_ITERATE() }}} // namespace boost::proto::transform #endif #else #define N BOOST_PP_ITERATION() /// \brief A grammar element and a PrimitiveTransform that associates /// a transform with the grammar. /// /// Use when\<\> to override a grammar's default transform /// with a custom transform. It is for used when composing larger /// transforms by associating smaller transforms with individual /// rules in your grammar, as in the following transform which /// counts the number of terminals in an expression. /// /// \code /// // Count the terminals in an expression tree. /// // Must be invoked with initial state == mpl::int_<0>(). /// struct CountLeaves /// : or_< /// when, mpl::next<_state>()> /// , otherwise > /// > /// {}; /// \endcode /// /// The when\ form accepts either a /// CallableTransform or an ObjectTransform as its second parameter. /// when\<\> uses is_callable\::::value to /// distinguish between the two, and uses call\<\> to /// evaluate CallableTransforms and make\<\> to evaluate /// ObjectTransforms. template struct when : proto::callable { typedef typename Grammar::proto_base_expr proto_base_expr; // Note: do not evaluate is_callable in this scope. // R may be an incomplete type at this point. template struct result; template struct result { typedef call call_; typedef make make_; typedef typename mpl::if_c< // OK to evaluate is_callable here. // R should be compete by now. is_callable::value , call_ // "R" is a function to call , make_ // "R" is an object to construct >::type impl; typedef typename impl::template result::type type; }; /// Evaluate R(A0,A1,...) as a transform either with /// call\<\> or with make\<\> depending on /// whether is_callable\::::value is \c true or /// \c false. /// /// \param expr The current expression /// \param state The current state /// \param visitor An arbitrary visitor /// \pre matches\::::value is \c true /// \return result\::::impl()(expr, state, visitor) template typename result::type operator ()(Expr const &expr, State const &state, Visitor &visitor) const { return typename result::impl()(expr, state, visitor); } }; #undef N #endif