Language¶
Minilang has a simple syntax, similar to Lua, Pascal and Oberon-2. Keywords are in lower case, statements are delimited by semicolons ;
, these can be and are usually omitted at the end of a line.
As Minilang is designed to be embedded into larger applications, there is no implicit requirement to store Minilang code in source files with any specific extension (or indeed to store Minilang in files at all). However, .mini
is used for the sample and test scripts and there are highlighters created for GtkSourceview and Visual Studio Code that recognize this extension.
The following is an example of Minilang code showing an implementation of the Fibonacci numbers.
1fun fibonacci(N) do
2 if N <= 0 then
3 error("RangeError", "N must be postive")
4 elseif N <= 2 then
5 ret 1
6 else
7 var A := 1, B := 1
8 for I in 2 .. (N - 1) do
9 var C := A + B
10 A := B
11 B := C
12 end
13 ret B
14 end
15end
16
17for I in 1 .. 10 do
18 print('fibonacci({I}) = {fibonacci(I)}\n')
19end
20
21print('fibonacci({0}) = {fibonacci(0)}\n')
This produces the following output:
fibonacci(1) = 1
fibonacci(2) = 1
fibonacci(3) = 2
fibonacci(4) = 3
fibonacci(5) = 5
fibonacci(6) = 8
fibonacci(7) = 13
fibonacci(8) = 21
fibonacci(9) = 34
fibonacci(10) = 55
Error: N must be postive
test/test12.mini:3
test/test12.mini:20
Identifiers and Keywords¶
Identifiers start with a letter or underscore and can contain letters, digits and underscores. Minilang is case sensitive.
1A
2factorial
3_Var
4X1
5X2
The following identifiers are reserved as keywords.
1_ and case debug def do each else elseif end exit for fun
2if in is it let loop meth must next nil not old on or ref
3ret susp switch then to until var when while with
Whitespace and Line Breaks¶
Minilang code consists of declarations (variables and functions) and expressions to evaluate. The bodies of complex expressions such as if
, for
, etc, can contain multiple declarations and expressions, in any order. Both semicolons ;
and line breaks can be used to separate declarations and expressions, however if a line break occurs where a token is required then it will be ignored. Other whitespace (spaces and tabs) have no significance other than to separate tokens or within string literals.
For example the following are equivalent as the semicolons are replaced by line breaks:
1do print("Hello "); print("world"); end
2
3do
4 print("Hello ")
5 print("world")
6end
The following are also equivalent as the line break occurs after an infix operator where at least one more token is required to complete the expression:
1let X := "Hello " + "world"
2
3let X := "Hello " +
4 "world"
However the following code is not equivalent to the code above as the line break occurs before the infix operator and hence no token is required to complete the expression:
1let X := "Hello "
2 + "world"
Instead the above code is equivalent to following where semicolons have been added to show the separate declaration and expression (with a prefix operation):
1let X := "Hello ";
2
3+ "world";
Blocks¶
A block in is a group of expressions and declarations. A block returns the result of the last expression in the block. Every block creates a new identifier scope; identifiers declared in a block are not visible outside that block (although they are visible within nested blocks). Some constructs such as the bodies of if
-expressions, for
-expressions, etc, are always blocks. A do
-expression wraps a block into a single expression.
When any code is loaded in Minilang, it is implicitly treated as a block.
1var X := do
2 let Y := 7
3 print("Y = ", Y, "\n")
4 Y - 5
5end
6
7if X = 2 then
8 let Y := 10
9 let Z := 11
10 print("X = ", X, "\n")
11 print("Y = ", Y, "\n")
12 print("Z = ", Z, "\n")
13end
Y = 7
X = 2
Y = 10
Z = 11
The code above has three blocks;
the body of
do
-expression,the
then
-clause of theif
-expression,the top-level block containing the entire code.
The identifier X
is declared in the top-level block and so is visible throughout the code. The identifier Y
is declared twice in two separate blocks, each block sees its local definition. Finally, the identifier Z
is only declared in the then
-block and is only visible there.
Declarations¶
All identifiers in Minilang (other than those provided by the compiler / embedding) must be explicitly declared. Declarations are only visible within their containing block and can be referenced before their actual declaration. This allows (among other things) mutually recursive functions.
There are 3 types of declaration:
var Name
bindsName
to a new variable with an initial value ofnil
. Variables can be reassigned usingName := Expression
. A variable declaration can optionally include an initial expression to evaluate and assign to the variablevar Name := Expression
, this is equivalent tovar Name; Name := Expression
.let Name := Expression
bindsName
to the result of evaluatingExpression
.Name
cannot be reassigned later in the block, hence the intial expression is required.def Name := Expression
bindsName
to the result of evaluatingExpression
. Unlike alet
-declaration,Expression
is evaluated once only when the code is first loaded. Consequently,Expression
can only contain references to identifiers that are visible at load time (e.g. global identifiers or otherdef
-declarations).
Declarations are visible in nested blocks (including nested functions), unless they are shadowed by another declaration.
1print('Y = {Y}\n') :> Y is nil here
2
3var Y := 1 + 2
4
5print('Y = {Y}\n') :> Y is 3 here
6
7var X
8
9do
10 X := 1 :> Sets X in surrounding scope
11end
12
13print('X = {X}\n')
14
15do
16 var X :> Shadows declaration of X
17 X := 2 :> Assigns to X in the previous line
18 print('X = {X}\n')
19end
20
21print('X = {X}\n')
Y =
Y = 3
X = 1
X = 2
X = 1
Function Declarations¶
Functions are first class values in Minilang, they can be assigned to variables or used to initialize identifiers. For convenience, instead of writing let Name := fun(Args...) Body
, we can write fun Name(Args...) Body
. For example:
1fun fact(N) do
2 if N < 2 then
3 return 1
4 else
5 return N * fact(N - 1)
6 end
7end
Note that this shorthand is only for let
-declarations, if another type of declaration is required (var
or def
) then the full declaration must be written.
Compound Declarations¶
Minilang provides no language support for modules, classes and probably some other useful features. Instead, Minilang allows for these features to be implemented as functions provided by the runtime, with evaluation at load time to remove any additional overhead from function calls. Minilang provides some syntax sugar constructs to simplify writing these types of declaration.
Imports, Classes, etc.¶
A declaration of the form Expression: Name(Args...)
is equivalent to def Name := Expression(Args...)
. This type of declaration is useful for declaring imported modules, classes, etc. For example:
1import: utils("lib/utils.mini")
2
3class: point(:X, :Y)
Exports, etc.¶
A declaration of the form Expression: Declaration
is equivalent to Declaration; Expression("Name", Name)
where Name is the identifier in the Declaration. Any type of declaration (var
, let
, def
, fun
or another compound declaration) is allowed. This form is useful for declaring exports. For example:
1export: fun add(X, Y) X + Y
2
3export: var Z
Compound declarations can be combined. For example, the following code creates and exports a class.
1export: class: point(:X, :Y)
Destructuring Declarations¶
Multiple identifiers can be declared and initialized with contents of a single aggregrate value (such as a tuple, list, map, module, etc). This avoids the need to declare a temporary identifier to hold the result. There are two forms of destructing declaration. Note that both forms can be used with var
, let
or def
, for brevity only the let
forms are shown below.
let (Name₁, Name₂, ...) := Expression
. Effectively equivalent to the following:1let Temp := Expression 2let Name₁ := Temp[1] 3let Name₂ := Temp[2]
let (Name₁, Name₂, ...) in Expression
. Effectively equivalent to the following:1let Temp := Expression 2let Name₁ := Temp["Name₁"] 3let Name₂ := Temp["Name₂"]
Expressions¶
Other than declarations, everything else in Minilang is an expression (something that can be evaluated).
Literals¶
The simplest expressions are single values.
- Nil
nil
.- Integers
1
,-257
. Note that the leading-
is parsed as part of a negative number, so that2-1
(with no spaces) will be parsed as2 -1
(and be invalid syntax) and not2 - 1
.- Reals
1.2
,.13
,-1.3e5
.- Booleans
true
,false
.- Strings
"Hello world!n"
,'X = {X}'
. Strings can be written using double quotes or single quotes. Strings written with single quotes can have embedded expressions (between{
and}
) and may span multiple lines (the line breaks are embedded in the string).- Regular Expressions
r".*.c"
(case sensitive),ri".*.c"
(case insenstive). Minilang uses TRE as its regular expression implementation, the precise syntax supported can be found here https://laurikari.net/tre/documentation/regex-syntax/.- Lists
[1, 2, 3]
,["a", 1.23, [nil]]
. The values in a list can be of any type including other lists and maps.- Maps
{"a" is 1, 10 is "string"}
. The keys of a map have to be immutable and comparable (e.g. numbers, strings, tuples, etc). The values can be of any type.- Tuples
(1, 2, 3)
,("a", 1.23, [nil])
. Like lists, tuples can contain values of any type. Tuple differ from lists by being immutable; once constructed the elements of a tuple cannot be modified. This allows them to be used as keys in maps. They can also be used for destructing assignments,- Methods
:length
,:X
,<>
,+
,:"[]"
. Methods consisting only of the characters!
,@
,#
,$
,%
,^
,&
,*
,-
,+
,=
,|
,\\
,~
,`
,/
,?
,<
,>
or.
can be written directly without surrounding:"
and"
.- Functions
fun(A, B) A + B
. If the last argument to a function or method call is an anonymous function then the following shorthand can be used:f(1, 2, fun(A, B) A + B)
can be written asf(1, 2; A, B) A + B
.- Dates and Times
T"2022-02-27"
,T"1970-01-01T12:34:56"
,T"1970-01-01T12:34:56+06"
. The optional time component can be separated by eitherT
or a space\ ``. Timezones can be specified using ``+NN
or-NN
, and UTC can be specified usingZ
, if no timezone is specified then the time is interpreted in the local timezone.- Imaginary Numbers
2i
,-0.5i
. If Minilang is built with support for complex number, the suffixi
can be used to denote \(\sqrt{-1}\). The identifieri
is also defined as1i
but is not treated as a keyword (so code that usesi
as an identifier will not break if run by a version of Minilang built with support for complex numbers).- UUIDs
U"1c0fec87-31bd-40b8-bc04-527f4b171412"
. If Minilang is built with support for UUIDs, UUID literals can be written directly in code.
Conditional Expressions¶
The expression A and B
returns nil
if the value of A
is nil
, otherwise it returns the value of B
.
The expression A or B
returns A
if the value of A
is not nil
, otherwise it returns the value of B
.
Note
Both and
-expressions and or
-expressions only evaluate their second expression if required.
The expression not A
returns nil
if the value of A
is not nil
, otherwise it returns some
(a value whose only notable property is being different to nil
).
If Expressions¶
The if
-expression, if ... then ... else ... end
evaluates each condition until one has a value other than nil
and returns the value of the selected branch. For example:
1var X := 1
2print(if X % 2 = 0 then "even" else "odd" end, "\n")
will print odd
.
Multiple conditions can be included using elseif
.
1for I in 1 .. 100 do
2 if I % 3 = 0 and I % 5 = 0 then
3 print("fizzbuzz\n")
4 elseif I % 3 = 0 then
5 print("fizz\n")
6 elseif I % 5 = 0 then
7 print("buzz\n")
8 else
9 print(I, "\n")
10 end
11end
The else
-clause is optional, if omitted and every condition evaluates to nil
then the if
-expression returns nil
.
Switch Expressions¶
There are two types of switch
-expression in Minilang. The basic switch
-expression chooses a branch based on an integer value, with cases corresponding to 0, 1, 2, ...
, etc.
1switch Expression
2case
3 Block
4case
5 Block
6else
7 Block
8end
When evaluated, Expression
must evaluate to a non-negative integer, n
. The n + 1
-th case
block is then evaluated if present, otherwise the else
block option is evaluated. If no else block is present, then the value nil
is used.
The general switch
-expression selects a branch corresponding to a value based on a specific switch provider.
1switch Expression: Provider
2case Expressions do
3 Block
4case Expressions do
5 Block
6else
7 Block
8end
Minilang includes switch providers for several basic types including numbers, strings and types. More details can be found in Switch Expressions.
Loop Expressions¶
A loop
-expression, loop ... end
evaluates its code repeatedly until an exit
-expression is evaluated: exit Value
exits a loop and returns the given value as the value of the loop. The value can be omitted, in which case the loop evaluates to nil
.
1var I := 1
2print('Found fizzbuzz at I = {loop
3 if I % 3 = 0 and I % 5 = 0 then
4 exit I
5 end
6 I := I + 1
7end}\n')
A next
-expression jumps to the start of the next iteration of the loop.
If an expression is passed to exit
, it is evaluated outside the loop. This allows control of nested loops, for example: exit exit Value
or exit next
.
A while
-expression, while Expression
, is equivalent to if not Expression then exit end
. Similarly, an until
-expression, until Expression
, is equivalent to if Expression then exit end
. An exit value can be specified using while Expression, Value
or until Expression, Value
.
For Expressions¶
The for expression, for Value in Collection do ... end
is used to iterate through a collection of values.
1for X in [1, 2, 3, 4, 5] do
2 print('X = {X}\n')
3end
If the collection has a key associated with each value, then a second variable can be added, for Key, Value in Collection do ... end
. When iterating through a list, the index of each value is used as the key.
1for Key, Value in {"a" is 1, "b" is 2, "c" is 3} do
2 print('{Key} -> {Value}\n')
3end
For loops can also use destructing assignments to simplify iterating over collections of tuples, lists, etc.
1for Key, (First, Second) in {"a" is (1, 10), "b" is (2, 20), "c" is (3, 30)} do
2 print('{Key} -> {First}, {Second}\n')
3end
A for loop is also an expression (like most things in Minilang), and can return a value using exit
, while
or until
. Unlike a basic loop expression, a for loop can also end when it runs out of values. In this case, the value of the for loop is nil
. An optional else
clause can be added to the for loop to give a different value in this case.
1var L := [1, 2, 3, 4, 5]
2
3print('Index of 3 is {for I, X in L do until X = 3, I end}\n')
4print('Index of 6 is {for I, X in L do until X = 6, I end}\n')
5print('Index of 6 is {for I, X in L do until X = 6, I else "not found" end}\n')
Index of 3 is 3
Index of 6 is
Index of 6 is not found
Sequences¶
For loops are not restricted to using lists and maps. Any value can be used in a for loop if it is sequence, i.e. can generate a sequence of values (or key / value pairs for the two variable version).
In order to loop over a range of numbers, Minilang has a range type, created using the ..
operator.
1for X in 1 .. 5 do
2 print('X = {X}\n')
3end
X = 1
X = 2
X = 3
X = 4
X = 5
The default step size is 1
but can be changed using the :by
method.
1for X in 1 .. 10 by 2 do
2 print('X = {X}\n')
3end
X = 1
X = 3
X = 5
X = 7
X = 9
Minilang provides many other types of sequences as well as functions that construct new sequences from others. More details can be found in Sequences.
Functions¶
Functions in Minilang are first class values. That means they can be passed to other functions and stored in variables, lists, maps, etc. Functions have access to variables in their surrounding scope when they were created.
The general syntax of a function is
fun(Name₁, Name₂, ...) Expression
. Calling a function is achieved by the traditional syntaxFunction(Expression, Expression, ...)
.
1let add := fun(A, B) A + B
2let sub := fun(A, B) A - B
3
4print('add(2, 3) = {add(2, 3)}\n')
add(2, 3) = 5
Note that Function
can be a variable containing a function, or any
expression which returns a function.
1var X := (if nil then add else sub end)(10, 3) :> 7
2
3let f := fun(A) fun(B) A + B
4
5var Y := f(2)(3) :> 5
As a shorthand, the code var Name := fun(Name₁, Name₂, ...) Expression
can be written
as fun Name(Name₁, Name₂, ...) Expression
. Internally, the two forms are identical.
1fun add(A, B) A + B
Although a function contains a single expression, this expression can be a block expression, do ... end
. A block can contain any number of declarations and expressions, which are evaluated in sequence. The last value evaluated is returned as the value of the block. A return expression, ret Expression
, returns the value of Expression
from the enclosing function. If Expression
is omitted, then nil
is returned.
1fun fact(N) do
2 var F := 1
3 for I in 1 .. N do
4 F := F * I
5 end
6 ret F
7end
When calling a function which expects another function as its last parameter, the following shorthand can be used:
1f(1, 2, fun(A, B) do
2 ret A + B
3end)
can be written as
1f(1, 2; A, B) do
2 ret A + B
3end
Generators¶
Minilang functions can be used as generators using suspend expressions, susp Key, Value
. If Key
is omitted, nil
is used as the key. The function must return nil
when it has no more values to produce.
1fun squares(N) do
2 for I in 1 .. N do
3 susp I, I * I
4 end
5 ret nil
6end
7
8for I, S in squares(10) do
9 print('I = {I}, I² = {S}\n')
10end
I = 1, I² = 1
I = 2, I² = 4
I = 3, I² = 9
I = 4, I² = 16
I = 5, I² = 25
I = 6, I² = 36
I = 7, I² = 49
I = 8, I² = 64
I = 9, I² = 81
I = 10, I² = 100
Types¶
Every value in Minilang has an associated type. The type of a value can be obtained by calling type(Value)
.
1print(type(10), "\n")
2print(type("Hello"), "\n")
3print(type(integer), "\n")
4print(type(type), "\n")
<<integer>>
<<string>>
<<type>>
<<type>>
Types are displayed as their names enclosed between << and >>. Note that type
is itself a type (whose type is itself, type
). Most types can be called as functions which return instances of that type based on the arguments passed.
For example:
boolean(X)
,integer(X)
,real(X)
,number(X)
,string(X)
,regex(X)
Convert
X
to an integer, real, number (integer or real), string or regular expression respectively.list(X)
,map(X)
These expect
X
to be sequence and the values (and keys) produced byX
into a list or map respectively.tuple(X₁, X₂, ...)
Constructs a new tuple with values
X₁, X₂, ...
.method(X)
,method()
Returns the (unique) method with name
X
. If no name is passed then a completely new anonymous method is returned.type(X)
Returns the type of
X
.stringbuffer()
Returns a new stringbuffer.
Generics¶
Minilang can optionally be built with support for generic types such as list[integer]
, map[string, tuple[string, number]]
, etc. More details can be found in Types.
Classes, Enums and Flags¶
Minilang can optionally be built with support for user-defined types, using the class
, enum
or flags
types. More details can be found in Classes.
Methods¶
Methods are first class objects in Minilang. They can be created using a colon :
followed by one or more alphanumeric characters, or any combination of characters surrounded by quotes.
Methods consisting of only the characters !
, @
, #
, $
, %
, ^
, &
, *
, -
, +
, =
, |
, \
, ~
, `
, /
, ?
, <
, >
or .
can be written directly, without any leading :
or quotes.
Methods behave as atoms, that is two methods with the same characters internally point to the same object, and are thus identically equal.
1:put
2:write
3:"write" :> same as previous method
4:"do+struff"
5+
6<>
Methods provide type-dependant function calls. Each method is effectively a mapping from lists of types to functions. When called with arguments, a method looks through its entries for the best match based on the types of all of the arguments and calls the corresponding function. More information on how methods work can be found in Methods.
1var L := []
2:put(L, 1, 2, 3)
3print('L = {L}\n')
L = 1 2 3
For convenience (i.e. similarity to other OOP languages), method calls can also be written with their first argument before the method. Thus the code above is equivalent to the following:
1var L := []
2L:put(1, 2, 3)
3print('L = {L}\n')
Methods with only symbol characters or that are valid identifiers can be invoked using infix notation. The following are equivalent:
1+(A, B)
2A + B
3
4+(A, *(B, C))
5A + (B * C)
6
7list(1 .. 10 limit 5)
8list(:limit(..(1, 10), 5))
Important
Minilang allows any combination of symbol characters (listed above) as well as any identifier to be used as an infix operator. As a result, there is no operator precedence in Minilang. Hence, the parentheses in the last example are required; the expression A + B * C
will be evaluated as (A + B) * C
.
Macros¶
Minilang has optional support for macros, which allow code to be generated or modified during compilation.
When the compiler encounters any function call in code Func(Arg₁, Arg₂, ...)
(here Func
and Argᵢ
are expressions), it checks if Func
can be evaluated to a constant. If Func
can be evaluated to a constant, and that constant is a macro then it applies the macro to Arg₁, Arg₂, ...
as expression values. The macro must return another expression value which the compiler then compiles in place of the original function call.
Expression values can be constructed using the syntax :{Expr, Name₁ is Expr₁, Name₂ is Expr₂, ...}
. The optional Nameᵢ is Exprᵢ
pairs define named expressions which can be referenced in Expr
as :$Nameᵢ
.
Macros can be created using the macro
constructor, the example below uses the compound declaration form described above. Note that macro
expects a function, hence the ;
in the definition of test
.
1macro: test(; Expr) :{do
2 let X := 10
3 let Y := "Hello world"
4 :$Expr
5end, Expr is Expr}
6
7test(print('X = {X}, Y = {Y}\n'))
8
9:> expands to
10
11do
12 let X := 10
13 let Y := "Hello world"
14 print('X = {X}, Y = {Y}\n')
15end
See Macros for more information.
Values¶
Nil¶
The special built in value nil
denotes the absence of any other value. Variables have the value nil
before they are assigned any other value. Likewise, function parameters default to nil
if a function is called with fewer arguments than parameters.
Important
Although Minilang has boolean values, conditional and looping statements treat only nil
as false and any other value as true.
1:> Nil
2nil
3
4if nil then
5 print("This will not be seen!")
6end
7
8if 0 then
9 print("This will be seen!")
10end
Comparison operators such as =
, >=
, etc, return the second argument if the comparison is true, and nil
if it isn't. Comparisons also return nil
if either argument is nil
, allowing comparisons to be chained.
11 < 2 :> returns 2
21 > 2 :> returns nil
3
41 < 2 < 3 :> returns 3
51 < 0 < 3 :> return nil
Numbers¶
Numbers in Minilang are either integers (whole numbers) or reals (decimals / floating point numbers).
Integers can be written in standard decimal notation. Reals can be written in standard decimal notation, with either e
or E
to denote an exponent in scientific notation. If a number contains either a decimal point .
or an exponent, then it will be read as a real number, otherwise it will be read as an integer.
They support the standard arithmetic operations, comparison operations and conversion to or from strings.
1:> Integers
210
3127
4-1
5
6:>Reals
71.234
810.
90.78e-12
1:> Arithmetic
21 + 1 :> 2
32 - 1.5 :> 0.5
42 * 3 :> 6
54 / 2 :> 2
63 / 2 :> 1.5
75 div 2 :> 2
85 mod 2 :> 1
9
10:> Comparison
111 < 2 :> 2
121 <= 2 :> 2
131 = 1.0 :> 1.0
141 > 1 :> nil
151 >= 1 :> 1
161 != 1 :> nil
17
18:> Conversion
19integer("1") :> 1
20real("2.5") :> 2.5
21number("1") :> integer 1
22number("1.1") :> real 1.1
See also number.
Ranges¶
Minilang provides integer and real ranges. The Min .. Max
operator returns an inclusive range from Min
to Max
.
1:> Construction
21 .. 10
310 .. 100 by 10
41 .. 10 by 0.5
51 .. 100 in 9
See also range.
Strings¶
Strings can be written in two ways:
Regular strings are written between double quotes "
, and contain regular characters. Special characters such as line breaks, tabs or ANSI escape sequences can be written using an escape sequence \n
, \t
, etc.
Complex strings are written between single quotes '
and can contain the same characters and escape sequences as regular strings. In addition, they can contain embedded expressions between braces {
and }
. At runtime, the expressions in braces are evaluated and converted to strings. To include a left brace {
in a complex string, escape it \{
.
1:> Regular strings
2"Hello world!"
3"This has a new line\n", "\t"
4
5:> Complex strings
6'The value of x is \'{x}\''
7'L:length = {L:length}\n'
8
9:> Conversion
10string(1) :> "1"
11string([1, 2, 3]) :> "[1, 2, 3]"
12string([1, 2, 3], ":") :> "1:2:3"
String[I]
Returns the I-th character of String as a string of length 1.
String[I, J]
Returns the sub-string of String starting with the I-th character up to but excluding the J-th character. Negative indices are taken from the end of String. If either I or J it outside the range of String, or I > J then
nil
is returned.
See also string.
Regular Expressions¶
Regular expressions can be written as r"expression"
, where expression is a POSIX compatible regular expression.
1:> Regular expressions
2r"[0-9]+/[0-9]+/[0-9]+"
3
4:> Conversion
5regex("[A-Za-z_]*") :> r"[A-Za-z_]*"
See also string.
Lists¶
Lists are extendable ordered collections of values, and are created using square brackets, [
and ]
. A list can contain any value, including other lists, maps, etc.
1:> Construction
2let L1 := [1, 2, 3, 4]
3let L2 := list(1 .. 10)
4
5:> Indexing
6L1[1]
7L1[2] := 100
8L1[-1]
9
10:> Slicing
11L1[1, 3]
12L1[2, 4] := [11, 12]
13
14:> Methods
15L1:put(5, 6)
16L1:pull
17L1:push(0, -1)
18L1:pop
19L1:length
20L1 + L2
21
22:> Iteration
23for V in L1 do
24 print('V = {V}\n')
25end
26for I, V in L1 do
27 print('I = {I}, V = {V}\n')
28end
29for V in L1 do
30 V := old + 1
31end
See also list.
Maps¶
Maps are extendable collections of key-value pairs, which can be indexed by its keys. Maps are created using braces {
and }
. Keys can be of any immutable type supporting equality testings (typically numbers and strings), and different types of keys can be mixed in the same map. Each key can only be associated with one value, although values can be any type, including lists, other maps, etc.
:> Construction
let M1 := {"A" is 1, "B" is 2}
let M2 := map("banana")
:> Indexing
M1["A"]
M1["C"]
M1["C"] := 3
print('D -> {M1["D", fun() 4]}\n')
:> Methods
M1:insert("E", 5)
M1:delete("C")
M1:size
See also map.
Comments¶
Line comments start with
:>
and run until the end of the line.Block comments start with
:<
and end with>:
and can be nested.