diff --git a/build/PARROT_REVISION b/build/PARROT_REVISION index 0eb18d95a80..8e43ce80bc1 100644 --- a/build/PARROT_REVISION +++ b/build/PARROT_REVISION @@ -1 +1 @@ -43953 +43956 diff --git a/docs/compiler_overview.pod b/docs/compiler_overview.pod index 3bf5872829d..da736550e37 100644 --- a/docs/compiler_overview.pod +++ b/docs/compiler_overview.pod @@ -8,8 +8,9 @@ This document describes the architecture and operation of the Rakudo Perl 6 (or simply Rakudo) compiler. The F describes how to build and run Rakudo. -Rakudo has six main parts (source code paths are relative to Rakudo's -F directory): +Rakudo has six main parts summarized below. Source code paths are +relative to Rakudo's F directory, and platform specific filename +extensions such as F<.exe> are sometimes omitted for brevity. =over 4 @@ -42,11 +43,15 @@ F, F, F) =back -The F (generated from F by F) -compiles all the parts to form the F executable and the -F or F "fake executable". We call it fake because it -has only a small stub of code to launch the Parrot executable and pass -itself as a chunk of bytecode for Parrot to execute. +The F (generated from F by +F<../Configure.pl>) compiles all the parts to form the F +executable and the F or F "fake executable". We call +it fake because it has only a small stub of code to launch the Parrot +executable, and passes itself as a chunk of bytecode for Parrot to +execute. The source code of the "fakecutable" is generated as +F with the stub at the very end. The entire contents of +F are represented as escaped octal characters in one huge +string called C. What a hack! =head2 1. NQP[-RX] @@ -55,17 +60,32 @@ Perl 6, the remainder in Parrot Intermediate Representation (PIR) or C. Not Quite Perl (nqp) provides the bootstrap step of compiling compiler code (yes!) written in a subset of Perl 6, into PIR. -The latest version is called B because it now also includes a -powerful Perl 6 regex engine. This has produced a streamlined compiler -framework on which to build a very functional Perl 6 implementation. +The latest version of NQP is called B because it now also +includes a powerful Perl 6 regex engine. This gives a streamlined +compiler framework on which to build a very functional Perl 6 +implementation. NQP itself is also written in PIR, is an important part of the Parrot Compiler Toolkit (PCT), and is installed with Parrot. PCT is a standard framework to make and use Parrot based languages. The source code of -NQP is in F<../parrot/ext/nqp-rx/> and the resulting (compiler-) -compiler is F<../parrot_install/bin/parrot-nqp>. Note, NQP only -I the Rakudo compiler, and does not compile or run user -programs. +NQP is in F<../parrot/ext/nqp-rx/> and the resulting compiler is +F<../parrot_install/bin/parrot-nqp>. Note, NQP only I the +Rakudo compiler, and does not compile or run user programs. + +=head3 Stages + +NQP[-RX] compiles us a very good compiler in F, referred +to as "stage-1", or C in the F. This version +would be limited in production though, because libraries of classes and +methods available at run time (for example Complex) have not yet been +added. + +The "stage-1" compiler (note: not NQP) compiles all Rakudo's Perl 6 code +again, this time including all the library modules (F), to +make F (note: not in F). That F file is +generated by F from a list called C +in F. Thanks to the staging process, a large and growing +proportion of Rakudo's source code is written in Perl 6. We can conceivably use the Rakudo compiler to compile itself to PIR and eliminate the need for NQP entirely. At some point as Rakudo matures we @@ -140,13 +160,79 @@ the user program. =head2 3. Actions -The C file defines what the compiler must output when -it matches certain tokens or rules. The output is a tree hierarchy of -objects representing language syntax elements, such as a statement. -The tree is called a Parrot Abstract Syntax Tree (PAST). +The F file defines the code that the compiler +generates when it matches each token or rule. The output is a tree +hierarchy of objects representing language syntax elements, such as a +statement. The tree is called a Parrot Abstract Syntax Tree (PAST). + +The C class inherits from C, another part +of the Parrot Compiler Toolkit. The source is in +F<../parrot/ext/nqp-rx/stage0/src/HLL-s0.pir>, look for several +instances of C<.namespace ["HLL";"Actions"]>. + +When the PCT calls the C<'parse'> method on a grammar, it passes not +only the program source code, but also a pointer to a parseactions class +such as our compiled C. Then, each time the parser +matches a named regex in the grammar, it automatically calls the same +named method in the actions class. + +For example, here's the parse rule for Rakudo's C statement +(in F): + + token statement_control:sym { + :s + + [ || + <.panic: 'unless does not take "else", please rewrite using "if"'> + ] + } + +This token says that an C statement consists of the word +"unless" (captured into C<< $ >>), and then an expression followed +by a block. If that all matches, the parser invokes the corresponding +action method for C<< statement_control:sym >>. + +Remember that for a match, not only must the C<< >> match the word +C, the C<< >> must also match the C token. If +you read more of F, you will learn that C in +turn tries to match an C<< >> and a C<< >>, which in +turn tries to match ..... + +This is why parsing source code this way is called Recursive Descent. + +Back to the C example, here's the action method for the +C statement (from F): + + method statement_control:sym($/) { + my $past := xblock_immediate( $.ast ); + $past.pasttype('unless'); + make $past; + } + +When the parser invokes this action method, the current match object +containing the parsed statement is passed into the method as C<$/>. +In Perl 6, this means that the expression C<< $ >> refers to +whatever the parser matched to the C token. Similarly there +are C<< $ >> and C<< $ >> objects etc until the end of the +recursive descent. By the way, C<< $ >> is Perl 6 syntactic +sugar for C< $/{'xblock'} >. + +The magic occurs in the C<< $.ast >> and C expressions in +the method body. The C<.ast> method retrieves the PAST made already for +the C subtree. Thus C<$past> becomes a node object describing +code to conditionally execute the block in the subtree. + +The C statement at the end of the method sets the newly created +C node as the PAST representation of the unless +statement that was just parsed. + +The Parrot Compiler Toolkit provides a wide variety of PAST node types +for representing the various components of a HLL program -- for more +details about the available node types, see PDD 26 +(L). The PAST representation is the final stage of processing in Rakudo -itself. The PAST datastructure is then passed on to Parrot directly. +itself. The PAST data structure is then passed on to Parrot directly. Parrot does the remainder of the work translating from PAST to pir and then to bytecode. @@ -158,85 +244,6 @@ far easier to write this component using PIR instead of a regular expression, but otherwise it acts just like any other rule in the grammar. -The action methods (in F) are used to convert the nodes -of the parse tree (produced by the parse grammar) into an equivalent Parrot -Abstract Syntax Tree (PAST) representation, which is then passed on to Parrot. - -The action methods are where the Rakudo compiler does the bulk of the work of -creating an executable program. Action methods are written in Perl 6, but we -use NQP to compile them into PIR as F. - -When Rakudo is compiling a Perl 6 program, action methods are invoked -by the C< {*} > symbols in the parse grammar. Each C< {*} > in a rule -causes the action method corresponding to the rule's name to be -invoked, passing the current match object as an argument. If the -rule source line containing C< {*} > also contains a comment -starting with C< #= >, any text after the comment is passed as a -separate key argument to the action method. (This is similar to -the approach that STD.pm uses to mark and distinguish actions.) - -For example, here's the parse rule for Rakudo's C statement -(in src/parser/grammar.pg): - - rule unless_statement { - $=[unless] - {*} - } - -This rule says that an unless statement consists of the word "unless" -(captured into C<< $ >>), followed by an expression and then a block. -If all of those match successfully, then the C< {*} > invokes the -corresponding action method for unless_statement. Here's the action -method for the unless statement (from src/parser/actions.pm): - - method unless_statement($/) { - my $then := $( $ ); - $then.blocktype('immediate'); - my $past := PAST::Op.new( $( $ ), $then, - :pasttype('unless'), - :node( $/ ) - ); - make $past; - } - -When this action method is invoked from the unless_statement rule, -the current match object containing the parsed statement is passed -into the method as C< $/ >. In Perl 6, this means that the -expressions C<< $ >> and C<< $ >> will refer to -whatever was matched by the C<< >> and C<< >> -subrules of the C rule. ( C<< $ >> -is Perl 6 syntactic sugar for C< $/{'block'} >.) - -Now then, the purpose of the action methods in our compiler is -to convert the parsed elements of the source program into their -abstract syntax tree (PAST) equivalents. The magic for this -occurs in the C< $(...) > and C expressions in the method -body. The C< $(...) > operator is used to retrieve the PAST -representation of a parsed subtree. Thus, the first two statements -of C retrieve the PAST representation of the -C<< >> subtree into C<$then>, and set that block to -be an immediately executed block. - -The third statement creates a new C node for the -unless statement, using the PAST representation of C<< >> -as the condition to be tested, the C<$then> block as the body, -and C<:pasttype('unless')> as the type of operation to be -performed. The C<:node($/)> argument is used to link this -PAST node back to the source code that generated it (e.g., for -error reporting). - -Finally, the C statement at the end of the method sets -the newly created PAST::Op node as the PAST representation of -the unless statement that was just parsed. - -The Parrot Compiler Toolkit provides a wide variety of PAST -node types for representing the various components of a HLL -program -- for more details about the available node types, -see PDD 26 (L). - - - - =head2 6. Builtin functions and runtime support The last component of the compiler are the various builtin @@ -245,11 +252,6 @@ have available when it is running. These include functions for the basic operations (C<< infix:<+> >>, C<< prefix: >>) as well as common global functions such as C and C. -Currently, most of the builtins are written in PIR, either because -it's simpler to write them that way or because they represent -very primitive operations (e.g., math primitives) or they're -easier to write in PIR than in Perl 6 or some other language. - =head2 Still to be documented * Rakudo PMCs @@ -259,7 +261,7 @@ easier to write in PIR than in Perl 6 or some other language. =head1 AUTHORS Patrick Michaud is the primary author and -maintainer. +maintainer of Rakudo. The other contributors and named in F. =head1 COPYRIGHT diff --git a/src/core/Any-list.pm b/src/core/Any-list.pm index 2b037f851fa..2aeb45118fd 100644 --- a/src/core/Any-list.pm +++ b/src/core/Any-list.pm @@ -150,6 +150,20 @@ augment class Any { } return @args[0]; } + + # This needs a way of taking a user-defined comparison + # specifier, but AFAIK nothing has been spec'd yet. + # CHEAT: Almost certainly should be hashed on something + # other than the stringification of the objects. + multi method uniq() { + my %seen; + gather for @.list { + unless %seen{$_} { + take $_; + %seen{$_} = 1; + } + } + } } our proto sub join (Str $separator = '', *@values) { @values.join($separator); } @@ -158,5 +172,8 @@ our multi sub reverse(*@v) { @v.reverse; } our proto sub end(@array) { @array.end; } our proto sub grep($test, @values) { @values.grep($test); } our proto sub first($test, @values) { @values.first($test); } +our proto sub min($by, *@values) { @values.min($by); } +our proto sub max($by, *@values) { @values.max($by); } +our proto sub uniq(@values) { @values.uniq; } # vim: ft=perl6 diff --git a/src/core/Any-num.pm b/src/core/Any-num.pm index 48ff0f0b778..1d6b0dfa3c5 100644 --- a/src/core/Any-num.pm +++ b/src/core/Any-num.pm @@ -1,6 +1,6 @@ augment class Any { multi method abs() { - self.Num.abs; + pir::abs__Nn(self.Num); } multi method exp() { diff --git a/src/core/Complex.pm b/src/core/Complex.pm index a9340cebcb6..9a99f13a490 100644 --- a/src/core/Complex.pm +++ b/src/core/Complex.pm @@ -320,9 +320,13 @@ multi sub prefix:<->(Complex $a) { Complex.new(-$a.re, -$a.im); } -#multi sub infix:<**>(Complex $a, $b) is default { -# ($a.log * $b).exp; -#} +multi sub infix:<**>(Complex $a, Complex $b) { + ($a.log * $b).exp; +} + +multi sub infix:<**>(Complex $a, $b) { + ($a.log * $b).exp; +} multi sub infix:<**>($a, Complex $b) { ($a.log * $b).exp; diff --git a/src/core/Str.pm b/src/core/Str.pm index fbb4393ecf2..1b8c2cb1cf4 100644 --- a/src/core/Str.pm +++ b/src/core/Str.pm @@ -4,4 +4,5 @@ augment class Str { # CHEAT: this implementation is a bit of a cheat, # but works fine for now. multi method Int { (+self).Int; } + multi method Num { (+self).Num; } } diff --git a/t/spectest.data b/t/spectest.data index c3b5f39f4ac..f935c3c5c00 100644 --- a/t/spectest.data +++ b/t/spectest.data @@ -443,7 +443,7 @@ S32-list/join.t # S32-list/reduce.t S32-list/reverse.t # S32-list/sort.t -# S32-list/uniq.t +S32-list/uniq.t S32-num/abs.t S32-num/complex.t S32-num/exp.t @@ -451,7 +451,7 @@ S32-num/int.t S32-num/log.t # S32-num/pi.t # S32-num/polar.t -# S32-num/power.t +S32-num/power.t # S32-num/rand.t S32-num/rat.t S32-num/roots.t @@ -471,7 +471,7 @@ S32-str/chop.t S32-str/flip.t S32-str/index.t S32-str/lcfirst.t -# S32-str/lc.t +S32-str/lc.t # S32-str/p5chomp.t # S32-str/p5chop.t S32-str/pos.t @@ -484,11 +484,11 @@ S32-str/split-simple2.t # CHEAT! simplified version of split-simple.t # S32-str/substr.t # S32-str/trim.t S32-str/ucfirst.t -# S32-str/uc.t # icu +S32-str/uc.t # icu # S32-str/unpack.t ## S32-str/words.t # icu # S32-temporal/Temporal.t -# S32-trig/e.t +S32-trig/e.t # S32-trig/pi.t # S32-trig/sin.t # S32-trig/cos.t