Skip to main content

Control Flow

If Statement

The if statement in Paraflow behaves similarly to other languages, although the syntax may be slightly different. Condition expressions do not need to be surrounded by parentheses, and boolean operators use names rather than symbols (e.g., not, and, or). The relational operators available in conditions include: ==, <>, <, <=, >, >=.

<if-statement> :=
"if" <expression> <*-stmt-block>
{ "else" "if" <expression> <*-stmt-block> }
[ "else" <*-stmt-block> ] }

Note that the if statement may appear in events, rules, and tasks, which each have specific allowed statements, so *-stmt-block corresponds to the appropriate block for the context in which the if appears (i.e., event-stmt-block, rule-stmt-block, or task-stmt-block).

Iteration over range

The foreach and forall loop statements are used to repeat a statement block with an index variable taking values from an integer range.

<range-loop-statement> :=
"foreach" <variable> "in" <expression> <range-operator> <expression> <*-stmt-block>
<range-operator> := "to" | "until"

Break statement

Within foreach loops the break statement will end the execution of the loop immediately. No statements after the break are executed and no further iterations are performed.

<break-statement> := "break" ";"

Return Statement

Events, tasks, and functions may all include a return statement that ends execution of the body and returns data.

The return statement may return scalar values as in:

return 10;

Or

return $sum;

It may also return objects as in:

return { count: $n, $sum };

Objects provide a list of fields and their values. If a variable appears without a field name (like $sum in the example), it is shorthand for a field by the same name as the variable (i.e., sum: $sum in the example).

Catch Block

A task can include a catch block to handle different run-time errors that may occur.

<catch-block> := "catch" "{" <catch-case> {"," <catch-case>} "}"
<case-case> := <exception-type> [ <data-binding> ] "->" <task-stmt-block>

The possible exception types are:

  • RPC_ERROR - error returned from a RPC call
  • DELEGATE_ERROR - error returned by the provider of a skill request
  • APPLICATION_ERROR - exception statement
  • MATCH_ERROR - with statement match error
  • NETWORK_ERROR - any network errors
  • RUNTIME_ERROR - other run-time errors such as invalid operands for an operator
  • MAX_RETRY_ERROR - maximum retries of a retry statement reached

If an exception matches the exception type in the catch block then the matching case body is executed to handle the error. In that case, the error is considered handled and the task goal state will be Complete unless an exception statement is encountered within the case body itself.

A retry statement may also appear within the case body for an NETWORK_ERROR exception.

<retry-statement> := "retry" ["max" <number>] ["after" <duration>];

Exception Statement

The exception statement can be used to cause an exception in a task body. When an exception is encountered, if the task has a catch block with a matching case then that case body will be executed, otherwise the error will be logged and the goal state becomes Failed. If a catch case is matched and executed then the goal state will become Complete unless the catch body itself contains an exception statement.

An exception statement may optionally have a data which can also be matched in the catch block. For example:

task !SomeTask($id, $x) {
if $x == 0 {
exception { severity: 1};
} else {
exception { severity: 2};
}
} catch {
APPLICATION_ERROR { $severity } -> {
log error(`SomeTask error severity $severity`);
if $severity > 1 {
exception;
}
}
}

Goal Updates

The state of a goal may be updated in event and task bodies via the following statements:

<update-goal-statement> :=
"assert" <identifier> <call-bindings> ";" |
"cancel" <identifier> <call-bindings> ";" |
"fail" <identifier> <call-bindings> ";"

The given name and call bindings must match exactly one goal, or a runtime exception will occur. The state of the matched goal is updated as follows:

- `assert`: Changes goal state to complete
- `cancel`: Changes goal state to canceled
- `fail`: Changes goal state to failed

A common use for the goal update statements is when a goal represents an external activity, and its outcome is reported back to Paraflow by an external service using an event.