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