User:HaleyHalcyon/Sandbox/Sonjalang

From Esolang
Jump to navigation Jump to search
Sonjalang
Paradigm(s) imperative
Designed by Haley Halcyon
Appeared in 2025
Type system static, a hybrid of strong (via mandatory type annotations everywhere) and weak (via automatically casting by changing the type annotation)
Memory system variable-based
Dimensions one-dimensional
Computational class Turing complete
Reference implementation Unimplemented
Influenced by Toki Pona, Python

Sonjalang is an esoteric programming language created by Haley Halcyon based on the vocabulary and syntax of the constructed language Toki Pona. It was named after Sonja Lang, its inventor.

Valid Sonjalang code should be intelligible as Toki Pona text, although with some idiosyncrasies and uncommon constructs, mainly related to arithmetic.

This article provides word-for-word and idiomatic translations of the Toki Pona statements into English for readers who are not familiar with Toki Pona.

Identifiers

The names of variables and functions must be a valid identifier. Valid identifiers must follow these rules, modified from Toki Pona proper noun formation rules:

  • The first letter must be a capital letter used in Latin-script Toki Pona or an underscore, i.e. one of AEIJKLMNOPTUW_.
  • The second letter onward must only consist of Toki Pona letters or underscores, i.e. aeijklmnoptuw_, with the following restrictions:
  1. Two vowels (aeiou) in a row are forbidden.
  2. A consonant must not be at the end of an identifier, before another consonant, or before an underscore, except for the following:
  3. n may be at the end of a word or before an underscore. Another consonant may follow n, except for m or n.
  4. Nowhere in the word must the sequences wu, wo, ji, or ti appear (case-insensitive).
  5. The underscore _ replaces the space in multiple-word names in actual Toki Pona. Only the first letter and letters directly after an underscore may be capital letters.

Attempting to use an invalid identifier will cause the computer to throw the Invalid Identifier Exception.

A variable or function cannot share the same identifier as another variable or function, because of "headnoun type casting".

Functions

Declaring a function

Functions (nasin pali, work-methods) can only be declared in the root level (outside all code blocks).

Declaring a function
code word for word meaning
nasin pali IDENTIFIER (kepeken TYPE IDENTIFIER (kepeken TYPE IDENTIFIER (...))) li ni: path/method do/work IDENTIFIER (use/using TYPE IDENTIFIER (use/using TYPE IDENTIFIER (...))) [predicate:] this: This is the work-method named IDENTIFIER, (using the TYPE IDENTIFIER (and the TYPE IDENTIFIER (and ...))).

Calling a function

Functions can be called using the phrase tawa nasin pali IDENTIFIER. Functions can call themselves recursively.

Calling a function
return value code word for word meaning
Discard the return value o tawa nasin pali IDENTIFIER (kepeken TYPE IDENTIFIER (kepeken TYPE IDENTIFIER (...))). [request/command] move/go path/method do/work IDENTIFIER (use/using TYPE IDENTIFIER (use/using TYPE IDENTIFIER (...))). Please follow the work-method named IDENTIFIER, (using the TYPE IDENTIFIER (and the TYPE IDENTIFIER (and ...))).
Assign the return value TYPE IDENTIFIER li tawa nasin pali IDENTIFIER (kepeken TYPE IDENTIFIER (kepeken TYPE IDENTIFIER (...))). TYPE IDENTIFIER [predicate:] move/go path/method do/work IDENTIFIER (use/using TYPE IDENTIFIER (use/using TYPE IDENTIFIER (...))). TYPE IDENTIFIER is according to the work-method named IDENTIFIER, (using the TYPE IDENTIFIER (and the TYPE IDENTIFIER (and ...))).

Exiting a function

