diff --git a/Loop-statement-expression.md b/Loop-statement-expression.md new file mode 100644 index 0000000..e6b1eaa --- /dev/null +++ b/Loop-statement-expression.md @@ -0,0 +1,242 @@ +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 and readable. \ No newline at end of file