Merge
This commit is contained in:
commit
c95f4ee02c
@ -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
|
||||||
|
@ -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.
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
FROM node:8.11.4
|
FROM node:12.16
|
||||||
|
|
||||||
WORKDIR /app/website
|
WORKDIR /app/website
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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>
|
||||||
|
|
||||||
|
@ -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`
|
||||||
|
@ -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>
|
||||||
|
|
||||||
|
17
gitlab-pages/docs/advanced/src/counter.ligo
Normal file
17
gitlab-pages/docs/advanced/src/counter.ligo
Normal 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)
|
9
gitlab-pages/docs/advanced/src/functions.ligo
Normal file
9
gitlab-pages/docs/advanced/src/functions.ligo
Normal 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)
|
17
gitlab-pages/docs/advanced/src/multiple-entrypoints.ligo
Normal file
17
gitlab-pages/docs/advanced/src/multiple-entrypoints.ligo
Normal 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)
|
5
gitlab-pages/docs/advanced/src/variables.ligo
Normal file
5
gitlab-pages/docs/advanced/src/variables.ligo
Normal 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)
|
@ -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>
|
||||||
|
|
||||||
|
@ -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/> block { skip } with a + b</code></pre>|
|
|Functions (short form)|<pre><code>function add (const a : int ; const b : int) : int is<br/> block { skip } with a + b</code></pre>|
|
||||||
|Functions (long form)|<pre><code>function add (const a : int ; const b : int) : int is<br/> block { <br/> const result: int = a + b;<br/> } with result</code></pre>|
|
|Functions (long form)|<pre><code>function add (const a : int ; const b : int) : int is<br/> block { <br/> const result: int = a + b;<br/> } 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/>| Increment of int<br/>| Decrement of int</code></pre>|
|
|Variants|<pre><code>type action is<br/>| Increment of int<br/>| Decrement of int</code></pre>|
|
||||||
|Variant *(pattern)* matching|<pre><code>const a: action = Increment(5);<br/>case a of<br/>| Increment(n) -> n + 1<br/>| Decrement(n) -> n - 1<br/>end</code></pre>|
|
|Variant *(pattern)* matching|<pre><code>const a: action = Increment(5);<br/>case a of<br/>| Increment(n) -> n + 1<br/>| 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/> 10n -> 60mutez;<br/> 50n -> 30mutez;<br/> 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/> 10n -> 60mutez;<br/> 50n -> 30mutez;<br/> 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/>| Increment n -> n + 1<br/>| Decrement n -> n - 1<br/></code></pre>|
|
|Variant *(pattern)* matching|<pre><code>let a: action = Increment 5<br/>match a with<br/>| Increment n -> n + 1<br/>| Decrement n -> n - 1<br/></code></pre>|
|
||||||
|Records|<pre><code>type person = {<br/> age: int ;<br/> name: string ;<br/>}<br/><br/>let john : person = {<br/> age = 18;<br/> name = "John Doe";<br/>}<br/><br/>let name: string = john.name</code></pre>|
|
|Records|<pre><code>type person = {<br/> age: int ;<br/> name: string ;<br/>}<br/><br/>let john : person = {<br/> age = 18;<br/> 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/> (10n, 60mutez);<br/> (50n, 30mutez);<br/> (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/> (10n, 60mutez);<br/> (50n, 30mutez);<br/> (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/>| Increment(n) => n + 1<br/>| Decrement(n) => n - 1;<br/> } <br/></code></pre>|
|
|Variant *(pattern)* matching|<pre><code>let a: action = Increment(5);<br/>switch(a) {<br/>| Increment(n) => n + 1<br/>| Decrement(n) => n - 1;<br/> } <br/></code></pre>|
|
||||||
|Records|<pre><code>type person = {<br/> age: int,<br/> name: string<br/>}<br/><br/>let john : person = {<br/> age: 18,<br/> name: "John Doe"<br/>};<br/><br/>let name: string = john.name;</code></pre>|
|
|Records|<pre><code>type person = {<br/> age: int,<br/> name: string<br/>}<br/><br/>let john : person = {<br/> age: 18,<br/> 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/> (10n, 60mutez),<br/> (50n, 30mutez),<br/> (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/> (10n, 60mutez),<br/> (50n, 30mutez),<br/> (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>
|
||||||
|
@ -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
|
||||||
|
@ -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>
|
||||||
|
|
||||||
|
@ -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>
|
||||||
|
|
||||||
|
@ -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
@ -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>
|
||||||
|
|
||||||
|
@ -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.
|
||||||
|
@ -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>
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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)
|
||||||
|
@ -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)
|
||||||
|
@ -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;
|
||||||
|
@ -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
|
||||||
|
@ -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>
|
||||||
|
|
||||||
|
@ -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>
|
||||||
|
|
||||||
|
@ -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>
|
||||||
|
|
||||||
|
@ -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>
|
||||||
|
|
||||||
|
@ -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>
|
||||||
|
|
||||||
|
@ -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-->
|
|
||||||
|
|
||||||
|
@ -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>
|
||||||
|
|
||||||
|
@ -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>
|
||||||
|
|
||||||
|
@ -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>
|
||||||
|
|
||||||
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:
|
## Tezos.now
|
||||||
|
|
||||||
|
Returns the current time as a [unix timestamp](https://en.wikipedia.org/wiki/Unix_time).
|
||||||
|
|
||||||
|
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>
|
||||||
|
|
||||||
|
@ -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>
|
||||||
|
|
||||||
|
@ -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-->
|
|
||||||
|
@ -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>
|
||||||
|
|
||||||
|
@ -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>
|
||||||
|
|
||||||
|
@ -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 ownerAddress : address = "tz1TGu6TN5GSez2ndXXeDX6LgUDvLzPLqgYV"
|
||||||
const taco_kind : taco_supply = get_force(taco_kind_index, taco_shop_storage);
|
const donationAddress : address = "tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx"
|
||||||
|
|
||||||
const current_purchase_price : tez = taco_kind.max_price / taco_kind.current_stock;
|
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)
|
|
||||||
|
@ -3,179 +3,229 @@ 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
|
|
||||||
type taco_supply is record
|
|
||||||
current_stock : nat;
|
|
||||||
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) :
|
```pascaligo group=a
|
||||||
(list(operation) * taco_shop_storage) is
|
type taco_supply is record [
|
||||||
begin
|
current_stock : nat;
|
||||||
// Retrieve the taco_kind from the contract's storage
|
max_price : tez
|
||||||
const taco_kind : taco_supply = get_force(taco_kind_index, taco_shop_storage);
|
]
|
||||||
|
|
||||||
const current_purchase_price : tez = taco_kind.max_price / taco_kind.current_stock;
|
type taco_shop_storage is map (nat, taco_supply)
|
||||||
|
|
||||||
|
type return is list (operation) * taco_shop_storage
|
||||||
|
|
||||||
|
function buy_taco (const taco_kind_index : nat ; var taco_shop_storage : taco_shop_storage) : return is
|
||||||
|
block {
|
||||||
|
// Retrieve the taco_kind from the contract's storage or fail
|
||||||
|
const taco_kind : taco_supply =
|
||||||
|
case taco_shop_storage[taco_kind_index] of
|
||||||
|
Some (kind) -> kind
|
||||||
|
| None -> (failwith ("Unknown kind of taco.") : taco_supply)
|
||||||
|
end;
|
||||||
|
|
||||||
|
const current_purchase_price : tez =
|
||||||
|
taco_kind.max_price / taco_kind.current_stock;
|
||||||
|
|
||||||
if amount =/= current_purchase_price then
|
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 ownerAddress : address =
|
||||||
const taco_kind : taco_supply = get_force(taco_kind_index, taco_shop_storage);
|
("tz1TGu6TN5GSez2ndXXeDX6LgUDvLzPLqgYV" : address)
|
||||||
|
|
||||||
const current_purchase_price : tez = taco_kind.max_price / taco_kind.current_stock;
|
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:
|
||||||
- Donation transfer (10%)
|
- Donation transfer (10%)
|
||||||
- Pedro's profits (90%)
|
- Pedro's profits (90%)
|
||||||
|
@ -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
|
type return is list (operation) * taco_shop_storage
|
||||||
const taco_kind : taco_supply = get_force(taco_kind_index, taco_shop_storage);
|
|
||||||
|
function buy_taco (const taco_kind_index : nat ; var taco_shop_storage : taco_shop_storage) : return is
|
||||||
const current_purchase_price : tez = taco_kind.max_price / taco_kind.current_stock;
|
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)
|
||||||
|
@ -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
|
|
||||||
type taco_supply is record
|
|
||||||
current_stock : nat;
|
|
||||||
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
|
```pascaligo group=e
|
||||||
begin
|
type taco_supply is record [
|
||||||
// Retrieve the taco_kind from the contract's storage
|
current_stock : nat;
|
||||||
const taco_kind : taco_supply = get_force(taco_kind_index, taco_shop_storage);
|
max_price : tez
|
||||||
|
]
|
||||||
const current_purchase_price : tez = taco_kind.max_price / taco_kind.current_stock;
|
|
||||||
|
type taco_shop_storage is map (nat, taco_supply)
|
||||||
|
|
||||||
|
type return is list (operation) * taco_shop_storage
|
||||||
|
|
||||||
|
function buy_taco (const taco_kind_index : nat ; var taco_shop_storage : taco_shop_storage) : return is
|
||||||
|
block {
|
||||||
|
// Retrieve the taco_kind from the contract's storage or fail
|
||||||
|
const taco_kind : taco_supply =
|
||||||
|
case taco_shop_storage[taco_kind_index] of
|
||||||
|
Some (kind) -> kind
|
||||||
|
| None -> (failwith ("Unknown kind of taco.") : taco_supply)
|
||||||
|
end;
|
||||||
|
|
||||||
|
const current_purchase_price : tez =
|
||||||
|
taco_kind.max_price / taco_kind.current_stock;
|
||||||
|
|
||||||
if amount =/= current_purchase_price then
|
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
|
||||||
```
|
```
|
||||||
|
@ -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)
|
|
@ -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)
|
|
@ -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)
|
|
@ -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
20
gitlab-pages/website/.gitignore
vendored
Normal 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*
|
@ -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>
|
))}
|
||||||
<div id="cameligo" className="tab-pane" data-group="examples">
|
</pre>
|
||||||
<MarkdownBlock>{CAMELIGO_EXAMPLE}</MarkdownBlock>
|
)}
|
||||||
</div>
|
</Highlight>
|
||||||
<div id="reasonligo" className="tab-pane" data-group="examples">
|
</TabItem>
|
||||||
<MarkdownBlock>{REASONLIGO_EXAMPLE}</MarkdownBlock>
|
<TabItem value="cameligo">
|
||||||
</div>
|
|
||||||
</div>
|
<Highlight {...defaultProps} language="cameligo" code={CAMELIGO_EXAMPLE} theme={prismTheme}>
|
||||||
</div>
|
{({ 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>
|
||||||
|
))}
|
||||||
|
</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>
|
||||||
|
))}
|
||||||
|
</pre>
|
||||||
|
)}
|
||||||
|
</Highlight>
|
||||||
|
</TabItem>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</Tabs>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export default CodeExamples
|
@ -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;
|
||||||
|
|
||||||
|
226
gitlab-pages/website/docusaurus.config.js
Normal file
226
gitlab-pages/website/docusaurus.config.js
Normal 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;
|
@ -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"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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>
|
|
||||||
);
|
|
||||||
};
|
|
@ -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;
|
|
@ -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;
|
|
@ -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,36 +91,44 @@ 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"
|
||||||
<div id="mural">
|
style={{
|
||||||
|
display: 'flex',
|
||||||
|
justifyContent: 'stretch',
|
||||||
|
alignItems: 'stretch',
|
||||||
|
fontSize: '20px',
|
||||||
|
flexDirection: 'row'
|
||||||
|
}}>
|
||||||
|
<div id="mural">
|
||||||
<div className="column">
|
<div className="column">
|
||||||
{membersInFistColumn.map(entry => Portrait(props.config, entry))}
|
{membersInFistColumn.map(entry => Portrait(props.config, entry))}
|
||||||
</div>
|
</div>
|
||||||
<div className="offset column">
|
<div className="offset column">
|
||||||
{membersInSecondColumn.map(entry => Portrait(props.config, entry))}
|
{membersInSecondColumn.map(entry => Portrait(props.config, entry))}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="message">
|
<div id="message">
|
||||||
<div className="title">Talk to us</div>
|
<div className="title">Talk to us</div>
|
||||||
<div className="communicationOptions">
|
<div className="communicationOptions">
|
||||||
{COMMUNICATION_CHANNELS.map(entry =>
|
{COMMUNICATION_CHANNELS.map(entry =>
|
||||||
CommunicationChannel(props.config, entry)
|
CommunicationChannel(props.config, entry)
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
</div>
|
||||||
};
|
</Layout>
|
||||||
|
}
|
||||||
|
|
184
gitlab-pages/website/src/pages/index.js
Normal file
184
gitlab-pages/website/src/pages/index.js
Normal 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;
|
||||||
|
|
||||||
|
|
113
gitlab-pages/website/src/pages/versions.js.fixme
Normal file
113
gitlab-pages/website/src/pages/versions.js.fixme
Normal 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;
|
194
gitlab-pages/website/src/theme/CodeBlock/index.js
Normal file
194
gitlab-pages/website/src/theme/CodeBlock/index.js
Normal 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>
|
||||||
|
);
|
||||||
|
};
|
45
gitlab-pages/website/src/theme/CodeBlock/styles.module.css
Normal file
45
gitlab-pages/website/src/theme/CodeBlock/styles.module.css
Normal 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);
|
||||||
|
}
|
80
gitlab-pages/website/src/theme/DocPage/index.js
Normal file
80
gitlab-pages/website/src/theme/DocPage/index.js
Normal 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;
|
28
gitlab-pages/website/src/theme/DocPage/styles.module.css
Normal file
28
gitlab-pages/website/src/theme/DocPage/styles.module.css
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
229
gitlab-pages/website/src/theme/DocSidebar/index.js
Normal file
229
gitlab-pages/website/src/theme/DocSidebar/index.js
Normal 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,
|
||||||
|
)}>
|
||||||
|
×
|
||||||
|
</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;
|
90
gitlab-pages/website/src/theme/DocSidebar/styles.module.css
Normal file
90
gitlab-pages/website/src/theme/DocSidebar/styles.module.css
Normal 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;
|
||||||
|
}
|
201
gitlab-pages/website/src/theme/Navbar/index.js
Normal file
201
gitlab-pages/website/src/theme/Navbar/index.js
Normal 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;
|
26
gitlab-pages/website/src/theme/Navbar/styles.module.css
Normal file
26
gitlab-pages/website/src/theme/Navbar/styles.module.css
Normal 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;
|
||||||
|
}
|
6
gitlab-pages/website/src/theme/Syntax/SyntaxContext.js
Normal file
6
gitlab-pages/website/src/theme/Syntax/SyntaxContext.js
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
const SyntaxContext = React.createContext('pascaligo');
|
||||||
|
|
||||||
|
export default SyntaxContext;
|
||||||
|
|
15
gitlab-pages/website/src/theme/Syntax/SyntaxSwitch.js
Normal file
15
gitlab-pages/website/src/theme/Syntax/SyntaxSwitch.js
Normal 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
|
18
gitlab-pages/website/src/theme/Syntax/index.js
Normal file
18
gitlab-pages/website/src/theme/Syntax/index.js
Normal 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
|
37
gitlab-pages/website/src/theme/Syntax/styles.module.css
Normal file
37
gitlab-pages/website/src/theme/Syntax/styles.module.css
Normal 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -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,20 +278,19 @@ 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
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;
|
||||||
|
}
|
||||||
|
BIN
gitlab-pages/website/static/fonts/Inter-Black.woff
Normal file
BIN
gitlab-pages/website/static/fonts/Inter-Black.woff
Normal file
Binary file not shown.
BIN
gitlab-pages/website/static/fonts/Inter-Black.woff2
Normal file
BIN
gitlab-pages/website/static/fonts/Inter-Black.woff2
Normal file
Binary file not shown.
BIN
gitlab-pages/website/static/fonts/Inter-BlackItalic.woff
Normal file
BIN
gitlab-pages/website/static/fonts/Inter-BlackItalic.woff
Normal file
Binary file not shown.
BIN
gitlab-pages/website/static/fonts/Inter-BlackItalic.woff2
Normal file
BIN
gitlab-pages/website/static/fonts/Inter-BlackItalic.woff2
Normal file
Binary file not shown.
BIN
gitlab-pages/website/static/fonts/Inter-Bold.woff
Normal file
BIN
gitlab-pages/website/static/fonts/Inter-Bold.woff
Normal file
Binary file not shown.
BIN
gitlab-pages/website/static/fonts/Inter-Bold.woff2
Normal file
BIN
gitlab-pages/website/static/fonts/Inter-Bold.woff2
Normal file
Binary file not shown.
BIN
gitlab-pages/website/static/fonts/Inter-BoldItalic.woff
Normal file
BIN
gitlab-pages/website/static/fonts/Inter-BoldItalic.woff
Normal file
Binary file not shown.
BIN
gitlab-pages/website/static/fonts/Inter-BoldItalic.woff2
Normal file
BIN
gitlab-pages/website/static/fonts/Inter-BoldItalic.woff2
Normal file
Binary file not shown.
BIN
gitlab-pages/website/static/fonts/Inter-ExtraBold.woff
Normal file
BIN
gitlab-pages/website/static/fonts/Inter-ExtraBold.woff
Normal file
Binary file not shown.
BIN
gitlab-pages/website/static/fonts/Inter-ExtraBold.woff2
Normal file
BIN
gitlab-pages/website/static/fonts/Inter-ExtraBold.woff2
Normal file
Binary file not shown.
BIN
gitlab-pages/website/static/fonts/Inter-ExtraBoldItalic.woff
Normal file
BIN
gitlab-pages/website/static/fonts/Inter-ExtraBoldItalic.woff
Normal file
Binary file not shown.
BIN
gitlab-pages/website/static/fonts/Inter-ExtraBoldItalic.woff2
Normal file
BIN
gitlab-pages/website/static/fonts/Inter-ExtraBoldItalic.woff2
Normal file
Binary file not shown.
BIN
gitlab-pages/website/static/fonts/Inter-ExtraLight.woff
Normal file
BIN
gitlab-pages/website/static/fonts/Inter-ExtraLight.woff
Normal file
Binary file not shown.
BIN
gitlab-pages/website/static/fonts/Inter-ExtraLight.woff2
Normal file
BIN
gitlab-pages/website/static/fonts/Inter-ExtraLight.woff2
Normal file
Binary file not shown.
BIN
gitlab-pages/website/static/fonts/Inter-ExtraLightItalic.woff
Normal file
BIN
gitlab-pages/website/static/fonts/Inter-ExtraLightItalic.woff
Normal file
Binary file not shown.
BIN
gitlab-pages/website/static/fonts/Inter-ExtraLightItalic.woff2
Normal file
BIN
gitlab-pages/website/static/fonts/Inter-ExtraLightItalic.woff2
Normal file
Binary file not shown.
BIN
gitlab-pages/website/static/fonts/Inter-Italic.woff
Normal file
BIN
gitlab-pages/website/static/fonts/Inter-Italic.woff
Normal file
Binary file not shown.
BIN
gitlab-pages/website/static/fonts/Inter-Italic.woff2
Normal file
BIN
gitlab-pages/website/static/fonts/Inter-Italic.woff2
Normal file
Binary file not shown.
BIN
gitlab-pages/website/static/fonts/Inter-Light.woff
Normal file
BIN
gitlab-pages/website/static/fonts/Inter-Light.woff
Normal file
Binary file not shown.
BIN
gitlab-pages/website/static/fonts/Inter-Light.woff2
Normal file
BIN
gitlab-pages/website/static/fonts/Inter-Light.woff2
Normal file
Binary file not shown.
BIN
gitlab-pages/website/static/fonts/Inter-LightItalic.woff
Normal file
BIN
gitlab-pages/website/static/fonts/Inter-LightItalic.woff
Normal file
Binary file not shown.
BIN
gitlab-pages/website/static/fonts/Inter-LightItalic.woff2
Normal file
BIN
gitlab-pages/website/static/fonts/Inter-LightItalic.woff2
Normal file
Binary file not shown.
BIN
gitlab-pages/website/static/fonts/Inter-Medium.woff
Normal file
BIN
gitlab-pages/website/static/fonts/Inter-Medium.woff
Normal file
Binary file not shown.
BIN
gitlab-pages/website/static/fonts/Inter-Medium.woff2
Normal file
BIN
gitlab-pages/website/static/fonts/Inter-Medium.woff2
Normal file
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user