Exiting a function
returns a value? code word for word meaning
No o pini e nasin pali ni. [request/command] end/finish [direct object:] path/method do/work thi. Please end this function.
Yes, variable value o pana e TYPE IDENTIFIER. [request/command] give/emit [direct object:] TYPE IDENTIFIER. Please give/emit the TYPE called IDENTIFIER.
Yes, inline literal or arithmetic o pana e STATEMENT. [request/command] give/emit [direct object:] STATEMENT. Please give/emit STATEMENT.

Syntax

Comments (ijo poka, meaning "context" or "nearby things") are enclosed in ( and ). Comments need not be in Toki Pona. Comments may span multiple lines, or be inside a line (in which case, an implicit space will be added before and after it, if it doesn’t already exist there).

Indents

As in Python, indentation levels indicate block scope. Statements ending in ni: start a code block. A dedented line exits the code block.

Every statement (toki, meaning "speech" or "communication") ends with a ., and . always ends a statement, unless it is part of a string or float literal.

A newline does not implicitly end a statement. Indentation only matters at the line in which the first token of the statement occurs. For example, the following are all valid and equivalent (spaces relevant for block scoping are replaced with ·):

Example
lon la,
 o pali e ni:
····o toki e ni:
········"Test."
····ni li pini pali.
lon la, o pali e ni:
··o toki e ni: "Test."
··ni li pini pali.
lon   la,
 o pali e  ni:
···o  toki
  e ni   :
··············"Test."
···ni(ike a)li
         pini
pali.

However, in the interest of simplicity (pona), the language’s designer recommends the following:

  1. Indent a block with 4 spaces.
  2. Use 1 extra space of indent on continuation lines.

If a statement that does not follow la: is more indented than the previous, or if a statement that follows la: is less indented that the previous, or a statement dedents to a level that does not match the root or a la: statememt, the Unexpected Indent exception gets thrown.

Expressions

Expressions are made up of constants, variables, and operators.

Constants
code word for word meaning
lon exist/true The boolean value true.
lon ala exist/true not/nothing The boolean value false.
telo nasa water/liquid odd/extraordinary/crazy The float value NaN. In Toki Pona, this coincidentally means "alcohol".
telo suli ale water/liquid big/important all/hundred The float value +Infinity.

Declaring variables

Variables must be declared before they are used.

Types
code word for word meaning
nanpa VALUE number/rank VALUE Integer, where VALUE is a valid number written as ASCII numerals, or as extended nasin nanpa pona. It can also be the result of an inline arithmetic expression.
telo VALUE water/liquid VALUE Float, where VALUE is a valid number written as ASCII numerals with . as the decimal point, or as extended nasin nanpa pona. It can also be the result of an inline arithmetic expression.
nimi VALUE name/word VALUE String, where the literal text is enclosed with ". A newline can be added with "\n", and a tab can be added with "\t".
"VALUE" "VALUE" Inline string literals may be declared and used without explicitly stating that it is a nimi.
anu VALUE or/choice VALUE Boolean. (The use of anu like this is a huge departure from actual Toki Pona grammar, so it is not recommended to directly declare booleans.)

Arrays currently exist in Sonjalang, but since Haley cannot think of a good way to declare them, they are currently only possible to create using the STRING kipisi STRING operator.

Statements for declaring variables and assigning them are as follows:

Variable declaration
code word for word meaning
TYPE IDENTIFIER sin li VALUE. TYPE IDENTIFIER new/young [predicate:] VALUE. Declare a new variable IDENTIFIER of type TYPE, and immediately assign the value VALUE.
TYPE IDENTIFIER li sin. TYPE IDENTIFIER [predicate:] new/young. Declare a new variable IDENTIFIER of type TYPE. If this variable is read before assigning a value, it throws an Unknown Identifier Exception.

Headnoun type casting

Every time you use a variable, you must specify its type by using its head noun. By changing the head noun, you can explicitly cast variables in the following way:

