FXYT

From Esolang
Jump to navigation Jump to search
FXYT
Paradigm(s) imperative
Designed by Susam Pal
Appeared in 2023
Computational class Total
Reference implementation susam.net/fxyt.html
Influenced by Forth, Tixy, CFRS[]
File extension(s) .fxyt

FXYT is a stack-based, postfix, canvas colouring language. It contains 36 commands, each represented by a single character. FXYT code is written as a string of FXYT commands next to each other which operate on the data stack. The output is displayed on a 256x256 graphical canvas. The code is evaluated for each of the 65536 cells of the canvas and the result left on the stack at the end of each evaluation determines the colour of each cell.

If we represent the coordinates of each cell in the canvas with the notation (x, y), then we can say that a given FXYT code is evaluated for each cell (x, y) where x, y are integers between 0 and 255 (inclusive) and the colour of each cell (x, y) is determined by the result of the evaluation. Further, FXYT code may be time-dependent too. Such code is evaluated in 256 iterations where we represent each iteration with a time variable t which changes from t = 0 to t = 255. In other words, time-dependent code is evaluated for each cell (x, y, t) where x and y represent the coordinate of each cell in the canvas and t represents the iteration of evaluation.

For example, the code XY+N128% (see screenshot of the output below) adds the x-coordinate value of each cell to its y-coordinate value and then obtains a remainder modulo 128. The result is used to choose the colour each cell (x, y) is painted with.

FXYT stands for function of x, y, and t and it may be pronounced "fixit".

Background

Output of the program XY+N128%
Output of the program XY^D
Output of the program XYN1+%DNS

FXYT is inspired by Tixy and Forth. Like Tixy, FXYT has a graphical grid where the colour of each cell is determined by the output of the program evaluated with the coordinates of each cell as input. Like Forth, it is a stack-oriented language with postfix notation. Most commands of FXYT operate on the data stack.

The Git project repository at github.com/susam/fxyt introduces the FXYT language and provides a web-based implementation written using HTML5 Canvas and JavaScript.

Implementation

A reference implementation is available at susam.net/fxyt.html.

Examples

Canvas

The colouring canvas is divided into a grid of 256x256 cells. Each cell has a coordinate represented in the form (x, y) where x represents the column of the cell and y represents the row of the cell. The value of x varies from 0 to 255 as we move from the leftmost column to the rightmost column. Similarly, the value of y varies from 0 to 255 as we move from the bottommost row to the topmost row.

Data Stack

The runtime environment contains exactly one data stack. Most FXYT commands manipulate this data stack. This data stack can contain at most 8 integer values.

Loop Control Stack

Apart from the data stack, there is a loop control stack. Unlike the data stack, the loop control stack cannot be manipulated directly. The loop control stack is an internal implementation detail of the two looping commands [ and ] introduced later in this document. Each entry in the loop control stack is a pair of integers: loop counter and loop body position. This stack can contain at most 8 such entries. As a result, while executing nested loops, at most 8 nested loop bodies can be entered. It is an error to enter a loop that is 9 levels deep.

Colours

Commands of FXYT manipulate the data stack. As mentioned before, the input code is evaluated for each cell at (x, y) for time-independent code. If the input code is time-dependent, then it is evaluated for each cell at (x, y, t).

At the end of evaluation of the code for each cell, the top 3 values of the data stack is inspected to determine the red, blue, and green (RGB) components of the colour of the cell. The value at the top of the data stack is used as the blue component, the second value from the top is the green component, and the third value from the top is the red component.

Suppose the data stack looks like the following after the evaluation of the input code for a certain cell: [10, 20, 30, 40, 50]. Then the colour used to paint that cell in RGB notation is rgb(30, 40, 50).

For example, consider the following code:

YYY

When this code is evaluated for each cell of the canvas, the y-coordinate value of the cell is pushed to the data stack three times. At the end of each evaluation, the three values at the top of the data stack determine the RGB components of the colour. Since they are all equal, we get a shade of grey for each cell.

If less than three values exist on the data stack at the end of evaluation, then values for the missing RGB components are set to 0. For example, consider the following code:

YY

At the end of evaluation, the data stack contains only two values, so they decide the values of the blue and green components. The red component is set to 0. Thus each cell gets a shade of cyan. Finally consider this code:

Y

This time we get only one value on the data stack at the end of each evaluation and that only value determines the blue component of the colour of each cell.

If the data stack is empty at the end of evaluation, then all three components of the RGB colour is set to 0 and the corresponding cell is painted black. For example, consider the following code:

XP

The X command pushes the x-coordinate value to the data stack but then the P command pops it off the data stack. Thus the data stack becomes empty at the end of each evaluation. As a result, all cells are painted black. In fact, when the input code is empty, the evaluation of the empty code results in an empty stack thus leading to a black canvas too.

The three values at the top of the data stack must be integers between 0 and 255, inclusive, because they are interpreted as the red, blue, and green components of the resulting RGB colour. If any value among these three values is negative, it is an error. Similarly, if any of these values exceed 255, it is an error.

