Flow Control

From HLKitWiki
Jump to: navigation, search

Context: HL KitKit Reference 

The scripting language supports a variety of basic flow control mechanisms, and each is described in the sections below.

Label and Goto Statements

The most primitive form of flow control is the use of "label" and "goto" statements. Label statements are defined with the form "name:", where "name" follows the same naming rules as variables. To transfer control to a label statement, a goto statement is used. The syntax for a goto statement is "goto name", where name corresponds to an existing label within the script. When a goto statement is executed, control passes to the label statement, and the next line executed in the script is the one immediately following the label statement. It is perfectly valid to issue a goto statement prior to the definition of the label statement, allowing you to skip over a section of the script if you wish. An example code block demonstrating the use of labels and gotos is given below.

var foo as number
foo = 10
goto mylabel
foo = 20
mylabel:
~The value of foo is still 10, since we skipped over the assignment to 20.

If/Then Blocks

A more traditional form of control flow is with the "if/then" block. Within an if/then block, a test of some sort is performed. Based on the results of that test, the following block of code may or may not be executed. The if/then block consists of two separate statements. The first statement is the test to be performed and uses the syntax "if (expr1 comparison expr2) then". The values of "expr1" and "expr2" can be any valid arithmetic expression. The valid values for "comparison" are the various relationship operators: '<', '<=', '=', '>=', '>', and '<>'. The first five of these comparison operators should be familiar, while the last one implies "not equal".

The "if" statement evaluates the two expressions and then compares them with the relationship indicated. If the comparison is satisfied, then execution continues with the line immediately following the "if" statement.

The second statement identifies the end of the if/then block and has the simple syntax "endif". If the comparison is failed, then execution skips over the if/then block until the "endif" statement is reached, at which point execution resumes. An example if/then block is shown below.

var foo as number
foo = 10
if (foo + 3 > 20) then
  foo = 1
  endif
~The value of foo is still 10, since we skipped over the assignment above.

If/Then/Else Blocks

The if/then block can be extended to be an if/then/else block. This form is useful when you need to execute one block of code if the condition is true and another block of code if it fails. The if/then/else block is identical to the if/then block, except that an additional "else" statement is inserted. This new statement demarcates where the block of code to execute on success ends and the block of code to execute on failure begins. If the conditional test is satisfied, then execution continues with the next line, but when the "else" statement is encountered, execution jumps to the line following the "endif" statement. If the conditional test fails, then execution jumps to the line following the "else" statement. An example if/then/else block is shown below.

var foo as number
foo = 10
if (foo + 3 > 20) then
  foo = 1
else
  foo = foo + 10
  endif
~The value of foo is now 20, since we executed the "else" clause only.

If/Then/Elseif/Else Blocks

To handle the situation where multiple value ranges need to be handled, the if/then/else block also supports an "elseif" statement. The "elseif" statement allows a separate condition to be tested, with its own block of code to be executed if the condition is satisfied. All condition blocks are tested in sequence, with only the first one that is satisfied having its code executed.

var foo as number
foo = 8
if (foo <= 5) then
  foo = 1
elseif (foo <= 10) then
  foo = 2
elseif (foo <= 15) then
  foo = 3
else
  foo = 4
  endif
~The value of foo is now 2, since we executed the first "elseif" clause only.

While/Loop Blocks

Another control flow mechanism provided by the scripting language is the "while/loop" block. The while/loop block executes a block of code repeatedly as long as a particular conditional test remains satisfied. The while/loop block begins with a statement of the form "while (expr1 comparison expr2)", where "expr1", "expr2", and "comparison" all behave identically to a standard "if" statement. The end of a while/loop block is identified by a "loop" statement, which consists solely of the keyword "loop" on a line. When the "loop" statement is encountered, the conditional test is evaluated again. As long as the condition remains satisfied, execution continues with the line following the "while" statement. Once the condition fails, execution jumps to the line following the "loop" statement. The loop will continue executing the code until the conditional test finally fails. An example while/loop block is shown below.

var foo as number
foo = 1
while (foo <= 10)
  foo = foo + 1
  loop
~The value of foo is now 11.

For/Next Blocks

The final control flow mechanism available is the "for/next" block. Like the while/loop block, the for/next block executes a block of code repeatedly, keying on the value of a variable (the "loop index"). The for/next block is identified by "for varname = expr1 to expr2", where "varname" is the name of the numeric variable to be used as the loop index and "expr1" and "expr2" are complex expressions. The variable is initialized with a given value and incremented by 1 every iteration of the loop. After the second value has been reached and processed, the iteration stops (so looping from 1 to 5 will run through the loop 5 times, the index taking on values of 1, 2, 3, 4 and 5 in succession before stopping). The loop index is automatically incremented by the for/next construct itself, and does not have to be maintained by the script writer.

var x as number
var text as string
text = "A list of some numbers: "
for x = 0 to (100 / 20 * 2)
  text = text & x
  next
~The string 'text' will now contain an ascending list of the numbers from 0 up to 10.

Nesting

All conditional statements (if/then, if/then/else, while/loop and for/next) can be safely nested within each other. For example, if two separate conditions must be satisfied in order to perform some action, you might have a script that looks similar to the example below. When nesting conditional statements, each "endif" statement is associated with the closest "if/then" statement. Appropriate use of indentation can greatly enhance the readability of scripts when nested statements are employed.

if (x > y) then
  if (a > b) then
    z = 1
  else
    z = 0
    endif
else
  if (a > b) then
    z = 0
  else
    z = 1
    endif
  endif

IMPORTANT! The scripting mechanism is designed to handle scripts of only moderate size and complexity. As such, scripts possess a maximum nesting depth of 20 levels, which ought to be significantly more than any script should ever need.

If a script is too large or complex, an error will be reported when compiling the script. In general, a given script can utilize dozens of flow control constructs without becoming too complex, so the complexity limit should not be reached under normal conditions.

Done Statement

If you reach a point in the execution of a script where all necessary processing is completed, you can utilize the "done" statement to immediately exit the current script. Judicious use of "done" can simplify scripts and make them easier to maintain by eliminating a great deal of nesting and matching of if/then/else statements.

Two examples are shown below, where the second script accomplishes the same as the first. The key difference is that the second script utilizes the "done" statement. Use of the "done" statement is a matter of personal style, but it can be very handy for scripts with both simple and complex conditions.

if (foo <= 3) then
  ~do something
else
  ~lots of code
  if (for <= 6) then
    ~lots of code
  else
    ~lots of code
    endif
  ~lots of code
  endif
if (foo <= 3) then
  ~do something
  done
  endif
~lots of code
if (for <= 6) then
  ~lots of code
else
  ~lots of code
  endif
~lots of code

DoneIf Statement

There will be numerous situations when writing scripts where you'll want to test for a condition and exit out of the script. This amounts to writing an "if" statement and using "done" if the test is satisfied. That's three lines of code that you'll be using over and over again.

To simplify this, the scripting language provides a "doneif" statement. This statement takes a comparison expression and will exit the script if the test is satisfied, thereby reducing three lines of code to one. For example, the following two blocks of code are functionally equivalent.

if (foo <= 3) then
  done
  endif
doneif (foo <= 3)