Compare commits
7 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 1538af79ed | |||
| c3788b2b5a | |||
| 32a98112d3 | |||
| acd2fa8184 | |||
| c5394c3068 | |||
| a347795475 | |||
| c6df9e875f |
@@ -2,4 +2,4 @@ mkdocs==1.4.2
|
||||
mkdocs-simple-hooks==0.1.5
|
||||
mkdocs-material==9.0.9
|
||||
mike==1.1.2
|
||||
pygments==2.17.2
|
||||
pygments==2.14.0
|
||||
@@ -24,4 +24,3 @@ current_counterexample.eqc
|
||||
test/contracts/test.aes
|
||||
__pycache__
|
||||
.docssite/docs/*.md
|
||||
.vscode
|
||||
|
||||
+6
-45
@@ -4,18 +4,7 @@ All notable changes to this project will be documented in this file.
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [Unreleased]
|
||||
### Added
|
||||
- Added a check for number of type variables in a type signature; it is serialized using 8 bits,
|
||||
so the upper limit is 256.
|
||||
### Changed
|
||||
### Removed
|
||||
|
||||
## [8.0.1]
|
||||
### Changed
|
||||
- Upgrade aebytecode to v3.4.1 to fix C warnings
|
||||
|
||||
## [8.0.0]
|
||||
## [CERES 8.0.0]
|
||||
### Added
|
||||
- Bitwise operations for integers: `band`, `bor`, `bxor`, `bnot`, `<<` and `>>`.
|
||||
- `Int.mulmod` - combined builtin operation for multiplication and modulus.
|
||||
@@ -23,7 +12,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
- `Address.to_bytes` - convert an address to its binary representation (for hashing, etc.).
|
||||
- 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.pointee`, where the latter now has a constructor `DataPt(string)`. All
|
||||
AENS actions have been moved to `AENSv2`, and `AENSv2.lookup` and
|
||||
`AENSv2.update` consume and produce the new types. The old `AENS` namespace
|
||||
only contains the old datatypes, that can be used to interface existing
|
||||
@@ -34,38 +23,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
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]
|
||||
## [Unreleased]
|
||||
### Added
|
||||
### 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.
|
||||
### Removed
|
||||
### 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
|
||||
@@ -456,12 +422,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
- Simplify calldata creation - instead of passing a compiled contract, simply
|
||||
pass a (stubbed) contract string.
|
||||
|
||||
[Unreleased]: https://github.com/aeternity/aesophia/compare/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
|
||||
[Unreleased]: https://github.com/aeternity/aesophia/compare/v7.2.1...HEAD
|
||||
[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
|
||||
|
||||
+17
-75
@@ -84,7 +84,7 @@ the return value of the call.
|
||||
|
||||
```sophia
|
||||
contract interface VotingType =
|
||||
entrypoint vote : string => unit
|
||||
entrypoint : vote : string => unit
|
||||
|
||||
contract Voter =
|
||||
entrypoint tryVote(v : VotingType, alt : string) =
|
||||
@@ -204,7 +204,7 @@ When a `contract` or a `contract interface` implements another `contract interfa
|
||||
|
||||
#### Subtyping and variance
|
||||
|
||||
Subtyping in Sophia follows common rules that take type variance into account. As described by [Wikipedia](https://en.wikipedia.org/wiki/Covariance_and_contravariance_(computer_science)),
|
||||
Subtyping in Sophia follows common rules that take type variance into account. As described by [Wikipedia](https://en.wikipedia.org/wiki/Covariance_and_contravariance_(computer_science)),
|
||||
|
||||
>Variance refers to how subtyping between more complex types relates to subtyping between their components.
|
||||
|
||||
@@ -224,11 +224,11 @@ A good example of where it matters can be pictured by subtyping of function type
|
||||
```sophia
|
||||
contract interface Animal =
|
||||
entrypoint age : () => int
|
||||
|
||||
|
||||
contract Dog : Animal =
|
||||
entrypoint age() = // ...
|
||||
entrypoint woof() = "woof"
|
||||
|
||||
|
||||
contract Cat : Animal =
|
||||
entrypoint age() = // ...
|
||||
entrypoint meow() = "meow"
|
||||
@@ -295,11 +295,6 @@ of `A`.
|
||||
- When a user-defined type `t('a)` is invariant in `'a`, then `t(A)` can never be
|
||||
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
|
||||
|
||||
Sophia does not have arbitrary mutable state, but only a limited form of state
|
||||
@@ -498,24 +493,6 @@ the file, except that error messages will refer to the original source
|
||||
locations. The language will try to include each file at most one time automatically,
|
||||
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
|
||||
|
||||
Sophia offers [standard library](sophia_stdlib.md) which exposes some
|
||||
@@ -563,7 +540,6 @@ Sophia has the following types:
|
||||
## Literals
|
||||
| Type | Constant/Literal example(s) |
|
||||
| ---------- | ------------------------------- |
|
||||
| unit | () |
|
||||
| int | `-1`, `2425`, `4598275923475723498573485768` |
|
||||
| address | `ak_2gx9MEFxKvY9vMG5YnqnXWv1hCsX7rgnfvBLJS4aQurustR1rt` |
|
||||
| bool | `true`, `false` |
|
||||
@@ -578,7 +554,7 @@ Sophia has the following types:
|
||||
| state | `state{ owner = Call.origin, magic_key = #a298105f }` |
|
||||
| event | `EventX(0, "Hello")` |
|
||||
| hash | `#000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f` |
|
||||
| signature | `sg_MhibzTP1wWzGCTjtPFr1TiPqRJrrJqw7auvEuF5i3FdoALWqXLBDY6xxRRNUSPHK3EQTnTzF12EyspkxrSMxVHKsZeSMj`, `#000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f` |
|
||||
| signature | `#000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f` |
|
||||
| Chain.ttl | `FixedTTL(1050)`, `RelativeTTL(50)` |
|
||||
| oracle('a, 'b) | `ok_2YNyxd6TRJPNrTcEDCe9ra59SVUdp9FR9qWC5msKZWYD9bP9z5` |
|
||||
| oracle_query('a, 'b) | `oq_2oRvyowJuJnEkxy58Ckkw77XfWJrmRgmGaLzhdqb67SKEL1gPY` |
|
||||
@@ -634,7 +610,7 @@ arithmetic operations:
|
||||
- remainder (`x mod y`), satisfying `y * (x / y) + x mod y == x` for non-zero `y`
|
||||
- exponentiation (`x ^ y`)
|
||||
|
||||
All operations are *safe* with respect to overflow and underflow.
|
||||
All operations are *safe* with respect to overflow and underflow.
|
||||
The division and modulo operations throw an arithmetic error if the
|
||||
right-hand operand is zero.
|
||||
|
||||
@@ -646,16 +622,10 @@ Sophia arbitrary-sized integers (FATE) also supports the following bitwise opera
|
||||
- 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
|
||||
|
||||
Originally Sophia integers did not support bit arithmetic. Instead we used a
|
||||
separate type `bits` (see the standard library
|
||||
[documentation](sophia_stdlib.md#bits)) - it is still provided as an
|
||||
alternative to bit arithmetic.
|
||||
Sophia integers do not support bit arithmetic. Instead there is a separate
|
||||
type `bits`. See the standard library [documentation](sophia_stdlib.md#bits).
|
||||
|
||||
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).
|
||||
@@ -960,18 +930,16 @@ functions are provided.
|
||||
|
||||
## AENS interface
|
||||
|
||||
Contracts can interact with the [æternity naming
|
||||
system](https://github.com/aeternity/protocol/blob/master/AENS.md). For this
|
||||
purpose the [AENS](sophia_stdlib.md#aens) and later the
|
||||
[AENSv2](sophia_stdlib.md#aensv2) library was exposed.
|
||||
Contracts can interact with the
|
||||
[æternity naming system](https://github.com/aeternity/protocol/blob/master/AENS.md).
|
||||
For this purpose the [AENS](sophia_stdlib.md#aens) library was exposed.
|
||||
|
||||
### Example
|
||||
|
||||
In this example we assume that the name `name` already exists, and is owned by
|
||||
an account with address `addr`. In order to allow a contract `ct` to handle
|
||||
`name` the account holder needs to create a [delegation
|
||||
signature](#delegation-signature) `sig` from the name owner address `addr`, the
|
||||
name hash and the contract address.
|
||||
`name` the account holder needs to create a
|
||||
[signature](#delegation-signature) `sig` of `addr | name.hash | ct.address`.
|
||||
|
||||
Armed with this information we can for example write a function that extends
|
||||
the name if it expires within 1000 blocks:
|
||||
@@ -1113,34 +1081,8 @@ however is in the gas consumption — while `abort` returns unused gas, a call t
|
||||
|
||||
## Delegation signature
|
||||
|
||||
Some chain operations (`Oracle.<operation>` and `AENSv2.<operation>`) have an
|
||||
Some chain operations (`Oracle.<operation>` and `AENS.<operation>`) have an
|
||||
optional delegation signature. This is typically used when a user/accounts
|
||||
would like to allow a contract to act on it's behalf.
|
||||
|
||||
### 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`
|
||||
would like to allow a contract to act on it's behalf. The exact data to be
|
||||
signed varies for the different operations, but in all cases you should prepend
|
||||
the signature data with the `network_id` (`ae_mainnet` for the æternity mainnet, etc.).
|
||||
|
||||
+56
-68
@@ -57,12 +57,6 @@ Address.to_str(a : address) : string
|
||||
|
||||
Base58 encoded string
|
||||
|
||||
#### to_bytes
|
||||
```
|
||||
Address.to_bytes(a : address) : bytes(32)
|
||||
```
|
||||
|
||||
The binary representation of the address.
|
||||
|
||||
#### is_contract
|
||||
```
|
||||
@@ -142,11 +136,11 @@ datatype name = Name(address, Chain.ttl, map(string, AENSv2.pointee))
|
||||
|
||||
```
|
||||
datatype pointee = AccountPt(address) | OraclePt(address)
|
||||
| ContractPt(address) | ChannelPt(address) | DataPt(bytes())
|
||||
| ContractPt(address) | ChannelPt(address) | DataPt(string)
|
||||
```
|
||||
|
||||
Note: on-chain there is a maximum length enforced for `DataPt`, it is 1024 bytes.
|
||||
Sophia itself does _not_ check for this.
|
||||
Sophia itself does _not_ enforce this.
|
||||
|
||||
#### Functions
|
||||
|
||||
@@ -181,14 +175,14 @@ Note: Changed to produce `AENSv2.name` in v8.0 (Ceres protocol upgrade).
|
||||
AENSv2.preclaim(owner : address, commitment_hash : hash, <signature : signature>) : unit
|
||||
```
|
||||
|
||||
The [signature](./sophia_features.md#delegation-signature) should be a
|
||||
serialized structure containing `network id`, `owner address`, and
|
||||
`Contract.address`.
|
||||
The [signature](./sophia_features.md#delegation-signature) should be over
|
||||
`network id` + `owner address` + `Contract.address` (concatenated as byte arrays).
|
||||
|
||||
From Ceres (i.e. FATE VM version 3) the
|
||||
[signature](./sophia_features.md#delegation-signature) can also be generic
|
||||
(allowing _all_, existing and future, names to be delegated with one
|
||||
signature), i.e. containing `network id`, `owner address`, `Contract.address`.
|
||||
signature), i.e. over `network id` + `owner address` + `string "AENS"` +
|
||||
`Contract.address`.
|
||||
|
||||
|
||||
##### claim
|
||||
@@ -196,14 +190,14 @@ signature), i.e. containing `network id`, `owner address`, `Contract.address`.
|
||||
AENSv2.claim(owner : address, name : string, salt : int, name_fee : int, <signature : signature>) : unit
|
||||
```
|
||||
|
||||
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.
|
||||
The [signature](./sophia_features.md#delegation-signature) should be over
|
||||
`network id` + `owner address` + `name_hash` + `Contract.address` (concatenated
|
||||
as byte arrays) using the private key of the `owner` account for signing.
|
||||
|
||||
From Ceres (i.e. FATE VM version 3) the
|
||||
[signature](./sophia_features.md#delegation-signature) can also be generic
|
||||
(allowing _all_, existing and future, names to be delegated with one
|
||||
signature), i.e. containing `network id`, `owner address`, `name_hash`, and
|
||||
signature), i.e. over `network id` + `owner address` + `string "AENS"` +
|
||||
`Contract.address`.
|
||||
|
||||
|
||||
@@ -214,14 +208,15 @@ AENSv2.transfer(owner : address, new_owner : address, name : string, <signature
|
||||
|
||||
Transfers name to the new owner.
|
||||
|
||||
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.
|
||||
The [signature](./sophia_features.md#delegation-signature) should be over
|
||||
`network id` + `owner address` + `name_hash` + `Contract.address`
|
||||
(concatenated as byte arrays)
|
||||
using the private key of the `owner` account for signing.
|
||||
|
||||
From Ceres (i.e. FATE VM version 3) the
|
||||
[signature](./sophia_features.md#delegation-signature) can also be generic
|
||||
(allowing _all_, existing and future, names to be delegated with one
|
||||
signature), i.e. containing `network id`, `owner address`, `name_hash`, and
|
||||
signature), i.e. over `network id` + `owner address` + `string "AENS"` +
|
||||
`Contract.address`.
|
||||
|
||||
|
||||
@@ -232,14 +227,15 @@ AENSv2.revoke(owner : address, name : string, <signature : signature>) : unit
|
||||
|
||||
Revokes the name to extend the ownership time.
|
||||
|
||||
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.
|
||||
The [signature](./sophia_features.md#delegation-signature) should be over
|
||||
`network id` + `owner address` + `name_hash` + `Contract.address`
|
||||
(concatenated as byte arrays)
|
||||
using the private key of the `owner` account for signing.
|
||||
|
||||
From Ceres (i.e. FATE VM version 3) the
|
||||
[signature](./sophia_features.md#delegation-signature) can also be generic
|
||||
(allowing _all_, existing and future, names to be delegated with one
|
||||
signature), i.e. containing `network id`, `owner address`, `name_hash`, and
|
||||
signature), i.e. over `network id` + `owner address` + `string "AENS"` +
|
||||
`Contract.address`.
|
||||
|
||||
|
||||
@@ -255,16 +251,6 @@ 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
|
||||
|
||||
|
||||
@@ -433,7 +419,7 @@ 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.
|
||||
`n` bytes, `None` is returned.
|
||||
|
||||
#### to\_any\_size
|
||||
```
|
||||
@@ -578,6 +564,14 @@ Chain.block_height : int"
|
||||
|
||||
The height of the current block (i.e. the block in which the current call will be included).
|
||||
|
||||
#### to_bytes
|
||||
```
|
||||
Address.to_bytes(a : address) : bytes(32)
|
||||
```
|
||||
|
||||
The binary representation of the address.
|
||||
|
||||
|
||||
##### bytecode_hash
|
||||
```
|
||||
Chain.bytecode_hash : 'c => option(hash)
|
||||
@@ -614,6 +608,14 @@ charging the calling contract. Note that this won't be visible in `Call.value`
|
||||
in the `init` call of the new contract. It will be included in
|
||||
`Contract.balance`, however.
|
||||
|
||||
#### poseidon
|
||||
```
|
||||
Crypto.poseidon(x1 : int, x2 : int) : int
|
||||
```
|
||||
|
||||
Hash two integers (in the scalar field of BLS12-381) to another integer (in the scalar
|
||||
field of BLS12-281). This is a ZK/SNARK-friendly hash function.
|
||||
|
||||
The type `'c` must be instantiated with a contract.
|
||||
|
||||
|
||||
@@ -679,8 +681,8 @@ Example usage:
|
||||
```
|
||||
payable contract interface Auction =
|
||||
entrypoint init : (int, string) => void
|
||||
stateful payable entrypoint buy : (int) => unit
|
||||
stateful entrypoint sell : (int) => unit
|
||||
stateful payable entrypoint buy : (int) => ()
|
||||
stateful entrypoint sell : (int) => ()
|
||||
|
||||
main contract Market =
|
||||
type state = list(Auction)
|
||||
@@ -740,15 +742,6 @@ 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
|
||||
@@ -841,14 +834,11 @@ Hash any object to blake2b
|
||||
|
||||
#### verify_sig
|
||||
```
|
||||
Crypto.verify_sig(msg : bytes(), pubkey : address, sig : signature) : bool
|
||||
Crypto.verify_sig(msg : hash, pubkey : address, sig : signature) : bool
|
||||
```
|
||||
|
||||
Checks if the signature of `msg` was made using private key corresponding to
|
||||
the `pubkey`.
|
||||
|
||||
Note: before v8 of the compiler, `msg` had type `hash` (i.e. `bytes(32)`).
|
||||
|
||||
the `pubkey`
|
||||
|
||||
#### ecverify_secp256k1
|
||||
```
|
||||
@@ -894,8 +884,7 @@ 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`.
|
||||
necessary).
|
||||
|
||||
|
||||
### Map
|
||||
@@ -954,11 +943,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`.
|
||||
|
||||
* The `acct` is the address of the oracle to register (can be the same as the contract).
|
||||
* The [signature](./sophia_features.md#delegation-signature) should be a
|
||||
serialized structure containing `network id`, `account address`, and
|
||||
`contract address`. Using the private key of `account address` for signing.
|
||||
Proving you have the private key of the oracle to be. If the address is the same
|
||||
as the contract `sign` is ignored and can be left out entirely.
|
||||
* `signature` is a signature proving that the contract is allowed to register the account -
|
||||
the `network id` + `account address` + `contract address` (concatenated as byte arrays) is
|
||||
[signed](./sophia_features.md#delegation-signature) with the
|
||||
private key of the account, proving you have the private key of the oracle to be. If the
|
||||
address is the same as the contract `sign` is ignored and can be left out entirely.
|
||||
* The `qfee` is the minimum query fee to be paid by a user when asking a question of the oracle.
|
||||
* 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)`).
|
||||
@@ -972,7 +961,7 @@ Examples:
|
||||
```
|
||||
|
||||
|
||||
#### get\_question
|
||||
#### get_question
|
||||
```
|
||||
Oracle.get_question(o : oracle('a, 'b), q : oracle_query('a, 'b)) : 'a
|
||||
```
|
||||
@@ -985,11 +974,12 @@ Checks what was the question of query `q` on oracle `o`
|
||||
Oracle.respond(<signature : bytes(64)>, o : oracle('a, 'b), q : oracle_query('a, 'b), 'b) : unit
|
||||
```
|
||||
|
||||
Responds to the question `q` on `o`. Unless the contract address is the same
|
||||
as the oracle address the `signature` (which is an optional, named argument)
|
||||
Responds to the question `q` on `o`.
|
||||
Unless the contract address is the same as the oracle address the `signature`
|
||||
(which is an optional, named argument)
|
||||
needs to be provided. Proving that we have the private key of the oracle by
|
||||
[signing](./sophia_features.md#delegation-signature) should be a serialized
|
||||
structure containing `network id`, `oracle query id`, and `contract address`.
|
||||
[signing](./sophia_features.md#delegation-signature)
|
||||
the `network id` + `oracle query id` + `contract address`
|
||||
|
||||
|
||||
#### extend
|
||||
@@ -1002,7 +992,7 @@ Extends TTL of an oracle.
|
||||
* `o` is the oracle being extended
|
||||
* `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
|
||||
```
|
||||
@@ -1023,7 +1013,7 @@ Asks the oracle a question.
|
||||
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)
|
||||
```
|
||||
@@ -2476,9 +2466,7 @@ an integer. If the string doesn't contain a valid number `None` is returned.
|
||||
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))`.
|
||||
Converts string into byte array.
|
||||
|
||||
#### sha3
|
||||
```
|
||||
|
||||
@@ -30,7 +30,6 @@ interface main using as for hiding
|
||||
- `ContractAddress` base58-encoded 32 byte contract address with `ct_` prefix
|
||||
- `OracleAddress` base58-encoded 32 byte oracle address with `ok_` prefix
|
||||
- `OracleQueryId` base58-encoded 32 byte oracle query id with `oq_` prefix
|
||||
- `Signature` base58-encoded 64 byte cryptographic signature with `sg_` prefix
|
||||
|
||||
Valid string escape codes are
|
||||
|
||||
@@ -240,7 +239,6 @@ Expr ::= '(' LamArgs ')' '=>' Block(Stmt) // Anonymous function (x) => x +
|
||||
| Int | Bytes | String | Char // Literals 123, 0xff, #00abc123, "foo", '%'
|
||||
| AccountAddress | ContractAddress // Chain identifiers
|
||||
| OracleAddress | OracleQueryId // Chain identifiers
|
||||
| Signature // Signature
|
||||
| '???' // Hole expression 1 + ???
|
||||
|
||||
Generator ::= Pattern '<-' Expr // Generator
|
||||
@@ -267,11 +265,11 @@ UnOp ::= '-' | '!' | 'bnot'
|
||||
| Operators | Type
|
||||
| --- | ---
|
||||
| `-` `+` `*` `/` `mod` `^` | arithmetic operators
|
||||
| `!` `&&` `\|\|` | logical operators
|
||||
| `!` `&&` `||` | logical operators
|
||||
| `band` `bor` `bxor` `bnot` `<<` `>>` | bitwise operators
|
||||
| `==` `!=` `<` `>` `=<` `>=` | comparison operators
|
||||
| `::` `++` | list operators
|
||||
| `\|>` | functional operators
|
||||
| `|>` | functional operators
|
||||
|
||||
## Operator precedence
|
||||
|
||||
@@ -291,5 +289,5 @@ In order of highest to lowest precedence.
|
||||
| `bxor` | left
|
||||
| `bor` | left
|
||||
| `&&` | right
|
||||
| `\|\|` | right
|
||||
| `\|>` | left
|
||||
| `||` | right
|
||||
| `|>` | left
|
||||
|
||||
@@ -282,9 +282,9 @@ namespace List =
|
||||
private function
|
||||
asc : (('a, 'a) => bool, 'a, list('a), list('a)) => list(list('a))
|
||||
asc(lt, x, acc, h::t) =
|
||||
if(lt(h, x)) reverse(x::acc) :: monotonic_subs(lt, h::t)
|
||||
if(lt(h, x)) List.reverse(x::acc) :: monotonic_subs(lt, h::t)
|
||||
else asc(lt, h, x::acc, t)
|
||||
asc(_, x, acc, []) = [reverse(x::acc)]
|
||||
asc(_, x, acc, []) = [List.reverse(x::acc)]
|
||||
|
||||
/** Merges list of sorted lists
|
||||
*/
|
||||
|
||||
+2
-2
@@ -2,7 +2,7 @@
|
||||
|
||||
{erl_opts, [debug_info]}.
|
||||
|
||||
{deps, [ {aebytecode, {git, "https://github.com/aeternity/aebytecode.git", {tag, "v3.4.1"}}}
|
||||
{deps, [ {aebytecode, {git, "https://github.com/aeternity/aebytecode.git", {tag, "v3.4.0"}}}
|
||||
, {eblake2, "1.0.0"}
|
||||
, {jsx, {git, "https://github.com/talentdeficit/jsx.git", {tag, "2.8.0"}}}
|
||||
]}.
|
||||
@@ -13,7 +13,7 @@
|
||||
{base_plt_apps, [erts, kernel, stdlib, crypto, mnesia]}
|
||||
]}.
|
||||
|
||||
{relx, [{release, {aesophia, "8.0.1"},
|
||||
{relx, [{release, {aesophia, "8.0.0"},
|
||||
[aesophia, aebytecode]},
|
||||
|
||||
{dev_mode, true},
|
||||
|
||||
+3
-3
@@ -1,11 +1,11 @@
|
||||
{"1.2.0",
|
||||
[{<<"aebytecode">>,
|
||||
{git,"https://github.com/aeternity/aebytecode.git",
|
||||
{ref,"6bd6f82c70d800950ea1a2c70c364a4181ff5291"}},
|
||||
{ref,"009e0361922037f978f9c0ef357d4d1be8559928"}},
|
||||
0},
|
||||
{<<"aeserialization">>,
|
||||
{git,"https://github.com/aeternity/aeserialization.git",
|
||||
{ref,"b26e6d105424748ba1c27917267b7cff07f37802"}},
|
||||
{ref,"177bf604b2a05e940f92cf00e96e6e269e708245"}},
|
||||
1},
|
||||
{<<"base58">>,
|
||||
{git,"https://github.com/aeternity/erl-base58.git",
|
||||
@@ -14,7 +14,7 @@
|
||||
{<<"eblake2">>,{pkg,<<"eblake2">>,<<"1.0.0">>},0},
|
||||
{<<"enacl">>,
|
||||
{git,"https://github.com/aeternity/enacl.git",
|
||||
{ref,"4eb7ec70084ba7c87b1af8797c4c4e90c84f95a2"}},
|
||||
{ref,"793ddb502f7fe081302e1c42227dca70b09f8e17"}},
|
||||
2},
|
||||
{<<"getopt">>,{pkg,<<"getopt">>,<<"1.0.1">>},1},
|
||||
{<<"jsx">>,
|
||||
|
||||
+7
-34
@@ -8,7 +8,6 @@
|
||||
%%%-------------------------------------------------------------------
|
||||
|
||||
-module(aeso_aci).
|
||||
-vsn("8.0.1").
|
||||
|
||||
-export([ file/2
|
||||
, file/3
|
||||
@@ -199,8 +198,7 @@ encode_expr({bytes, _, B}) ->
|
||||
<<N:Digits/unit:8>> = B,
|
||||
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;
|
||||
Lit == contract_pubkey; Lit == account_pubkey;
|
||||
Lit == signature ->
|
||||
Lit == contract_pubkey; Lit == account_pubkey ->
|
||||
aeser_api_encoder:encode(Lit, L);
|
||||
encode_expr({app, _, {'-', _}, [{int, _, N}]}) ->
|
||||
encode_expr({int, [], -N});
|
||||
@@ -223,41 +221,16 @@ do_render_aci_json(Json) ->
|
||||
case Json of
|
||||
JArray when is_list(JArray) -> JArray;
|
||||
JObject when is_map(JObject) -> [JObject];
|
||||
JText when is_binary(JText) -> decode(JText)
|
||||
JText when is_binary(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,
|
||||
DecodedContracts = [ decode_contract(C) || C <- Contracts ],
|
||||
{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,
|
||||
kind := Kind,
|
||||
payable := Payable,
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
-module(aeso_ast).
|
||||
-vsn("8.0.1").
|
||||
|
||||
-export([int/2,
|
||||
line/1,
|
||||
|
||||
+199
-211
@@ -11,7 +11,6 @@
|
||||
%%% instances of the compiler to be run in parallel.
|
||||
|
||||
-module(aeso_ast_infer_types).
|
||||
-vsn("8.0.1").
|
||||
|
||||
-export([ infer/1
|
||||
, infer/2
|
||||
@@ -156,6 +155,7 @@
|
||||
, in_pattern = false :: boolean()
|
||||
, in_guard = false :: boolean()
|
||||
, stateful = false :: boolean()
|
||||
, unify_throws = true :: boolean()
|
||||
, current_const = none :: none | aeso_syntax:id()
|
||||
, current_function = none :: none | aeso_syntax:id()
|
||||
, what = top :: top | namespace | contract | contract_interface
|
||||
@@ -757,7 +757,7 @@ global_env() ->
|
||||
{"OraclePt", Fun1(Address, PointeeV2)},
|
||||
{"ContractPt", Fun1(Address, PointeeV2)},
|
||||
{"ChannelPt", Fun1(Address, PointeeV2)},
|
||||
{"DataPt", Fun1(Bytes(any), PointeeV2)},
|
||||
{"DataPt", Fun1(String, PointeeV2)},
|
||||
%% Name object constructor v2
|
||||
{"Name", Fun([Address, TTL, Map(String, PointeeV2)], AENSNameV2)}
|
||||
])
|
||||
@@ -776,7 +776,7 @@ global_env() ->
|
||||
%% Crypto/Curve operations
|
||||
CryptoScope = #scope
|
||||
{ funs = MkDefs(
|
||||
[{"verify_sig", Fun([Bytes('_'), Address, SignId], Bool)},
|
||||
[{"verify_sig", Fun([Hash, Address, SignId], Bool)},
|
||||
{"verify_sig_secp256k1", Fun([Hash, Bytes(64), SignId], Bool)},
|
||||
{"ecverify_secp256k1", Fun([Hash, Bytes(20), Bytes(65)], Bool)},
|
||||
{"ecrecover_secp256k1", Fun([Hash, Bytes(65)], Option(Bytes(20)))},
|
||||
@@ -952,14 +952,14 @@ infer(Contracts, Options) ->
|
||||
{Env1, Decls} = infer1(Env, Contracts1, [], Options),
|
||||
when_warning(warn_unused_functions, fun() -> destroy_and_report_unused_functions() end),
|
||||
when_option(warn_error, fun() -> destroy_and_report_warnings_as_type_errors() end),
|
||||
WarningsUnsorted = lists:map(fun mk_warning/1, ets_tab2list(warnings)),
|
||||
Warnings = aeso_warnings:sort_warnings(WarningsUnsorted),
|
||||
{Env2, DeclsFolded, DeclsUnfolded} =
|
||||
case proplists:get_value(dont_unfold, Options, false) of
|
||||
true -> {Env1, Decls, Decls};
|
||||
false -> E = on_scopes(Env1, fun(Scope) -> unfold_record_types(Env1, Scope) end),
|
||||
{E, Decls, unfold_record_types(E, Decls)}
|
||||
end,
|
||||
WarningsUnsorted = lists:map(fun mk_warning/1, ets_tab2list(warnings)),
|
||||
Warnings = aeso_warnings:sort_warnings(WarningsUnsorted),
|
||||
case proplists:get_value(return_env, Options, false) of
|
||||
false -> {DeclsFolded, DeclsUnfolded, Warnings};
|
||||
true -> {Env2, DeclsFolded, DeclsUnfolded, Warnings}
|
||||
@@ -1162,7 +1162,7 @@ infer_contract(Env0, What, Defs0, Options) ->
|
||||
_ = bind_funs(lists:map(FunBind, Functions), #env{}),
|
||||
FunMap = maps:from_list([ {FunName(Def), Def} || Def <- Functions ]),
|
||||
check_reserved_entrypoints(FunMap),
|
||||
DepGraph = maps:map(fun(_, Def) -> aeso_syntax_utils:used_ids(Env3#env.namespace, Def) end, FunMap),
|
||||
DepGraph = maps:map(fun(_, Def) -> aeso_syntax_utils:used_ids(Def) end, FunMap),
|
||||
SCCs = aeso_utils:scc(DepGraph),
|
||||
{Env4, Defs1} = check_sccs(Env3, FunMap, SCCs, []),
|
||||
%% Remove namespaces used in the current namespace
|
||||
@@ -1609,7 +1609,7 @@ check_reserved_entrypoints(Funs) ->
|
||||
check_fundecl(Env, {fun_decl, Ann, Id = {id, _, Name}, Type = {fun_t, _, _, _, _}}) ->
|
||||
Type1 = {fun_t, _, Named, Args, Ret} = check_type(Env, Type),
|
||||
TypeSig = {type_sig, Ann, none, Named, Args, Ret},
|
||||
register_implementation(Env, Id, TypeSig),
|
||||
register_implementation(Id, TypeSig),
|
||||
{{Name, TypeSig}, {fun_decl, Ann, Id, Type1}};
|
||||
check_fundecl(Env, {fun_decl, Ann, Id = {id, _, Name}, Type}) ->
|
||||
type_error({fundecl_must_have_funtype, Ann, Id, Type}),
|
||||
@@ -1617,16 +1617,13 @@ check_fundecl(Env, {fun_decl, Ann, Id = {id, _, Name}, Type}) ->
|
||||
|
||||
%% Register the function FunId as implemented by deleting it from the functions
|
||||
%% to be implemented table if it is included there, or return true otherwise.
|
||||
-spec register_implementation(env(), FunId, FunSig) -> true | no_return() when
|
||||
-spec register_implementation(FunId, FunSig) -> true | no_return() when
|
||||
FunId :: aeso_syntax:id(),
|
||||
FunSig :: typesig().
|
||||
register_implementation(Env, Id, Sig) ->
|
||||
register_implementation(Id, Sig) ->
|
||||
Name = name(Id),
|
||||
case ets_lookup(functions_to_implement, Name) of
|
||||
[{Name, Interface, Decl = {fun_decl, _, DeclId, FunT}}] ->
|
||||
When = {implement_interface_fun, aeso_syntax:get_ann(Sig), Name, name(Interface)},
|
||||
unify(Env, typesig_to_fun_t(Sig), FunT, When),
|
||||
|
||||
[{Name, Interface, Decl = {fun_decl, _, DeclId, _}}] ->
|
||||
DeclStateful = aeso_syntax:get_ann(stateful, Decl, false),
|
||||
DeclPayable = aeso_syntax:get_ann(payable, Decl, false),
|
||||
|
||||
@@ -1654,7 +1651,7 @@ infer_nonrec(Env, LetFun) ->
|
||||
create_constraints(),
|
||||
NewLetFun = {{_, Sig}, _} = infer_letfun(Env, LetFun),
|
||||
check_special_funs(Env, NewLetFun),
|
||||
register_implementation(Env, get_letfun_id(LetFun), Sig),
|
||||
register_implementation(get_letfun_id(LetFun), Sig),
|
||||
solve_then_destroy_and_report_unsolved_constraints(Env),
|
||||
Result = {TypeSig, _} = instantiate(NewLetFun),
|
||||
print_typesig(TypeSig),
|
||||
@@ -1684,11 +1681,11 @@ infer_letrec(Env, Defs) ->
|
||||
Inferred =
|
||||
[ begin
|
||||
Res = {{Name, TypeSig}, LetFun} = infer_letfun(ExtendEnv, LF),
|
||||
register_implementation(Env, get_letfun_id(LetFun), TypeSig),
|
||||
register_implementation(get_letfun_id(LetFun), TypeSig),
|
||||
Got = proplists:get_value(Name, Funs),
|
||||
Expect = typesig_to_fun_t(TypeSig),
|
||||
unify(Env, Got, Expect, {check_typesig, Name, Got, Expect}),
|
||||
solve_all_constraints(Env),
|
||||
solve_constraints(Env),
|
||||
?PRINT_TYPES("Checked ~s : ~s\n",
|
||||
[Name, pp(dereference_deep(Got))]),
|
||||
Res
|
||||
@@ -1761,27 +1758,8 @@ desugar_clauses(Ann, Fun, {type_sig, _, _, _, ArgTypes, RetType}, Clauses) ->
|
||||
end.
|
||||
|
||||
print_typesig({Name, TypeSig}) ->
|
||||
assert_tvars(Name, TypeSig),
|
||||
?PRINT_TYPES("Inferred ~s : ~s\n", [Name, pp(TypeSig)]).
|
||||
|
||||
assert_tvars(Name, TS) ->
|
||||
TVars = assert_tvars_(TS, #{}),
|
||||
case maps:size(TVars) > 256 of
|
||||
true ->
|
||||
type_error({too_many_tvars, Name, TS});
|
||||
false ->
|
||||
ok
|
||||
end.
|
||||
|
||||
assert_tvars_({tvar, _, TV}, TVars) ->
|
||||
TVars#{TV => ok};
|
||||
assert_tvars_(T, TVars) when is_tuple(T) ->
|
||||
assert_tvars_(tuple_to_list(T), TVars);
|
||||
assert_tvars_(Ts, TVars) when is_list(Ts) ->
|
||||
lists:foldl(fun(T, TVars1) -> assert_tvars_(T, TVars1) end, TVars, Ts);
|
||||
assert_tvars_(_, TVars) ->
|
||||
TVars.
|
||||
|
||||
arg_type(ArgAnn, {id, Ann, "_"}) ->
|
||||
case aeso_syntax:get_ann(origin, Ann, user) of
|
||||
system -> fresh_uvar(ArgAnn);
|
||||
@@ -1955,8 +1933,6 @@ infer_expr(_Env, Body={bytes, As, Bin}) ->
|
||||
{typed, As, Body, {bytes_t, As, byte_size(Bin)}};
|
||||
infer_expr(_Env, Body={account_pubkey, As, _}) ->
|
||||
{typed, As, Body, {id, As, "address"}};
|
||||
infer_expr(_Env, Body={signature, As, Bin}) when byte_size(Bin) == 64 ->
|
||||
{typed, As, Body, {bytes_t, As, 64}};
|
||||
infer_expr(_Env, Body={oracle_pubkey, As, _}) ->
|
||||
Q = fresh_uvar(As),
|
||||
R = fresh_uvar(As),
|
||||
@@ -2195,8 +2171,6 @@ check_valid_const_expr({bytes, _, _}) ->
|
||||
true;
|
||||
check_valid_const_expr({account_pubkey, _, _}) ->
|
||||
true;
|
||||
check_valid_const_expr({signature, _, _}) ->
|
||||
true;
|
||||
check_valid_const_expr({oracle_pubkey, _, _}) ->
|
||||
true;
|
||||
check_valid_const_expr({oracle_query_id, _, _}) ->
|
||||
@@ -2634,124 +2608,61 @@ get_constraints() ->
|
||||
destroy_constraints() ->
|
||||
ets_delete(constraints).
|
||||
|
||||
%% Solve all constraints by iterating until no-progress
|
||||
-spec solve_constraints(env()) -> ok.
|
||||
solve_constraints(Env) ->
|
||||
%% First look for record fields that appear in only one type definition
|
||||
IsAmbiguous =
|
||||
fun(#field_constraint{
|
||||
record_t = RecordType,
|
||||
field = Field={id, _Attrs, FieldName},
|
||||
field_t = FieldType,
|
||||
kind = Kind,
|
||||
context = When }) ->
|
||||
Arity = fun_arity(dereference_deep(FieldType)),
|
||||
FieldInfos = case Arity of
|
||||
none -> lookup_record_field(Env, FieldName, Kind);
|
||||
_ -> lookup_record_field_arity(Env, FieldName, Arity, Kind)
|
||||
end,
|
||||
case FieldInfos of
|
||||
[] ->
|
||||
type_error({undefined_field, Field}),
|
||||
false;
|
||||
[#field_info{field_t = FldType, record_t = RecType}] ->
|
||||
create_freshen_tvars(),
|
||||
FreshFldType = freshen(FldType),
|
||||
FreshRecType = freshen(RecType),
|
||||
destroy_freshen_tvars(),
|
||||
unify(Env, FreshFldType, FieldType, {field_constraint, FreshFldType, FieldType, When}),
|
||||
unify(Env, FreshRecType, RecordType, {record_constraint, FreshRecType, RecordType, When}),
|
||||
false;
|
||||
_ ->
|
||||
%% ambiguity--need cleverer strategy
|
||||
true
|
||||
end;
|
||||
(_) -> true
|
||||
end,
|
||||
AmbiguousConstraints = lists:filter(IsAmbiguous, get_constraints()),
|
||||
|
||||
-spec solve_all_constraints(env()) -> ok.
|
||||
solve_all_constraints(Env) ->
|
||||
Constraints = [C || C <- get_constraints(), not one_shot_field_constraint(Env, C) ],
|
||||
solve_constraints_top(Env, Constraints).
|
||||
% The two passes on AmbiguousConstraints are needed
|
||||
solve_ambiguous_constraints(Env, AmbiguousConstraints ++ AmbiguousConstraints).
|
||||
|
||||
solve_constraints_top(Env, Constraints) ->
|
||||
UnsolvedCs = solve_constraints(Env, Constraints),
|
||||
Progress = solve_unknown_record_constraints(Env, UnsolvedCs),
|
||||
|
||||
if length(UnsolvedCs) < length(Constraints) orelse Progress == true ->
|
||||
solve_constraints_top(Env, UnsolvedCs);
|
||||
-spec solve_ambiguous_constraints(env(), [constraint()]) -> ok.
|
||||
solve_ambiguous_constraints(Env, Constraints) ->
|
||||
Unknown = solve_known_record_types(Env, Constraints),
|
||||
if Unknown == [] -> ok;
|
||||
length(Unknown) < length(Constraints) ->
|
||||
%% progress! Keep trying.
|
||||
solve_ambiguous_constraints(Env, Unknown);
|
||||
true ->
|
||||
ok
|
||||
case solve_unknown_record_types(Env, Unknown) of
|
||||
true -> %% Progress!
|
||||
solve_ambiguous_constraints(Env, Unknown);
|
||||
_ -> ok %% No progress. Report errors later.
|
||||
end
|
||||
end.
|
||||
|
||||
-spec solve_constraints(env(), [constraint()]) -> [constraint()].
|
||||
solve_constraints(Env, Constraints) ->
|
||||
[ C1 || C <- Constraints, C1 <- [dereference_deep(C)], not solve_constraint(Env, C1) ].
|
||||
|
||||
solve_unknown_record_constraints(Env, Constraints) ->
|
||||
FieldCs = lists:filter(fun(#field_constraint{record_t = {uvar, _, _}}) -> true; (_) -> false end, Constraints),
|
||||
FieldCsUVars = lists:usort([UVar || #field_constraint{record_t = UVar = {uvar, _, _}} <- FieldCs]),
|
||||
|
||||
FieldConstraint = fun(#field_constraint{ field = F, kind = K, context = Ctx }) -> {K, Ctx, F} end,
|
||||
FieldsForUVar = fun(UVar) ->
|
||||
[ FieldConstraint(FC) || FC = #field_constraint{record_t = U} <- FieldCs, U == UVar ]
|
||||
end,
|
||||
|
||||
|
||||
Solutions = [ solve_for_uvar(Env, UVar, FieldsForUVar(UVar)) || UVar <- FieldCsUVars ],
|
||||
case lists:member(true, Solutions) of
|
||||
true -> true;
|
||||
false -> Solutions
|
||||
end.
|
||||
|
||||
%% -- Simple constraints --
|
||||
%% Returns true if solved (unified or type error)
|
||||
solve_constraint(_Env, #field_constraint{record_t = {uvar, _, _}}) ->
|
||||
false;
|
||||
solve_constraint(Env, #field_constraint{record_t = RecordType,
|
||||
field = Field = {id, _As, FieldName},
|
||||
field_t = FieldType,
|
||||
context = When}) ->
|
||||
RecId = record_type_name(RecordType),
|
||||
Attrs = aeso_syntax:get_ann(RecId),
|
||||
case lookup_type(Env, RecId) of
|
||||
{_, {_Ann, {Formals, {What, Fields}}}} when What =:= record_t; What =:= contract_t ->
|
||||
FieldTypes = [{Name, Type} || {field_t, _, {id, _, Name}, Type} <- Fields],
|
||||
case proplists:get_value(FieldName, FieldTypes) of
|
||||
undefined ->
|
||||
type_error({missing_field, Field, RecId});
|
||||
FldType ->
|
||||
solve_field_constraint(Env, FieldType, FldType, RecordType, app_t(Attrs, RecId, Formals), When)
|
||||
end;
|
||||
_ ->
|
||||
type_error({not_a_record_type, instantiate(RecordType), When})
|
||||
end,
|
||||
true;
|
||||
solve_constraint(Env, C = #dependent_type_constraint{}) ->
|
||||
check_named_argument_constraint(Env, C);
|
||||
solve_constraint(Env, C = #named_argument_constraint{}) ->
|
||||
check_named_argument_constraint(Env, C);
|
||||
solve_constraint(_Env, {is_bytes, _, _}) -> false;
|
||||
solve_constraint(_Env, {is_fixed_bytes, _, _}) -> false;
|
||||
solve_constraint(Env, {add_bytes, Ann, Action, A0, B0, C0}) ->
|
||||
A = unfold_types_in_type(Env, dereference(A0)),
|
||||
B = unfold_types_in_type(Env, dereference(B0)),
|
||||
C = unfold_types_in_type(Env, dereference(C0)),
|
||||
case {A, B, C} of
|
||||
{{bytes_t, _, M}, {bytes_t, _, N}, _} when is_integer(M), is_integer(N) ->
|
||||
unify(Env, {bytes_t, Ann, M + N}, C, {at, Ann});
|
||||
{{bytes_t, _, M}, _, {bytes_t, _, R}} when is_integer(M), is_integer(R), R >= M ->
|
||||
unify(Env, {bytes_t, Ann, R - M}, B, {at, Ann});
|
||||
{_, {bytes_t, _, N}, {bytes_t, _, R}} when is_integer(N), is_integer(R), R >= N ->
|
||||
unify(Env, {bytes_t, Ann, R - N}, A, {at, Ann});
|
||||
{{bytes_t, _, _}, {bytes_t, _, _}, _} when Action == concat ->
|
||||
unify(Env, {bytes_t, Ann, any}, C, {at, Ann});
|
||||
_ -> false
|
||||
end;
|
||||
solve_constraint(_, _) -> false.
|
||||
|
||||
one_shot_field_constraint(Env, #field_constraint{record_t = RecordType,
|
||||
field = Field = {id, _As, FieldName},
|
||||
field_t = FieldType,
|
||||
kind = Kind,
|
||||
context = When}) ->
|
||||
Arity = fun_arity(dereference_deep(FieldType)),
|
||||
FieldInfos = case Arity of
|
||||
none -> lookup_record_field(Env, FieldName, Kind);
|
||||
_ -> lookup_record_field_arity(Env, FieldName, Arity, Kind)
|
||||
end,
|
||||
|
||||
case FieldInfos of
|
||||
[] ->
|
||||
type_error({undefined_field, Field}),
|
||||
true;
|
||||
[#field_info{field_t = FldType, record_t = RecType}] ->
|
||||
solve_field_constraint(Env, FieldType, FldType, RecordType, RecType, When),
|
||||
true;
|
||||
_ ->
|
||||
false
|
||||
end;
|
||||
one_shot_field_constraint(_Env, _Constraint) ->
|
||||
false.
|
||||
|
||||
|
||||
solve_field_constraint(Env, FieldType, FldType, RecordType, RecType, When) ->
|
||||
create_freshen_tvars(),
|
||||
FreshFldType = freshen(FldType),
|
||||
FreshRecType = freshen(RecType),
|
||||
destroy_freshen_tvars(),
|
||||
unify(Env, FreshFldType, FieldType, {field_constraint, FreshFldType, FieldType, When}),
|
||||
unify(Env, FreshRecType, RecordType, {record_constraint, FreshRecType, RecordType, When}).
|
||||
|
||||
solve_then_destroy_and_report_unsolved_constraints(Env) ->
|
||||
solve_all_constraints(Env),
|
||||
solve_constraints(Env),
|
||||
destroy_and_report_unsolved_constraints(Env).
|
||||
|
||||
destroy_and_report_unsolved_constraints(Env) ->
|
||||
@@ -2783,10 +2694,21 @@ destroy_and_report_unsolved_constraints(Env) ->
|
||||
(_) -> false
|
||||
end, OtherCs5),
|
||||
|
||||
check_field_constraints(Env, FieldCs),
|
||||
Unsolved = [ S || S <- [ solve_constraint(Env, dereference_deep(C)) || C <- NamedArgCs ],
|
||||
S == unsolved ],
|
||||
[ type_error({unsolved_named_argument_constraint, C}) || C <- Unsolved ],
|
||||
|
||||
Unknown = solve_known_record_types(Env, FieldCs),
|
||||
if Unknown == [] -> ok;
|
||||
true ->
|
||||
case solve_unknown_record_types(Env, Unknown) of
|
||||
true -> ok;
|
||||
Errors -> [ type_error(Err) || Err <- Errors ]
|
||||
end
|
||||
end,
|
||||
|
||||
check_record_create_constraints(Env, CreateCs),
|
||||
check_is_contract_constraints(Env, ContractCs),
|
||||
check_named_args_constraints(Env, NamedArgCs),
|
||||
check_bytes_constraints(Env, BytesCs),
|
||||
check_aens_resolve_constraints(Env, AensResolveCs),
|
||||
check_oracle_type_constraints(Env, OracleTypeCs),
|
||||
@@ -2804,21 +2726,20 @@ get_oracle_type(_Fun, _Args, _Ret) -> false.
|
||||
|
||||
%% -- Named argument constraints --
|
||||
|
||||
%% True if solved (unified or type error), false otherwise
|
||||
-spec check_named_argument_constraint(env(), named_argument_constraint()) -> true | false.
|
||||
%% If false, a type error has been emitted, so it's safe to drop the constraint.
|
||||
-spec check_named_argument_constraint(env(), named_argument_constraint()) -> true | false | unsolved.
|
||||
check_named_argument_constraint(_Env, #named_argument_constraint{ args = {uvar, _, _} }) ->
|
||||
false;
|
||||
unsolved;
|
||||
check_named_argument_constraint(Env,
|
||||
C = #named_argument_constraint{ args = Args,
|
||||
name = Id = {id, _, Name},
|
||||
type = Type }) ->
|
||||
case [ T || {named_arg_t, _, {id, _, Name1}, T, _} <- Args, Name1 == Name ] of
|
||||
[] ->
|
||||
type_error({bad_named_argument, Args, Id});
|
||||
[T] ->
|
||||
unify(Env, T, Type, {check_named_arg_constraint, C})
|
||||
end,
|
||||
true;
|
||||
type_error({bad_named_argument, Args, Id}),
|
||||
false;
|
||||
[T] -> unify(Env, T, Type, {check_named_arg_constraint, C}), true
|
||||
end;
|
||||
check_named_argument_constraint(Env,
|
||||
#dependent_type_constraint{ named_args_t = NamedArgsT0,
|
||||
named_args = NamedArgs,
|
||||
@@ -2835,11 +2756,10 @@ check_named_argument_constraint(Env,
|
||||
ArgEnv = maps:from_list([ {Name, GetVal(Name, Default)}
|
||||
|| {named_arg_t, _, {id, _, Name}, _, Default} <- NamedArgsT ]),
|
||||
GenType1 = specialize_dependent_type(ArgEnv, GenType),
|
||||
unify(Env, GenType1, SpecType, {check_expr, App, GenType1, SpecType});
|
||||
_ ->
|
||||
unify(Env, GenType, SpecType, {check_expr, App, GenType, SpecType})
|
||||
end,
|
||||
true.
|
||||
unify(Env, GenType1, SpecType, {check_expr, App, GenType1, SpecType}),
|
||||
true;
|
||||
_ -> unify(Env, GenType, SpecType, {check_expr, App, GenType, SpecType}), true
|
||||
end.
|
||||
|
||||
specialize_dependent_type(Env, Type) ->
|
||||
case dereference(Type) of
|
||||
@@ -2855,16 +2775,59 @@ specialize_dependent_type(Env, Type) ->
|
||||
_ -> Type %% Currently no deep dependent types
|
||||
end.
|
||||
|
||||
check_field_constraints(Env, Constraints) ->
|
||||
UnsolvedFieldCs = solve_constraints(Env, Constraints),
|
||||
case solve_unknown_record_constraints(Env, UnsolvedFieldCs) of
|
||||
true -> ok;
|
||||
Errors -> [ type_error(Err) || Err <- Errors ]
|
||||
end.
|
||||
%% -- Bytes constraints --
|
||||
|
||||
check_named_args_constraints(Env, Constraints) ->
|
||||
UnsolvedNamedArgCs = solve_constraints(Env, Constraints),
|
||||
[ type_error({unsolved_named_argument_constraint, C}) || C <- UnsolvedNamedArgCs ].
|
||||
solve_constraint(_Env, #field_constraint{record_t = {uvar, _, _}}) ->
|
||||
not_solved;
|
||||
solve_constraint(Env, C = #field_constraint{record_t = RecType,
|
||||
field = FieldName,
|
||||
field_t = FieldType,
|
||||
context = When}) ->
|
||||
RecId = record_type_name(RecType),
|
||||
Attrs = aeso_syntax:get_ann(RecId),
|
||||
case lookup_type(Env, RecId) of
|
||||
{_, {_Ann, {Formals, {What, Fields}}}} when What =:= record_t; What =:= contract_t ->
|
||||
FieldTypes = [{Name, Type} || {field_t, _, {id, _, Name}, Type} <- Fields],
|
||||
{id, _, FieldString} = FieldName,
|
||||
case proplists:get_value(FieldString, FieldTypes) of
|
||||
undefined ->
|
||||
type_error({missing_field, FieldName, RecId}),
|
||||
not_solved;
|
||||
FldType ->
|
||||
create_freshen_tvars(),
|
||||
FreshFldType = freshen(FldType),
|
||||
FreshRecType = freshen(app_t(Attrs, RecId, Formals)),
|
||||
destroy_freshen_tvars(),
|
||||
unify(Env, FreshFldType, FieldType, {field_constraint, FreshFldType, FieldType, When}),
|
||||
unify(Env, FreshRecType, RecType, {record_constraint, FreshRecType, RecType, When}),
|
||||
C
|
||||
end;
|
||||
_ ->
|
||||
type_error({not_a_record_type, instantiate(RecType), When}),
|
||||
not_solved
|
||||
end;
|
||||
solve_constraint(Env, C = #dependent_type_constraint{}) ->
|
||||
check_named_argument_constraint(Env, C);
|
||||
solve_constraint(Env, C = #named_argument_constraint{}) ->
|
||||
check_named_argument_constraint(Env, C);
|
||||
solve_constraint(_Env, {is_bytes, _, _}) -> ok;
|
||||
solve_constraint(_Env, {is_fixed_bytes, _, _}) -> ok;
|
||||
solve_constraint(Env, {add_bytes, Ann, Action, A0, B0, C0}) ->
|
||||
A = unfold_types_in_type(Env, dereference(A0)),
|
||||
B = unfold_types_in_type(Env, dereference(B0)),
|
||||
C = unfold_types_in_type(Env, dereference(C0)),
|
||||
case {A, B, C} of
|
||||
{{bytes_t, _, M}, {bytes_t, _, N}, _} when is_integer(M), is_integer(N) ->
|
||||
unify(Env, {bytes_t, Ann, M + N}, C, {at, Ann});
|
||||
{{bytes_t, _, M}, _, {bytes_t, _, R}} when is_integer(M), is_integer(R), R >= M ->
|
||||
unify(Env, {bytes_t, Ann, R - M}, B, {at, Ann});
|
||||
{_, {bytes_t, _, N}, {bytes_t, _, R}} when is_integer(N), is_integer(R), R >= N ->
|
||||
unify(Env, {bytes_t, Ann, R - N}, A, {at, Ann});
|
||||
{{bytes_t, _, _}, {bytes_t, _, _}, _} when Action == concat ->
|
||||
unify(Env, {bytes_t, Ann, any}, C, {at, Ann});
|
||||
_ -> ok
|
||||
end;
|
||||
solve_constraint(_, _) -> ok.
|
||||
|
||||
check_bytes_constraints(Env, Constraints) ->
|
||||
InAddConstraint = [ T || {add_bytes, _, _, A, B, C} <- Constraints,
|
||||
@@ -2972,11 +2935,36 @@ check_is_contract_constraints(Env, [C | Cs]) ->
|
||||
end,
|
||||
check_is_contract_constraints(Env, Cs).
|
||||
|
||||
-spec solve_unknown_record_types(env(), [field_constraint()]) -> true | [tuple()].
|
||||
solve_unknown_record_types(Env, Unknown) ->
|
||||
UVars = lists:usort([UVar || #field_constraint{record_t = UVar = {uvar, _, _}} <- Unknown]),
|
||||
Solutions = [solve_for_uvar(Env, UVar, [{Kind, When, Field}
|
||||
|| #field_constraint{record_t = U, field = Field, kind = Kind, context = When} <- Unknown,
|
||||
U == UVar])
|
||||
|| UVar <- UVars],
|
||||
case lists:member(true, Solutions) of
|
||||
true -> true;
|
||||
false -> Solutions
|
||||
end.
|
||||
|
||||
%% This will solve all kinds of constraints but will only return the
|
||||
%% unsolved field constraints
|
||||
-spec solve_known_record_types(env(), [constraint()]) -> [field_constraint()].
|
||||
solve_known_record_types(Env, Constraints) ->
|
||||
DerefConstraints = lists:map(fun(C = #field_constraint{record_t = RecordType}) ->
|
||||
C#field_constraint{record_t = dereference(RecordType)};
|
||||
(C) -> dereference_deep(C)
|
||||
end, Constraints),
|
||||
SolvedConstraints = lists:map(fun(C) -> solve_constraint(Env, dereference_deep(C)) end, DerefConstraints),
|
||||
Unsolved = DerefConstraints--SolvedConstraints,
|
||||
lists:filter(fun(#field_constraint{}) -> true; (_) -> false end, Unsolved).
|
||||
|
||||
record_type_name({app_t, _Attrs, RecId, _Args}) when ?is_type_id(RecId) ->
|
||||
RecId;
|
||||
record_type_name(RecId) when ?is_type_id(RecId) ->
|
||||
RecId;
|
||||
record_type_name(_Other) ->
|
||||
%% io:format("~p is not a record type\n", [Other]),
|
||||
{id, [{origin, system}], "not_a_record_type"}.
|
||||
|
||||
solve_for_uvar(Env, UVar = {uvar, Attrs, _}, Fields0) ->
|
||||
@@ -3084,8 +3072,7 @@ unfold_types_in_type(Env, {app_t, Ann, Id, Args}, Options) when ?is_type_id(Id)
|
||||
unfold_types_in_type(Env, Id, Options) when ?is_type_id(Id) ->
|
||||
%% Like the case above, but for types without parameters.
|
||||
when_warning(warn_unused_typedefs, fun() -> used_typedef(Id, 0) end),
|
||||
UnfoldSysAlias = not proplists:get_value(not_unfold_system_alias_types, Options, false),
|
||||
UnfoldRecords = proplists:get_value(unfold_record_types, Options, false),
|
||||
UnfoldRecords = proplists:get_value(unfold_record_types, Options, false),
|
||||
UnfoldVariants = proplists:get_value(unfold_variant_types, Options, false),
|
||||
case lookup_type(Env, Id) of
|
||||
{_, {_, {[], {record_t, Fields}}}} when UnfoldRecords ->
|
||||
@@ -3093,12 +3080,7 @@ unfold_types_in_type(Env, Id, Options) when ?is_type_id(Id) ->
|
||||
{_, {_, {[], {variant_t, Constrs}}}} when UnfoldVariants ->
|
||||
{variant_t, unfold_types_in_type(Env, Constrs, Options)};
|
||||
{_, {_, {[], {alias_t, Type1}}}} ->
|
||||
case aeso_syntax:get_ann(Type1) of
|
||||
[{origin, system}] when not UnfoldSysAlias ->
|
||||
Id;
|
||||
_ ->
|
||||
unfold_types_in_type(Env, Type1, Options)
|
||||
end;
|
||||
unfold_types_in_type(Env, Type1, Options);
|
||||
_ ->
|
||||
%% Not a record type, or ill-formed record type
|
||||
Id
|
||||
@@ -3155,12 +3137,16 @@ unify0(Env, A, B, Variance, When) ->
|
||||
unify1(_Env, {uvar, _, R}, {uvar, _, R}, _Variance, _When) ->
|
||||
true;
|
||||
unify1(_Env, {uvar, _, _}, {fun_t, _, _, var_args, _}, _Variance, When) ->
|
||||
type_error({unify_varargs, When}),
|
||||
false;
|
||||
unify1(_Env, {uvar, A, R}, T, _Variance, When) ->
|
||||
type_error({unify_varargs, When});
|
||||
unify1(Env, {uvar, A, R}, T, _Variance, When) ->
|
||||
case occurs_check(R, T) of
|
||||
true ->
|
||||
cannot_unify({uvar, A, R}, T, none, When),
|
||||
if
|
||||
Env#env.unify_throws ->
|
||||
cannot_unify({uvar, A, R}, T, none, When);
|
||||
true ->
|
||||
ok
|
||||
end,
|
||||
false;
|
||||
false ->
|
||||
ets_insert(type_vars, {R, T}),
|
||||
@@ -3187,13 +3173,18 @@ unify1(Env, A = {con, _, NameA}, B = {con, _, NameB}, Variance, When) ->
|
||||
case is_subtype(Env, NameA, NameB, Variance) of
|
||||
true -> true;
|
||||
false ->
|
||||
IsSubtype = is_subtype(Env, NameA, NameB, contravariant) orelse
|
||||
is_subtype(Env, NameA, NameB, covariant),
|
||||
Cxt = case IsSubtype of
|
||||
true -> Variance;
|
||||
false -> none
|
||||
end,
|
||||
cannot_unify(A, B, Cxt, When),
|
||||
if
|
||||
Env#env.unify_throws ->
|
||||
IsSubtype = is_subtype(Env, NameA, NameB, contravariant) orelse
|
||||
is_subtype(Env, NameA, NameB, covariant),
|
||||
Cxt = case IsSubtype of
|
||||
true -> Variance;
|
||||
false -> none
|
||||
end,
|
||||
cannot_unify(A, B, Cxt, When);
|
||||
true ->
|
||||
ok
|
||||
end,
|
||||
false
|
||||
end;
|
||||
unify1(_Env, {qid, _, Name}, {qid, _, Name}, _Variance, _When) ->
|
||||
@@ -3207,11 +3198,9 @@ unify1(Env, {if_t, _, {id, _, Id}, Then1, Else1}, {if_t, _, {id, _, Id}, Then2,
|
||||
unify0(Env, Else1, Else2, Variance, When);
|
||||
|
||||
unify1(_Env, {fun_t, _, _, _, _}, {fun_t, _, _, var_args, _}, _Variance, When) ->
|
||||
type_error({unify_varargs, When}),
|
||||
false;
|
||||
type_error({unify_varargs, When});
|
||||
unify1(_Env, {fun_t, _, _, var_args, _}, {fun_t, _, _, _, _}, _Variance, When) ->
|
||||
type_error({unify_varargs, When}),
|
||||
false;
|
||||
type_error({unify_varargs, When});
|
||||
unify1(Env, {fun_t, _, Named1, Args1, Result1}, {fun_t, _, Named2, Args2, Result2}, Variance, When)
|
||||
when length(Args1) == length(Args2) ->
|
||||
unify0(Env, Named1, Named2, opposite_variance(Variance), When) and
|
||||
@@ -3233,7 +3222,7 @@ unify1(Env, {tuple_t, _, As}, {tuple_t, _, Bs}, Variance, When)
|
||||
when length(As) == length(Bs) ->
|
||||
unify0(Env, As, Bs, Variance, When);
|
||||
unify1(Env, {named_arg_t, _, Id1, Type1, _}, {named_arg_t, _, Id2, Type2, _}, Variance, When) ->
|
||||
unify1(Env, Id1, Id2, Variance, {arg_name, Id1, Id2, When}) andalso
|
||||
unify1(Env, Id1, Id2, Variance, {arg_name, Id1, Id2, When}),
|
||||
unify1(Env, Type1, Type2, Variance, When);
|
||||
%% The grammar is a bit inconsistent about whether types without
|
||||
%% arguments are represented as applications to an empty list of
|
||||
@@ -3242,8 +3231,13 @@ unify1(Env, {app_t, _, T, []}, B, Variance, When) ->
|
||||
unify0(Env, T, B, Variance, When);
|
||||
unify1(Env, A, {app_t, _, T, []}, Variance, When) ->
|
||||
unify0(Env, A, T, Variance, When);
|
||||
unify1(_Env, A, B, _Variance, When) ->
|
||||
cannot_unify(A, B, none, When),
|
||||
unify1(Env, A, B, _Variance, When) ->
|
||||
if
|
||||
Env#env.unify_throws ->
|
||||
cannot_unify(A, B, none, When);
|
||||
true ->
|
||||
ok
|
||||
end,
|
||||
false.
|
||||
|
||||
is_subtype(_Env, NameA, NameB, invariant) ->
|
||||
@@ -3409,7 +3403,7 @@ instantiate1(X) ->
|
||||
integer_to_tvar(X) when X < 26 ->
|
||||
[$a + X];
|
||||
integer_to_tvar(X) ->
|
||||
integer_to_tvar(X div 26 - 1) ++ [$a + (X rem 26)].
|
||||
[integer_to_tvar(X div 26)] ++ [$a + (X rem 26)].
|
||||
|
||||
%% Warnings
|
||||
|
||||
@@ -3591,6 +3585,7 @@ create_type_errors() ->
|
||||
|
||||
destroy_and_report_type_errors(Env) ->
|
||||
Errors0 = lists:reverse(ets_tab2list(type_errors)),
|
||||
%% io:format("Type errors now: ~p\n", [Errors0]),
|
||||
ets_delete(type_errors),
|
||||
Errors = [ mk_error(unqualify(Env, Err)) || Err <- Errors0 ],
|
||||
aeso_errors:throw(Errors). %% No-op if Errors == []
|
||||
@@ -3796,9 +3791,6 @@ mk_error({type_decl, _, {id, Pos, Name}, _}) ->
|
||||
Msg = io_lib:format("Empty type declarations are not supported. Type `~s` lacks a definition",
|
||||
[Name]),
|
||||
mk_t_err(pos(Pos), Msg);
|
||||
mk_error({too_many_tvars, Name, {type_sig, Pos, _, _, _, _}}) ->
|
||||
Msg = io_lib:format("Too many type variables (max 256) in definition of `~s`", [Name]),
|
||||
mk_t_err(pos(Pos), Msg);
|
||||
mk_error({stateful_not_allowed, Id, Fun}) ->
|
||||
Msg = io_lib:format("Cannot reference stateful function `~s` in the definition of non-stateful function `~s`.",
|
||||
[pp(Id), pp(Fun)]),
|
||||
@@ -4197,8 +4189,8 @@ pp_when({if_branches, Then, ThenType0, Else, ElseType0}) ->
|
||||
Branches = [ {Then, ThenType} | [ {B, ElseType} || B <- if_branches(Else) ] ],
|
||||
{pos(element(1, hd(Branches))),
|
||||
io_lib:format("when comparing the types of the if-branches\n"
|
||||
"~s", [string:join([ io_lib:format("~s (at ~s)", [pp_typed(" - ", B, BType), pp_loc(B)])
|
||||
|| {B, BType} <- Branches ], "\n")])};
|
||||
"~s", [ [ io_lib:format("~s (at ~s)\n", [pp_typed(" - ", B, BType), pp_loc(B)])
|
||||
|| {B, BType} <- Branches ] ])};
|
||||
pp_when({case_pat, Pat, PatType0, ExprType0}) ->
|
||||
{PatType, ExprType} = instantiate({PatType0, ExprType0}),
|
||||
{pos(Pat),
|
||||
@@ -4245,10 +4237,6 @@ pp_when({var_args, Ann, Fun}) ->
|
||||
{pos(Ann)
|
||||
, io_lib:format("when resolving arguments of variadic function `~s`", [pp_expr(Fun)])
|
||||
};
|
||||
pp_when({implement_interface_fun, Ann, Entrypoint, Interface}) ->
|
||||
{ pos(Ann)
|
||||
, io_lib:format("when implementing the entrypoint `~s` from the interface `~s`", [Entrypoint, Interface])
|
||||
};
|
||||
pp_when(unknown) -> {pos(0,0), ""}.
|
||||
|
||||
-spec pp_why_record(why_record()) -> {pos(), iolist()}.
|
||||
|
||||
+53
-94
@@ -8,7 +8,6 @@
|
||||
%%%
|
||||
%%%-------------------------------------------------------------------
|
||||
-module(aeso_ast_to_fcode).
|
||||
-vsn("8.0.1").
|
||||
|
||||
-export([ast_to_fcode/2, format_fexpr/1]).
|
||||
-export_type([fcode/0, fexpr/0, fun_def/0]).
|
||||
@@ -56,15 +55,11 @@
|
||||
| {contract_pubkey, binary()}
|
||||
| {oracle_pubkey, binary()}
|
||||
| {oracle_query_id, binary()}
|
||||
| {signature, binary()}
|
||||
| {bool, false | true}
|
||||
| {contract_code, string()} %% for CREATE, by name
|
||||
| {typerep, ftype()}.
|
||||
|
||||
-type fann() :: [ {file, aeso_syntax:ann_file()} |
|
||||
{line, aeso_syntax:ann_line()} |
|
||||
{col, aeso_syntax:ann_col()}
|
||||
].
|
||||
-type fann() :: [ {file, aeso_syntax:ann_file()} | {line, aeso_syntax:ann_line()} ].
|
||||
|
||||
-type fexpr() :: {lit, fann(), flit()}
|
||||
| {nil, fann()}
|
||||
@@ -342,8 +337,8 @@ init_type_env() ->
|
||||
["Chain", "ttl"] => ?type({variant, [[integer], [integer]]}),
|
||||
["AENS", "pointee"] => ?type({variant, [[address], [address], [address], [address]]}),
|
||||
["AENS", "name"] => ?type({variant, [[address, {variant, [[integer], [integer]]}, {map, string, {variant, [[address], [address], [address], [address]]}}]]}),
|
||||
["AENSv2", "pointee"] => ?type({variant, [[address], [address], [address], [address], [{bytes, any}]]}),
|
||||
["AENSv2", "name"] => ?type({variant, [[address, {variant, [[integer], [integer]]}, {map, string, {variant, [[address], [address], [address], [address], [{bytes, any}]]}}]]}),
|
||||
["AENSv2", "pointee"] => ?type({variant, [[address], [address], [address], [address], [string]]}),
|
||||
["AENSv2", "name"] => ?type({variant, [[address, {variant, [[integer], [integer]]}, {map, string, {variant, [[address], [address], [address], [address], [string]]}}]]}),
|
||||
["Chain", "ga_meta_tx"] => ?type({variant, [[address, integer]]}),
|
||||
["Chain", "paying_for_tx"] => ?type({variant, [[address, integer]]}),
|
||||
["Chain", "base_tx"] => ?type(BaseTx),
|
||||
@@ -406,23 +401,11 @@ to_fcode(Env, [{namespace, _, {con, _, Con}, Decls} | Code]) ->
|
||||
Env1 = decls_to_fcode(Env#{ context => {namespace, Con} }, Decls),
|
||||
to_fcode(Env1, Code).
|
||||
|
||||
-spec ann_loc(aeso_syntax:ann() | fann()) -> {File, Line, Column} when
|
||||
File :: string() | none,
|
||||
Line :: non_neg_integer() | none,
|
||||
Column :: non_neg_integer() | none.
|
||||
ann_loc(Ann) ->
|
||||
File = proplists:get_value(file, Ann, none),
|
||||
Line = proplists:get_value(line, Ann, none),
|
||||
Col = proplists:get_value(col, Ann, none),
|
||||
{File, Line, Col}.
|
||||
|
||||
-spec to_fann(aeso_syntax:ann()) -> fann().
|
||||
to_fann(Ann) ->
|
||||
{File, Line, Col} = ann_loc(Ann),
|
||||
[ {Tag, X} ||
|
||||
{Tag, X} <- [{file, File}, {line, Line}, {col, Col}],
|
||||
X =/= none, X =/= no_file
|
||||
].
|
||||
File = proplists:lookup(file, Ann),
|
||||
Line = proplists:lookup(line, Ann),
|
||||
[ X || X <- [File, Line], X =/= none ].
|
||||
|
||||
-spec get_fann(fexpr()) -> fann().
|
||||
get_fann(FExpr) -> element(2, FExpr).
|
||||
@@ -601,7 +584,6 @@ expr_to_fcode(_Env, _Type, {char, Ann, N}) -> {lit, to_fann(Ann), {in
|
||||
expr_to_fcode(_Env, _Type, {bool, Ann, B}) -> {lit, to_fann(Ann), {bool, B}};
|
||||
expr_to_fcode(_Env, _Type, {string, Ann, S}) -> {lit, to_fann(Ann), {string, S}};
|
||||
expr_to_fcode(_Env, _Type, {account_pubkey, Ann, K}) -> {lit, to_fann(Ann), {account_pubkey, K}};
|
||||
expr_to_fcode(_Env, _Type, {signature, Ann, K}) -> {lit, to_fann(Ann), {signature, K}};
|
||||
expr_to_fcode(_Env, _Type, {contract_pubkey, Ann, K}) -> {lit, to_fann(Ann), {contract_pubkey, K}};
|
||||
expr_to_fcode(_Env, _Type, {oracle_pubkey, Ann, K}) -> {lit, to_fann(Ann), {oracle_pubkey, K}};
|
||||
expr_to_fcode(_Env, _Type, {oracle_query_id, Ann, K}) -> {lit, to_fann(Ann), {oracle_query_id, K}};
|
||||
@@ -1312,13 +1294,10 @@ event_function(_Env = #{event_type := {variant_t, EventCons}}, EventType = {vari
|
||||
|
||||
-spec lambda_lift(fcode()) -> fcode().
|
||||
lambda_lift(FCode = #{ functions := Funs, state_layout := StateLayout }) ->
|
||||
NewFuns =
|
||||
[ {FunName, FunDef}
|
||||
|| {ParentName, ParentDef} <- maps:to_list(Funs),
|
||||
{NewParentDef, Lambdas} <- [lambda_lift_fun(StateLayout, ParentName, ParentDef)],
|
||||
{FunName, FunDef} <- [{ParentName, NewParentDef} | maps:to_list(Lambdas)]
|
||||
],
|
||||
FCode#{ functions := maps:from_list(NewFuns) }.
|
||||
init_lambda_funs(),
|
||||
Funs1 = maps:map(fun(_, Body) -> lambda_lift_fun(StateLayout, Body) end, Funs),
|
||||
NewFuns = get_lambda_funs(),
|
||||
FCode#{ functions := maps:merge(Funs1, NewFuns) }.
|
||||
|
||||
-define(lambda_key, '%lambdalifted').
|
||||
|
||||
@@ -1326,42 +1305,18 @@ lambda_lift(FCode = #{ functions := Funs, state_layout := StateLayout }) ->
|
||||
init_lambda_funs() -> put(?lambda_key, #{}).
|
||||
|
||||
-spec get_lambda_funs() -> term().
|
||||
get_lambda_funs() ->
|
||||
Lambdas = erase(?lambda_key),
|
||||
%% Remove name feed entries and leave only actual functions
|
||||
maps:filter(fun({fresh, _}, _) -> false;
|
||||
(_, _) -> true
|
||||
end, Lambdas).
|
||||
get_lambda_funs() -> erase(?lambda_key).
|
||||
|
||||
-spec add_lambda_fun(fun_name(), fann(), fun_def()) -> fun_name().
|
||||
add_lambda_fun(Parent, FAnn, Def) ->
|
||||
-spec add_lambda_fun(fun_def()) -> fun_name().
|
||||
add_lambda_fun(Def) ->
|
||||
Name = fresh_fun(),
|
||||
Funs = get(?lambda_key),
|
||||
LambdaId = maps:get({fresh, Parent}, Funs, 0),
|
||||
Name = lambda_name(FAnn, LambdaId, Parent),
|
||||
put(?lambda_key, Funs#{ Name => Def, {fresh, Parent} => LambdaId + 1}),
|
||||
put(?lambda_key, Funs#{ Name => Def }),
|
||||
Name.
|
||||
|
||||
-spec lambda_name(fann(), non_neg_integer(), fun_name()) -> fun_name().
|
||||
lambda_name(FAnn, Id, PName) ->
|
||||
PSName = case PName of
|
||||
{entrypoint, N} -> [binary_to_list(N)];
|
||||
{local_fun, Ns} -> Ns
|
||||
end,
|
||||
{_File, Line, Col} = ann_loc(FAnn),
|
||||
Name = PSName ++
|
||||
[ "%lambda"
|
||||
, if is_integer(Line) -> integer_to_list(Line); true -> "" end
|
||||
, if is_integer(Col) -> integer_to_list(Col); true -> "" end
|
||||
, integer_to_list(Id)],
|
||||
{local_fun, Name}.
|
||||
|
||||
-spec lambda_lift_fun(state_layout(), fun_name(), fun_def()) -> {fun_def(), #{var_name() => term()}}.
|
||||
lambda_lift_fun(Layout, Name, Def = #{ body := Body }) ->
|
||||
%% Not thread safe! We initialize state per functions not to depend on the order in which
|
||||
%% functions are processed.
|
||||
init_lambda_funs(),
|
||||
NewDef = Def#{ body := lambda_lift_expr(Layout, Name, Body) },
|
||||
{NewDef, get_lambda_funs()}.
|
||||
-spec lambda_lift_fun(state_layout(), fun_def()) -> fun_def().
|
||||
lambda_lift_fun(Layout, Def = #{ body := Body }) ->
|
||||
Def#{ body := lambda_lift_expr(Layout, Body) }.
|
||||
|
||||
-spec lifted_fun([var_name()], [var_name()], fexpr()) -> fun_def().
|
||||
lifted_fun([Z], Xs, Body) ->
|
||||
@@ -1379,20 +1334,21 @@ lifted_fun(FVs, Xs, Body) ->
|
||||
body => lists:foldr(Proj, Body, indexed(FVs))
|
||||
}.
|
||||
|
||||
-spec make_closure(fun_name(), fann(), [var_name()], [var_name()], fexpr()) -> Closure when
|
||||
-spec make_closure([var_name()], [var_name()], fexpr()) -> Closure when
|
||||
Closure :: fexpr().
|
||||
make_closure(ParentName, FAnn, FVs, Xs, Body) ->
|
||||
Name = add_lambda_fun(ParentName, FAnn, lifted_fun(FVs, Xs, Body)),
|
||||
make_closure(FVs, Xs, Body) ->
|
||||
Fun = add_lambda_fun(lifted_fun(FVs, Xs, Body)),
|
||||
FAnn = get_fann(Body),
|
||||
Tup = fun([Y]) -> Y; (Ys) -> {tuple, FAnn, Ys} end,
|
||||
{closure, FAnn, Name, Tup([{var, FAnn, Y} || Y <- FVs])}.
|
||||
{closure, FAnn, Fun, Tup([{var, FAnn, Y} || Y <- FVs])}.
|
||||
|
||||
-spec lambda_lift_expr(state_layout(), fun_name(), fexpr()) -> Closure when
|
||||
-spec lambda_lift_expr(state_layout(), fexpr()) -> Closure when
|
||||
Closure :: fexpr().
|
||||
lambda_lift_expr(Layout, Name, L = {lam, FAnn, Xs, Body}) ->
|
||||
lambda_lift_expr(Layout, L = {lam, _, Xs, Body}) ->
|
||||
FVs = free_vars(L),
|
||||
make_closure(Name, FAnn, FVs, Xs, lambda_lift_expr(Layout, Name, Body));
|
||||
lambda_lift_expr(Layout, Name, UExpr) when element(1, UExpr) == def_u; element(1, UExpr) == builtin_u ->
|
||||
[Tag, FAnn, F, Ar | _] = tuple_to_list(UExpr),
|
||||
make_closure(FVs, Xs, lambda_lift_expr(Layout, Body));
|
||||
lambda_lift_expr(Layout, UExpr) when element(1, UExpr) == def_u; element(1, UExpr) == builtin_u ->
|
||||
[Tag, _, F, Ar | _] = tuple_to_list(UExpr),
|
||||
ExtraArgs = case UExpr of
|
||||
{builtin_u, _, _, _, TypeArgs} -> TypeArgs;
|
||||
_ -> []
|
||||
@@ -1403,41 +1359,41 @@ lambda_lift_expr(Layout, Name, UExpr) when element(1, UExpr) == def_u; element(1
|
||||
builtin_u -> builtin_to_fcode(Layout, get_fann(UExpr), F, Args);
|
||||
def_u -> {def, get_fann(UExpr), F, Args}
|
||||
end,
|
||||
make_closure(Name, FAnn, [], Xs, Body);
|
||||
lambda_lift_expr(Layout, Name, {remote_u, FAnn, ArgsT, RetT, Ct, F}) ->
|
||||
make_closure([], Xs, Body);
|
||||
lambda_lift_expr(Layout, {remote_u, FAnn, ArgsT, RetT, Ct, F}) ->
|
||||
FVs = free_vars(Ct),
|
||||
Ct1 = lambda_lift_expr(Layout, Name, Ct),
|
||||
Ct1 = lambda_lift_expr(Layout, Ct),
|
||||
NamedArgCount = 3,
|
||||
Xs = [ lists:concat(["arg", I]) || I <- lists:seq(1, length(ArgsT) + NamedArgCount) ],
|
||||
Args = [{var, [], X} || X <- Xs],
|
||||
make_closure(Name, FAnn, FVs, Xs, {remote, FAnn, ArgsT, RetT, Ct1, F, Args});
|
||||
lambda_lift_expr(Layout, Name, Expr) ->
|
||||
make_closure(FVs, Xs, {remote, FAnn, ArgsT, RetT, Ct1, F, Args});
|
||||
lambda_lift_expr(Layout, Expr) ->
|
||||
case Expr of
|
||||
{lit, _, _} -> Expr;
|
||||
{nil, _} -> Expr;
|
||||
{var, _, _} -> Expr;
|
||||
{closure, _, _, _} -> Expr;
|
||||
{def, FAnn, D, As} -> {def, FAnn, D, lambda_lift_exprs(Layout, Name, As)};
|
||||
{builtin, FAnn, B, As} -> {builtin, FAnn, B, lambda_lift_exprs(Layout, Name, As)};
|
||||
{remote, FAnn, ArgsT, RetT, Ct, F, As} -> {remote, FAnn, ArgsT, RetT, lambda_lift_expr(Layout, Name, Ct), F, lambda_lift_exprs(Layout, Name, As)};
|
||||
{con, FAnn, Ar, C, As} -> {con, FAnn, Ar, C, lambda_lift_exprs(Layout, Name, As)};
|
||||
{tuple, FAnn, As} -> {tuple, FAnn, lambda_lift_exprs(Layout, Name, As)};
|
||||
{proj, FAnn, A, I} -> {proj, FAnn, lambda_lift_expr(Layout, Name, A), I};
|
||||
{set_proj, FAnn, A, I, B} -> {set_proj, FAnn, lambda_lift_expr(Layout, Name, A), I, lambda_lift_expr(Layout, Name, B)};
|
||||
{op, FAnn, Op, As} -> {op, FAnn, Op, lambda_lift_exprs(Layout, Name, As)};
|
||||
{'let', FAnn, X, A, B} -> {'let', FAnn, X, lambda_lift_expr(Layout, Name, A), lambda_lift_expr(Layout, Name, B)};
|
||||
{funcall, FAnn, A, Bs} -> {funcall, FAnn, lambda_lift_expr(Layout, Name, A), lambda_lift_exprs(Layout, Name, Bs)};
|
||||
{set_state, FAnn, R, A} -> {set_state, FAnn, R, lambda_lift_expr(Layout, Name, A)};
|
||||
{def, FAnn, D, As} -> {def, FAnn, D, lambda_lift_exprs(Layout, As)};
|
||||
{builtin, FAnn, B, As} -> {builtin, FAnn, B, lambda_lift_exprs(Layout, As)};
|
||||
{remote, FAnn, ArgsT, RetT, Ct, F, As} -> {remote, FAnn, ArgsT, RetT, lambda_lift_expr(Layout, Ct), F, lambda_lift_exprs(Layout, As)};
|
||||
{con, FAnn, Ar, C, As} -> {con, FAnn, Ar, C, lambda_lift_exprs(Layout, As)};
|
||||
{tuple, FAnn, As} -> {tuple, FAnn, lambda_lift_exprs(Layout, As)};
|
||||
{proj, FAnn, A, I} -> {proj, FAnn, lambda_lift_expr(Layout, A), I};
|
||||
{set_proj, FAnn, A, I, B} -> {set_proj, FAnn, lambda_lift_expr(Layout, A), I, lambda_lift_expr(Layout, B)};
|
||||
{op, FAnn, Op, As} -> {op, FAnn, Op, lambda_lift_exprs(Layout, As)};
|
||||
{'let', FAnn, X, A, B} -> {'let', FAnn, X, lambda_lift_expr(Layout, A), lambda_lift_expr(Layout, B)};
|
||||
{funcall, FAnn, A, Bs} -> {funcall, FAnn, lambda_lift_expr(Layout, A), lambda_lift_exprs(Layout, Bs)};
|
||||
{set_state, FAnn, R, A} -> {set_state, FAnn, R, lambda_lift_expr(Layout, A)};
|
||||
{get_state, _, _} -> Expr;
|
||||
{switch, FAnn, S} -> {switch, FAnn, lambda_lift_expr(Layout, Name, S)};
|
||||
{split, Type, X, Alts} -> {split, Type, X, lambda_lift_exprs(Layout, Name, Alts)};
|
||||
{nosplit, Rens, A} -> {nosplit, Rens, lambda_lift_expr(Layout, Name, A)};
|
||||
{'case', P, S} -> {'case', P, lambda_lift_expr(Layout, Name, S)}
|
||||
{switch, FAnn, S} -> {switch, FAnn, lambda_lift_expr(Layout, S)};
|
||||
{split, Type, X, Alts} -> {split, Type, X, lambda_lift_exprs(Layout, Alts)};
|
||||
{nosplit, Rens, A} -> {nosplit, Rens, lambda_lift_expr(Layout, A)};
|
||||
{'case', P, S} -> {'case', P, lambda_lift_expr(Layout, S)}
|
||||
end.
|
||||
|
||||
-spec lambda_lift_exprs(state_layout(), fun_name(), [fexpr()]) -> [Closure] when
|
||||
-spec lambda_lift_exprs(state_layout(), [fexpr()]) -> [Closure] when
|
||||
Closure :: fexpr().
|
||||
lambda_lift_exprs(Layout, Name, As) -> [lambda_lift_expr(Layout, Name, A) || A <- As].
|
||||
lambda_lift_exprs(Layout, As) -> [lambda_lift_expr(Layout, A) || A <- As].
|
||||
|
||||
%% -- Optimisations ----------------------------------------------------------
|
||||
|
||||
@@ -1962,6 +1918,9 @@ fresh_name_save(Name) ->
|
||||
-spec fresh_name() -> var_name().
|
||||
fresh_name() -> fresh_name("%").
|
||||
|
||||
-spec fresh_fun() -> fun_name().
|
||||
fresh_fun() -> {local_fun, [fresh_name("^")]}.
|
||||
|
||||
-spec fresh_name(string()) -> var_name().
|
||||
fresh_name(Prefix) ->
|
||||
N = get('%fresh'),
|
||||
|
||||
+11
-24
@@ -7,7 +7,6 @@
|
||||
%%% Created : 12 Dec 2017
|
||||
%%%-------------------------------------------------------------------
|
||||
-module(aeso_compiler).
|
||||
-vsn("8.0.1").
|
||||
|
||||
-export([ file/1
|
||||
, file/2
|
||||
@@ -28,7 +27,7 @@
|
||||
, validate_byte_code/3
|
||||
]).
|
||||
|
||||
-include("$aebytecode_include/aeb_opcodes.hrl").
|
||||
-include_lib("aebytecode/include/aeb_opcodes.hrl").
|
||||
-include("aeso_utils.hrl").
|
||||
|
||||
|
||||
@@ -43,7 +42,6 @@
|
||||
| {include, {file_system, [string()]} |
|
||||
{explicit_files, #{string() => binary()}}}
|
||||
| {src_file, string()}
|
||||
| {src_dir, string()}
|
||||
| {aci, aeso_aci:aci_type()}.
|
||||
-type options() :: [option()].
|
||||
|
||||
@@ -89,9 +87,7 @@ file(Filename) ->
|
||||
file(File, Options0) ->
|
||||
Options = add_include_path(File, Options0),
|
||||
case read_contract(File) of
|
||||
{ok, Bin} ->
|
||||
SrcDir = aeso_utils:canonical_dir(filename:dirname(File)),
|
||||
from_string(Bin, [{src_file, File}, {src_dir, SrcDir} | Options]);
|
||||
{ok, Bin} -> from_string(Bin, [{src_file, File} | Options]);
|
||||
{error, Error} ->
|
||||
Msg = lists:flatten([File,": ",file:format_error(Error)]),
|
||||
{error, [aeso_errors:new(file_error, Msg)]}
|
||||
@@ -103,7 +99,7 @@ add_include_path(File, Options) ->
|
||||
false ->
|
||||
Dir = filename:dirname(File),
|
||||
{ok, Cwd} = file:get_cwd(),
|
||||
[{include, {file_system, [Cwd, aeso_utils:canonical_dir(Dir)]}} | Options]
|
||||
[{include, {file_system, [Cwd, Dir]}} | Options]
|
||||
end.
|
||||
|
||||
-spec from_string(binary() | string(), options()) -> {ok, map()} | {error, [aeso_errors:error()]}.
|
||||
@@ -229,13 +225,10 @@ encode_value(Contract0, Type, Value, Options) ->
|
||||
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,
|
||||
#{ unfolded_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 ]),
|
||||
Type1 = aeso_ast_infer_types:unfold_types_in_type(TypeEnv, Type0, [unfold_record_types, unfold_variant_types]),
|
||||
fate_data_to_sophia_value(Type0, Type1, FateValue);
|
||||
Err = {error, _} ->
|
||||
Err
|
||||
@@ -276,7 +269,7 @@ insert_call_function(Ast, Code, Call, {type, Type}) ->
|
||||
[ Code,
|
||||
"\n\n",
|
||||
lists:duplicate(Ind, " "),
|
||||
"entrypoint ", Call, "(val : ", Type, ") : ", Type, " = val\n"
|
||||
"entrypoint ", Call, "(val : ", Type, ") = val\n"
|
||||
]).
|
||||
|
||||
-spec insert_init_function(string(), options()) -> string().
|
||||
@@ -315,12 +308,9 @@ to_sophia_value(ContractString, FunName, ok, Data, Options0) ->
|
||||
Options = [no_code | Options0],
|
||||
try
|
||||
Code = string_to_code(ContractString, Options),
|
||||
#{ folded_typed_ast := TypedAst, type_env := TypeEnv} = Code,
|
||||
#{ unfolded_typed_ast := TypedAst, type_env := TypeEnv} = Code,
|
||||
{ok, _, Type0} = get_decode_type(FunName, TypedAst),
|
||||
Type = aeso_ast_infer_types:unfold_types_in_type(TypeEnv, Type0,
|
||||
[ unfold_record_types
|
||||
, unfold_variant_types
|
||||
, not_unfold_system_alias_types]),
|
||||
Type = aeso_ast_infer_types:unfold_types_in_type(TypeEnv, Type0, [unfold_record_types, unfold_variant_types]),
|
||||
|
||||
fate_data_to_sophia_value(Type0, Type, Data)
|
||||
catch
|
||||
@@ -367,17 +357,14 @@ decode_calldata(ContractString, FunName, Calldata, Options0) ->
|
||||
Options = [no_code | Options0],
|
||||
try
|
||||
Code = string_to_code(ContractString, Options),
|
||||
#{ folded_typed_ast := TypedAst, type_env := TypeEnv} = Code,
|
||||
#{ unfolded_typed_ast := TypedAst, type_env := TypeEnv} = Code,
|
||||
|
||||
{ok, Args, _} = get_decode_type(FunName, TypedAst),
|
||||
GetType = fun({typed, _, _, T}) -> T; (T) -> T end,
|
||||
ArgTypes = lists:map(GetType, Args),
|
||||
Type0 = {tuple_t, [], ArgTypes},
|
||||
%% 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
|
||||
, not_unfold_system_alias_types]),
|
||||
Type = aeso_ast_infer_types:unfold_types_in_type(TypeEnv, Type0, [unfold_record_types, unfold_variant_types]),
|
||||
case aeb_fate_abi:decode_calldata(FunName, Calldata) of
|
||||
{ok, FateArgs} ->
|
||||
try
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
%%%-------------------------------------------------------------------
|
||||
|
||||
-module(aeso_errors).
|
||||
-vsn("8.0.1").
|
||||
|
||||
-type src_file() :: no_file | iolist().
|
||||
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
%%%
|
||||
%%%-------------------------------------------------------------------
|
||||
-module(aeso_fcode_to_fate).
|
||||
-vsn("8.0.1").
|
||||
|
||||
-export([compile/3, compile/4, term_to_fate/1, term_to_fate/2]).
|
||||
|
||||
@@ -236,7 +235,6 @@ lit_to_fate(Env, L) ->
|
||||
{bytes, B} -> aeb_fate_data:make_bytes(B);
|
||||
{bool, B} -> aeb_fate_data:make_boolean(B);
|
||||
{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);
|
||||
{oracle_pubkey, K} -> aeb_fate_data:make_oracle(K);
|
||||
{oracle_query_id, H} -> aeb_fate_data:make_oracle_query(H);
|
||||
@@ -287,8 +285,6 @@ term_to_fate(_GlobEnv, _Env, {builtin, _, map_empty, []}) ->
|
||||
term_to_fate(GlobEnv, Env, {op, _, map_set, [M, K, V]}) ->
|
||||
Map = term_to_fate(GlobEnv, Env, M),
|
||||
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, _) ->
|
||||
throw(not_a_fate_value).
|
||||
|
||||
@@ -1181,16 +1177,11 @@ independent({i, _, I}, {i, _, J}) ->
|
||||
StackI = lists:member(?a, [WI | RI]),
|
||||
StackJ = lists:member(?a, [WJ | RJ]),
|
||||
|
||||
ReadStoreI = [] /= [ x || {store, _} <- RI ],
|
||||
ReadStoreJ = [] /= [ x || {store, _} <- RJ ],
|
||||
|
||||
if WI == pc; WJ == pc -> false; %% no jumps
|
||||
not (PureI or PureJ) -> false; %% at least one is pure
|
||||
StackI and StackJ -> false; %% cannot both use the stack
|
||||
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 ->
|
||||
if WI == pc; WJ == pc -> false; %% no jumps
|
||||
not (PureI or PureJ) -> false; %% at least one is pure
|
||||
StackI and StackJ -> false; %% cannot both use the stack
|
||||
WI == WJ -> false; %% cannot write to the same register
|
||||
true ->
|
||||
%% and cannot write to each other's inputs
|
||||
not lists:member(WI, RJ) andalso
|
||||
not lists:member(WJ, RI)
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
%%% @end
|
||||
%%%-------------------------------------------------------------------
|
||||
-module(aeso_parse_lib).
|
||||
-vsn("8.0.1").
|
||||
|
||||
-export([parse/2,
|
||||
return/1, fail/0, fail/1, fail/2, map/2, bind/2,
|
||||
@@ -16,7 +15,7 @@
|
||||
many/1, many1/1, sep/2, sep1/2,
|
||||
infixl/2, infixr/2]).
|
||||
|
||||
-export([current_file/0, set_current_file/1, current_dir/0, set_current_dir/1,
|
||||
-export([current_file/0, set_current_file/1,
|
||||
current_include_type/0, set_current_include_type/1]).
|
||||
|
||||
%% -- Types ------------------------------------------------------------------
|
||||
@@ -481,13 +480,6 @@ current_file() ->
|
||||
set_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(Pos) -> Pos.
|
||||
|
||||
|
||||
+21
-46
@@ -3,7 +3,6 @@
|
||||
%%% Description :
|
||||
%%% Created : 1 Mar 2018 by Ulf Norell
|
||||
-module(aeso_parser).
|
||||
-vsn("8.0.1").
|
||||
-compile({no_auto_import,[map_get/2]}).
|
||||
|
||||
-export([string/1,
|
||||
@@ -20,7 +19,6 @@
|
||||
|
||||
-include("aeso_parse_lib.hrl").
|
||||
-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]).
|
||||
|
||||
-type parse_result() :: aeso_syntax:ast() | {aeso_syntax:ast(), sets:set(include_hash())} | none().
|
||||
@@ -60,7 +58,6 @@ run_parser(P, Inp, Opts) ->
|
||||
|
||||
parse_and_scan(P, S, Opts) ->
|
||||
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)),
|
||||
case aeso_scan:scan(S) of
|
||||
{ok, Tokens} -> aeso_parse_lib:parse(P, Tokens);
|
||||
@@ -303,7 +300,7 @@ stmt() ->
|
||||
, {switch, keyword(switch), parens(expr()), maybe_block(branch())}
|
||||
, {'if', keyword('if'), parens(expr()), body()}
|
||||
, {elif, keyword(elif), parens(expr()), body()}
|
||||
, {'else', keyword('else'), body()}
|
||||
, {else, keyword(else), body()}
|
||||
])).
|
||||
|
||||
branch() ->
|
||||
@@ -327,7 +324,7 @@ expr100() ->
|
||||
Expr150 = ?LAZY_P(expr150()),
|
||||
choice(
|
||||
[ ?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())),
|
||||
case _2 of
|
||||
none -> _1;
|
||||
@@ -526,7 +523,7 @@ id_or_addr() ->
|
||||
?RULE(id(), parse_addr_literal(_1)).
|
||||
|
||||
parse_addr_literal(Id = {id, Ann, Name}) ->
|
||||
case lists:member(lists:sublist(Name, 3), ["ak_", "ok_", "oq_", "ct_", "sg_"]) of
|
||||
case lists:member(lists:sublist(Name, 3), ["ak_", "ok_", "oq_", "ct_"]) of
|
||||
false -> Id;
|
||||
true ->
|
||||
try aeser_api_encoder:decode(list_to_binary(Name)) of
|
||||
@@ -565,7 +562,6 @@ bracket_list(P) -> brackets(comma_sep(P)).
|
||||
-spec pos_ann(ann_line(), ann_col()) -> ann().
|
||||
pos_ann(Line, Col) ->
|
||||
[ {file, current_file()}
|
||||
, {dir, current_dir()}
|
||||
, {include_type, current_include_type()}
|
||||
, {line, Line}
|
||||
, {col, Col} ].
|
||||
@@ -613,7 +609,7 @@ group_ifs([], Acc) ->
|
||||
group_ifs([{'if', Ann, Cond, Then} | Stmts], Acc) ->
|
||||
{Elses, Rest} = else_branches(Stmts, []),
|
||||
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'"});
|
||||
group_ifs([{elif, Ann, _, _} | _], _) ->
|
||||
fail({Ann, "No matching 'if' for 'elif'"});
|
||||
@@ -623,14 +619,14 @@ group_ifs([Stmt | Stmts], Acc) ->
|
||||
build_if(Ann, Cond, Then, [{elif, Ann1, Cond1, Then1} | Elses]) ->
|
||||
{'if', Ann, Cond, Then,
|
||||
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};
|
||||
build_if(Ann, Cond, Then, []) ->
|
||||
{'if', Ann, Cond, Then, {tuple, [{origin, system}], []}}.
|
||||
|
||||
else_branches([Elif = {elif, _, _, _} | Stmts], Acc) ->
|
||||
else_branches(Stmts, [Elif | Acc]);
|
||||
else_branches([Else = {'else', _, _} | Stmts], Acc) ->
|
||||
else_branches([Else = {else, _, _} | Stmts], Acc) ->
|
||||
{lists:reverse([Else | Acc]), Stmts};
|
||||
else_branches(Stmts, Acc) ->
|
||||
{lists:reverse(Acc), Stmts}.
|
||||
@@ -706,7 +702,7 @@ expand_includes([], Included, Acc, Opts) ->
|
||||
end;
|
||||
expand_includes([{include, Ann, {string, _SAnn, File}} | AST], Included, Acc, Opts) ->
|
||||
case get_include_code(File, Ann, Opts) of
|
||||
{ok, AbsDir, Code} ->
|
||||
{ok, Code} ->
|
||||
Hashed = hash_include(File, Code),
|
||||
case sets:is_element(Hashed, Included) of
|
||||
false ->
|
||||
@@ -716,10 +712,9 @@ expand_includes([{include, Ann, {string, _SAnn, File}} | AST], Included, Acc, Op
|
||||
_ -> indirect
|
||||
end,
|
||||
Opts1 = lists:keystore(src_file, 1, Opts, {src_file, File}),
|
||||
Opts2 = lists:keystore(src_dir, 1, Opts1, {src_dir, AbsDir}),
|
||||
Opts3 = lists:keystore(include_type, 1, Opts2, {include_type, IncludeType}),
|
||||
Opts2 = lists:keystore(include_type, 1, Opts1, {include_type, IncludeType}),
|
||||
Included1 = sets:add_element(Hashed, Included),
|
||||
case parse_and_scan(file(), Code, Opts3) of
|
||||
case parse_and_scan(file(), Code, Opts2) of
|
||||
{ok, AST1} ->
|
||||
expand_includes(AST1 ++ AST, Included1, Acc, Opts);
|
||||
Err = {error, _} ->
|
||||
@@ -737,12 +732,13 @@ expand_includes([E | AST], Included, Acc, Opts) ->
|
||||
read_file(File, Opts) ->
|
||||
case proplists:get_value(include, Opts, {explicit_files, #{}}) of
|
||||
{file_system, Paths} ->
|
||||
lists:foldr(fun(Path, {error, _}) -> read_file_(Path, File);
|
||||
(_Path, OK) -> OK end, {error, not_found}, Paths);
|
||||
CandidateNames = [ filename:join(Dir, File) || Dir <- Paths ],
|
||||
lists:foldr(fun(F, {error, _}) -> file:read_file(F);
|
||||
(_F, OK) -> OK end, {error, not_found}, CandidateNames);
|
||||
{explicit_files, Files} ->
|
||||
case maps:get(binary_to_list(File), Files, not_found) of
|
||||
not_found -> {error, not_found};
|
||||
Src -> {ok, File, Src}
|
||||
Src -> {ok, Src}
|
||||
end;
|
||||
escript ->
|
||||
try
|
||||
@@ -751,7 +747,7 @@ read_file(File, Opts) ->
|
||||
Archive = proplists:get_value(archive, Sections),
|
||||
FileName = binary_to_list(filename:join([aesophia, priv, stdlib, File])),
|
||||
case zip:extract(Archive, [{file_list, [FileName]}, memory]) of
|
||||
{ok, [{_, Src}]} -> {ok, escript, Src};
|
||||
{ok, [{_, Src}]} -> {ok, Src};
|
||||
_ -> {error, not_found}
|
||||
end
|
||||
catch _:_ ->
|
||||
@@ -759,13 +755,6 @@ read_file(File, Opts) ->
|
||||
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() ->
|
||||
StdLibDir = aeso_stdlib:stdlib_include_path(),
|
||||
case filelib:is_dir(StdLibDir) of
|
||||
@@ -774,37 +763,23 @@ stdlib_options() ->
|
||||
end.
|
||||
|
||||
get_include_code(File, Ann, Opts) ->
|
||||
%% Temporarily extend include paths with the directory of the current file
|
||||
Opts1 = include_current_file_dir(Opts, Ann),
|
||||
case {read_file(File, Opts1), read_file(File, stdlib_options())} of
|
||||
{{ok, Dir, Bin}, {ok, _}} ->
|
||||
case {read_file(File, Opts), read_file(File, stdlib_options())} of
|
||||
{{ok, Bin}, {ok, _}} ->
|
||||
case filename:basename(File) == File of
|
||||
true -> { error
|
||||
, fail( ann_pos(Ann)
|
||||
, "Illegal redefinition of standard library " ++ binary_to_list(File))};
|
||||
%% If a path is provided then the stdlib takes lower priority
|
||||
false -> {ok, Dir, binary_to_list(Bin)}
|
||||
false -> {ok, binary_to_list(Bin)}
|
||||
end;
|
||||
{_, {ok, _, Bin}} ->
|
||||
{ok, stdlib, binary_to_list(Bin)};
|
||||
{{ok, Dir, Bin}, _} ->
|
||||
{ok, Dir, binary_to_list(Bin)};
|
||||
{_, {ok, Bin}} ->
|
||||
{ok, binary_to_list(Bin)};
|
||||
{{ok, Bin}, _} ->
|
||||
{ok, binary_to_list(Bin)};
|
||||
{_, _} ->
|
||||
{error, {ann_pos(Ann), include_error, File}}
|
||||
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().
|
||||
hash_include(File, Code) when is_binary(File) ->
|
||||
hash_include(binary_to_list(File), Code);
|
||||
|
||||
+3
-5
@@ -6,7 +6,6 @@
|
||||
%%% @end
|
||||
%%%-------------------------------------------------------------------
|
||||
-module(aeso_pretty).
|
||||
-vsn("8.0.1").
|
||||
|
||||
-import(prettypr, [text/1, sep/1, above/2, beside/2, nest/2, empty/0]).
|
||||
|
||||
@@ -388,8 +387,7 @@ expr_p(_, {Type, _, Bin})
|
||||
when Type == account_pubkey;
|
||||
Type == contract_pubkey;
|
||||
Type == oracle_pubkey;
|
||||
Type == oracle_query_id;
|
||||
Type == signature ->
|
||||
Type == oracle_query_id ->
|
||||
text(binary_to_list(aeser_api_encoder:encode(Type, Bin)));
|
||||
expr_p(_, {string, _, <<>>}) -> text("\"\"");
|
||||
expr_p(_, {string, _, S}) ->
|
||||
@@ -420,7 +418,7 @@ stmt_p({'if', _, Cond, Then}) ->
|
||||
block_expr(200, beside(text("if"), paren(expr(Cond))), Then);
|
||||
stmt_p({elif, _, Cond, Then}) ->
|
||||
block_expr(200, beside(text("elif"), paren(expr(Cond))), Then);
|
||||
stmt_p({'else', Else}) ->
|
||||
stmt_p({else, Else}) ->
|
||||
HideGenerated = not show_generated(),
|
||||
case aeso_syntax:get_ann(origin, Else) of
|
||||
system when HideGenerated -> empty();
|
||||
@@ -535,5 +533,5 @@ get_elifs(If = {'if', Ann, Cond, Then, Else}, Elifs) ->
|
||||
elif -> get_elifs(Else, [{elif, Ann, Cond, Then} | Elifs]);
|
||||
_ -> {lists:reverse(Elifs), If}
|
||||
end;
|
||||
get_elifs(Else, Elifs) -> {lists:reverse(Elifs), {'else', Else}}.
|
||||
get_elifs(Else, Elifs) -> {lists:reverse(Elifs), {else, Else}}.
|
||||
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
%%% @end
|
||||
%%%-------------------------------------------------------------------
|
||||
-module(aeso_scan).
|
||||
-vsn("8.0.1").
|
||||
|
||||
-export([scan/1, utf8_encode/1]).
|
||||
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
%%% @end
|
||||
%%%-------------------------------------------------------------------
|
||||
-module(aeso_scan_lib).
|
||||
-vsn("8.0.1").
|
||||
|
||||
-export([compile/1, string/3,
|
||||
token/1, token/2, symbol/0, skip/0,
|
||||
|
||||
+2
-3
@@ -9,10 +9,9 @@
|
||||
%%%-------------------------------------------------------------------
|
||||
|
||||
-module(aeso_stdlib).
|
||||
-vsn("8.0.1").
|
||||
|
||||
-export([stdlib_include_path/0]).
|
||||
|
||||
stdlib_include_path() ->
|
||||
{file, Path} = code:is_loaded(?MODULE),
|
||||
filename:join(filename:dirname(filename:dirname(Path)), "priv/stdlib").
|
||||
filename:join([code:priv_dir(aesophia), "stdlib"]).
|
||||
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
%%%-------------------------------------------------------------------
|
||||
|
||||
-module(aeso_syntax).
|
||||
-vsn("8.0.1").
|
||||
|
||||
-export([get_ann/1, get_ann/2, get_ann/3, set_ann/2, qualify/2]).
|
||||
|
||||
@@ -101,7 +100,6 @@
|
||||
| {contract_pubkey, ann(), binary()}
|
||||
| {oracle_pubkey, ann(), binary()}
|
||||
| {oracle_query_id, ann(), binary()}
|
||||
| {signature, ann(), binary()}
|
||||
| {string, ann(), binary()}
|
||||
| {char, ann(), integer()}.
|
||||
|
||||
|
||||
@@ -5,9 +5,8 @@
|
||||
%%% @end
|
||||
%%%-------------------------------------------------------------------
|
||||
-module(aeso_syntax_utils).
|
||||
-vsn("8.0.1").
|
||||
|
||||
-export([used_ids/1, used_ids/2, used_types/2, used/1]).
|
||||
-export([used_ids/1, used_types/2, used/1]).
|
||||
|
||||
-record(alg, {zero, plus, scoped}).
|
||||
|
||||
@@ -111,16 +110,8 @@ fold(Alg = #alg{zero = Zero, plus = Plus, scoped = Scoped}, Fun, K, X) ->
|
||||
|
||||
%% Name dependencies
|
||||
|
||||
%% Used ids, top level
|
||||
used_ids(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.
|
||||
[ X || {{term, [X]}, _} <- used(E) ].
|
||||
|
||||
used_types([Top] = _CurrentNS, T) ->
|
||||
F = fun({{type, [X]}, _}) -> [X];
|
||||
|
||||
+1
-14
@@ -5,24 +5,11 @@
|
||||
%%% @end
|
||||
%%%-------------------------------------------------------------------
|
||||
-module(aeso_utils).
|
||||
-vsn("8.0.1").
|
||||
|
||||
-export([scc/1, canonical_dir/1]).
|
||||
-export([scc/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
|
||||
|
||||
-type graph(Node) :: #{Node => [Node]}. %% List of incoming edges (dependencies).
|
||||
|
||||
+11
-19
@@ -5,21 +5,16 @@
|
||||
%%%-------------------------------------------------------------------
|
||||
|
||||
-module(aeso_vm_decode).
|
||||
-vsn("8.0.1").
|
||||
|
||||
-export([ from_fate/2 ]).
|
||||
|
||||
-include("$aebytecode_include/aeb_fate_data.hrl").
|
||||
-include_lib("aebytecode/include/aeb_fate_data.hrl").
|
||||
|
||||
-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, _, "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_query"}, _}, ?FATE_ORACLE_Q(Bin)) -> {oracle_query_id, [], 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({id, _, "bits"}, ?FATE_BITS(N)) -> make_bits(N);
|
||||
from_fate({id, _, "int"}, N) when is_integer(N) ->
|
||||
@@ -83,7 +78,6 @@ from_fate_builtin(QType, Val) ->
|
||||
Hsh = {bytes_t, [], 32},
|
||||
I32 = {bytes_t, [], 32},
|
||||
I48 = {bytes_t, [], 48},
|
||||
Bts = {bytes_t, [], any},
|
||||
Qid = fun(Name) -> {qid, [], Name} 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],
|
||||
@@ -109,16 +103,16 @@ from_fate_builtin(QType, Val) ->
|
||||
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)]);
|
||||
{["AENSv2", "pointee"], {variant, [1, 1, 1, 1, 1], 0, {Val}}} ->
|
||||
App(["AENSv2","AccountPt"], [Chk(Adr, Val)]);
|
||||
{["AENSv2", "pointee"], {variant, [1, 1, 1, 1, 1], 1, {Val}}} ->
|
||||
App(["AENSv2","OraclePt"], [Chk(Adr, Val)]);
|
||||
{["AENSv2", "pointee"], {variant, [1, 1, 1, 1, 1], 2, {Val}}} ->
|
||||
App(["AENSv2","ContractPt"], [Chk(Adr, Val)]);
|
||||
{["AENSv2", "pointee"], {variant, [1, 1, 1, 1, 1], 3, {Val}}} ->
|
||||
App(["AENSv2","ChannelPt"], [Chk(Adr, Val)]);
|
||||
{["AENSv2", "pointee"], {variant, [1, 1, 1, 1, 1], 4, {Val}}} ->
|
||||
App(["AENSv2","DataPt"], [Chk(Str, Val)]);
|
||||
|
||||
{["Chain", "ga_meta_tx"], {variant, [2], 0, {Addr, X}}} ->
|
||||
App(["Chain","GAMetaTx"], [Chk(Adr, Addr), Chk(Int, X)]);
|
||||
@@ -191,5 +185,3 @@ make_bits(Set, Zero, I, N) when 0 == N rem 2 ->
|
||||
make_bits(Set, Zero, I, N) ->
|
||||
{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,5 +1,4 @@
|
||||
-module(aeso_warnings).
|
||||
-vsn("8.0.1").
|
||||
|
||||
-record(warn, { pos :: aeso_errors:pos()
|
||||
, message :: iolist()
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
{application, aesophia,
|
||||
[{description, "Compiler for Aeternity Sophia language"},
|
||||
{vsn, "8.0.1"},
|
||||
{vsn, "8.0.0"},
|
||||
{registered, []},
|
||||
{applications,
|
||||
[kernel,
|
||||
stdlib,
|
||||
jsx,
|
||||
syntax_tools,
|
||||
getopt,
|
||||
aebytecode,
|
||||
eblake2
|
||||
]},
|
||||
|
||||
@@ -85,7 +85,6 @@ compilable_contracts() ->
|
||||
{"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", "read", ["{label = \"question 1\", result = 4}"]},
|
||||
{"funargs", "any_bytes", ["Bytes.to_any_size(#0011AA)"]},
|
||||
{"funargs", "sjutton", ["#0011012003100011012003100011012003"]},
|
||||
{"funargs", "sextiosju", ["#01020304050607080910111213141516171819202122232425262728293031323334353637383940"
|
||||
"414243444546474849505152535455565758596061626364656667"]},
|
||||
@@ -117,7 +116,6 @@ compilable_contracts() ->
|
||||
{"funargs", "chain_base_tx", ["Chain.NameRevokeTx(#ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff)"]},
|
||||
{"funargs", "chain_base_tx", ["Chain.NameTransferTx(ak_2dATVcZ9KJU5a8hdsVtTv21pYiGWiPbmVcU1Pz72FFqpk9pSRR, #ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff)"]},
|
||||
{"funargs", "chain_base_tx", ["Chain.GAAttachTx"]},
|
||||
{"funargs", "sig", ["sg_MhibzTP1wWzGCTjtPFr1TiPqRJrrJqw7auvEuF5i3FdoALWqXLBDY6xxRRNUSPHK3EQTnTzF12EyspkxrSMxVHKsZeSMj"]},
|
||||
{"variant_types", "init", []},
|
||||
{"basic_auth", "init", []},
|
||||
{"address_literals", "init", []},
|
||||
|
||||
@@ -70,7 +70,6 @@ simple_compile_test_() ->
|
||||
fun() ->
|
||||
#{ warnings := Warnings } = compile("warnings", [warn_all]),
|
||||
#{ warnings := [] } = compile("warning_unused_include_no_include", [warn_all]),
|
||||
#{ warnings := [] } = compile("warning_used_record_typedef", [warn_all]),
|
||||
check_warnings(warnings(), Warnings)
|
||||
end} ] ++
|
||||
[].
|
||||
@@ -162,7 +161,6 @@ compilable_contracts() ->
|
||||
"state_handling",
|
||||
"events",
|
||||
"include",
|
||||
"relative_include",
|
||||
"basic_auth",
|
||||
"basic_auth_tx",
|
||||
"bitcoin_auth",
|
||||
@@ -895,10 +893,10 @@ failing_contracts() ->
|
||||
"Trying to implement or extend an undefined interface `Z`">>
|
||||
])
|
||||
, ?TYPE_ERROR(polymorphism_contract_interface_same_name_different_type,
|
||||
[<<?Pos(5,5)
|
||||
"Cannot unify `char` and `int`\n"
|
||||
"when implementing the entrypoint `f` from the interface `I1`">>
|
||||
])
|
||||
[<<?Pos(9,5)
|
||||
"Duplicate definitions of `f` at\n"
|
||||
" - line 8, column 5\n"
|
||||
" - line 9, column 5">>])
|
||||
, ?TYPE_ERROR(polymorphism_contract_missing_implementation,
|
||||
[<<?Pos(4,20)
|
||||
"Unimplemented entrypoint `f` from the interface `I1` in the contract `I2`">>
|
||||
@@ -1302,10 +1300,6 @@ failing_contracts() ->
|
||||
<<?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_() ->
|
||||
@@ -1353,9 +1347,7 @@ validate(Contract1, Contract2) ->
|
||||
true -> [debug_mode];
|
||||
false -> []
|
||||
end ++
|
||||
[ {src_file, lists:concat([Contract2, ".aes"])}
|
||||
, {include, {file_system, [aeso_test_utils:contract_path()]}}
|
||||
]);
|
||||
[{include, {file_system, [aeso_test_utils:contract_path()]}}]);
|
||||
Error -> print_and_throw(Error)
|
||||
end.
|
||||
|
||||
|
||||
@@ -1,40 +0,0 @@
|
||||
-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)"}
|
||||
].
|
||||
|
||||
@@ -1,21 +1,19 @@
|
||||
include "Option.aes"
|
||||
include "String.aes"
|
||||
include "AENSCompat.aes"
|
||||
contract interface OldAENSContract =
|
||||
entrypoint set : (string, string, AENS.pointee) => unit
|
||||
entrypoint lookup : (string, string) => AENS.pointee
|
||||
|
||||
main contract AENSUpdate =
|
||||
stateful entrypoint update_name(owner : address, name : string, b : bytes(2)) =
|
||||
stateful entrypoint update_name(owner : address, name : string) =
|
||||
let p1 : AENSv2.pointee = AENSv2.AccountPt(Call.caller)
|
||||
let 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))
|
||||
let p5 : AENSv2.pointee = AENSv2.DataPt("any something will do")
|
||||
AENSv2.update(owner, name, None, None,
|
||||
Some({ ["account_pubkey"] = p1, ["oracle_pubkey"] = p2,
|
||||
["contract_pubkey"] = p3, ["misc"] = p4, ["data"] = p5, ["data2"] = p6 }))
|
||||
["contract_pubkey"] = p3, ["misc"] = p4, ["data"] = p5 }))
|
||||
|
||||
stateful entrypoint old_interaction(c : OldAENSContract, owner : address, name : string) =
|
||||
let p : AENS.pointee = c.lookup(name, "key1")
|
||||
|
||||
@@ -11,5 +11,4 @@ contract C =
|
||||
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)
|
||||
(a bor b band c bxor a << bnot b >> a, k)
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
include "../dir2/baz.aes"
|
||||
namespace D =
|
||||
function g() = E.h()
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
namespace E =
|
||||
function h() = 42
|
||||
|
||||
@@ -20,8 +20,6 @@ contract FunctionArguments =
|
||||
entrypoint read(a : answer(int)) =
|
||||
a.result
|
||||
|
||||
entrypoint any_bytes(b : bytes()) = b
|
||||
|
||||
entrypoint sjutton(b : bytes(17)) =
|
||||
b
|
||||
|
||||
@@ -59,5 +57,3 @@ contract FunctionArguments =
|
||||
entrypoint chain_ga_meta_tx(tx : Chain.ga_meta_tx) = true
|
||||
entrypoint chain_paying_for_tx(tx : Chain.paying_for_tx) = true
|
||||
entrypoint chain_base_tx(tx : Chain.base_tx) = true
|
||||
|
||||
entrypoint sig(sg : signature) = true
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
include "./dir1/bar.aes"
|
||||
contract C =
|
||||
entrypoint f() = D.g()
|
||||
@@ -1,60 +0,0 @@
|
||||
contract C =
|
||||
entrypoint too_many(
|
||||
(_, _, _, _, _, _, _, _, _, _),
|
||||
(_, _, _, _, _, _, _, _, _, _),
|
||||
(_, _, _, _, _, _, _, _, _, _),
|
||||
(_, _, _, _, _, _, _, _, _, _),
|
||||
(_, _, _, _, _, _, _, _, _, _),
|
||||
(_, _, _, _, _, _, _, _, _, _),
|
||||
(_, _, _, _, _, _, _, _, _, _),
|
||||
(_, _, _, _, _, _, _, _, _, _),
|
||||
(_, _, _, _, _, _, _, _, _, _),
|
||||
(_, _, _, _, _, _, _, _, _, _),
|
||||
|
||||
(_, _, _, _, _, _, _, _, _, _),
|
||||
(_, _, _, _, _, _, _, _, _, _),
|
||||
(_, _, _, _, _, _, _, _, _, _),
|
||||
(_, _, _, _, _, _, _, _, _, _),
|
||||
(_, _, _, _, _, _, _, _, _, _),
|
||||
(_, _, _, _, _, _, _, _, _, _),
|
||||
(_, _, _, _, _, _, _, _, _, _),
|
||||
(_, _, _, _, _, _, _, _, _, _),
|
||||
(_, _, _, _, _, _, _, _, _, _),
|
||||
(_, _, _, _, _, _, _, _, _, _),
|
||||
|
||||
(_, _, _, _, _, _, _, _, _, _),
|
||||
(_, _, _, _, _, _, _, _, _, _),
|
||||
(_, _, _, _, _, _, _, _, _, _),
|
||||
(_, _, _, _, _, _, _, _, _, _),
|
||||
(_, _, _, _, _, _, _, _, _, _),
|
||||
(_, _, _, _, _, _, _, _, _, _)) = 0
|
||||
|
||||
entrypoint not_too_many(
|
||||
(_, _, _, _, _, _, _, _, _, _),
|
||||
(_, _, _, _, _, _, _, _, _, _),
|
||||
(_, _, _, _, _, _, _, _, _, _),
|
||||
(_, _, _, _, _, _, _, _, _, _),
|
||||
(_, _, _, _, _, _, _, _, _, _),
|
||||
(_, _, _, _, _, _, _, _, _, _),
|
||||
(_, _, _, _, _, _, _, _, _, _),
|
||||
(_, _, _, _, _, _, _, _, _, _),
|
||||
(_, _, _, _, _, _, _, _, _, _),
|
||||
(_, _, _, _, _, _, _, _, _, _),
|
||||
|
||||
(_, _, _, _, _, _, _, _, _, _),
|
||||
(_, _, _, _, _, _, _, _, _, _),
|
||||
(_, _, _, _, _, _, _, _, _, _),
|
||||
(_, _, _, _, _, _, _, _, _, _),
|
||||
(_, _, _, _, _, _, _, _, _, _),
|
||||
(_, _, _, _, _, _, _, _, _, _),
|
||||
(_, _, _, _, _, _, _, _, _, _),
|
||||
(_, _, _, _, _, _, _, _, _, _),
|
||||
(_, _, _, _, _, _, _, _, _, _),
|
||||
(_, _, _, _, _, _, _, _, _, _),
|
||||
|
||||
(_, _, _, _, _, _, _, _, _, _),
|
||||
(_, _, _, _, _, _, _, _, _, _),
|
||||
(_, _, _, _, _, _, _, _, _, _),
|
||||
(_, _, _, _, _, _, _, _, _, _),
|
||||
(_, _, _, _, _, _, _, _, _, _),
|
||||
(_, _, _, _, _, _)) = 0
|
||||
@@ -36,7 +36,7 @@ contract UnappliedBuiltins =
|
||||
function map_delete() = Map.delete : (_, m) => _
|
||||
function map_from_list() = Map.from_list : _ => m
|
||||
function map_to_list() = Map.to_list : m => _
|
||||
function crypto_verify_sig() = Crypto.verify_sig : (bytes(), _, _) => _
|
||||
function crypto_verify_sig() = Crypto.verify_sig
|
||||
function crypto_verify_sig_secp256k1() = Crypto.verify_sig_secp256k1
|
||||
function crypto_ecverify_secp256k1() = Crypto.ecverify_secp256k1
|
||||
function crypto_ecrecover_secp256k1() = Crypto.ecrecover_secp256k1
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
contract Test =
|
||||
type option_int = option(int)
|
||||
record option_point = {x: int, y: option_int}
|
||||
|
||||
entrypoint test_option_record(a: option_point) = a
|
||||
@@ -1,21 +0,0 @@
|
||||
{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,[]}.
|
||||
@@ -1,19 +0,0 @@
|
||||
#! /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