Looping statements execute the sequence of statements several times until the looping condition becomes false. When the looping condition becomes false, the loop terminates. The looping statements in Jai include while
loops and for
loops.
while
loops
While loops executes a sequence of statements repeatedly until the loop condition is met. Their syntax is while condition action;
, where condition
is some expression that can be evaluated as true or false, and action is a statement or a block of statements. For instance:
n := 0;
while n < 10 {
n += 1;
}
This while
loop keeps on incrementing the n
variable when n
is less than 10. When n
is no longer less than 10, the program will terminate the loop.
for
loops
If you have a type that can be iterated over, such as an array of some sort, you can use a for
loop to iterate through it. For-loops in Jai are actually deceptively powerful, for a few reasons.
The simple format for for loops is for set action
, where the set
is something that supports iteration and action
is a statement or a block.
To iterate over a sequence of numbers, say from 1 to 10, simply do:
for number: 1..10 {
print("Number %\n", number);
}
Here, number
is the iterator variable name, but Jai allows you to skip it, in which case it will be called it
by default:
for 1..10 {
print("Number %\n", it);
}
It’s worth noting that this will iterate from 1 to 10 inclusive, or, as mathematicians might put it, [1, 10].
Often, rather than iterating over a sequence of numbers, you’ll want to iterate over an array. Then you simply state the array name as the set. For instance:
my_array := .[5, 10, 15, 20, 25, 30];
for my_array {
print("We got a %\n", it);
}
In addition to it
, Jai also defines it_index
by default, which contains the index of the item.
foods := .["Burek", "Pho", "Khachapuri", "Empanadas", "Jjajangmyeon"];
print("Top five dishes:\n");
for foods {
print(" %. %\n", it_index, it);
}
break
statement
The break statement terminates the current loop immediately after the break statement is executed. The break
statement works in both for
and while
loops.
for i: 0..5 { // This for loop prints out 0, 1, 2 then breaks out of the loop
if i == 3
break;
print("%, ", i);
}
In the example above, the for loop loops three times, printing out 0, 1, 2, then the break statement stops the iteration.
The break
statement can also be used to break out of an outer loop through the syntax: break var
, where var
is the variable name in the for loop. You can only break
out of an outer for
loop. You cannot break out of an outer while
loop.
for i: 0..5 {
for j: 0..5 {
if i == 3
break i; // breaks out of the outer loop for i: 0..5
print("(%, %)", i, j);
}
}
The example above prints out (0,0), (0,1), (0,2), (0,3)… (2,5), then when it reaches i==3, the break statement stops the outer loop.
continue
statement
The continue statement is used to skip all the statements in the current loop after the continue statement is executed. The continue
statement works in both for
and while
loops.
for i: 0..5 { // This for loop prints out 0, 1, 2, 4, 5
if i == 3
continue;
print("%, ", i);
}
In the example above, the for loop loops six times, printing out 0, 1, 2, 4, 5. The value of 3 is not printed since the continue statement causes the program to skip the rest of the loop.
The continue
statement can also be used to skip to the outer loop through the syntax: continue var
, continue var
is the variable name in the for loop. You can only continue
out of an outer for
loop. You cannot continue out of an outer while
loop.
for i: 0..5 {
for j: 0..5 {
if i == 3
continue i; // breaks out of the outer loop for i: 0..5
print("(%, %)", i, j);
}
}
The example above prints out (0,0), (0,1), (0,2), (0,3)… (2,5), (4,0), (4,1), (4,2)…(5,5). The for-loop skips all the value pairs starting with a 3, since the continue skips all the instructions after the continue statement.
remove
statement
The remove statement is used to remove an element from a dynamic array […] without needing to rewrite the entire for loop into a while loop. The remove statement assumes an unordered remove, the remove swaps the current element that is being iterated on with the last element, and then removes the last element. The remove statement happens in constant time O(1). remove
only works inside of a for
loop.
arr: [..] int;
for i: 0..10 {
array_add(*arr, i);
}
for a: arr {
if a == 2 {
remove a;
}
}
Reverse for
loop
To do a for loop in reverse, add a <
in front of the for
loop. The for
loop will start at the beginning number and countdown to the ending number. In this example, the for
loop will iterate from 5 down to 0 inclusive.
for < i: 5..0 { // This for loop prints out 5 4 3 2 1 0 in that order
print("%\n", i);
}
for
loop by pointer
To iterate an array by pointer, add a *
in front of the for
loop.
array := int.[1, 2, 3, 4, 5];
for * ele : array {
val := <<ele;
<<ele = val * val; // take all the values in an array and square the elements
}
for_expansion
Jai allows you to use the for
loop to iterate over custom data structures. for
loops are designated through a macro. Here is an example of how to create a for
loop:
LinkedList :: struct {
data: int;
next: *LinkedList;
}
for_expansion :: (list: *LinkedList, body: Code, flags: For_Flags) #expand {
iter := list;
i := 0;
while iter != null {
`it := iter.data;
`it_index := i;
#insert body;
iter = iter.next;
i += 1;
}
}
In the example above, we define a custom LinkedList, a very common computer science data structure. We define using the for loop over that data structure by using a for_expansion
. for_expansion
takes in three parameters: a pointer to the data structure one wants to use the for loop on, a Code
datatype, and a For_Flags
flags. The #insert body;
inserts body of the for loop at that portion of the macro.
You need to backtick an it
and it_index
to get the for_expansion
working. Else, this is an error.
The For_Flags
enum_flags is found in Preload.jai
with the following definition:
For_Flags :: enum_flags u32 {
POINTER :: 0x1; // this for-loop is done by pointer.
REVERSE :: 0x2; // this for-loop is a reverse for loop.
}
Redefining break and continue inside for_expansion
In the #insert
directive, break
, continue
, and remove
can be redefined and the default behavior can be overwritten to do custom things.
#insert (break=do_something(), continue=do_something()) code;