The Beginning
The story begins over a year ago with Adam Lindsay's invention of LOLCode. I was shown this language sometime in the summer of 2007, and decided I would try my hand at writing an Eclipse plugin for it. The plugin turned into an interpreted runtime, which flowed to my more active involvement in the shaping of the language. While the language itself is rather humorous and very readable, the most interesting part to me were the concepts we were describing.
LOLCode is designed by committee, which although allows for many various interesting ideas to get discussed, also leads to very-long debates and slow decision making. However, a few major pieces of LOLCode were decided early that shaped it into a very interesting language. Of primary importance was the appeal to feline programmers. This untapped market could revolutionize the software business for decades to come. It was later agreed that other fuzzy and/or exceptionally cute lifeforms should also be allowed to participate in this revolution. The most exciting decision (for me) was the decision to use Prototype-OO as the basis for the language. Most other design decisions fell from this.
While designing LOLCode, not only were we having fun, we were also toying with some very interesting programming language designs. The choice of prototype-OO lead to several other interesting choices, that eventually got a few of us excited about the possibilities what the language could express. Not only could you perform acts for others, you may also be able to do so succinctly and elegantly. This lead to the idea for "Protocopter"
A Language that can fly
Protocopter is a language runtime (currently very buggy + implemented on top of Scala) that we were using to test out the ideas of LOLCode in a very minimal syntax. The idea was to reduce parse complexity (as most of us weren't compiler designers by profession) while ironing out details in the runtime. So far, we've had some very exciting results, and I'd like to go over the general design/implementation of Protocopter/LOLCode for you. For future reference I will only use protocopter, but the designs are interchangeable at this point. Protocopter is almost a "vm" for LOLCode.
SLOTS IN YR OBJECT
The primary design of Protocopter revolves around its object construct. An object is a "thing" that may contain any number of "slots". Each slot has a name, and contains any number of objects. The concept is very similar to Java's Map<String,Object> and almost exactly the same of a JavaScript object.
The most interesting part about Protocopter objects are that they have prototypes. A "prototype" is essentially a parent class only it remains an object. In Ruby, you can access a class and inject methods into it, but in Protocopter there is no need. Everything is an object. IF you want to create a "class", you simple make an object (places all methods/fields you want inside) and then prototype it to create "instances". The concept shouldn't be new for any AJAX developer, but it can be rather unintuitive for C/Java programmers.

The hard part in dealing with prototypes is defining how to look up a slot name on an object using its prototypes. In Javascript, when looking for slot 'x', the object itself is initially queries for slot 'x'. Then it proceeds to the prototype of the object, then the prototype of the prototype and so on. In Protocopter we made the decision to allow a list of prototypes per object. This means we needed a more sophisticated algorithm. At the writing of this article, we've implemented a Depth-First search on the prototype list. This means we first check the first prototype, then its first prototype, etc, until we've check as far down the tree as possible (the entire list), then recurse backwards searching for slot names. The algorithm also marks objects that have been visited to prevent cyclic references from causing infinite lookup times.
Now that we've defined objects, and slot lookups, what do prototypes really look like? The prototype list needs to be modified at runtime, therefore it should fit in a slot. Not only that, the prototype list is a LIST, ideally it should prototype the "ListPrototype" object, so we can re-use list functions when working with it. All of these decision were made, although we haven't thoroughly defined the "ListPrototype" object, or how one would work with it.
Putting FUN back into FUNction
Function are the next interesting piece to Protocopter. There was much debate over how to create them, and what they should look like. It was decided that the language should support blocks of code. Blocks of code operate with some "scope object". A scope object is the object used to look up local variables when a "block" is executing. The block references these slots on the scope object without any qualifiers.
Note: The initial script run by Protocopter is run in the scope of an anonymous prototype of the "Object" object. Other potential prototypes may be implementation defined, but are non-standard. "Object" is the only global inside Protocopter and the prototype of *every* object in the system.
It was then decided to turn Functions into first-class objects. A function consists of a code block and a list of arguments. When calling a function, the function object is prototyped, and the arguments/self slots are assigned to the prototype. The anonymous prototype is then used as the "scope object" for the code block of the function. To turn a function into a closure, simply insert the "scope object" for the scope a function is created, into the function's prototype list. Not only was this approach elegant, it made implementation much simpler (as it uses the already existing slot-lookup algorithm + prototype system).
WE HAZ A FLAVORZ
The next part of protocopter was defining enough operations to make it a viable "VM" for lolcode. The operations are listed below in the "Protocopter" syntax. Later in the article I attempt list the relative LOLCode->Protocopter conversions.
Slot Access
expr '.' identifierThis access the value of a slot from an object
Call Code Block/Function
'!' expr expr expr*This calls a given code block with the scope/arguments
Assign Slot
l-value '<-' exprThis assigns a value to a given slot
Create Prototype
'~' exprThis creates a prototype of an object
Append Prototype
l-value '<<' exprThis appends a prototype to a given object
Code Block
'{' statement* '}' This creates a code block which will execute a series of statements.Literal Translation
'@' exprThis treats a string expression as a code-literal (for slot lookup)
The above form the basis for Protocopter syntax (and allow mapping from LOLCode). I've also (somewhat successfully) tried to define a few convenience extensions in the current implementation. These are not needed in the language, but helped me write some test cases quickly.
Function Definiton
'{' ('|' arg-list '|')? statement* '}'
arg-list := arg (',' arg)*
This creates a Function object that takes a series of arguments.
Call-function inline syntax
expr '!' identifier call-arguments
This syntax calls a function identified by a given slot on an object, using the object as "self" for the function.
Function Closure syntax
'[' ('|' arg-list '|')? statement* ']' This syntax creates a function that automatically prototypes the current scope.
Code-Block Closure syntax
'[' statement* ']'
This syntax creates a code-block that automatically prototypes the current scope.
IM IN YR LOOP WHILE YR NOT!
Now that we have some syntax available, it's easier to describe some issue's we're running into. The first is how to deal with while loops. Ideally, we want to implement tail-recursion optimizations and define while purely inside Protocopter like the function shown below (assuming 'if' is a valid function):
Object.while <- { |condition, loop|
! if current (!condition) [ ! loop; ! Object.while current condition loop ]
}
Note that I'm using some lazy syntax here with the || arguments, but let's look at the one-liner implementation. First, you should note that code blocks return the last value executed in their scope. Second you should note that "current" always refers to the current scope object. I could accomplish this same code in more lines, but I'm preferring brevity here. It might be more apparent what's going on if I write it without the syntax extensions.
Object.while <- ~Function
Object.while.block <- {
trueBlock <- {
!loop
! Object.while current condition loop
}
trueBlock << current
! if current (!condition) trueBlock
}
list <- ~ Object.libs.collection.List
list.0 <- 'condition'
list.1 <- 'loop'
Object.while.args <- list
Notice first, that we're creating an anonymous prototype of "Function" and placing a code-block and argument list inside it. Then notice to create a closure, we're making a code-block and then appending the current scope as a prototype. Also notice that we're using a very low-level mechanism of creating a list (assigning numbered slots). Although it gets into the details, I hope that's detailing some of what is going on at the lower-levels of protocopter.
The goal with the protocopter language is to provide a very simple low-level base that LOLCode can be implemented on, while provided nicer higher-level language features that make writing boiler-plate test-code easier (like functions/closures, etc.).
My next goal is to provide a few layers of niceties on top of the existing language extensions so you don't always have the verbose: "! function scope arg1 arg2" nonsense every time.
CAN HAZ CHEEZBURGER?
The most important part of Protocopter is the ability for LOLCode to compile into Protocopter instructions. Currently they're both interpreted, so it's a mere matter of source->source translation, but hopefully in the future Protocopter could be a form of byte-code.
Let's take a look at some LOLCode 1.3 spec examples and how they would look in Protocopter.
I HAS A var ITZ 0
---------------------------------------
var <- 0
HOW DUZ I foo YR bar
VISIBLE bar
FOUND YR NOOB
IF U SAY SO
---------------------------------------
foo <- { |bar|
! print current bar
null
}
I HAS A thingy ITZ A Bukkit
---------------------------------------
thingy <- ~ Bukkit
O HAI IM tired IM LIEK sleepy
I HAS A thingy ITZ 0
KTHX
---------------------------------------
tired <- ~sleepy
! { thingy <- 0 } tired
O HAI IM pile
I HAS A length IZ 0
HOW IZ I pushin YR item
ME HAS SRS length ITZ item
length R SUM OF length AN 1
IF U SAY SO
HOW IZ I popin
length R DIFF OF length AN 1
BTW Do bounds checking...
I HAS A mom ITZ ME'Z SRS length
ME'Z SRS length R NOOB
FOUND YR mom
IF U SAY SO
KTHX
---------------------------------------
pile <- ~Object
! {
length <- 0
pushin <- { |item|
self.(@length) <- item
self.length <- ! + current self.length 1
}
poppin <- {
self.length <- ! - current self.length 1
mom <- self.@length
self.@length <- null
mom
}
} pile
I HAS A fishBarrel ITZ A pile
fishBarrel IZ pushin YR "halibut" MKAY
fishBarrel IZ pushin YR "trout" MKAY
fishBarrel IZ pushin YR "salmon" MKAY
VISIBLE fishBarrel IZ popin MKAY BTW prints "salmon"
---------------------------------------
fishBarrel <- ~ pile
! fishBarrel.pushin current "halibut"
! fishBarrel.pushin current "trout"
! fishBarrel.pushin current "salmon"
! visible (! fishBarrel.popin current )
NOOOO HEZ STEALIN MAH BUKKIT!
We've almost discovered England, and dug our flag into Brighton. The only thing left is to look into a language known as IO. I discovered this language a few weeks ago and it made me very excited and also very sad. Not only is it almost exactly what we've been trying to implement with Protocopter, it even ups the ante with actor-based objects. In I/O all objects are actors and all slot-access/function calls are messages between actors. Most of the other work is already in-place in I/O. While this gives me the satisfaction of knowing we were on the right track, it also begs the question: What should we do with Protocopter?
Currently the I/O language is a little too far removed for LOLCode to compile into its world. However, would it be easier to finish Protocopter implementation, or re-define LOLCode 1.3 spec to fit the I/O language design? I leave the debate up to the readers and the LOLCode forums.
The unfortunately reality is that most of us trying to hack on Protocopter and LOLCode have more-than-full-time jobs and kids. I also try to place the needs of the scala-maven-community before some of my other nerdy hobbies (which are way below family/work), so Protocopter ends up being pretty low on the totem pole. Perhaps given enough insight, caffeine and hilarity to leverage, you'll see a 0.10 release of Protocopter (and 1.3 of LOLCode) out soon.
Anyone willing to help, please email me and we'll set you up with access to the project and whatever else you need. This blog now stand as the greatest single document of accumlated LOLCode-thought for the 1.3 spec. If you'd like to see the thought process that arrived at this point, please check out the LOLCode forums.
The current major issues in Protocopter are:
- Sequence/List Prototype Definiton
- Using Sequences for Prototype lists on objects, and runtime manipulation
- self/this references in functions. How can we pass "scope" + "self" without being incredibly verbose
- actor/continuation implementation + cleanup
- parser refinement
- Code-Block slot/metadata definitions