Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is this Perl 6 feed operator a "bogus statement"?

I took this example from Day 10 – Feed operators of the Perl 6 2010 Advent Calendar with the slight change of .uc for the .ucfirst that's no longer there:

my @rakudo-people = <scott patrick carl moritz jonathan jerry stephen>;
@rakudo-people
    ==> grep { /at/ } ==> map { .uc } ==> my @who-it's-at;
say ~@who-it's-at;

I write it slightly differently with some additional whitespace:

my @rakudo-people = <scott patrick carl moritz jonathan jerry stephen>;
@rakudo-people
    ==> grep { /at/ }
    ==> map { .uc } ==> my @who-it's-at;
say ~@who-it's-at;

Now it's a "bogus statement":

===SORRY!=== Error while compiling ...
Bogus statement
------>         ==> grep { /at/ }⏏<EOL>
expecting any of:
    postfix
    prefix
    statement end
    term

This isn't a problem with just this example. Some examples in the current docs can exhibit the same behavior.

If I add an unspace to the end of the offending line, it works again:

my @rakudo-people = <scott patrick carl moritz jonathan jerry stephen>;
@rakudo-people
    ==> grep { /at/ } \
    ==> map { .uc } ==> my @who-it's-at;
say ~@who-it's-at;

Curiously, a comment at the end of that line does not work. I would have thought it would have eaten the offending whitespace.

The feed operator says:

In the case of routines/methods that take a single argument or where the first argument is a block, it's often required that you call with parentheses

That works:

my @rakudo-people = <scott patrick carl moritz jonathan jerry stephen>;
@rakudo-people
    ==> grep( { /at/ } )
    ==> map { .uc } ==> my @who-it's-at;
say ~@who-it's-at;

But why wasn't that a problem in the first form? What is the whitespace doing here? And what situations are included in "often required"?

like image 925
brian d foy Avatar asked Jul 23 '17 20:07

brian d foy


1 Answers

From the Perl 6 documentation on Separating Statements:

A closing curly brace followed by a newline character implies a statement separator

In other words, whenever the closing brace of a block is the last thing in a line (not counting whitespace and comments), then the parser implicitly inserts a semicolon after it.

This allows us to write things like the following without a semicolon after the }:

my @foo = @bar.map: {
    ...
}

The semicolon would be ugly there, and if you had first written the loop as for @bar { ... } and then decided to turn it into a map with assignment like this, adding the trailing semicolon would be annoying and easy to forget. So for the most part, this automatic statement termination after end-of-line blocks is helpful.

However, feed operators feeding into blocks are one case (possibly the only one) where it trips people up.

To prevent it from happening, insert \ (a.k.a. unspace) after the block, as you've already noted. The unspace makes the whitespace which includes the newline invisible to the parser, and thus the aforementioned newline-based parser rule won't be applied.

like image 173
smls Avatar answered Jan 18 '23 18:01

smls