#include #include #include #include #ifdef _MSC_VER #pragma warning(disable: 4355) #endif namespace boost { namespace proto { struct external; template struct when { typedef typename Grammar::proto_grammar proto_grammar; template struct impl : Data::template when::template impl {}; template struct impl : Data::template when::template impl {}; }; }} namespace mpl = boost::mpl; namespace proto = boost::proto; namespace fusion = boost::fusion; using proto::_; // A transform that packs the state and data parameter struct _phoenix_env : proto::transform<_phoenix_env> { template struct impl : proto::transform_impl { typedef fusion::vector2 result_type; result_type operator()( typename impl::expr_param , typename impl::state_param s , typename impl::data_param d ) const { return fusion::vector2(s, d); }; }; }; namespace functional { template struct at : proto::callable { typedef typename boost::remove_reference::type index; template struct result; template struct result : fusion::result_of::at_c< typename boost::remove_reference::type , index::value > {}; template typename result::type operator()(Seq &seq) const { return fusion::at_c(seq); } }; typedef at > params; typedef at > actions; struct param_at : proto::callable { template struct result; template struct result : boost::result_of(typename boost::result_of::type)> {}; template typename result::type operator()(N const &, Env &env) const { return at()(params()(env)); } }; } // A collection of semantic actions, indexed by phoenix grammar rules struct PhoenixDefaultActions { template struct when; }; struct 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<> struct PhoenixDefaultActions::when : proto::_default< PhoenixGrammar > {}; // An openly extensible collection of phoenix rules and actions. // "Tag" here is an expression tag. struct PhoenixGrammar : proto::switch_ { template struct case_ : proto::when {}; }; // Hide the fact that there is an Actions parameter being // passed around as Data. The user shouldn't care. struct PhoenixEval : proto::call< PhoenixGrammar(_, functional::params(proto::_state), functional::actions(proto::_state)) > {}; // Define placeholders template 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 > >::type const arg1 = {}; // The phoenix rule for matching placeholder // (Can later be generalized with boost::is_placeholer) struct PhoenixRulePlaceholder : proto::terminal > {}; // The action to take for placeholders template<> struct PhoenixDefaultActions::when : proto::call {}; // Customization point for special terminal handling template struct is_custom_terminal : mpl::false_ {}; // Customization point for special terminal handling template struct get_custom_terminal; // Phoenix rule for matching custom terminals struct PhoenixRuleCustomTerminal : proto::if_()> {}; // Phoenix action to take for custom terminals template<> struct PhoenixDefaultActions::when : proto::lazy(proto::_value)> {}; // Rules for terminals template<> struct PhoenixGrammar::case_ : proto::or_< proto::when , proto::when , proto::when > {}; // Create a phoenix terminal, stored by value template typename proto::terminal::type const val(T t) { return proto::terminal::type::make(t); } // Create a phoenix terminal, stored by reference template typename proto::terminal >::type const ref(T &t) { return proto::terminal >::type::make(boost::ref(t)); } // Create a phoenix terminal, stored by const reference template typename proto::terminal >::type const cref(T const &t) { return proto::terminal >::type::make(boost::cref(t)); } // Call out boost::reference_wrapper for special handling template struct is_custom_terminal > : mpl::true_ {}; // Special handling for boost::reference_wrapper template struct get_custom_terminal > { typedef T &result_type; T &operator()(boost::reference_wrapper 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 struct if_then_else : proto::nary_expr {}; template struct else_gen { else_gen(Cond const& cond, Then const& then) : cond(cond) , then(then) {} template typename if_then_else::type const operator[](Else const &else_) const { return if_then_else::type::make(cond, then, else_); } Cond const &cond; Then const &then; }; template 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::type cond_type; typedef typename proto::result_of::child_c::type then_type; else_gen else_; }; template struct if_then : proto::binary_expr {}; template struct if_gen { explicit if_gen(Cond const& cond) : cond(cond) {} template if_expr::type> const operator[](Then const &then) const { return if_then::type::make(cond, then); } Cond const &cond; }; template if_gen const if_(Cond const &cond) { return if_gen(cond); } // Callable for evaluating if_/then_ statements //template struct if_then_eval : proto::callable { typedef void result_type; template result_type operator()(Cond const& cond, Then const& then, Env& env) const { if(PhoenixEval()(cond, env)) { PhoenixEval()(then, env); } } }; // Phoenix rule for matching if_/then_ statements struct PhoenixRuleIfThen : if_then {}; // Phoenix action to take for if_/then_ statements template<> struct PhoenixDefaultActions::when : proto::call {}; // Bind actions to rules for if_/then_ statements template<> struct PhoenixGrammar::case_ : proto::when {}; // Callable for evaluating if_/then_/else_ statements struct if_then_else_eval : proto::callable { typedef void result_type; template result_type operator()(Cond const& cond, Then const& then, Else const& else_, Env& env) const { if(PhoenixEval()(cond, env)) { PhoenixEval()(then, env); } else { PhoenixEval()(else_, env); } } }; // Phoenix rule for matching custom terminals struct PhoenixRuleIfThenElse : if_then_else {}; // Phoenix action to take for custom terminals template<> //typename Actions> struct PhoenixDefaultActions::when : proto::call {}; // Bind actions to rules for terminals template<> struct PhoenixGrammar::case_ : proto::when {}; //----- // 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 struct when : PhoenixDefaultActions::when {}; }; template<> struct MyActions::when : proto::make {}; int main() { PhoenixEval phoenix_eval; typedef fusion::vector1 params_type; fusion::vector2< params_type, PhoenixDefaultActions > env(params_type(42), PhoenixDefaultActions()); proto::literal i(1), j(2); int k = phoenix_eval(i + j, env); 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 fusion::vector2< params_type, MyActions > my_env(params_type(42), MyActions()); k = phoenix_eval( arg1 + 7, my_env ); std::cout << k << std::endl; // should be 7 }