Author: lwall Date: 2009-01-26 05:06:43 +0100 (Mon, 26 Jan 2009) New Revision: 25031
Modified: docs/Perl6/Spec/S03-operators.pod src/perl6/Cursor.pmc src/perl6/STD.pm t/spec/S02-names_and_variables/names.t t/spec/S29-hash/exists.t Log: [STD, S03] more operator alignment and cleanup Modified: docs/Perl6/Spec/S03-operators.pod =================================================================== --- docs/Perl6/Spec/S03-operators.pod 2009-01-26 01:45:30 UTC (rev 25030) +++ docs/Perl6/Spec/S03-operators.pod 2009-01-26 04:06:43 UTC (rev 25031) @@ -12,9 +12,9 @@ Maintainer: Larry Wall <la...@wall.org> Date: 8 Mar 2004 - Last Modified: 13 Jan 2009 + Last Modified: 24 Jan 2009 Number: 3 - Version: 148 + Version: 149 =head1 Overview @@ -33,7 +33,7 @@ L Method postfix .meth .+ .? .* .() .[] .{} .<> .«» .:: .= .^ .: N Autoincrement ++ -- R Exponentiation ** - L Symbolic unary ! + - ~ ? | +^ ~^ ?^ \ ^ = + L Symbolic unary ! + - ~ ? | +^ ~^ ?^ ^ = L Multiplicative * / % +& +< +> ~& ~< ~> ?& div mod L Additive + - +| +^ ~| ~^ ?| ?^ L Replication x xx @@ -48,9 +48,9 @@ R Conditional ?? !! ff fff R Item assignment = := ::= => += -= **= xx= .= L Loose unary true not :by(2) - X Comma operator , p5=> + X Comma operator , p5=> : X List infix Z minmax X X~X X*X XeqvX ... - R List prefix : print push say die map substr ... [+] [*] any $ @ + R List prefix print push say die map substr ... [+] [*] any $ @ X Loose and and andthen X Loose or or xor orelse X Sequencer <==, ==>, <<==, ==>> @@ -82,7 +82,7 @@ Note that list associativity (X) only works between identical operators. If two different list-associative operators have the same precedence, -they are assumed to be left-associative with respect to each other. +they are assumed to be right-associative with respect to each other. For example, the C<X> cross operator and the C<Z> zip operator both have a precedence of "list infix", but: @@ -90,10 +90,10 @@ is parsed as: - (@a X @b) Z @c + @a X (@b Z @c) Similarly, if the only implementation of a list-associative operator -is binary, it will be treated as left associative. +is binary, it will be treated as right associative. If you don't see your favorite operator above, the following sections cover all the operators in precedence order. Basic operator @@ -669,18 +669,6 @@ =item * -C<< prefix:<\> >>, Capture constructor - - \$x - \...@x - \%x - \($invocant: $pos1, $pos2, :named($arg)) - -Defers the contextualization of its argument or arguments till it is -bound into some other context. - -=item * - C<< prefix:<^> >>, upto operator ^$limit @@ -1557,6 +1545,71 @@ explicitly if there is an explicit signature, or pull them out of C<%_> rather than C<@_> if there is no explicit signature. +=item * + +C<< infix:<:> >>, the invocant marker + + say $*OUT: "howdy, world" + say($*OUT: "howdy, world") + push @array: 1,2,3 + push(@array: 1,2,3) + \($object: 1,2,3, :foo, :!bar) + +The colon operator parses just like a comma, but marks the argument to its left as an +invocant, which has the effect of turning what would otherwise be a function +call into a method call. It may only be used on the first argument of +an argument list or capture, and will fail to parse if used in any other position. +When used within a capture, it is not yet know what signature the capture will +be bound to; if bound to a non-method's signature, the invocant merely turns +into the first positional argument, as if the colon had been a comma. + +To avoid confusion with other colon forms, the colon infix operator +must be followed by whitespace or a terminator. It may optionally +have whitespace in front of it. + +Note: distinguish this infix operator from the colon in + + @array.push: 1,2,3 + @array.push(1,2,3): 4,5,6 + push(@array, 1,2,3): 4,5,6 + +which is a special form that turns an ordinary function or method +call into a list operator. The special form is recognized only after +a dotty method call, or after the right parenthesis of a method or +function call. The special form does not allow intervening whitespace, +but requires whitespace before the next argument. In all other +cases a colon will be parsed as the start of an adverb if possible, +or otherwise the invocant marker (the infix described above). + +Another way to think of it is that the special colon is allowed to +add listop arguments to a parenthesized argument list only after +the right parenthesis of that argument list, with the proviso that +you're allowed to shorten C<.foo(): 1,2,3> down to C<.foo: 1,2,3>. +(But only for method calls, since ordinary functions don't need the +colon in the first place to turn into a listop, just whitespace. +If you try to extend a function name with a colon, it's likely +to be taken as a label.) + + foo $obj.bar: 1,2,3 # special, means foo($obj.bar(1,2,3)) + foo $obj.bar(): 1,2,3 # special, means foo($obj.bar(1,2,3)) + foo $obj.bar(1): 2,3 # special, means foo($obj.bar(1,2,3)) + foo $obj.bar(1,2): 3 # special, means foo($obj.bar(1,2,3)) + foo($obj.bar): 1,2,3 # special, means foo($obj.bar, 1,2,3) + foo($obj.bar, 1): 2,3 # special, means foo($obj.bar, 1,2,3) + foo($obj.bar, 1,2): 3 # special, means foo($obj.bar, 1,2,3) + foo $obj.bar : 1,2,3 # infix:<:>, means $obj.bar.foo(1,2,3) + foo ($obj.bar): 1,2,3 # infix:<:>, means $obj.bar.foo(1,2,3) + foo $obj.bar:1,2,3 # syntax error + foo $obj.bar :1,2,3 # syntax error + foo $obj.bar :baz # adverb, means foo($obj.bar(:baz)) + foo ($obj.bar) :baz # adverb, means foo($obj.bar, :baz) + foo $obj.bar:baz # extended identifier, foo( $obj.'bar:baz' ) + foo $obj.infix:<+> # extended identifier, foo( $obj.'infix:<+>' ) + foo: 1,2,3 # label at statement start, else infix + +The moral of the story is, if you don't know how the colon is +going to bind, use whitespace or parentheses to make it clear. + =back =head2 List infix precedence @@ -1827,18 +1880,6 @@ =item * -C<< infix:<:> >>, the invocant marker - - say $*OUT: "howdy, world" - -The colon operator turns method calls and contextualizers into -list operators. It's not really a general operator; much like list -assignment, it takes a special syntax on the left side and turns it -into a list operator over the list on the right. See L</Invocant -marker>. - -=item * - Normal listops print push say join split substr open etc. @@ -2336,7 +2377,8 @@ =item * -The unary backslash operator captures its arguments, and returns an +The unary backslash operator is not really an operator, but a special noun form. +It "captures" its argument or arguments, and returns an object representing those arguments. You can I<dereference> this object in several ways to retrieve different parts of the arguments; see the definition of C<Capture> in S02 for details. (No whitespace is allowed Modified: src/perl6/Cursor.pmc =================================================================== --- src/perl6/Cursor.pmc 2009-01-26 01:45:30 UTC (rev 25030) +++ src/perl6/Cursor.pmc 2009-01-26 04:06:43 UTC (rev 25031) @@ -12,7 +12,7 @@ require 'mangle.pl'; our $CTX = ''; -our $DEBUG = defined($ENV{STD5DEBUG}) ? 1 : 0; +our $DEBUG = 0 + ($ENV{STD5DEBUG} // 0); our $DEPTH = 0; our %LEXERS; # per language, the cache of lexers, keyed by rule name our %FATECACHE; # fates we've already turned into linked lists Modified: src/perl6/STD.pm =================================================================== --- src/perl6/STD.pm 2009-01-26 01:45:30 UTC (rev 25030) +++ src/perl6/STD.pm 2009-01-26 04:06:43 UTC (rev 25031) @@ -14,6 +14,8 @@ my $ORIG is context; my @MEMOS is context; my $VOID is context<rw>; +my $INVOCANT_OK is context<rw>; +my $INVOCANT_IS is context<rw>; my @PADS; # random rule for debugging, please ignore @@ -1036,7 +1038,7 @@ | <colonpair> { $<fake> = 1; $<sym> = ':'; - %<O><prec> = %comma<prec>; + %<O><prec> = %comma<prec>; # actual test is non-inclusive of comma! %<O><assoc> = 'unary'; %<O><uassoc> = 'left'; } @@ -1055,7 +1057,7 @@ # doing fancy as one rule simplifies LTM token dotty:sym<.*> ( --> Methodcall) { - ('.' [ <[+*?=:]> | '^' '!'? ]) :: <.unspacey> <dottyop> + ('.' [ <[+*?=]> | '^' '!'? ]) :: <.unspacey> <dottyop> { $<sym> = $0.item; } } @@ -1071,6 +1073,7 @@ :dba('dotty method or postfix') [ | <methodop> + | <colonpair> | <!alpha> <postop> { $<O> = $<postop><O>; $<sym> = $<postop><sym>; } # only non-alpha postfixes have dotty form ] } @@ -1215,6 +1218,10 @@ ]? } +token semiarglist { + <arglist> ** ';' +} + token arglist { :my StrPos $endargs is context<rw> = 0; :my $GOAL is context = 'endargs'; @@ -1222,7 +1229,20 @@ :dba('argument list') [ | <?stdstopper> - | <EXPR(item %list_prefix)> + | <EXPR(item %list_prefix)> {{ + my $delims = $<EXPR><delims>; + for @$delims { + if ($_.<sym> // '') eq ':' { + if $+INVOCANT_OK { + $+INVOCANT_IS = $<EXPR><list>[0]; + } + else { + $¢.panic("Illegal use of colon as invocant marker"); + } + } + $+INVOCANT_OK = 0; + } + }} ] } @@ -2959,6 +2979,9 @@ token infix:sym<%> ( --> Multiplicative) { <sym> } +token infix:sym<mod> ( --> Multiplicative) + { <sym> } + token infix:sym<+&> ( --> Multiplicative) { <sym> } @@ -3086,31 +3109,7 @@ token infix:sym<^..^> ( --> Nonchaining) { <sym> } -token infix:sym<ff> ( --> Nonchaining) - { <sym> } -token infix:sym<^ff> ( --> Nonchaining) - { <sym> } - -token infix:sym<ff^> ( --> Nonchaining) - { <sym> } - -token infix:sym<^ff^> ( --> Nonchaining) - { <sym> } - -token infix:sym<fff> ( --> Nonchaining) - { <sym> } - -token infix:sym<^fff> ( --> Nonchaining) - { <sym> } - -token infix:sym<fff^> ( --> Nonchaining) - { <sym> } - -token infix:sym<^fff^> ( --> Nonchaining) - { <sym> } - - ## chaining binary token infix:sym<==> ( --> Chaining) { <sym> } @@ -3209,6 +3208,30 @@ token infix:sym<?> ( --> Conditional) { <sym> <.obs('?: for the conditional operator', '??!!')> } +token infix:sym<ff> ( --> Conditional) + { <sym> } + +token infix:sym<^ff> ( --> Conditional) + { <sym> } + +token infix:sym<ff^> ( --> Conditional) + { <sym> } + +token infix:sym<^ff^> ( --> Conditional) + { <sym> } + +token infix:sym<fff> ( --> Conditional) + { <sym> } + +token infix:sym<^fff> ( --> Conditional) + { <sym> } + +token infix:sym<fff^> ( --> Conditional) + { <sym> } + +token infix:sym<^fff^> ( --> Conditional) + { <sym> } + ## assignment # There is no "--> type" because assignment may be coerced to either # item assignment or list assignment at "make" time. @@ -3251,7 +3274,7 @@ { <sym> } token infix:sym<:> ( --> Comma) - { <sym> } + { <sym> <?before \s | <terminator> > } token infix:sym« p5=> » ( --> Comma) { <sym> } @@ -3295,7 +3318,7 @@ { $t = $<identifier>.text; } <args( $¢.is_type($t) )> {{ - %ROUTINES{$t} ~= $¢.lineof($¢.pos) ~ ' ' unless $¢.is_routine($t); + %ROUTINES{$t} ~= $¢.lineof($¢.pos) ~ ' ' unless $<args><invocant> or $¢.is_routine($t); }} } @@ -3307,17 +3330,20 @@ token args ($istype = 0) { :my $listopish = 0; :my $GOAL is context = ''; + :my $INVOCANT_OK is context<rw> = 1; + :my $INVOCANT_IS is context<rw>; [ - | :dba('argument list') '.(' ~ ')' <semilist> {*} #= func args - | :dba('argument list') '(' ~ ')' <semilist> {*} #= func args - | :dba('argument list') <.unsp> '.'? '(' ~ ')' <semilist> {*} #= func args - | {} [<?before \s> <!{ $istype }> <.ws> <!infixstopper> <listopargs=arglist> { $listopish = 1 }]? + | :dba('argument list') '.(' ~ ')' <semiarglist> {*} #= func args + | :dba('argument list') '(' ~ ')' <semiarglist> {*} #= func args + | :dba('argument list') <.unsp> '.'? '(' ~ ')' <semiarglist> {*} #= func args + | { $listopish = 1 } [<?before \s> <!{ $istype }> <.ws> <!infixstopper> <arglist>]? ] + { $<invocant> = $INVOCANT_IS; } :dba('extra arglist after (...):') [ || <?{ $listopish }> - || ':' <?before \s> <listopargs=arglist> # either switch to listopiness + || ':' <?before \s> <moreargs=arglist> # either switch to listopiness || {{ $<O> = {}; }} # or allow adverbs (XXX needs hoisting?) ] } @@ -3353,9 +3379,6 @@ token infix:sym<andthen> ( --> Loose_and) { <sym> } -token infix:sym<andthen> ( --> Loose_and) - { <sym> } - ## loose or token infix:sym<or> ( --> Loose_or) { <sym> } @@ -3366,9 +3389,7 @@ token infix:sym<xor> ( --> Loose_or) { <sym> } -token infix:sym<orelse> ( --> Loose_or) - { <sym> } - +## sequencer token infix:sym« <== » ( --> Sequencer) { <sym> } @@ -3655,7 +3676,7 @@ when 'chain' { } # just shift when 'unary' { } # just shift when 'list' { # if op differs reduce else shift - reduce() if $infix<sym> !eqv @opstack[*-1]<sym>; + # reduce() if $infix<sym> !eqv @opstack[*-1]<sym>; } default { $here.panic('Unknown associativity "' ~ $_ ~ '" for "' ~ $infix<sym> ~ '"') } } @@ -3946,7 +3967,7 @@ ] } - token assertion:identifier { <identifier> [ # is qq right here? + token assertion:identifier { <longname> [ # is qq right here? | <?before '>' > | <.ws> <nibbler> | '=' <assertion> @@ -4193,7 +4214,7 @@ [ <?before ')'> || <.panic: "Unable to parse Perl 5 regex; couldn't find right parenthesis"> ] } - #token assertion:identifier { <identifier> [ # is qq right here? + #token assertion:identifier { <longname> [ # is qq right here? # | <?before ')' > # | <.ws> <nibbler> # ] Modified: t/spec/S02-names_and_variables/names.t =================================================================== --- t/spec/S02-names_and_variables/names.t 2009-01-26 01:45:30 UTC (rev 25030) +++ t/spec/S02-names_and_variables/names.t 2009-01-26 04:06:43 UTC (rev 25031) @@ -22,7 +22,7 @@ #?rakudo 3 skip "Parse error" is(Terrain::Hill::<$mountain>, 1024, 'varaible name with sigil not in front of 2 package levels deep'); is($Terrain::($mountain)::mountain, 1024, 'variable name with a package name partially given by a variable '); - is($($river)::mountain, 1024, 'variable name with package name completely given by variable'); + is($::($river)::mountain, 1024, 'variable name with package name completely given by variable'); } { Modified: t/spec/S29-hash/exists.t =================================================================== --- t/spec/S29-hash/exists.t 2009-01-26 01:45:30 UTC (rev 25030) +++ t/spec/S29-hash/exists.t 2009-01-26 04:06:43 UTC (rev 25031) @@ -32,7 +32,7 @@ my $b = %h1<b>; #?rakudo skip 'unspecced' - is (exists %h1, 'a'), 1, "Test existence for single key. (Indirect notation)"; + is (exists %h1: 'a'), 1, "Test existence for single key. (Indirect notation)"; is (%h1.exists('a')), 1, "Test existence for single key. (method call)"; };