docs: restructuring & introduction of mkdocs with versioning provided by mike
This commit is contained in:
parent
3029bf31cb
commit
1744ec43e6
23
.github/workflows/docs-develop.yml
vendored
Normal file
23
.github/workflows/docs-develop.yml
vendored
Normal file
@ -0,0 +1,23 @@
|
||||
name: Publish development docs
|
||||
on:
|
||||
push:
|
||||
branches: ['master']
|
||||
|
||||
jobs:
|
||||
main:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- uses: actions/setup-python@v2
|
||||
with:
|
||||
python-version: 3.8
|
||||
- uses: actions/cache@v2
|
||||
with:
|
||||
path: ~/.cache/pip3
|
||||
key: ${{ runner.os }}-pip-${{ hashFiles('docs/requirements.txt') }}
|
||||
- run: pip3 install -r docs/requirements.txt
|
||||
- run: git config --global user.email "github-action@users.noreply.github.com"
|
||||
- run: git config --global user.name "GitHub Action"
|
||||
- run: mike deploy --push master
|
24
.github/workflows/docs-release.yml
vendored
Normal file
24
.github/workflows/docs-release.yml
vendored
Normal file
@ -0,0 +1,24 @@
|
||||
name: Publish release docs
|
||||
on:
|
||||
release:
|
||||
types: [released]
|
||||
|
||||
jobs:
|
||||
main:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- uses: actions/setup-python@v2
|
||||
with:
|
||||
python-version: 3.8
|
||||
- uses: actions/cache@v2
|
||||
with:
|
||||
path: ~/.cache/pip3
|
||||
key: ${{ runner.os }}-pip-${{ hashFiles('docs/requirements.txt') }}
|
||||
- run: pip3 install -r docs/requirements.txt
|
||||
- run: git config --global user.email "github-action@users.noreply.github.com"
|
||||
- run: git config --global user.name "GitHub Action"
|
||||
- run: echo "RELEASE_VERSION=${GITHUB_REF:10}" >> $GITHUB_ENV
|
||||
- run: mike deploy --push --update-aliases $RELEASE_VERSION latest
|
14
README.md
14
README.md
@ -9,9 +9,13 @@ The compiler is currently being used three places
|
||||
|
||||
## Documentation
|
||||
|
||||
* [Smart Contracts on aeternity Blockchain](https://github.com/aeternity/protocol/blob/master/contracts/contracts.md).
|
||||
* [Sophia Documentation](docs/sophia.md).
|
||||
* [Sophia Standard Library](docs/sophia_stdlib.md).
|
||||
* [Introduction](docs/index.md)
|
||||
* [Syntax](docs/sophia_syntax.md)
|
||||
* [Features](docs/sophia_features.md)
|
||||
* [Standard Library](docs/sophia_stdlib.md)
|
||||
* [Contract Examples](docs/sophia_examples.md)
|
||||
|
||||
Additionally you can check out the [contracts section](https://github.com/aeternity/protocol/blob/master/contracts/contracts.md) of the aeternity blockchain specification.
|
||||
|
||||
## Versioning
|
||||
|
||||
@ -26,5 +30,5 @@ Versioning should follow the [semantic versioning](https://semver.org/spec/v2.0.
|
||||
|
||||
The basic modules for interfacing the compiler:
|
||||
|
||||
* [aeso_compiler: the Sophia compiler](./docs/aeso_compiler.md)
|
||||
* [aeso_aci: the ACI interface](./docs/aeso_aci.md)
|
||||
* [aeso_compiler: the Sophia compiler](docs/aeso_compiler.md)
|
||||
* [aeso_aci: the ACI interface](docs/aeso_aci.md)
|
||||
|
2
docs/.gitignore
vendored
Normal file
2
docs/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
__pycache__
|
||||
CHANGELOG.md
|
BIN
docs/images/favicon.png
Normal file
BIN
docs/images/favicon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.0 KiB |
12
docs/index.md
Normal file
12
docs/index.md
Normal file
@ -0,0 +1,12 @@
|
||||
# Introduction
|
||||
Sophia is a language in the ML family designed for smart contract development. It is strongly typed and has
|
||||
restricted mutable state.
|
||||
|
||||
Sophia is customized for smart contracts, which can be published
|
||||
to a blockchain. Thus some features of conventional
|
||||
languages, such as floating point arithmetic, are not present in Sophia, and
|
||||
some [aeternity blockchain](https://aeternity.com) specific primitives, constructions and types have been added.
|
||||
|
||||
!!! Note
|
||||
- For rapid prototyping of smart contracts check out [AEstudio](https://studio.aepps.com/)!
|
||||
- For playing around with the language in general check out the [REPL](https://repl.aeternity.io/)!
|
8
docs/mkdocs-overrides/main.html
Normal file
8
docs/mkdocs-overrides/main.html
Normal file
@ -0,0 +1,8 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block outdated %}
|
||||
You're not viewing the latest version.
|
||||
<a href="{{ '../' ~ base_url }}">
|
||||
<strong>Click here to go to latest.</strong>
|
||||
</a>
|
||||
{% endblock %}
|
4
docs/python/hooks.py
Normal file
4
docs/python/hooks.py
Normal file
@ -0,0 +1,4 @@
|
||||
import shutil
|
||||
|
||||
def pre_build(**kwargs):
|
||||
shutil.copy('./CHANGELOG.md', './docs')
|
4
docs/python/requirements.txt
Normal file
4
docs/python/requirements.txt
Normal file
@ -0,0 +1,4 @@
|
||||
mkdocs==1.2.1
|
||||
mkdocs-simple-hooks==0.1.3
|
||||
mkdocs-material==7.1.9
|
||||
mike==1.0.1
|
67
docs/sophia_examples.md
Normal file
67
docs/sophia_examples.md
Normal file
@ -0,0 +1,67 @@
|
||||
# Contract Examples
|
||||
|
||||
## Crowdfunding
|
||||
```sophia
|
||||
/*
|
||||
* A simple crowd-funding example
|
||||
*/
|
||||
contract FundMe =
|
||||
|
||||
record spend_args = { recipient : address,
|
||||
amount : int }
|
||||
|
||||
record state = { contributions : map(address, int),
|
||||
total : int,
|
||||
beneficiary : address,
|
||||
deadline : int,
|
||||
goal : int }
|
||||
|
||||
stateful function spend(args : spend_args) =
|
||||
Chain.spend(args.recipient, args.amount)
|
||||
|
||||
entrypoint init(beneficiary, deadline, goal) : state =
|
||||
{ contributions = {},
|
||||
beneficiary = beneficiary,
|
||||
deadline = deadline,
|
||||
total = 0,
|
||||
goal = goal }
|
||||
|
||||
function is_contributor(addr) =
|
||||
Map.member(addr, state.contributions)
|
||||
|
||||
stateful entrypoint contribute() =
|
||||
if(Chain.block_height >= state.deadline)
|
||||
spend({ recipient = Call.caller, amount = Call.value }) // Refund money
|
||||
false
|
||||
else
|
||||
let amount =
|
||||
switch(Map.lookup(Call.caller, state.contributions))
|
||||
None => Call.value
|
||||
Some(n) => n + Call.value
|
||||
put(state{ contributions[Call.caller] = amount,
|
||||
total @ tot = tot + Call.value })
|
||||
true
|
||||
|
||||
stateful entrypoint withdraw() =
|
||||
if(Chain.block_height < state.deadline)
|
||||
abort("Cannot withdraw before deadline")
|
||||
if(Call.caller == state.beneficiary)
|
||||
withdraw_beneficiary()
|
||||
elif(is_contributor(Call.caller))
|
||||
withdraw_contributor()
|
||||
else
|
||||
abort("Not a contributor or beneficiary")
|
||||
|
||||
stateful function withdraw_beneficiary() =
|
||||
require(state.total >= state.goal, "Project was not funded")
|
||||
spend({recipient = state.beneficiary,
|
||||
amount = Contract.balance })
|
||||
|
||||
stateful function withdraw_contributor() =
|
||||
if(state.total >= state.goal)
|
||||
abort("Project was funded")
|
||||
let to = Call.caller
|
||||
spend({recipient = to,
|
||||
amount = state.contributions[to]})
|
||||
put(state{ contributions @ c = Map.delete(to, c) })
|
||||
```
|
@ -1,76 +1,5 @@
|
||||
<!-- IMPORTANT: REMEMBER TO UPDATE THE TABLE OF CONTENTS AFTER YOUR EDIT -->
|
||||
|
||||
# The Sophia Language
|
||||
An Æternity BlockChain Language
|
||||
|
||||
The Sophia is a language in the ML family. It is strongly typed and has
|
||||
restricted mutable state.
|
||||
|
||||
Sophia is customized for smart contracts, which can be published
|
||||
to a blockchain (the Æternity BlockChain). Thus some features of conventional
|
||||
languages, such as floating point arithmetic, are not present in Sophia, and
|
||||
some blockchain specific primitives, constructions and types have been added.
|
||||
|
||||
**Table of Contents**
|
||||
|
||||
- [Language Features](#language-features)
|
||||
- [Contracts](#contracts)
|
||||
- [Calling other contracts](#calling-other-contracts)
|
||||
- [Protected contract calls](#protected-contract-calls)
|
||||
- [Contract factories and child contracts](#contract-factories-and-child-contracts)
|
||||
- [Mutable state](#mutable-state)
|
||||
- [Stateful functions](#stateful-functions)
|
||||
- [Payable](#payable)
|
||||
- [Payable contracts](#payable-contracts)
|
||||
- [Payable entrypoints](#payable-entrypoints)
|
||||
- [Namespaces](#namespaces)
|
||||
- [Splitting code over multiple files](#splitting-code-over-multiple-files)
|
||||
- [Standard library](#standard-library)
|
||||
- [Types](#types)
|
||||
- [Literals](#literals)
|
||||
- [Arithmetic](#arithmetic)
|
||||
- [Bit fields](#bit-fields)
|
||||
- [Type aliases](#type-aliases)
|
||||
- [Algebraic data types](#algebraic-data-types)
|
||||
- [Lists](#lists)
|
||||
- [Maps and records](#maps-and-records)
|
||||
- [Constructing maps and records](#constructing-maps-and-records)
|
||||
- [Accessing values](#accessing-values)
|
||||
- [Updating a value](#updating-a-value)
|
||||
- [Map implementation](#map-implementation)
|
||||
- [Strings](#strings)
|
||||
- [Chars](#chars)
|
||||
- [Byte arrays](#byte-arrays)
|
||||
- [Cryptographic builins](#cryptographic-builins)
|
||||
- [AEVM note](#aevm-note)
|
||||
- [Authorization interface](#authorization-interface)
|
||||
- [Oracle interface](#oracle-interface)
|
||||
- [Example](#example)
|
||||
- [Sanity checks](#sanity-checks)
|
||||
- [AENS interface](#aens-interface)
|
||||
- [Example](#example)
|
||||
- [Events](#events)
|
||||
- [Argument order](#argument-order)
|
||||
- [Compiler pragmas](#compiler-pragmas)
|
||||
- [Exceptions](#exceptions)
|
||||
- [Syntax](#syntax)
|
||||
- [Lexical syntax](#lexical-syntax)
|
||||
- [Comments](#comments)
|
||||
- [Keywords](#keywords)
|
||||
- [Tokens](#tokens)
|
||||
- [Layout blocks](#layout-blocks)
|
||||
- [Notation](#notation)
|
||||
- [Declarations](#declarations)
|
||||
- [Types](#types)
|
||||
- [Statements](#statements)
|
||||
- [Expressions](#expressions)
|
||||
- [Operators types](#operators-types)
|
||||
- [Operator precendences](#operator-precendences)
|
||||
- [Examples](#examples)
|
||||
- [Delegation signature](#delegation-signature)
|
||||
|
||||
## Language Features
|
||||
### Contracts
|
||||
# Features
|
||||
## Contracts
|
||||
|
||||
The main unit of code in Sophia is the *contract*.
|
||||
|
||||
@ -85,10 +14,10 @@ The main unit of code in Sophia is the *contract*.
|
||||
state is initialized to its return value.
|
||||
|
||||
The language offers some primitive functions to interact with the blockchain and contracts.
|
||||
Please refer to the [Chain](sophia_stdlib.md#Chain), [Contract](sophia_stdlib.md#Contract)
|
||||
and the [Call](sophia_stdlib.md#Call) namespaces in the documentation.
|
||||
Please refer to the [Chain](sophia_stdlib.md#chain), [Contract](sophia_stdlib.md#contract)
|
||||
and the [Call](sophia_stdlib.md#call) namespaces in the documentation.
|
||||
|
||||
#### Calling other contracts
|
||||
### Calling other contracts
|
||||
|
||||
To call a function in another contract you need the address to an instance of
|
||||
the contract. The type of the address must be a contract type, which consists
|
||||
@ -141,7 +70,7 @@ without calling it you can write
|
||||
Chain.spend(v.address, amount)
|
||||
```
|
||||
|
||||
#### Protected contract calls
|
||||
### Protected contract calls
|
||||
|
||||
If a contract call fails for any reason (for instance, the remote contract
|
||||
crashes or runs out of gas, or the entrypoint doesn't exist or has the wrong
|
||||
@ -171,7 +100,7 @@ However, note that errors that would normally consume all the gas in the
|
||||
transaction still only uses up the gas spent running the contract.
|
||||
|
||||
|
||||
#### Contract factories and child contracts
|
||||
### Contract factories and child contracts
|
||||
|
||||
Since the version 6.0.0 Sophia supports deploying contracts by other
|
||||
contracts. This can be done in two ways:
|
||||
@ -187,7 +116,7 @@ While `Chain.clone` requires only a `contract interface` and a living instance
|
||||
of a given contract on the chain, `Chain.create` needs a full definition of a
|
||||
to-create contract defined by the standard `contract` syntax, for example
|
||||
|
||||
```
|
||||
```sophia
|
||||
contract IntHolder =
|
||||
type state = int
|
||||
entrypoint init(x) = x
|
||||
@ -203,7 +132,7 @@ In case of a presence of child contracts (`IntHolder` in this case), the main
|
||||
contract must be pointed out with the `main` keyword as shown in the example.
|
||||
|
||||
|
||||
### Mutable state
|
||||
## Mutable state
|
||||
|
||||
Sophia does not have arbitrary mutable state, but only a limited form of state
|
||||
associated with each contract instance.
|
||||
@ -226,7 +155,7 @@ associated with each contract instance.
|
||||
To make it convenient to update parts of a deeply nested state Sophia
|
||||
provides special syntax for map/record updates.
|
||||
|
||||
#### Stateful functions
|
||||
### Stateful functions
|
||||
|
||||
Top-level functions and entrypoints must be annotated with the
|
||||
`stateful` keyword to be allowed to affect the state of the running contract.
|
||||
@ -261,9 +190,9 @@ A `stateful` annotation *is not* required to
|
||||
* Issue an event using the `event` function.
|
||||
* Call another contract with `value = 0`, even if the called function is stateful.
|
||||
|
||||
### Payable
|
||||
## Payable
|
||||
|
||||
#### Payable contracts
|
||||
### Payable contracts
|
||||
|
||||
A concrete contract is by default *not* payable. Any attempt at spending to such
|
||||
a contract (either a `Chain.spend` or a normal spend transaction) will fail. If a
|
||||
@ -278,7 +207,7 @@ payable contract ExampleContract =
|
||||
If in doubt, it is possible to check if an address is payable using
|
||||
`Address.is_payable(addr)`.
|
||||
|
||||
#### Payable entrypoints
|
||||
### Payable entrypoints
|
||||
|
||||
A contract entrypoint is by default *not* payable. Any call to such a function
|
||||
(either a [Remote call](#calling-other-contracts) or a contract call transaction)
|
||||
@ -296,7 +225,7 @@ payable stateful entrypoint buy(to : address) =
|
||||
Note: In the Aeternity VM (AEVM) contracts and entrypoints were by default
|
||||
payable until the Lima release.
|
||||
|
||||
### Namespaces
|
||||
## Namespaces
|
||||
|
||||
Code can be split into libraries using the `namespace` construct. Namespaces
|
||||
can appear at the top-level and can contain type and function definitions, but
|
||||
@ -304,7 +233,7 @@ not entrypoints. Outside the namespace you can refer to the (non-private) names
|
||||
by qualifying them with the namespace (`Namespace.name`).
|
||||
For example,
|
||||
|
||||
```
|
||||
```sophia
|
||||
namespace Library =
|
||||
type number = int
|
||||
function inc(x : number) : number = x + 1
|
||||
@ -319,22 +248,21 @@ Functions in namespaces have access to the same environment (including the
|
||||
with the exception of `state`, `put` and `Chain.event` since these are
|
||||
dependent on the specific state and event types of the contract.
|
||||
|
||||
### Splitting code over multiple files
|
||||
|
||||
## Splitting code over multiple files
|
||||
|
||||
Code from another file can be included in a contract using an `include`
|
||||
statement. These must appear at the top-level (outside the main contract). The
|
||||
included file can contain one or more namespaces and abstract contracts. For
|
||||
example, if the file `library.aes` contains
|
||||
|
||||
```
|
||||
```sophia
|
||||
namespace Library =
|
||||
function inc(x) = x + 1
|
||||
```
|
||||
|
||||
you can use it from another file using an `include`:
|
||||
|
||||
```
|
||||
```sophia
|
||||
include "library.aes"
|
||||
contract MyContract =
|
||||
entrypoint plus2(x) = Library.inc(Library.inc(x))
|
||||
@ -345,7 +273,7 @@ the file, except that error messages will refer to the original source
|
||||
locations. The language will try to include each file at most one time automatically,
|
||||
so even cyclic includes should be working without any special tinkering.
|
||||
|
||||
### Standard library
|
||||
## Standard library
|
||||
|
||||
Sophia offers [standard library](sophia_stdlib.md) which exposes some
|
||||
primitive operations and some higher level utilities. The builtin
|
||||
@ -353,7 +281,7 @@ namespaces like `Chain`, `Contract`, `Map`
|
||||
are included by default and are supported internally by the compiler.
|
||||
Others like `List`, `Frac`, `Option` need to be manually included using the
|
||||
`include` directive. For example
|
||||
```
|
||||
```sophia
|
||||
include "List.aes"
|
||||
include "Pair.aes"
|
||||
-- Map is already there!
|
||||
@ -363,7 +291,7 @@ namespace C =
|
||||
List.map(Pair.fst, (Map.to_list(m)))
|
||||
```
|
||||
|
||||
### Types
|
||||
## Types
|
||||
Sophia has the following types:
|
||||
|
||||
| Type | Description | Example |
|
||||
@ -389,7 +317,7 @@ Sophia has the following types:
|
||||
| oracle_query('a, 'b) | A specific oracle query | ```Oracle.query(o, q, qfee, qttl, rttl)``` |
|
||||
| contract | A user defined, typed, contract address | ```function call_remote(r : RemoteContract) = r.fun()``` |
|
||||
|
||||
### Literals
|
||||
## Literals
|
||||
| Type | Constant/Literal example(s) |
|
||||
| ---------- | ------------------------------- |
|
||||
| int | `-1`, `2425`, `4598275923475723498573485768` |
|
||||
@ -412,7 +340,7 @@ Sophia has the following types:
|
||||
| oracle_query('a, 'b) | `oq_2oRvyowJuJnEkxy58Ckkw77XfWJrmRgmGaLzhdqb67SKEL1gPY` |
|
||||
| contract | `ct_Ez6MyeTMm17YnTnDdHTSrzMEBKmy7Uz2sXu347bTDPgVH2ifJ` |
|
||||
|
||||
### Arithmetic
|
||||
## Arithmetic
|
||||
|
||||
Sophia integers (`int`) are represented by 256-bit (AEVM) or arbitrary-sized (FATE) signed words and supports the following
|
||||
arithmetic operations:
|
||||
@ -431,17 +359,17 @@ fails rather than wrapping around to -2²⁵⁵.
|
||||
The division and modulo operations also throw an arithmetic error if the
|
||||
second argument is zero.
|
||||
|
||||
### Bit fields
|
||||
## Bit fields
|
||||
|
||||
Sophia integers do not support bit arithmetic. Instead there is a separate
|
||||
type `bits`. See the standard library [documentation](sophia_stdlib.md#Bits).
|
||||
type `bits`. See the standard library [documentation](sophia_stdlib.md#bits).
|
||||
|
||||
On the AEVM a bit field is represented by a 256-bit word and reading or writing
|
||||
a bit outside the 0..255 range fails with an `arithmetic_error`. On FATE a bit
|
||||
field can be of arbitrary size (but it is still represented by the
|
||||
corresponding integer, so setting very high bits can be expensive).
|
||||
|
||||
### Type aliases
|
||||
## Type aliases
|
||||
|
||||
Type aliases can be introduced with the `type` keyword and can be
|
||||
parameterized. For instance
|
||||
@ -454,13 +382,13 @@ type string_map('a) = map(string, 'a)
|
||||
A type alias and its definition can be used interchangeably. Sophia does not support
|
||||
higher-kinded types, meaning that following type alias is invalid: `type wrap('f, 'a) = 'f('a)`
|
||||
|
||||
### Algebraic data types
|
||||
## Algebraic data types
|
||||
|
||||
Sophia supports algebraic data types (variant types) and pattern matching. Data
|
||||
types are declared by giving a list of constructors with
|
||||
their respective arguments. For instance,
|
||||
|
||||
```
|
||||
```sophia
|
||||
datatype one_or_both('a, 'b) = Left('a) | Right('b) | Both('a, 'b)
|
||||
```
|
||||
|
||||
@ -485,7 +413,7 @@ function
|
||||
|
||||
*NOTE: Data types cannot currently be recursive.*
|
||||
|
||||
### Lists
|
||||
## Lists
|
||||
|
||||
A Sophia list is a dynamically sized, homogenous, immutable, singly
|
||||
linked list. A list is constructed with the syntax `[1, 2, 3]`. The
|
||||
@ -519,9 +447,9 @@ Lists can be constructed using the range syntax using special `..` operator:
|
||||
The ranges are always ascending and have step equal to 1.
|
||||
|
||||
|
||||
Please refer to the [standard library](sophia_stdlib.md#List) for the predefined functionalities.
|
||||
Please refer to the [standard library](sophia_stdlib.md#list) for the predefined functionalities.
|
||||
|
||||
### Maps and records
|
||||
## Maps and records
|
||||
|
||||
A Sophia record type is given by a fixed set of fields with associated,
|
||||
possibly different, types. For instance
|
||||
@ -536,9 +464,9 @@ but of a fixed type. The type of maps with keys of type `'k` and values of type
|
||||
`'v` is written `map('k, 'v)`. The key type can be any type that does not
|
||||
contain a map or a function type.
|
||||
|
||||
Please refer to the [standard library](sophia_stdlib.md#Map) for the predefined functionalities.
|
||||
Please refer to the [standard library](sophia_stdlib.md#map) for the predefined functionalities.
|
||||
|
||||
#### Constructing maps and records
|
||||
### Constructing maps and records
|
||||
|
||||
A value of record type is constructed by giving a value for each of the fields.
|
||||
For the example above,
|
||||
@ -553,7 +481,7 @@ Maps are constructed similarly, with keys enclosed in square brackets
|
||||
```
|
||||
The empty map is written `{}`.
|
||||
|
||||
#### Accessing values
|
||||
### Accessing values
|
||||
|
||||
Record fields access is written `r.f` and map lookup `m[k]`. For instance,
|
||||
```sophia
|
||||
@ -564,7 +492,7 @@ Looking up a non-existing key in a map results in contract execution failing. A
|
||||
default value to return for non-existing keys can be provided using the syntax
|
||||
`m[k = default]`. See also `Map.member` and `Map.lookup` below.
|
||||
|
||||
#### Updating a value
|
||||
### Updating a value
|
||||
|
||||
Record field updates are written `r{f = v}`. This creates a new record value
|
||||
which is the same as `r`, but with the value of the field `f` replaced by `v`.
|
||||
@ -592,54 +520,45 @@ an account if `a` is not in the map you can write (given a function `empty_accou
|
||||
accounts{ [a = empty_account()].history = [] }
|
||||
```
|
||||
|
||||
#### Map implementation
|
||||
### Map implementation
|
||||
|
||||
Internally in the VM maps are implemented as hash maps and support fast lookup
|
||||
and update. Large maps can be stored in the contract state and the size of the
|
||||
map does not contribute to the gas costs of a contract call reading or updating
|
||||
it.
|
||||
|
||||
### Strings
|
||||
## Strings
|
||||
|
||||
There is a builtin type `string`, which can be seen as an array of bytes.
|
||||
Strings can be compared for equality (`==`, `!=`), used as keys in maps and
|
||||
records, and used in builtin functions `String.length`, `String.concat` and
|
||||
the hash functions described below.
|
||||
|
||||
Please refer to the `String` [library documentation](sophia_stdlib.md#String).
|
||||
Please refer to the `String` [library documentation](sophia_stdlib.md#string).
|
||||
|
||||
### Chars
|
||||
## Chars
|
||||
|
||||
There is a builtin type `char` (the underlying representation being an integer),
|
||||
mainly used to manipulate strings via `String.to_list`/`String.from_list`.
|
||||
|
||||
Characters can also be introduced as character literals (`'x', '+', ...).
|
||||
|
||||
Please refer to the `Char` [library documentation](sophia_stdlib.md#Char).
|
||||
Please refer to the `Char` [library documentation](sophia_stdlib.md#char).
|
||||
|
||||
### Byte arrays
|
||||
## Byte arrays
|
||||
|
||||
Byte arrays are fixed size arrays of 8-bit integers. They are described in hexadecimal system,
|
||||
for example the literal `#cafe` creates a two-element array of bytes `ca` (202) and `fe` (254)
|
||||
and thus is a value of type `bytes(2)`.
|
||||
|
||||
Please refer to the `Bytes` [library documentation](sophia_stdlib.md#Bytes).
|
||||
Please refer to the `Bytes` [library documentation](sophia_stdlib.md#bytes).
|
||||
|
||||
## Cryptographic builtins
|
||||
|
||||
### Cryptographic builins
|
||||
|
||||
Libraries [Crypto](sophia_stdlib.md#Crypto) and [String](sophia_stdlib.md#String) provide functions to
|
||||
Libraries [Crypto](sophia_stdlib.md#crypto) and [String](sophia_stdlib.md#string) provide functions to
|
||||
hash objects, verify signatures etc. The `hash` is a type alias for `bytes(32)`.
|
||||
|
||||
#### AEVM note
|
||||
The hash functions in `String` hash strings interpreted as byte arrays, and
|
||||
the `Crypto` hash functions accept an element of any (first-order) type. The
|
||||
result is the hash of the binary encoding of the argument as [described
|
||||
below](#encoding-sophia-values-as-binaries). Note that this means that for `s :
|
||||
string`, `String.sha3(s)` and `Crypto.sha3(s)` will give different results on AEVM.
|
||||
|
||||
|
||||
### Authorization interface
|
||||
## Authorization interface
|
||||
|
||||
When a Generalized account is authorized, the authorization function needs
|
||||
access to the transaction and the transaction hash for the wrapped transaction. (A `GAMetaTx`
|
||||
@ -647,16 +566,15 @@ wrapping a transaction.) The transaction and the transaction hash is available i
|
||||
`Auth.tx` and `Auth.tx_hash` respectively, they are *only* available during authentication if invoked by a
|
||||
normal contract call they return `None`.
|
||||
|
||||
### Oracle interface
|
||||
## Oracle interface
|
||||
You can attach an oracle to the current contract and you can interact with oracles
|
||||
through the Oracle interface.
|
||||
|
||||
For a full description of how Oracle works see
|
||||
[Oracles](https://github.com/aeternity/protocol/blob/master/oracles/oracles.md#oracles).
|
||||
For a functionality documentation refer to the [standard library](sophia_stdlib.md#Oracle).
|
||||
For a functionality documentation refer to the [standard library](sophia_stdlib.md#oracle).
|
||||
|
||||
|
||||
#### Example
|
||||
### Example
|
||||
|
||||
Example for an oracle answering questions of type `string` with answers of type `int`:
|
||||
```sophia
|
||||
@ -709,19 +627,19 @@ contract Oracles =
|
||||
Oracle.get_answer(o, q)
|
||||
```
|
||||
|
||||
#### Sanity checks
|
||||
### Sanity checks
|
||||
|
||||
When an Oracle literal is passed to a contract, no deep checks are performed.
|
||||
For extra safety [Oracle.check](sophia_stdlib.md#check) and [Oracle.check_query](sophia_stdlib.md#check_query)
|
||||
functions are provided.
|
||||
|
||||
### AENS interface
|
||||
## AENS interface
|
||||
|
||||
Contracts can interact with the
|
||||
[Aeternity Naming System](https://github.com/aeternity/protocol/blob/master/AENS.md).
|
||||
For this purpose the [AENS](sophia_stdlib.md#AENS) library was exposed.
|
||||
For this purpose the [AENS](sophia_stdlib.md#aens) library was exposed.
|
||||
|
||||
#### Example
|
||||
### Example
|
||||
|
||||
In this example we assume that the name `name` already exists, and is owned by
|
||||
an account with address `addr`. In order to allow a contract `ct` to handle
|
||||
@ -762,7 +680,7 @@ name:
|
||||
a Sophia contract lookup or update (bad) legacy pointers, the bad keys are
|
||||
automatically removed so they will not appear in the pointers map.
|
||||
|
||||
### Events
|
||||
## Events
|
||||
|
||||
Sophia contracts log structured messages to an event log in the resulting
|
||||
blockchain transaction. The event log is quite similar to [Events in
|
||||
@ -773,7 +691,7 @@ Events are further discussed in the [protocol](https://github.com/aeternity/prot
|
||||
To use events a contract must declare a datatype `event`, and events are then
|
||||
logged using the `Chain.event` function:
|
||||
|
||||
```
|
||||
```sophia
|
||||
datatype event
|
||||
= Event1(int, int, string)
|
||||
| Event2(string, address)
|
||||
@ -806,7 +724,7 @@ will emit one Event of each kind in the example.
|
||||
Chain.event(Event2("This is not indexed", Contract.address))
|
||||
```
|
||||
|
||||
#### Argument order
|
||||
### Argument order
|
||||
|
||||
It is only possible to have one (1) `string` parameter in the event, but it can
|
||||
be placed in any position (and its value will end up in the `data` field), i.e.
|
||||
@ -819,14 +737,14 @@ Chain.event(AnotherEvent("This is not indexed", Contract.address))
|
||||
```
|
||||
would yield exactly the same result in the example above!
|
||||
|
||||
### Compiler pragmas
|
||||
## Compiler pragmas
|
||||
|
||||
To enforce that a contract is only compiled with specific versions of the
|
||||
Sophia compiler, you can give one or more `@compiler` pragmas at the
|
||||
top-level (typically at the beginning) of a file. For instance, to enforce that
|
||||
a contract is compiled with version 4.3 of the compiler you write
|
||||
|
||||
```
|
||||
```sophia
|
||||
@compiler >= 4.3
|
||||
@compiler < 4.4
|
||||
```
|
||||
@ -836,11 +754,11 @@ numbers are given as a sequence of non-negative integers separated by dots.
|
||||
Trailing zeros are ignored, so `4.0.0 == 4`. If a constraint is violated an
|
||||
error is reported and compilation fails.
|
||||
|
||||
### Exceptions
|
||||
## Exceptions
|
||||
|
||||
Contracts can fail with an (uncatchable) exception using the built-in function
|
||||
|
||||
```
|
||||
```sophia
|
||||
abort(reason : string) : 'a
|
||||
```
|
||||
|
||||
@ -851,342 +769,12 @@ consumes all available gas.
|
||||
|
||||
For convenience the following function is also built-in:
|
||||
|
||||
```
|
||||
```sophia
|
||||
function require(b : bool, err : string) =
|
||||
if(!b) abort(err)
|
||||
```
|
||||
|
||||
## Syntax
|
||||
|
||||
### Lexical syntax
|
||||
|
||||
#### Comments
|
||||
|
||||
Single line comments start with `//` and block comments are enclosed in `/*`
|
||||
and `*/` and can be nested.
|
||||
|
||||
#### Keywords
|
||||
|
||||
```
|
||||
contract elif else entrypoint false function if import include let mod namespace
|
||||
private payable stateful switch true type record datatype main interface
|
||||
```
|
||||
|
||||
#### Tokens
|
||||
|
||||
- `Id = [a-z_][A-Za-z0-9_']*` identifiers start with a lower case letter.
|
||||
- `Con = [A-Z][A-Za-z0-9_']*` constructors start with an upper case letter.
|
||||
- `QId = (Con\.)+Id` qualified identifiers (e.g. `Map.member`)
|
||||
- `QCon = (Con\.)+Con` qualified constructor
|
||||
- `TVar = 'Id` type variable (e.g `'a`, `'b`)
|
||||
- `Int = [0-9]+(_[0-9]+)*|0x[0-9A-Fa-f]+(_[0-9A-Fa-f]+)*` integer literal with optional `_` separators
|
||||
- `Bytes = #[0-9A-Fa-f]+(_[0-9A-Fa-f]+)*` byte array literal with optional `_` separators
|
||||
- `String` string literal enclosed in `"` with escape character `\`
|
||||
- `Char` character literal enclosed in `'` with escape character `\`
|
||||
- `AccountAddress` base58-encoded 32 byte account pubkey with `ak_` prefix
|
||||
- `ContractAddress` base58-encoded 32 byte contract address with `ct_` prefix
|
||||
- `OracleAddress` base58-encoded 32 byte oracle address with `ok_` prefix
|
||||
- `OracleQueryId` base58-encoded 32 byte oracle query id with `oq_` prefix
|
||||
|
||||
Valid string escape codes are
|
||||
|
||||
| Escape | ASCII | |
|
||||
|---------------|-------------|---|
|
||||
| `\b` | 8 | |
|
||||
| `\t` | 9 | |
|
||||
| `\n` | 10 | |
|
||||
| `\v` | 11 | |
|
||||
| `\f` | 12 | |
|
||||
| `\r` | 13 | |
|
||||
| `\e` | 27 | |
|
||||
| `\xHexDigits` | *HexDigits* | |
|
||||
|
||||
|
||||
See the [identifier encoding scheme](https://github.com/aeternity/protocol/blob/master/node/api/api_encoding.md) for the
|
||||
details on the base58 literals.
|
||||
|
||||
### Layout blocks
|
||||
|
||||
Sophia uses Python-style layout rules to group declarations and statements. A
|
||||
layout block with more than one element must start on a separate line and be
|
||||
indented more than the currently enclosing layout block. Blocks with a single
|
||||
element can be written on the same line as the previous token.
|
||||
|
||||
Each element of the block must share the same indentation and no part of an
|
||||
element may be indented less than the indentation of the block. For instance
|
||||
|
||||
```
|
||||
contract Layout =
|
||||
function foo() = 0 // no layout
|
||||
function bar() = // layout block starts on next line
|
||||
let x = foo() // indented more than 2 spaces
|
||||
x
|
||||
+ 1 // the '+' is indented more than the 'x'
|
||||
```
|
||||
|
||||
### Notation
|
||||
|
||||
In describing the syntax below, we use the following conventions:
|
||||
- Upper-case identifiers denote non-terminals (like `Expr`) or terminals with
|
||||
some associated value (like `Id`).
|
||||
- Keywords and symbols are enclosed in single quotes: `'let'` or `'='`.
|
||||
- Choices are separated by vertical bars: `|`.
|
||||
- Optional elements are enclosed in `[` square brackets `]`.
|
||||
- `(` Parentheses `)` are used for grouping.
|
||||
- Zero or more repetitions are denoted by a postfix `*`, and one or more
|
||||
repetitions by a `+`.
|
||||
- `Block(X)` denotes a layout block of `X`s.
|
||||
- `Sep(X, S)` is short for `[X (S X)*]`, i.e. a possibly empty sequence of `X`s
|
||||
separated by `S`s.
|
||||
- `Sep1(X, S)` is short for `X (S X)*`, i.e. same as `Sep`, but must not be empty.
|
||||
|
||||
|
||||
### Declarations
|
||||
|
||||
A Sophia file consists of a sequence of *declarations* in a layout block.
|
||||
|
||||
```c
|
||||
File ::= Block(TopDecl)
|
||||
|
||||
TopDecl ::= ['payable'] 'contract' Con '=' Block(Decl)
|
||||
| 'namespace' Con '=' Block(Decl)
|
||||
| '@compiler' PragmaOp Version
|
||||
| 'include' String
|
||||
|
||||
Decl ::= 'type' Id ['(' TVar* ')'] '=' TypeAlias
|
||||
| 'record' Id ['(' TVar* ')'] '=' RecordType
|
||||
| 'datatype' Id ['(' TVar* ')'] '=' DataType
|
||||
| (EModifier* 'entrypoint' | FModifier* 'function') Block(FunDecl)
|
||||
|
||||
FunDecl ::= Id ':' Type // Type signature
|
||||
| Id Args [':' Type] '=' Block(Stmt) // Definition
|
||||
|
||||
PragmaOp ::= '<' | '=<' | '==' | '>=' | '>'
|
||||
Version ::= Sep1(Int, '.')
|
||||
|
||||
EModifier ::= 'payable' | 'stateful'
|
||||
FModifier ::= 'stateful' | 'private'
|
||||
|
||||
Args ::= '(' Sep(Pattern, ',') ')'
|
||||
```
|
||||
|
||||
Contract declarations must appear at the top-level.
|
||||
|
||||
For example,
|
||||
```sophia
|
||||
contract Test =
|
||||
type t = int
|
||||
entrypoint add (x : t, y : t) = x + y
|
||||
```
|
||||
|
||||
There are three forms of type declarations: type aliases (declared with the
|
||||
`type` keyword), record type definitions (`record`) and data type definitions
|
||||
(`datatype`):
|
||||
|
||||
```c
|
||||
TypeAlias ::= Type
|
||||
RecordType ::= '{' Sep(FieldType, ',') '}'
|
||||
DataType ::= Sep1(ConDecl, '|')
|
||||
|
||||
FieldType ::= Id ':' Type
|
||||
ConDecl ::= Con ['(' Sep1(Type, ',') ')']
|
||||
```
|
||||
|
||||
For example,
|
||||
```
|
||||
record point('a) = {x : 'a, y : 'a}
|
||||
datatype shape('a) = Circle(point('a), 'a) | Rect(point('a), point('a))
|
||||
type int_shape = shape(int)
|
||||
```
|
||||
|
||||
### Types
|
||||
|
||||
```c
|
||||
Type ::= Domain '=>' Type // Function type
|
||||
| Type '(' Sep(Type, ',') ')' // Type application
|
||||
| '(' Type ')' // Parens
|
||||
| 'unit' | Sep(Type, '*') // Tuples
|
||||
| Id | QId | TVar
|
||||
|
||||
Domain ::= Type // Single argument
|
||||
| '(' Sep(Type, ',') ')' // Multiple arguments
|
||||
```
|
||||
|
||||
The function type arrow associates to the right.
|
||||
|
||||
Example,
|
||||
```
|
||||
'a => list('a) => (int * list('a))
|
||||
```
|
||||
|
||||
### Statements
|
||||
|
||||
Function bodies are blocks of *statements*, where a statement is one of the following
|
||||
|
||||
```c
|
||||
Stmt ::= 'switch' '(' Expr ')' Block(Case)
|
||||
| 'if' '(' Expr ')' Block(Stmt)
|
||||
| 'elif' '(' Expr ')' Block(Stmt)
|
||||
| 'else' Block(Stmt)
|
||||
| 'let' LetDef
|
||||
| Expr
|
||||
|
||||
LetDef ::= Id Args [':' Type] '=' Block(Stmt) // Function definition
|
||||
| Pattern '=' Block(Stmt) // Value definition
|
||||
|
||||
Case ::= Pattern '=>' Block(Stmt)
|
||||
Pattern ::= Expr
|
||||
```
|
||||
|
||||
`if` statements can be followed by zero or more `elif` statements and an optional final `else` statement. For example,
|
||||
|
||||
```
|
||||
let x : int = 4
|
||||
switch(f(x))
|
||||
None => 0
|
||||
Some(y) =>
|
||||
if(y > 10)
|
||||
"too big"
|
||||
elif(y < 3)
|
||||
"too small"
|
||||
else
|
||||
"just right"
|
||||
```
|
||||
|
||||
### Expressions
|
||||
|
||||
```c
|
||||
Expr ::= '(' LamArgs ')' '=>' Block(Stmt) // Anonymous function (x) => x + 1
|
||||
| 'if' '(' Expr ')' Expr 'else' Expr // If expression if(x < y) y else x
|
||||
| Expr ':' Type // Type annotation 5 : int
|
||||
| Expr BinOp Expr // Binary operator x + y
|
||||
| UnOp Expr // Unary operator ! b
|
||||
| Expr '(' Sep(Expr, ',') ')' // Application f(x, y)
|
||||
| Expr '.' Id // Projection state.x
|
||||
| Expr '[' Expr ']' // Map lookup map[key]
|
||||
| Expr '{' Sep(FieldUpdate, ',') '}' // Record or map update r{ fld[key].x = y }
|
||||
| '[' Sep(Expr, ',') ']' // List [1, 2, 3]
|
||||
| '[' Expr '|' Sep(Generator, ',') ']'
|
||||
// List comprehension [k | x <- [1], if (f(x)), let k = x+1]
|
||||
| '[' Expr '..' Expr ']' // List range [1..n]
|
||||
| '{' Sep(FieldUpdate, ',') '}' // Record or map value {x = 0, y = 1}, {[key] = val}
|
||||
| '(' Expr ')' // Parens (1 + 2) * 3
|
||||
| Id | Con | QId | QCon // Identifiers x, None, Map.member, AELib.Token
|
||||
| Int | Bytes | String | Char // Literals 123, 0xff, #00abc123, "foo", '%'
|
||||
| AccountAddress | ContractAddress // Chain identifiers
|
||||
| OracleAddress | OracleQueryId // Chain identifiers
|
||||
|
||||
Generator ::= Pattern '<-' Expr // Generator
|
||||
| 'if' '(' Expr ')' // Guard
|
||||
| LetDef // Definition
|
||||
|
||||
LamArgs ::= '(' Sep(LamArg, ',') ')'
|
||||
LamArg ::= Id [':' Type]
|
||||
|
||||
FieldUpdate ::= Path '=' Expr
|
||||
Path ::= Id // Record field
|
||||
| '[' Expr ']' // Map key
|
||||
| Path '.' Id // Nested record field
|
||||
| Path '[' Expr ']' // Nested map key
|
||||
|
||||
BinOp ::= '||' | '&&' | '<' | '>' | '=<' | '>=' | '==' | '!='
|
||||
| '::' | '++' | '+' | '-' | '*' | '/' | 'mod' | '^'
|
||||
UnOp ::= '-' | '!'
|
||||
```
|
||||
|
||||
### Operators types
|
||||
|
||||
| Operators | Type
|
||||
| --- | ---
|
||||
| `-` `+` `*` `/` `mod` `^` | arithmetic operators
|
||||
| `!` `&&` `\|\|` | logical operators
|
||||
| `==` `!=` `<` `>` `=<` `>=` | comparison operators
|
||||
| `::` `++` | list operators
|
||||
|
||||
### Operator precendences
|
||||
|
||||
In order of highest to lowest precedence.
|
||||
|
||||
| Operators | Associativity
|
||||
| --- | ---
|
||||
| `!` | right
|
||||
| `^` | left
|
||||
| `*` `/` `mod` | left
|
||||
| `-` (unary) | right
|
||||
| `+` `-` | left
|
||||
| `::` `++` | right
|
||||
| `<` `>` `=<` `>=` `==` `!=` | none
|
||||
| `&&` | right
|
||||
| `\|\|` | right
|
||||
|
||||
## Examples
|
||||
|
||||
```sophia
|
||||
/*
|
||||
* A simple crowd-funding example
|
||||
*/
|
||||
contract FundMe =
|
||||
|
||||
record spend_args = { recipient : address,
|
||||
amount : int }
|
||||
|
||||
record state = { contributions : map(address, int),
|
||||
total : int,
|
||||
beneficiary : address,
|
||||
deadline : int,
|
||||
goal : int }
|
||||
|
||||
stateful function spend(args : spend_args) =
|
||||
Chain.spend(args.recipient, args.amount)
|
||||
|
||||
entrypoint init(beneficiary, deadline, goal) : state =
|
||||
{ contributions = {},
|
||||
beneficiary = beneficiary,
|
||||
deadline = deadline,
|
||||
total = 0,
|
||||
goal = goal }
|
||||
|
||||
function is_contributor(addr) =
|
||||
Map.member(addr, state.contributions)
|
||||
|
||||
stateful entrypoint contribute() =
|
||||
if(Chain.block_height >= state.deadline)
|
||||
spend({ recipient = Call.caller, amount = Call.value }) // Refund money
|
||||
false
|
||||
else
|
||||
let amount =
|
||||
switch(Map.lookup(Call.caller, state.contributions))
|
||||
None => Call.value
|
||||
Some(n) => n + Call.value
|
||||
put(state{ contributions[Call.caller] = amount,
|
||||
total @ tot = tot + Call.value })
|
||||
true
|
||||
|
||||
stateful entrypoint withdraw() =
|
||||
if(Chain.block_height < state.deadline)
|
||||
abort("Cannot withdraw before deadline")
|
||||
if(Call.caller == state.beneficiary)
|
||||
withdraw_beneficiary()
|
||||
elif(is_contributor(Call.caller))
|
||||
withdraw_contributor()
|
||||
else
|
||||
abort("Not a contributor or beneficiary")
|
||||
|
||||
stateful function withdraw_beneficiary() =
|
||||
require(state.total >= state.goal, "Project was not funded")
|
||||
spend({recipient = state.beneficiary,
|
||||
amount = Contract.balance })
|
||||
|
||||
stateful function withdraw_contributor() =
|
||||
if(state.total >= state.goal)
|
||||
abort("Project was funded")
|
||||
let to = Call.caller
|
||||
spend({recipient = to,
|
||||
amount = state.contributions[to]})
|
||||
put(state{ contributions @ c = Map.delete(to, c) })
|
||||
```
|
||||
|
||||
### Delegation signature
|
||||
## Delegation signature
|
||||
|
||||
Some chain operations (`Oracle.<operation>` and `AENS.<operation>`) have an
|
||||
optional delegation signature. This is typically used when a user/accounts
|
@ -5,26 +5,26 @@ check if the comments in the sources are up to date as well. You may find them
|
||||
in the priv/stdlib directory. Thanks!
|
||||
-->
|
||||
|
||||
# Standard library
|
||||
# Standard Library
|
||||
|
||||
Sophia language offers standard library that consists of several namespaces. Some of them are already
|
||||
in the scope and do not need any actions to be used, while the others require some files to be included.
|
||||
|
||||
The out-of-the-box namespaces are:
|
||||
|
||||
- [Bits](#Bits)
|
||||
- [Bytes](#Bytes)
|
||||
- [Char](#Char)
|
||||
- [Int](#Int)
|
||||
- [Map](#Map)
|
||||
- [Address](#Address)
|
||||
- [Crypto](#Crypto)
|
||||
- [Auth](#Auth)
|
||||
- [Oracle](#Oracle)
|
||||
- [AENS](#AENS)
|
||||
- [Contract](#Contract)
|
||||
- [Call](#Call)
|
||||
- [Chain](#Chain)
|
||||
- [Bits](#bits)
|
||||
- [Bytes](#bytes)
|
||||
- [Char](#char)
|
||||
- [Int](#int)
|
||||
- [Map](#map)
|
||||
- [Address](#address)
|
||||
- [Crypto](#crypto)
|
||||
- [Auth](#auth)
|
||||
- [Oracle](#oracle)
|
||||
- [AENS](#aens)
|
||||
- [Contract](#contract)
|
||||
- [Call](#call)
|
||||
- [Chain](#chain)
|
||||
|
||||
The following ones need to be included as regular files with `.aes` suffix, for example
|
||||
```
|
||||
@ -41,11 +41,11 @@ include "List.aes"
|
||||
- [Frac](#Frac)
|
||||
- [Set](#set-stdlib)
|
||||
|
||||
# Builtin namespaces
|
||||
## Builtin namespaces
|
||||
|
||||
They are available without any explicit includes.
|
||||
|
||||
## Bits
|
||||
### Bits
|
||||
|
||||
#### none
|
||||
```
|
||||
@ -119,7 +119,7 @@ Bits.difference(a : bits, b : bits) : bits
|
||||
Each bit is true if and only if it was 1 in `a` and 0 in `b`
|
||||
|
||||
|
||||
## Bytes
|
||||
### Bytes
|
||||
|
||||
#### to_int
|
||||
```
|
||||
@ -153,7 +153,7 @@ Bytes.split(a : bytes(m + n)) : bytes(m) * bytes(n)
|
||||
Splits a byte array at given index
|
||||
|
||||
|
||||
## Char
|
||||
### Char
|
||||
|
||||
#### to_int
|
||||
```
|
||||
@ -172,7 +172,7 @@ Char.from_int(i : int) : option(char)
|
||||
Opposite of [to_int](#to_int). Returns `None` if the integer doesn't correspond to a single (normalized) codepoint.
|
||||
|
||||
|
||||
## Int
|
||||
### Int
|
||||
|
||||
#### to_str
|
||||
```
|
||||
@ -182,7 +182,7 @@ Int.to_str : int => string
|
||||
Casts integer to string using decimal representation
|
||||
|
||||
|
||||
## Map
|
||||
### Map
|
||||
|
||||
#### lookup
|
||||
`Map.lookup(k : 'k, m : map('k, 'v)) : option('v)`
|
||||
@ -229,7 +229,7 @@ Turns a list of pairs of form `(key, value)` into a map
|
||||
|
||||
|
||||
|
||||
## Address
|
||||
### Address
|
||||
|
||||
#### to_str
|
||||
```
|
||||
@ -271,7 +271,7 @@ Address.to_contract(a : address) : C
|
||||
Cast address to contract type C (where `C` is a contract)
|
||||
|
||||
|
||||
## Crypto
|
||||
### Crypto
|
||||
|
||||
#### sha3
|
||||
```
|
||||
@ -328,7 +328,7 @@ Crypto.verify_sig_secp256k1(msg : hash, pubkey : bytes(64), sig : bytes(64)) : b
|
||||
<!-- TODO -->
|
||||
|
||||
|
||||
## Auth
|
||||
### Auth
|
||||
|
||||
|
||||
#### tx
|
||||
@ -368,7 +368,7 @@ Auth.tx_hash : option(hash)
|
||||
|
||||
Gets the transaction hash during authentication.
|
||||
|
||||
## Oracle
|
||||
### Oracle
|
||||
|
||||
#### register
|
||||
```
|
||||
@ -380,7 +380,7 @@ Registers new oracle answering questions of type `'a` with answers of type `'b`.
|
||||
* The `acct` is the address of the oracle to register (can be the same as the contract).
|
||||
* `signature` is a signature proving that the contract is allowed to register the account -
|
||||
the `network id` + `account address` + `contract address` (concatenated as byte arrays) is
|
||||
[signed](./sophia.md#delegation-signature) with the
|
||||
[signed](./sophia_features.md#delegation-signature) with the
|
||||
private key of the account, proving you have the private key of the oracle to be. If the
|
||||
address is the same as the contract `sign` is ignored and can be left out entirely.
|
||||
* The `qfee` is the minimum query fee to be paid by a user when asking a question of the oracle.
|
||||
@ -413,7 +413,7 @@ Responds to the question `q` on `o`.
|
||||
Unless the contract address is the same as the oracle address the `signature`
|
||||
(which is an optional, named argument)
|
||||
needs to be provided. Proving that we have the private key of the oracle by
|
||||
[signing](./sophia.md#delegation-signature)
|
||||
[signing](./sophia_features.md#delegation-signature)
|
||||
the `network id` + `oracle query id` + `contract address`
|
||||
|
||||
|
||||
@ -481,7 +481,7 @@ Oracle.check_query(o : oracle('a, 'b), q : oracle_query('a, 'b)) : bool
|
||||
It returns `true` iff the oracle query exist and has the expected type.
|
||||
|
||||
|
||||
## AENS
|
||||
### AENS
|
||||
|
||||
The following functionality is available for interacting with the Aeternity
|
||||
Naming System (AENS).
|
||||
@ -491,15 +491,15 @@ a signature to prove that we are allowed to do AENS operations on behalf of
|
||||
`owner`. The [signature is tied to a network id](https://github.com/aeternity/protocol/blob/iris/consensus/consensus.md#transaction-signature),
|
||||
i.e. the signature material should be prefixed by the network id.
|
||||
|
||||
### Types
|
||||
#### Types
|
||||
|
||||
#### name
|
||||
##### name
|
||||
```
|
||||
datatype name = Name(address, Chain.ttl, map(string, AENS.pointee))
|
||||
```
|
||||
|
||||
|
||||
#### pointee
|
||||
##### pointee
|
||||
|
||||
```
|
||||
datatype pointee = AccountPt(address) | OraclePt(address)
|
||||
@ -507,9 +507,9 @@ datatype pointee = AccountPt(address) | OraclePt(address)
|
||||
```
|
||||
|
||||
|
||||
### Functions
|
||||
#### Functions
|
||||
|
||||
#### resolve
|
||||
##### resolve
|
||||
```
|
||||
AENS.resolve(name : string, key : string) : option('a)
|
||||
```
|
||||
@ -520,7 +520,7 @@ associated with this name (for instance `"account_pubkey"`). The return type
|
||||
type checked against this type at run time.
|
||||
|
||||
|
||||
#### lookup
|
||||
##### lookup
|
||||
```
|
||||
AENS.lookup(name : string) : option(AENS.name)
|
||||
```
|
||||
@ -534,53 +534,53 @@ let Some(Name(owner, FixedTTL(expiry), ptrs)) = AENS.lookup("example.chain")
|
||||
```
|
||||
|
||||
|
||||
#### preclaim
|
||||
##### preclaim
|
||||
```
|
||||
AENS.preclaim(owner : address, commitment_hash : hash, <signature : signature>) : unit
|
||||
```
|
||||
|
||||
The [signature](./sophia.md#delegation-signature) should be over
|
||||
The [signature](./sophia_features.md#delegation-signature) should be over
|
||||
`network id` + `owner address` + `Contract.address` (concatenated as byte arrays).
|
||||
|
||||
|
||||
#### claim
|
||||
##### claim
|
||||
```
|
||||
AENS.claim(owner : address, name : string, salt : int, name_fee : int, <signature : signature>) : unit
|
||||
```
|
||||
|
||||
The [signature](./sophia.md#delegation-signature) should be over
|
||||
The [signature](./sophia_features.md#delegation-signature) should be over
|
||||
`network id` + `owner address` + `name_hash` + `Contract.address`
|
||||
(concatenated as byte arrays)
|
||||
using the private key of the `owner` account for signing.
|
||||
|
||||
|
||||
#### transfer
|
||||
##### transfer
|
||||
```
|
||||
AENS.transfer(owner : address, new_owner : address, name : string, <signature : signature>) : unit
|
||||
```
|
||||
|
||||
Transfers name to the new owner.
|
||||
|
||||
The [signature](./sophia.md#delegation-signature) should be over
|
||||
The [signature](./sophia_features.md#delegation-signature) should be over
|
||||
`network id` + `owner address` + `name_hash` + `Contract.address`
|
||||
(concatenated as byte arrays)
|
||||
using the private key of the `owner` account for signing.
|
||||
|
||||
|
||||
#### revoke
|
||||
##### revoke
|
||||
```
|
||||
AENS.revoke(owner : address, name : string, <signature : signature>) : unit
|
||||
```
|
||||
|
||||
Revokes the name to extend the ownership time.
|
||||
|
||||
The [signature](./sophia.md#delegation-signature) should be over
|
||||
The [signature](./sophia_features.md#delegation-signature) should be over
|
||||
`network id` + `owner address` + `name_hash` + `Contract.address`
|
||||
(concatenated as byte arrays)
|
||||
using the private key of the `owner` account for signing.
|
||||
|
||||
|
||||
#### update
|
||||
##### update
|
||||
```
|
||||
AENS.update(owner : address, name : string, expiry : option(Chain.ttl), client_ttl : option(int),
|
||||
new_ptrs : map(string, AENS.pointee), <signature : signature>) : unit
|
||||
@ -591,7 +591,7 @@ will not be updated, for example if `None` is passed as `expiry` the expiry
|
||||
block of the name is not changed.
|
||||
|
||||
|
||||
## Contract
|
||||
### Contract
|
||||
|
||||
Values related to the current contract
|
||||
|
||||
@ -619,7 +619,7 @@ Contract.balance : int
|
||||
Amount of coins in the contract account
|
||||
|
||||
|
||||
## Call
|
||||
### Call
|
||||
|
||||
Values related to the call to the current contract
|
||||
|
||||
@ -670,13 +670,13 @@ Call.gas_left() : int
|
||||
The amount of gas left for the current call.
|
||||
|
||||
|
||||
## Chain
|
||||
### Chain
|
||||
|
||||
Values and functions related to the chain itself and other entities that live on it.
|
||||
|
||||
### Types
|
||||
#### Types
|
||||
|
||||
#### tx
|
||||
##### tx
|
||||
```
|
||||
record tx = { paying_for : option(Chain.paying_for_tx)
|
||||
, ga_metas : list(Chain.ga_meta_tx)
|
||||
@ -686,18 +686,18 @@ record tx = { paying_for : option(Chain.paying_for_tx)
|
||||
, tx : Chain.base_tx }
|
||||
```
|
||||
|
||||
#### ga_meta_tx
|
||||
##### ga_meta_tx
|
||||
```
|
||||
datatype ga_meta_tx = GAMetaTx(address, int)
|
||||
```
|
||||
|
||||
#### paying_for_tx
|
||||
##### paying_for_tx
|
||||
```
|
||||
datatype paying_for_tx = PayingForTx(address, int)
|
||||
```
|
||||
|
||||
|
||||
#### base_tx
|
||||
##### base_tx
|
||||
```
|
||||
datatype base_tx = SpendTx(address, int, string)
|
||||
| OracleRegisterTx | OracleQueryTx | OracleResponseTx | OracleExtendTx
|
||||
@ -711,9 +711,9 @@ datatype base_tx = SpendTx(address, int, string)
|
||||
```
|
||||
|
||||
|
||||
### Functions
|
||||
#### Functions
|
||||
|
||||
#### balance
|
||||
##### balance
|
||||
```
|
||||
Chain.balance(a : address) : int
|
||||
```
|
||||
@ -721,7 +721,7 @@ Chain.balance(a : address) : int
|
||||
The balance of account `a`.
|
||||
|
||||
|
||||
#### block_hash
|
||||
##### block_hash
|
||||
```
|
||||
Chain.block_hash(h : int) : option(bytes(32))
|
||||
```
|
||||
@ -734,7 +734,7 @@ allowed height. From FATE VM version 2 (IRIS) it will return the block hash of
|
||||
the current generation.
|
||||
|
||||
|
||||
#### block_height
|
||||
##### block_height
|
||||
```
|
||||
Chain.block_height : int"
|
||||
```
|
||||
@ -742,7 +742,7 @@ Chain.block_height : int"
|
||||
The height of the current block (i.e. the block in which the current call will be included).
|
||||
|
||||
|
||||
#### coinbase
|
||||
##### coinbase
|
||||
```
|
||||
Chain.coinbase : address
|
||||
```
|
||||
@ -750,7 +750,7 @@ Chain.coinbase : address
|
||||
The address of the account that mined the current block.
|
||||
|
||||
|
||||
#### timestamp
|
||||
##### timestamp
|
||||
```
|
||||
Chain.timestamp : int
|
||||
```
|
||||
@ -758,7 +758,7 @@ Chain.timestamp : int
|
||||
The timestamp of the current block.
|
||||
|
||||
|
||||
#### difficulty
|
||||
##### difficulty
|
||||
```
|
||||
Chain.difficulty : int
|
||||
```
|
||||
@ -766,7 +766,7 @@ Chain.difficulty : int
|
||||
The difficulty of the current block.
|
||||
|
||||
|
||||
#### gas
|
||||
##### gas
|
||||
```
|
||||
Chain.gas_limit : int
|
||||
```
|
||||
@ -774,7 +774,7 @@ Chain.gas_limit : int
|
||||
The gas limit of the current block.
|
||||
|
||||
|
||||
#### bytecode_hash
|
||||
##### bytecode_hash
|
||||
```
|
||||
Chain.bytecode_hash : 'c => option(hash)
|
||||
```
|
||||
@ -785,7 +785,7 @@ instantiated with a contract. The charged gas increases linearly to
|
||||
the size of the serialized bytecode of the deployed contract.
|
||||
|
||||
|
||||
#### create
|
||||
##### create
|
||||
```
|
||||
Chain.create(value : int, ...) => 'c
|
||||
```
|
||||
@ -837,7 +837,7 @@ main contract Market =
|
||||
The typechecker must be certain about the created contract's type, so it is
|
||||
worth writing it explicitly as shown in the example.
|
||||
|
||||
#### clone
|
||||
##### clone
|
||||
```
|
||||
Chain.clone : ( ref : 'c, gas : int, value : int, protected : bool, ...
|
||||
) => if(protected) option('c) else 'c
|
||||
@ -895,18 +895,18 @@ implementation of the `init` function does not actually return `state`, but
|
||||
calls `put` instead. Moreover, FATE prevents even handcrafted calls to `init`.
|
||||
|
||||
|
||||
#### event
|
||||
##### event
|
||||
```
|
||||
Chain.event(e : event) : unit
|
||||
```
|
||||
Emits the event. To use this function one needs to define the `event` type as a `datatype` in the contract.
|
||||
|
||||
|
||||
# Includable namespaces
|
||||
## Includable namespaces
|
||||
|
||||
These need to be explicitly included (with `.aes` suffix)
|
||||
|
||||
## List
|
||||
### List
|
||||
|
||||
This module contains common operations on lists like constructing, querying, traversing etc.
|
||||
|
||||
@ -1253,7 +1253,7 @@ List.enumerate(l : list('a)) : list(int * 'a)
|
||||
Equivalent to [zip](#zip) with `[0..length(l)]`, but slightly faster.
|
||||
|
||||
|
||||
## Option
|
||||
### Option
|
||||
|
||||
Common operations on `option` types and lists of `option`s.
|
||||
|
||||
@ -1438,7 +1438,7 @@ Option.choose_first(l : list(option('a))) : option('a)
|
||||
Same as [choose](#choose), but chooses from a list insted of two arguments.
|
||||
|
||||
|
||||
## String
|
||||
### String
|
||||
|
||||
Operations on the `string` type. A `string` is a UTF-8 encoded byte array.
|
||||
|
||||
@ -1554,7 +1554,7 @@ blake2b(s : string) : hash
|
||||
Computes the Blake2B hash of the string.
|
||||
|
||||
|
||||
## Func
|
||||
### Func
|
||||
|
||||
Functional combinators.
|
||||
|
||||
@ -1684,7 +1684,7 @@ Func.untuplify3(f : 'a * 'b * 'c => 'd) : ('a, 'b, 'c) => 'd
|
||||
Opposite to [tuplify](#tuplify).
|
||||
|
||||
|
||||
## Pair
|
||||
### Pair
|
||||
|
||||
Common operations on 2-tuples.
|
||||
|
||||
@ -1736,7 +1736,7 @@ Pair.swap(t : ('a * 'b)) : ('b * 'a)
|
||||
Swaps elements.
|
||||
|
||||
|
||||
## Triple
|
||||
### Triple
|
||||
|
||||
#### fst
|
||||
```
|
||||
@ -1817,234 +1817,234 @@ Triple.rotl(t : ('a * 'b * 'c)) : ('b * 'c * 'a)
|
||||
|
||||
Cyclic rotation of the elements to the left.
|
||||
|
||||
## BLS12\_381
|
||||
### BLS12\_381
|
||||
|
||||
### Types
|
||||
#### Types
|
||||
|
||||
#### fp
|
||||
##### fp
|
||||
|
||||
Built-in (Montgomery) integer representation 32 bytes
|
||||
|
||||
|
||||
#### fr
|
||||
##### fr
|
||||
|
||||
Built-in (Montgomery) integer representation 48 bytes
|
||||
|
||||
|
||||
#### fp2
|
||||
##### fp2
|
||||
```
|
||||
record fp2 = { x1 : fp, x2 : fp }`
|
||||
```
|
||||
|
||||
#### g1
|
||||
##### g1
|
||||
```
|
||||
record g1 = { x : fp, y : fp, z : fp }
|
||||
```
|
||||
|
||||
|
||||
#### g2
|
||||
##### g2
|
||||
```
|
||||
record g2 = { x : fp2, y : fp2, z : fp2 }
|
||||
```
|
||||
|
||||
|
||||
#### gt
|
||||
##### gt
|
||||
```
|
||||
record gt = { x1 : fp, x2 : fp, x3 : fp, x4 : fp, x5 : fp, x6 : fp, x7 : fp, x8 : fp, x9 : fp, x10 : fp, x11 : fp, x12 : fp }
|
||||
```
|
||||
|
||||
### Functions
|
||||
#### Functions
|
||||
|
||||
#### pairing\_check
|
||||
##### pairing\_check
|
||||
```
|
||||
BLS12_381.pairing_check(xs : list(g1), ys : list(g2)) : bool
|
||||
```
|
||||
|
||||
Pairing check of a list of points, `xs` and `ys` should be of equal length.
|
||||
|
||||
#### int_to_fr
|
||||
##### int_to_fr
|
||||
```
|
||||
BLS12_381.int_to_fr(x : int) : fr
|
||||
```
|
||||
|
||||
Convert an integer to an `fr` - a 32 bytes internal (Montgomery) integer representation.
|
||||
|
||||
#### int_to_fp
|
||||
##### int_to_fp
|
||||
```
|
||||
BLS12_381.int_to_fp(x : int) : fp
|
||||
```
|
||||
|
||||
Convert an integer to an `fp` - a 48 bytes internal (Montgomery) integer representation.
|
||||
|
||||
#### fr_to_int
|
||||
##### fr_to_int
|
||||
```
|
||||
BLS12_381.fr_to_int(x : fr) : int
|
||||
```
|
||||
|
||||
Convert a `fr` value into an integer.
|
||||
|
||||
#### fp_to_int
|
||||
##### fp_to_int
|
||||
```
|
||||
BLS12_381.fp_to_int(x : fp) : int
|
||||
```
|
||||
|
||||
Convert a `fp` value into an integer.
|
||||
|
||||
#### mk_g1
|
||||
##### mk_g1
|
||||
```
|
||||
BLS12_381.mk_g1(x : int, y : int, z : int) : g1
|
||||
```
|
||||
|
||||
Construct a `g1` point from three integers.
|
||||
|
||||
#### mk_g2
|
||||
##### mk_g2
|
||||
```
|
||||
BLS12_381.mk_g2(x1 : int, x2 : int, y1 : int, y2 : int, z1 : int, z2 : int) : g2
|
||||
```
|
||||
|
||||
Construct a `g2` point from six integers.
|
||||
|
||||
#### g1_neg
|
||||
##### g1_neg
|
||||
```
|
||||
BLS12_381.g1_neg(p : g1) : g1
|
||||
```
|
||||
|
||||
Negate a `g1` value.
|
||||
|
||||
#### g1_norm
|
||||
##### g1_norm
|
||||
```
|
||||
BLS12_381.g1_norm(p : g1) : g1
|
||||
```
|
||||
|
||||
Normalize a `g1` value.
|
||||
|
||||
#### g1_valid
|
||||
##### g1_valid
|
||||
```
|
||||
BLS12_381.g1_valid(p : g1) : bool
|
||||
```
|
||||
|
||||
Check that a `g1` value is a group member.
|
||||
|
||||
#### g1_is_zero
|
||||
##### g1_is_zero
|
||||
```
|
||||
BLS12_381.g1_is_zero(p : g1) : bool
|
||||
```
|
||||
|
||||
Check if a `g1` value corresponds to the zero value of the group.
|
||||
|
||||
#### g1_add
|
||||
##### g1_add
|
||||
```
|
||||
BLS12_381.g1_add(p : g1, q : g1) : g1
|
||||
```
|
||||
|
||||
Add two `g1` values.
|
||||
|
||||
#### g1_mul
|
||||
##### g1_mul
|
||||
```
|
||||
BLS12_381.g1_mul(k : fr, p : g1) : g1
|
||||
```
|
||||
|
||||
Scalar multiplication for `g1`.
|
||||
|
||||
#### g2_neg
|
||||
##### g2_neg
|
||||
```
|
||||
BLS12_381.g2_neg(p : g2) : g2
|
||||
```
|
||||
|
||||
Negate a `g2` value.
|
||||
|
||||
#### g2_norm
|
||||
##### g2_norm
|
||||
```
|
||||
BLS12_381.g2_norm(p : g2) : g2
|
||||
```
|
||||
|
||||
Normalize a `g2` value.
|
||||
|
||||
#### g2_valid
|
||||
##### g2_valid
|
||||
```
|
||||
BLS12_381.g2_valid(p : g2) : bool
|
||||
```
|
||||
|
||||
Check that a `g2` value is a group member.
|
||||
|
||||
#### g2_is_zero
|
||||
##### g2_is_zero
|
||||
```
|
||||
BLS12_381.g2_is_zero(p : g2) : bool
|
||||
```
|
||||
|
||||
Check if a `g2` value corresponds to the zero value of the group.
|
||||
|
||||
#### g2_add
|
||||
##### g2_add
|
||||
```
|
||||
BLS12_381.g2_add(p : g2, q : g2) : g2
|
||||
```
|
||||
|
||||
Add two `g2` values.
|
||||
|
||||
#### g2_mul
|
||||
##### g2_mul
|
||||
```
|
||||
BLS12_381.g2_mul(k : fr, p : g2) : g2
|
||||
```
|
||||
|
||||
Scalar multiplication for `g2`.
|
||||
|
||||
#### gt_inv
|
||||
##### gt_inv
|
||||
```
|
||||
BLS12_381.gt_inv(p : gt) : gt
|
||||
```
|
||||
|
||||
Invert a `gt` value.
|
||||
|
||||
#### gt_add
|
||||
##### gt_add
|
||||
```
|
||||
BLS12_381.gt_add(p : gt, q : gt) : gt
|
||||
```
|
||||
|
||||
Add two `gt` values.
|
||||
|
||||
#### gt_mul
|
||||
##### gt_mul
|
||||
```
|
||||
BLS12_381.gt_mul(p : gt, q : gt) : gt
|
||||
```
|
||||
|
||||
Multiply two `gt` values.
|
||||
|
||||
#### gt_pow
|
||||
##### gt_pow
|
||||
```
|
||||
BLS12_381.gt_pow(p : gt, k : fr) : gt
|
||||
```
|
||||
|
||||
Calculate exponentiation `p ^ k`.
|
||||
|
||||
#### gt_is_one
|
||||
##### gt_is_one
|
||||
```
|
||||
BLS12_381.gt_is_one(p : gt) : bool
|
||||
```
|
||||
|
||||
Compare a `gt` value to the unit value of the Gt group.
|
||||
|
||||
#### pairing
|
||||
##### pairing
|
||||
```
|
||||
BLS12_381.pairing(p : g1, q : g2) : gt
|
||||
```
|
||||
|
||||
Compute the pairing of a `g1` value and a `g2` value.
|
||||
|
||||
#### miller_loop
|
||||
##### miller_loop
|
||||
```
|
||||
BLS12_381.miller_loop(p : g1, q : g2) : gt
|
||||
```
|
||||
|
||||
Do the Miller loop stage of pairing for `g1` and `g2`.
|
||||
|
||||
#### final_exp
|
||||
##### final_exp
|
||||
```
|
||||
BLS12_381.final_exp(p : gt) : gt
|
||||
```
|
||||
|
||||
Perform the final exponentiation step of pairing for a `gt` value.
|
||||
|
||||
## Frac
|
||||
### Frac
|
||||
|
||||
This namespace provides operations on rational numbers. A rational number is represented
|
||||
as a fraction of two integers which are stored internally in the `frac` datatype.
|
||||
@ -2068,9 +2068,9 @@ language provides checkers to prevent unintended usage of them. Therefore the ty
|
||||
**will** allow that and the results of such comparison will be unspecified.
|
||||
You should use [lt](#lt), [geq](#geq), [eq](#eq) etc instead.
|
||||
|
||||
### Types
|
||||
#### Types
|
||||
|
||||
#### frac
|
||||
##### frac
|
||||
```
|
||||
datatype frac = Pos(int, int) | Zero | Neg(int, int)
|
||||
```
|
||||
@ -2079,194 +2079,194 @@ Internal representation of fractional numbers. First integer encodes the numerat
|
||||
both must be always positive, as the sign is being handled by the choice of the constructor.
|
||||
|
||||
|
||||
### Functions
|
||||
#### Functions
|
||||
|
||||
#### make_frac
|
||||
##### make_frac
|
||||
`Frac.make_frac(n : int, d : int) : frac`
|
||||
|
||||
Creates a fraction out of numerator and denominator. Automatically normalizes, so
|
||||
`make_frac(2, 4)` and `make_frac(1, 2)` will yield same results.
|
||||
|
||||
|
||||
#### num
|
||||
##### num
|
||||
`Frac.num(f : frac) : int`
|
||||
|
||||
Returns the numerator of a fraction.
|
||||
|
||||
|
||||
#### den
|
||||
##### den
|
||||
`Frac.den(f : frac) : int`
|
||||
|
||||
Returns the denominator of a fraction.
|
||||
|
||||
|
||||
#### to_pair
|
||||
##### to_pair
|
||||
`Frac.to_pair(f : frac) : int * int`
|
||||
|
||||
Turns a fraction into a pair of numerator and denominator.
|
||||
|
||||
|
||||
#### sign
|
||||
##### sign
|
||||
`Frac.sign(f : frac) : int`
|
||||
|
||||
Returns the signum of a fraction, -1, 0, 1 if negative, zero, positive respectively.
|
||||
|
||||
|
||||
#### to_str
|
||||
##### to_str
|
||||
`Frac.to_str(f : frac) : string`
|
||||
|
||||
Conversion to string. Does not display division by 1 or denominator if equals zero.
|
||||
|
||||
|
||||
#### simplify
|
||||
##### simplify
|
||||
`Frac.simplify(f : frac) : frac`
|
||||
|
||||
Reduces fraction to normal form if for some reason it is not in it.
|
||||
|
||||
|
||||
#### eq
|
||||
##### eq
|
||||
`Frac.eq(a : frac, b : frac) : bool`
|
||||
|
||||
Checks if `a` is equal to `b`.
|
||||
|
||||
|
||||
#### neq
|
||||
##### neq
|
||||
`Frac.neq(a : frac, b : frac) : bool`
|
||||
|
||||
Checks if `a` is not equal to `b`.
|
||||
|
||||
|
||||
#### geq
|
||||
##### geq
|
||||
`Frac.geq(a : frac, b : frac) : bool`
|
||||
|
||||
Checks if `a` is greater or equal to `b`.
|
||||
|
||||
|
||||
#### leq
|
||||
##### leq
|
||||
`Frac.leq(a : frac, b : frac) : bool`
|
||||
|
||||
Checks if `a` is lesser or equal to `b`.
|
||||
|
||||
|
||||
#### gt
|
||||
##### gt
|
||||
`Frac.gt(a : frac, b : frac) : bool`
|
||||
|
||||
Checks if `a` is greater than `b`.
|
||||
|
||||
|
||||
#### lt
|
||||
##### lt
|
||||
`Frac.lt(a : frac, b : frac) : bool`
|
||||
|
||||
Checks if `a` is lesser than `b`.
|
||||
|
||||
|
||||
#### min
|
||||
##### min
|
||||
`Frac.min(a : frac, b : frac) : frac`
|
||||
|
||||
Chooses lesser of the two fractions.
|
||||
|
||||
|
||||
#### max
|
||||
##### max
|
||||
`Frac.max(a : frac, b : frac) : frac`
|
||||
|
||||
Chooses greater of the two fractions.
|
||||
|
||||
|
||||
#### abs
|
||||
##### abs
|
||||
`Frac.abs(f : frac) : frac`
|
||||
|
||||
Absolute value.
|
||||
|
||||
|
||||
#### from_int
|
||||
##### from_int
|
||||
`Frac.from_int(n : int) : frac`
|
||||
|
||||
From integer conversion. Effectively `make_frac(n, 1)`.
|
||||
|
||||
|
||||
#### floor
|
||||
##### floor
|
||||
`Frac.floor(f : frac) : int`
|
||||
|
||||
Rounds a fraction to the nearest lesser or equal integer.
|
||||
|
||||
|
||||
#### ceil
|
||||
##### ceil
|
||||
`Frac.ceil(f : frac) : int`
|
||||
|
||||
Rounds a fraction to the nearest greater or equal integer.
|
||||
|
||||
|
||||
#### round_to_zero
|
||||
##### round_to_zero
|
||||
`Frac.round_to_zero(f : frac) : int`
|
||||
|
||||
Rounds a fraction towards zero.
|
||||
Effectively `ceil` if lesser than zero and `floor` if greater.
|
||||
|
||||
|
||||
#### round_from_zero
|
||||
##### round_from_zero
|
||||
`Frac.round_from_zero(f : frac) : int`
|
||||
|
||||
Rounds a fraction from zero.
|
||||
Effectively `ceil` if greater than zero and `floor` if lesser.
|
||||
|
||||
|
||||
#### round
|
||||
##### round
|
||||
`Frac.round(f : frac) : int`
|
||||
|
||||
Rounds a fraction to a nearest integer. If two integers are in the same distance it
|
||||
will choose the even one.
|
||||
|
||||
|
||||
#### add
|
||||
##### add
|
||||
`Frac.add(a : frac, b : frac) : frac`
|
||||
|
||||
Sum of the fractions.
|
||||
|
||||
|
||||
#### neg
|
||||
##### neg
|
||||
`Frac.neg(a : frac) : frac`
|
||||
|
||||
Negation of the fraction.
|
||||
|
||||
|
||||
#### sub
|
||||
##### sub
|
||||
`Frac.sub(a : frac, b : frac) : frac`
|
||||
|
||||
Subtraction of two fractions.
|
||||
|
||||
|
||||
#### inv
|
||||
##### inv
|
||||
`Frac.inv(a : frac) : frac`
|
||||
|
||||
Inverts a fraction. Throws error if `a` is zero.
|
||||
|
||||
|
||||
#### mul
|
||||
##### mul
|
||||
`Frac.mul(a : frac, b : frac) : frac`
|
||||
|
||||
Multiplication of two fractions.
|
||||
|
||||
|
||||
#### div
|
||||
##### div
|
||||
`Frac.div(a : frac, b : frac) : frac`
|
||||
|
||||
Division of two fractions.
|
||||
|
||||
|
||||
#### int_exp
|
||||
##### int_exp
|
||||
`Frac.int_exp(b : frac, e : int) : frac`
|
||||
|
||||
Takes `b` to the power of `e`. The exponent can be a negative value.
|
||||
|
||||
|
||||
#### optimize
|
||||
##### optimize
|
||||
`Frac.optimize(f : frac, loss : frac) : frac`
|
||||
|
||||
Shrink the internal size of a fraction as much as possible by approximating it to the
|
||||
point where the error would exceed the `loss` value.
|
||||
|
||||
|
||||
#### is_sane
|
||||
##### is_sane
|
||||
`Frac.is_sane(f : frac) : bool`
|
||||
|
||||
For debugging. If it ever returns false in a code that doesn't call `frac` constructors or
|
||||
|
262
docs/sophia_syntax.md
Normal file
262
docs/sophia_syntax.md
Normal file
@ -0,0 +1,262 @@
|
||||
# Syntax
|
||||
|
||||
## Lexical syntax
|
||||
|
||||
### Comments
|
||||
|
||||
Single line comments start with `//` and block comments are enclosed in `/*`
|
||||
and `*/` and can be nested.
|
||||
|
||||
### Keywords
|
||||
|
||||
```
|
||||
contract elif else entrypoint false function if import include let mod namespace
|
||||
private payable stateful switch true type record datatype main interface
|
||||
```
|
||||
|
||||
### Tokens
|
||||
|
||||
- `Id = [a-z_][A-Za-z0-9_']*` identifiers start with a lower case letter.
|
||||
- `Con = [A-Z][A-Za-z0-9_']*` constructors start with an upper case letter.
|
||||
- `QId = (Con\.)+Id` qualified identifiers (e.g. `Map.member`)
|
||||
- `QCon = (Con\.)+Con` qualified constructor
|
||||
- `TVar = 'Id` type variable (e.g `'a`, `'b`)
|
||||
- `Int = [0-9]+(_[0-9]+)*|0x[0-9A-Fa-f]+(_[0-9A-Fa-f]+)*` integer literal with optional `_` separators
|
||||
- `Bytes = #[0-9A-Fa-f]+(_[0-9A-Fa-f]+)*` byte array literal with optional `_` separators
|
||||
- `String` string literal enclosed in `"` with escape character `\`
|
||||
- `Char` character literal enclosed in `'` with escape character `\`
|
||||
- `AccountAddress` base58-encoded 32 byte account pubkey with `ak_` prefix
|
||||
- `ContractAddress` base58-encoded 32 byte contract address with `ct_` prefix
|
||||
- `OracleAddress` base58-encoded 32 byte oracle address with `ok_` prefix
|
||||
- `OracleQueryId` base58-encoded 32 byte oracle query id with `oq_` prefix
|
||||
|
||||
Valid string escape codes are
|
||||
|
||||
| Escape | ASCII | |
|
||||
|---------------|-------------|---|
|
||||
| `\b` | 8 | |
|
||||
| `\t` | 9 | |
|
||||
| `\n` | 10 | |
|
||||
| `\v` | 11 | |
|
||||
| `\f` | 12 | |
|
||||
| `\r` | 13 | |
|
||||
| `\e` | 27 | |
|
||||
| `\xHexDigits` | *HexDigits* | |
|
||||
|
||||
|
||||
See the [identifier encoding scheme](https://github.com/aeternity/protocol/blob/master/node/api/api_encoding.md) for the
|
||||
details on the base58 literals.
|
||||
|
||||
## Layout blocks
|
||||
|
||||
Sophia uses Python-style layout rules to group declarations and statements. A
|
||||
layout block with more than one element must start on a separate line and be
|
||||
indented more than the currently enclosing layout block. Blocks with a single
|
||||
element can be written on the same line as the previous token.
|
||||
|
||||
Each element of the block must share the same indentation and no part of an
|
||||
element may be indented less than the indentation of the block. For instance
|
||||
|
||||
```sophia
|
||||
contract Layout =
|
||||
function foo() = 0 // no layout
|
||||
function bar() = // layout block starts on next line
|
||||
let x = foo() // indented more than 2 spaces
|
||||
x
|
||||
+ 1 // the '+' is indented more than the 'x'
|
||||
```
|
||||
|
||||
## Notation
|
||||
|
||||
In describing the syntax below, we use the following conventions:
|
||||
- Upper-case identifiers denote non-terminals (like `Expr`) or terminals with
|
||||
some associated value (like `Id`).
|
||||
- Keywords and symbols are enclosed in single quotes: `'let'` or `'='`.
|
||||
- Choices are separated by vertical bars: `|`.
|
||||
- Optional elements are enclosed in `[` square brackets `]`.
|
||||
- `(` Parentheses `)` are used for grouping.
|
||||
- Zero or more repetitions are denoted by a postfix `*`, and one or more
|
||||
repetitions by a `+`.
|
||||
- `Block(X)` denotes a layout block of `X`s.
|
||||
- `Sep(X, S)` is short for `[X (S X)*]`, i.e. a possibly empty sequence of `X`s
|
||||
separated by `S`s.
|
||||
- `Sep1(X, S)` is short for `X (S X)*`, i.e. same as `Sep`, but must not be empty.
|
||||
|
||||
|
||||
## Declarations
|
||||
|
||||
A Sophia file consists of a sequence of *declarations* in a layout block.
|
||||
|
||||
```c
|
||||
File ::= Block(TopDecl)
|
||||
|
||||
TopDecl ::= ['payable'] 'contract' Con '=' Block(Decl)
|
||||
| 'namespace' Con '=' Block(Decl)
|
||||
| '@compiler' PragmaOp Version
|
||||
| 'include' String
|
||||
|
||||
Decl ::= 'type' Id ['(' TVar* ')'] '=' TypeAlias
|
||||
| 'record' Id ['(' TVar* ')'] '=' RecordType
|
||||
| 'datatype' Id ['(' TVar* ')'] '=' DataType
|
||||
| (EModifier* 'entrypoint' | FModifier* 'function') Block(FunDecl)
|
||||
|
||||
FunDecl ::= Id ':' Type // Type signature
|
||||
| Id Args [':' Type] '=' Block(Stmt) // Definition
|
||||
|
||||
PragmaOp ::= '<' | '=<' | '==' | '>=' | '>'
|
||||
Version ::= Sep1(Int, '.')
|
||||
|
||||
EModifier ::= 'payable' | 'stateful'
|
||||
FModifier ::= 'stateful' | 'private'
|
||||
|
||||
Args ::= '(' Sep(Pattern, ',') ')'
|
||||
```
|
||||
|
||||
Contract declarations must appear at the top-level.
|
||||
|
||||
For example,
|
||||
```sophia
|
||||
contract Test =
|
||||
type t = int
|
||||
entrypoint add (x : t, y : t) = x + y
|
||||
```
|
||||
|
||||
There are three forms of type declarations: type aliases (declared with the
|
||||
`type` keyword), record type definitions (`record`) and data type definitions
|
||||
(`datatype`):
|
||||
|
||||
```c
|
||||
TypeAlias ::= Type
|
||||
RecordType ::= '{' Sep(FieldType, ',') '}'
|
||||
DataType ::= Sep1(ConDecl, '|')
|
||||
|
||||
FieldType ::= Id ':' Type
|
||||
ConDecl ::= Con ['(' Sep1(Type, ',') ')']
|
||||
```
|
||||
|
||||
For example,
|
||||
```sophia
|
||||
record point('a) = {x : 'a, y : 'a}
|
||||
datatype shape('a) = Circle(point('a), 'a) | Rect(point('a), point('a))
|
||||
type int_shape = shape(int)
|
||||
```
|
||||
|
||||
## Types
|
||||
|
||||
```c
|
||||
Type ::= Domain '=>' Type // Function type
|
||||
| Type '(' Sep(Type, ',') ')' // Type application
|
||||
| '(' Type ')' // Parens
|
||||
| 'unit' | Sep(Type, '*') // Tuples
|
||||
| Id | QId | TVar
|
||||
|
||||
Domain ::= Type // Single argument
|
||||
| '(' Sep(Type, ',') ')' // Multiple arguments
|
||||
```
|
||||
|
||||
The function type arrow associates to the right.
|
||||
|
||||
Example,
|
||||
```sophia
|
||||
'a => list('a) => (int * list('a))
|
||||
```
|
||||
|
||||
## Statements
|
||||
|
||||
Function bodies are blocks of *statements*, where a statement is one of the following
|
||||
|
||||
```c
|
||||
Stmt ::= 'switch' '(' Expr ')' Block(Case)
|
||||
| 'if' '(' Expr ')' Block(Stmt)
|
||||
| 'elif' '(' Expr ')' Block(Stmt)
|
||||
| 'else' Block(Stmt)
|
||||
| 'let' LetDef
|
||||
| Expr
|
||||
|
||||
LetDef ::= Id Args [':' Type] '=' Block(Stmt) // Function definition
|
||||
| Pattern '=' Block(Stmt) // Value definition
|
||||
|
||||
Case ::= Pattern '=>' Block(Stmt)
|
||||
Pattern ::= Expr
|
||||
```
|
||||
|
||||
`if` statements can be followed by zero or more `elif` statements and an optional final `else` statement. For example,
|
||||
|
||||
```sophia
|
||||
let x : int = 4
|
||||
switch(f(x))
|
||||
None => 0
|
||||
Some(y) =>
|
||||
if(y > 10)
|
||||
"too big"
|
||||
elif(y < 3)
|
||||
"too small"
|
||||
else
|
||||
"just right"
|
||||
```
|
||||
|
||||
## Expressions
|
||||
|
||||
```c
|
||||
Expr ::= '(' LamArgs ')' '=>' Block(Stmt) // Anonymous function (x) => x + 1
|
||||
| 'if' '(' Expr ')' Expr 'else' Expr // If expression if(x < y) y else x
|
||||
| Expr ':' Type // Type annotation 5 : int
|
||||
| Expr BinOp Expr // Binary operator x + y
|
||||
| UnOp Expr // Unary operator ! b
|
||||
| Expr '(' Sep(Expr, ',') ')' // Application f(x, y)
|
||||
| Expr '.' Id // Projection state.x
|
||||
| Expr '[' Expr ']' // Map lookup map[key]
|
||||
| Expr '{' Sep(FieldUpdate, ',') '}' // Record or map update r{ fld[key].x = y }
|
||||
| '[' Sep(Expr, ',') ']' // List [1, 2, 3]
|
||||
| '[' Expr '|' Sep(Generator, ',') ']'
|
||||
// List comprehension [k | x <- [1], if (f(x)), let k = x+1]
|
||||
| '[' Expr '..' Expr ']' // List range [1..n]
|
||||
| '{' Sep(FieldUpdate, ',') '}' // Record or map value {x = 0, y = 1}, {[key] = val}
|
||||
| '(' Expr ')' // Parens (1 + 2) * 3
|
||||
| Id | Con | QId | QCon // Identifiers x, None, Map.member, AELib.Token
|
||||
| Int | Bytes | String | Char // Literals 123, 0xff, #00abc123, "foo", '%'
|
||||
| AccountAddress | ContractAddress // Chain identifiers
|
||||
| OracleAddress | OracleQueryId // Chain identifiers
|
||||
|
||||
Generator ::= Pattern '<-' Expr // Generator
|
||||
| 'if' '(' Expr ')' // Guard
|
||||
| LetDef // Definition
|
||||
|
||||
LamArgs ::= '(' Sep(LamArg, ',') ')'
|
||||
LamArg ::= Id [':' Type]
|
||||
|
||||
FieldUpdate ::= Path '=' Expr
|
||||
Path ::= Id // Record field
|
||||
| '[' Expr ']' // Map key
|
||||
| Path '.' Id // Nested record field
|
||||
| Path '[' Expr ']' // Nested map key
|
||||
|
||||
BinOp ::= '||' | '&&' | '<' | '>' | '=<' | '>=' | '==' | '!='
|
||||
| '::' | '++' | '+' | '-' | '*' | '/' | 'mod' | '^'
|
||||
UnOp ::= '-' | '!'
|
||||
```
|
||||
|
||||
## Operators types
|
||||
|
||||
| Operators | Type
|
||||
| --- | ---
|
||||
| `-` `+` `*` `/` `mod` `^` | arithmetic operators
|
||||
| `!` `&&` `\|\|` | logical operators
|
||||
| `==` `!=` `<` `>` `=<` `>=` | comparison operators
|
||||
| `::` `++` | list operators
|
||||
|
||||
## Operator precendences
|
||||
|
||||
In order of highest to lowest precedence.
|
||||
|
||||
| Operators | Associativity
|
||||
| --- | ---
|
||||
| `!` | right
|
||||
| `^` | left
|
||||
| `*` `/` `mod` | left
|
||||
| `-` (unary) | right
|
||||
| `+` `-` | left
|
||||
| `::` `++` | right
|
||||
| `<` `>` `=<` `>=` `==` `!=` | none
|
||||
| `&&` | right
|
||||
| `\|\|` | right
|
55
mkdocs.yml
Normal file
55
mkdocs.yml
Normal file
@ -0,0 +1,55 @@
|
||||
site_name: aeternity Sophia Language
|
||||
plugins:
|
||||
- search
|
||||
- mkdocs-simple-hooks:
|
||||
hooks:
|
||||
on_pre_build: 'docs.python.hooks:pre_build'
|
||||
repo_url: 'https://github.com/aeternity/aesophia'
|
||||
edit_uri: ''
|
||||
|
||||
extra:
|
||||
version:
|
||||
provider: mike
|
||||
|
||||
theme:
|
||||
favicon: images/favicon.png
|
||||
name: material
|
||||
custom_dir: docs/mkdocs-overrides
|
||||
language: en
|
||||
palette:
|
||||
- scheme: default
|
||||
primary: pink
|
||||
accent: pink
|
||||
toggle:
|
||||
icon: material/weather-night
|
||||
name: Switch to dark mode
|
||||
- scheme: slate
|
||||
primary: pink
|
||||
accent: pink
|
||||
toggle:
|
||||
icon: material/weather-sunny
|
||||
name: Switch to light mode
|
||||
features:
|
||||
- content.tabs.link
|
||||
- search.highlight
|
||||
- search.share
|
||||
- search.suggest
|
||||
|
||||
# Don't include MkDocs' JavaScript
|
||||
include_search_page: false
|
||||
search_index_only: true
|
||||
|
||||
markdown_extensions:
|
||||
- admonition
|
||||
- pymdownx.highlight
|
||||
- pymdownx.superfences
|
||||
- toc:
|
||||
toc_depth: 3
|
||||
|
||||
nav:
|
||||
- Introduction: index.md
|
||||
- Syntax: sophia_syntax.md
|
||||
- Features: sophia_features.md
|
||||
- Standard Library: sophia_stdlib.md
|
||||
- Contract Examples: sophia_examples.md
|
||||
- Changelog: CHANGELOG.md
|
Loading…
x
Reference in New Issue
Block a user