On 10/23/2010 10:12 AM, Eric Niebler wrote:
> I've tweaked both the traversal example you sent around as well as my
> over toy Phoenix. Tell me what you guys think.

Actually, I think it's better to leave the definition of "some_rule"
alone and wrap it in "named_rule" at the point of use. A bit cleaner.
See attached.

-- 
Eric Niebler
BoostPro Computing
http://www.boostpro.com
#include "stdafx.h"
#include <boost/preprocessor/arithmetic/inc.hpp>
#include <boost/preprocessor/repetition/enum.hpp>
#include <boost/preprocessor/repetition/enum_params.hpp>
#include <boost/preprocessor/repetition/enum_params_with_a_default.hpp>
#include <boost/preprocessor/repetition/repeat.hpp>
#include <iostream>

#ifdef _MSC_VER
#pragma warning(disable: 4355)
#endif

namespace boost { namespace proto
{
    namespace detail
    {
        // Define has_which trait
        BOOST_MPL_HAS_XXX_TRAIT_DEF(which)
        BOOST_MPL_HAS_XXX_TRAIT_DEF(rule_name)

        template<typename Grammar, typename EnableIf = void>
        struct get_rule_name
        {
            typedef Grammar type;
        };

        template<typename Grammar>
        struct get_rule_name<
            Grammar
          , typename boost::enable_if_c<has_rule_name<Grammar>::value >::type
        >
        {
            typedef typename Grammar::rule_name type;
        };

        template<typename Expr, typename Grammar, typename EnableIf = void>
        struct get_which
          : get_rule_name<Grammar>
        {};

        // 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<
                mpl::and_<
                    has_which<proto::matches<Expr, Grammar> >
                  , mpl::not_<has_rule_name<Grammar> >
                >::value
            >::type
        >
          : get_which<Expr, typename proto::matches<Expr, Grammar>::which>
        {};
    }

    template<typename Grammar>
    struct named_rule
      : Grammar
    {
        typedef Grammar rule_name;
    };

    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>
        {};
    };

    template <typename Grammar, typename Actions>
    struct is_callable<algorithm<Grammar, Actions> >
      : mpl::true_
    {};
}}

namespace mpl = boost::mpl;
namespace proto = boost::proto;
namespace fusion = boost::fusion;
using proto::_;

// A collection of semantic actions, indexed by phoenix grammar rules
struct PhoenixDefaultActions
{
    template<typename Rule, typename Actions = PhoenixDefaultActions>
    struct when;
};

// The phoenix grammar and evaluator algorithm, parameterized
// by a collection of semantic actions.
template<typename Actions = PhoenixDefaultActions>
struct PhoenixEval;

// This is the grammar of Phoenix expressions. It is
// independent of the semantic actions.
typedef PhoenixEval<> PhoenixGrammar;

// The Phoenix "default" rule, which handles most operands by
// delegating to proto::_default.
struct PhoenixRuleDefault
  : proto::_default< PhoenixGrammar >
{};

// Add to the collection of semantic actions the thing to
// do in the "default" case.
template<typename Actions>
struct PhoenixDefaultActions::when<PhoenixRuleDefault, Actions>
  : proto::_default< PhoenixEval<Actions> >
{};

// An openly extensible collection of phoenix rules and actions.
// "Tag" here is an expression tag.
struct PhoenixGrammarCases
{
    template<typename Tag>
    struct case_
      : proto::named_rule<PhoenixRuleDefault>
    {};
};

// The phoenix grammar and evaluator is just a
// collection of phoenix rules, parameterized by
// the actions to take for each rule.
template<typename Actions>
struct PhoenixEval
  : proto::algorithm< proto::switch_<PhoenixGrammarCases>, Actions >
{};

// Define placeholders
template<typename I>
struct placeholder
{
    typedef I type;
    typedef typename I::value_type value_type;
    static value_type const value = I::value;
};

