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

- 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
#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

    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> 
        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, 
                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_<
      , 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<
                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

Reply via email to