688 lines
56 KiB
Plaintext
688 lines
56 KiB
Plaintext
|
|
Episode: 321
|
||
|
|
Title: HPR0321: Parrot
|
||
|
|
Source: https://hub.hackerpublicradio.org/ccdn.php?filename=/eps/hpr0321/hpr0321.mp3
|
||
|
|
Transcribed: 2025-10-07 16:19:54
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
music
|
||
|
|
The Utah Open Source Foundation brings the Utah Logs home.
|
||
|
|
Feel free to listen live at stream.utos.org or catch the audio afterward at podcast.utos.org.
|
||
|
|
The bandwidth is provided by Center 7.
|
||
|
|
The following presentation, Parrot, was given on March 11, 2009 by Stephen Weeks at the
|
||
|
|
Provo Linux user group.
|
||
|
|
Visit their site at plug.org.
|
||
|
|
Wow.
|
||
|
|
Wow.
|
||
|
|
Happy.
|
||
|
|
Hello.
|
||
|
|
Let's see if this works again.
|
||
|
|
My ex-server wouldn't wake up.
|
||
|
|
What?
|
||
|
|
I'm not sure.
|
||
|
|
No.
|
||
|
|
I'm not sure if it works.
|
||
|
|
I don't know.
|
||
|
|
I'm not sure.
|
||
|
|
I'm not sure.
|
||
|
|
I'm not sure.
|
||
|
|
I'm not sure.
|
||
|
|
Oh, I'm not sure.
|
||
|
|
I'm not sure.
|
||
|
|
I'm not sure.
|
||
|
|
I'm not sure.
|
||
|
|
I'm not sure.
|
||
|
|
I'm not sure.
|
||
|
|
I'm not sure.
|
||
|
|
I'm not sure.
|
||
|
|
I'm not sure if it works.
|
||
|
|
Maybe we could, kittens or adults?
|
||
|
|
Or could we wake up?
|
||
|
|
And I was trying to log in again.
|
||
|
|
It was working before.
|
||
|
|
I'm here from Guru Lab's Parrot is really cool, so excited about Parrot.
|
||
|
|
Parrot is a, it's a virtual machine for dynamic languages and video settings.
|
||
|
|
And it's also a set of compiler tools on top of that, let me see, let's click here and
|
||
|
|
just say, no, don't be disabled, shut up.
|
||
|
|
Yes, this is how I teach all the time.
|
||
|
|
I shout profanities at my laptop, that's, whoa, am I, that will have to be good enough.
|
||
|
|
Now my display right here is very, very tiny, doesn't show as much as up there does, it's
|
||
|
|
interesting.
|
||
|
|
But I don't have an ATI card, I have zero ATI cards.
|
||
|
|
I'll just look up there, how the work.
|
||
|
|
Clint doesn't have to be nice.
|
||
|
|
Anyway, right, I was saying things, sorry, a bit flustered, I'm also a bit sick, so if
|
||
|
|
I fall on the ground coughing, just leave me for a minute, I'm sure I'll be fine.
|
||
|
|
So Parrot, like I was saying, Parrot is a virtual machine for dynamic languages and it's also
|
||
|
|
a set of compiler tools for building your own compiler for Parrot.
|
||
|
|
One of the main goals of Parrot is to be able to allow all these different languages to
|
||
|
|
interoperate with each other.
|
||
|
|
You write your Ruby script, we're getting there, right now, at this very moment, most of
|
||
|
|
that doesn't work because most of the languages library is, well, we're getting ready for
|
||
|
|
our release in six days, six days will be the Parrot 1.0 release, which is good.
|
||
|
|
How many people here know anything about Parrot, read about it, looked at it, okay.
|
||
|
|
So the main thing I'm going to present on here is I wrote a little scheme compiler in
|
||
|
|
Parrot and we're going to run through how to build the compiler and implement scheme.
|
||
|
|
I had this prepared in advance and I apparently deleted it, I'm not sure, it wasn't on my
|
||
|
|
laptop as of midnight last night.
|
||
|
|
So I wrote it again in about three hours today, so that's good.
|
||
|
|
These penguins here, the goal for these penguins is if you wanted a penguin, you have to
|
||
|
|
ask me a question during my presentation.
|
||
|
|
Your question is going to be if you can have a penguin, isn't it?
|
||
|
|
That's a meaningful question, too.
|
||
|
|
So any questions before I get started here?
|
||
|
|
It might be one on IRC.
|
||
|
|
It might be, I should, I could try to pay a tanking IRC.
|
||
|
|
Yeah, that's good.
|
||
|
|
Apparently he raised his hand but he doesn't ask the question so we'll wait.
|
||
|
|
That's good.
|
||
|
|
All right, so let's talk about Parrot.
|
||
|
|
All right, so the very first thing I did to try to build this compiler is around this.
|
||
|
|
There's this little tool of make language shell and go ahead and just run a Parrot slash
|
||
|
|
live slash one to bell, tools, dev, that's not right, I don't care, anyway, get it, check
|
||
|
|
it out, one.
|
||
|
|
Here we are, creates this little directory for you, it's got the very basics implemented.
|
||
|
|
It's with little test, which all this language is, is just say statement.
|
||
|
|
It's the word say, followed by some text and a semicolon.
|
||
|
|
So we can compile this, see if it works, then I'll show you a little bit about what we
|
||
|
|
have here.
|
||
|
|
All right, so if I run a Parrot on this steam.pbc, that's for Parrot bytecode, that's the
|
||
|
|
compiled bytecode repeating myself here, run it on, it's yours or say, so it apparently
|
||
|
|
works.
|
||
|
|
All right, so let's walk through the different stages of this compiler, the very first stage
|
||
|
|
is going to be the parsing, so we need a grammar here, so let's source, parser, grammar.pg
|
||
|
|
or program, these are purl six rules, kind of like regular expressions, and so it's
|
||
|
|
got comments here in pod, which is purls, markup, purls, commenting stuff, so you're going
|
||
|
|
to find a grammar, it inherits from the PCT grammar, PCT is the Parrot compiler tools.
|
||
|
|
All right, so we start off with a rule, it's kind of like a regular expression, there are
|
||
|
|
two things here, rules and tokens.
|
||
|
|
The difference is that in rules, white space is significant, any section of white space
|
||
|
|
is replaced with a call to the WS rule, and so it's white space in your rule here represents
|
||
|
|
white space in what you're trying to parse, right, which it'll work out, doesn't matter
|
||
|
|
that much, we'll see it in a minute, anyway, so we want to parse inside of angle brackets
|
||
|
|
is calling a named other rule, right, so it calls the statement rule, which if we look
|
||
|
|
down here, that's the liberal text, say, followed by an expression, find later on, followed
|
||
|
|
by a comma, another expression, any other, most of you familiar with regular expressions
|
||
|
|
to some degree, vaguely kind of shut up.
|
||
|
|
If anything I'm talking about just makes no sense to you at all, just throw something
|
||
|
|
at me, or shout angrily, or let me know somehow, or, no, not at me, it's no things at
|
||
|
|
pause, so, but care, anyway, calls the expressions, goes on like that, pretty straightforward, it's
|
||
|
|
a pretty simple syntax, I'm not going to get into it too much with this, we'll talk about
|
||
|
|
the scheme syntax, which I'm going to show you in just a minute, let's just go ahead
|
||
|
|
and move to that, whenever moving along too quickly, or, I'll just trust you guys to
|
||
|
|
harass me appropriately, anyway, the changes that I made here, right, a statement, which
|
||
|
|
this top rule that's where it comes in, it starts parsing here, so any number of statements
|
||
|
|
is a valid program, and after that it's either, the end of the string, so the dollar sign
|
||
|
|
means is the end, or it panics, or they syntax error, so just bail out, so first we start
|
||
|
|
with an open parenthesis, it's going to be a symbol, which I define all the way down
|
||
|
|
here as just the built-in little thing identifier, which is, you know, ASCII, I'm sorry, a word
|
||
|
|
character, letters, numbers, alpha numerics, that's what I was going for, some number of
|
||
|
|
those, and I'm giving it the name, CMD for a command that you're running on scheme, right,
|
||
|
|
the scheme syntax, hopefully all familiar with this, ASXpressions, so that'll be something
|
||
|
|
like, you know, print, hello, right, something like that, it's going to be your scheme, vaguely,
|
||
|
|
I don't actually delete no scheme, so this is based on little tutorials and grammar
|
||
|
|
references and such, and then some number of other terms, which I'm going to find down
|
||
|
|
here, become down a term, this leading a bar that's an OR, usually you'd see that in
|
||
|
|
some kind of grouping, there's no grouping, so this just means either it's a value, or
|
||
|
|
it's a symbol, right, so match those value, we come up here, that's this rule, right, that's
|
||
|
|
either an integer, which is defined right here, or a quotation, right, which is defined
|
||
|
|
here using some built and stuff, that just means either an apostrophe or the double quotes,
|
||
|
|
and then everything leading up to the trailing double product, so I am skipping over kind of
|
||
|
|
a lot, if you want me to stop and go into anything that I skip over, again, let me know,
|
||
|
|
right, and then it has to be a close, now this special little curly brace star,
|
||
|
|
close curly brace, what this means is, this is a use when we're actually trying to
|
||
|
|
transform our parse tree farther down, but let's get into that in just a minute, so first
|
||
|
|
let's see if this works, right, let's see if this parses some basic stuff, all right, so
|
||
|
|
let's recompile it, oh go away, I don't want that right now, that's my take typing
|
||
|
|
breaks thing, so my hands don't hurt, let's run parrot on steam.pbc, whoops, and let's
|
||
|
|
say dash dash target equals parse, so let's see what happens, what it spits out when we
|
||
|
|
give it a little expression, right, so let's say say hello, oh, and that's worked earlier,
|
||
|
|
aha, did work earlier today, what's, what, since when, it's interesting, oh, oh this is going
|
||
|
|
to be nice, let's see if it works anyway, what does work, so there's that, but no dump, oh,
|
||
|
|
I guess it does work now, yeah, don't worry about it, I don't care, anyway, this is our parse
|
||
|
|
tree, right, and so it takes the entire, except from that regular, from those rules, and it says,
|
||
|
|
well here's the entire parse, was this text right here, say hello, well that contains one
|
||
|
|
statement, which is, this right here, say hello, that contained a CMG, you remember earlier,
|
||
|
|
I assigned that name right, see here, CMD equals, and call the symbol rule, so CMD contains an
|
||
|
|
identifier, which was, say, there's also one term here, which, well that was a repetition, right,
|
||
|
|
it's got that star, so that's inside of an array, of size one, which contained a value,
|
||
|
|
which was a quote, which was a string literal, which was, hello, is this parse tree pretty
|
||
|
|
clear for everyone, right, this is just the, well, not repeating myself again, right, so yes,
|
||
|
|
how many people have written parses? I don't know, oh, I don't know, oh you were asking them,
|
||
|
|
not me, you're clever man, I haven't implemented any sort of compiler, well, a little bit for other
|
||
|
|
stuff, I like this a lot better than some of the other options for parsers, so anyway, the next
|
||
|
|
step is to take that, I just set up a bunch of aliases right here, all that is, is steamed
|
||
|
|
as just hard equals parse, saves me on type, right, so we want to compile this down, the next
|
||
|
|
step is an abstract syntax tree, so we're going to see, can everyone read this font size
|
||
|
|
comfortably? All right, so what we want is just an abstract representation of the sort of
|
||
|
|
things we want to do, right, this is going to be very high level view of our program, it's going
|
||
|
|
to be things like run a command with these arguments, right, so the next layer down, let me show you
|
||
|
|
what that looks like, this is a past block, past tense for parrot abstract syntax tree, there's a bunch of
|
||
|
|
classes in that namespace, right, we've got blocks, we've got operations, variables, values,
|
||
|
|
right, so we're saying that this is a block, is our entire program, and that's a declaration of
|
||
|
|
the par, we'll get into that in a minute, this is an operation, the type of operation is call, so a
|
||
|
|
function call, and this has two sub nodes, right, all of these nodes, all of these past nodes have two
|
||
|
|
parts, they have named parameters, you can see in here, so it's kind of like a Python dictionary or
|
||
|
|
purl hash, and there's also positional items, so this is kind of like a, both the hash and an array
|
||
|
|
together, or a dictionary and an array together, so the two items in here are a past var, right, so a new
|
||
|
|
variable, whose name, the name of the variable is say, and its scope is package scope, kind of like
|
||
|
|
global scope, I don't look in the namespace, and the past value is hello, so call the save function,
|
||
|
|
which is in our global namespace on the text hello, is that pretty, pretty clear, any question
|
||
|
|
now what this is doing, all right, so the way we get the, the way we get there is the compiler is
|
||
|
|
actually calling, every time it gets to one of these little curly brace, star, close, curly brace,
|
||
|
|
it calls a function often in other namespace, and it passes it this entire match, and then that
|
||
|
|
other function constructs those objects, right, so in this top rule, what it does is it says, oh well,
|
||
|
|
this is my entire program, so I'm going to make a block, I'm going to shove every item in there
|
||
|
|
as a statement in that block, right, as an operation, and so we see that's exactly what it is right here,
|
||
|
|
method top, it accepts this dollar sign slash, now this file here is written in a subset of
|
||
|
|
purl six, called not quite purl, it's a very restricted purl six, and so it doesn't support a lot
|
||
|
|
of the, a lot of the fancy things, just the basic syntax, for example it doesn't have assignment,
|
||
|
|
it only has binding, just kind of like a, by reference instead of by value, so we see right here,
|
||
|
|
it's accepting this dollar slash, that's the match object, and so that that's, everything
|
||
|
|
goes in there, when we said target equals parse, and it printed that out, that's the object that
|
||
|
|
this thing gets, so what we're going to do here is we're going to create and bind this variable,
|
||
|
|
the difference between assignment and binding isn't that much that you really need to care about,
|
||
|
|
it just means it doesn't get a new copy, it's just they're all pointing to the same data structure,
|
||
|
|
going to create a new pass block, so passblock.new, this colon and the word followed by parentheses,
|
||
|
|
that's purl six is a named argument passing, so we're going to create a block with block type
|
||
|
|
declaration, and this node thing here, that's for introspection, right, where it said,
|
||
|
|
right here, where it can tell what was going on here, right, this pass over is created from,
|
||
|
|
or this, some other stuff, yeah, not actually important, that's just extra stuff, anyway,
|
||
|
|
so we're going to iterate over, right, remember the statements, we're in array, right, it's,
|
||
|
|
our statements are in array, right, because of any number of them, so we iterate over them,
|
||
|
|
for each statement, you're going to push into it, right, because this block has a list of
|
||
|
|
statements, and a list of things it's going to do, now again we have some special syntax,
|
||
|
|
right, this is not quite purl, it's used here, it's mostly just special idioms, right,
|
||
|
|
this dollar sign parentheses means that this, if you haven't worked with purl, the dollar sign
|
||
|
|
underscore, that's the current topic, right, so for each time goes through this for loop,
|
||
|
|
it's, this dollar sign underscore is set to each item in there, don't bother with the name,
|
||
|
|
because we're not doing much special with it, so this dollar sign parentheses means get the syntax
|
||
|
|
tree representation of each of these objects, right, so, so go ahead and compile the syntax tree
|
||
|
|
for each one of those statements, and then give it back to me, and push it inside of this block,
|
||
|
|
right, so if I had multiple of those, right, I can go ahead and do that,
|
||
|
|
you know, say one, say two, we have two past ops, right, two operations in term,
|
||
|
|
pretty straightforward, and these are children at the block, so we've gone through this a little bit more,
|
||
|
|
we won't go through the whole thing unless someone asks me to, there's, well we'll get to it eventually,
|
||
|
|
right, so it's going to call the rule for those statements, right, so that's method statement,
|
||
|
|
again it accepts a match object, this says I want to create a new past op, right, an operation,
|
||
|
|
right, like a function call or a method call or something like that, on, again we see this dollar sign
|
||
|
|
so get the syntax tree of this, right, of this CMD thing, which is a symbol, and so we can chase that
|
||
|
|
down, come down here and see that for symbols, right now I'm doing, say make a new past variable,
|
||
|
|
whose name is, whatever was in the ident, part of the match, and whose scope is packet, so a
|
||
|
|
globally scope variable, right, and I'll show you in a little bit where that save function is defined,
|
||
|
|
it's not just magic, we'll get to it, all right, so inside the statement,
|
||
|
|
new past op, that past type call, so call that function, and for each one of those terms,
|
||
|
|
I remember term again was any number of these, push those into the op, okay, pretty straightforward,
|
||
|
|
and then the make command means set this as the syntax tree representation for this node,
|
||
|
|
it's kind of like return, it's slightly different for some reasons we're not going to get into,
|
||
|
|
but you can think of it as just returning it back into one of these calls here, right, that's what
|
||
|
|
that is, so any questions about how this is working, how this compiles that, that parse tree
|
||
|
|
down into a syntax tree, all right, so now parrot takes that abstract syntax tree,
|
||
|
|
next step it goes to is it compiles it down into a, well, couple steps, it compiles it down
|
||
|
|
into peer essentially, which is the parrot intermediate representation, that's essentially a
|
||
|
|
parrot's version of assembly, right, so I say say hello, it says dot sub create a new subroutine
|
||
|
|
with some garbage out here that we don't care about, so what we're going to do is we're going to
|
||
|
|
look in the global namespace, fetch it into a register, my parrot is a register based virtual
|
||
|
|
machine, not a stack based virtual machine like many others, who has done any kind of assembly
|
||
|
|
stuff, all right, so look up with this string say, and then we're going to save the result of
|
||
|
|
calling this function with the value hello, and then we're going to return it, so that's all it
|
||
|
|
does, right, pretty straightforward, any questions so far about how this works, all right, no questions,
|
||
|
|
oh, I guess I'll keep my penguins to myself, all right, so let's start implementing a little bit
|
||
|
|
more, this is a little not exciting, so let's check out next step, right, some basic math operations,
|
||
|
|
nested expressions, so let's see what we changed in here, first thing we changed, we're defining
|
||
|
|
more of these, right, in this built-ins directory, the make file compiles, you know, concatenates them
|
||
|
|
all together and then includes them in the bytecode, so let's take a look at these, all right,
|
||
|
|
the one we already have was that say function, the source built-ins say dot peer, this is just dot sub say,
|
||
|
|
we want to accept one parameter, which just slurps up, right, it accepts as many parameters,
|
||
|
|
sorry, as many arguments as we pass to it, it solves them inside of an array here called args,
|
||
|
|
yeah, that's a modifier to this, right, it says, yeah, that basically says for the calling
|
||
|
|
conventions, however many arguments are passed, just shove along into an array and put them inside
|
||
|
|
of this variable here, this is written in peer, it's a parrots assembly language,
|
||
|
|
so it's not, I mean, it looks kind of a little bit like, it's very high level for an assembly
|
||
|
|
language, so we create a new, we sign a name, parrot has four different kinds of registers,
|
||
|
|
right, there has four different kinds of registers and you see what the dollar sign out in front
|
||
|
|
for reasons we don't get into, but then it's a capital letter and a number, or four different
|
||
|
|
kinds of registers, there's PMs, well there's integers, right, so a whole number, there's
|
||
|
|
num registers, which are a float, right, there's string registers which contain some amount of text,
|
||
|
|
there's PMC registers, sensor parrot magic cookie, which basically means an object, right,
|
||
|
|
some sort of high level object, it could be an array, it could be a socket, it could be, you know,
|
||
|
|
some custom user class that you've made, it could be anything else, right,
|
||
|
|
and so this is just giving a name to a PMC register called it, it create a new object of the iterator
|
||
|
|
class, pass these args, and then just loop over it, keep pulling something out, printing it,
|
||
|
|
and then looping back, print a new line, and then we're done, so you define this little built-in,
|
||
|
|
once you get most of your language up a bit higher, you can start, you know, of course,
|
||
|
|
defining your libraries in terms of, you know, actually writing them in their own code, the
|
||
|
|
parrot's purl six implementation, for example, has a decent amount that's written in purl six itself,
|
||
|
|
I think, I think their PHP implementation might be doing a little bit of that, I'm not sure,
|
||
|
|
or a few others, anyway, we also added this math.purify, I'll just define some little basics,
|
||
|
|
so we create a subroutine called plus, which will add two values, we create a subroutine called minus,
|
||
|
|
which will subtract them, star from multiply, slash for divide.
|
||
|
|
These are actually op-codes already.
|
||
|
|
Yeah, that's what I'm saying, so you have to define those in a subroutine.
|
||
|
|
Right, this is a very high-level assembly language, which is kind of fun,
|
||
|
|
and what else do we do in here?
|
||
|
|
So we add those, and change the grammar a little bit around, I made it so that a term could
|
||
|
|
also be a statement, right, which you remember statement is a full-ass expression,
|
||
|
|
and I also changed the symbol rule to instead of just be alpha numeric to be any character other
|
||
|
|
than white space and parentheses, so that I can actually call the plus function and things like that.
|
||
|
|
All right, so if I compile this, I can then run it, and we'll say say plus one two.
|
||
|
|
Okay, pretty straightforward. Also, with each of these, I've been updating the tests,
|
||
|
|
right, so I now have that this is the tap format, what is it, the test anything protocol,
|
||
|
|
choose a law in the purl world, just print out the number of tests, and then okay one, okay two,
|
||
|
|
okay three, okay four, right, so if I make tests, it runs, T slash zero zero sanity, okay,
|
||
|
|
all tests successful. How do I actually just run steam on the file, it prints everything out?
|
||
|
|
Let's work on okay so far. Yeah.
|
||
|
|
Do you have to do like pause convention, excuse me, the drag?
|
||
|
|
In steam? Yes. Parrot actually has, and this is one reason that I kind of was a little unsure
|
||
|
|
about using steam for this, but actually has an additional way that you can use its parsing engine
|
||
|
|
to do bottom up parsing instead, so you actually just define a table of operators, right?
|
||
|
|
You define, well here, here I've got my infix plus, and I've got my prefix, you know minus to
|
||
|
|
do negatives, and they're all, you know, the infix plus is higher precedents or lower precedents,
|
||
|
|
and the infix multiply, and then you just define all those rules, and then you say can be a token
|
||
|
|
here, and we'll go through and just parse out, you know, all that infix math and all of that,
|
||
|
|
so there is some really nice stuff for that. If we have time at the end, we can go into that too,
|
||
|
|
as well, if someone wants. Someone asked a question, he gets a penguin.
|
||
|
|
All right, so what comes next? I don't even remember what order I did these in.
|
||
|
|
Up until now, I think I got about here by 1am this morning, four should come next.
|
||
|
|
Yes, yes, I got through to this part by 138, so implementation of the special form if,
|
||
|
|
right, which is just, you know, if, and then you have some condition, right,
|
||
|
|
if 1 is less than 2, then do this, otherwise do that. This is what it looks like in scheme.
|
||
|
|
Pretty straightforward, so let's actually take a look at what we changed here.
|
||
|
|
All right, so I added some comparison functions, let's take a look at those.
|
||
|
|
All right, I did sub equals. If they, if these two are equal, then jump to the true label,
|
||
|
|
which is down here, and return one. Otherwise, just fall through and return zero.
|
||
|
|
Same thing for less than greater than, less than or equal, greater than or equal.
|
||
|
|
You see, I'm just using these built-in parrot ops, which are, again, it's a very high-level language,
|
||
|
|
or assembly language. And we also did, right, there we go. I'll just pull it up.
|
||
|
|
Instead of the, whoops, instead of the diff, and what we have here is I changed the statement rule
|
||
|
|
to first check for one of the special forms, which have their own special parsing rules.
|
||
|
|
For example, instead of just like a function call, you don't want to evaluate both branches first
|
||
|
|
to pass the argument in. That would be bad if you evaluate both branches of the conditional.
|
||
|
|
So we check them both and only evaluate the one that's appropriate.
|
||
|
|
If it doesn't match any of those, then we call the simple rule, which is just what it was before.
|
||
|
|
So the special right down here, well, that's just the if rule. Now, one thing that you'll
|
||
|
|
see right here in a few places, this hash equals, then a word, that's when something could match
|
||
|
|
in a variety of different ways. And you want the parser engine to actually tell you which it was.
|
||
|
|
So the way that's actually implemented is down here in the statement rule,
|
||
|
|
and now except a second parameter here, which is a key. And that's which one of those
|
||
|
|
things actually matched, right? So what I do is I take, you know, just return the syntax tree for
|
||
|
|
the key named sub match of dollar slash, which is the match. So just actually return by far,
|
||
|
|
it's just the same thing that's in here. So it just tells you it matched simple instead of
|
||
|
|
special or special instead of simple, to simplify your rules there. Fun losing you that's not
|
||
|
|
too important. We'll see it again a few times. So it comes out here, tries to match if,
|
||
|
|
for if that's the literal text, if, and then one term, another term and a third term. So I'm
|
||
|
|
just naming them condition, if it's true, if it's false. And then we call this, right? If you're
|
||
|
|
just doing matching, right, if you're just trying to do, you know, the equivalent of regular
|
||
|
|
expression, you don't need to do anything special with it, you don't need this special curly thing,
|
||
|
|
right? So let me show you what, if, implements. So you have method if, that makes a new past operation,
|
||
|
|
it creates a new one. The three arguments are the condition, if it's true, and if it's false.
|
||
|
|
And then the past type, I saw earlier, right down here for a simple, so that's just a past type of
|
||
|
|
call, it's a function call. This past type is if, for doing conditionals, right? The
|
||
|
|
paracompilot will provide a lot of default implementations that make a lot of sense. We can
|
||
|
|
actually take a look at the documentation, docs, d, pdd, 26, st. It's also in some more reasonable
|
||
|
|
path, but that's the one I actually remember. So we look for past op, that can be past type of
|
||
|
|
copy, bind, or if the first, second, and third children represent the condition, the then,
|
||
|
|
and the else parts of a conditional expression. First, child's evaluated, if it's true, then the
|
||
|
|
second's evaluated, if it's false, and the third's evaluated. Pretty straightforward.
|
||
|
|
So we can actually see that, that's what the syntax tree looks like. We compile it,
|
||
|
|
we see if it works, we say, say, if, one is less than zero,
|
||
|
|
hello, hello, or goodbye. But if one is greater than zero, we say, hello, okay. Let's do a
|
||
|
|
dash dash target equals past, and we see it did actually make a past op of if, that's a child
|
||
|
|
of past type call, so call the save function on this past op. If you want to look at the
|
||
|
|
period generates, that's just target equals peer, if less than one zero, hello, or goodbye.
|
||
|
|
We see it get global that, if this jump to this value down here, and then go on and run these,
|
||
|
|
otherwise, make a goodbye, and then jump down to the end where it returns it. So that's what it
|
||
|
|
will generate for each one of these. It's pretty straightforward, completely losing you, and
|
||
|
|
because it was more typing. And I can do the same thing here.
|
||
|
|
Right. So in this case, the first get global say, then to the end down here, it calls this function,
|
||
|
|
which are retrieved up here, and it calls this function on which ever value it did here,
|
||
|
|
so I decided to set it to this or set it to that, and call the function on it.
|
||
|
|
So any questions so far about this? Pretty clear? All right. So the rest is just
|
||
|
|
implementing more of the special forms. So just adding more to our scheme compiler.
|
||
|
|
I think next is five? Whoa, I apparently can count. No, that's the same one. Oh wait, no, that was
|
||
|
|
previous. We'll skip that one for now. Okay, we define works, that's actually setting new variables.
|
||
|
|
Oh, oh way. Ah, right. And so we first make a grammar change, right? Here in our special rule,
|
||
|
|
say it could also be a define. And what that looks like is inside of the parentheses, right? Because
|
||
|
|
remember, special is called from something that says parentheses. So inside it, ask expression,
|
||
|
|
it starts with the literal text, define. And then I added some stuff here for error checking,
|
||
|
|
and I pulled it out later, so it doesn't matter much. But basically it's just define, and then
|
||
|
|
a variable you want to create, and what you want to set it to. Pretty straight forward, right?
|
||
|
|
And that in scheme is just define a as one. So let me show you what the grammar rule for that
|
||
|
|
looks like. It just says my variable, going to bind it to the syntax tree for variable, right,
|
||
|
|
for that match. And then I also set this is decal. That says, this is a declaration. I'm creating a
|
||
|
|
new variable here, right? It's not something that already exists, so don't try to fetch it,
|
||
|
|
just create a new one. And my value, that's that. So now we make a past op, the past type bind,
|
||
|
|
right? So actually do an assignment to this value, assign to the variable, the value.
|
||
|
|
Pretty straight forward. So we can try this, right? There are make, define, message.
|
||
|
|
Thank you, Clint.
|
||
|
|
Hello world. Say the message. It works. Fantastic, right?
|
||
|
|
Oh, I made some tests for if and for define, we run make test, we see they all pass.
|
||
|
|
See the if test pass prints out, define test prints out.
|
||
|
|
Pretty straightforward. If you want to actually look at the syntax tree for that,
|
||
|
|
right? You say steam dash dash target equals syntax tree, define a as one.
|
||
|
|
So you see it just calls bind a newly declared variable named a, that's in package scope,
|
||
|
|
but it got that from that symbol rule, right? Which creates a new variable nodes here.
|
||
|
|
And then it turns a new integer, right? Any questions about this? We okay with this?
|
||
|
|
Want me to look at anything more and more depth? Want to sit there quietly? Your face is staring
|
||
|
|
ominously. Okay. What's that? Oh, sure. Oh, below the assembly level.
|
||
|
|
Para compiles it down to what's called a PVC file, which is para byte code. So just compiles
|
||
|
|
it down to the actual binary representation of the op codes. And such.
|
||
|
|
So we can actually print it out like that. Well, we can actually do this,
|
||
|
|
that's that's a way.
|
||
|
|
I don't bother with it. Yeah, you can actually compile down your individual programs
|
||
|
|
down to a PVC. And so you don't need to strip your source with it or anything like that.
|
||
|
|
You can just run the PVC directly, right? I wonder to do something like that.
|
||
|
|
Well, that's just target equals peer. I'll put you defined there. And there's a little bit that
|
||
|
|
I'll need to change in here because I'm not generating it properly. Load byte code,
|
||
|
|
steam.pbc. You're on parodon it directly. That'll print it out. We'll write out to define.pbc.
|
||
|
|
So now we run parodon.byte code.
|
||
|
|
And actually dump it out and see here's the header, which tells me the word size,
|
||
|
|
all of that stuff. And down here's the actual op codes. All right.
|
||
|
|
Here's the constants table, which is for the literal text and such.
|
||
|
|
And so that is that is that is that about what you were asking about?
|
||
|
|
All right. So let's see what I implemented next. I don't even remember.
|
||
|
|
That was it. So that was now. 7th can count.
|
||
|
|
Let. Let is for doing lexically sculpt variables, right? So set these variables for just this block
|
||
|
|
and then they're gone. So it's kind of like many other languages you do with the curly braces
|
||
|
|
or something like that or indentation and Python, that kind of thing.
|
||
|
|
So let's actually show you what it's like. Again, it's pretty simple,
|
||
|
|
but I do need to do things a bit differently, right? Now that we've got lexically sculpt variables,
|
||
|
|
we need a way to actually track what's going on with them, right? See, you know, we need to maintain
|
||
|
|
a symbol table to say these variables have been defined here, but later on they're not defined.
|
||
|
|
So what we do is we're going to have this global variable of this at sign. Again,
|
||
|
|
this is purl six. The at sign means it's an array, a list. The question mark means it's a global
|
||
|
|
variable, right? So we're saying here's our package global variable called block and all capital
|
||
|
|
letters to show that it's weird. What we're going to do in here is as we go through and create new
|
||
|
|
blocks, they're nested inside each other, which is what let does, we're going to actually, you know,
|
||
|
|
make a new block object and save it inside of this array, right? We're just going to, you know,
|
||
|
|
shove it on the front, then every time we need to look at the current block, we'll just look at
|
||
|
|
the start of this array. We can just walk the whole thing there, right? Right, exactly, exactly.
|
||
|
|
And we also made a parsing change here, right? We're going to actually call this two times at the
|
||
|
|
very beginning, right, which is first we need to set up this stack, make our block for the entire
|
||
|
|
thing, and then again at the end, right? It was going to be called two times. So we see up here,
|
||
|
|
if the key equals begin, then we want to set us that are variable here to a new past block,
|
||
|
|
and we want to unshift it, it's purlish for, you know, shove it on the front, kind of like push,
|
||
|
|
but on the front instead of the end. So unshift this block on there. At the end, we want to actually
|
||
|
|
grab it off of the front. So we want to shift it off, like pop, but from the front,
|
||
|
|
then iterate over the statements and push them onto it, and then return it, right?
|
||
|
|
That's our change down here. Define, I actually had
|
||
|
|
do it lexically in the current block instead of globals now. So when we pull the variable out,
|
||
|
|
we set the scope on it to lexical. We also, right, first I grab my block out of
|
||
|
|
that block sub zero. So the very first one on the stack, right? So the very most recent,
|
||
|
|
and we call the symbol function on it, which is just a way to set some data in there, right? So we
|
||
|
|
keep this symbol table around, which I'm all in storing it here is the name of the variable,
|
||
|
|
and this is lexically sculpt, right? So later on, when we actually mentioned a symbol,
|
||
|
|
we can actually go back and walk up the stack and see, well, is it defined lexically anywhere?
|
||
|
|
If not, it must be a global variable, right? So try that instead. So we'll see that in a bit
|
||
|
|
down here. So the way we define let, the grammar for that is right here. What the grammar actually
|
||
|
|
looks like is let, the insider parentheses, we have a list of things inside parentheses. So we say
|
||
|
|
a is equal to one, and b is equal to two, and c is equal to three. Then over here, we can do,
|
||
|
|
you know, whatever you want, right? Say a, say b, right? That's what a let statement looks like.
|
||
|
|
So it's kind of like, you know, just defining a block in some of the little, little bit different.
|
||
|
|
Ah, I can't, yeah. So down here, what we do, oh, we also have the grammar for it.
|
||
|
|
I didn't show it. So we say we first have an open parentheses, and then any number,
|
||
|
|
well, at least one, the plus is like the star, but at least one instead of at least zero,
|
||
|
|
of open parentheses, a symbol, excuse me, a symbol, which we save under the name var and a term,
|
||
|
|
which we save under the name val, a closed parentheses, at which point, once we've parsed that much,
|
||
|
|
go ahead and call it, right? So we create our block first and, you know, save things inside the
|
||
|
|
symbol table. So the one we're out parsing the other statements, it has access to them. Then we
|
||
|
|
parse any number of statements, and then we're done, right? Call it again.
|
||
|
|
So the way we do this, right, we again use this, this global set of, you know, blocks at our little
|
||
|
|
symbol table. So if the key is begin, and we create a new past block, block type of media,
|
||
|
|
which means go ahead and run this right now, right? We're not defining some code, right? We're
|
||
|
|
not defining a function or something. This is just inline stuff to actually do, and we're going to
|
||
|
|
create a list of statements, which is like a block, but it doesn't make a new scope, right? So
|
||
|
|
just a list of statements to hold stuff in. And then for each one of the variables, we defined,
|
||
|
|
again, that's going to be a list, we want to save it inside, and we can actually look at the
|
||
|
|
parse tree as we're doing this. Oh, I already did make it. All right, so we say let a1 and b2,
|
||
|
|
then say a. Oh, that's bigger than I. Want it to be go get bigger. Yeah, there we go.
|
||
|
|
So we have our special form. It's let. It has two variables, which are a and b, because they both
|
||
|
|
get saved into that name. So it becomes an array. And we have two values, which are 1 and 2. And then
|
||
|
|
we have a statement here, which is this big thing. So what we do with it, right, for each variable,
|
||
|
|
give me the syntax tree representation of it. And then we want to shift off a value, right,
|
||
|
|
so pull a value off the front of the list of values. There would be a few other ways to write it,
|
||
|
|
so you know, work on the two lists in parallel, but I'm kind of lazy. So I'm not rewriting it.
|
||
|
|
Set the scope on it to lexical, say it is a new declaration, register it in the symbol table,
|
||
|
|
and then push it, right, push a new past off, which is we're going to bind this,
|
||
|
|
right, push that new off into the init variable, which I have to find up here. Then at the end,
|
||
|
|
we shove the init block onto the beginning of our block, right, so we start off in our block by
|
||
|
|
just assigning these variables. Then we unshift it off, right, we shove our block into this list
|
||
|
|
of block, right, our symbol table. Let me know if I'm going too fast or you're just throwing
|
||
|
|
something at me as a valid comment here, really. Anyway, if we're at the end, what we want to do is
|
||
|
|
make a list of statements, right, for each statement, push it in there, and then grab our block
|
||
|
|
off of the top of the symbol table, right, pull it off, shove our statements into it,
|
||
|
|
and then set it as the syntax tree for this node, right, for this part of the parse tree,
|
||
|
|
right, so let me show you what this actually looks like. It's pretty nice.
|
||
|
|
Past for the abstract syntax tree, let a equal the one, say a,
|
||
|
|
pretty straightforward, so we start off, we get a new block here,
|
||
|
|
right, of type of media, and it has a sim table attribute, right, so for this block,
|
||
|
|
we've got a new variable called a, which is lexically scoped, and then we want to bind,
|
||
|
|
right, there's our first child here, a list of statements, and an enlist of statements together
|
||
|
|
just concatenate, there's no difference between them, right, so first we want to bind,
|
||
|
|
right, into our new variable A, right, it's newly declared here, an integer, value of one,
|
||
|
|
and then we call our namesay, scope package, right, so our global save function,
|
||
|
|
on this value A, right, and the reason it was able to look up, right, this serialization is
|
||
|
|
pretty poor, it just references the earlier thing because that's how I got it, right, by looking
|
||
|
|
it up, let me show you, all the way down here somewhere, in symbol, yes, yeah, yeah, that's,
|
||
|
|
yeah, that's all it means, so down here in symbol, so every time we just have, you know,
|
||
|
|
just some plain text there and want to look something up, by default it's going to be global,
|
||
|
|
but in the name of it, it's going to be the stringification of the symbol match there,
|
||
|
|
then for every block, right, so we're going to start at the beginning and just walk through it,
|
||
|
|
if the block, we call the symbol function to look up a symbol from its symbol table,
|
||
|
|
and the scope is still packaged because we haven't found anything yet,
|
||
|
|
but if we find something we haven't found yet, then we just set the scope to whatever the scope
|
||
|
|
of that symbol is, it's going to be lexical, right, and then we return a new pass variable
|
||
|
|
with that name in that scope, is that pretty clear, we, all right, I keep asking that,
|
||
|
|
you can just stop that, anyway, I think we have one more thing, which is lambda's,
|
||
|
|
oh, let me actually show you that it works,
|
||
|
|
apparently works, right, for say one to three, we assign a is one, b is two, we say okay one,
|
||
|
|
okay two, okay, one plus two, and everything seems to work out, okay, all right,
|
||
|
|
make tests, still passes, all right, our four test files now,
|
||
|
|
eight, is that where we are, apparently, so lambda is just a closure, right, it's just,
|
||
|
|
you know, the lexical scope function, the function is sticking to variable,
|
||
|
|
so the syntax of it is just the word lambda, an open parenthesis, the list of parameters
|
||
|
|
that that function takes, closed parenthesis, and then a statement, video, okay, all right,
|
||
|
|
here's our examples here in the test, right, we define an, oh, using let, we set okay to be a lambda
|
||
|
|
on message, which is say the word okay, and then the message, and then here we call okay one,
|
||
|
|
okay, on a function on one, right, pretty straight, I'll stop saying straight forward, I'm sorry,
|
||
|
|
I know that was getting annoying, because it annoys me when I say it too much, anyway,
|
||
|
|
so the beginning, we had a new past block, it's a declaration, and then we iterate over these
|
||
|
|
variables, right, for each thing saved in the var name, that's a symbol, right, so we just bind
|
||
|
|
it to the syntax representation there, which makes a new past var, set the scope on it to parameter,
|
||
|
|
say, how we, we are declaring something, and then we also saved in the symbol table as a lexical
|
||
|
|
variable, and then we push it in there, right, and we unshift it off, unshift it off, otherwise,
|
||
|
|
right, so we're at the end, we take our statements, shove them into the block, set it as a return
|
||
|
|
value, and we're done, so let's look at what this syntax tree looks like, right, so I cough, and then
|
||
|
|
we check it out again, so we run past on, so make a lambda of a variable A, and we return
|
||
|
|
A times 2, and so we see that makes a past block, it's a declaration, has this lexical variable called A,
|
||
|
|
and it's got a, it's first statement in here, it's just a new parameter, right, called A,
|
||
|
|
and then it has one statement in it, which is call, the function star, on this value,
|
||
|
|
and this variable, all right, if we take a look at the, uh, pier generated by that,
|
||
|
|
let's, uh, say, uh, define, uh, double to be lambda on A of times A2, yeah, that works out,
|
||
|
|
oh, well, actually let me then call double, uh, say, double to, all right, so we first, um,
|
||
|
|
get this subroutine down here, 13 something, just see down here is named 13 something, as generated,
|
||
|
|
it doesn't give a meaningful name, it accepts one parameter, just parameter 23, that's going to be
|
||
|
|
a lexical variable, so we'll just use this little thing to say stored in the lexical symbol table as A,
|
||
|
|
and we look up the global function star, we then look up A again, because it might have changed in
|
||
|
|
the meantime, we call star on A and 2, return it, swap in here, we lexically save it as double,
|
||
|
|
get the save function, get the double function, call the double function on 2, call the save
|
||
|
|
function on double, and her done, so it generates some, okay, bike, or assembly here,
|
||
|
|
that's about it, again I have tests as well, uh, they run, make tests, everything checks out, okay,
|
||
|
|
any, any questions about this, anything you want to see more on, yeah,
|
||
|
|
what was the, uh, what was the, uh, what was the problem, the ration, it's really hard to build a
|
||
|
|
compiler, it takes a long time, it takes a lot of expertise, it takes a lot of training, and
|
||
|
|
well, if you're wanting people to be able to experiment with new things, they wanted to
|
||
|
|
enable people to go out and, you know, build their own, well that was the rationale for the
|
||
|
|
parrot compiler tools, specifically, um, for parrot, the original reasoning came around, was for
|
||
|
|
Perl 6, storage, raising a hand, yes, oh, the name parrot,
|
||
|
|
another, the m4, Perl, just like, for 5, yeah, then after the joke was done,
|
||
|
|
who in the world had that part,
|
||
|
|
she was around by the start,
|
||
|
|
so it's, what about it,
|
||
|
|
um, I can probably expand on that a little, okay, my specific interest is probably in how it does the
|
||
|
|
cross language, hybridish type stuff, and that's probably how the VM is best interacted with,
|
||
|
|
um, you can talk about how that's actually, like, conceptually just brought about, and now it's
|
||
|
|
actually implemented in some, over a high of 10,000. The way that works is, uh, each language actually
|
||
|
|
has its own, uh, its own namespace that it runs in, right, and so code that's running in
|
||
|
|
Perl 6 runs in the Perl 6 namespace, so when it, it sets a global variable, that's visible to
|
||
|
|
Perl 6 code, but it doesn't start stomping on other languages, right, it also just compiles
|
||
|
|
everything down to peer, as you saw here, right, there's nothing different from peer that's
|
||
|
|
generated by the Perl 6 compiler, versus peer that's generated by the Python compiler, or
|
||
|
|
generate by the law code compiler, or anything like that, yeah, well, for, for various, for various
|
||
|
|
meetings of support, we get different answers, um, there's currently a mostly complete tickle
|
||
|
|
implementation, a mostly complete Louis implementation, a fairly complete law code implementation,
|
||
|
|
um, of course just silly, oh, and, uh, coming along pretty nicely PHP implementation, and a
|
||
|
|
very nice, uh, Perl 6 implementation, not quite done, um, Python, there's a little bit of a,
|
||
|
|
Python compiler, but there hasn't really been enough interest in anyone to work on it very much,
|
||
|
|
um, there's, uh, there's a fully complete HQ9 plus compiler, which is a language which consists
|
||
|
|
of the letters HQ9 and plus, we're printing out hello world, printing out a quine, which is a
|
||
|
|
program that prints its own source code, printing out 99 bottles of the beer, beer on the wall,
|
||
|
|
and I don't remember what the last one was, but it's a joke language, um, there's a very
|
||
|
|
complete APL implementation, which is kind of fun to be able to call APL from Perl 6, entertaining,
|
||
|
|
um, APL is a really interesting language, um, I've been having to keep trouble keeping track of
|
||
|
|
all of them lately because, uh, right now they're being moved out of the parrot repository into their
|
||
|
|
own repositories, um, there's a, I wrote a kind of okay, uh, Ruby implementation, it's very slow at
|
||
|
|
parsing, um, once the program is actually compiled it runs okay, but it's very, very slow, I started on a,
|
||
|
|
small talk implementation, but the grammar's mostly complete, there's no standard library,
|
||
|
|
so it's useless, mostly, um, scheme implementation, Perl 6, and there's a huge, there's a big
|
||
|
|
wiki page on the parrot wiki that has all of the others that I'm not remembering, this is
|
||
|
|
everything that nobody's bothered to move over yet, awesome, basic, uh, be fun, implementation is
|
||
|
|
just scary, um, a few others that I know I'm forgetting, let's, I at least name all the big ones,
|
||
|
|
two, some degree, some languages of, well, the active languages have had that problem, yes, um,
|
||
|
|
but yeah, the parrot 1.0 is going to be out next Tuesday, is there a lease, and the headline for
|
||
|
|
parrot 1.0 is it's a stable API for language implementers, which means they're going to have,
|
||
|
|
start having a stable long term deprecation cycle, after this release, then the next major release,
|
||
|
|
there's still some bike shedding on what they're calling a major releases, deprecation releases,
|
||
|
|
whatever releases, but the next release that affects the deprecation cycle will be in June or July,
|
||
|
|
forget which, and then after that it's going to be on a six month cycle, right, it's going to be
|
||
|
|
every January, every June, right, so every six months, yeah. So is, uh, this 1.0 milestone, is that,
|
||
|
|
give us any hope of seeing pro-six? Parrot is separate from the pro-six development,
|
||
|
|
the pro-six compiler on parrot is currently passing, I think it's coming up on around 8,000 tests
|
||
|
|
from the, instead of spec tests, there has been some speculation that a complete set of tests will
|
||
|
|
be somewhere around 15,000, we're not there yet, we're still working on the test suite as well, so
|
||
|
|
I would not be surprised if it was released in 3rd or 4th quarter this year, the first
|
||
|
|
actual release of Rukudo was just this past month, it was alpha something named, but there was a
|
||
|
|
release and it's going to continue having a monthly release cycle just as a parrot has been
|
||
|
|
for, you foreseeable future. There's a lot of stuff that can be done if you want to help,
|
||
|
|
so it's still a lot of, so a lot of work that's pretty accessible, even if it's just on the test suite,
|
||
|
|
so pro-six is coming up right here, so that's actually pretty exciting, I can, uh,
|
||
|
|
oh, I think I already compiled that, oh, that's really cool, everything's all screwed up right now,
|
||
|
|
because, uh, parrots moving towards a lot of things are trying to rely on an installed parrot,
|
||
|
|
instead of a parrot from the build tree, and so right now, and I just changed around to that,
|
||
|
|
at around 12, 30 this morning, so there's still a few things that are fighting over which version
|
||
|
|
of parrot it's using, and yeah, that's not something you'd run into on a reasonable system,
|
||
|
|
it's not all hose, anything else you want to talk about?
|
||
|
|
Parrots targeted platforms are Windows, macOS, I know we've got both Intel and PPC, macOS,
|
||
|
|
64-bit and 32-bit Linux, they're looking to get packages in Ubuntu, packages in Fedora,
|
||
|
|
packages in Debian, they've been fighting to get packages in Debian for the past year and a half,
|
||
|
|
because everyone who keeps trying to sponsor them just disappears and doesn't respond to emails,
|
||
|
|
I know we have a few people running it on various BSDs, I don't know if they are in the officially
|
||
|
|
supported set or not, any other platforms you're curious about? There has been a lot of interest
|
||
|
|
in getting a running on mobile devices. Another interesting thing that I saw was some people were
|
||
|
|
working to get it running as a Firefox plugin, so you could then write your scripts instead of
|
||
|
|
in JavaScript in any language pair of supports. Not that I know of.
|
||
|
|
There has been some work at getting Java bytecode to run on Parrot, so you could then interoperate your
|
||
|
|
compiled Java classes with, you know, use them from Parrot, which is interesting as well,
|
||
|
|
as there's another project getting .NET bytecode running on it too.
|
||
|
|
It's fun though.
|
||
|
|
With Java that was originally Jonathan Worthington, who wrote most of it,
|
||
|
|
I know he is doing some kind of DBI stuff, but I'm not sure why.
|
||
|
|
Let's say your Python code or even really wanted to do your hash script to act as any database through
|
||
|
|
a little bit of a DBI. Who else wants a penguin?
|
||
|
|
Be careful you got a wire.
|
||
|
|
Oh, all the way back there. I'm out of penguins now.
|
||
|
|
The bytecode is a cross-platform. You compile your bytecode on one system. It will run that exact same
|
||
|
|
file on any other architecture, regardless of NDN, regardless of processor.
|
||
|
|
Right, as long as you have Parrot installed that, but it's not machine code. The closest you
|
||
|
|
can get for that is there is a tool, which will embed a Parrot interpreter into a piece of
|
||
|
|
bytecode, embed some bytecode into a Parrot interpreter to make a fake cutable instead of an
|
||
|
|
executable, which is kind of silly, but works out.
|
||
|
|
What's that? Now, performance, there are few bottlenecks in performance. Performance right now,
|
||
|
|
I actually did have some statistics. I don't remember when I made these, but at the time,
|
||
|
|
this was running on an unoptimized Parrot, and this is measuring some kind of loop or something
|
||
|
|
running on the cardinal, which was my Ruby implementation on Parrot against the C version of
|
||
|
|
Ruby. And about a ten times performance difference, but I was not able to run it on an
|
||
|
|
unoptimized Parrot, so there was no jits, no kind of optimization at all. But there are two
|
||
|
|
few big bottlenecks. One is the current Parrot architecture. There are several places where we go
|
||
|
|
back and forth from C calling conventions, and Parrot calling conventions, and back and forth
|
||
|
|
several times, which just kills performance horribly. And there are plans to fix that,
|
||
|
|
but nobody has implemented them yet. There's a plan how to do it, it's just a lot of work,
|
||
|
|
so it hasn't happened yet. Also, garbage collection, right now Parrot uses a stop-the-world
|
||
|
|
market sweep, everything, garbage collector, which is, well, slow and bad. There have been a
|
||
|
|
couple of projects to implement a generational garbage collector on Parrot. Apparently, it is
|
||
|
|
mostly done, but just needs to be merged in and touched up, and it's been that way for a few months
|
||
|
|
waiting for someone to finish it off. That was part of someone's Google Summer Code project,
|
||
|
|
partially a few of the other Parrot contributors were working on it. So
|
||
|
|
the core Parrot developers that I've talked to about this have very good hopes for Parrot's
|
||
|
|
performance in the future. It's not horrible right now. It's not, you know, thousands of times slower,
|
||
|
|
like a few things I've seen, but it's still, you know, not fast right now. Is that
|
||
|
|
bad on the order you wanted to know? For example,
|
||
|
|
let's just throw something together, i0 equals 0, greater than i0, a big number. Let's put another
|
||
|
|
zero on there. I don't want to count them. Loop, and increment i0, go to loop.
|
||
|
|
So let's run that. Oh, that was not enough zeros.
|
||
|
|
Let's make a thousand times more.
|
||
|
|
There, that was about three and a half seconds to run that many iterations. So in spinning
|
||
|
|
the CPU uselessly, at least it can do that much. That's in no means a reasonable benchmark,
|
||
|
|
not a very useful one, but it does mean something. There's also,
|
||
|
|
it does have a jit, which is not as good as it could be yet. Not quite everything can be jitted yet,
|
||
|
|
but I'm told there are plans for everything to be, so let's see about that.
|
||
|
|
Anything else?
|
||
|
|
How fast can you type?
|
||
|
|
Maybe that.
|
||
|
|
The Python interpreter or compiler right now does not very much. I can do the basics,
|
||
|
|
define a class, call a function, define a function, instantiate a class, the basic stuff like that,
|
||
|
|
but it doesn't have list comprehension, it doesn't have a lot of the fun stuff.
|
||
|
|
What about the constructs that are different between languages? How does Perry handle that?
|
||
|
|
Kind of thinking of examples of, and I really don't have a good understanding of
|
||
|
|
enough languages to actually say which one has different stuff in them. I know there are different
|
||
|
|
components in different languages. How does it deal with that in regard to like, so maybe in Perl,
|
||
|
|
there's some magical object in the structure in certain way, and it's different in Python,
|
||
|
|
where they build them. How does that, I mean, guessing it's in the interpreter itself in Perl, but
|
||
|
|
if it's fundamentally different, should they accomplish similar goals? The good example maybe is
|
||
|
|
like a reading loop that you think is differently there? The way that works is that the compiler
|
||
|
|
generates the same, it's always just generating peer. So control constructs like that, like loops,
|
||
|
|
and, you know, whatever else. There are several things like that I can see, that's the problem.
|
||
|
|
I'm thinking more like, you know, something abstract that probably got implemented in some language
|
||
|
|
that people use. I mean, there's probably examples, I'm not articulating that word, but
|
||
|
|
in general, most of that stuff is exposed through the same core parent primitives. There are a few
|
||
|
|
places that things are weird, for example, most scheme and list implementations that you look at.
|
||
|
|
Don't use an array, is there that object? They have, you know, the nested cons cells, which if
|
||
|
|
you implemented your language like that, if another language tried to work with one of your objects,
|
||
|
|
it would be weird. You couldn't do array access on it. You'd have to call the, you know,
|
||
|
|
the foreign function to do it. The parent took me to account that. He said, oh, that could be like an
|
||
|
|
array in this language and that. I can actually fill, I guess you could. The parent stance on that
|
||
|
|
is that they don't do anything like that. They do not define any kind of policy. You could define,
|
||
|
|
you know, the module in Python that would, you know, kind of wrap that foreign class, right? Like
|
||
|
|
to find your scheme module, right? So you'll import scheme, right? And then you could call scheme
|
||
|
|
functions. That's a reason of a way to deal with that. But there's nothing in pair that tries to
|
||
|
|
do that automatically. That tries to convert objects from one type to another type. Well, there's
|
||
|
|
what we don't know. For example, in Ruby, a lot of the core classes like integer and string and
|
||
|
|
such have a lot of methods on. And depending on how you implement things, if you just, you know,
|
||
|
|
if I returned a string from Perl 6 to some Ruby code, the Ruby code working on it would, you know,
|
||
|
|
if you tried to call that method, there's no method like that on this object, right? You could
|
||
|
|
just call the Perl methods because that's a Perl object, right? It's just a different class.
|
||
|
|
Right? So it doesn't translate that. Right. Exactly.
|
||
|
|
And that makes sense. That has never been implemented. So it's been pushed off until someone
|
||
|
|
implements it. It is not part of the one point or release. It is still part of the plan for the
|
||
|
|
eventually we'll do this magic ponies release number. But currently there's no STM.
|
||
|
|
The things it does have, it does have good threading, it does have a good event model.
|
||
|
|
The object model is Perl 6's object model, which is a 2% of all other object models basically.
|
||
|
|
So one interesting thing has been seen that you can define, you know, using roles in such
|
||
|
|
on other languages that don't normally support that. One tension that has existed has been,
|
||
|
|
it would be so easy to add this to my language, but the language doesn't support it. For example,
|
||
|
|
I added the gather take control structure from Perl 6. I added that to Ruby, a Ruby compiler,
|
||
|
|
because it was easy and made some things nicer to work with. But if anyone writes that in their
|
||
|
|
Ruby code, it will be not bad. But it was kind of fun actually calling Ruby functions, which would
|
||
|
|
take a variable and have that interoper with the Perl 6 gather construct and things like that.
|
||
|
|
What I've seen is one of the benefits of Perl 6 is that if other open source language is a chance to
|
||
|
|
be able to truly open source and gather the core work from another language that's abstracted to there.
|
||
|
|
So that's what Perl's tried to do all along with it now, sharing that same core.
|
||
|
|
Right now, all of the languages that I implemented, the
|
||
|
|
call code in another language construct in. If you try to use it, we'll still look for that
|
||
|
|
language to be in the language's directory of a paired installation, which it probably won't be,
|
||
|
|
because like I said, all the languages are moving out. There's some infrastructure work that's going on
|
||
|
|
on actually, where the language is going to be installed, and Perl can look them up for you, and
|
||
|
|
I'm not sure how that's been working out because I haven't been following that mailing list thread.
|
||
|
|
Right now, none of that works. After I think two or three months ago or something,
|
||
|
|
I posted a blog post about I got all of it working and the fun examples and such.
|