Compare commits

..

30 Commits

Author SHA1 Message Date
Dimitar Ivanov e30d99d87b Bump gmserialization to v1.2.0 2025-03-01 16:12:45 +02:00
Hans Svensson 927cd42592 Add check for number of type variables in type signature (#512)
* Fix tvar string generation

* Add check for number of tvars in a single type signature

The number of tvars is limited by serialization (u8) to 255

* Added a comment in CHANGELOG

* Docs fixes

* Adding docs about the limitation on number of tvars

* Limit is 256, not 255

* Update CHANGELOG.md

Co-authored-by: Gaith Hallak <gaithhallak@gmail.com>

---------

Co-authored-by: Gaith Hallak <gaithhallak@gmail.com>
2024-08-26 13:34:02 +02:00
Denis Davidyuk 16308a7840 Docs: Move poseidon outside of create (#510) 2024-08-12 09:02:56 +02:00
Denis Davidyuk 46a307432f Docs: Fix return value type in Auction example (#511) 2024-08-12 09:02:29 +02:00
Gaith Hallak 83dcc6dbc4 Upgrade to the latest aebytecode to fix C warnings (#509) 2024-05-24 15:46:21 +03:00
Hans Svensson ffdd4ecf26 Prepare release v8.0.0 (#506) 2024-04-18 09:15:34 +02:00
Hans Svensson 51bae61736 Add signature literals (#505)
* Add signature literals + handle system alias types

* Add tests for signature literals + encode/decode

* Add to CHANGELOG

* Add in documentation

* Additional documentation
2024-04-10 16:34:29 +02:00
Gaith Hallak 31301911a2 Docs: Mention the unit type in the literals section (#504) 2024-02-16 19:11:08 +03:00
Hans Svensson de426a210b Fix parser/pretty printer for OTP-27 (#502)
* In OTP-27 else is made a keyword, so needs quouting

* Fix List.aes - remove unnecessary self-qualification

* Changelog
2024-02-16 09:57:23 +01:00
Hans Svensson 944ed49f0b Allow self-qualification (#503)
* Properly allow self-qualification

* Changelog

* Simplify logic as suggested by Ulf
2024-02-16 09:56:26 +01:00
Radosław Rowicki 1387e814f8 Fix printing FCode with lifted lambdas (#501) 2024-02-04 09:24:41 +01:00
Hans Svensson 44d6982d66 Prepare release v8.0.0-rc1 2024-01-31 09:11:30 +01:00
Hans Svensson aa532046d3 [Ceres]: Improve documentation of new features 2024-01-31 09:11:30 +01:00
Hans Svensson fbaab570f2 [Ceres]: Handle Bytes.to_any_size in calldata (#495)
* [Ceres] Handle Bytes.to_any_size in calldata

* Edit CHANGELOG
2024-01-31 09:11:30 +01:00
Hans Svensson 1a80f3faa0 [Ceres]: Update delegation signature documentation (#494)
* [Ceres]: Update delegation signature documentation

* Fix TYPOs
2024-01-31 09:11:30 +01:00
Hans Svensson 745eeda858 [Ceres]: Raw pointers as bytes (#493)
* DataPt should contain bytes() now that we have it

* Fix missing negation in docs
2024-01-31 09:11:30 +01:00
Hans Svensson 78b758c337 [Ceres]: Allow arbitrary sized message in Crypto.verify_sig (#481)
* Allow arbitrary sized msg in signature verification

* Move Address.to_bytes documentation to correct place
2024-01-31 09:11:30 +01:00
Hans Svensson 108cb1f948 [Ceres]: Add Chain.network_id (#468)
* Add Chain.network_id

* Bump aebytecode version
2024-01-31 09:11:30 +01:00
Hans Svensson 2c8dcf8032 [Ceres]: Add arbitrary size byte arrays (#456)
* Extend compiler to allow bytes()/bytes as type

* Add split_any, to_fixed_size, size, to_any_size, Int.to_bytes and String.to_bytes

* Add tests

* Use and and not andalso in unify, some things have side-effects

* Bump to aebytecode v3.3.0

* Changelog + update documentation

* fix wording in documentation
2024-01-31 09:11:30 +01:00
Hans Svensson c51d0a5e21 [Ceres]: Document generic all names delegation signatures (#440) 2024-01-31 09:11:30 +01:00
Hans Svensson e44174b71c [Ceres]: document changes to Auth.tx_hash (#439) 2024-01-31 09:11:30 +01:00
Hans Svensson dcea538e11 [Ceres]: Introduce AENSv2 to add raw data pointers (#426)
Remove unused variable in AENSCompat
2024-01-31 09:11:30 +01:00
Hans Svensson f60f9122ba [Ceres]: Add bitwise ops, Address.to_bytes and Crypto.poseidon 2024-01-31 09:11:30 +01:00
Hans Svensson 5c3b42aff1 Fix Typo and whitespace in sophia_features.md (#500) 2024-01-25 09:57:08 +01:00
Hans Svensson dbeb792ca5 Prepare release v4.7.1 (#497) 2024-01-23 16:14:03 +01:00
Hans Svensson f75455bb85 Bump pygments version (#496) 2024-01-23 15:55:12 +01:00
Gaith Hallak cdbd430f23 Disable unused type warnings for type used inside of records (#492)
* Do not show warning for types used in records

* Exclude .vscode in .gitignore

* Update CHANGELOG.md
2023-11-27 12:12:24 +03:00
Hans Svensson 03d6dd6ca2 Improve resolution of relative includes (#489)
* Add aeso_utils:canonical_dir/1

* Add current file directory when resolving includes

* Add CHANGELOG

* Add documentation

* Add a test case

* Properly keep track of src_dir
2023-09-14 15:00:30 +02:00
Hans Svensson 33229c3513 Prepare release v7.4.0 (#487) 2023-09-05 10:04:46 +02:00
Radosław Rowicki 002e55d529 Name lambdas by their locations (#486)
* Name lambdas by their locations

* changelog
2023-09-04 18:50:37 +02:00
35 changed files with 824 additions and 446 deletions
+1 -1
View File
@@ -2,4 +2,4 @@ mkdocs==1.4.2
mkdocs-simple-hooks==0.1.5 mkdocs-simple-hooks==0.1.5
mkdocs-material==9.0.9 mkdocs-material==9.0.9
mike==1.1.2 mike==1.1.2
pygments==2.14.0 pygments==2.17.2
+2
View File
@@ -19,8 +19,10 @@ rebar3.crashdump
*.erl~ *.erl~
*.aes~ *.aes~
aesophia aesophia
sophia
.qcci .qcci
current_counterexample.eqc current_counterexample.eqc
test/contracts/test.aes test/contracts/test.aes
__pycache__ __pycache__
.docssite/docs/*.md .docssite/docs/*.md
.vscode
+37 -6
View File
@@ -4,7 +4,18 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [CERES 8.0.0] ## [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]
### Added ### Added
- Bitwise operations for integers: `band`, `bor`, `bxor`, `bnot`, `<<` and `>>`. - Bitwise operations for integers: `band`, `bor`, `bxor`, `bnot`, `<<` and `>>`.
- `Int.mulmod` - combined builtin operation for multiplication and modulus. - `Int.mulmod` - combined builtin operation for multiplication and modulus.
@@ -12,7 +23,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.). - `Address.to_bytes` - convert an address to its binary representation (for hashing, etc.).
- Raw data pointers added to AENS. In short we have introduced a new namespace - Raw data pointers added to AENS. In short we have introduced a new namespace
`AENSv2`; they contain types similar to the old `AENS`; `AENS.name` and `AENSv2`; they contain types similar to the old `AENS`; `AENS.name` and
`AENS.pointee`, where the latter now has a constructor `DataPt(string)`. All `AENS.pointee`, where the latter now has a constructor `DataPt(bytes())`. All
AENS actions have been moved to `AENSv2`, and `AENSv2.lookup` and AENS actions have been moved to `AENSv2`, and `AENSv2.lookup` and
`AENSv2.update` consume and produce the new types. The old `AENS` namespace `AENSv2.update` consume and produce the new types. The old `AENS` namespace
only contains the old datatypes, that can be used to interface existing only contains the old datatypes, that can be used to interface existing
@@ -23,17 +34,33 @@ 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 and `Int.to_bytes`; and adjust `Bytes.concat` to allow both fixed and arbitrary
sized byte arrays. sized byte arrays.
- `Chain.network_id` - a function to get hold of the Chain's network id. - `Chain.network_id` - a function to get hold of the Chain's network id.
- Allowing `Bytes.to_any_size` in calldata creation, to enable creation of arguments
with arbitray size.
- Signature literals `sg_...` - they have type `signature` (which is an alias for `bytes(64)`).
- Support for OTP-27 - no changes in behavior.
### Changed ### Changed
- `Crypto.verify_sig` is changed to have `msg : bytes()`. I.e. the - `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`). signed data can be of any length (used to be limited to `bytes(32)`/`hash`).
- System aliases are handled explicitly when converting to a Sophia value, this is only
observable for `signature` where a value of type `signature` is now represented as a
(new) signature literal.
- Allow self-qualification, i.e. referencing `X.foo` when in namespace `X`.
### Removed ### Removed
- `Bitwise.aes` standard library is removed - the builtin operations are superior. - `Bitwise.aes` standard library is removed - the builtin operations are superior.
## [Unreleased] ## [7.4.1]
### Added
### Changed ### Changed
### Removed - Improve how includes with relative paths are resolved during parsing/compilation. Relative
include paths are now always relative to the file containing the `include` statement.
### Fixed ### 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] ## [7.3.0]
### Fixed ### Fixed
@@ -429,7 +456,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Simplify calldata creation - instead of passing a compiled contract, simply - Simplify calldata creation - instead of passing a compiled contract, simply
pass a (stubbed) contract string. pass a (stubbed) contract string.
[Unreleased]: https://github.com/aeternity/aesophia/compare/v7.3.0...HEAD [Unreleased]: https://github.com/aeternity/aesophia/compare/v8.0.1...HEAD
[8.0.1]: https://github.com/aeternity/aesophia/compare/v8.0.0...v8.0.1
[8.0.0]: https://github.com/aeternity/aesophia/compare/v7.4.1...v8.0.0
[7.4.1]: https://github.com/aeternity/aesophia/compare/v7.4.0...v7.4.1
[7.4.0]: https://github.com/aeternity/aesophia/compare/v7.3.0...v7.4.0
[7.3.0]: https://github.com/aeternity/aesophia/compare/v7.2.1...v7.3.0 [7.3.0]: https://github.com/aeternity/aesophia/compare/v7.2.1...v7.3.0
[7.2.1]: https://github.com/aeternity/aesophia/compare/v7.2.0...v7.2.1 [7.2.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.2.0]: https://github.com/aeternity/aesophia/compare/v7.1.0...v7.2.0
+75 -17
View File
@@ -84,7 +84,7 @@ the return value of the call.
```sophia ```sophia
contract interface VotingType = contract interface VotingType =
entrypoint : vote : string => unit entrypoint vote : string => unit
contract Voter = contract Voter =
entrypoint tryVote(v : VotingType, alt : string) = entrypoint tryVote(v : VotingType, alt : string) =
@@ -204,7 +204,7 @@ When a `contract` or a `contract interface` implements another `contract interfa
#### Subtyping and variance #### Subtyping and variance
Subtyping in Sophia follows common rules that take type variance into account. As described by [Wikipedia](https://en.wikipedia.org/wiki/Covariance_and_contravariance_(computer_science)), Subtyping in Sophia follows common rules that take type variance into account. As described by [Wikipedia](https://en.wikipedia.org/wiki/Covariance_and_contravariance_(computer_science)),
>Variance refers to how subtyping between more complex types relates to subtyping between their components. >Variance refers to how subtyping between more complex types relates to subtyping between their components.
@@ -224,11 +224,11 @@ A good example of where it matters can be pictured by subtyping of function type
```sophia ```sophia
contract interface Animal = contract interface Animal =
entrypoint age : () => int entrypoint age : () => int
contract Dog : Animal = contract Dog : Animal =
entrypoint age() = // ... entrypoint age() = // ...
entrypoint woof() = "woof" entrypoint woof() = "woof"
contract Cat : Animal = contract Cat : Animal =
entrypoint age() = // ... entrypoint age() = // ...
entrypoint meow() = "meow" entrypoint meow() = "meow"
@@ -295,6 +295,11 @@ of `A`.
- When a user-defined type `t('a)` is invariant in `'a`, then `t(A)` can never be - When a user-defined type `t('a)` is invariant in `'a`, then `t(A)` can never be
a subtype of `t(B)`. a subtype of `t(B)`.
#### Type variable limitation
Because of how FATE represents types as values there is a fixed upper limit (256)
of type variables that can be used in a single type signature.
## Mutable state ## Mutable state
Sophia does not have arbitrary mutable state, but only a limited form of state Sophia does not have arbitrary mutable state, but only a limited form of state
@@ -493,6 +498,24 @@ the file, except that error messages will refer to the original source
locations. The language will try to include each file at most one time automatically, locations. The language will try to include each file at most one time automatically,
so even cyclic includes should be working without any special tinkering. so even cyclic includes should be working without any special tinkering.
### Include files using relative paths
When including code from another file using the `include` statement, the path
is relative to _the file that includes it_. Consider the following file tree:
```
c1.aes
c3.aes
dir1/c2.aes
dir1/c3.aes
```
If `c1.aes` contains `include "c3.aes"` it will include the top level `c3.aes`,
while if `c2.aes` contained the same line it would as expected include
`dir1/c3.aes`.
Note: Prior to v7.5.0, it would consider the include path relative to _the main
contract file_ (or any explicitly set include path).
## Standard library ## Standard library
Sophia offers [standard library](sophia_stdlib.md) which exposes some Sophia offers [standard library](sophia_stdlib.md) which exposes some
@@ -540,6 +563,7 @@ Sophia has the following types:
## Literals ## Literals
| Type | Constant/Literal example(s) | | Type | Constant/Literal example(s) |
| ---------- | ------------------------------- | | ---------- | ------------------------------- |
| unit | () |
| int | `-1`, `2425`, `4598275923475723498573485768` | | int | `-1`, `2425`, `4598275923475723498573485768` |
| address | `ak_2gx9MEFxKvY9vMG5YnqnXWv1hCsX7rgnfvBLJS4aQurustR1rt` | | address | `ak_2gx9MEFxKvY9vMG5YnqnXWv1hCsX7rgnfvBLJS4aQurustR1rt` |
| bool | `true`, `false` | | bool | `true`, `false` |
@@ -554,7 +578,7 @@ Sophia has the following types:
| state | `state{ owner = Call.origin, magic_key = #a298105f }` | | state | `state{ owner = Call.origin, magic_key = #a298105f }` |
| event | `EventX(0, "Hello")` | | event | `EventX(0, "Hello")` |
| hash | `#000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f` | | hash | `#000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f` |
| signature | `#000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f` | | signature | `sg_MhibzTP1wWzGCTjtPFr1TiPqRJrrJqw7auvEuF5i3FdoALWqXLBDY6xxRRNUSPHK3EQTnTzF12EyspkxrSMxVHKsZeSMj`, `#000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f` |
| Chain.ttl | `FixedTTL(1050)`, `RelativeTTL(50)` | | Chain.ttl | `FixedTTL(1050)`, `RelativeTTL(50)` |
| oracle('a, 'b) | `ok_2YNyxd6TRJPNrTcEDCe9ra59SVUdp9FR9qWC5msKZWYD9bP9z5` | | oracle('a, 'b) | `ok_2YNyxd6TRJPNrTcEDCe9ra59SVUdp9FR9qWC5msKZWYD9bP9z5` |
| oracle_query('a, 'b) | `oq_2oRvyowJuJnEkxy58Ckkw77XfWJrmRgmGaLzhdqb67SKEL1gPY` | | oracle_query('a, 'b) | `oq_2oRvyowJuJnEkxy58Ckkw77XfWJrmRgmGaLzhdqb67SKEL1gPY` |
@@ -610,7 +634,7 @@ arithmetic operations:
- remainder (`x mod y`), satisfying `y * (x / y) + x mod y == x` for non-zero `y` - remainder (`x mod y`), satisfying `y * (x / y) + x mod y == x` for non-zero `y`
- exponentiation (`x ^ y`) - exponentiation (`x ^ y`)
All operations are *safe* with respect to overflow and underflow. All operations are *safe* with respect to overflow and underflow.
The division and modulo operations throw an arithmetic error if the The division and modulo operations throw an arithmetic error if the
right-hand operand is zero. right-hand operand is zero.
@@ -622,10 +646,16 @@ Sophia arbitrary-sized integers (FATE) also supports the following bitwise opera
- arithmetic bitshift left (`x << n`) - arithmetic bitshift left (`x << n`)
- arithmetic bitshift right (`x >> n`) - arithmetic bitshift right (`x >> n`)
Note: Arithmetic bitshift treats the number as a signed integer (in 2s
complement), and "retains" the topmost bit. I.e. shifting in zeros if the
topmost bit was 0, and ones if it was one.
## Bit fields ## Bit fields
Sophia integers do not support bit arithmetic. Instead there is a separate Originally Sophia integers did not support bit arithmetic. Instead we used a
type `bits`. See the standard library [documentation](sophia_stdlib.md#bits). separate type `bits` (see the standard library
[documentation](sophia_stdlib.md#bits)) - it is still provided as an
alternative to bit arithmetic.
A bit field can be of arbitrary size (but it is still represented by the A bit field can be of arbitrary size (but it is still represented by the
corresponding integer, so setting very high bits can be expensive). corresponding integer, so setting very high bits can be expensive).
@@ -930,16 +960,18 @@ functions are provided.
## AENS interface ## AENS interface
Contracts can interact with the Contracts can interact with the [æternity naming
[æternity naming system](https://github.com/aeternity/protocol/blob/master/AENS.md). system](https://github.com/aeternity/protocol/blob/master/AENS.md). For this
For this purpose the [AENS](sophia_stdlib.md#aens) library was exposed. purpose the [AENS](sophia_stdlib.md#aens) and later the
[AENSv2](sophia_stdlib.md#aensv2) library was exposed.
### Example ### Example
In this example we assume that the name `name` already exists, and is owned by In this example we assume that the name `name` already exists, and is owned by
an account with address `addr`. In order to allow a contract `ct` to handle an account with address `addr`. In order to allow a contract `ct` to handle
`name` the account holder needs to create a `name` the account holder needs to create a [delegation
[signature](#delegation-signature) `sig` of `addr | name.hash | ct.address`. signature](#delegation-signature) `sig` from the name owner address `addr`, the
name hash and the contract address.
Armed with this information we can for example write a function that extends Armed with this information we can for example write a function that extends
the name if it expires within 1000 blocks: the name if it expires within 1000 blocks:
@@ -1081,8 +1113,34 @@ however is in the gas consumption — while `abort` returns unused gas, a call t
## Delegation signature ## Delegation signature
Some chain operations (`Oracle.<operation>` and `AENS.<operation>`) have an Some chain operations (`Oracle.<operation>` and `AENSv2.<operation>`) have an
optional delegation signature. This is typically used when a user/accounts optional delegation signature. This is typically used when a user/accounts
would like to allow a contract to act on it's behalf. The exact data to be would like to allow a contract to act on it's behalf.
signed varies for the different operations, but in all cases you should prepend
the signature data with the `network_id` (`ae_mainnet` for the æternity mainnet, etc.). ### From Ceres
From the Ceres protocol version the delegation signatures have more structure,
including a unique tag, `network_id` and identifiers; there are five different
delegation signatures:
- AENS wildcard - the user signs: `owner account + contract`
- `AENS_PRECLAIM` - the user signs: `owner account + contract`
- `AENS_CLAIM, AENS_UPDATE, AENS_TRANSFER, AENS_REVOKE` - the user signs: `owner account + name hash + contract`
- `ORACLE_REGISTER, ORACLE_EXTEND` - the user signs: `owner account + contract`
- `ORACLE_RESPOND` - the user signs: `query id + contract`
See [Serialized signature
data](https://github.com/aeternity/protocol/blob/master/contracts/fate.md#from-ceres-serialized-signature-data)
for the exact structure used.
### Before ceres
The exact data to be signed varies for the different operations, but in all
cases you should prepend the signature data with the `network_id` (`ae_mainnet`
for the æternity mainnet, etc.).
There are four different delegation signatures:
- `AENS_PRECLAIM` - the user signs: owner `network_id + account + contract`
- `AENS_CLAIM, AENS_UPDATE, AENS_TRANSFER, AENS_REVOKE` - the user signs: `network_id + owner account + name hash + contract`
- `ORACLE_REGISTER, ORACLE_EXTEND` - the user signs: `network_id + owner account + contract`
- `ORACLE_RESPOND` - the user signs: `network_id + query id + contract`
+55 -44
View File
@@ -146,7 +146,7 @@ datatype pointee = AccountPt(address) | OraclePt(address)
``` ```
Note: on-chain there is a maximum length enforced for `DataPt`, it is 1024 bytes. Note: on-chain there is a maximum length enforced for `DataPt`, it is 1024 bytes.
Sophia itself does _not_ enforce this. Sophia itself does _not_ check for this.
#### Functions #### Functions
@@ -181,14 +181,14 @@ Note: Changed to produce `AENSv2.name` in v8.0 (Ceres protocol upgrade).
AENSv2.preclaim(owner : address, commitment_hash : hash, <signature : signature>) : unit AENSv2.preclaim(owner : address, commitment_hash : hash, <signature : signature>) : unit
``` ```
The [signature](./sophia_features.md#delegation-signature) should be over The [signature](./sophia_features.md#delegation-signature) should be a
`network id` + `owner address` + `Contract.address` (concatenated as byte arrays). serialized structure containing `network id`, `owner address`, and
`Contract.address`.
From Ceres (i.e. FATE VM version 3) the From Ceres (i.e. FATE VM version 3) the
[signature](./sophia_features.md#delegation-signature) can also be generic [signature](./sophia_features.md#delegation-signature) can also be generic
(allowing _all_, existing and future, names to be delegated with one (allowing _all_, existing and future, names to be delegated with one
signature), i.e. over `network id` + `owner address` + `string "AENS"` + signature), i.e. containing `network id`, `owner address`, `Contract.address`.
`Contract.address`.
##### claim ##### claim
@@ -196,14 +196,14 @@ signature), i.e. over `network id` + `owner address` + `string "AENS"` +
AENSv2.claim(owner : address, name : string, salt : int, name_fee : int, <signature : signature>) : unit AENSv2.claim(owner : address, name : string, salt : int, name_fee : int, <signature : signature>) : unit
``` ```
The [signature](./sophia_features.md#delegation-signature) should be over The [signature](./sophia_features.md#delegation-signature) should be a
`network id` + `owner address` + `name_hash` + `Contract.address` (concatenated serialized structure containing `network id`, `owner address`, and
as byte arrays) using the private key of the `owner` account for signing. `Contract.address`. Using the private key of `owner address` for signing.
From Ceres (i.e. FATE VM version 3) the From Ceres (i.e. FATE VM version 3) the
[signature](./sophia_features.md#delegation-signature) can also be generic [signature](./sophia_features.md#delegation-signature) can also be generic
(allowing _all_, existing and future, names to be delegated with one (allowing _all_, existing and future, names to be delegated with one
signature), i.e. over `network id` + `owner address` + `string "AENS"` + signature), i.e. containing `network id`, `owner address`, `name_hash`, and
`Contract.address`. `Contract.address`.
@@ -214,15 +214,14 @@ AENSv2.transfer(owner : address, new_owner : address, name : string, <signature
Transfers name to the new owner. Transfers name to the new owner.
The [signature](./sophia_features.md#delegation-signature) should be over The [signature](./sophia_features.md#delegation-signature) should be a
`network id` + `owner address` + `name_hash` + `Contract.address` serialized structure containing `network id`, `owner address`, and
(concatenated as byte arrays) `Contract.address`. Using the private key of `owner address` for signing.
using the private key of the `owner` account for signing.
From Ceres (i.e. FATE VM version 3) the From Ceres (i.e. FATE VM version 3) the
[signature](./sophia_features.md#delegation-signature) can also be generic [signature](./sophia_features.md#delegation-signature) can also be generic
(allowing _all_, existing and future, names to be delegated with one (allowing _all_, existing and future, names to be delegated with one
signature), i.e. over `network id` + `owner address` + `string "AENS"` + signature), i.e. containing `network id`, `owner address`, `name_hash`, and
`Contract.address`. `Contract.address`.
@@ -233,15 +232,14 @@ AENSv2.revoke(owner : address, name : string, <signature : signature>) : unit
Revokes the name to extend the ownership time. Revokes the name to extend the ownership time.
The [signature](./sophia_features.md#delegation-signature) should be over The [signature](./sophia_features.md#delegation-signature) should be a
`network id` + `owner address` + `name_hash` + `Contract.address` serialized structure containing `network id`, `owner address`, and
(concatenated as byte arrays) `Contract.address`. Using the private key of `owner address` for signing.
using the private key of the `owner` account for signing.
From Ceres (i.e. FATE VM version 3) the From Ceres (i.e. FATE VM version 3) the
[signature](./sophia_features.md#delegation-signature) can also be generic [signature](./sophia_features.md#delegation-signature) can also be generic
(allowing _all_, existing and future, names to be delegated with one (allowing _all_, existing and future, names to be delegated with one
signature), i.e. over `network id` + `owner address` + `string "AENS"` + signature), i.e. containing `network id`, `owner address`, `name_hash`, and
`Contract.address`. `Contract.address`.
@@ -257,6 +255,16 @@ block of the name is not changed.
Note: Changed to consume `AENSv2.pointee` in v8.0 (Ceres protocol upgrade). Note: Changed to consume `AENSv2.pointee` in v8.0 (Ceres protocol upgrade).
The [signature](./sophia_features.md#delegation-signature) should be a
serialized structure containing `network id`, `owner address`, and
`Contract.address`. Using the private key of `owner address` for signing.
From Ceres (i.e. FATE VM version 3) the
[signature](./sophia_features.md#delegation-signature) can also be generic
(allowing _all_, existing and future, names to be delegated with one
signature), i.e. containing `network id`, `owner address`, `name_hash`, and
`Contract.address`.
### Auth ### Auth
@@ -606,14 +614,6 @@ charging the calling contract. Note that this won't be visible in `Call.value`
in the `init` call of the new contract. It will be included in in the `init` call of the new contract. It will be included in
`Contract.balance`, however. `Contract.balance`, however.
#### poseidon
```
Crypto.poseidon(x1 : int, x2 : int) : int
```
Hash two integers (in the scalar field of BLS12-381) to another integer (in the scalar
field of BLS12-281). This is a ZK/SNARK-friendly hash function.
The type `'c` must be instantiated with a contract. The type `'c` must be instantiated with a contract.
@@ -679,8 +679,8 @@ Example usage:
``` ```
payable contract interface Auction = payable contract interface Auction =
entrypoint init : (int, string) => void entrypoint init : (int, string) => void
stateful payable entrypoint buy : (int) => () stateful payable entrypoint buy : (int) => unit
stateful entrypoint sell : (int) => () stateful entrypoint sell : (int) => unit
main contract Market = main contract Market =
type state = list(Auction) type state = list(Auction)
@@ -740,6 +740,15 @@ Chain.network\_id : string
The network id of the chain. 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 ##### spend
``` ```
Chain.spend(to : address, amount : int) : unit Chain.spend(to : address, amount : int) : unit
@@ -885,7 +894,8 @@ Int.to_bytes(n : int, size : int) : bytes()
``` ```
Casts the integer to a byte array with `size` bytes (big endian, truncating if Casts the integer to a byte array with `size` bytes (big endian, truncating if
necessary). necessary not preserving signedness). I.e. if you try to squeeze `-129` into a
single byte that will be indistinguishable from `127`.
### Map ### Map
@@ -944,11 +954,11 @@ Oracle.register(<signature : bytes(64)>, acct : address, qfee : int, ttl : Chain
Registers new oracle answering questions of type `'a` with answers of type `'b`. Registers new oracle answering questions of type `'a` with answers of type `'b`.
* The `acct` is the address of the oracle to register (can be the same as the contract). * The `acct` is the address of the oracle to register (can be the same as the contract).
* `signature` is a signature proving that the contract is allowed to register the account - * The [signature](./sophia_features.md#delegation-signature) should be a
the `network id` + `account address` + `contract address` (concatenated as byte arrays) is serialized structure containing `network id`, `account address`, and
[signed](./sophia_features.md#delegation-signature) with the `contract address`. Using the private key of `account address` for signing.
private key of the account, proving you have the private key of the oracle to be. If the Proving you have the private key of the oracle to be. If the address is the same
address is the same as the contract `sign` is ignored and can be left out entirely. as the contract `sign` is ignored and can be left out entirely.
* The `qfee` is the minimum query fee to be paid by a user when asking a question of the oracle. * The `qfee` is the minimum query fee to be paid by a user when asking a question of the oracle.
* The `ttl` is the Time To Live for the oracle in key blocks, either relative to the current * The `ttl` is the Time To Live for the oracle in key blocks, either relative to the current
key block height (`RelativeTTL(delta)`) or a fixed key block height (`FixedTTL(height)`). key block height (`RelativeTTL(delta)`) or a fixed key block height (`FixedTTL(height)`).
@@ -962,7 +972,7 @@ Examples:
``` ```
#### get_question #### get\_question
``` ```
Oracle.get_question(o : oracle('a, 'b), q : oracle_query('a, 'b)) : 'a Oracle.get_question(o : oracle('a, 'b), q : oracle_query('a, 'b)) : 'a
``` ```
@@ -975,12 +985,11 @@ Checks what was the question of query `q` on oracle `o`
Oracle.respond(<signature : bytes(64)>, o : oracle('a, 'b), q : oracle_query('a, 'b), 'b) : unit Oracle.respond(<signature : bytes(64)>, o : oracle('a, 'b), q : oracle_query('a, 'b), 'b) : unit
``` ```
Responds to the question `q` on `o`. Responds to the question `q` on `o`. Unless the contract address is the same
Unless the contract address is the same as the oracle address the `signature` as the oracle address the `signature` (which is an optional, named argument)
(which is an optional, named argument)
needs to be provided. Proving that we have the private key of the oracle by needs to be provided. Proving that we have the private key of the oracle by
[signing](./sophia_features.md#delegation-signature) [signing](./sophia_features.md#delegation-signature) should be a serialized
the `network id` + `oracle query id` + `contract address` structure containing `network id`, `oracle query id`, and `contract address`.
#### extend #### extend
@@ -993,7 +1002,7 @@ Extends TTL of an oracle.
* `o` is the oracle being extended * `o` is the oracle being extended
* `ttl` must be `RelativeTTL`. The time to live of `o` will be extended by this value. * `ttl` must be `RelativeTTL`. The time to live of `o` will be extended by this value.
#### query_fee #### query\_fee
``` ```
Oracle.query_fee(o : oracle('a, 'b)) : int Oracle.query_fee(o : oracle('a, 'b)) : int
``` ```
@@ -1014,7 +1023,7 @@ Asks the oracle a question.
The call fails if the oracle could expire before an answer. The call fails if the oracle could expire before an answer.
#### get_answer #### get\_answer
``` ```
Oracle.get_answer(o : oracle('a, 'b), q : oracle_query('a, 'b)) : option('b) Oracle.get_answer(o : oracle('a, 'b), q : oracle_query('a, 'b)) : option('b)
``` ```
@@ -2467,7 +2476,9 @@ an integer. If the string doesn't contain a valid number `None` is returned.
to_bytes(s : string) : bytes() to_bytes(s : string) : bytes()
``` ```
Converts string into byte array. Converts string into byte array. String is UTF-8 encoded. I.e.
`String.length(s)` is not guaranteed to be equal to
`Bytes.size(String.to_bytes(s))`.
#### sha3 #### sha3
``` ```
+6 -4
View File
@@ -30,6 +30,7 @@ interface main using as for hiding
- `ContractAddress` base58-encoded 32 byte contract address with `ct_` prefix - `ContractAddress` base58-encoded 32 byte contract address with `ct_` prefix
- `OracleAddress` base58-encoded 32 byte oracle address with `ok_` prefix - `OracleAddress` base58-encoded 32 byte oracle address with `ok_` prefix
- `OracleQueryId` base58-encoded 32 byte oracle query id with `oq_` prefix - `OracleQueryId` base58-encoded 32 byte oracle query id with `oq_` prefix
- `Signature` base58-encoded 64 byte cryptographic signature with `sg_` prefix
Valid string escape codes are Valid string escape codes are
@@ -239,6 +240,7 @@ Expr ::= '(' LamArgs ')' '=>' Block(Stmt) // Anonymous function (x) => x +
| Int | Bytes | String | Char // Literals 123, 0xff, #00abc123, "foo", '%' | Int | Bytes | String | Char // Literals 123, 0xff, #00abc123, "foo", '%'
| AccountAddress | ContractAddress // Chain identifiers | AccountAddress | ContractAddress // Chain identifiers
| OracleAddress | OracleQueryId // Chain identifiers | OracleAddress | OracleQueryId // Chain identifiers
| Signature // Signature
| '???' // Hole expression 1 + ??? | '???' // Hole expression 1 + ???
Generator ::= Pattern '<-' Expr // Generator Generator ::= Pattern '<-' Expr // Generator
@@ -265,11 +267,11 @@ UnOp ::= '-' | '!' | 'bnot'
| Operators | Type | Operators | Type
| --- | --- | --- | ---
| `-` `+` `*` `/` `mod` `^` | arithmetic operators | `-` `+` `*` `/` `mod` `^` | arithmetic operators
| `!` `&&` `||` | logical operators | `!` `&&` `\|\|` | logical operators
| `band` `bor` `bxor` `bnot` `<<` `>>` | bitwise operators | `band` `bor` `bxor` `bnot` `<<` `>>` | bitwise operators
| `==` `!=` `<` `>` `=<` `>=` | comparison operators | `==` `!=` `<` `>` `=<` `>=` | comparison operators
| `::` `++` | list operators | `::` `++` | list operators
| `|>` | functional operators | `\|>` | functional operators
## Operator precedence ## Operator precedence
@@ -289,5 +291,5 @@ In order of highest to lowest precedence.
| `bxor` | left | `bxor` | left
| `bor` | left | `bor` | left
| `&&` | right | `&&` | right
| `||` | right | `\|\|` | right
| `|>` | left | `\|>` | left
+2 -2
View File
@@ -282,9 +282,9 @@ namespace List =
private function private function
asc : (('a, 'a) => bool, 'a, list('a), list('a)) => list(list('a)) asc : (('a, 'a) => bool, 'a, list('a), list('a)) => list(list('a))
asc(lt, x, acc, h::t) = asc(lt, x, acc, h::t) =
if(lt(h, x)) List.reverse(x::acc) :: monotonic_subs(lt, h::t) if(lt(h, x)) reverse(x::acc) :: monotonic_subs(lt, h::t)
else asc(lt, h, x::acc, t) else asc(lt, h, x::acc, t)
asc(_, x, acc, []) = [List.reverse(x::acc)] asc(_, x, acc, []) = [reverse(x::acc)]
/** Merges list of sorted lists /** Merges list of sorted lists
*/ */
+4 -3
View File
@@ -2,7 +2,8 @@
{erl_opts, [debug_info]}. {erl_opts, [debug_info]}.
{deps, [ {aebytecode, {git, "https://github.com/aeternity/aebytecode.git", {tag, "v3.4.0"}}} {deps, [ {gmbytecode, {git, "https://git.qpq.swiss/QPQ-AG/gmbytecode.git",
{ref, "691b9742bf7e4aa6a4e8e209397916be5abe1763"}}}
, {eblake2, "1.0.0"} , {eblake2, "1.0.0"}
, {jsx, {git, "https://github.com/talentdeficit/jsx.git", {tag, "2.8.0"}}} , {jsx, {git, "https://github.com/talentdeficit/jsx.git", {tag, "2.8.0"}}}
]}. ]}.
@@ -13,8 +14,8 @@
{base_plt_apps, [erts, kernel, stdlib, crypto, mnesia]} {base_plt_apps, [erts, kernel, stdlib, crypto, mnesia]}
]}. ]}.
{relx, [{release, {aesophia, "8.0.0"}, {relx, [{release, {sophia, "8.0.1"},
[aesophia, aebytecode]}, [sophia, gmbytecode]},
{dev_mode, true}, {dev_mode, true},
{include_erts, false}, {include_erts, false},
+13 -13
View File
@@ -1,22 +1,22 @@
{"1.2.0", {"1.2.0",
[{<<"aebytecode">>, [{<<"base58">>,
{git,"https://github.com/aeternity/aebytecode.git", {git,"https://git.qpq.swiss/QPQ-AG/erl-base58.git",
{ref,"009e0361922037f978f9c0ef357d4d1be8559928"}}, {ref,"e6aa62eeae3d4388311401f06e4b939bf4e94b9c"}},
0},
{<<"aeserialization">>,
{git,"https://github.com/aeternity/aeserialization.git",
{ref,"177bf604b2a05e940f92cf00e96e6e269e708245"}},
1},
{<<"base58">>,
{git,"https://github.com/aeternity/erl-base58.git",
{ref,"60a335668a60328a29f9731b67c4a0e9e3d50ab6"}},
2}, 2},
{<<"eblake2">>,{pkg,<<"eblake2">>,<<"1.0.0">>},0}, {<<"eblake2">>,{pkg,<<"eblake2">>,<<"1.0.0">>},0},
{<<"enacl">>, {<<"enacl">>,
{git,"https://github.com/aeternity/enacl.git", {git,"https://git.qpq.swiss/QPQ-AG/enacl.git",
{ref,"793ddb502f7fe081302e1c42227dca70b09f8e17"}}, {ref,"4eb7ec70084ba7c87b1af8797c4c4e90c84f95a2"}},
2}, 2},
{<<"getopt">>,{pkg,<<"getopt">>,<<"1.0.1">>},1}, {<<"getopt">>,{pkg,<<"getopt">>,<<"1.0.1">>},1},
{<<"gmbytecode">>,
{git,"https://git.qpq.swiss/QPQ-AG/gmbytecode.git",
{ref,"691b9742bf7e4aa6a4e8e209397916be5abe1763"}},
0},
{<<"gmserialization">>,
{git,"https://git.qpq.swiss/QPQ-AG/gmserialization.git",
{ref,"ac64e01b0f675c1a34c70a827062f381920742db"}},
1},
{<<"jsx">>, {<<"jsx">>,
{git,"https://github.com/talentdeficit/jsx.git", {git,"https://github.com/talentdeficit/jsx.git",
{ref,"3074d4865b3385a050badf7828ad31490d860df5"}}, {ref,"3074d4865b3385a050badf7828ad31490d860df5"}},
+2 -1
View File
@@ -198,7 +198,8 @@ encode_expr({bytes, _, B}) ->
<<N:Digits/unit:8>> = B, <<N:Digits/unit:8>> = B,
list_to_binary(lists:flatten(io_lib:format("#~*.16.0b", [Digits*2, N]))); list_to_binary(lists:flatten(io_lib:format("#~*.16.0b", [Digits*2, N])));
encode_expr({Lit, _, L}) when Lit == oracle_pubkey; Lit == oracle_query_id; encode_expr({Lit, _, L}) when Lit == oracle_pubkey; Lit == oracle_query_id;
Lit == contract_pubkey; Lit == account_pubkey -> Lit == contract_pubkey; Lit == account_pubkey;
Lit == signature ->
aeser_api_encoder:encode(Lit, L); aeser_api_encoder:encode(Lit, L);
encode_expr({app, _, {'-', _}, [{int, _, N}]}) -> encode_expr({app, _, {'-', _}, [{int, _, N}]}) ->
encode_expr({int, [], -N}); encode_expr({int, [], -N});
+38 -8
View File
@@ -951,14 +951,14 @@ infer(Contracts, Options) ->
{Env1, Decls} = infer1(Env, Contracts1, [], Options), {Env1, Decls} = infer1(Env, Contracts1, [], Options),
when_warning(warn_unused_functions, fun() -> destroy_and_report_unused_functions() end), 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), 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} = {Env2, DeclsFolded, DeclsUnfolded} =
case proplists:get_value(dont_unfold, Options, false) of case proplists:get_value(dont_unfold, Options, false) of
true -> {Env1, Decls, Decls}; true -> {Env1, Decls, Decls};
false -> E = on_scopes(Env1, fun(Scope) -> unfold_record_types(Env1, Scope) end), false -> E = on_scopes(Env1, fun(Scope) -> unfold_record_types(Env1, Scope) end),
{E, Decls, unfold_record_types(E, Decls)} {E, Decls, unfold_record_types(E, Decls)}
end, 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 case proplists:get_value(return_env, Options, false) of
false -> {DeclsFolded, DeclsUnfolded, Warnings}; false -> {DeclsFolded, DeclsUnfolded, Warnings};
true -> {Env2, DeclsFolded, DeclsUnfolded, Warnings} true -> {Env2, DeclsFolded, DeclsUnfolded, Warnings}
@@ -1161,7 +1161,7 @@ infer_contract(Env0, What, Defs0, Options) ->
_ = bind_funs(lists:map(FunBind, Functions), #env{}), _ = bind_funs(lists:map(FunBind, Functions), #env{}),
FunMap = maps:from_list([ {FunName(Def), Def} || Def <- Functions ]), FunMap = maps:from_list([ {FunName(Def), Def} || Def <- Functions ]),
check_reserved_entrypoints(FunMap), check_reserved_entrypoints(FunMap),
DepGraph = maps:map(fun(_, Def) -> aeso_syntax_utils:used_ids(Def) end, FunMap), DepGraph = maps:map(fun(_, Def) -> aeso_syntax_utils:used_ids(Env3#env.namespace, Def) end, FunMap),
SCCs = aeso_utils:scc(DepGraph), SCCs = aeso_utils:scc(DepGraph),
{Env4, Defs1} = check_sccs(Env3, FunMap, SCCs, []), {Env4, Defs1} = check_sccs(Env3, FunMap, SCCs, []),
%% Remove namespaces used in the current namespace %% Remove namespaces used in the current namespace
@@ -1760,8 +1760,27 @@ desugar_clauses(Ann, Fun, {type_sig, _, _, _, ArgTypes, RetType}, Clauses) ->
end. end.
print_typesig({Name, TypeSig}) -> print_typesig({Name, TypeSig}) ->
assert_tvars(Name, TypeSig),
?PRINT_TYPES("Inferred ~s : ~s\n", [Name, pp(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, "_"}) -> arg_type(ArgAnn, {id, Ann, "_"}) ->
case aeso_syntax:get_ann(origin, Ann, user) of case aeso_syntax:get_ann(origin, Ann, user) of
system -> fresh_uvar(ArgAnn); system -> fresh_uvar(ArgAnn);
@@ -1935,6 +1954,8 @@ infer_expr(_Env, Body={bytes, As, Bin}) ->
{typed, As, Body, {bytes_t, As, byte_size(Bin)}}; {typed, As, Body, {bytes_t, As, byte_size(Bin)}};
infer_expr(_Env, Body={account_pubkey, As, _}) -> infer_expr(_Env, Body={account_pubkey, As, _}) ->
{typed, As, Body, {id, As, "address"}}; {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, _}) -> infer_expr(_Env, Body={oracle_pubkey, As, _}) ->
Q = fresh_uvar(As), Q = fresh_uvar(As),
R = fresh_uvar(As), R = fresh_uvar(As),
@@ -2173,6 +2194,8 @@ check_valid_const_expr({bytes, _, _}) ->
true; true;
check_valid_const_expr({account_pubkey, _, _}) -> check_valid_const_expr({account_pubkey, _, _}) ->
true; true;
check_valid_const_expr({signature, _, _}) ->
true;
check_valid_const_expr({oracle_pubkey, _, _}) -> check_valid_const_expr({oracle_pubkey, _, _}) ->
true; true;
check_valid_const_expr({oracle_query_id, _, _}) -> check_valid_const_expr({oracle_query_id, _, _}) ->
@@ -2953,7 +2976,6 @@ record_type_name({app_t, _Attrs, RecId, _Args}) when ?is_type_id(RecId) ->
record_type_name(RecId) when ?is_type_id(RecId) -> record_type_name(RecId) when ?is_type_id(RecId) ->
RecId; RecId;
record_type_name(_Other) -> record_type_name(_Other) ->
%% io:format("~p is not a record type\n", [Other]),
{id, [{origin, system}], "not_a_record_type"}. {id, [{origin, system}], "not_a_record_type"}.
solve_for_uvar(Env, UVar = {uvar, Attrs, _}, Fields0) -> solve_for_uvar(Env, UVar = {uvar, Attrs, _}, Fields0) ->
@@ -3061,7 +3083,8 @@ 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) -> unfold_types_in_type(Env, Id, Options) when ?is_type_id(Id) ->
%% Like the case above, but for types without parameters. %% Like the case above, but for types without parameters.
when_warning(warn_unused_typedefs, fun() -> used_typedef(Id, 0) end), when_warning(warn_unused_typedefs, fun() -> used_typedef(Id, 0) end),
UnfoldRecords = proplists:get_value(unfold_record_types, Options, false), UnfoldSysAlias = not proplists:get_value(not_unfold_system_alias_types, Options, false),
UnfoldRecords = proplists:get_value(unfold_record_types, Options, false),
UnfoldVariants = proplists:get_value(unfold_variant_types, Options, false), UnfoldVariants = proplists:get_value(unfold_variant_types, Options, false),
case lookup_type(Env, Id) of case lookup_type(Env, Id) of
{_, {_, {[], {record_t, Fields}}}} when UnfoldRecords -> {_, {_, {[], {record_t, Fields}}}} when UnfoldRecords ->
@@ -3069,7 +3092,12 @@ unfold_types_in_type(Env, Id, Options) when ?is_type_id(Id) ->
{_, {_, {[], {variant_t, Constrs}}}} when UnfoldVariants -> {_, {_, {[], {variant_t, Constrs}}}} when UnfoldVariants ->
{variant_t, unfold_types_in_type(Env, Constrs, Options)}; {variant_t, unfold_types_in_type(Env, Constrs, Options)};
{_, {_, {[], {alias_t, Type1}}}} -> {_, {_, {[], {alias_t, Type1}}}} ->
unfold_types_in_type(Env, Type1, Options); case aeso_syntax:get_ann(Type1) of
[{origin, system}] when not UnfoldSysAlias ->
Id;
_ ->
unfold_types_in_type(Env, Type1, Options)
end;
_ -> _ ->
%% Not a record type, or ill-formed record type %% Not a record type, or ill-formed record type
Id Id
@@ -3380,7 +3408,7 @@ instantiate1(X) ->
integer_to_tvar(X) when X < 26 -> integer_to_tvar(X) when X < 26 ->
[$a + X]; [$a + X];
integer_to_tvar(X) -> integer_to_tvar(X) ->
[integer_to_tvar(X div 26)] ++ [$a + (X rem 26)]. integer_to_tvar(X div 26 - 1) ++ [$a + (X rem 26)].
%% Warnings %% Warnings
@@ -3562,7 +3590,6 @@ create_type_errors() ->
destroy_and_report_type_errors(Env) -> destroy_and_report_type_errors(Env) ->
Errors0 = lists:reverse(ets_tab2list(type_errors)), Errors0 = lists:reverse(ets_tab2list(type_errors)),
%% io:format("Type errors now: ~p\n", [Errors0]),
ets_delete(type_errors), ets_delete(type_errors),
Errors = [ mk_error(unqualify(Env, Err)) || Err <- Errors0 ], Errors = [ mk_error(unqualify(Env, Err)) || Err <- Errors0 ],
aeso_errors:throw(Errors). %% No-op if Errors == [] aeso_errors:throw(Errors). %% No-op if Errors == []
@@ -3768,6 +3795,9 @@ mk_error({type_decl, _, {id, Pos, Name}, _}) ->
Msg = io_lib:format("Empty type declarations are not supported. Type `~s` lacks a definition", Msg = io_lib:format("Empty type declarations are not supported. Type `~s` lacks a definition",
[Name]), [Name]),
mk_t_err(pos(Pos), Msg); 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}) -> mk_error({stateful_not_allowed, Id, Fun}) ->
Msg = io_lib:format("Cannot reference stateful function `~s` in the definition of non-stateful function `~s`.", Msg = io_lib:format("Cannot reference stateful function `~s` in the definition of non-stateful function `~s`.",
[pp(Id), pp(Fun)]), [pp(Id), pp(Fun)]),
+93 -53
View File
@@ -55,11 +55,15 @@
| {contract_pubkey, binary()} | {contract_pubkey, binary()}
| {oracle_pubkey, binary()} | {oracle_pubkey, binary()}
| {oracle_query_id, binary()} | {oracle_query_id, binary()}
| {signature, binary()}
| {bool, false | true} | {bool, false | true}
| {contract_code, string()} %% for CREATE, by name | {contract_code, string()} %% for CREATE, by name
| {typerep, ftype()}. | {typerep, ftype()}.
-type fann() :: [ {file, aeso_syntax:ann_file()} | {line, aeso_syntax:ann_line()} ]. -type fann() :: [ {file, aeso_syntax:ann_file()} |
{line, aeso_syntax:ann_line()} |
{col, aeso_syntax:ann_col()}
].
-type fexpr() :: {lit, fann(), flit()} -type fexpr() :: {lit, fann(), flit()}
| {nil, fann()} | {nil, fann()}
@@ -401,11 +405,23 @@ to_fcode(Env, [{namespace, _, {con, _, Con}, Decls} | Code]) ->
Env1 = decls_to_fcode(Env#{ context => {namespace, Con} }, Decls), Env1 = decls_to_fcode(Env#{ context => {namespace, Con} }, Decls),
to_fcode(Env1, Code). 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(). -spec to_fann(aeso_syntax:ann()) -> fann().
to_fann(Ann) -> to_fann(Ann) ->
File = proplists:lookup(file, Ann), {File, Line, Col} = ann_loc(Ann),
Line = proplists:lookup(line, Ann), [ {Tag, X} ||
[ X || X <- [File, Line], X =/= none ]. {Tag, X} <- [{file, File}, {line, Line}, {col, Col}],
X =/= none, X =/= no_file
].
-spec get_fann(fexpr()) -> fann(). -spec get_fann(fexpr()) -> fann().
get_fann(FExpr) -> element(2, FExpr). get_fann(FExpr) -> element(2, FExpr).
@@ -584,6 +600,7 @@ 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, {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, {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, {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, {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_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}}; expr_to_fcode(_Env, _Type, {oracle_query_id, Ann, K}) -> {lit, to_fann(Ann), {oracle_query_id, K}};
@@ -767,14 +784,14 @@ expr_to_fcode(Env, _, {app, _, Fun = {typed, Ann, FunE, {fun_t, _, NamedArgsT, A
_ -> _ ->
%% Here we little cheat on the typechecker, but this inconsistency %% Here we little cheat on the typechecker, but this inconsistency
%% is to be solved in `aeso_fcode_to_fate:type_to_scode/1` %% is to be solved in `aeso_fcode_to_fate:type_to_scode/1`
FInitArgsT = aeb_fate_data:make_typerep([type_to_fcode(Env, T) || T <- ArgsT]), FInitArgsT = gmb_fate_data:make_typerep([type_to_fcode(Env, T) || T <- ArgsT]),
builtin_to_fcode(state_layout(Env), FAnn, chain_clone, [{lit, FAnn, FInitArgsT}|FArgs]) builtin_to_fcode(state_layout(Env), FAnn, chain_clone, [{lit, FAnn, FInitArgsT}|FArgs])
end; end;
{builtin_u, FAnn, chain_create, _Ar} -> {builtin_u, FAnn, chain_create, _Ar} ->
case {ArgsT, Type} of case {ArgsT, Type} of
{var_args, _} -> fcode_error({var_args_not_set, FunE}); {var_args, _} -> fcode_error({var_args_not_set, FunE});
{_, {con, _, Contract}} -> {_, {con, _, Contract}} ->
FInitArgsT = aeb_fate_data:make_typerep([type_to_fcode(Env, T) || T <- ArgsT]), FInitArgsT = gmb_fate_data:make_typerep([type_to_fcode(Env, T) || T <- ArgsT]),
builtin_to_fcode(state_layout(Env), FAnn, chain_create, [{lit, FAnn, {contract_code, Contract}}, {lit, FAnn, FInitArgsT}|FArgs]); builtin_to_fcode(state_layout(Env), FAnn, chain_create, [{lit, FAnn, {contract_code, Contract}}, {lit, FAnn, FInitArgsT}|FArgs]);
{_, _} -> fcode_error({not_a_contract_type, Type}) {_, _} -> fcode_error({not_a_contract_type, Type})
end; end;
@@ -1294,10 +1311,13 @@ event_function(_Env = #{event_type := {variant_t, EventCons}}, EventType = {vari
-spec lambda_lift(fcode()) -> fcode(). -spec lambda_lift(fcode()) -> fcode().
lambda_lift(FCode = #{ functions := Funs, state_layout := StateLayout }) -> lambda_lift(FCode = #{ functions := Funs, state_layout := StateLayout }) ->
init_lambda_funs(), NewFuns =
Funs1 = maps:map(fun(_, Body) -> lambda_lift_fun(StateLayout, Body) end, Funs), [ {FunName, FunDef}
NewFuns = get_lambda_funs(), || {ParentName, ParentDef} <- maps:to_list(Funs),
FCode#{ functions := maps:merge(Funs1, NewFuns) }. {NewParentDef, Lambdas} <- [lambda_lift_fun(StateLayout, ParentName, ParentDef)],
{FunName, FunDef} <- [{ParentName, NewParentDef} | maps:to_list(Lambdas)]
],
FCode#{ functions := maps:from_list(NewFuns) }.
-define(lambda_key, '%lambdalifted'). -define(lambda_key, '%lambdalifted').
@@ -1305,18 +1325,42 @@ lambda_lift(FCode = #{ functions := Funs, state_layout := StateLayout }) ->
init_lambda_funs() -> put(?lambda_key, #{}). init_lambda_funs() -> put(?lambda_key, #{}).
-spec get_lambda_funs() -> term(). -spec get_lambda_funs() -> term().
get_lambda_funs() -> erase(?lambda_key). get_lambda_funs() ->
Lambdas = erase(?lambda_key),
%% Remove name feed entries and leave only actual functions
maps:filter(fun({fresh, _}, _) -> false;
(_, _) -> true
end, Lambdas).
-spec add_lambda_fun(fun_def()) -> fun_name(). -spec add_lambda_fun(fun_name(), fann(), fun_def()) -> fun_name().
add_lambda_fun(Def) -> add_lambda_fun(Parent, FAnn, Def) ->
Name = fresh_fun(),
Funs = get(?lambda_key), Funs = get(?lambda_key),
put(?lambda_key, Funs#{ Name => Def }), LambdaId = maps:get({fresh, Parent}, Funs, 0),
Name = lambda_name(FAnn, LambdaId, Parent),
put(?lambda_key, Funs#{ Name => Def, {fresh, Parent} => LambdaId + 1}),
Name. Name.
-spec lambda_lift_fun(state_layout(), fun_def()) -> fun_def(). -spec lambda_name(fann(), non_neg_integer(), fun_name()) -> fun_name().
lambda_lift_fun(Layout, Def = #{ body := Body }) -> lambda_name(FAnn, Id, PName) ->
Def#{ body := lambda_lift_expr(Layout, Body) }. 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 lifted_fun([var_name()], [var_name()], fexpr()) -> fun_def(). -spec lifted_fun([var_name()], [var_name()], fexpr()) -> fun_def().
lifted_fun([Z], Xs, Body) -> lifted_fun([Z], Xs, Body) ->
@@ -1334,21 +1378,20 @@ lifted_fun(FVs, Xs, Body) ->
body => lists:foldr(Proj, Body, indexed(FVs)) body => lists:foldr(Proj, Body, indexed(FVs))
}. }.
-spec make_closure([var_name()], [var_name()], fexpr()) -> Closure when -spec make_closure(fun_name(), fann(), [var_name()], [var_name()], fexpr()) -> Closure when
Closure :: fexpr(). Closure :: fexpr().
make_closure(FVs, Xs, Body) -> make_closure(ParentName, FAnn, FVs, Xs, Body) ->
Fun = add_lambda_fun(lifted_fun(FVs, Xs, Body)), Name = add_lambda_fun(ParentName, FAnn, lifted_fun(FVs, Xs, Body)),
FAnn = get_fann(Body),
Tup = fun([Y]) -> Y; (Ys) -> {tuple, FAnn, Ys} end, Tup = fun([Y]) -> Y; (Ys) -> {tuple, FAnn, Ys} end,
{closure, FAnn, Fun, Tup([{var, FAnn, Y} || Y <- FVs])}. {closure, FAnn, Name, Tup([{var, FAnn, Y} || Y <- FVs])}.
-spec lambda_lift_expr(state_layout(), fexpr()) -> Closure when -spec lambda_lift_expr(state_layout(), fun_name(), fexpr()) -> Closure when
Closure :: fexpr(). Closure :: fexpr().
lambda_lift_expr(Layout, L = {lam, _, Xs, Body}) -> lambda_lift_expr(Layout, Name, L = {lam, FAnn, Xs, Body}) ->
FVs = free_vars(L), FVs = free_vars(L),
make_closure(FVs, Xs, lambda_lift_expr(Layout, Body)); make_closure(Name, FAnn, FVs, Xs, lambda_lift_expr(Layout, Name, Body));
lambda_lift_expr(Layout, UExpr) when element(1, UExpr) == def_u; element(1, UExpr) == builtin_u -> lambda_lift_expr(Layout, Name, UExpr) when element(1, UExpr) == def_u; element(1, UExpr) == builtin_u ->
[Tag, _, F, Ar | _] = tuple_to_list(UExpr), [Tag, FAnn, F, Ar | _] = tuple_to_list(UExpr),
ExtraArgs = case UExpr of ExtraArgs = case UExpr of
{builtin_u, _, _, _, TypeArgs} -> TypeArgs; {builtin_u, _, _, _, TypeArgs} -> TypeArgs;
_ -> [] _ -> []
@@ -1359,41 +1402,41 @@ lambda_lift_expr(Layout, UExpr) when element(1, UExpr) == def_u; element(1, UExp
builtin_u -> builtin_to_fcode(Layout, get_fann(UExpr), F, Args); builtin_u -> builtin_to_fcode(Layout, get_fann(UExpr), F, Args);
def_u -> {def, get_fann(UExpr), F, Args} def_u -> {def, get_fann(UExpr), F, Args}
end, end,
make_closure([], Xs, Body); make_closure(Name, FAnn, [], Xs, Body);
lambda_lift_expr(Layout, {remote_u, FAnn, ArgsT, RetT, Ct, F}) -> lambda_lift_expr(Layout, Name, {remote_u, FAnn, ArgsT, RetT, Ct, F}) ->
FVs = free_vars(Ct), FVs = free_vars(Ct),
Ct1 = lambda_lift_expr(Layout, Ct), Ct1 = lambda_lift_expr(Layout, Name, Ct),
NamedArgCount = 3, NamedArgCount = 3,
Xs = [ lists:concat(["arg", I]) || I <- lists:seq(1, length(ArgsT) + NamedArgCount) ], Xs = [ lists:concat(["arg", I]) || I <- lists:seq(1, length(ArgsT) + NamedArgCount) ],
Args = [{var, [], X} || X <- Xs], Args = [{var, [], X} || X <- Xs],
make_closure(FVs, Xs, {remote, FAnn, ArgsT, RetT, Ct1, F, Args}); make_closure(Name, FAnn, FVs, Xs, {remote, FAnn, ArgsT, RetT, Ct1, F, Args});
lambda_lift_expr(Layout, Expr) -> lambda_lift_expr(Layout, Name, Expr) ->
case Expr of case Expr of
{lit, _, _} -> Expr; {lit, _, _} -> Expr;
{nil, _} -> Expr; {nil, _} -> Expr;
{var, _, _} -> Expr; {var, _, _} -> Expr;
{closure, _, _, _} -> Expr; {closure, _, _, _} -> Expr;
{def, FAnn, D, As} -> {def, FAnn, D, lambda_lift_exprs(Layout, As)}; {def, FAnn, D, As} -> {def, FAnn, D, lambda_lift_exprs(Layout, Name, As)};
{builtin, FAnn, B, As} -> {builtin, FAnn, B, lambda_lift_exprs(Layout, 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, Ct), F, lambda_lift_exprs(Layout, 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, 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, As)}; {tuple, FAnn, As} -> {tuple, FAnn, lambda_lift_exprs(Layout, Name, As)};
{proj, FAnn, A, I} -> {proj, FAnn, lambda_lift_expr(Layout, A), I}; {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, A), I, lambda_lift_expr(Layout, B)}; {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, As)}; {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, A), lambda_lift_expr(Layout, B)}; {'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, A), lambda_lift_exprs(Layout, Bs)}; {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, A)}; {set_state, FAnn, R, A} -> {set_state, FAnn, R, lambda_lift_expr(Layout, Name, A)};
{get_state, _, _} -> Expr; {get_state, _, _} -> Expr;
{switch, FAnn, S} -> {switch, FAnn, lambda_lift_expr(Layout, S)}; {switch, FAnn, S} -> {switch, FAnn, lambda_lift_expr(Layout, Name, S)};
{split, Type, X, Alts} -> {split, Type, X, lambda_lift_exprs(Layout, Alts)}; {split, Type, X, Alts} -> {split, Type, X, lambda_lift_exprs(Layout, Name, Alts)};
{nosplit, Rens, A} -> {nosplit, Rens, lambda_lift_expr(Layout, A)}; {nosplit, Rens, A} -> {nosplit, Rens, lambda_lift_expr(Layout, Name, A)};
{'case', P, S} -> {'case', P, lambda_lift_expr(Layout, S)} {'case', P, S} -> {'case', P, lambda_lift_expr(Layout, Name, S)}
end. end.
-spec lambda_lift_exprs(state_layout(), [fexpr()]) -> [Closure] when -spec lambda_lift_exprs(state_layout(), fun_name(), [fexpr()]) -> [Closure] when
Closure :: fexpr(). Closure :: fexpr().
lambda_lift_exprs(Layout, As) -> [lambda_lift_expr(Layout, A) || A <- As]. lambda_lift_exprs(Layout, Name, As) -> [lambda_lift_expr(Layout, Name, A) || A <- As].
%% -- Optimisations ---------------------------------------------------------- %% -- Optimisations ----------------------------------------------------------
@@ -1918,9 +1961,6 @@ fresh_name_save(Name) ->
-spec fresh_name() -> var_name(). -spec fresh_name() -> var_name().
fresh_name() -> fresh_name("%"). fresh_name() -> fresh_name("%").
-spec fresh_fun() -> fun_name().
fresh_fun() -> {local_fun, [fresh_name("^")]}.
-spec fresh_name(string()) -> var_name(). -spec fresh_name(string()) -> var_name().
fresh_name(Prefix) -> fresh_name(Prefix) ->
N = get('%fresh'), N = get('%fresh'),
+45 -33
View File
@@ -27,7 +27,7 @@
, validate_byte_code/3 , validate_byte_code/3
]). ]).
-include_lib("aebytecode/include/aeb_opcodes.hrl"). -include_lib("gmbytecode/include/gmb_opcodes.hrl").
-include("aeso_utils.hrl"). -include("aeso_utils.hrl").
@@ -42,6 +42,7 @@
| {include, {file_system, [string()]} | | {include, {file_system, [string()]} |
{explicit_files, #{string() => binary()}}} {explicit_files, #{string() => binary()}}}
| {src_file, string()} | {src_file, string()}
| {src_dir, string()}
| {aci, aeso_aci:aci_type()}. | {aci, aeso_aci:aci_type()}.
-type options() :: [option()]. -type options() :: [option()].
@@ -51,15 +52,15 @@
-spec version() -> {ok, binary()} | {error, term()}. -spec version() -> {ok, binary()} | {error, term()}.
version() -> version() ->
case lists:keyfind(aesophia, 1, application:loaded_applications()) of case lists:keyfind(sophia, 1, application:loaded_applications()) of
false -> false ->
case application:load(aesophia) of case application:load(sophia) of
ok -> ok ->
case application:get_key(aesophia, vsn) of case application:get_key(sophia, vsn) of
{ok, VsnString} -> {ok, VsnString} ->
{ok, list_to_binary(VsnString)}; {ok, list_to_binary(VsnString)};
undefined -> undefined ->
{error, failed_to_load_aesophia} {error, failed_to_load_sophia}
end; end;
Err = {error, _} -> Err = {error, _} ->
Err Err
@@ -87,7 +88,9 @@ file(Filename) ->
file(File, Options0) -> file(File, Options0) ->
Options = add_include_path(File, Options0), Options = add_include_path(File, Options0),
case read_contract(File) of case read_contract(File) of
{ok, Bin} -> from_string(Bin, [{src_file, File} | Options]); {ok, Bin} ->
SrcDir = aeso_utils:canonical_dir(filename:dirname(File)),
from_string(Bin, [{src_file, File}, {src_dir, SrcDir} | Options]);
{error, Error} -> {error, Error} ->
Msg = lists:flatten([File,": ",file:format_error(Error)]), Msg = lists:flatten([File,": ",file:format_error(Error)]),
{error, [aeso_errors:new(file_error, Msg)]} {error, [aeso_errors:new(file_error, Msg)]}
@@ -99,7 +102,7 @@ add_include_path(File, Options) ->
false -> false ->
Dir = filename:dirname(File), Dir = filename:dirname(File),
{ok, Cwd} = file:get_cwd(), {ok, Cwd} = file:get_cwd(),
[{include, {file_system, [Cwd, Dir]}} | Options] [{include, {file_system, [Cwd, aeso_utils:canonical_dir(Dir)]}} | Options]
end. end.
-spec from_string(binary() | string(), options()) -> {ok, map()} | {error, [aeso_errors:error()]}. -spec from_string(binary() | string(), options()) -> {ok, map()} | {error, [aeso_errors:error()]}.
@@ -121,14 +124,14 @@ from_string1(ContractString, Options) ->
SavedFreshNames = maps:get(saved_fresh_names, FCodeEnv, #{}), SavedFreshNames = maps:get(saved_fresh_names, FCodeEnv, #{}),
FateCode = aeso_fcode_to_fate:compile(ChildContracts, FCode, SavedFreshNames, Options), FateCode = aeso_fcode_to_fate:compile(ChildContracts, FCode, SavedFreshNames, Options),
pp_assembler(FateCode, Options), pp_assembler(FateCode, Options),
ByteCode = aeb_fate_code:serialize(FateCode, []), ByteCode = gmb_fate_code:serialize(FateCode, []),
{ok, Version} = version(), {ok, Version} = version(),
Res = #{byte_code => ByteCode, Res = #{byte_code => ByteCode,
compiler_version => Version, compiler_version => Version,
contract_source => ContractString, contract_source => ContractString,
type_info => [], type_info => [],
fate_code => FateCode, fate_code => FateCode,
abi_version => aeb_fate_abi:abi_version(), abi_version => gmb_fate_abi:abi_version(),
payable => maps:get(payable, FCode), payable => maps:get(payable, FCode),
warnings => Warnings warnings => Warnings
}, },
@@ -200,7 +203,7 @@ add_extra_call(Contract0, Call, Options) ->
, ast := Ast} = string_to_code(Contract0, Options), , ast := Ast} = string_to_code(Contract0, Options),
FateCode = aeso_fcode_to_fate:compile(ChildContracts, OrgFcode, #{}, []), FateCode = aeso_fcode_to_fate:compile(ChildContracts, OrgFcode, #{}, []),
%% collect all hashes and compute the first name without hash collision to %% collect all hashes and compute the first name without hash collision to
SymbolHashes = maps:keys(aeb_fate_code:symbols(FateCode)), SymbolHashes = maps:keys(gmb_fate_code:symbols(FateCode)),
CallName = first_none_match(?CALL_NAME, SymbolHashes, CallName = first_none_match(?CALL_NAME, SymbolHashes,
lists:seq($1, $9) ++ lists:seq($A, $Z) ++ lists:seq($a, $z)), lists:seq($1, $9) ++ lists:seq($A, $Z) ++ lists:seq($a, $z)),
Contract = insert_call_function(Ast, Contract0, CallName, Call), Contract = insert_call_function(Ast, Contract0, CallName, Call),
@@ -217,7 +220,7 @@ encode_value(Contract0, Type, Value, Options) ->
case add_extra_call(Contract0, {value, Type, Value}, Options) of case add_extra_call(Contract0, {value, Type, Value}, Options) of
{ok, CallName, Code} -> {ok, CallName, Code} ->
Body = get_call_body(CallName, Code), Body = get_call_body(CallName, Code),
{ok, aeb_fate_encoding:serialize(aeso_fcode_to_fate:term_to_fate(Body))}; {ok, gmb_fate_encoding:serialize(aeso_fcode_to_fate:term_to_fate(Body))};
Err = {error, _} -> Err = {error, _} ->
Err Err
end. end.
@@ -225,10 +228,13 @@ encode_value(Contract0, Type, Value, Options) ->
decode_value(Contract0, Type, FateValue, Options) -> decode_value(Contract0, Type, FateValue, Options) ->
case add_extra_call(Contract0, {type, Type}, Options) of case add_extra_call(Contract0, {type, Type}, Options) of
{ok, CallName, Code} -> {ok, CallName, Code} ->
#{ unfolded_typed_ast := TypedAst #{ folded_typed_ast := TypedAst
, type_env := TypeEnv} = Code, , type_env := TypeEnv} = Code,
{ok, _, Type0} = get_decode_type(CallName, TypedAst), {ok, _, Type0} = get_decode_type(CallName, TypedAst),
Type1 = aeso_ast_infer_types:unfold_types_in_type(TypeEnv, Type0, [unfold_record_types, unfold_variant_types]), Type1 = aeso_ast_infer_types:unfold_types_in_type(TypeEnv, Type0,
[ unfold_record_types
, unfold_variant_types
, not_unfold_system_alias_types ]),
fate_data_to_sophia_value(Type0, Type1, FateValue); fate_data_to_sophia_value(Type0, Type1, FateValue);
Err = {error, _} -> Err = {error, _} ->
Err Err
@@ -237,7 +243,7 @@ decode_value(Contract0, Type, FateValue, Options) ->
first_none_match(_CallName, _Hashes, []) -> first_none_match(_CallName, _Hashes, []) ->
error(unable_to_find_unique_call_name); error(unable_to_find_unique_call_name);
first_none_match(CallName, Hashes, [Char|Chars]) -> first_none_match(CallName, Hashes, [Char|Chars]) ->
case not lists:member(aeb_fate_code:symbol_identifier(list_to_binary(CallName)), Hashes) of case not lists:member(gmb_fate_code:symbol_identifier(list_to_binary(CallName)), Hashes) of
true -> true ->
CallName; CallName;
false -> false ->
@@ -269,7 +275,7 @@ insert_call_function(Ast, Code, Call, {type, Type}) ->
[ Code, [ Code,
"\n\n", "\n\n",
lists:duplicate(Ind, " "), lists:duplicate(Ind, " "),
"entrypoint ", Call, "(val : ", Type, ") = val\n" "entrypoint ", Call, "(val : ", Type, ") : ", Type, " = val\n"
]). ]).
-spec insert_init_function(string(), options()) -> string(). -spec insert_init_function(string(), options()) -> string().
@@ -297,7 +303,7 @@ to_sophia_value(ContractString, Fun, ResType, Data) ->
to_sophia_value(_, _, error, Err, _Options) -> to_sophia_value(_, _, error, Err, _Options) ->
{ok, {app, [], {id, [], "error"}, [{string, [], Err}]}}; {ok, {app, [], {id, [], "error"}, [{string, [], Err}]}};
to_sophia_value(_, _, revert, Data, _Options) -> to_sophia_value(_, _, revert, Data, _Options) ->
try aeso_vm_decode:from_fate({id, [], "string"}, aeb_fate_encoding:deserialize(Data)) of try aeso_vm_decode:from_fate({id, [], "string"}, gmb_fate_encoding:deserialize(Data)) of
Err -> Err ->
{ok, {app, [], {id, [], "abort"}, [Err]}} {ok, {app, [], {id, [], "abort"}, [Err]}}
catch _:_ -> catch _:_ ->
@@ -308,9 +314,12 @@ to_sophia_value(ContractString, FunName, ok, Data, Options0) ->
Options = [no_code | Options0], Options = [no_code | Options0],
try try
Code = string_to_code(ContractString, Options), Code = string_to_code(ContractString, Options),
#{ unfolded_typed_ast := TypedAst, type_env := TypeEnv} = Code, #{ folded_typed_ast := TypedAst, type_env := TypeEnv} = Code,
{ok, _, Type0} = get_decode_type(FunName, TypedAst), {ok, _, Type0} = get_decode_type(FunName, TypedAst),
Type = aeso_ast_infer_types:unfold_types_in_type(TypeEnv, Type0, [unfold_record_types, unfold_variant_types]), Type = aeso_ast_infer_types:unfold_types_in_type(TypeEnv, Type0,
[ unfold_record_types
, unfold_variant_types
, not_unfold_system_alias_types]),
fate_data_to_sophia_value(Type0, Type, Data) fate_data_to_sophia_value(Type0, Type, Data)
catch catch
@@ -319,11 +328,11 @@ to_sophia_value(ContractString, FunName, ok, Data, Options0) ->
fate_data_to_sophia_value(Type, UnfoldedType, FateData) -> fate_data_to_sophia_value(Type, UnfoldedType, FateData) ->
try try
{ok, aeso_vm_decode:from_fate(UnfoldedType, aeb_fate_encoding:deserialize(FateData))} {ok, aeso_vm_decode:from_fate(UnfoldedType, gmb_fate_encoding:deserialize(FateData))}
catch throw:cannot_translate_to_sophia -> catch throw:cannot_translate_to_sophia ->
Type1 = prettypr:format(aeso_pretty:type(Type)), Type1 = prettypr:format(aeso_pretty:type(Type)),
Msg = io_lib:format("Cannot translate FATE value ~p\n of Sophia type ~s", Msg = io_lib:format("Cannot translate FATE value ~p\n of Sophia type ~s",
[aeb_fate_encoding:deserialize(FateData), Type1]), [gmb_fate_encoding:deserialize(FateData), Type1]),
{error, [aeso_errors:new(data_error, Msg)]}; {error, [aeso_errors:new(data_error, Msg)]};
_:_ -> _:_ ->
Type1 = prettypr:format(aeso_pretty:type(Type)), Type1 = prettypr:format(aeso_pretty:type(Type)),
@@ -341,7 +350,7 @@ create_calldata(Code, Fun, Args, Options0) ->
Options = [no_code | Options0], Options = [no_code | Options0],
case check_call(Code, Fun, Args, Options) of case check_call(Code, Fun, Args, Options) of
{ok, FunName, FateArgs} -> {ok, FunName, FateArgs} ->
aeb_fate_abi:create_calldata(FunName, FateArgs); gmb_fate_abi:create_calldata(FunName, FateArgs);
{error, _} = Err -> Err {error, _} = Err -> Err
end. end.
@@ -357,15 +366,18 @@ decode_calldata(ContractString, FunName, Calldata, Options0) ->
Options = [no_code | Options0], Options = [no_code | Options0],
try try
Code = string_to_code(ContractString, Options), Code = string_to_code(ContractString, Options),
#{ unfolded_typed_ast := TypedAst, type_env := TypeEnv} = Code, #{ folded_typed_ast := TypedAst, type_env := TypeEnv} = Code,
{ok, Args, _} = get_decode_type(FunName, TypedAst), {ok, Args, _} = get_decode_type(FunName, TypedAst),
GetType = fun({typed, _, _, T}) -> T; (T) -> T end, GetType = fun({typed, _, _, T}) -> T; (T) -> T end,
ArgTypes = lists:map(GetType, Args), ArgTypes = lists:map(GetType, Args),
Type0 = {tuple_t, [], ArgTypes}, Type0 = {tuple_t, [], ArgTypes},
%% user defined data types such as variants needed to match against %% user defined data types such as variants needed to match against
Type = aeso_ast_infer_types:unfold_types_in_type(TypeEnv, Type0, [unfold_record_types, unfold_variant_types]), Type = aeso_ast_infer_types:unfold_types_in_type(TypeEnv, Type0,
case aeb_fate_abi:decode_calldata(FunName, Calldata) of [ unfold_record_types
, unfold_variant_types
, not_unfold_system_alias_types]),
case gmb_fate_abi:decode_calldata(FunName, Calldata) of
{ok, FateArgs} -> {ok, FateArgs} ->
try try
{tuple_t, [], ArgTypes1} = Type, {tuple_t, [], ArgTypes1} = Type,
@@ -412,7 +424,7 @@ pp_sophia_code(C, Opts)-> pp(C, Opts, pp_sophia_code, fun(Code) ->
pp_ast(C, Opts) -> pp(C, Opts, pp_ast, fun aeso_ast:pp/1). pp_ast(C, Opts) -> pp(C, Opts, pp_ast, fun aeso_ast:pp/1).
pp_typed_ast(C, Opts)-> pp(C, Opts, pp_typed_ast, fun aeso_ast:pp_typed/1). pp_typed_ast(C, Opts)-> pp(C, Opts, pp_typed_ast, fun aeso_ast:pp_typed/1).
pp_assembler(C, Opts) -> pp(C, Opts, pp_assembler, fun(Asm) -> io:format("~s", [aeb_fate_asm:pp(Asm)]) end). pp_assembler(C, Opts) -> pp(C, Opts, pp_assembler, fun(Asm) -> io:format("~s", [gmb_fate_asm:pp(Asm)]) end).
pp(Code, Options, Option, PPFun) -> pp(Code, Options, Option, PPFun) ->
case proplists:lookup(Option, Options) of case proplists:lookup(Option, Options) of
@@ -430,14 +442,14 @@ pp(Code, Options, Option, PPFun) ->
validate_byte_code(#{ byte_code := ByteCode, payable := Payable }, Source, Options) -> validate_byte_code(#{ byte_code := ByteCode, payable := Payable }, Source, Options) ->
Fail = fun(Err) -> {error, [aeso_errors:new(data_error, Err)]} end, Fail = fun(Err) -> {error, [aeso_errors:new(data_error, Err)]} end,
try try
FCode1 = ?protect(deserialize, aeb_fate_code:strip_init_function(aeb_fate_code:deserialize(ByteCode))), FCode1 = ?protect(deserialize, gmb_fate_code:strip_init_function(gmb_fate_code:deserialize(ByteCode))),
{FCode2, SrcPayable} = {FCode2, SrcPayable} =
?protect(compile, ?protect(compile,
begin begin
{ok, #{ byte_code := SrcByteCode, payable := SrcPayable }} = {ok, #{ byte_code := SrcByteCode, payable := SrcPayable }} =
from_string1(Source, Options), from_string1(Source, Options),
FCode = aeb_fate_code:deserialize(SrcByteCode), FCode = gmb_fate_code:deserialize(SrcByteCode),
{aeb_fate_code:strip_init_function(FCode), SrcPayable} {gmb_fate_code:strip_init_function(FCode), SrcPayable}
end), end),
case compare_fate_code(FCode1, FCode2) of case compare_fate_code(FCode1, FCode2) of
ok when SrcPayable /= Payable -> ok when SrcPayable /= Payable ->
@@ -453,10 +465,10 @@ validate_byte_code(#{ byte_code := ByteCode, payable := Payable }, Source, Optio
end. end.
compare_fate_code(FCode1, FCode2) -> compare_fate_code(FCode1, FCode2) ->
Funs1 = aeb_fate_code:functions(FCode1), Funs1 = gmb_fate_code:functions(FCode1),
Funs2 = aeb_fate_code:functions(FCode2), Funs2 = gmb_fate_code:functions(FCode2),
Syms1 = aeb_fate_code:symbols(FCode1), Syms1 = gmb_fate_code:symbols(FCode1),
Syms2 = aeb_fate_code:symbols(FCode2), Syms2 = gmb_fate_code:symbols(FCode2),
FunHashes1 = maps:keys(Funs1), FunHashes1 = maps:keys(Funs1),
FunHashes2 = maps:keys(Funs2), FunHashes2 = maps:keys(Funs2),
case FunHashes1 == FunHashes2 of case FunHashes1 == FunHashes2 of
+215 -212
View File
@@ -23,7 +23,7 @@
| loop | loop
| tuple() | atom(). %% FATE instruction | tuple() | atom(). %% FATE instruction
-type arg() :: tuple(). %% Not exported: aeb_fate_ops:fate_arg(). -type arg() :: tuple(). %% Not exported: gmb_fate_ops:fate_arg().
%% Annotated scode %% Annotated scode
-type scode_a() :: [sinstr_a()]. -type scode_a() :: [sinstr_a()].
@@ -87,14 +87,14 @@ compile(ChildContracts, FCode, SavedFreshNames, Options) ->
SFuns = functions_to_scode(ChildContracts, ContractName, Functions, SavedFreshNames, Options), SFuns = functions_to_scode(ChildContracts, ContractName, Functions, SavedFreshNames, Options),
SFuns1 = optimize_scode(SFuns, Options), SFuns1 = optimize_scode(SFuns, Options),
FateCode = to_basic_blocks(SFuns1), FateCode = to_basic_blocks(SFuns1),
?debug(compile, Options, "~s\n", [aeb_fate_asm:pp(FateCode)]), ?debug(compile, Options, "~s\n", [gmb_fate_asm:pp(FateCode)]),
case proplists:get_value(include_child_contract_symbols, Options, false) of case proplists:get_value(include_child_contract_symbols, Options, false) of
false -> FateCode; false -> FateCode;
true -> add_child_symbols(ChildContracts, FateCode) true -> add_child_symbols(ChildContracts, FateCode)
end. end.
make_function_id(X) -> make_function_id(X) ->
aeb_fate_code:symbol_identifier(make_function_name(X)). gmb_fate_code:symbol_identifier(make_function_name(X)).
make_function_name(event) -> <<"Chain.event">>; make_function_name(event) -> <<"Chain.event">>;
make_function_name({entrypoint, Name}) -> Name; make_function_name({entrypoint, Name}) -> Name;
@@ -103,7 +103,7 @@ make_function_name({local_fun, Xs}) -> list_to_binary("." ++ string:join(Xs,
add_child_symbols(ChildContracts, FateCode) -> add_child_symbols(ChildContracts, FateCode) ->
Funs = lists:flatten([ maps:keys(ChildFuns) || {_, #{functions := ChildFuns}} <- maps:to_list(ChildContracts) ]), Funs = lists:flatten([ maps:keys(ChildFuns) || {_, #{functions := ChildFuns}} <- maps:to_list(ChildContracts) ]),
Symbols = maps:from_list([ {make_function_id(FName), make_function_name(FName)} || FName <- Funs ]), Symbols = maps:from_list([ {make_function_id(FName), make_function_name(FName)} || FName <- Funs ]),
aeb_fate_code:update_symbols(FateCode, Symbols). gmb_fate_code:update_symbols(FateCode, Symbols).
functions_to_scode(ChildContracts, ContractName, Functions, SavedFreshNames, Options) -> functions_to_scode(ChildContracts, ContractName, Functions, SavedFreshNames, Options) ->
FunNames = maps:keys(Functions), FunNames = maps:keys(Functions),
@@ -212,14 +212,14 @@ serialize_contract_code(Env, C) ->
SavedFreshNames = Env#env.saved_fresh_names, SavedFreshNames = Env#env.saved_fresh_names,
FCode = maps:get(C, Env#env.child_contracts), FCode = maps:get(C, Env#env.child_contracts),
FateCode = compile(Env#env.child_contracts, FCode, SavedFreshNames, Options), FateCode = compile(Env#env.child_contracts, FCode, SavedFreshNames, Options),
ByteCode = aeb_fate_code:serialize(FateCode, []), ByteCode = gmb_fate_code:serialize(FateCode, []),
{ok, Version} = aeso_compiler:version(), {ok, Version} = aeso_compiler:version(),
OriginalSourceCode = proplists:get_value(original_src, Options, ""), OriginalSourceCode = proplists:get_value(original_src, Options, ""),
Code = #{byte_code => ByteCode, Code = #{byte_code => ByteCode,
compiler_version => Version, compiler_version => Version,
source_hash => crypto:hash(sha256, OriginalSourceCode ++ [0] ++ C), source_hash => crypto:hash(sha256, OriginalSourceCode ++ [0] ++ C),
type_info => [], type_info => [],
abi_version => aeb_fate_abi:abi_version(), abi_version => gmb_fate_abi:abi_version(),
payable => maps:get(payable, FCode) payable => maps:get(payable, FCode)
}, },
Serialized = aeser_contract_code:serialize(Code), Serialized = aeser_contract_code:serialize(Code),
@@ -230,16 +230,17 @@ serialize_contract_code(Env, C) ->
lit_to_fate(Env, L) -> lit_to_fate(Env, L) ->
case L of case L of
{int, N} -> aeb_fate_data:make_integer(N); {int, N} -> gmb_fate_data:make_integer(N);
{string, S} -> aeb_fate_data:make_string(S); {string, S} -> gmb_fate_data:make_string(S);
{bytes, B} -> aeb_fate_data:make_bytes(B); {bytes, B} -> gmb_fate_data:make_bytes(B);
{bool, B} -> aeb_fate_data:make_boolean(B); {bool, B} -> gmb_fate_data:make_boolean(B);
{account_pubkey, K} -> aeb_fate_data:make_address(K); {account_pubkey, K} -> gmb_fate_data:make_address(K);
{contract_pubkey, K} -> aeb_fate_data:make_contract(K); {signature, S} -> gmb_fate_data:make_bytes(S);
{oracle_pubkey, K} -> aeb_fate_data:make_oracle(K); {contract_pubkey, K} -> gmb_fate_data:make_contract(K);
{oracle_query_id, H} -> aeb_fate_data:make_oracle_query(H); {oracle_pubkey, K} -> gmb_fate_data:make_oracle(K);
{contract_code, C} -> aeb_fate_data:make_contract_bytearray(serialize_contract_code(Env, C)); {oracle_query_id, H} -> gmb_fate_data:make_oracle_query(H);
{typerep, T} -> aeb_fate_data:make_typerep(type_to_scode(T)) {contract_code, C} -> gmb_fate_data:make_contract_bytearray(serialize_contract_code(Env, C));
{typerep, T} -> gmb_fate_data:make_typerep(type_to_scode(T))
end. end.
term_to_fate(E) -> term_to_fate(#env{}, #{}, E). term_to_fate(E) -> term_to_fate(#env{}, #{}, E).
@@ -249,21 +250,21 @@ term_to_fate(GlobEnv, _Env, {lit, _, L}) ->
lit_to_fate(GlobEnv, L); lit_to_fate(GlobEnv, L);
%% negative literals are parsed as 0 - N %% negative literals are parsed as 0 - N
term_to_fate(_GlobEnv, _Env, {op, _, '-', [{lit, _, {int, 0}}, {lit, _, {int, N}}]}) -> term_to_fate(_GlobEnv, _Env, {op, _, '-', [{lit, _, {int, 0}}, {lit, _, {int, N}}]}) ->
aeb_fate_data:make_integer(-N); gmb_fate_data:make_integer(-N);
term_to_fate(_GlobEnv, _Env, {nil, _}) -> term_to_fate(_GlobEnv, _Env, {nil, _}) ->
aeb_fate_data:make_list([]); gmb_fate_data:make_list([]);
term_to_fate(GlobEnv, Env, {op, _, '::', [Hd, Tl]}) -> term_to_fate(GlobEnv, Env, {op, _, '::', [Hd, Tl]}) ->
%% The Tl will translate into a list, because FATE lists are just lists %% The Tl will translate into a list, because FATE lists are just lists
[term_to_fate(GlobEnv, Env, Hd) | term_to_fate(GlobEnv, Env, Tl)]; [term_to_fate(GlobEnv, Env, Hd) | term_to_fate(GlobEnv, Env, Tl)];
term_to_fate(GlobEnv, Env, {tuple, _, As}) -> term_to_fate(GlobEnv, Env, {tuple, _, As}) ->
aeb_fate_data:make_tuple(list_to_tuple([ term_to_fate(GlobEnv, Env, A) || A<-As])); gmb_fate_data:make_tuple(list_to_tuple([ term_to_fate(GlobEnv, Env, A) || A<-As]));
term_to_fate(GlobEnv, Env, {con, _, Ar, I, As}) -> term_to_fate(GlobEnv, Env, {con, _, Ar, I, As}) ->
FateAs = [ term_to_fate(GlobEnv, Env, A) || A <- As ], FateAs = [ term_to_fate(GlobEnv, Env, A) || A <- As ],
aeb_fate_data:make_variant(Ar, I, list_to_tuple(FateAs)); gmb_fate_data:make_variant(Ar, I, list_to_tuple(FateAs));
term_to_fate(_GlobEnv, _Env, {builtin, _, bits_all, []}) -> term_to_fate(_GlobEnv, _Env, {builtin, _, bits_all, []}) ->
aeb_fate_data:make_bits(-1); gmb_fate_data:make_bits(-1);
term_to_fate(_GlobEnv, _Env, {builtin, _, bits_none, []}) -> term_to_fate(_GlobEnv, _Env, {builtin, _, bits_none, []}) ->
aeb_fate_data:make_bits(0); gmb_fate_data:make_bits(0);
term_to_fate(GlobEnv, _Env, {op, _, bits_set, [B, I]}) -> term_to_fate(GlobEnv, _Env, {op, _, bits_set, [B, I]}) ->
{bits, N} = term_to_fate(GlobEnv, B), {bits, N} = term_to_fate(GlobEnv, B),
J = term_to_fate(GlobEnv, I), J = term_to_fate(GlobEnv, I),
@@ -281,10 +282,12 @@ term_to_fate(_GlobEnv, Env, {var, _, X}) ->
V -> V V -> V
end; end;
term_to_fate(_GlobEnv, _Env, {builtin, _, map_empty, []}) -> term_to_fate(_GlobEnv, _Env, {builtin, _, map_empty, []}) ->
aeb_fate_data:make_map(#{}); gmb_fate_data:make_map(#{});
term_to_fate(GlobEnv, Env, {op, _, map_set, [M, K, V]}) -> term_to_fate(GlobEnv, Env, {op, _, map_set, [M, K, V]}) ->
Map = term_to_fate(GlobEnv, Env, M), Map = term_to_fate(GlobEnv, Env, M),
Map#{term_to_fate(GlobEnv, Env, K) => term_to_fate(GlobEnv, Env, V)}; Map#{term_to_fate(GlobEnv, Env, K) => term_to_fate(GlobEnv, Env, V)};
term_to_fate(GlobEnv, Env, {builtin, _, bytes_to_any_size, [Bs]}) ->
term_to_fate(GlobEnv, Env, Bs);
term_to_fate(_GlobEnv, _Env, _) -> term_to_fate(_GlobEnv, _Env, _) ->
throw(not_a_fate_value). throw(not_a_fate_value).
@@ -301,7 +304,7 @@ to_scode1(Env, {lit, Ann, L}) ->
[ dbg_loc(Env, Ann), push(?i(lit_to_fate(Env, L))) ]; [ dbg_loc(Env, Ann), push(?i(lit_to_fate(Env, L))) ];
to_scode1(Env, {nil, Ann}) -> to_scode1(Env, {nil, Ann}) ->
[ dbg_loc(Env, Ann), aeb_fate_ops:nil(?a) ]; [ dbg_loc(Env, Ann), gmb_fate_ops:nil(?a) ];
to_scode1(Env, {var, Ann, X}) -> to_scode1(Env, {var, Ann, X}) ->
[ dbg_loc(Env, Ann), push(lookup_var(Env, X)) ]; [ dbg_loc(Env, Ann), push(lookup_var(Env, X)) ];
@@ -310,7 +313,7 @@ to_scode1(Env, {con, Ann, Ar, I, As}) ->
N = length(As), N = length(As),
[ dbg_loc(Env, Ann), [ dbg_loc(Env, Ann),
[to_scode(notail(Env), A) || A <- As], [to_scode(notail(Env), A) || A <- As],
aeb_fate_ops:variant(?a, ?i(Ar), ?i(I), ?i(N)) ]; gmb_fate_ops:variant(?a, ?i(Ar), ?i(I), ?i(N)) ];
to_scode1(Env, {tuple, Ann, As}) -> to_scode1(Env, {tuple, Ann, As}) ->
N = length(As), N = length(As),
@@ -321,13 +324,13 @@ to_scode1(Env, {tuple, Ann, As}) ->
to_scode1(Env, {proj, Ann, E, I}) -> to_scode1(Env, {proj, Ann, E, I}) ->
[ dbg_loc(Env, Ann), [ dbg_loc(Env, Ann),
to_scode(notail(Env), E), to_scode(notail(Env), E),
aeb_fate_ops:element_op(?a, ?i(I), ?a) ]; gmb_fate_ops:element_op(?a, ?i(I), ?a) ];
to_scode1(Env, {set_proj, Ann, R, I, E}) -> to_scode1(Env, {set_proj, Ann, R, I, E}) ->
[ dbg_loc(Env, Ann), [ dbg_loc(Env, Ann),
to_scode(notail(Env), E), to_scode(notail(Env), E),
to_scode(notail(Env), R), to_scode(notail(Env), R),
aeb_fate_ops:setelement(?a, ?i(I), ?a, ?a) ]; gmb_fate_ops:setelement(?a, ?i(I), ?a, ?a) ];
to_scode1(Env, {op, Ann, Op, Args}) -> to_scode1(Env, {op, Ann, Op, Args}) ->
[ dbg_loc(Env, Ann) | call_to_scode(Env, op_to_scode(Op), Args) ]; [ dbg_loc(Env, Ann) | call_to_scode(Env, op_to_scode(Op), Args) ];
@@ -338,7 +341,7 @@ to_scode1(Env, {'let', Ann, X, {var, _, Y}, Body}) ->
to_scode1(Env, {'let', Ann, X, Expr, Body}) -> to_scode1(Env, {'let', Ann, X, Expr, Body}) ->
{I, Env1} = bind_local(X, Env), {I, Env1} = bind_local(X, Env),
SCode = [ to_scode(notail(Env), Expr), SCode = [ to_scode(notail(Env), Expr),
aeb_fate_ops:store({var, I}, {stack, 0}), gmb_fate_ops:store({var, I}, {stack, 0}),
to_scode(Env1, Body) ], to_scode(Env1, Body) ],
[ dbg_loc(Env, Ann) | dbg_scoped_vars(Env1, [X], SCode) ]; [ dbg_loc(Env, Ann) | dbg_scoped_vars(Env1, [X], SCode) ];
@@ -352,18 +355,18 @@ to_scode1(Env = #env{ current_function = Fun, tailpos = true, debug_info = false
{I, Env2} = bind_local("_", Env1), {I, Env2} = bind_local("_", Env1),
ArgCode = to_scode(notail(Env2), Arg), ArgCode = to_scode(notail(Env2), Arg),
Acc1 = [Acc, ArgCode, Acc1 = [Acc, ArgCode,
aeb_fate_ops:store({var, I}, ?a)], gmb_fate_ops:store({var, I}, ?a)],
{[I | Is], Acc1, Env2} {[I | Is], Acc1, Env2}
end, {[], [], Env}, Args), end, {[], [], Env}, Args),
[ dbg_loc(Env, Ann), [ dbg_loc(Env, Ann),
Code, Code,
[ aeb_fate_ops:store({arg, I}, {var, J}) [ gmb_fate_ops:store({arg, I}, {var, J})
|| {I, J} <- lists:zip(lists:seq(0, length(Vars) - 1), || {I, J} <- lists:zip(lists:seq(0, length(Vars) - 1),
lists:reverse(Vars)) ], lists:reverse(Vars)) ],
loop ]; loop ];
to_scode1(Env, {def, Ann, Fun, Args}) -> to_scode1(Env, {def, Ann, Fun, Args}) ->
FName = make_function_id(Fun), FName = make_function_id(Fun),
Lbl = aeb_fate_data:make_string(FName), Lbl = gmb_fate_data:make_string(FName),
[ dbg_loc(Env, Ann) | call_to_scode(Env, local_call(Env, ?i(Lbl)), Args) ]; [ dbg_loc(Env, Ann) | call_to_scode(Env, local_call(Env, ?i(Lbl)), Args) ];
to_scode1(Env, {funcall, Ann, Fun, Args}) -> to_scode1(Env, {funcall, Ann, Fun, Args}) ->
[ dbg_loc(Env, Ann) | call_to_scode(Env, [to_scode(Env, Fun), local_call(Env, ?a)], Args) ]; [ dbg_loc(Env, Ann) | call_to_scode(Env, [to_scode(Env, Fun), local_call(Env, ?a)], Args) ];
@@ -374,23 +377,23 @@ to_scode1(Env, {builtin, Ann, B, Args}) ->
to_scode1(Env, {remote, Ann, ArgsT, RetT, Ct, Fun, [Gas, Value, Protected | Args]}) -> to_scode1(Env, {remote, Ann, ArgsT, RetT, Ct, Fun, [Gas, Value, Protected | Args]}) ->
Lbl = make_function_id(Fun), Lbl = make_function_id(Fun),
{ArgTypes, RetType0} = typesig_to_scode([{"_", T} || T <- ArgsT], RetT), {ArgTypes, RetType0} = typesig_to_scode([{"_", T} || T <- ArgsT], RetT),
ArgType = ?i(aeb_fate_data:make_typerep({tuple, ArgTypes})), ArgType = ?i(gmb_fate_data:make_typerep({tuple, ArgTypes})),
RetType = ?i(aeb_fate_data:make_typerep(RetType0)), RetType = ?i(gmb_fate_data:make_typerep(RetType0)),
SCode = case Protected of SCode = case Protected of
{lit, _, {bool, false}} -> {lit, _, {bool, false}} ->
case Gas of case Gas of
{builtin, _, call_gas_left, _} -> {builtin, _, call_gas_left, _} ->
Call = aeb_fate_ops:call_r(?a, Lbl, ArgType, RetType, ?a), Call = gmb_fate_ops:call_r(?a, Lbl, ArgType, RetType, ?a),
call_to_scode(Env, Call, [Ct, Value | Args]); call_to_scode(Env, Call, [Ct, Value | Args]);
_ -> _ ->
Call = aeb_fate_ops:call_gr(?a, Lbl, ArgType, RetType, ?a, ?a), Call = gmb_fate_ops:call_gr(?a, Lbl, ArgType, RetType, ?a, ?a),
call_to_scode(Env, Call, [Ct, Value, Gas | Args]) call_to_scode(Env, Call, [Ct, Value, Gas | Args])
end; end;
{lit, _, {bool, true}} -> {lit, _, {bool, true}} ->
Call = aeb_fate_ops:call_pgr(?a, Lbl, ArgType, RetType, ?a, ?a, ?i(true)), Call = gmb_fate_ops:call_pgr(?a, Lbl, ArgType, RetType, ?a, ?a, ?i(true)),
call_to_scode(Env, Call, [Ct, Value, Gas | Args]); call_to_scode(Env, Call, [Ct, Value, Gas | Args]);
_ -> _ ->
Call = aeb_fate_ops:call_pgr(?a, Lbl, ArgType, RetType, ?a, ?a, ?a), Call = gmb_fate_ops:call_pgr(?a, Lbl, ArgType, RetType, ?a, ?a, ?a),
call_to_scode(Env, Call, [Ct, Value, Gas, Protected | Args]) call_to_scode(Env, Call, [Ct, Value, Gas, Protected | Args])
end, end,
[ dbg_loc(Env, Ann) | SCode ]; [ dbg_loc(Env, Ann) | SCode ];
@@ -406,8 +409,8 @@ to_scode1(Env, {closure, Ann, Fun, FVs}) ->
to_scode1(Env, {switch, Ann, Case}) -> to_scode1(Env, {switch, Ann, Case}) ->
[ dbg_loc(Env, Ann) | split_to_scode(Env, Case) ]. [ dbg_loc(Env, Ann) | split_to_scode(Env, Case) ].
local_call( Env = #env{debug_info = false}, Fun) when Env#env.tailpos -> aeb_fate_ops:call_t(Fun); local_call( Env = #env{debug_info = false}, Fun) when Env#env.tailpos -> gmb_fate_ops:call_t(Fun);
local_call(_Env, Fun) -> aeb_fate_ops:call(Fun). local_call(_Env, Fun) -> gmb_fate_ops:call(Fun).
split_to_scode(Env, {nosplit, Renames, Expr}) -> split_to_scode(Env, {nosplit, Renames, Expr}) ->
[switch_body, dbg_scoped_vars(Env, Renames, to_scode(Env, Expr))]; [switch_body, dbg_scoped_vars(Env, Renames, to_scode(Env, Expr))];
@@ -445,13 +448,13 @@ split_to_scode(Env, {split, {list, _}, X, Alts}) ->
[{'case', {'::', Y, Z}, S} | _] -> [{'case', {'::', Y, Z}, S} | _] ->
{I, Env1} = bind_local(Y, Env), {I, Env1} = bind_local(Y, Env),
{J, Env2} = bind_local(Z, Env1), {J, Env2} = bind_local(Z, Env1),
[aeb_fate_ops:hd({var, I}, Arg), [gmb_fate_ops:hd({var, I}, Arg),
aeb_fate_ops:tl({var, J}, Arg), gmb_fate_ops:tl({var, J}, Arg),
split_to_scode(Env2, S)] split_to_scode(Env2, S)]
end end
end, end,
SAlts = [GetAlt('::'), GetAlt(nil)], SAlts = [GetAlt('::'), GetAlt(nil)],
[aeb_fate_ops:is_nil(?a, Arg), [gmb_fate_ops:is_nil(?a, Arg),
{switch, ?a, boolean, SAlts, Def}]; {switch, ?a, boolean, SAlts, Def}];
split_to_scode(Env, {split, Type, X, Alts}) when Type == integer; Type == string -> split_to_scode(Env, {split, Type, X, Alts}) when Type == integer; Type == string ->
{Def, Alts1} = catchall_to_scode(Env, X, Alts), {Def, Alts1} = catchall_to_scode(Env, X, Alts),
@@ -485,9 +488,9 @@ literal_split_to_scode(Env, Type, Arg, [{'case', Lit, Body} | Alts], Def) when T
end, end,
SLit = case Lit of SLit = case Lit of
{int, N} -> N; {int, N} -> N;
{string, S} -> aeb_fate_data:make_string(S) {string, S} -> gmb_fate_data:make_string(S)
end, end,
[aeb_fate_ops:eq(?a, Arg, ?i(SLit)), [gmb_fate_ops:eq(?a, Arg, ?i(SLit)),
{switch, ?a, boolean, [False, True], Def}]. {switch, ?a, boolean, [False, True], Def}].
catchall_to_scode(Env, X, Alts) -> catchall_to_scode(Env, X, Alts, []). catchall_to_scode(Env, X, Alts) -> catchall_to_scode(Env, X, Alts, []).
@@ -501,10 +504,10 @@ catchall_to_scode(_, _, [], Acc) -> {missing, lists:reverse(Acc)}.
%% Tuple is in the accumulator. Arguments are the variable names. %% Tuple is in the accumulator. Arguments are the variable names.
match_tuple(Env, Arg, Xs) -> match_tuple(Env, Arg, Xs) ->
match_tuple(Env, 0, fun aeb_fate_ops:element_op/3, Arg, Xs). match_tuple(Env, 0, fun gmb_fate_ops:element_op/3, Arg, Xs).
match_variant(Env, Arg, Xs) -> match_variant(Env, Arg, Xs) ->
Elem = fun(Dst, I, Val) -> aeb_fate_ops:variant_element(Dst, Val, I) end, Elem = fun(Dst, I, Val) -> gmb_fate_ops:variant_element(Dst, Val, I) end,
match_tuple(Env, 0, Elem, Arg, Xs). match_tuple(Env, 0, Elem, Arg, Xs).
match_tuple(Env, I, Elem, Arg, ["_" | Xs]) -> match_tuple(Env, I, Elem, Arg, ["_" | Xs]) ->
@@ -523,239 +526,239 @@ call_to_scode(Env, CallCode, Args) ->
CallCode]. CallCode].
builtin_to_scode(Env, chain_event, Args) -> builtin_to_scode(Env, chain_event, Args) ->
call_to_scode(Env, [erlang:apply(aeb_fate_ops, log, lists:duplicate(length(Args), ?a)), call_to_scode(Env, [erlang:apply(gmb_fate_ops, log, lists:duplicate(length(Args), ?a)),
tuple(0)], Args); tuple(0)], Args);
builtin_to_scode(_Env, map_empty, []) -> builtin_to_scode(_Env, map_empty, []) ->
[aeb_fate_ops:map_empty(?a)]; [gmb_fate_ops:map_empty(?a)];
builtin_to_scode(_Env, bits_none, []) -> builtin_to_scode(_Env, bits_none, []) ->
[aeb_fate_ops:bits_none(?a)]; [gmb_fate_ops:bits_none(?a)];
builtin_to_scode(_Env, bits_all, []) -> builtin_to_scode(_Env, bits_all, []) ->
[aeb_fate_ops:bits_all(?a)]; [gmb_fate_ops:bits_all(?a)];
builtin_to_scode(Env, bytes_to_int, [_] = Args) -> builtin_to_scode(Env, bytes_to_int, [_] = Args) ->
call_to_scode(Env, aeb_fate_ops:bytes_to_int(?a, ?a), Args); call_to_scode(Env, gmb_fate_ops:bytes_to_int(?a, ?a), Args);
builtin_to_scode(Env, bytes_to_str, [_] = Args) -> builtin_to_scode(Env, bytes_to_str, [_] = Args) ->
call_to_scode(Env, aeb_fate_ops:bytes_to_str(?a, ?a), Args); call_to_scode(Env, gmb_fate_ops:bytes_to_str(?a, ?a), Args);
builtin_to_scode(Env, bytes_concat, [_, _] = Args) -> builtin_to_scode(Env, bytes_concat, [_, _] = Args) ->
call_to_scode(Env, aeb_fate_ops:bytes_concat(?a, ?a, ?a), Args); call_to_scode(Env, gmb_fate_ops:bytes_concat(?a, ?a, ?a), Args);
builtin_to_scode(Env, bytes_split, [_, _] = Args) -> builtin_to_scode(Env, bytes_split, [_, _] = Args) ->
call_to_scode(Env, aeb_fate_ops:bytes_split(?a, ?a, ?a), Args); call_to_scode(Env, gmb_fate_ops:bytes_split(?a, ?a, ?a), Args);
builtin_to_scode(Env, bytes_split_any, [_, _] = Args) -> builtin_to_scode(Env, bytes_split_any, [_, _] = Args) ->
call_to_scode(Env, aeb_fate_ops:bytes_split_any(?a, ?a, ?a), Args); call_to_scode(Env, gmb_fate_ops:bytes_split_any(?a, ?a, ?a), Args);
builtin_to_scode(Env, bytes_to_fixed_size, [_, _] = Args) -> builtin_to_scode(Env, bytes_to_fixed_size, [_, _] = Args) ->
call_to_scode(Env, aeb_fate_ops:bytes_to_fixed_size(?a, ?a, ?a), Args); call_to_scode(Env, gmb_fate_ops:bytes_to_fixed_size(?a, ?a, ?a), Args);
builtin_to_scode(Env, bytes_to_any_size, [A]) -> builtin_to_scode(Env, bytes_to_any_size, [A]) ->
[to_scode(Env, A)]; %% no_op! [to_scode(Env, A)]; %% no_op!
builtin_to_scode(Env, bytes_size, [_] = Args) -> builtin_to_scode(Env, bytes_size, [_] = Args) ->
call_to_scode(Env, aeb_fate_ops:bytes_size(?a, ?a), Args); call_to_scode(Env, gmb_fate_ops:bytes_size(?a, ?a), Args);
builtin_to_scode(Env, abort, [_] = Args) -> builtin_to_scode(Env, abort, [_] = Args) ->
call_to_scode(Env, aeb_fate_ops:abort(?a), Args); call_to_scode(Env, gmb_fate_ops:abort(?a), Args);
builtin_to_scode(Env, exit, [_] = Args) -> builtin_to_scode(Env, exit, [_] = Args) ->
call_to_scode(Env, aeb_fate_ops:exit(?a), Args); call_to_scode(Env, gmb_fate_ops:exit(?a), Args);
builtin_to_scode(Env, chain_spend, [_, _] = Args) -> builtin_to_scode(Env, chain_spend, [_, _] = Args) ->
call_to_scode(Env, [aeb_fate_ops:spend(?a, ?a), call_to_scode(Env, [gmb_fate_ops:spend(?a, ?a),
tuple(0)], Args); tuple(0)], Args);
builtin_to_scode(Env, chain_balance, [_] = Args) -> builtin_to_scode(Env, chain_balance, [_] = Args) ->
call_to_scode(Env, aeb_fate_ops:balance_other(?a, ?a), Args); call_to_scode(Env, gmb_fate_ops:balance_other(?a, ?a), Args);
builtin_to_scode(Env, chain_block_hash, [_] = Args) -> builtin_to_scode(Env, chain_block_hash, [_] = Args) ->
call_to_scode(Env, aeb_fate_ops:blockhash(?a, ?a), Args); call_to_scode(Env, gmb_fate_ops:blockhash(?a, ?a), Args);
builtin_to_scode(_Env, chain_coinbase, []) -> builtin_to_scode(_Env, chain_coinbase, []) ->
[aeb_fate_ops:beneficiary(?a)]; [gmb_fate_ops:beneficiary(?a)];
builtin_to_scode(_Env, chain_timestamp, []) -> builtin_to_scode(_Env, chain_timestamp, []) ->
[aeb_fate_ops:timestamp(?a)]; [gmb_fate_ops:timestamp(?a)];
builtin_to_scode(_Env, chain_block_height, []) -> builtin_to_scode(_Env, chain_block_height, []) ->
[aeb_fate_ops:generation(?a)]; [gmb_fate_ops:generation(?a)];
builtin_to_scode(_Env, chain_difficulty, []) -> builtin_to_scode(_Env, chain_difficulty, []) ->
[aeb_fate_ops:difficulty(?a)]; [gmb_fate_ops:difficulty(?a)];
builtin_to_scode(_Env, chain_gas_limit, []) -> builtin_to_scode(_Env, chain_gas_limit, []) ->
[aeb_fate_ops:gaslimit(?a)]; [gmb_fate_ops:gaslimit(?a)];
builtin_to_scode(_Env, chain_network_id, []) -> builtin_to_scode(_Env, chain_network_id, []) ->
[aeb_fate_ops:network_id(?a)]; [gmb_fate_ops:network_id(?a)];
builtin_to_scode(_Env, contract_balance, []) -> builtin_to_scode(_Env, contract_balance, []) ->
[aeb_fate_ops:balance(?a)]; [gmb_fate_ops:balance(?a)];
builtin_to_scode(_Env, contract_address, []) -> builtin_to_scode(_Env, contract_address, []) ->
[aeb_fate_ops:address(?a)]; [gmb_fate_ops:address(?a)];
builtin_to_scode(_Env, contract_creator, []) -> builtin_to_scode(_Env, contract_creator, []) ->
[aeb_fate_ops:contract_creator(?a)]; [gmb_fate_ops:contract_creator(?a)];
builtin_to_scode(_Env, call_origin, []) -> builtin_to_scode(_Env, call_origin, []) ->
[aeb_fate_ops:origin(?a)]; [gmb_fate_ops:origin(?a)];
builtin_to_scode(_Env, call_caller, []) -> builtin_to_scode(_Env, call_caller, []) ->
[aeb_fate_ops:caller(?a)]; [gmb_fate_ops:caller(?a)];
builtin_to_scode(_Env, call_value, []) -> builtin_to_scode(_Env, call_value, []) ->
[aeb_fate_ops:call_value(?a)]; [gmb_fate_ops:call_value(?a)];
builtin_to_scode(_Env, call_gas_price, []) -> builtin_to_scode(_Env, call_gas_price, []) ->
[aeb_fate_ops:gasprice(?a)]; [gmb_fate_ops:gasprice(?a)];
builtin_to_scode(_Env, call_fee, []) -> builtin_to_scode(_Env, call_fee, []) ->
[aeb_fate_ops:fee(?a)]; [gmb_fate_ops:fee(?a)];
builtin_to_scode(_Env, call_gas_left, []) -> builtin_to_scode(_Env, call_gas_left, []) ->
[aeb_fate_ops:gas(?a)]; [gmb_fate_ops:gas(?a)];
builtin_to_scode(Env, oracle_register, [_Sign,_Account,_QFee,_TTL,_QType,_RType] = Args) -> builtin_to_scode(Env, oracle_register, [_Sign,_Account,_QFee,_TTL,_QType,_RType] = Args) ->
call_to_scode(Env, aeb_fate_ops:oracle_register(?a, ?a, ?a, ?a, ?a, ?a, ?a), Args); call_to_scode(Env, gmb_fate_ops:oracle_register(?a, ?a, ?a, ?a, ?a, ?a, ?a), Args);
builtin_to_scode(Env, oracle_expiry, [_Oracle] = Args) -> builtin_to_scode(Env, oracle_expiry, [_Oracle] = Args) ->
call_to_scode(Env, aeb_fate_ops:oracle_expiry(?a, ?a), Args); call_to_scode(Env, gmb_fate_ops:oracle_expiry(?a, ?a), Args);
builtin_to_scode(Env, oracle_query_fee, [_Oracle] = Args) -> builtin_to_scode(Env, oracle_query_fee, [_Oracle] = Args) ->
call_to_scode(Env, aeb_fate_ops:oracle_query_fee(?a, ?a), Args); call_to_scode(Env, gmb_fate_ops:oracle_query_fee(?a, ?a), Args);
builtin_to_scode(Env, oracle_query, [_Oracle, _Question, _QFee, _QTTL, _RTTL, _QType, _RType] = Args) -> builtin_to_scode(Env, oracle_query, [_Oracle, _Question, _QFee, _QTTL, _RTTL, _QType, _RType] = Args) ->
call_to_scode(Env, aeb_fate_ops:oracle_query(?a, ?a, ?a, ?a, ?a, ?a, ?a, ?a), Args); call_to_scode(Env, gmb_fate_ops:oracle_query(?a, ?a, ?a, ?a, ?a, ?a, ?a, ?a), Args);
builtin_to_scode(Env, oracle_get_question, [_Oracle, _QueryId, _QType, _RType] = Args) -> builtin_to_scode(Env, oracle_get_question, [_Oracle, _QueryId, _QType, _RType] = Args) ->
call_to_scode(Env, aeb_fate_ops:oracle_get_question(?a, ?a, ?a, ?a, ?a), Args); call_to_scode(Env, gmb_fate_ops:oracle_get_question(?a, ?a, ?a, ?a, ?a), Args);
builtin_to_scode(Env, oracle_respond, [_Sign, _Oracle, _QueryId, _Response, _QType, _RType] = Args) -> builtin_to_scode(Env, oracle_respond, [_Sign, _Oracle, _QueryId, _Response, _QType, _RType] = Args) ->
call_to_scode(Env, [aeb_fate_ops:oracle_respond(?a, ?a, ?a, ?a, ?a, ?a), call_to_scode(Env, [gmb_fate_ops:oracle_respond(?a, ?a, ?a, ?a, ?a, ?a),
tuple(0)], Args); tuple(0)], Args);
builtin_to_scode(Env, oracle_extend, [_Sign, _Oracle, _TTL] = Args) -> builtin_to_scode(Env, oracle_extend, [_Sign, _Oracle, _TTL] = Args) ->
call_to_scode(Env, [aeb_fate_ops:oracle_extend(?a, ?a, ?a), call_to_scode(Env, [gmb_fate_ops:oracle_extend(?a, ?a, ?a),
tuple(0)], Args); tuple(0)], Args);
builtin_to_scode(Env, oracle_get_answer, [_Oracle, _QueryId, _QType, _RType] = Args) -> builtin_to_scode(Env, oracle_get_answer, [_Oracle, _QueryId, _QType, _RType] = Args) ->
call_to_scode(Env, aeb_fate_ops:oracle_get_answer(?a, ?a, ?a, ?a, ?a), Args); call_to_scode(Env, gmb_fate_ops:oracle_get_answer(?a, ?a, ?a, ?a, ?a), Args);
builtin_to_scode(Env, oracle_check, [_Oracle, _QType, _RType] = Args) -> builtin_to_scode(Env, oracle_check, [_Oracle, _QType, _RType] = Args) ->
call_to_scode(Env, aeb_fate_ops:oracle_check(?a, ?a, ?a, ?a), Args); call_to_scode(Env, gmb_fate_ops:oracle_check(?a, ?a, ?a, ?a), Args);
builtin_to_scode(Env, oracle_check_query, [_Oracle, _Query, _QType, _RType] = Args) -> builtin_to_scode(Env, oracle_check_query, [_Oracle, _Query, _QType, _RType] = Args) ->
call_to_scode(Env, aeb_fate_ops:oracle_check_query(?a, ?a, ?a, ?a, ?a), Args); call_to_scode(Env, gmb_fate_ops:oracle_check_query(?a, ?a, ?a, ?a, ?a), Args);
builtin_to_scode(Env, address_is_oracle, [_] = Args) -> builtin_to_scode(Env, address_is_oracle, [_] = Args) ->
call_to_scode(Env, aeb_fate_ops:is_oracle(?a, ?a), Args); call_to_scode(Env, gmb_fate_ops:is_oracle(?a, ?a), Args);
builtin_to_scode(Env, address_is_contract, [_] = Args) -> builtin_to_scode(Env, address_is_contract, [_] = Args) ->
call_to_scode(Env, aeb_fate_ops:is_contract(?a, ?a), Args); call_to_scode(Env, gmb_fate_ops:is_contract(?a, ?a), Args);
builtin_to_scode(Env, address_is_payable, [_] = Args) -> builtin_to_scode(Env, address_is_payable, [_] = Args) ->
call_to_scode(Env, aeb_fate_ops:is_payable(?a, ?a), Args); call_to_scode(Env, gmb_fate_ops:is_payable(?a, ?a), Args);
builtin_to_scode(Env, aens_resolve, [_Name, _Key, _Type] = Args) -> builtin_to_scode(Env, aens_resolve, [_Name, _Key, _Type] = Args) ->
call_to_scode(Env, aeb_fate_ops:aens_resolve(?a, ?a, ?a, ?a), Args); call_to_scode(Env, gmb_fate_ops:aens_resolve(?a, ?a, ?a, ?a), Args);
builtin_to_scode(Env, aens_preclaim, [_Sign, _Account, _Hash] = Args) -> builtin_to_scode(Env, aens_preclaim, [_Sign, _Account, _Hash] = Args) ->
call_to_scode(Env, [aeb_fate_ops:aens_preclaim(?a, ?a, ?a), call_to_scode(Env, [gmb_fate_ops:aens_preclaim(?a, ?a, ?a),
tuple(0)], Args); tuple(0)], Args);
builtin_to_scode(Env, aens_claim, [_Sign, _Account, _NameString, _Salt, _NameFee] = Args) -> builtin_to_scode(Env, aens_claim, [_Sign, _Account, _NameString, _Salt, _NameFee] = Args) ->
call_to_scode(Env, [aeb_fate_ops:aens_claim(?a, ?a, ?a, ?a, ?a), call_to_scode(Env, [gmb_fate_ops:aens_claim(?a, ?a, ?a, ?a, ?a),
tuple(0)], Args); tuple(0)], Args);
builtin_to_scode(Env, aens_transfer, [_Sign, _From, _To, _Name] = Args) -> builtin_to_scode(Env, aens_transfer, [_Sign, _From, _To, _Name] = Args) ->
call_to_scode(Env, [aeb_fate_ops:aens_transfer(?a, ?a, ?a, ?a), call_to_scode(Env, [gmb_fate_ops:aens_transfer(?a, ?a, ?a, ?a),
tuple(0)], Args); tuple(0)], Args);
builtin_to_scode(Env, aens_revoke, [_Sign, _Account, _Name] = Args) -> builtin_to_scode(Env, aens_revoke, [_Sign, _Account, _Name] = Args) ->
call_to_scode(Env, [aeb_fate_ops:aens_revoke(?a, ?a, ?a), call_to_scode(Env, [gmb_fate_ops:aens_revoke(?a, ?a, ?a),
tuple(0)], Args); tuple(0)], Args);
builtin_to_scode(Env, aens_update, [_Sign, _Account, _NameString, _TTL, _ClientTTL, _Pointers] = Args) -> builtin_to_scode(Env, aens_update, [_Sign, _Account, _NameString, _TTL, _ClientTTL, _Pointers] = Args) ->
call_to_scode(Env, [aeb_fate_ops:aens_update(?a, ?a, ?a, ?a, ?a, ?a), call_to_scode(Env, [gmb_fate_ops:aens_update(?a, ?a, ?a, ?a, ?a, ?a),
tuple(0)], Args); tuple(0)], Args);
builtin_to_scode(Env, aens_lookup, [_Name] = Args) -> builtin_to_scode(Env, aens_lookup, [_Name] = Args) ->
call_to_scode(Env, aeb_fate_ops:aens_lookup(?a, ?a), Args); call_to_scode(Env, gmb_fate_ops:aens_lookup(?a, ?a), Args);
builtin_to_scode(_Env, auth_tx_hash, []) -> builtin_to_scode(_Env, auth_tx_hash, []) ->
[aeb_fate_ops:auth_tx_hash(?a)]; [gmb_fate_ops:auth_tx_hash(?a)];
builtin_to_scode(_Env, auth_tx, []) -> builtin_to_scode(_Env, auth_tx, []) ->
[aeb_fate_ops:auth_tx(?a)]; [gmb_fate_ops:auth_tx(?a)];
builtin_to_scode(Env, chain_bytecode_hash, [_Addr] = Args) -> builtin_to_scode(Env, chain_bytecode_hash, [_Addr] = Args) ->
call_to_scode(Env, aeb_fate_ops:bytecode_hash(?a, ?a), Args); call_to_scode(Env, gmb_fate_ops:bytecode_hash(?a, ?a), Args);
builtin_to_scode(Env, chain_clone, builtin_to_scode(Env, chain_clone,
[InitArgsT, GasCap, Value, Prot, Contract | InitArgs]) -> [InitArgsT, GasCap, Value, Prot, Contract | InitArgs]) ->
case GasCap of case GasCap of
{builtin, _, call_gas_left, _} -> {builtin, _, call_gas_left, _} ->
call_to_scode(Env, aeb_fate_ops:clone(?a, ?a, ?a, ?a), call_to_scode(Env, gmb_fate_ops:clone(?a, ?a, ?a, ?a),
[Contract, InitArgsT, Value, Prot | InitArgs] [Contract, InitArgsT, Value, Prot | InitArgs]
); );
_ -> _ ->
call_to_scode(Env, aeb_fate_ops:clone_g(?a, ?a, ?a, ?a, ?a), call_to_scode(Env, gmb_fate_ops:clone_g(?a, ?a, ?a, ?a, ?a),
[Contract, InitArgsT, Value, GasCap, Prot | InitArgs] [Contract, InitArgsT, Value, GasCap, Prot | InitArgs]
) )
end; end;
builtin_to_scode(Env, chain_create, builtin_to_scode(Env, chain_create,
[ Code, InitArgsT, Value | InitArgs]) -> [ Code, InitArgsT, Value | InitArgs]) ->
call_to_scode(Env, aeb_fate_ops:create(?a, ?a, ?a), call_to_scode(Env, gmb_fate_ops:create(?a, ?a, ?a),
[Code, InitArgsT, Value | InitArgs] [Code, InitArgsT, Value | InitArgs]
). ).
%% -- Operators -- %% -- Operators --
op_to_scode('+') -> aeb_fate_ops:add(?a, ?a, ?a); op_to_scode('+') -> gmb_fate_ops:add(?a, ?a, ?a);
op_to_scode('-') -> aeb_fate_ops:sub(?a, ?a, ?a); op_to_scode('-') -> gmb_fate_ops:sub(?a, ?a, ?a);
op_to_scode('*') -> aeb_fate_ops:mul(?a, ?a, ?a); op_to_scode('*') -> gmb_fate_ops:mul(?a, ?a, ?a);
op_to_scode('/') -> aeb_fate_ops:divide(?a, ?a, ?a); op_to_scode('/') -> gmb_fate_ops:divide(?a, ?a, ?a);
op_to_scode(mod) -> aeb_fate_ops:modulo(?a, ?a, ?a); op_to_scode(mod) -> gmb_fate_ops:modulo(?a, ?a, ?a);
op_to_scode('^') -> aeb_fate_ops:pow(?a, ?a, ?a); op_to_scode('^') -> gmb_fate_ops:pow(?a, ?a, ?a);
op_to_scode('++') -> aeb_fate_ops:append(?a, ?a, ?a); op_to_scode('++') -> gmb_fate_ops:append(?a, ?a, ?a);
op_to_scode('::') -> aeb_fate_ops:cons(?a, ?a, ?a); op_to_scode('::') -> gmb_fate_ops:cons(?a, ?a, ?a);
op_to_scode('<') -> aeb_fate_ops:lt(?a, ?a, ?a); op_to_scode('<') -> gmb_fate_ops:lt(?a, ?a, ?a);
op_to_scode('>') -> aeb_fate_ops:gt(?a, ?a, ?a); op_to_scode('>') -> gmb_fate_ops:gt(?a, ?a, ?a);
op_to_scode('=<') -> aeb_fate_ops:elt(?a, ?a, ?a); op_to_scode('=<') -> gmb_fate_ops:elt(?a, ?a, ?a);
op_to_scode('>=') -> aeb_fate_ops:egt(?a, ?a, ?a); op_to_scode('>=') -> gmb_fate_ops:egt(?a, ?a, ?a);
op_to_scode('==') -> aeb_fate_ops:eq(?a, ?a, ?a); op_to_scode('==') -> gmb_fate_ops:eq(?a, ?a, ?a);
op_to_scode('!=') -> aeb_fate_ops:neq(?a, ?a, ?a); op_to_scode('!=') -> gmb_fate_ops:neq(?a, ?a, ?a);
op_to_scode('!') -> aeb_fate_ops:not_op(?a, ?a); op_to_scode('!') -> gmb_fate_ops:not_op(?a, ?a);
op_to_scode('bnot') -> aeb_fate_ops:bin_not(?a, ?a); op_to_scode('bnot') -> gmb_fate_ops:bin_not(?a, ?a);
op_to_scode('band') -> aeb_fate_ops:bin_and(?a, ?a, ?a); op_to_scode('band') -> gmb_fate_ops:bin_and(?a, ?a, ?a);
op_to_scode('bor') -> aeb_fate_ops:bin_or(?a, ?a, ?a); op_to_scode('bor') -> gmb_fate_ops:bin_or(?a, ?a, ?a);
op_to_scode('bxor') -> aeb_fate_ops:bin_xor(?a, ?a, ?a); op_to_scode('bxor') -> gmb_fate_ops:bin_xor(?a, ?a, ?a);
op_to_scode('<<') -> aeb_fate_ops:bin_sl(?a, ?a, ?a); op_to_scode('<<') -> gmb_fate_ops:bin_sl(?a, ?a, ?a);
op_to_scode('>>') -> aeb_fate_ops:bin_sr(?a, ?a, ?a); op_to_scode('>>') -> gmb_fate_ops:bin_sr(?a, ?a, ?a);
op_to_scode(map_get) -> aeb_fate_ops:map_lookup(?a, ?a, ?a); op_to_scode(map_get) -> gmb_fate_ops:map_lookup(?a, ?a, ?a);
op_to_scode(map_get_d) -> aeb_fate_ops:map_lookup(?a, ?a, ?a, ?a); op_to_scode(map_get_d) -> gmb_fate_ops:map_lookup(?a, ?a, ?a, ?a);
op_to_scode(map_set) -> aeb_fate_ops:map_update(?a, ?a, ?a, ?a); op_to_scode(map_set) -> gmb_fate_ops:map_update(?a, ?a, ?a, ?a);
op_to_scode(map_from_list) -> aeb_fate_ops:map_from_list(?a, ?a); op_to_scode(map_from_list) -> gmb_fate_ops:map_from_list(?a, ?a);
op_to_scode(map_to_list) -> aeb_fate_ops:map_to_list(?a, ?a); op_to_scode(map_to_list) -> gmb_fate_ops:map_to_list(?a, ?a);
op_to_scode(map_delete) -> aeb_fate_ops:map_delete(?a, ?a, ?a); op_to_scode(map_delete) -> gmb_fate_ops:map_delete(?a, ?a, ?a);
op_to_scode(map_member) -> aeb_fate_ops:map_member(?a, ?a, ?a); op_to_scode(map_member) -> gmb_fate_ops:map_member(?a, ?a, ?a);
op_to_scode(map_size) -> aeb_fate_ops:map_size_(?a, ?a); op_to_scode(map_size) -> gmb_fate_ops:map_size_(?a, ?a);
op_to_scode(stringinternal_length) -> aeb_fate_ops:str_length(?a, ?a); op_to_scode(stringinternal_length) -> gmb_fate_ops:str_length(?a, ?a);
op_to_scode(stringinternal_concat) -> aeb_fate_ops:str_join(?a, ?a, ?a); op_to_scode(stringinternal_concat) -> gmb_fate_ops:str_join(?a, ?a, ?a);
op_to_scode(stringinternal_to_bytes) -> aeb_fate_ops:str_to_bytes(?a, ?a); op_to_scode(stringinternal_to_bytes) -> gmb_fate_ops:str_to_bytes(?a, ?a);
op_to_scode(stringinternal_to_list) -> aeb_fate_ops:str_to_list(?a, ?a); op_to_scode(stringinternal_to_list) -> gmb_fate_ops:str_to_list(?a, ?a);
op_to_scode(stringinternal_from_list) -> aeb_fate_ops:str_from_list(?a, ?a); op_to_scode(stringinternal_from_list) -> gmb_fate_ops:str_from_list(?a, ?a);
op_to_scode(stringinternal_to_lower) -> aeb_fate_ops:str_to_lower(?a, ?a); op_to_scode(stringinternal_to_lower) -> gmb_fate_ops:str_to_lower(?a, ?a);
op_to_scode(stringinternal_to_upper) -> aeb_fate_ops:str_to_upper(?a, ?a); op_to_scode(stringinternal_to_upper) -> gmb_fate_ops:str_to_upper(?a, ?a);
op_to_scode(char_to_int) -> aeb_fate_ops:char_to_int(?a, ?a); op_to_scode(char_to_int) -> gmb_fate_ops:char_to_int(?a, ?a);
op_to_scode(char_from_int) -> aeb_fate_ops:char_from_int(?a, ?a); op_to_scode(char_from_int) -> gmb_fate_ops:char_from_int(?a, ?a);
op_to_scode(bits_set) -> aeb_fate_ops:bits_set(?a, ?a, ?a); op_to_scode(bits_set) -> gmb_fate_ops:bits_set(?a, ?a, ?a);
op_to_scode(bits_clear) -> aeb_fate_ops:bits_clear(?a, ?a, ?a); op_to_scode(bits_clear) -> gmb_fate_ops:bits_clear(?a, ?a, ?a);
op_to_scode(bits_test) -> aeb_fate_ops:bits_test(?a, ?a, ?a); op_to_scode(bits_test) -> gmb_fate_ops:bits_test(?a, ?a, ?a);
op_to_scode(bits_sum) -> aeb_fate_ops:bits_sum(?a, ?a); op_to_scode(bits_sum) -> gmb_fate_ops:bits_sum(?a, ?a);
op_to_scode(bits_intersection) -> aeb_fate_ops:bits_and(?a, ?a, ?a); op_to_scode(bits_intersection) -> gmb_fate_ops:bits_and(?a, ?a, ?a);
op_to_scode(bits_union) -> aeb_fate_ops:bits_or(?a, ?a, ?a); op_to_scode(bits_union) -> gmb_fate_ops:bits_or(?a, ?a, ?a);
op_to_scode(bits_difference) -> aeb_fate_ops:bits_diff(?a, ?a, ?a); op_to_scode(bits_difference) -> gmb_fate_ops:bits_diff(?a, ?a, ?a);
op_to_scode(address_to_str) -> aeb_fate_ops:addr_to_str(?a, ?a); op_to_scode(address_to_str) -> gmb_fate_ops:addr_to_str(?a, ?a);
op_to_scode(address_to_bytes) -> aeb_fate_ops:addr_to_bytes(?a, ?a); op_to_scode(address_to_bytes) -> gmb_fate_ops:addr_to_bytes(?a, ?a);
op_to_scode(int_to_str) -> aeb_fate_ops:int_to_str(?a, ?a); op_to_scode(int_to_str) -> gmb_fate_ops:int_to_str(?a, ?a);
op_to_scode(int_to_bytes) -> aeb_fate_ops:int_to_bytes(?a, ?a, ?a); op_to_scode(int_to_bytes) -> gmb_fate_ops:int_to_bytes(?a, ?a, ?a);
op_to_scode(int_mulmod) -> aeb_fate_ops:mulmod(?a, ?a, ?a, ?a); op_to_scode(int_mulmod) -> gmb_fate_ops:mulmod(?a, ?a, ?a, ?a);
op_to_scode(contract_to_address) -> aeb_fate_ops:contract_to_address(?a, ?a); op_to_scode(contract_to_address) -> gmb_fate_ops:contract_to_address(?a, ?a);
op_to_scode(address_to_contract) -> aeb_fate_ops:address_to_contract(?a, ?a); op_to_scode(address_to_contract) -> gmb_fate_ops:address_to_contract(?a, ?a);
op_to_scode(crypto_verify_sig) -> aeb_fate_ops:verify_sig(?a, ?a, ?a, ?a); op_to_scode(crypto_verify_sig) -> gmb_fate_ops:verify_sig(?a, ?a, ?a, ?a);
op_to_scode(crypto_verify_sig_secp256k1) -> aeb_fate_ops:verify_sig_secp256k1(?a, ?a, ?a, ?a); op_to_scode(crypto_verify_sig_secp256k1) -> gmb_fate_ops:verify_sig_secp256k1(?a, ?a, ?a, ?a);
op_to_scode(crypto_ecverify_secp256k1) -> aeb_fate_ops:ecverify_secp256k1(?a, ?a, ?a, ?a); op_to_scode(crypto_ecverify_secp256k1) -> gmb_fate_ops:ecverify_secp256k1(?a, ?a, ?a, ?a);
op_to_scode(crypto_ecrecover_secp256k1) -> aeb_fate_ops:ecrecover_secp256k1(?a, ?a, ?a); op_to_scode(crypto_ecrecover_secp256k1) -> gmb_fate_ops:ecrecover_secp256k1(?a, ?a, ?a);
op_to_scode(crypto_sha3) -> aeb_fate_ops:sha3(?a, ?a); op_to_scode(crypto_sha3) -> gmb_fate_ops:sha3(?a, ?a);
op_to_scode(crypto_sha256) -> aeb_fate_ops:sha256(?a, ?a); op_to_scode(crypto_sha256) -> gmb_fate_ops:sha256(?a, ?a);
op_to_scode(crypto_blake2b) -> aeb_fate_ops:blake2b(?a, ?a); op_to_scode(crypto_blake2b) -> gmb_fate_ops:blake2b(?a, ?a);
op_to_scode(crypto_poseidon) -> aeb_fate_ops:poseidon(?a, ?a, ?a); op_to_scode(crypto_poseidon) -> gmb_fate_ops:poseidon(?a, ?a, ?a);
op_to_scode(stringinternal_sha3) -> aeb_fate_ops:sha3(?a, ?a); op_to_scode(stringinternal_sha3) -> gmb_fate_ops:sha3(?a, ?a);
op_to_scode(stringinternal_sha256) -> aeb_fate_ops:sha256(?a, ?a); op_to_scode(stringinternal_sha256) -> gmb_fate_ops:sha256(?a, ?a);
op_to_scode(stringinternal_blake2b) -> aeb_fate_ops:blake2b(?a, ?a); op_to_scode(stringinternal_blake2b) -> gmb_fate_ops:blake2b(?a, ?a);
op_to_scode(mcl_bls12_381_g1_neg) -> aeb_fate_ops:bls12_381_g1_neg(?a, ?a); op_to_scode(mcl_bls12_381_g1_neg) -> gmb_fate_ops:bls12_381_g1_neg(?a, ?a);
op_to_scode(mcl_bls12_381_g1_norm) -> aeb_fate_ops:bls12_381_g1_norm(?a, ?a); op_to_scode(mcl_bls12_381_g1_norm) -> gmb_fate_ops:bls12_381_g1_norm(?a, ?a);
op_to_scode(mcl_bls12_381_g1_valid) -> aeb_fate_ops:bls12_381_g1_valid(?a, ?a); op_to_scode(mcl_bls12_381_g1_valid) -> gmb_fate_ops:bls12_381_g1_valid(?a, ?a);
op_to_scode(mcl_bls12_381_g1_is_zero) -> aeb_fate_ops:bls12_381_g1_is_zero(?a, ?a); op_to_scode(mcl_bls12_381_g1_is_zero) -> gmb_fate_ops:bls12_381_g1_is_zero(?a, ?a);
op_to_scode(mcl_bls12_381_g1_add) -> aeb_fate_ops:bls12_381_g1_add(?a, ?a, ?a); op_to_scode(mcl_bls12_381_g1_add) -> gmb_fate_ops:bls12_381_g1_add(?a, ?a, ?a);
op_to_scode(mcl_bls12_381_g1_mul) -> aeb_fate_ops:bls12_381_g1_mul(?a, ?a, ?a); op_to_scode(mcl_bls12_381_g1_mul) -> gmb_fate_ops:bls12_381_g1_mul(?a, ?a, ?a);
op_to_scode(mcl_bls12_381_g2_neg) -> aeb_fate_ops:bls12_381_g2_neg(?a, ?a); op_to_scode(mcl_bls12_381_g2_neg) -> gmb_fate_ops:bls12_381_g2_neg(?a, ?a);
op_to_scode(mcl_bls12_381_g2_norm) -> aeb_fate_ops:bls12_381_g2_norm(?a, ?a); op_to_scode(mcl_bls12_381_g2_norm) -> gmb_fate_ops:bls12_381_g2_norm(?a, ?a);
op_to_scode(mcl_bls12_381_g2_valid) -> aeb_fate_ops:bls12_381_g2_valid(?a, ?a); op_to_scode(mcl_bls12_381_g2_valid) -> gmb_fate_ops:bls12_381_g2_valid(?a, ?a);
op_to_scode(mcl_bls12_381_g2_is_zero) -> aeb_fate_ops:bls12_381_g2_is_zero(?a, ?a); op_to_scode(mcl_bls12_381_g2_is_zero) -> gmb_fate_ops:bls12_381_g2_is_zero(?a, ?a);
op_to_scode(mcl_bls12_381_g2_add) -> aeb_fate_ops:bls12_381_g2_add(?a, ?a, ?a); op_to_scode(mcl_bls12_381_g2_add) -> gmb_fate_ops:bls12_381_g2_add(?a, ?a, ?a);
op_to_scode(mcl_bls12_381_g2_mul) -> aeb_fate_ops:bls12_381_g2_mul(?a, ?a, ?a); op_to_scode(mcl_bls12_381_g2_mul) -> gmb_fate_ops:bls12_381_g2_mul(?a, ?a, ?a);
op_to_scode(mcl_bls12_381_gt_inv) -> aeb_fate_ops:bls12_381_gt_inv(?a, ?a); op_to_scode(mcl_bls12_381_gt_inv) -> gmb_fate_ops:bls12_381_gt_inv(?a, ?a);
op_to_scode(mcl_bls12_381_gt_add) -> aeb_fate_ops:bls12_381_gt_add(?a, ?a, ?a); op_to_scode(mcl_bls12_381_gt_add) -> gmb_fate_ops:bls12_381_gt_add(?a, ?a, ?a);
op_to_scode(mcl_bls12_381_gt_mul) -> aeb_fate_ops:bls12_381_gt_mul(?a, ?a, ?a); op_to_scode(mcl_bls12_381_gt_mul) -> gmb_fate_ops:bls12_381_gt_mul(?a, ?a, ?a);
op_to_scode(mcl_bls12_381_gt_pow) -> aeb_fate_ops:bls12_381_gt_pow(?a, ?a, ?a); op_to_scode(mcl_bls12_381_gt_pow) -> gmb_fate_ops:bls12_381_gt_pow(?a, ?a, ?a);
op_to_scode(mcl_bls12_381_gt_is_one) -> aeb_fate_ops:bls12_381_gt_is_one(?a, ?a); op_to_scode(mcl_bls12_381_gt_is_one) -> gmb_fate_ops:bls12_381_gt_is_one(?a, ?a);
op_to_scode(mcl_bls12_381_pairing) -> aeb_fate_ops:bls12_381_pairing(?a, ?a, ?a); op_to_scode(mcl_bls12_381_pairing) -> gmb_fate_ops:bls12_381_pairing(?a, ?a, ?a);
op_to_scode(mcl_bls12_381_miller_loop) -> aeb_fate_ops:bls12_381_miller_loop(?a, ?a, ?a); op_to_scode(mcl_bls12_381_miller_loop) -> gmb_fate_ops:bls12_381_miller_loop(?a, ?a, ?a);
op_to_scode(mcl_bls12_381_final_exp) -> aeb_fate_ops:bls12_381_final_exp(?a, ?a); op_to_scode(mcl_bls12_381_final_exp) -> gmb_fate_ops:bls12_381_final_exp(?a, ?a);
op_to_scode(mcl_bls12_381_int_to_fr) -> aeb_fate_ops:bls12_381_int_to_fr(?a, ?a); op_to_scode(mcl_bls12_381_int_to_fr) -> gmb_fate_ops:bls12_381_int_to_fr(?a, ?a);
op_to_scode(mcl_bls12_381_int_to_fp) -> aeb_fate_ops:bls12_381_int_to_fp(?a, ?a); op_to_scode(mcl_bls12_381_int_to_fp) -> gmb_fate_ops:bls12_381_int_to_fp(?a, ?a);
op_to_scode(mcl_bls12_381_fr_to_int) -> aeb_fate_ops:bls12_381_fr_to_int(?a, ?a); op_to_scode(mcl_bls12_381_fr_to_int) -> gmb_fate_ops:bls12_381_fr_to_int(?a, ?a);
op_to_scode(mcl_bls12_381_fp_to_int) -> aeb_fate_ops:bls12_381_fp_to_int(?a, ?a). op_to_scode(mcl_bls12_381_fp_to_int) -> gmb_fate_ops:bls12_381_fp_to_int(?a, ?a).
%% PUSH and STORE ?a are the same, so we use STORE to make optimizations %% PUSH and STORE ?a are the same, so we use STORE to make optimizations
%% easier, and specialize to PUSH (which is cheaper) at the end. %% easier, and specialize to PUSH (which is cheaper) at the end.
push(A) -> {'STORE', ?a, A}. push(A) -> {'STORE', ?a, A}.
tuple(0) -> push(?i({tuple, {}})); tuple(0) -> push(?i({tuple, {}}));
tuple(N) -> aeb_fate_ops:tuple(?a, N). tuple(N) -> gmb_fate_ops:tuple(?a, N).
%% -- Debug info functions -- %% -- Debug info functions --
@@ -822,8 +825,8 @@ dbg_undef(Undef, SCode) when is_tuple(SCode); is_atom(SCode) ->
true -> tuple_to_list(SCode); true -> tuple_to_list(SCode);
false -> [SCode] false -> [SCode]
end, end,
Op = aeb_fate_opcodes:m_to_op(Mnemonic), Op = gmb_fate_opcodes:m_to_op(Mnemonic),
case aeb_fate_opcodes:end_bb(Op) of case gmb_fate_opcodes:end_bb(Op) of
true -> [Undef, SCode]; true -> [Undef, SCode];
false -> [SCode, Undef] false -> [SCode, Undef]
end. end.
@@ -895,7 +898,7 @@ pp_ann(_, []) -> [].
pp_op(switch_body) -> "SWITCH-BODY"; pp_op(switch_body) -> "SWITCH-BODY";
pp_op(loop) -> "LOOP"; pp_op(loop) -> "LOOP";
pp_op(I) -> pp_op(I) ->
aeb_fate_pp:format_op(I, #{}). gmb_fate_pp:format_op(I, #{}).
pp_arg(?i(I)) -> io_lib:format("~w", [I]); pp_arg(?i(I)) -> io_lib:format("~w", [I]);
pp_arg({arg, N}) -> io_lib:format("arg~p", [N]); pp_arg({arg, N}) -> io_lib:format("arg~p", [N]);
@@ -1665,14 +1668,14 @@ unannotate(Code) when is_list(Code) ->
unannotate({i, _Ann, I}) -> [I]. unannotate({i, _Ann, I}) -> [I].
%% Desugar and specialize %% Desugar and specialize
desugar({'ADD', ?a, ?i(1), ?a}) -> [aeb_fate_ops:inc()]; desugar({'ADD', ?a, ?i(1), ?a}) -> [gmb_fate_ops:inc()];
desugar({'ADD', A, ?i(1), A}) -> [aeb_fate_ops:inc(desugar_arg(A))]; desugar({'ADD', A, ?i(1), A}) -> [gmb_fate_ops:inc(desugar_arg(A))];
desugar({'ADD', ?a, ?a, ?i(1)}) -> [aeb_fate_ops:inc()]; desugar({'ADD', ?a, ?a, ?i(1)}) -> [gmb_fate_ops:inc()];
desugar({'ADD', A, A, ?i(1)}) -> [aeb_fate_ops:inc(desugar_arg(A))]; desugar({'ADD', A, A, ?i(1)}) -> [gmb_fate_ops:inc(desugar_arg(A))];
desugar({'SUB', ?a, ?a, ?i(1)}) -> [aeb_fate_ops:dec()]; desugar({'SUB', ?a, ?a, ?i(1)}) -> [gmb_fate_ops:dec()];
desugar({'SUB', A, A, ?i(1)}) -> [aeb_fate_ops:dec(desugar_arg(A))]; desugar({'SUB', A, A, ?i(1)}) -> [gmb_fate_ops:dec(desugar_arg(A))];
desugar({'STORE', ?a, A}) -> [aeb_fate_ops:push(desugar_arg(A))]; desugar({'STORE', ?a, A}) -> [gmb_fate_ops:push(desugar_arg(A))];
desugar({'STORE', R, ?a}) -> [aeb_fate_ops:pop(desugar_arg(R))]; desugar({'STORE', R, ?a}) -> [gmb_fate_ops:pop(desugar_arg(R))];
desugar({switch, Arg, Type, Alts, Def}) -> desugar({switch, Arg, Type, Alts, Def}) ->
[{switch, desugar_arg(Arg), Type, [desugar(A) || A <- Alts], desugar(Def)}]; [{switch, desugar_arg(Arg), Type, [desugar(A) || A <- Alts], desugar(Def)}];
desugar(missing) -> missing; desugar(missing) -> missing;
@@ -1692,11 +1695,11 @@ desugar_arg(A) -> A.
%% Constructing basic blocks %% Constructing basic blocks
to_basic_blocks(Funs) -> to_basic_blocks(Funs) ->
to_basic_blocks(maps:to_list(Funs), aeb_fate_code:new()). to_basic_blocks(maps:to_list(Funs), gmb_fate_code:new()).
to_basic_blocks([{Name, {Attrs, Sig, Code}}|Left], Acc) -> to_basic_blocks([{Name, {Attrs, Sig, Code}}|Left], Acc) ->
BB = bb(Name, Code ++ [aeb_fate_ops:return()]), BB = bb(Name, Code ++ [gmb_fate_ops:return()]),
to_basic_blocks(Left, aeb_fate_code:insert_fun(Name, Attrs, Sig, BB, Acc)); to_basic_blocks(Left, gmb_fate_code:insert_fun(Name, Attrs, Sig, BB, Acc));
to_basic_blocks([], Acc) -> to_basic_blocks([], Acc) ->
Acc. Acc.
@@ -1767,7 +1770,7 @@ block(Blk = #blk{code = [{switch, Arg, Type, Alts, Default} | Code],
{DefRef, DefBlk} = {DefRef, DefBlk} =
case Default of case Default of
missing when Catchall == none -> missing when Catchall == none ->
FreshBlk([aeb_fate_ops:abort(?i(<<"Incomplete patterns">>))], none); FreshBlk([gmb_fate_ops:abort(?i(<<"Incomplete patterns">>))], none);
missing -> {Catchall, []}; missing -> {Catchall, []};
_ -> FreshBlk(Default ++ [{jump, RestRef}], Catchall) _ -> FreshBlk(Default ++ [{jump, RestRef}], Catchall)
%% ^ fall-through to the outer catchall %% ^ fall-through to the outer catchall
@@ -1942,14 +1945,14 @@ split_calls(Ref, [I | Code], Acc, Blocks) ->
set_labels(Labels, {Ref, Code}) when is_reference(Ref) -> set_labels(Labels, {Ref, Code}) when is_reference(Ref) ->
{maps:get(Ref, Labels), [ set_labels(Labels, I) || I <- Code ]}; {maps:get(Ref, Labels), [ set_labels(Labels, I) || I <- Code ]};
set_labels(_Labels, loop) -> aeb_fate_ops:jump(0); set_labels(_Labels, loop) -> gmb_fate_ops:jump(0);
set_labels(Labels, {jump, Ref}) -> aeb_fate_ops:jump(maps:get(Ref, Labels)); set_labels(Labels, {jump, Ref}) -> gmb_fate_ops:jump(maps:get(Ref, Labels));
set_labels(Labels, {jumpif, Arg, Ref}) -> aeb_fate_ops:jumpif(Arg, maps:get(Ref, Labels)); set_labels(Labels, {jumpif, Arg, Ref}) -> gmb_fate_ops:jumpif(Arg, maps:get(Ref, Labels));
set_labels(Labels, {switch, Arg, Refs}) -> set_labels(Labels, {switch, Arg, Refs}) ->
case [ maps:get(Ref, Labels) || Ref <- Refs ] of case [ maps:get(Ref, Labels) || Ref <- Refs ] of
[R1, R2] -> aeb_fate_ops:switch(Arg, R1, R2); [R1, R2] -> gmb_fate_ops:switch(Arg, R1, R2);
[R1, R2, R3] -> aeb_fate_ops:switch(Arg, R1, R2, R3); [R1, R2, R3] -> gmb_fate_ops:switch(Arg, R1, R2, R3);
Rs -> aeb_fate_ops:switch(Arg, Rs) Rs -> gmb_fate_ops:switch(Arg, Rs)
end; end;
set_labels(_, I) -> I. set_labels(_, I) -> I.
+8 -1
View File
@@ -15,7 +15,7 @@
many/1, many1/1, sep/2, sep1/2, many/1, many1/1, sep/2, sep1/2,
infixl/2, infixr/2]). infixl/2, infixr/2]).
-export([current_file/0, set_current_file/1, -export([current_file/0, set_current_file/1, current_dir/0, set_current_dir/1,
current_include_type/0, set_current_include_type/1]). current_include_type/0, set_current_include_type/1]).
%% -- Types ------------------------------------------------------------------ %% -- Types ------------------------------------------------------------------
@@ -480,6 +480,13 @@ current_file() ->
set_current_file(File) -> set_current_file(File) ->
put('$current_file', File). put('$current_file', File).
%% Current source directory
current_dir() ->
get('$current_dir').
set_current_dir(File) ->
put('$current_dir', File).
add_current_file({L, C}) -> {current_file(), L, C}; add_current_file({L, C}) -> {current_file(), L, C};
add_current_file(Pos) -> Pos. add_current_file(Pos) -> Pos.
+46 -22
View File
@@ -19,6 +19,7 @@
-include("aeso_parse_lib.hrl"). -include("aeso_parse_lib.hrl").
-import(aeso_parse_lib, [current_file/0, set_current_file/1, -import(aeso_parse_lib, [current_file/0, set_current_file/1,
current_dir/0, set_current_dir/1,
current_include_type/0, set_current_include_type/1]). current_include_type/0, set_current_include_type/1]).
-type parse_result() :: aeso_syntax:ast() | {aeso_syntax:ast(), sets:set(include_hash())} | none(). -type parse_result() :: aeso_syntax:ast() | {aeso_syntax:ast(), sets:set(include_hash())} | none().
@@ -58,6 +59,7 @@ run_parser(P, Inp, Opts) ->
parse_and_scan(P, S, Opts) -> parse_and_scan(P, S, Opts) ->
set_current_file(proplists:get_value(src_file, Opts, no_file)), set_current_file(proplists:get_value(src_file, Opts, no_file)),
set_current_dir(proplists:get_value(src_dir, Opts, no_file)),
set_current_include_type(proplists:get_value(include_type, Opts, none)), set_current_include_type(proplists:get_value(include_type, Opts, none)),
case aeso_scan:scan(S) of case aeso_scan:scan(S) of
{ok, Tokens} -> aeso_parse_lib:parse(P, Tokens); {ok, Tokens} -> aeso_parse_lib:parse(P, Tokens);
@@ -300,7 +302,7 @@ stmt() ->
, {switch, keyword(switch), parens(expr()), maybe_block(branch())} , {switch, keyword(switch), parens(expr()), maybe_block(branch())}
, {'if', keyword('if'), parens(expr()), body()} , {'if', keyword('if'), parens(expr()), body()}
, {elif, keyword(elif), parens(expr()), body()} , {elif, keyword(elif), parens(expr()), body()}
, {else, keyword(else), body()} , {'else', keyword('else'), body()}
])). ])).
branch() -> branch() ->
@@ -324,7 +326,7 @@ expr100() ->
Expr150 = ?LAZY_P(expr150()), Expr150 = ?LAZY_P(expr150()),
choice( choice(
[ ?RULE(lam_args(), keyword('=>'), body(), {lam, _2, _1, _3}) %% TODO: better location [ ?RULE(lam_args(), keyword('=>'), body(), {lam, _2, _1, _3}) %% TODO: better location
, {'if', keyword('if'), parens(Expr100), Expr150, right(tok(else), Expr100)} , {'if', keyword('if'), parens(Expr100), Expr150, right(tok('else'), Expr100)}
, ?RULE(Expr150, optional(right(tok(':'), type())), , ?RULE(Expr150, optional(right(tok(':'), type())),
case _2 of case _2 of
none -> _1; none -> _1;
@@ -523,7 +525,7 @@ id_or_addr() ->
?RULE(id(), parse_addr_literal(_1)). ?RULE(id(), parse_addr_literal(_1)).
parse_addr_literal(Id = {id, Ann, Name}) -> parse_addr_literal(Id = {id, Ann, Name}) ->
case lists:member(lists:sublist(Name, 3), ["ak_", "ok_", "oq_", "ct_"]) of case lists:member(lists:sublist(Name, 3), ["ak_", "ok_", "oq_", "ct_", "sg_"]) of
false -> Id; false -> Id;
true -> true ->
try aeser_api_encoder:decode(list_to_binary(Name)) of try aeser_api_encoder:decode(list_to_binary(Name)) of
@@ -562,6 +564,7 @@ bracket_list(P) -> brackets(comma_sep(P)).
-spec pos_ann(ann_line(), ann_col()) -> ann(). -spec pos_ann(ann_line(), ann_col()) -> ann().
pos_ann(Line, Col) -> pos_ann(Line, Col) ->
[ {file, current_file()} [ {file, current_file()}
, {dir, current_dir()}
, {include_type, current_include_type()} , {include_type, current_include_type()}
, {line, Line} , {line, Line}
, {col, Col} ]. , {col, Col} ].
@@ -609,7 +612,7 @@ group_ifs([], Acc) ->
group_ifs([{'if', Ann, Cond, Then} | Stmts], Acc) -> group_ifs([{'if', Ann, Cond, Then} | Stmts], Acc) ->
{Elses, Rest} = else_branches(Stmts, []), {Elses, Rest} = else_branches(Stmts, []),
group_ifs(Rest, [build_if(Ann, Cond, Then, Elses) | Acc]); group_ifs(Rest, [build_if(Ann, Cond, Then, Elses) | Acc]);
group_ifs([{else, Ann, _} | _], _) -> group_ifs([{'else', Ann, _} | _], _) ->
fail({Ann, "No matching 'if' for 'else'"}); fail({Ann, "No matching 'if' for 'else'"});
group_ifs([{elif, Ann, _, _} | _], _) -> group_ifs([{elif, Ann, _, _} | _], _) ->
fail({Ann, "No matching 'if' for 'elif'"}); fail({Ann, "No matching 'if' for 'elif'"});
@@ -619,14 +622,14 @@ group_ifs([Stmt | Stmts], Acc) ->
build_if(Ann, Cond, Then, [{elif, Ann1, Cond1, Then1} | Elses]) -> build_if(Ann, Cond, Then, [{elif, Ann1, Cond1, Then1} | Elses]) ->
{'if', Ann, Cond, Then, {'if', Ann, Cond, Then,
set_ann(format, elif, build_if(Ann1, Cond1, Then1, Elses))}; set_ann(format, elif, build_if(Ann1, Cond1, Then1, Elses))};
build_if(Ann, Cond, Then, [{else, _Ann, Else}]) -> build_if(Ann, Cond, Then, [{'else', _Ann, Else}]) ->
{'if', Ann, Cond, Then, Else}; {'if', Ann, Cond, Then, Else};
build_if(Ann, Cond, Then, []) -> build_if(Ann, Cond, Then, []) ->
{'if', Ann, Cond, Then, {tuple, [{origin, system}], []}}. {'if', Ann, Cond, Then, {tuple, [{origin, system}], []}}.
else_branches([Elif = {elif, _, _, _} | Stmts], Acc) -> else_branches([Elif = {elif, _, _, _} | Stmts], Acc) ->
else_branches(Stmts, [Elif | Acc]); else_branches(Stmts, [Elif | Acc]);
else_branches([Else = {else, _, _} | Stmts], Acc) -> else_branches([Else = {'else', _, _} | Stmts], Acc) ->
{lists:reverse([Else | Acc]), Stmts}; {lists:reverse([Else | Acc]), Stmts};
else_branches(Stmts, Acc) -> else_branches(Stmts, Acc) ->
{lists:reverse(Acc), Stmts}. {lists:reverse(Acc), Stmts}.
@@ -702,7 +705,7 @@ expand_includes([], Included, Acc, Opts) ->
end; end;
expand_includes([{include, Ann, {string, _SAnn, File}} | AST], Included, Acc, Opts) -> expand_includes([{include, Ann, {string, _SAnn, File}} | AST], Included, Acc, Opts) ->
case get_include_code(File, Ann, Opts) of case get_include_code(File, Ann, Opts) of
{ok, Code} -> {ok, AbsDir, Code} ->
Hashed = hash_include(File, Code), Hashed = hash_include(File, Code),
case sets:is_element(Hashed, Included) of case sets:is_element(Hashed, Included) of
false -> false ->
@@ -712,9 +715,10 @@ expand_includes([{include, Ann, {string, _SAnn, File}} | AST], Included, Acc, Op
_ -> indirect _ -> indirect
end, end,
Opts1 = lists:keystore(src_file, 1, Opts, {src_file, File}), Opts1 = lists:keystore(src_file, 1, Opts, {src_file, File}),
Opts2 = lists:keystore(include_type, 1, Opts1, {include_type, IncludeType}), Opts2 = lists:keystore(src_dir, 1, Opts1, {src_dir, AbsDir}),
Opts3 = lists:keystore(include_type, 1, Opts2, {include_type, IncludeType}),
Included1 = sets:add_element(Hashed, Included), Included1 = sets:add_element(Hashed, Included),
case parse_and_scan(file(), Code, Opts2) of case parse_and_scan(file(), Code, Opts3) of
{ok, AST1} -> {ok, AST1} ->
expand_includes(AST1 ++ AST, Included1, Acc, Opts); expand_includes(AST1 ++ AST, Included1, Acc, Opts);
Err = {error, _} -> Err = {error, _} ->
@@ -732,22 +736,21 @@ expand_includes([E | AST], Included, Acc, Opts) ->
read_file(File, Opts) -> read_file(File, Opts) ->
case proplists:get_value(include, Opts, {explicit_files, #{}}) of case proplists:get_value(include, Opts, {explicit_files, #{}}) of
{file_system, Paths} -> {file_system, Paths} ->
CandidateNames = [ filename:join(Dir, File) || Dir <- Paths ], lists:foldr(fun(Path, {error, _}) -> read_file_(Path, File);
lists:foldr(fun(F, {error, _}) -> file:read_file(F); (_Path, OK) -> OK end, {error, not_found}, Paths);
(_F, OK) -> OK end, {error, not_found}, CandidateNames);
{explicit_files, Files} -> {explicit_files, Files} ->
case maps:get(binary_to_list(File), Files, not_found) of case maps:get(binary_to_list(File), Files, not_found) of
not_found -> {error, not_found}; not_found -> {error, not_found};
Src -> {ok, Src} Src -> {ok, File, Src}
end; end;
escript -> escript ->
try try
Escript = escript:script_name(), Escript = escript:script_name(),
{ok, Sections} = escript:extract(Escript, []), {ok, Sections} = escript:extract(Escript, []),
Archive = proplists:get_value(archive, Sections), Archive = proplists:get_value(archive, Sections),
FileName = binary_to_list(filename:join([aesophia, priv, stdlib, File])), FileName = binary_to_list(filename:join([sophia, priv, stdlib, File])),
case zip:extract(Archive, [{file_list, [FileName]}, memory]) of case zip:extract(Archive, [{file_list, [FileName]}, memory]) of
{ok, [{_, Src}]} -> {ok, Src}; {ok, [{_, Src}]} -> {ok, escript, Src};
_ -> {error, not_found} _ -> {error, not_found}
end end
catch _:_ -> catch _:_ ->
@@ -755,6 +758,13 @@ read_file(File, Opts) ->
end end
end. end.
read_file_(Path, File) ->
AbsFile = filename:join(Path, File),
case file:read_file(AbsFile) of
{ok, Bin} -> {ok, aeso_utils:canonical_dir(filename:dirname(AbsFile)), Bin};
Err -> Err
end.
stdlib_options() -> stdlib_options() ->
StdLibDir = aeso_stdlib:stdlib_include_path(), StdLibDir = aeso_stdlib:stdlib_include_path(),
case filelib:is_dir(StdLibDir) of case filelib:is_dir(StdLibDir) of
@@ -763,23 +773,37 @@ stdlib_options() ->
end. end.
get_include_code(File, Ann, Opts) -> get_include_code(File, Ann, Opts) ->
case {read_file(File, Opts), read_file(File, stdlib_options())} of %% Temporarily extend include paths with the directory of the current file
{{ok, Bin}, {ok, _}} -> Opts1 = include_current_file_dir(Opts, Ann),
case {read_file(File, Opts1), read_file(File, stdlib_options())} of
{{ok, Dir, Bin}, {ok, _}} ->
case filename:basename(File) == File of case filename:basename(File) == File of
true -> { error true -> { error
, fail( ann_pos(Ann) , fail( ann_pos(Ann)
, "Illegal redefinition of standard library " ++ binary_to_list(File))}; , "Illegal redefinition of standard library " ++ binary_to_list(File))};
%% If a path is provided then the stdlib takes lower priority %% If a path is provided then the stdlib takes lower priority
false -> {ok, binary_to_list(Bin)} false -> {ok, Dir, binary_to_list(Bin)}
end; end;
{_, {ok, Bin}} -> {_, {ok, _, Bin}} ->
{ok, binary_to_list(Bin)}; {ok, stdlib, binary_to_list(Bin)};
{{ok, Bin}, _} -> {{ok, Dir, Bin}, _} ->
{ok, binary_to_list(Bin)}; {ok, Dir, binary_to_list(Bin)};
{_, _} -> {_, _} ->
{error, {ann_pos(Ann), include_error, File}} {error, {ann_pos(Ann), include_error, File}}
end. end.
include_current_file_dir(Opts, Ann) ->
case {proplists:get_value(dir, Ann, undefined),
proplists:get_value(include, Opts, undefined)} of
{undefined, _} -> Opts;
{CurrDir, {file_system, Paths}} ->
case lists:member(CurrDir, Paths) of
false -> [{include, {file_system, [CurrDir | Paths]}} | Opts];
true -> Opts
end;
{_, _} -> Opts
end.
-spec hash_include(string() | binary(), string()) -> include_hash(). -spec hash_include(string() | binary(), string()) -> include_hash().
hash_include(File, Code) when is_binary(File) -> hash_include(File, Code) when is_binary(File) ->
hash_include(binary_to_list(File), Code); hash_include(binary_to_list(File), Code);
+4 -3
View File
@@ -387,7 +387,8 @@ expr_p(_, {Type, _, Bin})
when Type == account_pubkey; when Type == account_pubkey;
Type == contract_pubkey; Type == contract_pubkey;
Type == oracle_pubkey; Type == oracle_pubkey;
Type == oracle_query_id -> Type == oracle_query_id;
Type == signature ->
text(binary_to_list(aeser_api_encoder:encode(Type, Bin))); text(binary_to_list(aeser_api_encoder:encode(Type, Bin)));
expr_p(_, {string, _, <<>>}) -> text("\"\""); expr_p(_, {string, _, <<>>}) -> text("\"\"");
expr_p(_, {string, _, S}) -> expr_p(_, {string, _, S}) ->
@@ -418,7 +419,7 @@ stmt_p({'if', _, Cond, Then}) ->
block_expr(200, beside(text("if"), paren(expr(Cond))), Then); block_expr(200, beside(text("if"), paren(expr(Cond))), Then);
stmt_p({elif, _, Cond, Then}) -> stmt_p({elif, _, Cond, Then}) ->
block_expr(200, beside(text("elif"), paren(expr(Cond))), Then); block_expr(200, beside(text("elif"), paren(expr(Cond))), Then);
stmt_p({else, Else}) -> stmt_p({'else', Else}) ->
HideGenerated = not show_generated(), HideGenerated = not show_generated(),
case aeso_syntax:get_ann(origin, Else) of case aeso_syntax:get_ann(origin, Else) of
system when HideGenerated -> empty(); system when HideGenerated -> empty();
@@ -533,5 +534,5 @@ get_elifs(If = {'if', Ann, Cond, Then, Else}, Elifs) ->
elif -> get_elifs(Else, [{elif, Ann, Cond, Then} | Elifs]); elif -> get_elifs(Else, [{elif, Ann, Cond, Then} | Elifs]);
_ -> {lists:reverse(Elifs), If} _ -> {lists:reverse(Elifs), If}
end; end;
get_elifs(Else, Elifs) -> {lists:reverse(Elifs), {else, Else}}. get_elifs(Else, Elifs) -> {lists:reverse(Elifs), {'else', Else}}.
+1 -1
View File
@@ -13,5 +13,5 @@
-export([stdlib_include_path/0]). -export([stdlib_include_path/0]).
stdlib_include_path() -> stdlib_include_path() ->
filename:join([code:priv_dir(aesophia), "stdlib"]). filename:join([code:priv_dir(sophia), "stdlib"]).
+1
View File
@@ -100,6 +100,7 @@
| {contract_pubkey, ann(), binary()} | {contract_pubkey, ann(), binary()}
| {oracle_pubkey, ann(), binary()} | {oracle_pubkey, ann(), binary()}
| {oracle_query_id, ann(), binary()} | {oracle_query_id, ann(), binary()}
| {signature, ann(), binary()}
| {string, ann(), binary()} | {string, ann(), binary()}
| {char, ann(), integer()}. | {char, ann(), integer()}.
+10 -2
View File
@@ -6,7 +6,7 @@
%%%------------------------------------------------------------------- %%%-------------------------------------------------------------------
-module(aeso_syntax_utils). -module(aeso_syntax_utils).
-export([used_ids/1, used_types/2, used/1]). -export([used_ids/1, used_ids/2, used_types/2, used/1]).
-record(alg, {zero, plus, scoped}). -record(alg, {zero, plus, scoped}).
@@ -110,8 +110,16 @@ fold(Alg = #alg{zero = Zero, plus = Plus, scoped = Scoped}, Fun, K, X) ->
%% Name dependencies %% Name dependencies
%% Used ids, top level
used_ids(E) -> used_ids(E) ->
[ X || {{term, [X]}, _} <- used(E) ]. used_ids([], E).
%% Used ids, top level or in (current) namespace
used_ids(Ns, E) ->
[ lists:last(Xs) || {{term, Xs}, _} <- used(E), in_ns(Xs, Ns) ].
in_ns([_], _) -> true;
in_ns(Xs, Ns) -> lists:droplast(Xs) == Ns.
used_types([Top] = _CurrentNS, T) -> used_types([Top] = _CurrentNS, T) ->
F = fun({{type, [X]}, _}) -> [X]; F = fun({{type, [X]}, _}) -> [X];
+13 -1
View File
@@ -6,10 +6,22 @@
%%%------------------------------------------------------------------- %%%-------------------------------------------------------------------
-module(aeso_utils). -module(aeso_utils).
-export([scc/1]). -export([scc/1, canonical_dir/1]).
-export_type([graph/1]). -export_type([graph/1]).
%% -- Simplistic canonical directory
%% Note: no attempts to be 100% complete
canonical_dir(Dir) ->
{ok, Cwd} = file:get_cwd(),
AbsName = filename:absname(Dir),
RelAbsName = filename:join(tl(filename:split(AbsName))),
case filelib:safe_relative_path(RelAbsName, Cwd) of
unsafe -> AbsName;
Simplified -> filename:absname(Simplified, "")
end.
%% -- Topological sort %% -- Topological sort
-type graph(Node) :: #{Node => [Node]}. %% List of incoming edges (dependencies). -type graph(Node) :: #{Node => [Node]}. %% List of incoming edges (dependencies).
+8 -3
View File
@@ -8,14 +8,17 @@
-export([ from_fate/2 ]). -export([ from_fate/2 ]).
-include_lib("aebytecode/include/aeb_fate_data.hrl"). -include_lib("gmbytecode/include/gmb_fate_data.hrl").
-spec from_fate(aeso_syntax:type(), aeb_fate_data:fate_type()) -> aeso_syntax:expr(). -spec from_fate(aeso_syntax:type(), gmb_fate_data:fate_type()) -> aeso_syntax:expr().
from_fate({id, _, "address"}, ?FATE_ADDRESS(Bin)) -> {account_pubkey, [], Bin}; from_fate({id, _, "address"}, ?FATE_ADDRESS(Bin)) -> {account_pubkey, [], Bin};
from_fate({id, _, "signature"}, ?FATE_BYTES(Bin)) -> {signature, [], Bin};
from_fate({id, _, "hash"}, ?FATE_BYTES(Bin)) -> {bytes, [], Bin};
from_fate({id, _, "unit"}, ?FATE_UNIT) -> {tuple, [], []};
from_fate({app_t, _, {id, _, "oracle"}, _}, ?FATE_ORACLE(Bin)) -> {oracle_pubkey, [], Bin}; from_fate({app_t, _, {id, _, "oracle"}, _}, ?FATE_ORACLE(Bin)) -> {oracle_pubkey, [], Bin};
from_fate({app_t, _, {id, _, "oracle_query"}, _}, ?FATE_ORACLE_Q(Bin)) -> {oracle_query_id, [], Bin}; from_fate({app_t, _, {id, _, "oracle_query"}, _}, ?FATE_ORACLE_Q(Bin)) -> {oracle_query_id, [], Bin};
from_fate({con, _, _Name}, ?FATE_CONTRACT(Bin)) -> {contract_pubkey, [], Bin}; from_fate({con, _, _Name}, ?FATE_CONTRACT(Bin)) -> {contract_pubkey, [], Bin};
from_fate({bytes_t, _, any}, ?FATE_BYTES(Bin)) -> {bytes, [], Bin}; from_fate({bytes_t, _, any}, ?FATE_BYTES(Bin)) -> make_any_bytes(Bin);
from_fate({bytes_t, _, N}, ?FATE_BYTES(Bin)) when byte_size(Bin) == N -> {bytes, [], Bin}; from_fate({bytes_t, _, N}, ?FATE_BYTES(Bin)) when byte_size(Bin) == N -> {bytes, [], Bin};
from_fate({id, _, "bits"}, ?FATE_BITS(N)) -> make_bits(N); from_fate({id, _, "bits"}, ?FATE_BITS(N)) -> make_bits(N);
from_fate({id, _, "int"}, N) when is_integer(N) -> from_fate({id, _, "int"}, N) when is_integer(N) ->
@@ -187,3 +190,5 @@ make_bits(Set, Zero, I, N) when 0 == N rem 2 ->
make_bits(Set, Zero, I, N) -> make_bits(Set, Zero, I, N) ->
{app, [], Set, [make_bits(Set, Zero, I + 1, N div 2), {int, [], I}]}. {app, [], Set, [make_bits(Set, Zero, I + 1, N div 2), {int, [], I}]}.
make_any_bytes(Bin) ->
{app, [], {qid, [], ["Bytes", "to_any_size"]}, [{bytes, [], Bin}]}.
+3 -4
View File
@@ -1,14 +1,13 @@
{application, aesophia, {application, sophia,
[{description, "Compiler for Aeternity Sophia language"}, [{description, "Compiler for Aeternity Sophia language"},
{vsn, "8.0.0"}, {vsn, "8.0.1"},
{registered, []}, {registered, []},
{applications, {applications,
[kernel, [kernel,
stdlib, stdlib,
jsx, jsx,
syntax_tools, syntax_tools,
getopt, gmbytecode,
aebytecode,
eblake2 eblake2
]}, ]},
{env,[]}, {env,[]},
+6 -6
View File
@@ -65,9 +65,9 @@ to_sophia_value_mcl_bls12_381_test() ->
Opts = [{backend, fate}], Opts = [{backend, fate}],
CallValue32 = aeb_fate_encoding:serialize({bytes, <<20:256>>}), CallValue32 = gmb_fate_encoding:serialize({bytes, <<20:256>>}),
CallValue48 = aeb_fate_encoding:serialize({bytes, <<55:384>>}), CallValue48 = gmb_fate_encoding:serialize({bytes, <<55:384>>}),
CallValueTp = aeb_fate_encoding:serialize({tuple, {{bytes, <<15:256>>}, {bytes, <<160:256>>}, {bytes, <<1234:256>>}}}), CallValueTp = gmb_fate_encoding:serialize({tuple, {{bytes, <<15:256>>}, {bytes, <<160:256>>}, {bytes, <<1234:256>>}}}),
{ok, _} = aeso_compiler:to_sophia_value(Code, "test_bls12_381_fp", ok, CallValue32, Opts), {ok, _} = aeso_compiler:to_sophia_value(Code, "test_bls12_381_fp", ok, CallValue32, Opts),
{error, _} = aeso_compiler:to_sophia_value(Code, "test_bls12_381_fp", ok, CallValue48, Opts), {error, _} = aeso_compiler:to_sophia_value(Code, "test_bls12_381_fp", ok, CallValue48, Opts),
@@ -227,7 +227,7 @@ encode_decode_calldata_(Code, FunName, Args) ->
"init" -> "init" ->
[]; [];
_ -> _ ->
{ok, FateArgs} = aeb_fate_abi:decode_calldata(FunName, Calldata), {ok, FateArgs} = gmb_fate_abi:decode_calldata(FunName, Calldata),
FateArgs FateArgs
end. end.
@@ -236,7 +236,7 @@ encode_decode(D) ->
D. D.
encode(D) -> encode(D) ->
aeb_fate_encoding:serialize(D). gmb_fate_encoding:serialize(D).
decode(B) -> decode(B) ->
aeb_fate_encoding:deserialize(B). gmb_fate_encoding:deserialize(B).
+2
View File
@@ -85,6 +85,7 @@ compilable_contracts() ->
{"funargs", "bitsum", ["Bits.clear(Bits.clear(Bits.all, 4), 2)"]}, %% Order matters for test {"funargs", "bitsum", ["Bits.clear(Bits.clear(Bits.all, 4), 2)"]}, %% Order matters for test
{"funargs", "bitsum", ["Bits.set(Bits.set(Bits.none, 4), 2)"]}, {"funargs", "bitsum", ["Bits.set(Bits.set(Bits.none, 4), 2)"]},
{"funargs", "read", ["{label = \"question 1\", result = 4}"]}, {"funargs", "read", ["{label = \"question 1\", result = 4}"]},
{"funargs", "any_bytes", ["Bytes.to_any_size(#0011AA)"]},
{"funargs", "sjutton", ["#0011012003100011012003100011012003"]}, {"funargs", "sjutton", ["#0011012003100011012003100011012003"]},
{"funargs", "sextiosju", ["#01020304050607080910111213141516171819202122232425262728293031323334353637383940" {"funargs", "sextiosju", ["#01020304050607080910111213141516171819202122232425262728293031323334353637383940"
"414243444546474849505152535455565758596061626364656667"]}, "414243444546474849505152535455565758596061626364656667"]},
@@ -116,6 +117,7 @@ compilable_contracts() ->
{"funargs", "chain_base_tx", ["Chain.NameRevokeTx(#ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff)"]}, {"funargs", "chain_base_tx", ["Chain.NameRevokeTx(#ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff)"]},
{"funargs", "chain_base_tx", ["Chain.NameTransferTx(ak_2dATVcZ9KJU5a8hdsVtTv21pYiGWiPbmVcU1Pz72FFqpk9pSRR, #ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff)"]}, {"funargs", "chain_base_tx", ["Chain.NameTransferTx(ak_2dATVcZ9KJU5a8hdsVtTv21pYiGWiPbmVcU1Pz72FFqpk9pSRR, #ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff)"]},
{"funargs", "chain_base_tx", ["Chain.GAAttachTx"]}, {"funargs", "chain_base_tx", ["Chain.GAAttachTx"]},
{"funargs", "sig", ["sg_MhibzTP1wWzGCTjtPFr1TiPqRJrrJqw7auvEuF5i3FdoALWqXLBDY6xxRRNUSPHK3EQTnTzF12EyspkxrSMxVHKsZeSMj"]},
{"variant_types", "init", []}, {"variant_types", "init", []},
{"basic_auth", "init", []}, {"basic_auth", "init", []},
{"address_literals", "init", []}, {"address_literals", "init", []},
+12 -4
View File
@@ -28,7 +28,7 @@ simple_compile_test_() ->
fun() -> fun() ->
case compile(ContractName) of case compile(ContractName) of
#{fate_code := Code} -> #{fate_code := Code} ->
Code1 = aeb_fate_code:deserialize(aeb_fate_code:serialize(Code)), Code1 = gmb_fate_code:deserialize(gmb_fate_code:serialize(Code)),
?assertMatch({X, X}, {Code1, Code}); ?assertMatch({X, X}, {Code1, Code});
Error -> io:format("\n\n~p\n\n", [Error]), print_and_throw(Error) Error -> io:format("\n\n~p\n\n", [Error]), print_and_throw(Error)
end end
@@ -70,6 +70,7 @@ simple_compile_test_() ->
fun() -> fun() ->
#{ warnings := Warnings } = compile("warnings", [warn_all]), #{ warnings := Warnings } = compile("warnings", [warn_all]),
#{ warnings := [] } = compile("warning_unused_include_no_include", [warn_all]), #{ warnings := [] } = compile("warning_unused_include_no_include", [warn_all]),
#{ warnings := [] } = compile("warning_used_record_typedef", [warn_all]),
check_warnings(warnings(), Warnings) check_warnings(warnings(), Warnings)
end} ] ++ end} ] ++
[]. [].
@@ -83,7 +84,7 @@ stdlib_test_() ->
Options = [{src_file, File}], Options = [{src_file, File}],
case aeso_compiler:from_string(String, Options) of case aeso_compiler:from_string(String, Options) of
{ok, #{fate_code := Code}} -> {ok, #{fate_code := Code}} ->
Code1 = aeb_fate_code:deserialize(aeb_fate_code:serialize(Code)), Code1 = gmb_fate_code:deserialize(gmb_fate_code:serialize(Code)),
?assertMatch({X, X}, {Code1, Code}); ?assertMatch({X, X}, {Code1, Code});
{error, Error} -> io:format("\n\n~p\n\n", [Error]), print_and_throw(Error) {error, Error} -> io:format("\n\n~p\n\n", [Error]), print_and_throw(Error)
end end
@@ -161,6 +162,7 @@ compilable_contracts() ->
"state_handling", "state_handling",
"events", "events",
"include", "include",
"relative_include",
"basic_auth", "basic_auth",
"basic_auth_tx", "basic_auth_tx",
"bitcoin_auth", "bitcoin_auth",
@@ -1300,6 +1302,10 @@ failing_contracts() ->
<<?Pos(3,9) <<?Pos(3,9)
"The name of the compile-time constant cannot have pattern matching">> "The name of the compile-time constant cannot have pattern matching">>
]) ])
, ?TYPE_ERROR(too_many_tvars,
[<<?Pos(2,3)
"Too many type variables (max 256) in definition of `too_many`">>
])
]. ].
validation_test_() -> validation_test_() ->
@@ -1339,7 +1345,7 @@ validation_fails() ->
validate(Contract1, Contract2) -> validate(Contract1, Contract2) ->
case compile(Contract1) of case compile(Contract1) of
ByteCode = #{ fate_code := FCode } -> ByteCode = #{ fate_code := FCode } ->
FCode1 = aeb_fate_code:serialize(aeb_fate_code:strip_init_function(FCode)), FCode1 = gmb_fate_code:serialize(gmb_fate_code:strip_init_function(FCode)),
Source = aeso_test_utils:read_contract(Contract2), Source = aeso_test_utils:read_contract(Contract2),
aeso_compiler:validate_byte_code( aeso_compiler:validate_byte_code(
ByteCode#{ byte_code := FCode1 }, Source, ByteCode#{ byte_code := FCode1 }, Source,
@@ -1347,7 +1353,9 @@ validate(Contract1, Contract2) ->
true -> [debug_mode]; true -> [debug_mode];
false -> [] false -> []
end ++ end ++
[{include, {file_system, [aeso_test_utils:contract_path()]}}]); [ {src_file, lists:concat([Contract2, ".aes"])}
, {include, {file_system, [aeso_test_utils:contract_path()]}}
]);
Error -> print_and_throw(Error) Error -> print_and_throw(Error)
end. end.
+40
View File
@@ -0,0 +1,40 @@
-module(aeso_encode_decode_tests).
-compile([export_all, nowarn_export_all]).
-include_lib("eunit/include/eunit.hrl").
-define(EMPTY, "contract C =\n entrypoint f() = true").
encode_decode_test_() ->
[ {lists:flatten(io_lib:format("Testing encode-decode roundtrip for ~p : ~p", [Value, {EType, DType}])),
fun() ->
{ok, SerRes} = aeso_compiler:encode_value(?EMPTY, EType, Value, []),
{ok, Expr} = aeso_compiler:decode_value(?EMPTY, DType, SerRes, []),
Value2 = prettypr:format(aeso_pretty:expr(Expr)),
?assertEqual(Value, Value2)
end} || {Value, EType, DType} <- test_data() ].
test_data() ->
lists:map(fun({V, T}) -> {V, T, T};
({V, T1, T2}) -> {V, T1, T2} end, data()).
data() ->
[ {"42", "int"}
, {"- 42", "int"}
, {"true", "bool"}
, {"ak_Ez6MyeTMm17YnTnDdHTSrzMEBKmy7Uz2sXu347bTDPgVH2ifJ", "address"}
, {"ct_Ez6MyeTMm17YnTnDdHTSrzMEBKmy7Uz2sXu347bTDPgVH2ifJ", "C"}
, {"Some(42)", "option(int)"}
, {"None", "option(int)"}
, {"(true, 42)", "bool * int"}
, {"{[1] = true, [3] = false}", "map(int, bool)"}
, {"()", "unit"}
, {"#000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f", "hash"}
, {"#000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f", "bytes(32)"}
, {"sg_MhibzTP1wWzGCTjtPFr1TiPqRJrrJqw7auvEuF5i3FdoALWqXLBDY6xxRRNUSPHK3EQTnTzF12EyspkxrSMxVHKsZeSMj", "signature"}
, {"sg_MhibzTP1wWzGCTjtPFr1TiPqRJrrJqw7auvEuF5i3FdoALWqXLBDY6xxRRNUSPHK3EQTnTzF12EyspkxrSMxVHKsZeSMj", "bytes(64)", "signature"}
, {"#0102030405060708090a0b0c0d0e0f101718192021222324252627282930313233343536373839401a1b1c1d1e1f202122232425262728293031323334353637", "bytes(64)"}
, {"#0102030405060708090a0b0c0d0e0f101718192021222324252627282930313233343536373839401a1b1c1d1e1f202122232425262728293031323334353637", "signature", "bytes(64)"}
].
+1 -1
View File
@@ -11,7 +11,7 @@
-export([read_contract/1, contract_path/0]). -export([read_contract/1, contract_path/0]).
contract_path() -> contract_path() ->
filename:join(code:lib_dir(aesophia, test), "contracts"). filename:join(code:lib_dir(sophia, test), "contracts").
%% Read a contract file from the test/contracts directory. %% Read a contract file from the test/contracts directory.
-spec read_contract(string() | atom()) -> string(). -spec read_contract(string() | atom()) -> string().
+2 -1
View File
@@ -11,4 +11,5 @@ contract C =
let i = Int.mulmod(a, b, h) let i = Int.mulmod(a, b, h)
let j = Crypto.poseidon(i, a) let j = Crypto.poseidon(i, a)
let k : bytes(32) = Address.to_bytes(Call.origin) let k : bytes(32) = Address.to_bytes(Call.origin)
(a bor b band c bxor a << bnot b >> a, k) let l = sg_MhibzTP1wWzGCTjtPFr1TiPqRJrrJqw7auvEuF5i3FdoALWqXLBDY6xxRRNUSPHK3EQTnTzF12EyspkxrSMxVHKsZeSMj
(a bor b band c bxor a << bnot b >> a, k, l)
+4
View File
@@ -0,0 +1,4 @@
include "../dir2/baz.aes"
namespace D =
function g() = E.h()
+3
View File
@@ -0,0 +1,3 @@
namespace E =
function h() = 42
+4
View File
@@ -20,6 +20,8 @@ contract FunctionArguments =
entrypoint read(a : answer(int)) = entrypoint read(a : answer(int)) =
a.result a.result
entrypoint any_bytes(b : bytes()) = b
entrypoint sjutton(b : bytes(17)) = entrypoint sjutton(b : bytes(17)) =
b b
@@ -57,3 +59,5 @@ contract FunctionArguments =
entrypoint chain_ga_meta_tx(tx : Chain.ga_meta_tx) = true entrypoint chain_ga_meta_tx(tx : Chain.ga_meta_tx) = true
entrypoint chain_paying_for_tx(tx : Chain.paying_for_tx) = true entrypoint chain_paying_for_tx(tx : Chain.paying_for_tx) = true
entrypoint chain_base_tx(tx : Chain.base_tx) = true entrypoint chain_base_tx(tx : Chain.base_tx) = true
entrypoint sig(sg : signature) = true
+3
View File
@@ -0,0 +1,3 @@
include "./dir1/bar.aes"
contract C =
entrypoint f() = D.g()
+60
View File
@@ -0,0 +1,60 @@
contract C =
entrypoint too_many(
(_, _, _, _, _, _, _, _, _, _),
(_, _, _, _, _, _, _, _, _, _),
(_, _, _, _, _, _, _, _, _, _),
(_, _, _, _, _, _, _, _, _, _),
(_, _, _, _, _, _, _, _, _, _),
(_, _, _, _, _, _, _, _, _, _),
(_, _, _, _, _, _, _, _, _, _),
(_, _, _, _, _, _, _, _, _, _),
(_, _, _, _, _, _, _, _, _, _),
(_, _, _, _, _, _, _, _, _, _),
(_, _, _, _, _, _, _, _, _, _),
(_, _, _, _, _, _, _, _, _, _),
(_, _, _, _, _, _, _, _, _, _),
(_, _, _, _, _, _, _, _, _, _),
(_, _, _, _, _, _, _, _, _, _),
(_, _, _, _, _, _, _, _, _, _),
(_, _, _, _, _, _, _, _, _, _),
(_, _, _, _, _, _, _, _, _, _),
(_, _, _, _, _, _, _, _, _, _),
(_, _, _, _, _, _, _, _, _, _),
(_, _, _, _, _, _, _, _, _, _),
(_, _, _, _, _, _, _, _, _, _),
(_, _, _, _, _, _, _, _, _, _),
(_, _, _, _, _, _, _, _, _, _),
(_, _, _, _, _, _, _, _, _, _),
(_, _, _, _, _, _, _, _, _, _)) = 0
entrypoint not_too_many(
(_, _, _, _, _, _, _, _, _, _),
(_, _, _, _, _, _, _, _, _, _),
(_, _, _, _, _, _, _, _, _, _),
(_, _, _, _, _, _, _, _, _, _),
(_, _, _, _, _, _, _, _, _, _),
(_, _, _, _, _, _, _, _, _, _),
(_, _, _, _, _, _, _, _, _, _),
(_, _, _, _, _, _, _, _, _, _),
(_, _, _, _, _, _, _, _, _, _),
(_, _, _, _, _, _, _, _, _, _),
(_, _, _, _, _, _, _, _, _, _),
(_, _, _, _, _, _, _, _, _, _),
(_, _, _, _, _, _, _, _, _, _),
(_, _, _, _, _, _, _, _, _, _),
(_, _, _, _, _, _, _, _, _, _),
(_, _, _, _, _, _, _, _, _, _),
(_, _, _, _, _, _, _, _, _, _),
(_, _, _, _, _, _, _, _, _, _),
(_, _, _, _, _, _, _, _, _, _),
(_, _, _, _, _, _, _, _, _, _),
(_, _, _, _, _, _, _, _, _, _),
(_, _, _, _, _, _, _, _, _, _),
(_, _, _, _, _, _, _, _, _, _),
(_, _, _, _, _, _, _, _, _, _),
(_, _, _, _, _, _, _, _, _, _),
(_, _, _, _, _, _)) = 0
@@ -0,0 +1,5 @@
contract Test =
type option_int = option(int)
record option_point = {x: int, y: option_int}
entrypoint test_option_record(a: option_point) = a