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
[email protected]
http://lists.boost.org/mailman/listinfo.cgi/proto