Merge branch 'rinderknecht@doc' into 'dev'

Fixed the tutorial. Enabled underscores in tez amounts. Fixed docs on tuple components indexation (zero)

See merge request ligolang/ligo!447
This commit is contained in:
Christian Rinderknecht 2020-02-26 20:03:32 +00:00
commit 4886f540e4
57 changed files with 3382 additions and 2766 deletions

View File

@ -1,24 +1,24 @@
---
id: entrypoints-contracts
title: Access function and Entrypoints
title: Main function and Entrypoints
---
## Access Functions
A LIGO contract is made of a series of constant and function
declarations. Only functions having a special type can be called when
the contract is activated: we called them *access functions*. An
access function takes two parameters, the *contract parameter* and the
the contract is activated: we call them *main functions*. A main
function takes two parameters, the *contract parameter* and the
*on-chain storage*, and returns a pair made of a *list of operations*
and a (new) storage.
When the contract is originated, the initial value of the storage is
provided. When an access function is later called, only the parameter
is provided, but the type of an access function contains both.
provided. When a main function is later called, only the parameter is
provided, but the type of a main function contains both.
The type of the contract parameter and the storage are up to the
contract designer, but the type for list operations is not. The return
type of an access function is as follows, assuming that the type
type of a main function is as follows, assuming that the type
`storage` has been defined elsewhere. (Note that you can use any type
with any name for the storage.)
@ -42,13 +42,10 @@ type return = (list (operation), storage);
```
<!--END_DOCUSAURUS_CODE_TABS-->
The contract storage can only be modified by activating an access
function. It is important to understand what that means. What it does
*not* mean is that some global variable holding the storage is
modified by the access function. Instead, what it *does* mean is that,
given the state of the storage *on-chain*, an access function
specifies how to create another state for it, depending on a
parameter.
The contract storage can only be modified by activating a main
function: given the state of the storage *on-chain*, a main function
specifies how to create another state for it, depending on the
contract's parameter.
Here is an example where the storage is a single natural number that
is updated by the parameter.
@ -89,17 +86,18 @@ let main = ((action, store): (parameter, storage)) : return =>
## Entrypoints
In LIGO, the design pattern is to have *one* access function that
dispatches the control flow according to its parameter. Those
functions called for those actions are called *entrypoints*.
In LIGO, the design pattern is to have *one* main function called
`main`, that dispatches the control flow according to its
parameter. Those functions called for those actions are called
*entrypoints*.
As an analogy, in the C programming language, the `main` function is
the unique access function and any function called from it would be an
the unique main function and any function called from it would be an
entrypoint.
The parameter of the contract is then a variant type, and, depending
on the constructors of that type, different functions in the contract
are called. In other terms, the unique access function dispatches the
are called. In other terms, the unique main function dispatches the
control flow depending on a *pattern matching* on the contract
parameter.
@ -128,7 +126,7 @@ function entry_A (const n : nat; const store : storage) : return is
function entry_B (const s : string; const store : storage) : return is
((nil : list (operation)), store with record [name = s])
function access (const action : parameter; const store : storage): return is
function main (const action : parameter; const store : storage): return is
case action of
Action_A (n) -> entry_A (n, store)
| Action_B (s) -> entry_B (s, store)
@ -154,7 +152,7 @@ let entry_A (n, store : nat * storage) : return =
let entry_B (s, store : string * storage) : return =
([] : operation list), {store with name = s}
let access (action, store: parameter * storage) : return =
let main (action, store: parameter * storage) : return =
match action with
Action_A n -> entry_A (n, store)
| Action_B s -> entry_B (s, store)
@ -179,7 +177,7 @@ let entry_A = ((n, store): (nat, storage)) : return =>
let entry_B = ((s, store): (string, storage)) : return =>
(([] : list (operation)), {...store, name : s});
let access = ((action, store): (parameter, storage)) : return =>
let main = ((action, store): (parameter, storage)) : return =>
switch (action) {
| Action_A (n) => entry_A ((n, store))
| Action_B (s) => entry_B ((s, store))
@ -196,8 +194,8 @@ how those built-ins can be utilized.
### Accepting or Declining Tokens in a Smart Contract
This example shows how `amount` and `failwith` can be used to decline
any transaction that sends more tez than `0mutez`, that is, no
This example shows how `Tezos.amount` and `failwith` can be used to
decline any transaction that sends more tez than `0tez`, that is, no
incoming tokens are accepted.
<!--DOCUSAURUS_CODE_TABS-->
@ -208,11 +206,13 @@ type storage is unit
type return is list (operation) * storage
function deny (const action : parameter; const store : storage) : return is
if amount > 0mutez then
if Tezos.amount > 0tez then
(failwith ("This contract does not accept tokens.") : return)
else ((nil : list (operation)), store)
```
> Note that `amount` is *deprecated*.
<!--CameLIGO-->
```cameligo group=c
type parameter = unit
@ -220,11 +220,13 @@ type storage = unit
type return = operation list * storage
let deny (action, store : parameter * storage) : return =
if amount > 0mutez then
(failwith "This contract does not accept tokens.": return)
if Tezos.amount > 0tez then
(failwith "This contract does not accept tokens." : return)
else (([] : operation list), store)
```
> Note that `amount` is *deprecated*.
<!--ReasonLIGO-->
```reasonligo group=c
type parameter = unit;
@ -232,46 +234,56 @@ type storage = unit;
type return = (list (operation), storage);
let deny = ((action, store): (parameter, storage)) : return => {
if (amount > 0mutez) {
if (Tezos.amount > 0tez) {
(failwith("This contract does not accept tokens."): return); }
else { (([] : list (operation)), store); };
};
```
> Note that `amount` is *deprecated*.
<!--END_DOCUSAURUS_CODE_TABS-->
### Access Control
This example shows how `sender` or `source` can be used to deny access to an entrypoint.
This example shows how `Tezos.source` can be used to deny access to an
entrypoint.
<!--DOCUSAURUS_CODE_TABS-->
<!--PascaLIGO-->
```pascaligo group=c
const owner : address = ("tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx": address);
function filter (const action : parameter; const store : storage) : return is
if source =/= owner then (failwith ("Access denied.") : return)
else ((nil : list(operation)), store)
function main (const action : parameter; const store : storage) : return is
if Tezos.source =/= owner then (failwith ("Access denied.") : return)
else ((nil : list (operation)), store)
```
> Note that `source` is *deprecated*.
<!--CameLIGO-->
```cameligo group=c
let owner : address = ("tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx": address)
let filter (action, store: parameter * storage) : return =
if source <> owner then (failwith "Access denied." : return)
let main (action, store: parameter * storage) : return =
if Tezos.source <> owner then (failwith "Access denied." : return)
else (([] : operation list), store)
```
> Note that `source` is *deprecated*.
<!--ReasonLIGO-->
```reasonligo group=c
let owner : address = ("tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx": address);
let access = ((action, store): (parameter, storage)) : storage => {
if (source != owner) { (failwith ("Access denied.") : return); }
let main = ((action, store) : (parameter, storage)) : storage => {
if (Tezos.source != owner) { (failwith ("Access denied.") : return); }
else { (([] : list (operation)), store); };
};
```
> Note that `source` is *deprecated*.
<!--END_DOCUSAURUS_CODE_TABS-->
### Inter-Contract Invocations
@ -329,11 +341,15 @@ const dest : address = ("KT19wgxcuXG9VH4Af5Tpm1vqEKdaMFpznXT3" : address)
function proxy (const action : parameter; const store : storage): return is
block {
const counter : contract (parameter) = get_contract (dest);
const counter : contract (parameter) =
case (Tezos.get_contract_opt (dest) : option (contract (parameter))) of
Some (contract) -> contract
| None -> (failwith ("Contract not found.") : contract (parameter))
end;
(* Reuse the parameter in the subsequent
transaction or use another one, `mock_param`. *)
const mock_param : parameter = Increment (5n);
const op : operation = transaction (action, 0mutez, counter);
const op : operation = Tezos.transaction (action, 0tez, counter);
const ops : list (operation) = list [op]
} with (ops, store)
```
@ -365,14 +381,20 @@ type return = operation list * storage
let dest : address = ("KT19wgxcuXG9VH4Af5Tpm1vqEKdaMFpznXT3" : address)
let proxy (action, store : parameter * storage) : return =
let counter : parameter contract = Operation.get_contract dest in
let counter : parameter contract =
match (Tezos.get_contract_opt (dest) : parameter contract option) with
Some contract -> contract
| None -> (failwith "Contract not found." : parameter contract) in
(* Reuse the parameter in the subsequent
transaction or use another one, `mock_param`. *)
let mock_param : parameter = Increment (5n) in
let op : operation = Operation.transaction action 0mutez counter
let op : operation = Tezos.transaction action 0tez counter
in [op], store
```
> Note that `Operation.get_contract` and `Operation.transaction` are
> *deprecated*.
<!--ReasonLIGO-->
```reasonligo skip
// counter.religo
@ -400,13 +422,20 @@ type return = (list (operation), storage);
let dest : address = ("KT19wgxcuXG9VH4Af5Tpm1vqEKdaMFpznXT3" : address);
let proxy = ((action, store): (parameter, storage)) : return => {
let counter : contract (parameter) = Operation.get_contract (dest);
let counter : contract (parameter) =
switch (Tezos.get_contract_opt (dest) : option (contract (parameter))) {
| Some (contract) => contract;
| None => (failwith ("Contract not found.") : contract (parameter));
};
(* Reuse the parameter in the subsequent
transaction or use another one, `mock_param`. *)
let mock_param : parameter = Increment (5n);
let op : operation = Operation.transaction (action, 0mutez, counter);
let op : operation = Tezos.transaction (action, 0tez, counter);
([op], store)
};
```
> Note that `Operation.get_contract` and `Operation.transaction` are
> *deprecated*.
<!--END_DOCUSAURUS_CODE_TABS-->

View File

@ -11,13 +11,14 @@ We will be implementing a counter contract.
## Dry-running a Contract
Testing a contract can be quite easy if we utilize LIGO's built-in dry
run feature. Dry-run works by simulating the access function
execution, as if it were deployed on a real chain. You need to provide
the following:
run feature. Dry-run works by simulating the main function execution,
as if it were deployed on a real chain. You need to provide the
following:
- `file` - contract to run
- `entrypoint` - name of the function to execute
- `parameter` - parameter passed to the access function (in a theoretical invocation operation)
- `parameter` - parameter passed to the main function (in a
theoretical invocation operation)
- `storage` - a mock storage value, as if it were stored on a real chain
Here is a full example:
@ -33,67 +34,86 @@ ligo dry-run src/basic.ligo main Unit Unit
```
<!--END_DOCUSAURUS_CODE_TABS-->
Output of the `dry-run` is the return value of our access function, we
can see the operations emited - in our case an empty list, and the new
storage value being returned - which in our case is still `Unit`.
Output of the `dry-run` is the return value of our main function, we
can see the operations emitted (in our case an empty list, and the new
storage value being returned) which in our case is still `Unit`.
## A Counter Contract
Our counter contract will store a single `int` as it's storage, and
will accept an `action` variant in order to re-route our single `main`
access function to two entrypoints for `addition` and `subtraction`.
function to two entrypoints for `add` (addition) and `sub`
(subtraction).
<!--DOCUSAURUS_CODE_TABS-->
<!--Pascaligo-->
```
type action is
type parameter is
Increment of int
| Decrement of int
function main (const p : action ; const s : int) : (list(operation) * int) is
type storage is int
type return is list (operation) * storage
function add (const n : int; const store : storage) : storage is store + n
function sub (const n : int; const store : storage) : storage is store - n
function main (const action : parameter; const store : storage) : return is
((nil : list(operation)),
(case p of
| Increment (n) -> s + n
| Decrement (n) -> s - n
end))
case action of
Increment (n) -> add (n, store)
| Decrement (n) -> sub (n, store)
end)
```
<!--CameLIGO-->
```cameligo
type action =
| Increment of int
type parameter =
Increment of int
| Decrement of int
let main (p, s: action * int) : operation list * int =
let result =
match p with
| Increment n -> s + n
| Decrement n -> s - n
in
(([]: operation list), result)
type storage = int
type return = (operation) list * storage
let add (n, store : int * storage) : storage = store + n
let sub (n, store : int * storage) : storage = store - n
let main (action, store : parameter * storage) : operation list * storage =
(([]: operation list),
(match action with
Increment n -> add (n, store)
| Decrement n -> sub (n, store)))
```
<!--ReasonLIGO-->
```reasonligo
type action =
| Increment(int)
| Decrement(int);
type parameter =
Increment (int)
| Decrement (int)
;
let main = (p_s: (action, int)) : (list(operation), int) => {
let p, s = p_s;
let result =
switch (p) {
| Increment(n) => s + n
| Decrement(n) => s - n
};
(([]: list(operation)), result);
};
type storage = int;
type return = (list (operation), storage);
let add = ((n, store) : (int, storage)) : storage => store + n;
let sub = ((n, store) : (int, storage)) : storage => store - n;
let main = ((action, store) : (parameter, storage)) : return =>
(([]: list (operation)),
(switch (action) {
| Increment (n) => add ((n, store))
| Decrement (n) => sub ((n, store))
}));
```
<!--END_DOCUSAURUS_CODE_TABS-->
To dry-run the counter contract, we will use the `main` entrypoint, provide a variant parameter of `Increment(5)` and an initial storage value of `5`.
To dry-run the counter contract, we will provide the `main` function
with a variant parameter of value `Increment (5)` and an initial
storage value of `5`.
<!--DOCUSAURUS_CODE_TABS-->
<!--Pascaligo-->
@ -130,39 +150,30 @@ Command above will output the following Michelson code:
{ parameter (or (int %decrement) (int %increment)) ;
storage int ;
code { DUP ;
CAR ;
DIP { DUP } ;
SWAP ;
CDR ;
DIP { DUP } ;
SWAP ;
CAR ;
IF_LEFT
{ DUP ;
DIP 2 { DUP } ;
DIG 2 ;
DIP { DUP } ;
DIP { DIP { DUP } ; SWAP } ;
PAIR ;
DUP ;
CDR ;
DIP { DUP ; CAR } ;
SUB ;
SWAP ;
DROP ;
SWAP ;
DROP }
DIP { DROP 2 } }
{ DUP ;
DIP 2 { DUP } ;
DIG 2 ;
DIP { DUP } ;
DIP { DIP { DUP } ; SWAP } ;
PAIR ;
DUP ;
CDR ;
DIP { DUP ; CAR } ;
ADD ;
SWAP ;
DROP ;
SWAP ;
DROP } ;
DIP { DROP 2 } } ;
NIL operation ;
PAIR ;
SWAP ;
DROP ;
SWAP ;
DROP ;
SWAP ;
DROP } }
DIP { DROP 2 } } }
```
<!--END_DOCUSAURUS_CODE_TABS-->
@ -179,12 +190,15 @@ ligo compile-storage src/counter.ligo main 5
```
<!--END_DOCUSAURUS_CODE_TABS-->
In our case the LIGO storage value maps 1:1 to its Michelson representation, however this will not be the case once the parameter is of a more complex data type, like a record.
In our case the LIGO storage value maps 1:1 to its Michelson
representation, however this will not be the case once the parameter
is of a more complex data type, like a record.
## Invoking a LIGO contract
Same rules apply for parameters, as apply for translating LIGO storage values to Michelson. We will need to use `compile-parameter` to compile our `action` variant into Michelson, here's how:
Same rules apply for parameters, as apply for translating LIGO storage
values to Michelson. We will need to use `compile-parameter` to
compile our `action` variant into Michelson, here's how:
<!--DOCUSAURUS_CODE_TABS-->
<!--Pascaligo-->
@ -194,6 +208,5 @@ ligo compile-parameter src/counter.ligo main 'Increment(5)'
```
<!--END_DOCUSAURUS_CODE_TABS-->
Now we can use `(Right 5)` which is a Michelson value, to invoke our
contract - e.g. via `tezos-client`
contract - e.g., via `tezos-client`

View File

@ -0,0 +1,17 @@
type parameter is
Increment of int
| Decrement of int
type storage is int
type return is list (operation) * storage
function add (const n : int; const store : storage) : storage is store + n
function sub (const n : int; const store : storage) : storage is store - n
function main (const action : parameter; const store : storage) : return is
((nil : list(operation)),
case action of
Increment (n) -> add (n, store)
| Decrement (n) -> sub (n, store)
end)

View File

@ -0,0 +1,9 @@
function multiply (const a : int; const b : int) : int is
block {
const result : int = a * b
} with result
function add (const a : int; const b : int) : int is a + b
function main (const p : unit; const s : unit) : list (operation) * unit is
((nil : list (operation)), s)

View File

@ -0,0 +1,17 @@
type parameter is
Increment of int
| Decrement of int
type storage is int
type return is list (operation) * storage
function add (const n : int; const store : storage) : storage is store + n
function sub (const n : int; const store : storage) : storage is store - n
function main (const action : parameter; const store : storage) : return is
((nil : list(operation)),
case action of
Increment (n) -> add (n, store)
| Decrement (n) -> sub (n, store)
end)

View File

@ -0,0 +1,5 @@
const four : int = 4
const name : string = "John Doe"
function main (const p : unit; const s : unit) : list (operation) * unit is
((nil : list (operation)), s)

View File

@ -18,23 +18,29 @@ current timestamp value.
<!--DOCUSAURUS_CODE_TABS-->
<!--PascaLIGO-->
```pascaligo group=a
const today : timestamp = now
const today : timestamp = Tezos.now
```
> Note that `now` is *deprecated*.
<!--CameLIGO-->
```cameligo group=a
let today : timestamp = Current.time
let today : timestamp = Tezos.now
```
> Note that `Current.time` is *deprecated*.
<!--ReasonLIGO-->
```reasonligo group=a
let today : timestamp = Current.time;
let today : timestamp = Tezos.now;
```
> Note that `Current.time` is *deprecated*.
<!--END_DOCUSAURUS_CODE_TABS-->
> When running code, the LIGO CLI option
> `--predecessor-timestamp` allows you to control what `now` returns.
> When running code, the LIGO CLI option `--predecessor-timestamp`
> allows you to control what `Tezos.now` returns.
### Timestamp Arithmetics
@ -46,31 +52,37 @@ constraints on your smart contracts. Consider the following scenarios.
<!--DOCUSAURUS_CODE_TABS-->
<!--PascaLIGO-->
```pascaligo group=b
const today : timestamp = now
const today : timestamp = Tezos.now
const one_day : int = 86400
const in_24_hrs : timestamp = today + one_day
const some_date : timestamp = ("2000-01-01T10:10:10Z" : timestamp)
const one_day_later : timestamp = some_date + one_day
```
> Note that `now` is *deprecated*.
<!--CameLIGO-->
```cameligo group=b
let today : timestamp = Current.time
let today : timestamp = Tezos.now
let one_day : int = 86400
let in_24_hrs : timestamp = today + one_day
let some_date : timestamp = ("2000-01-01t10:10:10Z" : timestamp)
let one_day_later : timestamp = some_date + one_day
```
> Note that `Current.time` is *deprecated*.
<!--ReasonLIGO-->
```reasonligo group=b
let today : timestamp = Current.time;
let today : timestamp = Tezos.now;
let one_day : int = 86400;
let in_24_hrs : timestamp = today + one_day;
let some_date : timestamp = ("2000-01-01t10:10:10Z" : timestamp);
let one_day_later : timestamp = some_date + one_day;
```
> Note that `Current.time` is *deprecated*.
<!--END_DOCUSAURUS_CODE_TABS-->
#### 24 hours Ago
@ -78,25 +90,32 @@ let one_day_later : timestamp = some_date + one_day;
<!--DOCUSAURUS_CODE_TABS-->
<!--PascaLIGO-->
```pascaligo group=c
const today : timestamp = now
const today : timestamp = Tezos.now
const one_day : int = 86400
const in_24_hrs : timestamp = today - one_day
```
> Note that `now` is *deprecated*.
<!--CameLIGO-->
```cameligo group=c
let today : timestamp = Current.time
let today : timestamp = Tezos.now
let one_day : int = 86400
let in_24_hrs : timestamp = today - one_day
```
> Note that `Current.time` is *deprecated*.
<!--ReasonLIGO-->
```reasonligo group=c
let today : timestamp = Current.time;
let today : timestamp = Tezos.now;
let one_day : int = 86400;
let in_24_hrs : timestamp = today - one_day;
```
> Note that `Current.time` is *deprecated*.
<!--END_DOCUSAURUS_CODE_TABS-->
### Comparing Timestamps
@ -107,19 +126,26 @@ applying to numbers.
<!--DOCUSAURUS_CODE_TABS-->
<!--PascaLIGO-->
```pascaligo group=c
const not_tommorow : bool = (now = in_24_hrs)
const not_tommorow : bool = (Tezos.now = in_24_hrs)
```
> Note that `now` is *deprecated*.
<!--CameLIGO-->
```cameligo group=c
let not_tomorrow : bool = (Current.time = in_24_hrs)
let not_tomorrow : bool = (Tezos.now = in_24_hrs)
```
> Note that `Current.time` is *deprecated*.
<!--ReasonLIGO-->
```reasonligo group=c
let not_tomorrow : bool = (Current.time == in_24_hrs);
let not_tomorrow : bool = (Tezos.now == in_24_hrs);
```
> Note that `Current.time` is *deprecated*.
<!--END_DOCUSAURUS_CODE_TABS-->
## Addresses

View File

@ -4,7 +4,7 @@ title: Cheat Sheet
---
<div class="cheatsheet">
<!--
<!--
Note that this table is not compiled before production and currently needs to be managed manually.
-->
@ -30,7 +30,7 @@ Note that this table is not compiled before production and currently needs to be
|Includes|```#include "library.ligo"```|
|Functions (short form)|<pre><code>function add (const a : int ; const b : int) : int is<br/>&nbsp;&nbsp;block { skip } with a + b</code></pre>|
|Functions (long form)|<pre><code>function add (const a : int ; const b : int) : int is<br/>&nbsp;&nbsp;block { <br/>&nbsp;&nbsp;&nbsp;&nbsp;const result: int = a + b;<br/>&nbsp;&nbsp;} with result</code></pre>|
| If Statement | <pre><code>if age < 16 <br/>then fail("Too young to drive."); <br/>else const new_id: int = prev_id + 1;</code></pre>|
| If Statement | <pre><code>if age < 16 <br/>then failwith ("Too young to drive."); <br/>else const new_id: int = prev_id + 1;</code></pre>|
|Options|<pre><code>type middleName is option(string);<br/>const middleName : middleName = Some("Foo");<br/>const middleName : middleName = None;</code></pre>|
|Assignment| ```const age: int = 5;```|
|Assignment on an existing variable <br/></br>*⚠️ This feature is not supported at the top-level scope, you can use it e.g. within functions. Works for Records and Maps as well.*| ```age := 18;```, ```p.age := 21``` |
@ -41,7 +41,7 @@ Note that this table is not compiled before production and currently needs to be
|Maps|<pre><code>type prices is map(nat, tez);<br/><br/>const prices : prices = map<br/>&nbsp;&nbsp;10n -> 60mutez;<br/>&nbsp;&nbsp;50n -> 30mutez;<br/>&nbsp;&nbsp;100n -> 10mutez;<br/>end<br/><br/>const price: option(tez) = prices[50n];<br/><br/>prices[200n] := 5mutez;</code></pre>|
|Contracts & Accounts|<pre><code>const destinationAddress : address = "tz1...";<br/>const contract : contract(unit) = get_contract(destinationAddress);</code></pre>|
|Transactions|<pre><code>const payment : operation = transaction(unit, amount, receiver);</code></pre>|
|Exception/Failure|`failwith("Your descriptive error message for the user goes here.")`|
|Exception/Failure|`failwith ("Your descriptive error message for the user goes here.")`|
<!--CameLIGO-->
@ -63,7 +63,7 @@ Note that this table is not compiled before production and currently needs to be
|Types|`type age = int`, `type name = string` |
|Includes|```#include "library.mligo"```|
|Functions |<pre><code>let add (a : int) (b : int) : int = a + b </code></pre>|
| If Statement | <pre><code>let new_id: int = if age < 16 <br/> then failwith("Too young to drive.") <br/> else prev_id + 1</code></pre>|
| If Statement | <pre><code>let new_id: int = if age < 16 <br/> then failwith ("Too young to drive.") <br/> else prev_id + 1</code></pre>|
|Options|<pre><code>type middle_name = string option<br/>let middle_name : middle_name = Some "Foo"<br/>let middle_name : middle_name = None</code></pre>|
|Variable Binding | ```let age: int = 5```|
|Type Annotations| ```("tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx" : address)```|
@ -71,9 +71,9 @@ Note that this table is not compiled before production and currently needs to be
|Variant *(pattern)* matching|<pre><code>let a: action = Increment 5<br/>match a with<br/>&#124; Increment n -> n + 1<br/>&#124; Decrement n -> n - 1<br/></code></pre>|
|Records|<pre><code>type person = {<br/>&nbsp;&nbsp;age: int ;<br/>&nbsp;&nbsp;name: string ;<br/>}<br/><br/>let john : person = {<br/>&nbsp;&nbsp;age = 18;<br/>&nbsp;&nbsp;name = "John Doe";<br/>}<br/><br/>let name: string = john.name</code></pre>|
|Maps|<pre><code>type prices = (nat, tez) map<br/><br/>let prices : prices = Map.literal [<br/>&nbsp;&nbsp;(10n, 60mutez);<br/>&nbsp;&nbsp;(50n, 30mutez);<br/>&nbsp;&nbsp;(100n, 10mutez)<br/>]<br/><br/>let price: tez option = Map.find_opt 50n prices<br/><br/>let prices: prices = Map.update 200n (Some 5mutez) prices</code></pre>|
|Contracts & Accounts|<pre><code>let destination_address : address = "tz1..."<br/>let contract : unit contract = <br/> Operation.get_contract destination_address</code></pre>|
|Transactions|<pre><code>let payment : operation = <br/> Operation.transaction unit amount receiver</code></pre>|
|Exception/Failure|`failwith("Your descriptive error message for the user goes here.")`|
|Contracts & Accounts|<pre><code>let destination_address : address = "tz1..."<br/>let contract : unit contract = <br/> Tezos.get_contract destination_address</code></pre>|
|Transactions|<pre><code>let payment : operation = <br/> Tezos.transaction unit amount receiver</code></pre>|
|Exception/Failure|`failwith ("Your descriptive error message for the user goes here.")`|
<!--ReasonLIGO-->
@ -95,7 +95,7 @@ Note that this table is not compiled before production and currently needs to be
|Types|`type age = int;`, `type name = string;` |
|Includes|```#include "library.mligo"```|
|Functions |<pre><code>let add = (a: int, b: int) : int => a + b; </code></pre>|
| If Statement | <pre><code>let new_id: int = if (age < 16) {<br/> failwith("Too young to drive."); <br/> } else { prev_id + 1; }</code></pre>|
| If Statement | <pre><code>let new_id: int = if (age < 16) {<br/> failwith ("Too young to drive."); <br/> } else { prev_id + 1; }</code></pre>|
|Options|<pre><code>type middle_name = option(string);<br/>let middle_name : middle_name = Some("Foo");<br/>let middle_name : middle_name = None;</code></pre>|
|Variable Binding | ```let age: int = 5;```|
|Type Annotations| ```("tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx" : address)```|
@ -103,9 +103,9 @@ Note that this table is not compiled before production and currently needs to be
|Variant *(pattern)* matching|<pre><code>let a: action = Increment(5);<br/>switch(a) {<br/>&#124; Increment(n) => n + 1<br/>&#124; Decrement(n) => n - 1;<br/> } <br/></code></pre>|
|Records|<pre><code>type person = {<br/>&nbsp;&nbsp;age: int,<br/>&nbsp;&nbsp;name: string<br/>}<br/><br/>let john : person = {<br/>&nbsp;&nbsp;age: 18,<br/>&nbsp;&nbsp;name: "John Doe"<br/>};<br/><br/>let name: string = john.name;</code></pre>|
|Maps|<pre><code>type prices = map(nat, tez);<br/><br/>let prices : prices = Map.literal([<br/>&nbsp;&nbsp;(10n, 60mutez),<br/>&nbsp;&nbsp;(50n, 30mutez),<br/>&nbsp;&nbsp;(100n, 10mutez)<br/>]);<br/><br/>let price: option(tez) = Map.find_opt(50n, prices);<br/><br/>let prices: prices = Map.update(200n, Some (5mutez), prices);</code></pre>|
|Contracts & Accounts|<pre><code>let destination_address : address = "tz1...";<br/>let contract : contract(unit) = <br/> Operation.get_contract(destination_address);</code></pre>|
|Transactions|<pre><code>let payment : operation = <br/> Operation.transaction (unit, amount, receiver);</code></pre>|
|Exception/Failure|`failwith("Your descriptive error message for the user goes here.");`|
|Contracts & Accounts|<pre><code>let destination_address : address = "tz1...";<br/>let contract : contract(unit) = <br/> Tezos.get_contract(destination_address);</code></pre>|
|Transactions|<pre><code>let payment : operation = <br/> Tezos.transaction (unit, amount, receiver);</code></pre>|
|Exception/Failure|`failwith ("Your descriptive error message for the user goes here.");`|
<!--END_DOCUSAURUS_CODE_TABS-->

View File

@ -11,8 +11,8 @@ value:
<!--DOCUSAURUS_CODE_TABS-->
<!--PascaLIGO-->
```pascaligo group=a
const a : bool = True // Notice the capital letter
const b : bool = False // Same.
const a : bool = True // Also: true
const b : bool = False // Also: false
```
<!--CameLIGO-->
```cameligo group=a
@ -137,7 +137,7 @@ state.
type magnitude is Small | Large // See variant types.
function compare (const n : nat) : magnitude is
if n < 10n then Small (Unit) else Large (Unit) // Unit is needed for now.
if n < 10n then Small else Large
```
You can run the `compare` function defined above using the LIGO compiler
@ -145,7 +145,7 @@ like this:
```shell
ligo run-function
gitlab-pages/docs/language-basics/boolean-if-else/cond.ligo compare 21n'
# Outputs: Large (Unit)
# Outputs: Large(Unit)
```
When the branches of the conditional are not a single expression, as
@ -161,7 +161,7 @@ else skip;
```
As an exception to the rule, the blocks in a conditional branch do not
need to be introduced by the keywor `block`, so, we could have written
need to be introduced by the keyword `block`, so we could have written
instead:
```pascaligo skip
if x < y then {
@ -187,9 +187,15 @@ gitlab-pages/docs/language-basics/boolean-if-else/cond.mligo compare 21n'
# Outputs: Large
```
> Notice that, as in OCaml, in CameLIGO, if a conditional has a branch
> `else ()`, that branch can be omitted. The resulting so-called
> *dangling else* problem is parsed by associating any `else` to the
> closest previous `then`.
<!--ReasonLIGO-->
```reasonligo group=e
type magnitude = | Small | Large; // See variant types.
type magnitude = Small | Large; // See variant types.
let compare = (n : nat) : magnitude =>
if (n < 10n) { Small; } else { Large; };

View File

@ -4,7 +4,15 @@ title: Functions
---
LIGO functions are the basic building block of contracts. For example,
entrypoints are functions.
entrypoints are functions and each smart contract needs a main
function that dispatches control to the entrypoints (it is not already
the default entrypoint).
The semantics of function calls in LIGO is that of a *copy of the
arguments but also of the environment*. In the case of PascaLIGO, this
means that any mutation (assignment) on variables outside the scope of
the function will be lost when the function returns, just as the
mutations inside the functions will be.
## Declaring Functions
@ -230,10 +238,14 @@ function to all its elements.
<!--PascaLIGO-->
```pascaligo group=c
function incr_map (const l : list (int)) : list (int) is
list_map (function (const i : int) : int is i + 1, l)
List.map (function (const i : int) : int is i + 1, l)
```
You can call the function `incr_map` defined above using the LIGO compiler
like so:
> Note that `list_map` is *deprecated*.
You can call the function `incr_map` defined above using the LIGO
compiler like so:
```shell
ligo run-function
gitlab-pages/docs/language-basics/src/functions/incr_map.ligo incr_map

View File

@ -79,17 +79,22 @@ let gcd (x,y : nat * nat) : nat =
```
To ease the writing and reading of the iterated functions (here,
`iter`), two predefined functions are provided: `continue` and `stop`:
`iter`), two predefined functions are provided: `Loop.resume` and
`Loop.stop`:
```cameligo group=a
let iter (x,y : nat * nat) : bool * (nat * nat) =
if y = 0n then stop (x,y) else continue (y, x mod y)
if y = 0n then Loop.stop (x,y) else Loop.resume (y, x mod y)
let gcd (x,y : nat * nat) : nat =
let x,y = if x < y then y,x else x,y in
let x,y = Loop.fold_while iter (x,y)
in x
```
> Note that `stop` and `continue` (now `Loop.resume`) are
> *deprecated*.
You can call the function `gcd` defined above using the LIGO compiler
like so:
```shell
@ -131,11 +136,12 @@ let gcd = ((x,y) : (nat, nat)) : nat => {
```
To ease the writing and reading of the iterated functions (here,
`iter`), two predefined functions are provided: `continue` and `stop`:
`iter`), two predefined functions are provided: `Loop.resume` and
`Loop.stop`:
```reasonligo group=b
let iter = ((x,y) : (nat, nat)) : (bool, (nat, nat)) =>
if (y == 0n) { stop ((x,y)); } else { continue ((y, x mod y)); };
if (y == 0n) { Loop.stop ((x,y)); } else { Loop.resume ((y, x mod y)); };
let gcd = ((x,y) : (nat, nat)) : nat => {
let (x,y) = if (x < y) { (y,x); } else { (x,y); };
@ -143,6 +149,10 @@ let gcd = ((x,y) : (nat, nat)) : nat => {
x
};
```
> Note that `stop` and `continue` (now `Loop.resume`) are
> *deprecated*.
<!--END_DOCUSAURUS_CODE_TABS-->
## Bounded Loops

