Here's a message I posted to the cabal last week a couple of days after
our design meetings, in which we discussed the method lookahead issue.
This message resolves those issues as well as how adverbs are parsed.
Eventually this information will find its way into S12, when we get
around to writing it.
Larry
Date: Wed, 4 Aug 2004 10:13:27 -0700
From: Larry Wall <[EMAIL PROTECTED]>
Subject: resolution of method argument parsing issues
Okay, after mulling over this for two days and going over the same
mental ground repeatedly, I've come to some conclusions. First,
it's a mistake to try to make methods and functions parse the same.
Once I get that bee out of my bonnet, I am free to say they work
different (compare 1 with 2):
1) In the absence of evidence to the contrary, functions always
assume they're list operators. For functions:
1a) Unary and zero-ary functions will parse specially only if
there is an appropriate non-multi declaration, as in Perl 5.
$later = time + 20;
1b) The predeclaration of multis has no effect on parsing. They are
always parsed as list operators. Undeclared functions are assumed
to be multies, and can therefore be written in either functional
or listop notation.
1c) Explicit parentheses may delimit the actual arguments,
in which case the function is parsed as a function rather
than a list operator. Adverbs may follow the parens:
splurt(1,2,3):by{ +$_ } # okay
splurt(1,2,3):{ +$_ } # okay (implicit binding to *& param)
splurt 1,2,3 # okay (assumed to be list operator)
splurt; # okay, 0-arg list
splurt() + 1 # okay, explicit 0 arg list
splurt + 1 # wrong unless predeclared 0-ary
1d) Additional arguments may occur as adverbs *only* if there
are explicit parens. (Or in the absence of parens they may
parse as arguments when a term is expected--but then they're
not adverbs, just named arguments...)
splurt():by{ +$_ } # okay
splurt 1,2,3 :by{ +$_ } # ILLEGAL (comma rejects the adverb)
splurt 1,2,3 :{ +$_ } # ILLEGAL (comma rejects the adverb)
splurt 1,2,3,:{ +$_ } # likely okay (as anonymous named param)
splurt :{ +$_ } # likely okay (as anonymous named param)
splurt { +$_ } # okay (positional param)
splurt 1,2,3, { +$_ } # okay (positional param)
2) In the absence of evidence to the contrary, methods always
assume they have *no* arguments. For methods:
2a) A method not followed by a left paren or colon has no
arguments.
2b) As with multies, method declarations can have no effect on the
parsing of methods. Unlike multis, the default is no arguments.
2c) The only way to pass arguments to a method is by an
explicitly parenthesized list or by adverb. Or by both.
.splurt(1,2,3):by{ +$_ } # okay
.splurt(1,2,3):{ +$_ } # okay (implicit binding to *& param)
.splurt 1,2,3 # ILLEGAL
.splurt; # okay, 0-arg list
.splurt() + 1 # okay, explicit 0 arg list
.splurt + 1 # okay
2d) Given 2c, additional arguments may occur as adverbs
whether or not there is an argument "pill":
.splurt():by{ +$_ } # okay
.splurt 1,2,3 :by{ +$_ } # ILLEGAL (no term expected)
.splurt 1,2,3 :{ +$_ } # ILLEGAL (no term expected)
.splurt 1,2,3,:{ +$_ } # ILLEGAL (parens required)
.splurt :{ +$_ } # okay (as adverb--no term expected)
.splurt { +$_ } # ILLEGAL (parens required)
.splurt 1,2,3, { +$_ } # ILLEGAL (parens required)
3) A bare {...} where an operator is expected always terminates the
current list operator, and takes the precedence level back to statement
level. That is, it pops all the implicit left parentheses of list
operators with implicit right parentheses.
if print sort { +$_ }, @foo {...}
if print(sort({ +$_ }, @foo)) {...} # same thing
3a) Note that an operator {...} cannot occur in the arguments of either
a function or a method. Operator {...} is reserved for statement level
control flow blocks.
if blurk {...} {...} # 1st closure is arg, 2nd ifblock
if blurk(1) {...} # closure is ifblock
if blurk 1 {...} # closure is ifblock
if .blurk {...} # closure is ifblock
if .blurk {...} {...} # 1st is ifblock, 2nd is bare block?
if .blurk:{...} {...} # 1st closure is adverb, 2nd ifblock
if .blurk(1) {...} # closure is ifblock
if .blurk 1 {...} # ILLEGAL
3b) Term {...} cannot assume a comma after it if the next thing is
a closure. Otherwise the first line under 3a breaks. The fifth
line with a bare block is a bit problematic as a silent failure mode
if the user expects the first block to be an argument to .blurk, which
it isn't.
3c) Actually, despite the fact that I stated 3 in terms of
precedence, as far as the parser is concerned 3 probably
means that statement control things are parsed top down,
and the bottom up expression parser simply stops when it hits
an operator {...}.
4) Adverbs apply to the previous unparenthesized prefix, infix,
or postfix operator, bypassing simple terms and other "pill"
operators such as circumfix or postcircumfix.
$a + $b :foo # applies to +
$a + @b[2] :foo # applies to +
$a + int($b) :foo # applies to int
$a + (int($b)) :foo # applies to +
@a.=sort:{ +$_ } # applies to .sort
@a.sort(:quick):{ +$_ } # applies to .sort
@a.sort:quick:{ +$_ } # both adverbs apply to .sort
(This kind of argues that the iterator deref operator <...>
shouldn't be a circumfix though, if we want to adverb it.
It's tempting to steal <...> for something else anyway.)
5) The idea of trying to guess by lookahead heuristics whether
methods have parameters is dead (except for parens and colon).
The idea of using the colon in method C<.foo: 1,2,3> to force an
unparenthesized argument list is also dead. The adverbs are more
powerful, and more importantly, keep the operator precedence
parser at the right precedence, and keep the parens off of
attribute methods everywhere (except interpolation, of course).
Plus the indirect-object-like use of colon was ambiguous with
real indirect objects anyway:
foo $bar.baz: 1,2,3 # now is unambiguously $bar.baz.foo(1,2,3)
So the upshot is that if you want to avoid the parens around curlies
ugliness:
@foo.map({...}).sort({...})
you write the blocks as adverbs:
@foo.map:{...}.sort:{...}
Larry