Revert "Merge with dev"

This reverts commit 6ffe220d928dc3137496bcea0cc0f4d72edc2846.
This commit is contained in:
Matej Šima 2019-11-07 23:19:27 +00:00 committed by John David Pressman
parent 73919e3a5c
commit 628d818163
62 changed files with 2330 additions and 566 deletions

View File

@ -0,0 +1,114 @@
---
id: entrypoints-contracts
title: Entrypoints, Contracts
---
## Entrypoints
Each LIGO smart contract is essentially a single function, that has the following *(pseudo)* type signature:
<!--DOCUSAURUS_CODE_TABS-->
<!--Pascaligo-->
```
(const parameter: my_type, const store: my_store_type): (list(operation), my_store_type)
```
<!--END_DOCUSAURUS_CODE_TABS-->
This means that every smart contract needs at least one entrypoint function, here's an example:
> 💡 The contract below literally does *nothing*
<!--DOCUSAURUS_CODE_TABS-->
<!--Pascaligo-->
```
type parameter is unit;
type store is unit;
function main(const parameter: parameter; const store: store): (list(operation) * store) is
block { skip } with ((nil : list(operation)), store)
```
<!--END_DOCUSAURUS_CODE_TABS-->
Each entrypoint function receives two arguments:
- `parameter` - this is the parameter received in the invocation operation
- `storage` - this is the current (real) on-chain storage value
Storage can only be modified by running the smart contract entrypoint, which is responsible for returning a list of operations, and a new storage at the end of it's execution.
## Built-in contract variables
Each LIGO smart contract deployed on the Tezos blockchain, has access to certain built-in variables/constants that can be used to determine a range
of useful things. In this section you'll find how those built-ins can be utilized.
### Accepting/declining money in a smart contract
This example shows how `amount` and `failwith` can be used to decline a transaction that sends more tez than `0mutez`.
<!--DOCUSAURUS_CODE_TABS-->
<!--Pascaligo-->
```
function main (const p : unit ; const s : unit) : (list(operation) * unit) is
block {
if amount > 0mutez then failwith("This contract does not accept tez") else skip
} with ((nil : list(operation)), unit);
```
<!--END_DOCUSAURUS_CODE_TABS-->
### Access control locking
This example shows how `sender` or `source` can be used to deny access to an entrypoint.
<!--DOCUSAURUS_CODE_TABS-->
<!--Pascaligo-->
```
const owner: address = ("tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx": address);
function main (const p : unit ; const s : unit) : (list(operation) * unit) is
block {
if source =/= owner then failwith("This address can't call the contract") else skip
} with ((nil : list(operation)), unit);
```
<!--END_DOCUSAURUS_CODE_TABS-->
### Cross contract calls
This example shows how a contract can invoke another contract by emiting a transaction operation at the end of an entrypoint.
> The same technique can be used to transfer tez to an implicit account (tz1, ...), all you have to do is use `unit` instead of a parameter for a smart contract.
In our case, we have a `counter.ligo` contract that accepts a parameter of type `action`, and we have a `proxy.ligo` contract that accepts the same parameter type, and forwards the call to the deployed counter contract.
<!--DOCUSAURUS_CODE_TABS-->
<!--Pascaligo-->
```
// counter.types.ligo
type action is
| Increment of int
| Decrement of int
| Reset of unit
```
```
// counter.ligo
type action is
| Increment of int
| Decrement of int
| Reset of unit
```
```
// proxy.ligo
#include "counter.types.ligo"
const address: address = ("KT19wgxcuXG9VH4Af5Tpm1vqEKdaMFpznXT3": address);
function proxy(const param: action; const store: unit): (list(operation) * unit)
is block {
const counter: contract(action) = get_contract(address);
// re-use the param passed to the proxy in the subsequent transaction
// e.g.:
// const mockParam: action = Increment(5);
const op: operation = transaction(param, 0mutez, counter);
const opList: list(operation) = list op; end;
} with (opList, store)
```
<!--END_DOCUSAURUS_CODE_TABS-->

View File

@ -0,0 +1,152 @@
---
id: first-contract
title: First contract
---
So far so good, we've learned enough of the LIGO language, we're confident enough to write out first smart contract.
We'll be implementing a counter contract, let's go.
## Dry-running a contract
Testing a contract can be quite easy if we utilize LIGO's built-in dry run feature. Dry-run works by simulating the entrypoint execution, as if it were deployed on a real chain. You need to provide the following:
- `file` - contract to run
- `entrypoint` - name of the function to execute
- `parameter` - parameter passed to the entrypoint (in a theoretical invocation operation)
- `storage` - a mock storage value, as if it were stored on a real chain
Here's a full example:
<!--DOCUSAURUS_CODE_TABS-->
<!--Pascaligo-->
```
ligo dry-run src/basic.ligo main Unit Unit
// Outputs:
// tuple[ list[]
// Unit
// ]
```
<!--END_DOCUSAURUS_CODE_TABS-->
Output of the `dry-run` is the return value of our entrypoint function, we can see the operations emited - in our case an empty list, and the new storage value being returned - which in our case is still `Unit`.
## Building a counter contract
Our counter contract will store a single `int` as it's storage, and will accept an `action` variant in order to re-route our single `main` entrypoint into two entrypoints for `addition` and `subtraction`.
<!--DOCUSAURUS_CODE_TABS-->
<!--Pascaligo-->
```
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)
```
<!--END_DOCUSAURUS_CODE_TABS-->
To dry-run the counter contract, we will use the `main` entrypoint, provide a variant parameter of `Increment(5)` and an initial storage value of `5`.
<!--DOCUSAURUS_CODE_TABS-->
<!--Pascaligo-->
```
ligo dry-run src/counter.ligo main "Increment(5)" 5
// tuple[ list[]
// 10
// ]
```
<!--END_DOCUSAURUS_CODE_TABS-->
Yay, our contract's storage has been successfuly incremented to `10`.
## Deploying and interacting with a contract on a live-chain
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 `compile-contract` CLI command:
<!--DOCUSAURUS_CODE_TABS-->
<!--Pascaligo-->
```
ligo compile-contract src/counter.ligo main
```
<!--END_DOCUSAURUS_CODE_TABS-->
Command above will output the following Michelson code:
<!--DOCUSAURUS_CODE_TABS-->
<!--Pascaligo-->
```
{ parameter (or (int %decrement) (int %increment)) ;
storage int ;
code { DUP ;
CAR ;
DIP { DUP } ;
SWAP ;
CDR ;
DIP { DUP } ;
SWAP ;
IF_LEFT
{ DUP ;
DIP 2 { DUP } ;
DIG 2 ;
DIP { DUP } ;
SUB ;
SWAP ;
DROP ;
SWAP ;
DROP }
{ DUP ;
DIP 2 { DUP } ;
DIG 2 ;
DIP { DUP } ;
ADD ;
SWAP ;
DROP ;
SWAP ;
DROP } ;
NIL operation ;
PAIR ;
SWAP ;
DROP ;
SWAP ;
DROP ;
SWAP ;
DROP } }
```
<!--END_DOCUSAURUS_CODE_TABS-->
However in order to originate a Michelson contract on Tezos, we also need to provide the initial storage value, we can use `compile-storage` to compile the LIGO representation of the storage to Michelson.
<!--DOCUSAURUS_CODE_TABS-->
<!--Pascaligo-->
```
ligo compile-storage src/counter.ligo main 5
// Outputs: 5
```
<!--END_DOCUSAURUS_CODE_TABS-->
In our case the LIGO storage value maps 1:1 to it's Michelson representation, however this will not be the case once the parameter is of a more complex data type, like a record.
## Invoking a LIGO contract
Same rules apply for parameters, as apply for translating LIGO storage values to Michelson. We will need to use `compile-parameter` to compile our `action` variant into Michelson, here's how:
<!--DOCUSAURUS_CODE_TABS-->
<!--Pascaligo-->
```
ligo compile-parameter src/counter.ligo main 'Increment(5)'
// Outputs: (Right 5)
```
<!--END_DOCUSAURUS_CODE_TABS-->
Now we can use `(Right 5)` which is a Michelson value, to invoke our contract - e.g. via `tezos-client`

View File

@ -0,0 +1,4 @@
function main (const p : unit ; const s : unit) : (list(operation) * unit) is
block {
if amount > 0mutez then failwith("This contract does not accept tez") else skip
} with ((nil : list(operation)), unit);

View File

@ -0,0 +1,5 @@
const owner: address = ("tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx": address);
function main (const p : unit ; const s : unit) : (list(operation) * unit) is
block {
if source =/= owner then failwith("This address can't call the contract") else skip
} with ((nil : list(operation)), unit);

View File

@ -0,0 +1,9 @@
#include "counter.types.ligo"
function counter (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
| Reset(n) -> 0
end)

View File

@ -0,0 +1,4 @@
type action is
| Increment of int
| Decrement of int
| Reset of unit

View File

@ -0,0 +1,14 @@
#include "counter.types.ligo"
// Replace the following address with your deployed counter contract address
const address: address = ("KT19wgxcuXG9VH4Af5Tpm1vqEKdaMFpznXT3": address);
function proxy(const param: action; const store: unit): (list(operation) * unit)
is block {
const counter: contract(action) = get_contract(address);
// re-use the param passed to the proxy in the subsequent transaction
// e.g.:
// const mockParam: action = Increment(5);
const op: operation = transaction(param, 0mutez, counter);
const opList: list(operation) = list op; end;
} with (opList, store)

View File

@ -0,0 +1,9 @@
const today: timestamp = now;
const one_day: int = 86400;
const in_24_hrs: timestamp = today + one_day;
const today: timestamp = now;
const one_day: int = 86400;
const a_24_hrs_ago: timestamp = today - one_day;
const not_tommorow: bool = (now = in_24_hrs)

View File

@ -0,0 +1,69 @@
---
id: timestamps-addresses
title: Timestamps, Addresses
---
## Timestamps
Timestamps in LIGO, or in Michelson in general are available in smart contracts, while bakers baking the block (including the transaction in a block) are responsible for providing the given current timestamp for the contract.
### Current time
You can obtain the current time using the built-in syntax specific expression, please be aware that it's up to the baker to set the current timestamp value.
<!--DOCUSAURUS_CODE_TABS-->
<!--Pascaligo-->
```pascaligo
const today: timestamp = now;
```
<!--END_DOCUSAURUS_CODE_TABS-->
### Timestamp arithmetic
In LIGO, timestamps can be added with `int`(s), this enables you to set e.g. time constraints for your smart contracts like this:
#### In 24 hours
<!--DOCUSAURUS_CODE_TABS-->
<!--Pascaligo-->
```pascaligo
const today: timestamp = now;
const one_day: int = 86400;
const in_24_hrs: timestamp = today + one_day;
```
<!--END_DOCUSAURUS_CODE_TABS-->
#### 24 hours ago
<!--DOCUSAURUS_CODE_TABS-->
<!--Pascaligo-->
```pascaligo
const today: timestamp = now;
const one_day: int = 86400;
const 24_hrs_ago: timestamp = today - one_day;
```
<!--END_DOCUSAURUS_CODE_TABS-->
### Comparing timestamps
You can also compare timestamps using the same comparison operators as for numbers:
<!--DOCUSAURUS_CODE_TABS-->
<!--Pascaligo-->
```pascaligo
const not_tommorow: bool = (now = in_24_hrs)
```
<!--END_DOCUSAURUS_CODE_TABS-->
## Addresses
`address` is a LIGO datatype used for Tezos addresses (tz1, tz2, tz3, KT1, ...).
Here's how you can define an address:
<!--DOCUSAURUS_CODE_TABS-->
<!--Pascaligo-->
```pascaligo
const my_account: address = ("tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx": address);
```
<!--END_DOCUSAURUS_CODE_TABS-->

View File

@ -6,15 +6,15 @@ title: Documentation and releases
## Documentation
In case you'd like to contribute to the docs, you can find them at [`gitlab-pages/docs`]() in their raw markdown form.
If you'd like to contribute to the docs you can find them at [`gitlab-pages/docs`]() in raw markdown form.
Deployment of the docs/website for LIGO is taken care of within the CI, from `dev` and `master` branches.
## Releases & versioning
### Development releases (next)
Development releases of Ligo are tagged as `next` and are built with each commit to the `dev` branch. Both the docker image & the website are published automatically.
Development releases of Ligo are tagged `next` and are built with each commit to the `dev` branch. Both the docker image & the website are published automatically.
### Stable releases
Releases tagged with version numbers `x.x.x` are built manually, both docs & the docker image. While deployment of the website is handled by the CI.
Releases tagged with version numbers `x.x.x` are built manually, both docs & the docker image. Deployment of the website is handled by the CI.

View File

@ -4,37 +4,46 @@ title: Getting started
---
## Where
As weve seen, LIGO is big, as such, it is easier to start focus on a specific part of LIGO. As very vague suggestions:
If you want to immediately see the result of your contributions, you might want to start with the Front-End. This is what most people will directly see of LIGO.
If you want to get into Programming Language Theory, you might want to start with the Middle-End. This is where the Type System and the Language Definition are (the closest thing so far that youll find in a research paper).
If you want to get into the nitty gritty details of compiling to special targets, youll want to focus on the Back-End.
If you want to develop tooling on top of LIGO (editor integration, for instance), youll want to look at `Ast_typed/types.ml`. This is where most information that is relevant to devs will be (for now).
If you really want to get a grasp of the whole pipeline, search for issues tagged with “Everything”, theyll have you look at multiple parts of the code base.
LIGO is big, so it is easier to focus on a specific part of LIGO. As starting suggestions:
* If you want to immediately see the result of your contributions, you might want to start with the Front-End. This is what most people will directly see of LIGO.
* If you want to get into Programming Language Theory, you might want to start with the Middle-End. This is where the Type System and the Language Definition are (the closest thing so far that youll find in a research paper).
* If you want to get into the nitty gritty details of compiling to special targets, focus on the Back-End.
* If you want to develop tooling on top of LIGO (editor integration for instance), look at `Ast_typed/types.ml`. This is where most information that is relevant to devs will be (for now).
* If you want to get a grasp of the whole pipeline, search for issues tagged with “Everything.” Theyll help you look at multiple parts of the code base.
## What
Likely, the first issues will be about:
Adding tests
Extending the languages by adding new operators
Adding tests
Refactoring
Writing documentation and tutorials for users
Adding tests
Writing internal documentation when you understand a part of the code base
>Tests are **really** important, we dont have lots of them, and mostly regression ones. This cant be stressed enough. Some features are missing not because we cant add them, but because we dont know so as no tests tell us they are missing.
The first issues will most likely be:
* Adding tests
* Extending the languages by adding new operators
* *Adding tests*
* Refactoring
* Writing documentation and tutorials for users
* **_Adding tests_**
* Writing internal documentation when you understand a part of the code base
>Tests are **really** important, we dont have lots of them, and mostly regression ones. This cant be stressed enough. Some features are missing not because we cant add them, but because we dont know as no tests tell us they are missing.
## How
Issues will be added to the Gitlab, tagged with On-boarding and Front-End / Middle-End / Back-End / Everything. If you try to tackle one issue, and you have **any** problem, please tell us, by creating a new Gitlab issue, contacting us on Riot, Discord or even by mail! Problems might include:
Installing the repository or the tools needed to work on it
OCaml weirdness
Understanding undocumented parts of the code base
Documented parts of the code base too
**Anything really**
Issues will be added to Gitlab tagged with `On-boarding and Front-End` / `Middle-End` / `Back-End` / `Everything`.
If you try to tackle an issue and you have **any** problem, please tell us by creating a new Gitlab issue, contacting us on Riot, on Discord, or even by mail!
Problems might include:
* Installing the repository or the tools needed to work on it
* OCaml weirdness
* Understanding undocumented parts of the code base
* Understanding documented parts of the code base
**Anything, really.**
---
## FAQ
### I dont know much about OCaml, where should I start? What should I have in mind?
Id suggesting going through Real World OCaml to get a feel for the language, to know what are its features, and to know what to Google when youre lost.
Beyond that, Id say, start hacking! Either on LIGOs code base, or on any personal project.
There is a Discord server if you want real-time help (which makes things go way faster than waiting for an answer on stackoverflow or looking mindlessly at the monitor).
### I dont know much about OCaml. Where should I start? What should I keep in mind?
Id suggesting going through Real World OCaml to get a feel for the language, to know its features, and to know what to Google when youre lost.
Beyond that, Id say, start hacking! Either on LIGOs code base or on any personal project.
There is a Discord server if you want real-time help (which makes things go way faster than waiting for an answer on StackOverflow or staring mindlessly at the monitor).
### I want to add [X] to LIGO! Where should I begin?
Trying to add a new feature from scratch instead of building upon one can be quite complicated. However, if youre motivated, contact us! Well tell you what we see as the most likely plan to get the result you want to achieve.
Trying to add a new feature from scratch instead of building on one can be complicated. However, if youre motivated, contact us! Well tell you what we see as the best plan to get the result you want.

