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