Boost logo

Proto :

Subject: Re: [proto] : How to use complex grammars in a domain/extension
From: Thomas Heller (thom.heller_at_[hidden])
Date: 2010-09-21 10:26:20


Eric Niebler wrote:

> On 9/21/2010 9:51 AM, Eric Niebler wrote:
>> (proto lists members, see this thread for the rest of the discussion,
>> which has been happening on -users:
>> http://lists.boost.org/boost-users/2010/09/62747.php)
>>
>> On 9/21/2010 9:19 AM, Roland Bock wrote:
>>> On 09/21/2010 11:55 AM, Thomas Heller wrote:
>>>> <snip>
>>>> Solved the mistery. here is the code, explanation comes afterward:
>>>>
>>>> <snip>
>>>> So, everything works as expected!
>>>>
>>> Thomas,
>>>
>>> wow, this was driving me crazy, thanks for solving and explaining in all
>>> the detail! :-)
>>>
>>> I am still not sure if this isn't a conceptual problem, though:
>>>
>>> The "equation" grammar is perfectly OK. But without or-ing it with the
>>> "addition" grammar, the extension does not allow ANY valid expression to
>>> be created. I wonder if that is a bug or a feature?
>>
>> It's a feature. Imagine this grammar:
>>
>> struct IntsOnlyPlease
>> : proto::or_<
>> proto::terminal<int>
>> , proto::nary_expr<proto::_, proto::vararg<IntsOnlyPlease> >
>> >
>> {};
>>
>> And a integer terminal "i" in a domain that obeys this grammar. Now,
>> what should this do:
>>
>> i + "hello!";
>>
>> You want it to fail because if it doesn't, you would create an
>> expression that doesn't conform to the domain's grammar. Right? Proto
>> accomplishes this by enforcing that all operands must conform to the
>> domain's grammar *and* the resulting expression must also conform.
>> Otherwise, the operator is disabled.
>>
>> Anything else would be fundamentally broken.
>
> This explanation is incomplete. Naturally, this operator+ would be
> disabled anyway because the resulting expression doesn't conform to the
> grammar regardless of whether the LHS and RHS conform. It's a question
> of *when* the operator gets disabled. For a full explanation, see this
> bug report:
>
> https://svn.boost.org/trac/boost/ticket/2407
>
> The answer is simple and logically consistent: make sure *every* valid
> expression in your domain (including lone terminals) is accounted for by
> your grammar.

Let me add something:

The more I thought i about the problem, the more i thought that this would
be a perfect use case for sub domains! So i tried to hack something
together:

#include<boost/proto/proto.hpp>

using namespace boost;

typedef proto::terminal<int>::type const terminal;

struct equation;

struct addition:
    proto::or_
    <
       proto::terminal<proto::_>,
       proto::plus<addition, addition>
>
{};

struct equation:
    proto::or_
    <
        proto::equal_to<addition, addition>
>
{};

template<class Expr>
struct extension;

struct my_domain:
    proto::domain
    <
         proto::pod_generator<extension>,
         proto::or_<equation, addition>,
         proto::default_domain
>
{};

template<class Expr>
struct lhs_extension;

struct my_lhs_domain:
    proto::domain
    <
        proto::pod_generator<lhs_extension>,
        addition,
        my_domain
>
{};

template<class Expr>
struct rhs_extension;

struct my_rhs_domain:
    proto::domain
    <
        proto::pod_generator<rhs_extension>,
        addition,
        my_domain
>
{};

template<class Expr>
struct extension
{
     BOOST_PROTO_BASIC_EXTENDS(
         Expr
       , extension<Expr>
       , my_domain
     )

    void test() const
    {}
};

template<class Expr>
struct lhs_extension
{
     BOOST_PROTO_BASIC_EXTENDS(
         Expr
       , lhs_extension<Expr>
       , my_lhs_domain
     )
};

template<class Expr>
struct rhs_extension
{
     BOOST_PROTO_BASIC_EXTENDS(
         Expr
       , rhs_extension<Expr>
       , my_rhs_domain
     )
};

template <typename Grammar, typename Expr>
void matches(Expr const& expr)
{
    expr.test();

     std::cout << std::boolalpha
         << proto::matches<Expr, Grammar>::value << "\n";
}

int main()
{
     lhs_extension<terminal> const i = {};
     rhs_extension<terminal> const j = {};

     /*matches<equation>(i); // false
     matches<equation>(j); // false
     matches<equation>(i + i); // false
     matches<equation>(j + j); // false*/
     //matches<equation>(i + j); // compile error
     //matches<equation>(j + i); // compile error
     matches<equation>(i == j); // true
     matches<equation>(i == j + j); // true
     matches<equation>(i + i == j); // true
     matches<equation>(i + i == j + j); // true
}

This seems to be exactly what Roland wanted to achieve in the first place.
However, it looks like this design just overcomplicates stuff because we
have to specify the "addition" in our base domain anyway ...

Initially i was under the impression that this wasn't needed, but it seems
that proto cannot deduce something like:

lhs_expression OP rhs_expression results in expression

So the question is: is it reasonable to add features like that?
It seems valuable to me.


Proto list run by eric at boostpro.com