This commit is contained in:
Sander Spies 2020-03-06 08:30:55 +01:00
commit c95f4ee02c
386 changed files with 9330 additions and 6331 deletions

View File

@ -23,8 +23,8 @@ dont-merge-to-master:
only: only:
- master - master
.build_binary: &build_binary .build_binary:
# To run in sequence and save CPU usage, use stage: build_and_package_binaries &build_binary # To run in sequence and save CPU usage, use stage: build_and_package_binaries
stage: test stage: test
script: script:
- $build_binary_script "$target_os_family" "$target_os" "$target_os_version" - $build_binary_script "$target_os_family" "$target_os" "$target_os_version"
@ -35,7 +35,7 @@ dont-merge-to-master:
.website_build: &website_build .website_build: &website_build
stage: build_and_deploy stage: build_and_deploy
image: node:8 image: node:12
dependencies: dependencies:
- build-and-package-debian-9 - build-and-package-debian-9
- build-and-package-debian-10 - build-and-package-debian-10
@ -62,19 +62,15 @@ dont-merge-to-master:
# copy .deb packages into website # copy .deb packages into website
- find dist -name \*.deb -exec sh -c 'cp {} gitlab-pages/website/static/deb/ligo_$(basename $(dirname {})).deb' \; - find dist -name \*.deb -exec sh -c 'cp {} gitlab-pages/website/static/deb/ligo_$(basename $(dirname {})).deb' \;
# npm # yarn
- cd gitlab-pages/website - cd gitlab-pages/website
- npm install - yarn install
script: script:
- npm run version next - yarn build
- npm run build
# move internal odoc documentation to the website folder # move internal odoc documentation to the website folder
- mkdir -p build/ligo/ - mv ../../_build/default/_doc/_html/ build/odoc
- mv ../../_build/default/_doc/_html/ build/ligo/odoc
- pwd # for debug
- ls build/ligo/ # for debug
after_script: after_script:
- cp -r gitlab-pages/website/build/ligo public - cp -r gitlab-pages/website/build public
artifacts: artifacts:
paths: paths:
- public - public
@ -84,7 +80,6 @@ dont-merge-to-master:
services: services:
- docker:19.03.5-dind - docker:19.03.5-dind
.before_script: &before_script .before_script: &before_script
before_script: before_script:
# Install dependencies # Install dependencies
@ -224,9 +219,10 @@ run-webide-unit-tests:
- cd tools/webide/packages/server - cd tools/webide/packages/server
- npm ci - npm ci
- npm run test - npm run test
only: rules:
changes: - changes:
- tools/webide/** - tools/webide/**
when: always
build-publish-ide-image: build-publish-ide-image:
stage: build_and_deploy stage: build_and_deploy
@ -236,6 +232,7 @@ build-publish-ide-image:
- find dist/ - find dist/
- find dist/package/ -name '*ligo_*deb' - find dist/package/ -name '*ligo_*deb'
- mv $(realpath dist/package/debian-10/*.deb) tools/webide/ligo_deb10.deb - mv $(realpath dist/package/debian-10/*.deb) tools/webide/ligo_deb10.deb
- cp -r src/test/examples tools/webide/packages/client/examples
- cd tools/webide - cd tools/webide
- echo "${CI_BUILD_TOKEN}" | docker login -u gitlab-ci-token --password-stdin registry.gitlab.com - echo "${CI_BUILD_TOKEN}" | docker login -u gitlab-ci-token --password-stdin registry.gitlab.com
- > - >
@ -243,10 +240,12 @@ build-publish-ide-image:
-t "${WEBIDE_IMAGE_NAME}:${CI_COMMIT_SHORT_SHA}" -t "${WEBIDE_IMAGE_NAME}:${CI_COMMIT_SHORT_SHA}"
--build-arg GIT_TAG="${CI_COMMIT_SHA}" --build-arg GIT_TAG="${CI_COMMIT_SHA}"
--build-arg GIT_COMMIT="${CI_COMMIT_SHORT_SHA}" --build-arg GIT_COMMIT="${CI_COMMIT_SHORT_SHA}"
--build-arg EXAMPLES_DIR_SRC=packages/client/examples
. .
- docker push "${WEBIDE_IMAGE_NAME}:${CI_COMMIT_SHORT_SHA}" - docker push "${WEBIDE_IMAGE_NAME}:${CI_COMMIT_SHORT_SHA}"
rules: rules:
- if: '$CI_PIPELINE_SOURCE == "merge_request_event"' - changes:
- tools/webide/**
when: always when: always
- if: '$CI_COMMIT_REF_NAME == "dev"' - if: '$CI_COMMIT_REF_NAME == "dev"'
when: always when: always
@ -260,7 +259,8 @@ run-webide-e2e-tests:
- export WEBIDE_IMAGE="${WEBIDE_IMAGE_NAME}:${CI_COMMIT_SHORT_SHA}" - export WEBIDE_IMAGE="${WEBIDE_IMAGE_NAME}:${CI_COMMIT_SHORT_SHA}"
- docker-compose run e2e - docker-compose run e2e
rules: rules:
- if: '$CI_PIPELINE_SOURCE == "merge_request_event"' - changes:
- tools/webide/**
when: always when: always
- if: '$CI_COMMIT_REF_NAME == "dev"' - if: '$CI_COMMIT_REF_NAME == "dev"'
when: always when: always

View File

@ -2,6 +2,10 @@
## [Unreleased] ## [Unreleased]
## [Add crypto reference page to docs](https://gitlab.com/ligolang/ligo/-/merge_requests/459)
### Added
- support for `Tezos.create_contract` origination
## [9164206ef1fcf3e577820442b5afbad92d03ffa4] - 2020-02-09 ## [9164206ef1fcf3e577820442b5afbad92d03ffa4] - 2020-02-09
### Changed ### Changed
- Mutation of variables inside lambdas passed to list_iter do not have effect anymore. Side-effects used to survive iterations of list_iter via a quirk in the Michelson list_iter. Now, either use a list_fold and explicitly pass through the updated variables (e.g. storage) to the next iteration, or use a `for` loop which automatically detects mutations within the loop body and lifts the affected variables to a record that is passed from iteration to iteration. - Mutation of variables inside lambdas passed to list_iter do not have effect anymore. Side-effects used to survive iterations of list_iter via a quirk in the Michelson list_iter. Now, either use a list_fold and explicitly pass through the updated variables (e.g. storage) to the next iteration, or use a `for` loop which automatically detects mutations within the loop body and lifts the affected variables to a record that is passed from iteration to iteration.

View File

@ -1,4 +1,4 @@
FROM node:8.11.4 FROM node:12.16
WORKDIR /app/website WORKDIR /app/website

View File

@ -8,15 +8,16 @@ services:
- 35729:35729 - 35729:35729
volumes: volumes:
- ./docs:/app/docs - ./docs:/app/docs
- ./website/blog:/app/website/blog # - ./website/blog:/app/website/blog
- ./website/core:/app/website/core - ./website/core:/app/website/core
- ./website/i18n:/app/website/i18n # - ./website/i18n:/app/website/i18n
- ./website/pages:/app/website/pages - ./website/src:/app/website/src
- ./website/static:/app/website/static - ./website/static:/app/website/static
- ./website/versioned_sidebars:/app/website/versioned_sidebars # - ./website/versioned_sidebars:/app/website/versioned_sidebars
- ./website/versioned_docs:/app/website/versioned_docs # - ./website/versioned_docs:/app/website/versioned_docs
- ./website/sidebars.json:/app/website/sidebars.json - ./website/sidebars.json:/app/website/sidebars.json
- ./website/siteConfig.js:/app/website/siteConfig.js - ./website/docusaurus.config.js:/app/website/docusaurus.config.js
- ./website/versions.json:/app/website/versions.json - ./website/versions.json:/app/website/versions.json
- ./website/node_modules/reason-highlightjs:/app/website/node_modules/reason-highlightjs # - ./website/core/AlgoliaSearch.js:/app/website/core/AlgoliaSearch.js
working_dir: /app/website working_dir: /app/website

View File

@ -1,61 +1,68 @@
--- ---
id: entrypoints-contracts id: entrypoints-contracts
title: Access function and Entrypoints title: Main function and Entrypoints
--- ---
import Syntax from '@theme/Syntax';
## Access Functions ## Access Functions
A LIGO contract is made of a series of constant and function A LIGO contract is made of a series of constant and function
declarations. Only functions having a special type can be called when declarations. Only functions having a special type can be called when
the contract is activated: we called them *access functions*. An the contract is activated: we call them *main functions*. A main
access function takes two parameters, the *contract parameter* and the function takes two parameters, the *contract parameter* and the
*on-chain storage*, and returns a pair made of a *list of operations* *on-chain storage*, and returns a pair made of a *list of operations*
and a (new) storage. and a (new) storage.
When the contract is originated, the initial value of the storage is When the contract is originated, the initial value of the storage is
provided. When an access function is later called, only the parameter provided. When a main function is later called, only the parameter is
is provided, but the type of an access function contains both. provided, but the type of a main function contains both.
The type of the contract parameter and the storage are up to the 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 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 `storage` has been defined elsewhere. (Note that you can use any type
with any name for the storage.) with any name for the storage.)
<!--DOCUSAURUS_CODE_TABS-->
<!--PascaLIGO--> <Syntax syntax="pascaligo">
```pascaligo skip ```pascaligo skip
type storage is ... // Any name, any type type storage is ... // Any name, any type
type return is list (operation) * storage type return is list (operation) * storage
``` ```
<!--CameLIGO--> </Syntax>
<Syntax syntax="cameligo">
```cameligo skip ```cameligo skip
type storage = ... // Any name, any type type storage = ... // Any name, any type
type return = operation list * storage type return = operation list * storage
``` ```
<!--ReasonLIGO--> </Syntax>
<Syntax syntax="reasonligo">
```reasonligo skip ```reasonligo skip
type storage = ...; // Any name, any type type storage = ...; // Any name, any type
type return = (list (operation), storage); type return = (list (operation), storage);
``` ```
<!--END_DOCUSAURUS_CODE_TABS-->
The contract storage can only be modified by activating an access </Syntax>
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 The contract storage can only be modified by activating a main
specifies how to create another state for it, depending on a function: given the state of the storage *on-chain*, a main function
parameter. 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 Here is an example where the storage is a single natural number that
is updated by the parameter. is updated by the parameter.
<!--DOCUSAURUS_CODE_TABS-->
<!--PascaLIGO-->
<Syntax syntax="pascaligo">
```pascaligo group=a ```pascaligo group=a
type parameter is nat type parameter is nat
@ -65,8 +72,9 @@ type return is list (operation) * storage
function save (const action : parameter; const store : storage) : return is function save (const action : parameter; const store : storage) : return is
((nil : list (operation)), store) ((nil : list (operation)), store)
``` ```
</Syntax>
<Syntax syntax="cameligo">
<!--CameLIGO-->
```cameligo group=a ```cameligo group=a
type parameter = nat type parameter = nat
type storage = nat type storage = nat
@ -76,7 +84,9 @@ let save (action, store: parameter * storage) : return =
(([] : operation list), store) (([] : operation list), store)
``` ```
<!--ReasonLIGO--> </Syntax>
<Syntax syntax="reasonligo">
```reasonligo group=a ```reasonligo group=a
type parameter = nat; type parameter = nat;
type storage = nat; type storage = nat;
@ -85,21 +95,24 @@ type return = (list (operation), storage);
let main = ((action, store): (parameter, storage)) : return => let main = ((action, store): (parameter, storage)) : return =>
(([] : list (operation)), store); (([] : list (operation)), store);
``` ```
<!--END_DOCUSAURUS_CODE_TABS-->
</Syntax>
## Entrypoints ## Entrypoints
In LIGO, the design pattern is to have *one* access function that In LIGO, the design pattern is to have *one* main function called
dispatches the control flow according to its parameter. Those `main`, that dispatches the control flow according to its
functions called for those actions are called *entrypoints*. parameter. Those functions called for those actions are called
*entrypoints*.
As an analogy, in the C programming language, the `main` function is 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. entrypoint.
The parameter of the contract is then a variant type, and, depending The parameter of the contract is then a variant type, and, depending
on the constructors of that type, different functions in the contract 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 control flow depending on a *pattern matching* on the contract
parameter. parameter.
@ -107,9 +120,10 @@ In the following example, the storage contains a counter of type `nat`
and a name of type `string`. Depending on the parameter of the and a name of type `string`. Depending on the parameter of the
contract, either the counter or the name is updated. contract, either the counter or the name is updated.
<!--DOCUSAURUS_CODE_TABS-->
<!--PascaLIGO-->
<Syntax syntax="pascaligo">
```pascaligo group=b ```pascaligo group=b
type parameter is type parameter is
Action_A of nat Action_A of nat
@ -128,14 +142,16 @@ function entry_A (const n : nat; const store : storage) : return is
function entry_B (const s : string; const store : storage) : return is function entry_B (const s : string; const store : storage) : return is
((nil : list (operation)), store with record [name = s]) ((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 case action of
Action_A (n) -> entry_A (n, store) Action_A (n) -> entry_A (n, store)
| Action_B (s) -> entry_B (s, store) | Action_B (s) -> entry_B (s, store)
end end
``` ```
<!--CameLIGO--> </Syntax>
<Syntax syntax="cameligo">
```cameligo group=b ```cameligo group=b
type parameter = type parameter =
Action_A of nat Action_A of nat
@ -154,13 +170,15 @@ let entry_A (n, store : nat * storage) : return =
let entry_B (s, store : string * storage) : return = let entry_B (s, store : string * storage) : return =
([] : operation list), {store with name = s} ([] : operation list), {store with name = s}
let access (action, store: parameter * storage) : return = let main (action, store: parameter * storage) : return =
match action with match action with
Action_A n -> entry_A (n, store) Action_A n -> entry_A (n, store)
| Action_B s -> entry_B (s, store) | Action_B s -> entry_B (s, store)
``` ```
<!--ReasonLIGO--> </Syntax>
<Syntax syntax="reasonligo">
```reasonligo group=b ```reasonligo group=b
type parameter = type parameter =
| Action_A (nat) | Action_A (nat)
@ -179,13 +197,15 @@ let entry_A = ((n, store): (nat, storage)) : return =>
let entry_B = ((s, store): (string, storage)) : return => let entry_B = ((s, store): (string, storage)) : return =>
(([] : list (operation)), {...store, name : s}); (([] : list (operation)), {...store, name : s});
let access = ((action, store): (parameter, storage)) : return => let main = ((action, store): (parameter, storage)) : return =>
switch (action) { switch (action) {
| Action_A (n) => entry_A ((n, store)) | Action_A (n) => entry_A ((n, store))
| Action_B (s) => entry_B ((s, store)) | Action_B (s) => entry_B ((s, store))
}; };
``` ```
<!--END_DOCUSAURUS_CODE_TABS-->
</Syntax>
## Tezos-specific Built-ins ## Tezos-specific Built-ins
@ -196,83 +216,110 @@ how those built-ins can be utilized.
### Accepting or Declining Tokens in a Smart Contract ### Accepting or Declining Tokens in a Smart Contract
This example shows how `amount` and `failwith` can be used to decline This example shows how `Tezos.amount` and `failwith` can be used to
any transaction that sends more tez than `0mutez`, that is, no decline any transaction that sends more tez than `0tez`, that is, no
incoming tokens are accepted. incoming tokens are accepted.
<!--DOCUSAURUS_CODE_TABS-->
<!--PascaLIGO--> <Syntax syntax="pascaligo">
```pascaligo group=c ```pascaligo group=c
type parameter is unit type parameter is unit
type storage is unit type storage is unit
type return is list (operation) * storage type return is list (operation) * storage
function deny (const action : parameter; const store : storage) : return is 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) (failwith ("This contract does not accept tokens.") : return)
else ((nil : list (operation)), store) else ((nil : list (operation)), store)
``` ```
<!--CameLIGO--> > Note that `amount` is *deprecated*.
</Syntax>
<Syntax syntax="cameligo">
```cameligo group=c ```cameligo group=c
type parameter = unit type parameter = unit
type storage = unit type storage = unit
type return = operation list * storage type return = operation list * storage
let deny (action, store : parameter * storage) : return = let deny (action, store : parameter * storage) : return =
if amount > 0mutez then if Tezos.amount > 0tez then
(failwith "This contract does not accept tokens.": return) (failwith "This contract does not accept tokens." : return)
else (([] : operation list), store) else (([] : operation list), store)
``` ```
<!--ReasonLIGO--> > Note that `amount` is *deprecated*.
</Syntax>
<Syntax syntax="reasonligo">
```reasonligo group=c ```reasonligo group=c
type parameter = unit; type parameter = unit;
type storage = unit; type storage = unit;
type return = (list (operation), storage); type return = (list (operation), storage);
let deny = ((action, store): (parameter, storage)) : return => { let deny = ((action, store): (parameter, storage)) : return => {
if (amount > 0mutez) { if (Tezos.amount > 0tez) {
(failwith("This contract does not accept tokens."): return); } (failwith("This contract does not accept tokens."): return); }
else { (([] : list (operation)), store); }; else { (([] : list (operation)), store); };
}; };
``` ```
<!--END_DOCUSAURUS_CODE_TABS--> > Note that `amount` is *deprecated*.
</Syntax>
### Access Control ### 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.
<Syntax syntax="pascaligo">
<!--DOCUSAURUS_CODE_TABS-->
<!--PascaLIGO-->
```pascaligo group=c ```pascaligo group=c
const owner : address = ("tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx": address); const owner : address = ("tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx": address);
function filter (const action : parameter; const store : storage) : return is function main (const action : parameter; const store : storage) : return is
if source =/= owner then (failwith ("Access denied.") : return) if Tezos.source =/= owner then (failwith ("Access denied.") : return)
else ((nil : list(operation)), store) else ((nil : list (operation)), store)
``` ```
<!--CameLIGO--> > Note that `source` is *deprecated*.
</Syntax>
<Syntax syntax="cameligo">
```cameligo group=c ```cameligo group=c
let owner : address = ("tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx": address) let owner : address = ("tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx": address)
let filter (action, store: parameter * storage) : return = let main (action, store: parameter * storage) : return =
if source <> owner then (failwith "Access denied." : return) if Tezos.source <> owner then (failwith "Access denied." : return)
else (([] : operation list), store) else (([] : operation list), store)
``` ```
<!--ReasonLIGO--> > Note that `source` is *deprecated*.
</Syntax>
<Syntax syntax="reasonligo">
```reasonligo group=c ```reasonligo group=c
let owner : address = ("tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx": address); let owner : address = ("tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx": address);
let access = ((action, store): (parameter, storage)) : storage => { let main = ((action, store) : (parameter, storage)) : storage => {
if (source != owner) { (failwith ("Access denied.") : return); } if (Tezos.source != owner) { (failwith ("Access denied.") : return); }
else { (([] : list (operation)), store); }; else { (([] : list (operation)), store); };
}; };
``` ```
<!--END_DOCUSAURUS_CODE_TABS-->
> Note that `source` is *deprecated*.
</Syntax>
### Inter-Contract Invocations ### Inter-Contract Invocations
@ -298,9 +345,10 @@ of type `parameter`, and we have a `proxy.ligo` contract that accepts
the same parameter type, and forwards the call to the deployed counter the same parameter type, and forwards the call to the deployed counter
contract. contract.
<!--DOCUSAURUS_CODE_TABS-->
<!--PascaLIGO-->
<Syntax syntax="pascaligo">
```pascaligo skip ```pascaligo skip
// counter.ligo // counter.ligo
type parameter is type parameter is
@ -329,16 +377,22 @@ const dest : address = ("KT19wgxcuXG9VH4Af5Tpm1vqEKdaMFpznXT3" : address)
function proxy (const action : parameter; const store : storage): return is function proxy (const action : parameter; const store : storage): return is
block { 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 (* Reuse the parameter in the subsequent
transaction or use another one, `mock_param`. *) transaction or use another one, `mock_param`. *)
const mock_param : parameter = Increment (5n); 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] const ops : list (operation) = list [op]
} with (ops, store) } with (ops, store)
``` ```
<!--CameLIGO--> </Syntax>
<Syntax syntax="cameligo">
```cameligo skip ```cameligo skip
// counter.mligo // counter.mligo
@ -365,15 +419,22 @@ type return = operation list * storage
let dest : address = ("KT19wgxcuXG9VH4Af5Tpm1vqEKdaMFpznXT3" : address) let dest : address = ("KT19wgxcuXG9VH4Af5Tpm1vqEKdaMFpznXT3" : address)
let proxy (action, store : parameter * storage) : return = 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 (* Reuse the parameter in the subsequent
transaction or use another one, `mock_param`. *) transaction or use another one, `mock_param`. *)
let mock_param : parameter = Increment (5n) in 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 in [op], store
``` ```
<!--ReasonLIGO--> > Note that `Operation.get_contract` and `Operation.transaction` are
> *deprecated*.
</Syntax>
<Syntax syntax="reasonligo">
```reasonligo skip ```reasonligo skip
// counter.religo // counter.religo
@ -400,13 +461,21 @@ type return = (list (operation), storage);
let dest : address = ("KT19wgxcuXG9VH4Af5Tpm1vqEKdaMFpznXT3" : address); let dest : address = ("KT19wgxcuXG9VH4Af5Tpm1vqEKdaMFpznXT3" : address);
let proxy = ((action, store): (parameter, storage)) : return => { 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 (* Reuse the parameter in the subsequent
transaction or use another one, `mock_param`. *) transaction or use another one, `mock_param`. *)
let mock_param : parameter = Increment (5n); let mock_param : parameter = Increment (5n);
let op : operation = Operation.transaction (action, 0mutez, counter); let op : operation = Tezos.transaction (action, 0tez, counter);
([op], store) ([op], store)
}; };
``` ```
<!--END_DOCUSAURUS_CODE_TABS--> > Note that `Operation.get_contract` and `Operation.transaction` are
> *deprecated*.
</Syntax>

View File

@ -3,6 +3,8 @@ id: first-contract
title: First contract title: First contract
--- ---
import Syntax from '@theme/Syntax';
So far so good, we have learned enough of the LIGO language, we are So far so good, we have learned enough of the LIGO language, we are
confident enough to write out first smart contract. confident enough to write out first smart contract.
@ -11,99 +13,120 @@ We will be implementing a counter contract.
## Dry-running a Contract ## Dry-running a Contract
Testing a contract can be quite easy if we utilize LIGO's built-in dry 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 run feature. Dry-run works by simulating the main function execution,
execution, as if it were deployed on a real chain. You need to provide as if it were deployed on a real chain. You need to provide the
the following: following:
- `file` - contract to run - `file` - contract to run
- `entrypoint` - name of the function to execute - `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 - `storage` - a mock storage value, as if it were stored on a real chain
Here is a full example: Here is a full example:
<!--DOCUSAURUS_CODE_TABS-->
<!--Pascaligo--> ```shell
```
ligo dry-run src/basic.ligo main Unit Unit ligo dry-run src/basic.ligo main Unit Unit
// Outputs: // Outputs:
// tuple[ list[] // tuple[ list[]
// 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 Output of the `dry-run` is the return value of our main function, we
storage value being returned - which in our case is still `Unit`. 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 ## A Counter Contract
Our counter contract will store a single `int` as it's storage, and 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` 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--> <Syntax syntax="pascaligo">
<!--Pascaligo-->
``` ```pascaligo
type action is type parameter is
Increment of int Increment of int
| Decrement 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)), ((nil : list(operation)),
(case p of case action of
| Increment (n) -> s + n Increment (n) -> add (n, store)
| Decrement (n) -> s - n | Decrement (n) -> sub (n, store)
end)) end)
``` ```
<!--CameLIGO--> </Syntax>
<Syntax syntax="cameligo">
```cameligo ```cameligo
type action = type parameter =
| Increment of int Increment of int
| Decrement of int | Decrement of int
let main (p, s: action * int) : operation list * int = type storage = int
let result =
match p with type return = (operation) list * storage
| Increment n -> s + n
| Decrement n -> s - n let add (n, store : int * storage) : storage = store + n
in let sub (n, store : int * storage) : storage = store - n
(([]: operation list), result)
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--> </Syntax>
<Syntax syntax="reasonligo">
```reasonligo ```reasonligo
type action = type parameter =
| Increment(int) Increment (int)
| Decrement(int); | Decrement (int)
;
let main = (p_s: (action, int)) : (list(operation), int) => { type storage = int;
let p, s = p_s;
let result = type return = (list (operation), storage);
switch (p) {
| Increment(n) => s + n let add = ((n, store) : (int, storage)) : storage => store + n;
| Decrement(n) => s - n let sub = ((n, store) : (int, storage)) : storage => store - n;
};
(([]: list(operation)), result); 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--> </Syntax>
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`.
```shell
<!--DOCUSAURUS_CODE_TABS-->
<!--Pascaligo-->
```
ligo dry-run src/counter.ligo main "Increment(5)" 5 ligo dry-run src/counter.ligo main "Increment(5)" 5
// tuple[ list[] // tuple[ list[]
// 10 // 10
// ] // ]
``` ```
<!--END_DOCUSAURUS_CODE_TABS-->
Our contract's storage has been successfuly incremented to `10`. Our contract's storage has been successfuly incremented to `10`.
@ -114,86 +137,68 @@ In order to deploy the counter contract to a real Tezos network, we'd
have to compile it first, this can be done with the help of the have to compile it first, this can be done with the help of the
`compile-contract` CLI command: `compile-contract` CLI command:
<!--DOCUSAURUS_CODE_TABS--> ```shell
<!--Pascaligo-->
```
ligo compile-contract src/counter.ligo main ligo compile-contract src/counter.ligo main
``` ```
<!--END_DOCUSAURUS_CODE_TABS-->
Command above will output the following Michelson code: Command above will output the following Michelson code:
<!--DOCUSAURUS_CODE_TABS-->
<!--Pascaligo--> ```michelson
```
{ parameter (or (int %decrement) (int %increment)) ; { parameter (or (int %decrement) (int %increment)) ;
storage int ; storage int ;
code { DUP ; code { DUP ;
CAR ;
DIP { DUP } ;
SWAP ;
CDR ; CDR ;
DIP { DUP } ; DIP { DUP } ;
SWAP ; SWAP ;
CAR ;
IF_LEFT IF_LEFT
{ DUP ; { DUP ;
DIP 2 { DUP } ; DIP { DIP { DUP } ; SWAP } ;
DIG 2 ; PAIR ;
DIP { DUP } ; DUP ;
CDR ;
DIP { DUP ; CAR } ;
SUB ; SUB ;
SWAP ; DIP { DROP 2 } }
DROP ;
SWAP ;
DROP }
{ DUP ; { DUP ;
DIP 2 { DUP } ; DIP { DIP { DUP } ; SWAP } ;
DIG 2 ; PAIR ;
DIP { DUP } ; DUP ;
CDR ;
DIP { DUP ; CAR } ;
ADD ; ADD ;
SWAP ; DIP { DROP 2 } } ;
DROP ;
SWAP ;
DROP } ;
NIL operation ; NIL operation ;
PAIR ; PAIR ;
SWAP ; DIP { DROP 2 } } }
DROP ;
SWAP ;
DROP ;
SWAP ;
DROP } }
``` ```
<!--END_DOCUSAURUS_CODE_TABS-->
However in order to originate a Michelson contract on Tezos, we also However in order to originate a Michelson contract on Tezos, we also
need to provide the initial storage value, we can use need to provide the initial storage value, we can use
`compile-storage` to compile the LIGO representation of the storage to `compile-storage` to compile the LIGO representation of the storage to
Michelson. Michelson.
<!--DOCUSAURUS_CODE_TABS--> ```shell
<!--Pascaligo-->
```
ligo compile-storage src/counter.ligo main 5 ligo compile-storage src/counter.ligo main 5
// Outputs: 5 // Outputs: 5
``` ```
<!--END_DOCUSAURUS_CODE_TABS-->
In our case the LIGO storage value maps 1:1 to its Michelson
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. 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 ## 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--> ```shell
<!--Pascaligo-->
```
ligo compile-parameter src/counter.ligo main 'Increment(5)' ligo compile-parameter src/counter.ligo main 'Increment(5)'
// Outputs: (Right 5) // Outputs: (Right 5)
``` ```
<!--END_DOCUSAURUS_CODE_TABS-->
Now we can use `(Right 5)` which is a Michelson value, to invoke our 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

@ -3,6 +3,8 @@ id: include
title: Including Other Contracts title: Including Other Contracts
--- ---
import Syntax from '@theme/Syntax';
Let us say that we have a contract that is getting a too large. If it Let us say that we have a contract that is getting a too large. If it
has a modular structure, you might find it useful to use the has a modular structure, you might find it useful to use the
`#include` statement to split the contract up over multiple files. `#include` statement to split the contract up over multiple files.
@ -10,9 +12,10 @@ has a modular structure, you might find it useful to use the
You take the code that you want to include and put it in a separate You take the code that you want to include and put it in a separate
file, for example `included.ligo`: file, for example `included.ligo`:
<!--DOCUSAURUS_CODE_TABS-->
<!--PascaLIGO-->
<Syntax syntax="pascaligo">
```pascaligo ```pascaligo
// Demonstrate PascaLIGO inclusion statements, see includer.ligo // Demonstrate PascaLIGO inclusion statements, see includer.ligo
@ -20,46 +23,57 @@ file, for example `included.ligo`:
const foo : int = 144 const foo : int = 144
``` ```
<!--CameLIGO--> </Syntax>
<Syntax syntax="cameligo">
```cameligo ```cameligo
// Demonstrate CameLIGO inclusion statements, see includer.mligo // Demonstrate CameLIGO inclusion statements, see includer.mligo
let foo : int = 144 let foo : int = 144
``` ```
<!--ReasonLIGO--> </Syntax>
<Syntax syntax="reasonligo">
```reasonligo ```reasonligo
// Demonstrate ReasonLIGO inclusion statements, see includer.religo // Demonstrate ReasonLIGO inclusion statements, see includer.religo
let foo : int = 144; let foo : int = 144;
``` ```
<!--END_DOCUSAURUS_CODE_TABS--> </Syntax>
And then you can include this code using the `#include` statement like so: And then you can include this code using the `#include` statement like so:
<!--DOCUSAURUS_CODE_TABS-->
<!--PascaLIGO-->
<Syntax syntax="pascaligo">
```pascaligo ```pascaligo
#include "included.ligo" #include "included.ligo"
const bar : int = foo const bar : int = foo
``` ```
<!--CameLIGO--> </Syntax>
<Syntax syntax="cameligo">
```cameligo ```cameligo
#include "included.mligo" #include "included.mligo"
let bar : int = foo let bar : int = foo
``` ```
<!--ReasonLIGO--> </Syntax>
<Syntax syntax="reasonligo">
```reasonligo ```reasonligo
#include "included.religo" #include "included.religo"
let bar : int = foo; let bar : int = foo;
``` ```
<!--END_DOCUSAURUS_CODE_TABS--> </Syntax>

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

@ -3,6 +3,8 @@ id: timestamps-addresses
title: Timestamps, Addresses title: Timestamps, Addresses
--- ---
import Syntax from '@theme/Syntax';
## Timestamps ## Timestamps
LIGO features timestamps, as Michelson does, while bakers baking the LIGO features timestamps, as Michelson does, while bakers baking the
@ -15,26 +17,38 @@ You can obtain the current time using the built-in syntax specific
expression, please be aware that it is up to the baker to set the expression, please be aware that it is up to the baker to set the
current timestamp value. current timestamp value.
<!--DOCUSAURUS_CODE_TABS-->
<!--PascaLIGO--> <Syntax syntax="pascaligo">
```pascaligo group=a ```pascaligo group=a
const today : timestamp = now const today : timestamp = Tezos.now
``` ```
<!--CameLIGO--> > Note that `now` is *deprecated*.
</Syntax>
<Syntax syntax="cameligo">
```cameligo group=a ```cameligo group=a
let today : timestamp = Current.time let today : timestamp = Tezos.now
``` ```
<!--ReasonLIGO--> > Note that `Current.time` is *deprecated*.
</Syntax>
<Syntax syntax="reasonligo">
```reasonligo group=a ```reasonligo group=a
let today : timestamp = Current.time; let today : timestamp = Tezos.now;
``` ```
<!--END_DOCUSAURUS_CODE_TABS--> > Note that `Current.time` is *deprecated*.
> When running code, the LIGO CLI option </Syntax>
> `--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 ### Timestamp Arithmetics
@ -43,84 +57,120 @@ constraints on your smart contracts. Consider the following scenarios.
#### In 24 hours #### In 24 hours
<!--DOCUSAURUS_CODE_TABS-->
<!--PascaLIGO--> <Syntax syntax="pascaligo">
```pascaligo group=b ```pascaligo group=b
const today : timestamp = now const today : timestamp = Tezos.now
const one_day : int = 86400 const one_day : int = 86400
const in_24_hrs : timestamp = today + one_day const in_24_hrs : timestamp = today + one_day
const some_date : timestamp = ("2000-01-01T10:10:10Z" : timestamp) const some_date : timestamp = ("2000-01-01T10:10:10Z" : timestamp)
const one_day_later : timestamp = some_date + one_day const one_day_later : timestamp = some_date + one_day
``` ```
<!--CameLIGO--> > Note that `now` is *deprecated*.
</Syntax>
<Syntax syntax="cameligo">
```cameligo group=b ```cameligo group=b
let today : timestamp = Current.time let today : timestamp = Tezos.now
let one_day : int = 86400 let one_day : int = 86400
let in_24_hrs : timestamp = today + one_day let in_24_hrs : timestamp = today + one_day
let some_date : timestamp = ("2000-01-01t10:10:10Z" : timestamp) let some_date : timestamp = ("2000-01-01t10:10:10Z" : timestamp)
let one_day_later : timestamp = some_date + one_day let one_day_later : timestamp = some_date + one_day
``` ```
<!--ReasonLIGO--> > Note that `Current.time` is *deprecated*.
</Syntax>
<Syntax syntax="reasonligo">
```reasonligo group=b ```reasonligo group=b
let today : timestamp = Current.time; let today : timestamp = Tezos.now;
let one_day : int = 86400; let one_day : int = 86400;
let in_24_hrs : timestamp = today + one_day; let in_24_hrs : timestamp = today + one_day;
let some_date : timestamp = ("2000-01-01t10:10:10Z" : timestamp); let some_date : timestamp = ("2000-01-01t10:10:10Z" : timestamp);
let one_day_later : timestamp = some_date + one_day; let one_day_later : timestamp = some_date + one_day;
``` ```
<!--END_DOCUSAURUS_CODE_TABS--> > Note that `Current.time` is *deprecated*.
</Syntax>
#### 24 hours Ago #### 24 hours Ago
<!--DOCUSAURUS_CODE_TABS-->
<!--PascaLIGO--> <Syntax syntax="pascaligo">
```pascaligo group=c ```pascaligo group=c
const today : timestamp = now const today : timestamp = Tezos.now
const one_day : int = 86400 const one_day : int = 86400
const in_24_hrs : timestamp = today - one_day const in_24_hrs : timestamp = today - one_day
``` ```
<!--CameLIGO--> > Note that `now` is *deprecated*.
</Syntax>
<Syntax syntax="cameligo">
```cameligo group=c ```cameligo group=c
let today : timestamp = Current.time let today : timestamp = Tezos.now
let one_day : int = 86400 let one_day : int = 86400
let in_24_hrs : timestamp = today - one_day let in_24_hrs : timestamp = today - one_day
``` ```
<!--ReasonLIGO--> > Note that `Current.time` is *deprecated*.
</Syntax>
<Syntax syntax="reasonligo">
```reasonligo group=c ```reasonligo group=c
let today : timestamp = Current.time; let today : timestamp = Tezos.now;
let one_day : int = 86400; let one_day : int = 86400;
let in_24_hrs : timestamp = today - one_day; let in_24_hrs : timestamp = today - one_day;
``` ```
<!--END_DOCUSAURUS_CODE_TABS--> > Note that `Current.time` is *deprecated*.
</Syntax>
### Comparing Timestamps ### Comparing Timestamps
You can compare timestamps using the same comparison operators You can compare timestamps using the same comparison operators
applying to numbers. applying to numbers.
<!--DOCUSAURUS_CODE_TABS-->
<!--PascaLIGO--> <Syntax syntax="pascaligo">
```pascaligo group=c ```pascaligo group=c
const not_tommorow : bool = (now = in_24_hrs) const not_tommorow : bool = (Tezos.now = in_24_hrs)
``` ```
<!--CameLIGO--> > Note that `now` is *deprecated*.
</Syntax>
<Syntax syntax="cameligo">
```cameligo group=c ```cameligo group=c
let not_tomorrow : bool = (Current.time = in_24_hrs) let not_tomorrow : bool = (Tezos.now = in_24_hrs)
``` ```
<!--ReasonLIGO--> > Note that `Current.time` is *deprecated*.
</Syntax>
<Syntax syntax="reasonligo">
```reasonligo group=c ```reasonligo group=c
let not_tomorrow : bool = (Current.time == in_24_hrs); let not_tomorrow : bool = (Tezos.now == in_24_hrs);
``` ```
<!--END_DOCUSAURUS_CODE_TABS--> > Note that `Current.time` is *deprecated*.
</Syntax>
## Addresses ## Addresses
@ -129,26 +179,32 @@ KT1, ...). Currently, addresses are created by casting a string to the
`address` type. Beware of failures if the address is invalid. Consider `address` type. Beware of failures if the address is invalid. Consider
the following examples. the following examples.
<!--DOCUSAURUS_CODE_TABS-->
<!--PascaLIGO--> <Syntax syntax="pascaligo">
```pascaligo group=d ```pascaligo group=d
const my_account : address = const my_account : address =
("tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx" : address) ("tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx" : address)
``` ```
<!--CameLIGO--> </Syntax>
<Syntax syntax="cameligo">
```cameligo group=d ```cameligo group=d
let my_account : address = let my_account : address =
("tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx" : address) ("tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx" : address)
``` ```
<!--ReasonLIGO--> </Syntax>
<Syntax syntax="reasonligo">
```reasonligo group=d ```reasonligo group=d
let my_account : address = let my_account : address =
("tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx" : address); ("tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx" : address);
``` ```
<!--END_DOCUSAURUS_CODE_TABS--> </Syntax>
## Signatures ## Signatures
@ -158,26 +214,35 @@ failure if the signature is invalid.
Here is how you can define a signature: Here is how you can define a signature:
<!--DOCUSAURUS_CODE_TABS-->
<!--PascaLIGO--> <Syntax syntax="pascaligo">
```pascaligo group=e ```pascaligo group=e
const my_sig : signature = const my_sig : signature =
("edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7" : ("edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7" :
signature) signature)
``` ```
<!--CameLIGO-->
</Syntax>
<Syntax syntax="cameligo">
```cameligo group=e ```cameligo group=e
let my_sig : signature = let my_sig : signature =
("edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7" : ("edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7" :
signature) signature)
``` ```
<!--ReasonLIGO-->
</Syntax>
<Syntax syntax="reasonligo">
```reasonligo group=e ```reasonligo group=e
let my_sig : signature = let my_sig : signature =
("edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7" : ("edsigthTzJ8X7MPmNeEwybRAvdxS1pupqcM5Mk4uCuyZAe7uEk68YpuGDeViW8wSXMrCi5CwoNgqs8V2w8ayB5dMJzrYCHhD8C7" :
signature); signature);
``` ```
<!--END_DOCUSAURUS_CODE_TABS-->
</Syntax>
## Keys ## Keys
@ -187,20 +252,29 @@ failure if the key is invalid.
Here is how you can define a key. Here is how you can define a key.
<!--DOCUSAURUS_CODE_TABS-->
<!--PascaLIGO--> <Syntax syntax="pascaligo">
```pascaligo group=f ```pascaligo group=f
const my_key : key = const my_key : key =
("edpkuBknW28nW72KG6RoHtYW7p12T6GKc7nAbwYX5m8Wd9sDVC9yav" : key) ("edpkuBknW28nW72KG6RoHtYW7p12T6GKc7nAbwYX5m8Wd9sDVC9yav" : key)
``` ```
<!--CameLIGO-->
</Syntax>
<Syntax syntax="cameligo">
```cameligo group=f ```cameligo group=f
let my_key : key = let my_key : key =
("edpkuBknW28nW72KG6RoHtYW7p12T6GKc7nAbwYX5m8Wd9sDVC9yav" : key) ("edpkuBknW28nW72KG6RoHtYW7p12T6GKc7nAbwYX5m8Wd9sDVC9yav" : key)
``` ```
<!--ReasonLIGO-->
</Syntax>
<Syntax syntax="reasonligo">
```reasonligo group=f ```reasonligo group=f
let my_key : key = let my_key : key =
("edpkuBknW28nW72KG6RoHtYW7p12T6GKc7nAbwYX5m8Wd9sDVC9yav" : key); ("edpkuBknW28nW72KG6RoHtYW7p12T6GKc7nAbwYX5m8Wd9sDVC9yav" : key);
``` ```
<!--END_DOCUSAURUS_CODE_TABS-->
</Syntax>

View File

@ -2,14 +2,17 @@
id: cheat-sheet id: cheat-sheet
title: Cheat Sheet title: Cheat Sheet
--- ---
<div class="cheatsheet">
import Syntax from '@theme/Syntax';
<div className="cheatsheet">
<!-- <!--
Note that this table is not compiled before production and currently needs to be managed manually. Note that this table is not compiled before production and currently needs to be managed manually.
--> -->
<!--DOCUSAURUS_CODE_TABS-->
<!--PascaLIGO--> <Syntax syntax="pascaligo">
|Primitive |Example| |Primitive |Example|
|--- |---| |--- |---|
@ -30,10 +33,10 @@ Note that this table is not compiled before production and currently needs to be
|Includes|```#include "library.ligo"```| |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 (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>| |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>| |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| ```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``` | |Assignment on an existing variable <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``` |
|Type Annotations| ```("tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx" : address)```| |Type Annotations| ```("tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx" : address)```|
|Variants|<pre><code>type action is<br/>&#124; Increment of int<br/>&#124; Decrement of int</code></pre>| |Variants|<pre><code>type action is<br/>&#124; Increment of int<br/>&#124; Decrement of int</code></pre>|
|Variant *(pattern)* matching|<pre><code>const a: action = Increment(5);<br/>case a of<br/>&#124; Increment(n) -> n + 1<br/>&#124; Decrement(n) -> n - 1<br/>end</code></pre>| |Variant *(pattern)* matching|<pre><code>const a: action = Increment(5);<br/>case a of<br/>&#124; Increment(n) -> n + 1<br/>&#124; Decrement(n) -> n - 1<br/>end</code></pre>|
@ -41,9 +44,10 @@ 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>| |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>| |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>| |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--> </Syntax>
<Syntax syntax="cameligo">
|Primitive |Example| |Primitive |Example|
|--- |---| |--- |---|
@ -63,7 +67,7 @@ Note that this table is not compiled before production and currently needs to be
|Types|`type age = int`, `type name = string` | |Types|`type age = int`, `type name = string` |
|Includes|```#include "library.mligo"```| |Includes|```#include "library.mligo"```|
|Functions |<pre><code>let add (a : int) (b : int) : int = a + b </code></pre>| |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>| |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```| |Variable Binding | ```let age: int = 5```|
|Type Annotations| ```("tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx" : address)```| |Type Annotations| ```("tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx" : address)```|
@ -71,11 +75,12 @@ 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>| |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>| |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>| |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>| |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/> Operation.transaction unit amount receiver</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.")`| |Exception/Failure|`failwith ("Your descriptive error message for the user goes here.")`|
<!--ReasonLIGO--> </Syntax>
<Syntax syntax="reasonligo">
|Primitive |Example| |Primitive |Example|
|--- |---| |--- |---|
@ -95,7 +100,7 @@ Note that this table is not compiled before production and currently needs to be
|Types|`type age = int;`, `type name = string;` | |Types|`type age = int;`, `type name = string;` |
|Includes|```#include "library.mligo"```| |Includes|```#include "library.mligo"```|
|Functions |<pre><code>let add = (a: int, b: int) : int => a + b; </code></pre>| |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>| |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;```| |Variable Binding | ```let age: int = 5;```|
|Type Annotations| ```("tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx" : address)```| |Type Annotations| ```("tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx" : address)```|
@ -103,11 +108,12 @@ 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>| |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>| |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>| |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>| |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/> Operation.transaction (unit, amount, receiver);</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.");`| |Exception/Failure|`failwith ("Your descriptive error message for the user goes here.");`|
</Syntax>
<!--END_DOCUSAURUS_CODE_TABS-->
</div> </div>

View File

@ -3,6 +3,9 @@ id: introduction
title: Introduction To LIGO title: Introduction To LIGO
--- ---
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
LIGO is a programming language for writing [Tezos](https://tezos.com/) smart contracts. LIGO is a programming language for writing [Tezos](https://tezos.com/) smart contracts.
Smart contracts are a unique domain with extreme resource constraints and even Smart contracts are a unique domain with extreme resource constraints and even
more extreme security risks. Unlike desktop, mobile, or web more extreme security risks. Unlike desktop, mobile, or web
@ -49,8 +52,17 @@ Let's define some LIGO contract in the three flavours above. Do
not worry if it is a little confusing at first; we will explain all not worry if it is a little confusing at first; we will explain all
the syntax in the upcoming sections of the documentation. the syntax in the upcoming sections of the documentation.
<!--DOCUSAURUS_CODE_TABS-->
<!--PascaLIGO--> <Tabs
defaultValue="pascaligo"
values={[
{ label: 'PascaLIGO', value: 'pascaligo', },
{ label: 'CameLIGO', value: 'cameligo', },
{ label: 'ReasonLIGO', value: 'reasonligo', },
]
}>
<TabItem value="pascaligo">
```pascaligo group=a ```pascaligo group=a
type storage is int type storage is int
@ -70,7 +82,9 @@ function main (const action : parameter; const store : storage) : return is
end) end)
``` ```
<!--CameLIGO--> </TabItem>
<TabItem value="cameligo">
```cameligo group=a ```cameligo group=a
type storage = int type storage = int
@ -89,7 +103,9 @@ let main (action, store : parameter * storage) : return =
| Reset -> 0) | Reset -> 0)
``` ```
<!--ReasonLIGO--> </TabItem>
<TabItem value="reasonligo">
```reasonligo group=a ```reasonligo group=a
type storage = int; type storage = int;
@ -108,7 +124,9 @@ let main = ((action, store): (parameter, storage)) : return => {
| Reset => 0})); | Reset => 0}));
}; };
``` ```
<!--END_DOCUSAURUS_CODE_TABS-->
</TabItem>
</Tabs>
This LIGO contract accepts the following LIGO expressions: This LIGO contract accepts the following LIGO expressions:
`Increment(n)`, `Decrement(n)` and `Reset`. Those serve as `Increment(n)`, `Decrement(n)` and `Reset`. Those serve as

View File

@ -3,28 +3,39 @@ id: boolean-if-else
title: Booleans and Conditionals title: Booleans and Conditionals
--- ---
import Syntax from '@theme/Syntax';
## Booleans ## Booleans
The type of a boolean value is `bool`. Here is how to define a boolean The type of a boolean value is `bool`. Here is how to define a boolean
value: value:
<!--DOCUSAURUS_CODE_TABS-->
<!--PascaLIGO--> <Syntax syntax="pascaligo">
```pascaligo group=a ```pascaligo group=a
const a : bool = True // Notice the capital letter const a : bool = True // Also: true
const b : bool = False // Same. const b : bool = False // Also: false
``` ```
<!--CameLIGO-->
</Syntax>
<Syntax syntax="cameligo">
```cameligo group=a ```cameligo group=a
let a : bool = true let a : bool = true
let b : bool = false let b : bool = false
``` ```
<!--ReasonLIGO-->
</Syntax>
<Syntax syntax="reasonligo">
```reasonligo group=a ```reasonligo group=a
let a : bool = true; let a : bool = true;
let b : bool = false; let b : bool = false;
``` ```
<!--END_DOCUSAURUS_CODE_TABS-->
</Syntax>
## Comparing Values ## Comparing Values
@ -39,31 +50,41 @@ function.
### Comparing Strings ### Comparing Strings
<!--DOCUSAURUS_CODE_TABS-->
<!--PascaLIGO--> <Syntax syntax="pascaligo">
```pascaligo group=b ```pascaligo group=b
const a : string = "Alice" const a : string = "Alice"
const b : string = "Alice" const b : string = "Alice"
const c : bool = (a = b) // True const c : bool = (a = b) // True
``` ```
<!--CameLIGO-->
</Syntax>
<Syntax syntax="cameligo">
```cameligo group=b ```cameligo group=b
let a : string = "Alice" let a : string = "Alice"
let b : string = "Alice" let b : string = "Alice"
let c : bool = (a = b) // true let c : bool = (a = b) // true
``` ```
<!--ReasonLIGO-->
</Syntax>
<Syntax syntax="reasonligo">
```reasonligo group=b ```reasonligo group=b
let a : string = "Alice"; let a : string = "Alice";
let b : string = "Alice"; let b : string = "Alice";
let c : bool = (a == b); // true let c : bool = (a == b); // true
``` ```
<!--END_DOCUSAURUS_CODE_TABS-->
</Syntax>
### Comparing numbers ### Comparing numbers
<!--DOCUSAURUS_CODE_TABS-->
<!--PascaLIGO--> <Syntax syntax="pascaligo">
```pascaligo group=c ```pascaligo group=c
const a : int = 5 const a : int = 5
const b : int = 4 const b : int = 4
@ -74,7 +95,10 @@ const f : bool = (a <= b)
const g : bool = (a >= b) const g : bool = (a >= b)
const h : bool = (a =/= b) const h : bool = (a =/= b)
``` ```
<!--CameLIGO-->
</Syntax>
<Syntax syntax="cameligo">
```cameligo group=c ```cameligo group=c
let a : int = 5 let a : int = 5
let b : int = 4 let b : int = 4
@ -86,7 +110,9 @@ let g : bool = (a >= b)
let h : bool = (a <> b) let h : bool = (a <> b)
``` ```
<!--ReasonLIGO--> </Syntax>
<Syntax syntax="reasonligo">
```reasonligo group=c ```reasonligo group=c
let a : int = 5; let a : int = 5;
let b : int = 4; let b : int = 4;
@ -97,33 +123,43 @@ let f : bool = (a <= b);
let g : bool = (a >= b); let g : bool = (a >= b);
let h : bool = (a != b); let h : bool = (a != b);
``` ```
<!--END_DOCUSAURUS_CODE_TABS-->
</Syntax>
### Comparing tez ### Comparing tez
> 💡 Comparing `tez` values is especially useful when dealing with an > 💡 Comparing `tez` values is especially useful when dealing with an
> amount sent in a transaction. > amount sent in a transaction.
<!--DOCUSAURUS_CODE_TABS-->
<!--PascaLIGO--> <Syntax syntax="pascaligo">
```pascaligo group=d ```pascaligo group=d
const a : tez = 5mutez const a : tez = 5mutez
const b : tez = 10mutez const b : tez = 10mutez
const c : bool = (a = b) // False const c : bool = (a = b) // False
``` ```
<!--CameLIGO-->
</Syntax>
<Syntax syntax="cameligo">
```cameligo group=d ```cameligo group=d
let a : tez = 5mutez let a : tez = 5mutez
let b : tez = 10mutez let b : tez = 10mutez
let c : bool = (a = b) // false let c : bool = (a = b) // false
``` ```
<!--ReasonLIGO-->
</Syntax>
<Syntax syntax="reasonligo">
```reasonligo group=d ```reasonligo group=d
let a : tez = 5mutez; let a : tez = 5mutez;
let b : tez = 10mutez; let b : tez = 10mutez;
let c : bool = (a == b); // false let c : bool = (a == b); // false
``` ```
<!--END_DOCUSAURUS_CODE_TABS-->
</Syntax>
## Conditionals ## Conditionals
@ -131,13 +167,14 @@ let c : bool = (a == b); // false
Conditional logic enables forking the control flow depending on the Conditional logic enables forking the control flow depending on the
state. state.
<!--DOCUSAURUS_CODE_TABS-->
<!--PascaLIGO--> <Syntax syntax="pascaligo">
```pascaligo group=e ```pascaligo group=e
type magnitude is Small | Large // See variant types. type magnitude is Small | Large // See variant types.
function compare (const n : nat) : magnitude is 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 You can run the `compare` function defined above using the LIGO compiler
@ -145,7 +182,7 @@ like this:
```shell ```shell
ligo run-function ligo run-function
gitlab-pages/docs/language-basics/boolean-if-else/cond.ligo compare 21n' 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 When the branches of the conditional are not a single expression, as
@ -161,7 +198,7 @@ else skip;
``` ```
As an exception to the rule, the blocks in a conditional branch do not 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: instead:
```pascaligo skip ```pascaligo skip
if x < y then { if x < y then {
@ -171,7 +208,9 @@ if x < y then {
else skip; else skip;
``` ```
<!--CameLIGO--> </Syntax>
<Syntax syntax="cameligo">
```cameligo group=e ```cameligo group=e
type magnitude = Small | Large // See variant types. type magnitude = Small | Large // See variant types.
@ -187,9 +226,16 @@ gitlab-pages/docs/language-basics/boolean-if-else/cond.mligo compare 21n'
# Outputs: Large # Outputs: Large
``` ```
<!--ReasonLIGO--> > 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`.
</Syntax>
<Syntax syntax="reasonligo">
```reasonligo group=e ```reasonligo group=e
type magnitude = | Small | Large; // See variant types. type magnitude = Small | Large; // See variant types.
let compare = (n : nat) : magnitude => let compare = (n : nat) : magnitude =>
if (n < 10n) { Small; } else { Large; }; if (n < 10n) { Small; } else { Large; };
@ -202,4 +248,6 @@ ligo run-function
gitlab-pages/docs/language-basics/boolean-if-else/cond.religo compare 21n' gitlab-pages/docs/language-basics/boolean-if-else/cond.religo compare 21n'
# Outputs: Large # Outputs: Large
``` ```
<!--END_DOCUSAURUS_CODE_TABS-->
</Syntax>

View File

@ -3,13 +3,23 @@ id: functions
title: Functions title: Functions
--- ---
import Syntax from '@theme/Syntax';
LIGO functions are the basic building block of contracts. For example, 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 ## Declaring Functions
<!--DOCUSAURUS_CODE_TABS-->
<!--PascaLIGO--> <Syntax syntax="pascaligo">
There are two ways in PascaLIGO to define functions: with or without a There are two ways in PascaLIGO to define functions: with or without a
*block*. *block*.
@ -83,7 +93,8 @@ ligo run-function gitlab-pages/docs/language-basics/src/functions/blockless.ligo
# Outputs: 3 # Outputs: 3
``` ```
<!--CameLIGO--> </Syntax>
<Syntax syntax="cameligo">
Functions in CameLIGO are defined using the `let` keyword, like other Functions in CameLIGO are defined using the `let` keyword, like other
values. The difference is that a succession of parameters is provided values. The difference is that a succession of parameters is provided
@ -125,7 +136,7 @@ returns an integer as well:
```cameligo group=b ```cameligo group=b
let add (a, b : int * int) : int = a + b // Uncurried let add (a, b : int * int) : int = a + b // Uncurried
let add_curry (a : int) (b : int) : int = add (a, b) // Curried let add_curry (a : int) (b : int) : int = add (a, b) // Curried
let increment (b : int) : int = add_curry 1 // Partial application let increment : int -> int = add_curry 1 // Partial application
``` ```
You can run the `increment` function defined above using the LIGO You can run the `increment` function defined above using the LIGO
@ -137,7 +148,8 @@ ligo run-function gitlab-pages/docs/language-basics/src/functions/curry.mligo in
The function body is a single expression, whose value is returned. The function body is a single expression, whose value is returned.
<!--ReasonLIGO--> </Syntax>
<Syntax syntax="reasonligo">
Functions in ReasonLIGO are defined using the `let` keyword, like Functions in ReasonLIGO are defined using the `let` keyword, like
other values. The difference is that a tuple of parameters is provided other values. The difference is that a tuple of parameters is provided
@ -168,7 +180,8 @@ let myFun = ((x, y) : (int, int)) : int => {
}; };
``` ```
<!--END_DOCUSAURUS_CODE_TABS--> </Syntax>
## Anonymous functions (a.k.a. lambdas) ## Anonymous functions (a.k.a. lambdas)
@ -178,8 +191,9 @@ a key in a record or a map.
Here is how to define an anonymous function: Here is how to define an anonymous function:
<!--DOCUSAURUS_CODE_TABS-->
<!--PascaLIGO--> <Syntax syntax="pascaligo">
```pascaligo group=c ```pascaligo group=c
function increment (const b : int) : int is function increment (const b : int) : int is
(function (const a : int) : int is a + 1) (b) (function (const a : int) : int is a + 1) (b)
@ -193,7 +207,9 @@ ligo evaluate-value gitlab-pages/docs/language-basics/src/functions/anon.ligo a
# Outputs: 2 # Outputs: 2
``` ```
<!--CameLIGO--> </Syntax>
<Syntax syntax="cameligo">
```cameligo group=c ```cameligo group=c
let increment (b : int) : int = (fun (a : int) -> a + 1) b let increment (b : int) : int = (fun (a : int) -> a + 1) b
let a : int = increment 1 // a = 2 let a : int = increment 1 // a = 2
@ -206,7 +222,9 @@ ligo evaluate-value gitlab-pages/docs/language-basics/src/functions/anon.mligo a
# Outputs: 2 # Outputs: 2
``` ```
<!--ReasonLIGO--> </Syntax>
<Syntax syntax="reasonligo">
```reasonligo group=c ```reasonligo group=c
let increment = (b : int) : int => ((a : int) : int => a + 1) (b); let increment = (b : int) : int => ((a : int) : int => a + 1) (b);
let a : int = increment (1); // a == 2 let a : int = increment (1); // a == 2
@ -219,21 +237,27 @@ ligo evaluate-value gitlab-pages/docs/language-basics/src/functions/anon.religo
# Outputs: 2 # Outputs: 2
``` ```
<!--END_DOCUSAURUS_CODE_TABS--> </Syntax>
If the example above seems contrived, here is a more common design If the example above seems contrived, here is a more common design
pattern for lambdas: to be used as parameters to functions. Consider pattern for lambdas: to be used as parameters to functions. Consider
the use case of having a list of integers and mapping the increment the use case of having a list of integers and mapping the increment
function to all its elements. function to all its elements.
<!--DOCUSAURUS_CODE_TABS-->
<!--PascaLIGO--> <Syntax syntax="pascaligo">
```pascaligo group=c ```pascaligo group=c
function incr_map (const l : list (int)) : list (int) is 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 ```shell
ligo run-function ligo run-function
gitlab-pages/docs/language-basics/src/functions/incr_map.ligo incr_map gitlab-pages/docs/language-basics/src/functions/incr_map.ligo incr_map
@ -241,7 +265,9 @@ gitlab-pages/docs/language-basics/src/functions/incr_map.ligo incr_map
# Outputs: [ 2 ; 3 ; 4 ] # Outputs: [ 2 ; 3 ; 4 ]
``` ```
<!--CameLIGO--> </Syntax>
<Syntax syntax="cameligo">
```cameligo group=c ```cameligo group=c
let incr_map (l : int list) : int list = let incr_map (l : int list) : int list =
List.map (fun (i : int) -> i + 1) l List.map (fun (i : int) -> i + 1) l
@ -255,7 +281,9 @@ gitlab-pages/docs/language-basics/src/functions/incr_map.mligo incr_map
# Outputs: [ 2 ; 3 ; 4 ] # Outputs: [ 2 ; 3 ; 4 ]
``` ```
<!--ReasonLIGO--> </Syntax>
<Syntax syntax="reasonligo">
```reasonligo group=c ```reasonligo group=c
let incr_map = (l : list (int)) : list (int) => let incr_map = (l : list (int)) : list (int) =>
List.map ((i : int) => i + 1, l); List.map ((i : int) => i + 1, l);
@ -269,4 +297,5 @@ gitlab-pages/docs/language-basics/src/functions/incr_map.religo incr_map
# Outputs: [ 2 ; 3 ; 4 ] # Outputs: [ 2 ; 3 ; 4 ]
``` ```
<!--END_DOCUSAURUS_CODE_TABS--> </Syntax>

View File

@ -3,11 +3,13 @@ id: loops
title: Loops title: Loops
--- ---
import Syntax from '@theme/Syntax';
## General Iteration ## General Iteration
<!--DOCUSAURUS_CODE_TABS-->
<!--PascaLIGO-->
<Syntax syntax="pascaligo">
General iteration in PascaLIGO takes the shape of general loops, which General iteration in PascaLIGO takes the shape of general loops, which
should be familiar to programmers of imperative languages as "while should be familiar to programmers of imperative languages as "while
@ -47,7 +49,8 @@ gitlab-pages/docs/language-basics/src/loops/gcd.ligo gcd '(2n*2n*3n*11n, 2n*2n*2
# Outputs: +12 # Outputs: +12
``` ```
<!--CameLIGO--> </Syntax>
<Syntax syntax="cameligo">
CameLIGO is a functional language where user-defined values are CameLIGO is a functional language where user-defined values are
constant, therefore it makes no sense in CameLIGO to feature loops, constant, therefore it makes no sense in CameLIGO to feature loops,
@ -79,17 +82,22 @@ let gcd (x,y : nat * nat) : nat =
``` ```
To ease the writing and reading of the iterated functions (here, 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 ```cameligo group=a
let iter (x,y : nat * nat) : bool * (nat * nat) = 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 gcd (x,y : nat * nat) : nat =
let x,y = if x < y then y,x else x,y in let x,y = if x < y then y,x else x,y in
let x,y = Loop.fold_while iter (x,y) let x,y = Loop.fold_while iter (x,y)
in x in x
``` ```
> Note that `stop` and `continue` (now `Loop.resume`) are
> *deprecated*.
You can call the function `gcd` defined above using the LIGO compiler You can call the function `gcd` defined above using the LIGO compiler
like so: like so:
```shell ```shell
@ -98,7 +106,8 @@ gitlab-pages/docs/language-basics/src/loops/gcd.mligo gcd (2n*2n*3n*11n, 2n*2n*2
# Outputs: +12 # Outputs: +12
``` ```
<!--ReasonLIGO--> </Syntax>
<Syntax syntax="reasonligo">
ReasonLIGO is a functional language where user-defined values are ReasonLIGO is a functional language where user-defined values are
constant, therefore it makes no sense in ReasonLIGO to feature loops, constant, therefore it makes no sense in ReasonLIGO to feature loops,
@ -131,11 +140,12 @@ let gcd = ((x,y) : (nat, nat)) : nat => {
``` ```
To ease the writing and reading of the iterated functions (here, 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 ```reasonligo group=b
let iter = ((x,y) : (nat, nat)) : (bool, (nat, nat)) => 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 gcd = ((x,y) : (nat, nat)) : nat => {
let (x,y) = if (x < y) { (y,x); } else { (x,y); }; let (x,y) = if (x < y) { (y,x); } else { (x,y); };
@ -143,7 +153,12 @@ let gcd = ((x,y) : (nat, nat)) : nat => {
x x
}; };
``` ```
<!--END_DOCUSAURUS_CODE_TABS-->
> Note that `stop` and `continue` (now `Loop.resume`) are
> *deprecated*.
</Syntax>
## Bounded Loops ## Bounded Loops
@ -175,8 +190,8 @@ gitlab-pages/docs/language-basics/src/loops/sum.ligo sum 7n
PascaLIGO "for" loops can also iterate through the contents of a PascaLIGO "for" loops can also iterate through the contents of a
collection, that is, a list, a set or a map. This is done with a loop collection, that is, a list, a set or a map. This is done with a loop
of the form `for <element var> in <collection type> <collection var> of the form `for <element var> in <collection type> <collection var> <block>`,
<block>`, where `<collection type>` is any of the following keywords: where `<collection type>` is any of the following keywords:
`list`, `set` or `map`. `list`, `set` or `map`.
Here is an example where the integers in a list are summed up. Here is an example where the integers in a list are summed up.

File diff suppressed because it is too large Load Diff

View File

@ -3,7 +3,30 @@ id: math-numbers-tez
title: Math, Numbers & Tez title: Math, Numbers & Tez
--- ---
LIGO offers three built-in numerical types: `int`, `nat` and `tez`. import Syntax from '@theme/Syntax';
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 ## Addition
@ -17,8 +40,9 @@ remain in comments as they would otherwise not compile, for example,
adding a value of type `int` to a value of type `tez` is invalid. Note adding a value of type `int` to a value of type `tez` is invalid. Note
that adding an integer to a natural number produces an integer. that adding an integer to a natural number produces an integer.
<!--DOCUSAURUS_CODE_TABS-->
<!--PascaLIGO--> <Syntax syntax="pascaligo">
```pascaligo group=a ```pascaligo group=a
// int + int yields int // int + int yields int
const a : int = 5 + 10 const a : int = 5 + 10
@ -27,7 +51,7 @@ const a : int = 5 + 10
const b : int = 5n + 10 const b : int = 5n + 10
// tez + tez yields tez // tez + tez yields tez
const c : tez = 5mutez + 10mutez const c : tez = 5mutez + 0.000_010tez
//tez + int or tez + nat is invalid //tez + int or tez + nat is invalid
// const d : tez = 5mutez + 10n // const d : tez = 5mutez + 10n
@ -48,7 +72,9 @@ const g : int = 1_000_000
> const sum : tez = 100_000mutez > const sum : tez = 100_000mutez
>``` >```
<!--CameLIGO--> </Syntax>
<Syntax syntax="cameligo">
```cameligo group=a ```cameligo group=a
// int + int yields int // int + int yields int
let a : int = 5 + 10 let a : int = 5 + 10
@ -57,7 +83,7 @@ let a : int = 5 + 10
let b : int = 5n + 10 let b : int = 5n + 10
// tez + tez yields tez // tez + tez yields tez
let c : tez = 5mutez + 10mutez let c : tez = 5mutez + 0.000_010tez
// tez + int or tez + nat is invalid // tez + int or tez + nat is invalid
// let d : tez = 5mutez + 10n // let d : tez = 5mutez + 10n
@ -78,7 +104,9 @@ let g : int = 1_000_000
>let sum : tez = 100_000mutez >let sum : tez = 100_000mutez
>``` >```
<!--ReasonLIGO--> </Syntax>
<Syntax syntax="reasonligo">
```reasonligo group=a ```reasonligo group=a
// int + int yields int // int + int yields int
let a : int = 5 + 10; let a : int = 5 + 10;
@ -87,7 +115,7 @@ let a : int = 5 + 10;
let b : int = 5n + 10; let b : int = 5n + 10;
// tez + tez yields tez // tez + tez yields tez
let c : tez = 5mutez + 10mutez; let c : tez = 5mutez + 0.000_010tez;
// tez + int or tez + nat is invalid: // tez + int or tez + nat is invalid:
// let d : tez = 5mutez + 10n; // let d : tez = 5mutez + 10n;
@ -106,7 +134,9 @@ let g : int = 1_000_000;
>```reasonligo >```reasonligo
>let sum : tex = 100_000mutez; >let sum : tex = 100_000mutez;
>``` >```
<!--END_DOCUSAURUS_CODE_TABS-->
</Syntax>
## Subtraction ## Subtraction
@ -114,8 +144,9 @@ Subtraction looks as follows.
> ⚠️ Even when subtracting two `nats`, the result is an `int` > ⚠️ Even when subtracting two `nats`, the result is an `int`
<!--DOCUSAURUS_CODE_TABS-->
<!--PascaLIGO--> <Syntax syntax="pascaligo">
```pascaligo group=b ```pascaligo group=b
const a : int = 5 - 10 const a : int = 5 - 10
@ -128,7 +159,9 @@ const b : int = 5n - 2n
const d : tez = 5mutez - 1mutez const d : tez = 5mutez - 1mutez
``` ```
<!--CameLIGO--> </Syntax>
<Syntax syntax="cameligo">
```cameligo group=b ```cameligo group=b
let a : int = 5 - 10 let a : int = 5 - 10
@ -141,7 +174,9 @@ let b : int = 5n - 2n
let d : tez = 5mutez - 1mutez let d : tez = 5mutez - 1mutez
``` ```
<!--ReasonLIGO--> </Syntax>
<Syntax syntax="reasonligo">
```reasonligo group=b ```reasonligo group=b
let a : int = 5 - 10; let a : int = 5 - 10;
@ -154,15 +189,16 @@ let b : int = 5n - 2n;
let d : tez = 5mutez - 1mutez; let d : tez = 5mutez - 1mutez;
``` ```
<!--END_DOCUSAURUS_CODE_TABS--> </Syntax>
## Multiplication ## Multiplication
You can multiply values of the same type, such as: You can multiply values of the same type, such as:
<!--DOCUSAURUS_CODE_TABS-->
<!--PascaLIGO--> <Syntax syntax="pascaligo">
```pascaligo group=c ```pascaligo group=c
const a : int = 5 * 5 const a : int = 5 * 5
@ -172,7 +208,9 @@ const b : nat = 5n * 5n
const c : tez = 5n * 5mutez const c : tez = 5n * 5mutez
``` ```
<!--CameLIGO--> </Syntax>
<Syntax syntax="cameligo">
```cameligo group=c ```cameligo group=c
let a : int = 5 * 5 let a : int = 5 * 5
let b : nat = 5n * 5n let b : nat = 5n * 5n
@ -181,7 +219,9 @@ let b : nat = 5n * 5n
let c : tez = 5n * 5mutez let c : tez = 5n * 5mutez
``` ```
<!--ReasonLIGO--> </Syntax>
<Syntax syntax="reasonligo">
```reasonligo group=c ```reasonligo group=c
let a : int = 5 * 5; let a : int = 5 * 5;
let b : nat = 5n * 5n; let b : nat = 5n * 5n;
@ -190,62 +230,123 @@ let b : nat = 5n * 5n;
let c : tez = 5n * 5mutez; let c : tez = 5n * 5mutez;
``` ```
<!--END_DOCUSAURUS_CODE_TABS--> </Syntax>
## Division
## Euclidean Division
In LIGO you can divide `int`, `nat`, and `tez`. Here is how: In LIGO you can divide `int`, `nat`, and `tez`. Here is how:
> ⚠️ Division of two `tez` values results into a `nat` > ⚠️ Division of two `tez` values results into a `nat`
<!--DOCUSAURUS_CODE_TABS-->
<!--PascaLIGO--> <Syntax syntax="pascaligo">
```pascaligo group=d ```pascaligo group=d
const a : int = 10 / 3 const a : int = 10 / 3
const b : nat = 10n / 3n const b : nat = 10n / 3n
const c : nat = 10mutez / 3mutez const c : nat = 10mutez / 3mutez
``` ```
<!--CameLIGO--> </Syntax>
<Syntax syntax="cameligo">
```cameligo group=d ```cameligo group=d
let a : int = 10 / 3 let a : int = 10 / 3
let b : nat = 10n / 3n let b : nat = 10n / 3n
let c : nat = 10mutez / 3mutez let c : nat = 10mutez / 3mutez
``` ```
<!--ReasonLIGO--> </Syntax>
<Syntax syntax="reasonligo">
```reasonligo group=d ```reasonligo group=d
let a : int = 10 / 3; let a : int = 10 / 3;
let b : nat = 10n / 3n; let b : nat = 10n / 3n;
let c : nat = 10mutez / 3mutez; let c : nat = 10mutez / 3mutez;
``` ```
<!--END_DOCUSAURUS_CODE_TABS--> </Syntax>
LIGO also allows you to compute the remainder of the Euclidean
division. In LIGO, it is a natural number.
<Syntax syntax="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
```
</Syntax>
<Syntax syntax="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
```
</Syntax>
<Syntax syntax="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
```
</Syntax>
## From `int` to `nat` and back ## From `int` to `nat` and back
You can *cast* an `int` to a `nat` and vice versa. Here is how: You can *cast* an `int` to a `nat` and vice versa. Here is how:
<!--DOCUSAURUS_CODE_TABS-->
<!--PascaLIGO--> <Syntax syntax="pascaligo">
```pascaligo group=e ```pascaligo group=e
const a : int = int (1n) const a : int = int (1n)
const b : nat = abs (1) const b : nat = abs (1)
``` ```
<!--CameLIGO--> </Syntax>
<Syntax syntax="cameligo">
```cameligo group=e ```cameligo group=e
let a : int = int (1n) let a : int = int (1n)
let b : nat = abs (1) let b : nat = abs (1)
``` ```
<!--ReasonLIGO--> </Syntax>
<Syntax syntax="reasonligo">
```reasonligo group=e ```reasonligo group=e
let a : int = int (1n); let a : int = int (1n);
let b : nat = abs (1); let b : nat = abs (1);
``` ```
<!--END_DOCUSAURUS_CODE_TABS--> </Syntax>
## Checking a `nat` ## Checking a `nat`
@ -254,20 +355,26 @@ function which accepts an `int` and returns an optional `nat`: if the
result is not `None`, then the provided integer was indeed a natural result is not `None`, then the provided integer was indeed a natural
number, and not otherwise. number, and not otherwise.
<!--DOCUSAURUS_CODE_TABS-->
<!--PascaLIGO--> <Syntax syntax="pascaligo">
```pascaligo group=e ```pascaligo group=e
const is_a_nat : option (nat) = is_nat (1) const is_a_nat : option (nat) = is_nat (1)
``` ```
<!--CameLIGO--> </Syntax>
<Syntax syntax="cameligo">
```cameligo group=e ```cameligo group=e
let is_a_nat : nat option = Michelson.is_nat (1) let is_a_nat : nat option = Michelson.is_nat (1)
``` ```
<!--ReasonLIGO--> </Syntax>
<Syntax syntax="reasonligo">
```reasonligo group=e ```reasonligo group=e
let is_a_nat : option (nat) = Michelson.is_nat (1); let is_a_nat : option (nat) = Michelson.is_nat (1);
``` ```
<!--END_DOCUSAURUS_CODE_TABS--> </Syntax>

View File

@ -3,13 +3,14 @@ id: operators
title: 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 | |Michelson |Pascaligo |Description |
|--- |--- |--- | |--- |--- |--- |
| `SENDER` | `sender` | Address that initiated the current transaction | `SENDER` | `Tezos.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) | `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` | `amount` | Amount of tez sent by the transaction that invoked the contract | `AMOUNT` | `Tezos.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. | `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

@ -3,6 +3,8 @@ id: sets-lists-tuples
title: Tuples, Lists, Sets title: Tuples, Lists, Sets
--- ---
import Syntax from '@theme/Syntax';
Apart from complex data types such as `maps` and `records`, LIGO also Apart from complex data types such as `maps` and `records`, LIGO also
features `tuples`, `lists` and `sets`. features `tuples`, `lists` and `sets`.
@ -27,9 +29,9 @@ Unlike [a record](language-basics/maps-records.md), tuple types do not
have to be defined before they can be used. However below we will give have to be defined before they can be used. However below we will give
them names by *type aliasing*. them names by *type aliasing*.
<!--DOCUSAURUS_CODE_TABS-->
<!--Pascaligo-->
<Syntax syntax="pascaligo">
```pascaligo group=tuple ```pascaligo group=tuple
type full_name is string * string // Alias type full_name is string * string // Alias
@ -37,7 +39,8 @@ type full_name is string * string // Alias
const full_name : full_name = ("Alice", "Johnson") const full_name : full_name = ("Alice", "Johnson")
``` ```
<!--CameLIGO--> </Syntax>
<Syntax syntax="cameligo">
```cameligo group=tuple ```cameligo group=tuple
type full_name = string * string // Alias type full_name = string * string // Alias
@ -45,7 +48,8 @@ type full_name = string * string // Alias
let full_name : full_name = ("Alice", "Johnson") // Optional parentheses let full_name : full_name = ("Alice", "Johnson") // Optional parentheses
``` ```
<!--ReasonLIGO--> </Syntax>
<Syntax syntax="reasonligo">
```reasonligo group=tuple ```reasonligo group=tuple
type full_name = (string, string); // Alias type full_name = (string, string); // Alias
@ -53,7 +57,8 @@ type full_name = (string, string); // Alias
let full_name : full_name = ("Alice", "Johnson"); let full_name : full_name = ("Alice", "Johnson");
``` ```
<!--END_DOCUSAURUS_CODE_TABS--> </Syntax>
### Accessing Components ### Accessing Components
@ -62,35 +67,34 @@ Accessing the components of a tuple in OCaml is achieved by
[pattern matching](language-basics/unit-option-pattern-matching.md). LIGO [pattern matching](language-basics/unit-option-pattern-matching.md). LIGO
currently supports tuple patterns only in the parameters of functions, currently supports tuple patterns only in the parameters of functions,
not in pattern matching. However, we can access components by their 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: <Syntax syntax="pascaligo">
```pascaligo group=tuple ```pascaligo group=tuple
const first_name : string = full_name.1 const first_name : string = full_name.0
``` ```
<!--CameLIGO--> </Syntax>
<Syntax syntax="cameligo">
Tuple elements are zero-indexed and accessed like so:
```cameligo group=tuple ```cameligo group=tuple
let first_name : string = full_name.0 let first_name : string = full_name.0
``` ```
<!--ReasonLIGO--> </Syntax>
<Syntax syntax="reasonligo">
Tuple components are one-indexed and accessed like so:
```reasonligo group=tuple ```reasonligo group=tuple
let first_name : string = full_name[1]; let first_name : string = full_name[0];
``` ```
<!--END_DOCUSAURUS_CODE_TABS--> </Syntax>
## Lists ## Lists
@ -103,30 +107,35 @@ 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. think of a list a *stack*, where the top is written on the left.
> 💡 Lists are needed when returning operations from a smart > 💡 Lists are needed when returning operations from a smart
> contract's access function. > contract's main function.
### Defining Lists ### Defining Lists
<!--DOCUSAURUS_CODE_TABS-->
<!--PascaLIGO--> <Syntax syntax="pascaligo">
```pascaligo group=lists ```pascaligo group=lists
const empty_list : list (int) = nil // Or list [] const empty_list : list (int) = nil // Or list []
const my_list : list (int) = list [1; 2; 2] // The head is 1 const my_list : list (int) = list [1; 2; 2] // The head is 1
``` ```
<!--CameLIGO--> </Syntax>
<Syntax syntax="cameligo">
```cameligo group=lists ```cameligo group=lists
let empty_list : int list = [] let empty_list : int list = []
let my_list : int list = [1; 2; 2] // The head is 1 let my_list : int list = [1; 2; 2] // The head is 1
``` ```
<!--ReasonLIGO--> </Syntax>
<Syntax syntax="reasonligo">
```reasonligo group=lists ```reasonligo group=lists
let empty_list : list (int) = []; let empty_list : list (int) = [];
let my_list : list (int) = [1, 2, 2]; // The head is 1 let my_list : list (int) = [1, 2, 2]; // The head is 1
``` ```
<!--END_DOCUSAURUS_CODE_TABS--> </Syntax>
### Adding to Lists ### Adding to Lists
@ -135,9 +144,9 @@ Lists can be augmented by adding an element before the head (or, in
terms of stack, by *pushing an element on top*). This operation is terms of stack, by *pushing an element on top*). This operation is
usually called *consing* in functional languages. usually called *consing* in functional languages.
<!--DOCUSAURUS_CODE_TABS-->
<!--PascaLIGO-->
<Syntax syntax="pascaligo">
In PascaLIGO, the *cons operator* is infix and noted `#`. It is not In PascaLIGO, the *cons operator* is infix and noted `#`. It is not
symmetric: on the left lies the element to cons, and, on the right, a symmetric: on the left lies the element to cons, and, on the right, a
@ -148,7 +157,8 @@ you of that.)
const larger_list : list (int) = 5 # my_list // [5;1;2;2] const larger_list : list (int) = 5 # my_list // [5;1;2;2]
``` ```
<!--CameLIGO--> </Syntax>
<Syntax syntax="cameligo">
In CameLIGO, the *cons operator* is infix and noted `::`. It is not In CameLIGO, the *cons operator* is infix and noted `::`. It is not
symmetric: on the left lies the element to cons, and, on the right, a symmetric: on the left lies the element to cons, and, on the right, a
@ -158,7 +168,8 @@ list on which to cons.
let larger_list : int list = 5 :: my_list // [5;1;2;2] let larger_list : int list = 5 :: my_list // [5;1;2;2]
``` ```
<!--ReasonLIGO--> </Syntax>
<Syntax syntax="reasonligo">
In ReasonLIGO, the *cons operator* is infix and noted `, ...`. It is In ReasonLIGO, the *cons operator* is infix and noted `, ...`. It is
not symmetric: on the left lies the element to cons, and, on the not symmetric: on the left lies the element to cons, and, on the
@ -167,7 +178,9 @@ right, a list on which to cons.
```reasonligo group=lists ```reasonligo group=lists
let larger_list : list (int) = [5, ...my_list]; // [5,1,2,2] let larger_list : list (int) = [5, ...my_list]; // [5,1,2,2]
``` ```
<!--END_DOCUSAURUS_CODE_TABS-->
</Syntax>
### Functional Iteration over Lists ### Functional Iteration over Lists
@ -180,48 +193,36 @@ There are three kinds of functional iterations over LIGO lists: the
*iterated operation*, the *map operation* (not to be confused with the *iterated operation*, the *map operation* (not to be confused with the
*map data structure*) and the *fold operation*. *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 #### Iterated Operation over Lists
The first, the *iterated operation*, is an iteration over the list The first, the *iterated operation*, is an iteration over the list
with a unit return value. It is useful to enforce certain invariants 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 on the element of a list, or fail.
that each value inside of a list is within a certain range, and fail
otherwise.
<!--DOCUSAURUS_CODE_TABS--> For example you might want to check that each value inside of a list
is within a certain range, and fail otherwise. The predefined
<!--PascaLIGO--> functional iterator implementing the iterated operation over lists is
called `List.iter`.
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 In the following example, a list is iterated to check that all its
elements (integers) are greater than `3`: elements (integers) are strictly greater than `3`.
<Syntax syntax="pascaligo">
```pascaligo group=lists ```pascaligo group=lists
function iter_op (const l : list (int)) : unit is function iter_op (const l : list (int)) : unit is
block { block {
function iterated (const i : int) : unit is function iterated (const i : int) : unit is
if i > 2 then Unit else (failwith ("Below range.") : unit) if i > 3 then Unit else (failwith ("Below range.") : unit)
} with list_iter (iterated, l) } with List.iter (iterated, l)
``` ```
> The iterated function must be pure, that is, it cannot mutate > Note that `list_iter` is *deprecated*.
> variables.
<!--CameLIGO--> </Syntax>
<Syntax syntax="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 ```cameligo group=lists
let iter_op (l : int list) : unit = let iter_op (l : int list) : unit =
@ -229,13 +230,8 @@ let iter_op (l : int list) : unit =
in List.iter predicate l in List.iter predicate l
``` ```
<!--ReasonLIGO--> </Syntax>
<Syntax syntax="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 ```reasonligo group=lists
let iter_op = (l : list (int)) : unit => { let iter_op = (l : list (int)) : unit => {
@ -244,38 +240,33 @@ let iter_op = (l : list (int)) : unit => {
}; };
``` ```
<!--END_DOCUSAURUS_CODE_TABS--> </Syntax>
#### Mapped Operation over Lists #### Mapped Operation over Lists
We may want to change all the elements of a given list by applying to 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 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 <Syntax syntax="pascaligo">
mapped operation over lists is called `list_map` and is used as
follows:
```pascaligo group=lists ```pascaligo group=lists
function increment (const i : int): int is i + 1 function increment (const i : int): int is i + 1
// Creates a new list with all elements incremented by 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 > Note that `list_map` is *deprecated*.
> variables.
<!--CameLIGO--> </Syntax>
<Syntax syntax="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 ```cameligo group=lists
let increment (i : int) : int = i + 1 let increment (i : int) : int = i + 1
@ -284,11 +275,8 @@ let increment (i : int) : int = i + 1
let plus_one : int list = List.map increment larger_list let plus_one : int list = List.map increment larger_list
``` ```
<!--ReasonLIGO--> </Syntax>
<Syntax syntax="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 ```reasonligo group=lists
let increment = (i : int) : int => i + 1; let increment = (i : int) : int => i + 1;
@ -296,7 +284,9 @@ let increment = (i : int) : int => i + 1;
// Creates a new list with all elements incremented by 1 // Creates a new list with all elements incremented by 1
let plus_one : list (int) = List.map (increment, larger_list); let plus_one : list (int) = List.map (increment, larger_list);
``` ```
<!--END_DOCUSAURUS_CODE_TABS-->
</Syntax>
#### Folded Operation over Lists #### Folded Operation over Lists
@ -305,58 +295,52 @@ A *folded operation* is the most general of iterations. The folded
function takes two arguments: an *accumulator* and the structure function takes two arguments: an *accumulator* and the structure
*element* at hand, with which it then produces a new accumulator. This *element* at hand, with which it then produces a new accumulator. This
enables having a partial result that becomes complete when the 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 <Syntax syntax="pascaligo">
folded operation over lists is called `list_fold` and is used as
follows:
```pascaligo group=lists ```pascaligo group=lists
function sum (const acc : int; const i : int): int is acc + i 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 > Note that `list_fold` is *deprecated*.
> variables.
<!--CameLIGO--> </Syntax>
<Syntax syntax="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 ```cameligo group=lists
let sum (acc, i: int * int) : int = acc + i let sum (acc, i: int * int) : int = acc + i
let sum_of_elements : int = List.fold sum my_list 0 let sum_of_elements : int = List.fold sum my_list 0
``` ```
<!--ReasonLIGO--> </Syntax>
<Syntax syntax="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 ```reasonligo group=lists
let sum = ((result, i): (int, int)): int => result + i; let sum = ((result, i): (int, int)): int => result + i;
let sum_of_elements : int = List.fold (sum, my_list, 0); let sum_of_elements : int = List.fold (sum, my_list, 0);
``` ```
<!--END_DOCUSAURUS_CODE_TABS-->
</Syntax>
## Sets ## Sets
Sets are unordered collections of values of the same type, like lists Sets are unordered collections of values of the same type, like lists
are ordered collections. Like the mathematical sets and lists, sets are ordered collections. Like the mathematical sets and lists, sets
can be empty and, if not, elements of sets in LIGO are *unique*, 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 ### Empty Sets
<!--DOCUSAURUS_CODE_TABS-->
<!--PascaLIGO-->
<Syntax syntax="pascaligo">
In PascaLIGO, the notation for sets is similar to that for lists, In PascaLIGO, the notation for sets is similar to that for lists,
except the keyword `set` is used before: except the keyword `set` is used before:
@ -364,7 +348,9 @@ except the keyword `set` is used before:
```pascaligo group=sets ```pascaligo group=sets
const my_set : set (int) = set [] const my_set : set (int) = set []
``` ```
<!--CameLIGO-->
</Syntax>
<Syntax syntax="cameligo">
In CameLIGO, the empty set is denoted by the predefined value In CameLIGO, the empty set is denoted by the predefined value
`Set.empty`. `Set.empty`.
@ -373,7 +359,8 @@ In CameLIGO, the empty set is denoted by the predefined value
let my_set : int set = Set.empty let my_set : int set = Set.empty
``` ```
<!--ReasonLIGO--> </Syntax>
<Syntax syntax="reasonligo">
In ReasonLIGO, the empty set is denoted by the predefined value In ReasonLIGO, the empty set is denoted by the predefined value
`Set.empty`. `Set.empty`.
@ -381,13 +368,15 @@ In ReasonLIGO, the empty set is denoted by the predefined value
```reasonligo group=sets ```reasonligo group=sets
let my_set : set (int) = Set.empty; let my_set : set (int) = Set.empty;
``` ```
<!--END_DOCUSAURUS_CODE_TABS-->
</Syntax>
### Non-empty Sets ### Non-empty Sets
<!--DOCUSAURUS_CODE_TABS-->
<!--PascaLIGO-->
<Syntax syntax="pascaligo">
In PascaLIGO, the notation for sets is similar to that for lists, In PascaLIGO, the notation for sets is similar to that for lists,
except the keyword `set` is used before: except the keyword `set` is used before:
@ -404,7 +393,8 @@ gitlab-pages/docs/language-basics/src/sets-lists-tuples/sets.ligo my_set
# Outputs: { 3 ; 2 ; 1 } # Outputs: { 3 ; 2 ; 1 }
``` ```
<!--CameLIGO--> </Syntax>
<Syntax syntax="cameligo">
In CameLIGO, there is no predefined syntactic construct for sets: you In CameLIGO, there is no predefined syntactic construct for sets: you
must build your set by adding to the empty set. (This is the way in must build your set by adding to the empty set. (This is the way in
@ -424,7 +414,8 @@ gitlab-pages/docs/language-basics/src/sets-lists-tuples/sets.mligo my_set
# Outputs: { 3 ; 2 ; 1 } # Outputs: { 3 ; 2 ; 1 }
``` ```
<!--ReasonLIGO--> </Syntax>
<Syntax syntax="reasonligo">
In ReasonLIGO, there is no predefined syntactic construct for sets: In ReasonLIGO, there is no predefined syntactic construct for sets:
you must build your set by adding to the empty set. (This is the way you must build your set by adding to the empty set. (This is the way
@ -444,13 +435,15 @@ ligo evaluate-value
gitlab-pages/docs/language-basics/src/sets-lists-tuples/sets.religo my_set gitlab-pages/docs/language-basics/src/sets-lists-tuples/sets.religo my_set
# Outputs: { 3 ; 2 ; 1 } # Outputs: { 3 ; 2 ; 1 }
``` ```
<!--END_DOCUSAURUS_CODE_TABS-->
</Syntax>
### Set Membership ### Set Membership
<!--DOCUSAURUS_CODE_TABS-->
<!--PascaLIGO-->
<Syntax syntax="pascaligo">
PascaLIGO features a special keyword `contains` that operates like an PascaLIGO features a special keyword `contains` that operates like an
infix operator checking membership in a set. infix operator checking membership in a set.
@ -459,7 +452,8 @@ infix operator checking membership in a set.
const contains_3 : bool = my_set contains 3 const contains_3 : bool = my_set contains 3
``` ```
<!--CameLIGO--> </Syntax>
<Syntax syntax="cameligo">
In CameLIGO, the predefined predicate `Set.mem` tests for membership In CameLIGO, the predefined predicate `Set.mem` tests for membership
in a set as follows: in a set as follows:
@ -468,7 +462,8 @@ in a set as follows:
let contains_3 : bool = Set.mem 3 my_set let contains_3 : bool = Set.mem 3 my_set
``` ```
<!--ReasonLIGO--> </Syntax>
<Syntax syntax="reasonligo">
In ReasonLIGO, the predefined predicate `Set.mem` tests for membership In ReasonLIGO, the predefined predicate `Set.mem` tests for membership
in a set as follows: in a set as follows:
@ -476,57 +471,63 @@ in a set as follows:
```reasonligo group=sets ```reasonligo group=sets
let contains_3 : bool = Set.mem (3, my_set); let contains_3 : bool = Set.mem (3, my_set);
``` ```
<!--END_DOCUSAURUS_CODE_TABS-->
</Syntax>
### Cardinal of Sets ### Cardinal of Sets
<!--DOCUSAURUS_CODE_TABS--> The predefined function `Set.size` returns the number of
elements in a given set as follows.
<!--PascaLIGO-->
In PascaLIGO, the predefined function `size` returns the number of
elements in a given set as follows: <Syntax syntax="pascaligo">
```pascaligo group=sets ```pascaligo group=sets
const set_size : nat = size (my_set) const cardinal : nat = Set.size (my_set)
``` ```
<!--CameLIGO-->
In CameLIGO, the predefined function `Set.size` returns the number of > Note that `size` is *deprecated*.
elements in a given set as follows:
</Syntax>
<Syntax syntax="cameligo">
```cameligo group=sets ```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 </Syntax>
of elements in a given set as follows: <Syntax syntax="reasonligo">
```reasonligo group=sets ```reasonligo group=sets
let set_size : nat = Set.size (my_set); let cardinal : nat = Set.size (my_set);
``` ```
<!--END_DOCUSAURUS_CODE_TABS--> </Syntax>
### Updating Sets ### Updating Sets
<!--DOCUSAURUS_CODE_TABS--> There are two ways to update a set, that is to add or remove from
it.
<!--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 <Syntax syntax="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: modify it in-place. First, let us consider the former way:
```pascaligo group=sets ```pascaligo group=sets
const larger_set : set (int) = set_add (4, my_set) const larger_set : set (int) = Set.add (4, my_set)
const smaller_set : set (int) = Set.remove (3, 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 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 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 possible to add elements by means of a patch, not remove any: it is
@ -546,28 +547,32 @@ function update (var s : set (int)) : set (int) is block {
const new_set : set (int) = update (my_set) const new_set : set (int) = update (my_set)
``` ```
<!--CameLIGO--> </Syntax>
<Syntax syntax="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. without some elements.
```cameligo group=sets ```cameligo group=sets
let larger_set : int set = Set.add 4 my_set let larger_set : int set = Set.add 4 my_set
let smaller_set : int set = Set.remove 3 my_set let smaller_set : int set = Set.remove 3 my_set
``` ```
<!--ReasonLIGO--> </Syntax>
<Syntax syntax="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. without some elements.
```reasonligo group=sets ```reasonligo group=sets
let larger_set : set (int) = Set.add (4, my_set); let larger_set : set (int) = Set.add (4, my_set);
let smaller_set : set (int) = Set.remove (3, my_set); let smaller_set : set (int) = Set.remove (3, my_set);
``` ```
<!--END_DOCUSAURUS_CODE_TABS-->
</Syntax>
### Functional Iteration over Sets ### Functional Iteration over Sets
@ -588,34 +593,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 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. of a map is within a certain range, and fail with an error otherwise.
<!--DOCUSAURUS_CODE_TABS--> 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-->
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 <Syntax syntax="pascaligo">
elements (integers) are greater than `3`:
```pascaligo group=sets ```pascaligo group=sets
function iter_op (const s : set (int)) : unit is function iter_op (const s : set (int)) : unit is
block { block {
function iterated (const i : int) : unit is function iterated (const i : int) : unit is
if i > 2 then Unit else (failwith ("Below range.") : unit) 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 > Note that `set_iter` is *deprecated*.
> variables.
<!--CameLIGO--> </Syntax>
<Syntax syntax="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 ```cameligo group=sets
let iter_op (s : int set) : unit = let iter_op (s : int set) : unit =
@ -623,13 +621,8 @@ let iter_op (s : int set) : unit =
in Set.iter predicate s in Set.iter predicate s
``` ```
<!--ReasonLIGO--> </Syntax>
<Syntax syntax="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 ```reasonligo group=sets
let iter_op = (s : set (int)) : unit => { let iter_op = (s : set (int)) : unit => {
@ -638,54 +631,55 @@ let iter_op = (s : set (int)) : unit => {
}; };
``` ```
<!--END_DOCUSAURUS_CODE_TABS--> </Syntax>
#### Mapped Operation (NOT IMPLEMENTED YET)
We may want to change all the elements of a given set by applying to <!-- #### Mapped Operation (NOT IMPLEMENTED YET) -->
them a function. This is called a *mapped operation*, not to be
confused with the map data structure.
<!--DOCUSAURUS_CODE_TABS--> <!-- 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. -->
<!--PascaLIGO--> <!-- <\!--DOCUSAURUS_CODE_TABS-\-> -->
In PascaLIGO, the predefined functional iterator implementing the <!-- <\!--PascaLIGO-\-> -->
mapped operation over sets is called `set_map` and is used as follows:
```pascaligo skip <!-- In PascaLIGO, the predefined functional iterator implementing the -->
function increment (const i : int): int is i + 1 <!-- mapped operation over sets is called `Set.map` and is used as follows: -->
// Creates a new set with all elements incremented by 1 <!-- ```pascaligo skip -->
const plus_one : set (int) = set_map (increment, larger_set) <!-- function increment (const i : int): int is i + 1 -->
```
<!--CameLIGO--> <!-- // Creates a new set with all elements incremented by 1 -->
<!-- const plus_one : set (int) = Set.map (increment, larger_set) -->
<!-- ``` -->
In CameLIGO, the predefined functional iterator implementing the <!-- <\!--CameLIGO-\-> -->
mapped operation over sets is called `Set.map` and is used as follows:
```cameligo skip <!-- In CameLIGO, the predefined functional iterator implementing the -->
let increment (i : int) : int = i + 1 <!-- mapped operation over sets is called `Set.map` and is used as follows: -->
// Creates a new set with all elements incremented by 1 <!-- ```cameligo skip -->
let plus_one : int set = Set.map increment larger_set <!-- let increment (i : int) : int = i + 1 -->
```
<!--ReasonLIGO--> <!-- // Creates a new set with all elements incremented by 1 -->
<!-- let plus_one : int set = Set.map increment larger_set -->
<!-- ``` -->
In ReasonLIGO, the predefined functional iterator implementing the <!-- <\!--ReasonLIGO-\-> -->
mapped operation over sets is called `Set.map` and is used as follows:
```reasonligo skip <!-- In ReasonLIGO, the predefined functional iterator implementing the -->
let increment = (i : int) : int => i + 1; <!-- mapped operation over sets is called `Set.map` and is used as follows: -->
// Creates a new set with all elements incremented by 1 <!-- ```reasonligo skip -->
let plus_one : set (int) = Set.map (increment, larger_set); <!-- let increment = (i : int) : int => i + 1; -->
```
<!--END_DOCUSAURUS_CODE_TABS--> <!-- // Creates a new set with all elements incremented by 1 -->
<!-- let plus_one : set (int) = Set.map (increment, larger_set); -->
<!-- ``` -->
<!-- <\!--END_DOCUSAURUS_CODE_TABS-\-> -->
#### Folded Operation #### Folded Operation
@ -693,24 +687,18 @@ A *folded operation* is the most general of iterations. The folded
function takes two arguments: an *accumulator* and the structure function takes two arguments: an *accumulator* and the structure
*element* at hand, with which it then produces a new accumulator. This *element* at hand, with which it then produces a new accumulator. This
enables having a partial result that becomes complete when the 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--> <Syntax syntax="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 ```pascaligo group=sets
function sum (const acc : int; const i : int): int is acc + i 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 > Note that `set_fold` is *deprecated*.
> variables.
It is possible to use a *loop* over a set as well. It is possible to use a *loop* over a set as well.
@ -723,23 +711,21 @@ function loop (const s : set (int)) : int is block {
} with sum } with sum
``` ```
<!--CameLIGO--> </Syntax>
<Syntax syntax="cameligo">
In CameLIGO, the predefined fold over sets is called `Set.fold`.
```cameligo group=sets ```cameligo group=sets
let sum (acc, i : int * int) : int = acc + i let sum (acc, i : int * int) : int = acc + i
let sum_of_elements : int = Set.fold sum my_set 0 let sum_of_elements : int = Set.fold sum my_set 0
``` ```
<!--ReasonLIGO--> </Syntax>
<Syntax syntax="reasonligo">
In ReasonLIGO, the predefined fold over sets is called `Set.fold`.
```reasonligo group=sets ```reasonligo group=sets
let sum = ((acc, i) : (int, int)) : int => acc + i; let sum = ((acc, i) : (int, int)) : int => acc + i;
let sum_of_elements : int = Set.fold (sum, my_set, 0); let sum_of_elements : int = Set.fold (sum, my_set, 0);
``` ```
<!--END_DOCUSAURUS_CODE_TABS-->
</Syntax>

View File

@ -1,4 +1,4 @@
type magnitude is Small | Large // See variant types type magnitude is Small | Large // See variant types
function compare (const n : nat) : magnitude is 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 (const a : int) : int is a + 1) (b)
function incr_map (const l : list (int)) : list (int) is 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 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 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 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 { function update (var s : set (int)) : set (int) is block {
patch s with set [4; 7] 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 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 { function loop (const s : set (int)) : int is block {
var sum : int := 0; var sum : int := 0;

View File

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

View File

@ -3,28 +3,40 @@ id: strings
title: Strings title: Strings
--- ---
import Syntax from '@theme/Syntax';
Strings are defined using the built-in `string` type like this: Strings are defined using the built-in `string` type like this:
<!--DOCUSAURUS_CODE_TABS-->
<!--PascaLIGO--> <Syntax syntax="pascaligo">
``` ```
const a : string = "Hello Alice" const a : string = "Hello Alice"
``` ```
<!--CameLIGO-->
</Syntax>
<Syntax syntax="cameligo">
``` ```
let a : string = "Hello Alice" let a : string = "Hello Alice"
``` ```
<!--ReasonLIGO-->
</Syntax>
<Syntax syntax="reasonligo">
```reasonligo ```reasonligo
let a : string = "Hello Alice"; let a : string = "Hello Alice";
``` ```
<!--END_DOCUSAURUS_CODE_TABS-->
</Syntax>
## Concatenating Strings ## Concatenating Strings
<!--DOCUSAURUS_CODE_TABS-->
<!--PascaLIGO--> <Syntax syntax="pascaligo">
Strings can be concatenated using the `^` operator. Strings can be concatenated using the `^` operator.
```pascaligo group=a ```pascaligo group=a
@ -32,7 +44,10 @@ const name : string = "Alice"
const greeting : string = "Hello" const greeting : string = "Hello"
const full_greeting : string = greeting ^ " " ^ name const full_greeting : string = greeting ^ " " ^ name
``` ```
<!--CameLIGO-->
</Syntax>
<Syntax syntax="cameligo">
Strings can be concatenated using the `^` operator. Strings can be concatenated using the `^` operator.
```cameligo group=a ```cameligo group=a
@ -40,7 +55,10 @@ let name : string = "Alice"
let greeting : string = "Hello" let greeting : string = "Hello"
let full_greeting : string = greeting ^ " " ^ name let full_greeting : string = greeting ^ " " ^ name
``` ```
<!--ReasonLIGO-->
</Syntax>
<Syntax syntax="reasonligo">
Strings can be concatenated using the `++` operator. Strings can be concatenated using the `++` operator.
```reasonligo group=a ```reasonligo group=a
@ -48,52 +66,76 @@ let name : string = "Alice";
let greeting : string = "Hello"; let greeting : string = "Hello";
let full_greeting : string = greeting ++ " " ++ name; let full_greeting : string = greeting ++ " " ++ name;
``` ```
<!--END_DOCUSAURUS_CODE_TABS-->
</Syntax>
## Slicing Strings ## Slicing Strings
Strings can be sliced using a built-in function: Strings can be sliced using a built-in function:
<!--DOCUSAURUS_CODE_TABS-->
<!--PascaLIGO--> <Syntax syntax="pascaligo">
```pascaligo group=b ```pascaligo group=b
const name : string = "Alice" const name : string = "Alice"
const slice : string = string_slice (0n, 1n, name) const slice : string = String.slice (0n, 1n, name)
``` ```
<!--CameLIGO-->
> Note that `string_slide` is *deprecated*.
</Syntax>
<Syntax syntax="cameligo">
```cameligo group=b ```cameligo group=b
let name : string = "Alice" let name : string = "Alice"
let slice : string = String.slice 0n 1n name let slice : string = String.slice 0n 1n name
``` ```
<!--ReasonLIGO-->
</Syntax>
<Syntax syntax="reasonligo">
```reasonligo group=b ```reasonligo group=b
let name : string = "Alice"; let name : string = "Alice";
let slice : string = String.slice (0n, 1n, name); let slice : string = String.slice (0n, 1n, name);
``` ```
<!--END_DOCUSAURUS_CODE_TABS-->
> ⚠️ Notice that the offset and length of the slice are natural numbers. </Syntax>
> ⚠️ Notice that the offset and length of the slice are natural
> numbers.
## Length of Strings ## Length of Strings
The length of a string can be found using a built-in function: The length of a string can be found using a built-in function:
<!--DOCUSAURUS_CODE_TABS-->
<!--PascaLIGO--> <Syntax syntax="pascaligo">
```pascaligo group=c ```pascaligo group=c
const name : string = "Alice" const name : string = "Alice"
const length : nat = size (name) // length = 5 const length : nat = String.length (name) // length = 5
``` ```
<!--CameLIGO-->
> Note that `size` is *deprecated*.
</Syntax>
<Syntax syntax="cameligo">
```cameligo group=c ```cameligo group=c
let name : string = "Alice" let name : string = "Alice"
let length : nat = String.size name // length = 5 let length : nat = String.size name // length = 5
``` ```
<!--ReasonLIGO--> </Syntax>
<Syntax syntax="reasonligo">
```reasonligo group=c ```reasonligo group=c
let name : string = "Alice"; let name : string = "Alice";
let length : nat = String.size (name); // length == 5 let length : nat = String.size (name); // length == 5
``` ```
<!--END_DOCUSAURUS_CODE_TABS-->
</Syntax>

View File

@ -3,6 +3,8 @@ id: tezos-specific
title: Tezos Domain-Specific Operations title: Tezos Domain-Specific Operations
--- ---
import Syntax from '@theme/Syntax';
LIGO is a programming language for writing Tezos smart contracts. It LIGO is a programming language for writing Tezos smart contracts. It
would be a little odd if it did not have any Tezos specific would be a little odd if it did not have any Tezos specific
functions. This page will tell you about them. functions. This page will tell you about them.
@ -20,23 +22,30 @@ functionality can be accessed from within LIGO.
> untrusted source or casting the result to the wrong type. Do not use > untrusted source or casting the result to the wrong type. Do not use
> the corresponding LIGO functions without doing your homework first. > the corresponding LIGO functions without doing your homework first.
<!--DOCUSAURUS_CODE_TABS-->
<!--PascaLIGO-->
<Syntax syntax="pascaligo">
```pascaligo group=a ```pascaligo group=a
function id_string (const p : string) : option (string) is block { function id_string (const p : string) : option (string) is block {
const packed : bytes = bytes_pack (p) const packed : bytes = bytes_pack (p)
} with (bytes_unpack (packed) : option (string)) } with (Bytes.unpack (packed) : option (string))
``` ```
<!--CameLIGO--> > Note that `bytes_unpack` is *deprecated*.
</Syntax>
<Syntax syntax="cameligo">
```cameligo group=a ```cameligo group=a
let id_string (p : string) : string option = let id_string (p : string) : string option =
let packed: bytes = Bytes.pack p in let packed: bytes = Bytes.pack p in
(Bytes.unpack packed : string option) (Bytes.unpack packed : string option)
``` ```
<!--ReasonLIGO--> </Syntax>
<Syntax syntax="reasonligo">
```reasonligo group=a ```reasonligo group=a
let id_string = (p : string) : option (string) => { let id_string = (p : string) : option (string) => {
let packed : bytes = Bytes.pack (p); let packed : bytes = Bytes.pack (p);
@ -44,7 +53,8 @@ let id_string = (p : string) : option (string) => {
}; };
``` ```
<!--END_DOCUSAURUS_CODE_TABS--> </Syntax>
## Hashing Keys ## Hashing Keys
@ -54,9 +64,10 @@ if this were not the case, hashes are much smaller than keys, and
storage on blockchains comes at a cost premium. You can hash keys with storage on blockchains comes at a cost premium. You can hash keys with
a predefined functions returning a value of type `key_hash`. a predefined functions returning a value of type `key_hash`.
<!--DOCUSAURUS_CODE_TABS-->
<!--PascaLIGO-->
<Syntax syntax="pascaligo">
```pascaligo group=b ```pascaligo group=b
function check_hash_key (const kh1 : key_hash; const k2 : key) : bool * key_hash is function check_hash_key (const kh1 : key_hash; const k2 : key) : bool * key_hash is
block { block {
@ -66,14 +77,18 @@ function check_hash_key (const kh1 : key_hash; const k2 : key) : bool * key_hash
} with (ret, kh2) } with (ret, kh2)
``` ```
<!--CameLIGO--> </Syntax>
<Syntax syntax="cameligo">
```cameligo group=b ```cameligo group=b
let check_hash_key (kh1, k2 : key_hash * key) : bool * key_hash = let check_hash_key (kh1, k2 : key_hash * key) : bool * key_hash =
let kh2 : key_hash = Crypto.hash_key k2 in let kh2 : key_hash = Crypto.hash_key k2 in
if kh1 = kh2 then true, kh2 else false, kh2 if kh1 = kh2 then true, kh2 else false, kh2
``` ```
<!--ReasonLIGO--> </Syntax>
<Syntax syntax="reasonligo">
```reasonligo group=b ```reasonligo group=b
let check_hash_key = ((kh1, k2) : (key_hash, key)) : (bool, key_hash) => { let check_hash_key = ((kh1, k2) : (key_hash, key)) : (bool, key_hash) => {
let kh2 : key_hash = Crypto.hash_key (k2); let kh2 : key_hash = Crypto.hash_key (k2);
@ -81,7 +96,8 @@ let check_hash_key = ((kh1, k2) : (key_hash, key)) : (bool, key_hash) => {
}; };
``` ```
<!--END_DOCUSAURUS_CODE_TABS--> </Syntax>
## Checking Signatures ## Checking Signatures
@ -95,56 +111,114 @@ asynchronously. You can do this in LIGO using the `key` and
> because that would require storing a private key on chain, at which > because that would require storing a private key on chain, at which
> point it is not... private anymore. > point it is not... private anymore.
<!--DOCUSAURUS_CODE_TABS-->
<!--PascaLIGO-->
<Syntax syntax="pascaligo">
```pascaligo group=c ```pascaligo group=c
function check_signature function check_signature
(const pk : key; (const pk : key;
const signed : signature; const signed : signature;
const msg : bytes) : bool const msg : bytes) : bool
is crypto_check (pk, signed, msg) is Crypto.check (pk, signed, msg)
``` ```
<!--CameLIGO--> > Note that `crypto_check` is *deprecated*.
</Syntax>
<Syntax syntax="cameligo">
```cameligo group=c ```cameligo group=c
let check_signature (pk, signed, msg : key * signature * bytes) : bool = let check_signature (pk, signed, msg : key * signature * bytes) : bool =
Crypto.check pk signed msg Crypto.check pk signed msg
``` ```
<!--ReasonLIGO--> </Syntax>
<Syntax syntax="reasonligo">
```reasonligo group=c ```reasonligo group=c
let check_signature = let check_signature =
((pk, signed, msg) : (key, signature, bytes)) : bool => ((pk, signed, msg) : (key, signature, bytes)) : bool =>
Crypto.check (pk, signed, msg); Crypto.check (pk, signed, msg);
``` ```
<!--END_DOCUSAURUS_CODE_TABS--> </Syntax>
## Contract's Own Address ## Contract's Own Address
Often you want to get the address of the contract being executed. You 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 > Note that `self_address` is *deprecated*.
> only allowed at the top-level. Using it in an embedded function will
> cause an error.
<!--DOCUSAURUS_CODE_TABS--> > ⚠️ 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.
<Syntax syntax="pascaligo">
<!--PascaLIGO-->
```pascaligo group=d ```pascaligo group=d
const current_addr : address = self_address const current_addr : address = Tezos.self_address
``` ```
<!--CameLIGO--> </Syntax>
<Syntax syntax="cameligo">
```cameligo group=d ```cameligo group=d
let current_addr : address = Current.self_address let current_addr : address = Tezos.self_address
``` ```
<!--ReasonLIGO--> </Syntax>
<Syntax syntax="reasonligo">
```reasonligo group=d ```reasonligo group=d
let current_addr : address = Current.self_address; let current_addr : address = Tezos.self_address;
``` ```
<!--END_DOCUSAURUS_CODE_TABS--> </Syntax>
## Origination of a contract
`Tezos.create_contract` allows you to originate a contract given its code, delegate (if any), initial balance and initial storage.
The return value is a pair of type `(operation * address)`.
> ⚠️ Due to limitations in Michelson, `Tezos.create_contract` first argument
> must be inlined and must not contain references to free variables
<Syntax syntax="pascaligo">
```pascaligo group=e
const origination : operation * address = Tezos.create_contract (
function (const p : nat; const s : string): list(operation) * string is ((nil : list(operation)), s),
(None : option(key_hash)),
3tz,
"initial_storage")
```
</Syntax>
<Syntax syntax="cameligo">
```cameligo group=e
let origination : operation * address = Tezos.create_contract
(fun (p, s : nat * string) -> (([] : operation list), s))
(None: key_hash option)
3tz
"initial_storage"
```
</Syntax>
<Syntax syntax="reasonligo">
```reasonligo group=e
let origination : (operation, address) = Tezos.create_contract (
((p, s) : (nat,string)) : (list(operation),string) => (([] : list(operation)), s),
None: option(key_hash),
3tz,
"initial_storage")
```
</Syntax>

View File

@ -3,6 +3,8 @@ id: types
title: Types title: Types
--- ---
import Syntax from '@theme/Syntax';
*LIGO is strongly and statically typed.* This means that the compiler *LIGO is strongly and statically typed.* This means that the compiler
checks how your contract processes data. If it passes the test, your checks how your contract processes data. If it passes the test, your
contract will not fail at run-time due to inconsistent assumptions on contract will not fail at run-time due to inconsistent assumptions on
@ -22,36 +24,41 @@ maintainability of your smart contracts. For example we can choose to
alias a string type as an animal breed - this will allow us to alias a string type as an animal breed - this will allow us to
comunicate our intent with added clarity. comunicate our intent with added clarity.
<!--DOCUSAURUS_CODE_TABS-->
<!--PascaLIGO--> <Syntax syntax="pascaligo">
```pascaligo group=a ```pascaligo group=a
type breed is string type breed is string
const dog_breed : breed = "Saluki" const dog_breed : breed = "Saluki"
``` ```
<!--CameLIGO--> </Syntax>
<Syntax syntax="cameligo">
```cameligo group=a ```cameligo group=a
type breed = string type breed = string
let dog_breed : breed = "Saluki" let dog_breed : breed = "Saluki"
``` ```
<!--ReasonLIGO--> </Syntax>
<Syntax syntax="reasonligo">
```reasonligo group=a ```reasonligo group=a
type breed = string; type breed = string;
let dog_breed : breed = "Saluki"; let dog_breed : breed = "Saluki";
``` ```
<!--END_DOCUSAURUS_CODE_TABS--> </Syntax>
> The above type definitions are aliases, which means that `breed` and > The above type definitions are aliases, which means that `breed` and
> `string` are interchangable in all contexts. > `string` are interchangable in all contexts.
## Simple types ## Simple types
<!--DOCUSAURUS_CODE_TABS-->
<!--PascaLIGO--> <Syntax syntax="pascaligo">
```pascaligo group=b ```pascaligo group=b
// The type account_balances denotes maps from addresses to tez // The type account_balances denotes maps from addresses to tez
@ -61,7 +68,9 @@ const ledger : account_balances =
map [("tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx" : address) -> 10mutez] map [("tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx" : address) -> 10mutez]
``` ```
<!--CameLIGO--> </Syntax>
<Syntax syntax="cameligo">
```cameligo group=b ```cameligo group=b
// The type account_balances denotes maps from addresses to tez // The type account_balances denotes maps from addresses to tez
@ -72,7 +81,9 @@ let ledger : account_balances =
[(("tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx" : address), 10mutez)] [(("tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx" : address), 10mutez)]
``` ```
<!--ReasonLIGO--> </Syntax>
<Syntax syntax="reasonligo">
```reasonligo group=b ```reasonligo group=b
// The type account_balances denotes maps from addresses to tez // The type account_balances denotes maps from addresses to tez
@ -83,7 +94,8 @@ let ledger: account_balances =
([("tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx" : address, 10mutez)]); ([("tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx" : address, 10mutez)]);
``` ```
<!--END_DOCUSAURUS_CODE_TABS--> </Syntax>
## Structured types ## Structured types
@ -96,8 +108,9 @@ types as *fields* and index them with a *field name*. In the example
below you can see the definition of data types for a ledger that keeps below you can see the definition of data types for a ledger that keeps
the balance and number of previous transactions for a given account. the balance and number of previous transactions for a given account.
<!--DOCUSAURUS_CODE_TABS-->
<!--PascaLIGO--> <Syntax syntax="pascaligo">
```pascaligo group=c ```pascaligo group=c
// Type aliasing // Type aliasing
@ -124,7 +137,9 @@ const my_ledger : ledger = map [
] ]
``` ```
<!--CameLIGO--> </Syntax>
<Syntax syntax="cameligo">
```cameligo group=c ```cameligo group=c
// Type aliasing // Type aliasing
@ -147,7 +162,9 @@ let my_ledger : ledger = Map.literal
{balance = 10mutez; transactions = 5n})] {balance = 10mutez; transactions = 5n})]
``` ```
<!--ReasonLIGO--> </Syntax>
<Syntax syntax="reasonligo">
```reasonligo group=c ```reasonligo group=c
// Type aliasing // Type aliasing
@ -177,7 +194,8 @@ are dual because records are a product of types (types are bundled
into a record), whereas variant types are a sum of types (they are into a record), whereas variant types are a sum of types (they are
exclusive to each other). exclusive to each other).
<!--END_DOCUSAURUS_CODE_TABS--> </Syntax>
## Annotations ## Annotations
@ -185,9 +203,10 @@ In certain cases, the type of an expression cannot be properly
inferred by the compiler. In order to help the type checker, you can inferred by the compiler. In order to help the type checker, you can
annotate an expression with its desired type. Here is an example: annotate an expression with its desired type. Here is an example:
<!--DOCUSAURUS_CODE_TABS-->
<!--PascaLIGO-->
<Syntax syntax="pascaligo">
```pascaligo group=d ```pascaligo group=d
type parameter is Back | Claim | Withdraw type parameter is Back | Claim | Withdraw
@ -213,7 +232,9 @@ function back (var action : unit; var store : storage) : return is
end with ((nil : list (operation)), store) // Annotation end with ((nil : list (operation)), store) // Annotation
``` ```
<!--CameLIGO--> </Syntax>
<Syntax syntax="cameligo">
```cameligo group=d ```cameligo group=d
type parameter = Back | Claim | Withdraw type parameter = Back | Claim | Withdraw
@ -229,7 +250,7 @@ type return = operation list * storage
let back (param, store : unit * storage) : return = let back (param, store : unit * storage) : return =
let no_op : operation list = [] in let no_op : operation list = [] in
if Current.time > store.deadline then if Tezos.now > store.deadline then
(failwith "Deadline passed." : return) // Annotation (failwith "Deadline passed." : return) // Annotation
else else
match Map.find_opt sender store.backers with match Map.find_opt sender store.backers with
@ -239,7 +260,9 @@ let back (param, store : unit * storage) : return =
| Some (x) -> no_op, store | Some (x) -> no_op, store
``` ```
<!--ReasonLIGO--> </Syntax>
<Syntax syntax="reasonligo">
```reasonligo group=d ```reasonligo group=d
type parameter = | Back | Claim | Withdraw; type parameter = | Back | Claim | Withdraw;
@ -255,7 +278,7 @@ type return = (list (operation), storage);
let back = ((param, store) : (unit, storage)) : return => { let back = ((param, store) : (unit, storage)) : return => {
let no_op : list (operation) = []; let no_op : list (operation) = [];
if (Current.time > store.deadline) { if (Tezos.now > store.deadline) {
(failwith ("Deadline passed.") : return); // Annotation (failwith ("Deadline passed.") : return); // Annotation
} }
else { else {
@ -269,4 +292,5 @@ let back = ((param, store) : (unit, storage)) : return => {
}; };
``` ```
<!--END_DOCUSAURUS_CODE_TABS--> </Syntax>

View File

@ -3,6 +3,9 @@ id: unit-option-pattern-matching
title: Unit, Option, Pattern matching title: Unit, Option, Pattern matching
--- ---
import Syntax from '@theme/Syntax';
Optionals are a pervasive programing pattern in OCaml. Since Michelson Optionals are a pervasive programing pattern in OCaml. Since Michelson
and LIGO are both inspired by OCaml, *optional types* are available in and LIGO are both inspired by OCaml, *optional types* are available in
LIGO as well. Similarly, OCaml features a *unit* type, and LIGO LIGO as well. Similarly, OCaml features a *unit* type, and LIGO
@ -16,15 +19,16 @@ The `unit` type in Michelson or LIGO is a predefined type that
contains only one value that carries no information. It is used when contains only one value that carries no information. It is used when
no relevant information is required or produced. Here is how it used. no relevant information is required or produced. Here is how it used.
<!--DOCUSAURUS_CODE_TABS-->
<!--PascaLIGO--> <Syntax syntax="pascaligo">
In PascaLIGO, the unique value of the `unit` type is `Unit`. In PascaLIGO, the unique value of the `unit` type is `Unit`.
```pascaligo group=a ```pascaligo group=a
const n : unit = Unit // Note the capital letter const n : unit = Unit // Note the capital letter
``` ```
<!--CameLIGO--> </Syntax>
<Syntax syntax="cameligo">
In CameLIGO, the unique value of the `unit` type is `()`, following In CameLIGO, the unique value of the `unit` type is `()`, following
the OCaml convention. the OCaml convention.
@ -32,7 +36,8 @@ the OCaml convention.
let n : unit = () let n : unit = ()
``` ```
<!--ReasonLIGO--> </Syntax>
<Syntax syntax="reasonligo">
In ReasonLIGO, the unique value of the `unit` type is `()`, following In ReasonLIGO, the unique value of the `unit` type is `()`, following
the OCaml convention. the OCaml convention.
@ -40,7 +45,8 @@ the OCaml convention.
let n : unit = (); let n : unit = ();
``` ```
<!--END_DOCUSAURUS_CODE_TABS--> </Syntax>
## Variant types ## Variant types
@ -52,39 +58,49 @@ the enumerated types found in Java, C++, JavaScript etc.
Here is how we define a coin as being either head or tail (and nothing Here is how we define a coin as being either head or tail (and nothing
else): else):
<!--DOCUSAURUS_CODE_TABS-->
<!--PascaLIGO--> <Syntax syntax="pascaligo">
```pascaligo group=b ```pascaligo group=b
type coin is Head | Tail type coin is Head | Tail
const head : coin = Head (Unit) // Unit needed for now. const head : coin = Head
const tail : coin = Tail (Unit) // Unit needed for now. const tail : coin = Tail
``` ```
<!--CameLIGO--> </Syntax>
<Syntax syntax="cameligo">
```cameligo group=b ```cameligo group=b
type coin = Head | Tail type coin = Head | Tail
let head : coin = Head let head : coin = Head
let tail : coin = Tail let tail : coin = Tail
``` ```
<!--ReasonLIGO--> </Syntax>
<Syntax syntax="reasonligo">
```reasonligo group=b ```reasonligo group=b
type coin = | Head | Tail; type coin = Head | Tail;
let head : coin = Head; let head : coin = Head;
let tail : coin = Tail; let tail : coin = Tail;
``` ```
<!--END_DOCUSAURUS_CODE_TABS-->
</Syntax>
The names `Head` and `Tail` in the definition of the type `coin` are 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, In general, it is interesting for variants to carry some information,
and thus go beyond enumerated types. In the following, we show how to and thus go beyond enumerated types. In the following, we show how to
define different kinds of users of a system. define different kinds of users of a system.
<!--DOCUSAURUS_CODE_TABS-->
<!--PascaLIGO-->
<Syntax syntax="pascaligo">
```pascaligo group=c ```pascaligo group=c
type id is nat type id is nat
@ -94,10 +110,12 @@ type user is
| Guest | Guest
const u : user = Admin (1000n) const u : user = Admin (1000n)
const g : user = Guest (Unit) // Unit needed because of a bug const g : user = Guest
``` ```
<!--CameLIGO--> </Syntax>
<Syntax syntax="cameligo">
```cameligo group=c ```cameligo group=c
type id = nat type id = nat
@ -110,7 +128,9 @@ let u : user = Admin 1000n
let g : user = Guest let g : user = Guest
``` ```
<!--ReasonLIGO--> </Syntax>
<Syntax syntax="reasonligo">
```reasonligo group=c ```reasonligo group=c
type id = nat; type id = nat;
@ -123,9 +143,13 @@ let u : user = Admin (1000n);
let g : user = Guest; let g : user = Guest;
``` ```
<!--END_DOCUSAURUS_CODE_TABS--> </Syntax>
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 ## Optional values
The `option` type is a predefined variant type that is used to express The `option` type is a predefined variant type that is used to express
@ -136,26 +160,32 @@ type would be `None`, otherwise `Some (v)`, where `v` is some
meaningful value *of any type*. An example in arithmetic is the meaningful value *of any type*. An example in arithmetic is the
division operation: division operation:
<!--DOCUSAURUS_CODE_TABS-->
<!--PascaLIGO--> <Syntax syntax="pascaligo">
```pascaligo group=d ```pascaligo group=d
function div (const a : nat; const b : nat) : option (nat) is function div (const a : nat; const b : nat) : option (nat) is
if b = 0n then (None: option (nat)) else Some (a/b) if b = 0n then (None: option (nat)) else Some (a/b)
``` ```
<!--CameLIGO--> </Syntax>
<Syntax syntax="cameligo">
```cameligo group=d ```cameligo group=d
let div (a, b : nat * nat) : nat option = let div (a, b : nat * nat) : nat option =
if b = 0n then (None: nat option) else Some (a/b) if b = 0n then (None: nat option) else Some (a/b)
``` ```
<!--ReasonLIGO--> </Syntax>
<Syntax syntax="reasonligo">
```reasonligo group=d ```reasonligo group=d
let div = ((a, b) : (nat, nat)) : option (nat) => let div = ((a, b) : (nat, nat)) : option (nat) =>
if (b == 0n) { (None: option (nat)); } else { Some (a/b); }; if (b == 0n) { (None: option (nat)); } else { Some (a/b); };
``` ```
<!--END_DOCUSAURUS_CODE_TABS--> </Syntax>
## Pattern matching ## Pattern matching
@ -165,15 +195,16 @@ Javascript, and can be used to route the program's control flow based
on the value of a variant. Consider for example the definition of a on the value of a variant. Consider for example the definition of a
function `flip` that flips a coin. function `flip` that flips a coin.
<!--DOCUSAURUS_CODE_TABS-->
<!--PascaLIGO--> <Syntax syntax="pascaligo">
```pascaligo group=e ```pascaligo group=e
type coin is Head | Tail type coin is Head | Tail
function flip (const c : coin) : coin is function flip (const c : coin) : coin is
case c of case c of
Head -> Tail (Unit) // Unit needed because of a bug Head -> Tail
| Tail -> Head (Unit) // Unit needed because of a bug | Tail -> Head
end end
``` ```
@ -181,11 +212,13 @@ You can call the function `flip` by using the LIGO compiler like so:
```shell ```shell
ligo run-function ligo run-function
gitlab-pages/docs/language-basics/src/unit-option-pattern-matching/flip.ligo gitlab-pages/docs/language-basics/src/unit-option-pattern-matching/flip.ligo
flip "(Head (Unit))" flip "Head"
# Outputs: Tail(Unit) # Outputs: Tail(Unit)
``` ```
<!--CameLIGO--> </Syntax>
<Syntax syntax="cameligo">
```cameligo group=e ```cameligo group=e
type coin = Head | Tail type coin = Head | Tail
@ -203,7 +236,9 @@ flip Head
# Outputs: Tail(Unit) # Outputs: Tail(Unit)
``` ```
<!--ReasonLIGO--> </Syntax>
<Syntax syntax="reasonligo">
```reasonligo group=e ```reasonligo group=e
type coin = | Head | Tail; type coin = | Head | Tail;
@ -222,4 +257,5 @@ flip Head
# Outputs: Tail(Unit) # Outputs: Tail(Unit)
``` ```
<!--END_DOCUSAURUS_CODE_TABS--> </Syntax>

View File

@ -3,6 +3,9 @@ id: constants-and-variables
title: Constants & Variables title: Constants & Variables
--- ---
import Syntax from '@theme/Syntax';
The next building block after types are *constants* and *variables*. The next building block after types are *constants* and *variables*.
## Constants ## Constants
@ -12,8 +15,9 @@ reassigned. Put in another way, they can be assigned once, at their
declaration. When defining a constant you need to provide a `name`, declaration. When defining a constant you need to provide a `name`,
`type` and a `value`: `type` and a `value`:
<!--DOCUSAURUS_CODE_TABS-->
<!--PascaLIGO--> <Syntax syntax="pascaligo">
```pascaligo group=a ```pascaligo group=a
const age : int = 25 const age : int = 25
``` ```
@ -24,7 +28,10 @@ command:
ligo evaluate-value gitlab-pages/docs/language-basics/src/variables-and-constants/const.ligo age ligo evaluate-value gitlab-pages/docs/language-basics/src/variables-and-constants/const.ligo age
# Outputs: 25 # Outputs: 25
``` ```
<!--CameLIGO-->
</Syntax>
<Syntax syntax="cameligo">
```cameligo group=a ```cameligo group=a
let age : int = 25 let age : int = 25
``` ```
@ -36,7 +43,9 @@ ligo evaluate-value gitlab-pages/docs/language-basics/src/variables-and-constant
# Outputs: 25 # Outputs: 25
``` ```
<!--ReasonLIGO--> </Syntax>
<Syntax syntax="reasonligo">
```reasonligo group=a ```reasonligo group=a
let age : int = 25; let age : int = 25;
``` ```
@ -48,19 +57,23 @@ ligo evaluate-value gitlab-pages/docs/language-basics/src/variables-and-constant
# Outputs: 25 # Outputs: 25
``` ```
<!--END_DOCUSAURUS_CODE_TABS--> </Syntax>
## Variables ## Variables
<!--DOCUSAURUS_CODE_TABS-->
<!--PascaLIGO--> <Syntax syntax="pascaligo">
Variables, unlike constants, are *mutable*. They cannot be declared in Variables, unlike constants, are *mutable*. They cannot be declared in
a *global scope*, but they can be declared and used within functions, a *global scope*, but they can be declared and used within functions,
or as function parameters. or as function parameters.
> ⚠️ Please be wary that mutation only works within the function scope > ⚠️ 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 ```pascaligo group=b
@ -85,7 +98,8 @@ ligo run-function gitlab-pages/docs/language-basics/src/variables-and-constants/
# Outputs: 2 # Outputs: 2
``` ```
<!--CameLIGO--> </Syntax>
<Syntax syntax="cameligo">
As expected in the pure subset of a functional language, CameLIGO only As expected in the pure subset of a functional language, CameLIGO only
features *constant values*: once they are declared, the value cannot features *constant values*: once they are declared, the value cannot
@ -102,7 +116,9 @@ like this:
ligo run-function gitlab-pages/docs/language-basics/src/variables-and-constants/add.mligo add '(1,1)' ligo run-function gitlab-pages/docs/language-basics/src/variables-and-constants/add.mligo add '(1,1)'
# Outputs: 2 # Outputs: 2
``` ```
<!--ReasonLIGO-->
</Syntax>
<Syntax syntax="reasonligo">
As expected in the pure subset of a functional language, ReasonLIGO As expected in the pure subset of a functional language, ReasonLIGO
only features *constant values*: once they are declared, the value only features *constant values*: once they are declared, the value
@ -122,4 +138,5 @@ ligo run-function gitlab-pages/docs/language-basics/src/variables-and-constants/
# Outputs: 2 # Outputs: 2
``` ```
<!--END_DOCUSAURUS_CODE_TABS--> </Syntax>

View File

@ -1,268 +1,207 @@
--- ---
id: big-map-reference id: big-map-reference
title: Big Map — Scalable hashmap primitive title: Big Maps — Scalable Maps
--- ---
## Defining A Big Map Type import Syntax from '@theme/Syntax';
<!--DOCUSAURUS_CODE_TABS--> Ordinary maps are fine for contracts with a finite lifespan or a
<!--Pascaligo--> bounded number of users. For many contracts however, the intention is
```pascaligo to have a map holding *many* entries, potentially millions of
type move is (int * int) them. The cost of loading those entries into the environment each time
type moveset is big_map (address, move) a user executes the contract would eventually become too expensive
type foo is big_map (int, int) 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
<Syntax syntax="pascaligo">
```pascaligo group=big_maps
type move is int * int
type register is big_map (address, move)
``` ```
<!--CameLIGO--> </Syntax>
```cameligo <Syntax syntax="cameligo">
```cameligo group=big_maps
type move = int * int type move = int * int
type moveset = (address, move) big_map type register = (address, move) big_map
type foo = (int, int) big_map
``` ```
<!--ReasonLIGO--> </Syntax>
```reasonligo <Syntax syntax="reasonligo">
```reasonligo group=big_maps
type move = (int, int); type move = (int, int);
type moveset = big_map(address, move); type register = big_map (address, move);
type foo = big_map(int, int);
``` ```
<!--END_DOCUSAURUS_CODE_TABS--> </Syntax>
## Creating A Map
<!--DOCUSAURUS_CODE_TABS-->
<!--Pascaligo-->
```pascaligo # Creating an Empty Big Map
const moves: moveset =
big_map
("tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx": address) -> (1,2);
("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN": address) -> (0,3); <Syntax syntax="pascaligo">
end
```pascaligo group=big_maps
const empty : register = big_map []
``` ```
<!--CameLIGO--> </Syntax>
<Syntax syntax="cameligo">
```cameligo ```cameligo group=big_maps
let moves: moveset = let empty : register = Big_map.empty
```
</Syntax>
<Syntax syntax="reasonligo">
```reasonligo group=big_maps
let empty : register = Big_map.empty
```
</Syntax>
# Creating a Non-empty Map
<Syntax syntax="pascaligo">
```pascaligo group=big_maps
const moves : register =
big_map [
("tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx" : address) -> (1,2);
("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN" : address) -> (0,3)]
```
</Syntax>
<Syntax syntax="cameligo">
```cameligo group=big_maps
let moves : register =
Big_map.literal [ Big_map.literal [
(("tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx": address), (1,2)); (("tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx" : address), (1,2));
(("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN": address), (0,3)); (("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN" : address), (0,3))]
]
``` ```
<!--ReasonLIGO--> </Syntax>
<Syntax syntax="reasonligo">
```reasonligo ```reasonligo group=big_maps
let moves: moveset = let moves : register =
Big_map.literal ([ Big_map.literal ([
("tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx": address, (1,2)), ("tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx" : address, (1,2)),
("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN": address, (0,3)), ("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN" : address, (0,3))]);
]);
``` ```
<!--END_DOCUSAURUS_CODE_TABS--> </Syntax>
## 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 # Accessing Values
which can either shift logic in response to a missing value or throw an error.
<!--DOCUSAURUS_CODE_TABS-->
<!--Pascaligo--> <Syntax syntax="pascaligo">
```pascaligo
const my_balance : option(move) = ```pascaligo group=big_maps
moves [("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN": address)] const my_balance : option (move) =
moves [("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN" : address)]
``` ```
<!--CameLIGO--> </Syntax>
<Syntax syntax="cameligo">
```cameligo ```cameligo group=big_maps
let my_balance : move option = let my_balance : move option =
Big_map.find_opt ("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN": address) moves Big_map.find_opt ("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN" : address) moves
``` ```
<!--ReasonLIGO--> </Syntax>
<Syntax syntax="reasonligo">
```reasonligo ```reasonligo group=big_maps
let my_balance : option(move) = let my_balance : option (move) =
Big_map.find_opt("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN": address, moves); 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.
<!--DOCUSAURUS_CODE_TABS-->
<!--Pascaligo-->
```pascaligo
const my_balance : move =
get_force (("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN": address), moves);
``` ```
<!--CameLIGO--> </Syntax>
```cameligo
let my_balance : move =
Big_map.find ("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN": address) moves
```
<!--ReasonLIGO-->
```reasonligo # Updating Big Maps
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 <Syntax syntax="pascaligo">
Change the value associated with a particular key, if that value doesn't already ```pascaligo group=big_maps
exist add it. function add (var m : register) : register is
<!--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
block { block {
m [("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN": address)] := (4,9); m [("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN": address)] := (4,9)
} with m } with m
const updated_map : register = add (moves)
``` ```
<!--Cameligo--> </Syntax>
<Syntax syntax="cameligo">
```cameligo ```cameligo group=big_maps
let updated_map : moveset = let updated_map : register =
Big_map.update ("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN": address) (Some (4,9)) moves Big_map.update
("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN" : address) (Some (4,9)) moves
``` ```
<!--Reasonligo--> </Syntax>
<Syntax syntax="reasonligo">
```reasonligo ```reasonligo group=big_maps
let updated_map : moveset = let updated_map : register =
Big_map.update(("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN": address), Some((4,9)), moves); Big_map.update
(("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN": address), Some ((4,9)), moves);
``` ```
<!--END_DOCUSAURUS_CODE_TABS--> </Syntax>
## 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 <Syntax syntax="pascaligo">
function set_ (var n : int ; var m : foo) : foo is block {
m[23] := n ; ```pascaligo group=big_maps
} with m function rem (var m : register) : register is
block {
remove ("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN": address) from map moves
} with m
const updated_map : register = rem (moves)
``` ```
<!--CameLIGO--> </Syntax>
```cameligo <Syntax syntax="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--> </Syntax>
```reasonligo <Syntax syntax="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--> </Syntax>
## 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

@ -3,62 +3,67 @@ id: bytes-reference
title: Bytes — Manipulate bytes data title: Bytes — Manipulate bytes data
--- ---
import Syntax from '@theme/Syntax';
## Bytes.concat(b1: bytes, b2: bytes) : bytes ## Bytes.concat(b1: bytes, b2: bytes) : bytes
Concatenate together two `bytes` arguments and return the result. Concatenate together two `bytes` arguments and return the result.
<!--DOCUSAURUS_CODE_TABS--> <Syntax syntax="pascaligo">
<!--PascaLIGO-->
```pascaligo ```pascaligo
function concat_op (const s : bytes) : bytes is function concat_op (const s : bytes) : bytes is
begin skip end with bytes_concat(s , 0x7070) begin skip end with bytes_concat(s , 0x7070)
``` ```
<!--CameLIGO--> </Syntax>
<Syntax syntax="cameligo">
```cameligo ```cameligo
let concat_op (s : bytes) : bytes = let concat_op (s : bytes) : bytes =
Bytes.concat s 0x7070 Bytes.concat s 0x7070
``` ```
<!--ReasonLIGO--> </Syntax>
<Syntax syntax="reasonligo">
```reasonligo ```reasonligo
let concat_op = (s: bytes): bytes => Bytes.concat(s, 0x7070); let concat_op = (s: bytes): bytes => Bytes.concat(s, 0x7070);
``` ```
<!--END_DOCUSAURUS_CODE_TABS--> </Syntax>
## Bytes.slice(pos1: nat, pos2: nat, data: bytes) : bytes ## Bytes.slice(pos1: nat, pos2: nat, data: bytes) : bytes
Extract the bytes between `pos1` and `pos2`. **Positions are zero indexed and Extract the bytes between `pos1` and `pos2`. **Positions are zero indexed and
inclusive**. For example if you gave the input "ff7a7aff" to the following: inclusive**. For example if you gave the input "ff7a7aff" to the following:
<!--DOCUSAURUS_CODE_TABS-->
<!--PascaLIGO-->
<Syntax syntax="pascaligo">
```pascaligo ```pascaligo
function slice_op (const s : bytes) : bytes is function slice_op (const s : bytes) : bytes is
begin skip end with bytes_slice(1n , 2n , s) begin skip end with bytes_slice(1n , 2n , s)
``` ```
<!--CameLIGO--> </Syntax>
<Syntax syntax="cameligo">
```cameligo ```cameligo
let slice_op (s : bytes) : bytes = let slice_op (s : bytes) : bytes =
Bytes.slice 1n 2n s Bytes.slice 1n 2n s
``` ```
<!--ReasonLIGO--> </Syntax>
<Syntax syntax="reasonligo">
``` ```
let slice_op = (s: bytes): bytes => Bytes.slice(1n, 2n, s); let slice_op = (s: bytes): bytes => Bytes.slice(1n, 2n, s);
``` ```
<!--END_DOCUSAURUS_CODE_TABS--> </Syntax>
It would return "7a7a" rather than "ff7a" or "ff" or "7a". It would return "7a7a" rather than "ff7a" or "ff" or "7a".
@ -68,23 +73,28 @@ Converts Michelson data structures to a binary format for serialization.
> ⚠️ `PACK` and `UNPACK` are features of Michelson that are intended to be used by people that really know what they're doing. There are several failure cases (such as `UNPACK`ing a lambda from an untrusted source), most of which are beyond the scope of this document. Don't use these functions without doing your homework first. > ⚠️ `PACK` and `UNPACK` are features of Michelson that are intended to be used by people that really know what they're doing. There are several failure cases (such as `UNPACK`ing a lambda from an untrusted source), most of which are beyond the scope of this document. Don't use these functions without doing your homework first.
<!--DOCUSAURUS_CODE_TABS-->
<!--PascaLIGO-->
<Syntax syntax="pascaligo">
```pascaligo ```pascaligo
function id_string (const p : string) : option(string) is block { function id_string (const p : string) : option(string) is block {
const packed : bytes = bytes_pack(p) ; const packed : bytes = bytes_pack(p) ;
} with (bytes_unpack(packed): option(string)) } with (bytes_unpack(packed): option(string))
``` ```
<!--CameLIGO--> </Syntax>
<Syntax syntax="cameligo">
```cameligo ```cameligo
let id_string (p: string) : string option = let id_string (p: string) : string option =
let packed: bytes = Bytes.pack p in let packed: bytes = Bytes.pack p in
((Bytes.unpack packed): string option) ((Bytes.unpack packed): string option)
``` ```
<!--ReasonLIGO--> </Syntax>
<Syntax syntax="reasonligo">
```reasonligo ```reasonligo
let id_string = (p: string) : option(string) => { let id_string = (p: string) : option(string) => {
let packed : bytes = Bytes.pack(p); let packed : bytes = Bytes.pack(p);
@ -92,7 +102,8 @@ let id_string = (p: string) : option(string) => {
}; };
``` ```
<!--END_DOCUSAURUS_CODE_TABS--> </Syntax>
## Bytes.unpack(packed: bytes) : a' ## Bytes.unpack(packed: bytes) : a'
@ -101,23 +112,28 @@ serialization format to the `option` type annotated on the call.
> ⚠️ `PACK` and `UNPACK` are features of Michelson that are intended to be used by people that really know what they're doing. There are several failure cases (such as `UNPACK`ing a lambda from an untrusted source), most of which are beyond the scope of this document. Don't use these functions without doing your homework first. > ⚠️ `PACK` and `UNPACK` are features of Michelson that are intended to be used by people that really know what they're doing. There are several failure cases (such as `UNPACK`ing a lambda from an untrusted source), most of which are beyond the scope of this document. Don't use these functions without doing your homework first.
<!--DOCUSAURUS_CODE_TABS-->
<!--PascaLIGO-->
<Syntax syntax="pascaligo">
```pascaligo ```pascaligo
function id_string (const p : string) : option(string) is block { function id_string (const p : string) : option(string) is block {
const packed : bytes = bytes_pack(p) ; const packed : bytes = bytes_pack(p) ;
} with (bytes_unpack(packed): option(string)) } with (bytes_unpack(packed): option(string))
``` ```
<!--CameLIGO--> </Syntax>
<Syntax syntax="cameligo">
```cameligo ```cameligo
let id_string (p: string) : string option = let id_string (p: string) : string option =
let packed: bytes = Bytes.pack p in let packed: bytes = Bytes.pack p in
((Bytes.unpack packed): string option) ((Bytes.unpack packed): string option)
``` ```
<!--ReasonLIGO--> </Syntax>
<Syntax syntax="reasonligo">
```reasonligo ```reasonligo
let id_string = (p: string) : option(string) => { let id_string = (p: string) : option(string) => {
let packed : bytes = Bytes.pack(p); let packed : bytes = Bytes.pack(p);
@ -125,4 +141,5 @@ let id_string = (p: string) : option(string) => {
}; };
``` ```
<!--END_DOCUSAURUS_CODE_TABS--> </Syntax>

View File

@ -3,93 +3,108 @@ id: crypto-reference
title: Crypto — Cryptographic functions title: Crypto — Cryptographic functions
--- ---
import Syntax from '@theme/Syntax';
## Crypto.blake2b(data: bytes): bytes ## Crypto.blake2b(data: bytes): bytes
Runs the [blake2b hash algorithm](https://en.wikipedia.org/wiki/BLAKE_(hash_function)#BLAKE2) Runs the [blake2b hash algorithm](https://en.wikipedia.org/wiki/BLAKE_(hash_function)#BLAKE2)
over the given `bytes` data and returns a `bytes` representing the hash. over the given `bytes` data and returns a `bytes` representing the hash.
<!--DOCUSAURUS_CODE_TABS-->
<!--PascaLIGO-->
<Syntax syntax="pascaligo">
```pascaligo ```pascaligo
function hasherman_blake (const s: bytes) : bytes is blake2b(s) function hasherman_blake (const s: bytes) : bytes is blake2b(s)
``` ```
<!--CameLIGO--> </Syntax>
<Syntax syntax="cameligo">
```cameligo ```cameligo
let hasherman_blake (s: bytes) : bytes = Crypto.blake2b s let hasherman_blake (s: bytes) : bytes = Crypto.blake2b s
``` ```
<!--ReasonLIGO--> </Syntax>
<Syntax syntax="reasonligo">
```reasonligo ```reasonligo
let hasherman_blake = (s: bytes) => Crypto.blake2b(s); let hasherman_blake = (s: bytes) => Crypto.blake2b(s);
``` ```
<!--END_DOCUSAURUS_CODE_TABS--> </Syntax>
## Crypto.sha256(data: bytes) : bytes ## Crypto.sha256(data: bytes) : bytes
Runs the [sha256 hash algorithm](https://en.wikipedia.org/wiki/SHA-2) over the given Runs the [sha256 hash algorithm](https://en.wikipedia.org/wiki/SHA-2) over the given
`bytes` data and returns a `bytes` representing the hash. `bytes` data and returns a `bytes` representing the hash.
<!--DOCUSAURUS_CODE_TABS-->
<!--PascaLIGO-->
<Syntax syntax="pascaligo">
```pascaligo ```pascaligo
function hasherman (const s : bytes) : bytes is function hasherman (const s : bytes) : bytes is
begin skip end with sha_256(s) begin skip end with sha_256(s)
``` ```
<!--CameLIGO--> </Syntax>
<Syntax syntax="cameligo">
```cameligo ```cameligo
let hasherman (s : bytes) : bytes = let hasherman (s : bytes) : bytes =
Crypto.sha256 s Crypto.sha256 s
``` ```
<!--ReasonLIGO--> </Syntax>
<Syntax syntax="reasonligo">
```reasonligo ```reasonligo
let hasherman = (s: bytes): bytes => Crypto.sha256(s); let hasherman = (s: bytes): bytes => Crypto.sha256(s);
``` ```
<!--END_DOCUSAURUS_CODE_TABS--> </Syntax>
## Crypto.sha512(data: bytes) : bytes ## Crypto.sha512(data: bytes) : bytes
Runs the [sha512 hash algorithm](https://en.wikipedia.org/wiki/SHA-2) over the given Runs the [sha512 hash algorithm](https://en.wikipedia.org/wiki/SHA-2) over the given
`bytes` data and returns a `bytes` representing the hash. `bytes` data and returns a `bytes` representing the hash.
<!--DOCUSAURUS_CODE_TABS-->
<!--PascaLIGO-->
<Syntax syntax="pascaligo">
```pascaligo ```pascaligo
function hasherman512 (const s: bytes) : bytes is sha_512(s) function hasherman512 (const s: bytes) : bytes is sha_512(s)
``` ```
<!--CameLIGO--> </Syntax>
<Syntax syntax="cameligo">
```cameligo ```cameligo
let hasherman512 (s: bytes) : bytes = Crypto.sha512 s let hasherman512 (s: bytes) : bytes = Crypto.sha512 s
``` ```
<!--ReasonLIGO--> </Syntax>
<Syntax syntax="reasonligo">
```reasonligo ```reasonligo
let hasherman512 = (s: bytes) => Crypto.sha512(s); let hasherman512 = (s: bytes) => Crypto.sha512(s);
``` ```
<!--END_DOCUSAURUS_CODE_TABS--> </Syntax>
## Crypto.hash_key(k: key) : key_hash ## Crypto.hash_key(k: key) : key_hash
Hashes a key for easy comparison and storage. Hashes a key for easy comparison and storage.
<!--DOCUSAURUS_CODE_TABS-->
<!--PascaLIGO-->
<Syntax syntax="pascaligo">
```pascaligo ```pascaligo
function check_hash_key (const kh1 : key_hash; const k2 : key) : bool * key_hash is block { function check_hash_key (const kh1 : key_hash; const k2 : key) : bool * key_hash is block {
var ret : bool := False ; var ret : bool := False ;
@ -98,7 +113,9 @@ function check_hash_key (const kh1 : key_hash; const k2 : key) : bool * key_hash
} with (ret, kh2) } with (ret, kh2)
``` ```
<!--CameLIGO--> </Syntax>
<Syntax syntax="cameligo">
```cameligo ```cameligo
let check_hash_key (kh1, k2: key_hash * key) : bool * key_hash = let check_hash_key (kh1, k2: key_hash * key) : bool * key_hash =
let kh2 : key_hash = Crypto.hash_key k2 in let kh2 : key_hash = Crypto.hash_key k2 in
@ -107,7 +124,9 @@ let check_hash_key (kh1, k2: key_hash * key) : bool * key_hash =
else (false, kh2) else (false, kh2)
``` ```
<!--ReasonLIGO--> </Syntax>
<Syntax syntax="reasonligo">
```reasonligo ```reasonligo
let check_hash_key = ((kh1, k2): (key_hash, key)) : (bool, key_hash) => { let check_hash_key = ((kh1, k2): (key_hash, key)) : (bool, key_hash) => {
let kh2 : key_hash = Crypto.hash_key(k2); let kh2 : key_hash = Crypto.hash_key(k2);
@ -120,7 +139,8 @@ let check_hash_key = ((kh1, k2): (key_hash, key)) : (bool, key_hash) => {
}; };
``` ```
<!--END_DOCUSAURUS_CODE_TABS--> </Syntax>
## Crypto.check(pk: key, signed: signature, data: bytes) : bool ## Crypto.check(pk: key, signed: signature, data: bytes) : bool
@ -128,9 +148,10 @@ Check that a message has been signed by a particular key.
> ⚠️ There is no way to *generate* a signed message in LIGO. This is because that would require storing a private key on chain, at which point it isn't very private anymore. > ⚠️ There is no way to *generate* a signed message in LIGO. This is because that would require storing a private key on chain, at which point it isn't very private anymore.
<!--DOCUSAURUS_CODE_TABS-->
<!--PascaLIGO-->
<Syntax syntax="pascaligo">
```pascaligo ```pascaligo
function check_signature function check_signature
(const pk: key; (const pk: key;
@ -139,17 +160,22 @@ function check_signature
is crypto_check(pk, signed, msg) is crypto_check(pk, signed, msg)
``` ```
<!--CameLIGO--> </Syntax>
<Syntax syntax="cameligo">
```cameligo ```cameligo
let check_signature (pk, signed, msg: key * signature * bytes) : bool = let check_signature (pk, signed, msg: key * signature * bytes) : bool =
Crypto.check pk signed msg Crypto.check pk signed msg
``` ```
<!--ReasonLIGO--> </Syntax>
<Syntax syntax="reasonligo">
```reasonligo ```reasonligo
let check_signature = ((pk, signed, msg): (key, signature, bytes)) : bool => { let check_signature = ((pk, signed, msg): (key, signature, bytes)) : bool => {
Crypto.check(pk, signed, msg); Crypto.check(pk, signed, msg);
}; };
``` ```
<!--END_DOCUSAURUS_CODE_TABS--> </Syntax>

View File

@ -1,319 +1,456 @@
--- ---
id: current-reference id: current-reference
title: Current - Things relating to the current execution context title: Tezos - Things relating to the current execution context
--- ---
## Current.balance() : tez import Syntax from '@theme/Syntax';
# Tezos.balance
Get the balance for the contract. Get the balance for the contract.
<!--DOCUSAURUS_CODE_TABS-->
<!--PascaLIGO-->
<Syntax syntax="pascaligo">
```pascaligo ```pascaligo
function main (const p : unit; const s: tez) : list(operation) * tez is function main (const p : unit; const s: tez) : list (operation) * tez is
((nil : list(operation)), balance) ((nil : list (operation)), Tezos.balance)
``` ```
<!--CameLIGO-->
> Note that `balance` and `Current.balance` are *deprecated*.
</Syntax>
<Syntax syntax="cameligo">
```cameligo ```cameligo
let main (p, s : unit * tez) = let main (p,s : unit * tez) = ([] : operation list), Tezos.balance
([] : operation list), balance
``` ```
<!--ReasonLIGO-->
> Note that `balance` and `Current.balance` are *deprecated*.
</Syntax>
<Syntax syntax="reasonligo">
```reasonligo ```reasonligo
let main = ((p,s): (unit, tez)) => ([]: list(operation), balance); let main = ((p,s) : (unit, tez)) =>
([]: list (operation), Tezos.balance);
``` ```
<!--END_DOCUSAURUS_CODE_TABS--> > Note that `balance` and `Current.balance` are *deprecated*.
## Current.time() : timestamp </Syntax>
## 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 ### Examples
#### 24 hours from now #### 24 hours from now
<!--DOCUSAURUS_CODE_TABS-->
<!--Pascaligo--> <Syntax syntax="pascaligo">
```pascaligo group=b ```pascaligo group=b
const today: timestamp = now; const today: timestamp = Tezos.now;
const one_day: int = 86400; const one_day: int = 86_400;
const in_24_hrs: timestamp = today + one_day; const in_24_hrs: timestamp = today + one_day;
const some_date: timestamp = ("2000-01-01T10:10:10Z" : timestamp); const some_date: timestamp = ("2000-01-01T10:10:10Z" : timestamp);
const one_day_later: timestamp = some_date + one_day; const one_day_later: timestamp = some_date + one_day;
``` ```
<!--CameLIGO--> > Note that `now` is *deprecated*.
</Syntax>
<Syntax syntax="cameligo">
```cameligo group=b ```cameligo group=b
let today: timestamp = Current.time let today: timestamp = Tezos.now
let one_day: int = 86400 let one_day: int = 86_400
let in_24_hrs: timestamp = today + one_day let in_24_hrs: timestamp = today + one_day
let some_date: timestamp = ("2000-01-01t10:10:10Z" : timestamp) let some_date: timestamp = ("2000-01-01t10:10:10Z" : timestamp)
let one_day_later: timestamp = some_date + one_day let one_day_later: timestamp = some_date + one_day
``` ```
<!--ReasonLIGO--> > Note that `Current.time` is *deprecated*.
</Syntax>
<Syntax syntax="reasonligo">
```reasonligo group=b ```reasonligo group=b
let today: timestamp = Current.time; let today: timestamp = Tezos.now;
let one_day: int = 86400; let one_day: int = 86_400;
let in_24_hrs: timestamp = today + one_day; let in_24_hrs: timestamp = today + one_day;
let some_date: timestamp = ("2000-01-01t10:10:10Z" : timestamp); let some_date: timestamp = ("2000-01-01t10:10:10Z" : timestamp);
let one_day_later: timestamp = some_date + one_day; let one_day_later: timestamp = some_date + one_day;
``` ```
<!--END_DOCUSAURUS_CODE_TABS--> > Note that `Current.time` is *deprecated*.
</Syntax>
#### 24 hours ago #### 24 hours ago
<!--DOCUSAURUS_CODE_TABS-->
<!--Pascaligo-->
<Syntax syntax="pascaligo">
```pascaligo group=c ```pascaligo group=c
const today: timestamp = now; const today: timestamp = Tezos.now;
const one_day: int = 86400; const one_day: int = 86_400;
const in_24_hrs: timestamp = today - one_day; const in_24_hrs: timestamp = today - one_day;
``` ```
<!--CameLIGO--> > Note that `now` is *deprecated*.
</Syntax>
<Syntax syntax="cameligo">
```cameligo group=c ```cameligo group=c
let today: timestamp = Current.time let today: timestamp = Tezos.now
let one_day: int = 86400 let one_day: int = 86_400
let in_24_hrs: timestamp = today - one_day let in_24_hrs: timestamp = today - one_day
``` ```
<!--ReasonLIGO--> > Note that `Current.time` is *deprecated*.
</Syntax>
<Syntax syntax="reasonligo">
```reasonligo group=c ```reasonligo group=c
let today: timestamp = Current.time; let today: timestamp = Tezos.now;
let one_day: int = 86400; let one_day: int = 86_400;
let in_24_hrs: timestamp = today - one_day; let in_24_hrs: timestamp = today - one_day;
``` ```
<!--END_DOCUSAURUS_CODE_TABS--> > Note that `Current.time` is *deprecated*.
#### Comparing timestamps </Syntax>
You can also compare timestamps using the same comparison operators as for numbers:
<!--DOCUSAURUS_CODE_TABS--> #### Comparing Timestamps
<!--Pascaligo-->
You can also compare timestamps using the same comparison operators as
for numbers
<Syntax syntax="pascaligo">
```pascaligo group=c ```pascaligo group=c
const not_tommorow: bool = (now = in_24_hrs) const not_tommorow: bool = (Tezos.now = in_24_hrs)
``` ```
<!--CameLIGO--> > Note that `now` is *deprecated*.
</Syntax>
<Syntax syntax="cameligo">
```cameligo group=c ```cameligo group=c
let not_tomorrow: bool = (Current.time = in_24_hrs) let not_tomorrow: bool = (Tezos.now = in_24_hrs)
``` ```
<!--ReasonLIGO--> > Note that `Current.time` is *deprecated*.
</Syntax>
<Syntax syntax="reasonligo">
```reasonligo group=c ```reasonligo group=c
let not_tomorrow: bool = (Current.time == in_24_hrs); let not_tomorrow: bool = (Tezos.now == in_24_hrs);
``` ```
<!--END_DOCUSAURUS_CODE_TABS--> > Note that `Current.time` is *deprecated*.
</Syntax>
## Current.amount() : tez
Get the amount of tez provided by the sender to complete this transaction. ## Amount
<!--DOCUSAURUS_CODE_TABS--> Get the amount of tez provided by the sender to complete this
transaction.
<Syntax syntax="pascaligo">
<!--PascaLIGO-->
```pascaligo ```pascaligo
function check (const p: unit) : int is function threshold (const p : unit) : int is
begin if Tezos.amount = 100tz then 42 else 0
var result : int := 0;
if amount = 100tz then
result := 42
else
result := 0
end with result
``` ```
<!--CameLIGO--> > Note that `amount` is *deprecated*.
</Syntax>
<Syntax syntax="cameligo">
```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
``` ```
<!--ReasonLIGO--> > Note that `Current.amount` is *deprecated*.
</Syntax>
<Syntax syntax="reasonligo">
```reasonligo ```reasonligo
let check_ = (p: unit) : int => let threshold = (p : unit) : int =>
if (Current.amount == 100tz) { if (Tezos.amount == 100tz) { 42; } else { 0; };
42;
}
else {
0;
};
``` ```
<!--END_DOCUSAURUS_CODE_TABS--> > Note that `Current.amount` is *deprecated*.
## Current.sender() : address </Syntax>
## Sender
Get the address that initiated the current transaction. Get the address that initiated the current transaction.
<!--DOCUSAURUS_CODE_TABS-->
<!--PascaLIGO-->
<Syntax syntax="pascaligo">
```pascaligo ```pascaligo
function main (const p: unit) : address is sender function main (const p : unit) : address is Tezos.sender
``` ```
<!--CameLIGO--> > Note that `sender` is *deprecated*.
</Syntax>
<Syntax syntax="cameligo">
```cameligo ```cameligo
let main (p: unit) : address = Current.sender let main (p: unit) : address = Tezos.sender
``` ```
<!--ReasonLIGO--> > Note that `Current.sender` is *deprecated*.
</Syntax>
<Syntax syntax="reasonligo">
```reasonligo ```reasonligo
let main = (p: unit) : address => Current.sender; let main = (p : unit) : address => Tezos.sender;
``` ```
<!--END_DOCUSAURUS_CODE_TABS--> > Note that `Current.sender` is *deprecated*.
## Current.address(c: a' contract) : address </Syntax>
Get the address associated with a `contract`.
<!--DOCUSAURUS_CODE_TABS-->
<!--PascaLIGO--> ## Address
Get the address associated with a value of type `contract`.
<Syntax syntax="pascaligo">
```pascaligo ```pascaligo
function main (const p : key_hash) : address is block { function main (const p : key_hash) : address is block {
const c : contract(unit) = implicit_account(p) ; const c : contract (unit) = Tezos.implicit_account (p)
} with address(c) } with Tezos.address(c)
``` ```
<!--CameLIGO--> > Note that `implicit_account` and `address` are *deprecated*.
</Syntax>
<Syntax syntax="cameligo">
```cameligo ```cameligo
let main (p : key_hash) = let main (p : key_hash) =
let c : unit contract = Current.implicit_account p in let c : unit contract = Tezos.implicit_account p
Current.address c in Tezos.address c
``` ```
<!--ReasonLIGO--> > Note that `Current.implicit_account` and `Current.address` are
> *deprecated*.
</Syntax>
<Syntax syntax="reasonligo">
```reasonligo ```reasonligo
let main = (p : key_hash) : address => { let main = (p : key_hash) : address => {
let c : contract(unit) = Current.implicit_account(p) ; let c : contract (unit) = Tezos.implicit_account (p);
Current.address(c) ; Tezos.address (c);
}; };
``` ```
<!--END_DOCUSAURUS_CODE_TABS--> > Note that `Current.implicit_account` and `Current.address` are
> *deprecated*.
## Current.self_address() : address </Syntax>
## Self Address
Get the address of the currently running contract. Get the address of the currently running contract.
<!--DOCUSAURUS_CODE_TABS-->
<!--PascaLIGO-->
<Syntax syntax="pascaligo">
```pascaligo ```pascaligo
function main (const p: unit) : address is self_address function main (const p : unit) : address is Tezos.self_address
``` ```
<!--CameLIGO--> > Note that `self_address` is *deprecated*.
</Syntax>
<Syntax syntax="cameligo">
```cameligo ```cameligo
let main (p: unit) : address = Current.self_address let main (p : unit) : address = Tezos.self_address
``` ```
<!--ReasonLIGO--> > Note that `Current.self_address` is *deprecated*.
</Syntax>
<Syntax syntax="reasonligo">
```reasonligo ```reasonligo
let main = (p: unit): address => Current.self_address; let main = (p : unit) : address => Tezos.self_address;
``` ```
<!--END_DOCUSAURUS_CODE_TABS--> > Note that `Current.self_address` is *deprecated*.
## Current.implicit_account(p: key_hash) : a' contract </Syntax>
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.
<!--DOCUSAURUS_CODE_TABS--> ## Implicit Account
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.
<Syntax syntax="pascaligo">
<!--PascaLIGO-->
```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)
``` ```
<!--CameLIGO--> > Note that `implicit_account` is *deprecated*.
</Syntax>
<Syntax syntax="cameligo">
```cameligo ```cameligo
let main (kh: key_hash) : unit contract = Current.implicit_account kh let main (kh : key_hash) : unit contract = Tezos.implicit_account kh
``` ```
<!--ReasonLIGO--> > Note that `Current.implicit_account` is *deprecated*.
</Syntax>
<Syntax syntax="reasonligo">
```reasonligo ```reasonligo
let main = (kh: key_hash): contract(unit) => Current.implicit_account(kh); let main = (kh : key_hash): contract (unit) =>
Tezos.implicit_account (kh);
``` ```
<!--END_DOCUSAURUS_CODE_TABS--> > Note that `Current.implicit_account` is *deprecated*.
## Current.source() : address </Syntax>
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.
> ⚠️ ## Source
> There are a few caveats you should keep in mind before using `SOURCE` over `SENDER`:
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
> `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 > 1. `Tezos.source` will never be a contract, so if you want to allow
> 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. > 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-->
<Syntax syntax="pascaligo">
```pascaligo ```pascaligo
function main (const p: unit) : address is source function main (const p: unit) : address is Tezos.source
``` ```
<!--CameLIGO--> > Note that `source` is *deprecated*.
</Syntax>
<Syntax syntax="cameligo">
```cameligo ```cameligo
let main (p: unit) : address = Current.source let main (p : unit) : address = Tezos.source
``` ```
<!--ReasonLIGO--> > Note that `Current.source` is *deprecated*.
</Syntax>
<Syntax syntax="reasonligo">
```reasonligo ```reasonligo
let main = (p: unit) : address => Current.source; let main = (p : unit) : address => Tezos.source;
``` ```
<!--END_DOCUSAURUS_CODE_TABS--> > Note that `Current.source` is *deprecated*.
## Current.failwith(error_message: string) : a' </Syntax>
## Failwith
Cause the contract to fail with an error message. Cause the contract to fail with an error message.
> ⚠ Using this currently requires a type annotation on the failwith to unify it > ⚠ Using this currently requires in general a type annotation on the
> with the type of whatever other code branch it's on. > `failwith` call.
<!--DOCUSAURUS_CODE_TABS-->
<!--PascaLIGO-->
<Syntax syntax="pascaligo">
```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 { 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--> </Syntax>
<Syntax syntax="cameligo">
```cameligo ```cameligo
let main (p,s: unit * unit) = let main (p,s : int * unit) = if p > 10 then failwith "Failure."
if true then failwith "This contract always fails" else ()
``` ```
<!--ReasonLIGO--> </Syntax>
<Syntax syntax="reasonligo">
```reasonligo ```reasonligo
let main = ((p,s): (unit, unit)) => let main = ((p,s) : (int, unit)) =>
if (true) { if (p > 10) { failwith ("Failure."); };
failwith("This contract always fails");
} else {
();
};
``` ```
<!--END_DOCUSAURUS_CODE_TABS--> </Syntax>

View File

@ -1,140 +1,239 @@
--- ---
id: list-reference id: list-reference
title: List — Ordered collection of a type title: Lists — Linear Collections
--- ---
## List.size(lst: a' list) : nat import Syntax from '@theme/Syntax';
Get the number of elements in a list. 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.
<!--DOCUSAURUS_CODE_TABS--> # Defining Lists
<!--PascaLIGO-->
```pascaligo <Syntax syntax="pascaligo">
function size_ (const m : list(int)) : nat is size(m)
```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--> </Syntax>
```cameligo <Syntax syntax="cameligo">
let size_ (s: int list) : nat = List.size s
```cameligo group=lists
let empty_list : int list = []
let my_list : int list = [1; 2; 2] // The head is 1
``` ```
<!--ReasonLIGO--> </Syntax>
```reasonligo <Syntax syntax="reasonligo">
let size_ = (s: list(int)): nat => List.size(s);
```reasonligo group=lists
let empty_list : list (int) = [];
let my_list : list (int) = [1, 2, 2]; // The head is 1
``` ```
<!--END_DOCUSAURUS_CODE_TABS--> </Syntax>
## List.length(lst: a' list) : nat
Alias of `List.size`. # Adding to Lists
## List.map(map_function: a' -> b', lst: a' list) : 'b list Lists can be augmented by adding an element before the head (or, in
terms of stack, by *pushing an element on top*).
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--> <Syntax syntax="pascaligo">
```pascaligo group=b
function increment(const i: int): int is i + 1; ```pascaligo group=lists
// Creates a new list with elements incremented by 1 const larger_list : list (int) = 5 # my_list // [5;1;2;2]
const incremented_list: list(int) = list_map(increment, list 1; 2; 3; end );
``` ```
<!--CameLIGO--> </Syntax>
<Syntax syntax="cameligo">
```cameligo group=b ```cameligo group=lists
let increment (i: int) : int = i + 1 let larger_list : int list = 5 :: my_list // [5;1;2;2]
(* Creates a new list with elements incremented by 1 *)
let incremented_list: int list = List.map increment [1; 2; 3]
``` ```
</Syntax>
<Syntax syntax="reasonligo">
<!--ReasonLIGO--> ```reasonligo group=lists
let larger_list : list (int) = [5, ...my_list]; // [5,1,2,2]
```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--> </Syntax>
## 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--> # Functional Iteration over Lists
<!--PascaLIGO--> A *functional iterator* is a function that traverses a data structure
```pascaligo and calls in turn a given function over the elements of that structure
function iter_op (const s : list(int)) : int is to compute some value. Another approach is possible in PascaLIGO:
begin *loops* (see the relevant section).
var r : int := 0 ;
function aggregate (const i : int) : unit is There are three kinds of functional iterations over LIGO lists: the
begin *iterated operation*, the *map operation* (not to be confused with the
r := r + i ; *map data structure*) and the *fold operation*.
end with unit ;
list_iter(aggregate, s) ; ## Iterated Operation over Lists
end with r
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.
<Syntax syntax="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)
``` ```
<!--CameLIGO--> > Note that `list_iter` is *deprecated*.
```cameligo
let iter_op (s : int list) : unit = </Syntax>
let do_nothing = fun (_: int) -> unit <Syntax syntax="cameligo">
in List.iter do_nothing s
```cameligo group=lists
let iter_op (l : int list) : unit =
let predicate = fun (i : int) -> assert (i > 3)
in List.iter predicate l
``` ```
<!--ReasonLIGO--> </Syntax>
```reasonligo <Syntax syntax="reasonligo">
let iter_op = (s: list(int)): unit => {
let do_nothing = (z: int) => unit; ```reasonligo group=lists
List.iter(do_nothing, s); let iter_op = (l : list (int)) : unit => {
let predicate = (i : int) => assert (i > 3);
List.iter (predicate, l);
}; };
``` ```
<!--END_DOCUSAURUS_CODE_TABS--> </Syntax>
## 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 ## Mapped Operation over Lists
`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. We may want to change all the elements of a given list by applying to
2. Passes the accumulator value to `fold_function` along with the element to produce them a function. This is called a *map operation*, not to be confused
a new accumulated value. with the map data structure.
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--> <Syntax syntax="pascaligo">
```pascaligo group=b
function sum(const result: int; const i: int): int is result + i; ```pascaligo group=lists
const sum_of_a_list: int = list_fold(sum, list 1; 2; 3; end, 0); 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)
``` ```
<!--CameLIGO--> > Note that `list_map` is *deprecated*.
```cameligo group=b </Syntax>
let sum (result, i: int * int) : int = result + i <Syntax syntax="cameligo">
let sum_of_a_list: int = List.fold sum [1; 2; 3] 0
```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--> </Syntax>
<Syntax syntax="reasonligo">
```reasonligo group=b ```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);
```
</Syntax>
## 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.
<Syntax syntax="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*.
</Syntax>
<Syntax syntax="cameligo">
```cameligo group=lists
let sum (acc, i: int * int) : int = acc + i
let sum_of_elements : int = List.fold sum my_list 0
```
</Syntax>
<Syntax syntax="reasonligo">
```reasonligo group=lists
let sum = ((result, i): (int, int)): int => result + i; let sum = ((result, i): (int, int)): int => result + i;
let sum_of_a_list: int = List.fold(sum, [1, 2, 3], 0); let sum_of_elements : int = List.fold (sum, my_list, 0);
``` ```
<!--END_DOCUSAURUS_CODE_TABS--> </Syntax>
# List Length
Get the number of elements in a list.
<Syntax syntax="pascaligo">
```pascaligo
function size_of (const l : list (int)) : nat is List.length (l)
```
> Note that `size` is *deprecated*.
</Syntax>
<Syntax syntax="cameligo">
```cameligo
let size_of (l : int list) : nat = List.length l
```
</Syntax>
<Syntax syntax="reasonligo">
```reasonligo
let size_of = (l : list (int)) : nat => List.length (l);
```
</Syntax>

View File

@ -1,392 +1,419 @@
--- ---
id: map-reference id: map-reference
title: Map — Hashmaps that it makes sense to iterate over title: Maps
--- ---
## Defining A Map Type import Syntax from '@theme/Syntax';
<!--DOCUSAURUS_CODE_TABS--> *Maps* are a data structure which associate values of the same type to
<!--Pascaligo--> values of the same type. The former are called *key* and the latter
```pascaligo *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
<Syntax syntax="pascaligo">
```pascaligo group=maps
type move is int * int type move is int * int
type moveset is map(address, move) type register is map (address, move)
``` ```
<!--CameLIGO--> </Syntax>
```cameligo <Syntax syntax="cameligo">
```cameligo group=maps
type move = int * int type move = int * int
type moveset = (address, move) map type register = (address, move) map
``` ```
<!--ReasonLIGO--> </Syntax>
```reasonligo <Syntax syntax="reasonligo">
```reasonligo group=maps
type move = (int, int); type move = (int, int);
type moveset = map(address, move); type register = map (address, move);
``` ```
<!--END_DOCUSAURUS_CODE_TABS--> </Syntax>
## Creating A Map
<!--DOCUSAURUS_CODE_TABS--> # Creating an Empty Map
<!--Pascaligo-->
```pascaligo
const moves: moveset = map
("tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx": address) -> (1, 2); <Syntax syntax="pascaligo">
("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN": address) -> (0, 3);
end ```pascaligo group=maps
const empty : register = map []
``` ```
<!--CameLIGO--> </Syntax>
<Syntax syntax="cameligo">
```cameligo ```cameligo group=maps
let moves: moveset = Map.literal let empty : register = Map.empty
[ (("tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx": address), (1, 2)) ;
(("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN": address), (0, 3)) ;
]
``` ```
<!--ReasonLIGO--> </Syntax>
<Syntax syntax="reasonligo">
```reasonligo ```reasonligo group=maps
let moves : moveset = let empty : register = Map.empty
Map.literal([
("tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx": address, (1, 2)),
("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN": address, (0, 3)),
]);
```
<!--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--> </Syntax>
```cameligo
let my_balance : move option = Map.find_opt ("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN": address) moves # Creating a Non-empty Map
<Syntax syntax="pascaligo">
```pascaligo group=maps
const moves : register =
map [
("tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx" : address) -> (1,2);
("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN" : address) -> (0,3)]
``` ```
<!--ReasonLIGO--> </Syntax>
<Syntax syntax="cameligo">
```reasonligo ```cameligo group=maps
let my_balance : option(move) = let moves : register =
Map.find_opt("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN": address, moves); Map.literal [
``` (("tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx" : address), (1,2));
<!--END_DOCUSAURUS_CODE_TABS--> (("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN" : address), (0,3))]
## 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--> </Syntax>
<Syntax syntax="reasonligo">
```cameligo ```reasonligo group=maps
let my_balance : move = Map.find ("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN": address) moves let moves : register =
Map.literal ([
("tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx" : address, (1,2)),
("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN" : address, (0,3))]);
``` ```
<!--ReasonLIGO--> </Syntax>
```reasonligo
let my_balance : move = # Accessing Map Bindings
Map.find("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN": address, moves);
<Syntax syntax="pascaligo">
```pascaligo group=maps
const my_balance : option (move) =
moves [("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN" : address)]
``` ```
<!--END_DOCUSAURUS_CODE_TABS--> </Syntax>
<Syntax syntax="cameligo">
## Map.update(k: a', v: b', m: (a', b') map) : (a', b') map ```cameligo group=maps
let my_balance : move option =
Map.find_opt ("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN" : address) moves
```
Change the value associated with a particular key, if that value doesn't already </Syntax>
exist add it. <Syntax syntax="reasonligo">
<!--DOCUSAURUS_CODE_TABS--> ```reasonligo group=maps
let my_balance : option (move) =
Map.find_opt (("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN" : address), moves);
```
<!--Pascaligo--> </Syntax>
The values of a PascaLIGO map can be updated using the ordinary assignment syntax:
```pascaligo 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*.
function set_ (var m: moveset) : moveset is
<Syntax syntax="pascaligo">
```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
```
</Syntax>
<Syntax syntax="cameligo">
```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)
```
</Syntax>
<Syntax syntax="reasonligo">
```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
}
};
```
</Syntax>
# 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. All
those operations are called *updates*.
<Syntax syntax="pascaligo">
```pascaligo group=maps
function assign (var m : register) : register is
block { block {
m[("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN": address)] := (4,9); m [("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN": address)] := (4,9)
} with m } with m
``` ```
<!--Cameligo--> If multiple bindings need to be updated, PascaLIGO offers a *patch
instruction* for maps, similar to that for records.
We can update a map in CameLIGO using the `Map.update` built-in: ```pascaligo group=maps
function assignments (var m : register) : register is
```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
<!--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
```
<!--CameLIGO-->
```cameligo
let add (n,m: int * (int, int) map) : foobar = Map.add 23 n m
```
<!--ReasonLIGO-->
```reasonligo
let add = (n: int, m: map(int, int)) : foobar => Map.add(23, n, m);
```
<!--END_DOCUSAURUS_CODE_TABS-->
## Map.remove(k: a', m: (a', b') map) : (a', b') map
Remove a key and its associated value from the map.
<!--DOCUSAURUS_CODE_TABS-->
<!--PascaLIGO-->
```pascaligo
function rm (var m : map(int, int)) : map(int, int) is block {
remove 42 from map m
} with m
```
<!--CameLIGO-->
```cameligo
let rm (m: (int, int) map) : (int, int) map = Map.remove 42 m
```
<!--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 { block {
function aggregate (const i : address ; const j : move) : unit is block patch m with map [
{ if j.1 > 1 then skip else failwith("fail") } with unit ("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN" : address) -> (4,9);
} with map_iter(aggregate, m); ("tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx" : address) -> (1,2)
]
} with m
``` ```
<!--CameLIGO--> </Syntax>
```cameligo <Syntax syntax="cameligo">
let iter_op (m : moveset) : unit =
let assert_eq = fun (i,j: address * move) -> assert (j.0 > 1) ```cameligo group=maps
in Map.iter assert_eq m 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--> </Syntax>
```reasonligo <Syntax syntax="reasonligo">
let iter_op = (m: moveset): unit => {
let assert_eq = ((i,j): (address, move)) => assert (j[0] > 1); ```reasonligo group=maps
Map.iter(assert_eq, m); 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);
```
</Syntax>
To remove a binding from a map, we need its key.
<Syntax syntax="pascaligo">
```pascaligo group=maps
function delete (const key : address; var moves : register) : register is
block {
remove key from map moves
} with moves
```
</Syntax>
<Syntax syntax="cameligo">
```cameligo group=maps
let delete (key, moves : address * register) : register =
Map.remove key moves
```
</Syntax>
<Syntax syntax="reasonligo">
```reasonligo group=maps
let delete = ((key, moves) : (address, register)) : register =>
Map.remove (key, moves);
```
</Syntax>
# 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.
<Syntax syntax="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*.
</Syntax>
<Syntax syntax="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
```
</Syntax>
<Syntax syntax="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-->
</Syntax>
## Map.map(mapping_function: (a', b') -> b', m: (a', b') map) : (a', b') map ## Map Operations over Maps
Update the values associated with every key in the map according to some update We may want to change all the bindings of a map by applying to them a
rule `mapping_function`. 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 <Syntax syntax="pascaligo">
function map_op (const m : moveset) : moveset is
```pascaligo group=maps
function map_op (const m : register) : register is
block { block {
function increment (const i : address ; const j : move) : move is (j.0, j.1 + 1); function increment (const i : address; const j : move) : move is
} with map_map (increment, m); (j.0, j.1 + 1)
} with Map.map (increment, m)
``` ```
<!--CameLIGO--> > Note that `map_map` is *deprecated*.
```cameligo
let map_op (m : moveset) : moveset = </Syntax>
let increment = fun (i,j: address * move) -> (j.0, j.1 + 1) <Syntax syntax="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 in Map.map increment m
``` ```
<!--ReasonLIGO--> </Syntax>
```reasonligo <Syntax syntax="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); 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' </Syntax>
Combine every value in the map together according to a fold rule `folding_function`.
<!--DOCUSAURUS_CODE_TABS--> ## Folded Operations over Maps
<!--Pascaligo-->
```pascaligo A *folded operation* is the most general of iterations. The folded
function fold_op (const m : moveset) : int is 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.
<Syntax syntax="pascaligo">
```pascaligo group=maps
function fold_op (const m : register) : int is
block { block {
function aggregate (const j : int; const cur : address * (int * int)) : int is j + cur.1.1 function folded (const i : int; const j : address * move) : int is
} with map_fold(aggregate, m, 5) i + j.1.1
} with Map.fold (folded, m, 5)
``` ```
<!--CameLIGO--> > Note that `map_fold` is *deprecated*.
```cameligo
let fold_op (m : moveset) : moveset = </Syntax>
let aggregate = fun (i,j: int * (address * (int * int))) -> i + j.1.1 <Syntax syntax="cameligo">
in Map.fold aggregate m 5
```cameligo group=maps
let fold_op (m : register) : int =
let folded = fun (i,j : int * (address * move)) -> i + j.1.1
in Map.fold folded m 5
``` ```
<!--ReasonLIGO--> </Syntax>
```reasonligo <Syntax syntax="reasonligo">
let fold_op = (m: moveset): moveset => {
let aggregate = ((i,j): (int, (address, (int,int)))) => i + j[1][1]; ```reasonligo group=maps
Map.fold(aggregate, m, 5); let fold_op = (m : register) : int => {
let folded = ((i,j): (int, (address, move))) => i + j[1][1];
Map.fold (folded, m, 5);
}; };
``` ```
<!--END_DOCUSAURUS_CODE_TABS--> </Syntax>
## 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,272 @@
--- ---
id: set-reference id: set-reference
title: Set — Unordered unique collection of a type title: Sets — Unordered unique collection of a type
--- ---
## Defining a set import Syntax from '@theme/Syntax';
<!--DOCUSAURUS_CODE_TABS--> Sets are unordered collections of values of the same type, like lists
<!--Pascaligo--> are ordered collections. Like the mathematical sets and lists, sets
```pascaligo group=a can be empty and, if not, elements of sets in LIGO are *unique*,
type int_set is set (int); whereas they can be repeated in a *list*.
const my_set : int_set = set 1; 2; 3 end
# Empty Sets
<Syntax syntax="pascaligo">
```pascaligo group=sets
const my_set : set (int) = set []
``` ```
<!--CameLIGO--> </Syntax>
```cameligo group=a <Syntax syntax="cameligo">
type int_set = int set
let my_set : int_set = ```cameligo group=sets
Set.add 3 (Set.add 2 (Set.add 1 (Set.empty: int set))) let my_set : int set = Set.empty
``` ```
<!--ReasonLIGO--> </Syntax>
```reasonligo group=a <Syntax syntax="reasonligo">
type int_set = set (int);
let my_set : int_set = ```reasonligo group=sets
Set.add (3, Set.add (2, Set.add (1, Set.empty: set (int)))); let my_set : set (int) = Set.empty;
``` ```
<!--END_DOCUSAURUS_CODE_TABS--> </Syntax>
## Set.mem(is_member: a', s: a' set) : bool # Non-empty Sets
Check if a set `s` contains the element `is_member`.
<!--DOCUSAURUS_CODE_TABS--> <Syntax syntax="pascaligo">
<!--Pascaligo-->
```pascaligo group=a ```pascaligo group=sets
const contains_three : bool = my_set contains 3 const my_set : set (int) = set [3; 2; 2; 1]
// or alternatively
const contains_three_fn: bool = set_mem (3, my_set);
``` ```
<!--CameLIGO--> </Syntax>
```cameligo group=a <Syntax syntax="cameligo">
let contains_three: bool = Set.mem 3 my_set
``` ```cameligo group=sets
<!--ReasonLIGO--> let my_set : int set =
```reasonligo group=a Set.add 3 (Set.add 2 (Set.add 2 (Set.add 1 (Set.empty : int set))))
let contains_three: bool = Set.mem(3, my_set);
``` ```
<!--END_DOCUSAURUS_CODE_TABS--> </Syntax>
<Syntax syntax="reasonligo">
```reasonligo group=sets
## Set.empty() : a' set let my_set : set (int) =
Set.add (3, Set.add (2, Set.add (2, Set.add (1, Set.empty : set (int)))));
Create a new empty set. Needs to be annotated with the set type.
<!--DOCUSAURUS_CODE_TABS-->
<!--Pascaligo-->
```pascaligo group=a
const my_set: int_set = set end
const my_set_2: int_set = set_empty
```
<!--CameLIGO-->
```cameligo group=a
let my_set: int_set = (Set.empty: int set)
```
<!--ReasonLIGO-->
```reasonligo group=a
let my_set: int_set = (Set.empty: set (int));
```
<!--END_DOCUSAURUS_CODE_TABS-->
## Set.literal(element_list_literal: 'a list) : 'a set
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.
<!--DOCUSAURUS_CODE_TABS-->
<!--PascaLIGO-->
```pascaligo
const s_fb : set(string) = set [
"foo" ;
"bar" ;
]
``` ```
<!--CameLIGO--> </Syntax>
```cameligo
let literal_op (p: unit) : string set =
Set.literal ["foo"; "bar"; "foobar"] # Set Membership
<Syntax syntax="pascaligo">
```pascaligo group=sets
const contains_3 : bool = my_set contains 3
``` ```
<!--ReasonLIGO--> </Syntax>
```reasonligo <Syntax syntax="cameligo">
let literal_op = (p: unit) : set(string) => Set.literal(["foo", "bar", "foobar"]);
```cameligo group=sets
let contains_3 : bool = Set.mem 3 my_set
``` ```
<!--END_DOCUSAURUS_CODE_TABS--> </Syntax>
<Syntax syntax="reasonligo">
## Set.add(addition: a', s: a' set) : a' set ```reasonligo group=sets
let contains_3 : bool = Set.mem (3, my_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--> </Syntax>
```cameligo group=a
type int_set = int set
let my_set : int_set = # Cardinal of Sets
Set.add 3 (Set.add 2 (Set.add 1 (Set.empty: int set)))
The predefined function `Set.size` returns the number of
elements in a given set as follows.
<Syntax syntax="pascaligo">
```pascaligo group=sets
const cardinal : nat = Set.size (my_set)
``` ```
<!--ReasonLIGO--> > Note that `size` is *deprecated*.
```reasonligo group=a
type int_set = set (int); </Syntax>
let my_set : int_set = <Syntax syntax="cameligo">
Set.add (3, Set.add (2, Set.add (1, Set.empty: set (int))));
```cameligo group=sets
let cardinal : nat = Set.size my_set
``` ```
<!--END_DOCUSAURUS_CODE_TABS--> </Syntax>
<Syntax syntax="reasonligo">
## Set.remove(removal: a', s: a' set) : a' set ```reasonligo group=sets
let cardinal : nat = Set.size (my_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--> </Syntax>
```cameligo group=a
let smaller_set: int_set = Set.remove 3 my_set # Updating Sets
There are two ways to update a set, that is to add or remove from it.
<Syntax syntax="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)
``` ```
<!--ReasonLIGO--> > Note that `set_add` and `set_remove` are *deprecated*.
```reasonligo group=a If we are in a block, we can use an instruction to modify the set
let smaller_set: int_set = Set.remove(3, my_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)
``` ```
<!--END_DOCUSAURUS_CODE_TABS--> </Syntax>
<Syntax syntax="cameligo">
```cameligo group=sets
## Set.fold(folding_function: a' -> a' -> a', s: a' set, initial: a') : a' let larger_set : int set = Set.add 4 my_set
let smaller_set : int set = Set.remove 3 my_set
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--> </Syntax>
```cameligo group=a <Syntax syntax="reasonligo">
let sum (result, i: int * int) : int = result + i
let sum_of_a_set: int = Set.fold sum my_set 0 ```reasonligo group=sets
let larger_set : set (int) = Set.add (4, my_set);
let smaller_set : set (int) = Set.remove (3, my_set);
``` ```
<!--ReasonLIGO--> </Syntax>
```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);
```
<!--END_DOCUSAURUS_CODE_TABS-->
## Set.size(s: a' set) : nat
Get the number of elements in a set. # Functional Iteration over Sets
<!--DOCUSAURUS_CODE_TABS--> A *functional iterator* is a function that traverses a data structure
<!--Pascaligo--> and calls in turn a given function over the elements of that structure
```pascaligo group=a to compute some value. Another approach is possible in PascaLIGO:
const set_size: nat = size (my_set) *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.
<Syntax syntax="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)
``` ```
<!--CameLIGO--> > Note that `set_iter` is *deprecated*.
```cameligo group=a
let set_size: nat = Set.size my_set </Syntax>
<Syntax syntax="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--> </Syntax>
```reasonligo group=a <Syntax syntax="reasonligo">
let set_size: nat = Set.size (my_set);
```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--> </Syntax>
## 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.
<Syntax syntax="pascaligo">
```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
```
</Syntax>
<Syntax syntax="cameligo">
```cameligo group=sets
let sum (acc, i : int * int) : int = acc + i
let sum_of_elements : int = Set.fold sum my_set 0
```
</Syntax>
<Syntax syntax="reasonligo">
```reasonligo group=sets
let sum = ((acc, i) : (int, int)) : int => acc + i;
let sum_of_elements : int = Set.fold (sum, my_set, 0);
```
</Syntax>

View File

@ -3,29 +3,37 @@ id: string-reference
title: String — Manipulate string data title: String — Manipulate string data
--- ---
import Syntax from '@theme/Syntax';
## String.size(s: string) : nat ## String.size(s: string) : nat
Get the size of a string. [Michelson only supports ASCII strings](http://tezos.gitlab.io/whitedoc/michelson.html#constants) Get the size of a string. [Michelson only supports ASCII strings](http://tezos.gitlab.io/whitedoc/michelson.html#constants)
so for now you can assume that each character takes one byte of storage. so for now you can assume that each character takes one byte of storage.
<!--DOCUSAURUS_CODE_TABS-->
<!--PascaLIGO-->
<Syntax syntax="pascaligo">
```pascaligo ```pascaligo
function string_size (const s: string) : nat is size(s) function string_size (const s: string) : nat is size(s)
``` ```
<!--CameLIGO--> </Syntax>
<Syntax syntax="cameligo">
```cameligo ```cameligo
let size_op (s: string) : nat = String.size s let size_op (s: string) : nat = String.size s
``` ```
<!--ReasonLIGO--> </Syntax>
<Syntax syntax="reasonligo">
```reasonligo ```reasonligo
let size_op = (s: string): nat => String.size(s); let size_op = (s: string): nat => String.size(s);
``` ```
<!--END_DOCUSAURUS_CODE_TABS--> </Syntax>
## String.length(s: string) : nat ## String.length(s: string) : nat
@ -36,20 +44,29 @@ Alias for `String.size`.
Get the substring of `s` between `pos1` inclusive and `pos2` inclusive. For example Get the substring of `s` between `pos1` inclusive and `pos2` inclusive. For example
the string "tata" given to the function below would return "at". the string "tata" given to the function below would return "at".
<!--DOCUSAURUS_CODE_TABS-->
<!--PascaLIGO--> <Syntax syntax="pascaligo">
```pascaligo ```pascaligo
function slice_op (const s : string) : string is string_slice(1n , 2n , s) function slice_op (const s : string) : string is string_slice(1n , 2n , s)
``` ```
<!--CameLIGO-->
</Syntax>
<Syntax syntax="cameligo">
```cameligo ```cameligo
let slice_op (s: string) : string = String.slice 1n 2n s let slice_op (s: string) : string = String.slice 1n 2n s
``` ```
<!--ReasonLIGO-->
</Syntax>
<Syntax syntax="reasonligo">
```reasonligo ```reasonligo
let slice_op = (s: string): string => String.slice(1n, 2n, s); let slice_op = (s: string): string => String.slice(1n, 2n, s);
``` ```
<!--END_DOCUSAURUS_CODE_TABS-->
</Syntax>
## String.sub(pos1: nat, pos2: nat, s: string) : string ## String.sub(pos1: nat, pos2: nat, s: string) : string
@ -59,21 +76,27 @@ Alias for `String.slice`.
Concatenate two strings and return the result. Concatenate two strings and return the result.
<!--DOCUSAURUS_CODE_TABS-->
<!--PascaLIGO-->
<Syntax syntax="pascaligo">
```pascaligo ```pascaligo
function concat_op (const s : string) : string is s ^ "toto" function concat_op (const s : string) : string is s ^ "toto"
``` ```
<!--CameLIGO--> </Syntax>
<Syntax syntax="cameligo">
```cameligo ```cameligo
let concat_syntax (s: string) = s ^ "test_literal" let concat_syntax (s: string) = s ^ "test_literal"
``` ```
<!--ReasonLIGO--> </Syntax>
<Syntax syntax="reasonligo">
```reasonligo ```reasonligo
let concat_syntax = (s: string) => s ++ "test_literal"; let concat_syntax = (s: string) => s ++ "test_literal";
``` ```
<!--END_DOCUSAURUS_CODE_TABS--> </Syntax>

View File

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

View File

@ -3,177 +3,227 @@ id: tezos-taco-shop-payout
title: Paying out profits from the Taco Shop 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/> <br/>
<img src="/img/tutorials/get-started/tezos-taco-shop-payout/get-money.svg" width="50%" /> <img src="/img/tutorials/get-started/tezos-taco-shop-payout/get-money.svg" width="50%" />
<div style="opacity: 0.7; text-align: center; font-size: 10px;"> <div style={{ opacity: 0.7, textAlign: 'center', fontSize: '10px' }}>
<div>Icons made by <a href="https://www.flaticon.com/authors/smashicons" title="Smashicons">Smashicons</a> from <a href="https://www.flaticon.com/" title="Flaticon">www.flaticon.com</a> is licensed by <a href="http://creativecommons.org/licenses/by/3.0/" title="Creative Commons BY 3.0" target="_blank">CC 3.0 BY</a></div> <div>Icons made by <a href="https://www.flaticon.com/authors/smashicons" title="Smashicons">Smashicons</a> from <a href="https://www.flaticon.com/" title="Flaticon">www.flaticon.com</a> is licensed by <a href="http://creativecommons.org/licenses/by/3.0/" title="Creative Commons BY 3.0" target="_blank">CC 3.0 BY</a></div>
</div> </div>
## Analyzing the current contract ## Analyzing the Current Contract
### **`taco-shop.ligo`** ### **`taco-shop.ligo`**
```pascaligo group=a ```pascaligo group=a
type taco_supply is record type taco_supply is record [
current_stock : nat; current_stock : nat;
max_price : tez; max_price : tez
end ]
type taco_shop_storage is map(nat, taco_supply);
function buy_taco (const taco_kind_index: nat ; var taco_shop_storage : taco_shop_storage) : type taco_shop_storage is map (nat, taco_supply)
(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
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 if amount =/= current_purchase_price then
// we won't sell tacos if the amount isn't correct // We won't sell tacos if the amount is not correct
failwith("Sorry, the taco you're trying to purchase has a different price"); failwith ("Sorry, the taco you are trying to purchase has a different price");
else else skip;
// Decrease the stock by 1n, because we've just sold one
taco_kind.current_stock := abs(taco_kind.current_stock - 1n); // 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 // Update the storage with the refreshed taco_kind
taco_shop_storage[taco_kind_index] := taco_kind; taco_shop_storage[taco_kind_index] := taco_kind
end with ((nil : list(operation)), taco_shop_storage) } with ((nil : list (operation)), taco_shop_storage)
``` ```
### Purchase price formula ### Purchase Price Formula
Pedro's Taco Shop contract currently enables customers to buy tacos, at a computed price based on a simple formula.
Pedro's Taco Shop contract currently enables customers to buy tacos,
at a price based on a simple formula.
```pascaligo skip ```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 ### 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.
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 ### 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.
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 ```pascaligo group=ex1
const ownerAddress : address = ("tz1TGu6TN5GSez2ndXXeDX6LgUDvLzPLqgYV" : address); 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 ### 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.
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 ```pascaligo group=ex1
const payoutOperation : operation = transaction(unit, amount, receiver) ; const payoutOperation : operation = transaction (unit, amount, receiver) ;
const operations : list(operation) = list const operations : list (operation) = list [payoutOperation];
payoutOperation
end;
``` ```
--- ---
## Finalizing the contract ## Finalizing the Contract
### **`taco-shop.ligo`** ### **`taco-shop.ligo`**
```pascaligo group=b ```pascaligo group=b
type taco_supply is record type taco_supply is record [
current_stock : nat; current_stock : nat;
max_price : tez; max_price : tez
end ]
type taco_shop_storage is map(nat, taco_supply);
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 type return is list (operation) * taco_shop_storage
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; 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 if amount =/= current_purchase_price then
// we won't sell tacos if the amount isn't correct // We won't sell tacos if the amount is not correct
failwith("Sorry, the taco you're trying to purchase has a different price"); failwith ("Sorry, the taco you are trying to purchase has a different price");
else else skip;
// Decrease the stock by 1n, because we've just sold one
taco_kind.current_stock := abs(taco_kind.current_stock - 1n); // 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 // Update the storage with the refreshed taco_kind
taco_shop_storage[taco_kind_index] := taco_kind; taco_shop_storage[taco_kind_index] := taco_kind;
const receiver : contract(unit) = get_contract(ownerAddress); const receiver : contract(unit) = get_contract (ownerAddress);
const payoutOperation : operation = transaction(unit, amount, receiver); const payoutOperation : operation = transaction (unit, amount, receiver);
const operations : list(operation) = list const operations : list(operation) = list [payoutOperation]
payoutOperation } with ((nil : list (operation)), taco_shop_storage)
end;
end with (operations, 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
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. executed subsequently.
```pascaligo skip ```pascaligo skip
ligo dry-run taco-shop.ligo --syntax pascaligo --amount 1 buy_taco 1n "map ligo dry-run taco-shop.ligo --syntax pascaligo --amount 1 buy_taco 1n "map [
1n -> record 1n -> record [
current_stock = 50n; current_stock = 50n;
max_price = 50000000mutez; max_price = 50tez
end; ];
2n -> record 2n -> record [
current_stock = 20n; current_stock = 20n;
max_price = 75000000mutez; max_price = 75tez
end; ];
end" ]"
``` ```
<img src="/img/tutorials/get-started/tezos-taco-shop-payout/dry-run-1.png" /> <img src="/img/tutorials/get-started/tezos-taco-shop-payout/dry-run-1.png" />
<div style="opacity: 0.7; text-align: center; font-size: 12px; margin-top:-24px;"> <div style={{ opacity: 0.7, textAlign: 'center', fontSize: '12px', marginTop: '-24px' }}>
<b>Operation(...bytes)</b> included in the output <b>Operation(...bytes)</b> included in the output
</div> </div>
<br/> <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 ```pascaligo group=bonus
const ownerAddress: address = ("tz1TGu6TN5GSez2ndXXeDX6LgUDvLzPLqgYV" : address); const ownerAddress : address = ("tz1TGu6TN5GSez2ndXXeDX6LgUDvLzPLqgYV" : address);
const donationAddress: address = ("tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx" : address); const donationAddress : address = ("tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx" : address);
```
```pascaligo group=bonus const receiver : contract (unit) = get_contract (ownerAddress);
const receiver : contract(unit) = get_contract(ownerAddress); const donationReceiver : contract(unit) = get_contract (donationAddress);
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 // Pedro will get 90% of the amount
transaction(unit, amount - donationAmount, receiver); transaction (unit, amount - donationAmount, receiver);
transaction(unit, donationAmount, donationReceiver); transaction (unit, donationAmount, donationReceiver)
end; ];
``` ```
This will result into two operations being subsequently executed on the blockchain: This will result into two operations being subsequently executed on the blockchain:

View File

@ -1,23 +1,33 @@
type taco_supply is record type taco_supply is
record [
current_stock : nat; current_stock : nat;
max_price : tez; max_price : tez
end ]
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 type taco_shop_storage is map (nat, taco_supply)
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
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 if amount =/= current_purchase_price then
// we won't sell tacos if the amount isn't correct // We won't sell tacos if the amount is not correct
fail("Sorry, the taco you're trying to purchase has a different price"); failwith ("Sorry, the taco you are trying to purchase has a different price");
else else skip;
// Decrease the stock by 1n, because we've just sold one
taco_kind.current_stock := abs(taco_kind.current_stock - 1n); // 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 // Update the storage with the refreshed taco_kind
taco_shop_storage[taco_kind_index] := taco_kind; taco_shop_storage[taco_kind_index] := taco_kind
end with ((nil : list(operation)), taco_shop_storage) } with ((nil : list (operation)), taco_shop_storage)

View File

@ -1,112 +1,147 @@
--- ---
id: tezos-taco-shop-smart-contract id: tezos-taco-shop-smart-contract
title: Taco shop smart contract title: The Taco Shop Smart Contract
--- ---
<div> <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/> <br/>
<img src="/img/tutorials/get-started/tezos-taco-shop-smart-contract/taco-stand.svg" width="50%" /> <img src="/img/tutorials/get-started/tezos-taco-shop-smart-contract/taco-stand.svg" width="50%" />
<div style="opacity: 0.7; text-align: center; font-size: 10px;">Made by <a href="https://www.flaticon.com/authors/smashicons" title="Smashicons">Smashicons</a> from <a href="https://www.flaticon.com/" title="Flaticon">www.flaticon.com</a> is licensed by <a href="http://creativecommons.org/licenses/by/3.0/" title="Creative Commons BY 3.0" target="_blank">CC 3.0 BY</a></div> <div style={{ opacity: 0.7, textAlign: 'center', fontSize: '10px' }}>Made by <a href="https://www.flaticon.com/authors/smashicons" title="Smashicons">Smashicons</a> from <a href="https://www.flaticon.com/" title="Flaticon">www.flaticon.com</a> is licensed by <a href="http://creativecommons.org/licenses/by/3.0/" title="Creative Commons BY 3.0" target="_blank">CC 3.0 BY</a></div>
</div> </div>
--- ---
## Pricing ## 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**| |**kind** |id |**available_stock**| **max_price**|
|---|---|---|---| |---|---|---|---|
|el clásico | `1n` | `50n` | `50000000mutez` | |Clásico | `1n` | `50n` | `50tez` |
|especial del chef | `2n` | `20n` | `75000000mutez` | |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 ```pascaligo skip
current_purchase_price = max_price / available_stock current_purchase_price = max_price / available_stock
``` ```
#### El clásico #### El Clásico
|**available_stock**|**max_price**|**current_purchase_price**| |**available_stock**|**max_price**|**current_purchase_price**|
|---|---|---| |---|---|---|
| `50n` | `50000000mutez` | `1tz`| | `50n` | `50tez` | `1tez`|
| `20n` | `50000000mutez` | `2.5tz` | | `20n` | `50tez` | `2.5tez` |
| `5n` | `50000000mutez` | `10tz` | | `5n` | `50tez` | `10tez` |
#### Especial del chef #### Especial del chef
|**available_stock**|**max_price**|**current_purchase_price**| |**available_stock**|**max_price**|**current_purchase_price**|
|---|---|---| |---|---|---|
| `20n` | `75000000mutez` | `3.75tz` | | `20n` | `75tez` | `3.75tez` |
| `10n` | `75000000mutez` | `7.5tz`| | `10n` | `75tez` | `7.5tez`|
| `5n` | `75000000mutez` | `15tz` | | `5n` | `75tez` | `15tez` |
--- ---
## Installing LIGO ## 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" /> <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> <div style={{ opacity: 0.7, textAlign: 'center', fontSize: '12px', marginTop: '-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` ### `taco-shop.ligo`
```pascaligo group=a ```pascaligo group=a
function main (const parameter: int; const contractStorage: int) : (list(operation) * int) is function main (const parameter : int; const contractStorage : int) :
block {skip} with ((nil : list(operation)), contractStorage + parameter) 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 - **`function main`** - definition of the main function, which takes
- **`(const parameter : int; const contractStorage : int)`** - parameters passed to the function a the parameter of the contract and the storage
- **`const parameter : int`** - parameter provided by a transaction that invokes our contract - **`(const parameter : int; const contractStorage : int)`** -
- **`const contractStorage : int`** - definition of our storage (`int`) parameters passed to the function: the first is called `parameter`
- **`(list(operation) * int)`** - return type of our function, in our case a touple with a list of operations, and an int because it denotes the parameter of a specific invocation of the
- **`block {skip}`** - our function has no body, so we instruct LIGO to `skip` it contract, the second is the storage
- **`with ((nil : list(operation)), contractStorage + parameter)`** - essentially a return statement - **`(list (operation) * int)`** - return type of our function, in our
- **`(nil : list(operation))`** - a `nil` value annotated as a list of operations, because that's required by our return type specified above case a tuple with a list of operations, and an `int` (new value for
- **`contractStorage + parameter`** - a new storage value for our contract, sum of previous storage and a transaction parameter the storage after a succesful run of the contract)
### Running LIGO for the first time - **`((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: The `dry-run` command requires a few parameters:
- **contract** *(file path)* - **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)* - **parameter** *(parameter to execute our contract with)*
- **storage** *(starting storage before our contract's code is executed)* - **storage** *(starting storage before our contract's code is executed)*
It outputs what is returned from our main function: in our case a
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. 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 ```zsh
# Contract: taco-shop.ligo # Contract: taco-shop.ligo
# Entry point: main # Main function: main
# Parameter: 4 # Parameter: 4
# Storage: 3 # Storage: 3
ligo dry-run taco-shop.ligo --syntax pascaligo main 4 3 ligo dry-run taco-shop.ligo --syntax pascaligo main 4 3
@ -116,7 +151,7 @@ ligo dry-run taco-shop.ligo --syntax pascaligo main 4 3
``` ```
<img src="/img/tutorials/get-started/tezos-taco-shop-smart-contract/dry-run-1.png" /> <img src="/img/tutorials/get-started/tezos-taco-shop-smart-contract/dry-run-1.png" />
<div style="opacity: 0.7; text-align: center; font-size: 12px; margin-top:-24px;">Simulating contract execution with the CLI</div> <div style={{ opacity: 0.7, textAlign: 'center', fontSize: '12px', marginTop: '-24px' }}>Simulating contract execution with the CLI</div>
<br/> <br/>
@ -124,197 +159,257 @@ 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** **Taco shop's storage**
```pascaligo group=b
type taco_supply is record
current_stock : nat;
max_price : tez;
end
type taco_shop_storage is map(nat, taco_supply); ```pascaligo group=b
type taco_supply is record [
current_stock : nat;
max_price : tez
]
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`** **`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);
function main (const parameter: unit ; const taco_shop_storage : taco_shop_storage) : (list(operation) * taco_shop_storage) is ```pascaligo group=b+
block {skip} with ((nil : list(operation)), taco_shop_storage) 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 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** **Storage value**
```zsh ```zsh
map map [
1n -> record 1n -> record [
current_stock = 50n; current_stock = 50n;
max_price = 50000000mutez; max_price = 50tez
end; ];
2n -> record 2n -> record [
current_stock = 20n; current_stock = 20n;
max_price = 75000000mutez; max_price = 75tez
end; ]
end ]
``` ```
> 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** **Dry run command with a multi-line storage value**
```zsh ```zsh
ligo dry-run taco-shop.ligo --syntax pascaligo main unit "map ligo dry-run taco-shop.ligo --syntax pascaligo main unit "map [
1n -> record 1n -> record [
current_stock = 50n; current_stock = 50n;
max_price = 50000000mutez; max_price = 50tez
end; ];
2n -> record 2n -> record [
current_stock = 20n; current_stock = 20n;
max_price = 75000000mutez; max_price = 75tez
end; ]
end" ]"
``` ```
<img src="/img/tutorials/get-started/tezos-taco-shop-smart-contract/dry-run-2.png" /> <img src="/img/tutorials/get-started/tezos-taco-shop-smart-contract/dry-run-2.png" />
<div style="opacity: 0.7; text-align: center; font-size: 12px; margin-top:-24px;">Dry-run with a complex storage value</div> <div style={{ opacity: 0.7, textAlign: 'center', fontSize: '12px', marginTop: '-24px' }}>Dry-run with a complex storage value</div>
<br/> <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` - 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`** **`taco-shop.ligo`**
```pascaligo group=c ```pascaligo group=c
type taco_supply is record type taco_supply is record [
current_stock : nat; current_stock : nat;
max_price : tez; max_price : tez
end ]
type taco_shop_storage is map(nat, taco_supply);
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 type return is list (operation) * taco_shop_storage
block { skip } with ((nil : 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 - retrieve the `taco_kind` from our storage, based on the
- subtract the `taco_kind.current_stock` by `1n` `taco_kind_index` provided;
- we can find the absolute (`nat`) value of the subtraction above by using `abs`, otherwise we'd be left with an `int` - subtract the `taco_kind.current_stock` by `1n`;
- update the storage, and return it - 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`** **`taco-shop.ligo`**
```pascaligo group=d ```pascaligo group=d
type taco_supply is record type taco_supply is record [
current_stock : nat; current_stock : nat;
max_price : tez; max_price : tez
end ]
type taco_shop_storage is map(nat, taco_supply);
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 // Update the storage with the refreshed taco_kind
taco_shop_storage[taco_kind_index] := taco_kind; taco_shop_storage[taco_kind_index] := taco_kind
end with ((nil : list(operation)), taco_shop_storage) } with ((nil : list (operation)), taco_shop_storage)
``` ```
<img src="/img/tutorials/get-started/tezos-taco-shop-smart-contract/dry-run-3.png" /> <img src="/img/tutorials/get-started/tezos-taco-shop-smart-contract/dry-run-3.png" />
<div style="opacity: 0.7; text-align: center; font-size: 12px; margin-top:-24px;">Stock decreases after selling a taco</div> <div style={{ opacity: 0.7, textAlign: 'center', fontSize: '12px', marginTop: '-24px' }}>Stock decreases after selling a taco</div>
<br/> <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: 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) - calculate a `current_purchase_price` based on the
- check if the sent `amount` matches the `current_purchase_price` [equation specified earlier](tutorials/get-started/tezos-taco-shop-smart-contract.md#calculating-the-current-purchase-price)
- if not, then our contract will `fail` and stop executing - check if the sent `amount` matches the `current_purchase_price`:
- if yes, stock for the given `taco_kind` will be decreased and the payment accepted - 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`** **`taco-shop.ligo`**
```pascaligo group=e ```pascaligo group=e
type taco_supply is record type taco_supply is record [
current_stock : nat; current_stock : nat;
max_price : tez; max_price : tez
end ]
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 type taco_shop_storage is map (nat, taco_supply)
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
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 if amount =/= current_purchase_price then
// we won't sell tacos if the amount isn't correct // We won't sell tacos if the amount is not correct
failwith("Sorry, the taco you're trying to purchase has a different price"); failwith ("Sorry, the taco you are trying to purchase has a different price");
else else skip;
// Decrease the stock by 1n, because we've just sold one
taco_kind.current_stock := abs(taco_kind.current_stock - 1n); // 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 // Update the storage with the refreshed taco_kind
taco_shop_storage[taco_kind_index] := taco_kind; taco_shop_storage[taco_kind_index] := taco_kind
end with ((nil : list(operation)), taco_shop_storage) } 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 ```zsh
ligo dry-run taco-shop.ligo --syntax pascaligo --amount 1 buy_taco 1n "map ligo dry-run taco-shop.ligo --syntax pascaligo --amount 1 buy_taco 1n "map [
1n -> record 1n -> record [
current_stock = 50n; current_stock = 50n;
max_price = 50000000mutez; max_price = 50tez
end; ];
2n -> record 2n -> record [
current_stock = 20n; current_stock = 20n;
max_price = 75000000mutez; max_price = 75tez
end; ]
end" ]"
``` ```
**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" /> <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> <div style={{ opacity: 0.7, textAlign: 'center', fontSize: '12px', marginTop: '-24px' }}>Stock decreases after selling a taco, if the right amount of tezzies is provided</div>
<br/> <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" /> <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, textAlign: 'center', fontSize: '12px',
marginTop: '-24px' }}>Stock does not decrease after a purchase attempt
with an insufficient payment.</div>
<br/> <br/>
@ -322,16 +417,19 @@ 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** **Without tips**
```pascaligo skip ```pascaligo skip
if amount =/= current_purchase_price then if amount =/= current_purchase_price then
``` ```
**With tips** **With tips**
```pascaligo skip ```pascaligo skip
if amount >= current_purchase_price then if amount >= current_purchase_price then
``` ```

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)

20
gitlab-pages/website/.gitignore vendored Normal file
View File

@ -0,0 +1,20 @@
# dependencies
/node_modules
# production
/build
# generated files
.docusaurus
.cache-loader
# misc
.DS_Store
.env.local
.env.development.local
.env.test.local
.env.production.local
npm-debug.log*
yarn-debug.log*
yarn-error.log*

View File

@ -1,8 +1,12 @@
const React = require('react'); import React from 'react';
import Highlight, { defaultProps } from "prism-react-renderer";
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
import useThemeContext from '@theme/hooks/useThemeContext';
import defaultTheme from 'prism-react-renderer/themes/palenight';
import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
const pre = '```'; const PASCALIGO_EXAMPLE = `
const PASCALIGO_EXAMPLE = `${pre}pascaligo
type storage is int type storage is int
type parameter is type parameter is
@ -14,8 +18,11 @@ type return is list (operation) * storage
// Two entrypoints // Two entrypoints
function add (const store : storage; const delta : int) : storage is store + delta function add (const store : storage; const delta : int) : storage is
function sub (const store : storage; const delta : int) : storage is store - delta store + delta
function sub (const store : storage; const delta : int) : storage is
store - delta
(* Main access point that dispatches to the entrypoints according to (* Main access point that dispatches to the entrypoints according to
the smart contract parameter. *) the smart contract parameter. *)
@ -27,9 +34,9 @@ function main (const action : parameter; const store : storage) : return is
| Decrement (n) -> sub (store, n) | Decrement (n) -> sub (store, n)
| Reset -> 0 | Reset -> 0
end) end)
${pre}`; `;
const CAMELIGO_EXAMPLE = `${pre}ocaml const CAMELIGO_EXAMPLE = `
type storage = int type storage = int
type parameter = type parameter =
@ -53,10 +60,10 @@ let main (action, store : parameter * storage) : return =
Increment (n) -> add (store, n) Increment (n) -> add (store, n)
| Decrement (n) -> sub (store, n) | Decrement (n) -> sub (store, n)
| Reset -> 0) | Reset -> 0)
${pre}`; `;
const REASONLIGO_EXAMPLE = `${pre}reasonligo const REASONLIGO_EXAMPLE = `
type storage = int; type storage = int;
type parameter = type parameter =
@ -81,40 +88,82 @@ let main = ((action, store) : (parameter, storage)) : return => {
| Decrement (n) => sub ((store, n)) | Decrement (n) => sub ((store, n))
| Reset => 0})) | Reset => 0}))
}; };
${pre}`; `;
module.exports = props => { function CodeExamples (props) {
const MarkdownBlock = props.MarkdownBlock; const {
siteConfig: {
themeConfig: {prism = {}},
},
} = useDocusaurusContext();
const {isDarkTheme} = useThemeContext();
const lightModeTheme = prism.theme || defaultTheme;
const darkModeTheme = prism.darkTheme || lightModeTheme;
const prismTheme = isDarkTheme ? darkModeTheme : lightModeTheme;
return ( return (
<div className="tabs">
<div className="nav-tabs"> <Tabs
<div defaultValue="pascaligo"
className="nav-link active" values={[
data-group="examples" { label: 'PascaLIGO', value: 'pascaligo', },
data-tab="pascaligo" { label: 'CameLIGO', value: 'cameligo', },
> { label: 'ReasonLIGO', value: 'reasonligo', },
PascaLIGO ]
</div> }>
<div className="nav-link" data-group="examples" data-tab="cameligo"> <TabItem value="pascaligo">
CameLIGO <Highlight {...defaultProps} language="pascaligo" code={PASCALIGO_EXAMPLE} theme={prismTheme}>
</div> {({ className, style, tokens, getLineProps, getTokenProps }) => (
<div className="nav-link" data-group="examples" data-tab="reasonligo"> <pre className={className} style={style}>
ReasonLIGO {tokens.map((line, i) => (
</div> <div {...getLineProps({ line, key: i })}>
</div> {line.map((token, key) => (
<div className="tab-content"> <span {...getTokenProps({ token, key })} />
<div id="pascaligo" className="tab-pane active" data-group="examples"> ))}
<MarkdownBlock>{PASCALIGO_EXAMPLE}</MarkdownBlock>
</div>
<div id="cameligo" className="tab-pane" data-group="examples">
<MarkdownBlock>{CAMELIGO_EXAMPLE}</MarkdownBlock>
</div>
<div id="reasonligo" className="tab-pane" data-group="examples">
<MarkdownBlock>{REASONLIGO_EXAMPLE}</MarkdownBlock>
</div> </div>
))}
</pre>
)}
</Highlight>
</TabItem>
<TabItem value="cameligo">
<Highlight {...defaultProps} language="cameligo" code={CAMELIGO_EXAMPLE} theme={prismTheme}>
{({ className, style, tokens, getLineProps, getTokenProps }) => (
<pre className={className} style={style}>
{tokens.map((line, i) => (
<div {...getLineProps({ line, key: i })}>
{line.map((token, key) => (
<span {...getTokenProps({ token, key })} />
))}
</div> </div>
))}
</pre>
)}
</Highlight>
</TabItem>
<TabItem value="reasonligo">
<Highlight {...defaultProps} language="reasonligo" code={REASONLIGO_EXAMPLE} theme={prismTheme}>
{({ className, style, tokens, getLineProps, getTokenProps }) => (
<pre className={className} style={style}>
{tokens.map((line, i) => (
<div {...getLineProps({ line, key: i })}>
{line.map((token, key) => (
<span {...getTokenProps({ token, key })} />
))}
</div> </div>
))}
</pre>
)}
</Highlight>
</TabItem>
</Tabs>
); );
}; };
export default CodeExamples

View File

@ -1,3 +1,5 @@
// deprecated.
const React = require('react'); const React = require('react');
const docUrl = require(`${process.cwd()}/core/UrlUtils`).docUrl; const docUrl = require(`${process.cwd()}/core/UrlUtils`).docUrl;

View File

@ -0,0 +1,226 @@
const repoUrl = 'https://gitlab.com/ligolang/ligo';
// let reasonHighlightJs = require('reason-highlightjs');
const siteConfig = {
title: 'LIGO', // Title for your website.
tagline: 'LIGO is a friendly smart contract language for Tezos',
// taglineSub: 'Michelson was never so easy',
url: 'https://ligolang.org', // Your website URL
baseUrl: '/', // Base URL for your project */
// For github.io type URLs, you would set the url and baseUrl like:
// url: 'https://facebook.github.io',
// baseUrl: '/test-site/',
// Used for publishing and more
projectName: 'ligo',
organizationName: 'TBN',
// For top-level user or org sites, the organization is still the same.
// e.g., for the https://JoelMarcey.github.io site, it would be set like...
// organizationName: 'JoelMarcey'
// For no header links in the top nav bar -> headerLinks: [],
// footerLinks: {
// docs: [
// { doc: 'intro/installation', label: 'Install' },
// { doc: 'api/cli-commands', label: 'CLI Commands' },
// { doc: 'contributors/origin', label: 'Contribute' },
// { href: '/odoc', label: 'API Documentation' }
// ],
// community: [
// {
// href: 'https://forum.tezosagora.org/tag/ligo',
// label: 'Tezos Agora Forum',
// blankTarget: true
// },
// {
// href: 'https://tezos.stackexchange.com/questions/tagged/ligo',
// label: 'Tezos Stack Exchange',
// blankTarget: true
// },
// {
// href: 'https://t.me/LigoLang',
// label: 'Telegram',
// blankTarget: true
// },
// {
// href: 'https://discord.gg/9rhYaEt',
// label: 'Discord',
// blankTarget: true
// }
// ],
// more: [
// {
// doc: 'tutorials/get-started/tezos-taco-shop-smart-contract',
// label: 'Tutorials'
// },
// { href: repoUrl, label: 'GitLab' }
// ]
// },
favicon: 'img/circle.svg',
/* highlight: {
// Highlight.js theme to use for syntax highlighting in code blocks.
theme: 'default',
hljs: function (hljs) {
hljs.registerLanguage('reasonligo', reasonHighlightJs);
hljs.registerLanguage('pascaligo', function (hljs) {
return {
// case_insensitive: true,
beginKeywords: '',
keywords: {
keyword:
'and attributes begin big_map block case const contains else'
+ ' end False for from function if in is list map mod nil'
+ ' not of or patch record remove set skip then to True type'
+ ' var while with',
literal: 'true false unit int string Some None bool nat list'
},
lexemes: '[a-zA-Z][a-zA-Z0-9_]*',
contains: [
hljs.C_LINE_COMMENT_MODE,
{
className: 'type',
begin: /[A-Z][a-z]+/
},
{
begin: /[*+-:;\(\)\{\}|\>\<]/
// className: 'ignore'
}
]
};
});
}
},*/
// Add custom scripts here that would be placed in <script> tags.
scripts: ['https://buttons.github.io/buttons.js'],
// On page navigation for the current documentation page.
// No .html extensions for paths.
// Show documentation's last contributor's name.
// enableUpdateBy: true,
// Show documentation's last update time.
// enableUpdateTime: true,
// You may provide arbitrary config keys to be used as needed by your
// template. For example, if you need your repo's URL...
// repoUrl: repoUrl,
stylesheets: [
'https://fonts.googleapis.com/css?family=DM+Sans:400,400i,500,500i,700,700i|Open+Sans:300,300i,400,600|Source+Code+Pro&display=swap'
],
presets: [
[
'@docusaurus/preset-classic',
{
docs: {
// docs folder path relative to website dir.
path: '../docs',
// sidebars file relative to website dir.
sidebarPath: require.resolve('./sidebars.json'),
},
theme: {
customCss: require.resolve('./static/css/custom.css'),
}
}
]
],
themeConfig: {
googleAnalytics: {
trackingID: 'UA-153751765-1',
gtag: true
},
algolia: {
apiKey: '12be98d9fd4242a5f16b70a5cc6b0158',
indexName: 'ligolang',
algoliaOptions: {} // Optional, if provided by Algolia
},
navbar: {
logo: {
alt: 'LIGO Logo',
src: 'img/logo.svg',
srcDark: 'img/logo-night.svg'
},
links: [
{ href: 'https://ide.ligolang.org/', label: 'Try Online' },
{ to: 'docs/intro/installation', label: 'Install' },
{ to: 'docs/intro/introduction', label: 'Docs' },
{
to: 'docs/tutorials/get-started/tezos-taco-shop-smart-contract',
label: 'Tutorials'
},
{ href: 'https://forum.tezosagora.org/tag/ligo', label: 'Blog' },
// TODO: { href: "/odoc", label: "API" },
// { doc: 'contributors/origin', label: 'Contribute' },
{ to: '/contact', label: 'Ask Questions' }
],
},
footer: {
links: [
{
title: 'Docs',
items: [
{ to: 'docs/intro/installation', label: 'Install' },
{ to: 'docs/api/cli-commands', label: 'CLI Commands' },
{ to: 'docs/contributors/origin', label: 'Contribute' },
{ to: '/odoc', label: 'API Documentation' }
]
},
{
title: 'Community',
items: [
{
href: 'https://forum.tezosagora.org/tag/ligo',
label: 'Tezos Agora Forum'
},
{
href: 'https://tezos.stackexchange.com/questions/tagged/ligo',
label: 'Tezos Stack Exchange'
},
{
href: 'https://t.me/LigoLang',
label: 'Telegram'
},
{
href: 'https://discord.gg/9rhYaEt',
label: 'Discord'
}
]
},
{
title: 'More',
items: [
{
label: 'Tutorials',
to: 'docs/tutorials/get-started/tezos-taco-shop-smart-contract'
},
{
label: 'GitLab',
href: repoUrl
}
]
}
// { href: 'https://ide.ligolang.org/', title: 'Try Online' }
],
copyright: `© ${new Date().getFullYear()} LIGO. All rights reserved.`,
},
image: 'img/docusaurus.png',
sidebarCollapsible: true,
prism: {
theme: require('prism-react-renderer/themes/github'),
darkTheme: require('prism-react-renderer/themes/vsDark')
},
}
};
module.exports = siteConfig;

