Suptiftam

From Esolang
Jump to navigation Jump to search

Suptiftam is an esolang created by User:PythonshellDebugwindow.

Datatypes

Suptiftam uses integers (signed and unbounded), 8-bit bytes (unsigned and wrapping), and tape-tapes—two-dimensional tapes unbounded in all four directions, initialized to all zeros—of either type (an individual tape-tape, however, cannot contain both types).

Functions

Functions in Suptiftam must take one argument and can return no result. They need not be pure.

Builtins

Suptiftam has the following builtin functions, each of which takes a tape-tape as an argument.

  • down moves its argument's head down
  • left moves its argument's head left
  • right moves its argument's head right
  • up moves its argument's head up
  • include reads the 0th line of its argument as a null-terminated string and includes the file with that name, if there is one

It is undefined behavior if an integer or byte is passed to any of these functions.

Syntax

Each statement must be on its own line. Spaces can only appear in function definitions' first lines, and even then only to separate identifiers; anywhere else, they will cause a fatal syntax warning.

Literals

Integer literals are written in base 14 (with capital letters) and parsed in base 23; for example, 10 would yield 23 and 1D would yield 36. Byte literals are written as a printable, non-whitespace (a space here will still result in a "warning") ASCII character between single quotes; for example, 'A' yields 65, '\' yields 92 (note: there are no escape sequences in Suptiftam) and '*' yields 42. There are no tape-tape literals; a variable must be made in order to construct a new one.

Identifiers

Identifier (function names, function argument names, and variable names) must be entirely alphabetical, in the extended Latin, Greek, and/or Cyrillic alphabets.

Function definitions

Function definitions are started by a line containing the keyword fd, the function name, and the function's argument followed by a colon, all in no particular order. This means that fd x y:, x y: fd, and y: fd x are all functionally the same. Between this line and the matching fi (stolen from Bash), all code is the function's body.

Redefining a function doesn't overwrite the original, but instead appends the new body to the old one; this is called extending the function.

Function calls

Function calls can be written almost as they would be in Python: f(:x:) calls f on x. However, the four tokens (function name, both parentheses, and argument) can be written in any order, meaning that f:x:(), )f(:x:, and ():x:f are all the same.

Conditional function calls

Functions can be called conditionally by appending, prepending, or intrapending if(y) (which is considered to be one token) to a function call. This calls the function only if y is nonzero (if y is a tape-tape, then compare the value under its head). For example, :x:if(y)f (among 119 other combinations) calls f on x if y (or the value under its head) is nonzero.

Variable declaration

To declare a variable as an integer or a byte, write varname~value; this detects the type of value, creates a variable of that type called varname, and sets it to value. To declare a variable as a tape-tape, write varname[TYPE] where TYPE is either integer or byte, which, contrary to all logic, signify bytes and integers respectively.

Variable assignment

To assign the value value to the variable varname, write varname=value. Assigning a value to a tape-tape assigns to the tape-tape's current cell instead of the tape-tape itself, and if the value to assign is a tape-tape, its current cell is used instead. If the types of the value and the variable do not match (or, if the variable is a tape-tape, the type of its cells), then the variable is left unchanged and a random digit is printed to the output terminal's current cell (see #I/O format).

Math

The syntax to calculate x op y is %op[x]y%. Operations cannot be nested. For example, to find the sum of 6 and 36, you could write %+[6]1D%, which might be written as 6 + 36 in a more conventional language. Valid operators are + for addition, - for subtraction, and / for division (you must make multiplication yourself).

Comments

If a tab appears anywhere in a line, that line is a comment.

Scope

There is a global scope. In addition, each function has its own scope. In case of conflict, the most global name is used. All functions, including nested ones, belong to the global scope, as all function definitions (including nested ones) are "hoisted", or brought to the beginning of the file, before the program begins.

Including

Including a file means that its contents will be executed immediately in the global scope of the main file. The same file can be included multiple times.

I/O format

Input and output are represented as separate tape-tapes, named read and term (short for terminal). read is read before the start of the program, and term should be updated live (or at least printed after the program ends).

Integers with no digits

The expression A could be the literal value 10, or it could be a variable. This, and other expressions like it, are parsed in the following way:

  1. If it is a variable, evaluate to the variable's value;
  2. otherwise, evaluate it as an integer literal.

This means that in the following program, x will be equal to 10 and y will be equal to 7.

x=A
A=7
y=A

Examples

Untested.

Hello, world!

term='H'
right(:term:)
term='e'
right(:term:)
term='l'
right(:term:)
term='l'
right(:term:)
term='o'
right(:term:)
term=','
right(:term:)
term=%-['a']'A'%
right(:term:)
term='w'
right(:term:)
term='o'
right(:term:)
term='r'
right(:term:)
term='l'
right(:term:)
term='d'
right(:term:)
term='!'

Truth-machine

fd tmach x:
term=x
right(:term:)
tmach(:x:)if(x)
fi
tmach(:%-[read]48%:)

Cat program

Can't handle blank lines or null characters (ASCII zero).

fd cat :x
term=read
right(:term:)
right(:read:)
cat(:x:)if(:read:)
eol(:x:)if(:%-[1]read%:)
fi
fd eol :x
down(:term:)
down(:read:)
setXNegOne(:term:)
setXNegOne(:read:)
right(:term:)
right(:read:)
cat(:x:)if(:read:)
fi
fd setXNegOne :tt
left(:tt:)
setXNegOne(:tt:)if(:tt:)
fi
cat(:0:)