Fish

From Esolang
Jump to navigation Jump to search
The title of this article is not correct because of technical limitations. The correct title is actually ><>.

><> (pronounced as if it were spelled as “fish”) is a stack-based, reflective, two-dimensional esoteric programming language. It draws inspiration from, among others, Befunge. It was invented by User:Harpyon in 2009.

Concepts

><> is a two-dimensional language, meaning the code is not necessarily executed in a linear manner. Using various instructions, the direction the code is read can be changed to either up, down, left or right. It is also a stack-based language, so all operations are performed on a stack. You can also store and retrieve values in the codebox, so making a proper compiler is very hard, if not impossible.

What makes ><> unique is the fact that it supports multiple stacks. A program starts off with one stack, where values are pushed and popped. The program can however create a new stack on top of the original one, with a specific amount of values moved over from the original stack. The program can create as many new stacks as it wants to. When a stack is removed, the values residing on it are moved to the top of the underlying stack. Example here. Each stack is effectively a new scope in the program; this allows for writing functions and snippets to drop into code easily.

Code execution

><> code is laid out in a two-dimensional codebox. The codebox is infinite in all directions, positive and negative. It is traversed by the instruction pointer, or the IP.

Note: all coordinates for the codebox are given as (character,line), i.e., (column,row).

The instruction pointer starts out at (0,0), i.e. the top-left of the script. It initially moves towards the right, but its direction can be changed using a variety of instructions. When the IP reaches the end of the code in any direction, it will wrap around, or "jump" to the opposite side. The IP will never reach the negative side of the code; this makes this space useful for storing values. Execution will not stop until a ; instruction is met, or an error occurs.

In the following example, the IP moves upwards, wraps around to the bottom, moves leftwards, wraps around to the right side, goes upwards, then leftwards, and stops.

^ ;<

<   ^

Mirrors

Mirrors are special kinds of instructions that will change the direction of the IP depending on the direction it already has. For example, if the IP is moving rightwards and meets a \ instruction, it will be "reflected" (unrelated to reflection) downwards. If the IP meets it going downwards, it will be reflected to the right, and so on. Meeting _ horizontally or | vertically equals a NOP, but meeting them vertically and horizontally, respectively, will invert the direction, and # will do so unconditionally.

Stacks

><> is stack-based, and thus every instruction except movement-related and the end-execution instruction (;) do something to the stack. You can push numbers and input, perform modifications and pop output using various instructions. You can also create new stacks, this using the [ instruction. Creating a new stack pulls a specified number of items from the current stack onto the new one. The new stack is completely isolated from the previous one, and an arbitrary amount of stacks can be created on top of each other. When the ] instruction is met, the current stack is popped and its values are moved back to the underlying stack. If the current stack is the last stack, ] simply empties the stack and registry.

12345 3[  r  ]  rnnnnn;
  ^    ^  ^  ^     ^
  |    |  |  |     | Output: 12543. The three top values were reversed!
  |    |  |  |
  |    |  |  | The second stack is removed, putting its values back to the first stack.
  |    |  |
  |    |  | The second stack is reversed.
  |    |
  |    | A second stack is created, pulling 3 values from the first stack
  |
  | Numbers 1-5 are pushed onto the first stack.

The register

The & instruction is used to store and retrieve values in a register. If the register is empty, & stores a value in it. When the register holds a value, & pushes it back onto the stack.

When creating new stacks, new registers are also created. However, the values aren't moved around; each stack starts off with an empty register, and when the stack is removed, the register is dropped.

Input/output

><> has three input/output instructions: i for input and o/n for output. The i instruction simply reads a character from stdin. If no more input is available, i pushes -1. Note that there is no instruction to input a number, you will have to parse the characters yourself.

While parsing numbers is not very hard, it makes for slow and possibly glitchy programs. Most programs requiring number input reads it from the stack at program start. This is done with an interpreter that supports pre-populating the stack with values. Doing so with the fish.py interpreter looks like this:

$ ./fish.py --code "2*n;" --value 10
20

Output is a bit easier, as you have two instructions: o and n. They will pop a value and output it as a character and a number, respectively. The output is naturally written to stdout.

Errors

The following events will cause an error in ><>:

  • Division by zero
  • Reaching an invalid instruction
  • Trying to pop or modify on the stack when it is empty or has too few values
  • If the interpreter does not support arbitrary-precision numbers, an overflow results in an error

Although there are multiple reasons an error may occur, there is only one error message: something smells fishy...

Instructions

The following is merely a draft of the instructions in ><>, and is subject to change.

