Ly

Ly is a stack-based esoteric programming language inspired by ><> created by User:LyricLy in 2017.

Concepts
Ly is a stack-based language, so all operations are performed on a stack. However, the program operates on not just one stack, but on an infinite strip of stacks. It also has a backup cell that can store one value for later use. Execution is mostly linear, with the exception of the  and   instructions.

Code execution
In Ly, execution is mostly linear, with a single execution pointer that performs the action dictated by the character it is currently on, before moving to the right. However, there are two instructions that can move the pointer:  and , which check if the top value on the stack is 0, and jump accordingly between each other. This allows for looping and conditional behavior.

The stacks
In Ly, a stack is a simple one-dimensional list of integers and floats. The language operates on an infinite list of stacks. There are several operations for stacks such as arithmetic, reversal, popping and I/O, but values in a stack below the two highest ones cannot be accessed without reversing the stack (except with the  instruction). This can prove problematic in some cases where you need a place to store values. That's where other stacks come in. The  and   operators can be used to change stacks at will, allowing greater control over your programs. The  and   operators also complete the language's set of instructions to be able to emulate brainfuck, proving Turing completion of the language.

The backup cell
The backup cell is accessible all the time no matter what the current state of the stacks are. The  command will copy (not move) the current top value on the stack to the backup cell, and the   will copy it back. This can be incredibly useful for storing a value for later use.

Input/output
Ly has four I/O commands, two for input and two for output. The string I/O commands ( and  ) will input and output characters as ASCII codes. The number I/O commands ( and  ) will input and output numbers directly. takes input as space-separated digits, to make the job of taking input as a list of numbers much easier.

Functions
Ly also has the ability to create functions, pieces of reusable code that can be called at will. Functions are ran independently from the main program, allowing great flexibility with programs and even code that can be reused between programs. Functions, like with many other languages, can also be called with functions, allowing them to be dynamic and powerful.

Errors
The official Ly interpreter will throw an error if any of the following things occurs:


 * Invalid arithmetic operations, such as dividing by zero
 * Trying to pop from the stack when it is empty (and implicit input fails)
 * The program has unbalanced brackets
 * Trying to load from the backup cell when it is empty
 * Receiving a non-integer as input with  (or implicit input)

Error messages look like so: Error occurred at program index 6 (zero-indexed, includes comments) EmptyStackError: cannot pop from an empty stack

Implicit I/O
Implicit input and output is an optional feature of Ly mainly aimed towards code golfers.

Implicit input will occur whenever an instruction attempts to pop from the stack when it is empty. Instead of raising an error, the interpreter will read a number (character I/O is not supported implicitly) from STDIN and push it to the stack. This is slightly different from the  instruction in that it reads the input backwards for convenience. For example, an input of  will return   and not. If there is no more input to take implicitly (EOF is reached or an empty line of input is given),  will be used instead. Implicit input is never pushed to the stack; it is delivered straight to instructions that attempt to pop from the stack. If an invalid input is passed implicitly, an  is raised.

In addition to normal implicit input, instructions that perform an action on the entire stack will implicitly dump STDIN (take lines of input until EOF/empty line) onto the stack.

Implicit output occurs at the end of a program if that program is still running. Thus, ending execution with the  instruction before the end of the program will disable implicit output. Implicit output will print the entire stack that is under the stack pointer, with a space in between numbers.

Commands
This language is still under very active development, and these commands are subject to change. In these explanations, "the stack" refers to the current stack.

Modified commands
In Ly, commands can be modified using the  symbol so that their effect will take place on the entire stack, as opposed to only the top value.

Functions
A major feature of the Ly language is its functions.

Defining a function
Defining a function is simple:

{ is a single character denoting the name of your function, and   is the body of your function.

Inside a function, code is executed just like a completely seperate Ly program. The only connection between a function and the main program is the input and output commands.

Instead of performing I/O from STDIN and STDOUT, a function manages I/O through the stack of the parent program.

An example function looks like this:

P{ns::[1-s%![l%!u;]p:l]}

This is a simple prime number checker program wrapped up in a function  that takes a single number as a parameter and pushes either   or   to the stack depending on if the number passed was a prime or not.

NOTE: If you give a function the same name as an existing function or built-in instruction, the old function/instruction will be overwritten.

Calling functions
Calling functions is just as simple as creating them:

where  again is the name of the function.

The function is run like a normal program, with three differences:


 * Whenever the function outputs, it is pushed to the stack of the parent program
 * Whenever the function takes input, it is popped from the stack of the parent program
 * There is no implicit input. When the parent stack is empty, taking input inside the function will yield 0.

Here is an example call of the prime number function:

p

This will pop a number from the stack, and push  if it was prime and   otherwise.

Examples
All examples are using the official  interpreter.

Hello, world!
"Hello, world!"r[o]

$ ./ly.py helloworld.ly Hello, world!

Prime number checker
Takes in a number as input, and outputs 1 if it is prime and 0 otherwise. n:s[:2-![1u;]p1-:lf%![0u;]p]

$ ./ly.py prime.ly Enter program input: 7 1 $ ./ly.py prime.ly Enter program input: 8 0

Truth-machine
n:u![;]1[u1]

$ ./ly.py helloworld.ly Enter program input: 0 0 $ ./ly.py helloworld.ly Enter program input: 1 1111111111111111111111111111111111111111111111111111111111111111111111111111111...

Fibonacci sequence
01[s:u+lr]

$ ./ly.py helloworld.ly -t 0.01 1123581321... With newlines: 01[s:u+52*olr]

$ ./ly.py helloworld.ly -t 0.01 1 1 2 3 5 8 13 21 ...

ly.py
The official interpreter, and currently the only one. Hosted here.

Online ly.py
There are two online versions of the official ly.py interpreter currently: here and here. The latter is recommended, as it is more fully-featured and more likely to remain supported.