// Here is the arg1 placeholder
proto::terminal<placeholder<mpl::int_<0> > >::type const arg1 = {};

// Simple TR1-style function object for indexing a Fusion sequence
struct at : proto::callable
{
    template <typename Sig>
    struct result;

    template <typename This, typename N, typename Env>
    struct result<This(N, Env)>
      : fusion::result_of::at_c<
            typename boost::remove_reference<Env>::type
          , boost::remove_reference<N>::type::value
        >
    {};

    template<typename N, typename Env>
    typename fusion::result_of::at_c<Env, N::value>::type
    operator()(N, Env &env) const
    {
        return fusion::at_c<N::value>(env);
    }
};

// The phoenix rule for matching placeholder
// (Can later be generalized with boost::is_placeholer)
struct PhoenixRulePlaceholder
  : proto::terminal<placeholder<_> >
{};

// The action to take for placeholders
template<typename Actions>
struct PhoenixDefaultActions::when<PhoenixRulePlaceholder, Actions>
  : proto::call<at(proto::_value, proto::_state)>
{};

// Customization point for special terminal handling
template<typename T>
struct is_custom_terminal
  : mpl::false_
{};

// Customization point for special terminal handling
template<typename T>
struct get_custom_terminal;

// Phoenix rule for matching custom terminals
struct PhoenixRuleCustomTerminal
  : proto::if_<is_custom_terminal<proto::_value>()>
{};

// Phoenix action to take for custom terminals
template<typename Actions>
struct PhoenixDefaultActions::when<PhoenixRuleCustomTerminal, Actions>
  : proto::lazy<get_custom_terminal<proto::_value>(proto::_value)>
{};

// Rules for terminals
template<>
struct PhoenixGrammarCases::case_<proto::tag::terminal>
  : proto::or_<
        proto::named_rule<PhoenixRulePlaceholder>
      , proto::named_rule<PhoenixRuleCustomTerminal>
      , proto::named_rule<PhoenixRuleDefault>
    >
{};

// Create a phoenix terminal, stored by value
template<typename T>
typename proto::terminal<T>::type const val(T t)
{
    return proto::terminal<T>::type::make(t);
}

// Create a phoenix terminal, stored by reference
template<typename T>
typename proto::terminal<boost::reference_wrapper<T> >::type const ref(T &t)
{
    return proto::terminal<boost::reference_wrapper<T> 
>::type::make(boost::ref(t));
}

// Create a phoenix terminal, stored by const reference
template<typename T>
typename proto::terminal<boost::reference_wrapper<T const> >::type const cref(T 
const &t)
{
    return proto::terminal<boost::reference_wrapper<T const> 
>::type::make(boost::cref(t));
}

// Call out boost::reference_wrapper for special handling
template<typename T>
struct is_custom_terminal<boost::reference_wrapper<T> >
  : mpl::true_
{};

// Special handling for boost::reference_wrapper
template<typename T>
struct get_custom_terminal<boost::reference_wrapper<T> >
{
    typedef T &result_type;

    T &operator()(boost::reference_wrapper<T> r) const
    {
        return r;
    }
};

//-----
// Begin if_/then_/else_ implementation
//-----

// Define some tags for additional statements
namespace tag
{
    struct if_then {};
    struct if_then_else {};
}

template<typename Cond, typename Then, typename Else>
struct if_then_else
  : proto::nary_expr<tag::if_then_else, Cond, Then, Else>
{};

template<typename Cond, typename Then>
struct else_gen
{
    else_gen(Cond const& cond, Then const& then)
      : cond(cond)
      , then(then)
    {}

    template <typename Else>
    typename if_then_else<Cond, Then, Else>::type const
    operator[](Else const &else_) const
    {
        return if_then_else<Cond, Then, Else>::type::make(cond, then, else_);
    }

    Cond const &cond;
    Then const &then;
};

