tech

[English] [Japanese]

09. Repetition Syntax

This time I will explain the repeat syntax of LuneScript.

Syntax list

LuneScript supports the following repeat syntaxes:

  • while
  • repeat (to be removed in the future)
  • for
  • apply
  • foreach
  • forsort

while, repeat

Use while, repeat like this:

// @lnsFront: ok
let mut val = 1;
while val < 10 {
   val = val + 1;
}
print( val ); // 10
repeat {
   let mut endFlag = false;
   val = val + 1;
   if val >= 20 {
      endFlag = true;
   }
} endFlag;
print( val ); // 20

while will process the block while the expression is true, and repeat will process the block while the expression is false.

A repeat expression can make use of variables scoped inside the block.

Note that repeat will be removed in the future.

infinite loop

Use while true {} for infinite loops. Here true should be an immediate value.

For example, if a variable is used instead of an immediate value as shown below, it will loop infinitely in terms of processing, but it will not be treated as an infinite loop in flow analysis.

// @lnsFront: skip
let flag = true;
while flag {
}

The problem with not being regarded as an infinite loop is that the intended flow analysis cannot be performed.

For example, LuneScript determines that the print() statement after an infinite loop is not processed if:

// @lnsFront: error
while true {
}
print( "hoge" );

However, if the above true is not the immediate value, then it is determined that it is not an infinite loop and the print() statement may be processed.

If something that should not be processed is judged as processed, what should be a compilation error will not become an error, and there is a possibility that a defect in the code will be overlooked.

Always use immediate true for infinite loops.

Note that repeat {} false is also not treated as an infinite loop.

I thought it would be better to prepare instructions dedicated to infinite loops like Rust, but the current specification is this.

for

Use it like this:

// @lnsFront: ok
for count = 1, 10, 1 {
  print( count );
}

It is basically the same specification as Lua. The above example increments count from 1 to 10 by 1 and processes the block.

Note that the values 1, 10, 1 are only evaluated once at the start of for .

In other words, doing something like the following will not work as expected:

// @lnsFront: ok
let mut addVal = 1;
for count = 1, 10, addVal {
  addVal = addVal + 1;
  print( count );
}

If the increment value is omitted, 1 will be used.

apply

apply is a compatibility instruction with Lua's for in.

Use it like this:

// @lnsFront: ok
apply txt of string.gmatch( "hoge.foo.bar", '[^%.]+' ) {
   print( txt );
}

Note that the expression given to exp in apply val of exp {} must be a function call. This is a current limitation.

foreach

foreach is a function that enumerates the elements of lists, arrays and maps.

Use it like this:

// @lnsFront: ok
foreach val, index in [ 1, 2, 3 ] {
   print( index, val );
}
foreach val, index in [@ 10, 20, 30 ] {
   print( index, val );
}
foreach val, key in { "a":100, "b":200, "c":300 } {
   print( key, val );
}
foreach val in (@ 1, 2, 3 ) {
   print( val );
}

Set only enumerates values

List, array index, and map key can be omitted as follows.

// @lnsFront: ok
foreach val in [ 1, 2, 3 ] {
   print( val );
}
foreach val in [@ 10, 20, 30 ] {
   print( val );
}
foreach val in { "a":100, "b":200, "c":300 } {
   print( val );
}

It is prohibited to change the enumerated objects during loop processing of foreach and forsort. If changed, the behavior is undefined.

For example, the following are prohibited:

// @lnsFront: skip
let mut list = [ 1, 2, 3 ];
foreach val, index in list {
   list[ index ] = val + 10;
}

forsort

If the elements of Set or Map are enumerated by foreach, the enumeration order of the elements is undefined.

forsort enumerates the elements of Set and Map in the order sorted by key (ascending order).

// @lnsFront: ok
forsort val, key in { "b":200, "c":300, "a":100 } {
   print( key, val );
}
forsort val in (@ 2, 4, 1, 0 ) {
   print( val );
}

Map's forsort can omit the key.

// @lnsFront: ok
forsort val in { "b":200, "c":300, "a":100 } {
   print( val );
}

forsort internally clones and sorts, so there is overhead for that.

Also, if the type of the Set , or the key type of the Map is not a sortable type, an error will occur.

break

break exits the innermost repeat control statement.

There is no continue.

summary

LuneScript's general control syntax is basically the same as Lua's.

The main difference is the addition of foreach, forsort to handle lists etc.

I'll explain the functions next time.