Compare commits
50 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 3771b6a5f2 | |||
| ec316d2a0d | |||
| 6c6bf38d8c | |||
| 9f90396023 | |||
| 927cd42592 | |||
| 16308a7840 | |||
| 46a307432f | |||
| 83dcc6dbc4 | |||
| ffdd4ecf26 | |||
| 51bae61736 | |||
| 31301911a2 | |||
| de426a210b | |||
| 944ed49f0b | |||
| 1387e814f8 | |||
| 44d6982d66 | |||
| aa532046d3 | |||
| fbaab570f2 | |||
| 1a80f3faa0 | |||
| 745eeda858 | |||
| 78b758c337 | |||
| 108cb1f948 | |||
| 2c8dcf8032 | |||
| c51d0a5e21 | |||
| e44174b71c | |||
| dcea538e11 | |||
| f60f9122ba | |||
| 5c3b42aff1 | |||
| dbeb792ca5 | |||
| f75455bb85 | |||
| cdbd430f23 | |||
| 03d6dd6ca2 | |||
| 33229c3513 | |||
| 002e55d529 | |||
| 9b518150c3 | |||
| 67948513d5 | |||
| 08fa372c24 | |||
| 3b0ca28c8e | |||
| 86d7b36ba7 | |||
| 43c8328615 | |||
| c15d411660 | |||
| b902226c26 | |||
| c1e8195fd8 | |||
| d5ff9d4a2f | |||
| c395849684 | |||
| 7bac15949c | |||
| f11697da1a | |||
| fc2731fbbb | |||
| cc76f93dd7 | |||
| 7b6eba5319 | |||
| add82fe5ee |
@@ -2,4 +2,4 @@ mkdocs==1.4.2
|
|||||||
mkdocs-simple-hooks==0.1.5
|
mkdocs-simple-hooks==0.1.5
|
||||||
mkdocs-material==9.0.9
|
mkdocs-material==9.0.9
|
||||||
mike==1.1.2
|
mike==1.1.2
|
||||||
pygments==2.14.0
|
pygments==2.17.2
|
||||||
|
|||||||
@@ -24,3 +24,4 @@ current_counterexample.eqc
|
|||||||
test/contracts/test.aes
|
test/contracts/test.aes
|
||||||
__pycache__
|
__pycache__
|
||||||
.docssite/docs/*.md
|
.docssite/docs/*.md
|
||||||
|
.vscode
|
||||||
|
|||||||
+83
-1
@@ -6,8 +6,83 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
|
|
||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
### Added
|
### 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
|
### Changed
|
||||||
### Removed
|
### Removed
|
||||||
|
|
||||||
|
## [8.0.1]
|
||||||
|
### Changed
|
||||||
|
- Upgrade aebytecode to v3.4.1 to fix C warnings
|
||||||
|
|
||||||
|
## [8.0.0]
|
||||||
|
### Added
|
||||||
|
- Bitwise operations for integers: `band`, `bor`, `bxor`, `bnot`, `<<` and `>>`.
|
||||||
|
- `Int.mulmod` - combined builtin operation for multiplication and modulus.
|
||||||
|
- `Crypto.poseidon` - a ZK/SNARK-friendly hash function (over the BLS12-381 scalar field).
|
||||||
|
- `Address.to_bytes` - convert an address to its binary representation (for hashing, etc.).
|
||||||
|
- Raw data pointers added to AENS. In short we have introduced a new namespace
|
||||||
|
`AENSv2`; they contain types similar to the old `AENS`; `AENS.name` and
|
||||||
|
`AENS.pointee`, where the latter now has a constructor `DataPt(bytes())`. All
|
||||||
|
AENS actions have been moved to `AENSv2`, and `AENSv2.lookup` and
|
||||||
|
`AENSv2.update` consume and produce the new types. The old `AENS` namespace
|
||||||
|
only contains the old datatypes, that can be used to interface existing
|
||||||
|
contracts. Standard library `AENSCompat` is added to convert between old and
|
||||||
|
new pointers.
|
||||||
|
- 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
|
||||||
|
- `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
|
||||||
|
- `Bitwise.aes` standard library is removed - the builtin operations are superior.
|
||||||
|
|
||||||
|
## [7.4.1]
|
||||||
|
### 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
|
### Fixed
|
||||||
- Warning about unused include when there is no include.
|
- Warning about unused include when there is no include.
|
||||||
|
|
||||||
@@ -381,7 +456,14 @@ 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/v7.1.0...HEAD
|
[Unreleased]: https://github.com/aeternity/aesophia/compare/v8.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.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
|
||||||
|
|||||||
@@ -53,8 +53,6 @@ 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
|
||||||
|
|||||||
+105
-13
@@ -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) =
|
||||||
@@ -295,6 +295,11 @@ 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
|
||||||
@@ -493,6 +498,24 @@ 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
|
||||||
@@ -540,6 +563,7 @@ 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` |
|
||||||
@@ -554,7 +578,7 @@ 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 | `#000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f` |
|
| signature | `sg_MhibzTP1wWzGCTjtPFr1TiPqRJrrJqw7auvEuF5i3FdoALWqXLBDY6xxRRNUSPHK3EQTnTzF12EyspkxrSMxVHKsZeSMj`, `#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` |
|
||||||
@@ -573,6 +597,32 @@ contract C =
|
|||||||
|
|
||||||
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.
|
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
|
||||||
@@ -588,10 +638,24 @@ 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.
|
||||||
|
|
||||||
|
Sophia arbitrary-sized integers (FATE) also supports the following bitwise operations:
|
||||||
|
- bitwise and (`x band y`)
|
||||||
|
- bitwise or (`x bor y`)
|
||||||
|
- bitwise xor (`x bxor y`)
|
||||||
|
- bitwise not (`bnot x`)
|
||||||
|
- arithmetic bitshift left (`x << n`)
|
||||||
|
- arithmetic bitshift right (`x >> n`)
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
Sophia integers do not support bit arithmetic. Instead there is a separate
|
Originally Sophia integers did not support bit arithmetic. Instead we used a
|
||||||
type `bits`. See the standard library [documentation](sophia_stdlib.md#bits).
|
separate type `bits` (see the standard library
|
||||||
|
[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).
|
||||||
@@ -896,16 +960,18 @@ functions are provided.
|
|||||||
|
|
||||||
## AENS interface
|
## AENS interface
|
||||||
|
|
||||||
Contracts can interact with the
|
Contracts can interact with the [æternity naming
|
||||||
[æternity naming system](https://github.com/aeternity/protocol/blob/master/AENS.md).
|
system](https://github.com/aeternity/protocol/blob/master/AENS.md). For this
|
||||||
For this purpose the [AENS](sophia_stdlib.md#aens) library was exposed.
|
purpose the [AENS](sophia_stdlib.md#aens) and later the
|
||||||
|
[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
|
`name` the account holder needs to create a [delegation
|
||||||
[signature](#delegation-signature) `sig` of `addr | name.hash | ct.address`.
|
signature](#delegation-signature) `sig` from the name owner address `addr`, the
|
||||||
|
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:
|
||||||
@@ -1047,8 +1113,34 @@ however is in the gas consumption — while `abort` returns unused gas, a call t
|
|||||||
|
|
||||||
## Delegation signature
|
## Delegation signature
|
||||||
|
|
||||||
Some chain operations (`Oracle.<operation>` and `AENS.<operation>`) have an
|
Some chain operations (`Oracle.<operation>` and `AENSv2.<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. The exact data to be
|
would like to allow a contract to act on it's behalf.
|
||||||
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.).
|
### From Ceres
|
||||||
|
|
||||||
|
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`
|
||||||
|
|||||||
+253
-164
@@ -14,6 +14,7 @@ The out-of-the-box namespaces are:
|
|||||||
|
|
||||||
- [Address](#address)
|
- [Address](#address)
|
||||||
- [AENS](#aens)
|
- [AENS](#aens)
|
||||||
|
- [AENSv2](#aensv2)
|
||||||
- [Auth](#auth)
|
- [Auth](#auth)
|
||||||
- [Bits](#bits)
|
- [Bits](#bits)
|
||||||
- [Bytes](#bytes)
|
- [Bytes](#bytes)
|
||||||
@@ -31,6 +32,7 @@ The following ones need to be included as regular files with `.aes` suffix, for
|
|||||||
include "List.aes"
|
include "List.aes"
|
||||||
```
|
```
|
||||||
|
|
||||||
|
- [AENSCompat](#aenscompat)
|
||||||
- [Bitwise](#bitwise)
|
- [Bitwise](#bitwise)
|
||||||
- [BLS12_381](#bls12_381)
|
- [BLS12_381](#bls12_381)
|
||||||
- [Func](#func)
|
- [Func](#func)
|
||||||
@@ -55,6 +57,12 @@ 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
|
||||||
```
|
```
|
||||||
@@ -90,13 +98,10 @@ Cast address to contract type C (where `C` is a contract)
|
|||||||
|
|
||||||
### AENS
|
### AENS
|
||||||
|
|
||||||
The following functionality is available for interacting with the æternity
|
The old AENS namespace, kept in the compiler to be able to interact with
|
||||||
naming system (AENS).
|
contracts from before Ceres, compiled using aesophia compiler version 7.x and
|
||||||
If `owner` is equal to `Contract.address` the signature `signature` is
|
earlier. Used in [AENSCompat](#aenscompat) when converting between old and new
|
||||||
ignored, and can be left out since it is a named argument. Otherwise we need
|
pointers.
|
||||||
a signature to prove that we are allowed to do AENS operations on behalf of
|
|
||||||
`owner`. The [signature is tied to a network id](https://github.com/aeternity/protocol/blob/iris/consensus/consensus.md#transaction-signature),
|
|
||||||
i.e. the signature material should be prefixed by the network id.
|
|
||||||
|
|
||||||
#### Types
|
#### Types
|
||||||
|
|
||||||
@@ -113,12 +118,41 @@ datatype pointee = AccountPt(address) | OraclePt(address)
|
|||||||
| ContractPt(address) | ChannelPt(address)
|
| ContractPt(address) | ChannelPt(address)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### AENSv2
|
||||||
|
|
||||||
|
Note: introduced in v8.0
|
||||||
|
|
||||||
|
The following functionality is available for interacting with the æternity
|
||||||
|
naming system (AENS). If `owner` is equal to `Contract.address` the signature
|
||||||
|
`signature` is ignored, and can be left out since it is a named argument.
|
||||||
|
Otherwise we need a signature to prove that we are allowed to do AENS
|
||||||
|
operations on behalf of `owner`. The [signature is tied to a network
|
||||||
|
id](https://github.com/aeternity/protocol/blob/iris/consensus/consensus.md#transaction-signature),
|
||||||
|
i.e. the signature material should be prefixed by the network id.
|
||||||
|
|
||||||
|
#### Types
|
||||||
|
|
||||||
|
##### name
|
||||||
|
```
|
||||||
|
datatype name = Name(address, Chain.ttl, map(string, AENSv2.pointee))
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
##### pointee
|
||||||
|
|
||||||
|
```
|
||||||
|
datatype pointee = AccountPt(address) | OraclePt(address)
|
||||||
|
| ContractPt(address) | ChannelPt(address) | DataPt(bytes())
|
||||||
|
```
|
||||||
|
|
||||||
|
Note: on-chain there is a maximum length enforced for `DataPt`, it is 1024 bytes.
|
||||||
|
Sophia itself does _not_ check for this.
|
||||||
|
|
||||||
#### Functions
|
#### Functions
|
||||||
|
|
||||||
##### resolve
|
##### resolve
|
||||||
```
|
```
|
||||||
AENS.resolve(name : string, key : string) : option('a)
|
AENSv2.resolve(name : string, key : string) : option('a)
|
||||||
```
|
```
|
||||||
|
|
||||||
Name resolution. Here `name` should be a registered name and `key` one of the attributes
|
Name resolution. Here `name` should be a registered name and `key` one of the attributes
|
||||||
@@ -129,74 +163,107 @@ type checked against this type at run time.
|
|||||||
|
|
||||||
##### lookup
|
##### lookup
|
||||||
```
|
```
|
||||||
AENS.lookup(name : string) : option(AENS.name)
|
AENSv2.lookup(name : string) : option(AENSv2.name)
|
||||||
```
|
```
|
||||||
|
|
||||||
If `name` is an active name `AENS.lookup` returns a name object.
|
If `name` is an active name `AENSv2.lookup` returns a name object.
|
||||||
The three arguments to `Name` are `owner`, `expiry` and a map of the
|
The three arguments to `Name` are `owner`, `expiry` and a map of the
|
||||||
`pointees` for the name. Note: the expiry of the name is always a fixed TTL.
|
`pointees` for the name. Note: the expiry of the name is always a fixed TTL.
|
||||||
For example:
|
For example:
|
||||||
```
|
```
|
||||||
let Some(Name(owner, FixedTTL(expiry), ptrs)) = AENS.lookup("example.chain")
|
let Some(AENSv2.Name(owner, FixedTTL(expiry), ptrs)) = AENSv2.lookup("example.chain")
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Note: Changed to produce `AENSv2.name` in v8.0 (Ceres protocol upgrade).
|
||||||
|
|
||||||
##### preclaim
|
##### preclaim
|
||||||
```
|
```
|
||||||
AENS.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 over
|
The [signature](./sophia_features.md#delegation-signature) should be a
|
||||||
`network id` + `owner address` + `Contract.address` (concatenated as byte arrays).
|
serialized structure containing `network id`, `owner address`, and
|
||||||
|
`Contract.address`.
|
||||||
|
|
||||||
|
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`, `Contract.address`.
|
||||||
|
|
||||||
|
|
||||||
##### claim
|
##### claim
|
||||||
```
|
```
|
||||||
AENS.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 over
|
The [signature](./sophia_features.md#delegation-signature) should be a
|
||||||
`network id` + `owner address` + `name_hash` + `Contract.address`
|
serialized structure containing `network id`, `owner address`, and
|
||||||
(concatenated as byte arrays)
|
`Contract.address`. Using the private key of `owner address` for signing.
|
||||||
using the private key of the `owner` account for signing.
|
|
||||||
|
From Ceres (i.e. FATE VM version 3) the
|
||||||
|
[signature](./sophia_features.md#delegation-signature) can also be generic
|
||||||
|
(allowing _all_, existing and future, names to be delegated with one
|
||||||
|
signature), i.e. containing `network id`, `owner address`, `name_hash`, and
|
||||||
|
`Contract.address`.
|
||||||
|
|
||||||
|
|
||||||
##### transfer
|
##### transfer
|
||||||
```
|
```
|
||||||
AENS.transfer(owner : address, new_owner : address, name : string, <signature : signature>) : unit
|
AENSv2.transfer(owner : address, new_owner : address, name : string, <signature : signature>) : unit
|
||||||
```
|
```
|
||||||
|
|
||||||
Transfers name to the new owner.
|
Transfers name to the new owner.
|
||||||
|
|
||||||
The [signature](./sophia_features.md#delegation-signature) should be over
|
The [signature](./sophia_features.md#delegation-signature) should be a
|
||||||
`network id` + `owner address` + `name_hash` + `Contract.address`
|
serialized structure containing `network id`, `owner address`, and
|
||||||
(concatenated as byte arrays)
|
`Contract.address`. Using the private key of `owner address` for signing.
|
||||||
using the private key of the `owner` account for signing.
|
|
||||||
|
From Ceres (i.e. FATE VM version 3) the
|
||||||
|
[signature](./sophia_features.md#delegation-signature) can also be generic
|
||||||
|
(allowing _all_, existing and future, names to be delegated with one
|
||||||
|
signature), i.e. containing `network id`, `owner address`, `name_hash`, and
|
||||||
|
`Contract.address`.
|
||||||
|
|
||||||
|
|
||||||
##### revoke
|
##### revoke
|
||||||
```
|
```
|
||||||
AENS.revoke(owner : address, name : string, <signature : signature>) : unit
|
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 over
|
The [signature](./sophia_features.md#delegation-signature) should be a
|
||||||
`network id` + `owner address` + `name_hash` + `Contract.address`
|
serialized structure containing `network id`, `owner address`, and
|
||||||
(concatenated as byte arrays)
|
`Contract.address`. Using the private key of `owner address` for signing.
|
||||||
using the private key of the `owner` account for signing.
|
|
||||||
|
From Ceres (i.e. FATE VM version 3) the
|
||||||
|
[signature](./sophia_features.md#delegation-signature) can also be generic
|
||||||
|
(allowing _all_, existing and future, names to be delegated with one
|
||||||
|
signature), i.e. containing `network id`, `owner address`, `name_hash`, and
|
||||||
|
`Contract.address`.
|
||||||
|
|
||||||
|
|
||||||
##### update
|
##### update
|
||||||
```
|
```
|
||||||
AENS.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 : map(string, AENS.pointee), <signature : signature>) : unit
|
new_ptrs : option(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
|
||||||
will not be updated, for example if `None` is passed as `expiry` the expiry
|
will not be updated, for example if `None` is passed as `expiry` the expiry
|
||||||
block of the name is not changed.
|
block of the name is not changed.
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
@@ -236,7 +303,10 @@ namespace Chain =
|
|||||||
Auth.tx_hash : option(hash)
|
Auth.tx_hash : option(hash)
|
||||||
```
|
```
|
||||||
|
|
||||||
Gets the transaction hash during authentication.
|
Gets the transaction hash during authentication. Note: `Auth.tx_hash`
|
||||||
|
computation differs between protocol versions (changed in Ceres!), see
|
||||||
|
[aeserialisation](https://github.com/aeternity/protocol/blob/master/serializations.md)
|
||||||
|
specification for details.
|
||||||
|
|
||||||
|
|
||||||
### Bits
|
### Bits
|
||||||
@@ -315,7 +385,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
|
||||||
```
|
```
|
||||||
@@ -323,7 +393,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
|
||||||
```
|
```
|
||||||
@@ -336,7 +406,8 @@ 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
|
Concatenates two byte arrays. If `m` and `n` are known at compile time, the
|
||||||
|
result can be used as a fixed size byte array, otherwise it has type `bytes()`.
|
||||||
|
|
||||||
|
|
||||||
#### split
|
#### split
|
||||||
@@ -346,6 +417,38 @@ 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
|
||||||
|
|
||||||
@@ -381,6 +484,12 @@ Call.gas_price : int
|
|||||||
|
|
||||||
The gas price of the current call.
|
The gas price of the current call.
|
||||||
|
|
||||||
|
#### mulmod
|
||||||
|
```
|
||||||
|
Int.mulmod : (a : int, b : int, q : int) : int
|
||||||
|
```
|
||||||
|
|
||||||
|
Combined multiplication and modulus, returns `(a * b) mod q`.
|
||||||
|
|
||||||
#### fee
|
#### fee
|
||||||
```
|
```
|
||||||
@@ -469,39 +578,6 @@ 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).
|
||||||
|
|
||||||
|
|
||||||
##### coinbase
|
|
||||||
```
|
|
||||||
Chain.coinbase : address
|
|
||||||
```
|
|
||||||
|
|
||||||
The address of the account that mined the current block.
|
|
||||||
|
|
||||||
|
|
||||||
##### timestamp
|
|
||||||
```
|
|
||||||
Chain.timestamp : int
|
|
||||||
```
|
|
||||||
|
|
||||||
The timestamp of the current block (unix time, milliseconds).
|
|
||||||
|
|
||||||
|
|
||||||
##### 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)
|
||||||
@@ -538,7 +614,6 @@ charging the calling contract. Note that this won't be visible in `Call.value`
|
|||||||
in the `init` call of the new contract. It will be included in
|
in the `init` call of the new contract. It will be included in
|
||||||
`Contract.balance`, however.
|
`Contract.balance`, however.
|
||||||
|
|
||||||
|
|
||||||
The type `'c` must be instantiated with a contract.
|
The type `'c` must be instantiated with a contract.
|
||||||
|
|
||||||
|
|
||||||
@@ -565,6 +640,7 @@ 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, ...
|
||||||
@@ -603,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) => ()
|
stateful payable entrypoint buy : (int) => unit
|
||||||
stateful entrypoint sell : (int) => ()
|
stateful entrypoint sell : (int) => unit
|
||||||
|
|
||||||
main contract Market =
|
main contract Market =
|
||||||
type state = list(Auction)
|
type state = list(Auction)
|
||||||
@@ -623,11 +699,71 @@ 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
|
||||||
@@ -705,11 +841,14 @@ Hash any object to blake2b
|
|||||||
|
|
||||||
#### verify_sig
|
#### verify_sig
|
||||||
```
|
```
|
||||||
Crypto.verify_sig(msg : hash, pubkey : address, sig : signature) : bool
|
Crypto.verify_sig(msg : bytes(), 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
|
||||||
```
|
```
|
||||||
@@ -742,12 +881,21 @@ Verifies a standard 64-byte ECDSA signature (`R || S`).
|
|||||||
|
|
||||||
### Int
|
### Int
|
||||||
|
|
||||||
#### to_str
|
#### to\_str
|
||||||
```
|
```
|
||||||
Int.to_str : int => string
|
Int.to_str(n : int) : string
|
||||||
```
|
```
|
||||||
|
|
||||||
Casts integer to string using decimal representation
|
Casts the integer to a string (in 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
|
||||||
@@ -806,11 +954,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).
|
||||||
* `signature` is a signature proving that the contract is allowed to register the account -
|
* The [signature](./sophia_features.md#delegation-signature) should be a
|
||||||
the `network id` + `account address` + `contract address` (concatenated as byte arrays) is
|
serialized structure containing `network id`, `account address`, and
|
||||||
[signed](./sophia_features.md#delegation-signature) with the
|
`contract address`. Using the private key of `account address` for signing.
|
||||||
private key of the account, proving you have the private key of the oracle to be. If the
|
Proving you have the private key of the oracle to be. If the address is the same
|
||||||
address is the same as the contract `sign` is ignored and can be left out entirely.
|
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)`).
|
||||||
@@ -824,7 +972,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
|
||||||
```
|
```
|
||||||
@@ -837,12 +985,11 @@ 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`.
|
Responds to the question `q` on `o`. Unless the contract address is the same
|
||||||
Unless the contract address is the same as the oracle address the `signature`
|
as the oracle address the `signature` (which is an optional, named argument)
|
||||||
(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)
|
[signing](./sophia_features.md#delegation-signature) should be a serialized
|
||||||
the `network id` + `oracle query id` + `contract address`
|
structure containing `network id`, `oracle query id`, and `contract address`.
|
||||||
|
|
||||||
|
|
||||||
#### extend
|
#### extend
|
||||||
@@ -855,7 +1002,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
|
||||||
```
|
```
|
||||||
@@ -876,7 +1023,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)
|
||||||
```
|
```
|
||||||
@@ -914,88 +1061,21 @@ It returns `true` iff the oracle query exist and has the expected type.
|
|||||||
These need to be explicitly included (with `.aes` suffix)
|
These need to be explicitly included (with `.aes` suffix)
|
||||||
|
|
||||||
|
|
||||||
### Bitwise
|
### AENSCompat
|
||||||
|
|
||||||
Bitwise operations on arbitrary precision integers.
|
#### pointee\_to\_V2
|
||||||
|
|
||||||
#### bsr
|
|
||||||
```
|
```
|
||||||
Bitwise.bsr(n : int, x : int) : int
|
AENSCompat.pointee_to_V2(p : AENS.pointee) : AENSv2.pointee
|
||||||
```
|
```
|
||||||
|
|
||||||
Logical bit shift `x` right `n` positions.
|
Translate old pointee format to new, this is always possible.
|
||||||
|
|
||||||
|
#### pointee\_from\_V2
|
||||||
#### bsl
|
|
||||||
```
|
```
|
||||||
Bitwise.bsl(n : int, x : int) : int
|
AENSCompat.pointee_from_V2(p2 : AENSv2.pointee) : option(AENS.pointee)
|
||||||
```
|
```
|
||||||
|
|
||||||
Logical bit shift `x` left `n` positions.
|
Translate new pointee format to old, `DataPt` can't be translated, so `None` is returned in this case.
|
||||||
|
|
||||||
|
|
||||||
#### bsli
|
|
||||||
```
|
|
||||||
Bitwise.bsli(n : int, x : int, lim : int) : int
|
|
||||||
```
|
|
||||||
|
|
||||||
Logical bit shift `x` left `n` positions, limit to `lim` bits.
|
|
||||||
|
|
||||||
|
|
||||||
#### band
|
|
||||||
```
|
|
||||||
Bitwise.band(x : int, y : int) : int
|
|
||||||
```
|
|
||||||
|
|
||||||
Bitwise `and` of `x` and `y`.
|
|
||||||
|
|
||||||
|
|
||||||
#### bor
|
|
||||||
```
|
|
||||||
Bitwise.bor(x : int, y : int) : int
|
|
||||||
```
|
|
||||||
|
|
||||||
Bitwise `or` of `x` and `y`.
|
|
||||||
|
|
||||||
|
|
||||||
#### bxor
|
|
||||||
```
|
|
||||||
Bitwise.bxor(x : int, y : int) : int
|
|
||||||
```
|
|
||||||
|
|
||||||
Bitwise `xor` of `x` and `y`.
|
|
||||||
|
|
||||||
|
|
||||||
#### bnot
|
|
||||||
```
|
|
||||||
Bitwise.bnot(x : int) : int
|
|
||||||
```
|
|
||||||
|
|
||||||
Bitwise `not` of `x`. Defined and implemented as `bnot(x) = bxor(x, -1)`.
|
|
||||||
|
|
||||||
|
|
||||||
#### uband
|
|
||||||
```
|
|
||||||
Bitwise.uband(x : int, y : int) : int
|
|
||||||
```
|
|
||||||
|
|
||||||
Bitwise `and` of _non-negative_ numbers `x` and `y`.
|
|
||||||
|
|
||||||
|
|
||||||
#### ubor
|
|
||||||
```
|
|
||||||
Bitwise.ubor(x : int, y : int) : int
|
|
||||||
```
|
|
||||||
|
|
||||||
Bitwise `or` of _non-negative_ `x` and `y`.
|
|
||||||
|
|
||||||
|
|
||||||
#### ubxor
|
|
||||||
```
|
|
||||||
Bitwise.ubxor(x : int, y : int) : int
|
|
||||||
```
|
|
||||||
|
|
||||||
Bitwise `xor` of _non-negative_ `x` and `y`.
|
|
||||||
|
|
||||||
|
|
||||||
### BLS12\_381
|
### BLS12\_381
|
||||||
@@ -2391,6 +2471,15 @@ 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
|
||||||
|
|||||||
+15
-7
@@ -30,6 +30,7 @@ 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
|
||||||
|
|
||||||
@@ -104,6 +105,7 @@ 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
|
||||||
|
|
||||||
@@ -238,6 +240,7 @@ 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 + ???
|
| '???' // Hole expression 1 + ???
|
||||||
|
|
||||||
Generator ::= Pattern '<-' Expr // Generator
|
Generator ::= Pattern '<-' Expr // Generator
|
||||||
@@ -255,8 +258,8 @@ Path ::= Id // Record field
|
|||||||
|
|
||||||
BinOp ::= '||' | '&&' | '<' | '>' | '=<' | '>=' | '==' | '!='
|
BinOp ::= '||' | '&&' | '<' | '>' | '=<' | '>=' | '==' | '!='
|
||||||
| '::' | '++' | '+' | '-' | '*' | '/' | 'mod' | '^'
|
| '::' | '++' | '+' | '-' | '*' | '/' | 'mod' | '^'
|
||||||
| '|>'
|
| 'band' | 'bor' | 'bxor' | '<<' | '>>' | '|>'
|
||||||
UnOp ::= '-' | '!'
|
UnOp ::= '-' | '!' | 'bnot'
|
||||||
```
|
```
|
||||||
|
|
||||||
## Operators types
|
## Operators types
|
||||||
@@ -264,10 +267,11 @@ UnOp ::= '-' | '!'
|
|||||||
| Operators | Type
|
| Operators | Type
|
||||||
| --- | ---
|
| --- | ---
|
||||||
| `-` `+` `*` `/` `mod` `^` | arithmetic operators
|
| `-` `+` `*` `/` `mod` `^` | arithmetic operators
|
||||||
| `!` `&&` `||` | logical operators
|
| `!` `&&` `\|\|` | logical operators
|
||||||
|
| `band` `bor` `bxor` `bnot` `<<` `>>` | bitwise operators
|
||||||
| `==` `!=` `<` `>` `=<` `>=` | comparison operators
|
| `==` `!=` `<` `>` `=<` `>=` | comparison operators
|
||||||
| `::` `++` | list operators
|
| `::` `++` | list operators
|
||||||
| `|>` | functional operators
|
| `\|>` | functional operators
|
||||||
|
|
||||||
## Operator precedence
|
## Operator precedence
|
||||||
|
|
||||||
@@ -275,13 +279,17 @@ In order of highest to lowest precedence.
|
|||||||
|
|
||||||
| Operators | Associativity
|
| Operators | Associativity
|
||||||
| --- | ---
|
| --- | ---
|
||||||
| `!` | right
|
| `!` `bnot`| right
|
||||||
| `^` | left
|
| `^` | left
|
||||||
| `*` `/` `mod` | left
|
| `*` `/` `mod` | left
|
||||||
| `-` (unary) | right
|
| `-` (unary) | right
|
||||||
| `+` `-` | left
|
| `+` `-` | left
|
||||||
|
| `<<` `>>` | left
|
||||||
| `::` `++` | right
|
| `::` `++` | right
|
||||||
| `<` `>` `=<` `>=` `==` `!=` | none
|
| `<` `>` `=<` `>=` `==` `!=` | none
|
||||||
|
| `band` | left
|
||||||
|
| `bxor` | left
|
||||||
|
| `bor` | left
|
||||||
| `&&` | right
|
| `&&` | right
|
||||||
| `||` | right
|
| `\|\|` | right
|
||||||
| `|>` | left
|
| `\|>` | left
|
||||||
|
|||||||
@@ -0,0 +1,17 @@
|
|||||||
|
namespace AENSCompat =
|
||||||
|
// Translate old format to new format - always possible
|
||||||
|
function pointee_to_V2(p : AENS.pointee) : AENSv2.pointee =
|
||||||
|
switch(p)
|
||||||
|
AENS.AccountPt(a) => AENSv2.AccountPt(a)
|
||||||
|
AENS.OraclePt(a) => AENSv2.OraclePt(a)
|
||||||
|
AENS.ContractPt(a) => AENSv2.ContractPt(a)
|
||||||
|
AENS.ChannelPt(a) => AENSv2.ChannelPt(a)
|
||||||
|
|
||||||
|
// Translate new format to old format - option type!
|
||||||
|
function pointee_from_V2(p2 : AENSv2.pointee) : option(AENS.pointee) =
|
||||||
|
switch(p2)
|
||||||
|
AENSv2.AccountPt(a) => Some(AENS.AccountPt(a))
|
||||||
|
AENSv2.OraclePt(a) => Some(AENS.OraclePt(a))
|
||||||
|
AENSv2.ContractPt(a) => Some(AENS.ContractPt(a))
|
||||||
|
AENSv2.ChannelPt(a) => Some(AENS.ChannelPt(a))
|
||||||
|
AENSv2.DataPt(_) => None
|
||||||
@@ -1,126 +0,0 @@
|
|||||||
@compiler >= 4.3
|
|
||||||
|
|
||||||
namespace Bitwise =
|
|
||||||
|
|
||||||
// bit shift 'x' right 'n' postions
|
|
||||||
function bsr(n : int, x : int) : int =
|
|
||||||
let step = 2^n
|
|
||||||
let res = x / step
|
|
||||||
if (x >= 0 || x mod step == 0)
|
|
||||||
res
|
|
||||||
else
|
|
||||||
res - 1
|
|
||||||
|
|
||||||
// bit shift 'x' left 'n' positions
|
|
||||||
function bsl(n : int, x : int) : int =
|
|
||||||
x * 2^n
|
|
||||||
|
|
||||||
// bit shift 'x' left 'n' positions, limit at 'lim' bits
|
|
||||||
function bsli(n : int, x : int, lim : int) : int =
|
|
||||||
(x * 2^n) mod (2^lim)
|
|
||||||
|
|
||||||
// bitwise 'and' for arbitrary precision integers
|
|
||||||
function band(a : int, b : int) : int =
|
|
||||||
if (a >= 0 && b >= 0)
|
|
||||||
uband_(a, b)
|
|
||||||
elif (b >= 0)
|
|
||||||
ubnand_(b, -1 - a)
|
|
||||||
elif (a >= 0)
|
|
||||||
ubnand_(a, -1 - b)
|
|
||||||
else
|
|
||||||
-1 - ubor_(-1 - a, -1 - b)
|
|
||||||
|
|
||||||
// bitwise 'or' for arbitrary precision integers
|
|
||||||
function
|
|
||||||
bor : (int, int) => int
|
|
||||||
bor(0, b) = b
|
|
||||||
bor(a, 0) = a
|
|
||||||
bor(a : int, b : int) : int =
|
|
||||||
if (a >= 0 && b >= 0)
|
|
||||||
ubor_(a, b)
|
|
||||||
elif (b >= 0)
|
|
||||||
-1 - ubnand_(-1 - a, b)
|
|
||||||
elif (a >= 0)
|
|
||||||
-1 - ubnand_(-1 - b, a)
|
|
||||||
else
|
|
||||||
-1 - uband_(-1 - a, -1 - b)
|
|
||||||
|
|
||||||
// bitwise 'xor' for arbitrary precision integers
|
|
||||||
function
|
|
||||||
bxor : (int, int) => int
|
|
||||||
bxor(0, b) = b
|
|
||||||
bxor(a, 0) = a
|
|
||||||
bxor(a, b) =
|
|
||||||
if (a >= 0 && b >= 0)
|
|
||||||
ubxor_(a, b)
|
|
||||||
elif (b >= 0)
|
|
||||||
-1 - ubxor_(-1 - a, b)
|
|
||||||
elif (a >= 0)
|
|
||||||
-1 - ubxor_(a, -1 - b)
|
|
||||||
else
|
|
||||||
ubxor_(-1 - a, -1 - b)
|
|
||||||
|
|
||||||
// bitwise 'not' for arbitrary precision integers
|
|
||||||
function bnot(a : int) = bxor(a, -1)
|
|
||||||
|
|
||||||
// Bitwise 'and' for non-negative integers
|
|
||||||
function uband(a : int, b : int) : int =
|
|
||||||
require(a >= 0 && b >= 0, "uband is only defined for non-negative integers")
|
|
||||||
switch((a, b))
|
|
||||||
(0, _) => 0
|
|
||||||
(_, 0) => 0
|
|
||||||
_ => uband__(a, b, 1, 0)
|
|
||||||
|
|
||||||
private function uband_(a, b) = uband__(a, b, 1, 0)
|
|
||||||
|
|
||||||
private function
|
|
||||||
uband__(0, b, val, acc) = acc
|
|
||||||
uband__(a, 0, val, acc) = acc
|
|
||||||
uband__(a, b, val, acc) =
|
|
||||||
switch (a mod 2 + b mod 2)
|
|
||||||
2 => uband__(a / 2, b / 2, val * 2, acc + val)
|
|
||||||
_ => uband__(a / 2, b / 2, val * 2, acc)
|
|
||||||
|
|
||||||
// Bitwise 'or' for non-negative integers
|
|
||||||
function ubor(a, b) =
|
|
||||||
require(a >= 0 && b >= 0, "ubor is only defined for non-negative integers")
|
|
||||||
switch((a, b))
|
|
||||||
(0, _) => b
|
|
||||||
(_, 0) => a
|
|
||||||
_ => ubor__(a, b, 1, 0)
|
|
||||||
|
|
||||||
private function ubor_(a, b) = ubor__(a, b, 1, 0)
|
|
||||||
|
|
||||||
private function
|
|
||||||
ubor__(0, 0, val, acc) = acc
|
|
||||||
ubor__(a, b, val, acc) =
|
|
||||||
switch (a mod 2 + b mod 2)
|
|
||||||
0 => ubor__(a / 2, b / 2, val * 2, acc)
|
|
||||||
_ => ubor__(a / 2, b / 2, val * 2, acc + val)
|
|
||||||
|
|
||||||
//Bitwise 'xor' for non-negative integers
|
|
||||||
function
|
|
||||||
ubxor : (int, int) => int
|
|
||||||
ubxor(0, b) = b
|
|
||||||
ubxor(a, 0) = a
|
|
||||||
ubxor(a, b) =
|
|
||||||
require(a >= 0 && b >= 0, "ubxor is only defined for non-negative integers")
|
|
||||||
ubxor__(a, b, 1, 0)
|
|
||||||
|
|
||||||
private function ubxor_(a, b) = ubxor__(a, b, 1, 0)
|
|
||||||
|
|
||||||
private function
|
|
||||||
ubxor__(0, 0, val, acc) = acc
|
|
||||||
ubxor__(a, b, val, acc) =
|
|
||||||
switch(a mod 2 + b mod 2)
|
|
||||||
1 => ubxor__(a / 2, b / 2, val * 2, acc + val)
|
|
||||||
_ => ubxor__(a / 2, b / 2, val * 2, acc)
|
|
||||||
|
|
||||||
private function ubnand_(a, b) = ubnand__(a, b, 1, 0)
|
|
||||||
|
|
||||||
private function
|
|
||||||
ubnand__(0, b, val, acc) = acc
|
|
||||||
ubnand__(a, b, val, acc) =
|
|
||||||
switch((a mod 2, b mod 2))
|
|
||||||
(1, 0) => ubnand__(a / 2, b / 2, val * 2, acc + val)
|
|
||||||
_ => ubnand__(a / 2, b / 2, val * 2, acc)
|
|
||||||
@@ -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)) List.reverse(x::acc) :: monotonic_subs(lt, h::t)
|
if(lt(h, x)) 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, []) = [List.reverse(x::acc)]
|
asc(_, x, acc, []) = [reverse(x::acc)]
|
||||||
|
|
||||||
/** Merges list of sorted lists
|
/** Merges list of sorted lists
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
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.
|
||||||
|
|||||||
+3
-4
@@ -2,8 +2,7 @@
|
|||||||
|
|
||||||
{erl_opts, [debug_info]}.
|
{erl_opts, [debug_info]}.
|
||||||
|
|
||||||
{deps, [ {aebytecode, {git, "https://github.com/aeternity/aebytecode.git", {tag, "v3.2.0"}}}
|
{deps, [ {aebytecode, {git, "https://github.com/aeternity/aebytecode.git", {tag, "v3.4.1"}}}
|
||||||
, {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"}}}
|
||||||
]}.
|
]}.
|
||||||
@@ -14,8 +13,8 @@
|
|||||||
{base_plt_apps, [erts, kernel, stdlib, crypto, mnesia]}
|
{base_plt_apps, [erts, kernel, stdlib, crypto, mnesia]}
|
||||||
]}.
|
]}.
|
||||||
|
|
||||||
{relx, [{release, {aesophia, "7.1.0"},
|
{relx, [{release, {aesophia, "8.0.1"},
|
||||||
[aesophia, aebytecode, getopt]},
|
[aesophia, aebytecode]},
|
||||||
|
|
||||||
{dev_mode, true},
|
{dev_mode, true},
|
||||||
{include_erts, false},
|
{include_erts, false},
|
||||||
|
|||||||
+4
-4
@@ -1,11 +1,11 @@
|
|||||||
{"1.2.0",
|
{"1.2.0",
|
||||||
[{<<"aebytecode">>,
|
[{<<"aebytecode">>,
|
||||||
{git,"https://github.com/aeternity/aebytecode.git",
|
{git,"https://github.com/aeternity/aebytecode.git",
|
||||||
{ref,"2a0a397afad6b45da52572170f718194018bf33c"}},
|
{ref,"6bd6f82c70d800950ea1a2c70c364a4181ff5291"}},
|
||||||
0},
|
0},
|
||||||
{<<"aeserialization">>,
|
{<<"aeserialization">>,
|
||||||
{git,"https://github.com/aeternity/aeserialization.git",
|
{git,"https://github.com/aeternity/aeserialization.git",
|
||||||
{ref,"eb68fe331bd476910394966b7f5ede7a74d37e35"}},
|
{ref,"b26e6d105424748ba1c27917267b7cff07f37802"}},
|
||||||
1},
|
1},
|
||||||
{<<"base58">>,
|
{<<"base58">>,
|
||||||
{git,"https://github.com/aeternity/erl-base58.git",
|
{git,"https://github.com/aeternity/erl-base58.git",
|
||||||
@@ -14,9 +14,9 @@
|
|||||||
{<<"eblake2">>,{pkg,<<"eblake2">>,<<"1.0.0">>},0},
|
{<<"eblake2">>,{pkg,<<"eblake2">>,<<"1.0.0">>},0},
|
||||||
{<<"enacl">>,
|
{<<"enacl">>,
|
||||||
{git,"https://github.com/aeternity/enacl.git",
|
{git,"https://github.com/aeternity/enacl.git",
|
||||||
{ref,"793ddb502f7fe081302e1c42227dca70b09f8e17"}},
|
{ref,"4eb7ec70084ba7c87b1af8797c4c4e90c84f95a2"}},
|
||||||
2},
|
2},
|
||||||
{<<"getopt">>,{pkg,<<"getopt">>,<<"1.0.1">>},0},
|
{<<"getopt">>,{pkg,<<"getopt">>,<<"1.0.1">>},1},
|
||||||
{<<"jsx">>,
|
{<<"jsx">>,
|
||||||
{git,"https://github.com/talentdeficit/jsx.git",
|
{git,"https://github.com/talentdeficit/jsx.git",
|
||||||
{ref,"3074d4865b3385a050badf7828ad31490d860df5"}},
|
{ref,"3074d4865b3385a050badf7828ad31490d860df5"}},
|
||||||
|
|||||||
+36
-7
@@ -8,6 +8,7 @@
|
|||||||
%%%-------------------------------------------------------------------
|
%%%-------------------------------------------------------------------
|
||||||
|
|
||||||
-module(aeso_aci).
|
-module(aeso_aci).
|
||||||
|
-vsn("8.0.1").
|
||||||
|
|
||||||
-export([ file/2
|
-export([ file/2
|
||||||
, file/3
|
, file/3
|
||||||
@@ -198,7 +199,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);
|
aeser_api_encoder:encode(Lit, L);
|
||||||
encode_expr({app, _, {'-', _}, [{int, _, N}]}) ->
|
encode_expr({app, _, {'-', _}, [{int, _, N}]}) ->
|
||||||
encode_expr({int, [], -N});
|
encode_expr({int, [], -N});
|
||||||
@@ -221,16 +223,41 @@ do_render_aci_json(Json) ->
|
|||||||
case Json of
|
case Json of
|
||||||
JArray when is_list(JArray) -> JArray;
|
JArray when is_list(JArray) -> JArray;
|
||||||
JObject when is_map(JObject) -> [JObject];
|
JObject when is_map(JObject) -> [JObject];
|
||||||
JText when is_binary(JText) ->
|
JText when is_binary(JText) -> decode(JText)
|
||||||
case jsx:decode(Json, [{labels, atom}, return_maps]) of
|
|
||||||
JArray when is_list(JArray) -> JArray;
|
|
||||||
JObject when is_map(JObject) -> [JObject];
|
|
||||||
_ -> error(bad_aci_json)
|
|
||||||
end
|
|
||||||
end,
|
end,
|
||||||
DecodedContracts = [ decode_contract(C) || C <- Contracts ],
|
DecodedContracts = [ decode_contract(C) || C <- Contracts ],
|
||||||
{ok, list_to_binary(string:join(DecodedContracts, "\n"))}.
|
{ok, list_to_binary(string:join(DecodedContracts, "\n"))}.
|
||||||
|
|
||||||
|
|
||||||
|
decode(JSON) ->
|
||||||
|
case code:is_loaded(jsx) of
|
||||||
|
{file, _} ->
|
||||||
|
case jsx:decode(JSON, [{labels, atom}, return_maps]) of
|
||||||
|
JArray when is_list(JArray) -> JArray;
|
||||||
|
JObject when is_map(JObject) -> [JObject];
|
||||||
|
_ -> error(bad_aci_json)
|
||||||
|
end;
|
||||||
|
false ->
|
||||||
|
case zj:binary_decode(JSON) of
|
||||||
|
{ok, Decoded} when is_list(Decoded) -> atomize(Decoded);
|
||||||
|
{ok, Decoded} when is_map(Decoded) -> [atomize(Decoded)];
|
||||||
|
_ -> error(bad_aci_json)
|
||||||
|
end
|
||||||
|
end.
|
||||||
|
|
||||||
|
atomize(T) when is_map(T) ->
|
||||||
|
maps:fold(fun atomize/3, #{}, T);
|
||||||
|
atomize(T) when is_list(T) ->
|
||||||
|
lists:map(fun atomize/1, T);
|
||||||
|
atomize(T) ->
|
||||||
|
T.
|
||||||
|
|
||||||
|
atomize(K, V, M) when is_binary(K) ->
|
||||||
|
maps:put(binary_to_atom(K), atomize(V), M);
|
||||||
|
atomize(K, V, M) ->
|
||||||
|
maps:put(K, V, M).
|
||||||
|
|
||||||
|
|
||||||
decode_contract(#{contract := #{name := Name,
|
decode_contract(#{contract := #{name := Name,
|
||||||
kind := Kind,
|
kind := Kind,
|
||||||
payable := Payable,
|
payable := Payable,
|
||||||
@@ -282,6 +309,8 @@ 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}) ->
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
-module(aeso_ast).
|
-module(aeso_ast).
|
||||||
|
-vsn("8.0.1").
|
||||||
|
|
||||||
-export([int/2,
|
-export([int/2,
|
||||||
line/1,
|
line/1,
|
||||||
|
|||||||
+544
-243
File diff suppressed because it is too large
Load Diff
+768
-504
File diff suppressed because it is too large
Load Diff
+94
-40
@@ -7,11 +7,14 @@
|
|||||||
%%% Created : 12 Dec 2017
|
%%% Created : 12 Dec 2017
|
||||||
%%%-------------------------------------------------------------------
|
%%%-------------------------------------------------------------------
|
||||||
-module(aeso_compiler).
|
-module(aeso_compiler).
|
||||||
|
-vsn("8.0.1").
|
||||||
|
|
||||||
-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
|
||||||
@@ -25,7 +28,7 @@
|
|||||||
, validate_byte_code/3
|
, validate_byte_code/3
|
||||||
]).
|
]).
|
||||||
|
|
||||||
-include_lib("aebytecode/include/aeb_opcodes.hrl").
|
-include("$aebytecode_include/aeb_opcodes.hrl").
|
||||||
-include("aeso_utils.hrl").
|
-include("aeso_utils.hrl").
|
||||||
|
|
||||||
|
|
||||||
@@ -40,6 +43,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, aeso_aci:aci_type()}.
|
||||||
-type options() :: [option()].
|
-type options() :: [option()].
|
||||||
|
|
||||||
@@ -85,7 +89,9 @@ file(Filename) ->
|
|||||||
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} -> from_string(Bin, [{src_file, File} | Options]);
|
{ok, Bin} ->
|
||||||
|
SrcDir = aeso_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, [aeso_errors:new(file_error, Msg)]}
|
{error, [aeso_errors:new(file_error, Msg)]}
|
||||||
@@ -97,7 +103,7 @@ 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, Dir]}} | Options]
|
[{include, {file_system, [Cwd, aeso_utils:canonical_dir(Dir)]}} | Options]
|
||||||
end.
|
end.
|
||||||
|
|
||||||
-spec from_string(binary() | string(), options()) -> {ok, map()} | {error, [aeso_errors:error()]}.
|
-spec from_string(binary() | string(), options()) -> {ok, map()} | {error, [aeso_errors:error()]}.
|
||||||
@@ -117,7 +123,7 @@ 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, VarsRegs} = aeso_fcode_to_fate:compile(ChildContracts, FCode, SavedFreshNames, Options),
|
FateCode = aeso_fcode_to_fate:compile(ChildContracts, FCode, SavedFreshNames, Options),
|
||||||
pp_assembler(FateCode, Options),
|
pp_assembler(FateCode, Options),
|
||||||
ByteCode = aeb_fate_code:serialize(FateCode, []),
|
ByteCode = aeb_fate_code:serialize(FateCode, []),
|
||||||
{ok, Version} = version(),
|
{ok, Version} = version(),
|
||||||
@@ -130,13 +136,7 @@ from_string1(ContractString, Options) ->
|
|||||||
payable => maps:get(payable, FCode),
|
payable => maps:get(payable, FCode),
|
||||||
warnings => Warnings
|
warnings => Warnings
|
||||||
},
|
},
|
||||||
ResDbg = Res#{variables_registers => VarsRegs},
|
{ok, maybe_generate_aci(Res, FoldedTypedAst, Options)}.
|
||||||
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
|
||||||
@@ -188,30 +188,58 @@ 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, [ aeso_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(ContractString0, Options),
|
, ast := Ast} = string_to_code(Contract0, Options),
|
||||||
{FateCode, _} = aeso_fcode_to_fate:compile(ChildContracts, OrgFcode, #{}, []),
|
FateCode = aeso_fcode_to_fate:compile(ChildContracts, OrgFcode, #{}, []),
|
||||||
%% collect all hashes and compute the first name without hash collision to
|
%% collect all hashes and compute the first name without hash collision to
|
||||||
SymbolHashes = maps:keys(aeb_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)),
|
||||||
ContractString = insert_call_function(Ast, ContractString0, CallName, FunName, Args),
|
Contract = insert_call_function(Ast, Contract0, CallName, Call),
|
||||||
#{fcode := Fcode} = string_to_code(ContractString, Options),
|
{ok, CallName, string_to_code(Contract, 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.
|
||||||
|
|
||||||
arguments_of_body(CallName, _FunName, Fcode) ->
|
get_call_body(CallName, #{fcode := 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)),
|
||||||
{def, _FName, Args} = Body,
|
Body.
|
||||||
%% FName is either {entrypoint, list_to_binary(FunName)} or 'init'
|
|
||||||
[ aeso_fcode_to_fate:term_to_fate(A) || A <- Args ].
|
encode_value(Contract0, Type, Value, Options) ->
|
||||||
|
case add_extra_call(Contract0, {value, Type, Value}, Options) of
|
||||||
|
{ok, CallName, Code} ->
|
||||||
|
Body = get_call_body(CallName, Code),
|
||||||
|
{ok, aeb_fate_encoding:serialize(aeso_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 = aeso_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);
|
||||||
@@ -224,14 +252,31 @@ 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(aeso_syntax:ast(), string(), string(), string(), [string()]) -> string().
|
-spec insert_call_function(aeso_syntax:ast(), string(), string(),
|
||||||
insert_call_function(Ast, Code, Call, FunName, Args) ->
|
{call, string(), [string()]} | {value, string(), string()} | {type, string()}) -> string().
|
||||||
|
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().
|
||||||
@@ -270,26 +315,32 @@ 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),
|
||||||
#{ unfolded_typed_ast := TypedAst, type_env := TypeEnv} = Code,
|
#{ folded_typed_ast := TypedAst, type_env := TypeEnv} = Code,
|
||||||
{ok, _, Type0} = get_decode_type(FunName, TypedAst),
|
{ok, _, Type0} = get_decode_type(FunName, TypedAst),
|
||||||
Type = aeso_ast_infer_types:unfold_types_in_type(TypeEnv, Type0, [unfold_record_types, unfold_variant_types]),
|
Type = aeso_ast_infer_types:unfold_types_in_type(TypeEnv, Type0,
|
||||||
|
[ unfold_record_types
|
||||||
|
, unfold_variant_types
|
||||||
|
, not_unfold_system_alias_types]),
|
||||||
|
|
||||||
try
|
fate_data_to_sophia_value(Type0, Type, Data)
|
||||||
{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, aeso_vm_decode:from_fate(UnfoldedType, aeb_fate_encoding:deserialize(FateData))}
|
||||||
|
catch throw:cannot_translate_to_sophia ->
|
||||||
|
Type1 = prettypr:format(aeso_pretty:type(Type)),
|
||||||
|
Msg = io_lib:format("Cannot translate FATE value ~p\n of Sophia type ~s",
|
||||||
|
[aeb_fate_encoding:deserialize(FateData), Type1]),
|
||||||
|
{error, [aeso_errors:new(data_error, Msg)]};
|
||||||
|
_:_ ->
|
||||||
|
Type1 = prettypr:format(aeso_pretty:type(Type)),
|
||||||
|
Msg = io_lib:format("Failed to decode binary as type ~s", [Type1]),
|
||||||
|
{error, [aeso_errors:new(data_error, Msg)]}
|
||||||
|
end.
|
||||||
|
|
||||||
-spec create_calldata(string(), string(), [string()]) ->
|
-spec create_calldata(string(), string(), [string()]) ->
|
||||||
{ok, binary()} | {error, [aeso_errors:error()]}.
|
{ok, binary()} | {error, [aeso_errors:error()]}.
|
||||||
create_calldata(Code, Fun, Args) ->
|
create_calldata(Code, Fun, Args) ->
|
||||||
@@ -316,14 +367,17 @@ 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),
|
||||||
#{ unfolded_typed_ast := TypedAst, type_env := TypeEnv} = Code,
|
#{ folded_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 = aeso_ast_infer_types:unfold_types_in_type(TypeEnv, Type0, [unfold_record_types, unfold_variant_types]),
|
Type = aeso_ast_infer_types:unfold_types_in_type(TypeEnv, Type0,
|
||||||
|
[ unfold_record_types
|
||||||
|
, unfold_variant_types
|
||||||
|
, not_unfold_system_alias_types]),
|
||||||
case aeb_fate_abi:decode_calldata(FunName, Calldata) of
|
case aeb_fate_abi:decode_calldata(FunName, Calldata) of
|
||||||
{ok, FateArgs} ->
|
{ok, FateArgs} ->
|
||||||
try
|
try
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
%%%-------------------------------------------------------------------
|
%%%-------------------------------------------------------------------
|
||||||
|
|
||||||
-module(aeso_errors).
|
-module(aeso_errors).
|
||||||
|
-vsn("8.0.1").
|
||||||
|
|
||||||
-type src_file() :: no_file | iolist().
|
-type src_file() :: no_file | iolist().
|
||||||
|
|
||||||
|
|||||||
+222
-101
@@ -8,6 +8,7 @@
|
|||||||
%%%
|
%%%
|
||||||
%%%-------------------------------------------------------------------
|
%%%-------------------------------------------------------------------
|
||||||
-module(aeso_fcode_to_fate).
|
-module(aeso_fcode_to_fate).
|
||||||
|
-vsn("8.0.1").
|
||||||
|
|
||||||
-export([compile/3, compile/4, term_to_fate/1, term_to_fate/2]).
|
-export([compile/3, compile/4, term_to_fate/1, term_to_fate/2]).
|
||||||
|
|
||||||
@@ -52,7 +53,8 @@
|
|||||||
tailpos = true,
|
tailpos = true,
|
||||||
child_contracts = #{},
|
child_contracts = #{},
|
||||||
saved_fresh_names = #{},
|
saved_fresh_names = #{},
|
||||||
options = [] }).
|
options = [],
|
||||||
|
debug_info = false }).
|
||||||
|
|
||||||
%% -- Debugging --------------------------------------------------------------
|
%% -- Debugging --------------------------------------------------------------
|
||||||
|
|
||||||
@@ -81,24 +83,16 @@ code_error(Err) ->
|
|||||||
compile(FCode, SavedFreshNames, Options) ->
|
compile(FCode, SavedFreshNames, Options) ->
|
||||||
compile(#{}, FCode, SavedFreshNames, Options).
|
compile(#{}, FCode, SavedFreshNames, Options).
|
||||||
compile(ChildContracts, FCode, SavedFreshNames, Options) ->
|
compile(ChildContracts, FCode, SavedFreshNames, Options) ->
|
||||||
try
|
|
||||||
compile1(ChildContracts, FCode, SavedFreshNames, Options)
|
|
||||||
after
|
|
||||||
put(variables_registers, undefined)
|
|
||||||
end.
|
|
||||||
|
|
||||||
compile1(ChildContracts, FCode, SavedFreshNames, Options) ->
|
|
||||||
#{ contract_name := ContractName,
|
#{ contract_name := ContractName,
|
||||||
functions := Functions } = FCode,
|
functions := Functions } = FCode,
|
||||||
SFuns = functions_to_scode(ChildContracts, ContractName, Functions, SavedFreshNames, Options),
|
SFuns = functions_to_scode(ChildContracts, ContractName, Functions, SavedFreshNames, Options),
|
||||||
SFuns1 = optimize_scode(SFuns, Options),
|
SFuns1 = optimize_scode(SFuns, Options),
|
||||||
FateCode = to_basic_blocks(SFuns1),
|
FateCode = to_basic_blocks(SFuns1),
|
||||||
?debug(compile, Options, "~s\n", [aeb_fate_asm:pp(FateCode)]),
|
?debug(compile, Options, "~s\n", [aeb_fate_asm:pp(FateCode)]),
|
||||||
FateCode1 = case proplists:get_value(include_child_contract_symbols, Options, false) of
|
case proplists:get_value(include_child_contract_symbols, Options, false) of
|
||||||
false -> FateCode;
|
false -> FateCode;
|
||||||
true -> add_child_symbols(ChildContracts, FateCode)
|
true -> add_child_symbols(ChildContracts, FateCode)
|
||||||
end,
|
end.
|
||||||
{FateCode1, get_variables_registers()}.
|
|
||||||
|
|
||||||
make_function_id(X) ->
|
make_function_id(X) ->
|
||||||
aeb_fate_code:symbol_identifier(make_function_name(X)).
|
aeb_fate_code:symbol_identifier(make_function_name(X)).
|
||||||
@@ -123,31 +117,15 @@ functions_to_scode(ChildContracts, ContractName, Functions, SavedFreshNames, Opt
|
|||||||
|
|
||||||
function_to_scode(ChildContracts, ContractName, Functions, Name, Attrs0, Args, Body, ResType, SavedFreshNames, Options) ->
|
function_to_scode(ChildContracts, ContractName, Functions, Name, Attrs0, Args, Body, ResType, SavedFreshNames, Options) ->
|
||||||
{ArgTypes, ResType1} = typesig_to_scode(Args, ResType),
|
{ArgTypes, ResType1} = typesig_to_scode(Args, ResType),
|
||||||
Attrs = Attrs0 -- [stateful], %% Only track private and payable from here.
|
Attrs = [ A || A <- Attrs0, A == private orelse A == payable ],
|
||||||
Env = init_env(ChildContracts, ContractName, Functions, Name, Args, SavedFreshNames, Options),
|
Env = init_env(ChildContracts, ContractName, Functions, Name, Args, SavedFreshNames, Options),
|
||||||
[ add_variables_register(Env, Arg, Register) ||
|
ArgsNames = [ X || {X, _} <- lists:reverse(Env#env.vars) ],
|
||||||
proplists:get_value(debug_info, Options, false),
|
|
||||||
{Arg, Register} <- Env#env.vars ],
|
%% DBG_LOC is added before the function body to make it possible to break
|
||||||
|
%% at the function signature
|
||||||
SCode = to_scode(Env, Body),
|
SCode = to_scode(Env, Body),
|
||||||
{Attrs, {ArgTypes, ResType1}, SCode}.
|
DbgSCode = dbg_contract(Env) ++ dbg_loc(Env, Attrs0) ++ dbg_scoped_vars(Env, ArgsNames, SCode),
|
||||||
|
{Attrs, {ArgTypes, ResType1}, DbgSCode}.
|
||||||
get_variables_registers() ->
|
|
||||||
case get(variables_registers) of
|
|
||||||
undefined -> #{};
|
|
||||||
Vs -> Vs
|
|
||||||
end.
|
|
||||||
|
|
||||||
add_variables_register(Env = #env{saved_fresh_names = SavedFreshNames}, Name, Register) ->
|
|
||||||
Olds = get_variables_registers(),
|
|
||||||
RealName = maps:get(Name, SavedFreshNames, Name),
|
|
||||||
FunName =
|
|
||||||
case Env#env.current_function of
|
|
||||||
event -> "Chain.event";
|
|
||||||
{entrypoint, BinName} -> binary_to_list(BinName);
|
|
||||||
{local_fun, QualName} -> lists:last(QualName)
|
|
||||||
end,
|
|
||||||
New = {Env#env.contract, FunName, RealName},
|
|
||||||
put(variables_registers, Olds#{New => Register}).
|
|
||||||
|
|
||||||
-define(tvars, '$tvars').
|
-define(tvars, '$tvars').
|
||||||
|
|
||||||
@@ -201,13 +179,13 @@ init_env(ChildContracts, ContractName, FunNames, Name, Args, SavedFreshNames, Op
|
|||||||
current_function = Name,
|
current_function = Name,
|
||||||
options = Options,
|
options = Options,
|
||||||
tailpos = true,
|
tailpos = true,
|
||||||
saved_fresh_names = SavedFreshNames }.
|
saved_fresh_names = SavedFreshNames,
|
||||||
|
debug_info = proplists:get_value(debug_info, Options, false) }.
|
||||||
|
|
||||||
next_var(#env{ vars = Vars }) ->
|
next_var(#env{ vars = Vars }) ->
|
||||||
1 + lists:max([-1 | [J || {_, {var, J}} <- Vars]]).
|
1 + lists:max([-1 | [J || {_, {var, J}} <- Vars]]).
|
||||||
|
|
||||||
bind_var(Name, Var, Env = #env{ vars = Vars }) ->
|
bind_var(Name, Var, Env = #env{ vars = Vars }) ->
|
||||||
proplists:get_value(debug_info, Env#env.options, false) andalso add_variables_register(Env, Name, Var),
|
|
||||||
Env#env{ vars = [{Name, Var} | Vars] }.
|
Env#env{ vars = [{Name, Var} | Vars] }.
|
||||||
|
|
||||||
bind_local(Name, Env) ->
|
bind_local(Name, Env) ->
|
||||||
@@ -234,7 +212,7 @@ serialize_contract_code(Env, C) ->
|
|||||||
Options = Env#env.options,
|
Options = Env#env.options,
|
||||||
SavedFreshNames = Env#env.saved_fresh_names,
|
SavedFreshNames = Env#env.saved_fresh_names,
|
||||||
FCode = maps:get(C, Env#env.child_contracts),
|
FCode = maps:get(C, Env#env.child_contracts),
|
||||||
{FateCode, _} = compile1(Env#env.child_contracts, FCode, SavedFreshNames, Options),
|
FateCode = compile(Env#env.child_contracts, FCode, SavedFreshNames, Options),
|
||||||
ByteCode = aeb_fate_code:serialize(FateCode, []),
|
ByteCode = aeb_fate_code:serialize(FateCode, []),
|
||||||
{ok, Version} = aeso_compiler:version(),
|
{ok, Version} = aeso_compiler:version(),
|
||||||
OriginalSourceCode = proplists:get_value(original_src, Options, ""),
|
OriginalSourceCode = proplists:get_value(original_src, Options, ""),
|
||||||
@@ -258,6 +236,7 @@ lit_to_fate(Env, L) ->
|
|||||||
{bytes, B} -> aeb_fate_data:make_bytes(B);
|
{bytes, B} -> aeb_fate_data:make_bytes(B);
|
||||||
{bool, B} -> aeb_fate_data:make_boolean(B);
|
{bool, B} -> aeb_fate_data:make_boolean(B);
|
||||||
{account_pubkey, K} -> aeb_fate_data:make_address(K);
|
{account_pubkey, K} -> aeb_fate_data:make_address(K);
|
||||||
|
{signature, S} -> aeb_fate_data:make_bytes(S);
|
||||||
{contract_pubkey, K} -> aeb_fate_data:make_contract(K);
|
{contract_pubkey, K} -> aeb_fate_data:make_contract(K);
|
||||||
{oracle_pubkey, K} -> aeb_fate_data:make_oracle(K);
|
{oracle_pubkey, K} -> aeb_fate_data:make_oracle(K);
|
||||||
{oracle_query_id, H} -> aeb_fate_data:make_oracle_query(H);
|
{oracle_query_id, H} -> aeb_fate_data:make_oracle_query(H);
|
||||||
@@ -268,97 +247,106 @@ lit_to_fate(Env, L) ->
|
|||||||
term_to_fate(E) -> term_to_fate(#env{}, #{}, E).
|
term_to_fate(E) -> term_to_fate(#env{}, #{}, E).
|
||||||
term_to_fate(GlobEnv, E) -> term_to_fate(GlobEnv, #{}, E).
|
term_to_fate(GlobEnv, E) -> term_to_fate(GlobEnv, #{}, E).
|
||||||
|
|
||||||
term_to_fate(GlobEnv, _Env, {lit, L}) ->
|
term_to_fate(GlobEnv, _Env, {lit, _, L}) ->
|
||||||
lit_to_fate(GlobEnv, L);
|
lit_to_fate(GlobEnv, L);
|
||||||
%% negative literals are parsed as 0 - N
|
%% negative literals are parsed as 0 - N
|
||||||
term_to_fate(_GlobEnv, _Env, {op, '-', [{lit, {int, 0}}, {lit, {int, N}}]}) ->
|
term_to_fate(_GlobEnv, _Env, {op, _, '-', [{lit, _, {int, 0}}, {lit, _, {int, N}}]}) ->
|
||||||
aeb_fate_data:make_integer(-N);
|
aeb_fate_data:make_integer(-N);
|
||||||
term_to_fate(_GlobEnv, _Env, nil) ->
|
term_to_fate(_GlobEnv, _Env, {nil, _}) ->
|
||||||
aeb_fate_data:make_list([]);
|
aeb_fate_data:make_list([]);
|
||||||
term_to_fate(GlobEnv, Env, {op, '::', [Hd, Tl]}) ->
|
term_to_fate(GlobEnv, Env, {op, _, '::', [Hd, Tl]}) ->
|
||||||
%% The Tl will translate into a list, because FATE lists are just lists
|
%% The Tl will translate into a list, because FATE lists are just lists
|
||||||
[term_to_fate(GlobEnv, Env, Hd) | term_to_fate(GlobEnv, Env, Tl)];
|
[term_to_fate(GlobEnv, Env, Hd) | term_to_fate(GlobEnv, Env, Tl)];
|
||||||
term_to_fate(GlobEnv, Env, {tuple, As}) ->
|
term_to_fate(GlobEnv, Env, {tuple, _, As}) ->
|
||||||
aeb_fate_data:make_tuple(list_to_tuple([ term_to_fate(GlobEnv, Env, A) || A<-As]));
|
aeb_fate_data:make_tuple(list_to_tuple([ term_to_fate(GlobEnv, Env, A) || A<-As]));
|
||||||
term_to_fate(GlobEnv, Env, {con, Ar, I, As}) ->
|
term_to_fate(GlobEnv, Env, {con, _, Ar, I, As}) ->
|
||||||
FateAs = [ term_to_fate(GlobEnv, Env, A) || A <- As ],
|
FateAs = [ term_to_fate(GlobEnv, Env, A) || A <- As ],
|
||||||
aeb_fate_data:make_variant(Ar, I, list_to_tuple(FateAs));
|
aeb_fate_data:make_variant(Ar, I, list_to_tuple(FateAs));
|
||||||
term_to_fate(_GlobEnv, _Env, {builtin, bits_all, []}) ->
|
term_to_fate(_GlobEnv, _Env, {builtin, _, bits_all, []}) ->
|
||||||
aeb_fate_data:make_bits(-1);
|
aeb_fate_data:make_bits(-1);
|
||||||
term_to_fate(_GlobEnv, _Env, {builtin, bits_none, []}) ->
|
term_to_fate(_GlobEnv, _Env, {builtin, _, bits_none, []}) ->
|
||||||
aeb_fate_data:make_bits(0);
|
aeb_fate_data:make_bits(0);
|
||||||
term_to_fate(GlobEnv, _Env, {op, bits_set, [B, I]}) ->
|
term_to_fate(GlobEnv, _Env, {op, _, bits_set, [B, I]}) ->
|
||||||
{bits, N} = term_to_fate(GlobEnv, B),
|
{bits, N} = term_to_fate(GlobEnv, B),
|
||||||
J = term_to_fate(GlobEnv, I),
|
J = term_to_fate(GlobEnv, I),
|
||||||
{bits, N bor (1 bsl J)};
|
{bits, N bor (1 bsl J)};
|
||||||
term_to_fate(GlobEnv, _Env, {op, bits_clear, [B, I]}) ->
|
term_to_fate(GlobEnv, _Env, {op, _, bits_clear, [B, I]}) ->
|
||||||
{bits, N} = term_to_fate(GlobEnv, B),
|
{bits, N} = term_to_fate(GlobEnv, B),
|
||||||
J = term_to_fate(GlobEnv, I),
|
J = term_to_fate(GlobEnv, I),
|
||||||
{bits, N band bnot (1 bsl J)};
|
{bits, N band bnot (1 bsl J)};
|
||||||
term_to_fate(GlobEnv, Env, {'let', X, E, Body}) ->
|
term_to_fate(GlobEnv, Env, {'let', _, X, E, Body}) ->
|
||||||
Env1 = Env#{ X => term_to_fate(GlobEnv, Env, E) },
|
Env1 = Env#{ X => term_to_fate(GlobEnv, Env, E) },
|
||||||
term_to_fate(GlobEnv, Env1, Body);
|
term_to_fate(GlobEnv, Env1, Body);
|
||||||
term_to_fate(_GlobEnv, Env, {var, X}) ->
|
term_to_fate(_GlobEnv, Env, {var, _, X}) ->
|
||||||
case maps:get(X, Env, undefined) of
|
case maps:get(X, Env, undefined) of
|
||||||
undefined -> throw(not_a_fate_value);
|
undefined -> throw(not_a_fate_value);
|
||||||
V -> V
|
V -> V
|
||||||
end;
|
end;
|
||||||
term_to_fate(_GlobEnv, _Env, {builtin, map_empty, []}) ->
|
term_to_fate(_GlobEnv, _Env, {builtin, _, map_empty, []}) ->
|
||||||
aeb_fate_data:make_map(#{});
|
aeb_fate_data:make_map(#{});
|
||||||
term_to_fate(GlobEnv, Env, {op, map_set, [M, K, V]}) ->
|
term_to_fate(GlobEnv, Env, {op, _, map_set, [M, K, V]}) ->
|
||||||
Map = term_to_fate(GlobEnv, Env, M),
|
Map = term_to_fate(GlobEnv, Env, M),
|
||||||
Map#{term_to_fate(GlobEnv, Env, K) => term_to_fate(GlobEnv, Env, V)};
|
Map#{term_to_fate(GlobEnv, Env, K) => term_to_fate(GlobEnv, Env, V)};
|
||||||
|
term_to_fate(GlobEnv, Env, {builtin, _, bytes_to_any_size, [Bs]}) ->
|
||||||
|
term_to_fate(GlobEnv, Env, Bs);
|
||||||
term_to_fate(_GlobEnv, _Env, _) ->
|
term_to_fate(_GlobEnv, _Env, _) ->
|
||||||
throw(not_a_fate_value).
|
throw(not_a_fate_value).
|
||||||
|
|
||||||
to_scode(Env, T) ->
|
to_scode(Env, T) ->
|
||||||
try term_to_fate(Env, T) of
|
try term_to_fate(Env, T) of
|
||||||
V -> [push(?i(V))]
|
V ->
|
||||||
|
FAnn = element(2, T),
|
||||||
|
[dbg_loc(Env, FAnn), push(?i(V))]
|
||||||
catch throw:not_a_fate_value ->
|
catch throw:not_a_fate_value ->
|
||||||
to_scode1(Env, T)
|
to_scode1(Env, T)
|
||||||
end.
|
end.
|
||||||
|
|
||||||
to_scode1(Env, {lit, L}) ->
|
to_scode1(Env, {lit, Ann, L}) ->
|
||||||
[push(?i(lit_to_fate(Env, L)))];
|
[ dbg_loc(Env, Ann), push(?i(lit_to_fate(Env, L))) ];
|
||||||
|
|
||||||
to_scode1(_Env, nil) ->
|
to_scode1(Env, {nil, Ann}) ->
|
||||||
[aeb_fate_ops:nil(?a)];
|
[ dbg_loc(Env, Ann), aeb_fate_ops:nil(?a) ];
|
||||||
|
|
||||||
to_scode1(Env, {var, X}) ->
|
to_scode1(Env, {var, Ann, X}) ->
|
||||||
[push(lookup_var(Env, X))];
|
[ dbg_loc(Env, Ann), push(lookup_var(Env, X)) ];
|
||||||
|
|
||||||
to_scode1(Env, {con, Ar, I, As}) ->
|
to_scode1(Env, {con, Ann, Ar, I, As}) ->
|
||||||
N = length(As),
|
N = length(As),
|
||||||
[[to_scode(notail(Env), A) || A <- As],
|
[ dbg_loc(Env, Ann),
|
||||||
|
[to_scode(notail(Env), A) || A <- As],
|
||||||
aeb_fate_ops:variant(?a, ?i(Ar), ?i(I), ?i(N)) ];
|
aeb_fate_ops:variant(?a, ?i(Ar), ?i(I), ?i(N)) ];
|
||||||
|
|
||||||
to_scode1(Env, {tuple, As}) ->
|
to_scode1(Env, {tuple, Ann, As}) ->
|
||||||
N = length(As),
|
N = length(As),
|
||||||
[[ to_scode(notail(Env), A) || A <- As ],
|
[ dbg_loc(Env, Ann),
|
||||||
|
[ to_scode(notail(Env), A) || A <- As ],
|
||||||
tuple(N) ];
|
tuple(N) ];
|
||||||
|
|
||||||
to_scode1(Env, {proj, E, I}) ->
|
to_scode1(Env, {proj, Ann, E, I}) ->
|
||||||
[to_scode(notail(Env), E),
|
[ dbg_loc(Env, Ann),
|
||||||
|
to_scode(notail(Env), E),
|
||||||
aeb_fate_ops:element_op(?a, ?i(I), ?a) ];
|
aeb_fate_ops:element_op(?a, ?i(I), ?a) ];
|
||||||
|
|
||||||
to_scode1(Env, {set_proj, R, I, E}) ->
|
to_scode1(Env, {set_proj, Ann, R, I, E}) ->
|
||||||
[to_scode(notail(Env), E),
|
[ dbg_loc(Env, Ann),
|
||||||
|
to_scode(notail(Env), E),
|
||||||
to_scode(notail(Env), R),
|
to_scode(notail(Env), R),
|
||||||
aeb_fate_ops:setelement(?a, ?i(I), ?a, ?a) ];
|
aeb_fate_ops:setelement(?a, ?i(I), ?a, ?a) ];
|
||||||
|
|
||||||
to_scode1(Env, {op, Op, Args}) ->
|
to_scode1(Env, {op, Ann, Op, Args}) ->
|
||||||
call_to_scode(Env, op_to_scode(Op), Args);
|
[ dbg_loc(Env, Ann) | call_to_scode(Env, op_to_scode(Op), Args) ];
|
||||||
|
|
||||||
to_scode1(Env, {'let', X, {var, Y}, Body}) ->
|
to_scode1(Env, {'let', Ann, X, {var, _, Y}, Body}) ->
|
||||||
Env1 = bind_var(X, lookup_var(Env, Y), Env),
|
Env1 = bind_var(X, lookup_var(Env, Y), Env),
|
||||||
to_scode(Env1, Body);
|
[ dbg_loc(Env, Ann) | dbg_scoped_vars(Env1, [X], to_scode(Env1, Body)) ];
|
||||||
to_scode1(Env, {'let', X, Expr, Body}) ->
|
to_scode1(Env, {'let', Ann, X, Expr, Body}) ->
|
||||||
{I, Env1} = bind_local(X, Env),
|
{I, Env1} = bind_local(X, Env),
|
||||||
[ to_scode(notail(Env), Expr),
|
SCode = [ to_scode(notail(Env), Expr),
|
||||||
aeb_fate_ops:store({var, I}, {stack, 0}),
|
aeb_fate_ops:store({var, I}, {stack, 0}),
|
||||||
to_scode(Env1, Body) ];
|
to_scode(Env1, Body) ],
|
||||||
|
[ dbg_loc(Env, Ann) | dbg_scoped_vars(Env1, [X], SCode) ];
|
||||||
|
|
||||||
to_scode1(Env = #env{ current_function = Fun, tailpos = true }, {def, Fun, Args}) ->
|
to_scode1(Env = #env{ current_function = Fun, tailpos = true, debug_info = false }, {def, Ann, Fun, Args}) ->
|
||||||
%% Tail-call to current function, f(e0..en). Compile to
|
%% Tail-call to current function, f(e0..en). Compile to
|
||||||
%% [ let xi = ei ]
|
%% [ let xi = ei ]
|
||||||
%% [ STORE argi xi ]
|
%% [ STORE argi xi ]
|
||||||
@@ -371,61 +359,62 @@ to_scode1(Env = #env{ current_function = Fun, tailpos = true }, {def, Fun, Args}
|
|||||||
aeb_fate_ops:store({var, I}, ?a)],
|
aeb_fate_ops:store({var, I}, ?a)],
|
||||||
{[I | Is], Acc1, Env2}
|
{[I | Is], Acc1, Env2}
|
||||||
end, {[], [], Env}, Args),
|
end, {[], [], Env}, Args),
|
||||||
[ Code,
|
[ dbg_loc(Env, Ann),
|
||||||
|
Code,
|
||||||
[ aeb_fate_ops:store({arg, I}, {var, J})
|
[ aeb_fate_ops:store({arg, I}, {var, J})
|
||||||
|| {I, J} <- lists:zip(lists:seq(0, length(Vars) - 1),
|
|| {I, J} <- lists:zip(lists:seq(0, length(Vars) - 1),
|
||||||
lists:reverse(Vars)) ],
|
lists:reverse(Vars)) ],
|
||||||
loop ];
|
loop ];
|
||||||
to_scode1(Env, {def, Fun, Args}) ->
|
to_scode1(Env, {def, Ann, Fun, Args}) ->
|
||||||
FName = make_function_id(Fun),
|
FName = make_function_id(Fun),
|
||||||
Lbl = aeb_fate_data:make_string(FName),
|
Lbl = aeb_fate_data:make_string(FName),
|
||||||
call_to_scode(Env, local_call(Env, ?i(Lbl)), Args);
|
[ dbg_loc(Env, Ann) | call_to_scode(Env, local_call(Env, ?i(Lbl)), Args) ];
|
||||||
to_scode1(Env, {funcall, Fun, Args}) ->
|
to_scode1(Env, {funcall, Ann, Fun, Args}) ->
|
||||||
call_to_scode(Env, [to_scode(Env, Fun), local_call(Env, ?a)], Args);
|
[ dbg_loc(Env, Ann) | call_to_scode(Env, [to_scode(Env, Fun), local_call(Env, ?a)], Args) ];
|
||||||
|
|
||||||
to_scode1(Env, {builtin, B, Args}) ->
|
to_scode1(Env, {builtin, Ann, B, Args}) ->
|
||||||
builtin_to_scode(Env, B, Args);
|
[ dbg_loc(Env, Ann) | builtin_to_scode(Env, B, Args) ];
|
||||||
|
|
||||||
to_scode1(Env, {remote, ArgsT, RetT, Ct, Fun, [Gas, Value, Protected | Args]}) ->
|
to_scode1(Env, {remote, Ann, ArgsT, RetT, Ct, Fun, [Gas, Value, Protected | Args]}) ->
|
||||||
Lbl = make_function_id(Fun),
|
Lbl = make_function_id(Fun),
|
||||||
{ArgTypes, RetType0} = typesig_to_scode([{"_", T} || T <- ArgsT], RetT),
|
{ArgTypes, RetType0} = typesig_to_scode([{"_", T} || T <- ArgsT], RetT),
|
||||||
ArgType = ?i(aeb_fate_data:make_typerep({tuple, ArgTypes})),
|
ArgType = ?i(aeb_fate_data:make_typerep({tuple, ArgTypes})),
|
||||||
RetType = ?i(aeb_fate_data:make_typerep(RetType0)),
|
RetType = ?i(aeb_fate_data:make_typerep(RetType0)),
|
||||||
case Protected of
|
SCode = case Protected of
|
||||||
{lit, {bool, false}} ->
|
{lit, _, {bool, false}} ->
|
||||||
case Gas of
|
case Gas of
|
||||||
{builtin, call_gas_left, _} ->
|
{builtin, _, call_gas_left, _} ->
|
||||||
Call = aeb_fate_ops:call_r(?a, Lbl, ArgType, RetType, ?a),
|
Call = aeb_fate_ops:call_r(?a, Lbl, ArgType, RetType, ?a),
|
||||||
call_to_scode(Env, Call, [Ct, Value | Args]);
|
call_to_scode(Env, Call, [Ct, Value | Args]);
|
||||||
_ ->
|
_ ->
|
||||||
Call = aeb_fate_ops:call_gr(?a, Lbl, ArgType, RetType, ?a, ?a),
|
Call = aeb_fate_ops:call_gr(?a, Lbl, ArgType, RetType, ?a, ?a),
|
||||||
call_to_scode(Env, Call, [Ct, Value, Gas | Args])
|
call_to_scode(Env, Call, [Ct, Value, Gas | Args])
|
||||||
end;
|
end;
|
||||||
{lit, {bool, true}} ->
|
{lit, _, {bool, true}} ->
|
||||||
Call = aeb_fate_ops:call_pgr(?a, Lbl, ArgType, RetType, ?a, ?a, ?i(true)),
|
Call = aeb_fate_ops:call_pgr(?a, Lbl, ArgType, RetType, ?a, ?a, ?i(true)),
|
||||||
call_to_scode(Env, Call, [Ct, Value, Gas | Args]);
|
call_to_scode(Env, Call, [Ct, Value, Gas | Args]);
|
||||||
_ ->
|
_ ->
|
||||||
Call = aeb_fate_ops:call_pgr(?a, Lbl, ArgType, RetType, ?a, ?a, ?a),
|
Call = aeb_fate_ops:call_pgr(?a, Lbl, ArgType, RetType, ?a, ?a, ?a),
|
||||||
call_to_scode(Env, Call, [Ct, Value, Gas, Protected | Args])
|
call_to_scode(Env, Call, [Ct, Value, Gas, Protected | Args])
|
||||||
end;
|
end,
|
||||||
|
[ dbg_loc(Env, Ann) | SCode ];
|
||||||
|
|
||||||
to_scode1(_Env, {get_state, Reg}) ->
|
to_scode1(Env, {get_state, Ann, Reg}) ->
|
||||||
[push(?s(Reg))];
|
[ dbg_loc(Env, Ann), push(?s(Reg)) ];
|
||||||
to_scode1(Env, {set_state, Reg, Val}) ->
|
to_scode1(Env, {set_state, Ann, Reg, Val}) ->
|
||||||
call_to_scode(Env, [{'STORE', ?s(Reg), ?a},
|
[ dbg_loc(Env, Ann) | call_to_scode(Env, [{'STORE', ?s(Reg), ?a}, tuple(0)], [Val]) ];
|
||||||
tuple(0)], [Val]);
|
|
||||||
|
|
||||||
to_scode1(Env, {closure, Fun, FVs}) ->
|
to_scode1(Env, {closure, Ann, Fun, FVs}) ->
|
||||||
to_scode(Env, {tuple, [{lit, {string, make_function_id(Fun)}}, FVs]});
|
[ to_scode(Env, {tuple, Ann, [{lit, Ann, {string, make_function_id(Fun)}}, FVs]}) ];
|
||||||
|
|
||||||
to_scode1(Env, {switch, Case}) ->
|
to_scode1(Env, {switch, Ann, Case}) ->
|
||||||
split_to_scode(Env, Case).
|
[ dbg_loc(Env, Ann) | split_to_scode(Env, Case) ].
|
||||||
|
|
||||||
local_call( Env, Fun) when Env#env.tailpos -> aeb_fate_ops:call_t(Fun);
|
local_call( Env = #env{debug_info = false}, Fun) when Env#env.tailpos -> aeb_fate_ops:call_t(Fun);
|
||||||
local_call(_Env, Fun) -> aeb_fate_ops:call(Fun).
|
local_call(_Env, Fun) -> aeb_fate_ops:call(Fun).
|
||||||
|
|
||||||
split_to_scode(Env, {nosplit, Expr}) ->
|
split_to_scode(Env, {nosplit, Renames, Expr}) ->
|
||||||
[switch_body, to_scode(Env, Expr)];
|
[switch_body, dbg_scoped_vars(Env, Renames, to_scode(Env, Expr))];
|
||||||
split_to_scode(Env, {split, {tuple, _}, X, Alts}) ->
|
split_to_scode(Env, {split, {tuple, _}, X, Alts}) ->
|
||||||
{Def, Alts1} = catchall_to_scode(Env, X, Alts),
|
{Def, Alts1} = catchall_to_scode(Env, X, Alts),
|
||||||
Arg = lookup_var(Env, X),
|
Arg = lookup_var(Env, X),
|
||||||
@@ -554,6 +543,14 @@ builtin_to_scode(Env, bytes_concat, [_, _] = Args) ->
|
|||||||
call_to_scode(Env, aeb_fate_ops:bytes_concat(?a, ?a, ?a), Args);
|
call_to_scode(Env, aeb_fate_ops:bytes_concat(?a, ?a, ?a), Args);
|
||||||
builtin_to_scode(Env, bytes_split, [_, _] = Args) ->
|
builtin_to_scode(Env, bytes_split, [_, _] = Args) ->
|
||||||
call_to_scode(Env, aeb_fate_ops:bytes_split(?a, ?a, ?a), Args);
|
call_to_scode(Env, aeb_fate_ops:bytes_split(?a, ?a, ?a), Args);
|
||||||
|
builtin_to_scode(Env, bytes_split_any, [_, _] = Args) ->
|
||||||
|
call_to_scode(Env, aeb_fate_ops:bytes_split_any(?a, ?a, ?a), Args);
|
||||||
|
builtin_to_scode(Env, bytes_to_fixed_size, [_, _] = Args) ->
|
||||||
|
call_to_scode(Env, aeb_fate_ops:bytes_to_fixed_size(?a, ?a, ?a), Args);
|
||||||
|
builtin_to_scode(Env, bytes_to_any_size, [A]) ->
|
||||||
|
[to_scode(Env, A)]; %% no_op!
|
||||||
|
builtin_to_scode(Env, bytes_size, [_] = Args) ->
|
||||||
|
call_to_scode(Env, aeb_fate_ops:bytes_size(?a, ?a), Args);
|
||||||
builtin_to_scode(Env, abort, [_] = Args) ->
|
builtin_to_scode(Env, abort, [_] = Args) ->
|
||||||
call_to_scode(Env, aeb_fate_ops:abort(?a), Args);
|
call_to_scode(Env, aeb_fate_ops:abort(?a), Args);
|
||||||
builtin_to_scode(Env, exit, [_] = Args) ->
|
builtin_to_scode(Env, exit, [_] = Args) ->
|
||||||
@@ -575,6 +572,8 @@ builtin_to_scode(_Env, chain_difficulty, []) ->
|
|||||||
[aeb_fate_ops:difficulty(?a)];
|
[aeb_fate_ops:difficulty(?a)];
|
||||||
builtin_to_scode(_Env, chain_gas_limit, []) ->
|
builtin_to_scode(_Env, chain_gas_limit, []) ->
|
||||||
[aeb_fate_ops:gaslimit(?a)];
|
[aeb_fate_ops:gaslimit(?a)];
|
||||||
|
builtin_to_scode(_Env, chain_network_id, []) ->
|
||||||
|
[aeb_fate_ops:network_id(?a)];
|
||||||
builtin_to_scode(_Env, contract_balance, []) ->
|
builtin_to_scode(_Env, contract_balance, []) ->
|
||||||
[aeb_fate_ops:balance(?a)];
|
[aeb_fate_ops:balance(?a)];
|
||||||
builtin_to_scode(_Env, contract_address, []) ->
|
builtin_to_scode(_Env, contract_address, []) ->
|
||||||
@@ -649,7 +648,7 @@ builtin_to_scode(Env, chain_bytecode_hash, [_Addr] = Args) ->
|
|||||||
builtin_to_scode(Env, chain_clone,
|
builtin_to_scode(Env, chain_clone,
|
||||||
[InitArgsT, GasCap, Value, Prot, Contract | InitArgs]) ->
|
[InitArgsT, GasCap, Value, Prot, Contract | InitArgs]) ->
|
||||||
case GasCap of
|
case GasCap of
|
||||||
{builtin, call_gas_left, _} ->
|
{builtin, _, call_gas_left, _} ->
|
||||||
call_to_scode(Env, aeb_fate_ops:clone(?a, ?a, ?a, ?a),
|
call_to_scode(Env, aeb_fate_ops:clone(?a, ?a, ?a, ?a),
|
||||||
[Contract, InitArgsT, Value, Prot | InitArgs]
|
[Contract, InitArgsT, Value, Prot | InitArgs]
|
||||||
);
|
);
|
||||||
@@ -682,6 +681,12 @@ op_to_scode('>=') -> aeb_fate_ops:egt(?a, ?a, ?a);
|
|||||||
op_to_scode('==') -> aeb_fate_ops:eq(?a, ?a, ?a);
|
op_to_scode('==') -> aeb_fate_ops:eq(?a, ?a, ?a);
|
||||||
op_to_scode('!=') -> aeb_fate_ops:neq(?a, ?a, ?a);
|
op_to_scode('!=') -> aeb_fate_ops:neq(?a, ?a, ?a);
|
||||||
op_to_scode('!') -> aeb_fate_ops:not_op(?a, ?a);
|
op_to_scode('!') -> aeb_fate_ops:not_op(?a, ?a);
|
||||||
|
op_to_scode('bnot') -> aeb_fate_ops:bin_not(?a, ?a);
|
||||||
|
op_to_scode('band') -> aeb_fate_ops:bin_and(?a, ?a, ?a);
|
||||||
|
op_to_scode('bor') -> aeb_fate_ops:bin_or(?a, ?a, ?a);
|
||||||
|
op_to_scode('bxor') -> aeb_fate_ops:bin_xor(?a, ?a, ?a);
|
||||||
|
op_to_scode('<<') -> aeb_fate_ops:bin_sl(?a, ?a, ?a);
|
||||||
|
op_to_scode('>>') -> aeb_fate_ops:bin_sr(?a, ?a, ?a);
|
||||||
op_to_scode(map_get) -> aeb_fate_ops:map_lookup(?a, ?a, ?a);
|
op_to_scode(map_get) -> aeb_fate_ops:map_lookup(?a, ?a, ?a);
|
||||||
op_to_scode(map_get_d) -> aeb_fate_ops:map_lookup(?a, ?a, ?a, ?a);
|
op_to_scode(map_get_d) -> aeb_fate_ops:map_lookup(?a, ?a, ?a, ?a);
|
||||||
op_to_scode(map_set) -> aeb_fate_ops:map_update(?a, ?a, ?a, ?a);
|
op_to_scode(map_set) -> aeb_fate_ops:map_update(?a, ?a, ?a, ?a);
|
||||||
@@ -692,6 +697,7 @@ op_to_scode(map_member) -> aeb_fate_ops:map_member(?a, ?a, ?a);
|
|||||||
op_to_scode(map_size) -> aeb_fate_ops:map_size_(?a, ?a);
|
op_to_scode(map_size) -> aeb_fate_ops:map_size_(?a, ?a);
|
||||||
op_to_scode(stringinternal_length) -> aeb_fate_ops:str_length(?a, ?a);
|
op_to_scode(stringinternal_length) -> aeb_fate_ops:str_length(?a, ?a);
|
||||||
op_to_scode(stringinternal_concat) -> aeb_fate_ops:str_join(?a, ?a, ?a);
|
op_to_scode(stringinternal_concat) -> aeb_fate_ops:str_join(?a, ?a, ?a);
|
||||||
|
op_to_scode(stringinternal_to_bytes) -> aeb_fate_ops:str_to_bytes(?a, ?a);
|
||||||
op_to_scode(stringinternal_to_list) -> aeb_fate_ops:str_to_list(?a, ?a);
|
op_to_scode(stringinternal_to_list) -> aeb_fate_ops:str_to_list(?a, ?a);
|
||||||
op_to_scode(stringinternal_from_list) -> aeb_fate_ops:str_from_list(?a, ?a);
|
op_to_scode(stringinternal_from_list) -> aeb_fate_ops:str_from_list(?a, ?a);
|
||||||
op_to_scode(stringinternal_to_lower) -> aeb_fate_ops:str_to_lower(?a, ?a);
|
op_to_scode(stringinternal_to_lower) -> aeb_fate_ops:str_to_lower(?a, ?a);
|
||||||
@@ -706,7 +712,10 @@ op_to_scode(bits_intersection) -> aeb_fate_ops:bits_and(?a, ?a, ?a);
|
|||||||
op_to_scode(bits_union) -> aeb_fate_ops:bits_or(?a, ?a, ?a);
|
op_to_scode(bits_union) -> aeb_fate_ops:bits_or(?a, ?a, ?a);
|
||||||
op_to_scode(bits_difference) -> aeb_fate_ops:bits_diff(?a, ?a, ?a);
|
op_to_scode(bits_difference) -> aeb_fate_ops:bits_diff(?a, ?a, ?a);
|
||||||
op_to_scode(address_to_str) -> aeb_fate_ops:addr_to_str(?a, ?a);
|
op_to_scode(address_to_str) -> aeb_fate_ops:addr_to_str(?a, ?a);
|
||||||
|
op_to_scode(address_to_bytes) -> aeb_fate_ops:addr_to_bytes(?a, ?a);
|
||||||
op_to_scode(int_to_str) -> aeb_fate_ops:int_to_str(?a, ?a);
|
op_to_scode(int_to_str) -> aeb_fate_ops:int_to_str(?a, ?a);
|
||||||
|
op_to_scode(int_to_bytes) -> aeb_fate_ops:int_to_bytes(?a, ?a, ?a);
|
||||||
|
op_to_scode(int_mulmod) -> aeb_fate_ops:mulmod(?a, ?a, ?a, ?a);
|
||||||
op_to_scode(contract_to_address) -> aeb_fate_ops:contract_to_address(?a, ?a);
|
op_to_scode(contract_to_address) -> aeb_fate_ops:contract_to_address(?a, ?a);
|
||||||
op_to_scode(address_to_contract) -> aeb_fate_ops:address_to_contract(?a, ?a);
|
op_to_scode(address_to_contract) -> aeb_fate_ops:address_to_contract(?a, ?a);
|
||||||
op_to_scode(crypto_verify_sig) -> aeb_fate_ops:verify_sig(?a, ?a, ?a, ?a);
|
op_to_scode(crypto_verify_sig) -> aeb_fate_ops:verify_sig(?a, ?a, ?a, ?a);
|
||||||
@@ -716,6 +725,7 @@ op_to_scode(crypto_ecrecover_secp256k1) -> aeb_fate_ops:ecrecover_secp256k1(?a,
|
|||||||
op_to_scode(crypto_sha3) -> aeb_fate_ops:sha3(?a, ?a);
|
op_to_scode(crypto_sha3) -> aeb_fate_ops:sha3(?a, ?a);
|
||||||
op_to_scode(crypto_sha256) -> aeb_fate_ops:sha256(?a, ?a);
|
op_to_scode(crypto_sha256) -> aeb_fate_ops:sha256(?a, ?a);
|
||||||
op_to_scode(crypto_blake2b) -> aeb_fate_ops:blake2b(?a, ?a);
|
op_to_scode(crypto_blake2b) -> aeb_fate_ops:blake2b(?a, ?a);
|
||||||
|
op_to_scode(crypto_poseidon) -> aeb_fate_ops:poseidon(?a, ?a, ?a);
|
||||||
op_to_scode(stringinternal_sha3) -> aeb_fate_ops:sha3(?a, ?a);
|
op_to_scode(stringinternal_sha3) -> aeb_fate_ops:sha3(?a, ?a);
|
||||||
op_to_scode(stringinternal_sha256) -> aeb_fate_ops:sha256(?a, ?a);
|
op_to_scode(stringinternal_sha256) -> aeb_fate_ops:sha256(?a, ?a);
|
||||||
op_to_scode(stringinternal_blake2b) -> aeb_fate_ops:blake2b(?a, ?a);
|
op_to_scode(stringinternal_blake2b) -> aeb_fate_ops:blake2b(?a, ?a);
|
||||||
@@ -751,6 +761,77 @@ push(A) -> {'STORE', ?a, A}.
|
|||||||
tuple(0) -> push(?i({tuple, {}}));
|
tuple(0) -> push(?i({tuple, {}}));
|
||||||
tuple(N) -> aeb_fate_ops:tuple(?a, N).
|
tuple(N) -> aeb_fate_ops:tuple(?a, N).
|
||||||
|
|
||||||
|
%% -- Debug info functions --
|
||||||
|
|
||||||
|
dbg_contract(#env{debug_info = false}) ->
|
||||||
|
[];
|
||||||
|
dbg_contract(#env{contract = Contract}) ->
|
||||||
|
[{'DBG_CONTRACT', {immediate, Contract}}].
|
||||||
|
|
||||||
|
dbg_loc(#env{debug_info = false}, _) ->
|
||||||
|
[];
|
||||||
|
dbg_loc(_Env, Ann) ->
|
||||||
|
File = case proplists:get_value(file, Ann, no_file) of
|
||||||
|
no_file -> "";
|
||||||
|
F -> F
|
||||||
|
end,
|
||||||
|
Line = proplists:get_value(line, Ann, undefined),
|
||||||
|
case Line of
|
||||||
|
undefined -> [];
|
||||||
|
_ -> [{'DBG_LOC', {immediate, File}, {immediate, Line}}]
|
||||||
|
end.
|
||||||
|
|
||||||
|
dbg_scoped_vars(#env{debug_info = false}, _, SCode) ->
|
||||||
|
SCode;
|
||||||
|
dbg_scoped_vars(_Env, [], SCode) ->
|
||||||
|
SCode;
|
||||||
|
dbg_scoped_vars(Env, [{SavedVarName, Var} | Rest], SCode) ->
|
||||||
|
dbg_scoped_vars(Env, Rest, dbg_scoped_var(Env, SavedVarName, Var, SCode));
|
||||||
|
dbg_scoped_vars(Env = #env{saved_fresh_names = SavedFreshNames}, [Var | Rest], SCode) ->
|
||||||
|
SavedVarName = maps:get(Var, SavedFreshNames, Var),
|
||||||
|
dbg_scoped_vars(Env, Rest, dbg_scoped_var(Env, SavedVarName, Var, SCode)).
|
||||||
|
|
||||||
|
dbg_scoped_var(Env, SavedVarName, Var, SCode) ->
|
||||||
|
case SavedVarName == "_" orelse is_fresh_name(SavedVarName) of
|
||||||
|
true ->
|
||||||
|
SCode;
|
||||||
|
false ->
|
||||||
|
Register = lookup_var(Env, Var),
|
||||||
|
Def = [{'DBG_DEF', {immediate, SavedVarName}, Register}],
|
||||||
|
Undef = [{'DBG_UNDEF', {immediate, SavedVarName}, Register}],
|
||||||
|
Def ++ dbg_undef(Undef, SCode)
|
||||||
|
end.
|
||||||
|
|
||||||
|
is_fresh_name([$% | _]) ->
|
||||||
|
true;
|
||||||
|
is_fresh_name(_) ->
|
||||||
|
false.
|
||||||
|
|
||||||
|
dbg_undef(_Undef, missing) ->
|
||||||
|
missing;
|
||||||
|
dbg_undef(Undef, loop) ->
|
||||||
|
[Undef, loop];
|
||||||
|
dbg_undef(Undef, switch_body) ->
|
||||||
|
[switch_body, Undef];
|
||||||
|
dbg_undef(Undef, {switch, Arg, Type, Alts, Catch}) ->
|
||||||
|
NewAlts = [ dbg_undef(Undef, Alt) || Alt <- Alts ],
|
||||||
|
NewCatch = dbg_undef(Undef, Catch),
|
||||||
|
NewSwitch = {switch, Arg, Type, NewAlts, NewCatch},
|
||||||
|
NewSwitch;
|
||||||
|
dbg_undef(Undef, SCode) when is_list(SCode) ->
|
||||||
|
lists:droplast(SCode) ++ [dbg_undef(Undef, lists:last(SCode))];
|
||||||
|
dbg_undef(Undef, SCode) when is_tuple(SCode); is_atom(SCode) ->
|
||||||
|
[Mnemonic | _] =
|
||||||
|
case is_tuple(SCode) of
|
||||||
|
true -> tuple_to_list(SCode);
|
||||||
|
false -> [SCode]
|
||||||
|
end,
|
||||||
|
Op = aeb_fate_opcodes:m_to_op(Mnemonic),
|
||||||
|
case aeb_fate_opcodes:end_bb(Op) of
|
||||||
|
true -> [Undef, SCode];
|
||||||
|
false -> [SCode, Undef]
|
||||||
|
end.
|
||||||
|
|
||||||
%% -- Phase II ---------------------------------------------------------------
|
%% -- Phase II ---------------------------------------------------------------
|
||||||
%% Optimize
|
%% Optimize
|
||||||
|
|
||||||
@@ -886,6 +967,10 @@ attributes(I) ->
|
|||||||
loop -> Impure(pc, []);
|
loop -> Impure(pc, []);
|
||||||
switch_body -> Pure(none, []);
|
switch_body -> Pure(none, []);
|
||||||
'RETURN' -> Impure(pc, []);
|
'RETURN' -> Impure(pc, []);
|
||||||
|
{'DBG_LOC', _, _} -> Impure(none, []);
|
||||||
|
{'DBG_DEF', _, _} -> Impure(none, []);
|
||||||
|
{'DBG_UNDEF', _, _} -> Impure(none, []);
|
||||||
|
{'DBG_CONTRACT', _} -> Impure(none, []);
|
||||||
{'RETURNR', A} -> Impure(pc, A);
|
{'RETURNR', A} -> Impure(pc, A);
|
||||||
{'CALL', A} -> Impure(?a, [A]);
|
{'CALL', A} -> Impure(?a, [A]);
|
||||||
{'CALL_R', A, _, B, C, D} -> Impure(?a, [A, B, C, D]);
|
{'CALL_R', A, _, B, C, D} -> Impure(?a, [A, B, C, D]);
|
||||||
@@ -913,6 +998,13 @@ attributes(I) ->
|
|||||||
{'DIV', A, B, C} -> Pure(A, [B, C]);
|
{'DIV', A, B, C} -> Pure(A, [B, C]);
|
||||||
{'MOD', A, B, C} -> Pure(A, [B, C]);
|
{'MOD', A, B, C} -> Pure(A, [B, C]);
|
||||||
{'POW', A, B, C} -> Pure(A, [B, C]);
|
{'POW', A, B, C} -> Pure(A, [B, C]);
|
||||||
|
{'MULMOD', A, B, C, D} -> Pure(A, [B, C, D]);
|
||||||
|
{'BAND', A, B, C} -> Pure(A, [B, C]);
|
||||||
|
{'BOR', A, B, C} -> Pure(A, [B, C]);
|
||||||
|
{'BXOR', A, B, C} -> Pure(A, [B, C]);
|
||||||
|
{'BNOT', A, B} -> Pure(A, [B]);
|
||||||
|
{'BSL', A, B, C} -> Pure(A, [B, C]);
|
||||||
|
{'BSR', A, B, C} -> Pure(A, [B, C]);
|
||||||
{'LT', A, B, C} -> Pure(A, [B, C]);
|
{'LT', A, B, C} -> Pure(A, [B, C]);
|
||||||
{'GT', A, B, C} -> Pure(A, [B, C]);
|
{'GT', A, B, C} -> Pure(A, [B, C]);
|
||||||
{'EQ', A, B, C} -> Pure(A, [B, C]);
|
{'EQ', A, B, C} -> Pure(A, [B, C]);
|
||||||
@@ -943,9 +1035,11 @@ attributes(I) ->
|
|||||||
{'APPEND', A, B, C} -> Pure(A, [B, C]);
|
{'APPEND', A, B, C} -> Pure(A, [B, C]);
|
||||||
{'STR_JOIN', A, B, C} -> Pure(A, [B, C]);
|
{'STR_JOIN', A, B, C} -> Pure(A, [B, C]);
|
||||||
{'INT_TO_STR', A, B} -> Pure(A, B);
|
{'INT_TO_STR', A, B} -> Pure(A, B);
|
||||||
|
{'INT_TO_BYTES', A, B, C} -> Pure(A, [B, C]);
|
||||||
{'ADDR_TO_STR', A, B} -> Pure(A, B);
|
{'ADDR_TO_STR', A, B} -> Pure(A, B);
|
||||||
{'STR_REVERSE', A, B} -> Pure(A, B);
|
{'STR_REVERSE', A, B} -> Pure(A, B);
|
||||||
{'STR_LENGTH', A, B} -> Pure(A, B);
|
{'STR_LENGTH', A, B} -> Pure(A, B);
|
||||||
|
{'STR_TO_BYTES', A, B} -> Pure(A, B);
|
||||||
{'INT_TO_ADDR', A, B} -> Pure(A, B);
|
{'INT_TO_ADDR', A, B} -> Pure(A, B);
|
||||||
{'VARIANT', A, B, C, D} -> Pure(A, [?a, B, C, D]);
|
{'VARIANT', A, B, C, D} -> Pure(A, [?a, B, C, D]);
|
||||||
{'VARIANT_TEST', A, B, C} -> Pure(A, [B, C]);
|
{'VARIANT_TEST', A, B, C} -> Pure(A, [B, C]);
|
||||||
@@ -965,18 +1059,23 @@ attributes(I) ->
|
|||||||
{'SHA3', A, B} -> Pure(A, [B]);
|
{'SHA3', A, B} -> Pure(A, [B]);
|
||||||
{'SHA256', A, B} -> Pure(A, [B]);
|
{'SHA256', A, B} -> Pure(A, [B]);
|
||||||
{'BLAKE2B', A, B} -> Pure(A, [B]);
|
{'BLAKE2B', A, B} -> Pure(A, [B]);
|
||||||
|
{'POSEIDON', A, B, C} -> Pure(A, [B, C]);
|
||||||
{'VERIFY_SIG', A, B, C, D} -> Pure(A, [B, C, D]);
|
{'VERIFY_SIG', A, B, C, D} -> Pure(A, [B, C, D]);
|
||||||
{'VERIFY_SIG_SECP256K1', A, B, C, D} -> Pure(A, [B, C, D]);
|
{'VERIFY_SIG_SECP256K1', A, B, C, D} -> Pure(A, [B, C, D]);
|
||||||
{'ECVERIFY_SECP256K1', A, B, C, D} -> Pure(A, [B, C, D]);
|
{'ECVERIFY_SECP256K1', A, B, C, D} -> Pure(A, [B, C, D]);
|
||||||
{'ECRECOVER_SECP256K1', A, B, C} -> Pure(A, [B, C]);
|
{'ECRECOVER_SECP256K1', A, B, C} -> Pure(A, [B, C]);
|
||||||
{'CONTRACT_TO_ADDRESS', A, B} -> Pure(A, [B]);
|
{'CONTRACT_TO_ADDRESS', A, B} -> Pure(A, [B]);
|
||||||
{'ADDRESS_TO_CONTRACT', A, B} -> Pure(A, [B]);
|
{'ADDRESS_TO_CONTRACT', A, B} -> Pure(A, [B]);
|
||||||
|
{'ADDRESS_TO_BYTES', A, B} -> Pure(A, [B]);
|
||||||
{'AUTH_TX_HASH', A} -> Pure(A, []);
|
{'AUTH_TX_HASH', A} -> Pure(A, []);
|
||||||
{'AUTH_TX', A} -> Pure(A, []);
|
{'AUTH_TX', A} -> Pure(A, []);
|
||||||
{'BYTES_TO_INT', A, B} -> Pure(A, [B]);
|
{'BYTES_TO_INT', A, B} -> Pure(A, [B]);
|
||||||
{'BYTES_TO_STR', A, B} -> Pure(A, [B]);
|
{'BYTES_TO_STR', A, B} -> Pure(A, [B]);
|
||||||
{'BYTES_CONCAT', A, B, C} -> Pure(A, [B, C]);
|
{'BYTES_CONCAT', A, B, C} -> Pure(A, [B, C]);
|
||||||
{'BYTES_SPLIT', A, B, C} -> Pure(A, [B, C]);
|
{'BYTES_SPLIT', A, B, C} -> Pure(A, [B, C]);
|
||||||
|
{'BYTES_SPLIT_ANY', A, B, C} -> Pure(A, [B, C]);
|
||||||
|
{'BYTES_SIZE', A, B} -> Pure(A, B);
|
||||||
|
{'BYTES_TO_FIXED_SIZE', A, B, C} -> Pure(A, [B, C]);
|
||||||
{'ORACLE_CHECK', A, B, C, D} -> Pure(A, [B, C, D]);
|
{'ORACLE_CHECK', A, B, C, D} -> Pure(A, [B, C, D]);
|
||||||
{'ORACLE_CHECK_QUERY', A, B, C, D, E} -> Pure(A, [B, C, D, E]);
|
{'ORACLE_CHECK_QUERY', A, B, C, D, E} -> Pure(A, [B, C, D, E]);
|
||||||
{'IS_ORACLE', A, B} -> Pure(A, [B]);
|
{'IS_ORACLE', A, B} -> Pure(A, [B]);
|
||||||
@@ -997,6 +1096,7 @@ attributes(I) ->
|
|||||||
{'MICROBLOCK', A} -> Pure(A, []);
|
{'MICROBLOCK', A} -> Pure(A, []);
|
||||||
{'DIFFICULTY', A} -> Pure(A, []);
|
{'DIFFICULTY', A} -> Pure(A, []);
|
||||||
{'GASLIMIT', A} -> Pure(A, []);
|
{'GASLIMIT', A} -> Pure(A, []);
|
||||||
|
{'NETWORK_ID', A} -> Pure(A, []);
|
||||||
{'GAS', A} -> Pure(A, []);
|
{'GAS', A} -> Pure(A, []);
|
||||||
{'LOG0', A} -> Impure(none, [A]);
|
{'LOG0', A} -> Impure(none, [A]);
|
||||||
{'LOG1', A, B} -> Impure(none, [A, B]);
|
{'LOG1', A, B} -> Impure(none, [A, B]);
|
||||||
@@ -1081,10 +1181,15 @@ independent({i, _, I}, {i, _, J}) ->
|
|||||||
StackI = lists:member(?a, [WI | RI]),
|
StackI = lists:member(?a, [WI | RI]),
|
||||||
StackJ = lists:member(?a, [WJ | RJ]),
|
StackJ = lists:member(?a, [WJ | RJ]),
|
||||||
|
|
||||||
|
ReadStoreI = [] /= [ x || {store, _} <- RI ],
|
||||||
|
ReadStoreJ = [] /= [ x || {store, _} <- RJ ],
|
||||||
|
|
||||||
if WI == pc; WJ == pc -> false; %% no jumps
|
if WI == pc; WJ == pc -> false; %% no jumps
|
||||||
not (PureI or PureJ) -> false; %% at least one is pure
|
not (PureI or PureJ) -> false; %% at least one is pure
|
||||||
StackI and StackJ -> false; %% cannot both use the stack
|
StackI and StackJ -> false; %% cannot both use the stack
|
||||||
WI == WJ -> false; %% cannot write to the same register
|
WI == WJ -> false; %% cannot write to the same register
|
||||||
|
ReadStoreI and not PureJ -> false; %% can't read store/state if other is impure
|
||||||
|
ReadStoreJ and not PureI -> false; %% can't read store/state if other is impure
|
||||||
true ->
|
true ->
|
||||||
%% and cannot write to each other's inputs
|
%% and cannot write to each other's inputs
|
||||||
not lists:member(WI, RJ) andalso
|
not lists:member(WI, RJ) andalso
|
||||||
@@ -1605,7 +1710,23 @@ bb(_Name, Code) ->
|
|||||||
Blocks = lists:flatmap(fun split_calls/1, Blocks1),
|
Blocks = lists:flatmap(fun split_calls/1, Blocks1),
|
||||||
Labels = maps:from_list([ {Ref, I} || {I, {Ref, _}} <- with_ixs(Blocks) ]),
|
Labels = maps:from_list([ {Ref, I} || {I, {Ref, _}} <- with_ixs(Blocks) ]),
|
||||||
BBs = [ set_labels(Labels, B) || B <- Blocks ],
|
BBs = [ set_labels(Labels, B) || B <- Blocks ],
|
||||||
maps:from_list(BBs).
|
maps:from_list(dbg_loc_filter(BBs)).
|
||||||
|
|
||||||
|
%% Filter DBG_LOC instructions to keep one instruction per line
|
||||||
|
dbg_loc_filter(BBs) ->
|
||||||
|
dbg_loc_filter(BBs, [], [], sets:new()).
|
||||||
|
|
||||||
|
dbg_loc_filter([], _, AllBlocks, _) ->
|
||||||
|
lists:reverse(AllBlocks);
|
||||||
|
dbg_loc_filter([{I, []} | Rest], AllOps, AllBlocks, DbgLocs) ->
|
||||||
|
dbg_loc_filter(Rest, [], [{I, lists:reverse(AllOps)} | AllBlocks], DbgLocs);
|
||||||
|
dbg_loc_filter([{I, [Op = {'DBG_LOC', _, _} | Ops]} | Rest], AllOps, AllBlocks, DbgLocs) ->
|
||||||
|
case sets:is_element(Op, DbgLocs) of
|
||||||
|
true -> dbg_loc_filter([{I, Ops} | Rest], AllOps, AllBlocks, DbgLocs);
|
||||||
|
false -> dbg_loc_filter([{I, Ops} | Rest], [Op | AllOps], AllBlocks, sets:add_element(Op, DbgLocs))
|
||||||
|
end;
|
||||||
|
dbg_loc_filter([{I, [Op | Ops]} | Rest], AllOps, AllBlocks, DbgLocs) ->
|
||||||
|
dbg_loc_filter([{I, Ops} | Rest], [Op | AllOps], AllBlocks, DbgLocs).
|
||||||
|
|
||||||
%% -- Break up scode into basic blocks --
|
%% -- Break up scode into basic blocks --
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
%%% @end
|
%%% @end
|
||||||
%%%-------------------------------------------------------------------
|
%%%-------------------------------------------------------------------
|
||||||
-module(aeso_parse_lib).
|
-module(aeso_parse_lib).
|
||||||
|
-vsn("8.0.1").
|
||||||
|
|
||||||
-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 +16,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,
|
-export([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]).
|
||||||
|
|
||||||
%% -- Types ------------------------------------------------------------------
|
%% -- Types ------------------------------------------------------------------
|
||||||
@@ -480,6 +481,13 @@ 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.
|
||||||
|
|
||||||
|
|||||||
+60
-25
@@ -3,6 +3,7 @@
|
|||||||
%%% Description :
|
%%% Description :
|
||||||
%%% Created : 1 Mar 2018 by Ulf Norell
|
%%% Created : 1 Mar 2018 by Ulf Norell
|
||||||
-module(aeso_parser).
|
-module(aeso_parser).
|
||||||
|
-vsn("8.0.1").
|
||||||
-compile({no_auto_import,[map_get/2]}).
|
-compile({no_auto_import,[map_get/2]}).
|
||||||
|
|
||||||
-export([string/1,
|
-export([string/1,
|
||||||
@@ -19,6 +20,7 @@
|
|||||||
|
|
||||||
-include("aeso_parse_lib.hrl").
|
-include("aeso_parse_lib.hrl").
|
||||||
-import(aeso_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() :: aeso_syntax:ast() | {aeso_syntax:ast(), sets:set(include_hash())} | none().
|
-type parse_result() :: aeso_syntax:ast() | {aeso_syntax:ast(), sets:set(include_hash())} | none().
|
||||||
@@ -58,6 +60,7 @@ 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 aeso_scan:scan(S) of
|
case aeso_scan:scan(S) of
|
||||||
{ok, Tokens} -> aeso_parse_lib:parse(P, Tokens);
|
{ok, Tokens} -> aeso_parse_lib:parse(P, Tokens);
|
||||||
@@ -264,10 +267,11 @@ 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)})
|
||||||
]).
|
]).
|
||||||
@@ -299,7 +303,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() ->
|
||||||
@@ -323,7 +327,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;
|
||||||
@@ -333,14 +337,19 @@ expr100() ->
|
|||||||
|
|
||||||
expr150() -> infixl(expr200(), binop('|>')).
|
expr150() -> infixl(expr200(), binop('|>')).
|
||||||
expr200() -> infixr(expr300(), binop('||')).
|
expr200() -> infixr(expr300(), binop('||')).
|
||||||
expr300() -> infixr(expr400(), binop('&&')).
|
expr300() -> infixr(expr325(), binop('&&')).
|
||||||
|
expr325() -> infixl(expr350(), binop('bor')).
|
||||||
|
expr350() -> infixl(expr375(), binop('bxor')).
|
||||||
|
expr375() -> infixl(expr400(), binop('band')).
|
||||||
expr400() -> infix(expr500(), binop(['<', '>', '=<', '>=', '==', '!='])).
|
expr400() -> infix(expr500(), binop(['<', '>', '=<', '>=', '==', '!='])).
|
||||||
expr500() -> infixr(expr600(), binop(['::', '++'])).
|
expr500() -> infixr(expr550(), binop(['::', '++'])).
|
||||||
|
expr550() -> infixl(expr600(), binop(['<<', '>>'])).
|
||||||
expr600() -> infixl(expr650(), binop(['+', '-'])).
|
expr600() -> infixl(expr650(), binop(['+', '-'])).
|
||||||
expr650() -> ?RULE(many(token('-')), expr700(), prefixes(_1, _2)).
|
expr650() -> ?RULE(many(token('-')), expr700(), prefixes(_1, _2)).
|
||||||
expr700() -> infixl(expr750(), binop(['*', '/', mod])).
|
expr700() -> infixl(expr750(), binop(['*', '/', mod])).
|
||||||
expr750() -> infixl(expr800(), binop(['^'])).
|
expr750() -> infixl(expr800(), binop(['^'])).
|
||||||
expr800() -> ?RULE(many(token('!')), expr900(), prefixes(_1, _2)).
|
expr800() -> ?RULE(many(token('!')), expr850(), prefixes(_1, _2)).
|
||||||
|
expr850() -> ?RULE(many(token('bnot')), expr900(), prefixes(_1, _2)).
|
||||||
expr900() -> ?RULE(exprAtom(), many(elim()), elim(_1, _2)).
|
expr900() -> ?RULE(exprAtom(), many(elim()), elim(_1, _2)).
|
||||||
|
|
||||||
exprAtom() ->
|
exprAtom() ->
|
||||||
@@ -517,7 +526,7 @@ 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_"]) of
|
case lists:member(lists:sublist(Name, 3), ["ak_", "ok_", "oq_", "ct_", "sg_"]) of
|
||||||
false -> Id;
|
false -> Id;
|
||||||
true ->
|
true ->
|
||||||
try aeser_api_encoder:decode(list_to_binary(Name)) of
|
try aeser_api_encoder:decode(list_to_binary(Name)) of
|
||||||
@@ -556,6 +565,7 @@ bracket_list(P) -> brackets(comma_sep(P)).
|
|||||||
-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} ].
|
||||||
@@ -603,7 +613,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'"});
|
||||||
@@ -613,14 +623,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}.
|
||||||
@@ -696,7 +706,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, Code} ->
|
{ok, AbsDir, 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 ->
|
||||||
@@ -706,9 +716,10 @@ 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(include_type, 1, Opts1, {include_type, IncludeType}),
|
Opts2 = lists:keystore(src_dir, 1, Opts1, {src_dir, AbsDir}),
|
||||||
|
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, Opts2) of
|
case parse_and_scan(file(), Code, Opts3) of
|
||||||
{ok, AST1} ->
|
{ok, AST1} ->
|
||||||
expand_includes(AST1 ++ AST, Included1, Acc, Opts);
|
expand_includes(AST1 ++ AST, Included1, Acc, Opts);
|
||||||
Err = {error, _} ->
|
Err = {error, _} ->
|
||||||
@@ -726,13 +737,12 @@ 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} ->
|
||||||
CandidateNames = [ filename:join(Dir, File) || Dir <- Paths ],
|
lists:foldr(fun(Path, {error, _}) -> read_file_(Path, File);
|
||||||
lists:foldr(fun(F, {error, _}) -> file:read_file(F);
|
(_Path, OK) -> OK end, {error, not_found}, Paths);
|
||||||
(_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, Src}
|
Src -> {ok, File, Src}
|
||||||
end;
|
end;
|
||||||
escript ->
|
escript ->
|
||||||
try
|
try
|
||||||
@@ -741,7 +751,7 @@ read_file(File, Opts) ->
|
|||||||
Archive = proplists:get_value(archive, Sections),
|
Archive = proplists:get_value(archive, Sections),
|
||||||
FileName = binary_to_list(filename:join([aesophia, 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, Src};
|
{ok, [{_, Src}]} -> {ok, escript, Src};
|
||||||
_ -> {error, not_found}
|
_ -> {error, not_found}
|
||||||
end
|
end
|
||||||
catch _:_ ->
|
catch _:_ ->
|
||||||
@@ -749,6 +759,13 @@ 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, aeso_utils:canonical_dir(filename:dirname(AbsFile)), Bin};
|
||||||
|
Err -> Err
|
||||||
|
end.
|
||||||
|
|
||||||
stdlib_options() ->
|
stdlib_options() ->
|
||||||
StdLibDir = aeso_stdlib:stdlib_include_path(),
|
StdLibDir = aeso_stdlib:stdlib_include_path(),
|
||||||
case filelib:is_dir(StdLibDir) of
|
case filelib:is_dir(StdLibDir) of
|
||||||
@@ -757,23 +774,37 @@ stdlib_options() ->
|
|||||||
end.
|
end.
|
||||||
|
|
||||||
get_include_code(File, Ann, Opts) ->
|
get_include_code(File, Ann, Opts) ->
|
||||||
case {read_file(File, Opts), read_file(File, stdlib_options())} of
|
%% Temporarily extend include paths with the directory of the current file
|
||||||
{{ok, Bin}, {ok, _}} ->
|
Opts1 = include_current_file_dir(Opts, Ann),
|
||||||
|
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, binary_to_list(Bin)}
|
false -> {ok, Dir, binary_to_list(Bin)}
|
||||||
end;
|
end;
|
||||||
{_, {ok, Bin}} ->
|
{_, {ok, _, Bin}} ->
|
||||||
{ok, binary_to_list(Bin)};
|
{ok, stdlib, binary_to_list(Bin)};
|
||||||
{{ok, Bin}, _} ->
|
{{ok, Dir, Bin}, _} ->
|
||||||
{ok, binary_to_list(Bin)};
|
{ok, Dir, 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);
|
||||||
@@ -787,3 +818,7 @@ 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.
|
||||||
|
|||||||
+18
-8
@@ -6,6 +6,7 @@
|
|||||||
%%% @end
|
%%% @end
|
||||||
%%%-------------------------------------------------------------------
|
%%%-------------------------------------------------------------------
|
||||||
-module(aeso_pretty).
|
-module(aeso_pretty).
|
||||||
|
-vsn("8.0.1").
|
||||||
|
|
||||||
-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]).
|
||||||
|
|
||||||
@@ -275,7 +276,9 @@ 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}) ->
|
||||||
@@ -385,7 +388,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(aeser_api_encoder:encode(Type, Bin)));
|
||||||
expr_p(_, {string, _, <<>>}) -> text("\"\"");
|
expr_p(_, {string, _, <<>>}) -> text("\"\"");
|
||||||
expr_p(_, {string, _, S}) ->
|
expr_p(_, {string, _, S}) ->
|
||||||
@@ -416,7 +420,7 @@ 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 aeso_syntax:get_ann(origin, Else) of
|
case aeso_syntax:get_ann(origin, Else) of
|
||||||
system when HideGenerated -> empty();
|
system when HideGenerated -> empty();
|
||||||
@@ -436,15 +440,20 @@ 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
|
||||||
bin_prec('|>') -> {150, 150, 200};
|
bin_prec('|>') -> {150, 150, 200};
|
||||||
bin_prec('||') -> {200, 300, 200};
|
bin_prec('||') -> {200, 300, 200};
|
||||||
bin_prec('&&') -> {300, 400, 300};
|
bin_prec('&&') -> {300, 325, 300};
|
||||||
|
bin_prec('bor') -> {325, 350, 325};
|
||||||
|
bin_prec('bxor') -> {350, 375, 350};
|
||||||
|
bin_prec('band') -> {375, 400, 375};
|
||||||
bin_prec('<') -> {400, 500, 500};
|
bin_prec('<') -> {400, 500, 500};
|
||||||
bin_prec('>') -> {400, 500, 500};
|
bin_prec('>') -> {400, 500, 500};
|
||||||
bin_prec('=<') -> {400, 500, 500};
|
bin_prec('=<') -> {400, 500, 500};
|
||||||
bin_prec('>=') -> {400, 500, 500};
|
bin_prec('>=') -> {400, 500, 500};
|
||||||
bin_prec('==') -> {400, 500, 500};
|
bin_prec('==') -> {400, 500, 500};
|
||||||
bin_prec('!=') -> {400, 500, 500};
|
bin_prec('!=') -> {400, 500, 500};
|
||||||
bin_prec('++') -> {500, 600, 500};
|
bin_prec('++') -> {500, 550, 500};
|
||||||
bin_prec('::') -> {500, 600, 500};
|
bin_prec('::') -> {500, 550, 500};
|
||||||
|
bin_prec('<<') -> {550, 600, 550};
|
||||||
|
bin_prec('>>') -> {550, 600, 550};
|
||||||
bin_prec('+') -> {600, 600, 650};
|
bin_prec('+') -> {600, 600, 650};
|
||||||
bin_prec('-') -> {600, 600, 650};
|
bin_prec('-') -> {600, 600, 650};
|
||||||
bin_prec('*') -> {700, 700, 750};
|
bin_prec('*') -> {700, 700, 750};
|
||||||
@@ -454,7 +463,8 @@ bin_prec('^') -> {750, 750, 800}.
|
|||||||
|
|
||||||
-spec un_prec(aeso_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}.
|
||||||
|
|
||||||
equals(Ann, A, B) ->
|
equals(Ann, A, B) ->
|
||||||
{app, [{format, infix} | Ann], {'=', Ann}, [A, B]}.
|
{app, [{format, infix} | Ann], {'=', Ann}, [A, B]}.
|
||||||
@@ -525,5 +535,5 @@ get_elifs(If = {'if', Ann, Cond, Then, Else}, Elifs) ->
|
|||||||
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}}.
|
||||||
|
|
||||||
|
|||||||
+2
-1
@@ -6,6 +6,7 @@
|
|||||||
%%% @end
|
%%% @end
|
||||||
%%%-------------------------------------------------------------------
|
%%%-------------------------------------------------------------------
|
||||||
-module(aeso_scan).
|
-module(aeso_scan).
|
||||||
|
-vsn("8.0.1").
|
||||||
|
|
||||||
-export([scan/1, utf8_encode/1]).
|
-export([scan/1, utf8_encode/1]).
|
||||||
|
|
||||||
@@ -45,7 +46,7 @@ lexer() ->
|
|||||||
|
|
||||||
Keywords = ["contract", "include", "let", "switch", "type", "record", "datatype", "if", "elif", "else", "function",
|
Keywords = ["contract", "include", "let", "switch", "type", "record", "datatype", "if", "elif", "else", "function",
|
||||||
"stateful", "payable", "true", "false", "mod", "public", "entrypoint", "private", "indexed", "namespace",
|
"stateful", "payable", "true", "false", "mod", "public", "entrypoint", "private", "indexed", "namespace",
|
||||||
"interface", "main", "using", "as", "for", "hiding"
|
"interface", "main", "using", "as", "for", "hiding", "band", "bor", "bxor", "bnot"
|
||||||
],
|
],
|
||||||
KW = string:join(Keywords, "|"),
|
KW = string:join(Keywords, "|"),
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
%%% @end
|
%%% @end
|
||||||
%%%-------------------------------------------------------------------
|
%%%-------------------------------------------------------------------
|
||||||
-module(aeso_scan_lib).
|
-module(aeso_scan_lib).
|
||||||
|
-vsn("8.0.1").
|
||||||
|
|
||||||
-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,
|
||||||
|
|||||||
+3
-2
@@ -9,9 +9,10 @@
|
|||||||
%%%-------------------------------------------------------------------
|
%%%-------------------------------------------------------------------
|
||||||
|
|
||||||
-module(aeso_stdlib).
|
-module(aeso_stdlib).
|
||||||
|
-vsn("8.0.1").
|
||||||
|
|
||||||
-export([stdlib_include_path/0]).
|
-export([stdlib_include_path/0]).
|
||||||
|
|
||||||
stdlib_include_path() ->
|
stdlib_include_path() ->
|
||||||
filename:join([code:priv_dir(aesophia), "stdlib"]).
|
{file, Path} = code:is_loaded(?MODULE),
|
||||||
|
filename:join(filename:dirname(filename:dirname(Path)), "priv/stdlib").
|
||||||
|
|||||||
+7
-4
@@ -7,10 +7,11 @@
|
|||||||
%%%-------------------------------------------------------------------
|
%%%-------------------------------------------------------------------
|
||||||
|
|
||||||
-module(aeso_syntax).
|
-module(aeso_syntax).
|
||||||
|
-vsn("8.0.1").
|
||||||
|
|
||||||
-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_line/0, ann_col/0, ann_origin/0, ann_format/0, ann/0]).
|
-export_type([ann_file/0, 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,8 +25,9 @@
|
|||||||
-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() :: [ {line, ann_line()} | {col, ann_col()} | {format, ann_format()} | {origin, ann_origin()}
|
-type ann() :: [ {file, ann_file()} | {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().
|
||||||
@@ -99,6 +101,7 @@
|
|||||||
| {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()}.
|
||||||
|
|
||||||
@@ -106,8 +109,8 @@
|
|||||||
|
|
||||||
-type bin_op() :: '+' | '-' | '*' | '/' | mod | '^'
|
-type bin_op() :: '+' | '-' | '*' | '/' | mod | '^'
|
||||||
| '++' | '::' | '<' | '>' | '=<' | '>=' | '==' | '!='
|
| '++' | '::' | '<' | '>' | '=<' | '>=' | '==' | '!='
|
||||||
| '||' | '&&' | '..' | '|>'.
|
| '||' | '&&' | '..' | 'band' | 'bor' | 'bxor' | '>>' | '<<' | '|>'.
|
||||||
-type un_op() :: '-' | '!'.
|
-type un_op() :: '-' | '!' | 'bnot'.
|
||||||
|
|
||||||
-type expr()
|
-type expr()
|
||||||
:: {lam, ann(), [arg()], expr()}
|
:: {lam, ann(), [arg()], expr()}
|
||||||
|
|||||||
@@ -5,8 +5,9 @@
|
|||||||
%%% @end
|
%%% @end
|
||||||
%%%-------------------------------------------------------------------
|
%%%-------------------------------------------------------------------
|
||||||
-module(aeso_syntax_utils).
|
-module(aeso_syntax_utils).
|
||||||
|
-vsn("8.0.1").
|
||||||
|
|
||||||
-export([used_ids/1, used_types/2, used/1]).
|
-export([used_ids/1, used_ids/2, used_types/2, used/1]).
|
||||||
|
|
||||||
-record(alg, {zero, plus, scoped}).
|
-record(alg, {zero, plus, scoped}).
|
||||||
|
|
||||||
@@ -31,11 +32,13 @@
|
|||||||
| aeso_syntax:field(aeso_syntax:expr())
|
| aeso_syntax:field(aeso_syntax:expr())
|
||||||
| aeso_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, type, T) end,
|
Type = fun(T) -> fold(Alg, Fun, TypeKind, T) end,
|
||||||
Expr = fun(E) -> fold(Alg, Fun, expr, E) end,
|
Expr = fun(E) -> fold(Alg, Fun, ExprKind, 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),
|
||||||
@@ -108,8 +111,16 @@ 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) ->
|
||||||
[ X || {{term, [X]}, _} <- used(E) ].
|
used_ids([], 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];
|
||||||
@@ -155,4 +166,3 @@ used(D) ->
|
|||||||
(_, _) -> #{}
|
(_, _) -> #{}
|
||||||
end, decl, D)),
|
end, decl, D)),
|
||||||
lists:filter(NotBound, Xs).
|
lists:filter(NotBound, Xs).
|
||||||
|
|
||||||
|
|||||||
+14
-1
@@ -5,11 +5,24 @@
|
|||||||
%%% @end
|
%%% @end
|
||||||
%%%-------------------------------------------------------------------
|
%%%-------------------------------------------------------------------
|
||||||
-module(aeso_utils).
|
-module(aeso_utils).
|
||||||
|
-vsn("8.0.1").
|
||||||
|
|
||||||
-export([scc/1]).
|
-export([scc/1, canonical_dir/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).
|
||||||
|
|||||||
+24
-1
@@ -5,16 +5,21 @@
|
|||||||
%%%-------------------------------------------------------------------
|
%%%-------------------------------------------------------------------
|
||||||
|
|
||||||
-module(aeso_vm_decode).
|
-module(aeso_vm_decode).
|
||||||
|
-vsn("8.0.1").
|
||||||
|
|
||||||
-export([ from_fate/2 ]).
|
-export([ from_fate/2 ]).
|
||||||
|
|
||||||
-include_lib("aebytecode/include/aeb_fate_data.hrl").
|
-include("$aebytecode_include/aeb_fate_data.hrl").
|
||||||
|
|
||||||
-spec from_fate(aeso_syntax:type(), aeb_fate_data:fate_type()) -> aeso_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) ->
|
||||||
@@ -78,6 +83,7 @@ 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],
|
||||||
@@ -99,6 +105,21 @@ from_fate_builtin(QType, Val) ->
|
|||||||
{["AENS", "pointee"], {variant, [1, 1, 1, 1], 3, {Addr}}} ->
|
{["AENS", "pointee"], {variant, [1, 1, 1, 1], 3, {Addr}}} ->
|
||||||
App(["AENS","ChannelPt"], [Chk(Adr, Addr)]);
|
App(["AENS","ChannelPt"], [Chk(Adr, Addr)]);
|
||||||
|
|
||||||
|
{["AENSv2", "name"], {variant, [3], 0, {Addr, TTL, Ptrs}}} ->
|
||||||
|
App(["AENSv2","Name"], [Chk(Adr, Addr), Chk(Qid(["Chain", "ttl"]), TTL),
|
||||||
|
Chk(Map(Str, Qid(["AENSv2", "pointee"])), Ptrs)]);
|
||||||
|
|
||||||
|
{["AENSv2", "pointee"], {variant, [1, 1, 1, 1, 1], 0, {Value}}} ->
|
||||||
|
App(["AENSv2","AccountPt"], [Chk(Adr, Value)]);
|
||||||
|
{["AENSv2", "pointee"], {variant, [1, 1, 1, 1, 1], 1, {Value}}} ->
|
||||||
|
App(["AENSv2","OraclePt"], [Chk(Adr, Value)]);
|
||||||
|
{["AENSv2", "pointee"], {variant, [1, 1, 1, 1, 1], 2, {Value}}} ->
|
||||||
|
App(["AENSv2","ContractPt"], [Chk(Adr, Value)]);
|
||||||
|
{["AENSv2", "pointee"], {variant, [1, 1, 1, 1, 1], 3, {Value}}} ->
|
||||||
|
App(["AENSv2","ChannelPt"], [Chk(Adr, Value)]);
|
||||||
|
{["AENSv2", "pointee"], {variant, [1, 1, 1, 1, 1], 4, {Value}}} ->
|
||||||
|
App(["AENSv2","DataPt"], [Chk(Bts, Value)]);
|
||||||
|
|
||||||
{["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)]);
|
||||||
|
|
||||||
@@ -170,3 +191,5 @@ 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,4 +1,5 @@
|
|||||||
-module(aeso_warnings).
|
-module(aeso_warnings).
|
||||||
|
-vsn("8.0.1").
|
||||||
|
|
||||||
-record(warn, { pos :: aeso_errors:pos()
|
-record(warn, { pos :: aeso_errors:pos()
|
||||||
, message :: iolist()
|
, message :: iolist()
|
||||||
|
|||||||
@@ -1,13 +1,12 @@
|
|||||||
{application, aesophia,
|
{application, aesophia,
|
||||||
[{description, "Compiler for Aeternity Sophia language"},
|
[{description, "Compiler for Aeternity Sophia language"},
|
||||||
{vsn, "7.1.0"},
|
{vsn, "8.0.1"},
|
||||||
{registered, []},
|
{registered, []},
|
||||||
{applications,
|
{applications,
|
||||||
[kernel,
|
[kernel,
|
||||||
stdlib,
|
stdlib,
|
||||||
jsx,
|
jsx,
|
||||||
syntax_tools,
|
syntax_tools,
|
||||||
getopt,
|
|
||||||
aebytecode,
|
aebytecode,
|
||||||
eblake2
|
eblake2
|
||||||
]},
|
]},
|
||||||
|
|||||||
@@ -85,6 +85,7 @@ 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"]},
|
||||||
@@ -116,6 +117,7 @@ compilable_contracts() ->
|
|||||||
{"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", []},
|
||||||
|
|||||||
+130
-15
@@ -70,6 +70,7 @@ simple_compile_test_() ->
|
|||||||
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_unused_include_no_include", [warn_all]),
|
||||||
|
#{ warnings := [] } = compile("warning_used_record_typedef", [warn_all]),
|
||||||
check_warnings(warnings(), Warnings)
|
check_warnings(warnings(), Warnings)
|
||||||
end} ] ++
|
end} ] ++
|
||||||
[].
|
[].
|
||||||
@@ -161,6 +162,7 @@ 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",
|
||||||
@@ -170,6 +172,7 @@ 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",
|
||||||
@@ -222,6 +225,8 @@ compilable_contracts() ->
|
|||||||
"unapplied_contract_call",
|
"unapplied_contract_call",
|
||||||
"unapplied_named_arg_builtin",
|
"unapplied_named_arg_builtin",
|
||||||
"resolve_field_constraint_by_arity",
|
"resolve_field_constraint_by_arity",
|
||||||
|
"toplevel_constants",
|
||||||
|
"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.
|
||||||
].
|
].
|
||||||
|
|
||||||
@@ -286,7 +291,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() ->
|
||||||
@@ -442,6 +451,10 @@ 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)
|
||||||
@@ -599,6 +612,21 @@ 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"
|
||||||
@@ -623,7 +651,8 @@ 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 length of byte array.">>])
|
"Cannot resolve type of byte array in\n"
|
||||||
|
" 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"
|
||||||
@@ -658,10 +687,6 @@ 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. "
|
||||||
@@ -859,17 +884,21 @@ 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(9,5)
|
[<<?Pos(5,5)
|
||||||
"Duplicate definitions of `f` at\n"
|
"Cannot unify `char` and `int`\n"
|
||||||
" - line 8, column 5\n"
|
"when implementing the entrypoint `f` from the interface `I1`">>
|
||||||
" - 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 entrypoint `f` from the interface `I1` in the contract `I2`">>
|
||||||
@@ -923,6 +952,9 @@ 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)`">>,
|
||||||
@@ -971,6 +1003,9 @@ 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)`">>,
|
||||||
@@ -1014,6 +1049,9 @@ failing_contracts() ->
|
|||||||
<<?Pos(19,13)
|
<<?Pos(19,13)
|
||||||
"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 pattern `o07 : oracle(Animal, Cat)` against the expected type `oracle(Cat, Animal)`">>,
|
"when checking the type of the pattern `o07 : oracle(Animal, Cat)` against the expected type `oracle(Cat, Animal)`">>,
|
||||||
|
<<?Pos(19,13)
|
||||||
|
"Cannot unify `Animal` and `Cat` in a covariant context\n"
|
||||||
|
"when checking the type of the pattern `o07 : oracle(Animal, Cat)` against the expected type `oracle(Cat, Animal)`">>,
|
||||||
<<?Pos(20,13)
|
<<?Pos(20,13)
|
||||||
"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 pattern `o08 : oracle(Animal, Cat)` against the expected type `oracle(Cat, Cat)`">>,
|
"when checking the type of the pattern `o08 : oracle(Animal, Cat)` against the expected type `oracle(Cat, Cat)`">>,
|
||||||
@@ -1038,6 +1076,9 @@ failing_contracts() ->
|
|||||||
<<?Pos(42,13)
|
<<?Pos(42,13)
|
||||||
"Cannot unify `Animal` and `Cat` in a covariant context\n"
|
"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)`">>,
|
"when checking the type of the pattern `q13 : oracle_query(Cat, Cat)` against the expected type `oracle_query(Animal, Animal)`">>,
|
||||||
|
<<?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)
|
<<?Pos(43,13)
|
||||||
"Cannot unify `Animal` and `Cat` in a covariant context\n"
|
"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)`">>,
|
"when checking the type of the pattern `q14 : oracle_query(Cat, Cat)` against the expected type `oracle_query(Animal, Cat)`">>,
|
||||||
@@ -1099,19 +1140,19 @@ failing_contracts() ->
|
|||||||
])
|
])
|
||||||
, ?TYPE_ERROR(polymorphic_aens_resolve,
|
, ?TYPE_ERROR(polymorphic_aens_resolve,
|
||||||
[<<?Pos(4,5)
|
[<<?Pos(4,5)
|
||||||
"Invalid return type of `AENS.resolve`:\n"
|
"Invalid return type of `AENSv2.resolve`:\n"
|
||||||
" `'a`\n"
|
" `'a`\n"
|
||||||
"It must be a `string` or a pubkey type (`address`, `oracle`, 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 `AENS.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`, `oracle`, 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 `AENS.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`, `oracle`, etc)">>
|
"It must be a `string` or a pubkey type (`address`, `oracle`, etc)">>
|
||||||
])
|
])
|
||||||
@@ -1193,6 +1234,78 @@ failing_contracts() ->
|
|||||||
<<?Pos(13,20)
|
<<?Pos(13,20)
|
||||||
"Found a hole of type `'a`">>
|
"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_() ->
|
||||||
@@ -1240,7 +1353,9 @@ validate(Contract1, Contract2) ->
|
|||||||
true -> [debug_mode];
|
true -> [debug_mode];
|
||||||
false -> []
|
false -> []
|
||||||
end ++
|
end ++
|
||||||
[{include, {file_system, [aeso_test_utils:contract_path()]}}]);
|
[ {src_file, lists:concat([Contract2, ".aes"])}
|
||||||
|
, {include, {file_system, [aeso_test_utils:contract_path()]}}
|
||||||
|
]);
|
||||||
Error -> print_and_throw(Error)
|
Error -> print_and_throw(Error)
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,40 @@
|
|||||||
|
-module(aeso_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} = aeso_compiler:encode_value(?EMPTY, EType, Value, []),
|
||||||
|
{ok, Expr} = aeso_compiler:decode_value(?EMPTY, DType, SerRes, []),
|
||||||
|
Value2 = prettypr:format(aeso_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)"}
|
||||||
|
].
|
||||||
|
|
||||||
@@ -53,7 +53,7 @@ simple_contracts_test_() ->
|
|||||||
%% associativity
|
%% associativity
|
||||||
[ RightAssoc(Op) || Op <- ["||", "&&", "::", "++"] ],
|
[ RightAssoc(Op) || Op <- ["||", "&&", "::", "++"] ],
|
||||||
[ NonAssoc(Op) || Op <- ["==", "!=", "<", ">", "=<", ">="] ],
|
[ NonAssoc(Op) || Op <- ["==", "!=", "<", ">", "=<", ">="] ],
|
||||||
[ LeftAssoc(Op) || Op <- ["+", "-", "*", "/", "mod"] ],
|
[ LeftAssoc(Op) || Op <- ["+", "-", "*", "/", "mod", "band", "bor", "bxor", "<<", ">>"] ],
|
||||||
|
|
||||||
%% precedence
|
%% precedence
|
||||||
[ Stronger(Op2, Op1) || [T1 , T2 | _] <- tails(Tiers), Op1 <- T1, Op2 <- T2 ],
|
[ Stronger(Op2, Op1) || [T1 , T2 | _] <- tails(Tiers), Op1 <- T1, Op2 <- T2 ],
|
||||||
|
|||||||
@@ -39,7 +39,8 @@ all_tokens() ->
|
|||||||
%% Symbols
|
%% Symbols
|
||||||
lists:map(Lit, [',', '.', ';', '|', ':', '(', ')', '[', ']', '{', '}']) ++
|
lists:map(Lit, [',', '.', ';', '|', ':', '(', ')', '[', ']', '{', '}']) ++
|
||||||
%% Operators
|
%% Operators
|
||||||
lists:map(Lit, ['=', '==', '!=', '>', '<', '>=', '=<', '-', '+', '++', '*', '/', mod, ':', '::', '->', '=>', '||', '&&', '!']) ++
|
lists:map(Lit, ['=', '==', '!=', '>', '<', '>=', '=<', '-', '+', '++', '*', '/', mod,
|
||||||
|
':', '::', '->', '=>', '||', '&&', '!', 'band', 'bor', 'bxor', 'bnot' ,'<<', '>>']) ++
|
||||||
%% Keywords
|
%% Keywords
|
||||||
lists:map(Lit, [contract, type, 'let', switch]) ++
|
lists:map(Lit, [contract, type, 'let', switch]) ++
|
||||||
%% Comment token (not an actual token), just for tests
|
%% Comment token (not an actual token), just for tests
|
||||||
|
|||||||
+17
-17
@@ -6,77 +6,77 @@ main contract AENSTest =
|
|||||||
// Name resolution
|
// Name resolution
|
||||||
|
|
||||||
stateful entrypoint resolve_word(name : string, key : string) : option(address) =
|
stateful entrypoint resolve_word(name : string, key : string) : option(address) =
|
||||||
AENS.resolve(name, key)
|
AENSv2.resolve(name, key)
|
||||||
|
|
||||||
stateful entrypoint resolve_string(name : string, key : string) : option(string) =
|
stateful entrypoint resolve_string(name : string, key : string) : option(string) =
|
||||||
AENS.resolve(name, key)
|
AENSv2.resolve(name, key)
|
||||||
|
|
||||||
stateful entrypoint resolve_contract(name : string, key : string) : option(C) =
|
stateful entrypoint resolve_contract(name : string, key : string) : option(C) =
|
||||||
AENS.resolve(name, key)
|
AENSv2.resolve(name, key)
|
||||||
|
|
||||||
stateful entrypoint resolve_oracle(name : string, key : string) : option(oracle(int, int)) =
|
stateful entrypoint resolve_oracle(name : string, key : string) : option(oracle(int, int)) =
|
||||||
AENS.resolve(name, key)
|
AENSv2.resolve(name, key)
|
||||||
|
|
||||||
stateful entrypoint resolve_oracle_query(name : string, key : string) : option(oracle_query(int, int)) =
|
stateful entrypoint resolve_oracle_query(name : string, key : string) : option(oracle_query(int, int)) =
|
||||||
AENS.resolve(name, key)
|
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)
|
||||||
chash : hash) : unit = // Commitment hash
|
chash : hash) : unit = // Commitment hash
|
||||||
AENS.preclaim(addr, chash)
|
AENSv2.preclaim(addr, chash)
|
||||||
|
|
||||||
stateful entrypoint signedPreclaim(addr : address, // Claim on behalf of this account (can be Contract.address)
|
stateful entrypoint signedPreclaim(addr : address, // Claim on behalf of this account (can be Contract.address)
|
||||||
chash : hash, // Commitment hash
|
chash : hash, // Commitment hash
|
||||||
sign : signature) : unit = // Signed by addr (if not Contract.address)
|
sign : signature) : unit = // Signed by addr (if not Contract.address)
|
||||||
AENS.preclaim(addr, chash, signature = sign)
|
AENSv2.preclaim(addr, chash, signature = sign)
|
||||||
|
|
||||||
stateful entrypoint claim(addr : address,
|
stateful entrypoint claim(addr : address,
|
||||||
name : string,
|
name : string,
|
||||||
salt : int,
|
salt : int,
|
||||||
name_fee : int) : unit =
|
name_fee : int) : unit =
|
||||||
AENS.claim(addr, name, salt, name_fee)
|
AENSv2.claim(addr, name, salt, name_fee)
|
||||||
|
|
||||||
stateful entrypoint signedClaim(addr : address,
|
stateful entrypoint signedClaim(addr : address,
|
||||||
name : string,
|
name : string,
|
||||||
salt : int,
|
salt : int,
|
||||||
name_fee : int,
|
name_fee : int,
|
||||||
sign : signature) : unit =
|
sign : signature) : unit =
|
||||||
AENS.claim(addr, name, salt, name_fee, signature = sign)
|
AENSv2.claim(addr, name, salt, name_fee, signature = sign)
|
||||||
|
|
||||||
|
|
||||||
stateful entrypoint update(owner : address,
|
stateful entrypoint update(owner : address,
|
||||||
name : string,
|
name : string,
|
||||||
ttl : option(Chain.ttl),
|
ttl : option(Chain.ttl),
|
||||||
client_ttl : option(int),
|
client_ttl : option(int),
|
||||||
pointers : option(map(string, AENS.pointee))) : unit =
|
pointers : option(map(string, AENSv2.pointee))) : unit =
|
||||||
AENS.update(owner, name, ttl, client_ttl, pointers)
|
AENSv2.update(owner, name, ttl, client_ttl, pointers)
|
||||||
|
|
||||||
stateful entrypoint signedUpdate(owner : address,
|
stateful entrypoint signedUpdate(owner : address,
|
||||||
name : string,
|
name : string,
|
||||||
ttl : option(Chain.ttl),
|
ttl : option(Chain.ttl),
|
||||||
client_ttl : option(int),
|
client_ttl : option(int),
|
||||||
pointers : option(map(string, AENS.pointee)),
|
pointers : option(map(string, AENSv2.pointee)),
|
||||||
sign : signature) : unit =
|
sign : signature) : unit =
|
||||||
AENS.update(owner, name, ttl, client_ttl, pointers, signature = sign)
|
AENSv2.update(owner, name, ttl, client_ttl, pointers, signature = sign)
|
||||||
|
|
||||||
|
|
||||||
stateful entrypoint transfer(owner : address,
|
stateful entrypoint transfer(owner : address,
|
||||||
new_owner : address,
|
new_owner : address,
|
||||||
name : string) : unit =
|
name : string) : unit =
|
||||||
AENS.transfer(owner, new_owner, name)
|
AENSv2.transfer(owner, new_owner, name)
|
||||||
|
|
||||||
stateful entrypoint signedTransfer(owner : address,
|
stateful entrypoint signedTransfer(owner : address,
|
||||||
new_owner : address,
|
new_owner : address,
|
||||||
name : string,
|
name : string,
|
||||||
sign : signature) : unit =
|
sign : signature) : unit =
|
||||||
AENS.transfer(owner, new_owner, name, signature = sign)
|
AENSv2.transfer(owner, new_owner, name, signature = sign)
|
||||||
|
|
||||||
stateful entrypoint revoke(owner : address,
|
stateful entrypoint revoke(owner : address,
|
||||||
name : string) : unit =
|
name : string) : unit =
|
||||||
AENS.revoke(owner, name)
|
AENSv2.revoke(owner, name)
|
||||||
|
|
||||||
stateful entrypoint signedRevoke(owner : address,
|
stateful entrypoint signedRevoke(owner : address,
|
||||||
name : string,
|
name : string,
|
||||||
sign : signature) : unit =
|
sign : signature) : unit =
|
||||||
AENS.revoke(owner, name, signature = sign)
|
AENSv2.revoke(owner, name, signature = sign)
|
||||||
|
|||||||
@@ -1,17 +1,32 @@
|
|||||||
contract AENSUpdate =
|
include "Option.aes"
|
||||||
stateful entrypoint update_name(owner : address, name : string) =
|
include "String.aes"
|
||||||
let p1 : AENS.pointee = AENS.AccountPt(Call.caller)
|
include "AENSCompat.aes"
|
||||||
let p2 : AENS.pointee = AENS.OraclePt(Call.caller)
|
contract interface OldAENSContract =
|
||||||
let p3 : AENS.pointee = AENS.ContractPt(Call.caller)
|
entrypoint set : (string, string, AENS.pointee) => unit
|
||||||
let p4 : AENS.pointee = AENS.ChannelPt(Call.caller)
|
entrypoint lookup : (string, string) => AENS.pointee
|
||||||
AENS.update(owner, name, None, None,
|
|
||||||
|
main contract AENSUpdate =
|
||||||
|
stateful entrypoint update_name(owner : address, name : string, b : bytes(2)) =
|
||||||
|
let p1 : AENSv2.pointee = AENSv2.AccountPt(Call.caller)
|
||||||
|
let p2 : AENSv2.pointee = AENSv2.OraclePt(Call.caller)
|
||||||
|
let p3 : AENSv2.pointee = AENSv2.ContractPt(Call.caller)
|
||||||
|
let p4 : AENSv2.pointee = AENSv2.ChannelPt(Call.caller)
|
||||||
|
let p5 : AENSv2.pointee = AENSv2.DataPt(String.to_bytes("any something will do"))
|
||||||
|
let p6 : AENSv2.pointee = AENSv2.DataPt(Int.to_bytes(1345, 4))
|
||||||
|
AENSv2.update(owner, name, None, None,
|
||||||
Some({ ["account_pubkey"] = p1, ["oracle_pubkey"] = p2,
|
Some({ ["account_pubkey"] = p1, ["oracle_pubkey"] = p2,
|
||||||
["contract_pubkey"] = p3, ["misc"] = p4 }))
|
["contract_pubkey"] = p3, ["misc"] = p4, ["data"] = p5, ["data2"] = p6 }))
|
||||||
|
|
||||||
|
stateful entrypoint old_interaction(c : OldAENSContract, owner : address, name : string) =
|
||||||
|
let p : AENS.pointee = c.lookup(name, "key1")
|
||||||
|
AENSv2.update(owner, name, None, None, Some({ ["key1"] = AENSCompat.pointee_to_V2(p) }))
|
||||||
|
switch(AENSv2.lookup(name))
|
||||||
|
Some(AENSv2.Name(_, _, pt_map)) =>
|
||||||
|
c.set(name, "key2", Option.force(AENSCompat.pointee_from_V2(pt_map["key1"])))
|
||||||
|
|
||||||
entrypoint get_ttl(name : string) =
|
entrypoint get_ttl(name : string) =
|
||||||
switch(AENS.lookup(name))
|
switch(AENSv2.lookup(name))
|
||||||
Some(AENS.Name(_, FixedTTL(ttl), _)) => ttl
|
Some(AENSv2.Name(_, FixedTTL(ttl), _)) => ttl
|
||||||
|
|
||||||
entrypoint expiry(o : oracle(int, int)) : int =
|
entrypoint expiry(o : oracle(int, int)) : int =
|
||||||
Oracle.expiry(o)
|
Oracle.expiry(o)
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
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
|
||||||
@@ -33,6 +34,8 @@ 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,
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ contract BadAENSresolve =
|
|||||||
type t('a) = option(list('a))
|
type t('a) = option(list('a))
|
||||||
|
|
||||||
function fail() : t(int) =
|
function fail() : t(int) =
|
||||||
AENS.resolve("foo.aet", "whatever")
|
AENSv2.resolve("foo.aet", "whatever")
|
||||||
|
|
||||||
entrypoint main_fun() = ()
|
entrypoint main_fun() = ()
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
contract BadAENSresolve =
|
contract BadAENSresolve =
|
||||||
using AENS
|
using AENSv2
|
||||||
|
|
||||||
type t('a) = option(list('a))
|
type t('a) = option(list('a))
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
// 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)
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
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]
|
||||||
@@ -6,3 +6,5 @@ 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)
|
||||||
|
|||||||
@@ -0,0 +1,15 @@
|
|||||||
|
contract C =
|
||||||
|
entrypoint test() =
|
||||||
|
let a : int = 23
|
||||||
|
let b : int = 52
|
||||||
|
let c = a bor b
|
||||||
|
let d = c bxor b
|
||||||
|
let e = d band b
|
||||||
|
let f = bnot a
|
||||||
|
let g = f << 2
|
||||||
|
let h = g >> 2
|
||||||
|
let i = Int.mulmod(a, b, h)
|
||||||
|
let j = Crypto.poseidon(i, a)
|
||||||
|
let k : bytes(32) = Address.to_bytes(Call.origin)
|
||||||
|
let l = sg_MhibzTP1wWzGCTjtPFr1TiPqRJrrJqw7auvEuF5i3FdoALWqXLBDY6xxRRNUSPHK3EQTnTzF12EyspkxrSMxVHKsZeSMj
|
||||||
|
(a bor b band c bxor a << bnot b >> a, k, l)
|
||||||
@@ -2,7 +2,8 @@
|
|||||||
|
|
||||||
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}
|
||||||
@@ -11,3 +12,6 @@ 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})
|
||||||
|
|||||||
@@ -0,0 +1,4 @@
|
|||||||
|
include "../dir2/baz.aes"
|
||||||
|
namespace D =
|
||||||
|
function g() = E.h()
|
||||||
|
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
namespace E =
|
||||||
|
function h() = 42
|
||||||
|
|
||||||
@@ -20,6 +20,8 @@ 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
|
||||||
|
|
||||||
@@ -57,3 +59,5 @@ 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
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
contract PolymorphicAENSresolve =
|
contract PolymorphicAENSresolve =
|
||||||
|
|
||||||
function fail() : option('a) =
|
function fail() : option('a) =
|
||||||
AENS.resolve("foo.aet", "whatever")
|
AENSv2.resolve("foo.aet", "whatever")
|
||||||
|
|
||||||
entrypoint main_fun() = ()
|
entrypoint main_fun() = ()
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,3 @@
|
|||||||
|
include "./dir1/bar.aes"
|
||||||
|
contract C =
|
||||||
|
entrypoint f() = D.g()
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
contract C =
|
||||||
|
entrypoint too_many(
|
||||||
|
(_, _, _, _, _, _, _, _, _, _),
|
||||||
|
(_, _, _, _, _, _, _, _, _, _),
|
||||||
|
(_, _, _, _, _, _, _, _, _, _),
|
||||||
|
(_, _, _, _, _, _, _, _, _, _),
|
||||||
|
(_, _, _, _, _, _, _, _, _, _),
|
||||||
|
(_, _, _, _, _, _, _, _, _, _),
|
||||||
|
(_, _, _, _, _, _, _, _, _, _),
|
||||||
|
(_, _, _, _, _, _, _, _, _, _),
|
||||||
|
(_, _, _, _, _, _, _, _, _, _),
|
||||||
|
(_, _, _, _, _, _, _, _, _, _),
|
||||||
|
|
||||||
|
(_, _, _, _, _, _, _, _, _, _),
|
||||||
|
(_, _, _, _, _, _, _, _, _, _),
|
||||||
|
(_, _, _, _, _, _, _, _, _, _),
|
||||||
|
(_, _, _, _, _, _, _, _, _, _),
|
||||||
|
(_, _, _, _, _, _, _, _, _, _),
|
||||||
|
(_, _, _, _, _, _, _, _, _, _),
|
||||||
|
(_, _, _, _, _, _, _, _, _, _),
|
||||||
|
(_, _, _, _, _, _, _, _, _, _),
|
||||||
|
(_, _, _, _, _, _, _, _, _, _),
|
||||||
|
(_, _, _, _, _, _, _, _, _, _),
|
||||||
|
|
||||||
|
(_, _, _, _, _, _, _, _, _, _),
|
||||||
|
(_, _, _, _, _, _, _, _, _, _),
|
||||||
|
(_, _, _, _, _, _, _, _, _, _),
|
||||||
|
(_, _, _, _, _, _, _, _, _, _),
|
||||||
|
(_, _, _, _, _, _, _, _, _, _),
|
||||||
|
(_, _, _, _, _, _, _, _, _, _)) = 0
|
||||||
|
|
||||||
|
entrypoint not_too_many(
|
||||||
|
(_, _, _, _, _, _, _, _, _, _),
|
||||||
|
(_, _, _, _, _, _, _, _, _, _),
|
||||||
|
(_, _, _, _, _, _, _, _, _, _),
|
||||||
|
(_, _, _, _, _, _, _, _, _, _),
|
||||||
|
(_, _, _, _, _, _, _, _, _, _),
|
||||||
|
(_, _, _, _, _, _, _, _, _, _),
|
||||||
|
(_, _, _, _, _, _, _, _, _, _),
|
||||||
|
(_, _, _, _, _, _, _, _, _, _),
|
||||||
|
(_, _, _, _, _, _, _, _, _, _),
|
||||||
|
(_, _, _, _, _, _, _, _, _, _),
|
||||||
|
|
||||||
|
(_, _, _, _, _, _, _, _, _, _),
|
||||||
|
(_, _, _, _, _, _, _, _, _, _),
|
||||||
|
(_, _, _, _, _, _, _, _, _, _),
|
||||||
|
(_, _, _, _, _, _, _, _, _, _),
|
||||||
|
(_, _, _, _, _, _, _, _, _, _),
|
||||||
|
(_, _, _, _, _, _, _, _, _, _),
|
||||||
|
(_, _, _, _, _, _, _, _, _, _),
|
||||||
|
(_, _, _, _, _, _, _, _, _, _),
|
||||||
|
(_, _, _, _, _, _, _, _, _, _),
|
||||||
|
(_, _, _, _, _, _, _, _, _, _),
|
||||||
|
|
||||||
|
(_, _, _, _, _, _, _, _, _, _),
|
||||||
|
(_, _, _, _, _, _, _, _, _, _),
|
||||||
|
(_, _, _, _, _, _, _, _, _, _),
|
||||||
|
(_, _, _, _, _, _, _, _, _, _),
|
||||||
|
(_, _, _, _, _, _, _, _, _, _),
|
||||||
|
(_, _, _, _, _, _)) = 0
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
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 = ok_2YNyxd6TRJPNrTcEDCe9ra59SVUdp9FR9qWC5msKZWYD9bP9z5
|
||||||
|
let c20 = oq_2oRvyowJuJnEkxy58Ckkw77XfWJrmRgmGaLzhdqb67SKEL1gPY
|
||||||
|
let c21 = ct_Ez6MyeTMm17YnTnDdHTSrzMEBKmy7Uz2sXu347bTDPgVH2ifJ : C
|
||||||
|
let c22 = N.nsconst
|
||||||
|
let c23 = c01
|
||||||
|
let c24 = c11.name
|
||||||
|
let c25 : 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 f24() = c24
|
||||||
|
entrypoint f25() = c25
|
||||||
|
entrypoint fqual() = C.c01
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
contract G =
|
||||||
|
let const = 1
|
||||||
|
|
||||||
|
main contract C =
|
||||||
|
let c = G.const
|
||||||
|
|
||||||
|
stateful entrypoint f() =
|
||||||
|
let g = Chain.create() : G
|
||||||
|
|
||||||
|
g.const
|
||||||
|
g.const()
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
contract C =
|
||||||
|
let selfcycle = selfcycle
|
||||||
|
|
||||||
|
let cycle1 = cycle2
|
||||||
|
let cycle2 = cycle3
|
||||||
|
let cycle3 = cycle1
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
contract interface I =
|
||||||
|
let (x::y::_) = [1,2,3]
|
||||||
|
let c = 10
|
||||||
|
let d = 10
|
||||||
|
|
||||||
|
contract C =
|
||||||
|
entrypoint init() = ()
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
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
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
contract C =
|
||||||
|
let x::_ = [1,2,3,4]
|
||||||
|
let y::(p = z::_) = [1,2,3,4]
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
contract C =
|
|
||||||
let this_is_illegal = 2/0
|
|
||||||
entrypoint this_is_legal() = 2/0
|
|
||||||
@@ -2,10 +2,10 @@
|
|||||||
// Named argument builtins are:
|
// Named argument builtins are:
|
||||||
// Oracle.register
|
// Oracle.register
|
||||||
// Oracle.respond
|
// Oracle.respond
|
||||||
// AENS.preclaim
|
// AENSv2.preclaim
|
||||||
// AENS.claim
|
// AENSv2.claim
|
||||||
// AENS.transfer
|
// AENSv2.transfer
|
||||||
// AENS.revoke
|
// AENSv2.revoke
|
||||||
// Oracle.extend
|
// Oracle.extend
|
||||||
include "String.aes"
|
include "String.aes"
|
||||||
contract UnappliedBuiltins =
|
contract UnappliedBuiltins =
|
||||||
@@ -28,7 +28,7 @@ contract UnappliedBuiltins =
|
|||||||
function oracle_get_answer() = Oracle.get_answer : (o, _) => _
|
function oracle_get_answer() = Oracle.get_answer : (o, _) => _
|
||||||
function oracle_check() = Oracle.check : o => _
|
function oracle_check() = Oracle.check : o => _
|
||||||
function oracle_check_query() = Oracle.check_query : (o, _) => _
|
function oracle_check_query() = Oracle.check_query : (o, _) => _
|
||||||
function aens_resolve() = AENS.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, _) => _
|
||||||
function map_member() = Map.member : (_, m) => _
|
function map_member() = Map.member : (_, m) => _
|
||||||
@@ -36,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
|
function crypto_verify_sig() = Crypto.verify_sig : (bytes(), _, _) => _
|
||||||
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
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
contract Test =
|
||||||
|
type option_int = option(int)
|
||||||
|
record option_point = {x: int, y: option_int}
|
||||||
|
|
||||||
|
entrypoint test_option_record(a: option_point) = a
|
||||||
@@ -65,3 +65,24 @@ contract Remote =
|
|||||||
contract C =
|
contract C =
|
||||||
payable stateful entrypoint
|
payable stateful entrypoint
|
||||||
call_missing_con() : int = (ct_1111111111111111111111111111112JF6Dz72 : Remote).id(value = 1, 0)
|
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
|
||||||
|
|||||||
@@ -0,0 +1,21 @@
|
|||||||
|
{name,"Sophia Compiler"}.
|
||||||
|
{type,lib}.
|
||||||
|
{modules,[]}.
|
||||||
|
{prefix,none}.
|
||||||
|
{desc,"The Sophia smart contract language for FATE blockchains"}.
|
||||||
|
{author,"QPQ AG & Aeternity Foundation"}.
|
||||||
|
{package_id,{"otpr","aesophia",{8,0,1}}}.
|
||||||
|
{deps,[{"otpr","aebytecode",{3,2,1}},
|
||||||
|
{"otpr","getopt",{1,0,2}},
|
||||||
|
{"otpr","eblake2",{1,0,0}},
|
||||||
|
{"otpr","zj",{1,1,0}}]}.
|
||||||
|
{key_name,none}.
|
||||||
|
{a_email,[]}.
|
||||||
|
{c_email,[]}.
|
||||||
|
{copyright,"(c) 2024 QPQ AG, 2018 Aeternity Foundation"}.
|
||||||
|
{file_exts,[]}.
|
||||||
|
{license,skip}.
|
||||||
|
{repo_url,"https://gitlab.com/ioecs/aesophia"}.
|
||||||
|
{tags,["gaju","gajumaru","blockchain","sophia","crypto","ae","compiler",
|
||||||
|
"puck"]}.
|
||||||
|
{ws_url,[]}.
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
#! /bin/bash
|
||||||
|
|
||||||
|
# This is a small pre-packaging source generation and include correction script that should be
|
||||||
|
# run before packaging this project for use with ZX/Zomp.
|
||||||
|
|
||||||
|
rm -rf _build
|
||||||
|
cd src
|
||||||
|
for f in $(ls *.erl)
|
||||||
|
do
|
||||||
|
echo "Updating includes in: $f"
|
||||||
|
sed -i 's/aebytecode\/include\///g' "$f"
|
||||||
|
sed -i 's/\.\.\/include\///g' "$f"
|
||||||
|
sed -i 's/include_lib/include/g' "$f"
|
||||||
|
done
|
||||||
|
sed -i 's/aeb_opcodes\.hrl/\$aebytecode_include\/aeb_opcodes\.hrl/' aeso_compiler.erl
|
||||||
|
sed -i 's/aeb_fate_data\.hrl/\$aebytecode_include\/aeb_fate_data\.hrl/' aeso_vm_decode.erl
|
||||||
|
cd ..
|
||||||
|
rm -f ebin/*.beam
|
||||||
|
rm -f rebar*
|
||||||
Reference in New Issue
Block a user