Renaming and preparing to remove oracles (#985)
All checks were successful
Sophia Tests / tests (push) Successful in 48m54s

A few references to oracles still remain, but they have been removed as a feature, at least.

Reviewed-on: #985
Reviewed-by: Ulf Wiger <ulfwiger@qpq.swiss>
Co-authored-by: Craig Everett <zxq9@zxq9.com>
Co-committed-by: Craig Everett <zxq9@zxq9.com>
This commit is contained in:
Craig Everett 2025-03-13 12:53:01 +09:00 committed by Craig Everett
parent 927cd42592
commit dbab49936d
70 changed files with 927 additions and 1633 deletions

View File

@ -1,53 +0,0 @@
version: 2.1
executors:
aebuilder:
docker:
- image: aeternity/builder:bionic-otp24
user: builder
working_directory: ~/aesophia
jobs:
verify_rebar_lock:
executor: aebuilder
steps:
- checkout
- run:
name: Ensure lock file is up-to-date
command: |
./rebar3 upgrade
git diff --quiet -- rebar.lock || (echo "rebar.lock is not up-to-date" && exit 1)
build:
executor: aebuilder
steps:
- checkout
- restore_cache:
keys:
- dialyzer-cache-v2-{{ .Branch }}-{{ .Revision }}
- dialyzer-cache-v2-{{ .Branch }}-
- dialyzer-cache-v2-
- run:
name: Build
command: ./rebar3 compile
- run:
name: Static Analysis
command: ./rebar3 dialyzer
- run:
name: Eunit
command: ./rebar3 eunit
- run:
name: Common Tests
command: ./rebar3 ct
- save_cache:
key: dialyzer-cache-v2-{{ .Branch }}-{{ .Revision }}
paths:
- _build/default/rebar3_20.3.8_plt
- store_artifacts:
path: _build/test/logs
workflows:
version: 2
build_test:
jobs:
- build
- verify_rebar_lock

View File

@ -0,0 +1,14 @@
name: Sophia Tests
run-name: ${{ gitea.actor }} testing Sophia
on: [push, workflow_dispatch]
jobs:
tests:
runs-on: linux_amd64
steps:
- name: Check out repository code
uses: actions/checkout@v4
- name: test
run: |
. /home/act_runner/.erts/27.2.1/activate
./rebar3 eunit

View File

@ -1,21 +0,0 @@
name: Publish development docs
on:
push:
branches: ['master']
jobs:
main:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
with:
fetch-depth: 0
- uses: actions/setup-python@v2
with:
python-version: 3.8
- run: pip3 install -r .github/workflows/requirements.txt -U
- run: git config --global user.email "github-action@users.noreply.github.com"
- run: git config --global user.name "GitHub Action"
- run: |
cd .docssite
mike deploy --push master

View File

@ -1,22 +0,0 @@
name: Publish release docs
on:
release:
types: [released]
jobs:
main:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
with:
fetch-depth: 0
- uses: actions/setup-python@v2
with:
python-version: 3.8
- run: pip3 install -r .github/workflows/requirements.txt -U
- run: git config --global user.email "github-action@users.noreply.github.com"
- run: git config --global user.name "GitHub Action"
- run: echo "RELEASE_VERSION=${GITHUB_REF:10}" >> $GITHUB_ENV
- run: |
cd .docssite
mike deploy --push --update-aliases $RELEASE_VERSION latest

View File

@ -1,5 +0,0 @@
mkdocs==1.4.2
mkdocs-simple-hooks==0.1.5
mkdocs-material==9.0.9
mike==1.1.2
pygments==2.17.2

2
.gitignore vendored
View File

@ -18,7 +18,7 @@ _build
rebar3.crashdump rebar3.crashdump
*.erl~ *.erl~
*.aes~ *.aes~
aesophia sophia
.qcci .qcci
current_counterexample.eqc current_counterexample.eqc
test/contracts/test.aes test/contracts/test.aes

View File

@ -11,6 +11,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Changed ### Changed
### Removed ### Removed
## [9.0.0]
### Changed
- stdlib dir discovery now works by finding a relative path from the loaded Sophia installation
###Removed
- Oracles
## [8.0.1] ## [8.0.1]
### Changed ### Changed
- Upgrade aebytecode to v3.4.1 to fix C warnings - Upgrade aebytecode to v3.4.1 to fix C warnings

1
Emakefile Normal file
View File

@ -0,0 +1 @@
{"src/*", [debug_info, {i, "include/"}, {outdir, "ebin/"}]}.

View File

@ -1,5 +1,6 @@
ISC License ISC License
Copyright (c) 2025, QPQ AG
Copyright (c) 2017, æternity developers Copyright (c) 2017, æternity developers
Permission to use, copy, modify, and/or distribute this software for any Permission to use, copy, modify, and/or distribute this software for any

View File

@ -1,11 +1,11 @@
# aesophia # The Sophia smart contract language
This is the __sophia__ compiler for the æternity system which compiles contracts written in __sophia__ to [FATE](https://github.com/aeternity/protocol/blob/master/contracts/fate.md) instructions. This is the __sophia__ compiler which compiles contracts written in __sophia__ to [FATE](https://git.qpq.swiss/QPQ-AG/protocol/src/branch/master/contracts/fate.md) instructions.
The compiler is currently being used three places The compiler is currently being used three places
- [The command line compiler](https://github.com/aeternity/aesophia_cli) - [The command line compiler](https://git.qpq.swiss/QPQ-AG/sophia_cli)
- [The HTTP compiler](https://github.com/aeternity/aesophia_http) - [Desktop wallet](https://git.qpq.swiss/QPQ-AG/GajuDesk)
- In [æternity node](https://github.com/aeternity/aeternity) tests - In the [Gajumaru core node](https://git.qpq.swiss/QPQ-AG/gajumaru) tests
## Documentation ## Documentation
@ -16,7 +16,7 @@ The compiler is currently being used three places
* [Contract examples](docs/sophia_examples.md) * [Contract examples](docs/sophia_examples.md)
* [Contributing](CONTRIBUTING.md) * [Contributing](CONTRIBUTING.md)
Additionally you can check out the [contracts section](https://github.com/aeternity/protocol/blob/master/contracts/contracts.md) of the æternity blockchain specification. Additionally you can check out the [contracts section](https://git.qpq.swiss/QPQ-AG/protocol/src/branch/master/contracts) of the Gajumaru blockchain specification.
## Versioning ## Versioning
@ -31,5 +31,5 @@ Versioning should follow the [semantic versioning](https://semver.org/spec/v2.0.
The basic modules for interfacing the compiler: The basic modules for interfacing the compiler:
* [aeso_compiler: the Sophia compiler](docs/aeso_compiler.md) * [so_compiler: the Sophia compiler](docs/so_compiler.md)
* [aeso_aci: the ACI interface](docs/aeso_aci.md) * [so_aci: the ACI interface](docs/so_aci.md)

View File

@ -1,12 +1,9 @@
# Introduction # Introduction
Sophia is a functional language designed for smart contract development. It is strongly typed and has Sophia is a functional language designed for smart contract development.
restricted mutable state. It is strongly typed and has restricted mutable state.
Sophia is customized for smart contracts, which can be published Sophia is customized for smart contracts, which can be published to a blockchain.
to a blockchain. Thus some features of conventional Thus some features of conventional languages (such as floating point arithmetic) are not present in Sophia,
languages, such as floating point arithmetic, are not present in Sophia, and and some blockchain specific primitives, constructions and types have been added.
some [æternity blockchain](https://aeternity.com) specific primitives, constructions and types have been added.
!!! Note The file extension used for Sophia source files is ".aes", reflecting Sophia's Aeternity heritage.
- For rapid prototyping of smart contracts check out [AEstudio](https://studio.aepps.com/)!
- For playing around and diving deeper into the language itself check out the [REPL](https://repl.aeternity.io/)!

View File

@ -1,8 +1,8 @@
# aeso_aci # so_aci
### Module ### Module
### aeso_aci ### so_aci
The ACI interface encoder and decoder. The ACI interface encoder and decoder.
@ -123,7 +123,7 @@ be included inside another contract.
``` erlang ``` erlang
1> {ok,Contract} = file:read_file("aci_test.aes"). 1> {ok,Contract} = file:read_file("aci_test.aes").
{ok,<<"contract Answers =\n record state = { a : answers }\n type answers() = map(string, int)\n\n stateful function"...>>} {ok,<<"contract Answers =\n record state = { a : answers }\n type answers() = map(string, int)\n\n stateful function"...>>}
2> {ok,JsonACI} = aeso_aci:contract_interface(json, Contract). 2> {ok,JsonACI} = so_aci:contract_interface(json, Contract).
{ok,[#{contract => {ok,[#{contract =>
#{functions => #{functions =>
[#{arguments => [],name => <<"init">>, [#{arguments => [],name => <<"init">>,
@ -144,7 +144,7 @@ be included inside another contract.
vars => []}]}}]} vars => []}]}}]}
3> file:write_file("aci_test.aci", jsx:encode(JsonACI)). 3> file:write_file("aci_test.aci", jsx:encode(JsonACI)).
ok ok
4> {ok,InterfaceStub} = aeso_aci:render_aci_json(JsonACI). 4> {ok,InterfaceStub} = so_aci:render_aci_json(JsonACI).
{ok,<<"contract Answers =\n record state = {a : Answers.answers}\n type answers = map(string, int)\n function init "...>>} {ok,<<"contract Answers =\n record state = {a : Answers.answers}\n type answers = map(string, int)\n function init "...>>}
5> file:write_file("aci_test.include", InterfaceStub). 5> file:write_file("aci_test.include", InterfaceStub).
ok ok

View File

@ -1,8 +1,8 @@
# aeso_compiler # so_compiler
### Module ### Module
### aeso_compiler ### so_compiler
The Sophia compiler The Sophia compiler

View File

@ -65,9 +65,3 @@ contract FundMe =
amount = state.contributions[to]}) amount = state.contributions[to]})
put(state{ contributions @ c = Map.delete(to, c) }) put(state{ contributions @ c = Map.delete(to, c) })
``` ```
## Repositories
This is a list with repositories that include smart contracts written in Sophia:
- [aepp-sophia-examples](https://github.com/aeternity/aepp-sophia-examples)
- A repository that contains lots of different examples. The functionality of these examples is - to some extent - also covered by tests written in JavaScript.

View File

@ -274,12 +274,6 @@ counterpart in `Args1`.
- A map type `map(A1, A2)` is a subtype of `map(B1, B2)` if `A1` is a subtype - A map type `map(A1, A2)` is a subtype of `map(B1, B2)` if `A1` is a subtype
of `B1`, and `A2` is a subtype of `B2`. of `B1`, and `A2` is a subtype of `B2`.
- An oracle type `oracle(A1, A2)` is a subtype of `oracle(B1, B2)` if `B1` is
a subtype of `A1`, and `A2` is a subtype of `B2`.
- An oracle_query type `oracle_query(A1, A2)` is a subtype of `oracle_query(B1, B2)`
if `A1` is a subtype of `B1`, and `A2` is a subtype of `B2`.
- A user-defined datatype `t(Args1)` is a subtype of `t(Args2)` - A user-defined datatype `t(Args1)` is a subtype of `t(Args2)`
- When a user-defined type `t('a)` is covariant in `'a`, then `t(A)` is a - When a user-defined type `t('a)` is covariant in `'a`, then `t(A)` is a
@ -340,10 +334,6 @@ Without the `stateful` annotation the compiler does not allow the call to
* Use a stateful primitive function. These are * Use a stateful primitive function. These are
- `put` - `put`
- `Chain.spend` - `Chain.spend`
- `Oracle.register`
- `Oracle.query`
- `Oracle.respond`
- `Oracle.extend`
- `AENS.preclaim` - `AENS.preclaim`
- `AENS.claim` - `AENS.claim`
- `AENS.transfer` - `AENS.transfer`
@ -556,8 +546,6 @@ Sophia has the following types:
| hash | A 32-byte hash - equivalent to `bytes(32)` | | | hash | A 32-byte hash - equivalent to `bytes(32)` | |
| signature | A signature - equivalent to `bytes(64)` | | | signature | A signature - equivalent to `bytes(64)` | |
| Chain.ttl | Time-to-live (fixed height or relative to current block) | ```FixedTTL(1050)``` ```RelativeTTL(50)``` | | Chain.ttl | Time-to-live (fixed height or relative to current block) | ```FixedTTL(1050)``` ```RelativeTTL(50)``` |
| oracle('a, 'b) | And oracle answering questions of type 'a with answers of type 'b | ```Oracle.register(acct, qfee, ttl)``` |
| oracle_query('a, 'b) | A specific oracle query | ```Oracle.query(o, q, qfee, qttl, rttl)``` |
| contract | A user defined, typed, contract address | ```function call_remote(r : RemoteContract) = r.fun()``` | | contract | A user defined, typed, contract address | ```function call_remote(r : RemoteContract) = r.fun()``` |
## Literals ## Literals
@ -580,8 +568,6 @@ Sophia has the following types:
| hash | `#000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f` | | hash | `#000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f` |
| signature | `sg_MhibzTP1wWzGCTjtPFr1TiPqRJrrJqw7auvEuF5i3FdoALWqXLBDY6xxRRNUSPHK3EQTnTzF12EyspkxrSMxVHKsZeSMj`, `#000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f` | | signature | `sg_MhibzTP1wWzGCTjtPFr1TiPqRJrrJqw7auvEuF5i3FdoALWqXLBDY6xxRRNUSPHK3EQTnTzF12EyspkxrSMxVHKsZeSMj`, `#000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f` |
| Chain.ttl | `FixedTTL(1050)`, `RelativeTTL(50)` | | Chain.ttl | `FixedTTL(1050)`, `RelativeTTL(50)` |
| oracle('a, 'b) | `ok_2YNyxd6TRJPNrTcEDCe9ra59SVUdp9FR9qWC5msKZWYD9bP9z5` |
| oracle_query('a, 'b) | `oq_2oRvyowJuJnEkxy58Ckkw77XfWJrmRgmGaLzhdqb67SKEL1gPY` |
| contract | `ct_Ez6MyeTMm17YnTnDdHTSrzMEBKmy7Uz2sXu347bTDPgVH2ifJ` | | contract | `ct_Ez6MyeTMm17YnTnDdHTSrzMEBKmy7Uz2sXu347bTDPgVH2ifJ` |
## Hole expression ## Hole expression
@ -891,77 +877,9 @@ wrapping a transaction.) The transaction and the transaction hash is available i
`Auth.tx` and `Auth.tx_hash` respectively, they are *only* available during authentication if invoked by a `Auth.tx` and `Auth.tx_hash` respectively, they are *only* available during authentication if invoked by a
normal contract call they return `None`. normal contract call they return `None`.
## Oracle interface
You can attach an oracle to the current contract and you can interact with oracles
through the Oracle interface.
For a full description of how Oracle works see
[Oracles](https://github.com/aeternity/protocol/blob/master/oracles/oracles.md#oracles).
For a functionality documentation refer to the [standard library](sophia_stdlib.md#oracle).
### Example
Example for an oracle answering questions of type `string` with answers of type `int`:
```sophia
contract Oracles =
stateful entrypoint registerOracle(acct : address,
sign : signature, // Signed network id + oracle address + contract address
qfee : int,
ttl : Chain.ttl) : oracle(string, int) =
Oracle.register(acct, signature = sign, qfee, ttl)
entrypoint queryFee(o : oracle(string, int)) : int =
Oracle.query_fee(o)
payable stateful entrypoint createQuery(o : oracle_query(string, int),
q : string,
qfee : int,
qttl : Chain.ttl,
rttl : int) : oracle_query(string, int) =
require(qfee =< Call.value, "insufficient value for qfee")
Oracle.query(o, q, qfee, qttl, RelativeTTL(rttl))
stateful entrypoint extendOracle(o : oracle(string, int),
ttl : Chain.ttl) : unit =
Oracle.extend(o, ttl)
stateful entrypoint signExtendOracle(o : oracle(string, int),
sign : signature, // Signed network id + oracle address + contract address
ttl : Chain.ttl) : unit =
Oracle.extend(o, signature = sign, ttl)
stateful entrypoint respond(o : oracle(string, int),
q : oracle_query(string, int),
sign : signature, // Signed network id + oracle query id + contract address
r : int) =
Oracle.respond(o, q, signature = sign, r)
entrypoint getQuestion(o : oracle(string, int),
q : oracle_query(string, int)) : string =
Oracle.get_question(o, q)
entrypoint hasAnswer(o : oracle(string, int),
q : oracle_query(string, int)) =
switch(Oracle.get_answer(o, q))
None => false
Some(_) => true
entrypoint getAnswer(o : oracle(string, int),
q : oracle_query(string, int)) : option(int) =
Oracle.get_answer(o, q)
```
### Sanity checks
When an Oracle literal is passed to a contract, no deep checks are performed.
For extra safety [Oracle.check](sophia_stdlib.md#check) and [Oracle.check_query](sophia_stdlib.md#check_query)
functions are provided.
## AENS interface ## AENS interface
Contracts can interact with the [æternity naming Contracts can interact with the [æternity naming system](https://git.qpq.swiss/QPQ-AG/protocol/src/branch/master/AENS.md). For this
system](https://github.com/aeternity/protocol/blob/master/AENS.md). For this
purpose the [AENS](sophia_stdlib.md#aens) and later the purpose the [AENS](sophia_stdlib.md#aens) and later the
[AENSv2](sophia_stdlib.md#aensv2) library was exposed. [AENSv2](sophia_stdlib.md#aensv2) library was exposed.
@ -1009,10 +927,9 @@ automatically removed so they will not appear in the pointers map.
## Events ## Events
Sophia contracts log structured messages to an event log in the resulting Sophia contracts log structured messages to an event log in the resulting blockchain transaction.
blockchain transaction. The event log is quite similar to [Events in The event log is quite similar to [Events in Solidity](https://solidity.readthedocs.io/en/v0.4.24/contracts.html#events).
Solidity](https://solidity.readthedocs.io/en/v0.4.24/contracts.html#events). Events are further discussed in the [protocol](https://git.qpq.swiss/QPQ-AG/protocol/src/branch/master/contracts/events.md).
Events are further discussed in the [protocol](https://github.com/aeternity/protocol/blob/master/contracts/events.md).
To use events a contract must declare a datatype `event`, and events are then To use events a contract must declare a datatype `event`, and events are then
@ -1032,8 +949,6 @@ field is indexed if it fits in a 32-byte word, i.e.
- `int` - `int`
- `bits` - `bits`
- `address` - `address`
- `oracle(_, _)`
- `oracle_query(_, _)`
- contract types - contract types
- `bytes(n)` for `n` ≤ 32, in particular `hash` - `bytes(n)` for `n` ≤ 32, in particular `hash`
@ -1113,34 +1028,15 @@ however is in the gas consumption — while `abort` returns unused gas, a call t
## Delegation signature ## Delegation signature
Some chain operations (`Oracle.<operation>` and `AENSv2.<operation>`) have an Some chain operations (`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. would like to allow a contract to act on it's behalf.
### From Ceres There are five different delegation signatures:
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 wildcard - the user signs: `owner account + contract`
- `AENS_PRECLAIM` - 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` - `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 See [Serialized signature data](https://git.qpq.swiss/QPQ-AG/protocol/src/branch/master/serializations.md)
data](https://github.com/aeternity/protocol/blob/master/contracts/fate.md#from-ceres-serialized-signature-data)
for the exact structure used. 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`

View File

@ -25,7 +25,6 @@ The out-of-the-box namespaces are:
- [Crypto](#crypto) - [Crypto](#crypto)
- [Int](#int) - [Int](#int)
- [Map](#map) - [Map](#map)
- [Oracle](#oracle)
The following ones need to be included as regular files with `.aes` suffix, for example The following ones need to be included as regular files with `.aes` suffix, for example
``` ```
@ -72,14 +71,6 @@ Address.is_contract(a : address) : bool
Is the address a contract Is the address a contract
#### is_oracle
```
Address.is_oracle(a : address) : bool
```
Is the address a registered oracle
#### is_payable #### is_payable
``` ```
Address.is_payable(a : address) : bool Address.is_payable(a : address) : bool
@ -99,7 +90,7 @@ Cast address to contract type C (where `C` is a contract)
### AENS ### AENS
The old AENS namespace, kept in the compiler to be able to interact with The old AENS namespace, kept in the compiler to be able to interact with
contracts from before Ceres, compiled using aesophia compiler version 7.x and contracts from before Ceres, compiled using sophia compiler version 7.x and
earlier. Used in [AENSCompat](#aenscompat) when converting between old and new earlier. Used in [AENSCompat](#aenscompat) when converting between old and new
pointers. pointers.
@ -114,8 +105,9 @@ datatype name = Name(address, Chain.ttl, map(string, AENS.pointee))
##### pointee ##### pointee
``` ```
datatype pointee = AccountPt(address) | OraclePt(address) datatype pointee = AccountPt(address)
| ContractPt(address) | ChannelPt(address) | ContractPt(address)
| ChannelPt(address)
``` ```
### AENSv2 ### AENSv2
@ -127,7 +119,7 @@ naming system (AENS). If `owner` is equal to `Contract.address` the signature
`signature` is ignored, and can be left out since it is a named argument. `signature` is ignored, and can be left out since it is a named argument.
Otherwise we need a signature to prove that we are allowed to do AENS Otherwise we need a signature to prove that we are allowed to do AENS
operations on behalf of `owner`. The [signature is tied to a network operations on behalf of `owner`. The [signature is tied to a network
id](https://github.com/aeternity/protocol/blob/iris/consensus/consensus.md#transaction-signature), id](https://git.qpq.swiss/QPQ-AG/protocol/src/branch/master/consensus/README.md#transaction-signature),
i.e. the signature material should be prefixed by the network id. i.e. the signature material should be prefixed by the network id.
#### Types #### Types
@ -141,8 +133,10 @@ datatype name = Name(address, Chain.ttl, map(string, AENSv2.pointee))
##### pointee ##### pointee
``` ```
datatype pointee = AccountPt(address) | OraclePt(address) datatype pointee = AccountPt(address)
| ContractPt(address) | ChannelPt(address) | DataPt(bytes()) | ContractPt(address)
| ChannelPt(address)
| DataPt(bytes())
``` ```
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.
@ -185,8 +179,7 @@ The [signature](./sophia_features.md#delegation-signature) should be a
serialized structure containing `network id`, `owner address`, and serialized structure containing `network id`, `owner address`, and
`Contract.address`. `Contract.address`.
From Ceres (i.e. FATE VM version 3) the The [signature](./sophia_features.md#delegation-signature) can also be generic
[signature](./sophia_features.md#delegation-signature) can also be generic
(allowing _all_, existing and future, names to be delegated with one (allowing _all_, existing and future, names to be delegated with one
signature), i.e. containing `network id`, `owner address`, `Contract.address`. signature), i.e. containing `network id`, `owner address`, `Contract.address`.
@ -287,7 +280,6 @@ namespace Chain =
datatype ga_meta_tx = GAMetaTx(address, int) datatype ga_meta_tx = GAMetaTx(address, int)
datatype paying_for_tx = PayingForTx(address, int) datatype paying_for_tx = PayingForTx(address, int)
datatype base_tx = SpendTx(address, int, string) datatype base_tx = SpendTx(address, int, string)
| OracleRegisterTx | OracleQueryTx | OracleResponseTx | OracleExtendTx
| NamePreclaimTx | NameClaimTx(hash) | NameUpdateTx(string) | NamePreclaimTx | NameClaimTx(hash) | NameUpdateTx(string)
| NameRevokeTx(hash) | NameTransferTx(address, string) | NameRevokeTx(hash) | NameTransferTx(address, string)
| ChannelCreateTx(address) | ChannelDepositTx(address, int) | ChannelWithdrawTx(address, int) | | ChannelCreateTx(address) | ChannelDepositTx(address, int) | ChannelWithdrawTx(address, int) |
@ -305,7 +297,7 @@ Auth.tx_hash : option(hash)
Gets the transaction hash during authentication. Note: `Auth.tx_hash` Gets the transaction hash during authentication. Note: `Auth.tx_hash`
computation differs between protocol versions (changed in Ceres!), see computation differs between protocol versions (changed in Ceres!), see
[aeserialisation](https://github.com/aeternity/protocol/blob/master/serializations.md) [aeserialisation](https://git.qpq.swiss/QPQ-AG/protocol/src/branch/master/serializations.md)
specification for details. specification for details.
@ -537,7 +529,6 @@ datatype paying_for_tx = PayingForTx(address, int)
##### base_tx ##### base_tx
``` ```
datatype base_tx = SpendTx(address, int, string) datatype base_tx = SpendTx(address, int, string)
| OracleRegisterTx | OracleQueryTx | OracleResponseTx | OracleExtendTx
| NamePreclaimTx | NameClaimTx(hash) | NameUpdateTx(string) | NamePreclaimTx | NameClaimTx(hash) | NameUpdateTx(string)
| NameRevokeTx(hash) | NameTransferTx(address, string) | NameRevokeTx(hash) | NameTransferTx(address, string)
| ChannelCreateTx(address) | ChannelDepositTx(address, int) | ChannelWithdrawTx(address, int) | | ChannelCreateTx(address) | ChannelDepositTx(address, int) | ChannelWithdrawTx(address, int) |
@ -944,118 +935,6 @@ Returns a list containing pairs of keys and their respective elements.
Turns a list of pairs of form `(key, value)` into a map Turns a list of pairs of form `(key, value)` into a map
### Oracle
#### register
```
Oracle.register(<signature : bytes(64)>, acct : address, qfee : int, ttl : Chain.ttl) : oracle('a, '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 [signature](./sophia_features.md#delegation-signature) should be a
serialized structure containing `network id`, `account address`, and
`contract address`. Using the private key of `account address` for signing.
Proving you have the private key of the oracle to be. If the address is the same
as the contract `sign` is ignored and can be left out entirely.
* The `qfee` is the minimum query fee to be paid by a user when asking a question of the oracle.
* The `ttl` is the Time To Live for the oracle in key blocks, either relative to the current
key block height (`RelativeTTL(delta)`) or a fixed key block height (`FixedTTL(height)`).
* The type `'a` is the type of the question to ask.
* The type `'b` is the type of the oracle answers.
Examples:
```
Oracle.register(addr0, 25, RelativeTTL(400))
Oracle.register(addr1, 25, RelativeTTL(500), signature = sign1)
```
#### get\_question
```
Oracle.get_question(o : oracle('a, 'b), q : oracle_query('a, 'b)) : 'a
```
Checks what was the question of query `q` on oracle `o`
#### respond
```
Oracle.respond(<signature : bytes(64)>, o : oracle('a, 'b), q : oracle_query('a, 'b), 'b) : unit
```
Responds to the question `q` on `o`. Unless the contract address is the same
as the oracle address the `signature` (which is an optional, named argument)
needs to be provided. Proving that we have the private key of the oracle by
[signing](./sophia_features.md#delegation-signature) should be a serialized
structure containing `network id`, `oracle query id`, and `contract address`.
#### extend
```
Oracle.extend(<signature : bytes(64)>, o : oracle('a, 'b), ttl : Chain.ttl) : unit
```
Extends TTL of an oracle.
* `singature` is a named argument and thus optional. Must be the same as for `Oracle.register`
* `o` is the oracle being extended
* `ttl` must be `RelativeTTL`. The time to live of `o` will be extended by this value.
#### query\_fee
```
Oracle.query_fee(o : oracle('a, 'b)) : int
```
Returns the query fee of the oracle
#### query
```
Oracle.query(o : oracle('a, 'b), q : 'a, qfee : int, qttl : Chain.ttl, rttl : Chain.ttl) : oracle_query('a, 'b)
```
Asks the oracle a question.
* The `qfee` is the query fee debited to the contract account (`Contract.address`).
* The `qttl` controls the last height at which the oracle can submit a response
and can be either fixed or relative.
* The `rttl` must be relative and controls how long an answer is kept on the chain.
The call fails if the oracle could expire before an answer.
#### get\_answer
```
Oracle.get_answer(o : oracle('a, 'b), q : oracle_query('a, 'b)) : option('b)
```
Checks what is the optional query answer
#### expiry
```
Oracle.expiry(o : oracle('a, 'b)) : int
```
Ask the oracle when it expires. The result is the block height at which it will happen.
#### check
```
Oracle.check(o : oracle('a, 'b)) : bool
```
Returns `true` iff the oracle `o` exists and has correct type
#### check_query
```
Oracle.check_query(o : oracle('a, 'b), q : oracle_query('a, 'b)) : bool
```
It returns `true` iff the oracle query exist and has the expected type.
## Includable namespaces ## Includable namespaces
These need to be explicitly included (with `.aes` suffix) These need to be explicitly included (with `.aes` suffix)
@ -1664,7 +1543,7 @@ point where the error would exceed the `loss` value.
For debugging. If it ever returns false in a code that doesn't call `frac` constructors or For debugging. If it ever returns false in a code that doesn't call `frac` constructors or
accept arbitrary `frac`s from the surface you should report it as a accept arbitrary `frac`s from the surface you should report it as a
[bug](https://github.com/aeternity/aesophia/issues/new) [bug](https://git.qpq.swiss/QPQ-AG/sophia/issues/new)
If you expect getting calls with malformed `frac`s in your contract, you should use If you expect getting calls with malformed `frac`s in your contract, you should use
this function to verify the input. this function to verify the input.

View File

@ -28,8 +28,6 @@ interface main using as for hiding
- `Char` character literal enclosed in `'` with escape character `\` - `Char` character literal enclosed in `'` with escape character `\`
- `AccountAddress` base58-encoded 32 byte account pubkey with `ak_` prefix - `AccountAddress` base58-encoded 32 byte account pubkey with `ak_` prefix
- `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
- `OracleQueryId` base58-encoded 32 byte oracle query id with `oq_` prefix
- `Signature` base58-encoded 64 byte cryptographic signature with `sg_` prefix - `Signature` base58-encoded 64 byte cryptographic signature with `sg_` prefix
Valid string escape codes are Valid string escape codes are
@ -46,7 +44,7 @@ Valid string escape codes are
| `\xHexDigits` | *HexDigits* | | | `\xHexDigits` | *HexDigits* | |
See the [identifier encoding scheme](https://github.com/aeternity/protocol/blob/master/node/api/api_encoding.md) for the See the [identifier encoding scheme](https://git.qpq.swiss/QPQ-AG/protocol/src/branch/master/node/api/api_encoding.md) for the
details on the base58 literals. details on the base58 literals.
## Layout blocks ## Layout blocks
@ -239,7 +237,6 @@ Expr ::= '(' LamArgs ')' '=>' Block(Stmt) // Anonymous function (x) => x +
| Id | Con | QId | QCon // Identifiers x, None, Map.member, AELib.Token | Id | Con | QId | QCon // Identifiers x, None, Map.member, AELib.Token
| 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
| Signature // Signature | Signature // Signature
| '???' // Hole expression 1 + ??? | '???' // Hole expression 1 + ???

View File

@ -1,7 +1,7 @@
-define(LET_P(X, P, Q), aeso_parse_lib:bind(P, fun(X) -> Q end)). -define(LET_P(X, P, Q), so_parse_lib:bind(P, fun(X) -> Q end)).
-define(LAZY_P(P), aeso_parse_lib:lazy(fun() -> P end)). -define(LAZY_P(P), so_parse_lib:lazy(fun() -> P end)).
-define(MEMO_P(P), aeso_parse_lib:lazy(aeso_parse_lib:memoised(fun() -> P end))). -define(MEMO_P(P), so_parse_lib:lazy(so_parse_lib:memoised(fun() -> P end))).
-define(GUARD_P(G, P), -define(GUARD_P(G, P),
case G of case G of
@ -18,7 +18,7 @@
-define(RULE(A, B, C, D, E, F, G, Do), map(fun({_1, _2, _3, _4, _5, _6, _7}) -> Do end, {A, B, C, D, E, F, G} )). -define(RULE(A, B, C, D, E, F, G, Do), map(fun({_1, _2, _3, _4, _5, _6, _7}) -> Do end, {A, B, C, D, E, F, G} )).
-define(RULE(A, B, C, D, E, F, G, H, Do), map(fun({_1, _2, _3, _4, _5, _6, _7, _8}) -> Do end, {A, B, C, D, E, F, G, H})). -define(RULE(A, B, C, D, E, F, G, H, Do), map(fun({_1, _2, _3, _4, _5, _6, _7, _8}) -> Do end, {A, B, C, D, E, F, G, H})).
-import(aeso_parse_lib, -import(so_parse_lib,
[tok/1, tok/2, between/3, many/1, many1/1, sep/2, sep1/2, [tok/1, tok/2, between/3, many/1, many1/1, sep/2, sep1/2,
infixl/1, infixr/1, choice/1, choice/2, return/1, layout/0, infixl/1, infixr/1, choice/1, choice/2, return/1, layout/0,
fail/0, fail/1, fail/2, map/2, infixl/2, infixr/2, infixl1/2, infixr1/2, fail/0, fail/1, fail/2, map/2, infixl/2, infixr/2, infixl1/2, infixr1/2,

View File

@ -2,7 +2,9 @@
{erl_opts, [debug_info]}. {erl_opts, [debug_info]}.
{deps, [ {aebytecode, {git, "https://github.com/aeternity/aebytecode.git", {tag, "v3.4.1"}}} {deps, [ {gmbytecode,
{git, "https://git.qpq.swiss/QPQ-AG/gmbytecode.git",
{ref, "97cea33be8f3a35d26055664da7aa59531ff5537"}}}
, {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,10 +15,11 @@
{base_plt_apps, [erts, kernel, stdlib, crypto, mnesia]} {base_plt_apps, [erts, kernel, stdlib, crypto, mnesia]}
]}. ]}.
{relx, [{release, {aesophia, "8.0.1"}, {relx, [{release, {sophia, "9.0.0"},
[aesophia, aebytecode]}, [sophia, gmbytecode]},
{dev_mode, true}, {dev_mode, true},
{include_erts, false}, {include_erts, false},
{extended_start_script, true}]}. {extended_start_script, true}]}.

View File

@ -1,31 +1,30 @@
{"1.2.0", {"1.2.0",
[{<<"aebytecode">>, [{<<"gmbytecode">>,
{git,"https://github.com/aeternity/aebytecode.git", {git,"https://git.qpq.swiss/QPQ-AG/gmbytecode.git",
{ref,"6bd6f82c70d800950ea1a2c70c364a4181ff5291"}}, {ref, "97cea33be8f3a35d26055664da7aa59531ff5537"}},
0}, 0},
{<<"aeserialization">>, {<<"gmserialization">>,
{git,"https://github.com/aeternity/aeserialization.git", {git,"https://git.qpq.swiss/QPQ-AG/gmserialization.git",
{ref,"b26e6d105424748ba1c27917267b7cff07f37802"}}, {ref,"ac64e01b0f675c1a34c70a827062f381920742db"}},
1}, 1},
{<<"base58">>, {<<"base58">>,
{git,"https://github.com/aeternity/erl-base58.git", {git,"https://git.qpq.swiss/QPQ-AG/erl-base58.git",
{ref,"60a335668a60328a29f9731b67c4a0e9e3d50ab6"}}, {ref,"e6aa62eeae3d4388311401f06e4b939bf4e94b9c"}},
2}, 2},
{<<"eblake2">>,{pkg,<<"eblake2">>,<<"1.0.0">>},0}, {<<"eblake2">>,
{git,"https://git.qpq.swiss/QPQ-AG/eblake2.git",
{ref,"b29d585b8760746142014884007eb8441a3b6a14"}},
0},
{<<"enacl">>, {<<"enacl">>,
{git,"https://github.com/aeternity/enacl.git", {git,"https://git.qpq.swiss/QPQ-AG/enacl.git",
{ref,"4eb7ec70084ba7c87b1af8797c4c4e90c84f95a2"}}, {ref,"4eb7ec70084ba7c87b1af8797c4c4e90c84f95a2"}},
2}, 2},
{<<"getopt">>,{pkg,<<"getopt">>,<<"1.0.1">>},1}, {<<"getopt">>,
{git,"https://git.qpq.swiss/QPQ-AG/getopt.git",
{ref,"dbab6262a2430809430deda9d8650f58f9d80898"}},
1},
{<<"jsx">>, {<<"jsx">>,
{git,"https://github.com/talentdeficit/jsx.git", {git,"https://github.com/talentdeficit/jsx.git",
{ref,"3074d4865b3385a050badf7828ad31490d860df5"}}, {ref,"3074d4865b3385a050badf7828ad31490d860df5"}},
0}]}. 0}]}.
[
{pkg_hash,[
{<<"eblake2">>, <<"EC8AD20E438AAB3F2E8D5D118C366A0754219195F8A0F536587440F8F9BCF2EF">>},
{<<"getopt">>, <<"C73A9FA687B217F2FF79F68A3B637711BB1936E712B521D8CE466B29CBF7808A">>}]},
{pkg_hash_ext,[
{<<"eblake2">>, <<"3C4D300A91845B25D501929A26AC2E6F7157480846FAB2347A4C11AE52E08A99">>},
{<<"getopt">>, <<"53E1AB83B9CEB65C9672D3E7A35B8092E9BDC9B3EE80721471A161C10C59959C">>}]}
].

BIN
rebar3

Binary file not shown.

View File

@ -1,13 +1,14 @@
%%%------------------------------------------------------------------- %%%-------------------------------------------------------------------
%%% @author Robert Virding %%% @author Robert Virding
%%% @copyright (C) 2025, QPQ AG
%%% @copyright (C) 2019, Aeternity Anstalt %%% @copyright (C) 2019, Aeternity Anstalt
%%% @doc %%% @doc
%%% ACI interface %%% ACI interface
%%% @end %%% @end
%%% Created : 12 Jan 2019
%%%------------------------------------------------------------------- %%%-------------------------------------------------------------------
-module(aeso_aci). -module(so_aci).
-vsn("9.0.0").
-export([ file/2 -export([ file/2
, file/3 , file/3
@ -21,7 +22,7 @@
, json_encode_expr/1 , json_encode_expr/1
, json_encode_type/1]). , json_encode_type/1]).
-include("aeso_utils.hrl"). -include("so_utils.hrl").
-type aci_type() :: json | string. -type aci_type() :: json | string.
-type json() :: jsx:json_term(). -type json() :: jsx:json_term().
@ -35,7 +36,7 @@ file(Type, File) ->
file(Type, File, []). file(Type, File, []).
file(Type, File, Options0) -> file(Type, File, Options0) ->
Options = aeso_compiler:add_include_path(File, Options0), Options = so_compiler:add_include_path(File, Options0),
case file:read_file(File) of case file:read_file(File) of
{ok, BinCode} -> {ok, BinCode} ->
do_contract_interface(Type, binary_to_list(BinCode), Options); do_contract_interface(Type, binary_to_list(BinCode), Options);
@ -56,11 +57,11 @@ contract_interface(Type, ContractString, CompilerOpts) ->
render_aci_json(Json) -> render_aci_json(Json) ->
do_render_aci_json(Json). do_render_aci_json(Json).
-spec json_encode_expr(aeso_syntax:expr()) -> json(). -spec json_encode_expr(so_syntax:expr()) -> json().
json_encode_expr(Expr) -> json_encode_expr(Expr) ->
encode_expr(Expr). encode_expr(Expr).
-spec json_encode_type(aeso_syntax:type()) -> json(). -spec json_encode_type(so_syntax:type()) -> json().
json_encode_type(Type) -> json_encode_type(Type) ->
encode_type(Type). encode_type(Type).
@ -69,8 +70,8 @@ do_contract_interface(Type, Contract, Options) when is_binary(Contract) ->
do_contract_interface(Type, binary_to_list(Contract), Options); do_contract_interface(Type, binary_to_list(Contract), Options);
do_contract_interface(Type, ContractString, Options) -> do_contract_interface(Type, ContractString, Options) ->
try try
Ast = aeso_compiler:parse(ContractString, Options), Ast = so_compiler:parse(ContractString, Options),
{TypedAst, _, _} = aeso_ast_infer_types:infer(Ast, [dont_unfold | Options]), {TypedAst, _, _} = so_ast_infer_types:infer(Ast, [dont_unfold | Options]),
from_typed_ast(Type, TypedAst) from_typed_ast(Type, TypedAst)
catch catch
throw:{error, Errors} -> {error, Errors} throw:{error, Errors} -> {error, Errors}
@ -200,7 +201,7 @@ encode_expr({bytes, _, B}) ->
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 -> Lit == signature ->
aeser_api_encoder:encode(Lit, L); gmser_api_encoder:encode(Lit, L);
encode_expr({app, _, {'-', _}, [{int, _, N}]}) -> encode_expr({app, _, {'-', _}, [{int, _, N}]}) ->
encode_expr({int, [], -N}); encode_expr({int, [], -N});
encode_expr({app, _, F, As}) -> encode_expr({app, _, F, As}) ->
@ -361,14 +362,14 @@ is_type(_) -> false.
sort_decls(Ds) -> sort_decls(Ds) ->
Sort = fun (D1, D2) -> Sort = fun (D1, D2) ->
aeso_syntax:get_ann(line, D1, 0) =< so_syntax:get_ann(line, D1, 0) =<
aeso_syntax:get_ann(line, D2, 0) so_syntax:get_ann(line, D2, 0)
end, end,
lists:sort(Sort, Ds). lists:sort(Sort, Ds).
is_entrypoint(Node) -> aeso_syntax:get_ann(entrypoint, Node, false). is_entrypoint(Node) -> so_syntax:get_ann(entrypoint, Node, false).
is_stateful(Node) -> aeso_syntax:get_ann(stateful, Node, false). is_stateful(Node) -> so_syntax:get_ann(stateful, Node, false).
is_payable(Node) -> aeso_syntax:get_ann(payable, Node, false). is_payable(Node) -> so_syntax:get_ann(payable, Node, false).
typedef_name({type_def, _, {id, _, Name}, _, _}) -> Name. typedef_name({type_def, _, {id, _, Name}, _, _}) -> Name.

View File

@ -1,4 +1,5 @@
-module(aeso_ast). -module(so_ast).
-vsn("9.0.0").
-export([int/2, -export([int/2,
line/1, line/1,
@ -17,11 +18,11 @@ line({symbol, Line, _}) -> Line.
symbol_name({symbol, _, Name}) -> Name. symbol_name({symbol, _, Name}) -> Name.
pp(Ast) -> pp(Ast) ->
String = prettypr:format(aeso_pretty:decls(Ast, [])), String = prettypr:format(so_pretty:decls(Ast, [])),
io:format("Ast:\n~s\n", [String]). io:format("Ast:\n~s\n", [String]).
pp_typed(TypedAst) -> pp_typed(TypedAst) ->
%% io:format("Typed tree:\n~p\n",[TypedAst]), %% io:format("Typed tree:\n~p\n",[TypedAst]),
String = prettypr:format(aeso_pretty:decls(TypedAst, [show_generated])), String = prettypr:format(so_pretty:decls(TypedAst, [show_generated])),
io:format("Type ast:\n~s\n",[String]). io:format("Type ast:\n~s\n",[String]).

File diff suppressed because it is too large Load Diff

View File

@ -1,18 +1,18 @@
%%%------------------------------------------------------------------- %%%-------------------------------------------------------------------
%%% @author Ulf Norell %%% @author Ulf Norell
%%% @copyright (C) 2025, QPQ AG
%%% @copyright (C) 2019, Aeternity Anstalt %%% @copyright (C) 2019, Aeternity Anstalt
%%% @doc %%% @doc
%%% Compiler from Aeterinty Sophia language to Fate intermediate code. %%% Compiler from Sophia language to Fate intermediate code.
%%% @end %%% @end
%%% Created : 26 Mar 2019
%%%
%%%------------------------------------------------------------------- %%%-------------------------------------------------------------------
-module(aeso_ast_to_fcode). -module(so_ast_to_fcode).
-vsn("9.0.0").
-export([ast_to_fcode/2, format_fexpr/1]). -export([ast_to_fcode/2, format_fexpr/1]).
-export_type([fcode/0, fexpr/0, fun_def/0]). -export_type([fcode/0, fexpr/0, fun_def/0]).
-include("aeso_utils.hrl"). -include("so_utils.hrl").
%% -- Type definitions ------------------------------------------------------- %% -- Type definitions -------------------------------------------------------
@ -53,16 +53,14 @@
| {bytes, binary()} | {bytes, binary()}
| {account_pubkey, binary()} | {account_pubkey, binary()}
| {contract_pubkey, binary()} | {contract_pubkey, binary()}
| {oracle_pubkey, binary()}
| {oracle_query_id, binary()}
| {signature, 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()} | -type fann() :: [ {file, so_syntax:ann_file()} |
{line, aeso_syntax:ann_line()} | {line, so_syntax:ann_line()} |
{col, aeso_syntax:ann_col()} {col, so_syntax:ann_col()}
]. ].
-type fexpr() :: {lit, fann(), flit()} -type fexpr() :: {lit, fann(), flit()}
@ -115,8 +113,6 @@
| address | address
| {bytes, non_neg_integer()} | {bytes, non_neg_integer()}
| contract | contract
| {oracle, ftype(), ftype()} %% Query type, Response type
| oracle_query
| name | name
| channel | channel
| bits | bits
@ -166,7 +162,7 @@
fun_env := fun_env(), fun_env := fun_env(),
con_env := con_env(), con_env := con_env(),
child_con_env := child_con_env(), child_con_env := child_con_env(),
event_type => aeso_syntax:typedef(), event_type => so_syntax:typedef(),
builtins := builtins(), builtins := builtins(),
options := [option()], options := [option()],
state_layout => state_layout(), state_layout => state_layout(),
@ -181,9 +177,9 @@
%% -- Entrypoint ------------------------------------------------------------- %% -- Entrypoint -------------------------------------------------------------
%% Main entrypoint. Takes typed syntax produced by aeso_ast_infer_types:infer/1,2 %% Main entrypoint. Takes typed syntax produced by so_ast_infer_types:infer/1,2
%% and produces Fate intermediate code. %% and produces Fate intermediate code.
-spec ast_to_fcode(aeso_syntax:ast(), [option()]) -> {env(), fcode()}. -spec ast_to_fcode(so_syntax:ast(), [option()]) -> {env(), fcode()}.
ast_to_fcode(Code, Options) -> ast_to_fcode(Code, Options) ->
init_fresh_names(Options), init_fresh_names(Options),
{Env1, FCode1} = to_fcode(init_env(Options), Code), {Env1, FCode1} = to_fcode(init_env(Options), Code),
@ -305,7 +301,7 @@ builtins() ->
{"to_any_size", 1}, {"size", 1}, {"split_any", 2}]}, {"to_any_size", 1}, {"size", 1}, {"split_any", 2}]},
{["Int"], [{"to_str", 1}, {"to_bytes", 2}, {"mulmod", 2}]}, {["Int"], [{"to_str", 1}, {"to_bytes", 2}, {"mulmod", 2}]},
{["Address"], [{"to_str", 1}, {"to_bytes", 1}, {"to_contract", 1}, {["Address"], [{"to_str", 1}, {"to_bytes", 1}, {"to_contract", 1},
{"is_oracle", 1}, {"is_contract", 1}, {"is_payable", 1}]} {"is_contract", 1}, {"is_payable", 1}]}
], ],
maps:from_list([ {NS ++ [Fun], {MkName(NS, Fun), Arity}} maps:from_list([ {NS ++ [Fun], {MkName(NS, Fun), Arity}}
|| {NS, Funs} <- Scopes, || {NS, Funs} <- Scopes,
@ -333,8 +329,6 @@ init_type_env() ->
["address"] => ?type(address), ["address"] => ?type(address),
["hash"] => ?type(hash), ["hash"] => ?type(hash),
["signature"] => ?type(signature), ["signature"] => ?type(signature),
["oracle"] => ?type(Q, R, {oracle, Q, R}),
["oracle_query"] => ?type(_, _, oracle_query), %% TODO: not in Fate
["list"] => ?type(T, {list, T}), ["list"] => ?type(T, {list, T}),
["map"] => ?type(K, V, {map, K, V}), ["map"] => ?type(K, V, {map, K, V}),
["option"] => ?type(T, {variant, [[], [T]]}), ["option"] => ?type(T, {variant, [[], [T]]}),
@ -364,7 +358,7 @@ get_option(Opt, Env, Default) ->
%% -- Compilation ------------------------------------------------------------ %% -- Compilation ------------------------------------------------------------
-spec to_fcode(env(), aeso_syntax:ast()) -> {env(), fcode()}. -spec to_fcode(env(), so_syntax:ast()) -> {env(), fcode()}.
to_fcode(Env, [{Contract, Attrs, {con, _, Name}, _Impls, Decls}|Rest]) to_fcode(Env, [{Contract, Attrs, {con, _, Name}, _Impls, Decls}|Rest])
when ?IS_CONTRACT_HEAD(Contract) -> when ?IS_CONTRACT_HEAD(Contract) ->
case Contract =:= contract_interface of case Contract =:= contract_interface of
@ -405,7 +399,7 @@ 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 -spec ann_loc(so_syntax:ann() | fann()) -> {File, Line, Column} when
File :: string() | none, File :: string() | none,
Line :: non_neg_integer() | none, Line :: non_neg_integer() | none,
Column :: non_neg_integer() | none. Column :: non_neg_integer() | none.
@ -415,7 +409,7 @@ ann_loc(Ann) ->
Col = proplists:get_value(col, Ann, none), Col = proplists:get_value(col, Ann, none),
{File, Line, Col}. {File, Line, Col}.
-spec to_fann(aeso_syntax:ann()) -> fann(). -spec to_fann(so_syntax:ann()) -> fann().
to_fann(Ann) -> to_fann(Ann) ->
{File, Line, Col} = ann_loc(Ann), {File, Line, Col} = ann_loc(Ann),
[ {Tag, X} || [ {Tag, X} ||
@ -426,7 +420,7 @@ to_fann(Ann) ->
-spec get_fann(fexpr()) -> fann(). -spec get_fann(fexpr()) -> fann().
get_fann(FExpr) -> element(2, FExpr). get_fann(FExpr) -> element(2, FExpr).
-spec decls_to_fcode(env(), [aeso_syntax:decl()]) -> env(). -spec decls_to_fcode(env(), [so_syntax:decl()]) -> env().
decls_to_fcode(Env, Decls) -> decls_to_fcode(Env, Decls) ->
%% First compute mapping from Sophia names to fun_names and add it to the %% First compute mapping from Sophia names to fun_names and add it to the
%% environment. %% environment.
@ -434,7 +428,7 @@ decls_to_fcode(Env, Decls) ->
lists:foldl(fun(D, E) -> decl_to_fcode(E, D) lists:foldl(fun(D, E) -> decl_to_fcode(E, D)
end, Env1, Decls). end, Env1, Decls).
-spec decl_to_fcode(env(), aeso_syntax:decl()) -> env(). -spec decl_to_fcode(env(), so_syntax:decl()) -> env().
decl_to_fcode(Env, {fun_decl, _, _, _}) -> Env; decl_to_fcode(Env, {fun_decl, _, _, _}) -> Env;
decl_to_fcode(Env, {type_def, _Ann, Name, Args, Def}) -> decl_to_fcode(Env, {type_def, _Ann, Name, Args, Def}) ->
typedef_to_fcode(Env, Name, Args, Def); typedef_to_fcode(Env, Name, Args, Def);
@ -458,7 +452,7 @@ decl_to_fcode(Env = #{ consts := Consts }, {letval, _, {typed, _, {id, _, X}, _}
NewConsts = Consts#{ qname(Env, X) => FVal }, NewConsts = Consts#{ qname(Env, X) => FVal },
Env#{ consts := NewConsts }. Env#{ consts := NewConsts }.
-spec typedef_to_fcode(env(), aeso_syntax:id(), [aeso_syntax:tvar()], aeso_syntax:typedef()) -> env(). -spec typedef_to_fcode(env(), so_syntax:id(), [so_syntax:tvar()], so_syntax:typedef()) -> env().
typedef_to_fcode(Env, {id, _, Name}, Xs, Def) -> typedef_to_fcode(Env, {id, _, Name}, Xs, Def) ->
Q = qname(Env, Name), Q = qname(Env, Name),
FDef = fun(Args) when length(Args) == length(Xs) -> FDef = fun(Args) when length(Args) == length(Xs) ->
@ -525,11 +519,11 @@ compute_state_layout(R, [H | T]) ->
compute_state_layout(R, _) -> compute_state_layout(R, _) ->
{R + 1, {reg, R}}. {R + 1, {reg, R}}.
-spec type_to_fcode(env(), aeso_syntax:type()) -> ftype(). -spec type_to_fcode(env(), so_syntax:type()) -> ftype().
type_to_fcode(Env, Type) -> type_to_fcode(Env, Type) ->
type_to_fcode(Env, #{}, Type). type_to_fcode(Env, #{}, Type).
-spec type_to_fcode(env(), #{var_name() => ftype()}, aeso_syntax:type()) -> ftype(). -spec type_to_fcode(env(), #{var_name() => ftype()}, so_syntax:type()) -> ftype().
type_to_fcode(_Env, _Sub, {con, _, _}) -> contract; type_to_fcode(_Env, _Sub, {con, _, _}) -> contract;
type_to_fcode(Env, Sub, {app_t, _, T = {Id, _, _}, Types}) when Id == id; Id == qid -> type_to_fcode(Env, Sub, {app_t, _, T = {Id, _, _}, Types}) when Id == id; Id == qid ->
lookup_type(Env, T, [type_to_fcode(Env, Sub, Type) || Type <- Types]); lookup_type(Env, T, [type_to_fcode(Env, Sub, Type) || Type <- Types]);
@ -555,7 +549,7 @@ type_to_fcode(Env, Sub, {if_t, _, _, _, Else}) ->
type_to_fcode(_Env, _Sub, Type) -> type_to_fcode(_Env, _Sub, Type) ->
error({todo, Type}). error({todo, Type}).
-spec args_to_fcode(env(), [aeso_syntax:pat()]) -> [{var_name(), ftype()}]. -spec args_to_fcode(env(), [so_syntax:pat()]) -> [{var_name(), ftype()}].
args_to_fcode(Env, Args) -> args_to_fcode(Env, Args) ->
[ case Arg of [ case Arg of
{id, _, Name} -> {Name, type_to_fcode(Env, Type)}; {id, _, Name} -> {Name, type_to_fcode(Env, Type)};
@ -586,13 +580,13 @@ let_bind(Binds, Body) ->
lists:foldr(fun({X, E}, Rest) -> let_bind(X, E, Rest) end, lists:foldr(fun({X, E}, Rest) -> let_bind(X, E, Rest) end,
Body, Binds). Body, Binds).
-spec expr_to_fcode(env(), aeso_syntax:expr()) -> fexpr(). -spec expr_to_fcode(env(), so_syntax:expr()) -> fexpr().
expr_to_fcode(Env, {typed, _, Expr, Type}) -> expr_to_fcode(Env, {typed, _, Expr, Type}) ->
expr_to_fcode(Env, Type, Expr); expr_to_fcode(Env, Type, Expr);
expr_to_fcode(Env, Expr) -> expr_to_fcode(Env, Expr) ->
expr_to_fcode(Env, no_type, Expr). expr_to_fcode(Env, no_type, Expr).
-spec expr_to_fcode(env(), aeso_syntax:type() | no_type, aeso_syntax:expr()) -> fexpr(). -spec expr_to_fcode(env(), so_syntax:type() | no_type, so_syntax:expr()) -> fexpr().
%% Literals %% Literals
expr_to_fcode(_Env, _Type, {int, Ann, N}) -> {lit, to_fann(Ann), {int, N}}; expr_to_fcode(_Env, _Type, {int, Ann, N}) -> {lit, to_fann(Ann), {int, N}};
@ -602,25 +596,12 @@ expr_to_fcode(_Env, _Type, {string, Ann, S}) -> {lit, to_fann(Ann), {st
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, {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_query_id, Ann, K}) -> {lit, to_fann(Ann), {oracle_query_id, K}};
expr_to_fcode(_Env, _Type, {bytes, Ann, B}) -> {lit, to_fann(Ann), {bytes, B}}; expr_to_fcode(_Env, _Type, {bytes, Ann, B}) -> {lit, to_fann(Ann), {bytes, B}};
%% Variables %% Variables
expr_to_fcode(Env, _Type, {id, Ann, X}) -> resolve_var(Env, Ann, [X]); expr_to_fcode(Env, _Type, {id, Ann, X}) -> resolve_var(Env, Ann, [X]);
expr_to_fcode(Env, Type, {qid, Ann, X}) -> expr_to_fcode(Env, Type, {qid, Ann, X}) ->
case resolve_var(Env, Ann, X) of case resolve_var(Env, Ann, X) of
{builtin_u, FAnn, B, Ar} when B =:= oracle_query;
B =:= oracle_get_question;
B =:= oracle_get_answer;
B =:= oracle_respond;
B =:= oracle_register;
B =:= oracle_check;
B =:= oracle_check_query ->
OType = get_oracle_type(B, Type),
{oracle, QType, RType} = type_to_fcode(Env, OType),
TypeArgs = [{lit, FAnn, {typerep, QType}}, {lit, FAnn, {typerep, RType}}],
{builtin_u, FAnn, B, Ar, TypeArgs};
{builtin_u, FAnn, B = aens_resolve, Ar} -> {builtin_u, FAnn, B = aens_resolve, Ar} ->
{fun_t, _, _, _, ResType} = Type, {fun_t, _, _, _, ResType} = Type,
AensType = type_to_fcode(Env, ResType), AensType = type_to_fcode(Env, ResType),
@ -705,7 +686,7 @@ expr_to_fcode(Env, {record_t, FieldTypes}, {record, Ann, Rec, Fields}) ->
%% Lists %% Lists
expr_to_fcode(Env, _Type, {list, Ann, Es}) -> expr_to_fcode(Env, _Type, {list, Ann, Es}) ->
lists:foldr(fun(E, L) -> {op, to_fann(aeso_syntax:get_ann(E)), '::', [expr_to_fcode(Env, E), L]} end, lists:foldr(fun(E, L) -> {op, to_fann(so_syntax:get_ann(E)), '::', [expr_to_fcode(Env, E), L]} end,
{nil, to_fann(Ann)}, Es); {nil, to_fann(Ann)}, Es);
expr_to_fcode(Env, _Type, {app, As, {'..', _}, [A, B]}) -> expr_to_fcode(Env, _Type, {app, As, {'..', _}, [A, B]}) ->
@ -783,15 +764,15 @@ expr_to_fcode(Env, _, {app, _, Fun = {typed, Ann, FunE, {fun_t, _, NamedArgsT, A
var_args -> fcode_error({var_args_not_set, FunE}); var_args -> fcode_error({var_args_not_set, FunE});
_ -> _ ->
%% 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 `so_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;
@ -884,21 +865,10 @@ make_tuple_fpat(Ps) -> {tuple, Ps}.
strip_singleton_tuples({tuple, _, [T]}) -> strip_singleton_tuples(T); strip_singleton_tuples({tuple, _, [T]}) -> strip_singleton_tuples(T);
strip_singleton_tuples(T) -> T. strip_singleton_tuples(T) -> T.
-spec get_oracle_type(OracleFun, FunT) -> OracleType when
OracleFun :: atom(),
FunT :: aeso_syntax:type(),
OracleType :: aeso_syntax:type().
get_oracle_type(oracle_register, {fun_t, _, _, _, OType}) -> OType;
get_oracle_type(oracle_query, {fun_t, _, _, [OType | _], _}) -> OType;
get_oracle_type(oracle_get_question, {fun_t, _, _, [OType | _], _}) -> OType;
get_oracle_type(oracle_get_answer, {fun_t, _, _, [OType | _], _}) -> OType;
get_oracle_type(oracle_check, {fun_t, _, _, [OType | _], _}) -> OType;
get_oracle_type(oracle_check_query, {fun_t, _, _, [OType | _], _}) -> OType;
get_oracle_type(oracle_respond, {fun_t, _, _, [OType | _], _}) -> OType.
%% -- Pattern matching -- %% -- Pattern matching --
-spec alts_to_fcode(env(), ftype(), var_name(), [aeso_syntax:alt()], aeso_syntax:expr()) -> fsplit(). -spec alts_to_fcode(env(), ftype(), var_name(), [so_syntax:alt()], so_syntax:expr()) -> fsplit().
alts_to_fcode(Env, Type, X, Alts, Switch) -> alts_to_fcode(Env, Type, X, Alts, Switch) ->
FAlts = remove_guards(Env, Alts, Switch), FAlts = remove_guards(Env, Alts, Switch),
split_tree(Env, [{X, Type}], FAlts). split_tree(Env, [{X, Type}], FAlts).
@ -915,7 +885,7 @@ alts_to_fcode(Env, Type, X, Alts, Switch) ->
| {con, arities(), tag(), [fpat()]} | {con, arities(), tag(), [fpat()]}
| {assign, fpat(), fpat()}. | {assign, fpat(), fpat()}.
-spec remove_guards(env(), [aeso_syntax:alt()], aeso_syntax:expr()) -> [falt()]. -spec remove_guards(env(), [so_syntax:alt()], so_syntax:expr()) -> [falt()].
remove_guards(_Env, [], _Switch) -> remove_guards(_Env, [], _Switch) ->
[]; [];
remove_guards(Env, [Alt = {'case', _, _, [{guarded, _, [], _Expr}]} | Rest], Switch) -> remove_guards(Env, [Alt = {'case', _, _, [{guarded, _, [], _Expr}]} | Rest], Switch) ->
@ -1080,19 +1050,19 @@ next_split(Pats) ->
[I | _] -> I [I | _] -> I
end. end.
-spec alt_to_fcode(env(), aeso_syntax:alt()) -> falt(). -spec alt_to_fcode(env(), so_syntax:alt()) -> falt().
alt_to_fcode(Env, {'case', _, Pat, [{guarded, _, [], Expr}]}) -> alt_to_fcode(Env, {'case', _, Pat, [{guarded, _, [], Expr}]}) ->
FPat = pat_to_fcode(Env, Pat), FPat = pat_to_fcode(Env, Pat),
FExpr = expr_to_fcode(bind_vars(Env, pat_vars(FPat)), Expr), FExpr = expr_to_fcode(bind_vars(Env, pat_vars(FPat)), Expr),
{'case', [FPat], FExpr}. {'case', [FPat], FExpr}.
-spec pat_to_fcode(env(), aeso_syntax:pat()) -> fpat(). -spec pat_to_fcode(env(), so_syntax:pat()) -> fpat().
pat_to_fcode(Env, {typed, _, Pat, Type}) -> pat_to_fcode(Env, {typed, _, Pat, Type}) ->
pat_to_fcode(Env, Type, Pat); pat_to_fcode(Env, Type, Pat);
pat_to_fcode(Env, Pat) -> pat_to_fcode(Env, Pat) ->
pat_to_fcode(Env, no_type, Pat). pat_to_fcode(Env, no_type, Pat).
-spec pat_to_fcode(env(), aeso_syntax:type() | no_type, aeso_syntax:pat()) -> fpat(). -spec pat_to_fcode(env(), so_syntax:type() | no_type, so_syntax:pat()) -> fpat().
pat_to_fcode(_Env, _Type, {id, _, X}) -> {var, X}; pat_to_fcode(_Env, _Type, {id, _, X}) -> {var, X};
pat_to_fcode(Env, _Type, {C, _, _} = Con) when C == con; C == qcon -> pat_to_fcode(Env, _Type, {C, _, _} = Con) when C == con; C == qcon ->
#con_tag{tag = I, arities = As} = lookup_con(Env, Con), #con_tag{tag = I, arities = As} = lookup_con(Env, Con),
@ -1134,7 +1104,7 @@ pat_to_fcode(_Env, Type, Pat) ->
| {atom, fexpr()} | {atom, fexpr()}
| {'if', fexpr(), decision_tree(), decision_tree()}. | {'if', fexpr(), decision_tree(), decision_tree()}.
-spec decision_op(aeso_syntax:op(), decision_tree(), decision_tree()) -> decision_tree(). -spec decision_op(so_syntax:op(), decision_tree(), decision_tree()) -> decision_tree().
decision_op('&&', {atom, A}, B) -> {'if', A, B, false}; decision_op('&&', {atom, A}, B) -> {'if', A, B, false};
decision_op('&&', false, _) -> false; decision_op('&&', false, _) -> false;
decision_op('&&', true, B) -> B; decision_op('&&', true, B) -> B;
@ -1144,7 +1114,7 @@ decision_op('||', true, _) -> true;
decision_op(Op, {'if', A, Then, Else}, B) -> decision_op(Op, {'if', A, Then, Else}, B) ->
{'if', A, decision_op(Op, Then, B), decision_op(Op, Else, B)}. {'if', A, decision_op(Op, Then, B), decision_op(Op, Else, B)}.
-spec expr_to_decision_tree(env(), aeso_syntax:expr()) -> decision_tree(). -spec expr_to_decision_tree(env(), so_syntax:expr()) -> decision_tree().
expr_to_decision_tree(Env, {app, _Ann, {Op, _}, [A, B]}) when Op == '&&'; Op == '||' -> expr_to_decision_tree(Env, {app, _Ann, {Op, _}, [A, B]}) when Op == '&&'; Op == '||' ->
decision_op(Op, expr_to_decision_tree(Env, A), expr_to_decision_tree(Env, B)); decision_op(Op, expr_to_decision_tree(Env, A), expr_to_decision_tree(Env, B));
expr_to_decision_tree(Env, {typed, _, Expr, _}) -> expr_to_decision_tree(Env, Expr); expr_to_decision_tree(Env, {typed, _, Expr, _}) -> expr_to_decision_tree(Env, Expr);
@ -1163,7 +1133,7 @@ decision_tree_to_fcode({'if', A, Then, Else}) ->
%% -- Statements -- %% -- Statements --
-spec stmts_to_fcode(env(), [aeso_syntax:stmt()]) -> fexpr(). -spec stmts_to_fcode(env(), [so_syntax:stmt()]) -> fexpr().
stmts_to_fcode(Env, [{letval, Ann, {typed, _, {id, _, X}, _}, Expr} | Stmts]) -> stmts_to_fcode(Env, [{letval, Ann, {typed, _, {id, _, X}, _}, Expr} | Stmts]) ->
{'let', to_fann(Ann), X, expr_to_fcode(Env, Expr), stmts_to_fcode(bind_var(Env, X), Stmts)}; {'let', to_fann(Ann), X, expr_to_fcode(Env, Expr), stmts_to_fcode(bind_var(Env, X), Stmts)};
stmts_to_fcode(Env, [{letval, Ann, Pat, Expr} | Stmts]) -> stmts_to_fcode(Env, [{letval, Ann, Pat, Expr} | Stmts]) ->
@ -1178,7 +1148,7 @@ stmts_to_fcode(Env, [{letfun, Ann, {id, _, X}, Args, _Type, [{guarded, _, [], Ex
stmts_to_fcode(Env, [Expr]) -> stmts_to_fcode(Env, [Expr]) ->
expr_to_fcode(Env, Expr); expr_to_fcode(Env, Expr);
stmts_to_fcode(Env, [Expr | Stmts]) -> stmts_to_fcode(Env, [Expr | Stmts]) ->
{'let', to_fann(aeso_syntax:get_ann(Expr)), "_", expr_to_fcode(Env, Expr), stmts_to_fcode(Env, Stmts)}. {'let', to_fann(so_syntax:get_ann(Expr)), "_", expr_to_fcode(Env, Expr), stmts_to_fcode(Env, Stmts)}.
%% -- Builtins -- %% -- Builtins --
@ -1810,7 +1780,7 @@ used_functions(Used, [Name | Rest], Defs) ->
%% -- Types -- %% -- Types --
-spec lookup_type(env(), aeso_syntax:id() | aeso_syntax:qid() | sophia_name(), [ftype()]) -> ftype(). -spec lookup_type(env(), so_syntax:id() | so_syntax:qid() | sophia_name(), [ftype()]) -> ftype().
lookup_type(Env, {id, _, Name}, Args) -> lookup_type(Env, {id, _, Name}, Args) ->
lookup_type(Env, [Name], Args); lookup_type(Env, [Name], Args);
lookup_type(Env, {qid, _, Name}, Args) -> lookup_type(Env, {qid, _, Name}, Args) ->
@ -1842,7 +1812,7 @@ bind_constructors(Env = #{ con_env := ConEnv }, NewCons) ->
add_child_con(Env = #{child_con_env := CEnv}, Name, Fcode) -> add_child_con(Env = #{child_con_env := CEnv}, Name, Fcode) ->
Env#{ child_con_env := CEnv#{Name => Fcode} }. Env#{ child_con_env := CEnv#{Name => Fcode} }.
-spec add_fun_env(env(), [aeso_syntax:decl()]) -> env(). -spec add_fun_env(env(), [so_syntax:decl()]) -> env().
add_fun_env(Env = #{ context := {abstract_contract, _} }, _) -> Env; %% no functions from abstract contracts add_fun_env(Env = #{ context := {abstract_contract, _} }, _) -> Env; %% no functions from abstract contracts
add_fun_env(Env = #{ fun_env := FunEnv }, Decls) -> add_fun_env(Env = #{ fun_env := FunEnv }, Decls) ->
Entry = fun({letfun, Ann, {id, _, Name}, Args, _, _}) -> Entry = fun({letfun, Ann, {id, _, Name}, Args, _, _}) ->
@ -1853,7 +1823,7 @@ add_fun_env(Env = #{ fun_env := FunEnv }, Decls) ->
FunEnv1 = maps:from_list(lists:flatmap(Entry, Decls)), FunEnv1 = maps:from_list(lists:flatmap(Entry, Decls)),
Env#{ fun_env := maps:merge(FunEnv, FunEnv1) }. Env#{ fun_env := maps:merge(FunEnv, FunEnv1) }.
-spec make_fun_name(env(), aeso_syntax:ann(), aeso_syntax:name()) -> fun_name(). -spec make_fun_name(env(), so_syntax:ann(), so_syntax:name()) -> fun_name().
make_fun_name(#{ context := Context }, Ann, Name) -> make_fun_name(#{ context := Context }, Ann, Name) ->
Entrypoint = proplists:get_value(entrypoint, Ann, false), Entrypoint = proplists:get_value(entrypoint, Ann, false),
case Context of case Context of
@ -1884,7 +1854,7 @@ lookup_fun(#{ fun_env := FunEnv }, Name) ->
{FName, _} -> FName {FName, _} -> FName
end. end.
-spec lookup_con(env(), aeso_syntax:con() | aeso_syntax:qcon() | sophia_name()) -> con_tag(). -spec lookup_con(env(), so_syntax:con() | so_syntax:qcon() | sophia_name()) -> con_tag().
lookup_con(Env, {con, _, Con}) -> lookup_con(Env, [Con]); lookup_con(Env, {con, _, Con}) -> lookup_con(Env, [Con]);
lookup_con(Env, {qcon, _, Con}) -> lookup_con(Env, Con); lookup_con(Env, {qcon, _, Con}) -> lookup_con(Env, Con);
lookup_con(#{ con_env := ConEnv }, Con) -> lookup_con(#{ con_env := ConEnv }, Con) ->
@ -1900,7 +1870,7 @@ bind_vars(Env, Xs) ->
-spec bind_var(env(), var_name()) -> env(). -spec bind_var(env(), var_name()) -> env().
bind_var(Env = #{ vars := Vars }, X) -> Env#{ vars := [X | Vars] }. bind_var(Env = #{ vars := Vars }, X) -> Env#{ vars := [X | Vars] }.
-spec resolve_var(env(), aeso_syntax:ann(), [aeso_syntax:name()]) -> fexpr(). -spec resolve_var(env(), so_syntax:ann(), [so_syntax:name()]) -> fexpr().
resolve_var(#{ vars := Vars } = Env, Ann, [X]) -> resolve_var(#{ vars := Vars } = Env, Ann, [X]) ->
case lists:member(X, Vars) of case lists:member(X, Vars) of
true -> {var, to_fann(Ann), X}; true -> {var, to_fann(Ann), X};
@ -1922,7 +1892,7 @@ resolve_const(#{ consts := Consts }, Q) ->
Val -> Val Val -> Val
end. end.
-spec resolve_fun(env(), aeso_syntax:ann(), [aeso_syntax:name()]) -> fexpr(). -spec resolve_fun(env(), so_syntax:ann(), [so_syntax:name()]) -> fexpr().
resolve_fun(#{ fun_env := Funs, builtins := Builtin } = Env, Ann, Q) -> resolve_fun(#{ fun_env := Funs, builtins := Builtin } = Env, Ann, Q) ->
case {maps:get(Q, Funs, not_found), maps:get(Q, Builtin, not_found)} of case {maps:get(Q, Funs, not_found), maps:get(Q, Builtin, not_found)} of
{not_found, not_found} -> internal_error({unbound_variable, Q}); {not_found, not_found} -> internal_error({unbound_variable, Q});
@ -2102,7 +2072,7 @@ bottom_up(F, Env, Expr) ->
{'case', Pat, Split} -> {'case', Pat, bottom_up(F, Env, Split)} {'case', Pat, Split} -> {'case', Pat, bottom_up(F, Env, Split)}
end). end).
-spec get_named_args([aeso_syntax:named_arg_t()], [aeso_syntax:arg_expr()]) -> [aeso_syntax:expr()]. -spec get_named_args([so_syntax:named_arg_t()], [so_syntax:arg_expr()]) -> [so_syntax:expr()].
get_named_args(NamedArgsT, Args) -> get_named_args(NamedArgsT, Args) ->
IsNamed = fun({named_arg, _, _, _}) -> true; IsNamed = fun({named_arg, _, _, _}) -> true;
(_) -> false end, (_) -> false end,
@ -2110,7 +2080,7 @@ get_named_args(NamedArgsT, Args) ->
NamedArgs = [get_named_arg(NamedArg, Named) || NamedArg <- NamedArgsT], NamedArgs = [get_named_arg(NamedArg, Named) || NamedArg <- NamedArgsT],
NamedArgs ++ NotNamed. NamedArgs ++ NotNamed.
-spec get_named_arg(aeso_syntax:named_arg_t(), [aeso_syntax:arg_expr()]) -> aeso_syntax:expr(). -spec get_named_arg(so_syntax:named_arg_t(), [so_syntax:arg_expr()]) -> so_syntax:expr().
get_named_arg({named_arg_t, _, {id, _, Name}, _, Default}, Args) -> get_named_arg({named_arg_t, _, {id, _, Name}, _, Default}, Args) ->
case [ Val || {named_arg, _, {id, _, X}, Val} <- Args, X == Name ] of case [ Val || {named_arg, _, {id, _, X}, Val} <- Args, X == Name ] of
[Val] -> Val; [Val] -> Val;
@ -2236,15 +2206,15 @@ update_rename(OldRen, NewRen) ->
%% -- Records -- %% -- Records --
-spec field_index(aeso_syntax:typedef(), aeso_syntax:name()) -> integer(). -spec field_index(so_syntax:typedef(), so_syntax:name()) -> integer().
field_index({record_t, Fields}, X) -> field_index({record_t, Fields}, X) ->
IsX = fun({field_t, _, {id, _, Y}, _}) -> X == Y end, IsX = fun({field_t, _, {id, _, Y}, _}) -> X == Y end,
[I] = [ I || {I, Field} <- indexed(Fields), IsX(Field) ], [I] = [ I || {I, Field} <- indexed(Fields), IsX(Field) ],
I - 1. %% Tuples are 0-indexed I - 1. %% Tuples are 0-indexed
-spec field_value(aeso_syntax:field_t(), [aeso_syntax:field(aeso_syntax:pat())]) -> Res when -spec field_value(so_syntax:field_t(), [so_syntax:field(so_syntax:pat())]) -> Res when
Res :: {upd, aeso_syntax:name(), Expr} | {set, Expr} | false, Res :: {upd, so_syntax:name(), Expr} | {set, Expr} | false,
Expr :: aeso_syntax:expr(). Expr :: so_syntax:expr().
field_value({field_t, _, {id, _, X}, _}, Fields) -> field_value({field_t, _, {id, _, X}, _}, Fields) ->
View = fun({field, _, [{proj, _, {id, _, Y}}], E}) -> {Y, {set, E}}; View = fun({field, _, [{proj, _, {id, _, Y}}], E}) -> {Y, {set, E}};
({field_upd, _, [{proj, _, {id, _, Y}}], ({field_upd, _, [{proj, _, {id, _, Y}}],
@ -2256,13 +2226,13 @@ field_value({field_t, _, {id, _, X}, _}, Fields) ->
%% -- Attributes -- %% -- Attributes --
-spec get_attributes(aeso_syntax:ann()) -> [stateful | payable | private]. -spec get_attributes(so_syntax:ann()) -> [stateful | payable | private].
get_attributes(Ann) -> get_attributes(Ann) ->
[stateful || proplists:get_value(stateful, Ann, false)] ++ [stateful || proplists:get_value(stateful, Ann, false)] ++
[payable || proplists:get_value(payable, Ann, false)] ++ [payable || proplists:get_value(payable, Ann, false)] ++
[private || not proplists:get_value(entrypoint, Ann, false)]. [private || not proplists:get_value(entrypoint, Ann, false)].
-spec get_attributes_debug(aeso_syntax:ann()) -> [stateful | payable | private | fann()]. -spec get_attributes_debug(so_syntax:ann()) -> [stateful | payable | private | fann()].
get_attributes_debug(Ann) -> get_attributes_debug(Ann) ->
get_attributes(Ann) ++ to_fann(Ann). get_attributes(Ann) ++ to_fann(Ann).
@ -2283,14 +2253,14 @@ setnth(I, X, Xs) ->
-spec fcode_error(string()) -> no_return(). -spec fcode_error(string()) -> no_return().
fcode_error(Error) -> fcode_error(Error) ->
Pos = aeso_errors:pos(0, 0), Pos = so_errors:pos(0, 0),
Msg = lists:flatten(io_lib:format("Unknown error: ~p\n", [Error])), Msg = lists:flatten(io_lib:format("Unknown error: ~p\n", [Error])),
aeso_errors:throw(aeso_errors:new(code_error, Pos, Msg)). so_errors:throw(so_errors:new(code_error, Pos, Msg)).
-spec internal_error(string()) -> no_return(). -spec internal_error(string()) -> no_return().
internal_error(Error) -> internal_error(Error) ->
Msg = lists:flatten(io_lib:format("~p\n", [Error])), Msg = lists:flatten(io_lib:format("~p\n", [Error])),
aeso_errors:throw(aeso_errors:new(internal_error, aeso_errors:pos(0, 0), Msg)). so_errors:throw(so_errors:new(internal_error, so_errors:pos(0, 0), Msg)).
%% -- Pretty printing -------------------------------------------------------- %% -- Pretty printing --------------------------------------------------------
@ -2367,7 +2337,7 @@ pp_fexpr({lit, _, {typerep, T}}) ->
pp_fexpr({lit, _, {contract_code, Contract}}) -> pp_fexpr({lit, _, {contract_code, Contract}}) ->
pp_beside(pp_text("contract "), pp_text(Contract)); pp_beside(pp_text("contract "), pp_text(Contract));
pp_fexpr({lit, _, {Tag, Lit}}) -> pp_fexpr({lit, _, {Tag, Lit}}) ->
aeso_pretty:expr({Tag, [], Lit}); so_pretty:expr({Tag, [], Lit});
pp_fexpr({nil, _}) -> pp_fexpr({nil, _}) ->
pp_text("[]"); pp_text("[]");
pp_fexpr({var, _, X}) -> pp_text(X); pp_fexpr({var, _, X}) -> pp_text(X);
@ -2451,7 +2421,6 @@ pp_ftype(T) when is_atom(T) -> pp_text(T);
pp_ftype(any) -> pp_text("_"); pp_ftype(any) -> pp_text("_");
pp_ftype({tvar, X}) -> pp_text(X); pp_ftype({tvar, X}) -> pp_text(X);
pp_ftype({bytes, N}) -> pp_call(pp_text("bytes"), [{lit, [], {int, N}}]); pp_ftype({bytes, N}) -> pp_call(pp_text("bytes"), [{lit, [], {int, N}}]);
pp_ftype({oracle, Q, R}) -> pp_call_t("oracle", [Q, R]);
pp_ftype({tuple, Ts}) -> pp_ftype({tuple, Ts}) ->
pp_parens(pp_par(pp_punctuate(pp_text(" *"), [pp_ftype(T) || T <- Ts]))); pp_parens(pp_par(pp_punctuate(pp_text(" *"), [pp_ftype(T) || T <- Ts])));
pp_ftype({list, T}) -> pp_ftype({list, T}) ->

View File

@ -1,12 +1,13 @@
%%%------------------------------------------------------------------- %%%-------------------------------------------------------------------
%%% @author Happi (Erik Stenman) %%% @author Happi (Erik Stenman)
%%% @copyright (C) 2025, QPQ AG
%%% @copyright (C) 2017, Aeternity Anstalt %%% @copyright (C) 2017, Aeternity Anstalt
%%% @doc %%% @doc
%%% Compiler from Aeterinty Sophia language to FATE. %%% Compiler from Sophia language to FATE.
%%% @end %%% @end
%%% Created : 12 Dec 2017
%%%------------------------------------------------------------------- %%%-------------------------------------------------------------------
-module(aeso_compiler). -module(so_compiler).
-vsn("9.0.0").
-export([ file/1 -export([ file/1
, file/2 , file/2
@ -27,8 +28,8 @@
, 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("so_utils.hrl").
-type option() :: pp_sophia_code -type option() :: pp_sophia_code
@ -43,7 +44,7 @@
{explicit_files, #{string() => binary()}}} {explicit_files, #{string() => binary()}}}
| {src_file, string()} | {src_file, string()}
| {src_dir, string()} | {src_dir, string()}
| {aci, aeso_aci:aci_type()}. | {aci, so_aci:aci_type()}.
-type options() :: [option()]. -type options() :: [option()].
-export_type([ option/0 -export_type([ option/0
@ -52,15 +53,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
@ -80,20 +81,20 @@ numeric_version() ->
Err Err
end. end.
-spec file(string()) -> {ok, map()} | {error, [aeso_errors:error()]}. -spec file(string()) -> {ok, map()} | {error, [so_errors:error()]}.
file(Filename) -> file(Filename) ->
file(Filename, []). file(Filename, []).
-spec file(string(), options()) -> {ok, map()} | {error, [aeso_errors:error()]}. -spec file(string(), options()) -> {ok, map()} | {error, [so_errors:error()]}.
file(File, Options0) -> file(File, Options0) ->
Options = add_include_path(File, Options0), Options = add_include_path(File, Options0),
case read_contract(File) of case read_contract(File) of
{ok, Bin} -> {ok, Bin} ->
SrcDir = aeso_utils:canonical_dir(filename:dirname(File)), SrcDir = so_utils:canonical_dir(filename:dirname(File)),
from_string(Bin, [{src_file, File}, {src_dir, SrcDir} | Options]); 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, [so_errors:new(file_error, Msg)]}
end. end.
add_include_path(File, Options) -> add_include_path(File, Options) ->
@ -102,10 +103,10 @@ add_include_path(File, Options) ->
false -> false ->
Dir = filename:dirname(File), Dir = filename:dirname(File),
{ok, Cwd} = file:get_cwd(), {ok, Cwd} = file:get_cwd(),
[{include, {file_system, [Cwd, aeso_utils:canonical_dir(Dir)]}} | Options] [{include, {file_system, [Cwd, so_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, [so_errors:error()]}.
from_string(ContractBin, Options) when is_binary(ContractBin) -> from_string(ContractBin, Options) when is_binary(ContractBin) ->
from_string(binary_to_list(ContractBin), Options); from_string(binary_to_list(ContractBin), Options);
from_string(ContractString, Options) -> from_string(ContractString, Options) ->
@ -122,16 +123,16 @@ from_string1(ContractString, Options) ->
, warnings := Warnings } = string_to_code(ContractString, Options), , warnings := Warnings } = string_to_code(ContractString, Options),
#{ child_con_env := ChildContracts } = FCodeEnv, #{ child_con_env := ChildContracts } = FCodeEnv,
SavedFreshNames = maps:get(saved_fresh_names, FCodeEnv, #{}), SavedFreshNames = maps:get(saved_fresh_names, FCodeEnv, #{}),
FateCode = aeso_fcode_to_fate:compile(ChildContracts, FCode, SavedFreshNames, Options), FateCode = so_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
}, },
@ -142,7 +143,7 @@ maybe_generate_aci(Result, FoldedTypedAst, Options) ->
undefined -> undefined ->
Result; Result;
Type -> Type ->
{ok, Aci} = aeso_aci:from_typed_ast(Type, FoldedTypedAst), {ok, Aci} = so_aci:from_typed_ast(Type, FoldedTypedAst),
maps:put(aci, Aci, Result) maps:put(aci, Aci, Result)
end. end.
@ -151,9 +152,9 @@ string_to_code(ContractString, Options) ->
Ast = parse(ContractString, Options), Ast = parse(ContractString, Options),
pp_sophia_code(Ast, Options), pp_sophia_code(Ast, Options),
pp_ast(Ast, Options), pp_ast(Ast, Options),
{TypeEnv, FoldedTypedAst, UnfoldedTypedAst, Warnings} = aeso_ast_infer_types:infer(Ast, [return_env | Options]), {TypeEnv, FoldedTypedAst, UnfoldedTypedAst, Warnings} = so_ast_infer_types:infer(Ast, [return_env | Options]),
pp_typed_ast(UnfoldedTypedAst, Options), pp_typed_ast(UnfoldedTypedAst, Options),
{Env, Fcode} = aeso_ast_to_fcode:ast_to_fcode(UnfoldedTypedAst, [{original_src, ContractString}|Options]), {Env, Fcode} = so_ast_to_fcode:ast_to_fcode(UnfoldedTypedAst, [{original_src, ContractString}|Options]),
#{ fcode => Fcode #{ fcode => Fcode
, fcode_env => Env , fcode_env => Env
, unfolded_typed_ast => UnfoldedTypedAst , unfolded_typed_ast => UnfoldedTypedAst
@ -171,7 +172,7 @@ string_to_code(ContractString, Options) ->
%% NOTE: Special treatment for "init" since it might be implicit and has %% NOTE: Special treatment for "init" since it might be implicit and has
%% a special return type (typerep, T) %% a special return type (typerep, T)
-spec check_call(string(), string(), [string()], options()) -> {ok, string(), [term()]} -spec check_call(string(), string(), [string()], options()) -> {ok, string(), [term()]}
| {error, [aeso_errors:error()]}. | {error, [so_errors:error()]}.
check_call(Source, "init" = FunName, Args, Options) -> check_call(Source, "init" = FunName, Args, Options) ->
case check_call1(Source, FunName, Args, Options) of case check_call1(Source, FunName, Args, Options) of
Err = {error, _} when Args == [] -> Err = {error, _} when Args == [] ->
@ -190,7 +191,7 @@ check_call1(ContractString0, FunName, Args, Options) ->
case add_extra_call(ContractString0, {call, FunName, Args}, Options) of case add_extra_call(ContractString0, {call, FunName, Args}, Options) of
{ok, CallName, Code} -> {ok, CallName, Code} ->
{def, _, _, FcodeArgs} = get_call_body(CallName, Code), {def, _, _, FcodeArgs} = get_call_body(CallName, Code),
{ok, FunName, [ aeso_fcode_to_fate:term_to_fate(A) || A <- FcodeArgs ]}; {ok, FunName, [ so_fcode_to_fate:term_to_fate(A) || A <- FcodeArgs ]};
Err = {error, _} -> Err = {error, _} ->
Err Err
end. end.
@ -201,9 +202,9 @@ add_extra_call(Contract0, Call, Options) ->
#{fcode := OrgFcode #{fcode := OrgFcode
, fcode_env := #{child_con_env := ChildContracts} , fcode_env := #{child_con_env := ChildContracts}
, ast := Ast} = string_to_code(Contract0, Options), , ast := Ast} = string_to_code(Contract0, Options),
FateCode = aeso_fcode_to_fate:compile(ChildContracts, OrgFcode, #{}, []), FateCode = so_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),
@ -220,7 +221,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(so_fcode_to_fate:term_to_fate(Body))};
Err = {error, _} -> Err = {error, _} ->
Err Err
end. end.
@ -231,7 +232,7 @@ decode_value(Contract0, Type, FateValue, Options) ->
#{ folded_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, Type1 = so_ast_infer_types:unfold_types_in_type(TypeEnv, Type0,
[ unfold_record_types [ unfold_record_types
, unfold_variant_types , unfold_variant_types
, not_unfold_system_alias_types ]), , not_unfold_system_alias_types ]),
@ -243,7 +244,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 ->
@ -251,7 +252,7 @@ first_none_match(CallName, Hashes, [Char|Chars]) ->
end. end.
%% Add the __call function to a contract. %% Add the __call function to a contract.
-spec insert_call_function(aeso_syntax:ast(), string(), string(), -spec insert_call_function(so_syntax:ast(), string(), string(),
{call, string(), [string()]} | {value, string(), string()} | {type, string()}) -> string(). {call, string(), [string()]} | {value, string(), string()} | {type, string()}) -> string().
insert_call_function(Ast, Code, Call, {call, FunName, Args}) -> insert_call_function(Ast, Code, Call, {call, FunName, Args}) ->
Ind = last_contract_indent(Ast), Ind = last_contract_indent(Ast),
@ -290,25 +291,25 @@ insert_init_function(Code, Options) ->
last_contract_indent(Decls) -> last_contract_indent(Decls) ->
case lists:last(Decls) of case lists:last(Decls) of
{_, _, _, _, [Decl | _]} -> aeso_syntax:get_ann(col, Decl, 1) - 1; {_, _, _, _, [Decl | _]} -> so_syntax:get_ann(col, Decl, 1) - 1;
_ -> 0 _ -> 0
end. end.
-spec to_sophia_value(string(), string(), ok | error | revert, binary()) -> -spec to_sophia_value(string(), string(), ok | error | revert, binary()) ->
{ok, aeso_syntax:expr()} | {error, [aeso_errors:error()]}. {ok, so_syntax:expr()} | {error, [so_errors:error()]}.
to_sophia_value(ContractString, Fun, ResType, Data) -> to_sophia_value(ContractString, Fun, ResType, Data) ->
to_sophia_value(ContractString, Fun, ResType, Data, []). to_sophia_value(ContractString, Fun, ResType, Data, []).
-spec to_sophia_value(string(), string(), ok | error | revert, binary(), options()) -> -spec to_sophia_value(string(), string(), ok | error | revert, binary(), options()) ->
{ok, aeso_syntax:expr()} | {error, [aeso_errors:error()]}. {ok, so_syntax:expr()} | {error, [so_errors:error()]}.
to_sophia_value(_, _, error, Err, _Options) -> to_sophia_value(_, _, error, Err, _Options) ->
{ok, {app, [], {id, [], "error"}, [{string, [], Err}]}}; {ok, {app, [], {id, [], "error"}, [{string, [], Err}]}};
to_sophia_value(_, _, revert, Data, _Options) -> to_sophia_value(_, _, revert, Data, _Options) ->
try aeso_vm_decode:from_fate({id, [], "string"}, aeb_fate_encoding:deserialize(Data)) of try so_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 _:_ ->
Msg = "Could not deserialize the revert message", Msg = "Could not deserialize the revert message",
{error, [aeso_errors:new(data_error, Msg)]} {error, [so_errors:new(data_error, Msg)]}
end; end;
to_sophia_value(ContractString, FunName, ok, Data, Options0) -> to_sophia_value(ContractString, FunName, ok, Data, Options0) ->
Options = [no_code | Options0], Options = [no_code | Options0],
@ -316,7 +317,7 @@ to_sophia_value(ContractString, FunName, ok, Data, Options0) ->
Code = string_to_code(ContractString, Options), Code = string_to_code(ContractString, Options),
#{ folded_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, Type = so_ast_infer_types:unfold_types_in_type(TypeEnv, Type0,
[ unfold_record_types [ unfold_record_types
, unfold_variant_types , unfold_variant_types
, not_unfold_system_alias_types]), , not_unfold_system_alias_types]),
@ -328,40 +329,40 @@ 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, so_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(so_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, [so_errors:new(data_error, Msg)]};
_:_ -> _:_ ->
Type1 = prettypr:format(aeso_pretty:type(Type)), Type1 = prettypr:format(so_pretty:type(Type)),
Msg = io_lib:format("Failed to decode binary as type ~s", [Type1]), Msg = io_lib:format("Failed to decode binary as type ~s", [Type1]),
{error, [aeso_errors:new(data_error, Msg)]} {error, [so_errors:new(data_error, Msg)]}
end. end.
-spec create_calldata(string(), string(), [string()]) -> -spec create_calldata(string(), string(), [string()]) ->
{ok, binary()} | {error, [aeso_errors:error()]}. {ok, binary()} | {error, [so_errors:error()]}.
create_calldata(Code, Fun, Args) -> create_calldata(Code, Fun, Args) ->
create_calldata(Code, Fun, Args, []). create_calldata(Code, Fun, Args, []).
-spec create_calldata(string(), string(), [string()], [{atom(), any()}]) -> -spec create_calldata(string(), string(), [string()], [{atom(), any()}]) ->
{ok, binary()} | {error, [aeso_errors:error()]}. {ok, binary()} | {error, [so_errors:error()]}.
create_calldata(Code, Fun, Args, Options0) -> create_calldata(Code, Fun, Args, Options0) ->
Options = [no_code | Options0], Options = [no_code | Options0],
case check_call(Code, Fun, Args, Options) of case check_call(Code, Fun, Args, Options) of
{ok, FunName, FateArgs} -> {ok, FunName, FateArgs} ->
aeb_fate_abi:create_calldata(FunName, FateArgs); gmb_fate_abi:create_calldata(FunName, FateArgs);
{error, _} = Err -> Err {error, _} = Err -> Err
end. end.
-spec decode_calldata(string(), string(), binary()) -> -spec decode_calldata(string(), string(), binary()) ->
{ok, [aeso_syntax:type()], [aeso_syntax:expr()]} {ok, [so_syntax:type()], [so_syntax:expr()]}
| {error, [aeso_errors:error()]}. | {error, [so_errors:error()]}.
decode_calldata(ContractString, FunName, Calldata) -> decode_calldata(ContractString, FunName, Calldata) ->
decode_calldata(ContractString, FunName, Calldata, []). decode_calldata(ContractString, FunName, Calldata, []).
-spec decode_calldata(string(), string(), binary(), options()) -> -spec decode_calldata(string(), string(), binary(), options()) ->
{ok, [aeso_syntax:type()], [aeso_syntax:expr()]} {ok, [so_syntax:type()], [so_syntax:expr()]}
| {error, [aeso_errors:error()]}. | {error, [so_errors:error()]}.
decode_calldata(ContractString, FunName, Calldata, Options0) -> decode_calldata(ContractString, FunName, Calldata, Options0) ->
Options = [no_code | Options0], Options = [no_code | Options0],
try try
@ -373,26 +374,26 @@ decode_calldata(ContractString, FunName, Calldata, Options0) ->
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, Type = so_ast_infer_types:unfold_types_in_type(TypeEnv, Type0,
[ unfold_record_types [ unfold_record_types
, unfold_variant_types , unfold_variant_types
, not_unfold_system_alias_types]), , not_unfold_system_alias_types]),
case aeb_fate_abi:decode_calldata(FunName, Calldata) of case gmb_fate_abi:decode_calldata(FunName, Calldata) of
{ok, FateArgs} -> {ok, FateArgs} ->
try try
{tuple_t, [], ArgTypes1} = Type, {tuple_t, [], ArgTypes1} = Type,
AstArgs = [ aeso_vm_decode:from_fate(ArgType, FateArg) AstArgs = [ so_vm_decode:from_fate(ArgType, FateArg)
|| {ArgType, FateArg} <- lists:zip(ArgTypes1, FateArgs)], || {ArgType, FateArg} <- lists:zip(ArgTypes1, FateArgs)],
{ok, ArgTypes, AstArgs} {ok, ArgTypes, AstArgs}
catch throw:cannot_translate_to_sophia -> catch throw:cannot_translate_to_sophia ->
Type0Str = prettypr:format(aeso_pretty:type(Type0)), Type0Str = prettypr:format(so_pretty:type(Type0)),
Msg = io_lib:format("Cannot translate FATE value ~p\n to Sophia type ~s", Msg = io_lib:format("Cannot translate FATE value ~p\n to Sophia type ~s",
[FateArgs, Type0Str]), [FateArgs, Type0Str]),
{error, [aeso_errors:new(data_error, Msg)]} {error, [so_errors:new(data_error, Msg)]}
end; end;
{error, _} -> {error, _} ->
Msg = io_lib:format("Failed to decode calldata binary", []), Msg = io_lib:format("Failed to decode calldata binary", []),
{error, [aeso_errors:new(data_error, Msg)]} {error, [so_errors:new(data_error, Msg)]}
end end
catch catch
throw:{error, Errors} -> {error, Errors} throw:{error, Errors} -> {error, Errors}
@ -410,8 +411,8 @@ get_decode_type(FunName, [{Contract, Ann, _, _, Defs}]) when ?IS_CONTRACT_HEAD(C
"init" -> {ok, [], {tuple_t, [], []}}; "init" -> {ok, [], {tuple_t, [], []}};
_ -> _ ->
Msg = io_lib:format("Function '~s' is missing in contract", [FunName]), Msg = io_lib:format("Function '~s' is missing in contract", [FunName]),
Pos = aeso_errors:pos(Ann), Pos = so_errors:pos(Ann),
aeso_errors:throw(aeso_errors:new(data_error, Pos, Msg)) so_errors:throw(so_errors:new(data_error, Pos, Msg))
end end
end; end;
get_decode_type(FunName, [_ | Contracts]) -> get_decode_type(FunName, [_ | Contracts]) ->
@ -419,12 +420,12 @@ get_decode_type(FunName, [_ | Contracts]) ->
get_decode_type(FunName, Contracts). get_decode_type(FunName, Contracts).
pp_sophia_code(C, Opts)-> pp(C, Opts, pp_sophia_code, fun(Code) -> pp_sophia_code(C, Opts)-> pp(C, Opts, pp_sophia_code, fun(Code) ->
io:format("~s\n", [prettypr:format(aeso_pretty:decls(Code))]) io:format("~s\n", [prettypr:format(so_pretty:decls(Code))])
end). end).
pp_ast(C, Opts) -> pp(C, Opts, pp_ast, fun aeso_ast:pp/1). pp_ast(C, Opts) -> pp(C, Opts, pp_ast, fun so_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 so_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
@ -438,18 +439,18 @@ pp(Code, Options, Option, PPFun) ->
-define(protect(Tag, Code), fun() -> try Code catch _:Err1 -> throw({Tag, Err1}) end end()). -define(protect(Tag, Code), fun() -> try Code catch _:Err1 -> throw({Tag, Err1}) end end()).
-spec validate_byte_code(map(), string(), options()) -> ok | {error, [aeso_errors:error()]}. -spec validate_byte_code(map(), string(), options()) -> ok | {error, [so_errors:error()]}.
validate_byte_code(#{ byte_code := ByteCode, payable := Payable }, Source, Options) -> validate_byte_code(#{ byte_code := ByteCode, payable := Payable }, Source, Options) ->
Fail = fun(Err) -> {error, [aeso_errors:new(data_error, Err)]} end, Fail = fun(Err) -> {error, [so_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 ->
@ -465,10 +466,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
@ -513,13 +514,13 @@ pp_fate_type(T) -> io_lib:format("~w", [T]).
%% ------------------------------------------------------------------- %% -------------------------------------------------------------------
-spec parse(string(), aeso_compiler:options()) -> none() | aeso_syntax:ast(). -spec parse(string(), so_compiler:options()) -> none() | so_syntax:ast().
parse(Text, Options) -> parse(Text, Options) ->
parse(Text, sets:new(), Options). parse(Text, sets:new(), Options).
-spec parse(string(), sets:set(), aeso_compiler:options()) -> none() | aeso_syntax:ast(). -spec parse(string(), sets:set(), so_compiler:options()) -> none() | so_syntax:ast().
parse(Text, Included, Options) -> parse(Text, Included, Options) ->
aeso_parser:string(Text, Included, Options). so_parser:string(Text, Included, Options).
read_contract(Name) -> read_contract(Name) ->
file:read_file(Name). file:read_file(Name).

View File

@ -1,11 +1,13 @@
%%%------------------------------------------------------------------- %%%-------------------------------------------------------------------
%%% @copyright (C) 2025, QPQ AG
%%% @copyright (C) 2019, Aeternity Anstalt %%% @copyright (C) 2019, Aeternity Anstalt
%%% @doc ADT for structured error messages + formatting. %%% @doc ADT for structured error messages + formatting.
%%% %%%
%%% @end %%% @end
%%%------------------------------------------------------------------- %%%-------------------------------------------------------------------
-module(aeso_errors). -module(so_errors).
-vsn("9.0.0").
-type src_file() :: no_file | iolist(). -type src_file() :: no_file | iolist().
@ -55,9 +57,9 @@ new(Type, Pos, Msg, Ctxt) ->
#err{ type = Type, pos = Pos, message = Msg, context = Ctxt }. #err{ type = Type, pos = Pos, message = Msg, context = Ctxt }.
pos(Ann) -> pos(Ann) ->
File = aeso_syntax:get_ann(file, Ann, no_file), File = so_syntax:get_ann(file, Ann, no_file),
Line = aeso_syntax:get_ann(line, Ann, 0), Line = so_syntax:get_ann(line, Ann, 0),
Col = aeso_syntax:get_ann(col, Ann, 0), Col = so_syntax:get_ann(col, Ann, 0),
pos(File, Line, Col). pos(File, Line, Col).
pos(Line, Col) -> pos(Line, Col) ->

View File

@ -1,13 +1,13 @@
%%%------------------------------------------------------------------- %%%-------------------------------------------------------------------
%%% @author Ulf Norell %%% @author Ulf Norell
%%% @copyright (C) 2025, QPQ AG
%%% @copyright (C) 2019, Aeternity Anstalt %%% @copyright (C) 2019, Aeternity Anstalt
%%% @doc %%% @doc
%%% Fate backend for Sophia compiler %%% Fate backend for Sophia compiler
%%% @end %%% @end
%%% Created : 11 Jan 2019
%%%
%%%------------------------------------------------------------------- %%%-------------------------------------------------------------------
-module(aeso_fcode_to_fate). -module(so_fcode_to_fate).
-vsn("9.0.0").
-export([compile/3, compile/4, term_to_fate/1, term_to_fate/2]). -export([compile/3, compile/4, term_to_fate/1, term_to_fate/2]).
@ -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()].
@ -72,9 +72,9 @@ debug(Tag, Options, Fun) ->
-dialyzer({nowarn_function, [code_error/1]}). -dialyzer({nowarn_function, [code_error/1]}).
code_error(Err) -> code_error(Err) ->
Pos = aeso_errors:pos(0, 0), Pos = so_errors:pos(0, 0),
Msg = lists:flatten(io_lib:format("Unknown error: ~p\n", [Err])), Msg = lists:flatten(io_lib:format("Unknown error: ~p\n", [Err])),
aeso_errors:throw(aeso_errors:new(code_error, Pos, Msg)). so_errors:throw(so_errors:new(code_error, Pos, Msg)).
%% -- Main ------------------------------------------------------------------- %% -- Main -------------------------------------------------------------------
@ -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),
@ -140,8 +140,6 @@ type_to_scode(string) -> string;
type_to_scode(address) -> address; type_to_scode(address) -> address;
type_to_scode({bytes, N}) -> {bytes, N}; type_to_scode({bytes, N}) -> {bytes, N};
type_to_scode(contract) -> contract; type_to_scode(contract) -> contract;
type_to_scode({oracle, _, _}) -> oracle;
type_to_scode(oracle_query) -> oracle_query;
type_to_scode(name) -> name; type_to_scode(name) -> name;
type_to_scode(channel) -> channel; type_to_scode(channel) -> channel;
type_to_scode(bits) -> bits; type_to_scode(bits) -> bits;
@ -212,17 +210,17 @@ 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} = so_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 = gmser_contract_code:serialize(Code),
put(contract_code_cache, maps:put(C, Serialized, Cache)), put(contract_code_cache, maps:put(C, Serialized, Cache)),
Serialized; Serialized;
Serialized -> Serialized Serialized -> Serialized
@ -230,17 +228,15 @@ 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);
{signature, S} -> aeb_fate_data:make_bytes(S); {signature, S} -> gmb_fate_data:make_bytes(S);
{contract_pubkey, K} -> aeb_fate_data:make_contract(K); {contract_pubkey, K} -> gmb_fate_data:make_contract(K);
{oracle_pubkey, K} -> aeb_fate_data:make_oracle(K); {contract_code, C} -> gmb_fate_data:make_contract_bytearray(serialize_contract_code(Env, C));
{oracle_query_id, H} -> aeb_fate_data:make_oracle_query(H); {typerep, T} -> gmb_fate_data:make_typerep(type_to_scode(T))
{contract_code, C} -> aeb_fate_data:make_contract_bytearray(serialize_contract_code(Env, C));
{typerep, T} -> aeb_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).
@ -250,21 +246,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),
@ -282,7 +278,7 @@ 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)};
@ -304,7 +300,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)) ];
@ -313,7 +309,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),
@ -324,13 +320,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) ];
@ -341,7 +337,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) ];
@ -355,18 +351,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) ];
@ -377,23 +373,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 ];
@ -409,8 +405,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))];
@ -448,13 +444,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),
@ -488,9 +484,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, []).
@ -504,10 +500,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]) ->
@ -526,239 +522,215 @@ 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) ->
call_to_scode(Env, aeb_fate_ops:oracle_register(?a, ?a, ?a, ?a, ?a, ?a, ?a), Args);
builtin_to_scode(Env, oracle_expiry, [_Oracle] = Args) ->
call_to_scode(Env, aeb_fate_ops:oracle_expiry(?a, ?a), Args);
builtin_to_scode(Env, oracle_query_fee, [_Oracle] = Args) ->
call_to_scode(Env, aeb_fate_ops:oracle_query_fee(?a, ?a), 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);
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);
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),
tuple(0)], Args);
builtin_to_scode(Env, oracle_extend, [_Sign, _Oracle, _TTL] = Args) ->
call_to_scode(Env, [aeb_fate_ops:oracle_extend(?a, ?a, ?a),
tuple(0)], 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);
builtin_to_scode(Env, oracle_check, [_Oracle, _QType, _RType] = Args) ->
call_to_scode(Env, aeb_fate_ops:oracle_check(?a, ?a, ?a, ?a), 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);
builtin_to_scode(Env, address_is_oracle, [_] = Args) ->
call_to_scode(Env, aeb_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 --
@ -825,8 +797,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.
@ -898,7 +870,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]);
@ -1668,14 +1640,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;
@ -1695,11 +1667,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.
@ -1770,7 +1742,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
@ -1945,14 +1917,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.

View File

@ -1,12 +1,14 @@
%%% -*- erlang-indent-level:4; indent-tabs-mode: nil -*- %%% -*- erlang-indent-level:4; indent-tabs-mode: nil -*-
%%%------------------------------------------------------------------- %%%-------------------------------------------------------------------
%%% @copyright (C) 2025, QPQ AG
%%% @copyright (C) 2018, Aeternity Anstalt %%% @copyright (C) 2018, Aeternity Anstalt
%%% @doc Parser combinators for the Sophia parser. Based on %%% @doc Parser combinators for the Sophia parser. Based on
%%% Koen Claessen. 2004. Parallel Parsing Processes. J. Functional %%% Koen Claessen. 2004. Parallel Parsing Processes. J. Functional
%%% Programming 14, 6 (November 2004) %%% Programming 14, 6 (November 2004)
%%% @end %%% @end
%%%------------------------------------------------------------------- %%%-------------------------------------------------------------------
-module(aeso_parse_lib). -module(so_parse_lib).
-vsn("9.0.0").
-export([parse/2, -export([parse/2,
return/1, fail/0, fail/1, fail/2, map/2, bind/2, return/1, fail/0, fail/1, fail/2, map/2, bind/2,
@ -27,16 +29,16 @@
-type tokens() :: [token()]. -type tokens() :: [token()].
-type error() :: {pos(), string() | no_error}. -type error() :: {pos(), string() | no_error}.
-define(lazy(F), {aeso_parse_lazy, F}). -define(lazy(F), {so_parse_lazy, F}).
-define(fail(Err), {aeso_parse_fail, Err}). -define(fail(Err), {so_parse_fail, Err}).
-define(choice(Ps), {aeso_parse_choice, Ps}). -define(choice(Ps), {so_parse_choice, Ps}).
-define(bind(P, F), {aeso_parse_bind, P, F}). -define(bind(P, F), {so_parse_bind, P, F}).
-define(right(P, Q), {aeso_parse_right, P, Q}). -define(right(P, Q), {so_parse_right, P, Q}).
-define(left(P, Q), {aeso_parse_left, P, Q}). -define(left(P, Q), {so_parse_left, P, Q}).
-define(map(F, P), {aeso_parse_map, F, P}). -define(map(F, P), {so_parse_map, F, P}).
-define(layout, aeso_parse_layout). -define(layout, so_parse_layout).
-define(tok(Atom), {aeso_parse_tok, Atom}). -define(tok(Atom), {so_parse_tok, Atom}).
-define(return(X), {aeso_parse_return, X}). -define(return(X), {so_parse_return, X}).
%% Type synonyms since you can't have function types as macro arguments for some reason. %% Type synonyms since you can't have function types as macro arguments for some reason.
-type delayed(A) :: fun(() -> A). -type delayed(A) :: fun(() -> A).

View File

@ -1,8 +1,9 @@
%%% File : aeso_parser.erl %%% File : so_parser.erl
%%% Author : Ulf Norell %%% Author : Ulf Norell
%%% Description : %%% Description :
%%% Created : 1 Mar 2018 by Ulf Norell %%% Created : 1 Mar 2018 by Ulf Norell
-module(aeso_parser). -module(so_parser).
-vsn("9.0.0").
-compile({no_auto_import,[map_get/2]}). -compile({no_auto_import,[map_get/2]}).
-export([string/1, -export([string/1,
@ -17,12 +18,12 @@
run_parser/2, run_parser/2,
run_parser/3]). run_parser/3]).
-include("aeso_parse_lib.hrl"). -include("so_parse_lib.hrl").
-import(aeso_parse_lib, [current_file/0, set_current_file/1, -import(so_parse_lib, [current_file/0, set_current_file/1,
current_dir/0, set_current_dir/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() :: so_syntax:ast() | {so_syntax:ast(), sets:set(include_hash())} | none().
-type include_hash() :: {string(), binary()}. -type include_hash() :: {string(), binary()}.
@ -36,14 +37,14 @@ escape_errors({error, Err}) ->
string(String) -> string(String) ->
string(String, sets:new(), []). string(String, sets:new(), []).
-spec string(string(), aeso_compiler:options()) -> parse_result(). -spec string(string(), so_compiler:options()) -> parse_result().
string(String, Opts) -> string(String, Opts) ->
case lists:keyfind(src_file, 1, Opts) of case lists:keyfind(src_file, 1, Opts) of
{src_file, File} -> string(String, sets:add_element(File, sets:new()), Opts); {src_file, File} -> string(String, sets:add_element(File, sets:new()), Opts);
false -> string(String, sets:new(), Opts) false -> string(String, sets:new(), Opts)
end. end.
-spec string(string(), sets:set(include_hash()), aeso_compiler:options()) -> parse_result(). -spec string(string(), sets:set(include_hash()), so_compiler:options()) -> parse_result().
string(String, Included, Opts) -> string(String, Included, Opts) ->
AST = run_parser(file(), String, Opts), AST = run_parser(file(), String, Opts),
case expand_includes(AST, Included, Opts) of case expand_includes(AST, Included, Opts) of
@ -61,18 +62,18 @@ 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_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 so_scan:scan(S) of
{ok, Tokens} -> aeso_parse_lib:parse(P, Tokens); {ok, Tokens} -> so_parse_lib:parse(P, Tokens);
{error, {{Input, Pos}, _}} -> {error, {{Input, Pos}, _}} ->
{error, {Pos, scan_error, Input}} {error, {Pos, scan_error, Input}}
end. end.
-dialyzer({nowarn_function, parse_error/1}). -dialyzer({nowarn_function, parse_error/1}).
parse_error(Err) -> parse_error(Err) ->
aeso_errors:throw(mk_error(Err)). so_errors:throw(mk_error(Err)).
mk_p_err(Pos, Msg) -> mk_p_err(Pos, Msg) ->
aeso_errors:new(parse_error, mk_pos(Pos), lists:flatten(Msg)). so_errors:new(parse_error, mk_pos(Pos), lists:flatten(Msg)).
mk_error({Pos, scan_error, Input}) -> mk_error({Pos, scan_error, Input}) ->
mk_p_err(Pos, io_lib:format("Lexical error on input: ~s\n", [Input])); mk_p_err(Pos, io_lib:format("Lexical error on input: ~s\n", [Input]));
@ -86,8 +87,8 @@ mk_error({Pos, include_error, File}) ->
Msg = io_lib:format("Couldn't find include file '~s'\n", [File]), Msg = io_lib:format("Couldn't find include file '~s'\n", [File]),
mk_p_err(Pos, Msg). mk_p_err(Pos, Msg).
mk_pos({Line, Col}) -> aeso_errors:pos(Line, Col); mk_pos({Line, Col}) -> so_errors:pos(Line, Col);
mk_pos({File, Line, Col}) -> aeso_errors:pos(File, Line, Col). mk_pos({File, Line, Col}) -> so_errors:pos(File, Line, Col).
%% -- Parsing rules ---------------------------------------------------------- %% -- Parsing rules ----------------------------------------------------------
@ -411,7 +412,7 @@ map_key(Key, {ok, {_, Val}}) -> {map_key, Key, Val}.
elim(E, []) -> E; elim(E, []) -> E;
elim(E, [{proj, Ann, P} | Es]) -> elim({proj, Ann, E, P}, Es); elim(E, [{proj, Ann, P} | Es]) -> elim({proj, Ann, E, P}, Es);
elim(E, [{app, _Ann, Args} | Es]) -> elim({app, aeso_syntax:get_ann(E), E, Args}, Es); elim(E, [{app, _Ann, Args} | Es]) -> elim({app, so_syntax:get_ann(E), E, Args}, Es);
elim(E, [{rec_upd, Ann, Flds} | Es]) -> elim(record_update(Ann, E, Flds), Es); elim(E, [{rec_upd, Ann, Flds} | Es]) -> elim(record_update(Ann, E, Flds), Es);
elim(E, [{map_get, Ann, Key} | Es]) -> elim({map_get, Ann, E, Key}, Es); elim(E, [{map_get, Ann, Key} | Es]) -> elim({map_get, Ann, E, Key}, Es);
elim(E, [{map_get, Ann, Key, Val} | Es]) -> elim({map_get, Ann, E, Key, Val}, Es). elim(E, [{map_get, Ann, Key, Val} | Es]) -> elim({map_get, Ann, E, Key, Val}, Es).
@ -528,7 +529,7 @@ parse_addr_literal(Id = {id, Ann, Name}) ->
case lists:member(lists:sublist(Name, 3), ["ak_", "ok_", "oq_", "ct_", "sg_"]) of case lists:member(lists:sublist(Name, 3), ["ak_", "ok_", "oq_", "ct_", "sg_"]) of
false -> Id; false -> Id;
true -> true ->
try aeser_api_encoder:decode(list_to_binary(Name)) of try gmser_api_encoder:decode(list_to_binary(Name)) of
{Type, Bin} -> {Type, Ann, Bin} {Type, Bin} -> {Type, Ann, Bin}
catch _:_ -> catch _:_ ->
Id Id
@ -557,9 +558,9 @@ bracket_list(P) -> brackets(comma_sep(P)).
%% -- Annotations ------------------------------------------------------------ %% -- Annotations ------------------------------------------------------------
-type ann() :: aeso_syntax:ann(). -type ann() :: so_syntax:ann().
-type ann_line() :: aeso_syntax:ann_line(). -type ann_line() :: so_syntax:ann_line().
-type ann_col() :: aeso_syntax:ann_col(). -type ann_col() :: so_syntax:ann_col().
-spec pos_ann(ann_line(), ann_col()) -> ann(). -spec pos_ann(ann_line(), ann_col()) -> ann().
pos_ann(Line, Col) -> pos_ann(Line, Col) ->
@ -647,7 +648,7 @@ tuple_e(Ann, Exprs) -> {tuple, Ann, Exprs}.
list_comp_e(Ann, Expr, Binds) -> {list_comp, Ann, Expr, Binds}. list_comp_e(Ann, Expr, Binds) -> {list_comp, Ann, Expr, Binds}.
-spec parse_pattern(aeso_syntax:expr()) -> aeso_parse_lib:parser(aeso_syntax:pat()). -spec parse_pattern(so_syntax:expr()) -> so_parse_lib:parser(so_syntax:pat()).
parse_pattern({letpat, Ann, Id, Pat}) -> parse_pattern({letpat, Ann, Id, Pat}) ->
{letpat, Ann, Id, parse_pattern(Pat)}; {letpat, Ann, Id, parse_pattern(Pat)};
parse_pattern({app, Ann, Con = {'::', _}, Es}) -> parse_pattern({app, Ann, Con = {'::', _}, Es}) ->
@ -674,19 +675,19 @@ parse_pattern(E = {string, _, _}) -> E;
parse_pattern(E = {char, _, _}) -> E; parse_pattern(E = {char, _, _}) -> E;
parse_pattern(E) -> bad_expr_err("Not a valid pattern", E). parse_pattern(E) -> bad_expr_err("Not a valid pattern", E).
-spec parse_field_pattern(aeso_syntax:field(aeso_syntax:expr())) -> aeso_parse_lib:parser(aeso_syntax:field(aeso_syntax:pat())). -spec parse_field_pattern(so_syntax:field(so_syntax:expr())) -> so_parse_lib:parser(so_syntax:field(so_syntax:pat())).
parse_field_pattern({field, Ann, F, E}) -> parse_field_pattern({field, Ann, F, E}) ->
{field, Ann, F, parse_pattern(E)}. {field, Ann, F, parse_pattern(E)}.
-spec ret_doc_err(ann(), prettypr:document()) -> aeso_parse_lib:parser(none()). -spec ret_doc_err(ann(), prettypr:document()) -> so_parse_lib:parser(none()).
ret_doc_err(Ann, Doc) -> ret_doc_err(Ann, Doc) ->
fail(ann_pos(Ann), prettypr:format(Doc)). fail(ann_pos(Ann), prettypr:format(Doc)).
-spec bad_expr_err(string(), aeso_syntax:expr()) -> aeso_parse_lib:parser(none()). -spec bad_expr_err(string(), so_syntax:expr()) -> so_parse_lib:parser(none()).
bad_expr_err(Reason, E) -> bad_expr_err(Reason, E) ->
ret_doc_err(get_ann(E), ret_doc_err(get_ann(E),
prettypr:sep([prettypr:text(Reason ++ ":"), prettypr:sep([prettypr:text(Reason ++ ":"),
prettypr:nest(2, aeso_pretty:expr(E))])). prettypr:nest(2, so_pretty:expr(E))])).
%% -- Helper functions ------------------------------------------------------- %% -- Helper functions -------------------------------------------------------
@ -748,7 +749,7 @@ read_file(File, Opts) ->
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, escript, Src}; {ok, [{_, Src}]} -> {ok, escript, Src};
_ -> {error, not_found} _ -> {error, not_found}
@ -761,12 +762,12 @@ read_file(File, Opts) ->
read_file_(Path, File) -> read_file_(Path, File) ->
AbsFile = filename:join(Path, File), AbsFile = filename:join(Path, File),
case file:read_file(AbsFile) of case file:read_file(AbsFile) of
{ok, Bin} -> {ok, aeso_utils:canonical_dir(filename:dirname(AbsFile)), Bin}; {ok, Bin} -> {ok, so_utils:canonical_dir(filename:dirname(AbsFile)), Bin};
Err -> Err Err -> Err
end. end.
stdlib_options() -> stdlib_options() ->
StdLibDir = aeso_stdlib:stdlib_include_path(), StdLibDir = so_stdlib:stdlib_include_path(),
case filelib:is_dir(StdLibDir) of case filelib:is_dir(StdLibDir) of
true -> [{include, {file_system, [StdLibDir]}}]; true -> [{include, {file_system, [StdLibDir]}}];
false -> [{include, escript}] false -> [{include, escript}]

View File

@ -1,11 +1,13 @@
%%% -*- erlang-indent-level:4; indent-tabs-mode: nil -*- %%% -*- erlang-indent-level:4; indent-tabs-mode: nil -*-
%%%------------------------------------------------------------------- %%%-------------------------------------------------------------------
%%% @copyright (C) 2025, QPQ AG
%%% @copyright (C) 2017, Aeternity Anstalt %%% @copyright (C) 2017, Aeternity Anstalt
%%% @doc Pretty printer for Sophia. %%% @doc Pretty printer for Sophia.
%%% %%%
%%% @end %%% @end
%%%------------------------------------------------------------------- %%%-------------------------------------------------------------------
-module(aeso_pretty). -module(so_pretty).
-vsn("9.0.0").
-import(prettypr, [text/1, sep/1, above/2, beside/2, nest/2, empty/0]). -import(prettypr, [text/1, sep/1, above/2, beside/2, nest/2, empty/0]).
@ -13,7 +15,7 @@
-export_type([options/0]). -export_type([options/0]).
-include("aeso_utils.hrl"). -include("so_utils.hrl").
-type doc() :: prettypr:document(). -type doc() :: prettypr:document().
-type options() :: [{indent, non_neg_integer()} | show_generated]. -type options() :: [{indent, non_neg_integer()} | show_generated].
@ -24,11 +26,11 @@
%% -- Options ---------------------------------------------------------------- %% -- Options ----------------------------------------------------------------
-define(aeso_pretty_opts, aeso_pretty_opts). -define(so_pretty_opts, so_pretty_opts).
-spec options() -> options(). -spec options() -> options().
options() -> options() ->
case get(?aeso_pretty_opts) of case get(?so_pretty_opts) of
undefined -> []; undefined -> [];
Opts -> Opts Opts -> Opts
end. end.
@ -45,9 +47,9 @@ indent() -> option(indent, 2).
-spec with_options(options(), fun(() -> A)) -> A. -spec with_options(options(), fun(() -> A)) -> A.
with_options(Options, Fun) -> with_options(Options, Fun) ->
put(?aeso_pretty_opts, Options), put(?so_pretty_opts, Options),
Res = Fun(), Res = Fun(),
erase(?aeso_pretty_opts), erase(?so_pretty_opts),
Res. Res.
%% -- Pretty printing helpers ------------------------------------------------ %% -- Pretty printing helpers ------------------------------------------------
@ -125,9 +127,9 @@ record(Ds) ->
equals(A, B) -> follow(hsep(A, text("=")), B). equals(A, B) -> follow(hsep(A, text("=")), B).
%% typed(A, B) -> A : B. %% typed(A, B) -> A : B.
-spec typed(doc(), aeso_syntax:type()) -> doc(). -spec typed(doc(), so_syntax:type()) -> doc().
typed(A, Type) -> typed(A, Type) ->
case aeso_syntax:get_ann(origin, Type) == system andalso case so_syntax:get_ann(origin, Type) == system andalso
not show_generated() of not show_generated() of
true -> A; true -> A;
false -> follow(hsep(A, text(":")), type(Type)) false -> follow(hsep(A, text(":")), type(Type))
@ -139,18 +141,18 @@ contract_head(contract_interface) -> text("contract interface").
%% -- Exports ---------------------------------------------------------------- %% -- Exports ----------------------------------------------------------------
-spec decls([aeso_syntax:decl()], options()) -> doc(). -spec decls([so_syntax:decl()], options()) -> doc().
decls(Ds, Options) -> decls(Ds, Options) ->
with_options(Options, fun() -> decls(Ds) end). with_options(Options, fun() -> decls(Ds) end).
-spec decls([aeso_syntax:decl()]) -> doc(). -spec decls([so_syntax:decl()]) -> doc().
decls(Ds) -> above([ decl(D) || D <- Ds ]). decls(Ds) -> above([ decl(D) || D <- Ds ]).
-spec decl(aeso_syntax:decl(), options()) -> doc(). -spec decl(so_syntax:decl(), options()) -> doc().
decl(D, Options) -> decl(D, Options) ->
with_options(Options, fun() -> decl(D) end). with_options(Options, fun() -> decl(D) end).
-spec decl(aeso_syntax:decl()) -> doc(). -spec decl(so_syntax:decl()) -> doc().
decl({Con, Attrs, C, Is, Ds}) when ?IS_CONTRACT_HEAD(Con) -> decl({Con, Attrs, C, Is, Ds}) when ?IS_CONTRACT_HEAD(Con) ->
Mod = fun({Mod, true}) when Mod == payable -> Mod = fun({Mod, true}) when Mod == payable ->
text(atom_to_list(Mod)); text(atom_to_list(Mod));
@ -172,7 +174,7 @@ decl({fun_decl, Ann, F, T}) ->
Mod = fun({Mod, true}) when Mod == private; Mod == stateful; Mod == payable -> Mod = fun({Mod, true}) when Mod == private; Mod == stateful; Mod == payable ->
text(atom_to_list(Mod)); text(atom_to_list(Mod));
(_) -> empty() end, (_) -> empty() end,
Fun = case aeso_syntax:get_ann(entrypoint, Ann, false) of Fun = case so_syntax:get_ann(entrypoint, Ann, false) of
true -> text("entrypoint"); true -> text("entrypoint");
false -> text("function") false -> text("function")
end, end,
@ -181,7 +183,7 @@ decl(D = {letfun, Attrs, _, _, _, _}) ->
Mod = fun({Mod, true}) when Mod == private; Mod == stateful; Mod == payable -> Mod = fun({Mod, true}) when Mod == private; Mod == stateful; Mod == payable ->
text(atom_to_list(Mod)); text(atom_to_list(Mod));
(_) -> empty() end, (_) -> empty() end,
Fun = case aeso_syntax:get_ann(entrypoint, Attrs, false) of Fun = case so_syntax:get_ann(entrypoint, Attrs, false) of
true -> "entrypoint"; true -> "entrypoint";
false -> "function" false -> "function"
end, end,
@ -192,20 +194,20 @@ decl(D = {letval, _, _, _}) -> letdecl("let", D);
decl({block, _, Ds}) -> decl({block, _, Ds}) ->
above([ decl(D) || D <- Ds ]). above([ decl(D) || D <- Ds ]).
-spec pragma(aeso_syntax:pragma()) -> doc(). -spec pragma(so_syntax:pragma()) -> doc().
pragma({compiler, Op, Ver}) -> pragma({compiler, Op, Ver}) ->
text("@compiler " ++ atom_to_list(Op) ++ " " ++ string:join([integer_to_list(N) || N <- Ver], ".")). text("@compiler " ++ atom_to_list(Op) ++ " " ++ string:join([integer_to_list(N) || N <- Ver], ".")).
-spec expr(aeso_syntax:expr(), options()) -> doc(). -spec expr(so_syntax:expr(), options()) -> doc().
expr(E, Options) -> expr(E, Options) ->
with_options(Options, fun() -> expr(E) end). with_options(Options, fun() -> expr(E) end).
-spec expr(aeso_syntax:expr()) -> doc(). -spec expr(so_syntax:expr()) -> doc().
expr(E) -> expr_p(0, E). expr(E) -> expr_p(0, E).
%% -- Not exported ----------------------------------------------------------- %% -- Not exported -----------------------------------------------------------
-spec name(aeso_syntax:id() | aeso_syntax:qid() | aeso_syntax:con() | aeso_syntax:qcon() | aeso_syntax:tvar()) -> doc(). -spec name(so_syntax:id() | so_syntax:qid() | so_syntax:con() | so_syntax:qcon() | so_syntax:tvar()) -> doc().
name({id, _, Name}) -> text(Name); name({id, _, Name}) -> text(Name);
name({con, _, Name}) -> text(Name); name({con, _, Name}) -> text(Name);
name({qid, _, Names}) -> text(string:join(Names, ".")); name({qid, _, Names}) -> text(string:join(Names, "."));
@ -213,7 +215,7 @@ name({qcon, _, Names}) -> text(string:join(Names, "."));
name({tvar, _, Name}) -> text(Name); name({tvar, _, Name}) -> text(Name);
name({typed, _, Name, _}) -> name(Name). name({typed, _, Name, _}) -> name(Name).
-spec letdecl(string(), aeso_syntax:letbind()) -> doc(). -spec letdecl(string(), so_syntax:letbind()) -> doc().
letdecl(Let, {letval, _, P, E}) -> letdecl(Let, {letval, _, P, E}) ->
block_expr(0, hsep([text(Let), expr(P), text("=")]), E); block_expr(0, hsep([text(Let), expr(P), text("=")]), E);
letdecl(Let, {letfun, _, F, Args, T, [GuardedBody]}) -> letdecl(Let, {letfun, _, F, Args, T, [GuardedBody]}) ->
@ -221,14 +223,14 @@ letdecl(Let, {letfun, _, F, Args, T, [GuardedBody]}) ->
letdecl(Let, {letfun, _, F, Args, T, GuardedBodies}) -> letdecl(Let, {letfun, _, F, Args, T, GuardedBodies}) ->
block(hsep([text(Let), typed(beside(name(F), expr({tuple, [], Args})), T)]), above(lists:map(fun(GB) -> guarded_body(GB, "=") end, GuardedBodies))). block(hsep([text(Let), typed(beside(name(F), expr({tuple, [], Args})), T)]), above(lists:map(fun(GB) -> guarded_body(GB, "=") end, GuardedBodies))).
-spec args([aeso_syntax:arg()]) -> doc(). -spec args([so_syntax:arg()]) -> doc().
args(Args) -> args(Args) ->
tuple(lists:map(fun arg/1, Args)). tuple(lists:map(fun arg/1, Args)).
-spec arg(aeso_syntax:arg()) -> doc(). -spec arg(so_syntax:arg()) -> doc().
arg({arg, _, X, T}) -> typed(name(X), T). arg({arg, _, X, T}) -> typed(name(X), T).
-spec typedecl(alias_t | record_t | variant_t, aeso_syntax:id(), [aeso_syntax:tvar()]) -> doc(). -spec typedecl(alias_t | record_t | variant_t, so_syntax:id(), [so_syntax:tvar()]) -> doc().
typedecl(Kind, T, Vars) -> typedecl(Kind, T, Vars) ->
KW = case Kind of KW = case Kind of
alias_t -> text("type"); alias_t -> text("type");
@ -241,26 +243,26 @@ typedecl(Kind, T, Vars) ->
tuple(lists:map(fun name/1, Vars))) tuple(lists:map(fun name/1, Vars)))
end. end.
-spec typedef(aeso_syntax:typedef()) -> doc(). -spec typedef(so_syntax:typedef()) -> doc().
typedef({alias_t, Type}) -> type(Type); typedef({alias_t, Type}) -> type(Type);
typedef({record_t, Fields}) -> typedef({record_t, Fields}) ->
record(lists:map(fun field_t/1, Fields)); record(lists:map(fun field_t/1, Fields));
typedef({variant_t, Constructors}) -> typedef({variant_t, Constructors}) ->
par(punctuate(text(" |"), lists:map(fun constructor_t/1, Constructors))). par(punctuate(text(" |"), lists:map(fun constructor_t/1, Constructors))).
-spec constructor_t(aeso_syntax:constructor_t()) -> doc(). -spec constructor_t(so_syntax:constructor_t()) -> doc().
constructor_t({constr_t, _, C, []}) -> name(C); constructor_t({constr_t, _, C, []}) -> name(C);
constructor_t({constr_t, _, C, Args}) -> beside(name(C), args_type(Args)). constructor_t({constr_t, _, C, Args}) -> beside(name(C), args_type(Args)).
-spec field_t(aeso_syntax:field_t()) -> doc(). -spec field_t(so_syntax:field_t()) -> doc().
field_t({field_t, _, Name, Type}) -> field_t({field_t, _, Name, Type}) ->
typed(name(Name), Type). typed(name(Name), Type).
-spec type(aeso_syntax:type(), options()) -> doc(). -spec type(so_syntax:type(), options()) -> doc().
type(Type, Options) -> type(Type, Options) ->
with_options(Options, fun() -> type(Type) end). with_options(Options, fun() -> type(Type) end).
-spec type(aeso_syntax:type()) -> doc(). -spec type(so_syntax:type()) -> doc().
type(F = {fun_t, _, _, var_args, _}) -> type(F = {fun_t, _, _, var_args, _}) ->
type(setelement(4, F, [var_args])); type(setelement(4, F, [var_args]));
type({fun_t, _, Named, Args, Ret}) -> type({fun_t, _, Named, Args, Ret}) ->
@ -296,11 +298,11 @@ type(T = {tvar, _, _}) -> name(T);
type(var_args) -> text("var_args"). type(var_args) -> text("var_args").
-spec args_type([aeso_syntax:type()]) -> doc(). -spec args_type([so_syntax:type()]) -> doc().
args_type(Args) -> args_type(Args) ->
tuple(lists:map(fun type/1, Args)). tuple(lists:map(fun type/1, Args)).
-spec tuple_type([aeso_syntax:type()]) -> doc(). -spec tuple_type([so_syntax:type()]) -> doc().
tuple_type([]) -> tuple_type([]) ->
text("unit"); text("unit");
tuple_type(Factors) -> tuple_type(Factors) ->
@ -310,7 +312,7 @@ tuple_type(Factors) ->
, text(")") , text(")")
]). ]).
-spec expr_p(integer(), aeso_syntax:arg_expr()) -> doc(). -spec expr_p(integer(), so_syntax:arg_expr()) -> doc().
expr_p(P, {letpat, _, Id, Pat}) -> expr_p(P, {letpat, _, Id, Pat}) ->
paren(P > 100, follow(hsep(expr(Id), text("=")), expr(Pat))); paren(P > 100, follow(hsep(expr(Id), text("=")), expr(Pat)));
expr_p(P, {named_arg, _, Name, E}) -> expr_p(P, {named_arg, _, Name, E}) ->
@ -318,7 +320,7 @@ expr_p(P, {named_arg, _, Name, E}) ->
expr_p(P, {lam, _, Args, E}) -> expr_p(P, {lam, _, Args, E}) ->
paren(P > 100, follow(hsep(args(Args), text("=>")), expr_p(100, E))); paren(P > 100, follow(hsep(args(Args), text("=>")), expr_p(100, E)));
expr_p(P, If = {'if', Ann, Cond, Then, Else}) -> expr_p(P, If = {'if', Ann, Cond, Then, Else}) ->
Format = aeso_syntax:get_ann(format, If), Format = so_syntax:get_ann(format, If),
if Format == '?:' -> if Format == '?:' ->
paren(P > 100, paren(P > 100,
follow(expr_p(200, Cond), follow(expr_p(200, Cond),
@ -361,7 +363,7 @@ expr_p(P, {assign, _, LV, E}) ->
expr_p(_, {app, _, {'..', _}, [A, B]}) -> expr_p(_, {app, _, {'..', _}, [A, B]}) ->
list([infix(0, '..', A, B)]); list([infix(0, '..', A, B)]);
expr_p(P, E = {app, _, F = {Op, _}, Args}) when is_atom(Op) -> expr_p(P, E = {app, _, F = {Op, _}, Args}) when is_atom(Op) ->
case {aeso_syntax:get_ann(format, E), Args} of case {so_syntax:get_ann(format, E), Args} of
{infix, [A, B]} -> infix(P, Op, A, B); {infix, [A, B]} -> infix(P, Op, A, B);
{prefix, [A]} -> prefix(P, Op, A); {prefix, [A]} -> prefix(P, Op, A);
_ -> app(P, F, Args) _ -> app(P, F, Args)
@ -372,7 +374,7 @@ expr_p(P, {app, _, F, Args}) ->
app(P, F, Args); app(P, F, Args);
%% -- Constants %% -- Constants
expr_p(_, E = {int, _, N}) -> expr_p(_, E = {int, _, N}) ->
S = case aeso_syntax:get_ann(format, E) of S = case so_syntax:get_ann(format, E) of
hex -> "0x" ++ integer_to_list(N, 16); hex -> "0x" ++ integer_to_list(N, 16);
_ -> integer_to_list(N) _ -> integer_to_list(N)
end, end,
@ -389,7 +391,7 @@ expr_p(_, {Type, _, Bin})
Type == oracle_pubkey; Type == oracle_pubkey;
Type == oracle_query_id; Type == oracle_query_id;
Type == signature -> Type == signature ->
text(binary_to_list(aeser_api_encoder:encode(Type, Bin))); text(binary_to_list(gmser_api_encoder:encode(Type, Bin)));
expr_p(_, {string, _, <<>>}) -> text("\"\""); expr_p(_, {string, _, <<>>}) -> text("\"\"");
expr_p(_, {string, _, S}) -> expr_p(_, {string, _, S}) ->
text(io_lib:format("\"~s\"", [binary_to_list(S)])); text(io_lib:format("\"~s\"", [binary_to_list(S)]));
@ -402,7 +404,7 @@ expr_p(_, {char, _, C}) ->
text("'" ++ tl(lists:droplast(S)) ++ "'"); text("'" ++ tl(lists:droplast(S)) ++ "'");
_ -> _ ->
S = lists:flatten( S = lists:flatten(
io_lib:format("'~ts'", [list_to_binary(aeso_scan:utf8_encode([C]))])), io_lib:format("'~ts'", [list_to_binary(so_scan:utf8_encode([C]))])),
text(S) text(S)
end; end;
%% -- Names %% -- Names
@ -421,7 +423,7 @@ 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 so_syntax:get_ann(origin, Else) of
system when HideGenerated -> empty(); system when HideGenerated -> empty();
_ -> block_expr(200, text("else"), Else) _ -> block_expr(200, text("else"), Else)
end. end.
@ -433,7 +435,7 @@ lc_bind({comprehension_if, _, E}) ->
lc_bind(Let) -> lc_bind(Let) ->
letdecl("let", Let). letdecl("let", Let).
-spec bin_prec(aeso_syntax:bin_op()) -> {integer(), integer(), integer()}. -spec bin_prec(so_syntax:bin_op()) -> {integer(), integer(), integer()}.
bin_prec('..') -> { 0, 0, 0}; %% Always printed inside '[ ]' bin_prec('..') -> { 0, 0, 0}; %% Always printed inside '[ ]'
bin_prec('=') -> { 0, 0, 0}; %% Always printed inside '[ ]' bin_prec('=') -> { 0, 0, 0}; %% Always printed inside '[ ]'
bin_prec('@') -> { 0, 0, 0}; %% Only in error messages bin_prec('@') -> { 0, 0, 0}; %% Only in error messages
@ -460,7 +462,7 @@ bin_prec('/') -> {700, 700, 750};
bin_prec(mod) -> {700, 700, 750}; bin_prec(mod) -> {700, 700, 750};
bin_prec('^') -> {750, 750, 800}. bin_prec('^') -> {750, 750, 800}.
-spec un_prec(aeso_syntax:un_op()) -> {integer(), integer()}. -spec un_prec(so_syntax:un_op()) -> {integer(), integer()}.
un_prec('-') -> {650, 650}; un_prec('-') -> {650, 650};
un_prec('!') -> {800, 800}; un_prec('!') -> {800, 800};
un_prec('bnot') -> {850, 850}. un_prec('bnot') -> {850, 850}.
@ -468,7 +470,7 @@ un_prec('bnot') -> {850, 850}.
equals(Ann, A, B) -> equals(Ann, A, B) ->
{app, [{format, infix} | Ann], {'=', Ann}, [A, B]}. {app, [{format, infix} | Ann], {'=', Ann}, [A, B]}.
-spec infix(integer(), aeso_syntax:bin_op(), aeso_syntax:expr(), aeso_syntax:expr()) -> doc(). -spec infix(integer(), so_syntax:bin_op(), so_syntax:expr(), so_syntax:expr()) -> doc().
infix(P, Op, A, B) -> infix(P, Op, A, B) ->
{Top, L, R} = bin_prec(Op), {Top, L, R} = bin_prec(Op),
paren(P > Top, paren(P > Top,
@ -530,7 +532,7 @@ statement(E) -> expr(E).
get_elifs(Expr) -> get_elifs(Expr, []). get_elifs(Expr) -> get_elifs(Expr, []).
get_elifs(If = {'if', Ann, Cond, Then, Else}, Elifs) -> get_elifs(If = {'if', Ann, Cond, Then, Else}, Elifs) ->
case aeso_syntax:get_ann(format, If) of case so_syntax:get_ann(format, If) of
elif -> get_elifs(Else, [{elif, Ann, Cond, Then} | Elifs]); elif -> get_elifs(Else, [{elif, Ann, Cond, Then} | Elifs]);
_ -> {lists:reverse(Elifs), If} _ -> {lists:reverse(Elifs), If}
end; end;

View File

@ -1,15 +1,17 @@
%%% -*- erlang-indent-level:4; indent-tabs-mode: nil -*- %%% -*- erlang-indent-level:4; indent-tabs-mode: nil -*-
%%%------------------------------------------------------------------- %%%-------------------------------------------------------------------
%%% @copyright (C) 2025, QPQ AG
%%% @copyright (C) 2017, Aeternity Anstalt %%% @copyright (C) 2017, Aeternity Anstalt
%%% @doc The Sophia lexer. %%% @doc The Sophia lexer.
%%% %%%
%%% @end %%% @end
%%%------------------------------------------------------------------- %%%-------------------------------------------------------------------
-module(aeso_scan). -module(so_scan).
-vsn("9.0.0").
-export([scan/1, utf8_encode/1]). -export([scan/1, utf8_encode/1]).
-import(aeso_scan_lib, [token/1, token/2, symbol/0, skip/0, -import(so_scan_lib, [token/1, token/2, symbol/0, skip/0,
override/2, push/2, pop/1]). override/2, push/2, pop/1]).
lexer() -> lexer() ->
@ -79,8 +81,8 @@ lexer() ->
[{code, Rules}, {comment, CommentRules}]. [{code, Rules}, {comment, CommentRules}].
scan(String) -> scan(String) ->
Lexer = aeso_scan_lib:compile(lexer()), Lexer = so_scan_lib:compile(lexer()),
aeso_scan_lib:string(Lexer, code, String). so_scan_lib:string(Lexer, code, String).
%% -- Helpers ---------------------------------------------------------------- %% -- Helpers ----------------------------------------------------------------

View File

@ -1,10 +1,12 @@
%%% -*- erlang-indent-level:4; indent-tabs-mode: nil -*- %%% -*- erlang-indent-level:4; indent-tabs-mode: nil -*-
%%%------------------------------------------------------------------- %%%-------------------------------------------------------------------
%%% @copyright (C) 2025, QPQ AG
%%% @copyright (C) 2017, Aeternity Anstalt %%% @copyright (C) 2017, Aeternity Anstalt
%%% @doc A customisable lexer. %%% @doc A customisable lexer.
%%% @end %%% @end
%%%------------------------------------------------------------------- %%%-------------------------------------------------------------------
-module(aeso_scan_lib). -module(so_scan_lib).
-vsn("9.0.0").
-export([compile/1, string/3, -export([compile/1, string/3,
token/1, token/2, symbol/0, skip/0, token/1, token/2, symbol/0, skip/0,

View File

@ -1,17 +1,18 @@
%%%------------------------------------------------------------------- %%%-------------------------------------------------------------------
%%% @author Radosław Rowicki %%% @author Radosław Rowicki
%%% @copyright (C) 2025, QPQ AG
%%% @copyright (C) 2019, Aeternity Anstalt %%% @copyright (C) 2019, Aeternity Anstalt
%%% @doc %%% @doc
%%% Standard library for Sophia %%% Standard library for Sophia
%%% @end %%% @end
%%% Created : 6 July 2019
%%%
%%%------------------------------------------------------------------- %%%-------------------------------------------------------------------
-module(aeso_stdlib). -module(so_stdlib).
-vsn("9.0.0").
-export([stdlib_include_path/0]). -export([stdlib_include_path/0]).
stdlib_include_path() -> stdlib_include_path() ->
filename:join([code:priv_dir(aesophia), "stdlib"]). {file, BEAM} = code:is_loaded(?MODULE),
filename:join(filename:dirname(filename:dirname(BEAM)), "priv/stdlib").

View File

@ -1,12 +1,14 @@
%%% -*- erlang-indent-level:4; indent-tabs-mode: nil -*- %%% -*- erlang-indent-level:4; indent-tabs-mode: nil -*-
%%%------------------------------------------------------------------- %%%-------------------------------------------------------------------
%%% @copyright (C) 2025, QPQ AG
%%% @copyright (C) 2017, Aeternity Anstalt %%% @copyright (C) 2017, Aeternity Anstalt
%%% @doc Sophia abstract syntax types. %%% @doc Sophia abstract syntax types.
%%% %%%
%%% @end %%% @end
%%%------------------------------------------------------------------- %%%-------------------------------------------------------------------
-module(aeso_syntax). -module(so_syntax).
-vsn("9.0.0").
-export([get_ann/1, get_ann/2, get_ann/3, set_ann/2, qualify/2]). -export([get_ann/1, get_ann/2, get_ann/3, set_ann/2, qualify/2]).

View File

@ -1,10 +1,12 @@
%%%------------------------------------------------------------------- %%%-------------------------------------------------------------------
%%% @copyright (C) 2025, QPQ AG
%%% @copyright (C) 2018, Aeternity Anstalt %%% @copyright (C) 2018, Aeternity Anstalt
%%% @doc %%% @doc
%%% Sophia syntax utilities. %%% Sophia syntax utilities.
%%% @end %%% @end
%%%------------------------------------------------------------------- %%%-------------------------------------------------------------------
-module(aeso_syntax_utils). -module(so_syntax_utils).
-vsn("9.0.0").
-export([used_ids/1, used_ids/2, used_types/2, used/1]). -export([used_ids/1, used_ids/2, used_types/2, used/1]).
@ -17,19 +19,19 @@
-type kind() :: decl | type | bind_type | expr | bind_expr. -type kind() :: decl | type | bind_type | expr | bind_expr.
-spec fold(alg(A), fun((kind(), _) -> A), kind(), E | [E]) -> A -spec fold(alg(A), fun((kind(), _) -> A), kind(), E | [E]) -> A
when E :: aeso_syntax:decl() when E :: so_syntax:decl()
| aeso_syntax:typedef() | so_syntax:typedef()
| aeso_syntax:field_t() | so_syntax:field_t()
| aeso_syntax:constructor_t() | so_syntax:constructor_t()
| aeso_syntax:type() | so_syntax:type()
| aeso_syntax:expr() | so_syntax:expr()
| aeso_syntax:pat() | so_syntax:pat()
| aeso_syntax:arg() | so_syntax:arg()
| aeso_syntax:alt() | so_syntax:alt()
| aeso_syntax:elim() | so_syntax:elim()
| aeso_syntax:arg_expr() | so_syntax:arg_expr()
| aeso_syntax:field(aeso_syntax:expr()) | so_syntax:field(so_syntax:expr())
| aeso_syntax:stmt(). | so_syntax:stmt().
fold(Alg = #alg{zero = Zero, plus = Plus, scoped = Scoped}, Fun, K, X) -> fold(Alg = #alg{zero = Zero, plus = Plus, scoped = Scoped}, Fun, K, X) ->
ExprKind = if K == bind_expr -> bind_expr; true -> expr end, ExprKind = if K == bind_expr -> bind_expr; true -> expr end,
TypeKind = if K == bind_type -> bind_type; true -> type end, TypeKind = if K == bind_type -> bind_type; true -> type end,
@ -132,7 +134,7 @@ used_types([Top] = _CurrentNS, T) ->
| {type, [string()]} | {type, [string()]}
| {namespace, [string()]}. | {namespace, [string()]}.
-spec entity_alg() -> alg(#{entity() => aeso_syntax:ann()}). -spec entity_alg() -> alg(#{entity() => so_syntax:ann()}).
entity_alg() -> entity_alg() ->
IsBound = fun({K, _}) -> lists:member(K, [bound_term, bound_type]) end, IsBound = fun({K, _}) -> lists:member(K, [bound_term, bound_type]) end,
Unbind = fun(bound_term) -> term; (bound_type) -> type end, Unbind = fun(bound_term) -> term; (bound_type) -> type end,
@ -147,7 +149,7 @@ entity_alg() ->
, plus = fun maps:merge/2 , plus = fun maps:merge/2
, scoped = Scoped }. , scoped = Scoped }.
-spec used(_) -> [{entity(), aeso_syntax:ann()}]. -spec used(_) -> [{entity(), so_syntax:ann()}].
used(D) -> used(D) ->
Kind = fun(expr) -> term; Kind = fun(expr) -> term;
(bind_expr) -> bound_term; (bind_expr) -> bound_term;

View File

@ -1,10 +1,12 @@
%%%------------------------------------------------------------------- %%%-------------------------------------------------------------------
%%% @copyright (C) 2025, QPQ AG
%%% @copyright (C) 2018, Aeternity Anstalt %%% @copyright (C) 2018, Aeternity Anstalt
%%% @doc %%% @doc
%%% Sophia utility functions. %%% Sophia utility functions.
%%% @end %%% @end
%%%------------------------------------------------------------------- %%%-------------------------------------------------------------------
-module(aeso_utils). -module(so_utils).
-vsn("9.0.0").
-export([scc/1, canonical_dir/1]). -export([scc/1, canonical_dir/1]).

View File

@ -1,22 +1,22 @@
%%%------------------------------------------------------------------- %%%-------------------------------------------------------------------
%%% @copyright (C) 2025, QPQ AG
%%% @copyright (C) 2017, Aeternity Anstalt %%% @copyright (C) 2017, Aeternity Anstalt
%%% @doc Decoding fate data to AST %%% @doc Decoding fate data to AST
%%% @end %%% @end
%%%------------------------------------------------------------------- %%%-------------------------------------------------------------------
-module(aeso_vm_decode). -module(so_vm_decode).
-vsn("9.0.0").
-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(so_syntax:type(), gmb_fate_data:fate_type()) -> so_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, _, "signature"}, ?FATE_BYTES(Bin)) -> {signature, [], Bin};
from_fate({id, _, "hash"}, ?FATE_BYTES(Bin)) -> {bytes, [], Bin}; from_fate({id, _, "hash"}, ?FATE_BYTES(Bin)) -> {bytes, [], Bin};
from_fate({id, _, "unit"}, ?FATE_UNIT) -> {tuple, [], []}; from_fate({id, _, "unit"}, ?FATE_UNIT) -> {tuple, [], []};
from_fate({app_t, _, {id, _, "oracle"}, _}, ?FATE_ORACLE(Bin)) -> {oracle_pubkey, [], Bin};
from_fate({app_t, _, {id, _, "oracle_query"}, _}, ?FATE_ORACLE_Q(Bin)) -> {oracle_query_id, [], Bin};
from_fate({con, _, _Name}, ?FATE_CONTRACT(Bin)) -> {contract_pubkey, [], Bin}; from_fate({con, _, _Name}, ?FATE_CONTRACT(Bin)) -> {contract_pubkey, [], Bin};
from_fate({bytes_t, _, any}, ?FATE_BYTES(Bin)) -> make_any_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};

View File

@ -1,6 +1,7 @@
-module(aeso_warnings). -module(so_warnings).
-vsn("9.0.0").
-record(warn, { pos :: aeso_errors:pos() -record(warn, { pos :: so_errors:pos()
, message :: iolist() , message :: iolist()
}). }).
@ -16,16 +17,16 @@
]). ]).
new(Msg) -> new(Msg) ->
new(aeso_errors:pos(0, 0), Msg). new(so_errors:pos(0, 0), Msg).
new(Pos, Msg) -> new(Pos, Msg) ->
#warn{ pos = Pos, message = Msg }. #warn{ pos = Pos, message = Msg }.
warn_to_err(Kind, #warn{ pos = Pos, message = Msg }) -> warn_to_err(Kind, #warn{ pos = Pos, message = Msg }) ->
aeso_errors:new(Kind, Pos, lists:flatten(Msg)). so_errors:new(Kind, Pos, lists:flatten(Msg)).
sort_warnings(Warnings) -> sort_warnings(Warnings) ->
lists:sort(fun(W1, W2) -> W1#warn.pos =< W2#warn.pos end, Warnings). lists:sort(fun(W1, W2) -> W1#warn.pos =< W2#warn.pos end, Warnings).
pp(#warn{ pos = Pos, message = Msg }) -> pp(#warn{ pos = Pos, message = Msg }) ->
lists:flatten(io_lib:format("Warning~s:\n~s", [aeso_errors:pp_pos(Pos), Msg])). lists:flatten(io_lib:format("Warning~s:\n~s", [so_errors:pp_pos(Pos), Msg])).

View File

@ -1,13 +1,13 @@
{application, aesophia, {application, sophia,
[{description, "Compiler for Aeternity Sophia language"}, [{description, "Compiler for Sophia language"},
{vsn, "8.0.1"}, {vsn, "9.0.0"},
{registered, []}, {registered, []},
{applications, {applications,
[kernel, [kernel,
stdlib, stdlib,
jsx, jsx,
syntax_tools, syntax_tools,
aebytecode, gmbytecode,
eblake2 eblake2
]}, ]},
{env,[]}, {env,[]},

View File

@ -1,22 +0,0 @@
-module(aeso_eunit_SUITE).
-compile([export_all, nowarn_export_all]).
-include_lib("common_test/include/ct.hrl").
all() ->
[{group, eunit}].
groups() ->
[{eunit, [], [ aeso_scan_tests
, aeso_parser_tests
, aeso_compiler_tests
, aeso_abi_tests
, aeso_aci_tests
]}].
aeso_scan_tests(_Config) -> ok = eunit:test(aeso_scan_tests).
aeso_parser_tests(_Config) -> ok = eunit:test(aeso_parser_tests).
aeso_compiler_tests(_Config) -> ok = eunit:test(aeso_compiler_tests).
aeso_abi_tests(_Config) -> ok = eunit:test(aeso_abi_tests).
aeso_aci_tests(_Config) -> ok = eunit:test(aeso_aci_tests).

View File

@ -2,27 +2,12 @@ contract interface Remote =
entrypoint main_fun : (int) => unit entrypoint main_fun : (int) => unit
contract AddrChain = contract AddrChain =
type o_type = oracle(string, map(string, int))
type oq_type = oracle_query(string, map(string, int))
entrypoint is_o(a : address) =
Address.is_oracle(a)
entrypoint is_c(a : address) = entrypoint is_c(a : address) =
Address.is_contract(a) Address.is_contract(a)
// entrypoint get_o(a : address) : option(o_type) =
// Address.get_oracle(a)
// entrypoint get_c(a : address) : option(Remote) = // entrypoint get_c(a : address) : option(Remote) =
// Address.get_contract(a) // Address.get_contract(a)
entrypoint check_o(o : o_type) =
Oracle.check(o)
entrypoint check_oq(o : o_type, oq : oq_type) =
Oracle.check_query(o, oq)
// entrypoint h_to_i(h : hash) : int = // entrypoint h_to_i(h : hash) : int =
// Hash.to_int(h) // Hash.to_int(h)

View File

@ -5,10 +5,6 @@ contract interface Remote =
contract AddressLiterals = contract AddressLiterals =
entrypoint addr() : address = entrypoint addr() : address =
ak_2gx9MEFxKvY9vMG5YnqnXWv1hCsX7rgnfvBLJS4aQurustR1rt ak_2gx9MEFxKvY9vMG5YnqnXWv1hCsX7rgnfvBLJS4aQurustR1rt
entrypoint oracle() : oracle(int, bool) =
ok_2YNyxd6TRJPNrTcEDCe9ra59SVUdp9FR9qWC5msKZWYD9bP9z5
entrypoint query() : oracle_query(int, bool) =
oq_2oRvyowJuJnEkxy58Ckkw77XfWJrmRgmGaLzhdqb67SKEL1gPY
entrypoint contr() : Remote = entrypoint contr() : Remote =
ct_Ez6MyeTMm17YnTnDdHTSrzMEBKmy7Uz2sXu347bTDPgVH2ifJ ct_Ez6MyeTMm17YnTnDdHTSrzMEBKmy7Uz2sXu347bTDPgVH2ifJ
entrypoint contr_addr() : Remote = entrypoint contr_addr() : Remote =

View File

@ -14,12 +14,6 @@ main contract AENSTest =
stateful entrypoint resolve_contract(name : string, key : string) : option(C) = stateful entrypoint resolve_contract(name : string, key : string) : option(C) =
AENSv2.resolve(name, key) AENSv2.resolve(name, key)
stateful entrypoint resolve_oracle(name : string, key : string) : option(oracle(int, int)) =
AENSv2.resolve(name, key)
stateful entrypoint resolve_oracle_query(name : string, key : string) : option(oracle_query(int, int)) =
AENSv2.resolve(name, key)
// Transactions // Transactions
stateful entrypoint preclaim(addr : address, // Claim on behalf of this account (can be Contract.address) stateful entrypoint preclaim(addr : address, // Claim on behalf of this account (can be Contract.address)

View File

@ -14,7 +14,7 @@ main contract AENSUpdate =
let p5 : AENSv2.pointee = AENSv2.DataPt(String.to_bytes("any something will do")) let p5 : AENSv2.pointee = AENSv2.DataPt(String.to_bytes("any something will do"))
let p6 : AENSv2.pointee = AENSv2.DataPt(Int.to_bytes(1345, 4)) let p6 : AENSv2.pointee = AENSv2.DataPt(Int.to_bytes(1345, 4))
AENSv2.update(owner, name, None, None, AENSv2.update(owner, name, None, None,
Some({ ["account_pubkey"] = p1, ["oracle_pubkey"] = p2, Some({ ["account_pubkey"] = p1,
["contract_pubkey"] = p3, ["misc"] = p4, ["data"] = p5, ["data2"] = p6 })) ["contract_pubkey"] = p3, ["misc"] = p4, ["data"] = p5, ["data2"] = p6 }))
stateful entrypoint old_interaction(c : OldAENSContract, owner : address, name : string) = stateful entrypoint old_interaction(c : OldAENSContract, owner : address, name : string) =
@ -27,6 +27,3 @@ main contract AENSUpdate =
entrypoint get_ttl(name : string) = entrypoint get_ttl(name : string) =
switch(AENSv2.lookup(name)) switch(AENSv2.lookup(name))
Some(AENSv2.Name(_, FixedTTL(ttl), _)) => ttl Some(AENSv2.Name(_, FixedTTL(ttl), _)) => ttl
entrypoint expiry(o : oracle(int, int)) : int =
Oracle.expiry(o)

View File

@ -7,27 +7,9 @@ contract AddressLiterals =
ak_2gx9MEFxKvY9vMG5YnqnXWv1hCsX7rgnfvBLJS4aQurustR1rt ak_2gx9MEFxKvY9vMG5YnqnXWv1hCsX7rgnfvBLJS4aQurustR1rt
entrypoint addr2() : Remote = entrypoint addr2() : Remote =
ak_2gx9MEFxKvY9vMG5YnqnXWv1hCsX7rgnfvBLJS4aQurustR1rt ak_2gx9MEFxKvY9vMG5YnqnXWv1hCsX7rgnfvBLJS4aQurustR1rt
entrypoint addr3() : oracle(int, bool) =
ak_2gx9MEFxKvY9vMG5YnqnXWv1hCsX7rgnfvBLJS4aQurustR1rt
entrypoint oracle1() : oracle_query(int, bool) =
ok_2YNyxd6TRJPNrTcEDCe9ra59SVUdp9FR9qWC5msKZWYD9bP9z5
entrypoint oracle2() : bytes(32) =
ok_2YNyxd6TRJPNrTcEDCe9ra59SVUdp9FR9qWC5msKZWYD9bP9z5
entrypoint oracle3() : Remote =
ok_2YNyxd6TRJPNrTcEDCe9ra59SVUdp9FR9qWC5msKZWYD9bP9z5
entrypoint query1() : oracle(int, bool) =
oq_2oRvyowJuJnEkxy58Ckkw77XfWJrmRgmGaLzhdqb67SKEL1gPY
entrypoint query2() : bytes(32) =
oq_2oRvyowJuJnEkxy58Ckkw77XfWJrmRgmGaLzhdqb67SKEL1gPY
entrypoint query3() : Remote =
oq_2oRvyowJuJnEkxy58Ckkw77XfWJrmRgmGaLzhdqb67SKEL1gPY
entrypoint contr1() : address = entrypoint contr1() : address =
ct_Ez6MyeTMm17YnTnDdHTSrzMEBKmy7Uz2sXu347bTDPgVH2ifJ ct_Ez6MyeTMm17YnTnDdHTSrzMEBKmy7Uz2sXu347bTDPgVH2ifJ
entrypoint contr2() : oracle(int, bool) =
ct_Ez6MyeTMm17YnTnDdHTSrzMEBKmy7Uz2sXu347bTDPgVH2ifJ
entrypoint contr3() : bytes(32) = entrypoint contr3() : bytes(32) =
ct_Ez6MyeTMm17YnTnDdHTSrzMEBKmy7Uz2sXu347bTDPgVH2ifJ ct_Ez6MyeTMm17YnTnDdHTSrzMEBKmy7Uz2sXu347bTDPgVH2ifJ
entrypoint contr4() : address = entrypoint contr4() : address =

View File

@ -11,8 +11,6 @@ contract Events =
type ix5 = hash // bytes(32) type ix5 = hash // bytes(32)
type ix6 = address type ix6 = address
type ix7 = Remote type ix7 = Remote
type ix8 = oracle(int, int)
type ix9 = oracle_query(int, int)
// Valid payload types // Valid payload types
type data1 = string type data1 = string
@ -26,7 +24,6 @@ contract Events =
| Nodata3(ix4, ix5, ix6) | Nodata3(ix4, ix5, ix6)
| Data0(data1) | Data0(data1)
| Data1(data2, ix7) | Data1(data2, ix7)
| Data2(ix8, data3, ix9)
| Data3(ix1, ix2, ix5, data1) | Data3(ix1, ix2, ix5, data1)
entrypoint nodata0() = Chain.event(Nodata0) entrypoint nodata0() = Chain.event(Nodata0)
@ -35,6 +32,5 @@ contract Events =
entrypoint nodata3(ix4, ix5, ix6) = Chain.event(Nodata3(ix4, ix5, ix6)) entrypoint nodata3(ix4, ix5, ix6) = Chain.event(Nodata3(ix4, ix5, ix6))
entrypoint data0(data1) = Chain.event(Data0(data1)) entrypoint data0(data1) = Chain.event(Data0(data1))
entrypoint data1(data2, ix7) = Chain.event(Data1(data2, ix7)) entrypoint data1(data2, ix7) = Chain.event(Data1(data2, ix7))
entrypoint data2(ix8, data3, ix9) = Chain.event(Data2(ix8, data3, ix9))
entrypoint data3(ix1, ix2, ix5, data1) = Chain.event(Data3(ix1, ix2, ix5, data1)) entrypoint data3(ix1, ix2, ix5, data1) = Chain.event(Data3(ix1, ix2, ix5, data1))

View File

@ -31,12 +31,6 @@ contract FunctionArguments =
entrypoint trettiotva(b : bytes(32)) = entrypoint trettiotva(b : bytes(32)) =
b b
entrypoint find_oracle(o : oracle(int, bool)) =
true
entrypoint find_query(q : oracle_query(int, bool)) =
true
datatype colour() = Green | Yellow | Red | Pantone(int) datatype colour() = Green | Yellow | Red | Pantone(int)
entrypoint traffic_light(c : colour) = entrypoint traffic_light(c : colour) =

View File

@ -1,5 +0,0 @@
contract HigherOrderQueryType =
stateful function foo(o) : oracle_query(_, string ) =
Oracle.query(o, (x) => x + 1, 100, RelativeTTL(100), RelativeTTL(100))
entrypoint main_fun() = ()

View File

@ -1,5 +0,0 @@
contract HigherOrderResponseType =
stateful function foo(o, q : oracle_query(string, _)) =
Oracle.respond(o, q, (x) => x + 1)
entrypoint main_fun() = ()

View File

@ -1,110 +0,0 @@
contract Oracles =
type fee = int
type ttl = Chain.ttl
type query_t = string
type answer_t = int
type oracle_id = oracle(query_t, answer_t)
type query_id = oracle_query(query_t, answer_t)
stateful entrypoint registerOracle(acct : address,
qfee : fee,
ttl : ttl) : oracle_id =
Oracle.register(acct, qfee, ttl)
stateful entrypoint registerIntIntOracle(acct : address,
qfee : fee,
ttl : ttl) : oracle(int, int) =
Oracle.register(acct, qfee, ttl)
stateful entrypoint registerStringStringOracle(acct : address,
qfee : fee,
ttl : ttl) : oracle(string, string) =
Oracle.register(acct, qfee, ttl)
stateful entrypoint signedRegisterOracle(acct : address,
sign : signature,
qfee : fee,
ttl : ttl) : oracle_id =
Oracle.register(acct, qfee, ttl, signature = sign)
entrypoint queryFee(o : oracle_id) : fee =
Oracle.query_fee(o)
stateful entrypoint createQuery(o : oracle_id,
q : query_t,
qfee : fee,
qttl : ttl,
rttl : ttl) : query_id =
require(qfee =< Call.value, "insufficient value for qfee")
Oracle.query(o, q, qfee, qttl, rttl)
// Do not use in production!
stateful entrypoint unsafeCreateQuery(o : oracle_id,
q : query_t,
qfee : fee,
qttl : ttl,
rttl : ttl) : query_id =
Oracle.query(o, q, qfee, qttl, rttl)
// Do not use in production!
stateful entrypoint unsafeCreateQueryThenErr(o : oracle_id,
q : query_t,
qfee : fee,
qttl : ttl,
rttl : ttl) : query_id =
let res = Oracle.query(o, q, qfee, qttl, rttl)
require(qfee >= 100000000000000000, "causing a late error")
res
stateful entrypoint extendOracle(o : oracle_id,
ttl : ttl) : unit =
Oracle.extend(o, ttl)
stateful entrypoint signedExtendOracle(o : oracle_id,
sign : signature, // Signed oracle address
ttl : ttl) : unit =
Oracle.extend(o, signature = sign, ttl)
stateful entrypoint respond(o : oracle_id,
q : query_id,
r : answer_t) : unit =
Oracle.respond(o, q, r)
stateful entrypoint signedRespond(o : oracle_id,
q : query_id,
sign : signature,
r : answer_t) : unit =
Oracle.respond(o, q, signature = sign, r)
entrypoint getQuestion(o : oracle_id,
q : query_id) : query_t =
Oracle.get_question(o, q)
entrypoint hasAnswer(o : oracle_id,
q : query_id) =
switch(Oracle.get_answer(o, q))
None => false
Some(_) => true
entrypoint getAnswer(o : oracle_id,
q : query_id) : option(answer_t) =
Oracle.get_answer(o, q)
datatype complexQuestion = Why(int) | How(string)
datatype complexAnswer = NoAnswer | Answer(complexQuestion, string, int)
stateful entrypoint complexOracle(question) =
let o = Oracle.register(Contract.address, 0, FixedTTL(1000)) : oracle(complexQuestion, complexAnswer)
let q = Oracle.query(o, question, 0, RelativeTTL(100), RelativeTTL(100))
Oracle.respond(o, q, Answer(question, "magic", 1337))
Oracle.get_answer(o, q)
stateful entrypoint signedComplexOracle(question, sig) =
let o = Oracle.register(signature = sig, Contract.address, 0, FixedTTL(1000)) : oracle(complexQuestion, complexAnswer)
let q = Oracle.query(o, question, 0, RelativeTTL(100), RelativeTTL(100))
Oracle.respond(o, q, Answer(question, "magic", 1337), signature = sig)
Oracle.get_answer(o, q)

View File

@ -1,5 +0,0 @@
contract PolymorphicQueryType =
stateful function is_oracle(o) =
Oracle.check(o)
entrypoint main_fun() = ()

View File

@ -1,5 +0,0 @@
contract PolymorphicResponseType =
function is_oracle(o : oracle(string, 'r)) =
Oracle.check(o)
entrypoint main_fun(o : oracle(string, int)) = is_oracle(o)

View File

@ -1,47 +0,0 @@
contract interface Animal =
entrypoint sound : () => string
contract Cat : Animal =
entrypoint sound() = "meow"
main contract Main =
entrypoint oracle() = ok_2YNyxd6TRJPNrTcEDCe9ra59SVUdp9FR9qWC5msKZWYD9bP9z5
entrypoint query() = oq_2oRvyowJuJnEkxy58Ckkw77XfWJrmRgmGaLzhdqb67SKEL1gPY
entrypoint init() =
let o01 : oracle(Animal, Animal) = oracle() : oracle(Animal, Animal) // success
let o02 : oracle(Animal, Animal) = oracle() : oracle(Animal, Cat) // success
let o03 : oracle(Animal, Animal) = oracle() : oracle(Cat, Animal) // fail
let o04 : oracle(Animal, Animal) = oracle() : oracle(Cat, Cat) // fail
let o05 : oracle(Animal, Cat) = oracle() : oracle(Animal, Animal) // fail
let o06 : oracle(Animal, Cat) = oracle() : oracle(Animal, Cat) // success
let o07 : oracle(Animal, Cat) = oracle() : oracle(Cat, Animal) // fail
let o08 : oracle(Animal, Cat) = oracle() : oracle(Cat, Cat) // fail
let o09 : oracle(Cat, Animal) = oracle() : oracle(Animal, Animal) // success
let o10 : oracle(Cat, Animal) = oracle() : oracle(Animal, Cat) // success
let o11 : oracle(Cat, Animal) = oracle() : oracle(Cat, Animal) // success
let o12 : oracle(Cat, Animal) = oracle() : oracle(Cat, Cat) // success
let o13 : oracle(Cat, Cat) = oracle() : oracle(Animal, Animal) // fail
let o14 : oracle(Cat, Cat) = oracle() : oracle(Animal, Cat) // success
let o15 : oracle(Cat, Cat) = oracle() : oracle(Cat, Animal) // fail
let o16 : oracle(Cat, Cat) = oracle() : oracle(Cat, Cat) // success
let q01 : oracle_query(Animal, Animal) = query() : oracle_query(Animal, Animal) // success
let q02 : oracle_query(Animal, Animal) = query() : oracle_query(Animal, Cat) // success
let q03 : oracle_query(Animal, Animal) = query() : oracle_query(Cat, Animal) // success
let q04 : oracle_query(Animal, Animal) = query() : oracle_query(Cat, Cat) // success
let q05 : oracle_query(Animal, Cat) = query() : oracle_query(Animal, Animal) // fail
let q06 : oracle_query(Animal, Cat) = query() : oracle_query(Animal, Cat) // success
let q07 : oracle_query(Animal, Cat) = query() : oracle_query(Cat, Animal) // fail
let q08 : oracle_query(Animal, Cat) = query() : oracle_query(Cat, Cat) // success
let q09 : oracle_query(Cat, Animal) = query() : oracle_query(Animal, Animal) // fail
let q10 : oracle_query(Cat, Animal) = query() : oracle_query(Animal, Cat) // fail
let q11 : oracle_query(Cat, Animal) = query() : oracle_query(Cat, Animal) // success
let q12 : oracle_query(Cat, Animal) = query() : oracle_query(Cat, Cat) // success
let q13 : oracle_query(Cat, Cat) = query() : oracle_query(Animal, Animal) // fail
let q14 : oracle_query(Cat, Cat) = query() : oracle_query(Animal, Cat) // fail
let q15 : oracle_query(Cat, Cat) = query() : oracle_query(Cat, Animal) // fail
let q16 : oracle_query(Cat, Cat) = query() : oracle_query(Cat, Cat) // success
()

View File

@ -1,5 +1,5 @@
// This is a custom test file if you need to run a compiler without // This is a custom test file if you need to run a compiler without
// changing aeso_compiler_tests.erl // changing so_compiler_tests.erl
include "List.aes" include "List.aes"

View File

@ -28,8 +28,6 @@ contract C =
let c16 = #000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f let c16 = #000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f
let c17 = #000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f let c17 = #000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f
let c18 = RelativeTTL(50) let c18 = RelativeTTL(50)
let c19 = ok_2YNyxd6TRJPNrTcEDCe9ra59SVUdp9FR9qWC5msKZWYD9bP9z5
let c20 = oq_2oRvyowJuJnEkxy58Ckkw77XfWJrmRgmGaLzhdqb67SKEL1gPY
let c21 = ct_Ez6MyeTMm17YnTnDdHTSrzMEBKmy7Uz2sXu347bTDPgVH2ifJ : C let c21 = ct_Ez6MyeTMm17YnTnDdHTSrzMEBKmy7Uz2sXu347bTDPgVH2ifJ : C
let c22 = N.nsconst let c22 = N.nsconst
let c23 = c01 let c23 = c01
@ -54,8 +52,6 @@ contract C =
entrypoint f16() = c16 entrypoint f16() = c16
entrypoint f17() = c17 entrypoint f17() = c17
entrypoint f18() = c18 entrypoint f18() = c18
entrypoint f19() = c19
entrypoint f20() = c20
entrypoint f21() = c21 entrypoint f21() = c21
entrypoint f22() = c22 entrypoint f22() = c22
entrypoint f23() = c23 entrypoint f23() = c23

View File

@ -1,16 +1,12 @@
// Builtins without named arguments can appear unapplied. // Builtins without named arguments can appear unapplied.
// Named argument builtins are: // Named argument builtins are:
// Oracle.register
// Oracle.respond
// AENSv2.preclaim // AENSv2.preclaim
// AENSv2.claim // AENSv2.claim
// AENSv2.transfer // AENSv2.transfer
// AENSv2.revoke // AENSv2.revoke
// Oracle.extend
include "String.aes" include "String.aes"
contract UnappliedBuiltins = contract UnappliedBuiltins =
entrypoint main_fun() = () entrypoint main_fun() = ()
type o = oracle(int, int)
type t = list(int * string) type t = list(int * string)
type m = map(int, int) type m = map(int, int)
datatype event = Event(int) datatype event = Event(int)
@ -21,13 +17,6 @@ contract UnappliedBuiltins =
function call_gas_left() = Call.gas_left function call_gas_left() = Call.gas_left
function b_abort() = abort function b_abort() = abort
function b_require() = require function b_require() = require
function oracle_query_fee() = Oracle.query_fee
function oracle_expiry() = Oracle.expiry
stateful function oracle_query() = Oracle.query : (o, _, _, _, _) => _
function oracle_get_question() = Oracle.get_question : (o, _) => _
function oracle_get_answer() = Oracle.get_answer : (o, _) => _
function oracle_check() = Oracle.check : o => _
function oracle_check_query() = Oracle.check_query : (o, _) => _
function aens_resolve() = AENSv2.resolve : (_, _) => option(string) function aens_resolve() = AENSv2.resolve : (_, _) => option(string)
function map_lookup() = Map.lookup : (_, m) => _ function map_lookup() = Map.lookup : (_, m) => _
function map_lookup_default() = Map.lookup_default : (_, m, _) => _ function map_lookup_default() = Map.lookup_default : (_, m, _) => _
@ -57,7 +46,6 @@ contract UnappliedBuiltins =
function bits_sum() = Bits.sum function bits_sum() = Bits.sum
function int_to_str() = Int.to_str function int_to_str() = Int.to_str
function address_to_str() = Address.to_str function address_to_str() = Address.to_str
function address_is_oracle() = Address.is_oracle
function address_is_contract() = Address.is_contract function address_is_contract() = Address.is_contract
function address_is_payable() = Address.is_payable function address_is_payable() = Address.is_payable
function bytes_to_int() = Bytes.to_int : bytes(10) => int function bytes_to_int() = Bytes.to_int : bytes(10) => int

View File

@ -1,4 +0,0 @@
contract UnappliedNamedArgBuiltin =
stateful entrypoint main_fun(s) =
let reg = Oracle.register
reg(signature = s, Contract.address, 100, RelativeTTL(100)) : oracle(int, int)

View File

@ -1,4 +1,4 @@
-module(aeso_abi_tests). -module(so_abi_tests).
-include_lib("eunit/include/eunit.hrl"). -include_lib("eunit/include/eunit.hrl").
-compile([export_all, nowarn_export_all]). -compile([export_all, nowarn_export_all]).
@ -65,15 +65,15 @@ to_sophia_value_mcl_bls12_381_test() ->
Opts = [{backend, fate}], Opts = [{backend, fate}],
CallValue32 = 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, _} = so_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, _} = so_compiler:to_sophia_value(Code, "test_bls12_381_fp", ok, CallValue48, Opts),
{ok, _} = aeso_compiler:to_sophia_value(Code, "test_bls12_381_fr", ok, CallValue48, Opts), {ok, _} = so_compiler:to_sophia_value(Code, "test_bls12_381_fr", ok, CallValue48, Opts),
{error, _} = aeso_compiler:to_sophia_value(Code, "test_bls12_381_fr", ok, CallValue32, Opts), {error, _} = so_compiler:to_sophia_value(Code, "test_bls12_381_fr", ok, CallValue32, Opts),
{ok, _} = aeso_compiler:to_sophia_value(Code, "test_bls12_381_g1", ok, CallValueTp, Opts), {ok, _} = so_compiler:to_sophia_value(Code, "test_bls12_381_g1", ok, CallValueTp, Opts),
ok. ok.
@ -81,11 +81,11 @@ to_sophia_value_neg_test() ->
Code = [ "contract Foo =\n" Code = [ "contract Foo =\n"
" entrypoint f(x : int) : string = \"hello\"\n" ], " entrypoint f(x : int) : string = \"hello\"\n" ],
{error, [Err1]} = aeso_compiler:to_sophia_value(Code, "f", ok, encode(12)), {error, [Err1]} = so_compiler:to_sophia_value(Code, "f", ok, encode(12)),
?assertEqual("Data error:\nCannot translate FATE value 12\n of Sophia type string\n", aeso_errors:pp(Err1)), ?assertEqual("Data error:\nCannot translate FATE value 12\n of Sophia type string\n", so_errors:pp(Err1)),
{error, [Err2]} = aeso_compiler:to_sophia_value(Code, "f", revert, encode(12)), {error, [Err2]} = so_compiler:to_sophia_value(Code, "f", revert, encode(12)),
?assertEqual("Data error:\nCould not deserialize the revert message\n", aeso_errors:pp(Err2)), ?assertEqual("Data error:\nCould not deserialize the revert message\n", so_errors:pp(Err2)),
ok. ok.
encode_calldata_neg_test() -> encode_calldata_neg_test() ->
@ -97,8 +97,8 @@ encode_calldata_neg_test() ->
" `f : (int) => string`\n" " `f : (int) => string`\n"
"to arguments\n" "to arguments\n"
" `true : bool`\n", " `true : bool`\n",
{error, [Err1]} = aeso_compiler:create_calldata(Code, "f", ["true"]), {error, [Err1]} = so_compiler:create_calldata(Code, "f", ["true"]),
?assertEqual(ExpErr1, aeso_errors:pp(Err1)), ?assertEqual(ExpErr1, so_errors:pp(Err1)),
ok. ok.
@ -108,15 +108,15 @@ decode_calldata_neg_test() ->
Code2 = [ "contract Foo =\n" Code2 = [ "contract Foo =\n"
" entrypoint f(x : string) : int = 42\n" ], " entrypoint f(x : string) : int = 42\n" ],
{ok, CallDataFATE} = aeso_compiler:create_calldata(Code1, "f", ["42"]), {ok, CallDataFATE} = so_compiler:create_calldata(Code1, "f", ["42"]),
{error, [Err1]} = aeso_compiler:decode_calldata(Code2, "f", <<1,2,3>>), {error, [Err1]} = so_compiler:decode_calldata(Code2, "f", <<1,2,3>>),
?assertEqual("Data error:\nFailed to decode calldata binary\n", aeso_errors:pp(Err1)), ?assertEqual("Data error:\nFailed to decode calldata binary\n", so_errors:pp(Err1)),
{error, [Err2]} = aeso_compiler:decode_calldata(Code2, "f", CallDataFATE), {error, [Err2]} = so_compiler:decode_calldata(Code2, "f", CallDataFATE),
?assertEqual("Data error:\nCannot translate FATE value \"*\"\n to Sophia type (string)\n", aeso_errors:pp(Err2)), ?assertEqual("Data error:\nCannot translate FATE value \"*\"\n to Sophia type (string)\n", so_errors:pp(Err2)),
{error, [Err3]} = aeso_compiler:decode_calldata(Code2, "x", CallDataFATE), {error, [Err3]} = so_compiler:decode_calldata(Code2, "x", CallDataFATE),
?assertEqual("Data error at line 1, col 1:\nFunction 'x' is missing in contract\n", aeso_errors:pp(Err3)), ?assertEqual("Data error at line 1, col 1:\nFunction 'x' is missing in contract\n", so_errors:pp(Err3)),
ok. ok.
@ -128,12 +128,12 @@ encode_decode_sophia_string(SophiaType, String) ->
, " record r = {x : an_alias(int), y : variant}\n" , " record r = {x : an_alias(int), y : variant}\n"
, " datatype variant = Red | Blue(map(string, int))\n" , " datatype variant = Red | Blue(map(string, int))\n"
, " entrypoint foo : arg_type => arg_type\n" ], , " entrypoint foo : arg_type => arg_type\n" ],
case aeso_compiler:check_call(lists:flatten(Code), "foo", [String], [no_code]) of case so_compiler:check_call(lists:flatten(Code), "foo", [String], [no_code]) of
{ok, _, [Arg]} -> {ok, _, [Arg]} ->
Data = encode(Arg), Data = encode(Arg),
case aeso_compiler:to_sophia_value(Code, "foo", ok, Data, [no_code]) of case so_compiler:to_sophia_value(Code, "foo", ok, Data, [no_code]) of
{ok, Sophia} -> {ok, Sophia} ->
lists:flatten(io_lib:format("~s", [prettypr:format(aeso_pretty:expr(Sophia))])); lists:flatten(io_lib:format("~s", [prettypr:format(so_pretty:expr(Sophia))]));
{error, Err} -> {error, Err} ->
io:format("~s\n", [Err]), io:format("~s\n", [Err]),
{error, Err} {error, Err}
@ -194,40 +194,18 @@ parameterized_contract(ExtraCode, FunName, Types) ->
" datatype variant = Red | Blue(map(string, int))\n" " datatype variant = Red | Blue(map(string, int))\n"
" entrypoint ", FunName, " : (", string:join(Types, ", "), ") => int\n" ]). " entrypoint ", FunName, " : (", string:join(Types, ", "), ") => int\n" ]).
oracle_test() ->
Contract =
"contract OracleTest =\n"
" entrypoint question(o, q : oracle_query(list(string), option(int))) =\n"
" Oracle.get_question(o, q)\n",
?assertEqual({ok, "question", [{oracle, <<291:256>>}, {oracle_query, <<1110:256>>}]},
aeso_compiler:check_call(Contract, "question", ["ok_111111111111111111111111111111ZrdqRz9",
"oq_1111111111111111111111111111113AFEFpt5"], [no_code])),
ok.
permissive_literals_fail_test() ->
Contract =
"contract OracleTest =\n"
" stateful entrypoint haxx(o : oracle(list(string), option(int))) =\n"
" Chain.spend(o, 1000000)\n",
{error, [Err]} =
aeso_compiler:check_call(Contract, "haxx", ["#123"], []),
?assertMatch("Type error at line 3, col 5:\nCannot unify" ++ _, aeso_errors:pp(Err)),
?assertEqual(type_error, aeso_errors:type(Err)),
ok.
encode_decode_calldata(FunName, Types, Args) -> encode_decode_calldata(FunName, Types, Args) ->
Code = parameterized_contract(FunName, Types), Code = parameterized_contract(FunName, Types),
encode_decode_calldata_(Code, FunName, Args). encode_decode_calldata_(Code, FunName, Args).
encode_decode_calldata_(Code, FunName, Args) -> encode_decode_calldata_(Code, FunName, Args) ->
{ok, Calldata} = aeso_compiler:create_calldata(Code, FunName, Args, []), {ok, Calldata} = so_compiler:create_calldata(Code, FunName, Args, []),
{ok, _, _} = aeso_compiler:check_call(Code, FunName, Args, [no_code]), {ok, _, _} = so_compiler:check_call(Code, FunName, Args, [no_code]),
case FunName of case FunName of
"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 +214,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).

View File

@ -1,4 +1,4 @@
-module(aeso_aci_tests). -module(so_aci_tests).
-include_lib("eunit/include/eunit.hrl"). -include_lib("eunit/include/eunit.hrl").
@ -9,11 +9,11 @@ simple_aci_test_() ->
test_contract(N) -> test_contract(N) ->
{Contract,MapACI,DecACI} = test_cases(N), {Contract,MapACI,DecACI} = test_cases(N),
{ok,JSON} = aeso_aci:contract_interface(json, Contract), {ok,JSON} = so_aci:contract_interface(json, Contract),
?assertEqual([MapACI], JSON), ?assertEqual([MapACI], JSON),
?assertEqual({ok, DecACI}, aeso_aci:render_aci_json(JSON)), ?assertEqual({ok, DecACI}, so_aci:render_aci_json(JSON)),
%% Check if the compiler provides correct aci %% Check if the compiler provides correct aci
{ok,#{aci := JSON2}} = aeso_compiler:from_string(Contract, [{aci, json}]), {ok,#{aci := JSON2}} = so_compiler:from_string(Contract, [{aci, json}]),
?assertEqual(JSON, JSON2). ?assertEqual(JSON, JSON2).
test_cases(1) -> test_cases(1) ->
@ -95,39 +95,39 @@ aci_test_() ->
fun() -> aci_test_contract(ContractName) end} fun() -> aci_test_contract(ContractName) end}
|| ContractName <- all_contracts()]. || ContractName <- all_contracts()].
all_contracts() -> aeso_compiler_tests:compilable_contracts(). all_contracts() -> so_compiler_tests:compilable_contracts().
aci_test_contract(Name) -> aci_test_contract(Name) ->
String = aeso_test_utils:read_contract(Name), String = so_test_utils:read_contract(Name),
Opts = case lists:member(Name, aeso_compiler_tests:debug_mode_contracts()) of Opts = case lists:member(Name, so_compiler_tests:debug_mode_contracts()) of
true -> [debug_mode]; true -> [debug_mode];
false -> [] false -> []
end ++ [{include, {file_system, [aeso_test_utils:contract_path()]}}], end ++ [{include, {file_system, [so_test_utils:contract_path()]}}],
JSON = case aeso_aci:contract_interface(json, String, Opts) of JSON = case so_aci:contract_interface(json, String, Opts) of
{ok, J} -> J; {ok, J} -> J;
{error, ErrorStringJ} when is_binary(ErrorStringJ) -> error(ErrorStringJ); {error, ErrorStringJ} when is_binary(ErrorStringJ) -> error(ErrorStringJ);
{error, ErrorJ} -> aeso_compiler_tests:print_and_throw(ErrorJ) {error, ErrorJ} -> so_compiler_tests:print_and_throw(ErrorJ)
end, end,
case aeso_compiler:from_string(String, [{aci, json} | Opts]) of case so_compiler:from_string(String, [{aci, json} | Opts]) of
{ok, #{aci := JSON1}} -> {ok, #{aci := JSON1}} ->
?assertEqual(JSON, JSON1), ?assertEqual(JSON, JSON1),
io:format("JSON:\n~p\n", [JSON]), io:format("JSON:\n~p\n", [JSON]),
{ok, ContractStub} = aeso_aci:render_aci_json(JSON), {ok, ContractStub} = so_aci:render_aci_json(JSON),
io:format("STUB:\n~s\n", [ContractStub]), io:format("STUB:\n~s\n", [ContractStub]),
check_stub(ContractStub, [{src_file, Name}]), check_stub(ContractStub, [{src_file, Name}]),
ok; ok;
{error, ErrorString} when is_binary(ErrorString) -> error(ErrorString); {error, ErrorString} when is_binary(ErrorString) -> error(ErrorString);
{error, Error} -> aeso_compiler_tests:print_and_throw(Error) {error, Error} -> so_compiler_tests:print_and_throw(Error)
end. end.
check_stub(Stub, Options) -> check_stub(Stub, Options) ->
try aeso_parser:string(binary_to_list(Stub), Options) of try so_parser:string(binary_to_list(Stub), Options) of
Ast -> Ast ->
try try
%% io:format("AST: ~120p\n", [Ast]), %% io:format("AST: ~120p\n", [Ast]),
aeso_ast_infer_types:infer(Ast, [no_code]) so_ast_infer_types:infer(Ast, [no_code])
catch throw:{type_errors, TE} -> catch throw:{type_errors, TE} ->
io:format("Type error:\n~s\n", [TE]), io:format("Type error:\n~s\n", [TE]),
error(TE); error(TE);
@ -136,6 +136,6 @@ check_stub(Stub, Options) ->
error(R) error(R)
end end
catch throw:{error, Errs} -> catch throw:{error, Errs} ->
_ = [ io:format("~s\n", [aeso_errors:pp(E)]) || E <- Errs ], _ = [ io:format("~s\n", [so_errors:pp(E)]) || E <- Errs ],
error({parse_errors, Errs}) error({parse_errors, Errs})
end. end.

View File

@ -6,7 +6,7 @@
%%% @end %%% @end
%%%------------------------------------------------------------------- %%%-------------------------------------------------------------------
-module(aeso_calldata_tests). -module(so_calldata_tests).
-compile([export_all, nowarn_export_all]). -compile([export_all, nowarn_export_all]).
@ -18,7 +18,7 @@
calldata_test_() -> calldata_test_() ->
[ {"Testing " ++ ContractName ++ " contract calling " ++ Fun, [ {"Testing " ++ ContractName ++ " contract calling " ++ Fun,
fun() -> fun() ->
ContractString = aeso_test_utils:read_contract(ContractName), ContractString = so_test_utils:read_contract(ContractName),
FateExprs = ast_exprs(ContractString, Fun, Args), FateExprs = ast_exprs(ContractString, Fun, Args),
ParsedExprs = parse_args(Fun, Args), ParsedExprs = parse_args(Fun, Args),
?assertEqual(ParsedExprs, FateExprs), ?assertEqual(ParsedExprs, FateExprs),
@ -28,8 +28,8 @@ calldata_test_() ->
calldata_aci_test_() -> calldata_aci_test_() ->
[ {"Testing " ++ ContractName ++ " contract calling " ++ Fun, [ {"Testing " ++ ContractName ++ " contract calling " ++ Fun,
fun() -> fun() ->
ContractString = aeso_test_utils:read_contract(ContractName), ContractString = so_test_utils:read_contract(ContractName),
{ok, ContractACIBin} = aeso_aci:contract_interface(string, ContractString, [no_code]), {ok, ContractACIBin} = so_aci:contract_interface(string, ContractString, [no_code]),
ContractACI = binary_to_list(ContractACIBin), ContractACI = binary_to_list(ContractACIBin),
io:format("ACI:\n~s\n", [ContractACIBin]), io:format("ACI:\n~s\n", [ContractACIBin]),
FateExprs = ast_exprs(ContractACI, Fun, Args), FateExprs = ast_exprs(ContractACI, Fun, Args),
@ -40,7 +40,7 @@ calldata_aci_test_() ->
parse_args(Fun, Args) -> parse_args(Fun, Args) ->
[{contract_main, _, _, _, [{letfun, _, _, _, _, [{guarded, _, [], {app, _, _, AST}}]}]}] = [{contract_main, _, _, _, [{letfun, _, _, _, _, [{guarded, _, [], {app, _, _, AST}}]}]}] =
aeso_parser:string("main contract Temp = function foo() = " ++ Fun ++ "(" ++ string:join(Args, ", ") ++ ")"), so_parser:string("main contract Temp = function foo() = " ++ Fun ++ "(" ++ string:join(Args, ", ") ++ ")"),
strip_ann(AST). strip_ann(AST).
strip_ann(T) when is_tuple(T) -> strip_ann(T) when is_tuple(T) ->
@ -58,8 +58,8 @@ strip_ann1(X) -> X.
ast_exprs(ContractString, Fun, Args) -> ast_exprs(ContractString, Fun, Args) ->
ast_exprs(ContractString, Fun, Args, []). ast_exprs(ContractString, Fun, Args, []).
ast_exprs(ContractString, Fun, Args, Opts) -> ast_exprs(ContractString, Fun, Args, Opts) ->
{ok, Data} = (catch aeso_compiler:create_calldata(ContractString, Fun, Args, Opts)), {ok, Data} = (catch so_compiler:create_calldata(ContractString, Fun, Args, Opts)),
{ok, _Types, Exprs} = (catch aeso_compiler:decode_calldata(ContractString, Fun, Data, Opts)), {ok, _Types, Exprs} = (catch so_compiler:decode_calldata(ContractString, Fun, Data, Opts)),
?assert(is_list(Exprs)), ?assert(is_list(Exprs)),
strip_ann(Exprs). strip_ann(Exprs).
@ -90,8 +90,6 @@ compilable_contracts() ->
{"funargs", "sextiosju", ["#01020304050607080910111213141516171819202122232425262728293031323334353637383940" {"funargs", "sextiosju", ["#01020304050607080910111213141516171819202122232425262728293031323334353637383940"
"414243444546474849505152535455565758596061626364656667"]}, "414243444546474849505152535455565758596061626364656667"]},
{"funargs", "trettiotva", ["#0102030405060708091011121314151617181920212223242526272829303132"]}, {"funargs", "trettiotva", ["#0102030405060708091011121314151617181920212223242526272829303132"]},
{"funargs", "find_oracle", ["ok_2YNyxd6TRJPNrTcEDCe9ra59SVUdp9FR9qWC5msKZWYD9bP9z5"]},
{"funargs", "find_query", ["oq_2oRvyowJuJnEkxy58Ckkw77XfWJrmRgmGaLzhdqb67SKEL1gPY"]},
{"funargs", "traffic_light", ["Green"]}, {"funargs", "traffic_light", ["Green"]},
{"funargs", "traffic_light", ["Pantone(12)"]}, {"funargs", "traffic_light", ["Pantone(12)"]},
{"funargs", "tuples", ["()"]}, {"funargs", "tuples", ["()"]},

View File

@ -6,7 +6,7 @@
%%% @end %%% @end
%%%------------------------------------------------------------------- %%%-------------------------------------------------------------------
-module(aeso_compiler_tests). -module(so_compiler_tests).
-compile([export_all, nowarn_export_all]). -compile([export_all, nowarn_export_all]).
@ -28,14 +28,14 @@ simple_compile_test_() ->
fun() -> fun() ->
case compile(ContractName) of case compile(ContractName) of
#{fate_code := Code} -> #{fate_code := Code} ->
Code1 = 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
end} || ContractName <- compilable_contracts()] ++ end} || ContractName <- compilable_contracts()] ++
[ {"Test file not found error", [ {"Test file not found error",
fun() -> fun() ->
{error, Errors} = aeso_compiler:file("does_not_exist.aes"), {error, Errors} = so_compiler:file("does_not_exist.aes"),
ExpErr = <<"File error:\ndoes_not_exist.aes: no such file or directory">>, ExpErr = <<"File error:\ndoes_not_exist.aes: no such file or directory">>,
check_errors([ExpErr], Errors) check_errors([ExpErr], Errors)
end} ] ++ end} ] ++
@ -49,7 +49,7 @@ simple_compile_test_() ->
fun() -> fun() ->
FileSystem = maps:from_list( FileSystem = maps:from_list(
[ begin [ begin
{ok, Bin} = file:read_file(filename:join([aeso_test_utils:contract_path(), File])), {ok, Bin} = file:read_file(filename:join([so_test_utils:contract_path(), File])),
{File, Bin} {File, Bin}
end || File <- ["included.aes", "../contracts/included2.aes"] ]), end || File <- ["included.aes", "../contracts/included2.aes"] ]),
#{byte_code := Code1} = compile("include", [{include, {explicit_files, FileSystem}}]), #{byte_code := Code1} = compile("include", [{include, {explicit_files, FileSystem}}]),
@ -77,14 +77,14 @@ simple_compile_test_() ->
%% Check if all modules in the standard library compile %% Check if all modules in the standard library compile
stdlib_test_() -> stdlib_test_() ->
{ok, Files} = file:list_dir(aeso_stdlib:stdlib_include_path()), {ok, Files} = file:list_dir(so_stdlib:stdlib_include_path()),
[ { "Testing " ++ File ++ " from the stdlib", [ { "Testing " ++ File ++ " from the stdlib",
fun() -> fun() ->
String = "include \"" ++ File ++ "\"\nmain contract Test =\n entrypoint f(x) = x", String = "include \"" ++ File ++ "\"\nmain contract Test =\n entrypoint f(x) = x",
Options = [{src_file, File}], Options = [{src_file, File}],
case aeso_compiler:from_string(String, Options) of case so_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
@ -97,7 +97,7 @@ check_errors(Expect, #{}) ->
?assertEqual({error, Expect}, ok); ?assertEqual({error, Expect}, ok);
check_errors(Expect0, Actual0) -> check_errors(Expect0, Actual0) ->
Expect = lists:sort(Expect0), Expect = lists:sort(Expect0),
Actual = [ list_to_binary(string:trim(aeso_errors:pp(Err))) || Err <- Actual0 ], Actual = [ list_to_binary(string:trim(so_errors:pp(Err))) || Err <- Actual0 ],
case {Expect -- Actual, Actual -- Expect} of case {Expect -- Actual, Actual -- Expect} of
{[], Extra} -> ?assertMatch({unexpected, []}, {unexpected, Extra}); {[], Extra} -> ?assertMatch({unexpected, []}, {unexpected, Extra});
{Missing, []} -> ?assertMatch({missing, []}, {missing, Missing}); {Missing, []} -> ?assertMatch({missing, []}, {missing, Missing});
@ -106,7 +106,7 @@ check_errors(Expect0, Actual0) ->
check_warnings(Expect0, Actual0) -> check_warnings(Expect0, Actual0) ->
Expect = lists:sort(Expect0), Expect = lists:sort(Expect0),
Actual = [ list_to_binary(string:trim(aeso_warnings:pp(Warn))) || Warn <- Actual0 ], Actual = [ list_to_binary(string:trim(so_warnings:pp(Warn))) || Warn <- Actual0 ],
case {Expect -- Actual, Actual -- Expect} of case {Expect -- Actual, Actual -- Expect} of
{[], Extra} -> ?assertMatch({unexpected, []}, {unexpected, Extra}); {[], Extra} -> ?assertMatch({unexpected, []}, {unexpected, Extra});
{Missing, []} -> ?assertMatch({missing, []}, {missing, Missing}); {Missing, []} -> ?assertMatch({missing, []}, {missing, Missing});
@ -114,19 +114,19 @@ check_warnings(Expect0, Actual0) ->
end. end.
compile(Name) -> compile(Name) ->
compile( Name, [{include, {file_system, [aeso_test_utils:contract_path()]}}]). compile( Name, [{include, {file_system, [so_test_utils:contract_path()]}}]).
compile(Name, Options) -> compile(Name, Options) ->
String = aeso_test_utils:read_contract(Name), String = so_test_utils:read_contract(Name),
Options1 = Options1 =
case lists:member(Name, debug_mode_contracts()) of case lists:member(Name, debug_mode_contracts()) of
true -> [debug_mode]; true -> [debug_mode];
false -> [] false -> []
end ++ end ++
[ {src_file, Name ++ ".aes"} [ {src_file, Name ++ ".aes"}
, {include, {file_system, [aeso_test_utils:contract_path()]}} , {include, {file_system, [so_test_utils:contract_path()]}}
] ++ Options, ] ++ Options,
case aeso_compiler:from_string(String, Options1) of case so_compiler:from_string(String, Options1) of
{ok, Map} -> Map; {ok, Map} -> Map;
{error, ErrorString} when is_binary(ErrorString) -> ErrorString; {error, ErrorString} when is_binary(ErrorString) -> ErrorString;
{error, Errors} -> Errors {error, Errors} -> Errors
@ -145,7 +145,6 @@ compilable_contracts() ->
"fundme", "fundme",
"identity", "identity",
"maps", "maps",
"oracles",
"remote_call", "remote_call",
"remote_call_ambiguous_record", "remote_call_ambiguous_record",
"simple", "simple",
@ -223,7 +222,6 @@ compilable_contracts() ->
"polymorphic_entrypoint_return", "polymorphic_entrypoint_return",
"polymorphic_map_keys", "polymorphic_map_keys",
"unapplied_contract_call", "unapplied_contract_call",
"unapplied_named_arg_builtin",
"resolve_field_constraint_by_arity", "resolve_field_constraint_by_arity",
"toplevel_constants", "toplevel_constants",
"ceres", "ceres",
@ -299,7 +297,7 @@ warnings() ->
]). ]).
failing_contracts() -> failing_contracts() ->
{ok, V} = aeso_compiler:numeric_version(), {ok, V} = so_compiler:numeric_version(),
Version = list_to_binary(string:join([integer_to_list(N) || N <- V], ".")), Version = list_to_binary(string:join([integer_to_list(N) || N <- V], ".")),
%% Parse errors %% Parse errors
[ ?PARSE_ERROR(field_parse_error, [ ?PARSE_ERROR(field_parse_error,
@ -466,11 +464,7 @@ failing_contracts() ->
[<<?Pos(2, 12) [<<?Pos(2, 12)
"Nested contracts are not allowed. Contract `Con` is not defined at top level.">>]) "Nested contracts are not allowed. Contract `Con` is not defined at top level.">>])
, ?TYPE_ERROR(bad_address_literals, , ?TYPE_ERROR(bad_address_literals,
[<<?Pos(11, 5) [<<?Pos(9, 5)
"Cannot unify `address` and `oracle(int, bool)`\n"
"when checking the type of the expression `ak_2gx9MEFxKvY9vMG5YnqnXWv1hCsX7rgnfvBLJS4aQurustR1rt : address` "
"against the expected type `oracle(int, bool)`">>,
<<?Pos(9, 5)
"Cannot unify `address` and `Remote`\n" "Cannot unify `address` and `Remote`\n"
"when checking the type of the expression `ak_2gx9MEFxKvY9vMG5YnqnXWv1hCsX7rgnfvBLJS4aQurustR1rt : address` " "when checking the type of the expression `ak_2gx9MEFxKvY9vMG5YnqnXWv1hCsX7rgnfvBLJS4aQurustR1rt : address` "
"against the expected type `Remote`">>, "against the expected type `Remote`">>,
@ -478,52 +472,17 @@ failing_contracts() ->
"Cannot unify `address` and `bytes(32)`\n" "Cannot unify `address` and `bytes(32)`\n"
"when checking the type of the expression `ak_2gx9MEFxKvY9vMG5YnqnXWv1hCsX7rgnfvBLJS4aQurustR1rt : address` " "when checking the type of the expression `ak_2gx9MEFxKvY9vMG5YnqnXWv1hCsX7rgnfvBLJS4aQurustR1rt : address` "
"against the expected type `bytes(32)`">>, "against the expected type `bytes(32)`">>,
<<?Pos(14, 5) <<?Pos(12, 5)
"Cannot unify `oracle('a, 'b)` and `oracle_query(int, bool)`\n"
"when checking the type of the expression "
"`ok_2YNyxd6TRJPNrTcEDCe9ra59SVUdp9FR9qWC5msKZWYD9bP9z5 : oracle('a, 'b)` "
"against the expected type `oracle_query(int, bool)`">>,
<<?Pos(16, 5)
"Cannot unify `oracle('c, 'd)` and `bytes(32)`\n"
"when checking the type of the expression "
"`ok_2YNyxd6TRJPNrTcEDCe9ra59SVUdp9FR9qWC5msKZWYD9bP9z5 : oracle('c, 'd)` "
"against the expected type `bytes(32)`">>,
<<?Pos(18, 5)
"Cannot unify `oracle('e, 'f)` and `Remote`\n"
"when checking the type of the expression "
"`ok_2YNyxd6TRJPNrTcEDCe9ra59SVUdp9FR9qWC5msKZWYD9bP9z5 : oracle('e, 'f)` "
"against the expected type `Remote`">>,
<<?Pos(21, 5)
"Cannot unify `oracle_query('g, 'h)` and `oracle(int, bool)`\n"
"when checking the type of the expression "
"`oq_2oRvyowJuJnEkxy58Ckkw77XfWJrmRgmGaLzhdqb67SKEL1gPY : oracle_query('g, 'h)` "
"against the expected type `oracle(int, bool)`">>,
<<?Pos(23, 5)
"Cannot unify `oracle_query('i, 'j)` and `bytes(32)`\n"
"when checking the type of the expression "
"`oq_2oRvyowJuJnEkxy58Ckkw77XfWJrmRgmGaLzhdqb67SKEL1gPY : oracle_query('i, 'j)` "
"against the expected type `bytes(32)`">>,
<<?Pos(25, 5)
"Cannot unify `oracle_query('k, 'l)` and `Remote`\n"
"when checking the type of the expression "
"`oq_2oRvyowJuJnEkxy58Ckkw77XfWJrmRgmGaLzhdqb67SKEL1gPY : oracle_query('k, 'l)` "
"against the expected type `Remote`">>,
<<?Pos(28, 5)
"The type `address` is not a contract type\n" "The type `address` is not a contract type\n"
"when checking that the contract literal " "when checking that the contract literal "
"`ct_Ez6MyeTMm17YnTnDdHTSrzMEBKmy7Uz2sXu347bTDPgVH2ifJ` " "`ct_Ez6MyeTMm17YnTnDdHTSrzMEBKmy7Uz2sXu347bTDPgVH2ifJ` "
"has the type `address`">>, "has the type `address`">>,
<<?Pos(30, 5) <<?Pos(14, 5)
"The type `oracle(int, bool)` is not a contract type\n"
"when checking that the contract literal "
"`ct_Ez6MyeTMm17YnTnDdHTSrzMEBKmy7Uz2sXu347bTDPgVH2ifJ` "
"has the type `oracle(int, bool)`">>,
<<?Pos(32, 5)
"The type `bytes(32)` is not a contract type\n" "The type `bytes(32)` is not a contract type\n"
"when checking that the contract literal " "when checking that the contract literal "
"`ct_Ez6MyeTMm17YnTnDdHTSrzMEBKmy7Uz2sXu347bTDPgVH2ifJ` " "`ct_Ez6MyeTMm17YnTnDdHTSrzMEBKmy7Uz2sXu347bTDPgVH2ifJ` "
"has the type `bytes(32)`">>, "has the type `bytes(32)`">>,
<<?Pos(34, 5), <<?Pos(16, 5),
"The type `address` is not a contract type\n" "The type `address` is not a contract type\n"
"when checking that the call to `Address.to_contract` " "when checking that the call to `Address.to_contract` "
"has the type `address`">>]) "has the type `address`">>])
@ -1036,56 +995,6 @@ failing_contracts() ->
"Cannot unify `Animal` and `Cat` in a invariant context\n" "Cannot unify `Animal` and `Cat` in a invariant context\n"
"when checking the type of the pattern `r11 : rec_inv(Cat)` against the expected type `Main.rec_inv(Animal)`">> "when checking the type of the pattern `r11 : rec_inv(Cat)` against the expected type `Main.rec_inv(Animal)`">>
]) ])
, ?TYPE_ERROR(polymorphism_variance_switching_oracles,
[<<?Pos(15,13)
"Cannot unify `Cat` and `Animal` in a contravariant context\n"
"when checking the type of the pattern `o03 : oracle(Animal, Animal)` against the expected type `oracle(Cat, Animal)`">>,
<<?Pos(16,13)
"Cannot unify `Cat` and `Animal` in a contravariant context\n"
"when checking the type of the pattern `o04 : oracle(Animal, Animal)` against the expected type `oracle(Cat, Cat)`">>,
<<?Pos(17,13)
"Cannot unify `Animal` and `Cat` in a covariant context\n"
"when checking the type of the pattern `o05 : oracle(Animal, Cat)` against the expected type `oracle(Animal, Animal)`">>,
<<?Pos(19,13)
"Cannot unify `Cat` and `Animal` in a contravariant context\n"
"when checking the type of the pattern `o07 : oracle(Animal, Cat)` against the expected type `oracle(Cat, Animal)`">>,
<<?Pos(19,13)
"Cannot unify `Animal` and `Cat` in a covariant context\n"
"when checking the type of the pattern `o07 : oracle(Animal, Cat)` against the expected type `oracle(Cat, Animal)`">>,
<<?Pos(20,13)
"Cannot unify `Cat` and `Animal` in a contravariant context\n"
"when checking the type of the pattern `o08 : oracle(Animal, Cat)` against the expected type `oracle(Cat, Cat)`">>,
<<?Pos(25,13)
"Cannot unify `Animal` and `Cat` in a covariant context\n"
"when checking the type of the pattern `o13 : oracle(Cat, Cat)` against the expected type `oracle(Animal, Animal)`">>,
<<?Pos(27,13)
"Cannot unify `Animal` and `Cat` in a covariant context\n"
"when checking the type of the pattern `o15 : oracle(Cat, Cat)` against the expected type `oracle(Cat, Animal)`">>,
<<?Pos(34,13)
"Cannot unify `Animal` and `Cat` in a covariant context\n"
"when checking the type of the pattern `q05 : oracle_query(Animal, Cat)` against the expected type `oracle_query(Animal, Animal)`">>,
<<?Pos(36,13)
"Cannot unify `Animal` and `Cat` in a covariant context\n"
"when checking the type of the pattern `q07 : oracle_query(Animal, Cat)` against the expected type `oracle_query(Cat, Animal)`">>,
<<?Pos(38,13)
"Cannot unify `Animal` and `Cat` in a covariant context\n"
"when checking the type of the pattern `q09 : oracle_query(Cat, Animal)` against the expected type `oracle_query(Animal, Animal)`">>,
<<?Pos(39,13)
"Cannot unify `Animal` and `Cat` in a covariant context\n"
"when checking the type of the pattern `q10 : oracle_query(Cat, Animal)` against the expected type `oracle_query(Animal, Cat)`">>,
<<?Pos(42,13)
"Cannot unify `Animal` and `Cat` in a covariant context\n"
"when checking the type of the pattern `q13 : oracle_query(Cat, Cat)` against the expected type `oracle_query(Animal, Animal)`">>,
<<?Pos(42,13)
"Cannot unify `Animal` and `Cat` in a covariant context\n"
"when checking the type of the pattern `q13 : oracle_query(Cat, Cat)` against the expected type `oracle_query(Animal, Animal)`">>,
<<?Pos(43,13)
"Cannot unify `Animal` and `Cat` in a covariant context\n"
"when checking the type of the pattern `q14 : oracle_query(Cat, Cat)` against the expected type `oracle_query(Animal, Cat)`">>,
<<?Pos(44,13)
"Cannot unify `Animal` and `Cat` in a covariant context\n"
"when checking the type of the pattern `q15 : oracle_query(Cat, Cat)` against the expected type `oracle_query(Cat, Animal)`">>
])
, ?TYPE_ERROR(polymorphism_variance_switching_chain_create_fail, , ?TYPE_ERROR(polymorphism_variance_switching_chain_create_fail,
[<<?Pos(9,22) [<<?Pos(9,22)
"I is not implemented.\n" "I is not implemented.\n"
@ -1156,34 +1065,6 @@ failing_contracts() ->
" `list(int)`\n" " `list(int)`\n"
"It must be a `string` or a pubkey type (`address`, `oracle`, etc)">> "It must be a `string` or a pubkey type (`address`, `oracle`, etc)">>
]) ])
, ?TYPE_ERROR(polymorphic_query_type,
[<<?Pos(3,5)
"Invalid oracle type\n"
" `oracle('a, 'b)`\n"
"The query type must not be polymorphic (contain type variables)">>,
<<?Pos(3,5)
"Invalid oracle type\n"
" `oracle('a, 'b)`\n"
"The response type must not be polymorphic (contain type variables)">>
])
, ?TYPE_ERROR(polymorphic_response_type,
[<<?Pos(3,5)
"Invalid oracle type\n"
" `oracle(string, 'r)`\n"
"The response type must not be polymorphic (contain type variables)">>
])
, ?TYPE_ERROR(higher_order_query_type,
[<<?Pos(3,5)
"Invalid oracle type\n"
" `oracle((int) => int, string)`\n"
"The query type must not be higher-order (contain function types)">>
])
, ?TYPE_ERROR(higher_order_response_type,
[<<?Pos(3,5)
"Invalid oracle type\n"
" `oracle(string, (int) => int)`\n"
"The response type must not be higher-order (contain function types)">>
])
, ?TYPE_ERROR(var_args_unify_let, , ?TYPE_ERROR(var_args_unify_let,
[<<?Pos(3,9) [<<?Pos(3,9)
"Cannot infer types for variable argument list.\n" "Cannot infer types for variable argument list.\n"
@ -1345,16 +1226,16 @@ 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 = so_test_utils:read_contract(Contract2),
aeso_compiler:validate_byte_code( so_compiler:validate_byte_code(
ByteCode#{ byte_code := FCode1 }, Source, ByteCode#{ byte_code := FCode1 }, Source,
case lists:member(Contract2, debug_mode_contracts()) of case lists:member(Contract2, debug_mode_contracts()) of
true -> [debug_mode]; true -> [debug_mode];
false -> [] false -> []
end ++ end ++
[ {src_file, lists:concat([Contract2, ".aes"])} [ {src_file, lists:concat([Contract2, ".aes"])}
, {include, {file_system, [aeso_test_utils:contract_path()]}} , {include, {file_system, [so_test_utils:contract_path()]}}
]); ]);
Error -> print_and_throw(Error) Error -> print_and_throw(Error)
end. end.
@ -1365,6 +1246,6 @@ print_and_throw(Err) ->
io:format("\n~s", [ErrBin]), io:format("\n~s", [ErrBin]),
error(ErrBin); error(ErrBin);
Errors -> Errors ->
io:format("Compilation error:\n~s", [string:join([aeso_errors:pp(E) || E <- Errors], "\n\n")]), io:format("Compilation error:\n~s", [string:join([so_errors:pp(E) || E <- Errors], "\n\n")]),
error(compilation_error) error(compilation_error)
end. end.

View File

@ -1,4 +1,4 @@
-module(aeso_encode_decode_tests). -module(so_encode_decode_tests).
-compile([export_all, nowarn_export_all]). -compile([export_all, nowarn_export_all]).
@ -9,9 +9,9 @@
encode_decode_test_() -> encode_decode_test_() ->
[ {lists:flatten(io_lib:format("Testing encode-decode roundtrip for ~p : ~p", [Value, {EType, DType}])), [ {lists:flatten(io_lib:format("Testing encode-decode roundtrip for ~p : ~p", [Value, {EType, DType}])),
fun() -> fun() ->
{ok, SerRes} = aeso_compiler:encode_value(?EMPTY, EType, Value, []), {ok, SerRes} = so_compiler:encode_value(?EMPTY, EType, Value, []),
{ok, Expr} = aeso_compiler:decode_value(?EMPTY, DType, SerRes, []), {ok, Expr} = so_compiler:decode_value(?EMPTY, DType, SerRes, []),
Value2 = prettypr:format(aeso_pretty:expr(Expr)), Value2 = prettypr:format(so_pretty:expr(Expr)),
?assertEqual(Value, Value2) ?assertEqual(Value, Value2)
end} || {Value, EType, DType} <- test_data() ]. end} || {Value, EType, DType} <- test_data() ].

22
test/so_eunit_SUITE.erl Normal file
View File

@ -0,0 +1,22 @@
-module(so_eunit_SUITE).
-compile([export_all, nowarn_export_all]).
-include_lib("common_test/include/ct.hrl").
all() ->
[{group, eunit}].
groups() ->
[{eunit, [], [ so_scan_tests
, so_parser_tests
, so_compiler_tests
, so_abi_tests
, so_aci_tests
]}].
so_scan_tests(_Config) -> ok = eunit:test(so_scan_tests).
so_parser_tests(_Config) -> ok = eunit:test(so_parser_tests).
so_compiler_tests(_Config) -> ok = eunit:test(so_compiler_tests).
so_abi_tests(_Config) -> ok = eunit:test(so_abi_tests).
so_aci_tests(_Config) -> ok = eunit:test(so_aci_tests).

View File

@ -1,4 +1,4 @@
-module(aeso_parser_tests). -module(so_parser_tests).
-export([parse_contract/1]). -export([parse_contract/1]).
@ -68,15 +68,15 @@ simple_contracts_test_() ->
}. }.
parse_contract(Name) -> parse_contract(Name) ->
parse_string(aeso_test_utils:read_contract(Name)). parse_string(so_test_utils:read_contract(Name)).
roundtrip_contract(Name) -> roundtrip_contract(Name) ->
round_trip(aeso_test_utils:read_contract(Name)). round_trip(so_test_utils:read_contract(Name)).
parse_string(Text) -> parse_string(Text, []). parse_string(Text) -> parse_string(Text, []).
parse_string(Text, Opts) -> parse_string(Text, Opts) ->
aeso_parser:string(Text, Opts). so_parser:string(Text, Opts).
parse_expr(Text) -> parse_expr(Text) ->
[{letval, _, _, Expr}] = [{letval, _, _, Expr}] =
@ -85,8 +85,8 @@ parse_expr(Text) ->
round_trip(Text) -> round_trip(Text) ->
Contract = parse_string(Text), Contract = parse_string(Text),
Text1 = prettypr:format(aeso_pretty:decls(strip_stdlib(Contract))), Text1 = prettypr:format(so_pretty:decls(strip_stdlib(Contract))),
Contract1 = parse_string(aeso_scan:utf8_encode(Text1)), Contract1 = parse_string(so_scan:utf8_encode(Text1)),
NoSrcLoc = remove_line_numbers(Contract), NoSrcLoc = remove_line_numbers(Contract),
NoSrcLoc1 = remove_line_numbers(Contract1), NoSrcLoc1 = remove_line_numbers(Contract1),
?assertMatch(NoSrcLoc, diff(NoSrcLoc, NoSrcLoc1)). ?assertMatch(NoSrcLoc, diff(NoSrcLoc, NoSrcLoc1)).

View File

@ -1,4 +1,4 @@
-module(aeso_scan_tests). -module(so_scan_tests).
-include_lib("eunit/include/eunit.hrl"). -include_lib("eunit/include/eunit.hrl").
@ -13,7 +13,7 @@ empty_contract_test_() ->
[{"Scan an empty contract.", [{"Scan an empty contract.",
fun() -> fun() ->
Text = " ", Text = " ",
{ok, []} = aeso_scan:scan(Text), {ok, []} = so_scan:scan(Text),
ok ok
end} end}
]}. ]}.
@ -26,7 +26,7 @@ all_tokens_test_() ->
Tokens = all_tokens(), Tokens = all_tokens(),
Text = string:join(lists:map(fun show_token/1, Tokens), " "), Text = string:join(lists:map(fun show_token/1, Tokens), " "),
io:format("~s\n", [Text]), io:format("~s\n", [Text]),
{ok, Tokens1} = aeso_scan:scan(Text), {ok, Tokens1} = so_scan:scan(Text),
true = compare_tokens(Tokens, Tokens1), true = compare_tokens(Tokens, Tokens1),
ok ok
end} end}

View File

@ -6,12 +6,12 @@
%%% @end %%% @end
%%%------------------------------------------------------------------- %%%-------------------------------------------------------------------
-module(aeso_test_utils). -module(so_test_utils).
-export([read_contract/1, contract_path/0]). -export([read_contract/1, contract_path/0]).
contract_path() -> contract_path() ->
filename:join(code:lib_dir(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().

20
zomp.meta Normal file
View File

@ -0,0 +1,20 @@
{name,"Sophia Compiler"}.
{type,lib}.
{modules,[]}.
{prefix,none}.
{desc,"The Sophia smart contract language for the FATE VM"}.
{author,"QPQ AG"}.
{package_id,{"otpr","sophia",{9,0,0}}}.
{deps,[{"otpr","gmbytecode",{3,4,1}},
{"otpr","getopt",{1,0,2}},
{"otpr","eblake2",{1,0,0}},
{"otpr","zj",{1,1,0}}]}.
{key_name,none}.
{a_email,[]}.
{c_email,[]}.
{copyright,"(c) 2024 QPQ AG"}.
{file_exts,[]}.
{license,skip}.
{repo_url,"https://git.qpq.swiss/QPQ-AG/sophia"}.
{tags,["gaju","gajumaru","blockchain","sophia","crypto","compiler","puck"]}.
{ws_url,[]}.

19
zomp_prep Executable file
View File

@ -0,0 +1,19 @@
#! /bin/bash
# This is a small pre-packaging source generation and include correction script that should be
# run before packaging this project for use with ZX/Zomp.
rm -rf _build
cd src
for f in $(ls *.erl)
do
echo "Updating includes in: $f"
sed -i 's/gmbytecode\/include\///g' "$f"
sed -i 's/\.\.\/include\///g' "$f"
sed -i 's/include_lib/include/g' "$f"
done
sed -i 's/gmb_opcodes\.hrl/\$gmbytecode_include\/gmb_opcodes\.hrl/' so_compiler.erl
sed -i 's/gmb_fate_data\.hrl/\$gmbytecode_include\/gmb_fate_data\.hrl/' so_vm_decode.erl
cd ..
rm -f ebin/*.beam
rm -f rebar*