tag:blogger.com,1999:blog-27727533808750067132024-03-08T01:20:42.892-08:00ParrotNotes on implementation and design from the Parrot development teamChristoph Ottohttp://www.blogger.com/profile/05589658458274816699noreply@blogger.comBlogger40125tag:blogger.com,1999:blog-2772753380875006713.post-16164466098974084542012-01-10T21:19:00.001-08:002012-01-10T21:24:01.038-08:00Where have all the Parrot gone?We've stopped posting to this blog, but we're not done working on Parort. If you're looking for more Parrot blogging goodness, head over to <a href="http://parrot.org">parrot.org</a> or <a href="http://planet.parrot.org">planet.parrot.org</a>.Christoph Ottohttp://www.blogger.com/profile/05589658458274816699noreply@blogger.com0tag:blogger.com,1999:blog-2772753380875006713.post-83857956787524300972009-03-12T07:20:00.000-07:002009-03-12T07:22:46.233-07:00Less than a week to 1.0You should be following <a href="http://www.parrot.org/">parrot.org</a> for all your parroty goodness, but in case this blog is your main connection...<div><br /></div><div>...1.0 is due on Tuesday next week!</div>Cokehttp://www.blogger.com/profile/01745512237217656642noreply@blogger.com0tag:blogger.com,1999:blog-2772753380875006713.post-55008146239663651722009-02-17T16:36:00.000-08:002009-02-17T16:38:36.766-08:00Parrot 0.9.1 "Final Countdown" released!<div>o/~ We're leaving together,</div><div> but still its farewell o/~</div><div><br /></div><div>o/~ And maybe we'll come back,</div><div> To earth, who can tell? o/~</div><div><br /></div><div>o/~ I guess there is no one to blame</div><div> We're leaving ground</div><div> Will things ever be the same again? o/~</div><div><br /></div><div>o/~ It's the Final Countdown...</div><div> The Final Countdown o/~</div><div><br /></div><div>--Europe, "The Final Countdown"</div><div><br /></div><div><br /></div><div>On behalf of the Parrot team, I'm proud to announce Parrot 0.9.1</div><div>"Final Countdown." Parrot (http://parrot.org/) is a virtual machine aimed</div><div>at running all dynamic languages.</div><div><br /></div><div>Parrot 0.9.1 is available via CPAN (soon), or follow the download</div><div>instructions at http://parrotcode.org/source.html. For those who would like to develop on</div><div>Parrot, or help develop Parrot itself, we recommend using Subversion on</div><div>the source code repository to get the latest and best Parrot code.</div><div><br /></div><div>Parrot 0.9.1 News:</div><div>- Implementation</div><div> + Support for portable 'Inf', 'NaN' and -0.0</div><div> + pbc_disassemble prints constants in constants table</div><div> + New experimental BigNum implementation</div><div> + Pair is now a dynamic loadable PMC</div><div> + Various function name sanification</div><div> + New implementation of Strings component</div><div> + Replace various PMC value union access code by VTABLE method invocations</div><div> + Replace various PMC value unions by ATTRibutes</div><div> + Removed SArray PMC. Use FixedPMCArray instead.</div><div>- Documentation</div><div> + Book</div><div> - updates to Chapter 2 (getting started)</div><div> - updates to Chapter 3 (PIR basics)</div><div> - updates to Chapter 4 (PIR subroutines)</div><div> - updates to Chapter 10 (HLLs)</div><div> - updates to Chapter 12 (opcodes)</div><div> + Function documentation</div><div> + Pod documentation style modernized; no longer Perl 5 style.</div><div> + PMC has an additional acronym: Poly Morphic Container</div><div> + The DOD (Dead Object Detection) acronym is no longer used;</div><div> use 'GC' to refer to the Garbage Collector component.</div><div>- Compilers</div><div> + IMCC</div><div> - :named flag can now take string registers as argument</div><div> - A single '=cut' directive is now ignored (without initial Pod directive)</div><div> - :vtable subs now have proper access to 'self' pseudo variable</div><div>- Languages</div><div> + add new 'Pod' documentation parser</div><div> + Pipp (PHP implementation):</div><div> - Pipp is now at http://github.com/bschmalhofer/pipp</div><div> - support for 'print', 'dirname', 'implode', 'str_replace',</div><div> - various grammar fixes</div><div> + ECMAScript</div><div> + add 'quit', 'readline' builtins</div><div> + fix 'Boolean' type and 'print' builtin</div><div> + Lua</div><div> - left the nest and is now at http://github.com/fperrad/lua/</div><div> + Rakudo</div><div> - left the nest and is now at http://github.com/rakudo/rakudo/</div><div> - build instructions can be found at http://tinyurl.com/rakudo</div><div> + lazy-k</div><div> - left the nest and is now at http://github.com/bschmalhofer/lazy-k.git</div><div> + unlambda</div><div> - left the nest and is now at http://github.com/bschmalhofer/unlambda/</div><div> + WMLScript</div><div> - left the nest and is now at http://github.com/fperrad/wmlscript.git</div><div> + removed Zcode implementation</div><div>- Tools</div><div> + pmc2C</div><div> - ATTRs are now inherited automatically in subclassing PMCs</div><div>- Deprecations</div><div> + Parrot_readbc, Parrot_loadbc renamed to Parrot_pbc_read, Parrot_pbc_load.</div><div> + .HLL_map directive in favour of 'hll_map' method on Parrot interpreter</div><div> + Data::Escape library</div><div>- Tools</div><div> + pbc_disassemble options added</div><div> + pbc_dump renamed from pdump</div><div>- Miscellaneous</div><div> + Parrot is now Copyright Parrot Foundation</div><div> + Parrot's SVN repository is now hosted at https://svn.parrot.org</div><div> + Various code cleanups, consting, 64-bit incompatibilities and other bug fixes</div><div><br /></div><div><br /></div><div>Many thanks to all our contributors for making this possible, and our sponsors</div><div>for supporting this project. Our next scheduled release is 17 March 2009.</div><div><br /></div><div>Enjoy!</div><div><br /></div><div><br /></div>Anonymousnoreply@blogger.com0tag:blogger.com,1999:blog-2772753380875006713.post-39472801365809422522009-02-10T06:06:00.000-08:002009-02-10T06:45:40.216-08:00Readers Needed!One of our key requirements for the release next Tuesday is <a href="https://trac.parrot.org/parrot/ticket/237">improved documentation</a>. Documentation is key, because it's the doorway through which new users will enter the world of Parrot. I've been doing a lot of work on documentation recently, along with several of the other developers. The problem is that from inside the project we can't always see where the holes are, and what the confusing bits are going to be. So, I'm asking for a little help from people who aren't current Parrot users or developers:<br /><br /><div style="text-align: center;"><span style="font-weight: bold;">We need you!</span><br /></div><br />We need people to read over the documentation and find the problem spots. What parts are confusing? What material isn't well covered, or isn't covered at all? What do you wish we talked about more? What information do you need in order to get started working with Parrot?<br /><br />You can check out the source repository using SVN from <a href="https://svn.parrot.org/parrot/trunk/">https://svn.parrot.org/parrot/trunk/</a>, you can find our documentation in the <a href="https://svn.parrot.org/parrot/trunk/docs/">docs/</a> directory. Many of the files here, although not all of them, are used to populate our <a href="http://www.parrotcode.org/docs/">online documentation</a> too (the online documentation has it's own problems too). We have a comprehensive book in development in the directory <a href="https://svn.parrot.org/parrot/trunk/docs/book/">docs/book/</a>, which contains a lot of material arranged in a linear narrative. All these things need some help.<br /><br />We need suggestions, comments, even questions. Because answering your questions will help us to identify the information that is missing from our docs. We need patches, if you're able and want to contribute. Leave comments here on this blog with ideas, open a <a href="https://trac.parrot.org/parrot/newticket">ticket at trac</a>, or post a <a href="mailto:parrot-dev@lists.parrot.org">message to our mailinglist</a>. It doesn't matter how you send us your reviews and your fixes, so long as you send a lot of them! <span style="font-weight: bold;">We need help</span> from readers and reviewers, especially people who aren't current Parrot users or developers, people who don't already have the answers. <span style="font-weight: bold;">We need your help</span>.Whiteknighthttp://www.blogger.com/profile/16207472474429254890noreply@blogger.com2tag:blogger.com,1999:blog-2772753380875006713.post-6949997809693846722009-01-14T12:03:00.001-08:002009-01-14T12:08:56.808-08:00svn repository moveHeads up! In the short term, parrot's svn repository will be relocating from perl.org to parrot.org.<div><br /></div><div>When this happens, there will be a small amount of downtime, and after that you'll be able to keep working with a simple 'svn switch' in your checkout.</div><div><br /></div><div>We were going to try to squeeze this in today, but that's been postponed. More details on the schedule as they become available.</div>Cokehttp://www.blogger.com/profile/01745512237217656642noreply@blogger.com0tag:blogger.com,1999:blog-2772753380875006713.post-59652349825817584452008-12-17T05:04:00.000-08:002008-12-17T05:05:06.637-08:00Parrot 0.8.2 "Feliz Loro" Released!<p>On behalf of the Parrot team, I'm proud to announce Parrot 0.8.2<br />"Feliz Loro." <a href="http://parrotcode.org/">Parrot</a><br />is a virtual machine aimed at running all dynamic languages.</p><br /><br /><p>Parrot 0.8.2 is available via <a href="http://search.cpan.org/dist/parrot">CPAN</a><br />(soon), or <a href="http://parrotcode.org/source.html">follow the download<br />instructions</a>. For those who would like to develop on Parrot, or help<br />develop Parrot itself, we recommend using <a<br />href="http://subversion.tigris.org/">Subversion</a> on<br /><a href="https://svn.perl.org/parrot/trunk/">our source code repository</a> to get the latest<br />and best Parrot code.</p><br /><br /><p>Parrot 0.8.2 News:<br/><br /><pre>- Implementation<br /> + fixed lexical semantics<br /> + added the 'capture_lex' opcode<br /> + added automatic resume for nonfatal exceptions<br /> + added multidispatch cache<br /> + applied miscellaneous performance improvements, including startup time<br /> + fixed several bugs and leaks found by Coverity Scan<br /> + removed race conditions from parallel testing<br />- Compilers<br /> + IMCC<br /> - removed undocumented .param int <stringc> => <ident> syntax<br /> - .line directive now only takes an integer argument<br /> - new .file directive to specify the file name being compiled<br /> + PCT<br /> - properly handles lexical generation and closure semantics<br /> - uses :subid instead of name lookups to reference PAST::Block nodes<br /> - added PAST::Control node type (exception handlers)<br /> + PGE<br /> - add support for <?{{...}}> and <!{{...}}> assertions<br /> - Match objects use Capture PMC instead of Capture_PIR<br /> + PIRC<br /> - add macro handling to PASM mode<br /> - disable vanilla register allocation in PASM mode, but do allow optimization<br /> - add tests and bug fixes<br /> - first bits of bytecode generation. No sub calling/returning yet.<br />- Languages<br /> + Rakudo<br /> - fixed lexical handling and recursion<br /> - refactored subtypes implementation<br /> - support for quotes with multi-character delimiters<br /> - implemented list slices (Positional role)<br /> - list assignment<br /> - reduction meta operators<br /> - hyper meta operators<br /> - cross meta operators<br /> - more builtin functions<br /> - added Nil type<br /> - basic support for protos<br /> - iterator on filehandle objects<br /> - basic support for exception handlers<br /> - warn<br /> + Lua<br /> - added complex & mathx libraries<br /> - merged LuaClosure & LuaFunction PMC<br /> + Pipp<br /> - added support for a return value from user defined functions<br /> - added incomplete implemention of 'require_once'<br /> + Ecmascript<br /> - parser fixes, parses spidermonkey's top level test/shell.js<br />- Deprecations<br /> + PARROT_API is now PARROT_EXPORT<br /> + PIR<br /> - :lexid is now :subid<br /> - .arg is now .set_arg<br /> - .result is now .get_result<br /> - .yield (in .begin/end_yield) is now .set_yield<br /> - .return (in .begin/end_return) is now .set_return<br /> - .namespace x / .endnamespace x syntax is removed<br /> + Capture_PIR (runtime/parrot/library/Parrot/Capture_PIR.pir)<br /></pre></p><br /><br /><p>Thanks to all our contributors for making this possible, and our sponsors<br />for supporting this project. Our next release is 20 January 2009.</p><br /><br /><p>Enjoy!</p>Whiteknighthttp://www.blogger.com/profile/16207472474429254890noreply@blogger.com4tag:blogger.com,1999:blog-2772753380875006713.post-9782363670235153272008-12-09T22:28:00.000-08:002008-12-09T22:49:05.135-08:00Parrot development speedYesterday there was some converation on #parrot about our development momentum; since I had the numbers easily available I put together a small chart:<br /><br /><a href='http://www.pmichaud.com/perl6/commits-by-month.gif'><img src='http://www.pmichaud.com/perl6/commits-by-month.gif' width='550'></a><br /><br />This shows the number of commits to the Parrot repository within any given month; the regression line shows the (linear) rate of increase over the past two years.<br /><br />So, not only are we making progress on Parrot, but measured by commits the rate of progress is increasing as well.Pmhttp://www.blogger.com/profile/05117950909580615426noreply@blogger.com0tag:blogger.com,1999:blog-2772753380875006713.post-8361619025179902342008-11-29T14:43:00.000-08:002008-11-29T15:08:59.326-08:00Memory Management in PIRC<span class="Apple-style-span" style="font-size: x-large;">Introduction</span><div>PIRC is a new implementation of the PIR language, and currently under heavy construction. While the code is documented, it does not provide an easy overview of implementation issues and design decisions. In order to solve this documentation gap, I'm writing these design decisions in a series of parrotblog.org articles. This very short article discusses the memory management of PIRC. </div><div><br /></div><div>The current PIR compiler, IMCC, has had a lot of memory leaks, most of which have been solved by now. Although conceptually manual memory management through malloc() and free() is very simple and straightforward, things become ugly once you loose overview of when datastructures go out of scope, and as a result you forget to free the memory. In PIRC a different approach is taken.</div><div>Note that instead of using malloc() and free() directly, you should use mem_sys_allocate() and mem_sys_free(), respectively, which are provided by Parrot.</div><div><br /></div><div><span class="Apple-style-span" style="font-size: x-large;">Cheater!</span></div><div>PIRC parses the PASM or PIR input, builds a data structure, and generates a Parrot Byte Code file (a so-called Packfile). (at the moment of writing, the PBC is not generated yet, but work is underway to fix this; might take a while, though). The data structures that are created represent the PASM or PIR program being parsed, and as such can be considered an Abstract Syntax Tree.</div><div>As these data structures are used throughout the compilation phase, PIRC can cheat with memory management. Instead of freeing the memory of the data structures by manually calling mem_sys_free(), PIRC keeps track of all allocated memory blocks. Only when PIRC is done with the bytecode generation will it release all resources. This is fine, because the data structures are needed up to the end anyway, so memory is not occupied longer than necessary.</div><div><br /></div><div><span class="Apple-style-span" style="font-size: x-large;">Poor Man's Garbage Collector</span></div><div>Whenever PIRC needs memory, a block of memory is allocated through Parrot's memory allocation function, mem_sys_allocate() (or a variant, which zeroes out all bytes). Before returning a pointer to the allocated block of memory, however, PIRC stores a pointer to the block of memory as well (in a list), and only then is the pointer to the block returned.</div><div>When PIRC is done with compiling, it will go through the list of memory pointers, and release the memory pointed to by each of the pointers. In a sense, you could consider this a garbage collector, except that there's no reuse of memory (but there's no need to anyway).</div><div><br /></div><div>"Wait a minute," you might say, where are these pointers stored then? Well, of course, these pointers are stored in an extensible list, as we don't know the number of pointers to store beforehand. Surely the list cannot be allocated and store a pointer to itself. This is fine, because the problem of keeping track of memory is now isolated to a single point in the program. The nodes in the list of allocated memory pointers are allocated directly through Parrot's memory functions. When all stored pointers are mem_sys_free()d, we only have to remember to mem_sys_free() these nodes. <br /></div><div><br /></div><div>In this way, there's no need to worry about when pointers should be freed: it's done automatically, as long as PIRC allocates its memory through its built-in memory management system.</div><div><br /></div><div><span class="Apple-style-span" style="font-size: x-large;">List of Pointers</span></div><div>Obviously, we don't want to create a new node for each pointer to store. Instead, a node can store a number of pointers, currently set to 512. So, after allocating memory for 512 times, a new node is created. This number of 512 was decided upon after some experimentation, but might prove too low for real world PIR input. As it's #define'd, it's easy to change, though.</div><div><br /></div><div><span class="Apple-style-span" style="font-size: x-large;">Summary</span></div><div>In this very short article, I described how PIRC does its memory management. PIRC cheats a bit, by storing each pointer to an allocated block of memory in a special list. Once PIRC is done with compiling, all these pointers are passed to mem_sys_free(), Parrot's free() function (one by one, obviously). This way, you don't have to worry about when to free the memory in PIRC.</div>Anonymousnoreply@blogger.com3tag:blogger.com,1999:blog-2772753380875006713.post-45990575431715442962008-11-27T03:47:00.000-08:002008-11-27T06:17:22.557-08:00Parsing heredocs with PIRC<span class="Apple-style-span" style="font-size: x-large;">Introduction</span><div>The PIR language allows you to write so-called heredocs, as known from Perl (and I believe the idea was stolen from some older languages). If you're not a Perl programmer (like me), you might wonder what the heck I'm talking about. So, let's start with a simple example (using PIR syntax):</div><div></div><blockquote><div><span class="Apple-style-span" style="font-family:'courier new';">$S0 = <<'CODE'</span></div><div><span class="Apple-style-span" style="font-family:'courier new';">This is a heredoc string</span></div><div><span class="Apple-style-span" style="font-family:'courier new';">over</span></div><div><span class="Apple-style-span" style="font-family:'courier new';">multiple </span></div><div><span class="Apple-style-span" style="font-family:'courier new';">lines</span></div><div><span class="Apple-style-span" style="font-family:'courier new';">CODE</span></div></blockquote><div>So, using the special <<"CODE" is stored in register <span class="Apple-style-span" style="font-family:'courier new';">$S0</span>. So, the string stored in <span class="Apple-style-span" style="font-family:'courier new';">$S0</span> is:</div><div><blockquote>"<span class="Apple-style-span" style="font-family:'courier new';">\nThis is a heredoc string\nover\nmultiple\nlines\n</span>"</blockquote>Want to see for yourself? </div><div></div><blockquote><div><span class="Apple-style-span" style="font-family:'courier new';">cd compilers/pirc</span></div><div><span class="Apple-style-span" style="font-family:'courier new';">make</span></div><div><span class="Apple-style-span" style="font-family:'courier new';">export LD_LIBRARY_PATH=../../blib/lib</span></div><div><span class="Apple-style-span" style="font-family:'courier new';">./pirc <file></span></div></blockquote><div>Not too difficult, eh? Well... you're right, until you use multiple heredocs in, for instance, subroutine arguments. Many Parrot tests use Perl scripts to specify the input (code) and the expected output. That's done like this:</div><div></div><blockquote><div><span class="Apple-style-span" style="font-family:'courier new';">pir_output_is(<<'CODE', <<'OUTPUT');</span></div><div><span class="Apple-style-span" style="font-family:'courier new';">.sub main</span></div><div><span class="Apple-style-span" style="font-family:'courier new';"> say 42</span></div><div><span class="Apple-style-span" style="font-family:'courier new';">.end</span></div><div><span class="Apple-style-span" style="font-family:'courier new';">CODE</span></div><div><span class="Apple-style-span" style="font-family:'courier new';">42</span></div><div><span class="Apple-style-span" style="font-family:'courier new';">OUTPUT</span></div></blockquote><div>PIR also allows multiple ("nested" if you want, but they're not symmetrically nested; a better word would be "overlapping") heredocs. The current PIR compiler (IMCC) cannot handle this, but the new PIR compiler (currently still under development) PIRC, can. In an attempt to maximize the "<a href="http://c2.com/cgi/wiki?TruckNumberComposite">truck number</a>" of PIRC (which is currently estimated to be 1), I'm trying to do as much documentation of PIRC as possible. In this article, I'll be discussing how heredoc parsing is done in PIRC.</div><div><br /></div><div><span class="Apple-style-span" style="font-size: x-large;">Single heredoc parsing</span></div><div>Let's start out simple with a single heredoc string. The heredoc preprocessor is implemented in the file compilers/pirc/new/hdocprep.l. Yes, that's right, that's not a C file, but a Lex specification file. Using Lex (and it's probably Flex that you'll be running, a faster implementation of Lex), the .l file is converted into a C file.</div><div><br /></div><div>Now, for this discussion I'll assume that you know a bit about using Flex. A particular (advanced) feature of Flex-generated scanners (or "lexer" if you want) is the use of states. Using states you can implement several scanners in a single specification. Based on the state that the lexer is in, it'll recognize a subset of the rules. If no rule is specified, then the built-in, default INITIAL state is assumed. States can be pushed and popped of a stack, also managed by the generated C file. Whenever a new state is pushed onto the stack, that becomes the active state, and all rules that are specific to that state will become active. Once the state is popped of the stack, the rules fall out of scope again, and the state at the top of the stack (after popping) will become active.</div><div><br /></div><div>So, the trick that's used is, as soon as the heredoc marker is read (e.g. <<'CODE'), we enter a new state, which will read the input line by line. All rules of the previous state are no longer active, so strings such as "<<'OUTPUT'" won't be matched, but instead are stored in a string buffer. After reading each line, it will check whether the heredoc end marker was read. As soon as the end marker is read, the heredoc scanning state will be popped, and scanning will continue in the initial state.</div><div><br /></div><div><span class="Apple-style-span" style="font-size:x-large;">Single heredoc strings as subroutine arguments</span></div><div>Consider the following PIR line:</div><div><blockquote><span class="Apple-style-span" style="font-family:'courier new';">foo(<<'CODE', 42, 'hi')</span></blockquote></div><div>After reading <<<span class="Apple-style-span" style="font-family:'courier new';">'CODE'</span>, the scanner will continue scanning in the heredoc state. However, the rest of the line, containing "<span class="Apple-style-span" style="font-family:'courier new';">, 42, 'hi')</span>" should be stored somewhere, as this is not part of the heredoc. So, the "rest of the line" is scanned, stored in a buffer, and then the heredoc scanning can start. After reading the end marker of heredoc, the scanned heredoc is printed to the output, after which the "rest of the line" can be scanned. Not so hard, eh?</div><div><br /></div><div><span class="Apple-style-span" style="font-size: x-large;">Scanning multiple heredocs</span></div><div>Things get more interesting when you need to scan input like the following:</div><div></div><blockquote><div><span class="Apple-style-span" style="font-family:'courier new';">foo(<<'CODE', 42, <<'OUTPUT', 'hi')</span></div><div><span class="Apple-style-span" style="font-family:'courier new';">.sub main</span></div><div><span class="Apple-style-span" style="font-family:'courier new';"> say 42</span></div><div><span class="Apple-style-span" style="font-family:'courier new';">.end</span></div><div><span class="Apple-style-span" style="font-family:'courier new';">CODE</span></div><div><span class="Apple-style-span" style="font-family:'courier new';">42</span></div><div><span class="Apple-style-span" style="font-family:'courier new';">OUTPUT</span></div></blockquote><div>Scanning the first heredoc string works fine; the "rest of the line" is then:<span class="Apple-style-span" style="font-family:'courier new';"><blockquote>", 42, <<'OUTPUT', 'hi')"</blockquote></span>After scanning the first heredoc, we tell the lexer to start retrieving the next characters from the "rest of the line" buffer. When scanning this line buffer, we'll encounter the <<'OUTPUT' marker, which indicates another heredoc string. At this point, we need to re-save the "rest of the line", which will contain: <span class="Apple-style-span" style="font-family:'courier new';"><blockquote>, 'hi')</blockquote></span>At this point, we need to continue scanning from the input file, after the point we left off after scanning the first heredoc. So, off we go, again switching input buffers in the lexer, so that the contents of the second heredoc string are scanned. Again, scanning line by line, checking for the heredoc end marker. Again, once we find the end marker, we'll switch back to the "rest of line" buffer, and finish scanning that string. Once we read EOF on the line buffer, again we switch back to the input file, and the rest of the file is scanned as if nothing happened.</div><div><br /></div><div><span class="Apple-style-span" style="font-size: x-large;">Heredoc preprocessing</span></div><div>The heredoc handling is implemented as a separate pass over the input file. This was done to keep the complexity of the lexer manageable. Although this does result in more I/O operations, having better readable code is, IMHO anyway, a more important goal than presumably faster code, that is hard to maintain. Currently, the output of the heredoc preprocessor is written to a temporary file, of which the PIR lexer is reading.</div><div><br /></div><div><span class="Apple-style-span" style="font-size: x-large;">Including files</span></div><div>The PIR language has a C-preprocessor-like #include directive, spelled as "<span class="Apple-style-span" style="font-family:'courier new';">.include</span>". Logically, it's part of the macro layer, as the include directive is replaced by the contents of the specified file. However, as an included file may contain heredoc strings as well, the whole invocation scheme of the PIR compiler becomes more complex, as that included file must be handled by the heredoc preprocessor as well. </div><div><br /></div><div>So, PIRC cheats a bit. Instead of implementing the .include directive in the macro layer, it is moved "forward" to the heredoc preprocessor. This way, the heredoc preprocessor converts all heredoc strings into normal strings (a process I like to call "flattening the string", as the multi-line string is now flat, meaning it's a one-line string), and stores the contents of all included files into the temporary file. PIRC's normal lexer only ever sees one single input file, and does not need to handle the <span class="Apple-style-span" style="font-family:'courier new';">.include</span> directive.</div><div><br /></div><div><span class="Apple-style-span" style="font-size: x-large;">Summary</span></div><div>This article discusses the implementation of the heredoc preprocessor. PIRC allows you to use multiple heredoc strings in a single PIR statement, which introduces some complexity to the lexer. For that reason, heredocs are processed in a separate pass over the input. Besides handling heredocs, the <span class="Apple-style-span" style="font-family:'courier new';">.include</span> directive is handled in the heredoc preprocessor as well, to make life a bit easier for myself.</div><div><br /></div>Anonymousnoreply@blogger.com0tag:blogger.com,1999:blog-2772753380875006713.post-84771887181860346952008-10-31T03:10:00.000-07:002008-11-01T09:17:42.620-07:00Register allocation in a PIR compiler<div><span class="Apple-style-span" style="font-size:180%;">Introduction</span></div>As some of you may know, I have been working on a new implementation of a PIR compiler, which is named PIRC. In the end, my plan is to emit actual Parrot Byte Code (PBC), which can then be run by Parrot. Once everything's working and tested properly, I will make a case for replacing the current PIR compiler (IMCC). It might take a while before I get to that, though.<div><br /></div><div>In the mean time, I'm trying to make PIRC as feature-complete as possible, and will try to write up some of the implementation issues that have to be dealt with. This can be interesting for lurkers, who 'have always wanted to know how to do it', but also just as a way to document things.</div><div><br /></div><div>In this article, I will discuss the implementation of a recently added feature: a register allocator. Now, the implementation I came up with still needs a lot of testing, but the idea behind it does not change. The algorithm I chose is Linear Scan Register (LSR) Allocation, which is described in detail <a href="http://www.google.ie/url?sa=t&source=web&ct=res&cd=2&url=http%3A%2F%2Fportal.acm.org%2Fcitation.cfm%3Fid%3D330250&ei=YX4MSYjQF4b00AXG0rHzAQ&usg=AFQjCNHz7LtFkRqtkfyQ4vTw1GchiSCo2A&sig2=HB41Y-mk5tV6CBjSZhos_g">here</a>. This algorithm is very different from the more well-known (classic, if you like) register coloring algorithm, which is based on graph coloring theory. I won't go into details too much, except mentioning that while a register coloring algorithm can yield more efficient register usage, but is a lot more expensive in terms of processor cycles, compared to the LSR algorithm. Obviously, for dynamic languages, where runtime compilation is a common feature, this is an important feature.</div><div><br /></div><div><span class="Apple-style-span" style="font-size:180%;">Register allocation</span></div><div>First, a short review of register allocation. I will make some rough simplifications just for the sake of this discussion, so I probably will make some false statements here. In real CPUs, there's a limited number of registers. This is fine, as long as the number of registers is larger than the number of variables that are alive. However, once you have more variables than registers, you need to overwrite a previously used register. If the value in the register being reused for another variable is going to be used after this overwriting, then you need to make sure the value is stored somewhere temporarily, typically in memory. This is called <span class="Apple-style-span" style="font-style: italic;">register spilling</span>. Then, later, when the variable that was 'spilled' is referenced again, it needs to be reloaded into a register, overwriting that register's current value, which again needs to be spilled. </div><div><br /></div><div>In short, you typically have to map N variables onto M registers, and if N > M, you need to spill registers. </div><div><br /></div><div>In the Parrot virtual machine, this is not necessary. Parrot allows a subroutine to have as many registers as possible (up to the physical limitations of your memory, obviously). If a subroutine needs 50 registers, then it will happily allocate those. After all, Parrot can be considered a CPU in software, which uses memory for anything where a hardware CPU uses... eh... well, hardware. (Of course, memory chips are hardware... oh well, you get my point).</div><div><br /></div><div>In any case, this is good news for any register allocator in the PIR compiler, as it makes the job of register allocation extremely simple. PIRC has a 'vanilla' register allocator, which allocates registers using a counter, starting at 0, and increment the counter whenever it needs a new register. </div><div><br /></div><div>However, it's still a bit of a waste. If you look at typical PIR output of Rakudo, the Perl 6 implementation running on Parrot, then you'll see it's a lot of code. A Lot. It would be good if registers can actually be reused, if the variable that it represents is never referenced again. After all, as you now know, Parrot allocates as many registers as it needs for any given subroutine, and obviously, less is better, as it saves memory.</div><div><br /></div><div>(Ok, I admit it, I really just did it because it was a nice challenge to implement).</div><div><br /></div><div>Now you know why register optimization is useful, let's discuss some basics of the algorithm that was implemented.<br /></div><div><br /></div><div><span class="Apple-style-span" style="font-size:180%;">Linear Scan Register Allocation</span></div><div>The Linear Scan Register Allocation (LSR) algorithm is really quite simple. The basic idea is that, each variable has a certain life time. In a programming language, a variable typically has a scope, which is the maximum life span of a variable (because it will go out of scope after the scope has closed. Are you still with me?) . However, the fact that a variable has a scope doesn't mean it's being used throughout the whole scope; it's very possible, and likely, that a variable is only used in one or two statements in the scope. So, suppose there are two variables, say, <span style="font-family: courier new;">foo </span>and <span style="font-family: courier new;">bar</span>, which have mutual exclusive life spans, (this means they never live in the same 'era'). This means they can both be mapped to the same register. This is the fundamental idea behind the SLR allocator.</div><div><br /></div><div><span style="font-size:180%;">Data structures</span><br />First, I need to explain some basic data structures that are used in PIRC. I won't do this in too much detail; that would be a good topic for some other time.<br />PIRC has basically two important parts: the parser, and the back-end. The parser is implemented using a Bison (I think it uses some features that are not Yacc-compatible) specification. The back-end is a bunch of data structures that are manipulated during the parse.<br />In the context of register allocation, the most important data structures are the structs <span style="font-family: courier new;">target</span>, <span style="font-family: courier new;">symbol </span>and <span style="font-family: courier new;">pir_reg</span>. A symbol is a declared .local identifier; a pir_reg represents a PIR symbolic register (like $I42). A target represents a so-called l-value object; this is an object that can be assigned to. Basically, symbols and pir_reg objects have a one-to-one mapping w.r.t. the symbol or symbolic register they represent, while targets have a many-to-one relation w.r.t. the underlying symbol or pir_reg. So, suppose you declare a .local int foo, then there will be a single symbol object representing foo, but there may be many target nodes pointing to this symbol.<br />As symbols and pir_regs are only created once for the target they represent, the vanilla register allocator (which is a very basic, dumb allocator) will assign a new register to each new symbol/pir_reg object. Whenever a target is being parsed (and it's easy to recognize whether it's a identifier or a symbolic register), the symbol or pir_reg object for that target is looked up, and linked to the target node.<br />This link is very important, because it is used to tell the symbol (from now on, wherever you read symbol, you can interpret it as 'symbol or pir_reg') that it is used in the current instruction. During the parse, the compiler keeps track of an instruction counter, which just assigns numbers in a consecutive way to the instructions. So, basically whenever a target is parsed, it updates the life span of the symbol. The first usage of an identifier indicates the first usage of that symbol (and not its declaration: you may declare a symbol, but never use it).<br />What this means is, that after the parse, for each symbol (.local identifier and symbolic register), we have a life interval object, which knows when is the first usage of the symbol, and when is the last.<br /></div><div><br /></div><div><span style="font-size:180%;">Implementation</span><br />Once you know when the variables are used, it becomes extremely simple to optimize the register usage. Basically, you iterate through each life interval object, you assign the symbol it represents a new register (a real parrot register like P2, not a symbolic register, like $P2), and you place the live interval object into a list of "active" variables. Each iteration, you walk through this list, and "expire" any live intervals that represent symbols that are no longer used. For this, the interval objects that you're iterating over must be sorted. Whenever a live interval has expired, the register it was assigned becomes available, so you can put that register on a "free" list; the next time you need a new register, you first check whether there's any "old", previously used registers are available. If not, you just increment a counter, increasing the total number of registers that Parrot must allocate.<br /><br />This all might sound very complex, but, really, it's not. The implementation is only about 200 lines of code or so (that's a wild guess), and can be found in compilers/pirc/new/pirregalloc.c.<br /><br />Of course, the thing needs to be properly tested, but the basic idea stays the same. There's still quite some work to be done in PIRC anyway.<br /><br /><span style="font-size:180%;">Conclusion</span><br />In this article I tried to explain the implementation of a register allocator, which optimizes the register usage of code generated by PIRC, a new PIR compiler. The basic data structures were briefly explained, and the algorithm was summarized. Experience should show whether the investment was worth it, or that more heavy-weight implementations, such as graph-coloring-based algorithm should be used.<br /></div>Anonymousnoreply@blogger.com2tag:blogger.com,1999:blog-2772753380875006713.post-59178523659492616322008-10-03T01:55:00.000-07:002008-10-03T02:33:10.962-07:00Tracking down an IMCC bugSo I was adding support for handling next/redo/last exceptions to PCT's loops the other day, and I hit a weird bug. Here's the <a href="http://pleasedieinafire.net/~tene/next-broken.patch">patch</a>.<br /><br />The problem is approximately this:<br /><pre><br />$I0 = defined, stuff_to_loop_over<br />unless $I0, for_loop_end<br />push_eh for_loop_next<br />...<br />for_loop_end:<br />pop_eh<br /></pre><br />I'm adding the error handler there after a conditional jump, but popping the error handler off after the target of that jump, but I didn't notice this at the time. That's going to at least cause bugs at runtime, but this also caused the PIR compiler to hang. I beat my head against it for a while, posted a bug about it, and went to sleep.<br /><br />The next day, I used valgrind's callgrind tool to find where it was spending it's time. The output is:<br /><pre><br />--------------------------------------------------------------------------------<br /> Ir file:function<br />--------------------------------------------------------------------------------<br />13,455,028,108 /home/sweeks/src/parrot/compilers/imcc/sets.c:set_add [/home/sweeks/src/parrot/blib/lib/libparrot.so.0.7.1]<br />11,209,537,812 /home/sweeks/src/parrot/compilers/imcc/cfg.c:compute_dominance_frontiers [/home/sweeks/src/parrot/blib/lib/libparrot.so.0.7.1]<br /> 135,234,114 /home/sweeks/src/parrot/compilers/imcc/imclexer.c:yylex [/home/sweeks/src/parrot/blib/lib/libparrot.so.0.7.1]<br /> 128,962,606 /home/sweeks/src/parrot/compilers/imcc/sets.c:set_contains [/home/sweeks/src/parrot/blib/lib/libparrot.so.0.7.1]<br /> 88,825,729 /home/sweeks/src/parrot/compilers/imcc/imcparser.c:yyparse [/home/sweeks/src/parrot/blib/lib/libparrot.so.0.7.1]<br /> 70,349,560 /home/sweeks/src/parrot/compilers/imcc/instructions.c:instruction_reads [/home/sweeks/src/parrot/blib/lib/libparrot.so.0.7.1]<br /> 65,814,257 /home/sweeks/src/parrot/compilers/imcc/cfg.c:compute_dominators [/home/sweeks/src/parrot/blib/lib/libparrot.so.0.7.1]<br /> 56,483,518 /home/sweeks/src/parrot/compilers/imcc/instructions.c:instruction_writes [/home/sweeks/src/parrot/blib/lib/libparrot.so.0.7.1]<br /> 48,013,979 ???:_int_malloc [/lib64/libc-2.8.so]<br /> 46,419,350 /home/sweeks/src/parrot/compilers/imcc/pbc.c:constant_folding [/home/sweeks/src/parrot/blib/lib/libparrot.so.0.7.1]<br /> 33,201,086 /home/sweeks/src/parrot/compilers/imcc/sets.c:set_intersec_inplace [/home/sweeks/src/parrot/blib/lib/libparrot.so.0.7.1]<br /> 29,624,696 /home/sweeks/src/parrot/compilers/imcc/symreg.c:hash_str [/home/sweeks/src/parrot/blib/lib/libparrot.so.0.7.1]<br /> 20,719,320 ???:calloc [/lib64/ld-2.8.so]<br /> 18,291,953 /home/sweeks/src/parrot/compilers/imcc/cfg.c:bb_check_set_addr [/home/sweeks/src/parrot/blib/lib/libparrot.so.0.7.1]<br /> 17,404,418 /home/sweeks/src/parrot/compilers/imcc/reg_alloc.c:compute_one_du_chain [/home/sweeks/src/parrot/blib/lib/libparrot.so.0.7.1]<br /> 13,809,278 /home/sweeks/src/parrot/compilers/imcc/imcc.l:yylex<br /> 12,337,246 /home/sweeks/src/parrot/src/ops/core_ops.c:hash_str [/home/sweeks/src/parrot/blib/lib/libparrot.so.0.7.1]<br /> 12,162,840 ???:memcpy [/lib64/ld-2.8.so]<br /> 11,450,969 ???:strcmp'2 [/lib64/ld-2.8.so]<br /></pre><br />So it's in IMCC, the PIR compiler, specifically in compute_dominance_frontiers... which is what? So let's find out.<br /><br />The POD for that function says:<br /><pre><br />=item C<void compute_dominance_frontiers><br /><br />Algorithm to find dominance frontiers described in paper <a href="http://www.cs.rice.edu/~keith/EMBED/dom.pdf">"A Simple, Fast<br />Dominance Algorithm", Cooper et al. (2001)</a><br /></pre><br />A quick check with google turns up the PDF I linked.<br /><br />Skimming over that and the surrounding code that calls compute_dominance_frontier reveals that it's related to register allocation. I read it another couple of times, think I understand the general ideas, and go to sleep.<br /><br />The next day, I chat with pmichaud about it, and he manages to trim down a simplifed test case, and also notices the actual bug in my patch, which allows me to commit that and pass a half-dozen more tests. He passes the minimal test off to chromatic, who debugs it for a bit and finds that an inner loop in compute_dominance_frontiers is alternating between 8 and 9.<br /><br />chromatic suggests that I find a way to dump out the register and basic blocks information, and look for the edge identification between blocks. I only have a vague idea of what this means then, so I ask for more information. Here's chromatic's explanation:<br /><pre><br /><@chromatic> I can give you a quick overview.<br /><@chromatic> The alligator divides every compilation unit into basic blocks.<br /><@chromatic> A block is a single block of code between branch points.<br /><@chromatic> Every entrance and exit point demarcates a block.<br /><@chromatic> If you arrange the blocks in terms of a control flow graph, you can evaluate all of the possible ways you can reach a point within the block.<br /><@chromatic> You also keep track of which registers you use within a block.<br /><@chromatic> If all of the paths to a block go through another block, the latter dominates the former.<br /><@chromatic> All of this is to say, if you have a named register used in the first block of a unit and the final block of the unit can branch back to the first unit, you have to keep the physical register untouched.<br /><@chromatic> If there's a block beyond which you can never branch back, you can reuse physical registers unique to that branch and never used later.<br /><@chromatic> I've been unclear about name/physical register mapping, but I think you get the picture.<br /><@chromatic> It's the mapping of name to register that really matters.<br /></pre><br />So I start browsing that code again, but fall asleep before doing anything. Do you see the pattern here yet? ;)<br /><br />The next day, I go look around in there and I find a couple of debug functions I can use to dump relevant information. Here's what I find:<br /><pre><br />Dumping the CFG:<br />-------------------------------<br />0 (3) -> 8 1 2 <- <br />1 (3) -> 2 <- 0 <br />2 (3) -> 3 9 <- 1 0 <br />3 (2) -> 4 <- 2 <br />4 (2) -> 5 <- 3 <br />5 (3) -> 6 9 <- 8 7 4 <br />6 (3) -> 7 <- 5 <br />7 (3) -> 5 <- 6 <br />8 (2) -> 5 <- 9 0 <br />9 (3) -> 8 <- 5 2 <br /></pre><br />This is:<br /><pre><br />block number (loop depth) -> blocks that this block can branch to <- blocks that can branch to this block<br /></pre><br />We also have:<br /><pre><br />Dumping the Dominators Tree:<br />-------------------------------<br /> 0 <- ( 0) 0<br /> 1 <- ( 0) 0 1 8 9<br /> 2 <- ( 0) 0 2 8 9<br /> 3 <- ( 2) 0 2 3 8 9<br /> 4 <- ( 3) 0 2 3 4 8 9<br /> 5 <- ( 0) 0 5 8 9<br /> 6 <- ( 5) 0 5 6 8 9<br /> 7 <- ( 6) 0 5 6 7 8 9<br /> 8 <- ( 9) 0 8 9<br /> 9 <- ( 8) 0 8 9<br /></pre><br />This is:<br /><pre><br />block number <- (immediate dominator) full list of dominators<br /></pre><br />The loop that was spinning was:<br /><pre><br />while (runner >= 0 && runner != unit->idoms[b]) {<br /> /* add b to runner's dominance frontier set */<br /> set_add(unit->dominance_frontiers[runner], b);<br /><br /> /* runner = idoms[runner] */<br /> if (runner == 0)<br /> runner = -1;<br /> else<br /> runner = unit->idoms[runner];<br />}<br /></pre><br />Where 'runner' is the node we're currently evaluating, unit is the overall compilation unit, and idoms[] is the list of immediate dominators.<br /><br />Adding some debugging printfs, I discover that the problem is when the algorithm follows block five, it spins with the runner alternating between 8 and 9. If you look back up at the dominators tree, you'll see that the immediate dominator of block 8 is block 9, and the idom of block 9 is block 8. Infinite loop.<br /><br />After re-reading the algorithm and paper a few times to verify that I undersand what's going on, I add a conditional to break out of the statement if we're trying to add a block to the dominance frontiers list of a block that we've already added the current block to.<br /><pre><br />while (runner >= 0 && runner != unit->idoms[b]) {<br /> if (set_contains(unit->dominance_frontiers[runner], b))<br /> /* we've already gone down this path once before */<br /> runner = 0;<br /> else<br /> /* add b to runner's dominance frontier set */<br /> set_add(unit->dominance_frontiers[runner], b);<br /><br /> /* runner = idoms[runner] */<br /> if (runner == 0)<br /> runner = -1;<br /> else<br /> runner = unit->idoms[runner];<br />}<br /></pre><br />Everything seemed to work fine, so after getting a review from particle, I committed.tenehttp://www.blogger.com/profile/12325563865990451725noreply@blogger.com0tag:blogger.com,1999:blog-2772753380875006713.post-12232676991654737252008-09-10T17:45:00.000-07:002008-09-11T06:23:29.693-07:00"Final report" for Mozilla Foundation and TPF grant<!--PageText--><br /><div id='wikitext'><br />Last year I received a <a class='urllink' href='http://news.perlfoundation.org/2007/11/patrick_michaud_awarded_perl_6.html' rel='nofollow'>Perl 6 development grant</a> from the <a class='urllink' href='http://www.mozillafoundation.org/' rel='nofollow'>Mozilla Foundation</a> and <a class='urllink' href='http://www.perlfoundation.org/' rel='nofollow'>The Perl Foundation</a>. Below is a copy of the final report I've submitted to close out the grant. It's also available in <a class='urllink' href='http://www.pmichaud.com/perl6/mfp6grant.pdf' rel='nofollow'>PDF</a> if anyone wants a more printable version.<br /><br />My thanks to everyone who helped me with this grant, and I'm looking forward to the next one.<br /><br />[2008-09-11 update: the original version of this report mis-attributed the Squaak tutorial to Kevin Tew; the corrected author is Klaas-Jan Stol (kjs). My sincere apologies for the mistake, it is now corrected below.]<br /><br /><hr /><br /><h2 style='text-align: center;'>Perl 6 Development Grant<br />Final Report</h2>Patrick R. Michaud<br />September 10, 2008<br /><h3>INTRODUCTION</h3>This is the final report for the Perl 6 and Parrot development grant provided by the Mozilla Foundation and The Perl Foundation. This report summarizes the work performed under the grant, what has been accomplished, and where things are headed from here. As this report illustrates, we have achieved all of the goals and outcomes intended for this grant.<br /><h3>REPORT</h3>The primary focus of the project was to get Perl 6 on Parrot development "over the hump" and acquire a critical mass of infrastructure, developers, and tools from which sustained further development of Perl 6 can take place. The project proposal identified five specific expected outcomes:<br /><ol><li>A working Perl 6 on Parrot implementation that supports commonly used Perl constructs and operators<br /></li><li>Review and improvements to the Perl 6 language test suite<br /></li><li>A substantially complete Parrot Compiler Toolkit, with documentation<br /></li><li>Ongoing, active development efforts for other languages based on the Parrot Compiler Toolkit<br /></li><li>An increased number of participants in Perl 6 and Parrot design, implementation, and testing<br /></li></ol><em>1. A working Perl 6 on Parrot implementation</em><br /><br />We now have a substantial Perl 6 implementation on Parrot. At the beginning of this project, we had a rudimentary Perl 6 compiler that could handle some of the basic features and syntax of Perl. However, some key features such as arrays and hashes were only marginally implemented, and most of the translation components of the compiler were written in Parrot's intermediate assembly language (PIR).<br /><br />Today the Perl 6 on Parrot compiler has been substantially rewritten using the Parrot Compiler Toolkit (described below), and is now known as "Rakudo Perl" or "Rakudo" <a href='#r1'>[1]</a>. Rakudo currently supports arrays, hashes, classes, objects, inheritance, roles, enumeration types, subset types, role composition, multimethod dispatch, type checking, basic I/O, named regular expressions, grammars, optional parameters, named parameters, slurpy parameters, closures, smart match, junctions, and many other features expected from Perl 6. Rakudo has progressed to the point that others are now using Rakudo as an Apache handler ("mod_perl6") <a href='#r2'>[2]</a>, a wiki engine ("November") <a href='#r3'>[3]</a>, and recently to build applications on Xlib <a href='#r4'>[4]</a>. The Perl Foundation also recently awarded a grant to Vadim Konovalov to implement a Tk GUI interface for Rakudo <a href='#r5'>[5]</a>.<br /><br />During the project there have been many contributors to the development of Rakudo Perl; some of the major contributors include chromatic, Vasily Chekalkin (bacek), Jerry Gay, Jeff Horwitz, Moritz Lenz, Carl Mäsak, Cory Spencer, Stephen Weeks (Tene), and Jonathan Worthington. Jonathan Worthington's efforts deserve special mention: he is primarily responsible for the bulk of the work on classes and types in Rakudo Perl, and much of his work was supported by a grant from Vienna.pm <a href='#r6'>[6]</a>.<br /><br /><em>2. Review and improvements to the Perl 6 test suite</em><br /><br />At the beginning of this project, the test suite that existed for Perl 6 had been implemented as part of the Pugs effort and contained approximately 16,000 tests. However, in many cases the tests were out of date with respect to the current Perl 6 language specification, and we needed a way for multiple independent Perl 6 implementations to be able to easily make use of the test suite.<br /><br />In December 2007 I proposed a structure for reorganizing the test suite <a href='#r7'>[7]</a>; Jerry Gay and Larry Wall then extended this proposal and developed tools to make it easier to share the tests among multiple implementations. In May 2008 Moritz Lenz refactored Rakudo's test harness to provide a "make spectest_regression" target -- since then this has become our primary measure of Rakudo progress <a href='#r8'>[8]</a>. Moritz Lenz also developed a tool to display the progress in graphical form:<br /><pre> <img src='http://www.pmichaud.com/perl6/rakudo-tests-2008-09-10.png' alt='' title='' /></pre>Adrian Kreher received a Google Summer of Code grant (with Moritz Lenz and Jerry Gay as mentors) to continue the test suite refactoring <a href='#r9'>[9]</a>. As of early September 2008, the official, refactored test suite contains a little over 8,000 tests, or approximately half the size of the original Pugs test suite. Furthermore, the official suite includes many new tests for object-oriented and typing features of Perl 6 that weren't present in the original test suite. As the graph above indicates, Rakudo is currently passing over 3,200 of the tests in the official suite, and work is continuing on refactoring the suite and increasing Rakudo's pass rate.<br /><br /><em>3. A substantially complete Parrot Compiler Toolkit, with documentation</em><br /><br />As mentioned previously, the compilers that existed for Parrot at the beginning of the project (such as Perl 6) were primarily written in Parrot's intermediate assembly language. This made working on the compilers less accessible to new developers, as well as increasing the time needed to build a compiler. Therefore, the first couple of months of this project were spent on developing the Parrot Compiler Toolkit (PCT) and a simple Parrot language called Not Quite Perl (NQP). PCT provides an abstract syntax tree representation and code generator for Parrot languages; NQP enables compiler writers to easily create compilers and builtin functions for Parrot using a simplified Perl 6 syntax.<br /><br />Once PCT and NQP were substantially complete, we were then able to convert Perl 6 (now "Rakudo Perl") and many other Parrot compilers to use the new toolkit. This went surprisingly quickly -- most of the existing compilers were converted within just a couple of weeks. In addition, a few new compilers and languages arrived on the scene: Will Coleda and Simon Cozens quickly created an implementation of LOLCODE <a href='#r10'>[10]</a>, and Klaas-Jan Stol created a language called "Squaak" as a demonstration and tutorial for the toolkit <a href='#r11'>[11]</a>. A couple of quotes from the period give a sense of how these tools opened up Parrot development to others:<br /><blockquote>"The real fun, though, has been digging into perl6, the Parrot Perl 6 implementation. Recently, Patrick Michaud has been doing some incredible work building NQP (Not Quite Perl 6), a bootstrapping language for implementing Perl 6, and extensively refactoring the existing Perl 6 on Parrot compiler to fit with it. I'm still very much getting my head wrapped around the whole thing, but it's been easy enough to start digging into and implementing and fixing a few things."<br /><blockquote>- Jonathan Worthington, December 2007 <a href='#r12'>[12]</a></blockquote>"It's really, really true. Parrot lets you implement your own languages using Perl 6 rules for the grammar and Perl 6 for the compiler."<br /><blockquote>- Simon Cozens, January 2008 <a href='#r13'>[13]</a></blockquote></blockquote>Both PCT and NQP stabilized early in the project; recent changes have been primarily to optimize existing features or make other minor improvements. We expect these tools to continue to evolve as needed to support compiler development; however, given the wide variety of languages being implemented using the toolkit surprisingly few changes have been needed. Primary documentation for the toolkit consists of a Parrot Design Document (PDD26) for the abstract syntax tree representation <a href='#r14'>[14]</a>, the Squaak tutorial <a href='#r11'>[11]</a>, and numerous example languages in the Parrot repository. More detailed documentation and examples for the toolkit are expected to be developed over the coming months.<br /><br /><em>4. Ongoing, active development efforts for other languages based on the Parrot Compiler Toolkit</em><br /><br />Currently there is active development on at least three languages for Parrot; these include Perl 6 (Rakudo Perl), PHP (Pipp), and Ruby (Cardinal). In addition, there is ongoing but less active<br />development on implementations of Python (Pynie) and Smalltalk (ChitChat). All of these are based on the tools from the Parrot Compiler Toolkit. The Perl 6 and PHP implementations are usable from mod_parrot <a href='#r2'>[2]</a>, and our next steps are to improve the toolkit and library conventions to support loading multiple languages simultaneously in Parrot.<br /><br /><em>5. An increased number of participants in Perl 6 and Parrot design, implementation, and testing</em><br /><br />There can be little question that momentum for Perl 6 and Parrot development continues to grow, and the work supported by this grant has been a major catalyst for that growth. For the twelve months prior to September 2007 the Parrot subversion repository had a total of 6,634 commits; in the subsequent twelve months Parrot had 9,686 commits -- a year-over-year increase of 46% in the commit rate.<br /><br />At the beginning of this project there were perhaps three or four active contributors to the Perl 6 on Parrot compiler (i.e., Rakudo Perl); over the course of the past year that number has increased to at least ten active contributors and at least as many more occasional contributors to Rakudo Perl. Parrot and the Parrot Compiler Toolkit have also garnered new contributors, including several new committers. There are also new teams of developers working on applications based on Rakudo Perl and Parrot, such as the November wiki engine and the Rakudo/Tk GUI interface.<br /><br />Lastly, recent improvements in the Rakudo compiler architecture will allow much of the Perl 6 runtime library currently written in PIR to be rewritten substantially in Perl 6. This will enable even more new contributors to participate in Perl 6 development.<br /><h3>PROJECT EVALUATION</h3>The project proposal identified five criteria by which the success of this project could be measured:<br /><ul><li>Ability to write and test Perl 6 programs and language features<br /></li><li>Passing rate for Perl 6 language test suite<br /></li><li>Improved coverage and accuracy of the Perl 6 language test suite<br /></li><li>Increased number of participants in Perl 6 and Parrot development<br /></li><li>Active development of at least two other languages using Parrot compiler tools<br /></li></ul>This report demonstrates the success of this project along all of these measures. Perl 6 on Parrot ("Rakudo") is being used to write and test Perl 6 programs and language features, and has become a strong driver for improving the coverage and accuracy of the test suite (and indeed, of the Perl 6 language specification itself). Continual reporting and publication on Perl 6 and Parrot activities continues to attract increased interest and participation from the wider community.<br /><br />Moreover, this project helped jump-start even larger fund-raising efforts. In May 2008 the Perl Foundation received a $200,000 philanthropic donation from Ian Hague; roughly half of this donation is intended to continue the Perl 6 development efforts that have been part of this project <a href='#r15'>[15]</a>. And, as mentioned earlier, Jonathan Worthington and others are receiving grants for continued work on Rakudo Perl and Parrot <a href='#r6'>[6,8,16]</a>.<br /><h3>CONCLUSION AND FUTURE WORK</h3>The funding provided by the Mozilla Foundation and The Perl Foundation has indeed enabled us to get Perl 6 on Parrot development "over the hump" in development. We now have a robust platform for higher-level language development on Parrot, along with an active and growing development and support community (which is the hallmark of any successful open source project). All of the desired outcomes of this project have been realized.<br /><br />Our next steps will be to continue to extend and build upon the work of this project -- increasing Rakudo's coverage of the Perl 6 language and bringing all of our efforts much closer to production releases. In fact, we recently developed a "road map" for Rakudo Perl that identifies the major steps to be taken in the upcoming months and assists in coordinating the remaining development activities <a href='#r17'>[17]</a>.<br /><br />Lastly, I want to express my sincere appreciation to the many people who contribute time and energy to Perl 6 and Parrot, and to give special thanks to the people of the Mozilla Foundation and The Perl Foundation for their ongoing support and enthusiasm for this project. It is a great honor to work and correspond with such a terrific and professional group of individuals.<br /><h3>REFERENCES</h3><ol><li><a name='r1' id='r1'></a> P. Michaud (January 16, 2008), "The compiler formerly known as 'perl6'", <a class='urllink' href='http://use.perl.org/~pmichaud/journal/35400' rel='nofollow'>http://use.perl.org/~pmichaud/journal/35400</a></li><li><a name='r2' id='r2'></a> J. Horwitz, "Mod_parrot website", <a class='urllink' href='http://www.smashing.org/mod_parrot/' rel='nofollow'>http://www.smashing.org/mod_parrot/</a></li><li><a name='r3' id='r3'></a> C. Mäsak, "Announcing November, a wiki in Perl 6", <a class='urllink' href='http://use.perl.org/~masak/journal/37212' rel='nofollow'>http://use.perl.org/~masak/journal/37212</a></li><li><a name='r4' id='r4'></a> <a class='urllink' href='http://svn.perl.org/parrot/trunk/examples/nci/xlibtest.p6' rel='nofollow'>http://svn.perl.org/parrot/trunk/examples/nci/xlibtest.p6</a></li><li><a name='r5' id='r5'></a> Alberto Sim&otild;es (August 30, 2008), "2008Q3 Grants Results", <a class='urllink' href='http://news.perlfoundation.org/2008/08/2008q3_grants_results.html' rel='nofollow'>http://news.perlfoundation.org/2008/08/2008q3_grants_results.html</a></li><li><a name='r6' id='r6'></a> "Vienna.pm funds Jonathan Worthington to work on Ra[kudo]" (April 23, 2008), <a class='urllink' href='http://use.perl.org/article.pl?sid=08/04/23/2314234' rel='nofollow'>http://use.perl.org/article.pl?sid=08/04/23/2314234</a> <br /></li><li><a name='r7' id='r7'></a> P. Michaud (December 20, 2007), "Proposal: refactor the test suite according to synopsis, <a class='urllink' href='http://groups.google.com/group/perl.perl6.compiler/msg/ed748490f030da2f' rel='nofollow'>http://groups.google.com/group/perl.perl6.compiler/msg/ed748490f030da2f</a> <br /></li><li><a name='r8' id='r8'></a> P. Michaud (June 16, 2008), "Rakudo test suite progress", <a class='urllink' href='http://use.perl.org/~pmichaud/journal/36695' rel='nofollow'>http://use.perl.org/~pmichaud/journal/36695</a> <br /></li><li><a name='r9' id='r9'></a> A. Kreher, "Auzon's Blog: gsoc2008", <a class='urllink' href='http://auzon.blogspot.com/search/label/gsoc2008' rel='nofollow'>http://auzon.blogspot.com/search/label/gsoc2008</a> <br /></li><li><a name='r10' id='r10'></a> "I HAZ A PARROT" (January 3, 2008), <a class='urllink' href='http://lolcode.com/news/i-haz-a-parrot' rel='nofollow'>http://lolcode.com/news/i-haz-a-parrot</a> <br /></li><li><a name='r11' id='r11'></a> K. Stol (March 9, 2008), "PCT Tutorial Episode 1: Introduction", <a class='urllink' href='http://www.parrotblog.org/2008/03/targeting-parrot-vm.html' rel='nofollow'>http://www.parrotblog.org/2008/03/targeting-parrot-vm.html</a> <br /></li><li><a name='r12' id='r12'></a> J. Worthington, "Chipping away at perl6", <a class='urllink' href='http://www.jnthn.net/cgi-bin/blog_read.pl?id=589' rel='nofollow'>http://www.jnthn.net/cgi-bin/blog_read.pl?id=589</a> <br /></li><li><a name='r13' id='r13'></a> S. Cozens (January 3, 2008), "Parrot is really quite wonderful", <a class='urllink' href='http://blog.simon-cozens.org/post/view/132' rel='nofollow'>http://blog.simon-cozens.org/post/view/132</a></li><li><a name='r14' id='r14'></a> "Parrot Abstract Syntax Tree (PDD 26)", <a class='urllink' href='http://www.parrotcode.org/docs/pdd/pdd26_ast.html' rel='nofollow'>http://www.parrotcode.org/docs/pdd/pdd26_ast.html</a> <br /></li><li><a name='r15' id='r15'></a> R. Dice (May 16, 2008), "TPF receives large donation in support of Perl 6 development", <a class='urllink' href='http://news.perlfoundation.org/2008/05/tpf_receives_large_donation_in.html' rel='nofollow'>http://news.perlfoundation.org/2008/05/tpf_receives_large_donation_in.html</a></li><li><a name='r16' id='r16'></a> J. Worthington (August 5, 2008), "Multiple Dispatch Design Work", <a class='urllink' href='http://use.perl.org/~JonathanWorthington/journal/37101' rel='nofollow'>http://use.perl.org/~JonathanWorthington/journal/37101</a></li><li><a name='r17' id='r17'></a> "Perl 6 Development Roadmap", <a class='urllink' href='http://svn.perl.org/parrot/trunk/languages/perl6/ROADMAP' rel='nofollow'>http://svn.perl.org/parrot/trunk/languages/perl6/ROADMAP</a></li></ol></div><br /><!--/PageText-->Pmhttp://www.blogger.com/profile/05117950909580615426noreply@blogger.com0tag:blogger.com,1999:blog-2772753380875006713.post-14331869004766553422008-08-20T07:57:00.000-07:002008-08-29T08:47:23.524-07:00Using 'register' scope in Parrot Abstract Syntax Trees<span style="font-size:180%;">Introduction</span><br />The Parrot Compiler Toolkit (PCT) is evolving, slowly becoming mature. More and more features and improvements are added over time. In this short article, we'll be looking at <span style="font-family:courier new;">"register"</span> scope in the Parrot <span style="font-family:courier new;">PAST::Var</span> node, which was added recently. For this article, I assume you're familiar with the PCT, or at least heard of it, otherwise I'd suggest reading up a bit, for instance by reading the PCT Tutorial. In order to make things as easy as possible, I'll start out with a short introduction on the Parrot Abstract Syntax Tree data structure.<br /><span style="font-size:180%;"><br />PAST Variables and Scope</span><br />PCT-based compilers generate a data structure called a Parrot Abstract Syntax Tree (PAST). The <span style="font-family:courier new;">PAST </span>itself consists of a number of different <span style="font-family:courier new;">PAST </span>nodes. For instance, to represent a subroutine (or function, or procedure), you'd use a <span style="font-family:courier new;">PAST::Block</span> node, while you'd use <span style="font-family:courier new;">PAST::Val </span>nodes to represent literal constants (such as 42, "hello world", etc.).<br />For representing variables, you'd use a <span style="font-family:courier new;">PAST::Var</span> node. All variables have a <span style="font-family:courier new;">name </span>and a <span style="font-family:courier new;">scope</span>, implemented as attributes of the <span style="font-family:courier new;">PAST::Var</span> class. Available values for the scope attribute are, among others: <span style="font-family:courier new;">"package"</span> and <span style="font-family:courier new;">"lexical"</span>, representing "global" and "lexical" (or "local", except that <span style="font-family:courier new;">"lexical"</span> implies availability in nested subs (or <span style="font-family:courier new;">PAST::Block</span> nodes) as well) scope.<br /><br /><span style="font-size:180%;">Introducing Register Scope</span><br />Lexically scoped variables are stored in such a way that nested subroutines can access them too. In languages such as Perl 6 and Lua, this makes sense. However, in a language such as C (yes, there is a C implementation for Parrot as well, albeit an incomplete one) this is not needed, as C does not have nested functions. The overhead of lexicals would be a waste of your CPU cycles.<br />The new <span style="font-family:courier new;">register </span>scope allows for such "light-weight" local variables. Furthermore, although not implemented at the moment of writing this article, these register variables allow for reusable results. Consider the following pseudo-code example of a <span style="font-family:courier new;">"with"</span> statement. A with statement takes some expression, and the operations in the block are all executed on that expression. (Note that this is pseudo code).<br /><blockquote style="font-family:courier new;"><pre>with (foo) {<br /><span style="font-family:courier new;"> .bar();</span><br /><span style="font-family:courier new;"> .baz();</span><br /><span style="font-family:courier new;"> .foobar();</span><br />}</pre></blockquote>This is equivalent to:<br /><blockquote style="font-family: courier new;">foo.bar();<br />foo.baz();<br />foo.foobar();</blockquote>except that in the case of the with-statement, the expression is evaluated only once. I'm sure there are better examples to be thought of for a <span style="font-family:courier new;">with </span>statement, but this is the best I can come up with for now. Using the PCT, you could implement this as follows:<br /><blockquote><pre><span style="font-family:courier new;"> rule with_statement {</span><br /><span style="font-family:courier new;"> 'with' '(' <expression> ')'</span><br /><span style="font-family:courier new;"> '{' <statement>* '}'</span><br /><span style="font-family:courier new;"> {*} </span><br />}</pre></blockquote><br />The corresponding action method would be:<br /><blockquote style="font-family: courier new;"><pre>method with_statement($/) {<br /><span style="font-family:courier new;"> my $past := PAST::Stmts.new( :node($/) );</span><br /><span style="font-family:courier new;"> my $expr := $( $<expression> );</span><br /><span style="font-family:courier new;"> for $<statement> {</span><br /><span style="font-family:courier new;"> my $operation := $( $_ );</span><br /><span style="font-family:courier new;"> $operation.unshift($expr);</span><br /><span style="font-family:courier new;"> $past.push( $operation );</span><br /><span style="font-family:courier new;"> }</span><br /><span style="font-family:courier new;"> make $past;</span><br />}</pre></blockquote><br />Basically, the PAST node representing the expression is <span style="font-style: italic;">unshifted </span>onto each operation. However, this would result in PIR code that would evaluate the expression for each statement in the with-block. This, of course, reduce the efficiency of the whole with-statement, whose semantics define that the expression is evaluated only once. In order to solve this, you can generate PIR code that evaluates the expression once, stores the result in a register variable, and use that register variable in each operation.<br /><br /><span style="font-size:180%;">Why "Register" instead of "Local"?</span><br />You might wonder why this scope is called "register". The scope name "register" makes perfect sense, as this is exactly how it is implemented. A variable with "register" scope is implemented as a PIR variable declared with the <span style="font-family:courier new;">.local</span> directive. Such a variable<span style="font-family:courier new;"></span> is just a symbolic register, which makes writing PIR code by hand much easier. The PIR compiler will map these <span style="font-family:courier new;">.locals</span> to Parrot registers (of type PMC, Parrot does not support lexicals of other types). The name "register", therefore, makes perfect sense.<br /><br /><span style="font-size:180%;">Using Register-scoped Variables in Your Compiler</span><br />There is not much to it to use register-scoped variables. You use them the same way as you would use global or lexical variables. The <span style="font-family:courier new;">name </span>attribute gives the register a name, and when setting the<span style="font-family:courier new;"> isdecl</span> flag on it, the PAST node will generate a PIR <span style="font-family:courier new;">.local</span> declaration. In comparison, when this flag is set on a <span style="font-family:courier new;">PAST::Var</span> node with "lexical" scope, a <span style="font-family:courier new;">.lex</span> directive is generated.<br /><br /><span style="font-size:180%;">Conclusion</span><br />This article discussed a recently added feature to the PCT, albeit a small one. The addition of a new scope type to <span style="font-family:courier new;">PAST::Var</span> nodes. The new "register" scope allows for light-weight local variables, and in the not too distant future will allow for reusable (intermediate) results, preventing re-evaluation of expressions in your <span style="font-family:courier new;">PAST</span>.<br />As you can see, the PCT is evolving over time, which allows users to create compilers for all sorts of languages targeting the Parrot virtual machine.Anonymousnoreply@blogger.com0tag:blogger.com,1999:blog-2772753380875006713.post-43144493545831258772008-06-24T10:30:00.000-07:002008-06-24T11:40:22.567-07:00Announcing the Parrot FoundationOn June 9th, 2008, we filed the incorporation papers for the Parrot Foundation (abbreviated as just "Parrot", or "PaFo" if you can't resist the shiny alphabet soup). The articles of incorporation and bylaws were drafted on the mailing list and in the wiki, the same way all Parrot design documents are drafted. The design of the foundation is very much a part of the design of the whole project, tailored to the culture and customs of Parrot.<br /><br />The purpose of the foundation is to hold the intellectual property of the project, to help drive development of the core codebase and language implementations, to support and grow the community around Parrot, and reach out to other language projects. As we push through the final steps to the 1.0 release, the foundation will provide the infrastructure we need to move forward.<br /><br />The initial board of directors consists of: Allison Randal, Chairman; Jerry Gay, President; Will Coleda, Vice President; Shane Warden, Secretary; and Jeff Horwitz, Treasurer. The membership of the foundation will start with the current committers, and quickly expand to include all contributors. Members elect the board of directors every year, so the leadership and direction of the foundation is always guided by the developers.<br /><br />It's exciting to see the foundation come together so quickly and smoothly. While the idea of a foundation for Parrot has been bubbling on the back burner for about a year, it was only two months ago that we got together and decided it was time to make it a reality.<br /><br />Thanks to all who have helped make it possible, and cheers to a great future!Allisonhttp://www.blogger.com/profile/04152634008027752306noreply@blogger.com0tag:blogger.com,1999:blog-2772753380875006713.post-46097824330100360212008-06-22T17:44:00.000-07:002008-06-22T17:56:41.053-07:00Parrot Hackathon and Workshop at YAPC::NA 2008Many parrot committers attended the recent YAPC:NA; we scheduled a pre-conference hackathon that turned out to be very effective. Thanks to the conference hosts for keeping us floating in caffeine and snacks.<div><br /></div><div>More than the closed tickets and committed code, the face to face time with the other committers is always a plus. Working with someone online is very different than a face to face meeting, and can lay the groundwork for future collaboration efforts.</div><div><br /></div><div>Jim Keenan drove a workshop at the conference, a new format that provides an extended, freeform timeslot. Jim used the workshop to get everyone there to build both parrot and Rakudo. We were able to get most of the folks there building on their respective platforms. For those who did encounter difficulties, we were able to get some bug reports (and some fixes), and even some patches from those new to the project. (Packy++ and Deven++)</div><div><br /></div><div>I even got someone potentially interested in partcl (Tcl on Parrot) out of the workshop, a bonus I was not expecting. (Shane++).</div><div><br /></div><div>Hopefully we can recreate some of this success at YAPC::EU, and definitely next year at YAPC::NA '09. See you then!</div><div><br /></div>Cokehttp://www.blogger.com/profile/01745512237217656642noreply@blogger.com0tag:blogger.com,1999:blog-2772753380875006713.post-19957898350253679412008-06-19T19:03:00.000-07:002008-06-19T19:05:12.309-07:00Parrot workshop at YAPC::NA 2008 -- success!!Yesterday at YAPC::NA 2008 we had a Parrot workshop, primarily organized by Jim Keenan. It went great -- Jim did a fantastic job. I think we had approximately 20 participants total, and several of the parrot folks came by to help.<br /><br />During the workshop I think we managed to get nearly everyone with a working copy of Parrot and Rakudo Perl, and I even managed to take some notes on how we can improve things for others later.<br /><br />We also found (and fixed) some bugs in the official test suite, and Deven Corzine even grabbed a Pugs commit bit and fixed a Windows bug in the fudgeall script!<br /><br />I found the workshop to be very productive for me personally, and again my compliments and thanks to Jim Keenan and the other organizers for putting it together. (I was at the workshop to help, but I didn't do much of the work in putting it together. :-)<br /><br />PmPmhttp://www.blogger.com/profile/05117950909580615426noreply@blogger.com0tag:blogger.com,1999:blog-2772753380875006713.post-87762026766683531792008-06-17T11:19:00.000-07:002008-06-17T11:23:09.683-07:00Parrot 0.6.3 "Beautiful Parrot" Released!Greetings,<br /><br />On behalf of the Parrot team, I'm proud to announce Parrot 0.6.3 "Beautiful Parrot." <a href="http://parrotcode.org/">Parrot</a> is a virtual machine aimed at running all dynamic languages.<br /><br />Parrot 0.6.3 is available via CPAN (soon), or follow the <a href="http://parrotcode.org/source.html">download instructions</a>. For those who would like to develop on Parrot, or help develop Parrot itself, we recommend using Subversion on the source code repository to get the latest and best Parrot code.<br /><br />Parrot 0.6.3 News:<pre>- Specification<br />+ updated pdd09_gc.pod<br />- Languages<br />+ Cardinal:<br /> - dramatically improved parsing speed<br /> - added support for defining and instantiating classes<br /> - started fleshing out the builtin class hierarchy<br /> - added support for hashes and arrays<br />+ Chitchat: added the start of a smalltalk compiler<br />+ Pheme: updated to match PGE changes<br />+ Pynie: return statement, other minor updates<br />+ Rakudo:<br /> - added working list and hash contexts<br /> - added 'return' statements<br /> - added => pair constructor<br /> - added ?? !! ternary<br /> - added Range, range operators, Complex<br /> - added common List, Hash methods<br /> - refactored base classes<br /> - added Mutable, Perl6Scalar classes<br /> - added type-checking, is readonly/rw/copy for parameters<br /> - added make localtest, docs/spectest-progress.csv<br /> - fix named unaries<br />+ Squaak: implement return statement<br />+ Tcl: updated control flow exceptions to use new builtin types<br />- Compilers<br />+ All tools converted to P6object metamodel<br />+ PGE:<br /> - is now a zero-width match<br /> - reduced backtracking to improve parsing speed<br />+ PCT:<br /> - added "return" PAST.op node type for subroutine returns<br /> - added "keyed_int" scoping to PAST::Var<br /> - fixed calls to closures<br /> - automatically transcode 7-bit unicode to ascii for faster processing<br />+ NQP: added "return" statement, ?? !! ternary operator<br />- Configuration<br />+ expanded step gen::opengl<br />- Implementation<br />+ updated function and macro names to match pdd09_gc.pod<br />+ removed Super PMC<br />+ add ".namespace []" as alternative to ".namespace"<br />+ "make codetest" target runs standard coding tests<br />- Miscellaneous<br />+ added P6object class for Perl 6 interfaces to objects in Parrot<br />+ ported OpenGL/GLU/GLUT bindings to Win32, BSD, and more Mac OS X variants<br />+ generate OpenGL/GLU/GLUT bindings by parsing system headers<br />+ new OpenGL example shapes.pir, covering basic OpenGL 1.1 / GLUT 3 APIs<br />+ new float4.pir structure-packing benchmark<br />+ reduced memory use for variables<br />+ improved constant string caching<br />+ made code g++ and gcc (with optimizations) safe<br />+ the usual collection of bugfixes and optimizations<br /></pre><br />Many thanks to all our contributors for making this possible, and our sponsors for supporting this project. Our next scheduled release is 15 July 2008.<br /><br />Enjoy!<br /><span class="Apple-style-span" style="font-style: italic;">./smash</span>Cokehttp://www.blogger.com/profile/01745512237217656642noreply@blogger.com0tag:blogger.com,1999:blog-2772753380875006713.post-62285471754412133222008-06-13T21:45:00.000-07:002008-06-13T21:49:14.868-07:00YAPC::NA HackathonI know we have at least 5 parrot hackers here at YAPC::NA in the dorms, ready to start hacking at nine-ish Chicago-time tomorrow.<div><br /></div><div>If you're at YAPC, feel free to swing by; If you're on IRC, please join us tomorrow in #hackathon or #parrot in irc.perl.org.</div><div><br /></div><div>For an overview of what's on the agenda, see:</div><div><br /></div><div><span class="Apple-style-span" style="font-family: 'Lucida Grande'; font-size: 12px; white-space: pre; ">http://conferences.mongueurs.net/yn2008/wiki?node=ParrotHackathon</span><br /></div><div><span class="Apple-style-span" style="font-family: 'Lucida Grande'; font-size: 12px; white-space: pre;"><br /></span></div><div><span class="Apple-style-span" style="font-family: 'Lucida Grande'; font-size: 12px; white-space: pre;">See you there!</span></div>Cokehttp://www.blogger.com/profile/01745512237217656642noreply@blogger.com0tag:blogger.com,1999:blog-2772753380875006713.post-72981897771821872022008-06-11T06:48:00.001-07:002008-06-11T08:07:48.958-07:00Implementing the 'return' statement in SquaakRecently, Patrick Michaud made first steps to extend the Parrot Abstract Syntax Tree (PAST) to handle return statements. In this short report, I'll show how to implement a return statement in Squaak, the PCT tutorial language we created earlier. First, however, we'll have a quick review of why implementing <span style="font-family:courier new;">'return'</span> is not straightforward. Parrot has these fancy calling conventions, right? So why not just use the <span style="font-family:courier new;">.return</span> directive?<br /><br />The reason for this is that the PCT implements blocks (or scopes) as PIR subroutines. Consider the following Squaak code snippet:<br /><blockquote><pre><span style="font-family:courier new;">sub foo() </span><br /><span style="font-family:courier new;"> do</span><br /><span style="font-family:courier new;"> do</span><br /><span style="font-family:courier new;"> return 42</span><br /><span style="font-family:courier new;"> end</span><br /><span style="font-family:courier new;"> end</span><br /><span style="font-family:courier new;">end</span></pre></blockquote><span style="font-family:courier new;"></span>The subroutine <span style="font-family:courier new;">foo</span> translates to three different blocks, or scopes: one for each do-end pair, and one for the subroutine itself. Each block is represented by a PIR subroutine, which are nested (using the PIR <span style="font-family:courier new;">:outer</span> flag, if you were curious). I'll not go into details, because I'm sure this will be explained in more detail by others later on, but I just want to explain the basics here.<br />When a <span style="font-family:courier new;">.return</span> directive is executed by Parrot, it will return to the calling subroutine. As the foo subroutine above consists of three subroutines, the return statement above will return to its outer block (which invokes its nested block), and not to the caller of the <span style="font-family:courier new;">foo</span> subroutine.<br /><br />Instead of using the <span style="font-family:courier new;">.return</span> directive, Parrot will use the exceptions subsystem to implement control constructs such as return statements. Now, as I predicted before, I'm sure someone will explain all this in much more detail, but for now, we just want to get an idea how to actually use all this and implement a return statement. So let's not talk any longer, and look at how to do this.<br /><br />First, we should extend the grammar of Squaak. As the return statement is a statement, add an alternative to the statement rule, like so:<br /><blockquote style="font-family:courier new;"><pre>rule statement {<br /><span style="font-family:courier new;"> ...</span><br /><span style="font-family:courier new;"> | <return_statement> {*} #= return_statement</span><br />}<br /><br />rule return_statement {<br /><span style="font-family:courier new;"> 'return' <expression></span><br /><span style="font-family:courier new;"> {*}</span><br />}<br /></pre></blockquote>In order to allow for syntax like <span style="font-family:courier new;">"x = foo()"</span>, we need to extend the rule for term. Note that sub_call should come before primary. (Once Longest Token Matching is implemented, this is no longer necessary).<br /><blockquote><pre><span style="font-family:courier new;">rule term {</span><br /><span style="font-family:courier new;"> ...</span><br /><span style="font-family:courier new;"> | <sub_call> #= sub_call</span><br /><span style="font-family:courier new;"> | <primary> #= primary</span><br /><span style="font-family:courier new;"> ...</span><br /><span style="font-family:courier new;">}</span><br /></pre></blockquote>Now, that was easy huh? Let's look at the actions. The action method for statement will just dispatch to the action method in the key specified after <span style="font-family:courier new;">#=</span>.<br /><blockquote><pre><span style="font-family:courier new;">method return_statement($/) {</span><br /><span style="font-family:courier new;"> my $expr := $( $<expression> );</span><br /><span style="font-family:courier new;"> make PAST::Op.new( $expr,</span><br /><span style="font-family:courier new;"> :pasttype('return'),</span><br /><span style="font-family:courier new;"> :node($/) );</span><br /><span style="font-family:courier new;">}</span></pre></blockquote><span style="font-family:courier new;"></span>If you read the PCT tutorial, this code should be easy to read. First, we get the result object for the expression. Then we create a new <span style="font-family:courier new;">PAST::Op</span> node, this time of the new pasttype 'return'.<br />Now, you might think this is all, but not quite. We have to specify that the block representing the subroutine is doing the actual returning. This is done using the following line of code in the action method for sub_definition:<br /><blockquote style="font-family: courier new;">$past.control('return_pir');</blockquote>So, now we have implemented the return statement in Squaak, let's see what happens. Rebuild Squaak, and start the Squaak interpreter in interactive mode:<br /><span style="font-family:courier new;"><blockquote>$ ../../parrot squaak.pbc</blockquote></span>Now type:<br /><span style="font-family:courier new;"><blockquote>sub main() return 42 end x = main() print(x)</blockquote></span>You could also store this in a file, and then specify the file when running the Squaak compiler, but this is easier for now. After hitting return (no pun intended), you'll see:<br /><span style="font-family:courier new;"><blockquote>> 42</blockquote></span>Isn't the Parrot Compiler Toolkit a fabulous tool?Anonymousnoreply@blogger.com0tag:blogger.com,1999:blog-2772753380875006713.post-34123748900462107482008-05-31T13:36:00.000-07:002008-05-31T13:38:19.869-07:00P6object: Perl 6 metaclasses for Parrot<!--PageText--><br /><div id='wikitext'><br />A week or so ago I worked on creating a new metaclass library ("P6object") for use by Rakudo and the other compiler tools. It replaces the Protoobject.pbc and other metaclass components that those tools had previously been using. This article provides some background and details about the library.<br /><h2>Background</h2>The P6object library is based heavily on the Perl 6 object model described in <a class='urllink' href='http://dev.perl.org/perl6/doc/design/syn/S12.html' rel='nofollow'>Synopsis 12</a>. Perl 6's default object model looks a lot like a standard class-based model when it's used in typical programming, but it also has some important differences.<br /><br />One key feature of Perl 6's OO model is the concept of "prototype objects", or "protoobjects" for short. A <em>protoobject</em> is an "empty" or undefined instance of a class that proxies as a "generic instance" for the class as a whole. In other words, the protoobject for a class allows us to reason about and calculate what an instance of the class can do without having to have a defined instance of that class. For this reason Synopsis 12 talks about protoobjects as being the "class object" -- i.e., it's the thing you use when you want to talk generically about the class. In fact, Perl 6 doesn't have a mandatory Class type, it's all done with protoobjects and metaclasses (we'll cover metaclasses in a bit).<br /><br />The most common use for a protoobject is to create a new object:<br /><pre> class Dog { <br /> method bark() { say "Woof!"; }<br /> }<br /><br /> my $fido = Dog.new();<br /></pre>Another common use of protoobjects is to test 'isa' or 'does' semantics:<br /><pre> if $fido ~~ Dog { ... }<br /></pre>In the cases above we use the name "Dog" to indicate a class, but whereas Parrot and other languages would take "Dog" to be a Class object that defines the attributes and methods for objects in the class, in Perl 6 the "Dog" symbol above refers to an instance of the Dog class that reports itself as being undefined -- i.e., a protoobject.<br /><br />If you're now thinking "all this protoobject stuff is making things complicated" -- don't worry. Most of the time a Perl 6 programmer won't have to think about protoobjects -- just do the natural thing (as in the examples above) and it all works out correctly.<br /><br />We can use <code>.WHAT</code> on any object to obtain the protoobject for the object's type. One use for a protoobject is to get a stringified form of the (short) name of the type.<br /><pre> say $fido.WHAT; # "Dog\n"<br /></pre>So, now that we know something about protoobjects, what's a metaclass? Well, a <em>metaclass</em> is the compiler's underlying representation of a class. Synopsis 12 doesn't say a lot about how metaclasses work internally, leaving those details up to the implementation. But any time we want to manipulate the class itself, such as adding an attribute or determining the available methods, we use a metaclass to do it. We get to the metaclass of an object by using <code>.HOW</code>:<br /><pre> $fido.HOW.methods() # get the methods list for $fido<br /> Dog.HOW.attributes() # get the attribute list for Dog objects<br /></pre><h2>Using P6object</h2>Okay, with that background in mind, let's look at the P6object implementation. From this point I'll be using PIR for my examples, because that's what I expect most people using P6object will be using. However, it's nearly all method calls and symbol table lookups, so it's relatively easy to follow, and of course one can access the library from NQP or Rakudo.<br /><br />First, to load the library one uses the load_bytecode opcode:<br /><pre> load_bytecode 'P6object.pbc'<br /></pre>Of course, if a program has already loaded PGE or PCT, then the P6object library is already loaded. Once the library has been loaded, we can access the P6metaclass object and use it to create a new class:<br /><pre> .local pmc p6meta<br /> p6meta = get_hll_global 'P6metaclass'<br /> p6meta.'new_class'('Dog', 'attr'=>'legs tail')<br /></pre>This creates a new class called "Dog", and creates attribute slots named "legs" and "tail". Methods for the new class are defined the same way it's done in normal PIR -- decorate a sub in the appropriate namespace with ":method":<br /><pre> .namespace ['Dog']<br /> .sub "bark" :method<br /> say "Woof!"<br /> .end<br /></pre>Once the class is created, we can get its protoobject and use that to create a new instances of the class. So, to do the PIR equivalent of the Perl 6<br /><pre> $fido = Dog.new();<br /> $fido.bark();<br /></pre>one would write in PIR<br /><pre> .local pmc dogproto, fido<br /> dogproto = get_hll_global 'Dog'<br /> fido = dogproto.'new'()<br /> fido.'bark'() # "Woof!\n"<br /></pre>Note that the new class exists as a normal Parrot class -- i.e., one can still create new Dog objects by using the <code>new</code> opcode or the Dog parrot class via <code>get_class</code>. But once a decision is made to use P6object, it may be better to stick with its defined interfaces for metaprogramming operations. More on this below.<br /><br />To create a subclass of an existing class, simply supply a "parent" argument to the <code>new_class</code> method:<br /><pre> ## Perl 6:<br /> ## class Beagle is Dog { ... }<br /> ## $snoopy = Beagle.new();<br /><br /> .local pmc beagleproto, snoopy<br /> p6meta.'new_class'('Beagle', 'parent'=>'Dog')<br /> beagleproto = get_hll_global 'Beagle'<br /> snoopy = beagleproto.'new'()<br /></pre>Classes created using <code>new_class</code> always have <code>P6object</code> as one of the ancestor classes, which defines default <code>.WHAT</code> and <code>.HOW</code> methods for all objects. Thus:<br /><pre> ## Perl 6:<br /> ## say $snoopy.WHAT;<br /><br /> $P0 = snoopy.'WHAT'() # get snoopy's protoobject<br /> $S0 = $P0 # stringify it<br /> say $S0 # "Beagle\n"<br /></pre>Methods such as <code>.isa</code>, <code>.can</code>, and <code>.does</code> are defined on the metaclass for each object (as described in Synopsis 12).<br /><pre> ## Perl 6:<br /> ## $i = $snoopy.HOW.can('bark');<br /> ## $i = $snoopy.HOW.isa('Dog');<br /><br /> $P0 = snoopy.'HOW'() # get snoopy's metaclass<br /> $I0 = $P0.'can'('bark') # see if snoopy can bark<br /> $I0 = $P0.'isa'('Dog') # see if snoopy is a Dog<br /></pre>If the name of a class is segmented using double-colons, then P6object automatically places the protoobject in the appropriate Parrot namespace:<br /><pre> p6meta.'new_class'('NQP::Grammar::Actions')<br /><br /> $P0 = get_hll_global 'NQP::Grammar::Actions' # wrong<br /> $P0 = get_hll_global ['NQP';'Grammar'], 'Actions' # right<br /></pre>So, what do we gain from all of this? First, it provides a Perl 6-like foundation for all of the objects used in the Perl 6-related compiler components, including PCT, PGE, NQP, and Rakudo. Thus, each of these tools knows that the objects coming from another component support the Perl 6 metaprogramming model, which aids consistency. Also, most metaprogramming operations are method based, which means the tools can use a single access paradigm (method calls) to do their metaprogramming, instead of having to work with an irregular set of PIR opcodes with varying operand types.<br /><br />One key aspect of P6object that has particular importance to Rakudo Perl is that P6object can add Perl-6 like roles to Parrot's existing classes and built-in PMC types. For example, Perl 6 expects to work with 'Int', 'Str', and 'Num' objects, but other libraries in Parrot might return values that are 'Integer', 'String', or 'Float' PMCs. Since checking and autoboxing every value could get cumbersome and/or expensive, P6object allows us to give Perl 6 object model behaviors to existing classes. This is done using the 'register' method on P6metaclass:<br /><pre> p6meta.'register'('Float')<br /></pre>This line creates a protoobject for Parrot's built in Float type, and adds <code>.WHAT</code> and <code>.HOW</code> methods to Float objects. The protoobject also gives us a <code>.new</code> method for building Float PMCs:<br /><pre> .local pmc floatproto<br /> floatproto = get_hll_global 'Float'<br /> $P0 = floatproto.'new'()<br /></pre>Of course, the old way of creating Float objects in PIR still works:<br /><pre> $P0 = new 'Float'<br /> $P0 = 6.28318<br /></pre>And, as mentioned above, Floats receive the <code>.WHAT</code> and <code>.HOW</code> methods that all P6objects have:<br /><pre> $P1 = $P0.'WHAT'()<br /> $S1 = $P1<br /> say $S1 # "Float\n"<br /></pre>The "name" option to <code>.register</code> and <code>.new_class</code> causes the protoobject to be created using a different name:<br /><pre> p6meta.'register'('ResizablePMCArray', 'name'=>'List')<br /><br /> .local pmc list<br /> list = new 'ResizablePMCArray' # create a RPA<br /> $P1 = list.'WHAT'() # get the protoobject<br /> $S1 = $P1 # stringify it<br /> say $S1 # "List\n"<br /></pre>This is useful for mapping Parrot's built-in types to HLL-specific class<br />names.<br /><br />Note that registering a class doesn't mean that <code>new "List"</code> will work in PIR, because Parrot still thinks of the class as "ResizablePMCArray". But using the protoobject for List will do what we want:<br /><pre> .local pmc listproto, list<br /> listproto = get_hll_global 'List'<br /> list = listproto.'new'()<br /></pre>We can also register classes to use a specific protoobject instead of creating a new one:<br /><pre> ## create a subclass of Hash called MyHash<br /> p6meta.'new_class'('MyHash', 'parent'=>'Hash')<br /><br /> ## register existing Hash class as being MyHash<br /> .local pmc myhashproto<br /> myhashproto = get_hll_global 'MyHash'<br /> p6meta.'register'('Hash', 'protoobject'=>myhashproto)<br /></pre>This has the result of causing all Parrot Hash objects to report themselves as instances of "MyHash", and to return the same protoobject for 'MyHash' and 'Hash' objects.<br /><br />Finally, the "parent" argument to <code>.register</code> cause the named parent class(es) to be added as parents of the class being registered. If the class being registered is a built-in PMC type or otherwise cannot have parent classes added, then the methods of the parent classes are composed into the class directly.<br /><br />Thus the following causes Hash objects to return the MyHash protoobject and metaclass in response to <code>.WHAT</code> and <code>.HOW</code>, and adds all of the methods of MyHash to the existing Hash PMC type (unless Hash already has such methods).<br /><pre> p6meta.'register'('Hash', 'parent'=>'MyHash', 'protoobject'=>'MyHash')<br /></pre><h2>Summary</h2>The P6object library provides quite a few other features for managing and manipulating classes, and new features such as roles, attribute management, and method exporters are in the works. With these features, P6object provides a robust Perl 6-like interface to Parrot's underlying object model.<br /></div><br /><!--/PageText-->Pmhttp://www.blogger.com/profile/05117950909580615426noreply@blogger.com0tag:blogger.com,1999:blog-2772753380875006713.post-37234944338518054622008-05-20T12:45:00.000-07:002008-05-20T13:11:28.392-07:00Parrot 0.6.2 "Reverse Sublimation" Released!<blockquote><p>They were walking to the Hemlock, the Rooster and the Mice, and<br />the Mice kept looking at one another, questioning.</p><p>"We don't know what the future holds, do we?" said Chauntecleer. The Mice all shook their heads. They knew very little of anything. "If," said Chauntecleer, "I say, <em>if</em> I don't come back again, then you must make this food to last a long, long time. I trust your prudence, don't I?" he asked, and they nodded automatically, but their eyes were very big. "And I trust your integrity, right?" They nodded. "And you are mature, now, and I respect your maturity, isn't that so?" Poor Mice, they nodded and nodded, and they blinked, and they nodded. They looked afraid. "Good," said Chauntecleer. "I know I won't be disappointed."</p><p>In this way he gave each Mouse a manhood. They couldn't talk to him just now, having so much to turn over in their minds. But neither did they cry.</p></blockquote>— <em>The Book of Sorrows</em>, by Walter Wangerin Jr.<br /><p>On behalf of the Parrot team, I'm proud to announce Parrot 0.6.2<br />"Reverse Sublimation." <a href="http://parrotcode.org/">Parrot </a>is a virtual machine aimed at running all dynamic languages.</p>Parrot 0.6.2 is available via <a href="http://search.cpan.org/dist/parrot">CPAN</a> (soon), or <a href="http://parrotcode.org/source.html">follow the download instructions</a>. For those who would like to develop on Parrot, or help develop Parrot itself, we recommend using <a href="http://subversion.tigris.org/">Subversion</a> or <a href="http://svk.bestpractical.com/">SVK</a> on <a href="https://svn.perl.org/parrot/trunk/">our source code repository</a> to getthe latest and best Parrot code.<br /><p>Parrot 0.6.2 News:<br /></p><ul><li>Specification<br /><ul><li>updated and launched pdd28_strings.pod<br /></li><li>updated pdd19_pir.pod<br /></li></ul></li><li>Implementation<br /><ul><li>added implementation of Rational PMC<br /></li><li>simplified ops control flow syntax<br /></li><li>enabled backtrace on non-glibc platforms too<br /></li><li>improved some PIR error reporting<br /></li><li>removed user stack opcodes (save, restore, lookback, entrytype, depth, rotate_up)<br />(NOTE: This was scheduled to occur after 0.7.0, moved up to this release)<br /></li><li>removed register stack, saveall, and restoreall opcodes<br /></li><li>removed various deprecated features and unused code<br /></li></ul></li><li>Languages<br /><ul><li>Amber: retired<br /></li><li>C99: grammar updated<br /></li><li>Cardinal: resurrected, method calls and do blocks work now<br /></li><li>Eclectus: use NQP as PAST generating code<br /></li><li>Lua:<br /><ul><li>added big number library<br /></li><li>updated to match PGE changes<br /></li><li>added a bytecode disassembler & a Lua 5.1 VM bytecode translator<br /></li></ul></li><li>Pheme: updated to match PGE/PCT changes<br /></li><li>Plumhead:<br /><ul><li>use NQP as PAST generating code<br /></li><li>use riaxpander for macro expansion<br /></li></ul></li><li>Rakudo:<br /><ul><li>updated ROADMAP<br /></li><li>conditional and loop statement modifiers<br /></li><li>lots of class, object, role, and method improvements<br /></li><li>Str increment and decrement<br /></li><li>improved spectest reporting<br /></li><li>type checking on assignment<br /></li><li>regexes and grammars<br /></li><li>undef and self<br /></li><li>placeholder vars<br /></li></ul></li><li>Squaak: added to repository<br /></li><li>TAP: retired<br /></li></ul></li><li>Compilers<br /><ul><li>PGE: updated to match Synopsis 5, deprecated features removed<br /></li><li>PCT:<br /><ul><li>improve handling of register types, conversion between registers<br /></li><li>improved error diagnostics<br /></li><li>add 'arity' to for loops<br /></li></ul></li></ul></li><li>Configuration<br /><ul><li>added step auto::opengl<br /></li><li>added step gen::opengl<br /></li><li>added step gen::call_list<br /></li></ul></li><li>Miscellaneous<br /><ul><li>still more optimizations and performance improvements, especially in GC<br /></li><li>new libraries: OpenGL/GLU/GLUT bindings (small subset working)<br /></li><li>new dump_pbc.pl utility: PBC disassembly/source code weaver<br /></li><li>improved C++ compiler support<br /></li><li>optimized builds work again<br /></li></ul></li></ul><p>Gracias to all our contributors for making this possible, and our sponsors for supporting this project. The next scheduled release will occur on 17 June 2008.<br /></p><p>Enjoy!</p>chromatichttp://www.blogger.com/profile/16445595800382061121noreply@blogger.com0tag:blogger.com,1999:blog-2772753380875006713.post-59970719161747796052008-05-13T12:08:00.000-07:002008-05-13T12:11:53.235-07:00Parrot Bug Day, 17 May 2008The next monthly Parrot release will take place next Tuesday, 20 May 2008. In preparation for the release, we're holding yet another monthly Bug Day, all day Saturday 17 May. Parrot hackers, contributors, fans, and hangers-on will gather in #parrot on irc.perl.org to discuss proposed patches, verify and close bugs, and help potential new contributors download, configure, build, and understand Parrot and languages hosted in the Parrot repository. If you're interested in Parrot, have some free time, and want to get your hands a little bit dirty with code, please join us. You don't need to know how to program C or PIR or even Perl 5, but knowing how to download code from a public Subversion repository and build a C program will be very helpful.chromatichttp://www.blogger.com/profile/16445595800382061121noreply@blogger.com0tag:blogger.com,1999:blog-2772753380875006713.post-51651339262558303452008-05-08T06:06:00.000-07:002008-05-08T06:44:02.330-07:00700 Ticket Challenge...… whoops, you missed it.<br /><br /><a href="http://www.wgz.org/chromatic/">chromatic</a> <a href="http://www.parrotcode.org/misc/parrotsketch-logs/irclog.parrotsketch-200805/irclog.parrotsketch.20080506">challenged parrotteers on Tuesday</a> to get the number of open/new tickets in <a href="https://rt.perl.org/rt3/">RT</a> down to 700 before he cuts the monthly release on May 20th. As of now, we're down to 698, twelve days early!<br /><br />This is still a lot of tickets, but there's still a lot of simple cleanup that can be done.<br /><ul><li>Bug reports on old versions of parrot. We are now releasing code every month, and there's a good chance that a bug reported on a previous version no longer exists, or has changed presentation. Try to duplicate the issue with svn-latest or the most recent dev release, and add a note indicating if you could for your platform/revision.<br /></li><li>Apply patches! If you're not sure if a patch should be applied, you can still help by trying to apply it to trunk and see if it even applies cleanly; if not, reply to the requester (and the parrot mailing list) asking them to rebase their patch and resubmit it.<br /></li><li>Triage TODO items. Many of the TODO items came from XXX comments in the code. Check to see if this is an actual coding task, or something that can be solved by a simple documentation patch.</li><li>Close tickets! Sometimes a ticket will end up getting resolved via comments in email (saved as history on the ticket), but a bug admin simply hasn't gotten around to closing the ticket yet. If you're not a bug admin, you can ping the <span style="font-family:courier new;">parrot-porters</span> mailing list at <span style="font-family:courier new;">perl.org</span> or let us know on IRC (<span style="font-family:courier new;">#parrot on irc.perl.org</span>)<br /></li></ul>Keeping a better handle on what we have in our issue list helps us know how much work is left before we get to 1.0.<br /><br />So, even if you're not comfortable with hacking on parrot guts, consider helping out with the queue. This can free up those hackers to spend more time implementing features and fixing bugs.<br /><br />And if you are comfortable, feel free to grab a bug and dig in!<br /><br />Thanks!Cokehttp://www.blogger.com/profile/01745512237217656642noreply@blogger.com1tag:blogger.com,1999:blog-2772753380875006713.post-51224798118843899622008-04-08T17:54:00.000-07:002008-04-21T13:23:17.799-07:00Output of Episode 9's Game of LifeIn <a href="http://www.parrotblog.org/2008/03/episode-9-wrap-up-and-conclusion.html">Episode 9</a>, the source code for John Conway's Game of Life was posted. If you don't feel like doing exercises or just want to see what it looks like without doing any trouble, here's what it looks like (this is life generation 9).<br /><blockquote style="font-family: courier new;">-----------------------------------------<br />-----------------------------------------<br />-----------------------------------------<br />-----O-----------------------------------<br />----OO-----------------------------------<br />--OO--O----------------------------------<br />-----OO----------------------------------<br />--OOOOO------------------OOO-------------<br />------------------------O---O------------<br />-----------------------O-----O-----------<br />----------------------O---O---O----------<br />----------------------O--O-O--O----------<br />----------------------O---O---O----------<br />-----------------------O-----O-----------<br />------------------------O---O------------<br />-------------------------OOO-------------<br />-----------------------------------------<br />-----------------------------------------<br />-----------------------------------------<br />-----------------------------------------<br />-----------------------------------------<br /><br />Life - generation: 9<br /></blockquote>But really, it doesn't compare to seeing this program run on Parrot :-)<br /><br /><span style="font-weight: bold;">Update: </span>The sources for Squaak have been added to the Parrot repository. Update your local copy today, run Configure, build Squaak, and run <span style="font-family: courier new;">"../../parrot squaak.pbc examples/life.sq"</span>.Anonymousnoreply@blogger.com0tag:blogger.com,1999:blog-2772753380875006713.post-59527122153976066812008-04-08T07:08:00.001-07:002008-04-08T07:13:44.509-07:00Solutions to the PCT Tutorial ExercisesBelow you can find links to the solutions to the exercises of the PCT tutorial.<br />Episodes 1 and 2 didn't have any exercises.<br /><br /><ol><li><a href="http://www.parrotblog.org/2008/03/solutions-to-exercises-in-episode-3.html">Episode 3</a></li><li><a href="http://www.parrotblog.org/2008/04/solutions-to-exercises-in-episode-4.html">Episode 4</a></li><li><a href="http://www.parrotblog.org/2008/04/solutions-to-exercises-in-episode-5.html">Episode 5</a></li><li><a href="http://www.parrotblog.org/2008/04/solutions-to-exercises-in-episode-6.html">Episode 6</a></li><li><a href="http://www.parrotblog.org/2008/04/solutions-to-exercises-of-episode-7.html">Episode 7</a></li><li><a href="http://www.parrotblog.org/2008/04/solutions-to-exercises-of-episode-8.html">Episode 8</a></li><li><a href="http://www.parrotblog.org/2008/04/output-of-episode-9s-game-of-life.html">Episode 9</a><br /></li></ol>Anonymousnoreply@blogger.com0