loop statement - Raesangur/PascalScript_Reference GitHub Wiki
Detailed Syntax
- loop_statement:
(optional) loop_attributes
loop((optional) loop_init_statement; loop_condition; (optional) loop_iteration_expression): loop_block- or
(optional) loop_attributes
loop((optional) loop_init_statement; (1 ... n)ranged_loop_declarationinloop_expression): loop_block
-
do_loop_statement:
(optional) loop_attributes
do loop((optional) loop_init_statement; loop_condition; (optional) loop_iteration_expression): loop_block
-
loop_init_statement:
- (1 ... n) comma-separated declarations.
- If used, must end in a
;. If unused,;may be skipped. - Will be executed once before the beginning of the loop.
- Variables declared in the loop_init_statement are in the same scope as variables declared in the loop_block.
-
loop_condition:
- A boolean-resulting expression.
- In a regular
looploop, this expression is evaluated at the beginning of every iteration of the loop, including the first one. - In a
do looploop, this expression is evaluated at the end of every iteration of the loop.
-
loop_iteration_expression:
- (1 ... n) comma-separated expressions to be executed at the end of the loop_block.
- If unused, the preceding
;may be skipped.
-
loop_block:
(optional) statement
-
ranged_loop_declaration:
- A declaration of a variable of type
ranged_loop_expression.begin().types[0]orranged_loop_expression.begin().types[0]&. - The variable declared in the ranged_loop_declaration will be updated before each iteration of the loop.
- If multiple ranged_loop_declaration and ranged_loop_expression pairs are provided (separated by commas), both variables will be updated from their respective ranged_loop_expression before each iteration of the loop.
- A declaration of a variable of type
-
ranged_loop_expression:
- An expression which resulting value has a
begin()andend()function defined, that both return an object respecting theiteratortype traitdefine rle = ranged_loop_expression, rle.has_member(begin()) && rle.has_member(end()) && std.type_trait.is_iterator(rle.begin().returns()[0])
- An expression which resulting value has a
loop(int i = 0; i < 6; i++): // Regular C-style for loop
std.io.println(i);loop(int i in [0 ... 9]): // Ranged-based loop, using the `loop.index` variable
{
std.io.println(i);
if(loop.index == 5):
break;
} int i = 6;
loop(i): // Loop with only condition expression filled in
{
std.io.println(6 - i--);
} loop(int[] array = [0 ... 9], // Two initialized values & two iteration expressions
int* ptr = array.begin();
ptr < array.end(); *ptr = 0, ptr++): // Will set the value in the array to 0 before moving the iterator
{
std.io.println(*ptr);
if(loop.index == 5):
break;
}do loop(int i = 0; i < 5; i++):
std.io.println(i);All output:
0
1
2
3
4
5
A special flavor of the loop loop is the do_loop loop, in which the condition is evaluated at the end of the loop_block.
loop statements can also be used to loop over an iterating range of values, such as an array, a string literal or any standard library containers.
The keyword in is used to denote the ranged_loop_declaration from the ranged_loop_expression.
These ranged-based loop loops need the iterating object to have the begin() and end() methods defined, that both return an object compatible with the iterator requirements from type_traits.
If multiple ranged_loop_declaration and ranged_loop_expression pairs are provided, each loop variable will be updated from its expression at the beginning of the loop until the first expression reaches its end, effectively acting as a zipping loop.
These range-based loop loops will simply expand in a regular loop loop, where syntax (1) is equivalent to syntax (2).
// Syntax (1)
loop(int i in [0 ... 9]):
{
std.io.println(i);
}
// Syntax (2)
// ranged_loop_expression was of type int[]&&;
// int[].begin() and int[].end() returns an int*
loop(int[] expression = [0 ... 9],
int* it = expression.begin();
it < expression.end();
++it): // If ++operator() is not available for iterator type, will try with operator++()
{
int i = *it;
// ranged-based loop statements begin here:
std.io.println(i);
}// Syntax (1)
loop(int a in [0 ... 9], int b in [10 ... 15])
{
std.io.println(a + b);
}
// Syntax(2)
loop(int[] expression1 = [0 ... 9],
int* it1 = expression1.begin()
int[] expression2 = [10 ... 15],
int* it2 = expression2.begin();
it1 < expression1.end() && it2 < expression2.end()>;
++it1, ++it2):
{
int a = *it1;
int b = *it2;
// ranged-based loop statements begin here:
std.io.println(a + b);
}The loop.index variable is an easy way to keep track of the loop index during ranged-based loop loops (or any non-index-based loop loops).
This variable is normally not included in the compiled code, but if used, will be included to keep track of the current loop index.
For range-based loop loops, the loop.index variable will be calculated from the begin position and the loop iterator (see example (1)).
For other loops, there are two possibilities:
- If the loop loop contains a simple loop(type i = value; i < value; i++), and someType.has_member(operator-(value.type)) == true, the loop.index variable will be calculated from the used loop index i as long as this index is not modified during the loop execution (see example(2)).
- If the loop loop is more complicated, has an index that can't be easily calculated from or modifies the index during execution, the loop.index variable will be calculated independently (see example(3)).
// EXAMPLE (1)
// Syntax (1)
std.io.println("\nEXAMPLE 1 - Syntax 1");
loop(int i in [0 ... 5]):
{
std.io.print(loop.index + i);
}
// Syntax (2) <- Will be generated from Syntax (1)
std.io.println("\nEXAMPLE 1 - Syntax 2");
loop(int[] expression = [0 ... 5],
int* begin = expression.begin(),
int* it = begin;
it < expression.end(); ++it):
{
int i = *it;
std.io.print((it - begin) + i); // loop.index is simply substituted
}
// EXAMPLE (2)
// Syntax (1)
std.io.println("\n\nEXAMPLE 2 - Syntax 1");
loop(int i = 5; i < 10; i++):
{
std.io.print(i - loop.index);
}
// Syntax (2) <- Will be generated from Syntax (1)
std.io.println("\nEXAMPLE 2 - Syntax 2");
loop(int begin = 5, int i = 5; i < 10; i++):
{
std.io.print(i - (i - begin));
}
// EXAMPLE (3)
// Syntax (1)
std.io.println("\n\nEXAMPLE 3 - Syntax 1");
loop(int i = 0; i < 5; i++):
{
std.io.print(i + loop.index);
if (loop.index == 3):
i = 5;
}
// Syntax (2) <- Will be generated from Syntax (1)
// loop indexing variable is modified during execution, a standalone index will be generated
std.io.println("\nEXAMPLE 3 - Syntax 2");
loop(int index = 0, int i = 0; i < 6; index++, i++):
{
std.io.print(i + index);
if(index == 3):
i = 4;
}Output:
EXAMPLE 1 - Syntax 1
0246810
EXAMPLE 1 - Syntax 2
0246810
EXAMPLE 2 - Syntax 1
55555
EXAMPLE 2 - Syntax 2
55555
EXAMPLE 3 - Syntax 1
02469
EXAMPLE 3 - Syntax 2
02469
The #infinite attribute allows for better compiler optimization and warnings. A loop with the loop_condition evaluating to a compile-time true will emit an infinite loop warning.
Adding the #infinite attribute suppresses the warning and can allow for better optimization of the loop.
This attribute can also be used to suppress watchdog conditions if supported by the implementation.
If the loop's condition doesn't evaluate to true but the #infinite attribute is present, a warning will also be emitted.
#infinite
loop(true): // Would emit warning if it weren't for the #infinite attribute
std.io.println("Good morning");an #infinite loop can also be written shorthand like this:
#infinite
loop():
std.io.println("Good morning");The #parallel attribute is an optimization hint to run the loop in parallel on as many threads as specified if possible, modulo the numbers of iterations (if known at compile-time). Leaving this field empty (with or without parentheses) will take as many threads as recommended for the targeted platform. Other hardware acceleration tricks such as SIMD instruction usage may also occur from this optimization hint.
int[10] values;
#parallel(4)
loop(int i in [0 ... 10]):
values[i] = i * 2;