diff --git a/.docssite/docs/favicon.png b/.docssite/docs/favicon.png
new file mode 100644
index 0000000..e81502d
Binary files /dev/null and b/.docssite/docs/favicon.png differ
diff --git a/.docssite/hook.py b/.docssite/hook.py
new file mode 100644
index 0000000..cc7e359
--- /dev/null
+++ b/.docssite/hook.py
@@ -0,0 +1,7 @@
+import glob
+import shutil
+
+def pre_build(**kwargs):
+ for file in glob.glob('../docs/*.md'):
+ shutil.copy(file, 'docs')
+ shutil.copy('../CHANGELOG.md', 'docs')
diff --git a/.docssite/mkdocs.yml b/.docssite/mkdocs.yml
new file mode 100644
index 0000000..592f4fb
--- /dev/null
+++ b/.docssite/mkdocs.yml
@@ -0,0 +1,55 @@
+site_name: æternity Sophia Language
+plugins:
+ - search
+ - mkdocs-simple-hooks:
+ hooks:
+ on_pre_build: 'hook:pre_build'
+repo_url: 'https://github.com/aeternity/aesophia'
+edit_uri: ''
+
+extra:
+ version:
+ provider: mike
+
+theme:
+ favicon: favicon.png
+ name: material
+ custom_dir: 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
diff --git a/.docssite/overrides/main.html b/.docssite/overrides/main.html
new file mode 100644
index 0000000..35591d6
--- /dev/null
+++ b/.docssite/overrides/main.html
@@ -0,0 +1,8 @@
+{% extends "base.html" %}
+
+{% block outdated %}
+ You're not viewing the latest version.
+
+ Click here to go to latest.
+
+{% endblock %}
\ No newline at end of file
diff --git a/.github/workflows/docs-develop.yml b/.github/workflows/docs-develop.yml
new file mode 100644
index 0000000..48bc7f6
--- /dev/null
+++ b/.github/workflows/docs-develop.yml
@@ -0,0 +1,25 @@
+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('.github/workflows/requirements.txt') }}
+ - run: pip3 install -r .github/workflows/requirements.txt
+ - run: git config --global user.email "github-action@users.noreply.github.com"
+ - run: git config --global user.name "GitHub Action"
+ - run: |
+ cd .docssite
+ mike deploy --push master
\ No newline at end of file
diff --git a/.github/workflows/docs-release.yml b/.github/workflows/docs-release.yml
new file mode 100644
index 0000000..4ec58e2
--- /dev/null
+++ b/.github/workflows/docs-release.yml
@@ -0,0 +1,26 @@
+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('.github/workflows/requirements.txt') }}
+ - run: pip3 install -r .github/workflows/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: |
+ cd .docssite
+ mike deploy --push --update-aliases $RELEASE_VERSION latest
\ No newline at end of file
diff --git a/.github/workflows/requirements.txt b/.github/workflows/requirements.txt
new file mode 100644
index 0000000..61d5b2b
--- /dev/null
+++ b/.github/workflows/requirements.txt
@@ -0,0 +1,4 @@
+mkdocs==1.2.1
+mkdocs-simple-hooks==0.1.3
+mkdocs-material==7.1.9
+mike==1.0.1
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
index f7ebb14..095c8b0 100644
--- a/.gitignore
+++ b/.gitignore
@@ -22,3 +22,5 @@ aesophia
.qcci
current_counterexample.eqc
test/contracts/test.aes
+__pycache__
+.docssite/docs/*.md
diff --git a/LICENSE b/LICENSE
index 142825a..b4cc822 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,6 +1,6 @@
ISC License
-Copyright (c) 2017, aeternity developers
+Copyright (c) 2017, æternity developers
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
diff --git a/README.md b/README.md
index 68bcb6d..e11896a 100644
--- a/README.md
+++ b/README.md
@@ -5,13 +5,17 @@ This is the __sophia__ compiler for the æternity system which compiles contract
The compiler is currently being used three places
- [The command line compiler](https://github.com/aeternity/aesophia_cli)
- [The HTTP compiler](https://github.com/aeternity/aesophia_http)
- - In [Aeternity node](https://github.com/aeternity/aeternity) tests
+ - In [æternity node](https://github.com/aeternity/aeternity) tests
## 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 æternity 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)
diff --git a/docs/index.md b/docs/index.md
new file mode 100644
index 0000000..b3f2129
--- /dev/null
+++ b/docs/index.md
@@ -0,0 +1,12 @@
+# Introduction
+Sophia is a functional language 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 [æternity 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 and diving deeper into the language itself check out the [REPL](https://repl.aeternity.io/)!
diff --git a/docs/sophia.md b/docs/sophia.md
index 754f976..308108f 100644
--- a/docs/sophia.md
+++ b/docs/sophia.md
@@ -1,1195 +1 @@
-
-
-# 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
-
-The main unit of code in Sophia is the *contract*.
-
-- A contract implementation, or simply a contract, is the code for a
- smart contract and consists of a list of types, entrypoints and local
- functions. Only the entrypoints can be called from outside the contract.
-- A contract instance is an entity living on the block chain (or in a state
- channel). Each instance has an address that can be used to call its
- entrypoints, either from another contract or in a call transaction.
-- A contract may define a type `state` encapsulating its local
- state. When creating a new contract the `init` entrypoint is executed and the
- 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.
-
-#### 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
-of a number of type definitions and entrypoint declarations. For instance,
-
-```sophia
-// A contract type
-contract interface VotingType =
- entrypoint vote : string => unit
-```
-
-Now given contract address of type `VotingType` you can call the `vote`
-entrypoint of that contract:
-
-```sophia
-contract VoteTwice =
- entrypoint voteTwice(v : VotingType, alt : string) =
- v.vote(alt)
- v.vote(alt)
-```
-
-Contract calls take two optional named arguments `gas : int` and `value : int`
-that lets you set a gas limit and provide tokens to a contract call. If omitted
-the defaults are no gas limit and no tokens. Suppose there is a fee for voting:
-
-```sophia
- entrypoint voteTwice(v : VotingType, fee : int, alt : string) =
- v.vote(value = fee, alt)
- v.vote(value = fee, alt)
-```
-
-Named arguments can be given in any order.
-
-Note that reentrant calls are not permitted. In other words, when calling
-another contract it cannot call you back (directly or indirectly).
-
-To construct a value of a contract type you can give a contract address literal
-(for instance `ct_2gPXZnZdKU716QBUFKaT4VdBZituK93KLvHJB3n4EnbrHHw4Ay`), or
-convert an account address to a contract address using `Address.to_contract`.
-Note that if the contract does not exist, or it doesn't have the entrypoint, or
-the type of the entrypoint does not match the stated contract type, the call
-fails.
-
-To recover the underlying `address` of a contract instance there is a field
-`address : address`. For instance, to send tokens to the voting contract (given that it is payable)
-without calling it you can write
-
-```sophia
- entrypoint pay(v : VotingType, amount : int) =
- Chain.spend(v.address, amount)
-```
-
-#### 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
-type) the parent call also fails. To make it possible to recover from failures,
-contract calls takes a named argument `protected : bool` (default `false`).
-
-The protected argument must be a literal boolean, and when set to `true`
-changes the type of the contract call, wrapping the result in an `option` type.
-If the call fails the result is `None`, otherwise it's `Some(r)` where `r` is
-the return value of the call.
-
-```sophia
-contract interface VotingType =
- entrypoint : vote : string => unit
-
-contract Voter =
- entrypoint tryVote(v : VotingType, alt : string) =
- switch(v.vote(alt, protected = true) : option(unit))
- None => "Voting failed"
- Some(_) => "Voting successful"
-```
-
-Any gas that was consumed by the contract call before the failure stays
-consumed, which means that in order to protect against the remote contract
-running out of gas it is necessary to set a gas limit using the `gas` argument.
-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
-
-Since the version 6.0.0 Sophia supports deploying contracts by other
-contracts. This can be done in two ways:
-
-- Contract cloning via [`Chain.clone`](sophia_stdlib.md#clone)
-- Direct deploy via [`Chain.create`](sophia_stdlib.md#create)
-
-These functions take variable number of arguments that must match the created
-contract's `init` function. Beside that they take some additional named
-arguments – please refer to their documentation for the details.
-
-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
-
-```
-contract IntHolder =
- type state = int
- entrypoint init(x) = x
- entrypoint get() = state
-
-main contract IntHolderFactory =
- stateful entrypoint new(x : int) : IntHolder =
- let ih = Chain.create(x) : IntHolder
- ih
-```
-
-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
-
-Sophia does not have arbitrary mutable state, but only a limited form of state
-associated with each contract instance.
-
-- Each contract defines a type `state` encapsulating its mutable state.
- The type `state` defaults to the `unit`.
-- The initial state of a contract is computed by the contract's `init`
- function. The `init` function is *pure* and returns the initial state as its
- return value.
- If the type `state` is `unit`, the `init` function defaults to returning the value `()`.
- At contract creation time, the `init` function is executed and
- its result is stored as the contract state.
-- The value of the state is accessible from inside the contract
- through an implicitly bound variable `state`.
-- State updates are performed by calling a function `put : state => unit`.
-- Aside from the `put` function (and similar functions for transactions
- and events), the language is purely functional.
-- Functions modifying the state need to be annotated with the `stateful` keyword (see below).
-
-To make it convenient to update parts of a deeply nested state Sophia
-provides special syntax for map/record updates.
-
-#### 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.
-For instance,
-
-```sophia
- stateful entrypoint set_state(s : state) =
- put(s)
-```
-
-Without the `stateful` annotation the compiler does not allow the call to
-`put`. A `stateful` annotation is required to
-
-* Use a stateful primitive function. These are
- - `put`
- - `Chain.spend`
- - `Oracle.register`
- - `Oracle.query`
- - `Oracle.respond`
- - `Oracle.extend`
- - `AENS.preclaim`
- - `AENS.claim`
- - `AENS.transfer`
- - `AENS.revoke`
- - `AENS.update`
-* Call a `stateful` function in the current contract
-* Call another contract with a non-zero `value` argument.
-
-A `stateful` annotation *is not* required to
-
-* Read the contract state.
-* Issue an event using the `event` function.
-* Call another contract with `value = 0`, even if the called function is stateful.
-
-### Payable
-
-#### 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
-contract shall be able to receive funds in this way it has to be declared `payable`:
-
-```sophia
-// A payable contract
-payable contract ExampleContract =
- stateful entrypoint do_stuff() = ...
-```
-
-If in doubt, it is possible to check if an address is payable using
-`Address.is_payable(addr)`.
-
-#### 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)
-that has a non-zero `value` will fail. Contract entrypoints that should be called
-with a non-zero value should be declared `payable`.
-
-```sophia
-payable stateful entrypoint buy(to : address) =
- if(Call.value > 42)
- transfer_item(to)
- else
- abort("Value too low")
-```
-
-Note: In the Aeternity VM (AEVM) contracts and entrypoints were by default
-payable until the Lima release.
-
-### 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
-not entrypoints. Outside the namespace you can refer to the (non-private) names
-by qualifying them with the namespace (`Namespace.name`).
-For example,
-
-```
-namespace Library =
- type number = int
- function inc(x : number) : number = x + 1
-
-contract MyContract =
- entrypoint plus2(x) : Library.number =
- Library.inc(Library.inc(x))
-```
-
-Functions in namespaces have access to the same environment (including the
-`Chain`, `Call`, and `Contract`, builtin namespaces) as function in a contract,
-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
-
-
-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
-
-```
-namespace Library =
- function inc(x) = x + 1
-```
-
-you can use it from another file using an `include`:
-
-```
-include "library.aes"
-contract MyContract =
- entrypoint plus2(x) = Library.inc(Library.inc(x))
-```
-
-This behaves as if the contents of `library.aes` was textually inserted into
-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
-
-Sophia offers [standard library](sophia_stdlib.md) which exposes some
-primitive operations and some higher level utilities. The builtin
-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
-```
-include "List.aes"
-include "Pair.aes"
--- Map is already there!
-
-namespace C =
- entrypoint keys(m : map('a, 'b)) : list('a) =
- List.map(Pair.fst, (Map.to_list(m)))
-```
-
-### Types
-Sophia has the following types:
-
-| Type | Description | Example |
-|----------------------|---------------------------------------------------------------------------------------------|--------------------------------------------------------------|
-| int | A 2-complement integer | ```-1``` |
-| address | Aeternity address, 32 bytes | ```Call.origin``` |
-| bool | A Boolean | ```true``` |
-| bits | A bit field | ```Bits.none``` |
-| bytes(n) | A byte array with `n` bytes | ```#fedcba9876543210``` |
-| string | An array of bytes | ```"Foo"``` |
-| list | A homogeneous immutable singly linked list. | ```[1, 2, 3]``` |
-| ('a, 'b) => 'c | A function. Parentheses can be skipped if there is only one argument | ```(x : int, y : int) => x + y``` |
-| tuple | An ordered heterogeneous array | ```(42, "Foo", true)``` |
-| record | An immutable key value store with fixed key names and typed values | ``` record balance = { owner: address, value: int } ``` |
-| map | An immutable key value store with dynamic mapping of keys of one type to values of one type | ```type accounts = map(string, address)``` |
-| option('a) | An optional value either None or Some('a) | ```Some(42)``` |
-| state | A user defined type holding the contract state | ```record state = { owner: address, magic_key: bytes(4) }``` |
-| event | An append only list of blockchain events (or log entries) | ```datatype event = EventX(indexed int, string)``` |
-| hash | A 32-byte hash - equivalent to `bytes(32)` | |
-| signature | A signature - equivalent to `bytes(64)` | |
-| Chain.ttl | Time-to-live (fixed height or relative to current block) | ```FixedTTL(1050)``` ```RelativeTTL(50)``` |
-| oracle('a, 'b) | And oracle answering questions of type 'a with answers of type 'b | ```Oracle.register(acct, qfee, ttl)``` |
-| 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
-| Type | Constant/Literal example(s) |
-| ---------- | ------------------------------- |
-| int | `-1`, `2425`, `4598275923475723498573485768` |
-| address | `ak_2gx9MEFxKvY9vMG5YnqnXWv1hCsX7rgnfvBLJS4aQurustR1rt` |
-| bool | `true`, `false` |
-| bits | `Bits.none`, `Bits.all` |
-| bytes(8) | `#fedcba9876543210` |
-| string | `"This is a string"` |
-| list | `[1, 2, 3]`, `[(true, 24), (false, 19), (false, -42)]` |
-| tuple | `(42, "Foo", true)` |
-| record | `{ owner = Call.origin, value = 100000000 }` |
-| map | `{["foo"] = 19, ["bar"] = 42}`, `{}` |
-| option(int) | `Some(42)`, `None` |
-| state | `state{ owner = Call.origin, magic_key = #a298105f }` |
-| event | `EventX(0, "Hello")` |
-| hash | `#000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f` |
-| signature | `#000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f` |
-| Chain.ttl | `FixedTTL(1050)`, `RelativeTTL(50)` |
-| oracle('a, 'b) | `ok_2YNyxd6TRJPNrTcEDCe9ra59SVUdp9FR9qWC5msKZWYD9bP9z5` |
-| oracle_query('a, 'b) | `oq_2oRvyowJuJnEkxy58Ckkw77XfWJrmRgmGaLzhdqb67SKEL1gPY` |
-| contract | `ct_Ez6MyeTMm17YnTnDdHTSrzMEBKmy7Uz2sXu347bTDPgVH2ifJ` |
-
-### Arithmetic
-
-Sophia integers (`int`) are represented by 256-bit (AEVM) or arbitrary-sized (FATE) signed words and supports the following
-arithmetic operations:
-- addition (`x + y`)
-- subtraction (`x - y`)
-- multiplication (`x * y`)
-- division (`x / y`), truncated towards zero
-- remainder (`x mod y`), satisfying `y * (x / y) + x mod y == x` for non-zero `y`
-- exponentiation (`x ^ y`)
-
-All operations are *safe* with respect to overflow and underflow. On AEVM they behave as the corresponding
-operations on arbitrary-size integers and fail with `arithmetic_error` if the
-result cannot be represented by a 256-bit signed word. For example, `2 ^ 255`
-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
-
-Sophia integers do not support bit arithmetic. Instead there is a separate
-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 can be introduced with the `type` keyword and can be
-parameterized. For instance
-
-```sophia
-type number = int
-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
-
-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,
-
-```
-datatype one_or_both('a, 'b) = Left('a) | Right('b) | Both('a, 'b)
-```
-
-Elements of data types can be pattern matched against, using the `switch` construct:
-
-```sophia
-function get_left(x : one_or_both('a, 'b)) : option('a) =
- switch(x)
- Left(x) => Some(x)
- Right(_) => None
- Both(x, _) => Some(x)
-```
-
-or directly in the left-hand side:
-```sophia
-function
- get_left : one_or_both('a, 'b) => option('a)
- get_left(Left(x)) = Some(x)
- get_left(Right(_)) = None
- get_left(Both(x, _)) = Some(x)
-```
-
-*NOTE: Data types cannot currently be recursive.*
-
-### Lists
-
-A Sophia list is a dynamically sized, homogenous, immutable, singly
-linked list. A list is constructed with the syntax `[1, 2, 3]`. The
-elements of a list can be any of datatype but they must have the same
-type. The type of lists with elements of type `'e` is written
-`list('e)`. For example we can have the following lists:
-
-```sophia
-[1, 33, 2, 666] : list(int)
-[(1, "aaa"), (10, "jjj"), (666, "the beast")] : list(int * string)
-[{[1] = "aaa", [10] = "jjj"}, {[5] = "eee", [666] = "the beast"}] : list(map(int, string))
-```
-
-New elements can be prepended to the front of a list with the `::`
-operator. So `42 :: [1, 2, 3]` returns the list `[42, 1, 2, 3]`. The
-concatenation operator `++` appends its second argument to its first
-and returns the resulting list. So concatenating two lists
-`[1, 22, 33] ++ [10, 18, 55]` returns the list `[1, 22, 33, 10, 18, 55]`.
-
-Sophia supports list comprehensions known from languages like Python, Haskell or Erlang.
-Example syntax:
-```sophia
-[x + y | x <- [1,2,3,4,5], let k = x*x, if (k > 5), y <- [k, k+1, k+2]]
-// yields [12,13,14,20,21,22,30,31,32]
-```
-
-Lists can be constructed using the range syntax using special `..` operator:
-```sophia
-[1..4] == [1,2,3,4]
-```
-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.
-
-### Maps and records
-
-A Sophia record type is given by a fixed set of fields with associated,
-possibly different, types. For instance
-```sophia
- record account = { name : string,
- balance : int,
- history : list(transaction) }
-```
-
-Maps, on the other hand, can contain an arbitrary number of key-value bindings,
-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.
-
-#### Constructing maps and records
-
-A value of record type is constructed by giving a value for each of the fields.
-For the example above,
-```sophia
- function new_account(name) =
- {name = name, balance = 0, history = []}
-```
-Maps are constructed similarly, with keys enclosed in square brackets
-```sophia
- function example_map() : map(string, int) =
- {["key1"] = 1, ["key2"] = 2}
-```
-The empty map is written `{}`.
-
-#### Accessing values
-
-Record fields access is written `r.f` and map lookup `m[k]`. For instance,
-```sophia
- function get_balance(a : address, accounts : map(address, account)) =
- accounts[a].balance
-```
-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
-
-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`.
-Similarly, `m{[k] = v}` constructs a map with the same values as `m` except
-that `k` maps to `v`. It makes no difference if `m` has a mapping for `k` or
-not.
-
-It is possible to give a name to the old value of a field or mapping in an
-update: instead of `acc{ balance = acc.balance + 100 }` it is possible to write
-`acc{ balance @ b = b + 100 }`, binding `b` to `acc.balance`. When giving a
-name to a map value (`m{ [k] @ x = v }`), the corresponding key must be present
-in the map or execution fails, but a default value can be provided:
-`m{ [k = default] @ x = v }`. In this case `x` is bound to `default` if
-`k` is not in the map.
-
-Updates can be nested:
-```sophia
-function clear_history(a : address, accounts : map(address, account)) : map(address, account) =
- accounts{ [a].history = [] }
-```
-This is equivalent to `accounts{ [a] @ acc = acc{ history = [] } }` and thus
-requires `a` to be present in the accounts map. To have `clear_history` create
-an account if `a` is not in the map you can write (given a function `empty_account`):
-```sophia
- accounts{ [a = empty_account()].history = [] }
-```
-
-#### 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
-
-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).
-
-### 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).
-
-### 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).
-
-
-### Cryptographic builins
-
-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
-
-When a Generalized account is authorized, the authorization function needs
-access to the transaction and the transaction hash for the wrapped transaction. (A `GAMetaTx`
-wrapping a transaction.) The transaction and the transaction hash is available in the primitive
-`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
-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).
-
-
-#### Example
-
-Example for an oracle answering questions of type `string` with answers of type `int`:
-```sophia
-contract Oracles =
-
- stateful entrypoint registerOracle(acct : address,
- sign : signature, // Signed network id + oracle address + contract address
- qfee : int,
- ttl : Chain.ttl) : oracle(string, int) =
- Oracle.register(acct, signature = sign, qfee, ttl)
-
- entrypoint queryFee(o : oracle(string, int)) : int =
- Oracle.query_fee(o)
-
- payable stateful entrypoint createQuery(o : oracle_query(string, int),
- q : string,
- qfee : int,
- qttl : Chain.ttl,
- rttl : int) : oracle_query(string, int) =
- require(qfee =< Call.value, "insufficient value for qfee")
- Oracle.query(o, q, qfee, qttl, RelativeTTL(rttl))
-
- stateful entrypoint extendOracle(o : oracle(string, int),
- ttl : Chain.ttl) : unit =
- Oracle.extend(o, ttl)
-
- stateful entrypoint signExtendOracle(o : oracle(string, int),
- sign : signature, // Signed network id + oracle address + contract address
- ttl : Chain.ttl) : unit =
- Oracle.extend(o, signature = sign, ttl)
-
- stateful entrypoint respond(o : oracle(string, int),
- q : oracle_query(string, int),
- sign : signature, // Signed network id + oracle query id + contract address
- r : int) =
- Oracle.respond(o, q, signature = sign, r)
-
- entrypoint getQuestion(o : oracle(string, int),
- q : oracle_query(string, int)) : string =
- Oracle.get_question(o, q)
-
- entrypoint hasAnswer(o : oracle(string, int),
- q : oracle_query(string, int)) =
- switch(Oracle.get_answer(o, q))
- None => false
- Some(_) => true
-
- entrypoint getAnswer(o : oracle(string, int),
- q : oracle_query(string, int)) : option(int) =
- Oracle.get_answer(o, q)
-```
-
-#### 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
-
-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.
-
-#### 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
-`name` the account holder needs to create a
-[signature](#delegation-signature) `sig` of `addr | name.hash | ct.address`.
-
-Armed with this information we can for example write a function that extends
-the name if it expires within 1000 blocks:
-```sophia
- stateful entrypoint extend_if_necessary(addr : address, name : string, sig : signature) =
- switch(AENS.lookup(name))
- None => ()
- Some(AENS.Name(_, FixedTTL(expiry), _)) =>
- if(Chain.block_height + 1000 > expiry)
- AENS.update(addr, name, Some(RelativeTTL(50000)), None, None, signature = sig)
-```
-
-And we can write functions that adds and removes keys from the pointers of the
-name:
-```sophia
- stateful entrypoint add_key(addr : address, name : string, key : string,
- pt : AENS.pointee, sig : signature) =
- switch(AENS.lookup(name))
- None => ()
- Some(AENS.Name(_, _, ptrs)) =>
- AENS.update(addr, name, None, None, Some(ptrs{[key] = pt}), signature = sig)
-
- stateful entrypoint delete_key(addr : address, name : string,
- key : string, sig : signature) =
- switch(AENS.lookup(name))
- None => ()
- Some(AENS.Name(_, _, ptrs)) =>
- let ptrs = Map.delete(key, ptrs)
- AENS.update(addr, name, None, None, Some(ptrs), signature = sig)
-```
-
-*Note:* From the Iris hardfork more strict rules apply for AENS pointers, when
-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
-
-Sophia contracts log structured messages to an event log in the resulting
-blockchain transaction. The event log is quite similar to [Events in
-Solidity](https://solidity.readthedocs.io/en/v0.4.24/contracts.html#events).
-Events are further discussed in the [protocol](https://github.com/aeternity/protocol/blob/master/contracts/events.md).
-
-
-To use events a contract must declare a datatype `event`, and events are then
-logged using the `Chain.event` function:
-
-```
- datatype event
- = Event1(int, int, string)
- | Event2(string, address)
-
- Chain.event(e : event) : unit
-```
-
-The event can have 0-3 *indexed* fields, and an optional *payload* field. A
-field is indexed if it fits in a 32-byte word, i.e.
-- `bool`
-- `int`
-- `bits`
-- `address`
-- `oracle(_, _)`
-- `oracle_query(_, _)`
-- contract types
-- `bytes(n)` for `n` ≤ 32, in particular `hash`
-
-The payload field must be either a string or a byte array of more than 32 bytes.
-The fields can appear in any order.
-
-*NOTE:* Indexing is not part of the core aeternity node.
-
-Events are emitted by using the `Chain.event` function. The following function
-will emit one Event of each kind in the example.
-
-```sophia
- entrypoint emit_events() : () =
- Chain.event(Event1(42, 34, "foo"))
- Chain.event(Event2("This is not indexed", Contract.address))
-```
-
-#### 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.
-```sophia
-AnotherEvent(string, indexed address)
-
-...
-
-Chain.event(AnotherEvent("This is not indexed", Contract.address))
-```
-would yield exactly the same result in the example above!
-
-### 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
-
-```
-@compiler >= 4.3
-@compiler < 4.4
-```
-
-Valid operators in compiler pragmas are `<`, `=<`, `==`, `>=`, and `>`. Version
-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
-
-Contracts can fail with an (uncatchable) exception using the built-in function
-
-```
-abort(reason : string) : 'a
-```
-
-Calling abort causes the top-level call transaction to return an error result
-containing the `reason` string. Only the gas used up to and including the abort
-call is charged. This is different from termination due to a crash which
-consumes all available gas.
-
-For convenience the following function is also built-in:
-
-```
-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
-
-Some chain operations (`Oracle.` and `AENS.`) have an
-optional delegation signature. This is typically used when a user/accounts
-would like to allow a contract to act on it's behalf. The exact data to be
-signed varies for the different operations, but in all cases you should prepend
-the signature data with the `network_id` (`ae_mainnet` for the Aeternity mainnet, etc.).
+This file has been moved [here](sophia_features.md)
\ No newline at end of file
diff --git a/docs/sophia_examples.md b/docs/sophia_examples.md
new file mode 100644
index 0000000..fab9285
--- /dev/null
+++ b/docs/sophia_examples.md
@@ -0,0 +1,73 @@
+# 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) })
+```
+
+## Repositories
+This is a list with repositories that include smart contracts written in Sophia:
+
+- [aepp-sophia-examples](https://github.com/aeternity/aepp-sophia-examples)
+ - A repository that contains lots of different examples. The functionality of these examples is - to some extent - also covered by tests written in JavaScript.
\ No newline at end of file
diff --git a/docs/sophia_features.md b/docs/sophia_features.md
new file mode 100644
index 0000000..6be7ac4
--- /dev/null
+++ b/docs/sophia_features.md
@@ -0,0 +1,783 @@
+# Features
+## Contracts
+
+The main unit of code in Sophia is the *contract*.
+
+- A contract implementation, or simply a contract, is the code for a
+ smart contract and consists of a list of types, entrypoints and local
+ functions. Only the entrypoints can be called from outside the contract.
+- A contract instance is an entity living on the block chain (or in a state
+ channel). Each instance has an address that can be used to call its
+ entrypoints, either from another contract or in a call transaction.
+- A contract may define a type `state` encapsulating its local
+ state. When creating a new contract the `init` entrypoint is executed and the
+ 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.
+
+### 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
+of a number of type definitions and entrypoint declarations. For instance,
+
+```sophia
+// A contract type
+contract interface VotingType =
+ entrypoint vote : string => unit
+```
+
+Now given contract address of type `VotingType` you can call the `vote`
+entrypoint of that contract:
+
+```sophia
+contract VoteTwice =
+ entrypoint voteTwice(v : VotingType, alt : string) =
+ v.vote(alt)
+ v.vote(alt)
+```
+
+Contract calls take two optional named arguments `gas : int` and `value : int`
+that lets you set a gas limit and provide tokens to a contract call. If omitted
+the defaults are no gas limit and no tokens. Suppose there is a fee for voting:
+
+```sophia
+ entrypoint voteTwice(v : VotingType, fee : int, alt : string) =
+ v.vote(value = fee, alt)
+ v.vote(value = fee, alt)
+```
+
+Named arguments can be given in any order.
+
+Note that reentrant calls are not permitted. In other words, when calling
+another contract it cannot call you back (directly or indirectly).
+
+To construct a value of a contract type you can give a contract address literal
+(for instance `ct_2gPXZnZdKU716QBUFKaT4VdBZituK93KLvHJB3n4EnbrHHw4Ay`), or
+convert an account address to a contract address using `Address.to_contract`.
+Note that if the contract does not exist, or it doesn't have the entrypoint, or
+the type of the entrypoint does not match the stated contract type, the call
+fails.
+
+To recover the underlying `address` of a contract instance there is a field
+`address : address`. For instance, to send tokens to the voting contract (given that it is payable)
+without calling it you can write
+
+```sophia
+ entrypoint pay(v : VotingType, amount : int) =
+ Chain.spend(v.address, amount)
+```
+
+### 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
+type) the parent call also fails. To make it possible to recover from failures,
+contract calls takes a named argument `protected : bool` (default `false`).
+
+The protected argument must be a literal boolean, and when set to `true`
+changes the type of the contract call, wrapping the result in an `option` type.
+If the call fails the result is `None`, otherwise it's `Some(r)` where `r` is
+the return value of the call.
+
+```sophia
+contract interface VotingType =
+ entrypoint : vote : string => unit
+
+contract Voter =
+ entrypoint tryVote(v : VotingType, alt : string) =
+ switch(v.vote(alt, protected = true) : option(unit))
+ None => "Voting failed"
+ Some(_) => "Voting successful"
+```
+
+Any gas that was consumed by the contract call before the failure stays
+consumed, which means that in order to protect against the remote contract
+running out of gas it is necessary to set a gas limit using the `gas` argument.
+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
+
+Since the version 6.0.0 Sophia supports deploying contracts by other
+contracts. This can be done in two ways:
+
+- Contract cloning via [`Chain.clone`](sophia_stdlib.md#clone)
+- Direct deploy via [`Chain.create`](sophia_stdlib.md#create)
+
+These functions take variable number of arguments that must match the created
+contract's `init` function. Beside that they take some additional named
+arguments – please refer to their documentation for the details.
+
+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
+ entrypoint get() = state
+
+main contract IntHolderFactory =
+ stateful entrypoint new(x : int) : IntHolder =
+ let ih = Chain.create(x) : IntHolder
+ ih
+```
+
+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
+
+Sophia does not have arbitrary mutable state, but only a limited form of state
+associated with each contract instance.
+
+- Each contract defines a type `state` encapsulating its mutable state.
+ The type `state` defaults to the `unit`.
+- The initial state of a contract is computed by the contract's `init`
+ function. The `init` function is *pure* and returns the initial state as its
+ return value.
+ If the type `state` is `unit`, the `init` function defaults to returning the value `()`.
+ At contract creation time, the `init` function is executed and
+ its result is stored as the contract state.
+- The value of the state is accessible from inside the contract
+ through an implicitly bound variable `state`.
+- State updates are performed by calling a function `put : state => unit`.
+- Aside from the `put` function (and similar functions for transactions
+ and events), the language is purely functional.
+- Functions modifying the state need to be annotated with the `stateful` keyword (see below).
+
+To make it convenient to update parts of a deeply nested state Sophia
+provides special syntax for map/record updates.
+
+### 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.
+For instance,
+
+```sophia
+ stateful entrypoint set_state(s : state) =
+ put(s)
+```
+
+Without the `stateful` annotation the compiler does not allow the call to
+`put`. A `stateful` annotation is required to
+
+* Use a stateful primitive function. These are
+ - `put`
+ - `Chain.spend`
+ - `Oracle.register`
+ - `Oracle.query`
+ - `Oracle.respond`
+ - `Oracle.extend`
+ - `AENS.preclaim`
+ - `AENS.claim`
+ - `AENS.transfer`
+ - `AENS.revoke`
+ - `AENS.update`
+* Call a `stateful` function in the current contract
+* Call another contract with a non-zero `value` argument.
+
+A `stateful` annotation *is not* required to
+
+* Read the contract state.
+* Issue an event using the `event` function.
+* Call another contract with `value = 0`, even if the called function is stateful.
+
+## Payable
+
+### 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
+contract shall be able to receive funds in this way it has to be declared `payable`:
+
+```sophia
+// A payable contract
+payable contract ExampleContract =
+ stateful entrypoint do_stuff() = ...
+```
+
+If in doubt, it is possible to check if an address is payable using
+`Address.is_payable(addr)`.
+
+### 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)
+that has a non-zero `value` will fail. Contract entrypoints that should be called
+with a non-zero value should be declared `payable`.
+
+```sophia
+payable stateful entrypoint buy(to : address) =
+ if(Call.value > 42)
+ transfer_item(to)
+ else
+ abort("Value too low")
+```
+
+Note: In the æternity VM (AEVM) contracts and entrypoints were by default
+payable until the Lima release.
+
+## 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
+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
+
+contract MyContract =
+ entrypoint plus2(x) : Library.number =
+ Library.inc(Library.inc(x))
+```
+
+Functions in namespaces have access to the same environment (including the
+`Chain`, `Call`, and `Contract`, builtin namespaces) as function in a contract,
+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
+
+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))
+```
+
+This behaves as if the contents of `library.aes` was textually inserted into
+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
+
+Sophia offers [standard library](sophia_stdlib.md) which exposes some
+primitive operations and some higher level utilities. The builtin
+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!
+
+namespace C =
+ entrypoint keys(m : map('a, 'b)) : list('a) =
+ List.map(Pair.fst, (Map.to_list(m)))
+```
+
+## Types
+Sophia has the following types:
+
+| Type | Description | Example |
+|----------------------|---------------------------------------------------------------------------------------------|--------------------------------------------------------------|
+| int | A 2-complement integer | ```-1``` |
+| address | æternity address, 32 bytes | ```Call.origin``` |
+| bool | A Boolean | ```true``` |
+| bits | A bit field | ```Bits.none``` |
+| bytes(n) | A byte array with `n` bytes | ```#fedcba9876543210``` |
+| string | An array of bytes | ```"Foo"``` |
+| list | A homogeneous immutable singly linked list. | ```[1, 2, 3]``` |
+| ('a, 'b) => 'c | A function. Parentheses can be skipped if there is only one argument | ```(x : int, y : int) => x + y``` |
+| tuple | An ordered heterogeneous array | ```(42, "Foo", true)``` |
+| record | An immutable key value store with fixed key names and typed values | ``` record balance = { owner: address, value: int } ``` |
+| map | An immutable key value store with dynamic mapping of keys of one type to values of one type | ```type accounts = map(string, address)``` |
+| option('a) | An optional value either None or Some('a) | ```Some(42)``` |
+| state | A user defined type holding the contract state | ```record state = { owner: address, magic_key: bytes(4) }``` |
+| event | An append only list of blockchain events (or log entries) | ```datatype event = EventX(indexed int, string)``` |
+| hash | A 32-byte hash - equivalent to `bytes(32)` | |
+| signature | A signature - equivalent to `bytes(64)` | |
+| Chain.ttl | Time-to-live (fixed height or relative to current block) | ```FixedTTL(1050)``` ```RelativeTTL(50)``` |
+| oracle('a, 'b) | And oracle answering questions of type 'a with answers of type 'b | ```Oracle.register(acct, qfee, ttl)``` |
+| 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
+| Type | Constant/Literal example(s) |
+| ---------- | ------------------------------- |
+| int | `-1`, `2425`, `4598275923475723498573485768` |
+| address | `ak_2gx9MEFxKvY9vMG5YnqnXWv1hCsX7rgnfvBLJS4aQurustR1rt` |
+| bool | `true`, `false` |
+| bits | `Bits.none`, `Bits.all` |
+| bytes(8) | `#fedcba9876543210` |
+| string | `"This is a string"` |
+| list | `[1, 2, 3]`, `[(true, 24), (false, 19), (false, -42)]` |
+| tuple | `(42, "Foo", true)` |
+| record | `{ owner = Call.origin, value = 100000000 }` |
+| map | `{["foo"] = 19, ["bar"] = 42}`, `{}` |
+| option(int) | `Some(42)`, `None` |
+| state | `state{ owner = Call.origin, magic_key = #a298105f }` |
+| event | `EventX(0, "Hello")` |
+| hash | `#000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f` |
+| signature | `#000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f` |
+| Chain.ttl | `FixedTTL(1050)`, `RelativeTTL(50)` |
+| oracle('a, 'b) | `ok_2YNyxd6TRJPNrTcEDCe9ra59SVUdp9FR9qWC5msKZWYD9bP9z5` |
+| oracle_query('a, 'b) | `oq_2oRvyowJuJnEkxy58Ckkw77XfWJrmRgmGaLzhdqb67SKEL1gPY` |
+| contract | `ct_Ez6MyeTMm17YnTnDdHTSrzMEBKmy7Uz2sXu347bTDPgVH2ifJ` |
+
+## Arithmetic
+
+Sophia integers (`int`) are represented by 256-bit (AEVM) or arbitrary-sized (FATE) signed words and supports the following
+arithmetic operations:
+- addition (`x + y`)
+- subtraction (`x - y`)
+- multiplication (`x * y`)
+- division (`x / y`), truncated towards zero
+- remainder (`x mod y`), satisfying `y * (x / y) + x mod y == x` for non-zero `y`
+- exponentiation (`x ^ y`)
+
+All operations are *safe* with respect to overflow and underflow. On AEVM they behave as the corresponding
+operations on arbitrary-size integers and fail with `arithmetic_error` if the
+result cannot be represented by a 256-bit signed word. For example, `2 ^ 255`
+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
+
+Sophia integers do not support bit arithmetic. Instead there is a separate
+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 can be introduced with the `type` keyword and can be
+parameterized. For instance
+
+```sophia
+type number = int
+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
+
+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)
+```
+
+Elements of data types can be pattern matched against, using the `switch` construct:
+
+```sophia
+function get_left(x : one_or_both('a, 'b)) : option('a) =
+ switch(x)
+ Left(x) => Some(x)
+ Right(_) => None
+ Both(x, _) => Some(x)
+```
+
+or directly in the left-hand side:
+```sophia
+function
+ get_left : one_or_both('a, 'b) => option('a)
+ get_left(Left(x)) = Some(x)
+ get_left(Right(_)) = None
+ get_left(Both(x, _)) = Some(x)
+```
+
+*NOTE: Data types cannot currently be recursive.*
+
+## Lists
+
+A Sophia list is a dynamically sized, homogenous, immutable, singly
+linked list. A list is constructed with the syntax `[1, 2, 3]`. The
+elements of a list can be any of datatype but they must have the same
+type. The type of lists with elements of type `'e` is written
+`list('e)`. For example we can have the following lists:
+
+```sophia
+[1, 33, 2, 666] : list(int)
+[(1, "aaa"), (10, "jjj"), (666, "the beast")] : list(int * string)
+[{[1] = "aaa", [10] = "jjj"}, {[5] = "eee", [666] = "the beast"}] : list(map(int, string))
+```
+
+New elements can be prepended to the front of a list with the `::`
+operator. So `42 :: [1, 2, 3]` returns the list `[42, 1, 2, 3]`. The
+concatenation operator `++` appends its second argument to its first
+and returns the resulting list. So concatenating two lists
+`[1, 22, 33] ++ [10, 18, 55]` returns the list `[1, 22, 33, 10, 18, 55]`.
+
+Sophia supports list comprehensions known from languages like Python, Haskell or Erlang.
+Example syntax:
+```sophia
+[x + y | x <- [1,2,3,4,5], let k = x*x, if (k > 5), y <- [k, k+1, k+2]]
+// yields [12,13,14,20,21,22,30,31,32]
+```
+
+Lists can be constructed using the range syntax using special `..` operator:
+```sophia
+[1..4] == [1,2,3,4]
+```
+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.
+
+## Maps and records
+
+A Sophia record type is given by a fixed set of fields with associated,
+possibly different, types. For instance
+```sophia
+ record account = { name : string,
+ balance : int,
+ history : list(transaction) }
+```
+
+Maps, on the other hand, can contain an arbitrary number of key-value bindings,
+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.
+
+### Constructing maps and records
+
+A value of record type is constructed by giving a value for each of the fields.
+For the example above,
+```sophia
+ function new_account(name) =
+ {name = name, balance = 0, history = []}
+```
+Maps are constructed similarly, with keys enclosed in square brackets
+```sophia
+ function example_map() : map(string, int) =
+ {["key1"] = 1, ["key2"] = 2}
+```
+The empty map is written `{}`.
+
+### Accessing values
+
+Record fields access is written `r.f` and map lookup `m[k]`. For instance,
+```sophia
+ function get_balance(a : address, accounts : map(address, account)) =
+ accounts[a].balance
+```
+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
+
+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`.
+Similarly, `m{[k] = v}` constructs a map with the same values as `m` except
+that `k` maps to `v`. It makes no difference if `m` has a mapping for `k` or
+not.
+
+It is possible to give a name to the old value of a field or mapping in an
+update: instead of `acc{ balance = acc.balance + 100 }` it is possible to write
+`acc{ balance @ b = b + 100 }`, binding `b` to `acc.balance`. When giving a
+name to a map value (`m{ [k] @ x = v }`), the corresponding key must be present
+in the map or execution fails, but a default value can be provided:
+`m{ [k = default] @ x = v }`. In this case `x` is bound to `default` if
+`k` is not in the map.
+
+Updates can be nested:
+```sophia
+function clear_history(a : address, accounts : map(address, account)) : map(address, account) =
+ accounts{ [a].history = [] }
+```
+This is equivalent to `accounts{ [a] @ acc = acc{ history = [] } }` and thus
+requires `a` to be present in the accounts map. To have `clear_history` create
+an account if `a` is not in the map you can write (given a function `empty_account`):
+```sophia
+ accounts{ [a = empty_account()].history = [] }
+```
+
+### 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
+
+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).
+
+## 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).
+
+## 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).
+
+## Cryptographic builtins
+
+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)`.
+
+## 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`
+wrapping a transaction.) The transaction and the transaction hash is available in the primitive
+`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
+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).
+
+### Example
+
+Example for an oracle answering questions of type `string` with answers of type `int`:
+```sophia
+contract Oracles =
+
+ stateful entrypoint registerOracle(acct : address,
+ sign : signature, // Signed network id + oracle address + contract address
+ qfee : int,
+ ttl : Chain.ttl) : oracle(string, int) =
+ Oracle.register(acct, signature = sign, qfee, ttl)
+
+ entrypoint queryFee(o : oracle(string, int)) : int =
+ Oracle.query_fee(o)
+
+ payable stateful entrypoint createQuery(o : oracle_query(string, int),
+ q : string,
+ qfee : int,
+ qttl : Chain.ttl,
+ rttl : int) : oracle_query(string, int) =
+ require(qfee =< Call.value, "insufficient value for qfee")
+ Oracle.query(o, q, qfee, qttl, RelativeTTL(rttl))
+
+ stateful entrypoint extendOracle(o : oracle(string, int),
+ ttl : Chain.ttl) : unit =
+ Oracle.extend(o, ttl)
+
+ stateful entrypoint signExtendOracle(o : oracle(string, int),
+ sign : signature, // Signed network id + oracle address + contract address
+ ttl : Chain.ttl) : unit =
+ Oracle.extend(o, signature = sign, ttl)
+
+ stateful entrypoint respond(o : oracle(string, int),
+ q : oracle_query(string, int),
+ sign : signature, // Signed network id + oracle query id + contract address
+ r : int) =
+ Oracle.respond(o, q, signature = sign, r)
+
+ entrypoint getQuestion(o : oracle(string, int),
+ q : oracle_query(string, int)) : string =
+ Oracle.get_question(o, q)
+
+ entrypoint hasAnswer(o : oracle(string, int),
+ q : oracle_query(string, int)) =
+ switch(Oracle.get_answer(o, q))
+ None => false
+ Some(_) => true
+
+ entrypoint getAnswer(o : oracle(string, int),
+ q : oracle_query(string, int)) : option(int) =
+ Oracle.get_answer(o, q)
+```
+
+### 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
+
+Contracts can interact with the
+[æternity naming system](https://github.com/aeternity/protocol/blob/master/AENS.md).
+For this purpose the [AENS](sophia_stdlib.md#aens) library was exposed.
+
+### 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
+`name` the account holder needs to create a
+[signature](#delegation-signature) `sig` of `addr | name.hash | ct.address`.
+
+Armed with this information we can for example write a function that extends
+the name if it expires within 1000 blocks:
+```sophia
+ stateful entrypoint extend_if_necessary(addr : address, name : string, sig : signature) =
+ switch(AENS.lookup(name))
+ None => ()
+ Some(AENS.Name(_, FixedTTL(expiry), _)) =>
+ if(Chain.block_height + 1000 > expiry)
+ AENS.update(addr, name, Some(RelativeTTL(50000)), None, None, signature = sig)
+```
+
+And we can write functions that adds and removes keys from the pointers of the
+name:
+```sophia
+ stateful entrypoint add_key(addr : address, name : string, key : string,
+ pt : AENS.pointee, sig : signature) =
+ switch(AENS.lookup(name))
+ None => ()
+ Some(AENS.Name(_, _, ptrs)) =>
+ AENS.update(addr, name, None, None, Some(ptrs{[key] = pt}), signature = sig)
+
+ stateful entrypoint delete_key(addr : address, name : string,
+ key : string, sig : signature) =
+ switch(AENS.lookup(name))
+ None => ()
+ Some(AENS.Name(_, _, ptrs)) =>
+ let ptrs = Map.delete(key, ptrs)
+ AENS.update(addr, name, None, None, Some(ptrs), signature = sig)
+```
+
+*Note:* From the Iris hardfork more strict rules apply for AENS pointers, when
+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
+
+Sophia contracts log structured messages to an event log in the resulting
+blockchain transaction. The event log is quite similar to [Events in
+Solidity](https://solidity.readthedocs.io/en/v0.4.24/contracts.html#events).
+Events are further discussed in the [protocol](https://github.com/aeternity/protocol/blob/master/contracts/events.md).
+
+
+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)
+
+ Chain.event(e : event) : unit
+```
+
+The event can have 0-3 *indexed* fields, and an optional *payload* field. A
+field is indexed if it fits in a 32-byte word, i.e.
+- `bool`
+- `int`
+- `bits`
+- `address`
+- `oracle(_, _)`
+- `oracle_query(_, _)`
+- contract types
+- `bytes(n)` for `n` ≤ 32, in particular `hash`
+
+The payload field must be either a string or a byte array of more than 32 bytes.
+The fields can appear in any order.
+
+*NOTE:* Indexing is not part of the core æternity node.
+
+Events are emitted by using the `Chain.event` function. The following function
+will emit one Event of each kind in the example.
+
+```sophia
+ entrypoint emit_events() : () =
+ Chain.event(Event1(42, 34, "foo"))
+ Chain.event(Event2("This is not indexed", Contract.address))
+```
+
+### 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.
+```sophia
+AnotherEvent(string, indexed address)
+
+...
+
+Chain.event(AnotherEvent("This is not indexed", Contract.address))
+```
+would yield exactly the same result in the example above!
+
+## 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
+```
+
+Valid operators in compiler pragmas are `<`, `=<`, `==`, `>=`, and `>`. Version
+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
+
+Contracts can fail with an (uncatchable) exception using the built-in function
+
+```sophia
+abort(reason : string) : 'a
+```
+
+Calling abort causes the top-level call transaction to return an error result
+containing the `reason` string. Only the gas used up to and including the abort
+call is charged. This is different from termination due to a crash which
+consumes all available gas.
+
+For convenience the following function is also built-in:
+
+```sophia
+function require(b : bool, err : string) =
+ if(!b) abort(err)
+```
+
+## Delegation signature
+
+Some chain operations (`Oracle.` and `AENS.`) have an
+optional delegation signature. This is typically used when a user/accounts
+would like to allow a contract to act on it's behalf. The exact data to be
+signed varies for the different operations, but in all cases you should prepend
+the signature data with the `network_id` (`ae_mainnet` for the æternity mainnet, etc.).
\ No newline at end of file
diff --git a/docs/sophia_stdlib.md b/docs/sophia_stdlib.md
index 9a9ed5a..04421d5 100644
--- a/docs/sophia_stdlib.md
+++ b/docs/sophia_stdlib.md
@@ -12,40 +12,40 @@ in the scope and do not need any actions to be used, while the others require so
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
```
include "List.aes"
```
-- [List](#List)
-- [Option](#Option)
-- [String](#String)
-- [Func](#Func)
-- [Pair](#Pair)
-- [Triple](#Triple)
-- [BLS12_381](#BLS12_381)
-- [Frac](#Frac)
+- [List](#list)
+- [Option](#option)
+- [String](#string)
+- [Func](#func)
+- [Pair](#pair)
+- [Triple](#triple)
+- [BLS12_381](bls12_381)
+- [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
-## 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,25 +481,25 @@ 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).
+The following functionality is available for interacting with the æternity
+naming system (AENS).
If `owner` is equal to `Contract.address` the signature `signature` is
ignored, and can be left out since it is a named argument. Otherwise we need
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, ) : 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, ) : 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, ) : 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, ) : 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), ) : 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
diff --git a/docs/sophia_syntax.md b/docs/sophia_syntax.md
new file mode 100644
index 0000000..db438b5
--- /dev/null
+++ b/docs/sophia_syntax.md
@@ -0,0 +1,263 @@
+# 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