Author: lwall Date: 2009-01-29 21:32:51 +0100 (Thu, 29 Jan 2009) New Revision: 25113
Modified: docs/Perl6/Spec/S03-operators.pod src/perl6/STD.pm Log: [STD, S03] slaughter of the LTM metatokens STD now runs considerably faster Freed from LTM, metaoperators may now be nested arbitrarily deep new &[op] notation for infix functions Modified: docs/Perl6/Spec/S03-operators.pod =================================================================== --- docs/Perl6/Spec/S03-operators.pod 2009-01-29 15:35:07 UTC (rev 25112) +++ docs/Perl6/Spec/S03-operators.pod 2009-01-29 20:32:51 UTC (rev 25113) @@ -12,9 +12,9 @@ Maintainer: Larry Wall <la...@wall.org> Date: 8 Mar 2004 - Last Modified: 27 Jan 2009 + Last Modified: 29 Jan 2009 Number: 3 - Version: 150 + Version: 151 =head1 Overview @@ -49,7 +49,7 @@ R Item assignment = := ::= => += -= **= xx= .= L Loose unary true not :by(2) X Comma operator , p5=> : - X List infix Z minmax X X~X X*X XeqvX ... + X List infix Z minmax X X~ X* Xeqv ... R List prefix print push say die map substr ... [+] [*] any $ @ X Loose and and andthen X Loose or or xor orelse @@ -1697,9 +1697,9 @@ Cross hyperoperators - @files X~X '.' X~X @extensions - 1..10 X*X 1..10 - @x XeqvX @y + @files X~ '.' X~ @extensions + 1..10 X* 1..10 + @x Xeqv @y etc. See L</Cross operators>. @@ -3507,21 +3507,24 @@ The precedence of any negated operator is the same as the base operator. +The operator + + !% + +is specially allowed for testing even divisibility by an integer. + Note that logical operators such as C<||> and C<^^> do not return a Bool, but rather one of the operands. =head2 Reversed comparison operators -Any infix comparison operator returning type C<Order> may be transformed into its reversed sense -by prefixing with C<->. +Any infix operator may be called with its two arguments reversed +by prefixing with C<R>. For instance, to do reversed comparisons: - -cmp - -leg - -<=> + Rcmp + Rleg + R<=> -To avoid confusion with the C<-=> operator, you may not modify -any operator already beginning with C<=>. - The precedence of any reversed operator is the same as the base operator. =head2 Hyper operators @@ -3964,22 +3967,22 @@ =head2 Cross operators The final metaoperator is the cross metaoperator. It is formed syntactically -by placing an infix operator between two C<X> characters. It applies the +by placing an infix operator after the C<X> character. It applies the modified operator across all groupings of its list arguments as returned by the ordinary C<< infix:<X> >> operator. All cross operators are of list infix precedence, and are list associative. The string concatenating form is: - <a b> X~X <1 2> # 'a1', 'a2', 'b1', 'b2' + <a b> X~ <1 2> # 'a1', 'a2', 'b1', 'b2' -The C<X~X> operator desugars to something like: +The C<X~> operator desugars to something like: - [~]«( <a b> X,X <1 2> ) # 'a1', 'a2', 'b1', 'b2' + [~]«( <a b> X, <1 2> ) # 'a1', 'a2', 'b1', 'b2' -The list concatenating form, C<X,X>, when used like this: +The list concatenating form, C<X,>, when used like this: - <a b> X,X 1,2 X,X <x y> + <a b> X, 1,2 X, <x y> produces @@ -3998,15 +4001,15 @@ For the general form, any existing, non-mutating infix operator may be used. - 1,2 X*X 3,4 # 3,4,6,8 + 1,2 X* 3,4 # 3,4,6,8 (Note that C<< <== >> and C<< ==> >> are considered mutating, as well as all assignment operators.) If the underlying operator is non-associating, so is the metaoperator: - @a XcmpX @b XcmpX @c # ILLEGAL - @a XeqX @b XeqX @c # ok + @a Xcmp @b Xcmp @c # ILLEGAL + @a Xeq @b Xeq @c # ok In fact, though the C<X> operators are all list associative syntactically, the underlying operator is always applied with its @@ -4019,44 +4022,37 @@ =head2 Nesting of metaoperators -In order to match operators by the longest-token rule, the -compiler pregenerates various metaforms based on existing operators. -Unfortunately, with nesting metaoperators there are an infinite number -of metaforms, so we arbitrarily say that no metacircumfix form is -pregenerated that uses the same grammatical category more than once. -Therefore forms like C<[+=]> and C<»!===«> and C<X*X=> are generated, -but not forms like C<»X*X«> or C<X«*»X> or C<<< <<+=>>= >>>. -You do get C<[X*X]>, -though, because reduction is prefix_circumfix_meta_operator while -cross operators are infix_circumfix_meta_operator. +Constructs containing metaoperators are considered "metatokens", +by which we mean that they are not subject to ordinary longest-token +matching rules, although their components are. Like ordinary +tokens, however, metaoperators do not allow whitespace between +their subparts. -This use-each-category-once limitation is not a great hardship since -you can define your own infix operators. Suppose you say +Any ordinary infix operator may be enclosed in square brackets +with the same meaning. You may therefore use square brackets +within a metaoperator to disambiguate sequences that might +otherwise be misinterpreted, or to force a particular order +of application when there are multiple metaoperators in the metatoken: - &infix:<xp> ::= &infix:<X*X>; + @a [X+]= @b + @a X[+=] @b -After this you can use C<XxpX>, C<[xp]>, and C<[«xp»=]«> as if C<xp> -were a built-in. Not that any of those necessarily make sense... +Any infix function may be referred to as a noun either by the normal long +form or a short form using square brackets directly after the C<&> sigil: -The compiler is not actually required to pregenerate the metaform -tokens as long as it can guarantee the same semantics, that is, -that it follows the longest-token rule across all syntax categories -active at that spot in the parse. This could be achieved by use -of a DFA parser (or exhaustive NFA matcher) to guarantee longest -match of the generatable forms, for instance, followed by a check -to make sure it is not trumped by an even longer "hardwired" token. -Suppose the user were to define, say, C<< infix:<xx...@$> >> or -C<< statement_modifier:<XxXfor> >>; those hardwired forms must take -precedence over the C<XxX> operator even if the metaform DFA only -knows how to recognize the C<XxX> part. + &infix:<+> + &[+] -Note that the maximum possible token length is bounded by the sum -of the maximum lengths of each metacategory, so an enumerated solution -is always possible, though perhaps not practical. It's also the case -that no metaform is allowed to contain whitespace, so a solution -that starts at the length of the current "word" and works down is also -possible. +This is convenient for function application: + 1,1 ... &[+] # fibonacci series + sort &[R<=>], @list # reversed, numerically + +There is no corresponding form for unary operators, but those may +usually be constructed by applying an operator to C<*>: + + sort +*, @list # sort numerically + =head1 Declarators The list of variable declarators has expanded from C<my> and C<our> Modified: src/perl6/STD.pm =================================================================== --- src/perl6/STD.pm 2009-01-29 15:35:07 UTC (rev 25112) +++ src/perl6/STD.pm 2009-01-29 20:32:51 UTC (rev 25113) @@ -1074,6 +1074,7 @@ %<O><assoc> = 'unary'; %<O><uassoc> = 'left'; } + | '[' ~ ']' <infixish> { $<O> = $<infixish><O> } | <infix> <!before '='> { $<O> = $<infix>.<O>; $<sym> = $<infix>.<sym>; } | <infix_prefix_meta_operator> @@ -1133,6 +1134,7 @@ } regex prefix_circumfix_meta_operator:reduce (--> List_prefix) { + <?before '['\S+']'> $<s> = ( '[' [ @@ -1162,63 +1164,57 @@ token postfix_prefix_meta_operator:sym< » > { <sym> | '>>' } token infix_prefix_meta_operator:sym<!> ( --> Transparent) { - <sym> <!before '!'> <infix> + <sym> <!before '!'> {} <infixish> - <!!{ $<O> = $<infix><O>; }> - <!!lex1: 'negation'> + <?{ $<O> = $<infixish><O>; }> [ - || <!!{ ($<O><returns> // '') eq 'Bool' }> + || <?{ ($<O><returns> // '') eq 'Bool' }> + || <?{ $<infixish>.text eq '=' }> || <.panic: "Only boolean infix operators may be negated"> ] <!{ $<O><hyper> and $¢.panic("Negation of hyper operator not allowed") }> } -token infix_prefix_meta_operator:sym<-> ( --> Transparent) { - <sym> <!before '='> <infix> +token infix_prefix_meta_operator:sym<R> ( --> Transparent) { + <sym> <!before '='> {} <infixish> - <!!{ $<O> = $<infix><O>; }> - <!!lex1: 'negation'> + <?{ $<O> = $<infixish><O>; }> [ - || <!!{ ($<O><returns> // '') eq 'Order' }> + || <?{ ($<O><returns> // '') eq 'Order' }> || <.panic: "Only comparison infix operators may be negated"> ] <!{ $<O><hyper> and $¢.panic("Negation of hyper operator not allowed") }> } -method lex1 (Str $s) { - self.<O>{$s}++ and self.panic("Nested $s metaoperators not allowed"); - self; -} +#method lex1 (Str $s) { +# self.<O>{$s}++ and self.panic("Nested $s metaoperators not allowed"); +# self; +#} -token infix_circumfix_meta_operator:sym<X X> ( --> List_infix) { - X [ - | <infix> X - | <infix=infix_prefix_meta_operator> X - | <infix=infix_circumfix_meta_operator> X - ] - <!!{ $<O> = $<infix><O>; }> - <!!lex1: 'cross'> +token infix_circumfix_meta_operator:sym<X> ( --> List_infix) { + X {} + [ <infixish> X? # XXX temporarily + <?{ $<O> = $<infixish><O>; }> + ]? } token infix_circumfix_meta_operator:sym<« »> ( --> Transparent) { [ - | '«' <infix> [ '«' | '»' ] - | '»' <infix> [ '«' | '»' ] - | '<<' <infix> [ '<<' | '>>' ] - | '>>' <infix> [ '<<' | '>>' ] + | '«' {} <infixish> [ '«' | '»' ] + | '»' {} <infixish> [ '«' | '»' ] + | '<<' {} <infixish> [ '<<' | '>>' ] + | '>>' {} <infixish> [ '<<' | '>>' ] ] - <!!{ $<O> := $<infix><O>; }> - <!!lex1: 'hyper'> + <?{ $<O> := $<infixish><O>; }> } token infix_postfix_meta_operator:sym<=> ($op --> Item_assignment) { '=' { $<O> = $op<O>; } - <?lex1: 'assignment'> [ <?{ ($<O><assoc> // '') eq 'non' }> <.panic: "Can't make assignment op out of non-associative operator"> ]? [ <!{ $<O><assign> }> <.panic("Can't make assignment out of " ~ $<O><dba> ~ " operator")> ]? @@ -1723,7 +1719,11 @@ token variable { <?before <sigil> { $+SIGIL ||= $<sigil>.text } > {} [ - || '&' <twigil>? <sublongname> {*} #= subnoun + || '&' + [ + | <twigil>? <sublongname> {*} #= subnoun + | '[' ~ ']' <infixish> + ] || <?before '$::('> '$' <name>? || '$::' <name>? # XXX || '$:' <name>? # XXX @@ -3005,7 +3005,7 @@ { <sym> } token infix:sym<%> ( --> Multiplicative) - { <sym> <!!{ $<O><returns> = 'Bool'; }> } # Allow !% operator + { <sym> <?{ $<O><returns> = 'Bool'; }> } # Allow !% operator token infix:sym<mod> ( --> Multiplicative) { <sym> } @@ -3014,16 +3014,16 @@ { <sym> } token infix:sym« +< » ( --> Multiplicative) - { <sym> } + { <sym> <!before '<'> } token infix:sym« << » ( --> Multiplicative) - { <sym> <.obs('<< to do left shift', '+< or ~<')> } + { <sym> \s <.obs('<< to do left shift', '+< or ~<')> } token infix:sym« >> » ( --> Multiplicative) - { <sym> <.obs('>> to do right shift', '+> or ~>')> } + { <sym> \s <.obs('>> to do right shift', '+> or ~>')> } token infix:sym« +> » ( --> Multiplicative) - { <sym> } + { <sym> <!before '>'> } token infix:sym<~&> ( --> Multiplicative) { <sym> } @@ -3032,10 +3032,10 @@ { <sym> } token infix:sym« ~< » ( --> Multiplicative) - { <sym> } + { <sym> <!before '<'> } token infix:sym« ~> » ( --> Multiplicative) - { <sym> } + { <sym> <!before '>'> } ## additive @@ -3112,13 +3112,13 @@ ## nonchaining binary token infix:sym« <=> » ( --> Nonchaining) - { <sym> <!!{ $<O><returns> = "Order"; }> } + { <sym> <?{ $<O><returns> = "Order"; }> } token infix:cmp ( --> Nonchaining) - { <sym> <!!{ $<O><returns> = "Order"; }> } + { <sym> <?{ $<O><returns> = "Order"; }> } token infix:leg ( --> Nonchaining) - { <sym> <!!{ $<O><returns> = "Order"; }> } + { <sym> <?{ $<O><returns> = "Order"; }> } token infix:but ( --> Nonchaining) { <sym> } @@ -3141,10 +3141,10 @@ ## chaining binary token infix:sym<==> ( --> Chaining) - { <sym> } + { <sym> <!before '=' > } token infix:sym<!=> ( --> Chaining) - { <sym> } + { <sym> <?before \s> } token infix:sym« < » ( --> Chaining) { <sym> } @@ -3161,8 +3161,9 @@ token infix:sym<~~> ( --> Chaining) { <sym> } +# XXX should move to inside meta ! token infix:sym<!~> ( --> Chaining) - { <sym> <.obs('!~ to do negated pattern matching', '!~~')> } + { <sym> \s <.obs('!~ to do negated pattern matching', '!~~')> } token infix:sym<=~> ( --> Chaining) { <sym> <.obs('=~ to do pattern matching', '~~')> } @@ -3233,7 +3234,7 @@ [ || <?before '='> <.panic: "Assignment not allowed within ??!!"> || <?before '::'> <.panic: "Please use !! rather than ::"> - || <?before <infix>> # Note: a tight infix would have parsed right + || <?before <infixish>> # Note: a tight infix would have parsed right <.panic: "Precedence too loose within ??!!; use ??()!! instead "> || <.panic: "Found ?? but no !!; possible precedence problem"> ] @@ -3316,10 +3317,6 @@ token infix:sym« p5=> » ( --> Comma) { <sym> } -## list infix -token infix:sym<X> ( --> List_infix) - { <sym> } - token infix:sym<Z> ( --> List_infix) { <sym> } @@ -3481,6 +3478,10 @@ token terminator:sym<!!> ( --> Terminator) { '!!' <?{ $+GOAL eq '!!' }> } +# disallow &[] and such as infix +# token infix:sigil ( --> Term ) +# { <sigil><-[&]> <.worry: "Sigiled form not allowed where infix expected"> <!> } + regex infixstopper { :dba('infix stopper') [