[Proto] Access to member in proto expression tree

Hi Does proto support member access in its tree generation in any way. I'm looking at a few of the phoenix statement forms, particularly: if_(pred)[statements].else_[statements] and try_[statements].catch_<exception_type>()[statements].catch_call[statements] I need to specify member access to else_ and catch_<exception_type> etc. Is this something I'll have to hand roll, or does proto have some extension mechanism I've missed that will let me add these to the expression tree generation process? As phoenix expressions have operator(), I'm already using an expression wrapper around all my proto expressions, so I presume that is where I would add any special member support? Cheers Dan ___________________________________________________________ Yahoo! Mail is the world's favourite email. Don't settle for less, sign up for your free account today http://uk.rd.yahoo.com/evt=44106/*http://uk.docs.yahoo.com/mail/winter07.htm...

dan marsden wrote:
Hi
Does proto support member access in its tree generation in any way. I'm looking at a few of the phoenix statement forms, particularly:
if_(pred)[statements].else_[statements]
and
try_[statements].catch_<exception_type>()[statements].catch_call[statements]
I need to specify member access to else_ and catch_<exception_type> etc. Is this something I'll have to hand roll, or does proto have some extension mechanism I've missed that will let me add these to the expression tree generation process?
Yes, proto::extends is the extension mechanism.
As phoenix expressions have operator(), I'm already using an expression wrapper around all my proto expressions, so I presume that is where I would add any special member support?
Yep. You could be to put all such members into the Phoenix expression wrapper and use a grammar to flag or disallow invalid uses. The members would just be Proto terminals, like "terminal<phoenix::tag::else_>::type const else_". A better approach might be to partially specialize your wrapper such that members like else_ only show up where they make sense. So, something like: template<typename Expr, typename EnableIf = void> struct phoenix_expr : proto::extends<Expr, phoenix_expr, phoenix_domain> { // default phoenix stuff here, including // operator() }; // Here is the grammar for if_ expressions struct IfGrammar : proto::subscript< proto::terminal<phoenix::tag::if_> proto::_ > {}; template<typename Expr> struct phoenix_expr< Expr , typename enable_if<proto::matches<Expr, IfGrammar> >::type
: proto::extends<Expr, phoenix_expr, phoenix_domain> { // default phoenix stuff here, including // operator() terminal<phoenix::tag::else_>::type const else_; }; Obviously, you'd want to structure this such that both the primary template and the specialization inherit from a common base which has the operator() overloads and any other stuff that would be common to them. HTH, -- Eric Niebler Boost Consulting www.boost-consulting.com

Eric Niebler wrote:
dan marsden wrote:
As phoenix expressions have operator(), I'm already using an expression wrapper around all my proto expressions, so I presume that is where I would add any special member support?
Yep. You could be to put all such members into the Phoenix expression wrapper and use a grammar to flag or disallow invalid uses. The members would just be Proto terminals, like "terminal<phoenix::tag::else_>::type const else_".
Oh wait, that's not quite what you want, because then if_[e1].else_[e2] will chop off the if_ part of the tree. What you need instead is a member like (untested): template<typename Expr ...> struct phoenix_expr : proto::extends<Expr ...> { phoenix_expr(...) : else_(proto::make_expr<phoenix::tag::else_>(*this)) {} // ... proto::result_of::make_expr< pheonix::tag::else_ // else is now an "operator" , phoenix_expr const
::type const else_; };
Then, if_/else_ statements would conform to the following grammar: subscript< unary_expr< phoenix::tag::else_ ,subscript<terminal<phoenix::tag::if_>,_>
,_
-- Eric Niebler Boost Consulting www.boost-consulting.com

On Sunday 01 July 2007 10:13, Eric Niebler wrote:
Oh wait, that's not quite what you want, because then if_[e1].else_[e2] will chop off the if_ part of the tree. What you need instead is a member like (untested):
template<typename Expr ...> struct phoenix_expr
: proto::extends<Expr ...>
{ phoenix_expr(...)
: else_(proto::make_expr<phoenix::tag::else_>(*this))
{}
// ...
proto::result_of::make_expr< pheonix::tag::else_ // else is now an "operator" , phoenix_expr const
::type const else_;
};
Then, if_/else_ statements would conform to the following grammar:
subscript< unary_expr< phoenix::tag::else_ ,subscript<terminal<phoenix::tag::if_>,_>
,_
Ok, that makes sense to me, modulo the current lack of make_expr documentation. :) I'm looking to do something similar to what Dan is doing so I'm glad he asked the question. I was just about to. One thing that's not clear to me is how he would handle the if_(expr)[...] syntax. In your first message you have: // Here is the grammar for if_ expressions struct IfGrammar : proto::subscript< proto::terminal<phoenix::tag::if_> proto::_ > {}; I don't understand the derivation from proto::subscript. What about the call operator? From your second message: Then, if_/else_ statements would conform to the following grammar: subscript< unary_expr< phoenix::tag::else_ ,subscript<terminal<phoenix::tag::if_>,_> > ,_
Again what about the call operator? Dan has two uses of operator() here. The first is a proto expression that needs to be part of the grammar to match the if expression. The other is the operator() provided through proto::extends to do the runtime evaluation. I'm going to be doing something different. Rather than evaluate the expression, I'm going to want to run a transformation on it. Given the example from your second message: template<typename Expr ...> struct phoenix_expr : proto::extends<Expr ...> { phoenix_expr(...) : else_(proto::make_expr<phoenix::tag::else_>(*this)) {} // ... proto::result_of::make_expr< pheonix::tag::else_ // else is now an "operator" , phoenix_expr const >::type const else_; }; how do I match the new "else_ operator" and transform it? Thanks. -Dave

David A. Greene wrote:
On Sunday 01 July 2007 10:13, Eric Niebler wrote:
Oh wait, that's not quite what you want, because then if_[e1].else_[e2] will chop off the if_ part of the tree. What you need instead is a member like (untested):
template<typename Expr ...> struct phoenix_expr
: proto::extends<Expr ...>
{ phoenix_expr(...)
: else_(proto::make_expr<phoenix::tag::else_>(*this))
{}
// ...
proto::result_of::make_expr< pheonix::tag::else_ // else is now an "operator" , phoenix_expr const
::type const else_;
};
Then, if_/else_ statements would conform to the following grammar:
subscript< unary_expr< phoenix::tag::else_ ,subscript<terminal<phoenix::tag::if_>,_>
,_
Ok, that makes sense to me, modulo the current lack of make_expr documentation. :)
Patience! :)
I'm looking to do something similar to what Dan is doing so I'm glad he asked the question. I was just about to.
One thing that's not clear to me is how he would handle the if_(expr)[...] syntax. In your first message you have:
// Here is the grammar for if_ expressions struct IfGrammar : proto::subscript< proto::terminal<phoenix::tag::if_> proto::_ > {};
I don't understand the derivation from proto::subscript. What about the call operator?
D'oh! I forgot that part. // matches if_(e1)[e2] struct IfGrammar : subscript< function< terminal<phoenix::tag::if_> , _ > , _ > {}; This assumes that if_ is defined like: terminal<phoenix::tag::if_>::type const if_ = {{}}; But now that I think about it some more, Dan probably wants if_ to be an actual function instead of a Proto terminal, because phoenix expressions have an operator() that does something special. You can use the BOOST_PROTO_DEFINE_FUNCTION_TEMPLATE macro for this. BOOST_PROTO_DEFINE_FUNCTION_TEMPLATE( 1 , if_ , phoenix::phoenix_domain , (phoenix::tag::if_) , BOOST_PP_SEQ_NIL ) This creates a function template called if_() that takes one argument and returns a unary proto tree with an op tag of phoenix::tag::if_ in the phoenix_domain. If Dan goes this route, the IfGrammar changes to: // matches if_(e1)[e2] struct IfGrammar : subscript< unary_expr< phoenix::tag::if_ , _ > , _ > {}; Derivation is just the way to give a name to a proto grammar rule. A typedef would work just as well in this case, but using a struct is preferred, because in body of the grammar rule, the name of the struct can be used to recurse. <snip>
I'm going to be doing something different. Rather than evaluate the expression, I'm going to want to run a transformation on it. Given the example from your second message:
template<typename Expr ...> struct phoenix_expr : proto::extends<Expr ...> { phoenix_expr(...) : else_(proto::make_expr<phoenix::tag::else_>(*this)) {}
// ...
proto::result_of::make_expr< pheonix::tag::else_ // else is now an "operator" , phoenix_expr const >::type const else_; };
how do I match the new "else_ operator" and transform it?
Well, if you use the BOOST_PROTO_DEFINE_FUNCTION_TEMPLATE macro like I show above, the IfElseGrammar might look like this: // matches if_(e1)[e2].else_[e3] struct IfElseGrammar : subscript< unary_expr< phoenix::tag::else_ , subscript< unary_expr< phoenix::tag::if_ , PhoenixBooleanGrammar > , PhoenixGrammar > > , PhoenixGrammar > {}; Where PhoenixBooleanGrammar is some other grammar that defines what it means to be a boolean expression, and PhoenixGrammar is the whole shebang -- any valid phoenix expression. (The recursion here is implied. PhoenixGrammar is undoubtedly implemented in terms of IfElseGrammar.) As for how to transform it, that depends on what you're trying to do, but it would involve decorating the above grammar with transforms that Proto provides, or writing your own. Probably a little of both. And PhoenixBooleanGrammar and PhoenixGrammar would have their own transforms. HTH, -- Eric Niebler Boost Consulting www.boost-consulting.com

On Jul 1, 2007, at 6:24 PM, Eric Niebler wrote:
But now that I think about it some more, Dan probably wants if_ to be an actual function instead of a Proto terminal, because phoenix expressions have an operator() that does something special. You can use the BOOST_PROTO_DEFINE_FUNCTION_TEMPLATE macro for this.
BOOST_PROTO_DEFINE_FUNCTION_TEMPLATE( 1 , if_ , phoenix::phoenix_domain , (phoenix::tag::if_) , BOOST_PP_SEQ_NIL )
Eric, what is the meaning of the last argument (empty here and called BOUNDARGS in the sources)? The only example I could find is in mixed.cpp where it seems to be used to allow the tag to be unrelated to the function being defined. Following that example: BOOST_PROTO_DEFINE_FUNCTION_TEMPLATE( 1, if_, phoenix::phoenix_domain, proto::tag::function ((if_struct)) ) would also work and create a proto::expr with a tag::function as tag and first argument a (terminal?) if_struct. It assumes if_struct has a default constructor. Is this the right interpretation? In the mixed.cpp example is defining struct sin_ { } the way it is enough to allow the default_context to evaluate sin_(expr)?

On Sunday 01 July 2007 17:24, Eric Niebler wrote:
template<typename Expr ...> struct phoenix_expr
: proto::extends<Expr ...>
{ phoenix_expr(...)
: else_(proto::make_expr<phoenix::tag::else_>(*this))
{}
// ...
proto::result_of::make_expr< pheonix::tag::else_ // else is now an "operator" , phoenix_expr const
>::type const else_;
};
how do I match the new "else_ operator" and transform it?
Well, if you use the BOOST_PROTO_DEFINE_FUNCTION_TEMPLATE macro like I show above, the IfElseGrammar might look like this:
// matches if_(e1)[e2].else_[e3] struct IfElseGrammar
: subscript<
unary_expr< phoenix::tag::else_ , subscript< unary_expr< phoenix::tag::if_ , PhoenixBooleanGrammar
, PhoenixGrammar
, PhoenixGrammar
{};
All right, that makes good sense. Now the next obvious thing to do is try do_[e1].while_(e2). So here's my attempt: // A do_ "operator" boost::proto::terminal<tag::Do>::type const do_ = {{}}; // matches do[e1] struct DoGrammar : boost::proto::subscript< tag::Do, StatementGrammar > {}; // A while_ "operator" template<typename Expr> struct Expression< Expr , typename enable_if<proto::matches<Expr, DoGrammar> >::type > : proto::extends<Expr, Expression<Expr>, Domain> { Expression() : while_(proto::make_expr<tag::While>(*this)) {}; // Oops, don't know how to do this here BOOST_PROTO_DEFINE_FUNCTION_TEMPLATE( 1 , while_ , Domain , (tag::While) , BOOST_PP_SEQ_NIL ); }; // matches do[e1].while_(e2) struct DoWhileGrammar : boost::proto::unary_expr< DoGrammar, tag::While > {}; Other than the fact that I don't know how to declare the while_ member above, does this look correct? Of course, I want to do while_(e1)[e2] as well, so there already is BOOST_PROTO_DEFINE_FUNCTION_TEMPLATE( 1 , while_ , Domain , (tag::While) , BOOST_PP_SEQ_NIL ); at namespace scope. Is there some way to reuse this in the extension of expressions that match DoGrammar? -Dave