Movement and execution

 > < ^ v Change the direction of the instruction pointer (right, left, up, down respectively)
 / \ | _ # Mirrors; the IP will change direction depending on what direction it already has.
 x Random direction.
 ! Trampoline - skip the following instruction.
 ? Conditional trampoline - pop one value off the stack. The next instruction is only executed if the popped value is non-zero.
. Jump - pop y and x off the stack, and move the IP to (x,y) in the codebox. The current direction is retained. Note that you have to jump to the cell before the instructions you want to execute, as the IP will move one position next tick before executing.

Literals and operators

 0-9 a-f Push the corresponding value onto the stack. a = 10, ..., f = 15
 + - * , % Addition, subtraction, multiplication, division and modulo, respectively. Pop x and y off the stack, and push y operator x. Division is float division (meaning 94,n; outputs 2.25 and not 2). Division by 0 raises an error.
 = Equals. Pop x and y off the stack, and push 1 if y = x, and 0 otherwise.
 ) ( Greater than and less than, respectively. Pop x and y off the stack, and push 1 if y operator x, and 0 otherwise.
 ' " Single and double quote - enable string parsing. String parsing pushes every character found to the stack until it finds a closing quote.

Stack manipulation

 : Duplicate the top value on the stack.
 ~ Remove the top value from the stack.
 $ Swap the top two values on the stack
 @ Swap the top three values on the stack, shifting them rightwards (e.g. if your stack is 1,2,3,4, calling @ results in 1,4,2,3)
 } { Shift the entire stack to the right and left, respectively. (e.g. when having 1,2,3,4, calling } results in 4,1,2,3 while { results in 2,3,4,1)
 r Reverse the stack.
 l Push the length of the stack onto the stack.
 [ Pop x off the stack and create a new stack, moving x values from the old stack onto the new one. See Stacks.
 ] Remove the current stack, moving its values to the top of the underlying stack.

Input/output

See Input/output.

 o n Pop and output as a character and a number, respectively. Output is written to stdout.
 i Read one character from stdin and push it to the stack. The character should not be shown when read from console. When no more input is available, -1 is pushed.

Reflection/miscellaneous

 & Pop the top value off the stack and put it in the register. Calling & again will take the value in the register and put it back on the stack. See The register.
 g Pop y and x off the stack, and push the value at x,y in the codebox. Empty cells are equal to 0.
 p Pop y, x, and v off the stack, and change the value at x,y to v. E.g. 123p puts 1 at 2,3 in the codebox.
 ; End execution.

The space character is simply a NOP and is allowed anywhere.

Examples

All the examples are executed using the fish.py interpreter.

Hello, world!

>"Hello World!"0r>o:?v;
                 ^   <
$ ./fish.py helloworld.fish 
hello, world

FizzBuzz

0voa                            ~/?=0:\
 voa            oooo'Buzz'~<     /
 >1+:aa*1+=?;::5%:{3%:@*?\?/'zziF'oooo/
 ^oa                 n:~~/
$ ./fish.py fizzbuzz.fish
1
2
Fizz
...
98
Fizz
Buzz

Fibonacci sequence

Outputs Fibonacci numbers until stopped. The execution is slowed down using -t 0.01, to avoid being spammed to death with the endless Fibonacci sequence.

10::n' 'o&+&$10.
$ ./fish.py fibonacci.fish -t 0.01
0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597 2584 4181 ...

Lucas sequence

Outputs the Lucas numbers until stopped.

2n' 'ol?/21>::!
    $&+&\  /
$ ./fish.py lucas.fish -t 0.01
2 1 3 4 7 11 18 29 47 76 123 199 322 521 843 1364 2207 3571 5778 ...

Factorial

Calculates the factorial of the input number. Assumes the input is a non-negative integer. Notice that the input value, 10, is supplied using the -v switch of the interpreter.

 :?\~11>*l1\
-1:/ ;n\?- /
$ ./fish.py factorial.fish -v 10
3628800

Quine

Outputs its own source code.

"r00gol?!;40.
$ ./fish.py quine.fish
"r00gol?!;40.

Another one, this one is multi-line

0>:a$f8+$p1+:5-?vv     
 ^              <>~0v  
v             <     <  
>0v          ;^?-6:+1~<
v <                  < 
>$:{:}$go$   1+:f9+-?^^

Square root

A function (isolated stack; remove the 1[ and ] instructions to create "inline" version) that calculates and outputs the square root of the top of the stack/input number.

1[:>:r:@@:@,\;
]~$\!?={:,2+/n
$ ./fish.py sqrt.fish -v 64
8

Brainfuck interpreter

v
1
0

           >$    >$                 \
>:@$:@i:0(?^$:2=?^$:3b*-0=?\v/      >:&$:1=?v>$@p&0(?v$1+
\                  02]p00~~<> :'+'=?^\      $$       >1-0p
\01-\                       /^?='>': <      d+
v   <}            v?= \     > :'<'=?^\      %e
v}]p$p4r}:r:$4[2@:/f1+/     /^?='-': <      \/
>{1+:00g=?\:1g:e-?^~:}0a.   > :'['=?^\
/     -1-:/                 /^?=']': <
>1+:00g=?;:1g0$.            > :'.'=?^\
^             ~<   $\.51$~~ ~^?=',': <
 '['~ 20g:3g  ?^>$4g^

 ']'~ 20g:3g0=?^^
^                 <     \
 '+'~ 20g:3g1+3$@p^
 ','~ 30g:1+30p2g  20g3p/
 '-'~ 20g:3g1-3$@p^
 '.'~ 20g3go      /
 '<'~ 20g1-20p\
^             <
 '>'~ 20g1+20p/
echo '++++++++[>++++[>++>+++>+++>+<<<<-]>+>+>->>+[<]<-]>>.>---.+++++++..+++.>>.<-.<.+++.------.--------.>>+.>++.' | ./fish.py brainfuck.fish
Hello World!
echo '-,+[-[>>++++[>++++++++<-]<+<-[>+>+>-[>>>]<[[>+<-]>>+>]<<<<<-]]>>>[-]+>--[-[<->+++[-]]]<[++++++++++++<[>-[>+>>]>[+[<+>-]>+>>]<<<<<-]>>[<+>-]>[-[-<<[-]>>]<<[<<->>-]>>]<<[<<+>>-]]<[-]<.[-]<-,+]!Esolangs' | ./fish.py brainfuck.fish
Rfbynatf

Unusual Hello World

>"Hello World!"0r>}o$:?v;
                 ^     <

