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

Reply via email to