Table of Contents
SMNP language provides a loop statement which also acts as expression.
The statement has been totally designed from scratch and is not similar
to any known loop statements from other languages at all.
Loop allows you to repeat some instructions with counter set programmatically.
All loops are created through loop operator (^).
Simple loop
The simplest loop consists only of counter, loop operator and instruction or block of instructions.
Example:
# the simplest loop
3 ^ print("Money "); # Money Money Money
# the same using block of code
3 ^ {
print("Money ");
}
# Output: Money Money Money
Of course, you can use any expression as counter, like variable or function call:
function provideCounter(x: int) {
return x * 2;
}
provideCounter(5) ^ print("a"); # aaaaaaaaaa
You can define a counter variable whose value is increased with each iteration
using as clause (note, that values start from 0):
3 as i ^ print(i, " "); # 0 1 2
while loop
You can create a loop which is controlled by logic condition.
It can be done just putting a bool value as a counter.
Example:
end = false;
i = 0;
not end ^ {
if (i == 3) {
end = true;
}
i = i + 1;
}
println(end); # true
println(i); # 4
Note that condition-controlled loop doesn't support as clause.
For-each loop
This kind of loop works with lists, maps and strings.
List
You can put a list as a counter. In this case statement will be executed
for each element of list. You can obtain access to element through as clause
like in previous examples.
Example:
myList = [@c, @d, @e];
myList ^ print("Money "); # Money Money Money
myList as item ^ print(item, " "); # C D E
You can put additional parameter into as clause. In this case the first parameter
will be the value of passed list and the second one will be iterator that is increased after each loop iteration. If you are using more than one parameter in as clause,
you have to enclose them between parentheses.
Example:
[@c, @d, @e] as (n, i) ^ println(i, ". ", n);
# Output:
# 0. C
# 1. D
# 2. E
Map
Map is also supported to act as a counter of loop. In this case statement will be executed for each value of passed map.
Example:
x = {
a -> @c,
b -> @d,
c -> @e
};
x ^ print("Money "); # Money Money Money
You are also able to access keys and values of iterated map using parameters in as clause.
You can use up to three parameters, where
- the first is just a value
- the second is a corresponding key
- the third is an iterator increased by one with each iteration.
Example:
myMap = {
first -> true,
second -> [@c, @d, @e],
third -> 14
};
myMap as value ^ println(value);
# Output:
# true
# [C, D, E]
# 14
myMap as (value, key) ^ println(key, ": ", value);
# Output:
# first: true,
# second: [C, D, E]
# third: 14
myMap as (value, key, i) ^ println(i, ". ", key, ": ", value);
# Output:
# 0. first: true,
# 1. second: [C, D, E]
# 2. third: 14
String
Loop operator supports also string counter. In this case, you are able to iterate through each character
of passed string. As in the previous cases, you are able to access both current character and iterator using as clause.
Example:
text = "Hello";
text ^ print("0"); # 00000
text as char ^ println(char);
# H
# e
# l
# l
# o
text as (char, index) ^ println(index, ". ", char);
# 0. H
# 1. e
# 2. l
# 3. l
# 4. o
Filters
Loops in SMNP language also support filtering.
The filtering can be done with % clause, which contains a condition
that must be met to execute iteration. % clause is placed at the very last
of loop statement.
Example:
10 as i ^ println(i) % mod(i, 2) == 0;
# Output:
# 0
# 2
# 4
# 6
# 8
Filtering can be useful with simple counting loops like above, but it is really powerful with for-each loops. You can pass further only elements of list/map that met defined conditions. It is even more useful with special feature of loops that is covered in next section.
Loop expression
The power of designed loops relies on the fact, that all kinds of them actually can work as expressions. It means that you can use any kind of loop as e.g. function argument, because they can produce a value. They work similar to Python's list comprehension and actually produce a new list. One important condition you have to met in order to use loop as expression is to put expression as a loop's statement. Because of that in loop expression you can't use block of code. The statement must be a single instruction - expression.
Example:
x = [1, 2, 3, 4];
# 'y' holds numbers multipied by 2
y = x as i ^ i * 2; # y = [2, 4, 6, 8]
# 'z' holds squares of even numbers
z = x as i ^ i ** 2 % mod(i, 2) == 0; # y = [4.0, 16.0]
Note, that loop statement is right associative. That means nested loop statements are being accumulated in right-hand branch. Take look at example:
2 ^ 4 ^ 6 ^ print("a");
# is exactly the same as
2 ^ (4 ^ (6 ^ print("a")));
is parsed to following abstract syntax tree:
^
/ \
2 ^
/ \
4 ^
/ \
6 print("a")
It could be a flaw if you would like to create a mapping chain using loop statements (like streams in Java 8 or LINQ in .NET), because it requires from operator to be left associative, so that first instruction would produce value and pass it further. It can be of course achieved with parentheses:
data = ["lorem", "ipsum", "dolor", "sit", "amet"];
output = (((((data as d
^ d
% d.length > 3) as d
^ d.length) as d
^ d * 2) as d
^ d + 1) as d
^ d
% d == 11);
println(output); # [11, 11, 11]
As you can see it actually works but is not convenient nor readable.
Simple Music Notation Processor
SMNP Language Reference
- About SMNP Language
- Import statement
- Supported data types
- Variables
- Operators
- Functions and methods
- Condition statement
- Loop statement-expression
- Error handling
Modules and standard library: