Suptiftam
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 downleft
moves its argument's head leftright
moves its argument's head rightup
moves its argument's head upinclude
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:
- If it is a variable, evaluate to the variable's value;
- 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:)