Type casting
From to anu to nanpa to telo to nimi
anu (N/A) 1 if lon, 0 if lon ala 1.0 if lon, +0.0 if lon ala "lon" or "lon ala"
nanpa lon if nonzero, lon ala if zero (N/A) By value (as float precision allows) As base 10 Arabic numerals
telo lon if not exactly +0 or -0, lon ala if zero Round towards zero (N/A) As base 10 Arabic numerals, with . as the decimal separator
nimi lon if not empty, lon ala if empty Try parsing as a base 10 integer; if it fails, try parsing as nasin nanpa pona (can error if neither worked) NaN if "nasa" and +Infinity if "suli ale". If neither, try parsing as a base 10 decimal; if it fails, try parsing as nasin nanpa pona (can error if none of them work) (N/A)

Casts to or from nasin pali (function) will always fail.

Failed type casts throw a Type Casting Error.

nasin nanpa pona

Integer and float literals (nanpa and telo) can also be defined using extended nasin nanpa pona. A valid nasin nanpa pona literal works as follows:

(((...) [value_00_to_99] ale) [value_00_to_99] ale) [value_00_to_99]

where ale is a reserved word meaning 100, and [value_00_to_99] is either ala (0), or a sequence of the literals mute (20), luka (5), tu (2), and wan (1) repeated as many times as needed in descending order of magnitude.

nasin nanpa pona table from 0 to 39
x10 +0 +1 +2 +3 +4 +5 +6 +7 +8 +9
0 ala wan tu tu wan tu tu luka luka wan luka tu luka tu wan luka tu tu
1 luka luka luka luka wan luka luka tu luka luka tu wan luka luka tu tu luka luka luka luka luka luka wan luka luka luka tu luka luka luka tu wan luka luka luka tu tu
2 mute mute wan mute tu mute tu wan mute tu tu mute luka mute luka wan mute luka tu mute luka tu wan mute luka tu tu
3 mute luka luka mute luka luka wan mute luka luka tu mute luka luka tu wan mute luka luka tu tu mute luka luka luka mute luka luka luka wan mute luka luka luka tu mute luka luka luka tu wan mute luka luka luka tu tu

Decimals cannot be declared in nasin nanpa pona without inline arithmetic. For example, this declares pi using its fractional approximation 355/113:

nanpa Pi li
    tu wan ale
    mute mute luka luka luka
kipisi
    wan ale
    luka luka tu wan.

Arithmetic

The following operators may be used for arithmetic. Note that this section contains the most differences from "real" Toki Pona.

Arithmetic
code word for word meaning
X en Y X [another subject:] Y If both are booleans, "and". If both are ints, both are floats, or one is an int and one is a float, "plus". (If only one is an int, it will be casted to a float.) If both are strings, "concatenate".
X anu Y X or Y "or": Returns Y if X is falsy. Otherwise, returns X.
X ala X not/nothing "not": Always returns a boolean.
X weka Y X remove/away Y "minus", with the following overloads:
1) If X is a string and Y is an int, remove the last Y characters of X, returning the empty string if there are no more characters to remove.
2) If X and Y are both strings, remove the first occurrence of Y as a substring in X. If Y is not in X, do nothing and return X.
X kulupu Y X group Y "multiplied by", with the following overload: If X is a string and Y is an int, repeat X Y times.
X kipisi Y X split/cut/slice Y "divided by", with the following overload:
If X and Y are both strings, return an array of strings using Y as the separator.
X sike Y X circle/round Y "modulo".
suli X big/important X Returns the length (bigness) of a string or array.
X li sama Y X [predicate:] same/like Y X == Y.
X li nasa X [predicate:] unusual/crazy X is NaN. This exists because NaN != NaN, even if they're the exact same NaN.
X li sama ala Y X [predicate:] same/like not/nothing Y X != Y.
X la Y li suli X in_the_context_of Y [predicate:] big/important X < Y.
X la Y li suli ala X in_the_context_of Y [predicate:] big/important not/nothing X >= Y.
X la Y li lili X in_the_context_of Y [predicate:] small/young X > Y.
X la Y li lili ala X in_the_context_of Y [predicate:] small/young not/nothing X <= Y.
kipisi X lon Y split/cut/slice X place/exist/true Y Index [X] of array Y, or the Xth character of string Y.

