Looping constructs

OmniMark provides five types of looping constructs: repeat, repeat for, repeat to, repeat over, and repeat scan.

You can use a repeat loop to perform a series of actions repeatedly. You must explicitly exit a repeat loop using either a throw or an exit:

  process
     local integer i initial { 1 }
  
     repeat
        output "i is " || "d" % i || "%n"
        increment i by i
        exit 
           when i > 20
     again
        

This program will create the following output:

  i is 1
  i is 2
  i is 4
  i is 8
  i is 16

You can use a repeat to to repeat a block of code a specific number of times. The loop will repeat the number of times specified by an integer expression following the to:

  process
     repeat to 5
        output "X"
     again
        

The integer expression following the keyword to must evaluate to a value greater than 0 for the loop body to execute at all.

You can use a repeat for loop to repeat over a block of code a specific number of times. The repeat for loop provides an alias for the loop iteration and allows you to control the starting and ending values of the alias, as well as the increment it is changed by:

  process
     repeat for integer i from 9 to 27 by 3
        output "d" % i || " "
     again
        

In the first interation, i will be equal to the integer expression heralded by from. In successive iterations, at the beginning of each iteration i will by incremented by the integer expression heralded by by, until it surpasses the integer expression heralded by to, at which point the loop terminates. The starting value can be greater than the ending value, in which case the increment must be negative; otherwise the loop will terminate without executing.

You can use a repeat over loop to perform the same action on each item of a shelf in turn:

  global string guys variable initial { "Bob", "Doug", "Andy", "Greg" }
  
  process
     repeat over guys
        output guys || "%n"
     again
        

An alias can be used to access the iteration's current item:

  global string guys variable initial { "Bob", "Doug", "Andy", "Greg" }
  
  process
     repeat over guys as g
        output g || "%n"
     again
        

The alias is optional when iterating over a shelf, but required when iterating over a record field, a shelf literal, or a shelf-class function

The reversed keyword can be used to indicate that loop should begin from the last item on the shelf and iterate to the first item on the shelf:

  global string guys variable initial { "Bob", "Doug", "Andy", "Greg" }
  
  process
     repeat over reversed guys as g
        output g || "%n"
     again
        

Multiple shelves can be specified in the header of a repeat over loop. However, their sizes must match at run-time:

  global string  guys variable initial { "Bob", "Doug", "Andy", "Greg" }
  global integer ages variable initial { 36, 23, 45, 65 }
  
  process
     repeat over guys as g & ages as a
        output g || " is " || "d" % a || " years old.%n"
     again
        

When repeating over multiple shelves, the qualifier reversed applies only to the shelf immediately following it:

  global string  guys variable initial { "Bob", "Doug", "Andy", "Greg" }
  global integer ages variable initial { 36, 23, 45, 65 }
  
  process
     repeat over guys as g & reversed ages as a
        output g || " is " || "d" % a || " years old.%n"
     again
        

You can use a repeat scan to scan a data stream. The repeat scan loop will continue to match data from the source until the source is exhausted or it encounters data that is not matched by any of its alternatives:

  process
     local string guesses initial { "sufklbp" }
  
     repeat scan "abcdefghijklmnopqrstuvwxyz"
     match any => l
        do unless guesses matches any ** l
           output l
  
        else
           output "*"
        done
     again