David A. Greene wrote:
Now the next obvious thing to do is try do_[e1].while_(e2). So here's my attempt:
// A do_ "operator" boost::proto::terminal<tag::Do>::type const do_ = {{}};
// matches do[e1] struct DoGrammar : boost::proto::subscript< tag::Do, StatementGrammar > {};
// A while_ "operator" template<typename Expr> struct Expression< Expr , typename enable_if<proto::matches<Expr, DoGrammar> >::type > : proto::extends<Expr, Expression<Expr>, Domain> { Expression() : while_(proto::make_expr<tag::While>(*this)) {};
// Oops, don't know how to do this here BOOST_PROTO_DEFINE_FUNCTION_TEMPLATE( 1 , while_ , Domain , (tag::While) , BOOST_PP_SEQ_NIL ); };
Yes, it would be nice if that worked. I'll look into it.
Of course, I want to do while_(e1)[e2] as well, so there already is
BOOST_PROTO_DEFINE_FUNCTION_TEMPLATE( 1 , while_ , Domain , (tag::While) , BOOST_PP_SEQ_NIL );
at namespace scope. Is there some way to reuse this in the extension of expressions that match DoGrammar?
I don't think so. while_[...] and do_[...].while_(...) are two different things. Here is some code I just banged out for do_[...].while_(...). #include <iostream> #include <boost/xpressive/proto/proto.hpp> using namespace boost; using namespace proto; struct DoTag {}; struct WhileTag {}; template<typename Expr, typename EnableIf = void> struct Expression; struct Grammar // Stub grammar, matches all expressions : or_<terminal<_>, nary_expr<_, vararg<Grammar> > > {}; struct DoGrammar : subscript<terminal<DoTag>, Grammar> {}; struct Generator { template<typename Expr> struct apply { typedef Expression<Expr> type; }; template<typename Expr> static Expression<Expr> make(Expr const &expr) { return Expression<Expr>(expr); } }; struct Domain : domain<Generator, Grammar> {}; template<typename Expr, typename EnableIf> struct Expression : extends<Expr, Expression<Expr>, Domain> { explicit Expression(Expr const &expr = Expr()) : extends<Expr, Expression<Expr>, Domain>(expr) {} using extends<Expr, Expression<Expr>, Domain>::operator =; }; Expression<terminal<DoTag>::type> const do_ = Expression<terminal<DoTag>::type>(); template<typename Expr> struct Expression<Expr, typename enable_if<matches<Expr, DoGrammar>
::type> : extends<Expr, Expression<Expr>, Domain> { explicit Expression(Expr const &expr = Expr()) : extends<Expr, Expression<Expr>, Domain>(expr) , while_(make_expr<WhileTag, Domain>(This())) {}
using extends<Expr, Expression<Expr>, Domain>::operator =; typename proto::result_of::make_expr<WhileTag, Domain, Expression const>::type while_; private: Expression const &This() const { return *this; } }; struct DoWhileGrammar : function< unary_expr< WhileTag , DoGrammar > , Grammar > {}; template<typename Expr> void test(Expr const &expr) { BOOST_MPL_ASSERT((matches<Expr, DoWhileGrammar>)); } terminal<std::ostream &>::type const cout_ = {std::cout}; int main() { test(do_[ cout_ << "hello, world" ].while_(true)); return 0; } BTW, are you working with Dan Marsden on the Phoenix port, or just experimenting with your own Proto-flavored lambda library? Just curious. -- Eric Niebler Boost Consulting www.boost-consulting.com

