Statements occupy an entire line, and are concluded by a newline at their end:
statement
To combine multiple statements onto one line, join them using a semicolon (;
):
statement; statement
Comments can be placed at the end of a line using a hashtag symbol (#
), followed by the comment. Comments span the entire rest of the line, and can therefore not be inserted between tokens.
# Comment
statement # Comment
Multiple statements can be grouped into a block by surrounding them with curly brackets ({
, }
):
{
statement
statement
}
If a keyword requires being followed by statement(s), you can immediately place either a single statement or a block after it:
keyword statement
keyword {
statement
statement
}
Finally, whitespace, as in spaces or newlines, is optional (except to conclude statements):
keyword{statement;statement}
keyword
{
statement
statement
}
There are eight types of data.
For example -46
, 0
, 346
.
For verbose booleans, use True
and False
. They are identical to 1
and 0
.
For example -4.6
, 0.0
, 3.46E2
(= 346.0
).
For example "This is a string."
.
Strings can contain embedded expressions:
"2 * 2 = {2 * 2}" == "2 * 2 = 4"
The following characters must be escaped using a backslash (\
) to be used inside strings:
\
"
{
}
Also, the following sequences have special meaning:
\n
– Insert a new line.\r
– Insert a carriage return character.\t
– Insert a tab character.\e
– Inserts the ESC character.\a
– Inserts the BEL character.\oOO
– Insert the character with octal valueOO
.\xXX
– Insert the character with hexadecimal valueXX
.\
new line – Does not include the new line in the string.
For information on how to access or modify the characters making up a string, see 2.9.
For example:
(parameter1, parameter2) -> {
statement1
statement2
}
If your function only accepts one parameter, you may also omit the parenthesis around it
Functions are called by appending the arguments in parentheses ((
, )
) after their value:
(parameter1, parameter2) -> {
statement1
statement2
}(argument1, argument2)
For example print
.
These values are simply references to the underlying native functions, to allow passing them around.
To call a native function, use the same syntax as for user-defined functions:
print(argument)
Void
, used to communicate the absence of a value (see 6.2).
Lists can hold any number of any kind of data, including other lists. The items are separated using commas (,
):
[46, 4.6, "string", () -> return, print, [46]]
For information on how to access or modify the elements making up a list, see 2.9.
Much like lists, objects can hold any number of any kind of data, including objects, with the difference being that objects hold members, accessed using names instead of indices:
person = {
name: "Mia",
age: Void
}
print(person.name) # Prints 'Mia'.
To add new members to objects, just assign them a value:
person.surname = "Wallace"
When a function is stored in an object member, that function becomes a method of the object. During a method call, the enclosing object is available via the this
keyword.
person.set_age = (new_age) -> {
this.age = new_age
}
person.set_age(24)
print(person.age) # Prints '24'.
To access an element of a list or string, follow it by the offset of the item from the first item in square brackets ([
, ]
):
[1, 2, 3][0] # Retrieves '1'
"string"[1] # Retrieves '"t"'.
To retrieve multiple elements (called a slice) at once, provide a range:
[1, 2, 3, 4, 5][1..4] # Retrieves '[2, 3, 4]'. The range end is excluded from the slice.
You can also use
Void
as the range end to represent the end of the list or string.
You can also use negative indices to represent an offset from the end of the list or string:
"string"[1..-1] # Retrieves '"trin"'.
Negative indices can also be used when retrieving a single element.
Finally, you can omit either boundary. If the range start is omitted, it defaults to 0
. If the range end is omitted, it defaults to Void
.
"string"[3..] # Retrieves '"ing"'.
All of the above rules also apply when assigning to a list or string. As long as the right-hand value matches the pattern defined in the left-hand slice, the values will be modified.
a = [1, 2, 3, 4, 5]
a[2..4] = [23, 46] # 'a' is now '[1, 2, 23, 46, 5]'.
A conditional expression always evaluates to either 0
, being false, or 1
, being true.
Attributes required for each type to be considered true are:
- Integers: not being of value
0
. - Floating-point numbers: not being of value
0.0
. - Strings: not being empty.
- Lists: containing at least one element.
- Objects: having at least one member.
- Functions: always true.
- Native functions: always true.
- Void: never true.
Attributes required for each type to be considered false are the opposites of the ones required for it to be true.
The truthiness of a value can be inverted by prefixing the value with an exclamation mark (!
):
!0 # Evaluates to 'true'.
The following binary operators can be used between two values to compare them.
Types can be compared for equality using ==
. Each comparison evaluates to true if the type and the value are the same.
Exceptions are comparisons between integers and floating-point numbers with the same numerical value:
46.0==46 # Evaluates to 'true'.
The same types can be compared for inequality using !=
. Each comparison evaluates to true if the requirements for equality are not (exactly) met.
Integers, floating-point numbers, strings, and lists can be compared in terms of size using >
, >=
, <=
, and <
.
For a value A to be considered greater than a value B of the same type, the following requirements must be met:
- Integers and floating-point numbers: the numerical value of A must be greater than that of value B.
- Strings: the number of characters in A must be larger than the number of characters in B.
- Lists: the number of items in A must be larger than the number of items in B.
Conditions can be chained together.
Using &&
, the expression only evaluates to true if both conditions are true.
1 && 1 # 'true'
0 && 1 # 'false'
Using ||
, the expression evaluates to the left-hand side if the left condition is true; otherwise, it evaluates to the right-hand side.
1 || 0 # 'true'
0 || 0 # 'false'
Using ??
, the expression evaluates to the left-hand side if the left condition is not Void
; otherwise, it evaluates to the right-hand side.
1 ?? 2 # 1
print("Something") ?? 2 # 2
Sometimes we want to perform a comparison on all elements within an iterable. This is achieved using the any
and all
operators.
When placed in front of iterable values in comparisons, the comparison is performed once per element in the iterable. Using any
, the expression yields true if the comparison applies to any element in the iterable.
"foo" == any ["foo", "bar"]
Using all
, it yields true if the comparison applies to all elements in the iterable.
3 >= all [1, 2, 3]
Operators can be used on both sides to perform complex checks in a single expression:
# Check if any input is not an accepted value
inputs = [1, 2, 3]
accepted = [2, 3, 4]
any inputs != all accepted
All common arithmetic operations (addition, subtraction, multiplication, division, modulus, power) are supported. The operator for modulus is %
, the operator for power is **
. An additional operation, floor division, behaves like division but always rounds the result down to the next smallest integer. Its operator is //
.
For integers and floating-point numbers, the operations behave as expected. Some of them can, however, also be used for strings and lists: to combine two strings or lists into one, use the addition operator:
"foo" + "bar" == "foobar"
["A", "B"] + ["C"] == ["A", "B", "C"]
Using the multiplication operator between a string or list and an integer repeats the string or list the given number of times:
"piece" * 6 == "piecepiecepiecepiecepiecepiece"
3 * [46] == [46, 46, 46]
An additional operator, cover
, can be used to provide an alternative value for an expression that results in an error:
10/5 cover "Zero division" == 2
10/0 cover "Zero division" == "Zero division"
Variable names can consist of any alphanumeric characters plus underscores (_
). They are defined as follows:
variable_name = value
This is also how you define functions — as variables:
add = (left, right) -> { return left + right } add(40, 6) # Evaluates to '46'
All variables are mutable; to change their contents, simply assign them a new value.
Elements at a specific index in a list or string can be modified as follows:
list[index] = value
By default, variables defined within functions are limited to the context of the function, meaning they will be destroyed after the function concludes. The prevent this, or to change the value of a variable previously defined outside the function, add the global
keyword before the statement:
global variable_name = value
All of the arithmetic operations (see 4.) can be performed on variables in-place as follows:
number = 4
number **= 2 # 'number' now holds 16.
Under normal circumstances, statement(s) are interpreted sequentally, from left to right, from top to bottom:
first; second
third
Any execution context can be concluded early using the return
keyword, optionally followed by a return value. If the return value is omitted, Void
is returned (see 2.6). Return statements work inside functions, where they conclude the currently running function, or in the main script, where they conclude the entire execution:
() -> {
statement1
return some_value
statement2 # Not executed.
}
return # The return value can be omitted.
If there is no return
to conclude a function, it will simply return the last evaluated result.
A script can be aborted early using the exit
keyword, optionally followed by an integer-only exit code to be returned to the operating system. If the exit code is omitted, it defaults to 0.
return () -> {
return () -> {
exit 46 # Immediately ends the execution with exit code 46.
return 1 # Does not get returned.
}()
}()
Conditional execution is achieved using the if
keyword:
if conditional_expression {
# conditional_expression evaluated to 'true'.
}
Optionally, one can add separate branches using the elif
keyword.
if conditional_expression {
# conditional_expression evaluated to 'true'.
} elif other_conditional_expression {
# conditional_expression evaluated to 'false'.
# other_conditional_expression evaluated to 'true'.
}
Finally, alternative statement(s) can be included using the else
keyword.
if conditional_expression {
# The conditional expression evaluated to 'true'.
} else {
# The conditional expression evaluated to 'false'.
}
Statement(s) can be repeated.
Using the for
keyword, statement(s) can be repeated a given number of times:
for iterator_variable from starting_integer till concluding_integer {
statement
}
Here, iterator_variable
is the name for the variable that will hold the iteration inside the body. It can be accessed like any other variable. starting_integer
is the integer the iterator has at the beginning of the loop. concluding_integer
is the integer that, when reached, will conclude the loop; it is important to note here that once the concluding integer was reached, the body is not executed one last time. The operation applied to the iterator for every iteration depends on the starting and concluding integers: if the concluding integer is smaller than the starting integer, the iterator is decremented by 1
every loop — otherwise, it is incremented by 1
every loop.
Alternatively, the for
loop also accepts the in
keyword in place of from-till
. This simplifies the act of iterating over items in a list or characters in a string; instead of having to access the current element via the iterator variable, the current element is instead placed directly into the iterator variable:
for element in list_or_string {
statement
}
Using the while
keyword, statement(s) can be repeated until a conditional expression no longer evaluates to 'true':
i = 10
while i > 0 {
i = i-1
}
Both of these iterative control flows can be controlled using keywords.
To conclude a loop early, use break
:
i = 10
while 1 {
i = i-1
if i <= 0
break
}
To skip to the next iteration in a loop, use continue
:
odd_numbers = 0
for i from 0 till 11 {
if i%2
continue
odd_numbers = odd_numbers+1
}
The assert
statement is used to ensure assertions are met at runtime.
assert 2 > 1 # Passes.
assert 1 > 2 # Fails.
put(value)
– Printsvalue
to the standard output pipe:> une -s "put(\"Hello, World!\")" Hello, World!>
print(value)
– Same asput
, but automatically appends a newline to the output:> une -s "put(\"Hello, World!\")" Hello, World! >
int(value)
– Returnsvalue
as an integer:int("46") == 46
flt(value)
– Returnsvalue
as a floating-point number:flt(46) == 46.0
str(value)
– Returnsvalue
as a string:str(46) == "46"
len(value)
– Returns the number of characters or items invalue
:len("Une") == 3 len([1, 2, 3]) == 3
sleep(time)
– Halts execution fortime
milliseconds:[16:20:46] > une -s "sleep(10000); print(\"Done.\")" [16:20:56] Done.
ord(character)
– Returns the ordinal character code ofcharacter
:ord("A") == 65
chr(code)
– Returns the character represented by the ordinal character codecode
:chr(65) == "A"
write(path, text)
– Writes the texttext
to a file atpath
:test.txt:> une -s "write(\"test.txt\", \"return 40\")"
return 40
append(path, text)
– Same aswrite
, but does not overwrite existing content:test.txt:> une -s "append(\"test.txt\", \"+6\")"
return 40+6
read(path)
– Returns the text contents of a file atpath
:read("test.txt") == "return 40+6"
script(path)
– Calls a script atpath
into the host context:script("test.txt") == 46
eval(string)
– Same asscript()
, but accepts a string instead:eval("23*2") == 46
input(prompt)
– Printsprompt
and requests input from the user, returning the entered string:> une -s "print(\"You wrote '\" + input(\"Write something: \") + \"'\")" Write something: test You wrote 'test'
exist(path)
– Returns1
if a filepath
exists, otherwise0
:exist("test.txt") == 1
split(text, delimiters)
– Returns a list of slices created by separating the stringtext
at every delimiter contained in the listdelimiters
:split("1,2;3", [",", ";"]) == ["1", "2", "3"]
join(list, seperator)
– Joins the strings inlist
into a single string, seperated byseperator
:join(["1", "2", "3"], ";") == "1;2;3"
replace(search, replace, subject)
– Replace stringsearch
with stringreplace
in stringsubject
:replace("+", "*", "2+23") == "2*23"
sort(subject, comparator)
– Return a sorted copy of the listsubject
, using thecomparator
function to compare elements:sort([3, 1, 2], (a, b) -> return a-b) == [1, 2, 3]
setwd()
– Set the working directory.setwd("C:\Directory")
getwd()
– Get the current working directory.getwd() == "C:\Directory"
playwav()
– Play a WAV file. (Windows only)playwav("sound.wav")