Compare commits

..

6 Commits

Author SHA1 Message Date
Hans Svensson 8e191b0c88 [Ceres]: Document generic all names delegation signatures (#440) 2023-03-22 08:55:57 +01:00
Hans Svensson f70fc56df8 Ceres: document changes to Auth.tx_hash (#439) 2023-03-03 10:06:45 +01:00
Hans Svensson 4ae24722f4 Remove unused variable in AENSCompat 2022-12-01 08:33:59 +01:00
Hans Svensson 55a97852ed Introduce AENSv2 namespace to introduce raw data pointers (#426) 2022-11-16 21:31:44 +01:00
Hans Svensson 1380142082 Add bitwise operations, Address.to_bytes and Crypto.poseidon 2022-11-11 16:15:05 +01:00
Hans Svensson 1754763e23 Let CERES compiler be v8.0.0 tentatively 2022-11-04 10:30:04 +01:00
90 changed files with 2368 additions and 3506 deletions
+3 -3
View File
@@ -1,5 +1,5 @@
mkdocs==1.4.2 mkdocs==1.2.4
mkdocs-simple-hooks==0.1.5 mkdocs-simple-hooks==0.1.5
mkdocs-material==9.0.9 mkdocs-material==7.3.6
mike==1.1.2 mike==1.1.2
pygments==2.17.2 pygments==2.12.0
-1
View File
@@ -24,4 +24,3 @@ current_counterexample.eqc
test/contracts/test.aes test/contracts/test.aes
__pycache__ __pycache__
.docssite/docs/*.md .docssite/docs/*.md
.vscode
+5 -80
View File
@@ -4,18 +4,7 @@ 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/), 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). and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [Unreleased] ## [CERES 8.0.0]
### Added
- Added a check for number of type variables in a type signature; it is serialized using 8 bits,
so the upper limit is 256.
### Changed
### Removed
## [8.0.1]
### Changed
- Upgrade aebytecode to v3.4.1 to fix C warnings
## [8.0.0]
### Added ### Added
- Bitwise operations for integers: `band`, `bor`, `bxor`, `bnot`, `<<` and `>>`. - Bitwise operations for integers: `band`, `bor`, `bxor`, `bnot`, `<<` and `>>`.
- `Int.mulmod` - combined builtin operation for multiplication and modulus. - `Int.mulmod` - combined builtin operation for multiplication and modulus.
@@ -23,70 +12,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- `Address.to_bytes` - convert an address to its binary representation (for hashing, etc.). - `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 - 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 `AENSv2`; they contain types similar to the old `AENS`; `AENS.name` and
`AENS.pointee`, where the latter now has a constructor `DataPt(bytes())`. All `AENS.pointee`, where the latter now has a constructor `DataPt(string)`. All
AENS actions have been moved to `AENSv2`, and `AENSv2.lookup` and AENS actions have been moved to `AENSv2`, and `AENSv2.lookup` and
`AENSv2.update` consume and produce the new types. The old `AENS` namespace `AENSv2.update` consume and produce the new types. The old `AENS` namespace
only contains the old datatypes, that can be used to interface existing only contains the old datatypes, that can be used to interface existing
contracts. Standard library `AENSCompat` is added to convert between old and contracts. Standard library `AENSCompat` is added to convert between old and
new pointers. new pointers.
- Introduce arbitrary sized binary arrays (type `bytes()`); adding `Bytes.split_any`,
`Bytes.to_fixed_size`, `Bytes.to_any_size`, `Bytes.size`, `String.to_bytes`,
and `Int.to_bytes`; and adjust `Bytes.concat` to allow both fixed and arbitrary
sized byte arrays.
- `Chain.network_id` - a function to get hold of the Chain's network id.
- Allowing `Bytes.to_any_size` in calldata creation, to enable creation of arguments
with arbitray size.
- Signature literals `sg_...` - they have type `signature` (which is an alias for `bytes(64)`).
- Support for OTP-27 - no changes in behavior.
### Changed ### Changed
- `Crypto.verify_sig` is changed to have `msg : bytes()`. I.e. the
signed data can be of any length (used to be limited to `bytes(32)`/`hash`).
- System aliases are handled explicitly when converting to a Sophia value, this is only
observable for `signature` where a value of type `signature` is now represented as a
(new) signature literal.
- Allow self-qualification, i.e. referencing `X.foo` when in namespace `X`.
### Removed ### Removed
- `Bitwise.aes` standard library is removed - the builtin operations are superior. - `Bitwise.aes` standard library is removed - the builtin operations are superior.
## [7.4.1] ## [Unreleased]
### Changed
- Improve how includes with relative paths are resolved during parsing/compilation. Relative
include paths are now always relative to the file containing the `include` statement.
### Fixed
- Disable unused type warnings for types used inside of records.
## [7.4.0]
### Changed
- Names of lifted lambdas now consist of parent function's name and their
position in the source code.
### Fixed
- Lifted lambdas get their names assigned deterministically.
## [7.3.0]
### Fixed
- Fixed a bug with polymorphism that allowed functions with the same name but different type to be considered as implementations for their corresponding interface function.
- Fixed a bug in the byte code optimization that incorrectly reordered dependent instructions.
## [7.2.1]
### Fixed
- Fixed bugs with the newly added debugging symbols
## [7.2.0]
### Added
- Toplevel compile-time constants
```
namespace N =
let nc = 1
contract C =
let cc = 2
```
- API functions for encoding/decoding Sophia values to/from FATE.
### Removed
- Remove the mapping from variables to FATE registers from the compilation output.
### Fixed
- Warning about unused include when there is no include.
## [7.1.0]
### Added ### Added
- Options to enable/disable certain optimizations. - Options to enable/disable certain optimizations.
- The ability to call a different instance of the current contract - The ability to call a different instance of the current contract
@@ -96,12 +32,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
entrypoint f(c : Main) : int = c.spend(10) entrypoint f(c : Main) : int = c.spend(10)
``` ```
- Return a mapping from variables to FATE registers in the compilation output. - Return a mapping from variables to FATE registers in the compilation output.
- Hole expression.
### Changed ### Changed
- Type definitions serialised to ACI as `typedefs` field instead of `type_defs` to increase compatibility. - Type definitions serialised to ACI as `typedefs` field instead of `type_defs` to increase compatibility.
- Check contracts and entrypoints modifiers when implementing interfaces. ### Removed
- Contracts can no longer be used as namespaces.
- Do not show unused stateful warning for functions that call other contracts with a non-zero value argument.
### Fixed ### Fixed
- Typechecker crashes if Chain.create or Chain.clone are used without arguments. - Typechecker crashes if Chain.create or Chain.clone are used without arguments.
@@ -456,15 +389,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 - Simplify calldata creation - instead of passing a compiled contract, simply
pass a (stubbed) contract string. pass a (stubbed) contract string.
[Unreleased]: https://github.com/aeternity/aesophia/compare/v8.0.1...HEAD [Unreleased]: https://github.com/aeternity/aesophia/compare/v7.0.1...HEAD
[8.0.1]: https://github.com/aeternity/aesophia/compare/v8.0.0...v8.0.1
[8.0.0]: https://github.com/aeternity/aesophia/compare/v7.4.1...v8.0.0
[7.4.1]: https://github.com/aeternity/aesophia/compare/v7.4.0...v7.4.1
[7.4.0]: https://github.com/aeternity/aesophia/compare/v7.3.0...v7.4.0
[7.3.0]: https://github.com/aeternity/aesophia/compare/v7.2.1...v7.3.0
[7.2.1]: https://github.com/aeternity/aesophia/compare/v7.2.0...v7.2.1
[7.2.0]: https://github.com/aeternity/aesophia/compare/v7.1.0...v7.2.0
[7.1.0]: https://github.com/aeternity/aesophia/compare/v7.0.1...v7.1.0
[7.0.1]: https://github.com/aeternity/aesophia/compare/v7.0.0...v7.0.1 [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 [7.0.0]: https://github.com/aeternity/aesophia/compare/v6.1.0...v7.0.0
[6.1.0]: https://github.com/aeternity/aesophia/compare/v6.0.2...v6.1.0 [6.1.0]: https://github.com/aeternity/aesophia/compare/v6.0.2...v6.1.0
+2
View File
@@ -53,6 +53,8 @@ The **pp_** options all print to standard output the following:
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 `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: #### Options to control which compiler optimizations should run:
By default all optimizations are turned on, to disable an optimization, it should be By default all optimizations are turned on, to disable an optimization, it should be
+21 -129
View File
@@ -84,7 +84,7 @@ the return value of the call.
```sophia ```sophia
contract interface VotingType = contract interface VotingType =
entrypoint vote : string => unit entrypoint : vote : string => unit
contract Voter = contract Voter =
entrypoint tryVote(v : VotingType, alt : string) = entrypoint tryVote(v : VotingType, alt : string) =
@@ -191,20 +191,9 @@ contract interface X : Z =
entrypoint z() = 1 entrypoint z() = 1
``` ```
#### Adding or removing modifiers
When a `contract` or a `contract interface` implements another `contract interface`, the `payable` and `stateful` modifiers can be kept or changed, both in the contract and in the entrypoints, according to the following rules:
1. A `payable` contract or interface can implement a `payable` interface or a non-`payable` interface.
2. A non-`payable` contract or interface can only implement a non-`payable` interface, and cannot implement a `payable` interface.
3. A `payable` entrypoint can implement a `payable` entrypoint or a non-`payable` entrypoint.
4. A non-`payable` entrypoint can only implement a non-`payable` entrypoint, and cannot implement a `payable` entrypoint.
5. A non-`stateful` entrypoint can implement a `stateful` entrypoint or a non-`stateful` entrypoint.
6. A `stateful` entrypoint can only implement a `stateful` entrypoint, and cannot implement a non-`stateful` entrypoint.
#### Subtyping and variance #### 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)), 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. >Variance refers to how subtyping between more complex types relates to subtyping between their components.
@@ -224,11 +213,11 @@ A good example of where it matters can be pictured by subtyping of function type
```sophia ```sophia
contract interface Animal = contract interface Animal =
entrypoint age : () => int entrypoint age : () => int
contract Dog : Animal = contract Dog : Animal =
entrypoint age() = // ... entrypoint age() = // ...
entrypoint woof() = "woof" entrypoint woof() = "woof"
contract Cat : Animal = contract Cat : Animal =
entrypoint age() = // ... entrypoint age() = // ...
entrypoint meow() = "meow" entrypoint meow() = "meow"
@@ -256,10 +245,10 @@ datatype bi('a) = Bi // bi is bivariant on 'a
The following facts apply here: The following facts apply here:
- `co('a)` is a subtype of `co('b)` when `'a` is a subtype of `'b` - `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` - `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` - `in('a)` is a subtype of `in('b) when `'a` is equal to `'b`
- `bi('a)` is a subtype of `bi('b)` always - `bi('a)` is a subtype of `bi('b) always
That altogether induce the following rules of subtyping in Sophia: That altogether induce the following rules of subtyping in Sophia:
@@ -295,11 +284,6 @@ of `A`.
- When a user-defined type `t('a)` is invariant in `'a`, then `t(A)` can never be - When a user-defined type `t('a)` is invariant in `'a`, then `t(A)` can never be
a subtype of `t(B)`. a subtype of `t(B)`.
#### Type variable limitation
Because of how FATE represents types as values there is a fixed upper limit (256)
of type variables that can be used in a single type signature.
## Mutable state ## Mutable state
Sophia does not have arbitrary mutable state, but only a limited form of state Sophia does not have arbitrary mutable state, but only a limited form of state
@@ -498,24 +482,6 @@ the file, except that error messages will refer to the original source
locations. The language will try to include each file at most one time automatically, locations. The language will try to include each file at most one time automatically,
so even cyclic includes should be working without any special tinkering. so even cyclic includes should be working without any special tinkering.
### Include files using relative paths
When including code from another file using the `include` statement, the path
is relative to _the file that includes it_. Consider the following file tree:
```
c1.aes
c3.aes
dir1/c2.aes
dir1/c3.aes
```
If `c1.aes` contains `include "c3.aes"` it will include the top level `c3.aes`,
while if `c2.aes` contained the same line it would as expected include
`dir1/c3.aes`.
Note: Prior to v7.5.0, it would consider the include path relative to _the main
contract file_ (or any explicitly set include path).
## Standard library ## Standard library
Sophia offers [standard library](sophia_stdlib.md) which exposes some Sophia offers [standard library](sophia_stdlib.md) which exposes some
@@ -563,7 +529,6 @@ Sophia has the following types:
## Literals ## Literals
| Type | Constant/Literal example(s) | | Type | Constant/Literal example(s) |
| ---------- | ------------------------------- | | ---------- | ------------------------------- |
| unit | () |
| int | `-1`, `2425`, `4598275923475723498573485768` | | int | `-1`, `2425`, `4598275923475723498573485768` |
| address | `ak_2gx9MEFxKvY9vMG5YnqnXWv1hCsX7rgnfvBLJS4aQurustR1rt` | | address | `ak_2gx9MEFxKvY9vMG5YnqnXWv1hCsX7rgnfvBLJS4aQurustR1rt` |
| bool | `true`, `false` | | bool | `true`, `false` |
@@ -578,51 +543,12 @@ Sophia has the following types:
| state | `state{ owner = Call.origin, magic_key = #a298105f }` | | state | `state{ owner = Call.origin, magic_key = #a298105f }` |
| event | `EventX(0, "Hello")` | | event | `EventX(0, "Hello")` |
| hash | `#000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f` | | hash | `#000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f` |
| signature | `sg_MhibzTP1wWzGCTjtPFr1TiPqRJrrJqw7auvEuF5i3FdoALWqXLBDY6xxRRNUSPHK3EQTnTzF12EyspkxrSMxVHKsZeSMj`, `#000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f` | | signature | `#000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f` |
| Chain.ttl | `FixedTTL(1050)`, `RelativeTTL(50)` | | Chain.ttl | `FixedTTL(1050)`, `RelativeTTL(50)` |
| oracle('a, 'b) | `ok_2YNyxd6TRJPNrTcEDCe9ra59SVUdp9FR9qWC5msKZWYD9bP9z5` | | oracle('a, 'b) | `ok_2YNyxd6TRJPNrTcEDCe9ra59SVUdp9FR9qWC5msKZWYD9bP9z5` |
| oracle_query('a, 'b) | `oq_2oRvyowJuJnEkxy58Ckkw77XfWJrmRgmGaLzhdqb67SKEL1gPY` | | oracle_query('a, 'b) | `oq_2oRvyowJuJnEkxy58Ckkw77XfWJrmRgmGaLzhdqb67SKEL1gPY` |
| contract | `ct_Ez6MyeTMm17YnTnDdHTSrzMEBKmy7Uz2sXu347bTDPgVH2ifJ` | | contract | `ct_Ez6MyeTMm17YnTnDdHTSrzMEBKmy7Uz2sXu347bTDPgVH2ifJ` |
## Hole expression
Hole expressions, written as `???`, are expressions that are used as a placeholder. During compilation, the compiler will generate a type error indication the type of the hole expression.
```
include "List.aes"
contract C =
entrypoint f() =
List.sum(List.map(???, [1,2,3]))
```
A hole expression found in the example above will generate the error `` Found a hole of type `(int) => int` ``. This says that the compiler expects a function from `int` to `int` in place of the `???` placeholder.
## Constants
Constants in Sophia are contract-level bindings that can be used in either contracts or namespaces. The value of a constant can be a literal, another constant, or arithmetic operations applied to other constants. Lists, tuples, maps, and records can also be used to define a constant as long as their elements are also constants.
The following visibility rules apply to constants:
* Constants defined inside a contract are private in that contract. Thus, cannot be accessed through instances of their defining contract.
* Constants defined inside a namespace are public. Thus, can be used in other contracts or namespaces.
* Constants cannot be defined inside a contract interface.
When a constant is shadowed, it can be accessed using its qualified name:
```
contract C =
let c = 1
entrypoint f() =
let c = 2
c + C.c // the result is 3
```
The name of the constant must be an id; therefore, no pattern matching is allowed when defining a constant:
```
contract C
let x::y::_ = [1,2,3] // this will result in an error
```
## Arithmetic ## Arithmetic
Sophia integers (`int`) are represented by arbitrary-sized signed words and support the following Sophia integers (`int`) are represented by arbitrary-sized signed words and support the following
@@ -634,7 +560,7 @@ arithmetic operations:
- remainder (`x mod y`), satisfying `y * (x / y) + x mod y == x` for non-zero `y` - remainder (`x mod y`), satisfying `y * (x / y) + x mod y == x` for non-zero `y`
- exponentiation (`x ^ y`) - exponentiation (`x ^ y`)
All operations are *safe* with respect to overflow and underflow. All operations are *safe* with respect to overflow and underflow.
The division and modulo operations throw an arithmetic error if the The division and modulo operations throw an arithmetic error if the
right-hand operand is zero. right-hand operand is zero.
@@ -646,16 +572,10 @@ Sophia arbitrary-sized integers (FATE) also supports the following bitwise opera
- arithmetic bitshift left (`x << n`) - arithmetic bitshift left (`x << n`)
- arithmetic bitshift right (`x >> n`) - arithmetic bitshift right (`x >> n`)
Note: Arithmetic bitshift treats the number as a signed integer (in 2s
complement), and "retains" the topmost bit. I.e. shifting in zeros if the
topmost bit was 0, and ones if it was one.
## Bit fields ## Bit fields
Originally Sophia integers did not support bit arithmetic. Instead we used a Sophia integers do not support bit arithmetic. Instead there is a separate
separate type `bits` (see the standard library type `bits`. See the standard library [documentation](sophia_stdlib.md#bits).
[documentation](sophia_stdlib.md#bits)) - it is still provided as an
alternative to bit arithmetic.
A bit field can be of arbitrary size (but it is still represented by the A bit field can be of arbitrary size (but it is still represented by the
corresponding integer, so setting very high bits can be expensive). corresponding integer, so setting very high bits can be expensive).
@@ -960,18 +880,16 @@ functions are provided.
## AENS interface ## AENS interface
Contracts can interact with the [æternity naming Contracts can interact with the
system](https://github.com/aeternity/protocol/blob/master/AENS.md). For this [æternity naming system](https://github.com/aeternity/protocol/blob/master/AENS.md).
purpose the [AENS](sophia_stdlib.md#aens) and later the For this purpose the [AENS](sophia_stdlib.md#aens) library was exposed.
[AENSv2](sophia_stdlib.md#aensv2) library was exposed.
### Example ### Example
In this example we assume that the name `name` already exists, and is owned by In this example we assume that the name `name` already exists, and is owned by
an account with address `addr`. In order to allow a contract `ct` to handle an account with address `addr`. In order to allow a contract `ct` to handle
`name` the account holder needs to create a [delegation `name` the account holder needs to create a
signature](#delegation-signature) `sig` from the name owner address `addr`, the [signature](#delegation-signature) `sig` of `addr | name.hash | ct.address`.
name hash and the contract address.
Armed with this information we can for example write a function that extends Armed with this information we can for example write a function that extends
the name if it expires within 1000 blocks: the name if it expires within 1000 blocks:
@@ -1113,34 +1031,8 @@ however is in the gas consumption — while `abort` returns unused gas, a call t
## Delegation signature ## Delegation signature
Some chain operations (`Oracle.<operation>` and `AENSv2.<operation>`) have an Some chain operations (`Oracle.<operation>` and `AENS.<operation>`) have an
optional delegation signature. This is typically used when a user/accounts optional delegation signature. This is typically used when a user/accounts
would like to allow a contract to act on it's behalf. would like to allow a contract to act on it's behalf. The exact data to be
signed varies for the different operations, but in all cases you should prepend
### From Ceres the signature data with the `network_id` (`ae_mainnet` for the æternity mainnet, etc.).
From the Ceres protocol version the delegation signatures have more structure,
including a unique tag, `network_id` and identifiers; there are five different
delegation signatures:
- AENS wildcard - the user signs: `owner account + contract`
- `AENS_PRECLAIM` - the user signs: `owner account + contract`
- `AENS_CLAIM, AENS_UPDATE, AENS_TRANSFER, AENS_REVOKE` - the user signs: `owner account + name hash + contract`
- `ORACLE_REGISTER, ORACLE_EXTEND` - the user signs: `owner account + contract`
- `ORACLE_RESPOND` - the user signs: `query id + contract`
See [Serialized signature
data](https://github.com/aeternity/protocol/blob/master/contracts/fate.md#from-ceres-serialized-signature-data)
for the exact structure used.
### Before ceres
The exact data to be signed varies for the different operations, but in all
cases you should prepend the signature data with the `network_id` (`ae_mainnet`
for the æternity mainnet, etc.).
There are four different delegation signatures:
- `AENS_PRECLAIM` - the user signs: owner `network_id + account + contract`
- `AENS_CLAIM, AENS_UPDATE, AENS_TRANSFER, AENS_REVOKE` - the user signs: `network_id + owner account + name hash + contract`
- `ORACLE_REGISTER, ORACLE_EXTEND` - the user signs: `network_id + owner account + contract`
- `ORACLE_RESPOND` - the user signs: `network_id + query id + contract`
+93 -173
View File
@@ -57,12 +57,6 @@ Address.to_str(a : address) : string
Base58 encoded string Base58 encoded string
#### to_bytes
```
Address.to_bytes(a : address) : bytes(32)
```
The binary representation of the address.
#### is_contract #### is_contract
``` ```
@@ -142,11 +136,11 @@ datatype name = Name(address, Chain.ttl, map(string, AENSv2.pointee))
``` ```
datatype pointee = AccountPt(address) | OraclePt(address) datatype pointee = AccountPt(address) | OraclePt(address)
| ContractPt(address) | ChannelPt(address) | DataPt(bytes()) | ContractPt(address) | ChannelPt(address) | DataPt(string)
``` ```
Note: on-chain there is a maximum length enforced for `DataPt`, it is 1024 bytes. Note: on-chain there is a maximum length enforced for `DataPt`, it is 1024 bytes.
Sophia itself does _not_ check for this. Sophia itself does _not_ enforce this.
#### Functions #### Functions
@@ -181,14 +175,14 @@ Note: Changed to produce `AENSv2.name` in v8.0 (Ceres protocol upgrade).
AENSv2.preclaim(owner : address, commitment_hash : hash, <signature : signature>) : unit AENSv2.preclaim(owner : address, commitment_hash : hash, <signature : signature>) : unit
``` ```
The [signature](./sophia_features.md#delegation-signature) should be a The [signature](./sophia_features.md#delegation-signature) should be over
serialized structure containing `network id`, `owner address`, and `network id` + `owner address` + `Contract.address` (concatenated as byte arrays).
`Contract.address`.
From Ceres (i.e. FATE VM version 3) the From Ceres (i.e. FATE VM version 3) the
[signature](./sophia_features.md#delegation-signature) can also be generic [signature](./sophia_features.md#delegation-signature) can also be generic
(allowing _all_, existing and future, names to be delegated with one (allowing _all_, existing and future, names to be delegated with one
signature), i.e. containing `network id`, `owner address`, `Contract.address`. signature), i.e. over `network id` + `owner address` + `string "AENS"` +
`Contract.address`.
##### claim ##### claim
@@ -196,14 +190,14 @@ signature), i.e. containing `network id`, `owner address`, `Contract.address`.
AENSv2.claim(owner : address, name : string, salt : int, name_fee : int, <signature : signature>) : unit AENSv2.claim(owner : address, name : string, salt : int, name_fee : int, <signature : signature>) : unit
``` ```
The [signature](./sophia_features.md#delegation-signature) should be a The [signature](./sophia_features.md#delegation-signature) should be over
serialized structure containing `network id`, `owner address`, and `network id` + `owner address` + `name_hash` + `Contract.address` (concatenated
`Contract.address`. Using the private key of `owner address` for signing. as byte arrays) using the private key of the `owner` account for signing.
From Ceres (i.e. FATE VM version 3) the From Ceres (i.e. FATE VM version 3) the
[signature](./sophia_features.md#delegation-signature) can also be generic [signature](./sophia_features.md#delegation-signature) can also be generic
(allowing _all_, existing and future, names to be delegated with one (allowing _all_, existing and future, names to be delegated with one
signature), i.e. containing `network id`, `owner address`, `name_hash`, and signature), i.e. over `network id` + `owner address` + `string "AENS"` +
`Contract.address`. `Contract.address`.
@@ -214,14 +208,15 @@ AENSv2.transfer(owner : address, new_owner : address, name : string, <signature
Transfers name to the new owner. Transfers name to the new owner.
The [signature](./sophia_features.md#delegation-signature) should be a The [signature](./sophia_features.md#delegation-signature) should be over
serialized structure containing `network id`, `owner address`, and `network id` + `owner address` + `name_hash` + `Contract.address`
`Contract.address`. Using the private key of `owner address` for signing. (concatenated as byte arrays)
using the private key of the `owner` account for signing.
From Ceres (i.e. FATE VM version 3) the From Ceres (i.e. FATE VM version 3) the
[signature](./sophia_features.md#delegation-signature) can also be generic [signature](./sophia_features.md#delegation-signature) can also be generic
(allowing _all_, existing and future, names to be delegated with one (allowing _all_, existing and future, names to be delegated with one
signature), i.e. containing `network id`, `owner address`, `name_hash`, and signature), i.e. over `network id` + `owner address` + `string "AENS"` +
`Contract.address`. `Contract.address`.
@@ -232,21 +227,22 @@ AENSv2.revoke(owner : address, name : string, <signature : signature>) : unit
Revokes the name to extend the ownership time. Revokes the name to extend the ownership time.
The [signature](./sophia_features.md#delegation-signature) should be a The [signature](./sophia_features.md#delegation-signature) should be over
serialized structure containing `network id`, `owner address`, and `network id` + `owner address` + `name_hash` + `Contract.address`
`Contract.address`. Using the private key of `owner address` for signing. (concatenated as byte arrays)
using the private key of the `owner` account for signing.
From Ceres (i.e. FATE VM version 3) the From Ceres (i.e. FATE VM version 3) the
[signature](./sophia_features.md#delegation-signature) can also be generic [signature](./sophia_features.md#delegation-signature) can also be generic
(allowing _all_, existing and future, names to be delegated with one (allowing _all_, existing and future, names to be delegated with one
signature), i.e. containing `network id`, `owner address`, `name_hash`, and signature), i.e. over `network id` + `owner address` + `string "AENS"` +
`Contract.address`. `Contract.address`.
##### update ##### update
``` ```
AENSv2.update(owner : address, name : string, expiry : option(Chain.ttl), client_ttl : option(int), AENSv2.update(owner : address, name : string, expiry : option(Chain.ttl), client_ttl : option(int),
new_ptrs : option(map(string, AENSv2.pointee)), <signature : signature>) : unit new_ptrs : map(string, AENSv2.pointee), <signature : signature>) : unit
``` ```
Updates the name. If the optional parameters are set to `None` that parameter Updates the name. If the optional parameters are set to `None` that parameter
@@ -255,16 +251,6 @@ block of the name is not changed.
Note: Changed to consume `AENSv2.pointee` in v8.0 (Ceres protocol upgrade). Note: Changed to consume `AENSv2.pointee` in v8.0 (Ceres protocol upgrade).
The [signature](./sophia_features.md#delegation-signature) should be a
serialized structure containing `network id`, `owner address`, and
`Contract.address`. Using the private key of `owner address` 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. containing `network id`, `owner address`, `name_hash`, and
`Contract.address`.
### Auth ### Auth
@@ -385,7 +371,7 @@ Each bit is true if and only if it was 1 in `a` and 0 in `b`
### Bytes ### Bytes
#### to\_int #### to_int
``` ```
Bytes.to_int(b : bytes(n)) : int Bytes.to_int(b : bytes(n)) : int
``` ```
@@ -393,7 +379,7 @@ Bytes.to_int(b : bytes(n)) : int
Interprets the byte array as a big endian integer Interprets the byte array as a big endian integer
#### to\_str #### to_str
``` ```
Bytes.to_str(b : bytes(n)) : string Bytes.to_str(b : bytes(n)) : string
``` ```
@@ -406,8 +392,7 @@ Returns the hexadecimal representation of the byte array
Bytes.concat : (a : bytes(m), b : bytes(n)) => bytes(m + n) Bytes.concat : (a : bytes(m), b : bytes(n)) => bytes(m + n)
``` ```
Concatenates two byte arrays. If `m` and `n` are known at compile time, the Concatenates two byte arrays
result can be used as a fixed size byte array, otherwise it has type `bytes()`.
#### split #### split
@@ -417,38 +402,6 @@ Bytes.split(a : bytes(m + n)) : bytes(m) * bytes(n)
Splits a byte array at given index Splits a byte array at given index
#### split\_any
```
Bytes.split_any(a : bytes(), at : int) : option(bytes() * bytes(n))
```
Splits an arbitrary size byte array at index `at`. If `at` is positive split
from the beginning of the array, if `at` is negative, split `abs(at)` from the
_end_ of the array. If the array is shorter than `abs(at)` then `None` is
returned.
#### to\_fixed\_size
```
Bytes.to_fixed_size(a : bytes()) : option(bytes(n))
```
Converts an arbitrary size byte array to a fix size byte array. If `a` is
not `n` bytes, `None` is returned.
#### to\_any\_size
```
Bytes.to_any_size(a : bytes(n)) : bytes()
```
Converts a fixed size byte array to an arbitrary size byte array. This is a
no-op at run-time, and only used during type checking.
#### size
```
Bytes.size(a : bytes()) : int
```
Computes the lenght/size of a byte array.
### Call ### Call
@@ -578,6 +531,46 @@ Chain.block_height : int"
The height of the current block (i.e. the block in which the current call will be included). 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
```
Chain.coinbase : address
```
The address of the account that mined the current block.
##### timestamp
```
Chain.timestamp : int
```
The timestamp of the current block.
##### difficulty
```
Chain.difficulty : int
```
The difficulty of the current block.
##### gas
```
Chain.gas_limit : int
```
The gas limit of the current block.
##### bytecode_hash ##### bytecode_hash
``` ```
Chain.bytecode_hash : 'c => option(hash) Chain.bytecode_hash : 'c => option(hash)
@@ -614,6 +607,14 @@ 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 in the `init` call of the new contract. It will be included in
`Contract.balance`, however. `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. The type `'c` must be instantiated with a contract.
@@ -640,7 +641,6 @@ main contract Market =
The typechecker must be certain about the created contract's type, so it is The typechecker must be certain about the created contract's type, so it is
worth writing it explicitly as shown in the example. worth writing it explicitly as shown in the example.
##### clone ##### clone
``` ```
Chain.clone : ( ref : 'c, gas : int, value : int, protected : bool, ... Chain.clone : ( ref : 'c, gas : int, value : int, protected : bool, ...
@@ -679,8 +679,8 @@ Example usage:
``` ```
payable contract interface Auction = payable contract interface Auction =
entrypoint init : (int, string) => void entrypoint init : (int, string) => void
stateful payable entrypoint buy : (int) => unit stateful payable entrypoint buy : (int) => ()
stateful entrypoint sell : (int) => unit stateful entrypoint sell : (int) => ()
main contract Market = main contract Market =
type state = list(Auction) type state = list(Auction)
@@ -699,71 +699,11 @@ implementation of the `init` function does not actually return `state`, but
calls `put` instead. Moreover, FATE prevents even handcrafted calls to `init`. calls `put` instead. Moreover, FATE prevents even handcrafted calls to `init`.
##### coinbase
```
Chain.coinbase : address
```
The address of the account that mined the current block.
##### difficulty
```
Chain.difficulty : int
```
The difficulty of the current block.
##### event ##### event
``` ```
Chain.event(e : event) : unit Chain.event(e : event) : unit
``` ```
Emits the event. To use this function one needs to define the `event` type as a `datatype` in the contract.
Emits the event. To use this function one needs to define the `event` type as a
`datatype` in the contract.
##### gas\_limit
```
Chain.gas_limit : int
```
The gas limit of the current block.
##### network\_id
```
Chain.network\_id : string
```
The network id of the chain.
#### 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.
##### spend
```
Chain.spend(to : address, amount : int) : unit
```
Spend `amount` tokens to `to`. Will fail (and abort the contract) if contract
doesn't have `amount` tokens to transfer, or, if `to` is not `payable`.
##### timestamp
```
Chain.timestamp : int
```
The timestamp of the current block (unix time, milliseconds).
### Char ### Char
@@ -841,14 +781,11 @@ Hash any object to blake2b
#### verify_sig #### verify_sig
``` ```
Crypto.verify_sig(msg : bytes(), pubkey : address, sig : signature) : bool Crypto.verify_sig(msg : hash, pubkey : address, sig : signature) : bool
``` ```
Checks if the signature of `msg` was made using private key corresponding to Checks if the signature of `msg` was made using private key corresponding to
the `pubkey`. the `pubkey`
Note: before v8 of the compiler, `msg` had type `hash` (i.e. `bytes(32)`).
#### ecverify_secp256k1 #### ecverify_secp256k1
``` ```
@@ -881,21 +818,12 @@ Verifies a standard 64-byte ECDSA signature (`R || S`).
### Int ### Int
#### to\_str #### to_str
``` ```
Int.to_str(n : int) : string Int.to_str : int => string
``` ```
Casts the integer to a string (in decimal representation). Casts integer to string using decimal representation
#### to\_bytes
```
Int.to_bytes(n : int, size : int) : bytes()
```
Casts the integer to a byte array with `size` bytes (big endian, truncating if
necessary not preserving signedness). I.e. if you try to squeeze `-129` into a
single byte that will be indistinguishable from `127`.
### Map ### Map
@@ -954,11 +882,11 @@ Oracle.register(<signature : bytes(64)>, acct : address, qfee : int, ttl : Chain
Registers new oracle answering questions of type `'a` with answers of type `'b`. Registers new oracle answering questions of type `'a` with answers of type `'b`.
* The `acct` is the address of the oracle to register (can be the same as the contract). * The `acct` is the address of the oracle to register (can be the same as the contract).
* The [signature](./sophia_features.md#delegation-signature) should be a * `signature` is a signature proving that the contract is allowed to register the account -
serialized structure containing `network id`, `account address`, and the `network id` + `account address` + `contract address` (concatenated as byte arrays) is
`contract address`. Using the private key of `account address` for signing. [signed](./sophia_features.md#delegation-signature) with the
Proving you have the private key of the oracle to be. If the address is the same private key of the account, proving you have the private key of the oracle to be. If the
as the contract `sign` is ignored and can be left out entirely. 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 `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 * 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)`). key block height (`RelativeTTL(delta)`) or a fixed key block height (`FixedTTL(height)`).
@@ -972,7 +900,7 @@ Examples:
``` ```
#### get\_question #### get_question
``` ```
Oracle.get_question(o : oracle('a, 'b), q : oracle_query('a, 'b)) : 'a Oracle.get_question(o : oracle('a, 'b), q : oracle_query('a, 'b)) : 'a
``` ```
@@ -985,11 +913,12 @@ Checks what was the question of query `q` on oracle `o`
Oracle.respond(<signature : bytes(64)>, o : oracle('a, 'b), q : oracle_query('a, 'b), 'b) : unit Oracle.respond(<signature : bytes(64)>, o : oracle('a, 'b), q : oracle_query('a, 'b), 'b) : unit
``` ```
Responds to the question `q` on `o`. Unless the contract address is the same Responds to the question `q` on `o`.
as the oracle address the `signature` (which is an optional, named argument) Unless the contract address is the same as the oracle address the `signature`
(which is an optional, named argument)
needs to be provided. Proving that we have the private key of the oracle by needs to be provided. Proving that we have the private key of the oracle by
[signing](./sophia_features.md#delegation-signature) should be a serialized [signing](./sophia_features.md#delegation-signature)
structure containing `network id`, `oracle query id`, and `contract address`. the `network id` + `oracle query id` + `contract address`
#### extend #### extend
@@ -1002,7 +931,7 @@ Extends TTL of an oracle.
* `o` is the oracle being extended * `o` is the oracle being extended
* `ttl` must be `RelativeTTL`. The time to live of `o` will be extended by this value. * `ttl` must be `RelativeTTL`. The time to live of `o` will be extended by this value.
#### query\_fee #### query_fee
``` ```
Oracle.query_fee(o : oracle('a, 'b)) : int Oracle.query_fee(o : oracle('a, 'b)) : int
``` ```
@@ -1023,7 +952,7 @@ Asks the oracle a question.
The call fails if the oracle could expire before an answer. The call fails if the oracle could expire before an answer.
#### get\_answer #### get_answer
``` ```
Oracle.get_answer(o : oracle('a, 'b), q : oracle_query('a, 'b)) : option('b) Oracle.get_answer(o : oracle('a, 'b), q : oracle_query('a, 'b)) : option('b)
``` ```
@@ -2471,15 +2400,6 @@ to_int(s : string) : option(int)
Converts a decimal ("123", "-253") or a hexadecimal ("0xa2f", "-0xBBB") string into Converts a decimal ("123", "-253") or a hexadecimal ("0xa2f", "-0xBBB") string into
an integer. If the string doesn't contain a valid number `None` is returned. an integer. If the string doesn't contain a valid number `None` is returned.
#### to\_bytes
```
to_bytes(s : string) : bytes()
```
Converts string into byte array. String is UTF-8 encoded. I.e.
`String.length(s)` is not guaranteed to be equal to
`Bytes.size(String.to_bytes(s))`.
#### sha3 #### sha3
``` ```
sha3(s : string) : hash sha3(s : string) : hash
+4 -8
View File
@@ -30,7 +30,6 @@ interface main using as for hiding
- `ContractAddress` base58-encoded 32 byte contract address with `ct_` prefix - `ContractAddress` base58-encoded 32 byte contract address with `ct_` prefix
- `OracleAddress` base58-encoded 32 byte oracle address with `ok_` prefix - `OracleAddress` base58-encoded 32 byte oracle address with `ok_` prefix
- `OracleQueryId` base58-encoded 32 byte oracle query id with `oq_` prefix - `OracleQueryId` base58-encoded 32 byte oracle query id with `oq_` prefix
- `Signature` base58-encoded 64 byte cryptographic signature with `sg_` prefix
Valid string escape codes are Valid string escape codes are
@@ -105,7 +104,6 @@ Implement ::= ':' Sep1(Con, ',')
Decl ::= 'type' Id ['(' TVar* ')'] '=' TypeAlias Decl ::= 'type' Id ['(' TVar* ')'] '=' TypeAlias
| 'record' Id ['(' TVar* ')'] '=' RecordType | 'record' Id ['(' TVar* ')'] '=' RecordType
| 'datatype' Id ['(' TVar* ')'] '=' DataType | 'datatype' Id ['(' TVar* ')'] '=' DataType
| 'let' Id [':' Type] '=' Expr
| (EModifier* 'entrypoint' | FModifier* 'function') Block(FunDecl) | (EModifier* 'entrypoint' | FModifier* 'function') Block(FunDecl)
| Using | Using
@@ -240,8 +238,6 @@ Expr ::= '(' LamArgs ')' '=>' Block(Stmt) // Anonymous function (x) => x +
| Int | Bytes | String | Char // Literals 123, 0xff, #00abc123, "foo", '%' | Int | Bytes | String | Char // Literals 123, 0xff, #00abc123, "foo", '%'
| AccountAddress | ContractAddress // Chain identifiers | AccountAddress | ContractAddress // Chain identifiers
| OracleAddress | OracleQueryId // Chain identifiers | OracleAddress | OracleQueryId // Chain identifiers
| Signature // Signature
| '???' // Hole expression 1 + ???
Generator ::= Pattern '<-' Expr // Generator Generator ::= Pattern '<-' Expr // Generator
| 'if' '(' Expr ')' // Guard | 'if' '(' Expr ')' // Guard
@@ -267,11 +263,11 @@ UnOp ::= '-' | '!' | 'bnot'
| Operators | Type | Operators | Type
| --- | --- | --- | ---
| `-` `+` `*` `/` `mod` `^` | arithmetic operators | `-` `+` `*` `/` `mod` `^` | arithmetic operators
| `!` `&&` `\|\|` | logical operators | `!` `&&` `||` | logical operators
| `band` `bor` `bxor` `bnot` `<<` `>>` | bitwise operators | `band` `bor` `bxor` `bnot` `<<` `>>` | bitwise operators
| `==` `!=` `<` `>` `=<` `>=` | comparison operators | `==` `!=` `<` `>` `=<` `>=` | comparison operators
| `::` `++` | list operators | `::` `++` | list operators
| `\|>` | functional operators | `|>` | functional operators
## Operator precedence ## Operator precedence
@@ -291,5 +287,5 @@ In order of highest to lowest precedence.
| `bxor` | left | `bxor` | left
| `bor` | left | `bor` | left
| `&&` | right | `&&` | right
| `\|\|` | right | `||` | right
| `\|>` | left | `|>` | left
+2
View File
@@ -3,6 +3,7 @@ namespace AENSCompat =
function pointee_to_V2(p : AENS.pointee) : AENSv2.pointee = function pointee_to_V2(p : AENS.pointee) : AENSv2.pointee =
switch(p) switch(p)
AENS.AccountPt(a) => AENSv2.AccountPt(a) AENS.AccountPt(a) => AENSv2.AccountPt(a)
AENS.OraclePt(a) => AENSv2.OraclePt(a)
AENS.ContractPt(a) => AENSv2.ContractPt(a) AENS.ContractPt(a) => AENSv2.ContractPt(a)
AENS.ChannelPt(a) => AENSv2.ChannelPt(a) AENS.ChannelPt(a) => AENSv2.ChannelPt(a)
@@ -10,6 +11,7 @@ namespace AENSCompat =
function pointee_from_V2(p2 : AENSv2.pointee) : option(AENS.pointee) = function pointee_from_V2(p2 : AENSv2.pointee) : option(AENS.pointee) =
switch(p2) switch(p2)
AENSv2.AccountPt(a) => Some(AENS.AccountPt(a)) AENSv2.AccountPt(a) => Some(AENS.AccountPt(a))
AENSv2.OraclePt(a) => Some(AENS.OraclePt(a))
AENSv2.ContractPt(a) => Some(AENS.ContractPt(a)) AENSv2.ContractPt(a) => Some(AENS.ContractPt(a))
AENSv2.ChannelPt(a) => Some(AENS.ChannelPt(a)) AENSv2.ChannelPt(a) => Some(AENS.ChannelPt(a))
AENSv2.DataPt(_) => None AENSv2.DataPt(_) => None
+2 -2
View File
@@ -282,9 +282,9 @@ namespace List =
private function private function
asc : (('a, 'a) => bool, 'a, list('a), list('a)) => list(list('a)) asc : (('a, 'a) => bool, 'a, list('a), list('a)) => list(list('a))
asc(lt, x, acc, h::t) = asc(lt, x, acc, h::t) =
if(lt(h, x)) reverse(x::acc) :: monotonic_subs(lt, h::t) if(lt(h, x)) List.reverse(x::acc) :: monotonic_subs(lt, h::t)
else asc(lt, h, x::acc, t) else asc(lt, h, x::acc, t)
asc(_, x, acc, []) = [reverse(x::acc)] asc(_, x, acc, []) = [List.reverse(x::acc)]
/** Merges list of sorted lists /** Merges list of sorted lists
*/ */
-3
View File
@@ -1,8 +1,5 @@
include "List.aes" include "List.aes"
namespace String = namespace String =
// Gives a bytes() representation of the string
function to_bytes(s : string) : bytes() = StringInternal.to_bytes(s)
// Computes the SHA3/Keccak hash of the string // Computes the SHA3/Keccak hash of the string
function sha3(s : string) : hash = StringInternal.sha3(s) function sha3(s : string) : hash = StringInternal.sha3(s)
// Computes the SHA256 hash of the string. // Computes the SHA256 hash of the string.
+4 -3
View File
@@ -2,7 +2,8 @@
{erl_opts, [debug_info]}. {erl_opts, [debug_info]}.
{deps, [ {gmbytecode, {git, "https://git.qpq.swiss/QPQ-AG/gmbytecode.git", {ref, "cc4fd04019"}}} {deps, [ {aebytecode, {git, "https://github.com/aeternity/aebytecode.git", {tag, "v3.2.0"}}}
, {getopt, "1.0.1"}
, {eblake2, "1.0.0"} , {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"}}}
]}. ]}.
@@ -13,8 +14,8 @@
{base_plt_apps, [erts, kernel, stdlib, crypto, mnesia]} {base_plt_apps, [erts, kernel, stdlib, crypto, mnesia]}
]}. ]}.
{relx, [{release, {sophia, "8.0.1"}, {relx, [{release, {aesophia, "8.0.0"},
[sophia, gmbytecode]}, [aesophia, aebytecode, getopt]},
{dev_mode, true}, {dev_mode, true},
{include_erts, false}, {include_erts, false},
+14 -14
View File
@@ -1,22 +1,22 @@
{"1.2.0", {"1.2.0",
[{<<"base58">>, [{<<"aebytecode">>,
{git,"https://git.qpq.swiss/QPQ-AG/erl-base58.git", {git,"https://github.com/aeternity/aebytecode.git",
{ref,"e6aa62eeae3d4388311401f06e4b939bf4e94b9c"}}, {ref,"2a0a397afad6b45da52572170f718194018bf33c"}},
0},
{<<"aeserialization">>,
{git,"https://github.com/aeternity/aeserialization.git",
{ref,"eb68fe331bd476910394966b7f5ede7a74d37e35"}},
1},
{<<"base58">>,
{git,"https://github.com/aeternity/erl-base58.git",
{ref,"60a335668a60328a29f9731b67c4a0e9e3d50ab6"}},
2}, 2},
{<<"eblake2">>,{pkg,<<"eblake2">>,<<"1.0.0">>},0}, {<<"eblake2">>,{pkg,<<"eblake2">>,<<"1.0.0">>},0},
{<<"enacl">>, {<<"enacl">>,
{git,"https://git.qpq.swiss/QPQ-AG/enacl.git", {git,"https://github.com/aeternity/enacl.git",
{ref,"4eb7ec70084ba7c87b1af8797c4c4e90c84f95a2"}}, {ref,"793ddb502f7fe081302e1c42227dca70b09f8e17"}},
2}, 2},
{<<"getopt">>,{pkg,<<"getopt">>,<<"1.0.1">>},1}, {<<"getopt">>,{pkg,<<"getopt">>,<<"1.0.1">>},0},
{<<"gmbytecode">>,
{git,"https://git.qpq.swiss/QPQ-AG/gmbytecode.git",
{ref,"cc4fd0401903e9ce902a99160ac200e64040217f"}},
0},
{<<"gmserialization">>,
{git,"https://git.qpq.swiss/QPQ-AG/gmserialization.git",
{ref,"9d2ecc00d32ea295309563e54a81636ecb597e96"}},
1},
{<<"jsx">>, {<<"jsx">>,
{git,"https://github.com/talentdeficit/jsx.git", {git,"https://github.com/talentdeficit/jsx.git",
{ref,"3074d4865b3385a050badf7828ad31490d860df5"}}, {ref,"3074d4865b3385a050badf7828ad31490d860df5"}},
BIN
View File
Binary file not shown.
+14 -17
View File
@@ -7,7 +7,7 @@
%%% Created : 12 Jan 2019 %%% Created : 12 Jan 2019
%%%------------------------------------------------------------------- %%%-------------------------------------------------------------------
-module(so_aci). -module(aeso_aci).
-export([ file/2 -export([ file/2
, file/3 , file/3
@@ -21,7 +21,7 @@
, json_encode_expr/1 , json_encode_expr/1
, json_encode_type/1]). , json_encode_type/1]).
-include("so_utils.hrl"). -include("aeso_utils.hrl").
-type aci_type() :: json | string. -type aci_type() :: json | string.
-type json() :: jsx:json_term(). -type json() :: jsx:json_term().
@@ -35,7 +35,7 @@ file(Type, File) ->
file(Type, File, []). file(Type, File, []).
file(Type, File, Options0) -> file(Type, File, Options0) ->
Options = so_compiler:add_include_path(File, Options0), Options = aeso_compiler:add_include_path(File, Options0),
case file:read_file(File) of case file:read_file(File) of
{ok, BinCode} -> {ok, BinCode} ->
do_contract_interface(Type, binary_to_list(BinCode), Options); do_contract_interface(Type, binary_to_list(BinCode), Options);
@@ -56,11 +56,11 @@ contract_interface(Type, ContractString, CompilerOpts) ->
render_aci_json(Json) -> render_aci_json(Json) ->
do_render_aci_json(Json). do_render_aci_json(Json).
-spec json_encode_expr(so_syntax:expr()) -> json(). -spec json_encode_expr(aeso_syntax:expr()) -> json().
json_encode_expr(Expr) -> json_encode_expr(Expr) ->
encode_expr(Expr). encode_expr(Expr).
-spec json_encode_type(so_syntax:type()) -> json(). -spec json_encode_type(aeso_syntax:type()) -> json().
json_encode_type(Type) -> json_encode_type(Type) ->
encode_type(Type). encode_type(Type).
@@ -69,8 +69,8 @@ do_contract_interface(Type, Contract, Options) when is_binary(Contract) ->
do_contract_interface(Type, binary_to_list(Contract), Options); do_contract_interface(Type, binary_to_list(Contract), Options);
do_contract_interface(Type, ContractString, Options) -> do_contract_interface(Type, ContractString, Options) ->
try try
Ast = so_compiler:parse(ContractString, Options), Ast = aeso_compiler:parse(ContractString, Options),
{TypedAst, _, _} = so_ast_infer_types:infer(Ast, [dont_unfold | Options]), {TypedAst, _, _} = aeso_ast_infer_types:infer(Ast, [dont_unfold | Options]),
from_typed_ast(Type, TypedAst) from_typed_ast(Type, TypedAst)
catch catch
throw:{error, Errors} -> {error, Errors} throw:{error, Errors} -> {error, Errors}
@@ -198,9 +198,8 @@ encode_expr({bytes, _, B}) ->
<<N:Digits/unit:8>> = B, <<N:Digits/unit:8>> = B,
list_to_binary(lists:flatten(io_lib:format("#~*.16.0b", [Digits*2, N]))); list_to_binary(lists:flatten(io_lib:format("#~*.16.0b", [Digits*2, N])));
encode_expr({Lit, _, L}) when Lit == oracle_pubkey; Lit == oracle_query_id; encode_expr({Lit, _, L}) when Lit == oracle_pubkey; Lit == oracle_query_id;
Lit == contract_pubkey; Lit == account_pubkey; Lit == contract_pubkey; Lit == account_pubkey ->
Lit == signature -> aeser_api_encoder:encode(Lit, L);
gmser_api_encoder:encode(Lit, L);
encode_expr({app, _, {'-', _}, [{int, _, N}]}) -> encode_expr({app, _, {'-', _}, [{int, _, N}]}) ->
encode_expr({int, [], -N}); encode_expr({int, [], -N});
encode_expr({app, _, F, As}) -> encode_expr({app, _, F, As}) ->
@@ -283,8 +282,6 @@ decode_type(#{list := [Et]}) ->
decode_type(#{map := Ets}) -> decode_type(#{map := Ets}) ->
Ts = decode_types(Ets), Ts = decode_types(Ets),
["map",$(,lists:join(",", Ts),$)]; ["map",$(,lists:join(",", Ts),$)];
decode_type(#{bytes := any}) ->
["bytes()"];
decode_type(#{bytes := Len}) -> decode_type(#{bytes := Len}) ->
["bytes(", integer_to_list(Len), ")"]; ["bytes(", integer_to_list(Len), ")"];
decode_type(#{variant := Ets}) -> decode_type(#{variant := Ets}) ->
@@ -361,14 +358,14 @@ is_type(_) -> false.
sort_decls(Ds) -> sort_decls(Ds) ->
Sort = fun (D1, D2) -> Sort = fun (D1, D2) ->
so_syntax:get_ann(line, D1, 0) =< aeso_syntax:get_ann(line, D1, 0) =<
so_syntax:get_ann(line, D2, 0) aeso_syntax:get_ann(line, D2, 0)
end, end,
lists:sort(Sort, Ds). lists:sort(Sort, Ds).
is_entrypoint(Node) -> so_syntax:get_ann(entrypoint, Node, false). is_entrypoint(Node) -> aeso_syntax:get_ann(entrypoint, Node, false).
is_stateful(Node) -> so_syntax:get_ann(stateful, Node, false). is_stateful(Node) -> aeso_syntax:get_ann(stateful, Node, false).
is_payable(Node) -> so_syntax:get_ann(payable, Node, false). is_payable(Node) -> aeso_syntax:get_ann(payable, Node, false).
typedef_name({type_def, _, {id, _, Name}, _, _}) -> Name. typedef_name({type_def, _, {id, _, Name}, _, _}) -> Name.
+3 -3
View File
@@ -1,4 +1,4 @@
-module(so_ast). -module(aeso_ast).
-export([int/2, -export([int/2,
line/1, line/1,
@@ -17,11 +17,11 @@ line({symbol, Line, _}) -> Line.
symbol_name({symbol, _, Name}) -> Name. symbol_name({symbol, _, Name}) -> Name.
pp(Ast) -> pp(Ast) ->
String = prettypr:format(so_pretty:decls(Ast, [])), String = prettypr:format(aeso_pretty:decls(Ast, [])),
io:format("Ast:\n~s\n", [String]). io:format("Ast:\n~s\n", [String]).
pp_typed(TypedAst) -> pp_typed(TypedAst) ->
%% io:format("Typed tree:\n~p\n",[TypedAst]), %% io:format("Typed tree:\n~p\n",[TypedAst]),
String = prettypr:format(so_pretty:decls(TypedAst, [show_generated])), String = prettypr:format(aeso_pretty:decls(TypedAst, [show_generated])),
io:format("Type ast:\n~s\n",[String]). io:format("Type ast:\n~s\n",[String]).
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+94 -147
View File
@@ -6,14 +6,12 @@
%%% @end %%% @end
%%% Created : 12 Dec 2017 %%% Created : 12 Dec 2017
%%%------------------------------------------------------------------- %%%-------------------------------------------------------------------
-module(so_compiler). -module(aeso_compiler).
-export([ file/1 -export([ file/1
, file/2 , file/2
, from_string/2 , from_string/2
, check_call/4 , check_call/4
, decode_value/4
, encode_value/4
, create_calldata/3 , create_calldata/3
, create_calldata/4 , create_calldata/4
, version/0 , version/0
@@ -27,8 +25,8 @@
, validate_byte_code/3 , validate_byte_code/3
]). ]).
-include_lib("gmbytecode/include/gmb_opcodes.hrl"). -include_lib("aebytecode/include/aeb_opcodes.hrl").
-include("so_utils.hrl"). -include("aeso_utils.hrl").
-type option() :: pp_sophia_code -type option() :: pp_sophia_code
@@ -42,8 +40,7 @@
| {include, {file_system, [string()]} | | {include, {file_system, [string()]} |
{explicit_files, #{string() => binary()}}} {explicit_files, #{string() => binary()}}}
| {src_file, string()} | {src_file, string()}
| {src_dir, string()} | {aci, aeso_aci:aci_type()}.
| {aci, so_aci:aci_type()}.
-type options() :: [option()]. -type options() :: [option()].
-export_type([ option/0 -export_type([ option/0
@@ -52,15 +49,15 @@
-spec version() -> {ok, binary()} | {error, term()}. -spec version() -> {ok, binary()} | {error, term()}.
version() -> version() ->
case lists:keyfind(sophia, 1, application:loaded_applications()) of case lists:keyfind(aesophia, 1, application:loaded_applications()) of
false -> false ->
case application:load(sophia) of case application:load(aesophia) of
ok -> ok ->
case application:get_key(sophia, vsn) of case application:get_key(aesophia, vsn) of
{ok, VsnString} -> {ok, VsnString} ->
{ok, list_to_binary(VsnString)}; {ok, list_to_binary(VsnString)};
undefined -> undefined ->
{error, failed_to_load_sophia} {error, failed_to_load_aesophia}
end; end;
Err = {error, _} -> Err = {error, _} ->
Err Err
@@ -80,20 +77,18 @@ numeric_version() ->
Err Err
end. end.
-spec file(string()) -> {ok, map()} | {error, [so_errors:error()]}. -spec file(string()) -> {ok, map()} | {error, [aeso_errors:error()]}.
file(Filename) -> file(Filename) ->
file(Filename, []). file(Filename, []).
-spec file(string(), options()) -> {ok, map()} | {error, [so_errors:error()]}. -spec file(string(), options()) -> {ok, map()} | {error, [aeso_errors:error()]}.
file(File, Options0) -> file(File, Options0) ->
Options = add_include_path(File, Options0), Options = add_include_path(File, Options0),
case read_contract(File) of case read_contract(File) of
{ok, Bin} -> {ok, Bin} -> from_string(Bin, [{src_file, File} | Options]);
SrcDir = so_utils:canonical_dir(filename:dirname(File)),
from_string(Bin, [{src_file, File}, {src_dir, SrcDir} | Options]);
{error, Error} -> {error, Error} ->
Msg = lists:flatten([File,": ",file:format_error(Error)]), Msg = lists:flatten([File,": ",file:format_error(Error)]),
{error, [so_errors:new(file_error, Msg)]} {error, [aeso_errors:new(file_error, Msg)]}
end. end.
add_include_path(File, Options) -> add_include_path(File, Options) ->
@@ -102,10 +97,10 @@ add_include_path(File, Options) ->
false -> false ->
Dir = filename:dirname(File), Dir = filename:dirname(File),
{ok, Cwd} = file:get_cwd(), {ok, Cwd} = file:get_cwd(),
[{include, {file_system, [Cwd, so_utils:canonical_dir(Dir)]}} | Options] [{include, {file_system, [Cwd, Dir]}} | Options]
end. end.
-spec from_string(binary() | string(), options()) -> {ok, map()} | {error, [so_errors:error()]}. -spec from_string(binary() | string(), options()) -> {ok, map()} | {error, [aeso_errors:error()]}.
from_string(ContractBin, Options) when is_binary(ContractBin) -> from_string(ContractBin, Options) when is_binary(ContractBin) ->
from_string(binary_to_list(ContractBin), Options); from_string(binary_to_list(ContractBin), Options);
from_string(ContractString, Options) -> from_string(ContractString, Options) ->
@@ -122,27 +117,33 @@ from_string1(ContractString, Options) ->
, warnings := Warnings } = string_to_code(ContractString, Options), , warnings := Warnings } = string_to_code(ContractString, Options),
#{ child_con_env := ChildContracts } = FCodeEnv, #{ child_con_env := ChildContracts } = FCodeEnv,
SavedFreshNames = maps:get(saved_fresh_names, FCodeEnv, #{}), SavedFreshNames = maps:get(saved_fresh_names, FCodeEnv, #{}),
FateCode = so_fcode_to_fate:compile(ChildContracts, FCode, SavedFreshNames, Options), {FateCode, VarsRegs} = aeso_fcode_to_fate:compile(ChildContracts, FCode, SavedFreshNames, Options),
pp_assembler(FateCode, Options), pp_assembler(FateCode, Options),
ByteCode = gmb_fate_code:serialize(FateCode, []), ByteCode = aeb_fate_code:serialize(FateCode, []),
{ok, Version} = version(), {ok, Version} = version(),
Res = #{byte_code => ByteCode, Res = #{byte_code => ByteCode,
compiler_version => Version, compiler_version => Version,
contract_source => ContractString, contract_source => ContractString,
type_info => [], type_info => [],
fate_code => FateCode, fate_code => FateCode,
abi_version => gmb_fate_abi:abi_version(), abi_version => aeb_fate_abi:abi_version(),
payable => maps:get(payable, FCode), payable => maps:get(payable, FCode),
warnings => Warnings warnings => Warnings
}, },
{ok, maybe_generate_aci(Res, FoldedTypedAst, Options)}. 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)}.
maybe_generate_aci(Result, FoldedTypedAst, Options) -> maybe_generate_aci(Result, FoldedTypedAst, Options) ->
case proplists:get_value(aci, Options) of case proplists:get_value(aci, Options) of
undefined -> undefined ->
Result; Result;
Type -> Type ->
{ok, Aci} = so_aci:from_typed_ast(Type, FoldedTypedAst), {ok, Aci} = aeso_aci:from_typed_ast(Type, FoldedTypedAst),
maps:put(aci, Aci, Result) maps:put(aci, Aci, Result)
end. end.
@@ -151,9 +152,9 @@ string_to_code(ContractString, Options) ->
Ast = parse(ContractString, Options), Ast = parse(ContractString, Options),
pp_sophia_code(Ast, Options), pp_sophia_code(Ast, Options),
pp_ast(Ast, Options), pp_ast(Ast, Options),
{TypeEnv, FoldedTypedAst, UnfoldedTypedAst, Warnings} = so_ast_infer_types:infer(Ast, [return_env | Options]), {TypeEnv, FoldedTypedAst, UnfoldedTypedAst, Warnings} = aeso_ast_infer_types:infer(Ast, [return_env | Options]),
pp_typed_ast(UnfoldedTypedAst, Options), pp_typed_ast(UnfoldedTypedAst, Options),
{Env, Fcode} = so_ast_to_fcode:ast_to_fcode(UnfoldedTypedAst, [{original_src, ContractString}|Options]), {Env, Fcode} = aeso_ast_to_fcode:ast_to_fcode(UnfoldedTypedAst, [{original_src, ContractString}|Options]),
#{ fcode => Fcode #{ fcode => Fcode
, fcode_env => Env , fcode_env => Env
, unfolded_typed_ast => UnfoldedTypedAst , unfolded_typed_ast => UnfoldedTypedAst
@@ -171,7 +172,7 @@ string_to_code(ContractString, Options) ->
%% NOTE: Special treatment for "init" since it might be implicit and has %% NOTE: Special treatment for "init" since it might be implicit and has
%% a special return type (typerep, T) %% a special return type (typerep, T)
-spec check_call(string(), string(), [string()], options()) -> {ok, string(), [term()]} -spec check_call(string(), string(), [string()], options()) -> {ok, string(), [term()]}
| {error, [so_errors:error()]}. | {error, [aeso_errors:error()]}.
check_call(Source, "init" = FunName, Args, Options) -> check_call(Source, "init" = FunName, Args, Options) ->
case check_call1(Source, FunName, Args, Options) of case check_call1(Source, FunName, Args, Options) of
Err = {error, _} when Args == [] -> Err = {error, _} when Args == [] ->
@@ -187,63 +188,35 @@ check_call(Source, FunName, Args, Options) ->
check_call1(Source, FunName, Args, Options). check_call1(Source, FunName, Args, Options).
check_call1(ContractString0, FunName, Args, Options) -> check_call1(ContractString0, FunName, Args, Options) ->
case add_extra_call(ContractString0, {call, FunName, Args}, Options) of
{ok, CallName, Code} ->
{def, _, _, FcodeArgs} = get_call_body(CallName, Code),
{ok, FunName, [ so_fcode_to_fate:term_to_fate(A) || A <- FcodeArgs ]};
Err = {error, _} ->
Err
end.
add_extra_call(Contract0, Call, Options) ->
try try
%% First check the contract without the __call function %% First check the contract without the __call function
#{fcode := OrgFcode #{fcode := OrgFcode
, fcode_env := #{child_con_env := ChildContracts} , fcode_env := #{child_con_env := ChildContracts}
, ast := Ast} = string_to_code(Contract0, Options), , ast := Ast} = string_to_code(ContractString0, Options),
FateCode = so_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 %% collect all hashes and compute the first name without hash collision to
SymbolHashes = maps:keys(gmb_fate_code:symbols(FateCode)), SymbolHashes = maps:keys(aeb_fate_code:symbols(FateCode)),
CallName = first_none_match(?CALL_NAME, SymbolHashes, CallName = first_none_match(?CALL_NAME, SymbolHashes,
lists:seq($1, $9) ++ lists:seq($A, $Z) ++ lists:seq($a, $z)), lists:seq($1, $9) ++ lists:seq($A, $Z) ++ lists:seq($a, $z)),
Contract = insert_call_function(Ast, Contract0, CallName, Call), ContractString = insert_call_function(Ast, ContractString0, CallName, FunName, Args),
{ok, CallName, string_to_code(Contract, Options)} #{fcode := Fcode} = string_to_code(ContractString, Options),
CallArgs = arguments_of_body(CallName, FunName, Fcode),
{ok, FunName, CallArgs}
catch catch
throw:{error, Errors} -> {error, Errors} throw:{error, Errors} -> {error, Errors}
end. end.
get_call_body(CallName, #{fcode := Fcode}) -> arguments_of_body(CallName, _FunName, Fcode) ->
#{body := Body} = maps:get({entrypoint, list_to_binary(CallName)}, maps:get(functions, Fcode)), #{body := Body} = maps:get({entrypoint, list_to_binary(CallName)}, maps:get(functions, Fcode)),
Body. {def, _FName, Args} = Body,
%% FName is either {entrypoint, list_to_binary(FunName)} or 'init'
encode_value(Contract0, Type, Value, Options) -> [ aeso_fcode_to_fate:term_to_fate(A) || A <- Args ].
case add_extra_call(Contract0, {value, Type, Value}, Options) of
{ok, CallName, Code} ->
Body = get_call_body(CallName, Code),
{ok, gmb_fate_encoding:serialize(so_fcode_to_fate:term_to_fate(Body))};
Err = {error, _} ->
Err
end.
decode_value(Contract0, Type, FateValue, Options) ->
case add_extra_call(Contract0, {type, Type}, Options) of
{ok, CallName, Code} ->
#{ folded_typed_ast := TypedAst
, type_env := TypeEnv} = Code,
{ok, _, Type0} = get_decode_type(CallName, TypedAst),
Type1 = so_ast_infer_types:unfold_types_in_type(TypeEnv, Type0,
[ unfold_record_types
, unfold_variant_types
, not_unfold_system_alias_types ]),
fate_data_to_sophia_value(Type0, Type1, FateValue);
Err = {error, _} ->
Err
end.
first_none_match(_CallName, _Hashes, []) -> first_none_match(_CallName, _Hashes, []) ->
error(unable_to_find_unique_call_name); error(unable_to_find_unique_call_name);
first_none_match(CallName, Hashes, [Char|Chars]) -> first_none_match(CallName, Hashes, [Char|Chars]) ->
case not lists:member(gmb_fate_code:symbol_identifier(list_to_binary(CallName)), Hashes) of case not lists:member(aeb_fate_code:symbol_identifier(list_to_binary(CallName)), Hashes) of
true -> true ->
CallName; CallName;
false -> false ->
@@ -251,31 +224,14 @@ first_none_match(CallName, Hashes, [Char|Chars]) ->
end. end.
%% Add the __call function to a contract. %% Add the __call function to a contract.
-spec insert_call_function(so_syntax:ast(), string(), string(), -spec insert_call_function(aeso_syntax:ast(), string(), string(), string(), [string()]) -> string().
{call, string(), [string()]} | {value, string(), string()} | {type, string()}) -> string(). insert_call_function(Ast, Code, Call, FunName, Args) ->
insert_call_function(Ast, Code, Call, {call, FunName, Args}) ->
Ind = last_contract_indent(Ast), Ind = last_contract_indent(Ast),
lists:flatten( lists:flatten(
[ Code, [ Code,
"\n\n", "\n\n",
lists:duplicate(Ind, " "), lists:duplicate(Ind, " "),
"stateful entrypoint ", Call, "() = ", FunName, "(", string:join(Args, ","), ")\n" "stateful entrypoint ", Call, "() = ", FunName, "(", string:join(Args, ","), ")\n"
]);
insert_call_function(Ast, Code, Call, {value, Type, Value}) ->
Ind = last_contract_indent(Ast),
lists:flatten(
[ Code,
"\n\n",
lists:duplicate(Ind, " "),
"entrypoint ", Call, "() : ", Type, " = ", Value, "\n"
]);
insert_call_function(Ast, Code, Call, {type, Type}) ->
Ind = last_contract_indent(Ast),
lists:flatten(
[ Code,
"\n\n",
lists:duplicate(Ind, " "),
"entrypoint ", Call, "(val : ", Type, ") : ", Type, " = val\n"
]). ]).
-spec insert_init_function(string(), options()) -> string(). -spec insert_init_function(string(), options()) -> string().
@@ -290,109 +246,100 @@ insert_init_function(Code, Options) ->
last_contract_indent(Decls) -> last_contract_indent(Decls) ->
case lists:last(Decls) of case lists:last(Decls) of
{_, _, _, _, [Decl | _]} -> so_syntax:get_ann(col, Decl, 1) - 1; {_, _, _, _, [Decl | _]} -> aeso_syntax:get_ann(col, Decl, 1) - 1;
_ -> 0 _ -> 0
end. end.
-spec to_sophia_value(string(), string(), ok | error | revert, binary()) -> -spec to_sophia_value(string(), string(), ok | error | revert, binary()) ->
{ok, so_syntax:expr()} | {error, [so_errors:error()]}. {ok, aeso_syntax:expr()} | {error, [aeso_errors:error()]}.
to_sophia_value(ContractString, Fun, ResType, Data) -> to_sophia_value(ContractString, Fun, ResType, Data) ->
to_sophia_value(ContractString, Fun, ResType, Data, []). to_sophia_value(ContractString, Fun, ResType, Data, []).
-spec to_sophia_value(string(), string(), ok | error | revert, binary(), options()) -> -spec to_sophia_value(string(), string(), ok | error | revert, binary(), options()) ->
{ok, so_syntax:expr()} | {error, [so_errors:error()]}. {ok, aeso_syntax:expr()} | {error, [aeso_errors:error()]}.
to_sophia_value(_, _, error, Err, _Options) -> to_sophia_value(_, _, error, Err, _Options) ->
{ok, {app, [], {id, [], "error"}, [{string, [], Err}]}}; {ok, {app, [], {id, [], "error"}, [{string, [], Err}]}};
to_sophia_value(_, _, revert, Data, _Options) -> to_sophia_value(_, _, revert, Data, _Options) ->
try so_vm_decode:from_fate({id, [], "string"}, gmb_fate_encoding:deserialize(Data)) of try aeso_vm_decode:from_fate({id, [], "string"}, aeb_fate_encoding:deserialize(Data)) of
Err -> Err ->
{ok, {app, [], {id, [], "abort"}, [Err]}} {ok, {app, [], {id, [], "abort"}, [Err]}}
catch _:_ -> catch _:_ ->
Msg = "Could not deserialize the revert message", Msg = "Could not deserialize the revert message",
{error, [so_errors:new(data_error, Msg)]} {error, [aeso_errors:new(data_error, Msg)]}
end; end;
to_sophia_value(ContractString, FunName, ok, Data, Options0) -> to_sophia_value(ContractString, FunName, ok, Data, Options0) ->
Options = [no_code | Options0], Options = [no_code | Options0],
try try
Code = string_to_code(ContractString, Options), Code = string_to_code(ContractString, Options),
#{ folded_typed_ast := TypedAst, type_env := TypeEnv} = Code, #{ unfolded_typed_ast := TypedAst, type_env := TypeEnv} = Code,
{ok, _, Type0} = get_decode_type(FunName, TypedAst), {ok, _, Type0} = get_decode_type(FunName, TypedAst),
Type = so_ast_infer_types:unfold_types_in_type(TypeEnv, Type0, Type = aeso_ast_infer_types:unfold_types_in_type(TypeEnv, Type0, [unfold_record_types, unfold_variant_types]),
[ unfold_record_types
, unfold_variant_types
, not_unfold_system_alias_types]),
fate_data_to_sophia_value(Type0, Type, Data) try
{ok, aeso_vm_decode:from_fate(Type, aeb_fate_encoding:deserialize(Data))}
catch throw:cannot_translate_to_sophia ->
Type1 = prettypr:format(aeso_pretty:type(Type0)),
Msg = io_lib:format("Cannot translate FATE value ~p\n of Sophia type ~s",
[aeb_fate_encoding:deserialize(Data), Type1]),
{error, [aeso_errors:new(data_error, Msg)]};
_:_ ->
Type1 = prettypr:format(aeso_pretty:type(Type0)),
Msg = io_lib:format("Failed to decode binary as type ~s", [Type1]),
{error, [aeso_errors:new(data_error, Msg)]}
end
catch catch
throw:{error, Errors} -> {error, Errors} throw:{error, Errors} -> {error, Errors}
end. end.
fate_data_to_sophia_value(Type, UnfoldedType, FateData) ->
try
{ok, so_vm_decode:from_fate(UnfoldedType, gmb_fate_encoding:deserialize(FateData))}
catch throw:cannot_translate_to_sophia ->
Type1 = prettypr:format(so_pretty:type(Type)),
Msg = io_lib:format("Cannot translate FATE value ~p\n of Sophia type ~s",
[gmb_fate_encoding:deserialize(FateData), Type1]),
{error, [so_errors:new(data_error, Msg)]};
_:_ ->
Type1 = prettypr:format(so_pretty:type(Type)),
Msg = io_lib:format("Failed to decode binary as type ~s", [Type1]),
{error, [so_errors:new(data_error, Msg)]}
end.
-spec create_calldata(string(), string(), [string()]) -> -spec create_calldata(string(), string(), [string()]) ->
{ok, binary()} | {error, [so_errors:error()]}. {ok, binary()} | {error, [aeso_errors:error()]}.
create_calldata(Code, Fun, Args) -> create_calldata(Code, Fun, Args) ->
create_calldata(Code, Fun, Args, []). create_calldata(Code, Fun, Args, []).
-spec create_calldata(string(), string(), [string()], [{atom(), any()}]) -> -spec create_calldata(string(), string(), [string()], [{atom(), any()}]) ->
{ok, binary()} | {error, [so_errors:error()]}. {ok, binary()} | {error, [aeso_errors:error()]}.
create_calldata(Code, Fun, Args, Options0) -> create_calldata(Code, Fun, Args, Options0) ->
Options = [no_code | Options0], Options = [no_code | Options0],
case check_call(Code, Fun, Args, Options) of case check_call(Code, Fun, Args, Options) of
{ok, FunName, FateArgs} -> {ok, FunName, FateArgs} ->
gmb_fate_abi:create_calldata(FunName, FateArgs); aeb_fate_abi:create_calldata(FunName, FateArgs);
{error, _} = Err -> Err {error, _} = Err -> Err
end. end.
-spec decode_calldata(string(), string(), binary()) -> -spec decode_calldata(string(), string(), binary()) ->
{ok, [so_syntax:type()], [so_syntax:expr()]} {ok, [aeso_syntax:type()], [aeso_syntax:expr()]}
| {error, [so_errors:error()]}. | {error, [aeso_errors:error()]}.
decode_calldata(ContractString, FunName, Calldata) -> decode_calldata(ContractString, FunName, Calldata) ->
decode_calldata(ContractString, FunName, Calldata, []). decode_calldata(ContractString, FunName, Calldata, []).
-spec decode_calldata(string(), string(), binary(), options()) -> -spec decode_calldata(string(), string(), binary(), options()) ->
{ok, [so_syntax:type()], [so_syntax:expr()]} {ok, [aeso_syntax:type()], [aeso_syntax:expr()]}
| {error, [so_errors:error()]}. | {error, [aeso_errors:error()]}.
decode_calldata(ContractString, FunName, Calldata, Options0) -> decode_calldata(ContractString, FunName, Calldata, Options0) ->
Options = [no_code | Options0], Options = [no_code | Options0],
try try
Code = string_to_code(ContractString, Options), Code = string_to_code(ContractString, Options),
#{ folded_typed_ast := TypedAst, type_env := TypeEnv} = Code, #{ unfolded_typed_ast := TypedAst, type_env := TypeEnv} = Code,
{ok, Args, _} = get_decode_type(FunName, TypedAst), {ok, Args, _} = get_decode_type(FunName, TypedAst),
GetType = fun({typed, _, _, T}) -> T; (T) -> T end, GetType = fun({typed, _, _, T}) -> T; (T) -> T end,
ArgTypes = lists:map(GetType, Args), ArgTypes = lists:map(GetType, Args),
Type0 = {tuple_t, [], ArgTypes}, Type0 = {tuple_t, [], ArgTypes},
%% user defined data types such as variants needed to match against %% user defined data types such as variants needed to match against
Type = so_ast_infer_types:unfold_types_in_type(TypeEnv, Type0, Type = aeso_ast_infer_types:unfold_types_in_type(TypeEnv, Type0, [unfold_record_types, unfold_variant_types]),
[ unfold_record_types case aeb_fate_abi:decode_calldata(FunName, Calldata) of
, unfold_variant_types
, not_unfold_system_alias_types]),
case gmb_fate_abi:decode_calldata(FunName, Calldata) of
{ok, FateArgs} -> {ok, FateArgs} ->
try try
{tuple_t, [], ArgTypes1} = Type, {tuple_t, [], ArgTypes1} = Type,
AstArgs = [ so_vm_decode:from_fate(ArgType, FateArg) AstArgs = [ aeso_vm_decode:from_fate(ArgType, FateArg)
|| {ArgType, FateArg} <- lists:zip(ArgTypes1, FateArgs)], || {ArgType, FateArg} <- lists:zip(ArgTypes1, FateArgs)],
{ok, ArgTypes, AstArgs} {ok, ArgTypes, AstArgs}
catch throw:cannot_translate_to_sophia -> catch throw:cannot_translate_to_sophia ->
Type0Str = prettypr:format(so_pretty:type(Type0)), Type0Str = prettypr:format(aeso_pretty:type(Type0)),
Msg = io_lib:format("Cannot translate FATE value ~p\n to Sophia type ~s", Msg = io_lib:format("Cannot translate FATE value ~p\n to Sophia type ~s",
[FateArgs, Type0Str]), [FateArgs, Type0Str]),
{error, [so_errors:new(data_error, Msg)]} {error, [aeso_errors:new(data_error, Msg)]}
end; end;
{error, _} -> {error, _} ->
Msg = io_lib:format("Failed to decode calldata binary", []), Msg = io_lib:format("Failed to decode calldata binary", []),
{error, [so_errors:new(data_error, Msg)]} {error, [aeso_errors:new(data_error, Msg)]}
end end
catch catch
throw:{error, Errors} -> {error, Errors} throw:{error, Errors} -> {error, Errors}
@@ -410,8 +357,8 @@ get_decode_type(FunName, [{Contract, Ann, _, _, Defs}]) when ?IS_CONTRACT_HEAD(C
"init" -> {ok, [], {tuple_t, [], []}}; "init" -> {ok, [], {tuple_t, [], []}};
_ -> _ ->
Msg = io_lib:format("Function '~s' is missing in contract", [FunName]), Msg = io_lib:format("Function '~s' is missing in contract", [FunName]),
Pos = so_errors:pos(Ann), Pos = aeso_errors:pos(Ann),
so_errors:throw(so_errors:new(data_error, Pos, Msg)) aeso_errors:throw(aeso_errors:new(data_error, Pos, Msg))
end end
end; end;
get_decode_type(FunName, [_ | Contracts]) -> get_decode_type(FunName, [_ | Contracts]) ->
@@ -419,12 +366,12 @@ get_decode_type(FunName, [_ | Contracts]) ->
get_decode_type(FunName, Contracts). get_decode_type(FunName, Contracts).
pp_sophia_code(C, Opts)-> pp(C, Opts, pp_sophia_code, fun(Code) -> pp_sophia_code(C, Opts)-> pp(C, Opts, pp_sophia_code, fun(Code) ->
io:format("~s\n", [prettypr:format(so_pretty:decls(Code))]) io:format("~s\n", [prettypr:format(aeso_pretty:decls(Code))])
end). end).
pp_ast(C, Opts) -> pp(C, Opts, pp_ast, fun so_ast:pp/1). pp_ast(C, Opts) -> pp(C, Opts, pp_ast, fun aeso_ast:pp/1).
pp_typed_ast(C, Opts)-> pp(C, Opts, pp_typed_ast, fun so_ast:pp_typed/1). pp_typed_ast(C, Opts)-> pp(C, Opts, pp_typed_ast, fun aeso_ast:pp_typed/1).
pp_assembler(C, Opts) -> pp(C, Opts, pp_assembler, fun(Asm) -> io:format("~s", [gmb_fate_asm:pp(Asm)]) end). pp_assembler(C, Opts) -> pp(C, Opts, pp_assembler, fun(Asm) -> io:format("~s", [aeb_fate_asm:pp(Asm)]) end).
pp(Code, Options, Option, PPFun) -> pp(Code, Options, Option, PPFun) ->
case proplists:lookup(Option, Options) of case proplists:lookup(Option, Options) of
@@ -438,18 +385,18 @@ pp(Code, Options, Option, PPFun) ->
-define(protect(Tag, Code), fun() -> try Code catch _:Err1 -> throw({Tag, Err1}) end end()). -define(protect(Tag, Code), fun() -> try Code catch _:Err1 -> throw({Tag, Err1}) end end()).
-spec validate_byte_code(map(), string(), options()) -> ok | {error, [so_errors:error()]}. -spec validate_byte_code(map(), string(), options()) -> ok | {error, [aeso_errors:error()]}.
validate_byte_code(#{ byte_code := ByteCode, payable := Payable }, Source, Options) -> validate_byte_code(#{ byte_code := ByteCode, payable := Payable }, Source, Options) ->
Fail = fun(Err) -> {error, [so_errors:new(data_error, Err)]} end, Fail = fun(Err) -> {error, [aeso_errors:new(data_error, Err)]} end,
try try
FCode1 = ?protect(deserialize, gmb_fate_code:strip_init_function(gmb_fate_code:deserialize(ByteCode))), FCode1 = ?protect(deserialize, aeb_fate_code:strip_init_function(aeb_fate_code:deserialize(ByteCode))),
{FCode2, SrcPayable} = {FCode2, SrcPayable} =
?protect(compile, ?protect(compile,
begin begin
{ok, #{ byte_code := SrcByteCode, payable := SrcPayable }} = {ok, #{ byte_code := SrcByteCode, payable := SrcPayable }} =
from_string1(Source, Options), from_string1(Source, Options),
FCode = gmb_fate_code:deserialize(SrcByteCode), FCode = aeb_fate_code:deserialize(SrcByteCode),
{gmb_fate_code:strip_init_function(FCode), SrcPayable} {aeb_fate_code:strip_init_function(FCode), SrcPayable}
end), end),
case compare_fate_code(FCode1, FCode2) of case compare_fate_code(FCode1, FCode2) of
ok when SrcPayable /= Payable -> ok when SrcPayable /= Payable ->
@@ -465,10 +412,10 @@ validate_byte_code(#{ byte_code := ByteCode, payable := Payable }, Source, Optio
end. end.
compare_fate_code(FCode1, FCode2) -> compare_fate_code(FCode1, FCode2) ->
Funs1 = gmb_fate_code:functions(FCode1), Funs1 = aeb_fate_code:functions(FCode1),
Funs2 = gmb_fate_code:functions(FCode2), Funs2 = aeb_fate_code:functions(FCode2),
Syms1 = gmb_fate_code:symbols(FCode1), Syms1 = aeb_fate_code:symbols(FCode1),
Syms2 = gmb_fate_code:symbols(FCode2), Syms2 = aeb_fate_code:symbols(FCode2),
FunHashes1 = maps:keys(Funs1), FunHashes1 = maps:keys(Funs1),
FunHashes2 = maps:keys(Funs2), FunHashes2 = maps:keys(Funs2),
case FunHashes1 == FunHashes2 of case FunHashes1 == FunHashes2 of
@@ -513,13 +460,13 @@ pp_fate_type(T) -> io_lib:format("~w", [T]).
%% ------------------------------------------------------------------- %% -------------------------------------------------------------------
-spec parse(string(), so_compiler:options()) -> none() | so_syntax:ast(). -spec parse(string(), aeso_compiler:options()) -> none() | aeso_syntax:ast().
parse(Text, Options) -> parse(Text, Options) ->
parse(Text, sets:new(), Options). parse(Text, sets:new(), Options).
-spec parse(string(), sets:set(), so_compiler:options()) -> none() | so_syntax:ast(). -spec parse(string(), sets:set(), aeso_compiler:options()) -> none() | aeso_syntax:ast().
parse(Text, Included, Options) -> parse(Text, Included, Options) ->
so_parser:string(Text, Included, Options). aeso_parser:string(Text, Included, Options).
read_contract(Name) -> read_contract(Name) ->
file:read_file(Name). file:read_file(Name).
+4 -4
View File
@@ -5,7 +5,7 @@
%%% @end %%% @end
%%%------------------------------------------------------------------- %%%-------------------------------------------------------------------
-module(so_errors). -module(aeso_errors).
-type src_file() :: no_file | iolist(). -type src_file() :: no_file | iolist().
@@ -55,9 +55,9 @@ new(Type, Pos, Msg, Ctxt) ->
#err{ type = Type, pos = Pos, message = Msg, context = Ctxt }. #err{ type = Type, pos = Pos, message = Msg, context = Ctxt }.
pos(Ann) -> pos(Ann) ->
File = so_syntax:get_ann(file, Ann, no_file), File = aeso_syntax:get_ann(file, Ann, no_file),
Line = so_syntax:get_ann(line, Ann, 0), Line = aeso_syntax:get_ann(line, Ann, 0),
Col = so_syntax:get_ann(col, Ann, 0), Col = aeso_syntax:get_ann(col, Ann, 0),
pos(File, Line, Col). pos(File, Line, Col).
pos(Line, Col) -> pos(Line, Col) ->
File diff suppressed because it is too large Load Diff
+12 -19
View File
@@ -6,7 +6,7 @@
%%% Programming 14, 6 (November 2004) %%% Programming 14, 6 (November 2004)
%%% @end %%% @end
%%%------------------------------------------------------------------- %%%-------------------------------------------------------------------
-module(so_parse_lib). -module(aeso_parse_lib).
-export([parse/2, -export([parse/2,
return/1, fail/0, fail/1, fail/2, map/2, bind/2, return/1, fail/0, fail/1, fail/2, map/2, bind/2,
@@ -15,7 +15,7 @@
many/1, many1/1, sep/2, sep1/2, many/1, many1/1, sep/2, sep1/2,
infixl/2, infixr/2]). infixl/2, infixr/2]).
-export([current_file/0, set_current_file/1, current_dir/0, set_current_dir/1, -export([current_file/0, set_current_file/1,
current_include_type/0, set_current_include_type/1]). current_include_type/0, set_current_include_type/1]).
%% -- Types ------------------------------------------------------------------ %% -- Types ------------------------------------------------------------------
@@ -27,16 +27,16 @@
-type tokens() :: [token()]. -type tokens() :: [token()].
-type error() :: {pos(), string() | no_error}. -type error() :: {pos(), string() | no_error}.
-define(lazy(F), {so_parse_lazy, F}). -define(lazy(F), {aeso_parse_lazy, F}).
-define(fail(Err), {so_parse_fail, Err}). -define(fail(Err), {aeso_parse_fail, Err}).
-define(choice(Ps), {so_parse_choice, Ps}). -define(choice(Ps), {aeso_parse_choice, Ps}).
-define(bind(P, F), {so_parse_bind, P, F}). -define(bind(P, F), {aeso_parse_bind, P, F}).
-define(right(P, Q), {so_parse_right, P, Q}). -define(right(P, Q), {aeso_parse_right, P, Q}).
-define(left(P, Q), {so_parse_left, P, Q}). -define(left(P, Q), {aeso_parse_left, P, Q}).
-define(map(F, P), {so_parse_map, F, P}). -define(map(F, P), {aeso_parse_map, F, P}).
-define(layout, so_parse_layout). -define(layout, aeso_parse_layout).
-define(tok(Atom), {so_parse_tok, Atom}). -define(tok(Atom), {aeso_parse_tok, Atom}).
-define(return(X), {so_parse_return, X}). -define(return(X), {aeso_parse_return, X}).
%% Type synonyms since you can't have function types as macro arguments for some reason. %% Type synonyms since you can't have function types as macro arguments for some reason.
-type delayed(A) :: fun(() -> A). -type delayed(A) :: fun(() -> A).
@@ -480,13 +480,6 @@ current_file() ->
set_current_file(File) -> set_current_file(File) ->
put('$current_file', File). put('$current_file', File).
%% Current source directory
current_dir() ->
get('$current_dir').
set_current_dir(File) ->
put('$current_dir', File).
add_current_file({L, C}) -> {current_file(), L, C}; add_current_file({L, C}) -> {current_file(), L, C};
add_current_file(Pos) -> Pos. add_current_file(Pos) -> Pos.
@@ -1,7 +1,7 @@
-define(LET_P(X, P, Q), so_parse_lib:bind(P, fun(X) -> Q end)). -define(LET_P(X, P, Q), aeso_parse_lib:bind(P, fun(X) -> Q end)).
-define(LAZY_P(P), so_parse_lib:lazy(fun() -> P end)). -define(LAZY_P(P), aeso_parse_lib:lazy(fun() -> P end)).
-define(MEMO_P(P), so_parse_lib:lazy(so_parse_lib:memoised(fun() -> P end))). -define(MEMO_P(P), aeso_parse_lib:lazy(aeso_parse_lib:memoised(fun() -> P end))).
-define(GUARD_P(G, P), -define(GUARD_P(G, P),
case G of case G of
@@ -18,7 +18,7 @@
-define(RULE(A, B, C, D, E, F, G, Do), map(fun({_1, _2, _3, _4, _5, _6, _7}) -> Do end, {A, B, C, D, E, F, G} )). -define(RULE(A, B, C, D, E, F, G, Do), map(fun({_1, _2, _3, _4, _5, _6, _7}) -> Do end, {A, B, C, D, E, F, G} )).
-define(RULE(A, B, C, D, E, F, G, H, Do), map(fun({_1, _2, _3, _4, _5, _6, _7, _8}) -> Do end, {A, B, C, D, E, F, G, H})). -define(RULE(A, B, C, D, E, F, G, H, Do), map(fun({_1, _2, _3, _4, _5, _6, _7, _8}) -> Do end, {A, B, C, D, E, F, G, H})).
-import(so_parse_lib, -import(aeso_parse_lib,
[tok/1, tok/2, between/3, many/1, many1/1, sep/2, sep1/2, [tok/1, tok/2, between/3, many/1, many1/1, sep/2, sep1/2,
infixl/1, infixr/1, choice/1, choice/2, return/1, layout/0, infixl/1, infixr/1, choice/1, choice/2, return/1, layout/0,
fail/0, fail/1, fail/2, map/2, infixl/2, infixr/2, infixl1/2, infixr1/2, fail/0, fail/1, fail/2, map/2, infixl/2, infixr/2, infixl1/2, infixr1/2,
+50 -82
View File
@@ -1,8 +1,8 @@
%%% File : so_parser.erl %%% File : aeso_parser.erl
%%% Author : Ulf Norell %%% Author : Ulf Norell
%%% Description : %%% Description :
%%% Created : 1 Mar 2018 by Ulf Norell %%% Created : 1 Mar 2018 by Ulf Norell
-module(so_parser). -module(aeso_parser).
-compile({no_auto_import,[map_get/2]}). -compile({no_auto_import,[map_get/2]}).
-export([string/1, -export([string/1,
@@ -17,12 +17,11 @@
run_parser/2, run_parser/2,
run_parser/3]). run_parser/3]).
-include("so_parse_lib.hrl"). -include("aeso_parse_lib.hrl").
-import(so_parse_lib, [current_file/0, set_current_file/1, -import(aeso_parse_lib, [current_file/0, set_current_file/1,
current_dir/0, set_current_dir/1,
current_include_type/0, set_current_include_type/1]). current_include_type/0, set_current_include_type/1]).
-type parse_result() :: so_syntax:ast() | {so_syntax:ast(), sets:set(include_hash())} | none(). -type parse_result() :: aeso_syntax:ast() | {aeso_syntax:ast(), sets:set(include_hash())} | none().
-type include_hash() :: {string(), binary()}. -type include_hash() :: {string(), binary()}.
@@ -36,14 +35,14 @@ escape_errors({error, Err}) ->
string(String) -> string(String) ->
string(String, sets:new(), []). string(String, sets:new(), []).
-spec string(string(), so_compiler:options()) -> parse_result(). -spec string(string(), aeso_compiler:options()) -> parse_result().
string(String, Opts) -> string(String, Opts) ->
case lists:keyfind(src_file, 1, Opts) of case lists:keyfind(src_file, 1, Opts) of
{src_file, File} -> string(String, sets:add_element(File, sets:new()), Opts); {src_file, File} -> string(String, sets:add_element(File, sets:new()), Opts);
false -> string(String, sets:new(), Opts) false -> string(String, sets:new(), Opts)
end. end.
-spec string(string(), sets:set(include_hash()), so_compiler:options()) -> parse_result(). -spec string(string(), sets:set(include_hash()), aeso_compiler:options()) -> parse_result().
string(String, Included, Opts) -> string(String, Included, Opts) ->
AST = run_parser(file(), String, Opts), AST = run_parser(file(), String, Opts),
case expand_includes(AST, Included, Opts) of case expand_includes(AST, Included, Opts) of
@@ -59,20 +58,19 @@ run_parser(P, Inp, Opts) ->
parse_and_scan(P, S, Opts) -> parse_and_scan(P, S, Opts) ->
set_current_file(proplists:get_value(src_file, Opts, no_file)), set_current_file(proplists:get_value(src_file, Opts, no_file)),
set_current_dir(proplists:get_value(src_dir, Opts, no_file)),
set_current_include_type(proplists:get_value(include_type, Opts, none)), set_current_include_type(proplists:get_value(include_type, Opts, none)),
case so_scan:scan(S) of case aeso_scan:scan(S) of
{ok, Tokens} -> so_parse_lib:parse(P, Tokens); {ok, Tokens} -> aeso_parse_lib:parse(P, Tokens);
{error, {{Input, Pos}, _}} -> {error, {{Input, Pos}, _}} ->
{error, {Pos, scan_error, Input}} {error, {Pos, scan_error, Input}}
end. end.
-dialyzer({nowarn_function, parse_error/1}). -dialyzer({nowarn_function, parse_error/1}).
parse_error(Err) -> parse_error(Err) ->
so_errors:throw(mk_error(Err)). aeso_errors:throw(mk_error(Err)).
mk_p_err(Pos, Msg) -> mk_p_err(Pos, Msg) ->
so_errors:new(parse_error, mk_pos(Pos), lists:flatten(Msg)). aeso_errors:new(parse_error, mk_pos(Pos), lists:flatten(Msg)).
mk_error({Pos, scan_error, Input}) -> mk_error({Pos, scan_error, Input}) ->
mk_p_err(Pos, io_lib:format("Lexical error on input: ~s\n", [Input])); mk_p_err(Pos, io_lib:format("Lexical error on input: ~s\n", [Input]));
@@ -86,8 +84,8 @@ mk_error({Pos, include_error, File}) ->
Msg = io_lib:format("Couldn't find include file '~s'\n", [File]), Msg = io_lib:format("Couldn't find include file '~s'\n", [File]),
mk_p_err(Pos, Msg). mk_p_err(Pos, Msg).
mk_pos({Line, Col}) -> so_errors:pos(Line, Col); mk_pos({Line, Col}) -> aeso_errors:pos(Line, Col);
mk_pos({File, Line, Col}) -> so_errors:pos(File, Line, Col). mk_pos({File, Line, Col}) -> aeso_errors:pos(File, Line, Col).
%% -- Parsing rules ---------------------------------------------------------- %% -- Parsing rules ----------------------------------------------------------
@@ -266,11 +264,10 @@ type300() ->
type400() -> type400() ->
choice( choice(
[?RULE(typeAtom(), optional(type_args()), [?RULE(typeAtom(), optional(type_args()),
any_bytes( case _2 of
case _2 of none -> _1;
none -> _1; {ok, Args} -> {app_t, get_ann(_1), _1, Args}
{ok, Args} -> {app_t, get_ann(_1), _1, Args} end),
end)),
?RULE(id("bytes"), parens(token(int)), ?RULE(id("bytes"), parens(token(int)),
{bytes_t, get_ann(_1), element(3, _2)}) {bytes_t, get_ann(_1), element(3, _2)})
]). ]).
@@ -302,7 +299,7 @@ stmt() ->
, {switch, keyword(switch), parens(expr()), maybe_block(branch())} , {switch, keyword(switch), parens(expr()), maybe_block(branch())}
, {'if', keyword('if'), parens(expr()), body()} , {'if', keyword('if'), parens(expr()), body()}
, {elif, keyword(elif), parens(expr()), body()} , {elif, keyword(elif), parens(expr()), body()}
, {'else', keyword('else'), body()} , {else, keyword(else), body()}
])). ])).
branch() -> branch() ->
@@ -326,7 +323,7 @@ expr100() ->
Expr150 = ?LAZY_P(expr150()), Expr150 = ?LAZY_P(expr150()),
choice( choice(
[ ?RULE(lam_args(), keyword('=>'), body(), {lam, _2, _1, _3}) %% TODO: better location [ ?RULE(lam_args(), keyword('=>'), body(), {lam, _2, _1, _3}) %% TODO: better location
, {'if', keyword('if'), parens(Expr100), Expr150, right(tok('else'), Expr100)} , {'if', keyword('if'), parens(Expr100), Expr150, right(tok(else), Expr100)}
, ?RULE(Expr150, optional(right(tok(':'), type())), , ?RULE(Expr150, optional(right(tok(':'), type())),
case _2 of case _2 of
none -> _1; none -> _1;
@@ -367,12 +364,9 @@ exprAtom() ->
, ?RULE(tok('['), Expr, binop('..'), Expr, tok(']'), _3(_2, _4)) , ?RULE(tok('['), Expr, binop('..'), Expr, tok(']'), _3(_2, _4))
, ?RULE(keyword('('), comma_sep(Expr), tok(')'), tuple_e(_1, _2)) , ?RULE(keyword('('), comma_sep(Expr), tok(')'), tuple_e(_1, _2))
, letpat() , letpat()
, hole()
]) ])
end). end).
hole() -> ?RULE(token('???'), {id, get_ann(_1), "???"}).
comprehension_exp() -> comprehension_exp() ->
?LAZY_P(choice( ?LAZY_P(choice(
[ comprehension_bind() [ comprehension_bind()
@@ -411,7 +405,7 @@ map_key(Key, {ok, {_, Val}}) -> {map_key, Key, Val}.
elim(E, []) -> E; elim(E, []) -> E;
elim(E, [{proj, Ann, P} | Es]) -> elim({proj, Ann, E, P}, Es); elim(E, [{proj, Ann, P} | Es]) -> elim({proj, Ann, E, P}, Es);
elim(E, [{app, _Ann, Args} | Es]) -> elim({app, so_syntax:get_ann(E), E, Args}, Es); elim(E, [{app, _Ann, Args} | Es]) -> elim({app, aeso_syntax:get_ann(E), E, Args}, Es);
elim(E, [{rec_upd, Ann, Flds} | Es]) -> elim(record_update(Ann, E, Flds), Es); elim(E, [{rec_upd, Ann, Flds} | Es]) -> elim(record_update(Ann, E, Flds), Es);
elim(E, [{map_get, Ann, Key} | Es]) -> elim({map_get, Ann, E, Key}, Es); elim(E, [{map_get, Ann, Key} | Es]) -> elim({map_get, Ann, E, Key}, Es);
elim(E, [{map_get, Ann, Key, Val} | Es]) -> elim({map_get, Ann, E, Key, Val}, Es). elim(E, [{map_get, Ann, Key, Val} | Es]) -> elim({map_get, Ann, E, Key, Val}, Es).
@@ -525,10 +519,10 @@ id_or_addr() ->
?RULE(id(), parse_addr_literal(_1)). ?RULE(id(), parse_addr_literal(_1)).
parse_addr_literal(Id = {id, Ann, Name}) -> parse_addr_literal(Id = {id, Ann, Name}) ->
case lists:member(lists:sublist(Name, 3), ["ak_", "ok_", "oq_", "ct_", "sg_"]) of case lists:member(lists:sublist(Name, 3), ["ak_", "ok_", "oq_", "ct_"]) of
false -> Id; false -> Id;
true -> true ->
try gmser_api_encoder:decode(list_to_binary(Name)) of try aeser_api_encoder:decode(list_to_binary(Name)) of
{Type, Bin} -> {Type, Ann, Bin} {Type, Bin} -> {Type, Ann, Bin}
catch _:_ -> catch _:_ ->
Id Id
@@ -557,14 +551,13 @@ bracket_list(P) -> brackets(comma_sep(P)).
%% -- Annotations ------------------------------------------------------------ %% -- Annotations ------------------------------------------------------------
-type ann() :: so_syntax:ann(). -type ann() :: aeso_syntax:ann().
-type ann_line() :: so_syntax:ann_line(). -type ann_line() :: aeso_syntax:ann_line().
-type ann_col() :: so_syntax:ann_col(). -type ann_col() :: aeso_syntax:ann_col().
-spec pos_ann(ann_line(), ann_col()) -> ann(). -spec pos_ann(ann_line(), ann_col()) -> ann().
pos_ann(Line, Col) -> pos_ann(Line, Col) ->
[ {file, current_file()} [ {file, current_file()}
, {dir, current_dir()}
, {include_type, current_include_type()} , {include_type, current_include_type()}
, {line, Line} , {line, Line}
, {col, Col} ]. , {col, Col} ].
@@ -612,7 +605,7 @@ group_ifs([], Acc) ->
group_ifs([{'if', Ann, Cond, Then} | Stmts], Acc) -> group_ifs([{'if', Ann, Cond, Then} | Stmts], Acc) ->
{Elses, Rest} = else_branches(Stmts, []), {Elses, Rest} = else_branches(Stmts, []),
group_ifs(Rest, [build_if(Ann, Cond, Then, Elses) | Acc]); group_ifs(Rest, [build_if(Ann, Cond, Then, Elses) | Acc]);
group_ifs([{'else', Ann, _} | _], _) -> group_ifs([{else, Ann, _} | _], _) ->
fail({Ann, "No matching 'if' for 'else'"}); fail({Ann, "No matching 'if' for 'else'"});
group_ifs([{elif, Ann, _, _} | _], _) -> group_ifs([{elif, Ann, _, _} | _], _) ->
fail({Ann, "No matching 'if' for 'elif'"}); fail({Ann, "No matching 'if' for 'elif'"});
@@ -622,14 +615,14 @@ group_ifs([Stmt | Stmts], Acc) ->
build_if(Ann, Cond, Then, [{elif, Ann1, Cond1, Then1} | Elses]) -> build_if(Ann, Cond, Then, [{elif, Ann1, Cond1, Then1} | Elses]) ->
{'if', Ann, Cond, Then, {'if', Ann, Cond, Then,
set_ann(format, elif, build_if(Ann1, Cond1, Then1, Elses))}; set_ann(format, elif, build_if(Ann1, Cond1, Then1, Elses))};
build_if(Ann, Cond, Then, [{'else', _Ann, Else}]) -> build_if(Ann, Cond, Then, [{else, _Ann, Else}]) ->
{'if', Ann, Cond, Then, Else}; {'if', Ann, Cond, Then, Else};
build_if(Ann, Cond, Then, []) -> build_if(Ann, Cond, Then, []) ->
{'if', Ann, Cond, Then, {tuple, [{origin, system}], []}}. {'if', Ann, Cond, Then, {tuple, [{origin, system}], []}}.
else_branches([Elif = {elif, _, _, _} | Stmts], Acc) -> else_branches([Elif = {elif, _, _, _} | Stmts], Acc) ->
else_branches(Stmts, [Elif | Acc]); else_branches(Stmts, [Elif | Acc]);
else_branches([Else = {'else', _, _} | Stmts], Acc) -> else_branches([Else = {else, _, _} | Stmts], Acc) ->
{lists:reverse([Else | Acc]), Stmts}; {lists:reverse([Else | Acc]), Stmts};
else_branches(Stmts, Acc) -> else_branches(Stmts, Acc) ->
{lists:reverse(Acc), Stmts}. {lists:reverse(Acc), Stmts}.
@@ -647,7 +640,7 @@ tuple_e(Ann, Exprs) -> {tuple, Ann, Exprs}.
list_comp_e(Ann, Expr, Binds) -> {list_comp, Ann, Expr, Binds}. list_comp_e(Ann, Expr, Binds) -> {list_comp, Ann, Expr, Binds}.
-spec parse_pattern(so_syntax:expr()) -> so_parse_lib:parser(so_syntax:pat()). -spec parse_pattern(aeso_syntax:expr()) -> aeso_parse_lib:parser(aeso_syntax:pat()).
parse_pattern({letpat, Ann, Id, Pat}) -> parse_pattern({letpat, Ann, Id, Pat}) ->
{letpat, Ann, Id, parse_pattern(Pat)}; {letpat, Ann, Id, parse_pattern(Pat)};
parse_pattern({app, Ann, Con = {'::', _}, Es}) -> parse_pattern({app, Ann, Con = {'::', _}, Es}) ->
@@ -674,19 +667,19 @@ parse_pattern(E = {string, _, _}) -> E;
parse_pattern(E = {char, _, _}) -> E; parse_pattern(E = {char, _, _}) -> E;
parse_pattern(E) -> bad_expr_err("Not a valid pattern", E). parse_pattern(E) -> bad_expr_err("Not a valid pattern", E).
-spec parse_field_pattern(so_syntax:field(so_syntax:expr())) -> so_parse_lib:parser(so_syntax:field(so_syntax:pat())). -spec parse_field_pattern(aeso_syntax:field(aeso_syntax:expr())) -> aeso_parse_lib:parser(aeso_syntax:field(aeso_syntax:pat())).
parse_field_pattern({field, Ann, F, E}) -> parse_field_pattern({field, Ann, F, E}) ->
{field, Ann, F, parse_pattern(E)}. {field, Ann, F, parse_pattern(E)}.
-spec ret_doc_err(ann(), prettypr:document()) -> so_parse_lib:parser(none()). -spec ret_doc_err(ann(), prettypr:document()) -> aeso_parse_lib:parser(none()).
ret_doc_err(Ann, Doc) -> ret_doc_err(Ann, Doc) ->
fail(ann_pos(Ann), prettypr:format(Doc)). fail(ann_pos(Ann), prettypr:format(Doc)).
-spec bad_expr_err(string(), so_syntax:expr()) -> so_parse_lib:parser(none()). -spec bad_expr_err(string(), aeso_syntax:expr()) -> aeso_parse_lib:parser(none()).
bad_expr_err(Reason, E) -> bad_expr_err(Reason, E) ->
ret_doc_err(get_ann(E), ret_doc_err(get_ann(E),
prettypr:sep([prettypr:text(Reason ++ ":"), prettypr:sep([prettypr:text(Reason ++ ":"),
prettypr:nest(2, so_pretty:expr(E))])). prettypr:nest(2, aeso_pretty:expr(E))])).
%% -- Helper functions ------------------------------------------------------- %% -- Helper functions -------------------------------------------------------
@@ -705,7 +698,7 @@ expand_includes([], Included, Acc, Opts) ->
end; end;
expand_includes([{include, Ann, {string, _SAnn, File}} | AST], Included, Acc, Opts) -> expand_includes([{include, Ann, {string, _SAnn, File}} | AST], Included, Acc, Opts) ->
case get_include_code(File, Ann, Opts) of case get_include_code(File, Ann, Opts) of
{ok, AbsDir, Code} -> {ok, Code} ->
Hashed = hash_include(File, Code), Hashed = hash_include(File, Code),
case sets:is_element(Hashed, Included) of case sets:is_element(Hashed, Included) of
false -> false ->
@@ -715,10 +708,9 @@ expand_includes([{include, Ann, {string, _SAnn, File}} | AST], Included, Acc, Op
_ -> indirect _ -> indirect
end, end,
Opts1 = lists:keystore(src_file, 1, Opts, {src_file, File}), Opts1 = lists:keystore(src_file, 1, Opts, {src_file, File}),
Opts2 = lists:keystore(src_dir, 1, Opts1, {src_dir, AbsDir}), Opts2 = lists:keystore(include_type, 1, Opts1, {include_type, IncludeType}),
Opts3 = lists:keystore(include_type, 1, Opts2, {include_type, IncludeType}),
Included1 = sets:add_element(Hashed, Included), Included1 = sets:add_element(Hashed, Included),
case parse_and_scan(file(), Code, Opts3) of case parse_and_scan(file(), Code, Opts2) of
{ok, AST1} -> {ok, AST1} ->
expand_includes(AST1 ++ AST, Included1, Acc, Opts); expand_includes(AST1 ++ AST, Included1, Acc, Opts);
Err = {error, _} -> Err = {error, _} ->
@@ -736,21 +728,22 @@ expand_includes([E | AST], Included, Acc, Opts) ->
read_file(File, Opts) -> read_file(File, Opts) ->
case proplists:get_value(include, Opts, {explicit_files, #{}}) of case proplists:get_value(include, Opts, {explicit_files, #{}}) of
{file_system, Paths} -> {file_system, Paths} ->
lists:foldr(fun(Path, {error, _}) -> read_file_(Path, File); CandidateNames = [ filename:join(Dir, File) || Dir <- Paths ],
(_Path, OK) -> OK end, {error, not_found}, Paths); lists:foldr(fun(F, {error, _}) -> file:read_file(F);
(_F, OK) -> OK end, {error, not_found}, CandidateNames);
{explicit_files, Files} -> {explicit_files, Files} ->
case maps:get(binary_to_list(File), Files, not_found) of case maps:get(binary_to_list(File), Files, not_found) of
not_found -> {error, not_found}; not_found -> {error, not_found};
Src -> {ok, File, Src} Src -> {ok, Src}
end; end;
escript -> escript ->
try try
Escript = escript:script_name(), Escript = escript:script_name(),
{ok, Sections} = escript:extract(Escript, []), {ok, Sections} = escript:extract(Escript, []),
Archive = proplists:get_value(archive, Sections), Archive = proplists:get_value(archive, Sections),
FileName = binary_to_list(filename:join([sophia, priv, stdlib, File])), FileName = binary_to_list(filename:join([aesophia, priv, stdlib, File])),
case zip:extract(Archive, [{file_list, [FileName]}, memory]) of case zip:extract(Archive, [{file_list, [FileName]}, memory]) of
{ok, [{_, Src}]} -> {ok, escript, Src}; {ok, [{_, Src}]} -> {ok, Src};
_ -> {error, not_found} _ -> {error, not_found}
end end
catch _:_ -> catch _:_ ->
@@ -758,52 +751,31 @@ read_file(File, Opts) ->
end end
end. end.
read_file_(Path, File) ->
AbsFile = filename:join(Path, File),
case file:read_file(AbsFile) of
{ok, Bin} -> {ok, so_utils:canonical_dir(filename:dirname(AbsFile)), Bin};
Err -> Err
end.
stdlib_options() -> stdlib_options() ->
StdLibDir = so_stdlib:stdlib_include_path(), StdLibDir = aeso_stdlib:stdlib_include_path(),
case filelib:is_dir(StdLibDir) of case filelib:is_dir(StdLibDir) of
true -> [{include, {file_system, [StdLibDir]}}]; true -> [{include, {file_system, [StdLibDir]}}];
false -> [{include, escript}] false -> [{include, escript}]
end. end.
get_include_code(File, Ann, Opts) -> get_include_code(File, Ann, Opts) ->
%% Temporarily extend include paths with the directory of the current file case {read_file(File, Opts), read_file(File, stdlib_options())} of
Opts1 = include_current_file_dir(Opts, Ann), {{ok, Bin}, {ok, _}} ->
case {read_file(File, Opts1), read_file(File, stdlib_options())} of
{{ok, Dir, Bin}, {ok, _}} ->
case filename:basename(File) == File of case filename:basename(File) == File of
true -> { error true -> { error
, fail( ann_pos(Ann) , fail( ann_pos(Ann)
, "Illegal redefinition of standard library " ++ binary_to_list(File))}; , "Illegal redefinition of standard library " ++ binary_to_list(File))};
%% If a path is provided then the stdlib takes lower priority %% If a path is provided then the stdlib takes lower priority
false -> {ok, Dir, binary_to_list(Bin)} false -> {ok, binary_to_list(Bin)}
end; end;
{_, {ok, _, Bin}} -> {_, {ok, Bin}} ->
{ok, stdlib, binary_to_list(Bin)}; {ok, binary_to_list(Bin)};
{{ok, Dir, Bin}, _} -> {{ok, Bin}, _} ->
{ok, Dir, binary_to_list(Bin)}; {ok, binary_to_list(Bin)};
{_, _} -> {_, _} ->
{error, {ann_pos(Ann), include_error, File}} {error, {ann_pos(Ann), include_error, File}}
end. end.
include_current_file_dir(Opts, Ann) ->
case {proplists:get_value(dir, Ann, undefined),
proplists:get_value(include, Opts, undefined)} of
{undefined, _} -> Opts;
{CurrDir, {file_system, Paths}} ->
case lists:member(CurrDir, Paths) of
false -> [{include, {file_system, [CurrDir | Paths]}} | Opts];
true -> Opts
end;
{_, _} -> Opts
end.
-spec hash_include(string() | binary(), string()) -> include_hash(). -spec hash_include(string() | binary(), string()) -> include_hash().
hash_include(File, Code) when is_binary(File) -> hash_include(File, Code) when is_binary(File) ->
hash_include(binary_to_list(File), Code); hash_include(binary_to_list(File), Code);
@@ -817,7 +789,3 @@ auto_imports(L) when is_list(L) ->
auto_imports(T) when is_tuple(T) -> auto_imports(T) when is_tuple(T) ->
auto_imports(tuple_to_list(T)); auto_imports(tuple_to_list(T));
auto_imports(_) -> []. auto_imports(_) -> [].
any_bytes({id, Ann, "bytes"}) -> {bytes_t, Ann, any};
any_bytes({app_t, _, {id, Ann, "bytes"}, []}) -> {bytes_t, Ann, any};
any_bytes(Type) -> Type.
+44 -47
View File
@@ -5,7 +5,7 @@
%%% %%%
%%% @end %%% @end
%%%------------------------------------------------------------------- %%%-------------------------------------------------------------------
-module(so_pretty). -module(aeso_pretty).
-import(prettypr, [text/1, sep/1, above/2, beside/2, nest/2, empty/0]). -import(prettypr, [text/1, sep/1, above/2, beside/2, nest/2, empty/0]).
@@ -13,7 +13,7 @@
-export_type([options/0]). -export_type([options/0]).
-include("so_utils.hrl"). -include("aeso_utils.hrl").
-type doc() :: prettypr:document(). -type doc() :: prettypr:document().
-type options() :: [{indent, non_neg_integer()} | show_generated]. -type options() :: [{indent, non_neg_integer()} | show_generated].
@@ -24,11 +24,11 @@
%% -- Options ---------------------------------------------------------------- %% -- Options ----------------------------------------------------------------
-define(so_pretty_opts, so_pretty_opts). -define(aeso_pretty_opts, aeso_pretty_opts).
-spec options() -> options(). -spec options() -> options().
options() -> options() ->
case get(?so_pretty_opts) of case get(?aeso_pretty_opts) of
undefined -> []; undefined -> [];
Opts -> Opts Opts -> Opts
end. end.
@@ -45,9 +45,9 @@ indent() -> option(indent, 2).
-spec with_options(options(), fun(() -> A)) -> A. -spec with_options(options(), fun(() -> A)) -> A.
with_options(Options, Fun) -> with_options(Options, Fun) ->
put(?so_pretty_opts, Options), put(?aeso_pretty_opts, Options),
Res = Fun(), Res = Fun(),
erase(?so_pretty_opts), erase(?aeso_pretty_opts),
Res. Res.
%% -- Pretty printing helpers ------------------------------------------------ %% -- Pretty printing helpers ------------------------------------------------
@@ -125,9 +125,9 @@ record(Ds) ->
equals(A, B) -> follow(hsep(A, text("=")), B). equals(A, B) -> follow(hsep(A, text("=")), B).
%% typed(A, B) -> A : B. %% typed(A, B) -> A : B.
-spec typed(doc(), so_syntax:type()) -> doc(). -spec typed(doc(), aeso_syntax:type()) -> doc().
typed(A, Type) -> typed(A, Type) ->
case so_syntax:get_ann(origin, Type) == system andalso case aeso_syntax:get_ann(origin, Type) == system andalso
not show_generated() of not show_generated() of
true -> A; true -> A;
false -> follow(hsep(A, text(":")), type(Type)) false -> follow(hsep(A, text(":")), type(Type))
@@ -139,18 +139,18 @@ contract_head(contract_interface) -> text("contract interface").
%% -- Exports ---------------------------------------------------------------- %% -- Exports ----------------------------------------------------------------
-spec decls([so_syntax:decl()], options()) -> doc(). -spec decls([aeso_syntax:decl()], options()) -> doc().
decls(Ds, Options) -> decls(Ds, Options) ->
with_options(Options, fun() -> decls(Ds) end). with_options(Options, fun() -> decls(Ds) end).
-spec decls([so_syntax:decl()]) -> doc(). -spec decls([aeso_syntax:decl()]) -> doc().
decls(Ds) -> above([ decl(D) || D <- Ds ]). decls(Ds) -> above([ decl(D) || D <- Ds ]).
-spec decl(so_syntax:decl(), options()) -> doc(). -spec decl(aeso_syntax:decl(), options()) -> doc().
decl(D, Options) -> decl(D, Options) ->
with_options(Options, fun() -> decl(D) end). with_options(Options, fun() -> decl(D) end).
-spec decl(so_syntax:decl()) -> doc(). -spec decl(aeso_syntax:decl()) -> doc().
decl({Con, Attrs, C, Is, Ds}) when ?IS_CONTRACT_HEAD(Con) -> decl({Con, Attrs, C, Is, Ds}) when ?IS_CONTRACT_HEAD(Con) ->
Mod = fun({Mod, true}) when Mod == payable -> Mod = fun({Mod, true}) when Mod == payable ->
text(atom_to_list(Mod)); text(atom_to_list(Mod));
@@ -172,7 +172,7 @@ decl({fun_decl, Ann, F, T}) ->
Mod = fun({Mod, true}) when Mod == private; Mod == stateful; Mod == payable -> Mod = fun({Mod, true}) when Mod == private; Mod == stateful; Mod == payable ->
text(atom_to_list(Mod)); text(atom_to_list(Mod));
(_) -> empty() end, (_) -> empty() end,
Fun = case so_syntax:get_ann(entrypoint, Ann, false) of Fun = case aeso_syntax:get_ann(entrypoint, Ann, false) of
true -> text("entrypoint"); true -> text("entrypoint");
false -> text("function") false -> text("function")
end, end,
@@ -181,7 +181,7 @@ decl(D = {letfun, Attrs, _, _, _, _}) ->
Mod = fun({Mod, true}) when Mod == private; Mod == stateful; Mod == payable -> Mod = fun({Mod, true}) when Mod == private; Mod == stateful; Mod == payable ->
text(atom_to_list(Mod)); text(atom_to_list(Mod));
(_) -> empty() end, (_) -> empty() end,
Fun = case so_syntax:get_ann(entrypoint, Attrs, false) of Fun = case aeso_syntax:get_ann(entrypoint, Attrs, false) of
true -> "entrypoint"; true -> "entrypoint";
false -> "function" false -> "function"
end, end,
@@ -192,20 +192,20 @@ decl(D = {letval, _, _, _}) -> letdecl("let", D);
decl({block, _, Ds}) -> decl({block, _, Ds}) ->
above([ decl(D) || D <- Ds ]). above([ decl(D) || D <- Ds ]).
-spec pragma(so_syntax:pragma()) -> doc(). -spec pragma(aeso_syntax:pragma()) -> doc().
pragma({compiler, Op, Ver}) -> pragma({compiler, Op, Ver}) ->
text("@compiler " ++ atom_to_list(Op) ++ " " ++ string:join([integer_to_list(N) || N <- Ver], ".")). text("@compiler " ++ atom_to_list(Op) ++ " " ++ string:join([integer_to_list(N) || N <- Ver], ".")).
-spec expr(so_syntax:expr(), options()) -> doc(). -spec expr(aeso_syntax:expr(), options()) -> doc().
expr(E, Options) -> expr(E, Options) ->
with_options(Options, fun() -> expr(E) end). with_options(Options, fun() -> expr(E) end).
-spec expr(so_syntax:expr()) -> doc(). -spec expr(aeso_syntax:expr()) -> doc().
expr(E) -> expr_p(0, E). expr(E) -> expr_p(0, E).
%% -- Not exported ----------------------------------------------------------- %% -- Not exported -----------------------------------------------------------
-spec name(so_syntax:id() | so_syntax:qid() | so_syntax:con() | so_syntax:qcon() | so_syntax:tvar()) -> doc(). -spec name(aeso_syntax:id() | aeso_syntax:qid() | aeso_syntax:con() | aeso_syntax:qcon() | aeso_syntax:tvar()) -> doc().
name({id, _, Name}) -> text(Name); name({id, _, Name}) -> text(Name);
name({con, _, Name}) -> text(Name); name({con, _, Name}) -> text(Name);
name({qid, _, Names}) -> text(string:join(Names, ".")); name({qid, _, Names}) -> text(string:join(Names, "."));
@@ -213,7 +213,7 @@ name({qcon, _, Names}) -> text(string:join(Names, "."));
name({tvar, _, Name}) -> text(Name); name({tvar, _, Name}) -> text(Name);
name({typed, _, Name, _}) -> name(Name). name({typed, _, Name, _}) -> name(Name).
-spec letdecl(string(), so_syntax:letbind()) -> doc(). -spec letdecl(string(), aeso_syntax:letbind()) -> doc().
letdecl(Let, {letval, _, P, E}) -> letdecl(Let, {letval, _, P, E}) ->
block_expr(0, hsep([text(Let), expr(P), text("=")]), E); block_expr(0, hsep([text(Let), expr(P), text("=")]), E);
letdecl(Let, {letfun, _, F, Args, T, [GuardedBody]}) -> letdecl(Let, {letfun, _, F, Args, T, [GuardedBody]}) ->
@@ -221,14 +221,14 @@ letdecl(Let, {letfun, _, F, Args, T, [GuardedBody]}) ->
letdecl(Let, {letfun, _, F, Args, T, GuardedBodies}) -> letdecl(Let, {letfun, _, F, Args, T, GuardedBodies}) ->
block(hsep([text(Let), typed(beside(name(F), expr({tuple, [], Args})), T)]), above(lists:map(fun(GB) -> guarded_body(GB, "=") end, GuardedBodies))). block(hsep([text(Let), typed(beside(name(F), expr({tuple, [], Args})), T)]), above(lists:map(fun(GB) -> guarded_body(GB, "=") end, GuardedBodies))).
-spec args([so_syntax:arg()]) -> doc(). -spec args([aeso_syntax:arg()]) -> doc().
args(Args) -> args(Args) ->
tuple(lists:map(fun arg/1, Args)). tuple(lists:map(fun arg/1, Args)).
-spec arg(so_syntax:arg()) -> doc(). -spec arg(aeso_syntax:arg()) -> doc().
arg({arg, _, X, T}) -> typed(name(X), T). arg({arg, _, X, T}) -> typed(name(X), T).
-spec typedecl(alias_t | record_t | variant_t, so_syntax:id(), [so_syntax:tvar()]) -> doc(). -spec typedecl(alias_t | record_t | variant_t, aeso_syntax:id(), [aeso_syntax:tvar()]) -> doc().
typedecl(Kind, T, Vars) -> typedecl(Kind, T, Vars) ->
KW = case Kind of KW = case Kind of
alias_t -> text("type"); alias_t -> text("type");
@@ -241,26 +241,26 @@ typedecl(Kind, T, Vars) ->
tuple(lists:map(fun name/1, Vars))) tuple(lists:map(fun name/1, Vars)))
end. end.
-spec typedef(so_syntax:typedef()) -> doc(). -spec typedef(aeso_syntax:typedef()) -> doc().
typedef({alias_t, Type}) -> type(Type); typedef({alias_t, Type}) -> type(Type);
typedef({record_t, Fields}) -> typedef({record_t, Fields}) ->
record(lists:map(fun field_t/1, Fields)); record(lists:map(fun field_t/1, Fields));
typedef({variant_t, Constructors}) -> typedef({variant_t, Constructors}) ->
par(punctuate(text(" |"), lists:map(fun constructor_t/1, Constructors))). par(punctuate(text(" |"), lists:map(fun constructor_t/1, Constructors))).
-spec constructor_t(so_syntax:constructor_t()) -> doc(). -spec constructor_t(aeso_syntax:constructor_t()) -> doc().
constructor_t({constr_t, _, C, []}) -> name(C); constructor_t({constr_t, _, C, []}) -> name(C);
constructor_t({constr_t, _, C, Args}) -> beside(name(C), args_type(Args)). constructor_t({constr_t, _, C, Args}) -> beside(name(C), args_type(Args)).
-spec field_t(so_syntax:field_t()) -> doc(). -spec field_t(aeso_syntax:field_t()) -> doc().
field_t({field_t, _, Name, Type}) -> field_t({field_t, _, Name, Type}) ->
typed(name(Name), Type). typed(name(Name), Type).
-spec type(so_syntax:type(), options()) -> doc(). -spec type(aeso_syntax:type(), options()) -> doc().
type(Type, Options) -> type(Type, Options) ->
with_options(Options, fun() -> type(Type) end). with_options(Options, fun() -> type(Type) end).
-spec type(so_syntax:type()) -> doc(). -spec type(aeso_syntax:type()) -> doc().
type(F = {fun_t, _, _, var_args, _}) -> type(F = {fun_t, _, _, var_args, _}) ->
type(setelement(4, F, [var_args])); type(setelement(4, F, [var_args]));
type({fun_t, _, Named, Args, Ret}) -> type({fun_t, _, Named, Args, Ret}) ->
@@ -275,9 +275,7 @@ type({tuple_t, _, Args}) ->
tuple_type(Args); tuple_type(Args);
type({args_t, _, Args}) -> type({args_t, _, Args}) ->
args_type(Args); args_type(Args);
type({bytes_t, _, any}) -> text("bytes()"); type({bytes_t, _, any}) -> text("bytes(_)");
type({bytes_t, _, '_'}) -> text("bytes(_)");
type({bytes_t, _, fixed}) -> text("bytes(_)");
type({bytes_t, _, Len}) -> type({bytes_t, _, Len}) ->
text(lists:concat(["bytes(", Len, ")"])); text(lists:concat(["bytes(", Len, ")"]));
type({if_t, _, Id, Then, Else}) -> type({if_t, _, Id, Then, Else}) ->
@@ -296,11 +294,11 @@ type(T = {tvar, _, _}) -> name(T);
type(var_args) -> text("var_args"). type(var_args) -> text("var_args").
-spec args_type([so_syntax:type()]) -> doc(). -spec args_type([aeso_syntax:type()]) -> doc().
args_type(Args) -> args_type(Args) ->
tuple(lists:map(fun type/1, Args)). tuple(lists:map(fun type/1, Args)).
-spec tuple_type([so_syntax:type()]) -> doc(). -spec tuple_type([aeso_syntax:type()]) -> doc().
tuple_type([]) -> tuple_type([]) ->
text("unit"); text("unit");
tuple_type(Factors) -> tuple_type(Factors) ->
@@ -310,7 +308,7 @@ tuple_type(Factors) ->
, text(")") , text(")")
]). ]).
-spec expr_p(integer(), so_syntax:arg_expr()) -> doc(). -spec expr_p(integer(), aeso_syntax:arg_expr()) -> doc().
expr_p(P, {letpat, _, Id, Pat}) -> expr_p(P, {letpat, _, Id, Pat}) ->
paren(P > 100, follow(hsep(expr(Id), text("=")), expr(Pat))); paren(P > 100, follow(hsep(expr(Id), text("=")), expr(Pat)));
expr_p(P, {named_arg, _, Name, E}) -> expr_p(P, {named_arg, _, Name, E}) ->
@@ -318,7 +316,7 @@ expr_p(P, {named_arg, _, Name, E}) ->
expr_p(P, {lam, _, Args, E}) -> expr_p(P, {lam, _, Args, E}) ->
paren(P > 100, follow(hsep(args(Args), text("=>")), expr_p(100, E))); paren(P > 100, follow(hsep(args(Args), text("=>")), expr_p(100, E)));
expr_p(P, If = {'if', Ann, Cond, Then, Else}) -> expr_p(P, If = {'if', Ann, Cond, Then, Else}) ->
Format = so_syntax:get_ann(format, If), Format = aeso_syntax:get_ann(format, If),
if Format == '?:' -> if Format == '?:' ->
paren(P > 100, paren(P > 100,
follow(expr_p(200, Cond), follow(expr_p(200, Cond),
@@ -361,7 +359,7 @@ expr_p(P, {assign, _, LV, E}) ->
expr_p(_, {app, _, {'..', _}, [A, B]}) -> expr_p(_, {app, _, {'..', _}, [A, B]}) ->
list([infix(0, '..', A, B)]); list([infix(0, '..', A, B)]);
expr_p(P, E = {app, _, F = {Op, _}, Args}) when is_atom(Op) -> expr_p(P, E = {app, _, F = {Op, _}, Args}) when is_atom(Op) ->
case {so_syntax:get_ann(format, E), Args} of case {aeso_syntax:get_ann(format, E), Args} of
{infix, [A, B]} -> infix(P, Op, A, B); {infix, [A, B]} -> infix(P, Op, A, B);
{prefix, [A]} -> prefix(P, Op, A); {prefix, [A]} -> prefix(P, Op, A);
_ -> app(P, F, Args) _ -> app(P, F, Args)
@@ -372,7 +370,7 @@ expr_p(P, {app, _, F, Args}) ->
app(P, F, Args); app(P, F, Args);
%% -- Constants %% -- Constants
expr_p(_, E = {int, _, N}) -> expr_p(_, E = {int, _, N}) ->
S = case so_syntax:get_ann(format, E) of S = case aeso_syntax:get_ann(format, E) of
hex -> "0x" ++ integer_to_list(N, 16); hex -> "0x" ++ integer_to_list(N, 16);
_ -> integer_to_list(N) _ -> integer_to_list(N)
end, end,
@@ -387,9 +385,8 @@ expr_p(_, {Type, _, Bin})
when Type == account_pubkey; when Type == account_pubkey;
Type == contract_pubkey; Type == contract_pubkey;
Type == oracle_pubkey; Type == oracle_pubkey;
Type == oracle_query_id; Type == oracle_query_id ->
Type == signature -> text(binary_to_list(aeser_api_encoder:encode(Type, Bin)));
text(binary_to_list(gmser_api_encoder:encode(Type, Bin)));
expr_p(_, {string, _, <<>>}) -> text("\"\""); expr_p(_, {string, _, <<>>}) -> text("\"\"");
expr_p(_, {string, _, S}) -> expr_p(_, {string, _, S}) ->
text(io_lib:format("\"~s\"", [binary_to_list(S)])); text(io_lib:format("\"~s\"", [binary_to_list(S)]));
@@ -402,7 +399,7 @@ expr_p(_, {char, _, C}) ->
text("'" ++ tl(lists:droplast(S)) ++ "'"); text("'" ++ tl(lists:droplast(S)) ++ "'");
_ -> _ ->
S = lists:flatten( S = lists:flatten(
io_lib:format("'~ts'", [list_to_binary(so_scan:utf8_encode([C]))])), io_lib:format("'~ts'", [list_to_binary(aeso_scan:utf8_encode([C]))])),
text(S) text(S)
end; end;
%% -- Names %% -- Names
@@ -419,9 +416,9 @@ stmt_p({'if', _, Cond, Then}) ->
block_expr(200, beside(text("if"), paren(expr(Cond))), Then); block_expr(200, beside(text("if"), paren(expr(Cond))), Then);
stmt_p({elif, _, Cond, Then}) -> stmt_p({elif, _, Cond, Then}) ->
block_expr(200, beside(text("elif"), paren(expr(Cond))), Then); block_expr(200, beside(text("elif"), paren(expr(Cond))), Then);
stmt_p({'else', Else}) -> stmt_p({else, Else}) ->
HideGenerated = not show_generated(), HideGenerated = not show_generated(),
case so_syntax:get_ann(origin, Else) of case aeso_syntax:get_ann(origin, Else) of
system when HideGenerated -> empty(); system when HideGenerated -> empty();
_ -> block_expr(200, text("else"), Else) _ -> block_expr(200, text("else"), Else)
end. end.
@@ -433,7 +430,7 @@ lc_bind({comprehension_if, _, E}) ->
lc_bind(Let) -> lc_bind(Let) ->
letdecl("let", Let). letdecl("let", Let).
-spec bin_prec(so_syntax:bin_op()) -> {integer(), integer(), integer()}. -spec bin_prec(aeso_syntax:bin_op()) -> {integer(), integer(), integer()}.
bin_prec('..') -> { 0, 0, 0}; %% Always printed inside '[ ]' bin_prec('..') -> { 0, 0, 0}; %% Always printed inside '[ ]'
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('@') -> { 0, 0, 0}; %% Only in error messages
@@ -460,7 +457,7 @@ bin_prec('/') -> {700, 700, 750};
bin_prec(mod) -> {700, 700, 750}; bin_prec(mod) -> {700, 700, 750};
bin_prec('^') -> {750, 750, 800}. bin_prec('^') -> {750, 750, 800}.
-spec un_prec(so_syntax:un_op()) -> {integer(), integer()}. -spec un_prec(aeso_syntax:un_op()) -> {integer(), integer()}.
un_prec('-') -> {650, 650}; un_prec('-') -> {650, 650};
un_prec('!') -> {800, 800}; un_prec('!') -> {800, 800};
un_prec('bnot') -> {850, 850}. un_prec('bnot') -> {850, 850}.
@@ -468,7 +465,7 @@ un_prec('bnot') -> {850, 850}.
equals(Ann, A, B) -> equals(Ann, A, B) ->
{app, [{format, infix} | Ann], {'=', Ann}, [A, B]}. {app, [{format, infix} | Ann], {'=', Ann}, [A, B]}.
-spec infix(integer(), so_syntax:bin_op(), so_syntax:expr(), so_syntax:expr()) -> doc(). -spec infix(integer(), aeso_syntax:bin_op(), aeso_syntax:expr(), aeso_syntax:expr()) -> doc().
infix(P, Op, A, B) -> infix(P, Op, A, B) ->
{Top, L, R} = bin_prec(Op), {Top, L, R} = bin_prec(Op),
paren(P > Top, paren(P > Top,
@@ -530,9 +527,9 @@ statement(E) -> expr(E).
get_elifs(Expr) -> get_elifs(Expr, []). get_elifs(Expr) -> get_elifs(Expr, []).
get_elifs(If = {'if', Ann, Cond, Then, Else}, Elifs) -> get_elifs(If = {'if', Ann, Cond, Then, Else}, Elifs) ->
case so_syntax:get_ann(format, If) of case aeso_syntax:get_ann(format, If) of
elif -> get_elifs(Else, [{elif, Ann, Cond, Then} | Elifs]); elif -> get_elifs(Else, [{elif, Ann, Cond, Then} | Elifs]);
_ -> {lists:reverse(Elifs), If} _ -> {lists:reverse(Elifs), If}
end; end;
get_elifs(Else, Elifs) -> {lists:reverse(Elifs), {'else', Else}}. get_elifs(Else, Elifs) -> {lists:reverse(Elifs), {else, Else}}.
+5 -5
View File
@@ -5,12 +5,12 @@
%%% %%%
%%% @end %%% @end
%%%------------------------------------------------------------------- %%%-------------------------------------------------------------------
-module(so_scan). -module(aeso_scan).
-export([scan/1, utf8_encode/1]). -export([scan/1, utf8_encode/1]).
-import(so_scan_lib, [token/1, token/2, symbol/0, skip/0, -import(aeso_scan_lib, [token/1, token/2, symbol/0, skip/0,
override/2, push/2, pop/1]). override/2, push/2, pop/1]).
lexer() -> lexer() ->
Number = fun(Digit) -> [Digit, "+(_", Digit, "+)*"] end, Number = fun(Digit) -> [Digit, "+(_", Digit, "+)*"] end,
@@ -79,8 +79,8 @@ lexer() ->
[{code, Rules}, {comment, CommentRules}]. [{code, Rules}, {comment, CommentRules}].
scan(String) -> scan(String) ->
Lexer = so_scan_lib:compile(lexer()), Lexer = aeso_scan_lib:compile(lexer()),
so_scan_lib:string(Lexer, code, String). aeso_scan_lib:string(Lexer, code, String).
%% -- Helpers ---------------------------------------------------------------- %% -- Helpers ----------------------------------------------------------------
@@ -4,7 +4,7 @@
%%% @doc A customisable lexer. %%% @doc A customisable lexer.
%%% @end %%% @end
%%%------------------------------------------------------------------- %%%-------------------------------------------------------------------
-module(so_scan_lib). -module(aeso_scan_lib).
-export([compile/1, string/3, -export([compile/1, string/3,
token/1, token/2, symbol/0, skip/0, token/1, token/2, symbol/0, skip/0,
+2 -2
View File
@@ -8,10 +8,10 @@
%%% %%%
%%%------------------------------------------------------------------- %%%-------------------------------------------------------------------
-module(so_stdlib). -module(aeso_stdlib).
-export([stdlib_include_path/0]). -export([stdlib_include_path/0]).
stdlib_include_path() -> stdlib_include_path() ->
filename:join([code:priv_dir(sophia), "stdlib"]). filename:join([code:priv_dir(aesophia), "stdlib"]).
+3 -5
View File
@@ -6,11 +6,11 @@
%%% @end %%% @end
%%%------------------------------------------------------------------- %%%-------------------------------------------------------------------
-module(so_syntax). -module(aeso_syntax).
-export([get_ann/1, get_ann/2, get_ann/3, set_ann/2, qualify/2]). -export([get_ann/1, get_ann/2, get_ann/3, set_ann/2, qualify/2]).
-export_type([ann_file/0, ann_line/0, ann_col/0, ann_origin/0, ann_format/0, ann/0]). -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([name/0, id/0, con/0, qid/0, qcon/0, tvar/0, op/0]).
-export_type([bin_op/0, un_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, fundecl/0]).
@@ -24,9 +24,8 @@
-type ann_col() :: integer(). -type ann_col() :: integer().
-type ann_origin() :: system | user. -type ann_origin() :: system | user.
-type ann_format() :: '?:' | hex | infix | prefix | elif. -type ann_format() :: '?:' | hex | infix | prefix | elif.
-type ann_file() :: string() | no_file.
-type ann() :: [ {file, ann_file()} | {line, ann_line()} | {col, ann_col()} | {format, ann_format()} | {origin, ann_origin()} -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 | entrypoint].
-type name() :: string(). -type name() :: string().
@@ -100,7 +99,6 @@
| {contract_pubkey, ann(), binary()} | {contract_pubkey, ann(), binary()}
| {oracle_pubkey, ann(), binary()} | {oracle_pubkey, ann(), binary()}
| {oracle_query_id, ann(), binary()} | {oracle_query_id, ann(), binary()}
| {signature, ann(), binary()}
| {string, ann(), binary()} | {string, ann(), binary()}
| {char, ann(), integer()}. | {char, ann(), integer()}.
@@ -4,9 +4,9 @@
%%% Sophia syntax utilities. %%% Sophia syntax utilities.
%%% @end %%% @end
%%%------------------------------------------------------------------- %%%-------------------------------------------------------------------
-module(so_syntax_utils). -module(aeso_syntax_utils).
-export([used_ids/1, used_ids/2, used_types/2, used/1]). -export([used_ids/1, used_types/2, used/1]).
-record(alg, {zero, plus, scoped}). -record(alg, {zero, plus, scoped}).
@@ -17,27 +17,25 @@
-type kind() :: decl | type | bind_type | expr | bind_expr. -type kind() :: decl | type | bind_type | expr | bind_expr.
-spec fold(alg(A), fun((kind(), _) -> A), kind(), E | [E]) -> A -spec fold(alg(A), fun((kind(), _) -> A), kind(), E | [E]) -> A
when E :: so_syntax:decl() when E :: aeso_syntax:decl()
| so_syntax:typedef() | aeso_syntax:typedef()
| so_syntax:field_t() | aeso_syntax:field_t()
| so_syntax:constructor_t() | aeso_syntax:constructor_t()
| so_syntax:type() | aeso_syntax:type()
| so_syntax:expr() | aeso_syntax:expr()
| so_syntax:pat() | aeso_syntax:pat()
| so_syntax:arg() | aeso_syntax:arg()
| so_syntax:alt() | aeso_syntax:alt()
| so_syntax:elim() | aeso_syntax:elim()
| so_syntax:arg_expr() | aeso_syntax:arg_expr()
| so_syntax:field(so_syntax:expr()) | aeso_syntax:field(aeso_syntax:expr())
| so_syntax:stmt(). | aeso_syntax:stmt().
fold(Alg = #alg{zero = Zero, plus = Plus, scoped = Scoped}, Fun, K, X) -> fold(Alg = #alg{zero = Zero, plus = Plus, scoped = Scoped}, Fun, K, X) ->
ExprKind = if K == bind_expr -> bind_expr; true -> expr end,
TypeKind = if K == bind_type -> bind_type; true -> type end,
Sum = fun(Xs) -> lists:foldl(Plus, Zero, Xs) end, Sum = fun(Xs) -> lists:foldl(Plus, Zero, Xs) end,
Same = fun(A) -> fold(Alg, Fun, K, A) end, Same = fun(A) -> fold(Alg, Fun, K, A) end,
Decl = fun(D) -> fold(Alg, Fun, decl, D) end, Decl = fun(D) -> fold(Alg, Fun, decl, D) end,
Type = fun(T) -> fold(Alg, Fun, TypeKind, T) end, Type = fun(T) -> fold(Alg, Fun, type, T) end,
Expr = fun(E) -> fold(Alg, Fun, ExprKind, E) end, Expr = fun(E) -> fold(Alg, Fun, expr, E) end,
BindExpr = fun(P) -> fold(Alg, Fun, bind_expr, P) end, BindExpr = fun(P) -> fold(Alg, Fun, bind_expr, P) end,
BindType = fun(T) -> fold(Alg, Fun, bind_type, T) end, BindType = fun(T) -> fold(Alg, Fun, bind_type, T) end,
Top = Fun(K, X), Top = Fun(K, X),
@@ -110,16 +108,8 @@ fold(Alg = #alg{zero = Zero, plus = Plus, scoped = Scoped}, Fun, K, X) ->
%% Name dependencies %% Name dependencies
%% Used ids, top level
used_ids(E) -> used_ids(E) ->
used_ids([], E). [ X || {{term, [X]}, _} <- used(E) ].
%% Used ids, top level or in (current) namespace
used_ids(Ns, E) ->
[ lists:last(Xs) || {{term, Xs}, _} <- used(E), in_ns(Xs, Ns) ].
in_ns([_], _) -> true;
in_ns(Xs, Ns) -> lists:droplast(Xs) == Ns.
used_types([Top] = _CurrentNS, T) -> used_types([Top] = _CurrentNS, T) ->
F = fun({{type, [X]}, _}) -> [X]; F = fun({{type, [X]}, _}) -> [X];
@@ -132,7 +122,7 @@ used_types([Top] = _CurrentNS, T) ->
| {type, [string()]} | {type, [string()]}
| {namespace, [string()]}. | {namespace, [string()]}.
-spec entity_alg() -> alg(#{entity() => so_syntax:ann()}). -spec entity_alg() -> alg(#{entity() => aeso_syntax:ann()}).
entity_alg() -> entity_alg() ->
IsBound = fun({K, _}) -> lists:member(K, [bound_term, bound_type]) end, IsBound = fun({K, _}) -> lists:member(K, [bound_term, bound_type]) end,
Unbind = fun(bound_term) -> term; (bound_type) -> type end, Unbind = fun(bound_term) -> term; (bound_type) -> type end,
@@ -147,7 +137,7 @@ entity_alg() ->
, plus = fun maps:merge/2 , plus = fun maps:merge/2
, scoped = Scoped }. , scoped = Scoped }.
-spec used(_) -> [{entity(), so_syntax:ann()}]. -spec used(_) -> [{entity(), aeso_syntax:ann()}].
used(D) -> used(D) ->
Kind = fun(expr) -> term; Kind = fun(expr) -> term;
(bind_expr) -> bound_term; (bind_expr) -> bound_term;
@@ -165,3 +155,4 @@ used(D) ->
(_, _) -> #{} (_, _) -> #{}
end, decl, D)), end, decl, D)),
lists:filter(NotBound, Xs). lists:filter(NotBound, Xs).
+2 -14
View File
@@ -4,24 +4,12 @@
%%% Sophia utility functions. %%% Sophia utility functions.
%%% @end %%% @end
%%%------------------------------------------------------------------- %%%-------------------------------------------------------------------
-module(so_utils). -module(aeso_utils).
-export([scc/1, canonical_dir/1]). -export([scc/1]).
-export_type([graph/1]). -export_type([graph/1]).
%% -- Simplistic canonical directory
%% Note: no attempts to be 100% complete
canonical_dir(Dir) ->
{ok, Cwd} = file:get_cwd(),
AbsName = filename:absname(Dir),
RelAbsName = filename:join(tl(filename:split(AbsName))),
case filelib:safe_relative_path(RelAbsName, Cwd) of
unsafe -> AbsName;
Simplified -> filename:absname(Simplified, "")
end.
%% -- Topological sort %% -- Topological sort
-type graph(Node) :: #{Node => [Node]}. %% List of incoming edges (dependencies). -type graph(Node) :: #{Node => [Node]}. %% List of incoming edges (dependencies).
+13 -20
View File
@@ -4,21 +4,17 @@
%%% @end %%% @end
%%%------------------------------------------------------------------- %%%-------------------------------------------------------------------
-module(so_vm_decode). -module(aeso_vm_decode).
-export([ from_fate/2 ]). -export([ from_fate/2 ]).
-include_lib("gmbytecode/include/gmb_fate_data.hrl"). -include_lib("aebytecode/include/aeb_fate_data.hrl").
-spec from_fate(so_syntax:type(), gmb_fate_data:fate_type()) -> so_syntax:expr(). -spec from_fate(aeso_syntax:type(), aeb_fate_data:fate_type()) -> aeso_syntax:expr().
from_fate({id, _, "address"}, ?FATE_ADDRESS(Bin)) -> {account_pubkey, [], Bin}; from_fate({id, _, "address"}, ?FATE_ADDRESS(Bin)) -> {account_pubkey, [], Bin};
from_fate({id, _, "signature"}, ?FATE_BYTES(Bin)) -> {signature, [], Bin};
from_fate({id, _, "hash"}, ?FATE_BYTES(Bin)) -> {bytes, [], Bin};
from_fate({id, _, "unit"}, ?FATE_UNIT) -> {tuple, [], []};
from_fate({app_t, _, {id, _, "oracle"}, _}, ?FATE_ORACLE(Bin)) -> {oracle_pubkey, [], Bin}; from_fate({app_t, _, {id, _, "oracle"}, _}, ?FATE_ORACLE(Bin)) -> {oracle_pubkey, [], Bin};
from_fate({app_t, _, {id, _, "oracle_query"}, _}, ?FATE_ORACLE_Q(Bin)) -> {oracle_query_id, [], Bin}; from_fate({app_t, _, {id, _, "oracle_query"}, _}, ?FATE_ORACLE_Q(Bin)) -> {oracle_query_id, [], Bin};
from_fate({con, _, _Name}, ?FATE_CONTRACT(Bin)) -> {contract_pubkey, [], Bin}; from_fate({con, _, _Name}, ?FATE_CONTRACT(Bin)) -> {contract_pubkey, [], Bin};
from_fate({bytes_t, _, any}, ?FATE_BYTES(Bin)) -> make_any_bytes(Bin);
from_fate({bytes_t, _, N}, ?FATE_BYTES(Bin)) when byte_size(Bin) == N -> {bytes, [], Bin}; from_fate({bytes_t, _, N}, ?FATE_BYTES(Bin)) when byte_size(Bin) == N -> {bytes, [], Bin};
from_fate({id, _, "bits"}, ?FATE_BITS(N)) -> make_bits(N); from_fate({id, _, "bits"}, ?FATE_BITS(N)) -> make_bits(N);
from_fate({id, _, "int"}, N) when is_integer(N) -> from_fate({id, _, "int"}, N) when is_integer(N) ->
@@ -82,7 +78,6 @@ from_fate_builtin(QType, Val) ->
Hsh = {bytes_t, [], 32}, Hsh = {bytes_t, [], 32},
I32 = {bytes_t, [], 32}, I32 = {bytes_t, [], 32},
I48 = {bytes_t, [], 48}, I48 = {bytes_t, [], 48},
Bts = {bytes_t, [], any},
Qid = fun(Name) -> {qid, [], Name} end, Qid = fun(Name) -> {qid, [], Name} end,
Map = fun(KT, VT) -> {app_t, [], {id, [], "map"}, [KT, VT]} end, Map = fun(KT, VT) -> {app_t, [], {id, [], "map"}, [KT, VT]} end,
ChainTxArities = [3, 0, 0, 0, 0, 0, 1, 1, 1, 2, 1, 2, 2, 1, 1, 1, 1, 1, 1, 1, 2, 0], ChainTxArities = [3, 0, 0, 0, 0, 0, 1, 1, 1, 2, 1, 2, 2, 1, 1, 1, 1, 1, 1, 1, 2, 0],
@@ -108,16 +103,16 @@ from_fate_builtin(QType, Val) ->
App(["AENSv2","Name"], [Chk(Adr, Addr), Chk(Qid(["Chain", "ttl"]), TTL), App(["AENSv2","Name"], [Chk(Adr, Addr), Chk(Qid(["Chain", "ttl"]), TTL),
Chk(Map(Str, Qid(["AENSv2", "pointee"])), Ptrs)]); Chk(Map(Str, Qid(["AENSv2", "pointee"])), Ptrs)]);
{["AENSv2", "pointee"], {variant, [1, 1, 1, 1, 1], 0, {Value}}} -> {["AENSv2", "pointee"], {variant, [1, 1, 1, 1, 1], 0, {Val}}} ->
App(["AENSv2","AccountPt"], [Chk(Adr, Value)]); App(["AENSv2","AccountPt"], [Chk(Adr, Val)]);
{["AENSv2", "pointee"], {variant, [1, 1, 1, 1, 1], 1, {Value}}} -> {["AENSv2", "pointee"], {variant, [1, 1, 1, 1, 1], 1, {Val}}} ->
App(["AENSv2","OraclePt"], [Chk(Adr, Value)]); App(["AENSv2","OraclePt"], [Chk(Adr, Val)]);
{["AENSv2", "pointee"], {variant, [1, 1, 1, 1, 1], 2, {Value}}} -> {["AENSv2", "pointee"], {variant, [1, 1, 1, 1, 1], 2, {Val}}} ->
App(["AENSv2","ContractPt"], [Chk(Adr, Value)]); App(["AENSv2","ContractPt"], [Chk(Adr, Val)]);
{["AENSv2", "pointee"], {variant, [1, 1, 1, 1, 1], 3, {Value}}} -> {["AENSv2", "pointee"], {variant, [1, 1, 1, 1, 1], 3, {Val}}} ->
App(["AENSv2","ChannelPt"], [Chk(Adr, Value)]); App(["AENSv2","ChannelPt"], [Chk(Adr, Val)]);
{["AENSv2", "pointee"], {variant, [1, 1, 1, 1, 1], 4, {Value}}} -> {["AENSv2", "pointee"], {variant, [1, 1, 1, 1, 1], 4, {Val}}} ->
App(["AENSv2","DataPt"], [Chk(Bts, Value)]); App(["AENSv2","DataPt"], [Chk(Str, Val)]);
{["Chain", "ga_meta_tx"], {variant, [2], 0, {Addr, X}}} -> {["Chain", "ga_meta_tx"], {variant, [2], 0, {Addr, X}}} ->
App(["Chain","GAMetaTx"], [Chk(Adr, Addr), Chk(Int, X)]); App(["Chain","GAMetaTx"], [Chk(Adr, Addr), Chk(Int, X)]);
@@ -190,5 +185,3 @@ make_bits(Set, Zero, I, N) when 0 == N rem 2 ->
make_bits(Set, Zero, I, N) -> make_bits(Set, Zero, I, N) ->
{app, [], Set, [make_bits(Set, Zero, I + 1, N div 2), {int, [], I}]}. {app, [], Set, [make_bits(Set, Zero, I + 1, N div 2), {int, [], I}]}.
make_any_bytes(Bin) ->
{app, [], {qid, [], ["Bytes", "to_any_size"]}, [{bytes, [], Bin}]}.
@@ -1,6 +1,6 @@
-module(so_warnings). -module(aeso_warnings).
-record(warn, { pos :: so_errors:pos() -record(warn, { pos :: aeso_errors:pos()
, message :: iolist() , message :: iolist()
}). }).
@@ -16,16 +16,16 @@
]). ]).
new(Msg) -> new(Msg) ->
new(so_errors:pos(0, 0), Msg). new(aeso_errors:pos(0, 0), Msg).
new(Pos, Msg) -> new(Pos, Msg) ->
#warn{ pos = Pos, message = Msg }. #warn{ pos = Pos, message = Msg }.
warn_to_err(Kind, #warn{ pos = Pos, message = Msg }) -> warn_to_err(Kind, #warn{ pos = Pos, message = Msg }) ->
so_errors:new(Kind, Pos, lists:flatten(Msg)). aeso_errors:new(Kind, Pos, lists:flatten(Msg)).
sort_warnings(Warnings) -> sort_warnings(Warnings) ->
lists:sort(fun(W1, W2) -> W1#warn.pos =< W2#warn.pos end, Warnings). lists:sort(fun(W1, W2) -> W1#warn.pos =< W2#warn.pos end, Warnings).
pp(#warn{ pos = Pos, message = Msg }) -> pp(#warn{ pos = Pos, message = Msg }) ->
lists:flatten(io_lib:format("Warning~s:\n~s", [so_errors:pp_pos(Pos), Msg])). lists:flatten(io_lib:format("Warning~s:\n~s", [aeso_errors:pp_pos(Pos), Msg])).
+5 -4
View File
@@ -1,13 +1,14 @@
{application, sophia, {application, aesophia,
[{description, "Compiler for the Sophia language"}, [{description, "Compiler for Aeternity Sophia language"},
{vsn, "8.0.1"}, {vsn, "8.0.0"},
{registered, []}, {registered, []},
{applications, {applications,
[kernel, [kernel,
stdlib, stdlib,
jsx, jsx,
syntax_tools, syntax_tools,
gmbytecode, getopt,
aebytecode,
eblake2 eblake2
]}, ]},
{env,[]}, {env,[]},
@@ -1,4 +1,4 @@
-module(so_abi_tests). -module(aeso_abi_tests).
-include_lib("eunit/include/eunit.hrl"). -include_lib("eunit/include/eunit.hrl").
-compile([export_all, nowarn_export_all]). -compile([export_all, nowarn_export_all]).
@@ -65,15 +65,15 @@ to_sophia_value_mcl_bls12_381_test() ->
Opts = [{backend, fate}], Opts = [{backend, fate}],
CallValue32 = gmb_fate_encoding:serialize({bytes, <<20:256>>}), CallValue32 = aeb_fate_encoding:serialize({bytes, <<20:256>>}),
CallValue48 = gmb_fate_encoding:serialize({bytes, <<55:384>>}), CallValue48 = aeb_fate_encoding:serialize({bytes, <<55:384>>}),
CallValueTp = gmb_fate_encoding:serialize({tuple, {{bytes, <<15:256>>}, {bytes, <<160:256>>}, {bytes, <<1234:256>>}}}), CallValueTp = aeb_fate_encoding:serialize({tuple, {{bytes, <<15:256>>}, {bytes, <<160:256>>}, {bytes, <<1234:256>>}}}),
{ok, _} = so_compiler:to_sophia_value(Code, "test_bls12_381_fp", ok, CallValue32, Opts), {ok, _} = aeso_compiler:to_sophia_value(Code, "test_bls12_381_fp", ok, CallValue32, Opts),
{error, _} = so_compiler:to_sophia_value(Code, "test_bls12_381_fp", ok, CallValue48, Opts), {error, _} = aeso_compiler:to_sophia_value(Code, "test_bls12_381_fp", ok, CallValue48, Opts),
{ok, _} = so_compiler:to_sophia_value(Code, "test_bls12_381_fr", ok, CallValue48, Opts), {ok, _} = aeso_compiler:to_sophia_value(Code, "test_bls12_381_fr", ok, CallValue48, Opts),
{error, _} = so_compiler:to_sophia_value(Code, "test_bls12_381_fr", ok, CallValue32, Opts), {error, _} = aeso_compiler:to_sophia_value(Code, "test_bls12_381_fr", ok, CallValue32, Opts),
{ok, _} = so_compiler:to_sophia_value(Code, "test_bls12_381_g1", ok, CallValueTp, Opts), {ok, _} = aeso_compiler:to_sophia_value(Code, "test_bls12_381_g1", ok, CallValueTp, Opts),
ok. ok.
@@ -81,11 +81,11 @@ to_sophia_value_neg_test() ->
Code = [ "contract Foo =\n" Code = [ "contract Foo =\n"
" entrypoint f(x : int) : string = \"hello\"\n" ], " entrypoint f(x : int) : string = \"hello\"\n" ],
{error, [Err1]} = so_compiler:to_sophia_value(Code, "f", ok, encode(12)), {error, [Err1]} = aeso_compiler:to_sophia_value(Code, "f", ok, encode(12)),
?assertEqual("Data error:\nCannot translate FATE value 12\n of Sophia type string\n", so_errors:pp(Err1)), ?assertEqual("Data error:\nCannot translate FATE value 12\n of Sophia type string\n", aeso_errors:pp(Err1)),
{error, [Err2]} = so_compiler:to_sophia_value(Code, "f", revert, encode(12)), {error, [Err2]} = aeso_compiler:to_sophia_value(Code, "f", revert, encode(12)),
?assertEqual("Data error:\nCould not deserialize the revert message\n", so_errors:pp(Err2)), ?assertEqual("Data error:\nCould not deserialize the revert message\n", aeso_errors:pp(Err2)),
ok. ok.
encode_calldata_neg_test() -> encode_calldata_neg_test() ->
@@ -97,8 +97,8 @@ encode_calldata_neg_test() ->
" `f : (int) => string`\n" " `f : (int) => string`\n"
"to arguments\n" "to arguments\n"
" `true : bool`\n", " `true : bool`\n",
{error, [Err1]} = so_compiler:create_calldata(Code, "f", ["true"]), {error, [Err1]} = aeso_compiler:create_calldata(Code, "f", ["true"]),
?assertEqual(ExpErr1, so_errors:pp(Err1)), ?assertEqual(ExpErr1, aeso_errors:pp(Err1)),
ok. ok.
@@ -108,15 +108,15 @@ decode_calldata_neg_test() ->
Code2 = [ "contract Foo =\n" Code2 = [ "contract Foo =\n"
" entrypoint f(x : string) : int = 42\n" ], " entrypoint f(x : string) : int = 42\n" ],
{ok, CallDataFATE} = so_compiler:create_calldata(Code1, "f", ["42"]), {ok, CallDataFATE} = aeso_compiler:create_calldata(Code1, "f", ["42"]),
{error, [Err1]} = so_compiler:decode_calldata(Code2, "f", <<1,2,3>>), {error, [Err1]} = aeso_compiler:decode_calldata(Code2, "f", <<1,2,3>>),
?assertEqual("Data error:\nFailed to decode calldata binary\n", so_errors:pp(Err1)), ?assertEqual("Data error:\nFailed to decode calldata binary\n", aeso_errors:pp(Err1)),
{error, [Err2]} = so_compiler:decode_calldata(Code2, "f", CallDataFATE), {error, [Err2]} = aeso_compiler:decode_calldata(Code2, "f", CallDataFATE),
?assertEqual("Data error:\nCannot translate FATE value \"*\"\n to Sophia type (string)\n", so_errors:pp(Err2)), ?assertEqual("Data error:\nCannot translate FATE value \"*\"\n to Sophia type (string)\n", aeso_errors:pp(Err2)),
{error, [Err3]} = so_compiler:decode_calldata(Code2, "x", CallDataFATE), {error, [Err3]} = aeso_compiler:decode_calldata(Code2, "x", CallDataFATE),
?assertEqual("Data error at line 1, col 1:\nFunction 'x' is missing in contract\n", so_errors:pp(Err3)), ?assertEqual("Data error at line 1, col 1:\nFunction 'x' is missing in contract\n", aeso_errors:pp(Err3)),
ok. ok.
@@ -128,12 +128,12 @@ encode_decode_sophia_string(SophiaType, String) ->
, " record r = {x : an_alias(int), y : variant}\n" , " record r = {x : an_alias(int), y : variant}\n"
, " datatype variant = Red | Blue(map(string, int))\n" , " datatype variant = Red | Blue(map(string, int))\n"
, " entrypoint foo : arg_type => arg_type\n" ], , " entrypoint foo : arg_type => arg_type\n" ],
case so_compiler:check_call(lists:flatten(Code), "foo", [String], [no_code]) of case aeso_compiler:check_call(lists:flatten(Code), "foo", [String], [no_code]) of
{ok, _, [Arg]} -> {ok, _, [Arg]} ->
Data = encode(Arg), Data = encode(Arg),
case so_compiler:to_sophia_value(Code, "foo", ok, Data, [no_code]) of case aeso_compiler:to_sophia_value(Code, "foo", ok, Data, [no_code]) of
{ok, Sophia} -> {ok, Sophia} ->
lists:flatten(io_lib:format("~s", [prettypr:format(so_pretty:expr(Sophia))])); lists:flatten(io_lib:format("~s", [prettypr:format(aeso_pretty:expr(Sophia))]));
{error, Err} -> {error, Err} ->
io:format("~s\n", [Err]), io:format("~s\n", [Err]),
{error, Err} {error, Err}
@@ -194,18 +194,40 @@ parameterized_contract(ExtraCode, FunName, Types) ->
" datatype variant = Red | Blue(map(string, int))\n" " datatype variant = Red | Blue(map(string, int))\n"
" entrypoint ", FunName, " : (", string:join(Types, ", "), ") => int\n" ]). " entrypoint ", FunName, " : (", string:join(Types, ", "), ") => int\n" ]).
oracle_test() ->
Contract =
"contract OracleTest =\n"
" entrypoint question(o, q : oracle_query(list(string), option(int))) =\n"
" Oracle.get_question(o, q)\n",
?assertEqual({ok, "question", [{oracle, <<291:256>>}, {oracle_query, <<1110:256>>}]},
aeso_compiler:check_call(Contract, "question", ["ok_111111111111111111111111111111ZrdqRz9",
"oq_1111111111111111111111111111113AFEFpt5"], [no_code])),
ok.
permissive_literals_fail_test() ->
Contract =
"contract OracleTest =\n"
" stateful entrypoint haxx(o : oracle(list(string), option(int))) =\n"
" Chain.spend(o, 1000000)\n",
{error, [Err]} =
aeso_compiler:check_call(Contract, "haxx", ["#123"], []),
?assertMatch("Type error at line 3, col 5:\nCannot unify" ++ _, aeso_errors:pp(Err)),
?assertEqual(type_error, aeso_errors:type(Err)),
ok.
encode_decode_calldata(FunName, Types, Args) -> encode_decode_calldata(FunName, Types, Args) ->
Code = parameterized_contract(FunName, Types), Code = parameterized_contract(FunName, Types),
encode_decode_calldata_(Code, FunName, Args). encode_decode_calldata_(Code, FunName, Args).
encode_decode_calldata_(Code, FunName, Args) -> encode_decode_calldata_(Code, FunName, Args) ->
{ok, Calldata} = so_compiler:create_calldata(Code, FunName, Args, []), {ok, Calldata} = aeso_compiler:create_calldata(Code, FunName, Args, []),
{ok, _, _} = so_compiler:check_call(Code, FunName, Args, [no_code]), {ok, _, _} = aeso_compiler:check_call(Code, FunName, Args, [no_code]),
case FunName of case FunName of
"init" -> "init" ->
[]; [];
_ -> _ ->
{ok, FateArgs} = gmb_fate_abi:decode_calldata(FunName, Calldata), {ok, FateArgs} = aeb_fate_abi:decode_calldata(FunName, Calldata),
FateArgs FateArgs
end. end.
@@ -214,7 +236,7 @@ encode_decode(D) ->
D. D.
encode(D) -> encode(D) ->
gmb_fate_encoding:serialize(D). aeb_fate_encoding:serialize(D).
decode(B) -> decode(B) ->
gmb_fate_encoding:deserialize(B). aeb_fate_encoding:deserialize(B).
@@ -1,4 +1,4 @@
-module(so_aci_tests). -module(aeso_aci_tests).
-include_lib("eunit/include/eunit.hrl"). -include_lib("eunit/include/eunit.hrl").
@@ -9,11 +9,11 @@ simple_aci_test_() ->
test_contract(N) -> test_contract(N) ->
{Contract,MapACI,DecACI} = test_cases(N), {Contract,MapACI,DecACI} = test_cases(N),
{ok,JSON} = so_aci:contract_interface(json, Contract), {ok,JSON} = aeso_aci:contract_interface(json, Contract),
?assertEqual([MapACI], JSON), ?assertEqual([MapACI], JSON),
?assertEqual({ok, DecACI}, so_aci:render_aci_json(JSON)), ?assertEqual({ok, DecACI}, aeso_aci:render_aci_json(JSON)),
%% Check if the compiler provides correct aci %% Check if the compiler provides correct aci
{ok,#{aci := JSON2}} = so_compiler:from_string(Contract, [{aci, json}]), {ok,#{aci := JSON2}} = aeso_compiler:from_string(Contract, [{aci, json}]),
?assertEqual(JSON, JSON2). ?assertEqual(JSON, JSON2).
test_cases(1) -> test_cases(1) ->
@@ -95,39 +95,39 @@ aci_test_() ->
fun() -> aci_test_contract(ContractName) end} fun() -> aci_test_contract(ContractName) end}
|| ContractName <- all_contracts()]. || ContractName <- all_contracts()].
all_contracts() -> so_compiler_tests:compilable_contracts(). all_contracts() -> aeso_compiler_tests:compilable_contracts().
aci_test_contract(Name) -> aci_test_contract(Name) ->
String = so_test_utils:read_contract(Name), String = aeso_test_utils:read_contract(Name),
Opts = case lists:member(Name, so_compiler_tests:debug_mode_contracts()) of Opts = case lists:member(Name, aeso_compiler_tests:debug_mode_contracts()) of
true -> [debug_mode]; true -> [debug_mode];
false -> [] false -> []
end ++ [{include, {file_system, [so_test_utils:contract_path()]}}], end ++ [{include, {file_system, [aeso_test_utils:contract_path()]}}],
JSON = case so_aci:contract_interface(json, String, Opts) of JSON = case aeso_aci:contract_interface(json, String, Opts) of
{ok, J} -> J; {ok, J} -> J;
{error, ErrorStringJ} when is_binary(ErrorStringJ) -> error(ErrorStringJ); {error, ErrorStringJ} when is_binary(ErrorStringJ) -> error(ErrorStringJ);
{error, ErrorJ} -> so_compiler_tests:print_and_throw(ErrorJ) {error, ErrorJ} -> aeso_compiler_tests:print_and_throw(ErrorJ)
end, end,
case so_compiler:from_string(String, [{aci, json} | Opts]) of case aeso_compiler:from_string(String, [{aci, json} | Opts]) of
{ok, #{aci := JSON1}} -> {ok, #{aci := JSON1}} ->
?assertEqual(JSON, JSON1), ?assertEqual(JSON, JSON1),
io:format("JSON:\n~p\n", [JSON]), io:format("JSON:\n~p\n", [JSON]),
{ok, ContractStub} = so_aci:render_aci_json(JSON), {ok, ContractStub} = aeso_aci:render_aci_json(JSON),
io:format("STUB:\n~s\n", [ContractStub]), io:format("STUB:\n~s\n", [ContractStub]),
check_stub(ContractStub, [{src_file, Name}]), check_stub(ContractStub, [{src_file, Name}]),
ok; ok;
{error, ErrorString} when is_binary(ErrorString) -> error(ErrorString); {error, ErrorString} when is_binary(ErrorString) -> error(ErrorString);
{error, Error} -> so_compiler_tests:print_and_throw(Error) {error, Error} -> aeso_compiler_tests:print_and_throw(Error)
end. end.
check_stub(Stub, Options) -> check_stub(Stub, Options) ->
try so_parser:string(binary_to_list(Stub), Options) of try aeso_parser:string(binary_to_list(Stub), Options) of
Ast -> Ast ->
try try
%% io:format("AST: ~120p\n", [Ast]), %% io:format("AST: ~120p\n", [Ast]),
so_ast_infer_types:infer(Ast, [no_code]) aeso_ast_infer_types:infer(Ast, [no_code])
catch throw:{type_errors, TE} -> catch throw:{type_errors, TE} ->
io:format("Type error:\n~s\n", [TE]), io:format("Type error:\n~s\n", [TE]),
error(TE); error(TE);
@@ -136,6 +136,6 @@ check_stub(Stub, Options) ->
error(R) error(R)
end end
catch throw:{error, Errs} -> catch throw:{error, Errs} ->
_ = [ io:format("~s\n", [so_errors:pp(E)]) || E <- Errs ], _ = [ io:format("~s\n", [aeso_errors:pp(E)]) || E <- Errs ],
error({parse_errors, Errs}) error({parse_errors, Errs})
end. end.
@@ -6,7 +6,7 @@
%%% @end %%% @end
%%%------------------------------------------------------------------- %%%-------------------------------------------------------------------
-module(so_calldata_tests). -module(aeso_calldata_tests).
-compile([export_all, nowarn_export_all]). -compile([export_all, nowarn_export_all]).
@@ -18,7 +18,7 @@
calldata_test_() -> calldata_test_() ->
[ {"Testing " ++ ContractName ++ " contract calling " ++ Fun, [ {"Testing " ++ ContractName ++ " contract calling " ++ Fun,
fun() -> fun() ->
ContractString = so_test_utils:read_contract(ContractName), ContractString = aeso_test_utils:read_contract(ContractName),
FateExprs = ast_exprs(ContractString, Fun, Args), FateExprs = ast_exprs(ContractString, Fun, Args),
ParsedExprs = parse_args(Fun, Args), ParsedExprs = parse_args(Fun, Args),
?assertEqual(ParsedExprs, FateExprs), ?assertEqual(ParsedExprs, FateExprs),
@@ -28,8 +28,8 @@ calldata_test_() ->
calldata_aci_test_() -> calldata_aci_test_() ->
[ {"Testing " ++ ContractName ++ " contract calling " ++ Fun, [ {"Testing " ++ ContractName ++ " contract calling " ++ Fun,
fun() -> fun() ->
ContractString = so_test_utils:read_contract(ContractName), ContractString = aeso_test_utils:read_contract(ContractName),
{ok, ContractACIBin} = so_aci:contract_interface(string, ContractString, [no_code]), {ok, ContractACIBin} = aeso_aci:contract_interface(string, ContractString, [no_code]),
ContractACI = binary_to_list(ContractACIBin), ContractACI = binary_to_list(ContractACIBin),
io:format("ACI:\n~s\n", [ContractACIBin]), io:format("ACI:\n~s\n", [ContractACIBin]),
FateExprs = ast_exprs(ContractACI, Fun, Args), FateExprs = ast_exprs(ContractACI, Fun, Args),
@@ -40,7 +40,7 @@ calldata_aci_test_() ->
parse_args(Fun, Args) -> parse_args(Fun, Args) ->
[{contract_main, _, _, _, [{letfun, _, _, _, _, [{guarded, _, [], {app, _, _, AST}}]}]}] = [{contract_main, _, _, _, [{letfun, _, _, _, _, [{guarded, _, [], {app, _, _, AST}}]}]}] =
so_parser:string("main contract Temp = function foo() = " ++ Fun ++ "(" ++ string:join(Args, ", ") ++ ")"), aeso_parser:string("main contract Temp = function foo() = " ++ Fun ++ "(" ++ string:join(Args, ", ") ++ ")"),
strip_ann(AST). strip_ann(AST).
strip_ann(T) when is_tuple(T) -> strip_ann(T) when is_tuple(T) ->
@@ -58,8 +58,8 @@ strip_ann1(X) -> X.
ast_exprs(ContractString, Fun, Args) -> ast_exprs(ContractString, Fun, Args) ->
ast_exprs(ContractString, Fun, Args, []). ast_exprs(ContractString, Fun, Args, []).
ast_exprs(ContractString, Fun, Args, Opts) -> ast_exprs(ContractString, Fun, Args, Opts) ->
{ok, Data} = (catch so_compiler:create_calldata(ContractString, Fun, Args, Opts)), {ok, Data} = (catch aeso_compiler:create_calldata(ContractString, Fun, Args, Opts)),
{ok, _Types, Exprs} = (catch so_compiler:decode_calldata(ContractString, Fun, Data, Opts)), {ok, _Types, Exprs} = (catch aeso_compiler:decode_calldata(ContractString, Fun, Data, Opts)),
?assert(is_list(Exprs)), ?assert(is_list(Exprs)),
strip_ann(Exprs). strip_ann(Exprs).
@@ -85,11 +85,12 @@ compilable_contracts() ->
{"funargs", "bitsum", ["Bits.clear(Bits.clear(Bits.all, 4), 2)"]}, %% Order matters for test {"funargs", "bitsum", ["Bits.clear(Bits.clear(Bits.all, 4), 2)"]}, %% Order matters for test
{"funargs", "bitsum", ["Bits.set(Bits.set(Bits.none, 4), 2)"]}, {"funargs", "bitsum", ["Bits.set(Bits.set(Bits.none, 4), 2)"]},
{"funargs", "read", ["{label = \"question 1\", result = 4}"]}, {"funargs", "read", ["{label = \"question 1\", result = 4}"]},
{"funargs", "any_bytes", ["Bytes.to_any_size(#0011AA)"]},
{"funargs", "sjutton", ["#0011012003100011012003100011012003"]}, {"funargs", "sjutton", ["#0011012003100011012003100011012003"]},
{"funargs", "sextiosju", ["#01020304050607080910111213141516171819202122232425262728293031323334353637383940" {"funargs", "sextiosju", ["#01020304050607080910111213141516171819202122232425262728293031323334353637383940"
"414243444546474849505152535455565758596061626364656667"]}, "414243444546474849505152535455565758596061626364656667"]},
{"funargs", "trettiotva", ["#0102030405060708091011121314151617181920212223242526272829303132"]}, {"funargs", "trettiotva", ["#0102030405060708091011121314151617181920212223242526272829303132"]},
{"funargs", "find_oracle", ["ok_2YNyxd6TRJPNrTcEDCe9ra59SVUdp9FR9qWC5msKZWYD9bP9z5"]},
{"funargs", "find_query", ["oq_2oRvyowJuJnEkxy58Ckkw77XfWJrmRgmGaLzhdqb67SKEL1gPY"]},
{"funargs", "traffic_light", ["Green"]}, {"funargs", "traffic_light", ["Green"]},
{"funargs", "traffic_light", ["Pantone(12)"]}, {"funargs", "traffic_light", ["Pantone(12)"]},
{"funargs", "tuples", ["()"]}, {"funargs", "tuples", ["()"]},
@@ -97,6 +98,7 @@ compilable_contracts() ->
{"funargs", "singleton_rec", ["{x = 1000}"]}, {"funargs", "singleton_rec", ["{x = 1000}"]},
{"funargs", "aens_name", ["AENS.Name(ak_2dATVcZ9KJU5a8hdsVtTv21pYiGWiPbmVcU1Pz72FFqpk9pSRR, RelativeTTL(100), {[\"pt1\"] = AENS.AccountPt(ak_2dATVcZ9KJU5a8hdsVtTv21pYiGWiPbmVcU1Pz72FFqpk9pSRR)})"]}, {"funargs", "aens_name", ["AENS.Name(ak_2dATVcZ9KJU5a8hdsVtTv21pYiGWiPbmVcU1Pz72FFqpk9pSRR, RelativeTTL(100), {[\"pt1\"] = AENS.AccountPt(ak_2dATVcZ9KJU5a8hdsVtTv21pYiGWiPbmVcU1Pz72FFqpk9pSRR)})"]},
{"funargs", "aens_pointee", ["AENS.AccountPt(ak_2dATVcZ9KJU5a8hdsVtTv21pYiGWiPbmVcU1Pz72FFqpk9pSRR)"]}, {"funargs", "aens_pointee", ["AENS.AccountPt(ak_2dATVcZ9KJU5a8hdsVtTv21pYiGWiPbmVcU1Pz72FFqpk9pSRR)"]},
{"funargs", "aens_pointee", ["AENS.OraclePt(ak_2dATVcZ9KJU5a8hdsVtTv21pYiGWiPbmVcU1Pz72FFqpk9pSRR)"]},
{"funargs", "aens_pointee", ["AENS.ContractPt(ak_2dATVcZ9KJU5a8hdsVtTv21pYiGWiPbmVcU1Pz72FFqpk9pSRR)"]}, {"funargs", "aens_pointee", ["AENS.ContractPt(ak_2dATVcZ9KJU5a8hdsVtTv21pYiGWiPbmVcU1Pz72FFqpk9pSRR)"]},
{"funargs", "aens_pointee", ["AENS.ChannelPt(ak_2dATVcZ9KJU5a8hdsVtTv21pYiGWiPbmVcU1Pz72FFqpk9pSRR)"]}, {"funargs", "aens_pointee", ["AENS.ChannelPt(ak_2dATVcZ9KJU5a8hdsVtTv21pYiGWiPbmVcU1Pz72FFqpk9pSRR)"]},
{"funargs", "chain_ga_meta_tx", ["Chain.GAMetaTx(ak_2dATVcZ9KJU5a8hdsVtTv21pYiGWiPbmVcU1Pz72FFqpk9pSRR, 42)"]}, {"funargs", "chain_ga_meta_tx", ["Chain.GAMetaTx(ak_2dATVcZ9KJU5a8hdsVtTv21pYiGWiPbmVcU1Pz72FFqpk9pSRR, 42)"]},
@@ -104,13 +106,16 @@ compilable_contracts() ->
{"funargs", "chain_base_tx", ["Chain.SpendTx(ak_2dATVcZ9KJU5a8hdsVtTv21pYiGWiPbmVcU1Pz72FFqpk9pSRR, 42,\"foo\")"]}, {"funargs", "chain_base_tx", ["Chain.SpendTx(ak_2dATVcZ9KJU5a8hdsVtTv21pYiGWiPbmVcU1Pz72FFqpk9pSRR, 42,\"foo\")"]},
{"funargs", "chain_base_tx", ["Chain.ContractCreateTx(12234)"]}, {"funargs", "chain_base_tx", ["Chain.ContractCreateTx(12234)"]},
{"funargs", "chain_base_tx", ["Chain.ContractCallTx(ak_2dATVcZ9KJU5a8hdsVtTv21pYiGWiPbmVcU1Pz72FFqpk9pSRR, 12234)"]}, {"funargs", "chain_base_tx", ["Chain.ContractCallTx(ak_2dATVcZ9KJU5a8hdsVtTv21pYiGWiPbmVcU1Pz72FFqpk9pSRR, 12234)"]},
{"funargs", "chain_base_tx", ["Chain.OracleRegisterTx"]},
{"funargs", "chain_base_tx", ["Chain.OracleQueryTx"]},
{"funargs", "chain_base_tx", ["Chain.OracleResponseTx"]},
{"funargs", "chain_base_tx", ["Chain.OracleExtendTx"]},
{"funargs", "chain_base_tx", ["Chain.NamePreclaimTx"]}, {"funargs", "chain_base_tx", ["Chain.NamePreclaimTx"]},
{"funargs", "chain_base_tx", ["Chain.NameClaimTx(\"acoolname.chain\")"]}, {"funargs", "chain_base_tx", ["Chain.NameClaimTx(\"acoolname.chain\")"]},
{"funargs", "chain_base_tx", ["Chain.NameUpdateTx(#ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff)"]}, {"funargs", "chain_base_tx", ["Chain.NameUpdateTx(#ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff)"]},
{"funargs", "chain_base_tx", ["Chain.NameRevokeTx(#ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff)"]}, {"funargs", "chain_base_tx", ["Chain.NameRevokeTx(#ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff)"]},
{"funargs", "chain_base_tx", ["Chain.NameTransferTx(ak_2dATVcZ9KJU5a8hdsVtTv21pYiGWiPbmVcU1Pz72FFqpk9pSRR, #ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff)"]}, {"funargs", "chain_base_tx", ["Chain.NameTransferTx(ak_2dATVcZ9KJU5a8hdsVtTv21pYiGWiPbmVcU1Pz72FFqpk9pSRR, #ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff)"]},
{"funargs", "chain_base_tx", ["Chain.GAAttachTx"]}, {"funargs", "chain_base_tx", ["Chain.GAAttachTx"]},
{"funargs", "sig", ["sg_MhibzTP1wWzGCTjtPFr1TiPqRJrrJqw7auvEuF5i3FdoALWqXLBDY6xxRRNUSPHK3EQTnTzF12EyspkxrSMxVHKsZeSMj"]},
{"variant_types", "init", []}, {"variant_types", "init", []},
{"basic_auth", "init", []}, {"basic_auth", "init", []},
{"address_literals", "init", []}, {"address_literals", "init", []},
@@ -6,7 +6,7 @@
%%% @end %%% @end
%%%------------------------------------------------------------------- %%%-------------------------------------------------------------------
-module(so_compiler_tests). -module(aeso_compiler_tests).
-compile([export_all, nowarn_export_all]). -compile([export_all, nowarn_export_all]).
@@ -28,14 +28,14 @@ simple_compile_test_() ->
fun() -> fun() ->
case compile(ContractName) of case compile(ContractName) of
#{fate_code := Code} -> #{fate_code := Code} ->
Code1 = gmb_fate_code:deserialize(gmb_fate_code:serialize(Code)), Code1 = aeb_fate_code:deserialize(aeb_fate_code:serialize(Code)),
?assertMatch({X, X}, {Code1, Code}); ?assertMatch({X, X}, {Code1, Code});
Error -> io:format("\n\n~p\n\n", [Error]), print_and_throw(Error) Error -> io:format("\n\n~p\n\n", [Error]), print_and_throw(Error)
end end
end} || ContractName <- compilable_contracts()] ++ end} || ContractName <- compilable_contracts()] ++
[ {"Test file not found error", [ {"Test file not found error",
fun() -> fun() ->
{error, Errors} = so_compiler:file("does_not_exist.aes"), {error, Errors} = aeso_compiler:file("does_not_exist.aes"),
ExpErr = <<"File error:\ndoes_not_exist.aes: no such file or directory">>, ExpErr = <<"File error:\ndoes_not_exist.aes: no such file or directory">>,
check_errors([ExpErr], Errors) check_errors([ExpErr], Errors)
end} ] ++ end} ] ++
@@ -49,7 +49,7 @@ simple_compile_test_() ->
fun() -> fun() ->
FileSystem = maps:from_list( FileSystem = maps:from_list(
[ begin [ begin
{ok, Bin} = file:read_file(filename:join([so_test_utils:contract_path(), File])), {ok, Bin} = file:read_file(filename:join([aeso_test_utils:contract_path(), File])),
{File, Bin} {File, Bin}
end || File <- ["included.aes", "../contracts/included2.aes"] ]), end || File <- ["included.aes", "../contracts/included2.aes"] ]),
#{byte_code := Code1} = compile("include", [{include, {explicit_files, FileSystem}}]), #{byte_code := Code1} = compile("include", [{include, {explicit_files, FileSystem}}]),
@@ -69,22 +69,20 @@ simple_compile_test_() ->
[ {"Testing warning messages", [ {"Testing warning messages",
fun() -> fun() ->
#{ warnings := Warnings } = compile("warnings", [warn_all]), #{ warnings := Warnings } = compile("warnings", [warn_all]),
#{ warnings := [] } = compile("warning_unused_include_no_include", [warn_all]),
#{ warnings := [] } = compile("warning_used_record_typedef", [warn_all]),
check_warnings(warnings(), Warnings) check_warnings(warnings(), Warnings)
end} ] ++ end} ] ++
[]. [].
%% Check if all modules in the standard library compile %% Check if all modules in the standard library compile
stdlib_test_() -> stdlib_test_() ->
{ok, Files} = file:list_dir(so_stdlib:stdlib_include_path()), {ok, Files} = file:list_dir(aeso_stdlib:stdlib_include_path()),
[ { "Testing " ++ File ++ " from the stdlib", [ { "Testing " ++ File ++ " from the stdlib",
fun() -> fun() ->
String = "include \"" ++ File ++ "\"\nmain contract Test =\n entrypoint f(x) = x", String = "include \"" ++ File ++ "\"\nmain contract Test =\n entrypoint f(x) = x",
Options = [{src_file, File}], Options = [{src_file, File}],
case so_compiler:from_string(String, Options) of case aeso_compiler:from_string(String, Options) of
{ok, #{fate_code := Code}} -> {ok, #{fate_code := Code}} ->
Code1 = gmb_fate_code:deserialize(gmb_fate_code:serialize(Code)), Code1 = aeb_fate_code:deserialize(aeb_fate_code:serialize(Code)),
?assertMatch({X, X}, {Code1, Code}); ?assertMatch({X, X}, {Code1, Code});
{error, Error} -> io:format("\n\n~p\n\n", [Error]), print_and_throw(Error) {error, Error} -> io:format("\n\n~p\n\n", [Error]), print_and_throw(Error)
end end
@@ -97,7 +95,7 @@ check_errors(Expect, #{}) ->
?assertEqual({error, Expect}, ok); ?assertEqual({error, Expect}, ok);
check_errors(Expect0, Actual0) -> check_errors(Expect0, Actual0) ->
Expect = lists:sort(Expect0), Expect = lists:sort(Expect0),
Actual = [ list_to_binary(string:trim(so_errors:pp(Err))) || Err <- Actual0 ], Actual = [ list_to_binary(string:trim(aeso_errors:pp(Err))) || Err <- Actual0 ],
case {Expect -- Actual, Actual -- Expect} of case {Expect -- Actual, Actual -- Expect} of
{[], Extra} -> ?assertMatch({unexpected, []}, {unexpected, Extra}); {[], Extra} -> ?assertMatch({unexpected, []}, {unexpected, Extra});
{Missing, []} -> ?assertMatch({missing, []}, {missing, Missing}); {Missing, []} -> ?assertMatch({missing, []}, {missing, Missing});
@@ -106,7 +104,7 @@ check_errors(Expect0, Actual0) ->
check_warnings(Expect0, Actual0) -> check_warnings(Expect0, Actual0) ->
Expect = lists:sort(Expect0), Expect = lists:sort(Expect0),
Actual = [ list_to_binary(string:trim(so_warnings:pp(Warn))) || Warn <- Actual0 ], Actual = [ list_to_binary(string:trim(aeso_warnings:pp(Warn))) || Warn <- Actual0 ],
case {Expect -- Actual, Actual -- Expect} of case {Expect -- Actual, Actual -- Expect} of
{[], Extra} -> ?assertMatch({unexpected, []}, {unexpected, Extra}); {[], Extra} -> ?assertMatch({unexpected, []}, {unexpected, Extra});
{Missing, []} -> ?assertMatch({missing, []}, {missing, Missing}); {Missing, []} -> ?assertMatch({missing, []}, {missing, Missing});
@@ -114,19 +112,19 @@ check_warnings(Expect0, Actual0) ->
end. end.
compile(Name) -> compile(Name) ->
compile( Name, [{include, {file_system, [so_test_utils:contract_path()]}}]). compile( Name, [{include, {file_system, [aeso_test_utils:contract_path()]}}]).
compile(Name, Options) -> compile(Name, Options) ->
String = so_test_utils:read_contract(Name), String = aeso_test_utils:read_contract(Name),
Options1 = Options1 =
case lists:member(Name, debug_mode_contracts()) of case lists:member(Name, debug_mode_contracts()) of
true -> [debug_mode]; true -> [debug_mode];
false -> [] false -> []
end ++ end ++
[ {src_file, Name ++ ".aes"} [ {src_file, Name ++ ".aes"}
, {include, {file_system, [so_test_utils:contract_path()]}} , {include, {file_system, [aeso_test_utils:contract_path()]}}
] ++ Options, ] ++ Options,
case so_compiler:from_string(String, Options1) of case aeso_compiler:from_string(String, Options1) of
{ok, Map} -> Map; {ok, Map} -> Map;
{error, ErrorString} when is_binary(ErrorString) -> ErrorString; {error, ErrorString} when is_binary(ErrorString) -> ErrorString;
{error, Errors} -> Errors {error, Errors} -> Errors
@@ -145,6 +143,7 @@ compilable_contracts() ->
"fundme", "fundme",
"identity", "identity",
"maps", "maps",
"oracles",
"remote_call", "remote_call",
"remote_call_ambiguous_record", "remote_call_ambiguous_record",
"simple", "simple",
@@ -161,7 +160,6 @@ compilable_contracts() ->
"state_handling", "state_handling",
"events", "events",
"include", "include",
"relative_include",
"basic_auth", "basic_auth",
"basic_auth_tx", "basic_auth_tx",
"bitcoin_auth", "bitcoin_auth",
@@ -171,7 +169,6 @@ compilable_contracts() ->
"namespace_bug", "namespace_bug",
"bytes_to_x", "bytes_to_x",
"bytes_concat", "bytes_concat",
"bytes_misc",
"aens", "aens",
"aens_update", "aens_update",
"tuple_match", "tuple_match",
@@ -208,9 +205,6 @@ compilable_contracts() ->
"polymorphism_variance_switching_chain_create", "polymorphism_variance_switching_chain_create",
"polymorphism_variance_switching_void_supertype", "polymorphism_variance_switching_void_supertype",
"polymorphism_variance_switching_unify_with_interface_decls", "polymorphism_variance_switching_unify_with_interface_decls",
"polymorphism_preserve_or_add_payable_contract",
"polymorphism_preserve_or_add_payable_entrypoint",
"polymorphism_preserve_or_remove_stateful_entrypoint",
"missing_init_fun_state_unit", "missing_init_fun_state_unit",
"complex_compare_leq", "complex_compare_leq",
"complex_compare", "complex_compare",
@@ -222,8 +216,8 @@ compilable_contracts() ->
"polymorphic_entrypoint_return", "polymorphic_entrypoint_return",
"polymorphic_map_keys", "polymorphic_map_keys",
"unapplied_contract_call", "unapplied_contract_call",
"unapplied_named_arg_builtin",
"resolve_field_constraint_by_arity", "resolve_field_constraint_by_arity",
"toplevel_constants",
"ceres", "ceres",
"test" % Custom general-purpose test file. Keep it last on the list. "test" % Custom general-purpose test file. Keep it last on the list.
]. ].
@@ -289,15 +283,11 @@ warnings() ->
<<?PosW(48, 5) <<?PosW(48, 5)
"Unused return value.">>, "Unused return value.">>,
<<?PosW(60, 5) <<?PosW(60, 5)
"The function `dec` is defined but never used.">>, "The function `dec` is defined but never used.">>
<<?PosW(73, 9)
"The definition of `const` shadows an older definition at line 70, column 3.">>,
<<?PosW(84, 7)
"The constant `c` is defined but never used.">>
]). ]).
failing_contracts() -> failing_contracts() ->
{ok, V} = so_compiler:numeric_version(), {ok, V} = aeso_compiler:numeric_version(),
Version = list_to_binary(string:join([integer_to_list(N) || N <- V], ".")), Version = list_to_binary(string:join([integer_to_list(N) || N <- V], ".")),
%% Parse errors %% Parse errors
[ ?PARSE_ERROR(field_parse_error, [ ?PARSE_ERROR(field_parse_error,
@@ -449,10 +439,6 @@ failing_contracts() ->
[<<?Pos(12, 42) [<<?Pos(12, 42)
"Cannot unify `int` and `string`\n" "Cannot unify `int` and `string`\n"
"when checking the type of the expression `r.foo() : map(int, string)` " "when checking the type of the expression `r.foo() : map(int, string)` "
"against the expected type `map(string, int)`">>,
<<?Pos(12, 42)
"Cannot unify `string` and `int`\n"
"when checking the type of the expression `r.foo() : map(int, string)` "
"against the expected type `map(string, int)`">>]) "against the expected type `map(string, int)`">>])
, ?TYPE_ERROR(not_toplevel_include, , ?TYPE_ERROR(not_toplevel_include,
[<<?Pos(2, 11) [<<?Pos(2, 11)
@@ -464,7 +450,10 @@ failing_contracts() ->
[<<?Pos(2, 12) [<<?Pos(2, 12)
"Nested contracts are not allowed. Contract `Con` is not defined at top level.">>]) "Nested contracts are not allowed. Contract `Con` is not defined at top level.">>])
, ?TYPE_ERROR(bad_address_literals, , ?TYPE_ERROR(bad_address_literals,
[ [<<?Pos(11, 5)
"Cannot unify `address` and `oracle(int, bool)`\n"
"when checking the type of the expression `ak_2gx9MEFxKvY9vMG5YnqnXWv1hCsX7rgnfvBLJS4aQurustR1rt : address` "
"against the expected type `oracle(int, bool)`">>,
<<?Pos(9, 5) <<?Pos(9, 5)
"Cannot unify `address` and `Remote`\n" "Cannot unify `address` and `Remote`\n"
"when checking the type of the expression `ak_2gx9MEFxKvY9vMG5YnqnXWv1hCsX7rgnfvBLJS4aQurustR1rt : address` " "when checking the type of the expression `ak_2gx9MEFxKvY9vMG5YnqnXWv1hCsX7rgnfvBLJS4aQurustR1rt : address` "
@@ -473,17 +462,52 @@ failing_contracts() ->
"Cannot unify `address` and `bytes(32)`\n" "Cannot unify `address` and `bytes(32)`\n"
"when checking the type of the expression `ak_2gx9MEFxKvY9vMG5YnqnXWv1hCsX7rgnfvBLJS4aQurustR1rt : address` " "when checking the type of the expression `ak_2gx9MEFxKvY9vMG5YnqnXWv1hCsX7rgnfvBLJS4aQurustR1rt : address` "
"against the expected type `bytes(32)`">>, "against the expected type `bytes(32)`">>,
<<?Pos(12, 5) <<?Pos(14, 5)
"Cannot unify `oracle('a, 'b)` and `oracle_query(int, bool)`\n"
"when checking the type of the expression "
"`ok_2YNyxd6TRJPNrTcEDCe9ra59SVUdp9FR9qWC5msKZWYD9bP9z5 : oracle('a, 'b)` "
"against the expected type `oracle_query(int, bool)`">>,
<<?Pos(16, 5)
"Cannot unify `oracle('c, 'd)` and `bytes(32)`\n"
"when checking the type of the expression "
"`ok_2YNyxd6TRJPNrTcEDCe9ra59SVUdp9FR9qWC5msKZWYD9bP9z5 : oracle('c, 'd)` "
"against the expected type `bytes(32)`">>,
<<?Pos(18, 5)
"Cannot unify `oracle('e, 'f)` and `Remote`\n"
"when checking the type of the expression "
"`ok_2YNyxd6TRJPNrTcEDCe9ra59SVUdp9FR9qWC5msKZWYD9bP9z5 : oracle('e, 'f)` "
"against the expected type `Remote`">>,
<<?Pos(21, 5)
"Cannot unify `oracle_query('g, 'h)` and `oracle(int, bool)`\n"
"when checking the type of the expression "
"`oq_2oRvyowJuJnEkxy58Ckkw77XfWJrmRgmGaLzhdqb67SKEL1gPY : oracle_query('g, 'h)` "
"against the expected type `oracle(int, bool)`">>,
<<?Pos(23, 5)
"Cannot unify `oracle_query('i, 'j)` and `bytes(32)`\n"
"when checking the type of the expression "
"`oq_2oRvyowJuJnEkxy58Ckkw77XfWJrmRgmGaLzhdqb67SKEL1gPY : oracle_query('i, 'j)` "
"against the expected type `bytes(32)`">>,
<<?Pos(25, 5)
"Cannot unify `oracle_query('k, 'l)` and `Remote`\n"
"when checking the type of the expression "
"`oq_2oRvyowJuJnEkxy58Ckkw77XfWJrmRgmGaLzhdqb67SKEL1gPY : oracle_query('k, 'l)` "
"against the expected type `Remote`">>,
<<?Pos(28, 5)
"The type `address` is not a contract type\n" "The type `address` is not a contract type\n"
"when checking that the contract literal " "when checking that the contract literal "
"`ct_Ez6MyeTMm17YnTnDdHTSrzMEBKmy7Uz2sXu347bTDPgVH2ifJ` " "`ct_Ez6MyeTMm17YnTnDdHTSrzMEBKmy7Uz2sXu347bTDPgVH2ifJ` "
"has the type `address`">>, "has the type `address`">>,
<<?Pos(14, 5) <<?Pos(30, 5)
"The type `oracle(int, bool)` is not a contract type\n"
"when checking that the contract literal "
"`ct_Ez6MyeTMm17YnTnDdHTSrzMEBKmy7Uz2sXu347bTDPgVH2ifJ` "
"has the type `oracle(int, bool)`">>,
<<?Pos(32, 5)
"The type `bytes(32)` is not a contract type\n" "The type `bytes(32)` is not a contract type\n"
"when checking that the contract literal " "when checking that the contract literal "
"`ct_Ez6MyeTMm17YnTnDdHTSrzMEBKmy7Uz2sXu347bTDPgVH2ifJ` " "`ct_Ez6MyeTMm17YnTnDdHTSrzMEBKmy7Uz2sXu347bTDPgVH2ifJ` "
"has the type `bytes(32)`">>, "has the type `bytes(32)`">>,
<<?Pos(16, 5), <<?Pos(34, 5),
"The type `address` is not a contract type\n" "The type `address` is not a contract type\n"
"when checking that the call to `Address.to_contract` " "when checking that the call to `Address.to_contract` "
"has the type `address`">>]) "has the type `address`">>])
@@ -572,21 +596,6 @@ failing_contracts() ->
[<<?Pos(3, 5) [<<?Pos(3, 5)
"Unbound variable `Chain.event`\n" "Unbound variable `Chain.event`\n"
"Did you forget to define the event type?">>]) "Did you forget to define the event type?">>])
, ?TYPE_ERROR(bad_bytes_to_x,
[<<?Pos(3, 35)
"Cannot resolve length of byte array in\n"
" the result of a call to Bytes.to_fixed_size">>,
<<?Pos(4, 36)
"Cannot unify `bytes()` and `bytes(4)`\nwhen checking the application of\n"
" `Bytes.to_fixed_size : (bytes()) => option('a)`\n"
"to arguments\n"
" `b : bytes(4)`">>,
<<?Pos(4, 36)
"Cannot resolve length of byte array in\n"
" the result of a call to Bytes.to_fixed_size">>,
<<?Pos(5, 35)
"Cannot resolve length of byte array in\n"
" the first argument of a call to Bytes.to_any_size">>])
, ?TYPE_ERROR(bad_bytes_concat, , ?TYPE_ERROR(bad_bytes_concat,
[<<?Pos(12, 40) [<<?Pos(12, 40)
"Failed to resolve byte array lengths in call to Bytes.concat with arguments of type\n" "Failed to resolve byte array lengths in call to Bytes.concat with arguments of type\n"
@@ -611,8 +620,7 @@ failing_contracts() ->
"and result type\n" "and result type\n"
" - 'c (at line 16, column 39)">>, " - 'c (at line 16, column 39)">>,
<<?Pos(19, 25) <<?Pos(19, 25)
"Cannot resolve type of byte array in\n" "Cannot resolve length of byte array.">>])
" the first argument of a call to Bytes.to_str">>])
, ?TYPE_ERROR(bad_bytes_split, , ?TYPE_ERROR(bad_bytes_split,
[<<?Pos(13, 5) [<<?Pos(13, 5)
"Failed to resolve byte array lengths in call to Bytes.split with argument of type\n" "Failed to resolve byte array lengths in call to Bytes.split with argument of type\n"
@@ -647,6 +655,10 @@ failing_contracts() ->
[<<?Pos(5, 28) [<<?Pos(5, 28)
"Invalid call to contract entrypoint `Foo.foo`.\n" "Invalid call to contract entrypoint `Foo.foo`.\n"
"It must be called as `c.foo` for some `c : Foo`.">>]) "It must be called as `c.foo` for some `c : Foo`.">>])
, ?TYPE_ERROR(toplevel_let,
[<<?Pos(2, 7)
"Toplevel \"let\" definitions are not supported. "
"Value `this_is_illegal` could be replaced by 0-argument function.">>])
, ?TYPE_ERROR(empty_typedecl, , ?TYPE_ERROR(empty_typedecl,
[<<?Pos(2, 8) [<<?Pos(2, 8)
"Empty type declarations are not supported. " "Empty type declarations are not supported. "
@@ -844,24 +856,20 @@ failing_contracts() ->
<<?Pos(48, 5) <<?Pos(48, 5)
"Unused return value.">>, "Unused return value.">>,
<<?Pos(60, 5) <<?Pos(60, 5)
"The function `dec` is defined but never used.">>, "The function `dec` is defined but never used.">>
<<?Pos(73, 9)
"The definition of `const` shadows an older definition at line 70, column 3.">>,
<<?Pos(84, 7)
"The constant `c` is defined but never used.">>
]) ])
, ?TYPE_ERROR(polymorphism_contract_interface_recursive, , ?TYPE_ERROR(polymorphism_contract_interface_recursive,
[<<?Pos(1,24) [<<?Pos(1,24)
"Trying to implement or extend an undefined interface `Z`">> "Trying to implement or extend an undefined interface `Z`">>
]) ])
, ?TYPE_ERROR(polymorphism_contract_interface_same_name_different_type, , ?TYPE_ERROR(polymorphism_contract_interface_same_name_different_type,
[<<?Pos(5,5) [<<?Pos(9,5)
"Cannot unify `char` and `int`\n" "Duplicate definitions of `f` at\n"
"when implementing the entrypoint `f` from the interface `I1`">> " - line 8, column 5\n"
]) " - line 9, column 5">>])
, ?TYPE_ERROR(polymorphism_contract_missing_implementation, , ?TYPE_ERROR(polymorphism_contract_missing_implementation,
[<<?Pos(4,20) [<<?Pos(4,20)
"Unimplemented entrypoint `f` from the interface `I1` in the contract `I2`">> "Unimplemented function `f` from the interface `I1` in the contract `I2`">>
]) ])
, ?TYPE_ERROR(polymorphism_contract_same_decl_multi_interface, , ?TYPE_ERROR(polymorphism_contract_same_decl_multi_interface,
[<<?Pos(7,10) [<<?Pos(7,10)
@@ -912,9 +920,6 @@ failing_contracts() ->
<<?Pos(67,36) <<?Pos(67,36)
"Cannot unify `Cat` and `Animal` in a contravariant context\n" "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`">>, "when checking the application of\n `DT_INV : ((Cat) => Cat) => dt_inv(Cat)`\nto arguments\n `f_c_to_a : (Cat) => Animal`">>,
<<?Pos(67,36)
"Cannot unify `Cat` and `Animal` in a invariant context\n"
"when checking the type of the expression `DT_INV(f_c_to_a) : dt_inv(Cat)` against the expected type `dt_inv(Animal)`">>,
<<?Pos(68,36) <<?Pos(68,36)
"Cannot unify `Cat` and `Animal` in a invariant context\n" "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)`">>, "when checking the type of the expression `DT_INV(f_c_to_c) : dt_inv(Cat)` against the expected type `dt_inv(Animal)`">>,
@@ -963,9 +968,6 @@ failing_contracts() ->
<<?Pos(116,59) <<?Pos(116,59)
"Cannot unify `Cat` and `Animal` in a contravariant context\n" "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)`">>, "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(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) <<?Pos(119,59)
"Cannot unify `Cat` and `Animal` in a contravariant context\n" "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)`">>, "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)`">>,
@@ -996,6 +998,50 @@ failing_contracts() ->
"Cannot unify `Animal` and `Cat` in a invariant context\n" "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)`">> "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, , ?TYPE_ERROR(polymorphism_variance_switching_chain_create_fail,
[<<?Pos(9,22) [<<?Pos(9,22)
"I is not implemented.\n" "I is not implemented.\n"
@@ -1052,19 +1098,47 @@ failing_contracts() ->
[<<?Pos(4,5) [<<?Pos(4,5)
"Invalid return type of `AENSv2.resolve`:\n" "Invalid return type of `AENSv2.resolve`:\n"
" `'a`\n" " `'a`\n"
"It must be a `string` or a pubkey type (`address`, etc)">> "It must be a `string` or a pubkey type (`address`, `oracle`, etc)">>
]) ])
, ?TYPE_ERROR(bad_aens_resolve, , ?TYPE_ERROR(bad_aens_resolve,
[<<?Pos(6,5) [<<?Pos(6,5)
"Invalid return type of `AENSv2.resolve`:\n" "Invalid return type of `AENSv2.resolve`:\n"
" `list(int)`\n" " `list(int)`\n"
"It must be a `string` or a pubkey type (`address`, etc)">> "It must be a `string` or a pubkey type (`address`, `oracle`, etc)">>
]) ])
, ?TYPE_ERROR(bad_aens_resolve_using, , ?TYPE_ERROR(bad_aens_resolve_using,
[<<?Pos(7,5) [<<?Pos(7,5)
"Invalid return type of `AENSv2.resolve`:\n" "Invalid return type of `AENSv2.resolve`:\n"
" `list(int)`\n" " `list(int)`\n"
"It must be a `string` or a pubkey type (`address`, etc)">> "It must be a `string` or a pubkey type (`address`, `oracle`, etc)">>
])
, ?TYPE_ERROR(polymorphic_query_type,
[<<?Pos(3,5)
"Invalid oracle type\n"
" `oracle('a, 'b)`\n"
"The query type must not be polymorphic (contain type variables)">>,
<<?Pos(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)
"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)
"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, , ?TYPE_ERROR(var_args_unify_let,
[<<?Pos(3,9) [<<?Pos(3,9)
@@ -1079,115 +1153,6 @@ failing_contracts() ->
"to arguments\n" "to arguments\n"
" `Chain.create : (value : int, var_args) => 'c`">> " `Chain.create : (value : int, var_args) => 'c`">>
]) ])
, ?TYPE_ERROR(polymorphism_add_stateful_entrypoint,
[<<?Pos(5,25)
"`f` cannot be stateful because the entrypoint `f` in the interface `I` is not stateful">>
])
, ?TYPE_ERROR(polymorphism_change_entrypoint_to_function,
[<<?Pos(6,14)
"`f` must be declared as an entrypoint instead of a function in order to implement the entrypoint `f` from the interface `I`">>
])
, ?TYPE_ERROR(polymorphism_non_payable_contract_implement_payable,
[<<?Pos(4,10)
"Non-payable contract `C` cannot implement payable interface `I`">>
])
, ?TYPE_ERROR(polymorphism_non_payable_interface_implement_payable,
[<<?Pos(4,20)
"Non-payable interface `H` cannot implement payable interface `I`">>
])
, ?TYPE_ERROR(polymorphism_remove_payable_entrypoint,
[<<?Pos(5,16)
"`f` must be payable because the entrypoint `f` in the interface `I` is payable">>
])
, ?TYPE_ERROR(calling_child_contract_entrypoint,
[<<?Pos(5,20)
"Invalid call to contract entrypoint `F.g`.\n"
"It must be called as `c.g` for some `c : F`.">>])
, ?TYPE_ERROR(using_contract_as_namespace,
[<<?Pos(5,3)
"Cannot use undefined namespace F">>])
, ?TYPE_ERROR(hole_expression,
[<<?Pos(5,13)
"Found a hole of type `bool`">>,
<<?Pos(6,17)
"Found a hole of type `string`">>,
<<?Pos(9,37)
"Found a hole of type `(int) => int`">>,
<<?Pos(13,20)
"Found a hole of type `'a`">>
])
, ?TYPE_ERROR(toplevel_constants_contract_as_namespace,
[<<?Pos(5,13)
"Invalid use of the contract constant `G.const`.\n"
"Toplevel contract constants can only be used in the contracts where they are defined.">>,
<<?Pos(10,11)
"Record type `G` does not have field `const`">>,
<<?Pos(10,11)
"Unbound field const">>,
<<?Pos(11,11)
"Record type `G` does not have field `const`">>,
<<?Pos(11,11)
"Unbound field const">>
])
, ?TYPE_ERROR(toplevel_constants_cycles,
[<<?Pos(2,21)
"Unbound variable `selfcycle`">>,
<<?Pos(4,5)
"Mutual recursion detected between the constants\n"
" - `cycle1` at line 4, column 5\n"
" - `cycle2` at line 5, column 5\n"
" - `cycle3` at line 6, column 5">>
])
, ?TYPE_ERROR(toplevel_constants_in_interface,
[<<?Pos(2,10)
"The name of the compile-time constant cannot have pattern matching">>,
<<?Pos(3,5)
"Cannot define toplevel constants inside a contract interface">>,
<<?Pos(4,5)
"Cannot define toplevel constants inside a contract interface">>
])
, ?TYPE_ERROR(toplevel_constants_invalid_expr,
[<<?Pos(10,9)
"Invalid expression in the definition of the constant `c01`\n"
"You can only use the following expressions as constants: literals, lists, tuples, maps, and other constants">>,
<<?Pos(11,9)
"Invalid expression in the definition of the constant `c02`\n"
"You can only use the following expressions as constants: literals, lists, tuples, maps, and other constants">>,
<<?Pos(12,9)
"Invalid expression in the definition of the constant `c03`\n"
"You can only use the following expressions as constants: literals, lists, tuples, maps, and other constants">>,
<<?Pos(13,9)
"Invalid expression in the definition of the constant `c04`\n"
"You can only use the following expressions as constants: literals, lists, tuples, maps, and other constants">>,
<<?Pos(14,9)
"Invalid expression in the definition of the constant `c05`\n"
"You can only use the following expressions as constants: literals, lists, tuples, maps, and other constants">>,
<<?Pos(17,9)
"Invalid expression in the definition of the constant `c07`\n"
"You can only use the following expressions as constants: literals, lists, tuples, maps, and other constants">>,
<<?Pos(18,9)
"Invalid expression in the definition of the constant `c08`\n"
"You can only use the following expressions as constants: literals, lists, tuples, maps, and other constants">>,
<<?Pos(19,9)
"Invalid expression in the definition of the constant `c09`\n"
"You can only use the following expressions as constants: literals, lists, tuples, maps, and other constants">>,
<<?Pos(20,9)
"Invalid expression in the definition of the constant `c10`\n"
"You can only use the following expressions as constants: literals, lists, tuples, maps, and other constants">>,
<<?Pos(21,9)
"Invalid expression in the definition of the constant `c11`\n"
"You can only use the following expressions as constants: literals, lists, tuples, maps, and other constants">>
])
, ?TYPE_ERROR(toplevel_constants_invalid_id,
[<<?Pos(2,9)
"The name of the compile-time constant cannot have pattern matching">>,
<<?Pos(3,9)
"The name of the compile-time constant cannot have pattern matching">>
])
, ?TYPE_ERROR(too_many_tvars,
[<<?Pos(2,3)
"Too many type variables (max 256) in definition of `too_many`">>
])
]. ].
validation_test_() -> validation_test_() ->
@@ -1227,17 +1192,15 @@ validation_fails() ->
validate(Contract1, Contract2) -> validate(Contract1, Contract2) ->
case compile(Contract1) of case compile(Contract1) of
ByteCode = #{ fate_code := FCode } -> ByteCode = #{ fate_code := FCode } ->
FCode1 = gmb_fate_code:serialize(gmb_fate_code:strip_init_function(FCode)), FCode1 = aeb_fate_code:serialize(aeb_fate_code:strip_init_function(FCode)),
Source = so_test_utils:read_contract(Contract2), Source = aeso_test_utils:read_contract(Contract2),
so_compiler:validate_byte_code( aeso_compiler:validate_byte_code(
ByteCode#{ byte_code := FCode1 }, Source, ByteCode#{ byte_code := FCode1 }, Source,
case lists:member(Contract2, debug_mode_contracts()) of case lists:member(Contract2, debug_mode_contracts()) of
true -> [debug_mode]; true -> [debug_mode];
false -> [] false -> []
end ++ end ++
[ {src_file, lists:concat([Contract2, ".aes"])} [{include, {file_system, [aeso_test_utils:contract_path()]}}]);
, {include, {file_system, [so_test_utils:contract_path()]}}
]);
Error -> print_and_throw(Error) Error -> print_and_throw(Error)
end. end.
@@ -1247,6 +1210,6 @@ print_and_throw(Err) ->
io:format("\n~s", [ErrBin]), io:format("\n~s", [ErrBin]),
error(ErrBin); error(ErrBin);
Errors -> Errors ->
io:format("Compilation error:\n~s", [string:join([so_errors:pp(E) || E <- Errors], "\n\n")]), io:format("Compilation error:\n~s", [string:join([aeso_errors:pp(E) || E <- Errors], "\n\n")]),
error(compilation_error) error(compilation_error)
end. end.
+22
View File
@@ -0,0 +1,22 @@
-module(aeso_eunit_SUITE).
-compile([export_all, nowarn_export_all]).
-include_lib("common_test/include/ct.hrl").
all() ->
[{group, eunit}].
groups() ->
[{eunit, [], [ aeso_scan_tests
, aeso_parser_tests
, aeso_compiler_tests
, aeso_abi_tests
, aeso_aci_tests
]}].
aeso_scan_tests(_Config) -> ok = eunit:test(aeso_scan_tests).
aeso_parser_tests(_Config) -> ok = eunit:test(aeso_parser_tests).
aeso_compiler_tests(_Config) -> ok = eunit:test(aeso_compiler_tests).
aeso_abi_tests(_Config) -> ok = eunit:test(aeso_abi_tests).
aeso_aci_tests(_Config) -> ok = eunit:test(aeso_aci_tests).
@@ -1,4 +1,4 @@
-module(so_parser_tests). -module(aeso_parser_tests).
-export([parse_contract/1]). -export([parse_contract/1]).
@@ -68,15 +68,15 @@ simple_contracts_test_() ->
}. }.
parse_contract(Name) -> parse_contract(Name) ->
parse_string(so_test_utils:read_contract(Name)). parse_string(aeso_test_utils:read_contract(Name)).
roundtrip_contract(Name) -> roundtrip_contract(Name) ->
round_trip(so_test_utils:read_contract(Name)). round_trip(aeso_test_utils:read_contract(Name)).
parse_string(Text) -> parse_string(Text, []). parse_string(Text) -> parse_string(Text, []).
parse_string(Text, Opts) -> parse_string(Text, Opts) ->
so_parser:string(Text, Opts). aeso_parser:string(Text, Opts).
parse_expr(Text) -> parse_expr(Text) ->
[{letval, _, _, Expr}] = [{letval, _, _, Expr}] =
@@ -85,8 +85,8 @@ parse_expr(Text) ->
round_trip(Text) -> round_trip(Text) ->
Contract = parse_string(Text), Contract = parse_string(Text),
Text1 = prettypr:format(so_pretty:decls(strip_stdlib(Contract))), Text1 = prettypr:format(aeso_pretty:decls(strip_stdlib(Contract))),
Contract1 = parse_string(so_scan:utf8_encode(Text1)), Contract1 = parse_string(aeso_scan:utf8_encode(Text1)),
NoSrcLoc = remove_line_numbers(Contract), NoSrcLoc = remove_line_numbers(Contract),
NoSrcLoc1 = remove_line_numbers(Contract1), NoSrcLoc1 = remove_line_numbers(Contract1),
?assertMatch(NoSrcLoc, diff(NoSrcLoc, NoSrcLoc1)). ?assertMatch(NoSrcLoc, diff(NoSrcLoc, NoSrcLoc1)).
@@ -1,4 +1,4 @@
-module(so_scan_tests). -module(aeso_scan_tests).
-include_lib("eunit/include/eunit.hrl"). -include_lib("eunit/include/eunit.hrl").
@@ -13,7 +13,7 @@ empty_contract_test_() ->
[{"Scan an empty contract.", [{"Scan an empty contract.",
fun() -> fun() ->
Text = " ", Text = " ",
{ok, []} = so_scan:scan(Text), {ok, []} = aeso_scan:scan(Text),
ok ok
end} end}
]}. ]}.
@@ -26,7 +26,7 @@ all_tokens_test_() ->
Tokens = all_tokens(), Tokens = all_tokens(),
Text = string:join(lists:map(fun show_token/1, Tokens), " "), Text = string:join(lists:map(fun show_token/1, Tokens), " "),
io:format("~s\n", [Text]), io:format("~s\n", [Text]),
{ok, Tokens1} = so_scan:scan(Text), {ok, Tokens1} = aeso_scan:scan(Text),
true = compare_tokens(Tokens, Tokens1), true = compare_tokens(Tokens, Tokens1),
ok ok
end} end}
@@ -6,12 +6,12 @@
%%% @end %%% @end
%%%------------------------------------------------------------------- %%%-------------------------------------------------------------------
-module(so_test_utils). -module(aeso_test_utils).
-export([read_contract/1, contract_path/0]). -export([read_contract/1, contract_path/0]).
contract_path() -> contract_path() ->
filename:join(code:lib_dir(sophia, test), "contracts"). filename:join(code:lib_dir(aesophia, test), "contracts").
%% Read a contract file from the test/contracts directory. %% Read a contract file from the test/contracts directory.
-spec read_contract(string() | atom()) -> string(). -spec read_contract(string() | atom()) -> string().
+14
View File
@@ -2,13 +2,27 @@ contract interface Remote =
entrypoint main_fun : (int) => unit entrypoint main_fun : (int) => unit
contract AddrChain = contract AddrChain =
type o_type = oracle(string, map(string, int))
type oq_type = oracle_query(string, map(string, int))
entrypoint is_o(a : address) =
Address.is_oracle(a)
entrypoint is_c(a : address) = entrypoint is_c(a : address) =
Address.is_contract(a) Address.is_contract(a)
// entrypoint get_o(a : address) : option(o_type) =
// Address.get_oracle(a)
// entrypoint get_c(a : address) : option(Remote) = // entrypoint get_c(a : address) : option(Remote) =
// Address.get_contract(a) // Address.get_contract(a)
entrypoint check_o(o : o_type) =
Oracle.check(o)
entrypoint check_oq(o : o_type, oq : oq_type) =
Oracle.check_query(o, oq)
// entrypoint h_to_i(h : hash) : int = // entrypoint h_to_i(h : hash) : int =
// Hash.to_int(h) // Hash.to_int(h)
+4
View File
@@ -5,6 +5,10 @@ contract interface Remote =
contract AddressLiterals = contract AddressLiterals =
entrypoint addr() : address = entrypoint addr() : address =
ak_2gx9MEFxKvY9vMG5YnqnXWv1hCsX7rgnfvBLJS4aQurustR1rt ak_2gx9MEFxKvY9vMG5YnqnXWv1hCsX7rgnfvBLJS4aQurustR1rt
entrypoint oracle() : oracle(int, bool) =
ok_2YNyxd6TRJPNrTcEDCe9ra59SVUdp9FR9qWC5msKZWYD9bP9z5
entrypoint query() : oracle_query(int, bool) =
oq_2oRvyowJuJnEkxy58Ckkw77XfWJrmRgmGaLzhdqb67SKEL1gPY
entrypoint contr() : Remote = entrypoint contr() : Remote =
ct_Ez6MyeTMm17YnTnDdHTSrzMEBKmy7Uz2sXu347bTDPgVH2ifJ ct_Ez6MyeTMm17YnTnDdHTSrzMEBKmy7Uz2sXu347bTDPgVH2ifJ
entrypoint contr_addr() : Remote = entrypoint contr_addr() : Remote =
+6
View File
@@ -14,6 +14,12 @@ main contract AENSTest =
stateful entrypoint resolve_contract(name : string, key : string) : option(C) = stateful entrypoint resolve_contract(name : string, key : string) : option(C) =
AENSv2.resolve(name, key) 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)
// Transactions // Transactions
stateful entrypoint preclaim(addr : address, // Claim on behalf of this account (can be Contract.address) stateful entrypoint preclaim(addr : address, // Claim on behalf of this account (can be Contract.address)
+10 -8
View File
@@ -1,20 +1,19 @@
include "Option.aes" include "Option.aes"
include "String.aes"
include "AENSCompat.aes" include "AENSCompat.aes"
contract interface OldAENSContract = contract interface OldAENSContract =
entrypoint set : (string, string, AENS.pointee) => unit entrypoint set : (string, string, AENS.pointee) => unit
entrypoint lookup : (string, string) => AENS.pointee entrypoint lookup : (string, string) => AENS.pointee
main contract AENSUpdate = main contract AENSUpdate =
stateful entrypoint update_name(owner : address, name : string, b : bytes(2)) = stateful entrypoint update_name(owner : address, name : string) =
let p1 : AENSv2.pointee = AENSv2.AccountPt(Call.caller) let p1 : AENSv2.pointee = AENSv2.AccountPt(Call.caller)
let p2 : AENSv2.pointee = AENSv2.ContractPt(Call.caller) let p2 : AENSv2.pointee = AENSv2.OraclePt(Call.caller)
let p3 : AENSv2.pointee = AENSv2.ChannelPt(Call.caller) let p3 : AENSv2.pointee = AENSv2.ContractPt(Call.caller)
let p4 : AENSv2.pointee = AENSv2.DataPt(String.to_bytes("any something will do")) let p4 : AENSv2.pointee = AENSv2.ChannelPt(Call.caller)
let p5 : AENSv2.pointee = AENSv2.DataPt(Int.to_bytes(1345, 4)) let p5 : AENSv2.pointee = AENSv2.DataPt("any something will do")
AENSv2.update(owner, name, None, None, AENSv2.update(owner, name, None, None,
Some({ ["account_pubkey"] = p1, Some({ ["account_pubkey"] = p1, ["oracle_pubkey"] = p2,
["contract_pubkey"] = p2, ["misc"] = p3, ["data"] = p4, ["data2"] = p5 })) ["contract_pubkey"] = p3, ["misc"] = p4, ["data"] = p5 }))
stateful entrypoint old_interaction(c : OldAENSContract, owner : address, name : string) = stateful entrypoint old_interaction(c : OldAENSContract, owner : address, name : string) =
let p : AENS.pointee = c.lookup(name, "key1") let p : AENS.pointee = c.lookup(name, "key1")
@@ -26,3 +25,6 @@ main contract AENSUpdate =
entrypoint get_ttl(name : string) = entrypoint get_ttl(name : string) =
switch(AENSv2.lookup(name)) switch(AENSv2.lookup(name))
Some(AENSv2.Name(_, FixedTTL(ttl), _)) => ttl Some(AENSv2.Name(_, FixedTTL(ttl), _)) => ttl
entrypoint expiry(o : oracle(int, int)) : int =
Oracle.expiry(o)
-3
View File
@@ -6,7 +6,6 @@
namespace Ns = namespace Ns =
datatype d('a) = D | S(int) | M('a, list('a), int) datatype d('a) = D | S(int) | M('a, list('a), int)
private function fff() = 123 private function fff() = 123
let const = 1
stateful entrypoint stateful entrypoint
f (1, x) = (_) => x f (1, x) = (_) => x
@@ -34,8 +33,6 @@ contract AllSyntax =
type state = shakespeare(int) type state = shakespeare(int)
let cc = "str"
entrypoint init() = { entrypoint init() = {
johann = 1000, johann = 1000,
wolfgang = -10, wolfgang = -10,
+18
View File
@@ -7,9 +7,27 @@ contract AddressLiterals =
ak_2gx9MEFxKvY9vMG5YnqnXWv1hCsX7rgnfvBLJS4aQurustR1rt ak_2gx9MEFxKvY9vMG5YnqnXWv1hCsX7rgnfvBLJS4aQurustR1rt
entrypoint addr2() : Remote = entrypoint addr2() : Remote =
ak_2gx9MEFxKvY9vMG5YnqnXWv1hCsX7rgnfvBLJS4aQurustR1rt ak_2gx9MEFxKvY9vMG5YnqnXWv1hCsX7rgnfvBLJS4aQurustR1rt
entrypoint addr3() : oracle(int, bool) =
ak_2gx9MEFxKvY9vMG5YnqnXWv1hCsX7rgnfvBLJS4aQurustR1rt
entrypoint oracle1() : oracle_query(int, bool) =
ok_2YNyxd6TRJPNrTcEDCe9ra59SVUdp9FR9qWC5msKZWYD9bP9z5
entrypoint oracle2() : bytes(32) =
ok_2YNyxd6TRJPNrTcEDCe9ra59SVUdp9FR9qWC5msKZWYD9bP9z5
entrypoint oracle3() : Remote =
ok_2YNyxd6TRJPNrTcEDCe9ra59SVUdp9FR9qWC5msKZWYD9bP9z5
entrypoint query1() : oracle(int, bool) =
oq_2oRvyowJuJnEkxy58Ckkw77XfWJrmRgmGaLzhdqb67SKEL1gPY
entrypoint query2() : bytes(32) =
oq_2oRvyowJuJnEkxy58Ckkw77XfWJrmRgmGaLzhdqb67SKEL1gPY
entrypoint query3() : Remote =
oq_2oRvyowJuJnEkxy58Ckkw77XfWJrmRgmGaLzhdqb67SKEL1gPY
entrypoint contr1() : address = entrypoint contr1() : address =
ct_Ez6MyeTMm17YnTnDdHTSrzMEBKmy7Uz2sXu347bTDPgVH2ifJ ct_Ez6MyeTMm17YnTnDdHTSrzMEBKmy7Uz2sXu347bTDPgVH2ifJ
entrypoint contr2() : oracle(int, bool) =
ct_Ez6MyeTMm17YnTnDdHTSrzMEBKmy7Uz2sXu347bTDPgVH2ifJ
entrypoint contr3() : bytes(32) = entrypoint contr3() : bytes(32) =
ct_Ez6MyeTMm17YnTnDdHTSrzMEBKmy7Uz2sXu347bTDPgVH2ifJ ct_Ez6MyeTMm17YnTnDdHTSrzMEBKmy7Uz2sXu347bTDPgVH2ifJ
entrypoint contr4() : address = entrypoint contr4() : address =
-5
View File
@@ -1,5 +0,0 @@
// include "String.aes"
contract BytesToX =
entrypoint fail1(b : bytes()) = Bytes.to_fixed_size(b)
entrypoint fail2(b : bytes(4)) = Bytes.to_fixed_size(b)
entrypoint fail3(b : bytes()) = Bytes.to_any_size(b)
+5
View File
@@ -9,6 +9,7 @@
// datatype ga_meta_tx = GAMetaTx(address, int) // datatype ga_meta_tx = GAMetaTx(address, int)
// datatype paying_for_tx = PayingForTx(address, int) // datatype paying_for_tx = PayingForTx(address, int)
// datatype base_tx = SpendTx(address, int, string) // datatype base_tx = SpendTx(address, int, string)
// | OracleRegisterTx | OracleQueryTx | OracleResponseTx | OracleExtendTx
// | NamePreclaimTx | NameClaimTx(hash) | NameUpdateTx(string) // | NamePreclaimTx | NameClaimTx(hash) | NameUpdateTx(string)
// | NameRevokeTx(hash) | NameTransferTx(address, string) // | NameRevokeTx(hash) | NameTransferTx(address, string)
// | ChannelCreateTx(address) | ChannelDepositTx(address, int) | ChannelWithdrawTx(address, int) | // | ChannelCreateTx(address) | ChannelDepositTx(address, int) | ChannelWithdrawTx(address, int) |
@@ -41,6 +42,10 @@ contract BasicAuthTx =
fee = 123, ttl = 0, actor = Call.caller } fee = 123, ttl = 0, actor = Call.caller }
switch(tx0.tx) switch(tx0.tx)
Chain.SpendTx(receiver, amount, payload) => verify(tx_hash, n, s) Chain.SpendTx(receiver, amount, payload) => verify(tx_hash, n, s)
Chain.OracleRegisterTx => false
Chain.OracleQueryTx => false
Chain.OracleResponseTx => false
Chain.OracleExtendTx => false
Chain.NamePreclaimTx => false Chain.NamePreclaimTx => false
Chain.NameClaimTx(name) => false Chain.NameClaimTx(name) => false
Chain.NameUpdateTx(name) => false Chain.NameUpdateTx(name) => false
-27
View File
@@ -1,27 +0,0 @@
include "String.aes"
contract BytesMisc =
entrypoint sizeFixed(b : bytes(4)) : int = Bytes.size(b)
entrypoint sizeAny(b : bytes()) : int = Bytes.size(b)
entrypoint int_to_bytes(i : int) : bytes() = Int.to_bytes(i, 16)
entrypoint test(b3 : bytes(3), b7 : bytes(7), bX : bytes, i : int, s : string) =
let bi = Int.to_bytes(i, 8)
let bs = String.to_bytes(s)
let b10 = Bytes.concat(b3, b7)
let (b4, b6 : bytes(6)) = Bytes.split(b10)
let Some((b8, b2)) = Bytes.split_any(bX, 8)
let bX7 = Bytes.concat(bX, b7)
let Some((b5, bX2)) = Bytes.split_any(bX7, 5)
let Some((b7b, b0)) = Bytes.split_any(bX, Bytes.size(b7))
let Some(b5b : bytes(5)) = Bytes.to_fixed_size(b5)
let (b1 : bytes(1), _) = Bytes.split(b5b)
[bi, bs, b0, Bytes.to_any_size(b1), b2, Bytes.to_any_size(b4), Bytes.to_any_size(b6), b7b, b8, bX2]
-2
View File
@@ -6,5 +6,3 @@ contract BytesToX =
String.concat(Bytes.to_str(b), Bytes.to_str(#ffff)) String.concat(Bytes.to_str(b), Bytes.to_str(#ffff))
entrypoint to_str_big(b : bytes(65)) : string = entrypoint to_str_big(b : bytes(65)) : string =
Bytes.to_str(b) Bytes.to_str(b)
entrypoint to_fixed(b : bytes()) : option(bytes(4)) = Bytes.to_fixed_size(b)
entrypoint to_any(b : bytes(4)) = Bytes.to_any_size(b)
@@ -1,5 +0,0 @@
contract F =
entrypoint g() = 1
main contract C =
entrypoint f() = F.g()
+1 -2
View File
@@ -11,5 +11,4 @@ contract C =
let i = Int.mulmod(a, b, h) let i = Int.mulmod(a, b, h)
let j = Crypto.poseidon(i, a) let j = Crypto.poseidon(i, a)
let k : bytes(32) = Address.to_bytes(Call.origin) let k : bytes(32) = Address.to_bytes(Call.origin)
let l = sg_MhibzTP1wWzGCTjtPFr1TiPqRJrrJqw7auvEuF5i3FdoALWqXLBDY6xxRRNUSPHK3EQTnTzF12EyspkxrSMxVHKsZeSMj (a bor b band c bxor a << bnot b >> a, k)
(a bor b band c bxor a << bnot b >> a, k, l)
+1 -5
View File
@@ -2,8 +2,7 @@
contract ChainTest = contract ChainTest =
record state = { last_bf : address record state = { last_bf : address }
, nw_id : string }
function init() : state = function init() : state =
{last_bf = Contract.address} {last_bf = Contract.address}
@@ -12,6 +11,3 @@ contract ChainTest =
function save_coinbase() = function save_coinbase() =
put(state{last_bf = Chain.coinbase}) put(state{last_bf = Chain.coinbase})
function save_network_id() =
put(state{nw_id = Chain.network_id})
-4
View File
@@ -1,4 +0,0 @@
include "../dir2/baz.aes"
namespace D =
function g() = E.h()
-3
View File
@@ -1,3 +0,0 @@
namespace E =
function h() = 42
+4
View File
@@ -11,6 +11,8 @@ contract Events =
type ix5 = hash // bytes(32) type ix5 = hash // bytes(32)
type ix6 = address type ix6 = address
type ix7 = Remote type ix7 = Remote
type ix8 = oracle(int, int)
type ix9 = oracle_query(int, int)
// Valid payload types // Valid payload types
type data1 = string type data1 = string
@@ -24,6 +26,7 @@ contract Events =
| Nodata3(ix4, ix5, ix6) | Nodata3(ix4, ix5, ix6)
| Data0(data1) | Data0(data1)
| Data1(data2, ix7) | Data1(data2, ix7)
| Data2(ix8, data3, ix9)
| Data3(ix1, ix2, ix5, data1) | Data3(ix1, ix2, ix5, data1)
entrypoint nodata0() = Chain.event(Nodata0) entrypoint nodata0() = Chain.event(Nodata0)
@@ -32,5 +35,6 @@ contract Events =
entrypoint nodata3(ix4, ix5, ix6) = Chain.event(Nodata3(ix4, ix5, ix6)) entrypoint nodata3(ix4, ix5, ix6) = Chain.event(Nodata3(ix4, ix5, ix6))
entrypoint data0(data1) = Chain.event(Data0(data1)) entrypoint data0(data1) = Chain.event(Data0(data1))
entrypoint data1(data2, ix7) = Chain.event(Data1(data2, ix7)) entrypoint data1(data2, ix7) = Chain.event(Data1(data2, ix7))
entrypoint data2(ix8, data3, ix9) = Chain.event(Data2(ix8, data3, ix9))
entrypoint data3(ix1, ix2, ix5, data1) = Chain.event(Data3(ix1, ix2, ix5, data1)) entrypoint data3(ix1, ix2, ix5, data1) = Chain.event(Data3(ix1, ix2, ix5, data1))
+6 -4
View File
@@ -20,8 +20,6 @@ contract FunctionArguments =
entrypoint read(a : answer(int)) = entrypoint read(a : answer(int)) =
a.result a.result
entrypoint any_bytes(b : bytes()) = b
entrypoint sjutton(b : bytes(17)) = entrypoint sjutton(b : bytes(17)) =
b b
@@ -31,6 +29,12 @@ contract FunctionArguments =
entrypoint trettiotva(b : bytes(32)) = entrypoint trettiotva(b : bytes(32)) =
b b
entrypoint find_oracle(o : oracle(int, bool)) =
true
entrypoint find_query(q : oracle_query(int, bool)) =
true
datatype colour() = Green | Yellow | Red | Pantone(int) datatype colour() = Green | Yellow | Red | Pantone(int)
entrypoint traffic_light(c : colour) = entrypoint traffic_light(c : colour) =
@@ -53,5 +57,3 @@ contract FunctionArguments =
entrypoint chain_ga_meta_tx(tx : Chain.ga_meta_tx) = true entrypoint chain_ga_meta_tx(tx : Chain.ga_meta_tx) = true
entrypoint chain_paying_for_tx(tx : Chain.paying_for_tx) = true entrypoint chain_paying_for_tx(tx : Chain.paying_for_tx) = true
entrypoint chain_base_tx(tx : Chain.base_tx) = true entrypoint chain_base_tx(tx : Chain.base_tx) = true
entrypoint sig(sg : signature) = true
@@ -0,0 +1,5 @@
contract HigherOrderResponseType =
stateful function foo(o, q : oracle_query(string, _)) =
Oracle.respond(o, q, (x) => x + 1)
entrypoint main_fun() = ()
-13
View File
@@ -1,13 +0,0 @@
include "List.aes"
contract C =
entrypoint f() =
let ??? = true
let v = ???
let q = v == "str"
let xs = [1, 2, 3, 4]
switch (List.first(List.map(???, xs)))
Some(x) => x + 1
None => 0
function g() = ???
+110
View File
@@ -0,0 +1,110 @@
contract Oracles =
type fee = int
type ttl = Chain.ttl
type query_t = string
type answer_t = int
type oracle_id = oracle(query_t, answer_t)
type query_id = oracle_query(query_t, answer_t)
stateful entrypoint registerOracle(acct : address,
qfee : fee,
ttl : ttl) : oracle_id =
Oracle.register(acct, qfee, ttl)
stateful entrypoint registerIntIntOracle(acct : address,
qfee : fee,
ttl : ttl) : oracle(int, int) =
Oracle.register(acct, qfee, ttl)
stateful entrypoint registerStringStringOracle(acct : address,
qfee : fee,
ttl : ttl) : oracle(string, string) =
Oracle.register(acct, qfee, ttl)
stateful entrypoint signedRegisterOracle(acct : address,
sign : signature,
qfee : fee,
ttl : ttl) : oracle_id =
Oracle.register(acct, qfee, ttl, signature = sign)
entrypoint queryFee(o : oracle_id) : fee =
Oracle.query_fee(o)
stateful entrypoint createQuery(o : oracle_id,
q : query_t,
qfee : fee,
qttl : ttl,
rttl : ttl) : query_id =
require(qfee =< Call.value, "insufficient value for qfee")
Oracle.query(o, q, qfee, qttl, rttl)
// Do not use in production!
stateful entrypoint unsafeCreateQuery(o : oracle_id,
q : query_t,
qfee : fee,
qttl : ttl,
rttl : ttl) : query_id =
Oracle.query(o, q, qfee, qttl, rttl)
// Do not use in production!
stateful entrypoint unsafeCreateQueryThenErr(o : oracle_id,
q : query_t,
qfee : fee,
qttl : ttl,
rttl : ttl) : query_id =
let res = Oracle.query(o, q, qfee, qttl, rttl)
require(qfee >= 100000000000000000, "causing a late error")
res
stateful entrypoint extendOracle(o : oracle_id,
ttl : ttl) : unit =
Oracle.extend(o, ttl)
stateful entrypoint signedExtendOracle(o : oracle_id,
sign : signature, // Signed oracle address
ttl : ttl) : unit =
Oracle.extend(o, signature = sign, ttl)
stateful entrypoint respond(o : oracle_id,
q : query_id,
r : answer_t) : unit =
Oracle.respond(o, q, r)
stateful entrypoint signedRespond(o : oracle_id,
q : query_id,
sign : signature,
r : answer_t) : unit =
Oracle.respond(o, q, signature = sign, r)
entrypoint getQuestion(o : oracle_id,
q : query_id) : query_t =
Oracle.get_question(o, q)
entrypoint hasAnswer(o : oracle_id,
q : query_id) =
switch(Oracle.get_answer(o, q))
None => false
Some(_) => true
entrypoint getAnswer(o : oracle_id,
q : query_id) : option(answer_t) =
Oracle.get_answer(o, q)
datatype complexQuestion = Why(int) | How(string)
datatype complexAnswer = NoAnswer | Answer(complexQuestion, string, int)
stateful entrypoint complexOracle(question) =
let o = Oracle.register(Contract.address, 0, FixedTTL(1000)) : oracle(complexQuestion, complexAnswer)
let q = Oracle.query(o, question, 0, RelativeTTL(100), RelativeTTL(100))
Oracle.respond(o, q, Answer(question, "magic", 1337))
Oracle.get_answer(o, q)
stateful entrypoint signedComplexOracle(question, sig) =
let o = Oracle.register(signature = sig, Contract.address, 0, FixedTTL(1000)) : oracle(complexQuestion, complexAnswer)
let q = Oracle.query(o, question, 0, RelativeTTL(100), RelativeTTL(100))
Oracle.respond(o, q, Answer(question, "magic", 1337), signature = sig)
Oracle.get_answer(o, q)
@@ -0,0 +1,5 @@
contract PolymorphicQueryType =
stateful function is_oracle(o) =
Oracle.check(o)
entrypoint main_fun() = ()
@@ -0,0 +1,5 @@
contract PolymorphicResponseType =
function is_oracle(o : oracle(string, 'r)) =
Oracle.check(o)
entrypoint main_fun(o : oracle(string, int)) = is_oracle(o)
@@ -1,5 +0,0 @@
contract interface I =
entrypoint f : () => int
contract C : I =
stateful entrypoint f() = 1
@@ -1,6 +0,0 @@
contract interface I =
entrypoint f : () => int
contract C : I =
entrypoint init() = ()
function f() = 1
@@ -1,5 +0,0 @@
payable contract interface I =
payable entrypoint f : () => int
contract C : I =
entrypoint f() = 123
@@ -1,8 +0,0 @@
payable contract interface I =
payable entrypoint f : () => int
contract interface H : I =
payable entrypoint f : () => int
payable contract C : H =
entrypoint f() = 123
@@ -1,14 +0,0 @@
contract interface F =
entrypoint f : () => int
payable contract interface G : F =
payable entrypoint f : () => int
entrypoint g : () => int
payable contract interface H =
payable entrypoint h : () => int
payable contract C : G, H =
payable entrypoint f() = 1
payable entrypoint g() = 2
payable entrypoint h() = 3
@@ -1,7 +0,0 @@
contract interface I =
payable entrypoint f : () => int
entrypoint g : () => int
contract C : I =
payable entrypoint f() = 1
payable entrypoint g() = 2
@@ -1,7 +0,0 @@
contract interface I =
stateful entrypoint f : () => int
stateful entrypoint g : () => int
contract C : I =
stateful entrypoint f() = 1
entrypoint g() = 2
@@ -1,5 +0,0 @@
contract interface I =
payable entrypoint f : () => int
contract C : I =
entrypoint f() = 1
@@ -0,0 +1,47 @@
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
()
-3
View File
@@ -1,3 +0,0 @@
include "./dir1/bar.aes"
contract C =
entrypoint f() = D.g()
-60
View File
@@ -1,60 +0,0 @@
contract C =
entrypoint too_many(
(_, _, _, _, _, _, _, _, _, _),
(_, _, _, _, _, _, _, _, _, _),
(_, _, _, _, _, _, _, _, _, _),
(_, _, _, _, _, _, _, _, _, _),
(_, _, _, _, _, _, _, _, _, _),
(_, _, _, _, _, _, _, _, _, _),
(_, _, _, _, _, _, _, _, _, _),
(_, _, _, _, _, _, _, _, _, _),
(_, _, _, _, _, _, _, _, _, _),
(_, _, _, _, _, _, _, _, _, _),
(_, _, _, _, _, _, _, _, _, _),
(_, _, _, _, _, _, _, _, _, _),
(_, _, _, _, _, _, _, _, _, _),
(_, _, _, _, _, _, _, _, _, _),
(_, _, _, _, _, _, _, _, _, _),
(_, _, _, _, _, _, _, _, _, _),
(_, _, _, _, _, _, _, _, _, _),
(_, _, _, _, _, _, _, _, _, _),
(_, _, _, _, _, _, _, _, _, _),
(_, _, _, _, _, _, _, _, _, _),
(_, _, _, _, _, _, _, _, _, _),
(_, _, _, _, _, _, _, _, _, _),
(_, _, _, _, _, _, _, _, _, _),
(_, _, _, _, _, _, _, _, _, _),
(_, _, _, _, _, _, _, _, _, _),
(_, _, _, _, _, _, _, _, _, _)) = 0
entrypoint not_too_many(
(_, _, _, _, _, _, _, _, _, _),
(_, _, _, _, _, _, _, _, _, _),
(_, _, _, _, _, _, _, _, _, _),
(_, _, _, _, _, _, _, _, _, _),
(_, _, _, _, _, _, _, _, _, _),
(_, _, _, _, _, _, _, _, _, _),
(_, _, _, _, _, _, _, _, _, _),
(_, _, _, _, _, _, _, _, _, _),
(_, _, _, _, _, _, _, _, _, _),
(_, _, _, _, _, _, _, _, _, _),
(_, _, _, _, _, _, _, _, _, _),
(_, _, _, _, _, _, _, _, _, _),
(_, _, _, _, _, _, _, _, _, _),
(_, _, _, _, _, _, _, _, _, _),
(_, _, _, _, _, _, _, _, _, _),
(_, _, _, _, _, _, _, _, _, _),
(_, _, _, _, _, _, _, _, _, _),
(_, _, _, _, _, _, _, _, _, _),
(_, _, _, _, _, _, _, _, _, _),
(_, _, _, _, _, _, _, _, _, _),
(_, _, _, _, _, _, _, _, _, _),
(_, _, _, _, _, _, _, _, _, _),
(_, _, _, _, _, _, _, _, _, _),
(_, _, _, _, _, _, _, _, _, _),
(_, _, _, _, _, _, _, _, _, _),
(_, _, _, _, _, _)) = 0
-60
View File
@@ -1,60 +0,0 @@
namespace N0 =
let nsconst = 1
namespace N =
let nsconst = N0.nsconst
contract C =
datatype event = EventX(int, string)
record account = { name : string,
balance : int }
let c01 = 2425
let c02 = -5
let c03 = ak_2gx9MEFxKvY9vMG5YnqnXWv1hCsX7rgnfvBLJS4aQurustR1rt
let c04 = true
let c05 = Bits.none
let c06 = #fedcba9876543210
let c07 = "str"
let c08 = [1, 2, 3]
let c09 = [(true, 24), (false, 19), (false, -42)]
let c10 = (42, "Foo", true)
let c11 = { name = "str", balance = 100000000 }
let c12 = {["foo"] = 19, ["bar"] = 42}
let c13 = Some(42)
let c14 = 11 : int
let c15 = EventX(0, "Hello")
let c16 = #000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f
let c17 = #000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f
let c18 = RelativeTTL(50)
let c19 = ct_Ez6MyeTMm17YnTnDdHTSrzMEBKmy7Uz2sXu347bTDPgVH2ifJ : C
let c20 = N.nsconst
let c21 = c01
let c22 = c11.name
let c23 : int = 1
entrypoint f01() = c01
entrypoint f02() = c02
entrypoint f03() = c03
entrypoint f04() = c04
entrypoint f05() = c05
entrypoint f06() = c06
entrypoint f07() = c07
entrypoint f08() = c08
entrypoint f09() = c09
entrypoint f10() = c10
entrypoint f11() = c11
entrypoint f12() = c12
entrypoint f13() = c13
entrypoint f14() = c14
entrypoint f15() = c15
entrypoint f16() = c16
entrypoint f17() = c17
entrypoint f18() = c18
entrypoint f19() = c19
entrypoint f20() = c20
entrypoint f21() = c21
entrypoint f22() = c22
entrypoint f23() = c23
entrypoint fqual() = C.c01
@@ -1,11 +0,0 @@
contract G =
let const = 1
main contract C =
let c = G.const
stateful entrypoint f() =
let g = Chain.create() : G
g.const
g.const()
@@ -1,6 +0,0 @@
contract C =
let selfcycle = selfcycle
let cycle1 = cycle2
let cycle2 = cycle3
let cycle3 = cycle1
@@ -1,7 +0,0 @@
contract interface I =
let (x::y::_) = [1,2,3]
let c = 10
let d = 10
contract C =
entrypoint init() = ()
@@ -1,21 +0,0 @@
main contract C =
record account = { name : string,
balance : int }
let one = 1
let opt = Some(5)
let acc = { name = "str", balance = 100000 }
let mpp = {["foo"] = 19, ["bar"] = 42}
let c01 = [x | x <- [1,2,3,4,5]]
let c02 = [x + k | x <- [1,2,3,4,5], let k = x*x]
let c03 = [x + y | x <- [1,2,3,4,5], let k = x*x, if (k > 5), y <- [k, k+1, k+2]]
let c04 = if (one > 2) 3 else 4
let c05 = switch (opt)
Some(x) => x
None => 2
let c07 = acc{ balance = one }
let c08 = mpp["foo"]
let c09 = mpp["non" = 10]
let c10 = mpp{["foo"] = 20}
let c11 = (x) => x + 1
@@ -1,3 +0,0 @@
contract C =
let x::_ = [1,2,3,4]
let y::(p = z::_) = [1,2,3,4]
+3
View File
@@ -0,0 +1,3 @@
contract C =
let this_is_illegal = 2/0
entrypoint this_is_legal() = 2/0
+13 -1
View File
@@ -1,12 +1,16 @@
// Builtins without named arguments can appear unapplied. // Builtins without named arguments can appear unapplied.
// Named argument builtins are: // Named argument builtins are:
// Oracle.register
// Oracle.respond
// AENSv2.preclaim // AENSv2.preclaim
// AENSv2.claim // AENSv2.claim
// AENSv2.transfer // AENSv2.transfer
// AENSv2.revoke // AENSv2.revoke
// Oracle.extend
include "String.aes" include "String.aes"
contract UnappliedBuiltins = contract UnappliedBuiltins =
entrypoint main_fun() = () entrypoint main_fun() = ()
type o = oracle(int, int)
type t = list(int * string) type t = list(int * string)
type m = map(int, int) type m = map(int, int)
datatype event = Event(int) datatype event = Event(int)
@@ -17,6 +21,13 @@ contract UnappliedBuiltins =
function call_gas_left() = Call.gas_left function call_gas_left() = Call.gas_left
function b_abort() = abort function b_abort() = abort
function b_require() = require function b_require() = require
function oracle_query_fee() = Oracle.query_fee
function oracle_expiry() = Oracle.expiry
stateful function oracle_query() = Oracle.query : (o, _, _, _, _) => _
function oracle_get_question() = Oracle.get_question : (o, _) => _
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() = AENSv2.resolve : (_, _) => option(string)
function map_lookup() = Map.lookup : (_, m) => _ function map_lookup() = Map.lookup : (_, m) => _
function map_lookup_default() = Map.lookup_default : (_, m, _) => _ function map_lookup_default() = Map.lookup_default : (_, m, _) => _
@@ -25,7 +36,7 @@ contract UnappliedBuiltins =
function map_delete() = Map.delete : (_, m) => _ function map_delete() = Map.delete : (_, m) => _
function map_from_list() = Map.from_list : _ => m function map_from_list() = Map.from_list : _ => m
function map_to_list() = Map.to_list : m => _ function map_to_list() = Map.to_list : m => _
function crypto_verify_sig() = Crypto.verify_sig : (bytes(), _, _) => _ function crypto_verify_sig() = Crypto.verify_sig
function crypto_verify_sig_secp256k1() = Crypto.verify_sig_secp256k1 function crypto_verify_sig_secp256k1() = Crypto.verify_sig_secp256k1
function crypto_ecverify_secp256k1() = Crypto.ecverify_secp256k1 function crypto_ecverify_secp256k1() = Crypto.ecverify_secp256k1
function crypto_ecrecover_secp256k1() = Crypto.ecrecover_secp256k1 function crypto_ecrecover_secp256k1() = Crypto.ecrecover_secp256k1
@@ -46,6 +57,7 @@ contract UnappliedBuiltins =
function bits_sum() = Bits.sum function bits_sum() = Bits.sum
function int_to_str() = Int.to_str function int_to_str() = Int.to_str
function address_to_str() = Address.to_str function address_to_str() = Address.to_str
function address_is_oracle() = Address.is_oracle
function address_is_contract() = Address.is_contract function address_is_contract() = Address.is_contract
function address_is_payable() = Address.is_payable function address_is_payable() = Address.is_payable
function bytes_to_int() = Bytes.to_int : bytes(10) => int function bytes_to_int() = Bytes.to_int : bytes(10) => int
@@ -0,0 +1,4 @@
contract UnappliedNamedArgBuiltin =
stateful entrypoint main_fun(s) =
let reg = Oracle.register
reg(signature = s, Contract.address, 100, RelativeTTL(100)) : oracle(int, int)
@@ -1,7 +0,0 @@
contract F =
entrypoint g() = 1
main contract C =
using F for [g]
entrypoint f() = g()
@@ -1,5 +0,0 @@
namespace N =
function nconst() = 1
main contract C =
entrypoint f() = N.nconst()
@@ -1,5 +0,0 @@
contract Test =
type option_int = option(int)
record option_point = {x: int, y: option_int}
entrypoint test_option_record(a: option_point) = a
+1 -29
View File
@@ -12,7 +12,7 @@ namespace UnusedNamespace =
// Unused // Unused
private function h() = 3 private function h() = 3
main contract Warnings = contract Warnings =
type state = int type state = int
@@ -58,31 +58,3 @@ namespace FunctionsAsArgs =
private function inc(n : int) : int = n + 1 private function inc(n : int) : int = n + 1
// Never used // Never used
private function dec(n : int) : int = n - 1 private function dec(n : int) : int = n - 1
contract Remote =
entrypoint id(_) = 0
contract C =
payable stateful entrypoint
call_missing_con() : int = (ct_1111111111111111111111111111112JF6Dz72 : Remote).id(value = 1, 0)
namespace ShadowingConst =
let const = 1
function f() =
let const = 2
const
namespace UnusedConstNamespace =
// No warnings should be shown even though const is not used
let const = 1
contract UnusedConstContract =
// Only `c` should show a warning because it is never used in the contract
let a = 1
let b = 2
let c = 3
entrypoint f() =
// Both normal access and qualified access should prevent the unused const warning
a + UnusedConstContract.b
-40
View File
@@ -1,40 +0,0 @@
-module(so_encode_decode_tests).
-compile([export_all, nowarn_export_all]).
-include_lib("eunit/include/eunit.hrl").
-define(EMPTY, "contract C =\n entrypoint f() = true").
encode_decode_test_() ->
[ {lists:flatten(io_lib:format("Testing encode-decode roundtrip for ~p : ~p", [Value, {EType, DType}])),
fun() ->
{ok, SerRes} = so_compiler:encode_value(?EMPTY, EType, Value, []),
{ok, Expr} = so_compiler:decode_value(?EMPTY, DType, SerRes, []),
Value2 = prettypr:format(so_pretty:expr(Expr)),
?assertEqual(Value, Value2)
end} || {Value, EType, DType} <- test_data() ].
test_data() ->
lists:map(fun({V, T}) -> {V, T, T};
({V, T1, T2}) -> {V, T1, T2} end, data()).
data() ->
[ {"42", "int"}
, {"- 42", "int"}
, {"true", "bool"}
, {"ak_Ez6MyeTMm17YnTnDdHTSrzMEBKmy7Uz2sXu347bTDPgVH2ifJ", "address"}
, {"ct_Ez6MyeTMm17YnTnDdHTSrzMEBKmy7Uz2sXu347bTDPgVH2ifJ", "C"}
, {"Some(42)", "option(int)"}
, {"None", "option(int)"}
, {"(true, 42)", "bool * int"}
, {"{[1] = true, [3] = false}", "map(int, bool)"}
, {"()", "unit"}
, {"#000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f", "hash"}
, {"#000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f", "bytes(32)"}
, {"sg_MhibzTP1wWzGCTjtPFr1TiPqRJrrJqw7auvEuF5i3FdoALWqXLBDY6xxRRNUSPHK3EQTnTzF12EyspkxrSMxVHKsZeSMj", "signature"}
, {"sg_MhibzTP1wWzGCTjtPFr1TiPqRJrrJqw7auvEuF5i3FdoALWqXLBDY6xxRRNUSPHK3EQTnTzF12EyspkxrSMxVHKsZeSMj", "bytes(64)", "signature"}
, {"#0102030405060708090a0b0c0d0e0f101718192021222324252627282930313233343536373839401a1b1c1d1e1f202122232425262728293031323334353637", "bytes(64)"}
, {"#0102030405060708090a0b0c0d0e0f101718192021222324252627282930313233343536373839401a1b1c1d1e1f202122232425262728293031323334353637", "signature", "bytes(64)"}
].
-22
View File
@@ -1,22 +0,0 @@
-module(so_eunit_SUITE).
-compile([export_all, nowarn_export_all]).
-include_lib("common_test/include/ct.hrl").
all() ->
[{group, eunit}].
groups() ->
[{eunit, [], [ so_scan_tests
, so_parser_tests
, so_compiler_tests
, so_abi_tests
, so_aci_tests
]}].
so_scan_tests(_Config) -> ok = eunit:test(so_scan_tests).
so_parser_tests(_Config) -> ok = eunit:test(so_parser_tests).
so_compiler_tests(_Config) -> ok = eunit:test(so_compiler_tests).
so_abi_tests(_Config) -> ok = eunit:test(so_abi_tests).
so_aci_tests(_Config) -> ok = eunit:test(so_aci_tests).