Replying to myself ... Eric Niebler wrote:
template<typename Expr> struct Expression<Expr, typename enable_if<matches<Expr, DoGrammar>
::type> : extends<Expr, Expression<Expr>, Domain> { explicit Expression(Expr const &expr = Expr()) : extends<Expr, Expression<Expr>, Domain>(expr) , while_(make_expr<WhileTag, Domain>(This())) {}
using extends<Expr, Expression<Expr>, Domain>::operator =; typename proto::result_of::make_expr<WhileTag, Domain, Expression const>::type while_;
private: Expression const &This() const { return *this; } };
struct DoWhileGrammar : function< unary_expr< WhileTag , DoGrammar > , Grammar > {};
Or perhaps try the following, which is a little cleaner IMO ... template<typename Expr> struct Expression<Expr , typename enable_if<matches<Expr, DoGrammar> >::type > : extends<Expr, Expression<Expr>, Domain> { explicit Expression(Expr const &expr = Expr()) : extends<Expr, Expression<Expr>, Domain>(expr) {} using extends<Expr, Expression<Expr>, Domain>::operator =; template< typename A0 > typename proto::result_of::make_expr< WhileTag, Domain, Expression const, A0 const >::type const while_(A0 const &a0) const { return make_expr<WhileTag, Domain>(*this, a0); } }; struct DoWhileGrammar : binary_expr< WhileTag , DoGrammar , Grammar > {}; HTH, -- Eric Niebler Boost Consulting www.boost-consulting.com