View File

@ -1,17 +1,24 @@
{ {
"scripts": { "scripts": {
"examples": "docusaurus-examples", "start": "docusaurus start --host 0.0.0.0 --port 3000",
"start": "docusaurus-start", "build": "docusaurus build",
"build": "docusaurus-build", "swizzle": "docusaurus swizzle",
"publish-gh-pages": "docusaurus-publish", "deploy": "docusaurus deploy"
"write-translations": "docusaurus-write-translations",
"version": "docusaurus-version",
"preversion": "node preversion.js",
"postversion": "node postversion.js",
"rename-version": "docusaurus-rename-version"
}, },
"devDependencies": { "devDependencies": {
"docusaurus": "^1.14.0", "@docusaurus/core": "^2.0.0-alpha.43",
"reason-highlightjs": "0.2.1" "@docusaurus/preset-classic": "^2.0.0-alpha.43",
"classnames": "^2.2.6",
"react": "^16.13.0",
"react-dom": "^16.13.0",
"webpack": "4.41.2"
},
"browserslist": {
"production": [">0.2%", "not dead", "not op_mini all"],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
} }
} }

View File

@ -1,100 +0,0 @@
const React = require('react');
const MarkdownBlock = require('../../core/CompLibrary').MarkdownBlock;
const CodeExamples = require(`${process.cwd()}/core/CodeExamples`);
const docUrl = require(`${process.cwd()}/core/UrlUtils`).docUrl;
const FEATURES = [
{
image: 'img/strong-type-system.svg',
title: 'Strong, Static Type System',
content: 'Write types, then code. Benefit from the safety of type systems.'
},
{
image: 'img/syntax-agnostic.svg',
title: 'Polyglot',
content:
'Code in your language. Write PascaLIGO, CameLIGO, ReasonLIGO or add your own syntax.'
},
{
image: 'img/easy-integration.svg',
title: 'Easy Integration',
content: 'You can use LIGO as a NodeJS library with Granary'
}
];
const PARTNERS = [
{
name: 'Nomadic Labs',
image: 'img/nomadic-logo.png',
link: 'https://www.nomadic-labs.com/',
pinned: true
},
{
name: 'Tocqueville Group',
image: 'img/tq-logo.svg',
link: 'https://tqgroup.io/',
pinned: true
},
{
name: 'Stove Labs',
image: 'img/stove-logo.png',
link: 'https://stove-labs.com',
pinned: true
}
];
const Feature = (config, props) => (
<div className="feature" key={props.title}>
<img src={`${config.baseUrl}${props.image}`} />
<h1>{props.title}</h1>
<p>{props.content}</p>
</div>
);
const Partner = (config, props) => (
<a
href={props.link}
title={props.name}
target="_blank"
rel="noopener noreferrer"
>
<img src={`${config.baseUrl}${props.image}`} />
</a>
);
module.exports = props => {
return (
<div id="homePage">
<div id="intro" className="centered">
<div id="callToAction">
<ul>
<li className="primary">
<a href="https://ide.ligolang.org">Try Online</a>
</li>
<li className="secondary">
<a href={docUrl(props.config, 'intro/installation')}>Install</a>
</li>
</ul>
</div>
<div id="preview">
<h1>A friendly Smart Contract Language for Tezos</h1>
<p>Michelson was never so easy</p>
<CodeExamples MarkdownBlock={MarkdownBlock}></CodeExamples>
</div>
</div>
<div id="features" className="centered">
{FEATURES.map(entry => Feature(props.config, entry))}
</div>
<div id="partners">
<div className="centered wrapper">
<span id="heading">Our Partners</span>
<div id="list">
{PARTNERS.filter(entry => entry.pinned).map(entry =>
Partner(props.config, entry)
)}
</div>
</div>
</div>
</div>
);
};