Interpreters

fish.py

The "official" interpreter, or the one written by the author. The latest version is available here. Requires python versions 2.7 or 3.2 or later. For usage information, run it with the --help switch.

fishlanguage

An online interpreter, written in TypeScript. Features animation of the instruction pointer moving through the program, configurable execution speed, and display of stack contents. (Formerly found at fishlanguage.com.)

Mousetail's Fish Interpreter

Another online interpreter in Typescript. Able to create sharable links, pause execution, and see the state of multiple stacks at the same time. Inputs do not reset when repeatedly testing a program.

go-fish

An interpreter written by redstarcoder. It follows the same behaviour as the fish.py interpreter, but can also follow the fishlanguage.com behaviour with "-m" set. Download at GitHub.

fish.java

An interpreter written by User:Cxarli. It has the same console arguments as the "official" interpreter. Get the source from GitHub here. (dead link)

fishr

An interpreter written in Rust, by Marc Noirot. It has roughly the same console arguments as the "official" interpreter. Get the source from GitHub here.

fish-jit

A just-in-time compiling interpreter, written in RPython. Stack values are stored as arbitrary precision fractions, and converted to float only when displaying. Get the source from GitHub here.

Older interpreters

The following interpreters were written towards an older version of ><> that featured multithreading. The multithreading capabilities were removed and replaced with multiple stacks support, which was deemed more useful (not that esoteric languages are useful in the first place). These interpreters may not work with some updated instructions, like p, [ and ]. You can of course still use these interpreters using the old documentation.

Python

The old version of the official python interpreter is available through Gist. (dead link)

Invoke it by first making sure you have installed python, and typing python fish.py <script> [tick] into your system's command line. Script is replaced with a .fish file, and tick is optional and defines a delay in seconds between each instruction, to slow down execution for debugging etc. It should work with both python 2.x and 3.x, as well as both Windows, Linux and Mac.

Delphi

Another interpreter, written in Delphi, is a result of a so-called 'code-golf challenge'. It interprets every instruction (except the threading related instructions) in about 1290 characters of source code. (A version with threading support is also available on the same site.) Get it here!

Compile the code into a console application with any Unicode-enabled version of Delphi (a port to the FreePascalCompiler FPC is trivial). Invoke the resulting executable and supply the path to a .fish file on the command line. Speed can be limited by increasing the Sleep() time in the code.

More

There are several interpreters in a multitude of languages available in the StackExchange code-golf challenge.