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

Reply via email to