Control flow
In order to enable non-linear program execution - as many other languages do - ASTER introduces three classical operations that enable controlling flow of the program. These are IF
, WHILE
and FOR
. Looping functions WHILE
and FOR
allow for early exiting or continuing the loop, see Breaking and returning section for details.
Looking closely, one could say that these are functions as well. And that is true - from the syntax and parsing perspective, control flow expressions, and also WITH
, DEFUN
and LOCALS
are functions in the language. The difference is in how they process their arguments. While the “typical” functions like FIND
or SQRT
process their arguments as values, these functions process the actual code, transformed to the AST representation. This gives them “superpowers” and enables creative solutions in what is otherwise a simple scripting language.
IF
IF( <condition> , <eval_ if_true> [, <eval_if_false>] )
Classical conditional construct. Depending on the first argument evaluating to boolean TRUE or FALSE (represented as 'X'
and ' '
respectively) IF will evaluate either it’s second or third argument, which can be any code sequence.
Example
IF(1>2,A="This will not evaluate"); # only condition gets evaluated, IF will return FALSE
IF(1>2,A=1,A=2); # A is now equal 2, IF will return 2
IF(1>0,A=1,A=2); # A is now equal 1, IF will return 1
WHILE
WHILE( <condition> , <evaluated_code> )
Another classical construct known from other languages. It will, in a loop, evaluate the condition and then, if the condition evaluates to TRUE, the code will be evaluated. If the condition evaluates to FALSE, execution will stop immediately. The loop itself evaluates to last executed expression in the evaluated code.
Watch out - it’s easy to create an infinite loop!
Example
# example of a looping (instead of recurrent) implementation of factorial
# note how the control variable X is tested in condition and then
# reduced by 1 in every loop execution, ensuring that the looping finishes eventually
DEFUN("LOOPING_FACTORIAL",("X"),
LOCALS(("R"),
R=1; # initialization done outside the loop
WHILE(X>1, # loop continuation condition
R=R*X; # calculations
X=X-1); # counter decrement, to ensure the loop can stop!
R # this value will be returned by LOCALS block
) # and by consequence, also by the function
)
FOR
FOR( <initialization>, <condition>, <increment>, <evaluated_code> )
This looping construct is more complex and enables writing loops in a more concise way. It will start by evaluating initialization section. Then, similarly to WHILE
it checks the condition, and if it evaluates to TRUE the <evaluated_code>
is executed. After that, <increment>
code is executed and the loop continues, going again to checking the condition. The loop itself evaluates to last executed expression in the evaluated code.
Example
# example of using a FOR loop to create a text representation of
# the data contained in the list
# note that using INDEXES here means that the order
# of the elements listed may be arbitrary
DEFUN("PRINTLIST",("LIST"),
LOCALS(("I","R","J"),
FOR(
I=1;R="";J=INDEXES(LIST), # initialization
I<=COUNT(J), # condition
I=I+1, # increment
(R=R&LIST[J[i]]&",") # evaluated code
);
"[" & SUBSTR(R,0,-1) & "]" # this is executed after loop
) # returning the value after cutting the last comma
);
A=(1,2,3,4);
PRINTLIST(A) # returns list value as [1,2,3,4]