[svn:parrot] r37501 - in trunk: . docs/user/pir
allison at svn.parrot.org
allison at svn.parrot.org
Mon Mar 16 21:06:50 UTC 2009
Author: allison
Date: Mon Mar 16 21:06:48 2009
New Revision: 37501
URL: https://trac.parrot.org/parrot/changeset/37501
Log:
[doc] Renaming some introductory files.
Added:
trunk/docs/user/pir/intro.pod
- copied unchanged from r37497, trunk/docs/user/pir/pp001-intro.pod
trunk/docs/user/pir/objects.pod
- copied unchanged from r37497, trunk/docs/user/pir/pp003-oop.pod
trunk/docs/user/pir/pmcs.pod
- copied unchanged from r37497, trunk/docs/user/pir/pp002-pmc.pod
Deleted:
trunk/docs/user/pir/pp001-intro.pod
trunk/docs/user/pir/pp002-pmc.pod
trunk/docs/user/pir/pp003-oop.pod
Modified:
trunk/MANIFEST
Modified: trunk/MANIFEST
==============================================================================
--- trunk/MANIFEST Mon Mar 16 20:56:37 2009 (r37500)
+++ trunk/MANIFEST Mon Mar 16 21:06:48 2009 (r37501)
@@ -1,7 +1,7 @@
# ex: set ro:
# $Id$
#
-# generated by tools/dev/mk_manifest_and_skip.pl Mon Mar 16 17:06:35 2009 UT
+# generated by tools/dev/mk_manifest_and_skip.pl Mon Mar 16 21:02:26 2009 UT
#
# See tools/dev/install_files.pl for documentation on the
# format of this file.
@@ -528,9 +528,9 @@
docs/submissions.pod []
docs/tests.pod []
docs/user/pir/exceptions.pod [main]doc
-docs/user/pir/pp001-intro.pod [main]doc
-docs/user/pir/pp002-pmc.pod [main]doc
-docs/user/pir/pp003-oop.pod [main]doc
+docs/user/pir/intro.pod [main]doc
+docs/user/pir/objects.pod [main]doc
+docs/user/pir/pmcs.pod [main]doc
docs/vtables.pod [devel]doc
editor/README.pod []doc
editor/filetype_parrot.vim []
Copied: trunk/docs/user/pir/intro.pod (from r37497, trunk/docs/user/pir/pp001-intro.pod)
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ trunk/docs/user/pir/intro.pod Mon Mar 16 21:06:48 2009 (r37501, copy of r37497, trunk/docs/user/pir/pp001-intro.pod)
@@ -0,0 +1,347 @@
+# $Id$
+
+# One first version of this article was published on TPR 2.3
+#
+# Please feel free to edit it to suit latest parrot developments,
+# and to be a good starting point for beginners.
+
+=head1 Writing PIR
+
+PIR (Parrot Intermediate Representation) is a way to program the
+parrot virtual machine that is easier to use than PASM (Parrot
+Assembler). PASM notation is like any other assembler-like format and
+can be used directly, but it is more verbose and gives too much power
+to the user. PIR abstracts common operations and conventions into a
+syntax that more closely resembles a high-level language. PIR allows
+the programmer to write code that more naturally expresses their
+intent without worrying about setting up the exact details that PASM
+requires to function properly.
+
+This article will show the basics on programming in PIR. More advanced
+topics will appear in later articles.
+
+=head2 Getting Parrot
+
+In order to test the PIR and PASM code in this article, a parrot virtual
+machine is needed (henceforth just "parrot"). Parrot is available from
+L<http://parrot.org>. Just download the latest release, or checkout
+the current development version from the SVN tree. The programs in this
+article were tested with Parrot 0.8.1.
+
+Parrot is very easy to compile on unix-like and Microsoft Windows
+operating systems: just run C<perl Configure.pl && make> in the root
+directory of the parrot source and, if everything works correctly, a
+C<parrot> executable should appear. At the moment of writing, the
+C<make install> target does not work properly, so in this and other
+articles it is assumed that the parrot executable is invoked from the
+parrot root directory.
+
+If you do not want to compile your own Parrot you can download a pre-compiled
+binary from http://www.parrot.org/source.html.
+
+=head2 Parrot Virtual Machine overview
+
+Before we get started with the examples, here's a quick overview of
+parrot's architecture.
+
+Parrot is a register-based virtual machine. It provides 4 types of
+registers. The register types are:
+
+=over 4
+
+=item I - integer
+
+=item N - floating point
+
+=item S - string
+
+=item P - polymorphic container (PMC)
+
+=back
+
+In order to designate a register in PASM, use the character indicating
+the type (C<I>, C<N>, C<S> or C<P>) and the register number. For instance,
+in order to use register 10 of type integer, you'd write C<I10>. In this
+series of articles, we will mainly focus on programming PIR.
+
+In PIR, you would type the C<$> character in front of the register, to
+indicate a I<virtual> register. For instance, the integer registers are
+C<$I0>, C<$I1> and so on. The PMC registers hold arbitrary data objects
+and are parrot's mechanism for implementing more complex behavior than the
+ones that can be expressed using the other 3 register types alone.
+
+A virtual register is mapped to an actual register by the register allocator.
+You can use as many registers as you want, and the register allocator will
+allocate them as needed.
+
+PMCs will be covered in more detail in a future article. Examples in
+this article will focus on the first 3 register types.
+
+=head2 Simple Operators
+
+Let me start with a simple and typical example:
+
+ .sub main :main
+ print "hello world\n"
+ .end
+
+To run it, save the code in a C<hello.pir> file and pass it to the
+parrot virtual machine:
+
+ ./parrot hello.pir
+
+Note that I am using a relative path to parrot given that I didn't
+install it into the system.
+
+The keywords starting with a dot (C<.sub> and C<.end>) are PIR directives.
+They are used together to define subroutines. After the C<.sub> keyword
+I use the name of the subroutine. The keyword that starts with a colon
+(C<:main>) is a pragma that tells parrot that this is the main body of the
+program and that it should start by executing this subroutine.
+By the way, I could use C<.sub foo :main> and Parrot will use the C<foo>
+subroutine as the main body of the program. The actual name of the
+subroutine does not matter as long as it has the C<:main> pragma. If you
+don't specify the <:main> pragma on any subroutine, then parrot will start
+executing the first subroutine in the source file.
+The full set of pragmas are defined in L<docs/pdds/pdd19_pir.pod>.
+
+Before going into more details about subroutines and calling
+conventions, let's compare some PIR syntax to the equivalent PASM.
+
+If I want to add two integer registers using PASM I would use the
+Parrot C<set> opcode to put values into registers, and the C<add>
+opcode to add them, like this:
+
+ set $I1, 5
+ set $I2, 3
+ add $I0, $I1, $I2 # $I0 yields 5+3
+
+PIR includes infix operators for these common opcodes. I could write
+this same code as
+
+ $I1 = 5
+ $I2 = 3
+ $I0 = $I1 + $I2
+
+There are the four arithmetic operators as you should be expecting, as
+well as the six different comparison operators, which return a boolean
+value:
+
+ $I1 = 5
+ $I2 = 3
+ $I0 = $I1 <= $I2 # $I0 yields 0 (false)
+
+I can also use the short accumulation-like operators, like C<+=>.
+
+Another PIR perk is that local variable names may be declared and used
+instead of register names. For that I just need to declare the
+variable using the C<.local> keyword with any of the four data
+types available on PIR: C<int>, C<string>, C<num> and C<pmc>:
+
+ .local int size
+ size = 5
+
+Note that all registers, both numbered and named, are consolidated by
+the Parrot register allocator, assigning these "virtual registers" to
+actual registers as needed. The register allocator even coalesces two
+virtual names onto the same physical register when it can
+prove that they have non-overlapping lifetimes, so there is no need to
+be stingy with register names. To see the actual registers used, use
+C<pbc_disassemble> on the C<*.pbc> output. You can generate a Parrot
+Byte Code (PBC) file as follows:
+
+ ./parrot -o foo.pbc --output-pbc foo.pir
+
+Then, use C<pbc_disassemble> in order to disassemble it:
+
+ ./pbc_disassemble foo.pbc
+
+=head2 Branching
+
+Another simplification of PASM are branches. Basically, when I want to
+test a condition and jump to another place in the code, I would write
+the following PASM code:
+
+ le $I1, $I2, LESS_EQ
+
+Meaning, if C<$I1> is less or equal than C<$I2>, jump to label
+C<LESS_EQ>. In PIR I would write it in a more legible way:
+
+ if $I1 <= $I2 goto LESS_EQ
+
+PIR includes the C<unless> keyword as well.
+
+=head2 Calling Functions
+
+Subroutines can easily be created using the C<.sub> keyword shown
+before. If you do not need parameters, it is just as simple as I show in
+the following code:
+
+ .sub main :main
+ hello()
+ .end
+
+ .sub hello
+ print "Hello World\n"
+ .end
+
+Now, I want to make my C<hello> subroutine a little more useful, such
+that I can greet other people. For that I will use the C<.param>
+keyword to define the parameters C<hello> can handle:
+
+ .sub main :main
+ hello("leo")
+ hello("chip")
+ .end
+
+ .sub hello
+ .param string person
+ print "Hello "
+ print person
+ print "\n"
+ .end
+
+If I need more parameters I just need to add more C<.param> lines.
+
+To return values from PIR subroutines I use the C<.return> keyword,
+followed by one or more arguments, just like this:
+
+ .return (10, 20, 30)
+
+The calling subroutine can accept these values. If you want to retrieve
+only one value (or only the first value, in case multiple values are
+returned), write this:
+
+ $I0 = compute_it($I8, $I9)
+
+To accept multiple values from such a function, use a parenthesized
+results list:
+
+ ($I1, $I2, $I3) = compute_it($I8, $I9)
+
+=head2 Factorial Example
+
+Now, for a little more complicated example, let me show how I would
+code Factorial subroutine:
+
+ .sub main :main
+ $I1 = factorial(5)
+ print $I1
+ print "\n"
+ .end
+
+ .sub factorial
+ .param int i
+ if i > 1 goto recur
+ .return (1)
+ recur:
+ $I1 = i - 1
+ $I2 = factorial($I1)
+ $I2 *= i
+ .return ($I2)
+ .end
+
+This example also shows that PIR subroutines may be recursive just as in
+a high-level language.
+
+=head2 Named Arguments
+
+As some other languages as Python and Perl support named arguments,
+PIR supports them as well.
+
+As before, I need to use C<.param> for each named argument, but you need to
+specify a flag indicating the parameter is named:
+
+ .sub func
+ .param int a :named("foo")
+
+The subroutine will receive an integer named "foo", and inside of the
+subroutine that integer will be known as "a".
+
+When calling the function, I need to pass the names of the
+arguments. For that there are two syntaxes:
+
+ func( 10 :named("foo") ) # or
+ func( "foo" => 10 )
+
+Note that with named arguments, you may rearrange the order of your
+parameters at will.
+
+ .sub foo
+ .param string "name" => a
+ .param int "age" => b
+ .param string "gender" => c
+ # ...
+ .end
+
+This subroutine may be called in any of the following ways:
+
+ foo( "Fred", 35, "m" )
+ foo( "gender" => "m", "name" => "Fred", "age" => 35 )
+ foo( "age" => 35, "gender" => "m", "name" => "Fred" )
+ foo( "m" :named("gender"), 35 :named("age"), "name" => "Fred" )
+
+and any other permutation you can think of as long as you use the named
+argument syntax. Note that any positional parameters must be passed
+before the named parameters. So, the following is allowed:
+
+ .sub main
+ .param int a
+ .param int b :named("age")
+ # ...
+ .end
+
+Whereas the following is not:
+
+ .sub main
+ .param int a :named("name")
+ .param int b # cannot declare positional parameter after a named parameter
+ # ...
+ .end
+
+It's also possible to use named syntax when returning values from
+subroutines. Into the C<.return> command I'll use:
+
+ .return ( "bar" => 20, "foo" => 10)
+
+and when calling the function, I will do:
+
+ ("foo" => $I0, "bar" => $I1) = func()
+
+And C<$I0> will yield 10, and C<$I1> will yield 20, as expected.
+
+=head2 Concluding
+
+To conclude this first article on PIR and to let you test what you
+learned, let me show you how to do input on PASM (hence, also in
+PIR). There is a C<read> opcode to read from standard input. Just
+pass it a string register or variable where you wish the characters
+read to be placed and the number of characters you wish to read:
+
+ read $S1, 100
+
+This line will read 100 characters (or until the end of the line) and
+put the read string into C<$S1>. In case you need a number, just
+assign the string to the correct register type:
+
+ read $S1, 100
+ $I1 = $S1
+
+With the PIR syntax shown in this article you should be able to start
+writing simple programs. Next article we will look into available
+Polymorphic Containers (PMCs), and how they can be used.
+
+=head2 Author
+
+Alberto Simões
+
+=head2 Thanks
+
+=over 4
+
+=item * Jonathan Scott Duff
+
+=back
+
+=cut
+
Copied: trunk/docs/user/pir/objects.pod (from r37497, trunk/docs/user/pir/pp003-oop.pod)
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ trunk/docs/user/pir/objects.pod Mon Mar 16 21:06:48 2009 (r37501, copy of r37497, trunk/docs/user/pir/pp003-oop.pod)
@@ -0,0 +1,404 @@
+# $Id$
+
+=head1 Programming Parrot -- Using objects
+
+Yes, you've read correctly. Parrot has the ability to create
+and manipulate objects (aka, object oriented programming).
+While it may seem strange for a low-level language like
+PIR to have the facility for object oriented programming,
+it makes perfect sense in this particular case. Remember,
+the original goal of Parrot was to be the underlying
+implementation for Perl6, which has object oriented
+features. Parrot's secondary goal is to provide a good
+platform for other dynamic languages such as Python, Ruby,
+PHP, Javascript, etc. and those languages too have the
+ability (if not the requirement) to be object oriented. Thus
+Parrot contains facilities for a manipulating objects so
+that language implementors can easily express the
+appropriate object semantics for their language of interest.
+
+=head2 Namespaces
+
+Before I begin talking about how to create classes and
+instantiate objects, I first need to talk about an
+intimately related subject: namespaces. Namespaces serve a
+twofold purpose, they allow you to group related routines
+together and they allow you to give several subroutines the
+same name but different, domain specific, implementations.
+These characteristics are, oddly enough, similar to the
+basic requirements for a class.
+
+For instance, you may put all of your subroutines dealing
+with people in a C<Person> namespace and all of your
+subroutines dealing with computer programs in the C<Process>
+namespace. Both namespaces may have a subroutine called
+C<run()> but with radically different implementations. Below
+is some code to illustrate this example:
+
+=head3 Example 1:
+
+ .namespace [ "Person" ]
+
+ .sub run
+ say "Run Forrest, Run!"
+ .end
+
+ .namespace [ "Process" ]
+
+ .sub run
+ say "Running process #53"
+ .end
+
+As you might guess, the C<.namespace> directive tells Parrot
+what namespace to group subroutines under. A namespace ends when
+another C<.namespace> directive changes the namespace or when
+the end of the file is reached. A C<.namespace> directive
+with no names in the brackets changes back to the root namespace.
+
+Perl programmers will recognize that Parrot
+C<.namespace> declarations are just like Perl C<package>
+declarations, albeit with different syntax.
+But there are a few other differences. I'll
+talk more about how Parrot uses namespaces and classes
+together in just a minute.
+
+=head2 PIR with class
+
+Creating classes in Parrot is relatively easy. There are
+opcodes for it. The easiest to start with is C<newclass>;
+just say C<$P0 = newclass 'Foo'> where $P0 is a PMC
+register, and 'Foo' is the name of the class you want to create.
+
+When you wish to instantiate objects that belong to the class
+you've created, it's equally simple. Just say C<myobj = new
+"Foo"> where C<myobj> is a PMC and "Foo" is the classname you've
+created with C<newclass>. Here's a simple example:
+
+=head3 Example 2: A classic Dog
+
+ .sub _ :main
+ $P0 = newclass 'Dog'
+ .local pmc spot
+ spot = new 'Dog'
+ .end
+
+You may notice that I didn't use the return value of
+C<newclass>. That's only because this is a simple example. :-)
+I'll talk about what to do with the return value of C<newclass>
+a little later. Right now, let's talk about methods.
+
+=head2 Madness ... er, Methods
+
+So now that I've created a C<Dog> class, how do I add methods
+to it? Remember before when I talked about namespaces? Well,
+that's the answer. To add methods to a class, you create a
+namespace with the same name as the class and then put your
+subroutines in that namespace. PIR also provides a syntactic
+marker to let everyone know these subroutines are methods. When
+declaring the subroutine, add the C<:method> modifier after the
+subroutine name. Here's a familiar example to anyone who has
+read L<perlboot>.
+
+=head3 Example 3: Barnyard animals
+
+ .namespace [ "Cow" ]
+
+ .sub speak :method
+ print "Moo\n"
+ .end
+
+ .namespace [ "Dog" ]
+
+ .sub speak :method
+ print "Woof\n"
+ .end
+
+ .namespace [ "Pig" ]
+
+ .sub speak :method
+ print "Oink\n"
+ .end
+
+ .namespace []
+
+ .sub _ :main
+ $P0 = newclass "Cow"
+ $P0 = newclass "Dog"
+ $P0 = newclass "Pig"
+
+ .local pmc elsie, fido, porky
+
+ elsie = new "Cow"
+ fido = new "Dog"
+ porky = new "Pig"
+
+ elsie.'speak'()
+ fido.'speak'()
+ porky.'speak'()
+ .end
+
+It's important to note that even though I've declared the
+namespaces and put subroutines in them, this does not
+automatically create classes. The C<newclass> declarations
+tell Parrot to create a class and as a side effect,
+namespaces with the same name as the class may be used to
+store methods for that class.
+
+One thing you may notice about method calls is that the
+method names are quoted. Why is that? If you would have left out
+the quotes, then the identifier is assumed to be a declared
+C<.local> symbol. So, instead of writing:
+
+ elsie.'speak'()
+
+you could also have written:
+
+ .local string speak
+ speak = 'speak'
+ elsie.speak()
+
+Another example of this is shown below.
+
+=head3 Example 4: variable methods
+
+ .namespace [ 'Foo' ]
+
+ .sub foo :method
+ print "foo\n"
+ .end
+
+ .sub bar :method
+ print "bar\n"
+ .end
+
+ .namespace []
+
+ .sub _ :main
+ $P0 = newclass "Foo"
+ .local pmc f
+ f = new "Foo"
+
+ .local string m
+ m = "foo"
+ f.m()
+ m = "bar"
+ f.m()
+ .end
+
+=head2 But where do I store my stuff?
+
+So far I've talked about namespaces and creating classes
+and associating methods with those classes, but what about
+storing data in the class? Remember how the C<newclass>
+opcode returned a PMC that I didn't do anything to/with?
+Well, here's where it's used. The PMC returned from
+C<newclass> is the handle by which you manipulate the class.
+One such manipulation involves class "attributes". Attributes
+are where you store your class-specific data.
+
+Parrot has several opcodes for manipulating attributes; they
+are: C<addattribute>, C<setattribute>, and C<getattribute>.
+The C<addattribute> opcode lets you add a spot in the class
+for storing a particular value which may be get and set with
+C<getattribute> and C<setattribute> respectively. The only
+restriction on these values is that currently all
+attributes must be PMCs.
+
+So, say I wanted to give my barnyard animals names (I'll
+illustrate with just one animal and you can infer how to do the
+same for the rest):
+
+=head3 Example 5: Naming my animals
+
+ .namespace [ "Dog" ]
+
+ .sub name :method
+ .local pmc name
+ name = getattribute self, "name"
+ print name
+ .end
+
+ .sub speak :method
+ print "woof"
+ .end
+
+ .namespace []
+
+ .sub _ :main
+ $P0 = newclass "Dog"
+ addattribute $P0, "name"
+
+ .local pmc dog
+ dog = new "Dog"
+ $P0 = new "String"
+ $P0 = "Phideaux"
+ setattribute dog, "name", $P0
+
+ dog.'name'()
+ print " says "
+ dog.'speak'()
+ print "!\n"
+ .end
+
+Whew! There's a lot of new stuff in this code. I'll take them
+starting from the top of the program and working towards the
+bottom.
+
+One of the benefits of tagging your subroutines as methods
+is that they get a PMC named C<self> that represents the
+object they are acting on behalf of. The C<name> method
+takes advantage of this to retrieve the attribute called
+"name" from the C<self> PMC and print it.
+
+Immediately after I create the class called "Dog", I use the
+PMC handle returned from C<newclass> to add an attribute called
+"name" to the class. This just allocates a slot in the class for
+the value, it does nothing more.
+
+Next, I create a new Dog and give it a name. Because
+attributes may only be PMCs, in order to give the Dog a
+name, I first have to create a new String PMC (this is one
+of the PMCs builtin to Parrot) and assign the name I wish
+to give the dog to this PMC. Then I can pass this PMC as a
+parameter to C<setattribute> to give my Dog a name.
+
+Seems kind of complicated, doesn't it? Especially when you think
+about doing this for each animal. Each animal namespace
+would have an identical version of the C<name> method. For each
+call to C<newclass> I'd need to also call C<addattribute> so
+that all of the animals may have a name. Each time I wish to
+assign a name to an animal, I'd first need to create a
+C<String> and call C<setattribute> on it. Et cetera.
+
+Surely there's a better way?!? There is ...
+
+=head2 Inheritance
+
+You saw it coming didn't you? What's object oriented
+programming without inheritance? Parrot has an opcode
+C<subclass> that lets you inherit data and methods from an
+existing class. We can use this ability to create a base
+class called "Animal" that contains the "name" attribute and
+two methods that are common to all animals: C<setname> and
+C<getname> Then, to create new animals, I just inherit from
+the Animal base class like so:
+
+=head3 Example 6: inheriting
+
+ ...
+ $P0 = newclass "Animal"
+ addattribute $P0, "name"
+ $P0 = subclass "Animal", "Cow"
+ $P0 = subclass "Animal", "Dog"
+ $P0 = subclass "Animal", "Pig"
+ ...
+ cow = new 'Cow'
+ cow.'setname'("Elsie")
+ ...
+ cow.'getname'()
+
+Each subclass will contain an attribute called "name" that can be
+used to store the name of the animal. The C<setname> method
+abstracts out the process of creating a C<String> PMC and
+calling C<setattribute> on it. And finally the C<getname> method
+becomes a wrapper around C<getattribute>.
+
+=head2 Wrapup
+
+I hope this gives you an idea of how to do object oriented
+programming using Parrot. The opcodes illustrated here are what
+any language implementor that targets Parrot would use to
+implement object oriented features in their language. Of course
+there are more opcodes for richer object oriented behavior
+available in Parrot. This article only covers the basics. For
+more information see parrot/docs/pdds/pdd15_objects.pod.
+
+At the end of this article is a more complete listing of the
+program that gives my barnyard animals voices. There are
+many improvements that can be made to this code so take this
+opportunity to read and experiment and learn more about OOP
+in Parrot.
+
+=head2 Acknowledgements
+
+=over 4
+
+* Thanks to Randal Schwartz for providing a neat set of
+ examples in L<perlboot> from which this article
+ shamelessly borrows.
+* Thanks to the Parrot people for feedback
+
+=back
+
+=head2 Author
+
+Jonathan Scott Duff
+
+=head3 Example 6: Full barnyard listing
+
+ .namespace [ "Animal" ]
+
+ .sub setname :method
+ .param string name
+ $P0 = new 'String'
+ $P0 = name
+ setattribute self, "name", $P0
+ .end
+
+ .sub getname :method
+ $P0 = getattribute self, "name"
+ print $P0
+ .end
+
+ .sub speak :method
+ .local string name, sound
+ name = self.'getname'()
+ sound = self.'sound'()
+ print name
+ print " says "
+ print sound
+ print "\n"
+ .end
+
+ .namespace [ "Cow" ]
+
+ .sub sound :method
+ .return( "moo" )
+ .end
+
+ .namespace [ "Dog" ]
+
+ .sub sound :method
+ .return( "woof" )
+ .end
+
+ .namespace [ "Pig" ]
+
+ .sub sound :method
+ .return( "oink" )
+ .end
+
+ .namespace []
+
+ .sub _ :main
+ $P0 = newclass "Animal"
+ addattribute $P0, "name"
+ $P0 = subclass "Animal", "Cow"
+ $P0 = subclass "Animal", "Dog"
+ $P0 = subclass "Animal", "Pig"
+
+ .local pmc cow, dog, pig
+
+ cow = new "Cow"
+ cow.'setname'("Elsie")
+ dog = new "Dog"
+ dog.'setname'("Snoopy")
+ pig = new "Pig"
+ pig.'setname'("Porky")
+
+ cow.'speak'()
+ dog.'speak'()
+ pig.'speak'()
+ .end
+
+=cut
Copied: trunk/docs/user/pir/pmcs.pod (from r37497, trunk/docs/user/pir/pp002-pmc.pod)
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ trunk/docs/user/pir/pmcs.pod Mon Mar 16 21:06:48 2009 (r37501, copy of r37497, trunk/docs/user/pir/pp002-pmc.pod)
@@ -0,0 +1,348 @@
+# $Id$
+
+=head1 Programming Parrot -- PMCs
+
+=head2 Preliminaries
+
+To run the example code in this article, you'll need to
+obtain a copy of Parrot and build it for your system. For
+information on obtaining Parrot, see
+L<http://www.parrot.org/>. Instructions for compiling
+Parrot are available in the Parrot distribution itself. All
+code examples in this article were tested with Parrot 0.8.1
+
+=head2 A quick review of Parrot
+
+As mentioned by Alberto Manuel Simões in TPR 2.3, Parrot is
+a register-based virtual machine with 4 register types:
+Integer, String, Number and PMC. PIR registers are
+referenced by a C<$> character, a capital letter signifying
+the register type followed by the register number (C<$S15> is
+String register number 15). Parrot programs consist of lines of
+text where each line contains one opcode and its arguments.
+
+Each subroutine will have as many registers
+available as necessary; a simple subroutine will only need
+a few whereas complex subroutines with many calculations will
+need a larger number of registers. This is a fundamental
+difference from the original design of Parrot, in which there
+were 32 registers for each of the built-in types (int, num,
+pmc, string).
+PIR also provides for a more "natural" syntax for opcodes.
+Rather than saying C<set $I1, 0> to assign a zero to the $I1
+register, you may say instead C<$I1 = 0>.
+PIR also provides syntax for easily creating named variables
+and constants, subroutines, passing parameters to subroutines,
+accessing parameters by name, etc.
+
+Now, on to business ...
+
+=head2 What's a PMC?
+
+Integers, strings, and arbitrary floating point numbers are
+common data types in most programming languages, but what's
+a PMC? PMC stands for "Polymorphic Container". PMCs are how
+Parrot handles more complicated structures and behaviors
+(hence the magic :) Some examples of PMC usage would be for
+arrays, hashes, data structures, objects, etc. Anything that
+can't be expressed using just integers, floating point
+numbers and strings can be expressed with a PMC.
+
+Parrot comes with many types of PMC that encapsulate common,
+useful behavior.
+
+Many of the PMC type names give clues as to how they are
+used. Here's a table that gives a short description of
+several interesting and useful PMC types:
+
+ PMC type Description of PMC
+ -------- ------------------
+ Env access environment variables
+ Iterator iterate over aggregates such as arrays or hashes
+ Array A generic, resizable array
+ Hash A generic, resizable hash
+ Random Obtain a random number
+ String Similar to a string register but in PMC form
+ Integer Similar to an integer register but in PMC form
+ Float Similar to a number register but in PMC form
+ Exception The standard exception mechanism
+ Timer A timer of course :)
+
+=head2 Your wish is my command line
+
+Before I take a closer look at some of these PMC types,
+let's look at a common thing that people want to know how to
+do -- read command line arguments. The subroutine designated
+as the main program (by the C<:main> pragma) has an
+implicit parameter passed to it that is the command line
+arguments. Since previous examples never had such a
+parameter to the main program, Parrot simply ignored
+whatever was passed on the command line. Now I want Parrot
+to capture the command line so that I can manipulate it. So,
+let's write a program that reads the command line arguments
+and outputs them one per line:
+
+=head3 Example 2: reading command line arguments, take 1
+
+ .sub _ :main
+ .param pmc args
+ loop:
+ unless args goto end_loop # line 4
+ $S0 = shift args
+ print $S0
+ print "\n"
+ goto loop
+ end_loop:
+ .end
+
+The C<.param> directive tells parrot that I want this
+subroutine to accept a single parameter and that parameter
+is some sort of PMC that I've named C<args>. Since this is
+the main subroutine of my program (as designated by the
+C<:main> modifier to the subroutine), Parrot arranges for
+the C<args> PMC to be an aggregate of some sort that
+contains the command line arguments. We then repeatedly use
+the C<shift> opcode to remove an element from the front of
+C<args> and place it into a string register which I then
+output. When the C<args> PMC is empty, it will evaluate as a
+boolean false and the conditional on line 4 will cause the
+program to end.
+
+One problem with my program is that it's destructive to the
+C<args> PMC. What if I wanted to use the C<args> PMC later
+in the program? One way to do that is to use an integer to
+keep an index into the aggregate and then just print out
+each indexed value.
+
+=head3 Example 3: reading command line arguments, take 2
+
+ .sub _ :main
+ .param pmc args
+ .local int argc
+ argc = args # line 4
+ $I0 = 0
+ loop:
+ unless $I0 < argc goto end_loop
+ print $I0
+ print "\t"
+ $S0 = args[$I0] # line 10
+ print $S0
+ print "\n"
+ inc $I0
+ goto loop
+ end_loop:
+ .end
+
+Line 4 shows something interesting about aggregates. Similar
+to perl, when you assign an aggregate to an integer thing
+(whether it be a register or local variable, but as was explained
+before, a local variable is in fact just a symbol indicating that
+is mapped to a register), Parrot puts the number of elements in
+the aggregate into the integer thing. (e.g., if you had a PMC that
+held 5 things in C<$P0>, the statement C<$I0 = $P0> assigns 5 to
+the register C<$I0>)
+
+Since I know how many things are in the aggregate, I can
+make a loop that increments a value until it reaches that
+number. Line 10 shows that to index an aggregate, you use
+square brackets just like you would in Perl and many other
+programming languages. Also note that I'm assigning to a
+string register and then printing that register. Why didn't
+I just do C<print args[$I0]> instead? Because this isn't a
+high level language. PIR provides a nicer syntax but it's
+still really low level. Each line of PIR still essentially
+corresponds to one opcode (there are cases in which this is not
+the case, but those will be discussed later).
+So, while there's an opcode to index into an aggregate and
+an opcode to print a string, there is no opcode to do I<both>
+of those things.
+
+BTW, what type of aggregate is the C<args> PMC anyway?
+Another way to use the C<typeof> opcode is to pass it an
+actual PMC:
+
+=head3 Example 4: Typing the C<args> PMC
+
+ .sub _ :main
+ .param pmc args
+ $S0 = typeof args
+ print $S0
+ print "\n"
+ .end
+
+When you run this program it should output
+"ResizableStringArray". If you assign the result of the
+C<typeof> opcode to a string thing, you get the name of the
+PMC type.
+
+=head2 "You are standing in a field of PMCs"
+
+Now, let's get back to that table above. The C<Env> PMC can
+be thought of as a hash where the keys are environment
+variable names and the values are the corresponding
+environment variable values. But where does the actual PMC
+come from? For the command line, the PMC showed up as an
+implicit parameter to the main subroutine. Does C<Env> do
+something similar?
+
+Nope. If you want to access environment variables I<you>
+need to create a PMC of type C<Env>. This is accomplished by
+the C<new> opcode like so: C<$P0 = new 'Env'> After that
+statement, C<$P0> will contain a hash consisting of all of
+the environment variables at that time.
+
+But, both the keys and values the C<Env> hash are strings,
+so how do I iterate over them as I did for the command
+line? We can't do the same as I did with the command line
+and use an integer index into the PMC because the keys are
+strings, not integers. So, how do I do it? The answer is
+another PMC type--C<Iterator>
+
+An C<Iterator> PMC is used, as its name implies, to iterate
+over aggregates. It doesn't care if they are arrays or
+hashes or something else entirely, it just gives you a way
+to walk from one end of the aggregate to the other.
+
+Here's a program that outputs the name and value of all
+environment variables:
+
+=head3 Example 5: output environment
+
+ .sub _ :main
+ .local pmc env, iter
+ .local string key, value
+
+ env = new 'Env' # line 3
+ iter = new 'Iterator', env # line 4
+ iterloop:
+ unless iter goto iterend
+ key = shift iter # line 8
+ value = env[key]
+ print key
+ print ":"
+ print value
+ print "\n"
+ goto iterloop
+ iterend:
+ .end
+
+Lines 3 and 4 create my new PMCs. Line 3 creates a new
+C<Env> PMC which at the moment of its existence contains a
+hash of all of the environment variables currently in the
+environment. Line 4 creates a new C<Iterator> PMC and
+initializes it with the PMC that I wish to iterate over
+(my newly created C<Env> PMC in this case). From that point
+on, I treat the C<Iterator> much the same way I first
+treated the PMC of command line arguments. Test if it's
+"empty" (the iterator has been exhausted) and shift elements
+from the C<Iterator> in order to walk from one end of the
+aggregate to the other. A key difference is however, I'm
+not modifying the original aggregate, just the C<Iterator>
+which can be thrown away or reset so that I can iterate the
+aggregate over and over again or even have two iterators
+iterating the same aggregate simultaneously. For more
+information on iterators, see
+L<parrot/docs/pmc/iterator.pod>
+
+So, to output the environment variables, I use the
+C<Iterator> to walk the keys, and then index each key into
+the C<Env> PMC to get the value associated with that key and
+then output it. Simple. Say ... couldn't I have iterated
+over the command line this same way? Sure!
+
+=head3 Example 6: reading command line arguments, take 3
+
+ .sub _ :main
+ .param pmc args
+ .local pmc cmdline
+ cmdline = new 'Iterator', args
+ loop:
+ unless cmdline goto end_loop
+ $S0 = shift cmdline
+ print $S0
+ print "\n"
+ goto loop
+ end_loop:
+ .end
+
+Notice how this code approaches the simplicity of the
+original that destructively iterated the C<args> PMC. Using
+indexes can quickly become complicated by comparison.
+
+=head2 How do I create my own PMC type?
+
+That's really beyond the scope of this article, but if
+you're really interested in doing so, get a copy of the
+Parrot source and read the file C<docs/vtables.pod>.
+This file outlines the steps you need to take to create
+a new PMC type.
+
+=head2 A few more PMC examples
+
+I'll conclude with a few examples without explanation. I
+encourage you to explore the Parrot source code and
+documentation to find out more about these (and other) PMCs.
+A good place to start is the docs directory in the Parrot
+distribution (parrot/docs)
+
+=head3 Example 7: Output random numbers
+
+ .sub _ :main
+ $P0 = new 'Random'
+ $N0 = $P0
+ print $N0
+ print "\n"
+ $N0 = $P0
+ print $N0
+ print "\n"
+ .end
+
+=head3 Example 8: Triggering an exception
+
+ .sub _ :main
+ $P0 = new 'Exception'
+ $P0 = "The sky is falling!"
+ throw $P0
+ .end
+
+=head3 Example 9: Setting a timer
+
+ .include "timer.pasm" # for the timer constants
+
+ .sub expired
+ print "Timer has expired!\n"
+ .end
+
+ .sub _ :main
+ $P0 = new 'Timer'
+ $P1 = global "expired"
+
+ $P0[.PARROT_TIMER_HANDLER] = $P1 # call sub in $P1 when timer goes off
+ $P0[.PARROT_TIMER_SEC] = 2 # trigger every 2 seconds
+ $P0[.PARROT_TIMER_REPEAT] = -1 # repeat indefinitely
+ $P0[.PARROT_TIMER_RUNNING] = 1 # start timer immediately
+ global "timer" = $P0 # keep the timer around
+
+ $I0 = 0
+ loop:
+ print $I0
+ print ": running...\n"
+ inc $I0
+ sleep 1 # wait a second
+ goto loop
+ .end
+
+
+=head2 Author
+
+Jonathan Scott Duff <duff at pobox.com>
+
+=head2 Thanks
+
+=over 4
+
+* Alberto Simões
+
+=back
+
+=cut
Deleted: trunk/docs/user/pir/pp001-intro.pod
==============================================================================
--- trunk/docs/user/pir/pp001-intro.pod Mon Mar 16 21:06:48 2009 (r37500)
+++ /dev/null 00:00:00 1970 (deleted)
@@ -1,347 +0,0 @@
-# $Id$
-
-# One first version of this article was published on TPR 2.3
-#
-# Please feel free to edit it to suit latest parrot developments,
-# and to be a good starting point for beginners.
-
-=head1 Writing PIR
-
-PIR (Parrot Intermediate Representation) is a way to program the
-parrot virtual machine that is easier to use than PASM (Parrot
-Assembler). PASM notation is like any other assembler-like format and
-can be used directly, but it is more verbose and gives too much power
-to the user. PIR abstracts common operations and conventions into a
-syntax that more closely resembles a high-level language. PIR allows
-the programmer to write code that more naturally expresses their
-intent without worrying about setting up the exact details that PASM
-requires to function properly.
-
-This article will show the basics on programming in PIR. More advanced
-topics will appear in later articles.
-
-=head2 Getting Parrot
-
-In order to test the PIR and PASM code in this article, a parrot virtual
-machine is needed (henceforth just "parrot"). Parrot is available from
-L<http://parrot.org>. Just download the latest release, or checkout
-the current development version from the SVN tree. The programs in this
-article were tested with Parrot 0.8.1.
-
-Parrot is very easy to compile on unix-like and Microsoft Windows
-operating systems: just run C<perl Configure.pl && make> in the root
-directory of the parrot source and, if everything works correctly, a
-C<parrot> executable should appear. At the moment of writing, the
-C<make install> target does not work properly, so in this and other
-articles it is assumed that the parrot executable is invoked from the
-parrot root directory.
-
-If you do not want to compile your own Parrot you can download a pre-compiled
-binary from http://www.parrot.org/source.html.
-
-=head2 Parrot Virtual Machine overview
-
-Before we get started with the examples, here's a quick overview of
-parrot's architecture.
-
-Parrot is a register-based virtual machine. It provides 4 types of
-registers. The register types are:
-
-=over 4
-
-=item I - integer
-
-=item N - floating point
-
-=item S - string
-
-=item P - polymorphic container (PMC)
-
-=back
-
-In order to designate a register in PASM, use the character indicating
-the type (C<I>, C<N>, C<S> or C<P>) and the register number. For instance,
-in order to use register 10 of type integer, you'd write C<I10>. In this
-series of articles, we will mainly focus on programming PIR.
-
-In PIR, you would type the C<$> character in front of the register, to
-indicate a I<virtual> register. For instance, the integer registers are
-C<$I0>, C<$I1> and so on. The PMC registers hold arbitrary data objects
-and are parrot's mechanism for implementing more complex behavior than the
-ones that can be expressed using the other 3 register types alone.
-
-A virtual register is mapped to an actual register by the register allocator.
-You can use as many registers as you want, and the register allocator will
-allocate them as needed.
-
-PMCs will be covered in more detail in a future article. Examples in
-this article will focus on the first 3 register types.
-
-=head2 Simple Operators
-
-Let me start with a simple and typical example:
-
- .sub main :main
- print "hello world\n"
- .end
-
-To run it, save the code in a C<hello.pir> file and pass it to the
-parrot virtual machine:
-
- ./parrot hello.pir
-
-Note that I am using a relative path to parrot given that I didn't
-install it into the system.
-
-The keywords starting with a dot (C<.sub> and C<.end>) are PIR directives.
-They are used together to define subroutines. After the C<.sub> keyword
-I use the name of the subroutine. The keyword that starts with a colon
-(C<:main>) is a pragma that tells parrot that this is the main body of the
-program and that it should start by executing this subroutine.
-By the way, I could use C<.sub foo :main> and Parrot will use the C<foo>
-subroutine as the main body of the program. The actual name of the
-subroutine does not matter as long as it has the C<:main> pragma. If you
-don't specify the <:main> pragma on any subroutine, then parrot will start
-executing the first subroutine in the source file.
-The full set of pragmas are defined in L<docs/pdds/pdd19_pir.pod>.
-
-Before going into more details about subroutines and calling
-conventions, let's compare some PIR syntax to the equivalent PASM.
-
-If I want to add two integer registers using PASM I would use the
-Parrot C<set> opcode to put values into registers, and the C<add>
-opcode to add them, like this:
-
- set $I1, 5
- set $I2, 3
- add $I0, $I1, $I2 # $I0 yields 5+3
-
-PIR includes infix operators for these common opcodes. I could write
-this same code as
-
- $I1 = 5
- $I2 = 3
- $I0 = $I1 + $I2
-
-There are the four arithmetic operators as you should be expecting, as
-well as the six different comparison operators, which return a boolean
-value:
-
- $I1 = 5
- $I2 = 3
- $I0 = $I1 <= $I2 # $I0 yields 0 (false)
-
-I can also use the short accumulation-like operators, like C<+=>.
-
-Another PIR perk is that local variable names may be declared and used
-instead of register names. For that I just need to declare the
-variable using the C<.local> keyword with any of the four data
-types available on PIR: C<int>, C<string>, C<num> and C<pmc>:
-
- .local int size
- size = 5
-
-Note that all registers, both numbered and named, are consolidated by
-the Parrot register allocator, assigning these "virtual registers" to
-actual registers as needed. The register allocator even coalesces two
-virtual names onto the same physical register when it can
-prove that they have non-overlapping lifetimes, so there is no need to
-be stingy with register names. To see the actual registers used, use
-C<pbc_disassemble> on the C<*.pbc> output. You can generate a Parrot
-Byte Code (PBC) file as follows:
-
- ./parrot -o foo.pbc --output-pbc foo.pir
-
-Then, use C<pbc_disassemble> in order to disassemble it:
-
- ./pbc_disassemble foo.pbc
-
-=head2 Branching
-
-Another simplification of PASM are branches. Basically, when I want to
-test a condition and jump to another place in the code, I would write
-the following PASM code:
-
- le $I1, $I2, LESS_EQ
-
-Meaning, if C<$I1> is less or equal than C<$I2>, jump to label
-C<LESS_EQ>. In PIR I would write it in a more legible way:
-
- if $I1 <= $I2 goto LESS_EQ
-
-PIR includes the C<unless> keyword as well.
-
-=head2 Calling Functions
-
-Subroutines can easily be created using the C<.sub> keyword shown
-before. If you do not need parameters, it is just as simple as I show in
-the following code:
-
- .sub main :main
- hello()
- .end
-
- .sub hello
- print "Hello World\n"
- .end
-
-Now, I want to make my C<hello> subroutine a little more useful, such
-that I can greet other people. For that I will use the C<.param>
-keyword to define the parameters C<hello> can handle:
-
- .sub main :main
- hello("leo")
- hello("chip")
- .end
-
- .sub hello
- .param string person
- print "Hello "
- print person
- print "\n"
- .end
-
-If I need more parameters I just need to add more C<.param> lines.
-
-To return values from PIR subroutines I use the C<.return> keyword,
-followed by one or more arguments, just like this:
-
- .return (10, 20, 30)
-
-The calling subroutine can accept these values. If you want to retrieve
-only one value (or only the first value, in case multiple values are
-returned), write this:
-
- $I0 = compute_it($I8, $I9)
-
-To accept multiple values from such a function, use a parenthesized
-results list:
-
- ($I1, $I2, $I3) = compute_it($I8, $I9)
-
-=head2 Factorial Example
-
-Now, for a little more complicated example, let me show how I would
-code Factorial subroutine:
-
- .sub main :main
- $I1 = factorial(5)
- print $I1
- print "\n"
- .end
-
- .sub factorial
- .param int i
- if i > 1 goto recur
- .return (1)
- recur:
- $I1 = i - 1
- $I2 = factorial($I1)
- $I2 *= i
- .return ($I2)
- .end
-
-This example also shows that PIR subroutines may be recursive just as in
-a high-level language.
-
-=head2 Named Arguments
-
-As some other languages as Python and Perl support named arguments,
-PIR supports them as well.
-
-As before, I need to use C<.param> for each named argument, but you need to
-specify a flag indicating the parameter is named:
-
- .sub func
- .param int a :named("foo")
-
-The subroutine will receive an integer named "foo", and inside of the
-subroutine that integer will be known as "a".
-
-When calling the function, I need to pass the names of the
-arguments. For that there are two syntaxes:
-
- func( 10 :named("foo") ) # or
- func( "foo" => 10 )
-
-Note that with named arguments, you may rearrange the order of your
-parameters at will.
-
- .sub foo
- .param string "name" => a
- .param int "age" => b
- .param string "gender" => c
- # ...
- .end
-
-This subroutine may be called in any of the following ways:
-
- foo( "Fred", 35, "m" )
- foo( "gender" => "m", "name" => "Fred", "age" => 35 )
- foo( "age" => 35, "gender" => "m", "name" => "Fred" )
- foo( "m" :named("gender"), 35 :named("age"), "name" => "Fred" )
-
-and any other permutation you can think of as long as you use the named
-argument syntax. Note that any positional parameters must be passed
-before the named parameters. So, the following is allowed:
-
- .sub main
- .param int a
- .param int b :named("age")
- # ...
- .end
-
-Whereas the following is not:
-
- .sub main
- .param int a :named("name")
- .param int b # cannot declare positional parameter after a named parameter
- # ...
- .end
-
-It's also possible to use named syntax when returning values from
-subroutines. Into the C<.return> command I'll use:
-
- .return ( "bar" => 20, "foo" => 10)
-
-and when calling the function, I will do:
-
- ("foo" => $I0, "bar" => $I1) = func()
-
-And C<$I0> will yield 10, and C<$I1> will yield 20, as expected.
-
-=head2 Concluding
-
-To conclude this first article on PIR and to let you test what you
-learned, let me show you how to do input on PASM (hence, also in
-PIR). There is a C<read> opcode to read from standard input. Just
-pass it a string register or variable where you wish the characters
-read to be placed and the number of characters you wish to read:
-
- read $S1, 100
-
-This line will read 100 characters (or until the end of the line) and
-put the read string into C<$S1>. In case you need a number, just
-assign the string to the correct register type:
-
- read $S1, 100
- $I1 = $S1
-
-With the PIR syntax shown in this article you should be able to start
-writing simple programs. Next article we will look into available
-Polymorphic Containers (PMCs), and how they can be used.
-
-=head2 Author
-
-Alberto Simões
-
-=head2 Thanks
-
-=over 4
-
-=item * Jonathan Scott Duff
-
-=back
-
-=cut
-
Deleted: trunk/docs/user/pir/pp002-pmc.pod
==============================================================================
--- trunk/docs/user/pir/pp002-pmc.pod Mon Mar 16 21:06:48 2009 (r37500)
+++ /dev/null 00:00:00 1970 (deleted)
@@ -1,348 +0,0 @@
-# $Id$
-
-=head1 Programming Parrot -- PMCs
-
-=head2 Preliminaries
-
-To run the example code in this article, you'll need to
-obtain a copy of Parrot and build it for your system. For
-information on obtaining Parrot, see
-L<http://www.parrot.org/>. Instructions for compiling
-Parrot are available in the Parrot distribution itself. All
-code examples in this article were tested with Parrot 0.8.1
-
-=head2 A quick review of Parrot
-
-As mentioned by Alberto Manuel Simões in TPR 2.3, Parrot is
-a register-based virtual machine with 4 register types:
-Integer, String, Number and PMC. PIR registers are
-referenced by a C<$> character, a capital letter signifying
-the register type followed by the register number (C<$S15> is
-String register number 15). Parrot programs consist of lines of
-text where each line contains one opcode and its arguments.
-
-Each subroutine will have as many registers
-available as necessary; a simple subroutine will only need
-a few whereas complex subroutines with many calculations will
-need a larger number of registers. This is a fundamental
-difference from the original design of Parrot, in which there
-were 32 registers for each of the built-in types (int, num,
-pmc, string).
-PIR also provides for a more "natural" syntax for opcodes.
-Rather than saying C<set $I1, 0> to assign a zero to the $I1
-register, you may say instead C<$I1 = 0>.
-PIR also provides syntax for easily creating named variables
-and constants, subroutines, passing parameters to subroutines,
-accessing parameters by name, etc.
-
-Now, on to business ...
-
-=head2 What's a PMC?
-
-Integers, strings, and arbitrary floating point numbers are
-common data types in most programming languages, but what's
-a PMC? PMC stands for "Polymorphic Container". PMCs are how
-Parrot handles more complicated structures and behaviors
-(hence the magic :) Some examples of PMC usage would be for
-arrays, hashes, data structures, objects, etc. Anything that
-can't be expressed using just integers, floating point
-numbers and strings can be expressed with a PMC.
-
-Parrot comes with many types of PMC that encapsulate common,
-useful behavior.
-
-Many of the PMC type names give clues as to how they are
-used. Here's a table that gives a short description of
-several interesting and useful PMC types:
-
- PMC type Description of PMC
- -------- ------------------
- Env access environment variables
- Iterator iterate over aggregates such as arrays or hashes
- Array A generic, resizable array
- Hash A generic, resizable hash
- Random Obtain a random number
- String Similar to a string register but in PMC form
- Integer Similar to an integer register but in PMC form
- Float Similar to a number register but in PMC form
- Exception The standard exception mechanism
- Timer A timer of course :)
-
-=head2 Your wish is my command line
-
-Before I take a closer look at some of these PMC types,
-let's look at a common thing that people want to know how to
-do -- read command line arguments. The subroutine designated
-as the main program (by the C<:main> pragma) has an
-implicit parameter passed to it that is the command line
-arguments. Since previous examples never had such a
-parameter to the main program, Parrot simply ignored
-whatever was passed on the command line. Now I want Parrot
-to capture the command line so that I can manipulate it. So,
-let's write a program that reads the command line arguments
-and outputs them one per line:
-
-=head3 Example 2: reading command line arguments, take 1
-
- .sub _ :main
- .param pmc args
- loop:
- unless args goto end_loop # line 4
- $S0 = shift args
- print $S0
- print "\n"
- goto loop
- end_loop:
- .end
-
-The C<.param> directive tells parrot that I want this
-subroutine to accept a single parameter and that parameter
-is some sort of PMC that I've named C<args>. Since this is
-the main subroutine of my program (as designated by the
-C<:main> modifier to the subroutine), Parrot arranges for
-the C<args> PMC to be an aggregate of some sort that
-contains the command line arguments. We then repeatedly use
-the C<shift> opcode to remove an element from the front of
-C<args> and place it into a string register which I then
-output. When the C<args> PMC is empty, it will evaluate as a
-boolean false and the conditional on line 4 will cause the
-program to end.
-
-One problem with my program is that it's destructive to the
-C<args> PMC. What if I wanted to use the C<args> PMC later
-in the program? One way to do that is to use an integer to
-keep an index into the aggregate and then just print out
-each indexed value.
-
-=head3 Example 3: reading command line arguments, take 2
-
- .sub _ :main
- .param pmc args
- .local int argc
- argc = args # line 4
- $I0 = 0
- loop:
- unless $I0 < argc goto end_loop
- print $I0
- print "\t"
- $S0 = args[$I0] # line 10
- print $S0
- print "\n"
- inc $I0
- goto loop
- end_loop:
- .end
-
-Line 4 shows something interesting about aggregates. Similar
-to perl, when you assign an aggregate to an integer thing
-(whether it be a register or local variable, but as was explained
-before, a local variable is in fact just a symbol indicating that
-is mapped to a register), Parrot puts the number of elements in
-the aggregate into the integer thing. (e.g., if you had a PMC that
-held 5 things in C<$P0>, the statement C<$I0 = $P0> assigns 5 to
-the register C<$I0>)
-
-Since I know how many things are in the aggregate, I can
-make a loop that increments a value until it reaches that
-number. Line 10 shows that to index an aggregate, you use
-square brackets just like you would in Perl and many other
-programming languages. Also note that I'm assigning to a
-string register and then printing that register. Why didn't
-I just do C<print args[$I0]> instead? Because this isn't a
-high level language. PIR provides a nicer syntax but it's
-still really low level. Each line of PIR still essentially
-corresponds to one opcode (there are cases in which this is not
-the case, but those will be discussed later).
-So, while there's an opcode to index into an aggregate and
-an opcode to print a string, there is no opcode to do I<both>
-of those things.
-
-BTW, what type of aggregate is the C<args> PMC anyway?
-Another way to use the C<typeof> opcode is to pass it an
-actual PMC:
-
-=head3 Example 4: Typing the C<args> PMC
-
- .sub _ :main
- .param pmc args
- $S0 = typeof args
- print $S0
- print "\n"
- .end
-
-When you run this program it should output
-"ResizableStringArray". If you assign the result of the
-C<typeof> opcode to a string thing, you get the name of the
-PMC type.
-
-=head2 "You are standing in a field of PMCs"
-
-Now, let's get back to that table above. The C<Env> PMC can
-be thought of as a hash where the keys are environment
-variable names and the values are the corresponding
-environment variable values. But where does the actual PMC
-come from? For the command line, the PMC showed up as an
-implicit parameter to the main subroutine. Does C<Env> do
-something similar?
-
-Nope. If you want to access environment variables I<you>
-need to create a PMC of type C<Env>. This is accomplished by
-the C<new> opcode like so: C<$P0 = new 'Env'> After that
-statement, C<$P0> will contain a hash consisting of all of
-the environment variables at that time.
-
-But, both the keys and values the C<Env> hash are strings,
-so how do I iterate over them as I did for the command
-line? We can't do the same as I did with the command line
-and use an integer index into the PMC because the keys are
-strings, not integers. So, how do I do it? The answer is
-another PMC type--C<Iterator>
-
-An C<Iterator> PMC is used, as its name implies, to iterate
-over aggregates. It doesn't care if they are arrays or
-hashes or something else entirely, it just gives you a way
-to walk from one end of the aggregate to the other.
-
-Here's a program that outputs the name and value of all
-environment variables:
-
-=head3 Example 5: output environment
-
- .sub _ :main
- .local pmc env, iter
- .local string key, value
-
- env = new 'Env' # line 3
- iter = new 'Iterator', env # line 4
- iterloop:
- unless iter goto iterend
- key = shift iter # line 8
- value = env[key]
- print key
- print ":"
- print value
- print "\n"
- goto iterloop
- iterend:
- .end
-
-Lines 3 and 4 create my new PMCs. Line 3 creates a new
-C<Env> PMC which at the moment of its existence contains a
-hash of all of the environment variables currently in the
-environment. Line 4 creates a new C<Iterator> PMC and
-initializes it with the PMC that I wish to iterate over
-(my newly created C<Env> PMC in this case). From that point
-on, I treat the C<Iterator> much the same way I first
-treated the PMC of command line arguments. Test if it's
-"empty" (the iterator has been exhausted) and shift elements
-from the C<Iterator> in order to walk from one end of the
-aggregate to the other. A key difference is however, I'm
-not modifying the original aggregate, just the C<Iterator>
-which can be thrown away or reset so that I can iterate the
-aggregate over and over again or even have two iterators
-iterating the same aggregate simultaneously. For more
-information on iterators, see
-L<parrot/docs/pmc/iterator.pod>
-
-So, to output the environment variables, I use the
-C<Iterator> to walk the keys, and then index each key into
-the C<Env> PMC to get the value associated with that key and
-then output it. Simple. Say ... couldn't I have iterated
-over the command line this same way? Sure!
-
-=head3 Example 6: reading command line arguments, take 3
-
- .sub _ :main
- .param pmc args
- .local pmc cmdline
- cmdline = new 'Iterator', args
- loop:
- unless cmdline goto end_loop
- $S0 = shift cmdline
- print $S0
- print "\n"
- goto loop
- end_loop:
- .end
-
-Notice how this code approaches the simplicity of the
-original that destructively iterated the C<args> PMC. Using
-indexes can quickly become complicated by comparison.
-
-=head2 How do I create my own PMC type?
-
-That's really beyond the scope of this article, but if
-you're really interested in doing so, get a copy of the
-Parrot source and read the file C<docs/vtables.pod>.
-This file outlines the steps you need to take to create
-a new PMC type.
-
-=head2 A few more PMC examples
-
-I'll conclude with a few examples without explanation. I
-encourage you to explore the Parrot source code and
-documentation to find out more about these (and other) PMCs.
-A good place to start is the docs directory in the Parrot
-distribution (parrot/docs)
-
-=head3 Example 7: Output random numbers
-
- .sub _ :main
- $P0 = new 'Random'
- $N0 = $P0
- print $N0
- print "\n"
- $N0 = $P0
- print $N0
- print "\n"
- .end
-
-=head3 Example 8: Triggering an exception
-
- .sub _ :main
- $P0 = new 'Exception'
- $P0 = "The sky is falling!"
- throw $P0
- .end
-
-=head3 Example 9: Setting a timer
-
- .include "timer.pasm" # for the timer constants
-
- .sub expired
- print "Timer has expired!\n"
- .end
-
- .sub _ :main
- $P0 = new 'Timer'
- $P1 = global "expired"
-
- $P0[.PARROT_TIMER_HANDLER] = $P1 # call sub in $P1 when timer goes off
- $P0[.PARROT_TIMER_SEC] = 2 # trigger every 2 seconds
- $P0[.PARROT_TIMER_REPEAT] = -1 # repeat indefinitely
- $P0[.PARROT_TIMER_RUNNING] = 1 # start timer immediately
- global "timer" = $P0 # keep the timer around
-
- $I0 = 0
- loop:
- print $I0
- print ": running...\n"
- inc $I0
- sleep 1 # wait a second
- goto loop
- .end
-
-
-=head2 Author
-
-Jonathan Scott Duff <duff at pobox.com>
-
-=head2 Thanks
-
-=over 4
-
-* Alberto Simões
-
-=back
-
-=cut
Deleted: trunk/docs/user/pir/pp003-oop.pod
==============================================================================
--- trunk/docs/user/pir/pp003-oop.pod Mon Mar 16 21:06:48 2009 (r37500)
+++ /dev/null 00:00:00 1970 (deleted)
@@ -1,404 +0,0 @@
-# $Id$
-
-=head1 Programming Parrot -- Using objects
-
-Yes, you've read correctly. Parrot has the ability to create
-and manipulate objects (aka, object oriented programming).
-While it may seem strange for a low-level language like
-PIR to have the facility for object oriented programming,
-it makes perfect sense in this particular case. Remember,
-the original goal of Parrot was to be the underlying
-implementation for Perl6, which has object oriented
-features. Parrot's secondary goal is to provide a good
-platform for other dynamic languages such as Python, Ruby,
-PHP, Javascript, etc. and those languages too have the
-ability (if not the requirement) to be object oriented. Thus
-Parrot contains facilities for a manipulating objects so
-that language implementors can easily express the
-appropriate object semantics for their language of interest.
-
-=head2 Namespaces
-
-Before I begin talking about how to create classes and
-instantiate objects, I first need to talk about an
-intimately related subject: namespaces. Namespaces serve a
-twofold purpose, they allow you to group related routines
-together and they allow you to give several subroutines the
-same name but different, domain specific, implementations.
-These characteristics are, oddly enough, similar to the
-basic requirements for a class.
-
-For instance, you may put all of your subroutines dealing
-with people in a C<Person> namespace and all of your
-subroutines dealing with computer programs in the C<Process>
-namespace. Both namespaces may have a subroutine called
-C<run()> but with radically different implementations. Below
-is some code to illustrate this example:
-
-=head3 Example 1:
-
- .namespace [ "Person" ]
-
- .sub run
- say "Run Forrest, Run!"
- .end
-
- .namespace [ "Process" ]
-
- .sub run
- say "Running process #53"
- .end
-
-As you might guess, the C<.namespace> directive tells Parrot
-what namespace to group subroutines under. A namespace ends when
-another C<.namespace> directive changes the namespace or when
-the end of the file is reached. A C<.namespace> directive
-with no names in the brackets changes back to the root namespace.
-
-Perl programmers will recognize that Parrot
-C<.namespace> declarations are just like Perl C<package>
-declarations, albeit with different syntax.
-But there are a few other differences. I'll
-talk more about how Parrot uses namespaces and classes
-together in just a minute.
-
-=head2 PIR with class
-
-Creating classes in Parrot is relatively easy. There are
-opcodes for it. The easiest to start with is C<newclass>;
-just say C<$P0 = newclass 'Foo'> where $P0 is a PMC
-register, and 'Foo' is the name of the class you want to create.
-
-When you wish to instantiate objects that belong to the class
-you've created, it's equally simple. Just say C<myobj = new
-"Foo"> where C<myobj> is a PMC and "Foo" is the classname you've
-created with C<newclass>. Here's a simple example:
-
-=head3 Example 2: A classic Dog
-
- .sub _ :main
- $P0 = newclass 'Dog'
- .local pmc spot
- spot = new 'Dog'
- .end
-
-You may notice that I didn't use the return value of
-C<newclass>. That's only because this is a simple example. :-)
-I'll talk about what to do with the return value of C<newclass>
-a little later. Right now, let's talk about methods.
-
-=head2 Madness ... er, Methods
-
-So now that I've created a C<Dog> class, how do I add methods
-to it? Remember before when I talked about namespaces? Well,
-that's the answer. To add methods to a class, you create a
-namespace with the same name as the class and then put your
-subroutines in that namespace. PIR also provides a syntactic
-marker to let everyone know these subroutines are methods. When
-declaring the subroutine, add the C<:method> modifier after the
-subroutine name. Here's a familiar example to anyone who has
-read L<perlboot>.
-
-=head3 Example 3: Barnyard animals
-
- .namespace [ "Cow" ]
-
- .sub speak :method
- print "Moo\n"
- .end
-
- .namespace [ "Dog" ]
-
- .sub speak :method
- print "Woof\n"
- .end
-
- .namespace [ "Pig" ]
-
- .sub speak :method
- print "Oink\n"
- .end
-
- .namespace []
-
- .sub _ :main
- $P0 = newclass "Cow"
- $P0 = newclass "Dog"
- $P0 = newclass "Pig"
-
- .local pmc elsie, fido, porky
-
- elsie = new "Cow"
- fido = new "Dog"
- porky = new "Pig"
-
- elsie.'speak'()
- fido.'speak'()
- porky.'speak'()
- .end
-
-It's important to note that even though I've declared the
-namespaces and put subroutines in them, this does not
-automatically create classes. The C<newclass> declarations
-tell Parrot to create a class and as a side effect,
-namespaces with the same name as the class may be used to
-store methods for that class.
-
-One thing you may notice about method calls is that the
-method names are quoted. Why is that? If you would have left out
-the quotes, then the identifier is assumed to be a declared
-C<.local> symbol. So, instead of writing:
-
- elsie.'speak'()
-
-you could also have written:
-
- .local string speak
- speak = 'speak'
- elsie.speak()
-
-Another example of this is shown below.
-
-=head3 Example 4: variable methods
-
- .namespace [ 'Foo' ]
-
- .sub foo :method
- print "foo\n"
- .end
-
- .sub bar :method
- print "bar\n"
- .end
-
- .namespace []
-
- .sub _ :main
- $P0 = newclass "Foo"
- .local pmc f
- f = new "Foo"
-
- .local string m
- m = "foo"
- f.m()
- m = "bar"
- f.m()
- .end
-
-=head2 But where do I store my stuff?
-
-So far I've talked about namespaces and creating classes
-and associating methods with those classes, but what about
-storing data in the class? Remember how the C<newclass>
-opcode returned a PMC that I didn't do anything to/with?
-Well, here's where it's used. The PMC returned from
-C<newclass> is the handle by which you manipulate the class.
-One such manipulation involves class "attributes". Attributes
-are where you store your class-specific data.
-
-Parrot has several opcodes for manipulating attributes; they
-are: C<addattribute>, C<setattribute>, and C<getattribute>.
-The C<addattribute> opcode lets you add a spot in the class
-for storing a particular value which may be get and set with
-C<getattribute> and C<setattribute> respectively. The only
-restriction on these values is that currently all
-attributes must be PMCs.
-
-So, say I wanted to give my barnyard animals names (I'll
-illustrate with just one animal and you can infer how to do the
-same for the rest):
-
-=head3 Example 5: Naming my animals
-
- .namespace [ "Dog" ]
-
- .sub name :method
- .local pmc name
- name = getattribute self, "name"
- print name
- .end
-
- .sub speak :method
- print "woof"
- .end
-
- .namespace []
-
- .sub _ :main
- $P0 = newclass "Dog"
- addattribute $P0, "name"
-
- .local pmc dog
- dog = new "Dog"
- $P0 = new "String"
- $P0 = "Phideaux"
- setattribute dog, "name", $P0
-
- dog.'name'()
- print " says "
- dog.'speak'()
- print "!\n"
- .end
-
-Whew! There's a lot of new stuff in this code. I'll take them
-starting from the top of the program and working towards the
-bottom.
-
-One of the benefits of tagging your subroutines as methods
-is that they get a PMC named C<self> that represents the
-object they are acting on behalf of. The C<name> method
-takes advantage of this to retrieve the attribute called
-"name" from the C<self> PMC and print it.
-
-Immediately after I create the class called "Dog", I use the
-PMC handle returned from C<newclass> to add an attribute called
-"name" to the class. This just allocates a slot in the class for
-the value, it does nothing more.
-
-Next, I create a new Dog and give it a name. Because
-attributes may only be PMCs, in order to give the Dog a
-name, I first have to create a new String PMC (this is one
-of the PMCs builtin to Parrot) and assign the name I wish
-to give the dog to this PMC. Then I can pass this PMC as a
-parameter to C<setattribute> to give my Dog a name.
-
-Seems kind of complicated, doesn't it? Especially when you think
-about doing this for each animal. Each animal namespace
-would have an identical version of the C<name> method. For each
-call to C<newclass> I'd need to also call C<addattribute> so
-that all of the animals may have a name. Each time I wish to
-assign a name to an animal, I'd first need to create a
-C<String> and call C<setattribute> on it. Et cetera.
-
-Surely there's a better way?!? There is ...
-
-=head2 Inheritance
-
-You saw it coming didn't you? What's object oriented
-programming without inheritance? Parrot has an opcode
-C<subclass> that lets you inherit data and methods from an
-existing class. We can use this ability to create a base
-class called "Animal" that contains the "name" attribute and
-two methods that are common to all animals: C<setname> and
-C<getname> Then, to create new animals, I just inherit from
-the Animal base class like so:
-
-=head3 Example 6: inheriting
-
- ...
- $P0 = newclass "Animal"
- addattribute $P0, "name"
- $P0 = subclass "Animal", "Cow"
- $P0 = subclass "Animal", "Dog"
- $P0 = subclass "Animal", "Pig"
- ...
- cow = new 'Cow'
- cow.'setname'("Elsie")
- ...
- cow.'getname'()
-
-Each subclass will contain an attribute called "name" that can be
-used to store the name of the animal. The C<setname> method
-abstracts out the process of creating a C<String> PMC and
-calling C<setattribute> on it. And finally the C<getname> method
-becomes a wrapper around C<getattribute>.
-
-=head2 Wrapup
-
-I hope this gives you an idea of how to do object oriented
-programming using Parrot. The opcodes illustrated here are what
-any language implementor that targets Parrot would use to
-implement object oriented features in their language. Of course
-there are more opcodes for richer object oriented behavior
-available in Parrot. This article only covers the basics. For
-more information see parrot/docs/pdds/pdd15_objects.pod.
-
-At the end of this article is a more complete listing of the
-program that gives my barnyard animals voices. There are
-many improvements that can be made to this code so take this
-opportunity to read and experiment and learn more about OOP
-in Parrot.
-
-=head2 Acknowledgements
-
-=over 4
-
-* Thanks to Randal Schwartz for providing a neat set of
- examples in L<perlboot> from which this article
- shamelessly borrows.
-* Thanks to the Parrot people for feedback
-
-=back
-
-=head2 Author
-
-Jonathan Scott Duff
-
-=head3 Example 6: Full barnyard listing
-
- .namespace [ "Animal" ]
-
- .sub setname :method
- .param string name
- $P0 = new 'String'
- $P0 = name
- setattribute self, "name", $P0
- .end
-
- .sub getname :method
- $P0 = getattribute self, "name"
- print $P0
- .end
-
- .sub speak :method
- .local string name, sound
- name = self.'getname'()
- sound = self.'sound'()
- print name
- print " says "
- print sound
- print "\n"
- .end
-
- .namespace [ "Cow" ]
-
- .sub sound :method
- .return( "moo" )
- .end
-
- .namespace [ "Dog" ]
-
- .sub sound :method
- .return( "woof" )
- .end
-
- .namespace [ "Pig" ]
-
- .sub sound :method
- .return( "oink" )
- .end
-
- .namespace []
-
- .sub _ :main
- $P0 = newclass "Animal"
- addattribute $P0, "name"
- $P0 = subclass "Animal", "Cow"
- $P0 = subclass "Animal", "Dog"
- $P0 = subclass "Animal", "Pig"
-
- .local pmc cow, dog, pig
-
- cow = new "Cow"
- cow.'setname'("Elsie")
- dog = new "Dog"
- dog.'setname'("Snoopy")
- pig = new "Pig"
- pig.'setname'("Porky")
-
- cow.'speak'()
- dog.'speak'()
- pig.'speak'()
- .end
-
-=cut
More information about the parrot-commits
mailing list