Trilangle

From Esolang
Jump to navigation Jump to search

Trilangle is a 2-D, stack-based programming language. Despite only having one stack for memory, it's possible to peek arbitrarily deep, which makes it Turing complete (modulo memory limitations).

Source layout

All Trilangle programs are considered to be triangles. Technically, the code occupies a hexagonal grid, but the boundary of that grid is triangular.

A plain grid, represented with dots, may look like this:

    .
   . .
  . . .
 . . . .
. . . . .

The interpreter starts at the north corner, moving southwest. Once it walks off the grid, it continues one row or diagonal to its left. As such, a ten-cell grid is read in this order:

   0
  1 4
 2 5 7
3 6 8 9

However, it is possible to change the direction of movement. |, /, \, and _ represent the same mirrors as in Hexagony. < and > are similar to Hexagony, but differ in their treatment of zero, and there are four more such instructions that there's a branch in each direction: < west, ^ northwest, 7 northeast, > east, v southeast, L southwest.

Data storage

The only datatype in Trilangle is the 24-bit signed integer. Characters read from stdin or added to the stack by a push instruction are taken as their Unicode value (as in UTF-32); EOF is stored as -1.

Instruction set

Many of the instructions are taken from other esolangs: +-*:% for arithmetic (/ already has meaning), () for decrement and increment, . for NOP, # to skip an instruction, and @ to end the program. Some instructions that were created without specific inspiration include:

  • " and ' for "push". " pushes the Unicode value of a character, while ' pushes its numeric value. The behavior of ' for numbers outside the ASCII 0..9 range is unspecified: for example, the reference implementation interprets '↉ as 8537, but it would be equally correct for another implementation to interpret it as 0 (since ↉ is 0), or to simply end execution due to an unexpected character.
  • e to pop a value from the stack and compute 1 << value. This allows for quick computation of powers of two, and enables the creation of bitmasks without having to push strange Unicode characters.
  • j, the indexed read instruction. This pops a value from the stack and uses it as a (0-based) index to peek that far down the stack, after which the value is copied and pushed back. Though the inability to write arbitrarily far down the stack makes it difficult to have multiple working values, only the ability to read down the stack is necessary for Turing-completeness.
  • (U+FFFD) terminates the program with an error. The program is interpreted as UTF-8, and any invalid UTF-8 sequences are stored as this internally, but it only causes an error when the interpreter actually attempts to execute it. This is the only non-ASCII character whose execution has defined behavior.
  • { and } for "threads". These instructions create, join, or remove threads, depending on the direction the IP is travelling in. It might be possible to have Turing completeness without j using these, but j was added first.

Sample programs

Hello, World!

        "
       H o
      o " !
     " o ( o
    e o o o l
   o " " " o "
  " , W r " ! 3
 l o o o d o : o
o " " " o ' ( @ .

cat

   <
  > i
 , @ #
# o . .

Prime test

        '
       2 .
      ? . .
     < _ . @
    j . 2 ' 2
   , < | > ( %
  ! . \ S ) S ,
 , ) S < . . . .
. @ > - . . . . .

GCD

     ?
    ? ,
   < ! .
  j . 1 '
 > ( | # %
. @ \ S ) <

External links

  • Github repo containing reference implementation and proof of Turing-completeness