View File

@ -19,7 +19,7 @@ Let us first consider and example of record type declaration.
<!--DOCUSAURUS_CODE_TABS-->
<!--PascaLIGO-->
```pascaligo group=a
```pascaligo group=records1
type user is
record [
id : nat;
@ -29,7 +29,7 @@ type user is
```
<!--CameLIGO-->
```cameligo group=a
```cameligo group=records1
type user = {
id : nat;
is_admin : bool;
@ -38,7 +38,7 @@ type user = {
```
<!--ReasonLIGO-->
```reasonligo group=a
```reasonligo group=records1
type user = {
id : nat,
is_admin : bool,
@ -51,7 +51,7 @@ And here is how a record value is defined:
<!--DOCUSAURUS_CODE_TABS-->
<!--PascaLIGO-->
```pascaligo group=a
```pascaligo group=records1
const alice : user =
record [
id = 1n;
@ -61,7 +61,7 @@ const alice : user =
```
<!--CameLIGO-->
```cameligo group=a
```cameligo group=records1
let alice : user = {
id = 1n;
is_admin = true;
@ -70,7 +70,7 @@ let alice : user = {
```
<!--ReasonLIGO-->
```reasonligo group=a
```reasonligo group=records1
let alice : user = {
id : 1n,
is_admin : true,
@ -86,17 +86,17 @@ operator, like so:
<!--DOCUSAURUS_CODE_TABS-->
<!--PascaLIGO-->
```pascaligo group=a
```pascaligo group=records1
const alice_admin : bool = alice.is_admin
```
<!--CameLIGO-->
```cameligo group=a
```cameligo group=records1
let alice_admin : bool = alice.is_admin
```
<!--ReasonLIGO-->
```reasonligo group=a
```reasonligo group=records1
let alice_admin : bool = alice.is_admin;
```
<!--END_DOCUSAURUS_CODE_TABS-->
@ -123,7 +123,7 @@ In PascaLIGO, the shape of that expression is `<record variable> with
<record value>`. The record variable is the record to update and the
record value is the update itself.
```pascaligo group=b
```pascaligo group=records2
type point is record [x : int; y : int; z : int]
type vector is record [dx : int; dy : int]
@ -151,7 +151,7 @@ the blockless function.
The syntax for the functional updates of record in CameLIGO follows
that of OCaml:
```cameligo group=b
```cameligo group=records2
type point = {x : int; y : int; z : int}
type vector = {dx : int; dy : int}
@ -179,7 +179,7 @@ xy_translate "({x=2;y=3;z=1}, {dx=3;dy=4})"
The syntax for the functional updates of record in ReasonLIGO follows
that of ReasonML:
```reasonligo group=b
```reasonligo group=records2
type point = {x : int, y : int, z : int};
type vector = {dx : int, dy : int};
@ -216,7 +216,7 @@ name "patch").
Let us consider defining a function that translates three-dimensional
points on a plane.
```pascaligo group=c
```pascaligo group=records3
type point is record [x : int; y : int; z : int]
type vector is record [dx : int; dy : int]
@ -242,7 +242,7 @@ Of course, we can actually translate the point with only one `patch`,
as the previous example was meant to show that, after the first patch,
the value of `p` indeed changed. So, a shorter version would be
```pascaligo group=d
```pascaligo group=records4
type point is record [x : int; y : int; z : int]
type vector is record [dx : int; dy : int]
@ -267,7 +267,7 @@ Record patches can actually be simulated with functional updates. All
we have to do is *declare a new record value with the same name as the
one we want to update* and use a functional update, like so:
```pascaligo group=e
```pascaligo group=records5
type point is record [x : int; y : int; z : int]
type vector is record [dx : int; dy : int]
@ -298,71 +298,98 @@ values of the same type. The former are called *key* and the latter
is that the type of the keys must be *comparable*, in the Michelson
sense.
### Declaring a Map
Here is how a custom map from addresses to a pair of integers is
defined.
<!--DOCUSAURUS_CODE_TABS-->
<!--PascaLIGO-->
```pascaligo group=f
```pascaligo group=maps
type move is int * int
type register is map (address, move)
```
<!--CameLIGO-->
```cameligo group=f
```cameligo group=maps
type move = int * int
type register = (address, move) map
```
<!--ReasonLIGO-->
```reasonligo group=f
```reasonligo group=maps
type move = (int, int);
type register = map (address, move);
```
<!--END_DOCUSAURUS_CODE_TABS-->
And here is how a map value is defined:
### Creating an Empty Map
Here is how to create an empty map.
<!--DOCUSAURUS_CODE_TABS-->
<!--PascaLIGO-->
```pascaligo group=maps
const empty : register = map []
```
<!--CameLIGO-->
```cameligo group=maps
let empty : register = Map.empty
```
<!--ReasonLIGO-->
```reasonligo group=maps
let empty : register = Map.empty
```
<!--END_DOCUSAURUS_CODE_TABS-->
### Creating a Non-empty Map
And here is how to create a non-empty map value:
<!--DOCUSAURUS_CODE_TABS-->
<!--PascaLIGO-->
```pascaligo group=f
```pascaligo group=maps
const moves : register =
map [
("tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx" : address) -> (1,2);
("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN" : address) -> (0,3)]
```
> Notice the `->` between the key and its value and `;` to separate
> individual map entries. The annotated value `("<string value>" :
> address)` means that we cast a string into an address. Also, `map`
> is a keyword.
Notice the `->` between the key and its value and `;` to separate
individual map entries. The annotated value `("<string value>" :
address)` means that we cast a string into an address. Also, `map` is
a keyword.
<!--CameLIGO-->
```cameligo group=f
```cameligo group=maps
let moves : register =
Map.literal [
(("tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx" : address), (1,2));
(("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN" : address), (0,3))]
```
> The `Map.literal` predefined function builds a map from a list of
> key-value pair tuples, `(<key>, <value>)`. Note also the `;` to
> separate individual map entries. `("<string value>": address)`
> means that we type-cast a string into an address.
The `Map.literal` predefined function builds a map from a list of
key-value pair tuples, `(<key>, <value>)`. Note also the `;` to
separate individual map entries. `("<string value>": address)` means
that we type-cast a string into an address. -->
<!--ReasonLIGO-->
```reasonligo group=f
```reasonligo group=maps
let moves : register =
Map.literal ([
("tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx" : address, (1,2)),
("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN" : address, (0,3))]);
```
> The `Map.literal` predefined function builds a map from a list of
> key-value pair tuples, `(<key>, <value>)`. Note also the `;` to
> separate individual map entries. `("<string value>": address)`
> means that we type-cast a string into an address.
The `Map.literal` predefined function builds a map from a list of
key-value pair tuples, `(<key>, <value>)`. Note also the `;` to
separate individual map entries. `("<string value>": address)` means
that we type-cast a string into an address. -->
<!--END_DOCUSAURUS_CODE_TABS-->
@ -375,19 +402,19 @@ In PascaLIGO, we can use the postfix `[]` operator to read the `move`
value associated to a given key (`address` here) in the register. Here
is an example:
```pascaligo group=f
```pascaligo group=maps
const my_balance : option (move) =
moves [("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN" : address)]
```
<!--CameLIGO-->
```cameligo group=f
```cameligo group=maps
let my_balance : move option =
Map.find_opt ("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN" : address) moves
```
<!--ReasonLIGO-->
```reasonligo group=f
```reasonligo group=maps
let my_balance : option (move) =
Map.find_opt (("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN" : address), moves);
```
@ -400,7 +427,7 @@ the reader to account for a missing key in the map. This requires
<!--DOCUSAURUS_CODE_TABS-->
<!--PascaLIGO-->
```pascaligo group=f
```pascaligo group=maps
function force_access (const key : address; const moves : register) : move is
case moves[key] of
Some (move) -> move
@ -409,7 +436,7 @@ function force_access (const key : address; const moves : register) : move is
```
<!--CameLIGO-->
```cameligo group=f
```cameligo group=maps
let force_access (key, moves : address * register) : move =
match Map.find_opt key moves with
Some move -> move
@ -417,7 +444,7 @@ let force_access (key, moves : address * register) : move =
```
<!--ReasonLIGO-->
```reasonligo group=f
```reasonligo group=maps
let force_access = ((key, moves) : (address, register)) : move => {
switch (Map.find_opt (key, moves)) {
| Some (move) => move
@ -431,8 +458,7 @@ let force_access = ((key, moves) : (address, register)) : move => {
### Updating a Map
Given a map, we may want to add a new binding, remove one, or modify
one by changing the value associated to an already existing key. We
may even want to retain the key but not the associated value. All
one by changing the value associated to an already existing key. All
those operations are called *updates*.
<!--DOCUSAURUS_CODE_TABS-->
@ -443,7 +469,7 @@ The values of a PascaLIGO map can be updated using the usual
assignment syntax `<map variable>[<key>] := <new value>`. Let us
consider an example.
```pascaligo group=f
```pascaligo group=maps
function assign (var m : register) : register is
block {
m [("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN": address)] := (4,9)
@ -453,7 +479,7 @@ function assign (var m : register) : register is
If multiple bindings need to be updated, PascaLIGO offers a *patch
instruction* for maps, similar to that for records.
```pascaligo group=f
```pascaligo group=maps
function assignments (var m : register) : register is
block {
patch m with map [
@ -463,35 +489,51 @@ function assignments (var m : register) : register is
} with m
```
See further for the removal of bindings.
<!--CameLIGO-->
We can update a binding in a map in CameLIGO by means of the
`Map.update` built-in function:
```cameligo group=f
```cameligo group=maps
let assign (m : register) : register =
Map.update
("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN" : address) (Some (4,9)) m
```
> Notice the optional value `Some (4,9)` instead of `(4,9)`. If we had
> use `None` instead, that would have meant that the binding is
> removed.
Notice the optional value `Some (4,9)` instead of `(4,9)`. If we had
use `None` instead, that would have meant that the binding is removed.
As a particular case, we can only add a key and its associated value.
```cameligo group=maps
let add (m : register) : register =
Map.add
("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN" : address) (4,9) m
```
<!--ReasonLIGO-->
We can update a binding in a map in ReasonLIGO by means of the
`Map.update` built-in function:
```reasonligo group=f
```reasonligo group=maps
let assign = (m : register) : register =>
Map.update
(("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN" : address), Some ((4,9)), m);
```
> Notice the optional value `Some (4,9)` instead of `(4,9)`. If we had
> use `None` instead, that would have meant that the binding is
> removed.
Notice the optional value `Some (4,9)` instead of `(4,9)`. If we had
use `None` instead, that would have meant that the binding is removed.
As a particular case, we can only add a key and its associated value.
```reasonligo group=maps
let add = (m : register) : register =>
Map.add
(("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN" : address), (4,9), m);
```
<!--END_DOCUSAURUS_CODE_TABS-->
@ -503,7 +545,7 @@ To remove a binding from a map, we need its key.
In PascaLIGO, there is a special instruction to remove a binding from
a map.
```pascaligo group=f
```pascaligo group=maps
function delete (const key : address; var moves : register) : register is
block {
remove key from map moves
@ -514,7 +556,7 @@ function delete (const key : address; var moves : register) : register is
In CameLIGO, we use the predefined function `Map.remove` as follows:
```cameligo group=f
```cameligo group=maps
let delete (key, moves : address * register) : register =
Map.remove key moves
```
@ -523,7 +565,7 @@ let delete (key, moves : address * register) : register =
In ReasonLIGO, we use the predefined function `Map.remove` as follows:
```reasonligo group=f
```reasonligo group=maps
let delete = ((key, moves) : (address, register)) : register =>
Map.remove (key, moves);
```
@ -549,34 +591,28 @@ no return value: its only use is to produce side-effects. This can be
useful if for example you would like to check that each value inside
of a map is within a certain range, and fail with an error otherwise.
The predefined functional iterator implementing the iterated operation
over maps is called `Map.iter`. In the following example, the register
of moves is iterated to check that the start of each move is above
`3`.
<!--DOCUSAURUS_CODE_TABS-->
<!--PascaLIGO-->
In PascaLIGO, the predefined functional iterator implementing the
iterated operation over maps is called `map_iter`. In the following
example, the register of moves is iterated to check that the start of
each move is above `3`.
```pascaligo group=f
```pascaligo group=maps
function iter_op (const m : register) : unit is
block {
function iterated (const i : address; const j : move) : unit is
if j.1 > 3 then Unit else (failwith ("Below range.") : unit)
} with map_iter (iterated, m)
} with Map.iter (iterated, m)
```
> The iterated function must be pure, that is, it cannot mutate
> variables.
> Note that `map_iter` is *deprecated*.
<!--CameLIGO-->
In CameLIGO, the predefinded functional iterator implementing the
iterated operation over maps is called `Map.iter`. In the following
example, the register of moves is iterated to check that the start of
each move is above `3`.
```cameligo group=f
```cameligo group=maps
let iter_op (m : register) : unit =
let predicate = fun (i,j : address * move) -> assert (j.0 > 3)
in Map.iter predicate m
@ -584,12 +620,7 @@ let iter_op (m : register) : unit =
<!--ReasonLIGO-->
In ReasonLIGO, the predefined functional iterator implementing the
iterated operation over maps is called `Map.iter`. In the following
example, the register of moves is iterated to check that the start of
each move is above `3`.
```reasonligo group=f
```reasonligo group=maps
let iter_op = (m : register) : unit => {
let predicate = ((i,j) : (address, move)) => assert (j[0] > 3);
Map.iter (predicate, m);
@ -601,32 +632,28 @@ let iter_op = (m : register) : unit => {
We may want to change all the bindings of a map by applying to them a
function. This is called a *map operation*, not to be confused with
the map data structure.
the map data structure. The predefined functional iterator
implementing the map operation over maps is called `Map.map`. In the
following example, we add `1` to the ordinate of the moves in the
register.
<!--DOCUSAURUS_CODE_TABS-->
<!--PascaLIGO-->
In PascaLIGO, the predefined functional iterator implementing the map
operation over maps is called `map_map` and is used as follows:
```pascaligo group=f
```pascaligo group=maps
function map_op (const m : register) : register is
block {
function increment (const i : address; const j : move) : move is
(j.0, j.1 + 1);
} with map_map (increment, m)
(j.0, j.1 + 1)
} with Map.map (increment, m)
```
> The mapped function must be pure, that is, it cannot mutate
> variables.
> Note that `map_map` is *deprecated*.
<!--CameLIGO-->
In CameLIGO, the predefined functional iterator implementing the map
operation over maps is called `Map.map` and is used as follows:
```cameligo group=f
```cameligo group=maps
let map_op (m : register) : register =
let increment = fun (i,j : address * move) -> j.0, j.1 + 1
in Map.map increment m
@ -634,10 +661,7 @@ let map_op (m : register) : register =
<!--ReasonLIGO-->
In ReasonLIGO, the predefined functional iteratir implementing the map
operation over maps is called `Map.map` and is used as follows:
```reasonligo group=f
```reasonligo group=maps
let map_op = (m : register) : register => {
let increment = ((i,j): (address, move)) => (j[0], j[1] + 1);
Map.map (increment, m);
@ -653,31 +677,26 @@ function takes two arguments: an *accumulator* and the structure
enables having a partial result that becomes complete when the
traversal of the data structure is over.
The predefined functional iterator implementing the folded operation
over maps is called `Map.fold` and is used as follows.
<!--DOCUSAURUS_CODE_TABS-->
<!--PascaLIGO-->
In PascaLIGO, the predefined functional iterator implementing the
folded operation over maps is called `map_fold` and is used as
follows:
```pascaligo group=f
function fold_op (const m : register) : int is block {
function folded (const j : int; const cur : address * move) : int is
j + cur.1.1
} with map_fold (folded, m, 5)
```pascaligo group=maps
function fold_op (const m : register) : int is
block {
function folded (const i : int; const j : address * move) : int is
i + j.1.1
} with Map.fold (folded, m, 5)
```
> The folded function must be pure, that is, it cannot mutate
> variables.
> Note that `map_fold` is *deprecated*.
<!--CameLIGO-->
In CameLIGO, the predefined functional iterator implementing the
folded operation over maps is called `Map.fold` and is used as
follows:
```cameligo group=f
```cameligo group=maps
let fold_op (m : register) : register =
let folded = fun (i,j : int * (address * move)) -> i + j.1.1
in Map.fold folded m 5
@ -685,11 +704,7 @@ let fold_op (m : register) : register =
<!--ReasonLIGO-->
In ReasonLIGO, the predefined functional iterator implementing the
folded operation over maps is called `Map.fold` and is used as
follows:
```reasonligo group=f
```reasonligo group=maps
let fold_op = (m : register) : register => {
let folded = ((i,j): (int, (address, move))) => i + j[1][1];
Map.fold (folded, m, 5);
@ -709,75 +724,99 @@ were it not for *big maps*. Big maps are a data structure offered by
Michelson which handles the scaling concerns for us. In LIGO, the
interface for big maps is analogous to the one used for ordinary maps.
### Declaring a Map
Here is how we define a big map:
<!--DOCUSAURUS_CODE_TABS-->
<!--PascaLIGO-->
```pascaligo group=g
```pascaligo group=big_maps
type move is int * int
type register is big_map (address, move)
```
<!--CameLIGO-->
```cameligo group=g
```cameligo group=big_maps
type move = int * int
type register = (address, move) big_map
```
<!--ReasonLIGO-->
```reasonligo group=g
```reasonligo group=big_maps
type move = (int, int);
type register = big_map (address, move);
```
<!--END_DOCUSAURUS_CODE_TABS-->
And here is how a map value is created:
### Creating an Empty Big Map
Here is how to create an empty big map.
<!--DOCUSAURUS_CODE_TABS-->
<!--PascaLIGO-->
```pascaligo group=big_maps
const empty : register = big_map []
```
<!--CameLIGO-->
```cameligo group=big_maps
let empty : register = Big_map.empty
```
<!--ReasonLIGO-->
```reasonligo group=big_maps
let empty : register = Big_map.empty
```
<!--END_DOCUSAURUS_CODE_TABS-->
### Creating a Non-empty Map
And here is how to create a non-empty map value:
<!--DOCUSAURUS_CODE_TABS-->
<!--PascaLIGO-->
```pascaligo group=g
```pascaligo group=big_maps
const moves : register =
big_map [
("tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx" : address) -> (1,2);
("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN" : address) -> (0,3)]
```
> Notice the right arrow `->` between the key and its value and the
> semicolon separating individual map entries. The value annotation
> `("<string value>" : address)` means that we cast a string into an
> address.
Notice the right arrow `->` between the key and its value and the
semicolon separating individual map entries. The value annotation
`("<string value>" : address)` means that we cast a string into an
address. -->
<!--CameLIGO-->
```cameligo group=g
```cameligo group=big_maps
let moves : register =
Big_map.literal [
(("tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx" : address), (1,2));
(("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN" : address), (0,3))]
```
> The predefind function `Big_map.literal` constructs a big map from a
> list of key-value pairs `(<key>, <value>)`. Note also the semicolon
> separating individual map entries. The annotated value `("<string
> value>" : address)` means that we cast a string into an address.
The predefind function `Big_map.literal` constructs a big map from a
list of key-value pairs `(<key>, <value>)`. Note also the semicolon
separating individual map entries. The annotated value `("<string>
value>" : address)` means that we cast a string into an address.
<!--ReasonLIGO-->
```reasonligo group=g
```reasonligo group=big_maps
let moves : register =
Big_map.literal ([
("tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx" : address, (1,2)),
("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN" : address, (0,3))]);
```
> The predefind function `Big_map.literal` constructs a big map from a
> list of key-value pairs `(<key>, <value>)`. Note also the semicolon
> separating individual map entries. The annotated value `("<string
> value>" : address)` means that we cast a string into an address.
The predefind function `Big_map.literal` constructs a big map from a
list of key-value pairs `(<key>, <value>)`. Note also the semicolon
separating individual map entries. The annotated value `("<string>
value>" : address)` means that we cast a string into an address.
<!--END_DOCUSAURUS_CODE_TABS-->
@ -793,21 +832,21 @@ the value we read is an optional value (in our case, of type `option
<!--PascaLIGO-->
```pascaligo group=g
```pascaligo group=big_maps
const my_balance : option (move) =
moves [("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN" : address)]
```
<!--CameLIGO-->
```cameligo group=g
```cameligo group=big_maps
let my_balance : move option =
Big_map.find_opt ("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN" : address) moves
```
<!--ReasonLIGO-->
```reasonligo group=g
```reasonligo group=big_maps
let my_balance : option (move) =
Big_map.find_opt ("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN" : address, moves);
```
@ -822,7 +861,7 @@ let my_balance : option (move) =
The values of a PascaLIGO big map can be updated using the
assignment syntax for ordinary maps
```pascaligo group=g
```pascaligo group=big_maps
function add (var m : register) : register is
block {
m [("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN": address)] := (4,9)
@ -836,7 +875,7 @@ const updated_map : register = add (moves)
We can update a big map in CameLIGO using the `Big_map.update`
built-in:
```cameligo group=g
```cameligo group=big_maps
let updated_map : register =
Big_map.update
("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN" : address) (Some (4,9)) moves
@ -847,10 +886,10 @@ let updated_map : register =
We can update a big map in ReasonLIGO using the `Big_map.update`
built-in:
```reasonligo group=g
```reasonligo group=big_maps
let updated_map : register =
Big_map.update
(("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN": address), Some((4,9)), moves);
(("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN": address), Some ((4,9)), moves);
```
<!--END_DOCUSAURUS_CODE_TABS-->
@ -867,7 +906,7 @@ syntax.
PascaLIGO features a special syntactic construct to remove bindings
from maps, of the form `remove <key> from map <map>`. For example,
```pascaligo group=g
```pascaligo group=big_maps
function rem (var m : register) : register is
block {
remove ("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN": address) from map moves
@ -881,7 +920,7 @@ const updated_map : register = rem (moves)
In CameLIGO, the predefined function which removes a binding in a map
is called `Map.remove` and is used as follows:
```cameligo group=g
```cameligo group=big_maps
let updated_map : register =
Map.remove ("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN": address) moves
```
@ -891,7 +930,7 @@ let updated_map : register =
In ReasonLIGO, the predefined function which removes a binding in a map
is called `Map.remove` and is used as follows:
```reasonligo group=g
```reasonligo group=big_maps
let updated_map : register =
Map.remove (("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN": address), moves)
```

View File

@ -3,7 +3,28 @@ id: math-numbers-tez
title: Math, Numbers & Tez
---
LIGO offers three built-in numerical types: `int`, `nat` and `tez`.
LIGO offers three built-in numerical types: `int`, `nat` and
`tez`. Values of type `int` are integers; values of type `nat` are
natural numbers (integral numbers greater than or equal to zero);
values of type `tez` are units of measure of Tezos tokens.
* Integer literals are the same found in mainstream programming
languages, for example, `10`, `-6` and `0`, but there is only one
canonical zero: `0` (so, for instance, `-0` and `00` are invalid).
* Natural numbers are written as digits follwed by the suffix `n`,
like so: `12n`, `0n`, and the same restriction on zero as integers
applies: `0n` is the only way to specify the natural zero.
* Tezos tokens can be specified using literals of three kinds:
* units of millionth of `tez`, using the suffix `mutez` after a
natural literal, like `10000mutez` or `0mutez`;
* units of `tez`, using the suffix `tz` or `tez`, like `3tz` or
`3tez`;
* decimal amounts of `tz` or `tez`, like `12.3tz` or `12.4tez`.
Note that large integral values can be expressed using underscores to
separate groups of digits, like `1_000mutez` or `0.000_004tez`.
## Addition
@ -27,7 +48,7 @@ const a : int = 5 + 10
const b : int = 5n + 10
// tez + tez yields tez
const c : tez = 5mutez + 10mutez
const c : tez = 5mutez + 0.000_010tez
//tez + int or tez + nat is invalid
// const d : tez = 5mutez + 10n
@ -57,7 +78,7 @@ let a : int = 5 + 10
let b : int = 5n + 10
// tez + tez yields tez
let c : tez = 5mutez + 10mutez
let c : tez = 5mutez + 0.000_010tez
// tez + int or tez + nat is invalid
// let d : tez = 5mutez + 10n
@ -87,7 +108,7 @@ let a : int = 5 + 10;
let b : int = 5n + 10;
// tez + tez yields tez
let c : tez = 5mutez + 10mutez;
let c : tez = 5mutez + 0.000_010tez;
// tez + int or tez + nat is invalid:
// let d : tez = 5mutez + 10n;
@ -192,7 +213,7 @@ let c : tez = 5n * 5mutez;
<!--END_DOCUSAURUS_CODE_TABS-->
## Division
## Euclidean Division
In LIGO you can divide `int`, `nat`, and `tez`. Here is how:
@ -222,6 +243,46 @@ let c : nat = 10mutez / 3mutez;
<!--END_DOCUSAURUS_CODE_TABS-->
LIGO also allows you to compute the remainder of the Euclidean
division. In LIGO, it is a natural number.
<!--DOCUSAURUS_CODE_TABS-->
<!--PascaLIGO-->
```pascaligo group=d
const a : int = 120
const b : int = 9
const rem1 : nat = a mod b // 3
const c : nat = 120n
const rem2 : nat = c mod b // 3
const d : nat = 9n
const rem3 : nat = c mod d // 3
const rem4 : nat = a mod d // 3
```
<!--CameLIGO-->
```cameligo group=d
let a : int = 120
let b : int = 9
let rem1 : nat = a mod b // 3
let c : nat = 120n
let rem2 : nat = c mod b // 3
let d : nat = 9n
let rem3 : nat = c mod d // 3
let rem4 : nat = a mod d // 3
```
<!--ReasonLIGO-->
```reasonligo group=d
let a : int = 120;
let b : int = 9;
let rem1 : nat = a mod b; // 3
let c : nat = 120n;
let rem2 : nat = c mod b; // 3
let d : nat = 9n;
let rem3 : nat = c mod d; // 3
let rem4 : nat = a mod d; // 3
```
## From `int` to `nat` and back
You can *cast* an `int` to a `nat` and vice versa. Here is how:
@ -244,7 +305,6 @@ let b : nat = abs (1)
let a : int = int (1n);
let b : nat = abs (1);
```
<!--END_DOCUSAURUS_CODE_TABS-->
## Checking a `nat`

View File

@ -3,13 +3,14 @@ id: operators
title: Operators
---
## Available operators
## Available Operators
> This list is non-exhaustive. More operators will be added in upcoming LIGO releases.
> This list is non-exhaustive. More operators will be added in
> upcoming LIGO releases.
|Michelson |Pascaligo |Description |
|--- |--- |--- |
| `SENDER` | `sender` | Address that initiated the current transaction
| `SOURCE` | `source` | Address that initiated the transaction, which triggered the current transaction. (useful e.g. when there's a transaction sent by another contract)
| `AMOUNT` | `amount` | Amount of tez sent by the transaction that invoked the contract
| `NOW` | `now` | Timestamp of the block whose validation triggered execution of the contract, i.e. current time when the contract is run.
| `SENDER` | `Tezos.sender` | Address that initiated the current transaction
| `SOURCE` | `Tezos.source` | Address that initiated the transaction, which triggered the current transaction. (useful e.g. when there's a transaction sent by another contract)
| `AMOUNT` | `Tezos.amount` | Amount of tez sent by the transaction that invoked the contract
| `NOW` | `Tezos.now` | Timestamp of the block whose validation triggered execution of the contract, i.e. current time when the contract is run.

View File

@ -62,32 +62,28 @@ Accessing the components of a tuple in OCaml is achieved by
[pattern matching](language-basics/unit-option-pattern-matching.md). LIGO
currently supports tuple patterns only in the parameters of functions,
not in pattern matching. However, we can access components by their
position in their tuple, which cannot be done in OCaml.
position in their tuple, which cannot be done in OCaml. *Tuple
components are zero-indexed*, that is, the first component has index
`0`.
<!--DOCUSAURUS_CODE_TABS-->
<!--PascaLIGO-->
Tuple components are one-indexed and accessed like so:
```pascaligo group=tuple
const first_name : string = full_name.1
const first_name : string = full_name.0
```
<!--CameLIGO-->
Tuple elements are zero-indexed and accessed like so:
```cameligo group=tuple
let first_name : string = full_name.0
```
<!--ReasonLIGO-->
Tuple components are one-indexed and accessed like so:
```reasonligo group=tuple
let first_name : string = full_name[1];
let first_name : string = full_name[0];
```
<!--END_DOCUSAURUS_CODE_TABS-->
@ -103,7 +99,7 @@ called the *head*, and the sub-list after the head is called the
think of a list a *stack*, where the top is written on the left.
> 💡 Lists are needed when returning operations from a smart
> contract's access function.
> contract's main function.
### Defining Lists
@ -128,7 +124,6 @@ let my_list : list (int) = [1, 2, 2]; // The head is 1
<!--END_DOCUSAURUS_CODE_TABS-->
### Adding to Lists
Lists can be augmented by adding an element before the head (or, in
@ -180,49 +175,36 @@ There are three kinds of functional iterations over LIGO lists: the
*iterated operation*, the *map operation* (not to be confused with the
*map data structure*) and the *fold operation*.
> 💡 Lists can be iterated, folded or mapped to different values. You
> can find additional examples
> [here](https://gitlab.com/ligolang/ligo/tree/dev/src/test/contracts)
> and other built-in operators
> [here](https://gitlab.com/ligolang/ligo/blob/dev/src/passes/operators/operators.ml#L59)
#### Iterated Operation over Lists
The first, the *iterated operation*, is an iteration over the list
with a unit return value. It is useful to enforce certain invariants
on the element of a list, or fail. For example you might want to check
that each value inside of a list is within a certain range, and fail
otherwise.
on the element of a list, or fail.
For example you might want to check that each value inside of a list
is within a certain range, and fail otherwise. The predefined
functional iterator implementing the iterated operation over lists is
called `List.iter`.
In the following example, a list is iterated to check that all its
elements (integers) are strictly greater than `3`.
<!--DOCUSAURUS_CODE_TABS-->
<!--PascaLIGO-->
In PascaLIGO, the predefined functional iterator implementing the
iterated operation over lists is called `list_iter`.
In the following example, a list is iterated to check that all its
elements (integers) are greater than `3`:
```pascaligo group=lists
function iter_op (const l : list (int)) : unit is
block {
function iterated (const i : int) : unit is
if i > 2 then Unit else (failwith ("Below range.") : unit)
} with list_iter (iterated, l)
if i > 3 then Unit else (failwith ("Below range.") : unit)
} with List.iter (iterated, l)
```
> The iterated function must be pure, that is, it cannot mutate
> variables.
> Note that `list_iter` is *deprecated*.
<!--CameLIGO-->
In CameLIGO, the predefined functional iterator implementing the
iterated operation over lists is called `List.iter`.
In the following example, a list is iterated to check that all its
elements (integers) are greater than `3`:
```cameligo group=lists
let iter_op (l : int list) : unit =
let predicate = fun (i : int) -> assert (i > 3)
@ -231,12 +213,6 @@ let iter_op (l : int list) : unit =
<!--ReasonLIGO-->
In ReasonLIGO, the predefined functional iterator implementing the
iterated operation over lists is called `List.iter`.
In the following example, a list is iterated to check that all its
elements (integers) are greater than `3`:
```reasonligo group=lists
let iter_op = (l : list (int)) : unit => {
let predicate = (i : int) => assert (i > 3);
@ -251,32 +227,25 @@ let iter_op = (l : list (int)) : unit => {
We may want to change all the elements of a given list by applying to
them a function. This is called a *map operation*, not to be confused
with the map data structure.
with the map data structure. The predefined functional iterator
implementing the mapped operation over lists is called `List.map` and
is used as follows.
<!--DOCUSAURUS_CODE_TABS-->
<!--PascaLIGO-->
In PascaLIGO, the predefined functional iterator implementing the
mapped operation over lists is called `list_map` and is used as
follows:
```pascaligo group=lists
function increment (const i : int): int is i + 1
// Creates a new list with all elements incremented by 1
const plus_one : list (int) = list_map (increment, larger_list)
const plus_one : list (int) = List.map (increment, larger_list)
```
> The mapped function must be pure, that is, it cannot mutate
> variables.
> Note that `list_map` is *deprecated*.
<!--CameLIGO-->
In CameLIGO, the predefined functional iterator implementing the
mapped operation over lists is called `List.map` and is used as
follows:
```cameligo group=lists
let increment (i : int) : int = i + 1
@ -286,10 +255,6 @@ let plus_one : int list = List.map increment larger_list
<!--ReasonLIGO-->
In ReasonLIGO, the predefined functional iterator implementing the
mapped operation over lists is called `List.map` and is used as
follows:
```reasonligo group=lists
let increment = (i : int) : int => i + 1;
@ -305,29 +270,23 @@ A *folded operation* is the most general of iterations. The folded
function takes two arguments: an *accumulator* and the structure
*element* at hand, with which it then produces a new accumulator. This
enables having a partial result that becomes complete when the
traversal of the data structure is over.
traversal of the data structure is over. The predefined functional
iterator implementing the folded operation over lists is called
`List.fold` and is used as follows.
<!--DOCUSAURUS_CODE_TABS-->
<!--PascaLIGO-->
In PascaLIGO, the predefined functional iterator implementing the
folded operation over lists is called `list_fold` and is used as
follows:
```pascaligo group=lists
function sum (const acc : int; const i : int): int is acc + i
const sum_of_elements : int = list_fold (sum, my_list, 0)
const sum_of_elements : int = List.fold (sum, my_list, 0)
```
> The folded function must be pure, that is, it cannot mutate
> variables.
> Note that `list_fold` is *deprecated*.
<!--CameLIGO-->
In CameLIGO, the predefined functional iterator implementing the folded
operation over lists is called `List.fold` and is used as follows:
```cameligo group=lists
let sum (acc, i: int * int) : int = acc + i
let sum_of_elements : int = List.fold sum my_list 0
@ -335,10 +294,6 @@ let sum_of_elements : int = List.fold sum my_list 0
<!--ReasonLIGO-->
In ReasonLIGO, the predefined functional iterator implementing the
folded operation over lists is called `List.fold` and is used as
follows:
```reasonligo group=lists
let sum = ((result, i): (int, int)): int => result + i;
let sum_of_elements : int = List.fold (sum, my_list, 0);
@ -350,7 +305,7 @@ let sum_of_elements : int = List.fold (sum, my_list, 0);
Sets are unordered collections of values of the same type, like lists
are ordered collections. Like the mathematical sets and lists, sets
can be empty and, if not, elements of sets in LIGO are *unique*,
whereas they can be repeated in a list.
whereas they can be repeated in a *list*.
### Empty Sets
@ -476,36 +431,34 @@ in a set as follows:
```reasonligo group=sets
let contains_3 : bool = Set.mem (3, my_set);
```
<!--END_DOCUSAURUS_CODE_TABS-->
### Cardinal of Sets
The predefined function `Set.size` returns the number of
elements in a given set as follows.
<!--DOCUSAURUS_CODE_TABS-->
<!--PascaLIGO-->
In PascaLIGO, the predefined function `size` returns the number of
elements in a given set as follows:
```pascaligo group=sets
const set_size : nat = size (my_set)
const cardinal : nat = Set.size (my_set)
```
> Note that `size` is *deprecated*.
<!--CameLIGO-->
In CameLIGO, the predefined function `Set.size` returns the number of
elements in a given set as follows:
```cameligo group=sets
let set_size : nat = Set.size my_set
let cardinal : nat = Set.size my_set
```
<!--ReasonLIGO-->
In ReasonLIGO, the predefined function `Set.size` returns the number
of elements in a given set as follows:
```reasonligo group=sets
let set_size : nat = Set.size (my_set);
let cardinal : nat = Set.size (my_set);
```
<!--END_DOCUSAURUS_CODE_TABS-->
@ -513,20 +466,23 @@ let set_size : nat = Set.size (my_set);
### Updating Sets
There are two ways to update a set, that is to add or remove from
it.
<!--DOCUSAURUS_CODE_TABS-->
<!--PascaLIGO-->
In PascaLIGO, there are two ways to update a set, that is to add or
remove from it. Either we create a new set from the given one, or we
In PascaLIGO, either we create a new set from the given one, or we
modify it in-place. First, let us consider the former way:
```pascaligo group=sets
const larger_set : set (int) = set_add (4, my_set)
const smaller_set : set (int) = set_remove (3, my_set)
const larger_set : set (int) = Set.add (4, my_set)
const smaller_set : set (int) = Set.remove (3, my_set)
```
> Note that `set_add` and `set_remove` are *deprecated*.
If we are in a block, we can use an instruction to modify the set
bound to a given variable. This is called a *patch*. It is only
possible to add elements by means of a patch, not remove any: it is
@ -548,23 +504,23 @@ const new_set : set (int) = update (my_set)
<!--CameLIGO-->
In CameLIGO, we update a given set by creating another one, with or
In CameLIGO, we can use the predefined functions `Set.add` and
`Set.remove`. We update a given set by creating another one, with or
without some elements.
```cameligo group=sets
let larger_set : int set = Set.add 4 my_set
let smaller_set : int set = Set.remove 3 my_set
```
<!--ReasonLIGO-->
In ReasonLIGO, we update a given set by creating another one, with or
In ReasonLIGO, we can use the predefined functions `Set.add` and
`Set.remove`. We update a given set by creating another one, with or
without some elements.
```reasonligo group=sets
let larger_set : set (int) = Set.add (4, my_set);
let smaller_set : set (int) = Set.remove (3, my_set);
```
<!--END_DOCUSAURUS_CODE_TABS-->
@ -588,35 +544,27 @@ no return value: its only use is to produce side-effects. This can be
useful if for example you would like to check that each value inside
of a map is within a certain range, and fail with an error otherwise.
The predefined functional iterator implementing the iterated operation
over sets is called `Set.iter`. In the following example, a set is
iterated to check that all its elements (integers) are greater than
`3`.
<!--DOCUSAURUS_CODE_TABS-->
<!--PascaLIGO-->
In PascaLIGO, the predefined functional iterator implementing the
iterated operation over sets is called `set_iter`.
In the following example, a set is iterated to check that all its
elements (integers) are greater than `3`:
```pascaligo group=sets
function iter_op (const s : set (int)) : unit is
block {
function iterated (const i : int) : unit is
if i > 2 then Unit else (failwith ("Below range.") : unit)
} with set_iter (iterated, s)
} with Set.iter (iterated, s)
```
> The iterated function must be pure, that is, it cannot mutate
> variables.
> Note that `set_iter` is *deprecated*.
<!--CameLIGO-->
In CameLIGO, the predefined functional iterator implementing the
iterated operation over sets is called `Set.iter`.
In the following example, a set is iterated to check that all its
elements (integers) are greater than `3`:
```cameligo group=sets
let iter_op (s : int set) : unit =
let predicate = fun (i : int) -> assert (i > 3)
@ -625,12 +573,6 @@ let iter_op (s : int set) : unit =
<!--ReasonLIGO-->
In ReasonLIGO, the predefined functional iterator implementing the
iterated operation over sets is called `Set.iter`.
In the following example, a set is iterated to check that all its
elements (integers) are greater than `3`:
```reasonligo group=sets
let iter_op = (s : set (int)) : unit => {
let predicate = (i : int) => assert (i > 3);
@ -641,51 +583,51 @@ let iter_op = (s : set (int)) : unit => {
<!--END_DOCUSAURUS_CODE_TABS-->
#### Mapped Operation (NOT IMPLEMENTED YET)
<!-- #### Mapped Operation (NOT IMPLEMENTED YET) -->
We may want to change all the elements of a given set by applying to
them a function. This is called a *mapped operation*, not to be
confused with the map data structure.
<!-- We may want to change all the elements of a given set by applying to -->
<!-- them a function. This is called a *mapped operation*, not to be -->
<!-- confused with the map data structure. -->
<!--DOCUSAURUS_CODE_TABS-->
<!-- <\!--DOCUSAURUS_CODE_TABS-\-> -->
<!--PascaLIGO-->
<!-- <\!--PascaLIGO-\-> -->
In PascaLIGO, the predefined functional iterator implementing the
mapped operation over sets is called `set_map` and is used as follows:
<!-- In PascaLIGO, the predefined functional iterator implementing the -->
<!-- mapped operation over sets is called `Set.map` and is used as follows: -->
```pascaligo skip
function increment (const i : int): int is i + 1
<!-- ```pascaligo skip -->
<!-- function increment (const i : int): int is i + 1 -->
// Creates a new set with all elements incremented by 1
const plus_one : set (int) = set_map (increment, larger_set)
```
<!-- // Creates a new set with all elements incremented by 1 -->
<!-- const plus_one : set (int) = Set.map (increment, larger_set) -->
<!-- ``` -->
<!--CameLIGO-->
<!-- <\!--CameLIGO-\-> -->
In CameLIGO, the predefined functional iterator implementing the
mapped operation over sets is called `Set.map` and is used as follows:
<!-- In CameLIGO, the predefined functional iterator implementing the -->
<!-- mapped operation over sets is called `Set.map` and is used as follows: -->
```cameligo skip
let increment (i : int) : int = i + 1
<!-- ```cameligo skip -->
<!-- let increment (i : int) : int = i + 1 -->
// Creates a new set with all elements incremented by 1
let plus_one : int set = Set.map increment larger_set
```
<!-- // Creates a new set with all elements incremented by 1 -->
<!-- let plus_one : int set = Set.map increment larger_set -->
<!-- ``` -->
<!--ReasonLIGO-->
<!-- <\!--ReasonLIGO-\-> -->
In ReasonLIGO, the predefined functional iterator implementing the
mapped operation over sets is called `Set.map` and is used as follows:
<!-- In ReasonLIGO, the predefined functional iterator implementing the -->
<!-- mapped operation over sets is called `Set.map` and is used as follows: -->
```reasonligo skip
let increment = (i : int) : int => i + 1;
<!-- ```reasonligo skip -->
<!-- let increment = (i : int) : int => i + 1; -->
// Creates a new set with all elements incremented by 1
let plus_one : set (int) = Set.map (increment, larger_set);
```
<!-- // Creates a new set with all elements incremented by 1 -->
<!-- let plus_one : set (int) = Set.map (increment, larger_set); -->
<!-- ``` -->
<!--END_DOCUSAURUS_CODE_TABS-->
<!-- <\!--END_DOCUSAURUS_CODE_TABS-\-> -->
#### Folded Operation
@ -693,24 +635,17 @@ A *folded operation* is the most general of iterations. The folded
function takes two arguments: an *accumulator* and the structure
*element* at hand, with which it then produces a new accumulator. This
enables having a partial result that becomes complete when the
traversal of the data structure is over.
traversal of the data structure is over. The predefined fold over sets
is called `Set.fold`.
<!--DOCUSAURUS_CODE_TABS-->
<!--PascaLIGO-->
In PascaLIGO, the predefined functional iterator implementing the
folded operation over sets is called `set_fold` and is used as
follows:
```pascaligo group=sets
function sum (const acc : int; const i : int): int is acc + i
const sum_of_elements : int = set_fold (sum, my_set, 0)
const sum_of_elements : int = Set.fold (sum, my_set, 0)
```
> The folded function must be pure, that is, it cannot mutate
> variables.
> Note that `set_fold` is *deprecated*.
It is possible to use a *loop* over a set as well.
@ -724,22 +659,14 @@ function loop (const s : set (int)) : int is block {
```
<!--CameLIGO-->
In CameLIGO, the predefined fold over sets is called `Set.fold`.
```cameligo group=sets
let sum (acc, i : int * int) : int = acc + i
let sum_of_elements : int = Set.fold sum my_set 0
```
<!--ReasonLIGO-->
In ReasonLIGO, the predefined fold over sets is called `Set.fold`.
```reasonligo group=sets
let sum = ((acc, i) : (int, int)) : int => acc + i;
let sum_of_elements : int = Set.fold (sum, my_set, 0);
```
<!--END_DOCUSAURUS_CODE_TABS-->

View File

@ -1,4 +1,4 @@
type magnitude is Small | Large // See variant types
function compare (const n : nat) : magnitude is
if n < 10n then Small (Unit) else Large (Unit)
if n < 10n then Small else Large

View File

@ -2,4 +2,4 @@ function increment (const b : int) : int is
(function (const a : int) : int is a + 1) (b)
function incr_map (const l : list (int)) : list (int) is
list_map (function (const i : int) : int is i + 1, l)
List.map (function (const i : int) : int is i + 1, l)

View File

@ -4,9 +4,8 @@ const larger_list : int_list = 5 # my_list
function increment (const i : int): int is i + 1
// Creates a new list with all elements incremented by 1
const plus_one : list (int) = list_map (increment, larger_list);
const plus_one : list (int) = List.map (increment, larger_list);
function sum (const acc : int; const i : int): int is acc + i
const sum_of_elements : int = list_fold (sum, my_list, 0)
const sum_of_elements : int = List.fold (sum, my_list, 0)

View File

@ -6,9 +6,9 @@ const contains_3 : bool = my_set contains 3
const set_size : nat = size (my_set)
const larger_set : int_set = set_add (4, my_set)
const larger_set : int_set = Set.add (4, my_set)
const smaller_set : int_set = set_remove (3, my_set)
const smaller_set : int_set = Set.remove (3, my_set)
function update (var s : set (int)) : set (int) is block {
patch s with set [4; 7]
@ -18,7 +18,7 @@ const new_set : set (int) = update (my_set)
function sum (const acc : int; const i : int): int is acc + i
const sum_of_elements : int = set_fold (sum, my_set, 0)
const sum_of_elements : int = Set.fold (sum, my_set, 0)
function loop (const s : set (int)) : int is block {
var sum : int := 0;

View File

@ -2,6 +2,6 @@ type coin is Head | Tail
function flip (const c : coin) : coin is
case c of
Head -> Tail (Unit) // Unit needed because of a bug
| Tail -> Head (Unit) // Unit needed because of a bug
Head -> Tail
| Tail -> Head
end

View File

@ -59,21 +59,27 @@ Strings can be sliced using a built-in function:
<!--PascaLIGO-->
```pascaligo group=b
const name : string = "Alice"
const slice : string = string_slice (0n, 1n, name)
const slice : string = String.slice (0n, 1n, name)
```
> Note that `string_slide` is *deprecated*.
<!--CameLIGO-->
```cameligo group=b
let name : string = "Alice"
let slice : string = String.slice 0n 1n name
```
<!--ReasonLIGO-->
```reasonligo group=b
let name : string = "Alice";
let slice : string = String.slice (0n, 1n, name);
```
<!--END_DOCUSAURUS_CODE_TABS-->
> ⚠️ Notice that the offset and length of the slice are natural numbers.
> ⚠️ Notice that the offset and length of the slice are natural
> numbers.
## Length of Strings
@ -83,8 +89,11 @@ The length of a string can be found using a built-in function:
<!--PascaLIGO-->
```pascaligo group=c
const name : string = "Alice"
const length : nat = size (name) // length = 5
const length : nat = String.length (name) // length = 5
```
> Note that `size` is *deprecated*.
<!--CameLIGO-->
```cameligo group=c
let name : string = "Alice"

View File

@ -26,9 +26,11 @@ functionality can be accessed from within LIGO.
```pascaligo group=a
function id_string (const p : string) : option (string) is block {
const packed : bytes = bytes_pack (p)
} with (bytes_unpack (packed) : option (string))
} with (Bytes.unpack (packed) : option (string))
```
> Note that `bytes_unpack` is *deprecated*.
<!--CameLIGO-->
```cameligo group=a
let id_string (p : string) : string option =
@ -103,9 +105,11 @@ function check_signature
(const pk : key;
const signed : signature;
const msg : bytes) : bool
is crypto_check (pk, signed, msg)
is Crypto.check (pk, signed, msg)
```
> Note that `crypto_check` is *deprecated*.
<!--CameLIGO-->
```cameligo group=c
let check_signature (pk, signed, msg : key * signature * bytes) : bool =
@ -124,27 +128,29 @@ let check_signature =
## Contract's Own Address
Often you want to get the address of the contract being executed. You
can do it with `self_address`.
can do it with `Tezos.self_address`.
> ⚠️ Due to limitations in Michelson, `self_address` in a contract is
> only allowed at the top-level. Using it in an embedded function will
> cause an error.
> Note that `self_address` is *deprecated*.
> ⚠️ Due to limitations in Michelson, `Tezos.self_address` in a
> contract is only allowed at the top-level. Using it in an embedded
> function will cause an error.
<!--DOCUSAURUS_CODE_TABS-->
<!--PascaLIGO-->
```pascaligo group=d
const current_addr : address = self_address
const current_addr : address = Tezos.self_address
```
<!--CameLIGO-->
```cameligo group=d
let current_addr : address = Current.self_address
let current_addr : address = Tezos.self_address
```
<!--ReasonLIGO-->
```reasonligo group=d
let current_addr : address = Current.self_address;
let current_addr : address = Tezos.self_address;
```
<!--END_DOCUSAURUS_CODE_TABS-->

View File

@ -229,7 +229,7 @@ type return = operation list * storage
let back (param, store : unit * storage) : return =
let no_op : operation list = [] in
if Current.time > store.deadline then
if Tezos.now > store.deadline then
(failwith "Deadline passed." : return) // Annotation
else
match Map.find_opt sender store.backers with
@ -255,7 +255,7 @@ type return = (list (operation), storage);
let back = ((param, store) : (unit, storage)) : return => {
let no_op : list (operation) = [];
if (Current.time > store.deadline) {
if (Tezos.now > store.deadline) {
(failwith ("Deadline passed.") : return); // Annotation
}
else {

View File

@ -56,8 +56,8 @@ else):
<!--PascaLIGO-->
```pascaligo group=b
type coin is Head | Tail
const head : coin = Head (Unit) // Unit needed for now.
const tail : coin = Tail (Unit) // Unit needed for now.
const head : coin = Head
const tail : coin = Tail
```
<!--CameLIGO-->
@ -69,14 +69,16 @@ let tail : coin = Tail
<!--ReasonLIGO-->
```reasonligo group=b
type coin = | Head | Tail;
type coin = Head | Tail;
let head : coin = Head;
let tail : coin = Tail;
```
<!--END_DOCUSAURUS_CODE_TABS-->
The names `Head` and `Tail` in the definition of the type `coin` are
called *data constructors*, or *variants*.
called *data constructors*, or *variants*. In this particular, they
carry no information beyond their names, so they are called *constant
constructors*.
In general, it is interesting for variants to carry some information,
and thus go beyond enumerated types. In the following, we show how to
@ -94,7 +96,7 @@ type user is
| Guest
const u : user = Admin (1000n)
const g : user = Guest (Unit) // Unit needed because of a bug
const g : user = Guest
```
<!--CameLIGO-->
@ -125,6 +127,9 @@ let g : user = Guest;
<!--END_DOCUSAURUS_CODE_TABS-->
In LIGO, a constant constructor is equivalent to the same constructor
taking an argument of type `unit`, so, for example, `Guest` is the
same value as `Guest (unit)`.
## Optional values
@ -172,8 +177,8 @@ type coin is Head | Tail
function flip (const c : coin) : coin is
case c of
Head -> Tail (Unit) // Unit needed because of a bug
| Tail -> Head (Unit) // Unit needed because of a bug
Head -> Tail
| Tail -> Head
end
```
@ -181,7 +186,7 @@ You can call the function `flip` by using the LIGO compiler like so:
```shell
ligo run-function
gitlab-pages/docs/language-basics/src/unit-option-pattern-matching/flip.ligo
flip "(Head (Unit))"
flip "Head"
# Outputs: Tail(Unit)
```

View File

@ -60,7 +60,10 @@ a *global scope*, but they can be declared and used within functions,
or as function parameters.
> ⚠️ Please be wary that mutation only works within the function scope
> itself, values outside of the function scope will not be affected.
> itself, values outside of the function scope will not be
> affected. In other words, when a function is called, its arguments
> are copied, *as well as the environment*. Any side-effect to that
> environment is therefore lost when the function returns.
```pascaligo group=b

View File

@ -1,268 +1,164 @@
---
id: big-map-reference
title: Big Map — Scalable hashmap primitive
title: Big Maps — Scalable Maps
---
## Defining A Big Map Type
Ordinary maps are fine for contracts with a finite lifespan or a
bounded number of users. For many contracts however, the intention is
to have a map holding *many* entries, potentially millions of
them. The cost of loading those entries into the environment each time
a user executes the contract would eventually become too expensive
were it not for *big maps*. Big maps are a data structure offered by
Michelson which handles the scaling concerns for us. In LIGO, the
interface for big maps is analogous to the one used for ordinary maps.
# Declaring a Map
<!--DOCUSAURUS_CODE_TABS-->
<!--Pascaligo-->
```pascaligo
type move is (int * int)
type moveset is big_map (address, move)
type foo is big_map (int, int)
<!--PascaLIGO-->
```pascaligo group=big_maps
type move is int * int
type register is big_map (address, move)
```
<!--CameLIGO-->
```cameligo
```cameligo group=big_maps
type move = int * int
type moveset = (address, move) big_map
type foo = (int, int) big_map
type register = (address, move) big_map
```
<!--ReasonLIGO-->
```reasonligo
```reasonligo group=big_maps
type move = (int, int);
type moveset = big_map(address, move);
type foo = big_map(int, int);
type register = big_map (address, move);
```
<!--END_DOCUSAURUS_CODE_TABS-->
## Creating A Map
# Creating an Empty Big Map
<!--DOCUSAURUS_CODE_TABS-->
<!--Pascaligo-->
```pascaligo
const moves: moveset =
big_map
("tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx": address) -> (1,2);
("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN": address) -> (0,3);
end
<!--PascaLIGO-->
```pascaligo group=big_maps
const empty : register = big_map []
```
<!--CameLIGO-->
```cameligo
let moves: moveset =
Big_map.literal [
(("tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx": address), (1,2));
(("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN": address), (0,3));
]
```cameligo group=big_maps
let empty : register = Big_map.empty
```
<!--ReasonLIGO-->
```reasonligo
let moves: moveset =
Big_map.literal ([
("tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx": address, (1,2)),
("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN": address, (0,3)),
]);
```reasonligo group=big_maps
let empty : register = Big_map.empty
```
<!--END_DOCUSAURUS_CODE_TABS-->
## Big_map.find_opt(k: a', m: (a',b') big_map) : b' option
Retrieve the value associated with a particular key. This version returns an option
which can either shift logic in response to a missing value or throw an error.
# Creating a Non-empty Map
<!--DOCUSAURUS_CODE_TABS-->
<!--Pascaligo-->
```pascaligo
const my_balance : option(move) =
moves [("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN": address)]
<!--PascaLIGO-->
```pascaligo group=big_maps
const moves : register =
big_map [
("tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx" : address) -> (1,2);
("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN" : address) -> (0,3)]
```
<!--CameLIGO-->
```cameligo group=big_maps
let moves : register =
Big_map.literal [
(("tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx" : address), (1,2));
(("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN" : address), (0,3))]
```
```cameligo
<!--ReasonLIGO-->
```reasonligo group=big_maps
let moves : register =
Big_map.literal ([
("tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx" : address, (1,2)),
("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN" : address, (0,3))]);
```
<!--END_DOCUSAURUS_CODE_TABS-->
# Accessing Values
<!--DOCUSAURUS_CODE_TABS-->
<!--PascaLIGO-->
```pascaligo group=big_maps
const my_balance : option (move) =
moves [("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN" : address)]
```
<!--CameLIGO-->
```cameligo group=big_maps
let my_balance : move option =
Big_map.find_opt ("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN": address) moves
Big_map.find_opt ("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN" : address) moves
```
<!--ReasonLIGO-->
```reasonligo
let my_balance : option(move) =
Big_map.find_opt("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN": address, moves);
```reasonligo group=big_maps
let my_balance : option (move) =
Big_map.find_opt ("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN" : address, moves);
```
<!--END_DOCUSAURUS_CODE_TABS-->
## Big_map.find(k: a', m: (a', b') big_map) : b'
Forcefully retrieve the value associated with a particular key. If that value
doesn't exist, this function throws an error.
# Updating Big Maps
<!--DOCUSAURUS_CODE_TABS-->
<!--Pascaligo-->
```pascaligo
const my_balance : move =
get_force (("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN": address), moves);
```
<!--CameLIGO-->
```cameligo
let my_balance : move =
Big_map.find ("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN": address) moves
```
<!--ReasonLIGO-->
```reasonligo
let my_balance : move =
Big_map.find ("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN": address, moves);
```
<!--END_DOCUSAURUS_CODE_TABS-->
## Big_map.update(k: a', v: b', m: (a', b') big_map) : (a', b') big_map
Change the value associated with a particular key, if that value doesn't already
exist add it.
<!--DOCUSAURUS_CODE_TABS-->
<!--Pascaligo-->
The values of a PascaLIGO big map can be updated using the ordinary
assignment syntax:
```pascaligo
function set_ (var m : moveset) : moveset is
<!--PascaLIGO-->
```pascaligo group=big_maps
function add (var m : register) : register is
block {
m [("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN": address)] := (4,9);
m [("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN": address)] := (4,9)
} with m
const updated_map : register = add (moves)
```
<!--Cameligo-->
```cameligo
let updated_map : moveset =
Big_map.update ("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN": address) (Some (4,9)) moves
<!--CameLIGO-->
```cameligo group=big_maps
let updated_map : register =
Big_map.update
("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN" : address) (Some (4,9)) moves
```
<!--Reasonligo-->
```reasonligo
let updated_map : moveset =
Big_map.update(("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN": address), Some((4,9)), moves);
<!--ReasonLIGO-->
```reasonligo group=big_maps
let updated_map : register =
Big_map.update
(("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN": address), Some ((4,9)), moves);
```
<!--END_DOCUSAURUS_CODE_TABS-->
## Big_map.add(k: a', v: b', m: (a', b') big_map) : (a', b') big_map
Add a key and its associated value to the big map.
# Removing Bindings
<!--DOCUSAURUS_CODE_TABS-->
<!--PascaLIGO-->
```pascaligo
function set_ (var n : int ; var m : foo) : foo is block {
m[23] := n ;
} with m
```pascaligo group=big_maps
function rem (var m : register) : register is
block {
remove ("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN": address) from map moves
} with m
const updated_map : register = rem (moves)
```
<!--CameLIGO-->
```cameligo
let add (n,m : int * foo) : foo = Big_map.add 23 n m
```cameligo group=big_maps
let updated_map : register =
Map.remove ("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN": address) moves
```
<!--ReasonLIGO-->
```reasonligo
let add = ((n,m): (int, foo)): foo => Big_map.add(23, n, m);
```reasonligo group=big_maps
let updated_map : register =
Map.remove (("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN": address), moves)
```
<!--END_DOCUSAURUS_CODE_TABS-->
## Big_map.remove(k: a', m: (a', b') big_map) : (a', b') big_map
Remove a key and its associated value from the big map.
<!--DOCUSAURUS_CODE_TABS-->
<!--PascaLIGO-->
```pascaligo
function rm (var m : foo) : foo is block {
remove 42 from map m;
} with m
```
<!--CameLIGO-->
```cameligo
let rm (m : foo) : foo = Big_map.remove 42 m
```
<!--ReasonLIGO-->
```reasonligo
let rm = (m: foo): foo => Big_map.remove(42, m);
```
<!--END_DOCUSAURUS_CODE_TABS-->
## Big_map.literal(key_value_pair_list: (a', b') list) : (a', b') big_map
Constructs a big map from a list of key-value pair tuples.
<!--DOCUSAURUS_CODE_TABS-->
<!--Pascaligo-->
```pascaligo
const moves: moveset =
big_map
("tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx": address) -> (1,2);
("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN": address) -> (0,3);
end
```
<!--CameLIGO-->
```cameligo
let moves: moveset =
Big_map.literal [
(("tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx": address), (1,2));
(("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN": address), (0,3));
]
```
<!--ReasonLIGO-->
```reasonligo
let moves: moveset =
Big_map.literal ([
("tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx": address, (1,2)),
("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN": address, (0,3)),
]);
```
<!--END_DOCUSAURUS_CODE_TABS-->
## Big_map.empty() : (a', b') big_map
Create an empty big map.
<!--DOCUSAURUS_CODE_TABS-->
<!--PascaLIGO-->
```pascaligo
const empty_big_map : big_map(int,int) = big_map end
```
<!--CameLIGO-->
```cameligo
let empty_map : foo = Big_map.empty
```
<!--ReasonLIGO-->
```reasonligo
let empty_map: foo = Big_map.empty;
```
<!--END_DOCUSAURUS_CODE_TABS-->

View File

@ -1,9 +1,9 @@
---
id: current-reference
title: Current - Things relating to the current execution context
title: Tezos - Things relating to the current execution context
---
## Current.balance() : tez
# Tezos.balance
Get the balance for the contract.
@ -11,26 +11,36 @@ Get the balance for the contract.
<!--PascaLIGO-->
```pascaligo
function main (const p : unit; const s: tez) : list(operation) * tez is
((nil : list(operation)), balance)
function main (const p : unit; const s: tez) : list (operation) * tez is
((nil : list (operation)), Tezos.balance)
```
> Note that `balance` and `Current.balance` are *deprecated*.
<!--CameLIGO-->
```cameligo
let main (p, s : unit * tez) =
([] : operation list), balance
let main (p,s : unit * tez) = ([] : operation list), Tezos.balance
```
> Note that `balance` and `Current.balance` are *deprecated*.
<!--ReasonLIGO-->
```reasonligo
let main = ((p,s): (unit, tez)) => ([]: list(operation), balance);
let main = ((p,s) : (unit, tez)) =>
([]: list (operation), Tezos.balance);
```
> Note that `balance` and `Current.balance` are *deprecated*.
<!--END_DOCUSAURUS_CODE_TABS-->
## Current.time() : timestamp
## Tezos.now
Returns the current time as a [unix timestamp](https://en.wikipedia.org/wiki/Unix_time).
Returns the current time as a [unix timestamp](https://en.wikipedia.org/wiki/Unix_time).
In LIGO, timestamps are type compatible in operations with `int`(s). This lets you set e.g. time constraints for your smart contracts like this:
In LIGO, timestamps are type compatible in operations with
integers. This lets you set for instance time constraints for your
smart contracts like this:
### Examples
@ -38,118 +48,134 @@ In LIGO, timestamps are type compatible in operations with `int`(s). This lets y
<!--DOCUSAURUS_CODE_TABS-->
<!--Pascaligo-->
```pascaligo group=b
const today: timestamp = now;
const one_day: int = 86400;
const today: timestamp = Tezos.now;
const one_day: int = 86_400;
const in_24_hrs: timestamp = today + one_day;
const some_date: timestamp = ("2000-01-01T10:10:10Z" : timestamp);
const one_day_later: timestamp = some_date + one_day;
```
> Note that `now` is *deprecated*.
<!--CameLIGO-->
```cameligo group=b
let today: timestamp = Current.time
let one_day: int = 86400
let today: timestamp = Tezos.now
let one_day: int = 86_400
let in_24_hrs: timestamp = today + one_day
let some_date: timestamp = ("2000-01-01t10:10:10Z" : timestamp)
let one_day_later: timestamp = some_date + one_day
```
> Note that `Current.time` is *deprecated*.
<!--ReasonLIGO-->
```reasonligo group=b
let today: timestamp = Current.time;
let one_day: int = 86400;
let today: timestamp = Tezos.now;
let one_day: int = 86_400;
let in_24_hrs: timestamp = today + one_day;
let some_date: timestamp = ("2000-01-01t10:10:10Z" : timestamp);
let one_day_later: timestamp = some_date + one_day;
```
> Note that `Current.time` is *deprecated*.
<!--END_DOCUSAURUS_CODE_TABS-->
#### 24 hours ago
<!--DOCUSAURUS_CODE_TABS-->
<!--Pascaligo-->
```pascaligo group=c
const today: timestamp = now;
const one_day: int = 86400;
const today: timestamp = Tezos.now;
const one_day: int = 86_400;
const in_24_hrs: timestamp = today - one_day;
```
> Note that `now` is *deprecated*.
<!--CameLIGO-->
```cameligo group=c
let today: timestamp = Current.time
let one_day: int = 86400
let today: timestamp = Tezos.now
let one_day: int = 86_400
let in_24_hrs: timestamp = today - one_day
```
> Note that `Current.time` is *deprecated*.
<!--ReasonLIGO-->
```reasonligo group=c
let today: timestamp = Current.time;
let one_day: int = 86400;
let today: timestamp = Tezos.now;
let one_day: int = 86_400;
let in_24_hrs: timestamp = today - one_day;
```
> Note that `Current.time` is *deprecated*.
<!--END_DOCUSAURUS_CODE_TABS-->
#### Comparing timestamps
#### Comparing Timestamps
You can also compare timestamps using the same comparison operators as for numbers:
You can also compare timestamps using the same comparison operators as
for numbers
<!--DOCUSAURUS_CODE_TABS-->
<!--Pascaligo-->
```pascaligo group=c
const not_tommorow: bool = (now = in_24_hrs)
const not_tommorow: bool = (Tezos.now = in_24_hrs)
```
> Note that `now` is *deprecated*.
<!--CameLIGO-->
```cameligo group=c
let not_tomorrow: bool = (Current.time = in_24_hrs)
let not_tomorrow: bool = (Tezos.now = in_24_hrs)
```
> Note that `Current.time` is *deprecated*.
<!--ReasonLIGO-->
```reasonligo group=c
let not_tomorrow: bool = (Current.time == in_24_hrs);
let not_tomorrow: bool = (Tezos.now == in_24_hrs);
```
> Note that `Current.time` is *deprecated*.
<!--END_DOCUSAURUS_CODE_TABS-->
## Current.amount() : tez
## Amount
Get the amount of tez provided by the sender to complete this transaction.
Get the amount of tez provided by the sender to complete this
transaction.
<!--DOCUSAURUS_CODE_TABS-->
<!--PascaLIGO-->
```pascaligo
function check (const p: unit) : int is
begin
var result : int := 0;
if amount = 100tz then
result := 42
else
result := 0
end with result
function threshold (const p : unit) : int is
if Tezos.amount = 100tz then 42 else 0
```
> Note that `amount` is *deprecated*.
<!--CameLIGO-->
```cameligo
let check_ (p: unit) : int = if Current.amount = 100tz then 42 else 0
let threshold (p : unit) : int = if Tezos.amount = 100tz then 42 else 0
```
> Note that `Current.amount` is *deprecated*.
<!--ReasonLIGO-->
```reasonligo
let check_ = (p: unit) : int =>
if (Current.amount == 100tz) {
42;
}
else {
0;
};
let threshold = (p : unit) : int =>
if (Tezos.amount == 100tz) { 42; } else { 0; };
```
> Note that `Current.amount` is *deprecated*.
<!--END_DOCUSAURUS_CODE_TABS-->
## Current.sender() : address
## Sender
Get the address that initiated the current transaction.
@ -157,52 +183,67 @@ Get the address that initiated the current transaction.
<!--PascaLIGO-->
```pascaligo
function main (const p: unit) : address is sender
function main (const p : unit) : address is Tezos.sender
```
> Note that `sender` is *deprecated*.
<!--CameLIGO-->
```cameligo
let main (p: unit) : address = Current.sender
let main (p: unit) : address = Tezos.sender
```
> Note that `Current.sender` is *deprecated*.
<!--ReasonLIGO-->
```reasonligo
let main = (p: unit) : address => Current.sender;
let main = (p : unit) : address => Tezos.sender;
```
> Note that `Current.sender` is *deprecated*.
<!--END_DOCUSAURUS_CODE_TABS-->
## Current.address(c: a' contract) : address
Get the address associated with a `contract`.
## Address
Get the address associated with a value of type `contract`.
<!--DOCUSAURUS_CODE_TABS-->
<!--PascaLIGO-->
```pascaligo
function main (const p : key_hash) : address is block {
const c : contract(unit) = implicit_account(p) ;
} with address(c)
const c : contract (unit) = Tezos.implicit_account (p)
} with Tezos.address(c)
```
> Note that `implicit_account` and `address` are *deprecated*.
<!--CameLIGO-->
```cameligo
let main (p : key_hash) =
let c : unit contract = Current.implicit_account p in
Current.address c
let c : unit contract = Tezos.implicit_account p
in Tezos.address c
```
> Note that `Current.implicit_account` and `Current.address` are
> *deprecated*.
<!--ReasonLIGO-->
```reasonligo
let main = (p : key_hash) : address => {
let c : contract(unit) = Current.implicit_account(p) ;
Current.address(c) ;
let c : contract (unit) = Tezos.implicit_account (p);
Tezos.address (c);
};
```
> Note that `Current.implicit_account` and `Current.address` are
> *deprecated*.
<!--END_DOCUSAURUS_CODE_TABS-->
## Current.self_address() : address
## Self Address
Get the address of the currently running contract.
@ -210,110 +251,137 @@ Get the address of the currently running contract.
<!--PascaLIGO-->
```pascaligo
function main (const p: unit) : address is self_address
function main (const p : unit) : address is Tezos.self_address
```
> Note that `self_address` is *deprecated*.
<!--CameLIGO-->
```cameligo
let main (p: unit) : address = Current.self_address
let main (p : unit) : address = Tezos.self_address
```
> Note that `Current.self_address` is *deprecated*.
<!--ReasonLIGO-->
```reasonligo
let main = (p: unit): address => Current.self_address;
let main = (p : unit) : address => Tezos.self_address;
```
> Note that `Current.self_address` is *deprecated*.
<!--END_DOCUSAURUS_CODE_TABS-->
## Current.implicit_account(p: key_hash) : a' contract
## Implicit Account
Get the default contract associated with an on-chain keypair. This contract
doesn't execute code, instead it exists to receive money on behalf of a keys
owner.
Get the default contract associated with an on-chain key-pair. This
contract does not execute code, instead it exists to receive tokens on
behalf of a key's owner.
<!--DOCUSAURUS_CODE_TABS-->
<!--PascaLIGO-->
```pascaligo
function main (const kh: key_hash) : contract(unit) is implicit_account(kh)
function main (const kh: key_hash) : contract (unit) is
Tezos.implicit_account (kh)
```
> Note that `implicit_account` is *deprecated*.
<!--CameLIGO-->
```cameligo
let main (kh: key_hash) : unit contract = Current.implicit_account kh
let main (kh : key_hash) : unit contract = Tezos.implicit_account kh
```
> Note that `Current.implicit_account` is *deprecated*.
<!--ReasonLIGO-->
```reasonligo
let main = (kh: key_hash): contract(unit) => Current.implicit_account(kh);
let main = (kh : key_hash): contract (unit) =>
Tezos.implicit_account (kh);
```
> Note that `Current.implicit_account` is *deprecated*.
<!--END_DOCUSAURUS_CODE_TABS-->
## Current.source() : address
## Source
Get the _originator_ of the current transaction. That is, if a chain of transactions
led to the current execution get the address that began the chain. Not to be confused
with `Current.sender`, which gives the address of the contract or user which directly
caused the current transaction.
Get the _originator_ (address) of the current transaction. That is, if
a chain of transactions led to the current execution get the address
that began the chain. Not to be confused with `Tezos.sender`, which
gives the address of the contract or user which directly caused the
current transaction.
> ⚠️
> There are a few caveats you should keep in mind before using `SOURCE` over `SENDER`:
> ⚠️ There are a few caveats you should keep in mind before using
> `Tezos.source` over `Tezos.sender`:
>
> 1. SOURCE will never be a contract, so if you want to allow contracts (multisigs etc) to operate your contract, you need to use SENDER
> 2. https://vessenes.com/tx-origin-and-ethereum-oh-my/ -- in general it is somewhat unsafe to assume that SOURCE understands everything that's going to happen in a transaction. If SOURCE transfers to a malicious (or sufficiently attackable) contract, that contract might potentially transfer to yours, without SOURCE's consent. So if you are using SOURCE for authentication, you risk being confused. A good historical example of this is bakers paying out delegation rewards. Naive bakers did (and probably still do) just use tezos-client to transfer to whatever KT1 delegates they had, even if those KT1 were malicious scripts.
> 1. `Tezos.source` will never be a contract, so if you want to allow
> contracts (multisigs etc) to operate your contract, you need to
> use `Tezos.sender`
> 2. https://vessenes.com/tx-origin-and-ethereum-oh-my/ -- in general
> it is somewhat unsafe to assume that `Tezos.source` understands
> everything that is going to happen in a transaction. If
> `Tezos.source` transfers to a malicious (or sufficiently
> attackable) contract, that contract might potentially transfer to
> yours, without `Tezos.source`'s consent. So if you are using
> `Tezos.source` for authentication, you risk being confused. A
> good historical example of this is bakers paying out delegation
> rewards. Naive bakers did (and probably still do) just use
> tezos-client to transfer to whatever KT1 delegates they had, even
> if those KT1 were malicious scripts.
<!--DOCUSAURUS_CODE_TABS-->
<!--PascaLIGO-->
```pascaligo
function main (const p: unit) : address is source
function main (const p: unit) : address is Tezos.source
```
> Note that `source` is *deprecated*.
<!--CameLIGO-->
```cameligo
let main (p: unit) : address = Current.source
let main (p : unit) : address = Tezos.source
```
> Note that `Current.source` is *deprecated*.
<!--ReasonLIGO-->
```reasonligo
let main = (p: unit) : address => Current.source;
let main = (p : unit) : address => Tezos.source;
```
> Note that `Current.source` is *deprecated*.
<!--END_DOCUSAURUS_CODE_TABS-->
## Current.failwith(error_message: string) : a'
## Failwith
Cause the contract to fail with an error message.
> ⚠ Using this currently requires a type annotation on the failwith to unify it
> with the type of whatever other code branch it's on.
> ⚠ Using this currently requires in general a type annotation on the
> `failwith` call.
<!--DOCUSAURUS_CODE_TABS-->
<!--PascaLIGO-->
```pascaligo
function main (const p : int; const s : unit) : list(operation) * unit is
function main (const p : int; const s : unit) : list (operation) * unit is
block {
if p > 10 then failwith("fail") else skip;
if p > 10 then failwith ("Failure.") else skip
}
with ((nil : list(operation)), s)
with ((nil : list (operation)), s)
```
<!--CameLIGO-->
```cameligo
let main (p,s: unit * unit) =
if true then failwith "This contract always fails" else ()
let main (p,s : int * unit) = if p > 10 then failwith "Failure."
```
<!--ReasonLIGO-->
```reasonligo
let main = ((p,s): (unit, unit)) =>
if (true) {
failwith("This contract always fails");
} else {
();
};
let main = ((p,s) : (int, unit)) =>
if (p > 10) { failwith ("Failure."); };
```
<!--END_DOCUSAURUS_CODE_TABS-->

View File

@ -1,9 +1,191 @@
---
id: list-reference
title: List — Ordered collection of a type
title: Lists — Linear Collections
---
## List.size(lst: a' list) : nat
Lists are linear collections of elements of the same type. Linear
means that, in order to reach an element in a list, we must visit all
the elements before (sequential access). Elements can be repeated, as
only their order in the collection matters. The first element is
called the *head*, and the sub-list after the head is called the
*tail*. For those familiar with algorithmic data structure, you can
think of a list a *stack*, where the top is written on the left.
# Defining Lists
<!--DOCUSAURUS_CODE_TABS-->
<!--PascaLIGO-->
```pascaligo group=lists
const empty_list : list (int) = nil // Or list []
const my_list : list (int) = list [1; 2; 2] // The head is 1
```
<!--CameLIGO-->
```cameligo group=lists
let empty_list : int list = []
let my_list : int list = [1; 2; 2] // The head is 1
```
<!--ReasonLIGO-->
```reasonligo group=lists
let empty_list : list (int) = [];
let my_list : list (int) = [1, 2, 2]; // The head is 1
```
<!--END_DOCUSAURUS_CODE_TABS-->
# Adding to Lists
Lists can be augmented by adding an element before the head (or, in
terms of stack, by *pushing an element on top*).
<!--DOCUSAURUS_CODE_TABS-->
<!--PascaLIGO-->
```pascaligo group=lists
const larger_list : list (int) = 5 # my_list // [5;1;2;2]
```
<!--CameLIGO-->
```cameligo group=lists
let larger_list : int list = 5 :: my_list // [5;1;2;2]
```
<!--ReasonLIGO-->
```reasonligo group=lists
let larger_list : list (int) = [5, ...my_list]; // [5,1,2,2]
```
<!--END_DOCUSAURUS_CODE_TABS-->
# Functional Iteration over Lists
A *functional iterator* is a function that traverses a data structure
and calls in turn a given function over the elements of that structure
to compute some value. Another approach is possible in PascaLIGO:
*loops* (see the relevant section).
There are three kinds of functional iterations over LIGO lists: the
*iterated operation*, the *map operation* (not to be confused with the
*map data structure*) and the *fold operation*.
## Iterated Operation over Lists
The first, the *iterated operation*, is an iteration over the list
with a unit return value. It is useful to enforce certain invariants
on the element of a list, or fail.
<!--DOCUSAURUS_CODE_TABS-->
<!--PascaLIGO-->
```pascaligo group=lists
function iter_op (const l : list (int)) : unit is
block {
function iterated (const i : int) : unit is
if i > 3 then Unit else (failwith ("Below range.") : unit)
} with List.iter (iterated, l)
```
> Note that `list_iter` is *deprecated*.
<!--CameLIGO-->
```cameligo group=lists
let iter_op (l : int list) : unit =
let predicate = fun (i : int) -> assert (i > 3)
in List.iter predicate l
```
<!--ReasonLIGO-->
```reasonligo group=lists
let iter_op = (l : list (int)) : unit => {
let predicate = (i : int) => assert (i > 3);
List.iter (predicate, l);
};
```
<!--END_DOCUSAURUS_CODE_TABS-->
## Mapped Operation over Lists
We may want to change all the elements of a given list by applying to
them a function. This is called a *map operation*, not to be confused
with the map data structure.
<!--DOCUSAURUS_CODE_TABS-->
<!--PascaLIGO-->
```pascaligo group=lists
function increment (const i : int): int is i + 1
// Creates a new list with all elements incremented by 1
const plus_one : list (int) = List.map (increment, larger_list)
```
> Note that `list_map` is *deprecated*.
<!--CameLIGO-->
```cameligo group=lists
let increment (i : int) : int = i + 1
// Creates a new list with all elements incremented by 1
let plus_one : int list = List.map increment larger_list
```
<!--ReasonLIGO-->
```reasonligo group=lists
let increment = (i : int) : int => i + 1;
// Creates a new list with all elements incremented by 1
let plus_one : list (int) = List.map (increment, larger_list);
```
<!--END_DOCUSAURUS_CODE_TABS-->
## Folded Operation over Lists
A *folded operation* is the most general of iterations. The folded
function takes two arguments: an *accumulator* and the structure
*element* at hand, with which it then produces a new accumulator. This
enables having a partial result that becomes complete when the
traversal of the data structure is over.
<!--DOCUSAURUS_CODE_TABS-->
<!--PascaLIGO-->
```pascaligo group=lists
function sum (const acc : int; const i : int): int is acc + i
const sum_of_elements : int = List.fold (sum, my_list, 0)
```
> Note that `list_fold` is *deprecated*.
<!--CameLIGO-->
```cameligo group=lists
let sum (acc, i: int * int) : int = acc + i
let sum_of_elements : int = List.fold sum my_list 0
```
<!--ReasonLIGO-->
```reasonligo group=lists
let sum = ((result, i): (int, int)): int => result + i;
let sum_of_elements : int = List.fold (sum, my_list, 0);
```
<!--END_DOCUSAURUS_CODE_TABS-->
# List Length
Get the number of elements in a list.
@ -11,130 +193,19 @@ Get the number of elements in a list.
<!--PascaLIGO-->
```pascaligo
function size_ (const m : list(int)) : nat is size(m)
function size_of (const l : list (int)) : nat is List.length (l)
```
> Note that `size` is *deprecated*.
<!--CameLIGO-->
```cameligo
let size_ (s: int list) : nat = List.size s
let size_of (l : int list) : nat = List.length l
```
<!--ReasonLIGO-->
```reasonligo
let size_ = (s: list(int)): nat => List.size(s);
```
<!--END_DOCUSAURUS_CODE_TABS-->
## List.length(lst: a' list) : nat
Alias of `List.size`.
## List.map(map_function: a' -> b', lst: a' list) : 'b list
Apply an operation defined by `map_function` to each element of a list and return
a list of the modified elements.
<!--DOCUSAURUS_CODE_TABS-->
<!--Pascaligo-->
```pascaligo group=b
function increment(const i: int): int is i + 1;
// Creates a new list with elements incremented by 1
const incremented_list: list(int) = list_map(increment, list 1; 2; 3; end );
```
<!--CameLIGO-->
```cameligo group=b
let increment (i: int) : int = i + 1
(* Creates a new list with elements incremented by 1 *)
let incremented_list: int list = List.map increment [1; 2; 3]
```
<!--ReasonLIGO-->
```reasonligo group=b
let increment = (i: int): int => i + 1;
(* Creates a new list with elements incremented by 1 *)
let incremented_list: list(int) = List.map(increment, [1, 2, 3]);
```
<!--END_DOCUSAURUS_CODE_TABS-->
## List.iter(iter_function: a' -> unit, lst: a' list) : unit
Apply a side effecting function `iter_function` to each element of a list with no
return value. This is useful for asserting that each element of a list satisfies
a particular property.
<!--DOCUSAURUS_CODE_TABS-->
<!--PascaLIGO-->
```pascaligo
function iter_op (const s : list(int)) : int is
begin
var r : int := 0 ;
function aggregate (const i : int) : unit is
begin
r := r + i ;
end with unit ;
list_iter(aggregate, s) ;
end with r
```
<!--CameLIGO-->
```cameligo
let iter_op (s : int list) : unit =
let do_nothing = fun (_: int) -> unit
in List.iter do_nothing s
```
<!--ReasonLIGO-->
```reasonligo
let iter_op = (s: list(int)): unit => {
let do_nothing = (z: int) => unit;
List.iter(do_nothing, s);
};
```
<!--END_DOCUSAURUS_CODE_TABS-->
## List.fold(fold_function: (a' * a') -> a', lst: a' list, acc: a') : 'a
Combine the elements of a list into one value using the operation defined by
`fold_function'. For example, you could define summation by folding a list of
integers. Starting with some initial accumulator value `acc`, the fold:
1. Consumes an element of the list.
2. Passes the accumulator value to `fold_function` along with the element to produce
a new accumulated value.
3. The new accumulated value replaces the previous one.
4. IF there are still elements in the list go back to 1, ELSE return the accumulator
Summation would be defined then by using a `fold_function` that takes two integers and
adds them together. Each step of the fold would consume an element from the list
and add it to the total until you've summed over the list.
<!--DOCUSAURUS_CODE_TABS-->
<!--Pascaligo-->
```pascaligo group=b
function sum(const result: int; const i: int): int is result + i;
const sum_of_a_list: int = list_fold(sum, list 1; 2; 3; end, 0);
```
<!--CameLIGO-->
```cameligo group=b
let sum (result, i: int * int) : int = result + i
let sum_of_a_list: int = List.fold sum [1; 2; 3] 0
```
<!--ReasonLIGO-->
```reasonligo group=b
let sum = ((result, i): (int, int)): int => result + i;
let sum_of_a_list: int = List.fold(sum, [1, 2, 3], 0);
let size_of = (l : list (int)) : nat => List.length (l);
```
<!--END_DOCUSAURUS_CODE_TABS-->

View File

@ -1,392 +1,357 @@
---
id: map-reference
title: Map — Hashmaps that it makes sense to iterate over
title: Maps
---
## Defining A Map Type
*Maps* are a data structure which associate values of the same type to
values of the same type. The former are called *key* and the latter
*values*. Together they make up a *binding*. An additional requirement
is that the type of the keys must be *comparable*, in the Michelson
sense.
# Declaring a Map
<!--DOCUSAURUS_CODE_TABS-->
<!--Pascaligo-->
```pascaligo
<!--PascaLIGO-->
```pascaligo group=maps
type move is int * int
type moveset is map(address, move)
type register is map (address, move)
```
<!--CameLIGO-->
```cameligo
```cameligo group=maps
type move = int * int
type moveset = (address, move) map
type register = (address, move) map
```
<!--ReasonLIGO-->
```reasonligo
```reasonligo group=maps
type move = (int, int);
type moveset = map(address, move);
```
<!--END_DOCUSAURUS_CODE_TABS-->
## Creating A Map
<!--DOCUSAURUS_CODE_TABS-->
<!--Pascaligo-->
```pascaligo
const moves: moveset = map
("tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx": address) -> (1, 2);
("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN": address) -> (0, 3);
end
```
<!--CameLIGO-->
```cameligo
let moves: moveset = Map.literal
[ (("tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx": address), (1, 2)) ;
(("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN": address), (0, 3)) ;
]
```
<!--ReasonLIGO-->
```reasonligo
let moves : moveset =
Map.literal([
("tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx": address, (1, 2)),
("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN": address, (0, 3)),
]);
type register = map (address, move);
```
<!--END_DOCUSAURUS_CODE_TABS-->
## Map.find_opt(k: a', m: (a',b') map) : b' option
Retrieve the value associated with a particular key. This version returns an option
which can either shift logic in response to a missing value or throw an error.
<!--DOCUSAURUS_CODE_TABS-->
<!--Pascaligo-->
```pascaligo
const my_balance : option(move) = moves[("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN": address)];
```
<!--CameLIGO-->
```cameligo
let my_balance : move option = Map.find_opt ("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN": address) moves
```
<!--ReasonLIGO-->
```reasonligo
let my_balance : option(move) =
Map.find_opt("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN": address, moves);
```
<!--END_DOCUSAURUS_CODE_TABS-->
## Map.find(k: a', m: (a', b') map) : b'
Forcefully retrieve the value associated with a particular key. If that value
doesn't exist, this function throws an error.
<!--DOCUSAURUS_CODE_TABS-->
<!--Pascaligo-->
```pascaligo
const my_balance : move = get_force(("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN": address), moves);
```
<!--CameLIGO-->
```cameligo
let my_balance : move = Map.find ("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN": address) moves
```
<!--ReasonLIGO-->
```reasonligo
let my_balance : move =
Map.find("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN": address, moves);
```
<!--END_DOCUSAURUS_CODE_TABS-->
## Map.update(k: a', v: b', m: (a', b') map) : (a', b') map
Change the value associated with a particular key, if that value doesn't already
exist add it.
<!--DOCUSAURUS_CODE_TABS-->
<!--Pascaligo-->
The values of a PascaLIGO map can be updated using the ordinary assignment syntax:
```pascaligo
function set_ (var m: moveset) : moveset is
block {
m[("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN": address)] := (4,9);
} with m
```
<!--Cameligo-->
We can update a map in CameLIGO using the `Map.update` built-in:
```cameligo
let updated_map: moveset = Map.update ("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN": address) (Some (4,9)) moves
```
<!--Reasonligo-->
We can update a map in ReasonLIGO using the `Map.update` built-in:
```reasonligo
let updated_map: moveset = Map.update(("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN": address), Some((4,9)), moves);
```
<!--END_DOCUSAURUS_CODE_TABS-->
## Map.add(k: a', v: b', m: (a', b') map) : (a', b') map
# Creating an Empty Map
<!--DOCUSAURUS_CODE_TABS-->
<!--PascaLIGO-->
```pascaligo
function set_ (var n : int ; var m : map(int, int)) : map(int, int) is block {
m[23] := n ;
} with m
```pascaligo group=maps
const empty : register = map []
```
<!--CameLIGO-->
```cameligo
let add (n,m: int * (int, int) map) : foobar = Map.add 23 n m
```cameligo group=maps
let empty : register = Map.empty
```
<!--ReasonLIGO-->
```reasonligo
let add = (n: int, m: map(int, int)) : foobar => Map.add(23, n, m);
```reasonligo group=maps
let empty : register = Map.empty
```
<!--END_DOCUSAURUS_CODE_TABS-->
## Map.remove(k: a', m: (a', b') map) : (a', b') map
# Creating a Non-empty Map
Remove a key and its associated value from the map.
<!--DOCUSAURUS_CODE_TABS-->
<!--PascaLIGO-->
```pascaligo group=maps
const moves : register =
map [
("tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx" : address) -> (1,2);
("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN" : address) -> (0,3)]
```
<!--CameLIGO-->
```cameligo group=maps
let moves : register =
Map.literal [
(("tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx" : address), (1,2));
(("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN" : address), (0,3))]
```
<!--ReasonLIGO-->
```reasonligo group=maps
let moves : register =
Map.literal ([
("tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx" : address, (1,2)),
("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN" : address, (0,3))]);
```
<!--END_DOCUSAURUS_CODE_TABS-->
# Accessing Map Bindings
<!--DOCUSAURUS_CODE_TABS-->
<!--PascaLIGO-->
```pascaligo group=maps
const my_balance : option (move) =
moves [("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN" : address)]
```
<!--CameLIGO-->
```cameligo group=maps
let my_balance : move option =
Map.find_opt ("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN" : address) moves
```
<!--ReasonLIGO-->
```reasonligo group=maps
let my_balance : option (move) =
Map.find_opt (("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN" : address), moves);
```
<!--END_DOCUSAURUS_CODE_TABS-->
Notice how the value we read is an optional value: this is to force
the reader to account for a missing key in the map. This requires
*pattern matching*.
<!--DOCUSAURUS_CODE_TABS-->
<!--PascaLIGO-->
```pascaligo
function rm (var m : map(int, int)) : map(int, int) is block {
remove 42 from map m
} with m
```pascaligo group=maps
function force_access (const key : address; const moves : register) : move is
case moves[key] of
Some (move) -> move
| None -> (failwith ("No move.") : move)
end
```
<!--CameLIGO-->
```cameligo
let rm (m: (int, int) map) : (int, int) map = Map.remove 42 m
```cameligo group=maps
let force_access (key, moves : address * register) : move =
match Map.find_opt key moves with
Some move -> move
| None -> (failwith "No move." : move)
```
<!--ReasonLIGO-->
```reasonligo
let rm = (m: map(int, int)): map(int, int) => Map.remove(42, m);
```
<!--END_DOCUSAURUS_CODE_TABS-->
## Map.iter(iterator_function: (a', b') -> unit, m: (a', b') map) : unit
Run a function returning unit over the contents of a map's key-value pairs.
For example an assertion.
<!--DOCUSAURUS_CODE_TABS-->
<!--Pascaligo-->
```pascaligo
function iter_op (const m : moveset) : unit is
block {
function aggregate (const i : address ; const j : move) : unit is block
{ if j.1 > 1 then skip else failwith("fail") } with unit
} with map_iter(aggregate, m);
```
<!--CameLIGO-->
```cameligo
let iter_op (m : moveset) : unit =
let assert_eq = fun (i,j: address * move) -> assert (j.0 > 1)
in Map.iter assert_eq m
```
<!--ReasonLIGO-->
```reasonligo
let iter_op = (m: moveset): unit => {
let assert_eq = ((i,j): (address, move)) => assert (j[0] > 1);
Map.iter(assert_eq, m);
```reasonligo group=maps
let force_access = ((key, moves) : (address, register)) : move => {
switch (Map.find_opt (key, moves)) {
| Some (move) => move
| None => failwith ("No move.") : move
}
};
```
<!--END_DOCUSAURUS_CODE_TABS-->
# Updating a Map
## Map.map(mapping_function: (a', b') -> b', m: (a', b') map) : (a', b') map
Update the values associated with every key in the map according to some update
rule `mapping_function`.
Given a map, we may want to add a new binding, remove one, or modify
one by changing the value associated to an already existing key. All
those operations are called *updates*.
<!--DOCUSAURUS_CODE_TABS-->
<!--Pascaligo-->
```pascaligo
function map_op (const m : moveset) : moveset is
<!--PascaLIGO-->
```pascaligo group=maps
function assign (var m : register) : register is
block {
function increment (const i : address ; const j : move) : move is (j.0, j.1 + 1);
} with map_map (increment, m);
m [("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN": address)] := (4,9)
} with m
```
If multiple bindings need to be updated, PascaLIGO offers a *patch
instruction* for maps, similar to that for records.
```pascaligo group=maps
function assignments (var m : register) : register is
block {
patch m with map [
("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN" : address) -> (4,9);
("tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx" : address) -> (1,2)
]
} with m
```
<!--CameLIGO-->
```cameligo
let map_op (m : moveset) : moveset =
let increment = fun (i,j: address * move) -> (j.0, j.1 + 1)
```cameligo group=maps
let assign (m : register) : register =
Map.update
("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN" : address) (Some (4,9)) m
```
Notice the optional value `Some (4,9)` instead of `(4,9)`. If we had
use `None` instead, that would have meant that the binding is removed.
As a particular case, we can only add a key and its associated value.
```cameligo group=maps
let add (m : register) : register =
Map.add
("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN" : address) (4,9) m
```
<!--ReasonLIGO-->
```reasonligo group=maps
let assign = (m : register) : register =>
Map.update
(("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN" : address), Some ((4,9)), m);
```
Notice the optional value `Some (4,9)` instead of `(4,9)`. If we had
use `None` instead, that would have meant that the binding is removed.
As a particular case, we can only add a key and its associated value.
```reasonligo group=maps
let add = (m : register) : register =>
Map.add
(("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN" : address), (4,9), m);
```
<!--END_DOCUSAURUS_CODE_TABS-->
To remove a binding from a map, we need its key.
<!--DOCUSAURUS_CODE_TABS-->
<!--PascaLIGO-->
```pascaligo group=maps
function delete (const key : address; var moves : register) : register is
block {
remove key from map moves
} with moves
```
<!--CameLIGO-->
```cameligo group=maps
let delete (key, moves : address * register) : register =
Map.remove key moves
```
<!--ReasonLIGO-->
```reasonligo group=maps
let delete = ((key, moves) : (address, register)) : register =>
Map.remove (key, moves);
```
<!--END_DOCUSAURUS_CODE_TABS-->
# Functional Iteration over Maps
A *functional iterator* is a function that traverses a data structure
and calls in turn a given function over the elements of that structure
to compute some value. Another approach is possible in PascaLIGO:
*loops* (see the relevant section).
There are three kinds of functional iterations over LIGO maps: the
*iterated operation*, the *map operation* (not to be confused with the
*map data structure*) and the *fold operation*.
## Iterated Operation over Maps
The first, the *iterated operation*, is an iteration over the map with
no return value: its only use is to produce side-effects. This can be
useful if for example you would like to check that each value inside
of a map is within a certain range, and fail with an error otherwise.
<!--DOCUSAURUS_CODE_TABS-->
<!--PascaLIGO-->
```pascaligo group=maps
function iter_op (const m : register) : unit is
block {
function iterated (const i : address; const j : move) : unit is
if j.1 > 3 then Unit else (failwith ("Below range.") : unit)
} with Map.iter (iterated, m)
```
> Note that `map_iter` is *deprecated*.
<!--CameLIGO-->
```cameligo group=maps
let iter_op (m : register) : unit =
let predicate = fun (i,j : address * move) -> assert (j.0 > 3)
in Map.iter predicate m
```
<!--ReasonLIGO-->
```reasonligo group=maps
let iter_op = (m : register) : unit => {
let predicate = ((i,j) : (address, move)) => assert (j[0] > 3);
Map.iter (predicate, m);
};
```
<!--END_DOCUSAURUS_CODE_TABS-->
## Map Operations over Maps
We may want to change all the bindings of a map by applying to them a
function. This is called a *map operation*, not to be confused with
the map data structure. The predefined functional iterator
implementing the map operation over maps is called `Map.map`.
<!--DOCUSAURUS_CODE_TABS-->
<!--PascaLIGO-->
```pascaligo group=maps
function map_op (const m : register) : register is
block {
function increment (const i : address; const j : move) : move is
(j.0, j.1 + 1)
} with Map.map (increment, m)
```
> Note that `map_map` is *deprecated*.
<!--CameLIGO-->
```cameligo group=maps
let map_op (m : register) : register =
let increment = fun (i,j : address * move) -> j.0, j.1 + 1
in Map.map increment m
```
<!--ReasonLIGO-->
```reasonligo
let map_op = (m: moveset): moveset => {
```reasonligo group=maps
let map_op = (m : register) : register => {
let increment = ((i,j): (address, move)) => (j[0], j[1] + 1);
Map.map(increment, m);
Map.map (increment, m);
};
```
<!--END_DOCUSAURUS_CODE_TABS-->
## Map.fold(folding_function: (b', (a', b')) -> b', m: (a', b') map, initial: b') : b'
## Folded Operations over Maps
Combine every value in the map together according to a fold rule `folding_function`.
A *folded operation* is the most general of iterations. The folded
function takes two arguments: an *accumulator* and the structure
*element* at hand, with which it then produces a new accumulator. This
enables having a partial result that becomes complete when the
traversal of the data structure is over.
<!--DOCUSAURUS_CODE_TABS-->
<!--Pascaligo-->
```pascaligo
function fold_op (const m : moveset) : int is
<!--PascaLIGO-->
```pascaligo group=maps
function fold_op (const m : register) : int is
block {
function aggregate (const j : int; const cur : address * (int * int)) : int is j + cur.1.1
} with map_fold(aggregate, m, 5)
function folded (const i : int; const j : address * move) : int is
i + j.1.1
} with Map.fold (folded, m, 5)
```
> Note that `map_fold` is *deprecated*.
<!--CameLIGO-->
```cameligo
let fold_op (m : moveset) : moveset =
let aggregate = fun (i,j: int * (address * (int * int))) -> i + j.1.1
in Map.fold aggregate m 5
```cameligo group=maps
let fold_op (m : register) : register =
let folded = fun (i,j : int * (address * move)) -> i + j.1.1
in Map.fold folded m 5
```
<!--ReasonLIGO-->
```reasonligo
let fold_op = (m: moveset): moveset => {
let aggregate = ((i,j): (int, (address, (int,int)))) => i + j[1][1];
Map.fold(aggregate, m, 5);
```reasonligo group=maps
let fold_op = (m : register) : register => {
let folded = ((i,j): (int, (address, move))) => i + j[1][1];
Map.fold (folded, m, 5);
};
```
<!--END_DOCUSAURUS_CODE_TABS-->
## Map.mem(k: a', m: (a', b') map) : bool
Test whether a particular key `k` exists in a given map `m`.
<!--DOCUSAURUS_CODE_TABS-->
<!--PascaLIGO-->
```pascaligo
function mem (const k: int; const m: map(int, int)) : bool is map_mem(k, m)
```
<!--CameLIGO-->
```cameligo
let mem (k,m: int * (int, int) map) : bool = Map.mem k m
```
<!--ReasonLIGO-->
```reasonligo
let mem = ((k,m): (int, map(int,int))): bool => Map.mem(k, m);
```
<!--END_DOCUSAURUS_CODE_TABS-->
## Map.empty() : (a', b') map
Create an empty map.
<!--DOCUSAURUS_CODE_TABS-->
<!--PascaLIGO-->
```pascaligo
const empty_map : map(int, int) = map end
```
<!--CameLIGO-->
```cameligo
let empty_map : (int, int) map = Map.empty
```
<!--ReasonLIGO-->
```reasonligo
let empty_map: map(int, int) = Map.empty;
```
<!--END_DOCUSAURUS_CODE_TABS-->
## Map.literal(key_value_pair_list: (a', b') list) : (a', b') map
Constructs a map from a list of key-value pair tuples.
<!--DOCUSAURUS_CODE_TABS-->
<!--Pascaligo-->
```pascaligo
const moves: moveset = map
("tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx": address) -> (1, 2);
("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN": address) -> (0, 3);
end
```
<!--CameLIGO-->
```cameligo
let moves: moveset = Map.literal
[ (("tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx": address), (1, 2)) ;
(("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN": address), (0, 3)) ;
]
```
<!--ReasonLIGO-->
```reasonligo
let moves : moveset =
Map.literal([
("tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx": address, (1, 2)),
("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN": address, (0, 3)),
]);
```
<!--END_DOCUSAURUS_CODE_TABS-->
## Map.size(m: (a', b') map) : nat
Get the size of a given map `m`.
<!--DOCUSAURUS_CODE_TABS-->
<!--PascaLIGO-->
```pascaligo
function size_ (const m : map(int, int)) : nat is
block {skip} with (size(m))
```
<!--CameLIGO-->
```cameligo
let size_ (m: (int, int) map) : nat = Map.size m
```
<!--ReasonLIGO-->
```reasonligo
let size_ = (m: map(int, int)): nat => Map.size(m);
```
<!--END_DOCUSAURUS_CODE_TABS-->

View File

@ -1,201 +1,220 @@
---
id: set-reference
title: Set — Unordered unique collection of a type
title: Sets — Unordered unique collection of a type
---
## Defining a set
Sets are unordered collections of values of the same type, like lists
are ordered collections. Like the mathematical sets and lists, sets
can be empty and, if not, elements of sets in LIGO are *unique*,
whereas they can be repeated in a *list*.
# Empty Sets
<!--DOCUSAURUS_CODE_TABS-->
<!--Pascaligo-->
```pascaligo group=a
type int_set is set (int);
const my_set : int_set = set 1; 2; 3 end
<!--PascaLIGO-->
```pascaligo group=sets
const my_set : set (int) = set []
```
<!--CameLIGO-->
```cameligo group=a
type int_set = int set
let my_set : int_set =
Set.add 3 (Set.add 2 (Set.add 1 (Set.empty: int set)))
```cameligo group=sets
let my_set : int set = Set.empty
```
<!--ReasonLIGO-->
```reasonligo group=a
type int_set = set (int);
let my_set : int_set =
Set.add (3, Set.add (2, Set.add (1, Set.empty: set (int))));
```reasonligo group=sets
let my_set : set (int) = Set.empty;
```
<!--END_DOCUSAURUS_CODE_TABS-->
## Set.mem(is_member: a', s: a' set) : bool
Check if a set `s` contains the element `is_member`.
# Non-empty Sets
<!--DOCUSAURUS_CODE_TABS-->
<!--Pascaligo-->
```pascaligo group=a
const contains_three : bool = my_set contains 3
// or alternatively
const contains_three_fn: bool = set_mem (3, my_set);
<!--PascaLIGO-->
```pascaligo group=sets
const my_set : set (int) = set [3; 2; 2; 1]
```
<!--CameLIGO-->
```cameligo group=a
let contains_three: bool = Set.mem 3 my_set
```
<!--ReasonLIGO-->
```reasonligo group=a
let contains_three: bool = Set.mem(3, my_set);
```cameligo group=sets
let my_set : int set =
Set.add 3 (Set.add 2 (Set.add 2 (Set.add 1 (Set.empty : int set))))
```
<!--ReasonLIGO-->
```reasonligo group=sets
let my_set : set (int) =
Set.add (3, Set.add (2, Set.add (2, Set.add (1, Set.empty : set (int)))));
```
<!--END_DOCUSAURUS_CODE_TABS-->
## Set.empty() : a' set
Create a new empty set. Needs to be annotated with the set type.
# Set Membership
<!--DOCUSAURUS_CODE_TABS-->
<!--Pascaligo-->
```pascaligo group=a
const my_set: int_set = set end
const my_set_2: int_set = set_empty
<!--PascaLIGO-->
```pascaligo group=sets
const contains_3 : bool = my_set contains 3
```
<!--CameLIGO-->
```cameligo group=a
let my_set: int_set = (Set.empty: int set)
```cameligo group=sets
let contains_3 : bool = Set.mem 3 my_set
```
<!--ReasonLIGO-->
```reasonligo group=a
let my_set: int_set = (Set.empty: set (int));
```reasonligo group=sets
let contains_3 : bool = Set.mem (3, my_set);
```
<!--END_DOCUSAURUS_CODE_TABS-->
## Set.literal(element_list_literal: 'a list) : 'a set
# Cardinal of Sets
Create a set from the elements of a list. Note that **you must pass a list literal**
to this function, a variable will not work.
The predefined function `Set.size` returns the number of
elements in a given set as follows.
<!--DOCUSAURUS_CODE_TABS-->
<!--PascaLIGO-->
```pascaligo group=sets
const cardinal : nat = Set.size (my_set)
```
> Note that `size` is *deprecated*.
<!--CameLIGO-->
```cameligo group=sets
let cardinal : nat = Set.size my_set
```
<!--ReasonLIGO-->
```reasonligo group=sets
let cardinal : nat = Set.size (my_set);
```
<!--END_DOCUSAURUS_CODE_TABS-->
# Updating Sets
There are two ways to update a set, that is to add or remove from it.
<!--DOCUSAURUS_CODE_TABS-->
<!--PascaLIGO-->
In PascaLIGO, either we create a new set from the given one, or we
modify it in-place. First, let us consider the former way:
```pascaligo group=sets
const larger_set : set (int) = Set.add (4, my_set)
const smaller_set : set (int) = Set.remove (3, my_set)
```
> Note that `set_add` and `set_remove` are *deprecated*.
If we are in a block, we can use an instruction to modify the set
bound to a given variable. This is called a *patch*. It is only
possible to add elements by means of a patch, not remove any: it is
the union of two sets.
```pascaligo group=sets
function update (var s : set (int)) : set (int) is block {
patch s with set [4; 7]
} with s
const new_set : set (int) = update (my_set)
```
<!--CameLIGO-->
```cameligo group=sets
let larger_set : int set = Set.add 4 my_set
let smaller_set : int set = Set.remove 3 my_set
```
<!--ReasonLIGO-->
```reasonligo group=sets
let larger_set : set (int) = Set.add (4, my_set);
let smaller_set : set (int) = Set.remove (3, my_set);
```
<!--END_DOCUSAURUS_CODE_TABS-->
# Functional Iteration over Sets
A *functional iterator* is a function that traverses a data structure
and calls in turn a given function over the elements of that structure
to compute some value. Another approach is possible in PascaLIGO:
*loops* (see the relevant section).
There are three kinds of functional iterations over LIGO maps: the
*iterated operation*, the *mapped operation* (not to be confused with
the *map data structure*) and the *folded operation*.
## Iterated Operation
The first, the *iterated operation*, is an iteration over the map with
no return value: its only use is to produce side-effects. This can be
useful if for example you would like to check that each value inside
of a map is within a certain range, and fail with an error otherwise.
<!--DOCUSAURUS_CODE_TABS-->
<!--PascaLIGO-->
```pascaligo group=sets
function iter_op (const s : set (int)) : unit is
block {
function iterated (const i : int) : unit is
if i > 2 then Unit else (failwith ("Below range.") : unit)
} with Set.iter (iterated, s)
```
> Note that `set_iter` is *deprecated*.
<!--CameLIGO-->
```cameligo group=sets
let iter_op (s : int set) : unit =
let predicate = fun (i : int) -> assert (i > 3)
in Set.iter predicate s
```
<!--ReasonLIGO-->
```reasonligo group=sets
let iter_op = (s : set (int)) : unit => {
let predicate = (i : int) => assert (i > 3);
Set.iter (predicate, s);
};
```
<!--END_DOCUSAURUS_CODE_TABS-->
## Folded Operation
A *folded operation* is the most general of iterations. The folded
function takes two arguments: an *accumulator* and the structure
*element* at hand, with which it then produces a new accumulator. This
enables having a partial result that becomes complete when the
traversal of the data structure is over.
<!--DOCUSAURUS_CODE_TABS-->
<!--PascaLIGO-->
```pascaligo
const s_fb : set(string) = set [
"foo" ;
"bar" ;
]
```pascaligo group=sets
function sum (const acc : int; const i : int): int is acc + i
const sum_of_elements : int = Set.fold (sum, my_set, 0)
```
> Note that `set_fold` is *deprecated*.
It is possible to use a *loop* over a set as well.
```pascaligo group=sets
function loop (const s : set (int)) : int is block {
var sum : int := 0;
for element in set s block {
sum := sum + element
}
} with sum
```
<!--CameLIGO-->
```cameligo
let literal_op (p: unit) : string set =
Set.literal ["foo"; "bar"; "foobar"]
```cameligo group=sets
let sum (acc, i : int * int) : int = acc + i
let sum_of_elements : int = Set.fold sum my_set 0
```
<!--ReasonLIGO-->
```reasonligo
let literal_op = (p: unit) : set(string) => Set.literal(["foo", "bar", "foobar"]);
```
<!--END_DOCUSAURUS_CODE_TABS-->
## Set.add(addition: a', s: a' set) : a' set
Add the element `addition` to a set `s`.
<!--DOCUSAURUS_CODE_TABS-->
<!--Pascaligo-->
```pascaligo group=a
function add_op (const s : set(string)) : set(string) is
begin skip end with set_add("foobar" , s)
```
<!--CameLIGO-->
```cameligo group=a
type int_set = int set
let my_set : int_set =
Set.add 3 (Set.add 2 (Set.add 1 (Set.empty: int set)))
```
<!--ReasonLIGO-->
```reasonligo group=a
type int_set = set (int);
let my_set : int_set =
Set.add (3, Set.add (2, Set.add (1, Set.empty: set (int))));
```
<!--END_DOCUSAURUS_CODE_TABS-->
## Set.remove(removal: a', s: a' set) : a' set
Remove the element `removal` from a set `s`.
<!--DOCUSAURUS_CODE_TABS-->
<!--Pascaligo-->
```pascaligo group=a
const smaller_set: int_set = set_remove(3, my_set);
```
<!--CameLIGO-->
```cameligo group=a
let smaller_set: int_set = Set.remove 3 my_set
```
<!--ReasonLIGO-->
```reasonligo group=a
let smaller_set: int_set = Set.remove(3, my_set);
```
<!--END_DOCUSAURUS_CODE_TABS-->
## Set.fold(folding_function: a' -> a' -> a', s: a' set, initial: a') : a'
Combine the elements of a set into a single value using a folding function.
<!--DOCUSAURUS_CODE_TABS-->
<!--Pascaligo-->
```pascaligo group=a
function sum(const result: int; const i: int): int is result + i;
// Outputs 6
const sum_of_a_set: int = set_fold(sum, my_set, 0);
```
<!--CameLIGO-->
```cameligo group=a
let sum (result, i: int * int) : int = result + i
let sum_of_a_set: int = Set.fold sum my_set 0
```
<!--ReasonLIGO-->
```reasonligo group=a
let sum = (result_i: (int, int)): int => result_i[0] + result_i[1];
let sum_of_a_set: int = Set.fold(sum, my_set, 0);
```reasonligo group=sets
let sum = ((acc, i) : (int, int)) : int => acc + i;
let sum_of_elements : int = Set.fold (sum, my_set, 0);
```
<!--END_DOCUSAURUS_CODE_TABS-->
## Set.size(s: a' set) : nat
Get the number of elements in a set.
<!--DOCUSAURUS_CODE_TABS-->
<!--Pascaligo-->
```pascaligo group=a
const set_size: nat = size (my_set)
```
<!--CameLIGO-->
```cameligo group=a
let set_size: nat = Set.size my_set
```
<!--ReasonLIGO-->
```reasonligo group=a
let set_size: nat = Set.size (my_set);
```
<!--END_DOCUSAURUS_CODE_TABS-->

View File

@ -1,37 +1,46 @@
type taco_supply is record
type taco_supply is
record [
current_stock : nat;
max_price : tez;
end
type taco_shop_storage is map(nat, taco_supply);
max_price : tez
]
const ownerAddress: address = "tz1TGu6TN5GSez2ndXXeDX6LgUDvLzPLqgYV";
const donationAddress: address = "tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx";
type taco_shop_storage is map (nat, taco_supply)
function buy_taco (const taco_kind_index: nat ; var taco_shop_storage : taco_shop_storage) : (list(operation) * taco_shop_storage) is
begin
// Retrieve the taco_kind from the contract's storage
const taco_kind : taco_supply = get_force(taco_kind_index, taco_shop_storage);
const current_purchase_price : tez = taco_kind.max_price / taco_kind.current_stock;
type return is list (operation) * taco_shop_storage
const ownerAddress : address = "tz1TGu6TN5GSez2ndXXeDX6LgUDvLzPLqgYV"
const donationAddress : address = "tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx"
function buy_taco (const taco_kind_index : nat; var taco_shop_storage : taco_shop_storage) : return is
block {
// Retrieve the taco_kind from the contract's storage or fail
const taco_kind : taco_supply =
case taco_shop_storage[taco_kind_index] of
Some (kind) -> kind
| None -> (failwith ("Unknown kind of taco.") : taco_supply)
end;
const current_purchase_price : tez =
taco_kind.max_price / taco_kind.current_stock;
if amount =/= current_purchase_price then
// we won't sell tacos if the amount isn't correct
fail("Sorry, the taco you're trying to purchase has a different price");
else
// Decrease the stock by 1n, because we've just sold one
taco_kind.current_stock := abs(taco_kind.current_stock - 1n);
// We won't sell tacos if the amount is not correct
failwith ("Sorry, the taco you are trying to purchase has a different price");
else skip;
// Decrease the stock by 1n, because we have just sold one
taco_kind.current_stock := abs (taco_kind.current_stock - 1n);
// Update the storage with the refreshed taco_kind
taco_shop_storage[taco_kind_index] := taco_kind;
const receiver: contract(unit) = get_contract(ownerAddress);
const donationReceiver: contract(unit) = get_contract(donationAddress);
const receiver : contract (unit) = get_contract (ownerAddress);
const donationReceiver : contract (unit) = get_contract (donationAddress);
const donationAmount: tez = amount / 10n;
const donationAmount : tez = amount / 10n;
const operations : list(operation) = list
transaction(unit, amount - donationAmount, receiver);
transaction(unit, donationAmount, donationReceiver);
end;
end with (operations, taco_shop_storage)
const operations : list (operation) = list [
transaction (unit, amount - donationAmount, receiver);
transaction (unit, donationAmount, donationReceiver);
]
} with (operations, taco_shop_storage)

View File

@ -3,8 +3,14 @@ id: tezos-taco-shop-payout
title: Paying out profits from the Taco Shop
---
In the [previous tutorial](tutorials/get-started/tezos-taco-shop-smart-contract.md) we've learned how to setup & interact with the LIGO CLI. Followed by implementation of a simple Taco Shop smart contract for our entepreneur Pedro. In this tutorial we'll make sure Pedro has access to tokens that people have spent at his shop when buying tacos.
In the
[previous tutorial](tutorials/get-started/tezos-taco-shop-smart-contract.md)
we have learnt how to setup & interact with the LIGO CLI. Followed an
implementation of a simple Taco Shop smart contract for our
entrepreneur Pedro.
In this tutorial we will make sure Pedro has access to tokens that
people have spent at his shop when buying tacos.
<br/>
<img src="/img/tutorials/get-started/tezos-taco-shop-payout/get-money.svg" width="50%" />
@ -14,133 +20,173 @@ In the [previous tutorial](tutorials/get-started/tezos-taco-shop-smart-contract.
</div>
## Analyzing the current contract
## Analyzing the Current Contract
### **`taco-shop.ligo`**
```pascaligo group=a
type taco_supply is record
current_stock : nat;
max_price : tez;
end
type taco_shop_storage is map(nat, taco_supply);
type taco_supply is record [
current_stock : nat;
max_price : tez
]
function buy_taco (const taco_kind_index: nat ; var taco_shop_storage : taco_shop_storage) :
(list(operation) * taco_shop_storage) is
begin
// Retrieve the taco_kind from the contract's storage
const taco_kind : taco_supply = get_force(taco_kind_index, taco_shop_storage);
const current_purchase_price : tez = taco_kind.max_price / taco_kind.current_stock;
type taco_shop_storage is map (nat, taco_supply)
type return is list (operation) * taco_shop_storage
function buy_taco (const taco_kind_index : nat ; var taco_shop_storage : taco_shop_storage) : return is
block {
// Retrieve the taco_kind from the contract's storage or fail
const taco_kind : taco_supply =
case taco_shop_storage[taco_kind_index] of
Some (kind) -> kind
| None -> (failwith ("Unknown kind of taco.") : taco_supply)
end;
const current_purchase_price : tez =
taco_kind.max_price / taco_kind.current_stock;
if amount =/= current_purchase_price then
// we won't sell tacos if the amount isn't correct
failwith("Sorry, the taco you're trying to purchase has a different price");
else
// Decrease the stock by 1n, because we've just sold one
taco_kind.current_stock := abs(taco_kind.current_stock - 1n);
// We won't sell tacos if the amount is not correct
failwith ("Sorry, the taco you are trying to purchase has a different price");
else skip;
// Decrease the stock by 1n, because we have just sold one
taco_kind.current_stock := abs (taco_kind.current_stock - 1n);
// Update the storage with the refreshed taco_kind
taco_shop_storage[taco_kind_index] := taco_kind;
end with ((nil : list(operation)), taco_shop_storage)
taco_shop_storage[taco_kind_index] := taco_kind
} with ((nil : list (operation)), taco_shop_storage)
```
### Purchase price formula
Pedro's Taco Shop contract currently enables customers to buy tacos, at a computed price based on a simple formula.
### Purchase Price Formula
Pedro's Taco Shop contract currently enables customers to buy tacos,
at a price based on a simple formula.
```pascaligo skip
const current_purchase_price : tez = taco_kind.max_price / taco_kind.current_stock;
const current_purchase_price : tez =
taco_kind.max_price / taco_kind.current_stock
```
### Replacing *spendable* smart contracts
However, due to the [recent protocol upgrade](http://tezos.gitlab.io/mainnet/protocols/004_Pt24m4xi.html) of the Tezos mainnet, Pedro can't access the tokens stored in his Shop's contract directly. This was previously possible via `spendable` smart contracts, which are no longer available in the new protocol. We will have to implement a solution to access tokens from the contract programatically.
### Replacing *spendable* Smart Contracts
However, due to the
[recent protocol upgrade](http://tezos.gitlab.io/mainnet/protocols/004_Pt24m4xi.html)
of the Tezos `mainnet`, Pedro cannot access the tokens stored in his
shop's contract directly. This was previously possible via *spendable
smart contracts*, which are no longer available in the new
protocol. We will have to implement a solution to access tokens from
the contract programatically.
---
## Designing a payout scheme
## Designing a Payout Scheme
Pedro is a standalone bussines owner, and in our case, he doesn't have to split profits / earnings of the taco shop with anyone. So for the sake of simplicity, we'll payout all the earned XTZ directly to Pedro right after a succesful taco purchase.
Pedro is a standalone bussines owner, and in our case, he does not
have to split profits and earnings of the taco shop with anyone. So
for the sake of simplicity, we will payout all the earned XTZ directly
to Pedro right after a succesful purchase.
This means that after all the *purchase conditions* of our contract are met - e.g. correct amount is sent to the contract - we'll not only decrease the supply of the individual purchased *taco kind*, but we'll also transfer this amount in a *subsequent transaction* to Pedro's personal address.
This means that after all the *purchase conditions* of our contract
are met, e.g., the correct amount is sent to the contract, we will not
only decrease the supply of the individual purchased *taco kind*, but
we will also transfer this amount in a *subsequent transaction* to
Pedro's personal address.
## Forging a payout transaction
## Forging a Payout Transaction
### Defining the recipient
In order to send tokens, we will need a receiver address - which in our case will be Pedro's personal account. Additionally we'll wrap the given address as a *`contract(unit)`* - which represents either a contract with no parameters, or an implicit account.
### Defining the Recipient
In order to send tokens, we will need a receiver address, which, in
our case, will be Pedro's personal account. Additionally we will wrap
the given address as a *`contract (unit)`*, which represents either a
contract with no parameters, or an implicit account.
```pascaligo group=ex1
const ownerAddress : address = ("tz1TGu6TN5GSez2ndXXeDX6LgUDvLzPLqgYV" : address);
const receiver : contract(unit) = get_contract(ownerAddress);
const receiver : contract (unit) = get_contract (ownerAddress);
```
> Would you like to learn more about addresses, contracts and operations in LIGO? Check out the [LIGO cheat sheet](api/cheat-sheet.md)
> Would you like to learn more about addresses, contracts and
> operations in LIGO? Check out the
> [LIGO cheat sheet](api/cheat-sheet.md)
### Adding the transaction to the list of output operations
Now we can transfer the `amount` received by `buy_taco` to Pedro's `ownerAddress`. We will do so by forging a `transaction(unit, amount, receiver)` within a list of operations returned at the end of our contract.
### Adding the Transaction to the List of Output Operations
Now we can transfer the amount received by `buy_taco` to Pedro's
`ownerAddress`. We will do so by forging a `transaction (unit, amount,
receiver)` within a list of operations returned at the end of our
contract.
```pascaligo group=ex1
const payoutOperation : operation = transaction(unit, amount, receiver) ;
const operations : list(operation) = list
payoutOperation
end;
const payoutOperation : operation = transaction (unit, amount, receiver) ;
const operations : list (operation) = list [payoutOperation];
```
---
## Finalizing the contract
## Finalizing the Contract
### **`taco-shop.ligo`**
```pascaligo group=b
type taco_supply is record
current_stock : nat;
max_price : tez;
end
type taco_shop_storage is map(nat, taco_supply);
type taco_supply is record [
current_stock : nat;
max_price : tez
]
const ownerAddress: address = ("tz1TGu6TN5GSez2ndXXeDX6LgUDvLzPLqgYV" : address);
type taco_shop_storage is map (nat, taco_supply)
function buy_taco (const taco_kind_index: nat ; var taco_shop_storage : taco_shop_storage) : (list(operation) * taco_shop_storage) is
begin
// Retrieve the taco_kind from the contract's storage
const taco_kind : taco_supply = get_force(taco_kind_index, taco_shop_storage);
const current_purchase_price : tez = taco_kind.max_price / taco_kind.current_stock;
type return is list (operation) * taco_shop_storage
const ownerAddress : address =
("tz1TGu6TN5GSez2ndXXeDX6LgUDvLzPLqgYV" : address)
function buy_taco (const taco_kind_index : nat ; var taco_shop_storage : taco_shop_storage) : return is
block {
// Retrieve the taco_kind from the contract's storage or fail
const taco_kind : taco_supply =
case taco_shop_storage[taco_kind_index] of
Some (kind) -> kind
| None -> (failwith ("Unknown kind of taco.") : taco_supply)
end;
const current_purchase_price : tez =
taco_kind.max_price / taco_kind.current_stock;
if amount =/= current_purchase_price then
// we won't sell tacos if the amount isn't correct
failwith("Sorry, the taco you're trying to purchase has a different price");
else
// Decrease the stock by 1n, because we've just sold one
taco_kind.current_stock := abs(taco_kind.current_stock - 1n);
// We won't sell tacos if the amount is not correct
failwith ("Sorry, the taco you are trying to purchase has a different price");
else skip;
// Decrease the stock by 1n, because we have just sold one
taco_kind.current_stock := abs (taco_kind.current_stock - 1n);
// Update the storage with the refreshed taco_kind
taco_shop_storage[taco_kind_index] := taco_kind;
const receiver : contract(unit) = get_contract(ownerAddress);
const payoutOperation : operation = transaction(unit, amount, receiver);
const operations : list(operation) = list
payoutOperation
end;
end with (operations, taco_shop_storage)
const receiver : contract(unit) = get_contract (ownerAddress);
const payoutOperation : operation = transaction (unit, amount, receiver);
const operations : list(operation) = list [payoutOperation]
} with ((nil : list (operation)), taco_shop_storage)
```
### Dry-run the Contract
### Dry-run the contract
To confirm that our contract is valid, we can dry run it. As a result we see a *new operation* in the list of returned operations to be executed subsequently.
To confirm that our contract is valid, we can dry-run it. As a result,
we see a *new operation* in the list of returned operations to be
executed subsequently.
```pascaligo skip
ligo dry-run taco-shop.ligo --syntax pascaligo --amount 1 buy_taco 1n "map
1n -> record
current_stock = 50n;
max_price = 50000000mutez;
end;
2n -> record
current_stock = 20n;
max_price = 75000000mutez;
end;
end"
ligo dry-run taco-shop.ligo --syntax pascaligo --amount 1 buy_taco 1n "map [
1n -> record [
current_stock = 50n;
max_price = 50tez
];
2n -> record [
current_stock = 20n;
max_price = 75tez
];
]"
```
<img src="/img/tutorials/get-started/tezos-taco-shop-payout/dry-run-1.png" />
@ -150,32 +196,34 @@ end"
<br/>
**Done! Our tokens are no longer locked in the contract, and instead they are sent to Pedro's personal account/wallet.**
**Done! Our tokens are no longer locked in the contract, and instead
they are sent to Pedro's personal account/wallet.**
---
## 👼 Bonus: donating part of the profits
## 👼 Bonus: Donating Part of the Profits
Because Pedro is a member of the (STA) Specialty Taco Association, he has decided to donate **10%** of the earnings to the STA. We'll just add a `donationAddress` to the contract, and compute a 10% donation sum from each taco purchase.
Because Pedro is a member of the Specialty Taco Association (STA), he
has decided to donate **10%** of the earnings to the STA. We will just
add a `donationAddress` to the contract, and compute a 10% donation
sum from each taco purchase.
```pascaligo group=bonus
const ownerAddress: address = ("tz1TGu6TN5GSez2ndXXeDX6LgUDvLzPLqgYV" : address);
const donationAddress: address = ("tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx" : address);
```
const ownerAddress : address = ("tz1TGu6TN5GSez2ndXXeDX6LgUDvLzPLqgYV" : address);
const donationAddress : address = ("tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx" : address);
```pascaligo group=bonus
const receiver : contract(unit) = get_contract(ownerAddress);
const donationReceiver : contract(unit) = get_contract(donationAddress);
const receiver : contract (unit) = get_contract (ownerAddress);
const donationReceiver : contract(unit) = get_contract (donationAddress);
const donationAmount: tez = amount / 10n;
const donationAmount : tez = amount / 10n;
const operations : list(operation) = list
const operations : list (operation) = list [
// Pedro will get 90% of the amount
transaction(unit, amount - donationAmount, receiver);
transaction(unit, donationAmount, donationReceiver);
end;
transaction (unit, amount - donationAmount, receiver);
transaction (unit, donationAmount, donationReceiver)
];
```
This will result into two operations being subsequently executed on the blockchain:
- Donation transfer (10%)
- Pedro's profits (90%)
- Pedro's profits (90%)

View File

@ -1,23 +1,33 @@
type taco_supply is record
type taco_supply is
record [
current_stock : nat;
max_price : tez;
end
type taco_shop_storage is map(nat, taco_supply);
max_price : tez
]
function buy_taco (const taco_kind_index: nat ; var taco_shop_storage : taco_shop_storage) : (list(operation) * taco_shop_storage) is
begin
// Retrieve the taco_kind from the contract's storage
const taco_kind : taco_supply = get_force(taco_kind_index, taco_shop_storage);
const current_purchase_price : tez = taco_kind.max_price / taco_kind.current_stock;
type taco_shop_storage is map (nat, taco_supply)
type return is list (operation) * taco_shop_storage
function buy_taco (const taco_kind_index : nat ; var taco_shop_storage : taco_shop_storage) : return is
block {
// Retrieve the taco_kind from the contract's storage or fail
const taco_kind : taco_supply =
case taco_shop_storage[taco_kind_index] of
Some (kind) -> kind
| None -> (failwith ("Unknown kind of taco.") : taco_supply)
end;
const current_purchase_price : tez =
taco_kind.max_price / taco_kind.current_stock;
if amount =/= current_purchase_price then
// we won't sell tacos if the amount isn't correct
fail("Sorry, the taco you're trying to purchase has a different price");
else
// Decrease the stock by 1n, because we've just sold one
taco_kind.current_stock := abs(taco_kind.current_stock - 1n);
// We won't sell tacos if the amount is not correct
failwith ("Sorry, the taco you are trying to purchase has a different price");
else skip;
// Decrease the stock by 1n, because we have just sold one
taco_kind.current_stock := abs (taco_kind.current_stock - 1n);
// Update the storage with the refreshed taco_kind
taco_shop_storage[taco_kind_index] := taco_kind;
end with ((nil : list(operation)), taco_shop_storage)
taco_shop_storage[taco_kind_index] := taco_kind
} with ((nil : list (operation)), taco_shop_storage)

View File

@ -1,13 +1,18 @@
---
id: tezos-taco-shop-smart-contract
title: Taco shop smart contract
title: The Taco Shop Smart Contract
---
<div>
Meet **Pedro**, our *artisan taco chef* who has decided to open a Taco shop on the Tezos blockchain, using a smart contract. He sells two different kinds of tacos, the **el clásico** and the **especial del chef**.
Meet **Pedro**, our *artisan taco chef*, who has decided to open a
Taco shop on the Tezos blockchain, using a smart contract. He sells
two different kinds of tacos: **el Clásico** and the **Especial
del Chef**.
To help Pedro open his dream taco shop, we'll implement a smart contract, that will manage supply, pricing & sales of his tacos to the consumers.
To help Pedro open his dream taco shop, we will implement a smart
contract that will manage supply, pricing & sales of his tacos to the
consumers.
<br/>
<img src="/img/tutorials/get-started/tezos-taco-shop-smart-contract/taco-stand.svg" width="50%" />
@ -18,95 +23,124 @@ To help Pedro open his dream taco shop, we'll implement a smart contract, that w
## Pricing
Pedro's tacos are a rare delicacy, so their **price goes up**, as the **stock for the day begins to deplete**.
Pedro's tacos are a rare delicacy, so their **price goes up** as the
**stock for the day begins to deplete**.
Each taco kind, has its own `max_price` that it sells for, and a finite supply for the current sales lifecycle.
Each taco kind, has its own `max_price` that it sells for, and a
finite supply for the current sales lifecycle.
> For the sake of simplicity, we won't implement replenishing of the supply after it runs out.
> For the sake of simplicity, we will not implement the replenishing
> of the supply after it has run out.
### Daily offer
### Daily Offer
|**kind** |id |**available_stock**| **max_price**|
|---|---|---|---|
|el clásico | `1n` | `50n` | `50000000mutez` |
|especial del chef | `2n` | `20n` | `75000000mutez` |
|Clásico | `1n` | `50n` | `50tez` |
|Especial del Chef | `2n` | `20n` | `75tez` |
### Calculating the current purchase price
### Calculating the Current Purchase Price
Current purchase price is calculated with the following equation:
The current purchase price is calculated with the following formula:
```pascaligo skip
current_purchase_price = max_price / available_stock
```
#### El clásico
#### El Clásico
|**available_stock**|**max_price**|**current_purchase_price**|
|---|---|---|
| `50n` | `50000000mutez` | `1tz`|
| `20n` | `50000000mutez` | `2.5tz` |
| `5n` | `50000000mutez` | `10tz` |
| `50n` | `50tez` | `1tez`|
| `20n` | `50tez` | `2.5tez` |
| `5n` | `50tez` | `10tez` |
#### Especial del chef
|**available_stock**|**max_price**|**current_purchase_price**|
|---|---|---|
| `20n` | `75000000mutez` | `3.75tz` |
| `10n` | `75000000mutez` | `7.5tz`|
| `5n` | `75000000mutez` | `15tz` |
| `20n` | `75tez` | `3.75tez` |
| `10n` | `75tez` | `7.5tez`|
| `5n` | `75tez` | `15tez` |
---
## Installing LIGO
In this tutorial, we'll use LIGO's dockerized version for the sake of simplicity. You can find the installation instructions [here](intro/installation.md#dockerized-installation-recommended).
In this tutorial, we will use LIGO's dockerized version, for the sake
of simplicity. You can find the installation instructions
[here](intro/installation.md#dockerized-installation-recommended).
The best way to install the dockerized LIGO is as a **global executable** through the installation script, as shown in the screenshot below:
The best way to install the dockerized LIGO is as a **global
executable** through the installation script, as shown in the
screenshot below:
<img src="/img/tutorials/get-started/tezos-taco-shop-smart-contract/install-ligo.png" />
<div style="opacity: 0.7; text-align: center; font-size: 12px; margin-top:-24px;">Installing the <b>next</b> version of LIGO's CLI</div>
## Implementing our first entry point
## Implementing our First `main` Function
> From now on we'll get a bit more technical. If you run into something we have not covered yet - please try checking out the [LIGO cheat sheet](api/cheat-sheet.md) for some extra tips & tricks.
> From now on we will get a bit more technical. If you run into
> something we have not covered yet - please try checking out the
> [LIGO cheat sheet](api/cheat-sheet.md) for some extra tips & tricks.
To begin implementing our smart contract, we need an entry point. We'll call it `main` and it'll specify our contract's storage (`int`) and input parameter (`int`). Of course this is not the final storage/parameter of our contract, but it is something to get us started and test our LIGO installation as well.
To begin implementing our smart contract, we need a *main function*,
that is the first function being executed. We will call it `main` and
it will specify our contract's storage (`int`) and input parameter
(`int`). Of course this is not the final storage/parameter of our
contract, but it is something to get us started and test our LIGO
installation as well.
### `taco-shop.ligo`
```pascaligo group=a
function main (const parameter: int; const contractStorage: int) : (list(operation) * int) is
block {skip} with ((nil : list(operation)), contractStorage + parameter)
function main (const parameter : int; const contractStorage : int) :
list (operation) * int is
((nil : list (operation)), contractStorage + parameter)
```
Let's break down the contract above to make sure we understand each bit of the LIGO syntax:
Let us break down the contract above to make sure we understand each
bit of the LIGO syntax:
- **`function main`** - definition of a function that serves as an entry point
- **`(const parameter : int; const contractStorage : int)`** - parameters passed to the function
- **`const parameter : int`** - parameter provided by a transaction that invokes our contract
- **`const contractStorage : int`** - definition of our storage (`int`)
- **`(list(operation) * int)`** - return type of our function, in our case a touple with a list of operations, and an int
- **`block {skip}`** - our function has no body, so we instruct LIGO to `skip` it
- **`with ((nil : list(operation)), contractStorage + parameter)`** - essentially a return statement
- **`(nil : list(operation))`** - a `nil` value annotated as a list of operations, because that's required by our return type specified above
- **`contractStorage + parameter`** - a new storage value for our contract, sum of previous storage and a transaction parameter
### Running LIGO for the first time
- **`function main`** - definition of the main function, which takes
a the parameter of the contract and the storage
- **`(const parameter : int; const contractStorage : int)`** -
parameters passed to the function: the first is called `parameter`
because it denotes the parameter of a specific invocation of the
contract, the second is the storage
- **`(list (operation) * int)`** - return type of our function, in our
case a tuple with a list of operations, and an `int` (new value for
the storage after a succesful run of the contract)
- **`((nil : list (operation)), contractStorage + parameter)`** -
essentially a return statement
- **`(nil : list (operation))`** - a `nil` value annotated as a list
of operations, because that is required by our return type specified
above
- **`contractStorage + parameter`** - a new storage value for our
contract, sum of previous storage and a transaction parameter
To test that we've installed LIGO correctly, and that `taco-shop.ligo` is a valid contract, we'll dry-run it.
### Running LIGO for the First Time
> Dry-running is a simulated execution of the smart contract, based on a mock storage value and a parameter.
To test that we have installed LIGO correctly, and that
`taco-shop.ligo` is a valid contract, we will dry-run it.
Our contract has a storage of `int` and accepts a parameter that is also an `int`.
> Dry-running is a simulated execution of the smart contract, based on
> a mock storage value and a parameter.
Our contract has a storage of `int` and accepts a parameter that is
also an `int`.
The `dry-run` command requires a few parameters:
- **contract** *(file path)*
- **entrypoint** *(name of the entrypoint function in the contract)*
- **entrypoint** *(name of the main function in the contract)*
- **parameter** *(parameter to execute our contract with)*
- **storage** *(starting storage before our contract's code is executed)*
And outputs what's returned from our entrypoint - in our case a touple containing an empty list (of operations to apply) and the new storage value - which in our case is the sum of the previous storage and the parameter we've used.
It outputs what is returned from our main function: in our case a
tuple containing an empty list (of operations to apply) and the new
storage value, which, in our case, is the sum of the previous storage
and the parameter we have used for the invocation.
```zsh
# Contract: taco-shop.ligo
# Entry point: main
# Main function: main
# Parameter: 4
# Storage: 3
ligo dry-run taco-shop.ligo --syntax pascaligo main 4 3
@ -124,66 +158,80 @@ ligo dry-run taco-shop.ligo --syntax pascaligo main 4 3
---
## Designing Taco shop's contract storage
## Designing the Taco Shop's Contract Storage
We know that Pedro's Taco Shop serves two kinds of tacos, so we'll need to manage stock individually, per kind. Let's define a type, that will keep the `stock` & `max_price` per kind - in a record with two fields. Additionally, we'll want to combine our `taco_supply` type into a map, consisting of the entire offer of Pedro's shop.
We know that Pedro's Taco Shop serves two kinds of tacos, so we will
need to manage stock individually, per kind. Let us define a type,
that will keep the `stock` & `max_price` per kind in a record with two
fields. Additionally, we will want to combine our `taco_supply` type
into a map, consisting of the entire offer of Pedro's shop.
**Taco shop's storage**
```pascaligo group=b
type taco_supply is record
current_stock : nat;
max_price : tez;
end
type taco_supply is record [
current_stock : nat;
max_price : tez
]
type taco_shop_storage is map(nat, taco_supply);
type taco_shop_storage is map (nat, taco_supply)
```
Next step is to update the `main` entry point to include `taco_shop_storage` in its storage - while doing that let's set the `parameter` to `unit` as well to clear things up.
Next step is to update the `main` function to include
`taco_shop_storage` in its storage. In the meanwhile, let us set the
`parameter` to `unit` as well to clear things up.
**`taco-shop.ligo`**
```pascaligo group=b+
type taco_supply is record
current_stock : nat;
max_price : tez;
end
type taco_shop_storage is map(nat, taco_supply);
type taco_supply is record [
current_stock : nat;
max_price : tez
]
function main (const parameter: unit ; const taco_shop_storage : taco_shop_storage) : (list(operation) * taco_shop_storage) is
block {skip} with ((nil : list(operation)), taco_shop_storage)
type taco_shop_storage is map (nat, taco_supply)
type return is list (operation) * taco_shop_storage
function main (const parameter : unit; const taco_shop_storage : taco_shop_storage) : return is
((nil : list (operation)), taco_shop_storage)
```
### Populating our storage in a dry-run
### Populating our Storage in a dry-run
When dry-running a contract, it is crucial to provide a correct initial storage value - in our case the storage is type-checked as `taco_shop_storage`. Reflecting [Pedro's daily offer](tutorials/get-started/tezos-taco-shop-smart-contract.md#daily-offer), our storage's value will be defined as following:
When dry-running a contract, it is crucial to provide a correct
initial storage value. In our case the storage is type-checked as
`taco_shop_storage`. Reflecting
[Pedro's daily offer](tutorials/get-started/tezos-taco-shop-smart-contract.md#daily-offer),
our storage's value will be defined as follows:
**Storage value**
```zsh
map
1n -> record
current_stock = 50n;
max_price = 50000000mutez;
end;
2n -> record
current_stock = 20n;
max_price = 75000000mutez;
end;
end
map [
1n -> record [
current_stock = 50n;
max_price = 50tez
];
2n -> record [
current_stock = 20n;
max_price = 75tez
]
]
```
> Storage value is a map, with two items in it, both items are records identified by natural numbers `1n` & `2n`.
> The storage value is a map with two bindings (entries) distinguished
> by their keys `1n` and `2n`.
**Dry run command with a multi-line storage value**
```zsh
ligo dry-run taco-shop.ligo --syntax pascaligo main unit "map
1n -> record
current_stock = 50n;
max_price = 50000000mutez;
end;
2n -> record
current_stock = 20n;
max_price = 75000000mutez;
end;
end"
ligo dry-run taco-shop.ligo --syntax pascaligo main unit "map [
1n -> record [
current_stock = 50n;
max_price = 50tez
];
2n -> record [
current_stock = 20n;
max_price = 75tez
]
]"
```
<img src="/img/tutorials/get-started/tezos-taco-shop-smart-contract/dry-run-2.png" />
@ -191,62 +239,84 @@ end"
<br/>
*If everything went as expected, the `dry-run` command will return an empty list of operations and the contract's current storage, which is the map of products we've defined based on the daily offer of Pedro's taco shop.*
*If everything went as expected, the `dry-run` command will return an
empty list of operations and the contract's current storage, which is
the map of the products we have defined based on the daily offer of
Pedro's taco shop.*
---
## Providing an entrypoint for buying tacos
## Providing another Access Function for Buying Tacos
Now that we have our stock well defined in form of storage, we can move on to the actual sales. We'll replace the `main` entrypoint with `buy_taco`, that takes an `id` - effectively a key from our `taco_shop_storage` map. This will allow us to calculate pricing, and if the sale is successful - then we can reduce our stock - because we have sold a taco!
Now that we have our stock well defined in form of storage, we can
move on to the actual sales. The `main` function will take a key `id`
from our `taco_shop_storage` map and will be renamed `buy_taco` for
more readability. This will allow us to calculate pricing, and if the
sale is successful, we will be able to reduce our stock because we
have sold a taco!
### Selling the tacos for free
### Selling the Tacos for Free
Let's start by customizing our contract a bit, we will:
Let is start by customizing our contract a bit, we will:
- rename the entrypoint from `main` to `buy_taco`
- rename `parameter` to `taco_kind_index`
- change `taco_shop_storage` to a `var` instead of a `const`, because we'll want to modify it
- change `taco_shop_storage` to a `var` instead of a `const`, because
we will want to modify it
**`taco-shop.ligo`**
```pascaligo group=c
type taco_supply is record
type taco_supply is record [
current_stock : nat;
max_price : tez;
end
type taco_shop_storage is map(nat, taco_supply);
max_price : tez
]
type taco_shop_storage is map (nat, taco_supply)
function buy_taco (const taco_kind_index: nat ; var taco_shop_storage : taco_shop_storage) : (list(operation) * taco_shop_storage) is
block { skip } with ((nil : list(operation)), taco_shop_storage)
type return is list (operation) * taco_shop_storage
function buy_taco (const taco_kind_index : nat; var taco_shop_storage : taco_shop_storage) : return is
((nil : list (operation)), taco_shop_storage)
```
#### Decreasing `current_stock` when a taco is sold
#### Decreasing `current_stock` when a Taco is Sold
In order to decrease the stock in our contract's storage for a specific taco kind, a few things needs to happen:
In order to decrease the stock in our contract's storage for a
specific taco kind, a few things needs to happen:
- retrieve the `taco_kind` from our storage, based on the `taco_kind_index` provided
- subtract the `taco_kind.current_stock` by `1n`
- we can find the absolute (`nat`) value of the subtraction above by using `abs`, otherwise we'd be left with an `int`
- update the storage, and return it
- retrieve the `taco_kind` from our storage, based on the
`taco_kind_index` provided;
- subtract the `taco_kind.current_stock` by `1n`;
- we can find the absolute value of the subtraction above by
calling `abs` (otherwise we would be left with an `int`);
- update the storage, and return it.
**`taco-shop.ligo`**
```pascaligo group=d
type taco_supply is record
current_stock : nat;
max_price : tez;
end
type taco_shop_storage is map(nat, taco_supply);
type taco_supply is record [
current_stock : nat;
max_price : tez
]
type taco_shop_storage is map (nat, taco_supply)
type return is list (operation) * taco_shop_storage
function buy_taco (const taco_kind_index : nat; var taco_shop_storage : taco_shop_storage) : return is
block {
// Retrieve the taco_kind from the contract's storage or fail
const taco_kind : taco_supply =
case taco_shop_storage[taco_kind_index] of
Some (kind) -> kind
| None -> (failwith ("Unknown kind of taco.") : taco_supply)
end;
// Decrease the stock by 1n, because we have just sold one
taco_kind.current_stock := abs (taco_kind.current_stock - 1n);
function buy_taco (const taco_kind_index: nat ; var taco_shop_storage : taco_shop_storage) : (list(operation) * taco_shop_storage) is
begin
// Retrieve the taco_kind from the contract's storage
const taco_kind : taco_supply = get_force(taco_kind_index, taco_shop_storage);
// Decrease the stock by 1n, because we've just sold one
taco_kind.current_stock := abs(taco_kind.current_stock - 1n);
// Update the storage with the refreshed taco_kind
taco_shop_storage[taco_kind_index] := taco_kind;
end with ((nil : list(operation)), taco_shop_storage)
taco_shop_storage[taco_kind_index] := taco_kind
} with ((nil : list (operation)), taco_shop_storage)
```
<img src="/img/tutorials/get-started/tezos-taco-shop-smart-contract/dry-run-3.png" />
@ -254,67 +324,85 @@ function buy_taco (const taco_kind_index: nat ; var taco_shop_storage : taco_sho
<br/>
### Making sure we get paid for our tacos
### Making Sure We Get Paid for Our Tacos
In order to make Pedro's taco shop profitable, he needs to stop giving away tacos for free. When a contract is invoked via a transaction, an amount of tezzies to be sent can be specified as well. This amount is accessible within LIGO as `amount`.
In order to make Pedro's taco shop profitable, he needs to stop giving
away tacos for free. When a contract is invoked via a transaction, an
amount of tezzies to be sent can be specified as well. This amount is
accessible within LIGO as `amount`.
To make sure we get paid, we will:
- calculate a `current_purchase_price` based on the [equation specified earlier](tutorials/get-started/tezos-taco-shop-smart-contract.md#calculating-the-current-purchase-price)
- check if the sent `amount` matches the `current_purchase_price`
- if not, then our contract will `fail` and stop executing
- if yes, stock for the given `taco_kind` will be decreased and the payment accepted
- calculate a `current_purchase_price` based on the
[equation specified earlier](tutorials/get-started/tezos-taco-shop-smart-contract.md#calculating-the-current-purchase-price)
- check if the sent `amount` matches the `current_purchase_price`:
- if not, then our contract will fail (`failwith`)
- otherwise, stock for the given `taco_kind` will be decreased and
the payment accepted
**`taco-shop.ligo`**
```pascaligo group=e
type taco_supply is record
current_stock : nat;
max_price : tez;
end
type taco_shop_storage is map(nat, taco_supply);
type taco_supply is record [
current_stock : nat;
max_price : tez
]
function buy_taco (const taco_kind_index: nat ; var taco_shop_storage : taco_shop_storage) : (list(operation) * taco_shop_storage) is
begin
// Retrieve the taco_kind from the contract's storage
const taco_kind : taco_supply = get_force(taco_kind_index, taco_shop_storage);
const current_purchase_price : tez = taco_kind.max_price / taco_kind.current_stock;
type taco_shop_storage is map (nat, taco_supply)
type return is list (operation) * taco_shop_storage
function buy_taco (const taco_kind_index : nat ; var taco_shop_storage : taco_shop_storage) : return is
block {
// Retrieve the taco_kind from the contract's storage or fail
const taco_kind : taco_supply =
case taco_shop_storage[taco_kind_index] of
Some (kind) -> kind
| None -> (failwith ("Unknown kind of taco.") : taco_supply)
end;
const current_purchase_price : tez =
taco_kind.max_price / taco_kind.current_stock;
if amount =/= current_purchase_price then
// we won't sell tacos if the amount isn't correct
failwith("Sorry, the taco you're trying to purchase has a different price");
else
// Decrease the stock by 1n, because we've just sold one
taco_kind.current_stock := abs(taco_kind.current_stock - 1n);
// We won't sell tacos if the amount is not correct
failwith ("Sorry, the taco you are trying to purchase has a different price");
else skip;
// Decrease the stock by 1n, because we have just sold one
taco_kind.current_stock := abs (taco_kind.current_stock - 1n);
// Update the storage with the refreshed taco_kind
taco_shop_storage[taco_kind_index] := taco_kind;
end with ((nil : list(operation)), taco_shop_storage)
taco_shop_storage[taco_kind_index] := taco_kind
} with ((nil : list (operation)), taco_shop_storage)
```
In order to test the `amount` sent, we'll use the `--amount` option of `dry-run`:
In order to test the `amount` sent, we will use the `--amount` option
of `dry-run`:
```zsh
ligo dry-run taco-shop.ligo --syntax pascaligo --amount 1 buy_taco 1n "map
1n -> record
current_stock = 50n;
max_price = 50000000mutez;
end;
2n -> record
current_stock = 20n;
max_price = 75000000mutez;
end;
end"
ligo dry-run taco-shop.ligo --syntax pascaligo --amount 1 buy_taco 1n "map [
1n -> record [
current_stock = 50n;
max_price = 50tez
];
2n -> record [
current_stock = 20n;
max_price = 75tez
]
]"
```
**Purchasing a taco with 1.0tz**
** Purchasing a Taco with 1tez **
<img src="/img/tutorials/get-started/tezos-taco-shop-smart-contract/dry-run-4.png" />
<div style="opacity: 0.7; text-align: center; font-size: 12px; margin-top:-24px;">Stock decreases after selling a taco, if the right amount of tezzies is provided</div>
<br/>
**Attempting to purchase a taco with 0.7tz**
**Attempting to Purchase a Taco with 0.7tez**
<img src="/img/tutorials/get-started/tezos-taco-shop-smart-contract/dry-run-5.png" />
<div style="opacity: 0.7; text-align: center; font-size: 12px; margin-top:-24px;">Stock does not decrease after a purchase attempt with a lower than required amount.</div>
<div style="opacity: 0.7; text-align: center; font-size: 12px;
margin-top:-24px;">Stock does not decrease after a purchase attempt
with an insufficient payment.</div>
<br/>
@ -322,9 +410,10 @@ end"
---
## 💰 Bonus: *Accepting tips above the taco purchase price*
## 💰 Bonus: *Accepting Tips above the Taco Purchase Price*
If you'd like to accept tips in your contract as well, simply change the following line, depending on your preference.
If you would like to accept tips in your contract, simply change the
following line, depending on your preference.
**Without tips**
```pascaligo skip

View File

@ -1,10 +0,0 @@
type action is
| Increment of int
| Decrement of int
function main (const p : action ; const s : int) : (list(operation) * int) is
block {skip} with ((nil : list(operation)),
case p of
| Increment n -> s + n
| Decrement n -> s - n
end)

View File

@ -1,10 +0,0 @@
function multiply (const a : int ; const b : int) : int is
begin
const result : int = a * b ;
end with result
function add (const a : int ; const b : int) : int is
block { skip } with a + b
function main (const p : unit ; const s : unit) : (list(operation) * unit) is
block {skip} with ((nil : list(operation)), s)

View File

@ -1,16 +0,0 @@
type action is
| Increment of int
| Decrement of int
function add (const a : int ; const b : int) : int is
block { skip } with a + b
function subtract (const a : int ; const b : int) : int is
block { skip } with a - b
function main (const p : action ; const s : int) : (list(operation) * int) is
block {skip} with ((nil : list(operation)),
case p of
| Increment n -> add(s, n)
| Decrement n -> subtract(s, n)
end)

View File

@ -1,5 +0,0 @@
const four : int = 4;
const name : string = "John Doe";
function main (const p : unit ; const s : unit) : (list(operation) * unit) is
block {skip} with ((nil : list(operation)), s)

View File

@ -24,9 +24,17 @@
"version-next-advanced/include",
"version-next-advanced/first-contract"
],
"API": [
"API & Reference": [
"version-next-api/cli-commands",
"version-next-api/cheat-sheet"
"version-next-api/cheat-sheet",
"version-next-reference/big-map-reference",
"version-next-reference/bytes-reference",
"version-next-reference/crypto-reference",
"version-next-reference/current-reference",
"version-next-reference/list-reference",
"version-next-reference/map-reference",
"version-next-reference/set-reference",
"version-next-reference/string-reference"
]
},
"version-next-contributors-docs": {

View File

@ -20,3 +20,4 @@ $HOME/git/ligo/vendors/ligo-utils/simple-utils/region.ml
../shared/LexerUnit.ml
../shared/ParserUnit.ml
Stubs/Simple_utils.ml
$HOME/git/ligo/_build/default/src/passes/1-parser/cameligo/ParErr.ml

View File

@ -266,7 +266,6 @@ let keywords = [
let reserved =
let open SSet in
empty
|> add "and"
|> add "as"
|> add "asr"
|> add "class"

View File

@ -1,5 +1,7 @@
(* Driver for the CameLIGO lexer *)
module Region = Simple_utils.Region
module IO =
struct
let ext = ".mligo"

View File

@ -593,10 +593,14 @@ core_expr:
| par(expr ":" type_expr {$1,$2,$3}) { EAnnot $1 }
module_field:
module_name "." field_name {
module_name "." module_fun {
let region = cover $1.region $3.region in
{region; value = $1.value ^ "." ^ $3.value} }
module_fun:
field_name { $1 }
| "or" { {value="or"; region=$1} }
projection:
struct_name "." nsepseq(selection,".") {
let start = $1.region in

View File

@ -24,3 +24,4 @@ $HOME/git/ligo/vendors/ligo-utils/simple-utils/region.ml
../shared/Memo.mli
../shared/Memo.ml
Stubs/Simple_utils.ml
$HOME/git/ligo/_build/default/src/passes/1-parser/pascaligo/ParErr.ml

View File

@ -98,11 +98,12 @@ sepseq(X,Sep):
(* Inlines *)
%inline var : "<ident>" { $1 }
%inline type_name : "<ident>" { $1 }
%inline fun_name : "<ident>" { $1 }
%inline field_name : "<ident>" { $1 }
%inline struct_name : "<ident>" { $1 }
%inline var : "<ident>" { $1 }
%inline type_name : "<ident>" { $1 }
%inline fun_name : "<ident>" { $1 }
%inline field_name : "<ident>" { $1 }
%inline struct_name : "<ident>" { $1 }
%inline module_name : "<constr>" { $1 }
(* Main *)
@ -829,7 +830,7 @@ core_expr:
"<int>" { EArith (Int $1) }
| "<nat>" { EArith (Nat $1) }
| "<mutez>" { EArith (Mutez $1) }
| var { EVar $1 }
| "<ident>" | module_field { EVar $1 }
| "<string>" { EString (String $1) }
| "<bytes>" { EBytes $1 }
| "False" { ELogic (BoolExpr (False $1)) }
@ -902,13 +903,32 @@ path:
var { Name $1 }
| projection { Path $1 }
module_field:
module_name "." module_fun {
let region = cover $1.region $3.region in
{region; value = $1.value ^ "." ^ $3.value} }
module_fun:
field_name { $1 }
| "map" { {value="map"; region=$1} }
| "or" { {value="or"; region=$1} }
| "and" { {value="and"; region=$1} }
| "remove" { {value="remove"; region=$1} }
projection:
struct_name "." nsepseq(selection,".") {
let stop = nsepseq_to_region selection_to_region $3 in
let region = cover $1.region stop
and value = {struct_name = $1;
selector = $2;
field_path = $3}
and value = {struct_name=$1; selector=$2; field_path=$3}
in {region; value}
}
| module_name "." field_name "." nsepseq(selection,".") {
let value = $1.value ^ "." ^ $3.value in
let struct_name = {$1 with value} in
let start = $1.region in
let stop = nsepseq_to_region selection_to_region $5 in
let region = cover start stop in
let value = {struct_name; selector=$4; field_path=$5}
in {region; value} }
selection:
@ -939,31 +959,26 @@ record_expr:
update_record:
path "with" ne_injection("record",field_path_assignment){
let region = cover (path_to_region $1) $3.region in
let value = {
record = $1;
kwd_with = $2;
updates = $3}
let value = {record=$1; kwd_with=$2; updates=$3}
in {region; value} }
field_assignment:
field_name "=" expr {
let region = cover $1.region (expr_to_region $3)
and value = {field_name = $1;
equal = $2;
field_expr = $3}
and value = {field_name=$1; equal=$2; field_expr=$3}
in {region; value} }
field_path_assignment:
nsepseq(field_name,".") "=" expr {
let region = cover (nsepseq_to_region (fun x -> x.region) $1) (expr_to_region $3)
and value = {field_path = $1;
equal = $2;
field_expr = $3}
let start = nsepseq_to_region (fun x -> x.region) $1
and stop = expr_to_region $3 in
let region = cover start stop
and value = {field_path=$1; equal=$2; field_expr=$3}
in {region; value} }
fun_call:
fun_name arguments {
fun_name arguments
| module_field arguments {
let region = cover $1.region $2.region
in {region; value = (EVar $1),$2} }

File diff suppressed because it is too large Load Diff

View File

@ -25,4 +25,5 @@ Stubs/Parser_cameligo.ml
../cameligo/ParserLog.mli
../cameligo/ParserLog.ml
../cameligo/Scoping.mli
../cameligo/Scoping.ml
../cameligo/Scoping.ml
$HOME/git/ligo/_build/default/src/passes/1-parser/reasonligo/ParErr.ml

View File

@ -238,12 +238,9 @@ let keywords = [
(fun reg -> True reg);
(fun reg -> Type reg)]
(* See: http://caml.inria.fr/pub/docs/manual-ocaml/lex.html#sec86 and
https://github.com/facebook/reason/blob/master/src/reason-parser/reason_parser.mly *)
let reserved =
let open SSet in
empty
|> add "and"
|> add "as"
|> add "asr"
|> add "begin"

View File

@ -1,5 +1,7 @@
(* Driver for the ReasonLIGO lexer *)
module Region = Simple_utils.Region
module IO =
struct
let ext = ".religo"

View File

@ -24,22 +24,22 @@ type 'a sequence_or_record =
let (<@) f g x = f (g x)
(**
Covert nsepseq to a chain of TFun's.
(**
Covert nsepseq to a chain of TFun's.
Necessary to handle cases like:
`type foo = (int, int) => int;`
*)
let rec nsepseq_to_curry hd rest =
match hd, rest with
| hd, (sep, item) :: rest ->
let rec nsepseq_to_curry hd rest =
match hd, rest with
| hd, (sep, item) :: rest ->
let start = type_expr_to_region hd in
let stop = nsepseq_to_region type_expr_to_region (hd, rest) in
let region = cover start stop in
let region = cover start stop in
TFun {
value = hd, sep, (nsepseq_to_curry item rest);
value = hd, sep, (nsepseq_to_curry item rest);
region
}
}
| hd, [] -> hd
(* END HEADER *)
@ -178,34 +178,34 @@ type_expr:
cartesian | sum_type | record_type { $1 }
type_expr_func:
"=>" cartesian {
"=>" cartesian {
$1, $2
}
cartesian:
core_type { $1 }
| type_name type_expr_func {
| type_name type_expr_func {
let (arrow, c) = $2 in
let value = TVar $1, arrow, c in
let region = cover $1.region (type_expr_to_region c) in
TFun { region; value }
}
| "(" cartesian ")" type_expr_func {
| "(" cartesian ")" type_expr_func {
let (arrow, c) = $4 in
let value = $2, arrow, c in
let region = cover $1 (type_expr_to_region c) in
TFun { region; value }
}
| "(" cartesian "," nsepseq(cartesian,",") ")" type_expr_func? {
match $6 with
| Some (arrow, c) ->
match $6 with
| Some (arrow, c) ->
let (hd, rest) = Utils.nsepseq_cons $2 $3 $4 in
let rest = rest @ [(arrow, c)] in
let rest = rest @ [(arrow, c)] in
nsepseq_to_curry hd rest
| None ->
let value = Utils.nsepseq_cons $2 $3 $4 in
let region = cover $1 $5 in
TProd {region; value}
TProd {region; value}
}
core_type:
@ -515,30 +515,30 @@ fun_expr:
_
}; _ }; region} ->
let expr_to_type = function
let expr_to_type = function
| EVar v -> TVar v
| e -> let open! SyntaxError
in raise (Error (WrongFunctionArguments e))
in
let type_expr = (
match type_expr with
| TProd {value; _} ->
| TProd {value; _} ->
let (hd, rest) = value in
let rest = rest @ [(arrow, expr_to_type body)] in
nsepseq_to_curry hd rest
| e ->
let rest = rest @ [(arrow, expr_to_type body)] in
nsepseq_to_curry hd rest
| e ->
TFun {
value = e, arrow, expr_to_type body;
region = fun_region
}
}
)
in
in
PTyped {
value = {
pattern;
colon;
type_expr
};
};
region;
}, []
| EPar {value = {inside = fun_arg; _ }; _} ->
@ -552,7 +552,7 @@ fun_expr:
arg_to_pattern (fst fun_args), bindings
| EUnit _ as e ->
arg_to_pattern e, []
| EVar _ as e ->
| EVar _ as e ->
arg_to_pattern e, []
| e -> let open! SyntaxError
in raise (Error (WrongFunctionArguments e))
@ -834,10 +834,13 @@ core_expr:
| par(expr) { EPar $1 }
module_field:
module_name "." field_name {
let region = cover $1.region $3.region
and value = $1.value ^ "." ^ $3.value
in {region; value} }
module_name "." module_fun {
let region = cover $1.region $3.region in
{region; value = $1.value ^ "." ^ $3.value} }
module_fun:
field_name { $1 }
| "or" { {value="or"; region=$1} }
selection:
"[" "<int>" "]" selection {

View File

@ -499,7 +499,7 @@ module Make (Token: TOKEN) : (S with module Token = Token) =
| Error Token.Non_canonical_zero ->
fail region Non_canonical_zero
let mk_tz state buffer =
let mk_tez state buffer =
let region, lexeme, state = sync state buffer in
let lexeme = Str.string_before lexeme (String.index lexeme 't') in
let lexeme = Z.mul (Z.of_int 1_000_000) (Z.of_string lexeme) in
@ -508,7 +508,7 @@ module Make (Token: TOKEN) : (S with module Token = Token) =
| Error Token.Non_canonical_zero ->
fail region Non_canonical_zero
let format_tz s =
let format_tez s =
match String.index s '.' with
index ->
let len = String.length s in
@ -522,10 +522,11 @@ module Make (Token: TOKEN) : (S with module Token = Token) =
if Z.equal Z.one should_be_1 then Some (Q.num mutez) else None
| exception Not_found -> assert false
let mk_tz_decimal state buffer =
let mk_tez_decimal state buffer =
let region, lexeme, state = sync state buffer in
let lexeme = Str.(global_replace (regexp "_") "" lexeme) in
let lexeme = Str.string_before lexeme (String.index lexeme 't') in
match format_tz lexeme with
match format_tez lexeme with
None -> assert false
| Some tz ->
match Token.mk_mutez (Z.to_string tz ^ "mutez") region with
@ -573,7 +574,7 @@ let nl = ['\n' '\r'] | "\r\n"
let blank = ' ' | '\t'
let digit = ['0'-'9']
let natural = digit | digit (digit | '_')* digit
let decimal = digit+ '.' digit+
let decimal = natural '.' natural
let small = ['a'-'z']
let capital = ['A'-'Z']
let letter = small | capital
@ -624,9 +625,9 @@ and scan state = parse
| natural 'n' { mk_nat state lexbuf |> enqueue }
| natural "mutez" { mk_mutez state lexbuf |> enqueue }
| natural "tz"
| natural "tez" { mk_tz state lexbuf |> enqueue }
| natural "tez" { mk_tez state lexbuf |> enqueue }
| decimal "tz"
| decimal "tez" { mk_tz_decimal state lexbuf |> enqueue }
| decimal "tez" { mk_tez_decimal state lexbuf |> enqueue }
| natural { mk_int state lexbuf |> enqueue }
| symbol { mk_sym state lexbuf |> enqueue }
| eof { mk_eof state lexbuf |> enqueue }

View File

@ -35,8 +35,8 @@ module Simplify = struct
let unit_expr = make_t @@ T_constant TC_unit
let type_constants s =
match s with
| "chain_id" -> ok TC_chain_id
match s with
"chain_id" -> ok TC_chain_id
| "unit" -> ok TC_unit
| "string" -> ok TC_string
| "bytes" -> ok TC_bytes
@ -50,95 +50,196 @@ module Simplify = struct
| "key_hash" -> ok TC_key_hash
| "signature" -> ok TC_signature
| "timestamp" -> ok TC_timestamp
| _ -> simple_fail @@ "Not a type_constant " ^ s
| _ -> simple_fail @@ "Not a built-in type (" ^ s ^ ")."
let type_operators s =
match s with
| "list" -> ok @@ TC_list unit_expr
match s with
"list" -> ok @@ TC_list unit_expr
| "option" -> ok @@ TC_option unit_expr
| "set" -> ok @@ TC_set unit_expr
| "map" -> ok @@ TC_map (unit_expr,unit_expr)
| "big_map" -> ok @@ TC_big_map (unit_expr,unit_expr)
| "contract" -> ok @@ TC_contract unit_expr
| _ -> simple_fail @@ "Not a typ_operator " ^ s
| _ -> simple_fail @@ "Not a built-in type (" ^ s ^ ")."
module Pascaligo = struct
let constants = function
| "assert" -> ok C_ASSERTION
| "get_chain_id" -> ok C_CHAIN_ID
| "transaction" -> ok C_CALL
| "get_contract" -> ok C_CONTRACT
| "get_contract_opt"-> ok C_CONTRACT_OPT
| "get_entrypoint" -> ok C_CONTRACT_ENTRYPOINT
| "get_entrypoint_opt" -> ok C_CONTRACT_ENTRYPOINT_OPT
| "size" -> ok C_SIZE
| "int" -> ok C_INT
| "abs" -> ok C_ABS
| "is_nat" -> ok C_IS_NAT
| "amount" -> ok C_AMOUNT
| "balance" -> ok C_BALANCE
| "now" -> ok C_NOW
| "unit" -> ok C_UNIT
| "source" -> ok C_SOURCE
| "sender" -> ok C_SENDER
| "failwith" -> ok C_FAILWITH
| "bitwise_or" -> ok C_OR
| "bitwise_and" -> ok C_AND
| "bitwise_xor" -> ok C_XOR
| "bitwise_lsl" -> ok C_LSL
| "bitwise_lsr" -> ok C_LSR
| "string_concat" -> ok C_CONCAT
| "string_slice" -> ok C_SLICE
| "crypto_check" -> ok C_CHECK_SIGNATURE
| "crypto_hash_key" -> ok C_HASH_KEY
| "bytes_concat" -> ok C_CONCAT
| "bytes_slice" -> ok C_SLICE
| "bytes_pack" -> ok C_BYTES_PACK
| "bytes_unpack" -> ok C_BYTES_UNPACK
| "set_empty" -> ok C_SET_EMPTY
| "set_mem" -> ok C_SET_MEM
| "set_add" -> ok C_SET_ADD
| "set_remove" -> ok C_SET_REMOVE
| "set_iter" -> ok C_SET_ITER
| "set_fold" -> ok C_SET_FOLD
| "list_iter" -> ok C_LIST_ITER
| "list_fold" -> ok C_LIST_FOLD
| "list_map" -> ok C_LIST_MAP
| "get_force" -> ok C_MAP_FIND
| "map_iter" -> ok C_MAP_ITER
| "map_map" -> ok C_MAP_MAP
| "map_fold" -> ok C_MAP_FOLD
| "map_remove" -> ok C_MAP_REMOVE
| "map_update" -> ok C_MAP_UPDATE
| "map_get" -> ok C_MAP_FIND_OPT
| "map_mem" -> ok C_MAP_MEM
| "sha_256" -> ok C_SHA256
| "sha_512" -> ok C_SHA512
| "blake2b" -> ok C_BLAKE2b
| "cons" -> ok C_CONS
| "EQ" -> ok C_EQ
| "NEQ" -> ok C_NEQ
| "NEG" -> ok C_NEG
| "ADD" -> ok C_ADD
| "SUB" -> ok C_SUB
| "TIMES" -> ok C_MUL
| "DIV" -> ok C_DIV
| "MOD" -> ok C_MOD
| "NOT" -> ok C_NOT
| "AND" -> ok C_AND
| "OR" -> ok C_OR
| "GT" -> ok C_GT
| "GE" -> ok C_GE
| "LT" -> ok C_LT
| "LE" -> ok C_LE
| "CONS" -> ok C_CONS
| "address" -> ok C_ADDRESS
| "self_address" -> ok C_SELF_ADDRESS
| "implicit_account"-> ok C_IMPLICIT_ACCOUNT
| "set_delegate" -> ok C_SET_DELEGATE
| _ -> simple_fail "Not a PascaLIGO constant"
(* Tezos module (ex-Michelson) *)
| "Tezos.chain_id" -> ok C_CHAIN_ID
| "chain_id" -> ok C_CHAIN_ID (* Deprecated *)
| "get_chain_id" -> ok C_CHAIN_ID (* Deprecated *)
| "Tezos.balance" -> ok C_BALANCE
| "balance" -> ok C_BALANCE (* Deprecated *)
| "Tezos.now" -> ok C_NOW
| "now" -> ok C_NOW (* Deprecated *)
| "Tezos.amount" -> ok C_AMOUNT
| "amount" -> ok C_AMOUNT (* Deprecated *)
| "Tezos.sender" -> ok C_SENDER
| "sender" -> ok C_SENDER (* Deprecated *)
| "Tezos.address" -> ok C_ADDRESS
| "address" -> ok C_ADDRESS (* Deprecated *)
| "Tezos.self_address" -> ok C_SELF_ADDRESS
| "self_address" -> ok C_SELF_ADDRESS (* Deprecated *)
| "Tezos.implicit_account" -> ok C_IMPLICIT_ACCOUNT
| "implicit_account" -> ok C_IMPLICIT_ACCOUNT (* Deprecated *)
| "Tezos.source" -> ok C_SOURCE
| "source" -> ok C_SOURCE (* Deprecated *)
| "Tezos.failwith" -> ok C_FAILWITH
| "failwith" -> ok C_FAILWITH
| "Tezos.transaction" -> ok C_CALL
| "transaction" -> ok C_CALL (* Deprecated *)
| "Tezos.set_delegate" -> ok C_SET_DELEGATE
| "set_delegate" -> ok C_SET_DELEGATE (* Deprecated *)
| "get_contract" -> ok C_CONTRACT (* Deprecated *)
| "Tezos.get_contract_opt" -> ok C_CONTRACT_OPT
| "get_contract_opt" -> ok C_CONTRACT_OPT (* Deprecated *)
| "get_entrypoint" -> ok C_CONTRACT_ENTRYPOINT (* Deprecated *)
| "Tezos.get_entrypoint_opt" -> ok C_CONTRACT_ENTRYPOINT_OPT
| "get_entrypoint_opt" -> ok C_CONTRACT_ENTRYPOINT_OPT (* Deprecated *)
| "Michelson.is_nat" -> ok C_IS_NAT (* Deprecated *)
| "is_nat" -> ok C_IS_NAT
| "int" -> ok C_INT
| "abs" -> ok C_ABS
| "unit" -> ok C_UNIT
| "NEG" -> ok C_NEG
| "ADD" -> ok C_ADD
| "SUB" -> ok C_SUB
| "TIMES" -> ok C_MUL
| "DIV" -> ok C_DIV
| "MOD" -> ok C_MOD
| "EQ" -> ok C_EQ
| "NOT" -> ok C_NOT
| "AND" -> ok C_AND
| "OR" -> ok C_OR
| "GT" -> ok C_GT
| "GE" -> ok C_GE
| "LT" -> ok C_LT
| "LE" -> ok C_LE
| "CONS" -> ok C_CONS
| "cons" -> ok C_CONS (* Deprecated *)
| "NEQ" -> ok C_NEQ
(* Crypto module *)
| "Crypto.check" -> ok C_CHECK_SIGNATURE
| "crypto_check" -> ok C_CHECK_SIGNATURE (* Deprecated *)
| "Crypto.hash_key" -> ok C_HASH_KEY
| "crypto_hash_key" -> ok C_HASH_KEY (* Deprecated *)
| "Crypto.blake2b" -> ok C_BLAKE2b
| "blake2b" -> ok C_BLAKE2b (* Deprecated *)
| "Crypto.sha256" -> ok C_SHA256
| "sha_256" -> ok C_SHA256 (* Deprecated *)
| "Crypto.sha512" -> ok C_SHA512
| "sha_512" -> ok C_SHA512 (* Deprecated *)
(* Bytes module *)
| "Bytes.pack" -> ok C_BYTES_PACK
| "bytes_pack" -> ok C_BYTES_PACK (* Deprecated *)
| "Bytes.unpack" -> ok C_BYTES_UNPACK
| "bytes_unpack" -> ok C_BYTES_UNPACK (* Deprecated *)
| "Bytes.length" -> ok C_SIZE
| "Bytes.size" -> ok C_SIZE
| "bytes_concat" -> ok C_CONCAT (* Deprecated *)
| "Bytes.concat" -> ok C_CONCAT
| "Bytes.slice" -> ok C_SLICE
| "bytes_slice" -> ok C_SLICE (* Deprecated *)
| "Bytes.sub" -> ok C_SLICE
(* List module *)
| "List.length" -> ok C_SIZE
| "List.size" -> ok C_SIZE
| "list_size" -> ok C_SIZE (* Deprecated *)
| "List.iter" -> ok C_LIST_ITER
| "list_iter" -> ok C_LIST_ITER (* Deprecated *)
| "List.map" -> ok C_LIST_MAP
| "list_map" -> ok C_LIST_MAP (* Deprecated *)
| "List.fold" -> ok C_LIST_FOLD
| "list_fold" -> ok C_LIST_FOLD (* Deprecated *)
(* Set module *)
| "Set.size" -> ok C_SIZE
| "set_size" -> ok C_SIZE (* Deprecated *)
| "set_empty" -> ok C_SET_EMPTY (* Deprecated *)
| "Set.mem" -> ok C_SET_MEM
| "set_mem" -> ok C_SET_MEM (* Deprecated *)
| "Set.add" -> ok C_SET_ADD
| "set_add" -> ok C_SET_ADD (* Deprecated *)
| "Set.remove" -> ok C_SET_REMOVE
| "set_remove" -> ok C_SET_REMOVE (* Deprecated *)
| "Set.iter" -> ok C_SET_ITER
| "set_iter" -> ok C_SET_ITER (* Deprecated *)
| "Set.fold" -> ok C_SET_FOLD
| "set_fold" -> ok C_SET_FOLD (* Deprecated *)
(* Map module *)
| "get_force" -> ok C_MAP_FIND (* Deprecated *)
| "map_get" -> ok C_MAP_FIND_OPT (* Deprecated *)
| "Map.find_opt" -> ok C_MAP_FIND_OPT
| "Map.update" -> ok C_MAP_UPDATE
| "map_update" -> ok C_MAP_UPDATE (* Deprecated *)
| "map_remove" -> ok C_MAP_REMOVE (* Deprecated *)
| "Map.iter" -> ok C_MAP_ITER
| "map_iter" -> ok C_MAP_ITER (* Deprecated *)
| "Map.map" -> ok C_MAP_MAP
| "map_map" -> ok C_MAP_MAP (* Deprecated *)
| "Map.fold" -> ok C_MAP_FOLD
| "map_fold" -> ok C_MAP_FOLD (* Deprecated *)
| "Map.mem" -> ok C_MAP_MEM
| "map_mem" -> ok C_MAP_MEM (* Deprecated *)
| "Map.size" -> ok C_SIZE
| "map_size" -> ok C_SIZE (* Deprecated *)
(* Big_map module *)
| "Big_map.find_opt" -> ok C_MAP_FIND_OPT
| "Big_map.update" -> ok C_MAP_UPDATE
| "Big_map.literal" -> ok C_BIG_MAP_LITERAL
| "Big_map.empty" -> ok C_BIG_MAP_EMPTY
| "Big_map.size" -> ok C_SIZE
| "Big_map.mem" -> ok C_MAP_MEM
| "Big_map.iter" -> ok C_MAP_ITER
| "Big_map.map" -> ok C_MAP_MAP
| "Big_map.fold" -> ok C_MAP_FOLD
| "Big_map.remove" -> ok C_MAP_REMOVE
(* Bitwise module *)
| "Bitwise.or" -> ok C_OR
| "bitwise_or" -> ok C_OR (* Deprecated *)
| "Bitwise.and" -> ok C_AND
| "bitwise_and" -> ok C_AND (* Deprecated *)
| "Bitwise.xor" -> ok C_XOR
| "bitwise_xor" -> ok C_XOR (* Deprecated *)
| "Bitwise.shift_left" -> ok C_LSL
| "bitwise_lsl" -> ok C_LSL (* Deprecated *)
| "Bitwise.shift_right" -> ok C_LSR
| "bitwise_lsr" -> ok C_LSR (* Deprecated *)
(* String module *)
| "String.length" -> ok C_SIZE
| "String.size" -> ok C_SIZE
| "String.slice" -> ok C_SLICE
| "string_slice" -> ok C_SLICE (* Deprecated *)
| "String.sub" -> ok C_SLICE
| "String.concat" -> ok C_CONCAT
| "string_concat" -> ok C_CONCAT (* Deprecated *)
(* Others *)
| "assert" -> ok C_ASSERTION
| "size" -> ok C_SIZE (* Deprecated *)
| _ -> simple_fail "Not a PascaLIGO built-in."
let type_constants = type_constants
let type_operators = type_operators
@ -147,119 +248,163 @@ module Simplify = struct
module Cameligo = struct
let constants = function
| "assert" -> ok C_ASSERTION
| "chain_id" -> ok C_CHAIN_ID
| "Current.balance" -> ok C_BALANCE
| "balance" -> ok C_BALANCE
| "Current.time" -> ok C_NOW
| "time" -> ok C_NOW
| "Current.amount" -> ok C_AMOUNT
| "amount" -> ok C_AMOUNT
| "Current.sender" -> ok C_SENDER
| "Current.address" -> ok C_ADDRESS
| "Current.self_address" -> ok C_SELF_ADDRESS
| "Current.implicit_account" -> ok C_IMPLICIT_ACCOUNT
| "sender" -> ok C_SENDER
| "Current.source" -> ok C_SOURCE
| "source" -> ok C_SOURCE
| "Current.failwith" -> ok C_FAILWITH
| "failwith" -> ok C_FAILWITH
(* Tezos (ex-Michelson, ex-Current, ex-Operation) *)
| "Crypto.blake2b" -> ok C_BLAKE2b
| "Crypto.sha256" -> ok C_SHA256
| "Crypto.sha512" -> ok C_SHA512
| "Crypto.hash_key" -> ok C_HASH_KEY
| "Crypto.check" -> ok C_CHECK_SIGNATURE
| "Tezos.chain_id" -> ok C_CHAIN_ID
| "chain_id" -> ok C_CHAIN_ID (* Deprecated *)
| "Tezos.balance" -> ok C_BALANCE
| "Current.balance" -> ok C_BALANCE (* Deprecated *)
| "balance" -> ok C_BALANCE (* Deprecated *)
| "Tezos.now" -> ok C_NOW
| "Current.time" -> ok C_NOW (* Deprecated *)
| "time" -> ok C_NOW (* Deprecated *)
| "Tezos.amount" -> ok C_AMOUNT
| "Current.amount" -> ok C_AMOUNT (* Deprecated *)
| "amount" -> ok C_AMOUNT (* Deprecated *)
| "Tezos.sender" -> ok C_SENDER
| "Current.sender" -> ok C_SENDER (* Deprecated *)
| "sender" -> ok C_SENDER (* Deprecated *)
| "Tezos.address" -> ok C_ADDRESS
| "Current.address" -> ok C_ADDRESS (* Deprecated *)
| "Tezos.self_address" -> ok C_SELF_ADDRESS
| "Current.self_address" -> ok C_SELF_ADDRESS (* Deprecated *)
| "Tezos.implicit_account" -> ok C_IMPLICIT_ACCOUNT
| "Current.implicit_account" -> ok C_IMPLICIT_ACCOUNT (* Deprecated *)
| "Tezos.source" -> ok C_SOURCE
| "Current.source" -> ok C_SOURCE (* Deprecated *)
| "source" -> ok C_SOURCE (* Deprecated *)
| "Tezos.failwith" -> ok C_FAILWITH
| "Current.failwith" -> ok C_FAILWITH (* Deprecated *)
| "failwith" -> ok C_FAILWITH
| "Bytes.pack" -> ok C_BYTES_PACK
| "Bytes.unpack" -> ok C_BYTES_UNPACK
| "Bytes.length" -> ok C_SIZE
| "Bytes.size" -> ok C_SIZE
| "Bytes.concat" -> ok C_CONCAT
| "Bytes.slice" -> ok C_SLICE
| "Bytes.sub" -> ok C_SLICE
| "Tezos.transaction" -> ok C_CALL
| "Operation.transaction" -> ok C_CALL (* Deprecated *)
| "Tezos.set_delegate" -> ok C_SET_DELEGATE (* Deprecated *)
| "Operation.set_delegate" -> ok C_SET_DELEGATE (* Deprecated *)
| "Operation.get_contract" -> ok C_CONTRACT (* Deprecated *)
| "Tezos.get_contract_opt" -> ok C_CONTRACT_OPT
| "Operation.get_contract_opt" -> ok C_CONTRACT_OPT (* Deprecated *)
| "Operation.get_entrypoint" -> ok C_CONTRACT_ENTRYPOINT (* Deprecated *)
| "Tezos.get_entrypoint_opt" -> ok C_CONTRACT_ENTRYPOINT_OPT
| "Operation.get_entrypoint_opt" -> ok C_CONTRACT_ENTRYPOINT_OPT (* Deprecated *)
| "Set.mem" -> ok C_SET_MEM
| "Set.iter" -> ok C_SET_ITER
| "Set.empty" -> ok C_SET_EMPTY
| "Set.literal" -> ok C_SET_LITERAL
| "Set.add" -> ok C_SET_ADD
| "Set.remove" -> ok C_SET_REMOVE
| "Set.fold" -> ok C_SET_FOLD
| "Set.size" -> ok C_SIZE
| "Michelson.is_nat" -> ok C_IS_NAT (* Deprecated *)
| "is_nat" -> ok C_IS_NAT
| "int" -> ok C_INT
| "abs" -> ok C_ABS
| "unit" -> ok C_UNIT
| "Map.find_opt" -> ok C_MAP_FIND_OPT
| "Map.find" -> ok C_MAP_FIND
| "Map.update" -> ok C_MAP_UPDATE
| "Map.add" -> ok C_MAP_ADD
| "Map.remove" -> ok C_MAP_REMOVE
| "Map.iter" -> ok C_MAP_ITER
| "Map.map" -> ok C_MAP_MAP
| "Map.fold" -> ok C_MAP_FOLD
| "Map.mem" -> ok C_MAP_MEM
| "Map.empty" -> ok C_MAP_EMPTY
| "Map.literal" -> ok C_MAP_LITERAL
| "Map.size" -> ok C_SIZE
| "NEG" -> ok C_NEG
| "ADD" -> ok C_ADD
| "SUB" -> ok C_SUB
| "TIMES" -> ok C_MUL
| "DIV" -> ok C_DIV
| "MOD" -> ok C_MOD
| "EQ" -> ok C_EQ
| "NOT" -> ok C_NOT
| "AND" -> ok C_AND
| "OR" -> ok C_OR
| "GT" -> ok C_GT
| "GE" -> ok C_GE
| "LT" -> ok C_LT
| "LE" -> ok C_LE
| "CONS" -> ok C_CONS
| "NEQ" -> ok C_NEQ
| "Big_map.find_opt" -> ok C_MAP_FIND_OPT
| "Big_map.find" -> ok C_MAP_FIND
| "Big_map.update" -> ok C_MAP_UPDATE
| "Big_map.add" -> ok C_MAP_ADD
| "Big_map.remove" -> ok C_MAP_REMOVE
| "Big_map.literal" -> ok C_BIG_MAP_LITERAL
| "Big_map.empty" -> ok C_BIG_MAP_EMPTY
(* Crypto module *)
| "Bitwise.lor" -> ok C_OR
| "Bitwise.land" -> ok C_AND
| "Bitwise.lxor" -> ok C_XOR
| "Bitwise.shift_left" -> ok C_LSL
| "Bitwise.shift_right" -> ok C_LSR
| "Crypto.check" -> ok C_CHECK_SIGNATURE
| "Crypto.hash_key" -> ok C_HASH_KEY
| "Crypto.blake2b" -> ok C_BLAKE2b
| "Crypto.sha256" -> ok C_SHA256
| "Crypto.sha512" -> ok C_SHA512
| "String.length" -> ok C_SIZE
| "String.size" -> ok C_SIZE
| "String.slice" -> ok C_SLICE
| "String.sub" -> ok C_SLICE
| "String.concat" -> ok C_CONCAT
(* Bytes module *)
| "List.length" -> ok C_SIZE
| "List.size" -> ok C_SIZE
| "List.iter" -> ok C_LIST_ITER
| "List.map" -> ok C_LIST_MAP
| "List.fold" -> ok C_LIST_FOLD
| "Bytes.pack" -> ok C_BYTES_PACK
| "Bytes.unpack" -> ok C_BYTES_UNPACK
| "Bytes.length" -> ok C_SIZE
| "Bytes.size" -> ok C_SIZE
| "Bytes.concat" -> ok C_CONCAT
| "Bytes.slice" -> ok C_SLICE
| "Bytes.sub" -> ok C_SLICE
| "Loop.fold_while" -> ok C_FOLD_WHILE
| "continue" -> ok C_CONTINUE
| "stop" -> ok C_STOP
(* List module *)
| "Operation.transaction" -> ok C_CALL
| "Operation.set_delegate" -> ok C_SET_DELEGATE
| "Operation.get_contract" -> ok C_CONTRACT
| "Operation.get_contract_opt" -> ok C_CONTRACT_OPT
| "Operation.get_entrypoint" -> ok C_CONTRACT_ENTRYPOINT
| "Operation.get_entrypoint_opt" -> ok C_CONTRACT_ENTRYPOINT_OPT
| "int" -> ok C_INT
| "abs" -> ok C_ABS
| "unit" -> ok C_UNIT
| "List.length" -> ok C_SIZE
| "List.size" -> ok C_SIZE
| "List.iter" -> ok C_LIST_ITER
| "List.map" -> ok C_LIST_MAP
| "List.fold" -> ok C_LIST_FOLD
| "NEG" -> ok C_NEG
| "ADD" -> ok C_ADD
| "SUB" -> ok C_SUB
| "TIMES" -> ok C_MUL
| "DIV" -> ok C_DIV
| "MOD" -> ok C_MOD
| "EQ" -> ok C_EQ
| "NOT" -> ok C_NOT
| "AND" -> ok C_AND
| "OR" -> ok C_OR
| "GT" -> ok C_GT
| "GE" -> ok C_GE
| "LT" -> ok C_LT
| "LE" -> ok C_LE
| "CONS" -> ok C_CONS
| "NEQ" -> ok C_NEQ
(* Set module *)
| "Michelson.is_nat" -> ok C_IS_NAT
| _ -> simple_fail "Not a constant"
| "Set.mem" -> ok C_SET_MEM
| "Set.iter" -> ok C_SET_ITER
| "Set.empty" -> ok C_SET_EMPTY
| "Set.literal" -> ok C_SET_LITERAL
| "Set.add" -> ok C_SET_ADD
| "Set.remove" -> ok C_SET_REMOVE
| "Set.fold" -> ok C_SET_FOLD
| "Set.size" -> ok C_SIZE
(* Map module *)
| "Map.find_opt" -> ok C_MAP_FIND_OPT
| "Map.find" -> ok C_MAP_FIND (* Deprecated *)
| "Map.update" -> ok C_MAP_UPDATE
| "Map.add" -> ok C_MAP_ADD
| "Map.remove" -> ok C_MAP_REMOVE
| "Map.iter" -> ok C_MAP_ITER
| "Map.map" -> ok C_MAP_MAP
| "Map.fold" -> ok C_MAP_FOLD
| "Map.mem" -> ok C_MAP_MEM
| "Map.empty" -> ok C_MAP_EMPTY
| "Map.literal" -> ok C_MAP_LITERAL
| "Map.size" -> ok C_SIZE
(* Big_map module *)
| "Big_map.find_opt" -> ok C_MAP_FIND_OPT
| "Big_map.find" -> ok C_MAP_FIND
| "Big_map.update" -> ok C_MAP_UPDATE
| "Big_map.add" -> ok C_MAP_ADD
| "Big_map.remove" -> ok C_MAP_REMOVE
| "Big_map.literal" -> ok C_BIG_MAP_LITERAL
| "Big_map.empty" -> ok C_BIG_MAP_EMPTY
(* Bitwise module *)
| "Bitwise.or" -> ok C_OR
| "Bitwise.lor" -> ok C_OR (* Deprecated *)
| "Bitwise.and" -> ok C_AND
| "Bitwise.land" -> ok C_AND (* Deprecated *)
| "Bitwise.xor" -> ok C_XOR
| "Bitwise.lxor" -> ok C_XOR (* Deprecated *)
| "Bitwise.shift_left" -> ok C_LSL
| "Bitwise.shift_right" -> ok C_LSR
(* String module *)
| "String.length" -> ok C_SIZE
| "String.size" -> ok C_SIZE
| "String.slice" -> ok C_SLICE
| "String.sub" -> ok C_SLICE
| "String.concat" -> ok C_CONCAT
(* Loop module *)
| "Loop.fold_while" -> ok C_FOLD_WHILE
| "Loop.resume" -> ok C_CONTINUE
| "continue" -> ok C_CONTINUE (* Deprecated *)
| "Loop.stop" -> ok C_STOP
| "stop" -> ok C_STOP (* Deprecated *)
(* Others *)
| "assert" -> ok C_ASSERTION
| _ -> simple_fail "Not a CameLIGO built-in."
let type_constants = type_constants
let type_operators = type_operators
@ -821,19 +966,19 @@ module Typer = struct
let%bind key = get_t_set set in
if eq_1 elt key
then ok @@ t_bool ()
else fail @@ Operator_errors.type_error "Set_mem: elt and set don't match" elt key ()
else fail @@ Operator_errors.type_error "Set.mem: elt and set don't match" elt key ()
let set_add = typer_2 "SET_ADD" @@ fun elt set ->
let%bind key = get_t_set set in
if eq_1 elt key
then ok set
else fail @@ Operator_errors.type_error "Set_add: elt and set don't match" elt key ()
else fail @@ Operator_errors.type_error "Set.add: elt and set don't match" elt key ()
let set_remove = typer_2 "SET_REMOVE" @@ fun elt set ->
let%bind key = get_t_set set in
if eq_1 elt key
then ok set
else fail @@ Operator_errors.type_error "Set_remove: elt and set don't match" key elt ()
else fail @@ Operator_errors.type_error "Set.remove: elt and set don't match" key elt ()
let set_iter = typer_2 "SET_ITER" @@ fun body set ->
let%bind (arg , res) = get_t_function body in

View File

@ -1,11 +1,7 @@
// Test PascaLIGO bitwise operators
function or_op (const n : nat) : nat is bitwise_or (n, 4n)
function and_op (const n : nat) : nat is bitwise_and (n, 7n)
function xor_op (const n : nat) : nat is bitwise_xor (n, 7n)
function lsl_op (const n : nat) : nat is bitwise_lsl (n, 7n)
function lsr_op (const n : nat) : nat is bitwise_lsr (n, 7n)
function or_op (const n : nat) : nat is Bitwise.or (n, 4n)
function and_op (const n : nat) : nat is Bitwise.and (n, 7n)
function xor_op (const n : nat) : nat is Bitwise.xor (n, 7n)
function lsl_op (const n : nat) : nat is Bitwise.shift_left (n, 7n)
function lsr_op (const n : nat) : nat is Bitwise.shift_right (n, 7n)

View File

@ -1,7 +1,7 @@
(* Test CameLIGO bitwise operators *)
let or_op (n: nat) : nat = Bitwise.lor n 4n
let and_op (n: nat) : nat = Bitwise.land n 7n
let xor_op (n: nat) : nat = Bitwise.lxor n 7n
let or_op (n: nat) : nat = Bitwise.or n 4n
let and_op (n: nat) : nat = Bitwise.and n 7n
let xor_op (n: nat) : nat = Bitwise.xor n 7n
let lsl_op (n: nat) : nat = Bitwise.shift_left n 7n
let lsr_op (n: nat) : nat = Bitwise.shift_right n 7n

View File

@ -1,7 +1,7 @@
/* Test ReasonLigo bitwise operators */
let or_op = (n: nat): nat => Bitwise.lor(n, 4n);
let and_op = (n: nat): nat => Bitwise.land(n, 7n);
let xor_op = (n: nat): nat => Bitwise.lxor(n, 7n);
let lsl_op = (n: nat) : nat => Bitwise.shift_left(n, 7n);
let lsr_op = (n: nat) : nat => Bitwise.shift_right(n, 7n);
let or_op = (n : nat) : nat => Bitwise.or (n, 4n);
let and_op = (n : nat) : nat => Bitwise.and (n, 7n);
let xor_op = (n : nat) : nat => Bitwise.xor (n, 7n);
let lsl_op = (n : nat) : nat => Bitwise.shift_left (n, 7n);
let lsr_op = (n : nat) : nat => Bitwise.shift_right (n, 7n);