On Saturday 07 July 2007 22:23, Eric Niebler wrote:
BTW, are you working with Dan Marsden on the Phoenix port, or just experimenting with your own Proto-flavored lambda library? Just curious.
Nope, not on phoenix. I'm not working on a lambda library at all. I'm doing some experiments with compilers and language representation, so I will eventually want to transform this into an abstract syntax tree that can be analyzed and manipulated. I'm hopeful that boost::proto will be useful for constructing a DSEL that non-compiler-expert people can use to express program construction (replacing bits of a program with something else, etc.). Naturally, I'm looking for something close to a C-like syntax. It's too bad that the semantics of operator->() make it tough to overload in proto. Thanks for your help. -Dave

David A. Greene wrote:
On Saturday 07 July 2007 22:23, Eric Niebler wrote:
BTW, are you working with Dan Marsden on the Phoenix port, or just experimenting with your own Proto-flavored lambda library? Just curious.
Nope, not on phoenix. I'm not working on a lambda library at all. I'm doing some experiments with compilers and language representation, so I will eventually want to transform this into an abstract syntax tree that can be analyzed and manipulated.
I'm hopeful that boost::proto will be useful for constructing a DSEL that non-compiler-expert people can use to express program construction (replacing bits of a program with something else, etc.). Naturally, I'm looking for something close to a C-like syntax.
I'll be interested to see how it turns out.
It's too bad that the semantics of operator->() make it tough to overload in proto.
Too true. But there's always operator ->*(). -- Eric Niebler Boost Consulting www.boost-consulting.com

On Saturday 07 July 2007 23:37, Eric Niebler wrote:
I'm hopeful that boost::proto will be useful for constructing a DSEL that non-compiler-expert people can use to express program construction (replacing bits of a program with something else, etc.). Naturally, I'm looking for something close to a C-like syntax.
I'll be interested to see how it turns out.
Yeah, me too. This is entirely a hobby project so it kind of happens in fits and spurts. My long-term evil-genius goal is to hook it up to llvm (llvm.org) and create a jit-able dynamic programming environment. That's a ways off, though. -Dave
participants (4)
-
dan marsden
-
David A. Greene
-
Eric Niebler
-
Maurizio Vitale