|
Boost : |
From: Zach Laine (whatwasthataddress_at_[hidden])
Date: 2024-02-26 07:36:00
On Thu, Feb 22, 2024 at 2:17â¯AM Zach Laine <whatwasthataddress_at_[hidden]> wrote:
>
> On Wed, Feb 21, 2024 at 12:27â¯PM Phil Endecott via Boost
> <boost_at_[hidden]> wrote:
> >
[snip]
> > One other advantage of having the lambda return a result could
> > be improving how the semantic type (aka attribute type) of a
> > rule is set. For example, if I have the rule
> >
> > degrees >> minutes
> >
> > where degrees and minutes return doubles, the semantic type of
> > the combined rule is something like tuple<double,double>. But
> > I'm going to add a semantic action that adds the two values as
> > shown above, returning one double. If the return value of the
> > semantic action's lambda were used as the semantic type of the
> > rule then we could write:
> >
> > auto rule = (degrees >> minutes)
> > [( [](auto d, auto m) { return d + m/60.0; } )];
> >
> > and rule would return a double to its parent rule. As it is, the
> > semantic action doesn't change the type and we have to
> > explicitly and verbosely declare the rule as returning a double.
>
> I had not thought of this before, but I really like it. I'll have to
> think pretty deeply about whether there is some reason this might not
> work, but I'm definitely going to try to implement this. I'm thinking
> that the rule would be: if std::apply(f, tup) is well-formed (where f
> is your invocable, and tup is your tuple of values returned by
> _attr()), and decltype(std::apply(f, tup)) is assignable to _val(),
> then do the semantic action as _val(ctx) = std::apply(f, _attr(ctx));
> otherwise, the semantic action gets called with the current context..
> There would be a special case when _attr() is not a tuple, but you get
> the idea. Ticket to track it:
> https://github.com/tzlaine/parser/issues/106
This is now implemented. The logic I came up with is this. In
general, the return value of the semantic action can be used to assign
the value that would normally be assigned to _val(ctx) in a semantic
action, but after the semantic action is executed. So, now you can
write a semantic action with a signature like void(auto&ctx) like
before, or you can write one like T(auto&ctx), for some non-void type
T. In the latter case, the returned T gets assigned to _val(ctx).
You can also write a semantic action that takes the attribute and
returns something assignable to _val(ctx), or even one that takes the
individual elements of the attribute, if it is a tuple, and returns
something assignable to _val(ctx).
>From the updated docs:
"
More formally, within a rule, the use of a semantic action is
determined as follows. Assume we have a function APPLY that calls a
function with the elements of a tuple, like std::apply. For some
context ctx, semantic action action, and attribute attr, action is
used like this:
- _val(ctx) = action(std::move(attr)), if that is well-formed;
- otherwise, _val(ctx) = APPLY(action, std::move(attr)), if that is well-formed;
- otherwise, _val(ctx) = action(ctx), if that is well-formed;
- otherwise, action(ctx).
The first two cases do not pass the context to the action at all. The
last case is the normal use of semantic actions outside of rules.
"
Zach
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk