Chris@16: /////////////////////////////////////////////////////////////////////////////// Chris@16: /// \file when.hpp Chris@16: /// Definition of when transform. Chris@16: // Chris@16: // Copyright 2008 Eric Niebler. Distributed under the Boost Chris@16: // Software License, Version 1.0. (See accompanying file Chris@16: // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) Chris@16: Chris@16: #ifndef BOOST_PROTO_TRANSFORM_WHEN_HPP_EAN_10_29_2007 Chris@16: #define BOOST_PROTO_TRANSFORM_WHEN_HPP_EAN_10_29_2007 Chris@16: Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: Chris@101: #if defined(_MSC_VER) Chris@16: # pragma warning(push) Chris@16: # pragma warning(disable : 4714) // function 'xxx' marked as __forceinline not inlined Chris@16: #endif Chris@16: Chris@16: namespace boost { namespace proto Chris@16: { Chris@16: namespace detail Chris@16: { Chris@16: template Chris@16: struct when_impl Chris@16: : transform > Chris@16: { Chris@16: typedef Grammar first; Chris@16: typedef Fun second; Chris@16: typedef typename Grammar::proto_grammar proto_grammar; Chris@16: Chris@16: // Note: do not evaluate is_callable in this scope. Chris@16: // R may be an incomplete type at this point. Chris@16: Chris@16: template Chris@16: struct impl : transform_impl Chris@16: { Chris@16: // OK to evaluate is_callable here. R should be compete by now. Chris@16: typedef Chris@16: typename mpl::if_c< Chris@16: is_callable::value Chris@16: , proto::call // "R" is a function to call Chris@16: , proto::make // "R" is an object to construct Chris@16: >::type Chris@16: which; Chris@16: Chris@16: typedef typename which::template impl::result_type result_type; Chris@16: Chris@16: /// Evaluate R(A0,A1,...) as a transform either with Chris@16: /// call\<\> or with make\<\> depending on Chris@16: /// whether is_callable\::value is \c true or Chris@16: /// \c false. Chris@16: /// Chris@16: /// \param e The current expression Chris@16: /// \param s The current state Chris@16: /// \param d An arbitrary data Chris@16: /// \pre matches\::value is \c true Chris@16: /// \return which()(e, s, d) Chris@16: BOOST_FORCEINLINE Chris@16: result_type operator ()( Chris@16: typename impl::expr_param e Chris@16: , typename impl::state_param s Chris@16: , typename impl::data_param d Chris@16: ) const Chris@16: { Chris@16: return typename which::template impl()(e, s, d); Chris@16: } Chris@16: }; Chris@16: }; Chris@16: } Chris@16: Chris@16: /// \brief A grammar element and a PrimitiveTransform that associates Chris@16: /// a transform with the grammar. Chris@16: /// Chris@16: /// Use when\<\> to override a grammar's default transform Chris@16: /// with a custom transform. It is for used when composing larger Chris@16: /// transforms by associating smaller transforms with individual Chris@16: /// rules in your grammar, as in the following transform which Chris@16: /// counts the number of terminals in an expression. Chris@16: /// Chris@16: /// \code Chris@16: /// // Count the terminals in an expression tree. Chris@16: /// // Must be invoked with initial state == mpl::int_<0>(). Chris@16: /// struct CountLeaves Chris@16: /// : or_< Chris@16: /// when, mpl::next<_state>()> Chris@16: /// , otherwise > Chris@16: /// > Chris@16: /// {}; Chris@16: /// \endcode Chris@16: /// Chris@16: /// In when\, when \c T is a class type it is a Chris@16: /// PrimitiveTransform and the following equivalencies hold: Chris@16: /// Chris@16: /// boost::result_of\(E,S,V)\>::type is the same as Chris@16: /// boost::result_of\::type. Chris@16: /// Chris@16: /// when\()(e,s,d) is the same as Chris@16: /// T()(e,s,d). Chris@16: template Chris@16: struct when Chris@16: : PrimitiveTransform Chris@16: { Chris@16: typedef Grammar first; Chris@16: typedef PrimitiveTransform second; Chris@16: typedef typename Grammar::proto_grammar proto_grammar; Chris@16: }; Chris@16: Chris@16: /// \brief A specialization that treats function pointer Transforms as Chris@16: /// if they were function type Transforms. Chris@16: /// Chris@16: /// This specialization requires that \c Fun is actually a function type. Chris@16: /// Chris@16: /// This specialization is required for nested transforms such as Chris@16: /// when\. In C++, functions that are used as Chris@16: /// parameters to other functions automatically decay to funtion Chris@16: /// pointer types. In other words, the type T0(T1(_)) is Chris@16: /// indistinguishable from T0(T1(*)(_)). This specialization Chris@16: /// is required to handle these nested function pointer type transforms Chris@16: /// properly. Chris@16: template Chris@16: struct when Chris@16: : when Chris@16: {}; Chris@16: Chris@16: /// \brief Syntactic sugar for when\<_, Fun\>, for use Chris@16: /// in grammars to handle all the cases not yet handled. Chris@16: /// Chris@16: /// Use otherwise\ in your grammars as a synonym for Chris@16: /// when\<_, T\> as in the following transform which Chris@16: /// counts the number of terminals in an expression. Chris@16: /// Chris@16: /// \code Chris@16: /// // Count the terminals in an expression tree. Chris@16: /// // Must be invoked with initial state == mpl::int_<0>(). Chris@16: /// struct CountLeaves Chris@16: /// : or_< Chris@16: /// when, mpl::next<_state>()> Chris@16: /// , otherwise > Chris@16: /// > Chris@16: /// {}; Chris@16: /// \endcode Chris@16: template Chris@16: struct otherwise Chris@16: : when<_, Fun> Chris@16: {}; Chris@16: Chris@16: namespace envns_ Chris@16: { Chris@16: // Define the transforms global Chris@16: BOOST_PROTO_DEFINE_ENV_VAR(transforms_type, transforms); Chris@16: } Chris@16: Chris@16: using envns_::transforms; Chris@16: Chris@16: /// \brief This specialization uses the Data parameter as a collection Chris@16: /// of transforms that can be indexed by the specified rule. Chris@16: /// Chris@16: /// Use when\ in your code when you would like Chris@16: /// to define a grammar once and use it to evaluate expressions with Chris@16: /// many different sets of transforms. The transforms are found by Chris@16: /// using the Data parameter as a map from rules to transforms. Chris@16: /// Chris@16: /// See \c action_map for an example. Chris@16: template Chris@16: struct when Chris@16: : proto::transform > Chris@16: { Chris@16: typedef Grammar first; Chris@16: typedef external_transform second; Chris@16: typedef typename Grammar::proto_grammar proto_grammar; Chris@16: Chris@16: template Chris@16: struct impl Chris@16: : remove_reference< Chris@16: typename mpl::eval_if_c< Chris@16: proto::result_of::has_env_var::value Chris@16: , proto::result_of::env_var Chris@16: , proto::result_of::env_var Chris@16: >::type Chris@16: >::type::template when::template impl Chris@16: {}; Chris@16: }; Chris@16: Chris@16: /// \brief For defining a map of Rule/Transform pairs for use with Chris@16: /// when\ to make transforms external to the grammar Chris@16: /// Chris@16: /// The following code defines a grammar with a couple of external transforms. Chris@16: /// It also defines an action_map that maps from rules to transforms. It then Chris@16: /// passes that transforms map at the Data parameter to the grammar. In this way, Chris@16: /// the behavior of the grammar can be modified post-hoc by passing a different Chris@16: /// action_map. Chris@16: /// Chris@16: /// \code Chris@16: /// struct int_terminal Chris@16: /// : proto::terminal Chris@16: /// {}; Chris@16: /// Chris@16: /// struct char_terminal Chris@16: /// : proto::terminal Chris@16: /// {}; Chris@16: /// Chris@16: /// struct my_grammar Chris@16: /// : proto::or_< Chris@16: /// proto::when< int_terminal, proto::external_transform > Chris@16: /// , proto::when< char_terminal, proto::external_transform > Chris@16: /// , proto::when< Chris@16: /// proto::plus< my_grammar, my_grammar > Chris@16: /// , proto::fold< _, int(), my_grammar > Chris@16: /// > Chris@16: /// > Chris@16: /// {}; Chris@16: /// Chris@16: /// struct my_transforms Chris@16: /// : proto::external_transforms< Chris@16: /// proto::when Chris@16: /// , proto::when Chris@16: /// > Chris@16: /// {}; Chris@16: /// Chris@16: /// proto::literal i(1); Chris@16: /// proto::literal c('a'); Chris@16: /// my_transforms trx; Chris@16: /// Chris@16: /// // Evaluate "i+c" using my_grammar with the specified transforms: Chris@16: /// my_grammar()(i + c, 0, trx); Chris@16: /// \endcode Chris@16: template Chris@16: struct external_transforms Chris@16: { Chris@16: typedef mpl::map map_type; Chris@16: Chris@16: template Chris@16: struct when Chris@16: : proto::when<_, typename mpl::at::type> Chris@16: {}; Chris@16: }; Chris@16: Chris@16: // Other specializations of proto::when are generated by the preprocessor... Chris@16: #include Chris@16: Chris@16: /// INTERNAL ONLY Chris@16: /// Chris@16: template Chris@16: struct is_callable > Chris@16: : mpl::true_ Chris@16: {}; Chris@16: Chris@16: }} // namespace boost::proto Chris@16: Chris@101: #if defined(_MSC_VER) Chris@16: # pragma warning(pop) Chris@16: #endif Chris@16: Chris@16: #endif