MashedPotatoes

MashedPotatoes is a register-based esoteric programming language written by User:Mercerenies that is designed to look like other languages at a glance. It borrows many syntactic constructs from other languages but uses them for unusual purposes.

Overview
A MashedPotatoes program consists of a sequence of statements. There are three registers, three labels, and three stacks into which data can be stored. The registers are referred to as  (the accumulator),   (the counter), and   (the evaluator). The labels and stacks are simply numbered from 0 to 2 and are referred to by their index. Additionally, some statements can store peripheral data in their local state.

Syntax
The syntax of MashedPotatoes is designed, fittingly, to be a mash-up of the syntax of various other languages. As such, it is very ad hoc. In MashedPotatoes, whitespace is completely ignored. Whitespace is used in this article for the sake of readability, but it is unnecessary. There are certain statements whose behavior depends on the current line number, but aside from that, whitespace is always ignored.

To ensure that programs do not look too mundane, many expressions and statements must be referred to by different names depending on their placement in the code. If a statement has multiple forms listed, they must be used in cyclic order. That is, the first form must be used the first time a statement appears in the program. The second time it appears, the second form must be used, and so on. If the statement appears more times than there are forms in the list, it becomes necessary to loop back around to the first. For instance, Label 0 is defined as follows.

0.0f ++i <> Object

This should be read as such: the first time you wish to refer to Label 0, you should call it. The second time you wish to do so, you should call it, then  , then. The fifth time, you will loop back around to, and so on. It is a syntax error to refer to an entity by the wrong name. Note that this cyclic order refers to the order in which the parser reads the labels, not the order in which the evaluator executes them, so it doesn't matter if the name is in a loop or not; all that matters is that when reading the code from top to bottom, the names listed above appear in that order.

Labels
Labels are not statements, but they are often used as arguments to statements. There are three labels available. A label can hold either a numerical value or a reference to a code block. If a label holds a reference to a code block, the code block can be triggered by using either the Trigger A or Trigger B statements to do so. Different code blocks will respond differently to these two triggers.

Standard Labels
0.0f ++i <> Object

These names refer to Label 0. See the above section on cyclic order for when to use which name.

std::ignore nullptr __dict__ void(0)

These names refer to Label 1, again in cyclic order.

$ARGV *read-eval* FS

These names refer to Label 2.

Null Label
t

This is a special label value whose behavior is comparable to that of  on Unix systems. Any attempt to assign a value to  will be a no-op, and any attempt to read the value of   will result in an unbound variable error. This is most useful in a loop, if all you wish to do is repeat a block of code and do not need to name the loop.

Statements
These are the building blocks of any MashedPotatoes program. Remember that whitespace is mostly ignored; the forms provided here include whitespace for readability alone. Code that is placed in italics is intended to be replaced by the appropriate syntactic construct, so  is intended to be replaced by an expression.

Label Binding Statements
synchronized (LABEL) { STMTS }

This block executes  in order, with the value of   bound to the line number of the opening parenthesis   (the first line is considered to be line 1, not 0). Note that this is the only time that whitespace makes a difference in MashedPotatoes: the numerical label binding depends on the current line number.

(format LABEL "  STMTS ")

This is the basic looping construct in MashedPotatoes. It will execute the statements  in a loop until the value of   is less than or equal to zero. At the end of each loop iteration,  is automatically decremented by one. Within the loop body,  refers to the loop control code block. Sending Trigger A to the label will immediately break out of the loop, and sending Trigger B to the label will jump to the next loop iteration. In the latter case,  is still decremented.

proc LABEL {EXPR} { STMTS }

This statement allows printing to the console. The statements  are executed, with   bound to a printing block. If the label is triggered, the expression  will be evaluated, and its result will be printed to the console. On Trigger A, the resulting value will be treated as a Unicode code point (truncating if necessary) and its corresponding character will be printed to the screen. On Trigger B, the resulting value will be printed as a number in base 10.

case LABEL of { _ -> STMTS }

This statements allows reading input from the user. The statements  are executed, with   bound to a reading block. If the label is triggered, input will be read from STDIN and stored into. On Trigger A, a line of user input will be read and parsed as an integer. On Trigger B, a single character of user input will be read, and its code point will be used as the result.

WHILE LABEL OP EXPR STMTS WEND

This statement allows arithmetic to be done. When the block is entered,  is bound to an evaluator code block, the value of   is stored in the statement itself, and   is evaluated and used as the new value of. Then the statements  are evaluated. At the end of the block, the statement's stored value is placed back in. The behavior of triggers on  depends on the   argument, which should be one of the following.

Trigger Statements
use strict qw/LABEL/; SETLOCAL LABEL import LABEL; CFLAGS=LABEL \emph{LABEL} `cat LABEL`