Only the empty string "" is the only falsy string.

An empty array is the only falsy array.

Control flow

If-else statements use the phrase CONDITION la, o pali e ni: (word for word: CONDITION in_the_context_of, [request/command] do/work [direct object:] this: i.e. "In the case of CONDITION [being true], please do this:") and ante la, o pali e ni: (word for word: other/different in_the_context_of, [...]: "Otherwise, please do this").

Here is a simple if-else statement:

CONDITION la, o pali e ni:
    BLOCK_IF.
ante la, o pali e ni:
    BLOCK_ELSE.

An if-elif-else statement is a little different, and uses the phrase CONDITION anu seme? lon la: (word for word: CONDITION or what? at/exist/true in_the_context_of: i.e. "Is it that CONDITION? If so:") and ante la: (word for word: other/different in_the_context_of: i.e. "otherwise:"). Note the difference in punctuation because of the rule that la: (outside string literals) always means the start of a code block.

CONDITION_0 anu seme? lon la:
    BLOCK_IF_0.
ante la, CONDITION_1 anu seme? lon la:
    BLOCK_IF_1.
ante la, CONDITION_2 anu seme? lon la:
    BLOCK_IF_2.
ante la: (note the colon instead of comma)
    BLOCK_ELSE.

A while loop uses the statement CONDITION la, o awen pali e ni: (word for word: CONDITION in_the_context_of, [request/command] stay/remain do/work [direct object] this/these: i.e. "If CONDITION, please keep doing this:").

CONDITION la, o awen pali e ni:
    BLOCK_WHILE.

A continue statement translates to o tawa awen. (word for word: [request/command] go/move stay/remain, i.e. "Please move in a way where you will stay.")

A break statement translates to o pini pali. (word for word: [request/command] end/finish do/work, i.e. "Please end this process.")

Sonjalang does not support for loops. Please use a while loop using a counter variable defined outside the scope.

(Fizzbuzz from 1 to 20.)
nanpa A li nanpa ala.
("While true" statement to demonstrate "break".)
lon la, o awen pali e ni:
    (Increment the counter.)
    nanpa A li nanpa A en nanpa wan.
    (Exit condition:)
    nanpa mute la, nanpa A li suli la, o pali e ni:
        o pini pali.
    nanpa A sike nanpa luka luka luka li sama nanpa ala anu seme? o pali e ni:
        o toki e ni: "FizzBuzz ".
        o tawa awen.
    ante la, nanpa A sike nanpa luka li sama nanpa ala anu seme? o pali e ni:
        o toki e ni: "Buzz ".
        o tawa awen.
    ante la, nanpa A sike nanpa tu wan li sama nanpa ala anu seme? o pali e ni:
        o toki e ni: "Fizz ".
        o tawa awen.
    ante la:
        o toki e ni: nanpa A. " ".

Other statements

