Rui

From Esolang
Jump to navigation Jump to search

Rui is a thread-based esolang created by User:Sinthorion. All control flow and even basic arithmetic requires the use of multiple threads that create, communicate with, and destroy other threads. The source code (file extension .rui) is a single file with any number of lines of code.

Each thread stores a single unbounded non-negative integer as value for data storage and to distinguish it from other threads. Newly started threads always start at the beginning of one line that has been specified when creating the thread, and run through the rest of the code until they get terminated. Newly spawned threads have the value 0.

Execution happens in cycles. In each cycle, each thread executes one instruction. The order in which threads execute within a cycle is implementation-dependent; in the provided standard implementation, older threads always execute before younger threads. Newly created threads need to wait until the next cycle before first executing.

Instruction set

The language currently features these instructions:

  • =<value> sets value of current thread
  • +<line> spawns a new thread which starts execution at the specified code line
  • *<line> spawns as many threads as this thread's value, which start execution at the specified line
  • -<value> kills all other threads with the specified value; sets own value to number of threads killed
  • r reads a number from STDIN into current thread value
  • w writes thread value to output
  • ! stops execution and kills thread
  • # comment until end of line
  • . sleep for one tick (each thread executes one instruction each tick, in the order they were created in)
  • $ adds this thread's value to all other threads
  • ~ remove this thread's value from all other threads (to a floor of zero).
  • :<line> jump to line

Some instructions may be followed by a number as parameter. These numbers must consist of one or more digits (an no other characters) and immediately follow the instruction. Line numbers are 1-based, so 0 is invalid as `line` parameter, but valid as `value` parameter.

IO works in numbers. Implementations might choose to have ASCII IO instead.

Strict Rui

The specification above has a couple of ambiguities and unclear special cases. Normal Rui implementations are free to choose between different options concerning these, leading to Rui programs usually only working as intended in one specific interpretation. To solve this problem, there is a stricter Rui specification, called "strict Rui", as outlined below:

  • The number of allowed threads should be expected to be at least 2^32.
  • Thread values are arbitrary size integers (bigint).
  • Numeric arguments in code should be expected to be no greater than 2^32.
  • In each tick, threads are executed in the order they were created in. Threads created this cycle do not execute until next cycle.
  • A thread reaching the end of file will die the moment it tries to execute an instruction that isn't there. This is effectively the same as there being an implicit `!` at the end of the file.
  • IO is in numbers. Both input and output numbers must be expected to be arbitrary size (bigint). Each value read is consumed and cannot be read again by another thread.
  • Input can be done in two modes and implementations must support one or both modes: In interactive input mode, input is read from stdin and buffered and the `r` instruction blocks until input is available. In predefined input mode, the input for the entire program is known when the program starts; when `r` is executed while all input has been consumed, the current thread is set to 0 instead.

Examples

Echo/cat:

rw:1

or multithreaded

rw+1

Read two numbers and print the sum

r*2r*2-0w!
:2

Print all Fibonacci numbers:

+2=1.
..w+2$

Explanation: This starts with two threads (+2), with values 0 and 1 (=1). Each thread then first waits to sync with other threads (.), then writes its value (w), spawns a new thread (+2) and adds its value to all other threads ($). Precise timing, as in most Rui programs, is critical.

More complex examples written by Daniel Cristofani:
Compute sequence from http://oeis.org/A014221
Compute factorial
Compute square root
Calculate Euler's number (e)
Compute Collatz sequence for one number...
...or for all natural numbers (https://oeis.org/A006577) but including 0 -> 0).
Output Sierpiński triangle
Compute pi (not very fast)
Sort bytes

Naming

The language is named after Rui from Kimetsu no Yaiba, by suggestion of User:LyricLy.

Implementations

An example implementation in Ruby is found here.

Here's an optimizing interpreter in C by Daniel Cristofani.

yaiba, an unoptimizing interpreter written in Rust, by User:LyricLy.

Turing-Completeness

Rui is Turing-complete (proved by Daniel Cristofani, by translation from Minsky machines given here).