tag:blogger.com,1999:blog-27727533808750067132008-07-02T11:06:35.574-07:00ParrotParrothttp://www.blogger.com/profile/04219797441113470313noreply@blogger.comBlogger28125tag: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.comtag: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.comtag: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.comtag: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.comtag: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.comtag: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?kjshttp://www.blogger.com/profile/18109327874846144778noreply@blogger.comtag: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.comtag: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.comtag: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.comtag: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.comtag: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>.kjshttp://www.blogger.com/profile/18109327874846144778noreply@blogger.comtag: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>kjshttp://www.blogger.com/profile/18109327874846144778noreply@blogger.comtag:blogger.com,1999:blog-2772753380875006713.post-32956808771039694982008-04-08T06:45:00.001-07:002008-05-12T02:56:03.919-07:00Solutions to the Exercises of Episode 81. We've shown how to implement keyed variable access for arrays, by implementing the action method for index. The same principle can be applied to keyed access for hashtables. Implement the action method for key.<br /><blockquote style="font-family: courier new;"><pre>method key($/) {<br />my $key := $( $<expression> );<br /><br />make PAST::Var.new( $key, :scope('keyed'),<br /> :vivibase('Hash'),<br /> :viviself('Undef'),<br /> :node($/) );<br />}</pre></blockquote>2. Implement the action methods for <span style="font-family:courier new;">array_constructor</span> and <span style="font-family:courier new;">hash_constructor</span>. Use a <span style="font-family:courier new;">PAST::Op</span> node and set the pasttype to <span style="font-family:courier new;">'call'</span>. Use the "name" attribute to specify the names of the subs to be invoked (e.g., <span style="font-family:courier new;">:name("!array")</span> ). Note that all hash fields must be passed as named arguments. Check out PDD26 for doing this, and look for a "named " method.<br /><span style="font-family:courier new;"></span><blockquote><pre><span style="font-family:courier new;">method named_field($/) {</span><br /><span style="font-family:courier new;"> my $past := $( $<expression> );</expression></span><br /><span style="font-family:courier new;"> my $name := $( $<string_constant> );</string_constant></span><br /><span style="font-family:courier new;"> ## the passed expression is in fact a named argument,</span><br /><span style="font-family:courier new;"> ## use the named() accessor to set that name.</span><br /><span style="font-family:courier new;"> $past.named($name);</span><br /><span style="font-family:courier new;"> make $past;</span><br /><span style="font-family:courier new;">}</span><br /><br /><span style="font-family:courier new;">method array_constructor($/) {</span><br /><span style="font-family:courier new;"> ## use the parrot calling conventions to </span><br /><span style="font-family:courier new;"> ## create an array, </span><br /><span style="font-family:courier new;"> ## using the "anonymous" sub !array </span><br /><span style="font-family:courier new;"> ## (which is not a valid Squaak name)</span><br /><span style="font-family:courier new;"> my $past := PAST::Op.new( :name('!array'), </span><br /><span style="font-family:courier new;"> :pasttype('call'), </span><br /><span style="font-family:courier new;"> :node($/) );</span><br /><span style="font-family:courier new;"> for $<expression> {</span><br /><span style="font-family:courier new;"> $past.push($($_));</span><br /><span style="font-family:courier new;"> }</span><br /><span style="font-family:courier new;"> make $past;</span><br /><span style="font-family:courier new;">}</span><br /><br /><span style="font-family:courier new;">method hash_constructor($/) {</span><br /><span style="font-family:courier new;"> ## use the parrot calling conventions to </span><br /><span style="font-family:courier new;"> ## create a hash, using the "anonymous" sub </span><br /><span style="font-family:courier new;"> ## !hash (which is not a valid Squaak name)</span><br /><span style="font-family:courier new;"> my $past := PAST::Op.new( :name('!hash'), </span><br /><span style="font-family:courier new;"> :pasttype('call'), </span><br /><span style="font-family:courier new;"> :node($/) );</span><br /><span style="font-family:courier new;"> for $<named_field> {</span><br /><span style="font-family:courier new;"> $past.push($($_));</span><br /><span style="font-family:courier new;"> }</span><br /><span style="font-family:courier new;"> make $past;</span><br /><span style="font-family:courier new;">}</span><br /></pre></blockquote>3. We'd like to add a little bit of syntactic sugar for accessing hashtable keys. Instead of writing <span style="font-family:courier new;">foo{"key"}</span>, I'd like to write <span style="font-family:courier new;">foo.key</span>. Of course, this only works for keys that do not contain spaces and such. Add the appropriate grammar rule (call it "member") that enables this syntax, and write the associated action method. Make sure this member name is converted to a string.<br />Hint: use a <span style="font-family:courier new;">PAST::Val</span> node for the string conversion.<br /><blockquote style="font-family: courier new;"><pre>rule postfix_expression {<br />| <key> {*} #= key<br />| <member> {*} #= member<br />| <index> {*} #= index<br />}<br /><br />rule member {<br />'.' <identifier><br />{*}<br />}<br /><br />method member($/) {<br />my $member := $( $<identifier> );<br />## x.y is syntactic sugar for x{"y"},<br />## so stringify the identifier:<br />my $key := PAST::Val.new( :returns('String'),<br /> :value($member.name()),<br /> :node($/) );<br /><br />## the rest of this method is the same<br />## as method key() above.<br />make PAST::Var.new( $key, :scope('keyed'),<br /> :vivibase('Hash'),<br /> :viviself('Undef'),<br /> :node($/) );<br />}<br /></pre></blockquote>kjshttp://www.blogger.com/profile/18109327874846144778noreply@blogger.comtag:blogger.com,1999:blog-2772753380875006713.post-76886575176773941592008-04-08T06:32:00.000-07:002008-04-08T06:43:21.071-07:00Solutions to the Exercises of Episode 71. Currently, Squaak only has grammar rules for integer and string constants, not floating point constants. Implement this grammar rule. A floating-point number consists of zero or more digits, followed by a dot and at least one digit, or, at least one digit followed by a dot and any number of digits. Examples are: 42.0, 1., .0001. There may be no whitespace between the individual digits and the dot. Make sure you understand the difference between a "rule" and a "token".<br /><blockquote><span style="font-family: courier new;"><pre>token float_constant {</span><br /><span style="font-family: courier new;"> [</span><br /><span style="font-family: courier new;"> | \d+ '.' \d*</span><br /><span style="font-family: courier new;"> | \d* '.' \d+</span><br /><span style="font-family: courier new;"> ]</span><br /><span style="font-family: courier new;"> {*}</span><br /><span style="font-family: courier new;">}</span><br /></pre></blockquote>2. Implement the missing operators: (binary) <span style="font-family: courier new;">"-", "<=", ">=", "==", "!=", "/", "%", "or"<br /></span><br />For sake of completeness (and easy copy-paste for you), here's the list of operator declarations as I wrote them for Squaak:<br /><blockquote style="font-family: courier new;"><pre>rule expression is optable { ... }<br /><br />proto 'infix:or' is precedence('1')<br /> is pasttype('unless') { ... }<br />proto 'infix:and' is tighter('infix:or')<br /> is pasttype('if') { ... }<br /><br />proto 'infix:<' is tighter('infix:and') { ... }<br />proto 'infix:<=' is equiv('infix:<') { ... }<br />proto 'infix:>' is equiv('infix:<') { ... }<br />proto 'infix:>=' is equiv('infix:<') { ... }<br />proto 'infix:==' is equiv('infix:<') { ... }<br />proto 'infix:!=' is equiv('infix:<') { ... }<br /><br />proto 'infix:+' is tighter('infix:<')<br /> is pirop('n_add') { ... }<br />proto 'infix:-' is equiv('infix:+') <br /> is pirop('n_sub') { ... }<br /><br />proto 'infix:..' is equiv('infix:+') <br /> is pirop('n_concat') { ... }<br /><br />proto 'infix:*' is tighter('infix:+') <br /> is pirop('n_mul') { ... }<br />proto 'infix:%' is equiv('infix:*') <br /> is pirop('n_mod') { ... }<br />proto 'infix:/' is equiv('infix:*') <br /> is pirop('n_div') { ... }<br /><br />proto 'prefix:not' is tighter('infix:*') <br /> is pirop('n_not') { ... }<br />proto 'prefix:-' is tighter('prefix:not')<br /> is pirop('n_neg') { ... }<br /><br />proto 'term:' is tighter('prefix:-') <br /> is parsed(&term) { ... }<br /><br /></pre></blockquote>kjshttp://www.blogger.com/profile/18109327874846144778noreply@blogger.comtag:blogger.com,1999:blog-2772753380875006713.post-25593479392574086562008-04-03T08:40:00.000-07:002008-05-12T02:46:59.118-07:00Solutions to the Exercises in Episode 6<div style="text-align: justify;">Without further ado, the solution to the exercise in <a href="http://www.parrotblog.org/2008/03/episode-6-scope-and-subroutines.html">Episode 6</a>:<br /><br />1. By now you should have a good idea on the implementation of scope in Squaak. We haven't implemented the for-statement yet, as it needs proper scope handling to implement. Implement this. Check out <a href="http://www.parrotblog.org/2008/03/episode-3-squaak-details-and-first.html">Episode 3</a> for the BNF rules that define the syntax of the for-statement. When implementing it, you will run into the same issue as we did when implementing subroutines and parameters. Use the same trick for the implementation of the for-statement.<br /><br />First, let us look at the BNF of the for-statement:<br /><blockquote><pre>for-statement ::= 'for' for-init ',' expression [step]<br /><span style="font-family:courier new;"> 'do'</span><br /><span style="font-family:courier new;"> block</span><br /><span style="font-family:courier new;"> 'end'</span><br /><br />step ::= ',' expression<br /><br />for-init ::= 'var' identifier '=' expression<br /></pre></blockquote>It's pretty easy to convert this to Perl 6 rules:<br /><blockquote><pre><span style="font-family:courier new;">rule for_statement {</span><br /><span style="font-family:courier new;"> 'for' <for_init> ',' <expression> <step>?</span><br /><span style="font-family:courier new;"> 'do' <statement>* 'end'</span><br /><span style="font-family:courier new;"> {*}</span><br /><span style="font-family:courier new;">}</span><br /><br /><span style="font-family:courier new;">rule step {</span><br /><span style="font-family:courier new;"> ',' <expression></span><br /><span style="font-family:courier new;"> {*}</span><br /><span style="font-family:courier new;">}</span><br /><br /><span style="font-family:courier new;">rule for_init {</span><br /><span style="font-family:courier new;"> 'var' <identifier> '=' <expression></span><br /><span style="font-family:courier new;"> {*}</span><br /><span style="font-family:courier new;">}</span><br /></pre></blockquote>Pretty easy huh? Let's take a look at the semantics. A for-loop is just another way to write a while loop, but much easier in certain cases. This:<br /><blockquote style="font-family: courier new;"><pre>for var <ident> = <expr1>, <expr2>, <expr3> do<br /> <statement>*<br />end</pre></blockquote>corresponds to:<br /><blockquote style="font-family: courier new;"><pre>do<br /> var <ident> = <expr1><br /> while <ident> <= <expr2> do<br /> <statement>*<br /> <ident> = <ident> + <expr3><br /> end<br />end</pre></blockquote>If <expr3> is absent, it defaults to the value "1". Note that the step expression (expr3) should be positive; the loop condition contains a "<span style="font-family:courier new;"><=</span>" operator. When you specify a negative step expression, the loop variable will only decrease in value, which will never make the loop condition false (unless it overflows, but that's a different issue; this might even raise an exception in Parrot; this I do not know). Allowing negative step expressions introduces more complexity, which I felt was not worth the trouble for this tutorial language.<br /><br />Note that the loop variable <span style="font-family:courier new;"><ident></span> is local to the for loop; this is expressed in the equivalent while loop by the surrounding <span style="font-family:courier new;">do/end</span> pair: a new do/end pair defines a new (nested) scope; after the "end" keyword, the loop variable is no longer visible.<br /><br />Let's implement the action method for the for-statement. As was mentioned in the exercise description, we're dealing with the same situation as with subroutine parameters. In this case, we're dealing with the loop variable, which is local to the for-statement. Let's check out the rule for for_init:<br /><blockquote style="font-family: courier new;"><pre>method for_init($/) {<br /><span style="font-family:courier new;"> our $?BLOCK;</span><br /><span style="font-family:courier new;"> our @?BLOCK;</span><br /><br /><span style="font-family:courier new;"> ## create a new scope here, so that we can</span><br /><span style="font-family:courier new;"> ## add the loop variable</span><br /><span style="font-family:courier new;"> ## to this block here, which is convenient.</span><br /><span style="font-family:courier new;"> $?BLOCK := PAST::Block.new( :blocktype('immediate'),</span><br /><span style="font-family:courier new;"> :node($/) );</span><br /><span style="font-family:courier new;"> @?BLOCK.unshift($?BLOCK);</span><br /><br /><span style="font-family:courier new;"> my $iter := $( $<identifier> );</span><br /><span style="font-family:courier new;"> ## set a flag that this identifier is being declared</span><br /><span style="font-family:courier new;"> $iter.isdecl(1);</span><br /><span style="font-family:courier new;"> $iter.scope('lexical');</span><br /><span style="font-family:courier new;"> ## the identifier is initialized with this expression</span><br /><span style="font-family:courier new;"> $iter.viviself( $( $<expression> ) );</span><br /><br /><span style="font-family:courier new;"> ## enter the loop variable into the symbol table.</span><br /><span style="font-family:courier new;"> $?BLOCK.symbol($iter.name(), :scope('lexical'));</span><br /><br /><span style="font-family:courier new;"> make $iter;</span><br />}</pre></blockquote><br />So, just as we created a new PAST::Block for the subroutine in the action method for parameters, we create a new PAST::Block for the for-statement in the action method that defines the loop variable. (Guess why we made for-init a subrule, and didn't put in "var <ident&gt = <expression>" in the rule of for-statement). This block is the place to live for the loop variable. The loop variable is declared, initialized using the viviself attribute, and entered into the new block's symbol table. Note that after creating the new PAST::Block object, we put it onto the stack scope.<br /><br />Now, the action method for the for statement is quite long, so I'll just embed my comments, which makes reading it easier.<br /><blockquote style="font-family: courier new;"><pre>method for_statement($/) {<br /><span style="font-family:courier new;"> our $?BLOCK;</span><br /><span style="font-family:courier new;"> our @?BLOCK</span><span style="font-family:courier new;">;<br /></span></pre></blockquote>First, get the result object of the for statement initialization rule; this is the PAST::Var object, representing the declaration and initialization of the loop variable.<br /><pre><span style="font-family:courier new;"> my $init := $( $<for_init> );</span></pre>Then, create a new node for the loop variable. Yes, another one (besides the one that is currently contained in the PAST::Block). This one is used when the loop variable is updated at the end of the code block (each iteration). The difference with the other one, is that it doesn't have the isdecl flag, and it doesn't have a viviself clause, which would result in extra instructions checking whether the variable is null (and we know it's not, because we initialize the loop variable).<br /><pre><span style="font-family:courier new;"> ## cache the name of the loop variable</span><br /><span style="font-family:courier new;"> my $itername := $init.name();</span><br /><span style="font-family:courier new;"> my $iter := PAST::Var.new( :name($itername),</span><br /><span style="font-family:courier new;"> :scope('lexical'),</span><br /><span style="font-family:courier new;"> :node($/) );</span><br /></pre>Now, retrieve the PAST::Block node from the scope stack, and push all statement PAST nodes onto it.<br /><pre><span style="font-family:courier new;"> ## the body of the loop consists of the statements written by the user and</span><br /><span style="font-family:courier new;"> ## the increment instruction of the loop iterator.</span><br /><br /><span style="font-family:courier new;"> my $body := @?BLOCK.shift();</span><br /><span style="font-family:courier new;"> $?BLOCK := @?BLOCK[0];</span><br /><span style="font-family:courier new;"> for $<statement> {</span><br /><span style="font-family:courier new;"> $body.push($($_));</span><br /><span style="font-family:courier new;"> }</span><span style="font-family:courier new;"> </span></pre>If there was a step, we use that value; otherwise, we use assume a default step size of "1".<br />Negative step sizes won't work, but if you Feel Lucky, you could go ahead and try. It's not that hard, it's just a lot of work, and I'm too lazy for that now.... ehm, I mean, I leave it as the proverbial exercise to the reader.<span style="font-family:courier new;"></span><br /><pre><span style="font-family:courier new;"> my $step;</span><br /><span style="font-family:courier new;"> if $<step> {</span><br /><span style="font-family:courier new;"> my $stepsize := $( $<step>[0] );</span><br /><span style="font-family:courier new;"> $step := PAST::Op.new( $iter, $stepsize, :pirop('add'), :node($/) );</span><br /><span style="font-family:courier new;"> }</span><br /><span style="font-family:courier new;"> else { ## default is increment by 1</span><br /><span style="font-family:courier new;"> $step := PAST::Op.new( $iter,</span><br /><span style="font-family:courier new;"> :pirop('inc'),</span><br /><span style="font-family:courier new;"> :node($/) );</span><br /><span style="font-family:courier new;"> }</span><br /><span style="font-family:courier new;"><br /></span></pre>The incrementing of the loop variable is part of the loop body, so add the incrementing statement to $body.<br /><pre><span style="font-family:courier new;"> $body.push($step);</span><span style="font-family:courier new;"><br /></span></pre>The loop condition uses the "<=" operator, and compares the loop variable with the maximum value that was specified.<br /><pre><span style="font-family:courier new;"> ## while loop iterator <= end-expression</span><br /><span style="font-family:courier new;"> my $cond := PAST::Op.new( $iter, $( $<expression> ),</span><br /><span style="font-family:courier new;"> :name('infix:<=') );</span><br /><span style="font-family:courier new;"><br /></span></pre>Now we have the PAST for the loop condition and the loop body, so now create a PAST to represent the (while) loop.<br /><pre><span style="font-family:courier new;"> my $loop := PAST::Op.new( $cond, $body,</span><br /><span style="font-family:courier new;"> :pasttype('while'),</span><br /><span style="font-family:courier new;"> :node($/) );</span><br /><span style="font-family:courier new;"><br /></span></pre>Finally, the initialization of the loop variable should go before the loop itself, so create a PAST::Stmts node to do this:<br /><pre><span style="font-family:courier new;"> make PAST::Stmts.new( $init, $loop,</span><br /><span style="font-family:courier new;"> :node($/) );</span><br />}</pre> <br />Wow, we've done it! This was a good example of how to implement a non-trivial statement type using PAST.<br /></div>kjshttp://www.blogger.com/profile/18109327874846144778noreply@blogger.comtag:blogger.com,1999:blog-2772753380875006713.post-74491365511145562132008-04-03T00:54:00.000-07:002008-04-03T08:02:07.393-07:00Solutions to the Exercises in Episode 5<div style="text-align: justify;">1. In this episode, we changed the action method for the TOP rule; it is now invoked twice, once at the beginning of the parse, once at the end of the parse. The block rule, which defines a block to be a series of statements, represents a new scope. This rule is used in for instance if-statement (the then-part and else-part), while-statement (the loop body) and others. Update the parse action for block so it is invoked twice; once before parsing the statements, during which a new PAST::Block is created and stored onto the scope stack, and once after parsing the statements, during which this PAST node is set as the result object. Make sure $?BLOCK is always pointing to the current block. In order to do this exercise correctly, you should understand well what the shift and unshift methods do, and why we didn't implement methods to push and pop, which are more appropriate words in the context of a (scope) stack.<br /><br /><span style="font-size:130%;">Keeping the Current block up to date</span><br />Sometimes we need to access the current block's symbol table. In order to be able to do so, we need a reference to the "current block". We do this by declaring a package variable called "$?BLOCK", declared with "our" (as opposed with "my"). This variable will always point to the "current" block. As blocks can nest, we use a "stack", on which newly created blocks are stored.<br />Whenever a new block is created, we assign this to $?BLOCK, and store it onto the stack, so that the next time a new block is created, the "old" current block isn't lost. Whenever a scope is closed, we pop off the current block from the stack, and restore the previous "current" block.<br /><br /><span style="font-size:130%;">Why unshift/shift and not push/pop?</span><br />When we're talking about stacks, it would seem logical to talk about stack operations such as "push" and "pop". Instead, we use the operations "unshift" and "shift". If you're not a Perl programmer (such as myself), these names might not make sense. However, it's pretty easy. Instead of pushing a new object onto the "top" of the stack, you unshift objects onto this stack. Just see it as an old school bus, with only one entrance (at the front of the bus). Pushing a new person means taking the first free seat when entering, while unshifting a new person means everybody moves (shifts) one place to the back, so the new person can sit in the front seat. You might think this is not as efficient (more stuff is moved around), but that's not really true (actually: I guess (and certainly hope) the shift and unshift operations are implemented more effectively than the bus metaphor; I don't know how it is implemented).<br /><br />So why unshift/shift, and not push/pop? When restoring the previous "current block", we need to know exactly where it is (what position). It would be nice to be able to always refer to the "first passenger on the bus", instead of the last person. We know how to reference the first passenger (it's on seat no. 0 (it was designed by an IT guy)); we don't really know what is the seat no. of the last person: s/he might sit in the middle, or at the back.<br /><br />I hope it's clear what I mean here... otherwise, have a look at the code, and try to figure out what's happening:<br /><blockquote><pre><span style="font-family:courier new;"><span style="font-family:courier new;">method block($/, $key) {</span></span><span style="font-family:courier new;"> <br /> our $?BLOCK;<br /> our @?BLOCK;<br /> if $key eq 'open' {</span><br /><span style="font-family:courier new;"> $?BLOCK := PAST::Block.new(<br /> :blocktype('immediate'), </span><br /><span style="font-family:courier new;"> :node($/) );<br /> @?BLOCK.unshift($?BLOCK);<br /></span><span style="font-family:courier new;"> }</span><br /><span style="font-family:courier new;"> else {</span><br /><span style="font-family:courier new;"> my $past := @?BLOCK.shift();</span><br /><span style="font-family:courier new;"> $?BLOCK := @?BLOCK[0];</span><br /><br /><span style="font-family:courier new;"> for $<statement> {</span><br /><span style="font-family:courier new;"> $past.push( $( $_ ) );</span><br /><span style="font-family:courier new;"> }</span><br /><span style="font-family:courier new;"> make $past;</span><br /><span style="font-family:courier new;"> }<br />} </span><br /></pre></blockquote></div>kjshttp://www.blogger.com/profile/18109327874846144778noreply@blogger.comtag:blogger.com,1999:blog-2772753380875006713.post-48628755631017895792008-04-01T01:49:00.000-07:002008-04-03T08:10:19.625-07:00Solutions to the Exercises in Episode 4<div style="text-align: justify;">These are the solutions to the exercises in <a href="http://www.parrotblog.org/2008/03/episode-4-past-nodes-and-more.html">Episode 4</a> of the Parrot Compiler Tools tutorial.<br /><br />1. We showed how the if-statement was implemented. The while-statement and try-statement are very similar. Implement these. Check out pdd26 to see what PAST::Op nodes you should create.<br /><br />The while-statement is straightforward:<br /><blockquote face="courier new"><pre>method while_statement($/) {<br /><span style="font-family:courier new;"> my $cond := $( $<expression> );</span><br /><span style="font-family:courier new;"> my $body := $( $<block> );</span><br /><span style="font-family:courier new;"> make PAST::Op.new( $cond, $body,</span><br /><span style="font-family:courier new;"> :pasttype('while'),</span><br /><span style="font-family:courier new;"> :node($/) );</span><br />}<br /></pre></blockquote>The try-statement is a bit more complex. Here are the grammar rules and action methods.<br /><blockquote style="font-family: courier new;"><pre>rule try_statement {<br /><span style="font-family:courier new;"> 'try' $<try>=<block></span><br /><span style="font-family:courier new;"> 'catch' <exception></span><br /><span style="font-family:courier new;"> $<catch>=<block><br /> 'end'<br /></span><span style="font-family:courier new;"> {*}</span><br />}<br /><br />rule exception {<br /><span style="font-family:courier new;"> <identifier></span><br /><span style="font-family:courier new;"> {*}</span><br />}<br /><br />method try_statement($/) {<br /><span style="font-family:courier new;"> ## get the try block</span><br /><span style="font-family:courier new;"> my $try := $( $<try> );</span><br /><br /><span style="font-family:courier new;"> ## create a new PAST::Stmts node for</span><br /><span style="font-family:courier new;"> ## the catch block; note that no</span><br /><span style="font-family:courier new;"> ## PAST::Block is created, as this</span><br /><span style="font-family:courier new;"> ## currently has problems with the</span><br /><span style="font-family:courier new;"> ## exception object. For now this will</span><br /><span style="font-family:courier new;"> ## do.</span><br /><span style="font-family:courier new;"> my $catch := PAST::Stmts.new( :node($/) );</span><br /><span style="font-family:courier new;"> $catch.push( $( $<catch> ) );</span><br /><br /><span style="font-family:courier new;"> ## get the exception identifier;</span><br /><span style="font-family:courier new;"> ## set a declaration flag, the scope,</span><br /><span style="font-family:courier new;"> ## and clear the viviself attribute.</span><br /><span style="font-family:courier new;"> my $exc := $( $<exception> );</span><br /><span style="font-family:courier new;"> $exc.isdecl(1);</span><br /><span style="font-family:courier new;"> $exc.scope('lexical');</span><br /><span style="font-family:courier new;"> $exc.viviself(0);</span><br /><br /><span style="font-family:courier new;"> ## generate instruction to retrieve</span><br /><span style="font-family:courier new;"> ## the exception objct (and the</span><br /><span style="font-family:courier new;"> ## exception message, that is passed</span><br /><span style="font-family:courier new;"> ## automatically in PIR, this is stored</span><br /><span style="font-family:courier new;"> ## into $S0 (but not used).</span><br /><span style="font-family:courier new;"> my $pir := " .get_results (%r, $S0)\n"</span><br /><span style="font-family:courier new;"> ~ " store_lex '" ~ $exc.name()</span><br /><span style="font-family:courier new;"> ~ "', %r";</span><br /><br /><span style="font-family:courier new;"> $catch.unshift( PAST::Op.new(</span><br /><span style="font-family:courier new;"> :inline($pir),</span><br /><span style="font-family:courier new;"> :node($/) ) );</span><br /><br /><span style="font-family:courier new;"> ## do the declaration of the exception</span><br /><span style="font-family:courier new;"> ## object as a lexical here:</span><br /><span style="font-family:courier new;"> $catch.unshift( $exc );</span><br /><br /><span style="font-family:courier new;"> make PAST::Op.new( $try, $catch,</span><br /><span style="font-family:courier new;"> :pasttype('try'),</span><br /><span style="font-family:courier new;"> :node($/) );</span><br />}<br /><br />method exception($/) {<br /><span style="font-family:courier new;"> our $?BLOCK;</span><br /><span style="font-family:courier new;"> my $past := $( $<identifier> );</span><br /><span style="font-family:courier new;"> $?BLOCK.symbol( $past.name(), :scope('lexical') );</span><br /><span style="font-family:courier new;"> make $past;</span><br />}<br /></pre></blockquote><br />Instead of putting "identifier" after the "catch" keyword, we made it a separate rule, with its own action method. This allows us to insert the identifier into the symbol table of the current block (the try-block), before the catch block is parsed.<br /><br />First the PAST node for the try block is retrieved. Then, the catch block is retrieved, and stored into a <span style="font-family:courier new;">PAST::Stmts</span> node. This is needed, so that we can make sure that the instructions that retrieve the exception object come first in the exception handler.<br /><br />Then, we retrieve the PAST node for the exception identifier. We're setting its scope, a flag telling the PAST compiler this is a declaration, and we clear the viviself attribute. The viviself attribute is discussed in a later episode; if you didn't read that yet, just keep in mind the viviself attribute (if set) will make sure all declared variables are initialized. We must clear this attribute here, to make sure that this exception object is not initialized, because that will be done by the instruction that retrieves the thrown exception object, discussed next.<br /><br />In PIR, we can use the <span style="font-family:courier new;">.get_results</span> directive to retrieve a thrown exception. You could also generate the <span style="font-family:courier new;">get_results</span> <span style="font-style: italic;">instruction </span>(note the missing dot), but this is much easier. Currently, in PIR, when retrieving the exception object, you must always specify both a variable (or register) for the exception object, and a string variable (or register) to store the exception message. The exception message is actually stored within the exception object. We use $S0 to store the exception message, and we'll ignore it after that. Just remember for now that if you want to retrieve the exception object, you must also specify a place to store the exception message.<br />There is no special PAST node to generate these instructions, so we use a so-called <span style="font-style: italic;">inline </span><span style="font-family:courier new;">PAST::Op</span> node. We store the instructions to be generated into a string and store that in the inline attribute of a PAST::Op node. Once created, this node is unshifted onto the <span style="font-family:courier new;">PAST::Stmts</span> node representing the exception handler. After that, the declaration is stored in that <span style="font-family:courier new;">PAST::Stmts</span> node, so that this declaration comes first.<br /><br />Finally, we have the block representing the try block, and a <span style="font-family:courier new;">PAST::Stmts</span> node representing the exception handler. Both are used to create a <span style="font-family:courier new;">PAST::Op</span> node whose pasttype is set to the built-in "try" type.<br /><br />2. Start Squaak in interactive mode, and specify the target option to show the generated PIR instructions. Check out what instructions and labels are generated, and see if you can recognize which instructions make up the conditional expression, which represent the "then" block, and which represent the "else" block (if any).<br /><blockquote><span style="font-family:courier new;">> if 1 then else end</span><br /><br /><span style="font-family:courier new;">.namespace</span><br /><span style="font-family:courier new;">.sub "_block16"</span><br /><span style="font-family:courier new;"> new $P18, "Integer"</span><br /><span style="font-family:courier new;"> assign $P18, 1<br /><br />## this is the condition:<br /></span><span style="font-family:courier new;"> if $P18, if_17<br /><br />## this is invoking the else-block:<br /></span><span style="font-family:courier new;"> get_global $P21, "_block19"</span><br /><span style="font-family:courier new;"> newclosure $P21, $P21</span><br /><span style="font-family:courier new;"> $P20 = $P21()</span><br /><span style="font-family:courier new;"> set $P18, $P20</span><br /><span style="font-family:courier new;"> goto if_17_end<br /><br />## this is invoking the then-block:<br /></span><span style="font-family:courier new;"> if_17:</span><br /><span style="font-family:courier new;"> get_global $P24, "_block22"</span><br /><span style="font-family:courier new;"> newclosure $P24, $P24</span><br /><span style="font-family:courier new;"> $P23 = $P24()</span><br /><span style="font-family:courier new;"> set $P18, $P23</span><br /><span style="font-family:courier new;"> if_17_end:</span><br /><span style="font-family:courier new;"> .return ($P18)</span><br /><span style="font-family:courier new;">.end</span><br /><br /><span style="font-family:courier new;">.namespace</span><br /><span style="font-family:courier new;">.sub "_block22" :outer("_block16")</span><br /><span style="font-family:courier new;"> .return ()</span><br /><span style="font-family:courier new;">.end</span><br /><br /><span style="font-family:courier new;">.namespace</span><br /><span style="font-family:courier new;">.sub "_block19" :outer("_block16")</span><br /><span style="font-family:courier new;"> .return ()</span><br /><span style="font-family:courier new;">.end</span><br /><br /></blockquote><br /><br /><br /></div>kjshttp://www.blogger.com/profile/18109327874846144778noreply@blogger.comtag:blogger.com,1999:blog-2772753380875006713.post-70363392620269890452008-03-31T01:18:00.000-07:002008-05-22T09:56:15.251-07:00Solutions to the Exercises in Episode 3<div style="text-align: justify;">By now, you may have finished the PCT tutorial. If you felt too lazy to do the exercises or if you want to see what solution I had in mind, here are the solutions to the exercises in <a href="http://www.parrotblog.org/2008/03/episode-3-squaak-details-and-first.html">Episode 3</a> (Episode 1's exercise was discussed at the end of Episode 2, and the latter didn't have any coding assignments).<br /><br />1. Rename the names of the action methods according to the name changes we made on the grammar rules. So, "integer" becomes "integer_constant", "value" becomes "expression", and so on.<br /><blockquote>I assume you don't need any help with this.</blockquote>2. Look at the grammar rule for statement. A statement currently consists of an assignment. Implement the action method "statement" to retrieve the result object of this assignment and set it as statement's result object using the special <span style="font-family:courier new;">make </span>function. Do the same for rule primary.<br /><blockquote style="font-family:courier new;"><pre>method statement($/) {<br /><span style="font-family:courier new;"> make $( $<assignment> );</span><br />}</pre></blockquote>Note that at this point, the rule statement doesn't define different #= keys for each type of statement, so we don't declare a parameter $key. This will be changed later.<br /><blockquote style="font-family:courier new;"><pre>method primary($/) {<br /><span style="font-family:courier new;"> make $( $<identifier> );</span><br />}</pre></blockquote>3. Write the action method for the rule identifier. As a result object of this "match", a new <span style="font-family:courier new;">PAST::Var</span> node should be set, taking as name a string representation of the match object (<span style="font-family:courier new;">$/</span>). For now, you can set the scope to 'package'. See "pdd26: ast" for details on <span style="font-family: courier new;">PAST::Var</span> nodes.<br /><blockquote face="courier new"><pre><span style="font-family:courier new;">method identifier($/) {</span><br /><span style="font-family:courier new;"> make PAST::Var.new( :name(~$/),</span><br /><span style="font-family:courier new;"> :scope('package'),</span><br /><span style="font-family:courier new;"> :node($/) );</span><br />}</pre></blockquote>4. Write the action method for assignment. Retrieve the result objects for <span style="font-family:courier new;">"primary"</span> and for "expression", and create a <span style="font-family:courier new;">PAST::Op</span> node that <span style="font-style: italic;">binds </span>the expression to the primary. (Check out pdd26 for <span style="font-family:courier new;">PAST::Op</span> node types, and find out how you do such a binding).<br /><span style="font-family:courier new;"></span><blockquote><pre><span style="font-family:courier new;">method assignment($/) {</span><br /><span style="font-family:courier new;"> my $lhs := $( $<primary> );</span><br /><span style="font-family:courier new;"> my $rhs := $( $<expression> );</span><br /><span style="font-family:courier new;"> $lhs.lvalue(1);</span><br /><span style="font-family:courier new;"> make PAST::Op.new( $lhs, $rhs,</span><br /><span style="font-family:courier new;"> :pasttype('bind'),</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>Note that we set the <span style="font-family:courier new;">lvalue</span> flag on <span style="font-family:courier new;">$lhs</span>. See PDD26 for details on this flag.<br /><br />5. Run your compiler on a script or in interactive mode. Use the target option to see what PIR is being generated on the input <span style="font-family:courier new;">"x = 42"</span>.<br /><blockquote face="courier new"><pre>.namespace<br />.sub "_block10"<br /><span style="font-family:courier new;"> new $P11, "Integer"</span><br /><span style="font-family:courier new;"> assign $P11, 42</span><br /><span style="font-family:courier new;"> set_global "x", $P11</span><br /><span style="font-family:courier new;"> .return ($P11)</span><br />.end</pre></blockquote>The first two lines of code in the sub create an object to store the number 42, the third line stores this number as <span style="font-family: courier new;">"x"</span>. The PAST compiler will always generate an instruction to return the result of the last statement, in this case <span style="font-family: courier new;">$P11</span>.<br /><br /></div>kjshttp://www.blogger.com/profile/18109327874846144778noreply@blogger.comtag:blogger.com,1999:blog-2772753380875006713.post-48620556016380429142008-03-23T11:59:00.000-07:002008-03-28T03:32:32.960-07:00Episode 9: Wrap up and Conclusion<div style="text-align: justify;">Welcome to the final Episode of the Parrot Compiler Tools Tutorial! Let's review the previous episodes, and summarize this tutorial.<br /><br /><span style="font-size:130%;">Review</span><br />In <a href="http://www.parrotblog.org/2008/03/targeting-parrot-vm.html">Episode 1</a>, we introduced the Parrot Compiler Tools (PCT), gave a high-level feature overview of Squaak, the case study language that we are implementing in this tutorial, and we generated a language shell that we use as a foundation to implement Squaak.<br /><br /><a href="http://www.parrotblog.org/2008/03/episode-2-poking-in-compiler-guts.html">Episode 2</a> discussed the general structure of PCT-based compilers. After this, we described each of the four default compilation stages: parse phase, parse tree to PAST, PAST to POST and POST to PIR. We also added a command line banner and command line prompt to the interactive language shell.<br /><br />In <a href="http://www.parrotblog.org/2008/03/episode-3-squaak-details-and-first.html">Episode 3</a>, we introduced the full grammar of the Squaak language. After this, we started implementing the first bits, after which we were able to generate code for (simple) assignments.<br /><br />In <a href="http://www.parrotblog.org/2008/03/episode-4-past-nodes-and-more.html">Episode 4</a> we discussed the construction of Parrot Abstract Syntax Tree nodes in more detail, after which we implemented the if-statement and throw-statement.<br /><br /><a href="http://www.parrotblog.org/2008/03/episode-5-variable-declaration-and.html">Episode 5</a> focused on variable declarations and variable scope. We implemented the necessary infrastructure to handle global and local variables correctly. In <a href="http://www.parrotblog.org/2008/03/episode-6-scope-and-subroutines.html">Episode 6</a> we continued the discussion of scope, but now in the context of subroutines. After this we implemented subroutine invocation.<br /><br /><a href="http://www.parrotblog.org/2008/03/episode-7-operators-and-precedence.html">Episode 7</a> extended our grammar to handle complex expressions that allows us to use arithmetic and other operators. We discussed how to use PCT's built-in support for handling operator precedence.<br /><br />In the previous episode, <a href="http://www.parrotblog.org/2008/03/episode-8-hashtables-and-arrays.html">Episode 8</a>, we discussed the grammar and action methods for handling the aggregate data types of Squaak: arrays and hashes. We also touched on the topic of argument passing by reference and by value.<br /><br />If you followed the tutorial and did the exercises, your implementation should be complete. Although a lot of the implementation was discussed, some parts were left as the proverbial exercise to the reader. This is to stimulate you to get your hands dirty and figure out things for yourself, while the text contained enough hints (in my opinion) to solve the given problems. Sure enough, this approach requires you to spend more time and think for yourself, but I think you're reading all this stuff to learn something. The extra time spent is well worth it, in my opinion.<br /><br />Now it's time to see what we can do with this language. Squaak is more than just the average calculator example, which is often provided in beginner's discussions on parsers; it's a complete programming language.<br /><br /><span style="font-size:130%;">What's Next?</span><br />This is the last episode of the Parrot Compiler Tools tutorial. We showed how we implemented a complete language for the Parrot virtual machine in only a few hundred lines of source code. Surely, this must be the proof that the PCT really is an effective toolkit for implementing languages. At the moment of writing, the PCT still lacks efficient support for certain language constructs. Therefore, we focused on the parts that are easy to build with the PCT. Once the PCT is feature complete, there's bound to be another tutorial on advanced features. Think of object-oriented programming, closures, coroutines, and advanced control-flow such as return statements. Most of them can be done already, but are too complex for this tutorial's level.<br /><br /><span style="font-size:130%;">The Game of Life</span><br />You might have noticed that Squaak looks a bit like Lua, although it does differ in some points. This is not entirely accidental. In the distribution of the Lua source code, there's an example called "life.lua", which implements Conway's "Game of Life". This is a nice demonstration program, and it's easy to port it to Squaak. Its implementation is shown below. Run it, and enjoy!<br /><blockquote><pre><span style="font-family:courier new;">## John Conway's Game of Life</span><br /><span style="font-family:courier new;">## Implementation based on life.lua, found in Lua's distribution.</span><br /><span style="font-family:courier new;">##</span><br /><span style="font-family:courier new;">var width = 40 # width of "board"</span><br /><span style="font-family:courier new;">var height = 20 # height of "board"</span><br /><span style="font-family:courier new;">var generation = 1 # generation couner</span><br /><span style="font-family:courier new;">var numgenerations = 50 # how often should we evolve?</span><br /><br /><span style="font-family:courier new;">## initialize board to all zeroes</span><br /><span style="font-family:courier new;">sub initboard(board)</span><br /><span style="font-family:courier new;"> for var y = 0, height do</span><br /><span style="font-family:courier new;"> for var x = 0, width do</span><br /><span style="font-family:courier new;"> board[y][x] = 0</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><br /><br /><span style="font-family:courier new;">## spawn new life in board, at position (left, top),</span><br /><span style="font-family:courier new;">## the life data is stored in shapedata, and shape width and</span><br /><span style="font-family:courier new;">## height are specified.</span><br /><span style="font-family:courier new;">sub spawn(board, left, top, shapew, shapeh, shapedata)</span><br /><span style="font-family:courier new;"> for var y = 0, shapeh - 1 do</span><br /><span style="font-family:courier new;"> for var x = 0, shapew - 1 do</span><br /><span style="font-family:courier new;"> board[top + y][left + x] = shapedata[y * shapew + x]</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><br /><br /><span style="font-family:courier new;">## calculate the next generation.</span><br /><span style="font-family:courier new;">sub evolve(thisgen, nextgen)</span><br /><span style="font-family:courier new;"> var ym1 = height - 1</span><br /><span style="font-family:courier new;"> var y = height</span><br /><span style="font-family:courier new;"> var yp1 = 1</span><br /><span style="font-family:courier new;"> var yi = height</span><br /><br /><span style="font-family:courier new;"> while yi > 0 do</span><br /><span style="font-family:courier new;"> var xm1 = width-1</span><br /><span style="font-family:courier new;"> var x = width</span><br /><span style="font-family:courier new;"> var xp1 = 1</span><br /><span style="font-family:courier new;"> var xi = width</span><br /><br /><span style="font-family:courier new;"> while xi > 0 do</span><br /><br /><span style="font-family:courier new;"> var sum = thisgen[ym1][xm1]</span><br /><span style="font-family:courier new;"> + thisgen[ym1][x]</span><br /><span style="font-family:courier new;"> + thisgen[ym1][xp1]</span><br /><span style="font-family:courier new;"> + thisgen[y][xm1]</span><br /><span style="font-family:courier new;"> + thisgen[y][xp1]</span><br /><span style="font-family:courier new;"> + thisgen[yp1][xm1]</span><br /><span style="font-family:courier new;"> + thisgen[yp1][x]</span><br /><span style="font-family:courier new;"> + thisgen[yp1][xp1]</span><br /><br /><span style="font-family:courier new;"> nextgen[y][x] = sum==2 and thisgen[y][x] or sum==3</span><br /><br /><span style="font-family:courier new;"> xm1 = x</span><br /><span style="font-family:courier new;"> x = xp1</span><br /><span style="font-family:courier new;"> xp1 = xp1 + 1</span><br /><span style="font-family:courier new;"> xi = xi - 1</span><br /><span style="font-family:courier new;"> end</span><br /><br /><span style="font-family:courier new;"> ym1 = y</span><br /><span style="font-family:courier new;"> y = yp1</span><br /><span style="font-family:courier new;"> yp1 = yp1 + 1</span><br /><span style="font-family:courier new;"> yi = yi - 1</span><br /><br /><span style="font-family:courier new;"> end</span><br /><span style="font-family:courier new;">end</span><br /><br /><span style="font-family:courier new;">## display thisgen to stdout.</span><br /><span style="font-family:courier new;">sub display(thisgen)</span><br /><span style="font-family:courier new;"> var line = ""</span><br /><span style="font-family:courier new;"> for var y = 0, height do</span><br /><span style="font-family:courier new;"> for var x = 0, width do</span><br /><span style="font-family:courier new;"> if thisgen[y][x] == 0 then</span><br /><span style="font-family:courier new;"> line = line .. "-"</span><br /><span style="font-family:courier new;"> else</span><br /><span style="font-family:courier new;"> line = line .. "O"</span><br /><span style="font-family:courier new;"> end</span><br /><br /><span style="font-family:courier new;"> end</span><br /><span style="font-family:courier new;"> line = line .. "\n"</span><br /><span style="font-family:courier new;"> end</span><br /><span style="font-family:courier new;"> print(line, "\nLife - generation: ", generation)</span><br /><span style="font-family:courier new;">end</span><br /><br /><span style="font-family:courier new;">## main program</span><br /><span style="font-family:courier new;">sub main()</span><br /><span style="font-family:courier new;"> var heart = [1,0,1,1,0,1,1,1,1]</span><br /><span style="font-family:courier new;"> var glider = [0,0,1,1,0,1,0,1,1]</span><br /><span style="font-family:courier new;"> var explode = [0,1,0,1,1,1,1,0,1,0,1,0]</span><br /><br /><span style="font-family:courier new;"> var thisgen = []</span><br /><span style="font-family:courier new;"> initboard(thisgen)</span><br /><br /><span style="font-family:courier new;"> var nextgen = []</span><br /><span style="font-family:courier new;"> initboard(nextgen)</span><br /><br /><span style="font-family:courier new;"> spawn(thisgen,3,5,3,3,heart)</span><br /><span style="font-family:courier new;"> spawn(thisgen,5,4,3,3,glider)</span><br /><span style="font-family:courier new;"> spawn(thisgen,25,10,3,4,explode)</span><br /><br /><span style="font-family:courier new;"> while generation <= numgenerations do</span><br /><span style="font-family:courier new;"> evolve(thisgen, nextgen)</span><br /><span style="font-family:courier new;"> display(thisgen)</span><br /><span style="font-family:courier new;"> generation = generation + 1</span><br /><br /><span style="font-family:courier new;"> ## prevent switching nextgen and thisgen around,</span><br /><span style="font-family:courier new;"> ## just call evolve with arguments switched.</span><br /><span style="font-family:courier new;"> evolve(nextgen, thisgen)</span><br /><span style="font-family:courier new;"> display(nextgen)</span><br /><span style="font-family:courier new;"> generation = generation + 1</span><br /><br /><span style="font-family:courier new;"> end</span><br /><span style="font-family:courier new;">end</span><br /><br /><span style="font-family:courier new;">## start here.</span><br /><span style="font-family:courier new;">main()</span><br /><br /></pre></blockquote>Note the use of a subroutine "print". Check out the file src/builtins/say.pir, and rename the sub "say" (which was generated by the language shell creation script) to "print".<br /><br /><span style="font-size:130%;">Exercises</span><br />Squaak was designed to be a simple language, offering enough features to get some work done, but at the same time keeping it simple. Of course, after reading this tutorial, You are an expert too ;-) If you feel like adding more features, here are some suggestions.<br /><ul><li>Implement prefix and postfix increment/decrement operators, allowing you to write "generation++" instead of "generation = generation + 1".</li><li>Implement augmenting assign operators, such as "+=" and friends.</li><li>Extend the grammar to allow multiple variable declarations in one statement, allowing you to write "var x = 1, y, z =3". Of course, the initialization part should still be optional. How do you make sure that the identifier and initialization expression are kept together?</li><li>Implement a mechanism (such as an "import" statement) to include or load another Squaak file, so Squaak programs can be split into multiple files. The PCT does not have any support for this, so you'll need to write a bit of PIR to do this.<br /></li><li>Improve the for-statement, to allow for a negative step. Note that the loop condition becomes more complex when doing so.<br /></li></ul>Note that these are suggestions, and I did not implement them myself, so I won't have a solution for you at the end.<br /><br /><span style="font-size:130%;">Final words and Acknowledgments</span><br />By now, you should have got a good impression of the PCT and you should be able to work on other languages targeting Parrot. Currently, work has been done on ECMAScript, Python, Ruby and of course Perl 6. Most of them are not complete yet (hint, hint).<br /><br />I hope you enjoyed reading this tutorial and learned enough to feel confident about working on other (existing) languages targeting Parrot. The Perl 6 implementation can still use more contributors!<br /><br />Many thanks to all who read this tutorial and provided me with hints, tips and feedback! Thank You for reading this!<br /><br /><span style="font-size:130%;">License</span><br />The source code in this tutorial has been released by the author into the public domain. Where this is not possible by law, the author grants license to use this file for any reason without any rights reserved, and with no warranty express or implied or fitness for a particular purpose.<br /></div>kjshttp://www.blogger.com/profile/18109327874846144778noreply@blogger.comtag:blogger.com,1999:blog-2772753380875006713.post-31784155637177289332008-03-22T11:57:00.000-07:002008-05-12T02:58:48.119-07:00