Control Flow Statements
Note
While this section is up-to-date and complete, it has to be reformated to be easier on the eyes. All UPPERCASE statement names and code should be changed to lowercase.
STORE _ IN _
The STORE
statement assigns a value to a variable.
Syntax:
1 |
|
Type Conversion Notes:
If the value to be stored is NUMBER and it's to be stored in a TEXT variable,
the value will be converted to text, so 15
will be turned into "15"
. If the
value to be stored is a TEXT value two things can happen. If it contains any
non-numeric characters (for example letters, or more than one minus sign or
more than one decimal point, for example "--1.2"
or "15a"
) the conversion
will fail and 0 will be stored in the NUMBER variable. If the TEXT contains a
proper number, though, for example "-416.419"
or "89"
it will be converted
to its number equivalent and stored in the variable. If a string literal depicting
a number is preceded by leading zeros, these will be trimmed (turning 0005
into 5
, -0002.3
into -2.3
and 00.23
into 0.23
).
IF _ IS _ THEN
The IF
statement evaluates if the condition given is positive. If it is, the code in the positive branch is executed. If it is not, the code in the negative branch is executed (if available). Execution then continues normally.
Syntax:
1 2 3 4 5 |
|
or
1 2 3 |
|
The <CONDITION>
may be a relational operator between two values with the same type:
<NUMBER-VAR or NUMBER> IS <REL-OP-A> <NUMBER-VAR or NUMBER>
<TEXT-VAR or TEXT> IS <REL-OP-A> <TEXT-VAR or TEXT>
<NUMBER LIST> IS <REL-OP-B> <NUMBER LIST>
<TEXT LIST> IS <REL-OP-B> <TEXT LIST>
<NUMBER MAP> IS <REL-OP-B> <NUMBER MAP>
<TEXT MAP> IS <REL-OP-B> <TEXT MAP>
Possible values of REL-OP-A
:
EQUAL TO
NOT EQUAL TO
GREATER THAN
LESS THAN
GREATER THAN OR EQUAL TO
LESS THAN OR EQUAL TO
Possible values of REL-OP-B
:
EQUAL TO
NOT EQUAL TO
For containers, both values must have the same type. You cannot compare, for example,
a list of lists of numbers
with a list of lists of lists of numbers
or a number map
with a text map
.
The <CONDITION>
may also be a membership operator:
<NUMBER-VAR or NUMBER or TEXT-VAR or TEXT> IN <LIST>
<NUMBER-VAR or NUMBER or TEXT-VAR or TEXT> IN <MAP>
When using a membership operator, if the second value is a list, it checks if the first value is contained within that list. If the second value is a map, however, it checks if the first value is contained within the keys of that map.
The first value must always be a scalar value, you cannot check if, for example, a
map of numbers
is contained within a list of maps of numbers
.
You can also write compound conditions using AND
, OR
and parenthesis:
<CONDITION> AND <CONDITION>
is positive if both conditions are positive<CONDITION> OR <CONDITION>
is positive if any of the conditions is positive( <CONDITION> )
is positive if the condition is positive and it's used to alter the default precedence
The AND
has higher precedence than OR
, and the conditions inside parenthesis will be evaluated first. That means that C1 AND C2 OR C3
is the same as ( C1 AND C2 ) OR C3
, but you can make the OR
evaluate first if you write C1 AND ( C2 OR C3 )
. Mind the spaces surrounding the parenthesis: (<CONDITION>)
is not a
valid condition, while ( <CONDITION> )
is.
Both AND
and OR
perform short-circuit evaluation: If the first operand of an AND is negative the second will not be evaluated and the AND
condition is determined as negative. If the first operand of an OR is positive the second will not be evaluated and the OR
condition is determined as positive.
For example:
1 2 3 4 5 6 7 8 |
|
The names
list is empty, so the length is greater than 0
condition is negative, and the second one is not evaluated (and the execution continues after the END IF
). Thanks to short-circuit evaluation names:0
is not evaluated and we don`t get an index out of range runtime error!
ELSE IF _ IS _ THEN
The ELSE IF
statement is equivalent to writing an IF
statement inside the ELSE
statement of another IF
statement, but shorter. Must be used after an IF statement and before END IF
or ELSE
.
Syntax:
All the different IF
variants of the IF statement apply, just with ELSE
added before them.
Example:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
WHILE _ IS _ DO
The WHILE
statement evaluates if the condition given is positive. While it is, the code between the WHILE
and REPEAT
statements is repeatedly ran.
Syntax:
1 2 3 |
|
The <CONDITION>
that you can use are the same as the IF statement ones.
FOR _ FROM _ TO _ STEP _ DO
The FOR
statement repeatedly run the code in its body a number of times, given a counter
variable, the start
of the range, its end
and a step
.
When the loop starts, start
is assigned to counter
and starts an iteration, evaluating a condition. The condition is counter < end
if step >= 0
and counter > end
if step < 0
. If the condition passes, the code in the body of the FOR
is executed, otherwise the loop will end. After the code is ran the counter
is incremeted by step
and a new iteration is started (checking the condition and so on).
Syntax:
1 2 3 |
|
Example:
1 2 3 4 5 6 7 |
|
FOR EACH _ IN _ DO
The FOR EACH
statement repeatedly run the code in its body for every element in a given LIST
or MAP
. At the start of each iteration an element of the collection is assigned to a variable matching its type. This even works with multicontainers. For example, you can iterate a NUMBER MAP LIST
using a NUMBER MAP
as the iteration variable.
If the collection is a LIST
, its elements will be iterated increasingly from index 0
, while in the case of a MAP
all the elements will be iterated in no particular order.
Info
Starting from LDPL 5 Groovy Gualicho, FOR EACH
iterates over the may keys, instead of its elements. The iteration variable type must thus be TEXT
.
Syntax:
1 2 3 |
|
Example:
1 2 3 4 5 6 7 8 9 10 11 12 |
|
BREAK
The BREAK
statement breaks the execution of the innermost WHILE
, FOR
or FOR EACH
loop. Will throw a compiler error if used outside one.
Syntax:
1 |
|
CONTINUE
The CONTINUE
statement jumps to the next iteration of the innermost WHILE
or FOR
loop. Will throw a compiler error if used outside one.
Syntax:
1 |
|
CALL SUB-PROCEDURE
The CALL SUB-PROCEDURE
statement executes a SUB-PROCEDURE. Once the SUB-PROCEDURE returns, execution continues from the line following the CALL SUB-PROCEDURE
.
Syntax:
1 2 |
|
Or
1 2 |
|
Of course, a SUB-PROCEDURE must be declared somewhere in your program for you to call it.
If the SUB-PROCEDURE you call doesn't have any declared parameters, you must call it without the WITH
keyword, otherwise you must include it and pass all required parameters after it, in the same order declared in the PARAMETERS
section of the SUB-PROCEDURE.
RETURN
The RETURN
statement returns from a SUB-PROCEDURE. Will throw a compiler error if used outside one.
Syntax:
1 |
|
EXIT
The EXIT
statement ends execution of the program.
Syntax:
1 |
|
WAIT _ MILLISECONDS
The WAIT
statement pauses the execution of a program for the given number of milliseconds.
Syntax:
1 |
|
GOTO and LABEL
"If you want to go somewhere, goto is the best way to get there." -- Ken Thompson
The GOTO
statement performs a one-way transfer of control to a line of code marked by a LABEL
statement. In lame man terms, the execution jumps to the line where the wanted LABEL
is found and continues from there.
While maligned by Edsger W. Dijkstra and his cohorts, GOTO
is very useful in many situations. Its reputation is undeserved and mostly perpetuated by people that don't understand the origins of the criticism or how the statement can be used.
You also can't make a COBOL-esque language without GOTO
, so (due to popular request) we've added it to the language.
Syntax:
1 |
|
1 |
|
Hint
Label names follow the naming rules stated in the Identifier Naming Schemes section of this documentation.
Example:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
|
In the output of this program you can see the middle
LABEL and the start of the cool-code
SUB-PROCEDURE are skipped:
1 2 3 |
|
In order to keep GOTO
from turning your source into unmaintainable spaghetti code, both your GOTO
statements and the LABEL
s they jump to have to be declared together in the same sub-procedure or in the main code body of an LDPL program. You can't goto
across sub-procedures or into them, or anything like that.
CREATE STATEMENT _ EXECUTING _
The CREATE STATEMENT
statement lets you add custom statements to LDPL that execute SUB-PROCEDUREs.
Syntax:
1 |
|
The TEXT
describes the new statement syntax and must contain tokens separated by whitespace. Each token can be a keyword, which is a word with A-Z
characters (preferably in English), or "$"
, a character that marks where parameters are passed. At least one keyword token is required and the number of "$"
tokens must be the same as the number of parameters of the SUB-PROCEDURE you pass after EXECUTING
. For example, a valid TEXT
is "DISPLAY $ $ TIMES"
if the SUB-PROCEDURE has exactly two parameters. The SUB-PROCEDURE must be declared before creating the statement.
After a statement is created you can use it like any other LDPL statement in PROCEDURE
sections, just write a line with all the tokens of the TEXT
in the same order but placing values instead of "$"
. The types of the values must be the same as the parameter types of the SUB-PROCEDURE the statement executes following the same order. Using the new statement will produce the same effect as CALL
ing the SUB-PROCEDURE (parameters are passed by reference too).
You can create two different statements with same TEXT
and use both if at least one of the parameter types are different in each SUB-PROCEDURE, because the resulting syntaxes will differ from each other. Using this you can create two versions of the same statements dealing with different parameter types, like the first example shows.
Bear in mind that a line in your program could match more than one statement: If all of them were created with CREATE STATEMENT
, the one that was created first will be executed. If one of the them is a LDPL built-in statement, this will be executed. For example, if you create "DISPLAY $ $ TIMES"
, declare a variable TIMES
and use the line DISPLAY "Hi!" 3 TIMES
, the LDPL DISPLAY
statement will be executed, because the line matches its syntax. This is illustrated in the second example.
Example 1:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
|
Example 2:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
|
CALL EXTERNAL _
Hint
This section talks about external sub-procedure calling for C++ Extensions. If you have not read the section on C++ Extensions yet, ignore this and then come back later.
The CALL EXTERNAL
statement executes a SUB-PROCEDURE defined in an extension to LDPL, typically in C++. It otherwise operates the same as CALL SUB-PROCEDURE
, except that external SUB-PROCEDURES do not receive parameters.
Syntax:
1 |
|
Example:
1 |
|