If an error occurs during the evaluation of the code, the error is displayed in the status panel and the entire canvas is painted red.

Commands

Here is a brief summary of all FXYT commands:

  • X: Push x-coordinate value of the current cell to the data stack. The cells on the leftmost edge of the canvas have 0 as their x-coordinate values. The cells on the rightmost edge of the canvas have 255 as their x-coordinate values.
  • Y: Push y-coordinate value of the current cell to the data stack. The cells on the bottommost edge of the canvas have 0 as their y-coordinate values. The cells on the topmost edge of the canvas have 255 as their y-coordinate values.
  • T: Push t-value of the current iteration of evaluation to the data stack. Any code containing this command is rendered in 256 iterations where t takes integer values from 0 to 255.
  • N: Push 0 to the data stack.
  • 0-9: Multiply the value at the top of the stack with 10 and add the given number to it. In other words, append digit to the value at the top of the data stack. For example, if the value at the top of the stack is 20, then the command 3 changes that value to 203.
  • +: Pop two values from the data stack and push their sum to the data stack.
  • -: Pop two values from the data stack. Then subtract the value popped first from the value popped second and push the result to the data stack.
  • *: Pop two values from the data stack and push their product.
  • /: Pop two values from the data stack. Then use the value popped first to divide the value popped second, discard fractional part from the result, and push the integer result to the data stack.
  • %: Pop two values from the data stack. Then use the value popped first to divide the value popped second, obtain a nonnegative remainder, and push the remainder to the data stack.
  • =: Pop two values from the data stack. If they are equal, push 1 to the data stack. Otherwise push 0.
  • <: Pop two values from the data stack. If the value popped second is less than the value popped first, push 1 to the data stack. Otherwise push 0.
  • >: Pop two values from the data stack. If the value popped second is greater than the value popped first, push 1 to the data stack. Otherwise push 0.
  • !: If the value at the top of the data stack is 0, change it to 1. Otherwise change it to 0.
  • ^: Pop two values from the data stack, perform bitwise XOR operation on the values, and push the result to the data stack.
  • &: Pop two values from the data stack, perform bitwise AND operation on the values, and push the result to the data stack.
  • |: Pop two values from the data stack, perform bitwise OR operation on the values, and push the result to the data stack.
  • C: Clip the value at the top of the data stack between 0 and 255, i.e., if the value is less than 0, change the value to 0, and similarly, if the value is greater than 255, change the value to 255.
  • D: Duplicate the value at the top of the data stack by pushing a copy of it.
  • P: Pop one value from the data stack.
  • S: Swap the two values at the top of the data stack.
  • R: Rotate the three values at the top of the data stack. The third value from the top of the stack is brought to top. The value at the top of the stack moves to the second place from the top. The value at the second place from the top moves to the third place from the top.
  • [: Pop one value from the data stack and begin loop with the popped value as the loop counter. All code from the command after the opening [ up to the corresponding ] forms the body of the loop. If the loop counter is positive, enter the loop body. Otherwise skip the loop. The loop counter is maintained in the loop control stack which cannot be accessed directly by the programmer.
  • ]: Decrement the loop counter. If the counter is still positive, jump back to the beginning of the loop body of the current loop. Otherwise exit the loop. The loop counter is removed from the loop control stack while exiting the loop.
  • W: Display current coordinate and stack in the status panel and halt. The stack is printed from bottom to top.
  • F: Pop one value from the top of the stack and set the frame interval to that many number of milliseconds. The default frame interval is 100 ms.
  • M: Increment mode number. The default mode number is 0. In mode 0, division by zero leads to an error. In mode 1, division by zero leads to a black cell. In mode 2, division by zero leads to a red cell. It is an error to increment mode value beyond 2.

Idioms

The following idioms may be useful while writing FXYT code:

  • To place an arbitrary positive integer on the data stack, write N followed by the decimal digits of the integer. For example, N105 places the integer 105 on the data stack. The code N105 may be informally read as the number 105. This works because N pushes the integer 0 to the data stack and every digit command multiplies the number at the top of the stack with 10 and adds the digit to it. So when N105 is evaluated, first the command N pushes the integer 0 to the stack. Then the command 1 changes the value 0 at the top of the stack to 10 * 0 + 1 = 1. Then the command 0 changes the value 1 at the top of the stack to 10 * 1 + 0 = 10. Finally the command 5 changes the value 10 at the top of the stack to 10 * 10 + 5 = 105.
  • To place an arbitrary negative integer on the data stack, write NN followed by the digits of the integer followed by -. For example, NN105- places the integer -105 on the data stack. The code NN105- may be informally read as the negative number 105.
  • To increment an integer at the top of the data stack, write N1+. Similarly, to decrement an integer at the top of the data stack, write N1-.
  • To check if the top two values on the data stack are unequal, write =!. This replaces the two values at the top of the data stack with 1 if they are unequal, 0 otherwise.
  • To execute a block of code conditionally, push 1 on the data stack if the block should be executed and 0 otherwise, and then write a loop with the code block in it. For example, the code YN10=[N255] places the integer 255 on the data stack if the y-coordinate value equals 10.