Miscellaneous
English name for convenience code word for word meaning
Variable assignment jan kepeken li pana sona pi TYPE IDENTIFIER. person/human use [predicate:] emit/give knowledge [modifier grouper:] TYPE IDENTIFIER. The user teaches (what the) TYPE IDENTIFIER (is).
Print statement o toki e ni: EXPRESSION(S). [request/command] talk/state [direct object:] this: EXPRESSION(S). Please say this/these: EXPRESSION(S).
Assertion wile la, EXPRESSION. want/need in_the_context_of, EXPRESSION. I need (that) EXPRESSION (be true). (Throws the Failed Assertion error if it isn't.)
Integer as nasin nanpa pona string nanpa IDENTIFIRE lon nasin nanpa pona name/word IDENTIFIER exist/true/place number path/method good/simple The number IDENTIFIER according to the simple number-method
Character to Unicode code point nimi IDENTIFIER lon nasin nanpa Juniko name/word IDENTIFIER exist/true/place number path/method Unicode The string IDENTIFIER according to the number-method called Unicode
Unicode code point to character nanpa IDENTIFIER lon nasin sitelen Juniko number IDENTIFIER exist/true/place letter/picture/image Unicode The number IDENTIFIER according to the letter-method called Unicode
Early return from root level

ni li pini. || this [predicate:] end/finish. || This is the end.

Exceptions

Exceptions/Errors (pakala) can be thrown in Sonjalang, but they cannot be caught. An error message consists of three lines.

The first line is the common error message header:

Error message header
error message word for word meaning
pakala lon linja nanpa LINE_NUMBER a! mistake/break exist/true line/string number/rank LINE_NUMBER [interjection]! There's a mistake in the LINE_NUMBER(st/nd/rd/th) line!

The second line shows the specific exception type:

Exceptions
English name for convenience error message word for word meaning
Failed Assertion wile sina li lon ala. want/need you [predicate:] place/true not/nothing. Your requirement is false.
Invalid Identifier mi ken ala kalama uta e nimi ni. I/me possible/able not/nothing sound mouth [direct object:] name/word this. I can't pronounce this word.
Uninitialized Identifier mi sona ala e nimi IDENTIFIER. I/me know not/nothing [direct object:] name/word IDENTIFIER. I don't know the word IDENTIFIER.
Unterminated Comment ijo poka ni li pini ala. thing side/beside this [predicate:] end/finish not/nothing. This context does not end. (The line with the opening parenthesis should be quoted on the third line.)
Inconsistent/Unexpected Indent mi sona ala e kon pi suli kon ni. I/me know not [direct object:] air/soul [modifier grouper] big/important air/soul this/these. I don't understand the meaning of the size of this empty space.
(Other) Syntax Error mi sona ala e kon pi toki ni. I/me know not [direct object:] air/soul [modifier grouper] talk/statement this. I don't know what this means.
Type Error ijo ni la, mi ken ala pali e ni. thing this in_the_context_of, I/me possible/able not/nothing do/work [direct object:] this. I can't do that regarding this thing/these things.
Type Casting Error TYPE la, mi sona ala e VALUE. TYPE in_the_context_of, I/me know/understand not/nothing [direct object:] VALUE. I can't understand VALUE as TYPE.
Arithmetic Error pali nanpa ni li pakala. do/work number/order this [predicate:] mistake/break. This calculation is broken.
Too Much Recursion mi tawa nasin pali pi mute ike. I/me go/towards road/way do/work [modifier grouper] many/twenty bad/complex. I followed too many work-methods (functions).
Keyboard Interrupt sina wile e ni: mi pini pali. You want/need [direct object:] this: I/me finish/end do/work. You want me to stop operating.

The third line prints that specific line as is.

Code samples

Hello World

This demonstrates a print statement.

(word for word, it means "earth/land all [vocative], talk/statement [interjection]!")
o toki e ni: "ma ale o, toki a!".

Truth-machine

This demonstrates declaring a variable without a value, taking user input for the value, and a while loop.

(Declare an int to store input. If you use a string, you'll need to use a comparison.)
("Number Truth_tool is new.")
nanpa Ilo_lon li sin.
(Read user input. If user input cannot be casted into an int, it throws a Type Casting Error.)
("User teaches about the number Truth_tool.")
jan kepeken li pana sona pi nanpa Ilo_lon.
(While statement, if Ilo_lon is nonzero.)
("In the context of number Truth_tool [being true], continue doing this:")
nanpa Ilo_lon la, o awen pali e ni:
    (Print "1". This is an infinite loop; pressing Ctrl+C throws a Keyboard Interrupt Exception.)
    o toki e ni: "1".
(If not, fall through. Print "0". Then return.)
o toki e ni: "0".

Four-function calculator

This demonstrates the arithmetic functions. For more complex arithmetic not obeying PEMDAS, declare variables to use as intermediate values.

(Declare as floats, just in case.)
telo Wan li sin. telo Tu li sin.
(String to store the operator.)
nimi Pali li sin.
o toki e ni: "First number? ".
jan kepeken li pana sona pi telo Wan.
o toki e ni: "Operator (+-*/%)? ".
jan kepeken li pana sona pi nimi Pali.
o toki e ni: "Second number? ".
jan kepeken li pana sona pi telo Tu.
(If-else chain depending on the operator.)
"+" li sama nimi Pali anu seme? lon la:
    o toki e ni: telo Wan en telo Tu.
ante la,
"-" li sama nimi Pali anu seme? lon la:
    o toki e ni: telo Wan weka telo Tu.
ante la,
"*" li sama nimi Pali anu seme? lon la:
    o toki e ni: telo Wan kulupu telo Tu.
ante la,
"/" li sama nimi Pali anu seme? lon la:
    (A division by zero may cause an Arithmetic Error.)
    o toki e ni: telo Wan kipisi telo Tu.
ante la,
"%" li sama nimi Pali anu seme? lon la:
    (A division by zero may cause an Arithmetic Error.)
    o toki e ni: telo Wan sike telo Tu.
ante la:
    o toki e ni: "Invalid operator.".

Factorial calculator

This demonstrates how to declare functions, how to call them, and how to call them recursively.

(Patolija is a Tokiponization of the English word "factorial")
nasin pali Pana_e_Patolija kepeken nanpa A li ni:
    (Error case. If A is negative, then A factorial is undefined.)
    ("Assertion: compared to 0, A is not smaller.")
    wile la, nanpa ala la, nanpa A li lili ala.
    (Base case. If A is 0 or 1, then A factorial is 1.)
    ("Compared to A, is 1 larger? If that's true:")
    nanpa A la,
    nanpa wan li suli anu seme? lon la:
        (Return. "Emit the number 1.")
        o pana e nanpa wan.
    (Recursive case.)
    ("The new number E is according to the work-method Emit_the_Factorial using number A minus number 1.")
    nanpa E sin li tawa nasin pali Pana_e_Patolija kepeken nanpa A weka nanpa wan.
    (Return. "Emit the number A times the number E.")
    o pana e nanpa A kulupu nanpa E.

(Declare the int we want to factorialize. "alasa" means to hunt, to try, or to search for.)
nanpa Alasa li sin.
o toki e ni: "Number to calculate factorial of: ".
jan kepeken li pana sona pi nanpa Alasa.
(Calculate the factorial by passing this variable to that function above.)
nanpa Patolija sin li tawa nasin pali Pana_e_Patolija kepeken nanpa Alasa.
o toki e ni: nanpa Patolija.

Comparison with other Toki Pona-based esolangs

  • Both use nasin nanpa pona to define numbers (though in Sonjalang, it's optional).
  • Both use lon and lon ala instead of true and false.
  • Both use CONDITION la for conditionals, though the exact wording after that differs.
  • toki pi ilo nanpa has tables/arrays.
  • toki pi ilo nanpa can declare a global variable using the keyword suli.
  • toki pi ilo nanpa uses "paragraphs", stored in the type pali; Sonjalang uses "functions" that can only be called, not referenced (i.e. Sonjalang does not have a functional paradigm).
  • Both use o pana to return a value from a paragraph/function.
  • Sonjalang statements are generally shorter.
  • Sonjalang has while loops, while toki pi ilo nanpa works around its absence using recursion.
  • toki pi ilo nanpa has a way to declare arrays directly.
  • Sonjalang supports multiplication, division, and modulo natively.
  • toki pona li pona is based on Questa.
  • toki pona li pona redefines seemingly arbitrary statements to perform functions.
  • Assigning a variable uses jan IDENTIFIER li VALUE, meaning "(the person named) IDENTIFIER is VALUE".
  • Printing uses toki! mi jan IDENTIFIER, meaning "Hello! My name is IDENTIFIER".
  • toki pona li pona cannot accept user input.
  • toki pona li pona uses goto statements.