toki pi ilo nanpa
Paradigm(s) | imperative |
---|---|
Designed by | User:Olus2000 |
Appeared in | 2021 |
Computational class | Turing-complete |
Reference implementation | Python |
Influenced by | toki pona Lua |
File extension(s) | .tin .til (bytecode) |
toki pi ilo nanpa ("computer language" in toki pona) is a Pseudonatural programming language in development based on toki pona (language of good), a minimalistic constructed language invented by Sonja Lang, and Lua, a popular scripting language. The aim of the esolang is to make it's programs resemble valid toki pona sentences as closely as possible.
Lexical conventions
Identifiers in toki can be any word viable under toki pona word building rules, excluding the rules about banned letter pairs. This means an identifier must start with a (C)V(n) capitalised syllable and continue using CV(n) syllables, all using letters avaliable in toki pona: aeioujklmnpstw
. Identifiers are used to name variables.
The following keywords are currently used in the language. Note that even if they were not reserved they wouldn't be viable identifiers because of their lack of capitalisation.
ala ale ali e en ijo kepeken kipisi kulupu la li lili lon luka lukin mute nanpa ni nimi o open pali pana pi pini sin sitelen suli tu wan
The other tokens are .
for ending sentences and "
for literal strings.
Literal strings are prefixed by nimi
, have to be delimited by a pair of double quotes and can contain any characters. Allowed escape sequences are '\"' for a literal double quote, '\\' for a literal backslash and '\n' for a newline.
A numerical constant is prefixed with nanpa
and consists of a ala
for a 0 or a non-decreasing series of toki pona number words with values as follows:
word | ale /ali |
mute |
luka |
tu |
wan |
ala
|
---|---|---|---|---|---|---|
value | 100 | 20 | 5 | 2 | 1 | 0 |
Values and types
toki pi ilo nanpa is a dynamically typed language. This means that variables do not have types; only values do. There are no type definitions in the language. Values carry their own type.
All values in toki are first class values, meaning they can be stored in variables, passed to functions and returned as results.
There are seven basic data types in toki: ala
, lon
, nanpa
, nimi
, kulupu
, pali
and lipu
. ala
is the type of value ala
, whose main property is to be different from the other value. It usually represents the absence of a useful value. It's similar to 'Nil' or 'None' from other languages. lon
is type of values lon
and it's inverse - lon ala
which represent boolean values of true and false. Both ala
and lon ala
make a condition false; any other values make it true. nanpa
represents integer values, optimally unbounded but that may depend on the implementation; every implementation must allow for positive and negative integers. There is no way to get non-integer values in toki as it lacks any form of division operation, although users are encouraged to implement their own real number system with the tools given by the language. nimi
represents arrays of characters. It can contain any of the 8-bit character values including embedded zeros.
kulupu
implements associative arrays (later called 'tables'), that is, arrays that can be indexed not only with numbers, but with any value (including ala
). Tables can be heterogeneous; that is, they can contain values of all types (including ala
). Tables are the sole data structuring mechanism in toki; they can be used to represent ordinary arrays, symbol tables, sets, records, graphs, trees, etc. To represent records, toki uses the field name as an index. There is only one way to create a new table in toki: expression kulupu
evaluates to a new empty table.
pali
is a type of a paragraph - a set of sentences to be executed in order. Variables holding a pali
value is similar to functions from other languages. A value holding a refernece to the paragraph currently being executed can be obtained using an expression pali ni
.
lipu
is a type of a file open for reading or writing. It is created using the verb open
and is used as an argument to verbs sitelen
(for writing) and lukin
(for reading).
kulupu
and pali
are not stored directly in the variables. Variables contain only references to these values. This means that parameter passing, assignment and function returns will copy a reference, not the full value. It also means that they can be freely used as table keys.
Expressions and operators
The basic expressions in toki are the following:
expr := literal expr := var expr := nanpa nasa expr := expr binop expr expr := expr ala
nanpa nasa
evaluates to a random integer between some boundaries. Original implementation uses a random byte but it is allowed to vary between implementations.
toki uses two binary operators:
pi
- returns value of a field of table from the first argument indexed by the second argument or a character of the string from the first argument indexed by the second argument (first character being 0). If there is no such field or character or the first argument isn't a table or string returnsala
. Takes precedence overen
.en
- adds two numbers, concatenates two strings or boolean add two boolean values; if arguments aren't strings, numbers or booleans or have different types returnsala
.
toki has one unary postfix operator ala
which takes precedence before en
but not pi
and serves as a negation operator: if given a number it will return its integer negative, and if given a boolean it will return its boolean negative. In other cases it returns ala
.
Binary operator precedence allows for arithmetic on table contents, but not for arithmetic on table indexes which should be calculated beforehand and stored in variables.
Sentences
Sentences are to toki what statements are to usual programming languages. They include assignments, control structures and function calls. Each sentence ends with a .
. The most basic sentence is o expr.
which evaluates 'expr' and discards its value.
Assignment
Assignments are the second sentence type and their syntax is var li expr.
. expr
can be any expression. var
can be one of the three types of variable declarations/references:
ijo lili Identifier
- declares/references a local variable "Identifier" (obviously "Identifier" is not a legal identifier, it's only used here as a placeholder)ijo suli Identifier
- declares/references a global variable "Identifier"ijo Identifier
- searches for variable "Identifier" from the top layer of local variables through locals declared by parent paragraphs ending with the global variables and references the first one found. If found none then declares a global variable.table_expr pi key_expr
- sets a field of the table returned by table_expr indexed by the value of key_expr.
Control structures
The only control structure in toki is a conditional prefix. To achieve loops use recursion.
Conditionals work by prepending a conditional prefix to any sentence. The sentence is then skipped if the prefix evaluates to lon ala
or ala
and executed otherwise. If the sentence opens a paragraph the whole paragraph is skipped or executed. Any number of conditions can be prepended to any sentence; they will be evaluated from left to right until one fails or all pass and the main sentence is executed.
There are four types of conditional prefixes:
expr la
- uses the value of the expressionexpr li lili la
-lon
ifexpr
is numeric and less than zero,lon ala
otherwiseexpr li suli la
-lon
ifexpr
is numeric and more than zero,lon ala
otherwiseexpr li expr la
-lon
if expressions are equal,lon ala
otherwise
Verb sentences
Verb sentences have a verb expression instead of their main expression. The verb operators may take a main argument introduced with e
and a list of subarguments, each introduced with kepeken
. Excess arguments are ignored and lacking arguments are assumed to be ala
. The general syntax of verb sentences is:
[condition la ...] o verb [e expr [kepeken expr ...]]. [condition la ...] var li verb [e expr [kepeken expr ...]].
The list and specification of verb operators may change between implementations, but there is a list proposed by the author:
pali e pali_expr kepeken Arg1 (...) kepeken ArgN
- execute paragraph pali_exp with arguments Arg1 through ArgN and return it's value. Returnsala
if pali_exp is not of typepali
.pana e expr
- stop executing the current paragraph and returnexpr
.lukin e lipu_expr
- returns a string - a single line read fromlipu_expr
, or the standard input iflipu_expr
is not of typelipu
and open for reading, including the trailing newline if present. Returns empty strings after reading through the whole input.sitelen e nimi_expr kepeken lipu_expr
- writes its argument tolipu_expr
, or standard output iflipu_expr
is not of typelipu
and open for writing. Non-string values are converted to[type_name]
strings.kipisi e nimi_expr kepeken nanpa_expr1 kepeken nanpa_expr2
- return a substring of nimi_expr starting from nanpa_expr1 (zero-indexed) up to but not including nanpa_expr2. If nimi_expr is not animi
returnsala
. If nanpa_expr1 is notnanpa
or is smaller than 0 it's corrected to 0. If nanpa_expr2 is notnanpa
or is bigger than the string's length it's corrected to the string's length. If nanpa_expr1 is greater or equal nanpa_expr2 the resulting string is empty.open e nimi_expr kepeken mode
- tries to open filenimi_epxr
and return it as alipu
value. If it fails ornimi_expr
is not of typenimi
returnsala
. Ifmode
evaluates tonimi "sitelen"
the file is open for writing, otherwise it's open for reading.pini e lipu_expr
- closes the filelipu_expr
which makes sure any data written to it is saved on disc. Prevents any further reads or writes to or from the file.
Paragraph definitions
Paragraph definitions are a special case of sentences that start new paragraphs. The defined paragraph is then passed as a value of a pali sin
expression. There are three types of paragraph definitions corresponding to assignment, verb and verb assignment sentences:
o pali e pali sin [kepeken expr ...]. var li pali sin. var li pali e pali sin [kepeken expr ...].
Each of those types can also have conditional prefixes like any sentence. Paragraphs opened with a paragraph definition end with pali sin li pini.
Paragraphs
Paragraphs are multiple sentences executed sequentially. Every paragraph including the main program is stored as a pali
type value. Local variables are local to the paragraph they were declared in but can be used or changed by paragraphs called from within the paragraph they were declared in. A new paragraph definition starts after a paragraph definition sentence and ends with a sentence pali sin li pini.
at which point the pali sin
expression in the paragraph definition sentence will return a value of type pali
containing the paragraph. Paragraphs are executed using the verb pali
.
Any paragraph can recieve arguments. The arguments are specified with pali ni li kepeken e ijo Arg1 (...) e ijo ArgN.
on the first sentence of the paragraph. If the any arguments are passed to the paragraph when it's called their values are assigned to their respective variables. Any excessive arguments are discarded, and any variables that didn't get an argument are assigned ala
. The main paragraph (the whole program) is called with two arguments: a string with a script name and a table of command line arguments.
Any paragraph will return a single value. The value returned and the return point of the paragraph can be specified with the verb pana
. Executing this sentence will exit the current paragraph. After executing the last sentence in the paragraph it will return ala
.
Errors and exceptions
The only errors possible in toki are parsing errors which are left to be implemented in the interpreters/compilers. Correct toki pi ilo nanpa code always executes without errors, although it may turn some values to ala
if things don't go as planned.
Missing features
There's a lot of features in standard programming languages that toki pi ilo nanpa lacks. This section is dedicated to implementing them and working around the minimalism.
Comments
toki doesn't have comments, but it's very easy to write code that will do nothing when executed and can carry an arbitrary message: o nimi "comment".
. Such comment may span any number of lines and be inserted in any place in code a normal sentence could, because it is just a sentence. The main drawback of this approach is the amount of additional useless strings the interpreter will be forced to store, although a well implemented interpreter would find and eliminate such constructs at parse-time.
Loops
Loops in toki are implemented with recursion; this is the main motivation behind pali ni
construct. To create a while loop simply put a o pali e pali ni.
under a condition at the end of a paragraph. An iterator can be passed to the looping paragraph to emulate a for loop. Using pseudocode:
loop_start_condition la o pali e pali sin kepeken iterator_starting_value. pali ni li kepeken e ijo iterator. loop body. loop_continue_condition la o pali e pali ni kepeken changed_iterator. pali sin li pini.
Finding length of a string/table
Getting the length of the string or a table that is used as a continous array is a very useful feature that toki lacks. Fortunately it can be easily implemented by binary-searching and checking if an element of a certain number exists. The function has O(log(n))) complexity.
pali ni li kepeken e ijo Kulupu e ijo I. o nimi "Kulupu is the string/table we are measuring, I is an iterator, should be initialised at one". ijo lili Ansa li nanpa ala. ijo lili Seme li lon. ijo Kulupu pi ijo I li ala la ijo Seme li lon ala. o nimi "Run this recursively doubling the I until you jump over the end of string/table". ijo Seme la ijo Ansa li pali e pali ni kepeken ijo Kulupu kepeken ijo I en ijo I. ijo lili En li ijo Ansa en ijo I en nanpa wan ala. ijo Seme li lon. ijo Kulupu pi ijo En li ala la ijo Seme li lon ala. ijo Seme la o pana e ijo Ansa en ijo I. o pana e ijo Ansa.
Multiplication
These two of the basic math operations are not present in toki. Multiplication can be implemented using a simple loop in O(n) or using a binary method in O(log(n)):
pali ni li kepeken e ijo A e ijo E. o nimi "Make sure we are iterating over a smaller number". ijo lili Seme li lon ala. ijo A en ijo E ala li suli la ijo lili Seme li lon. ijo Seme la ijo lili Ansa li pali e pali ni kepeken ijo E kepeken ijo A. ijo Seme la o pana e ijo Ansa. o nimi "The actual multiplication loop". ijo lili Ansa li pali e pali sin kepeken ijo A kepeken ijo E kepeken nanpa wan. pali ni li kepeken e ijo A e ijo E e ijo I. ijo lili Ansa li kulupu. ijo Ansa pi nanpa wan li nanpa ala. o nimi "Ansa[1] holds how much we already multiplied". ijo Ansa pi nanpa tu li nanpa ala. o nimi "Ansa[2] holds the current multiplication outcome". ijo I en ijo A ala li lili la ijo lili Ansa li pali e pali ni kepeken ijo A kepeken ijo E en ijo E kepeken ijo I en ijo I. ijo lili Seme li lon. ijo Ansa pi nanpa wan en ijo I en ijo A ala li suli la ijo lili Seme li lon ala. ijo Seme la ijo Ansa pi nanpa wan li ijo Ansa pi nanpa wan en ijo I. ijo Seme la ijo Ansa pi nanpa tu li ijo Ansa pi nanpa tu en ijo E. o pana e ijo Ansa. pali sin li pini. o pana e ijo Ansa pi nanpa tu.
Division and modulo
Division and modulo are similar problems to multiplication and can be implemented using a single binary divmod method in O(log(n)):
pali ni li kepeken e ijo A e ijo E. ijo lili Ansa li kulupu. ijo Ansa pi nanpa wan li nanpa ala. o nimi "Ansa[1] stores the outcome". ijo Ansa pi nanpa tu li ijo A. o nimi "Ansa[2] stores the retmainder". ijo E en ijo A ala li lili la ijo Ansa li pali e pali ni kepeken ijo A kepeken ijo E en ijo E. ijo Ansa pi nanpa wan li ijo Ansa pi nanpa wan en ijo Ansa pi nanpa wan. ijo lili Seme li lon. ijo E en ijo Ansa pi nanpa tu ala li suli la ijo Seme li lon ala. ijo Seme la ijo Ansa pi nanpa tu li ijo Ansa pi nanpa tu en ijo E ala. ijo Seme la ijo Ansa pi nanpa wan li ijo Ansa pi nanpa wan en nanpa wan. o pana e ijo Ansa.
Computational class
toki is Turing-complete because it can be used to simulate Bitwise Cyclic Tag using the following code, and BCT is Turing-complete.
ijo Kote li lukin. o nimi "First line of input is the BCT program". ijo Tata li lukin. o nimi "Second line of input is the data-string". ijo Kote pi nanpa ala li ala la o pana. ijo Tata pi nanpa ala li ala la o pana. o nimi "The interpreter will print out any deleted bits as an output". ijo Tata pi nanpa ala li nimi "\n" la ijo Tata li kipisi e ijo Tata kepeken nanpa wan. o pali e pali sin. ijo Kote pi nanpa ala li nimi "\n" la ijo Kote li kipisi e ijo Kote kepeken nanpa wan. ijo Kon li ijo Kote pi nanpa ala. ijo Kote li kipisi e ijo Kote kepeken nanpa wan. ijo Kote li ijo Kote en ijo Kon. ijo Kote pi nanpa ala li nimi "\n" la ijo Kote li kipisi e ijo Kote kepeken nanpa wan. ijo Kon li nimi "0" la o pali e pali sin. o sitelen e ijo Tata pi nanpa ala. ijo Tata li kipisi e ijo Tata kepeken nanpa wan. ijo Tata pi nanpa ala li nimi "\n" la ijo Tata li kipisi e ijo Tata kepeken nanpa wan. pali sin li pini. ijo Kon li nimi "0" la ijo Tata pi nanpa ala li ala la o pana. ijo Kon li nimi "1" la o pali e pali sin. ijo Tata pi nanpa ala li nimi "1" la ijo Tata li ijo Tata en ijo Kote pi nanpa ala. ijo Kote li ijo Kote en ijo Kote pi nanpa ala. ijo Kote li kipisi e ijo Kote kepeken nanpa wan. pali sin li pini. o pali e pali ni. pali sin li pini.