1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225
|
Loops
=====
Basic Storm has three different loops:
- The generic loop:
```bsstmt:placeholders
do {
} while (<condition>) {
}
```
- The for loop:
```bsstmt
for (Nat i = 0; i < count; i++) {
}
```
- The range loop:
```bsstmt:placeholders
for (x in <container>) {
}
```
While the loops are technically expressions, none of them return anything other than void (since
they may execute zero times). It is therefore not very useful to use them as expressions. This might
change in the future.
As in C++, it is possible to use `break` and `continue` inside any of the loops. `break` exits the
loop, while `continue` aborts the current loop iterations and continues to the next. Custom loops
with support for `break` and `continue` should inherit from the `lang:bs:Breakable` class.
The Generic Loop
----------------
The generic loop is a generalization of the `while` and the `do-while` loops in C++ and Java. It has
the following generic form:
```bsstmt:placeholders
do {
<do expression>;
} while (<condition>) {
<while expression>;
}
```
All parts are optional. It is possible to select a sequence of one or more parts of the loop to form
the following different loops. The first one is the traditional while loop:
```bsstmt:placeholders
while (<condition>) {
}
```
And the traditional do-while loop:
```bsstmt:placeholders
do {
} while (<condition>);
```
But also an infinite loop like so:
```bsstmt:placeholders
do {
}
```
And a loop with the condition in the middle of an iteration:
```bsstmt:placeholders
do {
} while (<condition>) {
}
```
The last form is useful when checking input. For example, the following type of code is sometimes
common in C++:
```bs
int inputPositive() {
int result = 0;
while (true) {
cout << "Enter a positive integer: ";
cin >> result;
if (result > 0)
break;
cout << "Incorrect input. Only positive integers!" << endl;
}
return result;
}
```
To avoid repeating parts of the code, the programmer has opted to use `break` to exit the loop
midway. In Basic Storm, one can write the same logic as follows:
```bs
Int inputPositive() {
do {
print("Enter a positive integer: ");
Int result = readInt(); // Note: for illustration, not present in the standard library.
} while (result <= 0) {
print("Not correct. ${result} is not positive!");
}
return result;
}
```
One observation from the example above is that even though the body of the loop is split into two
blocks, variables from the first block are visible in the condition and in the second block.
The For Loop
------------
The for loop looks like in C++ and Java:
```bsstmt:placeholders
for (<initializer>; <condition>; <update>) {
}
```
Since variable declarations are expressions in Basic Storm, no special consideration needs to be
made for the `<initializer>` portion of the loop. It is just an expression.
The semantics are equivalent to:
```bsstmt:placeholders
{
<initializer>;
while (<condition>) {
// Loop body.
<update>;
}
}
```
With the exception that `continue` executes `<update>` before continuing to the next iteration. The
above loop expansion would not call `<update>` when `continue` is used.
The Range Loop
--------------
The final loop (which is actually implemented entirely in Basic Storm itself) is the range loop. It
is dedicated to iterating through a container using any of the
[iterators](md:/Library_Reference/Standard_Library/Iterators) available in the standard library. It
has the following form:
```bsstmt:placeholders
for (<key>, <value> in <container>) {
}
```
Here, `<key>` and `<value>` are two identifiers that determine the names of the variables used for
the current element in the loop body. `<key>` can be omitted, and must be omitted for iterators that
provide no notion of a key. `<container>` is an arbitrary expression that evaluates to a container.
The range loop supports three types of iteration strategies. They are all illustrated in the context
of the following loop, where `<container>` is some expression that produces a container:
```bsstmt:placeholders
for (k, v in <container>) {
print("Key: ${k}");
print("Val: ${v}");
}
```
The tree types are as follows. They are attempted in the following order:
1. If `begin` and `end` are available, then iterators are used. The loop is transformed into the
following:
```bsstmt:placeholders
{
var _container = <container>;
var _end = container.end();
for (var _at = container.begin(); _at != _end; ++_at) {
var k = _at.k();
var v = _at.v();
print("Key: ${k}");
print("Val: ${v}");
}
}
```
Note that the key is only useable if the iterators of the container provide the `k` member.
2. If `iter` is available, and returns a type with a member `next`, then the loop is transformed
into the following:
```bsstmt:placeholders
{
var _iter = container.iter();
while (v = container.next) {
print("Val: ${v}");
}
}
```
Note that this iteration strategy does not support keys.
3. Finally, if `count` and the `[]`-operator are available, then the loop is transformed into the
following:
```bsstmt:placeholders
{
var _container = container; // To only evaluate 'container' once.
var _count = container.count;
for (Nat k = 0; k < _count; ++k) {
var v = _container[k];
print("Key: ${k}");
print("Val: ${v}");
}
}
```
Note that the key is marked as constant after the loop header in this transform. This is,
however, not possible to express in source code currently.
|