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
proto@lists.boost.org
http://lists.boost.org/mailman/listinfo.cgi/proto

Reply via email to