Compare commits
15 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 21cc6f2b3e | |||
| e8da0a7cfe | |||
| 4562a7166c | |||
| fc2875965e | |||
| 9d296f04cb | |||
| ea98fc97bb | |||
| 46ac9bfa82 | |||
| 75f2711148 | |||
| 8e6c6d81ad | |||
| 2d17ce3ee2 | |||
| fc08fe09a5 | |||
| 6c17e57a7c | |||
| 69713036d0 | |||
| f56eeb0b2b | |||
| 3f177d363f |
@@ -3,7 +3,7 @@ version: 2.1
|
||||
executors:
|
||||
aebuilder:
|
||||
docker:
|
||||
- image: aeternity/builder:bionic-otp24
|
||||
- image: aeternity/builder:xenial-otp21
|
||||
user: builder
|
||||
working_directory: ~/aesophia
|
||||
|
||||
|
||||
@@ -13,6 +13,10 @@ jobs:
|
||||
- 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 -U
|
||||
- run: git config --global user.email "github-action@users.noreply.github.com"
|
||||
- run: git config --global user.name "GitHub Action"
|
||||
|
||||
@@ -13,6 +13,10 @@ jobs:
|
||||
- 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 -U
|
||||
- run: git config --global user.email "github-action@users.noreply.github.com"
|
||||
- run: git config --global user.name "GitHub Action"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
mkdocs==1.2.4
|
||||
mkdocs-simple-hooks==0.1.5
|
||||
mkdocs-material==7.3.6
|
||||
mike==1.1.2
|
||||
pygments==2.12.0
|
||||
mkdocs-simple-hooks==0.1.3
|
||||
mkdocs-material==7.1.9
|
||||
mike==1.0.1
|
||||
pygments==2.11.2
|
||||
+10
-48
@@ -4,52 +4,9 @@ All notable changes to this project will be documented in this file.
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [CERES 8.0.0]
|
||||
### Added
|
||||
- Bitwise operations for integers: `band`, `bor`, `bxor`, `bnot`, `<<` and `>>`.
|
||||
- `Int.mulmod` - combined builtin operation for multiplication and modulus.
|
||||
- `Crypto.poseidon` - a ZK/SNARK-friendly hash function (over the BLS12-381 scalar field).
|
||||
- `Address.to_bytes` - convert an address to its binary representation (for hashing, etc.).
|
||||
- Raw data pointers added to AENS. In short we have introduced a new namespace
|
||||
`AENSv2`; they contain types similar to the old `AENS`; `AENS.name` and
|
||||
`AENS.pointee`, where the latter now has a constructor `DataPt(string)`. All
|
||||
AENS actions have been moved to `AENSv2`, and `AENSv2.lookup` and
|
||||
`AENSv2.update` consume and produce the new types. The old `AENS` namespace
|
||||
only contains the old datatypes, that can be used to interface existing
|
||||
contracts. Standard library `AENSCompat` is added to convert between old and
|
||||
new pointers.
|
||||
### Changed
|
||||
### Removed
|
||||
- `Bitwise.aes` standard library is removed - the builtin operations are superior.
|
||||
|
||||
## [Unreleased]
|
||||
### Added
|
||||
- Options to enable/disable certain optimizations.
|
||||
- The ability to call a different instance of the current contract
|
||||
```
|
||||
contract Main =
|
||||
entrypoint spend(x : int) : int = x
|
||||
entrypoint f(c : Main) : int = c.spend(10)
|
||||
```
|
||||
- Return a mapping from variables to FATE registers in the compilation output.
|
||||
### Changed
|
||||
- Type definitions serialised to ACI as `typedefs` field instead of `type_defs` to increase compatibility.
|
||||
### Removed
|
||||
### Fixed
|
||||
- Typechecker crashes if Chain.create or Chain.clone are used without arguments.
|
||||
|
||||
## [7.0.1]
|
||||
### Added
|
||||
- Add CONTRIBUTING.md file.
|
||||
### Changed
|
||||
- Update Sophia syntax docs to include missing information about existing syntax.
|
||||
### Fixed
|
||||
- [404](https://github.com/aeternity/aesophia/issues/404) Contract polymorphism crashes on non-obvious child contract typing.
|
||||
|
||||
## [7.0.0]
|
||||
### Added
|
||||
- Added support for `EXIT` opcode via `exit : (string) => 'a` function (behaves same as `ABORT`, but consumes all gas).
|
||||
- Compiler warnings for the following: shadowing, negative spends, division by zero, unused functions, unused includes, unused stateful annotations, unused variables, unused parameters, unused user-defined type, dead return value.
|
||||
- Compiler warnings for the follwing: shadowing, negative spends, division by zero, unused functions, unused includes, unused stateful annotations, unused variables, unused parameters, unused user-defined type, dead return value.
|
||||
- The pipe operator |>
|
||||
```
|
||||
[1, 2, 3] |> List.first |> Option.is_some // Option.is_some(List.first([1, 2, 3]))
|
||||
@@ -59,7 +16,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
function sum(l : list(int)) : int = foldl((+), 0, l)
|
||||
function logical_and(x, y) = (&&)(x, y)
|
||||
```
|
||||
- Contract interfaces polymorphism
|
||||
- Add comparable typevar constraints (`ord` and `eq`)
|
||||
```
|
||||
lt : 'a is ord ; ('a, 'a) => bool
|
||||
lt(x, y) = x < y
|
||||
|
||||
is_eq : 'a is eq ; ('a, 'a) => bool
|
||||
is_eq(x, y) = x == y
|
||||
```
|
||||
### Changed
|
||||
- Error messages have been restructured (less newlines) to provide more unified errors. Also `pp_oneline/1` has been added.
|
||||
- Ban empty record definitions (e.g. `record r = {}` would give an error).
|
||||
@@ -389,9 +353,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
- Simplify calldata creation - instead of passing a compiled contract, simply
|
||||
pass a (stubbed) contract string.
|
||||
|
||||
[Unreleased]: https://github.com/aeternity/aesophia/compare/v7.0.1...HEAD
|
||||
[7.0.1]: https://github.com/aeternity/aesophia/compare/v7.0.0...v7.0.1
|
||||
[7.0.0]: https://github.com/aeternity/aesophia/compare/v6.1.0...v7.0.0
|
||||
[Unreleased]: https://github.com/aeternity/aesophia/compare/v6.1.0...HEAD
|
||||
[6.1.0]: https://github.com/aeternity/aesophia/compare/v6.0.2...v6.1.0
|
||||
[6.0.2]: https://github.com/aeternity/aesophia/compare/v6.0.1...v6.0.2
|
||||
[6.0.1]: https://github.com/aeternity/aesophia/compare/v6.0.0...v6.0.1
|
||||
|
||||
@@ -1,40 +0,0 @@
|
||||
# Contributing to Sophia
|
||||
|
||||
## Checklist For Creating New Pull Requests
|
||||
|
||||
The following points should be considered before creating a new PR to the Sophia compiler.
|
||||
|
||||
### Documentation
|
||||
|
||||
- The [Changelog](CHANGELOG.md) file should be updated for all PRs.
|
||||
- If a PR introduces a new feature that is relevant to the users of the language, the [Sophia Features Documentation](docs/sophia_features.md) should be updated to describe the new feature.
|
||||
- If a PR introduces new syntax (e.g. changes in [aeso_syntax.erl](src/aeso_syntax.erl), [aeso_scan.erl](src/aeso_scan.erl), or [aeso_parser.erl](src/aeso_parser.erl)), the [Sophia Syntax Documentation](docs/sophia_syntax.md) should be updated to include the new syntax.
|
||||
- If a PR introduces a new library, the public interface of the new library should be fully documented in the [Sophia Standard Library Documentation](docs/sophia_stdlib.md).
|
||||
- If a PR introduces a new compiler option, the new option should be documented in the file
|
||||
[aeso_compiler.md](docs/aeso_compiler.md).
|
||||
|
||||
### Tests
|
||||
|
||||
- If a PR introduces new syntax (e.g. changes in [aeso_syntax.erl](src/aeso_syntax.erl), [aeso_scan.erl](src/aeso_scan.erl), or [aeso_parser.erl](src/aeso_parser.erl)), the contract [all_syntax.aes](test/contracts/all_syntax.aes) should be updated to include the new syntax.
|
||||
- If a PR fixes a bug, the code that replicates the bug should be added as a new passing test contract.
|
||||
- If a PR introduces a new feature, add tests for both successful and failing usage of that feature. In order to run the entire compilation pipeline and to avoid erroring during intermediate steps, failing tests should not be mixed with the successful ones.
|
||||
|
||||
### Source Code
|
||||
|
||||
- If a PR introduces new syntax (e.g. changes in [aeso_syntax.erl](src/aeso_syntax.erl), [aeso_scan.erl](src/aeso_scan.erl), or [aeso_parser.erl](src/aeso_parser.erl)), the following code should be updated to handle the new syntax:
|
||||
- The function `aeso_syntax_utils:fold/4` in the file [aeso_syntax_utils.erl](src/aeso_syntax_utils.erl).
|
||||
- Any related pretty printing function in the file [aeso_pretty.erl](src/aeso_pretty.erl), depending on the type of the newly added syntax.
|
||||
|
||||
## Checklist For Creating a Release
|
||||
|
||||
- Update the version in the file [aesophia.app.src](src/aesophia.app.src).
|
||||
- Update the version in the file [rebar.config](rebar.config).
|
||||
- In the [Changelog](CHANGELOG.md):
|
||||
- Update the `Unreleased` changes to be under the new version.
|
||||
- Update the version at the bottom of the file.
|
||||
- Commit and the changes and create a new PR (check the commit of [v6.1.0](https://github.com/aeternity/aesophia/commit/5ad5270e381f6e810d7b8b5cdc168d283e7a90bb) for reference).
|
||||
- Create a release after merging the new PR to `master` branch.
|
||||
- After releasing `aesophia`, refer to each of the following repositories and create new releases as well, using the new `aesophia` release:
|
||||
- [aesophia_cli](https://github.com/aeternity/aesophia_cli)
|
||||
- [aesophia_http](https://github.com/aeternity/aesophia_http)
|
||||
- [aerepl](https://github.com/aeternity/aerepl)
|
||||
@@ -14,7 +14,6 @@ The compiler is currently being used three places
|
||||
* [Features](docs/sophia_features.md)
|
||||
* [Standard library](docs/sophia_stdlib.md)
|
||||
* [Contract examples](docs/sophia_examples.md)
|
||||
* [Contributing](CONTRIBUTING.md)
|
||||
|
||||
Additionally you can check out the [contracts section](https://github.com/aeternity/protocol/blob/master/contracts/contracts.md) of the æternity blockchain specification.
|
||||
|
||||
|
||||
+2
-2
@@ -67,7 +67,7 @@ generates the following JSON structure representing the contract interface:
|
||||
}
|
||||
]
|
||||
},
|
||||
"typedefs": [
|
||||
"type_defs": [
|
||||
{
|
||||
"name": "answers",
|
||||
"typedef": {
|
||||
@@ -138,7 +138,7 @@ be included inside another contract.
|
||||
state =>
|
||||
#{record =>
|
||||
[#{name => <<"a">>,type => <<"Answers.answers">>}]},
|
||||
typedefs =>
|
||||
type_defs =>
|
||||
[#{name => <<"answers">>,
|
||||
typedef => #{<<"map">> => [<<"string">>,<<"int">>]},
|
||||
vars => []}]}}]}
|
||||
|
||||
@@ -51,36 +51,6 @@ The **pp_** options all print to standard output the following:
|
||||
|
||||
`pp_assembler` - print the generated assembler code
|
||||
|
||||
The option `include_child_contract_symbols` includes the symbols of child contracts functions in the generated fate code. It is turned off by default to avoid making contracts bigger on chain.
|
||||
|
||||
The option `debug_info` includes information related to debugging in the compiler output. Currently this option only includes the mapping from variables to registers.
|
||||
|
||||
#### Options to control which compiler optimizations should run:
|
||||
|
||||
By default all optimizations are turned on, to disable an optimization, it should be
|
||||
explicitly set to false and passed as a compiler option.
|
||||
|
||||
List of optimizations:
|
||||
|
||||
- optimize_inliner
|
||||
- optimize_inline_local_functions
|
||||
- optimize_bind_subexpressions
|
||||
- optimize_let_floating
|
||||
- optimize_simplifier
|
||||
- optimize_drop_unused_lets
|
||||
- optimize_push_consume
|
||||
- optimize_one_shot_var
|
||||
- optimize_write_to_dead_var
|
||||
- optimize_inline_switch_target
|
||||
- optimize_swap_push
|
||||
- optimize_swap_pop
|
||||
- optimize_swap_write
|
||||
- optimize_constant_propagation
|
||||
- optimize_prune_impossible_branches
|
||||
- optimize_single_successful_branch
|
||||
- optimize_inline_store
|
||||
- optimize_float_switch_bod
|
||||
|
||||
#### check_call(ContractString, Options) -> CheckRet
|
||||
|
||||
Types
|
||||
|
||||
+56
-169
@@ -134,155 +134,6 @@ main contract IntHolderFactory =
|
||||
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.
|
||||
|
||||
### Contract interfaces and polymorphism
|
||||
|
||||
Contracts can implement one or multiple interfaces, the contract has to define
|
||||
every entrypoint from the implemented interface and the entrypoints in both
|
||||
the contract and implemented interface should have compatible types.
|
||||
|
||||
```
|
||||
contract interface Animal =
|
||||
entrypoint sound : () => string
|
||||
|
||||
contract Cat : Animal =
|
||||
entrypoint sound() = "Cat sound"
|
||||
```
|
||||
|
||||
Contract interfaces can extend other interfaces. An extended interface has to
|
||||
declare all entrypoints from every parent interface. All the declarations in the extended
|
||||
interface must have types compatible with the declarations from the parent
|
||||
interface.
|
||||
|
||||
```
|
||||
contract interface II =
|
||||
entrypoint f : () => unit
|
||||
|
||||
contract interface I : II =
|
||||
entrypoint f : () => unit
|
||||
entrypoint g : () => unit
|
||||
|
||||
contract C : I =
|
||||
entrypoint f() = ()
|
||||
entrypoint g() = ()
|
||||
```
|
||||
|
||||
It is only possible to implement (or extend) an interface that has been already
|
||||
defined earlier in the file (or in an included file). Therefore recursive
|
||||
interface implementation is not allowed in Sophia.
|
||||
|
||||
```
|
||||
// The following code would show an error
|
||||
|
||||
contract interface X : Z =
|
||||
entrypoint x : () => int
|
||||
|
||||
contract interface Y : X =
|
||||
entrypoint x : () => int
|
||||
entrypoint y : () => int
|
||||
|
||||
contract interface Z : Y =
|
||||
entrypoint x : () => int
|
||||
entrypoint y : () => int
|
||||
entrypoint z : () => int
|
||||
|
||||
contract C : Z =
|
||||
entrypoint x() = 1
|
||||
entrypoint y() = 1
|
||||
entrypoint z() = 1
|
||||
```
|
||||
|
||||
#### Subtyping and variance
|
||||
|
||||
Subtyping in Sophia follows common rules that take type variance into account. As described by [Wikipedia](https://en.wikipedia.org/wiki/Covariance_and_contravariance_(computer_science)),
|
||||
|
||||
>Variance refers to how subtyping between more complex types relates to subtyping between their components.
|
||||
|
||||
This concept plays an important role in complex types such as tuples, `datatype`s and functions. Depending on the context, it can apply to positions in the structure of a type, or type parameters of generic types. There are four kinds of variances:
|
||||
|
||||
- covariant
|
||||
- contravariant
|
||||
- invariant
|
||||
- bivariant
|
||||
|
||||
A type is said to be on a "covariant" position when it describes output or a result of some computation. Analogously, position is "contravariant" when it is an input, or a parameter. Intuitively, when a part of the type is produced by values of it, it is covariant. When it is consumed, it is contravariant. When a type appears to be simultaneously input and output, it is described as invariant. If a type is neither of those (that is, it's unused) it's bivariant. Furthermore, whenever a complex type appears on a contravariant position, all its covariant components become contravariant and vice versa.
|
||||
|
||||
Variance influences how subtyping is applied. Types on covariant positions are subtyped normally, while contravariant the opposite way. Invariant types have to be exactly the same in order for subtyping to work. Bivariant types are always compatible.
|
||||
|
||||
A good example of where it matters can be pictured by subtyping of function types. Let us assume there is a contract interface `Animal` and two contracts that implement it: `Dog` and `Cat`.
|
||||
|
||||
```sophia
|
||||
contract interface Animal =
|
||||
entrypoint age : () => int
|
||||
|
||||
contract Dog : Animal =
|
||||
entrypoint age() = // ...
|
||||
entrypoint woof() = "woof"
|
||||
|
||||
contract Cat : Animal =
|
||||
entrypoint age() = // ...
|
||||
entrypoint meow() = "meow"
|
||||
```
|
||||
|
||||
The assumption of this exercise is that cats do not bark (because `Cat` does not define the `woof` entrypoint). If subtyping rules were applied naively, that is if we let `Dog => Dog` be a subtype of `Animal => Animal`, the following code would break:
|
||||
|
||||
```sophia
|
||||
let f : (Dog) => string = d => d.woof()
|
||||
let g : (Animal) => string = f
|
||||
let c : Cat = Chain.create()
|
||||
g(c) // Cat barking!
|
||||
```
|
||||
|
||||
That is because arguments of functions are contravariant, as opposed to return the type which is covariant. Because of that, the assignment of `f` to `g` is invalid - while `Dog` is a subtype of `Animal`, `Dog => string` is **not** a subtype of `Animal => string`. However, `Animal => string` **is** a subtype of `Dog => string`. More than that, `(Dog => Animal) => Dog` is a subtype of `(Animal => Dog) => Animal`.
|
||||
|
||||
This has consequences on how user-defined generic types work. A type variable gains its variance from its role in the type definition as shown in the example:
|
||||
|
||||
```sophia
|
||||
datatype co('a) = Co('a) // co is covariant on 'a
|
||||
datatype ct('a) = Ct('a => unit) // ct is contravariant on 'a
|
||||
datatype in('a) = In('a => 'a) // in is invariant on 'a
|
||||
datatype bi('a) = Bi // bi is bivariant on 'a
|
||||
```
|
||||
|
||||
The following facts apply here:
|
||||
|
||||
- `co('a)` is a subtype of `co('b) when `'a` is a subtype of `'b`
|
||||
- `ct('a)` is a subtype of `ct('b) when `'b` is a subtype of `'a`
|
||||
- `in('a)` is a subtype of `in('b) when `'a` is equal to `'b`
|
||||
- `bi('a)` is a subtype of `bi('b) always
|
||||
|
||||
That altogether induce the following rules of subtyping in Sophia:
|
||||
|
||||
- A function type `(Args1) => Ret1` is a subtype of `(Args2) => Ret2` when `Ret1`
|
||||
is a subtype of `Ret2` and each argument type from `Args2` is a subtype of its
|
||||
counterpart in `Args1`.
|
||||
|
||||
- A list type `list(A)` is a subtype of `list(B)` if `A` is a subtype of `B`.
|
||||
|
||||
- An option type `option(A)` is a subtype of `option(B)` if `A` is a subtype of `B`.
|
||||
|
||||
- A map type `map(A1, A2)` is a subtype of `map(B1, B2)` if `A1` is a subtype
|
||||
of `B1`, and `A2` is a subtype of `B2`.
|
||||
|
||||
- An oracle type `oracle(A1, A2)` is a subtype of `oracle(B1, B2)` if `B1` is
|
||||
a subtype of `A1`, and `A2` is a subtype of `B2`.
|
||||
|
||||
- An oracle_query type `oracle_query(A1, A2)` is a subtype of `oracle_query(B1, B2)`
|
||||
if `A1` is a subtype of `B1`, and `A2` is a subtype of `B2`.
|
||||
|
||||
- A user-defined datatype `t(Args1)` is a subtype of `t(Args2)`
|
||||
|
||||
- When a user-defined type `t('a)` is covariant in `'a`, then `t(A)` is a
|
||||
subtype of `t(B)` when `A` is a subtype of `B`.
|
||||
|
||||
- When a user-defined type `t('a)` is contravariant in `'a`, then `t(A)` is a
|
||||
subtype of `t(B)` when `B` is a subtype of `A`.
|
||||
|
||||
- When a user-defined type `t('a)` is binvariant in `'a`, then `t(A)` is a
|
||||
subtype of `t(B)` when either `A` is a subtype of `B` or when `B` is a subtype
|
||||
of `A`.
|
||||
|
||||
- When a user-defined type `t('a)` is invariant in `'a`, then `t(A)` can never be
|
||||
a subtype of `t(B)`.
|
||||
|
||||
## Mutable state
|
||||
|
||||
@@ -504,9 +355,10 @@ namespace C =
|
||||
Sophia has the following types:
|
||||
|
||||
| Type | Description | Example |
|
||||
|----------------------|---------------------------------------------------------------------------------------------|--------------------------------------------------------------|
|
||||
|----------------------|---------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------|
|
||||
| int | A 2-complement integer | ```-1``` |
|
||||
| address | æternity address, 32 bytes | ```Call.origin``` |
|
||||
| char | A single character | ```'c'``` |
|
||||
| address | æternity address, 32 bytes | ```Call.origin``` ```ak_2gx9MEFxKvY9vMG5YnqnXWv1hCsX7rgnfvBLJS4aQurustR1rt``` |
|
||||
| bool | A Boolean | ```true``` |
|
||||
| bits | A bit field | ```Bits.none``` |
|
||||
| bytes(n) | A byte array with `n` bytes | ```#fedcba9876543210``` |
|
||||
@@ -564,14 +416,6 @@ All operations are *safe* with respect to overflow and underflow.
|
||||
The division and modulo operations throw an arithmetic error if the
|
||||
right-hand operand is zero.
|
||||
|
||||
Sophia arbitrary-sized integers (FATE) also supports the following bitwise operations:
|
||||
- bitwise and (`x band y`)
|
||||
- bitwise or (`x bor y`)
|
||||
- bitwise xor (`x bxor y`)
|
||||
- bitwise not (`bnot x`)
|
||||
- arithmetic bitshift left (`x << n`)
|
||||
- arithmetic bitshift right (`x >> n`)
|
||||
|
||||
## Bit fields
|
||||
|
||||
Sophia integers do not support bit arithmetic. Instead there is a separate
|
||||
@@ -658,6 +502,59 @@ function
|
||||
|
||||
Guards cannot be stateful even when used inside a stateful function.
|
||||
|
||||
## Comparable types
|
||||
|
||||
Only certain types are allowed to be compared by equality (`==`, `!=`) and
|
||||
inequality (`<`, `>`, `=<`, `>=`). For instance, while it is legal to compare
|
||||
integers, comparing functions would lead to an error:
|
||||
|
||||
```
|
||||
function f() =
|
||||
f == f // type error
|
||||
```
|
||||
|
||||
The rules apply as follows:
|
||||
|
||||
- All types that are comparable by inequality are also comparable by equality.
|
||||
- The builtin types `bool`, `int`, `char`, `bits`, `bytes`, `string`, `unit`,
|
||||
`hash`, `address` and `signature` are comparable by inequality (and thus by
|
||||
equality).
|
||||
- The composite types `list`, `option`, and tuples are comparable by
|
||||
equality/inequality if their type parameters are comparable by
|
||||
equality/inequality.
|
||||
- The composite types `map`, `oracle`, and `oracle_query` are comparable by
|
||||
equality if their type parameters are comparable by equality.
|
||||
- User-defined records and datatypes are comparable by equality if their type
|
||||
parameters are comparable by equality.
|
||||
- Smart contracts are comparable by equality.
|
||||
- User-declared type variables are comparable according to the [type
|
||||
constraints](#type-constraints) given in the function signature.
|
||||
|
||||
In all other cases the types are not comparable.
|
||||
|
||||
### Type constraints
|
||||
|
||||
Polymorphic types are not declared as comparable by default. If the user
|
||||
specifies the type signature for a function, they need to manually declare type
|
||||
constraints in order to allow the variables to be compared. This can only be
|
||||
done if the type declaration is separated from the function definition. The
|
||||
constraints have to be prepended to the type declaration and separated with a
|
||||
semicolon:
|
||||
|
||||
```
|
||||
|
||||
function eq(x : 'a, y : 'a) = x == y // Type error, 'a is not comparable
|
||||
|
||||
function
|
||||
eq : 'a is eq ; ('a, 'a) => bool
|
||||
eq(x, y) = x == y // Compiles
|
||||
|
||||
function eq(x, y) = x == y // Compiles as the constraints are inferred
|
||||
```
|
||||
|
||||
Currently only two constraints are allowed: `eq` for equality and `ord` for
|
||||
inequality. Declaring a type as `ord` automatically implies `eq`.
|
||||
|
||||
## Lists
|
||||
|
||||
A Sophia list is a dynamically sized, homogenous, immutable, singly
|
||||
@@ -1019,16 +916,6 @@ function require(b : bool, err : string) =
|
||||
if(!b) abort(err)
|
||||
```
|
||||
|
||||
Aside from that, there is an almost equivalent function `exit`
|
||||
|
||||
```sophia
|
||||
exit(reason : string) : 'a
|
||||
```
|
||||
|
||||
Just like `abort`, it breaks the execution with the given reason. The difference
|
||||
however is in the gas consumption — while `abort` returns unused gas, a call to
|
||||
`exit` burns it all.
|
||||
|
||||
## Delegation signature
|
||||
|
||||
Some chain operations (`Oracle.<operation>` and `AENS.<operation>`) have an
|
||||
|
||||
+97
-106
@@ -14,7 +14,6 @@ The out-of-the-box namespaces are:
|
||||
|
||||
- [Address](#address)
|
||||
- [AENS](#aens)
|
||||
- [AENSv2](#aensv2)
|
||||
- [Auth](#auth)
|
||||
- [Bits](#bits)
|
||||
- [Bytes](#bytes)
|
||||
@@ -32,7 +31,6 @@ The following ones need to be included as regular files with `.aes` suffix, for
|
||||
include "List.aes"
|
||||
```
|
||||
|
||||
- [AENSCompat](#aenscompat)
|
||||
- [Bitwise](#bitwise)
|
||||
- [BLS12_381](#bls12_381)
|
||||
- [Func](#func)
|
||||
@@ -92,10 +90,13 @@ Cast address to contract type C (where `C` is a contract)
|
||||
|
||||
### AENS
|
||||
|
||||
The old AENS namespace, kept in the compiler to be able to interact with
|
||||
contracts from before Ceres, compiled using aesophia compiler version 7.x and
|
||||
earlier. Used in [AENSCompat](#aenscompat) when converting between old and new
|
||||
pointers.
|
||||
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
|
||||
|
||||
@@ -112,41 +113,12 @@ datatype pointee = AccountPt(address) | OraclePt(address)
|
||||
| ContractPt(address) | ChannelPt(address)
|
||||
```
|
||||
|
||||
### AENSv2
|
||||
|
||||
Note: introduced in v8.0
|
||||
|
||||
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
|
||||
|
||||
##### name
|
||||
```
|
||||
datatype name = Name(address, Chain.ttl, map(string, AENSv2.pointee))
|
||||
```
|
||||
|
||||
|
||||
##### pointee
|
||||
|
||||
```
|
||||
datatype pointee = AccountPt(address) | OraclePt(address)
|
||||
| ContractPt(address) | ChannelPt(address) | DataPt(string)
|
||||
```
|
||||
|
||||
Note: on-chain there is a maximum length enforced for `DataPt`, it is 1024 bytes.
|
||||
Sophia itself does _not_ enforce this.
|
||||
|
||||
#### Functions
|
||||
|
||||
##### resolve
|
||||
```
|
||||
AENSv2.resolve(name : string, key : string) : option('a)
|
||||
AENS.resolve(name : string, key : string) : option('a)
|
||||
```
|
||||
|
||||
Name resolution. Here `name` should be a registered name and `key` one of the attributes
|
||||
@@ -157,53 +129,41 @@ type checked against this type at run time.
|
||||
|
||||
##### lookup
|
||||
```
|
||||
AENSv2.lookup(name : string) : option(AENSv2.name)
|
||||
AENS.lookup(name : string) : option(AENS.name)
|
||||
```
|
||||
|
||||
If `name` is an active name `AENSv2.lookup` returns a name object.
|
||||
If `name` is an active name `AENS.lookup` returns a name object.
|
||||
The three arguments to `Name` are `owner`, `expiry` and a map of the
|
||||
`pointees` for the name. Note: the expiry of the name is always a fixed TTL.
|
||||
For example:
|
||||
```
|
||||
let Some(AENSv2.Name(owner, FixedTTL(expiry), ptrs)) = AENSv2.lookup("example.chain")
|
||||
let Some(Name(owner, FixedTTL(expiry), ptrs)) = AENS.lookup("example.chain")
|
||||
```
|
||||
|
||||
Note: Changed to produce `AENSv2.name` in v8.0 (Ceres protocol upgrade).
|
||||
|
||||
##### preclaim
|
||||
```
|
||||
AENSv2.preclaim(owner : address, commitment_hash : hash, <signature : signature>) : unit
|
||||
AENS.preclaim(owner : address, commitment_hash : hash, <signature : signature>) : unit
|
||||
```
|
||||
|
||||
The [signature](./sophia_features.md#delegation-signature) should be over
|
||||
`network id` + `owner address` + `Contract.address` (concatenated as byte arrays).
|
||||
|
||||
From Ceres (i.e. FATE VM version 3) the
|
||||
[signature](./sophia_features.md#delegation-signature) can also be generic
|
||||
(allowing _all_, existing and future, names to be delegated with one
|
||||
signature), i.e. over `network id` + `owner address` + `string "AENS"` +
|
||||
`Contract.address`.
|
||||
|
||||
|
||||
##### claim
|
||||
```
|
||||
AENSv2.claim(owner : address, name : string, salt : int, name_fee : int, <signature : signature>) : unit
|
||||
AENS.claim(owner : address, name : string, salt : int, name_fee : int, <signature : signature>) : unit
|
||||
```
|
||||
|
||||
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.
|
||||
|
||||
From Ceres (i.e. FATE VM version 3) the
|
||||
[signature](./sophia_features.md#delegation-signature) can also be generic
|
||||
(allowing _all_, existing and future, names to be delegated with one
|
||||
signature), i.e. over `network id` + `owner address` + `string "AENS"` +
|
||||
`Contract.address`.
|
||||
`network id` + `owner address` + `name_hash` + `Contract.address`
|
||||
(concatenated as byte arrays)
|
||||
using the private key of the `owner` account for signing.
|
||||
|
||||
|
||||
##### transfer
|
||||
```
|
||||
AENSv2.transfer(owner : address, new_owner : address, name : string, <signature : signature>) : unit
|
||||
AENS.transfer(owner : address, new_owner : address, name : string, <signature : signature>) : unit
|
||||
```
|
||||
|
||||
Transfers name to the new owner.
|
||||
@@ -213,16 +173,10 @@ The [signature](./sophia_features.md#delegation-signature) should be over
|
||||
(concatenated as byte arrays)
|
||||
using the private key of the `owner` account for signing.
|
||||
|
||||
From Ceres (i.e. FATE VM version 3) the
|
||||
[signature](./sophia_features.md#delegation-signature) can also be generic
|
||||
(allowing _all_, existing and future, names to be delegated with one
|
||||
signature), i.e. over `network id` + `owner address` + `string "AENS"` +
|
||||
`Contract.address`.
|
||||
|
||||
|
||||
##### revoke
|
||||
```
|
||||
AENSv2.revoke(owner : address, name : string, <signature : signature>) : unit
|
||||
AENS.revoke(owner : address, name : string, <signature : signature>) : unit
|
||||
```
|
||||
|
||||
Revokes the name to extend the ownership time.
|
||||
@@ -232,24 +186,17 @@ The [signature](./sophia_features.md#delegation-signature) should be over
|
||||
(concatenated as byte arrays)
|
||||
using the private key of the `owner` account for signing.
|
||||
|
||||
From Ceres (i.e. FATE VM version 3) the
|
||||
[signature](./sophia_features.md#delegation-signature) can also be generic
|
||||
(allowing _all_, existing and future, names to be delegated with one
|
||||
signature), i.e. over `network id` + `owner address` + `string "AENS"` +
|
||||
`Contract.address`.
|
||||
|
||||
|
||||
##### update
|
||||
```
|
||||
AENSv2.update(owner : address, name : string, expiry : option(Chain.ttl), client_ttl : option(int),
|
||||
new_ptrs : map(string, AENSv2.pointee), <signature : signature>) : unit
|
||||
AENS.update(owner : address, name : string, expiry : option(Chain.ttl), client_ttl : option(int),
|
||||
new_ptrs : map(string, AENS.pointee), <signature : signature>) : unit
|
||||
```
|
||||
|
||||
Updates the name. If the optional parameters are set to `None` that parameter
|
||||
will not be updated, for example if `None` is passed as `expiry` the expiry
|
||||
block of the name is not changed.
|
||||
|
||||
Note: Changed to consume `AENSv2.pointee` in v8.0 (Ceres protocol upgrade).
|
||||
|
||||
### Auth
|
||||
|
||||
@@ -289,10 +236,7 @@ namespace Chain =
|
||||
Auth.tx_hash : option(hash)
|
||||
```
|
||||
|
||||
Gets the transaction hash during authentication. Note: `Auth.tx_hash`
|
||||
computation differs between protocol versions (changed in Ceres!), see
|
||||
[aeserialisation](https://github.com/aeternity/protocol/blob/master/serializations.md)
|
||||
specification for details.
|
||||
Gets the transaction hash during authentication.
|
||||
|
||||
|
||||
### Bits
|
||||
@@ -437,12 +381,6 @@ Call.gas_price : int
|
||||
|
||||
The gas price of the current call.
|
||||
|
||||
#### mulmod
|
||||
```
|
||||
Int.mulmod : (a : int, b : int, q : int) : int
|
||||
```
|
||||
|
||||
Combined multiplication and modulus, returns `(a * b) mod q`.
|
||||
|
||||
#### fee
|
||||
```
|
||||
@@ -531,13 +469,6 @@ Chain.block_height : int"
|
||||
|
||||
The height of the current block (i.e. the block in which the current call will be included).
|
||||
|
||||
#### to_bytes
|
||||
```
|
||||
Address.to_bytes(a : address) : bytes(32)
|
||||
```
|
||||
|
||||
The binary representation of the address.
|
||||
|
||||
|
||||
##### coinbase
|
||||
```
|
||||
@@ -607,13 +538,6 @@ charging the calling contract. Note that this won't be visible in `Call.value`
|
||||
in the `init` call of the new contract. It will be included in
|
||||
`Contract.balance`, however.
|
||||
|
||||
#### poseidon
|
||||
```
|
||||
Crypto.poseidon(x1 : int, x2 : int) : int
|
||||
```
|
||||
|
||||
Hash two integers (in the scalar field of BLS12-381) to another integer (in the scalar
|
||||
field of BLS12-281). This is a ZK/SNARK-friendly hash function.
|
||||
|
||||
The type `'c` must be instantiated with a contract.
|
||||
|
||||
@@ -888,8 +812,8 @@ Registers new oracle answering questions of type `'a` with answers of type `'b`.
|
||||
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.
|
||||
* The `ttl` is the Time To Live for the oracle in key blocks, either relative to the current
|
||||
key block height (`RelativeTTL(delta)`) or a fixed key block height (`FixedTTL(height)`).
|
||||
* The `ttl` is the Time To Live for the oracle, either relative to the current
|
||||
height (`RelativeTTL(delta)`) or a fixed height (`FixedTTL(height)`).
|
||||
* The type `'a` is the type of the question to ask.
|
||||
* The type `'b` is the type of the oracle answers.
|
||||
|
||||
@@ -990,21 +914,88 @@ It returns `true` iff the oracle query exist and has the expected type.
|
||||
These need to be explicitly included (with `.aes` suffix)
|
||||
|
||||
|
||||
### AENSCompat
|
||||
### Bitwise
|
||||
|
||||
#### pointee\_to\_V2
|
||||
Bitwise operations on arbitrary precision integers.
|
||||
|
||||
#### bsr
|
||||
```
|
||||
AENSCompat.pointee_to_V2(p : AENS.pointee) : AENSv2.pointee
|
||||
Bitwise.bsr(n : int, x : int) : int
|
||||
```
|
||||
|
||||
Translate old pointee format to new, this is always possible.
|
||||
Logical bit shift `x` right `n` positions.
|
||||
|
||||
#### pointee\_from\_V2
|
||||
|
||||
#### bsl
|
||||
```
|
||||
AENSCompat.pointee_from_V2(p2 : AENSv2.pointee) : option(AENS.pointee)
|
||||
Bitwise.bsl(n : int, x : int) : int
|
||||
```
|
||||
|
||||
Translate new pointee format to old, `DataPt` can't be translated, so `None` is returned in this case.
|
||||
Logical bit shift `x` left `n` positions.
|
||||
|
||||
|
||||
#### bsli
|
||||
```
|
||||
Bitwise.bsli(n : int, x : int, lim : int) : int
|
||||
```
|
||||
|
||||
Logical bit shift `x` left `n` positions, limit to `lim` bits.
|
||||
|
||||
|
||||
#### band
|
||||
```
|
||||
Bitwise.band(x : int, y : int) : int
|
||||
```
|
||||
|
||||
Bitwise `and` of `x` and `y`.
|
||||
|
||||
|
||||
#### bor
|
||||
```
|
||||
Bitwise.bor(x : int, y : int) : int
|
||||
```
|
||||
|
||||
Bitwise `or` of `x` and `y`.
|
||||
|
||||
|
||||
#### bxor
|
||||
```
|
||||
Bitwise.bxor(x : int, y : int) : int
|
||||
```
|
||||
|
||||
Bitwise `xor` of `x` and `y`.
|
||||
|
||||
|
||||
#### bnot
|
||||
```
|
||||
Bitwise.bnot(x : int) : int
|
||||
```
|
||||
|
||||
Bitwise `not` of `x`. Defined and implemented as `bnot(x) = bxor(x, -1)`.
|
||||
|
||||
|
||||
#### uband
|
||||
```
|
||||
Bitwise.uband(x : int, y : int) : int
|
||||
```
|
||||
|
||||
Bitwise `and` of _non-negative_ numbers `x` and `y`.
|
||||
|
||||
|
||||
#### ubor
|
||||
```
|
||||
Bitwise.ubor(x : int, y : int) : int
|
||||
```
|
||||
|
||||
Bitwise `or` of _non-negative_ `x` and `y`.
|
||||
|
||||
|
||||
#### ubxor
|
||||
```
|
||||
Bitwise.ubxor(x : int, y : int) : int
|
||||
```
|
||||
|
||||
Bitwise `xor` of _non-negative_ `x` and `y`.
|
||||
|
||||
|
||||
### BLS12\_381
|
||||
|
||||
+11
-35
@@ -10,9 +10,8 @@ and `*/` and can be nested.
|
||||
### Keywords
|
||||
|
||||
```
|
||||
contract include let switch type record datatype if elif else function
|
||||
stateful payable true false mod public entrypoint private indexed namespace
|
||||
interface main using as for hiding
|
||||
contract elif else entrypoint false function if import include let mod namespace
|
||||
private payable stateful switch true type record datatype main interface
|
||||
```
|
||||
|
||||
### Tokens
|
||||
@@ -92,30 +91,18 @@ A Sophia file consists of a sequence of *declarations* in a layout block.
|
||||
```c
|
||||
File ::= Block(TopDecl)
|
||||
|
||||
TopDecl ::= ['payable'] ['main'] 'contract' Con [Implement] '=' Block(Decl)
|
||||
| 'contract' 'interface' Con [Implement] '=' Block(Decl)
|
||||
TopDecl ::= ['payable'] 'contract' Con '=' Block(Decl)
|
||||
| 'namespace' Con '=' Block(Decl)
|
||||
| '@compiler' PragmaOp Version
|
||||
| 'include' String
|
||||
| Using
|
||||
|
||||
Implement ::= ':' Sep1(Con, ',')
|
||||
|
||||
Decl ::= 'type' Id ['(' TVar* ')'] '=' TypeAlias
|
||||
| 'record' Id ['(' TVar* ')'] '=' RecordType
|
||||
| 'datatype' Id ['(' TVar* ')'] '=' DataType
|
||||
| (EModifier* 'entrypoint' | FModifier* 'function') Block(FunDecl)
|
||||
| Using
|
||||
|
||||
FunDecl ::= Id ':' Type // Type signature
|
||||
| Id Args [':' Type] '=' Block(Stmt) // Definition
|
||||
| Id Args [':' Type] Block(GuardedDef) // Guarded definitions
|
||||
|
||||
GuardedDef ::= '|' Sep1(Expr, ',') '=' Block(Stmt)
|
||||
|
||||
Using ::= 'using' Con ['as' Con] [UsingParts]
|
||||
UsingParts ::= 'for' '[' Sep1(Id, ',') ']'
|
||||
| 'hiding' '[' Sep1(Id, ',') ']'
|
||||
|
||||
PragmaOp ::= '<' | '=<' | '==' | '>=' | '>'
|
||||
Version ::= Sep1(Int, '.')
|
||||
@@ -185,17 +172,12 @@ Stmt ::= 'switch' '(' Expr ')' Block(Case)
|
||||
| 'elif' '(' Expr ')' Block(Stmt)
|
||||
| 'else' Block(Stmt)
|
||||
| 'let' LetDef
|
||||
| Using
|
||||
| Expr
|
||||
|
||||
LetDef ::= Id Args [':' Type] '=' Block(Stmt) // Function definition
|
||||
| Pattern '=' Block(Stmt) // Value definition
|
||||
|
||||
Case ::= Pattern '=>' Block(Stmt)
|
||||
| Pattern Block(GuardedCase)
|
||||
|
||||
GuardedCase ::= '|' Sep1(Expr, ',') '=>' Block(Stmt)
|
||||
|
||||
Pattern ::= Expr
|
||||
```
|
||||
|
||||
@@ -233,7 +215,6 @@ Expr ::= '(' LamArgs ')' '=>' Block(Stmt) // Anonymous function (x) => x +
|
||||
| '[' Expr '..' Expr ']' // List range [1..n]
|
||||
| '{' Sep(FieldUpdate, ',') '}' // Record or map value {x = 0, y = 1}, {[key] = val}
|
||||
| '(' Expr ')' // Parens (1 + 2) * 3
|
||||
| '(' Expr '=' Expr ')' // Assign pattern (y = x::_)
|
||||
| Id | Con | QId | QCon // Identifiers x, None, Map.member, AELib.Token
|
||||
| Int | Bytes | String | Char // Literals 123, 0xff, #00abc123, "foo", '%'
|
||||
| AccountAddress | ContractAddress // Chain identifiers
|
||||
@@ -254,8 +235,8 @@ Path ::= Id // Record field
|
||||
|
||||
BinOp ::= '||' | '&&' | '<' | '>' | '=<' | '>=' | '==' | '!='
|
||||
| '::' | '++' | '+' | '-' | '*' | '/' | 'mod' | '^'
|
||||
| 'band' | 'bor' | 'bxor' | '<<' | '>>' | '|>'
|
||||
UnOp ::= '-' | '!' | 'bnot'
|
||||
| '|>'
|
||||
UnOp ::= '-' | '!'
|
||||
```
|
||||
|
||||
## Operators types
|
||||
@@ -263,29 +244,24 @@ UnOp ::= '-' | '!' | 'bnot'
|
||||
| Operators | Type
|
||||
| --- | ---
|
||||
| `-` `+` `*` `/` `mod` `^` | arithmetic operators
|
||||
| `!` `&&` `||` | logical operators
|
||||
| `band` `bor` `bxor` `bnot` `<<` `>>` | bitwise operators
|
||||
| `!` `&&` `\|\|` | logical operators
|
||||
| `==` `!=` `<` `>` `=<` `>=` | comparison operators
|
||||
| `::` `++` | list operators
|
||||
| `|>` | functional operators
|
||||
| `\|>` | functional operators
|
||||
|
||||
## Operator precedence
|
||||
## Operator precendences
|
||||
|
||||
In order of highest to lowest precedence.
|
||||
|
||||
| Operators | Associativity
|
||||
| --- | ---
|
||||
| `!` `bnot`| right
|
||||
| `!` | right
|
||||
| `^` | left
|
||||
| `*` `/` `mod` | left
|
||||
| `-` (unary) | right
|
||||
| `+` `-` | left
|
||||
| `<<` `>>` | left
|
||||
| `::` `++` | right
|
||||
| `<` `>` `=<` `>=` `==` `!=` | none
|
||||
| `band` | left
|
||||
| `bxor` | left
|
||||
| `bor` | left
|
||||
| `&&` | right
|
||||
| `||` | right
|
||||
| `|>` | left
|
||||
| `\|\|` | right
|
||||
| `\|>` | left
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
namespace AENSCompat =
|
||||
// Translate old format to new format - always possible
|
||||
function pointee_to_V2(p : AENS.pointee) : AENSv2.pointee =
|
||||
switch(p)
|
||||
AENS.AccountPt(a) => AENSv2.AccountPt(a)
|
||||
AENS.OraclePt(a) => AENSv2.OraclePt(a)
|
||||
AENS.ContractPt(a) => AENSv2.ContractPt(a)
|
||||
AENS.ChannelPt(a) => AENSv2.ChannelPt(a)
|
||||
|
||||
// Translate new format to old format - option type!
|
||||
function pointee_from_V2(p2 : AENSv2.pointee) : option(AENS.pointee) =
|
||||
switch(p2)
|
||||
AENSv2.AccountPt(a) => Some(AENS.AccountPt(a))
|
||||
AENSv2.OraclePt(a) => Some(AENS.OraclePt(a))
|
||||
AENSv2.ContractPt(a) => Some(AENS.ContractPt(a))
|
||||
AENSv2.ChannelPt(a) => Some(AENS.ChannelPt(a))
|
||||
AENSv2.DataPt(_) => None
|
||||
@@ -0,0 +1,126 @@
|
||||
@compiler >= 4.3
|
||||
|
||||
namespace Bitwise =
|
||||
|
||||
// bit shift 'x' right 'n' postions
|
||||
function bsr(n : int, x : int) : int =
|
||||
let step = 2^n
|
||||
let res = x / step
|
||||
if (x >= 0 || x mod step == 0)
|
||||
res
|
||||
else
|
||||
res - 1
|
||||
|
||||
// bit shift 'x' left 'n' positions
|
||||
function bsl(n : int, x : int) : int =
|
||||
x * 2^n
|
||||
|
||||
// bit shift 'x' left 'n' positions, limit at 'lim' bits
|
||||
function bsli(n : int, x : int, lim : int) : int =
|
||||
(x * 2^n) mod (2^lim)
|
||||
|
||||
// bitwise 'and' for arbitrary precision integers
|
||||
function band(a : int, b : int) : int =
|
||||
if (a >= 0 && b >= 0)
|
||||
uband_(a, b)
|
||||
elif (b >= 0)
|
||||
ubnand_(b, -1 - a)
|
||||
elif (a >= 0)
|
||||
ubnand_(a, -1 - b)
|
||||
else
|
||||
-1 - ubor_(-1 - a, -1 - b)
|
||||
|
||||
// bitwise 'or' for arbitrary precision integers
|
||||
function
|
||||
bor : (int, int) => int
|
||||
bor(0, b) = b
|
||||
bor(a, 0) = a
|
||||
bor(a : int, b : int) : int =
|
||||
if (a >= 0 && b >= 0)
|
||||
ubor_(a, b)
|
||||
elif (b >= 0)
|
||||
-1 - ubnand_(-1 - a, b)
|
||||
elif (a >= 0)
|
||||
-1 - ubnand_(-1 - b, a)
|
||||
else
|
||||
-1 - uband_(-1 - a, -1 - b)
|
||||
|
||||
// bitwise 'xor' for arbitrary precision integers
|
||||
function
|
||||
bxor : (int, int) => int
|
||||
bxor(0, b) = b
|
||||
bxor(a, 0) = a
|
||||
bxor(a, b) =
|
||||
if (a >= 0 && b >= 0)
|
||||
ubxor_(a, b)
|
||||
elif (b >= 0)
|
||||
-1 - ubxor_(-1 - a, b)
|
||||
elif (a >= 0)
|
||||
-1 - ubxor_(a, -1 - b)
|
||||
else
|
||||
ubxor_(-1 - a, -1 - b)
|
||||
|
||||
// bitwise 'not' for arbitrary precision integers
|
||||
function bnot(a : int) = bxor(a, -1)
|
||||
|
||||
// Bitwise 'and' for non-negative integers
|
||||
function uband(a : int, b : int) : int =
|
||||
require(a >= 0 && b >= 0, "uband is only defined for non-negative integers")
|
||||
switch((a, b))
|
||||
(0, _) => 0
|
||||
(_, 0) => 0
|
||||
_ => uband__(a, b, 1, 0)
|
||||
|
||||
private function uband_(a, b) = uband__(a, b, 1, 0)
|
||||
|
||||
private function
|
||||
uband__(0, b, val, acc) = acc
|
||||
uband__(a, 0, val, acc) = acc
|
||||
uband__(a, b, val, acc) =
|
||||
switch (a mod 2 + b mod 2)
|
||||
2 => uband__(a / 2, b / 2, val * 2, acc + val)
|
||||
_ => uband__(a / 2, b / 2, val * 2, acc)
|
||||
|
||||
// Bitwise 'or' for non-negative integers
|
||||
function ubor(a, b) =
|
||||
require(a >= 0 && b >= 0, "ubor is only defined for non-negative integers")
|
||||
switch((a, b))
|
||||
(0, _) => b
|
||||
(_, 0) => a
|
||||
_ => ubor__(a, b, 1, 0)
|
||||
|
||||
private function ubor_(a, b) = ubor__(a, b, 1, 0)
|
||||
|
||||
private function
|
||||
ubor__(0, 0, val, acc) = acc
|
||||
ubor__(a, b, val, acc) =
|
||||
switch (a mod 2 + b mod 2)
|
||||
0 => ubor__(a / 2, b / 2, val * 2, acc)
|
||||
_ => ubor__(a / 2, b / 2, val * 2, acc + val)
|
||||
|
||||
//Bitwise 'xor' for non-negative integers
|
||||
function
|
||||
ubxor : (int, int) => int
|
||||
ubxor(0, b) = b
|
||||
ubxor(a, 0) = a
|
||||
ubxor(a, b) =
|
||||
require(a >= 0 && b >= 0, "ubxor is only defined for non-negative integers")
|
||||
ubxor__(a, b, 1, 0)
|
||||
|
||||
private function ubxor_(a, b) = ubxor__(a, b, 1, 0)
|
||||
|
||||
private function
|
||||
ubxor__(0, 0, val, acc) = acc
|
||||
ubxor__(a, b, val, acc) =
|
||||
switch(a mod 2 + b mod 2)
|
||||
1 => ubxor__(a / 2, b / 2, val * 2, acc + val)
|
||||
_ => ubxor__(a / 2, b / 2, val * 2, acc)
|
||||
|
||||
private function ubnand_(a, b) = ubnand__(a, b, 1, 0)
|
||||
|
||||
private function
|
||||
ubnand__(0, b, val, acc) = acc
|
||||
ubnand__(a, b, val, acc) =
|
||||
switch((a mod 2, b mod 2))
|
||||
(1, 0) => ubnand__(a / 2, b / 2, val * 2, acc + val)
|
||||
_ => ubnand__(a / 2, b / 2, val * 2, acc)
|
||||
@@ -29,7 +29,9 @@ namespace List =
|
||||
[] => abort("drop_last_unsafe: list empty")
|
||||
|
||||
|
||||
function contains(e : 'a, l : list('a)) = switch(l)
|
||||
function
|
||||
contains : 'a is eq; ('a, list('a)) => bool
|
||||
contains(e, l) = switch(l)
|
||||
[] => false
|
||||
h::t => h == e || contains(e, t)
|
||||
|
||||
|
||||
@@ -30,7 +30,9 @@ namespace Option =
|
||||
None => abort(err)
|
||||
Some(x) => x
|
||||
|
||||
function contains(e : 'a, o : option('a)) = o == Some(e)
|
||||
function
|
||||
contains : 'a is eq; ('a, option('a)) => bool
|
||||
contains(e, o) = o == Some(e)
|
||||
|
||||
function on_elem(o : option('a), f : 'a => unit) : unit = match((), f, o)
|
||||
|
||||
|
||||
@@ -90,6 +90,7 @@ namespace String =
|
||||
Some(ix)
|
||||
|
||||
private function
|
||||
is_prefix : (list(char), list(char)) => option(list(char))
|
||||
is_prefix([], ys) = Some(ys)
|
||||
is_prefix(_, []) = None
|
||||
is_prefix(x :: xs, y :: ys) =
|
||||
@@ -98,10 +99,10 @@ namespace String =
|
||||
|
||||
private function
|
||||
to_int_([], _, x, _) = Some(x)
|
||||
to_int_(i :: is, value, x, b) =
|
||||
to_int_(i :: ints, value, x, b) =
|
||||
switch(value(i))
|
||||
None => None
|
||||
Some(n) => to_int_(is, value, x * b + n, b)
|
||||
Some(i) => to_int_(ints, value, x * b + i, b)
|
||||
|
||||
private function ch_to_int_10(ch) =
|
||||
let c = Char.to_int(ch)
|
||||
|
||||
+4
-3
@@ -2,10 +2,11 @@
|
||||
|
||||
{erl_opts, [debug_info]}.
|
||||
|
||||
{deps, [ {aebytecode, {git, "https://github.com/aeternity/aebytecode.git", {tag, "v3.2.0"}}}
|
||||
{deps, [ {aebytecode, {git, "https://github.com/aeternity/aebytecode.git", {ref,"0699f35"}}}
|
||||
, {getopt, "1.0.1"}
|
||||
, {eblake2, "1.0.0"}
|
||||
, {jsx, {git, "https://github.com/talentdeficit/jsx.git", {tag, "2.8.0"}}}
|
||||
, {jsx, {git, "https://github.com/talentdeficit/jsx.git",
|
||||
{tag, "2.8.0"}}}
|
||||
]}.
|
||||
|
||||
{dialyzer, [
|
||||
@@ -14,7 +15,7 @@
|
||||
{base_plt_apps, [erts, kernel, stdlib, crypto, mnesia]}
|
||||
]}.
|
||||
|
||||
{relx, [{release, {aesophia, "8.0.0"},
|
||||
{relx, [{release, {aesophia, "6.1.0"},
|
||||
[aesophia, aebytecode, getopt]},
|
||||
|
||||
{dev_mode, true},
|
||||
|
||||
+5
-8
@@ -1,11 +1,11 @@
|
||||
{"1.2.0",
|
||||
{"1.1.0",
|
||||
[{<<"aebytecode">>,
|
||||
{git,"https://github.com/aeternity/aebytecode.git",
|
||||
{ref,"2a0a397afad6b45da52572170f718194018bf33c"}},
|
||||
{ref,"0699f35b0398bac6cd4468da654d608375bd853d"}},
|
||||
0},
|
||||
{<<"aeserialization">>,
|
||||
{git,"https://github.com/aeternity/aeserialization.git",
|
||||
{ref,"eb68fe331bd476910394966b7f5ede7a74d37e35"}},
|
||||
{ref,"47aaa8f5434b365c50a35bfd1490340b19241991"}},
|
||||
1},
|
||||
{<<"base58">>,
|
||||
{git,"https://github.com/aeternity/erl-base58.git",
|
||||
@@ -14,7 +14,7 @@
|
||||
{<<"eblake2">>,{pkg,<<"eblake2">>,<<"1.0.0">>},0},
|
||||
{<<"enacl">>,
|
||||
{git,"https://github.com/aeternity/enacl.git",
|
||||
{ref,"793ddb502f7fe081302e1c42227dca70b09f8e17"}},
|
||||
{ref,"26180f42c0b3a450905d2efd8bc7fd5fd9cece75"}},
|
||||
2},
|
||||
{<<"getopt">>,{pkg,<<"getopt">>,<<"1.0.1">>},0},
|
||||
{<<"jsx">>,
|
||||
@@ -24,8 +24,5 @@
|
||||
[
|
||||
{pkg_hash,[
|
||||
{<<"eblake2">>, <<"EC8AD20E438AAB3F2E8D5D118C366A0754219195F8A0F536587440F8F9BCF2EF">>},
|
||||
{<<"getopt">>, <<"C73A9FA687B217F2FF79F68A3B637711BB1936E712B521D8CE466B29CBF7808A">>}]},
|
||||
{pkg_hash_ext,[
|
||||
{<<"eblake2">>, <<"3C4D300A91845B25D501929A26AC2E6F7157480846FAB2347A4C11AE52E08A99">>},
|
||||
{<<"getopt">>, <<"53E1AB83B9CEB65C9672D3E7A35B8092E9BDC9B3EE80721471A161C10C59959C">>}]}
|
||||
{<<"getopt">>, <<"C73A9FA687B217F2FF79F68A3B637711BB1936E712B521D8CE466B29CBF7808A">>}]}
|
||||
].
|
||||
|
||||
+7
-9
@@ -83,7 +83,7 @@ from_typed_ast(Type, TypedAst) ->
|
||||
string -> do_render_aci_json(JArray)
|
||||
end.
|
||||
|
||||
encode_contract(Contract = {Head, _, {con, _, Name}, _, _}) when ?IS_CONTRACT_HEAD(Head) ->
|
||||
encode_contract(Contract = {Head, _, {con, _, Name}, _}) when ?IS_CONTRACT_HEAD(Head) ->
|
||||
C0 = #{name => encode_name(Name)},
|
||||
|
||||
Tdefs0 = [ encode_typedef(T) || T <- sort_decls(contract_types(Contract)) ],
|
||||
@@ -91,7 +91,7 @@ encode_contract(Contract = {Head, _, {con, _, Name}, _, _}) when ?IS_CONTRACT_HE
|
||||
{Es, Tdefs1} = lists:partition(FilterT(<<"event">>), Tdefs0),
|
||||
{Ss, Tdefs} = lists:partition(FilterT(<<"state">>), Tdefs1),
|
||||
|
||||
C1 = C0#{typedefs => Tdefs},
|
||||
C1 = C0#{type_defs => Tdefs},
|
||||
|
||||
C2 = case Es of
|
||||
[] -> C1;
|
||||
@@ -111,7 +111,7 @@ encode_contract(Contract = {Head, _, {con, _, Name}, _, _}) when ?IS_CONTRACT_HE
|
||||
encode_contract(Namespace = {namespace, _, {con, _, Name}, _}) ->
|
||||
Tdefs = [ encode_typedef(T) || T <- sort_decls(contract_types(Namespace)) ],
|
||||
#{namespace => #{name => encode_name(Name),
|
||||
typedefs => Tdefs}}.
|
||||
type_defs => Tdefs}}.
|
||||
|
||||
%% Encode a function definition. Currently we are only interested in
|
||||
%% the interface and type.
|
||||
@@ -234,7 +234,7 @@ do_render_aci_json(Json) ->
|
||||
decode_contract(#{contract := #{name := Name,
|
||||
kind := Kind,
|
||||
payable := Payable,
|
||||
typedefs := Ts0,
|
||||
type_defs := Ts0,
|
||||
functions := Fs} = C}) ->
|
||||
MkTDef = fun(N, T) -> #{name => N, vars => [], typedef => T} end,
|
||||
Ts = [ MkTDef(<<"state">>, maps:get(state, C)) || maps:is_key(state, C) ] ++
|
||||
@@ -246,7 +246,7 @@ decode_contract(#{contract := #{name := Name,
|
||||
end,
|
||||
io_lib:format("~s", [Name])," =\n",
|
||||
decode_tdefs(Ts), decode_funcs(Fs)];
|
||||
decode_contract(#{namespace := #{name := Name, typedefs := Ts}}) when Ts /= [] ->
|
||||
decode_contract(#{namespace := #{name := Name, type_defs := Ts}}) when Ts /= [] ->
|
||||
["namespace ", io_lib:format("~s", [Name])," =\n",
|
||||
decode_tdefs(Ts)];
|
||||
decode_contract(_) -> [].
|
||||
@@ -341,12 +341,10 @@ stateful(false) -> "".
|
||||
|
||||
%% #contract{Ann, Con, [Declarations]}.
|
||||
|
||||
contract_funcs({C, _, _, _, Decls}) when ?IS_CONTRACT_HEAD(C) ->
|
||||
contract_funcs({C, _, _, Decls}) when ?IS_CONTRACT_HEAD(C); C == namespace ->
|
||||
[ D || D <- Decls, is_fun(D)].
|
||||
|
||||
contract_types({namespace, _, _, Decls}) ->
|
||||
[ D || D <- Decls, is_type(D) ];
|
||||
contract_types({C, _, _, _, Decls}) when ?IS_CONTRACT_HEAD(C) ->
|
||||
contract_types({C, _, _, Decls}) when ?IS_CONTRACT_HEAD(C); C == namespace ->
|
||||
[ D || D <- Decls, is_type(D) ].
|
||||
|
||||
is_fun({letfun, _, _, _, _, _}) -> true;
|
||||
|
||||
+223
-524
File diff suppressed because it is too large
Load Diff
+113
-87
@@ -32,13 +32,12 @@
|
||||
|
||||
-type op() :: '+' | '-' | '*' | '/' | mod | '^' | '++' | '::' |
|
||||
'<' | '>' | '=<' | '>=' | '==' | '!=' | '!' |
|
||||
'band' | 'bor' | 'bxor' | 'bnot' | '<<' | '>>' |
|
||||
map_get | map_get_d | map_set | map_from_list | map_to_list |
|
||||
map_delete | map_member | map_size | string_length |
|
||||
string_concat | bits_set | bits_clear | bits_test | bits_sum |
|
||||
bits_intersection | bits_union | bits_difference |
|
||||
contract_to_address | address_to_contract | crypto_verify_sig | crypto_verify_sig_secp256k1 |
|
||||
crypto_sha3 | crypto_sha256 | crypto_blake2b | crypto_poseidon |
|
||||
crypto_sha3 | crypto_sha256 | crypto_blake2b |
|
||||
crypto_ecverify_secp256k1 | crypto_ecrecover_secp256k1 |
|
||||
mcl_bls12_381_g1_neg | mcl_bls12_381_g1_norm | mcl_bls12_381_g1_valid |
|
||||
mcl_bls12_381_g1_is_zero | mcl_bls12_381_g1_add | mcl_bls12_381_g1_mul |
|
||||
@@ -160,8 +159,7 @@
|
||||
state_layout => state_layout(),
|
||||
context => context(),
|
||||
vars => [var_name()],
|
||||
functions := #{ fun_name() => fun_def() },
|
||||
saved_fresh_names => #{ var_name() => var_name() }
|
||||
functions := #{ fun_name() => fun_def() }
|
||||
}.
|
||||
|
||||
-define(HASH_BYTES, 32).
|
||||
@@ -172,7 +170,7 @@
|
||||
%% and produces Fate intermediate code.
|
||||
-spec ast_to_fcode(aeso_syntax:ast(), [option()]) -> {env(), fcode()}.
|
||||
ast_to_fcode(Code, Options) ->
|
||||
init_fresh_names(Options),
|
||||
init_fresh_names(),
|
||||
{Env1, FCode1} = to_fcode(init_env(Options), Code),
|
||||
FCode2 = optimize(FCode1, Options),
|
||||
Env2 = Env1#{ child_con_env :=
|
||||
@@ -180,18 +178,13 @@ ast_to_fcode(Code, Options) ->
|
||||
fun (_, FC) -> optimize(FC, Options) end,
|
||||
maps:get(child_con_env, Env1)
|
||||
)},
|
||||
Env3 =
|
||||
case proplists:get_value(debug_info, Options, false) of
|
||||
true -> Env2#{ saved_fresh_names => get(saved_fresh_names) };
|
||||
false -> Env2
|
||||
end,
|
||||
clear_fresh_names(Options),
|
||||
{Env3, FCode2}.
|
||||
clear_fresh_names(),
|
||||
{Env2, FCode2}.
|
||||
|
||||
optimize(FCode1, Options) ->
|
||||
Verbose = lists:member(pp_fcode, Options),
|
||||
[io:format("-- Before lambda lifting --\n~s\n\n", [format_fcode(FCode1)]) || Verbose],
|
||||
FCode2 = optimize_fcode(FCode1, Options),
|
||||
FCode2 = optimize_fcode(FCode1),
|
||||
[ io:format("-- After optimization --\n~s\n\n", [format_fcode(FCode2)]) || Verbose, FCode2 /= FCode1 ],
|
||||
FCode3 = lambda_lift(FCode2),
|
||||
[ io:format("-- After lambda lifting --\n~s\n\n", [format_fcode(FCode3)]) || Verbose, FCode3 /= FCode2 ],
|
||||
@@ -215,12 +208,6 @@ init_env(Options) ->
|
||||
["AENS", "ContractPt"] => #con_tag{ tag = 2, arities = [1, 1, 1, 1] },
|
||||
["AENS", "ChannelPt"] => #con_tag{ tag = 3, arities = [1, 1, 1, 1] },
|
||||
["AENS", "Name"] => #con_tag{ tag = 0, arities = [3] },
|
||||
["AENSv2", "AccountPt"] => #con_tag{ tag = 0, arities = [1, 1, 1, 1, 1] },
|
||||
["AENSv2", "OraclePt"] => #con_tag{ tag = 1, arities = [1, 1, 1, 1, 1] },
|
||||
["AENSv2", "ContractPt"] => #con_tag{ tag = 2, arities = [1, 1, 1, 1, 1] },
|
||||
["AENSv2", "ChannelPt"] => #con_tag{ tag = 3, arities = [1, 1, 1, 1, 1] },
|
||||
["AENSv2", "DataPt"] => #con_tag{ tag = 4, arities = [1, 1, 1, 1, 1] },
|
||||
["AENSv2", "Name"] => #con_tag{ tag = 0, arities = [3] },
|
||||
["Chain", "GAMetaTx"] => #con_tag{ tag = 0, arities = [2] },
|
||||
["Chain", "PayingForTx"] => #con_tag{ tag = 0, arities = [2] },
|
||||
["Chain", "SpendTx"] => #con_tag{ tag = 0, arities = ChainTxArities },
|
||||
@@ -252,13 +239,10 @@ init_env(Options) ->
|
||||
|
||||
-spec builtins() -> builtins().
|
||||
builtins() ->
|
||||
MkName = fun
|
||||
(["AENSv2"], Fun) ->
|
||||
list_to_atom(string:to_lower("AENS_" ++ Fun));
|
||||
(NS, Fun) ->
|
||||
MkName = fun(NS, Fun) ->
|
||||
list_to_atom(string:to_lower(string:join(NS ++ [Fun], "_")))
|
||||
end,
|
||||
Scopes = [{[], [{"abort", 1}, {"require", 2}, {"exit", 1}]},
|
||||
Scopes = [{[], [{"abort", 1}, {"require", 2}]},
|
||||
{["Chain"], [{"spend", 2}, {"balance", 1}, {"block_hash", 1}, {"coinbase", none},
|
||||
{"timestamp", none}, {"block_height", none}, {"difficulty", none},
|
||||
{"gas_limit", none}, {"bytecode_hash", 1}, {"create", variable}, {"clone", variable}]},
|
||||
@@ -268,13 +252,13 @@ builtins() ->
|
||||
{["Oracle"], [{"register", 4}, {"expiry", 1}, {"query_fee", 1}, {"query", 5}, {"get_question", 2},
|
||||
{"respond", 4}, {"extend", 3}, {"get_answer", 2},
|
||||
{"check", 1}, {"check_query", 2}]},
|
||||
{["AENSv2"], [{"resolve", 2}, {"preclaim", 3}, {"claim", 5}, {"transfer", 4},
|
||||
{["AENS"], [{"resolve", 2}, {"preclaim", 3}, {"claim", 5}, {"transfer", 4},
|
||||
{"revoke", 3}, {"update", 6}, {"lookup", 1}]},
|
||||
{["Map"], [{"from_list", 1}, {"to_list", 1}, {"lookup", 2},
|
||||
{"lookup_default", 3}, {"delete", 2}, {"member", 2}, {"size", 1}]},
|
||||
{["Crypto"], [{"verify_sig", 3}, {"verify_sig_secp256k1", 3},
|
||||
{"ecverify_secp256k1", 3}, {"ecrecover_secp256k1", 2},
|
||||
{"sha3", 1}, {"sha256", 1}, {"blake2b", 1}, {"poseidon", 2}]},
|
||||
{"sha3", 1}, {"sha256", 1}, {"blake2b", 1}]},
|
||||
{["MCL_BLS12_381"], [{"g1_neg", 1}, {"g1_norm", 1}, {"g1_valid", 1}, {"g1_is_zero", 1}, {"g1_add", 2}, {"g1_mul", 2},
|
||||
{"g2_neg", 1}, {"g2_norm", 1}, {"g2_valid", 1}, {"g2_is_zero", 1}, {"g2_add", 2}, {"g2_mul", 2},
|
||||
{"gt_inv", 1}, {"gt_add", 2}, {"gt_mul", 2}, {"gt_pow", 2}, {"gt_is_one", 1},
|
||||
@@ -287,9 +271,8 @@ builtins() ->
|
||||
{["Bits"], [{"set", 2}, {"clear", 2}, {"test", 2}, {"sum", 1}, {"intersection", 2},
|
||||
{"union", 2}, {"difference", 2}, {"none", none}, {"all", none}]},
|
||||
{["Bytes"], [{"to_int", 1}, {"to_str", 1}, {"concat", 2}, {"split", 1}]},
|
||||
{["Int"], [{"to_str", 1}, {"mulmod", 2}]},
|
||||
{["Address"], [{"to_str", 1}, {"to_bytes", 1}, {"to_contract", 1},
|
||||
{"is_oracle", 1}, {"is_contract", 1}, {"is_payable", 1}]}
|
||||
{["Int"], [{"to_str", 1}]},
|
||||
{["Address"], [{"to_str", 1}, {"to_contract", 1}, {"is_oracle", 1}, {"is_contract", 1}, {"is_payable", 1}]}
|
||||
],
|
||||
maps:from_list([ {NS ++ [Fun], {MkName(NS, Fun), Arity}}
|
||||
|| {NS, Funs} <- Scopes,
|
||||
@@ -324,8 +307,6 @@ init_type_env() ->
|
||||
["Chain", "ttl"] => ?type({variant, [[integer], [integer]]}),
|
||||
["AENS", "pointee"] => ?type({variant, [[address], [address], [address], [address]]}),
|
||||
["AENS", "name"] => ?type({variant, [[address, {variant, [[integer], [integer]]}, {map, string, {variant, [[address], [address], [address], [address]]}}]]}),
|
||||
["AENSv2", "pointee"] => ?type({variant, [[address], [address], [address], [address], [string]]}),
|
||||
["AENSv2", "name"] => ?type({variant, [[address, {variant, [[integer], [integer]]}, {map, string, {variant, [[address], [address], [address], [address], [string]]}}]]}),
|
||||
["Chain", "ga_meta_tx"] => ?type({variant, [[address, integer]]}),
|
||||
["Chain", "paying_for_tx"] => ?type({variant, [[address, integer]]}),
|
||||
["Chain", "base_tx"] => ?type(BaseTx),
|
||||
@@ -345,7 +326,7 @@ get_option(Opt, Env, Default) ->
|
||||
%% -- Compilation ------------------------------------------------------------
|
||||
|
||||
-spec to_fcode(env(), aeso_syntax:ast()) -> {env(), fcode()}.
|
||||
to_fcode(Env, [{Contract, Attrs, {con, _, Name}, _Impls, Decls}|Rest])
|
||||
to_fcode(Env, [{Contract, Attrs, Con = {con, _, Name}, Decls}|Rest])
|
||||
when ?IS_CONTRACT_HEAD(Contract) ->
|
||||
case Contract =:= contract_interface of
|
||||
false ->
|
||||
@@ -368,7 +349,7 @@ to_fcode(Env, [{Contract, Attrs, {con, _, Name}, _Impls, Decls}|Rest])
|
||||
event_type => EventType,
|
||||
payable => Payable,
|
||||
functions => add_init_function(
|
||||
Env1,
|
||||
Env1, Con, StateType,
|
||||
add_event_function(Env1, EventType, Funs)) },
|
||||
case Contract of
|
||||
contract_main -> [] = Rest, {Env1, ConFcode};
|
||||
@@ -381,6 +362,8 @@ to_fcode(Env, [{Contract, Attrs, {con, _, Name}, _Impls, Decls}|Rest])
|
||||
Env1 = decls_to_fcode(Env#{ context => {abstract_contract, Name} }, Decls),
|
||||
to_fcode(Env1, Rest)
|
||||
end;
|
||||
to_fcode(_Env, [NotMain = {NotMainHead, _ ,_ , _}]) when NotMainHead =/= contract_def ->
|
||||
fcode_error({last_declaration_must_be_main_contract, NotMain});
|
||||
to_fcode(Env, [{namespace, _, {con, _, Con}, Decls} | Code]) ->
|
||||
Env1 = decls_to_fcode(Env#{ context => {namespace, Con} }, Decls),
|
||||
to_fcode(Env1, Code).
|
||||
@@ -394,15 +377,22 @@ decls_to_fcode(Env, Decls) ->
|
||||
end, Env1, Decls).
|
||||
|
||||
-spec decl_to_fcode(env(), aeso_syntax:decl()) -> env().
|
||||
decl_to_fcode(Env = #{context := {contract_def, _}}, {fun_decl, _, Id, _}) ->
|
||||
case is_no_code(Env) of
|
||||
false -> fcode_error({missing_definition, Id});
|
||||
true -> Env
|
||||
end;
|
||||
decl_to_fcode(Env, {fun_decl, _, _, _}) -> Env;
|
||||
decl_to_fcode(Env, {type_def, _Ann, Name, Args, Def}) ->
|
||||
typedef_to_fcode(Env, Name, Args, Def);
|
||||
decl_to_fcode(Env = #{ functions := Funs }, {letfun, Ann, {id, _, Name}, Args, Ret, [{guarded, _, [], Body}]}) ->
|
||||
decl_to_fcode(Env = #{ functions := Funs }, {letfun, Ann, Id = {id, _, Name}, Args, Ret, [{guarded, _, [], Body}]}) ->
|
||||
Attrs = get_attributes(Ann),
|
||||
FName = lookup_fun(Env, qname(Env, Name)),
|
||||
FArgs = args_to_fcode(Env, Args),
|
||||
FRet = type_to_fcode(Env, Ret),
|
||||
FBody = expr_to_fcode(Env#{ vars => [X || {X, _} <- FArgs] }, Body),
|
||||
[ ensure_first_order_entrypoint(Ann, Id, Args, Ret, FArgs, FRet)
|
||||
|| aeso_syntax:get_ann(entrypoint, Ann, false) ],
|
||||
Def = #{ attrs => Attrs,
|
||||
args => FArgs,
|
||||
return => FRet,
|
||||
@@ -411,7 +401,8 @@ decl_to_fcode(Env = #{ functions := Funs }, {letfun, Ann, {id, _, Name}, Args, R
|
||||
Env#{ functions := NewFuns }.
|
||||
|
||||
-spec typedef_to_fcode(env(), aeso_syntax:id(), [aeso_syntax:tvar()], aeso_syntax:typedef()) -> env().
|
||||
typedef_to_fcode(Env, {id, _, Name}, Xs, Def) ->
|
||||
typedef_to_fcode(Env, Id = {id, _, Name}, Xs, Def) ->
|
||||
check_state_and_event_types(Env, Id, Xs),
|
||||
Q = qname(Env, Name),
|
||||
FDef = fun(Args) when length(Args) == length(Xs) ->
|
||||
Sub = maps:from_list(lists:zip([X || {tvar, _, X} <- Xs], Args)),
|
||||
@@ -475,6 +466,14 @@ compute_state_layout(R, [H | T]) ->
|
||||
compute_state_layout(R, _) ->
|
||||
{R + 1, {reg, R}}.
|
||||
|
||||
check_state_and_event_types(#{ context := {contract_def, _} }, Id, [_ | _]) ->
|
||||
case Id of
|
||||
{id, _, "state"} -> fcode_error({parameterized_state, Id});
|
||||
{id, _, "event"} -> fcode_error({parameterized_event, Id});
|
||||
_ -> ok
|
||||
end;
|
||||
check_state_and_event_types(_, _, _) -> ok.
|
||||
|
||||
-spec type_to_fcode(env(), aeso_syntax:type()) -> ftype().
|
||||
type_to_fcode(Env, Type) ->
|
||||
type_to_fcode(Env, #{}, Type).
|
||||
@@ -492,8 +491,12 @@ type_to_fcode(Env, Sub, {record_t, Fields}) ->
|
||||
type_to_fcode(Env, Sub, {tuple_t, [], lists:map(FieldType, Fields)});
|
||||
type_to_fcode(_Env, _Sub, {bytes_t, _, N}) ->
|
||||
{bytes, N};
|
||||
type_to_fcode(_Env, _Sub, {tvar, Ann, "void"}) ->
|
||||
fcode_error({found_void, Ann});
|
||||
type_to_fcode(_Env, Sub, {tvar, _, X}) ->
|
||||
maps:get(X, Sub, {tvar, X});
|
||||
type_to_fcode(Env, Sub, {constrained_t, _, _, TVar = {tvar, _, _}}) ->
|
||||
type_to_fcode(Env, Sub, TVar);
|
||||
type_to_fcode(_Env, _Sub, {fun_t, Ann, _, var_args, _}) ->
|
||||
fcode_error({var_args_not_set, {id, Ann, "a very suspicious function"}});
|
||||
type_to_fcode(Env, Sub, {fun_t, _, Named, Args, Res}) ->
|
||||
@@ -553,7 +556,7 @@ expr_to_fcode(_Env, _Type, {bytes, _, B}) -> {lit, {bytes, B}};
|
||||
|
||||
%% Variables
|
||||
expr_to_fcode(Env, _Type, {id, _, X}) -> resolve_var(Env, [X]);
|
||||
expr_to_fcode(Env, Type, {qid, _, X}) ->
|
||||
expr_to_fcode(Env, Type, {qid, Ann, X}) ->
|
||||
case resolve_var(Env, X) of
|
||||
{builtin_u, B, Ar} when B =:= oracle_query;
|
||||
B =:= oracle_get_question;
|
||||
@@ -564,11 +567,13 @@ expr_to_fcode(Env, Type, {qid, _, X}) ->
|
||||
B =:= oracle_check_query ->
|
||||
OType = get_oracle_type(B, Type),
|
||||
{oracle, QType, RType} = type_to_fcode(Env, OType),
|
||||
validate_oracle_type(Ann, OType, QType, RType),
|
||||
TypeArgs = [{lit, {typerep, QType}}, {lit, {typerep, RType}}],
|
||||
{builtin_u, B, Ar, TypeArgs};
|
||||
{builtin_u, B = aens_resolve, Ar} ->
|
||||
{fun_t, _, _, _, ResType} = Type,
|
||||
AensType = type_to_fcode(Env, ResType),
|
||||
validate_aens_resolve_type(Ann, ResType, AensType),
|
||||
TypeArgs = [{lit, {typerep, AensType}}],
|
||||
{builtin_u, B, Ar, TypeArgs};
|
||||
{builtin_u, B = bytes_split, Ar} ->
|
||||
@@ -708,12 +713,11 @@ expr_to_fcode(Env, Type, {app, Ann, {Op, _}, [A, B]}) when is_atom(Op) ->
|
||||
expr_to_fcode(Env, _Type, {app, _Ann, {Op, _}, [A]}) when is_atom(Op) ->
|
||||
case Op of
|
||||
'-' -> {op, '-', [{lit, {int, 0}}, expr_to_fcode(Env, A)]};
|
||||
'bnot' -> {op, 'bnot', [expr_to_fcode(Env, A)]};
|
||||
'!' -> {op, '!', [expr_to_fcode(Env, A)]}
|
||||
end;
|
||||
|
||||
%% Function calls
|
||||
expr_to_fcode(Env, _, {app, _, Fun = {typed, _, FunE, {fun_t, _, NamedArgsT, ArgsT, Type}}, Args}) ->
|
||||
expr_to_fcode(Env, Type, {app, _, Fun = {typed, _, FunE, {fun_t, _, NamedArgsT, ArgsT, _}}, Args}) ->
|
||||
Args1 = get_named_args(NamedArgsT, Args),
|
||||
FArgs = [expr_to_fcode(Env, Arg) || Arg <- Args1],
|
||||
case expr_to_fcode(Env, Fun) of
|
||||
@@ -822,6 +826,53 @@ get_oracle_type(oracle_check, {fun_t, _, _, [OType | _], _}) -> OType;
|
||||
get_oracle_type(oracle_check_query, {fun_t, _, _, [OType | _], _}) -> OType;
|
||||
get_oracle_type(oracle_respond, {fun_t, _, _, [OType | _], _}) -> OType.
|
||||
|
||||
validate_oracle_type(Ann, Type, QType, RType) ->
|
||||
ensure_monomorphic(QType, {invalid_oracle_type, polymorphic, query, Ann, Type}),
|
||||
ensure_monomorphic(RType, {invalid_oracle_type, polymorphic, response, Ann, Type}),
|
||||
ensure_first_order(QType, {invalid_oracle_type, higher_order, query, Ann, Type}),
|
||||
ensure_first_order(RType, {invalid_oracle_type, higher_order, response, Ann, Type}),
|
||||
ok.
|
||||
|
||||
validate_aens_resolve_type(Ann, {app_t, _, _, [Type]}, {variant, [[], [FType]]}) ->
|
||||
case FType of
|
||||
string -> ok;
|
||||
address -> ok;
|
||||
contract -> ok;
|
||||
{oracle, _, _} -> ok;
|
||||
oracle_query -> ok;
|
||||
_ -> fcode_error({invalid_aens_resolve_type, Ann, Type})
|
||||
end.
|
||||
|
||||
ensure_first_order_entrypoint(Ann, Id = {id, _, Name}, Args, Ret, FArgs, FRet) ->
|
||||
[ ensure_first_order(FT, {invalid_entrypoint, higher_order, Ann1, Id, {argument, X, T}})
|
||||
|| {{typed, Ann1, X, T}, {_, FT}} <- lists:zip(Args, FArgs) ],
|
||||
[ ensure_first_order(FRet, {invalid_entrypoint, higher_order, Ann, Id, {result, Ret}})
|
||||
|| Name /= "init" ], %% init can return higher-order values, since they're written to the store
|
||||
%% rather than being returned.
|
||||
ok.
|
||||
|
||||
ensure_monomorphic(Type, Err) ->
|
||||
case is_monomorphic(Type) of
|
||||
true -> ok;
|
||||
false -> fcode_error(Err)
|
||||
end.
|
||||
|
||||
ensure_first_order(Type, Err) ->
|
||||
case is_first_order(Type) of
|
||||
true -> ok;
|
||||
false -> fcode_error(Err)
|
||||
end.
|
||||
|
||||
is_monomorphic({tvar, _}) -> false;
|
||||
is_monomorphic(Ts) when is_list(Ts) -> lists:all(fun is_monomorphic/1, Ts);
|
||||
is_monomorphic(Tup) when is_tuple(Tup) -> is_monomorphic(tuple_to_list(Tup));
|
||||
is_monomorphic(_) -> true.
|
||||
|
||||
is_first_order({function, _, _}) -> false;
|
||||
is_first_order(Ts) when is_list(Ts) -> lists:all(fun is_first_order/1, Ts);
|
||||
is_first_order(Tup) when is_tuple(Tup) -> is_first_order(tuple_to_list(Tup));
|
||||
is_first_order(_) -> true.
|
||||
|
||||
%% -- Pattern matching --
|
||||
|
||||
-spec alts_to_fcode(env(), ftype(), var_name(), [aeso_syntax:alt()], aeso_syntax:expr()) -> fsplit().
|
||||
@@ -1100,9 +1151,9 @@ op_builtins() ->
|
||||
stringinternal_sha3, stringinternal_sha256, stringinternal_blake2b,
|
||||
char_to_int, char_from_int, stringinternal_to_lower, stringinternal_to_upper,
|
||||
bits_set, bits_clear, bits_test, bits_sum, bits_intersection, bits_union,
|
||||
bits_difference, int_to_str, int_mulmod, address_to_str, address_to_bytes, crypto_verify_sig,
|
||||
bits_difference, int_to_str, address_to_str, crypto_verify_sig,
|
||||
address_to_contract,
|
||||
crypto_verify_sig_secp256k1, crypto_sha3, crypto_sha256, crypto_blake2b, crypto_poseidon,
|
||||
crypto_verify_sig_secp256k1, crypto_sha3, crypto_sha256, crypto_blake2b,
|
||||
crypto_ecverify_secp256k1, crypto_ecrecover_secp256k1,
|
||||
mcl_bls12_381_g1_neg, mcl_bls12_381_g1_norm, mcl_bls12_381_g1_valid,
|
||||
mcl_bls12_381_g1_is_zero, mcl_bls12_381_g1_add, mcl_bls12_381_g1_mul,
|
||||
@@ -1154,11 +1205,11 @@ builtin_to_fcode(_Layout, Builtin, Args) ->
|
||||
|
||||
%% -- Init function --
|
||||
|
||||
add_init_function(Env, Funs0) ->
|
||||
add_init_function(Env, Main, StateType, Funs0) ->
|
||||
case is_no_code(Env) of
|
||||
true -> Funs0;
|
||||
false ->
|
||||
Funs = add_default_init_function(Env, Funs0),
|
||||
Funs = add_default_init_function(Env, Main, StateType, Funs0),
|
||||
InitName = {entrypoint, <<"init">>},
|
||||
InitFun = #{ body := InitBody} = maps:get(InitName, Funs),
|
||||
Funs1 = Funs#{ InitName => InitFun#{ return => {tuple, []},
|
||||
@@ -1166,14 +1217,16 @@ add_init_function(Env, Funs0) ->
|
||||
Funs1
|
||||
end.
|
||||
|
||||
add_default_init_function(_Env, Funs) ->
|
||||
add_default_init_function(_Env, Main, StateType, Funs) ->
|
||||
InitName = {entrypoint, <<"init">>},
|
||||
case maps:get(InitName, Funs, none) of
|
||||
none ->
|
||||
%% Only add default init function if state is unit.
|
||||
none when StateType == {tuple, []} ->
|
||||
Funs#{ InitName => #{attrs => [],
|
||||
args => [],
|
||||
return => {tuple, []},
|
||||
body => {tuple, []}} };
|
||||
none -> fcode_error({missing_init_function, Main});
|
||||
_ -> Funs
|
||||
end.
|
||||
|
||||
@@ -1307,28 +1360,20 @@ lambda_lift_exprs(Layout, As) -> [lambda_lift_expr(Layout, A) || A <- As].
|
||||
%% - Constant propagation
|
||||
%% - Inlining
|
||||
|
||||
-spec optimize_fcode(fcode(), [option()]) -> fcode().
|
||||
optimize_fcode(Code = #{ functions := Funs }, Options) ->
|
||||
Code1 = Code#{ functions := maps:map(fun(Name, Def) -> optimize_fun(Code, Name, Def, Options) end, Funs) },
|
||||
-spec optimize_fcode(fcode()) -> fcode().
|
||||
optimize_fcode(Code = #{ functions := Funs }) ->
|
||||
Code1 = Code#{ functions := maps:map(fun(Name, Def) -> optimize_fun(Code, Name, Def) end, Funs) },
|
||||
eliminate_dead_code(Code1).
|
||||
|
||||
-spec optimize_fun(fcode(), fun_name(), fun_def(), [option()]) -> fun_def().
|
||||
optimize_fun(Fcode, Fun, Def = #{ body := Body0 }, Options) ->
|
||||
Inliner = proplists:get_value(optimize_inliner, Options, true),
|
||||
InlineLocalFunctions = proplists:get_value(optimize_inline_local_functions, Options, true),
|
||||
BindSubexpressions = proplists:get_value(optimize_bind_subexpressions, Options, true),
|
||||
LetFloating = proplists:get_value(optimize_let_floating, Options, true),
|
||||
Simplifier = proplists:get_value(optimize_simplifier, Options, true),
|
||||
DropUnusedLets = proplists:get_value(optimize_drop_unused_lets, Options, true),
|
||||
|
||||
Body1 = if Inliner -> inliner (Fcode, Fun, Body0); true -> Body0 end,
|
||||
Body2 = if InlineLocalFunctions -> inline_local_functions(Body1); true -> Body1 end,
|
||||
Body3 = if BindSubexpressions -> bind_subexpressions (Body2); true -> Body2 end,
|
||||
Body4 = if LetFloating -> let_floating (Body3); true -> Body3 end,
|
||||
Body5 = if Simplifier -> simplifier (Body4); true -> Body4 end,
|
||||
Body6 = if DropUnusedLets -> drop_unused_lets (Body5); true -> Body5 end,
|
||||
|
||||
Def#{ body := Body6 }.
|
||||
-spec optimize_fun(fcode(), fun_name(), fun_def()) -> fun_def().
|
||||
optimize_fun(Fcode, Fun, Def = #{ body := Body }) ->
|
||||
%% io:format("Optimizing ~p =\n~s\n", [_Fun, prettypr:format(pp_fexpr(_Body))]),
|
||||
Def#{ body := drop_unused_lets(
|
||||
simplifier(
|
||||
let_floating(
|
||||
bind_subexpressions(
|
||||
inline_local_functions(
|
||||
inliner(Fcode, Fun, Body)))))) }.
|
||||
|
||||
%% --- Inlining ---
|
||||
|
||||
@@ -1748,29 +1793,12 @@ resolve_fun(#{ fun_env := Funs, builtins := Builtin } = Env, Q) ->
|
||||
{{Fun, Ar}, _} -> {def_u, Fun, Ar}
|
||||
end.
|
||||
|
||||
init_fresh_names(Options) ->
|
||||
proplists:get_value(debug_info, Options, false) andalso init_saved_fresh_names(),
|
||||
init_fresh_names() ->
|
||||
put('%fresh', 0).
|
||||
|
||||
clear_fresh_names(Options) ->
|
||||
proplists:get_value(debug_info, Options, false) andalso clear_saved_fresh_names(),
|
||||
clear_fresh_names() ->
|
||||
erase('%fresh').
|
||||
|
||||
init_saved_fresh_names() ->
|
||||
put(saved_fresh_names, #{}).
|
||||
|
||||
clear_saved_fresh_names() ->
|
||||
erase(saved_fresh_names).
|
||||
|
||||
-spec fresh_name_save(string()) -> var_name().
|
||||
fresh_name_save(Name) ->
|
||||
Fresh = fresh_name(),
|
||||
case get(saved_fresh_names) of
|
||||
undefined -> ok;
|
||||
Old -> put(saved_fresh_names, Old#{Fresh => Name})
|
||||
end,
|
||||
Fresh.
|
||||
|
||||
-spec fresh_name() -> var_name().
|
||||
fresh_name() -> fresh_name("%").
|
||||
|
||||
@@ -1899,7 +1927,7 @@ bottom_up(F, Env, Expr) ->
|
||||
(_) -> true end,
|
||||
case ShouldFreshen(X) of
|
||||
true ->
|
||||
Z = fresh_name_save(X),
|
||||
Z = fresh_name(),
|
||||
Env1 = Env#{ Z => E1 },
|
||||
{'let', Z, E1, bottom_up(F, Env1, rename([{X, Z}], Body))};
|
||||
false ->
|
||||
@@ -2064,9 +2092,7 @@ setnth(I, X, Xs) ->
|
||||
-dialyzer({nowarn_function, [fcode_error/1, internal_error/1]}).
|
||||
|
||||
fcode_error(Error) ->
|
||||
Pos = aeso_errors:pos(0, 0),
|
||||
Msg = lists:flatten(io_lib:format("Unknown error: ~p\n", [Error])),
|
||||
aeso_errors:throw(aeso_errors:new(code_error, Pos, Msg)).
|
||||
aeso_errors:throw(aeso_code_errors:format(Error)).
|
||||
|
||||
internal_error(Error) ->
|
||||
Msg = lists:flatten(io_lib:format("~p\n", [Error])),
|
||||
|
||||
@@ -0,0 +1,94 @@
|
||||
%%%-------------------------------------------------------------------
|
||||
%%% @author Ulf Norell
|
||||
%%% @copyright (C) 2019, Aeternity Anstalt
|
||||
%%% @doc
|
||||
%%% Formatting of code generation errors.
|
||||
%%% @end
|
||||
%%%
|
||||
%%%-------------------------------------------------------------------
|
||||
-module(aeso_code_errors).
|
||||
|
||||
-export([format/1, pos/1]).
|
||||
|
||||
format({last_declaration_must_be_main_contract, Decl = {Kind, _, {con, _, C}, _}}) ->
|
||||
Msg = io_lib:format("Expected a main contract as the last declaration instead of the ~p '~s'",
|
||||
[Kind, C]),
|
||||
mk_err(pos(Decl), Msg);
|
||||
format({missing_init_function, Con}) ->
|
||||
Msg = io_lib:format("Missing init function for the contract '~s'.", [pp_expr(Con)]),
|
||||
Cxt = "The 'init' function can only be omitted if the state type is 'unit'.",
|
||||
mk_err(pos(Con), Msg, Cxt);
|
||||
format({missing_definition, Id}) ->
|
||||
Msg = io_lib:format("Missing definition of function '~s'.", [pp_expr(Id)]),
|
||||
mk_err(pos(Id), Msg);
|
||||
format({parameterized_state, Decl}) ->
|
||||
Msg = "The state type cannot be parameterized.",
|
||||
mk_err(pos(Decl), Msg);
|
||||
format({parameterized_event, Decl}) ->
|
||||
Msg = "The event type cannot be parameterized.",
|
||||
mk_err(pos(Decl), Msg);
|
||||
format({invalid_entrypoint, Why, Ann, {id, _, Name}, Thing}) ->
|
||||
What = case Why of higher_order -> "higher-order (contains function types)";
|
||||
polymorphic -> "polymorphic (contains type variables)" end,
|
||||
ThingS = case Thing of
|
||||
{argument, X, T} -> io_lib:format("argument\n~s\n", [pp_typed(X, T)]);
|
||||
{result, T} -> io_lib:format("return type\n~s\n", [pp_type(2, T)])
|
||||
end,
|
||||
Bad = case Thing of
|
||||
{argument, _, _} -> io_lib:format("has a ~s type", [What]);
|
||||
{result, _} -> io_lib:format("is ~s", [What])
|
||||
end,
|
||||
Msg = io_lib:format("The ~sof entrypoint '~s' ~s.",
|
||||
[ThingS, Name, Bad]),
|
||||
case Why of
|
||||
higher_order -> mk_err(pos(Ann), Msg)
|
||||
end;
|
||||
format({invalid_aens_resolve_type, Ann, T}) ->
|
||||
Msg = io_lib:format("Invalid return type of AENS.resolve:\n"
|
||||
"~s\n"
|
||||
"It must be a string or a pubkey type (address, oracle, etc).",
|
||||
[pp_type(2, T)]),
|
||||
mk_err(pos(Ann), Msg);
|
||||
format({invalid_oracle_type, Why, What, Ann, Type}) ->
|
||||
WhyS = case Why of higher_order -> "higher-order (contain function types)";
|
||||
polymorphic -> "polymorphic (contain type variables)" end,
|
||||
Msg = io_lib:format("Invalid oracle type\n~s", [pp_type(2, Type)]),
|
||||
Cxt = io_lib:format("The ~s type must not be ~s.", [What, WhyS]),
|
||||
mk_err(pos(Ann), Msg, Cxt);
|
||||
format({var_args_not_set, Expr}) ->
|
||||
mk_err( pos(Expr), "Could not deduce type of variable arguments list"
|
||||
, "When compiling " ++ pp_expr(Expr)
|
||||
);
|
||||
format({found_void, Ann}) ->
|
||||
mk_err(pos(Ann), "Found a void-typed value.", "`void` is a restricted, uninhabited type. Did you mean `unit`?");
|
||||
|
||||
format(Err) ->
|
||||
mk_err(aeso_errors:pos(0, 0), io_lib:format("Unknown error: ~p\n", [Err])).
|
||||
|
||||
pos(Ann) ->
|
||||
File = aeso_syntax:get_ann(file, Ann, no_file),
|
||||
Line = aeso_syntax:get_ann(line, Ann, 0),
|
||||
Col = aeso_syntax:get_ann(col, Ann, 0),
|
||||
aeso_errors:pos(File, Line, Col).
|
||||
|
||||
pp_typed(E, T) ->
|
||||
prettypr:format(prettypr:nest(2,
|
||||
lists:foldr(fun prettypr:beside/2, prettypr:empty(),
|
||||
[aeso_pretty:expr(E), prettypr:text(" : "),
|
||||
aeso_pretty:type(T)]))).
|
||||
|
||||
pp_expr(E) ->
|
||||
pp_expr(0, E).
|
||||
|
||||
pp_expr(N, E) ->
|
||||
prettypr:format(prettypr:nest(N, aeso_pretty:expr(E))).
|
||||
|
||||
pp_type(N, T) ->
|
||||
prettypr:format(prettypr:nest(N, aeso_pretty:type(T))).
|
||||
|
||||
mk_err(Pos, Msg) ->
|
||||
aeso_errors:new(code_error, Pos, lists:flatten(Msg)).
|
||||
|
||||
mk_err(Pos, Msg, Cxt) ->
|
||||
aeso_errors:new(code_error, Pos, lists:flatten(Msg), lists:flatten(Cxt)).
|
||||
|
||||
+7
-15
@@ -112,12 +112,10 @@ from_string(ContractString, Options) ->
|
||||
|
||||
from_string1(ContractString, Options) ->
|
||||
#{ fcode := FCode
|
||||
, fcode_env := FCodeEnv
|
||||
, fcode_env := #{child_con_env := ChildContracts}
|
||||
, folded_typed_ast := FoldedTypedAst
|
||||
, warnings := Warnings } = string_to_code(ContractString, Options),
|
||||
#{ child_con_env := ChildContracts } = FCodeEnv,
|
||||
SavedFreshNames = maps:get(saved_fresh_names, FCodeEnv, #{}),
|
||||
{FateCode, VarsRegs} = aeso_fcode_to_fate:compile(ChildContracts, FCode, SavedFreshNames, Options),
|
||||
FateCode = aeso_fcode_to_fate:compile(ChildContracts, FCode, Options),
|
||||
pp_assembler(FateCode, Options),
|
||||
ByteCode = aeb_fate_code:serialize(FateCode, []),
|
||||
{ok, Version} = version(),
|
||||
@@ -130,13 +128,7 @@ from_string1(ContractString, Options) ->
|
||||
payable => maps:get(payable, FCode),
|
||||
warnings => Warnings
|
||||
},
|
||||
ResDbg = Res#{variables_registers => VarsRegs},
|
||||
FinalRes =
|
||||
case proplists:get_value(debug_info, Options, false) of
|
||||
true -> ResDbg;
|
||||
false -> Res
|
||||
end,
|
||||
{ok, maybe_generate_aci(FinalRes, FoldedTypedAst, Options)}.
|
||||
{ok, maybe_generate_aci(Res, FoldedTypedAst, Options)}.
|
||||
|
||||
maybe_generate_aci(Result, FoldedTypedAst, Options) ->
|
||||
case proplists:get_value(aci, Options) of
|
||||
@@ -193,7 +185,7 @@ check_call1(ContractString0, FunName, Args, Options) ->
|
||||
#{fcode := OrgFcode
|
||||
, fcode_env := #{child_con_env := ChildContracts}
|
||||
, ast := Ast} = string_to_code(ContractString0, Options),
|
||||
{FateCode, _} = aeso_fcode_to_fate:compile(ChildContracts, OrgFcode, #{}, []),
|
||||
FateCode = aeso_fcode_to_fate:compile(ChildContracts, OrgFcode, []),
|
||||
%% collect all hashes and compute the first name without hash collision to
|
||||
SymbolHashes = maps:keys(aeb_fate_code:symbols(FateCode)),
|
||||
CallName = first_none_match(?CALL_NAME, SymbolHashes,
|
||||
@@ -246,7 +238,7 @@ insert_init_function(Code, Options) ->
|
||||
|
||||
last_contract_indent(Decls) ->
|
||||
case lists:last(Decls) of
|
||||
{_, _, _, _, [Decl | _]} -> aeso_syntax:get_ann(col, Decl, 1) - 1;
|
||||
{_, _, _, [Decl | _]} -> aeso_syntax:get_ann(col, Decl, 1) - 1;
|
||||
_ -> 0
|
||||
end.
|
||||
|
||||
@@ -346,7 +338,7 @@ decode_calldata(ContractString, FunName, Calldata, Options0) ->
|
||||
end.
|
||||
|
||||
-dialyzer({nowarn_function, get_decode_type/2}).
|
||||
get_decode_type(FunName, [{Contract, Ann, _, _, Defs}]) when ?IS_CONTRACT_HEAD(Contract) ->
|
||||
get_decode_type(FunName, [{Contract, Ann, _, Defs}]) when ?IS_CONTRACT_HEAD(Contract) ->
|
||||
GetType = fun({letfun, _, {id, _, Name}, Args, Ret, _}) when Name == FunName -> [{Args, Ret}];
|
||||
({fun_decl, _, {id, _, Name}, {fun_t, _, _, Args, Ret}}) when Name == FunName -> [{Args, Ret}];
|
||||
(_) -> [] end,
|
||||
@@ -357,7 +349,7 @@ get_decode_type(FunName, [{Contract, Ann, _, _, Defs}]) when ?IS_CONTRACT_HEAD(C
|
||||
"init" -> {ok, [], {tuple_t, [], []}};
|
||||
_ ->
|
||||
Msg = io_lib:format("Function '~s' is missing in contract", [FunName]),
|
||||
Pos = aeso_errors:pos(Ann),
|
||||
Pos = aeso_code_errors:pos(Ann),
|
||||
aeso_errors:throw(aeso_errors:new(data_error, Pos, Msg))
|
||||
end
|
||||
end;
|
||||
|
||||
@@ -34,7 +34,6 @@
|
||||
, new/2
|
||||
, new/3
|
||||
, new/4
|
||||
, pos/1
|
||||
, pos/2
|
||||
, pos/3
|
||||
, pp/1
|
||||
@@ -54,12 +53,6 @@ new(Type, Pos, Msg) ->
|
||||
new(Type, Pos, Msg, Ctxt) ->
|
||||
#err{ type = Type, pos = Pos, message = Msg, context = Ctxt }.
|
||||
|
||||
pos(Ann) ->
|
||||
File = aeso_syntax:get_ann(file, Ann, no_file),
|
||||
Line = aeso_syntax:get_ann(line, Ann, 0),
|
||||
Col = aeso_syntax:get_ann(col, Ann, 0),
|
||||
pos(File, Line, Col).
|
||||
|
||||
pos(Line, Col) ->
|
||||
#pos{ line = Line, col = Col }.
|
||||
|
||||
|
||||
+73
-144
@@ -9,7 +9,7 @@
|
||||
%%%-------------------------------------------------------------------
|
||||
-module(aeso_fcode_to_fate).
|
||||
|
||||
-export([compile/3, compile/4, term_to_fate/1, term_to_fate/2]).
|
||||
-export([compile/2, compile/3, term_to_fate/1, term_to_fate/2]).
|
||||
|
||||
-ifdef(TEST).
|
||||
-export([optimize_fun/4, to_basic_blocks/1]).
|
||||
@@ -45,14 +45,7 @@
|
||||
-define(s(N), {store, N}).
|
||||
-define(void, {var, 9999}).
|
||||
|
||||
-record(env, { contract,
|
||||
vars = [],
|
||||
locals = [],
|
||||
current_function,
|
||||
tailpos = true,
|
||||
child_contracts = #{},
|
||||
saved_fresh_names = #{},
|
||||
options = [] }).
|
||||
-record(env, { contract, vars = [], locals = [], current_function, tailpos = true, child_contracts = #{}, options = []}).
|
||||
|
||||
%% -- Debugging --------------------------------------------------------------
|
||||
|
||||
@@ -71,34 +64,21 @@ debug(Tag, Options, Fun) ->
|
||||
|
||||
-dialyzer({nowarn_function, [code_error/1]}).
|
||||
code_error(Err) ->
|
||||
Pos = aeso_errors:pos(0, 0),
|
||||
Msg = lists:flatten(io_lib:format("Unknown error: ~p\n", [Err])),
|
||||
aeso_errors:throw(aeso_errors:new(code_error, Pos, Msg)).
|
||||
aeso_errors:throw(aeso_code_errors:format(Err)).
|
||||
|
||||
%% -- Main -------------------------------------------------------------------
|
||||
|
||||
%% @doc Main entry point.
|
||||
compile(FCode, SavedFreshNames, Options) ->
|
||||
compile(#{}, FCode, SavedFreshNames, Options).
|
||||
compile(ChildContracts, FCode, SavedFreshNames, Options) ->
|
||||
try
|
||||
compile1(ChildContracts, FCode, SavedFreshNames, Options)
|
||||
after
|
||||
put(variables_registers, undefined)
|
||||
end.
|
||||
|
||||
compile1(ChildContracts, FCode, SavedFreshNames, Options) ->
|
||||
compile(FCode, Options) ->
|
||||
compile(#{}, FCode, Options).
|
||||
compile(ChildContracts, FCode, Options) ->
|
||||
#{ contract_name := ContractName,
|
||||
functions := Functions } = FCode,
|
||||
SFuns = functions_to_scode(ChildContracts, ContractName, Functions, SavedFreshNames, Options),
|
||||
SFuns = functions_to_scode(ChildContracts, ContractName, Functions, Options),
|
||||
SFuns1 = optimize_scode(SFuns, Options),
|
||||
FateCode = to_basic_blocks(SFuns1),
|
||||
?debug(compile, Options, "~s\n", [aeb_fate_asm:pp(FateCode)]),
|
||||
FateCode1 = case proplists:get_value(include_child_contract_symbols, Options, false) of
|
||||
false -> FateCode;
|
||||
true -> add_child_symbols(ChildContracts, FateCode)
|
||||
end,
|
||||
{FateCode1, get_variables_registers()}.
|
||||
FateCode.
|
||||
|
||||
make_function_id(X) ->
|
||||
aeb_fate_code:symbol_identifier(make_function_name(X)).
|
||||
@@ -107,48 +87,22 @@ make_function_name(event) -> <<"Chain.event">>;
|
||||
make_function_name({entrypoint, Name}) -> Name;
|
||||
make_function_name({local_fun, Xs}) -> list_to_binary("." ++ string:join(Xs, ".")).
|
||||
|
||||
add_child_symbols(ChildContracts, FateCode) ->
|
||||
Funs = lists:flatten([ maps:keys(ChildFuns) || {_, #{functions := ChildFuns}} <- maps:to_list(ChildContracts) ]),
|
||||
Symbols = maps:from_list([ {make_function_id(FName), make_function_name(FName)} || FName <- Funs ]),
|
||||
aeb_fate_code:update_symbols(FateCode, Symbols).
|
||||
|
||||
functions_to_scode(ChildContracts, ContractName, Functions, SavedFreshNames, Options) ->
|
||||
functions_to_scode(ChildContracts, ContractName, Functions, Options) ->
|
||||
FunNames = maps:keys(Functions),
|
||||
maps:from_list(
|
||||
[ {make_function_name(Name), function_to_scode(ChildContracts, ContractName, FunNames, Name, Attrs, Args, Body, Type, SavedFreshNames, Options)}
|
||||
[ {make_function_name(Name), function_to_scode(ChildContracts, ContractName, FunNames, Name, Attrs, Args, Body, Type, Options)}
|
||||
|| {Name, #{args := Args,
|
||||
body := Body,
|
||||
attrs := Attrs,
|
||||
return := Type}} <- maps:to_list(Functions)]).
|
||||
|
||||
function_to_scode(ChildContracts, ContractName, Functions, Name, Attrs0, Args, Body, ResType, SavedFreshNames, Options) ->
|
||||
function_to_scode(ChildContracts, ContractName, Functions, Name, Attrs0, Args, Body, ResType, Options) ->
|
||||
{ArgTypes, ResType1} = typesig_to_scode(Args, ResType),
|
||||
Attrs = Attrs0 -- [stateful], %% Only track private and payable from here.
|
||||
Env = init_env(ChildContracts, ContractName, Functions, Name, Args, SavedFreshNames, Options),
|
||||
[ add_variables_register(Env, Arg, Register) ||
|
||||
proplists:get_value(debug_info, Options, false),
|
||||
{Arg, Register} <- Env#env.vars ],
|
||||
Env = init_env(ChildContracts, ContractName, Functions, Name, Args, Options),
|
||||
SCode = to_scode(Env, Body),
|
||||
{Attrs, {ArgTypes, ResType1}, SCode}.
|
||||
|
||||
get_variables_registers() ->
|
||||
case get(variables_registers) of
|
||||
undefined -> #{};
|
||||
Vs -> Vs
|
||||
end.
|
||||
|
||||
add_variables_register(Env = #env{saved_fresh_names = SavedFreshNames}, Name, Register) ->
|
||||
Olds = get_variables_registers(),
|
||||
RealName = maps:get(Name, SavedFreshNames, Name),
|
||||
FunName =
|
||||
case Env#env.current_function of
|
||||
event -> "Chain.event";
|
||||
{entrypoint, BinName} -> binary_to_list(BinName);
|
||||
{local_fun, QualName} -> lists:last(QualName)
|
||||
end,
|
||||
New = {Env#env.contract, FunName, RealName},
|
||||
put(variables_registers, Olds#{New => Register}).
|
||||
|
||||
-define(tvars, '$tvars').
|
||||
|
||||
typesig_to_scode(Args, Res) ->
|
||||
@@ -193,21 +147,19 @@ types_to_scode(Ts) -> lists:map(fun type_to_scode/1, Ts).
|
||||
|
||||
%% -- Environment functions --
|
||||
|
||||
init_env(ChildContracts, ContractName, FunNames, Name, Args, SavedFreshNames, Options) ->
|
||||
init_env(ChildContracts, ContractName, FunNames, Name, Args, Options) ->
|
||||
#env{ vars = [ {X, {arg, I}} || {I, {X, _}} <- with_ixs(Args) ],
|
||||
contract = ContractName,
|
||||
child_contracts = ChildContracts,
|
||||
locals = FunNames,
|
||||
current_function = Name,
|
||||
options = Options,
|
||||
tailpos = true,
|
||||
saved_fresh_names = SavedFreshNames }.
|
||||
tailpos = true }.
|
||||
|
||||
next_var(#env{ vars = Vars }) ->
|
||||
1 + lists:max([-1 | [J || {_, {var, J}} <- Vars]]).
|
||||
|
||||
bind_var(Name, Var, Env = #env{ vars = Vars }) ->
|
||||
proplists:get_value(debug_info, Env#env.options, false) andalso add_variables_register(Env, Name, Var),
|
||||
Env#env{ vars = [{Name, Var} | Vars] }.
|
||||
|
||||
bind_local(Name, Env) ->
|
||||
@@ -232,9 +184,8 @@ serialize_contract_code(Env, C) ->
|
||||
case maps:get(C, Cache, none) of
|
||||
none ->
|
||||
Options = Env#env.options,
|
||||
SavedFreshNames = Env#env.saved_fresh_names,
|
||||
FCode = maps:get(C, Env#env.child_contracts),
|
||||
{FateCode, _} = compile1(Env#env.child_contracts, FCode, SavedFreshNames, Options),
|
||||
FateCode = compile(Env#env.child_contracts, FCode, Options),
|
||||
ByteCode = aeb_fate_code:serialize(FateCode, []),
|
||||
{ok, Version} = aeso_compiler:version(),
|
||||
OriginalSourceCode = proplists:get_value(original_src, Options, ""),
|
||||
@@ -556,8 +507,6 @@ builtin_to_scode(Env, bytes_split, [_, _] = Args) ->
|
||||
call_to_scode(Env, aeb_fate_ops:bytes_split(?a, ?a, ?a), Args);
|
||||
builtin_to_scode(Env, abort, [_] = Args) ->
|
||||
call_to_scode(Env, aeb_fate_ops:abort(?a), Args);
|
||||
builtin_to_scode(Env, exit, [_] = Args) ->
|
||||
call_to_scode(Env, aeb_fate_ops:exit(?a), Args);
|
||||
builtin_to_scode(Env, chain_spend, [_, _] = Args) ->
|
||||
call_to_scode(Env, [aeb_fate_ops:spend(?a, ?a),
|
||||
tuple(0)], Args);
|
||||
@@ -682,12 +631,6 @@ op_to_scode('>=') -> aeb_fate_ops:egt(?a, ?a, ?a);
|
||||
op_to_scode('==') -> aeb_fate_ops:eq(?a, ?a, ?a);
|
||||
op_to_scode('!=') -> aeb_fate_ops:neq(?a, ?a, ?a);
|
||||
op_to_scode('!') -> aeb_fate_ops:not_op(?a, ?a);
|
||||
op_to_scode('bnot') -> aeb_fate_ops:bin_not(?a, ?a);
|
||||
op_to_scode('band') -> aeb_fate_ops:bin_and(?a, ?a, ?a);
|
||||
op_to_scode('bor') -> aeb_fate_ops:bin_or(?a, ?a, ?a);
|
||||
op_to_scode('bxor') -> aeb_fate_ops:bin_xor(?a, ?a, ?a);
|
||||
op_to_scode('<<') -> aeb_fate_ops:bin_sl(?a, ?a, ?a);
|
||||
op_to_scode('>>') -> aeb_fate_ops:bin_sr(?a, ?a, ?a);
|
||||
op_to_scode(map_get) -> aeb_fate_ops:map_lookup(?a, ?a, ?a);
|
||||
op_to_scode(map_get_d) -> aeb_fate_ops:map_lookup(?a, ?a, ?a, ?a);
|
||||
op_to_scode(map_set) -> aeb_fate_ops:map_update(?a, ?a, ?a, ?a);
|
||||
@@ -712,9 +655,7 @@ op_to_scode(bits_intersection) -> aeb_fate_ops:bits_and(?a, ?a, ?a);
|
||||
op_to_scode(bits_union) -> aeb_fate_ops:bits_or(?a, ?a, ?a);
|
||||
op_to_scode(bits_difference) -> aeb_fate_ops:bits_diff(?a, ?a, ?a);
|
||||
op_to_scode(address_to_str) -> aeb_fate_ops:addr_to_str(?a, ?a);
|
||||
op_to_scode(address_to_bytes) -> aeb_fate_ops:addr_to_bytes(?a, ?a);
|
||||
op_to_scode(int_to_str) -> aeb_fate_ops:int_to_str(?a, ?a);
|
||||
op_to_scode(int_mulmod) -> aeb_fate_ops:mulmod(?a, ?a, ?a, ?a);
|
||||
op_to_scode(contract_to_address) -> aeb_fate_ops:contract_to_address(?a, ?a);
|
||||
op_to_scode(address_to_contract) -> aeb_fate_ops:address_to_contract(?a, ?a);
|
||||
op_to_scode(crypto_verify_sig) -> aeb_fate_ops:verify_sig(?a, ?a, ?a, ?a);
|
||||
@@ -724,7 +665,6 @@ op_to_scode(crypto_ecrecover_secp256k1) -> aeb_fate_ops:ecrecover_secp256k1(?a,
|
||||
op_to_scode(crypto_sha3) -> aeb_fate_ops:sha3(?a, ?a);
|
||||
op_to_scode(crypto_sha256) -> aeb_fate_ops:sha256(?a, ?a);
|
||||
op_to_scode(crypto_blake2b) -> aeb_fate_ops:blake2b(?a, ?a);
|
||||
op_to_scode(crypto_poseidon) -> aeb_fate_ops:poseidon(?a, ?a, ?a);
|
||||
op_to_scode(stringinternal_sha3) -> aeb_fate_ops:sha3(?a, ?a);
|
||||
op_to_scode(stringinternal_sha256) -> aeb_fate_ops:sha256(?a, ?a);
|
||||
op_to_scode(stringinternal_blake2b) -> aeb_fate_ops:blake2b(?a, ?a);
|
||||
@@ -922,13 +862,6 @@ attributes(I) ->
|
||||
{'DIV', A, B, C} -> Pure(A, [B, C]);
|
||||
{'MOD', A, B, C} -> Pure(A, [B, C]);
|
||||
{'POW', A, B, C} -> Pure(A, [B, C]);
|
||||
{'MULMOD', A, B, C, D} -> Pure(A, [B, C, D]);
|
||||
{'BAND', A, B, C} -> Pure(A, [B, C]);
|
||||
{'BOR', A, B, C} -> Pure(A, [B, C]);
|
||||
{'BXOR', A, B, C} -> Pure(A, [B, C]);
|
||||
{'BNOT', A, B} -> Pure(A, [B]);
|
||||
{'BSL', A, B, C} -> Pure(A, [B, C]);
|
||||
{'BSR', A, B, C} -> Pure(A, [B, C]);
|
||||
{'LT', A, B, C} -> Pure(A, [B, C]);
|
||||
{'GT', A, B, C} -> Pure(A, [B, C]);
|
||||
{'EQ', A, B, C} -> Pure(A, [B, C]);
|
||||
@@ -981,14 +914,12 @@ attributes(I) ->
|
||||
{'SHA3', A, B} -> Pure(A, [B]);
|
||||
{'SHA256', A, B} -> Pure(A, [B]);
|
||||
{'BLAKE2B', A, B} -> Pure(A, [B]);
|
||||
{'POSEIDON', A, B, C} -> Pure(A, [B, C]);
|
||||
{'VERIFY_SIG', A, B, C, D} -> Pure(A, [B, C, D]);
|
||||
{'VERIFY_SIG_SECP256K1', A, B, C, D} -> Pure(A, [B, C, D]);
|
||||
{'ECVERIFY_SECP256K1', A, B, C, D} -> Pure(A, [B, C, D]);
|
||||
{'ECRECOVER_SECP256K1', A, B, C} -> Pure(A, [B, C]);
|
||||
{'CONTRACT_TO_ADDRESS', A, B} -> Pure(A, [B]);
|
||||
{'ADDRESS_TO_CONTRACT', A, B} -> Pure(A, [B]);
|
||||
{'ADDRESS_TO_BYTES', A, B} -> Pure(A, [B]);
|
||||
{'AUTH_TX_HASH', A} -> Pure(A, []);
|
||||
{'AUTH_TX', A} -> Pure(A, []);
|
||||
{'BYTES_TO_INT', A, B} -> Pure(A, [B]);
|
||||
@@ -1157,8 +1088,7 @@ simpl_top(I, Code, Options) ->
|
||||
simpl_top(0, I, Code, _Options) ->
|
||||
code_error({optimizer_out_of_fuel, I, Code});
|
||||
simpl_top(Fuel, I, Code, Options) ->
|
||||
Rules = [R || R = {Rule, _} <- rules(), proplists:get_value(Rule, Options, true)],
|
||||
apply_rules(Fuel, Rules, I, Code, Options).
|
||||
apply_rules(Fuel, rules(), I, Code, Options).
|
||||
|
||||
apply_rules(Fuel, Rules, I, Code, Options) ->
|
||||
Cons = fun(X, Xs) -> simpl_top(Fuel - 1, X, Xs, Options) end,
|
||||
@@ -1185,29 +1115,29 @@ apply_rules_once([{RName, Rule} | Rules], I, Code) ->
|
||||
-define(RULE(Name), {Name, fun Name/2}).
|
||||
|
||||
merge_rules() ->
|
||||
[?RULE(optimize_push_consume),
|
||||
?RULE(optimize_one_shot_var),
|
||||
?RULE(optimize_write_to_dead_var),
|
||||
?RULE(optimize_inline_switch_target)
|
||||
[?RULE(r_push_consume),
|
||||
?RULE(r_one_shot_var),
|
||||
?RULE(r_write_to_dead_var),
|
||||
?RULE(r_inline_switch_target)
|
||||
].
|
||||
|
||||
rules() ->
|
||||
merge_rules() ++
|
||||
[?RULE(optimize_swap_push),
|
||||
?RULE(optimize_swap_pop),
|
||||
?RULE(optimize_swap_write),
|
||||
?RULE(optimize_constant_propagation),
|
||||
?RULE(optimize_prune_impossible_branches),
|
||||
?RULE(optimize_single_successful_branch),
|
||||
?RULE(optimize_inline_store),
|
||||
?RULE(optimize_float_switch_body)
|
||||
[?RULE(r_swap_push),
|
||||
?RULE(r_swap_pop),
|
||||
?RULE(r_swap_write),
|
||||
?RULE(r_constant_propagation),
|
||||
?RULE(r_prune_impossible_branches),
|
||||
?RULE(r_single_successful_branch),
|
||||
?RULE(r_inline_store),
|
||||
?RULE(r_float_switch_body)
|
||||
].
|
||||
|
||||
%% Removing pushes that are immediately consumed.
|
||||
optimize_push_consume({i, Ann1, {'STORE', ?a, A}}, Code) ->
|
||||
r_push_consume({i, Ann1, {'STORE', ?a, A}}, Code) ->
|
||||
inline_push(Ann1, A, 0, Code, []);
|
||||
%% Writing directly to memory instead of going through the accumulator.
|
||||
optimize_push_consume({i, Ann1, I}, [{i, Ann2, {'STORE', R, ?a}} | Code]) ->
|
||||
r_push_consume({i, Ann1, I}, [{i, Ann2, {'STORE', R, ?a}} | Code]) ->
|
||||
IsPush =
|
||||
case op_view(I) of
|
||||
{_, ?a, _} -> true;
|
||||
@@ -1219,7 +1149,7 @@ optimize_push_consume({i, Ann1, I}, [{i, Ann2, {'STORE', R, ?a}} | Code]) ->
|
||||
end,
|
||||
if IsPush -> {[{i, merge_ann(Ann1, Ann2), setelement(2, I, R)}], Code};
|
||||
true -> false end;
|
||||
optimize_push_consume(_, _) -> false.
|
||||
r_push_consume(_, _) -> false.
|
||||
|
||||
inline_push(Ann, Arg, Stack, [{i, _, switch_body} = AI | Code], Acc) ->
|
||||
{AI1, {i, Ann1, _}} = swap_instrs({i, Ann, {'STORE', ?a, Arg}}, AI),
|
||||
@@ -1252,7 +1182,7 @@ split_stack_arg(N, [A | As], Acc) ->
|
||||
split_stack_arg(N1, As, [A | Acc]).
|
||||
|
||||
%% Move PUSHes past non-stack instructions.
|
||||
optimize_swap_push(Push = {i, _, PushI}, [I | Code]) ->
|
||||
r_swap_push(Push = {i, _, PushI}, [I | Code]) ->
|
||||
case op_view(PushI) of
|
||||
{_, ?a, _} ->
|
||||
case independent(Push, I) of
|
||||
@@ -1263,10 +1193,10 @@ optimize_swap_push(Push = {i, _, PushI}, [I | Code]) ->
|
||||
end;
|
||||
_ -> false
|
||||
end;
|
||||
optimize_swap_push(_, _) -> false.
|
||||
r_swap_push(_, _) -> false.
|
||||
|
||||
%% Move non-stack instruction past POPs.
|
||||
optimize_swap_pop(IA = {i, _, I}, [JA = {i, _, J} | Code]) ->
|
||||
r_swap_pop(IA = {i, _, I}, [JA = {i, _, J} | Code]) ->
|
||||
case independent(IA, JA) of
|
||||
true ->
|
||||
case {op_view(I), op_view(J)} of
|
||||
@@ -1274,7 +1204,7 @@ optimize_swap_pop(IA = {i, _, I}, [JA = {i, _, J} | Code]) ->
|
||||
{_, false} -> false;
|
||||
{{_, IR, IAs}, {_, RJ, JAs}} ->
|
||||
NonStackI = not lists:member(?a, [IR | IAs]),
|
||||
%% RJ /= ?a to not conflict with optimize_swap_push
|
||||
%% RJ /= ?a to not conflict with r_swap_push
|
||||
PopJ = RJ /= ?a andalso lists:member(?a, JAs),
|
||||
case NonStackI andalso PopJ of
|
||||
false -> false;
|
||||
@@ -1285,22 +1215,22 @@ optimize_swap_pop(IA = {i, _, I}, [JA = {i, _, J} | Code]) ->
|
||||
end;
|
||||
false -> false
|
||||
end;
|
||||
optimize_swap_pop(_, _) -> false.
|
||||
r_swap_pop(_, _) -> false.
|
||||
|
||||
%% Match up writes to variables with instructions further down.
|
||||
optimize_swap_write(I = {i, _, _}, [J | Code]) ->
|
||||
r_swap_write(I = {i, _, _}, [J | Code]) ->
|
||||
case {var_writes(I), independent(I, J)} of
|
||||
{[_], true} ->
|
||||
{J1, I1} = swap_instrs(I, J),
|
||||
optimize_swap_write([J1], I1, Code);
|
||||
r_swap_write([J1], I1, Code);
|
||||
_ -> false
|
||||
end;
|
||||
optimize_swap_write(_, _) -> false.
|
||||
r_swap_write(_, _) -> false.
|
||||
|
||||
optimize_swap_write(Pre, I, [{i, _, switch_body} = J | Code]) ->
|
||||
r_swap_write(Pre, I, [{i, _, switch_body} = J | Code]) ->
|
||||
{J1, I1} = swap_instrs(I, J),
|
||||
optimize_swap_write([J1 | Pre], I1, Code);
|
||||
optimize_swap_write(Pre, I, Code0 = [J | Code]) ->
|
||||
r_swap_write([J1 | Pre], I1, Code);
|
||||
r_swap_write(Pre, I, Code0 = [J | Code]) ->
|
||||
case apply_rules_once(merge_rules(), I, Code0) of
|
||||
{_Rule, New, Rest} ->
|
||||
{lists:reverse(Pre) ++ New, Rest};
|
||||
@@ -1309,27 +1239,27 @@ optimize_swap_write(Pre, I, Code0 = [J | Code]) ->
|
||||
false -> false;
|
||||
true ->
|
||||
{J1, I1} = swap_instrs(I, J),
|
||||
optimize_swap_write([J1 | Pre], I1, Code)
|
||||
r_swap_write([J1 | Pre], I1, Code)
|
||||
end
|
||||
end;
|
||||
optimize_swap_write(_, _, _) -> false.
|
||||
r_swap_write(_, _, _) -> false.
|
||||
|
||||
%% Precompute instructions with known values
|
||||
optimize_constant_propagation(Cons = {i, Ann1, {'CONS', R, X, Xs}}, [{i, Ann, {'IS_NIL', S, R}} | Code]) ->
|
||||
r_constant_propagation(Cons = {i, Ann1, {'CONS', R, X, Xs}}, [{i, Ann, {'IS_NIL', S, R}} | Code]) ->
|
||||
Store = {i, Ann, {'STORE', S, ?i(false)}},
|
||||
Cons1 = case R of
|
||||
?a -> {i, Ann1, {'CONS', ?void, X, Xs}};
|
||||
_ -> Cons
|
||||
end,
|
||||
{[Cons1, Store], Code};
|
||||
optimize_constant_propagation(Nil = {i, Ann1, {'NIL', R}}, [{i, Ann, {'IS_NIL', S, R}} | Code]) ->
|
||||
r_constant_propagation(Nil = {i, Ann1, {'NIL', R}}, [{i, Ann, {'IS_NIL', S, R}} | Code]) ->
|
||||
Store = {i, Ann, {'STORE', S, ?i(true)}},
|
||||
Nil1 = case R of
|
||||
?a -> {i, Ann1, {'NIL', ?void}};
|
||||
_ -> Nil
|
||||
end,
|
||||
{[Nil1, Store], Code};
|
||||
optimize_constant_propagation({i, Ann, I}, Code) ->
|
||||
r_constant_propagation({i, Ann, I}, Code) ->
|
||||
case op_view(I) of
|
||||
false -> false;
|
||||
{Op, R, As} ->
|
||||
@@ -1343,7 +1273,7 @@ optimize_constant_propagation({i, Ann, I}, Code) ->
|
||||
end
|
||||
end
|
||||
end;
|
||||
optimize_constant_propagation(_, _) -> false.
|
||||
r_constant_propagation(_, _) -> false.
|
||||
|
||||
eval_op('ADD', [X, Y]) when is_integer(X), is_integer(Y) -> X + Y;
|
||||
eval_op('SUB', [X, Y]) when is_integer(X), is_integer(Y) -> X - Y;
|
||||
@@ -1362,12 +1292,12 @@ eval_op('NOT', [false]) -> true;
|
||||
eval_op(_, _) -> no_eval. %% TODO: bits?
|
||||
|
||||
%% Prune impossible branches from switches
|
||||
optimize_prune_impossible_branches({switch, ?i(V), Type, Alts, missing}, Code) ->
|
||||
r_prune_impossible_branches({switch, ?i(V), Type, Alts, missing}, Code) ->
|
||||
case pick_branch(Type, V, Alts) of
|
||||
false -> false;
|
||||
Alt -> {Alt, Code}
|
||||
end;
|
||||
optimize_prune_impossible_branches({switch, ?i(V), boolean, [False, True] = Alts, Def}, Code) when V == true; V == false ->
|
||||
r_prune_impossible_branches({switch, ?i(V), boolean, [False, True] = Alts, Def}, Code) when V == true; V == false ->
|
||||
Alts1 = [if V -> missing; true -> False end,
|
||||
if V -> True; true -> missing end],
|
||||
case Alts == Alts1 of
|
||||
@@ -1378,7 +1308,7 @@ optimize_prune_impossible_branches({switch, ?i(V), boolean, [False, True] = Alts
|
||||
_ -> {[{switch, ?i(V), boolean, Alts1, Def}], Code}
|
||||
end
|
||||
end;
|
||||
optimize_prune_impossible_branches(Variant = {i, _, {'VARIANT', R, ?i(_), ?i(Tag), ?i(_)}},
|
||||
r_prune_impossible_branches(Variant = {i, _, {'VARIANT', R, ?i(_), ?i(Tag), ?i(_)}},
|
||||
[{switch, R, Type = {variant, _}, Alts, missing} | Code]) when is_integer(Tag) ->
|
||||
case {R, lists:nth(Tag + 1, Alts)} of
|
||||
{_, missing} ->
|
||||
@@ -1394,7 +1324,7 @@ optimize_prune_impossible_branches(Variant = {i, _, {'VARIANT', R, ?i(_), ?i(Tag
|
||||
false -> {Alt, Code}
|
||||
end
|
||||
end;
|
||||
optimize_prune_impossible_branches(_, _) -> false.
|
||||
r_prune_impossible_branches(_, _) -> false.
|
||||
|
||||
pick_branch(boolean, V, [False, True]) when V == true; V == false ->
|
||||
Alt = if V -> True; true -> False end,
|
||||
@@ -1407,7 +1337,7 @@ pick_branch(_Type, _V, _Alts) ->
|
||||
|
||||
%% If there's a single branch that doesn't abort we can push the code for that
|
||||
%% out of the switch.
|
||||
optimize_single_successful_branch({switch, R, Type, Alts, Def}, Code) ->
|
||||
r_single_successful_branch({switch, R, Type, Alts, Def}, Code) ->
|
||||
case push_code_out_of_switch([Def | Alts]) of
|
||||
{_, none} -> false;
|
||||
{_, many} -> false;
|
||||
@@ -1415,7 +1345,7 @@ optimize_single_successful_branch({switch, R, Type, Alts, Def}, Code) ->
|
||||
{[Def1 | Alts1], PushedOut} ->
|
||||
{[{switch, R, Type, Alts1, Def1} | PushedOut], Code}
|
||||
end;
|
||||
optimize_single_successful_branch(_, _) -> false.
|
||||
r_single_successful_branch(_, _) -> false.
|
||||
|
||||
push_code_out_of_switch([]) -> {[], none};
|
||||
push_code_out_of_switch([Alt | Alts]) ->
|
||||
@@ -1451,7 +1381,7 @@ does_abort({switch, _, _, Alts, Def}) ->
|
||||
does_abort(_) -> false.
|
||||
|
||||
%% STORE R A, SWITCH R --> SWITCH A
|
||||
optimize_inline_switch_target({i, Ann, {'STORE', R, A}}, [{switch, R, Type, Alts, Def} | Code]) ->
|
||||
r_inline_switch_target({i, Ann, {'STORE', R, A}}, [{switch, R, Type, Alts, Def} | Code]) ->
|
||||
Ann1 =
|
||||
case is_reg(A) of
|
||||
true -> Ann#{ live_out := ordsets:add_element(A, maps:get(live_out, Ann)) };
|
||||
@@ -1470,18 +1400,18 @@ optimize_inline_switch_target({i, Ann, {'STORE', R, A}}, [{switch, R, Type, Alts
|
||||
end;
|
||||
_ -> false %% impossible
|
||||
end;
|
||||
optimize_inline_switch_target(_, _) -> false.
|
||||
r_inline_switch_target(_, _) -> false.
|
||||
|
||||
%% Float switch-body to closest switch
|
||||
optimize_float_switch_body(I = {i, _, _}, [J = {i, _, switch_body} | Code]) ->
|
||||
r_float_switch_body(I = {i, _, _}, [J = {i, _, switch_body} | Code]) ->
|
||||
{J1, I1} = swap_instrs(I, J),
|
||||
{[], [J1, I1 | Code]};
|
||||
optimize_float_switch_body(_, _) -> false.
|
||||
r_float_switch_body(_, _) -> false.
|
||||
|
||||
%% Inline stores
|
||||
optimize_inline_store({i, _, {'STORE', R, R}}, Code) ->
|
||||
r_inline_store({i, _, {'STORE', R, R}}, Code) ->
|
||||
{[], Code};
|
||||
optimize_inline_store(I = {i, _, {'STORE', R = {var, _}, A}}, Code) ->
|
||||
r_inline_store(I = {i, _, {'STORE', R = {var, _}, A}}, Code) ->
|
||||
%% Not when A is var unless updating the annotations properly.
|
||||
Inline = case A of
|
||||
{arg, _} -> true;
|
||||
@@ -1489,13 +1419,13 @@ optimize_inline_store(I = {i, _, {'STORE', R = {var, _}, A}}, Code) ->
|
||||
{store, _} -> true;
|
||||
_ -> false
|
||||
end,
|
||||
if Inline -> optimize_inline_store([I], false, R, A, Code);
|
||||
if Inline -> r_inline_store([I], false, R, A, Code);
|
||||
true -> false end;
|
||||
optimize_inline_store(_, _) -> false.
|
||||
r_inline_store(_, _) -> false.
|
||||
|
||||
optimize_inline_store(Acc, Progress, R, A, [I = {i, _, switch_body} | Code]) ->
|
||||
optimize_inline_store([I | Acc], Progress, R, A, Code);
|
||||
optimize_inline_store(Acc, Progress, R, A, [{i, Ann, I} | Code]) ->
|
||||
r_inline_store(Acc, Progress, R, A, [I = {i, _, switch_body} | Code]) ->
|
||||
r_inline_store([I | Acc], Progress, R, A, Code);
|
||||
r_inline_store(Acc, Progress, R, A, [{i, Ann, I} | Code]) ->
|
||||
#{ write := W } = attributes(I),
|
||||
Inl = fun(X) when X == R -> A; (X) -> X end,
|
||||
case live_in(R, Ann) of
|
||||
@@ -1515,14 +1445,14 @@ optimize_inline_store(Acc, Progress, R, A, [{i, Ann, I} | Code]) ->
|
||||
case lists:member(W, [R, A]) of
|
||||
true when Progress1 -> {lists:reverse(Acc1), Code};
|
||||
true -> false;
|
||||
false -> optimize_inline_store(Acc1, Progress1, R, A, Code)
|
||||
false -> r_inline_store(Acc1, Progress1, R, A, Code)
|
||||
end
|
||||
end;
|
||||
optimize_inline_store(Acc, true, _, _, Code) -> {lists:reverse(Acc), Code};
|
||||
optimize_inline_store(_, false, _, _, _) -> false.
|
||||
r_inline_store(Acc, true, _, _, Code) -> {lists:reverse(Acc), Code};
|
||||
r_inline_store(_, false, _, _, _) -> false.
|
||||
|
||||
%% Shortcut write followed by final read
|
||||
optimize_one_shot_var({i, Ann1, I}, [{i, Ann2, J} | Code]) ->
|
||||
r_one_shot_var({i, Ann1, I}, [{i, Ann2, J} | Code]) ->
|
||||
case op_view(I) of
|
||||
{Op, R = {var, _}, As} ->
|
||||
Copy = case J of
|
||||
@@ -1536,11 +1466,11 @@ optimize_one_shot_var({i, Ann1, I}, [{i, Ann2, J} | Code]) ->
|
||||
end;
|
||||
_ -> false
|
||||
end;
|
||||
optimize_one_shot_var(_, _) -> false.
|
||||
r_one_shot_var(_, _) -> false.
|
||||
|
||||
%% Remove writes to dead variables
|
||||
optimize_write_to_dead_var({i, _, {'STORE', ?void, ?a}}, _) -> false; %% Avoid looping
|
||||
optimize_write_to_dead_var({i, Ann, I}, Code) ->
|
||||
r_write_to_dead_var({i, _, {'STORE', ?void, ?a}}, _) -> false; %% Avoid looping
|
||||
r_write_to_dead_var({i, Ann, I}, Code) ->
|
||||
#{ pure := Pure } = attributes(I),
|
||||
case op_view(I) of
|
||||
{_Op, R, As} when R /= ?a, Pure ->
|
||||
@@ -1553,10 +1483,9 @@ optimize_write_to_dead_var({i, Ann, I}, Code) ->
|
||||
end;
|
||||
_ -> false
|
||||
end;
|
||||
optimize_write_to_dead_var(_, _) -> false.
|
||||
r_write_to_dead_var(_, _) -> false.
|
||||
|
||||
op_view({'ABORT', R}) -> {'ABORT', none, [R]};
|
||||
op_view({'EXIT', R}) -> {'EXIT', none, [R]};
|
||||
op_view(T) when is_tuple(T) ->
|
||||
[Op, R | As] = tuple_to_list(T),
|
||||
CheckReads = fun(Rs, X) -> case [] == Rs -- [dst, src] of true -> X; false -> false end end,
|
||||
|
||||
+22
-28
@@ -96,29 +96,17 @@ decl() ->
|
||||
choice(
|
||||
%% Contract declaration
|
||||
[ ?RULE(token(main), keyword(contract),
|
||||
con(), tok('='), maybe_block(decl()), {contract_main, _2, _3, [], _5})
|
||||
, ?RULE(token(main), keyword(contract),
|
||||
con(), tok(':'), comma_sep(con()), tok('='), maybe_block(decl()), {contract_main, _2, _3, _5, _7})
|
||||
con(), tok('='), maybe_block(decl()), {contract_main, _2, _3, _5})
|
||||
, ?RULE(keyword(contract),
|
||||
con(), tok('='), maybe_block(decl()), {contract_child, _1, _2, [], _4})
|
||||
, ?RULE(keyword(contract),
|
||||
con(), tok(':'), comma_sep(con()), tok('='), maybe_block(decl()), {contract_child, _1, _2, _4, _6})
|
||||
con(), tok('='), maybe_block(decl()), {contract_child, _1, _2, _4})
|
||||
, ?RULE(keyword(contract), token(interface),
|
||||
con(), tok('='), maybe_block(decl()), {contract_interface, _1, _3, [], _5})
|
||||
, ?RULE(keyword(contract), token(interface),
|
||||
con(), tok(':'), comma_sep(con()), tok('='), maybe_block(decl()), {contract_interface, _1, _3, _5, _7})
|
||||
con(), tok('='), maybe_block(decl()), {contract_interface, _1, _3, _5})
|
||||
, ?RULE(token(payable), token(main), keyword(contract),
|
||||
con(), tok('='), maybe_block(decl()), add_modifiers([_1], {contract_main, _3, _4, [], _6}))
|
||||
, ?RULE(token(payable), token(main), keyword(contract),
|
||||
con(), tok(':'), comma_sep(con()), tok('='), maybe_block(decl()), add_modifiers([_1], {contract_main, _3, _4, _6, _8}))
|
||||
con(), tok('='), maybe_block(decl()), add_modifiers([_1], {contract_main, _3, _4, _6}))
|
||||
, ?RULE(token(payable), keyword(contract),
|
||||
con(), tok('='), maybe_block(decl()), add_modifiers([_1], {contract_child, _2, _3, [], _5}))
|
||||
, ?RULE(token(payable), keyword(contract),
|
||||
con(), tok(':'), comma_sep(con()), tok('='), maybe_block(decl()), add_modifiers([_1], {contract_child, _2, _3, _5, _7}))
|
||||
con(), tok('='), maybe_block(decl()), add_modifiers([_1], {contract_child, _2, _3, _5}))
|
||||
, ?RULE(token(payable), keyword(contract), token(interface),
|
||||
con(), tok('='), maybe_block(decl()), add_modifiers([_1], {contract_interface, _2, _4, [], _6}))
|
||||
, ?RULE(token(payable), keyword(contract), token(interface),
|
||||
con(), tok(':'), comma_sep(con()), tok('='), maybe_block(decl()), add_modifiers([_1], {contract_interface, _2, _4, _6, _8}))
|
||||
con(), tok('='), maybe_block(decl()), add_modifiers([_1], {contract_interface, _2, _4, _6}))
|
||||
|
||||
|
||||
, ?RULE(keyword(namespace), con(), tok('='), maybe_block(decl()), {namespace, _1, _2, _4})
|
||||
@@ -146,9 +134,19 @@ fun_block(Mods, Kind, [Decl]) ->
|
||||
fun_block(Mods, Kind, Decls) ->
|
||||
{block, get_ann(Kind), [ add_modifiers(Mods, Kind, Decl) || Decl <- Decls ]}.
|
||||
|
||||
typevar_constraint() ->
|
||||
?RULE(tvar(), keyword(is), id(), {constraint, get_ann(_1), _1, _3}).
|
||||
|
||||
typevars_constraints() ->
|
||||
?RULE(comma_sep1(typevar_constraint()), tok(';'), _1).
|
||||
|
||||
fundecl() ->
|
||||
choice([?RULE(id(), tok(':'), typevars_constraints(), type(),
|
||||
{fun_decl, get_ann(_1), _1, {constrained_t, get_ann(_1), _3, _4}}),
|
||||
?RULE(id(), tok(':'), type(), {fun_decl, get_ann(_1), _1, _3})]).
|
||||
|
||||
fundef_or_decl() ->
|
||||
choice([?RULE(id(), tok(':'), type(), {fun_decl, get_ann(_1), _1, _3}),
|
||||
fundef()]).
|
||||
choice([fundecl(), fundef()]).
|
||||
|
||||
using() ->
|
||||
Alias = {keyword(as), con()},
|
||||
@@ -333,19 +331,14 @@ expr100() ->
|
||||
|
||||
expr150() -> infixl(expr200(), binop('|>')).
|
||||
expr200() -> infixr(expr300(), binop('||')).
|
||||
expr300() -> infixr(expr325(), binop('&&')).
|
||||
expr325() -> infixl(expr350(), binop('bor')).
|
||||
expr350() -> infixl(expr375(), binop('bxor')).
|
||||
expr375() -> infixl(expr400(), binop('band')).
|
||||
expr300() -> infixr(expr400(), binop('&&')).
|
||||
expr400() -> infix(expr500(), binop(['<', '>', '=<', '>=', '==', '!='])).
|
||||
expr500() -> infixr(expr550(), binop(['::', '++'])).
|
||||
expr550() -> infixl(expr600(), binop(['<<', '>>'])).
|
||||
expr500() -> infixr(expr600(), binop(['::', '++'])).
|
||||
expr600() -> infixl(expr650(), binop(['+', '-'])).
|
||||
expr650() -> ?RULE(many(token('-')), expr700(), prefixes(_1, _2)).
|
||||
expr700() -> infixl(expr750(), binop(['*', '/', mod])).
|
||||
expr750() -> infixl(expr800(), binop(['^'])).
|
||||
expr800() -> ?RULE(many(token('!')), expr850(), prefixes(_1, _2)).
|
||||
expr850() -> ?RULE(many(token('bnot')), expr900(), prefixes(_1, _2)).
|
||||
expr800() -> ?RULE(many(token('!')), expr900(), prefixes(_1, _2)).
|
||||
expr900() -> ?RULE(exprAtom(), many(elim()), elim(_1, _2)).
|
||||
|
||||
exprAtom() ->
|
||||
@@ -544,6 +537,7 @@ parens(P) -> between(tok('('), P, tok(')')).
|
||||
braces(P) -> between(tok('{'), P, tok('}')).
|
||||
brackets(P) -> between(tok('['), P, tok(']')).
|
||||
comma_sep(P) -> sep(P, tok(',')).
|
||||
comma_sep1(P) -> sep1(P, tok(',')).
|
||||
|
||||
paren_list(P) -> parens(comma_sep(P)).
|
||||
brace_list(P) -> braces(comma_sep(P)).
|
||||
|
||||
+8
-21
@@ -151,16 +151,12 @@ decl(D, Options) ->
|
||||
with_options(Options, fun() -> decl(D) end).
|
||||
|
||||
-spec decl(aeso_syntax:decl()) -> doc().
|
||||
decl({Con, Attrs, C, Is, Ds}) when ?IS_CONTRACT_HEAD(Con) ->
|
||||
decl({Con, Attrs, C, Ds}) when ?IS_CONTRACT_HEAD(Con) ->
|
||||
Mod = fun({Mod, true}) when Mod == payable ->
|
||||
text(atom_to_list(Mod));
|
||||
(_) -> empty() end,
|
||||
ImplsList = case Is of
|
||||
[] -> [empty()];
|
||||
_ -> [text(":"), par(punctuate(text(","), lists:map(fun name/1, Is)), 0)]
|
||||
end,
|
||||
block(follow( hsep(lists:map(Mod, Attrs) ++ [contract_head(Con)])
|
||||
, hsep([name(C)] ++ ImplsList ++ [text("=")])), decls(Ds));
|
||||
, hsep(name(C), text("="))), decls(Ds));
|
||||
decl({namespace, _, C, Ds}) ->
|
||||
block(follow(text("namespace"), hsep(name(C), text("="))), decls(Ds));
|
||||
decl({pragma, _, Pragma}) -> pragma(Pragma);
|
||||
@@ -261,8 +257,6 @@ type(Type, Options) ->
|
||||
with_options(Options, fun() -> type(Type) end).
|
||||
|
||||
-spec type(aeso_syntax:type()) -> doc().
|
||||
type(F = {fun_t, _, _, var_args, _}) ->
|
||||
type(setelement(4, F, [var_args]));
|
||||
type({fun_t, _, Named, Args, Ret}) ->
|
||||
follow(hsep(args_type(Named ++ Args), text("=>")), type(Ret));
|
||||
type({type_sig, _, Named, Args, Ret}) ->
|
||||
@@ -291,8 +285,8 @@ type(T = {qid, _, _}) -> name(T);
|
||||
type(T = {con, _, _}) -> name(T);
|
||||
type(T = {qcon, _, _}) -> name(T);
|
||||
type(T = {tvar, _, _}) -> name(T);
|
||||
|
||||
type(var_args) -> text("var_args").
|
||||
type({constrained_t, _, Cs, T}) ->
|
||||
beside([name(T), text(" is "), tuple(lists:map(fun expr/1, Cs))]).
|
||||
|
||||
-spec args_type([aeso_syntax:type()]) -> doc().
|
||||
args_type(Args) ->
|
||||
@@ -434,22 +428,16 @@ lc_bind(Let) ->
|
||||
bin_prec('..') -> { 0, 0, 0}; %% Always printed inside '[ ]'
|
||||
bin_prec('=') -> { 0, 0, 0}; %% Always printed inside '[ ]'
|
||||
bin_prec('@') -> { 0, 0, 0}; %% Only in error messages
|
||||
bin_prec('|>') -> {150, 150, 200};
|
||||
bin_prec('||') -> {200, 300, 200};
|
||||
bin_prec('&&') -> {300, 325, 300};
|
||||
bin_prec('bor') -> {325, 350, 325};
|
||||
bin_prec('bxor') -> {350, 375, 350};
|
||||
bin_prec('band') -> {375, 400, 375};
|
||||
bin_prec('&&') -> {300, 400, 300};
|
||||
bin_prec('<') -> {400, 500, 500};
|
||||
bin_prec('>') -> {400, 500, 500};
|
||||
bin_prec('=<') -> {400, 500, 500};
|
||||
bin_prec('>=') -> {400, 500, 500};
|
||||
bin_prec('==') -> {400, 500, 500};
|
||||
bin_prec('!=') -> {400, 500, 500};
|
||||
bin_prec('++') -> {500, 550, 500};
|
||||
bin_prec('::') -> {500, 550, 500};
|
||||
bin_prec('<<') -> {550, 600, 550};
|
||||
bin_prec('>>') -> {550, 600, 550};
|
||||
bin_prec('++') -> {500, 600, 500};
|
||||
bin_prec('::') -> {500, 600, 500};
|
||||
bin_prec('+') -> {600, 600, 650};
|
||||
bin_prec('-') -> {600, 600, 650};
|
||||
bin_prec('*') -> {700, 700, 750};
|
||||
@@ -459,8 +447,7 @@ bin_prec('^') -> {750, 750, 800}.
|
||||
|
||||
-spec un_prec(aeso_syntax:un_op()) -> {integer(), integer()}.
|
||||
un_prec('-') -> {650, 650};
|
||||
un_prec('!') -> {800, 800};
|
||||
un_prec('bnot') -> {850, 850}.
|
||||
un_prec('!') -> {800, 800}.
|
||||
|
||||
equals(Ann, A, B) ->
|
||||
{app, [{format, infix} | Ann], {'=', Ann}, [A, B]}.
|
||||
|
||||
+1
-1
@@ -45,7 +45,7 @@ lexer() ->
|
||||
|
||||
Keywords = ["contract", "include", "let", "switch", "type", "record", "datatype", "if", "elif", "else", "function",
|
||||
"stateful", "payable", "true", "false", "mod", "public", "entrypoint", "private", "indexed", "namespace",
|
||||
"interface", "main", "using", "as", "for", "hiding", "band", "bor", "bxor", "bnot"
|
||||
"interface", "main", "using", "as", "for", "hiding", "is"
|
||||
],
|
||||
KW = string:join(Keywords, "|"),
|
||||
|
||||
|
||||
+10
-8
@@ -13,7 +13,7 @@
|
||||
-export_type([ann_line/0, ann_col/0, ann_origin/0, ann_format/0, ann/0]).
|
||||
-export_type([name/0, id/0, con/0, qid/0, qcon/0, tvar/0, op/0]).
|
||||
-export_type([bin_op/0, un_op/0]).
|
||||
-export_type([decl/0, letbind/0, typedef/0, pragma/0, fundecl/0]).
|
||||
-export_type([decl/0, letbind/0, typedef/0, pragma/0]).
|
||||
-export_type([arg/0, field_t/0, constructor_t/0, named_arg_t/0]).
|
||||
-export_type([type/0, constant/0, expr/0, arg_expr/0, field/1, stmt/0, alt/0, lvalue/0, elim/0, pat/0]).
|
||||
-export_type([ast/0]).
|
||||
@@ -26,7 +26,7 @@
|
||||
-type ann_format() :: '?:' | hex | infix | prefix | elif.
|
||||
|
||||
-type ann() :: [ {line, ann_line()} | {col, ann_col()} | {format, ann_format()} | {origin, ann_origin()}
|
||||
| stateful | private | payable | main | interface | entrypoint].
|
||||
| stateful | private | payable | main | interface].
|
||||
|
||||
-type name() :: string().
|
||||
-type id() :: {id, ann(), name()}.
|
||||
@@ -38,11 +38,10 @@
|
||||
-type namespace_alias() :: none | con().
|
||||
-type namespace_parts() :: none | {for, [id()]} | {hiding, [id()]}.
|
||||
|
||||
-type decl() :: {contract_main, ann(), con(), [con()], [decl()]}
|
||||
| {contract_child, ann(), con(), [con()], [decl()]}
|
||||
| {contract_interface, ann(), con(), [con()], [decl()]}
|
||||
-type decl() :: {contract_main, ann(), con(), [decl()]}
|
||||
| {contract_child, ann(), con(), [decl()]}
|
||||
| {contract_interface, ann(), con(), [decl()]}
|
||||
| {namespace, ann(), con(), [decl()]}
|
||||
| {include, ann(), {string, ann(), string()}}
|
||||
| {pragma, ann(), pragma()}
|
||||
| {type_decl, ann(), id(), [tvar()]} % Only for error msgs
|
||||
| {type_def, ann(), id(), [tvar()], typedef()}
|
||||
@@ -80,11 +79,14 @@
|
||||
|
||||
-type constructor_t() :: {constr_t, ann(), con(), [type()]}.
|
||||
|
||||
-type tvar_constraint() :: {constraint, ann(), tvar(), id()}.
|
||||
|
||||
-type type() :: {fun_t, ann(), [named_arg_t()], [type()], type()}
|
||||
| {app_t, ann(), type(), [type()]}
|
||||
| {tuple_t, ann(), [type()]}
|
||||
| {args_t, ann(), [type()]} %% old tuple syntax, old for error messages
|
||||
| {bytes_t, ann(), integer() | any}
|
||||
| {constrained_t, ann(), [tvar_constraint()], type()}
|
||||
| id() | qid()
|
||||
| con() | qcon() %% contracts
|
||||
| tvar().
|
||||
@@ -106,8 +108,8 @@
|
||||
|
||||
-type bin_op() :: '+' | '-' | '*' | '/' | mod | '^'
|
||||
| '++' | '::' | '<' | '>' | '=<' | '>=' | '==' | '!='
|
||||
| '||' | '&&' | '..' | 'band' | 'bor' | 'bxor' | '>>' | '<<' | '|>'.
|
||||
-type un_op() :: '-' | '!' | 'bnot'.
|
||||
| '||' | '&&' | '..'.
|
||||
-type un_op() :: '-' | '!'.
|
||||
|
||||
-type expr()
|
||||
:: {lam, ann(), [arg()], expr()}
|
||||
|
||||
@@ -61,6 +61,7 @@ fold(Alg = #alg{zero = Zero, plus = Plus, scoped = Scoped}, Fun, K, X) ->
|
||||
{fun_t, _, Named, Args, Ret} -> Type([Named, Args, Ret]);
|
||||
{app_t, _, T, Ts} -> Type([T | Ts]);
|
||||
{tuple_t, _, Ts} -> Type(Ts);
|
||||
{constrained_t, _, _, T} -> Type(T);
|
||||
%% named_arg_t()
|
||||
{named_arg_t, _, _, T, E} -> Plus(Type(T), Expr(E));
|
||||
%% expr()
|
||||
|
||||
@@ -99,21 +99,6 @@ from_fate_builtin(QType, Val) ->
|
||||
{["AENS", "pointee"], {variant, [1, 1, 1, 1], 3, {Addr}}} ->
|
||||
App(["AENS","ChannelPt"], [Chk(Adr, Addr)]);
|
||||
|
||||
{["AENSv2", "name"], {variant, [3], 0, {Addr, TTL, Ptrs}}} ->
|
||||
App(["AENSv2","Name"], [Chk(Adr, Addr), Chk(Qid(["Chain", "ttl"]), TTL),
|
||||
Chk(Map(Str, Qid(["AENSv2", "pointee"])), Ptrs)]);
|
||||
|
||||
{["AENSv2", "pointee"], {variant, [1, 1, 1, 1, 1], 0, {Val}}} ->
|
||||
App(["AENSv2","AccountPt"], [Chk(Adr, Val)]);
|
||||
{["AENSv2", "pointee"], {variant, [1, 1, 1, 1, 1], 1, {Val}}} ->
|
||||
App(["AENSv2","OraclePt"], [Chk(Adr, Val)]);
|
||||
{["AENSv2", "pointee"], {variant, [1, 1, 1, 1, 1], 2, {Val}}} ->
|
||||
App(["AENSv2","ContractPt"], [Chk(Adr, Val)]);
|
||||
{["AENSv2", "pointee"], {variant, [1, 1, 1, 1, 1], 3, {Val}}} ->
|
||||
App(["AENSv2","ChannelPt"], [Chk(Adr, Val)]);
|
||||
{["AENSv2", "pointee"], {variant, [1, 1, 1, 1, 1], 4, {Val}}} ->
|
||||
App(["AENSv2","DataPt"], [Chk(Str, Val)]);
|
||||
|
||||
{["Chain", "ga_meta_tx"], {variant, [2], 0, {Addr, X}}} ->
|
||||
App(["Chain","GAMetaTx"], [Chk(Adr, Addr), Chk(Int, X)]);
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{application, aesophia,
|
||||
[{description, "Compiler for Aeternity Sophia language"},
|
||||
{vsn, "8.0.0"},
|
||||
{vsn, "6.1.0"},
|
||||
{registered, []},
|
||||
{applications,
|
||||
[kernel,
|
||||
|
||||
@@ -21,7 +21,7 @@ test_cases(1) ->
|
||||
" payable stateful entrypoint a(i : int) = i+1\n">>,
|
||||
MapACI = #{contract =>
|
||||
#{name => <<"C">>,
|
||||
typedefs => [],
|
||||
type_defs => [],
|
||||
payable => true,
|
||||
kind => contract_main,
|
||||
functions =>
|
||||
@@ -43,7 +43,7 @@ test_cases(2) ->
|
||||
MapACI = #{contract =>
|
||||
#{name => <<"C">>, payable => false,
|
||||
kind => contract_main,
|
||||
typedefs =>
|
||||
type_defs =>
|
||||
[#{name => <<"allan">>,
|
||||
typedef => <<"int">>,
|
||||
vars => []}],
|
||||
@@ -76,7 +76,7 @@ test_cases(3) ->
|
||||
name => <<"C">>, payable => false, kind => contract_main,
|
||||
event => #{variant => [#{<<"SingleEventDefined">> => []}]},
|
||||
state => <<"unit">>,
|
||||
typedefs =>
|
||||
type_defs =>
|
||||
[#{name => <<"bert">>,
|
||||
typedef =>
|
||||
#{variant =>
|
||||
@@ -127,7 +127,7 @@ check_stub(Stub, Options) ->
|
||||
Ast ->
|
||||
try
|
||||
%% io:format("AST: ~120p\n", [Ast]),
|
||||
aeso_ast_infer_types:infer(Ast, [no_code])
|
||||
aeso_ast_infer_types:infer(Ast, [])
|
||||
catch throw:{type_errors, TE} ->
|
||||
io:format("Type error:\n~s\n", [TE]),
|
||||
error(TE);
|
||||
|
||||
@@ -29,7 +29,7 @@ calldata_aci_test_() ->
|
||||
[ {"Testing " ++ ContractName ++ " contract calling " ++ Fun,
|
||||
fun() ->
|
||||
ContractString = aeso_test_utils:read_contract(ContractName),
|
||||
{ok, ContractACIBin} = aeso_aci:contract_interface(string, ContractString, [no_code]),
|
||||
{ok, ContractACIBin} = aeso_aci:contract_interface(string, ContractString),
|
||||
ContractACI = binary_to_list(ContractACIBin),
|
||||
io:format("ACI:\n~s\n", [ContractACIBin]),
|
||||
FateExprs = ast_exprs(ContractACI, Fun, Args),
|
||||
@@ -39,7 +39,7 @@ calldata_aci_test_() ->
|
||||
end} || {ContractName, Fun, Args} <- compilable_contracts()].
|
||||
|
||||
parse_args(Fun, Args) ->
|
||||
[{contract_main, _, _, _, [{letfun, _, _, _, _, [{guarded, _, [], {app, _, _, AST}}]}]}] =
|
||||
[{contract_main, _, _, [{letfun, _, _, _, _, [{guarded, _, [], {app, _, _, AST}}]}]}] =
|
||||
aeso_parser:string("main contract Temp = function foo() = " ++ Fun ++ "(" ++ string:join(Args, ", ") ++ ")"),
|
||||
strip_ann(AST).
|
||||
|
||||
|
||||
+161
-340
@@ -45,6 +45,12 @@ simple_compile_test_() ->
|
||||
check_errors(ExpectedErrors, Errors)
|
||||
end} ||
|
||||
{ContractName, ExpectedErrors} <- failing_contracts() ] ++
|
||||
[ {"Testing code generation error messages of " ++ ContractName,
|
||||
fun() ->
|
||||
Errors = compile(ContractName),
|
||||
check_errors([ExpectedError], Errors)
|
||||
end} ||
|
||||
{ContractName, ExpectedError} <- failing_code_gen_contracts()] ++
|
||||
[ {"Testing include with explicit files",
|
||||
fun() ->
|
||||
FileSystem = maps:from_list(
|
||||
@@ -196,29 +202,6 @@ compilable_contracts() ->
|
||||
"assign_patterns",
|
||||
"patterns_guards",
|
||||
"pipe_operator",
|
||||
"polymorphism_contract_implements_interface",
|
||||
"polymorphism_contract_multi_interface",
|
||||
"polymorphism_contract_interface_extends_interface",
|
||||
"polymorphism_contract_interface_extensions",
|
||||
"polymorphism_contract_interface_same_decl_multi_interface",
|
||||
"polymorphism_contract_interface_same_name_same_type",
|
||||
"polymorphism_variance_switching_chain_create",
|
||||
"polymorphism_variance_switching_void_supertype",
|
||||
"polymorphism_variance_switching_unify_with_interface_decls",
|
||||
"missing_init_fun_state_unit",
|
||||
"complex_compare_leq",
|
||||
"complex_compare",
|
||||
"higher_order_compare",
|
||||
"higher_order_map_keys",
|
||||
"higher_order_state",
|
||||
"polymorphic_compare",
|
||||
"polymorphic_entrypoint",
|
||||
"polymorphic_entrypoint_return",
|
||||
"polymorphic_map_keys",
|
||||
"unapplied_contract_call",
|
||||
"unapplied_named_arg_builtin",
|
||||
"resolve_field_constraint_by_arity",
|
||||
"ceres",
|
||||
"test" % Custom general-purpose test file. Keep it last on the list.
|
||||
].
|
||||
|
||||
@@ -282,7 +265,9 @@ warnings() ->
|
||||
"The function `called_unused_function2` is defined but never used.">>,
|
||||
<<?PosW(48, 5)
|
||||
"Unused return value.">>,
|
||||
<<?PosW(60, 5)
|
||||
<<?PosW(53, 44)
|
||||
"The constraint on the type variable `'a` is a duplication of the constraint at line 53, column 34">>,
|
||||
<<?PosW(65, 5)
|
||||
"The function `dec` is defined but never used.">>
|
||||
]).
|
||||
|
||||
@@ -300,26 +285,34 @@ failing_contracts() ->
|
||||
|
||||
%% Type errors
|
||||
, ?TYPE_ERROR(name_clash,
|
||||
[<<?Pos(4, 3)
|
||||
"Duplicate definitions of `double_def` at\n"
|
||||
" - line 3, column 3\n"
|
||||
" - line 4, column 3">>,
|
||||
<<?Pos(7, 3)
|
||||
[<<?Pos(14, 3)
|
||||
"Duplicate definitions of `abort` at\n"
|
||||
" - (builtin location)\n"
|
||||
" - line 7, column 3">>,
|
||||
<<?Pos(8, 3)
|
||||
" - line 14, column 3">>,
|
||||
<<?Pos(15, 3)
|
||||
"Duplicate definitions of `require` at\n"
|
||||
" - (builtin location)\n"
|
||||
" - line 15, column 3">>,
|
||||
<<?Pos(11, 3)
|
||||
"Duplicate definitions of `double_def` at\n"
|
||||
" - line 10, column 3\n"
|
||||
" - line 11, column 3">>,
|
||||
<<?Pos(5, 3)
|
||||
"Duplicate definitions of `double_proto` at\n"
|
||||
" - line 4, column 3\n"
|
||||
" - line 5, column 3">>,
|
||||
<<?Pos(8, 3)
|
||||
"Duplicate definitions of `proto_and_def` at\n"
|
||||
" - line 7, column 3\n"
|
||||
" - line 8, column 3">>,
|
||||
<<?Pos(9, 3)
|
||||
<<?Pos(16, 3)
|
||||
"Duplicate definitions of `put` at\n"
|
||||
" - (builtin location)\n"
|
||||
" - line 9, column 3">>,
|
||||
<<?Pos(10, 3)
|
||||
" - line 16, column 3">>,
|
||||
<<?Pos(17, 3)
|
||||
"Duplicate definitions of `state` at\n"
|
||||
" - (builtin location)\n"
|
||||
" - line 10, column 3">>])
|
||||
" - line 17, column 3">>])
|
||||
, ?TYPE_ERROR(type_errors,
|
||||
[<<?Pos(17, 23)
|
||||
"Unbound variable `zz`">>,
|
||||
@@ -573,7 +566,7 @@ failing_contracts() ->
|
||||
])
|
||||
, ?TYPE_ERROR(list_comp_bad_shadow,
|
||||
[<<?Pos(2, 53)
|
||||
"Cannot unify `string` and `int`\n"
|
||||
"Cannot unify `int` and `string`\n"
|
||||
"when checking the type of the pattern `x : int` against the expected type `string`">>
|
||||
])
|
||||
, ?TYPE_ERROR(map_as_map_key,
|
||||
@@ -737,20 +730,8 @@ failing_contracts() ->
|
||||
[<<?Pos(10,18)
|
||||
"Chain.clone requires `ref` named argument of contract type.">>,
|
||||
<<?Pos(11,18)
|
||||
"Cannot unify `(gas : int, value : int, protected : bool) => if(protected, option(void), void)` and `(gas : int, value : int, protected : bool, int, bool) => if(protected, option(void), void)`\n"
|
||||
"when checking contract construction of type\n"
|
||||
" (gas : int, value : int, protected : bool) =>\n"
|
||||
" if(protected, option(void), void) (at line 11, column 18)\n"
|
||||
"against the expected type\n"
|
||||
" (gas : int, value : int, protected : bool, int, bool) =>\n"
|
||||
" if(protected, option(void), void)">>,
|
||||
<<?Pos(11,18)
|
||||
"Cannot unify `Bakoom` and `Kaboom`\n"
|
||||
"when checking that contract construction of type\n"
|
||||
" Bakoom\n"
|
||||
"arising from resolution of variadic function `Chain.clone`\n"
|
||||
"matches the expected type\n"
|
||||
" Kaboom">>,
|
||||
"Cannot unify `(gas : int, value : int, protected : bool) => if(protected, option(void), void)` and `(gas : int, value : int, protected : bool, int, bool) => 'b`\n"
|
||||
"when checking contract construction of type\n (gas : int, value : int, protected : bool) =>\n if(protected, option(void), void) (at line 11, column 18)\nagainst the expected type\n (gas : int, value : int, protected : bool, int, bool) => 'b">>,
|
||||
<<?Pos(12,37)
|
||||
"Cannot unify `int` and `bool`\n"
|
||||
"when checking named argument `gas : int` against inferred type `bool`">>,
|
||||
@@ -826,6 +807,88 @@ failing_contracts() ->
|
||||
"to arguments\n"
|
||||
" `1 : int`">>
|
||||
])
|
||||
, ?TYPE_ERROR(comparable_typevar_constraints,
|
||||
[<<?Pos(21,30)
|
||||
"Values of type `'a` are not comparable by equality">>,
|
||||
<<?Pos(25,38)
|
||||
"The type variable `'b` is constrained but never used">>,
|
||||
<<?Pos(29,41)
|
||||
"Unknown constraint `foo` used on the type variable `'a`">>,
|
||||
<<?Pos(63,58)
|
||||
"Values of type `Chain.ttl` are not comparable by inequality">>,
|
||||
<<?Pos(66,45)
|
||||
"Values of type `A` are not comparable by inequality">>,
|
||||
<<?Pos(73,47)
|
||||
"Values of type `(int, char) => bool` are not comparable by inequality">>,
|
||||
<<?Pos(74,47)
|
||||
"Values of type `(int, char) => bool` are not comparable by equality">>,
|
||||
<<?Pos(89,59)
|
||||
"Values of type `list(A)` are not comparable by inequality">>,
|
||||
<<?Pos(92,65)
|
||||
"Values of type `option(A)` are not comparable by inequality">>,
|
||||
<<?Pos(95,64)
|
||||
"Values of type `(A * int)` are not comparable by inequality">>,
|
||||
<<?Pos(96,64)
|
||||
"Values of type `(A * int)` are not comparable by equality">>,
|
||||
<<?Pos(100,68)
|
||||
"Values of type `list((int, char) => bool)` are not comparable by inequality">>,
|
||||
<<?Pos(101,68)
|
||||
"Values of type `list((int, char) => bool)` are not comparable by equality">>,
|
||||
<<?Pos(103,74)
|
||||
"Values of type `option((int, char) => bool)` are not comparable by inequality">>,
|
||||
<<?Pos(104,74)
|
||||
"Values of type `option((int, char) => bool)` are not comparable by equality">>,
|
||||
<<?Pos(106,73)
|
||||
"Values of type `((int, char) => bool * int)` are not comparable by inequality">>,
|
||||
<<?Pos(107,73)
|
||||
"Values of type `((int, char) => bool * int)` are not comparable by equality">>,
|
||||
<<?Pos(111,71)
|
||||
"Values of type `map(int, int)` are not comparable by inequality">>,
|
||||
<<?Pos(114,80)
|
||||
"Values of type `oracle(int, int)` are not comparable by inequality">>,
|
||||
<<?Pos(117,98)
|
||||
"Values of type `oracle_query(int, int)` are not comparable by inequality">>,
|
||||
<<?Pos(120,90)
|
||||
"Values of type `custom_datatype(int)` are not comparable by inequality">>,
|
||||
<<?Pos(123,84)
|
||||
"Values of type `custom_record(int)` are not comparable by inequality">>,
|
||||
<<?Pos(128,62)
|
||||
"Values of type `map(A, A)` are not comparable by inequality">>,
|
||||
<<?Pos(131,71)
|
||||
"Values of type `oracle(A, A)` are not comparable by inequality">>,
|
||||
<<?Pos(134,89)
|
||||
"Values of type `oracle_query(A, A)` are not comparable by inequality">>,
|
||||
<<?Pos(137,85)
|
||||
"Values of type `custom_datatype(A)` are not comparable by inequality">>,
|
||||
<<?Pos(140,79)
|
||||
"Values of type `custom_record(A)` are not comparable by inequality">>,
|
||||
<<?Pos(145,75)
|
||||
"Values of type `map((int, char) => bool, (int, char) => bool)` are not comparable by inequality">>,
|
||||
<<?Pos(146,75)
|
||||
"Values of type `map((int, char) => bool, (int, char) => bool)` are not comparable by equality">>,
|
||||
<<?Pos(148,84)
|
||||
"Values of type `oracle((int, char) => bool, (int, char) => bool)` are not comparable by inequality">>,
|
||||
<<?Pos(149,84)
|
||||
"Values of type `oracle((int, char) => bool, (int, char) => bool)` are not comparable by equality">>,
|
||||
<<?Pos(151,102)
|
||||
"Values of type `oracle_query((int, char) => bool, (int, char) => bool)` are not comparable by inequality">>,
|
||||
<<?Pos(152,102)
|
||||
"Values of type `oracle_query((int, char) => bool, (int, char) => bool)` are not comparable by equality">>,
|
||||
<<?Pos(154,94)
|
||||
"Values of type `custom_datatype((int, char) => bool)` are not comparable by inequality">>,
|
||||
<<?Pos(155,94)
|
||||
"Values of type `custom_datatype((int, char) => bool)` are not comparable by equality">>,
|
||||
<<?Pos(157,88)
|
||||
"Values of type `custom_record((int, char) => bool)` are not comparable by inequality">>,
|
||||
<<?Pos(158,88)
|
||||
"Values of type `custom_record((int, char) => bool)` are not comparable by equality">>,
|
||||
<<?Pos(162,35)
|
||||
"Values of type `map(int, int)` are not comparable by inequality">>,
|
||||
<<?Pos(163,35)
|
||||
"Values of type `('a) => 'a` are not comparable by inequality">>,
|
||||
<<?Pos(167,34)
|
||||
"Values of type `('b) => 'b` are not comparable by equality">>
|
||||
])
|
||||
, ?TYPE_ERROR(warnings,
|
||||
[<<?Pos(0, 0)
|
||||
"The file `Triple.aes` is included but not used.">>,
|
||||
@@ -855,304 +918,62 @@ failing_contracts() ->
|
||||
"The function `called_unused_function2` is defined but never used.">>,
|
||||
<<?Pos(48, 5)
|
||||
"Unused return value.">>,
|
||||
<<?Pos(60, 5)
|
||||
<<?Pos(53, 44)
|
||||
"The constraint on the type variable `'a` is a duplication of the constraint at line 53, column 34">>,
|
||||
<<?Pos(65, 5)
|
||||
"The function `dec` is defined but never used.">>
|
||||
])
|
||||
, ?TYPE_ERROR(polymorphism_contract_interface_recursive,
|
||||
[<<?Pos(1,24)
|
||||
"Trying to implement or extend an undefined interface `Z`">>
|
||||
])
|
||||
, ?TYPE_ERROR(polymorphism_contract_interface_same_name_different_type,
|
||||
[<<?Pos(9,5)
|
||||
"Duplicate definitions of `f` at\n"
|
||||
" - line 8, column 5\n"
|
||||
" - line 9, column 5">>])
|
||||
, ?TYPE_ERROR(polymorphism_contract_missing_implementation,
|
||||
[<<?Pos(4,20)
|
||||
"Unimplemented function `f` from the interface `I1` in the contract `I2`">>
|
||||
])
|
||||
, ?TYPE_ERROR(polymorphism_contract_same_decl_multi_interface,
|
||||
[<<?Pos(7,10)
|
||||
"Both interfaces `I` and `J` implemented by the contract `C` have a function called `f`">>
|
||||
])
|
||||
, ?TYPE_ERROR(polymorphism_contract_undefined_interface,
|
||||
[<<?Pos(1,14)
|
||||
"Trying to implement or extend an undefined interface `I`">>
|
||||
])
|
||||
, ?TYPE_ERROR(polymorphism_contract_same_name_different_type_multi_interface,
|
||||
[<<?Pos(7,10)
|
||||
"Both interfaces `I` and `J` implemented by the contract `C` have a function called `f`">>
|
||||
])
|
||||
, ?TYPE_ERROR(polymorphism_contract_interface_undefined_interface,
|
||||
[<<?Pos(1,24)
|
||||
"Trying to implement or extend an undefined interface `H`">>
|
||||
])
|
||||
, ?TYPE_ERROR(polymorphism_variance_switching,
|
||||
[<<?Pos(36,49)
|
||||
"Cannot unify `Cat` and `Animal` in a contravariant context\n"
|
||||
"when checking the application of\n"
|
||||
" `g2 : (Cat) => Cat`\n"
|
||||
"to arguments\n"
|
||||
" `x : Animal`">>,
|
||||
<<?Pos(39,43)
|
||||
"Cannot unify `Animal` and `Cat` in a covariant context\n"
|
||||
"when checking the type of the expression `g3(x) : Animal` against the expected type `Cat`">>,
|
||||
<<?Pos(48,55)
|
||||
"Cannot unify `Animal` and `Cat` in a covariant context\n"
|
||||
"when checking the application of\n"
|
||||
" `g5 : ((Animal) => Animal) => Cat`\n"
|
||||
"to arguments\n"
|
||||
" `x : (Cat) => Cat`">>,
|
||||
<<?Pos(52,44)
|
||||
"Cannot unify `Animal` and `Cat` in a covariant context\n"
|
||||
"when checking the type of the expression `f6() : option(Animal)` against the expected type `option(Cat)`">>,
|
||||
<<?Pos(73,43)
|
||||
"Cannot unify `Animal` and `Cat` in a covariant context\n"
|
||||
"when checking the type of the expression `some_animal : Animal` against the expected type `Cat`">>
|
||||
])
|
||||
, ?TYPE_ERROR(polymorphism_variance_switching_custom_types,
|
||||
[<<?Pos(56,39)
|
||||
"Cannot unify `Cat` and `Animal` in a contravariant context\n"
|
||||
"when checking the type of the expression `DT_CONTRA(f_c_to_u) : dt_contra(Cat)` against the expected type `dt_contra(Animal)`">>,
|
||||
<<?Pos(62,35)
|
||||
"Cannot unify `Animal` and `Cat` in a covariant context\n"
|
||||
"when checking the type of the expression `DT_CO(f_u_to_a) : dt_co(Animal)` against the expected type `dt_co(Cat)`">>,
|
||||
<<?Pos(67,36)
|
||||
"Cannot unify `Cat` and `Animal` in a contravariant context\n"
|
||||
"when checking the application of\n `DT_INV : ((Cat) => Cat) => dt_inv(Cat)`\nto arguments\n `f_c_to_a : (Cat) => Animal`">>,
|
||||
<<?Pos(68,36)
|
||||
"Cannot unify `Cat` and `Animal` in a invariant context\n"
|
||||
"when checking the type of the expression `DT_INV(f_c_to_c) : dt_inv(Cat)` against the expected type `dt_inv(Animal)`">>,
|
||||
<<?Pos(69,36)
|
||||
"Cannot unify `Animal` and `Cat` in a invariant context\n"
|
||||
"when checking the type of the expression `DT_INV(f_a_to_a) : dt_inv(Animal)` against the expected type `dt_inv(Cat)`">>,
|
||||
<<?Pos(70,36)
|
||||
"Cannot unify `Animal` and `Cat` in a invariant context\n"
|
||||
"when checking the type of the expression `DT_INV(f_a_to_c) : dt_inv(Animal)` against the expected type `dt_inv(Cat)`">>,
|
||||
<<?Pos(71,36)
|
||||
"Cannot unify `Cat` and `Animal` in a contravariant context\n"
|
||||
"when checking the application of\n `DT_INV : ((Cat) => Cat) => dt_inv(Cat)`\nto arguments\n `f_c_to_a : (Cat) => Animal`">>,
|
||||
<<?Pos(80,40)
|
||||
"Cannot unify `Cat` and `Animal` in a invariant context\n"
|
||||
"when checking the type of the expression `DT_INV_SEP_A(f_c_to_u) : dt_inv_sep(Cat)` against the expected type `dt_inv_sep(Animal)`">>,
|
||||
<<?Pos(82,40)
|
||||
"Cannot unify `Cat` and `Animal` in a invariant context\n"
|
||||
"when checking the type of the expression `DT_INV_SEP_B(f_u_to_c) : dt_inv_sep(Cat)` against the expected type `dt_inv_sep(Animal)`">>,
|
||||
<<?Pos(83,40)
|
||||
"Cannot unify `Animal` and `Cat` in a invariant context\n"
|
||||
"when checking the type of the expression `DT_INV_SEP_A(f_a_to_u) : dt_inv_sep(Animal)` against the expected type `dt_inv_sep(Cat)`">>,
|
||||
<<?Pos(85,40)
|
||||
"Cannot unify `Animal` and `Cat` in a invariant context\n"
|
||||
"when checking the type of the expression `DT_INV_SEP_B(f_u_to_a) : dt_inv_sep(Animal)` against the expected type `dt_inv_sep(Cat)`">>,
|
||||
<<?Pos(90,42)
|
||||
"Cannot unify `Animal` and `Cat` in a covariant context\n"
|
||||
"when checking the type of the expression `DT_CO_NEST_A(f_dt_contra_a_to_u) : dt_co_nest_a(Animal)` against the expected type `dt_co_nest_a(Cat)`">>,
|
||||
<<?Pos(94,46)
|
||||
"Cannot unify `Cat` and `Animal` in a contravariant context\n"
|
||||
"when checking the type of the expression `DT_CONTRA_NEST_A(f_dt_co_c_to_u) : dt_contra_nest_a(Cat)` against the expected type `dt_contra_nest_a(Animal)`">>,
|
||||
<<?Pos(99,46)
|
||||
"Cannot unify `Cat` and `Animal` in a contravariant context\n"
|
||||
"when checking the type of the expression `DT_CONTRA_NEST_B(f_u_to_dt_contra_c) : dt_contra_nest_b(Cat)` against the expected type `dt_contra_nest_b(Animal)`">>,
|
||||
<<?Pos(105,42)
|
||||
"Cannot unify `Animal` and `Cat` in a covariant context\n"
|
||||
"when checking the type of the expression `DT_CO_NEST_B(f_u_to_dt_co_a) : dt_co_nest_b(Animal)` against the expected type `dt_co_nest_b(Cat)`">>,
|
||||
<<?Pos(110,13)
|
||||
"Cannot unify `Animal` and `Cat` in a covariant context\n"
|
||||
"when checking the type of the pattern `vj3 : dt_co_twice(Cat)` against the expected type `dt_co_twice(Animal)`">>,
|
||||
<<?Pos(114,59)
|
||||
"Cannot unify `Cat` and `Animal` in a contravariant context\n"
|
||||
"when checking the type of the expression `DT_A_CONTRA_B_CONTRA(f_a_to_c_to_u) : dt_a_contra_b_contra(Animal, Cat)` against the expected type `dt_a_contra_b_contra(Animal, Animal)`">>,
|
||||
<<?Pos(115,59)
|
||||
"Cannot unify `Cat` and `Animal` in a contravariant context\n"
|
||||
"when checking the type of the expression `DT_A_CONTRA_B_CONTRA(f_c_to_a_to_u) : dt_a_contra_b_contra(Cat, Animal)` against the expected type `dt_a_contra_b_contra(Animal, Animal)`">>,
|
||||
<<?Pos(116,59)
|
||||
"Cannot unify `Cat` and `Animal` in a contravariant context\n"
|
||||
"when checking the type of the expression `DT_A_CONTRA_B_CONTRA(f_c_to_c_to_u) : dt_a_contra_b_contra(Cat, Cat)` against the expected type `dt_a_contra_b_contra(Animal, Animal)`">>,
|
||||
<<?Pos(119,59)
|
||||
"Cannot unify `Cat` and `Animal` in a contravariant context\n"
|
||||
"when checking the type of the expression `DT_A_CONTRA_B_CONTRA(f_c_to_a_to_u) : dt_a_contra_b_contra(Cat, Animal)` against the expected type `dt_a_contra_b_contra(Animal, Cat)`">>,
|
||||
<<?Pos(120,59)
|
||||
"Cannot unify `Cat` and `Animal` in a contravariant context\n"
|
||||
"when checking the type of the expression `DT_A_CONTRA_B_CONTRA(f_c_to_c_to_u) : dt_a_contra_b_contra(Cat, Cat)` against the expected type `dt_a_contra_b_contra(Animal, Cat)`">>,
|
||||
<<?Pos(122,59)
|
||||
"Cannot unify `Cat` and `Animal` in a contravariant context\n"
|
||||
"when checking the type of the expression `DT_A_CONTRA_B_CONTRA(f_a_to_c_to_u) : dt_a_contra_b_contra(Animal, Cat)` against the expected type `dt_a_contra_b_contra(Cat, Animal)`">>,
|
||||
<<?Pos(124,59)
|
||||
"Cannot unify `Cat` and `Animal` in a contravariant context\n"
|
||||
"when checking the type of the expression `DT_A_CONTRA_B_CONTRA(f_c_to_c_to_u) : dt_a_contra_b_contra(Cat, Cat)` against the expected type `dt_a_contra_b_contra(Cat, Animal)`">>,
|
||||
<<?Pos(131,13)
|
||||
"Cannot unify `Cat` and `Animal` in a contravariant context\n"
|
||||
"when checking the type of the pattern `vl2 : dt_contra_twice(Animal)` against the expected type `dt_contra_twice(Cat)`">>
|
||||
])
|
||||
, ?TYPE_ERROR(polymorphism_variance_switching_records,
|
||||
[<<?Pos(27,13)
|
||||
"Cannot unify `Animal` and `Cat` in a covariant context\n"
|
||||
"when checking the type of the pattern `r03 : rec_co(Cat)` against the expected type `Main.rec_co(Animal)`">>,
|
||||
<<?Pos(33,13)
|
||||
"Cannot unify `Cat` and `Animal` in a contravariant context\n"
|
||||
"when checking the type of the pattern `r06 : rec_contra(Animal)` against the expected type `Main.rec_contra(Cat)`">>,
|
||||
<<?Pos(40,13)
|
||||
"Cannot unify `Cat` and `Animal` in a invariant context\n"
|
||||
"when checking the type of the pattern `r10 : rec_inv(Animal)` against the expected type `Main.rec_inv(Cat)`">>,
|
||||
<<?Pos(41,13)
|
||||
"Cannot unify `Animal` and `Cat` in a invariant context\n"
|
||||
"when checking the type of the pattern `r11 : rec_inv(Cat)` against the expected type `Main.rec_inv(Animal)`">>
|
||||
])
|
||||
, ?TYPE_ERROR(polymorphism_variance_switching_oracles,
|
||||
[<<?Pos(15,13)
|
||||
"Cannot unify `Cat` and `Animal` in a contravariant context\n"
|
||||
"when checking the type of the pattern `o03 : oracle(Animal, Animal)` against the expected type `oracle(Cat, Animal)`">>,
|
||||
<<?Pos(16,13)
|
||||
"Cannot unify `Cat` and `Animal` in a contravariant context\n"
|
||||
"when checking the type of the pattern `o04 : oracle(Animal, Animal)` against the expected type `oracle(Cat, Cat)`">>,
|
||||
<<?Pos(17,13)
|
||||
"Cannot unify `Animal` and `Cat` in a covariant context\n"
|
||||
"when checking the type of the pattern `o05 : oracle(Animal, Cat)` against the expected type `oracle(Animal, Animal)`">>,
|
||||
<<?Pos(19,13)
|
||||
"Cannot unify `Cat` and `Animal` in a contravariant context\n"
|
||||
"when checking the type of the pattern `o07 : oracle(Animal, Cat)` against the expected type `oracle(Cat, Animal)`">>,
|
||||
<<?Pos(20,13)
|
||||
"Cannot unify `Cat` and `Animal` in a contravariant context\n"
|
||||
"when checking the type of the pattern `o08 : oracle(Animal, Cat)` against the expected type `oracle(Cat, Cat)`">>,
|
||||
<<?Pos(25,13)
|
||||
"Cannot unify `Animal` and `Cat` in a covariant context\n"
|
||||
"when checking the type of the pattern `o13 : oracle(Cat, Cat)` against the expected type `oracle(Animal, Animal)`">>,
|
||||
<<?Pos(27,13)
|
||||
"Cannot unify `Animal` and `Cat` in a covariant context\n"
|
||||
"when checking the type of the pattern `o15 : oracle(Cat, Cat)` against the expected type `oracle(Cat, Animal)`">>,
|
||||
<<?Pos(34,13)
|
||||
"Cannot unify `Animal` and `Cat` in a covariant context\n"
|
||||
"when checking the type of the pattern `q05 : oracle_query(Animal, Cat)` against the expected type `oracle_query(Animal, Animal)`">>,
|
||||
<<?Pos(36,13)
|
||||
"Cannot unify `Animal` and `Cat` in a covariant context\n"
|
||||
"when checking the type of the pattern `q07 : oracle_query(Animal, Cat)` against the expected type `oracle_query(Cat, Animal)`">>,
|
||||
<<?Pos(38,13)
|
||||
"Cannot unify `Animal` and `Cat` in a covariant context\n"
|
||||
"when checking the type of the pattern `q09 : oracle_query(Cat, Animal)` against the expected type `oracle_query(Animal, Animal)`">>,
|
||||
<<?Pos(39,13)
|
||||
"Cannot unify `Animal` and `Cat` in a covariant context\n"
|
||||
"when checking the type of the pattern `q10 : oracle_query(Cat, Animal)` against the expected type `oracle_query(Animal, Cat)`">>,
|
||||
<<?Pos(42,13)
|
||||
"Cannot unify `Animal` and `Cat` in a covariant context\n"
|
||||
"when checking the type of the pattern `q13 : oracle_query(Cat, Cat)` against the expected type `oracle_query(Animal, Animal)`">>,
|
||||
<<?Pos(43,13)
|
||||
"Cannot unify `Animal` and `Cat` in a covariant context\n"
|
||||
"when checking the type of the pattern `q14 : oracle_query(Cat, Cat)` against the expected type `oracle_query(Animal, Cat)`">>,
|
||||
<<?Pos(44,13)
|
||||
"Cannot unify `Animal` and `Cat` in a covariant context\n"
|
||||
"when checking the type of the pattern `q15 : oracle_query(Cat, Cat)` against the expected type `oracle_query(Cat, Animal)`">>
|
||||
])
|
||||
, ?TYPE_ERROR(polymorphism_variance_switching_chain_create_fail,
|
||||
[<<?Pos(9,22)
|
||||
"I is not implemented.\n"
|
||||
"when resolving arguments of variadic function `Chain.create`">>,
|
||||
<<?Pos(10,13)
|
||||
"Cannot unify `I` and `C` in a covariant context\n"
|
||||
"when checking the type of the pattern `c2 : C` against the expected type `I`">>,
|
||||
<<?Pos(10,22)
|
||||
"I is not implemented.\n"
|
||||
"when resolving arguments of variadic function `Chain.create`">>,
|
||||
<<?Pos(11,22)
|
||||
"I is not implemented.\n"
|
||||
"when resolving arguments of variadic function `Chain.create`">>
|
||||
])
|
||||
, ?TYPE_ERROR(missing_definition,
|
||||
[<<?Pos(2,14)
|
||||
"Missing definition of function `foo`">>
|
||||
])
|
||||
, ?TYPE_ERROR(child_with_decls,
|
||||
[<<?Pos(2,14)
|
||||
"Missing definition of function `f`">>
|
||||
])
|
||||
, ?TYPE_ERROR(parameterised_state,
|
||||
[<<?Pos(3,8)
|
||||
"The state type cannot be parameterized">>
|
||||
])
|
||||
, ?TYPE_ERROR(parameterised_event,
|
||||
[<<?Pos(3,12)
|
||||
"The event type cannot be parameterized">>
|
||||
])
|
||||
, ?TYPE_ERROR(missing_init_fun_alias_to_type,
|
||||
[<<?Pos(1,10)
|
||||
"Missing `init` function for the contract `AliasToType`.\n"
|
||||
"The `init` function can only be omitted if the state type is `unit`">>
|
||||
])
|
||||
, ?TYPE_ERROR(missing_init_fun_alias_to_alias_to_type,
|
||||
[<<?Pos(1,10)
|
||||
"Missing `init` function for the contract `AliasToAliasToType`.\n"
|
||||
"The `init` function can only be omitted if the state type is `unit`">>
|
||||
])
|
||||
, ?TYPE_ERROR(higher_order_entrypoint,
|
||||
[<<?Pos(2,20)
|
||||
].
|
||||
|
||||
-define(Path(File), "code_errors/" ??File).
|
||||
-define(Msg(File, Line, Col, Err), <<?Pos("Code generation", ?Path(File), Line, Col) Err>>).
|
||||
|
||||
-define(FATE_ERR(File, Line, Col, Err), {?Path(File), ?Msg(File, Line, Col, Err)}).
|
||||
|
||||
failing_code_gen_contracts() ->
|
||||
[ ?FATE_ERR(missing_definition, 2, 14,
|
||||
"Missing definition of function 'foo'.")
|
||||
, ?FATE_ERR(higher_order_entrypoint, 2, 20,
|
||||
"The argument\n"
|
||||
" `f : (int) => int`\n"
|
||||
"of entrypoint `apply` has a higher-order (contains function types) type">>
|
||||
])
|
||||
, ?TYPE_ERROR(higher_order_entrypoint_return,
|
||||
[<<?Pos(2,3)
|
||||
" f : (int) => int\n"
|
||||
"of entrypoint 'apply' has a higher-order (contains function types) type.")
|
||||
, ?FATE_ERR(higher_order_entrypoint_return, 2, 3,
|
||||
"The return type\n"
|
||||
" `(int) => int`\n"
|
||||
"of entrypoint `add` is higher-order (contains function types)">>
|
||||
])
|
||||
, ?TYPE_ERROR(polymorphic_aens_resolve,
|
||||
[<<?Pos(4,5)
|
||||
"Invalid return type of `AENSv2.resolve`:\n"
|
||||
" `'a`\n"
|
||||
"It must be a `string` or a pubkey type (`address`, `oracle`, etc)">>
|
||||
])
|
||||
, ?TYPE_ERROR(bad_aens_resolve,
|
||||
[<<?Pos(6,5)
|
||||
"Invalid return type of `AENSv2.resolve`:\n"
|
||||
" `list(int)`\n"
|
||||
"It must be a `string` or a pubkey type (`address`, `oracle`, etc)">>
|
||||
])
|
||||
, ?TYPE_ERROR(bad_aens_resolve_using,
|
||||
[<<?Pos(7,5)
|
||||
"Invalid return type of `AENSv2.resolve`:\n"
|
||||
" `list(int)`\n"
|
||||
"It must be a `string` or a pubkey type (`address`, `oracle`, etc)">>
|
||||
])
|
||||
, ?TYPE_ERROR(polymorphic_query_type,
|
||||
[<<?Pos(3,5)
|
||||
" (int) => int\n"
|
||||
"of entrypoint 'add' is higher-order (contains function types).")
|
||||
, ?FATE_ERR(missing_init_function, 1, 10,
|
||||
"Missing init function for the contract 'MissingInitFunction'.\n"
|
||||
"The 'init' function can only be omitted if the state type is 'unit'.")
|
||||
, ?FATE_ERR(parameterised_state, 3, 8,
|
||||
"The state type cannot be parameterized.")
|
||||
, ?FATE_ERR(parameterised_event, 3, 12,
|
||||
"The event type cannot be parameterized.")
|
||||
, ?FATE_ERR(polymorphic_aens_resolve, 4, 5,
|
||||
"Invalid return type of AENS.resolve:\n"
|
||||
" 'a\n"
|
||||
"It must be a string or a pubkey type (address, oracle, etc).")
|
||||
, ?FATE_ERR(bad_aens_resolve, 6, 5,
|
||||
"Invalid return type of AENS.resolve:\n"
|
||||
" list(int)\n"
|
||||
"It must be a string or a pubkey type (address, oracle, etc).")
|
||||
, ?FATE_ERR(polymorphic_query_type, 3, 5,
|
||||
"Invalid oracle type\n"
|
||||
" `oracle('a, 'b)`\n"
|
||||
"The query type must not be polymorphic (contain type variables)">>,
|
||||
<<?Pos(3,5)
|
||||
" oracle('a, 'b)\n"
|
||||
"The query type must not be polymorphic (contain type variables).")
|
||||
, ?FATE_ERR(polymorphic_response_type, 3, 5,
|
||||
"Invalid oracle type\n"
|
||||
" `oracle('a, 'b)`\n"
|
||||
"The response type must not be polymorphic (contain type variables)">>
|
||||
])
|
||||
, ?TYPE_ERROR(polymorphic_response_type,
|
||||
[<<?Pos(3,5)
|
||||
" oracle(string, 'r)\n"
|
||||
"The response type must not be polymorphic (contain type variables).")
|
||||
, ?FATE_ERR(higher_order_query_type, 3, 5,
|
||||
"Invalid oracle type\n"
|
||||
" `oracle(string, 'r)`\n"
|
||||
"The response type must not be polymorphic (contain type variables)">>
|
||||
])
|
||||
, ?TYPE_ERROR(higher_order_query_type,
|
||||
[<<?Pos(3,5)
|
||||
" oracle((int) => int, string)\n"
|
||||
"The query type must not be higher-order (contain function types).")
|
||||
, ?FATE_ERR(higher_order_response_type, 3, 5,
|
||||
"Invalid oracle type\n"
|
||||
" `oracle((int) => int, string)`\n"
|
||||
"The query type must not be higher-order (contain function types)">>
|
||||
])
|
||||
, ?TYPE_ERROR(higher_order_response_type,
|
||||
[<<?Pos(3,5)
|
||||
"Invalid oracle type\n"
|
||||
" `oracle(string, (int) => int)`\n"
|
||||
"The response type must not be higher-order (contain function types)">>
|
||||
])
|
||||
, ?TYPE_ERROR(var_args_unify_let,
|
||||
[<<?Pos(3,9)
|
||||
"Cannot infer types for variable argument list.\n"
|
||||
"when checking the type of the pattern `x : 'a` against the expected type `(gas : int, value : int, protected : bool, ref : 'b, var_args) => 'b`">>
|
||||
])
|
||||
, ?TYPE_ERROR(var_args_unify_fun_call,
|
||||
[<<?Pos(6,5)
|
||||
"Cannot infer types for variable argument list.\n"
|
||||
"when checking the application of\n"
|
||||
" `g : (() => 'b) => 'b`\n"
|
||||
"to arguments\n"
|
||||
" `Chain.create : (value : int, var_args) => 'c`">>
|
||||
])
|
||||
" oracle(string, (int) => int)\n"
|
||||
"The response type must not be higher-order (contain function types).")
|
||||
, ?FATE_ERR(child_with_decls, 2, 14,
|
||||
"Missing definition of function 'f'.")
|
||||
].
|
||||
|
||||
validation_test_() ->
|
||||
|
||||
@@ -15,7 +15,7 @@ simple_contracts_test_() ->
|
||||
Text = "main contract Identity =\n"
|
||||
" function id(x) = x\n",
|
||||
?assertMatch(
|
||||
[{contract_main, _, {con, _, "Identity"}, _,
|
||||
[{contract_main, _, {con, _, "Identity"},
|
||||
[{letfun, _, {id, _, "id"}, [{id, _, "x"}], {id, _, "_"},
|
||||
[{guarded, _, [], {id, _, "x"}}]}]}], parse_string(Text)),
|
||||
ok
|
||||
@@ -53,7 +53,7 @@ simple_contracts_test_() ->
|
||||
%% associativity
|
||||
[ RightAssoc(Op) || Op <- ["||", "&&", "::", "++"] ],
|
||||
[ NonAssoc(Op) || Op <- ["==", "!=", "<", ">", "=<", ">="] ],
|
||||
[ LeftAssoc(Op) || Op <- ["+", "-", "*", "/", "mod", "band", "bor", "bxor", "<<", ">>"] ],
|
||||
[ LeftAssoc(Op) || Op <- ["+", "-", "*", "/", "mod"] ],
|
||||
|
||||
%% precedence
|
||||
[ Stronger(Op2, Op1) || [T1 , T2 | _] <- tails(Tiers), Op1 <- T1, Op2 <- T2 ],
|
||||
|
||||
@@ -39,8 +39,7 @@ all_tokens() ->
|
||||
%% Symbols
|
||||
lists:map(Lit, [',', '.', ';', '|', ':', '(', ')', '[', ']', '{', '}']) ++
|
||||
%% Operators
|
||||
lists:map(Lit, ['=', '==', '!=', '>', '<', '>=', '=<', '-', '+', '++', '*', '/', mod,
|
||||
':', '::', '->', '=>', '||', '&&', '!', 'band', 'bor', 'bxor', 'bnot' ,'<<', '>>']) ++
|
||||
lists:map(Lit, ['=', '==', '!=', '>', '<', '>=', '=<', '-', '+', '++', '*', '/', mod, ':', '::', '->', '=>', '||', '&&', '!']) ++
|
||||
%% Keywords
|
||||
lists:map(Lit, [contract, type, 'let', switch]) ++
|
||||
%% Comment token (not an actual token), just for tests
|
||||
|
||||
+15
-26
@@ -1,82 +1,71 @@
|
||||
contract C = entrypoint init() = ()
|
||||
|
||||
// AENS tests
|
||||
main contract AENSTest =
|
||||
contract AENSTest =
|
||||
|
||||
// Name resolution
|
||||
|
||||
stateful entrypoint resolve_word(name : string, key : string) : option(address) =
|
||||
AENSv2.resolve(name, key)
|
||||
AENS.resolve(name, key)
|
||||
|
||||
stateful entrypoint resolve_string(name : string, key : string) : option(string) =
|
||||
AENSv2.resolve(name, key)
|
||||
|
||||
stateful entrypoint resolve_contract(name : string, key : string) : option(C) =
|
||||
AENSv2.resolve(name, key)
|
||||
|
||||
stateful entrypoint resolve_oracle(name : string, key : string) : option(oracle(int, int)) =
|
||||
AENSv2.resolve(name, key)
|
||||
|
||||
stateful entrypoint resolve_oracle_query(name : string, key : string) : option(oracle_query(int, int)) =
|
||||
AENSv2.resolve(name, key)
|
||||
AENS.resolve(name, key)
|
||||
|
||||
// Transactions
|
||||
|
||||
stateful entrypoint preclaim(addr : address, // Claim on behalf of this account (can be Contract.address)
|
||||
chash : hash) : unit = // Commitment hash
|
||||
AENSv2.preclaim(addr, chash)
|
||||
AENS.preclaim(addr, chash)
|
||||
|
||||
stateful entrypoint signedPreclaim(addr : address, // Claim on behalf of this account (can be Contract.address)
|
||||
chash : hash, // Commitment hash
|
||||
sign : signature) : unit = // Signed by addr (if not Contract.address)
|
||||
AENSv2.preclaim(addr, chash, signature = sign)
|
||||
AENS.preclaim(addr, chash, signature = sign)
|
||||
|
||||
stateful entrypoint claim(addr : address,
|
||||
name : string,
|
||||
salt : int,
|
||||
name_fee : int) : unit =
|
||||
AENSv2.claim(addr, name, salt, name_fee)
|
||||
AENS.claim(addr, name, salt, name_fee)
|
||||
|
||||
stateful entrypoint signedClaim(addr : address,
|
||||
name : string,
|
||||
salt : int,
|
||||
name_fee : int,
|
||||
sign : signature) : unit =
|
||||
AENSv2.claim(addr, name, salt, name_fee, signature = sign)
|
||||
AENS.claim(addr, name, salt, name_fee, signature = sign)
|
||||
|
||||
|
||||
stateful entrypoint update(owner : address,
|
||||
name : string,
|
||||
ttl : option(Chain.ttl),
|
||||
client_ttl : option(int),
|
||||
pointers : option(map(string, AENSv2.pointee))) : unit =
|
||||
AENSv2.update(owner, name, ttl, client_ttl, pointers)
|
||||
pointers : option(map(string, AENS.pointee))) : unit =
|
||||
AENS.update(owner, name, ttl, client_ttl, pointers)
|
||||
|
||||
stateful entrypoint signedUpdate(owner : address,
|
||||
name : string,
|
||||
ttl : option(Chain.ttl),
|
||||
client_ttl : option(int),
|
||||
pointers : option(map(string, AENSv2.pointee)),
|
||||
pointers : option(map(string, AENS.pointee)),
|
||||
sign : signature) : unit =
|
||||
AENSv2.update(owner, name, ttl, client_ttl, pointers, signature = sign)
|
||||
AENS.update(owner, name, ttl, client_ttl, pointers, signature = sign)
|
||||
|
||||
|
||||
stateful entrypoint transfer(owner : address,
|
||||
new_owner : address,
|
||||
name : string) : unit =
|
||||
AENSv2.transfer(owner, new_owner, name)
|
||||
AENS.transfer(owner, new_owner, name)
|
||||
|
||||
stateful entrypoint signedTransfer(owner : address,
|
||||
new_owner : address,
|
||||
name : string,
|
||||
sign : signature) : unit =
|
||||
AENSv2.transfer(owner, new_owner, name, signature = sign)
|
||||
AENS.transfer(owner, new_owner, name, signature = sign)
|
||||
|
||||
stateful entrypoint revoke(owner : address,
|
||||
name : string) : unit =
|
||||
AENSv2.revoke(owner, name)
|
||||
AENS.revoke(owner, name)
|
||||
|
||||
stateful entrypoint signedRevoke(owner : address,
|
||||
name : string,
|
||||
sign : signature) : unit =
|
||||
AENSv2.revoke(owner, name, signature = sign)
|
||||
AENS.revoke(owner, name, signature = sign)
|
||||
|
||||
@@ -1,30 +1,17 @@
|
||||
include "Option.aes"
|
||||
include "AENSCompat.aes"
|
||||
contract interface OldAENSContract =
|
||||
entrypoint set : (string, string, AENS.pointee) => unit
|
||||
entrypoint lookup : (string, string) => AENS.pointee
|
||||
|
||||
main contract AENSUpdate =
|
||||
contract AENSUpdate =
|
||||
stateful entrypoint update_name(owner : address, name : string) =
|
||||
let p1 : AENSv2.pointee = AENSv2.AccountPt(Call.caller)
|
||||
let p2 : AENSv2.pointee = AENSv2.OraclePt(Call.caller)
|
||||
let p3 : AENSv2.pointee = AENSv2.ContractPt(Call.caller)
|
||||
let p4 : AENSv2.pointee = AENSv2.ChannelPt(Call.caller)
|
||||
let p5 : AENSv2.pointee = AENSv2.DataPt("any something will do")
|
||||
AENSv2.update(owner, name, None, None,
|
||||
let p1 : AENS.pointee = AENS.AccountPt(Call.caller)
|
||||
let p2 : AENS.pointee = AENS.OraclePt(Call.caller)
|
||||
let p3 : AENS.pointee = AENS.ContractPt(Call.caller)
|
||||
let p4 : AENS.pointee = AENS.ChannelPt(Call.caller)
|
||||
AENS.update(owner, name, None, None,
|
||||
Some({ ["account_pubkey"] = p1, ["oracle_pubkey"] = p2,
|
||||
["contract_pubkey"] = p3, ["misc"] = p4, ["data"] = p5 }))
|
||||
|
||||
stateful entrypoint old_interaction(c : OldAENSContract, owner : address, name : string) =
|
||||
let p : AENS.pointee = c.lookup(name, "key1")
|
||||
AENSv2.update(owner, name, None, None, Some({ ["key1"] = AENSCompat.pointee_to_V2(p) }))
|
||||
switch(AENSv2.lookup(name))
|
||||
Some(AENSv2.Name(_, _, pt_map)) =>
|
||||
c.set(name, "key2", Option.force(AENSCompat.pointee_from_V2(pt_map["key1"])))
|
||||
["contract_pubkey"] = p3, ["misc"] = p4 }))
|
||||
|
||||
entrypoint get_ttl(name : string) =
|
||||
switch(AENSv2.lookup(name))
|
||||
Some(AENSv2.Name(_, FixedTTL(ttl), _)) => ttl
|
||||
switch(AENS.lookup(name))
|
||||
Some(AENS.Name(_, FixedTTL(ttl), _)) => ttl
|
||||
|
||||
entrypoint expiry(o : oracle(int, int)) : int =
|
||||
Oracle.expiry(o)
|
||||
|
||||
|
||||
@@ -80,4 +80,3 @@ contract AllSyntax =
|
||||
let sh : shakespeare(shakespeare(int)) =
|
||||
{wolfgang = state}
|
||||
sh{wolfgang.wolfgang = sh.wolfgang} // comment
|
||||
exit("hope you had fun reading this")
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
contract BadAENSresolve =
|
||||
using AENSv2
|
||||
|
||||
type t('a) = option(list('a))
|
||||
|
||||
function fail() : t(int) =
|
||||
resolve("foo.aet", "whatever")
|
||||
|
||||
entrypoint main_fun() = ()
|
||||
@@ -1,14 +0,0 @@
|
||||
contract C =
|
||||
entrypoint test() =
|
||||
let a : int = 23
|
||||
let b : int = 52
|
||||
let c = a bor b
|
||||
let d = c bxor b
|
||||
let e = d band b
|
||||
let f = bnot a
|
||||
let g = f << 2
|
||||
let h = g >> 2
|
||||
let i = Int.mulmod(a, b, h)
|
||||
let j = Crypto.poseidon(i, a)
|
||||
let k : bytes(32) = Address.to_bytes(Call.origin)
|
||||
(a bor b band c bxor a << bnot b >> a, k)
|
||||
+1
-1
@@ -3,7 +3,7 @@ contract BadAENSresolve =
|
||||
type t('a) = option(list('a))
|
||||
|
||||
function fail() : t(int) =
|
||||
AENSv2.resolve("foo.aet", "whatever")
|
||||
AENS.resolve("foo.aet", "whatever")
|
||||
|
||||
entrypoint main_fun() = ()
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
contract MissingInitFunction =
|
||||
type state = int * int
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
contract PolymorphicAENSresolve =
|
||||
|
||||
function fail() : option('a) =
|
||||
AENSv2.resolve("foo.aet", "whatever")
|
||||
AENS.resolve("foo.aet", "whatever")
|
||||
|
||||
entrypoint main_fun() = ()
|
||||
|
||||
@@ -0,0 +1,169 @@
|
||||
contract A = entrypoint init() = ()
|
||||
|
||||
main contract C =
|
||||
datatype custom_datatype('a) = CD('a)
|
||||
|
||||
record custom_record('a) = { f : 'a }
|
||||
|
||||
// pass
|
||||
function
|
||||
passing_ord : 'a is ord ; ('a, 'a) => bool
|
||||
passing_ord(x, y) = x >= y
|
||||
|
||||
// pass
|
||||
function
|
||||
passing_eq : 'a is eq ; ('a, 'a) => bool
|
||||
passing_eq(x, y) = x == y
|
||||
|
||||
// fail because eq is not specified for 'a
|
||||
function
|
||||
fail_no_eq : ('a, 'a) => bool
|
||||
fail_no_eq(x, y) = x == y
|
||||
|
||||
// fail because 'b is not used
|
||||
function
|
||||
fail_unused_tvar : 'a is eq, 'b is eq ; ('a, 'a) => bool
|
||||
fail_unused_tvar(x, y) = x == y
|
||||
|
||||
function
|
||||
fail_unknown_constraint : 'a is foo ; ('a) => 'a
|
||||
fail_unknown_constraint(x) = x
|
||||
|
||||
// Ord types
|
||||
|
||||
function bool_ord(x : bool, y : bool) = x >= y // pass
|
||||
function bool_eq (x : bool, y : bool) = x == y // pass
|
||||
|
||||
function int_ord(x : int, y : int) = x >= y // pass
|
||||
function int_eq (x : int, y : int) = x == y // pass
|
||||
|
||||
function char_ord(x : char, y : char) = x >= y // pass
|
||||
function char_eq (x : char, y : char) = x == y // pass
|
||||
|
||||
function bits_ord(x : bits, y : bits) = x >= y // pass
|
||||
function bits_eq (x : bits, y : bits) = x == y // pass
|
||||
|
||||
function bytes_ord(x : bytes(16), y : bytes(16)) = x >= y // pass
|
||||
function bytes_eq (x : bytes(16), y : bytes(16)) = x == y // pass
|
||||
|
||||
function string_ord(x : string, y : string) = x >= y // pass
|
||||
function string_eq (x : string, y : string) = x == y // pass
|
||||
|
||||
function hash_ord(x : hash, y : hash) = x >= y // pass
|
||||
function hash_eq (x : hash, y : hash) = x == y // pass
|
||||
|
||||
function signature_ord(x : signature, y : signature) = x >= y // pass
|
||||
function signature_eq (x : signature, y : signature) = x == y // pass
|
||||
|
||||
function address_ord(x : address, y : address) = x >= y // pass
|
||||
function address_eq (x : address, y : address) = x == y // pass
|
||||
|
||||
// Eq types
|
||||
|
||||
function event_ord(x : Chain.ttl, y : Chain.ttl) = x >= y // fail
|
||||
function event_eq (x : Chain.ttl, y : Chain.ttl) = x == y // pass
|
||||
|
||||
function contract_ord(x : A, y : A) = x >= y // fail
|
||||
function contract_eq (x : A, y : A) = x == y // pass
|
||||
|
||||
// Noncomparable types
|
||||
|
||||
type lam = (int, char) => bool
|
||||
|
||||
function lambda_ord(x : lam, y : lam) = x >= y // fail
|
||||
function lambda_eq (x : lam, y : lam) = x == y // fail
|
||||
|
||||
// Ord composite types of ord
|
||||
|
||||
function list_of_ord_ord(x : list(int), y : list(int)) = x >= y // pass
|
||||
function list_of_ord_eq (x : list(int), y : list(int)) = x == y // pass
|
||||
|
||||
function option_of_ord_ord(x : option(int), y : option(int)) = x >= y // pass
|
||||
function option_of_ord_eq (x : option(int), y : option(int)) = x == y // pass
|
||||
|
||||
function tuple_of_ord_ord(x : (int * bool), y : (int * bool)) = x >= y // pass
|
||||
function tuple_of_ord_eq (x : (int * bool), y : (int * bool)) = x == y // pass
|
||||
|
||||
// Ord composite types of eq
|
||||
|
||||
function list_of_eq_ord(x : list(A), y : list(A)) = x >= y // fail
|
||||
function list_of_eq_eq (x : list(A), y : list(A)) = x == y // pass
|
||||
|
||||
function option_of_eq_ord(x : option(A), y : option(A)) = x >= y // fail
|
||||
function option_of_eq_eq (x : option(A), y : option(A)) = x == y // pass
|
||||
|
||||
function tuple_of_eq_ord(x : (A * int), y : (A * int)) = x >= y // fail
|
||||
function tuple_of_eq_eq (x : (A * int), y : (A * int)) = x == y // pass
|
||||
|
||||
// Ord composite types of nomcomparable
|
||||
|
||||
function list_of_noncomp_ord(x : list(lam), y : list(lam)) = x >= y // fail
|
||||
function list_of_noncomp_eq (x : list(lam), y : list(lam)) = x == y // fail
|
||||
|
||||
function option_of_noncomp_ord(x : option(lam), y : option(lam)) = x >= y // fail
|
||||
function option_of_noncomp_eq (x : option(lam), y : option(lam)) = x == y // fail
|
||||
|
||||
function tuple_of_noncomp_ord(x : (lam * int), y : (lam * int)) = x >= y // fail
|
||||
function tuple_of_noncomp_eq (x : (lam * int), y : (lam * int)) = x == y // fail
|
||||
|
||||
// Eq composite types of ord
|
||||
|
||||
function map_of_ord_ord(x : map(int, int), y : map(int, int)) = x >= y // fail
|
||||
function map_of_ord_eq (x : map(int, int), y : map(int, int)) = x == y // pass
|
||||
|
||||
function oracle_of_ord_ord(x : oracle(int, int), y : oracle(int, int)) = x >= y // fail
|
||||
function oracle_of_ord_eq (x : oracle(int, int), y : oracle(int, int)) = x == y // pass
|
||||
|
||||
function oracle_query_of_ord_ord(x : oracle_query(int, int), y : oracle_query(int, int)) = x >= y // fail
|
||||
function oracle_query_of_ord_eq (x : oracle_query(int, int), y : oracle_query(int, int)) = x == y // pass
|
||||
|
||||
function datatype_of_ord_ord(x : custom_datatype(int), y : custom_datatype(int)) = x >= y // fail
|
||||
function datatype_of_ord_eq (x : custom_datatype(int), y : custom_datatype(int)) = x == y // pass
|
||||
|
||||
function record_of_ord_ord(x : custom_record(int), y : custom_record(int)) = x >= y // fail
|
||||
function record_of_ord_eq (x : custom_record(int), y : custom_record(int)) = x == y // pass
|
||||
|
||||
// Eq composite types of eq
|
||||
|
||||
function map_of_eq_ord(x : map(A, A), y : map(A, A)) = x >= y // fail
|
||||
function map_of_eq_eq (x : map(A, A), y : map(A, A)) = x == y // pass
|
||||
|
||||
function oracle_of_eq_ord(x : oracle(A, A), y : oracle(A, A)) = x >= y // fail
|
||||
function oracle_of_eq_eq (x : oracle(A, A), y : oracle(A, A)) = x == y // pass
|
||||
|
||||
function oracle_query_of_eq_ord(x : oracle_query(A, A), y : oracle_query(A, A)) = x >= y // fail
|
||||
function oracle_query_of_eq_eq (x : oracle_query(A, A), y : oracle_query(A, A)) = x == y // pass
|
||||
|
||||
function datatype_of_eq_ord(x : custom_datatype(A), y : custom_datatype(A)) = x >= y // fail
|
||||
function datatype_of_eq_eq (x : custom_datatype(A), y : custom_datatype(A)) = x == y // pass
|
||||
|
||||
function record_of_eq_ord(x : custom_record(A), y : custom_record(A)) = x >= y // fail
|
||||
function record_of_eq_eq (x : custom_record(A), y : custom_record(A)) = x == y // pass
|
||||
|
||||
// Eq composite types of nomcomparable
|
||||
|
||||
function map_of_noncomp_ord(x : map(lam, lam), y : map(lam, lam)) = x >= y // fail
|
||||
function map_of_noncomp_eq (x : map(lam, lam), y : map(lam, lam)) = x == y // fail
|
||||
|
||||
function oracle_of_noncomp_ord(x : oracle(lam, lam), y : oracle(lam, lam)) = x >= y // fail
|
||||
function oracle_of_noncomp_eq (x : oracle(lam, lam), y : oracle(lam, lam)) = x == y // fail
|
||||
|
||||
function oracle_query_of_noncomp_ord(x : oracle_query(lam, lam), y : oracle_query(lam, lam)) = x >= y // fail
|
||||
function oracle_query_of_noncomp_eq (x : oracle_query(lam, lam), y : oracle_query(lam, lam)) = x == y // fail
|
||||
|
||||
function datatype_of_noncomp_ord(x : custom_datatype(lam), y : custom_datatype(lam)) = x >= y // fail
|
||||
function datatype_of_noncomp_eq (x : custom_datatype(lam), y : custom_datatype(lam)) = x == y // pass
|
||||
|
||||
function record_of_nomcomp_ord(x : custom_record(lam), y : custom_record(lam)) = x >= y // fail
|
||||
function record_of_nomcomp_eq (x : custom_record(lam), y : custom_record(lam)) = x == y // pass
|
||||
|
||||
entrypoint init() =
|
||||
let passing_ord_ord = passing_ord([1], [2]) // pass
|
||||
let passing_ord_eq = passing_ord({[1] = 2}, {[2] = 3}) // fail
|
||||
let passing_ord_noncomp = passing_ord((x) => x, (x) => x) // fail
|
||||
|
||||
let passing_eq_ord = passing_eq([1], [2]) // pass
|
||||
let passing_eq_eq = passing_eq({[1] = 2}, {[2] = 3}) // pass
|
||||
let passing_eq_noncomp = passing_eq((x) => x, (x) => x) // fail
|
||||
|
||||
()
|
||||
@@ -1,7 +1,16 @@
|
||||
|
||||
contract interface Remote =
|
||||
entrypoint up_to : (int) => list(int)
|
||||
entrypoint sum : (list(int)) => int
|
||||
entrypoint some_string : () => string
|
||||
entrypoint pair : (int, string) => int * string
|
||||
entrypoint squares : (int) => list(int * int)
|
||||
entrypoint filter_some : (list(option(int))) => list(int)
|
||||
entrypoint all_some : (list(option(int))) => option(list(int))
|
||||
|
||||
contract ComplexTypes =
|
||||
|
||||
record state = { worker : ComplexTypes }
|
||||
record state = { worker : Remote }
|
||||
|
||||
entrypoint init(worker) = {worker = worker}
|
||||
|
||||
|
||||
@@ -1,9 +1,14 @@
|
||||
|
||||
// Testing primitives for accessing the block chain environment
|
||||
contract interface Interface =
|
||||
entrypoint contract_address : () => address
|
||||
entrypoint call_origin : () => address
|
||||
entrypoint call_caller : () => address
|
||||
entrypoint call_value : () => int
|
||||
|
||||
contract Environment =
|
||||
|
||||
record state = {remote : Environment}
|
||||
record state = {remote : Interface}
|
||||
|
||||
entrypoint init(remote) = {remote = remote}
|
||||
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
contract AliasToAliasToType =
|
||||
type alias = int * int
|
||||
type state = alias
|
||||
@@ -1,2 +0,0 @@
|
||||
contract AliasToType =
|
||||
type state = int * int
|
||||
@@ -1,9 +0,0 @@
|
||||
contract AliasToAliasToUnit =
|
||||
type alias = unit
|
||||
type state = alias
|
||||
|
||||
contract AliasToUnit =
|
||||
type state = unit
|
||||
|
||||
main contract ImplicitState =
|
||||
type sometype = int
|
||||
@@ -1,5 +1,12 @@
|
||||
|
||||
contract NameClash =
|
||||
|
||||
entrypoint double_proto : () => int
|
||||
entrypoint double_proto : () => int
|
||||
|
||||
entrypoint proto_and_def : int => int
|
||||
entrypoint proto_and_def(n) = n + 1
|
||||
|
||||
entrypoint double_def(x) = x
|
||||
entrypoint double_def(y) = 0
|
||||
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
contract interface Strokable =
|
||||
entrypoint stroke : () => string
|
||||
|
||||
contract Cat : Strokable =
|
||||
entrypoint stroke() = "Cat stroke"
|
||||
@@ -1,10 +0,0 @@
|
||||
contract interface II =
|
||||
entrypoint f : () => unit
|
||||
|
||||
contract interface I : II =
|
||||
entrypoint f : () => unit
|
||||
entrypoint g : () => unit
|
||||
|
||||
contract C : I =
|
||||
entrypoint f() = ()
|
||||
entrypoint g() = ()
|
||||
@@ -1,9 +0,0 @@
|
||||
contract interface I0 =
|
||||
entrypoint f : () => int
|
||||
|
||||
contract interface I1 : I0 =
|
||||
entrypoint f : () => int
|
||||
entrypoint something_else : () => int
|
||||
|
||||
main contract C =
|
||||
entrypoint f(x : I1) = x.f() // Here we should know that x has f
|
||||
@@ -1,13 +0,0 @@
|
||||
contract interface X : Z =
|
||||
entrypoint x : () => int
|
||||
|
||||
contract interface Y : X =
|
||||
entrypoint y : () => int
|
||||
|
||||
contract interface Z : Y =
|
||||
entrypoint z : () => int
|
||||
|
||||
contract C : Z =
|
||||
entrypoint x() = 1
|
||||
entrypoint y() = 1
|
||||
entrypoint z() = 1
|
||||
@@ -1,8 +0,0 @@
|
||||
contract interface I =
|
||||
entrypoint f : () => int
|
||||
|
||||
contract interface II : I =
|
||||
entrypoint f : () => int
|
||||
|
||||
contract C : II =
|
||||
entrypoint f() = 1
|
||||
@@ -1,9 +0,0 @@
|
||||
contract interface I1 =
|
||||
entrypoint f : () => int
|
||||
|
||||
contract interface I2 : I1 =
|
||||
entrypoint f : () => char
|
||||
|
||||
contract C : I2 =
|
||||
entrypoint f() = 1
|
||||
entrypoint f() = 'c'
|
||||
@@ -1,8 +0,0 @@
|
||||
contract interface I1 =
|
||||
entrypoint f : () => int
|
||||
|
||||
contract interface I2 : I1 =
|
||||
entrypoint f : () => int
|
||||
|
||||
contract C : I2 =
|
||||
entrypoint f() = 1
|
||||
@@ -1,5 +0,0 @@
|
||||
contract interface I : H =
|
||||
entrypoint f : () => unit
|
||||
|
||||
contract C =
|
||||
entrypoint g() = ()
|
||||
@@ -1,8 +0,0 @@
|
||||
contract interface I1 =
|
||||
entrypoint f : () => int
|
||||
|
||||
contract interface I2 : I1 =
|
||||
entrypoint g : () => int
|
||||
|
||||
contract C : I2 =
|
||||
entrypoint g() = 1
|
||||
@@ -1,9 +0,0 @@
|
||||
contract interface I =
|
||||
entrypoint f : () => int
|
||||
|
||||
contract interface J =
|
||||
entrypoint g : () => char
|
||||
|
||||
contract C : I, J =
|
||||
entrypoint f() = 1
|
||||
entrypoint g() = 'c'
|
||||
@@ -1,8 +0,0 @@
|
||||
contract interface I =
|
||||
entrypoint f : () => int
|
||||
|
||||
contract interface J =
|
||||
entrypoint f : () => int
|
||||
|
||||
contract C : I, J =
|
||||
entrypoint f() = 1
|
||||
@@ -1,9 +0,0 @@
|
||||
contract interface I =
|
||||
entrypoint f : () => int
|
||||
|
||||
contract interface J =
|
||||
entrypoint f : () => char
|
||||
|
||||
contract C : I, J =
|
||||
entrypoint f() = 1
|
||||
entrypoint f() = 'c'
|
||||
@@ -1,2 +0,0 @@
|
||||
contract C : I =
|
||||
entrypoint f() = ()
|
||||
@@ -1,75 +0,0 @@
|
||||
contract interface Creature =
|
||||
entrypoint is_alive : () => bool
|
||||
|
||||
contract interface Animal : Creature =
|
||||
entrypoint is_alive : () => bool
|
||||
entrypoint sound : () => string
|
||||
|
||||
contract Cat : Animal =
|
||||
entrypoint sound() = "meow"
|
||||
entrypoint is_alive() = true
|
||||
|
||||
main contract Main =
|
||||
entrypoint init() = ()
|
||||
|
||||
stateful function g0(_ : Creature) : Cat = Chain.create()
|
||||
stateful function f0(x : Cat) : Creature = g0(x)
|
||||
stateful function h0() =
|
||||
let a : Animal = (Chain.create() : Cat)
|
||||
let c : Creature = (Chain.create() : Cat)
|
||||
let c1 : Creature = a
|
||||
()
|
||||
|
||||
stateful function g1(x : Animal) : Cat = Chain.create()
|
||||
stateful function f1(x : Cat) : Animal = g1(x)
|
||||
|
||||
stateful function g11(x : list(Animal)) : list(Cat) = [Chain.create()]
|
||||
stateful function f11(x : list(Cat)) : list(Animal) = g11(x)
|
||||
|
||||
stateful function g12(x : Animal * Animal) : Cat * Cat = (Chain.create(), Chain.create())
|
||||
stateful function f12(x : Cat * Cat) : Animal * Animal = g12(x)
|
||||
|
||||
stateful function g13() : map(Cat, Cat) = { [Chain.create()] = Chain.create() }
|
||||
stateful function f13() : map(Animal, Animal) = g13()
|
||||
|
||||
stateful function g2(x : Cat) : Cat = Chain.create()
|
||||
stateful function f2(x : Animal) : Animal = g2(x) // fail
|
||||
|
||||
stateful function g3(x : Cat) : Animal = f1(x)
|
||||
stateful function f3(x : Cat) : Cat = g3(x) // fail
|
||||
|
||||
stateful function g4(x : (Cat => Animal)) : Cat = Chain.create()
|
||||
stateful function f4(x : (Animal => Cat)) : Animal = g4(x)
|
||||
|
||||
stateful function g44(x : list(list(Cat) => list(Animal))) : Cat = Chain.create()
|
||||
stateful function f44(x : list(list(Animal) => list(Cat))) : Animal = g44(x)
|
||||
|
||||
stateful function g5(x : (Animal => Animal)) : Cat = Chain.create()
|
||||
stateful function f5(x : (Cat => Cat)) : Animal = g5(x) // fail
|
||||
|
||||
stateful function g6() : option(Cat) = Some(Chain.create())
|
||||
stateful function f6() : option(Animal) = g6()
|
||||
stateful function h6() : option(Cat) = f6() // fail
|
||||
|
||||
type cat_type = Cat
|
||||
type animal_type = Animal
|
||||
type cat_cat_map = map(cat_type, cat_type)
|
||||
type animal_animal_map = map(animal_type, animal_type)
|
||||
|
||||
stateful function g71(x : animal_type) : cat_type = Chain.create()
|
||||
stateful function f71(x : cat_type) : animal_type = g1(x)
|
||||
|
||||
stateful function g72() : cat_cat_map = { [Chain.create()] = Chain.create() }
|
||||
stateful function f72() : animal_animal_map = g13()
|
||||
|
||||
stateful function g73() =
|
||||
let some_cat : Cat = Chain.create()
|
||||
let some_animal : Animal = some_cat
|
||||
|
||||
let some_cat_cat_map : map(Cat, Cat) = g13()
|
||||
let some_animal_animal_map : map(Animal, Animal) = some_cat_cat_map
|
||||
|
||||
let x : Animal = some_animal_animal_map[some_cat] // success
|
||||
let y : Cat = some_cat_cat_map[some_animal] // fail
|
||||
|
||||
()
|
||||
@@ -1,29 +0,0 @@
|
||||
contract interface I =
|
||||
entrypoint f : () => int
|
||||
|
||||
contract C1 : I =
|
||||
entrypoint f() = 123
|
||||
|
||||
contract C2 : I =
|
||||
entrypoint f() = 888
|
||||
|
||||
namespace Make =
|
||||
stateful function new1() : I = Chain.create() : C1
|
||||
stateful function new2() : I = Chain.create() : C2
|
||||
|
||||
stateful function new(c : I) : int = c.f()
|
||||
|
||||
main contract Main =
|
||||
stateful entrypoint test1() =
|
||||
let c = Make.new1()
|
||||
Make.new(c)
|
||||
|
||||
stateful entrypoint test2() =
|
||||
let c = Make.new2()
|
||||
Make.new(c)
|
||||
|
||||
stateful entrypoint test3() =
|
||||
let c1 = Chain.create() : C1 // succeeds
|
||||
let c2 : I = Chain.create() : C1 // succeeds
|
||||
let c3 : C1 = Chain.create() // succeeds
|
||||
()
|
||||
@@ -1,12 +0,0 @@
|
||||
contract interface I =
|
||||
entrypoint f : () => int
|
||||
|
||||
contract C : I =
|
||||
entrypoint f() = 123
|
||||
|
||||
main contract Main =
|
||||
stateful entrypoint test() =
|
||||
let c1 : I = Chain.create() // fails
|
||||
let c2 : C = Chain.create() : I // fails
|
||||
let c3 = Chain.create() : I // fails
|
||||
()
|
||||
@@ -1,135 +0,0 @@
|
||||
contract interface Animal =
|
||||
entrypoint sound : () => string
|
||||
|
||||
contract Cat : Animal =
|
||||
entrypoint sound() = "meow"
|
||||
|
||||
main contract Main =
|
||||
datatype dt_contra('a) = DT_CONTRA('a => unit)
|
||||
datatype dt_co('a) = DT_CO(unit => 'a)
|
||||
datatype dt_inv('a) = DT_INV('a => 'a)
|
||||
datatype dt_biv('a) = DT_BIV(unit => unit)
|
||||
datatype dt_inv_sep('a) = DT_INV_SEP_A('a => unit) | DT_INV_SEP_B(unit => 'a)
|
||||
datatype dt_co_nest_a('a) = DT_CO_NEST_A(dt_contra('a) => unit)
|
||||
datatype dt_contra_nest_a('a) = DT_CONTRA_NEST_A(dt_co('a) => unit)
|
||||
datatype dt_contra_nest_b('a) = DT_CONTRA_NEST_B(unit => dt_contra('a))
|
||||
datatype dt_co_nest_b('a) = DT_CO_NEST_B(unit => dt_co('a))
|
||||
datatype dt_co_twice('a) = DT_CO_TWICE(('a => unit) => 'a)
|
||||
datatype dt_contra_twice('a) = DT_CONTRA_TWICE('a => 'a => unit)
|
||||
datatype dt_a_contra_b_contra('a, 'b) = DT_A_CONTRA_B_CONTRA('a => 'b => unit)
|
||||
|
||||
function f_a_to_a_to_u(_ : Animal) : (Animal => unit) = f_a_to_u
|
||||
function f_a_to_c_to_u(_ : Animal) : (Cat => unit) = f_c_to_u
|
||||
function f_c_to_a_to_u(_ : Cat) : (Animal => unit) = f_a_to_u
|
||||
function f_c_to_c_to_u(_ : Cat) : (Cat => unit) = f_c_to_u
|
||||
|
||||
function f_u_to_u(_ : unit) : unit = ()
|
||||
function f_a_to_u(_ : Animal) : unit = ()
|
||||
function f_c_to_u(_ : Cat) : unit = ()
|
||||
|
||||
function f_dt_contra_a_to_u(_ : dt_contra(Animal)) : unit = ()
|
||||
function f_dt_contra_c_to_u(_ : dt_contra(Cat)) : unit = ()
|
||||
function f_dt_co_a_to_u(_ : dt_co(Animal)) : unit = ()
|
||||
function f_dt_co_c_to_u(_ : dt_co(Cat)) : unit = ()
|
||||
function f_u_to_dt_contra_a(_ : unit) : dt_contra(Animal) = DT_CONTRA(f_a_to_u)
|
||||
function f_u_to_dt_contra_c(_ : unit) : dt_contra(Cat) = DT_CONTRA(f_c_to_u)
|
||||
|
||||
stateful function f_c() : Cat = Chain.create()
|
||||
stateful function f_a() : Animal = f_c()
|
||||
|
||||
stateful function f_u_to_a(_ : unit) : Animal = f_a()
|
||||
stateful function f_u_to_c(_ : unit) : Cat = f_c()
|
||||
stateful function f_a_to_a(_ : Animal) : Animal = f_a()
|
||||
stateful function f_a_to_c(_ : Animal) : Cat = f_c()
|
||||
stateful function f_c_to_a(_ : Cat) : Animal = f_a()
|
||||
stateful function f_c_to_c(_ : Cat) : Cat = f_c()
|
||||
|
||||
stateful function f_a_to_u_to_c(_ : (Animal => unit)) : Cat = f_c()
|
||||
stateful function f_c_to_u_to_a(_ : (Cat => unit)) : Animal = f_a()
|
||||
stateful function f_c_to_u_to_c(_ : (Cat => unit)) : Cat = f_c()
|
||||
|
||||
stateful function f_u_to_dt_co_a(_ : unit) : dt_co(Animal) = DT_CO(f_u_to_a)
|
||||
stateful function f_u_to_dt_co_c(_ : unit) : dt_co(Cat) = DT_CO(f_u_to_c)
|
||||
|
||||
stateful entrypoint init() =
|
||||
let va1 : dt_contra(Animal) = DT_CONTRA(f_a_to_u) // success
|
||||
let va2 : dt_contra(Animal) = DT_CONTRA(f_c_to_u) // fail
|
||||
let va3 : dt_contra(Cat) = DT_CONTRA(f_a_to_u) // success
|
||||
let va4 : dt_contra(Cat) = DT_CONTRA(f_c_to_u) // success
|
||||
|
||||
let vb1 : dt_co(Animal) = DT_CO(f_u_to_a) // success
|
||||
let vb2 : dt_co(Animal) = DT_CO(f_u_to_c) // success
|
||||
let vb3 : dt_co(Cat) = DT_CO(f_u_to_a) // fail
|
||||
let vb4 : dt_co(Cat) = DT_CO(f_u_to_c) // success
|
||||
|
||||
let vc1 : dt_inv(Animal) = DT_INV(f_a_to_a) // success
|
||||
let vc2 : dt_inv(Animal) = DT_INV(f_a_to_c) // success
|
||||
let vc3 : dt_inv(Animal) = DT_INV(f_c_to_a) // fail
|
||||
let vc4 : dt_inv(Animal) = DT_INV(f_c_to_c) // fail
|
||||
let vc5 : dt_inv(Cat) = DT_INV(f_a_to_a) // fail
|
||||
let vc6 : dt_inv(Cat) = DT_INV(f_a_to_c) // fail
|
||||
let vc7 : dt_inv(Cat) = DT_INV(f_c_to_a) // fail
|
||||
let vc8 : dt_inv(Cat) = DT_INV(f_c_to_c) // success
|
||||
|
||||
let vd1 : dt_biv(Animal) = DT_BIV(f_u_to_u) : dt_biv(Animal) // success
|
||||
let vd2 : dt_biv(Animal) = DT_BIV(f_u_to_u) : dt_biv(Cat) // success
|
||||
let vd3 : dt_biv(Cat) = DT_BIV(f_u_to_u) : dt_biv(Animal) // success
|
||||
let vd4 : dt_biv(Cat) = DT_BIV(f_u_to_u) : dt_biv(Cat) // success
|
||||
|
||||
let ve1 : dt_inv_sep(Animal) = DT_INV_SEP_A(f_a_to_u) // success
|
||||
let ve2 : dt_inv_sep(Animal) = DT_INV_SEP_A(f_c_to_u) // fail
|
||||
let ve3 : dt_inv_sep(Animal) = DT_INV_SEP_B(f_u_to_a) // success
|
||||
let ve4 : dt_inv_sep(Animal) = DT_INV_SEP_B(f_u_to_c) // fail
|
||||
let ve5 : dt_inv_sep(Cat) = DT_INV_SEP_A(f_a_to_u) // fail
|
||||
let ve6 : dt_inv_sep(Cat) = DT_INV_SEP_A(f_c_to_u) // success
|
||||
let ve7 : dt_inv_sep(Cat) = DT_INV_SEP_B(f_u_to_a) // fail
|
||||
let ve8 : dt_inv_sep(Cat) = DT_INV_SEP_B(f_u_to_c) // success
|
||||
|
||||
let vf1 : dt_co_nest_a(Animal) = DT_CO_NEST_A(f_dt_contra_a_to_u) // success
|
||||
let vf2 : dt_co_nest_a(Animal) = DT_CO_NEST_A(f_dt_contra_c_to_u) // success
|
||||
let vf3 : dt_co_nest_a(Cat) = DT_CO_NEST_A(f_dt_contra_a_to_u) // fail
|
||||
let vf4 : dt_co_nest_a(Cat) = DT_CO_NEST_A(f_dt_contra_c_to_u) // success
|
||||
|
||||
let vg1 : dt_contra_nest_a(Animal) = DT_CONTRA_NEST_A(f_dt_co_a_to_u) // success
|
||||
let vg2 : dt_contra_nest_a(Animal) = DT_CONTRA_NEST_A(f_dt_co_c_to_u) // fail
|
||||
let vg3 : dt_contra_nest_a(Cat) = DT_CONTRA_NEST_A(f_dt_co_a_to_u) // success
|
||||
let vg4 : dt_contra_nest_a(Cat) = DT_CONTRA_NEST_A(f_dt_co_c_to_u) // success
|
||||
|
||||
let vh1 : dt_contra_nest_b(Animal) = DT_CONTRA_NEST_B(f_u_to_dt_contra_a) // success
|
||||
let vh2 : dt_contra_nest_b(Animal) = DT_CONTRA_NEST_B(f_u_to_dt_contra_c) // fail
|
||||
let vh3 : dt_contra_nest_b(Cat) = DT_CONTRA_NEST_B(f_u_to_dt_contra_a) // success
|
||||
let vh4 : dt_contra_nest_b(Cat) = DT_CONTRA_NEST_B(f_u_to_dt_contra_c) // success
|
||||
|
||||
let vi1 : dt_co_nest_b(Animal) = DT_CO_NEST_B(f_u_to_dt_co_a) // success
|
||||
let vi2 : dt_co_nest_b(Animal) = DT_CO_NEST_B(f_u_to_dt_co_c) // success
|
||||
let vi3 : dt_co_nest_b(Cat) = DT_CO_NEST_B(f_u_to_dt_co_a) // fail
|
||||
let vi4 : dt_co_nest_b(Cat) = DT_CO_NEST_B(f_u_to_dt_co_c) // success
|
||||
|
||||
let vj1 : dt_co_twice(Animal) = DT_CO_TWICE(f_a_to_u_to_c : (Animal => unit) => Animal) : dt_co_twice(Animal) // success
|
||||
let vj2 : dt_co_twice(Animal) = DT_CO_TWICE(f_c_to_u_to_c : (Cat => unit) => Cat ) : dt_co_twice(Cat) // success
|
||||
let vj3 : dt_co_twice(Cat) = DT_CO_TWICE(f_c_to_u_to_a : (Animal => unit) => Animal) : dt_co_twice(Animal) // fail
|
||||
let vj4 : dt_co_twice(Cat) = DT_CO_TWICE(f_c_to_u_to_c : (Cat => unit) => Cat ) : dt_co_twice(Cat) // success
|
||||
|
||||
let vk01 : dt_a_contra_b_contra(Animal, Animal) = DT_A_CONTRA_B_CONTRA(f_a_to_a_to_u) // success
|
||||
let vk02 : dt_a_contra_b_contra(Animal, Animal) = DT_A_CONTRA_B_CONTRA(f_a_to_c_to_u) // fail
|
||||
let vk03 : dt_a_contra_b_contra(Animal, Animal) = DT_A_CONTRA_B_CONTRA(f_c_to_a_to_u) // fail
|
||||
let vk04 : dt_a_contra_b_contra(Animal, Animal) = DT_A_CONTRA_B_CONTRA(f_c_to_c_to_u) // fail
|
||||
let vk05 : dt_a_contra_b_contra(Animal, Cat) = DT_A_CONTRA_B_CONTRA(f_a_to_a_to_u) // success
|
||||
let vk06 : dt_a_contra_b_contra(Animal, Cat) = DT_A_CONTRA_B_CONTRA(f_a_to_c_to_u) // success
|
||||
let vk07 : dt_a_contra_b_contra(Animal, Cat) = DT_A_CONTRA_B_CONTRA(f_c_to_a_to_u) // fail
|
||||
let vk08 : dt_a_contra_b_contra(Animal, Cat) = DT_A_CONTRA_B_CONTRA(f_c_to_c_to_u) // fail
|
||||
let vk09 : dt_a_contra_b_contra(Cat, Animal) = DT_A_CONTRA_B_CONTRA(f_a_to_a_to_u) // success
|
||||
let vk10 : dt_a_contra_b_contra(Cat, Animal) = DT_A_CONTRA_B_CONTRA(f_a_to_c_to_u) // fail
|
||||
let vk11 : dt_a_contra_b_contra(Cat, Animal) = DT_A_CONTRA_B_CONTRA(f_c_to_a_to_u) // success
|
||||
let vk12 : dt_a_contra_b_contra(Cat, Animal) = DT_A_CONTRA_B_CONTRA(f_c_to_c_to_u) // fail
|
||||
let vk13 : dt_a_contra_b_contra(Cat, Cat) = DT_A_CONTRA_B_CONTRA(f_a_to_a_to_u) // success
|
||||
let vk14 : dt_a_contra_b_contra(Cat, Cat) = DT_A_CONTRA_B_CONTRA(f_a_to_c_to_u) // success
|
||||
let vk15 : dt_a_contra_b_contra(Cat, Cat) = DT_A_CONTRA_B_CONTRA(f_c_to_a_to_u) // success
|
||||
let vk16 : dt_a_contra_b_contra(Cat, Cat) = DT_A_CONTRA_B_CONTRA(f_c_to_c_to_u) // success
|
||||
|
||||
let vl1 : dt_contra_twice(Animal) = DT_CONTRA_TWICE(f_a_to_a_to_u : Animal => Animal => unit) : dt_contra_twice(Animal) // success
|
||||
let vl2 : dt_contra_twice(Animal) = DT_CONTRA_TWICE(f_a_to_c_to_u : Cat => Cat => unit) : dt_contra_twice(Cat) // fail
|
||||
let vl3 : dt_contra_twice(Cat) = DT_CONTRA_TWICE(f_a_to_a_to_u : Animal => Animal => unit) : dt_contra_twice(Animal) // success
|
||||
let vl4 : dt_contra_twice(Cat) = DT_CONTRA_TWICE(f_c_to_a_to_u : Cat => Cat => unit) : dt_contra_twice(Cat) // success
|
||||
|
||||
()
|
||||
@@ -1,47 +0,0 @@
|
||||
contract interface Animal =
|
||||
entrypoint sound : () => string
|
||||
|
||||
contract Cat : Animal =
|
||||
entrypoint sound() = "meow"
|
||||
|
||||
main contract Main =
|
||||
entrypoint oracle() = ok_2YNyxd6TRJPNrTcEDCe9ra59SVUdp9FR9qWC5msKZWYD9bP9z5
|
||||
|
||||
entrypoint query() = oq_2oRvyowJuJnEkxy58Ckkw77XfWJrmRgmGaLzhdqb67SKEL1gPY
|
||||
|
||||
entrypoint init() =
|
||||
let o01 : oracle(Animal, Animal) = oracle() : oracle(Animal, Animal) // success
|
||||
let o02 : oracle(Animal, Animal) = oracle() : oracle(Animal, Cat) // success
|
||||
let o03 : oracle(Animal, Animal) = oracle() : oracle(Cat, Animal) // fail
|
||||
let o04 : oracle(Animal, Animal) = oracle() : oracle(Cat, Cat) // fail
|
||||
let o05 : oracle(Animal, Cat) = oracle() : oracle(Animal, Animal) // fail
|
||||
let o06 : oracle(Animal, Cat) = oracle() : oracle(Animal, Cat) // success
|
||||
let o07 : oracle(Animal, Cat) = oracle() : oracle(Cat, Animal) // fail
|
||||
let o08 : oracle(Animal, Cat) = oracle() : oracle(Cat, Cat) // fail
|
||||
let o09 : oracle(Cat, Animal) = oracle() : oracle(Animal, Animal) // success
|
||||
let o10 : oracle(Cat, Animal) = oracle() : oracle(Animal, Cat) // success
|
||||
let o11 : oracle(Cat, Animal) = oracle() : oracle(Cat, Animal) // success
|
||||
let o12 : oracle(Cat, Animal) = oracle() : oracle(Cat, Cat) // success
|
||||
let o13 : oracle(Cat, Cat) = oracle() : oracle(Animal, Animal) // fail
|
||||
let o14 : oracle(Cat, Cat) = oracle() : oracle(Animal, Cat) // success
|
||||
let o15 : oracle(Cat, Cat) = oracle() : oracle(Cat, Animal) // fail
|
||||
let o16 : oracle(Cat, Cat) = oracle() : oracle(Cat, Cat) // success
|
||||
|
||||
let q01 : oracle_query(Animal, Animal) = query() : oracle_query(Animal, Animal) // success
|
||||
let q02 : oracle_query(Animal, Animal) = query() : oracle_query(Animal, Cat) // success
|
||||
let q03 : oracle_query(Animal, Animal) = query() : oracle_query(Cat, Animal) // success
|
||||
let q04 : oracle_query(Animal, Animal) = query() : oracle_query(Cat, Cat) // success
|
||||
let q05 : oracle_query(Animal, Cat) = query() : oracle_query(Animal, Animal) // fail
|
||||
let q06 : oracle_query(Animal, Cat) = query() : oracle_query(Animal, Cat) // success
|
||||
let q07 : oracle_query(Animal, Cat) = query() : oracle_query(Cat, Animal) // fail
|
||||
let q08 : oracle_query(Animal, Cat) = query() : oracle_query(Cat, Cat) // success
|
||||
let q09 : oracle_query(Cat, Animal) = query() : oracle_query(Animal, Animal) // fail
|
||||
let q10 : oracle_query(Cat, Animal) = query() : oracle_query(Animal, Cat) // fail
|
||||
let q11 : oracle_query(Cat, Animal) = query() : oracle_query(Cat, Animal) // success
|
||||
let q12 : oracle_query(Cat, Animal) = query() : oracle_query(Cat, Cat) // success
|
||||
let q13 : oracle_query(Cat, Cat) = query() : oracle_query(Animal, Animal) // fail
|
||||
let q14 : oracle_query(Cat, Cat) = query() : oracle_query(Animal, Cat) // fail
|
||||
let q15 : oracle_query(Cat, Cat) = query() : oracle_query(Cat, Animal) // fail
|
||||
let q16 : oracle_query(Cat, Cat) = query() : oracle_query(Cat, Cat) // success
|
||||
|
||||
()
|
||||
@@ -1,51 +0,0 @@
|
||||
contract interface Animal =
|
||||
entrypoint sound : () => string
|
||||
|
||||
contract Cat : Animal =
|
||||
entrypoint sound() = "meow"
|
||||
|
||||
main contract Main =
|
||||
record rec_co('a) = { x : 'a ,
|
||||
y : () => 'a }
|
||||
record rec_contra('a) = { x : 'a => unit }
|
||||
record rec_inv('a) = { x : 'a => unit,
|
||||
y : () => 'a }
|
||||
record rec_biv('a) = { x : int }
|
||||
|
||||
stateful entrypoint new_cat() : Cat = Chain.create()
|
||||
stateful entrypoint new_animal() : Animal = new_cat()
|
||||
stateful entrypoint animal_to_unit(_ : Animal) : unit = ()
|
||||
stateful entrypoint cat_to_unit(_ : Cat) : unit = ()
|
||||
stateful entrypoint unit_to_animal() : Animal = new_animal()
|
||||
stateful entrypoint unit_to_cat() : Cat = new_cat()
|
||||
|
||||
stateful entrypoint init() =
|
||||
let ra : rec_co(Animal) = { x = new_animal(), y = unit_to_animal }
|
||||
let rc : rec_co(Cat) = { x = new_cat(), y = unit_to_cat }
|
||||
let r01 : rec_co(Animal) = ra // success
|
||||
let r02 : rec_co(Animal) = rc // success
|
||||
let r03 : rec_co(Cat) = ra // fail
|
||||
let r04 : rec_co(Cat) = rc // sucess
|
||||
|
||||
let ratu : rec_contra(Animal) = { x = animal_to_unit }
|
||||
let rctu : rec_contra(Cat) = { x = cat_to_unit }
|
||||
let r05 : rec_contra(Animal) = ratu // success
|
||||
let r06 : rec_contra(Animal) = rctu // fail
|
||||
let r07 : rec_contra(Cat) = ratu // success
|
||||
let r08 : rec_contra(Cat) = rctu // success
|
||||
|
||||
let rxaya : rec_inv(Animal) = { x = animal_to_unit, y = unit_to_animal }
|
||||
let rxcyc : rec_inv(Cat) = { x = cat_to_unit, y = unit_to_cat }
|
||||
let r09 : rec_inv(Animal) = rxaya // success
|
||||
let r10 : rec_inv(Animal) = rxcyc // fail
|
||||
let r11 : rec_inv(Cat) = rxaya // fail
|
||||
let r12 : rec_inv(Cat) = rxcyc // success
|
||||
|
||||
let rba : rec_biv(Animal) = { x = 1 }
|
||||
let rbc : rec_biv(Cat) = { x = 1 }
|
||||
let r13 : rec_biv(Animal) = rba // success
|
||||
let r14 : rec_biv(Animal) = rbc // success
|
||||
let r15 : rec_biv(Cat) = rba // success
|
||||
let r16 : rec_biv(Cat) = rbc // success
|
||||
|
||||
()
|
||||
@@ -1,5 +0,0 @@
|
||||
payable contract interface SalesOffer =
|
||||
entrypoint init : (address, address, int, int) => unit
|
||||
|
||||
payable contract Test : SalesOffer =
|
||||
entrypoint init(_, _, _, _) = ()
|
||||
@@ -1,5 +0,0 @@
|
||||
payable contract interface SalesOffer =
|
||||
entrypoint init : (address, address, int, int) => void
|
||||
|
||||
payable contract Test : SalesOffer =
|
||||
entrypoint init(_ : address, _ : address, _ : int, _ : int) = ()
|
||||
@@ -1,9 +0,0 @@
|
||||
contract First =
|
||||
entrypoint print_num(x) = 1 + x
|
||||
|
||||
contract Second =
|
||||
entrypoint print_num() = 1
|
||||
|
||||
main contract Test =
|
||||
entrypoint f(c) = c.print_num(1)
|
||||
entrypoint g(c) = c.print_num()
|
||||
@@ -1,4 +1,7 @@
|
||||
|
||||
contract interface SpendContract =
|
||||
entrypoint withdraw : (int) => int
|
||||
|
||||
contract SpendTest =
|
||||
|
||||
stateful entrypoint spend(to, amount) =
|
||||
|
||||
+4
-12
@@ -1,12 +1,4 @@
|
||||
// This is a custom test file if you need to run a compiler without
|
||||
// changing aeso_compiler_tests.erl
|
||||
|
||||
include "List.aes"
|
||||
|
||||
contract IntegerHolder =
|
||||
type state = int
|
||||
entrypoint init(x) = x
|
||||
entrypoint get() = state
|
||||
|
||||
main contract Test =
|
||||
stateful entrypoint f(c) = Chain.clone(ref=c, 123)
|
||||
contract ShareTwo =
|
||||
record state = {s1 : int, s2 : int}
|
||||
entrypoint init() = {s1 = 0, s2 = 0}
|
||||
stateful entrypoint buy() = ()
|
||||
@@ -2,10 +2,10 @@
|
||||
// Named argument builtins are:
|
||||
// Oracle.register
|
||||
// Oracle.respond
|
||||
// AENSv2.preclaim
|
||||
// AENSv2.claim
|
||||
// AENSv2.transfer
|
||||
// AENSv2.revoke
|
||||
// AENS.preclaim
|
||||
// AENS.claim
|
||||
// AENS.transfer
|
||||
// AENS.revoke
|
||||
// Oracle.extend
|
||||
include "String.aes"
|
||||
contract UnappliedBuiltins =
|
||||
@@ -28,7 +28,7 @@ contract UnappliedBuiltins =
|
||||
function oracle_get_answer() = Oracle.get_answer : (o, _) => _
|
||||
function oracle_check() = Oracle.check : o => _
|
||||
function oracle_check_query() = Oracle.check_query : (o, _) => _
|
||||
function aens_resolve() = AENSv2.resolve : (_, _) => option(string)
|
||||
function aens_resolve() = AENS.resolve : (_, _) => option(string)
|
||||
function map_lookup() = Map.lookup : (_, m) => _
|
||||
function map_lookup_default() = Map.lookup_default : (_, m, _) => _
|
||||
function map_member() = Map.member : (_, m) => _
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user