Expressions¶
Indigo has several builders of expressions (here generically called operators) and statements employing them. This appendix is meant to list the former and present the latter.
This will not explain the basics of expressions, because this is already the argument of some tutorial's chapters. In particular, if you haven't already, please read the tutorial's chapter about Expressions and operators.
As a reminder, for informations on types you can instead consult their reference material.
Consulting the operators' tables¶
All operators listed in the following tables can have a certain amount of argument expressions and will always return a single resulting expression.
As a reminder the most basic expressions are the constant ones, for example you
can write True
or 42 int
in your contract code and know that these are expressions
of type Bool
or Integer
, respectively.
Much like constants some of the following operators can be used on their own,
because they have no inputs. For example, sender
takes no arguments and is an
expression of type Address
.
However most operators have one or more inputs, in which case you can use them by writing the operator followed by its arguments, each separated by spaces. For example, these are valid expressions:
abs (1 int)
(abs
takes 1 argument expression of typeInteger
)pair () True
(pair
takes 2 of any type instead)
Infix operators are all the ones that take 2 arguments and are made of symbols
(as opposed to letters) and as such they are used between their arguments and not
before them (e.g. 1 + 2
, True || False
, etc.)
Many infix operator have a synonym prefix form, in which case you'll find them
specified in the same row (e.g. add
and +
).
Compound operators are also infix, but are special in that they:
- do require the first argument to be a variable
- will replace the value of the variable with the result of the expression
- do not return an expression, but a complete statement For example:
1 int += 2 int -- is invalid, this will not compile
a <- new$ 1 int
a += 2 int -- "a" will have value of "3" after this expression
b <- new$ a += 1 int -- is also invalid, because "(a += b)" is not an expression
Type variables are used in the types of these tables as well, you can recognize them because they start with a lower-case letter.
Unless differently specified, they can be replaced by any other type, however remember that if the same variable is used in a line this means its type is the same everywhere it is used.
For example, if an operator says to accept an expression of type [a]
as an input
and return one of type a
, it means it can operate on a list of any type and will
return a single element, but of that same type (e.g. take a [Integer]
and return
an Integer
, or a [Natural]
and return a Natural
, but not take [Integer]
and return a Natural
).
You'll notice also that some operators are overloaded, so you'll find them in
multiple places, operating on and returning different types.
For example you can sum 2 Natural
s with +
as well as 2 Integer
s.
Logical sections¶
Starting right below are the operators and statements for Indigo.
They are grouped in sections based on the logic they execute.
Arithmetic¶
Operators¶
Operator | Infix | Input type I | Input type II | Result type | Compound | Description |
---|---|---|---|---|---|---|
add |
+ |
Natural |
Integer |
Integer |
Sums the two values | |
add |
+ |
Integer |
Natural |
Integer |
+= |
Sums the two values |
add |
+ |
Natural |
Natural |
Natural |
+= |
Sums the two values |
add |
+ |
Integer |
Integer |
Integer |
+= |
Sums the two values |
add |
+ |
Timestamp |
Integer |
Timestamp |
+= |
Increments/decrements the Timestamp by the given number of seconds |
add |
+ |
Integer |
Timestamp |
Timestamp |
Increments/decrements the Timestamp by the given number of seconds |
|
add |
+ |
Mutez |
Mutez |
Mutez |
+= |
Sums the two values |
sub |
- |
Natural |
Integer |
Integer |
Subtracts the second value from the first | |
sub |
- |
Integer |
Natural |
Integer |
-= |
Subtracts the second value from the first |
sub |
- |
Natural |
Natural |
Integer |
Subtracts the second value from the first | |
sub |
- |
Integer |
Integer |
Integer |
-= |
Subtracts the second value from the first |
sub |
- |
Timestamp |
Integer |
Timestamp |
-= |
Subtracts a number of seconds from the Timestamp |
sub |
- |
Timestamp |
Timestamp |
Integer |
Subtracts the second value from the first | |
sub |
- |
Mutez |
Mutez |
Mutez |
-= |
Subtracts the second value from the first |
mul |
* |
Natural |
Integer |
Integer |
Multiplies the two values | |
mul |
* |
Integer |
Natural |
Integer |
*= |
Multiplies the two values |
mul |
* |
Natural |
Natural |
Natural |
*= |
Multiplies the two values |
mul |
* |
Integer |
Integer |
Integer |
*= |
Multiplies the two values |
mul |
* |
Natural |
Mutez |
Mutez |
Multiplies the two values | |
mul |
* |
Mutez |
Natural |
Mutez |
*= |
Multiplies the two values |
div |
/ |
Integer |
Integer |
Integer |
Divides the first value by the second | |
div |
/ |
Integer |
Natural |
Integer |
Divides the first value by the second | |
div |
/ |
Natural |
Integer |
Integer |
Divides the first value by the second | |
div |
/ |
Natural |
Natural |
Natural |
Divides the first value by the second | |
div |
/ |
Mutez |
Mutez |
Natural |
Divides the first value by the second | |
div |
/ |
Mutez |
Natural |
Mutez |
Divides the first value by the second | |
mod |
% |
Integer |
Integer |
Natural |
Modulo of the first value by the second | |
mod |
% |
Integer |
Natural |
Natural |
Modulo of the first value by the second | |
mod |
% |
Natural |
Integer |
Natural |
Modulo of the first value by the second | |
mod |
% |
Natural |
Natural |
Natural |
Modulo of the first value by the second | |
mod |
% |
Mutez |
Mutez |
Mutez |
Modulo of the first value by the second | |
mod |
% |
Mutez |
Natural |
Mutez |
Modulo of the first value by the second | |
neg |
Integer |
Integer |
Negates the input value | |||
neg |
Natural |
Integer |
Negates the input value | |||
abs |
Integer |
Natural |
Absolute value of the input |
Comparison¶
NOTE: the comparable
type variable in this section can be replaced only by a type that
can be compared and not any arbitrary type, for more information see
tezos's documentation.
Operators¶
Operator | Infix | Input type I | Input type II | Result type | Description |
---|---|---|---|---|---|
eq |
== |
comparable |
comparable |
Bool |
Equal to |
neq |
/= |
comparable |
comparable |
Bool |
Not equal to |
le |
<= |
comparable |
comparable |
Bool |
Less than or equal to |
ge |
>= |
comparable |
comparable |
Bool |
Greater than or equal to |
lt |
< |
comparable |
comparable |
Bool |
Less than |
gt |
> |
comparable |
comparable |
Bool |
Greater than |
Bits and boolean¶
Operators¶
Operator | Infix | Input type I | Input type II | Result type | Compound | Description |
---|---|---|---|---|---|---|
lsl |
<<< |
Natural |
Natural |
Natural |
<<<= |
Bitwise left shift |
lsr |
>>> |
Natural |
Natural |
Natural |
>>>= |
Bitwise right shift |
and |
&& |
Integer |
Natural |
Natural |
Bitwise and |
|
and |
&& |
Natural |
Natural |
Natural |
&&= |
Bitwise and |
and |
&& |
Bool |
Bool |
Bool |
&&= |
Boolean and |
or |
|| |
Natural |
Natural |
Natural |
||= |
Bitwise or |
or |
|| |
Bool |
Bool |
Bool |
||= |
Boolean or |
xor |
^ |
Natural |
Natural |
Natural |
^= |
Bitwise xor |
xor |
^ |
Bool |
Bool |
Bool |
^= |
Boolean xor |
not |
Integer |
Integer |
Bitwise complement | |||
not |
Natural |
Integer |
Bitwise complement | |||
not |
Bool |
Bool |
Boolean not |
Serialization¶
Operators¶
Operator | Input type I | Result type | Description |
---|---|---|---|
packRaw |
any |
ByteString |
Serializes a piece of data to its binary representation |
unpackRaw |
ByteString |
Maybe any |
Returns some deserialized piece of data if valid, none otherwise |
pack |
any a |
Packed a |
Type-safer version of packRaw |
unpack |
Packed a |
Maybe a |
Type-safer version of unpackRaw |
Pairs¶
Operators¶
Operator | Input type I | Input type II | Result type | Description |
---|---|---|---|---|
pair |
a |
b |
(a, b) |
Constructs a pair of values |
car |
(a, b) |
a |
Extracts the left-side value from a pair. Synonym of fst . |
|
cdr |
(a, b) |
b |
Extracts the right-side value from a pair. Synonym of snd . |
|
fst |
(a, b) |
a |
Extracts the left-side value from a pair. Synonym of car . |
|
snd |
(a, b) |
b |
Extracts the right-side value from a pair. Synonym of cdr . |
Maybe¶
Operators¶
Operator | Input type I | Result type | Description |
---|---|---|---|
some |
a |
Maybe a |
Wraps a value in a some |
none |
Maybe a |
Creates a none |
Either¶
Operators¶
Operator | Input type I | Result type | Description |
---|---|---|---|
right |
a |
Either b a |
Wraps a value in a right |
left |
b |
Either b a |
Wraps a value in a left |
Conversion¶
Operators¶
Operator | Input type I | Result type | Description |
---|---|---|---|
isNat |
Integer |
Maybe Natural |
Converts an Integer to some Natural if possible, none otherwise |
toInt |
Natural |
Integer |
Converts a Natural to an Integer |
nonZero |
Integer |
Maybe Integer |
Returns some of the given value if it is not 0 , none otherwise. |
nonZero |
Natural |
Maybe Natural |
Returns some of the given value if it is not 0 , none otherwise. |
coerce |
a |
b |
Safely converts between two types that have the same Michelson representation and are explicitely cleared for conversion. |
forcedCoerce |
a |
b |
Forcefully converts between any two types that have the same Michelson representation. |
Bytes and String¶
Operators¶
Operator | Infix | Input type I | Input type II | Result type | Description |
---|---|---|---|---|---|
slice |
(Natural, Natural) |
MText |
Maybe MText |
Returns some sub-string by the given (offset, length) pair if one exists, none otherwise |
|
slice |
(Natural, Natural) |
ByteString |
Maybe ByteString |
Returns some sub-bytestring by the given (offset, length) pair if one exists, none otherwise |
|
concat |
<> |
MText |
MText |
MText |
String concatanation, the first value is pre-pended to the second one |
concat |
<> |
ByteString |
ByteString |
ByteString |
Byte-strings concatanation, the first value is pre-pended to the second one |
List¶
Operators¶
Operator | Infix | Input type I | Input type II | Result type | Description |
---|---|---|---|---|---|
cons |
.: |
a |
[a] |
[a] |
Prepends/cons the given value to the given list |
concatAll |
[MText] |
MText |
Concatenates all the strings in the list into a single one | ||
concatAll |
[ByteString] |
ByteString |
Concatenates all the bytestrings in the list into a single one | ||
size |
[a] |
Natural |
Returns the size of the given list | ||
nil |
[a] |
Creates an empty list |
Set¶
Operators¶
Operator | Input type I | Input type II | Result type | Description |
---|---|---|---|---|
!: |
Set a |
(a, Bool) |
Set a |
If the Bool is True it inserts the given value in the set, otherwise it remove it. |
+: |
Set a |
a |
Set a |
Inserts the given value into the set |
-: |
Set a |
a |
Set a |
Removes the given value from the set |
?: |
Set a |
a |
Bool |
Checks for the presence of the given value in the set |
update |
(a, Bool) |
Set a |
Set a |
If the Bool is True it inserts the given value in the set, otherwise it remove it. |
insert |
a |
Set a |
Set a |
Inserts the given value into the set |
remove |
a |
Set a |
Set a |
Removes the given value from the set |
mem |
a |
Set a |
Bool |
Checks for the presence of the given value in the set |
size |
Set a |
Natural |
Returns the size of the given set | |
empty |
Set a |
Creates an empty set | ||
emptySet |
Set a |
Alias for empty to resolve ambiguousness in some cases |
Map¶
Operators¶
Operator | Input type I | Input type II | Result type | Description |
---|---|---|---|---|
#: |
Map k v |
k |
Maybe v |
Looks up the key in the map and returns its value in some if found, none otherwise |
!: |
Map k v |
(k, Maybe v) |
Map k v |
Updates the value associated to a key in a map. Inserts/replaces it with a value in some or removes it with none . |
+: |
Map k v |
(k, v) |
Map k v |
Inserts the value associated to a key in a map. If there was one already, this gets overridden |
-: |
Map k v |
k |
Map k v |
Removes the value associated to a key in a map |
?: |
Map k v |
k |
Map k v |
Checks for the presence of the given key in the map |
get |
k |
Map k v |
Maybe v |
Looks up the key in the map and returns its value in some if found, none otherwise |
update |
(k, Maybe v) |
Map k v |
Map k v |
Updates the value associated to a key in a map. Inserts/replaces it with a value in some or removes it with none . |
insert |
(k, v) |
Map k v |
Map k v |
Inserts the value associated to a key in a map. If there was one already, this gets overridden |
remove |
k |
Map k v |
Map k v |
Removes the value associated to a key in a map |
mem |
k |
Map k v |
Bool |
Checks for the presence of the given key in the map |
size |
Map k v |
Natural |
Returns the size of the given map | |
empty |
Map k v |
Creates an empty map | ||
emptyMap |
Map k v |
Alias for empty to resolve ambiguousness in some cases |
BigMap¶
Operators¶
Operator | Input type I | Input type II | Result type | Description |
---|---|---|---|---|
#: |
BigMap k v |
k |
Maybe v |
Looks up the key in the bigMap and returns its value in some if found, none otherwise |
!: |
BigMap k v |
(k, Maybe v) |
BigMap k v |
Updates the value associated to a key in a bigMap. Inserts/replaces it with a value in some or removes it with none . |
+: |
BigMap k v |
(k, v) |
BigMap k v |
Inserts the value associated to a key in a bigMap. If there was one already, this gets overridden |
-: |
BigMap k v |
k |
BigMap k v |
Removes the value associated to a key in a bigMap |
?: |
BigMap k v |
k |
BigMap k v |
Checks for the presence of the given key in the bigMap |
get |
k |
BigMap k v |
Maybe v |
Looks up the key in the bigMap and returns its value in some if found, none otherwise |
update |
(k, Maybe v) |
BigMap k v |
BigMap k v |
Updates the value associated to a key in a bigMap. Inserts/replaces it with a value in some or removes it with none . |
insert |
(k, v) |
BigMap k v |
BigMap k v |
Inserts the value associated to a key in a bigMap. If there was one already, this gets overridden |
remove |
k |
BigMap k v |
BigMap k v |
Removes the value associated to a key in a bigMap |
mem |
k |
BigMap k v |
Bool |
Checks for the presence of the given key in the bigMap |
size |
BigMap k v |
Natural |
Returns the size of the given bigMap | |
empty |
BigMap k v |
Creates an empty bigMap | ||
emptyBigMap |
BigMap k v |
Alias for empty to resolve ambiguousness in some cases |
Constructor¶
Note
To wrap
/unwrap
a value in a constructor the type (here sumType
) needs
to have multiple constructors, all with a single field each, see types.
Note
Just like we have seen in the statements chapter to
identify a constructor (e.g. First
) we need a label prepended with a c
(e.g. #cFirst
).
Operators¶
Operator | Input type I | Input type II | Result type | Description |
---|---|---|---|---|
wrap |
Label |
field |
sumType |
Creates a sumType from the constructor specified by the given Label and a value for its field |
unwrap |
Label |
sumType |
field |
Retrieves the value from the field of the sumType constructor specified by the given Label |
Record¶
Operators¶
Operator | Input type I | Input type II | Result type | Description |
---|---|---|---|---|
!! |
record |
(Label, field) |
record |
Sets the record field for the given Label to the given value |
#! |
record |
Label |
field |
Retrieves the value associated with the given Label from the record |
name |
Label |
field |
record |
Creates a record with one field, set to the given value, associated with the given Label |
unName |
Label |
record |
field |
Retrieves the value associated with the given Label from the record that has only one field |
!~ |
field |
Label |
record |
Creates a record with one field, set to the given value, associated with the given Label |
#~ |
record |
Label |
field |
Retrieves the value associated with the given Label from the record that has only one field |
construct |
(record, record, ...) |
record |
Creates a bigger record starting from a tuple of smaller ones |
Auxiliary¶
Operators¶
Operator | Input type I | Input type II | Input type III | Result type | Description |
---|---|---|---|---|---|
checkSignature |
PublicKey |
Signature |
ByteString |
Bool |
Checks that the given bytestring has been signed the given key |
blake2b |
bs (e.g. ByteString ) |
Hash Blake2b bs |
Returns the cryptographic hash of the given value using the blake2b hash function |
||
sha256 |
bs (e.g. ByteString ) |
Hash Sha256 |
Returns the cryptographic hash of the given value using the sha256 hash function |
||
sha512 |
bs (e.g. ByteString ) |
Hash Sha512 |
Returns the cryptographic hash of the given value using the sha512 hash function |
||
sha3 |
bs (e.g. ByteString ) |
Hash Sha3 |
Returns the cryptographic hash of the given value using the sha3 hash function |
||
keccak |
bs (e.g. ByteString ) |
Hash Keccak |
Returns the cryptographic hash of the given value using the keccak hash function |
||
hashKey |
PublicKey |
KeyHash |
Returns the b58check of the public key |
||
now |
Timestamp |
The current time | |||
amount |
Mutez |
Amount of the current transaction | |||
sender |
Address |
Address that initiated the current transaction | |||
chainId |
ChainId |
The chain identifier | |||
balance |
Mutez |
Current balance held by the executing contract | |||
level |
Natural |
ID of the block that the current transaction is included into | |||
votingPower |
KeyHash |
Natural |
Voting power of the given baker | ||
totalVotingPower |
Natural |
Overall voting power of all the bakers |
Never¶
Operators¶
Operator | Input type I | Input type II | Result type | Description |
---|---|---|---|---|
never |
Never |
Marks the current execution branch as impossible |
Contract¶
As a reminder chapter 05 explains and shows with an example how to use the result of the following operators and statements to perform side effects.
Operators¶
Operator | Input type I | Result type | Description |
---|---|---|---|
contract |
Address |
Maybe (ContractRef param) |
Casts the address to some ContractRef param if possible, none otherwise |
implicitAccount |
KeyHash |
ContractRef () |
Returns a default contract with the given public/private key pair, which cannot execute code |
contractAddress |
ContractRef p |
Address |
Cast the given ContractRef param to its Address |
contractCallingString |
MText |
Address |
Make an unsafe reference to a contract from the given entrypoint |
self |
ContractRef param |
ContractRef param of the current contract |
|
selfAddress |
Address |
Address of the current contract. When in a lambda - refers to the contract eventually executing it. |
Statements¶
For improved type safety Indigo internally uses some types in addition to
Address
and ContractRef param
(the only ones listed in Appendix A: types).
Among these types the only one necessary to use the following statements is
EntrypointRef mname
.
As the name might suggest this is an identifier for the entrypoint we want to
call, there are two possibile choices for it:
- CallDefault
for the default entrypoint of a contract
- Call @"<entrypointname>"
where <entrypointname>
is the name of the entrypoint
we want to call
selfCalling
is a statement that returns a ContractRef param
variable given an
EntrypointRef mname
for the contract is executed in.
For example, supposing we want to use this statement in the example controlContract
of chapter 03, which defines its parameter type IncrementIf
with entrypoints
IsZero
and HasDigitOne
, each of the following is a valid use:
contractRef <- selfCalling CallDefault
contractRef <- selfCalling Call @"IsZero"
contractRef <- selfCalling Call @"HasDigitOne"
contractCalling
is just like selfCalling
, except it points at a different contract
and because of this it also needs an expression for its address.
For example, supposing this time we want to call the controlContract
above from
a different one (and that we already have a ccAddr
variable for it), each of
the following is a valid use:
mContractRef <- contractCalling CallDefault ccAddr
mContractRef <- contractCalling (Call @"IsZero") ccAddr
mContractRef <- contractCalling (Call @"HasDigitOne") ccAddr
Note that another difference with selfCalling
is that it returns
Maybe (ContractRef param)
because it may fail to lookup the contract and return
none
.
view
s and void
s¶
Operators¶
Operator | Input type I | Input type II | Result type | Description |
---|---|---|---|---|
makeView |
a |
ContractRef param |
View a param |
Creates a View entrypoint parameter |
makeVoid |
a |
Lambda param param |
Void_ a param |
Creates a Void_ entrypoint parameter |
Statements¶
The view_
statement allows to implement a View
entrypoint by using a function.
For example, let's say we have a contract that takes a View Integer Bool
param
for an entrypoint we could implement it like this:
-- previous contract code to select the entrypoint
view_ greaterThan0 param
greaterThan0 :: Var Integer -> IndigoFunction Bool
greaterThan0 val = defFunction do
return (val >. 0 int)
As you can see we only need the function to take an Integer
as parameter and
return a Bool
to satisfy the View Integer Bool
requirement.
Another way to do so is by using the project
statements, which is like view_
with the arguments inverted. This may seem pointless, but allows to define the
function in place, so the previous example could be written as:
-- previous contract code to select the entrypoint
project param $ \val ->
return (val > 0 int)
This is more compact and does not require the definition of a specific function.
Just like for View
s there are statements for Void
s that work in a matching
way to the ones above: void_
and projectVoid
.
Conditional¶
Statements¶
The most common conditional statement is the if ... then ... else ...
construct.
This specifies two branches of code to execute based on a Bool
condition.
Note that the branches can return a value, in which case this can be captured as
a variable, but both branches need to return the same type.
For example, these are valid statements:
if 1 int <= 2 int
then do
storage =: 1 int -- this will be executed
return ()
else do
return () -- this will not
resVal <- if 1 int == 2 int
then do
return False
else do
a <- new$ 1 int == 1 int
return a
-- we can now use the `resVal` `Bool` variable
From the first example statement above you can see than in its second branch we
do not do anything (return ()
), for these cases Indigo has a convenience statement
called when
that only takes the Bool
condition and a single branch, that will
be executed only if the condition is True
.
The first statement above could so be rewritten as:
when (1 int <= 2 int) do
storage =: 1 int
In other cases we might want to do exactly the opposite and execute some code
only when a Bool
condition is False
.
Indigo has a convenience statement for this too, called unless
.
The previous example for instance could also be written as:
unless (1 int > 2 int) do
storage =: 1 int
When we have to deal with Maybe a
s we often want to know if they are some a
or none
and execute a different code in each case.
For this reason Indigo has the ifSome
statement, that based on a Maybe a
it
executes one of its two branches.
The first branch is executed in case the value is some a
and takes that a
as an
input, the second one takes no input and is executed if the value is none
For example, let's suppose to have a val
variable containing some 1
of type
Maybe Integer
, these would be a valid statement:
ifSome val
(\n -> storage =: n)
(return ())
Just as for if
we can have both branches return a value and assign it to a
variable.
We have the reverse of ifSome
as well, ifNone
, whose first branch is executed only
when the value is none
and second branch is executed in case the value issome a
and
takes that a
as an input.
We also two have statements similar to when
for convenience:
- whenSome
whose single branch is executed only if the value is some a
- whenNone
whose single branch is executed only if the value is none
Similar to Maybe
we also have conditional statement that work with Either
as well:
- ifRight
whose:
- first branch is executed only if the value is right a
and takes a
as input
- second branch is executed in case the value is left b
and takes b
as an input
- ifLeft
which is the reverse of ifRight
- whenRight
whose single branch is executed only if the value is right a
- whenLeft
whose single branch is executed only if the value is left b
We also have another conditional statement that works with List a
which is ifCons
whose:
- first branch is executed only if the value is not an empty list and takes the first
element a
and the rest of the elements List a
as inputs
- second branch is executed only if the value is an empty list
Loop¶
Statements¶
while
is the statement that will execute a piece of code as long as a Bool
condition holds. For example, this loop would execute twice:
i <- new$ 0 int
while (i int < 2 int) do
-- more code can be here
i += 1 int
-- the code following will get executed after the loop
i =: 0 int
whileLeft
is another statement that will execute a function as long as the
condition is a Left a
and the function will take a
as the argument. The
statement will exit the loop when the condition is a Right b
and return
the b
as the result.
forEach
is instead a way to execute a piece of code over each of the elements
of a container (a list, set or map).
For example, given a numList
variable of type [Integer]
this will compute
the sum of all its elements:
sum <- new$ 0 int
forEach numList $ \number -> do
sum += number
Case¶
Statements¶
case_
is the statement that allows use to pattern-match on the constructors of
a custom data-type to execute a different piece of code depending on the value
of an expression.
To know about what types case_
can be used with, please refer to the
types reference page.
An example of a valid type and case_
usage can be found in the Tutorial's
statements chapter.