On 10/22/2010 10:45 AM, Eric Niebler wrote: > On 10/22/2010 10:01 AM, Thomas Heller wrote: >> I think this is the simplification of client proto code we searched for. It >> probably needs some minor polishment though. > <snip> > > Hi Thomas, this looks promising. I'm digging into this now.
This is so wonderful, I can't /not/ put this in Proto. I just made a small change to proto::matches to VASTLY simplify the implementation (sync up). I also made a few changes: - The action CRTP base is no more. You can't legally specialize a member template in a derived class anyway. - Proto::or_, proto::switch_ and proto::if_ are the only branching grammar constructs and need special handling to find the sub-rule that matched. All the nasty logic for that is now mixed in with the implementation of proto::matches (where the information was already available but not exposed). - You have the option (but not the obligation) to select a rule's default transform when defining the primary "when" template in your actions class. (You can also defer to another action class's "when" template for inheriting actions, but Thomas' code already had that capability.) - I changed the name from "_traverse" to "algorithm" to reflect its role as a generic way to build algorithms by binding actions to control flow as specified by grammar rules. I also want to avoid any possible future conflict with Dan Marsden's Traverse library, which I hope to reuse in Proto. That said ... the name "algorithm" sucks and I'd like to do better. Naming is hard. - The algorithm class is also a grammar (in addition to a transform) that matches its Grammar template parameter. When you pass an expression that does not match the grammar, it is now a precondition violation. That is consistent with the rest of Proto. That's it. It's simple, elegant, powerful, and orthogonal to and fits in well with the rest of Proto. I think we have a winner. Good job! -- Eric Niebler BoostPro Computing http://www.boostpro.com
#include <string> #include <iostream> #include <boost/proto/proto.hpp> #include <boost/utility/enable_if.hpp> namespace mpl = boost::mpl; namespace proto = boost::proto; namespace detail { // Define has_which trait BOOST_MPL_HAS_XXX_TRAIT_DEF(which) template<typename Expr, typename Grammar, typename EnableIf = void> struct get_which { typedef Grammar type; }; // Only proto::or_, proto::switch_ and proto::if_ have branches and // need to define a which member. template<typename Expr, typename Grammar> struct get_which< typename Expr , typename Grammar , typename boost::enable_if_c<has_which<proto::matches<Expr, Grammar> >::value>::type > { typedef typename proto::matches<Expr, Grammar>::which type; }; } template<typename Grammar, typename Actions> struct algorithm : proto::transform<algorithm<Grammar, Actions> > { typedef Grammar proto_grammar; // Cheating! relies on Proto implementation details (the // presence of a nested which typedef in proto::matches). template <typename Expr, typename State, typename Data> struct impl : Actions::template when<typename detail::get_which<Expr, Grammar>::type, Actions>::template impl<Expr, State, Data> {}; }; namespace boost { namespace proto { template <typename Grammar, typename Actions> struct is_callable<algorithm<Grammar, Actions> > : mpl::true_ {}; }} struct int_terminal : proto::terminal<int> {}; struct char_terminal : proto::terminal<char> {}; struct plus_int_int : proto::plus<int_terminal, int_terminal> {}; struct my_grammar : proto::or_< int_terminal , char_terminal , plus_int_int > {}; struct my_actions; struct print : proto::callable { typedef std::string result_type; result_type operator()(int) const { return "int"; } result_type operator()(char) const { return "char"; } template <typename T1, typename T2> result_type operator()(T1 res, T2 t2) const { res += " + "; res += t2; return res; } }; struct my_actions { template <typename Grammar, typename Actions = my_actions> struct when; template <typename Actions> struct when<int_terminal, Actions> : proto::call<print(proto::_value)> {}; template <typename Actions> struct when<char_terminal, Actions> : proto::call<print(proto::_value)> {}; template <typename Actions> struct when<plus_int_int, Actions> : proto::call< print( proto::call<algorithm<my_grammar, Actions>(proto::_left)> , proto::call<algorithm<my_grammar, Actions>(proto::_right)> ) > {}; }; int main() { proto::literal<int> i(8), j(9); proto::literal<char> a('a'), b('b'); std::cout << algorithm<char_terminal, my_actions>()(a) << "\n"; // printing char proto::assert_matches_not<algorithm<int_terminal, my_actions> >(a); //std::cout << algorithm<int_terminal, my_actions>()(a) << "\n"; // precondition violation proto::assert_matches_not<algorithm<char_terminal, my_actions> >(i); //std::cout << algorithm<char_terminal, my_actions>()(i) << "\n"; // precondition violation std::cout << algorithm<int_terminal, my_actions>()(j) << "\n"; // printing int std::cout << algorithm<my_grammar, my_actions>()(j) << "\n"; // printing int std::cout << algorithm<my_grammar, my_actions>()(a) << "\n"; // printing char std::cout << algorithm<my_grammar, my_actions>()(i + i) << "\n"; // printing int + int }
_______________________________________________ proto mailing list proto@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/proto