 some quick ground rules. If you're a loss, want to ask a question, raise your hand, and I'll answer it there. This is not the kind of talk where we can wait till the end to go over questions, because we'll have absolutely no context for what's going on, okay? Everybody cool? All right, great. Okay, this is titled Developing a Language. This is my Twitter handle, this is where I'm on GitHub, this is some nice curly stuff. I made this slide like two minutes ago. Okay, this is talk number 11. So you know what that means. You know what everybody's thinking about, right? Oh, wait, these are out of order. Oh, well, that's okay. So, this is my shout out for LARB. So you guys know about LARBs and here, know about a Tuesday night hack. All right, all right, cool. So I guess we'll see you all there. Shane, get all their numbers. Okay, so as I was saying, this is the 11th talk. It's the last talk of the day. So everybody's thinking about LARB. You're a painter. Dinner, dinner, dinner. But we're not gonna get to dinner first. First, I'm gonna give you some things to talk about with your friends over dinner. And for that talk, we're actually going to go through and we're going to write a new programming language in this talk. So we're gonna see how this goes. So, the big question about why do we need a new programming language first is there's a philosophical question out there which is which came first in society or in human evolution at all? Language or idea, abstract idea in this case. So is the ability to express an idea to someone, the genesis for having that abstract idea or did you have to have that abstract idea and realize I have to tell somebody about this to come up with the language? And it's hard to say. And in many ways, the idea of having an abstract idea is part of the parcel of having language to express it because if you have an abstract idea, it's very difficult to do anything with it if you don't have the ability to communicate it in some way. And a very wise man once said that the programmer, like the poet, works only slightly removed from pure thought stuff. So programming is really all about abstract ideas. And so the language in which you express those abstract ideas influences what kind of ideas you can have in some ways. So ideas are the manifestation of the language can a better language, can different languages lead to better ideas. And this is sort of the idea that the pragmatic program idea that learn new language it will make you a better programmer because seeing how other people express similar ideas can help you realize that perhaps they're doing something that you had no, they're expressing an idea you didn't even know about. Additionally, newer languages are not, newer ideas are not always better than older ones. There's plenty of old, we could, you could spend your whole life learning about all the ideas that people have already thought of and not come up with any more and be done. You'd be the smartest person alive. So looking backwards is also good. But if you wanna learn a language the best way to learn a language is really to implement one. And that is what we're gonna do today. And so in the course of saying, well, let's look back and another language is another very wise man said something, which is to pass the language from scratch to take 90% of the past and call it groundbreaking. So we're gonna peek back a little bit in time here. We're gonna peek back to one of, one of Ruby's forefathers. It's, it's, maybe it's father, maybe it's mother. It's a direct descendant and that would be small talk. So today we're gonna be implementing in this talk small talk. It's not gonna be a full small talk. It's gonna get, the idea is to wet your whistle to realize how can you, if you have an idea to express, if you wanna work on a language, how easy it is for you to actually dive right in and to get started implementing that language. And also to look at how other languages do things and learn, maybe bring some of those ideas over to Ruby or to some other language. So the original idea for this talk was to actually develop a piece of software for you guys to use after this talk called the Ruvinius Language Kit. And the idea was that you could implement things with ease. And so I, as many good programmers do, decided, well I really first, before I get started on this, I need to write a whole bunch of companion software. So I ended up writing my own, I ended up writing a very simple parsing library. And then I realized it was yesterday and I hadn't even gotten to the actual toolkit part. So what we're gonna present today is a language. And the idea for this language is that after this talk, we figure out how to extract out the pieces from this language and make it into a toolkit. So the other people, you people or people on the internet, hello people of the future, can use this toolkit to build new languages, to experiment with new ideas. So thus Prattle is the name of our small talk we're gonna be making today. It is sort of the genesis of this language toolkit. So if you have a laptop out, just a sec. If you have a laptop out, there's a lot of code in these slides and I had to condense it down to make it meaningful. So the code for all, for these things is already online right here. If you wanna take just a quick moment and clone it, this is my laptop running. So it hopefully is still an IP. If not, then that won't work. Otherwise here. So I'll give you a quick moment while Mitch asks this question. I'm a little upset, I think that Alice would agree that you didn't name the languages Demonmore. You know, I could have gone back and I could have named it Demonmore. That's a, you make a very good point. So, okay. So if you've got the URLs, if you want them, hopefully it's cloning now and the Wi-Fi is satisfactory. So, like I said, this whole thing kind of has turned into a little bit of a, you know, kind of a yak shave. So with that, I present Prattle. So, small talk is very much like Ruby. Ruby, well, the inverse is actually the truth. Ruby is very much like small talk. So we're gonna start with really the four of the most basic concepts you can have in small talk. You can have self, true, false, and no. This is all exactly the same as you would have in Ruby. So inside the, oh, real quick note, when you're looking at that code, and if you're in the future watching this online, hopefully you have the code up somewhere around here. All right, so move your windows to here. Okay, great. So, you'll be looking at what is essentially one of the first few commits and that's how do we add the ability to parse self? Cause really we're talking about writing both a parser and the ability to run that parsed code. So what you'll find is that that first commit looks a bit like this, which is really too big. It's small, it's in green, cause it's a diff. So really we want the relevant portions which are somewhere around there. So let's pull that out. So really what this is, is how are we going to parse this self statement? So we'll go over a few of the finer details here that we're going to be using throughout this talk. So we're going to make a rule called self and it's going to be a string literal called self. And then when we match one of these, we're going to return a new self object. We were, don't forget, we were inside this self class. So whenever you see those, they all follow the same convention, so don't get lost. So very easy. We see a string called SELF and we return this thing. Awesome, great. We've now successfully parsed a small talk program. Congratulations. You can now tell your friends you are able to parse some small talk. So we move on to true, false, and nil. Not really all that exciting. Really just looking at these string literals. Let's get on to something that is just slightly bigger. Numbers. So we've learned the numbers and we want to go ahead and create a new number rule again. In this case, we're going to create it from a regular expression. So you can just embed a regular expression right here. In this case, I've opted for sort of the simplest possible representation of a decimal number. A zero or a little lot, right? And when we match this, we create a new number, AST node, with the value converted there. Great, now we can parse numbers just like that. We're rapidly on our way. So what we'll find though is we now have five different rules, five different things. But we have no way to bind them together. We have no, nothing that says, hey, you know what, a small talk program can be a self, or false, or a nil, or a number, or whatever. So we need a root node. And so what we do is we extract this back out into another part of the grammar called the global part of the grammar, where we make a new root node and it's really just any of these things. It's a true, it's a false, it's a self, it's a nil, it's a number. Another quick convention node here is that the, when you've got what is implicitly a list of potential rules, you can just use a symbol to name the rule and it'll automatically figure it out for you, right? So we're saying any of these things is a valid program. So now we can parse all those things. Any of that input will be parsed. So this is a slightly easier way to look at this is to look at it in the actual grammar output, which looks something like this, right? Root, this is self, blah, blah, blah, blah. Everybody switch me? Okay. So writing a language is all about instant gratification. So instant gratification, you need a rebel. You need something that you can put this text into and see what it is when it comes back. Because this, what I'm about to show you, whenever, I encourage you to go off and do this from scratch. Because when you get to this moment and you type into the rebel, I'm not sure what it is, but everyone has this sort of like, wow, I can't believe it worked a moment. It's impossible for you to not feel this sense of like strange euphoria that you've actually managed to do this. So in this case, what we've done is we've fired up our rebel, which comes with the project and you can just copy it to your project. And we ask it for 42 and we get back a very nice little note. Oh, yep, okay, I parsed the number note and it's got a value of 42, great. Oh, we asked for a true and it comes back as a true. So we're well on our way. So this is all fine and good. We're able to parse things, but it's sort of boring. We haven't really been able to do much yet. So what we want to do now is we want to have the ability to say, when you get to a true, what should you be doing? Or you get to a number or you get to a nil. What is the actual code to run? And what we're gonna be using for these next few examples and for the rest of the deck is actually the ability for inside or vinias for you to inject and write methods actually directly in bytecode. So you don't have to go around concatenating Ruby strings together. You could just use a very problematic API to build up your code basically exactly the way you would any other data structure. So what we do is for self, ooh, we're going fast for you at home with your window right here with the code. Yeah, this right here is the commit, is the hash of the commit that adds this particular chunk of code. So if you want to go back and check that out, now's a good time to just pull it up. Oh, wait a second, why you typed in? Okay. So what we're using here is similar to the previous slides where we were using G where G meant grammar here, G means generator. That's the simple API that we use inside for vinias for generating bytecode. It has a very, we have a big long section documenting it on the website. I'm not gonna go over all of them right now, but it's fairly easy to follow. That what we've said is push the value, current value of self on the stack. That's all we've done here, right? It's pretty simple. We do that for the rest of these. We do that for true, we do that for false, we do that for nil. So all of these are sort of singleton objects that the vinias, the VM knows about anyway. You can ask for these values and it will happily push them on them. So something slightly more interesting is you'd think it's number, but again, oh crap, I made it too smart so you can just pass it a number. So the generator API handles that for you. You didn't really have to do all that much. So now let's get on to something that has a little more complicated rules and I'm gonna try and go over these rules and we'll see how well it goes. And that is string. So string is actually slightly harder to parse because you wanna be able to handle say a slash quotation mark and not exit. You wanna, all those simple kinds of things. So this is actually kind of hard to read just because of the constrained form of slide coding. So instead what we're gonna look at is the actual grammar output from this which is slightly easier to read which is something like this. So a character is either a list of escapes which is not included, just imagine that it contains things like slash n, slash t or not a quote mark, right? So then we say not any, I'm not sure why I call this not quote. That's kind of a crappy name, but nonetheless. So this should be sort of string body, right? A string body is a number of characters and the string itself is actually a quotation followed by a body followed by another quotation. Small top, by the way, really quickly grammar-wise only supports strings with a single quotation mark. Double quotation mark actually means comment and is totally up to you to implement. I did not do that for you. That's my present to you. So let's, from now on, whenever we do these things really what we're interested in is that that instant gratification that shot like, parsed it, it even ran. So let's go over, let's check out the REPL. Over here in REPL land, we see we added 42 and got back 42. Wow, that's amazing, it looks stupid, I know. Because what you have to realize is that you've round tripped, you put in the string 42, it parsed, it actually injected itself as a method that all it did was return the number 42, but it went through the entire pipeline of parsing to bytecode to come back. In this case, again, 42 is sort of 42, so that's how it is. True is true, and again, the string is slightly more, slightly cooler, but again, it's not, again, just, it's the same thing we got out of, we put it in the way we got out of it. Yeah. Is it true to return to 42? True is 42, I think that's- Yeah, well, you know, that's how it goes. Like. Like, that's how it goes. Okay, your turn. Yeah. Again, up to now, we've basically been doing, and I can tell by most of your faces in here, other than that, like, when it's dinner look, is this is some pretty boring parsing stuff. Parsing, I mean, we literally were basically asking it to give us a value or giving back. You could just write that as a method that just took it and gave it in. So let's get to the first sort of interesting case, which is actually sending something a method. So this is the syntax to send the object three, the method class. So the equivalent code in Ruby would be that. I know, it's a big change, but I'll show it to you again, because I know it's hard to follow. We got this, and we got this. Okay. So is the receiver, and we got this, is the method name. Pretty simple. So as simple as that is, that's actually about as simple as it is to parse. So to parse that, what we have is actually, in this particular case, a number, a space, and then a method name. Easy peasy. We return a new unary send that has a, that's by the way what this is called in small talk, just so that you can fit in at your small talk, luncheon, this is called the unary send. So v here is the, I don't know why I called it v, but nonetheless it is the number here is the receiver, and then n is the name of the method. Oh, pretty easy. This is what it looks like in the grammar. Again, I've put it in the grammars because they're easier to follow in the code in this particular form. So great. Now we can send three, we can send the message class to three. Super. But what if we wanna do this? Okay, so, well, okay, well, now it's not just a number, it's also a true. So really what we wanna do is now we wanna extract those core patterns that we've done thus far. We've had false, nil, true, number, and a string. And what we do is we extract those things grammar-wise into something sort of like what Giles was talking about, that idea of an atom. It's basically the simplest possible value that isn't really composed of other things. And so we put that in our global grammar, and then we use it in here. So now we can say an atom, a unary send is an atom, a space, and then a method thing. So now we can accept things like three, true, false, nil, anything, an atom on the left-hand side, and it will work fine. Again, so the rule for an atom looks something like this, then. And then the rule for a unary send now looks like this, atom, space, method thing. Okay, so great, so we're doing great. We're well on our way to having small talk at the moment. But now we get to the next interesting case, which is this one. We actually want this to work. And then in small talk's particular case, the precedence rules work sort of like if you had dots here, again. So really what we want to do is send the object three, method class, and then we want to send that thing as return value to method class again. So in this case, we would ask them for fixed nums class, which would be class. So we want to go ahead and support that. Previously, we were just having atoms there. So what do we need to do? What we need to do is add another rule in here to unary send, which is actually to say that a unary send can also be itself as a receiver. Now this particular case is actually very nice in terms of the one of the reasons I ended up writing the parsing library to use here, because this construct actually is very difficult to handle in other parsing expression grammars. It's the idea of left recursion, where you're actually saying that a thing can be itself in at any depth, and normally what would cause, normally what happened was it caused it to go in an infinite loop, but it handled fine. And it's easily the easiest way to represent this, because it is literally the way that you read it from left to right, which is that a unary send can be a unary send receiver. So now the grammar looks something like this. The unary send is exactly what it has sent. Great. So now we want to run this. So now we're sort of getting to the interesting case in terms of the actual bytecode. And this particular case, again, because Ruby and Smalltalk are so similar, it's actually very easy to implement this. What we get is we get something like this. So we've got the receiver inside this unary send, and all we do is we ask it, hey, generate the bytecode for yourself. Just calling down. So all those bytecode methods we'd seen thus far, one of those might be called for true, for false, for mill, whatever. In fact, this method itself might be called in the case of three class, class. And then we just tell the generator to send the method, the method of the method name with zero arguments, because we haven't had any arguments to methods thus far. And so, again, we want that shot in the arm, that thing that is what's keeping you up at 2 a.m. when you're doing this undoubtedly is the REPL. So let's go ahead and run that in the REPL. And we see that it's working great. We can ask three, it's class, we can ask fix them, it's class, we can ask hello, it's class, and we get a string. So now we can actually, this alone gives you a lot of functionality. You can now call, you can have those objects, and you can call methods on them. And just this alone actually gives you, like I said, a fair bit of functionality. So let's get into, up to now it's been sort of vanilla in terms of the differences between small talk and Ruby. So the first big difference is gonna be how you actually pass methods to a particular, arguments to a method, excuse me. And that's gonna be what small talk calls the keyword send. So this, what this says is send the method index colon two O, or two hello, passing the string with O in it as that. Now, at first glance, you might think, okay, let's find that's not gonna be really all that different, it's just gonna be this, right? I mean, that seems like a trivial thing, right? And if you were to go ahead and implement it like that, you would just go ahead, we would, like I said, we would go ahead and we'd add this. And for the most part, I'm gonna start skipping past these slides to the grammar that's right after them because I can tell that when I get to these slides I get a lot of like, we're all one of these slides again. So, the keyword send is an atom, a space, a name, a method name, and then a colon and a space and an atom. Pretty simple, it's the pattern we've had thus far. So, but we can also, so we can also get, I thought I had those slides here. That's okay, we'll get to that in a second. So, if you wanna pass two arguments though, what you're actually required to do is break those arguments up between keywords. So, in this case, what this is actually doing is this is sending the method at colon, put colon, to the string hello, and it's passing two arguments, a zero, and a J with a quote, a quote, a string containing J. So, the method name is actually at colon, put colon. That's it. And that is the way that small talk is equal is passes multiple arguments. There's actually no way to pass multiple arguments other than passing them on keywords. And there's a few cases in small talk where you see that it becomes sort of a detriment because they end up with this collage where people start putting the keyword with on things. So, you'll basically see like, if you wanted to pass, if something takes six arguments, you would see a method that takes call foo with colon, with colon, with colon, with colon, with colon, with colon, with colon, just so that you can get those extra spaces in terms of the actual method. But the crux here is that all, if you have multiple arguments, it ends up becoming a new method name. So, this in small talk is sort of the equivalent of Ruby. So, now what we wanna do is we wanna implement that. How do we actually get to having multiple colons and arguments sort of spaced out over the end? So, we get another one of these. So, we're actually gonna break it up into different pieces now. So, we get pairs, right, which is a method name, colon space, and then an argument. And then we have the actual keyword sentence up, which is, oh, blah, blah, blah, blah. Let's go on to the easy one. So, this is the way it's expressed much more easily, which is you have an atom on the left-hand side, and then you have multiple pairs. Actually, this is a, there's a grammar bug in here, there should be a star and not a plus. So, you have multiple of these pairs, then you have at least one pair on the end. So, that way you basically collect up all the pairs with things in there. So, now what we wanna do is we wanna go ahead and implement this as to run. We get something like this. So, very similar, we're really not getting all that complicated, again, really what we have is the receiver that we did before. And then, now what we do is we also have arguments that we basically just stick on, just run the bytecode for them and let them go on the stack, and then at the very end, we just call a method with the particular arguments at that size. So, now we, in that case of hello at cook, at colon, cook colon, you know, arguments would be two, argument size would be two, and these would be a zero and a string with j, or j, or whatever I had put in there. So, now we want, again, let's go back to the repl. What do we get? So, in this particular case, we go ahead and run it. Yeah. Can I say eight out of my code, G? Yes, thank you. Very good. Uh, give that man a drink ticket. Thank you. Thanks for debugging the slides. So, let's go back to the repl, we run this. And the expectation here is that, okay, well sweet, we should be get, we should get what, like four, right? But what actually happens is we get this, because what we've actually sent to hello is index colon, not index. So, this is the point at which Prattle becomes not actually small talk and becomes our own language right here, so this is the reflection point, if you will. Because what we want to do is we still want to allow that to work, because remember that this code in small talk is sort of the equivalent of this in Ruby and that's obviously not what we want. So, let's go ahead and let's add a little twiddle to the actual way that these are parsed. In this case, let's actually use a twiddle to do that. So, now what we're gonna do is we're gonna say that, okay, well, if the method name happens to start with a tilde, then go ahead and strip off everything past the colon and just send that method with all the arguments on there. So, that way we can basically call Ruby methods much more easily with arguments without having to go through some other complicated semantics. So, how do we go ahead and do that? All we do is we go back into that bytecode method and we say, all right, well, if the name started with a tilde, then go ahead and do it in Ruby style, otherwise do it in small talk style and I've included the code for this. But it's essentially just go through, cut off, take the method name, take the first character off, take everything after the colon off and you're done. Yes? What is the question mark until the next sentence? Yes, this is okay. So, in Ruby 1.8, when you access a string, as a particular character on the string, you give back a fixed node, right? This is actually the character syntax, right? So, what I've actually said here is that I want the character code for tilde, which comes out to be whatever it is, 61. So, the value of this is gonna be 61, right? So, now, once we've done this, we get the equivalent code to that, which, now we can go back over the replung, give it a shot and we see, indeed, it does work. So, now we've basically not only built, sort of bringing in ideas from a different language, but we start to add our own features. So, we've actually sort of changed what, Prattle is really no longer small talk at this point, it's really its own language, because we've taken 95% from the past and we've added our own little twiddle, if you will, and made it our own. And now we can sort of build it up from there. So, now we move on to sort of the next case, which is, what would, sort of like unary send, where you wanted to say three class, class. How would you do this? Again, what the keyword said, we were doing only atoms to begin with, and then we changed it. So, what we obviously want to do is basically just add the ability to have a unary send as the receiver here. So, this was our rule four, and this is actually the problem point, right here. So, really what we want to just say is, well, it could be an atom, or it can be just a unary send. It's okay. So, now we get that a keyword send is now a receiver, which is either a unary send or an atom. We'll pull pairs. Again, this should be a star, and then at least one pair. Pretty easy. So, now we're actually able to do, have literals. We've got the ability to send methods of any airity to any object. So, now what you could actually do is, if for instance you wanted to have a webpage where people could try out little bits of small talk code, we could deploy this right now, because people are able to put in essentially valid small talk expressions and get decent values back for a pretty wide variety of things. So, one of the biggest syntactical features that Ruby takes from small talk is the idea of blocks. And in small talk, a block just looks like this. It's just square brackets with something in the middle. And this is the sort of the simplest possible block is actually a block with nothing inside it. That looks, doesn't look very good on slide. So, this is a block who, when run would evaluate, when run would evaluate to one. So, seems pretty easy, right? Just got some brackets, some expression in the middle. Again, expression is something new that we haven't looked at yet, but it's sort of like atom. We basically, when building up these pieces of syntax, they're beginning, they started at the smallest point, they're beginning a little bigger and a little bigger. So, we needed something to say, well, it's any of those pieces we've hit so far. So, we get an expression is basically one of those things. Just a keyword send or a unary send or an atom. Piece of cake. So, now we can say that block is really an expression. Expression inside brackets. Up to now, we've only been able to represent one expression of one. Yes? Are you missing a quote there? Yes. This is what happens when you use slides. So, up to now, we've been only able to represent one expression. The repl can basically take one thing. Like, oh, you want to do a false grade. You want to do one method send grade. You want to do whatever. You can just do one possible thing and then it's done. So, really what we want is the ability to have something like this. So, in small talk, if you want to have two or two or more expressions, you basically just separate them with periods, sort of like what would be a semicolon in C language or in Ruby if you're one of those crazy Rubyists that uses semicolons all the time. Don't laugh. I've seen them. So, it's going to look something like this, which again, is really just this. An expression is really just many things with dot on the front there. So, we get back to this. Now we've added just the S. Yes? Let's slide right before this. Do you have to, in this set of the parts that you have to specify spaces or optional before? I didn't go into that. I didn't really go into the dealing with spacing because if you think this is hard to read in terms of discussing about grammars and how to pull things apart, if I had to go into spacing, I hear it would just, it would be a nightmare. The spacing rules additionally would be yes, that around expressions you would allow for arbitrary spaces and there's a couple of places earlier where I assume is one significant space and you would allow many significant spaces, but that's all in the code. So, when you go back and you're watching this later tonight, hi by the way, and you can pull it up right here again and then you can see that there's all the things for a significant spacing. Isn't there an expression at the beginning of the start? Yes, so there's also a bug in this one, which is that this should have an expression at the beginning here, that's how that goes. So, hopefully you're watching these. I should probably, I'll fix all of these errors before we put these back online because that would be nice. So, now we've got, we've changed, we add the S here so now we've got multiple expressions in there and again we're missing the quote, but that's okay. So, we go ahead and run this. So, now we wanna run 10 times, put that cell up. And this is sort of a fairly complicated expression. We're creating a block, we're sending multiple methods, we're invoking that block, we're actually allowing Ruby code, external Ruby code to invoke a block that we've actually created inside Prattle. So, we're sort of, we're now blending the barrier between where the Ruby code is and where our new language is and we can see that they actually have a very close interaction because we're not really defining any of what we call small talk semantics other than the particular kind of esoteric method calling. We haven't made a behavior class or a small integer or any of the other things that are in small talk. That's sort of up to you. Really what we're looking at is building a sort of small talk skin, if you will. And a place where we can experiment with these ideas that small talk has. So, we go ahead and have this and we run it and to our delight, oh and I changed it. All right, whatever. It is a light bulb. It is a light bulb. I am the light bulb, thank you. So, we see it prints out a bunch of times and then we get 10 as a return value, 10 being the return value of the times method on integer. So, thus far we've actually been able to build things up in a fairly interesting way. So, we've now been going at this for 37 minutes and I have about 15 slides left. So, at this point in the presentation, I know that these are some sort of heady topics. So, I'm going to sort of go through and I'm going to just sort of demo things that are actually in the project for you to go look at and not give you the actual grammar for them. So, in addition to a block, a normal block, we have a block that actually can take an argument. So, you can do something like this. Times, pass, send, you know which time it is. So, you can go. Okay, cool. We get a thing called Cascade Send. Cascading sends, which is probably one of the more interesting ideas of small talk. And really what this is, is the idea that you want to send multiple messages to one object. So, what this actually is saying, I want to send three, I want to send the method concat to array three different times with three different arguments. And it sort of saves the receiver, it lets you reuse the receiver to multiple methods over time. It's very useful for when you're actually working building up a big object and trying to manipulate it. We don't have any operators yet, so we should probably add some operators. So, we get something, we can have, this is, again, operators in small talk look exactly like they do in Ruby. So, we get something like this. But, again, when we come over to the Ripple, we find out that we evaluate this particular expression, we get 35, which seems wrong, wrong. And you would be right in assuming that it is wrong, except that we're in small talk. And in small talk, this is actually correct. So, there is no operator in precedence in small talk. It is all left to right. So, really what we want to do is, we need to give the ability to someone to specify precedence. So, we need to add parens. So, we have some parens, and again, thank you, Shane, I know I have a missing quotation mark. So, we have the parens. Again, parens are trivial, given everything else that we've built up thus far. It's just parentheses with an expression inside the piece of cake. So, we go ahead and we run that. Get 20 grades. So, let's look at what we've done here. And hopefully, I've sort of wet your whistle for your idea that building a language is actually not all that complicated. Really, what we've done is built up some very simple rules for saying, how, start at the bottom, the simplest possible thing, and you build it up a little bit at a time. Oh, we're gonna add one more case here, one more case here, and slowly build it up and slowly, all of a sudden, you've got a very fully fleshed out system for doing things. So, in almost exactly 40 minutes, we basically went from zero code, zero small talk we can do, to essentially a usable small talk, just like that. So, what I would suggest to you, and now we've sort of done with the tech portion, is that if you've got a big idea, or even if you've got a small idea, that you be encouraged to go out and to experiment, and to try those things out, and don't feel like, oh, language design is too hard, or writing a compiler is too hard. All of those things are hard because people say they're hard, but unless you have actually gone out there and tried it yourself with the tools that you're disposing, you don't know if they're hard. So, whether it's a complex language, like say, Fortran, if anyone would want to be Fortran already, or a simple language, like maybe we do Lisp, it's all the tools are available for you to experiment with those things and to find out. Maybe you want to go learn Lisp, and maybe the best, and in my opinion, the best way to say learn Lisp is to go out and write your own Lisp. After all, that's what every single Lisp developer has ever done. So, thank you very much, see you out there. Forty to death or whatever, but if you have any questions, now they're at the end. Hopefully you answered them during, but Shane, yes. Is Prattle battle-tested? Prattle is not battle-tested, I don't know. No, Prattle is not battle-tested. Prattle should not be taken into any kind of war zone. A child's bedroom, nowhere, really. Is it prattle-tested? Prattle-tested, yeah. All right, well, thank you. No more questions, thank you very much. Thank you.