View File

@ -1,72 +1,108 @@
# Testing LIGO
Adding to the LIGO test suite is one of the more accessible ways to contribute. It exposes you to the compiler structure and primitives without necessarily demanding a deep understanding of OCaml or compiler development. And you'll probably become more familiar with LIGO itself in the process, which is helpful.
Adding to the LIGO test suite is one of the most accessible ways to contribute. It exposes you to the compiler structure and primitives without demanding a deep understanding of OCaml or compiler development.
Unfortunately right now LIGO itself doesn't have a good way to do automated testing. So the tests are written in OCaml, outside of the LIGO language. Thankfully the test code is typically less demanding than the features being tested. These tests are currently contained in [src/test](https://gitlab.com/ligolang/ligo/tree/dev/src/test), but the bulk are integration tests which rely on test contracts kept in [src/test/contracts](https://gitlab.com/ligolang/ligo/tree/dev/src/test/contracts). If you're new to LIGO, reading these contracts can be a useful introduction to a given syntax. In the future we plan
Bonus: you'll become more familiar with LIGO in the process!
Tests are written in OCaml, as LIGO doesn't (yet) have a good way to do automated testing. Thankfully the test code is typically less demanding than the features being tested.
Tests are currently contained in [src/test](https://gitlab.com/ligolang/ligo/tree/dev/src/test), but most are integration tests which rely on test contracts kept in [src/test/contracts](https://gitlab.com/ligolang/ligo/tree/dev/src/test/contracts). If you're new to LIGO, reading these contracts can be a useful introduction to a particular LIGO syntax. In the future we plan
to have detailed documentation for each syntax, but at the moment we only have a reference manual for [PascaLIGO](https://gitlab.com/ligolang/ligo/blob/dev/src/passes/1-parser/pascaligo/Doc/pascaligo.md)
## How To Find Good Test Cases
Your first question is probably "If I'm not already experienced, how do I know what to test?". There's a handful of things you can do to systematically find good test cases. All of them will either get you more familiar with the LIGO code base or LIGO itself.
Your first question is probably "If I'm not already experienced, how do I know what to test?". There are a handful of things you can do to systematically find good test cases. All of them will either get you more familiar with the LIGO code base or LIGO itself.
### Extending Existing Test Cases
The fastest way to improve LIGO's test coverage is to extend existing test cases. This means considering the test cases that already exist, and thinking of things they don't cover or situations they'll fail on. A good deal of inference is required for this, but it requires minimal experience with the existing code.
The fastest way to improve LIGO's test coverage is to extend existing test cases. Consider the test cases that already exist, and think of things they don't cover or situations they'll fail in. A good deal of inference is required for this, but it requires minimal experience with the existing code.
### Studying The Parsers For Gaps In Coverage
LIGO is divided into a **front end** which handles syntax and a **backend** which optimizes and compiles a core language shared between syntaxes. You can find basic test cases for a particular LIGO syntax by studying its parser. You will find these under [src/passes/1-parser](https://gitlab.com/ligolang/ligo/tree/dev/src/passes/1-parser). One kind of useful test focuses on **coverage**, whether we have any testing at all for a particular aspect of a syntax. You can find these by carefully going over the syntax tree for a syntax (probably best read by looking at its `Parser.mly`) and comparing each branch to the test suite. While these tests are plentiful at the time of writing, they will eventually be filled in reliably as part of writing a new syntax.
LIGO is divided into two parts
- the **front end** handles syntax
- the **backend** optimizes and compiles a core language shared between syntaxes
### Creating Interesting Test Cases By Using LIGO
You can find basic test cases for a particular LIGO syntax by studying its parser. You will find the parser under [src/passes/1-parser](https://gitlab.com/ligolang/ligo/tree/dev/src/passes/1-parser).
Another kind of useful test focuses on **depth**, whether the features are put through a wide variety of complex scenarios to make sure they stand up to real world use. One of the best ways to write these
is to use LIGO for a real project. This will require some time and energy, not just to learn LIGO but to write projects complex enough to stretch the limits of what the language can do. At the same time however it will get you used to engaging with LIGO from a developers perspective, asking how things could be better or what features are underdeveloped. If your project has practical uses, you will also be contributing to the Tezos/LIGO ecosystem while you learn. Note that because LIGO is open source, in under for us to incorporate your work as a test case it needs to be licensed in a way that's compatible with LIGO.
### Two Useful Test Cases Using LIGO
#### Coverage
> whether we have any testing at all for a particular aspect of a syntax
You can find coverage tests by carefully going over the syntax tree for a syntax (probably best read by looking at its `Parser.mly`) and comparing each branch to the test suite. (These tests are plentiful at the time of writing, but they will eventually be filled in reliably as part of writing a new syntax.)
#### Depth
> features are put through a wide variety of complex scenarios to make sure they stand up to real world use
One of the best ways to find these is to use LIGO for a real project. This will require some time and energy—not just to learn LIGO but to write projects complex enough to stretch the limits of what the language can do. However, it will also get you used to engaging with LIGO from a developers perspective, asking how things could be better or what features are underdeveloped. If your project has practical use, you will also be contributing to the Tezos/LIGO ecosystem while you learn.
*Note: because LIGO is open source, in order for us to add your work as a test case it needs to be licensed in a way that's compatible with LIGO.*
### Fuzzing (Speculative)
In the future you'll be able to [use fuzzing](https://en.wikipedia.org/wiki/Fuzzing) to generate test cases for LIGO. Fuzzing is often useful for finding 'weird' bugs on code paths that humans normally wouldn't stumble into. This makes it a useful supplement to human testing.
In the future you'll be able to [use fuzzing](https://en.wikipedia.org/wiki/Fuzzing) to generate test cases for LIGO. Fuzzing is often useful for finding 'weird' bugs on code paths that humans normally wouldn't stumble onto. This makes it a useful supplement to human testing.
## Structure of LIGO Tests
LIGO's OCaml-based tests are written in [alcotest](https://github.com/mirage/alcotest/). However the tests you encounter in [src/test/integration_tests.ml](https://gitlab.com/ligolang/ligo/blob/dev/src/test/integration_tests.ml) are built on top of some abstractions, currently defined in [src/test/test_helpers.ml](https://gitlab.com/ligolang/ligo/blob/dev/src/test/test_helpers.ml). The use of these can be inferred fairly well from looking at existing tests, but lets break a few of them down for analysis. We'll first analyze a short integration test for assignment:
LIGO's OCaml-based tests are written in [alcotest](https://github.com/mirage/alcotest/). However, the tests you encounter in [src/test/integration_tests.ml](https://gitlab.com/ligolang/ligo/blob/dev/src/test/integration_tests.ml) are built on top of some abstractions, currently defined in [src/test/test_helpers.ml](https://gitlab.com/ligolang/ligo/blob/dev/src/test/test_helpers.ml). The use of these can be inferred fairly well from looking at existing tests, but let's break a few of them down for analysis.
### Assignment Test
We'll first analyze a short integration test for assignment.
let assign () : unit result =
let%bind program = type_file "./contracts/assign.ligo" in
let make_expect = fun n -> n + 1 in
expect_eq_n_int program "main" make_expect
### assign.ligo
function main (const i : int) : int is
begin
i := i + 1 ;
end with i
#### assign.ligo
function main (const i : int) : int is
begin
i := i + 1 ;
end with i
So what's going on here? We have a function which takes no arguments and returns a `unit result`. We then define two variables, a `program` which is read from disk and fed to the LIGO compiler; and a comparison function `make_expect` which takes an integer and adds one to it. Using `expect_eq_n_int` the `program`'s main function is run and compared to the result of providing the same input to `make_expect`. This gives us some flavor of what to expect from these integration tests. Notice that the `main` argument given to `expect_eq_n_int` corresponds to the name of the function in `assign.ligo`. We can see in more complex tests that we're able to pull the values of arbitrary expressions or function calls from LIGO test contracts. Consider:
What's going on here?
We have a function which takes no arguments and returns a `unit result`.
We then define two variables:
- a `program` which is read from disk and fed to the LIGO compiler
- a comparison function `make_expect` which takes an integer and adds one to it
Using `expect_eq_n_int` the `program`'s main function is run and compared to the result of the same input provided to `make_expect`. Notice that the `main` argument given to `expect_eq_n_int` corresponds to the name of the function in `assign.ligo`.
This gives us a taste of what to expect from these integration tests.
### Annotation Test
let annotation () : unit result =
let%bind program = type_file "./contracts/annotation.ligo" in
let%bind () =
expect_eq_evaluate program "lst" (e_list [])
in
let%bind () =
expect_eq_evaluate program "address" (e_address "tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx")
in
let%bind () =
expect_eq_evaluate program "address_2" (e_address "tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx")
in
ok ()
We can see in more complex tests that we're able to pull the values of arbitrary expressions or function calls from LIGO test contracts. Consider:
### annotation.ligo
const lst : list(int) = list [] ;
let annotation () : unit result =
let%bind program = type_file "./contracts/annotation.ligo" in
let%bind () =
expect_eq_evaluate program "lst" (e_list [])
in
let%bind () =
expect_eq_evaluate program "address" (e_address "tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx")
in
let%bind () =
expect_eq_evaluate program "address_2" (e_address "tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx")
in
ok ()
#### annotation.ligo
const lst : list(int) = list [] ;
const address : address = "tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx" ;
const address : address = "tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx" ;
const address_2 : address = ("tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx" : address) ;
const address_2 : address = ("tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx" : address) ;
Here what's going on is similar to the last program; `expect_eq_evaluate` runs a program and then pulls a particular named value from the final program state. For example, once the program stops running the value of `address` is `"tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx"`. The *comparison* however is made to a constructed expression. Remember that we're testing from OCaml, but the program is written and evaluated as LIGO. In order to provide a proper comparison, we convert our expected test values into LIGO expressions and data. Constructors such as `e_list` and `e_address` provide a bridge between LIGO and OCaml. Their definitions can be found in files such as [src/stages/ast_simplified/combinators.ml](https://gitlab.com/ligolang/ligo/blob/dev/src/stages/ast_simplified/combinators.ml), or using [Merlin's definition point finder](https://github.com/ocaml/merlin/wiki). These same functions are used during the simplification stage of LIGO compilation, so becoming familiar with them will help prepare you to work on the [front end](contributors/big-picture/front-end/).
What's going on is similar to the last program: `expect_eq_evaluate` runs a program and then pulls a particular named value from the final program state.
For example, once the program stops running the value of `address` is `"tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx"`. The *comparison*, however, is made to a constructed expression.
Remember that we're testing from OCaml, but the program is written and evaluated as LIGO. In order to provide a proper comparison, we convert our expected test values into LIGO expressions and data. Constructors such as `e_list` and `e_address` provide a bridge between LIGO and OCaml. Their definitions can be found in files such as [src/stages/ast_simplified/combinators.ml](https://gitlab.com/ligolang/ligo/blob/dev/src/stages/ast_simplified/combinators.ml), or using [Merlin's definition point finder](https://github.com/ocaml/merlin/wiki). These same functions are used during the simplification stage of LIGO compilation, so becoming familiar with them will help prepare you to work on the [front end](contributors/big-picture/front-end/).
## How To Write A Test For LIGO

View File

@ -3,8 +3,8 @@ id: origin
title: Origin
---
LIGO is a programming language that aims to provide developers with an uncomplicated and safer way to implement smart-contracts. LIGO is currently being implemented for the Tezos blockchain and as a result, it compiles down to Michelson - the native smart-contract language of Tezos.
LIGO is a programming language that aims to provide developers with an uncomplicated and safe way to implement smart-contracts. Since it is being implemented for the Tezos blockchain LIGO compiles to Michelson—the native smart-contract language of Tezos.
> Smart-contracts are programs that run within a blockchain network.
LIGO was initially meant to be a language for developing Marigold, on top of a hacky framework called Meta-Michelson. However, due to the attention received by the Tezos community, a decision has been put into action to develop LIGO as a standalone language that will support Tezos directly as well.
LIGO was meant to be a language for developing Marigold on top of a hacky framework called Meta-Michelson. However, due to the attention received by the Tezos community, LIGO is now a standalone language being developed to support Tezos directly.

View File

@ -3,23 +3,22 @@ id: philosophy
title: Philosophy
---
To understand LIGOs design choices, its important to get its philosophy. There are two main concerns that we have in mind when building LIGO.
To understand LIGOs design choices its important to understand its philosophy. We have two main concerns in mind while building LIGO.
## Safety
Once a smart-contract is deployed, it will likely be impossible to change it. You must get it right on the first try, and LIGO should help as much as possible. There are multiple ways to make LIGO a safer language for smart-contracts.
### Automated Testing
Automated Testing is the process through which a program will run some other program, and check that this other program behaves correctly.
Automated Testing is the process through which a program runs another program, and checks that this other program behaves correctly.
There already is a testing library for LIGO programs written in OCaml that is used to test LIGO itself. Making it accessible to users will greatly improve safety. A way to do so would be to make it accessible from within LIGO.
### Static Analysis
Static analysis is the process of having a program analyze another one.
For instance, type systems are a kind of static analysis through which it is possible to find lots of bugs. There is already a fairly simple type system in LIGO, and we plan to make it much stronger.
For instance, type systems are a kind of static analysis through which it is possible to find lots of bugs. LIGO already has a simple type system, and we plan to make it much stronger.
### Conciseness
Writing less code gives you less room to introduce errors and that's why LIGO encourages writing lean rather than chunky smart-contracts.
Writing less code gives you less room to introduce errors. That's why LIGO encourages writing lean rather than chunky smart-contracts.
---

View File

@ -0,0 +1,12 @@
---
id: editor-support
title: Editor Support
---
Painters need a brush and a canvas. Developers need a good IDE experience. LIGO currently offers support for [VSCode](https://code.visualstudio.com), including syntax highlighting and on-the-fly compilation error reporting.
Available extensions:
- **[Syntax highlighting for PascaLIGO](https://marketplace.visualstudio.com/items?itemName=LigoLang.pascaligo-vscode)**
- **[On-the-fly compilation error reporting](https://marketplace.visualstudio.com/items?itemName=Ligo.ligo-tools)**
![error reporting](/img/docs/intro/editor-support/error-reporting.png)

View File

@ -3,19 +3,20 @@ id: installation
title: Installation
---
There are currently two ways to get started with Ligo. You can choose to either use a Docker image, or to install packages for your Debian Linux distribution.
There are currently two ways to get started with Ligo. You can choose to use a Docker image, or to install packages for your Debian Linux distribution.
## Dockerized installation (recommended)
> 🐳 You can find instructions on how to install Docker [here](https://docs.docker.com/install/).
It's easiest to use LIGO through one of its Docker images. You have two options,
the first is to use our installation script to set up a globally available LIGO
executable (see below). This manages the Docker bits for you. The second
is to directly use the Docker image available at [Docker Hub](https://hub.docker.com/r/ligolang/ligo).
It's easiest to use LIGO through one of its Docker images. You have two options:
* Use our installation script to set up a globally available LIGO
executable (see below). This manages the Docker bits for you.
* Use the Docker image available at [Docker Hub](https://hub.docker.com/r/ligolang/ligo).
This lets you run multiple versions and keep your installation(s) self contained, but requires more familiarity with Docker.
Sources for the image can be found on [Gitlab](https://gitlab.com/ligolang/ligo/blob/master/docker/Dockerfile).
If this is your first time using Docker, you probably want to set up a global ligo executable as shown below.
If this is your first time using Docker, you probably want to set up a global LIGO executable as shown below.
### Setting up a globally available `ligo` executable
@ -42,10 +43,18 @@ ligo --help
## Debian Linux package installation
We have produced .deb packages for a few Debian Linuxes. They will install a global `ligo` executable. You can install them in the usual way.
We have produced .deb packages for a few Debian Linux versions. They will install a global `ligo` executable.
First download one of the packages below, and then install using:
```
sudo apt install ./<package_name_here>.deb
```
- [Ubuntu 18.04](/deb/ligo_ubuntu-18.04.deb)
- [Ubuntu 19.04](/deb/ligo_ubuntu-19.04.deb)
- [Debian 9](/deb/ligo_debian-9.deb)
- [Debian 10](/deb/ligo_debian-10.deb)
## Release schedule
Important: LIGO is currently being released on a rolling release schedule. This means that you always get the latest development features. You can find our [rolling builds at the CI](https://gitlab.com/ligolang/ligo/pipelines).

View File

@ -0,0 +1,15 @@
var storage = 0;
function add(a) {
storage += a
}
function sub(a) {
storage -= a
}
// We're calling this function reset instead of default
// because `default` is a javascript keyword
function reset() {
storage = 0;
}

View File

@ -0,0 +1,7 @@
{ parameter (or (or (nat %add) (nat %sub)) (unit %default)) ;
storage int ;
code { AMOUNT ; PUSH mutez 0 ; ASSERT_CMPEQ ; UNPAIR ;
IF_LEFT
{ IF_LEFT { ADD } { SWAP ; SUB } }
{ DROP ; DROP ; PUSH int 0 } ;
NIL operation ; PAIR } }

View File

@ -0,0 +1,12 @@
type action is
| Increment of int
| Decrement of int
| Reset of unit
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
| Reset(n) -> 0
end)

View File

@ -0,0 +1,41 @@
{ parameter (or (or int int) unit) ;
storage int ;
code { DUP ;
CAR ;
DIP { DUP } ;
SWAP ;
CDR ;
DIP { DUP } ;
SWAP ;
IF_LEFT
{ DUP ;
IF_LEFT
{ DUP ;
DIP { DIP { DIP { DUP } ; SWAP } ; SWAP } ;
SWAP ;
DIP { DUP } ;
SUB ;
SWAP ;
DROP ;
SWAP ;
DROP }
{ DUP ;
DIP { DIP { DIP { DUP } ; SWAP } ; SWAP } ;
SWAP ;
DIP { DUP } ;
ADD ;
SWAP ;
DROP ;
SWAP ;
DROP } ;
SWAP ;
DROP }
{ DROP ; PUSH int 0 } ;
NIL operation ;
PAIR ;
SWAP ;
DROP ;
SWAP ;
DROP ;
SWAP ;
DROP } }

View File

@ -0,0 +1,115 @@
---
id: what-and-why
title: What & Why
---
Before we get into what LIGO is and why LIGO needs to exist, let's take a look at what options the Tezos blockchain offers us out of the box. If you want to implement smart contracts natively on Tezos, you have to learn [Michelson](https://tezos.gitlab.io/whitedoc/michelson.html).
> 💡 The (Michelson) language is stack-based, with high level data types and primitives and strict static type checking.
Here's an example of Michelson code:
**`counter.tz`**
```text
{ parameter (or (or (nat %add) (nat %sub)) (unit %default)) ;
storage int ;
code { AMOUNT ; PUSH mutez 0 ; ASSERT_CMPEQ ; UNPAIR ;
IF_LEFT
{ IF_LEFT { ADD } { SWAP ; SUB } }
{ DROP ; DROP ; PUSH int 0 } ;
NIL operation ; PAIR } }
```
The contract above maintains an `int` in its storage. It has two entrypoints *(functions)* `add` and `sub` to modify it, and the default *entrypoint* of type unit will reset it to 0.
The contract itself contains three main parts:
- `parameter` - Argument provided by a transaction invoking the contract
- `storage` - Type definition for the contract's data storage.
- `code` - Actual Michelson code that has the provided parameter & the current storage value in its initial stack. It outputs a pair of operations and a new storage value as its resulting stack.
Michelson code consists of *instructions* like `IF_LEFT`, `PUSH ...`, `UNPAIR` that are bundled togeter in what is called a *sequence*. Stack represents an intermediate state of the program, while **storage represents a persistent state**. Instructions are used to modify the run-time stack in order to yield a desired stack value when the program terminates.
> 💡 A Michelson program running on the Tezos blockchain is meant to output a pair of values including a `list of operations` to emit and a new `storage` value to persist
## Differences between a stack and traditional variable management
Stack management might be a little bit challanging, especially if you're coming from a *C-like language*. Let's implement a similar program in Javascript:
**`counter.js`**
```javascript
var storage = 0;
function add(a) {
storage += a
}
function sub(a) {
storage -= a
}
// We're calling this function reset instead of default
// because `default` is a javascript keyword
function reset() {
storage = 0;
}
```
In our javascript program the initial `storage` value is `0` and it can be modified by running the functions `add(a)`, `sub(a)` and `reset()`.
Unfortunately (???), we **can't run Javascript on the Tezos blockchain** at the moment. But we can choose LIGO, which will abstract the stack management and allow us to create readable, type-safe, and efficient smart contracts.
> 💡 You can try running the javascript program [here](https://codepen.io/maht0rz/pen/dyyvoPQ?editors=0012)
## C-like smart contracts instead of Michelson
Let's take a look at a similar LIGO program. Don't worry if it's a little confusing at first; we'll explain all the syntax in the upcoming sections of the documentation.
<!--DOCUSAURUS_CODE_TABS-->
<!--Pascaligo-->
```pascaligo
type action is
| Increment of int
| Decrement of int
| Reset of unit
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
| Reset(n) -> 0
end)
```
<!--END_DOCUSAURUS_CODE_TABS-->
> 💡 You can find the Michelson compilation output of the contract above in **`ligo-counter.tz`**
The LIGO contract behaves exactly* like the Michelson contract we've saw first, and it accepts the following LIGO expressions/values: `Increment(n)`, `Decrement(n)` and `Reset(n)`. Those serve as `entrypoint` identification, same as `%add` `%sub` or `%default` in the Michelson contract.
**not exactly, the Michelson contract also checks if the `AMOUNT` sent is `0`*
---
## Runnable code snippets & exercises
Some of the sections in this documentation will include runnable code snippets and exercises. Sources for those are available at
the [LIGO Gitlab repository](https://gitlab.com/ligolang/ligo).
### Snippets
For example **code snippets** for the *Types* subsection of this doc, can be found here:
`gitlab-pages/docs/language-basics/src/types/**`
### Exercises
Solutions to exercises can be found e.g. here: `gitlab-pages/docs/language-basics/exercises/types/**/solutions/**`
### Running snippets / excercise solutions
In certain cases it makes sense to be able to run/evaluate the given snippet or a solution, usually there'll be an example command which you can use, such as:
```shell
ligo evaluate-value -s pascaligo gitlab-pages/docs/language-basics/src/variables-and-constants/const.ligo age
# Outputs: 25
```

View File

@ -0,0 +1,153 @@
---
id: boolean-if-else
title: Boolean, If, Else
---
## Boolean
The type of a Boolean is `bool` and the possible values are `True` and `False`.
Here's how to define a boolean:
<!--DOCUSAURUS_CODE_TABS-->
<!--Pascaligo-->
```pascaligo
const a: bool = True;
const b: bool = False;
```
<!--Cameligo-->
```cameligo
let a: bool = true
let b: bool = false
```
<!--END_DOCUSAURUS_CODE_TABS-->
## Comparing two values
In LIGO, only values of the same type can be compared. We call these "comparable types." Comparable types include e.g. `int`, `nat`, `string`, `tez`, `timestamp`, `address`, ...
### Comparing strings
<!--DOCUSAURUS_CODE_TABS-->
<!--Pascaligo-->
```pascaligo
const a: string = "Alice";
const b: string = "Alice";
// True
const c: bool = (a = b);
```
<!--Cameligo-->
```cameligo
let a: string = "Alice"
let b: string = "Alice"
// true
let c: bool = (a = b)
```
<!--END_DOCUSAURUS_CODE_TABS-->
### Comparing numbers
<!--DOCUSAURUS_CODE_TABS-->
<!--Pascaligo-->
```pascaligo
const a: int = 5;
const b: int = 4;
const c: bool = (a = b);
const d: bool = (a > b);
const e: bool = (a < b);
const f: bool = (a <= b);
const g: bool = (a >= b);
const h: bool = (a =/= b);
```
<!--Cameligo-->
```cameligo
let a: int = 5
let b: int = 4
let c: bool = (a = b)
let d: bool = (a > b)
let e: bool = (a < b)
let f: bool = (a <= b)
let g: bool = (a >= b)
let h: bool = (a =/= b)
```
<!--END_DOCUSAURUS_CODE_TABS-->
### Comparing tez
> 💡 Comparing `tez` values is especially useful when dealing with an `amount` sent in a transaction.
<!--DOCUSAURUS_CODE_TABS-->
<!--Pascaligo-->
```pascaligo
const a: tez = 5mtz;
const b: tez = 10mtz;
const c: bool = (a = b);
```
<!--Cameligo-->
```cameligo
let a: tez = 5mtz
let b: tez = 10mtz
// false
let c: bool = (a = b)
```
<!--END_DOCUSAURUS_CODE_TABS-->
## Conditionals, if staments, and more
Conditional logic is an important part of every real world program.
### If/else statements
<!--DOCUSAURUS_CODE_TABS-->
<!--Pascaligo-->
```pascaligo
const min_age: nat = 16n;
(*
This function is really obnoxious, but it showcases
how the if statement and it's syntax can be used.
Normally, you'd use `with (age > min_age)` instead.
*)
function is_adult(const age: nat): bool is
block {
var is_adult: bool := False;
if (age > min_age) then begin
is_adult := True;
end else begin
is_adult := False;
end
} with is_adult
```
> You can run the function above with
> ```
> ligo run-function -s pascaligo src/if-else.ligo is_adult 21n
> ```
<!--Cameligo-->
```cameligo
let min_age: nat = 16n
(**
This function is really obnoxious, but it showcases
how the if statement and it's syntax can be used.
Normally, you'd use `with (age > min_age)` instead.
*)
let is_adult (age: nat) : bool =
if (age > min_age) then true else false
```
> You can run the function above with
> ```
> ligo run-function -s cameligo src/if-else.mligo is_adult 21n
> ```
<!--END_DOCUSAURUS_CODE_TABS-->

View File

@ -38,7 +38,7 @@ title: Cheat Sheet
|Maps|<pre><code>type prices is map(nat, tez);<br/><br/>const prices : prices = map<br/>&nbsp;&nbsp;10n -> 60mutez;<br/>&nbsp;&nbsp;50n -> 30mutez;<br/>&nbsp;&nbsp;100n -> 10mutez;<br/>end<br/><br/>const price: option(tez) = prices[50n];<br/><br/>prices[200n] := 5mutez;</code></pre>|
|Contracts & Accounts|<pre><code>const destinationAddress : address = "tz1...";<br/>const contract : contract(unit) = get_contract(destinationAddress);</code></pre>|
|Transactions|<pre><code>const payment : operation = transaction(unit, amount, receiver);</code></pre>|
|Exception/Failure|`fail("Your descriptive error message for the user goes here.")`|
|Exception/Failure|`failwith("Your descriptive error message for the user goes here.")`|
<!--END_DOCUSAURUS_CODE_TABS-->

View File

@ -3,13 +3,13 @@ id: entrypoints
title: Entrypoints
---
Entrypoints serve as a gate to our smart contracts. In LIGO each entrypoint is a function that accepts two arguments - first one is the parameter used to invoke the contract, and the second is the current storage of the contract. Each entrypoint has to return a list of operations to apply as a result of the smart contract call, and a new storage value.
Entrypoints are the gates to a smart contract. In LIGO each entrypoint is a function that accepts two arguments. The first is the parameter used to invoke the contract, and the second is the current storage of the contract. Each entrypoint must return a list of operations to apply as a result of the smart contract call, and a new storage value.
> If you don't want to update the storage, don't worry, just re-cycle your last storage value.
## Defining an entry point
Contract below is effectively an empty contract, that takes a `unit` as a parameter, and returns a `unit` as well.
The contract below is effectively an empty contract. It takes a `unit` as a parameter, and returns a `unit`.
<!--DOCUSAURUS_CODE_TABS-->
<!--Pascaligo-->
@ -21,7 +21,7 @@ function main (const p : unit ; const s : unit) : (list(operation) * unit) is
## Multiple entry points
Multiple entrypoints are currently not supported in Michelson yet, however with Ligo, you can work that around by using variants & pattern matching.
Multiple entrypoints are currently not supported in Michelson. But with Ligo you can work around that by using variants & pattern matching.
In the example below we have a simple counter contract, that can be either `Increment(int)`-ed, or `Decrement(int)`-ed.

View File

@ -3,41 +3,65 @@ id: functions
title: Functions
---
## Defining a function
Writing code is fun as long as it doesn't get out of hand. To make sure our code doesn't turn into spaghetti we can group some logic into functions.
Body of a function consists of two parts, the first part (**`block {}`** or **`begin ... end`**) - normally consists of logic *(flow conditions, variable declarations, etc.)*, and the second part (**`with ...`**) usually defines the return value of your function.
## Instruction blocks
With `block`(s) you can wrap *instructions* and *expressions* into an isolated scope.
Each `block` needs to include at least one `instruction`, or a *placeholder* instruction called `skip`.
<!--DOCUSAURUS_CODE_TABS-->
<!--Pascaligo-->
```pascaligo
const availableSupply: nat = 15n;
const totalSupply: nat = 100n;
function calculatePrice(const available: nat; const total: nat): nat is
begin
const price: nat = total / available
end with price
const price: nat = calculatePrice(availableSupply, totalSupply);
// shorthand syntax
block { skip }
// verbose syntax
begin
skip
end
```
<!--END_DOCUSAURUS_CODE_TABS-->
## Defining a function
### Functions without an explicit body (shorter syntax)
A short hand syntax for the same function as above can inline the price calculation directly into the return statement.
While this approach can have it's benefits, it can decrease readability.
<!--DOCUSAURUS_CODE_TABS-->
<!--Pascaligo-->
Functions in PascaLIGO are defined using the `function` keyword followed by their `name`, `parameters` and `return` type definitions.
Here's how you define a basic function that accepts two `ints` and returns a single `int`:
```pascaligo
const availableSupply: nat = 15n;
const totalSupply: nat = 100n;
function calculatePrice(const available: nat; const total: nat): nat is
block { skip } with total / available
const price: nat = calculatePrice(availableSupply, totalSupply);
function add(const a: int; const b: int): int is
block { skip } with a + b
```
<!--END_DOCUSAURUS_CODE_TABS-->
The function body consists of two parts:
- `block {<code>}` - logic of the function
- `with <value>` - the return value of the function
> 💡 `skip` can be used as a placeholder for empty function blocks, when all the neccessary logic fits into `with` at the end. It is also possible to omit `block { skip } with`
in the above example, leaving only `a + b`.
<!--Cameligo-->
Functions in CameLIGO are defined using the `let` keyword, like value bindings.
The difference is that after the value name a list of function parameters is provided,
along with a return type.
Here's how you define a basic function that accepts two `ints` and returns an `int` as well:
```cameligo
let add (a: int) (b: int) : int = a + b
```
The function body is a series of expressions, which are evaluated to give the return
value.
<!--END_DOCUSAURUS_CODE_TABS-->

View File

@ -0,0 +1,157 @@
---
id: maps-records
title: Maps, Records
---
So far we've seen pretty basic data types. LIGO also offers more complex built-in constructs, such as Maps and Records.
## Maps
Maps are natively available in Michelson, and LIGO builds on top of them. A requirement for a Map is that its keys be of the same type, and that type must be comparable.
Here's how a custom map type is defined:
<!--DOCUSAURUS_CODE_TABS-->
<!--Pascaligo-->
```pascaligo
type ledger is map(address, tez);
```
<!--Cameligo-->
```cameligo
type ledger = (address, tez) map
```
<!--END_DOCUSAURUS_CODE_TABS-->
And here's how a map value is populated:
<!--DOCUSAURUS_CODE_TABS-->
<!--Pascaligo-->
```pascaligo
const ledger: ledger = map
("tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx": address) -> 1000mtz;
("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN": address) -> 2000mtz;
end
```
> Notice the `->` between the key and its value and `;` to separate individual map entries.
>
> `("<string value>": address)` means that we type-cast a string into an address.
<!--Cameligo-->
```cameligo
let ledger: ledger = Map.literal
[ (("tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx": address), 1000mtz) ;
(("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN": address), 2000mtz) ;
]
```
> Map.literal constructs the map from a list of key-value pair tuples, `(<key>, <value>)`.
> Note also the `;` to separate individual map entries.
>
> `("<string value>": address)` means that we type-cast a string into an address.
<!--END_DOCUSAURUS_CODE_TABS-->
### Accessing map values by key
If we want to access a balance from our ledger above, we can use the `[]` operator/accessor to read the associated `tez` value. However, the value we'll get will be wrapped as an optional; in our case `option(tez)`. Here's an example:
<!--DOCUSAURUS_CODE_TABS-->
<!--Pascaligo-->
```pascaligo
const balance: option(tez) = ledger[("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN": address)];
```
<!--Cameligo-->
```cameligo
let balance: tez option = Map.find_opt ("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN": address) ledger
```
<!--END_DOCUSAURUS_CODE_TABS-->
#### Obtaining a map value forcefully
Accessing a value in a map yields an option, however you can also get the value directly:
<!--DOCUSAURUS_CODE_TABS-->
<!--Pascaligo-->
```pascaligo
const balance: tez = get_force(("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN": address), ledger);
```
<!--Cameligo-->
```cameligo
let balance: tez = Map.find ("tz1gjaF81ZRRvdzjobyfVNsAeSC6PScjfQwN": address) ledger
```
<!--END_DOCUSAURUS_CODE_TABS-->
## Records
Records are a construct introduced in LIGO, and are not natively available in Michelson. The LIGO compiler translates records into Michelson `Pairs`.
Here's how a custom record type is defined:
<!--DOCUSAURUS_CODE_TABS-->
<!--Pascaligo-->
```pascaligo
type user is record
id: nat;
is_admin: bool;
name: string;
end
```
<!--Cameligo-->
```cameligo
type user = {
id: nat;
is_admin: bool;
name: string;
}
```
<!--END_DOCUSAURUS_CODE_TABS-->
And here's how a record value is populated:
<!--DOCUSAURUS_CODE_TABS-->
<!--Pascaligo-->
```pascaligo
const user: user = record
id = 1n;
is_admin = True;
name = "Alice";
end
```
<!--Cameligo-->
```cameligo
let user: user = {
id = 1n;
is_admin = true;
name = "Alice";
}
```
<!--END_DOCUSAURUS_CODE_TABS-->
### Accessing record keys by name
If we want to obtain a value from a record for a given key, we can do the following:
<!--DOCUSAURUS_CODE_TABS-->
<!--Pascaligo-->
```pascaligo
const is_admin: bool = user.is_admin;
```
<!--Cameligo-->
```cameligo
let is_admin: bool = user.is_admin
```
<!--END_DOCUSAURUS_CODE_TABS-->

View File

@ -0,0 +1,154 @@
---
id: math-numbers-tez
title: Math, Numbers & Tez
---
LIGO offers three built-in numerical types: `int`, `nat` and `tez`.
## Addition
Addition in ligo is acomplished by using the `+` operator. Some type constraints apply; for example you can't add `tez + nat`.
In the following example you can find a series of arithmetic operations, including various numerical types. However, some bits of the example won't compile because adding an `int` to a `nat` produces an `int`, not a `nat`. Similiar rules apply for `tez`:
<!--DOCUSAURUS_CODE_TABS-->
<!--Pascaligo-->
```pascaligo
// int + int produces int
const a: int = 5 + 10;
// nat + int produces int
const b: int = 5n + 10;
// tez + tez produces tez
const c: tez = 5mutez + 10mutez;
// you can't add tez + int or tez + nat, this won't compile
// const d: tez = 5mutez + 10n;
// two nats produce a nat
const e: nat = 5n + 10n;
// nat + int produces an int, this won't compile
// const f: nat = 5n + 10;
const g: int = 1_000_000;
```
> Pro tip: you can use underscores for readability when defining large numbers
>
>```pascaligo
>const g: int = 1_000_000;
>```
<!--Cameligo-->
```cameligo
// int + int produces int
let a: int = 5 + 10
// nat + int produces int
let b: int = 5n + 10
// tez + tez produces tez
let c: tez = 5mutez + 10mutez
// you can't add tez + int or tez + nat, this won't compile
// const d: tez = 5mutez + 10n
// two nats produce a nat
let e: nat = 5n + 10n
// nat + int produces an int, this won't compile
// const f: nat = 5n + 10
let g: int = 1_000_000
```
> Pro tip: you can use underscores for readability when defining large numbers
>
>```cameligo
>let g: int = 1_000_000;
>```
<!--END_DOCUSAURUS_CODE_TABS-->
## Subtraction
The simpliest substraction looks like this:
> ⚠️ Even when subtracting two `nats`, the result is an `int`
<!--DOCUSAURUS_CODE_TABS-->
<!--Pascaligo-->
```pascaligo
const a: int = 5 - 10;
// substraction of two nats, yields an int
const b: int = 5n - 2n;
// won't compile, result is an int, not a nat
// const c: nat = 5n - 2n;
const d: tez = 5mutez - 1mt;
```
<!--Cameligo-->
```cameligo
let a: int = 5 - 10
// substraction of two nats, yields an int
let b: int = 5n - 2n
// won't compile, result is an int, not a nat
// const c: nat = 5n - 2n
let d: tez = 5mutez - 1mt
```
<!--END_DOCUSAURUS_CODE_TABS-->
## Multiplication
You can multiply values of the same type, such as:
<!--DOCUSAURUS_CODE_TABS-->
<!--Pascaligo-->
```pascaligo
const a: int = 5 * 5;
const b: nat = 5n * 5n;
// you can also multiply `nat` and `tez`
const c: tez = 5n * 5mutez;
```
<!--Cameligo-->
```cameligo
let a: int = 5 * 5
let b: nat = 5n * 5n
// you can also multiply `nat` and `tez`
let c: tez = 5n * 5mutez
```
<!--END_DOCUSAURUS_CODE_TABS-->
## Division
In LIGO you can divide `int`, `nat`, and `tez`. Here's how:
> ⚠️ Division of two `tez` values results into a `nat`
<!--DOCUSAURUS_CODE_TABS-->
<!--Pascaligo-->
```pascaligo
const a: int = 10 / 3;
const b: nat = 10n / 3n;
const c: nat = 10mutez / 3mutez;
```
<!--Cameligo-->
```cameligo
let a: int = 10 / 3
let b: nat = 10n / 3n
let c: nat = 10mutez / 3mutez
```
<!--END_DOCUSAURUS_CODE_TABS-->
## From `int` to `nat` and back
You can *cast* an `int` to a `nat` and vice versa, here's how:
<!--DOCUSAURUS_CODE_TABS-->
<!--Pascaligo-->
```pascaligo
const a: int = int(1n);
const b: nat = abs(1);
```
<!--END_DOCUSAURUS_CODE_TABS-->

View File

@ -5,7 +5,7 @@ title: Operators
## Available operators
> This list is non-exhaustive, more operators will be added in the upcoming LIGO releases.
> This list is non-exhaustive. More operators will be added in upcoming LIGO releases.
|Michelson |Pascaligo |Description |
|--- |--- |--- |

View File

@ -0,0 +1,240 @@
---
id: sets-lists-touples
title: Sets, Lists, Tuples
---
Apart from complex data types such as `maps` and `records`, ligo also exposes `sets`, `lists` and `tuples`.
> ⚠️ Make sure to pick the appropriate data type for your use case; it carries not only semantic but also gas related costs.
## Sets
Sets are similar to lists. The main difference is that elements of a `set` must be *unique*.
### Defining a set
<!--DOCUSAURUS_CODE_TABS-->
<!--Pascaligo-->
```pascaligo
type int_set is set(int);
const my_set: int_set = set
1;
2;
3;
end
```
<!--Cameligo-->
```cameligo
type int_set = int set
let my_set: int_set =
Set.add 3 (Set.add 2 (Set.add 1 Set.empty))
```
<!--END_DOCUSAURUS_CODE_TABS-->
### Empty sets
<!--DOCUSAURUS_CODE_TABS-->
<!--Pascaligo-->
```pascaligo
const my_set: int_set = set end;
const my_set_2: int_set = set_empty;
```
<!--END_DOCUSAURUS_CODE_TABS-->
### Checking if set contains an element
<!--DOCUSAURUS_CODE_TABS-->
<!--Pascaligo-->
```pascaligo
const contains_three: bool = my_set contains 3;
// or alternatively
const contains_three_fn: bool = set_mem(3, my_set);
```
<!--Cameligo-->
```cameligo
let contains_three: bool = Set.mem 3 my_set
```
<!--END_DOCUSAURUS_CODE_TABS-->
### Obtaining the size of a set
<!--DOCUSAURUS_CODE_TABS-->
<!--Pascaligo-->
```pascaligo
const set_size: nat = size(my_set);
```
<!--Cameligo-->
```cameligo
let set_size: nat = Set.size my_set
```
<!--END_DOCUSAURUS_CODE_TABS-->
### Modifying a set
<!--DOCUSAURUS_CODE_TABS-->
<!--Pascaligo-->
```pascaligo
const larger_set: int_set = set_add(4, my_set);
const smaller_set: int_set = set_remove(3, my_set);
```
<!--Cameligo-->
```cameligo
let larger_set: int_set = Set.add 4 my_set
let smaller_set: int_set = Set.remove 3 my_set
```
<!--END_DOCUSAURUS_CODE_TABS-->
### Folding a set
<!--DOCUSAURUS_CODE_TABS-->
<!--Pascaligo-->
```pascaligo
function sum(const result: int; const i: int): int is result + i;
// Outputs 6
const sum_of_a_set: int = set_fold(my_set, 0, sum);
```
<!--Cameligo-->
```cameligo
let sum (result: int) (i: int) : int = result + i
let sum_of_a_set: int = Set.fold my_set 0 sum
```
<!--END_DOCUSAURUS_CODE_TABS-->
## Lists
Lists are similar to sets, but their elements don't need to be unique and they don't offer the same range of built-in functions.
> 💡 Lists are useful when returning operations from a smart contract's entrypoint.
### Defining a list
<!--DOCUSAURUS_CODE_TABS-->
<!--Pascaligo-->
```pascaligo
type int_list is list(int);
const my_list: int_list = list
1;
2;
3;
end
```
<!--Cameligo-->
```cameligo
type int_list = int list
let my_list: int_list = [1; 2; 3]
```
<!--END_DOCUSAURUS_CODE_TABS-->
### Appending an element to a list
<!--DOCUSAURUS_CODE_TABS-->
<!--Pascaligo-->
```pascaligo
const larger_list: int_list = cons(4, my_list);
const even_larger_list: int_list = 5 # larger_list;
```
<!--Cameligo-->
```cameligo
let larger_list: int_list = 4 :: my_list
(* CameLIGO doesn't have a List.cons *)
```
<!--END_DOCUSAURUS_CODE_TABS-->
<br/>
> 💡 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)
### Mapping of a list
<!--DOCUSAURUS_CODE_TABS-->
<!--Pascaligo-->
```pascaligo
function increment(const i: int): int is block { skip } with i + 1;
// Creates a new list with elements incremented by 1
const incremented_list: int_list = list_map(even_larger_list, increment);
```
<!--Cameligo-->
```cameligo
let increment (i: int) : int = i + 1
(* Creates a new list with elements incremented by 1 *)
let incremented_list: int_list = List.map larger_list increment
```
<!--END_DOCUSAURUS_CODE_TABS-->
### Folding of a list:
<!--DOCUSAURUS_CODE_TABS-->
<!--Pascaligo-->
```pascaligo
function sum(const result: int; const i: int): int is block { skip } with result + i;
// Outputs 6
const sum_of_a_list: int = list_fold(my_list, 0, sum);
```
<!--Cameligo-->
```cameligo
let sum (result: int) (i: int) : int = result + i
// Outputs 6
let sum_of_a_list: int = List.fold my_list 0 sum
```
<!--END_DOCUSAURUS_CODE_TABS-->
## Tuples
Tuples are useful for data that belong together but don't have an index or a specific name.
### Defining a tuple
<!--DOCUSAURUS_CODE_TABS-->
<!--Pascaligo-->
```pascaligo
type full_name is string * string;
const full_name: full_name = ("Alice", "Johnson");
```
<!--Cameligo-->
```cameligo
type full_name = string * string
(* The parenthesis here are optional *)
let full_name: full_name = ("Alice", "Johnson")
```
<!--END_DOCUSAURUS_CODE_TABS-->
### Accessing an element in a tuple
<!--DOCUSAURUS_CODE_TABS-->
<!--Pascaligo-->
```pascaligo
const first_name: string = full_name.1;
```
<!--Cameligo-->
```cameligo
let first_name: string = full_name.1
```
<!--END_DOCUSAURUS_CODE_TABS-->

View File

@ -0,0 +1,13 @@
// int + int produces int
const a: int = 5 + 10;
// nat + int produces int
const b: int = 5n + 10;
// tez + tez produces tez
const c: tez = 5mutez + 10mutez;
// you can't add tez + int or tez + nat, this won't compile
// const d: tez = 5mutez + 10n;
// two nats produce a nat
const e: nat = 5n + 10n;
// nat + int produces an int, this won't compile
// const f: nat = 5n + 10;
const g: int = 1_000_000;

View File

@ -0,0 +1,2 @@
const a: int = int(1n);
const b: nat = abs(1);

View File

@ -0,0 +1,5 @@
const a: int = 10 / 3;
const b: nat = 10n / 3n;
const c: nat = 10mutez / 3mutez;
const d: int = 10 / 5 / 2 * 5;

View File

@ -0,0 +1,3 @@
const a: int = 5 * 5;
const b: nat = 5n * 5n;
const c: tez = 5n * 5mutez;

View File

@ -0,0 +1,6 @@
const a: int = 5 - 10;
// substraction of two nats, yields an int
const b: int = 5n - 2n;
// won't compile, result is an int, not a nat
// const c: nat = 5n - 2n;
const d: tez = 5mutez - 1mutez;

View File

@ -0,0 +1,3 @@
type int_set is set(int);
const my_set: int_set = set end;
const my_set_2: int_set = set_empty;

View File

@ -0,0 +1 @@
const a: string = string_concat("Hello ", "World");

View File

@ -0,0 +1,2 @@
type animalBreed is string;
const dogBreed : animalBreed = "Saluki";

View File

@ -0,0 +1,19 @@
// alias two types
type account is address;
type numberOfTransactions is nat;
// accountData consists of a record with two fields (balance, numberOfTransactions)
type accountData is record
balance: tez;
numberOfTransactions: numberOfTransactions;
end
// our ledger / accountBalances is a map of account <-> accountData
type accountBalances is map(account, accountData);
// pseudo-JSON representation of our map
// { "tz1...": {balance: 10mutez, numberOfTransactions: 5n} }
const ledger: accountBalances = map
("tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx": address) -> record
balance = 10mutez;
numberOfTransactions = 5n;
end
end

View File

@ -0,0 +1,6 @@
// accountBalances is a simple type, a map of address <-> tez
type accountBalances is map(address, tez);
const ledger: accountBalances = map
("tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx": address) -> 10mutez
end

View File

@ -0,0 +1,7 @@
// won't work, use const for global values instead
// var four: int = 4;
function add(const a: int; const b: int) : int is
block {
var c : int := a + b;
} with c

View File

@ -0,0 +1 @@
const age : int = 25;

View File

@ -0,0 +1,81 @@
---
id: strings
title: Strings
---
Strings are defined using the built-in `string` type like this:
<!--DOCUSAURUS_CODE_TABS-->
<!--Pascaligo-->
```
const a: string = "Hello Alice";
```
<!--Cameligo-->
```
let a: string = "Hello Alice"
```
<!--END_DOCUSAURUS_CODE_TABS-->
## Concatenating strings
Strings can be concatenated using the `^` operator.
<!--DOCUSAURUS_CODE_TABS-->
<!--Pascaligo-->
```pascaligo
const name: string = "Alice";
const greeting: string = "Hello";
// Hello Alice
const full_greeting: string = greeting ^ " " ^ name;
// Hello Alice! (alternatively)
const full_greeting_exclamation: string = string_concat(full_greeting, "!");
```
<!--Cameligo-->
```cameligo
let name: string = "Alice"
let greeting: string = "Hello"
let full_greeting: string = greeting ^ " " ^ name
```
<!--END_DOCUSAURUS_CODE_TABS-->
## Slicing strings
Strings can be sliced using the syntax specific built-in built-in function:
<!--DOCUSAURUS_CODE_TABS-->
<!--Pascaligo-->
```pascaligo
const name: string = "Alice";
// slice = "A"
const slice: string = string_slice(0n, 1n, name);
```
<!--Cameligo-->
```cameligo
let name: string = "Alice"
let slice: string = String.slice 0n 1n name
```
<!--END_DOCUSAURUS_CODE_TABS-->
> ⚠️ Notice that the `offset` and slice `length` are `nats`
## Aquiring the length of a string
The length of a string can be found using the syntax specific built-in function:
<!--DOCUSAURUS_CODE_TABS-->
<!--Pascaligo-->
```pascaligo
const name: string = "Alice";
// length = 5
const length: nat = size(name);
```
<!--Cameligo-->
```cameligo
let name: string = "Alice"
let length: nat = String.size name
```
<!--END_DOCUSAURUS_CODE_TABS-->

View File

@ -3,27 +3,33 @@ id: types
title: Types
---
LIGO is strongly and statically typed. This means that the compiler checks your program at compilation time and makes sure there won't be any type related runtime errors. LIGO types are built on top of Michelson's type system.
## Built-in types
For the list of built-in types, please refer to the [Cheat Sheet](language-basics/cheat-sheet.md). LIGO's type system is built on top of Michelson, but offers a handful of features like type aliasing, or groupping of multiple types into a single powerful type.
For quick referrence, you can find all the built-in types [here](https://gitlab.com/ligolang/ligo/blob/dev/src/passes/operators/operators.ml#L35).
## Type aliases
Type aliasing is a great choice when working towards a readable / maintainable smart contract. One well typed variable is worth a thousand words. For example we can choose to *alias* a string, as an animal breed - this will allow us to comunicate our intent with added clarity.
Type aliasing is great for creating a readable / maintainable smart contract. One well typed type/variable is worth a thousand words. For example we can choose to *alias* a string as an animal breed - this will allow us to comunicate our intent with added clarity.
<!--DOCUSAURUS_CODE_TABS-->
<!--Pascaligo-->
```pascaligo
type animalBreed is string;
const dogBreed : animalBreed = "Saluki";
```
const dogBreed: animalBreed = "Saluki";
<!--Cameligo-->
```cameligo
type animal_breed = string
let dog_breed: animal_breed = "Saluki"
```
<!--END_DOCUSAURUS_CODE_TABS-->
## Defining custom types
### Simple types
## Simple types
<!--DOCUSAURUS_CODE_TABS-->
<!--Pascaligo-->
```pascaligo
@ -35,14 +41,22 @@ const ledger: accountBalances = map
end
```
<!--Cameligo-->
```cameligo
// account_balances is a simple type, a map of address <-> tez
type account_balances is (address, tez) map
let ledger: account_balances = Map.literal
[(("tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx": address), 10mutez)]
```
<!--END_DOCUSAURUS_CODE_TABS-->
## Composed types
### Composed types
Often contracts require complex data structures, which in turn require well-typed storage or functions to work with. LIGO offers a simple way to compose simple types into larger & more expressive composed types.
Often our contracts will require complex data structures, which will in turn require a well-typed storage, or functions to work with. LIGO offers a simple way to compose simple types, into larger & more expressive composed types.
In the example below you can see definition of data types for a ledger, that keeps a balance & number of previous transactions for a given account.
In the example 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.
<!--DOCUSAURUS_CODE_TABS-->
<!--Pascaligo-->
@ -50,7 +64,6 @@ In the example below you can see definition of data types for a ledger, that kee
// alias two types
type account is address;
type numberOfTransactions is nat;
// accountData consists of a record with two fields (balance, numberOfTransactions)
type accountData is record
balance: tez;
@ -59,7 +72,7 @@ end
// our ledger / accountBalances is a map of account <-> accountData
type accountBalances is map(account, accountData);
// pseudo-JSON representation of our map
// pseudo-JSON representation of our map
// { "tz1...": {balance: 10mutez, numberOfTransactions: 5n} }
const ledger: accountBalances = map
("tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx": address) -> record
@ -69,4 +82,26 @@ const ledger: accountBalances = map
end
```
<!--END_DOCUSAURUS_CODE_TABS-->
<!--Cameligo-->
```cameligo
(* alias two types *)
type account = address
type number_of_transactions = nat
(* account_data consists of a record with two fields (balance, number_of_transactions) *)
type account_data = {
balance: tez;
number_of_transactions: number_of_transactions;
}
(* our ledger / account_balances is a map of account <-> account_data *)
type account_balances = (account, account_data) map
// pseudo-JSON representation of our map
// {"tz1...": {balance: 10mutez, number_of_transactions: 5n}}
let ledger: account_balances = Map.literal
[(("tz1KqTpEZ7Yob7QbPE4Hy4Wo8fHG8LhKxZSx": address),
{balance = 10mutez;
number_of_transactions = 5n;}
)]
```
<!--END_DOCUSAURUS_CODE_TABS-->

View File

@ -0,0 +1,116 @@
---
id: unit-option-pattern-matching
title: Unit, Option, Pattern matching
---
Optionals are a programing pattern seen in OCaml. Since Michelson and LIGO are both inspired by OCaml, you'll have the *option* to use them in LIGO as well.
## Type unit
Units in Michelson or LIGO represent *for the lack of better words* - an empty/useless/not needed value.
Here's how they're defined:
> 💡 Units come in handy when we try pattern matching on custom variants below.
<!--DOCUSAURUS_CODE_TABS-->
<!--Pascaligo-->
```pascaligo
const n: unit = Unit;
```
<!--Cameligo-->
```cameligo
let n: unit = ()
```
<!--END_DOCUSAURUS_CODE_TABS-->
## Variants
Variant is a user-defined or a built-in type (in case of optionals) that can be compared to Enum (from javascript).
Here's how to define a new variant type:
<!--DOCUSAURUS_CODE_TABS-->
<!--Pascaligo-->
```pascaligo
type id is nat
type user is
| Admin of id
| Manager of id
| Guest;
const u: user = Admin(1000n);
const g: user = Guest(Unit);
```
<!--Cameligo-->
```cameligo
type id = nat
type user =
| Admin of id
| Manager of id
| Guest of unit
let u: user = Admin 1000n
let g: user = Guest ()
```
<!--END_DOCUSAURUS_CODE_TABS-->
Defining a varient can be extremely useful for building semantically appealing contracts. We'll learn how to use variants for 'logic purposes' shortly.
## Optional values
Optionals are a type of built-in variant that can be used to determine if a variable holds a certain value or not. This is especially useful when (for example) your program's state allows for a certain variable value to be empty, like this:
<!--DOCUSAURUS_CODE_TABS-->
<!--Pascaligo-->
```pascaligo
type dinner is option(string);
// stay hungry
const p1: dinner = None;
// have some hamburgers
const p2: dinner = Some("Hamburgers")
```
<!--Cameligo-->
```cameligo
type dinner = string option
let p1: dinner = None
let p2: dinner = Some "Hamburgers"
```
<!--END_DOCUSAURUS_CODE_TABS-->
## Pattern matching
Pattern matching is very similiar to e.g. `switch` in Javascript, and can be used to re-route the program's flow based on a value of a variant.
<!--DOCUSAURUS_CODE_TABS-->
<!--Pascaligo-->
```pascaligo
type dinner is option(string);
function is_hungry(const dinner: dinner): bool is block { skip }
with (
case dinner of
| None -> True
| Some(d) -> False
end
)
```
<!--Cameligo-->
```cameligo
type dinner = string option
let is_hungry (d: dinner) : bool =
match d with
| None -> true
| Some s -> false
```
<!--END_DOCUSAURUS_CODE_TABS-->

View File

@ -0,0 +1,88 @@
---
id: constants-and-variables
title: Constants & Variables
---
The next building block after types are constants and variables.
## Constants
Constants are immutable by design, which means their values can't be reassigned.
When defining a constant you need to provide a `name`, `type` and a `value`:
<!--DOCUSAURUS_CODE_TABS-->
<!--Pascaligo-->
```pascaligo
const age : int = 25;
```
You can evaluate the constant definition above using the following CLI command:
```shell
ligo evaluate-value -s pascaligo gitlab-pages/docs/language-basics/src/variables-and-constants/const.ligo age
# Outputs: 25
```
<!--Cameligo-->
```cameligo
let age: int = 25
```
You can evaluate the constant definition above using the following CLI command:
```shell
ligo evaluate-value -s cameligo gitlab-pages/docs/language-basics/src/variables-and-constants/const.mligo age
# Outputs: 25
```
<!--END_DOCUSAURUS_CODE_TABS-->
## Variables
<!--DOCUSAURUS_CODE_TABS-->
<!--Pascaligo-->
Variables, unlike constants, are mutable. They can't be used in a *global scope*, but they can be used within functions, or function arguments.
> 💡 Don't worry if you don't understand the function syntax yet. We'll get to it in upcoming sections of the docs.
```pascaligo
// won't work, use const for global values instead
// var four: int = 4;
function add(const a: int; const b: int) : int is
block {
var c : int := a + b;
} with c
```
> ⚠️ Notice the different assignment operator `:=`
You can run the `add` function defined above using the LIGO compiler like this:
```shell
ligo run-function -s pascaligo gitlab-pages/docs/language-basics/src/variables-and-constants/add.ligo add '(1,1)'
# Outputs: 2
```
<!--Cameligo-->
As expected from a functional language, CameLIGO uses value-binding
for variables rather than assignment. Variables are changed by replacement,
with a new value being bound in place of the old one.
> 💡 Don't worry if you don't understand the function syntax yet. We'll get to it in upcoming sections of the docs.
```cameligo
let add(const a: int; const b: int) : int =
let c : int = a + b in c
```
You can run the `add` function defined above using the LIGO compiler like this:
```shell
ligo run-function -s cameligo gitlab-pages/docs/language-basics/src/variables-and-constants/add.mligo add '(1,1)'
# Outputs: 2
```
<!--END_DOCUSAURUS_CODE_TABS-->

View File

@ -1,40 +0,0 @@
---
id: variables
title: Variables
---
## Defining a variable
Variables in LIGO can be defined in two ways - by using either the `const` or `var` keywords. `const` can be used both at global (top-level) and local scope (within functions/blocks), while `var` can be used for mutable values in the local scope.
### Imutable variables using `const`
> ⚠️ Currently const values are mutable as well, however this is something that will change in the upcoming release. For the time being think of `const` as a semantical way to indicate developer intentions.
<!--DOCUSAURUS_CODE_TABS-->
<!--Pascaligo-->
```Pascal
const four: int = 4;
```
<!--END_DOCUSAURUS_CODE_TABS-->
### Mutable variables using `var`
> ⚠️ `var` can't be used in the global scope
<!--DOCUSAURUS_CODE_TABS-->
<!--Pascaligo-->
```Pascal
// won't work, use const for global values instead
var four: int = 4;
// value of `number` can be mutated within local scope
function addFour(var number: int): int is
block {
number := number + 4;
} with number;
```
<!--END_DOCUSAURUS_CODE_TABS-->

View File

@ -1,8 +0,0 @@
---
id: editor-support
title: Editor Support
---
Good editor support is the basic component of proper development experience - currently, we provide support for VSCode via an [extension](https://marketplace.visualstudio.com/items?itemName=Brice.ligo).
Currently the extension supports Pascaligo for syntax highlighting (work in progress). But it aims to support debug, gas optimization, dry run and other relevant features in the near future.

View File

View File

View File

@ -26,7 +26,6 @@ class Footer extends React.Component {
<footer className="nav-footer" id="footer">
<section className="footer-wrapper">
<div className="sitemap">
<a className="nav-home"></a>
<div>
<h5>Docs</h5>
<a href={this.docUrl('setup/installation/', this.props.language)}>
@ -70,6 +69,8 @@ class Footer extends React.Component {
</div>
</section>
{/* Load the DM Sans font, there's most likely a more appropriate place to load it in docusaurus than here */}
<link href="https://fonts.googleapis.com/css?family=DM+Sans:400,400i,500,500i,700,700i&display=swap&subset=latin-ext" rel="stylesheet"></link>
</footer>
);

View File

@ -12,18 +12,18 @@
}
},
"@babel/core": {
"version": "7.6.2",
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.6.2.tgz",
"integrity": "sha512-l8zto/fuoZIbncm+01p8zPSDZu/VuuJhAfA7d/AbzM09WR7iVhavvfNDYCNpo1VvLk6E6xgAoP9P+/EMJHuRkQ==",
"version": "7.6.4",
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.6.4.tgz",
"integrity": "sha512-Rm0HGw101GY8FTzpWSyRbki/jzq+/PkNQJ+nSulrdY6gFGOsNseCqD6KHRYe2E+EdzuBdr2pxCp6s4Uk6eJ+XQ==",
"dev": true,
"requires": {
"@babel/code-frame": "^7.5.5",
"@babel/generator": "^7.6.2",
"@babel/generator": "^7.6.4",
"@babel/helpers": "^7.6.2",
"@babel/parser": "^7.6.2",
"@babel/parser": "^7.6.4",
"@babel/template": "^7.6.0",
"@babel/traverse": "^7.6.2",
"@babel/types": "^7.6.0",
"@babel/traverse": "^7.6.3",
"@babel/types": "^7.6.3",
"convert-source-map": "^1.1.0",
"debug": "^4.1.0",
"json5": "^2.1.0",
@ -34,12 +34,12 @@
}
},
"@babel/generator": {
"version": "7.6.2",
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.6.2.tgz",
"integrity": "sha512-j8iHaIW4gGPnViaIHI7e9t/Hl8qLjERI6DcV9kEpAIDJsAOrcnXqRS7t+QbhL76pwbtqP+QCQLL0z1CyVmtjjQ==",
"version": "7.6.4",
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.6.4.tgz",
"integrity": "sha512-jsBuXkFoZxk0yWLyGI9llT9oiQ2FeTASmRFE32U+aaDTfoE92t78eroO7PTpU/OrYq38hlcDM6vbfLDaOLy+7w==",
"dev": true,
"requires": {
"@babel/types": "^7.6.0",
"@babel/types": "^7.6.3",
"jsesc": "^2.5.1",
"lodash": "^4.17.13",
"source-map": "^0.5.0"
@ -284,9 +284,9 @@
}
},
"@babel/parser": {
"version": "7.6.2",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.6.2.tgz",
"integrity": "sha512-mdFqWrSPCmikBoaBYMuBulzTIKuXVPtEISFbRRVNwMWpCms/hmE2kRq0bblUHaNRKrjRlmVbx1sDHmjmRgD2Xg==",
"version": "7.6.4",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.6.4.tgz",
"integrity": "sha512-D8RHPW5qd0Vbyo3qb+YjO5nvUVRTXFLQ/FsDxJU2Nqz4uB5EnUN0ZQSEYpvTIbRuttig1XbHWU5oMeQwQSAA+A==",
"dev": true
},
"@babel/plugin-proposal-async-generator-functions": {
@ -445,9 +445,9 @@
}
},
"@babel/plugin-transform-block-scoping": {
"version": "7.6.2",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.6.2.tgz",
"integrity": "sha512-zZT8ivau9LOQQaOGC7bQLQOT4XPkPXgN2ERfUgk1X8ql+mVkLc4E8eKk+FO3o0154kxzqenWCorfmEXpEZcrSQ==",
"version": "7.6.3",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.6.3.tgz",
"integrity": "sha512-7hvrg75dubcO3ZI2rjYTzUrEuh1E9IyDEhhB6qfcooxhDA33xx2MasuLVgdxzcP6R/lipAC6n9ub9maNW6RKdw==",
"dev": true,
"requires": {
"@babel/helper-plugin-utils": "^7.0.0",
@ -600,9 +600,9 @@
}
},
"@babel/plugin-transform-named-capturing-groups-regex": {
"version": "7.6.2",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.6.2.tgz",
"integrity": "sha512-xBdB+XOs+lgbZc2/4F5BVDVcDNS4tcSKQc96KmlqLEAwz6tpYPEvPdmDfvVG0Ssn8lAhronaRs6Z6KSexIpK5g==",
"version": "7.6.3",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.6.3.tgz",
"integrity": "sha512-jTkk7/uE6H2s5w6VlMHeWuH+Pcy2lmdwFoeWCVnvIrDUnB5gQqTVI8WfmEAhF2CDEarGrknZcmSFg1+bkfCoSw==",
"dev": true,
"requires": {
"regexpu-core": "^4.6.0"
@ -774,9 +774,9 @@
}
},
"@babel/preset-env": {
"version": "7.6.2",
"resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.6.2.tgz",
"integrity": "sha512-Ru7+mfzy9M1/YTEtlDS8CD45jd22ngb9tXnn64DvQK3ooyqSw9K4K9DUWmYknTTVk4TqygL9dqCrZgm1HMea/Q==",
"version": "7.6.3",
"resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.6.3.tgz",
"integrity": "sha512-CWQkn7EVnwzlOdR5NOm2+pfgSNEZmvGjOhlCHBDq0J8/EStr+G+FvPEiz9B56dR6MoiUFjXhfE4hjLoAKKJtIQ==",
"dev": true,
"requires": {
"@babel/helper-module-imports": "^7.0.0",
@ -795,7 +795,7 @@
"@babel/plugin-transform-arrow-functions": "^7.2.0",
"@babel/plugin-transform-async-to-generator": "^7.5.0",
"@babel/plugin-transform-block-scoped-functions": "^7.2.0",
"@babel/plugin-transform-block-scoping": "^7.6.2",
"@babel/plugin-transform-block-scoping": "^7.6.3",
"@babel/plugin-transform-classes": "^7.5.5",
"@babel/plugin-transform-computed-properties": "^7.2.0",
"@babel/plugin-transform-destructuring": "^7.6.0",
@ -810,7 +810,7 @@
"@babel/plugin-transform-modules-commonjs": "^7.6.0",
"@babel/plugin-transform-modules-systemjs": "^7.5.0",
"@babel/plugin-transform-modules-umd": "^7.2.0",
"@babel/plugin-transform-named-capturing-groups-regex": "^7.6.2",
"@babel/plugin-transform-named-capturing-groups-regex": "^7.6.3",
"@babel/plugin-transform-new-target": "^7.4.4",
"@babel/plugin-transform-object-super": "^7.5.5",
"@babel/plugin-transform-parameters": "^7.4.4",
@ -823,7 +823,7 @@
"@babel/plugin-transform-template-literals": "^7.4.4",
"@babel/plugin-transform-typeof-symbol": "^7.2.0",
"@babel/plugin-transform-unicode-regex": "^7.6.2",
"@babel/types": "^7.6.0",
"@babel/types": "^7.6.3",
"browserslist": "^4.6.0",
"core-js-compat": "^3.1.1",
"invariant": "^2.2.2",
@ -832,9 +832,9 @@
}
},
"@babel/preset-react": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.0.0.tgz",
"integrity": "sha512-oayxyPS4Zj+hF6Et11BwuBkmpgT/zMxyuZgFrMeZID6Hdh3dGlk4sHCAhdBCpuCKW2ppBfl2uCCetlrUIJRY3w==",
"version": "7.6.3",
"resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.6.3.tgz",
"integrity": "sha512-07yQhmkZmRAfwREYIQgW0HEwMY9GBJVuPY4Q12UC72AbfaawuupVWa8zQs2tlL+yun45Nv/1KreII/0PLfEsgA==",
"dev": true,
"requires": {
"@babel/helper-plugin-utils": "^7.0.0",
@ -869,26 +869,26 @@
}
},
"@babel/traverse": {
"version": "7.6.2",
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.6.2.tgz",
"integrity": "sha512-8fRE76xNwNttVEF2TwxJDGBLWthUkHWSldmfuBzVRmEDWOtu4XdINTgN7TDWzuLg4bbeIMLvfMFD9we5YcWkRQ==",
"version": "7.6.3",
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.6.3.tgz",
"integrity": "sha512-unn7P4LGsijIxaAJo/wpoU11zN+2IaClkQAxcJWBNCMS6cmVh802IyLHNkAjQ0iYnRS3nnxk5O3fuXW28IMxTw==",
"dev": true,
"requires": {
"@babel/code-frame": "^7.5.5",
"@babel/generator": "^7.6.2",
"@babel/generator": "^7.6.3",
"@babel/helper-function-name": "^7.1.0",
"@babel/helper-split-export-declaration": "^7.4.4",
"@babel/parser": "^7.6.2",
"@babel/types": "^7.6.0",
"@babel/parser": "^7.6.3",
"@babel/types": "^7.6.3",
"debug": "^4.1.0",
"globals": "^11.1.0",
"lodash": "^4.17.13"
}
},
"@babel/types": {
"version": "7.6.1",
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.6.1.tgz",
"integrity": "sha512-X7gdiuaCmA0uRjCmRtYJNAVCc/q+5xSgsfKJHqMN4iNLILX39677fJE1O40arPMh0TTtS9ItH67yre6c7k6t0g==",
"version": "7.6.3",
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.6.3.tgz",
"integrity": "sha512-CqbcpTxMcpuQTMhjI37ZHVgjBkysg5icREQIEZ0eG1yCNwg3oy+5AaLiOKmjsCj6nqOsa6Hf0ObjRVwokb7srA==",
"dev": true,
"requires": {
"esutils": "^2.0.2",
@ -928,9 +928,9 @@
}
},
"@types/node": {
"version": "12.7.7",
"resolved": "https://registry.npmjs.org/@types/node/-/node-12.7.7.tgz",
"integrity": "sha512-4jUncNe2tj1nmrO/34PsRpZqYVnRV1svbU78cKhuQKkMntKB/AmdLyGgswcZKjFHEHGpiY8pVD8CuVI55nP54w==",
"version": "12.12.5",
"resolved": "https://registry.npmjs.org/@types/node/-/node-12.12.5.tgz",
"integrity": "sha512-KEjODidV4XYUlJBF3XdjSH5FWoMCtO0utnhtdLf1AgeuZLOrRbvmU/gaRCVg7ZaQDjVf3l84egiY0mRNe5xE4A==",
"dev": true
},
"@types/q": {
@ -1010,9 +1010,9 @@
"dev": true
},
"anymatch": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.0.tgz",
"integrity": "sha512-Ozz7l4ixzI7Oxj2+cw+p0tVUt27BpaJ+1+q1TCeANWxHpvyn2+Un+YamBdfKu0uh8xLodGhoa1v7595NhKDAuA==",
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.1.tgz",
"integrity": "sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==",
"dev": true,
"requires": {
"normalize-path": "^3.0.0",
@ -1130,10 +1130,13 @@
"dev": true
},
"async": {
"version": "1.5.2",
"resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz",
"integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=",
"dev": true
"version": "2.6.3",
"resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz",
"integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==",
"dev": true,
"requires": {
"lodash": "^4.17.14"
}
},
"async-each": {
"version": "1.0.3",
@ -1163,18 +1166,18 @@
}
},
"autoprefixer": {
"version": "9.6.1",
"resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-9.6.1.tgz",
"integrity": "sha512-aVo5WxR3VyvyJxcJC3h4FKfwCQvQWb1tSI5VHNibddCVWrcD1NvlxEweg3TSgiPztMnWfjpy2FURKA2kvDE+Tw==",
"version": "9.7.1",
"resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-9.7.1.tgz",
"integrity": "sha512-w3b5y1PXWlhYulevrTJ0lizkQ5CyqfeU6BIRDbuhsMupstHQOeb1Ur80tcB1zxSu7AwyY/qCQ7Vvqklh31ZBFw==",
"dev": true,
"requires": {
"browserslist": "^4.6.3",
"caniuse-lite": "^1.0.30000980",
"browserslist": "^4.7.2",
"caniuse-lite": "^1.0.30001006",
"chalk": "^2.4.2",
"normalize-range": "^0.1.2",
"num2fraction": "^1.2.2",
"postcss": "^7.0.17",
"postcss-value-parser": "^4.0.0"
"postcss": "^7.0.21",
"postcss-value-parser": "^4.0.2"
}
},
"aws-sign2": {
@ -1664,14 +1667,14 @@
}
},
"browserslist": {
"version": "4.7.0",
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.7.0.tgz",
"integrity": "sha512-9rGNDtnj+HaahxiVV38Gn8n8Lr8REKsel68v1sPFfIGEK6uSXTY3h9acgiT1dZVtOOUtifo/Dn8daDQ5dUgVsA==",
"version": "4.7.2",
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.7.2.tgz",
"integrity": "sha512-uZavT/gZXJd2UTi9Ov7/Z340WOSQ3+m1iBVRUknf+okKxonL9P83S3ctiBDtuRmRu8PiCHjqyueqQ9HYlJhxiw==",
"dev": true,
"requires": {
"caniuse-lite": "^1.0.30000989",
"electron-to-chromium": "^1.3.247",
"node-releases": "^1.1.29"
"caniuse-lite": "^1.0.30001004",
"electron-to-chromium": "^1.3.295",
"node-releases": "^1.1.38"
}
},
"buffer": {
@ -1849,9 +1852,9 @@
}
},
"caniuse-lite": {
"version": "1.0.30000997",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000997.tgz",
"integrity": "sha512-BQLFPIdj2ntgBNWp9Q64LGUIEmvhKkzzHhUHR3CD5A9Lb7ZKF20/+sgadhFap69lk5XmK1fTUleDclaRFvgVUA==",
"version": "1.0.30001006",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001006.tgz",
"integrity": "sha512-MXnUVX27aGs/QINz+QG1sWSLDr3P1A3Hq5EUWoIt0T7K24DuvMxZEnh3Y5aHlJW6Bz2aApJdSewdYLd8zQnUuw==",
"dev": true
},
"caseless": {
@ -1962,19 +1965,19 @@
}
},
"chokidar": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.1.1.tgz",
"integrity": "sha512-df4o16uZmMHzVQwECZRHwfguOt5ixpuQVaZHjYMvYisgKhE+JXwcj/Tcr3+3bu/XeOJQ9ycYmzu7Mv8XrGxJDQ==",
"version": "3.3.0",
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.3.0.tgz",
"integrity": "sha512-dGmKLDdT3Gdl7fBUe8XK+gAtGmzy5Fn0XkkWQuYxGIgWVPPse2CxFA5mtrlD0TOHaHjEUqkWNyP1XdHoJES/4A==",
"dev": true,
"requires": {
"anymatch": "^3.1.0",
"braces": "^3.0.2",
"fsevents": "^2.0.6",
"glob-parent": "^5.0.0",
"is-binary-path": "^2.1.0",
"is-glob": "^4.0.1",
"normalize-path": "^3.0.0",
"readdirp": "^3.1.1"
"anymatch": "~3.1.1",
"braces": "~3.0.2",
"fsevents": "~2.1.1",
"glob-parent": "~5.1.0",
"is-binary-path": "~2.1.0",
"is-glob": "~4.0.1",
"normalize-path": "~3.0.0",
"readdirp": "~3.2.0"
}
},
"class-utils": {
@ -2114,9 +2117,9 @@
}
},
"commander": {
"version": "2.20.0",
"resolved": "https://registry.npmjs.org/commander/-/commander-2.20.0.tgz",
"integrity": "sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ==",
"version": "2.20.3",
"resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
"integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
"dev": true
},
"commondir": {
@ -2231,18 +2234,18 @@
"dev": true
},
"core-js": {
"version": "2.6.9",
"resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.9.tgz",
"integrity": "sha512-HOpZf6eXmnl7la+cUdMnLvUxKNqLUzJvgIziQ0DiF3JwSImNphIqdGqzj6hIKyX04MmV0poclQ7+wjWvxQyR2A==",
"version": "2.6.10",
"resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.10.tgz",
"integrity": "sha512-I39t74+4t+zau64EN1fE5v2W31Adtc/REhzWN+gWRRXg6WH5qAsZm62DHpQ1+Yhe4047T55jvzz7MUqF/dBBlA==",
"dev": true
},
"core-js-compat": {
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.2.1.tgz",
"integrity": "sha512-MwPZle5CF9dEaMYdDeWm73ao/IflDH+FjeJCWEADcEgFSE9TLimFKwJsfmkwzI8eC0Aj0mgvMDjeQjrElkz4/A==",
"version": "3.3.6",
"resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.3.6.tgz",
"integrity": "sha512-YnwZG/+0/f7Pf6Lr3jxtVAFjtGBW9lsLYcqrxhYJai1GfvrP8DEyEpnNzj/FRQfIkOOfk1j5tTBvPBLWVVJm4A==",
"dev": true,
"requires": {
"browserslist": "^4.6.6",
"browserslist": "^4.7.2",
"semver": "^6.3.0"
},
"dependencies": {
@ -2331,13 +2334,21 @@
"dev": true
},
"css-tree": {
"version": "1.0.0-alpha.33",
"resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.0.0-alpha.33.tgz",
"integrity": "sha512-SPt57bh5nQnpsTBsx/IXbO14sRc9xXu5MtMAVuo0BaQQmyf0NupNPPSoMaqiAF5tDFafYsTkfeH4Q/HCKXkg4w==",
"version": "1.0.0-alpha.37",
"resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.0.0-alpha.37.tgz",
"integrity": "sha512-DMxWJg0rnz7UgxKT0Q1HU/L9BeJI0M6ksor0OgqOnF+aRCDWg/N2641HmVyU9KVIu0OVVWOb2IpC9A+BJRnejg==",
"dev": true,
"requires": {
"mdn-data": "2.0.4",
"source-map": "^0.5.3"
"source-map": "^0.6.1"
},
"dependencies": {
"source-map": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
"dev": true
}
}
},
"css-unit-converter": {
@ -2436,30 +2447,12 @@
"dev": true
},
"csso": {
"version": "3.5.1",
"resolved": "https://registry.npmjs.org/csso/-/csso-3.5.1.tgz",
"integrity": "sha512-vrqULLffYU1Q2tLdJvaCYbONStnfkfimRxXNaGjxMldI0C7JPBC4rB1RyjhfdZ4m1frm8pM9uRPKH3d2knZ8gg==",
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/csso/-/csso-4.0.2.tgz",
"integrity": "sha512-kS7/oeNVXkHWxby5tHVxlhjizRCSv8QdU7hB2FpdAibDU8FjTAolhNjKNTiLzXtUrKT6HwClE81yXwEk1309wg==",
"dev": true,
"requires": {
"css-tree": "1.0.0-alpha.29"
},
"dependencies": {
"css-tree": {
"version": "1.0.0-alpha.29",
"resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.0.0-alpha.29.tgz",
"integrity": "sha512-sRNb1XydwkW9IOci6iB2xmy8IGCj6r/fr+JWitvJ2JxQRPzN3T4AGGVWCMlVmVwM1gtgALJRmGIlWv5ppnGGkg==",
"dev": true,
"requires": {
"mdn-data": "~1.1.0",
"source-map": "^0.5.3"
}
},
"mdn-data": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-1.1.4.tgz",
"integrity": "sha512-FSYbp3lyKjyj3E7fMl6rYvUdX0FBXaluGqlFoYESWQlyUTq8R+wp0rkFxoYFqZlHCvsUXGjyJmLQSnXToYhOSA==",
"dev": true
}
"css-tree": "1.0.0-alpha.37"
}
},
"currently-unhandled": {
@ -2771,20 +2764,20 @@
}
},
"docusaurus": {
"version": "1.13.0",
"resolved": "https://registry.npmjs.org/docusaurus/-/docusaurus-1.13.0.tgz",
"integrity": "sha512-3L/0p7CVM4jzAKoUzDDO4IFvLAJ6aA/8zin00tvLk32VQSdw+6S8JggE2ZFKOg+c+oxQ5MQUnsUxL/n5HyBtVg==",
"version": "1.14.0",
"resolved": "https://registry.npmjs.org/docusaurus/-/docusaurus-1.14.0.tgz",
"integrity": "sha512-wdjdAQAk6Ndypl0F3BIg/EUtYgSCxN9g90KbZ+BkObs0Haz62ehCGPeCNqv97m88YVaYbFzk3geQk1jL77gz5g==",
"dev": true,
"requires": {
"@babel/core": "^7.5.5",
"@babel/core": "^7.6.2",
"@babel/plugin-proposal-class-properties": "^7.5.5",
"@babel/plugin-proposal-object-rest-spread": "^7.5.5",
"@babel/plugin-proposal-object-rest-spread": "^7.6.2",
"@babel/polyfill": "^7.4.4",
"@babel/preset-env": "^7.5.5",
"@babel/preset-env": "^7.6.2",
"@babel/preset-react": "^7.0.0",
"@babel/register": "^7.5.5",
"@babel/traverse": "^7.5.5",
"@babel/types": "^7.5.5",
"@babel/register": "^7.6.2",
"@babel/traverse": "^7.6.2",
"@babel/types": "^7.6.1",
"autoprefixer": "^9.6.1",
"babylon": "^6.18.0",
"chalk": "^2.4.2",
@ -2950,9 +2943,9 @@
"dev": true
},
"electron-to-chromium": {
"version": "1.3.265",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.265.tgz",
"integrity": "sha512-ypHt5Nv1Abr27QvJqk3VC4YDNqsrrWYMCmpmR7BNfCpcgYEwmCDoi3uJpp6kvj/MIjpScQoZMCQzLqfMQGmOsg==",
"version": "1.3.302",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.302.tgz",
"integrity": "sha512-1qConyiVEbj4xZRBXqtGR003+9tV0rJF0PS6aeO0Ln/UL637js9hdwweCl07meh/kJoI2N4W8q3R3g3F5z46ww==",
"dev": true
},
"emojis-list": {
@ -2968,9 +2961,9 @@
"dev": true
},
"end-of-stream": {
"version": "1.4.3",
"resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.3.tgz",
"integrity": "sha512-cbNhPFS6MlYlWTGncSiDYbdqKhwWFy7kNeb1YSOG6K65i/wPTkLVCJQj0hXA4j0m5Da+hBWnqopEnu1FFelisQ==",
"version": "1.4.4",
"resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz",
"integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==",
"dev": true,
"requires": {
"once": "^1.4.0"
@ -3009,9 +3002,9 @@
}
},
"es-abstract": {
"version": "1.14.2",
"resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.14.2.tgz",
"integrity": "sha512-DgoQmbpFNOofkjJtKwr87Ma5EW4Dc8fWhD0R+ndq7Oc456ivUfGOOP6oAZTTKl5/CcNMP+EN+e3/iUzgE0veZg==",
"version": "1.16.0",
"resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.16.0.tgz",
"integrity": "sha512-xdQnfykZ9JMEiasTAJZJdMWCQ1Vm00NBw79/AWi7ELfZuuPCSOMDZbT9mkOfSctVtfhb+sAAzrm+j//GjjLHLg==",
"dev": true,
"requires": {
"es-to-primitive": "^1.2.0",
@ -3022,8 +3015,8 @@
"is-regex": "^1.0.4",
"object-inspect": "^1.6.0",
"object-keys": "^1.1.1",
"string.prototype.trimleft": "^2.0.0",
"string.prototype.trimright": "^2.0.0"
"string.prototype.trimleft": "^2.1.0",
"string.prototype.trimright": "^2.1.0"
}
},
"es-to-primitive": {
@ -3768,8 +3761,7 @@
"ansi-regex": {
"version": "2.1.1",
"bundled": true,
"dev": true,
"optional": true
"dev": true
},
"aproba": {
"version": "1.2.0",
@ -3790,14 +3782,12 @@
"balanced-match": {
"version": "1.0.0",
"bundled": true,
"dev": true,
"optional": true
"dev": true
},
"brace-expansion": {
"version": "1.1.11",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
@ -3812,20 +3802,17 @@
"code-point-at": {
"version": "1.1.0",
"bundled": true,
"dev": true,
"optional": true
"dev": true
},
"concat-map": {
"version": "0.0.1",
"bundled": true,
"dev": true,
"optional": true
"dev": true
},
"console-control-strings": {
"version": "1.1.0",
"bundled": true,
"dev": true,
"optional": true
"dev": true
},
"core-util-is": {
"version": "1.0.2",
@ -3942,8 +3929,7 @@
"inherits": {
"version": "2.0.3",
"bundled": true,
"dev": true,
"optional": true
"dev": true
},
"ini": {
"version": "1.3.5",
@ -3955,7 +3941,6 @@
"version": "1.0.0",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"number-is-nan": "^1.0.0"
}
@ -3970,7 +3955,6 @@
"version": "3.0.4",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"brace-expansion": "^1.1.7"
}
@ -3978,14 +3962,12 @@
"minimist": {
"version": "0.0.8",
"bundled": true,
"dev": true,
"optional": true
"dev": true
},
"minipass": {
"version": "2.3.5",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"safe-buffer": "^5.1.2",
"yallist": "^3.0.0"
@ -4004,7 +3986,6 @@
"version": "0.5.1",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"minimist": "0.0.8"
}
@ -4085,8 +4066,7 @@
"number-is-nan": {
"version": "1.0.1",
"bundled": true,
"dev": true,
"optional": true
"dev": true
},
"object-assign": {
"version": "4.1.1",
@ -4098,7 +4078,6 @@
"version": "1.4.0",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"wrappy": "1"
}
@ -4184,8 +4163,7 @@
"safe-buffer": {
"version": "5.1.2",
"bundled": true,
"dev": true,
"optional": true
"dev": true
},
"safer-buffer": {
"version": "2.1.2",
@ -4221,7 +4199,6 @@
"version": "1.0.2",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"code-point-at": "^1.0.0",
"is-fullwidth-code-point": "^1.0.0",
@ -4241,7 +4218,6 @@
"version": "3.0.1",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"ansi-regex": "^2.0.0"
}
@ -4285,14 +4261,12 @@
"wrappy": {
"version": "1.0.2",
"bundled": true,
"dev": true,
"optional": true
"dev": true
},
"yallist": {
"version": "3.0.3",
"bundled": true,
"dev": true,
"optional": true
"dev": true
}
}
},
@ -4433,9 +4407,9 @@
"dev": true
},
"fsevents": {
"version": "2.0.7",
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.0.7.tgz",
"integrity": "sha512-a7YT0SV3RB+DjYcppwVDLtn13UQnmg0SWZS7ezZD0UjnLwXmy8Zm21GMVGLaFGimIqcvyMQaOJBrop8MyOp1kQ==",
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.1.tgz",
"integrity": "sha512-4FRPXWETxtigtJW/gxzEDsX1LVbPAM93VleB83kZB+ellqbHMkyt2aJfuzNLRvFPnGi6bcE5SvfxgbXPeKteJw==",
"dev": true,
"optional": true
},
@ -4529,9 +4503,9 @@
}
},
"glob": {
"version": "7.1.4",
"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz",
"integrity": "sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==",
"version": "7.1.5",
"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.5.tgz",
"integrity": "sha512-J9dlskqUXK1OeTOYBEn5s8aMukWMwWfs+rPTn/jn50Ux4MNXVhubL1wu/j2t+H4NVI+cXEcCaYellqaPVGXNqQ==",
"dev": true,
"requires": {
"fs.realpath": "^1.0.0",
@ -4650,9 +4624,9 @@
}
},
"graceful-fs": {
"version": "4.2.2",
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.2.tgz",
"integrity": "sha512-IItsdsea19BoLC7ELy13q1iJFNmd7ofZH5+X/pJr90/nRoPEX0DJo1dHDbgtYWOhJhcCgMDTOw84RZ72q6lB+Q==",
"version": "4.2.3",
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz",
"integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==",
"dev": true
},
"graceful-readlink": {
@ -4826,15 +4800,15 @@
"dev": true
},
"highlight.js": {
"version": "9.15.10",
"resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-9.15.10.tgz",
"integrity": "sha512-RoV7OkQm0T3os3Dd2VHLNMoaoDVx77Wygln3n9l5YV172XonWG6rgQD3XnF/BuFFZw9A0TJgmMSO8FEWQgvcXw==",
"version": "9.16.2",
"resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-9.16.2.tgz",
"integrity": "sha512-feMUrVLZvjy0oC7FVJQcSQRqbBq9kwqnYE4+Kj9ZjbHh3g+BisiPgF49NyQbVLNdrL/qqZr3Ca9yOKwgn2i/tw==",
"dev": true
},
"hosted-git-info": {
"version": "2.8.4",
"resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.4.tgz",
"integrity": "sha512-pzXIvANXEFrc5oFFXRMkbLPQ2rXRoDERwDLyrcUxGhaZhgP54BBSl9Oheh7Vv0T090cszWBxPjkQQ5Sq1PbBRQ==",
"version": "2.8.5",
"resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.5.tgz",
"integrity": "sha512-kssjab8CvdXfcXMXVcvsXum4Hwdq9XGtRD3TteMEvEbq0LXyiNQr6AprqKqfeaDXze7SxWvRxdpwE6ku7ikLkg==",
"dev": true
},
"hsl-regex": {
@ -5606,9 +5580,9 @@
"dev": true
},
"json5": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/json5/-/json5-2.1.0.tgz",
"integrity": "sha512-8Mh9h6xViijj36g7Dxi+Y4S6hNGV96vcJZr/SrlHh1LR/pEn/8j/+qIBbs44YKl69Lrfctp4QD+AdWLTMqEZAQ==",
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/json5/-/json5-2.1.1.tgz",
"integrity": "sha512-l+3HXD0GEI3huGq1njuqtzYK8OYJyXMkOLtQ53pjWh89tvWS2h6l+1zMkYWqlb57+SiQodKZyvMEFb2X+KrFhQ==",
"dev": true,
"requires": {
"minimist": "^1.2.0"
@ -5650,6 +5624,15 @@
"integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==",
"dev": true
},
"klaw-sync": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/klaw-sync/-/klaw-sync-6.0.0.tgz",
"integrity": "sha512-nIeuVSzdCCs6TDPTqI8w1Yre34sSq7AkZ4B3sfOBbI2CgVSB4Du4aLQijFU2+lhAFCwt9+42Hel6lQNIv6AntQ==",
"dev": true,
"requires": {
"graceful-fs": "^4.1.11"
}
},
"lazy-cache": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-2.0.2.tgz",
@ -6329,12 +6312,20 @@
"dev": true
},
"node-releases": {
"version": "1.1.32",
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.32.tgz",
"integrity": "sha512-VhVknkitq8dqtWoluagsGPn3dxTvN9fwgR59fV3D7sLBHe0JfDramsMI8n8mY//ccq/Kkrf8ZRHRpsyVZ3qw1A==",
"version": "1.1.39",
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.39.tgz",
"integrity": "sha512-8MRC/ErwNCHOlAFycy9OPca46fQYUjbJRDcZTHVWIGXIjYLM73k70vv3WkYutVnM4cCo4hE0MqBVVZjP6vjISA==",
"dev": true,
"requires": {
"semver": "^5.3.0"
"semver": "^6.3.0"
},
"dependencies": {
"semver": {
"version": "6.3.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
"dev": true
}
}
},
"normalize-package-data": {
@ -6762,9 +6753,9 @@
"dev": true
},
"picomatch": {
"version": "2.0.7",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.0.7.tgz",
"integrity": "sha512-oLHIdio3tZ0qH76NybpeneBhYVj0QFTfXEFTc/B3zKQspYfYYkWYgFsmzo+4kvId/bQRcNkVeguI3y+CD22BtA==",
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.1.0.tgz",
"integrity": "sha512-uhnEDzAbrcJ8R3g2fANnSuXZMBtkpSjxTTgn2LeSiQlfmq72enQJWdQllXW24MBLYnA1SBD2vfvx2o0Zw3Ielw==",
"dev": true
},
"pify": {
@ -6861,30 +6852,24 @@
}
},
"portfinder": {
"version": "1.0.24",
"resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.24.tgz",
"integrity": "sha512-ekRl7zD2qxYndYflwiryJwMioBI7LI7rVXg3EnLK3sjkouT5eOuhS3gS255XxBksa30VG8UPZYZCdgfGOfkSUg==",
"version": "1.0.25",
"resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.25.tgz",
"integrity": "sha512-6ElJnHBbxVA1XSLgBp7G1FiCkQdlqGzuF7DswL5tcea+E8UpuvPU7beVAjjRwCioTS9ZluNbu+ZyRvgTsmqEBg==",
"dev": true,
"requires": {
"async": "^1.5.2",
"debug": "^2.2.0",
"mkdirp": "0.5.x"
"async": "^2.6.2",
"debug": "^3.1.1",
"mkdirp": "^0.5.1"
},
"dependencies": {
"debug": {
"version": "2.6.9",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
"version": "3.2.6",
"resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz",
"integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==",
"dev": true,
"requires": {
"ms": "2.0.0"
"ms": "^2.1.1"
}
},
"ms": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
"dev": true
}
}
},
@ -6895,9 +6880,9 @@
"dev": true
},
"postcss": {
"version": "7.0.18",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.18.tgz",
"integrity": "sha512-/7g1QXXgegpF+9GJj4iN7ChGF40sYuGYJ8WZu8DZWnmhQ/G36hfdk3q9LBJmoK+lZ+yzZ5KYpOoxq7LF1BxE8g==",
"version": "7.0.21",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.21.tgz",
"integrity": "sha512-uIFtJElxJo29QC753JzhidoAhvp/e/Exezkdhfmt8AymWT6/5B7W1WmponYWkHk2eg6sONyTch0A3nkMPun3SQ==",
"dev": true,
"requires": {
"chalk": "^2.4.2",
@ -7427,6 +7412,15 @@
"integrity": "sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw=",
"dev": true
},
"preprocess": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/preprocess/-/preprocess-3.1.0.tgz",
"integrity": "sha1-pE5c3Vu7WlTwrSiaru2AmV19k4o=",
"dev": true,
"requires": {
"xregexp": "3.1.0"
}
},
"prismjs": {
"version": "1.17.1",
"resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.17.1.tgz",
@ -7570,9 +7564,9 @@
}
},
"react": {
"version": "16.9.0",
"resolved": "https://registry.npmjs.org/react/-/react-16.9.0.tgz",
"integrity": "sha512-+7LQnFBwkiw+BobzOF6N//BdoNw0ouwmSJTEm9cglOOmsg/TMiFHZLe2sEoN5M7LgJTj9oHH0gxklfnQe66S1w==",
"version": "16.11.0",
"resolved": "https://registry.npmjs.org/react/-/react-16.11.0.tgz",
"integrity": "sha512-M5Y8yITaLmU0ynd0r1Yvfq98Rmll6q8AxaEe88c8e7LxO8fZ2cNgmFt0aGAS9wzf1Ao32NKXtCl+/tVVtkxq6g==",
"dev": true,
"requires": {
"loose-envify": "^1.1.0",
@ -7581,9 +7575,9 @@
}
},
"react-dev-utils": {
"version": "9.0.4",
"resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-9.0.4.tgz",
"integrity": "sha512-VwR+mBUXPLdYk/rOz6s6qpasIFGd7GW0KXd/3bih+/qGcMQvPG19XxtjDMtiAg0zWiFwp1ugCzAjLThbzFjVqw==",
"version": "9.1.0",
"resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-9.1.0.tgz",
"integrity": "sha512-X2KYF/lIGyGwP/F/oXgGDF24nxDA2KC4b7AFto+eqzc/t838gpSGiaU8trTqHXOohuLxxc5qi1eDzsl9ucPDpg==",
"dev": true,
"requires": {
"@babel/code-frame": "7.5.5",
@ -7605,7 +7599,7 @@
"loader-utils": "1.2.3",
"open": "^6.3.0",
"pkg-up": "2.0.0",
"react-error-overlay": "^6.0.2",
"react-error-overlay": "^6.0.3",
"recursive-readdir": "2.2.2",
"shell-quote": "1.7.2",
"sockjs-client": "1.4.0",
@ -7619,6 +7613,17 @@
"integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==",
"dev": true
},
"browserslist": {
"version": "4.7.0",
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.7.0.tgz",
"integrity": "sha512-9rGNDtnj+HaahxiVV38Gn8n8Lr8REKsel68v1sPFfIGEK6uSXTY3h9acgiT1dZVtOOUtifo/Dn8daDQ5dUgVsA==",
"dev": true,
"requires": {
"caniuse-lite": "^1.0.30000989",
"electron-to-chromium": "^1.3.247",
"node-releases": "^1.1.29"
}
},
"escape-string-regexp": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
@ -7637,27 +7642,27 @@
}
},
"react-dom": {
"version": "16.9.0",
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-16.9.0.tgz",
"integrity": "sha512-YFT2rxO9hM70ewk9jq0y6sQk8cL02xm4+IzYBz75CQGlClQQ1Bxq0nhHF6OtSbit+AIahujJgb/CPRibFkMNJQ==",
"version": "16.11.0",
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-16.11.0.tgz",
"integrity": "sha512-nrRyIUE1e7j8PaXSPtyRKtz+2y9ubW/ghNgqKFHHAHaeP0fpF5uXR+sq8IMRHC+ZUxw7W9NyCDTBtwWxvkb0iA==",
"dev": true,
"requires": {
"loose-envify": "^1.1.0",
"object-assign": "^4.1.1",
"prop-types": "^15.6.2",
"scheduler": "^0.15.0"
"scheduler": "^0.17.0"
}
},
"react-error-overlay": {
"version": "6.0.2",
"resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.2.tgz",
"integrity": "sha512-DHRuRk3K4Lg9obI6J4Y+nKvtwjasYRU9CFL3ud42x9YJG1HbQjSNublapC/WBJOA726gNUbqbj0U2df9+uzspQ==",
"version": "6.0.3",
"resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.3.tgz",
"integrity": "sha512-bOUvMWFQVk5oz8Ded9Xb7WVdEi3QGLC8tH7HmYP0Fdp4Bn3qw0tRFmr5TW6mvahzvmrK4a6bqWGfCevBflP+Xw==",
"dev": true
},
"react-is": {
"version": "16.9.0",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.9.0.tgz",
"integrity": "sha512-tJBzzzIgnnRfEm046qRcURvwQnZVXmuCbscxUO5RWrGTXpon2d4c8mI0D8WE6ydVIm29JiLB6+RslkIvym9Rjw==",
"version": "16.11.0",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.11.0.tgz",
"integrity": "sha512-gbBVYR2p8mnriqAwWx9LbuUrShnAuSCNnuPGyc7GJrMVQtPDAh8iLpv7FRuMPFb56KkaVZIYSz1PrjI9q0QPCw==",
"dev": true
},
"read-pkg": {
@ -7737,9 +7742,9 @@
}
},
"readdirp": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.1.2.tgz",
"integrity": "sha512-8rhl0xs2cxfVsqzreYCvs8EwBfn/DhVdqtoLmw19uI3SC5avYX9teCurlErfpPXGmYtMHReGaP2RsLnFvz/lnw==",
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.2.0.tgz",
"integrity": "sha512-crk4Qu3pmXwgxdSgGhgA/eXiJAPQiX4GMOZZMXnqKxHX7TaoL+3gQVo/WeuAiogr07DpnfjIMpXXa+PAIvwPGQ==",
"dev": true,
"requires": {
"picomatch": "^2.0.4"
@ -7828,9 +7833,9 @@
}
},
"regjsgen": {
"version": "0.5.0",
"resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.5.0.tgz",
"integrity": "sha512-RnIrLhrXCX5ow/E5/Mh2O4e/oa1/jW0eaBKTSy3LaCj+M3Bqvm97GWDp2yUtzIs4LEn65zR2yiYGFqb2ApnzDA==",
"version": "0.5.1",
"resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.5.1.tgz",
"integrity": "sha512-5qxzGZjDs9w4tzT3TPhCJqWdCc3RLYwy9J2NB0nm5Lz+S273lvWcpjaTGHsT1dc6Hhfq41uSEOw8wBmxrKOuyg==",
"dev": true
},
"regjsparser": {
@ -8046,9 +8051,9 @@
"dev": true
},
"scheduler": {
"version": "0.15.0",
"resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.15.0.tgz",
"integrity": "sha512-xAefmSfN6jqAa7Kuq7LIJY0bwAPG3xlCj0HMEBQk1lxYiDKZscY2xJ5U/61ZTrYbmNQbXa+gc7czPkVo11tnCg==",
"version": "0.17.0",
"resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.17.0.tgz",
"integrity": "sha512-7rro8Io3tnCPuY4la/NuI5F2yfESpnfZyT6TtkXnSWVkcu0BCDJ+8gk5ozUaFaxpIyNuWAPXrH0yFcSi28fnDA==",
"dev": true,
"requires": {
"loose-envify": "^1.1.0",
@ -8449,9 +8454,9 @@
}
},
"source-map-support": {
"version": "0.5.13",
"resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz",
"integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==",
"version": "0.5.16",
"resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.16.tgz",
"integrity": "sha512-efyLRJDr68D9hBBNIPWFjhpFzURh+KJykQwvMyW5UiZzYwoF6l4YMMDIJJEyFWxWCqfyxLzz6tSfUFR+kXXsVQ==",
"dev": true,
"requires": {
"buffer-from": "^1.0.0",
@ -8786,17 +8791,17 @@
}
},
"svgo": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/svgo/-/svgo-1.3.0.tgz",
"integrity": "sha512-MLfUA6O+qauLDbym+mMZgtXCGRfIxyQoeH6IKVcFslyODEe/ElJNwr0FohQ3xG4C6HK6bk3KYPPXwHVJk3V5NQ==",
"version": "1.3.2",
"resolved": "https://registry.npmjs.org/svgo/-/svgo-1.3.2.tgz",
"integrity": "sha512-yhy/sQYxR5BkC98CY7o31VGsg014AKLEPxdfhora76l36hD9Rdy5NZA/Ocn6yayNPgSamYdtX2rFJdcv07AYVw==",
"dev": true,
"requires": {
"chalk": "^2.4.1",
"coa": "^2.0.2",
"css-select": "^2.0.0",
"css-select-base-adapter": "^0.1.1",
"css-tree": "1.0.0-alpha.33",
"csso": "^3.5.1",
"css-tree": "1.0.0-alpha.37",
"csso": "^4.0.2",
"js-yaml": "^3.13.1",
"mkdirp": "~0.5.1",
"object.values": "^1.1.0",
@ -9376,9 +9381,9 @@
"dev": true
},
"whatwg-url": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-7.0.0.tgz",
"integrity": "sha512-37GeVSIJ3kn1JgKyjiYNmSLP1yzbpb29jdmwBSgkD9h40/hyrR/OifpVUndji3tmwGgD8qpw7iQu3RSbCrBpsQ==",
"version": "7.1.0",
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-7.1.0.tgz",
"integrity": "sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==",
"dev": true,
"requires": {
"lodash.sortby": "^4.7.0",
@ -9428,6 +9433,12 @@
"integrity": "sha512-Eux0i2QdDYKbdbA6AM6xE4m6ZTZr4G4xF9kahI2ukSEMCzwce2eX9WlTI5J3s+NU7hpasFsr8hWIONae7LluAQ==",
"dev": true
},
"xregexp": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/xregexp/-/xregexp-3.1.0.tgz",
"integrity": "sha1-FNhGHgvdOCJL/uUDmgiY/EL80zY=",
"dev": true
},
"xtend": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",

View File

@ -11,6 +11,6 @@
"rename-version": "docusaurus-rename-version"
},
"devDependencies": {
"docusaurus": "^1.13.0"
"docusaurus": "^1.14.0"
}
}

View File

@ -185,17 +185,16 @@ class HomeSplash extends React.Component {
<div className="home-container">
<div className="home-text">
<div className="projectTitle">
<img alt={siteConfig.title} src={`${siteConfig.baseUrl}img/logo.svg`} />
LIGO is a statically typed high-level smart-contract programming language that compiles to Michelson
</div>
<h4 className="tagline-text">{siteConfig.tagline}</h4>
<p className="body">{siteConfig.taglineSub}</p>
{/* <h4 className="tagline-text">{siteConfig.tagline}</h4> */}
<p className="body subtagline-text">It seeks to be easy to use, extensible and safe.</p>
<LinkButton
href="https://ide.ligolang.org/"
className="large-primary-button"
>
Try Online
</LinkButton>
<p></p>
<LinkButton
href={docUrl("setup/installation.html")}
className="large-secondary-button"
@ -370,12 +369,15 @@ class Index extends React.Component {
));
return (
<div className="partners-container hide-small">
{PartnerShowcase}
<div className="partners-text">
<h3>Partners</h3>
<div className="partners-container-wrapper hide-small">
<div className="partners-container">
{PartnerShowcase}
<div className="partners-text">
<h3>Partners</h3>
<p>We're not alone in this world.</p>
</div>
</div>
</div>
);
};

View File

@ -1,13 +1,22 @@
{
"docs": {
"Setup": ["setup/installation", "setup/editor-support"],
"Intro": ["intro/what-and-why", "intro/installation", "intro/editor-support"],
"Language Basics": [
"language-basics/cheat-sheet",
"language-basics/types",
"language-basics/variables",
"language-basics/constants-and-variables",
"language-basics/math-numbers-tez",
"language-basics/strings",
"language-basics/functions",
"language-basics/entrypoints",
"language-basics/operators"
"language-basics/boolean-if-else",
"language-basics/unit-option-pattern-matching",
"language-basics/maps-records",
"language-basics/sets-lists-touples"
],
"Advanced": [
"advanced/timestamps-addresses",
"advanced/entrypoints-contracts",
"advanced/first-contract"
],
"API": ["api-cli-commands"]
},

View File

@ -99,7 +99,7 @@ const siteConfig = {
// For no header links in the top nav bar -> headerLinks: [],
headerLinks: [
{ doc: "setup/installation", label: "Docs" },
{ doc: "intro/what-and-why", label: "Docs" },
{
doc: "tutorials/get-started/tezos-taco-shop-smart-contract",
label: "Tutorials"

View File

@ -30,7 +30,7 @@ h4,
font-family: "DM Sans", sans-serif;
font-weight: bold;
/** Override docusaurus rule that makes a huge top margin **/
margin-top: 1rem;
margin-top: 2rem;
}
body,
@ -63,6 +63,8 @@ h1 {
}
h2 {
font-size: 2.25rem;
margin-bottom: 0.5rem;
margin-top: 1.5rem;
}
.landing h2 {
font-size: 3rem;
@ -76,6 +78,9 @@ h3 {
h4 {
font-size: 1.125rem;
}
p {
line-height: 25px;
}
.landing h4 {
font-size: 1.5rem;
}
@ -89,6 +94,7 @@ h4 {
body,
.body {
font-size: 1rem;
color: var(--color-primary-text);
}
.landing .body,
.landing {
@ -115,6 +121,7 @@ footnote {
.fixedHeaderContainer {
background-color: #ffffff;
color: var(--color-primary-text);
padding: 0px;
}
.fixedHeaderContainer a {
@ -141,6 +148,7 @@ footnote {
.fixedHeaderContainer {
left: 0;
min-height: 80px;
}
.nav-footer {
@ -149,17 +157,16 @@ footnote {
.nav-footer .copyright {
text-align: left;
margin-left: 92px;
margin-top: 3em;
border-top: 1px solid white;
padding-top: 3em;
margin-right: 92px;
}
.nav-footer .footer-wrapper {
margin: 0 auto 3em;
max-width: 1080px;
margin: 0 auto;
margin-top: var(--padding-level-4);
max-width: 1500px;
}
.nav-footer .sitemap {
@ -211,6 +218,8 @@ footnote {
background-color: white;
}
.hljs {
text-align: left;
background: transparent;
@ -219,7 +228,6 @@ footnote {
.tabs {
margin: 0 auto;
border-top: none;
border-bottom: 4px solid #e0e0e0;
}
.tabs .nav-tabs > div {
@ -228,16 +236,24 @@ footnote {
border-bottom: none;
padding-bottom: 8px;
}
.tab-content {
padding-top: 12px;
/* .tabs blockquote {
margin-top: 16px;
}
.tabs p {
margin-top: 16px;
} */
.tabs .nav-tabs > div.active {
border-bottom: 4px solid #1a1a1a;
}
.tab-content {
border-top: 4px solid #e0e0e0;
padding-top: 16px;
border-bottom: 4px solid #e0e0e0;
margin-bottom: 16px;
}
.nav-tabs {
@ -255,27 +271,40 @@ footnote {
}
blockquote {
background-color: rgba(26, 26, 26, 0.3);
border-left: 8px solid rgba(26, 26, 26, 0.1);
color: rgba(255, 255, 255, 1);
background-color: #EFEFEF;
border-left: 5px solid var(--color-primary-text);
color: var(--color-primary-text);
border-radius: 2px;
}
blockquote code {
opacity: 0.5;
opacity: 1;
background: var(--color-code-background2);
}
a {
color: var(--color-primary-text);
}
a:hover {
a, a:hover {
color: var(--color-primary-brand);
}
/* blockquote a {
color: rgba(255, 255, 255, 1);
opacity: 0.9;
} */
.docMainWrapper a:hover {
text-decoration: underline;
}
.landing a {
color: var(--color-white);
}
.landing .hljs {
background-color: rgba(255,255,255,0.5);
}
.landing a:hover {
font-weight: bold;
}
@ -329,7 +358,6 @@ html {
body {
margin: 0 auto;
max-width: 1500px;
}
.copyright a {
@ -357,9 +385,50 @@ body {
visibility: hidden;
}
.toc .toggleNav ul li a {
font-size: 16px;
line-height: 25px;
color: var(--color-primary-text);
}
.toc .toggleNav .navGroup .navGroupCategoryTitle {
color: var(--color-secondary-text);
font-size: 12px;
line-height: 16px;
margin-bottom: 20px;
}
.toc .toggleNav .navGroup {
margin-bottom: 30px;
}
.toc .toggleNav ul {
padding: 0px;
}
.navListItemActive a{
color: var(--color-primary-brand) !important;
}
.onPageNav > .toc-headings {
border-color: var(--color-gray);
}
.onPageNav .toc-headings > li > a {
color: var(--color-secondary-text);
}
.onPageNav .toc-headings > li > a.active {
color: var(--color-primary-text);
}
code {
background: rgb(240, 240, 240);
color: #444;
background: var(--color-code-background1);
margin-left: 2px;
margin-right: 2px;
border-radius: 2px;
border: none;
outline: none;
}
body
@ -374,8 +443,9 @@ body
background-repeat: no-repeat;
background-position: center center;
min-width: 50px;
padding-top: 5px;
opacity: 0.8;
position: relative;
top: 1px;
}
body
@ -527,7 +597,6 @@ body
justify-content: center;
max-width: fit-content;
color: var(--color-primary-text);
padding: 0 var(--padding-level-1);
}
.profileContainer a {
@ -555,6 +624,31 @@ body
flex-wrap: wrap;
}
.subtagline-text {
text-align: left;
margin-bottom: 25px;
}
.projectTitle {
font-size: 2.5rem;
text-align: left;
margin-bottom: 25px;
line-height: 47px;
}
.home-text {
text-align: left;
margin-top: -50px;
}
.home-text a:nth-of-type(2) {
margin-left: 24px;
}
.nav-footer .sitemap {
max-width: 1500px;
}
@media only screen and (min-device-width: 360px) and (max-device-width: 736px) {
}
@ -578,12 +672,20 @@ body
.flex-inline-container {
display: flex;
flex-direction: row;
justify-content: space-around;
padding: var(--padding-level-1);
justify-content: space-between;
flex-wrap: wrap;
align-items: stretch;
}
.features h2, .team h2 {
margin-bottom: 70px;
}
.features, .team, .home-container, .partners-container {
max-width: 1500px;
margin: 0 auto;
}
.team .flex-inline-container {
align-items: flex-start;
}
@ -603,14 +705,20 @@ body
text-align: center;
}
.partners-container-wrapper {
padding-bottom: 0px;
padding-top: 0px;
margin-top: 45px;
background-color: var(--color-light-gray);
}
/** Partners **/
.partners-container {
background-color: var(--color-light-gray);
display: flex;
justify-content: space-around;
align-content: center;
padding: var(--padding-level-3);
margin: var(--padding-level-4) 0;
padding-top: var(--padding-level-5);
padding-bottom: var(--padding-level-5);
}
.partners-container a {
@ -623,12 +731,45 @@ body
.partners-text {
padding: 0 var(--padding-level-1);
border-left: 5px solid var(--color-primary-brand);
font-size: 18px;
line-height: 28px;
color: var(--color-primary-text);
}
.partners-text h3 {
margin-bottom: 10px;
}
.code-snippet > div:nth-child(2) {
display: none;
}
.navigationSlider .slidingNav ul li a {
text-transform: lowercase;
font-size: 16px;
line-height: 22px;
}
.headerWrapper.wrapper {
margin-top: 21px;
}
.home-container .tab-pane pre {
margin: 0;
}
pre {
margin: 0px;
}
.home-container {
margin-top: 50px;
}
.landing .mainContainer {
padding-bottom: 0px;
}
@media only screen and (min-width: 1024px) {
.code-snippet > div:nth-child(2) {
display: block;
@ -649,7 +790,7 @@ body
}
.home-container .tab-pane {
height: 500px;
height: 520px;
}
}
@ -730,13 +871,9 @@ body
}
}
@media only screen and (min-width: 1280px) {
.home-container {
flex-direction: row;
margin: var(--padding-level-1);
max-width: 90%;
padding: var(--padding-level-3);
}
}
@ -766,9 +903,10 @@ input#search_input_react::placeholder {
.hljs {
display:block;
overflow-x:hidden;
padding:.5em;
background:white;
padding:20px;
background: var(--color-code-background1);
color:black;
margin-bottom: 16px;
}
.hljs-comment,
.hljs-quote,
@ -818,6 +956,5 @@ input#search_input_react::placeholder {
}
.docMainWrapper .hljs {
border: solid 1px lightgray;
overflow-x: auto;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

View File

@ -1,45 +0,0 @@
---
id: version-next-language-basics-entrypoints
title: Entrypoints
original_id: language-basics-entrypoints
---
## Defining an entry point
<!--DOCUSAURUS_CODE_TABS-->
<!--Pascaligo-->
```Pascal
function main (const p : int ; const s : int) : (list(operation) * int) is
block {skip} with ((nil : list(operation)), s + 1)
```
<!--END_DOCUSAURUS_CODE_TABS-->
## Multiple entry points
Multiple entrypoints are currently not supported in Michelson, however with Ligo, you can work that around by using variants.
<!--DOCUSAURUS_CODE_TABS-->
<!--Pascaligo-->
```Pascal
// variant defining pseudo multi-entrypoint actions
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
// real entrypoint that re-routes the flow based on the action provided
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)
```
<!--END_DOCUSAURUS_CODE_TABS-->

View File

@ -1,23 +0,0 @@
---
id: version-next-language-basics-functions
title: Functions
original_id: language-basics-functions
---
## Defining a function
<!--DOCUSAURUS_CODE_TABS-->
<!--Pascaligo-->
```Pascal
// multiply(1, 2) = 2
function multiply (const a : int ; const b : int) : int is
begin
const result : int = a * b ;
end with result
// add(1, 2) = 3
function add (const a : int ; const b : int) : int is
block { skip } with a + b
```
<!--END_DOCUSAURUS_CODE_TABS-->

View File

@ -1,13 +0,0 @@
---
id: version-next-language-basics-operators
title: Operators
original_id: language-basics-operators
---
## Available operators
|Michelson |Pascaligo |Description |
|--- |--- |--- |
| `SENDER` | `sender` | Address that initiated the current transaction
| `SOURCE` | `source` | Address that initiated the transaction, which triggered the current transaction. (useful e.g. when there's a transaction sent by another contract)
| `AMOUNT` | `amount` | Amount of tez sent by the transaction that invoked the contract

View File

@ -1,19 +0,0 @@
---
id: version-next-language-basics-variables
title: Variables
original_id: language-basics-variables
---
## Defining a variable
<!--DOCUSAURUS_CODE_TABS-->
<!--Pascaligo-->
```Pascal
// int
const four : int = 4;
// string
const name : string = "John Doe";
```
<!--END_DOCUSAURUS_CODE_TABS-->

View File

@ -1,8 +1,9 @@
{
"version-next-docs": {
"Setup": [
"version-next-setup/installation",
"version-next-setup/editor-support"
"Intro": [
"version-next-intro/what-and-why",
"version-next-intro/installation",
"version-next-intro/editor-support"
],
"Language Basics": [
"version-next-language-basics/cheat-sheet",