Here's the current precedence table as I see it, based mostly
on what the, er, cabal came up with after the Perl conference.

[Cabal members: note that I've demoted cmp and <=> from chaining
relationals, and I've moved the pipe operators closer together.
I've also generalized the two middle categories to chaining and
non-chaining binaries, and stuffed "but" into the non-chaining,
since we neglected to deal with it.]

    terms               42 "eek" $x /abc/ (1+2) a(1) :by(2) .meth listop(left)
    method postfix      .foo .+foo .?foo .*foo .+foo .() .[] .{} .«» .=foo
    autoincrement       ++ --
    exponentiation      **
    symbolic unary      ! + - ~ ? * ** +^ ~^ ?^ \
    multiplicative      * / % x xx +& +<< +>> ~& ~<< ~>>
    additive            + - ~ +| +^ ~| ~^
    junctive and (all)  &
    junctive or (any)   | ^
    named unary         rand sleep abs etc.
    nonchaining binary  => but does cmp <=> .. ^.. ..^ ^..^
    chaining binary     != == < <= > >= ~~ !~ eq ne lt le gt ge =:=
    tight and           &&
    tight or            || ^^ //
    ternary             ?? ::
    assignment          = := ::= += **= xx= etc. (but not .=)
    list item separator ,
    list op (rightward) <== print push any all true not etc.
    pipe forward        ==>
    loose and           and
    loose or            or xor err
    expr separator      ; {} as control block, statement modifiers

Some random comments:

Hyper ops always have the same precedence as their unhyper versions.

List operators are terms on their left side only, just as in Perl 5.
Basically you can think of them kind of as an opening paren without a
corresponding closing paren.  (Instead they're closed by something
of looser precedence.)

The .meth as a term is the one we call "unary dot" because it doesn't
have an invocant.  But really it's just parsed as a term, because you
only get it when a term is expected.  The method postfixes are when
an operator is expected.  Dot itself is not really an operator--it
just introduces a postfix operator.  This is important to understand
because, as a postfix operator, you only hyperize the left of it:

    @foo».bar

All the bitwise operators are considered to be doing boolean algebra,
where 1 * 1 == 1, so they're just classified with the ordinary multiply
and divide operations.  The bitwise shifts are also multiplicative,
but because they multiply or divide by two.  The cabal felt the various
bit operators weren't important enough to warrant separate precedence
levels anymore.  Even in C, people almost always parenthesize them
because they're not sure...

However, even though they've merged with the arithmetic operators,
you'll note that by the rules of boolean algebra, the "ands" are still
one precedence level tighter than the "ors".  That is consistent 
across all the "ands" and "ors" of every time.  (And the corresponding
"not" is always tighter than either the "and" or the "or".)

The xx operator is in there with the x operator only for mnemonic
purposes.  By rights it should probably be a lot looser if we want
it to "multiply lists", but we'll just force people to parenthesize
their lists, as we do with list assignment.

Junctions deserve their own levels because they're actually
constructing compound data values out of simple ones, so they need
to be looser than the simple data operators but tighter than the
comparison operators.  Arguably they could be looser than named
unaries, but it sort of feels right to keep all the generic unary
and binary operators in the middle together.

There is no binary "nor" operator...

The generic non-chaining binaries are mostly the sorts of operators
that construct new objects (ranges, pairs, mixins) out of two related
values.  Though admittedly, the numbers -1, 0, and 1 are a bit of a
stretch to think of that way in the case of cmp and <=>.  I don't
think there's much merit in defining a "comparison result object"
that just happens to return -1, 0, or 1...

We haven't said much about associativity here.  Mostly it's what you'd
expect.  ** and = are right associative, ++/-- are nonassociative.
I think the main reason for lumping all the non-chaining binaries
together is that we should call them non-associative, and you have
to parenthesize to be clear whether you mean:

    ($a => $b) => $c
    ($a .. $b) .. $c
    ($a but $b) but $c

or

    $a => ($b => $c)
    $a .. ($b .. $c)
    $a but ($b but $c)

Assuming those mean anything at all.  Certainly a pair can contain
a pair as either its key or its value (or both).

Nothing much surprising down to the list ops.  We decided to make
C<true> and C<not> list ops just to save a level of precedence,
though we'll probably actually make them able to process lists of
values so you can say weird things like

    if all true $a, $b, $c {...}

and

    if all not $a, $b, $c {...}

though admittedly

    if not all $a, $b, $c {...}

reads a little better, and also presumably works.  Or how about this?

    if not all true $a, $b, $c {...}

The ==> operator is not a list operator because it wants to gobble
any list or listop on its left and pass it to a listop on its right.

The C<;> level is basically the loosest thing recognized by the
operator precedence grammar.  Anything looser than C<;> or tighter
than a term is the province of the recursive descent grammar.  We
could have just left it out, except that we want to be able to
parse semicolons within subscripts for slice notation:

    @foo[0..100:by(5); 0..10; $x; /foo/]

We also want semicolons in loops:

    loop $i = 1; $i; $i++ {...}

You'll note that that cannot readily be parsed by operator precedence,
though.  We could go as far as to try to give a looser precedence to
things like loop ... {...}, but that's really a little silly when we
can just have grammar rules for those kinds of things.  The control
structures are essentially macros, and macros are essentially terms
on the outside, with some number of embedded calls to the operator
precedence grammar inside.

Also of note is that we decided to keep the relative precedence of
assignment and comma the same as in Perl 5.  It's just good documentation
to parenthesize your lists when assigning, and it prevents nasty
surprises when C programmers write things like:

    loop $i = 0, $j = 0; $i < 10; $i++, $j += 10 {...}

Anyway, feel free to point out any infelicities we might not have
considered.  The fact that there are fewer precedence levels than in
Perl 5 will not be considered an infelicity.  :-)

Larry

Reply via email to