On 10/4/2010 12:20 PM, Thomas Heller wrote:
> On Mon, Oct 4, 2010 at 8:53 PM, joel falcou wrote:
>> On 04/10/10 20:45, Eric Niebler wrote:
>>>
>>> I'm not opposed to such a thing being in Proto, but I
>>> (personally) don't feel a strong need. I'd be more willing if I
>>> saw a more strongly motivating example. I believe Joel Falcou
>>> invented something similar. Joel, what was your use scenario?
>>
>> NT2 ;)
>>
>> More specifically, all our transform are built the same way: visit
>> the tree, dispatch on visitor type + tag and act accordignly. It
>> was needed for us cause the grammar could NOT have been written by
>> hand as we supprot 200+ functions on nt2 terminal. All our code is
>> somethign like "for each node, do Foo" with variable Foo depending
>> on the pass and duplicating the grammar was a no-no.
Fair 'nuf. But I haven't yet reached the conclusion that visitor is the
appropriate solution.
>> We ended up with somethign like this, except without switch_ (which
>> I like btw), so we can easily add new transform on the AST from the
>> external view point of user who didn't have to know much proto. As
>> I only had to define one grammar (the visitor)
This is something I have trouble with. A visitor is a grammar? That
doesn't make sense to me.
>> and only specialisation of the visitor for some tag, it compiled
>> fast and that was what we wanted.
>>
>> Thomas, why not showign the split example ? It's far better than
>> this one and I remember I and Eric weren't able to write it usign
>> grammar/transform back in the day.
Joel, I don't recall this particular problem or being unable to solve it
with Proto transforms.
> The split example was one of the motivating examples, that is
> correct, though it suffers the exact points Eric is criticizing. The
> split example was possible because i added some new transforms which
> proto currently misses, but i didn't want to shoot out all my
> ammunition just yet :P
>
> But since you ask for it:
>
> http://github.com/sithhell/boosties/blob/master/proto/libs/proto/test/splitter.cpp
>
> the new thing i added is transform_expr, which works like
> fusion::transform: It creates the expression again, with transformed
> child nodes (the child nodes get transformed according to the
> transform you specify as template parameter
If the theory is that this particular problem cannot be implemented with
existing Proto grammars and transforms, then I submit the attached
solution as contrary evidence. I'll admit that it doesn't have the
property that the transforms can be substituted post-hoc into an
existing Proto algorithm, but is that really necessary? There is no
grammar to speak of; *every* expression is a valid split expression.
This solution is much, much simpler than Thomas' solution that uses a
visitor. Heck, it took me longer to understand Thomas' code than it did
for me to write the solution using standard Proto components.
Still not seeing the big picture with visitors,
--
Eric Niebler
BoostPro Computing
http://www.boostpro.com
#include <iostream>
#include <boost/proto/proto.hpp>
#include <boost/fusion/algorithm/iteration/for_each.hpp>
namespace proto = boost::proto;
namespace fusion = boost::fusion;
namespace mpl = boost::mpl;
using proto::_;
// For display_expr debugging purposes
namespace boost { namespace mpl
{
template<int N>
std::ostream & operator<<(std::ostream & sout, mpl::int_<N>)
{
return std::cout << "mpl::int_<" << N << ">";
}
}}
namespace tag { struct split {}; }
template <typename Expr>
struct make_split
: proto::result_of::make_expr<tag::split, proto::default_domain, Expr>
{};
template <typename Expr>
typename make_split<Expr>::type const
split(Expr const& expr)
{
typename make_split<Expr>::type const e = {expr};
return e;
}
struct push_back
{
BOOST_PROTO_CALLABLE()
template <typename Sig>
struct result;
template <typename This, typename Seq, typename T>
struct result<This(Seq, T)>
: boost::add_const<
typename fusion::result_of::push_back<
typename boost::add_const<typename
boost::remove_reference<Seq>::type>::type
, typename boost::remove_const<typename
boost::remove_reference<T>::type>::type
>::type
>
{};
template <typename Seq, typename T>
typename fusion::result_of::push_back<Seq const, T>::type const
operator()(Seq const& seq, T const& t) const
{
return fusion::push_back(seq, t);
}
};
#if BOOST_WORKAROUND(BOOST_MSVC, BOOST_TESTED_AT(1600))
#define push_back(x,y) proto::call<push_back(x,y)>
#endif
// Given an expression that (maybe) contains split expressions,
// replace the expressions with mpl::int_<0> terminals.
struct Substitute
: proto::or_<
proto::when<
proto::unary_expr<tag::split, _>
, proto::terminal<mpl::int_<0> >::type(mpl::int_<0>())
>
, proto::terminal<_>
, proto::nary_expr<_, proto::vararg<Substitute> >
>
{};
// Walk an expression recursively. Collect into the state
// vector the split expressions. Return the collected
// replacements.
struct Replacements
: proto::or_<
proto::when<proto::terminal<_>, proto::_state>
, proto::when<
proto::unary_expr<tag::split, _>
, Replacements(
proto::_child
, push_back(proto::_state, Substitute(proto::_child))
)
>
, proto::otherwise<proto::fold<_, proto::_state, Replacements> >
>
{};
// Start the recursive replacement collection on an expression
// that may have split expressions.
struct Splitter
: proto::otherwise<
Replacements(_, push_back(proto::_state, Substitute))
>
{};
#if BOOST_WORKAROUND(BOOST_MSVC, BOOST_TESTED_AT(1600))
#undef push_back
#endif
int main()
{
typedef proto::terminal<char>::type char_;
char_ const a = {'a'};
char_ const b = {'b'};
char_ const c = {'c'};
char_ const d = {'d'};
char_ const e = {'e'};
char_ const f = {'f'};
fusion::vector0<> const res = fusion::vector0<>();
fusion::for_each(Splitter()(split(a) + split(b), res),
proto::functional::display_expr()); std::cout << "\n\n";
fusion::for_each(Splitter()(a + b, res),
proto::functional::display_expr()); std::cout << "\n\n";
fusion::for_each(Splitter()(split(a) + b, res),
proto::functional::display_expr()); std::cout << "\n\n";
fusion::for_each(Splitter()(a + split(b), res),
proto::functional::display_expr()); std::cout << "\n\n";
fusion::for_each(Splitter()(a + split(b + c), res),
proto::functional::display_expr()); std::cout << "\n\n";
fusion::for_each(Splitter()(a+b+split( c*d + split(e-f)), res),
proto::functional::display_expr()); std::cout << "\n\n";
Splitter()(split(a) + split(b), res);
Splitter()(a + b, res);
Splitter()(split(a) + b, res);
Splitter()(a + split(b), res);
Splitter()(a + split(b + c), res);
}
_______________________________________________
proto mailing list
[email protected]
http://lists.boost.org/mailman/listinfo.cgi/proto