template<typename Expr>
struct if_expr
  : Expr
{
    if_expr(Expr const& expr)
      : Expr(expr)
      , else_(proto::child_c<0>(*this), proto::child_c<1>(*this))
    {}

    typedef typename proto::result_of::child_c<Expr, 0>::type cond_type;
    typedef typename proto::result_of::child_c<Expr, 1>::type then_type;
    else_gen<cond_type, then_type> else_;
};

template<typename Cond, typename Then>
struct if_then
  : proto::binary_expr<tag::if_then, Cond, Then>
{};

template<typename Cond>
struct if_gen
{
    explicit if_gen(Cond const& cond)
      : cond(cond)
    {}

    template<typename Then>
    if_expr<typename if_then<Cond const &, Then const &>::type> const
    operator[](Then const &then) const
    {
        return if_then<Cond const &, Then const &>::type::make(cond, then);
    }

    Cond const &cond;
};

template <typename Cond>
if_gen<Cond> const if_(Cond const &cond)
{
    return if_gen<Cond>(cond);
}

// Callable for evaluating if_/then_ statements
template<typename Actions>
struct if_then_eval : proto::callable
{
    typedef void result_type;

    template <typename Cond, typename Then, typename Env>
    result_type operator()(Cond const& cond, Then const& then, Env& env) const
    {
        if(PhoenixEval<Actions>()(cond, env))
        {
            PhoenixEval<Actions>()(then, env);
        }
    }
};

// Phoenix rule for matching if_/then_ statements
struct PhoenixRuleIfThen
  : if_then<PhoenixGrammar, PhoenixGrammar>
{};

// Phoenix action to take for if_/then_ statements
template<typename Actions>
struct PhoenixDefaultActions::when<PhoenixRuleIfThen, Actions>
  : proto::call<if_then_eval<Actions>(proto::_child0, proto::_child1, 
proto::_state)>
{};

// Bind actions to rules for if_/then_ statements
template<>
struct PhoenixGrammarCases::case_<tag::if_then>
  : proto::named_rule<PhoenixRuleIfThen>
{};

// Callable for evaluating if_/then_/else_ statements
template<typename Actions>
struct if_then_else_eval : proto::callable
{
    typedef void result_type;

    template <typename Cond, typename Then, typename Else, typename Env>
    result_type operator()(Cond const& cond, Then const& then, Else const& 
else_, Env& env) const
    {
        if(PhoenixEval<Actions>()(cond, env))
        {
            PhoenixEval<Actions>()(then, env);
        }
        else
        {
            PhoenixEval<Actions>()(else_, env);
        }
    }
};

// Phoenix rule for matching custom terminals
struct PhoenixRuleIfThenElse
  : if_then_else<PhoenixGrammar, PhoenixGrammar, PhoenixGrammar>
{};

// Phoenix action to take for custom terminals
template<typename Actions>
struct PhoenixDefaultActions::when<PhoenixRuleIfThenElse, Actions>
  : proto::call<if_then_else_eval<Actions>(proto::_child0, proto::_child1, 
proto::_child2, proto::_state)>
{};

// Bind actions to rules for terminals
template<>
struct PhoenixGrammarCases::case_<tag::if_then_else >
  : proto::named_rule<PhoenixRuleIfThenElse>
{};

//-----
// End if_/then_/else_ implementation
//-----

// With this set of semantic actions, we can easily force
// arg1 to always evaluate to int(0). Nice little example
// of how the Phoenix expression evaluator can be customized.
struct MyActions
{
    template<typename Rule, typename Actions = MyActions>
    struct when
      : PhoenixDefaultActions::when<Rule, Actions>
    {};

    template<typename Actions>
    struct when<PhoenixRulePlaceholder, Actions>
      : proto::make<int()>
    {};
};