This statement sends Trigger A to. Like other statements with multiple forms, appearances of this statement must occur cyclically in order within the code. It is an error if the label is unbound or is bound to a numeric value.

s/LABEL//g OUTPUT = LABEL guard LABEL lambda: LABEL """LABEL"""

This statement sends Trigger B to. Like other statements with multiple forms, appearances of this statement must occur cyclically in order within the code. It is an error if the label is unbound or is bound to a numeric value.

Register Statements
std::cout << EXPR << std::endl;

This relatively simple statement evaluates the expression and stores the result in, overwriting any previous value in that register.

goto LABEL;

Rotates the three registers. If the label has an even value, rotates the values. If the label has an odd value, rotates the values in the opposite order. It is an error if a  uses an unbound label or a label whose value is not numeric.

Stack Statements
def LABEL(EXPR) STMTS end

This is the generalized stack manipulation command. The statements  are executed, with   bound to a stack manipulation code block. When the label is triggered, the expression  is evaluated. Its numerical value is used (modulo 3) to determine the stack on which to operate. When Trigger A is used,  will be pushed onto the given stack. When Trigger B is used,  will be popped off the given stack. If the stack is empty, the value popped off will default to zero.

Comment Statements
:F(TEXT)

Comments can appear anywhere that a statement can appear and will be ignored. Comment blocks, like many statements in MashedPotatoes, must occur cyclically, so the first comment should use the  form, the second should use the   form, the third , and so on. The text inside the comment block can contain anything, including newlines, with the caveat that any parentheses must be balanced within the comment.

Expressions
Unlike statements, expressions return a value.

Register Expressions
It is useful to remember that all of the register expressions cycle through their values in  (remember: "Ace") order, simply with different starting points.

STDERR

This expression refers to the value of  at its first lexical appearance, then   the next time it is read by the parser, then , then   and so on.

$[

This expression refers to the value of  at its first lexical appearance, then   the next time it is read by the parser, then , then   and so on.

`uniq -c`

This expression refers to the value of  at its first lexical appearance, then   the next time it is read by the parser, then , then   and so on.

Numerical Expressions
--help

This expressions always evaluates to the numerical value zero.

"Hello, world!" arr[:]

These are two separate expressions (they are not cyclic forms of the same expression). Each expression evaluates to zero at its first lexical appearance, then one at its next, then two, and so on. It increments each time it appears in the code lexically.

Compound Expressions
(int) LABEL

This expression returns the numerical value of the label. It is an error if the label is unbound or non-numeric.

@{[ EXPR ]}

This expression evaluates the inner expression  and returns its additive inverse. That is, it negates the value.

Factorial
This is a factorial function written in MashedPotatoes. It takes input from STDIN and outputs  to STDOUT.

synchronized (std::ignore) { :S(We need a label with an odd value so we can rotate the registers) :F(This is merely to increment the value of "Hello, world!") std::cout << "Hello, world!" << std::endl; :S(Read in from the user) case 0.0f of { _ -> use strict qw/++i/; }  :F(Rotate the registers) goto nullptr; :S(Put the constant 1 into ^A) std::cout << "Hello, world!" << std::endl; :F(Rotate again; this is equivalent to the previous goto) goto __dict__; :S(Loop N times) (format t "    :F(Multiply the expression value by the loop counter)     WHILE $ARGV > $[       s/*read-eval*//g     WEND   ") :S(Output the result) proc <> { `uniq -c` } { OUTPUT = Object } }

Fibonacci Sequence
Likewise, here is the Fibonacci sequence written in MashedPotatoes. Once again, it takes a single numerical value as input and prints the Nth Fibonacci number. If you run this code, ensure that you do not accidentally insert any newlines into it. The first  block should be on an odd numbered line, and the rest should be on even numbered lines.

synchronized (std::ignore) { std::cout << "Hello, world!" << std::endl; case 0.0f of { _ -> use strict qw/++i/; }  goto nullptr; std::cout << "Hello, world!" << std::endl; def $ARGV(--help) SETLOCAL *read-eval* import FS; end goto __dict__; (format t "    def (--help)       s/$ARGV//g       goto void(0);     end     goto std::ignore;     def *read-eval*(--help)       OUTPUT = FS     end     goto nullptr;     WHILE <> < --help       goto __dict__;       CFLAGS=Object       synchronized (void(0)) {         goto std::ignore;       }     WEND     def (--help)       \emph{$ARGV}     end synchronized (nullptr) {       goto __dict__;       def *read-eval*(--help) `cat FS` end     }     goto void(0);   ") def (--help) guard $ARGV lambda: *read-eval* proc 0.0f { STDERR } { """++i""" }  end }

Implementation
The canonical implementation is written in Python and is available on GitHub.

Computational Class
MashedPotatoes is believed to be Turing complete, as it has multiple stacks and can perform arbitrary arithmetic and loops. This has not yet been proven, however.