View File

@ -1,113 +0,0 @@
/**
* Copyright (c) 2017-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
const React = require('react');
const CompLibrary = require('../../core/CompLibrary');
const Container = CompLibrary.Container;
const CWD = process.cwd();
const versions = require(`${CWD}/versions.json`);
function Versions(props) {
const {config: siteConfig} = props;
const latestVersion = versions[0];
const repoUrl = `${siteConfig.repoUrl}`;
return (
<div className="docMainWrapper wrapper">
<Container className="mainContainer versionsContainer">
<div className="post">
<header className="postHeader">
<h1>{siteConfig.title} Versions </h1>
</header>
<h3 id="latest">Current version</h3>
<table className="versions">
<tbody>
<tr>
<th>{latestVersion}</th>
<td>
{/* You are supposed to change this href where appropriate
Example: href="<baseUrl>/docs(/:language)/:id" */}
<a
href={`${siteConfig.baseUrl}${siteConfig.docsUrl}/${
props.language ? props.language + '/' : ''
}intro/installation`}>
Documentation
</a>
</td>
<td>
<a href={repoUrl}>Source Code</a>
</td>
{/* <td>
<a href="">Release Notes</a>
</td> */}
</tr>
</tbody>
</table>
<h3 id="rc">Pre-release versions</h3>
<table className="versions">
<tbody>
<tr>
<th>next</th>
<td>
{/* You are supposed to change this href where appropriate
Example: href="<baseUrl>/docs(/:language)/next/:id" */}
<a
href={`${siteConfig.baseUrl}${siteConfig.docsUrl}/${
props.language ? props.language + '/' : ''
}next/intro/installation`}>
Documentation
</a>
</td>
<td>
<a href={repoUrl}>Source Code</a>
</td>
</tr>
</tbody>
</table>
<h3 id="archive">Past Versions</h3>
<p>Here you can find previous versions of the documentation.</p>
<table className="versions">
<tbody>
{versions.map(
version =>
version !== latestVersion && version !== "next" && (
<tr>
<th>{version}</th>
<td>
{/* You are supposed to change this href where appropriate
Example: href="<baseUrl>/docs(/:language)/:version/:id" */}
<a
href={`${siteConfig.baseUrl}${siteConfig.docsUrl}/${
props.language ? props.language + '/' : ''
}${version}/intro/installation`}>
Documentation
</a>
</td>
<td>
<a href={`${repoUrl}/releases/tag/v${version}`}>
Release Notes
</a>
</td>
</tr>
),
)}
</tbody>
</table>
<p>
You can find past versions of this project on{' '}
<a href={repoUrl}>GitLab</a>.
</p>
</div>
</Container>
</div>
);
}
module.exports = Versions;

