Transio

From Esolang
Jump to navigation Jump to search

Transio is an assembly-like esoteric language based on transactions. The name stands for "transactional I/O". Every line of code is a transaction in the format destination <- source. There are two kinds of destinations: the special ports (or special registers) and regular ports (also regular registers or simply registers). And there are three kinds of sources: the same two kinds of destinations plus numeric literal (which are always in hexadecimal base).

Examples

Hello World

The program below prints Hello, World!\n to stdout.

io <- $48
io <- $65
io <- $6C
io <- $6C
io <- $6F
io <- $2C
io <- $20
io <- $57
io <- $6F
io <- $72
io <- $6C
io <- $64
io <- $21
io <- $A

Cat

The program below reads all its input, byte by byte, and prints it back to the stdout.

ip <- $1
io <- byte
byte <- io
front1 <- byte
cmp <- $FFFF
add <- $1
mul <- $7
ip <- front1

Informal Standards

Transio 18:1

This (informal) standard is the first Transio standard of 2018 (also the first ever), thus its name is Transio 18:1.

Lexic/Syntax

There are five classes of tokens:

  1. Whitespace: a sequence of either unicode character 9, 10, 13 or 32 (which are all discarded).
  2. Comments: a sequence of characters starting with unicode character 35 (#) and ending at its first newline (unicode character 10) or with end of input, in case there is no newline (which are all discarded).
  3. Transaction Operator: two characters together which are <- (unicode characters 60 and 45).
  4. Identifiers: a non-empty sequence of characters. Each character ranges from either a-z (unicode characters 97 and 122), A-Z (unicode characters 65 and 90) or 0-9 (unicode characters 48 and 57), all inclusive. Also, _ (underscore, unicode character 95) is allowed. The only rule for combining them is: the sequence must be non-empty.
  5. Literals: a sequence of hexadecimals digits prefixed with $ (unicode character 36). A single valid character to be inserted at the digits sequence range from either a-f (unicode characters 97 and 102), A-F (unicode characters 65 and 70), or 0-9 (unicode characters 48 and 57). 0-9 represents themselves, while both a-f and A-F represents 10-15. The sequence is allowed to be empty, but the dollar prefix is required always. An empty digit sequence implies in zero. Extra prefix zero are allowed as well.

The source code is required to be ASCII compatible, excluding the comment contents, which may contain arbitrary bytes.

There are to kinds of expressions:

  1. Left values: a single identifier.
  2. Right values: either a single identifier or a single literal.

A transactions formed by a left value, immediately followed by a transaction operator, immediately followed by a right value.

A program consists of a sequence of transactions.

Whitespace and comments are allowed to appear anywhere, and may help separating different tokens.

Overflowing numeric literals are wrapped (16 bits).

Semanthics

A transio program state consist of the following items:

  • Instruction pointer (ip): an internal pointer which points to the current executing transaction. After each transaction, the pointer is incremented by one. The first transaction is mapped to zero in terms of instruction pointing.
  • Regular ports/registers: a collection of all the custom registers found in the code, initialized to 0, and each one keeps a 16 bit unsigned integer.
  • Deque 1: a doubly-ended queue of 16 bit unsigned integers.
  • Deque 2: a second doubly-ended queue of 16 bit unsigned integers.
  • IO: standard input and output devices of the program.

Every identifier token found on parsing maps to a port/register. However, there are some special and reserved registers.

Reserved Registers
Name In left position In right position
io Prints the right value first 8 bits to stdout. Reads a single byte from stdin to the left value, and if end-of-input is found, the left value has its bits filled with 1 (65535).
ip Changes instruction pointer to the right value modulo (number of transactions + 1). After the current transaction, the pointer is incremented. Puts the current instruction pointer value into the left value.
front1 Pushes the right value onto the front of deque 1. Pops the value from the front of deque 1, and if there is a value, puts it into the left value, otherwise puts 0.
front2 Pushes the right value onto the front of deque 2. Pops the value from the front of deque 2, and if there is a value, puts it into the left value, otherwise puts 0.
back1 Pushes the right value onto the back of deque 1. Pops the value from the back of deque 1, and if there is a value, puts it into the left value, otherwise puts 0.
back2 Pushes the right value onto the back of deque 2. Pops the value from the back of deque 2, and if there is a value, puts it into the left value, otherwise puts 0.
add Pops a value from the front1, sum it with the right value, and pushes the sum onto the front1. Pops two values from front1, sums them, and put the result in left value.
mul Pops a value from the front1, multiplies it with the right value, and pushes the product onto the front1 Pops two values from front1, multiplies them, and put the result in the left value.
xor Pops a value from the front1, performs xor on its bits it with the right value's bits, and pushes the result onto the front1 Pops two values from front1, performs xor on their bits, and put the result in the left value.
and Pops a value from the front1, performs and on its bits it with the right value's bits, and pushes the result onto the front1 Pops two values from front1, performs and on their bits, and put the result in the left value.
shl Pops a value from the front1, shifts its bits to the left by right value places, and pushes the result onto the front1 Pops two values from front1, shifts the second popped value's bits to the left by the first popped value and put the result in the left value.
shr Pops a value from the front1, shifts its bits to the right by right value places, and pushes the result onto the front1 Pops two values from front1, shifts the second popped value's bits to the right by the first popped value and put the result in the left value.
cmp Pops a value from the front1, compares it with the right value. If the popped value is greater, 1 is pushed onto the front1, if it is less, 65535 is pushed onto the front1, if they are equal, 0 is pushed onto the front1. Pops two values from front1, and compares the second popped value with the first popped value. If the second value is greater, 1 is put into the left value, if it is less, 65535 is put into the left value, if they are equal, 0 is put into the left value.

Notes

Overflow on addition and multiplication wraps. Overflow on shift left and shift right results in zero.

The behavior of regular registers on left value is storing a value into its mapped integer. The behavior of regular registers is loading the value of its mapped integer.

Putting the instruction pointer at one number beyond the number of transactions cause the program exit.

Since literals are only allowed as right values, they evaluate to their integer values.

Executing a transaction after the 65536th one is undefined behavior. The implementation may choose a way of handling it, but it is advised that it emit an error.

Implementations

Computational Class

Any brainfuck program can be translated to transio. The tape can be implemented by glueing the two deques. A register may hold the current cell, while the previous cells are in deque 1's back and the next cells are in deque 2's front. Incrementing is just adding 1 with the add port/register. Decrementing is just adding 65535. Looping can be done via reading ip, performing comparisons + arithmetic on comparison and ip as shown in Cat program.

Therefore, Transio is Turing Complete