Code Blocks and Looping

Code Blocks from Expression Engine perspective behave as functions – i.e. can define a return value. These blocks consist of code lines and can use internal variables. Access to internal variables is very fast and a single variable can contain any data type that a standard expression value can hold (simple types, arrays, etc.). Internal variables do not need type definitions. Every internal variable starts with an @ character and can be a combination of alphanumeric characters. The default value for all internal variables is an “Empty” value. Internal variables defined in the main code block can be used by inner code blocks or code lines sections.

Main code blocks have two basic sections – variable declarations (optional), and code lines section. Each data block internally defines a return variable with a special, well-known name - @@.

DECLARE

Internal variable declaration section

(e.g. @myvariable; @mysecondVariable = 10;)

BEGIN

Code section with code lines…

END

When the declare section is not specified, then the only available internal variable is the return value @@. The variable declaration section can define any number of internal variables. Each variable can be optionally initialized. The variable declaration line ends with a semicolon character.

@myVariable;

@myInitializedVariable = 10;

As was mentioned earlier, multiple code blocks can be used side-by-side inside an expression:

BEGIN SET @@=5; END + BEGIN SET @@=7; END

Is equivalent to

5 + 7

These examples are used to demonstrate code blocks behavior as functions and how to specify a return value inside a code block. In this example, both code blocks are independent, thus cannot share their internal variables. To be able to share variables between separate code blocks, one upper code block is necessary:

DECLARE

  @a = 5; @b = 7;

BEGIN

  SET @@= BEGIN SET @@=@a; END + BEGIN SET @@=@b; END

END

Code Lines

Each code line starts with a keyword and ends with a semicolon character.

SET STATEMENT

This is used to set internal variables. The following is the SET syntax:

SET @variable_name = value;

Where variable_name specifies the internal variable declared in the declare section and the value can be any standard expression [combination of functions, operators and variables (internal or external)].

Examples:

SET @myvar = 10;

SET @myvar = @myvar + 1;

SET @myvar = {{my OPC Tag 1}} + {{my OPC Tag 2}};

SET @myvar = tonumber({{my OPC Tag 1}}) * @myvar2 + {{my OPC Tag 2}};

SET @myvar = IF {{my OPC Tag 1}} > 0 THEN {{my OPC Tag 1}} ELSE 0;

EXIT STATEMENT

This command allows for an exit code block earlier than in the end of the code block. It can be used as a simple EXIT command, where it makes sense in combination with an IF statement or conditional exit with WHEN part specified:

EXIT WHEN boolean_condition (expression);

or

EXIT;

The Exit command is not propagated to upper code blocks – i.e. Exit exists from the existing code block only.

Examples:

EXIT WHEN @a > 0;

IF @a > 0 THEN EXIT;

EXIT WHEN {{my data tag}} > 1 && @a < 0;

FOREACH STATEMENT

Simple loop designed to iterate through arrays. Syntax is:

FOREACH counter_variable IN array_value

LOOP

/* add code lines here */

END