View File

@ -1,158 +0,0 @@
const repoUrl = 'https://gitlab.com/ligolang/ligo';
let reasonHighlightJs = require('reason-highlightjs');
const siteConfig = {
title: 'LIGO', // Title for your website.
tagline: 'LIGO is a friendly smart contract language for Tezos',
taglineSub: 'Michelson was never so easy',
url: 'https://ligolang.org', // Your website URL
baseUrl: '/', // Base URL for your project */
// For github.io type URLs, you would set the url and baseUrl like:
// url: 'https://facebook.github.io',
// baseUrl: '/test-site/',
// Used for publishing and more
projectName: 'ligo',
organizationName: 'TBN',
// For top-level user or org sites, the organization is still the same.
// e.g., for the https://JoelMarcey.github.io site, it would be set like...
// organizationName: 'JoelMarcey'
// For no header links in the top nav bar -> headerLinks: [],
headerLinks: [
{ href: 'https://ide.ligolang.org/', label: 'Try Online' },
{ doc: 'intro/installation', label: 'Install' },
{ doc: 'intro/introduction', label: 'Docs' },
{
doc: 'tutorials/get-started/tezos-taco-shop-smart-contract',
label: 'Tutorials'
},
{ blog: true, label: 'Blog' },
// TODO: { href: "/odoc", label: "API" },
// { doc: 'contributors/origin', label: 'Contribute' },
{ href: '/contact', label: 'Ask Questions' },
{ search: true }
],
footerLinks: {
docs: [
{ doc: 'intro/installation', label: 'Install' },
{ doc: 'api/cli-commands', label: 'CLI Commands' },
{ doc: 'contributors/origin', label: 'Contribute' },
{ href: '/odoc', label: 'API Documentation' }
],
community: [
{
href: 'https://forum.tezosagora.org/tag/ligo',
label: 'Tezos Agora Forum',
blankTarget: true
},
{
href: 'https://tezos.stackexchange.com/questions/tagged/ligo',
label: 'Tezos Stack Exchange',
blankTarget: true
},
{
href: 'https://t.me/LigoLang',
label: 'Telegram',
blankTarget: true
},
{
href: 'https://discord.gg/9rhYaEt',
label: 'Discord',
blankTarget: true
}
],
more: [
{
doc: 'tutorials/get-started/tezos-taco-shop-smart-contract',
label: 'Tutorials'
},
{ href: repoUrl, label: 'GitLab' }
]
},
/* path to images for header/footer */
footerIcon: 'img/logo.svg',
favicon: 'img/logo.svg',
/* Colors for website */
colors: {
primaryColor: '#1A1A1A',
secondaryColor: '#1A1A1A'
},
// This copyright info is used in /core/Footer.js and blog RSS/Atom feeds.
copyright: `© ${new Date().getFullYear()} LIGO. All rights reserved.`,
highlight: {
// Highlight.js theme to use for syntax highlighting in code blocks.
theme: 'default',
hljs: function (hljs) {
hljs.registerLanguage('reasonligo', reasonHighlightJs);
hljs.registerLanguage('pascaligo', function (hljs) {
return {
// case_insensitive: true,
beginKeywords: '',
keywords: {
keyword:
'and attributes begin big_map block case const contains else'
+ ' end False for from function if in is list map mod nil'
+ ' not of or patch record remove set skip then to True type'
+ ' var while with',
literal: 'true false unit int string Some None bool nat list'
},
lexemes: '[a-zA-Z][a-zA-Z0-9_]*',
contains: [
hljs.C_LINE_COMMENT_MODE,
{
className: 'type',
begin: /[A-Z][a-z]+/
},
{
begin: /[*+-:;\(\)\{\}|\>\<]/
// className: 'ignore'
}
]
};
});
}
},
// Add custom scripts here that would be placed in <script> tags.
scripts: ['https://buttons.github.io/buttons.js'],
// On page navigation for the current documentation page.
onPageNav: 'separate',
// No .html extensions for paths.
cleanUrl: true,
// Open Graph and Twitter card images.
ogImage: 'img/logo.svg',
twitterImage: 'img/undraw_tweetstorm.svg',
// Show documentation's last contributor's name.
// enableUpdateBy: true,
// Show documentation's last update time.
// enableUpdateTime: true,
// You may provide arbitrary config keys to be used as needed by your
// template. For example, if you need your repo's URL...
repoUrl: repoUrl,
stylesheets: [
'https://fonts.googleapis.com/css?family=DM+Sans:400,400i,500,500i,700,700i|Open+Sans:300,300i,400,600|Source+Code+Pro&display=swap'
],
algolia: {
apiKey: '12be98d9fd4242a5f16b70a5cc6b0158',
indexName: 'ligolang',
algoliaOptions: {} // Optional, if provided by Algolia
},
docsSideNavCollapsible: true,
gaTrackingId: 'UA-153751765-1',
gaGtag: true
};
module.exports = siteConfig;

