For reasons I'll save for a later post, I've been meaning to implement a solid piece of software in LOLCODE. This is all good and well — a reasonable joke in and of itself — with exception to the fact that none of the existing parsers (that I found) were up to par for serious use. They made excellent, if buggy, imperative interpreters for simple scripts, but lacked the oomph to, say, calculate a recursive function.
Enter YALI. To stick with good computer concept nomenclature, you've got two options on this one: Yet Another LOLCODE Interpreter, or YALI: Another LOLCODE Interpreter, but I prefer the former (recursive acronyms are so 1990s).
YALI is implemented mostly up through LOLCODE spec 1.2, probably with a few caveats. It is a Perl-based interpreter, using the beautiful Parse::RecDescent module, and is based (loosely) off of original work by Joe Drago. Notably, since YALI is an interpreted language running on top of an interpreted language (at work, we refer to it simply as “Double-VMed”), it can get really bogged down with too much code or too many variables.
YALI is my first venture into language implementation — if using Perl even allows me to call it that — so be gentle.
Although YALI adheres closely to LOLCODE spec 1.2, it's probably best to call out all available keywords, since some changes have definitely been made.
Unless otherwise stated, all statements must be delimited by newlines.
IZ [comparator] O RLY? ... KTHX
[comparator]; if true, jumps to
YA RLYstatement, otherwise to
NO WAIstatement (only one of which is necessary).
IZ [comparator] ? [action]
YA RLYis implicit and newlines are not permitted.
IM IN YR [loop label] ... KTHX
function, print result to
STDOUT, and exit.
OBTW ... TLDR
TLDRneed to be on their own lines.
I HAS A [variable] [ITZ [function]]
ITZdeclaration, assigns the result of
LOL [variable] R [function]
variable; barfs if
variablehas not been declared.
VISIBLE [pipe] [variable][!]
pipe, defaulting to
pipeis not declared. With
!, does not print newline.
amoutis present (and a series of digits), increments by
amountinstead of 1.
[formula] BIGR THAN [formula]
[formula] SMALR THAN [formula]
[formula] LIEK [formula]
IZstatements. Returns value equivalence for values, strict equivalence for references.
[variable] SORTA [string list]
string listas a (Perl) regular expression. If capturing groups are used, the results are available through
GIMMEH [LINEZ|LINE|WURD|LETTAR|NUMBR] [variable] [OUTTA [source]]
source, defaulting to
LINEZshould be used only for file IO and sockets.
sourceis a file descriptor, either local or a URL, which will load all at once. In this case, if
LINEZis the selected option, will return an array of results.
DO NOT WANTZ [variable]
variable; presently deprecated.
HOW DUZ I [function name] [YR [variable name] [AN YR [variable name] [...]]] ... IF U SAY SO
FOUND YR [function]
functionand returns its result, breaking from all necessary loops in the process.
MEBBE [function1] MEBBE [function2]
variable, taken as an array.
VALUE, as appropriate for
General syntax out of the way, here are the definitions for a few key terms:
variable name: a variable identifier; anything matching
[[...] [formula] IN MAH] [variable name]. Numbers prefixing the variable name are taken as array indices in reverse order; also, possibly a determined value: a string or number.
digits: a string of numbers, 0-9 (a natural number).
number: any possibly-floating point value; scientific notation is not allowed.
variable [N variable [...]]concatenates values to form a single string.
formula: a straight variable name; possibly
formula [UP|NERF|TIEMZ|OVARZ|BOOMZ] [(] formula [)](you can probably figure out what the operators are). If a number is used in a formula, it must be the last entry (see bug list).
[variable name] [YR [variable] [AN YR [variable] [...]]] MKAY. Evaluates the function named
[variable name]on the supplied parameters (overloading is not permitted). To pass formula and function values to a function, first pass to a variable and then pass to the function.
Last but not least, a note on value versus reference. In YALI, all variables may be either values or arrays; consider values as leaf nodes, and arrays as branches. When a leaf node is passed to a function, it is passed by value; when a branching node is passed to a function, it is passed by reference. To pass a value by reference, use
LOL 0 IN MAH array R value and pass the array instead. You cannot pass an array by value, but you can possibly rebuild a copy yourself.
Like the rest of you, I learn poorly from documentation and excellently from examples. So here we go.
HAI BTW Hello, world! VISIBLE "Hello, " N "world!" KTHXBYE
HAI BTW Cheater's quine I HAS A quine GIMMEH LINEZ quine OUTTA "quine.lol" I HAS A loop_max ITZ ALL quine I HAS A loop_index ITZ 0 IM IN YR loop IZ loop_index LIEK loop_max O RLY? YA RLY GTFO KTHX VISIBLE loop_index IN MAH quine UP loop_index!! KTHX KTHXBYE
It's a cheater's quine since it's just reading its own source code and printing it out. Nothing algorithmically intriguing here, but it's a good introduction to basic syntax usage.
HAI OBTW Naive Fibonacci, with no caching TLDR HOW DUZ I fibonacci YR index IZ index SMALR THAN 2 ? FOUND YR 1 LOL index R index NERF 1 I HAS A fibs_left ITZ fibonacci YR index MKAY LOL index R index NERF 1 I HAS A fibs_right ITZ fibonacci YR index MKAY FOUND YR fibs_left UP fibs_right IF U SAY SO I HAS A index VISIBLE "Watnz numbr: "! GIMMEH NUMBR index I HAS A fibs ITZ fibonacci YR index MKAY VISIBLE index N " fibs r " N fibs KTHXBYE
A simple Fibonacci sequence generator (when given an index).
HAI OBTW join Basic array join. TLDR HOW DUZ I join YR a AN YR b I HAS A count ITZ ALL a LOL count R count NERF 1 IZ count SMALR THAN 0 ? FOUND YR "" I HAS A output ITZ "" IM IN YR LOOP LOL output R count IN MAH a N output IZ count BIGR THAN 0 ? LOL output R b N output IZ count LIEK 0 ? GTFO LOL count R count NERF 1 KTHX FOUND YR output IF U SAY SO OBTW mapMult Toy function to demonstrate pass-by-reference. TLDR HOW DUZ I mapMult YR array AN YR factor I HAS A index ITZ 0 I HAS A array_lemf ITZ ALL array IM IN YR loop IZ index LIEK array_lemf ? GTFO LOL index IN MAH array R index IN MAH array TIEMZ factor UP index!! KTHX IF U SAY SO I HAS A array I HAS A array_lemf ITZ 10 I HAS A current_lemf IM IN YR loop LOL current_lemf R ALL array IZ current_lemf LIEK array_lemf ? GTFO LOL current_lemf IN MAH array R MEBBE 1 MEBBE array_lemf KTHX I HAS A array_join ITZ join YR array AN YR "\n" MKAY VISIBLE "Before:\n" N array_join I HAS A NUFN ITZ mapMult YR array AN YR 3 MKAY LOL array_join R join YR array AN YR "\n" MKAY VISIBLE "\n\nAfter:\n" N array_join KTHXBYE
Just a quick toy demonstration of reference versus value.
A much more detailed, specific, practical, and complete example will follow shortly — there had to be some reason for me to implement this.
Sadly, the YALI implementation is imperfect. A quick list of pertinent bugs follows:
TYEPshould be able to return
NOT LIEKis broken.
Frankly, those are probably ordered in terms of difficulty to fix (the first item being the most difficult). If you want to attack them, head from the bottom up.
If you find errors in any of the above, please let me know. Feel free to update and distribute YALI at your leisure.
Due to a server migration three years ago, YALI has been unavailable for download for awhile. Fortunately, it turns out that YALI is the standard LOLCODE implementation shipped with FreeBSD, so their archives came to the rescue and the interpreted is again available for download.
All included graphics are generated at LaTeX to png .
Sorry, further commenting on this post has been disabled. For more information, contact me.