Control structures - Palamecia/mint GitHub Wiki
Control structures allow you to execute different parts of a script depending on certain conditions. Mint uses four kinds of control structures:
- Conditional control structures: These allow you to execute parts of a script based on specific conditions.
- Loop control structures: These allow you to repeat parts of a script based on certain conditions.
- Print control structures: These allow you to execute parts of a script and send the results to an object.
- Exception handling control structures: These allow you to execute parts of a script to handle errors.
Caution
Inserting a new line before the {
that starts the statement block is a syntax error. The block must follow immediately. This prevents some invalid states in the interactive mode.
The if statement allows you to execute a part of the script only when a condition becomes true.
It is introduced by the if
keyword followed by an expression. The statement opens a block of script that is executed if the expression evaluates to true
.
Note
The expression is considered inside the opened block by the let
keyword.
The if statement can use two kinds of expressions:
- A simple expression: In this case, the result of the expression is cast to a boolean.
- An "in" expression: In this case, the left part of the expression is passed to the
in
method of the object on the right side, and the result is cast to a boolean.
Important
If the object on the right side of the "in" expression does not overload the in
method, the object is cast to an iterator to use the iterator's method implementation. The method can also return an iterator. In this case, the iterator's in
method implementation of the returned object is also used.
Example:
if value > 10 {
// Script to be executed when value > 10
}
if 'e' in str {
// Script to be executed when str contains 'e'
}
if 5 not in values {
// Script to be executed when values does not contain 5
}
An if statement can be immediately followed by an elif statement, allowing you to execute a part of the script only when the condition is false and another condition becomes true. An elif statement can also be followed by other elif statements.
It is introduced by the elif
keyword followed by an expression. The statement opens a block of script that is executed if the expression evaluates to true
.
Example:
if value > 10 {
// Script to be executed when value > 10
} elif threshold < 10 {
// Script to be executed when value <= 10 and threshold < 10
} elif value < 0 {
// Script to be executed when value <= 10, threshold >= 10 and value < 0
}
An if or elif statement can also be followed by an else statement, allowing you to execute a part of the script only when all the previous conditions are false.
It is introduced by the else
keyword. The statement opens a block of script that is executed if all the previous expressions evaluates to false
.
Example:
if value > 10 {
// Script to be executed when value > 10
} elif threshold < 10 {
// Script to be executed when value <= 10 and threshold < 10
} else {
// Script to be executed when value <= 10 and threshold >= 10
}
Caution
Inserting a new line between the }
and the elif
or else
keyword is a syntax error. The next statement must follow immediately. This prevents some invalid states in the interactive mode.
The switch statement allows you to execute parts of a script from different points depending on the result of an expression.
It is introduced by the switch
keyword followed by an expression. The statement opens a block containing the script and the descriptions of the different entry points.
Note
The expression is considered inside the opened block by the let
keyword.
An entry point is introduced by the case
keyword followed by a value and finished by the :
operator.
The result of the expression is compared to the value using the ==
operator. If the result of the comparison cast to a boolean is true
, the execution of the part of the script starts from this point.
Example:
switch value {
case 0:
// Script to be executed when value == 0
case 1:
// Script to be executed when value == 0 or value == 1
case 2:
// Script to be executed when value == 0 or value == 1 or value == 2
}
The case
keyword can also be followed by the is
operator. In this case, the result of the expression is compared to the value using the is
operator.
Example:
switch value {
case is none:
// Script to be executed when value is none
case is null:
// Script to be executed when value is none or value is null
case 0:
// Script to be executed when value is none or value is null or value == 0
}
The case
keyword may be followed by the in
operator. In this case, the result of the expression is used to search the value using the in
operator.
An expression following an in
operator can also use special syntaxes like a range operator or a list of values.
Example:
switch value {
case in 0...5:
// Script to be executed when value is in the range 0...5
case in 7..9:
// Script to be executed when value is in the range 7..9
case in 10, 12, 24, 32:
// Script to be executed when value is in the list
case in 'aeiou':
// Script to be executed when value is in the string
}
A special entry point can also be introduced by the default
keyword. This entry point is used when all the previous entry points were passed without entering a part of the script.
Important
The default entry point must be the last entry point of the list because no more entry points will be evaluated after it.
Example:
switch value {
case 0:
// Script to be executed when value == 0
case 1:
// Script to be executed when value == 0 or value == 1
default:
// Script to be executed in any case
}
The execution of the part of the script can be stopped with the break
keyword. In this case, the execution will continue with the first instruction after the block of the switch statement.
Example:
switch value {
case 0:
// Script to be executed when value == 0
break
case 1:
// Script to be executed when value == 1
break
case 2:
// Script to be executed when value == 2
}
Loop control structures allow you to create a block of script that can be re-executed several times depending on some conditions. Each block of a loop control structure provides two features:
The execution of the part of the script can be stopped with the break
keyword. In this case, the execution will continue with the first instruction after the block of the statement.
Example:
for i in values {
if i is none {
break
}
// Script to be executed with the new value of i while i is not none
}
The execution of the part of the script can go to the next loop statement with the continue
keyword. In this case, the execution will continue as if the end of the block was reached.
Example:
while value != expected {
if value < 0 {
// Script to be executed to fix the value of value
continue
}
// Script to be executed while value != expected
}
The while statement allows you to re-execute a part of the script while a condition remains true.
It is introduced by the while
keyword followed by an expression. The statement opens a block of script that is executed while the expression evaluates to true
.
Note
The expression is considered inside the opened block by the let
keyword.
The while statement uses the same kinds of expressions as the if statement.
Example:
while value > 10 {
// Script to be executed while value > 10
}
while 'e' in str {
// Script to be executed while str contains 'e'
}
while 5 not in values {
// Script to be executed while values does not contain 5
}
The for statement allows you to re-execute a part of the script for each element of an object.
It is introduced by the for
keyword followed by a symbol name, the in
operator, and an expression. The statement opens a block of script that is executed for each element found in the object given by the expression on the right side of the in
operator.
Note
The expression on the right side of the in
operator is considered inside the opened block by the let
keyword.
The expression on the left side of the in
operator is considered like inside a virtual block around the loop's structure by the let
keyword.
The symbol between the for
keyword and the in
operator is used to store the current element. These elements must be provided by an iterator. If the result of the expression is not an iterator, the in
method of the given object is called to get an iterator.
Important
If the object given by the expression does not overload the in
method, the object is cast to an iterator to iterate over it. If the method exists but the value returned by the method is not an iterator, the result is also cast to an iterator to iterate over it.
Example:
for i in 0...count {
// Script to be executed with the new value of i
}
The for statement can also use several symbols separated by ,
. In this case, a temporary iterator will be created with each symbol, and the :=
method will be used to get the element. This behavior allows you to get each sub-element of an iterator element of the object stored in a different symbol. This is useful to iterate over a hash.
Example:
for key, value in dict {
// Script to be executed with the new values of key and value
}
The custom for statement allows you to re-execute a part of the script for each element of an object that cannot be browsed with an iterator.
It is introduced by the for
keyword followed by a custom range description. The statement opens a block of script that is executed for each element found by the custom range.
A custom range description starts with a (
and ends with a )
and contains three steps separated by ,
:
- The initialization step, executed before the first execution of the loop.
- The update step, executed before each next execution of the loop.
- The end check step, executed after the initialization/update step to check the end of the loop.
Note
The custom range update and end check steps are considered inside the opened block by the let
keyword.
The custom range initialization step is considered like inside a virtual block around the loop's structure by the let
keyword.
Example:
for (pos = str.indexOf(c), pos = str.indexOf(c, pos + 1), defined pos) {
// Script to be executed with the new value of pos
}
Tip
The custom for statement can also be used to reproduce the behavior of the "do while" structure of C.
Example:
for (do = true, do = not obj.isOver(), do) {
obj.perform()
}
Each conditional or loop control structure can be preceded by a move assignment or a copy assignment operation to create a generator expression. In this case, the result of each statement in the structure's block will be yielded to an iterator, which will then be used as the right side of the operation. This is the same behavior as if the control structure were in a generator function with a yield
keyword before each line.
Example:
let var foo = for let var i in myList {
func1(i)
func2(i)
func3(i)
}
// Is equivalent to
let var foo = def [...] {
for let var i in myList {
yield func1(i)
yield func2(i)
yield func3(i)
}
} ()
This control structure can also be used between [
and ]
tokens to generate an array. In this case, each value of the generated iterator is expanded to set up the array as if the unpack operator was used.
The print statement allows you to send each value returned by a part of the script to the standard output.
It is introduced by the print
keyword. The statement opens a block of script. Each value obtained in this block is sent to the standard output.
Example:
print {
1 + 1 // Prints 2 to the standard output
func() // Prints the result of func() to the standard output
for line in lines {
line // Prints the content of line to the standard output
}
}
Important
A custom conversion mechanism is used to convert the value to a string printable on the output. To ensure the format of the value, it is recommended to perform the conversion to string explicitly.
The parametrized print statement allows you to send each value returned by a part of the script to a custom output.
It is introduced by the print
keyword followed by a custom output description. The statement opens a block of script. Each value obtained in this block is sent to the custom output.
A custom output description starts with a (
and ends with a )
and contains an expression giving the custom output object. If the value returned is a number or a string, a minimal file printer is created with the given file descriptor or file path. Otherwise, the write
method of the object is called with each value to perform the print.
Example:
print (2) {
// Script to be executed to print data on the error output
}
print (obj) {
'value' // Equivalent to obj.write('value')
}
Note
The module system.terminal also provides tools to perform extended print operations on a terminal.
The try statement allows you to specify a part of the script that will be aborted if an exception is raised.
It is introduced by the try
keyword. The statement opens a block of script that could raise exceptions.
Example:
try {
// Script that could raise exceptions
}
If an exception is raised in a try statement, the execution of the script will continue with the first instruction after the block of the statement. Exceptions raised inmodule loading or a function call are also handled.
An exception is raised with the raise
keyword followed by an expression. The expression allows you to create an object that will describe the context of the exception.
Example:
try {
// ...
if error {
raise ErrorException(error)
}
// ...
}
If an exception is raised outside of a try statement, the context of the exception will be printed on the error output, and the execution of the script will be stopped as if an error occurred. To print the context of the exception, the show
method of the context object is called. If the context object does not implement this method, the value of the object is printed instead.
The catch statement allows you to execute a part of the script if an exception is raised in a try statement.
It is introduced by the catch
keyword followed by a symbol name. The statement opens a block of script that is executed if an exception was raised in the previous try statement. The symbol is used to store the context of the exception.
Example:
try {
// Script that could raise exceptions
} catch e {
// Script to recover a normal state after the e exception
}
Caution
Inserting a new line between the }
and the catch
keyword is a syntax error. The catch statement must follow immediately. This prevents some invalid states in the interactive mode.