View File

@ -1,4 +1,6 @@
const React = require('react'); import React from 'react';
import Layout from '@theme/Layout';
import useBaseUrl from '@docusaurus/useBaseUrl';
const TEAM = [ const TEAM = [
{ {
@ -49,7 +51,7 @@ const COMMUNICATION_CHANNELS = [
{ {
link: 'https://t.me/LigoLang', link: 'https://t.me/LigoLang',
icon: 'img/telegram.svg', icon: 'img/telegram.svg',
description: "We're hear to help. Ask us anything" description: "We're here to help. Ask us anything"
}, },
{ {
link: 'https://gitlab.com/ligolang/ligo/issues', link: 'https://gitlab.com/ligolang/ligo/issues',
@ -72,7 +74,7 @@ const Portrait = (config, props) => {
target="_blank" target="_blank"
rel="noopener noreferrer" rel="noopener noreferrer"
> >
<img className="portrait" src={`${config.baseUrl}${props.image}`} /> <img className="portrait" src={useBaseUrl(props.image)} />
<div className="overlay"> <div className="overlay">
<span>{props.firstName}</span> <span>{props.firstName}</span>
<span>{props.lastName}</span> <span>{props.lastName}</span>
@ -89,20 +91,27 @@ const CommunicationChannel = (config, props) => {
target="_blank" target="_blank"
rel="noopener noreferrer" rel="noopener noreferrer"
> >
<img className="icon" src={`${config.baseUrl}${props.icon}`} /> <img className="icon" src={useBaseUrl(props.icon)} />
{props.description} {props.description}
</a> </a>
); );
}; };
module.exports = props => { export default props => {
const pinnedMembers = TEAM.filter(member => member.pinned); const pinnedMembers = TEAM.filter(member => member.pinned);
const membersCeilCount = Math.ceil(pinnedMembers.length / 2); const membersCeilCount = Math.ceil(pinnedMembers.length / 2);
const membersInFistColumn = pinnedMembers.slice(0, membersCeilCount); const membersInFistColumn = pinnedMembers.slice(0, membersCeilCount);
const membersInSecondColumn = pinnedMembers.slice(membersCeilCount); const membersInSecondColumn = pinnedMembers.slice(membersCeilCount);
return <Layout title="Contact">
return ( <div
<div id="contactPage" className="centered"> id="contactPage"
style={{
display: 'flex',
justifyContent: 'stretch',
alignItems: 'stretch',
fontSize: '20px',
flexDirection: 'row'
}}>
<div id="mural"> <div id="mural">
<div className="column"> <div className="column">
{membersInFistColumn.map(entry => Portrait(props.config, entry))} {membersInFistColumn.map(entry => Portrait(props.config, entry))}
@ -120,5 +129,6 @@ module.exports = props => {
</div> </div>
</div> </div>
</div> </div>
); </Layout>
}; }

View File

@ -0,0 +1,184 @@
import React from 'react';
import Layout from '@theme/Layout';
import useBaseUrl from '@docusaurus/useBaseUrl';
import CodeExamples from '../../core/CodeExamples';
const {Prism} = require("prism-react-renderer");
Prism.languages = {
...Prism.languages,
pascaligo: {
'comment': [
/\(\*[\s\S]+?\*\)/,
// /\{[\s\S]+?\}/,
/\/\/.*/
],
'string': {
pattern: /(?:'(?:''|[^'\r\n])*'|#[&$%]?[a-f\d]+)+|\^[a-z]/i,
greedy: true
},
'keyword': [
{
// Turbo Pascal
pattern: /(^|[^&])\b(?:absolute|array|asm|begin|case|const|constructor|destructor|do|downto|else|end|file|for|function|goto|if|implementation|inherited|inline|interface|label|nil|object|of|operator|packed|procedure|program|record|reintroduce|repeat|self|set|string|then|to|type|unit|until|uses|var|while|with)\b/i,
lookbehind: true
},
{
// Free Pascal
pattern: /(^|[^&])\b(?:dispose|exit|false|new|true)\b/i,
lookbehind: true
},
{
// Object Pascal
pattern: /(^|[^&])\b(?:class|dispinterface|except|exports|finalization|finally|initialization|inline|library|on|out|packed|property|raise|resourcestring|threadvar|try)\b/i,
lookbehind: true
},
{
// Modifiers
pattern: /(^|[^&])\b(?:absolute|abstract|alias|assembler|bitpacked|break|cdecl|continue|cppdecl|cvar|default|deprecated|dynamic|enumerator|experimental|export|external|far|far16|forward|generic|helper|implements|index|interrupt|iochecks|local|message|name|near|nodefault|noreturn|nostackframe|oldfpccall|otherwise|overload|override|pascal|platform|private|protected|public|published|read|register|reintroduce|result|safecall|saveregisters|softfloat|specialize|static|stdcall|stored|strict|unaligned|unimplemented|varargs|virtual|write)\b/i,
lookbehind: true
}
],
'number': [
// Hexadecimal, octal and binary
/(?:[&%]\d+|\$[a-f\d]+)/i,
// Decimal
/\b\d+(?:\.\d+)?(?:e[+-]?\d+)?/i
],
'operator': [
/\.\.|\*\*|:=|<[<=>]?|>[>=]?|[+\-*\/]=?|[@^=]/i,
{
pattern: /(^|[^&])\b(?:and|as|div|exclude|in|include|is|mod|not|or|shl|shr|xor)\b/,
lookbehind: true
}
],
'punctuation': /\(\.|\.\)|[()\[\]:;,.]/
},
reasonligo:
{...Prism.languages.reason,
'comment': [
/(^|[^\\])\/\*[\s\S]*?\*\//,
/\(\*[\s\S]*?\*\)/,
/\/\/.*/
]
},
cameligo: {
...Prism.languages.ocaml,
'comment': [
/(^|[^\\])\/\*[\s\S]*?\*\//,
/\(\*[\s\S]*?\*\)/,
/\/\/.*/
]}
};
const FEATURES = [
{
image: 'img/strong-type-system.svg',
title: 'Strong, Static Type System',
content: 'Write types, then code. Benefit from the safety of type systems.'
},
{
image: 'img/syntax-agnostic.svg',
title: 'Polyglot',
content:
'Code in your language. Write PascaLIGO, CameLIGO, ReasonLIGO or add your own syntax.'
},
{
image: 'img/easy-integration.svg',
title: 'Easy Integration',
content: 'You can use LIGO as a NodeJS library with Granary'
}
];
const PARTNERS = [
{
name: 'Nomadic Labs',
image: 'img/nomadic-logo.png',
link: 'https://www.nomadic-labs.com/',
pinned: true
},
{
name: 'Tocqueville Group',
image: 'img/tq-logo.svg',
link: 'https://tqgroup.io/',
pinned: true
},
{
name: 'Stove Labs',
image: 'img/stove-logo.png',
link: 'https://stove-labs.com',
pinned: true
}
];
const Feature = (props) => (
<div className="feature" key={props.title}>
<img src={useBaseUrl(props.image)} />
<h1>{props.title}</h1>
<p>{props.content}</p>
</div>
);
const Partner = (props) => (
<a
href={props.link}
title={props.name}
target="_blank"
rel="noopener noreferrer"
>
<img src={useBaseUrl(props.image)} />
</a>
);
function HomePage() {
return <Layout title="Homepage">
<div
id="homePage"
style={{
display: 'flex',
justifyContent: 'stretch',
alignItems: 'stretch',
fontSize: '20px',
flexDirection: 'column'
}}>
<div id="intro" className="centered">
<div id="callToAction">
<ul>
<li className="primary">
<a href="https://ide.ligolang.org">Try Online</a>
</li>
<li className="secondary">
<a href={useBaseUrl('/docs/intro/installation')}>Install</a>
</li>
</ul>
</div>
<div id="preview">
<h1>A friendly Smart Contract Language for Tezos</h1>
<p>Tezos was never so easy</p>
<CodeExamples />
</div>
</div>
<div id="features" className="centered">
{FEATURES.map(entry =>
<Feature key={entry.title} title={entry.title} content={entry.content} image={entry.image} />
)}
</div>
<div id="partners">
<div className="centered wrapper">
<span id="heading">Our Partners</span>
<div id="list">
{PARTNERS.filter(entry => entry.pinned).map(entry =>
<Partner key={entry.name} name={entry.name} image={entry.image} link={entry.link} />
)}
</div>
</div>
</div>
</div>
</Layout>
}
export default HomePage;

View File

@ -0,0 +1,113 @@
// /**
// * Copyright (c) 2017-present, Facebook, Inc.
// *
// * This source code is licensed under the MIT license found in the
// * LICENSE file in the root directory of this source tree.
// */
// const React = require('react');
// const CompLibrary = require('../../core/CompLibrary');
// const Container = CompLibrary.Container;
// const CWD = process.cwd();
// const versions = require(`${CWD}/versions.json`);
// function Versions(props) {
// const {config: siteConfig} = props;
// const latestVersion = versions[0];
// const repoUrl = `${siteConfig.repoUrl}`;
// return (
// <div className="docMainWrapper wrapper">
// <Container className="mainContainer versionsContainer">
// <div className="post">
// <header className="postHeader">
// <h1>{siteConfig.title} Versions </h1>
// </header>
// <h3 id="latest">Current version</h3>
// <table className="versions">
// <tbody>
// <tr>
// <th>{latestVersion}</th>
// <td>
// {/* You are supposed to change this href where appropriate
// Example: href="<baseUrl>/docs(/:language)/:id" */}
// <a
// href={`${siteConfig.baseUrl}${siteConfig.docsUrl}/${
// props.language ? props.language + '/' : ''
// }intro/installation`}>
// Documentation
// </a>
// </td>
// <td>
// <a href={repoUrl}>Source Code</a>
// </td>
// {/* <td>
// <a href="">Release Notes</a>
// </td> */}
// </tr>
// </tbody>
// </table>
// <h3 id="rc">Pre-release versions</h3>
// <table className="versions">
// <tbody>
// <tr>
// <th>next</th>
// <td>
// {/* You are supposed to change this href where appropriate
// Example: href="<baseUrl>/docs(/:language)/next/:id" */}
// <a
// href={`${siteConfig.baseUrl}${siteConfig.docsUrl}/${
// props.language ? props.language + '/' : ''
// }next/intro/installation`}>
// Documentation
// </a>
// </td>
// <td>
// <a href={repoUrl}>Source Code</a>
// </td>
// </tr>
// </tbody>
// </table>
// <h3 id="archive">Past Versions</h3>
// <p>Here you can find previous versions of the documentation.</p>
// <table className="versions">
// <tbody>
// {versions.map(
// version =>
// version !== latestVersion && version !== "next" && (
// <tr>
// <th>{version}</th>
// <td>
// {/* You are supposed to change this href where appropriate
// Example: href="<baseUrl>/docs(/:language)/:version/:id" */}
// <a
// href={`${siteConfig.baseUrl}${siteConfig.docsUrl}/${
// props.language ? props.language + '/' : ''
// }${version}/intro/installation`}>
// Documentation
// </a>
// </td>
// <td>
// <a href={`${repoUrl}/releases/tag/v${version}`}>
// Release Notes
// </a>
// </td>
// </tr>
// ),
// )}
// </tbody>
// </table>
// <p>
// You can find past versions of this project on{' '}
// <a href={repoUrl}>GitLab</a>.
// </p>
// </div>
// </Container>
// </div>
// );
// }
// module.exports = Versions;

View File

@ -0,0 +1,194 @@
/**
* Copyright (c) 2017-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
import React, {useEffect, useState, useRef} from 'react';
import classnames from 'classnames';
import Highlight, {defaultProps} from 'prism-react-renderer';
const {Prism} = require("prism-react-renderer");
Prism.languages = {
...Prism.languages,
pascaligo: {
'comment': [
/\(\*[\s\S]+?\*\)/,
// /\{[\s\S]+?\}/,
/\/\/.*/
],
'string': {
pattern: /(?:'(?:''|[^'\r\n])*'|#[&$%]?[a-f\d]+)+|\^[a-z]/i,
greedy: true
},
'keyword': [
{
// Turbo Pascal
pattern: /(^|[^&])\b(?:absolute|array|asm|begin|case|const|constructor|destructor|do|downto|else|end|file|for|function|goto|if|implementation|inherited|inline|interface|label|nil|object|of|operator|packed|procedure|program|record|reintroduce|repeat|self|set|string|then|to|type|unit|until|uses|var|while|with)\b/i,
lookbehind: true
},
{
// Free Pascal
pattern: /(^|[^&])\b(?:dispose|exit|false|new|true)\b/i,
lookbehind: true
},
{
// Object Pascal
pattern: /(^|[^&])\b(?:class|dispinterface|except|exports|finalization|finally|initialization|inline|library|on|out|packed|property|raise|resourcestring|threadvar|try)\b/i,
lookbehind: true
},
{
// Modifiers
pattern: /(^|[^&])\b(?:absolute|abstract|alias|assembler|bitpacked|break|cdecl|continue|cppdecl|cvar|default|deprecated|dynamic|enumerator|experimental|export|external|far|far16|forward|generic|helper|implements|index|interrupt|iochecks|local|message|name|near|nodefault|noreturn|nostackframe|oldfpccall|otherwise|overload|override|pascal|platform|private|protected|public|published|read|register|reintroduce|result|safecall|saveregisters|softfloat|specialize|static|stdcall|stored|strict|unaligned|unimplemented|varargs|virtual|write)\b/i,
lookbehind: true
}
],
'number': [
// Hexadecimal, octal and binary
/(?:[&%]\d+|\$[a-f\d]+)/i,
// Decimal
/\b\d+(?:\.\d+)?(?:e[+-]?\d+)?/i
],
'operator': [
/\.\.|\*\*|:=|<[<=>]?|>[>=]?|[+\-*\/]=?|[@^=]/i,
{
pattern: /(^|[^&])\b(?:and|as|div|exclude|in|include|is|mod|not|or|shl|shr|xor)\b/,
lookbehind: true
}
],
'punctuation': /\(\.|\.\)|[()\[\]:;,.]/
},
reasonligo:
{...Prism.languages.reason,
'comment': [
/(^|[^\\])\/\*[\s\S]*?\*\//,
/\(\*[\s\S]*?\*\)/,
/\/\/.*/
]
},
cameligo: {...Prism.languages.ocaml,
'comment': [
/(^|[^\\])\/\*[\s\S]*?\*\//,
/\(\*[\s\S]*?\*\)/,
/\/\/.*/
]}
};
import defaultTheme from 'prism-react-renderer/themes/palenight';
import Clipboard from 'clipboard';
import rangeParser from 'parse-numeric-range';
import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
import useThemeContext from '@theme/hooks/useThemeContext';
import styles from './styles.module.css';
const highlightLinesRangeRegex = /{([\d,-]+)}/;
export default ({children, className: languageClassName, metastring}) => {
const {
siteConfig: {
themeConfig: {prism = {}},
},
} = useDocusaurusContext();
const [showCopied, setShowCopied] = useState(false);
const [mounted, setMounted] = useState(false);
// The Prism theme on SSR is always the default theme but the site theme
// can be in a different mode. React hydration doesn't update DOM styles
// that come from SSR. Hence force a re-render after mounting to apply the
// current relevant styles. There will be a flash seen of the original
// styles seen using this current approach but that's probably ok. Fixing
// the flash will require changing the theming approach and is not worth it
// at this point.
useEffect(() => {
setMounted(true);
}, []);
const target = useRef(null);
const button = useRef(null);
let highlightLines = [];
const {isDarkTheme} = useThemeContext();
const lightModeTheme = prism.theme || defaultTheme;
const darkModeTheme = prism.darkTheme || lightModeTheme;
const prismTheme = isDarkTheme ? darkModeTheme : lightModeTheme;
if (metastring && highlightLinesRangeRegex.test(metastring)) {
const highlightLinesRange = metastring.match(highlightLinesRangeRegex)[1];
highlightLines = rangeParser.parse(highlightLinesRange).filter(n => n > 0);
}
useEffect(() => {
let clipboard;
if (button.current) {
clipboard = new Clipboard(button.current, {
target: () => target.current,
});
}
return () => {
if (clipboard) {
clipboard.destroy();
}
};
}, [button.current, target.current]);
let language =
languageClassName && languageClassName.replace(/language-/, '');
if (!language && prism.defaultLanguage) {
language = prism.defaultLanguage;
}
const handleCopyCode = () => {
window.getSelection().empty();
setShowCopied(true);
setTimeout(() => setShowCopied(false), 2000);
};
return (
<Highlight
{...defaultProps}
key={mounted}
theme={prismTheme}
code={children.trim()}
language={language}>
{({className, style, tokens, getLineProps, getTokenProps}) => (
<pre className={classnames(className, styles.codeBlock)}>
<button
ref={button}
type="button"
aria-label="Copy code to clipboard"
className={styles.copyButton}
onClick={handleCopyCode}>
{showCopied ? 'Copied' : 'Copy'}
</button>
<code ref={target} className={styles.codeBlockLines} style={style}>
{tokens.map((line, i) => {
if (line.length === 1 && line[0].content === '') {
line[0].content = '\n'; // eslint-disable-line no-param-reassign
}
const lineProps = getLineProps({line, key: i});
if (highlightLines.includes(i + 1)) {
lineProps.className = `${lineProps.className} docusaurus-highlight-code-line`;
}
return (
<div key={i} {...lineProps}>
{line.map((token, key) => (
<span key={key} {...getTokenProps({token, key})} />
))}
</div>
);
})}
</code>
</pre>
)}
</Highlight>
);
};

View File

@ -0,0 +1,45 @@
/**
* Copyright (c) 2017-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
.codeBlock {
overflow: auto;
display: block;
padding: 0;
margin: 0;
}
.copyButton {
background: rgb(1, 22, 39);
border: 1px solid rgb(214, 222, 235);
border-radius: var(--ifm-global-radius);
color: rgb(214, 222, 235);
cursor: pointer;
line-height: 12px;
opacity: 0;
outline: none;
padding: 4px 8px;
position: absolute;
right: var(--ifm-pre-padding);
top: var(--ifm-pre-padding);
visibility: hidden;
transition: opacity 200ms ease-in-out, visibility 200ms ease-in-out,
bottom 200ms ease-in-out;
}
.codeBlock:hover > .copyButton {
visibility: visible;
opacity: 1;
}
.codeBlockLines {
background-color: transparent;
border-radius: 0;
margin-bottom: 0;
float: left;
min-width: 100%;
padding: var(--ifm-pre-padding);
}

View File

@ -0,0 +1,80 @@
/**
* Copyright (c) 2017-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
import React, { useState } from 'react';
import {MDXProvider} from '@mdx-js/react';
import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
import renderRoutes from '@docusaurus/renderRoutes';
import Layout from '@theme/Layout';
import DocSidebar from '@theme/DocSidebar';
import MDXComponents from '@theme/MDXComponents';
import NotFound from '@theme/NotFound';
import {matchPath} from '@docusaurus/router';
import styles from './styles.module.css';
import SyntaxContext from '@theme/Syntax/SyntaxContext';
function DocPage(props) {
const {route: baseRoute, docsMetadata, location} = props;
// case-sensitive route such as it is defined in the sidebar
const currentRoute =
baseRoute.routes.find(route => {
return matchPath(location.pathname, route);
}) || {};
const {permalinkToSidebar, docsSidebars, version} = docsMetadata;
const sidebar = permalinkToSidebar[currentRoute.path];
const {
siteConfig: {themeConfig = {}} = {},
isClient,
} = useDocusaurusContext();
const {sidebarCollapsible = true} = themeConfig;
let defaultSyntax = 'pascaligo';
if (isClient) {
defaultSyntax = localStorage.getItem('syntax') || defaultSyntax
}
const [syntax, setSyntax] = useState(defaultSyntax);
if (Object.keys(currentRoute).length === 0) {
return <NotFound {...props} />;
}
return (
<Layout version={version} key={isClient}>
<SyntaxContext.Provider value={syntax}>
<div className={styles.docPage}>
{sidebar && (
<div className={styles.docSidebarContainer}>
<DocSidebar
docsSidebars={docsSidebars}
path={currentRoute.path}
sidebar={sidebar}
sidebarCollapsible={sidebarCollapsible}
syntax={syntax}
onSyntaxChange={l => {
localStorage.setItem('syntax', l);
setSyntax(l)
}}
/>
</div>
)}
<main className={styles.docMainContainer}>
<MDXProvider components={MDXComponents}>
{renderRoutes(baseRoute.routes)}
</MDXProvider>
</main>
</div>
</SyntaxContext.Provider>
</Layout>
);
}
export default DocPage;

View File

@ -0,0 +1,28 @@
/**
* Copyright (c) 2017-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
.docPage {
display: flex;
}
.docSidebarContainer {
border-right: 1px solid var(--ifm-contents-border-color);
box-sizing: border-box;
width: 300px;
position: relative;
top: calc(-1 * var(--ifm-navbar-height));
}
.docMainContainer {
flex-grow: 1;
}
@media (max-width: 996px) {
.docPage {
display: inherit;
}
}

View File

@ -0,0 +1,229 @@
/**
* Copyright (c) 2017-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
import React, {useState, useCallback} from 'react';
import classnames from 'classnames';
import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
import useBaseUrl from '@docusaurus/useBaseUrl';
import useLockBodyScroll from '@theme/hooks/useLockBodyScroll';
import Link from '@docusaurus/Link';
import isInternalUrl from '@docusaurus/utils'; // eslint-disable-line import/no-extraneous-dependencies
import styles from './styles.module.css';
import SyntaxSwitch from '../Syntax/SyntaxSwitch';
const MOBILE_TOGGLE_SIZE = 24;
function DocSidebarItem({item, onItemClick, collapsible}) {
const {items, href, label, type} = item;
const [collapsed, setCollapsed] = useState(item.collapsed);
const [prevCollapsedProp, setPreviousCollapsedProp] = useState(null);
// If the collapsing state from props changed, probably a navigation event
// occurred. Overwrite the component's collapsed state with the props'
// collapsed value.
if (item.collapsed !== prevCollapsedProp) {
setPreviousCollapsedProp(item.collapsed);
setCollapsed(item.collapsed);
}
const handleItemClick = useCallback(e => {
e.preventDefault();
setCollapsed(state => !state);
});
switch (type) {
case 'category':
return (
items.length > 0 && (
<li
className={classnames('menu__list-item', {
'menu__list-item--collapsed': collapsed,
})}
key={label}>
<a
className={classnames('menu__link', {
'menu__link--sublist': collapsible,
'menu__link--active': collapsible && !item.collapsed,
})}
href="#!"
onClick={collapsible ? handleItemClick : undefined}>
{label}
</a>
<ul className="menu__list">
{items.map(childItem => (
<DocSidebarItem
key={childItem.label}
item={childItem}
onItemClick={onItemClick}
collapsible={collapsible}
/>
))}
</ul>
</li>
)
);
case 'link':
default:
return (
<li className="menu__list-item" key={label}>
<Link
className="menu__link"
to={href}
{...(isInternalUrl(href)
? {
activeClassName: 'menu__link--active',
exact: true,
onClick: onItemClick,
}
: {
target: '_blank',
rel: 'noreferrer noopener',
})}>
{label}
</Link>
</li>
);
}
}
// Calculate the category collapsing state when a page navigation occurs.
// We want to automatically expand the categories which contains the current page.
function mutateSidebarCollapsingState(item, path) {
const {items, href, type} = item;
switch (type) {
case 'category': {
const anyChildItemsActive =
items
.map(childItem => mutateSidebarCollapsingState(childItem, path))
.filter(val => val).length > 0;
// eslint-disable-next-line no-param-reassign
item.collapsed = !anyChildItemsActive;
return anyChildItemsActive;
}
case 'link':
default:
return href === path;
}
}
function DocSidebar(props) {
const [showResponsiveSidebar, setShowResponsiveSidebar] = useState(false);
const {
siteConfig: {themeConfig: {navbar: {title, logo = {}} = {}}} = {}, isClient
} = useDocusaurusContext();
const logoUrl = useBaseUrl(logo.src);
const {
docsSidebars,
path,
sidebar: currentSidebar,
sidebarCollapsible,
} = props;
useLockBodyScroll(showResponsiveSidebar);
if (!currentSidebar) {
return null;
}
const sidebarData = docsSidebars[currentSidebar];
if (!sidebarData) {
throw new Error(
`Cannot find the sidebar "${currentSidebar}" in the sidebar config!`,
);
}
if (sidebarCollapsible) {
sidebarData.forEach(sidebarItem =>
mutateSidebarCollapsingState(sidebarItem, path),
);
}
return (
<div className={styles.sidebar}>
<div className={styles.sidebarLogo}>
{logo != null && <img src={logoUrl} alt={logo.alt} />}
{title != null && <strong>{title}</strong>}
</div>
{isClient && document.location.pathname.startsWith('/docs') && !showResponsiveSidebar ?
<div className={styles.switchContainer}>
Display syntax: <SyntaxSwitch syntax={props.syntax} onSyntaxChange={s => props.onSyntaxChange(s)} />
</div>
:
null
}
<div
className={classnames('menu', 'menu--responsive', styles.menu, {
'menu--show': showResponsiveSidebar,
})}>
{isClient && document.location.pathname.startsWith('/docs') && showResponsiveSidebar ?
<div className={styles.switchContainerResponsive}>
Display syntax:
<SyntaxSwitch syntax={props.syntax} onSyntaxChange={s => props.onSyntaxChange(s)} />
</div>
:
null
}
<button
aria-label={showResponsiveSidebar ? 'Close Menu' : 'Open Menu'}
className="button button--secondary button--sm menu__button"
type="button"
onClick={() => {
setShowResponsiveSidebar(!showResponsiveSidebar);
}}>
{showResponsiveSidebar ? (
<span
className={classnames(
styles.sidebarMenuIcon,
styles.sidebarMenuCloseIcon,
)}>
&times;
</span>
) : (
<svg
className={styles.sidebarMenuIcon}
xmlns="http://www.w3.org/2000/svg"
height={MOBILE_TOGGLE_SIZE}
width={MOBILE_TOGGLE_SIZE}
viewBox="0 0 32 32"
role="img"
focusable="false">
<title>Menu</title>
<path
stroke="currentColor"
strokeLinecap="round"
strokeMiterlimit="10"
strokeWidth="2"
d="M4 7h22M4 15h22M4 23h22"
/>
</svg>
)}
</button>
<ul className="menu__list">
{sidebarData.map(item => (
<DocSidebarItem
key={item.label}
item={item}
onItemClick={() => {
setShowResponsiveSidebar(false);
}}
collapsible={sidebarCollapsible}
/>
))}
</ul>
</div>
</div>
);
}
export default DocSidebar;

View File

@ -0,0 +1,90 @@
/**
* Copyright (c) 2017-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
@media (min-width: 997px) {
.sidebar {
height: 100vh;
overflow-y: auto;
position: sticky;
top: 0;
padding-top: var(--ifm-navbar-height);
}
.sidebar::-webkit-scrollbar {
width: 7px;
}
.sidebar::-webkit-scrollbar-track {
background: #f1f1f1;
border-radius: 10px;
}
.sidebar::-webkit-scrollbar-thumb {
background: #888;
border-radius: 10px;
}
.sidebar::-webkit-scrollbar-thumb:hover {
background: #555;
}
.sidebarLogo {
display: flex !important;
align-items: center;
position: absolute;
top: 0;
margin: 0 var(--ifm-navbar-padding-horizontal);
height: var(--ifm-navbar-height);
}
.sidebarLogo img {
margin-right: 0.5rem;
height: 2rem;
}
.menu {
padding: 0.5rem;
}
.switchContainer {
flex: 1;
display: flex;
background-color: var(--ifm-pre-background);
align-items: center;
justify-content: center;
padding: 1rem 0;
border-bottom: 1px solid var(--ifm-contents-border-color);
}
}
.switchContainerResponsive {
background-color: var(--ifm-pre-background);
flex: 1;
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
}
.sidebarLogo {
display: none;
}
.sidebarMenuIcon {
vertical-align: middle;
}
.sidebarMenuCloseIcon {
display: inline-flex;
justify-content: center;
align-items: center;
height: 24px;
font-size: 1.5rem;
font-weight: var(--ifm-font-weight-bold);
line-height: 0.9;
width: 24px;
}

View File

@ -0,0 +1,201 @@
/**
* Copyright (c) 2017-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
import React, {useCallback, useState} from 'react';
import Link from '@docusaurus/Link';
import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
import useBaseUrl from '@docusaurus/useBaseUrl';
import SearchBar from '@theme/SearchBar';
import Toggle from '@theme/Toggle';
import classnames from 'classnames';
import useThemeContext from '@theme/hooks/useThemeContext';
import useHideableNavbar from '@theme/hooks/useHideableNavbar';
import useLockBodyScroll from '@theme/hooks/useLockBodyScroll';
import styles from './styles.module.css';
function NavLink({to, href, label, position, ...props}) {
const toUrl = useBaseUrl(to);
return (
<Link
className="navbar__item navbar__link"
{...(href
? {
target: '_blank',
rel: 'noopener noreferrer',
href,
}
: {
activeClassName: 'navbar__link--active',
to: toUrl,
})}
{...props}>
{label}
</Link>
);
}
function Navbar(props) {
const context = useDocusaurusContext();
const {siteConfig = {}} = context;
const {baseUrl, themeConfig = {}} = siteConfig;
const {navbar = {}, disableDarkMode = false} = themeConfig;
const {title, logo = {}, links = [], hideOnScroll = false} = navbar;
const [sidebarShown, setSidebarShown] = useState(false);
const [isSearchBarExpanded, setIsSearchBarExpanded] = useState(false);
const {isDarkTheme, setLightTheme, setDarkTheme} = useThemeContext();
const {navbarRef, isNavbarVisible} = useHideableNavbar(hideOnScroll);
useLockBodyScroll(sidebarShown);
const showSidebar = useCallback(() => {
setSidebarShown(true);
}, [setSidebarShown]);
const hideSidebar = useCallback(() => {
setSidebarShown(false);
}, [setSidebarShown]);
const onToggleChange = useCallback(
e => (e.target.checked ? setDarkTheme() : setLightTheme()),
[setLightTheme, setDarkTheme],
);
const logoLink = logo.href || baseUrl;
const isExternalLogoLink = /http/.test(logoLink);
const logoLinkProps = isExternalLogoLink
? {
rel: 'noopener noreferrer',
target: '_blank',
}
: null;
const logoSrc = logo.srcDark && isDarkTheme ? logo.srcDark : logo.src;
const logoImageUrl = useBaseUrl(logoSrc);
return (
<nav
ref={navbarRef}
className={classnames('navbar', 'navbar--light', 'navbar--fixed-top', {
'navbar-sidebar--show': sidebarShown,
[styles.navbarHideable]: hideOnScroll,
[styles.navbarHidden]: !isNavbarVisible,
})}>
<div className="navbar__inner">
<div className="navbar__items">
<div
aria-label="Navigation bar toggle"
className="navbar__toggle"
role="button"
tabIndex={0}
onClick={showSidebar}
onKeyDown={showSidebar}>
<svg
xmlns="http://www.w3.org/2000/svg"
width="30"
height="30"
viewBox="0 0 30 30"
role="img"
focusable="false">
<title>Menu</title>
<path
stroke="currentColor"
strokeLinecap="round"
strokeMiterlimit="10"
strokeWidth="2"
d="M4 7h22M4 15h22M4 23h22"
/>
</svg>
</div>
<Link className="navbar__brand" to={logoLink} {...logoLinkProps}>
{logo != null && (
<img className="navbar__logo" src={logoImageUrl} alt={logo.alt} />
)}
{title != null && (
<strong
className={isSearchBarExpanded ? styles.hideLogoText : ''}>
{title}
</strong>
)}
</Link>
{links
.filter(linkItem => linkItem.position !== 'right')
.map((linkItem, i) => (
<NavLink {...linkItem} key={i} />
))}
</div>
<div className="navbar__items navbar__items--right">
{links
.filter(linkItem => linkItem.position === 'right')
.map((linkItem, i) => (
<NavLink {...linkItem} key={i} />
))}
{!disableDarkMode && (
<Toggle
className={styles.displayOnlyInLargeViewport}
aria-label="Dark mode toggle"
checked={isDarkTheme}
onChange={onToggleChange}
/>
)}
<SearchBar
handleSearchBarToggle={setIsSearchBarExpanded}
isSearchBarExpanded={isSearchBarExpanded}
/>
</div>
</div>
<div
role="presentation"
className="navbar-sidebar__backdrop"
onClick={hideSidebar}
/>
<div className="navbar-sidebar">
<div className="navbar-sidebar__brand">
<Link
className="navbar__brand"
onClick={hideSidebar}
to={logoLink}
{...logoLinkProps}>
{logo != null && (
<img className="navbar__logo" src={logoImageUrl} alt={logo.alt} />
)}
{title != null && <strong>{title}</strong>}
</Link>
{!disableDarkMode && sidebarShown && (
<Toggle
aria-label="Dark mode toggle in sidebar"
checked={isDarkTheme}
onChange={onToggleChange}
/>
)}
</div>
<div className="navbar-sidebar__items">
<div className="menu">
<ul className="menu__list">
{links.map((linkItem, i) => (
<li className="menu__list-item" key={i}>
<NavLink
className="menu__link"
{...linkItem}
onClick={hideSidebar}
/>
</li>
))}
</ul>
</div>
</div>
</div>
</nav>
);
}
export default Navbar;

View File

@ -0,0 +1,26 @@
/**
* Copyright (c) 2017-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
@media screen and (max-width: 997px) {
.displayOnlyInLargeViewport {
display: none !important;
}
}
@media (max-width: 360px) {
.hideLogoText {
display: none;
}
}
.navbarHideable {
transition: top 0.2s ease-in-out;
}
.navbarHidden {
top: calc(var(--ifm-navbar-height) * -1) !important;
}

View File

@ -0,0 +1,6 @@
import React from 'react';
const SyntaxContext = React.createContext('pascaligo');
export default SyntaxContext;

View File

@ -0,0 +1,15 @@
import React from 'react';
import styles from './styles.module.css';
function SyntaxSwitch (props) {
return (
<select className={styles.syntaxSwitch} defaultValue={props.syntax} onChange={e => props.onSyntaxChange(e.target.value)}>
<option value="pascaligo">PascaLIGO</option>
<option value="cameligo">CameLIGO</option>
<option value="reasonligo">ReasonLIGO</option>
</select>
)
}
export default SyntaxSwitch

View File

@ -0,0 +1,18 @@
import React from 'react';
import SyntaxContext from './SyntaxContext'
function Syntax(props) {
return (
<SyntaxContext.Consumer>
{(syntax => {
if (syntax === props.syntax) {
return props.children
} else {
return <></>
}
})}
</SyntaxContext.Consumer>
)
}
export default Syntax

View File

@ -0,0 +1,37 @@
.syntaxSwitch {
display: block;
font-size: 1rem;
font-weight: bold;
line-height: 1rem;
padding: .6em 1.4em .5em .8em;
box-sizing: border-box;
border: none;
color: var(--color-primary-text);
-moz-appearance: none;
-webkit-appearance: none;
appearance: none;
background-color: transparent;
background-image: url('data:image/svg+xml;charset=US-ASCII,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22292.4%22%20height%3D%22292.4%22%3E%3Cpath%20fill%3D%22%23007CB2%22%20d%3D%22M287%2069.4a17.6%2017.6%200%200%200-13-5.4H18.4c-5%200-9.3%201.8-12.9%205.4A17.6%2017.6%200%200%200%200%2082.2c0%205%201.8%209.3%205.4%2012.9l128%20127.9c3.6%203.6%207.8%205.4%2012.8%205.4s9.2-1.8%2012.8-5.4L287%2095c3.5-3.5%205.4-7.8%205.4-12.8%200-5-1.9-9.2-5.5-12.8z%22%2F%3E%3C%2Fsvg%3E');
background-repeat: no-repeat, repeat;
background-position: right .7em top 50%, 0 0;
background-size: .65em auto, 100%;
}
.syntaxSwitch::-ms-expand {
display: none;
}
.syntaxSwitch:hover {
border-color: #888;
}
.syntaxSwitch:focus {
border-color: #aaa;
box-shadow: 0 0 1px 3px rgba(59, 153, 252, .7);
box-shadow: 0 0 0 3px -moz-mac-focusring;
color: var(--color-primary-text);
outline: none;
}
.syntaxSwitch option {
color: var(--color-primary-text);
font-weight:normal;
}

View File

@ -1,5 +1,28 @@
@import url('/fonts/inter.css');
:root {
--ifm-color-primary: #0e74ff;
--ifm-color-primary-dark: rgb(33, 175, 144);
--ifm-color-primary-darker: rgb(31, 165, 136);
--ifm-color-primary-darkest: rgb(26, 136, 112);
--ifm-color-primary-light: rgb(70, 203, 174);
--ifm-color-primary-lighter: rgb(102, 212, 189);
--ifm-color-primary-lightest: #92e0d0;
--blockquote-color: #efefef;
--ifm-code-font-size: .9rem;
/* header */
--ifm-navbar-link-hover-color: #0e74ff;
/* footer */
--ifm-footer-title-color: #fff;
--ifm-footer-background-color: #0d0f33;
--ifm-footer-link-hover-color: hsla(0,0%,100%,.6);
--ifm-footer-color: #fff;
}
:root { :root {
--primary-brand-color: #0e74ff;
--secondary-brand-color: #fc683a; --secondary-brand-color: #fc683a;
--blue: #3aa0ff; --blue: #3aa0ff;
--lighter-blue: #e1f1ff; --lighter-blue: #e1f1ff;
@ -24,12 +47,19 @@
--padding-level-6: 100px; --padding-level-6: 100px;
} }
html[data-theme='dark'] {
--color-primary-text: white;
--blockquote-color: var(--ifm-navbar-background-color);
}
html { html {
font-size: 16px; font-size: 16px;
} }
body { body {
font-family: 'Open Sans', sans-serif; font-family: 'Open Sans', sans-serif;
font-family: 'Inter var',SF Pro Text,Roboto,-apple-system,BlinkMacSystemFont,Helvetica Neue,Arial,sans-serif;
font-weight: 400;
font-size: 1rem; font-size: 1rem;
color: var(--color-primary-text); color: var(--color-primary-text);
margin: 0 auto; margin: 0 auto;
@ -39,8 +69,8 @@ body {
* Docusaurus overrides * Docusaurus overrides
*/ */
code { code {
font-family: 'Source Code Pro', monospace; /* font-family: 'Source Code Pro', monospace; */
background: var(--light-blue); font-family: Menlo,Roboto Mono,SFMono-Regular,Segoe UI,Courier,monospace;
margin-left: 2px; margin-left: 2px;
margin-right: 2px; margin-right: 2px;
border-radius: 2px; border-radius: 2px;
@ -66,7 +96,6 @@ h1 {
} }
h2 { h2 {
font-size: 2.25rem;
margin-bottom: 0.5rem; margin-bottom: 0.5rem;
margin-top: 1.5rem; margin-top: 1.5rem;
} }
@ -182,7 +211,7 @@ p {
.navigationSlider .slidingNav ul li.siteNavItemActive > a, .navigationSlider .slidingNav ul li.siteNavItemActive > a,
.navigationSlider .slidingNav ul li.siteNavGroupActive > a { .navigationSlider .slidingNav ul li.siteNavGroupActive > a {
background-color: white; background-color: white;
color: var(--primary-brand-color) !important; color: var(--ifm-color-primary) !important;
} }
.navSearchWrapper:before { .navSearchWrapper:before {
@ -249,7 +278,7 @@ p {
} }
blockquote { blockquote {
background-color: #efefef; background-color: var(--blockquote-color);
border-left: 5px solid var(--color-primary-text); border-left: 5px solid var(--color-primary-text);
color: var(--color-primary-text); color: var(--color-primary-text);
border-radius: 2px; border-radius: 2px;
@ -257,12 +286,11 @@ blockquote {
blockquote code { blockquote code {
opacity: 1; opacity: 1;
background: var(--light-blue);
} }
a, a,
a:hover { a:hover {
color: var(--primary-brand-color); color: var(--ifm-color-primary);
} }
.docMainWrapper a:hover { .docMainWrapper a:hover {
@ -333,7 +361,7 @@ a:hover {
} }
.navListItemActive a { .navListItemActive a {
color: var(--primary-brand-color) !important; color: var(--ifm-color-primary) !important;
} }
.onPageNav > .toc-headings { .onPageNav > .toc-headings {
@ -366,7 +394,7 @@ a:hover {
.button:hover { .button:hover {
border-radius: 36px; border-radius: 36px;
padding: 10px 20px; padding: 10px 20px;
background-color: var(--primary-brand-color); background-color: var(--ifm-color-primary);
min-width: 130px; min-width: 130px;
color: var(--color-white); color: var(--color-white);
} }
@ -469,7 +497,7 @@ a:hover {
} }
.primary { .primary {
color: var(--primary-brand-color); color: var(--ifm-color-primary);
} }
.secondary { .secondary {
@ -509,10 +537,13 @@ a:hover {
#homePage #intro { #homePage #intro {
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
align-items: center;
width: 100%; width: 100%;
} }
#callToAction {
margin-top: 300px;
}
#homePage #intro #callToAction ul { #homePage #intro #callToAction ul {
padding: 0; padding: 0;
margin: 0; margin: 0;
@ -536,8 +567,8 @@ a:hover {
} }
#homePage #intro #callToAction ul li.primary:hover { #homePage #intro #callToAction ul li.primary:hover {
background-color: var(--primary-brand-color); background-color: var(--ifm-color-primary);
border-left: 4px solid var(--primary-brand-color); border-left: 4px solid var(--ifm-color-primary);
} }
#homePage #intro #callToAction ul li.secondary:hover { #homePage #intro #callToAction ul li.secondary:hover {
@ -547,11 +578,12 @@ a:hover {
#homePage #intro #callToAction ul li a { #homePage #intro #callToAction ul li a {
color: inherit; color: inherit;
text-decoration: none;
} }
#homePage #intro #preview .hljs { #homePage #intro #preview {
min-width: 700px;
min-height: 450px; min-height: 450px;
max-width: 400px
} }
#homePage #intro #preview p { #homePage #intro #preview p {
@ -559,13 +591,14 @@ a:hover {
font-size: 1.5em; font-size: 1.5em;
} }
#homePage #features { #features {
margin: 100px auto; margin: 100px auto;
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
flex: 1;
} }
#homePage #features .feature { #features .feature {
flex: 1; flex: 1;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
@ -573,46 +606,47 @@ a:hover {
text-align: center; text-align: center;
} }
#homePage #features .feature p { #features .feature p {
text-align: center; text-align: center;
font-size: 1.25em; font-size: 1.25rem;
} }
#homePage #partners { #partners {
background-color: var(--primary-brand-color); background-color: var(--ifm-color-primary);
color: white; color: white;
font-size: 2.8125em; font-size: 2.8rem;
font-weight: bold; font-weight: bold;
padding: 50px 0; padding: 50px 0;
margin-top: auto; margin-top: auto;
flex: 1;
} }
#homePage #partners .wrapper { #partners .wrapper {
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
align-items: center; align-items: center;
width: 100%; width: 100%;
} }
#homePage #partners #heading { #partners #heading {
word-wrap: break-word; word-wrap: break-word;
width: 200px; width: 200px;
line-height: 1em; line-height: 1em;
} }
#homePage #partners #list { #partners #list {
display: flex; display: flex;
} }
#homePage #partners a { #partners a {
line-height: 0; line-height: 0;
} }
#homePage #partners a + a { #partners a + a {
margin-left: 50px; margin-left: 50px;
} }
#homePage #partners img { #partners img {
height: 80px; height: 80px;
} }
@ -849,6 +883,11 @@ a:hover {
} }
@media (min-width: 1024px) { @media (min-width: 1024px) {
.row .col {
padding-left: 3rem;
padding-right: 3rem;
}
.nav-footer .footer-wrapper { .nav-footer .footer-wrapper {
max-width: 1400px; max-width: 1400px;
} }
@ -856,6 +895,9 @@ a:hover {
.nav-footer .sitemap { .nav-footer .sitemap {
max-width: 1400px; max-width: 1400px;
} }
#homePage #intro #preview {
min-width: 700px;
}
} }
@media (min-width: 1500px) { @media (min-width: 1500px) {
@ -879,7 +921,7 @@ a:hover {
#homePage #intro #preview { #homePage #intro #preview {
order: 1; order: 1;
width: 100%; min-width: 100%;
} }
#homePage #intro #preview .hljs { #homePage #intro #preview .hljs {
@ -904,20 +946,20 @@ a:hover {
margin-top: 0; margin-top: 0;
} }
#homePage #partners #heading { #partners #heading {
text-align: center; text-align: center;
word-wrap: normal; word-wrap: normal;
width: auto; width: auto;
margin-bottom: 50px; margin-bottom: 50px;
} }
#homePage #partners #list { #partners #list {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
justify-content: center; justify-content: center;
} }
#homePage #partners a + a { #partners a + a {
margin: 25px auto; margin: 25px auto;
} }
} }
@ -962,3 +1004,6 @@ a:hover {
color: #a31515; color: #a31515;
} }
.badge {
display: none;
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Some files were not shown because too many files have changed in this diff Show More