yali: yet another lolcode interpreter

16 March 2008

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.

Keywords

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.

General syntax out of the way, here are the definitions for a few key terms:

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.

Examples

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

Aww, memories.

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.

Known bugs

Sadly, the YALI implementation is imperfect. A quick list of pertinent bugs follows:

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.

Download

Update 2008-09-20:

Alex Klink has been kind enough to discover and patch a bug in variable filenames in GIMMEH. The newest version of YALI is available here: download YALI1.1!

Thanks, Alex!

If you find errors in any of the above, please let me know. Feel free to update and distribute YALI at your leisure.

Update 2013-12-16:

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 LaTeX graphics are generated at LaTeX to png .

contemporary entries

comments

nice captcha
foo (1 April 2010, 3:35am)

Sorry, further commenting on this post has been disabled. For more information, contact me.