The Worst Programming Language (it doesn't have a logo yet)

Learn Worst

Here’s a medium-length tutorial. It should give you a feel for how Worst works; by the end, you should be able to read and understand simple programs.

When you start the interpreter, you’ll be greeted by a message followed by the prompt.

$ rlwrap lworsti
Welcome to the Worst interactive environment. Type help for assistance.
worst () >

The parts of the prompt, from left to right:

  • worst - Just so you don’t forget.
  • () - The current state of the stack.
  • > - A prompt marker of no significance.

Worst is a stack-based language. The stack is, simply, a pile of values. It starts out empty and new things go on the right. Any piece of data you want to deal with will go on the stack at some point, and many functions will take things off the stack as input and leave things on it as output.

For example, you could enter two numbers to put them on the stack, and use add to replace them with their sum:

worst () > 1
worst (1) > 2
worst (1 2) > add
worst (3) >

You can do more than one thing per line:

worst (3) > 4 5 6
worst (3 4 5 6) > add add
worst (3 15) > add 7 add
worst (25) >

Use drop to discard the value at the top of the stack:

worst (25) > drop
worst () >

Try something else, like swap or print:

worst () > "test\n" 8
worst ("test\n" 8) > swap
worst (8 "test\n") > print
worst (8) > drop
worst () >

Most Worst is just words like these. Try help if you get stuck. It’s a work in progress though.


Here’s most of the syntax you will find in a Worst program.

; single-line comments
123 45.6 ; numbers
#t #f ; boolean true and false
symbols ; uh, symbols
"strings" ; ... strings
"strings\nwith \"escape\" sequences"
(lists {which can be [delimited] using () and {} and []}
    and (can [be [nested] (however) you {like}]) {
        and can contain "any other data as well"

That’s it. All programs are lists, which can contain other lists, symbols, and things that are neither lists nor symbols. Whitespace and indentation are not significant, except to separate consecutive data (i.e. hello123 and hello 123 are different things).


Time for a recap:

  • Put things on the stack by typing them in
  • Except plain words. They’re called ‘symbols’ and are treated specially
  • Special treatment includes doing stuff other than putting them on the stack
  • Symbols encountered so far include add, drop, and swap
  • Surely there must be some way of adding your own symbols

There sure is! Now is a good time to define a function:

worst () > define nine [4 5 add]
worst () > nine
worst (9) >

This is new. Usually, things are done one at a time, so you might think it would go like this:

  1. define clearly does something. There’s nothing on the stack though, so its options are limited.
  2. nine isn’t defined, so should the interpreter crash or something?
  3. Okay, it didn’t crash, but shouldn’t the list (1 2 add) end up on the stack at least?

In fact, define is able to read the symbol nine and a list, and combine them into a function definition. How it does this will have to wait for the next section, but first, let’s get a little more funky:

worst () > define add-ten [10 add]
worst () > 11 add-ten
worst (21) >

This time, the definition doesn’t exactly work on its own - add takes two things off the stack, but clearly, 10 is only one thing. The other thing must be on the stack before add-ten is called, so that add has enough things to work with.

If you consider add as a function that takes two arguments, then add-ten implicitly takes one argument. If you try add-ten without anything on the stack, i.e. without any arguments, then the interpreter will crash because add doesn’t know what to do with only one number.

The next section

So, how does define do the thing where it reads the next thing without evaluating it?

Consider, first, quote:

worst () > quote add
worst (add) >

Here, instead of add doing any addition, quote puts it on the stack. Useful, sort of. Let’s combine it with uplevel for something slightly more interesting:

worst () > define cool-quote [quote quote uplevel]
worst () > cool-quote hello
worst (hello) >

Now, uplevel does something completely new. It temporarily jumps back up to whatever called it in order to evaluate the symbol on top of the stack, stashing the current function call away for later. In this case, it uses quote to read hello and put it on the stack.

In the case of define, it uses uplevel three times: twice to read the name and body of the definition, and the third time to add the definition in the right place.

A slightly better example

That was several words strewn together, so have a look at this next bit to show how useful this quote/uplevel combo can be:

worst () > define + [quote quote uplevel add]
worst () > 12 + 13
worst (25) >

Now we’re getting somewhere! Regular-looking addition! Here’s how 12 + 13 works, step by step:

  1. Put 12 on the stack as normal.
  2. Evaluate +.
  3. Inside +, quote takes the next thing (the second quote) and puts it on the stack.
  4. uplevel steps out of + and evaluates the symbol quote (because it’s on the stack).
  5. quote then takes 13 as the next thing after +, and puts it on the stack.
  6. Back inside +, add takes 12 and 13 from the stack and adds them together.
  7. add puts 25 on the stack. The end. <applause dies down eventually>

As you may expect, quote quote uplevel is fairly common, so it has its own shorthand: upquote.

Uh, that’s it for now

Thanks for reading so far. There’s no advanced tutorial yet, mostly because there’s barely any “advanced” Worst at all, and there’s no reference manual or other documentation yet either. If you like, you can read the source code for the interpreter, linked on the downloads page.