int main()
{
    PhoenixEval<> phoenix_eval;
    fusion::vector1<int> env(42);
    proto::literal<int> i(1), j(2);

    int k = phoenix_eval(i + j);
    std::cout << k << std::endl; // should be 3

    k = phoenix_eval(i + arg1, env);
    std::cout << k << std::endl; // should be 43

    k = phoenix_eval(cref(7), env);
    std::cout << k << std::endl; // should be 7

    phoenix_eval( if_(i == 1)[ ++i ], env );
    std::cout << i.get() << std::endl; // should be 2

    phoenix_eval( if_(i == 1)[ ++i ].else_[ --i ], env );
    std::cout << i.get() << std::endl; // should be 1

    // Test for custom semantic actions
    PhoenixEval<MyActions> my_eval;
    k = my_eval( arg1 + 7, env );
    std::cout << k << std::endl; // should be 7
}
#include "stdafx.h"
#include <string>
#include <iostream>
#include <boost/utility/enable_if.hpp>
#include <boost/mpl/and.hpp>
#include <boost/mpl/not.hpp>
#include <boost/mpl/has_xxx.hpp>

namespace boost { namespace proto
{
    namespace detail
    {
        // Define has_which trait
        BOOST_MPL_HAS_XXX_TRAIT_DEF(which)
        BOOST_MPL_HAS_XXX_TRAIT_DEF(rule_name)

        template<typename Grammar, typename EnableIf = void>
        struct get_rule_name
        {
            typedef Grammar type;
        };

        template<typename Grammar>
        struct get_rule_name<
            Grammar
          , typename boost::enable_if_c<has_rule_name<Grammar>::value >::type
        >
        {
            typedef typename Grammar::rule_name type;
        };

        template<typename Expr, typename Grammar, typename EnableIf = void>
        struct get_which
          : get_rule_name<Grammar>
        {};

        // 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<
                mpl::and_<
                    has_which<proto::matches<Expr, Grammar> >
                  , mpl::not_<has_rule_name<Grammar> >
                >::value
            >::type
        >
          : get_which<Expr, typename proto::matches<Expr, Grammar>::which>
        {};
    }

    template<typename Grammar>
    struct named_rule
      : Grammar
    {
        typedef Grammar rule_name;
    };

    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>
        {};
    };

    template <typename Grammar, typename Actions>
    struct is_callable<algorithm<Grammar, Actions> >
      : mpl::true_
    {};
}}

namespace mpl = boost::mpl;
namespace proto = boost::proto;

struct nothing
  : proto::not_<proto::_>
{};

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_grammar
  : proto::switch_<my_grammar>
{
    template<typename Tag>
    struct case_
      : proto::named_rule<nothing>
    {};
};

template<>
struct my_grammar::case_<proto::tag::terminal>
  : proto::or_<
        proto::named_rule<int_terminal>
      , proto::named_rule<char_terminal>
    >
{};

template<>
struct my_grammar::case_<proto::tag::plus>
  : //proto::or_<
        proto::named_rule<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<proto::algorithm<my_grammar, Actions>(proto::_left)>
              , proto::call<proto::algorithm<my_grammar, 
Actions>(proto::_right)>
            )
        >
    {};
};

int main()
{
    proto::literal<int> i(8), j(9);
    proto::literal<char> a('a'), b('b');

    std::cout << proto::algorithm<char_terminal, my_actions>()(a)  << "\n"; // 
printing char
    proto::assert_matches_not<proto::algorithm<int_terminal, my_actions> >(a);
    //std::cout << proto::algorithm<int_terminal, my_actions>()(a)   << "\n"; 
// precondition violation
    proto::assert_matches_not<proto::algorithm<char_terminal, my_actions> >(i);
    //std::cout << proto::algorithm<char_terminal, my_actions>()(i)  << "\n"; 
// precondition violation
    std::cout << proto::algorithm<int_terminal, my_actions>()(j)   << "\n"; // 
printing int
    std::cout << proto::algorithm<my_grammar, my_actions>()(j)     << "\n"; // 
printing int
    std::cout << proto::algorithm<my_grammar, my_actions>()(a)     << "\n"; // 
printing char
    std::cout << proto::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