where counter_variable is an internal variable, which is declared by FOREACH statement – i.e. doesn’t need to be explicitly declared. This variable is known inside the loop body only and contains a current array element. The array_value is any expression (functions, operators, etc. that can return an array. In case it returns a simple value (non-array value), it is converted by the expression conversion mechanism to a single element array.

Looping can be stopped earlier (if needed) by EXIT statement.

Examples:

/* simple sum function */

DECLARE

@sum = 0;

BEGIN

FOREACH @elm IN

array (

{{data:Signals.RampSlow}},

{{data:Signals.RampFast}},

{{data:Signals.RandomFast}})

LOOP

SET @sum = @sum + @elm;

END

SET @@ = @sum;

END

Or without using explicitly declared variable:

BEGIN

FOREACH @elm IN

array (

{{data:Signals.RampSlow}},

{{data:Signals.RampFast}},

{{data:Signals.RandomFast}})

LOOP

SET @@ = @@ + @elm;

END

END

With Exit statement:

BEGIN

FOREACH @elm IN

array (

{{data:Signals.RampSlow}},

{{data:Signals.RampFast}},

{{data:Signals.RandomFast}})

LOOP

SET @@ = @@ + @elm;

EXIT WHEN @@ > 100;

END

END

FOR COMMAND

The FOR loop is always looping between specified numbers and optionally allows for specifying direction and step values. Loop values (from, to, step) are read before looping starts, thus any changes to these parameters via internal variables won’t take any effect to actual loop. Looping can be stopped earlier (if needed) by EXIT statement.

Syntax is:

FOR counter_variable IN [REVERSE] lowest_number..highest_number [STEP value]

LOOP

/* code lines */

END

Where counter_variable is an internal variable, which is declared by FOR statement – i.e. doesn’t need to be explicitly declared. This variable is known inside the loop body only and contains current counter value. The lowest and highest numbers determine the FORloop range. To start looping, the lowest number must contain a lower value than the highest number. When REVERSE is specified, then it starts looping from the highest number and ends in the lowest value. STEP is followed by a numeric value that specifies the increment value used in FOR loop. The default value is 1.

Examples (without code block):

FOR @i IN 1..10

LOOP

/* values in variable @i will be: 1,2,3,4,5,6,7,8,9,10 */

@@ = @@ + @i;

END

/*********************************************************/

FOR @i IN REVERSE 1..10

LOOP

/* values in variable @i will be: 10,9,8,7,6,5,4,3,2,1 */

@@ = @@ + @i;

END

/*********************************************************/

FOR @i IN 1..10 STEP 3

LOOP

/* values in variable @i will be: 1,4,7,10 */

@@ = @@ + @i;

END

/*********************************************************/

FOR @i IN REVERSE 1..10 STEP 3

LOOP

/* values in variable @i will be: 10,7,4,1 */

@@ = @@ + @i;

END

FOR loop can use internal/external variables in place of lowest/highest and step numbers. See full examples below:

/*********************************************************/

DECLARE

@a = 0;

BEGIN

  FOR @i IN {{data:Signals.RampSlow}}..{{data:Signals.RampFast}}

  LOOP

    SET @a =

IF {{data:Signals.RampSlow}} > 50

THEN @a + @i

ELSE @a - @i;  

            

  END

  SET @@ = @a;

END

/*********************************************************/

DECLARE

@array; @a;

BEGIN

SET @@ = 0;

SET @array = array({{var_a}}, {{var_b}}, {{var_c}});

FOR @i IN 0 .. (len(@array) - 1)

LOOP

SET @a = getat(@array, @i);

IF @a > 0 THEN SET @@ = @@ + @a;

END

END

IF AND IFQ STATEMENTS

IF statements can be used directly in code blocks. Their behavior is very similar to IF used in standard expression text. The only difference is that THEN and ELSE values are not expressions, but either a code line or another code block. The ELSE section is optional.

Syntax is:

IF Boolean_condition THEN code_block [ELSE code_block]

Examples:

BEGIN

IF {{my variable}} > 0 THEN

EXIT;

SET @@ = {{my variable}};

END

/*********************************************************/

BEGIN

IF {{my variable}} > 0 THEN

BEGIN

SET @@ = {{my variable}};

EXIT;

END

SET @@ = “No Value”;

END

CASE-WHEN-THEN STATEMENTS

CASE statements can be used directly in code blocks and their behavior is very similar to CASE statements used in standard expression text. The only difference is that THEN and ELSE values are not expressions, but either code lines or another code block. The ELSE section is optional.

Notes

Loops with eventually infinite end are intentionally unsupported (e.g. while loop). This is because it can quite easily create an infinite loop, which can be very difficult to find (e.g, in a GraphWorX64 display with thousands of expressions). Instead, a FOR statement, in combination with an EXIT statement, can be used. A FOR loop always requires specification of the maximum number of iterations (can be multiples of expected iterations). Loops should be always used with care. They can quite easily create extremely long evaluations (with thousands of evaluation steps), which may eventually block the whole application.

See Also:

Expression Editor

Switch Statement