toki pi ilo nanpa
|Influenced by||toki pona
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.
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:
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 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
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
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).
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 returns
ala. Takes precedence over
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 returns
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 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.
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.
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 expression
expr li lili la-
expris numeric and less than zero,
expr li suli la-
expris numeric and more than zero,
expr li expr la-
lonif expressions are equal,
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. Returns
alaif pali_exp is not of type
pana e expr- stop executing the current sentence and return
lukin e lipu_expr- returns a string - a single line read from
lipu_expr, or the standard input if
lipu_expris not of type
lipuand 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 to
lipu_expr, or standard output if
lipu_expris not of type
lipuand open for writing. Non-string values are converted to
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 a
ala. If nanpa_expr1 is not
nanpaor is smaller than 0 it's corrected to 0. If nanpa_expr2 is not
nanpaor 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 file
nimi_epxrand return it as a
lipuvalue. If it fails or
nimi_expris not of type
nimi "sitelen"the file is open for writing, otherwise it's open for reading.
pini e lipu_expr- closes the file
lipu_exprwhich makes sure any data written to it is saved on disc. Prevents any further reads or writes to or from the file.
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 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
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
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.
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.
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 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.
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 holds how much we already multiplied". ijo Ansa pi nanpa tu li nanpa ala. o nimi "Ansa 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 stores the outcome". ijo Ansa pi nanpa tu li ijo A. o nimi "Ansa 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.
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". 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 Tata pi nanpa ala li nimi "\n" la ijo Tata li kipisi e ijo Tata 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 sitelen e ijo Tata pi nanpa ala. ijo Kon li nimi "0" la ijo Tata li kipisi e ijo Tata kepeken nanpa wan. 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.