Control
if
The conditional branching instruction if e then i
executes instruction i
if the bool expression e
is true
.
For example, instr1 is executed if expr1 is true
:
if expr1 then
instr1
The instruction to execute when expression expr1 is false
follows the else
keyword:
if expr1 then
instr1
else
instr2
A sequence of instructions is delimited by begin ... end
and instructions are separated by ;
:
if expr1 then begin
instr1;
instr2
end else begin
instr3;
instr4
end
A dangling else
is attached to the last if
. For example in the following expression, the else
branch is attached to if b = 1 then a := 42
instruction:
if a = 1 then
if b = 1 then
a := 42
else
b := 42
That is that it is equivalent to:
/* 'begin end' is optional here, it is to emphasis the logical structure */
if a = 1 then begin
if b = 1 then
a := 42
else
b := 42
end
Note that there is no need for parenthesis in the bool expression; for example:
var max : nat = 0;
if a < b then
max := b
else
max := a
A conditional if
expression is also available.
match with
The match with
instruction, inspired by the Ocaml language, desconstructs a value of enumerated type to extract data from it. Enumerated types are option
, or
, list
, states
and composite type enum
.
Its generic syntactic structure is presented below, given that E1 ... En are the named values of the enumerated type of expr1:
match expr1 with
| E1 -> instr1 /* instruction when expr1 is E1 */
| E2 -> instr2 /* instruction when expr1 is E2 */
/* ... */
| En -> instrn /* instruction when expr1 is En */
end
If one named type Ei is missing, the compiler fails with the message:
Partial match (missing "Ei")
It is possible to escape the enumeration with the _
keyword; for example:
match expr1 with
| E1 -> instr1
| E2 -> instr2
| _ -> instr3 /* instruction when expr1 is E3 or E4 ... or En */
end
Option
An option
value has two named values: some
and none
.
For example, suppose opt
is typed option<string>
:
match opt with
| some(s) -> instr1 /* declares constant 's' typed 'string' in instr1 */
| none -> instr2
end
Or
An or
value has two named values: left
and right
.
For example, suppose o
is typed or<string, nat>
:
match o with
| left(s) -> instr1 /* declares constant 's' typed 'string' in instr1 */
| right(n) -> instr2 /* declares constant 'n' typed 'nat' in instr2 */
end
List
A list
value has two named values: []
for empty list and ::
for recursive composition.
For example, suppose l
is typed list<bytes>
:
match l with
| h::tl -> instr1 /* declares constants h typed 'bytes' and tl typed 'list<bytes' */
| [] -> instr2 /* when l is empty */
end
In the example above, h
is the first element of the list l
, and tl
is the list l
without the first element.
Note that Archetype does not support recursive calls, hence the match
instruction cannot be used to fold a list as in Ocaml; it is rather used to retrieve the first element of a list and manage the case of an empty list. The for
instruction is used to iterate over list elements.
States
Contract's states
may be interrogated with the match
instruction.
Consider the states declaration:
states =
| Pending initial
| Shipped
| Accepted
| Canceled
The following enables acting based on contract's state:
match state with
| Pending -> instr1 /* when in Pending state */
| Shipped -> instr2 /* when in Shipped state */
| Accepted -> instr3 /* when in Accepted state */
| Canceled -> instr4 /* when in Canceled state */
end;
Enumeration
An enum
value has a user-defined list of values.
Consider the following declaration:
enum color =
| RGB<nat * nat * nat>
| Hex<bytes>
| Css<string>
The following enables acting based on color
's values:
match color with
| RGB(rgb) -> instr1 /* declares 'rgb' as a tuple of 3 values typed 'nat' in instr1 */
| Hex(h) -> instr2 /* declares 'h' as a bytes value in instr2 */
| Css(css) -> instr3 /* declares 'css' as a string value in instr3 */
end
for
The for
instruction iterates the elements of a container (set
, list
, map
and asset
).
The generic syntax structure is presented below, given c
is a container:
for e in c do
instr1 /* declares constant element 'e' in instr1 */
done
The type of element e
above depends on the type of the container. See below for more information.
Note that it is not possible to break an iteration. See the fold
builtin for an iteration process with a possiblity to break.
Set
Elements of a set
are iterated in the element's type natural order.
For example, suppose set s
is typed set<string>
:
for e in s do
instr1 /* constant e is typed 'string' and is an element of s */
done
List
Elements of a list
are iterated in the order of the list's construction process. See prepend
and concat
instructions.
For example, suppose list l
is typed list<nat>
:
for e in l do
instr1 /* constant 'e' is typed `nat` */
done
Map
Elements of a map
big_map
or iterable_big_map
are iterated in the natural order of the key.
For example, suppose map m
is typed map<string, bytes>
:
for (k, v) in m do
instr1
end
In the example above:
k
is a key of the map typedstring
v
is the associated value typedbytes
Asset
Elements of a asset
are iterated in the natural order of the asset identifier.
Consider the following visitor
asset declaration identified by login
field:
asset visitor identified by login {
login : address;
fullname : string;
nbvisits : nat = 0
}
The following iterates on the visitor
asset collection:
for log in visitor do
instr1 /* 'log' is the visitor 'login' typed 'address' */
done
Since log
is the iterated visitor's login, visitor data is accessed with []
operator, like for example:
var nbv = visitor[log].nbvisits
while
The while
instruction executes an instruction as long as a condition holds true.
The generic syntax is:
while expr1 do
instr1
done
where expr1 is a bool
typed expression.
For example:
var i = 0;
while i < 20 do
instr1;
i += 1
done
There is no guarantee that the iteration terminates. In such a case the entrypoint fails with a gas exceeded
error.
iter
The iter
instruction iterates over a integer value in a specified range. The generic syntax is:
iter i from expr1 to expr2 do
instr1 /* declares an integer constant 'i' between expr1 and expr2 included */
done
In the instruction above, expr1 and expr2 are expressions typed int
. It does not iterate if expr1 is greater than expr2.
The initial from
value may be omitted, it is then defaulted to 1
:
iter i to expr2 do
instr1 /* declares an integer constant 'i' between 1 and expr2 included */
done