Expression statements
The most common type of statement is the expression statement—an expression followed by;.
See the FunC expressions article for details on the allowed expressions.
return statement
The return statement ends function execution and specifies a value to be returned to the function caller. Any statement after the return statement is not executed.
In this example, the return statement instructs the function to halt execution and produce x + 1 as a result.
return executes:
Block statement
A block statement is used to group zero or more statements. The block is delimited by a pair of curly braces{ ... }. A block statement also defines a scope, in which variables defined in the block are accessible only in the block or in nested blocks.
For example:
Conditional statements
These statements control the flow of the code based on a condition.if...else statement
When executing an if...else statement, first, the specified condition is evaluated.
If the condition evaluates to an integer different from 0, see absence of boolean type, the block after the condition is executed. Otherwise, if the condition evaluates to 0, the optional else block is executed.
If the else block is missing, nothing happens, and execution continues further.
Examples:
{} are required in each block of an if...else statement.
For example, the following code will not compile:
else block must have curly brackets:
elseif keyword, to avoid the need to write several nested curly brackets in the else case:
elseif keyword is useful for stating several alternative cases:
elseifnot keyword, which allows the inclusion of ifnot statements in the alternatives:
ifnot...else statement
The ifnot...else statement is equivalent to the if...else statement but with the condition negated using the bitwise ~ operator.
More specifically:
ifnot evaluates to 0, see absence of boolean type, the block after the condition is executed. Otherwise, if the condition evaluates to an integer different from 0, the optional else block is executed.
If the else block is missing, nothing happens, and execution continues further.
Examples:
if...else, it is possible to use the keyword elseifnot to add several alternative cases:
elseif keyword, which allows the inclusion of standard if statements in the alternatives:
Loops
FunC supportsrepeat, while, and do { ... } until loops. The for loop is not supported.
repeat loop
The repeat loop executes a block of code a specified number of times. The number of repetitions should be given as a positive 32-bit integer in the inclusive range from 1 to 2^31 - 1, i.e., 2,147,483,647. If the value is greater, an error with exit code 5, Integer out of expected range, will be thrown.
0 or any negative number in the inclusive range from -2^256 to -1, it is ignored, and the code block is not executed at all.
while loop
The while loop continues executing the block of code as long as the given condition evaluates to an integer different from 0, see absence of boolean type.
do...until loop
The do...until loop is a post-test loop that executes the block of code at least once and then continues to execute it until the given condition evaluates to an integer different from 0, see absence of boolean type.
try...catch statement
Available in FunC since v0.4.0
The try...catch statement consists of a try block and a catch block. The code in the try block is executed first, and if it fails, all changes made within the try block are rolled back, and the catch block is executed instead.
The catch block has two arguments, which are local to the catch block:
- The exception parameter, which can be of any type. Used to provide extra information about the error.
- The error code, an integer, which identifies the kind of error.
try block. These modifications include updates to local and global variables and changes to control registers. For example, c4 for storage, c5for action/messages, c7 for context, etc.
Any contract storage updates and outgoing messages are also reverted.
However, certain TVM state components are not rolled back, such as:
- Codepage settings
- Gas counters
try block is still accounted for, and any modifications carried out by operations that change gas limits (e.g., accept_message or set_gas_limit) will remain in effect.
In this example:
x is incremented to 1 inside the try block, the modification is rolled back due to the exception produced by the throw function. Hence, x has value 0 at the moment the catch block starts execution. However, the gas consumed inside the try block is not rolled back when the catch block starts execution.
Here is an example which illustrates how to generate and use the exception parameter:
throw_arg(-1, 100) produces an exception with error code 100 and exception parameter -1. However, since the exception parameter can be of any type, which may vary depending on the exception, FunC cannot determine its type at compile time in the catch block.
This requires the developer to manually cast the exception parameter. In the example, casting of the exception parameter is achieved with the assembler and polymorphic function cast_to_int, which receives an argument of any type and returns the same argument as an integer by wrapping the NOP (no operation) TVM instruction: